@localskills/cli 0.8.0 → 0.9.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/dist/index.js +118 -22
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -161,6 +161,7 @@ var require_src = __commonJS({
|
|
|
161
161
|
});
|
|
162
162
|
|
|
163
163
|
// src/index.ts
|
|
164
|
+
import { createRequire } from "module";
|
|
164
165
|
import { Command as Command10 } from "commander";
|
|
165
166
|
|
|
166
167
|
// src/commands/auth.ts
|
|
@@ -1368,6 +1369,11 @@ function setAnonymousKey(key) {
|
|
|
1368
1369
|
config.anonymous_key = key;
|
|
1369
1370
|
saveConfig(config);
|
|
1370
1371
|
}
|
|
1372
|
+
function setLastUpdateCheck(ts) {
|
|
1373
|
+
const config = loadFullConfig();
|
|
1374
|
+
config.last_update_check = ts;
|
|
1375
|
+
saveFullConfig(config);
|
|
1376
|
+
}
|
|
1371
1377
|
|
|
1372
1378
|
// src/lib/api-client.ts
|
|
1373
1379
|
var ApiClient = class {
|
|
@@ -1593,6 +1599,22 @@ function isValidSemVer(v) {
|
|
|
1593
1599
|
function isValidSemVerRange(range) {
|
|
1594
1600
|
return RANGE_RE.test(range);
|
|
1595
1601
|
}
|
|
1602
|
+
function compareSemVer(a, b) {
|
|
1603
|
+
if (a.major !== b.major)
|
|
1604
|
+
return a.major > b.major ? 1 : -1;
|
|
1605
|
+
if (a.minor !== b.minor)
|
|
1606
|
+
return a.minor > b.minor ? 1 : -1;
|
|
1607
|
+
if (a.patch !== b.patch)
|
|
1608
|
+
return a.patch > b.patch ? 1 : -1;
|
|
1609
|
+
return 0;
|
|
1610
|
+
}
|
|
1611
|
+
function isGreaterThan(next, prev) {
|
|
1612
|
+
const a = parseSemVer(next);
|
|
1613
|
+
const b = parseSemVer(prev);
|
|
1614
|
+
if (!a || !b)
|
|
1615
|
+
return false;
|
|
1616
|
+
return compareSemVer(a, b) === 1;
|
|
1617
|
+
}
|
|
1596
1618
|
|
|
1597
1619
|
// ../../packages/shared/dist/utils/index.js
|
|
1598
1620
|
function titleFromSlug(slug) {
|
|
@@ -1617,8 +1639,8 @@ function buildVersionQuery(range) {
|
|
|
1617
1639
|
console.error(`Invalid version specifier: ${range}`);
|
|
1618
1640
|
process.exit(1);
|
|
1619
1641
|
}
|
|
1620
|
-
function formatVersionLabel(semver,
|
|
1621
|
-
return semver ? `v${semver}` : `v${
|
|
1642
|
+
function formatVersionLabel(semver, version2) {
|
|
1643
|
+
return semver ? `v${semver}` : `v${version2}`;
|
|
1622
1644
|
}
|
|
1623
1645
|
function cancelGuard(value) {
|
|
1624
1646
|
if (Ct(value)) {
|
|
@@ -2320,13 +2342,13 @@ function getCacheDir(slug) {
|
|
|
2320
2342
|
}
|
|
2321
2343
|
return dir;
|
|
2322
2344
|
}
|
|
2323
|
-
function store(slug, content, skill,
|
|
2345
|
+
function store(slug, content, skill, version2) {
|
|
2324
2346
|
const dir = getCacheDir(slug);
|
|
2325
2347
|
mkdirSync5(dir, { recursive: true });
|
|
2326
2348
|
writeFileSync5(join12(dir, "raw.md"), content);
|
|
2327
2349
|
const meta = {
|
|
2328
2350
|
hash: skill.contentHash,
|
|
2329
|
-
version,
|
|
2351
|
+
version: version2,
|
|
2330
2352
|
semver: skill.currentSemver ?? null,
|
|
2331
2353
|
name: skill.name,
|
|
2332
2354
|
description: skill.description,
|
|
@@ -2372,14 +2394,14 @@ function purge(slug) {
|
|
|
2372
2394
|
rmSync3(dir, { recursive: true, force: true });
|
|
2373
2395
|
}
|
|
2374
2396
|
}
|
|
2375
|
-
function storePackage(slug, zipBuffer, manifest, skill,
|
|
2397
|
+
function storePackage(slug, zipBuffer, manifest, skill, version2) {
|
|
2376
2398
|
const dir = getCacheDir(slug);
|
|
2377
2399
|
mkdirSync5(dir, { recursive: true });
|
|
2378
2400
|
writeFileSync5(join12(dir, "package.zip"), zipBuffer);
|
|
2379
2401
|
writeFileSync5(join12(dir, "manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
|
|
2380
2402
|
const meta = {
|
|
2381
2403
|
hash: skill.contentHash,
|
|
2382
|
-
version,
|
|
2404
|
+
version: version2,
|
|
2383
2405
|
semver: skill.currentSemver ?? null,
|
|
2384
2406
|
name: skill.name,
|
|
2385
2407
|
description: skill.description,
|
|
@@ -2528,13 +2550,13 @@ function parsePlatforms(raw) {
|
|
|
2528
2550
|
}
|
|
2529
2551
|
return platforms;
|
|
2530
2552
|
}
|
|
2531
|
-
function buildSkillRecord(cacheKey, skill,
|
|
2553
|
+
function buildSkillRecord(cacheKey, skill, version2, resolvedSemver, requestedRange, existingInstallations, newInstallations) {
|
|
2532
2554
|
return {
|
|
2533
2555
|
slug: cacheKey,
|
|
2534
2556
|
name: skill.name,
|
|
2535
2557
|
type: skill.type ?? "skill",
|
|
2536
2558
|
hash: skill.contentHash,
|
|
2537
|
-
version,
|
|
2559
|
+
version: version2,
|
|
2538
2560
|
semver: resolvedSemver ?? null,
|
|
2539
2561
|
semverRange: requestedRange ?? null,
|
|
2540
2562
|
cachedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -2619,13 +2641,13 @@ var installCommand = new Command2("install").description("Install a skill locall
|
|
|
2619
2641
|
const format = resData.format ?? "text";
|
|
2620
2642
|
const cacheKey = resData.skill.publicId || slug;
|
|
2621
2643
|
if (format === "package") {
|
|
2622
|
-
const { skill: skill2, downloadUrl, manifest, version:
|
|
2623
|
-
spinner.stop(`Fetched ${skill2.name} ${formatVersionLabel(resolvedSemver2,
|
|
2644
|
+
const { skill: skill2, downloadUrl, manifest, version: version3, semver: resolvedSemver2 } = resData;
|
|
2645
|
+
spinner.stop(`Fetched ${skill2.name} ${formatVersionLabel(resolvedSemver2, version3)} (package, ${manifest.files.length} files)`);
|
|
2624
2646
|
const dlSpinner = bt2();
|
|
2625
2647
|
dlSpinner.start("Downloading package...");
|
|
2626
2648
|
const zipBuffer = await client.fetchBinary(downloadUrl);
|
|
2627
2649
|
dlSpinner.stop(`Downloaded ${(zipBuffer.length / 1024).toFixed(1)} KB`);
|
|
2628
|
-
storePackage(cacheKey, zipBuffer, manifest, skill2,
|
|
2650
|
+
storePackage(cacheKey, zipBuffer, manifest, skill2, version3);
|
|
2629
2651
|
const installations2 = [];
|
|
2630
2652
|
const results2 = [];
|
|
2631
2653
|
for (const platformId of platforms) {
|
|
@@ -2656,7 +2678,7 @@ var installCommand = new Command2("install").description("Install a skill locall
|
|
|
2656
2678
|
config.installed_skills[cacheKey] = buildSkillRecord(
|
|
2657
2679
|
cacheKey,
|
|
2658
2680
|
skill2,
|
|
2659
|
-
|
|
2681
|
+
version3,
|
|
2660
2682
|
resolvedSemver2,
|
|
2661
2683
|
requestedRange,
|
|
2662
2684
|
config.installed_skills[cacheKey]?.installations,
|
|
@@ -2669,9 +2691,9 @@ var installCommand = new Command2("install").description("Install a skill locall
|
|
|
2669
2691
|
Le(`Done! Installed to ${installations2.length} target(s).`);
|
|
2670
2692
|
return;
|
|
2671
2693
|
}
|
|
2672
|
-
const { skill, content, version, semver: resolvedSemver } = resData;
|
|
2673
|
-
spinner.stop(`Fetched ${skill.name} ${formatVersionLabel(resolvedSemver,
|
|
2674
|
-
store(cacheKey, content, skill,
|
|
2694
|
+
const { skill, content, version: version2, semver: resolvedSemver } = resData;
|
|
2695
|
+
spinner.stop(`Fetched ${skill.name} ${formatVersionLabel(resolvedSemver, version2)}`);
|
|
2696
|
+
store(cacheKey, content, skill, version2);
|
|
2675
2697
|
const contentType = skill.type ?? "skill";
|
|
2676
2698
|
const installations = [];
|
|
2677
2699
|
const results = [];
|
|
@@ -2713,7 +2735,7 @@ var installCommand = new Command2("install").description("Install a skill locall
|
|
|
2713
2735
|
config.installed_skills[cacheKey] = buildSkillRecord(
|
|
2714
2736
|
cacheKey,
|
|
2715
2737
|
skill,
|
|
2716
|
-
|
|
2738
|
+
version2,
|
|
2717
2739
|
resolvedSemver,
|
|
2718
2740
|
requestedRange,
|
|
2719
2741
|
config.installed_skills[cacheKey]?.installations,
|
|
@@ -2863,7 +2885,7 @@ var pullCommand = new Command5("pull").description("Pull latest versions of all
|
|
|
2863
2885
|
}
|
|
2864
2886
|
const resData = res.data;
|
|
2865
2887
|
const format = resData.format ?? "text";
|
|
2866
|
-
const { skill, version } = resData;
|
|
2888
|
+
const { skill, version: version2 } = resData;
|
|
2867
2889
|
if (skill.contentHash === installed.hash) {
|
|
2868
2890
|
spinner.stop(`${slug} \u2014 up to date`);
|
|
2869
2891
|
skipped++;
|
|
@@ -2872,7 +2894,7 @@ var pullCommand = new Command5("pull").description("Pull latest versions of all
|
|
|
2872
2894
|
if (format === "package") {
|
|
2873
2895
|
const { downloadUrl, manifest } = resData;
|
|
2874
2896
|
const zipBuffer = await client.fetchBinary(downloadUrl);
|
|
2875
|
-
storePackage(slug, zipBuffer, manifest, skill,
|
|
2897
|
+
storePackage(slug, zipBuffer, manifest, skill, version2);
|
|
2876
2898
|
for (const installation of installed.installations) {
|
|
2877
2899
|
const adapter = getAdapter(installation.platform);
|
|
2878
2900
|
const targetPath = adapter.resolvePath(slug, installation.scope, installation.projectDir, skill.type ?? "skill");
|
|
@@ -2881,7 +2903,7 @@ var pullCommand = new Command5("pull").description("Pull latest versions of all
|
|
|
2881
2903
|
}
|
|
2882
2904
|
} else {
|
|
2883
2905
|
const { content } = resData;
|
|
2884
|
-
store(slug, content, skill,
|
|
2906
|
+
store(slug, content, skill, version2);
|
|
2885
2907
|
for (const installation of installed.installations) {
|
|
2886
2908
|
if (installation.method === "symlink") {
|
|
2887
2909
|
getPlatformFile(slug, installation.platform, skill);
|
|
@@ -2911,11 +2933,11 @@ ${transformed}`
|
|
|
2911
2933
|
}
|
|
2912
2934
|
}
|
|
2913
2935
|
installed.hash = skill.contentHash;
|
|
2914
|
-
installed.version =
|
|
2936
|
+
installed.version = version2;
|
|
2915
2937
|
installed.semver = resData.semver ?? null;
|
|
2916
2938
|
installed.cachedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2917
2939
|
updated++;
|
|
2918
|
-
spinner.stop(`${slug} \u2014 updated to ${formatVersionLabel(res.data.semver,
|
|
2940
|
+
spinner.stop(`${slug} \u2014 updated to ${formatVersionLabel(res.data.semver, version2)}`);
|
|
2919
2941
|
}
|
|
2920
2942
|
saveConfig(config);
|
|
2921
2943
|
Le(`Pull complete. ${updated} updated, ${skipped} up to date.`);
|
|
@@ -3564,12 +3586,86 @@ profileCommand.command("delete <name>").description("Delete a profile").option("
|
|
|
3564
3586
|
console.log(`Profile "${name}" deleted.`);
|
|
3565
3587
|
});
|
|
3566
3588
|
|
|
3589
|
+
// src/lib/update-check.ts
|
|
3590
|
+
var REGISTRY_URL = "https://registry.npmjs.org/@localskills/cli/latest";
|
|
3591
|
+
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
3592
|
+
var FETCH_TIMEOUT_MS = 500;
|
|
3593
|
+
var pendingCheck = null;
|
|
3594
|
+
var pendingAbort = null;
|
|
3595
|
+
var currentVer = null;
|
|
3596
|
+
function shouldCheck() {
|
|
3597
|
+
if (process.env.LOCALSKILLS_NO_UPDATE_CHECK === "1") return false;
|
|
3598
|
+
try {
|
|
3599
|
+
const config = loadFullConfig();
|
|
3600
|
+
if (config.update_check_opted_out) return false;
|
|
3601
|
+
const last = config.last_update_check;
|
|
3602
|
+
if (last) {
|
|
3603
|
+
const elapsed = Date.now() - new Date(last).getTime();
|
|
3604
|
+
if (elapsed < CHECK_INTERVAL_MS) return false;
|
|
3605
|
+
}
|
|
3606
|
+
} catch {
|
|
3607
|
+
return false;
|
|
3608
|
+
}
|
|
3609
|
+
return true;
|
|
3610
|
+
}
|
|
3611
|
+
function startUpdateCheck(currentVersion) {
|
|
3612
|
+
try {
|
|
3613
|
+
if (!shouldCheck()) return;
|
|
3614
|
+
currentVer = currentVersion;
|
|
3615
|
+
try {
|
|
3616
|
+
setLastUpdateCheck((/* @__PURE__ */ new Date()).toISOString());
|
|
3617
|
+
} catch {
|
|
3618
|
+
}
|
|
3619
|
+
pendingAbort = new AbortController();
|
|
3620
|
+
pendingCheck = fetch(REGISTRY_URL, { signal: pendingAbort.signal }).then((res) => {
|
|
3621
|
+
if (!res.ok) return null;
|
|
3622
|
+
return res.json();
|
|
3623
|
+
}).then((data) => {
|
|
3624
|
+
if (data && typeof data.version === "string" && isGreaterThan(data.version, currentVersion)) {
|
|
3625
|
+
return data.version;
|
|
3626
|
+
}
|
|
3627
|
+
return null;
|
|
3628
|
+
}).catch(() => null);
|
|
3629
|
+
} catch {
|
|
3630
|
+
}
|
|
3631
|
+
}
|
|
3632
|
+
async function printUpdateNotice() {
|
|
3633
|
+
try {
|
|
3634
|
+
if (!pendingCheck) return;
|
|
3635
|
+
const timeout = new Promise((resolve7) => {
|
|
3636
|
+
setTimeout(() => resolve7(null), FETCH_TIMEOUT_MS).unref();
|
|
3637
|
+
});
|
|
3638
|
+
const remoteVersion = await Promise.race([pendingCheck, timeout]);
|
|
3639
|
+
pendingAbort?.abort();
|
|
3640
|
+
pendingAbort = null;
|
|
3641
|
+
pendingCheck = null;
|
|
3642
|
+
if (remoteVersion) {
|
|
3643
|
+
const from = currentVer ?? "unknown";
|
|
3644
|
+
process.stderr.write(
|
|
3645
|
+
`
|
|
3646
|
+
Update available: ${from} \u2192 ${remoteVersion}
|
|
3647
|
+
Run: npm update -g @localskills/cli
|
|
3648
|
+
`
|
|
3649
|
+
);
|
|
3650
|
+
}
|
|
3651
|
+
} catch {
|
|
3652
|
+
}
|
|
3653
|
+
}
|
|
3654
|
+
|
|
3567
3655
|
// src/index.ts
|
|
3656
|
+
var require2 = createRequire(import.meta.url);
|
|
3657
|
+
var { version } = require2("../package.json");
|
|
3568
3658
|
var program = new Command10();
|
|
3569
|
-
program.name("localskills").description("Install and manage agent skills from localskills.sh").version(
|
|
3659
|
+
program.name("localskills").description("Install and manage agent skills from localskills.sh").version(version).option("--profile <name>", "Use a specific profile").option("--no-update-check", "Skip update check");
|
|
3570
3660
|
program.hook("preAction", (thisCommand) => {
|
|
3571
3661
|
const opts = thisCommand.opts();
|
|
3572
3662
|
setProfileOverride(opts.profile);
|
|
3663
|
+
if (opts.updateCheck !== false) {
|
|
3664
|
+
startUpdateCheck(version);
|
|
3665
|
+
}
|
|
3666
|
+
});
|
|
3667
|
+
program.hook("postAction", async () => {
|
|
3668
|
+
await printUpdateNotice();
|
|
3573
3669
|
});
|
|
3574
3670
|
program.addCommand(loginCommand);
|
|
3575
3671
|
program.addCommand(logoutCommand);
|