@jrpool/kilotest 38.1.0 → 39.0.1

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 (57) hide show
  1. package/.markdownlint-cli2.jsonc +12 -0
  2. package/.vscode/settings.json +3 -0
  3. package/CLAUDE.md +5 -0
  4. package/README.md +6 -4
  5. package/ai0BalanceForm/index.html +1 -1
  6. package/alerts.js +3 -1
  7. package/api/getReport.js +66 -0
  8. package/api/listDiagnoses.js +157 -0
  9. package/api/listIssues.js +225 -0
  10. package/api/listReports.js +87 -0
  11. package/api/listViolators.js +164 -0
  12. package/api/requestFeature.js +56 -0
  13. package/api/requestRetest.js +102 -0
  14. package/api/requestTest.js +106 -0
  15. package/api/routes.js +97 -0
  16. package/api/schemas.js +297 -0
  17. package/api/testSuite.js +294 -0
  18. package/api/util.js +149 -0
  19. package/diagnoses/index.js +2 -2
  20. package/docs/{AI-TOOL.md → AI-TOOLS.md} +54 -26
  21. package/docs/SERVICE.md +4 -1
  22. package/docs/decisions/001-api-design.md +59 -49
  23. package/eslint.config.mjs +13 -3
  24. package/index.html +1 -1
  25. package/index.js +202 -188
  26. package/issues/index.js +13 -21
  27. package/jsconfig.json +8 -0
  28. package/llms-full.txt +2 -2
  29. package/llms.txt +16 -11
  30. package/mcp.js +129 -65
  31. package/openapi.yaml +1234 -572
  32. package/package.json +18 -11
  33. package/reannotate/index.js +26 -15
  34. package/reannotateForm/index.js +15 -13
  35. package/redocly.yaml +4 -0
  36. package/reportHideForm/index.html +1 -1
  37. package/reportHideForm/index.js +24 -38
  38. package/reportIssue/index.js +3 -3
  39. package/reportIssues/index.js +128 -1
  40. package/reportUnhideForm/index.js +36 -44
  41. package/reportsExpungeForm/index.js +22 -16
  42. package/reportsPruneForm/index.js +22 -12
  43. package/reportsRewindForm/index.js +17 -9
  44. package/retestRec/index.js +8 -4
  45. package/retestRecForm/index.js +18 -6
  46. package/scripts/generate-openapi.js +83 -0
  47. package/targets/index.js +18 -13
  48. package/testOrder/index.js +11 -8
  49. package/tutorial/index.html +12 -12
  50. package/util.js +581 -539
  51. package/api/reportList.js +0 -83
  52. package/api/reportSummary.js +0 -181
  53. package/reportIssue/api.js +0 -183
  54. package/reportIssues/util.js +0 -138
  55. package/researchAgent.js +0 -206
  56. package/target/api.js +0 -126
  57. package/testRecForm/api.js +0 -55
