@jrpool/kilotest 46.1.2 → 48.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/.claude/settings.local.json +13 -1
  2. package/.devin/config.local.json +5 -1
  3. package/.github/workflows/ci.yml +0 -3
  4. package/.github/workflows/periodic-smoke-tests.yml +30 -0
  5. package/.github/workflows/publish-mcp.yml +4 -4
  6. package/{alerts.test.js → alerts.test.ts} +17 -29
  7. package/{alerts.js → alerts.ts} +10 -13
  8. package/api/{getReport.test.js → getReport.test.ts} +9 -10
  9. package/api/{getReport.js → getReport.ts} +23 -24
  10. package/api/{listDiagnoses.test.js → listDiagnoses.test.ts} +26 -27
  11. package/api/{listDiagnoses.js → listDiagnoses.ts} +46 -70
  12. package/api/{listIssues.test.js → listIssues.test.ts} +21 -14
  13. package/api/{listIssues.js → listIssues.ts} +75 -74
  14. package/api/{listReports.test.js → listReports.test.ts} +17 -16
  15. package/api/listReports.ts +87 -0
  16. package/api/{listViolators.test.js → listViolators.test.ts} +19 -20
  17. package/api/{listViolators.js → listViolators.ts} +45 -70
  18. package/api/requestFeature.test.ts +54 -0
  19. package/api/{requestFeature.js → requestFeature.ts} +18 -15
  20. package/api/requestRetest.test.ts +144 -0
  21. package/api/requestRetest.ts +119 -0
  22. package/api/requestTest.test.ts +153 -0
  23. package/api/requestTest.ts +123 -0
  24. package/api/{routes.test.js → routes.test.ts} +5 -5
  25. package/api/{routes.js → routes.ts} +6 -6
  26. package/api/{schemas.js → schemas.ts} +69 -50
  27. package/api/{util.test.js → util.test.ts} +35 -14
  28. package/api/{util.js → util.ts} +54 -51
  29. package/api/version.ts +8 -0
  30. package/{apiIntegration.test.js → apiIntegration.test.ts} +12 -13
  31. package/balances.ts +87 -0
  32. package/{checkinfo.js → checkinfo.ts} +24 -20
  33. package/docs/AI-TOOLS.md +4 -4
  34. package/docs/BACKLOG.md +360 -0
  35. package/docs/SERVICE.md +170 -17
  36. package/docs/decisions/002-coverage-tool.md +40 -0
  37. package/docs/decisions/003-adr-threshold.md +34 -0
  38. package/docs/decisions/004-docs-directory.md +23 -0
  39. package/docs/decisions/005-observability.md +28 -0
  40. package/docs/decisions/006-git-workflow.md +28 -0
  41. package/docs/decisions/007-internal-testing.md +34 -0
  42. package/docs/decisions/008-dependencies.md +28 -0
  43. package/docs/decisions/009-qai-integration.md +40 -0
  44. package/docs/decisions/QAI-HISTORICAL-CONTEXT.md +42 -0
  45. package/eslint.config.mjs +27 -0
  46. package/index.html +3 -3
  47. package/{index.test.js → index.test.ts} +397 -152
  48. package/{index.js → index.ts} +386 -285
  49. package/{indexBalances.test.js → indexBalances.test.ts} +21 -17
  50. package/{indexServe.test.js → indexServe.test.ts} +9 -9
  51. package/linkValidation.test.ts +190 -0
  52. package/{mcp.test.js → mcp.test.ts} +53 -26
  53. package/{mcp.js → mcp.ts} +29 -20
  54. package/memory/MEMORY.md +7 -0
  55. package/memory/user_maintainer_context.md +24 -0
  56. package/openapi.yaml +115 -68
  57. package/package.json +35 -15
  58. package/pm2.config.cjs +29 -0
  59. package/{routes.test.js → routes.test.ts} +8 -7
  60. package/{routing.test.js → routing.test.ts} +11 -12
  61. package/scripts/{generate-openapi.js → generate-openapi.ts} +13 -13
  62. package/serve.ts +15 -0
  63. package/smokeTest.ts +234 -0
  64. package/test/dbFixture.ts +21 -0
  65. package/test/fixtures/{buildFixtures.js → buildFixtures.ts} +14 -13
  66. package/test/{setup.cjs → setup.ts} +2 -2
  67. package/tsconfig.json +16 -0
  68. package/util.test.ts +1129 -0
  69. package/util.ts +1017 -0
  70. package/web/ai0BalanceForm/{ai0BalanceForm.test.js → ai0BalanceForm.test.ts} +15 -15
  71. package/web/ai0BalanceForm/{index.js → index.ts} +10 -18
  72. package/web/enqueue/index.ts +56 -0
  73. package/web/enqueueForm/index.html +9 -9
  74. package/web/enqueueForm/index.ts +43 -0
  75. package/web/expungeReportsForm/{expungeReportsForm.test.js → expungeReportsForm.test.ts} +18 -20
  76. package/web/expungeReportsForm/index.ts +18 -0
  77. package/web/hideReportForm/{hideReportForm.test.js → hideReportForm.test.ts} +14 -14
  78. package/web/hideReportForm/{index.js → index.ts} +17 -21
  79. package/web/listDiagnoses/{index.js → index.ts} +48 -58
  80. package/web/listDiagnoses/{listDiagnoses.test.js → listDiagnoses.test.ts} +39 -34
  81. package/web/listIssues/{index.js → index.ts} +67 -92
  82. package/web/listIssues/{listIssues.test.js → listIssues.test.ts} +45 -51
  83. package/web/listReports/index.html +3 -3
  84. package/web/listReports/{index.js → index.ts} +74 -58
  85. package/web/listReports/{listReports.test.js → listReports.test.ts} +41 -43
  86. package/web/listRules/{index.js → index.ts} +18 -23
  87. package/web/listRules/{listRules.test.js → listRules.test.ts} +26 -19
  88. package/web/listTopIssues/{index.js → index.ts} +36 -47
  89. package/web/listTopIssues/{listTopIssues.test.js → listTopIssues.test.ts} +26 -17
  90. package/web/listViolators/{index.js → index.ts} +51 -71
  91. package/web/listViolators/{listViolators.test.js → listViolators.test.ts} +43 -36
  92. package/web/manage/index.ts +22 -0
  93. package/web/pruneReportsForm/index.ts +18 -0
  94. package/web/pruneReportsForm/{pruneReportsForm.test.js → pruneReportsForm.test.ts} +11 -11
  95. package/web/reannotate/index.ts +71 -0
  96. package/web/reannotate/{reannotate.test.js → reannotate.test.ts} +19 -22
  97. package/web/reannotateForm/{index.js → index.ts} +41 -50
  98. package/web/reannotateForm/{reannotateForm.test.js → reannotateForm.test.ts} +13 -16
  99. package/web/renewWCAG/{index.js → index.ts} +9 -9
  100. package/web/renewWCAG/{renewWCAG.test.js → renewWCAG.test.ts} +17 -20
  101. package/web/renewWCAGForm/index.ts +22 -0
  102. package/web/{expungeReportsForm/index.js → reportDeletion.ts} +57 -39
  103. package/web/requestRetest/index.html +7 -7
  104. package/web/requestRetest/index.ts +62 -0
  105. package/web/requestRetest/requestRetest.test.ts +130 -0
  106. package/web/requestRetestForm/{index.js → index.ts} +10 -16
  107. package/web/requestRetestForm/{requestRetestForm.test.js → requestRetestForm.test.ts} +11 -12
  108. package/web/requestTest/index.html +7 -7
  109. package/web/requestTest/index.ts +52 -0
  110. package/web/requestTest/{requestTest.test.js → requestTest.test.ts} +39 -24
  111. package/web/requestTestForm/index.html +4 -4
  112. package/web/requestTestForm/index.ts +21 -0
  113. package/web/requestTestForm/{requestTestForm.test.js → requestTestForm.test.ts} +9 -9
  114. package/web/rewindReportsForm/index.ts +18 -0
  115. package/web/rewindReportsForm/{rewindReportsForm.test.js → rewindReportsForm.test.ts} +11 -11
  116. package/web/tutorialAI/index.html +184 -0
  117. package/web/tutorialAI/index.ts +80 -0
  118. package/web/tutorialAI/tutorialAI.test.ts +192 -0
  119. package/web/{tutorial → tutorialWeb}/index.html +9 -8
  120. package/web/tutorialWeb/index.ts +78 -0
  121. package/web/tutorialWeb/tutorialWeb.test.ts +195 -0
  122. package/web/unhideReportForm/{index.js → index.ts} +18 -22
  123. package/web/unhideReportForm/{unhideReportForm.test.js → unhideReportForm.test.ts} +16 -16
  124. package/aceconfig.js +0 -28
  125. package/api/listReports.js +0 -89
  126. package/api/requestFeature.test.js +0 -58
  127. package/api/requestRetest.js +0 -96
  128. package/api/requestRetest.test.js +0 -80
  129. package/api/requestTest.js +0 -106
  130. package/api/requestTest.test.js +0 -92
  131. package/api/version.js +0 -8
  132. package/indexFallback.test.js +0 -33
  133. package/indexWorkers.test.js +0 -79
  134. package/jsconfig.json +0 -8
  135. package/pm2.config.js +0 -18
  136. package/smokeTest.js +0 -128
  137. package/util.js +0 -744
  138. package/util.test.js +0 -968
  139. package/web/enqueue/index.js +0 -67
  140. package/web/enqueueForm/index.js +0 -49
  141. package/web/manage/index.js +0 -22
  142. package/web/pruneReportsForm/index.js +0 -123
  143. package/web/reannotate/index.js +0 -58
  144. package/web/renewWCAGForm/index.js +0 -22
  145. package/web/requestRetest/index.js +0 -31
  146. package/web/requestRetest/requestRetest.test.js +0 -119
  147. package/web/requestTest/index.js +0 -24
  148. package/web/requestTestForm/index.js +0 -21
  149. package/web/rewindReportsForm/index.js +0 -121
  150. package/web/tutorial/index.js +0 -63
  151. package/web/tutorial/tutorial.test.js +0 -97
  152. /package/test/fixtures/db/jobs/{recs.json → testRequests.json} +0 -0
  153. /package/web/{tutorial → tutorialWeb}/images/newsletter-form.png +0 -0
