@hasna/skills 0.1.64 → 0.1.67
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/README.md +33 -16
- package/bin/index.js +710 -511
- package/bin/mcp.js +285 -239
- package/bin/server.js +791 -232
- package/bin/worker.js +178 -148
- package/dist/index.d.ts +1 -1
- package/dist/index.js +421 -321
- package/dist/lib/agent-sync.d.ts +2 -2
- package/dist/lib/native-storage.d.ts +28 -0
- package/dist/lib/portable-skills.d.ts +14 -0
- package/dist/lib/registry-types.d.ts +9 -0
- package/dist/lib/run-routing.d.ts +60 -0
- package/dist/mcp/index.d.ts +10 -0
- package/dist/sdk/index.js +14095 -14019
- package/dist/server/app.d.ts +3 -0
- package/dist/server/store-fixtures.d.ts +6 -0
- package/dist/storage.d.ts +1 -1
- package/dist/storage.js +50 -0
- package/package.json +3 -1
package/bin/index.js
CHANGED
|
@@ -36860,7 +36860,7 @@ var package_default;
|
|
|
36860
36860
|
var init_package = __esm(() => {
|
|
36861
36861
|
package_default = {
|
|
36862
36862
|
name: "@hasna/skills",
|
|
36863
|
-
version: "0.1.
|
|
36863
|
+
version: "0.1.67",
|
|
36864
36864
|
description: "Skills library for AI coding agents",
|
|
36865
36865
|
type: "module",
|
|
36866
36866
|
bin: {
|
|
@@ -36901,6 +36901,7 @@ var init_package = __esm(() => {
|
|
|
36901
36901
|
scripts: {
|
|
36902
36902
|
clean: "rm -rf bin/ dist/",
|
|
36903
36903
|
build: "bun run clean && bun build ./src/cli/index.tsx --outdir ./bin --target bun && bun build ./src/mcp/index.ts --outfile ./bin/mcp.js --target bun && bun build ./src/server/index.ts --outfile ./bin/server.js --target bun && bun build ./src/server/worker.ts --outfile ./bin/worker.js --target bun && bun build ./src/server/migrate.ts --outfile ./bin/migrate.js --target bun && bun build ./src/index.ts ./src/storage.ts ./src/sdk/index.ts --outdir ./dist --target bun && tsc --emitDeclarationOnly --declaration --outDir dist",
|
|
36904
|
+
"build:js": "rm -rf dist && bun build ./src/index.ts ./src/storage.ts ./src/sdk/index.ts --outdir ./dist --target bun && tsc --emitDeclarationOnly --declaration --outDir dist",
|
|
36904
36905
|
test: "bun test --timeout 30000",
|
|
36905
36906
|
dev: "bun run ./src/cli/index.tsx",
|
|
36906
36907
|
"dev:watch": "bun --watch run ./src/cli/index.tsx",
|
|
@@ -36910,6 +36911,7 @@ var init_package = __esm(() => {
|
|
|
36910
36911
|
migrate: "bun run ./src/server/migrate.ts",
|
|
36911
36912
|
typecheck: "tsc --noEmit",
|
|
36912
36913
|
"verify:release": "bun run scripts/release-guard.ts",
|
|
36914
|
+
prepare: "bun run build:js",
|
|
36913
36915
|
prepack: "bun run build && bun run verify:release",
|
|
36914
36916
|
prepublishOnly: "bun run typecheck && bun run test",
|
|
36915
36917
|
postinstall: "mkdir -p $HOME/.hasna/skills/custom 2>/dev/null || true"
|
|
@@ -38888,6 +38890,8 @@ var init_registry_data = __esm(() => {
|
|
|
38888
38890
|
});
|
|
38889
38891
|
|
|
38890
38892
|
// src/lib/hosted-skill-set.ts
|
|
38893
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
38894
|
+
import { join as join4 } from "path";
|
|
38891
38895
|
function normalizeMarker(value) {
|
|
38892
38896
|
return typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
38893
38897
|
}
|
|
@@ -38897,6 +38901,16 @@ function isHostedMetadataPackage(pkg) {
|
|
|
38897
38901
|
return false;
|
|
38898
38902
|
return HOSTED_RUNTIMES.has(normalizeMarker(skills.runtime)) || HOSTED_SOURCES.has(normalizeMarker(skills.source));
|
|
38899
38903
|
}
|
|
38904
|
+
function isHostedMetadataSkillDir(skillDir) {
|
|
38905
|
+
const pkgPath = join4(skillDir, "package.json");
|
|
38906
|
+
if (!existsSync4(pkgPath))
|
|
38907
|
+
return false;
|
|
38908
|
+
try {
|
|
38909
|
+
return isHostedMetadataPackage(JSON.parse(readFileSync3(pkgPath, "utf8")));
|
|
38910
|
+
} catch {
|
|
38911
|
+
return false;
|
|
38912
|
+
}
|
|
38913
|
+
}
|
|
38900
38914
|
var HOSTED_RUNTIMES, HOSTED_SOURCES, HOSTED_METADATA_SET_EMPTY_ERROR, SLUG = "[^,{}/]+", BRACE_SOURCE_EXCLUSION, SINGLE_SOURCE_EXCLUSION;
|
|
38901
38915
|
var init_hosted_skill_set = __esm(() => {
|
|
38902
38916
|
HOSTED_RUNTIMES = new Set(["hosted"]);
|
|
@@ -38917,13 +38931,13 @@ var init_hosted_skill_set = __esm(() => {
|
|
|
38917
38931
|
});
|
|
38918
38932
|
|
|
38919
38933
|
// src/lib/skill-validation.ts
|
|
38920
|
-
import { existsSync as
|
|
38921
|
-
import { isAbsolute, join as
|
|
38934
|
+
import { existsSync as existsSync5, lstatSync, readFileSync as readFileSync4, readdirSync as readdirSync3, statSync as statSync3 } from "fs";
|
|
38935
|
+
import { isAbsolute, join as join5, normalize } from "path";
|
|
38922
38936
|
function add2(target, code, message) {
|
|
38923
38937
|
target.push({ code, message });
|
|
38924
38938
|
}
|
|
38925
38939
|
function readJsonFile(path) {
|
|
38926
|
-
return JSON.parse(
|
|
38940
|
+
return JSON.parse(readFileSync4(path, "utf-8"));
|
|
38927
38941
|
}
|
|
38928
38942
|
function asRecord(value) {
|
|
38929
38943
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
|
|
@@ -39007,7 +39021,7 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
39007
39021
|
binCommands: [],
|
|
39008
39022
|
docFiles: []
|
|
39009
39023
|
};
|
|
39010
|
-
if (!
|
|
39024
|
+
if (!existsSync5(skillPath)) {
|
|
39011
39025
|
add2(issues, "skill.dir_missing", `Skill directory not found: ${skillPath}`);
|
|
39012
39026
|
return {
|
|
39013
39027
|
name: bareName,
|
|
@@ -39021,8 +39035,8 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
39021
39035
|
if (!VALID_BIN_COMMAND.test(bareName)) {
|
|
39022
39036
|
add2(issues, "skill.name_invalid", `Skill name '${bareName}' must use lowercase letters, numbers, dots, underscores, or hyphens`);
|
|
39023
39037
|
}
|
|
39024
|
-
for (const entry of
|
|
39025
|
-
const entryPath =
|
|
39038
|
+
for (const entry of readdirSync3(skillPath).sort()) {
|
|
39039
|
+
const entryPath = join5(skillPath, entry);
|
|
39026
39040
|
if (RESERVED_SKILL_ENTRIES.has(entry)) {
|
|
39027
39041
|
add2(issues, "skill.reserved_file", `Reserved file '${entry}' is not allowed in skill packages`);
|
|
39028
39042
|
}
|
|
@@ -39034,15 +39048,15 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
39034
39048
|
}
|
|
39035
39049
|
}
|
|
39036
39050
|
for (const docFile of DOC_FILES) {
|
|
39037
|
-
if (
|
|
39051
|
+
if (existsSync5(join5(skillPath, docFile)))
|
|
39038
39052
|
metadata.docFiles.push(docFile);
|
|
39039
39053
|
}
|
|
39040
39054
|
if (metadata.docFiles.length === 0) {
|
|
39041
39055
|
add2(issues, "skill.docs_missing", "Missing documentation file: expected SKILL.md, README.md, or CLAUDE.md");
|
|
39042
39056
|
}
|
|
39043
|
-
const skillMdPath =
|
|
39044
|
-
if (
|
|
39045
|
-
const frontmatter = parseSkillFrontmatter(
|
|
39057
|
+
const skillMdPath = join5(skillPath, "SKILL.md");
|
|
39058
|
+
if (existsSync5(skillMdPath)) {
|
|
39059
|
+
const frontmatter = parseSkillFrontmatter(readFileSync4(skillMdPath, "utf-8"));
|
|
39046
39060
|
if (!frontmatter) {
|
|
39047
39061
|
add2(warnings, "skill.frontmatter_missing", "SKILL.md has no YAML frontmatter");
|
|
39048
39062
|
} else {
|
|
@@ -39084,8 +39098,8 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
39084
39098
|
}
|
|
39085
39099
|
metadata.kind = resolvedKind;
|
|
39086
39100
|
const isInstruction = resolvedKind === "instruction";
|
|
39087
|
-
const pkgPath =
|
|
39088
|
-
if (!
|
|
39101
|
+
const pkgPath = join5(skillPath, "package.json");
|
|
39102
|
+
if (!existsSync5(pkgPath)) {
|
|
39089
39103
|
if (!isInstruction)
|
|
39090
39104
|
add2(issues, "package.missing", "Missing package.json");
|
|
39091
39105
|
} else {
|
|
@@ -39143,10 +39157,10 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
39143
39157
|
add2(issues, "package.bin_target_unsafe", `package.json bin '${command}' target '${target}' must stay inside the skill directory`);
|
|
39144
39158
|
continue;
|
|
39145
39159
|
}
|
|
39146
|
-
const targetPath =
|
|
39147
|
-
if (!
|
|
39160
|
+
const targetPath = join5(skillPath, target);
|
|
39161
|
+
if (!existsSync5(targetPath)) {
|
|
39148
39162
|
add2(warnings, "package.bin_target_missing", `package.json bin '${command}' target '${target}' is not present before build`);
|
|
39149
|
-
} else if (
|
|
39163
|
+
} else if (statSync3(targetPath).isDirectory()) {
|
|
39150
39164
|
add2(issues, "package.bin_target_directory", `package.json bin '${command}' target '${target}' must point to a file, not a directory`);
|
|
39151
39165
|
}
|
|
39152
39166
|
}
|
|
@@ -39161,18 +39175,18 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
39161
39175
|
metadata.runtime = "none";
|
|
39162
39176
|
} else {
|
|
39163
39177
|
metadata.runtime = hostedMetadata ? "hosted" : "local";
|
|
39164
|
-
const srcDir =
|
|
39178
|
+
const srcDir = join5(skillPath, "src");
|
|
39165
39179
|
if (hostedMetadata) {
|
|
39166
|
-
if (
|
|
39180
|
+
if (existsSync5(srcDir)) {
|
|
39167
39181
|
add2(issues, "skill.hosted_source_forbidden", "Hosted metadata skills must not include local implementation source");
|
|
39168
39182
|
}
|
|
39169
|
-
} else if (!
|
|
39183
|
+
} else if (!existsSync5(srcDir)) {
|
|
39170
39184
|
add2(issues, "skill.src_missing", "Missing src/ directory");
|
|
39171
|
-
} else if (!
|
|
39185
|
+
} else if (!existsSync5(join5(srcDir, "index.ts")) && !existsSync5(join5(srcDir, "index.js"))) {
|
|
39172
39186
|
add2(issues, "skill.src_index_missing", "Missing src/index.ts or src/index.js");
|
|
39173
39187
|
} else {
|
|
39174
|
-
const indexPath =
|
|
39175
|
-
const size2 =
|
|
39188
|
+
const indexPath = existsSync5(join5(srcDir, "index.ts")) ? join5(srcDir, "index.ts") : join5(srcDir, "index.js");
|
|
39189
|
+
const size2 = statSync3(indexPath).size;
|
|
39176
39190
|
if (size2 < 50)
|
|
39177
39191
|
add2(warnings, "skill.src_index_minimal", `Source entry point is very small (${size2}B)`);
|
|
39178
39192
|
}
|
|
@@ -39242,8 +39256,8 @@ var init_skill_validation = __esm(() => {
|
|
|
39242
39256
|
|
|
39243
39257
|
// src/lib/skill-hash.ts
|
|
39244
39258
|
import { createHash } from "crypto";
|
|
39245
|
-
import { existsSync as
|
|
39246
|
-
import { join as
|
|
39259
|
+
import { existsSync as existsSync6, readdirSync as readdirSync4, readFileSync as readFileSync5, statSync as statSync4 } from "fs";
|
|
39260
|
+
import { join as join6, sep } from "path";
|
|
39247
39261
|
function normalizeLineEndings(content) {
|
|
39248
39262
|
return content.replace(/\r\n/g, `
|
|
39249
39263
|
`).replace(/\r/g, `
|
|
@@ -39289,10 +39303,10 @@ function collectBundleFiles(skillPath) {
|
|
|
39289
39303
|
if (seen.has(entry))
|
|
39290
39304
|
continue;
|
|
39291
39305
|
seen.add(entry);
|
|
39292
|
-
const absolute =
|
|
39293
|
-
if (!
|
|
39306
|
+
const absolute = join6(skillPath, entry);
|
|
39307
|
+
if (!existsSync6(absolute))
|
|
39294
39308
|
continue;
|
|
39295
|
-
if (
|
|
39309
|
+
if (statSync4(absolute).isDirectory())
|
|
39296
39310
|
collectDirectory(files, absolute, entry);
|
|
39297
39311
|
else
|
|
39298
39312
|
collectFile(files, absolute, entry);
|
|
@@ -39300,14 +39314,14 @@ function collectBundleFiles(skillPath) {
|
|
|
39300
39314
|
return files.sort((a, b) => a.rel < b.rel ? -1 : a.rel > b.rel ? 1 : 0);
|
|
39301
39315
|
}
|
|
39302
39316
|
function collectDirectory(files, dir, rel) {
|
|
39303
|
-
for (const entry of
|
|
39317
|
+
for (const entry of readdirSync4(dir).sort()) {
|
|
39304
39318
|
if (entry.startsWith("."))
|
|
39305
39319
|
continue;
|
|
39306
|
-
const absolute =
|
|
39320
|
+
const absolute = join6(dir, entry);
|
|
39307
39321
|
const childRel = `${rel}/${entry}`;
|
|
39308
39322
|
let stats;
|
|
39309
39323
|
try {
|
|
39310
|
-
stats =
|
|
39324
|
+
stats = statSync4(absolute);
|
|
39311
39325
|
} catch {
|
|
39312
39326
|
continue;
|
|
39313
39327
|
}
|
|
@@ -39323,7 +39337,7 @@ function collectDirectory(files, dir, rel) {
|
|
|
39323
39337
|
}
|
|
39324
39338
|
}
|
|
39325
39339
|
function collectFile(files, absolute, rel) {
|
|
39326
|
-
const buffer =
|
|
39340
|
+
const buffer = readFileSync5(absolute);
|
|
39327
39341
|
if (rel === "skill.json") {
|
|
39328
39342
|
files.push({ rel: rel.split(sep).join("/"), content: new TextEncoder().encode(canonicalizeManifest(new TextDecoder().decode(buffer))) });
|
|
39329
39343
|
return;
|
|
@@ -39378,7 +39392,7 @@ function hashSkillMarkdown(content) {
|
|
|
39378
39392
|
return hash.digest("hex");
|
|
39379
39393
|
}
|
|
39380
39394
|
function hashSkillMarkdownFile(path) {
|
|
39381
|
-
return hashSkillMarkdown(
|
|
39395
|
+
return hashSkillMarkdown(readFileSync5(path, "utf-8"));
|
|
39382
39396
|
}
|
|
39383
39397
|
var CONTENT_HASH_ALGORITHM = "sha256", HASH_EXCLUDE_DIRS, HASH_COVERAGE;
|
|
39384
39398
|
var init_skill_hash = __esm(() => {
|
|
@@ -39558,14 +39572,14 @@ var init_skill_contract = __esm(() => {
|
|
|
39558
39572
|
// src/lib/portable-skills-files.ts
|
|
39559
39573
|
import {
|
|
39560
39574
|
cpSync,
|
|
39561
|
-
existsSync as
|
|
39575
|
+
existsSync as existsSync7,
|
|
39562
39576
|
lstatSync as lstatSync2,
|
|
39563
39577
|
mkdirSync as mkdirSync2,
|
|
39564
|
-
readFileSync as
|
|
39578
|
+
readFileSync as readFileSync6,
|
|
39565
39579
|
realpathSync,
|
|
39566
39580
|
writeFileSync as writeFileSync2
|
|
39567
39581
|
} from "fs";
|
|
39568
|
-
import { basename, dirname as dirname2, join as
|
|
39582
|
+
import { basename, dirname as dirname2, join as join7, relative } from "path";
|
|
39569
39583
|
function defaultRuntimeContract(entrypoint = "src/index.ts") {
|
|
39570
39584
|
return {
|
|
39571
39585
|
runtime: "bun",
|
|
@@ -39589,12 +39603,12 @@ function normalizePortableSkillName(name) {
|
|
|
39589
39603
|
return normalized;
|
|
39590
39604
|
}
|
|
39591
39605
|
function readPortableSkillManifest(skillPath, fallbackName = basename(skillPath)) {
|
|
39592
|
-
const skillJsonPath =
|
|
39593
|
-
const skillMdPath =
|
|
39594
|
-
const pkgPath =
|
|
39595
|
-
const jsonManifest =
|
|
39596
|
-
const frontmatter =
|
|
39597
|
-
const pkg =
|
|
39606
|
+
const skillJsonPath = join7(skillPath, "skill.json");
|
|
39607
|
+
const skillMdPath = join7(skillPath, "SKILL.md");
|
|
39608
|
+
const pkgPath = join7(skillPath, "package.json");
|
|
39609
|
+
const jsonManifest = existsSync7(skillJsonPath) ? readJsonObject(skillJsonPath) : undefined;
|
|
39610
|
+
const frontmatter = existsSync7(skillMdPath) ? parseSkillFrontmatter(readFileSync6(skillMdPath, "utf-8")) ?? undefined : undefined;
|
|
39611
|
+
const pkg = existsSync7(pkgPath) ? readJsonObject(pkgPath) : undefined;
|
|
39598
39612
|
const name = normalizePortableSkillName(stringField(jsonManifest, "name") ?? frontmatter?.name ?? stringValue(pkg?.name) ?? fallbackName);
|
|
39599
39613
|
const description = stringField(jsonManifest, "description") ?? frontmatter?.description ?? stringValue(pkg?.description) ?? `${name} skill`;
|
|
39600
39614
|
const version = stringField(jsonManifest, "version") ?? frontmatter?.version ?? stringValue(pkg?.version) ?? PORTABLE_SKILL_DEFAULT_VERSION;
|
|
@@ -39640,7 +39654,7 @@ function createInstructionManifest(name, options) {
|
|
|
39640
39654
|
}
|
|
39641
39655
|
function writeInstructionSkillTemplate(skillPath, manifest) {
|
|
39642
39656
|
mkdirSync2(skillPath, { recursive: true });
|
|
39643
|
-
writeFileSync2(
|
|
39657
|
+
writeFileSync2(join7(skillPath, "SKILL.md"), renderInstructionSkillMd(manifest));
|
|
39644
39658
|
writeSkillJsonWithHash(skillPath, manifest);
|
|
39645
39659
|
}
|
|
39646
39660
|
function renderInstructionSkillMd(manifest) {
|
|
@@ -39689,12 +39703,12 @@ function createPortableManifest(name, options) {
|
|
|
39689
39703
|
};
|
|
39690
39704
|
}
|
|
39691
39705
|
function writePortableSkillTemplate(skillPath, manifest) {
|
|
39692
|
-
mkdirSync2(
|
|
39693
|
-
writeFileSync2(
|
|
39694
|
-
writeFileSync2(
|
|
39695
|
-
writeFileSync2(
|
|
39696
|
-
writeFileSync2(
|
|
39697
|
-
writeFileSync2(
|
|
39706
|
+
mkdirSync2(join7(skillPath, "src"), { recursive: true });
|
|
39707
|
+
writeFileSync2(join7(skillPath, "SKILL.md"), renderSkillMd(manifest));
|
|
39708
|
+
writeFileSync2(join7(skillPath, "AGENTS.md"), renderAgentsMd(manifest));
|
|
39709
|
+
writeFileSync2(join7(skillPath, "package.json"), renderPackageJson(manifest));
|
|
39710
|
+
writeFileSync2(join7(skillPath, "tsconfig.json"), renderTsconfig());
|
|
39711
|
+
writeFileSync2(join7(skillPath, "src", "index.ts"), renderEntrypoint(manifest));
|
|
39698
39712
|
writeSkillJsonWithHash(skillPath, manifest);
|
|
39699
39713
|
}
|
|
39700
39714
|
function fillContractDefaults(manifest, entrypoint) {
|
|
@@ -39719,7 +39733,7 @@ function writeSkillJsonWithHash(skillPath, manifest) {
|
|
|
39719
39733
|
content_hash: undefined
|
|
39720
39734
|
}
|
|
39721
39735
|
};
|
|
39722
|
-
writeFileSync2(
|
|
39736
|
+
writeFileSync2(join7(skillPath, "skill.json"), `${JSON.stringify({ ...existing, ...renderSkillJsonObject(withoutHash) }, null, 2)}
|
|
39723
39737
|
`);
|
|
39724
39738
|
const hash = computeContentHash(skillPath);
|
|
39725
39739
|
const withHash = {
|
|
@@ -39729,16 +39743,16 @@ function writeSkillJsonWithHash(skillPath, manifest) {
|
|
|
39729
39743
|
content_hash: hash
|
|
39730
39744
|
}
|
|
39731
39745
|
};
|
|
39732
|
-
writeFileSync2(
|
|
39746
|
+
writeFileSync2(join7(skillPath, "skill.json"), `${JSON.stringify({ ...existing, ...renderSkillJsonObject(withHash) }, null, 2)}
|
|
39733
39747
|
`);
|
|
39734
39748
|
return withHash;
|
|
39735
39749
|
}
|
|
39736
39750
|
function readExistingSkillJson(skillPath) {
|
|
39737
|
-
const path =
|
|
39738
|
-
if (!
|
|
39751
|
+
const path = join7(skillPath, "skill.json");
|
|
39752
|
+
if (!existsSync7(path))
|
|
39739
39753
|
return {};
|
|
39740
39754
|
try {
|
|
39741
|
-
const parsed = JSON.parse(
|
|
39755
|
+
const parsed = JSON.parse(readFileSync6(path, "utf-8"));
|
|
39742
39756
|
return isRecord2(parsed) ? parsed : {};
|
|
39743
39757
|
} catch {
|
|
39744
39758
|
return {};
|
|
@@ -39768,28 +39782,28 @@ function ensurePortableSkillFiles(skillPath, manifest) {
|
|
|
39768
39782
|
tags: next.tags?.length ? next.tags : ["custom", next.name]
|
|
39769
39783
|
};
|
|
39770
39784
|
const entry = next.commands[0]?.entry ?? "src/index.ts";
|
|
39771
|
-
if (entry && !
|
|
39772
|
-
mkdirSync2(dirname2(
|
|
39773
|
-
writeFileSync2(
|
|
39785
|
+
if (entry && !existsSync7(join7(skillPath, entry))) {
|
|
39786
|
+
mkdirSync2(dirname2(join7(skillPath, entry)), { recursive: true });
|
|
39787
|
+
writeFileSync2(join7(skillPath, entry), renderEntrypoint(next));
|
|
39774
39788
|
}
|
|
39775
|
-
if (!
|
|
39776
|
-
writeFileSync2(
|
|
39789
|
+
if (!existsSync7(join7(skillPath, "SKILL.md")))
|
|
39790
|
+
writeFileSync2(join7(skillPath, "SKILL.md"), renderSkillMd(next));
|
|
39777
39791
|
else
|
|
39778
|
-
writeFileSync2(
|
|
39779
|
-
if (!
|
|
39780
|
-
writeFileSync2(
|
|
39792
|
+
writeFileSync2(join7(skillPath, "SKILL.md"), ensureSkillMdFrontmatter(readFileSync6(join7(skillPath, "SKILL.md"), "utf-8"), next));
|
|
39793
|
+
if (!existsSync7(join7(skillPath, "AGENTS.md")))
|
|
39794
|
+
writeFileSync2(join7(skillPath, "AGENTS.md"), renderAgentsMd(next));
|
|
39781
39795
|
ensurePackageJson(skillPath, next);
|
|
39782
|
-
if (!
|
|
39783
|
-
writeFileSync2(
|
|
39796
|
+
if (!existsSync7(join7(skillPath, "tsconfig.json")))
|
|
39797
|
+
writeFileSync2(join7(skillPath, "tsconfig.json"), renderTsconfig());
|
|
39784
39798
|
writeSkillJsonWithHash(skillPath, next);
|
|
39785
39799
|
return readPortableSkillManifest(skillPath, next.name);
|
|
39786
39800
|
}
|
|
39787
39801
|
function ensurePackageJson(skillPath, manifest) {
|
|
39788
|
-
const pkgPath =
|
|
39802
|
+
const pkgPath = join7(skillPath, "package.json");
|
|
39789
39803
|
const first = manifest.commands[0] ?? { name: manifest.name, entry: "src/index.ts" };
|
|
39790
39804
|
const commandName = normalizePortableSkillName(first.name || manifest.name);
|
|
39791
39805
|
const entry = (first.entry ?? "src/index.ts").replace(/^\.\//, "");
|
|
39792
|
-
if (!
|
|
39806
|
+
if (!existsSync7(pkgPath)) {
|
|
39793
39807
|
writeFileSync2(pkgPath, renderPackageJson(manifest));
|
|
39794
39808
|
return;
|
|
39795
39809
|
}
|
|
@@ -39832,8 +39846,8 @@ function ensureInstructionSkillFiles(skillPath, manifest) {
|
|
|
39832
39846
|
inputs: [],
|
|
39833
39847
|
commands: []
|
|
39834
39848
|
};
|
|
39835
|
-
if (!
|
|
39836
|
-
writeFileSync2(
|
|
39849
|
+
if (!existsSync7(join7(skillPath, "SKILL.md"))) {
|
|
39850
|
+
writeFileSync2(join7(skillPath, "SKILL.md"), renderSkillMd(next));
|
|
39837
39851
|
}
|
|
39838
39852
|
writeSkillJsonWithHash(skillPath, next);
|
|
39839
39853
|
return readPortableSkillManifest(skillPath, next.name);
|
|
@@ -40084,7 +40098,7 @@ function inferPackageCommands(pkg, fallbackName) {
|
|
|
40084
40098
|
return;
|
|
40085
40099
|
}
|
|
40086
40100
|
function readJsonObject(path) {
|
|
40087
|
-
const parsed = JSON.parse(
|
|
40101
|
+
const parsed = JSON.parse(readFileSync6(path, "utf-8"));
|
|
40088
40102
|
if (!isRecord2(parsed))
|
|
40089
40103
|
throw new Error(`${basename(path)} must contain a JSON object`);
|
|
40090
40104
|
return parsed;
|
|
@@ -40140,48 +40154,49 @@ var init_portable_skills_files = __esm(() => {
|
|
|
40140
40154
|
// src/lib/portable-skills.ts
|
|
40141
40155
|
import {
|
|
40142
40156
|
cpSync as cpSync2,
|
|
40143
|
-
existsSync as
|
|
40157
|
+
existsSync as existsSync8,
|
|
40144
40158
|
mkdirSync as mkdirSync3,
|
|
40145
|
-
|
|
40159
|
+
mkdtempSync,
|
|
40160
|
+
readdirSync as readdirSync5,
|
|
40146
40161
|
renameSync,
|
|
40147
40162
|
rmSync,
|
|
40148
|
-
statSync as
|
|
40163
|
+
statSync as statSync6,
|
|
40149
40164
|
writeFileSync as writeFileSync3
|
|
40150
40165
|
} from "fs";
|
|
40151
|
-
import { basename as basename2, dirname as dirname3, isAbsolute as isAbsolute2, join as
|
|
40166
|
+
import { basename as basename2, dirname as dirname3, isAbsolute as isAbsolute2, join as join8, normalize as normalize2 } from "path";
|
|
40152
40167
|
function getPortableSkillsRoot(options = {}) {
|
|
40153
40168
|
if (options.rootDir)
|
|
40154
40169
|
return options.rootDir;
|
|
40155
|
-
const appDir = options.homeDir ?
|
|
40156
|
-
const cache3 =
|
|
40170
|
+
const appDir = options.homeDir ? join8(options.homeDir, ".hasna", "skills") : getDataDir();
|
|
40171
|
+
const cache3 = join8(appDir, SKILLS_CACHE_DIRNAME);
|
|
40157
40172
|
if (isOwnerLayoutMigrated(appDir) && safeIsDirectory(cache3))
|
|
40158
40173
|
return cache3;
|
|
40159
|
-
const installed =
|
|
40174
|
+
const installed = join8(appDir, INSTALLED_SKILLS_DIRNAME);
|
|
40160
40175
|
migrateLegacySkillLayout(appDir, installed);
|
|
40161
40176
|
return installed;
|
|
40162
40177
|
}
|
|
40163
40178
|
function looksLikeSkillDirectory(path) {
|
|
40164
40179
|
if (!safeIsDirectory(path))
|
|
40165
40180
|
return false;
|
|
40166
|
-
return
|
|
40181
|
+
return existsSync8(join8(path, "SKILL.md")) || existsSync8(join8(path, "skill.json")) || existsSync8(join8(path, "package.json"));
|
|
40167
40182
|
}
|
|
40168
40183
|
function migrateLegacySkillLayout(appDir, installed) {
|
|
40169
40184
|
if (!safeIsDirectory(appDir))
|
|
40170
40185
|
return;
|
|
40171
40186
|
const candidates = [];
|
|
40172
40187
|
try {
|
|
40173
|
-
for (const entry of
|
|
40188
|
+
for (const entry of readdirSync5(appDir)) {
|
|
40174
40189
|
if (entry.startsWith(".") || entry === INSTALLED_SKILLS_DIRNAME)
|
|
40175
40190
|
continue;
|
|
40176
|
-
const path =
|
|
40191
|
+
const path = join8(appDir, entry);
|
|
40177
40192
|
if (entry === LEGACY_CUSTOM_DIRNAME) {
|
|
40178
40193
|
if (!safeIsDirectory(path))
|
|
40179
40194
|
continue;
|
|
40180
40195
|
try {
|
|
40181
|
-
for (const nested of
|
|
40196
|
+
for (const nested of readdirSync5(path)) {
|
|
40182
40197
|
if (nested.startsWith("."))
|
|
40183
40198
|
continue;
|
|
40184
|
-
const nestedPath =
|
|
40199
|
+
const nestedPath = join8(path, nested);
|
|
40185
40200
|
if (looksLikeSkillDirectory(nestedPath))
|
|
40186
40201
|
candidates.push({ from: nestedPath, name: nested });
|
|
40187
40202
|
}
|
|
@@ -40195,10 +40210,10 @@ function migrateLegacySkillLayout(appDir, installed) {
|
|
|
40195
40210
|
return;
|
|
40196
40211
|
}
|
|
40197
40212
|
for (const { from, name } of candidates) {
|
|
40198
|
-
const target =
|
|
40199
|
-
if (
|
|
40213
|
+
const target = join8(installed, name);
|
|
40214
|
+
if (existsSync8(target))
|
|
40200
40215
|
continue;
|
|
40201
|
-
const staging =
|
|
40216
|
+
const staging = join8(installed, `.migrating-${name}-${process.pid}`);
|
|
40202
40217
|
try {
|
|
40203
40218
|
rmSync(staging, { recursive: true, force: true });
|
|
40204
40219
|
cpSync2(from, staging, { recursive: true, errorOnExist: false });
|
|
@@ -40211,7 +40226,7 @@ function migrateLegacySkillLayout(appDir, installed) {
|
|
|
40211
40226
|
}
|
|
40212
40227
|
}
|
|
40213
40228
|
function getPortableSkillPath(name, options = {}) {
|
|
40214
|
-
return
|
|
40229
|
+
return join8(getPortableSkillsRoot(options), normalizePortableSkillName(name));
|
|
40215
40230
|
}
|
|
40216
40231
|
function findPortableSkill(name, options = {}) {
|
|
40217
40232
|
let normalized;
|
|
@@ -40221,7 +40236,7 @@ function findPortableSkill(name, options = {}) {
|
|
|
40221
40236
|
return null;
|
|
40222
40237
|
}
|
|
40223
40238
|
const path = getPortableSkillPath(normalized, options);
|
|
40224
|
-
if (!
|
|
40239
|
+
if (!existsSync8(path) || !statSync6(path).isDirectory())
|
|
40225
40240
|
return null;
|
|
40226
40241
|
try {
|
|
40227
40242
|
return summarizePortableSkill(path, normalized);
|
|
@@ -40234,10 +40249,10 @@ function listPortableSkills(options = {}) {
|
|
|
40234
40249
|
if (!safeIsDirectory(root))
|
|
40235
40250
|
return [];
|
|
40236
40251
|
const skills = [];
|
|
40237
|
-
for (const entry of
|
|
40252
|
+
for (const entry of readdirSync5(root).sort()) {
|
|
40238
40253
|
if (entry.startsWith("."))
|
|
40239
40254
|
continue;
|
|
40240
|
-
const path =
|
|
40255
|
+
const path = join8(root, entry);
|
|
40241
40256
|
if (!safeIsDirectory(path))
|
|
40242
40257
|
continue;
|
|
40243
40258
|
try {
|
|
@@ -40259,7 +40274,8 @@ function listPortableSkillMetas(options = {}) {
|
|
|
40259
40274
|
tags: manifest.tags || ["custom"],
|
|
40260
40275
|
version: skill.version,
|
|
40261
40276
|
...manifest.kind ? { kind: manifest.kind } : {},
|
|
40262
|
-
source: "custom"
|
|
40277
|
+
source: "custom",
|
|
40278
|
+
...isHostedMetadataSkillDir(skill.path) ? { serverOwned: true } : {}
|
|
40263
40279
|
};
|
|
40264
40280
|
});
|
|
40265
40281
|
}
|
|
@@ -40269,8 +40285,8 @@ function isOfficialSkillName(name) {
|
|
|
40269
40285
|
function scaffoldPortableSkill(name, options = {}) {
|
|
40270
40286
|
const skillName = normalizePortableSkillName(name);
|
|
40271
40287
|
const root = getPortableSkillsRoot(options);
|
|
40272
|
-
const skillPath =
|
|
40273
|
-
if (
|
|
40288
|
+
const skillPath = join8(root, skillName);
|
|
40289
|
+
if (existsSync8(skillPath)) {
|
|
40274
40290
|
if (!options.overwrite)
|
|
40275
40291
|
throw new Error(`Skill '${skillName}' already exists at ${skillPath}`);
|
|
40276
40292
|
rmSync(skillPath, { recursive: true, force: true });
|
|
@@ -40288,7 +40304,7 @@ function scaffoldPortableSkill(name, options = {}) {
|
|
|
40288
40304
|
}
|
|
40289
40305
|
function portPortableSkillDirectory(sourceDir, options = {}) {
|
|
40290
40306
|
const absoluteSource = normalize2(sourceDir);
|
|
40291
|
-
if (!
|
|
40307
|
+
if (!existsSync8(absoluteSource) || !statSync6(absoluteSource).isDirectory()) {
|
|
40292
40308
|
throw new Error(`Import directory not found: ${sourceDir}`);
|
|
40293
40309
|
}
|
|
40294
40310
|
const continueOnError = options.continueOnError ?? true;
|
|
@@ -40299,9 +40315,9 @@ function portPortableSkillDirectory(sourceDir, options = {}) {
|
|
|
40299
40315
|
};
|
|
40300
40316
|
const imported = [];
|
|
40301
40317
|
const skipped = [];
|
|
40302
|
-
const entries =
|
|
40318
|
+
const entries = readdirSync5(absoluteSource, { withFileTypes: true }).map((entry) => entry.name).filter((entryName) => !entryName.startsWith(".")).sort();
|
|
40303
40319
|
for (const entryName of entries) {
|
|
40304
|
-
const childPath =
|
|
40320
|
+
const childPath = join8(absoluteSource, entryName);
|
|
40305
40321
|
if (!safeIsDirectory(childPath))
|
|
40306
40322
|
continue;
|
|
40307
40323
|
if (!isSkillCandidate(childPath)) {
|
|
@@ -40330,11 +40346,11 @@ function portPortableSkillDirectory(sourceDir, options = {}) {
|
|
|
40330
40346
|
};
|
|
40331
40347
|
}
|
|
40332
40348
|
function isSkillCandidate(dir) {
|
|
40333
|
-
return
|
|
40349
|
+
return existsSync8(join8(dir, "SKILL.md")) || existsSync8(join8(dir, "skill.json")) || existsSync8(join8(dir, "package.json"));
|
|
40334
40350
|
}
|
|
40335
40351
|
function portPortableSkill(sourcePath, options = {}) {
|
|
40336
40352
|
const absoluteSource = normalize2(sourcePath);
|
|
40337
|
-
if (!
|
|
40353
|
+
if (!existsSync8(absoluteSource) || !statSync6(absoluteSource).isDirectory()) {
|
|
40338
40354
|
throw new Error(`Skill source directory not found: ${sourcePath}`);
|
|
40339
40355
|
}
|
|
40340
40356
|
const inferred = readPortableSkillManifest(absoluteSource, basename2(absoluteSource));
|
|
@@ -40346,8 +40362,8 @@ function portPortableSkill(sourcePath, options = {}) {
|
|
|
40346
40362
|
throw new Error(`${via} Importing it would shadow the official '${skillName}'. ` + `Pass --name to choose a different name, or --allow-shadow to override deliberately.`);
|
|
40347
40363
|
}
|
|
40348
40364
|
const root = getPortableSkillsRoot(options);
|
|
40349
|
-
const destination =
|
|
40350
|
-
if (
|
|
40365
|
+
const destination = join8(root, skillName);
|
|
40366
|
+
if (existsSync8(destination)) {
|
|
40351
40367
|
if (!options.overwrite)
|
|
40352
40368
|
throw new Error(`Skill '${skillName}' already exists at ${destination}`);
|
|
40353
40369
|
rmSync(destination, { recursive: true, force: true });
|
|
@@ -40369,16 +40385,10 @@ function safeNormalizeName(name) {
|
|
|
40369
40385
|
return;
|
|
40370
40386
|
}
|
|
40371
40387
|
}
|
|
40372
|
-
function
|
|
40373
|
-
const name = normalizePortableSkillName(input.name);
|
|
40374
|
-
const root = getPortableSkillsRoot(options);
|
|
40375
|
-
const skillPath = join7(root, name);
|
|
40376
|
-
const created = !existsSync7(skillPath);
|
|
40377
|
-
mkdirSync3(skillPath, { recursive: true });
|
|
40378
|
-
writeFileSync3(join7(skillPath, "SKILL.md"), input.skillMd);
|
|
40388
|
+
function buildCorpusManifest(input, name) {
|
|
40379
40389
|
const frontmatter = parseSkillFrontmatter(input.skillMd) ?? undefined;
|
|
40380
40390
|
const kind = input.meta?.kind ?? parseSkillKind(frontmatter?.kind) ?? "instruction";
|
|
40381
|
-
|
|
40391
|
+
return {
|
|
40382
40392
|
$schema: PORTABLE_SKILL_SCHEMA,
|
|
40383
40393
|
standard: PORTABLE_SKILL_STANDARD,
|
|
40384
40394
|
name,
|
|
@@ -40391,8 +40401,38 @@ function writeCorpusSkill(input, options = {}) {
|
|
|
40391
40401
|
inputs: [],
|
|
40392
40402
|
commands: []
|
|
40393
40403
|
};
|
|
40394
|
-
|
|
40395
|
-
|
|
40404
|
+
}
|
|
40405
|
+
function installCorpusSkillAtomically(input, options = {}) {
|
|
40406
|
+
const name = normalizePortableSkillName(input.name);
|
|
40407
|
+
const root = getPortableSkillsRoot(options);
|
|
40408
|
+
const target = join8(root, name);
|
|
40409
|
+
const created = !existsSync8(target);
|
|
40410
|
+
mkdirSync3(root, { recursive: true });
|
|
40411
|
+
const staging = mkdtempSync(join8(root, `.pull-${name}-`));
|
|
40412
|
+
let moved = false;
|
|
40413
|
+
let backup = null;
|
|
40414
|
+
try {
|
|
40415
|
+
writeFileSync3(join8(staging, "SKILL.md"), input.skillMd);
|
|
40416
|
+
const manifest = buildCorpusManifest(input, name);
|
|
40417
|
+
writeSkillJsonWithHash(staging, manifest);
|
|
40418
|
+
if (existsSync8(target)) {
|
|
40419
|
+
backup = mkdtempSync(join8(root, `.pull-backup-${name}-`));
|
|
40420
|
+
renameSync(target, join8(backup, name));
|
|
40421
|
+
moved = true;
|
|
40422
|
+
}
|
|
40423
|
+
renameSync(staging, target);
|
|
40424
|
+
if (moved && backup)
|
|
40425
|
+
rmSync(backup, { recursive: true, force: true });
|
|
40426
|
+
return { name, path: target, manifest, created };
|
|
40427
|
+
} catch (error) {
|
|
40428
|
+
rmSync(staging, { recursive: true, force: true });
|
|
40429
|
+
if (moved && backup && existsSync8(join8(backup, name))) {
|
|
40430
|
+
try {
|
|
40431
|
+
renameSync(join8(backup, name), target);
|
|
40432
|
+
} catch {}
|
|
40433
|
+
}
|
|
40434
|
+
throw error;
|
|
40435
|
+
}
|
|
40396
40436
|
}
|
|
40397
40437
|
function validatePortableSkillDirectory(name, skillPath) {
|
|
40398
40438
|
const normalizedName = normalizePortableSkillName(name);
|
|
@@ -40400,10 +40440,10 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
40400
40440
|
const issues = [...base2.issues];
|
|
40401
40441
|
const warnings = [...base2.warnings];
|
|
40402
40442
|
let manifest;
|
|
40403
|
-
if (
|
|
40404
|
-
const skillJsonPath =
|
|
40405
|
-
const skillMdPath =
|
|
40406
|
-
if (!
|
|
40443
|
+
if (existsSync8(skillPath)) {
|
|
40444
|
+
const skillJsonPath = join8(skillPath, "skill.json");
|
|
40445
|
+
const skillMdPath = join8(skillPath, "SKILL.md");
|
|
40446
|
+
if (!existsSync8(skillJsonPath) && !existsSync8(skillMdPath)) {
|
|
40407
40447
|
add4(issues, "portable.manifest_missing", "Missing portable manifest: expected SKILL.md frontmatter and/or skill.json");
|
|
40408
40448
|
}
|
|
40409
40449
|
try {
|
|
@@ -40422,7 +40462,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
40422
40462
|
add4(issues, "portable.version_missing", "Portable manifest missing version");
|
|
40423
40463
|
}
|
|
40424
40464
|
const contractIssues = validatePortableManifestContract(manifest, {
|
|
40425
|
-
strict:
|
|
40465
|
+
strict: existsSync8(join8(skillPath, "skill.json")),
|
|
40426
40466
|
skillPath
|
|
40427
40467
|
});
|
|
40428
40468
|
for (const issue of contractIssues)
|
|
@@ -40458,10 +40498,10 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
40458
40498
|
add4(issues, "portable.command_entry_unsafe", `Command '${command.name}' entry '${command.entry}' must stay inside the skill directory`);
|
|
40459
40499
|
continue;
|
|
40460
40500
|
}
|
|
40461
|
-
const entryPath =
|
|
40462
|
-
if (!
|
|
40501
|
+
const entryPath = join8(skillPath, command.entry);
|
|
40502
|
+
if (!existsSync8(entryPath))
|
|
40463
40503
|
add4(issues, "portable.command_entry_missing", `Command '${command.name}' entry '${command.entry}' is missing`);
|
|
40464
|
-
else if (
|
|
40504
|
+
else if (statSync6(entryPath).isDirectory())
|
|
40465
40505
|
add4(issues, "portable.command_entry_directory", `Command '${command.name}' entry '${command.entry}' must be a file`);
|
|
40466
40506
|
}
|
|
40467
40507
|
}
|
|
@@ -40469,7 +40509,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
40469
40509
|
} catch (error) {
|
|
40470
40510
|
add4(issues, "portable.manifest_invalid", error.message);
|
|
40471
40511
|
}
|
|
40472
|
-
if (manifest?.kind !== "instruction" && !
|
|
40512
|
+
if (manifest?.kind !== "instruction" && !existsSync8(join8(skillPath, "AGENTS.md"))) {
|
|
40473
40513
|
add4(issues, "portable.agents_missing", "Missing AGENTS.md with build-out instructions for coding agents");
|
|
40474
40514
|
}
|
|
40475
40515
|
}
|
|
@@ -40501,7 +40541,7 @@ function summarizePortableSkill(skillPath, fallbackName) {
|
|
|
40501
40541
|
}
|
|
40502
40542
|
function safeIsDirectory(path) {
|
|
40503
40543
|
try {
|
|
40504
|
-
return
|
|
40544
|
+
return statSync6(path).isDirectory();
|
|
40505
40545
|
} catch {
|
|
40506
40546
|
return false;
|
|
40507
40547
|
}
|
|
@@ -40522,6 +40562,7 @@ var LEGACY_CUSTOM_DIRNAME = "custom", OFFICIAL_SKILL_NAMES;
|
|
|
40522
40562
|
var init_portable_skills = __esm(() => {
|
|
40523
40563
|
init_config();
|
|
40524
40564
|
init_registry_data();
|
|
40565
|
+
init_hosted_skill_set();
|
|
40525
40566
|
init_skill_validation();
|
|
40526
40567
|
init_skill_contract();
|
|
40527
40568
|
init_portable_skills_files();
|
|
@@ -40737,8 +40778,8 @@ __export(exports_registry, {
|
|
|
40737
40778
|
CATEGORIES: () => CATEGORIES,
|
|
40738
40779
|
BASIC_SKILL_NAMES: () => BASIC_SKILL_NAMES
|
|
40739
40780
|
});
|
|
40740
|
-
import { existsSync as
|
|
40741
|
-
import { join as
|
|
40781
|
+
import { existsSync as existsSync9, readFileSync as readFileSync7, readdirSync as readdirSync6 } from "fs";
|
|
40782
|
+
import { join as join9 } from "path";
|
|
40742
40783
|
function isBasicSkillName(name) {
|
|
40743
40784
|
return BASIC_SKILL_NAMES.includes(name);
|
|
40744
40785
|
}
|
|
@@ -40774,20 +40815,20 @@ function parseSkillMdFrontmatter(content) {
|
|
|
40774
40815
|
return Object.keys(result2).length > 0 ? result2 : null;
|
|
40775
40816
|
}
|
|
40776
40817
|
function discoverSkillsInDir(dir, source = "custom") {
|
|
40777
|
-
if (!
|
|
40818
|
+
if (!existsSync9(dir))
|
|
40778
40819
|
return [];
|
|
40779
40820
|
const result2 = [];
|
|
40780
40821
|
try {
|
|
40781
|
-
const entries =
|
|
40822
|
+
const entries = readdirSync6(dir, { withFileTypes: true });
|
|
40782
40823
|
for (const entry of entries) {
|
|
40783
40824
|
if (!entry.isDirectory())
|
|
40784
40825
|
continue;
|
|
40785
|
-
const skillMdPath =
|
|
40786
|
-
if (!
|
|
40826
|
+
const skillMdPath = join9(dir, entry.name, "SKILL.md");
|
|
40827
|
+
if (!existsSync9(skillMdPath))
|
|
40787
40828
|
continue;
|
|
40788
40829
|
let content;
|
|
40789
40830
|
try {
|
|
40790
|
-
content =
|
|
40831
|
+
content = readFileSync7(skillMdPath, "utf-8");
|
|
40791
40832
|
} catch {
|
|
40792
40833
|
continue;
|
|
40793
40834
|
}
|
|
@@ -40802,6 +40843,7 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
40802
40843
|
category: fm.category || "Development Tools",
|
|
40803
40844
|
tags: fm.tags || [],
|
|
40804
40845
|
...fm.kind ? { kind: fm.kind } : {},
|
|
40846
|
+
...isHostedMetadataSkillDir(join9(dir, entry.name)) ? { serverOwned: true } : {},
|
|
40805
40847
|
source
|
|
40806
40848
|
});
|
|
40807
40849
|
}
|
|
@@ -40810,20 +40852,20 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
40810
40852
|
}
|
|
40811
40853
|
function findExtensionSkillPath(name) {
|
|
40812
40854
|
const config = loadConfig();
|
|
40813
|
-
if (!config.extensionsDir || !
|
|
40855
|
+
if (!config.extensionsDir || !existsSync9(config.extensionsDir))
|
|
40814
40856
|
return null;
|
|
40815
40857
|
try {
|
|
40816
|
-
const entries =
|
|
40858
|
+
const entries = readdirSync6(config.extensionsDir, { withFileTypes: true });
|
|
40817
40859
|
for (const entry of entries) {
|
|
40818
40860
|
if (!entry.isDirectory())
|
|
40819
40861
|
continue;
|
|
40820
|
-
const skillDir =
|
|
40821
|
-
const skillMdPath =
|
|
40822
|
-
if (!
|
|
40862
|
+
const skillDir = join9(config.extensionsDir, entry.name);
|
|
40863
|
+
const skillMdPath = join9(skillDir, "SKILL.md");
|
|
40864
|
+
if (!existsSync9(skillMdPath))
|
|
40823
40865
|
continue;
|
|
40824
40866
|
let content;
|
|
40825
40867
|
try {
|
|
40826
|
-
content =
|
|
40868
|
+
content = readFileSync7(skillMdPath, "utf-8");
|
|
40827
40869
|
} catch {
|
|
40828
40870
|
continue;
|
|
40829
40871
|
}
|
|
@@ -40852,7 +40894,7 @@ function loadRegistry(cwd2) {
|
|
|
40852
40894
|
const official = SKILLS.map((s) => ({ ...s, source: "official" }));
|
|
40853
40895
|
const extensions = config.extensionsDir ? discoverSkillsInDir(config.extensionsDir, "extension") : [];
|
|
40854
40896
|
const portableCustom = listPortableSkillMetas();
|
|
40855
|
-
const legacyCustom = discoverSkillsInDir(
|
|
40897
|
+
const legacyCustom = discoverSkillsInDir(join9(dataDir, "custom"));
|
|
40856
40898
|
const globalCustom = mergeCustomSkills([...legacyCustom, ...portableCustom]);
|
|
40857
40899
|
registryCache = mergeSkillRegistryLists(official, extensions, globalCustom);
|
|
40858
40900
|
registryCacheTime = now3;
|
|
@@ -40902,6 +40944,7 @@ var registryCache = null, registryCacheTime = 0, registryCacheKey = null, REGIST
|
|
|
40902
40944
|
var init_registry = __esm(() => {
|
|
40903
40945
|
init_config();
|
|
40904
40946
|
init_portable_skills();
|
|
40947
|
+
init_hosted_skill_set();
|
|
40905
40948
|
init_registry_merge();
|
|
40906
40949
|
init_skill_aliases();
|
|
40907
40950
|
init_registry_data();
|
|
@@ -42550,33 +42593,33 @@ var require_cli_spinners = __commonJS((exports, module) => {
|
|
|
42550
42593
|
});
|
|
42551
42594
|
|
|
42552
42595
|
// src/lib/home-migration.ts
|
|
42553
|
-
import { existsSync as
|
|
42554
|
-
import { join as
|
|
42596
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync4, readdirSync as readdirSync7, renameSync as renameSync2, rmSync as rmSync2, statSync as statSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
42597
|
+
import { join as join10 } from "path";
|
|
42555
42598
|
function layoutMigrationRecordPath(appDir) {
|
|
42556
|
-
return
|
|
42599
|
+
return join10(appDir, SKILLS_CACHE_DIRNAME, LAYOUT_MIGRATION_RECORD);
|
|
42557
42600
|
}
|
|
42558
42601
|
function resolveCorpusRoot(options = {}) {
|
|
42559
42602
|
return getPortableSkillsRoot(options);
|
|
42560
42603
|
}
|
|
42561
42604
|
function migrationAppDir(homeDir) {
|
|
42562
|
-
return homeDir ?
|
|
42605
|
+
return homeDir ? join10(homeDir, ".hasna", "skills") : getDataDir();
|
|
42563
42606
|
}
|
|
42564
42607
|
function looksLikeSkillDirectory2(path) {
|
|
42565
42608
|
try {
|
|
42566
|
-
if (!
|
|
42609
|
+
if (!statSync7(path).isDirectory())
|
|
42567
42610
|
return false;
|
|
42568
42611
|
} catch {
|
|
42569
42612
|
return false;
|
|
42570
42613
|
}
|
|
42571
|
-
return
|
|
42614
|
+
return existsSync10(join10(path, "SKILL.md")) || existsSync10(join10(path, "skill.json")) || existsSync10(join10(path, "package.json"));
|
|
42572
42615
|
}
|
|
42573
42616
|
function listLegacyFlatSkillDirs(appDir) {
|
|
42574
42617
|
const legacy = [];
|
|
42575
|
-
if (!
|
|
42618
|
+
if (!existsSync10(appDir))
|
|
42576
42619
|
return legacy;
|
|
42577
42620
|
let entries = [];
|
|
42578
42621
|
try {
|
|
42579
|
-
entries =
|
|
42622
|
+
entries = readdirSync7(appDir);
|
|
42580
42623
|
} catch {
|
|
42581
42624
|
return legacy;
|
|
42582
42625
|
}
|
|
@@ -42586,15 +42629,15 @@ function listLegacyFlatSkillDirs(appDir) {
|
|
|
42586
42629
|
if (entry === SKILLS_CACHE_DIRNAME || entry === INSTALLED_SKILLS_DIRNAME || entry === LEGACY_CUSTOM_DIRNAME2 || entry === LOGS_DIRNAME || entry === OUTPUTS_DIRNAME) {
|
|
42587
42630
|
continue;
|
|
42588
42631
|
}
|
|
42589
|
-
if (looksLikeSkillDirectory2(
|
|
42632
|
+
if (looksLikeSkillDirectory2(join10(appDir, entry)))
|
|
42590
42633
|
legacy.push(entry);
|
|
42591
42634
|
}
|
|
42592
42635
|
return legacy;
|
|
42593
42636
|
}
|
|
42594
42637
|
function createLazyDirs(appDir, created) {
|
|
42595
42638
|
for (const name of [LOGS_DIRNAME, OUTPUTS_DIRNAME]) {
|
|
42596
|
-
const dir =
|
|
42597
|
-
if (!
|
|
42639
|
+
const dir = join10(appDir, name);
|
|
42640
|
+
if (!existsSync10(dir)) {
|
|
42598
42641
|
mkdirSync4(dir, { recursive: true });
|
|
42599
42642
|
created.push(dir);
|
|
42600
42643
|
}
|
|
@@ -42602,17 +42645,17 @@ function createLazyDirs(appDir, created) {
|
|
|
42602
42645
|
}
|
|
42603
42646
|
function migrateOwnerLayout(options = {}) {
|
|
42604
42647
|
const appDir = migrationAppDir(options.homeDir);
|
|
42605
|
-
const cache3 =
|
|
42606
|
-
const installed =
|
|
42648
|
+
const cache3 = join10(appDir, SKILLS_CACHE_DIRNAME);
|
|
42649
|
+
const installed = join10(appDir, INSTALLED_SKILLS_DIRNAME);
|
|
42607
42650
|
const moved = [];
|
|
42608
42651
|
const created = [];
|
|
42609
42652
|
if (isOwnerLayoutMigrated(appDir)) {
|
|
42610
42653
|
return { status: "already-migrated", moved, created };
|
|
42611
42654
|
}
|
|
42612
|
-
if (
|
|
42655
|
+
if (existsSync10(cache3)) {
|
|
42613
42656
|
let entries = [];
|
|
42614
42657
|
try {
|
|
42615
|
-
entries =
|
|
42658
|
+
entries = readdirSync7(cache3);
|
|
42616
42659
|
} catch {}
|
|
42617
42660
|
if (entries.length > 0) {
|
|
42618
42661
|
return {
|
|
@@ -42623,7 +42666,7 @@ function migrateOwnerLayout(options = {}) {
|
|
|
42623
42666
|
};
|
|
42624
42667
|
}
|
|
42625
42668
|
}
|
|
42626
|
-
const installedPresent =
|
|
42669
|
+
const installedPresent = existsSync10(installed);
|
|
42627
42670
|
const legacy = listLegacyFlatSkillDirs(appDir);
|
|
42628
42671
|
const planned = [...installedPresent ? [INSTALLED_SKILLS_DIRNAME] : [], ...legacy];
|
|
42629
42672
|
if (!installedPresent && legacy.length === 0) {
|
|
@@ -42636,10 +42679,10 @@ function migrateOwnerLayout(options = {}) {
|
|
|
42636
42679
|
}
|
|
42637
42680
|
const collisionNames = new Set;
|
|
42638
42681
|
for (const dir of [cache3, ...installedPresent ? [installed] : []]) {
|
|
42639
|
-
if (!
|
|
42682
|
+
if (!existsSync10(dir))
|
|
42640
42683
|
continue;
|
|
42641
42684
|
try {
|
|
42642
|
-
for (const entry of
|
|
42685
|
+
for (const entry of readdirSync7(dir))
|
|
42643
42686
|
collisionNames.add(entry);
|
|
42644
42687
|
} catch {}
|
|
42645
42688
|
}
|
|
@@ -42653,7 +42696,7 @@ function migrateOwnerLayout(options = {}) {
|
|
|
42653
42696
|
};
|
|
42654
42697
|
}
|
|
42655
42698
|
}
|
|
42656
|
-
if (
|
|
42699
|
+
if (existsSync10(cache3)) {
|
|
42657
42700
|
rmSync2(cache3, { recursive: true, force: true });
|
|
42658
42701
|
}
|
|
42659
42702
|
if (installedPresent) {
|
|
@@ -42663,7 +42706,7 @@ function migrateOwnerLayout(options = {}) {
|
|
|
42663
42706
|
mkdirSync4(cache3, { recursive: true });
|
|
42664
42707
|
}
|
|
42665
42708
|
for (const name of legacy) {
|
|
42666
|
-
renameSync2(
|
|
42709
|
+
renameSync2(join10(appDir, name), join10(cache3, name));
|
|
42667
42710
|
moved.push(name);
|
|
42668
42711
|
}
|
|
42669
42712
|
createLazyDirs(appDir, created);
|
|
@@ -42687,18 +42730,18 @@ var init_home_migration = __esm(() => {
|
|
|
42687
42730
|
// src/lib/agent-sync.ts
|
|
42688
42731
|
import {
|
|
42689
42732
|
cpSync as cpSync3,
|
|
42690
|
-
existsSync as
|
|
42733
|
+
existsSync as existsSync11,
|
|
42691
42734
|
mkdirSync as mkdirSync5,
|
|
42692
|
-
mkdtempSync,
|
|
42693
|
-
readFileSync as
|
|
42694
|
-
readdirSync as
|
|
42735
|
+
mkdtempSync as mkdtempSync2,
|
|
42736
|
+
readFileSync as readFileSync8,
|
|
42737
|
+
readdirSync as readdirSync8,
|
|
42695
42738
|
renameSync as renameSync3,
|
|
42696
42739
|
rmSync as rmSync3,
|
|
42697
|
-
statSync as
|
|
42740
|
+
statSync as statSync8,
|
|
42698
42741
|
writeFileSync as writeFileSync5
|
|
42699
42742
|
} from "fs";
|
|
42700
42743
|
import { homedir as homedir3 } from "os";
|
|
42701
|
-
import { basename as basename3, dirname as dirname4, join as
|
|
42744
|
+
import { basename as basename3, dirname as dirname4, join as join11 } from "path";
|
|
42702
42745
|
function isSyncAgent(value) {
|
|
42703
42746
|
return SYNC_AGENTS.includes(value);
|
|
42704
42747
|
}
|
|
@@ -42713,9 +42756,9 @@ function resolveSyncAgents(arg) {
|
|
|
42713
42756
|
function agentGlobalSkillsDir(agent, homeDir = homedir3()) {
|
|
42714
42757
|
switch (agent) {
|
|
42715
42758
|
case "opencode":
|
|
42716
|
-
return
|
|
42759
|
+
return join11(homeDir, ".config", "opencode", "skills");
|
|
42717
42760
|
default:
|
|
42718
|
-
return
|
|
42761
|
+
return join11(homeDir, `.${agent}`, "skills");
|
|
42719
42762
|
}
|
|
42720
42763
|
}
|
|
42721
42764
|
function adaptSkillMdForAgent(skillMd, agent) {
|
|
@@ -42773,8 +42816,8 @@ function resolveSyncCorpus(options = {}) {
|
|
|
42773
42816
|
function packageSourceRoots(source) {
|
|
42774
42817
|
const roots = [];
|
|
42775
42818
|
for (const sub of ["skills"]) {
|
|
42776
|
-
const candidate =
|
|
42777
|
-
if (
|
|
42819
|
+
const candidate = join11(source, sub);
|
|
42820
|
+
if (existsSync11(candidate) && isDirectory(candidate))
|
|
42778
42821
|
roots.push(candidate);
|
|
42779
42822
|
}
|
|
42780
42823
|
if (roots.length > 0)
|
|
@@ -42784,20 +42827,20 @@ function packageSourceRoots(source) {
|
|
|
42784
42827
|
function containsSkillDirectories(path) {
|
|
42785
42828
|
let entries;
|
|
42786
42829
|
try {
|
|
42787
|
-
entries =
|
|
42830
|
+
entries = readdirSync8(path);
|
|
42788
42831
|
} catch {
|
|
42789
42832
|
return false;
|
|
42790
42833
|
}
|
|
42791
42834
|
return entries.some((entry) => {
|
|
42792
|
-
const candidate =
|
|
42835
|
+
const candidate = join11(path, entry);
|
|
42793
42836
|
if (!isDirectory(candidate))
|
|
42794
42837
|
return false;
|
|
42795
|
-
return
|
|
42838
|
+
return existsSync11(join11(candidate, "SKILL.md")) || existsSync11(join11(candidate, "skill.json")) || existsSync11(join11(candidate, "package.json"));
|
|
42796
42839
|
});
|
|
42797
42840
|
}
|
|
42798
42841
|
function isDirectory(path) {
|
|
42799
42842
|
try {
|
|
42800
|
-
return
|
|
42843
|
+
return statSync8(path).isDirectory();
|
|
42801
42844
|
} catch {
|
|
42802
42845
|
return false;
|
|
42803
42846
|
}
|
|
@@ -42831,7 +42874,7 @@ function syncSkillsToAgents(options = {}) {
|
|
|
42831
42874
|
actions.push({
|
|
42832
42875
|
skill: name,
|
|
42833
42876
|
agent,
|
|
42834
|
-
path:
|
|
42877
|
+
path: join11(agentGlobalSkillsDir(agent, homeDir), name, "SKILL.md"),
|
|
42835
42878
|
action: "skip",
|
|
42836
42879
|
reason: "not found in this machine's corpus"
|
|
42837
42880
|
});
|
|
@@ -42841,7 +42884,7 @@ function syncSkillsToAgents(options = {}) {
|
|
|
42841
42884
|
}
|
|
42842
42885
|
for (const skill of targets) {
|
|
42843
42886
|
const manifest = readPortableSkillManifest(skill.path, skill.name);
|
|
42844
|
-
const kind = manifest.kind
|
|
42887
|
+
const kind = manifest.kind;
|
|
42845
42888
|
const sourceMd = sourceSkillMd(skill.path, skill.name, manifest.description, kind, source === "source");
|
|
42846
42889
|
for (const agent of agents) {
|
|
42847
42890
|
const adapted = adaptSkillMdForAgent(sourceMd, agent);
|
|
@@ -42861,7 +42904,7 @@ function syncSkillsToAgents(options = {}) {
|
|
|
42861
42904
|
}
|
|
42862
42905
|
function writeManagedAgentSkill(params) {
|
|
42863
42906
|
const homeDir = params.homeDir ?? homedir3();
|
|
42864
|
-
const dir =
|
|
42907
|
+
const dir = join11(agentGlobalSkillsDir(params.agent, homeDir), params.skill);
|
|
42865
42908
|
const result2 = writeManagedSkillDir(dir, params.skillMd, {
|
|
42866
42909
|
skill: params.skill,
|
|
42867
42910
|
source: params.source,
|
|
@@ -42878,11 +42921,11 @@ function writeManagedAgentSkill(params) {
|
|
|
42878
42921
|
};
|
|
42879
42922
|
}
|
|
42880
42923
|
function writeManagedSkillDir(dir, skillMd, options) {
|
|
42881
|
-
const skillMdPath =
|
|
42882
|
-
const markerPath =
|
|
42883
|
-
const dirExists =
|
|
42884
|
-
const managed =
|
|
42885
|
-
const hasSkillMd =
|
|
42924
|
+
const skillMdPath = join11(dir, "SKILL.md");
|
|
42925
|
+
const markerPath = join11(dir, SYNC_MARKER_FILE);
|
|
42926
|
+
const dirExists = existsSync11(dir);
|
|
42927
|
+
const managed = existsSync11(markerPath);
|
|
42928
|
+
const hasSkillMd = existsSync11(skillMdPath);
|
|
42886
42929
|
if (dirExists && !managed && !hasSkillMd) {
|
|
42887
42930
|
return {
|
|
42888
42931
|
action: "skip",
|
|
@@ -42900,7 +42943,7 @@ function writeManagedSkillDir(dir, skillMd, options) {
|
|
|
42900
42943
|
if (dirExists && managed && hasSkillMd && !options.force && isPointerSkillMd(skillMd)) {
|
|
42901
42944
|
let existingIsStub = false;
|
|
42902
42945
|
try {
|
|
42903
|
-
existingIsStub = isPointerSkillMd(
|
|
42946
|
+
existingIsStub = isPointerSkillMd(readFileSync8(skillMdPath, "utf-8"));
|
|
42904
42947
|
} catch {
|
|
42905
42948
|
existingIsStub = false;
|
|
42906
42949
|
}
|
|
@@ -42917,11 +42960,11 @@ function writeManagedSkillDir(dir, skillMd, options) {
|
|
|
42917
42960
|
return { action, path: skillMdPath };
|
|
42918
42961
|
const parentDir = dirname4(dir);
|
|
42919
42962
|
mkdirSync5(parentDir, { recursive: true });
|
|
42920
|
-
const transactionDir =
|
|
42921
|
-
const candidateDir =
|
|
42922
|
-
const backupDir =
|
|
42923
|
-
const candidateSkillMdPath =
|
|
42924
|
-
const candidateMarkerPath =
|
|
42963
|
+
const transactionDir = mkdtempSync2(join11(parentDir, `.hasna-skills-write-${basename3(dir)}-`));
|
|
42964
|
+
const candidateDir = join11(transactionDir, "candidate");
|
|
42965
|
+
const backupDir = join11(transactionDir, "backup");
|
|
42966
|
+
const candidateSkillMdPath = join11(candidateDir, "SKILL.md");
|
|
42967
|
+
const candidateMarkerPath = join11(candidateDir, SYNC_MARKER_FILE);
|
|
42925
42968
|
const marker = {
|
|
42926
42969
|
managedBy: SYNC_MARKER_MANAGED_BY,
|
|
42927
42970
|
skill: options.skill,
|
|
@@ -42948,9 +42991,9 @@ function writeManagedSkillDir(dir, skillMd, options) {
|
|
|
42948
42991
|
}
|
|
42949
42992
|
renameDirectory(candidateDir, dir);
|
|
42950
42993
|
} catch (error) {
|
|
42951
|
-
if (originalMoved &&
|
|
42994
|
+
if (originalMoved && existsSync11(backupDir)) {
|
|
42952
42995
|
try {
|
|
42953
|
-
if (
|
|
42996
|
+
if (existsSync11(dir))
|
|
42954
42997
|
rmSync3(dir, { recursive: true, force: true });
|
|
42955
42998
|
renameDirectory(backupDir, dir);
|
|
42956
42999
|
originalMoved = false;
|
|
@@ -42970,10 +43013,10 @@ function writeManagedSkillDir(dir, skillMd, options) {
|
|
|
42970
43013
|
return { action, path: skillMdPath };
|
|
42971
43014
|
}
|
|
42972
43015
|
function sourceSkillMd(skillPath, name, description, kind, preferBundledDocs = false) {
|
|
42973
|
-
if (kind === "instruction" || preferBundledDocs) {
|
|
42974
|
-
const skillMdPath =
|
|
42975
|
-
if (
|
|
42976
|
-
return
|
|
43016
|
+
if (kind === undefined || kind === "instruction" || preferBundledDocs) {
|
|
43017
|
+
const skillMdPath = join11(skillPath, "SKILL.md");
|
|
43018
|
+
if (existsSync11(skillMdPath))
|
|
43019
|
+
return readFileSync8(skillMdPath, "utf-8");
|
|
42977
43020
|
}
|
|
42978
43021
|
return pointerSkillMd(name, description);
|
|
42979
43022
|
}
|
|
@@ -43009,20 +43052,20 @@ function normalizeSkillName(name) {
|
|
|
43009
43052
|
}
|
|
43010
43053
|
|
|
43011
43054
|
// src/lib/project-state.ts
|
|
43012
|
-
import { existsSync as
|
|
43013
|
-
import { join as
|
|
43055
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "fs";
|
|
43056
|
+
import { join as join12 } from "path";
|
|
43014
43057
|
function getProjectStateDir(targetDir = process.cwd()) {
|
|
43015
|
-
return
|
|
43058
|
+
return join12(targetDir, SKILLS_PROJECT_DIR);
|
|
43016
43059
|
}
|
|
43017
43060
|
function getProjectConfigPath(targetDir = process.cwd()) {
|
|
43018
|
-
return
|
|
43061
|
+
return join12(getProjectStateDir(targetDir), PROJECT_CONFIG_FILE);
|
|
43019
43062
|
}
|
|
43020
43063
|
function loadProjectConfig(targetDir = process.cwd()) {
|
|
43021
43064
|
const path = getProjectConfigPath(targetDir);
|
|
43022
|
-
if (!
|
|
43065
|
+
if (!existsSync12(path))
|
|
43023
43066
|
return null;
|
|
43024
43067
|
try {
|
|
43025
|
-
return normalizeProjectConfig(JSON.parse(
|
|
43068
|
+
return normalizeProjectConfig(JSON.parse(readFileSync9(path, "utf-8")));
|
|
43026
43069
|
} catch {
|
|
43027
43070
|
return null;
|
|
43028
43071
|
}
|
|
@@ -43176,44 +43219,44 @@ __export(exports_installer, {
|
|
|
43176
43219
|
AGENT_TARGETS: () => AGENT_TARGETS,
|
|
43177
43220
|
AGENT_LABELS: () => AGENT_LABELS
|
|
43178
43221
|
});
|
|
43179
|
-
import { existsSync as
|
|
43180
|
-
import { dirname as dirname5, join as
|
|
43222
|
+
import { existsSync as existsSync13, readFileSync as readFileSync10, rmSync as rmSync4 } from "fs";
|
|
43223
|
+
import { dirname as dirname5, join as join13 } from "path";
|
|
43181
43224
|
import { homedir as homedir4 } from "os";
|
|
43182
43225
|
import { fileURLToPath } from "url";
|
|
43183
43226
|
function findSkillsDir() {
|
|
43184
43227
|
let dir = __dirname2;
|
|
43185
43228
|
for (let i = 0;i < 5; i++) {
|
|
43186
|
-
const candidate =
|
|
43187
|
-
if (
|
|
43229
|
+
const candidate = join13(dir, "skills");
|
|
43230
|
+
if (existsSync13(candidate) && !dir.includes(".skills"))
|
|
43188
43231
|
return candidate;
|
|
43189
43232
|
dir = dirname5(dir);
|
|
43190
43233
|
}
|
|
43191
|
-
return
|
|
43234
|
+
return join13(__dirname2, "..", "skills");
|
|
43192
43235
|
}
|
|
43193
43236
|
function getSkillPath(name) {
|
|
43194
43237
|
const skillName = normalizeSkillName(getCanonicalSkillName(name));
|
|
43195
43238
|
const portable = findPortableSkill(skillName);
|
|
43196
43239
|
if (portable)
|
|
43197
43240
|
return portable.path;
|
|
43198
|
-
const legacyCustomPath =
|
|
43199
|
-
if (
|
|
43241
|
+
const legacyCustomPath = join13(getDataDir(), "custom", skillName);
|
|
43242
|
+
if (existsSync13(legacyCustomPath))
|
|
43200
43243
|
return legacyCustomPath;
|
|
43201
43244
|
const extensionPath = findExtensionSkillPath(skillName);
|
|
43202
43245
|
if (extensionPath)
|
|
43203
43246
|
return extensionPath;
|
|
43204
|
-
return
|
|
43247
|
+
return join13(SKILLS_DIR, skillName);
|
|
43205
43248
|
}
|
|
43206
43249
|
function getCanonicalSkillName(name) {
|
|
43207
43250
|
return getSkill(name)?.name ?? resolveSkillAlias(normalizeSkillSlug(name));
|
|
43208
43251
|
}
|
|
43209
43252
|
function skillExists(name) {
|
|
43210
|
-
return
|
|
43253
|
+
return existsSync13(getSkillPath(name));
|
|
43211
43254
|
}
|
|
43212
43255
|
function installSkill(name, options = {}) {
|
|
43213
43256
|
const { targetDir = process.cwd(), overwrite = false } = options;
|
|
43214
43257
|
const canonicalName = getCanonicalSkillName(name);
|
|
43215
43258
|
const skillName = normalizeSkillName(canonicalName);
|
|
43216
|
-
if (!
|
|
43259
|
+
if (!existsSync13(getSkillPath(name))) {
|
|
43217
43260
|
const knownOfficial = Boolean(getSkill(name));
|
|
43218
43261
|
return {
|
|
43219
43262
|
skill: canonicalName,
|
|
@@ -43263,7 +43306,7 @@ function installRemoteSkill(skill, options = {}) {
|
|
|
43263
43306
|
}
|
|
43264
43307
|
function installSkillSource(name, _options = {}) {
|
|
43265
43308
|
const canonicalName = getCanonicalSkillName(name);
|
|
43266
|
-
if (!
|
|
43309
|
+
if (!existsSync13(getSkillPath(name))) {
|
|
43267
43310
|
return { skill: canonicalName, success: false, error: `Skill '${name}' not found`, mode: "source" };
|
|
43268
43311
|
}
|
|
43269
43312
|
return {
|
|
@@ -43284,12 +43327,12 @@ function installSkillManifest(manifest, _options = {}) {
|
|
|
43284
43327
|
}
|
|
43285
43328
|
function createLocalSkillManifest(name, generateSkillMd) {
|
|
43286
43329
|
const sourcePath = getSkillPath(name);
|
|
43287
|
-
if (!
|
|
43330
|
+
if (!existsSync13(sourcePath))
|
|
43288
43331
|
return null;
|
|
43289
43332
|
let skillMd = "";
|
|
43290
|
-
const skillMdPath =
|
|
43291
|
-
if (
|
|
43292
|
-
skillMd =
|
|
43333
|
+
const skillMdPath = join13(sourcePath, "SKILL.md");
|
|
43334
|
+
if (existsSync13(skillMdPath)) {
|
|
43335
|
+
skillMd = readFileSync10(skillMdPath, "utf-8");
|
|
43293
43336
|
} else if (generateSkillMd) {
|
|
43294
43337
|
skillMd = generateSkillMd(name) ?? "";
|
|
43295
43338
|
} else {
|
|
@@ -43369,20 +43412,20 @@ function getAgentSkillsDir(agent, scope = "global", projectDir) {
|
|
|
43369
43412
|
const base2 = projectDir || process.cwd();
|
|
43370
43413
|
switch (agent) {
|
|
43371
43414
|
case "pi":
|
|
43372
|
-
return scope === "project" ?
|
|
43415
|
+
return scope === "project" ? join13(base2, ".pi", "skills") : join13(homedir4(), ".pi", "agent", "skills");
|
|
43373
43416
|
case "opencode":
|
|
43374
|
-
return scope === "project" ?
|
|
43417
|
+
return scope === "project" ? join13(base2, ".opencode", "skills") : join13(homedir4(), ".config", "opencode", "skills");
|
|
43375
43418
|
default:
|
|
43376
|
-
return scope === "project" ?
|
|
43419
|
+
return scope === "project" ? join13(base2, `.${agent}`, "skills") : join13(homedir4(), `.${agent}`, "skills");
|
|
43377
43420
|
}
|
|
43378
43421
|
}
|
|
43379
43422
|
function getAgentSkillPath(name, agent, scope = "global", projectDir) {
|
|
43380
43423
|
const skillName = normalizeSkillName(getCanonicalSkillName(name));
|
|
43381
|
-
return
|
|
43424
|
+
return join13(getAgentSkillsDir(agent, scope, projectDir), skillName);
|
|
43382
43425
|
}
|
|
43383
43426
|
function installSkillForAgent(name, options, generateSkillMd) {
|
|
43384
43427
|
const canonicalName = getCanonicalSkillName(name);
|
|
43385
|
-
if (!
|
|
43428
|
+
if (!existsSync13(getSkillPath(name))) {
|
|
43386
43429
|
return { skill: canonicalName, success: false, error: `Skill '${name}' not found` };
|
|
43387
43430
|
}
|
|
43388
43431
|
const scope = options.scope ?? "global";
|
|
@@ -43406,16 +43449,16 @@ function removeSkillForAgent(name, options) {
|
|
|
43406
43449
|
const canonicalName = getCanonicalSkillName(name);
|
|
43407
43450
|
const scope = options.scope ?? "global";
|
|
43408
43451
|
const dir = getAgentSkillPath(canonicalName, options.agent, scope, options.projectDir);
|
|
43409
|
-
if (!
|
|
43452
|
+
if (!existsSync13(join13(dir, SYNC_MARKER_FILE)))
|
|
43410
43453
|
return false;
|
|
43411
43454
|
rmSync4(dir, { recursive: true, force: true });
|
|
43412
43455
|
return true;
|
|
43413
43456
|
}
|
|
43414
43457
|
function resolveAgentSkillMd(name, generateSkillMd) {
|
|
43415
43458
|
const sourcePath = getSkillPath(name);
|
|
43416
|
-
const skillMdPath =
|
|
43417
|
-
if (
|
|
43418
|
-
return
|
|
43459
|
+
const skillMdPath = join13(sourcePath, "SKILL.md");
|
|
43460
|
+
if (existsSync13(skillMdPath))
|
|
43461
|
+
return readFileSync10(skillMdPath, "utf-8");
|
|
43419
43462
|
if (generateSkillMd)
|
|
43420
43463
|
return generateSkillMd(name);
|
|
43421
43464
|
return generateMinimalSkillMd(name);
|
|
@@ -43433,7 +43476,7 @@ function warnMissingDependencies(name, targetDir) {
|
|
|
43433
43476
|
}
|
|
43434
43477
|
function generateMinimalSkillMd(name) {
|
|
43435
43478
|
const sourcePath = getSkillPath(name);
|
|
43436
|
-
if (!
|
|
43479
|
+
if (!existsSync13(sourcePath))
|
|
43437
43480
|
return null;
|
|
43438
43481
|
const canonicalName = getCanonicalSkillName(name);
|
|
43439
43482
|
const meta = getSkill(canonicalName);
|
|
@@ -43448,7 +43491,7 @@ function generateMinimalSkillMd(name) {
|
|
|
43448
43491
|
"---",
|
|
43449
43492
|
""
|
|
43450
43493
|
].filter(Boolean);
|
|
43451
|
-
const fallbackDoc = readFileIfExists(
|
|
43494
|
+
const fallbackDoc = readFileIfExists(join13(sourcePath, "README.md")) || readFileIfExists(join13(sourcePath, "CLAUDE.md"));
|
|
43452
43495
|
if (fallbackDoc)
|
|
43453
43496
|
return `${frontmatter.join(`
|
|
43454
43497
|
`)}${fallbackDoc.trim()}
|
|
@@ -43467,18 +43510,18 @@ skills run ${canonicalName}
|
|
|
43467
43510
|
`;
|
|
43468
43511
|
}
|
|
43469
43512
|
function readBundledSkillVersion(name) {
|
|
43470
|
-
const pkgPath =
|
|
43471
|
-
if (!
|
|
43513
|
+
const pkgPath = join13(getSkillPath(name), "package.json");
|
|
43514
|
+
if (!existsSync13(pkgPath))
|
|
43472
43515
|
return "unknown";
|
|
43473
43516
|
try {
|
|
43474
|
-
const pkg = JSON.parse(
|
|
43517
|
+
const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
|
|
43475
43518
|
return pkg.version || "unknown";
|
|
43476
43519
|
} catch {
|
|
43477
43520
|
return "unknown";
|
|
43478
43521
|
}
|
|
43479
43522
|
}
|
|
43480
43523
|
function readFileIfExists(path) {
|
|
43481
|
-
return
|
|
43524
|
+
return existsSync13(path) ? readFileSync10(path, "utf-8") : null;
|
|
43482
43525
|
}
|
|
43483
43526
|
function loadProjectConfigCompat(targetDir) {
|
|
43484
43527
|
return loadProjectConfig(targetDir);
|
|
@@ -47597,24 +47640,24 @@ __export(exports_auth_store, {
|
|
|
47597
47640
|
getApiKey: () => getApiKey,
|
|
47598
47641
|
clearAuthConfig: () => clearAuthConfig
|
|
47599
47642
|
});
|
|
47600
|
-
import { existsSync as
|
|
47601
|
-
import { dirname as dirname6, join as
|
|
47643
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync7, readFileSync as readFileSync11, writeFileSync as writeFileSync7, unlinkSync } from "fs";
|
|
47644
|
+
import { dirname as dirname6, join as join14 } from "path";
|
|
47602
47645
|
import { homedir as homedir5 } from "os";
|
|
47603
47646
|
function getAuthFilePath() {
|
|
47604
|
-
return
|
|
47647
|
+
return join14(getDataDir(), "auth.json");
|
|
47605
47648
|
}
|
|
47606
47649
|
function getAuthFilePathReadOnly() {
|
|
47607
|
-
return
|
|
47650
|
+
return join14(getDataDirReadOnly(), "auth.json");
|
|
47608
47651
|
}
|
|
47609
47652
|
function legacyAuthFilePath() {
|
|
47610
|
-
return
|
|
47653
|
+
return join14(process.env["HOME"] || process.env["USERPROFILE"] || homedir5(), ".skills", "auth.json");
|
|
47611
47654
|
}
|
|
47612
47655
|
function getAuthConfig() {
|
|
47613
47656
|
if (cachedConfig !== undefined)
|
|
47614
47657
|
return cachedConfig;
|
|
47615
47658
|
try {
|
|
47616
|
-
const file =
|
|
47617
|
-
const raw =
|
|
47659
|
+
const file = existsSync14(getAuthFilePath()) ? getAuthFilePath() : legacyAuthFilePath();
|
|
47660
|
+
const raw = readFileSync11(file, "utf-8");
|
|
47618
47661
|
const config = JSON.parse(raw);
|
|
47619
47662
|
if (!config.apiKey) {
|
|
47620
47663
|
cachedConfig = null;
|
|
@@ -47652,8 +47695,8 @@ function getApiKey() {
|
|
|
47652
47695
|
}
|
|
47653
47696
|
function getAuthConfigReadOnly() {
|
|
47654
47697
|
try {
|
|
47655
|
-
const file =
|
|
47656
|
-
const raw =
|
|
47698
|
+
const file = existsSync14(getAuthFilePathReadOnly()) ? getAuthFilePathReadOnly() : legacyAuthFilePath();
|
|
47699
|
+
const raw = readFileSync11(file, "utf-8");
|
|
47657
47700
|
const config = JSON.parse(raw);
|
|
47658
47701
|
if (!config.apiKey)
|
|
47659
47702
|
return null;
|
|
@@ -48545,28 +48588,28 @@ __export(exports_skillinfo, {
|
|
|
48545
48588
|
generateEnvExample: () => generateEnvExample,
|
|
48546
48589
|
detectProjectSkills: () => detectProjectSkills
|
|
48547
48590
|
});
|
|
48548
|
-
import { existsSync as
|
|
48549
|
-
import { join as
|
|
48591
|
+
import { existsSync as existsSync15, readFileSync as readFileSync12 } from "fs";
|
|
48592
|
+
import { join as join15 } from "path";
|
|
48550
48593
|
function isInstructionSkillDir(skillPath, meta) {
|
|
48551
48594
|
if (meta?.kind === "instruction")
|
|
48552
48595
|
return true;
|
|
48553
|
-
const skillMdPath =
|
|
48554
|
-
if (!
|
|
48596
|
+
const skillMdPath = join15(skillPath, "SKILL.md");
|
|
48597
|
+
if (!existsSync15(skillMdPath))
|
|
48555
48598
|
return false;
|
|
48556
48599
|
try {
|
|
48557
|
-
return parseSkillFrontmatter(
|
|
48600
|
+
return parseSkillFrontmatter(readFileSync12(skillMdPath, "utf-8"))?.kind === "instruction";
|
|
48558
48601
|
} catch {
|
|
48559
48602
|
return false;
|
|
48560
48603
|
}
|
|
48561
48604
|
}
|
|
48562
48605
|
function getSkillDocs(name) {
|
|
48563
48606
|
const skillPath = getSkillPath(name);
|
|
48564
|
-
if (!
|
|
48607
|
+
if (!existsSync15(skillPath))
|
|
48565
48608
|
return null;
|
|
48566
48609
|
return {
|
|
48567
|
-
skillMd: readIfExists(
|
|
48568
|
-
readme: readIfExists(
|
|
48569
|
-
claudeMd: readIfExists(
|
|
48610
|
+
skillMd: readIfExists(join15(skillPath, "SKILL.md")),
|
|
48611
|
+
readme: readIfExists(join15(skillPath, "README.md")),
|
|
48612
|
+
claudeMd: readIfExists(join15(skillPath, "CLAUDE.md"))
|
|
48570
48613
|
};
|
|
48571
48614
|
}
|
|
48572
48615
|
function getSkillBestDoc(name) {
|
|
@@ -48577,11 +48620,11 @@ function getSkillBestDoc(name) {
|
|
|
48577
48620
|
}
|
|
48578
48621
|
function getSkillRequirements(name) {
|
|
48579
48622
|
const skillPath = getSkillPath(name);
|
|
48580
|
-
if (!
|
|
48623
|
+
if (!existsSync15(skillPath))
|
|
48581
48624
|
return null;
|
|
48582
48625
|
const texts = [];
|
|
48583
48626
|
for (const file of ["SKILL.md", "README.md", "CLAUDE.md", ".env.example", ".env.local.example"]) {
|
|
48584
|
-
const content = readIfExists(
|
|
48627
|
+
const content = readIfExists(join15(skillPath, file));
|
|
48585
48628
|
if (content)
|
|
48586
48629
|
texts.push(content);
|
|
48587
48630
|
}
|
|
@@ -48620,10 +48663,10 @@ function getSkillRequirements(name) {
|
|
|
48620
48663
|
const skillName = normalizeSkillName(name);
|
|
48621
48664
|
let cliCommand = `skills run ${skillName}`;
|
|
48622
48665
|
let dependencies = {};
|
|
48623
|
-
const pkgPath =
|
|
48624
|
-
if (
|
|
48666
|
+
const pkgPath = join15(skillPath, "package.json");
|
|
48667
|
+
if (existsSync15(pkgPath)) {
|
|
48625
48668
|
try {
|
|
48626
|
-
const pkg = JSON.parse(
|
|
48669
|
+
const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
|
|
48627
48670
|
dependencies = pkg.dependencies || {};
|
|
48628
48671
|
} catch {}
|
|
48629
48672
|
}
|
|
@@ -48640,9 +48683,9 @@ function isHostedPremiumSkill(skillName, meta) {
|
|
|
48640
48683
|
function isPackageResolvable(pkgName, fromDir) {
|
|
48641
48684
|
let dir = fromDir;
|
|
48642
48685
|
while (true) {
|
|
48643
|
-
if (
|
|
48686
|
+
if (existsSync15(join15(dir, "node_modules", pkgName, "package.json")))
|
|
48644
48687
|
return true;
|
|
48645
|
-
const parent =
|
|
48688
|
+
const parent = join15(dir, "..");
|
|
48646
48689
|
if (parent === dir)
|
|
48647
48690
|
return false;
|
|
48648
48691
|
dir = parent;
|
|
@@ -48662,7 +48705,7 @@ async function runSkill(name, args, options = {}) {
|
|
|
48662
48705
|
const meta = getSkill(name);
|
|
48663
48706
|
const canonicalName = meta?.name ?? name;
|
|
48664
48707
|
const skillPath = getSkillPath(canonicalName);
|
|
48665
|
-
if (!
|
|
48708
|
+
if (!existsSync15(skillPath)) {
|
|
48666
48709
|
return { exitCode: 1, error: `Skill '${name}' not found` };
|
|
48667
48710
|
}
|
|
48668
48711
|
if (isInstructionSkillDir(skillPath, meta)) {
|
|
@@ -48671,13 +48714,13 @@ async function runSkill(name, args, options = {}) {
|
|
|
48671
48714
|
error: `Skill '${name}' is an instruction skill (kind: instruction) and is not runnable. Instruction skills are consumed by coding agents via SKILL.md, not executed with 'skills run'.`
|
|
48672
48715
|
};
|
|
48673
48716
|
}
|
|
48674
|
-
const pkgPath =
|
|
48675
|
-
if (!
|
|
48717
|
+
const pkgPath = join15(skillPath, "package.json");
|
|
48718
|
+
if (!existsSync15(pkgPath)) {
|
|
48676
48719
|
return { exitCode: 1, error: `No package.json in skill '${name}'` };
|
|
48677
48720
|
}
|
|
48678
48721
|
let entryPoint;
|
|
48679
48722
|
try {
|
|
48680
|
-
const pkg = JSON.parse(
|
|
48723
|
+
const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
|
|
48681
48724
|
if (pkg.bin) {
|
|
48682
48725
|
const binValues = Object.values(pkg.bin);
|
|
48683
48726
|
entryPoint = binValues[0];
|
|
@@ -48691,12 +48734,12 @@ async function runSkill(name, args, options = {}) {
|
|
|
48691
48734
|
} catch {
|
|
48692
48735
|
return { exitCode: 1, error: `Failed to parse package.json for skill '${name}'` };
|
|
48693
48736
|
}
|
|
48694
|
-
const entryPath =
|
|
48695
|
-
if (!
|
|
48737
|
+
const entryPath = join15(skillPath, entryPoint);
|
|
48738
|
+
if (!existsSync15(entryPath)) {
|
|
48696
48739
|
return { exitCode: 1, error: `Entry point '${entryPoint}' not found in skill '${name}'` };
|
|
48697
48740
|
}
|
|
48698
|
-
const nodeModules =
|
|
48699
|
-
if (!
|
|
48741
|
+
const nodeModules = join15(skillPath, "node_modules");
|
|
48742
|
+
if (!existsSync15(nodeModules)) {
|
|
48700
48743
|
const install = Bun.spawn(["bun", "install", "--no-save"], {
|
|
48701
48744
|
cwd: skillPath,
|
|
48702
48745
|
stdout: "pipe",
|
|
@@ -48723,15 +48766,15 @@ async function runSkill(name, args, options = {}) {
|
|
|
48723
48766
|
return { exitCode };
|
|
48724
48767
|
}
|
|
48725
48768
|
function detectProjectSkills(cwd2 = process.cwd()) {
|
|
48726
|
-
const pkgPath =
|
|
48727
|
-
if (!
|
|
48769
|
+
const pkgPath = join15(cwd2, "package.json");
|
|
48770
|
+
if (!existsSync15(pkgPath)) {
|
|
48728
48771
|
const alwaysRecommend = ["market-research-report", "repo-onboarding-report", "blog-article"];
|
|
48729
48772
|
const recommended2 = alwaysRecommend.map((name) => loadRegistry().find((s) => s.name === name)).filter((s) => s !== undefined);
|
|
48730
48773
|
return { detected: [], recommended: recommended2 };
|
|
48731
48774
|
}
|
|
48732
48775
|
let pkg;
|
|
48733
48776
|
try {
|
|
48734
|
-
pkg = JSON.parse(
|
|
48777
|
+
pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
|
|
48735
48778
|
} catch {
|
|
48736
48779
|
const alwaysRecommend = ["market-research-report", "repo-onboarding-report", "blog-article"];
|
|
48737
48780
|
const recommended2 = alwaysRecommend.map((name) => loadRegistry().find((s) => s.name === name)).filter((s) => s !== undefined);
|
|
@@ -48851,7 +48894,7 @@ function generateSkillMd(name) {
|
|
|
48851
48894
|
if (!meta)
|
|
48852
48895
|
return null;
|
|
48853
48896
|
const skillPath = getSkillPath(name);
|
|
48854
|
-
if (!
|
|
48897
|
+
if (!existsSync15(skillPath))
|
|
48855
48898
|
return null;
|
|
48856
48899
|
const frontmatter = [
|
|
48857
48900
|
"---",
|
|
@@ -48860,13 +48903,13 @@ function generateSkillMd(name) {
|
|
|
48860
48903
|
"---"
|
|
48861
48904
|
].join(`
|
|
48862
48905
|
`);
|
|
48863
|
-
const readme = readIfExists(
|
|
48864
|
-
const claudeMd = readIfExists(
|
|
48906
|
+
const readme = readIfExists(join15(skillPath, "README.md"));
|
|
48907
|
+
const claudeMd = readIfExists(join15(skillPath, "CLAUDE.md"));
|
|
48865
48908
|
let cliCommand = null;
|
|
48866
|
-
const pkgPath =
|
|
48867
|
-
if (
|
|
48909
|
+
const pkgPath = join15(skillPath, "package.json");
|
|
48910
|
+
if (existsSync15(pkgPath)) {
|
|
48868
48911
|
try {
|
|
48869
|
-
const pkg = JSON.parse(
|
|
48912
|
+
const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
|
|
48870
48913
|
if (pkg.bin) {
|
|
48871
48914
|
const binKeys = Object.keys(pkg.bin);
|
|
48872
48915
|
if (binKeys.length > 0)
|
|
@@ -48939,8 +48982,8 @@ function extractEnvVars(text) {
|
|
|
48939
48982
|
}
|
|
48940
48983
|
function readIfExists(path) {
|
|
48941
48984
|
try {
|
|
48942
|
-
if (
|
|
48943
|
-
return
|
|
48985
|
+
if (existsSync15(path)) {
|
|
48986
|
+
return readFileSync12(path, "utf-8");
|
|
48944
48987
|
}
|
|
48945
48988
|
} catch {}
|
|
48946
48989
|
return null;
|
|
@@ -48975,8 +49018,8 @@ var exports_introspect = {};
|
|
|
48975
49018
|
__export(exports_introspect, {
|
|
48976
49019
|
registerIntrospect: () => registerIntrospect
|
|
48977
49020
|
});
|
|
48978
|
-
import { existsSync as
|
|
48979
|
-
import { join as
|
|
49021
|
+
import { existsSync as existsSync16, readFileSync as readFileSync13 } from "fs";
|
|
49022
|
+
import { join as join16 } from "path";
|
|
48980
49023
|
import { execSync } from "child_process";
|
|
48981
49024
|
function registerIntrospect(parent) {
|
|
48982
49025
|
parent.command("info").argument("<skill>", "Skill name").option("--json", "Output as JSON", false).option("--brief", "Single line: name \u2014 description [category] (tags: ...)", false).option("--remote", "Use remote registry from SKILLS_API_URL or config apiUrl", false).description("Show details about a specific skill").action((name, options) => {
|
|
@@ -49197,36 +49240,36 @@ function handleDiff(name, options) {
|
|
|
49197
49240
|
const bare = name;
|
|
49198
49241
|
const normalized = normalizePortableSkillName(bare);
|
|
49199
49242
|
const sourcePath = getSkillPath(bare);
|
|
49200
|
-
const canonicalDir =
|
|
49201
|
-
const canonicalSkillMd =
|
|
49243
|
+
const canonicalDir = join16(resolveCorpusRoot(), normalized);
|
|
49244
|
+
const canonicalSkillMd = join16(canonicalDir, "SKILL.md");
|
|
49202
49245
|
const canonical = {
|
|
49203
|
-
present:
|
|
49246
|
+
present: existsSync16(canonicalSkillMd),
|
|
49204
49247
|
path: canonicalDir,
|
|
49205
|
-
...
|
|
49206
|
-
...
|
|
49248
|
+
...existsSync16(canonicalSkillMd) ? { hash: hashSkillMarkdownFile(canonicalSkillMd) } : {},
|
|
49249
|
+
...existsSync16(canonicalSkillMd) ? { stub: isPointerSkillMd(readFileSync13(canonicalSkillMd, "utf-8")) } : {}
|
|
49207
49250
|
};
|
|
49208
49251
|
const pinned = getInstalledSkills().includes(bare);
|
|
49209
49252
|
const installMeta = getInstallMeta();
|
|
49210
49253
|
const installedVersion = installMeta.skills[bare]?.version ?? "unknown";
|
|
49211
|
-
const registryPkgPath =
|
|
49254
|
+
const registryPkgPath = join16(sourcePath, "package.json");
|
|
49212
49255
|
let registryVersion = "unknown";
|
|
49213
|
-
if (
|
|
49256
|
+
if (existsSync16(registryPkgPath)) {
|
|
49214
49257
|
try {
|
|
49215
|
-
registryVersion = JSON.parse(
|
|
49258
|
+
registryVersion = JSON.parse(readFileSync13(registryPkgPath, "utf-8")).version || "unknown";
|
|
49216
49259
|
} catch {}
|
|
49217
49260
|
}
|
|
49218
49261
|
const upToDate = installedVersion === registryVersion;
|
|
49219
49262
|
const homes = [];
|
|
49220
49263
|
for (const agent of SYNC_AGENTS) {
|
|
49221
|
-
const dir =
|
|
49222
|
-
const present =
|
|
49223
|
-
const managed =
|
|
49224
|
-
const skillMdPath =
|
|
49225
|
-
const hash = present &&
|
|
49264
|
+
const dir = join16(agentGlobalSkillsDir(agent), normalized);
|
|
49265
|
+
const present = existsSync16(dir);
|
|
49266
|
+
const managed = existsSync16(join16(dir, SYNC_MARKER_FILE));
|
|
49267
|
+
const skillMdPath = join16(dir, "SKILL.md");
|
|
49268
|
+
const hash = present && existsSync16(skillMdPath) ? hashSkillMarkdownFile(skillMdPath) : undefined;
|
|
49226
49269
|
let stub;
|
|
49227
|
-
if (present &&
|
|
49270
|
+
if (present && existsSync16(skillMdPath)) {
|
|
49228
49271
|
try {
|
|
49229
|
-
stub = isPointerSkillMd(
|
|
49272
|
+
stub = isPointerSkillMd(readFileSync13(skillMdPath, "utf-8"));
|
|
49230
49273
|
} catch {
|
|
49231
49274
|
stub = undefined;
|
|
49232
49275
|
}
|
|
@@ -49759,8 +49802,8 @@ var exports_init = {};
|
|
|
49759
49802
|
__export(exports_init, {
|
|
49760
49803
|
registerSetup: () => registerSetup
|
|
49761
49804
|
});
|
|
49762
|
-
import { existsSync as
|
|
49763
|
-
import { join as
|
|
49805
|
+
import { existsSync as existsSync17, readFileSync as readFileSync14, writeFileSync as writeFileSync8, appendFileSync } from "fs";
|
|
49806
|
+
import { join as join17 } from "path";
|
|
49764
49807
|
function registerSetup(parent) {
|
|
49765
49808
|
parent.command("init").option("--json", "Output as JSON", false).option("--for <agent>", "Detect project type and show MCP registration guidance for agent").option("--scope <scope>", "Deprecated; agent skill-folder installs are disabled", "global").description("Initialize project for pinned skills (.env.example, .gitignore)").action((options) => handleInit(options));
|
|
49766
49809
|
parent.command("export").option("--json", "Output as JSON (default behavior)", false).description("Export pinned skills to JSON for sharing or backup").action((_options) => handleExport());
|
|
@@ -49844,7 +49887,7 @@ Use: skills render`));
|
|
|
49844
49887
|
lines.push(`# Used by: ${skills.join(", ")}`);
|
|
49845
49888
|
lines.push(`${envVar}=`);
|
|
49846
49889
|
}
|
|
49847
|
-
writeFileSync8(
|
|
49890
|
+
writeFileSync8(join17(cwd2, ".env.example"), lines.join(`
|
|
49848
49891
|
`) + `
|
|
49849
49892
|
`);
|
|
49850
49893
|
envVarCount = envMap.size;
|
|
@@ -49852,9 +49895,9 @@ Use: skills render`));
|
|
|
49852
49895
|
console.log(source_default.green(`\u2713 Generated .env.example (${envVarCount} variables from ${installed.length} skills)`));
|
|
49853
49896
|
} else if (!options.json)
|
|
49854
49897
|
console.log(source_default.dim(" No environment variables detected across pinned skills"));
|
|
49855
|
-
const gitignorePath =
|
|
49898
|
+
const gitignorePath = join17(cwd2, ".gitignore");
|
|
49856
49899
|
const gitignoreEntries = [".skills/runs/", ".skills/exports/", ".skills/tmp/"];
|
|
49857
|
-
let gitignoreContent =
|
|
49900
|
+
let gitignoreContent = existsSync17(gitignorePath) ? readFileSync14(gitignorePath, "utf-8") : "";
|
|
49858
49901
|
let gitignoreUpdated = false;
|
|
49859
49902
|
const missingEntries = gitignoreEntries.filter((entry) => !gitignoreContent.includes(entry));
|
|
49860
49903
|
if (missingEntries.length > 0) {
|
|
@@ -49900,7 +49943,7 @@ async function handleImport(file, options) {
|
|
|
49900
49943
|
if (file === "-")
|
|
49901
49944
|
raw = await new Response(process.stdin).text();
|
|
49902
49945
|
else {
|
|
49903
|
-
if (!
|
|
49946
|
+
if (!existsSync17(file)) {
|
|
49904
49947
|
const error = `File not found: ${file}`;
|
|
49905
49948
|
if (options.json)
|
|
49906
49949
|
console.log(JSON.stringify({ imported: 0, error }));
|
|
@@ -49909,7 +49952,7 @@ async function handleImport(file, options) {
|
|
|
49909
49952
|
process.exitCode = 1;
|
|
49910
49953
|
return;
|
|
49911
49954
|
}
|
|
49912
|
-
raw =
|
|
49955
|
+
raw = readFileSync14(file, "utf-8");
|
|
49913
49956
|
}
|
|
49914
49957
|
} catch (err) {
|
|
49915
49958
|
const error = `Failed to read file: ${err.message}`;
|
|
@@ -50006,24 +50049,24 @@ var init_init = __esm(() => {
|
|
|
50006
50049
|
});
|
|
50007
50050
|
|
|
50008
50051
|
// src/lib/home-adoption.ts
|
|
50009
|
-
import { existsSync as
|
|
50052
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync8, readdirSync as readdirSync9, readFileSync as readFileSync15, rmSync as rmSync5, statSync as statSync9, writeFileSync as writeFileSync9 } from "fs";
|
|
50010
50053
|
import { homedir as homedir6 } from "os";
|
|
50011
|
-
import { join as
|
|
50054
|
+
import { join as join18 } from "path";
|
|
50012
50055
|
function indexCanonicalCorpus(corpusRoot) {
|
|
50013
50056
|
const byName = new Map;
|
|
50014
|
-
if (!
|
|
50057
|
+
if (!existsSync18(corpusRoot))
|
|
50015
50058
|
return byName;
|
|
50016
50059
|
let entries = [];
|
|
50017
50060
|
try {
|
|
50018
|
-
entries =
|
|
50061
|
+
entries = readdirSync9(corpusRoot);
|
|
50019
50062
|
} catch {
|
|
50020
50063
|
return byName;
|
|
50021
50064
|
}
|
|
50022
50065
|
for (const entry of entries.sort()) {
|
|
50023
50066
|
if (entry.startsWith("."))
|
|
50024
50067
|
continue;
|
|
50025
|
-
const skillMd =
|
|
50026
|
-
if (!
|
|
50068
|
+
const skillMd = join18(corpusRoot, entry, "SKILL.md");
|
|
50069
|
+
if (!existsSync18(skillMd))
|
|
50027
50070
|
continue;
|
|
50028
50071
|
try {
|
|
50029
50072
|
byName.set(entry, hashSkillMarkdownFile(skillMd));
|
|
@@ -50039,33 +50082,33 @@ function scanUnmarkedHomes(options = {}) {
|
|
|
50039
50082
|
const scan = { adoptable: [], conflicts: [], unknown: [], managed: 0 };
|
|
50040
50083
|
for (const agent of agents) {
|
|
50041
50084
|
const home = agentGlobalSkillsDir(agent, homeDir);
|
|
50042
|
-
if (!
|
|
50085
|
+
if (!existsSync18(home))
|
|
50043
50086
|
continue;
|
|
50044
50087
|
let entries = [];
|
|
50045
50088
|
try {
|
|
50046
|
-
entries =
|
|
50089
|
+
entries = readdirSync9(home);
|
|
50047
50090
|
} catch {
|
|
50048
50091
|
continue;
|
|
50049
50092
|
}
|
|
50050
50093
|
for (const skill of entries.sort()) {
|
|
50051
50094
|
if (skill.startsWith("."))
|
|
50052
50095
|
continue;
|
|
50053
|
-
const dir =
|
|
50096
|
+
const dir = join18(home, skill);
|
|
50054
50097
|
try {
|
|
50055
|
-
if (!
|
|
50098
|
+
if (!statSync9(dir).isDirectory())
|
|
50056
50099
|
continue;
|
|
50057
50100
|
} catch {
|
|
50058
50101
|
continue;
|
|
50059
50102
|
}
|
|
50060
|
-
if (
|
|
50103
|
+
if (existsSync18(join18(dir, SYNC_MARKER_FILE))) {
|
|
50061
50104
|
scan.managed += 1;
|
|
50062
50105
|
continue;
|
|
50063
50106
|
}
|
|
50064
|
-
const skillMdPath =
|
|
50065
|
-
if (!
|
|
50107
|
+
const skillMdPath = join18(dir, "SKILL.md");
|
|
50108
|
+
if (!existsSync18(skillMdPath))
|
|
50066
50109
|
continue;
|
|
50067
50110
|
const hash = hashSkillMarkdownFile(skillMdPath);
|
|
50068
|
-
const mtime =
|
|
50111
|
+
const mtime = statSync9(skillMdPath).mtime.toISOString();
|
|
50069
50112
|
const entry = { agent, skill, home, path: dir, hash, mtime };
|
|
50070
50113
|
const canonicalHash = index.get(skill);
|
|
50071
50114
|
if (canonicalHash === undefined) {
|
|
@@ -50082,11 +50125,11 @@ function scanUnmarkedHomes(options = {}) {
|
|
|
50082
50125
|
function appendConflictsLedger(appDir, conflicts) {
|
|
50083
50126
|
if (conflicts.length === 0)
|
|
50084
50127
|
return;
|
|
50085
|
-
const ledgerPath =
|
|
50128
|
+
const ledgerPath = join18(appDir, CONFLICTS_LEDGER_FILE);
|
|
50086
50129
|
let ledger = { version: 1, entries: [] };
|
|
50087
|
-
if (
|
|
50130
|
+
if (existsSync18(ledgerPath)) {
|
|
50088
50131
|
try {
|
|
50089
|
-
const parsed = JSON.parse(
|
|
50132
|
+
const parsed = JSON.parse(readFileSync15(ledgerPath, "utf-8"));
|
|
50090
50133
|
if (parsed && typeof parsed === "object" && Array.isArray(parsed.entries)) {
|
|
50091
50134
|
ledger = parsed;
|
|
50092
50135
|
}
|
|
@@ -50102,9 +50145,9 @@ function appendConflictsLedger(appDir, conflicts) {
|
|
|
50102
50145
|
`);
|
|
50103
50146
|
}
|
|
50104
50147
|
function writeRollbackRecord(mode, entries, appDir = getDataDir()) {
|
|
50105
|
-
const dir =
|
|
50148
|
+
const dir = join18(appDir, ROLLBACK_DIRNAME);
|
|
50106
50149
|
mkdirSync8(dir, { recursive: true });
|
|
50107
|
-
const file =
|
|
50150
|
+
const file = join18(dir, `${mode}-${Date.now()}.json`);
|
|
50108
50151
|
const record = { version: 1, mode, timestamp: new Date().toISOString(), entries };
|
|
50109
50152
|
writeFileSync9(file, `${JSON.stringify(record, null, 2)}
|
|
50110
50153
|
`);
|
|
@@ -50115,7 +50158,7 @@ function adoptUnmarkedHomes(options = {}) {
|
|
|
50115
50158
|
if (!options.apply) {
|
|
50116
50159
|
return { ...scan, applied: false };
|
|
50117
50160
|
}
|
|
50118
|
-
const appDir = options.homeDir ?
|
|
50161
|
+
const appDir = options.homeDir ? join18(options.homeDir, ".hasna", "skills") : getDataDir();
|
|
50119
50162
|
const markers = scan.adoptable.map((entry) => {
|
|
50120
50163
|
const marker = {
|
|
50121
50164
|
managedBy: SYNC_MARKER_MANAGED_BY,
|
|
@@ -50123,7 +50166,7 @@ function adoptUnmarkedHomes(options = {}) {
|
|
|
50123
50166
|
source: "adopted",
|
|
50124
50167
|
syncedAt: new Date().toISOString()
|
|
50125
50168
|
};
|
|
50126
|
-
writeFileSync9(
|
|
50169
|
+
writeFileSync9(join18(entry.path, SYNC_MARKER_FILE), `${JSON.stringify(marker, null, 2)}
|
|
50127
50170
|
`);
|
|
50128
50171
|
return { agent: entry.agent, skill: entry.skill, path: entry.path, hash: entry.hash, marker };
|
|
50129
50172
|
});
|
|
@@ -50142,47 +50185,47 @@ function pruneStrayHomes(options = {}) {
|
|
|
50142
50185
|
const candidates = [];
|
|
50143
50186
|
for (const agent of agents) {
|
|
50144
50187
|
const home = agentGlobalSkillsDir(agent, homeDir);
|
|
50145
|
-
if (!
|
|
50188
|
+
if (!existsSync18(home))
|
|
50146
50189
|
continue;
|
|
50147
50190
|
let entries = [];
|
|
50148
50191
|
try {
|
|
50149
|
-
entries =
|
|
50192
|
+
entries = readdirSync9(home);
|
|
50150
50193
|
} catch {
|
|
50151
50194
|
continue;
|
|
50152
50195
|
}
|
|
50153
50196
|
for (const skill of entries.sort()) {
|
|
50154
50197
|
if (skill.startsWith("."))
|
|
50155
50198
|
continue;
|
|
50156
|
-
const dir =
|
|
50199
|
+
const dir = join18(home, skill);
|
|
50157
50200
|
try {
|
|
50158
|
-
if (!
|
|
50201
|
+
if (!statSync9(dir).isDirectory())
|
|
50159
50202
|
continue;
|
|
50160
50203
|
} catch {
|
|
50161
50204
|
continue;
|
|
50162
50205
|
}
|
|
50163
|
-
const markerPath =
|
|
50164
|
-
if (!
|
|
50206
|
+
const markerPath = join18(dir, SYNC_MARKER_FILE);
|
|
50207
|
+
if (!existsSync18(markerPath))
|
|
50165
50208
|
continue;
|
|
50166
50209
|
if (index.has(skill))
|
|
50167
50210
|
continue;
|
|
50168
50211
|
let marker;
|
|
50169
50212
|
try {
|
|
50170
|
-
const parsed = JSON.parse(
|
|
50213
|
+
const parsed = JSON.parse(readFileSync15(markerPath, "utf-8"));
|
|
50171
50214
|
if (!parsed || typeof parsed !== "object" || typeof parsed.managedBy !== "string")
|
|
50172
50215
|
continue;
|
|
50173
50216
|
marker = parsed;
|
|
50174
50217
|
} catch {
|
|
50175
50218
|
continue;
|
|
50176
50219
|
}
|
|
50177
|
-
const skillMdPath =
|
|
50178
|
-
const hash =
|
|
50220
|
+
const skillMdPath = join18(dir, "SKILL.md");
|
|
50221
|
+
const hash = existsSync18(skillMdPath) ? hashSkillMarkdownFile(skillMdPath) : "";
|
|
50179
50222
|
candidates.push({ agent, skill, home, path: dir, hash, marker });
|
|
50180
50223
|
}
|
|
50181
50224
|
}
|
|
50182
50225
|
if (!options.apply) {
|
|
50183
50226
|
return { candidates, pruned: 0, dryRun: true };
|
|
50184
50227
|
}
|
|
50185
|
-
const appDir = options.homeDir ?
|
|
50228
|
+
const appDir = options.homeDir ? join18(options.homeDir, ".hasna", "skills") : getDataDir();
|
|
50186
50229
|
const rollbackFile = writeRollbackRecord("prune", candidates.map(({ agent, skill, path, hash, marker }) => ({ agent, skill, path, hash, marker })), appDir);
|
|
50187
50230
|
for (const candidate of candidates) {
|
|
50188
50231
|
rmSync5(candidate.path, { recursive: true, force: true });
|
|
@@ -50198,9 +50241,9 @@ var init_home_adoption = __esm(() => {
|
|
|
50198
50241
|
});
|
|
50199
50242
|
|
|
50200
50243
|
// src/lib/home-census.ts
|
|
50201
|
-
import { existsSync as
|
|
50244
|
+
import { existsSync as existsSync19, readFileSync as readFileSync16, readdirSync as readdirSync10, statSync as statSync10 } from "fs";
|
|
50202
50245
|
import { homedir as homedir7 } from "os";
|
|
50203
|
-
import { join as
|
|
50246
|
+
import { join as join19 } from "path";
|
|
50204
50247
|
function sortEntries(entries) {
|
|
50205
50248
|
return entries.sort((a, b) => {
|
|
50206
50249
|
const left = `${a.agent}/${a.skill}/${a.kind}`;
|
|
@@ -50219,29 +50262,29 @@ function censusHomeDrift(options = {}) {
|
|
|
50219
50262
|
let homesChecked = 0;
|
|
50220
50263
|
for (const agent of agents) {
|
|
50221
50264
|
const home = agentGlobalSkillsDir(agent, homeDir);
|
|
50222
|
-
if (!
|
|
50265
|
+
if (!existsSync19(home))
|
|
50223
50266
|
continue;
|
|
50224
50267
|
homesChecked += 1;
|
|
50225
50268
|
const present = new Set;
|
|
50226
50269
|
let dirEntries = [];
|
|
50227
50270
|
try {
|
|
50228
|
-
dirEntries =
|
|
50271
|
+
dirEntries = readdirSync10(home);
|
|
50229
50272
|
} catch {
|
|
50230
50273
|
continue;
|
|
50231
50274
|
}
|
|
50232
50275
|
for (const skill of dirEntries.sort()) {
|
|
50233
50276
|
if (skill.startsWith("."))
|
|
50234
50277
|
continue;
|
|
50235
|
-
const dir =
|
|
50278
|
+
const dir = join19(home, skill);
|
|
50236
50279
|
try {
|
|
50237
|
-
if (!
|
|
50280
|
+
if (!statSync10(dir).isDirectory())
|
|
50238
50281
|
continue;
|
|
50239
50282
|
} catch {
|
|
50240
50283
|
continue;
|
|
50241
50284
|
}
|
|
50242
50285
|
present.add(skill);
|
|
50243
|
-
const markerPath =
|
|
50244
|
-
if (!
|
|
50286
|
+
const markerPath = join19(dir, SYNC_MARKER_FILE);
|
|
50287
|
+
if (!existsSync19(markerPath)) {
|
|
50245
50288
|
unmarked += 1;
|
|
50246
50289
|
continue;
|
|
50247
50290
|
}
|
|
@@ -50251,8 +50294,8 @@ function censusHomeDrift(options = {}) {
|
|
|
50251
50294
|
entries.push({ agent, skill, kind: "stray-in-home", path: dir });
|
|
50252
50295
|
continue;
|
|
50253
50296
|
}
|
|
50254
|
-
const skillMdPath =
|
|
50255
|
-
if (!
|
|
50297
|
+
const skillMdPath = join19(dir, "SKILL.md");
|
|
50298
|
+
if (!existsSync19(skillMdPath)) {
|
|
50256
50299
|
entries.push({ agent, skill, kind: "diverged", path: dir, canonicalHash });
|
|
50257
50300
|
continue;
|
|
50258
50301
|
}
|
|
@@ -50260,14 +50303,14 @@ function censusHomeDrift(options = {}) {
|
|
|
50260
50303
|
if (homeHash !== canonicalHash) {
|
|
50261
50304
|
let homeStub;
|
|
50262
50305
|
try {
|
|
50263
|
-
homeStub = isPointerSkillMd(
|
|
50306
|
+
homeStub = isPointerSkillMd(readFileSync16(skillMdPath, "utf-8"));
|
|
50264
50307
|
} catch {
|
|
50265
50308
|
homeStub = undefined;
|
|
50266
50309
|
}
|
|
50267
50310
|
let canonicalStub;
|
|
50268
|
-
const canonicalSkillMd =
|
|
50311
|
+
const canonicalSkillMd = join19(corpusRoot, skill, "SKILL.md");
|
|
50269
50312
|
try {
|
|
50270
|
-
canonicalStub = isPointerSkillMd(
|
|
50313
|
+
canonicalStub = isPointerSkillMd(readFileSync16(canonicalSkillMd, "utf-8"));
|
|
50271
50314
|
} catch {
|
|
50272
50315
|
canonicalStub = undefined;
|
|
50273
50316
|
}
|
|
@@ -50280,7 +50323,7 @@ function censusHomeDrift(options = {}) {
|
|
|
50280
50323
|
agent,
|
|
50281
50324
|
skill: name,
|
|
50282
50325
|
kind: "missing-from-home",
|
|
50283
|
-
path:
|
|
50326
|
+
path: join19(home, name),
|
|
50284
50327
|
canonicalHash
|
|
50285
50328
|
});
|
|
50286
50329
|
}
|
|
@@ -50306,8 +50349,8 @@ var exports_diagnostic = {};
|
|
|
50306
50349
|
__export(exports_diagnostic, {
|
|
50307
50350
|
registerDiagnostic: () => registerDiagnostic
|
|
50308
50351
|
});
|
|
50309
|
-
import { existsSync as
|
|
50310
|
-
import { join as
|
|
50352
|
+
import { existsSync as existsSync20, readFileSync as readFileSync17, readdirSync as readdirSync11, statSync as statSync11, writeFileSync as writeFileSync10 } from "fs";
|
|
50353
|
+
import { join as join20 } from "path";
|
|
50311
50354
|
import { execSync as execSync2 } from "child_process";
|
|
50312
50355
|
function registerDiagnostic(parent) {
|
|
50313
50356
|
parent.command("doctor").option("--json", "Output as JSON", false).description("Check env vars, system deps, and readiness for pinned skills").action((options) => handleDoctor(options));
|
|
@@ -50423,7 +50466,7 @@ Skills Test (${results.length} skill${results.length === 1 ? "" : "s"}):
|
|
|
50423
50466
|
}
|
|
50424
50467
|
function handleAuth(name, options) {
|
|
50425
50468
|
const cwd2 = process.cwd();
|
|
50426
|
-
const envFilePath =
|
|
50469
|
+
const envFilePath = join20(cwd2, ".env");
|
|
50427
50470
|
if (options.set) {
|
|
50428
50471
|
const eqIdx = options.set.indexOf("=");
|
|
50429
50472
|
if (eqIdx === -1) {
|
|
@@ -50445,7 +50488,7 @@ function handleAuth(name, options) {
|
|
|
50445
50488
|
process.exitCode = 1;
|
|
50446
50489
|
return;
|
|
50447
50490
|
}
|
|
50448
|
-
let existing =
|
|
50491
|
+
let existing = existsSync20(envFilePath) ? readFileSync17(envFilePath, "utf-8") : "";
|
|
50449
50492
|
const keyPattern = new RegExp(`^${key}=.*$`, "m");
|
|
50450
50493
|
const updated = keyPattern.test(existing) ? existing.replace(keyPattern, `${key}=${value}`) : existing.endsWith(`
|
|
50451
50494
|
`) || existing === "" ? existing + `${key}=${value}
|
|
@@ -50511,11 +50554,11 @@ function handleWhoami(options) {
|
|
|
50511
50554
|
const agentConfigs = [];
|
|
50512
50555
|
for (const agent of AGENT_TARGETS) {
|
|
50513
50556
|
const agentSkillsPath = getAgentSkillsDir(agent, "global");
|
|
50514
|
-
const exists =
|
|
50557
|
+
const exists = existsSync20(agentSkillsPath);
|
|
50515
50558
|
let skillCount = 0;
|
|
50516
50559
|
if (exists)
|
|
50517
50560
|
try {
|
|
50518
|
-
skillCount =
|
|
50561
|
+
skillCount = readdirSync11(agentSkillsPath).filter((f) => !f.startsWith(".") && statSync11(join20(agentSkillsPath, f)).isDirectory()).length;
|
|
50519
50562
|
} catch {}
|
|
50520
50563
|
agentConfigs.push({ agent, label: AGENT_LABELS[agent], path: agentSkillsPath, exists, skillCount });
|
|
50521
50564
|
}
|
|
@@ -50549,11 +50592,11 @@ function handleOutdated(options) {
|
|
|
50549
50592
|
for (const name of installed) {
|
|
50550
50593
|
const installedVersion = meta.skills[name]?.version ?? "unknown";
|
|
50551
50594
|
const registryPath = getSkillPath(name);
|
|
50552
|
-
const registryPkgPath =
|
|
50595
|
+
const registryPkgPath = join20(registryPath, "package.json");
|
|
50553
50596
|
let registryVersion = "unknown";
|
|
50554
|
-
if (
|
|
50597
|
+
if (existsSync20(registryPkgPath))
|
|
50555
50598
|
try {
|
|
50556
|
-
registryVersion = JSON.parse(
|
|
50599
|
+
registryVersion = JSON.parse(readFileSync17(registryPkgPath, "utf-8")).version || "unknown";
|
|
50557
50600
|
} catch {}
|
|
50558
50601
|
if (installedVersion !== registryVersion)
|
|
50559
50602
|
pins.push({ skill: name, installedVersion, registryVersion });
|
|
@@ -50817,20 +50860,20 @@ var init_runs = __esm(() => {
|
|
|
50817
50860
|
|
|
50818
50861
|
// src/lib/run-state.ts
|
|
50819
50862
|
import { createHash as createHash2, randomBytes } from "crypto";
|
|
50820
|
-
import { existsSync as
|
|
50821
|
-
import { extname, join as
|
|
50863
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync9, readFileSync as readFileSync18, readdirSync as readdirSync12, statSync as statSync12, writeFileSync as writeFileSync11 } from "fs";
|
|
50864
|
+
import { extname, join as join21, relative as relative2 } from "path";
|
|
50822
50865
|
function createSkillRun(params, targetDir = process.cwd()) {
|
|
50823
50866
|
const now3 = new Date;
|
|
50824
50867
|
const id = createRunId(now3);
|
|
50825
50868
|
const day = now3.toISOString().slice(0, 10);
|
|
50826
50869
|
const skillName = normalizeSkillName(params.skill);
|
|
50827
50870
|
const root = getProjectStateDir(targetDir);
|
|
50828
|
-
const runDir =
|
|
50829
|
-
const logsDir =
|
|
50830
|
-
const exportDir =
|
|
50871
|
+
const runDir = join21(root, "runs", day, id);
|
|
50872
|
+
const logsDir = join21(runDir, "logs");
|
|
50873
|
+
const exportDir = join21(root, "exports", skillName, id);
|
|
50831
50874
|
mkdirSync9(logsDir, { recursive: true });
|
|
50832
50875
|
mkdirSync9(exportDir, { recursive: true });
|
|
50833
|
-
mkdirSync9(
|
|
50876
|
+
mkdirSync9(join21(root, "tmp"), { recursive: true });
|
|
50834
50877
|
const record = {
|
|
50835
50878
|
id,
|
|
50836
50879
|
skill: skillName,
|
|
@@ -50881,27 +50924,27 @@ function updateSkillRun(context, patch) {
|
|
|
50881
50924
|
return context.record;
|
|
50882
50925
|
}
|
|
50883
50926
|
function writeRunLogs(context, stdout = "", stderr = "") {
|
|
50884
|
-
writeFileSync11(
|
|
50885
|
-
writeFileSync11(
|
|
50927
|
+
writeFileSync11(join21(context.logsDir, "stdout.log"), stdout);
|
|
50928
|
+
writeFileSync11(join21(context.logsDir, "stderr.log"), stderr);
|
|
50886
50929
|
}
|
|
50887
50930
|
function appendRunEvent(context, event, data = {}) {
|
|
50888
50931
|
const line = JSON.stringify({ ts: new Date().toISOString(), event, ...data }) + `
|
|
50889
50932
|
`;
|
|
50890
|
-
const path =
|
|
50891
|
-
const previous =
|
|
50933
|
+
const path = join21(context.runDir, "events.ndjson");
|
|
50934
|
+
const previous = existsSync21(path) ? readFileSync18(path, "utf-8") : "";
|
|
50892
50935
|
writeFileSync11(path, previous + line);
|
|
50893
50936
|
}
|
|
50894
50937
|
function listSkillRuns(targetDir = process.cwd(), limit = 50) {
|
|
50895
|
-
const runsRoot =
|
|
50896
|
-
if (!
|
|
50938
|
+
const runsRoot = join21(getProjectStateDir(targetDir), "runs");
|
|
50939
|
+
if (!existsSync21(runsRoot))
|
|
50897
50940
|
return [];
|
|
50898
50941
|
const records = [];
|
|
50899
|
-
for (const day of
|
|
50900
|
-
const dayDir =
|
|
50901
|
-
if (!
|
|
50942
|
+
for (const day of readdirSync12(runsRoot).sort().reverse()) {
|
|
50943
|
+
const dayDir = join21(runsRoot, day);
|
|
50944
|
+
if (!statSync12(dayDir).isDirectory())
|
|
50902
50945
|
continue;
|
|
50903
|
-
for (const runId of
|
|
50904
|
-
const record = readRunRecord(
|
|
50946
|
+
for (const runId of readdirSync12(dayDir).sort().reverse()) {
|
|
50947
|
+
const record = readRunRecord(join21(dayDir, runId));
|
|
50905
50948
|
if (record)
|
|
50906
50949
|
records.push(record);
|
|
50907
50950
|
if (records.length >= limit)
|
|
@@ -50911,11 +50954,11 @@ function listSkillRuns(targetDir = process.cwd(), limit = 50) {
|
|
|
50911
50954
|
return records;
|
|
50912
50955
|
}
|
|
50913
50956
|
function findSkillRun(runId, targetDir = process.cwd()) {
|
|
50914
|
-
const runsRoot =
|
|
50915
|
-
if (!
|
|
50957
|
+
const runsRoot = join21(getProjectStateDir(targetDir), "runs");
|
|
50958
|
+
if (!existsSync21(runsRoot))
|
|
50916
50959
|
return null;
|
|
50917
|
-
for (const day of
|
|
50918
|
-
const record = readRunRecord(
|
|
50960
|
+
for (const day of readdirSync12(runsRoot)) {
|
|
50961
|
+
const record = readRunRecord(join21(runsRoot, day, runId));
|
|
50919
50962
|
if (record)
|
|
50920
50963
|
return record;
|
|
50921
50964
|
}
|
|
@@ -50932,23 +50975,23 @@ function skillRunEnv(context) {
|
|
|
50932
50975
|
};
|
|
50933
50976
|
}
|
|
50934
50977
|
function getRunExportDir(runId, skill, targetDir = process.cwd()) {
|
|
50935
|
-
return
|
|
50978
|
+
return join21(getProjectStateDir(targetDir), "exports", normalizeSkillName(skill), runId);
|
|
50936
50979
|
}
|
|
50937
50980
|
function writeRunRecord(context) {
|
|
50938
|
-
writeFileSync11(
|
|
50981
|
+
writeFileSync11(join21(context.runDir, "run.json"), JSON.stringify(context.record, null, 2) + `
|
|
50939
50982
|
`);
|
|
50940
50983
|
}
|
|
50941
50984
|
function writeArtifactsManifest(context, artifacts) {
|
|
50942
|
-
writeFileSync11(
|
|
50985
|
+
writeFileSync11(join21(context.runDir, "artifacts.json"), JSON.stringify({ runId: context.record.id, artifacts }, null, 2) + `
|
|
50943
50986
|
`);
|
|
50944
50987
|
}
|
|
50945
50988
|
function collectRunArtifacts(context) {
|
|
50946
|
-
if (!
|
|
50989
|
+
if (!existsSync21(context.exportDir))
|
|
50947
50990
|
return [];
|
|
50948
50991
|
const artifacts = [];
|
|
50949
50992
|
for (const path of walkFiles(context.exportDir)) {
|
|
50950
|
-
const stat =
|
|
50951
|
-
const bytes =
|
|
50993
|
+
const stat = statSync12(path);
|
|
50994
|
+
const bytes = readFileSync18(path);
|
|
50952
50995
|
artifacts.push({
|
|
50953
50996
|
path: toProjectRelative(context.targetDir, path),
|
|
50954
50997
|
mime: mimeForPath(path),
|
|
@@ -50959,20 +51002,20 @@ function collectRunArtifacts(context) {
|
|
|
50959
51002
|
return artifacts.sort((a, b) => a.path.localeCompare(b.path));
|
|
50960
51003
|
}
|
|
50961
51004
|
function readRunRecord(runDir) {
|
|
50962
|
-
const path =
|
|
50963
|
-
if (!
|
|
51005
|
+
const path = join21(runDir, "run.json");
|
|
51006
|
+
if (!existsSync21(path))
|
|
50964
51007
|
return null;
|
|
50965
51008
|
try {
|
|
50966
|
-
return JSON.parse(
|
|
51009
|
+
return JSON.parse(readFileSync18(path, "utf-8"));
|
|
50967
51010
|
} catch {
|
|
50968
51011
|
return null;
|
|
50969
51012
|
}
|
|
50970
51013
|
}
|
|
50971
51014
|
function walkFiles(dir) {
|
|
50972
51015
|
const files = [];
|
|
50973
|
-
for (const entry of
|
|
50974
|
-
const full =
|
|
50975
|
-
if (
|
|
51016
|
+
for (const entry of readdirSync12(dir)) {
|
|
51017
|
+
const full = join21(dir, entry);
|
|
51018
|
+
if (statSync12(full).isDirectory())
|
|
50976
51019
|
files.push(...walkFiles(full));
|
|
50977
51020
|
else
|
|
50978
51021
|
files.push(full);
|
|
@@ -56445,6 +56488,42 @@ var init_types2 = __esm(() => {
|
|
|
56445
56488
|
});
|
|
56446
56489
|
|
|
56447
56490
|
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
|
|
56491
|
+
class ReadBuffer {
|
|
56492
|
+
constructor(options) {
|
|
56493
|
+
this._maxBufferSize = options?.maxBufferSize ?? STDIO_DEFAULT_MAX_BUFFER_SIZE;
|
|
56494
|
+
}
|
|
56495
|
+
append(chunk2) {
|
|
56496
|
+
const newSize = (this._buffer?.length ?? 0) + chunk2.length;
|
|
56497
|
+
if (newSize > this._maxBufferSize) {
|
|
56498
|
+
this.clear();
|
|
56499
|
+
throw new Error(`ReadBuffer exceeded maximum size of ${this._maxBufferSize} bytes`);
|
|
56500
|
+
}
|
|
56501
|
+
this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk2]) : chunk2;
|
|
56502
|
+
}
|
|
56503
|
+
readMessage() {
|
|
56504
|
+
if (!this._buffer) {
|
|
56505
|
+
return null;
|
|
56506
|
+
}
|
|
56507
|
+
const index = this._buffer.indexOf(`
|
|
56508
|
+
`);
|
|
56509
|
+
if (index === -1) {
|
|
56510
|
+
return null;
|
|
56511
|
+
}
|
|
56512
|
+
const line = this._buffer.toString("utf8", 0, index).replace(/\r$/, "");
|
|
56513
|
+
this._buffer = this._buffer.subarray(index + 1);
|
|
56514
|
+
return deserializeMessage(line);
|
|
56515
|
+
}
|
|
56516
|
+
clear() {
|
|
56517
|
+
this._buffer = undefined;
|
|
56518
|
+
}
|
|
56519
|
+
}
|
|
56520
|
+
function deserializeMessage(line) {
|
|
56521
|
+
return JSONRPCMessageSchema.parse(JSON.parse(line));
|
|
56522
|
+
}
|
|
56523
|
+
function serializeMessage(message) {
|
|
56524
|
+
return JSON.stringify(message) + `
|
|
56525
|
+
`;
|
|
56526
|
+
}
|
|
56448
56527
|
var STDIO_DEFAULT_MAX_BUFFER_SIZE;
|
|
56449
56528
|
var init_stdio = __esm(() => {
|
|
56450
56529
|
init_types2();
|
|
@@ -56452,6 +56531,69 @@ var init_stdio = __esm(() => {
|
|
|
56452
56531
|
});
|
|
56453
56532
|
|
|
56454
56533
|
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
56534
|
+
import process14 from "process";
|
|
56535
|
+
|
|
56536
|
+
class StdioServerTransport {
|
|
56537
|
+
constructor(_stdin = process14.stdin, _stdout = process14.stdout, options) {
|
|
56538
|
+
this._stdin = _stdin;
|
|
56539
|
+
this._stdout = _stdout;
|
|
56540
|
+
this._started = false;
|
|
56541
|
+
this._ondata = (chunk2) => {
|
|
56542
|
+
try {
|
|
56543
|
+
this._readBuffer.append(chunk2);
|
|
56544
|
+
this.processReadBuffer();
|
|
56545
|
+
} catch (error2) {
|
|
56546
|
+
this.onerror?.(error2);
|
|
56547
|
+
this.close().catch(() => {});
|
|
56548
|
+
}
|
|
56549
|
+
};
|
|
56550
|
+
this._onerror = (error2) => {
|
|
56551
|
+
this.onerror?.(error2);
|
|
56552
|
+
};
|
|
56553
|
+
this._readBuffer = new ReadBuffer({ maxBufferSize: options?.maxBufferSize });
|
|
56554
|
+
}
|
|
56555
|
+
async start() {
|
|
56556
|
+
if (this._started) {
|
|
56557
|
+
throw new Error("StdioServerTransport already started! If using Server class, note that connect() calls start() automatically.");
|
|
56558
|
+
}
|
|
56559
|
+
this._started = true;
|
|
56560
|
+
this._stdin.on("data", this._ondata);
|
|
56561
|
+
this._stdin.on("error", this._onerror);
|
|
56562
|
+
}
|
|
56563
|
+
processReadBuffer() {
|
|
56564
|
+
while (true) {
|
|
56565
|
+
try {
|
|
56566
|
+
const message = this._readBuffer.readMessage();
|
|
56567
|
+
if (message === null) {
|
|
56568
|
+
break;
|
|
56569
|
+
}
|
|
56570
|
+
this.onmessage?.(message);
|
|
56571
|
+
} catch (error2) {
|
|
56572
|
+
this.onerror?.(error2);
|
|
56573
|
+
}
|
|
56574
|
+
}
|
|
56575
|
+
}
|
|
56576
|
+
async close() {
|
|
56577
|
+
this._stdin.off("data", this._ondata);
|
|
56578
|
+
this._stdin.off("error", this._onerror);
|
|
56579
|
+
const remainingDataListeners = this._stdin.listenerCount("data");
|
|
56580
|
+
if (remainingDataListeners === 0) {
|
|
56581
|
+
this._stdin.pause();
|
|
56582
|
+
}
|
|
56583
|
+
this._readBuffer.clear();
|
|
56584
|
+
this.onclose?.();
|
|
56585
|
+
}
|
|
56586
|
+
send(message) {
|
|
56587
|
+
return new Promise((resolve) => {
|
|
56588
|
+
const json = serializeMessage(message);
|
|
56589
|
+
if (this._stdout.write(json)) {
|
|
56590
|
+
resolve();
|
|
56591
|
+
} else {
|
|
56592
|
+
this._stdout.once("drain", resolve);
|
|
56593
|
+
}
|
|
56594
|
+
});
|
|
56595
|
+
}
|
|
56596
|
+
}
|
|
56455
56597
|
var init_stdio2 = __esm(() => {
|
|
56456
56598
|
init_stdio();
|
|
56457
56599
|
});
|
|
@@ -68186,6 +68328,43 @@ var init_discovery_tools = __esm(() => {
|
|
|
68186
68328
|
init_helpers();
|
|
68187
68329
|
});
|
|
68188
68330
|
|
|
68331
|
+
// src/lib/run-routing.ts
|
|
68332
|
+
var exports_run_routing = {};
|
|
68333
|
+
__export(exports_run_routing, {
|
|
68334
|
+
resolveRunRouting: () => resolveRunRouting,
|
|
68335
|
+
resolveConfiguredRunRouting: () => resolveConfiguredRunRouting,
|
|
68336
|
+
isServerOwnedSkill: () => isServerOwnedSkill
|
|
68337
|
+
});
|
|
68338
|
+
function isServerOwnedSkill(skill) {
|
|
68339
|
+
return skill.serverOwned === true;
|
|
68340
|
+
}
|
|
68341
|
+
function resolveRunRouting(skill, apiKey, apiUrl) {
|
|
68342
|
+
if (!isServerOwnedSkill(skill))
|
|
68343
|
+
return { route: "local" };
|
|
68344
|
+
if (!apiUrl) {
|
|
68345
|
+
return {
|
|
68346
|
+
route: "error",
|
|
68347
|
+
code: "REMOTE_REQUIRES_ORIGIN",
|
|
68348
|
+
error: `${skill.name} is a server-owned skill. Point the CLI at a Skills API: ` + `skills setup --api-url <url> (or export SKILLS_API_URL)`
|
|
68349
|
+
};
|
|
68350
|
+
}
|
|
68351
|
+
if (!apiKey) {
|
|
68352
|
+
return {
|
|
68353
|
+
route: "error",
|
|
68354
|
+
code: "REMOTE_REQUIRES_CREDENTIAL",
|
|
68355
|
+
error: `${skill.name} is a server-owned skill. Run: skills auth login`
|
|
68356
|
+
};
|
|
68357
|
+
}
|
|
68358
|
+
return { route: "remote", apiKey };
|
|
68359
|
+
}
|
|
68360
|
+
function resolveConfiguredRunRouting(skill) {
|
|
68361
|
+
return resolveRunRouting(skill, getApiKey(), resolveApiUrl());
|
|
68362
|
+
}
|
|
68363
|
+
var init_run_routing = __esm(() => {
|
|
68364
|
+
init_api_url();
|
|
68365
|
+
init_auth_store();
|
|
68366
|
+
});
|
|
68367
|
+
|
|
68189
68368
|
// src/lib/remote-client.ts
|
|
68190
68369
|
var exports_remote_client = {};
|
|
68191
68370
|
__export(exports_remote_client, {
|
|
@@ -68486,8 +68665,8 @@ var init_remote_client = __esm(() => {
|
|
|
68486
68665
|
});
|
|
68487
68666
|
|
|
68488
68667
|
// src/mcp/operation-tools.ts
|
|
68489
|
-
import { existsSync as
|
|
68490
|
-
import { join as
|
|
68668
|
+
import { existsSync as existsSync22, readdirSync as readdirSync13, statSync as statSync13 } from "fs";
|
|
68669
|
+
import { join as join22 } from "path";
|
|
68491
68670
|
function registerOperationTools(server) {
|
|
68492
68671
|
server.registerTool("scaffold_skill", {
|
|
68493
68672
|
title: "Scaffold Skill",
|
|
@@ -68695,7 +68874,6 @@ function registerOperationTools(server) {
|
|
|
68695
68874
|
if (!skill) {
|
|
68696
68875
|
return mcpError("SKILL_NOT_FOUND", `Skill '${name}' not found`, findSimilarSkills(name));
|
|
68697
68876
|
}
|
|
68698
|
-
const { getApiKey: getApiKey2 } = await Promise.resolve().then(() => (init_auth_store(), exports_auth_store));
|
|
68699
68877
|
const {
|
|
68700
68878
|
ARTICLE_GENERATION_SLUG: ARTICLE_GENERATION_SLUG2,
|
|
68701
68879
|
validateBlogArticleRunOptions: validateBlogArticleRunOptions2
|
|
@@ -68709,24 +68887,24 @@ function registerOperationTools(server) {
|
|
|
68709
68887
|
return mcpError("INVALID_BLOG_ARTICLE_OPTIONS", validation.errors.join(" "));
|
|
68710
68888
|
}
|
|
68711
68889
|
}
|
|
68712
|
-
const
|
|
68713
|
-
const hostedRuntime = false;
|
|
68890
|
+
const routing = resolveConfiguredRunRouting(skill);
|
|
68714
68891
|
const runContext = createSkillRun({
|
|
68715
68892
|
skill: skillName,
|
|
68716
68893
|
args: runArgs,
|
|
68717
|
-
remote:
|
|
68894
|
+
remote: routing.route === "remote"
|
|
68718
68895
|
});
|
|
68719
|
-
if (
|
|
68720
|
-
const error2 =
|
|
68896
|
+
if (routing.route === "error") {
|
|
68897
|
+
const error2 = routing.error;
|
|
68721
68898
|
writeRunLogs(runContext, "", error2 + `
|
|
68722
68899
|
`);
|
|
68723
68900
|
const run = completeSkillRun(runContext, { status: "failed", error: error2 });
|
|
68724
|
-
|
|
68901
|
+
const suggestions = routing.code === "REMOTE_REQUIRES_ORIGIN" ? ["skills setup --api-url <url>", "skills auth login"] : ["skills auth login"];
|
|
68902
|
+
return mcpError(routing.code, `${error2}. Local run metadata: ${run.paths.runDir}/run.json`, suggestions);
|
|
68725
68903
|
}
|
|
68726
|
-
if (
|
|
68904
|
+
if (routing.route === "remote") {
|
|
68727
68905
|
try {
|
|
68728
68906
|
const { RemoteSkillsClient: RemoteSkillsClient2 } = await Promise.resolve().then(() => (init_remote_client(), exports_remote_client));
|
|
68729
|
-
const client = new RemoteSkillsClient2(apiKey);
|
|
68907
|
+
const client = new RemoteSkillsClient2(routing.apiKey);
|
|
68730
68908
|
const run = await client.submitRun(skillName, runInput, runArgs);
|
|
68731
68909
|
if (run.error) {
|
|
68732
68910
|
writeRunLogs(runContext, "", String(run.error) + `
|
|
@@ -68885,13 +69063,13 @@ function registerOperationTools(server) {
|
|
|
68885
69063
|
const agents = [];
|
|
68886
69064
|
for (const agent of AGENT_TARGETS) {
|
|
68887
69065
|
const agentSkillsPath = getAgentSkillsDir(agent, "global");
|
|
68888
|
-
const exists =
|
|
69066
|
+
const exists = existsSync22(agentSkillsPath);
|
|
68889
69067
|
let skillCount = 0;
|
|
68890
69068
|
if (exists) {
|
|
68891
69069
|
try {
|
|
68892
|
-
skillCount =
|
|
68893
|
-
const full =
|
|
68894
|
-
return !f.startsWith(".") &&
|
|
69070
|
+
skillCount = readdirSync13(agentSkillsPath).filter((f) => {
|
|
69071
|
+
const full = join22(agentSkillsPath, f);
|
|
69072
|
+
return !f.startsWith(".") && statSync13(full).isDirectory();
|
|
68895
69073
|
}).length;
|
|
68896
69074
|
} catch {}
|
|
68897
69075
|
}
|
|
@@ -68943,19 +69121,20 @@ var init_operation_tools = __esm(() => {
|
|
|
68943
69121
|
init_run_state();
|
|
68944
69122
|
init_portable_skills();
|
|
68945
69123
|
init_helpers();
|
|
69124
|
+
init_run_routing();
|
|
68946
69125
|
});
|
|
68947
69126
|
|
|
68948
69127
|
// src/lib/feedback.ts
|
|
68949
|
-
import { existsSync as
|
|
68950
|
-
import { dirname as dirname7, join as
|
|
69128
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync10 } from "fs";
|
|
69129
|
+
import { dirname as dirname7, join as join23 } from "path";
|
|
68951
69130
|
import { Database } from "bun:sqlite";
|
|
68952
69131
|
function getFeedbackDbPath() {
|
|
68953
|
-
return
|
|
69132
|
+
return join23(getDataDir(), "skills.db");
|
|
68954
69133
|
}
|
|
68955
69134
|
function getFeedbackDb() {
|
|
68956
69135
|
const dbPath = getFeedbackDbPath();
|
|
68957
69136
|
const dir = dirname7(dbPath);
|
|
68958
|
-
if (!
|
|
69137
|
+
if (!existsSync23(dir))
|
|
68959
69138
|
mkdirSync10(dir, { recursive: true });
|
|
68960
69139
|
const db = new Database(dbPath);
|
|
68961
69140
|
db.exec("PRAGMA journal_mode = WAL");
|
|
@@ -69129,24 +69308,24 @@ var init_resource_meta_tools = __esm(() => {
|
|
|
69129
69308
|
});
|
|
69130
69309
|
|
|
69131
69310
|
// src/lib/scheduler.ts
|
|
69132
|
-
import { existsSync as
|
|
69133
|
-
import { join as
|
|
69311
|
+
import { existsSync as existsSync24, readFileSync as readFileSync19, writeFileSync as writeFileSync12, mkdirSync as mkdirSync11 } from "fs";
|
|
69312
|
+
import { join as join24 } from "path";
|
|
69134
69313
|
function getSchedulesPath(targetDir = process.cwd()) {
|
|
69135
|
-
return
|
|
69314
|
+
return join24(targetDir, ".skills", "schedules.json");
|
|
69136
69315
|
}
|
|
69137
69316
|
function loadSchedules(targetDir = process.cwd()) {
|
|
69138
69317
|
const path = getSchedulesPath(targetDir);
|
|
69139
|
-
if (
|
|
69318
|
+
if (existsSync24(path)) {
|
|
69140
69319
|
try {
|
|
69141
|
-
return JSON.parse(
|
|
69320
|
+
return JSON.parse(readFileSync19(path, "utf-8"));
|
|
69142
69321
|
} catch {}
|
|
69143
69322
|
}
|
|
69144
69323
|
return { version: 1, schedules: [] };
|
|
69145
69324
|
}
|
|
69146
69325
|
function saveSchedules(data, targetDir = process.cwd()) {
|
|
69147
69326
|
const path = getSchedulesPath(targetDir);
|
|
69148
|
-
const dir =
|
|
69149
|
-
if (!
|
|
69327
|
+
const dir = join24(targetDir, ".skills");
|
|
69328
|
+
if (!existsSync24(dir))
|
|
69150
69329
|
mkdirSync11(dir, { recursive: true });
|
|
69151
69330
|
writeFileSync12(path, JSON.stringify(data, null, 2));
|
|
69152
69331
|
}
|
|
@@ -69446,14 +69625,14 @@ var init_schedule_tools = __esm(() => {
|
|
|
69446
69625
|
// src/lib/native-storage.ts
|
|
69447
69626
|
import { createHash as createHash3, createHmac as createHmac2 } from "crypto";
|
|
69448
69627
|
import {
|
|
69449
|
-
existsSync as
|
|
69628
|
+
existsSync as existsSync25,
|
|
69450
69629
|
mkdirSync as mkdirSync12,
|
|
69451
|
-
readFileSync as
|
|
69452
|
-
readdirSync as
|
|
69453
|
-
statSync as
|
|
69630
|
+
readFileSync as readFileSync20,
|
|
69631
|
+
readdirSync as readdirSync14,
|
|
69632
|
+
statSync as statSync14,
|
|
69454
69633
|
writeFileSync as writeFileSync13
|
|
69455
69634
|
} from "fs";
|
|
69456
|
-
import { dirname as dirname8, join as
|
|
69635
|
+
import { dirname as dirname8, join as join25, normalize as normalize3, relative as relative3, sep as sep2 } from "path";
|
|
69457
69636
|
function resolveSkillsNativeStorageConfig(env3 = process.env) {
|
|
69458
69637
|
assertNoRetiredModeEnvVars(env3, {
|
|
69459
69638
|
app: SKILLS_ENV_NAMESPACE,
|
|
@@ -69494,7 +69673,7 @@ function getSkillsNativeStorageStatus(options = {}) {
|
|
|
69494
69673
|
local: {
|
|
69495
69674
|
dataDir: getDataDir(),
|
|
69496
69675
|
projectStateDir: getProjectStateDir(targetDir),
|
|
69497
|
-
feedbackDbPath:
|
|
69676
|
+
feedbackDbPath: join25(getDataDir(), "skills.db")
|
|
69498
69677
|
},
|
|
69499
69678
|
remote: {
|
|
69500
69679
|
databaseConfigured: Boolean(config2.databaseUrl),
|
|
@@ -69514,9 +69693,9 @@ function getStorageStatus(options = {}) {
|
|
|
69514
69693
|
function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
|
|
69515
69694
|
const projectStateDir = getProjectStateDir(targetDir);
|
|
69516
69695
|
const files = [];
|
|
69517
|
-
if (
|
|
69696
|
+
if (existsSync25(projectStateDir)) {
|
|
69518
69697
|
for (const filePath of walkFiles2(projectStateDir)) {
|
|
69519
|
-
const bytes =
|
|
69698
|
+
const bytes = readFileSync20(filePath);
|
|
69520
69699
|
const relativePath = toPosix(relative3(targetDir, filePath));
|
|
69521
69700
|
files.push({
|
|
69522
69701
|
path: relativePath,
|
|
@@ -69574,9 +69753,9 @@ function parsePositiveInteger(value) {
|
|
|
69574
69753
|
}
|
|
69575
69754
|
function walkFiles2(dir) {
|
|
69576
69755
|
const files = [];
|
|
69577
|
-
for (const entry of
|
|
69578
|
-
const full =
|
|
69579
|
-
const stats =
|
|
69756
|
+
for (const entry of readdirSync14(dir)) {
|
|
69757
|
+
const full = join25(dir, entry);
|
|
69758
|
+
const stats = statSync14(full);
|
|
69580
69759
|
if (stats.isDirectory())
|
|
69581
69760
|
files.push(...walkFiles2(full));
|
|
69582
69761
|
else
|
|
@@ -70086,6 +70265,7 @@ var init_http = __esm(() => {
|
|
|
70086
70265
|
// src/mcp/index.ts
|
|
70087
70266
|
var exports_mcp = {};
|
|
70088
70267
|
__export(exports_mcp, {
|
|
70268
|
+
startMcpStdio: () => startMcpStdio,
|
|
70089
70269
|
buildServer: () => buildServer
|
|
70090
70270
|
});
|
|
70091
70271
|
function printHelp() {
|
|
@@ -70099,6 +70279,10 @@ Options:
|
|
|
70099
70279
|
--http run Streamable HTTP transport on 127.0.0.1 (default port 8836)
|
|
70100
70280
|
--port <n> HTTP port (--http or MCP_HTTP=1)`);
|
|
70101
70281
|
}
|
|
70282
|
+
async function startMcpStdio() {
|
|
70283
|
+
const server2 = buildServer();
|
|
70284
|
+
await server2.connect(new StdioServerTransport);
|
|
70285
|
+
}
|
|
70102
70286
|
var args;
|
|
70103
70287
|
var init_mcp2 = __esm(() => {
|
|
70104
70288
|
init_stdio2();
|
|
@@ -70119,9 +70303,9 @@ var init_mcp2 = __esm(() => {
|
|
|
70119
70303
|
});
|
|
70120
70304
|
|
|
70121
70305
|
// src/cli/commands/runtime-mcp.ts
|
|
70122
|
-
import { existsSync as
|
|
70306
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync13, readFileSync as readFileSync21, writeFileSync as writeFileSync14 } from "fs";
|
|
70123
70307
|
import { homedir as homedir8 } from "os";
|
|
70124
|
-
import { dirname as dirname9, join as
|
|
70308
|
+
import { dirname as dirname9, join as join26 } from "path";
|
|
70125
70309
|
async function handleMcp(options) {
|
|
70126
70310
|
if (options.register) {
|
|
70127
70311
|
let agents;
|
|
@@ -70154,7 +70338,8 @@ async function handleMcp(options) {
|
|
|
70154
70338
|
process.exitCode = 1;
|
|
70155
70339
|
return;
|
|
70156
70340
|
}
|
|
70157
|
-
await Promise.resolve().then(() => (init_mcp2(), exports_mcp));
|
|
70341
|
+
const { startMcpStdio: startMcpStdio2 } = await Promise.resolve().then(() => (init_mcp2(), exports_mcp));
|
|
70342
|
+
await startMcpStdio2();
|
|
70158
70343
|
}
|
|
70159
70344
|
async function registerMcpForAgent(agent, command) {
|
|
70160
70345
|
switch (agent) {
|
|
@@ -70163,24 +70348,24 @@ async function registerMcpForAgent(agent, command) {
|
|
|
70163
70348
|
case "codex":
|
|
70164
70349
|
return registerCodexMcp(command);
|
|
70165
70350
|
case "gemini":
|
|
70166
|
-
return registerJsonMcpServer(agent,
|
|
70351
|
+
return registerJsonMcpServer(agent, join26(homedir8(), ".gemini", "settings.json"), "mcpServers", {
|
|
70167
70352
|
command,
|
|
70168
70353
|
args: []
|
|
70169
70354
|
});
|
|
70170
70355
|
case "pi":
|
|
70171
|
-
return registerJsonMcpServer(agent,
|
|
70356
|
+
return registerJsonMcpServer(agent, join26(homedir8(), ".pi", "agent", "mcp.json"), "mcpServers", {
|
|
70172
70357
|
command,
|
|
70173
70358
|
args: []
|
|
70174
70359
|
});
|
|
70175
70360
|
case "opencode":
|
|
70176
70361
|
return registerOpenCodeMcp(command);
|
|
70177
70362
|
case "cursor":
|
|
70178
|
-
return registerJsonMcpServer(agent,
|
|
70363
|
+
return registerJsonMcpServer(agent, join26(homedir8(), ".cursor", "mcp.json"), "mcpServers", {
|
|
70179
70364
|
command,
|
|
70180
70365
|
args: []
|
|
70181
70366
|
});
|
|
70182
70367
|
case "windsurf":
|
|
70183
|
-
return registerJsonMcpServer(agent,
|
|
70368
|
+
return registerJsonMcpServer(agent, join26(homedir8(), ".windsurf", "mcp.json"), "mcpServers", {
|
|
70184
70369
|
command,
|
|
70185
70370
|
args: []
|
|
70186
70371
|
});
|
|
@@ -70203,7 +70388,7 @@ async function registerClaudeMcp(command) {
|
|
|
70203
70388
|
if (exitCode === 0) {
|
|
70204
70389
|
return { agent: "claude", success: true, command: cliCommand };
|
|
70205
70390
|
}
|
|
70206
|
-
const fallback = registerJsonMcpServer("claude",
|
|
70391
|
+
const fallback = registerJsonMcpServer("claude", join26(homedir8(), ".claude", ".mcp.json"), "mcpServers", {
|
|
70207
70392
|
command,
|
|
70208
70393
|
args: []
|
|
70209
70394
|
});
|
|
@@ -70213,7 +70398,7 @@ async function registerClaudeMcp(command) {
|
|
|
70213
70398
|
error: fallback.success ? undefined : `claude exited with ${exitCode}: ${(stderr || stdout).trim()}`
|
|
70214
70399
|
};
|
|
70215
70400
|
} catch (err) {
|
|
70216
|
-
const fallback = registerJsonMcpServer("claude",
|
|
70401
|
+
const fallback = registerJsonMcpServer("claude", join26(homedir8(), ".claude", ".mcp.json"), "mcpServers", {
|
|
70217
70402
|
command,
|
|
70218
70403
|
args: []
|
|
70219
70404
|
});
|
|
@@ -70225,11 +70410,11 @@ async function registerClaudeMcp(command) {
|
|
|
70225
70410
|
}
|
|
70226
70411
|
}
|
|
70227
70412
|
function registerCodexMcp(command) {
|
|
70228
|
-
const path =
|
|
70413
|
+
const path = join26(homedir8(), ".codex", "config.toml");
|
|
70229
70414
|
const config2 = `[mcp_servers.${MCP_SERVER_NAME}]
|
|
70230
70415
|
command = ${JSON.stringify(command)}`;
|
|
70231
70416
|
try {
|
|
70232
|
-
const current =
|
|
70417
|
+
const current = existsSync26(path) ? readFileSync21(path, "utf-8") : "";
|
|
70233
70418
|
writeTextFile(path, upsertTomlSection(current, `[mcp_servers.${MCP_SERVER_NAME}]`, `command = ${JSON.stringify(command)}`));
|
|
70234
70419
|
return { agent: "codex", success: true, path, config: config2 };
|
|
70235
70420
|
} catch (err) {
|
|
@@ -70237,7 +70422,7 @@ command = ${JSON.stringify(command)}`;
|
|
|
70237
70422
|
}
|
|
70238
70423
|
}
|
|
70239
70424
|
function registerOpenCodeMcp(command) {
|
|
70240
|
-
const path =
|
|
70425
|
+
const path = join26(homedir8(), ".config", "opencode", "opencode.json");
|
|
70241
70426
|
const config2 = JSON.stringify({
|
|
70242
70427
|
$schema: "https://opencode.ai/config.json",
|
|
70243
70428
|
mcp: {
|
|
@@ -70279,9 +70464,9 @@ function registerJsonMcpServer(agent, path, containerKey, server2) {
|
|
|
70279
70464
|
}
|
|
70280
70465
|
}
|
|
70281
70466
|
function readJsonObject2(path) {
|
|
70282
|
-
if (!
|
|
70467
|
+
if (!existsSync26(path))
|
|
70283
70468
|
return {};
|
|
70284
|
-
const raw =
|
|
70469
|
+
const raw = readFileSync21(path, "utf-8").trim();
|
|
70285
70470
|
if (!raw)
|
|
70286
70471
|
return {};
|
|
70287
70472
|
const parsed = JSON.parse(raw);
|
|
@@ -70325,8 +70510,8 @@ function findCommandOnPath(command) {
|
|
|
70325
70510
|
for (const dir of pathValue.split(":")) {
|
|
70326
70511
|
if (!dir)
|
|
70327
70512
|
continue;
|
|
70328
|
-
const candidate =
|
|
70329
|
-
if (
|
|
70513
|
+
const candidate = join26(dir, command);
|
|
70514
|
+
if (existsSync26(candidate))
|
|
70330
70515
|
return candidate;
|
|
70331
70516
|
}
|
|
70332
70517
|
return command;
|
|
@@ -70346,7 +70531,7 @@ __export(exports_runtime, {
|
|
|
70346
70531
|
registerRuntime: () => registerRuntime
|
|
70347
70532
|
});
|
|
70348
70533
|
import { mkdirSync as mkdirSync14, writeFileSync as writeFileSync15 } from "fs";
|
|
70349
|
-
import { dirname as dirname10, join as
|
|
70534
|
+
import { dirname as dirname10, join as join27 } from "path";
|
|
70350
70535
|
import { createInterface } from "readline";
|
|
70351
70536
|
function registerRuntime(parent) {
|
|
70352
70537
|
parent.command("run").argument("<skill>", "Skill name").argument("[args...]", "Arguments to pass to the skill").allowUnknownOption(true).passThroughOptions(true).option("--json", "Output result as JSON", false).option("--wait", "Poll remote runs until a terminal status", false).option("--poll-interval-ms <ms>", "Remote polling interval in milliseconds", "1000").option("--poll-timeout-ms <ms>", "Maximum time to wait for a remote run", "300000").description("Run a skill directly").action(async (name, args2, options) => handleRun(name, args2, options));
|
|
@@ -70357,7 +70542,14 @@ function registerRuntime(parent) {
|
|
|
70357
70542
|
const exportsCommand = parent.command("exports").description("Inspect or open skill run exports");
|
|
70358
70543
|
exportsCommand.command("open").argument("<run-id>", "Run id").option("--json", "Output as JSON", false).description("Open the export directory for a run").action((runId, options) => handleExportsOpen(runId, options));
|
|
70359
70544
|
exportsCommand.command("download").argument("<run-id>", "Remote run id").option("--json", "Output as JSON", false).description("Download remote run artifacts into .skills/exports").action((runId, options) => handleExportsDownload(runId, options));
|
|
70360
|
-
parent.command("mcp").option("--register <agent>", "Register MCP server with agent").option("--json", "Output registration result as JSON", false).description("Start MCP server (stdio) or register with an agent").action(async (options) =>
|
|
70545
|
+
parent.command("mcp").option("--register <agent>", "Register MCP server with agent").option("--json", "Output registration result as JSON", false).allowExcessArguments(true).description("Start MCP server (stdio) or register with an agent").action(async (options, command) => {
|
|
70546
|
+
const stray = command.args[0];
|
|
70547
|
+
if (stray !== undefined) {
|
|
70548
|
+
console.error(source_default.red(`error: unknown argument '${stray}'. 'skills mcp' takes no positional arguments. ` + `Valid forms: 'skills mcp' (start the MCP stdio server), ` + `'skills mcp --register <agent>', 'skills mcp --register all'`));
|
|
70549
|
+
process.exit(1);
|
|
70550
|
+
}
|
|
70551
|
+
await handleMcp(options);
|
|
70552
|
+
});
|
|
70361
70553
|
const setup = parent.command("setup").description("Point this CLI at a Skills API server, or register agent integrations").option("--api-url <url>", "Skills API origin to send remote work to").option("--global", "Save the API origin globally instead of in this project", false).option("--json", "Output setup result as JSON", false).action(async (options) => handleSetup(options));
|
|
70362
70554
|
setup.command("agents").option("--json", "Output registration result as JSON", false).description("Register the Skills MCP server with all supported agents").action(async (options) => handleMcp({ register: "all", json: options.json }));
|
|
70363
70555
|
parent.command("self-update").description("Update @hasna/skills to the latest version").option("--json", "Output result as JSON", false).action(async (options) => {
|
|
@@ -70493,31 +70685,29 @@ async function handleRun(name, args2, options) {
|
|
|
70493
70685
|
return;
|
|
70494
70686
|
}
|
|
70495
70687
|
}
|
|
70496
|
-
const
|
|
70688
|
+
const routing = resolveConfiguredRunRouting(skill);
|
|
70497
70689
|
const runContext = createSkillRun({
|
|
70498
70690
|
skill: skill.name,
|
|
70499
70691
|
args: args2,
|
|
70500
70692
|
prompt,
|
|
70501
|
-
remote:
|
|
70693
|
+
remote: routing.route === "remote"
|
|
70502
70694
|
});
|
|
70503
|
-
if (
|
|
70504
|
-
const
|
|
70505
|
-
|
|
70506
|
-
if (!apiKey) {
|
|
70507
|
-
const error2 = `${skill.name} is a hosted skill. Run: skills auth login`;
|
|
70508
|
-
writeRunLogs(runContext, "", error2 + `
|
|
70695
|
+
if (routing.route === "error") {
|
|
70696
|
+
const error2 = routing.error;
|
|
70697
|
+
writeRunLogs(runContext, "", error2 + `
|
|
70509
70698
|
`);
|
|
70510
|
-
|
|
70511
|
-
|
|
70512
|
-
|
|
70513
|
-
|
|
70514
|
-
|
|
70515
|
-
|
|
70516
|
-
|
|
70517
|
-
|
|
70699
|
+
const run = completeSkillRun(runContext, { status: "failed", error: error2 });
|
|
70700
|
+
if (options.json)
|
|
70701
|
+
console.log(JSON.stringify({ contractVersion: REMOTE_SKILL_RUN_CONTRACT_VERSION, skill: skill.name, args: args2, exitCode: 1, remote: true, error: error2, run }, null, 2));
|
|
70702
|
+
else
|
|
70703
|
+
console.error(source_default.red(error2));
|
|
70704
|
+
process.exitCode = 1;
|
|
70705
|
+
return;
|
|
70706
|
+
}
|
|
70707
|
+
if (routing.route === "remote") {
|
|
70518
70708
|
try {
|
|
70519
70709
|
const { RemoteSkillsClient: RemoteSkillsClient2 } = await Promise.resolve().then(() => (init_remote_client(), exports_remote_client));
|
|
70520
|
-
const client = new RemoteSkillsClient2(apiKey);
|
|
70710
|
+
const client = new RemoteSkillsClient2(routing.apiKey);
|
|
70521
70711
|
const run = await client.submitRun(skill.name, {}, args2);
|
|
70522
70712
|
if (run.error) {
|
|
70523
70713
|
writeRunLogs(runContext, "", String(run.error) + `
|
|
@@ -70830,7 +71020,7 @@ async function handleExportsDownload(runId, options) {
|
|
|
70830
71020
|
if (!response.ok)
|
|
70831
71021
|
throw new Error(`download failed for artifact ${artifactId}: ${response.status}`);
|
|
70832
71022
|
const relativePath = safeArtifactRelativePath(typeof artifact.relativePath === "string" ? artifact.relativePath : artifact.fileName, String(artifact.fileName || artifactId));
|
|
70833
|
-
const outputPath =
|
|
71023
|
+
const outputPath = join27(exportDir, relativePath);
|
|
70834
71024
|
mkdirSync14(dirname10(outputPath), { recursive: true });
|
|
70835
71025
|
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
70836
71026
|
writeFileSync15(outputPath, bytes);
|
|
@@ -71049,6 +71239,7 @@ var init_runtime = __esm(() => {
|
|
|
71049
71239
|
init_runs();
|
|
71050
71240
|
init_run_state();
|
|
71051
71241
|
init_runtime_mcp();
|
|
71242
|
+
init_run_routing();
|
|
71052
71243
|
});
|
|
71053
71244
|
|
|
71054
71245
|
// src/cli/commands/completion.ts
|
|
@@ -71195,8 +71386,8 @@ var exports_create_sync_config = {};
|
|
|
71195
71386
|
__export(exports_create_sync_config, {
|
|
71196
71387
|
registerCreateSync: () => registerCreateSync
|
|
71197
71388
|
});
|
|
71198
|
-
import { existsSync as
|
|
71199
|
-
import { join as
|
|
71389
|
+
import { existsSync as existsSync27, writeFileSync as writeFileSync16, mkdirSync as mkdirSync15 } from "fs";
|
|
71390
|
+
import { join as join28 } from "path";
|
|
71200
71391
|
function registerCreateSync(parent) {
|
|
71201
71392
|
const configCmd = parent.command("config").description("Manage skills configuration");
|
|
71202
71393
|
configCmd.command("show", { isDefault: true }).option("--json", "Output as JSON", false).description("Show current merged configuration").action((options) => {
|
|
@@ -71262,13 +71453,13 @@ function registerCreateSync(parent) {
|
|
|
71262
71453
|
const pp = getConfigPath("project");
|
|
71263
71454
|
if (options.json) {
|
|
71264
71455
|
console.log(JSON.stringify({
|
|
71265
|
-
global: { path: gp, exists:
|
|
71266
|
-
project: { path: pp, exists:
|
|
71456
|
+
global: { path: gp, exists: existsSync27(gp) },
|
|
71457
|
+
project: { path: pp, exists: existsSync27(pp) }
|
|
71267
71458
|
}, null, 2));
|
|
71268
71459
|
return;
|
|
71269
71460
|
}
|
|
71270
|
-
console.log(`${source_default.cyan("global")}: ${gp}${
|
|
71271
|
-
console.log(`${source_default.cyan("project")}: ${pp}${
|
|
71461
|
+
console.log(`${source_default.cyan("global")}: ${gp}${existsSync27(gp) ? source_default.green(" (exists)") : source_default.dim(" (not found)")}`);
|
|
71462
|
+
console.log(`${source_default.cyan("project")}: ${pp}${existsSync27(pp) ? source_default.green(" (exists)") : source_default.dim(" (not found)")}`);
|
|
71272
71463
|
});
|
|
71273
71464
|
parent.command("create").argument("<name>", "Skill name (e.g. my-tool)").option("--category <category>", "Skill category", "Development Tools").option("--description <description>", "Short description of what the skill does").option("--tags <tags>", "Comma-separated tags (e.g. api,testing,automation)").option("--global", "Deprecated; custom skills are always global", false).option("--json", "Output result as JSON", false).description("Scaffold a new custom skill directory").action((name, options) => handleCreate(name, options));
|
|
71274
71465
|
parent.command("sync").alias("render").argument("[names...]", "Skills to sync (default: every skill in this machine's corpus)").option("--for <agent>", `Target one agent (${SYNC_AGENTS.join(", ")}, or all)`, "all").option("--all", "Sync every corpus skill (the default)", false).option("--source <path>", "Canonical corpus source: a directory of skill folders, or a package root with skills/ (overrides $SKILLS_SOURCE)").option("--dry-run", "Show what would be written without touching any agent folder", false).option("--force", "Adopt an unmanaged skill that already has SKILL.md; other unmarked directories are never overwritten", false).option("--check", "Home drift census (missing-from-home / stray-in-home / diverged); exits non-zero on drift, writes nothing", false).option("--adopt", "Unmarked-home adoption mode: hash unmarked home skills against the corpus; exact matches are marked (dry-run by default)", false).option("--prune", "Prune mode: list (or with --apply, remove) marked home skill dirs that have no canonical corpus entry", false).option("--apply", "Write adoption markers / conflicts ledger, or perform prune removals", false).option("--json", "Output as JSON", false).description("Write corpus skills into each coding agent's global skills folder, per-tool adapted").action((names, options) => handleSync(names, options));
|
|
@@ -71277,8 +71468,8 @@ function handleCreate(name, options) {
|
|
|
71277
71468
|
const bare = name.trim();
|
|
71278
71469
|
const dirName = bare;
|
|
71279
71470
|
const baseDir = getPortableSkillsRoot();
|
|
71280
|
-
const skillDir =
|
|
71281
|
-
if (
|
|
71471
|
+
const skillDir = join28(baseDir, dirName);
|
|
71472
|
+
if (existsSync27(skillDir)) {
|
|
71282
71473
|
console.log(options.json ? JSON.stringify({ error: `Skill '${bare}' already exists at ${skillDir}` }) : source_default.red(`Skill '${bare}' already exists at ${skillDir}`));
|
|
71283
71474
|
process.exitCode = 1;
|
|
71284
71475
|
return;
|
|
@@ -71286,8 +71477,8 @@ function handleCreate(name, options) {
|
|
|
71286
71477
|
const description = options.description || `${bare} skill`;
|
|
71287
71478
|
const tags = options.tags ? options.tags.split(",").map((t) => t.trim()).filter(Boolean) : [bare];
|
|
71288
71479
|
const displayName2 = bare.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
71289
|
-
mkdirSync15(
|
|
71290
|
-
writeFileSync16(
|
|
71480
|
+
mkdirSync15(join28(skillDir, "src"), { recursive: true });
|
|
71481
|
+
writeFileSync16(join28(skillDir, "SKILL.md"), [
|
|
71291
71482
|
"---",
|
|
71292
71483
|
`name: ${bare}`,
|
|
71293
71484
|
`description: ${description}`,
|
|
@@ -71307,11 +71498,11 @@ function handleCreate(name, options) {
|
|
|
71307
71498
|
""
|
|
71308
71499
|
].join(`
|
|
71309
71500
|
`));
|
|
71310
|
-
writeFileSync16(
|
|
71501
|
+
writeFileSync16(join28(skillDir, "src", "index.ts"), [`#!/usr/bin/env bun`, `/**`, ` * ${displayName2} \u2014 ${description}`, ` */`, "", `console.log("${displayName2}");`, ""].join(`
|
|
71311
71502
|
`));
|
|
71312
|
-
writeFileSync16(
|
|
71503
|
+
writeFileSync16(join28(skillDir, "package.json"), JSON.stringify({ name: bare, version: "0.1.0", description, bin: { [bare]: "./src/index.ts" }, scripts: { dev: `bun src/index.ts` }, dependencies: {} }, null, 2) + `
|
|
71313
71504
|
`);
|
|
71314
|
-
writeFileSync16(
|
|
71505
|
+
writeFileSync16(join28(skillDir, "tsconfig.json"), JSON.stringify({ compilerOptions: { target: "ES2022", module: "ESNext", moduleResolution: "bundler", strict: true, outDir: "dist" }, include: ["src/**/*.ts"] }, null, 2) + `
|
|
71315
71506
|
`);
|
|
71316
71507
|
clearRegistryCache();
|
|
71317
71508
|
if (options.json)
|
|
@@ -71320,8 +71511,8 @@ function handleCreate(name, options) {
|
|
|
71320
71511
|
console.log(source_default.green(`\u2713 Created custom skill '${bare}' at ${skillDir}`));
|
|
71321
71512
|
console.log(source_default.dim(` Category: ${options.category}`));
|
|
71322
71513
|
console.log(source_default.dim(` Tags: ${tags.join(", ")}`));
|
|
71323
|
-
console.log(` ${source_default.cyan("Edit:")} ${
|
|
71324
|
-
console.log(` ${source_default.cyan("Run:")} bun ${
|
|
71514
|
+
console.log(` ${source_default.cyan("Edit:")} ${join28(skillDir, "src", "index.ts")}`);
|
|
71515
|
+
console.log(` ${source_default.cyan("Run:")} bun ${join28(skillDir, "src", "index.ts")}`);
|
|
71325
71516
|
}
|
|
71326
71517
|
}
|
|
71327
71518
|
function handleSync(names, options) {
|
|
@@ -71783,6 +71974,14 @@ async function executeScheduledSkill(skillName, args2, options) {
|
|
|
71783
71974
|
const skill = getSkill2(skillName);
|
|
71784
71975
|
if (!skill)
|
|
71785
71976
|
throw new Error(`Skill '${skillName}' not found`);
|
|
71977
|
+
const { resolveConfiguredRunRouting: resolveConfiguredRunRouting2 } = await Promise.resolve().then(() => (init_run_routing(), exports_run_routing));
|
|
71978
|
+
const routing = resolveConfiguredRunRouting2(skill);
|
|
71979
|
+
if (routing.route === "error") {
|
|
71980
|
+
throw new Error(`${routing.code}: ${routing.error}`);
|
|
71981
|
+
}
|
|
71982
|
+
if (routing.route === "remote") {
|
|
71983
|
+
throw new Error(`${skill.name} is a server-owned skill. Scheduled hosted runs are not supported yet \u2014 ` + `run it with: skills run ${skill.name}`);
|
|
71984
|
+
}
|
|
71786
71985
|
const { runSkill: runSkill2 } = await Promise.resolve().then(() => (init_skillinfo(), exports_skillinfo));
|
|
71787
71986
|
const result2 = await runSkill2(skill.name, args2);
|
|
71788
71987
|
if (result2.exitCode !== 0) {
|
|
@@ -71920,8 +72119,8 @@ var init_revision = __esm(() => {
|
|
|
71920
72119
|
|
|
71921
72120
|
// src/lib/skill-bundle.ts
|
|
71922
72121
|
import { createHash as createHash5 } from "crypto";
|
|
71923
|
-
import { readFileSync as
|
|
71924
|
-
import { join as
|
|
72122
|
+
import { readFileSync as readFileSync22, readdirSync as readdirSync15, statSync as statSync15 } from "fs";
|
|
72123
|
+
import { join as join29, relative as relative5 } from "path";
|
|
71925
72124
|
function isDotenvFile(lower) {
|
|
71926
72125
|
if (lower === ".env" || lower.startsWith(".env."))
|
|
71927
72126
|
return true;
|
|
@@ -71958,8 +72157,8 @@ function collectSkillBundleEntries(dir) {
|
|
|
71958
72157
|
return entries.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
71959
72158
|
}
|
|
71960
72159
|
function walk(root, current, out) {
|
|
71961
|
-
for (const entry of
|
|
71962
|
-
const absolute =
|
|
72160
|
+
for (const entry of readdirSync15(current, { withFileTypes: true })) {
|
|
72161
|
+
const absolute = join29(current, entry.name);
|
|
71963
72162
|
const rel = relative5(root, absolute).split("\\").join("/");
|
|
71964
72163
|
const isRootLevel = !rel.includes("/");
|
|
71965
72164
|
if (ANY_SEGMENT_EXCLUDES.has(entry.name.toLowerCase()))
|
|
@@ -71980,10 +72179,10 @@ function walk(root, current, out) {
|
|
|
71980
72179
|
continue;
|
|
71981
72180
|
if (isCredentialFile(entry.name))
|
|
71982
72181
|
continue;
|
|
71983
|
-
const stats =
|
|
72182
|
+
const stats = statSync15(absolute);
|
|
71984
72183
|
out.push({
|
|
71985
72184
|
path: rel,
|
|
71986
|
-
bytes: ownBytes(
|
|
72185
|
+
bytes: ownBytes(readFileSync22(absolute)),
|
|
71987
72186
|
mode: stats.mode & 64 ? 493 : 420
|
|
71988
72187
|
});
|
|
71989
72188
|
}
|
|
@@ -72269,8 +72468,8 @@ var init_skill_bundles = __esm(() => {
|
|
|
72269
72468
|
});
|
|
72270
72469
|
|
|
72271
72470
|
// src/lib/pull.ts
|
|
72272
|
-
import { existsSync as
|
|
72273
|
-
import { dirname as dirname12, join as
|
|
72471
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync17, mkdtempSync as mkdtempSync3, readFileSync as readFileSync23, renameSync as renameSync4, rmSync as rmSync6, writeFileSync as writeFileSync18 } from "fs";
|
|
72472
|
+
import { dirname as dirname12, join as join30 } from "path";
|
|
72274
72473
|
async function pullSkills(options = {}) {
|
|
72275
72474
|
const client = options.client !== undefined ? options.client : createRemoteSkillsClient();
|
|
72276
72475
|
if (!client) {
|
|
@@ -72315,7 +72514,7 @@ async function pullOne(client, rawName, corpusOptions, verify) {
|
|
|
72315
72514
|
return reconcileTombstone(slug, corpusOptions);
|
|
72316
72515
|
}
|
|
72317
72516
|
if (bundleResponse.status === 404) {
|
|
72318
|
-
const marker = readPullMarker(
|
|
72517
|
+
const marker = readPullMarker(join30(getPortableSkillsRoot(corpusOptions), slug));
|
|
72319
72518
|
if (marker && typeof marker.revisionId === "string" && marker.revisionId) {
|
|
72320
72519
|
return { name: slug, success: true, purged: true, removed: false };
|
|
72321
72520
|
}
|
|
@@ -72346,7 +72545,7 @@ async function pullOne(client, rawName, corpusOptions, verify) {
|
|
|
72346
72545
|
return { name: slug, success: false, error: `Skill '${slug}' was not found on the configured Skills instance.` };
|
|
72347
72546
|
}
|
|
72348
72547
|
if (!meta?.revisionId) {
|
|
72349
|
-
const marker = readPullMarker(
|
|
72548
|
+
const marker = readPullMarker(join30(getPortableSkillsRoot(corpusOptions), slug));
|
|
72350
72549
|
if (marker && typeof marker.revisionId === "string" && marker.revisionId) {
|
|
72351
72550
|
return { name: slug, success: true, purged: true, removed: false };
|
|
72352
72551
|
}
|
|
@@ -72360,7 +72559,7 @@ async function pullOne(client, rawName, corpusOptions, verify) {
|
|
|
72360
72559
|
}
|
|
72361
72560
|
throw error2;
|
|
72362
72561
|
}
|
|
72363
|
-
const written =
|
|
72562
|
+
const written = installCorpusSkillAtomically({ name: slug, skillMd, meta }, corpusOptions);
|
|
72364
72563
|
writePullMarker(written.path, {
|
|
72365
72564
|
skill: slug,
|
|
72366
72565
|
version: written.manifest.version,
|
|
@@ -72403,8 +72602,8 @@ function provenRevision(meta, slug, bundle) {
|
|
|
72403
72602
|
return declared;
|
|
72404
72603
|
}
|
|
72405
72604
|
function reconcileTombstone(slug, corpusOptions) {
|
|
72406
|
-
const target =
|
|
72407
|
-
if (!
|
|
72605
|
+
const target = join30(getPortableSkillsRoot(corpusOptions), slug);
|
|
72606
|
+
if (!existsSync28(join30(target, PULL_MARKER_FILE))) {
|
|
72408
72607
|
return { name: slug, success: true, tombstoned: true, removed: false, leftInPlace: true };
|
|
72409
72608
|
}
|
|
72410
72609
|
rmSync6(target, { recursive: true, force: true });
|
|
@@ -72412,7 +72611,7 @@ function reconcileTombstone(slug, corpusOptions) {
|
|
|
72412
72611
|
}
|
|
72413
72612
|
function readPullMarker(dir) {
|
|
72414
72613
|
try {
|
|
72415
|
-
return JSON.parse(
|
|
72614
|
+
return JSON.parse(readFileSync23(join30(dir, PULL_MARKER_FILE), "utf-8"));
|
|
72416
72615
|
} catch {
|
|
72417
72616
|
return null;
|
|
72418
72617
|
}
|
|
@@ -72533,14 +72732,14 @@ function verifyBundleResponseBytes(buffer, response, verify = {}) {
|
|
|
72533
72732
|
function installBundleAtomically(name, entries, options = {}, marker = {}) {
|
|
72534
72733
|
const root = getPortableSkillsRoot(options);
|
|
72535
72734
|
mkdirSync17(root, { recursive: true });
|
|
72536
|
-
const target =
|
|
72537
|
-
const created = !
|
|
72538
|
-
const staging =
|
|
72735
|
+
const target = join30(root, name);
|
|
72736
|
+
const created = !existsSync28(target);
|
|
72737
|
+
const staging = mkdtempSync3(join30(root, `.pull-${name}-`));
|
|
72539
72738
|
let moved = false;
|
|
72540
72739
|
let backup = null;
|
|
72541
72740
|
try {
|
|
72542
72741
|
for (const entry of entries) {
|
|
72543
|
-
const destination =
|
|
72742
|
+
const destination = join30(staging, entry.path);
|
|
72544
72743
|
mkdirSync17(dirname12(destination), { recursive: true });
|
|
72545
72744
|
writeFileSync18(destination, entry.bytes, { mode: entry.mode });
|
|
72546
72745
|
}
|
|
@@ -72552,9 +72751,9 @@ function installBundleAtomically(name, entries, options = {}, marker = {}) {
|
|
|
72552
72751
|
...marker.signature ? { signature: marker.signature } : {},
|
|
72553
72752
|
...marker.revisionId ? { revisionId: marker.revisionId } : {}
|
|
72554
72753
|
});
|
|
72555
|
-
if (
|
|
72556
|
-
backup =
|
|
72557
|
-
renameSync4(target,
|
|
72754
|
+
if (existsSync28(target)) {
|
|
72755
|
+
backup = mkdtempSync3(join30(root, `.pull-backup-${name}-`));
|
|
72756
|
+
renameSync4(target, join30(backup, name));
|
|
72558
72757
|
moved = true;
|
|
72559
72758
|
}
|
|
72560
72759
|
renameSync4(staging, target);
|
|
@@ -72562,9 +72761,9 @@ function installBundleAtomically(name, entries, options = {}, marker = {}) {
|
|
|
72562
72761
|
rmSync6(backup, { recursive: true, force: true });
|
|
72563
72762
|
} catch (error2) {
|
|
72564
72763
|
rmSync6(staging, { recursive: true, force: true });
|
|
72565
|
-
if (moved && backup &&
|
|
72764
|
+
if (moved && backup && existsSync28(join30(backup, name))) {
|
|
72566
72765
|
try {
|
|
72567
|
-
renameSync4(
|
|
72766
|
+
renameSync4(join30(backup, name), target);
|
|
72568
72767
|
} catch {}
|
|
72569
72768
|
}
|
|
72570
72769
|
throw error2;
|
|
@@ -72583,7 +72782,7 @@ function writePullMarker(dir, record3) {
|
|
|
72583
72782
|
...record3.revisionId ? { revisionId: record3.revisionId } : {},
|
|
72584
72783
|
syncedAt: new Date().toISOString()
|
|
72585
72784
|
};
|
|
72586
|
-
writeFileSync18(
|
|
72785
|
+
writeFileSync18(join30(dir, PULL_MARKER_FILE), `${JSON.stringify(marker, null, 2)}
|
|
72587
72786
|
`);
|
|
72588
72787
|
}
|
|
72589
72788
|
async function safeMeta(client, slug) {
|
|
@@ -72754,8 +72953,8 @@ __export(exports_publish, {
|
|
|
72754
72953
|
pushSkill: () => pushSkill,
|
|
72755
72954
|
PushSkillError: () => PushSkillError
|
|
72756
72955
|
});
|
|
72757
|
-
import { existsSync as
|
|
72758
|
-
import { join as
|
|
72956
|
+
import { existsSync as existsSync29, readFileSync as readFileSync24 } from "fs";
|
|
72957
|
+
import { join as join31 } from "path";
|
|
72759
72958
|
function registerPublish(parent) {
|
|
72760
72959
|
parent.command("push").argument("<name>", "Name of a skill in the local corpus (~/.hasna/skills/installed or the migrated ~/.hasna/skills/skills)").option("--version <version>", "Override the version recorded on the instance").option("--dry-run", "Pack and validate without uploading", false).option("--json", "Output result as JSON", false).description("Publish a local skill to the configured skills instance").action(async (name, options) => {
|
|
72761
72960
|
try {
|
|
@@ -72796,8 +72995,8 @@ async function pushSkill(name, options = {}) {
|
|
|
72796
72995
|
}
|
|
72797
72996
|
const manifest = readPortableSkillManifest(skill.path, skill.name);
|
|
72798
72997
|
const packed = packSkillBundle(skill.path, { maxUnpackedBytes: MAX_UNPACKED_BYTES });
|
|
72799
|
-
const skillMdPath =
|
|
72800
|
-
const skillMd =
|
|
72998
|
+
const skillMdPath = join31(skill.path, "SKILL.md");
|
|
72999
|
+
const skillMd = existsSync29(skillMdPath) ? readFileSync24(skillMdPath, "utf-8") : undefined;
|
|
72801
73000
|
const base2 = {
|
|
72802
73001
|
slug: skill.name,
|
|
72803
73002
|
path: skill.path,
|
|
@@ -72823,7 +73022,7 @@ async function pushSkill(name, options = {}) {
|
|
|
72823
73022
|
description: manifest.description,
|
|
72824
73023
|
category: manifest.category ?? "Development Tools",
|
|
72825
73024
|
tags: manifest.tags ?? [],
|
|
72826
|
-
kind: manifest.kind ?? "
|
|
73025
|
+
kind: manifest.kind ?? "instruction",
|
|
72827
73026
|
version: options.version ?? manifest.version,
|
|
72828
73027
|
source: "custom",
|
|
72829
73028
|
bundleSha256: packed.sha256,
|
|
@@ -73568,11 +73767,11 @@ var init_storage = __esm(() => {
|
|
|
73568
73767
|
});
|
|
73569
73768
|
|
|
73570
73769
|
// src/lib/registry-reconcile.ts
|
|
73571
|
-
import { existsSync as
|
|
73572
|
-
import { join as
|
|
73770
|
+
import { existsSync as existsSync30, readFileSync as readFileSync25, statSync as statSync16, writeFileSync as writeFileSync19 } from "fs";
|
|
73771
|
+
import { join as join32 } from "path";
|
|
73573
73772
|
function isDirectory2(path) {
|
|
73574
73773
|
try {
|
|
73575
|
-
return
|
|
73774
|
+
return statSync16(path).isDirectory();
|
|
73576
73775
|
} catch {
|
|
73577
73776
|
return false;
|
|
73578
73777
|
}
|
|
@@ -73580,15 +73779,15 @@ function isDirectory2(path) {
|
|
|
73580
73779
|
function migrationNeeded(options) {
|
|
73581
73780
|
if (options.rootDir)
|
|
73582
73781
|
return false;
|
|
73583
|
-
const appDir = options.homeDir ?
|
|
73584
|
-
return !(isOwnerLayoutMigrated(appDir) && isDirectory2(
|
|
73782
|
+
const appDir = options.homeDir ? join32(options.homeDir, ".hasna", "skills") : getDataDir();
|
|
73783
|
+
return !(isOwnerLayoutMigrated(appDir) && isDirectory2(join32(appDir, SKILLS_CACHE_DIRNAME)));
|
|
73585
73784
|
}
|
|
73586
73785
|
function readBaseline(skillDir) {
|
|
73587
|
-
const markerPath =
|
|
73588
|
-
if (!
|
|
73786
|
+
const markerPath = join32(skillDir, PULL_MARKER_FILE);
|
|
73787
|
+
if (!existsSync30(markerPath))
|
|
73589
73788
|
return;
|
|
73590
73789
|
try {
|
|
73591
|
-
const marker = JSON.parse(
|
|
73790
|
+
const marker = JSON.parse(readFileSync25(markerPath, "utf-8"));
|
|
73592
73791
|
return {
|
|
73593
73792
|
...typeof marker.contentHash === "string" && marker.contentHash ? { contentHash: marker.contentHash } : {},
|
|
73594
73793
|
...typeof marker.version === "string" && marker.version ? { version: marker.version } : {}
|
|
@@ -73598,11 +73797,11 @@ function readBaseline(skillDir) {
|
|
|
73598
73797
|
}
|
|
73599
73798
|
}
|
|
73600
73799
|
function readCursor(root) {
|
|
73601
|
-
const path =
|
|
73602
|
-
if (!
|
|
73800
|
+
const path = join32(root, SYNC_CURSOR_FILE);
|
|
73801
|
+
if (!existsSync30(path))
|
|
73603
73802
|
return { runCount: 0 };
|
|
73604
73803
|
try {
|
|
73605
|
-
const cursor = JSON.parse(
|
|
73804
|
+
const cursor = JSON.parse(readFileSync25(path, "utf-8"));
|
|
73606
73805
|
return { runCount: typeof cursor.runCount === "number" ? cursor.runCount : 0 };
|
|
73607
73806
|
} catch {
|
|
73608
73807
|
return { runCount: 0 };
|
|
@@ -73611,12 +73810,12 @@ function readCursor(root) {
|
|
|
73611
73810
|
function resolveCorpusRootReadOnly(options) {
|
|
73612
73811
|
if (options.rootDir)
|
|
73613
73812
|
return { root: options.rootDir, migrationPending: false };
|
|
73614
|
-
const appDir = options.homeDir ?
|
|
73615
|
-
const cache3 =
|
|
73813
|
+
const appDir = options.homeDir ? join32(options.homeDir, ".hasna", "skills") : getDataDirReadOnly();
|
|
73814
|
+
const cache3 = join32(appDir, SKILLS_CACHE_DIRNAME);
|
|
73616
73815
|
if (isOwnerLayoutMigrated(appDir) && isDirectory2(cache3)) {
|
|
73617
73816
|
return { root: cache3, migrationPending: false };
|
|
73618
73817
|
}
|
|
73619
|
-
return { root:
|
|
73818
|
+
return { root: join32(appDir, INSTALLED_SKILLS_DIRNAME), migrationPending: true };
|
|
73620
73819
|
}
|
|
73621
73820
|
function remoteRowToSkill(record3) {
|
|
73622
73821
|
const slug = typeof record3.slug === "string" ? record3.slug : typeof record3.name === "string" ? record3.name : undefined;
|
|
@@ -73630,7 +73829,7 @@ function remoteRowToSkill(record3) {
|
|
|
73630
73829
|
}
|
|
73631
73830
|
function recheckLocalSide(plannedLocal, localDir, ops = {
|
|
73632
73831
|
pack: (dir) => packSkillBundle(dir).sha256,
|
|
73633
|
-
exists:
|
|
73832
|
+
exists: existsSync30
|
|
73634
73833
|
}) {
|
|
73635
73834
|
let localNow;
|
|
73636
73835
|
try {
|
|
@@ -73748,7 +73947,7 @@ async function reconcileRegistry(options = {}) {
|
|
|
73748
73947
|
for (const slug of allSlugs) {
|
|
73749
73948
|
const local = locals.get(slug);
|
|
73750
73949
|
const remote = remotes.get(slug);
|
|
73751
|
-
const baseline = local ? readBaseline(
|
|
73950
|
+
const baseline = local ? readBaseline(join32(root, slug)) : undefined;
|
|
73752
73951
|
const { state, reason } = classifySkill(local, remote, baseline);
|
|
73753
73952
|
let { action, reason: actionReason } = resolveAction(state, direction, conflict);
|
|
73754
73953
|
if (state === "remote-only" && isDigestless(remote)) {
|
|
@@ -73807,7 +74006,7 @@ async function reconcileRegistry(options = {}) {
|
|
|
73807
74006
|
try {
|
|
73808
74007
|
await pushSkill(slug, { rootDir: root, client });
|
|
73809
74008
|
const pushed = locals.get(slug);
|
|
73810
|
-
writePullMarker(
|
|
74009
|
+
writePullMarker(join32(root, slug), {
|
|
73811
74010
|
skill: slug,
|
|
73812
74011
|
...pushed?.version ? { version: pushed.version } : {},
|
|
73813
74012
|
...pushed?.sha256 ? { contentHash: pushed.sha256 } : {},
|
|
@@ -73879,7 +74078,7 @@ async function reconcileRegistry(options = {}) {
|
|
|
73879
74078
|
runCount: readCursor(root).runCount + 1,
|
|
73880
74079
|
summary
|
|
73881
74080
|
};
|
|
73882
|
-
writeFileSync19(
|
|
74081
|
+
writeFileSync19(join32(root, SYNC_CURSOR_FILE), `${JSON.stringify(cursor, null, 2)}
|
|
73883
74082
|
`);
|
|
73884
74083
|
return {
|
|
73885
74084
|
corpusRoot: root,
|