webmcp-cli 1.2.2 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (330) hide show
  1. package/dist/analysis/form-to-tool-mapper.d.ts +61 -0
  2. package/dist/analysis/form-to-tool-mapper.js +360 -0
  3. package/dist/analysis/form-to-tool-mapper.js.map +1 -0
  4. package/dist/analysis/index.d.ts +84 -0
  5. package/dist/analysis/index.js +81 -0
  6. package/dist/analysis/index.js.map +1 -0
  7. package/dist/analysis/missing-tool-analyzer.d.ts +35 -0
  8. package/dist/analysis/missing-tool-analyzer.js +617 -0
  9. package/dist/analysis/missing-tool-analyzer.js.map +1 -0
  10. package/dist/audit/run-multi-page-audit.d.ts +34 -0
  11. package/dist/audit/run-multi-page-audit.js +233 -0
  12. package/dist/audit/run-multi-page-audit.js.map +1 -0
  13. package/dist/cli/commands/potential.d.ts +8 -0
  14. package/dist/cli/commands/potential.js +323 -0
  15. package/dist/cli/commands/potential.js.map +1 -0
  16. package/dist/cli/commands/report.d.ts +12 -0
  17. package/dist/cli/commands/report.js +89 -0
  18. package/dist/cli/commands/report.js.map +1 -0
  19. package/dist/cli/index.js +35 -0
  20. package/dist/cli/index.js.map +1 -1
  21. package/dist/config/defaults.d.ts +36 -0
  22. package/dist/config/defaults.js +33 -0
  23. package/dist/config/defaults.js.map +1 -0
  24. package/dist/config/index.d.ts +7 -0
  25. package/dist/config/index.js +7 -0
  26. package/dist/config/index.js.map +1 -0
  27. package/dist/config/loader.d.ts +22 -0
  28. package/dist/config/loader.js +91 -0
  29. package/dist/config/loader.js.map +1 -0
  30. package/dist/config/schema.d.ts +280 -0
  31. package/dist/config/schema.js +42 -0
  32. package/dist/config/schema.js.map +1 -0
  33. package/dist/core/types/audit.d.ts +1 -1
  34. package/dist/core/types/index.d.ts +1 -0
  35. package/dist/core/types/index.js +1 -0
  36. package/dist/core/types/index.js.map +1 -1
  37. package/dist/core/types/recon.d.ts +265 -0
  38. package/dist/core/types/recon.js +5 -0
  39. package/dist/core/types/recon.js.map +1 -0
  40. package/dist/core/types/rule.d.ts +1 -1
  41. package/dist/core/types/rule.js +7 -5
  42. package/dist/core/types/rule.js.map +1 -1
  43. package/dist/crawler/depth-crawler.d.ts +29 -0
  44. package/dist/crawler/depth-crawler.js +212 -0
  45. package/dist/crawler/depth-crawler.js.map +1 -0
  46. package/dist/crawler/index.d.ts +2 -0
  47. package/dist/crawler/index.js +3 -0
  48. package/dist/crawler/index.js.map +1 -0
  49. package/dist/crawler/link-extractor.d.ts +1 -0
  50. package/dist/crawler/link-extractor.js +49 -0
  51. package/dist/crawler/link-extractor.js.map +1 -0
  52. package/dist/generators/index.d.ts +10 -0
  53. package/dist/generators/index.js +8 -0
  54. package/dist/generators/index.js.map +1 -0
  55. package/dist/generators/report-html.d.ts +12 -0
  56. package/dist/generators/report-html.js +470 -0
  57. package/dist/generators/report-html.js.map +1 -0
  58. package/dist/generators/report-json.d.ts +95 -0
  59. package/dist/generators/report-json.js +144 -0
  60. package/dist/generators/report-json.js.map +1 -0
  61. package/dist/generators/report-manager.d.ts +31 -0
  62. package/dist/generators/report-manager.js +208 -0
  63. package/dist/generators/report-manager.js.map +1 -0
  64. package/dist/generators/tool-code-generator.d.ts +31 -0
  65. package/dist/generators/tool-code-generator.js +201 -0
  66. package/dist/generators/tool-code-generator.js.map +1 -0
  67. package/dist/potential/ai-recommender.d.ts +33 -0
  68. package/dist/potential/ai-recommender.js +414 -0
  69. package/dist/potential/ai-recommender.js.map +1 -0
  70. package/dist/potential/analyzer.d.ts +32 -0
  71. package/dist/potential/analyzer.js +383 -0
  72. package/dist/potential/analyzer.js.map +1 -0
  73. package/dist/potential/index.d.ts +3 -0
  74. package/dist/potential/index.js +4 -0
  75. package/dist/potential/index.js.map +1 -0
  76. package/dist/potential/prompts.d.ts +20 -0
  77. package/dist/potential/prompts.js +42 -0
  78. package/dist/potential/prompts.js.map +1 -0
  79. package/dist/potential/types.d.ts +40 -0
  80. package/dist/potential/types.js +2 -0
  81. package/dist/potential/types.js.map +1 -0
  82. package/dist/recon/index.d.ts +20 -0
  83. package/dist/recon/index.js +143 -0
  84. package/dist/recon/index.js.map +1 -0
  85. package/dist/recon/manifest.d.ts +16 -0
  86. package/dist/recon/manifest.js +108 -0
  87. package/dist/recon/manifest.js.map +1 -0
  88. package/dist/recon/meta-extractor.d.ts +11 -0
  89. package/dist/recon/meta-extractor.js +276 -0
  90. package/dist/recon/meta-extractor.js.map +1 -0
  91. package/dist/recon/robots.d.ts +16 -0
  92. package/dist/recon/robots.js +158 -0
  93. package/dist/recon/robots.js.map +1 -0
  94. package/dist/recon/route-discovery.d.ts +25 -0
  95. package/dist/recon/route-discovery.js +303 -0
  96. package/dist/recon/route-discovery.js.map +1 -0
  97. package/dist/recon/sitemap.d.ts +12 -0
  98. package/dist/recon/sitemap.js +177 -0
  99. package/dist/recon/sitemap.js.map +1 -0
  100. package/dist/rules/accessibility/AXE-001.d.ts +9 -0
  101. package/dist/rules/accessibility/AXE-001.js +109 -0
  102. package/dist/rules/accessibility/AXE-001.js.map +1 -0
  103. package/dist/rules/accessibility/AXE-002.d.ts +8 -0
  104. package/dist/rules/accessibility/AXE-002.js +85 -0
  105. package/dist/rules/accessibility/AXE-002.js.map +1 -0
  106. package/dist/rules/accessibility/AXE-003.d.ts +8 -0
  107. package/dist/rules/accessibility/AXE-003.js +94 -0
  108. package/dist/rules/accessibility/AXE-003.js.map +1 -0
  109. package/dist/rules/accessibility/AXE-004.d.ts +8 -0
  110. package/dist/rules/accessibility/AXE-004.js +101 -0
  111. package/dist/rules/accessibility/AXE-004.js.map +1 -0
  112. package/dist/rules/accessibility/AXE-005.d.ts +9 -0
  113. package/dist/rules/accessibility/AXE-005.js +89 -0
  114. package/dist/rules/accessibility/AXE-005.js.map +1 -0
  115. package/dist/rules/best-practices/BP-004.d.ts +9 -0
  116. package/dist/rules/best-practices/BP-004.js +96 -0
  117. package/dist/rules/best-practices/BP-004.js.map +1 -0
  118. package/dist/rules/best-practices/BP-005.d.ts +8 -0
  119. package/dist/rules/best-practices/BP-005.js +94 -0
  120. package/dist/rules/best-practices/BP-005.js.map +1 -0
  121. package/dist/rules/best-practices/BP-006.d.ts +8 -0
  122. package/dist/rules/best-practices/BP-006.js +80 -0
  123. package/dist/rules/best-practices/BP-006.js.map +1 -0
  124. package/dist/rules/best-practices/BP-007.d.ts +8 -0
  125. package/dist/rules/best-practices/BP-007.js +92 -0
  126. package/dist/rules/best-practices/BP-007.js.map +1 -0
  127. package/dist/rules/best-practices/BP-008.d.ts +12 -0
  128. package/dist/rules/best-practices/BP-008.js +86 -0
  129. package/dist/rules/best-practices/BP-008.js.map +1 -0
  130. package/dist/rules/best-practices/BP-009.d.ts +9 -0
  131. package/dist/rules/best-practices/BP-009.js +77 -0
  132. package/dist/rules/best-practices/BP-009.js.map +1 -0
  133. package/dist/rules/best-practices/BP-010.d.ts +8 -0
  134. package/dist/rules/best-practices/BP-010.js +85 -0
  135. package/dist/rules/best-practices/BP-010.js.map +1 -0
  136. package/dist/rules/coverage/COV-002.d.ts +8 -0
  137. package/dist/rules/coverage/COV-002.js +68 -0
  138. package/dist/rules/coverage/COV-002.js.map +1 -0
  139. package/dist/rules/coverage/COV-003.d.ts +8 -0
  140. package/dist/rules/coverage/COV-003.js +68 -0
  141. package/dist/rules/coverage/COV-003.js.map +1 -0
  142. package/dist/rules/coverage/COV-004.d.ts +8 -0
  143. package/dist/rules/coverage/COV-004.js +89 -0
  144. package/dist/rules/coverage/COV-004.js.map +1 -0
  145. package/dist/rules/coverage/COV-005.d.ts +8 -0
  146. package/dist/rules/coverage/COV-005.js +67 -0
  147. package/dist/rules/coverage/COV-005.js.map +1 -0
  148. package/dist/rules/coverage/COV-006.d.ts +9 -0
  149. package/dist/rules/coverage/COV-006.js +76 -0
  150. package/dist/rules/coverage/COV-006.js.map +1 -0
  151. package/dist/rules/coverage/COV-007.d.ts +8 -0
  152. package/dist/rules/coverage/COV-007.js +67 -0
  153. package/dist/rules/coverage/COV-007.js.map +1 -0
  154. package/dist/rules/coverage/COV-008.d.ts +9 -0
  155. package/dist/rules/coverage/COV-008.js +87 -0
  156. package/dist/rules/coverage/COV-008.js.map +1 -0
  157. package/dist/rules/coverage/COV-009.d.ts +8 -0
  158. package/dist/rules/coverage/COV-009.js +73 -0
  159. package/dist/rules/coverage/COV-009.js.map +1 -0
  160. package/dist/rules/coverage/COV-010.d.ts +9 -0
  161. package/dist/rules/coverage/COV-010.js +82 -0
  162. package/dist/rules/coverage/COV-010.js.map +1 -0
  163. package/dist/rules/description/DESC-001.d.ts +9 -0
  164. package/dist/rules/description/DESC-001.js +88 -0
  165. package/dist/rules/description/DESC-001.js.map +1 -0
  166. package/dist/rules/description/DESC-002.d.ts +10 -0
  167. package/dist/rules/description/DESC-002.js +99 -0
  168. package/dist/rules/description/DESC-002.js.map +1 -0
  169. package/dist/rules/description/DESC-006.d.ts +9 -0
  170. package/dist/rules/description/DESC-006.js +78 -0
  171. package/dist/rules/description/DESC-006.js.map +1 -0
  172. package/dist/rules/description/DESC-007.d.ts +9 -0
  173. package/dist/rules/description/DESC-007.js +70 -0
  174. package/dist/rules/description/DESC-007.js.map +1 -0
  175. package/dist/rules/description/DESC-008.d.ts +9 -0
  176. package/dist/rules/description/DESC-008.js +70 -0
  177. package/dist/rules/description/DESC-008.js.map +1 -0
  178. package/dist/rules/description/DESC-009.d.ts +8 -0
  179. package/dist/rules/description/DESC-009.js +55 -0
  180. package/dist/rules/description/DESC-009.js.map +1 -0
  181. package/dist/rules/description/DESC-010.d.ts +9 -0
  182. package/dist/rules/description/DESC-010.js +92 -0
  183. package/dist/rules/description/DESC-010.js.map +1 -0
  184. package/dist/rules/description/DESC-011.d.ts +9 -0
  185. package/dist/rules/description/DESC-011.js +81 -0
  186. package/dist/rules/description/DESC-011.js.map +1 -0
  187. package/dist/rules/description/DESC-012.d.ts +9 -0
  188. package/dist/rules/description/DESC-012.js +98 -0
  189. package/dist/rules/description/DESC-012.js.map +1 -0
  190. package/dist/rules/implementation/IMP-002.d.ts +9 -0
  191. package/dist/rules/implementation/IMP-002.js +59 -0
  192. package/dist/rules/implementation/IMP-002.js.map +1 -0
  193. package/dist/rules/implementation/IMP-006.d.ts +9 -0
  194. package/dist/rules/implementation/IMP-006.js +48 -0
  195. package/dist/rules/implementation/IMP-006.js.map +1 -0
  196. package/dist/rules/implementation/IMP-008.d.ts +9 -0
  197. package/dist/rules/implementation/IMP-008.js +46 -0
  198. package/dist/rules/implementation/IMP-008.js.map +1 -0
  199. package/dist/rules/implementation/IMP-009.d.ts +9 -0
  200. package/dist/rules/implementation/IMP-009.js +48 -0
  201. package/dist/rules/implementation/IMP-009.js.map +1 -0
  202. package/dist/rules/implementation/IMP-010.d.ts +9 -0
  203. package/dist/rules/implementation/IMP-010.js +66 -0
  204. package/dist/rules/implementation/IMP-010.js.map +1 -0
  205. package/dist/rules/implementation/IMP-011.d.ts +9 -0
  206. package/dist/rules/implementation/IMP-011.js +82 -0
  207. package/dist/rules/implementation/IMP-011.js.map +1 -0
  208. package/dist/rules/implementation/IMP-012.d.ts +9 -0
  209. package/dist/rules/implementation/IMP-012.js +88 -0
  210. package/dist/rules/implementation/IMP-012.js.map +1 -0
  211. package/dist/rules/implementation/IMP-014.d.ts +9 -0
  212. package/dist/rules/implementation/IMP-014.js +58 -0
  213. package/dist/rules/implementation/IMP-014.js.map +1 -0
  214. package/dist/rules/implementation/IMP-015.d.ts +9 -0
  215. package/dist/rules/implementation/IMP-015.js +64 -0
  216. package/dist/rules/implementation/IMP-015.js.map +1 -0
  217. package/dist/rules/implementation/IMP-016.d.ts +9 -0
  218. package/dist/rules/implementation/IMP-016.js +52 -0
  219. package/dist/rules/implementation/IMP-016.js.map +1 -0
  220. package/dist/rules/implementation/IMP-017.d.ts +8 -0
  221. package/dist/rules/implementation/IMP-017.js +51 -0
  222. package/dist/rules/implementation/IMP-017.js.map +1 -0
  223. package/dist/rules/implementation/IMP-018.d.ts +8 -0
  224. package/dist/rules/implementation/IMP-018.js +52 -0
  225. package/dist/rules/implementation/IMP-018.js.map +1 -0
  226. package/dist/rules/implementation/IMP-019.d.ts +8 -0
  227. package/dist/rules/implementation/IMP-019.js +53 -0
  228. package/dist/rules/implementation/IMP-019.js.map +1 -0
  229. package/dist/rules/implementation/IMP-020.d.ts +9 -0
  230. package/dist/rules/implementation/IMP-020.js +62 -0
  231. package/dist/rules/implementation/IMP-020.js.map +1 -0
  232. package/dist/rules/implementation/IMP-021.d.ts +8 -0
  233. package/dist/rules/implementation/IMP-021.js +64 -0
  234. package/dist/rules/implementation/IMP-021.js.map +1 -0
  235. package/dist/rules/implementation/IMP-022.d.ts +8 -0
  236. package/dist/rules/implementation/IMP-022.js +70 -0
  237. package/dist/rules/implementation/IMP-022.js.map +1 -0
  238. package/dist/rules/index.d.ts +73 -6
  239. package/dist/rules/index.js +141 -6
  240. package/dist/rules/index.js.map +1 -1
  241. package/dist/rules/schema/SCHEMA-004.d.ts +9 -0
  242. package/dist/rules/schema/SCHEMA-004.js +57 -0
  243. package/dist/rules/schema/SCHEMA-004.js.map +1 -0
  244. package/dist/rules/schema/SCHEMA-005.d.ts +9 -0
  245. package/dist/rules/schema/SCHEMA-005.js +61 -0
  246. package/dist/rules/schema/SCHEMA-005.js.map +1 -0
  247. package/dist/rules/schema/SCHEMA-006.d.ts +10 -0
  248. package/dist/rules/schema/SCHEMA-006.js +85 -0
  249. package/dist/rules/schema/SCHEMA-006.js.map +1 -0
  250. package/dist/rules/schema/SCHEMA-007.d.ts +9 -0
  251. package/dist/rules/schema/SCHEMA-007.js +73 -0
  252. package/dist/rules/schema/SCHEMA-007.js.map +1 -0
  253. package/dist/rules/schema/SCHEMA-008.d.ts +9 -0
  254. package/dist/rules/schema/SCHEMA-008.js +70 -0
  255. package/dist/rules/schema/SCHEMA-008.js.map +1 -0
  256. package/dist/rules/schema/SCHEMA-009.d.ts +10 -0
  257. package/dist/rules/schema/SCHEMA-009.js +80 -0
  258. package/dist/rules/schema/SCHEMA-009.js.map +1 -0
  259. package/dist/rules/schema/SCHEMA-010.d.ts +9 -0
  260. package/dist/rules/schema/SCHEMA-010.js +96 -0
  261. package/dist/rules/schema/SCHEMA-010.js.map +1 -0
  262. package/dist/rules/schema/SCHEMA-012.d.ts +9 -0
  263. package/dist/rules/schema/SCHEMA-012.js +65 -0
  264. package/dist/rules/schema/SCHEMA-012.js.map +1 -0
  265. package/dist/rules/security/SEC-002.d.ts +8 -0
  266. package/dist/rules/security/SEC-002.js +81 -0
  267. package/dist/rules/security/SEC-002.js.map +1 -0
  268. package/dist/rules/security/SEC-003.d.ts +8 -0
  269. package/dist/rules/security/SEC-003.js +85 -0
  270. package/dist/rules/security/SEC-003.js.map +1 -0
  271. package/dist/rules/security/SEC-004.d.ts +9 -0
  272. package/dist/rules/security/SEC-004.js +87 -0
  273. package/dist/rules/security/SEC-004.js.map +1 -0
  274. package/dist/rules/security/SEC-005.d.ts +8 -0
  275. package/dist/rules/security/SEC-005.js +87 -0
  276. package/dist/rules/security/SEC-005.js.map +1 -0
  277. package/dist/rules/security/SEC-006.d.ts +10 -0
  278. package/dist/rules/security/SEC-006.js +108 -0
  279. package/dist/rules/security/SEC-006.js.map +1 -0
  280. package/dist/rules/security/SEC-007.d.ts +9 -0
  281. package/dist/rules/security/SEC-007.js +108 -0
  282. package/dist/rules/security/SEC-007.js.map +1 -0
  283. package/dist/rules/security/SEC-008.d.ts +8 -0
  284. package/dist/rules/security/SEC-008.js +109 -0
  285. package/dist/rules/security/SEC-008.js.map +1 -0
  286. package/dist/rules/security/SEC-009.d.ts +9 -0
  287. package/dist/rules/security/SEC-009.js +93 -0
  288. package/dist/rules/security/SEC-009.js.map +1 -0
  289. package/dist/rules/security/SEC-010.d.ts +8 -0
  290. package/dist/rules/security/SEC-010.js +78 -0
  291. package/dist/rules/security/SEC-010.js.map +1 -0
  292. package/dist/rules/security/SEC-011.d.ts +8 -0
  293. package/dist/rules/security/SEC-011.js +93 -0
  294. package/dist/rules/security/SEC-011.js.map +1 -0
  295. package/dist/rules/security/SEC-012.d.ts +8 -0
  296. package/dist/rules/security/SEC-012.js +79 -0
  297. package/dist/rules/security/SEC-012.js.map +1 -0
  298. package/dist/rules/security/SEC-013.d.ts +9 -0
  299. package/dist/rules/security/SEC-013.js +107 -0
  300. package/dist/rules/security/SEC-013.js.map +1 -0
  301. package/dist/scoring/calculator.js +1 -0
  302. package/dist/scoring/calculator.js.map +1 -1
  303. package/dist/ui/ink/components/AIRecommendationCard.d.ts +11 -0
  304. package/dist/ui/ink/components/AIRecommendationCard.js +23 -0
  305. package/dist/ui/ink/components/AIRecommendationCard.js.map +1 -0
  306. package/dist/ui/ink/components/OpportunityList.d.ts +10 -0
  307. package/dist/ui/ink/components/OpportunityList.js +48 -0
  308. package/dist/ui/ink/components/OpportunityList.js.map +1 -0
  309. package/dist/ui/ink/components/PotentialPageCard.d.ts +13 -0
  310. package/dist/ui/ink/components/PotentialPageCard.js +43 -0
  311. package/dist/ui/ink/components/PotentialPageCard.js.map +1 -0
  312. package/dist/ui/ink/components/PotentialProgress.d.ts +16 -0
  313. package/dist/ui/ink/components/PotentialProgress.js +44 -0
  314. package/dist/ui/ink/components/PotentialProgress.js.map +1 -0
  315. package/dist/ui/ink/components/PotentialSummary.d.ts +10 -0
  316. package/dist/ui/ink/components/PotentialSummary.js +86 -0
  317. package/dist/ui/ink/components/PotentialSummary.js.map +1 -0
  318. package/dist/ui/ink/components/SuggestionCard.d.ts +34 -0
  319. package/dist/ui/ink/components/SuggestionCard.js +36 -0
  320. package/dist/ui/ink/components/SuggestionCard.js.map +1 -0
  321. package/dist/ui/ink/components/views/MultiPageCrawlView.d.ts +21 -0
  322. package/dist/ui/ink/components/views/MultiPageCrawlView.js +55 -0
  323. package/dist/ui/ink/components/views/MultiPageCrawlView.js.map +1 -0
  324. package/dist/ui/ink/components/views/PotentialView.d.ts +18 -0
  325. package/dist/ui/ink/components/views/PotentialView.js +74 -0
  326. package/dist/ui/ink/components/views/PotentialView.js.map +1 -0
  327. package/dist/ui/ink/components/views/ReconView.d.ts +22 -0
  328. package/dist/ui/ink/components/views/ReconView.js +30 -0
  329. package/dist/ui/ink/components/views/ReconView.js.map +1 -0
  330. package/package.json +2 -1
