@cyanheads/mcp-ts-core 0.12.8 → 0.13.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.
- package/AGENTS.md +12 -11
- package/CLAUDE.md +12 -11
- package/README.md +2 -2
- package/biome.json +1 -1
- package/changelog/0.12.x/0.12.9.md +36 -0
- package/changelog/0.13.x/0.13.0.md +48 -0
- package/changelog/template.md +7 -24
- package/dist/cli/init.js +2 -2
- package/dist/cli/init.js.map +1 -1
- package/dist/config/envValue.d.ts +18 -0
- package/dist/config/envValue.d.ts.map +1 -0
- package/dist/config/envValue.js +35 -0
- package/dist/config/envValue.js.map +1 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +5 -7
- package/dist/config/index.js.map +1 -1
- package/dist/config/parseEnvConfig.d.ts +7 -0
- package/dist/config/parseEnvConfig.d.ts.map +1 -1
- package/dist/config/parseEnvConfig.js +9 -1
- package/dist/config/parseEnvConfig.js.map +1 -1
- package/dist/linter/validate.js +2 -2
- package/dist/linter/validate.js.map +1 -1
- package/dist/mcp-server/transports/http/httpTransport.d.ts.map +1 -1
- package/dist/mcp-server/transports/http/httpTransport.js +70 -2
- package/dist/mcp-server/transports/http/httpTransport.js.map +1 -1
- package/dist/mcp-server/transports/http/landing-page/sections/connect.d.ts.map +1 -1
- package/dist/mcp-server/transports/http/landing-page/sections/connect.js +9 -2
- package/dist/mcp-server/transports/http/landing-page/sections/connect.js.map +1 -1
- package/dist/mcp-server/transports/http/sessionStore.d.ts +10 -2
- package/dist/mcp-server/transports/http/sessionStore.d.ts.map +1 -1
- package/dist/mcp-server/transports/http/sessionStore.js.map +1 -1
- package/dist/services/mirror/sqlite/handle.d.ts.map +1 -1
- package/dist/services/mirror/sqlite/handle.js +14 -12
- package/dist/services/mirror/sqlite/handle.js.map +1 -1
- package/dist/services/mirror/sqlite/sqliteMirrorStore.js +8 -9
- package/dist/services/mirror/sqlite/sqliteMirrorStore.js.map +1 -1
- package/dist/services/mirror/types.d.ts +5 -1
- package/dist/services/mirror/types.d.ts.map +1 -1
- package/dist/utils/internal/performance.d.ts +1 -1
- package/dist/utils/internal/performance.js +2 -2
- package/dist/utils/network/fetchWithTimeout.js +1 -1
- package/dist/utils/network/retry.js +1 -1
- package/dist/utils/security/idGenerator.d.ts +3 -1
- package/dist/utils/security/idGenerator.d.ts.map +1 -1
- package/dist/utils/security/idGenerator.js +12 -1
- package/dist/utils/security/idGenerator.js.map +1 -1
- package/framework-skills/README.md +40 -0
- package/{skills → framework-skills}/add-app-tool/SKILL.md +2 -2
- package/{skills → framework-skills}/add-resource/SKILL.md +2 -2
- package/{skills → framework-skills}/add-service/SKILL.md +2 -2
- package/{skills → framework-skills}/add-test/SKILL.md +2 -2
- package/{skills → framework-skills}/add-tool/SKILL.md +7 -7
- package/{skills → framework-skills}/api-config/SKILL.md +3 -1
- package/{skills → framework-skills}/api-context/SKILL.md +3 -3
- package/{skills → framework-skills}/api-errors/SKILL.md +2 -1
- package/{skills → framework-skills}/api-linter/SKILL.md +4 -4
- package/{skills → framework-skills}/api-mirror/SKILL.md +3 -1
- package/{skills → framework-skills}/design-mcp-server/SKILL.md +59 -101
- package/{skills → framework-skills}/field-test/SKILL.md +10 -5
- package/{skills → framework-skills}/git-wrapup/SKILL.md +5 -3
- package/{skills → framework-skills}/maintenance/SKILL.md +30 -21
- package/{skills → framework-skills}/orchestrations/SKILL.md +2 -2
- package/{skills → framework-skills}/orchestrations/workflows/field-test-fix.md +8 -8
- package/{skills → framework-skills}/orchestrations/workflows/fix-wrapup-release.md +5 -5
- package/{skills → framework-skills}/orchestrations/workflows/greenfield-build.md +11 -11
- package/{skills → framework-skills}/orchestrations/workflows/maintenance-release.md +12 -12
- package/{skills → framework-skills}/polish-docs-meta/SKILL.md +18 -10
- package/{skills → framework-skills}/polish-docs-meta/references/agent-protocol.md +1 -1
- package/{skills → framework-skills}/polish-docs-meta/references/package-meta.md +1 -1
- package/{skills → framework-skills}/polish-docs-meta/references/readme.md +88 -72
- package/{skills → framework-skills}/release-and-publish/SKILL.md +4 -1
- package/{skills → framework-skills}/release-pr-review/SKILL.md +2 -2
- package/{skills → framework-skills}/report-issue-framework/SKILL.md +25 -25
- package/{skills → framework-skills}/report-issue-local/SKILL.md +22 -24
- package/{skills → framework-skills}/security-pass/SKILL.md +2 -2
- package/{skills → framework-skills}/setup/SKILL.md +10 -8
- package/package.json +13 -13
- package/scripts/check-framework-antipatterns.ts +1 -1
- package/scripts/check-skill-versions.ts +16 -9
- package/scripts/check-skills-sync.ts +64 -13
- package/scripts/clean-mcpb.ts +3 -3
- package/scripts/devcheck.ts +37 -27
- package/scripts/lint-packaging.ts +158 -24
- package/scripts/list-skills.ts +2 -2
- package/templates/.claude-plugin/plugin.json +5 -1
- package/templates/.env.example +1 -1
- package/templates/.github/CONTRIBUTING.md +4 -5
- package/templates/.github/ISSUE_TEMPLATE/bug_report.yml +5 -4
- package/templates/.github/ISSUE_TEMPLATE/config.yml +6 -1
- package/templates/.github/ISSUE_TEMPLATE/feature_request.yml +1 -2
- package/templates/AGENTS.md +16 -15
- package/templates/CLAUDE.md +16 -15
- package/templates/_.mcpbignore +1 -1
- package/templates/changelog/template.md +7 -24
- package/templates/package.json +4 -3
- package/templates/src/mcp-server/resources/definitions/echo-app-ui.app-resource.ts +1 -1
- package/skills/README.md +0 -38
- /package/{skills → framework-skills}/add-export/SKILL.md +0 -0
- /package/{skills → framework-skills}/add-prompt/SKILL.md +0 -0
- /package/{skills → framework-skills}/add-provider/SKILL.md +0 -0
- /package/{skills → framework-skills}/api-auth/SKILL.md +0 -0
- /package/{skills → framework-skills}/api-canvas/SKILL.md +0 -0
- /package/{skills → framework-skills}/api-services/SKILL.md +0 -0
- /package/{skills → framework-skills}/api-services/references/graph.md +0 -0
- /package/{skills → framework-skills}/api-services/references/llm.md +0 -0
- /package/{skills → framework-skills}/api-services/references/speech.md +0 -0
- /package/{skills → framework-skills}/api-telemetry/SKILL.md +0 -0
- /package/{skills → framework-skills}/api-testing/SKILL.md +0 -0
- /package/{skills → framework-skills}/api-utils/SKILL.md +0 -0
- /package/{skills → framework-skills}/api-utils/references/formatting.md +0 -0
- /package/{skills → framework-skills}/api-utils/references/parsing.md +0 -0
- /package/{skills → framework-skills}/api-utils/references/security.md +0 -0
- /package/{skills → framework-skills}/api-workers/SKILL.md +0 -0
- /package/{skills → framework-skills}/code-simplifier/SKILL.md +0 -0
- /package/{skills → framework-skills}/polish-docs-meta/references/server-json.md +0 -0
- /package/{skills → framework-skills}/techniques/SKILL.md +0 -0
- /package/{skills → framework-skills}/techniques/references/outline-on-overflow.md +0 -0
- /package/{skills → framework-skills}/tool-defs-analysis/SKILL.md +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyanheads/mcp-ts-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"mcpName": "io.github.cyanheads/mcp-ts-core",
|
|
5
5
|
"description": "Agent-native TypeScript framework for MCP servers. Includes runtime infrastructure and agent skills for building, testing, and shipping servers.",
|
|
6
6
|
"files": [
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"scripts/list-skills.ts",
|
|
22
22
|
"scripts/release-github.ts",
|
|
23
23
|
"scripts/tree.ts",
|
|
24
|
-
"skills/",
|
|
24
|
+
"framework-skills/",
|
|
25
25
|
"templates/",
|
|
26
26
|
"AGENTS.md",
|
|
27
27
|
"CLAUDE.md",
|
|
@@ -189,7 +189,7 @@
|
|
|
189
189
|
"test:ui": "bunx vitest --ui",
|
|
190
190
|
"test:coverage": "bunx vitest run --coverage",
|
|
191
191
|
"audit": "bun audit",
|
|
192
|
-
"audit:fix": "bun audit
|
|
192
|
+
"audit:fix": "bun audit fix",
|
|
193
193
|
"audit:refresh": "rm -f bun.lock && bun install && bun audit",
|
|
194
194
|
"changelog:build": "bun run scripts/build-changelog.ts",
|
|
195
195
|
"changelog:check": "bun run scripts/build-changelog.ts --check",
|
|
@@ -197,9 +197,9 @@
|
|
|
197
197
|
"publish-mcp": "mcp-publisher login github -token \"$(security find-generic-password -a \"$USER\" -s mcp-publisher-github-pat -w)\" && mcp-publisher publish"
|
|
198
198
|
},
|
|
199
199
|
"devDependencies": {
|
|
200
|
-
"@biomejs/biome": "2.5.
|
|
200
|
+
"@biomejs/biome": "2.5.13",
|
|
201
201
|
"@cloudflare/vitest-pool-workers": "^0.22.0",
|
|
202
|
-
"@cloudflare/workers-types": "5.
|
|
202
|
+
"@cloudflare/workers-types": "5.20260910.1",
|
|
203
203
|
"@duckdb/node-api": "^1.5.5-r.4",
|
|
204
204
|
"@hono/otel": "^1.1.2",
|
|
205
205
|
"@opentelemetry/exporter-metrics-otlp-http": "^0.222.0",
|
|
@@ -212,9 +212,9 @@
|
|
|
212
212
|
"@opentelemetry/sdk-trace-node": "^2.11.0",
|
|
213
213
|
"@opentelemetry/semantic-conventions": "^1.43.0",
|
|
214
214
|
"@socketsecurity/bun-security-scanner": "^1.1.2",
|
|
215
|
-
"@supabase/supabase-js": "^2.
|
|
216
|
-
"@types/bun": "^1.4.
|
|
217
|
-
"@types/node": "26.
|
|
215
|
+
"@supabase/supabase-js": "^2.116.0",
|
|
216
|
+
"@types/bun": "^1.4.2",
|
|
217
|
+
"@types/node": "26.5.1",
|
|
218
218
|
"@types/papaparse": "^5.5.2",
|
|
219
219
|
"@types/sanitize-html": "^2.16.1",
|
|
220
220
|
"@types/validator": "^13.15.10",
|
|
@@ -230,7 +230,7 @@
|
|
|
230
230
|
"execa": "^10.0.1",
|
|
231
231
|
"fast-check": "^4.9.0",
|
|
232
232
|
"fast-xml-parser": "^5.11.1",
|
|
233
|
-
"ignore": "^7.0.
|
|
233
|
+
"ignore": "^7.0.9",
|
|
234
234
|
"js-yaml": "^5.4.1",
|
|
235
235
|
"linkedom": "^0.18.13",
|
|
236
236
|
"node-cron": "^4.6.0",
|
|
@@ -247,7 +247,7 @@
|
|
|
247
247
|
"typescript-v6": "npm:typescript@^6.0.3",
|
|
248
248
|
"unpdf": "^1.8.1",
|
|
249
249
|
"validator": "^13.15.35",
|
|
250
|
-
"vite": "8.
|
|
250
|
+
"vite": "8.3.0",
|
|
251
251
|
"vitest": "^4.1.11"
|
|
252
252
|
},
|
|
253
253
|
"keywords": [
|
|
@@ -282,7 +282,7 @@
|
|
|
282
282
|
],
|
|
283
283
|
"packageManager": "bun@1.4.0",
|
|
284
284
|
"engines": {
|
|
285
|
-
"bun": ">=1.
|
|
285
|
+
"bun": ">=1.4.0",
|
|
286
286
|
"node": ">=24.0.0"
|
|
287
287
|
},
|
|
288
288
|
"depcheck": {
|
|
@@ -302,14 +302,14 @@
|
|
|
302
302
|
"dependencies": {
|
|
303
303
|
"@hono/node-server": "^2.1.1",
|
|
304
304
|
"@modelcontextprotocol/client": "^2.0.0",
|
|
305
|
-
"@modelcontextprotocol/ext-apps": "^
|
|
305
|
+
"@modelcontextprotocol/ext-apps": "^2.0.0",
|
|
306
306
|
"@modelcontextprotocol/server": "^2.0.0",
|
|
307
307
|
"@opentelemetry/api": "^1.9.1",
|
|
308
308
|
"dotenv": "^17.4.2",
|
|
309
309
|
"hono": "^4.13.7",
|
|
310
310
|
"jose": "^6.2.12",
|
|
311
311
|
"pino": "^10.3.1",
|
|
312
|
-
"zod": "^4.
|
|
312
|
+
"zod": "^4.6.1"
|
|
313
313
|
},
|
|
314
314
|
"peerDependencies": {
|
|
315
315
|
"@duckdb/node-api": "^1.5.5-r.1",
|
|
@@ -152,6 +152,6 @@ for (const f of findings) {
|
|
|
152
152
|
console.error('');
|
|
153
153
|
}
|
|
154
154
|
console.error(
|
|
155
|
-
'See skills/api-linter/SKILL.md or scripts/check-framework-antipatterns.ts for rule rationale.',
|
|
155
|
+
'See framework-skills/api-linter/SKILL.md or scripts/check-framework-antipatterns.ts for rule rationale.',
|
|
156
156
|
);
|
|
157
157
|
process.exit(1);
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
3
|
* @fileoverview Enforces the skill-versioning policy (#98 → #99): a change to a
|
|
4
|
-
* `skills/<name>/SKILL.md` body must bump `metadata.version` in the same edit.
|
|
4
|
+
* `framework-skills/<name>/SKILL.md` body must bump `metadata.version` in the same edit.
|
|
5
5
|
* Documenting the policy made the expectation visible; this check makes it stick.
|
|
6
6
|
* The triggering incident was 7 missed bumps across 2 consecutive releases — the
|
|
7
7
|
* kind of low-salience checklist item that needs tooling, not vigilance.
|
|
8
8
|
*
|
|
9
|
-
* For each `skills/<name>/SKILL.md` that differs from `HEAD` (working tree, staged
|
|
9
|
+
* For each `framework-skills/<name>/SKILL.md` that differs from `HEAD` (working tree, staged
|
|
10
10
|
* or not), it compares the frontmatter `metadata.version` and the body across
|
|
11
11
|
* `HEAD` → working tree. A changed body with an unchanged version is a violation.
|
|
12
12
|
* Whitespace-only body edits never trigger it (the policy's typo/whitespace
|
|
@@ -35,7 +35,7 @@ import { resolve } from 'node:path';
|
|
|
35
35
|
import process from 'node:process';
|
|
36
36
|
|
|
37
37
|
const ROOT = resolve('.');
|
|
38
|
-
const SKILL_MD_RE = /^skills\/[^/]+\/SKILL\.md$/;
|
|
38
|
+
const SKILL_MD_RE = /^framework-skills\/[^/]+\/SKILL\.md$/;
|
|
39
39
|
|
|
40
40
|
interface DevcheckConfig {
|
|
41
41
|
skillVersions?: { ignore?: string[] };
|
|
@@ -54,7 +54,7 @@ function loadIgnorePatterns(): string[] {
|
|
|
54
54
|
|
|
55
55
|
/** Match check-skills-sync semantics: full `<name>/SKILL.md` path or the bare `<name>`. */
|
|
56
56
|
function isIgnored(relPath: string, patterns: string[]): boolean {
|
|
57
|
-
const name = relPath.split('/')[1]; // skills/<name>/SKILL.md → <name>
|
|
57
|
+
const name = relPath.split('/')[1]; // framework-skills/<name>/SKILL.md → <name>
|
|
58
58
|
return patterns.some(
|
|
59
59
|
(p) => p === relPath || p === name || (name !== undefined && p === `${name}/SKILL.md`),
|
|
60
60
|
);
|
|
@@ -70,10 +70,17 @@ function changedSkillFiles(): string[] {
|
|
|
70
70
|
.filter((p) => SKILL_MD_RE.test(p));
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
/**
|
|
73
|
+
/**
|
|
74
|
+
* Content of a path at `HEAD`, or null when it didn't exist there (new file).
|
|
75
|
+
* A tree renamed from the pre-0.13 `skills/` reads its `HEAD` copy from the old
|
|
76
|
+
* path, so the release that carries the rename still checks every body edit.
|
|
77
|
+
*/
|
|
74
78
|
function headContent(relPath: string): string | null {
|
|
75
|
-
const
|
|
76
|
-
|
|
79
|
+
const show = (p: string) => spawnSync('git', ['show', `HEAD:${p}`], { encoding: 'utf-8' });
|
|
80
|
+
const result = show(relPath);
|
|
81
|
+
if (result.status === 0) return result.stdout;
|
|
82
|
+
const legacy = show(relPath.replace(/^framework-skills\//, 'skills/'));
|
|
83
|
+
return legacy.status === 0 ? legacy.stdout : null;
|
|
77
84
|
}
|
|
78
85
|
|
|
79
86
|
/** `metadata.version` from skill frontmatter, or null when absent/unparseable. */
|
|
@@ -95,8 +102,8 @@ function bodiesDiffer(a: string, b: string): boolean {
|
|
|
95
102
|
return a.replace(/\s+/g, '') !== b.replace(/\s+/g, '');
|
|
96
103
|
}
|
|
97
104
|
|
|
98
|
-
if (!existsSync(resolve(ROOT, 'skills'))) {
|
|
99
|
-
console.log('Skipped: no skills/ directory.');
|
|
105
|
+
if (!existsSync(resolve(ROOT, 'framework-skills'))) {
|
|
106
|
+
console.log('Skipped: no framework-skills/ directory.');
|
|
100
107
|
process.exit(0);
|
|
101
108
|
}
|
|
102
109
|
|
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* @fileoverview Verifies that `skills/` (canonical) has been propagated to the
|
|
3
|
+
* @fileoverview Verifies that `framework-skills/` (canonical) has been propagated to the
|
|
4
4
|
* local mirrors `.agents/skills/` and `.claude/skills/`. The maintenance skill
|
|
5
|
-
* updates `skills/` for downstream servers; the mirrors are what local agent
|
|
5
|
+
* updates `framework-skills/` for downstream servers; the mirrors are what local agent
|
|
6
6
|
* toolchains actually read, and silent drift means agents run on stale guidance.
|
|
7
7
|
*
|
|
8
|
-
* Propagation is one-way (`skills/` → mirrors), so missing or content-drifted
|
|
8
|
+
* Propagation is one-way (`framework-skills/` → mirrors), so missing or content-drifted
|
|
9
9
|
* files are reported. A skill that exists *only* in a mirror is left alone when
|
|
10
10
|
* it's externally sourced (globally installed, other tools), but flagged as
|
|
11
11
|
* stale when its `SKILL.md` carries `metadata.audience: external` — a framework
|
|
12
|
-
* skill removed from `skills/` upstream that the mirror never had pruned.
|
|
12
|
+
* skill removed from `framework-skills/` upstream that the mirror never had pruned.
|
|
13
13
|
*
|
|
14
14
|
* Behavior:
|
|
15
15
|
* • In sync → pass
|
|
16
16
|
* • Mirrors missing entirely → skip (no mirrors to sync)
|
|
17
17
|
* • Drift (missing or changed files) → exit 1 with details (devcheck demotes to warning)
|
|
18
18
|
* • Stale framework skill in mirror → exit 1 (mirror-only dir with audience: external)
|
|
19
|
+
* • Unmigrated pre-0.13 `skills/` → exit 1 with the `git mv` step
|
|
20
|
+
* • Leftover pre-0.13 `skills/` → exit 1 with the removal step (both trees present)
|
|
19
21
|
*
|
|
20
22
|
* Ignore specific skills or files via `devcheck.config.json`:
|
|
21
23
|
*
|
|
@@ -25,7 +27,7 @@
|
|
|
25
27
|
* }
|
|
26
28
|
* }
|
|
27
29
|
*
|
|
28
|
-
* Patterns match relative paths under `skills/`. A bare name like `add-tool`
|
|
30
|
+
* Patterns match relative paths under `framework-skills/`. A bare name like `add-tool`
|
|
29
31
|
* ignores the whole directory; `add-tool/SKILL.md` ignores a single file.
|
|
30
32
|
* `.DS_Store` and other OS cruft are ignored by default.
|
|
31
33
|
*
|
|
@@ -39,7 +41,13 @@ import { relative, resolve, sep } from 'node:path';
|
|
|
39
41
|
import process from 'node:process';
|
|
40
42
|
|
|
41
43
|
const ROOT = resolve('.');
|
|
42
|
-
const SKILLS_DIR = resolve(ROOT, 'skills');
|
|
44
|
+
const SKILLS_DIR = resolve(ROOT, 'framework-skills');
|
|
45
|
+
/**
|
|
46
|
+
* Where the tree lived before 0.13. Claude Code and Codex auto-load a plugin's
|
|
47
|
+
* root `skills/`, so a server shipping a plugin manifest handed its development
|
|
48
|
+
* skills to every installing agent — hence the move.
|
|
49
|
+
*/
|
|
50
|
+
const LEGACY_SKILLS_DIR = resolve(ROOT, 'skills');
|
|
43
51
|
const MIRRORS: { label: string; path: string }[] = [
|
|
44
52
|
{ label: '.agents/skills', path: resolve(ROOT, '.agents/skills') },
|
|
45
53
|
{ label: '.claude/skills', path: resolve(ROOT, '.claude/skills') },
|
|
@@ -95,11 +103,51 @@ function isFrameworkManaged(skillMdPath: string): boolean {
|
|
|
95
103
|
return /^\s*audience:\s*external\s*$/m.test(readFileSync(skillMdPath, 'utf-8'));
|
|
96
104
|
}
|
|
97
105
|
|
|
106
|
+
/** Skill directories under `root` whose `SKILL.md` carries `audience: external`. */
|
|
107
|
+
function frameworkManagedDirs(root: string): string[] {
|
|
108
|
+
return skillDirNames(root).filter((name) => isFrameworkManaged(resolve(root, name, 'SKILL.md')));
|
|
109
|
+
}
|
|
110
|
+
|
|
98
111
|
if (!existsSync(SKILLS_DIR)) {
|
|
99
|
-
|
|
112
|
+
const unmigrated = frameworkManagedDirs(LEGACY_SKILLS_DIR).length > 0;
|
|
113
|
+
if (unmigrated) {
|
|
114
|
+
console.log(
|
|
115
|
+
[
|
|
116
|
+
'skills/ still holds framework-managed skills and framework-skills/ is absent.',
|
|
117
|
+
'The framework moved its skill tree in 0.13.0: plugin hosts auto-load a root skills/,',
|
|
118
|
+
'which surfaced these development skills to every agent that installed the server.',
|
|
119
|
+
'',
|
|
120
|
+
'Fix: git mv skills framework-skills',
|
|
121
|
+
' then update the path in CLAUDE.md/AGENTS.md, .mcpbignore (/framework-skills/),',
|
|
122
|
+
' and .github/CONTRIBUTING.md, and regenerate docs/tree.md.',
|
|
123
|
+
].join('\n'),
|
|
124
|
+
);
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
console.log('Skipped: no framework-skills/ directory.');
|
|
100
128
|
process.exit(0);
|
|
101
129
|
}
|
|
102
130
|
|
|
131
|
+
// Both trees present. `init` run in place never overwrites an existing file, so an
|
|
132
|
+
// upgrade creates `framework-skills/` and leaves the old copies where a plugin host
|
|
133
|
+
// still auto-loads them. Only a name carried by both trees is a leftover — a `skills/`
|
|
134
|
+
// name of its own is the reserved server-published kind.
|
|
135
|
+
const canonicalDirs = new Set(skillDirNames(SKILLS_DIR));
|
|
136
|
+
const leftover = frameworkManagedDirs(LEGACY_SKILLS_DIR).filter((name) => canonicalDirs.has(name));
|
|
137
|
+
if (leftover.length > 0) {
|
|
138
|
+
console.log(
|
|
139
|
+
[
|
|
140
|
+
`skills/ still holds ${leftover.length} framework skill(s) that framework-skills/ also carries.`,
|
|
141
|
+
'Plugin hosts auto-load a root skills/, so those development skills still reach every',
|
|
142
|
+
'agent that installs the server.',
|
|
143
|
+
'',
|
|
144
|
+
`Fix: rm -rf ${leftover.map((name) => `skills/${name}`).join(' ')}`,
|
|
145
|
+
' Keep skills/ for skills the server publishes to the agents that use it.',
|
|
146
|
+
].join('\n'),
|
|
147
|
+
);
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
150
|
+
|
|
103
151
|
const presentMirrors = MIRRORS.filter((m) => existsSync(m.path));
|
|
104
152
|
if (presentMirrors.length === 0) {
|
|
105
153
|
console.log('Skipped: no skill mirrors (.agents/skills, .claude/skills) present.');
|
|
@@ -131,10 +179,9 @@ for (const mirror of presentMirrors) {
|
|
|
131
179
|
}
|
|
132
180
|
|
|
133
181
|
// Stale framework skills: a skill dir present only in a mirror (absent from
|
|
134
|
-
// canonical skills/) is fine when externally sourced, but stale when it carries
|
|
135
|
-
// `audience: external` — a framework skill removed from skills/ that was never
|
|
182
|
+
// canonical framework-skills/) is fine when externally sourced, but stale when it carries
|
|
183
|
+
// `audience: external` — a framework skill removed from framework-skills/ that was never
|
|
136
184
|
// pruned from the mirror. User/external skills (no marker) are left alone.
|
|
137
|
-
const canonicalDirs = new Set(skillDirNames(SKILLS_DIR));
|
|
138
185
|
const stale: Record<string, string[]> = {};
|
|
139
186
|
for (const mirror of presentMirrors) {
|
|
140
187
|
const staleHere = skillDirNames(mirror.path)
|
|
@@ -152,13 +199,15 @@ const totals = {
|
|
|
152
199
|
const driftCount = totals.missing + totals.drifted + totals.stale;
|
|
153
200
|
|
|
154
201
|
if (driftCount === 0) {
|
|
155
|
-
console.log(
|
|
202
|
+
console.log(
|
|
203
|
+
`framework-skills/ is in sync with ${presentMirrors.map((m) => m.label).join(' and ')}.`,
|
|
204
|
+
);
|
|
156
205
|
process.exit(0);
|
|
157
206
|
}
|
|
158
207
|
|
|
159
208
|
const lines: string[] = [];
|
|
160
209
|
lines.push(
|
|
161
|
-
`skills/ has drifted from ${presentMirrors.length > 1 ? 'mirrors' : 'its mirror'} ` +
|
|
210
|
+
`framework-skills/ has drifted from ${presentMirrors.length > 1 ? 'mirrors' : 'its mirror'} ` +
|
|
162
211
|
`(${totals.missing} missing, ${totals.drifted} changed, ${totals.stale} stale).`,
|
|
163
212
|
);
|
|
164
213
|
|
|
@@ -175,7 +224,9 @@ renderSection('Content differs in', drifted);
|
|
|
175
224
|
renderSection('Stale framework skill (deleted upstream) in', stale);
|
|
176
225
|
|
|
177
226
|
lines.push('');
|
|
178
|
-
lines.push(
|
|
227
|
+
lines.push(
|
|
228
|
+
'Fix: propagate framework-skills/ to the mirror(s) and delete stale framework skills from them,',
|
|
229
|
+
);
|
|
179
230
|
lines.push(
|
|
180
231
|
' or add entries to devcheck.config.json `skillsSync.ignore` to silence specific paths.',
|
|
181
232
|
);
|
package/scripts/clean-mcpb.ts
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
* 2. Exact-name strip of two entry classes nested under `node_modules/`,
|
|
10
10
|
* which root-anchored `.mcpbignore` patterns cannot reach by design
|
|
11
11
|
* (issues #146/#207):
|
|
12
|
-
* a. Dependency-shipped agent docs — `skills/`,
|
|
13
|
-
* trees and stray `SKILL.md` files (issue #230).
|
|
12
|
+
* a. Dependency-shipped agent docs — `framework-skills/`, `skills/`,
|
|
13
|
+
* `.claude/`, `.agents/` trees and stray `SKILL.md` files (issue #230).
|
|
14
14
|
* b. Platform-specific native bindings, which would otherwise lock the
|
|
15
15
|
* bundle to the build host's platform and push it past the 25 MB cap
|
|
16
16
|
* registries enforce (issue #274).
|
|
@@ -36,7 +36,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
36
36
|
* (post-bundle content check) — a unit test asserts the two are identical.
|
|
37
37
|
*/
|
|
38
38
|
export const AGENT_DOC_ENTRY =
|
|
39
|
-
/^node_modules\/.*(?:\/skills\/|\/\.claude\/|\/\.agents\/|\/SKILL\.md$)/;
|
|
39
|
+
/^node_modules\/.*(?:\/framework-skills\/|\/skills\/|\/\.claude\/|\/\.agents\/|\/SKILL\.md$)/;
|
|
40
40
|
|
|
41
41
|
/**
|
|
42
42
|
* Platform-specific native binding packages, which must not ship in a bundle.
|
package/scripts/devcheck.ts
CHANGED
|
@@ -437,7 +437,8 @@ interface OutdatedRow {
|
|
|
437
437
|
current: string;
|
|
438
438
|
/** The declared key when attribution is unambiguous, else null. */
|
|
439
439
|
declaredKey: string | null;
|
|
440
|
-
|
|
440
|
+
/** The block the row belongs to; `bun outdated` leaves `prod` rows unmarked. */
|
|
441
|
+
group: DependencyGroup;
|
|
441
442
|
/** The row verbatim, used to key the rendered rewrite back to its line. */
|
|
442
443
|
line: string;
|
|
443
444
|
/** First cell as printed, marker included. */
|
|
@@ -457,11 +458,11 @@ interface OutdatedRow {
|
|
|
457
458
|
*/
|
|
458
459
|
function attributeOutdatedRow(
|
|
459
460
|
target: string,
|
|
460
|
-
group: DependencyGroup
|
|
461
|
+
group: DependencyGroup,
|
|
461
462
|
current: string,
|
|
462
463
|
): Pick<OutdatedRow, 'candidates' | 'declaredKey'> {
|
|
463
464
|
const matches = DECLARED_DEPENDENCIES.filter(
|
|
464
|
-
(declared) => declared.target === target &&
|
|
465
|
+
(declared) => declared.target === target && declared.group === group,
|
|
465
466
|
);
|
|
466
467
|
const candidates = matches.map((declared) => declared.key);
|
|
467
468
|
if (candidates.length <= 1) return { candidates, declaredKey: candidates[0] ?? null };
|
|
@@ -481,7 +482,7 @@ function parseOutdatedRows(output: string): OutdatedRow[] {
|
|
|
481
482
|
const rawName = cells[1] ?? '';
|
|
482
483
|
// Skip table chrome: header row and separator (e.g., "---")
|
|
483
484
|
if (!rawName || rawName === 'Package' || /^-+$/.test(rawName)) continue;
|
|
484
|
-
const group = (OUTDATED_GROUP_MARKER.exec(rawName)?.[1] ??
|
|
485
|
+
const group = (OUTDATED_GROUP_MARKER.exec(rawName)?.[1] ?? 'prod') as DependencyGroup;
|
|
485
486
|
const target = rawName.replace(OUTDATED_GROUP_MARKER, '');
|
|
486
487
|
const current = cells[2] ?? '';
|
|
487
488
|
const update = (cells[3] ?? '').replace(/\*/g, '').trim();
|
|
@@ -514,7 +515,7 @@ function renderOutdatedTable(output: string): string {
|
|
|
514
515
|
const row = attributed.get(line);
|
|
515
516
|
let display = cell.trim();
|
|
516
517
|
if (row?.declaredKey && row.declaredKey !== row.target) {
|
|
517
|
-
display = row.group ? `${row.declaredKey} (${row.group})
|
|
518
|
+
display = row.group === 'prod' ? row.declaredKey : `${row.declaredKey} (${row.group})`;
|
|
518
519
|
}
|
|
519
520
|
return { line, display };
|
|
520
521
|
});
|
|
@@ -552,9 +553,12 @@ function renderOutdatedTable(output: string): string {
|
|
|
552
553
|
* Parses `bun audit` output and classifies high/critical vulnerabilities as
|
|
553
554
|
* direct (in our package.json) or upstream (transitive dependency we can't fix).
|
|
554
555
|
*
|
|
555
|
-
* Bun audit format per vulnerability block
|
|
556
|
-
*
|
|
557
|
-
*
|
|
556
|
+
* Bun audit format per vulnerability block — Bun 1.4 changed the header token
|
|
557
|
+
* and the path separator, so both shapes are accepted:
|
|
558
|
+
* <package> <version-range> ← header, Bun <1.4 (no indent, 2+ spaces before range)
|
|
559
|
+
* <package>@<version> ← header, Bun ≥1.4
|
|
560
|
+
* <parent> › <child> [› ...] ← dependency path (indented; › or, Bun ≥1.4, > = transitive)
|
|
561
|
+
* (direct dependency) ← dependency path of a direct dependency, Bun ≥1.4
|
|
558
562
|
* <severity>: <description> ← advisory (indented)
|
|
559
563
|
*
|
|
560
564
|
* Returns null if parsing yields no results (caller should fall back to default behavior).
|
|
@@ -567,8 +571,10 @@ function classifyAuditVulns(output: string): { direct: string[]; upstream: strin
|
|
|
567
571
|
let i = 0;
|
|
568
572
|
|
|
569
573
|
while (i < lines.length) {
|
|
570
|
-
// Package header: non-indented
|
|
571
|
-
|
|
574
|
+
// Package header: non-indented `name range` (2+ spaces, Bun <1.4) or
|
|
575
|
+
// `name@version` (Bun ≥1.4). A scoped name leads with `@`, so only a
|
|
576
|
+
// later `@` splits the Bun 1.4 form.
|
|
577
|
+
const pkgMatch = lines[i]?.match(/^(@?\w[\w./-]*)(?:\s{2,}|@)(\S.*)$/);
|
|
572
578
|
if (!pkgMatch) {
|
|
573
579
|
i++;
|
|
574
580
|
continue;
|
|
@@ -593,14 +599,15 @@ function classifyAuditVulns(output: string): { direct: string[]; upstream: strin
|
|
|
593
599
|
|
|
594
600
|
if (!hasHighCritical) continue;
|
|
595
601
|
|
|
596
|
-
// Direct if: the vulnerable package is in our package.json,
|
|
597
|
-
//
|
|
602
|
+
// Direct if: the vulnerable package is in our package.json, or any
|
|
603
|
+
// dependency path lacks a transitive separator — U+203A `›` (Bun <1.4)
|
|
604
|
+
// or `>` (Bun ≥1.4). Bun 1.4's literal `(direct dependency)` path has neither.
|
|
598
605
|
const pkgName = pkg ?? '';
|
|
599
|
-
const isDirect = DIRECT_DEPS.has(pkgName) || paths.some((p) =>
|
|
606
|
+
const isDirect = DIRECT_DEPS.has(pkgName) || paths.some((p) => !/[\u203a>]/.test(p));
|
|
600
607
|
if (isDirect) {
|
|
601
608
|
direct.push(`${pkgName} ${versionRange}`);
|
|
602
609
|
} else {
|
|
603
|
-
const via = paths[0]?.split(/\s
|
|
610
|
+
const via = paths[0]?.split(/\s*[\u203a>]\s*/)[0] ?? 'unknown';
|
|
604
611
|
upstream.push(`${pkgName} ${versionRange} (via ${via})`);
|
|
605
612
|
}
|
|
606
613
|
}
|
|
@@ -689,7 +696,7 @@ const ALL_CHECKS: Check[] = [
|
|
|
689
696
|
canFix: false,
|
|
690
697
|
getCommand: () => ['bun', 'run', 'scripts/lint-mcp.ts'],
|
|
691
698
|
tip: (c) =>
|
|
692
|
-
`Fix definition errors above — each diagnostic links to its rule in ${c.bold('skills/api-linter/SKILL.md')}.`,
|
|
699
|
+
`Fix definition errors above — each diagnostic links to its rule in ${c.bold('framework-skills/api-linter/SKILL.md')}.`,
|
|
693
700
|
},
|
|
694
701
|
{
|
|
695
702
|
name: 'Packaging',
|
|
@@ -764,16 +771,19 @@ const ALL_CHECKS: Check[] = [
|
|
|
764
771
|
name: 'Skills Sync',
|
|
765
772
|
flag: '--no-skills-sync',
|
|
766
773
|
canFix: false,
|
|
767
|
-
// Compares canonical skills/ against local mirrors (.agents/skills, .claude/skills).
|
|
768
|
-
// Skipped when skills/ or both mirrors are absent (non-mirrored projects)
|
|
769
|
-
//
|
|
770
|
-
//
|
|
774
|
+
// Compares canonical framework-skills/ against local mirrors (.agents/skills, .claude/skills).
|
|
775
|
+
// Skipped when framework-skills/ or both mirrors are absent (non-mirrored projects),
|
|
776
|
+
// except that a pre-0.13 `skills/` tree always runs — absent or alongside
|
|
777
|
+
// `framework-skills/` — so the script's migration message surfaces. Drift is demoted to
|
|
778
|
+
// a warning via isSuccess — intentional ignores live in devcheck.config.json
|
|
779
|
+
// `skillsSync.ignore`.
|
|
771
780
|
getCommand: () => {
|
|
772
|
-
const hasSkills = existsSync(path.join(ROOT_DIR, 'skills'));
|
|
781
|
+
const hasSkills = existsSync(path.join(ROOT_DIR, 'framework-skills'));
|
|
782
|
+
const hasLegacySkills = existsSync(path.join(ROOT_DIR, 'skills'));
|
|
773
783
|
const hasMirrors =
|
|
774
784
|
existsSync(path.join(ROOT_DIR, '.agents/skills')) ||
|
|
775
785
|
existsSync(path.join(ROOT_DIR, '.claude/skills'));
|
|
776
|
-
if (!hasSkills || !hasMirrors) return null;
|
|
786
|
+
if (!hasLegacySkills && (!hasSkills || !hasMirrors)) return null;
|
|
777
787
|
return ['bun', 'run', 'scripts/check-skills-sync.ts'];
|
|
778
788
|
},
|
|
779
789
|
isSuccess: (result) => {
|
|
@@ -782,18 +792,18 @@ const ALL_CHECKS: Check[] = [
|
|
|
782
792
|
return { success: true, warning: firstLine };
|
|
783
793
|
},
|
|
784
794
|
tip: (c) =>
|
|
785
|
-
`Propagate ${c.bold('skills/')} to ${c.bold('.agents/skills/')} and ${c.bold('.claude/skills/')}, or add entries to ${c.bold('devcheck.config.json')} ${c.bold('skillsSync.ignore')}.`,
|
|
795
|
+
`Propagate ${c.bold('framework-skills/')} to ${c.bold('.agents/skills/')} and ${c.bold('.claude/skills/')}, or add entries to ${c.bold('devcheck.config.json')} ${c.bold('skillsSync.ignore')}.`,
|
|
786
796
|
},
|
|
787
797
|
{
|
|
788
798
|
name: 'Skill Versions',
|
|
789
799
|
flag: '--no-skill-versions',
|
|
790
800
|
canFix: false,
|
|
791
|
-
// Flags skills/<name>/SKILL.md body changes (vs HEAD) that lack a metadata.version
|
|
792
|
-
// bump (#99). Skipped when skills/ is absent. Drift is demoted to a warning via
|
|
801
|
+
// Flags framework-skills/<name>/SKILL.md body changes (vs HEAD) that lack a metadata.version
|
|
802
|
+
// bump (#99). Skipped when framework-skills/ is absent. Drift is demoted to a warning via
|
|
793
803
|
// isSuccess — the typo/whitespace carve-out lives in devcheck.config.json
|
|
794
804
|
// `skillVersions.ignore`.
|
|
795
805
|
getCommand: () => {
|
|
796
|
-
if (!existsSync(path.join(ROOT_DIR, 'skills'))) return null;
|
|
806
|
+
if (!existsSync(path.join(ROOT_DIR, 'framework-skills'))) return null;
|
|
797
807
|
return ['bun', 'run', 'scripts/check-skill-versions.ts'];
|
|
798
808
|
},
|
|
799
809
|
isSuccess: (result) => {
|
|
@@ -896,7 +906,7 @@ const ALL_CHECKS: Check[] = [
|
|
|
896
906
|
{
|
|
897
907
|
name: 'Security Audit',
|
|
898
908
|
flag: '--no-audit',
|
|
899
|
-
canFix: false, // audit
|
|
909
|
+
canFix: false, // `audit fix` exists but often requires manual review.
|
|
900
910
|
slowCheck: true,
|
|
901
911
|
getCommand: () => [PM_CMD, 'audit'],
|
|
902
912
|
isSuccess: (result, _mode) => {
|
|
@@ -944,7 +954,7 @@ const ALL_CHECKS: Check[] = [
|
|
|
944
954
|
return true;
|
|
945
955
|
},
|
|
946
956
|
tip: (c) =>
|
|
947
|
-
`Direct dependency vulnerabilities found. Run ${c.bold(`${PM_CMD}
|
|
957
|
+
`Direct dependency vulnerabilities found. Run ${c.bold(`${PM_CMD} audit fix`)} or ${c.bold(`${PM_CMD} update <pkg>`)} to resolve.`,
|
|
948
958
|
},
|
|
949
959
|
{
|
|
950
960
|
name: 'Dependencies (Outdated)',
|