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
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "faf-mcp",
3
- "version": "2.3.0",
3
+ "version": "3.0.0",
4
4
  "mcpName": "one.faf/faf-mcp",
5
- "description": "Persistent Project Context for Cursor, IDEs and VS Code. IANA-registered .faf format, 31 MCP tools, 309 tests.",
5
+ "description": "Persistent Project Context for Cursor, IDEs and VS Code. IANA-registered .faf format. Curated core tools by default, full set via FAF_TOOLS=all.",
6
6
  "icon": "./assets/icons/faf-icon-256.png",
7
7
  "logo": "./assets/icons/faf-icon-256.png",
8
8
  "displayName": ".faf 🐘",
@@ -11,11 +11,10 @@
11
11
  "faf-mcp": "dist/src/index.js"
12
12
  },
13
13
  "scripts": {
14
+ "prebuild": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
14
15
  "build": "tsc",
15
- "start": "node start-http.js",
16
16
  "dev": "ts-node src/server.ts",
17
17
  "dev:stdio": "ts-node src/cli.ts --transport stdio",
18
- "dev:http": "ts-node src/cli.ts --transport http-sse --port 3001",
19
18
  "test": "bun test --isolate --timeout=120000 --path-ignore-patterns=\"**/performance.test.ts\"",
20
19
  "test:performance": "bun test tests/performance.test.ts",
21
20
  "test:mcp": "mcp-inspector stdio ts-node src/cli.ts",
@@ -23,13 +22,11 @@
23
22
  "lint:fix": "eslint src/**/*.ts --fix",
24
23
  "type-check": "tsc --noEmit",
25
24
  "check:stylesheet": "node scripts/check-stylesheet-drift.mjs",
26
- "format:check": "prettier --check \"src/**/*.ts\"",
27
- "format": "prettier --write \"src/**/*.ts\"",
25
+ "check:engines": "node scripts/check-engines.mjs",
28
26
  "prepare": "npm run build",
29
27
  "sync-version": "node scripts/sync-version.js",
30
- "version": "npm run sync-version && git add project.faf",
31
- "prepublishOnly": "npm run build",
32
- "postinstall": "node scripts/postinstall.js",
28
+ "version": "npm run sync-version && git add project.faf server.json CHANGELOG.md docs/index.html AGENTS.md",
29
+ "prepublishOnly": "npm run build && npm run check:engines",
33
30
  "debug": "node --inspect-brk=0.0.0.0:9229 -r ts-node/register src/cli.ts"
34
31
  },
35
32
  "keywords": [
@@ -82,16 +79,15 @@
82
79
  },
83
80
  "homepage": "https://faf.one",
84
81
  "engines": {
85
- "node": ">=18.0.0"
82
+ "node": ">=22.0.0"
86
83
  },
87
84
  "files": [
88
85
  "dist/**/*",
89
86
  "assets/**/*",
90
87
  "scripts/**/*",
91
- "skill/SKILL.md",
88
+ "skills/**",
92
89
  "README.md",
93
90
  "CLAUDE.md",
94
- ".faf",
95
91
  "project.faf",
96
92
  "LICENSE",
97
93
  "CHANGELOG.md",
@@ -101,8 +97,8 @@
101
97
  "access": "public"
102
98
  },
103
99
  "dependencies": {
104
- "@modelcontextprotocol/sdk": "^1.27.1",
105
- "faf-cli": "^6.10.1",
100
+ "@modelcontextprotocol/sdk": "^1.30.0",
101
+ "faf-cli": "^7.12.0",
106
102
  "faf-scoring-kernel": "^2.0.3",
107
103
  "yaml": "^2.4.1"
108
104
  },
@@ -114,5 +110,12 @@
114
110
  "eslint": "^8.56.0",
115
111
  "ts-node": "^10.9.2",
116
112
  "typescript": "^5.9.3"
