fodda-mcp 1.46.31 → 1.46.97

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 (289) hide show
  1. package/README.md +14 -94
  2. package/dist/agents/fodda-researcher/skills.d.ts +1 -1
  3. package/dist/agents/fodda-researcher/skills.d.ts.map +1 -1
  4. package/dist/agents/fodda-researcher/skills.js +1 -1
  5. package/dist/brandTemplate.d.ts +1 -1
  6. package/dist/brandTemplate.d.ts.map +1 -1
  7. package/dist/brandTemplate.js +162 -74
  8. package/dist/brandTemplate.js.map +1 -1
  9. package/dist/catalogCache.d.ts +29 -1
  10. package/dist/catalogCache.d.ts.map +1 -1
  11. package/dist/catalogCache.js +267 -16
  12. package/dist/catalogCache.js.map +1 -1
  13. package/dist/coverageRelevance.d.ts +97 -2
  14. package/dist/coverageRelevance.d.ts.map +1 -1
  15. package/dist/coverageRelevance.js +959 -164
  16. package/dist/coverageRelevance.js.map +1 -1
  17. package/dist/editorialFill.d.ts +5 -0
  18. package/dist/editorialFill.d.ts.map +1 -1
  19. package/dist/editorialFill.js +1 -1
  20. package/dist/editorialFill.js.map +1 -1
  21. package/dist/enrichment.d.ts +26 -0
  22. package/dist/enrichment.d.ts.map +1 -1
  23. package/dist/enrichment.js +394 -31
  24. package/dist/enrichment.js.map +1 -1
  25. package/dist/errorHandling.d.ts +35 -7
  26. package/dist/errorHandling.d.ts.map +1 -1
  27. package/dist/errorHandling.js +225 -155
  28. package/dist/errorHandling.js.map +1 -1
  29. package/dist/index.d.ts +25 -0
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +351 -143
  32. package/dist/index.js.map +1 -1
  33. package/dist/jobs/jlens_quarterly_sweep.d.ts +62 -0
  34. package/dist/jobs/jlens_quarterly_sweep.d.ts.map +1 -0
  35. package/dist/jobs/jlens_quarterly_sweep.js +160 -0
  36. package/dist/jobs/jlens_quarterly_sweep.js.map +1 -0
  37. package/dist/pricingCache.d.ts.map +1 -1
  38. package/dist/pricingCache.js +41 -1
  39. package/dist/pricingCache.js.map +1 -1
  40. package/dist/queryCache.d.ts.map +1 -1
  41. package/dist/queryCache.js +2 -0
  42. package/dist/queryCache.js.map +1 -1
  43. package/dist/reportBriefing.d.ts +89 -0
  44. package/dist/reportBriefing.d.ts.map +1 -0
  45. package/dist/reportBriefing.js +662 -0
  46. package/dist/reportBriefing.js.map +1 -0
  47. package/dist/searchTemplate.d.ts.map +1 -1
  48. package/dist/searchTemplate.js +65 -53
  49. package/dist/searchTemplate.js.map +1 -1
  50. package/dist/services/graphRouter.d.ts +7 -0
  51. package/dist/services/graphRouter.d.ts.map +1 -0
  52. package/dist/services/graphRouter.js +7 -0
  53. package/dist/services/graphRouter.js.map +1 -0
  54. package/dist/services/notifications.d.ts +49 -0
  55. package/dist/services/notifications.d.ts.map +1 -0
  56. package/dist/services/notifications.js +206 -0
  57. package/dist/services/notifications.js.map +1 -0
  58. package/dist/sessionTracker.d.ts +19 -2
  59. package/dist/sessionTracker.d.ts.map +1 -1
  60. package/dist/sessionTracker.js +69 -16
  61. package/dist/sessionTracker.js.map +1 -1
  62. package/dist/skillClient.d.ts.map +1 -1
  63. package/dist/skillClient.js +11 -6
  64. package/dist/skillClient.js.map +1 -1
  65. package/dist/svgVisuals.d.ts +17 -19
  66. package/dist/svgVisuals.d.ts.map +1 -1
  67. package/dist/svgVisuals.js +189 -233
  68. package/dist/svgVisuals.js.map +1 -1
  69. package/dist/systemPrompt.d.ts +7 -2
  70. package/dist/systemPrompt.d.ts.map +1 -1
  71. package/dist/systemPrompt.js +110 -68
  72. package/dist/systemPrompt.js.map +1 -1
  73. package/dist/telemetry.d.ts.map +1 -1
  74. package/dist/telemetry.js +15 -0
  75. package/dist/telemetry.js.map +1 -1
  76. package/dist/test_adjacent_trends_polymorphic.d.ts +2 -0
  77. package/dist/test_adjacent_trends_polymorphic.d.ts.map +1 -0
  78. package/dist/test_adjacent_trends_polymorphic.js +154 -0
  79. package/dist/test_adjacent_trends_polymorphic.js.map +1 -0
  80. package/dist/test_book_a_call_live.js +18 -5
  81. package/dist/test_book_a_call_live.js.map +1 -1
  82. package/dist/test_byo_mcp_submission_clarity.d.ts +2 -0
  83. package/dist/test_byo_mcp_submission_clarity.d.ts.map +1 -0
  84. package/dist/test_byo_mcp_submission_clarity.js +142 -0
  85. package/dist/test_byo_mcp_submission_clarity.js.map +1 -0
  86. package/dist/test_capabilities_guidance.d.ts +2 -0
  87. package/dist/test_capabilities_guidance.d.ts.map +1 -0
  88. package/dist/test_capabilities_guidance.js +372 -0
  89. package/dist/test_capabilities_guidance.js.map +1 -0
  90. package/dist/test_client_provenance.d.ts +2 -0
  91. package/dist/test_client_provenance.d.ts.map +1 -0
  92. package/dist/test_client_provenance.js +77 -0
  93. package/dist/test_client_provenance.js.map +1 -0
  94. package/dist/test_connection_surface_cleanup.d.ts +2 -0
  95. package/dist/test_connection_surface_cleanup.d.ts.map +1 -0
  96. package/dist/test_connection_surface_cleanup.js +203 -0
  97. package/dist/test_connection_surface_cleanup.js.map +1 -0
  98. package/dist/test_consult_routing.d.ts +2 -0
  99. package/dist/test_consult_routing.d.ts.map +1 -0
  100. package/dist/test_consult_routing.js +86 -0
  101. package/dist/test_consult_routing.js.map +1 -0
  102. package/dist/test_consult_split.d.ts +2 -0
  103. package/dist/test_consult_split.d.ts.map +1 -0
  104. package/dist/test_consult_split.js +30 -0
  105. package/dist/test_consult_split.js.map +1 -0
  106. package/dist/test_coverage_relevance.js +111 -70
  107. package/dist/test_coverage_relevance.js.map +1 -1
  108. package/dist/test_coverage_replay.d.ts +2 -0
  109. package/dist/test_coverage_replay.d.ts.map +1 -0
  110. package/dist/test_coverage_replay.js +170 -0
  111. package/dist/test_coverage_replay.js.map +1 -0
  112. package/dist/test_dcr_and_legacy_deprecation.js +45 -50
  113. package/dist/test_dcr_and_legacy_deprecation.js.map +1 -1
  114. package/dist/test_demand_signal_logging.d.ts +2 -0
  115. package/dist/test_demand_signal_logging.d.ts.map +1 -0
  116. package/dist/test_demand_signal_logging.js +92 -0
  117. package/dist/test_demand_signal_logging.js.map +1 -0
  118. package/dist/test_earnings_activity_scope.d.ts +5 -0
  119. package/dist/test_earnings_activity_scope.d.ts.map +1 -0
  120. package/dist/test_earnings_activity_scope.js +101 -0
  121. package/dist/test_earnings_activity_scope.js.map +1 -0
  122. package/dist/test_earnings_divergence_live.d.ts +5 -0
  123. package/dist/test_earnings_divergence_live.d.ts.map +1 -0
  124. package/dist/test_earnings_divergence_live.js +135 -0
  125. package/dist/test_earnings_divergence_live.js.map +1 -0
  126. package/dist/test_earnings_hygiene_and_binding.d.ts +5 -0
  127. package/dist/test_earnings_hygiene_and_binding.d.ts.map +1 -0
  128. package/dist/test_earnings_hygiene_and_binding.js +104 -0
  129. package/dist/test_earnings_hygiene_and_binding.js.map +1 -0
  130. package/dist/test_exec_quotes_render.d.ts +2 -0
  131. package/dist/test_exec_quotes_render.d.ts.map +1 -0
  132. package/dist/test_exec_quotes_render.js +86 -0
  133. package/dist/test_exec_quotes_render.js.map +1 -0
  134. package/dist/test_expert_intro.d.ts +2 -0
  135. package/dist/test_expert_intro.d.ts.map +1 -0
  136. package/dist/test_expert_intro.js +57 -0
  137. package/dist/test_expert_intro.js.map +1 -0
  138. package/dist/test_expert_layer.d.ts +11 -0
  139. package/dist/test_expert_layer.d.ts.map +1 -0
  140. package/dist/test_expert_layer.js +356 -0
  141. package/dist/test_expert_layer.js.map +1 -0
  142. package/dist/test_gap_alert.js +8 -0
  143. package/dist/test_gap_alert.js.map +1 -1
  144. package/dist/test_grok_offering_surfaces.d.ts +2 -0
  145. package/dist/test_grok_offering_surfaces.d.ts.map +1 -0
  146. package/dist/test_grok_offering_surfaces.js +155 -0
  147. package/dist/test_grok_offering_surfaces.js.map +1 -0
  148. package/dist/test_human_agent_live.d.ts +2 -0
  149. package/dist/test_human_agent_live.d.ts.map +1 -0
  150. package/dist/test_human_agent_live.js +48 -0
  151. package/dist/test_human_agent_live.js.map +1 -0
  152. package/dist/test_identity_gap.d.ts +2 -0
  153. package/dist/test_identity_gap.d.ts.map +1 -0
  154. package/dist/test_identity_gap.js +171 -0
  155. package/dist/test_identity_gap.js.map +1 -0
  156. package/dist/test_intelligence_and_verifier.d.ts +17 -0
  157. package/dist/test_intelligence_and_verifier.d.ts.map +1 -0
  158. package/dist/test_intelligence_and_verifier.js +162 -0
  159. package/dist/test_intelligence_and_verifier.js.map +1 -0
  160. package/dist/test_latency_mcp_brief5.d.ts +12 -0
  161. package/dist/test_latency_mcp_brief5.d.ts.map +1 -0
  162. package/dist/test_latency_mcp_brief5.js +200 -0
  163. package/dist/test_latency_mcp_brief5.js.map +1 -0
  164. package/dist/test_limit_and_credit_card_capture.d.ts +21 -0
  165. package/dist/test_limit_and_credit_card_capture.d.ts.map +1 -0
  166. package/dist/test_limit_and_credit_card_capture.js +216 -0
  167. package/dist/test_limit_and_credit_card_capture.js.map +1 -0
  168. package/dist/test_list_graphs_topics.js +1 -1
  169. package/dist/test_list_graphs_topics.js.map +1 -1
  170. package/dist/test_live_deployed_mcp_search.d.ts +2 -0
  171. package/dist/test_live_deployed_mcp_search.d.ts.map +1 -0
  172. package/dist/test_live_deployed_mcp_search.js +85 -0
  173. package/dist/test_live_deployed_mcp_search.js.map +1 -0
  174. package/dist/test_live_deployed_split.d.ts +2 -0
  175. package/dist/test_live_deployed_split.d.ts.map +1 -0
  176. package/dist/test_live_deployed_split.js +72 -0
  177. package/dist/test_live_deployed_split.js.map +1 -0
  178. package/dist/test_live_endpoint_runner.js +2 -2
  179. package/dist/test_live_endpoint_runner.js.map +1 -1
  180. package/dist/test_live_mcp.js +1 -1
  181. package/dist/test_live_mcp.js.map +1 -1
  182. package/dist/test_live_neil_widget.d.ts +2 -0
  183. package/dist/test_live_neil_widget.d.ts.map +1 -0
  184. package/dist/test_live_neil_widget.js +84 -0
  185. package/dist/test_live_neil_widget.js.map +1 -0
  186. package/dist/test_longpoll_status.d.ts +2 -0
  187. package/dist/test_longpoll_status.d.ts.map +1 -0
  188. package/dist/test_longpoll_status.js +117 -0
  189. package/dist/test_longpoll_status.js.map +1 -0
  190. package/dist/test_mcp_find_expert_and_vocabulary_routing.d.ts +2 -0
  191. package/dist/test_mcp_find_expert_and_vocabulary_routing.d.ts.map +1 -0
  192. package/dist/test_mcp_find_expert_and_vocabulary_routing.js +130 -0
  193. package/dist/test_mcp_find_expert_and_vocabulary_routing.js.map +1 -0
  194. package/dist/test_next_moves.js +644 -279
  195. package/dist/test_next_moves.js.map +1 -1
  196. package/dist/test_next_moves_transcripts.js +122 -40
  197. package/dist/test_next_moves_transcripts.js.map +1 -1
  198. package/dist/test_on_request_caller_identity.d.ts +13 -0
  199. package/dist/test_on_request_caller_identity.d.ts.map +1 -0
  200. package/dist/test_on_request_caller_identity.js +131 -0
  201. package/dist/test_on_request_caller_identity.js.map +1 -0
  202. package/dist/test_on_request_intercept.d.ts +10 -0
  203. package/dist/test_on_request_intercept.d.ts.map +1 -0
  204. package/dist/test_on_request_intercept.js +95 -0
  205. package/dist/test_on_request_intercept.js.map +1 -0
  206. package/dist/test_onboarding_consent_and_errors.d.ts +2 -0
  207. package/dist/test_onboarding_consent_and_errors.d.ts.map +1 -0
  208. package/dist/test_onboarding_consent_and_errors.js +110 -0
  209. package/dist/test_onboarding_consent_and_errors.js.map +1 -0
  210. package/dist/test_onboarding_live_scenarios.d.ts +2 -0
  211. package/dist/test_onboarding_live_scenarios.d.ts.map +1 -0
  212. package/dist/test_onboarding_live_scenarios.js +189 -0
  213. package/dist/test_onboarding_live_scenarios.js.map +1 -0
  214. package/dist/test_referral_live.d.ts +2 -0
  215. package/dist/test_referral_live.d.ts.map +1 -0
  216. package/dist/test_referral_live.js +33 -0
  217. package/dist/test_referral_live.js.map +1 -0
  218. package/dist/test_referral_piers.d.ts +2 -0
  219. package/dist/test_referral_piers.d.ts.map +1 -0
  220. package/dist/test_referral_piers.js +33 -0
  221. package/dist/test_referral_piers.js.map +1 -0
  222. package/dist/test_report_editorial_briefing.d.ts +21 -0
  223. package/dist/test_report_editorial_briefing.d.ts.map +1 -0
  224. package/dist/test_report_editorial_briefing.js +356 -0
  225. package/dist/test_report_editorial_briefing.js.map +1 -0
  226. package/dist/test_search_graph_quality.d.ts +2 -0
  227. package/dist/test_search_graph_quality.d.ts.map +1 -0
  228. package/dist/test_search_graph_quality.js +493 -0
  229. package/dist/test_search_graph_quality.js.map +1 -0
  230. package/dist/test_service_to_service_auth.d.ts +2 -0
  231. package/dist/test_service_to_service_auth.d.ts.map +1 -0
  232. package/dist/test_service_to_service_auth.js +199 -0
  233. package/dist/test_service_to_service_auth.js.map +1 -0
  234. package/dist/test_sources_live.d.ts +2 -0
  235. package/dist/test_sources_live.d.ts.map +1 -0
  236. package/dist/test_sources_live.js +30 -0
  237. package/dist/test_sources_live.js.map +1 -0
  238. package/dist/test_specialist_and_analyst_tiers.d.ts +2 -0
  239. package/dist/test_specialist_and_analyst_tiers.d.ts.map +1 -0
  240. package/dist/test_specialist_and_analyst_tiers.js +155 -0
  241. package/dist/test_specialist_and_analyst_tiers.js.map +1 -0
  242. package/dist/test_v2_2_visual_hardening.d.ts +5 -0
  243. package/dist/test_v2_2_visual_hardening.d.ts.map +1 -0
  244. package/dist/test_v2_2_visual_hardening.js +333 -0
  245. package/dist/test_v2_2_visual_hardening.js.map +1 -0
  246. package/dist/test_verify_deprecate_render_spec.d.ts +2 -0
  247. package/dist/test_verify_deprecate_render_spec.d.ts.map +1 -0
  248. package/dist/test_verify_deprecate_render_spec.js +217 -0
  249. package/dist/test_verify_deprecate_render_spec.js.map +1 -0
  250. package/dist/test_verify_neil_demo.d.ts +2 -0
  251. package/dist/test_verify_neil_demo.d.ts.map +1 -0
  252. package/dist/test_verify_neil_demo.js +149 -0
  253. package/dist/test_verify_neil_demo.js.map +1 -0
  254. package/dist/test_waitable_research_and_grounded_links.d.ts +2 -0
  255. package/dist/test_waitable_research_and_grounded_links.d.ts.map +1 -0
  256. package/dist/test_waitable_research_and_grounded_links.js +129 -0
  257. package/dist/test_waitable_research_and_grounded_links.js.map +1 -0
  258. package/dist/test_widget_guards.d.ts +2 -0
  259. package/dist/test_widget_guards.d.ts.map +1 -0
  260. package/dist/test_widget_guards.js +229 -0
  261. package/dist/test_widget_guards.js.map +1 -0
  262. package/dist/test_zero_retention_alerts.d.ts +14 -0
  263. package/dist/test_zero_retention_alerts.d.ts.map +1 -0
  264. package/dist/test_zero_retention_alerts.js +76 -0
  265. package/dist/test_zero_retention_alerts.js.map +1 -0
  266. package/dist/toolHandlers.d.ts +38 -1
  267. package/dist/toolHandlers.d.ts.map +1 -1
  268. package/dist/toolHandlers.js +3856 -938
  269. package/dist/toolHandlers.js.map +1 -1
  270. package/dist/tools.d.ts +20 -0
  271. package/dist/tools.d.ts.map +1 -1
  272. package/dist/tools.js +25 -4
  273. package/dist/tools.js.map +1 -1
  274. package/dist/verify_discoverability.d.ts +2 -0
  275. package/dist/verify_discoverability.d.ts.map +1 -0
  276. package/dist/verify_discoverability.js +53 -0
  277. package/dist/verify_discoverability.js.map +1 -0
  278. package/dist/verify_tools_endpoint.js +16 -3
  279. package/dist/verify_tools_endpoint.js.map +1 -1
  280. package/dist/widgetShell.d.ts +2 -2
  281. package/dist/widgetShell.d.ts.map +1 -1
  282. package/dist/widgetShell.js +1 -1
  283. package/dist/widgetShell.js.map +1 -1
  284. package/package.json +1 -1
  285. package/server.json +4 -32
  286. package/dist/oauthRegisterShim.d.ts +0 -13
  287. package/dist/oauthRegisterShim.d.ts.map +0 -1
  288. package/dist/oauthRegisterShim.js +0 -83
  289. package/dist/oauthRegisterShim.js.map +0 -1