@@ -0,0 +1,9 @@
1
+ /**
2
+ * IMP-002: Feature Detection
3
+ *
4
+ * Checks if the site guards WebMCP usage with
5
+ * `"modelContext" in navigator` before calling APIs.
6
+ */
7
+ import type { Rule } from '../../core/types/rule.js';
8
+ export declare const IMP_002: Rule;
9
+ export default IMP_002;
@@ -0,0 +1,59 @@
1
+ /**
2
+ * IMP-002: Feature Detection
3
+ *
4
+ * Checks if the site guards WebMCP usage with
5
+ * `"modelContext" in navigator` before calling APIs.
6
+ */
7
+ import { createRuleResult } from '../runner.js';
8
+ const FEATURE_DETECTION_PATTERNS = [
9
+ /["']modelContext["']\s*in\s*(window\.)?navigator/,
10
+ /navigator\s*\.\s*modelContext\s*!==?\s*undefined/,
11
+ /typeof\s+navigator\s*\.\s*modelContext\s*!==?\s*["']undefined["']/,
12
+ /navigator\.modelContext\s*\?\./,
13
+ ];
14
+ export const IMP_002 = {
15
+ id: 'IMP-002',
16
+ category: 'implementation',
17
+ name: 'Feature Detection',
18
+ description: 'Checks if site guards WebMCP usage with feature detection',
19
+ severity: 'warning',
20
+ maxScore: 5,
21
+ async check(context) {
22
+ if (!context.hasWebMCP) {
23
+ return createRuleResult('IMP-002', 5, {
24
+ passed: true,
25
+ score: 5,
26
+ message: 'No WebMCP API detected (rule not applicable)',
27
+ });
28
+ }
29
+ const scripts = context.scripts ?? [];
30
+ const html = context.html ?? '';
31
+ // Search in scripts and inline HTML for feature detection patterns
32
+ const allContent = [
33
+ ...scripts.map((s) => s.content),
34
+ html,
35
+ ];
36
+ for (const content of allContent) {
37
+ for (const pattern of FEATURE_DETECTION_PATTERNS) {
38
+ if (pattern.test(content)) {
39
+ return createRuleResult('IMP-002', 5, {
40
+ passed: true,
41
+ score: 5,
42
+ message: 'Site uses feature detection before accessing WebMCP API',
43
+ });
44
+ }
45
+ }
46
+ }
47
+ return createRuleResult('IMP-002', 5, {
48
+ passed: false,
49
+ score: 0,
50
+ message: 'No feature detection found for WebMCP API',
51
+ suggestions: [
52
+ 'Guard WebMCP usage with: if ("modelContext" in navigator) { ... }',
53
+ 'This prevents errors in browsers that do not support WebMCP',
54
+ ],
55
+ });
56
+ },
57
+ };
58
+ export default IMP_002;
59
+ //# sourceMappingURL=IMP-002.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IMP-002.js","sourceRoot":"","sources":["../../../src/rules/implementation/IMP-002.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,0BAA0B,GAAG;IACjC,kDAAkD;IAClD,kDAAkD;IAClD,mEAAmE;IACnE,gCAAgC;CACjC,CAAC;AAEF,MAAM,CAAC,MAAM,OAAO,GAAS;IAC3B,EAAE,EAAE,SAAS;IACb,QAAQ,EAAE,gBAAgB;IAC1B,IAAI,EAAE,mBAAmB;IACzB,WAAW,EAAE,2DAA2D;IACxE,QAAQ,EAAE,SAAS;IACnB,QAAQ,EAAE,CAAC;IAEX,KAAK,CAAC,KAAK,CAAC,OAAoB;QAC9B,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;YACvB,OAAO,gBAAgB,CAAC,SAAS,EAAE,CAAC,EAAE;gBACpC,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAE,CAAC;gBACR,OAAO,EAAE,8CAA8C;aACxD,CAAC,CAAC;QACL,CAAC;QAED,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;QAEhC,mEAAmE;QACnE,MAAM,UAAU,GAAG;YACjB,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;YAChC,IAAI;SACL,CAAC;QAEF,KAAK,MAAM,OAAO,IAAI,UAAU,EAAE,CAAC;YACjC,KAAK,MAAM,OAAO,IAAI,0BAA0B,EAAE,CAAC;gBACjD,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;oBAC1B,OAAO,gBAAgB,CAAC,SAAS,EAAE,CAAC,EAAE;wBACpC,MAAM,EAAE,IAAI;wBACZ,KAAK,EAAE,CAAC;wBACR,OAAO,EAAE,yDAAyD;qBACnE,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,gBAAgB,CAAC,SAAS,EAAE,CAAC,EAAE;YACpC,MAAM,EAAE,KAAK;YACb,KAAK,EAAE,CAAC;YACR,OAAO,EAAE,2CAA2C;YACpD,WAAW,EAAE;gBACX,mEAAmE;gBACnE,6DAA6D;aAC9D;SACF,CAAC,CAAC;IACL,CAAC;CACF,CAAC;AAEF,eAAe,OAAO,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * IMP-006: Tool Has Execute
3
+ *
4
+ * Checks that every imperative tool has an execute function.
5
+ * Without execute, the agent cannot invoke the tool.
6
+ */
7
+ import type { Rule } from '../../core/types/rule.js';
8
+ export declare const IMP_006: Rule;
9
+ export default IMP_006;
@@ -0,0 +1,48 @@
1
+ /**
2
+ * IMP-006: Tool Has Execute
3
+ *
4
+ * Checks that every imperative tool has an execute function.
5
+ * Without execute, the agent cannot invoke the tool.
6
+ */
7
+ import { createRuleResult } from '../runner.js';
8
+ export const IMP_006 = {
9
+ id: 'IMP-006',
10
+ category: 'implementation',
11
+ name: 'Tool Has Execute',
12
+ description: 'Every imperative tool must have an execute function',
13
+ severity: 'critical',
14
+ maxScore: 10,
15
+ async check(context) {
16
+ const imperativeTools = context.tools.filter((t) => t.source === 'imperative');
17
+ if (imperativeTools.length === 0) {
18
+ return createRuleResult('IMP-006', 10, {
19
+ passed: true,
20
+ score: 10,
21
+ message: 'No imperative tools found to check',
22
+ });
23
+ }
24
+ const toolsWithoutExecute = imperativeTools.filter((t) => !t.hasExecute);
25
+ if (toolsWithoutExecute.length === 0) {
26
+ return createRuleResult('IMP-006', 10, {
27
+ passed: true,
28
+ score: 10,
29
+ message: `All ${imperativeTools.length} imperative tool(s) have execute functions`,
30
+ });
31
+ }
32
+ return createRuleResult('IMP-006', 10, {
33
+ passed: false,
34
+ score: Math.max(0, 10 - toolsWithoutExecute.length * 5),
35
+ message: `${toolsWithoutExecute.length} imperative tool(s) missing execute function`,
36
+ details: toolsWithoutExecute.map((t) => `Tool "${t.name || '(unnamed)'}" has no execute function`),
37
+ suggestions: [
38
+ 'Every imperative tool must define an execute function',
39
+ 'Example: navigator.modelContext.registerTool({ name: "...", execute: async (params) => { ... } })',
40
+ ],
41
+ affectedTools: toolsWithoutExecute
42
+ .filter((t) => t.name)
43
+ .map((t) => t.name),
44
+ });
45
+ },
46
+ };
47
+ export default IMP_006;
48
+ //# sourceMappingURL=IMP-006.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IMP-006.js","sourceRoot":"","sources":["../../../src/rules/implementation/IMP-006.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,CAAC,MAAM,OAAO,GAAS;IAC3B,EAAE,EAAE,SAAS;IACb,QAAQ,EAAE,gBAAgB;IAC1B,IAAI,EAAE,kBAAkB;IACxB,WAAW,EAAE,qDAAqD;IAClE,QAAQ,EAAE,UAAU;IACpB,QAAQ,EAAE,EAAE;IAEZ,KAAK,CAAC,KAAK,CAAC,OAAoB;QAC9B,MAAM,eAAe,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAC1C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,YAAY,CACjC,CAAC;QAEF,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjC,OAAO,gBAAgB,CAAC,SAAS,EAAE,EAAE,EAAE;gBACrC,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAE,EAAE;gBACT,OAAO,EAAE,oCAAoC;aAC9C,CAAC,CAAC;QACL,CAAC;QAED,MAAM,mBAAmB,GAAG,eAAe,CAAC,MAAM,CAChD,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CACrB,CAAC;QAEF,IAAI,mBAAmB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrC,OAAO,gBAAgB,CAAC,SAAS,EAAE,EAAE,EAAE;gBACrC,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAE,EAAE;gBACT,OAAO,EAAE,OAAO,eAAe,CAAC,MAAM,4CAA4C;aACnF,CAAC,CAAC;QACL,CAAC;QAED,OAAO,gBAAgB,CAAC,SAAS,EAAE,EAAE,EAAE;YACrC,MAAM,EAAE,KAAK;YACb,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,mBAAmB,CAAC,MAAM,GAAG,CAAC,CAAC;YACvD,OAAO,EAAE,GAAG,mBAAmB,CAAC,MAAM,8CAA8C;YACpF,OAAO,EAAE,mBAAmB,CAAC,GAAG,CAC9B,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,IAAI,IAAI,WAAW,2BAA2B,CACjE;YACD,WAAW,EAAE;gBACX,uDAAuD;gBACvD,mGAAmG;aACpG;YACD,aAAa,EAAE,mBAAmB;iBAC/B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;iBACrB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;SACtB,CAAC,CAAC;IACL,CAAC;CACF,CAAC;AAEF,eAAe,OAAO,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * IMP-008: Declarative Has Toolname
3
+ *
4
+ * Checks that declarative forms have a toolname attribute.
5
+ * Without toolname, the form cannot be exposed as a WebMCP tool.
6
+ */
7
+ import type { Rule } from '../../core/types/rule.js';
8
+ export declare const IMP_008: Rule;
9
+ export default IMP_008;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * IMP-008: Declarative Has Toolname
3
+ *
4
+ * Checks that declarative forms have a toolname attribute.
5
+ * Without toolname, the form cannot be exposed as a WebMCP tool.
6
+ */
7
+ import { createRuleResult } from '../runner.js';
8
+ export const IMP_008 = {
9
+ id: 'IMP-008',
10
+ category: 'implementation',
11
+ name: 'Declarative Has Toolname',
12
+ description: 'Declarative forms must have a toolname attribute',
13
+ severity: 'critical',
14
+ maxScore: 10,
15
+ async check(context) {
16
+ const declarativeTools = context.tools.filter((t) => t.source === 'declarative');
17
+ if (declarativeTools.length === 0) {
18
+ return createRuleResult('IMP-008', 10, {
19
+ passed: true,
20
+ score: 10,
21
+ message: 'No declarative tools found to check',
22
+ });
23
+ }
24
+ const toolsWithoutName = declarativeTools.filter((t) => !t.name || t.name.trim() === '');
25
+ if (toolsWithoutName.length === 0) {
26
+ return createRuleResult('IMP-008', 10, {
27
+ passed: true,
28
+ score: 10,
29
+ message: `All ${declarativeTools.length} declarative form(s) have toolname attributes`,
30
+ });
31
+ }
32
+ return createRuleResult('IMP-008', 10, {
33
+ passed: false,
34
+ score: Math.max(0, 10 - toolsWithoutName.length * 5),
35
+ message: `${toolsWithoutName.length} declarative form(s) missing toolname attribute`,
36
+ details: toolsWithoutName.map((t) => `Declarative form at ${t.pageUrl} is missing toolname`),
37
+ suggestions: [
38
+ 'Add a toolname attribute to each form: <form toolname="search-flights">',
39
+ 'The toolname identifies the form as a WebMCP tool',
40
+ ],
41
+ affectedPages: [...new Set(toolsWithoutName.map((t) => t.pageUrl))],
42
+ });
43
+ },
44
+ };
45
+ export default IMP_008;
46
+ //# sourceMappingURL=IMP-008.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IMP-008.js","sourceRoot":"","sources":["../../../src/rules/implementation/IMP-008.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,CAAC,MAAM,OAAO,GAAS;IAC3B,EAAE,EAAE,SAAS;IACb,QAAQ,EAAE,gBAAgB;IAC1B,IAAI,EAAE,0BAA0B;IAChC,WAAW,EAAE,kDAAkD;IAC/D,QAAQ,EAAE,UAAU;IACpB,QAAQ,EAAE,EAAE;IAEZ,KAAK,CAAC,KAAK,CAAC,OAAoB;QAC9B,MAAM,gBAAgB,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAC3C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,aAAa,CAClC,CAAC;QAEF,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAClC,OAAO,gBAAgB,CAAC,SAAS,EAAE,EAAE,EAAE;gBACrC,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAE,EAAE;gBACT,OAAO,EAAE,qCAAqC;aAC/C,CAAC,CAAC;QACL,CAAC;QAED,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,MAAM,CAC9C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CACvC,CAAC;QAEF,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAClC,OAAO,gBAAgB,CAAC,SAAS,EAAE,EAAE,EAAE;gBACrC,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAE,EAAE;gBACT,OAAO,EAAE,OAAO,gBAAgB,CAAC,MAAM,+CAA+C;aACvF,CAAC,CAAC;QACL,CAAC;QAED,OAAO,gBAAgB,CAAC,SAAS,EAAE,EAAE,EAAE;YACrC,MAAM,EAAE,KAAK;YACb,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC;YACpD,OAAO,EAAE,GAAG,gBAAgB,CAAC,MAAM,iDAAiD;YACpF,OAAO,EAAE,gBAAgB,CAAC,GAAG,CAC3B,CAAC,CAAC,EAAE,EAAE,CAAC,uBAAuB,CAAC,CAAC,OAAO,sBAAsB,CAC9D;YACD,WAAW,EAAE;gBACX,yEAAyE;gBACzE,mDAAmD;aACpD;YACD,aAAa,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;SACpE,CAAC,CAAC;IACL,CAAC;CACF,CAAC;AAEF,eAAe,OAAO,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * IMP-009: Declarative Has Tooldescription
3
+ *
4
+ * Checks that declarative forms have a tooldescription attribute.
5
+ * Without tooldescription, the agent cannot determine when to use the form.
6
+ */
7
+ import type { Rule } from '../../core/types/rule.js';
8
+ export declare const IMP_009: Rule;
9
+ export default IMP_009;
@@ -0,0 +1,48 @@
1
+ /**
2
+ * IMP-009: Declarative Has Tooldescription
3
+ *
4
+ * Checks that declarative forms have a tooldescription attribute.
5
+ * Without tooldescription, the agent cannot determine when to use the form.
6
+ */
7
+ import { createRuleResult } from '../runner.js';
8
+ export const IMP_009 = {
9
+ id: 'IMP-009',
10
+ category: 'implementation',
11
+ name: 'Declarative Has Tooldescription',
12
+ description: 'Declarative forms must have a tooldescription attribute',
13
+ severity: 'critical',
14
+ maxScore: 10,
15
+ async check(context) {
16
+ const declarativeTools = context.tools.filter((t) => t.source === 'declarative');
17
+ if (declarativeTools.length === 0) {
18
+ return createRuleResult('IMP-009', 10, {
19
+ passed: true,
20
+ score: 10,
21
+ message: 'No declarative tools found to check',
22
+ });
23
+ }
24
+ const toolsWithoutDesc = declarativeTools.filter((t) => !t.description || t.description.trim() === '');
25
+ if (toolsWithoutDesc.length === 0) {
26
+ return createRuleResult('IMP-009', 10, {
27
+ passed: true,
28
+ score: 10,
29
+ message: `All ${declarativeTools.length} declarative form(s) have tooldescription attributes`,
30
+ });
31
+ }
32
+ return createRuleResult('IMP-009', 10, {
33
+ passed: false,
34
+ score: Math.max(0, 10 - toolsWithoutDesc.length * 5),
35
+ message: `${toolsWithoutDesc.length} declarative form(s) missing tooldescription attribute`,
36
+ details: toolsWithoutDesc.map((t) => `Form "${t.name || '(unnamed)'}" at ${t.pageUrl} is missing tooldescription`),
37
+ suggestions: [
38
+ 'Add a tooldescription attribute: <form toolname="..." tooldescription="Search for flights between airports">',
39
+ 'Descriptions help agents understand when and how to use the tool',
40
+ ],
41
+ affectedTools: toolsWithoutDesc
42
+ .filter((t) => t.name)
43
+ .map((t) => t.name),
44
+ });
45
+ },
46
+ };
47
+ export default IMP_009;
48
+ //# sourceMappingURL=IMP-009.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IMP-009.js","sourceRoot":"","sources":["../../../src/rules/implementation/IMP-009.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,CAAC,MAAM,OAAO,GAAS;IAC3B,EAAE,EAAE,SAAS;IACb,QAAQ,EAAE,gBAAgB;IAC1B,IAAI,EAAE,iCAAiC;IACvC,WAAW,EAAE,yDAAyD;IACtE,QAAQ,EAAE,UAAU;IACpB,QAAQ,EAAE,EAAE;IAEZ,KAAK,CAAC,KAAK,CAAC,OAAoB;QAC9B,MAAM,gBAAgB,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAC3C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,aAAa,CAClC,CAAC;QAEF,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAClC,OAAO,gBAAgB,CAAC,SAAS,EAAE,EAAE,EAAE;gBACrC,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAE,EAAE;gBACT,OAAO,EAAE,qCAAqC;aAC/C,CAAC,CAAC;QACL,CAAC;QAED,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,MAAM,CAC9C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,CACrD,CAAC;QAEF,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAClC,OAAO,gBAAgB,CAAC,SAAS,EAAE,EAAE,EAAE;gBACrC,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAE,EAAE;gBACT,OAAO,EAAE,OAAO,gBAAgB,CAAC,MAAM,sDAAsD;aAC9F,CAAC,CAAC;QACL,CAAC;QAED,OAAO,gBAAgB,CAAC,SAAS,EAAE,EAAE,EAAE;YACrC,MAAM,EAAE,KAAK;YACb,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC;YACpD,OAAO,EAAE,GAAG,gBAAgB,CAAC,MAAM,wDAAwD;YAC3F,OAAO,EAAE,gBAAgB,CAAC,GAAG,CAC3B,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,IAAI,IAAI,WAAW,QAAQ,CAAC,CAAC,OAAO,6BAA6B,CACpF;YACD,WAAW,EAAE;gBACX,8GAA8G;gBAC9G,kEAAkE;aACnE;YACD,aAAa,EAAE,gBAAgB;iBAC5B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;iBACrB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;SACtB,CAAC,CAAC;IACL,CAAC;CACF,CAAC;AAEF,eAAe,OAAO,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * IMP-010: Declarative Submit Button
3
+ *
4
+ * Checks that declarative forms have a submit button.
5
+ * Without a submit button, agents may not be able to invoke the form.
6
+ */
7
+ import type { Rule } from '../../core/types/rule.js';
8
+ export declare const IMP_010: Rule;
9
+ export default IMP_010;
@@ -0,0 +1,66 @@
1
+ /**
2
+ * IMP-010: Declarative Submit Button
3
+ *
4
+ * Checks that declarative forms have a submit button.
5
+ * Without a submit button, agents may not be able to invoke the form.
6
+ */
7
+ import * as cheerio from 'cheerio';
8
+ import { createRuleResult } from '../runner.js';
9
+ export const IMP_010 = {
10
+ id: 'IMP-010',
11
+ category: 'implementation',
12
+ name: 'Declarative Submit Button',
13
+ description: 'Declarative forms should have a submit button',
14
+ severity: 'warning',
15
+ maxScore: 5,
16
+ async check(context) {
17
+ const declarativeTools = context.tools.filter((t) => t.source === 'declarative');
18
+ if (declarativeTools.length === 0) {
19
+ return createRuleResult('IMP-010', 5, {
20
+ passed: true,
21
+ score: 5,
22
+ message: 'No declarative tools found to check',
23
+ });
24
+ }
25
+ const html = context.html ?? '';
26
+ if (!html) {
27
+ return createRuleResult('IMP-010', 5, {
28
+ passed: true,
29
+ score: 5,
30
+ message: 'No HTML content available for analysis',
31
+ });
32
+ }
33
+ const $ = cheerio.load(html);
34
+ const formsWithoutSubmit = [];
35
+ $('form[toolname]').each((_i, form) => {
36
+ const $form = $(form);
37
+ const toolname = $form.attr('toolname') ?? '(unnamed)';
38
+ const hasSubmitButton = $form.find('button[type="submit"]').length > 0 ||
39
+ $form.find('input[type="submit"]').length > 0 ||
40
+ $form.find('button:not([type])').length > 0;
41
+ if (!hasSubmitButton) {
42
+ formsWithoutSubmit.push(toolname);
43
+ }
44
+ });
45
+ if (formsWithoutSubmit.length === 0) {
46
+ return createRuleResult('IMP-010', 5, {
47
+ passed: true,
48
+ score: 5,
49
+ message: 'All declarative forms have submit buttons',
50
+ });
51
+ }
52
+ return createRuleResult('IMP-010', 5, {
53
+ passed: false,
54
+ score: Math.max(0, 5 - formsWithoutSubmit.length * 2),
55
+ message: `${formsWithoutSubmit.length} declarative form(s) missing a submit button`,
56
+ details: formsWithoutSubmit.map((name) => `Form "${name}" has no submit button`),
57
+ suggestions: [
58
+ 'Add a <button type="submit"> or <input type="submit"> to each form',
59
+ 'Submit buttons allow agents to trigger form submission',
60
+ ],
61
+ affectedTools: formsWithoutSubmit,
62
+ });
63
+ },
64
+ };
65
+ export default IMP_010;
66
+ //# sourceMappingURL=IMP-010.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IMP-010.js","sourceRoot":"","sources":["../../../src/rules/implementation/IMP-010.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAEnC,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,CAAC,MAAM,OAAO,GAAS;IAC3B,EAAE,EAAE,SAAS;IACb,QAAQ,EAAE,gBAAgB;IAC1B,IAAI,EAAE,2BAA2B;IACjC,WAAW,EAAE,+CAA+C;IAC5D,QAAQ,EAAE,SAAS;IACnB,QAAQ,EAAE,CAAC;IAEX,KAAK,CAAC,KAAK,CAAC,OAAoB;QAC9B,MAAM,gBAAgB,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAC3C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,aAAa,CAClC,CAAC;QAEF,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAClC,OAAO,gBAAgB,CAAC,SAAS,EAAE,CAAC,EAAE;gBACpC,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAE,CAAC;gBACR,OAAO,EAAE,qCAAqC;aAC/C,CAAC,CAAC;QACL,CAAC;QAED,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;QAChC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,gBAAgB,CAAC,SAAS,EAAE,CAAC,EAAE;gBACpC,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAE,CAAC;gBACR,OAAO,EAAE,wCAAwC;aAClD,CAAC,CAAC;QACL,CAAC;QAED,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7B,MAAM,kBAAkB,GAAa,EAAE,CAAC;QAExC,CAAC,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE;YACpC,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;YACtB,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,WAAW,CAAC;YAEvD,MAAM,eAAe,GACnB,KAAK,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC,MAAM,GAAG,CAAC;gBAC9C,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,MAAM,GAAG,CAAC;gBAC7C,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;YAE9C,IAAI,CAAC,eAAe,EAAE,CAAC;gBACrB,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACpC,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,IAAI,kBAAkB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACpC,OAAO,gBAAgB,CAAC,SAAS,EAAE,CAAC,EAAE;gBACpC,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAE,CAAC;gBACR,OAAO,EAAE,2CAA2C;aACrD,CAAC,CAAC;QACL,CAAC;QAED,OAAO,gBAAgB,CAAC,SAAS,EAAE,CAAC,EAAE;YACpC,MAAM,EAAE,KAAK;YACb,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,kBAAkB,CAAC,MAAM,GAAG,CAAC,CAAC;YACrD,OAAO,EAAE,GAAG,kBAAkB,CAAC,MAAM,8CAA8C;YACnF,OAAO,EAAE,kBAAkB,CAAC,GAAG,CAC7B,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,IAAI,wBAAwB,CAChD;YACD,WAAW,EAAE;gBACX,oEAAoE;gBACpE,wDAAwD;aACzD;YACD,aAAa,EAAE,kBAAkB;SAClC,CAAC,CAAC;IACL,CAAC;CACF,CAAC;AAEF,eAAe,OAAO,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * IMP-011: Declarative Labels
3
+ *
4
+ * Checks that form fields in declarative forms have associated label elements.
5
+ * Labels help agents understand what each field represents.
6
+ */
7
+ import type { Rule } from '../../core/types/rule.js';
8
+ export declare const IMP_011: Rule;
9
+ export default IMP_011;
@@ -0,0 +1,82 @@
1
+ /**
2
+ * IMP-011: Declarative Labels
3
+ *
4
+ * Checks that form fields in declarative forms have associated label elements.
5
+ * Labels help agents understand what each field represents.
6
+ */
7
+ import * as cheerio from 'cheerio';
8
+ import { createRuleResult } from '../runner.js';
9
+ export const IMP_011 = {
10
+ id: 'IMP-011',
11
+ category: 'implementation',
12
+ name: 'Declarative Labels',
13
+ description: 'Form fields should have associated label elements',
14
+ severity: 'warning',
15
+ maxScore: 5,
16
+ async check(context) {
17
+ const declarativeTools = context.tools.filter((t) => t.source === 'declarative');
18
+ if (declarativeTools.length === 0) {
19
+ return createRuleResult('IMP-011', 5, {
20
+ passed: true,
21
+ score: 5,
22
+ message: 'No declarative tools found to check',
23
+ });
24
+ }
25
+ const html = context.html ?? '';
26
+ if (!html) {
27
+ return createRuleResult('IMP-011', 5, {
28
+ passed: true,
29
+ score: 5,
30
+ message: 'No HTML content available for analysis',
31
+ });
32
+ }
33
+ const $ = cheerio.load(html);
34
+ const fieldsWithoutLabels = [];
35
+ $('form[toolname]').each((_i, form) => {
36
+ const $form = $(form);
37
+ const toolname = $form.attr('toolname') ?? '(unnamed)';
38
+ $form
39
+ .find('input, select, textarea')
40
+ .not('[type="hidden"], [type="submit"]')
41
+ .each((_j, input) => {
42
+ const $input = $(input);
43
+ const id = $input.attr('id');
44
+ const name = $input.attr('name') ?? '(unnamed)';
45
+ const ariaLabel = $input.attr('aria-label');
46
+ const ariaLabelledBy = $input.attr('aria-labelledby');
47
+ // Check for associated label: for=id, wrapper label, or aria
48
+ const hasLabel = (id && $(`label[for="${id}"]`).length > 0) ||
49
+ $input.closest('label').length > 0 ||
50
+ !!ariaLabel ||
51
+ !!ariaLabelledBy;
52
+ if (!hasLabel) {
53
+ fieldsWithoutLabels.push({ form: toolname, field: name });
54
+ }
55
+ });
56
+ });
57
+ if (fieldsWithoutLabels.length === 0) {
58
+ return createRuleResult('IMP-011', 5, {
59
+ passed: true,
60
+ score: 5,
61
+ message: 'All form fields have associated labels',
62
+ });
63
+ }
64
+ return createRuleResult('IMP-011', 5, {
65
+ passed: false,
66
+ score: Math.max(0, 5 - fieldsWithoutLabels.length),
67
+ message: `${fieldsWithoutLabels.length} form field(s) missing labels`,
68
+ details: fieldsWithoutLabels.map((v) => `Field "${v.field}" in form "${v.form}" has no associated label`),
69
+ suggestions: [
70
+ 'Add <label for="fieldId"> for each input field',
71
+ 'Or wrap inputs in <label> elements',
72
+ 'Or use aria-label/aria-labelledby attributes',
73
+ 'Labels help agents understand field purpose',
74
+ ],
75
+ affectedTools: [
76
+ ...new Set(fieldsWithoutLabels.map((v) => v.form)),
77
+ ],
78
+ });
79
+ },
80
+ };
81
+ export default IMP_011;
82
+ //# sourceMappingURL=IMP-011.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IMP-011.js","sourceRoot":"","sources":["../../../src/rules/implementation/IMP-011.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * IMP-012: Declarative Required Match
3
+ *
4
+ * Checks that HTML required attributes on form fields match
5
+ * the schema required array for declarative tools.
6
+ */
7
+ import type { Rule } from '../../core/types/rule.js';
8
+ export declare const IMP_012: Rule;
9
+ export default IMP_012;
@@ -0,0 +1,88 @@
1
+ /**
2
+ * IMP-012: Declarative Required Match
3
+ *
4
+ * Checks that HTML required attributes on form fields match
5
+ * the schema required array for declarative tools.
6
+ */
7
+ import * as cheerio from 'cheerio';
8
+ import { createRuleResult } from '../runner.js';
9
+ export const IMP_012 = {
10
+ id: 'IMP-012',
11
+ category: 'implementation',
12
+ name: 'Declarative Required Match',
13
+ description: 'HTML required attributes should match schema required array',
14
+ severity: 'warning',
15
+ maxScore: 5,
16
+ async check(context) {
17
+ const declarativeTools = context.tools.filter((t) => t.source === 'declarative' && t.inputSchema);
18
+ if (declarativeTools.length === 0) {
19
+ return createRuleResult('IMP-012', 5, {
20
+ passed: true,
21
+ score: 5,
22
+ message: 'No declarative tools with schemas found to check',
23
+ });
24
+ }
25
+ const html = context.html ?? '';
26
+ if (!html) {
27
+ return createRuleResult('IMP-012', 5, {
28
+ passed: true,
29
+ score: 5,
30
+ message: 'No HTML content available for analysis',
31
+ });
32
+ }
33
+ const $ = cheerio.load(html);
34
+ const mismatches = [];
35
+ for (const tool of declarativeTools) {
36
+ const $form = $(`form[toolname="${tool.name}"]`);
37
+ if ($form.length === 0)
38
+ continue;
39
+ const schemaRequired = new Set((tool.inputSchema?.required ?? []).map((r) => r.toLowerCase()));
40
+ const htmlRequired = new Set();
41
+ $form
42
+ .find('input[required], select[required], textarea[required]')
43
+ .each((_i, el) => {
44
+ const name = $(el).attr('name');
45
+ if (name)
46
+ htmlRequired.add(name.toLowerCase());
47
+ });
48
+ // Fields required in HTML but not in schema
49
+ for (const field of htmlRequired) {
50
+ if (!schemaRequired.has(field)) {
51
+ mismatches.push({
52
+ tool: tool.name,
53
+ details: `Field "${field}" is required in HTML but not in schema`,
54
+ });
55
+ }
56
+ }
57
+ // Fields required in schema but not in HTML
58
+ for (const field of schemaRequired) {
59
+ if (!htmlRequired.has(field)) {
60
+ mismatches.push({
61
+ tool: tool.name,
62
+ details: `Field "${field}" is required in schema but not in HTML`,
63
+ });
64
+ }
65
+ }
66
+ }
67
+ if (mismatches.length === 0) {
68
+ return createRuleResult('IMP-012', 5, {
69
+ passed: true,
70
+ score: 5,
71
+ message: 'HTML required attributes match schema required arrays',
72
+ });
73
+ }
74
+ return createRuleResult('IMP-012', 5, {
75
+ passed: false,
76
+ score: Math.max(0, 5 - mismatches.length),
77
+ message: `${mismatches.length} required field mismatch(es) found`,
78
+ details: mismatches.map((m) => `Tool "${m.tool}": ${m.details}`),
79
+ suggestions: [
80
+ 'Ensure HTML required attributes match the schema required array',
81
+ 'Both the form and schema should agree on which fields are mandatory',
82
+ ],
83
+ affectedTools: [...new Set(mismatches.map((m) => m.tool))],
84
+ });
85
+ },
86
+ };
87
+ export default IMP_012;
88
+ //# sourceMappingURL=IMP-012.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IMP-012.js","sourceRoot":"","sources":["../../../src/rules/implementation/IMP-012.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * IMP-014: Execute Returns Content
3
+ *
4
+ * Checks that execute functions return { content: [...] } format.
5
+ * This is the expected response format for WebMCP tool results.
6
+ */
7
+ import type { Rule } from '../../core/types/rule.js';
8
+ export declare const IMP_014: Rule;
9
+ export default IMP_014;
@@ -0,0 +1,58 @@
1
+ /**
2
+ * IMP-014: Execute Returns Content
3
+ *
4
+ * Checks that execute functions return { content: [...] } format.
5
+ * This is the expected response format for WebMCP tool results.
6
+ */
7
+ import { createRuleResult } from '../runner.js';
8
+ const CONTENT_RETURN_PATTERNS = [
9
+ /return\s*\{[\s\S]*content\s*:/,
10
+ /return\s*\{[\s\S]*["']content["']\s*:/,
11
+ /\.content\s*=\s*\[/,
12
+ ];
13
+ export const IMP_014 = {
14
+ id: 'IMP-014',
15
+ category: 'implementation',
16
+ name: 'Execute Returns Content',
17
+ description: 'Execute functions should return { content: [...] } format',
18
+ severity: 'warning',
19
+ maxScore: 5,
20
+ async check(context) {
21
+ const imperativeTools = context.tools.filter((t) => t.source === 'imperative' && t.hasExecute && t.executeSource);
22
+ if (imperativeTools.length === 0) {
23
+ return createRuleResult('IMP-014', 5, {
24
+ passed: true,
25
+ score: 5,
26
+ message: 'No imperative tools with execute source to check',
27
+ });
28
+ }
29
+ const violations = [];
30
+ for (const tool of imperativeTools) {
31
+ const source = tool.executeSource ?? '';
32
+ const hasContentReturn = CONTENT_RETURN_PATTERNS.some((p) => p.test(source));
33
+ if (!hasContentReturn) {
34
+ violations.push(tool.name);
35
+ }
36
+ }
37
+ if (violations.length === 0) {
38
+ return createRuleResult('IMP-014', 5, {
39
+ passed: true,
40
+ score: 5,
41
+ message: `All ${imperativeTools.length} execute function(s) return content format`,
42
+ });
43
+ }
44
+ return createRuleResult('IMP-014', 5, {
45
+ passed: false,
46
+ score: Math.max(0, 5 - violations.length * 2),
47
+ message: `${violations.length} execute function(s) may not return { content: [...] } format`,
48
+ details: violations.map((name) => `Tool "${name}" execute function does not appear to return { content: [...] }`),
49
+ suggestions: [
50
+ 'Execute functions should return: { content: [{ type: "text", text: "result" }] }',
51
+ 'This format allows agents to properly parse tool results',
52
+ ],
53
+ affectedTools: violations,
54
+ });
55
+ },
56
+ };
57
+ export default IMP_014;
58
+ //# sourceMappingURL=IMP-014.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IMP-014.js","sourceRoot":"","sources":["../../../src/rules/implementation/IMP-014.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,uBAAuB,GAAG;IAC9B,+BAA+B;IAC/B,uCAAuC;IACvC,oBAAoB;CACrB,CAAC;AAEF,MAAM,CAAC,MAAM,OAAO,GAAS;IAC3B,EAAE,EAAE,SAAS;IACb,QAAQ,EAAE,gBAAgB;IAC1B,IAAI,EAAE,yBAAyB;IAC/B,WAAW,EAAE,2DAA2D;IACxE,QAAQ,EAAE,SAAS;IACnB,QAAQ,EAAE,CAAC;IAEX,KAAK,CAAC,KAAK,CAAC,OAAoB;QAC9B,MAAM,eAAe,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAC1C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,YAAY,IAAI,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,aAAa,CACpE,CAAC;QAEF,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjC,OAAO,gBAAgB,CAAC,SAAS,EAAE,CAAC,EAAE;gBACpC,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAE,CAAC;gBACR,OAAO,EAAE,kDAAkD;aAC5D,CAAC,CAAC;QACL,CAAC;QAED,MAAM,UAAU,GAAa,EAAE,CAAC;QAEhC,KAAK,MAAM,IAAI,IAAI,eAAe,EAAE,CAAC;YACnC,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,IAAI,EAAE,CAAC;YACxC,MAAM,gBAAgB,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAC1D,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CACf,CAAC;YAEF,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBACtB,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;QAED,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,OAAO,gBAAgB,CAAC,SAAS,EAAE,CAAC,EAAE;gBACpC,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAE,CAAC;gBACR,OAAO,EAAE,OAAO,eAAe,CAAC,MAAM,4CAA4C;aACnF,CAAC,CAAC;QACL,CAAC;QAED,OAAO,gBAAgB,CAAC,SAAS,EAAE,CAAC,EAAE;YACpC,MAAM,EAAE,KAAK;YACb,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;YAC7C,OAAO,EAAE,GAAG,UAAU,CAAC,MAAM,+DAA+D;YAC5F,OAAO,EAAE,UAAU,CAAC,GAAG,CACrB,CAAC,IAAI,EAAE,EAAE,CACP,SAAS,IAAI,iEAAiE,CACjF;YACD,WAAW,EAAE;gBACX,kFAAkF;gBAClF,0DAA0D;aAC3D;YACD,aAAa,EAAE,UAAU;SAC1B,CAAC,CAAC;IACL,CAAC;CACF,CAAC;AAEF,eAAe,OAAO,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * IMP-015: Execute Returns on Error
3
+ *
4
+ * Checks that execute functions handle errors by returning error content
5
+ * rather than just throwing exceptions.
6
+ */
7
+ import type { Rule } from '../../core/types/rule.js';
8
+ export declare const IMP_015: Rule;
9
+ export default IMP_015;