dsh-skills-anywhere 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/cli.js ADDED
@@ -0,0 +1,501 @@
1
+ #!/usr/bin/env node
2
+ import { a as readSourcesFile, b as projectSourcesFile, d as findProjectRoot, g as AGENTS, i as readLock, l as writeSourcesFile, o as resolveSource, r as hasGit, s as sameRepository, t as SkillsAnywhereProvider, x as resolveConfig } from "./provider-C8Jncd8r.js";
3
+ import { isAbsolute, relative, sep } from "node:path";
4
+ import { parseArgs } from "node:util";
5
+ //#region src/cli.ts
6
+ /**
7
+ * `dsh-skills-anywhere` command line: inspect what the provider would give
8
+ * dsh, manage git sources, and diagnose skipped skills — without booting dsh.
9
+ *
10
+ * @module
11
+ */
12
+ const HELP = `dsh-skills-anywhere — your skills, anywhere.
13
+
14
+ Usage: dsh-skills-anywhere <command> [options]
15
+
16
+ Commands
17
+ list Skills the provider would publish to dsh (default)
18
+ agents Supported agents and which directories exist here
19
+ sources Configured git sources and their synced commits
20
+ add <source> Add a git source (owner/repo, owner/repo/sub/dir,
21
+ https://github.com/o/r/tree/main/dir, git URL, or path)
22
+ remove <source> Remove a git source
23
+ sync Clone or refresh every source now
24
+ doctor Explain skipped, repaired, and duplicate skills
25
+ mcp Serve the same skills to any MCP client over stdio
26
+
27
+ Options
28
+ --cwd <dir> Project directory (default: current directory)
29
+ --project add/remove: use <project>/.dsh/skills-anywhere.json
30
+ --ref <ref> add: branch, tag, or commit
31
+ --path <dir> add: sub-directory inside the repository
32
+ --rank <n> add: precedence rank inside dsh (lower wins)
33
+ --force sync: refresh even when pinned to a commit
34
+ --all list: include dropped duplicates
35
+ --json Machine-readable output
36
+ -h, --help Show this help
37
+ `;
38
+ async function main(argv = process.argv.slice(2)) {
39
+ let parsed;
40
+ try {
41
+ parsed = parseArgs({
42
+ args: [...argv],
43
+ allowPositionals: true,
44
+ options: {
45
+ cwd: { type: "string" },
46
+ json: {
47
+ type: "boolean",
48
+ default: false
49
+ },
50
+ all: {
51
+ type: "boolean",
52
+ default: false
53
+ },
54
+ project: {
55
+ type: "boolean",
56
+ default: false
57
+ },
58
+ force: {
59
+ type: "boolean",
60
+ default: false
61
+ },
62
+ ref: { type: "string" },
63
+ path: { type: "string" },
64
+ rank: { type: "string" },
65
+ help: {
66
+ type: "boolean",
67
+ short: "h",
68
+ default: false
69
+ }
70
+ }
71
+ });
72
+ } catch (error) {
73
+ console.error(String(error instanceof Error ? error.message : error));
74
+ console.error(HELP);
75
+ return 2;
76
+ }
77
+ if (parsed.values.help) {
78
+ console.log(HELP);
79
+ return 0;
80
+ }
81
+ const [command = "list", ...positional] = parsed.positionals;
82
+ const cli = {
83
+ command,
84
+ positional,
85
+ cwd: parsed.values.cwd ?? process.cwd(),
86
+ json: parsed.values.json ?? false,
87
+ all: parsed.values.all ?? false,
88
+ project: parsed.values.project ?? false,
89
+ force: parsed.values.force ?? false,
90
+ ...parsed.values.ref !== void 0 ? { ref: parsed.values.ref } : {},
91
+ ...parsed.values.path !== void 0 ? { path: parsed.values.path } : {},
92
+ ...parsed.values.rank !== void 0 ? { rank: Number(parsed.values.rank) } : {}
93
+ };
94
+ const config = resolveConfig({
95
+ watch: false,
96
+ sync: false
97
+ });
98
+ switch (command) {
99
+ case "list": return await list(cli, config);
100
+ case "agents": return agents(cli, config);
101
+ case "sources": return await sources(cli, config);
102
+ case "add": return await add(cli, config);
103
+ case "remove":
104
+ case "rm": return await remove(cli, config);
105
+ case "sync": return await sync(cli, config);
106
+ case "doctor": return await doctor(cli, config);
107
+ case "mcp": return await mcp(cli);
108
+ default:
109
+ console.error(`unknown command "${command}"\n`);
110
+ console.error(HELP);
111
+ return 2;
112
+ }
113
+ }
114
+ function logger() {
115
+ return {
116
+ info: (message) => console.error(message),
117
+ warn: (message) => console.error(message)
118
+ };
119
+ }
120
+ async function collect(cli, config) {
121
+ return (await collectWithSources(cli, config)).report;
122
+ }
123
+ /** One discovery pass plus the resolved git sources, so paths inside a source checkout can be shown repo-relative. */
124
+ async function collectWithSources(cli, config) {
125
+ const provider = new SkillsAnywhereProvider(config, logger());
126
+ try {
127
+ await provider.list({ cwd: cli.cwd });
128
+ return {
129
+ report: provider.report() ?? {
130
+ skills: [],
131
+ dropped: [],
132
+ invalid: [],
133
+ roots: [],
134
+ complete: true
135
+ },
136
+ sourceDirs: (await provider.sources(cli.cwd)).map((source) => source.dir)
137
+ };
138
+ } finally {
139
+ await provider.dispose();
140
+ }
141
+ }
142
+ /** `~`-shortened path, or the path inside its git source checkout (the FROM column already names the repo). */
143
+ function displayPath(path, config, sourceDirs) {
144
+ return sourceDirs.map((dir) => relative(dir, path)).filter((rel) => rel !== "" && !rel.startsWith("..") && !isAbsolute(rel)).toSorted((a, b) => a.length - b.length)[0] ?? shorten(path, config.home);
145
+ }
146
+ function originLabel(skill) {
147
+ const { origin } = skill;
148
+ switch (origin.kind) {
149
+ case "agent": return `${origin.agent ?? "agent"} (${origin.scope ?? "?"})`;
150
+ case "claude-plugins": return `claude plugin ${origin.plugin ?? "?"}${origin.marketplace !== void 0 ? ` @ ${origin.marketplace}` : ""}`;
151
+ case "source": return `source ${origin.repo ?? "?"}`;
152
+ default: return `custom (${origin.scope ?? "?"})`;
153
+ }
154
+ }
155
+ function table(rows) {
156
+ if (rows.length === 0) return "";
157
+ const widths = rows[0].map((_, column) => Math.max(...rows.map((row) => (row[column] ?? "").length)));
158
+ return rows.map((row) => row.map((cell, column) => cell.padEnd(widths[column] ?? 0)).join(" ").trimEnd()).join("\n");
159
+ }
160
+ async function list(cli, config) {
161
+ const { report, sourceDirs } = await collectWithSources(cli, config);
162
+ if (cli.json) {
163
+ console.log(JSON.stringify({
164
+ skills: report.skills.map((skill) => ({
165
+ name: skill.name,
166
+ description: skill.description,
167
+ source: skill.source,
168
+ rank: skill.rank,
169
+ path: skill.path,
170
+ origin: skill.origin,
171
+ warnings: skill.warnings
172
+ })),
173
+ ...cli.all ? { dropped: report.dropped.map((entry) => ({
174
+ name: entry.skill.name,
175
+ path: entry.skill.path,
176
+ reason: entry.reason,
177
+ winner: entry.winner.path
178
+ })) } : {},
179
+ invalid: report.invalid.map((entry) => ({
180
+ path: entry.path,
181
+ reason: entry.reason
182
+ })),
183
+ complete: report.complete
184
+ }, null, 2));
185
+ return 0;
186
+ }
187
+ if (report.skills.length === 0) console.log("No skills found outside the dsh defaults. Try: dsh-skills-anywhere add anthropics/skills");
188
+ else console.log(table([[
189
+ "NAME",
190
+ "FROM",
191
+ "PATH"
192
+ ], ...report.skills.map((skill) => [
193
+ skill.name,
194
+ originLabel(skill),
195
+ displayPath(skill.path, config, sourceDirs)
196
+ ])]));
197
+ if (cli.all && report.dropped.length > 0) {
198
+ console.log(`\nDropped duplicates (${report.dropped.length}):`);
199
+ console.log(table(report.dropped.map((entry) => [
200
+ entry.skill.name,
201
+ entry.reason,
202
+ shorten(entry.skill.path, config.home),
203
+ `-> ${shorten(entry.winner.path, config.home)}`
204
+ ])));
205
+ }
206
+ const renamed = report.skills.filter(isRenamed).length;
207
+ const repaired = report.skills.filter((skill) => skill.warnings.length > 0 && !isRenamed(skill)).length;
208
+ console.log(`\n${report.skills.length} skills` + (report.dropped.length > 0 ? `, ${report.dropped.length} duplicates hidden` : "") + (report.invalid.length > 0 ? `, ${report.invalid.length} skipped` : "") + (renamed > 0 ? `, ${renamed} renamed` : "") + (repaired > 0 ? `, ${repaired} repaired` : "") + (report.invalid.length + repaired + renamed > 0 ? " — run `dsh-skills-anywhere doctor` for details" : ""));
209
+ return 0;
210
+ }
211
+ function isRenamed(skill) {
212
+ return typeof skill.metadata.skillsAnywhere?.renamedFrom === "string";
213
+ }
214
+ async function agents(cli, config) {
215
+ const provider = new SkillsAnywhereProvider(config, logger());
216
+ try {
217
+ const roots = await provider.roots(cli.cwd);
218
+ const existing = new Set((await collect(cli, config)).roots.filter((root) => root.exists).map((root) => root.root.path));
219
+ const rows = AGENTS.map((agent) => {
220
+ const projectRoot = roots.find((root) => root.origin.kind === "agent" && root.origin.agent === agent.id && root.origin.scope === "project");
221
+ const userRoot = roots.find((root) => root.origin.kind === "agent" && root.origin.agent === agent.id && root.origin.scope === "user");
222
+ return {
223
+ id: agent.id,
224
+ label: agent.label,
225
+ project: agent.project ?? null,
226
+ user: agent.user !== void 0 ? `~/${agent.user}` : null,
227
+ present: projectRoot !== void 0 && existing.has(projectRoot.path) || userRoot !== void 0 && existing.has(userRoot.path)
228
+ };
229
+ });
230
+ if (cli.json) console.log(JSON.stringify(rows, null, 2));
231
+ else {
232
+ console.log(table([[
233
+ "AGENT",
234
+ "ID",
235
+ "PROJECT DIR",
236
+ "USER DIR",
237
+ "FOUND HERE"
238
+ ], ...rows.map((row) => [
239
+ row.label,
240
+ row.id,
241
+ row.project ?? "-",
242
+ row.user ?? "-",
243
+ row.present ? "yes" : ""
244
+ ])]));
245
+ console.log(`\n${rows.length} agents supported; ${rows.filter((row) => row.present).length} have a skills directory on this machine.`);
246
+ console.log("(.agents/skills and .dsh/skills are handled by the built-in dsh provider.)");
247
+ }
248
+ return 0;
249
+ } finally {
250
+ await provider.dispose();
251
+ }
252
+ }
253
+ async function sources(cli, config) {
254
+ const provider = new SkillsAnywhereProvider(config, logger());
255
+ try {
256
+ const resolved = await provider.sources(cli.cwd);
257
+ const lock = await readLock(config.lockFile);
258
+ if (cli.json) {
259
+ console.log(JSON.stringify(resolved.map((source) => ({
260
+ ...source,
261
+ lock: lock[source.key] ?? null
262
+ })), null, 2));
263
+ return 0;
264
+ }
265
+ if (resolved.length === 0) {
266
+ console.log("No git sources configured. Add one with: dsh-skills-anywhere add owner/repo");
267
+ return 0;
268
+ }
269
+ console.log(table([[
270
+ "SOURCE",
271
+ "REF",
272
+ "SYNCED COMMIT",
273
+ "CACHE"
274
+ ], ...resolved.map((source) => [
275
+ source.display,
276
+ source.ref ?? "(default)",
277
+ lock[source.key]?.sha.slice(0, 12) ?? "(never)",
278
+ shorten(source.dir, config.home)
279
+ ])]));
280
+ console.log(`\nuser file: ${shorten(config.userSourcesFile, config.home)}`);
281
+ console.log(`project file: ${shorten(projectSourcesFile(await findProjectRoot(cli.cwd)), config.home)}`);
282
+ return 0;
283
+ } finally {
284
+ await provider.dispose();
285
+ }
286
+ }
287
+ async function targetFile(cli, config) {
288
+ return cli.project ? projectSourcesFile(await findProjectRoot(cli.cwd)) : config.userSourcesFile;
289
+ }
290
+ async function add(cli, config) {
291
+ const input = cli.positional[0];
292
+ if (input === void 0) {
293
+ console.error("usage: dsh-skills-anywhere add <source> [--ref <ref>] [--path <dir>] [--rank <n>] [--project]");
294
+ return 2;
295
+ }
296
+ const spec = {
297
+ repo: input,
298
+ ...cli.ref !== void 0 ? { ref: cli.ref } : {},
299
+ ...cli.path !== void 0 ? { path: cli.path } : {},
300
+ ...cli.rank !== void 0 && Number.isFinite(cli.rank) ? { rank: cli.rank } : {}
301
+ };
302
+ let resolved;
303
+ try {
304
+ resolved = resolveSource(spec, config.cacheDir);
305
+ } catch (error) {
306
+ console.error(String(error instanceof Error ? error.message : error));
307
+ return 2;
308
+ }
309
+ const file = await targetFile(cli, config);
310
+ const existing = await readSourcesFile(file);
311
+ if (existing.some((entry) => sameSourcePath(entry, resolved, config.cacheDir))) {
312
+ console.log(`${resolved.display} is already in ${shorten(file, config.home)}`);
313
+ return 0;
314
+ }
315
+ await writeSourcesFile(file, [...existing, spec]);
316
+ console.log(`added ${resolved.display} to ${shorten(file, config.home)}`);
317
+ if (!await hasGit()) {
318
+ console.error("git was not found on PATH; the source will sync once git is installed.");
319
+ return 0;
320
+ }
321
+ const provider = new SkillsAnywhereProvider(config, logger());
322
+ try {
323
+ const mine = (await provider.syncAll(cli.cwd)).find((result) => result.source.id === resolved.id);
324
+ if (mine !== void 0) printSync([mine], config);
325
+ const fromSource = (await collectWith(provider, cli)).skills.filter((skill) => skill.origin.kind === "source" && skill.origin.repo === resolved.display);
326
+ console.log(`${fromSource.length} skills available from ${resolved.display}`);
327
+ return mine?.status === "failed" ? 1 : 0;
328
+ } finally {
329
+ await provider.dispose();
330
+ }
331
+ }
332
+ async function collectWith(provider, cli) {
333
+ await provider.list({ cwd: cli.cwd });
334
+ return provider.report() ?? {
335
+ skills: [],
336
+ dropped: [],
337
+ invalid: [],
338
+ roots: [],
339
+ complete: true
340
+ };
341
+ }
342
+ /** Same repository and same sub-path, comparing resolved values so `o/r/sub` and `{ repo: 'o/r', path: 'sub' }` match. */
343
+ function sameSourcePath(entry, resolved, cacheDir) {
344
+ try {
345
+ const other = resolveSource(entry, cacheDir);
346
+ return other.id === resolved.id && (other.path ?? "") === (resolved.path ?? "");
347
+ } catch {
348
+ return false;
349
+ }
350
+ }
351
+ async function remove(cli, config) {
352
+ const input = cli.positional[0];
353
+ if (input === void 0) {
354
+ console.error("usage: dsh-skills-anywhere remove <source> [--project]");
355
+ return 2;
356
+ }
357
+ const file = await targetFile(cli, config);
358
+ const existing = await readSourcesFile(file);
359
+ const remaining = existing.filter((entry) => !sameRepository(entry, input, config.cacheDir));
360
+ if (remaining.length === existing.length) {
361
+ console.error(`${input} is not listed in ${shorten(file, config.home)}`);
362
+ return 1;
363
+ }
364
+ await writeSourcesFile(file, remaining);
365
+ console.log(`removed ${input} from ${shorten(file, config.home)} (cached checkout kept under ${shorten(config.cacheDir, config.home)})`);
366
+ return 0;
367
+ }
368
+ async function sync(cli, config) {
369
+ const provider = new SkillsAnywhereProvider(config, logger());
370
+ try {
371
+ const results = await provider.syncAll(cli.cwd, { force: cli.force });
372
+ if (cli.json) console.log(JSON.stringify(results.map((result) => ({
373
+ source: result.source.display,
374
+ status: result.status,
375
+ sha: result.sha ?? null,
376
+ error: result.error ?? null
377
+ })), null, 2));
378
+ else if (results.length === 0) console.log("No git sources configured.");
379
+ else printSync(results, config);
380
+ return results.some((result) => result.status === "failed") ? 1 : 0;
381
+ } finally {
382
+ await provider.dispose();
383
+ }
384
+ }
385
+ function printSync(results, _config) {
386
+ console.log(table([[
387
+ "SOURCE",
388
+ "STATUS",
389
+ "COMMIT"
390
+ ], ...results.map((result) => [
391
+ result.source.display,
392
+ result.status,
393
+ result.sha?.slice(0, 12) ?? result.error ?? ""
394
+ ])]));
395
+ }
396
+ async function doctor(cli, config) {
397
+ const report = await collect(cli, config);
398
+ const git = await hasGit();
399
+ if (cli.json) {
400
+ console.log(JSON.stringify({
401
+ git,
402
+ roots: report.roots.map((root) => ({
403
+ label: root.root.label,
404
+ path: root.root.path,
405
+ exists: root.exists,
406
+ count: root.count
407
+ })),
408
+ renamed: report.skills.filter(isRenamed).map((skill) => ({
409
+ name: skill.name,
410
+ from: skill.metadata.skillsAnywhere.renamedFrom,
411
+ path: skill.path
412
+ })),
413
+ repaired: report.skills.filter((skill) => skill.warnings.length > 0 && !isRenamed(skill)).map((skill) => ({
414
+ name: skill.name,
415
+ path: skill.path,
416
+ warnings: skill.warnings
417
+ })),
418
+ invalid: report.invalid.map((entry) => ({
419
+ path: entry.path,
420
+ reason: entry.reason
421
+ })),
422
+ dropped: report.dropped.map((entry) => ({
423
+ name: entry.skill.name,
424
+ path: entry.skill.path,
425
+ reason: entry.reason,
426
+ winner: entry.winner.path
427
+ })),
428
+ complete: report.complete
429
+ }, null, 2));
430
+ return 0;
431
+ }
432
+ console.log(`git: ${git ? "available" : "NOT FOUND (git sources disabled)"}`);
433
+ console.log(`state: ${shorten(config.stateDir, config.home)}`);
434
+ const present = report.roots.filter((root) => root.exists);
435
+ console.log(`\nRoots present (${present.length} of ${report.roots.length}):`);
436
+ console.log(table(present.map((root) => [
437
+ root.root.label,
438
+ String(root.count).padStart(3),
439
+ shorten(root.root.path, config.home)
440
+ ])));
441
+ const renamed = report.skills.filter(isRenamed);
442
+ if (renamed.length > 0) {
443
+ console.log(`\nRenamed to avoid collisions (${renamed.length}):`);
444
+ console.log(table(renamed.map((skill) => [
445
+ skill.metadata.skillsAnywhere.renamedFrom,
446
+ `-> ${skill.name}`,
447
+ shorten(skill.path, config.home)
448
+ ])));
449
+ }
450
+ const repaired = report.skills.filter((skill) => skill.warnings.length > 0 && !isRenamed(skill));
451
+ if (repaired.length > 0) {
452
+ console.log(`\nRepaired frontmatter (${repaired.length}):`);
453
+ for (const skill of repaired) {
454
+ console.log(` ${skill.name} ${shorten(skill.path, config.home)}`);
455
+ for (const warning of skill.warnings) console.log(` - ${warning}`);
456
+ }
457
+ }
458
+ if (report.invalid.length > 0) {
459
+ console.log(`\nSkipped (${report.invalid.length}):`);
460
+ for (const entry of report.invalid) console.log(` ${shorten(entry.path, config.home)}\n - ${entry.reason}`);
461
+ }
462
+ if (report.dropped.length > 0) {
463
+ console.log(`\nHidden duplicates (${report.dropped.length}):`);
464
+ console.log(table(report.dropped.map((entry) => [
465
+ entry.skill.name,
466
+ entry.reason,
467
+ shorten(entry.skill.path, config.home),
468
+ `-> ${shorten(entry.winner.path, config.home)}`
469
+ ])));
470
+ }
471
+ if (!report.complete) console.log("\nWARNING: at least one root could not be read completely; see messages above.");
472
+ return 0;
473
+ }
474
+ async function mcp(cli) {
475
+ const { runStdio } = await import("./mcp.js");
476
+ await runStdio({
477
+ cwd: cli.cwd,
478
+ config: {
479
+ sync: true,
480
+ watch: false
481
+ }
482
+ });
483
+ return 0;
484
+ }
485
+ function shorten(path, home) {
486
+ if (path === home) return "~";
487
+ const rel = relative(home, path);
488
+ if (rel === "" || rel.startsWith("..") || isAbsolute(rel)) return path;
489
+ return `~${sep}${rel}`;
490
+ }
491
+ if ((() => {
492
+ const entry = process.argv[1];
493
+ return entry !== void 0 && /(?:^|[\\/])(?:dsh-skills-anywhere|cli(?:\.js|\.ts)?)$/.test(entry);
494
+ })()) main().then((code) => {
495
+ process.exitCode = code;
496
+ }, (error) => {
497
+ console.error(error instanceof Error ? error.stack ?? error.message : String(error));
498
+ process.exitCode = 1;
499
+ });
500
+ //#endregion
501
+ export { main };
package/lib/index.d.ts ADDED
@@ -0,0 +1,40 @@
1
+ import { A as SourceSpec, C as RankConfig, D as LockEntry, E as resolveConfig, F as readSourcesFile, I as resolveSource, L as sameRepository, M as SyncStatus, N as hasGit, O as LockFile, P as readLock, R as syncSource, S as DEFAULT_RANKS, T as projectSourcesFile, _ as normalizeSkillName, a as DiscoveredSkill, b as CatalogConfig, c as InvalidSkill, d as SkillRoot, f as discover, g as isSkillName, h as ParsedSkill, i as applyCatalogBudget, j as SyncResult, k as ResolvedSource, l as RootReport, m as ParseResult, n as ProviderLogger, o as DiscoveryReport, p as findProjectRoot, r as SkillsAnywhereProvider, s as DroppedSkill, t as CatalogState, u as SkillOrigin, v as parseSkillMarkdown, w as ResolvedConfig, x as Config, y as splitFrontmatter, z as writeSourcesFile } from "./provider-gYkY_3P9.js";
2
+ import { Context } from "@deepseek-ai/cordis";
3
+ //#region src/agents.d.ts
4
+ /**
5
+ * Where other coding agents keep their Agent Skills.
6
+ *
7
+ * The table follows the conventions catalogued by the `skills` CLI
8
+ * (https://github.com/vercel-labs/skills) and each agent's own docs. Two rows
9
+ * are deliberately absent because the shipped `@deepseek-ai/dsh-skill-filesystem`
10
+ * provider already scans them: `.agents/skills` (project and `~/.agents/skills`)
11
+ * and `.dsh/skills`. Re-scanning them here would only produce duplicates.
12
+ *
13
+ * `project` is relative to the project root (nearest ancestor with `.git`, else
14
+ * the cwd). `user` is relative to the home directory. Either may be absent.
15
+ *
16
+ * @module
17
+ */
18
+ interface AgentSpec {
19
+ /** Stable identifier, usable in `excludeAgents`. */
20
+ readonly id: string;
21
+ /** Human-readable product name. */
22
+ readonly label: string;
23
+ /** Project-level skills directory, relative to the project root. */
24
+ readonly project?: string;
25
+ /** User-level skills directory, relative to the home directory. */
26
+ readonly user?: string;
27
+ }
28
+ export declare const AGENTS: readonly AgentSpec[];
29
+ /** Look up one agent by id. */
30
+ export declare function agentById(id: string): AgentSpec | undefined;
31
+ //#endregion
32
+ //#region src/index.d.ts
33
+ /** Cordis plugin name; stable across releases. */
34
+ export declare const name = "skills-anywhere";
35
+ /** The skill registry must exist before the provider can register. */
36
+ export declare const inject: string[];
37
+ /** Register the skills-anywhere provider on `ctx.skills`. */
38
+ export declare function apply(ctx: Context, config?: Config): void;
39
+ //#endregion
40
+ export { type AgentSpec, type CatalogConfig, type CatalogState, Config, type Config as ConfigInput, DEFAULT_RANKS, type DiscoveredSkill, type DiscoveryReport, type DroppedSkill, type InvalidSkill, type LockEntry, type LockFile, type ParseResult, type ParsedSkill, type ProviderLogger, type RankConfig, type ResolvedConfig, type ResolvedSource, type RootReport, type SkillOrigin, type SkillRoot, SkillsAnywhereProvider, type SourceSpec, type SyncResult, type SyncStatus, applyCatalogBudget, discover, findProjectRoot, hasGit, isSkillName, normalizeSkillName, parseSkillMarkdown, projectSourcesFile, readLock, readSourcesFile, resolveConfig, resolveSource, sameRepository, splitFrontmatter, syncSource, writeSourcesFile };
package/lib/index.js ADDED
@@ -0,0 +1,25 @@
1
+ import { _ as agentById, a as readSourcesFile, b as projectSourcesFile, c as syncSource, d as findProjectRoot, f as isSkillName, g as AGENTS, h as splitFrontmatter, i as readLock, l as writeSourcesFile, m as parseSkillMarkdown, n as applyCatalogBudget, o as resolveSource, p as normalizeSkillName, r as hasGit, s as sameRepository, t as SkillsAnywhereProvider, u as discover, v as Config, x as resolveConfig, y as DEFAULT_RANKS } from "./provider-C8Jncd8r.js";
2
+ //#region src/index.ts
3
+ /** Cordis plugin name; stable across releases. */
4
+ const name = "skills-anywhere";
5
+ /** The skill registry must exist before the provider can register. */
6
+ const inject = ["skills"];
7
+ /** Register the skills-anywhere provider on `ctx.skills`. */
8
+ function apply(ctx, config = {}) {
9
+ const resolved = resolveConfig(config);
10
+ let provider;
11
+ ctx.skills.registerProvider((control) => {
12
+ provider = new SkillsAnywhereProvider(resolved, {
13
+ info: (message) => ctx.logger.info(message),
14
+ warn: (message) => ctx.logger.warn(message),
15
+ debug: (message) => ctx.logger.debug(message)
16
+ }, control);
17
+ return provider;
18
+ });
19
+ ctx.effect(() => () => {
20
+ provider.dispose();
21
+ }, "skills-anywhere provider");
22
+ ctx.logger.info(`skills-anywhere: provider "${resolved.providerName}" registered (agents=${resolved.agents}, claudePlugins=${resolved.claudePlugins}, sources=${resolved.sources.length}${resolved.sourcesFiles ? "+files" : ""})`);
23
+ }
24
+ //#endregion
25
+ export { AGENTS, Config, DEFAULT_RANKS, SkillsAnywhereProvider, agentById, apply, applyCatalogBudget, discover, findProjectRoot, hasGit, inject, isSkillName, name, normalizeSkillName, parseSkillMarkdown, projectSourcesFile, readLock, readSourcesFile, resolveConfig, resolveSource, sameRepository, splitFrontmatter, syncSource, writeSourcesFile };
package/lib/mcp.d.ts ADDED
@@ -0,0 +1,48 @@
1
+ import { a as DiscoveredSkill, n as ProviderLogger, o as DiscoveryReport, r as SkillsAnywhereProvider, w as ResolvedConfig, x as Config } from "./provider-gYkY_3P9.js";
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ //#region src/mcp.d.ts
4
+ export interface McpOptions {
5
+ /** Project directory that selects project-level skill roots and sources. */
6
+ readonly cwd?: string;
7
+ /** Provider configuration; defaults follow the dsh plugin defaults. */
8
+ readonly config?: Config | ResolvedConfig;
9
+ /** Where diagnostics go. Defaults to stderr, which stdio MCP clients ignore. */
10
+ readonly log?: ProviderLogger;
11
+ /** How long one discovery pass is reused before rescanning (ms). */
12
+ readonly cacheMs?: number;
13
+ /** Default `find_skills` result count. */
14
+ readonly findLimit?: number;
15
+ /** Hard cap for `find_skills` and `list_skills` result counts. */
16
+ readonly maxLimit?: number;
17
+ }
18
+ export interface SkillsAnywhereMcp {
19
+ readonly server: McpServer;
20
+ readonly provider: SkillsAnywhereProvider;
21
+ /** Discover (or reuse the cached pass) and return the current pool. */
22
+ refresh(force?: boolean): Promise<DiscoveryReport>;
23
+ /** Close the transport and release watchers and timers. */
24
+ close(): Promise<void>;
25
+ }
26
+ export interface OpenedSkill {
27
+ readonly name: string;
28
+ readonly description: string;
29
+ readonly directory: string;
30
+ readonly path: string;
31
+ readonly source: string;
32
+ readonly content: string;
33
+ }
34
+ export declare function packageVersion(): string;
35
+ /** Skills the author allows a model to invoke, in catalog order. */
36
+ export declare function modelSkills(report: DiscoveryReport): DiscoveredSkill[];
37
+ /**
38
+ * Render a skill the way dsh hands it to its model, so clients that already
39
+ * understand `<skill_content>` blocks see a familiar shape.
40
+ */
41
+ export declare function renderSkill(skill: Pick<OpenedSkill, 'name' | 'directory' | 'content'>): string;
42
+ /** Re-read a discovered skill from disk so edits since discovery are honoured. */
43
+ export declare function openSkill(skill: DiscoveredSkill, lenient: boolean): Promise<OpenedSkill | undefined>;
44
+ /** Build a server over a standalone provider. Nothing is connected yet. */
45
+ export declare function createSkillsAnywhereServer(options?: McpOptions): SkillsAnywhereMcp;
46
+ /** Serve over stdio until the client disconnects; resolves when closed. */
47
+ export declare function runStdio(options?: McpOptions): Promise<void>;
48
+ //#endregion