vskill 1.2.4 → 1.2.7

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 (114) hide show
  1. package/README.md +51 -3
  2. package/agents.json +6 -1
  3. package/dist/agents/agents-registry.d.ts +43 -16
  4. package/dist/agents/agents-registry.js +119 -33
  5. package/dist/agents/agents-registry.js.map +1 -1
  6. package/dist/agents/global-dirs.d.ts +19 -0
  7. package/dist/agents/global-dirs.js +53 -0
  8. package/dist/agents/global-dirs.js.map +1 -0
  9. package/dist/audit/fix-suggestions.js +6 -0
  10. package/dist/audit/fix-suggestions.js.map +1 -1
  11. package/dist/commands/add-github-bundle.d.ts +29 -0
  12. package/dist/commands/add-github-bundle.js +135 -0
  13. package/dist/commands/add-github-bundle.js.map +1 -0
  14. package/dist/commands/add-lockfile.d.ts +2 -0
  15. package/dist/commands/add-lockfile.js +1 -1
  16. package/dist/commands/add-lockfile.js.map +1 -1
  17. package/dist/commands/add.d.ts +5 -7
  18. package/dist/commands/add.js +207 -111
  19. package/dist/commands/add.js.map +1 -1
  20. package/dist/commands/audit-webmcp.d.ts +25 -0
  21. package/dist/commands/audit-webmcp.js +167 -0
  22. package/dist/commands/audit-webmcp.js.map +1 -0
  23. package/dist/commands/doctor.d.ts +69 -0
  24. package/dist/commands/doctor.js +760 -0
  25. package/dist/commands/doctor.js.map +1 -0
  26. package/dist/commands/remove.js +43 -8
  27. package/dist/commands/remove.js.map +1 -1
  28. package/dist/commands/scan.js +1 -1
  29. package/dist/commands/scan.js.map +1 -1
  30. package/dist/commands/update.js +12 -4
  31. package/dist/commands/update.js.map +1 -1
  32. package/dist/discovery/github-skill-bundle.d.ts +74 -0
  33. package/dist/discovery/github-skill-bundle.js +323 -0
  34. package/dist/discovery/github-skill-bundle.js.map +1 -0
  35. package/dist/eval/skill-scanner.js +7 -1
  36. package/dist/eval/skill-scanner.js.map +1 -1
  37. package/dist/eval-server/install-skill-routes.js +10 -3
  38. package/dist/eval-server/install-skill-routes.js.map +1 -1
  39. package/dist/eval-server/remove-skill-routes.js +262 -29
  40. package/dist/eval-server/remove-skill-routes.js.map +1 -1
  41. package/dist/eval-server/studio-privacy.js +2 -3
  42. package/dist/eval-server/studio-privacy.js.map +1 -1
  43. package/dist/eval-server/utils/scan-install-locations.js +22 -3
  44. package/dist/eval-server/utils/scan-install-locations.js.map +1 -1
  45. package/dist/eval-ui/assets/{CreateSkillPage-BUrgworx.js → CreateSkillPage-CXDd6gDN.js} +1 -1
  46. package/dist/eval-ui/assets/{FindSkillsPalette-BstJ22TI.js → FindSkillsPalette-DQ6uGhFP.js} +2 -2
  47. package/dist/eval-ui/assets/{SearchPaletteCore-Dagnc-E7.js → SearchPaletteCore-DpHCf0mf.js} +1 -1
  48. package/dist/eval-ui/assets/{SkillDetailPanel-DnujVk6g.js → SkillDetailPanel-BjHFjGxg.js} +1 -1
  49. package/dist/eval-ui/assets/{UpdateDropdown-B7D2vXrm.js → UpdateDropdown-Cn4Vsq5d.js} +1 -1
  50. package/dist/eval-ui/assets/main-BmB7Zj9I.js +86 -0
  51. package/dist/eval-ui/index.html +1 -1
  52. package/dist/index.js +34 -0
  53. package/dist/index.js.map +1 -1
  54. package/dist/installer/bundle-files.d.ts +39 -2
  55. package/dist/installer/bundle-files.js +80 -10
  56. package/dist/installer/bundle-files.js.map +1 -1
  57. package/dist/installer/canonical.d.ts +39 -4
  58. package/dist/installer/canonical.js +178 -24
  59. package/dist/installer/canonical.js.map +1 -1
  60. package/dist/installer/multi-install.d.ts +11 -2
  61. package/dist/installer/multi-install.js +41 -9
  62. package/dist/installer/multi-install.js.map +1 -1
  63. package/dist/installer/transformers/index.d.ts +8 -0
  64. package/dist/installer/yaml-safe-mutate.js +48 -2
  65. package/dist/installer/yaml-safe-mutate.js.map +1 -1
  66. package/dist/lib/github-fetch.js +2 -0
  67. package/dist/lib/github-fetch.js.map +1 -1
  68. package/dist/lib/private-source.d.ts +8 -0
  69. package/dist/lib/private-source.js +16 -2
  70. package/dist/lib/private-source.js.map +1 -1
  71. package/dist/scanner/hidden-content.d.ts +47 -0
  72. package/dist/scanner/hidden-content.js +904 -0
  73. package/dist/scanner/hidden-content.js.map +1 -0
  74. package/dist/scanner/installer-hosts.d.ts +26 -0
  75. package/dist/scanner/installer-hosts.js +92 -0
  76. package/dist/scanner/installer-hosts.js.map +1 -0
  77. package/dist/scanner/judge-guard.d.ts +119 -0
  78. package/dist/scanner/judge-guard.js +481 -0
  79. package/dist/scanner/judge-guard.js.map +1 -0
  80. package/dist/scanner/patterns.d.ts +12 -0
  81. package/dist/scanner/patterns.js +353 -113
  82. package/dist/scanner/patterns.js.map +1 -1
  83. package/dist/scanner/repo-scanner.d.ts +4 -0
  84. package/dist/scanner/repo-scanner.js +4 -1
  85. package/dist/scanner/repo-scanner.js.map +1 -1
  86. package/dist/scanner/tier1.js +37 -7
  87. package/dist/scanner/tier1.js.map +1 -1
  88. package/dist/scanner/tier2-llm.d.ts +22 -4
  89. package/dist/scanner/tier2-llm.js +163 -23
  90. package/dist/scanner/tier2-llm.js.map +1 -1
  91. package/dist/scanner/types.d.ts +8 -0
  92. package/dist/webmcp/args.d.ts +34 -0
  93. package/dist/webmcp/args.js +87 -0
  94. package/dist/webmcp/args.js.map +1 -0
  95. package/dist/webmcp/attribution.d.ts +38 -0
  96. package/dist/webmcp/attribution.js +141 -0
  97. package/dist/webmcp/attribution.js.map +1 -0
  98. package/dist/webmcp/enumerate.d.ts +81 -0
  99. package/dist/webmcp/enumerate.js +436 -0
  100. package/dist/webmcp/enumerate.js.map +1 -0
  101. package/dist/webmcp/format.d.ts +9 -0
  102. package/dist/webmcp/format.js +105 -0
  103. package/dist/webmcp/format.js.map +1 -0
  104. package/dist/webmcp/merge.d.ts +49 -0
  105. package/dist/webmcp/merge.js +167 -0
  106. package/dist/webmcp/merge.js.map +1 -0
  107. package/dist/webmcp/score.d.ts +70 -0
  108. package/dist/webmcp/score.js +586 -0
  109. package/dist/webmcp/score.js.map +1 -0
  110. package/dist/webmcp/types.d.ts +92 -0
  111. package/dist/webmcp/types.js +8 -0
  112. package/dist/webmcp/types.js.map +1 -0
  113. package/package.json +1 -1
  114. package/dist/eval-ui/assets/main-DjA5gpjV.js +0 -86
