@aijadugar/skyboy-core 0.1.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/LICENSE +21 -0
- package/dist/agent-context.d.ts +9 -0
- package/dist/agent-context.d.ts.map +1 -0
- package/dist/agent-context.js +66 -0
- package/dist/agent-context.js.map +1 -0
- package/dist/catalog.d.ts +31 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +91 -0
- package/dist/catalog.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/install.d.ts +16 -0
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +94 -0
- package/dist/install.js.map +1 -0
- package/dist/manifest.d.ts +6 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +53 -0
- package/dist/manifest.js.map +1 -0
- package/dist/resolve.d.ts +9 -0
- package/dist/resolve.d.ts.map +1 -0
- package/dist/resolve.js +75 -0
- package/dist/resolve.js.map +1 -0
- package/dist/search.d.ts +9 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +61 -0
- package/dist/search.js.map +1 -0
- package/dist/types.d.ts +95 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +36 -0
- package/dist/types.js.map +1 -0
- package/package.json +25 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Skyboy project contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface AgentContext {
|
|
2
|
+
agent: string;
|
|
3
|
+
targetDir: string;
|
|
4
|
+
guideSlug: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function detectAgentContext(cwd: string): AgentContext | null;
|
|
7
|
+
export declare const DEFAULT_TARGET_DIR = ".claude/skills";
|
|
8
|
+
export declare function safeSkillFolderName(slug: string): string;
|
|
9
|
+
//# sourceMappingURL=agent-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-context.d.ts","sourceRoot":"","sources":["../src/agent-context.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AA2CD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAQnE;AAKD,eAAO,MAAM,kBAAkB,mBAAmB,CAAC;AAInD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGxD"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// Detect the calling agent context so the CLI can pick a sensible target folder
|
|
2
|
+
// without a prompt. Scans the working directory for the well-known agent folders
|
|
3
|
+
// the ecosystem has converged on. Returns null when nothing is detected (caller
|
|
4
|
+
// prompts or falls back to a default).
|
|
5
|
+
import { existsSync } from "node:fs";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
// The 8 agent targets the CLI autodetects. Note this is the CLI's own table
|
|
8
|
+
// (the site's SUPPORTED_AGENTS is a superset for display); keep the targetDir
|
|
9
|
+
// paths aligned with the install guides.
|
|
10
|
+
const CONTEXTS = [
|
|
11
|
+
{
|
|
12
|
+
agent: "Claude Code",
|
|
13
|
+
guideSlug: "claude-code",
|
|
14
|
+
probe: (cwd) => (existsSync(join(cwd, ".claude", "skills")) ? ".claude/skills" : existsSync(join(cwd, ".claude")) ? ".claude" : null),
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
agent: "Cursor",
|
|
18
|
+
guideSlug: "cursor",
|
|
19
|
+
probe: (cwd) => (existsSync(join(cwd, ".cursor", "rules")) ? ".cursor/rules" : existsSync(join(cwd, ".cursor")) ? ".cursor" : null),
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
agent: "Windsurf",
|
|
23
|
+
guideSlug: "windsurf",
|
|
24
|
+
probe: (cwd) => (existsSync(join(cwd, ".windsurf", "skills")) ? ".windsurf/skills" : null),
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
agent: "Claude Desktop",
|
|
28
|
+
guideSlug: "claude-desktop",
|
|
29
|
+
probe: (cwd) => (existsSync(join(cwd, ".claude", "skills")) ? ".claude/skills" : null),
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
agent: "Codex CLI",
|
|
33
|
+
guideSlug: "codex-cli",
|
|
34
|
+
probe: (cwd) => (existsSync(join(cwd, ".codex")) ? ".codex" : null),
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
agent: "Gemini CLI",
|
|
38
|
+
guideSlug: "gemini-cli",
|
|
39
|
+
probe: (cwd) => (existsSync(join(cwd, ".gemini", "skills")) ? ".gemini/skills" : null),
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
agent: "MCP",
|
|
43
|
+
guideSlug: "mcp",
|
|
44
|
+
probe: (cwd) => (existsSync(join(cwd, ".mcp")) ? ".mcp" : null),
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
export function detectAgentContext(cwd) {
|
|
48
|
+
for (const ctx of CONTEXTS) {
|
|
49
|
+
const targetDir = ctx.probe(cwd);
|
|
50
|
+
if (targetDir) {
|
|
51
|
+
return { agent: ctx.agent, targetDir, guideSlug: ctx.guideSlug };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
// The default target folder when no agent context is detected and the caller
|
|
57
|
+
// chooses not to prompt. `.claude/skills` is the safest default because that is
|
|
58
|
+
// where the most install-guide traffic points.
|
|
59
|
+
export const DEFAULT_TARGET_DIR = ".claude/skills";
|
|
60
|
+
// Derive the skill's local destination folder name. Most agents want the slug
|
|
61
|
+
// usable as a bare folder under the target; a guard against `../` injection.
|
|
62
|
+
export function safeSkillFolderName(slug) {
|
|
63
|
+
const name = slug.replace(/[^a-zA-Z0-9._-]/g, "-");
|
|
64
|
+
return name === "" ? "skill" : name;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=agent-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-context.js","sourceRoot":"","sources":["../src/agent-context.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { CatalogManifest, SkillRecord, PluginRecord, Agent, SkillMetaShard } from "./types.js";
|
|
2
|
+
export interface LoadOptions {
|
|
3
|
+
manifestUrl?: string;
|
|
4
|
+
cwd?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class Catalog {
|
|
7
|
+
private manifest;
|
|
8
|
+
private byId;
|
|
9
|
+
constructor(manifest: CatalogManifest);
|
|
10
|
+
static create(manifest: CatalogManifest): Catalog;
|
|
11
|
+
get skills(): SkillRecord[];
|
|
12
|
+
get plugins(): PluginRecord[];
|
|
13
|
+
get categories(): string[];
|
|
14
|
+
get agents(): Agent[];
|
|
15
|
+
get generatedAt(): string;
|
|
16
|
+
get version(): number;
|
|
17
|
+
getSkill(id: string): SkillRecord | undefined;
|
|
18
|
+
getPlugin(slug: string): PluginRecord | undefined;
|
|
19
|
+
getAllTags(): string[];
|
|
20
|
+
getFeaturedSkills(): SkillRecord[];
|
|
21
|
+
resolve(id: string): SkillRecord | undefined;
|
|
22
|
+
search(query: string, opts?: {
|
|
23
|
+
category?: string;
|
|
24
|
+
agent?: string;
|
|
25
|
+
limit?: number;
|
|
26
|
+
}): SkillRecord[];
|
|
27
|
+
badge(skill: SkillRecord): import("./types.js").Badge;
|
|
28
|
+
name(skill: SkillRecord): string;
|
|
29
|
+
fetchMeta(skill: SkillRecord): Promise<SkillMetaShard>;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=catalog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,YAAY,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAKpG,MAAM,WAAW,WAAW;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,qBAAa,OAAO;IAClB,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,IAAI,CAA2B;gBAE3B,QAAQ,EAAE,eAAe;IAKrC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO;IAIjD,IAAI,MAAM,IAAI,WAAW,EAAE,CAE1B;IAED,IAAI,OAAO,IAAI,YAAY,EAAE,CAE5B;IAED,IAAI,UAAU,IAAI,MAAM,EAAE,CAEzB;IAED,IAAI,MAAM,IAAI,KAAK,EAAE,CAEpB;IAED,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAI7C,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAIjD,UAAU,IAAI,MAAM,EAAE;IAMtB,iBAAiB,IAAI,WAAW,EAAE;IAiBlC,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAI5C,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,WAAW,EAAE;IAKlG,KAAK,CAAC,KAAK,EAAE,WAAW;IAKxB,IAAI,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM;IAO1B,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC;CAO7D"}
|
package/dist/catalog.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// The Catalog class. Holds one in-memory copy of the manifest and exposes the
|
|
2
|
+
// same read surface the site exposes via lib/catalog.ts, plus the lookups the
|
|
3
|
+
// CLI and MCP tools need. Pure data, no Next imports, no filesystem coupling
|
|
4
|
+
// beyond what the caller passes in.
|
|
5
|
+
import { skillSlug, badgeFor, skillMetaUrl } from "./types.js";
|
|
6
|
+
import { resolveSlug } from "./resolve.js";
|
|
7
|
+
import { searchSkills } from "./search.js";
|
|
8
|
+
export class Catalog {
|
|
9
|
+
manifest;
|
|
10
|
+
byId;
|
|
11
|
+
constructor(manifest) {
|
|
12
|
+
this.manifest = manifest;
|
|
13
|
+
this.byId = new Map(manifest.skills.map((s) => [s.id, s]));
|
|
14
|
+
}
|
|
15
|
+
static create(manifest) {
|
|
16
|
+
return new Catalog(manifest);
|
|
17
|
+
}
|
|
18
|
+
get skills() {
|
|
19
|
+
return this.manifest.skills;
|
|
20
|
+
}
|
|
21
|
+
get plugins() {
|
|
22
|
+
return this.manifest.plugins;
|
|
23
|
+
}
|
|
24
|
+
get categories() {
|
|
25
|
+
return this.manifest.categories;
|
|
26
|
+
}
|
|
27
|
+
get agents() {
|
|
28
|
+
return this.manifest.agents;
|
|
29
|
+
}
|
|
30
|
+
get generatedAt() {
|
|
31
|
+
return this.manifest.generatedAt;
|
|
32
|
+
}
|
|
33
|
+
get version() {
|
|
34
|
+
return this.manifest.version;
|
|
35
|
+
}
|
|
36
|
+
getSkill(id) {
|
|
37
|
+
return this.byId.get(id);
|
|
38
|
+
}
|
|
39
|
+
getPlugin(slug) {
|
|
40
|
+
return this.manifest.plugins.find((p) => p.slug === slug);
|
|
41
|
+
}
|
|
42
|
+
getAllTags() {
|
|
43
|
+
const set = new Set();
|
|
44
|
+
for (const s of this.manifest.skills)
|
|
45
|
+
for (const t of s.t)
|
|
46
|
+
set.add(t);
|
|
47
|
+
return [...set].sort();
|
|
48
|
+
}
|
|
49
|
+
getFeaturedSkills() {
|
|
50
|
+
const order = [
|
|
51
|
+
"nextjs-app-router-conventions",
|
|
52
|
+
"anti-slop-landing",
|
|
53
|
+
"context-window-management",
|
|
54
|
+
"copy-self-audit",
|
|
55
|
+
];
|
|
56
|
+
const found = [];
|
|
57
|
+
for (const slug of order) {
|
|
58
|
+
const hit = this.byId.get(slug);
|
|
59
|
+
if (hit)
|
|
60
|
+
found.push(hit);
|
|
61
|
+
}
|
|
62
|
+
return found;
|
|
63
|
+
}
|
|
64
|
+
// Resolve a slug or scoped id: exact first, then fuzzy. Returns the closest
|
|
65
|
+
// match or undefined.
|
|
66
|
+
resolve(id) {
|
|
67
|
+
return resolveSlug(this.manifest.skills, id);
|
|
68
|
+
}
|
|
69
|
+
search(query, opts) {
|
|
70
|
+
return searchSkills(this.manifest.skills, query, opts);
|
|
71
|
+
}
|
|
72
|
+
// Derived badge from origin + verified (spec §4). Never stored in the record.
|
|
73
|
+
badge(skill) {
|
|
74
|
+
return badgeFor(skill);
|
|
75
|
+
}
|
|
76
|
+
// The human-facing name of a record is its slug: one name, ever (spec §1).
|
|
77
|
+
name(skill) {
|
|
78
|
+
return skillSlug(skill);
|
|
79
|
+
}
|
|
80
|
+
// Fetch the per-skill meta.json shard for full detail (license, author,
|
|
81
|
+
// permissions, upstream repo). Network-only: the index deliberately omits
|
|
82
|
+
// these fields, so consumers get them on demand (spec §6).
|
|
83
|
+
async fetchMeta(skill) {
|
|
84
|
+
const res = await fetch(skillMetaUrl(skill));
|
|
85
|
+
if (!res.ok) {
|
|
86
|
+
throw new Error(`skyboy: failed to fetch meta for ${skill.id} (HTTP ${res.status})`);
|
|
87
|
+
}
|
|
88
|
+
return (await res.json());
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type { Origin, Badge, Permissions, SkillRecord, SkillMetaShard, PluginSkillRef, PluginRecord, Agent, CatalogManifest, } from "./types.js";
|
|
2
|
+
export { RAW_BASE, REPO, API_BASE, GITHUB_BLAME, skillMarkdownUrl, skillMetaUrl, skillSlotUrl, skillSlug, skillOwner, badgeFor, } from "./types.js";
|
|
3
|
+
export { resolveManifestUrl, findUpCatalog, fetchCatalog, DEFAULT_MANIFEST_URL, } from "./manifest.js";
|
|
4
|
+
export { Catalog } from "./catalog.js";
|
|
5
|
+
export type { LoadOptions } from "./catalog.js";
|
|
6
|
+
export { resolve, resolveSlug, } from "./resolve.js";
|
|
7
|
+
export type { ResolveResult } from "./resolve.js";
|
|
8
|
+
export { searchSkills, score as scoreSkill } from "./search.js";
|
|
9
|
+
export type { SearchOptions } from "./search.js";
|
|
10
|
+
export { detectAgentContext, DEFAULT_TARGET_DIR, safeSkillFolderName, } from "./agent-context.js";
|
|
11
|
+
export type { AgentContext } from "./agent-context.js";
|
|
12
|
+
export { installSkill, skillFolder, targetExists, isSafeSlug, installDirName, } from "./install.js";
|
|
13
|
+
export type { InstallResult } from "./install.js";
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,YAAY,EACV,MAAM,EACN,KAAK,EACL,WAAW,EACX,WAAW,EACX,cAAc,EACd,cAAc,EACd,YAAY,EACZ,KAAK,EACL,eAAe,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,QAAQ,EACR,IAAI,EACJ,QAAQ,EACR,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,UAAU,EACV,QAAQ,GACT,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,YAAY,EACZ,oBAAoB,GACrB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,EACL,OAAO,EACP,WAAW,GACZ,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,EAAE,YAAY,EAAE,KAAK,IAAI,UAAU,EAAE,MAAM,aAAa,CAAC;AAChE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,EACL,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,UAAU,EACV,cAAc,GACf,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// @skyboy/core - shared catalog + install logic for the skyboy CLI and MCP server.
|
|
2
|
+
// The site reads skills/ directly at build time; these standalone packages must
|
|
3
|
+
// not, so they consume the committed catalog.json via the manifest loader.
|
|
4
|
+
export { RAW_BASE, REPO, API_BASE, GITHUB_BLAME, skillMarkdownUrl, skillMetaUrl, skillSlotUrl, skillSlug, skillOwner, badgeFor, } from "./types.js";
|
|
5
|
+
export { resolveManifestUrl, findUpCatalog, fetchCatalog, DEFAULT_MANIFEST_URL, } from "./manifest.js";
|
|
6
|
+
export { Catalog } from "./catalog.js";
|
|
7
|
+
export { resolve, resolveSlug, } from "./resolve.js";
|
|
8
|
+
export { searchSkills, score as scoreSkill } from "./search.js";
|
|
9
|
+
export { detectAgentContext, DEFAULT_TARGET_DIR, safeSkillFolderName, } from "./agent-context.js";
|
|
10
|
+
export { installSkill, skillFolder, targetExists, isSafeSlug, installDirName, } from "./install.js";
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,gFAAgF;AAChF,2EAA2E;AAc3E,OAAO,EACL,QAAQ,EACR,IAAI,EACJ,QAAQ,EACR,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,UAAU,EACV,QAAQ,GACT,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,YAAY,EACZ,oBAAoB,GACrB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAIvC,OAAO,EACL,OAAO,EACP,WAAW,GACZ,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,YAAY,EAAE,KAAK,IAAI,UAAU,EAAE,MAAM,aAAa,CAAC;AAGhE,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,UAAU,EACV,cAAc,GACf,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { SkillRecord } from "./types.js";
|
|
2
|
+
export declare function skillFolder(skill: SkillRecord): string;
|
|
3
|
+
export interface InstallResult {
|
|
4
|
+
slug: string;
|
|
5
|
+
destDir: string;
|
|
6
|
+
filesWritten: number;
|
|
7
|
+
sourceUrl: string;
|
|
8
|
+
node: "file" | "dir";
|
|
9
|
+
}
|
|
10
|
+
export declare function installSkill(skill: SkillRecord, targetRoot: string, opts?: {
|
|
11
|
+
cwd?: string;
|
|
12
|
+
}): Promise<InstallResult>;
|
|
13
|
+
export declare function targetExists(cwd: string, targetDir: string): boolean;
|
|
14
|
+
export declare function isSafeSlug(slug: string): boolean;
|
|
15
|
+
export declare function installDirName(id: string): string;
|
|
16
|
+
//# sourceMappingURL=install.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAkC9C,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAItD;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;CACtB;AAED,wBAAsB,YAAY,CAChC,KAAK,EAAE,WAAW,EAClB,UAAU,EAAE,MAAM,EAClB,IAAI,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACtB,OAAO,CAAC,aAAa,CAAC,CAyCxB;AAGD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAEpE;AAKD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGhD;AAGD,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEjD"}
|
package/dist/install.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// Install a skill into a target folder. Fetches just that skill's folder via the
|
|
2
|
+
// GitHub contents API (enumerate files recursively) then pulls each file from the
|
|
3
|
+
// raw URL, mirroring the degit snippet in the brief sans the git history. This is
|
|
4
|
+
// the "download just that skill folder" step shared by the CLI and the stdio MCP
|
|
5
|
+
// `install_skill` tool.
|
|
6
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
7
|
+
import { join, dirname } from "node:path";
|
|
8
|
+
import { API_BASE, RAW_BASE, GITHUB_BLAME } from "./types.js";
|
|
9
|
+
import { skillSlug } from "./types.js";
|
|
10
|
+
import { safeSkillFolderName } from "./agent-context.js";
|
|
11
|
+
async function listDir(apiPath) {
|
|
12
|
+
const res = await fetch(`${API_BASE}/${apiPath}`, {
|
|
13
|
+
headers: { Accept: "application/vnd.github+json", "User-Agent": "skyboy" },
|
|
14
|
+
});
|
|
15
|
+
if (!res.ok) {
|
|
16
|
+
throw new Error(`skyboy: failed to list skill files (HTTP ${res.status}) at ${apiPath}`);
|
|
17
|
+
}
|
|
18
|
+
const data = (await res.json());
|
|
19
|
+
if (Array.isArray(data))
|
|
20
|
+
return data;
|
|
21
|
+
throw new Error(`skyboy: listing ${apiPath} failed: ${data.message}`);
|
|
22
|
+
}
|
|
23
|
+
async function fetchFile(url) {
|
|
24
|
+
const res = await fetch(url, { headers: { "User-Agent": "skyboy" } });
|
|
25
|
+
if (!res.ok) {
|
|
26
|
+
throw new Error(`skyboy: failed to fetch ${url} (HTTP ${res.status})`);
|
|
27
|
+
}
|
|
28
|
+
return Buffer.from(await res.arrayBuffer());
|
|
29
|
+
}
|
|
30
|
+
// Resolve the repo-relative folder for a skill. Uses the manifest `p` field
|
|
31
|
+
// (`skills/<category>/[<owner>/]<slug>`); falls back to the API search if a
|
|
32
|
+
// consumer only has an id and a category string.
|
|
33
|
+
export function skillFolder(skill) {
|
|
34
|
+
if (skill.p)
|
|
35
|
+
return skill.p;
|
|
36
|
+
// No path in the record: derive from the raw API tree by slug match.
|
|
37
|
+
return `skills/${skill.c.split("/")[0]}/${skillSlug(skill)}`;
|
|
38
|
+
}
|
|
39
|
+
export async function installSkill(skill, targetRoot, opts) {
|
|
40
|
+
const base = opts?.cwd ?? process.cwd();
|
|
41
|
+
const destDir = join(base, targetRoot, safeSkillFolderName(skillSlug(skill)));
|
|
42
|
+
const folder = skillFolder(skill);
|
|
43
|
+
// Enumerate the folder recursively.
|
|
44
|
+
const entries = [];
|
|
45
|
+
const queue = [folder];
|
|
46
|
+
while (queue.length > 0) {
|
|
47
|
+
const dir = queue.shift();
|
|
48
|
+
const children = await listDir(dir);
|
|
49
|
+
for (const child of children) {
|
|
50
|
+
if (child.type === "dir")
|
|
51
|
+
queue.push(child.path);
|
|
52
|
+
else
|
|
53
|
+
entries.push(child);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (entries.length === 0) {
|
|
57
|
+
throw new Error(`skyboy: no files found for skill ${skill.id} in ${folder}`);
|
|
58
|
+
}
|
|
59
|
+
mkdirSync(destDir, { recursive: true });
|
|
60
|
+
// Download and write each file under the skill folder. The generated
|
|
61
|
+
// meta.json shard ships in the repo, so it lands in the install too; that is
|
|
62
|
+
// fine, it is small and documents the skill's own metadata.
|
|
63
|
+
let filesWritten = 0;
|
|
64
|
+
for (const entry of entries) {
|
|
65
|
+
const local = join(destDir, entry.path.slice(folder.length + 1));
|
|
66
|
+
mkdirSync(dirname(local), { recursive: true });
|
|
67
|
+
const buf = await fetchFile(`${RAW_BASE}/${entry.path}`);
|
|
68
|
+
writeFileSync(local, buf);
|
|
69
|
+
filesWritten += 1;
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
slug: skillSlug(skill),
|
|
73
|
+
destDir,
|
|
74
|
+
filesWritten,
|
|
75
|
+
sourceUrl: `${GITHUB_BLAME}/${folder}/SKILL.md`,
|
|
76
|
+
node: "dir",
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
// Check whether a target root exists (used by the CLI to decide prompt vs write).
|
|
80
|
+
export function targetExists(cwd, targetDir) {
|
|
81
|
+
return existsSync(join(cwd, targetDir));
|
|
82
|
+
}
|
|
83
|
+
// Lightweight guard so an id can never produce a path that escapes the target.
|
|
84
|
+
// Accepts scoped ids (@owner/slug): the owner segment never reaches the
|
|
85
|
+
// filesystem path anyway, only the slug part becomes the folder name.
|
|
86
|
+
export function isSafeSlug(slug) {
|
|
87
|
+
const bare = slug.startsWith("@") ? slug.slice(slug.indexOf("/") + 1) : slug;
|
|
88
|
+
return !bare.includes("/") && !bare.includes("\\") && bare !== ".." && bare !== ".";
|
|
89
|
+
}
|
|
90
|
+
// Derive a plain install directory name without fetching anything.
|
|
91
|
+
export function installDirName(id) {
|
|
92
|
+
return safeSkillFolderName(skillSlug({ id }));
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { CatalogManifest } from "./types.js";
|
|
2
|
+
export declare const DEFAULT_MANIFEST_URL = "https://raw.githubusercontent.com/aijadugar/skyboy/main/catalog.json";
|
|
3
|
+
export declare function resolveManifestUrl(cwd: string, explicitUrl?: string): string;
|
|
4
|
+
export declare function findUpCatalog(start: string): string | null;
|
|
5
|
+
export declare function fetchCatalog(src: string): Promise<CatalogManifest>;
|
|
6
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,eAAO,MAAM,oBAAoB,yEAA6B,CAAC;AAO/D,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAK5E;AAMD,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAS1D;AAMD,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAaxE"}
|
package/dist/manifest.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// Fetch the shared catalog manifest. The CLI and MCP run in arbitrary user
|
|
2
|
+
// projects with no local checkout of the repo, so they pull catalog.json from
|
|
3
|
+
// the GitHub raw URL. A local file path or a local catalog.json is honoured for
|
|
4
|
+
// dev/offline (e.g. a checkout of this repo).
|
|
5
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
6
|
+
import { join, dirname } from "node:path";
|
|
7
|
+
import { RAW_BASE } from "./types.js";
|
|
8
|
+
export const DEFAULT_MANIFEST_URL = `${RAW_BASE}/catalog.json`;
|
|
9
|
+
// Resolution order for the manifest source:
|
|
10
|
+
// 1. explicit URL passed by the caller
|
|
11
|
+
// 2. a local catalog.json, found by walking up from cwd (a checkout of this
|
|
12
|
+
// repo, or a vendored copy)
|
|
13
|
+
// 3. the default raw.githubusercontent URL
|
|
14
|
+
export function resolveManifestUrl(cwd, explicitUrl) {
|
|
15
|
+
if (explicitUrl)
|
|
16
|
+
return explicitUrl;
|
|
17
|
+
const local = findUpCatalog(cwd);
|
|
18
|
+
if (local)
|
|
19
|
+
return local;
|
|
20
|
+
return DEFAULT_MANIFEST_URL;
|
|
21
|
+
}
|
|
22
|
+
// Walk up from cwd looking for a committed catalog.json. This lets the hosted
|
|
23
|
+
// route, CLI, and MCP all resolve the repo-root manifest during local dev even
|
|
24
|
+
// when they run from a nested dir (e.g. apps/web), while still falling back to
|
|
25
|
+
// the network for a clean, non-repo install.
|
|
26
|
+
export function findUpCatalog(start) {
|
|
27
|
+
let dir = start;
|
|
28
|
+
for (;;) {
|
|
29
|
+
const candidate = join(dir, "catalog.json");
|
|
30
|
+
if (existsSync(candidate))
|
|
31
|
+
return candidate;
|
|
32
|
+
const parent = dirname(dir);
|
|
33
|
+
if (parent === dir)
|
|
34
|
+
return null;
|
|
35
|
+
dir = parent;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function isLocalPath(src) {
|
|
39
|
+
return src.startsWith(".") || src.startsWith("/") || /^[a-zA-Z]:[\\/]/.test(src) || src.startsWith("file:");
|
|
40
|
+
}
|
|
41
|
+
export async function fetchCatalog(src) {
|
|
42
|
+
if (isLocalPath(src)) {
|
|
43
|
+
const p = src.startsWith("file:") ? src.replace(/^file:/, "") : src;
|
|
44
|
+
return JSON.parse(readFileSync(p, "utf8"));
|
|
45
|
+
}
|
|
46
|
+
const res = await fetch(src, { headers: { "Cache-Control": "no-cache" } });
|
|
47
|
+
if (!res.ok) {
|
|
48
|
+
throw new Error(`skyboy: failed to fetch catalog from ${src} (HTTP ${res.status}). ` +
|
|
49
|
+
`Check your network, or run with a local catalog.json present.`);
|
|
50
|
+
}
|
|
51
|
+
return (await res.json());
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,8EAA8E;AAC9E,gFAAgF;AAChF,8CAA8C;AAE9C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGtC,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAG,QAAQ,eAAe,CAAC;AAE/D,4CAA4C;AAC5C,yCAAyC;AACzC,8EAA8E;AAC9E,iCAAiC;AACjC,6CAA6C;AAC7C,MAAM,UAAU,kBAAkB,CAAC,GAAW,EAAE,WAAoB;IAClE,IAAI,WAAW;QAAE,OAAO,WAAW,CAAC;IACpC,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IACjC,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IACxB,OAAO,oBAAoB,CAAC;AAC9B,CAAC;AAED,8EAA8E;AAC9E,+EAA+E;AAC/E,+EAA+E;AAC/E,6CAA6C;AAC7C,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,IAAI,GAAG,GAAG,KAAK,CAAC;IAChB,SAAS,CAAC;QACR,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;QAC5C,IAAI,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO,SAAS,CAAC;QAC5C,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,MAAM,KAAK,GAAG;YAAE,OAAO,IAAI,CAAC;QAChC,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,GAAW;IAC9B,OAAO,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;AAC9G,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAW;IAC5C,IAAI,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,CAAC,GAAG,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QACpE,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAoB,CAAC;IAChE,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,EAAE,eAAe,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC;IAC3E,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,wCAAwC,GAAG,UAAU,GAAG,CAAC,MAAM,KAAK;YAClE,+DAA+D,CAClE,CAAC;IACJ,CAAC;IACD,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAoB,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { SkillRecord } from "./types.js";
|
|
2
|
+
export interface ResolveResult {
|
|
3
|
+
slug: string;
|
|
4
|
+
score: number;
|
|
5
|
+
exact: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function resolve(target: string, skills: SkillRecord[]): ResolveResult | null;
|
|
8
|
+
export declare function resolveSlug(skills: SkillRecord[], target: string): SkillRecord | undefined;
|
|
9
|
+
//# sourceMappingURL=resolve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA+C9C,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,aAAa,GAAG,IAAI,CA2BnF;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAG1F"}
|
package/dist/resolve.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// Slug resolution over compact v2 records: exact match first, then a simple,
|
|
2
|
+
// dependency-free fuzzy match. We compare against the id and the slug (and
|
|
3
|
+
// fall back to the path). No Levenshtein dependency; a containment +
|
|
4
|
+
// prefix/token heuristic is enough and keeps the core dependency-free.
|
|
5
|
+
import { skillSlug } from "./types.js";
|
|
6
|
+
function norm(s) {
|
|
7
|
+
return s.toLowerCase().replace(/[^a-z0-9@/]+/g, "-").replace(/^-+|-+$/g, "");
|
|
8
|
+
}
|
|
9
|
+
function similarity(a, b) {
|
|
10
|
+
if (a === b)
|
|
11
|
+
return 1;
|
|
12
|
+
if (b.length === 0 || a.length === 0)
|
|
13
|
+
return 0;
|
|
14
|
+
let best = 0;
|
|
15
|
+
// A query that is a whole leading segment of the other string is a strong hit:
|
|
16
|
+
// "nextjs" should match "nextjs-app-router-conventions". This is the common
|
|
17
|
+
// case users type, so weight it above a generic overlap.
|
|
18
|
+
if (a.length > 0 && (b.startsWith(a + "-") || b.startsWith(a + ".") || b.startsWith(a + "/"))) {
|
|
19
|
+
best = Math.max(best, 0.72);
|
|
20
|
+
}
|
|
21
|
+
if (b.length > 0 && (a.startsWith(b + "-") || a.startsWith(b + ".") || a.startsWith(b + "/"))) {
|
|
22
|
+
best = Math.max(best, 0.72);
|
|
23
|
+
}
|
|
24
|
+
// containment: is one a prefix/substring of the other?
|
|
25
|
+
if (a.includes(b) || b.includes(a)) {
|
|
26
|
+
best = Math.max(best, Math.min(a.length, b.length) / Math.max(a.length, b.length));
|
|
27
|
+
}
|
|
28
|
+
// token overlap across -_./ boundaries (always scored, since a partial segment
|
|
29
|
+
// substring match like "app-router" in "nextjs-app-router-conventions" is a
|
|
30
|
+
// strong signal that the containment score underweights). A full-token hit in
|
|
31
|
+
// a short query scores high because the query is a meaningful fragment.
|
|
32
|
+
const ta = a.split(/[-_./]+/).filter(Boolean);
|
|
33
|
+
const tb = b.split(/[-_./]+/).filter(Boolean);
|
|
34
|
+
let hits = 0;
|
|
35
|
+
for (const tok of ta)
|
|
36
|
+
if (tb.includes(tok))
|
|
37
|
+
hits++;
|
|
38
|
+
const tokenScore = hits / Math.max(ta.length, tb.length, 1);
|
|
39
|
+
best = Math.max(best, tokenScore);
|
|
40
|
+
// If every query token appears as a real token in the target, that is a strong
|
|
41
|
+
// signal even when the target is much longer (a fragment match).
|
|
42
|
+
if (hits === ta.length && ta.length > 0) {
|
|
43
|
+
best = Math.max(best, 0.68);
|
|
44
|
+
}
|
|
45
|
+
return best;
|
|
46
|
+
}
|
|
47
|
+
export function resolve(target, skills) {
|
|
48
|
+
const t = norm(target);
|
|
49
|
+
if (!t)
|
|
50
|
+
return null;
|
|
51
|
+
// Exact on id wins immediately; an exact bare-slug match also resolves (the
|
|
52
|
+
// bare form is the common way users type a skyboy skill).
|
|
53
|
+
for (const s of skills) {
|
|
54
|
+
if (norm(s.id) === t || norm(skillSlug(s)) === t) {
|
|
55
|
+
return { slug: s.id, score: 1, exact: true };
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
let best = null;
|
|
59
|
+
for (const s of skills) {
|
|
60
|
+
const score = Math.max(similarity(t, norm(s.id)), similarity(t, norm(skillSlug(s))), similarity(t, norm(s.c)));
|
|
61
|
+
if (score > 0 && (!best || score > best.score)) {
|
|
62
|
+
best = { slug: s.id, score, exact: false };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Only return a fuzzy hit above a low sanity bar so we don't silently grab an
|
|
66
|
+
// unrelated skill on a typo.
|
|
67
|
+
if (best && best.score >= 0.4)
|
|
68
|
+
return best;
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
export function resolveSlug(skills, target) {
|
|
72
|
+
const r = resolve(target, skills);
|
|
73
|
+
return r ? skills.find((s) => s.id === r.slug) : undefined;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=resolve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"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"}
|
package/dist/search.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { SkillRecord } from "./types.js";
|
|
2
|
+
export interface SearchOptions {
|
|
3
|
+
category?: string;
|
|
4
|
+
agent?: string;
|
|
5
|
+
limit?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function score(query: string, skill: SkillRecord): number;
|
|
8
|
+
export declare function searchSkills(skills: SkillRecord[], query: string, opts?: SearchOptions): SkillRecord[];
|
|
9
|
+
//# sourceMappingURL=search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG9C,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAcD,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,MAAM,CAsB/D;AAED,wBAAgB,YAAY,CAC1B,MAAM,EAAE,WAAW,EAAE,EACrB,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,aAAa,GACnB,WAAW,EAAE,CAqBf"}
|
package/dist/search.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// Fuzzy search over the compact v2 catalog records. Mirrors the ranking a
|
|
2
|
+
// search bar would do, but dependency-free: token-overlap scoring over id,
|
|
3
|
+
// description, and tags, optionally filtered by category and compatible agent.
|
|
4
|
+
import { skillSlug } from "./types.js";
|
|
5
|
+
function norm(s) {
|
|
6
|
+
return s.toLowerCase();
|
|
7
|
+
}
|
|
8
|
+
function tokenOverlap(qTokens, hayTokens) {
|
|
9
|
+
if (qTokens.length === 0)
|
|
10
|
+
return 0;
|
|
11
|
+
let hits = 0;
|
|
12
|
+
for (const q of qTokens) {
|
|
13
|
+
if (hayTokens.some((h) => h.includes(q)))
|
|
14
|
+
hits += 1;
|
|
15
|
+
}
|
|
16
|
+
return hits / qTokens.length;
|
|
17
|
+
}
|
|
18
|
+
export function score(query, skill) {
|
|
19
|
+
const q = norm(query);
|
|
20
|
+
if (!q)
|
|
21
|
+
return 0;
|
|
22
|
+
const qTokens = q.split(/[^a-z0-9]+/).filter(Boolean);
|
|
23
|
+
const id = norm(skill.id);
|
|
24
|
+
const slug = norm(skillSlug(skill));
|
|
25
|
+
// Exact id / slug prefix is the strongest signal. The scoped id scores
|
|
26
|
+
// slightly above the bare slug so "@vercel/nextjs" beats a slug-only match.
|
|
27
|
+
if (id === q)
|
|
28
|
+
return 1.0;
|
|
29
|
+
if (slug === q)
|
|
30
|
+
return 0.97;
|
|
31
|
+
if (id.startsWith(q))
|
|
32
|
+
return 0.92;
|
|
33
|
+
if (slug.startsWith(q))
|
|
34
|
+
return 0.88;
|
|
35
|
+
let best = 0;
|
|
36
|
+
best = Math.max(best, tokenOverlap(qTokens, id.split(/[^a-z0-9]+/).filter(Boolean)));
|
|
37
|
+
best = Math.max(best, tokenOverlap(qTokens, skill.d.split(/[^a-z0-9]+/).filter(Boolean)));
|
|
38
|
+
for (const t of skill.t) {
|
|
39
|
+
best = Math.max(best, tokenOverlap(qTokens, t.split(/[^a-z0-9]+/).filter(Boolean)));
|
|
40
|
+
}
|
|
41
|
+
return best;
|
|
42
|
+
}
|
|
43
|
+
export function searchSkills(skills, query, opts) {
|
|
44
|
+
const q = (query ?? "").trim();
|
|
45
|
+
let pool = skills;
|
|
46
|
+
if (opts?.category)
|
|
47
|
+
pool = pool.filter((s) => s.c === opts.category);
|
|
48
|
+
if (opts?.agent) {
|
|
49
|
+
pool = pool.filter((s) => s.a.some((a) => norm(a) === norm(opts.agent) || norm(a).includes(norm(opts.agent))));
|
|
50
|
+
}
|
|
51
|
+
// Empty query: return the pool as-is (a bare tool call lists the catalog).
|
|
52
|
+
if (!q)
|
|
53
|
+
return pool;
|
|
54
|
+
const scored = pool
|
|
55
|
+
.map((s) => ({ s, score: score(q, s) }))
|
|
56
|
+
.filter((r) => r.score > 0)
|
|
57
|
+
.sort((a, b) => b.score - a.score || a.s.id.localeCompare(b.s.id));
|
|
58
|
+
const limit = opts?.limit ?? 50;
|
|
59
|
+
return scored.slice(0, limit).map((r) => r.s);
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
export type Origin = "skyboy" | "vendor" | "community";
|
|
2
|
+
export type Badge = "official" | "vendor" | "verified" | "community";
|
|
3
|
+
export interface SkillRecord {
|
|
4
|
+
id: string;
|
|
5
|
+
d: string;
|
|
6
|
+
c: string;
|
|
7
|
+
t: string[];
|
|
8
|
+
a: string[];
|
|
9
|
+
v: string;
|
|
10
|
+
h: string;
|
|
11
|
+
o: Origin;
|
|
12
|
+
y: boolean;
|
|
13
|
+
p: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function skillSlug(record: Pick<SkillRecord, "id">): string;
|
|
16
|
+
export declare function skillOwner(record: Pick<SkillRecord, "id">): string | null;
|
|
17
|
+
export declare function badgeFor(record: Pick<SkillRecord, "o" | "y">): Badge;
|
|
18
|
+
export interface Permissions {
|
|
19
|
+
network: boolean;
|
|
20
|
+
filesystem_write_outside_target: boolean;
|
|
21
|
+
shell_exec: boolean;
|
|
22
|
+
env_read: string[];
|
|
23
|
+
}
|
|
24
|
+
export interface SkillMetaShard {
|
|
25
|
+
id: string;
|
|
26
|
+
slug: string;
|
|
27
|
+
description: string;
|
|
28
|
+
category: string;
|
|
29
|
+
tags: string[];
|
|
30
|
+
compatible_agents: string[];
|
|
31
|
+
version: string;
|
|
32
|
+
license: string;
|
|
33
|
+
author: string;
|
|
34
|
+
origin: Origin;
|
|
35
|
+
verified: boolean;
|
|
36
|
+
upstream_repo: string | null;
|
|
37
|
+
canonical_of: string | null;
|
|
38
|
+
permissions: Permissions | null;
|
|
39
|
+
frontmatter: {
|
|
40
|
+
name: string | null;
|
|
41
|
+
license: string | null;
|
|
42
|
+
};
|
|
43
|
+
hash: string;
|
|
44
|
+
path: string;
|
|
45
|
+
skill_md_url: string;
|
|
46
|
+
}
|
|
47
|
+
export interface PluginSkillRef {
|
|
48
|
+
name: string;
|
|
49
|
+
description: string;
|
|
50
|
+
path: string;
|
|
51
|
+
url: string;
|
|
52
|
+
}
|
|
53
|
+
export interface PluginRecord {
|
|
54
|
+
slug: string;
|
|
55
|
+
name: string;
|
|
56
|
+
vendor: string;
|
|
57
|
+
vendorUrl?: string;
|
|
58
|
+
sourceType: "vendor";
|
|
59
|
+
origin: Origin;
|
|
60
|
+
category: string;
|
|
61
|
+
tags: string[];
|
|
62
|
+
license: string;
|
|
63
|
+
upstreamRepo: string;
|
|
64
|
+
install: string;
|
|
65
|
+
description: string;
|
|
66
|
+
compatibleAgents: string[];
|
|
67
|
+
skills: PluginSkillRef[];
|
|
68
|
+
commands: string[];
|
|
69
|
+
agents: string[];
|
|
70
|
+
mcp: string | null;
|
|
71
|
+
note: string;
|
|
72
|
+
badge: Badge;
|
|
73
|
+
version?: string;
|
|
74
|
+
path: string;
|
|
75
|
+
}
|
|
76
|
+
export interface Agent {
|
|
77
|
+
name: string;
|
|
78
|
+
note: string;
|
|
79
|
+
}
|
|
80
|
+
export interface CatalogManifest {
|
|
81
|
+
generatedAt: string;
|
|
82
|
+
version: number;
|
|
83
|
+
categories: string[];
|
|
84
|
+
agents: Agent[];
|
|
85
|
+
skills: SkillRecord[];
|
|
86
|
+
plugins: PluginRecord[];
|
|
87
|
+
}
|
|
88
|
+
export declare const REPO = "aijadugar/skyboy";
|
|
89
|
+
export declare const RAW_BASE = "https://raw.githubusercontent.com/aijadugar/skyboy/main";
|
|
90
|
+
export declare const API_BASE = "https://api.github.com/repos/aijadugar/skyboy/contents";
|
|
91
|
+
export declare const GITHUB_BLAME = "https://github.com/aijadugar/skyboy/blob/main";
|
|
92
|
+
export declare function skillMarkdownUrl(skill: Pick<SkillRecord, "p">): string;
|
|
93
|
+
export declare function skillMetaUrl(skill: Pick<SkillRecord, "p">): string;
|
|
94
|
+
export declare function skillSlotUrl(skill: Pick<SkillRecord, "p">): string;
|
|
95
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Shared catalog types for the standalone CLI + MCP server. These mirror the
|
|
2
|
+
// compact v2 record shape emitted by scripts/export-catalog.ts into catalog.json
|
|
3
|
+
// (docs/skill-spec.md §6). They are kept dependency-free (no Node types beyond
|
|
4
|
+
// the runtime globals) so the core is consumable from both the npm packages
|
|
5
|
+
// and, via the thin wrapper, PyPI.
|
|
6
|
+
// Derived views so consumers never re-derive these by hand.
|
|
7
|
+
export function skillSlug(record) {
|
|
8
|
+
return record.id.includes("/") ? record.id.slice(record.id.indexOf("/") + 1) : record.id;
|
|
9
|
+
}
|
|
10
|
+
export function skillOwner(record) {
|
|
11
|
+
return record.id.startsWith("@") ? record.id.slice(1, record.id.indexOf("/")) : null;
|
|
12
|
+
}
|
|
13
|
+
export function badgeFor(record) {
|
|
14
|
+
if (record.o === "skyboy")
|
|
15
|
+
return "official";
|
|
16
|
+
if (record.o === "vendor")
|
|
17
|
+
return "vendor";
|
|
18
|
+
return record.y ? "verified" : "community";
|
|
19
|
+
}
|
|
20
|
+
// The GitHub raw base for the skill catalog. The repo is the source of truth;
|
|
21
|
+
// the manifest's `p` fields turn into raw URLs under this base.
|
|
22
|
+
export const REPO = "aijadugar/skyboy";
|
|
23
|
+
export const RAW_BASE = `https://raw.githubusercontent.com/${REPO}/main`;
|
|
24
|
+
export const API_BASE = `https://api.github.com/repos/${REPO}/contents`;
|
|
25
|
+
export const GITHUB_BLAME = `https://github.com/${REPO}/blob/main`;
|
|
26
|
+
// A skill's SKILL.md raw URL (used for preview / one-off fetch).
|
|
27
|
+
export function skillMarkdownUrl(skill) {
|
|
28
|
+
return `${RAW_BASE}/${skill.p}/SKILL.md`;
|
|
29
|
+
}
|
|
30
|
+
export function skillMetaUrl(skill) {
|
|
31
|
+
return `${RAW_BASE}/${skill.p}/meta.json`;
|
|
32
|
+
}
|
|
33
|
+
export function skillSlotUrl(skill) {
|
|
34
|
+
return `${RAW_BASE}/${skill.p}`;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,iFAAiF;AACjF,+EAA+E;AAC/E,4EAA4E;AAC5E,mCAAmC;AAwBnC,4DAA4D;AAC5D,MAAM,UAAU,SAAS,CAAC,MAA+B;IACvD,OAAO,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;AAC3F,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAA+B;IACxD,OAAO,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACvF,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,MAAoC;IAC3D,IAAI,MAAM,CAAC,CAAC,KAAK,QAAQ;QAAE,OAAO,UAAU,CAAC;IAC7C,IAAI,MAAM,CAAC,CAAC,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC3C,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC;AAC7C,CAAC;AA6ED,8EAA8E;AAC9E,gEAAgE;AAChE,MAAM,CAAC,MAAM,IAAI,GAAG,kBAAkB,CAAC;AACvC,MAAM,CAAC,MAAM,QAAQ,GAAG,qCAAqC,IAAI,OAAO,CAAC;AACzE,MAAM,CAAC,MAAM,QAAQ,GAAG,gCAAgC,IAAI,WAAW,CAAC;AACxE,MAAM,CAAC,MAAM,YAAY,GAAG,sBAAsB,IAAI,YAAY,CAAC;AAEnE,iEAAiE;AACjE,MAAM,UAAU,gBAAgB,CAAC,KAA6B;IAC5D,OAAO,GAAG,QAAQ,IAAI,KAAK,CAAC,CAAC,WAAW,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAA6B;IACxD,OAAO,GAAG,QAAQ,IAAI,KAAK,CAAC,CAAC,YAAY,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAA6B;IACxD,OAAO,GAAG,QAAQ,IAAI,KAAK,CAAC,CAAC,EAAE,CAAC;AAClC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aijadugar/skyboy-core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Shared catalog + install logic for the skyboy CLI and MCP server.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": ["dist", "LICENSE"],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc -p tsconfig.json"
|
|
18
|
+
},
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=20"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@types/node": "^22.10.0"
|
|
24
|
+
}
|
|
25
|
+
}
|