@@ -1,33 +0,0 @@
1
- /*
2
- indexFallback.test.js
3
- Tests that index.js loads successfully when PROTOCOL and TESTARO_WORKERS
4
- are not set, exercising the || fallback branches at module load time.
5
- This must be a separate file because index.js reads these env vars
6
- at module load time, and each test file runs in its own process.
7
- */
8
-
9
- // ENVIRONMENT (must be set before requiring index.js)
10
-
11
- const path = require('node:path');
12
- const fixtureDBDir = path.join(__dirname, 'test', 'fixtures', 'db');
13
-
14
- process.env.DB_DIR = fixtureDBDir;
15
- process.env.AUTH_CODE = 'test-auth-code';
16
- // Set PROTOCOL and TESTARO_WORKERS to empty strings (falsy) so that
17
- // the || fallbacks in index.js are exercised. dotenv does not override
18
- // existing env vars, so .env will not replace these.
19
- process.env.PROTOCOL = '';
20
- process.env.TESTARO_WORKERS = '';
21
-
22
- // IMPORTS
23
-
24
- const {test} = require('node:test');
25
- const assert = require('node:assert/strict');
26
- const {requestHandler} = require('./index');
27
-
28
- // TESTS
29
-
30
- test('index.js loads with empty PROTOCOL and TESTARO_WORKERS using fallbacks', () => {
31
- // If index.js loaded successfully, requestHandler is a function.
32
- assert.equal(typeof requestHandler, 'function');
33
- });
@@ -1,79 +0,0 @@
1
- /*
2
- indexWorkers.test.js
3
- Tests for index.js when TESTARO_WORKERS is invalid JSON.
4
- This must be a separate file because index.js reads TESTARO_WORKERS
5
- at module load time.
6
- */
7
-
8
- // ENVIRONMENT (must be set before requiring index.js)
9
-
10
- const path = require('node:path');
11
- const fixtureDBDir = path.join(__dirname, 'test', 'fixtures', 'db');
12
-
13
- process.env.DB_DIR = fixtureDBDir;
14
- process.env.AUTH_CODE = 'test-auth-code';
15
- process.env.TESTARO_WORKERS = 'not valid json';
16
-
17
- // IMPORTS
18
-
19
- const {test} = require('node:test');
20
- const assert = require('node:assert/strict');
21
- const http = require('node:http');
22
- const {requestHandler} = require('./index');
23
-
24
- // CONSTANTS
25
-
26
- const port = 3993;
27
-
28
- // HELPERS
29
-
30
- const request = (method, requestPath, body = null, headers = {}) => new Promise((resolve, reject) => {
31
- const options = {method, host: 'localhost', port, path: requestPath, headers: {...headers}};
32
- let bodyData = '';
33
- if (body) {
34
- bodyData = JSON.stringify(body);
35
- options.headers['content-type'] = 'application/json';
36
- options.headers['content-length'] = Buffer.byteLength(bodyData);
37
- }
38
- const req = http.request(options, response => {
39
- const chunks = [];
40
- response.on('data', chunk => chunks.push(chunk));
41
- response.on('end', () => {
42
- resolve({statusCode: response.statusCode, headers: response.headers, body: Buffer.concat(chunks).toString()});
43
- });
44
- });
45
- req.on('error', reject);
46
- req.end(bodyData || '');
47
- });
48
-
49
- // TESTS
50
-
51
- test('index.js loads with invalid TESTARO_WORKERS and treats workers as empty', () => {
52
- // If index.js loaded successfully, requestHandler is a function.
53
- assert.equal(typeof requestHandler, 'function');
54
- });
55
-
56
- test('POST /worker/job with invalid TESTARO_WORKERS returns 401 for any credentials', async () => {
57
- const server = http.createServer(requestHandler);
58
- await new Promise(resolve => server.listen(port, () => resolve()));
59
- try {
60
- const auth = Buffer.from('worker1:secret1').toString('base64');
61
- const res = await request('POST', '/worker/job', {}, {
62
- authorization: `Basic ${auth}`
63
- });
64
- assert.equal(res.statusCode, 401);
65
- }
66
- finally {
67
- server.closeAllConnections?.();
68
- await new Promise(resolve => {
69
- const timer = setTimeout(() => {
70
- server.closeAllConnections?.();
71
- resolve();
72
- }, 1000);
73
- server.close(() => {
74
- clearTimeout(timer);
75
- resolve();
76
- });
77
- });
78
- }
79
- });
package/jsconfig.json DELETED
@@ -1,8 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "allowJs": true,
4
- "checkJs": true,
5
- "noEmit": true,
6
- "strict": false
7
- }
8
- }
package/pm2.config.js DELETED
@@ -1,18 +0,0 @@
1
- module.exports = {
2
- apps: [
3
- {
4
- name: 'kilotest',
5
- script: 'index.js',
6
- instances: 1,
7
- autorestart: true,
8
- watch: false,
9
- max_memory_restart: '500M',
10
- time: true,
11
- env: {
12
- NODE_ENV: 'production',
13
- BASE_PATH: '/',
14
- DEMO_SSE_DELAY_MS: '100'
15
- }
16
- }
17
- ]
18
- };
package/smokeTest.js DELETED
@@ -1,128 +0,0 @@
1
- /*
2
- smokeTest.js
3
- Sends requests to all valid GET and POST paths on the deployed server and verifies that Caddy forwards them to Kilotest (i.e., the response is not a bare Caddy 404).
4
- */
5
-
6
- // IMPORTS
7
-
8
- const https = require('https');
9
- const {routes} = require('./index');
10
-
11
- // CONSTANTS
12
-
13
- const host = process.env.SMOKE_HOST || 'kilotest.com';
14
- // Concrete paths matching each wildcard pattern in the routes table, for smoke testing.
15
- const concretePaths = {
16
- GET: {
17
- '*.html*': '/listReports.html',
18
- '/': '/',
19
- '/api-docs': '/api-docs',
20
- '/api/*': '/api/listReports',
21
- '/capability.md': '/capability.md',
22
- '/favicon.*': '/favicon.ico',
23
- '/fullReport.json/*': '/fullReport.json/260101T0000/mix',
24
- '/index.html': '/index.html',
25
- '/llms-full.txt': '/llms-full.txt',
26
- '/llms.txt': '/llms.txt',
27
- '/mcp': '/mcp',
28
- '/openapi.json': '/openapi.json',
29
- '/openapi.yaml': '/openapi.yaml',
30
- '/robots.txt': '/robots.txt',
31
- '/sitemap.xml': '/sitemap.xml',
32
- '/style.css': '/style.css',
33
- '/swagger.json': '/swagger.json',
34
- '/swagger.yaml': '/swagger.yaml',
35
- '/tutorial/images/*': '/tutorial/images/diagram.png'
36
- },
37
- POST: {
38
- '/api/*': '/api/requestFeature',
39
- '/mcp': '/mcp',
40
- '/reannotate.html': '/reannotate.html',
41
- '/recAction.html': '/recAction.html',
42
- '/renewWCAG.html': '/renewWCAG.html',
43
- '/requestRetest.html/*': '/requestRetest.html/260101T0001/ct',
44
- '/requestTest.html': '/requestTest.html',
45
- '/tutorialComment.html': '/tutorialComment.html',
46
- '/worker/job': '/worker/job',
47
- '/worker/report': '/worker/report'
48
- }
49
- };
50
- // Minimal POST bodies for paths that require them.
51
- const postBodies = {
52
- '/api/requestFeature': {feature: 'smoke test'},
53
- '/mcp': {},
54
- '/reannotate.html': {authCode: 'invalid'},
55
- '/recAction.html': {
56
- target: 'https://smoketest.example.com\tSmoke Test Page', authCode: 'invalid'
57
- },
58
- '/renewWCAG.html': {authCode: 'invalid'},
59
- '/requestRetest.html/260101T0001/ct': {why: 'smoke test'},
60
- '/requestTest.html': {what: 'Smoke Test Page', url: 'https://smoketest.example.com', why: 'smoke test'},
61
- '/tutorialComment.html': {content: 'smoke test'},
62
- '/worker/job': {},
63
- '/worker/report': {}
64
- };
65
-
66
- // FUNCTIONS
67
-
68
- // Sends an HTTPS request and returns the status code and body length.
69
- const sendRequest = (method, requestPath) => new Promise((resolve, reject) => {
70
- const body = method === 'POST' ? JSON.stringify(postBodies[requestPath] || {}) : null;
71
- const headers = {'x-kilotest-smoke': '1'};
72
- if (body) {
73
- headers['content-type'] = 'application/json; charset=utf-8';
74
- headers['content-length'] = Buffer.byteLength(body);
75
- }
76
- const options = {
77
- method,
78
- host,
79
- path: requestPath,
80
- headers
81
- };
82
- const req = https.request(options, response => {
83
- const chunks = [];
84
- response.on('data', chunk => chunks.push(chunk));
85
- response.on('end', () => {
86
- const responseBody = chunks.join('');
87
- resolve({statusCode: response.statusCode, bodyLength: responseBody.length});
88
- });
89
- });
90
- req.on('error', reject);
91
- req.end(body || '');
92
- });
93
-
94
- // Returns whether a response is a bare Caddy 404 (the failure this test detects).
95
- const isCaddy404 = result => result.statusCode === 404 && result.bodyLength === 0;
96
-
97
- // EXECUTION
98
-
99
- (async () => {
100
- let failures = 0;
101
- for (const method of ['GET', 'POST']) {
102
- console.log(`\n=== ${method} paths ===`);
103
- for (const pattern of routes[method]) {
104
- const requestPath = concretePaths[method][pattern];
105
- if (!requestPath) {
106
- console.log(`FAIL: no concrete path defined for pattern ${pattern}`);
107
- failures++;
108
- continue;
109
- }
110
- try {
111
- const result = await sendRequest(method, requestPath);
112
- if (isCaddy404(result)) {
113
- console.log(`FAIL: ${method} ${requestPath} -> Caddy 404 (path not forwarded)`);
114
- failures++;
115
- }
116
- else {
117
- console.log(`PASS: ${method} ${requestPath} -> ${result.statusCode} (body ${result.bodyLength} bytes)`);
118
- }
119
- }
120
- catch (error) {
121
- console.log(`FAIL: ${method} ${requestPath} -> error: ${error.message}`);
122
- failures++;
123
- }
124
- }
125
- }
126
- console.log(`\n=== ${failures === 0 ? 'All paths forwarded' : `${failures} failure(s)`} ===`);
127
- process.exit(failures === 0 ? 0 : 1);
128
- })();