@@ -37,6 +37,15 @@ export interface CatalogGraph {
37
37
  skill_phase?: string;
38
38
  skill_tool_name?: string;
39
39
  webpage_url?: string | null;
40
+ core_tension?: string | null | undefined;
41
+ matched_human_twin_slug?: string | null | undefined;
42
+ expert_stance_quote?: string | null | undefined;
43
+ cross_graph_signals?: Array<{
44
+ graph_id: string;
45
+ signal_type: 'validates' | 'contrasts';
46
+ connection_summary: string;
47
+ source_case_study?: string | undefined;
48
+ }> | undefined;
40
49
  }
41
50
  export interface CatalogResponse {
42
51
  version: string;
@@ -44,27 +53,41 @@ export interface CatalogResponse {
44
53
  graph_count: number;
45
54
  graphs: CatalogGraph[];
46
55
  }
56
+ export type AgentCategory = 'human_agent' | 'classic_agent' | 'c_suite_agent' | 'synthetic_agent';
47
57
  export interface CatalogAnalyst {
48
58
  analyst_id: string;
49
59
  name: string;
50
60
  description: string;
61
+ category?: AgentCategory;
62
+ category_label?: string;
63
+ twin_type?: string;
51
64
  type?: string;
52
65
  agent_type?: string;
53
66
  kind?: string;
54
67
  is_digital_twin?: boolean;
55
68
  is_human_agent?: boolean;
69
+ is_classic_agent?: boolean;
70
+ is_c_suite_agent?: boolean;
56
71
  consult_tool?: string;
57
72
  price?: string;
58
73
  offerings?: any[];
59
74
  status?: string;
60
75
  Status?: string;
76
+ expert_in?: string;
77
+ outside_their_lane?: string;
78
+ topics?: string[];
79
+ what_they_offer?: string;
80
+ example_questions?: string[];
81
+ [key: string]: any;
61
82
  }
83
+ export declare function stringifyField(f: any): string;
84
+ export declare function normalizeAnalyst(a: any): CatalogAnalyst;
62
85
  /**
63
86
  * Initialize the catalog cache. Call once at server startup.
64
87
  * Fetches immediately, then sets up hourly refresh.
65
88
  */
66
89
  export declare function initCatalogCache(): Promise<void>;
67
- export declare function setCachedCatalogForTesting(catalog: CatalogResponse, analysts?: CatalogAnalyst[]): void;
90
+ export declare function setCachedCatalogForTesting(catalog: CatalogResponse, analysts?: any[]): void;
68
91
  /**
69
92
  * Get the cached catalog. Returns null if not yet fetched.
70
93
  */
@@ -115,6 +138,11 @@ export declare function buildGraphNamingBlock(): string;
115
138
  * Build a human-friendly display name for a graph.
116
139
  */
117
140
  export declare function buildDisplayName(g: CatalogGraph): string;
141
+ /**
142
+ * Clean display names across MCP surfaces.
143
+ * Removes retired suffixes such as "(Classic Digital Twin)", "(Digital Twin)", etc.
144
+ */
145
+ export declare function cleanDisplayName(name: string | undefined | null): string;
118
146
  /**
119
147
  * Build the GRAPH TYPES block from catalog data.
120
148
  */
@@ -1 +1 @@
1
- {"version":3,"file":"catalogCache.d.ts","sourceRoot":"","sources":["../src/catalogCache.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,YAAY;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,uBAAuB,EAAE,MAAM,CAAC;IAChC,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAChC,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAE3B,0BAA0B,CAAC,EAAE,MAAM,EAAE,CAAC;IACtC,4BAA4B,CAAC,EAAE,MAAM,EAAE,CAAC;IACxC,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,eAAe;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,YAAY,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,GAAG,EAAE,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AA6CD;;;GAGG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CA0BtD;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,eAAe,EAAE,QAAQ,CAAC,EAAE,cAAc,EAAE,GAAG,IAAI,CAKtG;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,eAAe,GAAG,IAAI,CAEnD;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,cAAc,EAAE,CAE9C;AAED;;GAEG;AACH,wBAAgB,SAAS,IAAI,YAAY,EAAE,CAE1C;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAEzE;AAED,wBAAgB,aAAa,IAAI,YAAY,EAAE,CAE9C;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,YAAY,EAAE,CAEhD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,IAAI,YAAY,EAAE,CAEhD;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,YAAY,EAAE,CAE/C;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,OAAO,kBAAkB,EAAE,WAAW,EAAE,CAQ9G;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,GAAG,CAAC,MAAM,CAAC,CAE/C;AAMD;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,YAAY,GAAG,MAAM,CA6BxD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CA4B7C;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAehD;AAkCD;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAOjD;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,IAAI,MAAM,CAgCtD;AA8ID;;GAEG;AACH,wBAAgB,6BAA6B,IAAI,MAAM,CAwBtD;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,IAAI,MAAM,CAEnD;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,IAAI,MAAM,GAAG,IAAI,CAuB1D;AA+OD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE,YAAY,GAAG,MAAM,CAa1E;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,YAAY,GAAG,QAAQ,GAAG,eAAe,GAAG,QAAQ,GAAG,cAAc,GAAG,OAAO,CAiBnH;AAED,MAAM,WAAW,oBAAoB;IACjC,KAAK,EAAE,YAAY,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,QAAQ,GAAG,eAAe,GAAG,QAAQ,GAAG,cAAc,GAAG,OAAO,CAAC;IAC5E,aAAa,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAC7B,KAAK,EAAE,MAAM,EACb,SAAS,GAAE,MAAU,EACrB,SAAS,GAAE,MAAW,EACtB,SAAS,GAAE,MAAa,GACzB,oBAAoB,EAAE,CA6JxB;AAWD,MAAM,MAAM,eAAe,GACrB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,oBAAoB,CAAC,WAAW,CAAC,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC/G;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACtH;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AA4HhF,wBAAgB,oBAAoB,IAAI,IAAI,CAG3C;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAC9B,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACtE,eAAe,EAAE,CA+BnB"}
1
+ {"version":3,"file":"catalogCache.d.ts","sourceRoot":"","sources":["../src/catalogCache.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,100 @@
7
7
  */
8
8
  import axios from 'axios';
9
9
  import { cacheClear } from './queryCache.js';
10
+ export function stringifyField(f) {
11
+ if (!f)
12
+ return '';
13
+ if (typeof f === 'string')
14
+ return f.trim();
15
+ if (Array.isArray(f)) {
16
+ return f.map(item => {
17
+ if (typeof item === 'string')
18
+ return item;
19
+ if (item && typeof item === 'object') {
20
+ return [item.title, item.name, item.description, item.topic].filter(Boolean).join(' ');
21
+ }
22
+ return '';
23
+ }).filter(Boolean).join('. ').trim();
24
+ }
25
+ if (typeof f === 'object') {
26
+ return [f.title, f.name, f.description, f.topic].filter(Boolean).join(' ').trim();
27
+ }
28
+ return String(f);
29
+ }
30
+ export function normalizeAnalyst(a) {
31
+ const analyst_id = String(a.analyst_id || a.id || a.slug || a.name || '').trim();
32
+ const name = cleanDisplayName(String(a.name || a.analyst_id || a.id || a.slug || '').trim());
33
+ const description = stringifyField(a.description || a.bio || a.lens || a.standpoint || '');
34
+ const expert_in = stringifyField(a.expert_in || a.expertIn || a.topic || '');
35
+ const outside_their_lane = stringifyField(a.outside_their_lane || a.outsideTheirLane || a.blind_spots || a.blindSpots || '');
36
+ const topics = Array.isArray(a.topics) ? a.topics : (typeof a.topics === 'string' ? a.topics.split(',').map((s) => s.trim()) : undefined);
37
+ const rawSubType = (a.graphSubType || a.graph_sub_type || a.subType || a.type || a.kind || a.agent_type || '').toString().trim();
38
+ const cleanId = analyst_id.toLowerCase();
39
+ // ── 4-Tier Agent Classification ──
40
+ // 1. C-Suite Agents: corporate executive personas grounded in SEC/earnings
41
+ const is_c_suite = cleanId === 'brand-cmo' || cleanId === 'brand-ceo' || cleanId === 'brand-cfo' ||
42
+ /brand-(cmo|ceo|cfo)/i.test(cleanId) || /c-suite|executive/i.test(rawSubType);
43
+ // 2. Classic Agents: public-domain historical thinkers providing philosophical lenses
44
+ const is_classic = !is_c_suite && (rawSubType === 'Classic Digital Twin' ||
45
+ /classic digital twin/i.test(rawSubType) ||
46
+ a.is_classic_agent === true ||
47
+ a.category === 'classic_agent');
48
+ // 3. Human Agents: real living industry figures with consented digital twins
49
+ const is_human = !is_c_suite && !is_classic && Boolean(rawSubType === 'Digital Twin' ||
50
+ rawSubType === 'human_agent' ||
51
+ rawSubType === 'human_twin' ||
52
+ rawSubType === 'expert_twin' ||
53
+ a.is_human_agent ||
54
+ a.is_digital_twin ||
55
+ a.isVerifiedRealPerson ||
56
+ a.is_verified_real_person ||
57
+ a.type === 'human_agent' ||
58
+ a.type === 'human_twin' ||
59
+ a.kind === 'human_agent' ||
60
+ a.kind === 'human_twin' ||
61
+ a.agent_type === 'human_agent' ||
62
+ a.agent_type === 'human_twin');
63
+ let category = 'synthetic_agent';
64
+ let category_label = 'Synthetic Agent';
65
+ let twin_type = undefined;
66
+ if (is_human) {
67
+ category = 'human_agent';
68
+ category_label = 'Human Agent';
69
+ twin_type = 'Expert Digital Twin';
70
+ }
71
+ else if (is_classic) {
72
+ category = 'classic_agent';
73
+ category_label = 'Classic Agent';
74
+ twin_type = 'Classic Agent';
75
+ }
76
+ else if (is_c_suite) {
77
+ category = 'c_suite_agent';
78
+ category_label = 'C-Suite Agent';
79
+ }
80
+ const slug = a.expertSlug || a.expert_slug || a.slug || a.analyst_id || (is_human ? a.id : undefined);
81
+ const consult_tool = is_human ? 'consult_human_agent' : 'consult_analyst';
82
+ return {
83
+ ...a,
84
+ analyst_id,
85
+ name,
86
+ description,
87
+ category,
88
+ category_label,
89
+ ...(twin_type ? { twin_type } : {}),
90
+ type: category,
91
+ is_human_agent: is_human,
92
+ is_classic_agent: is_classic,
93
+ is_c_suite_agent: is_c_suite,
94
+ is_verified_real_person: is_human,
95
+ consult_tool,
96
+ slug: slug ? String(slug).trim() : undefined,
97
+ ...(expert_in ? { expert_in } : {}),
98
+ ...(outside_their_lane ? { outside_their_lane } : {}),
99
+ ...(topics ? { topics } : {}),
100
+ ...(a.what_they_offer || a.whatTheyOffer || a.askLine ? { what_they_offer: stringifyField(a.what_they_offer || a.whatTheyOffer || a.askLine) } : {}),
101
+ ...(a.example_questions || a.exampleQuestions || a.exampleQueries ? { example_questions: a.example_questions || a.exampleQuestions || a.exampleQueries } : {})
102
+ };
103
+ }
10
104
  // ---------------------------------------------------------------------------
11
105
  // Cache
12
106
  // ---------------------------------------------------------------------------
@@ -34,18 +128,103 @@ async function fetchCatalog() {
34
128
  * Fetch the analysts from the API. Requires internal auth.
35
129
  */
36
130
  async function fetchAnalysts() {
37
- const url = `${API_BASE_URL}/v1/analysts`;
38
- const internalKey = process.env.FODDA_INTERNAL_API_KEY;
131
+ const url = `${API_BASE_URL}/v1/analysts?include=unclaimed`;
132
+ const internalKey = process.env.FODDA_INTERNAL_API_KEY || process.env.FODDA_API_KEY;
39
133
  const headers = internalKey ? { 'Authorization': `Bearer ${internalKey}` } : {};
40
134
  try {
41
135
  const response = await axios.get(url, { headers, timeout: 10000 });
42
- return Array.isArray(response.data) ? response.data : (response.data.analysts || []);
136
+ const raw = Array.isArray(response.data) ? response.data : (response.data.analysts || []);
137
+ return raw.map(normalizeAnalyst);
43
138
  }
44
139
  catch (err) {
45
140
  console.error(`[catalogCache] Failed to fetch analysts: ${err.message}`);
46
141
  return [];
47
142
  }
48
143
  }
144
+ /**
145
+ * Bridges active individual analysts into the searchable graph catalog.
146
+ * Solves the "two-store indexing gap" where an analyst exists in the Analysts table
147
+ * with a backing Neo4j graph, but has no dedicated record in Airtable's Graph List.
148
+ */
149
+ function bridgeAnalystGraphs(catalog, analysts) {
150
+ if (!catalog?.graphs)
151
+ return catalog;
152
+ const existingIds = new Set(catalog.graphs.map(g => (g.graph_id || '').toLowerCase().trim()));
153
+ const bridged = [...catalog.graphs];
154
+ for (const a of analysts) {
155
+ const id = (a.analyst_id || a.id || '').toLowerCase().trim();
156
+ const status = (a.status || a.Status || '').toLowerCase().trim();
157
+ if (!id || (status && status !== 'active'))
158
+ continue;
159
+ // Skip synthetic C-suite leads that already span all graphs
160
+ if (a.is_c_suite_agent || /brand-(cmo|ceo|cfo|analyst)/i.test(id))
161
+ continue;
162
+ // Determine target graph IDs for this analyst:
163
+ // Check backingGraphs first (e.g. 'postpals-expert-graph', 'sic', '2026-macro-trend-graph')
164
+ const candidateGraphIds = new Set();
165
+ const backingList = Array.isArray(a.backingGraphs) ? a.backingGraphs : [];
166
+ for (const rawBg of backingList) {
167
+ const bg = (rawBg || '').toLowerCase().trim();
168
+ if (bg && bg !== '*' && !existingIds.has(bg)) {
169
+ candidateGraphIds.add(bg);
170
+ }
171
+ }
172
+ // If no un-registered backingGraph found, use the analyst ID itself (e.g. 'peter-abraham-bicycles-cycling')
173
+ if (candidateGraphIds.size === 0 && !existingIds.has(id) && !backingList.includes('*')) {
174
+ candidateGraphIds.add(id);
175
+ }
176
+ if (candidateGraphIds.size === 0)
177
+ continue;
178
+ const topics = Array.isArray(a.topics) ? a.topics : [];
179
+ const expertIn = typeof a.expert_in === 'string' ? a.expert_in : '';
180
+ const desc = a.description || a.what_they_offer || expertIn || `${a.name} expert knowledge graph`;
181
+ for (const targetGraphId of candidateGraphIds) {
182
+ bridged.push({
183
+ graph_id: targetGraphId,
184
+ name: a.name,
185
+ description: desc,
186
+ curator: a.name,
187
+ curator_url: '',
188
+ quality_checker_name: '',
189
+ quality_checker_title: '',
190
+ quality_checker_company: '',
191
+ update_frequency: 'Weekly',
192
+ domain: expertIn || 'Specialist Intelligence',
193
+ version: '1.0.0',
194
+ node_types: ['Trend', 'Article'],
195
+ relationship_types: ['HAS_EVIDENCE'],
196
+ graph_type: 'analyst',
197
+ status: 'live',
198
+ trend_count: 5,
199
+ evidence_count: 5,
200
+ last_synced: new Date().toISOString(),
201
+ topics: topics.length > 0 ? topics : [targetGraphId],
202
+ company: a.company || '',
203
+ headline: a.askLine || expertIn || desc,
204
+ subhead: expertIn || '',
205
+ geography: 'Global',
206
+ icon_url: '',
207
+ source_url: '',
208
+ available_as: 'API, MCP',
209
+ is_playground: false,
210
+ last_updated: new Date().toISOString(),
211
+ published_date: null,
212
+ example_queries: Array.isArray(a.example_questions) ? a.example_questions : [],
213
+ portrait_url: a.portrait_url || '',
214
+ core_tension: null,
215
+ matched_human_twin_slug: id,
216
+ expert_stance_quote: null,
217
+ cross_graph_signals: []
218
+ });
219
+ existingIds.add(targetGraphId);
220
+ }
221
+ }
222
+ return {
223
+ ...catalog,
224
+ graph_count: bridged.length,
225
+ graphs: bridged
226
+ };
227
+ }
49
228
  /**
50
229
  * Initialize the catalog cache. Call once at server startup.
51
230
  * Fetches immediately, then sets up hourly refresh.
@@ -53,8 +232,9 @@ async function fetchAnalysts() {
53
232
  export async function initCatalogCache() {
54
233
  try {
55
234
  cacheClear();
56
- cachedCatalog = await fetchCatalog();
235
+ const rawCatalog = await fetchCatalog();
57
236
  cachedAnalysts = await fetchAnalysts();
237
+ cachedCatalog = bridgeAnalystGraphs(rawCatalog, cachedAnalysts);
58
238
  lastFetchedAt = Date.now();
59
239
  rebuildSearchIndex();
60
240
  console.error(`[catalogCache] Loaded ${cachedCatalog.graph_count} graphs from catalog (search index: ${graphSearchTexts.size} entries)`);
@@ -68,8 +248,9 @@ export async function initCatalogCache() {
68
248
  clearInterval(refreshInterval);
69
249
  refreshInterval = setInterval(async () => {
70
250
  try {
71
- cachedCatalog = await fetchCatalog();
251
+ const rawCatalog = await fetchCatalog();
72
252
  cachedAnalysts = await fetchAnalysts();
253
+ cachedCatalog = bridgeAnalystGraphs(rawCatalog, cachedAnalysts);
73
254
  lastFetchedAt = Date.now();
74
255
  rebuildSearchIndex();
75
256
  console.error(`[catalogCache] Refreshed catalog — ${cachedCatalog.graph_count} graphs (search index rebuilt) and ${cachedAnalysts.length} analysts`);
@@ -80,9 +261,9 @@ export async function initCatalogCache() {
80
261
  }, CATALOG_REFRESH_MS);
81
262
  }
82
263
  export function setCachedCatalogForTesting(catalog, analysts) {
83
- cachedCatalog = catalog;
84
264
  if (analysts)
85
- cachedAnalysts = analysts;
265
+ cachedAnalysts = analysts.map(normalizeAnalyst);
266
+ cachedCatalog = bridgeAnalystGraphs(catalog, cachedAnalysts);
86
267
  lastFetchedAt = Date.now();
87
268
  rebuildSearchIndex();
88
269
  }
@@ -192,6 +373,18 @@ export function buildDisplayName(g) {
192
373
  }
193
374
  return g.name;
194
375
  }
376
+ /**
377
+ * Clean display names across MCP surfaces.
378
+ * Removes retired suffixes such as "(Classic Digital Twin)", "(Digital Twin)", etc.
379
+ */
380
+ export function cleanDisplayName(name) {
381
+ if (!name || typeof name !== 'string')
382
+ return '';
383
+ return name
384
+ .replace(/\s*[\(\[]\s*(?:Classic\s+|Expert\s+|Human\s+)?(?:Digital\s+)?Twin\s*[\)\]]/gi, '')
385
+ .replace(/\s*[\(\[]\s*(?:Classic|Human|Synthetic|C-Suite)\s+Agent\s*[\)\]]/gi, '')
386
+ .trim();
387
+ }
195
388
  /**
196
389
  * Build the GRAPH TYPES block from catalog data.
197
390
  */
@@ -592,8 +785,30 @@ const QUERY_EXPANSION_MAP = {
592
785
  // Pet & Animal Care
593
786
  pet: ['pet', 'cpg', 'food', 'wellness', 'retail'],
594
787
  pets: ['pet', 'cpg', 'food', 'wellness', 'retail'],
595
- dog: ['pet', 'cpg', 'food', 'wellness'],
596
- cat: ['pet', 'cpg', 'food', 'wellness'],
788
+ dog: ['pet', 'cpg', 'food', 'wellness', 'retail'],
789
+ dogs: ['pet', 'cpg', 'food', 'wellness', 'retail'],
790
+ cat: ['pet', 'cpg', 'food', 'wellness', 'retail'],
791
+ cats: ['pet', 'cpg', 'food', 'wellness', 'retail'],
792
+ petfood: ['pet', 'cpg', 'food', 'wellness', 'retail'],
793
+ // Marketing, Experiential & Activations
794
+ activation: ['retail', 'cpg', 'marketing', 'brand', 'experience', 'hospitality', 'culture'],
795
+ activations: ['retail', 'cpg', 'marketing', 'brand', 'experience', 'hospitality', 'culture'],
796
+ experiential: ['retail', 'cpg', 'marketing', 'brand', 'experience', 'hospitality', 'culture', 'design'],
797
+ popup: ['retail', 'cpg', 'fashion', 'experience', 'design'],
798
+ popups: ['retail', 'cpg', 'fashion', 'experience', 'design'],
799
+ sampling: ['cpg', 'retail', 'food', 'beverage', 'beauty', 'experience'],
800
+ sponsorship: ['marketing', 'brand', 'culture', 'retail', 'entertainment'],
801
+ installation: ['retail', 'design', 'art', 'experience', 'culture'],
802
+ flagship: ['retail', 'fashion', 'design', 'experience', 'brand'],
803
+ immersive: ['retail', 'experience', 'design', 'entertainment', 'technology'],
804
+ stunt: ['marketing', 'brand', 'culture', 'retail'],
805
+ showcase: ['retail', 'design', 'experience', 'marketing'],
806
+ marketing: ['retail', 'cpg', 'brand', 'strategy', 'advertising', 'culture'],
807
+ campaign: ['marketing', 'brand', 'advertising', 'retail', 'cpg'],
808
+ advertising: ['marketing', 'brand', 'media', 'retail', 'cpg'],
809
+ promo: ['marketing', 'retail', 'cpg', 'promotion'],
810
+ promotion: ['marketing', 'retail', 'cpg', 'promotion'],
811
+ hospitality: ['hospitality', 'hotel', 'dining', 'food', 'experience', 'leisure', 'culture'],
597
812
  // Tech, AI & SaaS
598
813
  ai: ['technology', 'ai', 'software', 'enterprise', 'innovation'],
599
814
  saas: ['technology', 'software', 'enterprise', 'b2b'],
@@ -623,12 +838,15 @@ function scoreClauseRelevance(clause, g) {
623
838
  const searchText = graphSearchTexts.get(g.graph_id) || buildSearchableText(g);
624
839
  const topicsText = [...(g.topics || []), ...(g.routing_keywords || []), g.name || '', g.graph_id || ''].join(' ').toLowerCase();
625
840
  const domainText = (g.domain || '').toLowerCase();
841
+ const words = new Set(searchText.split(/[^a-z0-9]+/));
842
+ const topicWords = new Set(topicsText.split(/[^a-z0-9]+/));
843
+ const domainWords = new Set(domainText.split(/[^a-z0-9]+/));
626
844
  let matchedTerms = 0;
627
845
  let highValueMatches = 0;
628
846
  for (const term of terms) {
629
- if (searchText.includes(term)) {
847
+ if (words.has(term)) {
630
848
  matchedTerms++;
631
- if (topicsText.includes(term) || domainText.includes(term)) {
849
+ if (topicWords.has(term) || domainWords.has(term)) {
632
850
  highValueMatches++;
633
851
  }
634
852
  }
@@ -649,9 +867,9 @@ function scoreClauseRelevance(clause, g) {
649
867
  let expMatches = 0;
650
868
  let expHighValueMatches = 0;
651
869
  for (const exp of expandedSet) {
652
- if (searchText.includes(exp)) {
870
+ if (words.has(exp)) {
653
871
  expMatches++;
654
- if (topicsText.includes(exp) || domainText.includes(exp)) {
872
+ if (topicWords.has(exp) || domainWords.has(exp)) {
655
873
  expHighValueMatches++;
656
874
  }
657
875
  }
@@ -686,6 +904,18 @@ function scoreClauseRelevance(clause, g) {
686
904
  finalScore = Math.min(finalScore, 0.40); // Cap generic agency floor
687
905
  }
688
906
  }
907
+ // Experiential & Activation Tactic Boost
908
+ const experientialTerms = new Set([
909
+ 'activation', 'activations', 'experiential', 'popup', 'popups', 'sampling',
910
+ 'installation', 'flagship', 'immersive', 'stunt', 'showcase'
911
+ ]);
912
+ const queryHasExperiential = terms.some(t => experientialTerms.has(t));
913
+ if (queryHasExperiential) {
914
+ const isExperienceGraph = /retail|cpg|brand|marketing|experience|culture|hospitality/i.test(g.graph_id + ' ' + (g.domain || '') + ' ' + (g.topics || []).join(' ') + ' ' + (g.routing_keywords || []).join(' '));
915
+ if (isExperienceGraph || g.graph_id === 'retail') {
916
+ finalScore += 0.20; // Experiential Format Boost
917
+ }
918
+ }
689
919
  // Generalized Narrow-Domain Mismatch Penalty
690
920
  const narrowDomains = ['beauty', 'gaming', 'automotive', 'fashion'];
691
921
  for (const dom of narrowDomains) {
@@ -773,9 +1003,30 @@ export function getRelevantGraphs(query, minGraphs = 4, maxGraphs = 15, threshol
773
1003
  if (skippedShells > 0) {
774
1004
  console.error(`[graphRouter] Skipped ${skippedShells} unsynced graph shell(s) (trend_count=0, last_synced=null): ${shellGraphs.map(g => g.graph_id).join(', ')}`);
775
1005
  }
776
- // ── Phase 0: Direct name matching ──
1006
+ // ── Phase 0: Direct name matching & phrase routing overrides ──
777
1007
  const queryLower = query.toLowerCase();
778
1008
  const directMatchIds = new Set();
1009
+ const isCreatorQuery = /creator economy|content creator|creator monetization|creators report/i.test(queryLower);
1010
+ const isNightlifeQuery = /nightlife|going out|shared experiences|shared social experiences/i.test(queryLower);
1011
+ const eligibleGraphs = syncedGraphs.filter(g => {
1012
+ if (isCreatorQuery && g.graph_id === 'mary-shelley')
1013
+ return false;
1014
+ return true;
1015
+ });
1016
+ if (isCreatorQuery) {
1017
+ for (const g of eligibleGraphs) {
1018
+ if (g.graph_id === 'visa-creators_report-2025' || g.graph_id.includes('youtube') || g.graph_id.includes('tiktok')) {
1019
+ directMatchIds.add(g.graph_id);
1020
+ }
1021
+ }
1022
+ }
1023
+ if (isNightlifeQuery) {
1024
+ for (const g of eligibleGraphs) {
1025
+ if (g.graph_id.includes('bompasparr')) {
1026
+ directMatchIds.add(g.graph_id);
1027
+ }
1028
+ }
1029
+ }
779
1030
  const matchesWordBoundary = (text, term) => {
780
1031
  if (!term || term.length < 3)
781
1032
  return false;
@@ -790,7 +1041,7 @@ export function getRelevantGraphs(query, minGraphs = 4, maxGraphs = 15, threshol
790
1041
  const rx = new RegExp(`\\b${escaped}\\b`, 'i');
791
1042
  return rx.test(text);
792
1043
  };
793
- for (const g of syncedGraphs) {
1044
+ for (const g of eligibleGraphs) {
794
1045
  // Check graph_id (e.g., "alyson-stevens-macro", "sic")
795
1046
  if (g.graph_id.length > 3 && matchesWordBoundary(queryLower, g.graph_id)) {
796
1047
  directMatchIds.add(g.graph_id);
@@ -832,7 +1083,7 @@ export function getRelevantGraphs(query, minGraphs = 4, maxGraphs = 15, threshol
832
1083
  console.error(`[graphRouter] Phase 0 direct name matches: ${[...directMatchIds].join(', ')}`);
833
1084
  }
834
1085
  // Score ALL graph types together — domain, expert, industry report compete on merit
835
- const scored = syncedGraphs.map(g => {
1086
+ const scored = eligibleGraphs.map(g => {
836
1087
  const isDirect = directMatchIds.has(g.graph_id);
837
1088
  return {
838
1089
  graph: g,