skillex 0.2.1 → 0.2.3
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/CHANGELOG.md +16 -0
- package/README.md +57 -18
- package/dist/adapters.js +15 -8
- package/dist/catalog.js +24 -3
- package/dist/cli.js +65 -20
- package/dist/config.d.ts +20 -1
- package/dist/config.js +31 -0
- package/dist/fs.d.ts +7 -0
- package/dist/fs.js +16 -3
- package/dist/install.d.ts +4 -4
- package/dist/install.js +59 -28
- package/dist/runner.js +9 -4
- package/dist/sync.d.ts +2 -2
- package/dist/sync.js +194 -50
- package/dist/types.d.ts +24 -2
- package/package.json +1 -1
package/dist/fs.d.ts
CHANGED
|
@@ -48,6 +48,13 @@ export declare function writeText(filePath: string, value: string): Promise<void
|
|
|
48
48
|
* @param targetPath - File system path to remove.
|
|
49
49
|
*/
|
|
50
50
|
export declare function removePath(targetPath: string): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Copies a file or directory recursively to a destination path.
|
|
53
|
+
*
|
|
54
|
+
* @param sourcePath - Existing source path.
|
|
55
|
+
* @param targetPath - Destination path.
|
|
56
|
+
*/
|
|
57
|
+
export declare function copyPath(sourcePath: string, targetPath: string): Promise<void>;
|
|
51
58
|
/**
|
|
52
59
|
* Creates a relative symlink and reports whether the caller should fall back to copy mode.
|
|
53
60
|
*
|
package/dist/fs.js
CHANGED
|
@@ -89,6 +89,17 @@ export async function writeText(filePath, value) {
|
|
|
89
89
|
export async function removePath(targetPath) {
|
|
90
90
|
await fs.rm(targetPath, { recursive: true, force: true });
|
|
91
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* Copies a file or directory recursively to a destination path.
|
|
94
|
+
*
|
|
95
|
+
* @param sourcePath - Existing source path.
|
|
96
|
+
* @param targetPath - Destination path.
|
|
97
|
+
*/
|
|
98
|
+
export async function copyPath(sourcePath, targetPath) {
|
|
99
|
+
await ensureDir(path.dirname(targetPath));
|
|
100
|
+
await removePath(targetPath);
|
|
101
|
+
await fs.cp(sourcePath, targetPath, { recursive: true, force: true });
|
|
102
|
+
}
|
|
92
103
|
/**
|
|
93
104
|
* Creates a relative symlink and reports whether the caller should fall back to copy mode.
|
|
94
105
|
*
|
|
@@ -98,14 +109,16 @@ export async function removePath(targetPath) {
|
|
|
98
109
|
*/
|
|
99
110
|
export async function createSymlink(targetPath, linkPath) {
|
|
100
111
|
const absoluteTarget = path.resolve(targetPath);
|
|
112
|
+
const relativeTarget = path.relative(path.dirname(linkPath), absoluteTarget) || ".";
|
|
101
113
|
await ensureDir(path.dirname(linkPath));
|
|
102
114
|
await removePath(linkPath);
|
|
103
115
|
try {
|
|
104
|
-
await fs.
|
|
116
|
+
const stats = await fs.lstat(absoluteTarget);
|
|
117
|
+
await fs.symlink(relativeTarget, linkPath, stats.isDirectory() ? "dir" : "file");
|
|
105
118
|
return {
|
|
106
119
|
ok: true,
|
|
107
120
|
fallback: false,
|
|
108
|
-
relativeTarget
|
|
121
|
+
relativeTarget,
|
|
109
122
|
};
|
|
110
123
|
}
|
|
111
124
|
catch (error) {
|
|
@@ -116,7 +129,7 @@ export async function createSymlink(targetPath, linkPath) {
|
|
|
116
129
|
return {
|
|
117
130
|
ok: false,
|
|
118
131
|
fallback: true,
|
|
119
|
-
relativeTarget
|
|
132
|
+
relativeTarget,
|
|
120
133
|
};
|
|
121
134
|
}
|
|
122
135
|
throw error;
|
package/dist/install.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ interface InstallOptions extends ProjectOptions {
|
|
|
15
15
|
*/
|
|
16
16
|
export declare function initProject(options?: ProjectOptions): Promise<InitProjectResult>;
|
|
17
17
|
/**
|
|
18
|
-
* Installs one or more catalog skills or direct GitHub skills into the
|
|
18
|
+
* Installs one or more catalog skills or direct GitHub skills into the selected Skillex state.
|
|
19
19
|
*
|
|
20
20
|
* @param requestedSkillIds - Requested skill ids or `owner/repo[@ref]` direct references.
|
|
21
21
|
* @param options - Installation options.
|
|
@@ -33,7 +33,7 @@ export declare function installSkills(requestedSkillIds: string[], options?: Ins
|
|
|
33
33
|
*/
|
|
34
34
|
export declare function updateInstalledSkills(requestedSkillIds: string[], options?: InstallOptions): Promise<UpdateInstalledSkillsResult>;
|
|
35
35
|
/**
|
|
36
|
-
* Removes installed skills from the
|
|
36
|
+
* Removes installed skills from the selected Skillex state.
|
|
37
37
|
*
|
|
38
38
|
* @param requestedSkillIds - Skill ids to remove.
|
|
39
39
|
* @param options - Remove options.
|
|
@@ -46,11 +46,11 @@ export declare function removeSkills(requestedSkillIds: string[], options?: Proj
|
|
|
46
46
|
*
|
|
47
47
|
* @param options - Sync options.
|
|
48
48
|
* @returns Sync command result.
|
|
49
|
-
* @throws {InstallError} When
|
|
49
|
+
* @throws {InstallError} When the selected install scope is missing or invalid.
|
|
50
50
|
*/
|
|
51
51
|
export declare function syncInstalledSkills(options?: ProjectOptions): Promise<SyncCommandResult>;
|
|
52
52
|
/**
|
|
53
|
-
* Reads the
|
|
53
|
+
* Reads the selected Skillex lockfile when it exists.
|
|
54
54
|
*
|
|
55
55
|
* @param options - Project lookup options.
|
|
56
56
|
* @returns Normalized lockfile state or `null` when no install exists.
|
package/dist/install.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
|
-
import {
|
|
2
|
+
import { DEFAULT_INSTALL_SCOPE, DEFAULT_REF, DEFAULT_REPO, getScopedStatePaths, } from "./config.js";
|
|
3
3
|
import { confirmAction } from "./confirm.js";
|
|
4
4
|
import { ensureDir, pathExists, readJson, removePath, writeJson, writeText } from "./fs.js";
|
|
5
5
|
import { fetchOptionalJson, fetchOptionalText, fetchText } from "./http.js";
|
|
@@ -18,7 +18,7 @@ import { CliError, InstallError } from "./types.js";
|
|
|
18
18
|
export async function initProject(options = {}) {
|
|
19
19
|
try {
|
|
20
20
|
const cwd = options.cwd || process.cwd();
|
|
21
|
-
const statePaths =
|
|
21
|
+
const statePaths = resolveStatePathsForOptions(cwd, options);
|
|
22
22
|
const now = getNow(options);
|
|
23
23
|
await ensureDir(statePaths.stateDir);
|
|
24
24
|
await ensureDir(statePaths.skillsDirPath);
|
|
@@ -41,10 +41,12 @@ export async function initProject(options = {}) {
|
|
|
41
41
|
}
|
|
42
42
|
lockfile.updatedAt = now();
|
|
43
43
|
await writeJson(statePaths.lockfilePath, lockfile);
|
|
44
|
-
// Create .gitignore for the state directory on first init
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
await
|
|
44
|
+
// Create .gitignore for the local state directory on first init.
|
|
45
|
+
if (statePaths.scope === "local") {
|
|
46
|
+
const gitignorePath = path.join(statePaths.stateDir, ".gitignore");
|
|
47
|
+
if (!(await pathExists(gitignorePath))) {
|
|
48
|
+
await writeText(gitignorePath, ".cache/\n*.log\n");
|
|
49
|
+
}
|
|
48
50
|
}
|
|
49
51
|
return { created: !existing, statePaths, lockfile };
|
|
50
52
|
}
|
|
@@ -53,7 +55,7 @@ export async function initProject(options = {}) {
|
|
|
53
55
|
}
|
|
54
56
|
}
|
|
55
57
|
/**
|
|
56
|
-
* Installs one or more catalog skills or direct GitHub skills into the
|
|
58
|
+
* Installs one or more catalog skills or direct GitHub skills into the selected Skillex state.
|
|
57
59
|
*
|
|
58
60
|
* @param requestedSkillIds - Requested skill ids or `owner/repo[@ref]` direct references.
|
|
59
61
|
* @param options - Installation options.
|
|
@@ -63,7 +65,7 @@ export async function initProject(options = {}) {
|
|
|
63
65
|
export async function installSkills(requestedSkillIds, options = {}) {
|
|
64
66
|
try {
|
|
65
67
|
const cwd = options.cwd || process.cwd();
|
|
66
|
-
const statePaths =
|
|
68
|
+
const statePaths = resolveStatePathsForOptions(cwd, options);
|
|
67
69
|
const now = getNow(options);
|
|
68
70
|
const catalogLoader = options.catalogLoader || loadCatalog;
|
|
69
71
|
const downloader = options.downloader || downloadSkill;
|
|
@@ -126,6 +128,7 @@ export async function installSkills(requestedSkillIds, options = {}) {
|
|
|
126
128
|
await writeJson(statePaths.lockfilePath, lockfile);
|
|
127
129
|
const autoSync = await maybeAutoSync(withAgentSkillsDir({
|
|
128
130
|
cwd,
|
|
131
|
+
scope: options.scope,
|
|
129
132
|
adapter: lockfile.adapters.active,
|
|
130
133
|
enabled: lockfile.settings.autoSync,
|
|
131
134
|
now,
|
|
@@ -154,13 +157,15 @@ export async function installSkills(requestedSkillIds, options = {}) {
|
|
|
154
157
|
export async function updateInstalledSkills(requestedSkillIds, options = {}) {
|
|
155
158
|
try {
|
|
156
159
|
const cwd = options.cwd || process.cwd();
|
|
157
|
-
const statePaths =
|
|
160
|
+
const statePaths = resolveStatePathsForOptions(cwd, options);
|
|
158
161
|
const now = getNow(options);
|
|
159
162
|
const catalogLoader = options.catalogLoader || loadCatalog;
|
|
160
163
|
const downloader = options.downloader || downloadSkill;
|
|
161
164
|
const existing = await readJson(statePaths.lockfilePath, null);
|
|
162
165
|
if (!existing) {
|
|
163
|
-
throw new InstallError(
|
|
166
|
+
throw new InstallError(statePaths.scope === "global"
|
|
167
|
+
? "No global installation found. Run: skillex init --global --adapter <id>"
|
|
168
|
+
: "No local installation found. Run: skillex init", "LOCKFILE_MISSING");
|
|
164
169
|
}
|
|
165
170
|
const defaultSource = resolveSource(toCatalogSourceInput(options, resolvePrimarySourceOverride(options, existing)));
|
|
166
171
|
const lockfile = normalizeLockfile(existing, defaultSource, now);
|
|
@@ -211,6 +216,7 @@ export async function updateInstalledSkills(requestedSkillIds, options = {}) {
|
|
|
211
216
|
await writeJson(statePaths.lockfilePath, lockfile);
|
|
212
217
|
const autoSync = await maybeAutoSync(withAgentSkillsDir({
|
|
213
218
|
cwd,
|
|
219
|
+
scope: options.scope,
|
|
214
220
|
adapter: lockfile.adapters.active,
|
|
215
221
|
enabled: lockfile.settings.autoSync,
|
|
216
222
|
now,
|
|
@@ -229,7 +235,7 @@ export async function updateInstalledSkills(requestedSkillIds, options = {}) {
|
|
|
229
235
|
}
|
|
230
236
|
}
|
|
231
237
|
/**
|
|
232
|
-
* Removes installed skills from the
|
|
238
|
+
* Removes installed skills from the selected Skillex state.
|
|
233
239
|
*
|
|
234
240
|
* @param requestedSkillIds - Skill ids to remove.
|
|
235
241
|
* @param options - Remove options.
|
|
@@ -239,11 +245,13 @@ export async function updateInstalledSkills(requestedSkillIds, options = {}) {
|
|
|
239
245
|
export async function removeSkills(requestedSkillIds, options = {}) {
|
|
240
246
|
try {
|
|
241
247
|
const cwd = options.cwd || process.cwd();
|
|
242
|
-
const statePaths =
|
|
248
|
+
const statePaths = resolveStatePathsForOptions(cwd, options);
|
|
243
249
|
const now = getNow(options);
|
|
244
250
|
const existing = await readJson(statePaths.lockfilePath, null);
|
|
245
251
|
if (!existing) {
|
|
246
|
-
throw new InstallError(
|
|
252
|
+
throw new InstallError(statePaths.scope === "global"
|
|
253
|
+
? "No global installation found. Run: skillex init --global --adapter <id>"
|
|
254
|
+
: "No local installation found. Run: skillex init", "LOCKFILE_MISSING");
|
|
247
255
|
}
|
|
248
256
|
if (!requestedSkillIds.length) {
|
|
249
257
|
throw new InstallError("Provide at least one skill-id to remove.", "REMOVE_REQUIRES_SKILL");
|
|
@@ -258,7 +266,7 @@ export async function removeSkills(requestedSkillIds, options = {}) {
|
|
|
258
266
|
missingSkills.push(skillId);
|
|
259
267
|
continue;
|
|
260
268
|
}
|
|
261
|
-
await removePath(
|
|
269
|
+
await removePath(resolveInstalledSkillPath(cwd, metadata.path));
|
|
262
270
|
delete lockfile.installed[skillId];
|
|
263
271
|
removedSkills.push(skillId);
|
|
264
272
|
}
|
|
@@ -266,6 +274,7 @@ export async function removeSkills(requestedSkillIds, options = {}) {
|
|
|
266
274
|
await writeJson(statePaths.lockfilePath, lockfile);
|
|
267
275
|
const autoSync = await maybeAutoSync(withAgentSkillsDir({
|
|
268
276
|
cwd,
|
|
277
|
+
scope: options.scope,
|
|
269
278
|
adapter: lockfile.adapters.active,
|
|
270
279
|
enabled: lockfile.settings.autoSync,
|
|
271
280
|
now,
|
|
@@ -288,16 +297,18 @@ export async function removeSkills(requestedSkillIds, options = {}) {
|
|
|
288
297
|
*
|
|
289
298
|
* @param options - Sync options.
|
|
290
299
|
* @returns Sync command result.
|
|
291
|
-
* @throws {InstallError} When
|
|
300
|
+
* @throws {InstallError} When the selected install scope is missing or invalid.
|
|
292
301
|
*/
|
|
293
302
|
export async function syncInstalledSkills(options = {}) {
|
|
294
303
|
try {
|
|
295
304
|
const cwd = options.cwd || process.cwd();
|
|
296
|
-
const statePaths =
|
|
305
|
+
const statePaths = resolveStatePathsForOptions(cwd, options);
|
|
297
306
|
const now = getNow(options);
|
|
298
307
|
const existing = await readJson(statePaths.lockfilePath, null);
|
|
299
308
|
if (!existing) {
|
|
300
|
-
throw new InstallError(
|
|
309
|
+
throw new InstallError(statePaths.scope === "global"
|
|
310
|
+
? "No global installation found. Run: skillex init --global --adapter <id>"
|
|
311
|
+
: "No local installation found. Run: skillex init", "LOCKFILE_MISSING");
|
|
301
312
|
}
|
|
302
313
|
const defaultSource = resolveSource(toCatalogSourceInput(options, resolvePrimarySourceOverride(options, existing)));
|
|
303
314
|
const lockfile = normalizeLockfile(existing, defaultSource, now);
|
|
@@ -311,9 +322,11 @@ export async function syncInstalledSkills(options = {}) {
|
|
|
311
322
|
});
|
|
312
323
|
const syncResult = await syncAdapterFiles({
|
|
313
324
|
cwd,
|
|
325
|
+
scope: statePaths.scope,
|
|
314
326
|
adapterId,
|
|
315
327
|
statePaths,
|
|
316
328
|
skills,
|
|
329
|
+
previousSkillIds: lockfile.sync?.skillIds || [],
|
|
317
330
|
...(options.mode ? { mode: options.mode } : {}),
|
|
318
331
|
...(options.dryRun !== undefined ? { dryRun: options.dryRun } : {}),
|
|
319
332
|
});
|
|
@@ -335,6 +348,7 @@ export async function syncInstalledSkills(options = {}) {
|
|
|
335
348
|
adapter: syncResult.adapter,
|
|
336
349
|
targetPath: syncResult.targetPath,
|
|
337
350
|
syncedAt: now(),
|
|
351
|
+
skillIds: skills.map((skill) => skill.id),
|
|
338
352
|
};
|
|
339
353
|
lockfile.syncMode = syncResult.syncMode;
|
|
340
354
|
lockfile.updatedAt = now();
|
|
@@ -354,14 +368,14 @@ export async function syncInstalledSkills(options = {}) {
|
|
|
354
368
|
}
|
|
355
369
|
}
|
|
356
370
|
/**
|
|
357
|
-
* Reads the
|
|
371
|
+
* Reads the selected Skillex lockfile when it exists.
|
|
358
372
|
*
|
|
359
373
|
* @param options - Project lookup options.
|
|
360
374
|
* @returns Normalized lockfile state or `null` when no install exists.
|
|
361
375
|
*/
|
|
362
376
|
export async function getInstalledSkills(options = {}) {
|
|
363
377
|
const cwd = options.cwd || process.cwd();
|
|
364
|
-
const statePaths =
|
|
378
|
+
const statePaths = resolveStatePathsForOptions(cwd, options);
|
|
365
379
|
if (!(await pathExists(statePaths.lockfilePath))) {
|
|
366
380
|
return null;
|
|
367
381
|
}
|
|
@@ -380,7 +394,7 @@ export async function getInstalledSkills(options = {}) {
|
|
|
380
394
|
*/
|
|
381
395
|
export async function resolveProjectSource(options = {}) {
|
|
382
396
|
const cwd = options.cwd || process.cwd();
|
|
383
|
-
const statePaths =
|
|
397
|
+
const statePaths = resolveStatePathsForOptions(cwd, options);
|
|
384
398
|
const existing = await readJson(statePaths.lockfilePath, null);
|
|
385
399
|
return resolveSource(toCatalogSourceInput(options, resolvePrimarySourceOverride(options, existing)));
|
|
386
400
|
}
|
|
@@ -392,7 +406,7 @@ export async function resolveProjectSource(options = {}) {
|
|
|
392
406
|
*/
|
|
393
407
|
export async function resolveProjectSources(options = {}) {
|
|
394
408
|
const cwd = options.cwd || process.cwd();
|
|
395
|
-
const statePaths =
|
|
409
|
+
const statePaths = resolveStatePathsForOptions(cwd, options);
|
|
396
410
|
const existing = await readJson(statePaths.lockfilePath, null);
|
|
397
411
|
if (options.repo) {
|
|
398
412
|
return [toLockfileSource(resolveSource(toCatalogSourceInput(options, { repo: options.repo, ref: options.ref })))];
|
|
@@ -435,7 +449,7 @@ export async function loadProjectCatalogs(options = {}, catalogLoader = loadCata
|
|
|
435
449
|
*/
|
|
436
450
|
export async function addProjectSource(sourceInput, options = {}) {
|
|
437
451
|
const cwd = options.cwd || process.cwd();
|
|
438
|
-
const statePaths =
|
|
452
|
+
const statePaths = resolveStatePathsForOptions(cwd, options);
|
|
439
453
|
const now = getNow(options);
|
|
440
454
|
await ensureDir(statePaths.stateDir);
|
|
441
455
|
await ensureDir(statePaths.skillsDirPath);
|
|
@@ -461,11 +475,13 @@ export async function addProjectSource(sourceInput, options = {}) {
|
|
|
461
475
|
*/
|
|
462
476
|
export async function removeProjectSource(repo, options = {}) {
|
|
463
477
|
const cwd = options.cwd || process.cwd();
|
|
464
|
-
const statePaths =
|
|
478
|
+
const statePaths = resolveStatePathsForOptions(cwd, options);
|
|
465
479
|
const now = getNow(options);
|
|
466
480
|
const existing = await readJson(statePaths.lockfilePath, null);
|
|
467
481
|
if (!existing) {
|
|
468
|
-
throw new InstallError(
|
|
482
|
+
throw new InstallError(statePaths.scope === "global"
|
|
483
|
+
? "No global installation found. Run: skillex init --global --adapter <id>"
|
|
484
|
+
: "No local installation found. Run: skillex init", "LOCKFILE_MISSING");
|
|
469
485
|
}
|
|
470
486
|
const fallbackSource = resolveSource(toCatalogSourceInput(options, resolvePrimarySourceOverride(options, existing)));
|
|
471
487
|
const lockfile = normalizeLockfile(existing, fallbackSource, now);
|
|
@@ -489,7 +505,7 @@ export async function removeProjectSource(repo, options = {}) {
|
|
|
489
505
|
*/
|
|
490
506
|
export async function listProjectSources(options = {}) {
|
|
491
507
|
const cwd = options.cwd || process.cwd();
|
|
492
|
-
const statePaths =
|
|
508
|
+
const statePaths = resolveStatePathsForOptions(cwd, options);
|
|
493
509
|
const existing = await readJson(statePaths.lockfilePath, null);
|
|
494
510
|
const fallbackSource = resolveSource(toCatalogSourceInput(options, resolvePrimarySourceOverride(options, existing)));
|
|
495
511
|
return getLockfileSources(existing, fallbackSource);
|
|
@@ -657,11 +673,14 @@ function normalizeLockfile(existing, source, now) {
|
|
|
657
673
|
installed: existing.installed || {},
|
|
658
674
|
};
|
|
659
675
|
}
|
|
676
|
+
/** Repos that are known placeholder values written by older versions and must be ignored. */
|
|
677
|
+
const PLACEHOLDER_REPOS = new Set(["owner/repo"]);
|
|
660
678
|
function getLockfileSources(existing, fallbackSource) {
|
|
661
679
|
const legacyCatalog = getLegacyCatalog(existing);
|
|
662
680
|
const configuredSources = Array.isArray(existing?.sources)
|
|
663
681
|
? existing.sources
|
|
664
682
|
.filter((entry) => Boolean(entry?.repo))
|
|
683
|
+
.filter((entry) => !PLACEHOLDER_REPOS.has(entry.repo))
|
|
665
684
|
.map((entry) => ({
|
|
666
685
|
repo: entry.repo,
|
|
667
686
|
ref: entry.ref || DEFAULT_REF,
|
|
@@ -671,7 +690,7 @@ function getLockfileSources(existing, fallbackSource) {
|
|
|
671
690
|
if (configuredSources.length > 0) {
|
|
672
691
|
return dedupeSources(configuredSources);
|
|
673
692
|
}
|
|
674
|
-
if (legacyCatalog?.repo) {
|
|
693
|
+
if (legacyCatalog?.repo && !PLACEHOLDER_REPOS.has(legacyCatalog.repo)) {
|
|
675
694
|
return dedupeSources([
|
|
676
695
|
{
|
|
677
696
|
repo: legacyCatalog.repo,
|
|
@@ -781,7 +800,9 @@ function buildInstalledMetadata(skill, context) {
|
|
|
781
800
|
return {
|
|
782
801
|
name: skill.name,
|
|
783
802
|
version: skill.version,
|
|
784
|
-
path:
|
|
803
|
+
path: context.statePaths.scope === "global"
|
|
804
|
+
? toPosix(path.join(context.statePaths.skillsDirPath, skill.id))
|
|
805
|
+
: toPosix(path.relative(context.cwd, path.join(context.statePaths.skillsDirPath, skill.id))),
|
|
785
806
|
installedAt: context.installedAt,
|
|
786
807
|
compatibility: skill.compatibility,
|
|
787
808
|
tags: skill.tags,
|
|
@@ -799,7 +820,7 @@ function resolveInstalledSkillIds(lockfile, requestedSkillIds) {
|
|
|
799
820
|
const installedSet = new Set(installedIds);
|
|
800
821
|
for (const skillId of requestedSkillIds) {
|
|
801
822
|
if (!installedSet.has(skillId)) {
|
|
802
|
-
throw new InstallError(`Skill "${skillId}" is not installed
|
|
823
|
+
throw new InstallError(`Skill "${skillId}" is not installed in the selected scope.`, "SKILL_NOT_INSTALLED");
|
|
803
824
|
}
|
|
804
825
|
}
|
|
805
826
|
return requestedSkillIds;
|
|
@@ -816,6 +837,7 @@ async function maybeAutoSync(options) {
|
|
|
816
837
|
}
|
|
817
838
|
return syncInstalledSkills({
|
|
818
839
|
cwd: options.cwd,
|
|
840
|
+
scope: options.scope || DEFAULT_INSTALL_SCOPE,
|
|
819
841
|
...(options.agentSkillsDir ? { agentSkillsDir: options.agentSkillsDir } : {}),
|
|
820
842
|
...(options.adapter ? { adapter: options.adapter } : {}),
|
|
821
843
|
...(options.mode ? { mode: options.mode } : {}),
|
|
@@ -853,6 +875,15 @@ function withAgentSkillsDir(options, agentSkillsDir) {
|
|
|
853
875
|
...(agentSkillsDir ? { agentSkillsDir } : {}),
|
|
854
876
|
};
|
|
855
877
|
}
|
|
878
|
+
function resolveStatePathsForOptions(cwd, options) {
|
|
879
|
+
return getScopedStatePaths(cwd, {
|
|
880
|
+
scope: options.scope || DEFAULT_INSTALL_SCOPE,
|
|
881
|
+
baseDir: options.agentSkillsDir,
|
|
882
|
+
});
|
|
883
|
+
}
|
|
884
|
+
function resolveInstalledSkillPath(cwd, skillPath) {
|
|
885
|
+
return path.isAbsolute(skillPath) ? skillPath : path.resolve(cwd, skillPath);
|
|
886
|
+
}
|
|
856
887
|
async function confirmDirectInstall(skillRef, options) {
|
|
857
888
|
const warning = `Warning: ${skillRef} will be installed directly from GitHub and has not been verified by the active catalog.`;
|
|
858
889
|
(options.warn || console.error)(warning);
|
package/dist/runner.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import { DEFAULT_INSTALL_SCOPE, getScopedStatePaths } from "./config.js";
|
|
4
4
|
import { confirmAction } from "./confirm.js";
|
|
5
5
|
import { readJson } from "./fs.js";
|
|
6
6
|
import { CliError } from "./types.js";
|
|
@@ -32,16 +32,21 @@ export function parseSkillCommandReference(value) {
|
|
|
32
32
|
*/
|
|
33
33
|
export async function runSkillScript(skillId, commandName, options = {}) {
|
|
34
34
|
const cwd = options.cwd || process.cwd();
|
|
35
|
-
const statePaths =
|
|
35
|
+
const statePaths = getScopedStatePaths(cwd, {
|
|
36
|
+
scope: options.scope || DEFAULT_INSTALL_SCOPE,
|
|
37
|
+
baseDir: options.agentSkillsDir,
|
|
38
|
+
});
|
|
36
39
|
const lockfile = (await readJson(statePaths.lockfilePath, null)) || null;
|
|
37
40
|
if (!lockfile) {
|
|
38
|
-
throw new CliError(
|
|
41
|
+
throw new CliError(statePaths.scope === "global"
|
|
42
|
+
? "Nenhuma instalacao global encontrada. Rode: skillex init --global --adapter <id>"
|
|
43
|
+
: "Nenhuma instalacao local encontrada. Rode: skillex init", "LOCKFILE_MISSING");
|
|
39
44
|
}
|
|
40
45
|
const metadata = lockfile.installed?.[skillId];
|
|
41
46
|
if (!metadata?.path) {
|
|
42
47
|
throw new CliError(`Skill "${skillId}" nao esta instalada.`, "SKILL_NOT_INSTALLED");
|
|
43
48
|
}
|
|
44
|
-
const skillDir = path.resolve(cwd, metadata.path);
|
|
49
|
+
const skillDir = path.isAbsolute(metadata.path) ? metadata.path : path.resolve(cwd, metadata.path);
|
|
45
50
|
const manifest = (await readJson(path.join(skillDir, "skill.json"), {})) || {};
|
|
46
51
|
const scripts = manifest.scripts || {};
|
|
47
52
|
const script = scripts[commandName];
|
package/dist/sync.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { InstalledSkillDocument, LockfileState, PreparedSyncResult, SyncOptions, SyncResult } from "./types.js";
|
|
2
2
|
/**
|
|
3
|
-
* Loads installed skill documents from the
|
|
3
|
+
* Loads installed skill documents from the selected Skillex state directory.
|
|
4
4
|
*
|
|
5
5
|
* @param context - Workspace root and lockfile context.
|
|
6
6
|
* @returns Installed skill documents used for sync rendering.
|
|
@@ -10,7 +10,7 @@ export declare function loadInstalledSkillDocuments(context: {
|
|
|
10
10
|
lockfile: LockfileState;
|
|
11
11
|
}): Promise<InstalledSkillDocument[]>;
|
|
12
12
|
/**
|
|
13
|
-
* Synchronizes installed skills into the target
|
|
13
|
+
* Synchronizes installed skills into the target consumed by an adapter.
|
|
14
14
|
*
|
|
15
15
|
* @param options - Sync execution options.
|
|
16
16
|
* @returns Final sync result.
|