@lifeaitools/rdc-skills 0.24.14 → 0.24.16
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/.claude-plugin/plugin.json +156 -4
- package/git-sha.json +1 -1
- package/lib/catalog.mjs +7 -7
- package/package.json +2 -2
- package/skills/co-develop/SKILL.md +1 -0
- package/skills/tests/MATRIX.md +3 -3
- package/skills/tests/rdc-lifeai-brochure-author.test.json +2 -2
- package/skills/tests/rdc-rdc-brochurify.test.json +2 -2
- package/skills/tests/rdc-rdc-extract-verifier-rules.test.json +2 -2
- package/tests/manifest-contract-fields.test.mjs +78 -0
- package/tests/mcp.test.mjs +4 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rdc",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.16",
|
|
4
4
|
"description": "RDC typed-agent dispatch skill suite for Claude Code — plan, build, review, overnight unattended builds with work-item tracking and TDD enforcement.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "LIFEAI",
|
|
@@ -158,6 +158,89 @@
|
|
|
158
158
|
"enabled_default": true,
|
|
159
159
|
"codeflow_required": false
|
|
160
160
|
},
|
|
161
|
+
"rdc-brochurify": {
|
|
162
|
+
"name": "rdc-brochurify",
|
|
163
|
+
"slash": "rdc:brochurify",
|
|
164
|
+
"category": "tooling",
|
|
165
|
+
"usage": "rdc:brochurify <source|job-payload>",
|
|
166
|
+
"args": {
|
|
167
|
+
"positional": [
|
|
168
|
+
{
|
|
169
|
+
"name": "source",
|
|
170
|
+
"required": true,
|
|
171
|
+
"description": "URL, HTML, DOCX, Markdown, JSX, corpus query, or broker job payload to turn into a brochure PDF.",
|
|
172
|
+
"accepts": "path|url|json|string"
|
|
173
|
+
}
|
|
174
|
+
],
|
|
175
|
+
"flags": []
|
|
176
|
+
},
|
|
177
|
+
"requires": [
|
|
178
|
+
"agent-dispatch"
|
|
179
|
+
],
|
|
180
|
+
"produces": [
|
|
181
|
+
"pdf_artifact",
|
|
182
|
+
".rdc/reports/"
|
|
183
|
+
],
|
|
184
|
+
"default_model": "opus",
|
|
185
|
+
"triggers": [
|
|
186
|
+
"rdc:brochurify",
|
|
187
|
+
"brochurify this",
|
|
188
|
+
"make a brochure from",
|
|
189
|
+
"convert this to a brochure PDF",
|
|
190
|
+
"generate brochure from",
|
|
191
|
+
"monkey_dispatch payload with skill=\"brochurify\""
|
|
192
|
+
],
|
|
193
|
+
"follows": [
|
|
194
|
+
"channel-formatter",
|
|
195
|
+
"convert",
|
|
196
|
+
"lifeai-brochure-author"
|
|
197
|
+
],
|
|
198
|
+
"leads_to": [],
|
|
199
|
+
"sandbox_aware": true,
|
|
200
|
+
"output_contract": "guides/output-contract.md",
|
|
201
|
+
"enabled_default": true,
|
|
202
|
+
"codeflow_required": false
|
|
203
|
+
},
|
|
204
|
+
"lifeai-brochure-author": {
|
|
205
|
+
"name": "lifeai-brochure-author",
|
|
206
|
+
"slash": "lifeai-brochure-author",
|
|
207
|
+
"category": "tooling",
|
|
208
|
+
"usage": "lifeai-brochure-author <brochure-jsx-task>",
|
|
209
|
+
"args": {
|
|
210
|
+
"positional": [
|
|
211
|
+
{
|
|
212
|
+
"name": "brochure-jsx-task",
|
|
213
|
+
"required": true,
|
|
214
|
+
"description": "Brief, source content, or JSX verification task for @lifeai/brochure-kit output.",
|
|
215
|
+
"accepts": "string|path"
|
|
216
|
+
}
|
|
217
|
+
],
|
|
218
|
+
"flags": []
|
|
219
|
+
},
|
|
220
|
+
"requires": [],
|
|
221
|
+
"produces": [
|
|
222
|
+
"brochure_jsx_guidance"
|
|
223
|
+
],
|
|
224
|
+
"default_model": "opus",
|
|
225
|
+
"triggers": [
|
|
226
|
+
"write a brochure",
|
|
227
|
+
"make a one-pager",
|
|
228
|
+
"draft a PDF report",
|
|
229
|
+
"design a brochure",
|
|
230
|
+
"create an investor doc",
|
|
231
|
+
"generate a fact sheet",
|
|
232
|
+
"brochurify",
|
|
233
|
+
"@lifeai/brochure-kit"
|
|
234
|
+
],
|
|
235
|
+
"follows": [],
|
|
236
|
+
"leads_to": [
|
|
237
|
+
"rdc-brochurify"
|
|
238
|
+
],
|
|
239
|
+
"sandbox_aware": false,
|
|
240
|
+
"output_contract": "guides/output-contract.md",
|
|
241
|
+
"enabled_default": true,
|
|
242
|
+
"codeflow_required": false
|
|
243
|
+
},
|
|
161
244
|
"build": {
|
|
162
245
|
"name": "build",
|
|
163
246
|
"slash": "rdc:build",
|
|
@@ -382,7 +465,7 @@
|
|
|
382
465
|
"follows": [],
|
|
383
466
|
"leads_to": [],
|
|
384
467
|
"sandbox_aware": false,
|
|
385
|
-
"output_contract":
|
|
468
|
+
"output_contract": "guides/output-contract.md",
|
|
386
469
|
"enabled_default": true,
|
|
387
470
|
"codeflow_required": false
|
|
388
471
|
},
|
|
@@ -815,6 +898,75 @@
|
|
|
815
898
|
"enabled_default": true,
|
|
816
899
|
"codeflow_required": true
|
|
817
900
|
},
|
|
901
|
+
"rdc-extract-verifier-rules": {
|
|
902
|
+
"name": "rdc-extract-verifier-rules",
|
|
903
|
+
"slash": "rdc:extract-verifier-rules",
|
|
904
|
+
"category": "tooling",
|
|
905
|
+
"usage": "rdc:extract-verifier-rules [enhancement-log]",
|
|
906
|
+
"args": {
|
|
907
|
+
"positional": [
|
|
908
|
+
{
|
|
909
|
+
"name": "enhancement-log",
|
|
910
|
+
"required": false,
|
|
911
|
+
"description": "Optional path or description of enhancement-log entries to cluster into verifier-rule candidates.",
|
|
912
|
+
"accepts": "path|string"
|
|
913
|
+
}
|
|
914
|
+
],
|
|
915
|
+
"flags": []
|
|
916
|
+
},
|
|
917
|
+
"requires": [
|
|
918
|
+
"git"
|
|
919
|
+
],
|
|
920
|
+
"produces": [
|
|
921
|
+
".rdc/reports/",
|
|
922
|
+
"git_commits"
|
|
923
|
+
],
|
|
924
|
+
"default_model": "opus",
|
|
925
|
+
"triggers": [
|
|
926
|
+
"rdc:extract-verifier-rules",
|
|
927
|
+
"extract verifier rules",
|
|
928
|
+
"promote enhancement log",
|
|
929
|
+
"what new rules should we add",
|
|
930
|
+
"verifier corpus update",
|
|
931
|
+
"nightly cron at 3:00 AM PT"
|
|
932
|
+
],
|
|
933
|
+
"follows": [
|
|
934
|
+
"rdc-brochurify"
|
|
935
|
+
],
|
|
936
|
+
"leads_to": [
|
|
937
|
+
"review"
|
|
938
|
+
],
|
|
939
|
+
"sandbox_aware": false,
|
|
940
|
+
"output_contract": "guides/output-contract.md",
|
|
941
|
+
"enabled_default": true,
|
|
942
|
+
"codeflow_required": false
|
|
943
|
+
},
|
|
944
|
+
"rpms-filemap": {
|
|
945
|
+
"name": "rpms-filemap",
|
|
946
|
+
"slash": "rdc:rpms-filemap",
|
|
947
|
+
"category": "tooling",
|
|
948
|
+
"usage": "rdc:rpms-filemap",
|
|
949
|
+
"args": {
|
|
950
|
+
"positional": [],
|
|
951
|
+
"flags": []
|
|
952
|
+
},
|
|
953
|
+
"requires": [],
|
|
954
|
+
"produces": [],
|
|
955
|
+
"default_model": "haiku",
|
|
956
|
+
"triggers": [
|
|
957
|
+
"rpms file map",
|
|
958
|
+
"rule #1",
|
|
959
|
+
"context export",
|
|
960
|
+
"where does this file belong",
|
|
961
|
+
"where should pm artifacts go"
|
|
962
|
+
],
|
|
963
|
+
"follows": [],
|
|
964
|
+
"leads_to": [],
|
|
965
|
+
"sandbox_aware": false,
|
|
966
|
+
"output_contract": "guides/output-contract.md",
|
|
967
|
+
"enabled_default": true,
|
|
968
|
+
"codeflow_required": false
|
|
969
|
+
},
|
|
818
970
|
"release": {
|
|
819
971
|
"name": "release",
|
|
820
972
|
"slash": "rdc:release",
|
|
@@ -1005,7 +1157,7 @@
|
|
|
1005
1157
|
],
|
|
1006
1158
|
"follows": [],
|
|
1007
1159
|
"leads_to": [],
|
|
1008
|
-
"sandbox_aware":
|
|
1160
|
+
"sandbox_aware": true,
|
|
1009
1161
|
"output_contract": "guides/output-contract.md",
|
|
1010
1162
|
"enabled_default": true,
|
|
1011
1163
|
"codeflow_required": false
|
|
@@ -1135,7 +1287,7 @@
|
|
|
1135
1287
|
],
|
|
1136
1288
|
"follows": [],
|
|
1137
1289
|
"leads_to": [],
|
|
1138
|
-
"sandbox_aware":
|
|
1290
|
+
"sandbox_aware": true,
|
|
1139
1291
|
"output_contract": "guides/output-contract.md",
|
|
1140
1292
|
"enabled_default": true,
|
|
1141
1293
|
"codeflow_required": false
|
package/git-sha.json
CHANGED
package/lib/catalog.mjs
CHANGED
|
@@ -8,9 +8,10 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Loading is LIVE: the catalog is re-read from disk when older than CACHE_TTL_MS
|
|
10
10
|
* so a skill edit (frontmatter or body) is picked up without a server restart.
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* Published packages must have one `skills_meta` entry for every skill
|
|
12
|
+
* directory. The frontmatter-only path below is a local-dev resilience fallback
|
|
13
|
+
* so an incomplete checkout does not silently hide a skill while it is being
|
|
14
|
+
* repaired; tests enforce that released packages do not rely on it.
|
|
14
15
|
*/
|
|
15
16
|
|
|
16
17
|
import fs from 'node:fs';
|
|
@@ -45,9 +46,8 @@ function readFrontmatter(skillMdPath) {
|
|
|
45
46
|
function toCatalogEntry(name, meta, frontmatter) {
|
|
46
47
|
const fm = frontmatter || {};
|
|
47
48
|
const description = fm.description || meta.description || '';
|
|
48
|
-
// triggers/usage/slash/etc.
|
|
49
|
-
//
|
|
50
|
-
// searchable — these fields are what `rdc_skill_search` routes on.
|
|
49
|
+
// triggers/usage/slash/etc. should live in skills_meta for published packages.
|
|
50
|
+
// Frontmatter fallback keeps incomplete local checkouts searchable during repair.
|
|
51
51
|
const metaTriggers = Array.isArray(meta.triggers) && meta.triggers.length ? meta.triggers : null;
|
|
52
52
|
const fmTriggers = Array.isArray(fm.triggers) ? fm.triggers : [];
|
|
53
53
|
const slash = meta.slash || fm.slash || `rdc:${name}`;
|
|
@@ -84,7 +84,7 @@ function buildCatalog() {
|
|
|
84
84
|
byName.set(name, toCatalogEntry(name, meta || {}, fm));
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
// 2.
|
|
87
|
+
// 2. Local-dev fallback: a skill dir with SKILL.md but no meta entry.
|
|
88
88
|
if (fs.existsSync(SKILLS_DIR)) {
|
|
89
89
|
for (const entry of fs.readdirSync(SKILLS_DIR, { withFileTypes: true })) {
|
|
90
90
|
if (!entry.isDirectory() || byName.has(entry.name)) continue;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lifeaitools/rdc-skills",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.16",
|
|
4
4
|
"description": "RDC typed-agent dispatch skill suite for Claude Code - plan, build, review, overnight builds",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude-code",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"rdc-design": "node scripts/rdc-design-cli.mjs",
|
|
36
36
|
"test:hooks": "node scripts/test-rdc-hooks.mjs",
|
|
37
37
|
"test:truth-gate": "node tests/run-evidence-gate.test.mjs && node tests/work-item-exit-gate-l2.test.mjs && node tests/work-item-exit-gate-l3.test.mjs && node tests/require-work-item-on-commit.test.mjs && node tests/harness-gates.test.mjs",
|
|
38
|
-
"test:acceptance": "node tests/acceptance.test.mjs && node tests/install-rdc-skills.test.mjs && node tests/help-surface.test.mjs",
|
|
38
|
+
"test:acceptance": "node tests/acceptance.test.mjs && node tests/install-rdc-skills.test.mjs && node tests/help-surface.test.mjs && node tests/manifest-contract-fields.test.mjs",
|
|
39
39
|
"acceptance": "node scripts/acceptance.mjs --changed",
|
|
40
40
|
"test:mcp": "node tests/mcp.test.mjs",
|
|
41
41
|
"test:mcp:remote": "node tests/mcp.test.mjs --remote",
|
|
@@ -6,6 +6,7 @@ description: "Usage `rdc:co-develop <ask|reply|inbox|start|resume|status>` — p
|
|
|
6
6
|
> **⚠️ OUTPUT CONTRACT (READ FIRST):** `guides/output-contract.md`
|
|
7
7
|
> Checklist-only output. No tool-call narration. No raw MCP/JSON/log dumps.
|
|
8
8
|
> One checklist upfront, updated in place, shown again at end with a 1-line verdict.
|
|
9
|
+
> **Sandbox contract:** This skill honors `RDC_TEST=1` per `guides/agent-bootstrap.md` § RDC_TEST Sandbox Contract. Under the flag, do not create/send/reply to live co-development turns; report the intended clauth command and mark the external relay action as skipped.
|
|
9
10
|
|
|
10
11
|
# rdc:co-develop — Peer-Aware Co-Development
|
|
11
12
|
|
package/skills/tests/MATRIX.md
CHANGED
|
@@ -21,13 +21,13 @@ The manifest layer verifies each skill can be started from a realistic caller pr
|
|
|
21
21
|
| `rdc:handoff` | `rdc-handoff.test.json` | Stub work handoff | `exit_code`, `stdout_contains` | Basic manifest |
|
|
22
22
|
| `rdc:help` | `rdc-help.test.json` | Help menu rendering | `commits_made`, `exit_code`, `stdout_contains` | Basic manifest |
|
|
23
23
|
| `rdc:housekeeping` | `rdc-housekeeping.test.json` | Read-only housekeeping audit | `commits_made`, `exit_code`, `stdout_contains` | Basic manifest |
|
|
24
|
-
| `
|
|
24
|
+
| `lifeai-brochure-author` | `rdc-lifeai-brochure-author.test.json` | JSX compliance review fixture | `exit_code`, `stdout_contains` | Basic manifest |
|
|
25
25
|
| `rdc:overnight` | `rdc-overnight.test.json` | Label-based overnight queue drain | `exit_code`, `stdout_contains` | Basic manifest |
|
|
26
26
|
| `rdc:plan` | `rdc-plan.test.json` | Health-endpoint planning prompt | `exit_code`, `stdout_contains` | Basic manifest |
|
|
27
27
|
| `rdc:preplan` | `rdc-preplan.test.json` | Rate-limiter research prompt | `commits_made`, `exit_code`, `stdout_contains` | Basic manifest |
|
|
28
28
|
| `rdc:prototype` | `rdc-prototype.test.json` | Tiny component prototype prompt | `exit_code`, `stdout_contains` | Basic manifest |
|
|
29
|
-
| `rdc:
|
|
30
|
-
| `rdc:
|
|
29
|
+
| `rdc:brochurify` | `rdc-rdc-brochurify.test.json` | Read-only markdown Brochurify fixture | `exit_code`, `stdout_contains` | Sandbox output and no-follow-up negative checks |
|
|
30
|
+
| `rdc:extract-verifier-rules` | `rdc-rdc-extract-verifier-rules.test.json` | Enhancement-log verifier fixture | `exit_code`, `stdout_contains` | Basic manifest |
|
|
31
31
|
| `rdc:release` | `rdc-release.test.json` | Dry-run package release | `commits_made`, `exit_code`, `stdout_contains` | Basic manifest |
|
|
32
32
|
| `rdc:report` | `rdc-report.test.json` | Unattended report generation | `exit_code`, `stdout_contains` | Basic manifest |
|
|
33
33
|
| `rdc:review` | `rdc-review.test.json` | Unattended review gate | `exit_code`, `stdout_contains` | Basic manifest |
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest_version": 1,
|
|
3
|
-
"skill": "
|
|
3
|
+
"skill": "lifeai-brochure-author",
|
|
4
4
|
"description": "LifeAI brochure author contract rejects raw HTML and returns brochure-kit component guidance.",
|
|
5
5
|
"fixture": {
|
|
6
|
-
"prompt": "
|
|
6
|
+
"prompt": "lifeai-brochure-author review this JSX fixture for brochure-kit compliance: docs/source/brochure-author-fixture.tsx",
|
|
7
7
|
"precondition_files": [
|
|
8
8
|
{
|
|
9
9
|
"path": "docs/source/brochure-author-fixture.tsx",
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest_version": 1,
|
|
3
|
-
"skill": "rdc:
|
|
3
|
+
"skill": "rdc:brochurify",
|
|
4
4
|
"description": "Brochurify orchestrator accepts a markdown source fixture and reports sandboxed orchestration state.",
|
|
5
5
|
"fixture": {
|
|
6
|
-
"prompt": "rdc:
|
|
6
|
+
"prompt": "rdc:brochurify docs/source/brochurify-fixture.md --mode read-only --theme editorial-neutral",
|
|
7
7
|
"precondition_files": [
|
|
8
8
|
{
|
|
9
9
|
"path": "docs/source/brochurify-fixture.md",
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest_version": 1,
|
|
3
|
-
"skill": "rdc:
|
|
3
|
+
"skill": "rdc:extract-verifier-rules",
|
|
4
4
|
"description": "Verifier-rule extraction reads a tiny enhancement-log fixture and reports candidate-rule status without opening a PR.",
|
|
5
5
|
"fixture": {
|
|
6
|
-
"prompt": "rdc:
|
|
6
|
+
"prompt": "rdc:extract-verifier-rules --since 2026-01-01 --auto-merge=false docs/source/enhancement-log-fixture.jsonl",
|
|
7
7
|
"precondition_files": [
|
|
8
8
|
{
|
|
9
9
|
"path": "docs/source/enhancement-log-fixture.jsonl",
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
4
|
+
import { dirname, join, resolve } from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const root = resolve(__dirname, '..');
|
|
9
|
+
const manifest = JSON.parse(readFileSync(join(root, '.claude-plugin', 'plugin.json'), 'utf8'));
|
|
10
|
+
const skillDirs = readdirSync(join(root, 'skills'), { withFileTypes: true })
|
|
11
|
+
.filter((entry) => entry.isDirectory() && entry.name !== 'tests')
|
|
12
|
+
.map((entry) => entry.name)
|
|
13
|
+
.sort();
|
|
14
|
+
const metaNames = Object.keys(manifest.skills_meta).sort();
|
|
15
|
+
const manifestSlashes = new Set(Object.values(manifest.skills_meta).map((meta) => meta.slash));
|
|
16
|
+
|
|
17
|
+
assert.deepEqual(
|
|
18
|
+
metaNames,
|
|
19
|
+
skillDirs,
|
|
20
|
+
'Every skills/<name>/SKILL.md directory must have a skills_meta entry so MCP/help use explicit caller-facing terms',
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
function skillPath(name) {
|
|
24
|
+
const direct = join(root, 'skills', name, 'SKILL.md');
|
|
25
|
+
if (existsSync(direct)) return direct;
|
|
26
|
+
const prefixed = join(root, 'skills', `rdc-${name}`, 'SKILL.md');
|
|
27
|
+
if (existsSync(prefixed)) return prefixed;
|
|
28
|
+
return direct;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
for (const [name, meta] of Object.entries(manifest.skills_meta)) {
|
|
32
|
+
const file = skillPath(name);
|
|
33
|
+
assert.equal(existsSync(file), true, `${name} must have a SKILL.md`);
|
|
34
|
+
const body = readFileSync(file, 'utf8');
|
|
35
|
+
|
|
36
|
+
assert.equal(meta.name, name, `${name} manifest name must match its skills_meta key`);
|
|
37
|
+
assert.doesNotMatch(meta.slash, /^rdc:rdc-/, `${name} slash command must not be a synthesized rdc:rdc-* name`);
|
|
38
|
+
assert.doesNotMatch(meta.slash, /^rdc:lifeai-/, `${name} slash command must not invent an rdc: prefix for non-rdc skills`);
|
|
39
|
+
|
|
40
|
+
const hasOutputContract = body.includes('guides/output-contract.md') || body.includes('OUTPUT CONTRACT');
|
|
41
|
+
assert.equal(
|
|
42
|
+
Boolean(meta.output_contract),
|
|
43
|
+
hasOutputContract,
|
|
44
|
+
`${name} manifest output_contract must match SKILL.md banner`,
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
if (body.includes('RDC_TEST=1')) {
|
|
48
|
+
assert.equal(meta.sandbox_aware, true, `${name} mentions RDC_TEST=1 and must be sandbox_aware`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (meta.sandbox_aware) {
|
|
52
|
+
assert.match(
|
|
53
|
+
body,
|
|
54
|
+
/Sandbox contract|RDC_TEST=1/,
|
|
55
|
+
`${name} is sandbox_aware and must explain the sandbox contract in SKILL.md`,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const testManifests = readdirSync(join(root, 'skills', 'tests'), { withFileTypes: true })
|
|
61
|
+
.filter((entry) => entry.isFile() && entry.name.endsWith('.test.json'));
|
|
62
|
+
|
|
63
|
+
for (const entry of testManifests) {
|
|
64
|
+
const testPath = join(root, 'skills', 'tests', entry.name);
|
|
65
|
+
const test = JSON.parse(readFileSync(testPath, 'utf8'));
|
|
66
|
+
assert.equal(
|
|
67
|
+
manifestSlashes.has(test.skill),
|
|
68
|
+
true,
|
|
69
|
+
`${entry.name} skill "${test.skill}" must match a skills_meta[].slash value`,
|
|
70
|
+
);
|
|
71
|
+
assert.match(
|
|
72
|
+
test.fixture?.prompt || '',
|
|
73
|
+
new RegExp(`(^|\\s)${test.skill.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}(\\s|$)`),
|
|
74
|
+
`${entry.name} prompt must invoke its manifest skill name`,
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
console.log('manifest contract field tests — PASS');
|
package/tests/mcp.test.mjs
CHANGED
|
@@ -88,7 +88,10 @@ function unitTests() {
|
|
|
88
88
|
check('unit: catalog non-empty', cat.length >= 20, `got ${cat.length}`);
|
|
89
89
|
check('unit: every entry has name+slash+category+summary field',
|
|
90
90
|
cat.every((s) => s.name && s.slash && s.category && 'summary' in s));
|
|
91
|
-
check('unit: every slash is
|
|
91
|
+
check('unit: every slash is explicit caller-facing shape',
|
|
92
|
+
cat.every((s) => /^rdc:/.test(s.slash) || s.slash === s.name));
|
|
93
|
+
check('unit: no synthesized duplicate rdc prefixes',
|
|
94
|
+
cat.every((s) => !/^rdc:rdc-/.test(s.slash) && !/^rdc:lifeai-/.test(s.slash)));
|
|
92
95
|
check('unit: getSkill(deploy) resolves', !!getSkill('deploy'));
|
|
93
96
|
check('unit: getSkill(nonexistent) is null', getSkill('___nope___') === null);
|
|
94
97
|
check('unit: search ranks exact name first', searchSkills('deploy')[0]?.name === 'deploy');
|