@jrpool/kilotest 59.1.2 → 59.1.4

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/docs/AI-TOOLS.md CHANGED
@@ -29,7 +29,7 @@ The internal features that make Kilotest a collection of tools for language mode
29
29
  - A `server.json` file, conforming to the [MCP server schema](https://modelcontextprotocol.io/), and a GitHub Actions workflow (`publish-mcp.yml`) that authenticates via GitHub OIDC and publishes that file to the official MCP Registry whenever `server.json` or `api/version.ts` changes on the `main` branch.
30
30
  - A `capability.md` file with a URL, summarizing what Kilotest tools can do.
31
31
  - `mcp`, `mcp-server`, and `modelcontextprotocol` keywords in `package.json`, supporting discovery of the `@jrpool/kilotest` npm package by tools and humans searching the npm registry for MCP servers.
32
- - An `lhm.plugin.json` file, conforming to the [LobeHub plugin manifest format](https://market.lobehub.com/s/publish-mcp/references/manifest), declaring Kilotest as a plugin in the [LobeHub MCP Market](https://lobehub.com/mcp). Publishing and updating are non-automated (`lhm plugin publish`/`update`), because LobeHub requires browser-based OAuth and does not support machine-to-machine publishing.
32
+ - An `lhm.plugin.json` file, conforming to the [LobeHub plugin manifest format](https://market.lobehub.com/s/publish-mcp/references/manifest), declaring Kilotest as a plugin in the [LobeHub MCP Market](https://lobehub.com/mcp). Publishing and updating are non-automated (`lhm plugin publish` for the initial listing; thereafter `npm run publish:lhm`, which wraps `lhm plugin update` and also runs from the `postpublish` hook), because LobeHub requires browser-based OAuth and does not support machine-to-machine publishing.
33
33
  - A `sitemap.xml` file.
34
34
  - Documentation in the `README.md` file.
35
35
  - This `AI-TOOLS.md` file.
@@ -62,11 +62,11 @@ The external features that support the use of Kilotest as a collection of AI too
62
62
 
63
63
  ## Required maintenance
64
64
 
65
- Whenever the `version` property of the `package.json` file is updated:
65
+ Releasing a new version is a two-script procedure:
66
66
 
67
- - Update `openapi.yaml` and the versions of `server.json` and `lhm.plugin.json` (`npm run generate`).
68
- - Create a pull request and merge to `main` (triggers `publish-mcp.yml` automatically for the MCP Registry).
69
- - Execute `lhm plugin update --dir .` (for LobeHub).
67
+ - On a feature branch, commit all substantive changes, then execute `npm run prePR -- <level>` (`major`, `minor`, or `patch`). The script bumps `package.json` and `package-lock.json`, regenerates `openapi.yaml` and the versions of `server.json` and `lhm.plugin.json` via the `version` hook, commits and pushes the result, and records the branch name for the next step.
68
+ - Submit a pull request and merge it to `main` (triggers `publish-mcp.yml` automatically for the MCP Registry).
69
+ - Execute `npm run postPR`. The script checks out and pulls `main`, verifies that the merge landed, publishes to npm (whose `postpublish` hook updates the LobeHub listing), deletes the feature branch, and prunes remote-tracking branches. If the LobeHub update fails, retry it alone with `npm run publish:lhm`.
70
70
 
71
71
  ## Use cases
72
72
 
package/lhm.plugin.json CHANGED
@@ -4509,5 +4509,5 @@
4509
4509
  }
4510
4510
  }
4511
4511
  ],
4512
- "version": "59.1.2"
4512
+ "version": "59.1.3"
4513
4513
  }
package/openapi.yaml CHANGED
@@ -2,7 +2,7 @@ openapi: 3.1.0
2
2
  info:
3
3
  title: Kilotest API
4
4
  description: 'Kilotest is an ensemble testing and reporting service for front-end web quality. It uses an ensemble of 12 rule engines to test web pages for front-end quality (accessibility, usability, and web standards, including HTML, CSS, ARIA, and WCAG). Kilotest acts as a web server for human users, an MCP server for AI platforms, and an API for programmatic access. With this API you can request that a page be tested or retested, discover available reports, incrementally retrieve facts from a report: from what reports are available, to what issues were reported in one report, to what elements violated one issue, to what diagnoses rule engines gave for one violation.'
5
- version: 59.1.2
5
+ version: 59.1.3
6
6
  license:
7
7
  name: MIT
8
8
  identifier: MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jrpool/kilotest",
