@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.
- package/.markdownlint-cli2.jsonc +12 -0
- package/.vscode/settings.json +3 -0
- package/CLAUDE.md +5 -0
- package/README.md +6 -4
- package/ai0BalanceForm/index.html +1 -1
- package/alerts.js +3 -1
- package/api/getReport.js +66 -0
- package/api/listDiagnoses.js +157 -0
- package/api/listIssues.js +225 -0
- package/api/listReports.js +87 -0
- package/api/listViolators.js +164 -0
- package/api/requestFeature.js +56 -0
- package/api/requestRetest.js +102 -0
- package/api/requestTest.js +106 -0
- package/api/routes.js +97 -0
- package/api/schemas.js +297 -0
- package/api/testSuite.js +294 -0
- package/api/util.js +149 -0
- package/diagnoses/index.js +2 -2
- package/docs/{AI-TOOL.md → AI-TOOLS.md} +54 -26
- package/docs/SERVICE.md +4 -1
- package/docs/decisions/001-api-design.md +59 -49
- package/eslint.config.mjs +13 -3
- package/index.html +1 -1
- package/index.js +202 -188
- package/issues/index.js +13 -21
- package/jsconfig.json +8 -0
- package/llms-full.txt +2 -2
- package/llms.txt +16 -11
- package/mcp.js +129 -65
- package/openapi.yaml +1234 -572
- package/package.json +18 -11
- package/reannotate/index.js +26 -15
- package/reannotateForm/index.js +15 -13
- package/redocly.yaml +4 -0
- package/reportHideForm/index.html +1 -1
- package/reportHideForm/index.js +24 -38
- package/reportIssue/index.js +3 -3
- package/reportIssues/index.js +128 -1
- package/reportUnhideForm/index.js +36 -44
- package/reportsExpungeForm/index.js +22 -16
- package/reportsPruneForm/index.js +22 -12
- package/reportsRewindForm/index.js +17 -9
- package/retestRec/index.js +8 -4
- package/retestRecForm/index.js +18 -6
- package/scripts/generate-openapi.js +83 -0
- package/targets/index.js +18 -13
- package/testOrder/index.js +11 -8
- package/tutorial/index.html +12 -12
- package/util.js +581 -539
- package/api/reportList.js +0 -83
- package/api/reportSummary.js +0 -181
- package/reportIssue/api.js +0 -183
- package/reportIssues/util.js +0 -138
- package/researchAgent.js +0 -206
- package/target/api.js +0 -126
- package/testRecForm/api.js +0 -55
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/*
|
|
2
|
+
listViolators.js
|
|
3
|
+
Returns details about one issue in one report and basics about all the violators of the issue.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// IMPORTS
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
getIssueClassification,
|
|
10
|
+
getReportBasics,
|
|
11
|
+
getResponseMetadata,
|
|
12
|
+
getRuleEnginesFacts,
|
|
13
|
+
getToolsFacts,
|
|
14
|
+
thisHost
|
|
15
|
+
} = require('./util');
|
|
16
|
+
const {getReport} = require('../util');
|
|
17
|
+
|
|
18
|
+
// FUNCTIONS
|
|
19
|
+
|
|
20
|
+
// Returns the response body.
|
|
21
|
+
exports.response = async args => {
|
|
22
|
+
const [issueID = '', timeStamp = '', jobID = ''] = args;
|
|
23
|
+
// Initialize the response content.
|
|
24
|
+
const responseContent = {
|
|
25
|
+
'basics about the report': null,
|
|
26
|
+
'basics about the issue': null,
|
|
27
|
+
'details about the issue': null,
|
|
28
|
+
'basics about all elements exhibiting the issue': null
|
|
29
|
+
};
|
|
30
|
+
// Get the report.
|
|
31
|
+
const report = await getReport(timeStamp, jobID);
|
|
32
|
+
// If this failed:
|
|
33
|
+
if (report.error) {
|
|
34
|
+
// Add this to the response content.
|
|
35
|
+
responseContent['basics about the report'] = report;
|
|
36
|
+
}
|
|
37
|
+
// Otherwise, i.e. if it succeeded:
|
|
38
|
+
else {
|
|
39
|
+
// Get the basics about the report (which may be only an error message).
|
|
40
|
+
const reportBasics = await getReportBasics(timeStamp, jobID);
|
|
41
|
+
// Add them to the response content.
|
|
42
|
+
responseContent['basics about the report'] = reportBasics;
|
|
43
|
+
}
|
|
44
|
+
// Get the classification of the issue.
|
|
45
|
+
const issueClassification = issueID ? getIssueClassification(issueID) : null;
|
|
46
|
+
// If the issue is ignorable or not fully classified:
|
|
47
|
+
if (!issueClassification) {
|
|
48
|
+
// Add this to the response content.
|
|
49
|
+
responseContent['basics about the issue'] = {
|
|
50
|
+
'error': 'No information about the specified issue is available'
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
// Otherwise, i.e. if it is non-ignorable and fully classified:
|
|
54
|
+
else {
|
|
55
|
+
const {summary, wcag, weight, why} = issueClassification;
|
|
56
|
+
// Initialize the basics and details about it.
|
|
57
|
+
const issueBasics = {
|
|
58
|
+
'identifier': issueID,
|
|
59
|
+
summary,
|
|
60
|
+
'impact on a user': why,
|
|
61
|
+
'related WCAG standard': {
|
|
62
|
+
'layer': (wcag.length > 4 ? 'success criterion' : 'guideline'),
|
|
63
|
+
'identifier': wcag
|
|
64
|
+
},
|
|
65
|
+
priority: ['lowest', 'low', 'high', 'highest'][weight - 1]
|
|
66
|
+
};
|
|
67
|
+
// Add the basics about the issue to the response content.
|
|
68
|
+
responseContent['basics about the issue'] = issueBasics;
|
|
69
|
+
// If the report is available:
|
|
70
|
+
if (!report.error) {
|
|
71
|
+
// Initialize data about the instances of the issue.
|
|
72
|
+
const reporterIDs = new Set();
|
|
73
|
+
const violators = {};
|
|
74
|
+
// For each act in the report:
|
|
75
|
+
report.acts.forEach(act => {
|
|
76
|
+
const {result, type, which} = act;
|
|
77
|
+
const instances = result?.standardResult?.instances || [];
|
|
78
|
+
// If the act is a test act with a specified rule engine:
|
|
79
|
+
if (type === 'test' && which) {
|
|
80
|
+
// For each standard instance of the act:
|
|
81
|
+
instances.forEach(instance => {
|
|
82
|
+
// If the instance has the issue ID:
|
|
83
|
+
if (instance.issueID === issueID) {
|
|
84
|
+
const {catalogIndex} = instance;
|
|
85
|
+
// Ensure the rule-engine ID is in the reporters data.
|
|
86
|
+
reporterIDs.add(which);
|
|
87
|
+
// If the instance has a catalog index:
|
|
88
|
+
if (catalogIndex) {
|
|
89
|
+
// Ensure the catalog index is in the violators data.
|
|
90
|
+
violators[catalogIndex] ??= {
|
|
91
|
+
catalogIndex,
|
|
92
|
+
reporters: new Set()
|
|
93
|
+
};
|
|
94
|
+
// Ensure the reporter ID is in the violator data.
|
|
95
|
+
violators[catalogIndex].reporters.add(which);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
// Get details about the reporters of the issue.
|
|
102
|
+
const reportersFacts = getRuleEnginesFacts(reporterIDs);
|
|
103
|
+
// Add them to the facts about the issue.
|
|
104
|
+
const issueDetails = {
|
|
105
|
+
'rule engines reporting violations belonging to the issue': reportersFacts
|
|
106
|
+
};
|
|
107
|
+
// Add the details about the issue to the response content.
|
|
108
|
+
responseContent['details about the issue'] = issueDetails;
|
|
109
|
+
const {catalog} = report;
|
|
110
|
+
// Get a sorted array of data about the violators.
|
|
111
|
+
const sortedViolatorData = Object.values(violators).sort(
|
|
112
|
+
(a, b) => {
|
|
113
|
+
if (b.reporters.size === a.reporters.size) {
|
|
114
|
+
return Number(a.catalogIndex) - Number(b.catalogIndex);
|
|
115
|
+
}
|
|
116
|
+
return b.reporters.size - a.reporters.size;
|
|
117
|
+
}
|
|
118
|
+
);
|
|
119
|
+
// Get basics about the violators.
|
|
120
|
+
const violatorsBasics = sortedViolatorData
|
|
121
|
+
.map(violator => {
|
|
122
|
+
const {catalogIndex, reporters} = violator;
|
|
123
|
+
const catalogItem = catalog[catalogIndex];
|
|
124
|
+
return {
|
|
125
|
+
identifier: catalogIndex,
|
|
126
|
+
'tag name': catalogItem?.tagName || null,
|
|
127
|
+
'inner text': catalogItem?.text ?? null,
|
|
128
|
+
'count of rule engines reporting that the element exhibited the issue': reporters.size,
|
|
129
|
+
'how to get details about the element': {
|
|
130
|
+
URL: `${thisHost}/api/listDiagnoses/${catalogIndex}/${issueID}/${timeStamp}/${jobID}`,
|
|
131
|
+
'request method': 'GET'
|
|
132
|
+
},
|
|
133
|
+
'web users can get details about the element at': `${thisHost}/diagnoses.html/${issueID}/${timeStamp}/${jobID}/${catalogIndex}`
|
|
134
|
+
};
|
|
135
|
+
});
|
|
136
|
+
// Add basics about the violators to the response content.
|
|
137
|
+
responseContent['basics about all elements exhibiting the issue'] = violatorsBasics;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Create a response body.
|
|
141
|
+
const body = {
|
|
142
|
+
'tool collection': getToolsFacts(),
|
|
143
|
+
'tool name': 'listViolators',
|
|
144
|
+
'this request': {
|
|
145
|
+
description: 'Provide details about one issue in one report, including basics about the elements of the tested page that exhibited the issue. The issueID, timeStamp, and jobID parameters identify the issue and report that I want details about. Those parameters were in the response to my earlier listIssues request.',
|
|
146
|
+
method: 'GET',
|
|
147
|
+
URL: `${thisHost}/api/listViolators/${issueID}/${timeStamp}/${jobID}`,
|
|
148
|
+
'closest ancestor request': {
|
|
149
|
+
'tool name': 'listIssues',
|
|
150
|
+
description: 'Provide details about one report, including basics about the issues reported in it.',
|
|
151
|
+
method: 'GET',
|
|
152
|
+
URL: `${thisHost}/api/listIssues/${timeStamp}/${jobID}`
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
'URLs of similar requests for web users': {
|
|
156
|
+
'this request': `${thisHost}/reportIssue.html/${issueID}/${timeStamp}/${jobID}`,
|
|
157
|
+
'closest ancestor request': `${thisHost}/reportIssues.html/${timeStamp}/${jobID}`
|
|
158
|
+
},
|
|
159
|
+
'response metadata': getResponseMetadata(),
|
|
160
|
+
'response content': responseContent
|
|
161
|
+
}
|
|
162
|
+
// Return it.
|
|
163
|
+
return body;
|
|
164
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/*
|
|
2
|
+
requestFeature.js
|
|
3
|
+
Processes a request to add or improve a feature and returns an acknowledgement.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// IMPORTS
|
|
7
|
+
|
|
8
|
+
const {getResponseMetadata, getToolsFacts, thisHost} = require('./util');
|
|
9
|
+
const {sendAlert} = require('../alerts');
|
|
10
|
+
|
|
11
|
+
// FUNCTIONS
|
|
12
|
+
|
|
13
|
+
// Returns the response body.
|
|
14
|
+
exports.response = async args => {
|
|
15
|
+
const [request = ''] = args;
|
|
16
|
+
// Initialize the response content.
|
|
17
|
+
const responseContent = {
|
|
18
|
+
'details about your request': null
|
|
19
|
+
};
|
|
20
|
+
// If the request is empty:
|
|
21
|
+
if (!request) {
|
|
22
|
+
// Add this to the response content.
|
|
23
|
+
responseContent['details about your request'] = {
|
|
24
|
+
error: 'request invalid: request is empty'
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
// Otherwise, i.e. if it exists:
|
|
28
|
+
else {
|
|
29
|
+
// Notify the manager.
|
|
30
|
+
await sendAlert('MCP feature request received', request);
|
|
31
|
+
// Add the disposition to the response content.
|
|
32
|
+
responseContent['details about your request'] = {
|
|
33
|
+
'date and time received': new Date().toISOString(),
|
|
34
|
+
disposition: 'received and logged; manager notified'
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
// Create a response body.
|
|
38
|
+
const body = {
|
|
39
|
+
'tool collection': getToolsFacts(),
|
|
40
|
+
'tool name': 'requestFeature',
|
|
41
|
+
'this request': {
|
|
42
|
+
description: 'Process my request to add or improve a feature.',
|
|
43
|
+
method: 'POST',
|
|
44
|
+
URL: `${thisHost}/api/requestFeature`,
|
|
45
|
+
body: {
|
|
46
|
+
request
|
|
47
|
+
},
|
|
48
|
+
'closest ancestor request': null
|
|
49
|
+
},
|
|
50
|
+
'URLs of similar requests for web users': null,
|
|
51
|
+
'response metadata': getResponseMetadata(),
|
|
52
|
+
'response content': responseContent
|
|
53
|
+
};
|
|
54
|
+
// Return it.
|
|
55
|
+
return body;
|
|
56
|
+
};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/*
|
|
2
|
+
requestRetest.js
|
|
3
|
+
Processes a request to retest a page and returns an acknowledgement.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// IMPORTS
|
|
7
|
+
|
|
8
|
+
const {getResponseMetadata, getToolsFacts, processTestRequest, thisHost} = require('./util');
|
|
9
|
+
const {getReportsExtract} = require('../util');
|
|
10
|
+
|
|
11
|
+
// FUNCTIONS
|
|
12
|
+
|
|
13
|
+
// Returns the response body.
|
|
14
|
+
exports.response = async args => {
|
|
15
|
+
const [timeStamp = '', jobID = '', reason = ''] = args;
|
|
16
|
+
// Initialize the response content.
|
|
17
|
+
const responseContent = {
|
|
18
|
+
'details about your request': {},
|
|
19
|
+
'disposition of your request': null
|
|
20
|
+
};
|
|
21
|
+
const reasonLength = reason.length;
|
|
22
|
+
// Get data on the available reports.
|
|
23
|
+
const reportsExtract = await getReportsExtract();
|
|
24
|
+
// Get data on the report.
|
|
25
|
+
const reportExtract = Object
|
|
26
|
+
.values(reportsExtract)
|
|
27
|
+
.find(extract => extract.timeStamp === timeStamp && extract.jobID === jobID);
|
|
28
|
+
const {what, url} = reportExtract || {};
|
|
29
|
+
// If this failed:
|
|
30
|
+
if (!reportExtract) {
|
|
31
|
+
// Add this to the response content.
|
|
32
|
+
responseContent['details about your request'] = {
|
|
33
|
+
error: 'request invalid: the specified existing report is not an available report'
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
// Otherwise, if the report has been superseded:
|
|
37
|
+
else if (
|
|
38
|
+
Object
|
|
39
|
+
.values(reportsExtract)
|
|
40
|
+
.filter(extract => extract.what === what && extract.url === url)
|
|
41
|
+
.length > 1
|
|
42
|
+
) {
|
|
43
|
+
// Add this to the response content.
|
|
44
|
+
responseContent['details about your request'] = {
|
|
45
|
+
error: 'request invalid: a later report about the page exists'
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
// Otherwise, if the encoded reason is too short or too long:
|
|
49
|
+
else if (reasonLength < 20 || reasonLength > 100) {
|
|
50
|
+
// Add this to the response content.
|
|
51
|
+
responseContent['details about your request'] = {
|
|
52
|
+
error: 'request invalid: your reason is not between 20 and 100 characters long'
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// Otherwise, i.e. if getting the report succeeded and the request is valid:
|
|
56
|
+
else {
|
|
57
|
+
// Process the request.
|
|
58
|
+
await processTestRequest('retest', what, url, reason);
|
|
59
|
+
// Add details about the request to the response content.
|
|
60
|
+
responseContent['details about your request'] = {
|
|
61
|
+
'date and time received': new Date().toISOString(),
|
|
62
|
+
'page to be retested': {
|
|
63
|
+
'description': what,
|
|
64
|
+
'URL': url
|
|
65
|
+
},
|
|
66
|
+
'reason why the page should be retested': reason
|
|
67
|
+
};
|
|
68
|
+
// Add information about the disposition of the request to the response content.
|
|
69
|
+
responseContent['disposition of your request'] = {
|
|
70
|
+
'what happens next': 'Your request is likely to be approved and processed within 1 hour to 1 day.',
|
|
71
|
+
'how you can check for completion': 'You can call the listReports tool to learn whether the page has been retested and a new report is available.',
|
|
72
|
+
'how a web user can check for completion': `A web user can visit ${thisHost}/targets.html to learn whether the page has been retested and a new report is available.`
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
// Create a response body.
|
|
76
|
+
const body = {
|
|
77
|
+
'tool collection': getToolsFacts(),
|
|
78
|
+
'tool name': 'requestRetest',
|
|
79
|
+
'this request': {
|
|
80
|
+
description: 'Process my request to retest a page. The timeStamp and jobID parameters identify the latest available report about the page. Those parameters were in the response to my earlier listIssues request. The reason property of the request body is the reason why the page should be retested.',
|
|
81
|
+
method: 'POST',
|
|
82
|
+
URL: `${thisHost}/api/requestRetest/${timeStamp}/${jobID}`,
|
|
83
|
+
body: {
|
|
84
|
+
reason
|
|
85
|
+
},
|
|
86
|
+
'closest ancestor request': {
|
|
87
|
+
'tool name': 'listIssues',
|
|
88
|
+
description: 'Provide details about one report, including basics about the issues reported in it.',
|
|
89
|
+
method: 'GET',
|
|
90
|
+
URL: `${thisHost}/api/listIssues/${timeStamp}/${jobID}`
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
'URLs of similar requests for web users': {
|
|
94
|
+
'this request': `${thisHost}/retestRecForm.html/${timeStamp}/${jobID}`,
|
|
95
|
+
'closest ancestor request': `${thisHost}/reportIssues.html/${timeStamp}/${jobID}`
|
|
96
|
+
},
|
|
97
|
+
'response metadata': getResponseMetadata(),
|
|
98
|
+
'response content': responseContent
|
|
99
|
+
};
|
|
100
|
+
// Return it.
|
|
101
|
+
return body;
|
|
102
|
+
};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/*
|
|
2
|
+
requestTest.js
|
|
3
|
+
Processes a request to test an untested page and returns an acknowledgement.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// IMPORTS
|
|
7
|
+
|
|
8
|
+
const {getResponseMetadata, getToolsFacts, processTestRequest, thisHost} = require('./util');
|
|
9
|
+
const {getReportExtracts, isURL} = require('../util');
|
|
10
|
+
|
|
11
|
+
// FUNCTIONS
|
|
12
|
+
|
|
13
|
+
// Returns the response body.
|
|
14
|
+
exports.response = async args => {
|
|
15
|
+
const [what = '', url = '', reason = ''] = args;
|
|
16
|
+
// Initialize the response content.
|
|
17
|
+
const responseContent = {
|
|
18
|
+
'details about your request': {},
|
|
19
|
+
'disposition of your request': null
|
|
20
|
+
};
|
|
21
|
+
const whatLength = what.length;
|
|
22
|
+
// If the description is empty or too long:
|
|
23
|
+
if (!whatLength || whatLength > 100) {
|
|
24
|
+
// Add this to the response content.
|
|
25
|
+
responseContent['details about your request'] = {
|
|
26
|
+
error: 'request invalid: your description of the page is not between 1 and 100 characters long'
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
// Otherwise, i.e. if the URL is too short or too long::
|
|
30
|
+
else if (url.length < 12 || url.length > 300) {
|
|
31
|
+
// Add this to the response content.
|
|
32
|
+
responseContent['details about your request'] = {
|
|
33
|
+
error: 'request invalid: you specified a URL for the page that is not between 12 and 300 characters long'
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
// Otherwise, i.e. if the URL is invalid:
|
|
37
|
+
else if (!isURL(url)) {
|
|
38
|
+
// Add this to the response content.
|
|
39
|
+
responseContent['details about your request'] = {
|
|
40
|
+
error: 'request invalid: you specified an invalid URL for the page'
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
// Otherwise, i.e. if the description and URL are valid:
|
|
44
|
+
else {
|
|
45
|
+
// Get an extract of the available reports.
|
|
46
|
+
const reportExtracts = await getReportExtracts();
|
|
47
|
+
// If any report is on a page with the specified description and URL:
|
|
48
|
+
if (
|
|
49
|
+
reportExtracts.some(extract => extract.what === what && extract.url === url)
|
|
50
|
+
) {
|
|
51
|
+
// Add this to the response content.
|
|
52
|
+
responseContent['details about your request'] = {
|
|
53
|
+
error: 'request invalid: the page has already been tested and its report is available'
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
// Otherwise, i.e. if none is on the page:
|
|
57
|
+
else {
|
|
58
|
+
// Process the request.
|
|
59
|
+
await processTestRequest('test', what, url, reason);
|
|
60
|
+
// Add details about the request to the response content.
|
|
61
|
+
responseContent['details about your request'] = {
|
|
62
|
+
'date and time received': new Date().toISOString(),
|
|
63
|
+
'page to be tested': {
|
|
64
|
+
description: what,
|
|
65
|
+
URL: url
|
|
66
|
+
},
|
|
67
|
+
'reason why the page should be tested': reason
|
|
68
|
+
};
|
|
69
|
+
// Add information about the disposition of the request to the response content.
|
|
70
|
+
responseContent['disposition of your request'] = {
|
|
71
|
+
'what happens next': 'Your request is likely to be approved and processed within 1 hour to 1 day.',
|
|
72
|
+
'how you can check for completion': 'You can call the listReports tool to learn whether the page has been tested and a report is available.',
|
|
73
|
+
'how a web user can check for completion': `A web user can visit ${thisHost}/targets.html to learn whether the page has been tested and a report is available.`
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Create a response body.
|
|
78
|
+
const body = {
|
|
79
|
+
'tool collection': getToolsFacts(),
|
|
80
|
+
'tool name': 'requestTest',
|
|
81
|
+
'this request': {
|
|
82
|
+
description: 'Process my request to test a page about which no report is available yet. I have provided a description and the URL of the page and a reason why it should be tested.',
|
|
83
|
+
method: 'POST',
|
|
84
|
+
URL: `${thisHost}/api/requestTest`,
|
|
85
|
+
body: {
|
|
86
|
+
description: what,
|
|
87
|
+
URL: url,
|
|
88
|
+
reason
|
|
89
|
+
},
|
|
90
|
+
'closest ancestor request': {
|
|
91
|
+
'tool name': 'listReports',
|
|
92
|
+
description: 'Provide basics about all available reports.',
|
|
93
|
+
method: 'GET',
|
|
94
|
+
URL: `${thisHost}/api/listReports`
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
'URLs of similar requests for web users': {
|
|
98
|
+
'this request': `${thisHost}/testRecForm.html`,
|
|
99
|
+
'closest ancestor request': `${thisHost}/targets.html`
|
|
100
|
+
},
|
|
101
|
+
'response metadata': getResponseMetadata(),
|
|
102
|
+
'response content': responseContent
|
|
103
|
+
};
|
|
104
|
+
// Return it.
|
|
105
|
+
return body;
|
|
106
|
+
};
|
package/api/routes.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/*
|
|
2
|
+
routes.js
|
|
3
|
+
Route metadata for OpenAPI generation. Pairs each Kilotest API operation with its HTTP method, path template, and the request/response schemas from schemas.js. This table supplies the facts that schemas.js cannot express on its own (method, path, path-vs-body placement), mirroring the manual dispatch in index.js and the // GET/POST comments in schemas.js.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// IMPORTS
|
|
7
|
+
|
|
8
|
+
const {z} = require('zod');
|
|
9
|
+
const {
|
|
10
|
+
listIssuesSchema,
|
|
11
|
+
listViolatorsSchema,
|
|
12
|
+
listDiagnosesSchema,
|
|
13
|
+
getReportSchema,
|
|
14
|
+
requestTestSchema,
|
|
15
|
+
requestRetestSchema,
|
|
16
|
+
requestFeatureSchema,
|
|
17
|
+
listReportsResponseSchema,
|
|
18
|
+
listIssuesResponseSchema,
|
|
19
|
+
listViolatorsResponseSchema,
|
|
20
|
+
listDiagnosesResponseSchema,
|
|
21
|
+
getReportResponseSchema,
|
|
22
|
+
requestTestResponseSchema,
|
|
23
|
+
requestRetestResponseSchema,
|
|
24
|
+
requestFeatureResponseSchema
|
|
25
|
+
} = require('./schemas');
|
|
26
|
+
|
|
27
|
+
// ROUTES
|
|
28
|
+
|
|
29
|
+
module.exports = [
|
|
30
|
+
{
|
|
31
|
+
operationId: 'listReports',
|
|
32
|
+
method: 'get',
|
|
33
|
+
path: '/api/listReports',
|
|
34
|
+
summary: 'List all available reports',
|
|
35
|
+
responseSchema: listReportsResponseSchema
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
operationId: 'listIssues',
|
|
39
|
+
method: 'get',
|
|
40
|
+
path: '/api/listIssues/{timeStamp}/{jobID}',
|
|
41
|
+
summary: 'List basics about the issues in one report',
|
|
42
|
+
pathParamsSchema: z.object(listIssuesSchema),
|
|
43
|
+
responseSchema: listIssuesResponseSchema
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
operationId: 'listViolators',
|
|
47
|
+
method: 'get',
|
|
48
|
+
path: '/api/listViolators/{issueID}/{timeStamp}/{jobID}',
|
|
49
|
+
summary: 'List elements reported as exhibiting one issue',
|
|
50
|
+
pathParamsSchema: z.object(listViolatorsSchema),
|
|
51
|
+
responseSchema: listViolatorsResponseSchema
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
operationId: 'listDiagnoses',
|
|
55
|
+
method: 'get',
|
|
56
|
+
path: '/api/listDiagnoses/{catalogIndex}/{issueID}/{timeStamp}/{jobID}',
|
|
57
|
+
summary: 'List diagnoses of how one element exhibited one issue',
|
|
58
|
+
pathParamsSchema: z.object(listDiagnosesSchema),
|
|
59
|
+
responseSchema: listDiagnosesResponseSchema
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
operationId: 'getReport',
|
|
63
|
+
method: 'get',
|
|
64
|
+
path: '/api/getReport/{timeStamp}/{jobID}',
|
|
65
|
+
summary: 'Get one full report in JSON',
|
|
66
|
+
pathParamsSchema: z.object(getReportSchema),
|
|
67
|
+
responseSchema: getReportResponseSchema
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
operationId: 'requestTest',
|
|
71
|
+
method: 'post',
|
|
72
|
+
path: '/api/requestTest',
|
|
73
|
+
summary: 'Request that a page be tested',
|
|
74
|
+
bodySchema: z.object(requestTestSchema),
|
|
75
|
+
responseSchema: requestTestResponseSchema
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
operationId: 'requestRetest',
|
|
79
|
+
method: 'post',
|
|
80
|
+
path: '/api/requestRetest/{timeStamp}/{jobID}',
|
|
81
|
+
summary: 'Request that a page be retested',
|
|
82
|
+
pathParamsSchema: z.object({
|
|
83
|
+
timeStamp: requestRetestSchema.timeStamp,
|
|
84
|
+
jobID: requestRetestSchema.jobID
|
|
85
|
+
}),
|
|
86
|
+
bodySchema: z.object({reason: requestRetestSchema.reason}),
|
|
87
|
+
responseSchema: requestRetestResponseSchema
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
operationId: 'requestFeature',
|
|
91
|
+
method: 'post',
|
|
92
|
+
path: '/api/requestFeature',
|
|
93
|
+
summary: 'Request a new feature or feature improvement',
|
|
94
|
+
bodySchema: z.object(requestFeatureSchema),
|
|
95
|
+
responseSchema: requestFeatureResponseSchema
|
|
96
|
+
}
|
|
97
|
+
];
|