113
+ },
114
+ "overrides": {
115
+ "hono": ">=4.13.5",
116
+ "fast-uri": ">=4.1.2",
117
+ "ip-address": ">=10.3.1",
118
+ "brace-expansion@1": "1.1.18",
119
+ "brace-expansion@2": "2.1.4"
117
120
  }
118
121
  }
package/project.faf CHANGED
@@ -1,6 +1,8 @@
1
1
  faf_version: "3.0"
2
2
  project:
3
3
  name: faf-mcp
4
+ title: .FAF Context
5
+ version: 3.0.0
4
6
  goal: The Interop MCP for Context — the Cursor / IDE Edition. Persistent context for Cursor, VS Code, and every MCP-compatible IDE. IANA-registered application/vnd.faf+yaml. Start with "Use FAF".
5
7
  main_language: TypeScript
6
8
  type: mcp
@@ -12,11 +14,11 @@ stack:
12
14
  ui_library: slotignored
13
15
  state_management: slotignored
14
16
  backend: MCP SDK (TS)
15
- api_type: MCP (stdio + Streamable HTTP)
16
- runtime: Node.js >=18
17
+ api_type: MCP (stdio)
18
+ runtime: Node.js >=22
17
19
  database: slotignored
18
20
  connection: slotignored
19
- hosting: npm + Cloudflare edge
21
+ hosting: npm
20
22
  build: TypeScript (tsc)
21
23
  cicd: GitHub Actions
22
24
  monorepo_tool: slotignored
@@ -30,8 +32,8 @@ human_context:
30
32
  who: Developers using Claude, Cursor, Windsurf, VS Code, Cline, and any MCP-compatible IDE
31
33
  what: The Cursor / IDE Edition — persistent context for Cursor, VS Code, and every MCP-compatible IDE — 29 MCP tools (15 essential shown by default), interop with AGENTS.md, .cursorrules, GEMINI.md
32
34
  why: Eliminate the 20-minute AI context tax — give AI instant project understanding in 30 seconds
33
- where: npm · MCP Registry · Cloudflare edge (ide.faf.one/mcp/v1) · any MCP-compatible IDE — people get it how they wish
34
- when: Production/Stable — v2.3.0 The Curated Edition, WJTTC certified
35
+ where: npm · MCP Registry · any MCP-compatible IDE — people get it how they wish
36
+ when: Production/Stable — v3.0.0 The Compose Edition, WJTTC certified
35
37
  how: npx faf-mcp or npm install -g faf-mcp, then add to your MCP config
36
38
  monorepo:
37
39
  packages_count: slotignored
@@ -39,3 +41,19 @@ monorepo:
39
41
  versioning_strategy: slotignored
40
42
  shared_configs: slotignored
41
43
  remote_cache: slotignored
