@skill-map/testkit 0.3.0 → 0.3.2
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/README.md +22 -22
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# `@skill-map/testkit`
|
|
2
2
|
|
|
3
|
-
Kernel mocks and builders for plugin authors. Unit-test
|
|
3
|
+
Kernel mocks and builders for plugin authors. Unit-test Extractors, Rules, and Formatters without spinning up a real kernel or DB.
|
|
4
4
|
|
|
5
5
|
The full plugin contract lives in [`spec/plugin-author-guide.md`](../spec/plugin-author-guide.md). This README is a fast on-ramp: how to ship the smallest viable plugin and validate it with the testkit.
|
|
6
6
|
|
|
@@ -20,7 +20,7 @@ A plugin is a directory with one manifest and one extension file:
|
|
|
20
20
|
my-plugin/
|
|
21
21
|
├── plugin.json
|
|
22
22
|
└── extensions/
|
|
23
|
-
└── my-
|
|
23
|
+
└── my-extractor.js
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
`plugin.json`:
|
|
@@ -30,54 +30,54 @@ my-plugin/
|
|
|
30
30
|
"id": "my-plugin",
|
|
31
31
|
"version": "1.0.0",
|
|
32
32
|
"specCompat": "^1.0.0",
|
|
33
|
-
"extensions": ["./extensions/my-
|
|
33
|
+
"extensions": ["./extensions/my-extractor.js"]
|
|
34
34
|
}
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
The directory name MUST equal `id`. Cross-root id collisions block both plugins.
|
|
38
38
|
|
|
39
|
-
`extensions/my-
|
|
39
|
+
`extensions/my-extractor.js` — an Extractor that emits one `references` link per `[[ref:<name>]]` token in the body:
|
|
40
40
|
|
|
41
41
|
```javascript
|
|
42
42
|
export default {
|
|
43
|
-
id: 'my-
|
|
44
|
-
kind: '
|
|
43
|
+
id: 'my-extractor',
|
|
44
|
+
kind: 'extractor',
|
|
45
45
|
version: '1.0.0',
|
|
46
46
|
emitsLinkKinds: ['references'],
|
|
47
47
|
defaultConfidence: 'medium',
|
|
48
48
|
scope: 'body',
|
|
49
|
-
|
|
50
|
-
const out = [];
|
|
49
|
+
extract(ctx) {
|
|
51
50
|
for (const m of ctx.body.matchAll(/\[\[ref:([a-z0-9-]+)\]\]/gi)) {
|
|
52
|
-
|
|
51
|
+
ctx.emitLink({
|
|
53
52
|
source: ctx.node.path,
|
|
54
53
|
target: m[1].toLowerCase(),
|
|
55
54
|
kind: 'references',
|
|
56
55
|
confidence: 'medium',
|
|
57
|
-
sources: ['my-
|
|
56
|
+
sources: ['my-extractor'],
|
|
58
57
|
trigger: { originalTrigger: m[0], normalizedTrigger: m[0].toLowerCase() },
|
|
59
58
|
});
|
|
60
59
|
}
|
|
61
|
-
return out;
|
|
62
60
|
},
|
|
63
61
|
};
|
|
64
62
|
```
|
|
65
63
|
|
|
66
|
-
The extension's `id` is short (`my-
|
|
64
|
+
The extension's `id` is short (`my-extractor`); the kernel composes the qualified id `my-plugin/my-extractor` from the manifest. Pick a token syntax that does not collide with the built-in `@<token>` and `/<token>` Extractors.
|
|
67
65
|
|
|
68
|
-
The
|
|
66
|
+
The `extract(ctx) → void` shape is normative: Extractors emit through three callbacks (`ctx.emitLink`, `ctx.enrichNode`, `ctx.store`) instead of returning links. See [`spec/architecture.md` §Extractor · output callbacks](../spec/architecture.md#extractor--output-callbacks).
|
|
67
|
+
|
|
68
|
+
The five other extension kinds (`provider`, `rule`, `formatter`, `action`, `hook`) follow the same shape — see [`spec/plugin-author-guide.md`](../spec/plugin-author-guide.md#the-six-extension-kinds).
|
|
69
69
|
|
|
70
70
|
## Test it
|
|
71
71
|
|
|
72
72
|
```javascript
|
|
73
|
-
// test/my-
|
|
73
|
+
// test/my-extractor.test.js
|
|
74
74
|
import { test } from 'node:test';
|
|
75
75
|
import { strictEqual } from 'node:assert';
|
|
76
|
-
import { node,
|
|
77
|
-
import
|
|
76
|
+
import { node, runExtractorOnFixture } from '@skill-map/testkit';
|
|
77
|
+
import extractor from '../extensions/my-extractor.js';
|
|
78
78
|
|
|
79
79
|
test('emits one link per [[ref:<name>]]', async () => {
|
|
80
|
-
const links = await
|
|
80
|
+
const { links } = await runExtractorOnFixture(extractor, {
|
|
81
81
|
body: 'See [[ref:architect]] and [[ref:sre]].',
|
|
82
82
|
context: { node: node({ path: 'sample.md' }) },
|
|
83
83
|
});
|
|
@@ -87,23 +87,23 @@ test('emits one link per [[ref:<name>]]', async () => {
|
|
|
87
87
|
```
|
|
88
88
|
|
|
89
89
|
```bash
|
|
90
|
-
node --test test/my-
|
|
90
|
+
node --test test/my-extractor.test.js
|
|
91
91
|
```
|
|
92
92
|
|
|
93
|
-
The testkit also ships `runRuleOnGraph` (
|
|
93
|
+
The testkit also ships `runRuleOnGraph` (Rules), `runFormatterOnGraph` (Formatters), `makeFakeStorage` (KV storage), and `makeFakeRunner` (probabilistic mode). Full surface in [`index.ts`](./index.ts).
|
|
94
94
|
|
|
95
95
|
## Run it under the real CLI
|
|
96
96
|
|
|
97
97
|
```bash
|
|
98
98
|
mkdir -p .skill-map/plugins
|
|
99
99
|
cp -r my-plugin .skill-map/plugins/
|
|
100
|
-
sm plugins list # status should be:
|
|
100
|
+
sm plugins list # status should be: enabled
|
|
101
101
|
sm scan
|
|
102
102
|
```
|
|
103
103
|
|
|
104
104
|
Discovery roots (in order): `<project>/.skill-map/plugins/`, then `~/.skill-map/plugins/`. Override with `--plugin-dir <path>`.
|
|
105
105
|
|
|
106
|
-
If `sm plugins list` shows anything other than `
|
|
106
|
+
If `sm plugins list` shows anything other than `enabled` / `disabled`, run `sm plugins doctor` for the diagnostic and check the [Diagnostics table](../spec/plugin-author-guide.md#diagnostics).
|
|
107
107
|
|
|
108
108
|
## A complete worked example
|
|
109
109
|
|
|
@@ -118,4 +118,4 @@ If `sm plugins list` shows anything other than `loaded` / `disabled`, run `sm pl
|
|
|
118
118
|
|
|
119
119
|
## Stability
|
|
120
120
|
|
|
121
|
-
`experimental` while Step 9 is in flight. The
|
|
121
|
+
`experimental` while Step 9 is in flight. The Extractor / Rule / Formatter helpers and builders are intended to stay stable through v1.0; `makeFakeRunner` may change to track the Step 10 job subsystem contract.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skill-map/testkit",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "Kernel mocks + builders for plugin authors. Test detectors, rules, and formatters without spinning up the full skill-map runtime.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"test": "tsc --noEmit && node --import tsx --test --test-reporter=spec 'test/**/*.test.ts'",
|
|
37
37
|
"test:ci": "tsc --noEmit && node --import tsx --test 'test/**/*.test.ts'",
|
|
38
38
|
"test:coverage": "tsc --noEmit && node --experimental-default-config-file --import tsx --test --experimental-test-coverage 'test/**/*.test.ts'",
|
|
39
|
+
"validate": "npm run typecheck && npm run build && npm run test:ci",
|
|
39
40
|
"clean": "rm -rf dist"
|
|
40
41
|
},
|
|
41
42
|
"dependencies": {
|