3
- "version": "59.1.2",
3
+ "version": "59.1.4",
4
4
  "description": "Ensemble testing for front-end web quality",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -14,7 +14,13 @@
14
14
  "test": "c8 node --require ./test/setup.ts --experimental-test-module-mocks --test --test-concurrency=1 --test-randomize '**/*.test.ts'",
15
15
  "test:smoke": "node smokeTest.ts",
16
16
  "checkinfo": "node checkinfo.ts",
17
- "generate": "node scripts/generate-openapi.ts && node scripts/update-versions.ts"
17
+ "generate": "node scripts/generate-openapi.ts && node scripts/update-versions.ts",
18
+ "version": "npm run generate",
19
+ "prepublishOnly": "test \"$(git branch --show-current)\" = main",
20
+ "postpublish": "npm run publish:lhm",
21
+ "publish:lhm": "npx -y @lobehub/market-cli plugin update --dir .",
22
+ "prePR": "node scripts/prePR.ts",
23
+ "postPR": "node scripts/postPR.ts"
18
24
  },
19
25
  "repository": {
20
26
  "type": "git",
@@ -0,0 +1,89 @@
1
+ /*
2
+ postPR.ts
3
+ Finalizes a release after the prePR pull request has been merged: checks out main, pulls, verifies that the merge landed, publishes to npm (the "postpublish" hook then updates the LobeHub listing), deletes the feature branch, and prunes remote-tracking branches. The feature-branch name is read from the marker file written by prePR.ts, or from an optional command-line argument.
4
+ */
5
+
6
+ // IMPORTS
7
+
8
+ import {spawnSync} from 'node:child_process';
9
+ import fs from 'node:fs';
10
+ import path from 'node:path';
11
+
12
+ // CONSTANTS
13
+
14
+ const markerFile = 'kilotest-pr-branch';
15
+
16
+ // FUNCTIONS
17
+
18
+ // Runs a command with inherited stdio and throws on failure.
19
+ const run = (command: string, args: string[]): void => {
20
+ if (spawnSync(command, args, {stdio: 'inherit'}).status !== 0) {
21
+ throw new Error(`${command} ${args.join(' ')} failed`);
22
+ }
23
+ };
24
+ // Runs a command and returns its trimmed standard output.
25
+ const capture = (command: string, args: string[]): string => {
26
+ const result = spawnSync(command, args, {encoding: 'utf8'});
27
+ if (result.status !== 0) {
28
+ throw new Error(`${command} ${args.join(' ')} failed`);
29
+ }
30
+ return result.stdout.trim();
31
+ };
32
+ // Returns the absolute path of a file inside the git directory.
33
+ const gitPath = (name: string): string =>
34
+ path.join(capture('git', ['rev-parse', '--absolute-git-dir']), name);
35
+ // Exits unless the working tree is clean.
36
+ const requireCleanTree = (): void => {
37
+ const dirty = capture('git', ['status', '--porcelain']);
38
+ if (dirty) {
39
+ console.error(`Working tree is not clean. Commit or stash all changes first:\n${dirty}`);
40
+ process.exit(1);
41
+ }
42
+ };
43
+ // Returns the version field of package.json, either from the working tree or from a git ref.
44
+ const versionOf = (ref?: string): string => {
45
+ const content = ref
46
+ ? capture('git', ['show', `${ref}:package.json`])
47
+ : fs.readFileSync('package.json', 'utf8');
48
+ return JSON.parse(content).version;
49
+ };
50
+
51
+ // EXECUTION
52
+
53
+ const marker = gitPath(markerFile);
54
+ const argBranch = process.argv[2] ?? '';
55
+ const branch = argBranch ||
56
+ (fs.existsSync(marker) ? fs.readFileSync(marker, 'utf8').trim() : '');
57
+ if (!branch) {
58
+ console.error('No feature branch recorded. Run prePR first, or pass the branch name: npm run postPR -- <branch>');
59
+ process.exit(1);
60
+ }
61
+ if (branch === 'main') {
62
+ console.error('Refusing to treat main as the feature branch');
63
+ process.exit(1);
64
+ }
65
+ if (!capture('git', ['branch', '--list', branch])) {
66
+ console.error(`Branch ${branch} does not exist locally; it may already have been deleted`);
67
+ process.exit(1);
68
+ }
69
+ requireCleanTree();
70
+ run('git', ['checkout', 'main']);
71
+ run('git', ['pull', '--ff-only']);
72
+ // Aborts if the pull request has not been merged: under squash-merges the feature branch is never an ancestor of main, so version equality is the merge check.
73
+ const branchVersion = versionOf(branch);
74
+ const mainVersion = versionOf();
75
+ if (branchVersion !== mainVersion) {
76
+ console.error(`main is at version ${mainVersion} but ${branch} is at ${branchVersion}; merge the pull request first`);
77
+ process.exit(1);
78
+ }
79
+ run('npm', ['publish']);
80
+ // Branch cleanup is best-effort: deletion must precede pruning, because "git branch -d" checks mergedness against the upstream ref, which pruning would remove.
81
+ const deleted = spawnSync('git', ['branch', '-d', branch], {stdio: 'inherit'});
82
+ if (deleted.status !== 0) {
83
+ console.warn(`Could not delete ${branch}; delete it manually after confirming the merge`);
84
+ }
85
+ if (spawnSync('git', ['remote', 'prune', 'origin'], {stdio: 'inherit'}).status !== 0) {
86
+ console.warn('git remote prune origin failed');
87
+ }
88
+ fs.rmSync(marker, {force: true});
89
+ console.log('Release complete');
@@ -0,0 +1,64 @@
1
+ /*
2
+ prePR.ts
3
+ Prepares a release pull request on the current feature branch: verifies a clean working tree, bumps the package version (the npm "version" hook regenerates openapi.yaml, server.json, and lhm.plugin.json), commits and pushes the result, records the branch name for postPR.ts, and prints the remaining manual steps.
4
+ */
5
+
6
+ // IMPORTS
7
+
8
+ import {spawnSync} from 'node:child_process';
9
+ import fs from 'node:fs';
10
+ import path from 'node:path';
11
+
12
+ // CONSTANTS
13
+
14
+ const levels = ['major', 'minor', 'patch'];
15
+ const usage = 'Usage: npm run prePR -- <major|minor|patch>';
16
+ const markerFile = 'kilotest-pr-branch';
17
+
18
+ // FUNCTIONS
19
+
20
+ // Runs a command with inherited stdio and throws on failure.
21
+ const run = (command: string, args: string[]): void => {
22
+ if (spawnSync(command, args, {stdio: 'inherit'}).status !== 0) {
23
+ throw new Error(`${command} ${args.join(' ')} failed`);
24
+ }
25
+ };
26
+ // Runs a command and returns its trimmed standard output.
27
+ const capture = (command: string, args: string[]): string => {
28
+ const result = spawnSync(command, args, {encoding: 'utf8'});
29
+ if (result.status !== 0) {
30
+ throw new Error(`${command} ${args.join(' ')} failed`);
31
+ }
32
+ return result.stdout.trim();
33
+ };
34
+ // Returns the absolute path of a file inside the git directory.
35
+ const gitPath = (name: string): string =>
36
+ path.join(capture('git', ['rev-parse', '--absolute-git-dir']), name);
37
+ // Exits unless the working tree is clean, so all substantive changes are committed before the version bump.
38
+ const requireCleanTree = (): void => {
39
+ const dirty = capture('git', ['status', '--porcelain']);
40
+ if (dirty) {
41
+ console.error(`Working tree is not clean. Commit or stash all changes first:\n${dirty}`);
42
+ process.exit(1);
43
+ }
44
+ };
45
+
46
+ // EXECUTION
47
+
48
+ const level = process.argv[2] ?? '';
49
+ if (!levels.includes(level)) {
50
+ console.error(usage);
51
+ process.exit(1);
52
+ }
53
+ const branch = capture('git', ['branch', '--show-current']);
54
+ if (!branch || branch === 'main') {
55
+ console.error('prePR must run on a feature branch, not on main');
56
+ process.exit(1);
57
+ }
58
+ requireCleanTree();
59
+ run('npm', ['version', level, '--no-git-tag-version']);
60
+ run('git', ['add', '-A']);
61
+ run('git', ['commit', '-m', 'update version and generated files']);
62
+ run('git', ['push', '-u', 'origin', branch]);
63
+ fs.writeFileSync(gitPath(markerFile), `${branch}\n`);
64
+ console.log('Submit a pull request, merge it to main, then run: npm run postPR');
package/server.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "url": "https://github.com/jrpool/kilotest",
7
7
  "source": "github"
8
8
  },
9
- "version": "59.1.2",
9
+ "version": "59.1.3",
10
10
  "remotes": [
11
11
  {
12
12
  "type": "streamable-http",