skillex 0.2.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/bin/skillex.js ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { main } from "../dist/cli.js";
4
+ import { CliError } from "../dist/types.js";
5
+
6
+ main(process.argv.slice(2)).catch((error) => {
7
+ const message =
8
+ error instanceof CliError || error instanceof Error ? error.message : String(error);
9
+ console.error(`Error: ${message}`);
10
+ process.exitCode = 1;
11
+ });
@@ -0,0 +1,60 @@
1
+ import type { AdapterConfig, AdapterState } from "./types.js";
2
+ /**
3
+ * Lists supported adapters for CLI help and UI display.
4
+ *
5
+ * @returns Lightweight adapter descriptors.
6
+ */
7
+ export declare function listAdapters(): Array<Pick<AdapterConfig, "id" | "label">>;
8
+ /**
9
+ * Lists canonical adapter identifiers.
10
+ *
11
+ * @returns Supported adapter ids.
12
+ */
13
+ export declare function listAdapterIds(): string[];
14
+ /**
15
+ * Normalizes adapter aliases to canonical adapter identifiers.
16
+ *
17
+ * @param adapterId - User-supplied adapter identifier.
18
+ * @returns Canonical adapter id or `null` when empty.
19
+ */
20
+ export declare function normalizeAdapterId(adapterId: string | null | undefined): string | null;
21
+ /**
22
+ * Normalizes a list of adapter identifiers or aliases.
23
+ *
24
+ * @param values - Adapter values as a list or comma-separated string.
25
+ * @returns Canonical adapter ids without duplicates.
26
+ */
27
+ export declare function normalizeAdapterList(values: string[] | string | null | undefined): string[];
28
+ /**
29
+ * Checks whether an adapter id or alias maps to a supported adapter.
30
+ *
31
+ * @param adapterId - Adapter identifier to check.
32
+ * @returns `true` when the adapter is known.
33
+ */
34
+ export declare function isKnownAdapter(adapterId: string | null | undefined): boolean;
35
+ /**
36
+ * Resolves a canonical adapter configuration by id or alias.
37
+ *
38
+ * @param adapterId - Adapter identifier to resolve.
39
+ * @returns Adapter configuration.
40
+ * @throws {AdapterNotFoundError} When the adapter is unknown.
41
+ */
42
+ export declare function getAdapter(adapterId: string): AdapterConfig;
43
+ /**
44
+ * Detects supported adapters present in a workspace and orders them by specificity.
45
+ *
46
+ * @param cwd - Workspace root.
47
+ * @returns Ordered list of detected adapter ids.
48
+ */
49
+ export declare function detectAdapters(cwd: string): Promise<string[]>;
50
+ /**
51
+ * Resolves the active adapter state for a workspace.
52
+ *
53
+ * @param options - Resolution options including cwd and optional adapter override.
54
+ * @returns Active and detected adapter ids.
55
+ * @throws {AdapterNotFoundError} When the explicit override is unknown.
56
+ */
57
+ export declare function resolveAdapterState(options?: {
58
+ cwd?: string | undefined;
59
+ adapter?: string | undefined;
60
+ }): Promise<AdapterState>;
@@ -0,0 +1,213 @@
1
+ import * as path from "node:path";
2
+ import { pathExists } from "./fs.js";
3
+ import { AdapterNotFoundError } from "./types.js";
4
+ const ADAPTERS = [
5
+ {
6
+ id: "codex",
7
+ label: "OpenAI Codex",
8
+ markers: [
9
+ { path: "AGENTS.md", weight: 1 },
10
+ { path: ".codex", weight: 12 },
11
+ { path: ".codex/skills", weight: 16 },
12
+ ],
13
+ syncTarget: "AGENTS.md",
14
+ syncMode: "managed-block",
15
+ },
16
+ {
17
+ id: "copilot",
18
+ label: "GitHub Copilot",
19
+ markers: [{ path: ".github/copilot-instructions.md", weight: 16 }],
20
+ syncTarget: ".github/copilot-instructions.md",
21
+ syncMode: "managed-block",
22
+ },
23
+ {
24
+ id: "cline",
25
+ label: "Cline / Roo Code",
26
+ markers: [
27
+ { path: ".cline", weight: 16 },
28
+ { path: ".roo", weight: 16 },
29
+ { path: ".clinerules", weight: 12 },
30
+ { path: ".roo/rules", weight: 12 },
31
+ ],
32
+ syncTarget: ".clinerules/skillex-skills.md",
33
+ legacySyncTargets: [".clinerules/askill-skills.md"],
34
+ syncMode: "managed-file",
35
+ },
36
+ {
37
+ id: "cursor",
38
+ label: "Cursor",
39
+ markers: [
40
+ { path: ".cursor", weight: 16 },
41
+ { path: ".cursor/rules", weight: 18 },
42
+ { path: ".cursorrules", weight: 12 },
43
+ ],
44
+ syncTarget: ".cursor/rules/skillex-skills.mdc",
45
+ legacySyncTargets: [".cursor/rules/askill-skills.mdc"],
46
+ syncMode: "managed-file",
47
+ },
48
+ {
49
+ id: "claude",
50
+ label: "Claude Code",
51
+ markers: [
52
+ { path: "CLAUDE.md", weight: 16 },
53
+ { path: ".claude", weight: 18 },
54
+ ],
55
+ syncTarget: "CLAUDE.md",
56
+ syncMode: "managed-block",
57
+ },
58
+ {
59
+ id: "gemini",
60
+ label: "Gemini CLI",
61
+ markers: [
62
+ { path: "GEMINI.md", weight: 16 },
63
+ { path: ".gemini", weight: 18 },
64
+ ],
65
+ syncTarget: "GEMINI.md",
66
+ syncMode: "managed-block",
67
+ },
68
+ {
69
+ id: "windsurf",
70
+ label: "Windsurf",
71
+ markers: [
72
+ { path: ".windsurf", weight: 16 },
73
+ { path: ".windsurf/rules", weight: 18 },
74
+ ],
75
+ syncTarget: ".windsurf/rules/skillex-skills.md",
76
+ legacySyncTargets: [".windsurf/rules/askill-skills.md"],
77
+ syncMode: "managed-file",
78
+ },
79
+ ];
80
+ const ADAPTER_INDEX = new Map(ADAPTERS.map((adapter, index) => [adapter.id, index]));
81
+ const ADAPTER_ALIASES = new Map([
82
+ ["github-copilot", "copilot"],
83
+ ["roo", "cline"],
84
+ ["roo-code", "cline"],
85
+ ["claude-code", "claude"],
86
+ ["gemini-cli", "gemini"],
87
+ ["codeium", "windsurf"],
88
+ ["codeium-windsurf", "windsurf"],
89
+ ]);
90
+ /**
91
+ * Lists supported adapters for CLI help and UI display.
92
+ *
93
+ * @returns Lightweight adapter descriptors.
94
+ */
95
+ export function listAdapters() {
96
+ return ADAPTERS.map((adapter) => ({
97
+ id: adapter.id,
98
+ label: adapter.label,
99
+ }));
100
+ }
101
+ /**
102
+ * Lists canonical adapter identifiers.
103
+ *
104
+ * @returns Supported adapter ids.
105
+ */
106
+ export function listAdapterIds() {
107
+ return ADAPTERS.map((adapter) => adapter.id);
108
+ }
109
+ /**
110
+ * Normalizes adapter aliases to canonical adapter identifiers.
111
+ *
112
+ * @param adapterId - User-supplied adapter identifier.
113
+ * @returns Canonical adapter id or `null` when empty.
114
+ */
115
+ export function normalizeAdapterId(adapterId) {
116
+ if (adapterId === undefined || adapterId === null) {
117
+ return null;
118
+ }
119
+ const normalized = String(adapterId).trim().toLowerCase();
120
+ if (!normalized) {
121
+ return null;
122
+ }
123
+ return ADAPTER_ALIASES.get(normalized) || normalized;
124
+ }
125
+ /**
126
+ * Normalizes a list of adapter identifiers or aliases.
127
+ *
128
+ * @param values - Adapter values as a list or comma-separated string.
129
+ * @returns Canonical adapter ids without duplicates.
130
+ */
131
+ export function normalizeAdapterList(values) {
132
+ if (!values) {
133
+ return [];
134
+ }
135
+ const items = Array.isArray(values) ? values : String(values).split(",");
136
+ const normalized = [];
137
+ for (const item of items) {
138
+ const canonical = normalizeAdapterId(item);
139
+ if (!canonical || normalized.includes(canonical)) {
140
+ continue;
141
+ }
142
+ normalized.push(canonical);
143
+ }
144
+ return normalized;
145
+ }
146
+ /**
147
+ * Checks whether an adapter id or alias maps to a supported adapter.
148
+ *
149
+ * @param adapterId - Adapter identifier to check.
150
+ * @returns `true` when the adapter is known.
151
+ */
152
+ export function isKnownAdapter(adapterId) {
153
+ return ADAPTERS.some((adapter) => adapter.id === normalizeAdapterId(adapterId));
154
+ }
155
+ /**
156
+ * Resolves a canonical adapter configuration by id or alias.
157
+ *
158
+ * @param adapterId - Adapter identifier to resolve.
159
+ * @returns Adapter configuration.
160
+ * @throws {AdapterNotFoundError} When the adapter is unknown.
161
+ */
162
+ export function getAdapter(adapterId) {
163
+ const adapter = ADAPTERS.find((candidate) => candidate.id === normalizeAdapterId(adapterId)) || null;
164
+ if (!adapter) {
165
+ throw new AdapterNotFoundError(String(adapterId));
166
+ }
167
+ return adapter;
168
+ }
169
+ /**
170
+ * Detects supported adapters present in a workspace and orders them by specificity.
171
+ *
172
+ * @param cwd - Workspace root.
173
+ * @returns Ordered list of detected adapter ids.
174
+ */
175
+ export async function detectAdapters(cwd) {
176
+ const detected = [];
177
+ for (const adapter of ADAPTERS) {
178
+ const score = await adapterScore(cwd, adapter);
179
+ if (score > 0) {
180
+ detected.push({ id: adapter.id, score, index: ADAPTER_INDEX.get(adapter.id) || 0 });
181
+ }
182
+ }
183
+ detected.sort((left, right) => right.score - left.score || left.index - right.index);
184
+ return detected.map((adapter) => adapter.id);
185
+ }
186
+ /**
187
+ * Resolves the active adapter state for a workspace.
188
+ *
189
+ * @param options - Resolution options including cwd and optional adapter override.
190
+ * @returns Active and detected adapter ids.
191
+ * @throws {AdapterNotFoundError} When the explicit override is unknown.
192
+ */
193
+ export async function resolveAdapterState(options = {}) {
194
+ const cwd = options.cwd || process.cwd();
195
+ const preferred = normalizeAdapterId(options.adapter);
196
+ if (preferred && !isKnownAdapter(preferred)) {
197
+ throw new AdapterNotFoundError(preferred);
198
+ }
199
+ const detected = await detectAdapters(cwd);
200
+ return {
201
+ active: preferred || detected[0] || null,
202
+ detected,
203
+ };
204
+ }
205
+ async function adapterScore(cwd, adapter) {
206
+ let score = 0;
207
+ for (const marker of adapter.markers) {
208
+ if (await pathExists(path.join(cwd, marker.path))) {
209
+ score += marker.weight;
210
+ }
211
+ }
212
+ return score;
213
+ }
@@ -0,0 +1,73 @@
1
+ import type { CatalogData, CatalogSource, CatalogSourceInput, ParsedGitHubRepo, SearchOptions, SkillManifest } from "./types.js";
2
+ /**
3
+ * Reads a cached catalog from disk.
4
+ *
5
+ * @param cacheDir - Directory where cache files are stored.
6
+ * @param cacheKey - Unique key for this catalog source.
7
+ * @returns Cached catalog data, or `null` if missing or expired.
8
+ */
9
+ export declare function readCatalogCache(cacheDir: string, cacheKey: string): Promise<CatalogData | null>;
10
+ /**
11
+ * Writes catalog data to the local cache with a 5-minute TTL.
12
+ *
13
+ * @param cacheDir - Directory where cache files are stored.
14
+ * @param cacheKey - Unique key for this catalog source.
15
+ * @param data - Catalog data to cache.
16
+ */
17
+ export declare function writeCatalogCache(cacheDir: string, cacheKey: string, data: CatalogData): Promise<void>;
18
+ /**
19
+ * Computes a short, stable cache key for a catalog source URL.
20
+ *
21
+ * @param source - Resolved catalog source.
22
+ * @returns 16-character hex string.
23
+ */
24
+ export declare function computeCatalogCacheKey(source: CatalogSource): string;
25
+ /**
26
+ * Loads a remote skill catalog from `catalog.json` or falls back to repository tree inspection.
27
+ *
28
+ * @param options - Catalog source overrides.
29
+ * @returns Normalized remote catalog data.
30
+ * @throws {CatalogError} When the catalog cannot be fetched or normalized.
31
+ */
32
+ export declare function loadCatalog(options?: CatalogSourceInput): Promise<CatalogData>;
33
+ /**
34
+ * Resolves the effective GitHub catalog source from CLI options.
35
+ *
36
+ * @param options - Catalog source overrides.
37
+ * @returns Normalized catalog source.
38
+ * @throws {CatalogError} When the repository reference is invalid.
39
+ */
40
+ export declare function resolveSource(options?: CatalogSourceInput): CatalogSource;
41
+ /**
42
+ * Parses a GitHub repository reference in `owner/repo` or GitHub URL format.
43
+ *
44
+ * @param input - Repository reference to parse.
45
+ * @returns Parsed GitHub repository parts.
46
+ * @throws {CatalogError} When the input cannot be parsed.
47
+ */
48
+ export declare function parseGitHubRepo(input: string): ParsedGitHubRepo;
49
+ /**
50
+ * Builds a raw GitHub content URL for a repository file.
51
+ *
52
+ * @param repo - Repository in `owner/name` format.
53
+ * @param ref - Branch, tag, or commit.
54
+ * @param filePath - Repository-relative file path.
55
+ * @returns Raw GitHub content URL.
56
+ */
57
+ export declare function buildRawGitHubUrl(repo: string, ref: string, filePath: string): string;
58
+ /**
59
+ * Builds the GitHub tree API URL for a repository reference.
60
+ *
61
+ * @param repo - Repository in `owner/name` format.
62
+ * @param ref - Branch, tag, or commit.
63
+ * @returns GitHub API URL for recursive tree inspection.
64
+ */
65
+ export declare function buildGitHubApiUrl(repo: string, ref: string): string;
66
+ /**
67
+ * Filters a list of skills using text, compatibility, and tag criteria.
68
+ *
69
+ * @param skills - Skills to search.
70
+ * @param options - Search filters.
71
+ * @returns Matching skills ordered by id.
72
+ */
73
+ export declare function searchCatalogSkills(skills: SkillManifest[], options?: SearchOptions): SkillManifest[];