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.
@@ -0,0 +1,442 @@
1
+ /**
2
+ * Shared types and error classes for the Skillex CLI.
3
+ */
4
+ /**
5
+ * Supported sync file rendering modes.
6
+ */
7
+ export type SyncMode = "managed-block" | "managed-file";
8
+ /**
9
+ * Workspace sync write modes.
10
+ */
11
+ export type SyncWriteMode = "symlink" | "copy";
12
+ /**
13
+ * Marker used to detect an adapter in a workspace.
14
+ */
15
+ export interface AdapterMarker {
16
+ path: string;
17
+ weight: number;
18
+ }
19
+ /**
20
+ * Static adapter definition used for detection and synchronization.
21
+ */
22
+ export interface AdapterConfig {
23
+ id: string;
24
+ label: string;
25
+ markers: AdapterMarker[];
26
+ syncTarget: string;
27
+ legacySyncTargets?: string[];
28
+ syncMode: SyncMode;
29
+ }
30
+ /**
31
+ * Persisted adapter state in the workspace lockfile.
32
+ */
33
+ export interface AdapterState {
34
+ active: string | null;
35
+ detected: string[];
36
+ }
37
+ /**
38
+ * Remote catalog source configuration.
39
+ */
40
+ export interface CatalogSource {
41
+ owner: string;
42
+ repoName: string;
43
+ repo: string;
44
+ ref: string;
45
+ catalogPath: string;
46
+ skillsDir: string;
47
+ catalogUrl: string | null;
48
+ }
49
+ /**
50
+ * Optional catalog source overrides accepted by CLI and installer entrypoints.
51
+ */
52
+ export interface CatalogSourceInput {
53
+ owner?: string | undefined;
54
+ repoName?: string | undefined;
55
+ repo?: string | undefined;
56
+ ref?: string | undefined;
57
+ catalogPath?: string | undefined;
58
+ skillsDir?: string | undefined;
59
+ catalogUrl?: string | null | undefined;
60
+ /** Directory to store catalog cache files. Caching is skipped when absent. */
61
+ cacheDir?: string | undefined;
62
+ /** When `true`, bypass the local catalog cache and always fetch from the network. */
63
+ noCache?: boolean | undefined;
64
+ }
65
+ /**
66
+ * Parsed GitHub repository reference.
67
+ */
68
+ export interface ParsedGitHubRepo {
69
+ owner: string;
70
+ repo: string;
71
+ ref: string | null;
72
+ }
73
+ /**
74
+ * Skill manifest stored in catalog and local installs.
75
+ */
76
+ export interface SkillManifest {
77
+ id: string;
78
+ name: string;
79
+ version: string;
80
+ description: string;
81
+ author: string | null;
82
+ tags: string[];
83
+ compatibility: string[];
84
+ entry: string;
85
+ path: string;
86
+ files: string[];
87
+ scripts?: Record<string, string> | undefined;
88
+ }
89
+ /**
90
+ * Alias used by catalog payloads for individual skill entries.
91
+ */
92
+ export interface CatalogEntry extends SkillManifest {
93
+ }
94
+ /**
95
+ * Remote skill catalog structure.
96
+ */
97
+ export interface CatalogData {
98
+ formatVersion: number;
99
+ repo: string;
100
+ ref: string;
101
+ skills: SkillManifest[];
102
+ }
103
+ /**
104
+ * Skill entry annotated with its originating catalog source.
105
+ */
106
+ export interface SourcedSkillManifest extends SkillManifest {
107
+ source: {
108
+ repo: string;
109
+ ref: string;
110
+ label?: string | undefined;
111
+ };
112
+ }
113
+ /**
114
+ * Clock function used to stamp lockfile updates during tests and runtime.
115
+ */
116
+ export type NowFn = () => string;
117
+ /**
118
+ * Search filters accepted by catalog lookups.
119
+ */
120
+ export interface SearchOptions {
121
+ query?: string;
122
+ compatibility?: string[] | string;
123
+ tags?: string[] | string;
124
+ }
125
+ /**
126
+ * Local metadata for an installed skill entry.
127
+ */
128
+ export interface InstalledSkillMetadata {
129
+ name: string;
130
+ version: string;
131
+ path: string;
132
+ installedAt: string;
133
+ compatibility: string[];
134
+ tags: string[];
135
+ source?: string | undefined;
136
+ }
137
+ /**
138
+ * Alias used by lockfile and installer contracts.
139
+ */
140
+ export interface InstalledSkill extends InstalledSkillMetadata {
141
+ }
142
+ /**
143
+ * Catalog source persisted inside the local lockfile.
144
+ */
145
+ export interface LockfileSource {
146
+ repo: string;
147
+ ref: string;
148
+ label?: string | undefined;
149
+ }
150
+ /**
151
+ * Workspace adapter state persisted in the lockfile.
152
+ */
153
+ export interface LockfileAdapters extends AdapterState {
154
+ }
155
+ /**
156
+ * Workspace settings persisted in the lockfile.
157
+ */
158
+ export interface LockfileSettings {
159
+ autoSync: boolean;
160
+ }
161
+ /**
162
+ * Last synchronization metadata persisted in the lockfile.
163
+ */
164
+ export interface SyncMetadata {
165
+ adapter: string;
166
+ targetPath: string;
167
+ syncedAt: string;
168
+ }
169
+ /**
170
+ * Full workspace lockfile structure.
171
+ */
172
+ export interface LockfileState {
173
+ formatVersion: number;
174
+ createdAt: string;
175
+ updatedAt: string;
176
+ sources: LockfileSource[];
177
+ adapters: LockfileAdapters;
178
+ settings: LockfileSettings;
179
+ sync: SyncMetadata | null;
180
+ syncMode: SyncWriteMode | null;
181
+ installed: Record<string, InstalledSkillMetadata>;
182
+ }
183
+ /**
184
+ * Result of aggregating multiple remote catalogs.
185
+ */
186
+ export interface AggregatedCatalogData {
187
+ formatVersion: number;
188
+ skills: SourcedSkillManifest[];
189
+ sources: Array<LockfileSource & {
190
+ skillCount: number;
191
+ }>;
192
+ }
193
+ /**
194
+ * Result of resolving a skill id across configured sources.
195
+ */
196
+ export interface ResolvedSkillSelection {
197
+ skill: SkillManifest;
198
+ catalog: CatalogData;
199
+ source: LockfileSource;
200
+ }
201
+ /**
202
+ * Common filesystem paths used by the local state manager.
203
+ */
204
+ export interface StatePaths {
205
+ stateDir: string;
206
+ lockfilePath: string;
207
+ skillsDirPath: string;
208
+ generatedDirPath: string;
209
+ }
210
+ /**
211
+ * Shared workspace options accepted by most install and sync functions.
212
+ */
213
+ export interface ProjectOptions extends CatalogSourceInput {
214
+ cwd?: string | undefined;
215
+ agentSkillsDir?: string | undefined;
216
+ adapter?: string | undefined;
217
+ autoSync?: boolean | undefined;
218
+ dryRun?: boolean | undefined;
219
+ mode?: SyncWriteMode | undefined;
220
+ trust?: boolean | undefined;
221
+ yes?: boolean | undefined;
222
+ timeout?: number | undefined;
223
+ now?: NowFn | undefined;
224
+ /** When `true`, enables verbose debug output. */
225
+ verbose?: boolean | undefined;
226
+ /** Progress callback invoked for each skill during installation. */
227
+ onProgress?: ((current: number, total: number, skillId: string) => void) | undefined;
228
+ }
229
+ /**
230
+ * Sync target resolved for an adapter file.
231
+ */
232
+ export interface SyncTarget {
233
+ adapter: string;
234
+ filePath: string;
235
+ mode: SyncMode;
236
+ }
237
+ /**
238
+ * Skill document loaded from disk for sync rendering.
239
+ */
240
+ export interface InstalledSkillDocument {
241
+ id: string;
242
+ name: string;
243
+ version: string;
244
+ body: string;
245
+ skillDir: string;
246
+ scripts: Record<string, string>;
247
+ autoInject: boolean;
248
+ activationPrompt: string | null;
249
+ }
250
+ /**
251
+ * Internal prepared sync state before writing to disk.
252
+ */
253
+ export interface PreparedSyncResult {
254
+ adapter: string;
255
+ absoluteTargetPath: string;
256
+ targetPath: string;
257
+ cleanupPaths: string[];
258
+ changed: boolean;
259
+ currentContent: string;
260
+ nextContent: string;
261
+ diff: string;
262
+ syncMode: SyncWriteMode;
263
+ generatedSourcePath?: string | undefined;
264
+ }
265
+ /**
266
+ * Dry-run preview returned before a sync writes files.
267
+ */
268
+ export interface SyncPreview {
269
+ adapter: string;
270
+ filePath: string;
271
+ before: string;
272
+ after: string;
273
+ }
274
+ /**
275
+ * Public sync result returned after writing or dry-run preparation.
276
+ */
277
+ export interface SyncResult {
278
+ adapter: string;
279
+ targetPath: string;
280
+ changed: boolean;
281
+ diff: string;
282
+ syncMode: SyncWriteMode;
283
+ }
284
+ /**
285
+ * Shared options for sync execution.
286
+ */
287
+ export interface SyncOptions {
288
+ cwd: string;
289
+ adapterId: string;
290
+ statePaths: StatePaths;
291
+ skills: InstalledSkillDocument[];
292
+ mode?: SyncWriteMode | undefined;
293
+ dryRun?: boolean | undefined;
294
+ linkFactory?: ((targetPath: string, linkPath: string) => Promise<CreateSymlinkResult>) | undefined;
295
+ warn?: ((message: string) => void) | undefined;
296
+ }
297
+ /**
298
+ * Result returned by the top-level sync command.
299
+ */
300
+ export interface SyncCommandResult {
301
+ statePaths: StatePaths;
302
+ sync: {
303
+ adapter: string;
304
+ targetPath: string;
305
+ } | SyncMetadata;
306
+ skillCount: number;
307
+ changed: boolean;
308
+ diff: string;
309
+ dryRun: boolean;
310
+ syncMode: SyncWriteMode;
311
+ }
312
+ /**
313
+ * Result returned by `initProject`.
314
+ */
315
+ export interface InitProjectResult {
316
+ created: boolean;
317
+ statePaths: StatePaths;
318
+ lockfile: LockfileState;
319
+ }
320
+ /**
321
+ * Result returned by `installSkills`.
322
+ */
323
+ export interface InstallSkillsResult {
324
+ installedCount: number;
325
+ installedSkills: SkillManifest[];
326
+ statePaths: StatePaths;
327
+ autoSync: SyncCommandResult | null;
328
+ }
329
+ /**
330
+ * Result returned by `updateInstalledSkills`.
331
+ */
332
+ export interface UpdateInstalledSkillsResult {
333
+ statePaths: StatePaths;
334
+ updatedSkills: SkillManifest[];
335
+ missingFromCatalog: string[];
336
+ autoSync: SyncCommandResult | null;
337
+ }
338
+ /**
339
+ * Result returned by `removeSkills`.
340
+ */
341
+ export interface RemoveSkillsResult {
342
+ statePaths: StatePaths;
343
+ removedSkills: string[];
344
+ missingSkills: string[];
345
+ autoSync: SyncCommandResult | null;
346
+ }
347
+ /**
348
+ * Catalog loader signature override used in tests.
349
+ */
350
+ export type CatalogLoader = (source: CatalogSource) => Promise<CatalogData>;
351
+ /**
352
+ * Skill downloader implementation used by installers.
353
+ */
354
+ export type SkillDownloader = (skill: SkillManifest, catalog: CatalogData, stateDir: string) => Promise<void>;
355
+ /**
356
+ * Parsed CLI arguments.
357
+ */
358
+ export interface ParsedArgs {
359
+ command?: string | undefined;
360
+ positionals: string[];
361
+ flags: Record<string, string | boolean>;
362
+ }
363
+ /**
364
+ * Parsed direct GitHub install reference.
365
+ */
366
+ export interface DirectGitHubRef {
367
+ owner: string;
368
+ repo: string;
369
+ ref: string;
370
+ }
371
+ /**
372
+ * Result of a filesystem link attempt.
373
+ */
374
+ export interface CreateSymlinkResult {
375
+ ok: boolean;
376
+ fallback: boolean;
377
+ relativeTarget: string;
378
+ }
379
+ /**
380
+ * Shared base class for typed Skillex errors.
381
+ */
382
+ export declare class SkillexError extends Error {
383
+ code: string;
384
+ /**
385
+ * Creates a typed Skillex error.
386
+ */
387
+ constructor(message: string, code: string);
388
+ }
389
+ /**
390
+ * Error thrown for catalog lookup and parsing failures.
391
+ */
392
+ export declare class CatalogError extends SkillexError {
393
+ /**
394
+ * Creates a catalog error.
395
+ */
396
+ constructor(message: string, code?: string);
397
+ }
398
+ /**
399
+ * Error thrown for install, update, or remove failures.
400
+ */
401
+ export declare class InstallError extends SkillexError {
402
+ /**
403
+ * Creates an install error.
404
+ */
405
+ constructor(message: string, code?: string);
406
+ }
407
+ /**
408
+ * Error thrown for sync preparation or write failures.
409
+ */
410
+ export declare class SyncError extends SkillexError {
411
+ /**
412
+ * Creates a sync error.
413
+ */
414
+ constructor(message: string, code?: string);
415
+ }
416
+ /**
417
+ * Error thrown for invalid user input or unsafe data.
418
+ */
419
+ export declare class ValidationError extends SkillexError {
420
+ /**
421
+ * Creates a validation error.
422
+ */
423
+ constructor(message: string, code?: string);
424
+ }
425
+ /**
426
+ * Error thrown when an unknown adapter is requested.
427
+ */
428
+ export declare class AdapterNotFoundError extends SkillexError {
429
+ /**
430
+ * Creates an adapter lookup error.
431
+ */
432
+ constructor(adapterId: string);
433
+ }
434
+ /**
435
+ * Error thrown for invalid CLI usage.
436
+ */
437
+ export declare class CliError extends SkillexError {
438
+ /**
439
+ * Creates a CLI error.
440
+ */
441
+ constructor(message: string, code?: string);
442
+ }
package/dist/types.js ADDED
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Shared types and error classes for the Skillex CLI.
3
+ */
4
+ /**
5
+ * Shared base class for typed Skillex errors.
6
+ */
7
+ export class SkillexError extends Error {
8
+ code;
9
+ /**
10
+ * Creates a typed Skillex error.
11
+ */
12
+ constructor(message, code) {
13
+ super(message);
14
+ this.name = new.target.name;
15
+ this.code = code;
16
+ }
17
+ }
18
+ /**
19
+ * Error thrown for catalog lookup and parsing failures.
20
+ */
21
+ export class CatalogError extends SkillexError {
22
+ /**
23
+ * Creates a catalog error.
24
+ */
25
+ constructor(message, code = "CATALOG_ERROR") {
26
+ super(message, code);
27
+ }
28
+ }
29
+ /**
30
+ * Error thrown for install, update, or remove failures.
31
+ */
32
+ export class InstallError extends SkillexError {
33
+ /**
34
+ * Creates an install error.
35
+ */
36
+ constructor(message, code = "INSTALL_ERROR") {
37
+ super(message, code);
38
+ }
39
+ }
40
+ /**
41
+ * Error thrown for sync preparation or write failures.
42
+ */
43
+ export class SyncError extends SkillexError {
44
+ /**
45
+ * Creates a sync error.
46
+ */
47
+ constructor(message, code = "SYNC_ERROR") {
48
+ super(message, code);
49
+ }
50
+ }
51
+ /**
52
+ * Error thrown for invalid user input or unsafe data.
53
+ */
54
+ export class ValidationError extends SkillexError {
55
+ /**
56
+ * Creates a validation error.
57
+ */
58
+ constructor(message, code = "VALIDATION_ERROR") {
59
+ super(message, code);
60
+ }
61
+ }
62
+ /**
63
+ * Error thrown when an unknown adapter is requested.
64
+ */
65
+ export class AdapterNotFoundError extends SkillexError {
66
+ /**
67
+ * Creates an adapter lookup error.
68
+ */
69
+ constructor(adapterId) {
70
+ super(`Unknown adapter: ${adapterId}`, "ADAPTER_NOT_FOUND");
71
+ }
72
+ }
73
+ /**
74
+ * Error thrown for invalid CLI usage.
75
+ */
76
+ export class CliError extends SkillexError {
77
+ /**
78
+ * Creates a CLI error.
79
+ */
80
+ constructor(message, code = "CLI_ERROR") {
81
+ super(message, code);
82
+ }
83
+ }
package/dist/ui.d.ts ADDED
@@ -0,0 +1,43 @@
1
+ import type { SkillManifest } from "./types.js";
2
+ interface UiChoice {
3
+ name: string;
4
+ value: string;
5
+ checked?: boolean | undefined;
6
+ }
7
+ interface UiPrompts {
8
+ input?: ((options: {
9
+ message: string;
10
+ default?: string | undefined;
11
+ }) => Promise<string>) | undefined;
12
+ checkbox?: ((options: {
13
+ message: string;
14
+ instructions?: string | undefined;
15
+ choices: UiChoice[];
16
+ }) => Promise<string[]>) | undefined;
17
+ }
18
+ /**
19
+ * Filters catalog skills for the interactive UI using a case-insensitive text query.
20
+ *
21
+ * @param skills - Catalog skills.
22
+ * @param query - Search text.
23
+ * @returns Filtered skills in their original order.
24
+ */
25
+ export declare function filterCatalogForUi(skills: SkillManifest[], query: string): SkillManifest[];
26
+ /**
27
+ * Runs the interactive terminal flow used by `skillex ui`.
28
+ *
29
+ * @param options - UI state and optional prompt overrides.
30
+ * @returns Selected, installable, and removable skill ids.
31
+ */
32
+ export declare function runInteractiveUi(options: {
33
+ skills: SkillManifest[];
34
+ installedIds: string[];
35
+ prompts?: UiPrompts | undefined;
36
+ }): Promise<{
37
+ query: string;
38
+ visibleIds: string[];
39
+ selectedIds: string[];
40
+ toInstall: string[];
41
+ toRemove: string[];
42
+ }>;
43
+ export {};
package/dist/ui.js ADDED
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Filters catalog skills for the interactive UI using a case-insensitive text query.
3
+ *
4
+ * @param skills - Catalog skills.
5
+ * @param query - Search text.
6
+ * @returns Filtered skills in their original order.
7
+ */
8
+ export function filterCatalogForUi(skills, query) {
9
+ const normalized = query.trim().toLowerCase();
10
+ if (!normalized) {
11
+ return skills;
12
+ }
13
+ return skills.filter((skill) => [skill.id, skill.name, skill.description, skill.compatibility.join(","), skill.tags.join(",")]
14
+ .join("\n")
15
+ .toLowerCase()
16
+ .includes(normalized));
17
+ }
18
+ /**
19
+ * Runs the interactive terminal flow used by `skillex ui`.
20
+ *
21
+ * @param options - UI state and optional prompt overrides.
22
+ * @returns Selected, installable, and removable skill ids.
23
+ */
24
+ export async function runInteractiveUi(options) {
25
+ const prompts = options.prompts || (await loadPromptAdapters());
26
+ const query = await (prompts.input || fallbackInput)({
27
+ message: "Filtro das skills (Enter para mostrar tudo)",
28
+ default: "",
29
+ });
30
+ const filteredSkills = filterCatalogForUi(options.skills, query);
31
+ const installedSet = new Set(options.installedIds);
32
+ const visibleIds = filteredSkills.map((skill) => skill.id);
33
+ const selectedIds = filteredSkills.length === 0
34
+ ? []
35
+ : await (prompts.checkbox || fallbackCheckbox)({
36
+ message: "Selecione as skills",
37
+ instructions: "Type to filter first • Space to select • Enter to install",
38
+ choices: filteredSkills.map((skill) => ({
39
+ name: `${skill.name} (${skill.id}) - ${skill.description || "Sem descricao"} [${skill.compatibility.join(",") || "sem-compat"}]`,
40
+ value: skill.id,
41
+ checked: installedSet.has(skill.id),
42
+ })),
43
+ });
44
+ const selectedSet = new Set(selectedIds);
45
+ const toInstall = selectedIds.filter((skillId) => !installedSet.has(skillId));
46
+ const toRemove = visibleIds.filter((skillId) => installedSet.has(skillId) && !selectedSet.has(skillId));
47
+ return {
48
+ query,
49
+ visibleIds,
50
+ selectedIds,
51
+ toInstall,
52
+ toRemove,
53
+ };
54
+ }
55
+ async function loadPromptAdapters() {
56
+ const prompts = await import("@inquirer/prompts");
57
+ return {
58
+ input: async (options) => prompts.input({
59
+ message: options.message,
60
+ ...(options.default !== undefined ? { default: options.default } : {}),
61
+ }),
62
+ checkbox: async (options) => prompts.checkbox({
63
+ message: options.message,
64
+ ...(options.instructions ? { instructions: options.instructions } : {}),
65
+ choices: options.choices.map((choice) => ({
66
+ name: choice.name,
67
+ value: choice.value,
68
+ ...(choice.checked !== undefined ? { checked: choice.checked } : {}),
69
+ })),
70
+ }),
71
+ };
72
+ }
73
+ async function fallbackInput() {
74
+ return "";
75
+ }
76
+ async function fallbackCheckbox() {
77
+ return [];
78
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Global user configuration for the Skillex CLI.
3
+ *
4
+ * Reads and writes `~/.askillrc.json`. CLI flags and environment variables
5
+ * always take precedence over values stored here.
6
+ */
7
+ /**
8
+ * Shape of the global user configuration file (`~/.askillrc.json`).
9
+ */
10
+ export interface UserConfig {
11
+ /** Default catalog repository in `owner/repo` format. */
12
+ defaultRepo?: string | undefined;
13
+ /** Default adapter ID to use when none is detected. */
14
+ defaultAdapter?: string | undefined;
15
+ /** GitHub personal access token (fallback when GITHUB_TOKEN env is unset). */
16
+ githubToken?: string | undefined;
17
+ /** When `true`, auto-sync is disabled globally. */
18
+ disableAutoSync?: boolean | undefined;
19
+ }
20
+ /** Valid keys that may be set via `skillex config set`. */
21
+ export declare const VALID_CONFIG_KEYS: ReadonlyArray<keyof UserConfig>;
22
+ /**
23
+ * Resolves the path to the global config file.
24
+ *
25
+ * Respects `XDG_CONFIG_HOME` when set; otherwise uses `~/.askillrc.json`.
26
+ */
27
+ export declare function getUserConfigPath(): string;
28
+ /**
29
+ * Reads the global user configuration file.
30
+ *
31
+ * Returns an empty object when the file does not exist or is invalid JSON.
32
+ */
33
+ export declare function readUserConfig(): Promise<UserConfig>;
34
+ /**
35
+ * Writes the global user configuration file, merging with any existing values.
36
+ *
37
+ * @param updates - Key/value pairs to write.
38
+ */
39
+ export declare function writeUserConfig(updates: Partial<UserConfig>): Promise<void>;