@@ -0,0 +1,167 @@
1
+ /**
2
+ * vskill audit-webmcp -- audit the WebMCP tools a website registers.
3
+ *
4
+ * Loads each URL once in headless Chromium with the WebMCP feature on,
5
+ * enumerates document.modelContext tools (registerTool capture, CDP WebMCP
6
+ * domain, getTools), and scores them. Never invokes a tool or submits a form.
7
+ *
8
+ * Exit codes: 0 done, 1 a finding at or above --fail-on, 2 bad arguments or
9
+ * no browser available.
10
+ */
11
+ import { readFileSync, writeFileSync, appendFileSync } from "node:fs";
12
+ import { ArgError, resolveOptions } from "../webmcp/args.js";
13
+ import { enumerateSite, launchBrowser, userAgentFor } from "../webmcp/enumerate.js";
14
+ import { formatBatchFooter, formatSiteTerminal } from "../webmcp/format.js";
15
+ import { atOrAbove, buildReport } from "../webmcp/score.js";
16
+ import { red } from "../utils/output.js";
17
+ /** Scan URLs with a bounded pool; per-site failures become reports with `error`. */
18
+ export async function auditSites(browser, urls, opts, onReport) {
19
+ const reports = new Array(urls.length);
20
+ let current = browser;
21
+ let relaunching = null;
22
+ const ensureBrowser = async () => {
23
+ if (current.isConnected() || !opts.relaunch)
24
+ return;
25
+ relaunching ??= opts
26
+ .relaunch()
27
+ .then((b) => {
28
+ current = b;
29
+ })
30
+ .catch(() => { })
31
+ .finally(() => {
32
+ relaunching = null;
33
+ });
34
+ await relaunching;
35
+ };
36
+ let next = 0;
37
+ const worker = async () => {
38
+ while (next < urls.length) {
39
+ const i = next++;
40
+ const url = urls[i];
41
+ await ensureBrowser();
42
+ const hardLimit = opts.timeoutMs + (opts.settleMs ?? 5000) + 15_000;
43
+ let timer;
44
+ // On the hard limit, abort: enumerateSite closes its context so a hung page stops using CPU.
45
+ const abort = new AbortController();
46
+ const enumeration = await Promise.race([
47
+ enumerateSite(current, url, {
48
+ timeoutMs: opts.timeoutMs,
49
+ settleMs: opts.settleMs,
50
+ userAgent: opts.userAgent,
51
+ signal: abort.signal,
52
+ }),
53
+ new Promise((_, reject) => {
54
+ timer = setTimeout(() => {
55
+ abort.abort();
56
+ reject(new Error(`site scan exceeded ${hardLimit}ms`));
57
+ }, hardLimit);
58
+ }),
59
+ ])
60
+ .catch((e) => ({
61
+ url,
62
+ finalUrl: null,
63
+ documentModelContext: false,
64
+ navigatorModelContext: false,
65
+ permissionsPolicy: null,
66
+ tools: [],
67
+ error: e instanceof Error ? e.message.split("\n")[0] : String(e),
68
+ }))
69
+ .finally(() => clearTimeout(timer));
70
+ const report = buildReport(enumeration);
71
+ reports[i] = report;
72
+ onReport?.(report, i);
73
+ }
74
+ };
75
+ await Promise.all(Array.from({ length: Math.max(1, Math.min(opts.concurrency, urls.length)) }, worker));
76
+ return reports;
77
+ }
78
+ export function shouldFail(reports, failOn) {
79
+ if (!failOn)
80
+ return false;
81
+ return reports.some((r) => r.findings.some((f) => atOrAbove(f.severity, failOn)));
82
+ }
83
+ export async function auditWebmcpCommand(positional, raw) {
84
+ let opts;
85
+ try {
86
+ let fileText;
87
+ if (raw.urlsFile) {
88
+ try {
89
+ fileText = readFileSync(raw.urlsFile, "utf8");
90
+ }
91
+ catch (e) {
92
+ throw new ArgError(`Cannot read --urls-file ${raw.urlsFile}: ${e.message}`);
93
+ }
94
+ }
95
+ opts = resolveOptions(positional, raw, fileText);
96
+ }
97
+ catch (e) {
98
+ if (e instanceof ArgError) {
99
+ console.error(red(e.message));
100
+ process.exit(2);
101
+ return;
102
+ }
103
+ throw e;
104
+ }
105
+ // Fail on an unwritable --out before starting a browser.
106
+ if (opts.out) {
107
+ try {
108
+ writeFileSync(opts.out, "");
109
+ }
110
+ catch (e) {
111
+ console.error(red(`Cannot write --out ${opts.out}: ${e.message}`));
112
+ process.exit(2);
113
+ return;
114
+ }
115
+ }
116
+ let browser;
117
+ try {
118
+ browser = await launchBrowser({ executablePath: opts.executablePath });
119
+ }
120
+ catch (e) {
121
+ const err = e;
122
+ console.error(err.code === "VSKILL_NO_PLAYWRIGHT" ? err.message : red(`Could not launch headless Chromium: ${err.message.split("\n")[0]}`));
123
+ if (err.code !== "VSKILL_NO_PLAYWRIGHT") {
124
+ console.error("Install one with `npx playwright install chromium-headless-shell` or pass --executable-path <path>.");
125
+ }
126
+ process.exit(2);
127
+ return;
128
+ }
129
+ const batch = opts.urls.length > 1;
130
+ let reports;
131
+ try {
132
+ // Identify the crawler in the UA; fall back to the browser default if that probe fails.
133
+ const userAgent = await userAgentFor(browser).catch(() => undefined);
134
+ const relaunch = async () => {
135
+ await browser.close().catch(() => { });
136
+ browser = await launchBrowser({ executablePath: opts.executablePath });
137
+ return browser;
138
+ };
139
+ const auditOpts = { concurrency: opts.concurrency, timeoutMs: opts.timeoutMs, userAgent, relaunch };
140
+ reports = await auditSites(browser, opts.urls, auditOpts, (r, i) => {
141
+ if (opts.out && opts.outFormat === "jsonl")
142
+ appendFileSync(opts.out, JSON.stringify(r) + "\n");
143
+ if (opts.json) {
144
+ if (batch)
145
+ console.log(JSON.stringify(r));
146
+ }
147
+ else {
148
+ if (batch)
149
+ process.stderr.write(`[${i + 1}/${opts.urls.length}] ${r.url}\n`);
150
+ console.log(formatSiteTerminal(r) + "\n");
151
+ }
152
+ });
153
+ }
154
+ finally {
155
+ await browser.close().catch(() => { });
156
+ }
157
+ if (opts.out && opts.outFormat === "json")
158
+ writeFileSync(opts.out, JSON.stringify(reports[0], null, 2) + "\n");
159
+ if (opts.json && !batch)
160
+ console.log(JSON.stringify(reports[0], null, 2));
161
+ if (!opts.json && batch)
162
+ console.log(formatBatchFooter(reports));
163
+ // process.exit can drop buffered stdout when it is a pipe (`| jq`): flush first.
164
+ await new Promise((resolve) => process.stdout.write("", () => resolve()));
165
+ process.exit(shouldFail(reports, opts.failOn) ? 1 : 0);
166
+ }
167
+ //# sourceMappingURL=audit-webmcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-webmcp.js","sourceRoot":"","sources":["../../src/commands/audit-webmcp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ import { type AgentDefinition } from "../agents/agents-registry.js";
2
+ export type DoctorScope = "global" | "project";
3
+ export type DoctorSeverity = "error" | "warning";
4
+ export type DoctorIssueKind = "divergent" | "identical-copy" | "broken-link" | "redundant-link" | "migration-damage" | "name-mismatch" | "duplicate-name" | "bad-name" | "bad-description";
5
+ export declare const DOCTOR_ISSUE_KINDS: readonly DoctorIssueKind[];
6
+ export interface DoctorIssue {
7
+ kind: DoctorIssueKind;
8
+ severity: DoctorSeverity;
9
+ scope: DoctorScope;
10
+ /** Skill folder name (or declared name for duplicate-name). */
11
+ skill: string;
12
+ /** Every path involved; for identical-copy the first is the kept copy. */
13
+ paths: string[];
14
+ message: string;
15
+ fixable: boolean;
16
+ /** Agents affected, where it matters (redundant-link, duplicate-name). */
17
+ agents?: string[];
18
+ }
19
+ export interface DoctorFixAction {
20
+ kind: DoctorIssueKind;
21
+ action: "remove-link" | "replace-with-link";
22
+ path: string;
23
+ target?: string;
24
+ ok: boolean;
25
+ error?: string;
26
+ }
27
+ export interface ScannedDir {
28
+ scope: DoctorScope;
29
+ dir: string;
30
+ readers: string[];
31
+ }
32
+ export interface DoctorReport {
33
+ scopes: DoctorScope[];
34
+ scanned: ScannedDir[];
35
+ issues: DoctorIssue[];
36
+ fixes: DoctorFixAction[];
37
+ summary: Record<DoctorIssueKind, number>;
38
+ /** Problems left after any fixes (equals issues.length). */
39
+ remaining: number;
40
+ }
41
+ export interface DoctorOptions {
42
+ global?: boolean;
43
+ project?: boolean;
44
+ json?: boolean;
45
+ fix?: boolean;
46
+ /** Test seams — default to the real home dir, cwd and platform. */
47
+ home?: string;
48
+ cwd?: string;
49
+ platform?: NodeJS.Platform;
50
+ }
51
+ /** Every dir an agent reads in a scope (absolute paths). */
52
+ export declare function agentSkillDirs(agent: AgentDefinition, scope: DoctorScope, home: string, cwd: string): string[];
53
+ /** Hash every file in a folder (sorted by relative path), ignoring .DS_Store.
54
+ * 0894: a file's executable bit is part of its record (a copy whose script
55
+ * lost +x is not identical), and a symlink inside the skill is hashed by
56
+ * where it resolves — inside the skill (relative) or outside (absolute) —
57
+ * not by its link text, so `assets -> ../foo-assets` in two copies that
58
+ * point at different folders does not count as identical. */
59
+ export declare function hashSkillFolder(dir: string, normalizeSkillMd?: (text: string) => string): string;
60
+ export interface SkillFrontmatter {
61
+ name?: string;
62
+ description?: string;
63
+ }
64
+ /** Minimal YAML frontmatter reader for top-level `name` / `description`,
65
+ * including folded (`>`) and literal (`|`) block scalars. */
66
+ export declare function parseSkillFrontmatter(content: string): SkillFrontmatter | null;
67
+ /** Run the checks (and fixes when `opts.fix`). Pure apart from `--fix`. */
68
+ export declare function runDoctor(opts?: DoctorOptions): DoctorReport;
69
+ export declare function doctorCommand(opts: DoctorOptions): Promise<void>;