skillmds 1.0.21 → 1.1.1

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/bin/skillmd.mjs CHANGED
File without changes
package/dist/cli.js CHANGED
@@ -1,314 +1,17 @@
1
- // ../cli/src/index.ts
1
+ // src/index.ts
2
2
  import { Command as Command13 } from "commander";
3
3
  import { readFileSync as readFileSync4 } from "fs";
4
4
 
5
- // ../cli/src/commands/lint.ts
5
+ // src/commands/lint.ts
6
6
  import { Command } from "commander";
7
7
  import { writeFileSync } from "fs";
8
8
  import { homedir } from "os";
9
9
  import { resolve } from "path";
10
10
  import pc2 from "picocolors";
11
11
  import * as p from "@clack/prompts";
12
+ import { lint, toJson, toSarif, toGithub } from "@skillmds/core";
12
13
 
13
- // ../../packages/core/src/parse.ts
14
- import { parse as parseYaml } from "yaml";
15
- var MAX_SKILL_BYTES = 256 * 1024;
16
- var MAX_DESCRIPTION = 1024;
17
- var MAX_NAME = 120;
18
- var slugify = (s) => String(s).toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60) || "skill";
19
- function parseSkillMd(raw, type = "single") {
20
- if (!raw || raw.length > MAX_SKILL_BYTES) return { error: "SKILL.md missing or too large (max 256KB)" };
21
- const m = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
22
- if (!m) return { error: "Missing YAML frontmatter (--- ... ---)" };
23
- let fm;
24
- try {
25
- fm = parseYaml(m[1] ?? "") ?? {};
26
- } catch {
27
- return { error: "Invalid YAML frontmatter" };
28
- }
29
- const name = String(fm.name ?? "").trim();
30
- const description = String(fm.description ?? "").replace(/\s+/g, " ").trim();
31
- if (!name) return { error: "frontmatter 'name' is required" };
32
- if (!description) return { error: "frontmatter 'description' is required" };
33
- if (description.length > MAX_DESCRIPTION) return { error: `description must be <= ${MAX_DESCRIPTION} chars` };
34
- return {
35
- name: name.slice(0, MAX_NAME),
36
- description: description.slice(0, MAX_DESCRIPTION),
37
- license: fm.license ? String(fm.license).slice(0, 64) : null,
38
- body: m[2] ?? "",
39
- type
40
- };
41
- }
42
-
43
- // ../../packages/core/src/security.ts
44
- var UNTRUSTED_INSTALL_RE = new RegExp(
45
- [
46
- /(?:npx|npm|yarn|pnpm|bun)\b[^\n]*--registry[= ]/.source,
47
- // custom npm registry
48
- /npm\s+config\s+set\s+registry/.source,
49
- /pip3?\s+install\b[^\n]*(?:--index-url|--extra-index-url|-i\s+https?:)/.source,
50
- // custom pip index
51
- /(?:curl|wget)\b[^\n|]*\|\s*(?:sudo\s+)?(?:ba|z|fi)?sh\b/.source,
52
- // curl … | sh
53
- /(?:iwr|irm|invoke-webrequest|invoke-restmethod)\b[^\n|]*\|\s*iex\b/.source,
54
- // PowerShell pipe-to-exec
55
- /bash\s+<\(\s*(?:curl|wget)/.source,
56
- // bash <(curl …)
57
- /(?:pip3?|npm|npx)\s+(?:install|--yes|-y)?\s*[^\n]*https?:\/\/(?!registry\.npmjs\.org|pypi\.org|files\.pythonhosted\.org)[^\s'"`]+\.(?:whl|tar\.gz|tgz|zip)\b/.source
58
- // install from raw archive URL
59
- ].join("|"),
60
- "i"
61
- );
62
- var RULES = [
63
- ["untrusted_install", UNTRUSTED_INSTALL_RE],
64
- ["executes_scripts", /```(?:sh|bash|python|py|js|ts|ruby|rb)\b|\b(subprocess|os\.system|child_process|exec\()/i],
65
- ["network_calls", /\b(fetch|requests\.|urllib|axios|curl|wget|https?:\/\/|websocket)\b/i],
66
- ["reads_secrets", /\b(api[_-]?key|secret|token|password|os\.environ|process\.env|getenv)\b/i]
67
- ];
68
- function scanSecurity(body) {
69
- const findings = [];
70
- body.split(/\r?\n/).forEach((text3, i) => {
71
- for (const [flag, re] of RULES) {
72
- if (re.test(text3)) findings.push({ flag, line: i + 1, snippet: text3.trim().slice(0, 120) });
73
- }
74
- });
75
- const flags = [...new Set(findings.map((f) => f.flag))];
76
- return { flags: flags.length ? flags : ["docs_only"], findings };
77
- }
78
-
79
- // ../../packages/core/src/rules.ts
80
- function utf8Bytes(s) {
81
- let bytes = 0;
82
- for (let i = 0; i < s.length; i++) {
83
- const c = s.charCodeAt(i);
84
- if (c < 128) bytes += 1;
85
- else if (c < 2048) bytes += 2;
86
- else if (c >= 55296 && c <= 56319) {
87
- bytes += 4;
88
- i++;
89
- } else bytes += 3;
90
- }
91
- return bytes;
92
- }
93
- var diag = (rule, message, line) => ({
94
- id: rule.id,
95
- severity: rule.severity,
96
- message,
97
- ...line !== void 0 ? { line } : {}
98
- });
99
- var RULES2 = [
100
- {
101
- id: "SK002",
102
- severity: "error",
103
- description: "name must be present and \u2264 120 chars",
104
- check(s, _ctx) {
105
- const out = [];
106
- if (!s.name.trim()) out.push(diag(this, "frontmatter 'name' is required"));
107
- else if (s.name.length > MAX_NAME) out.push(diag(this, `name must be \u2264 ${MAX_NAME} chars`));
108
- return out;
109
- }
110
- },
111
- {
112
- id: "SK003",
113
- severity: "error",
114
- description: "description must be present and \u2264 1024 chars",
115
- check(s, _ctx) {
116
- const out = [];
117
- if (!s.description.trim()) out.push(diag(this, "frontmatter 'description' is required"));
118
- else if (s.description.length > MAX_DESCRIPTION) out.push(diag(this, `description must be \u2264 ${MAX_DESCRIPTION} chars`));
119
- return out;
120
- }
121
- },
122
- {
123
- id: "SK010",
124
- severity: "warn",
125
- description: "description should be \u2265 20 chars (not too terse)",
126
- check(s, _ctx) {
127
- return s.description.trim().length > 0 && s.description.trim().length < 20 ? [diag(this, "description is very terse (< 20 chars); add more detail to help discovery")] : [];
128
- }
129
- },
130
- {
131
- id: "SK011",
132
- severity: "warn",
133
- description: "license should be declared in frontmatter",
134
- check(s, _ctx) {
135
- return s.license ? [] : [diag(this, "no 'license' declared in frontmatter")];
136
- }
137
- },
138
- {
139
- id: "SK020",
140
- severity: "warn",
141
- description: "body should be \u2265 200 chars (not a stub)",
142
- check(s, _ctx) {
143
- return s.body.trim().length < 200 ? [diag(this, "body is very short (< 200 chars); this looks like a stub")] : [];
144
- }
145
- },
146
- {
147
- id: "SK021",
148
- severity: "warn",
149
- description: "body should contain at least one Markdown heading",
150
- check(s, _ctx) {
151
- return /^#{1,6}\s/m.test(s.body) ? [] : [diag(this, "body has no Markdown headings; add structure with '#' headings")];
152
- }
153
- },
154
- {
155
- id: "SK030",
156
- severity: "error",
157
- description: "total SKILL.md size must be \u2264 256KB",
158
- check(s, _ctx) {
159
- return utf8Bytes(s.body) > MAX_SKILL_BYTES ? [diag(this, "SKILL.md exceeds 256KB")] : [];
160
- }
161
- },
162
- {
163
- id: "SK040",
164
- severity: "warn",
165
- description: "name should match its directory/slug",
166
- check(s, ctx) {
167
- if (!ctx.slug) return [];
168
- const expected = slugify(s.name);
169
- return expected === ctx.slug ? [] : [diag(this, `name slug '${expected}' does not match directory '${ctx.slug}'`)];
170
- }
171
- }
172
- ];
173
- function runRules(skill, ctx = {}) {
174
- return RULES2.flatMap((r) => r.check(skill, ctx));
175
- }
176
-
177
- // ../../packages/core/src/quality.ts
178
- var WEIGHT = {
179
- error: 30,
180
- warn: 10,
181
- info: 3
182
- };
183
- var RISK = {
184
- docs_only: 0,
185
- reads_secrets: 2,
186
- network_calls: 1,
187
- executes_scripts: 5,
188
- // fetch-and-execute from a non-standard source — the supply-chain pattern the
189
- // AI verdict floors to "warning"; the heaviest penalty here for the same reason
190
- untrusted_install: 15
191
- };
192
- var VERIFIED_FLOOR = 85;
193
- function qualityScore(diagnostics, security, opts = {}) {
194
- let penalty = diagnostics.reduce((sum, d) => sum + WEIGHT[d.severity], 0);
195
- if (security) {
196
- for (const flag of security.flags) penalty += RISK[flag] ?? 0;
197
- }
198
- const score = Math.max(0, Math.min(100, 100 - penalty));
199
- const hasError = diagnostics.some((d) => d.severity === "error");
200
- return opts.verified && !hasError ? Math.max(score, VERIFIED_FLOOR) : score;
201
- }
202
-
203
- // ../../packages/core/src/lint.ts
204
- function lint(raw, opts = {}) {
205
- const parsed = parseSkillMd(raw, opts.type ?? "single");
206
- if ("error" in parsed) {
207
- const diagnostics2 = [{ id: "SK001", severity: "error", message: parsed.error }];
208
- const security2 = scanSecurity(raw);
209
- return {
210
- ok: false,
211
- diagnostics: diagnostics2,
212
- security: security2,
213
- score: qualityScore(diagnostics2, security2, { verified: opts.verified })
214
- };
215
- }
216
- const ctx = opts.slug !== void 0 ? { slug: opts.slug } : {};
217
- const diagnostics = runRules(parsed, ctx);
218
- const security = scanSecurity(parsed.body);
219
- const ok = !diagnostics.some((d) => d.severity === "error");
220
- return { ok, skill: parsed, diagnostics, security, score: qualityScore(diagnostics, security, { verified: opts.verified }) };
221
- }
222
-
223
- // ../../packages/core/src/format/text.ts
224
- var BADGE = { error: "ERROR", warn: " WARN", info: " INFO" };
225
- function toText(results, opts = {}) {
226
- const paint = opts.decorate ?? ((t) => t);
227
- const out = [];
228
- for (const { file, result } of results) {
229
- const status = result.ok ? paint("PASS", "ok") : paint("FAIL", "error");
230
- out.push(`${status} ${file} ${paint(`score ${result.score}/100`, "dim")}`);
231
- for (const d of result.diagnostics) {
232
- const where = d.line !== void 0 ? `:${d.line}` : "";
233
- out.push(` ${paint(BADGE[d.severity], d.severity)} ${d.id}${where} ${d.message}`);
234
- }
235
- if (result.security.flags.length && result.security.flags[0] !== "docs_only") {
236
- out.push(` ${paint("SEC ", "warn")} flags: ${result.security.flags.join(", ")}`);
237
- }
238
- out.push("");
239
- }
240
- const failed = results.filter((r) => !r.result.ok).length;
241
- const summary = failed === 0 ? paint(`\u2713 ${results.length} skill(s) passed`, "ok") : paint(`\u2717 ${failed}/${results.length} skill(s) failed`, "error");
242
- out.push(summary);
243
- return out.join("\n");
244
- }
245
-
246
- // ../../packages/core/src/format/json.ts
247
- function toJson(results) {
248
- return results.map(({ file, result }) => ({
249
- file,
250
- ok: result.ok,
251
- score: result.score,
252
- diagnostics: result.diagnostics,
253
- security: result.security
254
- }));
255
- }
256
-
257
- // ../../packages/core/src/format/sarif.ts
258
- var SARIF_LEVEL = { error: "error", warn: "warning", info: "note" };
259
- function toSarif(results) {
260
- const sarifResults = results.flatMap(
261
- ({ file, result }) => result.diagnostics.map((d) => ({
262
- ruleId: d.id,
263
- level: SARIF_LEVEL[d.severity] ?? "note",
264
- message: { text: d.message },
265
- locations: [
266
- {
267
- physicalLocation: {
268
- artifactLocation: { uri: file },
269
- region: { startLine: d.line ?? 1 }
270
- }
271
- }
272
- ]
273
- }))
274
- );
275
- return {
276
- $schema: "https://json.schemastore.org/sarif-2.1.0.json",
277
- version: "2.1.0",
278
- runs: [
279
- {
280
- tool: {
281
- driver: {
282
- name: "skillmd",
283
- informationUri: "https://skillmd.com",
284
- rules: RULES2.map((r) => ({
285
- id: r.id,
286
- shortDescription: { text: r.description },
287
- defaultConfiguration: { level: SARIF_LEVEL[r.severity] ?? "note" }
288
- }))
289
- }
290
- },
291
- results: sarifResults
292
- }
293
- ]
294
- };
295
- }
296
-
297
- // ../../packages/core/src/format/github.ts
298
- var LEVEL = { error: "error", warn: "warning", info: "notice" };
299
- function toGithub(results) {
300
- const lines = [];
301
- for (const { file, result } of results) {
302
- for (const d of result.diagnostics) {
303
- const level = LEVEL[d.severity] ?? "notice";
304
- const loc = d.line !== void 0 ? `,line=${d.line}` : "";
305
- lines.push(`::${level} file=${file}${loc},title=${d.id}::${d.message}`);
306
- }
307
- }
308
- return lines.join("\n");
309
- }
310
-
311
- // ../cli/src/source.ts
14
+ // src/source.ts
312
15
  import { existsSync, statSync, lstatSync, readFileSync, readdirSync, mkdtempSync, rmSync } from "fs";
313
16
  import { tmpdir } from "os";
314
17
  import { join, basename, dirname, relative, sep } from "path";
@@ -427,7 +130,7 @@ function normalizeGiget(arg) {
427
130
  return `github:${arg}`;
428
131
  }
429
132
 
430
- // ../cli/src/ui.ts
133
+ // src/ui.ts
431
134
  import pc from "picocolors";
432
135
  var decorate = (text3, kind) => {
433
136
  switch (kind) {
@@ -561,7 +264,7 @@ function exitCodeFor(results, policy = {}) {
561
264
  return 0;
562
265
  }
563
266
 
564
- // ../cli/src/commands/lint.ts
267
+ // src/commands/lint.ts
565
268
  function applyLicenseFix(raw) {
566
269
  if (/^---[\s\S]*?\blicense:\s*\S+[\s\S]*?^---/m.test(raw)) return null;
567
270
  const m = raw.match(/^(---\r?\n)([\s\S]*?)(\r?\n---)/);
@@ -633,8 +336,9 @@ function lintCommand() {
633
336
  });
634
337
  }
635
338
 
636
- // ../cli/src/commands/scan.ts
339
+ // src/commands/scan.ts
637
340
  import { Command as Command2 } from "commander";
341
+ import { scanSecurity, parseSkillMd } from "@skillmds/core";
638
342
  import pc3 from "picocolors";
639
343
  async function runScan(target, flags) {
640
344
  const resolved = await resolveSource(target);
@@ -673,12 +377,13 @@ function scanCommand() {
673
377
  });
674
378
  }
675
379
 
676
- // ../cli/src/commands/rules.ts
380
+ // src/commands/rules.ts
677
381
  import { Command as Command3 } from "commander";
382
+ import { RULES } from "@skillmds/core";
678
383
  import pc4 from "picocolors";
679
384
  function rulesCommand() {
680
385
  return new Command3("rules").description("List lint rules, or show detail for one rule id").argument("[id]", "a rule id, e.g. SK010").option("--json", "machine-readable output").action((id, opts) => {
681
- const list = id ? RULES2.filter((r) => r.id.toLowerCase() === id.toLowerCase()) : RULES2;
386
+ const list = id ? RULES.filter((r) => r.id.toLowerCase() === id.toLowerCase()) : RULES;
682
387
  if (id && list.length === 0) {
683
388
  console.error(`Unknown rule: ${id}`);
684
389
  process.exitCode = 1;
@@ -695,10 +400,11 @@ function rulesCommand() {
695
400
  });
696
401
  }
697
402
 
698
- // ../cli/src/commands/init.ts
403
+ // src/commands/init.ts
699
404
  import { Command as Command4 } from "commander";
700
405
  import { mkdirSync, writeFileSync as writeFileSync2, existsSync as existsSync2 } from "fs";
701
406
  import { join as join2 } from "path";
407
+ import { slugify } from "@skillmds/core";
702
408
  import * as p2 from "@clack/prompts";
703
409
  function skillTemplate(name, description, license) {
704
410
  const desc = description.trim() || `A skill that helps agents with ${name}.`;
@@ -756,15 +462,15 @@ function initCommand() {
756
462
  });
757
463
  }
758
464
 
759
- // ../cli/src/commands/search.ts
465
+ // src/commands/search.ts
760
466
  import { Command as Command5 } from "commander";
761
467
  import pc5 from "picocolors";
762
468
 
763
- // ../cli/src/api.ts
469
+ // src/api.ts
764
470
  import { createHash } from "crypto";
765
- import { stringify as stringifyYaml } from "yaml";
471
+ import { isAllowedSourceUrl } from "@skillmds/core";
766
472
 
767
- // ../cli/src/config.ts
473
+ // src/config.ts
768
474
  import { readFileSync as readFileSync2, writeFileSync as writeFileSync3, mkdirSync as mkdirSync2 } from "fs";
769
475
  import { homedir as homedir2 } from "os";
770
476
  import { join as join3 } from "path";
@@ -791,7 +497,8 @@ function resolveApi(flags = {}) {
791
497
  return flags.api || process.env.SKILLMD_API || readConfig().api || DEFAULT_API;
792
498
  }
793
499
 
794
- // ../cli/src/api.ts
500
+ // src/api.ts
501
+ import { isAllowedSourceUrl as isAllowedSourceUrl2, reconstructSkillMd, skillMdFor } from "@skillmds/core";
795
502
  var IntegrityError = class extends Error {
796
503
  integrity = true;
797
504
  constructor(message) {
@@ -807,15 +514,6 @@ var RegistryError = class extends Error {
807
514
  }
808
515
  status;
809
516
  };
810
- var ALLOWED_SOURCE_HOSTS = /* @__PURE__ */ new Set(["raw.githubusercontent.com", "gist.githubusercontent.com"]);
811
- function isAllowedSourceUrl(u) {
812
- try {
813
- const parsed = new URL(u);
814
- return parsed.protocol === "https:" && ALLOWED_SOURCE_HOSTS.has(parsed.hostname.toLowerCase());
815
- } catch {
816
- return false;
817
- }
818
- }
819
517
  function createClient(flags = {}) {
820
518
  const base = resolveApi(flags);
821
519
  const token = resolveToken(flags);
@@ -862,20 +560,8 @@ async function fetchBundle(base, slug, token) {
862
560
  }
863
561
  return out;
864
562
  }
865
- function skillMdFor(skill) {
866
- if (skill.raw_md) return skill.raw_md;
867
- return reconstructSkillMd(skill);
868
- }
869
- function reconstructSkillMd(skill) {
870
- const name = skill.slug.split("/")[1] || skill.title;
871
- const fm = { name, description: String(skill.description).replace(/\n/g, " ") };
872
- if (skill.license) fm.license = skill.license;
873
- return `---
874
- ${stringifyYaml(fm)}---
875
- ${skill.body_md || ""}`;
876
- }
877
563
 
878
- // ../cli/src/commands/search.ts
564
+ // src/commands/search.ts
879
565
  var MAX_LINE_WIDTH = 100;
880
566
  function formatStars(n) {
881
567
  if (n >= 1e6) {
@@ -925,7 +611,7 @@ function searchCommand() {
925
611
  });
926
612
  }
927
613
 
928
- // ../cli/src/commands/info.ts
614
+ // src/commands/info.ts
929
615
  import { Command as Command6 } from "commander";
930
616
  import pc6 from "picocolors";
931
617
  async function runInfo(slug, flags) {
@@ -974,14 +660,15 @@ function infoCommand() {
974
660
  });
975
661
  }
976
662
 
977
- // ../cli/src/commands/add.ts
663
+ // src/commands/add.ts
978
664
  import { Command as Command7, Option } from "commander";
979
665
  import { existsSync as existsSync4 } from "fs";
980
666
  import { homedir as homedir4 } from "os";
981
667
  import { resolve as resolve3 } from "path";
982
668
  import pc7 from "picocolors";
669
+ import { lint as lint2 } from "@skillmds/core";
983
670
 
984
- // ../cli/src/agents.ts
671
+ // src/agents.ts
985
672
  import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4, rmSync as rmSync2, symlinkSync, existsSync as existsSync3, readdirSync as readdirSync2, statSync as statSync2, readFileSync as readFileSync3 } from "fs";
986
673
  import { homedir as homedir3 } from "os";
987
674
  import { join as join4, resolve as resolve2, dirname as dirname2, sep as sep2 } from "path";
@@ -1106,7 +793,7 @@ function installedSkills(opts = {}) {
1106
793
  return out;
1107
794
  }
1108
795
 
1109
- // ../cli/src/commands/add.ts
796
+ // src/commands/add.ts
1110
797
  function isLocalish(arg) {
1111
798
  return arg === "." || arg.startsWith("./") || arg.startsWith("../") || arg.startsWith("/") || /^[a-zA-Z]:[\\/]/.test(arg) || existsSync4(arg);
1112
799
  }
@@ -1229,7 +916,7 @@ async function runAdd(arg, flags, deps = defaultDeps) {
1229
916
  dirAgents.set(dir, [...dirAgents.get(dir) ?? [], agentId]);
1230
917
  }
1231
918
  for (const c of candidates) {
1232
- const result = lint(c.raw, { slug: c.slug });
919
+ const result = lint2(c.raw, { slug: c.slug });
1233
920
  const allFlags = [.../* @__PURE__ */ new Set([...result.security.flags, ...c.securityFlags ?? []])];
1234
921
  const deniedFlags = allFlags.filter((f) => deny.has(f));
1235
922
  if (!flags.skipLint && !result.ok) {
@@ -1271,9 +958,10 @@ function addCommand() {
1271
958
  });
1272
959
  }
1273
960
 
1274
- // ../cli/src/commands/list.ts
961
+ // src/commands/list.ts
1275
962
  import { Command as Command8 } from "commander";
1276
963
  import pc8 from "picocolors";
964
+ import { parseSkillMd as parseSkillMd2 } from "@skillmds/core";
1277
965
  function listCommand() {
1278
966
  return new Command8("list").alias("ls").description("List installed skills across detected agents").option("-g, --global", "only global skills").option("--json", "machine-readable output").action((opts) => {
1279
967
  const scope = { global: opts.global };
@@ -1287,7 +975,7 @@ function listCommand() {
1287
975
  return;
1288
976
  }
1289
977
  for (const s of skills) {
1290
- const parsed = parseSkillMd(s.raw);
978
+ const parsed = parseSkillMd2(s.raw);
1291
979
  const desc = "error" in parsed ? pc8.red(`(invalid SKILL.md \u2014 ${parsed.error})`) : pc8.dim(parsed.description.slice(0, 80));
1292
980
  console.log(`${pc8.bold(s.name)} ${pc8.dim(`[${s.agent}/${s.scope}]`)}
1293
981
  ${desc}`);
@@ -1295,7 +983,7 @@ function listCommand() {
1295
983
  });
1296
984
  }
1297
985
 
1298
- // ../cli/src/commands/remove.ts
986
+ // src/commands/remove.ts
1299
987
  import { Command as Command9 } from "commander";
1300
988
  import { rmSync as rmSync3 } from "fs";
1301
989
  import pc9 from "picocolors";
@@ -1321,11 +1009,12 @@ function removeCommand() {
1321
1009
  });
1322
1010
  }
1323
1011
 
1324
- // ../cli/src/commands/update.ts
1012
+ // src/commands/update.ts
1325
1013
  import { Command as Command10 } from "commander";
1326
1014
  import { writeFileSync as writeFileSync5 } from "fs";
1327
1015
  import { join as join5 } from "path";
1328
1016
  import pc10 from "picocolors";
1017
+ import { lint as lint3 } from "@skillmds/core";
1329
1018
  async function runUpdate(names, flags, scope = {}) {
1330
1019
  const { api } = createClient(flags);
1331
1020
  const installed = installedSkills(scope).filter((s) => names.length === 0 || names.includes(s.name));
@@ -1345,7 +1034,7 @@ async function runUpdate(names, flags, scope = {}) {
1345
1034
  lines.push(pc10.dim(`- ${s.name} already up to date`));
1346
1035
  continue;
1347
1036
  }
1348
- const result = lint(next, { slug: s.name });
1037
+ const result = lint3(next, { slug: s.name });
1349
1038
  if (!result.ok) {
1350
1039
  lines.push(pc10.red(`\u2717 ${s.name} update failed lint \u2014 skipped`));
1351
1040
  continue;
@@ -1372,9 +1061,10 @@ function updateCommand() {
1372
1061
  });
1373
1062
  }
1374
1063
 
1375
- // ../cli/src/commands/publish.ts
1064
+ // src/commands/publish.ts
1376
1065
  import { Command as Command11 } from "commander";
1377
1066
  import pc11 from "picocolors";
1067
+ import { lint as lint4, toText } from "@skillmds/core";
1378
1068
  var defaultDeps2 = {
1379
1069
  resolve: resolveSource,
1380
1070
  async submit(payload, flags) {
@@ -1390,10 +1080,10 @@ var defaultDeps2 = {
1390
1080
  async function runPublish(target, flags, deps = defaultDeps2) {
1391
1081
  const sources = await deps.resolve(target);
1392
1082
  if (sources.length !== 1) {
1393
- return { result: lint(""), published: false, exitCode: 1, output: `Expected exactly one SKILL.md, found ${sources.length}.` };
1083
+ return { result: lint4(""), published: false, exitCode: 1, output: `Expected exactly one SKILL.md, found ${sources.length}.` };
1394
1084
  }
1395
1085
  const src = sources[0];
1396
- const result = lint(src.raw, { slug: src.slug });
1086
+ const result = lint4(src.raw, { slug: src.slug });
1397
1087
  const report = toText([{ file: src.path, result }], { decorate });
1398
1088
  if (!result.ok) {
1399
1089
  return { result, published: false, exitCode: 1, output: `${report}
@@ -1421,7 +1111,7 @@ function publishCommand() {
1421
1111
  });
1422
1112
  }
1423
1113
 
1424
- // ../cli/src/commands/login.ts
1114
+ // src/commands/login.ts
1425
1115
  import { Command as Command12 } from "commander";
1426
1116
  import * as p3 from "@clack/prompts";
1427
1117
  function loginCommand() {
@@ -1456,9 +1146,10 @@ function logoutCommand() {
1456
1146
  });
1457
1147
  }
1458
1148
 
1459
- // ../cli/src/commands/interactive.ts
1149
+ // src/commands/interactive.ts
1460
1150
  import * as p4 from "@clack/prompts";
1461
1151
  import pc12 from "picocolors";
1152
+ import { parseSkillMd as parseSkillMd3 } from "@skillmds/core";
1462
1153
  function bail(v) {
1463
1154
  if (p4.isCancel(v)) {
1464
1155
  p4.cancel("Cancelled.");
@@ -1604,7 +1295,7 @@ async function runInteractive() {
1604
1295
  } else {
1605
1296
  p4.log.message(
1606
1297
  skills.map((sk) => {
1607
- const parsed = parseSkillMd(sk.raw);
1298
+ const parsed = parseSkillMd3(sk.raw);
1608
1299
  const desc = "error" in parsed ? pc12.red(`(invalid SKILL.md \u2014 ${parsed.error})`) : pc12.dim(parsed.description.slice(0, 70));
1609
1300
  return `${pc12.bold(sk.name)} ${pc12.dim(`[${sk.agent}/${sk.scope}]`)}
1610
1301
  ${desc}`;
@@ -1635,7 +1326,7 @@ async function runInteractive() {
1635
1326
  p4.outro(pc12.dim("skillmd.com"));
1636
1327
  }
1637
1328
 
1638
- // ../cli/src/index.ts
1329
+ // src/index.ts
1639
1330
  var version = "0.0.0";
1640
1331
  try {
1641
1332
  version = JSON.parse(readFileSync4(new URL("../package.json", import.meta.url), "utf8")).version;
package/package.json CHANGED
@@ -1,12 +1,25 @@
1
1
  {
2
2
  "name": "skillmds",
3
- "version": "1.0.21",
3
+ "version": "1.1.1",
4
4
  "description": "SkillMD for agents: the `skillmds` MCP server + the `skillmd` CLI (lint, scan, search, install, publish Agent Skills) from skillmd.com.",
5
+ "license": "MIT",
6
+ "author": "SkillMD",
5
7
  "type": "module",
8
+ "mcpName": "com.skillmd/skillmd",
6
9
  "bin": {
7
10
  "skillmds": "bin/skillmd-mcp.mjs",
8
11
  "skillmd": "bin/skillmd.mjs"
9
12
  },
13
+ "files": [
14
+ "bin",
15
+ "dist",
16
+ "assets",
17
+ "README.md",
18
+ "CHANGELOG.md"
19
+ ],
20
+ "engines": {
21
+ "node": ">=18"
22
+ },
10
23
  "keywords": [
11
24
  "mcp",
12
25
  "model-context-protocol",
@@ -23,37 +36,37 @@
23
36
  "ai-agents",
24
37
  "llm"
25
38
  ],
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "git+https://github.com/skillmds/skillmd.git",
42
+ "directory": "packages/skillmds"
43
+ },
26
44
  "homepage": "https://skillmd.com",
27
45
  "bugs": {
28
- "url": "https://skillmd.com/contact"
46
+ "url": "https://github.com/skillmds/skillmd/issues"
29
47
  },
30
- "author": "SkillMD",
31
- "license": "MIT",
32
- "files": [
33
- "bin",
34
- "dist",
35
- "vendor",
36
- "assets",
37
- "README.md",
38
- "CHANGELOG.md"
39
- ],
40
- "engines": {
41
- "node": ">=18"
48
+ "publishConfig": {
49
+ "provenance": true
50
+ },
51
+ "scripts": {
52
+ "build": "tsup",
53
+ "test": "vitest run",
54
+ "typecheck": "tsc --noEmit",
55
+ "prepublishOnly": "npm run build"
42
56
  },
43
57
  "dependencies": {
44
58
  "@clack/prompts": "^0.8.0",
45
59
  "@modelcontextprotocol/sdk": "^1.13.0",
60
+ "@skillmds/core": "^1.0.0",
46
61
  "commander": "^12.1.0",
47
62
  "giget": "^3.3.0",
48
63
  "picocolors": "^1.1.0",
49
64
  "yaml": "^2.6.1"
50
65
  },
51
66
  "devDependencies": {
52
- "@skillmd/core": "*",
53
- "tsup": "^8.3.0"
54
- },
55
- "scripts": {
56
- "build": "tsup",
57
- "prepublishOnly": "tsup"
67
+ "@types/node": "^22.10.0",
68
+ "tsup": "^8.3.0",
69
+ "typescript": "^5.7.2",
70
+ "vitest": "^2.1.0"
58
71
  }
59
72
  }