package/llms.txt CHANGED
@@ -8,20 +8,25 @@ There is a [detailed explanation of Kilotest and its capabilities for LLMs](http
8
8
 
9
9
  ## API
10
10
 
11
- - [Get summaries of reports about a specified web page](/api/target)
12
- - [List all available reports](/api/reportList)
13
- - Summarize one report: `/api/reportSummary/{timeStamp}/{jobID}`
14
- - Get details about one issue from one report: `/api/reportIssue/{issueID}/{timeStamp}/{jobID}`
15
- - Recommend testing of a web page: `/api/testRecForm` (requires `POST` request)
11
+ - [List all available reports](/api/listReports)
12
+ - List all issues in one report: `/api/listIssues/{timeStamp}/{jobID}`
13
+ - List all elements exhibiting one issue in one report: `/api/listViolators/{issueID}/{timeStamp}/{jobID}`
14
+ - List all diagnoses of one element exhibiting one issue in one report: `/api/listDiagnoses/{catalogIndex}/{issueID}/{timeStamp}/{jobID}`
15
+ - Get one full report in JSON: `/api/getReport/{timeStamp}/{jobID}`
16
+ - Request testing of a web page: `/api/requestTest` (requires `POST` request)
17
+ - Request retesting of a web page: `/api/requestRetest/{timeStamp}/{jobID}` (requires `POST` request)
18
+ - Request adding or improving a feature: `/api/requestFeature` (requires `POST` request)
16
19
  - [OpenAPI specification for Kilotest](https://kilotest.com/openapi.yaml)
17
20
 
18
21
  ## Web UI
19
22
 
20
- - [Summarize test results for all tested pages](https://kilotest.com/targets.html)
21
- - Provide statistics about issues reported in one job: `https://kilotest.com/reportIssues.html/{timeStamp}/{jobID}`
22
- - Provide details about one issue reported in one job: `https://kilotest.com/reportIssue.html/{issueID}/{timeStamp}/{jobID}`
23
- - Provide diagnoses about one issue exhibited by one HTML element in one job: `https://kilotest.com/diagnoses.html/{issueID}/{timeStamp}/{jobID}/{catalogIndex}`
24
- - [Provide statistics about frequently reported issues across all pages](https://kilotest.com/issues.html)
25
- - [Recommend testing of a web page](https://kilotest.com/testRecForm.html)
23
+ - [List all available reports](https://kilotest.com/targets.html)
24
+ - List all issues in one report: `https://kilotest.com/reportIssues.html/{timeStamp}/{jobID}`
25
+ - List all elements exhibiting one issue in one report: `https://kilotest.com/reportIssue.html/{issueID}/{timeStamp}/{jobID}`
26
+ - List all diagnoses of one element exhibiting one issue in one report: `https://kilotest.com/diagnoses.html/{issueID}/{timeStamp}/{jobID}/{catalogIndex}`
27
+ - Get one full report in JSON: `https://kilotest.com/fullReport.json/{timeStamp}/{jobID}`
28
+ - [Request testing of a web page](https://kilotest.com/testRecForm.html)
29
+ - Request retesting of a web page: `https://kilotest.com/retestRecForm.html/{timeStamp}/{jobID}`
26
30
  - [List the operations that Kilotest managers are authorized to request](https://kilotest.com/manage.html)
31
+ - [Provide statistics about frequently reported issues across all pages](https://kilotest.com/issues.html)
27
32
  - [Tutorial, “Accessibility testing strategies”](https://kilotest.com/tutorial.html)
package/mcp.js CHANGED
@@ -9,13 +9,32 @@ const {McpServer} = require('@modelcontextprotocol/sdk/server/mcp.js');
9
9
  const {StreamableHTTPServerTransport} = require(
10
10
  '@modelcontextprotocol/sdk/server/streamableHttp.js'
11
11
  );
12
- const {z} = require('zod');
13
- const {isReportAvailable, isURL} = require('./util');
14
- const targetAPI = require('./target/api');
15
- const reportListAPI = require('./api/reportList');
16
- const reportSummaryAPI = require('./api/reportSummary');
17
- const reportIssueAPI = require('./reportIssue/api');
18
- const testRecFormAPI = require('./testRecForm/api');
12
+ const getReportAPI = require('./api/getReport');
13
+ const listReportsAPI = require('./api/listReports');
14
+ const listIssuesAPI = require('./api/listIssues');
15
+ const listViolatorsAPI = require('./api/listViolators');
16
+ const listDiagnosesAPI = require('./api/listDiagnoses');
17
+ const requestTestAPI = require('./api/requestTest');
18
+ const requestRetestAPI = require('./api/requestRetest');
19
+ const requestFeatureAPI = require('./api/requestFeature');
20
+
21
+ const {
22
+ getReportSchema,
23
+ listIssuesSchema,
24
+ listViolatorsSchema,
25
+ listDiagnosesSchema,
26
+ requestTestSchema,
27
+ requestRetestSchema,
28
+ requestFeatureSchema,
29
+ listReportsResponseSchema,
30
+ listIssuesResponseSchema,
31
+ listViolatorsResponseSchema,
32
+ listDiagnosesResponseSchema,
33
+ getReportResponseSchema,
34
+ requestTestResponseSchema,
35
+ requestRetestResponseSchema,
36
+ requestFeatureResponseSchema
37
+ } = require('./api/schemas');
19
38
 
20
39
  // CONSTANTS
21
40
 
@@ -25,119 +44,164 @@ exports.mcpPath = '/mcp';
25
44
 
26
45
  // Creates and returns an McpServer with Kilotest tools registered.
27
46
  const createMCPServer = () => {
28
- const server = new McpServer({name: 'Kilotest', version: '1.0.0'});
47
+ const server = new McpServer({
48
+ name: 'Kilotest',
49
+ version: '2.0.0',
50
+ description: 'Tools that test web pages for front-end quality (accessibility, usability, and standards conformity) and make test results available'
51
+ },
52
+ {
53
+ instructions: 'Use the listReports tool to start. If it shows that there is a report available about the page you want facts about, drill down with the listIssues, listViolators, and listDiagnoses tools. If not, use the requestTest tool to request that the page be tested. If the latest report about the page is obsolete, use the requestRetest tool to request that the page be retested.'
54
+ });
29
55
  server.registerTool(
30
- 'summarizeQualityOfMatchingWebPages',
56
+ 'listReports',
31
57
  {
32
- description: 'Returns summary data from every available Kilotest report about the front-end quality (i.e. accessibility, usability, and standards conformity) of web pages that match the description or hostname fragment of a web page that you have provided. Matching is case-insensitive and succeeds if the page property either is included by or includes the specified fragment.',
33
- inputSchema: {
34
- description: z.string().describe('All or part of a description of the web page.'),
35
- hostname: z.string().describe('All or part of the hostname of the URL of the web page.')
36
- },
58
+ description: 'Provide basics about all available reports.',
59
+ inputSchema: {},
60
+ outputSchema: listReportsResponseSchema,
37
61
  annotations: {
38
- title: 'Summarize the quality of matching web pages',
62
+ title: 'Provide basics about all available reports.',
39
63
  readOnlyHint: true,
40
64
  idempotentHint: true,
41
65
  destructiveHint: false,
42
66
  openWorldHint: false
43
67
  }
44
68
  },
45
- async ({description, hostname}) => {
46
- const result = await targetAPI.response([description, hostname]);
47
- return {content: [{type: 'text', text: JSON.stringify(result)}]};
69
+ async () => {
70
+ const result = await listReportsAPI.response();
71
+ return {content: [{type: 'text', text: JSON.stringify(result)}], structuredContent: result};
48
72
  }
49
73
  );
50
74
  server.registerTool(
51
- 'listAllAvailableReports',
75
+ 'listIssues',
52
76
  {
53
- description: 'Returns a list of all available Kilotest reports; each report describes the results of a job that tested one web page for front-end quality (i.e. accessibility, usability, and standards conformity).',
54
- inputSchema: {},
77
+ description: 'Provide details about one report, including basics about the issues reported in it.',
78
+ inputSchema: listIssuesSchema,
79
+ outputSchema: listIssuesResponseSchema,
55
80
  annotations: {
56
- title: 'List all available reports',
81
+ title: 'Provide details about one report, including basics about the issues reported in it.',
57
82
  readOnlyHint: true,
58
83
  idempotentHint: true,
59
84
  destructiveHint: false,
60
85
  openWorldHint: false
61
86
  }
62
87
  },
63
- async () => {
64
- const result = await reportListAPI.response();
65
- return {content: [{type: 'text', text: JSON.stringify(result)}]};
88
+ async ({timeStamp, jobID}) => {
89
+ const result = await listIssuesAPI.response([timeStamp, jobID]);
90
+ return {content: [{type: 'text', text: JSON.stringify(result)}], structuredContent: result};
66
91
  }
67
92
  );
68
93
  server.registerTool(
69
- 'summarizeOneReport',
94
+ 'listViolators',
70
95
  {
71
- description: 'Returns a summary of a specified Kilotest report about the front-end quality (i.e. accessibility, usability, and standards conformity) of a web page. The required timeStamp and jobID parameters identify the report and are obtained from a listAllAvailableReports response.',
72
- inputSchema: {
73
- timeStamp: z.string().describe('Timestamp of the report in YYMMDDTHHMM format, e.g. 260503T0432'),
74
- jobID: z.string().describe('Job identifier, e.g. x9z')
75
- },
96
+ description: 'Provide details about one issue in one report, including basics about the elements of the tested page that were reported as exhibiting the issue.',
97
+ inputSchema: listViolatorsSchema,
98
+ outputSchema: listViolatorsResponseSchema,
76
99
  annotations: {
77
- title: 'Summarize one report',
100
+ title: 'Provide details about one issue in one report, including basics about the elements of the tested page that were reported as exhibiting the issue.',
78
101
  readOnlyHint: true,
79
102
  idempotentHint: true,
80
103
  destructiveHint: false,
81
104
  openWorldHint: false
82
105
  }
83
106
  },
84
- async ({timeStamp, jobID}) => {
85
- const result = await reportSummaryAPI.response([timeStamp, jobID]);
86
- return {content: [{type: 'text', text: JSON.stringify(result)}]};
107
+ async ({issueID, timeStamp, jobID}) => {
108
+ const result = await listViolatorsAPI.response([issueID, timeStamp, jobID]);
109
+ return {content: [{type: 'text', text: JSON.stringify(result)}], structuredContent: result};
87
110
  }
88
111
  );
89
112
  server.registerTool(
90
- 'describeOneIssueFromOneReport',
113
+ 'listDiagnoses',
91
114
  {
92
- description: 'Returns data from a specified Kilotest report about one of the issues for the front-end quality (i.e. accessibility, usability, and standards conformity) of a web page. The required issueID, timeStamp, and jobID parameters identify the issue and the report and are obtained from a summarizeOneReport response.',
93
- inputSchema: {
94
- issueID: z.string().describe('Issue identifier, e.g. contrastPoor'),
95
- timeStamp: z.string().describe('Report timestamp in YYMMDDTHHMM format, e.g. 260503T0432'),
96
- jobID: z.string().describe('Job identifier, e.g. x9z')
97
- },
115
+ description: 'Provide details about one element reported as exhibiting one issue in one report, including the diagnoses provided by rule engines about how the element exhibited the issue.',
116
+ inputSchema: listDiagnosesSchema,
117
+ outputSchema: listDiagnosesResponseSchema,
98
118
  annotations: {
99
- title: 'Describe one issue from one report',
119
+ title: 'Provide details about one element reported as exhibiting one issue in one report, including the diagnoses provided by rule engines about how the element exhibited the issue.',
100
120
  readOnlyHint: true,
101
121
  idempotentHint: true,
102
122
  destructiveHint: false,
103
123
  openWorldHint: false
104
124
  }
105
125
  },
106
- async ({issueID, timeStamp, jobID}) => {
107
- const result = await reportIssueAPI.response([issueID, timeStamp, jobID]);
108
- return {content: [{type: 'text', text: JSON.stringify(result)}]};
126
+ async ({catalogIndex, issueID, timeStamp, jobID}) => {
127
+ const result = await listDiagnosesAPI.response([catalogIndex, issueID, timeStamp, jobID]);
128
+ return {content: [{type: 'text', text: JSON.stringify(result)}], structuredContent: result};
129
+ }
130
+ );
131
+ server.registerTool(
132
+ 'getReport',
133
+ {
134
+ description: 'Get one full report in JSON.',
135
+ inputSchema: getReportSchema,
136
+ outputSchema: getReportResponseSchema,
137
+ annotations: {
138
+ title: 'Get one full report in JSON.',
139
+ readOnlyHint: true,
140
+ idempotentHint: true,
141
+ destructiveHint: false,
142
+ openWorldHint: false
143
+ }
144
+ },
145
+ async ({timeStamp, jobID}) => {
146
+ const result = await getReportAPI.response([timeStamp, jobID]);
147
+ return {content: [{type: 'text', text: JSON.stringify(result)}], structuredContent: result};
109
148
  }
110
149
  );
111
150
  server.registerTool(
112
- 'recommendQualityTestingOfOneWebPage',
151
+ 'requestTest',
113
152
  {
114
- description: 'Recommends a web page for Kilotest to test for front-end quality (i.e. accessibility, usability, and standards conformity). Do not call this tool until after you call listAllAvailableReports to check whether a report about the page, or a related page that satisfies your requirements, is available and to understand the naming conventions for pages.',
115
- inputSchema: {
116
- 'description of the web page': z.string().describe('Short description of the page, following the naming conventions visible in the listAllAvailableReports response'),
117
- 'URL of the web page': z.string().describe('Full HTTPS URL of the page to test'),
118
- 'reason for testing the web page': z.string().describe('Reason for recommending this page for testing')
119
- },
153
+ description: 'Process my request to test a page about which no report is available yet.',
154
+ inputSchema: requestTestSchema,
155
+ outputSchema: requestTestResponseSchema,
120
156
  annotations: {
121
- title: 'Recommend quality testing of one web page',
157
+ title: 'Process my request to test a page about which no report is available yet.',
122
158
  readOnlyHint: false,
123
159
  idempotentHint: false,
124
160
  destructiveHint: false,
125
161
  openWorldHint: false
126
162
  }
127
163
  },
128
- async ({
129
- 'description of the web page': what,
130
- 'URL of the web page': url,
131
- 'reason for testing the web page': why
132
- }) => {
133
- if (!isURL(url)) {
134
- return {content: [{type: 'text', text: JSON.stringify({error: 'Invalid URL'})}], isError: true};
164
+ async ({description, URL, reason}) => {
165
+ const result = await requestTestAPI.response([description, URL, reason]);
166
+ return {content: [{type: 'text', text: JSON.stringify(result)}], structuredContent: result};
167
+ }
168
+ );
169
+ server.registerTool(
170
+ 'requestRetest',
171
+ {
172
+ description: 'Process my request to retest a page about which a report is available.',
173
+ inputSchema: requestRetestSchema,
174
+ outputSchema: requestRetestResponseSchema,
175
+ annotations: {
176
+ title: 'Process my request to retest a page about which a report is available.',
177
+ readOnlyHint: false,
178
+ idempotentHint: false,
179
+ destructiveHint: false,
180
+ openWorldHint: false
135
181
  }
136
- if (await isReportAvailable(what, url)) {
137
- return {content: [{type: 'text', text: JSON.stringify({error: 'A report about the page is already available'})}], isError: true};
182
+ },
183
+ async ({timeStamp, jobID, reason}) => {
184
+ const result = await requestRetestAPI.response([timeStamp, jobID, reason]);
185
+ return {content: [{type: 'text', text: JSON.stringify(result)}], structuredContent: result};
186
+ }
187
+ );
188
+ server.registerTool(
189
+ 'requestFeature',
190
+ {
191
+ description: 'Process my request to add or improve a feature.',
192
+ inputSchema: requestFeatureSchema,
193
+ outputSchema: requestFeatureResponseSchema,
194
+ annotations: {
195
+ title: 'Process my request to add or improve a feature.',
196
+ readOnlyHint: false,
197
+ idempotentHint: false,
198
+ destructiveHint: false,
199
+ openWorldHint: false
138
200
  }
139
- const result = await testRecFormAPI.response(what, url, why);
140
- return {content: [{type: 'text', text: JSON.stringify(result)}]};
201
+ },
202
+ async ({request}) => {
203
+ const result = await requestFeatureAPI.response([request]);
204
+ return {content: [{type: 'text', text: JSON.stringify(result)}], structuredContent: result};
141
205
  }
142
206
  );
143
207
  return server;