44
+ surfaces:
45
+ # Distribution map — the machine-checkable form of human_context.where. Score-neutral.
46
+ auto: # derived from manifests; regenerate with `faf surface --sync`
47
+ - { type: npm, id: faf-mcp, source: "package.json#name" }
48
+ - { type: github, id: Wolfe-Jam/faf-mcp, source: "package.json#repository" }
49
+ - { type: mcp-registry, id: one.faf/faf-mcp, state: active, source: "server.json#name" }
50
+ declared: # hand-authored: surfaces the manifests don't carry + targets
51
+ # v3.0: removed a false hosted-endpoint `mcpaas` entry here. The URL it
52
+ # pointed at serves MCPaaS (mcpaas-cf) — a different product with a
53
+ # different tool surface — not this package's tools. faf-mcp runs
54
+ # locally over stdio; no hosted deployment of it exists today.
55
+ - { type: homebrew, id: faf-mcp, status: live }
56
+ - { type: mcp-registry, id: io.github.Wolfe-Jam/faf-mcp, state: deprecated, superseded_by: one.faf/faf-mcp }
57
+ - { type: pulsemcp, id: faf-mcp, status: pending }
58
+ - { type: glama, id: faf-mcp, status: pending }
59
+ - { type: awesome-mcp-servers, id: faf-mcp, status: pending }
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env node
2
+ // check-engines.mjs — the Node engine floor must match what CI actually runs.
3
+ //
4
+ // House rule (memory: feedback-node-engine-floor-and-terminal-release-test):
5
+ // `engines.node` == the LOWEST Node in the CI matrix, never aspirational. You
6
+ // can't raise the floor without dropping that Node from CI (a visible,
7
+ // deliberate act), and you can't claim support for a Node the gate never runs.
8
+ // faf-mcp receipt: the floor said >=18 while six production transitives
9
+ // required >=20 — every Node-18 install printed EBADENGINE six times.
10
+ //
11
+ // Runs in CI (Code Quality) and in prepublishOnly.
12
+
13
+ import { readFileSync } from 'node:fs';
14
+ import { fileURLToPath } from 'node:url';
15
+ import { dirname, join } from 'node:path';
16
+
17
+ const root = join(dirname(fileURLToPath(import.meta.url)), '..');
18
+ const read = (p) => readFileSync(join(root, p), 'utf8');
19
+
20
+ const enginesRaw = JSON.parse(read('package.json')).engines?.node ?? '';
21
+ const floorMatch = enginesRaw.match(/(\d+)/);
22
+ if (!floorMatch) {
23
+ console.error(`✗ package.json engines.node missing or unparseable: ${JSON.stringify(enginesRaw)}`);
24
+ process.exit(1);
25
+ }
26
+ const floor = Number(floorMatch[1]);
27
+
28
+ // CI node matrix — this repo writes it as `node: [22.x, 24.x]`.
29
+ const ci = read('.github/workflows/ci.yml');
30
+ const matrixMatch = ci.match(/node:\s*\[([^\]]+)\]/);
31
+ if (!matrixMatch) {
32
+ console.error('✗ .github/workflows/ci.yml — could not find `node: [ ... ]` matrix');
33
+ process.exit(1);
34
+ }
35
+ const matrix = matrixMatch[1]
36
+ .split(',')
37
+ .map((s) => Number(s.replace(/['"\s]/g, '').replace(/\.x$/, '')))
38
+ .filter((n) => Number.isFinite(n))
39
+ .sort((a, b) => a - b);
40
+ if (matrix.length === 0) {
41
+ console.error('✗ CI node matrix parsed empty');
42
+ process.exit(1);
43
+ }
44
+ const ciMin = matrix[0];
45
+
46
+ if (floor !== ciMin) {
47
+ console.error(
48
+ `✗ engine floor drift — package.json engines.node = ">=${floor}", CI node matrix low = ${ciMin} (matrix: ${matrix.join(', ')}).\n` +
49
+ ` Make them equal: lower the floor to ${ciMin}, or drop Node ${ciMin} from ci.yml on purpose.`,
50
+ );
51
+ process.exit(1);
52
+ }
53
+ console.log(`✓ engine floor ${floor} == CI matrix low ${ciMin} (matrix: ${matrix.join(', ')})`);
@@ -0,0 +1,54 @@
1
+ #!/bin/sh
2
+ # Test runner with a bounded, discriminating retry for the Linux bun --isolate
3
+ # epoll flake. (Ported from the grok-faf-mcp fix, 2026-06-26.)
4
+ #
5
+ # Background: `bun test --isolate` on Ubuntu intermittently errors with
6
+ # "EEXIST: file already exists, epoll_ctl"
7
+ # — a runner-shutdown race, not a code bug (green on macOS + Windows in the same
8
+ # matrix, re-runs pass). It manifests TWO ways: a fast error (epoll_ctl in
9
+ # output) OR a HARNESS HANG (no output, never exits).
10
+ #
11
+ # This wrapper:
12
+ # 1. On Linux, bounds the run with `timeout` so a HANG is killed (exit 124)
13
+ # instead of running unbounded → cancelled CI run → RED npm badge.
14
+ # 2. Retries ONCE on the flake — whether it failed fast (epoll_ctl) or hung (124).
15
+ # 3. Propagates any real failure immediately — does NOT mask.
16
+ # macOS/Windows run bare (no flake, no portable `timeout`).
17
+ #
18
+ # Doctrine: targeted retry, not blind retry. Real test failures still fail.
19
+
20
+ set -u
21
+
22
+ TMP=$(mktemp -t faf-tests.XXXXXX)
23
+ trap 'rm -f "$TMP"' EXIT
24
+
25
+ if [ "$(uname)" = "Linux" ] && command -v timeout >/dev/null 2>&1; then
26
+ TIMEOUT="timeout 600"
27
+ else
28
+ TIMEOUT=""
29
+ fi
30
+
31
+ # Capture exit via file + $? (not `| tee` + PIPESTATUS, a bashism that masks the
32
+ # real exit under sh/dash → a timeout-killed hang would read as a false green).
33
+ $TIMEOUT bun test --isolate --timeout=120000 --path-ignore-patterns="**/performance.test.ts" "$@" > "$TMP" 2>&1
34
+ RC=$?
35
+ cat "$TMP"
36
+
37
+ if [ "$RC" -eq 0 ]; then
38
+ exit 0
39
+ fi
40
+
41
+ # Discriminating retry — the epoll flake, whether it fails fast (epoll_ctl in
42
+ # output) or HANGS (timeout kills it, exit 124). Real failures still propagate.
43
+ if grep -q "epoll_ctl" "$TMP" || [ "$RC" -eq 124 ]; then
44
+ echo ""
45
+ echo "============================================================"
46
+ echo "Detected Linux bun --isolate epoll flake (fail or hang) — retrying ONCE."
47
+ echo "============================================================"
48
+ echo ""
49
+ $TIMEOUT bun test --isolate --timeout=120000 --path-ignore-patterns="**/performance.test.ts" "$@"
50
+ exit $?
51
+ fi
52
+
53
+ # Real failure — propagate original exit code, do NOT mask
54
+ exit "$RC"
@@ -1,34 +1,48 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Sync version from package.json to project.faf
4
- * Run: npm run sync-version
5
- * Auto-runs on: npm version (via "version" lifecycle hook)
3
+ * Sync the package.json version to every other stamp that carries it.
4
+ * Run: npm run sync-version (auto on `npm version` via the "version" hook)
5
+ *
6
+ * project.faf project.version
7
+ * server.json top-level version + packages[].version
8
+ * CHANGELOG.md <!-- faf: doc=changelog | latest=vX.Y.Z ... --> meta-stamp
9
+ * docs/index.html the version badge (guarded by wjttc-p0-no-false-hosted-claim)
10
+ * AGENTS.md the "· vX.Y.Z" stamp on the facts line
11
+ *
12
+ * Doc Gate 101 (/pubpro) refuses on any drift between these; this is what
13
+ * keeps them from drifting in the first place.
6
14
  */
7
15
 
8
16
  const fs = require('fs');
9
17
  const path = require('path');
10
18
 
11
- const packageJsonPath = path.join(__dirname, '..', 'package.json');
12
- const projectFafPath = path.join(__dirname, '..', 'project.faf');
19
+ const root = path.join(__dirname, '..');
20
+ const read = (f) => fs.readFileSync(path.join(root, f), 'utf-8');
21
+ const write = (f, s) => fs.writeFileSync(path.join(root, f), s);
22
+ const version = JSON.parse(read('package.json')).version;
23
+ const changed = [];
13
24
 
14
- try {
15
- // Read version from package.json
16
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
17
- const version = packageJson.version;
25
+ function sub(file, pattern, replacement, label) {
26
+ const before = read(file);
27
+ const after = before.replace(pattern, replacement);
28
+ if (after !== before) { write(file, after); changed.push(`${file} (${label})`); }
29
+ else if (!pattern.test(before)) console.warn(`⚠️ ${file}: no ${label} stamp found — nothing synced`);
30
+ }
18
31
 
19
- // Read project.faf
20
- let projectFaf = fs.readFileSync(projectFafPath, 'utf-8');
32
+ try {
33
+ sub('project.faf', /^(\s*version:\s*).+$/m, `$1${version}`, 'project.version');
21
34
 
22
- // Update version field in state section
23
- projectFaf = projectFaf.replace(
24
- /^(\s*version:\s*).+$/m,
25
- `$1${version}`
26
- );
35
+ const serverJson = JSON.parse(read('server.json'));
36
+ let touched = false;
37
+ if (serverJson.version !== version) { serverJson.version = version; touched = true; }
38
+ for (const p of serverJson.packages ?? []) if (p.version !== version) { p.version = version; touched = true; }
39
+ if (touched) { write('server.json', JSON.stringify(serverJson, null, 2) + '\n'); changed.push('server.json (version, packages[].version)'); }
27
40
 
28
- // Write back
29
- fs.writeFileSync(projectFafPath, projectFaf);
41
+ sub('CHANGELOG.md', /(<!-- faf: doc=changelog \| latest=v)\d+\.\d+\.\d+/, `$1${version}`, 'latest= meta-stamp');
42
+ sub('docs/index.html', /(id="versionBadge"[^>]*>[^<]*v)\d+\.\d+\.\d+/, `$1${version}`, 'version badge');
43
+ sub('AGENTS.md', /(·\s*v)\d+\.\d+\.\d+(?=\s*$)/m, `$1${version}`, 'facts-line stamp');
30
44
 
31
- console.log(`Synced project.faf version to ${version}`);
45
+ console.log(changed.length ? `Synced v${version} → ${changed.join(', ')}` : `All stamps already at v${version}`);
32
46
  } catch (error) {
33
47
  console.error('Failed to sync version:', error.message);
34
48
  process.exit(1);
@@ -0,0 +1,40 @@
1
+ ---
2
+ name: faf-ide
3
+ description: Use FAF context and IDE interop tools on this server — score, sync, platform formats; claim equals wire.
4
+ ---
5
+
6
+ # faf-ide
7
+
8
+ Product playbook for **faf-mcp** (`one.faf/faf-mcp`) — IANA `.faf` project context over MCP for Cursor, VS Code, Windsurf, Cline-class hosts.
9
+
10
+ **Transport:** local stdio (`npx` / `bunx faf-mcp`). Skills guide; tools act.
11
+
12
+ ## Tools (call these)
13
+
14
+ | Tool | When |
15
+ |------|------|
16
+ | `faf_auto` | Zero → context in one shot (init, detect, sync, score) |
17
+ | `faf_init` | Create or enhance `project.faf` |
18
+ | `faf_score` | AI-readiness 0–100% + gaps |
19
+ | `faf_context` | Current project context snapshot |
20
+ | `faf_sync` | Reconcile `project.faf` with package.json / git (dry-run; `apply:true` writes) |
21
+ | `faf_bi_sync` | Write CLAUDE.md + IDE format files from `project.faf` |
22
+ | `faf_cursor` | Cursor / `.cursorrules` interop |
23
+ | `faf_agents` | `AGENTS.md` interop |
24
+ | `faf_gemini` | Gemini context interop |
25
+ | `faf_about` | What `.faf` is (format overview) |
26
+
27
+ Default `tools/list` is a curated Core set; more tools may exist when `FAF_TOOLS=all`. Only call tools this server lists.
28
+
29
+ ## Rules
30
+
31
+ 1. Prefer **structured `.faf`** over free-form chat memory for project facts.
32
+ 2. **Claim equals wire** — only tools advertised by this server.
33
+ 3. **No secrets** in skill text or tool args you do not own.
34
+ 4. **Origin** — served by faf-mcp (`skills/*` + `resources/read`); not a remote install authority.
35
+
36
+ ## Flow
37
+
38
+ ```text
39
+ initialize → skills/list → resources/read(skill://faf-ide/SKILL.md) → tools/call
40
+ ```
@@ -1,41 +0,0 @@
1
- /**
2
- * 🏎️ FAF Tool Visibility Configuration - v2.8.0
3
- * Controls which tools are visible (core vs all)
4
- * Championship-grade configuration management
5
- */
6
- export interface VisibilityConfig {
7
- showAdvanced: boolean;
8
- source: 'env' | 'flag' | 'config' | 'default';
9
- }
10
- export interface FafConfig {
11
- showAdvanced?: boolean;
12
- [key: string]: unknown;
13
- }
14
- /**
15
- * Get visibility configuration from multiple sources
16
- * Priority: ENV var > config file > default
17
- */
18
- export declare function getVisibilityConfig(): VisibilityConfig;
19
- /**
20
- * Read configuration from .fafrc file
21
- * Checks multiple locations:
22
- * 1. ~/.fafrc (home directory)
23
- * 2. ./.fafrc (current working directory)
24
- */
25
- export declare function readConfigFile(): FafConfig | null;
26
- /**
27
- * Write configuration to ~/.fafrc file
28
- */
29
- export declare function writeConfigFile(config: FafConfig): boolean;
30
- /**
31
- * Enable advanced tools
32
- */
33
- export declare function enableAdvancedTools(): boolean;
34
- /**
35
- * Disable advanced tools (show core only)
36
- */
37
- export declare function disableAdvancedTools(): boolean;
38
- /**
39
- * Get current tool visibility status (for logging)
40
- */
41
- export declare function getVisibilityStatus(): string;
@@ -1,158 +0,0 @@
1
- "use strict";
2
- /**
3
- * 🏎️ FAF Tool Visibility Configuration - v2.8.0
4
- * Controls which tools are visible (core vs all)
5
- * Championship-grade configuration management
6
- */
7
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
- if (k2 === undefined) k2 = k;
9
- var desc = Object.getOwnPropertyDescriptor(m, k);
10
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
- desc = { enumerable: true, get: function() { return m[k]; } };
12
- }
13
- Object.defineProperty(o, k2, desc);
14
- }) : (function(o, m, k, k2) {
15
- if (k2 === undefined) k2 = k;
16
- o[k2] = m[k];
17
- }));
18
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
- Object.defineProperty(o, "default", { enumerable: true, value: v });
20
- }) : function(o, v) {
21
- o["default"] = v;
22
- });
23
- var __importStar = (this && this.__importStar) || (function () {
24
- var ownKeys = function(o) {
25
- ownKeys = Object.getOwnPropertyNames || function (o) {
26
- var ar = [];
27
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
- return ar;
29
- };
30
- return ownKeys(o);
31
- };
32
- return function (mod) {
33
- if (mod && mod.__esModule) return mod;
34
- var result = {};
35
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
- __setModuleDefault(result, mod);
37
- return result;
38
- };
39
- })();
40
- Object.defineProperty(exports, "__esModule", { value: true });
41
- exports.getVisibilityConfig = getVisibilityConfig;
42
- exports.readConfigFile = readConfigFile;
43
- exports.writeConfigFile = writeConfigFile;
44
- exports.enableAdvancedTools = enableAdvancedTools;
45
- exports.disableAdvancedTools = disableAdvancedTools;
46
- exports.getVisibilityStatus = getVisibilityStatus;
47
- const fs = __importStar(require("fs"));
48
- const path = __importStar(require("path"));
49
- const os = __importStar(require("os"));
50
- /**
51
- * Get visibility configuration from multiple sources
52
- * Priority: ENV var > config file > default
53
- */
54
- function getVisibilityConfig() {
55
- // 1. Check ENV: FAF_MCP_SHOW_ADVANCED=true
56
- if (process.env.FAF_MCP_SHOW_ADVANCED === 'true') {
57
- return { showAdvanced: true, source: 'env' };
58
- }
59
- // 2. Check config file: ~/.fafrc or .fafrc
60
- const configFile = readConfigFile();
61
- if (configFile?.showAdvanced === true) {
62
- return { showAdvanced: true, source: 'config' };
63
- }
64
- // 3. Default: core only (changed from "show all" to align with spec)
65
- // NOTE: For backward compatibility during transition, you may want to
66
- // temporarily set default to `true` and notify users to update config
67
- return { showAdvanced: false, source: 'default' };
68
- }
69
- /**
70
- * Read configuration from .fafrc file
71
- * Checks multiple locations:
72
- * 1. ~/.fafrc (home directory)
73
- * 2. ./.fafrc (current working directory)
74
- */
75
- function readConfigFile() {
76
- const configPaths = [
77
- path.join(os.homedir(), '.fafrc'),
78
- path.join(process.cwd(), '.fafrc'),
79
- ];
80
- for (const configPath of configPaths) {
81
- try {
82
- if (fs.existsSync(configPath)) {
83
- const content = fs.readFileSync(configPath, 'utf-8');
84
- // Support both JSON and simple key=value format
85
- if (content.trim().startsWith('{')) {
86
- // JSON format
87
- return JSON.parse(content);
88
- }
89
- else {
90
- // Simple key=value format
91
- const config = {};
92
- const lines = content.split('\n');
93
- for (const line of lines) {
94
- const trimmed = line.trim();
95
- if (!trimmed || trimmed.startsWith('#'))
96
- continue;
97
- const [key, value] = trimmed.split('=').map((s) => s.trim());
98
- if (key === 'showAdvanced' || key === 'FAF_SHOW_ADVANCED') {
99
- config.showAdvanced = value === 'true';
100
- }
101
- }
102
- return config;
103
- }
104
- }
105
- }
106
- catch (error) {
107
- // Silently ignore config file errors - graceful degradation
108
- // Config file is optional, errors are non-critical
109
- }
110
- }
111
- return null;
112
- }
113
- /**
114
- * Write configuration to ~/.fafrc file
115
- */
116
- function writeConfigFile(config) {
117
- const configPath = path.join(os.homedir(), '.fafrc');
118
- try {
119
- const content = JSON.stringify(config, null, 2);
120
- fs.writeFileSync(configPath, content, 'utf-8');
121
- return true;
122
- }
123
- catch (error) {
124
- // Silent failure - config file write is optional
125
- return false;
126
- }
127
- }
128
- /**
129
- * Enable advanced tools
130
- */
131
- function enableAdvancedTools() {
132
- const config = readConfigFile() || {};
133
- config.showAdvanced = true;
134
- return writeConfigFile(config);
135
- }
136
- /**
137
- * Disable advanced tools (show core only)
138
- */
139
- function disableAdvancedTools() {
140
- const config = readConfigFile() || {};
141
- config.showAdvanced = false;
142
- return writeConfigFile(config);
143
- }
144
- /**
145
- * Get current tool visibility status (for logging)
146
- */
147
- function getVisibilityStatus() {
148
- const config = getVisibilityConfig();
149
- const toolCount = config.showAdvanced ? '51 (ALL)' : '20 (CORE)';
150
- const sourceEmoji = {
151
- env: '🌍',
152
- flag: '🚩',
153
- config: '⚙️',
154
- default: '🏁',
155
- };
156
- return `${sourceEmoji[config.source]} ${toolCount} tools via ${config.source.toUpperCase()}`;
157
- }
158
- //# sourceMappingURL=visibility.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"visibility.js","sourceRoot":"","sources":["../../../src/config/visibility.ts"],"names":[],"mappings":"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"}
@@ -1,21 +0,0 @@
1
- /**
2
- * 🔍 faf audit - Comprehensive Quality Audit (Mk3 Bundled)
3
- * Audit project.faf quality and completeness
4
- */
5
- export interface AuditOptions {
6
- json?: boolean;
7
- verbose?: boolean;
8
- }
9
- export interface AuditResult {
10
- success: boolean;
11
- score: number;
12
- grade: string;
13
- issues: Array<{
14
- severity: 'high' | 'medium' | 'low';
15
- message: string;
16
- fix?: string;
17
- }>;
18
- strengths: string[];
19
- message: string;
20
- }
21
- export declare function auditFafFile(projectPath?: string, options?: AuditOptions): Promise<AuditResult>;
@@ -1,83 +0,0 @@
1
- "use strict";
2
- /**
3
- * 🔍 faf audit - Comprehensive Quality Audit (Mk3 Bundled)
4
- * Audit project.faf quality and completeness
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.auditFafFile = auditFafFile;
8
- const fs_1 = require("fs");
9
- const yaml_1 = require("../fix-once/yaml");
10
- const file_utils_1 = require("../utils/file-utils");
11
- const faf_compiler_1 = require("../compiler/faf-compiler");
12
- async function auditFafFile(projectPath, options = {}) {
13
- try {
14
- const fafPath = projectPath ? `${projectPath}/project.faf` : await (0, file_utils_1.findFafFile)();
15
- if (!fafPath || !await (0, file_utils_1.fileExists)(fafPath)) {
16
- return {
17
- success: false,
18
- score: 0,
19
- grade: 'F',
20
- issues: [{ severity: 'high', message: 'No project.faf file found', fix: 'Run faf init' }],
21
- strengths: [],
22
- message: 'No project.faf file found'
23
- };
24
- }
25
- // Read and parse
26
- const content = await fs_1.promises.readFile(fafPath, 'utf-8');
27
- const fafData = (0, yaml_1.parse)(content);
28
- // Run compiler scoring
29
- const compiler = new faf_compiler_1.FafCompiler();
30
- const scoreResult = await compiler.compile(fafPath);
31
- const issues = [];
32
- const strengths = [];
33
- // Audit checks
34
- if (!fafData.project?.name) {
35
- issues.push({ severity: 'high', message: 'Missing project name', fix: 'Add project.name field' });
36
- }
37
- else {
38
- strengths.push('Project name defined');
39
- }
40
- if (!fafData.project?.goal) {
41
- issues.push({ severity: 'medium', message: 'Missing project goal', fix: 'Add project.goal field' });
42
- }
43
- else {
44
- strengths.push('Project goal defined');
45
- }
46
- if (!fafData.stack?.frontend && !fafData.stack?.backend) {
47
- issues.push({ severity: 'medium', message: 'Stack information incomplete', fix: 'Add stack details' });
48
- }
49
- else {
50
- strengths.push('Stack information present');
51
- }
52
- if (!fafData.instant_context?.what_building) {
53
- issues.push({ severity: 'low', message: 'Missing instant context', fix: 'Add what_building description' });
54
- }
55
- else {
56
- strengths.push('Instant context defined');
57
- }
58
- // Determine grade
59
- const grade = scoreResult.score >= 90 ? 'A' :
60
- scoreResult.score >= 80 ? 'B' :
61
- scoreResult.score >= 70 ? 'C' :
62
- scoreResult.score >= 60 ? 'D' : 'F';
63
- return {
64
- success: true,
65
- score: scoreResult.score,
66
- grade,
67
- issues,
68
- strengths,
69
- message: `Audit complete - Score: ${scoreResult.score}% (Grade: ${grade})`
70
- };
71
- }
72
- catch (error) {
73
- return {
74
- success: false,
75
- score: 0,
76
- grade: 'F',
77
- issues: [{ severity: 'high', message: error instanceof Error ? error.message : 'Audit failed' }],
78
- strengths: [],
79
- message: 'Audit failed'
80
- };
81
- }
82
- }
83
- //# sourceMappingURL=audit.js.map