@localskills/cli 0.1.8 → 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/dist/index.js +82 -36
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1476,7 +1476,7 @@ function detect(projectDir) {
|
|
|
1476
1476
|
project: existsSync3(join2(cwd, ".cursor"))
|
|
1477
1477
|
};
|
|
1478
1478
|
}
|
|
1479
|
-
function resolvePath(slug, scope, projectDir) {
|
|
1479
|
+
function resolvePath(slug, scope, projectDir, _contentType) {
|
|
1480
1480
|
const safeName = slug.replace(/\//g, "-");
|
|
1481
1481
|
if (scope === "global") {
|
|
1482
1482
|
return join2(homedir2(), ".cursor", "rules", `${safeName}.mdc`);
|
|
@@ -1537,19 +1537,22 @@ function detect2(projectDir) {
|
|
|
1537
1537
|
project: existsSync4(join3(cwd, ".claude"))
|
|
1538
1538
|
};
|
|
1539
1539
|
}
|
|
1540
|
-
function resolvePath2(slug, scope, projectDir) {
|
|
1540
|
+
function resolvePath2(slug, scope, projectDir, contentType) {
|
|
1541
1541
|
const safeName = slug.replace(/\//g, "-");
|
|
1542
|
-
|
|
1543
|
-
|
|
1542
|
+
const base = scope === "global" ? join3(homedir3(), ".claude") : join3(projectDir || process.cwd(), ".claude");
|
|
1543
|
+
if (contentType === "rule") {
|
|
1544
|
+
return join3(base, "rules", `${safeName}.md`);
|
|
1544
1545
|
}
|
|
1545
|
-
|
|
1546
|
-
return join3(dir, ".claude", "skills", safeName, "SKILL.md");
|
|
1546
|
+
return join3(base, "skills", safeName, "SKILL.md");
|
|
1547
1547
|
}
|
|
1548
1548
|
function transformContent2(content, skill) {
|
|
1549
|
+
if (skill.type === "rule") {
|
|
1550
|
+
return toPlainMD(content);
|
|
1551
|
+
}
|
|
1549
1552
|
return toClaudeMD(content, skill);
|
|
1550
1553
|
}
|
|
1551
1554
|
function install2(opts) {
|
|
1552
|
-
const targetPath = resolvePath2(opts.slug, opts.scope, opts.projectDir);
|
|
1555
|
+
const targetPath = resolvePath2(opts.slug, opts.scope, opts.projectDir, opts.contentType);
|
|
1553
1556
|
const targetDir = join3(targetPath, "..");
|
|
1554
1557
|
if (opts.method === "symlink") {
|
|
1555
1558
|
createSymlink(opts.cachePath, targetPath);
|
|
@@ -1665,7 +1668,7 @@ function detect3() {
|
|
|
1665
1668
|
}
|
|
1666
1669
|
return { global: hasCommand, project: hasCommand };
|
|
1667
1670
|
}
|
|
1668
|
-
function resolvePath3(slug, scope, projectDir) {
|
|
1671
|
+
function resolvePath3(slug, scope, projectDir, _contentType) {
|
|
1669
1672
|
if (scope === "global") {
|
|
1670
1673
|
return join4(homedir4(), ".codex", "AGENTS.md");
|
|
1671
1674
|
}
|
|
@@ -1718,7 +1721,7 @@ function detect4(projectDir) {
|
|
|
1718
1721
|
project: existsSync6(join5(cwd, ".windsurf"))
|
|
1719
1722
|
};
|
|
1720
1723
|
}
|
|
1721
|
-
function resolvePath4(slug, scope, projectDir) {
|
|
1724
|
+
function resolvePath4(slug, scope, projectDir, _contentType) {
|
|
1722
1725
|
const safeName = slug.replace(/\//g, "-");
|
|
1723
1726
|
if (scope === "global") {
|
|
1724
1727
|
return join5(homedir5(), ".codeium", "windsurf", "memories", "global_rules.md");
|
|
@@ -1782,7 +1785,7 @@ function detect5(projectDir) {
|
|
|
1782
1785
|
project: existsSync7(join6(cwd, ".clinerules"))
|
|
1783
1786
|
};
|
|
1784
1787
|
}
|
|
1785
|
-
function resolvePath5(slug, scope, projectDir) {
|
|
1788
|
+
function resolvePath5(slug, scope, projectDir, _contentType) {
|
|
1786
1789
|
if (scope === "global") {
|
|
1787
1790
|
throw new Error("Cline does not support global installation");
|
|
1788
1791
|
}
|
|
@@ -1840,7 +1843,7 @@ function detect6(projectDir) {
|
|
|
1840
1843
|
project: existsSync8(join7(cwd, ".github"))
|
|
1841
1844
|
};
|
|
1842
1845
|
}
|
|
1843
|
-
function resolvePath6(slug, scope, projectDir) {
|
|
1846
|
+
function resolvePath6(slug, scope, projectDir, _contentType) {
|
|
1844
1847
|
if (scope === "global") {
|
|
1845
1848
|
throw new Error("GitHub Copilot does not support global installation");
|
|
1846
1849
|
}
|
|
@@ -1898,7 +1901,7 @@ function detect7(projectDir) {
|
|
|
1898
1901
|
project: hasCommand || existsSync9(join8(cwd, ".opencode"))
|
|
1899
1902
|
};
|
|
1900
1903
|
}
|
|
1901
|
-
function resolvePath7(slug, scope, projectDir) {
|
|
1904
|
+
function resolvePath7(slug, scope, projectDir, _contentType) {
|
|
1902
1905
|
const safeName = slug.replace(/\//g, "-");
|
|
1903
1906
|
if (scope === "global") {
|
|
1904
1907
|
return join8(homedir6(), ".config", "opencode", "rules", `${safeName}.md`);
|
|
@@ -1959,12 +1962,13 @@ function detect8() {
|
|
|
1959
1962
|
}
|
|
1960
1963
|
return { global: false, project: hasCommand };
|
|
1961
1964
|
}
|
|
1962
|
-
function resolvePath8(slug, scope, projectDir) {
|
|
1965
|
+
function resolvePath8(slug, scope, projectDir, contentType) {
|
|
1963
1966
|
if (scope === "global") {
|
|
1964
1967
|
throw new Error("Aider does not support global installation");
|
|
1965
1968
|
}
|
|
1966
1969
|
const safeName = slug.replace(/\//g, "-");
|
|
1967
|
-
|
|
1970
|
+
const subdir = contentType === "rule" ? "rules" : "skills";
|
|
1971
|
+
return join9(projectDir || process.cwd(), ".aider", subdir, `${safeName}.md`);
|
|
1968
1972
|
}
|
|
1969
1973
|
function transformContent8(content) {
|
|
1970
1974
|
return toPlainMD(content);
|
|
@@ -1993,7 +1997,7 @@ function removeAiderRead(projectDir, relativePath) {
|
|
|
1993
1997
|
writeFileSync8(configPath, filtered.join("\n"));
|
|
1994
1998
|
}
|
|
1995
1999
|
function install8(opts) {
|
|
1996
|
-
const targetPath = resolvePath8(opts.slug, opts.scope, opts.projectDir);
|
|
2000
|
+
const targetPath = resolvePath8(opts.slug, opts.scope, opts.projectDir, opts.contentType);
|
|
1997
2001
|
const projectDir = opts.projectDir || process.cwd();
|
|
1998
2002
|
if (opts.method === "symlink") {
|
|
1999
2003
|
createSymlink(opts.cachePath, targetPath);
|
|
@@ -2002,7 +2006,8 @@ function install8(opts) {
|
|
|
2002
2006
|
writeFileSync8(targetPath, opts.content);
|
|
2003
2007
|
}
|
|
2004
2008
|
const safeName = opts.slug.replace(/\//g, "-");
|
|
2005
|
-
const
|
|
2009
|
+
const subdir = opts.contentType === "rule" ? "rules" : "skills";
|
|
2010
|
+
const relativePath = `.aider/${subdir}/${safeName}.md`;
|
|
2006
2011
|
addAiderRead(projectDir, relativePath);
|
|
2007
2012
|
return targetPath;
|
|
2008
2013
|
}
|
|
@@ -2014,8 +2019,8 @@ function uninstall8(installation, slug) {
|
|
|
2014
2019
|
}
|
|
2015
2020
|
const projectDir = installation.projectDir || process.cwd();
|
|
2016
2021
|
const safeName = slug.replace(/\//g, "-");
|
|
2017
|
-
|
|
2018
|
-
removeAiderRead(projectDir,
|
|
2022
|
+
removeAiderRead(projectDir, `.aider/skills/${safeName}.md`);
|
|
2023
|
+
removeAiderRead(projectDir, `.aider/rules/${safeName}.md`);
|
|
2019
2024
|
}
|
|
2020
2025
|
function defaultMethod8() {
|
|
2021
2026
|
return "symlink";
|
|
@@ -2074,6 +2079,7 @@ function store(slug, content, skill, version) {
|
|
|
2074
2079
|
version,
|
|
2075
2080
|
name: skill.name,
|
|
2076
2081
|
description: skill.description,
|
|
2082
|
+
type: skill.type ?? "skill",
|
|
2077
2083
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2078
2084
|
};
|
|
2079
2085
|
writeFileSync9(join10(dir, "meta.json"), JSON.stringify(meta, null, 2) + "\n");
|
|
@@ -2086,6 +2092,13 @@ function getPlatformFile(slug, platform, skill) {
|
|
|
2086
2092
|
if (!raw) throw new Error(`No cached content for ${slug}`);
|
|
2087
2093
|
const transformed = adapter.transformContent(raw, skill);
|
|
2088
2094
|
if (platform === "claude") {
|
|
2095
|
+
if (skill.type === "rule") {
|
|
2096
|
+
const claudeRuleDir = join10(dir, "claude-rule");
|
|
2097
|
+
mkdirSync10(claudeRuleDir, { recursive: true });
|
|
2098
|
+
const filePath3 = join10(claudeRuleDir, `${slug.replace(/\//g, "-")}.md`);
|
|
2099
|
+
writeFileSync9(filePath3, transformed);
|
|
2100
|
+
return filePath3;
|
|
2101
|
+
}
|
|
2089
2102
|
const claudeDir = join10(dir, "claude");
|
|
2090
2103
|
mkdirSync10(claudeDir, { recursive: true });
|
|
2091
2104
|
const filePath2 = join10(claudeDir, "SKILL.md");
|
|
@@ -2349,7 +2362,9 @@ var installCommand = new Command2("install").description("Install a skill locall
|
|
|
2349
2362
|
}
|
|
2350
2363
|
const { skill, content, version } = res.data;
|
|
2351
2364
|
spinner.stop(`Fetched ${skill.name} v${version}`);
|
|
2352
|
-
|
|
2365
|
+
const cacheKey = skill.publicId || slug;
|
|
2366
|
+
store(cacheKey, content, skill, version);
|
|
2367
|
+
const contentType = skill.type ?? "skill";
|
|
2353
2368
|
const installations = [];
|
|
2354
2369
|
const results = [];
|
|
2355
2370
|
for (const platformId of platforms) {
|
|
@@ -2364,15 +2379,16 @@ var installCommand = new Command2("install").description("Install a skill locall
|
|
|
2364
2379
|
continue;
|
|
2365
2380
|
}
|
|
2366
2381
|
const actualMethod = adapter.defaultMethod(scope) === "section" ? "section" : method;
|
|
2367
|
-
const cachePath = getPlatformFile(
|
|
2382
|
+
const cachePath = getPlatformFile(cacheKey, platformId, skill);
|
|
2368
2383
|
const transformed = adapter.transformContent(content, skill);
|
|
2369
2384
|
const installedPath = adapter.install({
|
|
2370
|
-
slug,
|
|
2385
|
+
slug: cacheKey,
|
|
2371
2386
|
content: transformed,
|
|
2372
2387
|
scope,
|
|
2373
2388
|
method: actualMethod,
|
|
2374
2389
|
cachePath,
|
|
2375
|
-
projectDir
|
|
2390
|
+
projectDir,
|
|
2391
|
+
contentType
|
|
2376
2392
|
});
|
|
2377
2393
|
const installation = {
|
|
2378
2394
|
platform: platformId,
|
|
@@ -2386,16 +2402,17 @@ var installCommand = new Command2("install").description("Install a skill locall
|
|
|
2386
2402
|
const methodLabel = actualMethod === "symlink" ? "symlinked" : actualMethod === "section" ? "section" : "copied";
|
|
2387
2403
|
results.push(`${desc.name} \u2192 ${installedPath} (${methodLabel})`);
|
|
2388
2404
|
}
|
|
2389
|
-
const existing = config.installed_skills[
|
|
2405
|
+
const existing = config.installed_skills[cacheKey];
|
|
2390
2406
|
const skillRecord = {
|
|
2391
|
-
slug,
|
|
2407
|
+
slug: cacheKey,
|
|
2392
2408
|
name: skill.name,
|
|
2409
|
+
type: contentType,
|
|
2393
2410
|
hash: skill.contentHash,
|
|
2394
2411
|
version,
|
|
2395
2412
|
cachedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2396
2413
|
installations: existing ? [...existing.installations, ...installations] : installations
|
|
2397
2414
|
};
|
|
2398
|
-
config.installed_skills[
|
|
2415
|
+
config.installed_skills[cacheKey] = skillRecord;
|
|
2399
2416
|
saveConfig(config);
|
|
2400
2417
|
for (const r of results) {
|
|
2401
2418
|
R2.success(r);
|
|
@@ -2571,6 +2588,8 @@ function scanForSkills(projectDir) {
|
|
|
2571
2588
|
scanDirectory(join12(cwd, ".cursor", "rules"), ".mdc", "cursor", "project", results);
|
|
2572
2589
|
scanClaudeSkills(join12(home, ".claude", "skills"), "global", results);
|
|
2573
2590
|
scanClaudeSkills(join12(cwd, ".claude", "skills"), "project", results);
|
|
2591
|
+
scanDirectory(join12(home, ".claude", "rules"), ".md", "claude", "global", results, "rule");
|
|
2592
|
+
scanDirectory(join12(cwd, ".claude", "rules"), ".md", "claude", "project", results, "rule");
|
|
2574
2593
|
scanSingleFile(join12(home, ".codex", "AGENTS.md"), "codex", "global", results);
|
|
2575
2594
|
scanSingleFile(join12(cwd, "AGENTS.md"), "codex", "project", results);
|
|
2576
2595
|
scanSingleFile(
|
|
@@ -2619,7 +2638,7 @@ function slugFromFilename(filename) {
|
|
|
2619
2638
|
function nameFromSlug(slug) {
|
|
2620
2639
|
return slug.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
2621
2640
|
}
|
|
2622
|
-
function scanDirectory(dir, ext, platform, scope, results) {
|
|
2641
|
+
function scanDirectory(dir, ext, platform, scope, results, contentType = "skill") {
|
|
2623
2642
|
if (!existsSync13(dir)) return;
|
|
2624
2643
|
let entries;
|
|
2625
2644
|
try {
|
|
@@ -2641,7 +2660,8 @@ function scanDirectory(dir, ext, platform, scope, results) {
|
|
|
2641
2660
|
scope,
|
|
2642
2661
|
suggestedName: nameFromSlug(slug),
|
|
2643
2662
|
suggestedSlug: slug,
|
|
2644
|
-
content
|
|
2663
|
+
content,
|
|
2664
|
+
contentType
|
|
2645
2665
|
});
|
|
2646
2666
|
} catch {
|
|
2647
2667
|
}
|
|
@@ -2668,7 +2688,8 @@ function scanClaudeSkills(skillsDir, scope, results) {
|
|
|
2668
2688
|
scope,
|
|
2669
2689
|
suggestedName: nameFromSlug(entry),
|
|
2670
2690
|
suggestedSlug: entry,
|
|
2671
|
-
content
|
|
2691
|
+
content,
|
|
2692
|
+
contentType: "skill"
|
|
2672
2693
|
});
|
|
2673
2694
|
} catch {
|
|
2674
2695
|
}
|
|
@@ -2698,7 +2719,8 @@ function scanSingleFile(filePath, platform, scope, results) {
|
|
|
2698
2719
|
scope,
|
|
2699
2720
|
suggestedName: nameFromSlug(slug2),
|
|
2700
2721
|
suggestedSlug: slug2,
|
|
2701
|
-
content: content2
|
|
2722
|
+
content: content2,
|
|
2723
|
+
contentType: "skill"
|
|
2702
2724
|
});
|
|
2703
2725
|
}
|
|
2704
2726
|
return;
|
|
@@ -2712,7 +2734,8 @@ function scanSingleFile(filePath, platform, scope, results) {
|
|
|
2712
2734
|
scope,
|
|
2713
2735
|
suggestedName: nameFromSlug(slug),
|
|
2714
2736
|
suggestedSlug: slug,
|
|
2715
|
-
content
|
|
2737
|
+
content,
|
|
2738
|
+
contentType: "skill"
|
|
2716
2739
|
});
|
|
2717
2740
|
}
|
|
2718
2741
|
|
|
@@ -2721,7 +2744,7 @@ var publishCommand = new Command6("publish").description("Publish local skill fi
|
|
|
2721
2744
|
"--visibility <visibility>",
|
|
2722
2745
|
"Visibility: public, private, or unlisted",
|
|
2723
2746
|
"private"
|
|
2724
|
-
).option("-m, --message <message>", "Version message").action(
|
|
2747
|
+
).option("--type <type>", "Content type: skill or rule", "skill").option("-m, --message <message>", "Version message").action(
|
|
2725
2748
|
async (fileArg, opts) => {
|
|
2726
2749
|
const client = new ApiClient();
|
|
2727
2750
|
if (!client.isAuthenticated()) {
|
|
@@ -2754,13 +2777,15 @@ var publishCommand = new Command6("publish").description("Publish local skill fi
|
|
|
2754
2777
|
const defaultSlug = basename2(filePath, extname2(filePath));
|
|
2755
2778
|
const defaultName = defaultSlug.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
2756
2779
|
const skillName = opts.name || defaultName;
|
|
2780
|
+
const contentType = validateContentType(opts.type || "skill");
|
|
2757
2781
|
const visibility = validateVisibility(opts.visibility || "private");
|
|
2758
2782
|
const tenantId = await resolveTeam(teams, opts.team);
|
|
2759
2783
|
await uploadSkill(client, {
|
|
2760
2784
|
name: skillName,
|
|
2761
2785
|
content,
|
|
2762
2786
|
tenantId,
|
|
2763
|
-
visibility
|
|
2787
|
+
visibility,
|
|
2788
|
+
type: contentType
|
|
2764
2789
|
});
|
|
2765
2790
|
} else {
|
|
2766
2791
|
We("localskills publish");
|
|
@@ -2777,11 +2802,11 @@ var publishCommand = new Command6("publish").description("Publish local skill fi
|
|
|
2777
2802
|
return;
|
|
2778
2803
|
}
|
|
2779
2804
|
const selected = await je({
|
|
2780
|
-
message: "Select
|
|
2805
|
+
message: "Select items to publish",
|
|
2781
2806
|
options: detected.map((s) => ({
|
|
2782
2807
|
value: s,
|
|
2783
2808
|
label: s.suggestedName,
|
|
2784
|
-
hint: `${s.platform}/${s.scope} ${shortenPath(s.filePath)}`
|
|
2809
|
+
hint: `${s.platform}/${s.scope}/${s.contentType} ${shortenPath(s.filePath)}`
|
|
2785
2810
|
})),
|
|
2786
2811
|
required: true
|
|
2787
2812
|
});
|
|
@@ -2818,11 +2843,24 @@ var publishCommand = new Command6("publish").description("Publish local skill fi
|
|
|
2818
2843
|
Ne("Cancelled.");
|
|
2819
2844
|
process.exit(0);
|
|
2820
2845
|
}
|
|
2846
|
+
const contentType = await Je({
|
|
2847
|
+
message: "Type?",
|
|
2848
|
+
options: [
|
|
2849
|
+
{ value: "skill", label: "Skill", hint: "Reusable agent instructions" },
|
|
2850
|
+
{ value: "rule", label: "Rule", hint: "Governance constraints" }
|
|
2851
|
+
],
|
|
2852
|
+
initialValue: skill.contentType
|
|
2853
|
+
});
|
|
2854
|
+
if (Ct(contentType)) {
|
|
2855
|
+
Ne("Cancelled.");
|
|
2856
|
+
process.exit(0);
|
|
2857
|
+
}
|
|
2821
2858
|
await uploadSkill(client, {
|
|
2822
2859
|
name,
|
|
2823
2860
|
content: skill.content,
|
|
2824
2861
|
tenantId,
|
|
2825
|
-
visibility
|
|
2862
|
+
visibility,
|
|
2863
|
+
type: contentType
|
|
2826
2864
|
});
|
|
2827
2865
|
}
|
|
2828
2866
|
Le("Done!");
|
|
@@ -2862,7 +2900,8 @@ async function uploadSkill(client, params) {
|
|
|
2862
2900
|
name: params.name,
|
|
2863
2901
|
content: params.content,
|
|
2864
2902
|
tenantId: params.tenantId,
|
|
2865
|
-
visibility: params.visibility
|
|
2903
|
+
visibility: params.visibility,
|
|
2904
|
+
type: params.type
|
|
2866
2905
|
});
|
|
2867
2906
|
if (!res.success || !res.data) {
|
|
2868
2907
|
spinner.stop(`Failed: ${res.error || "Unknown error"}`);
|
|
@@ -2871,6 +2910,13 @@ async function uploadSkill(client, params) {
|
|
|
2871
2910
|
spinner.stop(`Published!`);
|
|
2872
2911
|
R2.success(`\u2192 localskills.sh/s/${res.data.slug}`);
|
|
2873
2912
|
}
|
|
2913
|
+
function validateContentType(value) {
|
|
2914
|
+
if (value === "skill" || value === "rule") {
|
|
2915
|
+
return value;
|
|
2916
|
+
}
|
|
2917
|
+
console.error(`Invalid type: ${value}. Use skill or rule.`);
|
|
2918
|
+
process.exit(1);
|
|
2919
|
+
}
|
|
2874
2920
|
function validateVisibility(value) {
|
|
2875
2921
|
if (value === "public" || value === "private" || value === "unlisted") {
|
|
2876
2922
|
return value;
|