@hasna/skills 0.1.64 → 0.1.66
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 +594 -509
- package/bin/mcp.js +277 -237
- package/bin/server.js +789 -232
- package/bin/worker.js +178 -148
- package/dist/index.d.ts +1 -1
- package/dist/index.js +419 -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/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 +1 -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.66",
|
|
36864
36864
|
description: "Skills library for AI coding agents",
|
|
36865
36865
|
type: "module",
|
|
36866
36866
|
bin: {
|
|
@@ -38888,6 +38888,8 @@ var init_registry_data = __esm(() => {
|
|
|
38888
38888
|
});
|
|
38889
38889
|
|
|
38890
38890
|
// src/lib/hosted-skill-set.ts
|
|
38891
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
38892
|
+
import { join as join4 } from "path";
|
|
38891
38893
|
function normalizeMarker(value) {
|
|
38892
38894
|
return typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
38893
38895
|
}
|
|
@@ -38897,6 +38899,16 @@ function isHostedMetadataPackage(pkg) {
|
|
|
38897
38899
|
return false;
|
|
38898
38900
|
return HOSTED_RUNTIMES.has(normalizeMarker(skills.runtime)) || HOSTED_SOURCES.has(normalizeMarker(skills.source));
|
|
38899
38901
|
}
|
|
38902
|
+
function isHostedMetadataSkillDir(skillDir) {
|
|
38903
|
+
const pkgPath = join4(skillDir, "package.json");
|
|
38904
|
+
if (!existsSync4(pkgPath))
|
|
38905
|
+
return false;
|
|
38906
|
+
try {
|
|
38907
|
+
return isHostedMetadataPackage(JSON.parse(readFileSync3(pkgPath, "utf8")));
|
|
38908
|
+
} catch {
|
|
38909
|
+
return false;
|
|
38910
|
+
}
|
|
38911
|
+
}
|
|
38900
38912
|
var HOSTED_RUNTIMES, HOSTED_SOURCES, HOSTED_METADATA_SET_EMPTY_ERROR, SLUG = "[^,{}/]+", BRACE_SOURCE_EXCLUSION, SINGLE_SOURCE_EXCLUSION;
|
|
38901
38913
|
var init_hosted_skill_set = __esm(() => {
|
|
38902
38914
|
HOSTED_RUNTIMES = new Set(["hosted"]);
|
|
@@ -38917,13 +38929,13 @@ var init_hosted_skill_set = __esm(() => {
|
|
|
38917
38929
|
});
|
|
38918
38930
|
|
|
38919
38931
|
// src/lib/skill-validation.ts
|
|
38920
|
-
import { existsSync as
|
|
38921
|
-
import { isAbsolute, join as
|
|
38932
|
+
import { existsSync as existsSync5, lstatSync, readFileSync as readFileSync4, readdirSync as readdirSync3, statSync as statSync3 } from "fs";
|
|
38933
|
+
import { isAbsolute, join as join5, normalize } from "path";
|
|
38922
38934
|
function add2(target, code, message) {
|
|
38923
38935
|
target.push({ code, message });
|
|
38924
38936
|
}
|
|
38925
38937
|
function readJsonFile(path) {
|
|
38926
|
-
return JSON.parse(
|
|
38938
|
+
return JSON.parse(readFileSync4(path, "utf-8"));
|
|
38927
38939
|
}
|
|
38928
38940
|
function asRecord(value) {
|
|
38929
38941
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
|
|
@@ -39007,7 +39019,7 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
39007
39019
|
binCommands: [],
|
|
39008
39020
|
docFiles: []
|
|
39009
39021
|
};
|
|
39010
|
-
if (!
|
|
39022
|
+
if (!existsSync5(skillPath)) {
|
|
39011
39023
|
add2(issues, "skill.dir_missing", `Skill directory not found: ${skillPath}`);
|
|
39012
39024
|
return {
|
|
39013
39025
|
name: bareName,
|
|
@@ -39021,8 +39033,8 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
39021
39033
|
if (!VALID_BIN_COMMAND.test(bareName)) {
|
|
39022
39034
|
add2(issues, "skill.name_invalid", `Skill name '${bareName}' must use lowercase letters, numbers, dots, underscores, or hyphens`);
|
|
39023
39035
|
}
|
|
39024
|
-
for (const entry of
|
|
39025
|
-
const entryPath =
|
|
39036
|
+
for (const entry of readdirSync3(skillPath).sort()) {
|
|
39037
|
+
const entryPath = join5(skillPath, entry);
|
|
39026
39038
|
if (RESERVED_SKILL_ENTRIES.has(entry)) {
|
|
39027
39039
|
add2(issues, "skill.reserved_file", `Reserved file '${entry}' is not allowed in skill packages`);
|
|
39028
39040
|
}
|
|
@@ -39034,15 +39046,15 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
39034
39046
|
}
|
|
39035
39047
|
}
|
|
39036
39048
|
for (const docFile of DOC_FILES) {
|
|
39037
|
-
if (
|
|
39049
|
+
if (existsSync5(join5(skillPath, docFile)))
|
|
39038
39050
|
metadata.docFiles.push(docFile);
|
|
39039
39051
|
}
|
|
39040
39052
|
if (metadata.docFiles.length === 0) {
|
|
39041
39053
|
add2(issues, "skill.docs_missing", "Missing documentation file: expected SKILL.md, README.md, or CLAUDE.md");
|
|
39042
39054
|
}
|
|
39043
|
-
const skillMdPath =
|
|
39044
|
-
if (
|
|
39045
|
-
const frontmatter = parseSkillFrontmatter(
|
|
39055
|
+
const skillMdPath = join5(skillPath, "SKILL.md");
|
|
39056
|
+
if (existsSync5(skillMdPath)) {
|
|
39057
|
+
const frontmatter = parseSkillFrontmatter(readFileSync4(skillMdPath, "utf-8"));
|
|
39046
39058
|
if (!frontmatter) {
|
|
39047
39059
|
add2(warnings, "skill.frontmatter_missing", "SKILL.md has no YAML frontmatter");
|
|
39048
39060
|
} else {
|
|
@@ -39084,8 +39096,8 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
39084
39096
|
}
|
|
39085
39097
|
metadata.kind = resolvedKind;
|
|
39086
39098
|
const isInstruction = resolvedKind === "instruction";
|
|
39087
|
-
const pkgPath =
|
|
39088
|
-
if (!
|
|
39099
|
+
const pkgPath = join5(skillPath, "package.json");
|
|
39100
|
+
if (!existsSync5(pkgPath)) {
|
|
39089
39101
|
if (!isInstruction)
|
|
39090
39102
|
add2(issues, "package.missing", "Missing package.json");
|
|
39091
39103
|
} else {
|
|
@@ -39143,10 +39155,10 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
39143
39155
|
add2(issues, "package.bin_target_unsafe", `package.json bin '${command}' target '${target}' must stay inside the skill directory`);
|
|
39144
39156
|
continue;
|
|
39145
39157
|
}
|
|
39146
|
-
const targetPath =
|
|
39147
|
-
if (!
|
|
39158
|
+
const targetPath = join5(skillPath, target);
|
|
39159
|
+
if (!existsSync5(targetPath)) {
|
|
39148
39160
|
add2(warnings, "package.bin_target_missing", `package.json bin '${command}' target '${target}' is not present before build`);
|
|
39149
|
-
} else if (
|
|
39161
|
+
} else if (statSync3(targetPath).isDirectory()) {
|
|
39150
39162
|
add2(issues, "package.bin_target_directory", `package.json bin '${command}' target '${target}' must point to a file, not a directory`);
|
|
39151
39163
|
}
|
|
39152
39164
|
}
|
|
@@ -39161,18 +39173,18 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
39161
39173
|
metadata.runtime = "none";
|
|
39162
39174
|
} else {
|
|
39163
39175
|
metadata.runtime = hostedMetadata ? "hosted" : "local";
|
|
39164
|
-
const srcDir =
|
|
39176
|
+
const srcDir = join5(skillPath, "src");
|
|
39165
39177
|
if (hostedMetadata) {
|
|
39166
|
-
if (
|
|
39178
|
+
if (existsSync5(srcDir)) {
|
|
39167
39179
|
add2(issues, "skill.hosted_source_forbidden", "Hosted metadata skills must not include local implementation source");
|
|
39168
39180
|
}
|
|
39169
|
-
} else if (!
|
|
39181
|
+
} else if (!existsSync5(srcDir)) {
|
|
39170
39182
|
add2(issues, "skill.src_missing", "Missing src/ directory");
|
|
39171
|
-
} else if (!
|
|
39183
|
+
} else if (!existsSync5(join5(srcDir, "index.ts")) && !existsSync5(join5(srcDir, "index.js"))) {
|
|
39172
39184
|
add2(issues, "skill.src_index_missing", "Missing src/index.ts or src/index.js");
|
|
39173
39185
|
} else {
|
|
39174
|
-
const indexPath =
|
|
39175
|
-
const size2 =
|
|
39186
|
+
const indexPath = existsSync5(join5(srcDir, "index.ts")) ? join5(srcDir, "index.ts") : join5(srcDir, "index.js");
|
|
39187
|
+
const size2 = statSync3(indexPath).size;
|
|
39176
39188
|
if (size2 < 50)
|
|
39177
39189
|
add2(warnings, "skill.src_index_minimal", `Source entry point is very small (${size2}B)`);
|
|
39178
39190
|
}
|
|
@@ -39242,8 +39254,8 @@ var init_skill_validation = __esm(() => {
|
|
|
39242
39254
|
|
|
39243
39255
|
// src/lib/skill-hash.ts
|
|
39244
39256
|
import { createHash } from "crypto";
|
|
39245
|
-
import { existsSync as
|
|
39246
|
-
import { join as
|
|
39257
|
+
import { existsSync as existsSync6, readdirSync as readdirSync4, readFileSync as readFileSync5, statSync as statSync4 } from "fs";
|
|
39258
|
+
import { join as join6, sep } from "path";
|
|
39247
39259
|
function normalizeLineEndings(content) {
|
|
39248
39260
|
return content.replace(/\r\n/g, `
|
|
39249
39261
|
`).replace(/\r/g, `
|
|
@@ -39289,10 +39301,10 @@ function collectBundleFiles(skillPath) {
|
|
|
39289
39301
|
if (seen.has(entry))
|
|
39290
39302
|
continue;
|
|
39291
39303
|
seen.add(entry);
|
|
39292
|
-
const absolute =
|
|
39293
|
-
if (!
|
|
39304
|
+
const absolute = join6(skillPath, entry);
|
|
39305
|
+
if (!existsSync6(absolute))
|
|
39294
39306
|
continue;
|
|
39295
|
-
if (
|
|
39307
|
+
if (statSync4(absolute).isDirectory())
|
|
39296
39308
|
collectDirectory(files, absolute, entry);
|
|
39297
39309
|
else
|
|
39298
39310
|
collectFile(files, absolute, entry);
|
|
@@ -39300,14 +39312,14 @@ function collectBundleFiles(skillPath) {
|
|
|
39300
39312
|
return files.sort((a, b) => a.rel < b.rel ? -1 : a.rel > b.rel ? 1 : 0);
|
|
39301
39313
|
}
|
|
39302
39314
|
function collectDirectory(files, dir, rel) {
|
|
39303
|
-
for (const entry of
|
|
39315
|
+
for (const entry of readdirSync4(dir).sort()) {
|
|
39304
39316
|
if (entry.startsWith("."))
|
|
39305
39317
|
continue;
|
|
39306
|
-
const absolute =
|
|
39318
|
+
const absolute = join6(dir, entry);
|
|
39307
39319
|
const childRel = `${rel}/${entry}`;
|
|
39308
39320
|
let stats;
|
|
39309
39321
|
try {
|
|
39310
|
-
stats =
|
|
39322
|
+
stats = statSync4(absolute);
|
|
39311
39323
|
} catch {
|
|
39312
39324
|
continue;
|
|
39313
39325
|
}
|
|
@@ -39323,7 +39335,7 @@ function collectDirectory(files, dir, rel) {
|
|
|
39323
39335
|
}
|
|
39324
39336
|
}
|
|
39325
39337
|
function collectFile(files, absolute, rel) {
|
|
39326
|
-
const buffer =
|
|
39338
|
+
const buffer = readFileSync5(absolute);
|
|
39327
39339
|
if (rel === "skill.json") {
|
|
39328
39340
|
files.push({ rel: rel.split(sep).join("/"), content: new TextEncoder().encode(canonicalizeManifest(new TextDecoder().decode(buffer))) });
|
|
39329
39341
|
return;
|
|
@@ -39378,7 +39390,7 @@ function hashSkillMarkdown(content) {
|
|
|
39378
39390
|
return hash.digest("hex");
|
|
39379
39391
|
}
|
|
39380
39392
|
function hashSkillMarkdownFile(path) {
|
|
39381
|
-
return hashSkillMarkdown(
|
|
39393
|
+
return hashSkillMarkdown(readFileSync5(path, "utf-8"));
|
|
39382
39394
|
}
|
|
39383
39395
|
var CONTENT_HASH_ALGORITHM = "sha256", HASH_EXCLUDE_DIRS, HASH_COVERAGE;
|
|
39384
39396
|
var init_skill_hash = __esm(() => {
|
|
@@ -39558,14 +39570,14 @@ var init_skill_contract = __esm(() => {
|
|
|
39558
39570
|
// src/lib/portable-skills-files.ts
|
|
39559
39571
|
import {
|
|
39560
39572
|
cpSync,
|
|
39561
|
-
existsSync as
|
|
39573
|
+
existsSync as existsSync7,
|
|
39562
39574
|
lstatSync as lstatSync2,
|
|
39563
39575
|
mkdirSync as mkdirSync2,
|
|
39564
|
-
readFileSync as
|
|
39576
|
+
readFileSync as readFileSync6,
|
|
39565
39577
|
realpathSync,
|
|
39566
39578
|
writeFileSync as writeFileSync2
|
|
39567
39579
|
} from "fs";
|
|
39568
|
-
import { basename, dirname as dirname2, join as
|
|
39580
|
+
import { basename, dirname as dirname2, join as join7, relative } from "path";
|
|
39569
39581
|
function defaultRuntimeContract(entrypoint = "src/index.ts") {
|
|
39570
39582
|
return {
|
|
39571
39583
|
runtime: "bun",
|
|
@@ -39589,12 +39601,12 @@ function normalizePortableSkillName(name) {
|
|
|
39589
39601
|
return normalized;
|
|
39590
39602
|
}
|
|
39591
39603
|
function readPortableSkillManifest(skillPath, fallbackName = basename(skillPath)) {
|
|
39592
|
-
const skillJsonPath =
|
|
39593
|
-
const skillMdPath =
|
|
39594
|
-
const pkgPath =
|
|
39595
|
-
const jsonManifest =
|
|
39596
|
-
const frontmatter =
|
|
39597
|
-
const pkg =
|
|
39604
|
+
const skillJsonPath = join7(skillPath, "skill.json");
|
|
39605
|
+
const skillMdPath = join7(skillPath, "SKILL.md");
|
|
39606
|
+
const pkgPath = join7(skillPath, "package.json");
|
|
39607
|
+
const jsonManifest = existsSync7(skillJsonPath) ? readJsonObject(skillJsonPath) : undefined;
|
|
39608
|
+
const frontmatter = existsSync7(skillMdPath) ? parseSkillFrontmatter(readFileSync6(skillMdPath, "utf-8")) ?? undefined : undefined;
|
|
39609
|
+
const pkg = existsSync7(pkgPath) ? readJsonObject(pkgPath) : undefined;
|
|
39598
39610
|
const name = normalizePortableSkillName(stringField(jsonManifest, "name") ?? frontmatter?.name ?? stringValue(pkg?.name) ?? fallbackName);
|
|
39599
39611
|
const description = stringField(jsonManifest, "description") ?? frontmatter?.description ?? stringValue(pkg?.description) ?? `${name} skill`;
|
|
39600
39612
|
const version = stringField(jsonManifest, "version") ?? frontmatter?.version ?? stringValue(pkg?.version) ?? PORTABLE_SKILL_DEFAULT_VERSION;
|
|
@@ -39640,7 +39652,7 @@ function createInstructionManifest(name, options) {
|
|
|
39640
39652
|
}
|
|
39641
39653
|
function writeInstructionSkillTemplate(skillPath, manifest) {
|
|
39642
39654
|
mkdirSync2(skillPath, { recursive: true });
|
|
39643
|
-
writeFileSync2(
|
|
39655
|
+
writeFileSync2(join7(skillPath, "SKILL.md"), renderInstructionSkillMd(manifest));
|
|
39644
39656
|
writeSkillJsonWithHash(skillPath, manifest);
|
|
39645
39657
|
}
|
|
39646
39658
|
function renderInstructionSkillMd(manifest) {
|
|
@@ -39689,12 +39701,12 @@ function createPortableManifest(name, options) {
|
|
|
39689
39701
|
};
|
|
39690
39702
|
}
|
|
39691
39703
|
function writePortableSkillTemplate(skillPath, manifest) {
|
|
39692
|
-
mkdirSync2(
|
|
39693
|
-
writeFileSync2(
|
|
39694
|
-
writeFileSync2(
|
|
39695
|
-
writeFileSync2(
|
|
39696
|
-
writeFileSync2(
|
|
39697
|
-
writeFileSync2(
|
|
39704
|
+
mkdirSync2(join7(skillPath, "src"), { recursive: true });
|
|
39705
|
+
writeFileSync2(join7(skillPath, "SKILL.md"), renderSkillMd(manifest));
|
|
39706
|
+
writeFileSync2(join7(skillPath, "AGENTS.md"), renderAgentsMd(manifest));
|
|
39707
|
+
writeFileSync2(join7(skillPath, "package.json"), renderPackageJson(manifest));
|
|
39708
|
+
writeFileSync2(join7(skillPath, "tsconfig.json"), renderTsconfig());
|
|
39709
|
+
writeFileSync2(join7(skillPath, "src", "index.ts"), renderEntrypoint(manifest));
|
|
39698
39710
|
writeSkillJsonWithHash(skillPath, manifest);
|
|
39699
39711
|
}
|
|
39700
39712
|
function fillContractDefaults(manifest, entrypoint) {
|
|
@@ -39719,7 +39731,7 @@ function writeSkillJsonWithHash(skillPath, manifest) {
|
|
|
39719
39731
|
content_hash: undefined
|
|
39720
39732
|
}
|
|
39721
39733
|
};
|
|
39722
|
-
writeFileSync2(
|
|
39734
|
+
writeFileSync2(join7(skillPath, "skill.json"), `${JSON.stringify({ ...existing, ...renderSkillJsonObject(withoutHash) }, null, 2)}
|
|
39723
39735
|
`);
|
|
39724
39736
|
const hash = computeContentHash(skillPath);
|
|
39725
39737
|
const withHash = {
|
|
@@ -39729,16 +39741,16 @@ function writeSkillJsonWithHash(skillPath, manifest) {
|
|
|
39729
39741
|
content_hash: hash
|
|
39730
39742
|
}
|
|
39731
39743
|
};
|
|
39732
|
-
writeFileSync2(
|
|
39744
|
+
writeFileSync2(join7(skillPath, "skill.json"), `${JSON.stringify({ ...existing, ...renderSkillJsonObject(withHash) }, null, 2)}
|
|
39733
39745
|
`);
|
|
39734
39746
|
return withHash;
|
|
39735
39747
|
}
|
|
39736
39748
|
function readExistingSkillJson(skillPath) {
|
|
39737
|
-
const path =
|
|
39738
|
-
if (!
|
|
39749
|
+
const path = join7(skillPath, "skill.json");
|
|
39750
|
+
if (!existsSync7(path))
|
|
39739
39751
|
return {};
|
|
39740
39752
|
try {
|
|
39741
|
-
const parsed = JSON.parse(
|
|
39753
|
+
const parsed = JSON.parse(readFileSync6(path, "utf-8"));
|
|
39742
39754
|
return isRecord2(parsed) ? parsed : {};
|
|
39743
39755
|
} catch {
|
|
39744
39756
|
return {};
|
|
@@ -39768,28 +39780,28 @@ function ensurePortableSkillFiles(skillPath, manifest) {
|
|
|
39768
39780
|
tags: next.tags?.length ? next.tags : ["custom", next.name]
|
|
39769
39781
|
};
|
|
39770
39782
|
const entry = next.commands[0]?.entry ?? "src/index.ts";
|
|
39771
|
-
if (entry && !
|
|
39772
|
-
mkdirSync2(dirname2(
|
|
39773
|
-
writeFileSync2(
|
|
39783
|
+
if (entry && !existsSync7(join7(skillPath, entry))) {
|
|
39784
|
+
mkdirSync2(dirname2(join7(skillPath, entry)), { recursive: true });
|
|
39785
|
+
writeFileSync2(join7(skillPath, entry), renderEntrypoint(next));
|
|
39774
39786
|
}
|
|
39775
|
-
if (!
|
|
39776
|
-
writeFileSync2(
|
|
39787
|
+
if (!existsSync7(join7(skillPath, "SKILL.md")))
|
|
39788
|
+
writeFileSync2(join7(skillPath, "SKILL.md"), renderSkillMd(next));
|
|
39777
39789
|
else
|
|
39778
|
-
writeFileSync2(
|
|
39779
|
-
if (!
|
|
39780
|
-
writeFileSync2(
|
|
39790
|
+
writeFileSync2(join7(skillPath, "SKILL.md"), ensureSkillMdFrontmatter(readFileSync6(join7(skillPath, "SKILL.md"), "utf-8"), next));
|
|
39791
|
+
if (!existsSync7(join7(skillPath, "AGENTS.md")))
|
|
39792
|
+
writeFileSync2(join7(skillPath, "AGENTS.md"), renderAgentsMd(next));
|
|
39781
39793
|
ensurePackageJson(skillPath, next);
|
|
39782
|
-
if (!
|
|
39783
|
-
writeFileSync2(
|
|
39794
|
+
if (!existsSync7(join7(skillPath, "tsconfig.json")))
|
|
39795
|
+
writeFileSync2(join7(skillPath, "tsconfig.json"), renderTsconfig());
|
|
39784
39796
|
writeSkillJsonWithHash(skillPath, next);
|
|
39785
39797
|
return readPortableSkillManifest(skillPath, next.name);
|
|
39786
39798
|
}
|
|
39787
39799
|
function ensurePackageJson(skillPath, manifest) {
|
|
39788
|
-
const pkgPath =
|
|
39800
|
+
const pkgPath = join7(skillPath, "package.json");
|
|
39789
39801
|
const first = manifest.commands[0] ?? { name: manifest.name, entry: "src/index.ts" };
|
|
39790
39802
|
const commandName = normalizePortableSkillName(first.name || manifest.name);
|
|
39791
39803
|
const entry = (first.entry ?? "src/index.ts").replace(/^\.\//, "");
|
|
39792
|
-
if (!
|
|
39804
|
+
if (!existsSync7(pkgPath)) {
|
|
39793
39805
|
writeFileSync2(pkgPath, renderPackageJson(manifest));
|
|
39794
39806
|
return;
|
|
39795
39807
|
}
|
|
@@ -39832,8 +39844,8 @@ function ensureInstructionSkillFiles(skillPath, manifest) {
|
|
|
39832
39844
|
inputs: [],
|
|
39833
39845
|
commands: []
|
|
39834
39846
|
};
|
|
39835
|
-
if (!
|
|
39836
|
-
writeFileSync2(
|
|
39847
|
+
if (!existsSync7(join7(skillPath, "SKILL.md"))) {
|
|
39848
|
+
writeFileSync2(join7(skillPath, "SKILL.md"), renderSkillMd(next));
|
|
39837
39849
|
}
|
|
39838
39850
|
writeSkillJsonWithHash(skillPath, next);
|
|
39839
39851
|
return readPortableSkillManifest(skillPath, next.name);
|
|
@@ -40084,7 +40096,7 @@ function inferPackageCommands(pkg, fallbackName) {
|
|
|
40084
40096
|
return;
|
|
40085
40097
|
}
|
|
40086
40098
|
function readJsonObject(path) {
|
|
40087
|
-
const parsed = JSON.parse(
|
|
40099
|
+
const parsed = JSON.parse(readFileSync6(path, "utf-8"));
|
|
40088
40100
|
if (!isRecord2(parsed))
|
|
40089
40101
|
throw new Error(`${basename(path)} must contain a JSON object`);
|
|
40090
40102
|
return parsed;
|
|
@@ -40140,48 +40152,49 @@ var init_portable_skills_files = __esm(() => {
|
|
|
40140
40152
|
// src/lib/portable-skills.ts
|
|
40141
40153
|
import {
|
|
40142
40154
|
cpSync as cpSync2,
|
|
40143
|
-
existsSync as
|
|
40155
|
+
existsSync as existsSync8,
|
|
40144
40156
|
mkdirSync as mkdirSync3,
|
|
40145
|
-
|
|
40157
|
+
mkdtempSync,
|
|
40158
|
+
readdirSync as readdirSync5,
|
|
40146
40159
|
renameSync,
|
|
40147
40160
|
rmSync,
|
|
40148
|
-
statSync as
|
|
40161
|
+
statSync as statSync6,
|
|
40149
40162
|
writeFileSync as writeFileSync3
|
|
40150
40163
|
} from "fs";
|
|
40151
|
-
import { basename as basename2, dirname as dirname3, isAbsolute as isAbsolute2, join as
|
|
40164
|
+
import { basename as basename2, dirname as dirname3, isAbsolute as isAbsolute2, join as join8, normalize as normalize2 } from "path";
|
|
40152
40165
|
function getPortableSkillsRoot(options = {}) {
|
|
40153
40166
|
if (options.rootDir)
|
|
40154
40167
|
return options.rootDir;
|
|
40155
|
-
const appDir = options.homeDir ?
|
|
40156
|
-
const cache3 =
|
|
40168
|
+
const appDir = options.homeDir ? join8(options.homeDir, ".hasna", "skills") : getDataDir();
|
|
40169
|
+
const cache3 = join8(appDir, SKILLS_CACHE_DIRNAME);
|
|
40157
40170
|
if (isOwnerLayoutMigrated(appDir) && safeIsDirectory(cache3))
|
|
40158
40171
|
return cache3;
|
|
40159
|
-
const installed =
|
|
40172
|
+
const installed = join8(appDir, INSTALLED_SKILLS_DIRNAME);
|
|
40160
40173
|
migrateLegacySkillLayout(appDir, installed);
|
|
40161
40174
|
return installed;
|
|
40162
40175
|
}
|
|
40163
40176
|
function looksLikeSkillDirectory(path) {
|
|
40164
40177
|
if (!safeIsDirectory(path))
|
|
40165
40178
|
return false;
|
|
40166
|
-
return
|
|
40179
|
+
return existsSync8(join8(path, "SKILL.md")) || existsSync8(join8(path, "skill.json")) || existsSync8(join8(path, "package.json"));
|
|
40167
40180
|
}
|
|
40168
40181
|
function migrateLegacySkillLayout(appDir, installed) {
|
|
40169
40182
|
if (!safeIsDirectory(appDir))
|
|
40170
40183
|
return;
|
|
40171
40184
|
const candidates = [];
|
|
40172
40185
|
try {
|
|
40173
|
-
for (const entry of
|
|
40186
|
+
for (const entry of readdirSync5(appDir)) {
|
|
40174
40187
|
if (entry.startsWith(".") || entry === INSTALLED_SKILLS_DIRNAME)
|
|
40175
40188
|
continue;
|
|
40176
|
-
const path =
|
|
40189
|
+
const path = join8(appDir, entry);
|
|
40177
40190
|
if (entry === LEGACY_CUSTOM_DIRNAME) {
|
|
40178
40191
|
if (!safeIsDirectory(path))
|
|
40179
40192
|
continue;
|
|
40180
40193
|
try {
|
|
40181
|
-
for (const nested of
|
|
40194
|
+
for (const nested of readdirSync5(path)) {
|
|
40182
40195
|
if (nested.startsWith("."))
|
|
40183
40196
|
continue;
|
|
40184
|
-
const nestedPath =
|
|
40197
|
+
const nestedPath = join8(path, nested);
|
|
40185
40198
|
if (looksLikeSkillDirectory(nestedPath))
|
|
40186
40199
|
candidates.push({ from: nestedPath, name: nested });
|
|
40187
40200
|
}
|
|
@@ -40195,10 +40208,10 @@ function migrateLegacySkillLayout(appDir, installed) {
|
|
|
40195
40208
|
return;
|
|
40196
40209
|
}
|
|
40197
40210
|
for (const { from, name } of candidates) {
|
|
40198
|
-
const target =
|
|
40199
|
-
if (
|
|
40211
|
+
const target = join8(installed, name);
|
|
40212
|
+
if (existsSync8(target))
|
|
40200
40213
|
continue;
|
|
40201
|
-
const staging =
|
|
40214
|
+
const staging = join8(installed, `.migrating-${name}-${process.pid}`);
|
|
40202
40215
|
try {
|
|
40203
40216
|
rmSync(staging, { recursive: true, force: true });
|
|
40204
40217
|
cpSync2(from, staging, { recursive: true, errorOnExist: false });
|
|
@@ -40211,7 +40224,7 @@ function migrateLegacySkillLayout(appDir, installed) {
|
|
|
40211
40224
|
}
|
|
40212
40225
|
}
|
|
40213
40226
|
function getPortableSkillPath(name, options = {}) {
|
|
40214
|
-
return
|
|
40227
|
+
return join8(getPortableSkillsRoot(options), normalizePortableSkillName(name));
|
|
40215
40228
|
}
|
|
40216
40229
|
function findPortableSkill(name, options = {}) {
|
|
40217
40230
|
let normalized;
|
|
@@ -40221,7 +40234,7 @@ function findPortableSkill(name, options = {}) {
|
|
|
40221
40234
|
return null;
|
|
40222
40235
|
}
|
|
40223
40236
|
const path = getPortableSkillPath(normalized, options);
|
|
40224
|
-
if (!
|
|
40237
|
+
if (!existsSync8(path) || !statSync6(path).isDirectory())
|
|
40225
40238
|
return null;
|
|
40226
40239
|
try {
|
|
40227
40240
|
return summarizePortableSkill(path, normalized);
|
|
@@ -40234,10 +40247,10 @@ function listPortableSkills(options = {}) {
|
|
|
40234
40247
|
if (!safeIsDirectory(root))
|
|
40235
40248
|
return [];
|
|
40236
40249
|
const skills = [];
|
|
40237
|
-
for (const entry of
|
|
40250
|
+
for (const entry of readdirSync5(root).sort()) {
|
|
40238
40251
|
if (entry.startsWith("."))
|
|
40239
40252
|
continue;
|
|
40240
|
-
const path =
|
|
40253
|
+
const path = join8(root, entry);
|
|
40241
40254
|
if (!safeIsDirectory(path))
|
|
40242
40255
|
continue;
|
|
40243
40256
|
try {
|
|
@@ -40259,7 +40272,8 @@ function listPortableSkillMetas(options = {}) {
|
|
|
40259
40272
|
tags: manifest.tags || ["custom"],
|
|
40260
40273
|
version: skill.version,
|
|
40261
40274
|
...manifest.kind ? { kind: manifest.kind } : {},
|
|
40262
|
-
source: "custom"
|
|
40275
|
+
source: "custom",
|
|
40276
|
+
...isHostedMetadataSkillDir(skill.path) ? { serverOwned: true } : {}
|
|
40263
40277
|
};
|
|
40264
40278
|
});
|
|
40265
40279
|
}
|
|
@@ -40269,8 +40283,8 @@ function isOfficialSkillName(name) {
|
|
|
40269
40283
|
function scaffoldPortableSkill(name, options = {}) {
|
|
40270
40284
|
const skillName = normalizePortableSkillName(name);
|
|
40271
40285
|
const root = getPortableSkillsRoot(options);
|
|
40272
|
-
const skillPath =
|
|
40273
|
-
if (
|
|
40286
|
+
const skillPath = join8(root, skillName);
|
|
40287
|
+
if (existsSync8(skillPath)) {
|
|
40274
40288
|
if (!options.overwrite)
|
|
40275
40289
|
throw new Error(`Skill '${skillName}' already exists at ${skillPath}`);
|
|
40276
40290
|
rmSync(skillPath, { recursive: true, force: true });
|
|
@@ -40288,7 +40302,7 @@ function scaffoldPortableSkill(name, options = {}) {
|
|
|
40288
40302
|
}
|
|
40289
40303
|
function portPortableSkillDirectory(sourceDir, options = {}) {
|
|
40290
40304
|
const absoluteSource = normalize2(sourceDir);
|
|
40291
|
-
if (!
|
|
40305
|
+
if (!existsSync8(absoluteSource) || !statSync6(absoluteSource).isDirectory()) {
|
|
40292
40306
|
throw new Error(`Import directory not found: ${sourceDir}`);
|
|
40293
40307
|
}
|
|
40294
40308
|
const continueOnError = options.continueOnError ?? true;
|
|
@@ -40299,9 +40313,9 @@ function portPortableSkillDirectory(sourceDir, options = {}) {
|
|
|
40299
40313
|
};
|
|
40300
40314
|
const imported = [];
|
|
40301
40315
|
const skipped = [];
|
|
40302
|
-
const entries =
|
|
40316
|
+
const entries = readdirSync5(absoluteSource, { withFileTypes: true }).map((entry) => entry.name).filter((entryName) => !entryName.startsWith(".")).sort();
|
|
40303
40317
|
for (const entryName of entries) {
|
|
40304
|
-
const childPath =
|
|
40318
|
+
const childPath = join8(absoluteSource, entryName);
|
|
40305
40319
|
if (!safeIsDirectory(childPath))
|
|
40306
40320
|
continue;
|
|
40307
40321
|
if (!isSkillCandidate(childPath)) {
|
|
@@ -40330,11 +40344,11 @@ function portPortableSkillDirectory(sourceDir, options = {}) {
|
|
|
40330
40344
|
};
|
|
40331
40345
|
}
|
|
40332
40346
|
function isSkillCandidate(dir) {
|
|
40333
|
-
return
|
|
40347
|
+
return existsSync8(join8(dir, "SKILL.md")) || existsSync8(join8(dir, "skill.json")) || existsSync8(join8(dir, "package.json"));
|
|
40334
40348
|
}
|
|
40335
40349
|
function portPortableSkill(sourcePath, options = {}) {
|
|
40336
40350
|
const absoluteSource = normalize2(sourcePath);
|
|
40337
|
-
if (!
|
|
40351
|
+
if (!existsSync8(absoluteSource) || !statSync6(absoluteSource).isDirectory()) {
|
|
40338
40352
|
throw new Error(`Skill source directory not found: ${sourcePath}`);
|
|
40339
40353
|
}
|
|
40340
40354
|
const inferred = readPortableSkillManifest(absoluteSource, basename2(absoluteSource));
|
|
@@ -40346,8 +40360,8 @@ function portPortableSkill(sourcePath, options = {}) {
|
|
|
40346
40360
|
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
40361
|
}
|
|
40348
40362
|
const root = getPortableSkillsRoot(options);
|
|
40349
|
-
const destination =
|
|
40350
|
-
if (
|
|
40363
|
+
const destination = join8(root, skillName);
|
|
40364
|
+
if (existsSync8(destination)) {
|
|
40351
40365
|
if (!options.overwrite)
|
|
40352
40366
|
throw new Error(`Skill '${skillName}' already exists at ${destination}`);
|
|
40353
40367
|
rmSync(destination, { recursive: true, force: true });
|
|
@@ -40369,16 +40383,10 @@ function safeNormalizeName(name) {
|
|
|
40369
40383
|
return;
|
|
40370
40384
|
}
|
|
40371
40385
|
}
|
|
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);
|
|
40386
|
+
function buildCorpusManifest(input, name) {
|
|
40379
40387
|
const frontmatter = parseSkillFrontmatter(input.skillMd) ?? undefined;
|
|
40380
40388
|
const kind = input.meta?.kind ?? parseSkillKind(frontmatter?.kind) ?? "instruction";
|
|
40381
|
-
|
|
40389
|
+
return {
|
|
40382
40390
|
$schema: PORTABLE_SKILL_SCHEMA,
|
|
40383
40391
|
standard: PORTABLE_SKILL_STANDARD,
|
|
40384
40392
|
name,
|
|
@@ -40391,8 +40399,38 @@ function writeCorpusSkill(input, options = {}) {
|
|
|
40391
40399
|
inputs: [],
|
|
40392
40400
|
commands: []
|
|
40393
40401
|
};
|
|
40394
|
-
|
|
40395
|
-
|
|
40402
|
+
}
|
|
40403
|
+
function installCorpusSkillAtomically(input, options = {}) {
|
|
40404
|
+
const name = normalizePortableSkillName(input.name);
|
|
40405
|
+
const root = getPortableSkillsRoot(options);
|
|
40406
|
+
const target = join8(root, name);
|
|
40407
|
+
const created = !existsSync8(target);
|
|
40408
|
+
mkdirSync3(root, { recursive: true });
|
|
40409
|
+
const staging = mkdtempSync(join8(root, `.pull-${name}-`));
|
|
40410
|
+
let moved = false;
|
|
40411
|
+
let backup = null;
|
|
40412
|
+
try {
|
|
40413
|
+
writeFileSync3(join8(staging, "SKILL.md"), input.skillMd);
|
|
40414
|
+
const manifest = buildCorpusManifest(input, name);
|
|
40415
|
+
writeSkillJsonWithHash(staging, manifest);
|
|
40416
|
+
if (existsSync8(target)) {
|
|
40417
|
+
backup = mkdtempSync(join8(root, `.pull-backup-${name}-`));
|
|
40418
|
+
renameSync(target, join8(backup, name));
|
|
40419
|
+
moved = true;
|
|
40420
|
+
}
|
|
40421
|
+
renameSync(staging, target);
|
|
40422
|
+
if (moved && backup)
|
|
40423
|
+
rmSync(backup, { recursive: true, force: true });
|
|
40424
|
+
return { name, path: target, manifest, created };
|
|
40425
|
+
} catch (error) {
|
|
40426
|
+
rmSync(staging, { recursive: true, force: true });
|
|
40427
|
+
if (moved && backup && existsSync8(join8(backup, name))) {
|
|
40428
|
+
try {
|
|
40429
|
+
renameSync(join8(backup, name), target);
|
|
40430
|
+
} catch {}
|
|
40431
|
+
}
|
|
40432
|
+
throw error;
|
|
40433
|
+
}
|
|
40396
40434
|
}
|
|
40397
40435
|
function validatePortableSkillDirectory(name, skillPath) {
|
|
40398
40436
|
const normalizedName = normalizePortableSkillName(name);
|
|
@@ -40400,10 +40438,10 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
40400
40438
|
const issues = [...base2.issues];
|
|
40401
40439
|
const warnings = [...base2.warnings];
|
|
40402
40440
|
let manifest;
|
|
40403
|
-
if (
|
|
40404
|
-
const skillJsonPath =
|
|
40405
|
-
const skillMdPath =
|
|
40406
|
-
if (!
|
|
40441
|
+
if (existsSync8(skillPath)) {
|
|
40442
|
+
const skillJsonPath = join8(skillPath, "skill.json");
|
|
40443
|
+
const skillMdPath = join8(skillPath, "SKILL.md");
|
|
40444
|
+
if (!existsSync8(skillJsonPath) && !existsSync8(skillMdPath)) {
|
|
40407
40445
|
add4(issues, "portable.manifest_missing", "Missing portable manifest: expected SKILL.md frontmatter and/or skill.json");
|
|
40408
40446
|
}
|
|
40409
40447
|
try {
|
|
@@ -40422,7 +40460,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
40422
40460
|
add4(issues, "portable.version_missing", "Portable manifest missing version");
|
|
40423
40461
|
}
|
|
40424
40462
|
const contractIssues = validatePortableManifestContract(manifest, {
|
|
40425
|
-
strict:
|
|
40463
|
+
strict: existsSync8(join8(skillPath, "skill.json")),
|
|
40426
40464
|
skillPath
|
|
40427
40465
|
});
|
|
40428
40466
|
for (const issue of contractIssues)
|
|
@@ -40458,10 +40496,10 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
40458
40496
|
add4(issues, "portable.command_entry_unsafe", `Command '${command.name}' entry '${command.entry}' must stay inside the skill directory`);
|
|
40459
40497
|
continue;
|
|
40460
40498
|
}
|
|
40461
|
-
const entryPath =
|
|
40462
|
-
if (!
|
|
40499
|
+
const entryPath = join8(skillPath, command.entry);
|
|
40500
|
+
if (!existsSync8(entryPath))
|
|
40463
40501
|
add4(issues, "portable.command_entry_missing", `Command '${command.name}' entry '${command.entry}' is missing`);
|
|
40464
|
-
else if (
|
|
40502
|
+
else if (statSync6(entryPath).isDirectory())
|
|
40465
40503
|
add4(issues, "portable.command_entry_directory", `Command '${command.name}' entry '${command.entry}' must be a file`);
|
|
40466
40504
|
}
|
|
40467
40505
|
}
|
|
@@ -40469,7 +40507,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
40469
40507
|
} catch (error) {
|
|
40470
40508
|
add4(issues, "portable.manifest_invalid", error.message);
|
|
40471
40509
|
}
|
|
40472
|
-
if (manifest?.kind !== "instruction" && !
|
|
40510
|
+
if (manifest?.kind !== "instruction" && !existsSync8(join8(skillPath, "AGENTS.md"))) {
|
|
40473
40511
|
add4(issues, "portable.agents_missing", "Missing AGENTS.md with build-out instructions for coding agents");
|
|
40474
40512
|
}
|
|
40475
40513
|
}
|
|
@@ -40501,7 +40539,7 @@ function summarizePortableSkill(skillPath, fallbackName) {
|
|
|
40501
40539
|
}
|
|
40502
40540
|
function safeIsDirectory(path) {
|
|
40503
40541
|
try {
|
|
40504
|
-
return
|
|
40542
|
+
return statSync6(path).isDirectory();
|
|
40505
40543
|
} catch {
|
|
40506
40544
|
return false;
|
|
40507
40545
|
}
|
|
@@ -40522,6 +40560,7 @@ var LEGACY_CUSTOM_DIRNAME = "custom", OFFICIAL_SKILL_NAMES;
|
|
|
40522
40560
|
var init_portable_skills = __esm(() => {
|
|
40523
40561
|
init_config();
|
|
40524
40562
|
init_registry_data();
|
|
40563
|
+
init_hosted_skill_set();
|
|
40525
40564
|
init_skill_validation();
|
|
40526
40565
|
init_skill_contract();
|
|
40527
40566
|
init_portable_skills_files();
|
|
@@ -40737,8 +40776,8 @@ __export(exports_registry, {
|
|
|
40737
40776
|
CATEGORIES: () => CATEGORIES,
|
|
40738
40777
|
BASIC_SKILL_NAMES: () => BASIC_SKILL_NAMES
|
|
40739
40778
|
});
|
|
40740
|
-
import { existsSync as
|
|
40741
|
-
import { join as
|
|
40779
|
+
import { existsSync as existsSync9, readFileSync as readFileSync7, readdirSync as readdirSync6 } from "fs";
|
|
40780
|
+
import { join as join9 } from "path";
|
|
40742
40781
|
function isBasicSkillName(name) {
|
|
40743
40782
|
return BASIC_SKILL_NAMES.includes(name);
|
|
40744
40783
|
}
|
|
@@ -40774,20 +40813,20 @@ function parseSkillMdFrontmatter(content) {
|
|
|
40774
40813
|
return Object.keys(result2).length > 0 ? result2 : null;
|
|
40775
40814
|
}
|
|
40776
40815
|
function discoverSkillsInDir(dir, source = "custom") {
|
|
40777
|
-
if (!
|
|
40816
|
+
if (!existsSync9(dir))
|
|
40778
40817
|
return [];
|
|
40779
40818
|
const result2 = [];
|
|
40780
40819
|
try {
|
|
40781
|
-
const entries =
|
|
40820
|
+
const entries = readdirSync6(dir, { withFileTypes: true });
|
|
40782
40821
|
for (const entry of entries) {
|
|
40783
40822
|
if (!entry.isDirectory())
|
|
40784
40823
|
continue;
|
|
40785
|
-
const skillMdPath =
|
|
40786
|
-
if (!
|
|
40824
|
+
const skillMdPath = join9(dir, entry.name, "SKILL.md");
|
|
40825
|
+
if (!existsSync9(skillMdPath))
|
|
40787
40826
|
continue;
|
|
40788
40827
|
let content;
|
|
40789
40828
|
try {
|
|
40790
|
-
content =
|
|
40829
|
+
content = readFileSync7(skillMdPath, "utf-8");
|
|
40791
40830
|
} catch {
|
|
40792
40831
|
continue;
|
|
40793
40832
|
}
|
|
@@ -40802,6 +40841,7 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
40802
40841
|
category: fm.category || "Development Tools",
|
|
40803
40842
|
tags: fm.tags || [],
|
|
40804
40843
|
...fm.kind ? { kind: fm.kind } : {},
|
|
40844
|
+
...isHostedMetadataSkillDir(join9(dir, entry.name)) ? { serverOwned: true } : {},
|
|
40805
40845
|
source
|
|
40806
40846
|
});
|
|
40807
40847
|
}
|
|
@@ -40810,20 +40850,20 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
40810
40850
|
}
|
|
40811
40851
|
function findExtensionSkillPath(name) {
|
|
40812
40852
|
const config = loadConfig();
|
|
40813
|
-
if (!config.extensionsDir || !
|
|
40853
|
+
if (!config.extensionsDir || !existsSync9(config.extensionsDir))
|
|
40814
40854
|
return null;
|
|
40815
40855
|
try {
|
|
40816
|
-
const entries =
|
|
40856
|
+
const entries = readdirSync6(config.extensionsDir, { withFileTypes: true });
|
|
40817
40857
|
for (const entry of entries) {
|
|
40818
40858
|
if (!entry.isDirectory())
|
|
40819
40859
|
continue;
|
|
40820
|
-
const skillDir =
|
|
40821
|
-
const skillMdPath =
|
|
40822
|
-
if (!
|
|
40860
|
+
const skillDir = join9(config.extensionsDir, entry.name);
|
|
40861
|
+
const skillMdPath = join9(skillDir, "SKILL.md");
|
|
40862
|
+
if (!existsSync9(skillMdPath))
|
|
40823
40863
|
continue;
|
|
40824
40864
|
let content;
|
|
40825
40865
|
try {
|
|
40826
|
-
content =
|
|
40866
|
+
content = readFileSync7(skillMdPath, "utf-8");
|
|
40827
40867
|
} catch {
|
|
40828
40868
|
continue;
|
|
40829
40869
|
}
|
|
@@ -40852,7 +40892,7 @@ function loadRegistry(cwd2) {
|
|
|
40852
40892
|
const official = SKILLS.map((s) => ({ ...s, source: "official" }));
|
|
40853
40893
|
const extensions = config.extensionsDir ? discoverSkillsInDir(config.extensionsDir, "extension") : [];
|
|
40854
40894
|
const portableCustom = listPortableSkillMetas();
|
|
40855
|
-
const legacyCustom = discoverSkillsInDir(
|
|
40895
|
+
const legacyCustom = discoverSkillsInDir(join9(dataDir, "custom"));
|
|
40856
40896
|
const globalCustom = mergeCustomSkills([...legacyCustom, ...portableCustom]);
|
|
40857
40897
|
registryCache = mergeSkillRegistryLists(official, extensions, globalCustom);
|
|
40858
40898
|
registryCacheTime = now3;
|
|
@@ -40902,6 +40942,7 @@ var registryCache = null, registryCacheTime = 0, registryCacheKey = null, REGIST
|
|
|
40902
40942
|
var init_registry = __esm(() => {
|
|
40903
40943
|
init_config();
|
|
40904
40944
|
init_portable_skills();
|
|
40945
|
+
init_hosted_skill_set();
|
|
40905
40946
|
init_registry_merge();
|
|
40906
40947
|
init_skill_aliases();
|
|
40907
40948
|
init_registry_data();
|
|
@@ -42550,33 +42591,33 @@ var require_cli_spinners = __commonJS((exports, module) => {
|
|
|
42550
42591
|
});
|
|
42551
42592
|
|
|
42552
42593
|
// src/lib/home-migration.ts
|
|
42553
|
-
import { existsSync as
|
|
42554
|
-
import { join as
|
|
42594
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync4, readdirSync as readdirSync7, renameSync as renameSync2, rmSync as rmSync2, statSync as statSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
42595
|
+
import { join as join10 } from "path";
|
|
42555
42596
|
function layoutMigrationRecordPath(appDir) {
|
|
42556
|
-
return
|
|
42597
|
+
return join10(appDir, SKILLS_CACHE_DIRNAME, LAYOUT_MIGRATION_RECORD);
|
|
42557
42598
|
}
|
|
42558
42599
|
function resolveCorpusRoot(options = {}) {
|
|
42559
42600
|
return getPortableSkillsRoot(options);
|
|
42560
42601
|
}
|
|
42561
42602
|
function migrationAppDir(homeDir) {
|
|
42562
|
-
return homeDir ?
|
|
42603
|
+
return homeDir ? join10(homeDir, ".hasna", "skills") : getDataDir();
|
|
42563
42604
|
}
|
|
42564
42605
|
function looksLikeSkillDirectory2(path) {
|
|
42565
42606
|
try {
|
|
42566
|
-
if (!
|
|
42607
|
+
if (!statSync7(path).isDirectory())
|
|
42567
42608
|
return false;
|
|
42568
42609
|
} catch {
|
|
42569
42610
|
return false;
|
|
42570
42611
|
}
|
|
42571
|
-
return
|
|
42612
|
+
return existsSync10(join10(path, "SKILL.md")) || existsSync10(join10(path, "skill.json")) || existsSync10(join10(path, "package.json"));
|
|
42572
42613
|
}
|
|
42573
42614
|
function listLegacyFlatSkillDirs(appDir) {
|
|
42574
42615
|
const legacy = [];
|
|
42575
|
-
if (!
|
|
42616
|
+
if (!existsSync10(appDir))
|
|
42576
42617
|
return legacy;
|
|
42577
42618
|
let entries = [];
|
|
42578
42619
|
try {
|
|
42579
|
-
entries =
|
|
42620
|
+
entries = readdirSync7(appDir);
|
|
42580
42621
|
} catch {
|
|
42581
42622
|
return legacy;
|
|
42582
42623
|
}
|
|
@@ -42586,15 +42627,15 @@ function listLegacyFlatSkillDirs(appDir) {
|
|
|
42586
42627
|
if (entry === SKILLS_CACHE_DIRNAME || entry === INSTALLED_SKILLS_DIRNAME || entry === LEGACY_CUSTOM_DIRNAME2 || entry === LOGS_DIRNAME || entry === OUTPUTS_DIRNAME) {
|
|
42587
42628
|
continue;
|
|
42588
42629
|
}
|
|
42589
|
-
if (looksLikeSkillDirectory2(
|
|
42630
|
+
if (looksLikeSkillDirectory2(join10(appDir, entry)))
|
|
42590
42631
|
legacy.push(entry);
|
|
42591
42632
|
}
|
|
42592
42633
|
return legacy;
|
|
42593
42634
|
}
|
|
42594
42635
|
function createLazyDirs(appDir, created) {
|
|
42595
42636
|
for (const name of [LOGS_DIRNAME, OUTPUTS_DIRNAME]) {
|
|
42596
|
-
const dir =
|
|
42597
|
-
if (!
|
|
42637
|
+
const dir = join10(appDir, name);
|
|
42638
|
+
if (!existsSync10(dir)) {
|
|
42598
42639
|
mkdirSync4(dir, { recursive: true });
|
|
42599
42640
|
created.push(dir);
|
|
42600
42641
|
}
|
|
@@ -42602,17 +42643,17 @@ function createLazyDirs(appDir, created) {
|
|
|
42602
42643
|
}
|
|
42603
42644
|
function migrateOwnerLayout(options = {}) {
|
|
42604
42645
|
const appDir = migrationAppDir(options.homeDir);
|
|
42605
|
-
const cache3 =
|
|
42606
|
-
const installed =
|
|
42646
|
+
const cache3 = join10(appDir, SKILLS_CACHE_DIRNAME);
|
|
42647
|
+
const installed = join10(appDir, INSTALLED_SKILLS_DIRNAME);
|
|
42607
42648
|
const moved = [];
|
|
42608
42649
|
const created = [];
|
|
42609
42650
|
if (isOwnerLayoutMigrated(appDir)) {
|
|
42610
42651
|
return { status: "already-migrated", moved, created };
|
|
42611
42652
|
}
|
|
42612
|
-
if (
|
|
42653
|
+
if (existsSync10(cache3)) {
|
|
42613
42654
|
let entries = [];
|
|
42614
42655
|
try {
|
|
42615
|
-
entries =
|
|
42656
|
+
entries = readdirSync7(cache3);
|
|
42616
42657
|
} catch {}
|
|
42617
42658
|
if (entries.length > 0) {
|
|
42618
42659
|
return {
|
|
@@ -42623,7 +42664,7 @@ function migrateOwnerLayout(options = {}) {
|
|
|
42623
42664
|
};
|
|
42624
42665
|
}
|
|
42625
42666
|
}
|
|
42626
|
-
const installedPresent =
|
|
42667
|
+
const installedPresent = existsSync10(installed);
|
|
42627
42668
|
const legacy = listLegacyFlatSkillDirs(appDir);
|
|
42628
42669
|
const planned = [...installedPresent ? [INSTALLED_SKILLS_DIRNAME] : [], ...legacy];
|
|
42629
42670
|
if (!installedPresent && legacy.length === 0) {
|
|
@@ -42636,10 +42677,10 @@ function migrateOwnerLayout(options = {}) {
|
|
|
42636
42677
|
}
|
|
42637
42678
|
const collisionNames = new Set;
|
|
42638
42679
|
for (const dir of [cache3, ...installedPresent ? [installed] : []]) {
|
|
42639
|
-
if (!
|
|
42680
|
+
if (!existsSync10(dir))
|
|
42640
42681
|
continue;
|
|
42641
42682
|
try {
|
|
42642
|
-
for (const entry of
|
|
42683
|
+
for (const entry of readdirSync7(dir))
|
|
42643
42684
|
collisionNames.add(entry);
|
|
42644
42685
|
} catch {}
|
|
42645
42686
|
}
|
|
@@ -42653,7 +42694,7 @@ function migrateOwnerLayout(options = {}) {
|
|
|
42653
42694
|
};
|
|
42654
42695
|
}
|
|
42655
42696
|
}
|
|
42656
|
-
if (
|
|
42697
|
+
if (existsSync10(cache3)) {
|
|
42657
42698
|
rmSync2(cache3, { recursive: true, force: true });
|
|
42658
42699
|
}
|
|
42659
42700
|
if (installedPresent) {
|
|
@@ -42663,7 +42704,7 @@ function migrateOwnerLayout(options = {}) {
|
|
|
42663
42704
|
mkdirSync4(cache3, { recursive: true });
|
|
42664
42705
|
}
|
|
42665
42706
|
for (const name of legacy) {
|
|
42666
|
-
renameSync2(
|
|
42707
|
+
renameSync2(join10(appDir, name), join10(cache3, name));
|
|
42667
42708
|
moved.push(name);
|
|
42668
42709
|
}
|
|
42669
42710
|
createLazyDirs(appDir, created);
|
|
@@ -42687,18 +42728,18 @@ var init_home_migration = __esm(() => {
|
|
|
42687
42728
|
// src/lib/agent-sync.ts
|
|
42688
42729
|
import {
|
|
42689
42730
|
cpSync as cpSync3,
|
|
42690
|
-
existsSync as
|
|
42731
|
+
existsSync as existsSync11,
|
|
42691
42732
|
mkdirSync as mkdirSync5,
|
|
42692
|
-
mkdtempSync,
|
|
42693
|
-
readFileSync as
|
|
42694
|
-
readdirSync as
|
|
42733
|
+
mkdtempSync as mkdtempSync2,
|
|
42734
|
+
readFileSync as readFileSync8,
|
|
42735
|
+
readdirSync as readdirSync8,
|
|
42695
42736
|
renameSync as renameSync3,
|
|
42696
42737
|
rmSync as rmSync3,
|
|
42697
|
-
statSync as
|
|
42738
|
+
statSync as statSync8,
|
|
42698
42739
|
writeFileSync as writeFileSync5
|
|
42699
42740
|
} from "fs";
|
|
42700
42741
|
import { homedir as homedir3 } from "os";
|
|
42701
|
-
import { basename as basename3, dirname as dirname4, join as
|
|
42742
|
+
import { basename as basename3, dirname as dirname4, join as join11 } from "path";
|
|
42702
42743
|
function isSyncAgent(value) {
|
|
42703
42744
|
return SYNC_AGENTS.includes(value);
|
|
42704
42745
|
}
|
|
@@ -42713,9 +42754,9 @@ function resolveSyncAgents(arg) {
|
|
|
42713
42754
|
function agentGlobalSkillsDir(agent, homeDir = homedir3()) {
|
|
42714
42755
|
switch (agent) {
|
|
42715
42756
|
case "opencode":
|
|
42716
|
-
return
|
|
42757
|
+
return join11(homeDir, ".config", "opencode", "skills");
|
|
42717
42758
|
default:
|
|
42718
|
-
return
|
|
42759
|
+
return join11(homeDir, `.${agent}`, "skills");
|
|
42719
42760
|
}
|
|
42720
42761
|
}
|
|
42721
42762
|
function adaptSkillMdForAgent(skillMd, agent) {
|
|
@@ -42773,8 +42814,8 @@ function resolveSyncCorpus(options = {}) {
|
|
|
42773
42814
|
function packageSourceRoots(source) {
|
|
42774
42815
|
const roots = [];
|
|
42775
42816
|
for (const sub of ["skills"]) {
|
|
42776
|
-
const candidate =
|
|
42777
|
-
if (
|
|
42817
|
+
const candidate = join11(source, sub);
|
|
42818
|
+
if (existsSync11(candidate) && isDirectory(candidate))
|
|
42778
42819
|
roots.push(candidate);
|
|
42779
42820
|
}
|
|
42780
42821
|
if (roots.length > 0)
|
|
@@ -42784,20 +42825,20 @@ function packageSourceRoots(source) {
|
|
|
42784
42825
|
function containsSkillDirectories(path) {
|
|
42785
42826
|
let entries;
|
|
42786
42827
|
try {
|
|
42787
|
-
entries =
|
|
42828
|
+
entries = readdirSync8(path);
|
|
42788
42829
|
} catch {
|
|
42789
42830
|
return false;
|
|
42790
42831
|
}
|
|
42791
42832
|
return entries.some((entry) => {
|
|
42792
|
-
const candidate =
|
|
42833
|
+
const candidate = join11(path, entry);
|
|
42793
42834
|
if (!isDirectory(candidate))
|
|
42794
42835
|
return false;
|
|
42795
|
-
return
|
|
42836
|
+
return existsSync11(join11(candidate, "SKILL.md")) || existsSync11(join11(candidate, "skill.json")) || existsSync11(join11(candidate, "package.json"));
|
|
42796
42837
|
});
|
|
42797
42838
|
}
|
|
42798
42839
|
function isDirectory(path) {
|
|
42799
42840
|
try {
|
|
42800
|
-
return
|
|
42841
|
+
return statSync8(path).isDirectory();
|
|
42801
42842
|
} catch {
|
|
42802
42843
|
return false;
|
|
42803
42844
|
}
|
|
@@ -42831,7 +42872,7 @@ function syncSkillsToAgents(options = {}) {
|
|
|
42831
42872
|
actions.push({
|
|
42832
42873
|
skill: name,
|
|
42833
42874
|
agent,
|
|
42834
|
-
path:
|
|
42875
|
+
path: join11(agentGlobalSkillsDir(agent, homeDir), name, "SKILL.md"),
|
|
42835
42876
|
action: "skip",
|
|
42836
42877
|
reason: "not found in this machine's corpus"
|
|
42837
42878
|
});
|
|
@@ -42841,7 +42882,7 @@ function syncSkillsToAgents(options = {}) {
|
|
|
42841
42882
|
}
|
|
42842
42883
|
for (const skill of targets) {
|
|
42843
42884
|
const manifest = readPortableSkillManifest(skill.path, skill.name);
|
|
42844
|
-
const kind = manifest.kind
|
|
42885
|
+
const kind = manifest.kind;
|
|
42845
42886
|
const sourceMd = sourceSkillMd(skill.path, skill.name, manifest.description, kind, source === "source");
|
|
42846
42887
|
for (const agent of agents) {
|
|
42847
42888
|
const adapted = adaptSkillMdForAgent(sourceMd, agent);
|
|
@@ -42861,7 +42902,7 @@ function syncSkillsToAgents(options = {}) {
|
|
|
42861
42902
|
}
|
|
42862
42903
|
function writeManagedAgentSkill(params) {
|
|
42863
42904
|
const homeDir = params.homeDir ?? homedir3();
|
|
42864
|
-
const dir =
|
|
42905
|
+
const dir = join11(agentGlobalSkillsDir(params.agent, homeDir), params.skill);
|
|
42865
42906
|
const result2 = writeManagedSkillDir(dir, params.skillMd, {
|
|
42866
42907
|
skill: params.skill,
|
|
42867
42908
|
source: params.source,
|
|
@@ -42878,11 +42919,11 @@ function writeManagedAgentSkill(params) {
|
|
|
42878
42919
|
};
|
|
42879
42920
|
}
|
|
42880
42921
|
function writeManagedSkillDir(dir, skillMd, options) {
|
|
42881
|
-
const skillMdPath =
|
|
42882
|
-
const markerPath =
|
|
42883
|
-
const dirExists =
|
|
42884
|
-
const managed =
|
|
42885
|
-
const hasSkillMd =
|
|
42922
|
+
const skillMdPath = join11(dir, "SKILL.md");
|
|
42923
|
+
const markerPath = join11(dir, SYNC_MARKER_FILE);
|
|
42924
|
+
const dirExists = existsSync11(dir);
|
|
42925
|
+
const managed = existsSync11(markerPath);
|
|
42926
|
+
const hasSkillMd = existsSync11(skillMdPath);
|
|
42886
42927
|
if (dirExists && !managed && !hasSkillMd) {
|
|
42887
42928
|
return {
|
|
42888
42929
|
action: "skip",
|
|
@@ -42900,7 +42941,7 @@ function writeManagedSkillDir(dir, skillMd, options) {
|
|
|
42900
42941
|
if (dirExists && managed && hasSkillMd && !options.force && isPointerSkillMd(skillMd)) {
|
|
42901
42942
|
let existingIsStub = false;
|
|
42902
42943
|
try {
|
|
42903
|
-
existingIsStub = isPointerSkillMd(
|
|
42944
|
+
existingIsStub = isPointerSkillMd(readFileSync8(skillMdPath, "utf-8"));
|
|
42904
42945
|
} catch {
|
|
42905
42946
|
existingIsStub = false;
|
|
42906
42947
|
}
|
|
@@ -42917,11 +42958,11 @@ function writeManagedSkillDir(dir, skillMd, options) {
|
|
|
42917
42958
|
return { action, path: skillMdPath };
|
|
42918
42959
|
const parentDir = dirname4(dir);
|
|
42919
42960
|
mkdirSync5(parentDir, { recursive: true });
|
|
42920
|
-
const transactionDir =
|
|
42921
|
-
const candidateDir =
|
|
42922
|
-
const backupDir =
|
|
42923
|
-
const candidateSkillMdPath =
|
|
42924
|
-
const candidateMarkerPath =
|
|
42961
|
+
const transactionDir = mkdtempSync2(join11(parentDir, `.hasna-skills-write-${basename3(dir)}-`));
|
|
42962
|
+
const candidateDir = join11(transactionDir, "candidate");
|
|
42963
|
+
const backupDir = join11(transactionDir, "backup");
|
|
42964
|
+
const candidateSkillMdPath = join11(candidateDir, "SKILL.md");
|
|
42965
|
+
const candidateMarkerPath = join11(candidateDir, SYNC_MARKER_FILE);
|
|
42925
42966
|
const marker = {
|
|
42926
42967
|
managedBy: SYNC_MARKER_MANAGED_BY,
|
|
42927
42968
|
skill: options.skill,
|
|
@@ -42948,9 +42989,9 @@ function writeManagedSkillDir(dir, skillMd, options) {
|
|
|
42948
42989
|
}
|
|
42949
42990
|
renameDirectory(candidateDir, dir);
|
|
42950
42991
|
} catch (error) {
|
|
42951
|
-
if (originalMoved &&
|
|
42992
|
+
if (originalMoved && existsSync11(backupDir)) {
|
|
42952
42993
|
try {
|
|
42953
|
-
if (
|
|
42994
|
+
if (existsSync11(dir))
|
|
42954
42995
|
rmSync3(dir, { recursive: true, force: true });
|
|
42955
42996
|
renameDirectory(backupDir, dir);
|
|
42956
42997
|
originalMoved = false;
|
|
@@ -42970,10 +43011,10 @@ function writeManagedSkillDir(dir, skillMd, options) {
|
|
|
42970
43011
|
return { action, path: skillMdPath };
|
|
42971
43012
|
}
|
|
42972
43013
|
function sourceSkillMd(skillPath, name, description, kind, preferBundledDocs = false) {
|
|
42973
|
-
if (kind === "instruction" || preferBundledDocs) {
|
|
42974
|
-
const skillMdPath =
|
|
42975
|
-
if (
|
|
42976
|
-
return
|
|
43014
|
+
if (kind === undefined || kind === "instruction" || preferBundledDocs) {
|
|
43015
|
+
const skillMdPath = join11(skillPath, "SKILL.md");
|
|
43016
|
+
if (existsSync11(skillMdPath))
|
|
43017
|
+
return readFileSync8(skillMdPath, "utf-8");
|
|
42977
43018
|
}
|
|
42978
43019
|
return pointerSkillMd(name, description);
|
|
42979
43020
|
}
|
|
@@ -43009,20 +43050,20 @@ function normalizeSkillName(name) {
|
|
|
43009
43050
|
}
|
|
43010
43051
|
|
|
43011
43052
|
// src/lib/project-state.ts
|
|
43012
|
-
import { existsSync as
|
|
43013
|
-
import { join as
|
|
43053
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "fs";
|
|
43054
|
+
import { join as join12 } from "path";
|
|
43014
43055
|
function getProjectStateDir(targetDir = process.cwd()) {
|
|
43015
|
-
return
|
|
43056
|
+
return join12(targetDir, SKILLS_PROJECT_DIR);
|
|
43016
43057
|
}
|
|
43017
43058
|
function getProjectConfigPath(targetDir = process.cwd()) {
|
|
43018
|
-
return
|
|
43059
|
+
return join12(getProjectStateDir(targetDir), PROJECT_CONFIG_FILE);
|
|
43019
43060
|
}
|
|
43020
43061
|
function loadProjectConfig(targetDir = process.cwd()) {
|
|
43021
43062
|
const path = getProjectConfigPath(targetDir);
|
|
43022
|
-
if (!
|
|
43063
|
+
if (!existsSync12(path))
|
|
43023
43064
|
return null;
|
|
43024
43065
|
try {
|
|
43025
|
-
return normalizeProjectConfig(JSON.parse(
|
|
43066
|
+
return normalizeProjectConfig(JSON.parse(readFileSync9(path, "utf-8")));
|
|
43026
43067
|
} catch {
|
|
43027
43068
|
return null;
|
|
43028
43069
|
}
|
|
@@ -43176,44 +43217,44 @@ __export(exports_installer, {
|
|
|
43176
43217
|
AGENT_TARGETS: () => AGENT_TARGETS,
|
|
43177
43218
|
AGENT_LABELS: () => AGENT_LABELS
|
|
43178
43219
|
});
|
|
43179
|
-
import { existsSync as
|
|
43180
|
-
import { dirname as dirname5, join as
|
|
43220
|
+
import { existsSync as existsSync13, readFileSync as readFileSync10, rmSync as rmSync4 } from "fs";
|
|
43221
|
+
import { dirname as dirname5, join as join13 } from "path";
|
|
43181
43222
|
import { homedir as homedir4 } from "os";
|
|
43182
43223
|
import { fileURLToPath } from "url";
|
|
43183
43224
|
function findSkillsDir() {
|
|
43184
43225
|
let dir = __dirname2;
|
|
43185
43226
|
for (let i = 0;i < 5; i++) {
|
|
43186
|
-
const candidate =
|
|
43187
|
-
if (
|
|
43227
|
+
const candidate = join13(dir, "skills");
|
|
43228
|
+
if (existsSync13(candidate) && !dir.includes(".skills"))
|
|
43188
43229
|
return candidate;
|
|
43189
43230
|
dir = dirname5(dir);
|
|
43190
43231
|
}
|
|
43191
|
-
return
|
|
43232
|
+
return join13(__dirname2, "..", "skills");
|
|
43192
43233
|
}
|
|
43193
43234
|
function getSkillPath(name) {
|
|
43194
43235
|
const skillName = normalizeSkillName(getCanonicalSkillName(name));
|
|
43195
43236
|
const portable = findPortableSkill(skillName);
|
|
43196
43237
|
if (portable)
|
|
43197
43238
|
return portable.path;
|
|
43198
|
-
const legacyCustomPath =
|
|
43199
|
-
if (
|
|
43239
|
+
const legacyCustomPath = join13(getDataDir(), "custom", skillName);
|
|
43240
|
+
if (existsSync13(legacyCustomPath))
|
|
43200
43241
|
return legacyCustomPath;
|
|
43201
43242
|
const extensionPath = findExtensionSkillPath(skillName);
|
|
43202
43243
|
if (extensionPath)
|
|
43203
43244
|
return extensionPath;
|
|
43204
|
-
return
|
|
43245
|
+
return join13(SKILLS_DIR, skillName);
|
|
43205
43246
|
}
|
|
43206
43247
|
function getCanonicalSkillName(name) {
|
|
43207
43248
|
return getSkill(name)?.name ?? resolveSkillAlias(normalizeSkillSlug(name));
|
|
43208
43249
|
}
|
|
43209
43250
|
function skillExists(name) {
|
|
43210
|
-
return
|
|
43251
|
+
return existsSync13(getSkillPath(name));
|
|
43211
43252
|
}
|
|
43212
43253
|
function installSkill(name, options = {}) {
|
|
43213
43254
|
const { targetDir = process.cwd(), overwrite = false } = options;
|
|
43214
43255
|
const canonicalName = getCanonicalSkillName(name);
|
|
43215
43256
|
const skillName = normalizeSkillName(canonicalName);
|
|
43216
|
-
if (!
|
|
43257
|
+
if (!existsSync13(getSkillPath(name))) {
|
|
43217
43258
|
const knownOfficial = Boolean(getSkill(name));
|
|
43218
43259
|
return {
|
|
43219
43260
|
skill: canonicalName,
|
|
@@ -43263,7 +43304,7 @@ function installRemoteSkill(skill, options = {}) {
|
|
|
43263
43304
|
}
|
|
43264
43305
|
function installSkillSource(name, _options = {}) {
|
|
43265
43306
|
const canonicalName = getCanonicalSkillName(name);
|
|
43266
|
-
if (!
|
|
43307
|
+
if (!existsSync13(getSkillPath(name))) {
|
|
43267
43308
|
return { skill: canonicalName, success: false, error: `Skill '${name}' not found`, mode: "source" };
|
|
43268
43309
|
}
|
|
43269
43310
|
return {
|
|
@@ -43284,12 +43325,12 @@ function installSkillManifest(manifest, _options = {}) {
|
|
|
43284
43325
|
}
|
|
43285
43326
|
function createLocalSkillManifest(name, generateSkillMd) {
|
|
43286
43327
|
const sourcePath = getSkillPath(name);
|
|
43287
|
-
if (!
|
|
43328
|
+
if (!existsSync13(sourcePath))
|
|
43288
43329
|
return null;
|
|
43289
43330
|
let skillMd = "";
|
|
43290
|
-
const skillMdPath =
|
|
43291
|
-
if (
|
|
43292
|
-
skillMd =
|
|
43331
|
+
const skillMdPath = join13(sourcePath, "SKILL.md");
|
|
43332
|
+
if (existsSync13(skillMdPath)) {
|
|
43333
|
+
skillMd = readFileSync10(skillMdPath, "utf-8");
|
|
43293
43334
|
} else if (generateSkillMd) {
|
|
43294
43335
|
skillMd = generateSkillMd(name) ?? "";
|
|
43295
43336
|
} else {
|
|
@@ -43369,20 +43410,20 @@ function getAgentSkillsDir(agent, scope = "global", projectDir) {
|
|
|
43369
43410
|
const base2 = projectDir || process.cwd();
|
|
43370
43411
|
switch (agent) {
|
|
43371
43412
|
case "pi":
|
|
43372
|
-
return scope === "project" ?
|
|
43413
|
+
return scope === "project" ? join13(base2, ".pi", "skills") : join13(homedir4(), ".pi", "agent", "skills");
|
|
43373
43414
|
case "opencode":
|
|
43374
|
-
return scope === "project" ?
|
|
43415
|
+
return scope === "project" ? join13(base2, ".opencode", "skills") : join13(homedir4(), ".config", "opencode", "skills");
|
|
43375
43416
|
default:
|
|
43376
|
-
return scope === "project" ?
|
|
43417
|
+
return scope === "project" ? join13(base2, `.${agent}`, "skills") : join13(homedir4(), `.${agent}`, "skills");
|
|
43377
43418
|
}
|
|
43378
43419
|
}
|
|
43379
43420
|
function getAgentSkillPath(name, agent, scope = "global", projectDir) {
|
|
43380
43421
|
const skillName = normalizeSkillName(getCanonicalSkillName(name));
|
|
43381
|
-
return
|
|
43422
|
+
return join13(getAgentSkillsDir(agent, scope, projectDir), skillName);
|
|
43382
43423
|
}
|
|
43383
43424
|
function installSkillForAgent(name, options, generateSkillMd) {
|
|
43384
43425
|
const canonicalName = getCanonicalSkillName(name);
|
|
43385
|
-
if (!
|
|
43426
|
+
if (!existsSync13(getSkillPath(name))) {
|
|
43386
43427
|
return { skill: canonicalName, success: false, error: `Skill '${name}' not found` };
|
|
43387
43428
|
}
|
|
43388
43429
|
const scope = options.scope ?? "global";
|
|
@@ -43406,16 +43447,16 @@ function removeSkillForAgent(name, options) {
|
|
|
43406
43447
|
const canonicalName = getCanonicalSkillName(name);
|
|
43407
43448
|
const scope = options.scope ?? "global";
|
|
43408
43449
|
const dir = getAgentSkillPath(canonicalName, options.agent, scope, options.projectDir);
|
|
43409
|
-
if (!
|
|
43450
|
+
if (!existsSync13(join13(dir, SYNC_MARKER_FILE)))
|
|
43410
43451
|
return false;
|
|
43411
43452
|
rmSync4(dir, { recursive: true, force: true });
|
|
43412
43453
|
return true;
|
|
43413
43454
|
}
|
|
43414
43455
|
function resolveAgentSkillMd(name, generateSkillMd) {
|
|
43415
43456
|
const sourcePath = getSkillPath(name);
|
|
43416
|
-
const skillMdPath =
|
|
43417
|
-
if (
|
|
43418
|
-
return
|
|
43457
|
+
const skillMdPath = join13(sourcePath, "SKILL.md");
|
|
43458
|
+
if (existsSync13(skillMdPath))
|
|
43459
|
+
return readFileSync10(skillMdPath, "utf-8");
|
|
43419
43460
|
if (generateSkillMd)
|
|
43420
43461
|
return generateSkillMd(name);
|
|
43421
43462
|
return generateMinimalSkillMd(name);
|
|
@@ -43433,7 +43474,7 @@ function warnMissingDependencies(name, targetDir) {
|
|
|
43433
43474
|
}
|
|
43434
43475
|
function generateMinimalSkillMd(name) {
|
|
43435
43476
|
const sourcePath = getSkillPath(name);
|
|
43436
|
-
if (!
|
|
43477
|
+
if (!existsSync13(sourcePath))
|
|
43437
43478
|
return null;
|
|
43438
43479
|
const canonicalName = getCanonicalSkillName(name);
|
|
43439
43480
|
const meta = getSkill(canonicalName);
|
|
@@ -43448,7 +43489,7 @@ function generateMinimalSkillMd(name) {
|
|
|
43448
43489
|
"---",
|
|
43449
43490
|
""
|
|
43450
43491
|
].filter(Boolean);
|
|
43451
|
-
const fallbackDoc = readFileIfExists(
|
|
43492
|
+
const fallbackDoc = readFileIfExists(join13(sourcePath, "README.md")) || readFileIfExists(join13(sourcePath, "CLAUDE.md"));
|
|
43452
43493
|
if (fallbackDoc)
|
|
43453
43494
|
return `${frontmatter.join(`
|
|
43454
43495
|
`)}${fallbackDoc.trim()}
|
|
@@ -43467,18 +43508,18 @@ skills run ${canonicalName}
|
|
|
43467
43508
|
`;
|
|
43468
43509
|
}
|
|
43469
43510
|
function readBundledSkillVersion(name) {
|
|
43470
|
-
const pkgPath =
|
|
43471
|
-
if (!
|
|
43511
|
+
const pkgPath = join13(getSkillPath(name), "package.json");
|
|
43512
|
+
if (!existsSync13(pkgPath))
|
|
43472
43513
|
return "unknown";
|
|
43473
43514
|
try {
|
|
43474
|
-
const pkg = JSON.parse(
|
|
43515
|
+
const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
|
|
43475
43516
|
return pkg.version || "unknown";
|
|
43476
43517
|
} catch {
|
|
43477
43518
|
return "unknown";
|
|
43478
43519
|
}
|
|
43479
43520
|
}
|
|
43480
43521
|
function readFileIfExists(path) {
|
|
43481
|
-
return
|
|
43522
|
+
return existsSync13(path) ? readFileSync10(path, "utf-8") : null;
|
|
43482
43523
|
}
|
|
43483
43524
|
function loadProjectConfigCompat(targetDir) {
|
|
43484
43525
|
return loadProjectConfig(targetDir);
|
|
@@ -47597,24 +47638,24 @@ __export(exports_auth_store, {
|
|
|
47597
47638
|
getApiKey: () => getApiKey,
|
|
47598
47639
|
clearAuthConfig: () => clearAuthConfig
|
|
47599
47640
|
});
|
|
47600
|
-
import { existsSync as
|
|
47601
|
-
import { dirname as dirname6, join as
|
|
47641
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync7, readFileSync as readFileSync11, writeFileSync as writeFileSync7, unlinkSync } from "fs";
|
|
47642
|
+
import { dirname as dirname6, join as join14 } from "path";
|
|
47602
47643
|
import { homedir as homedir5 } from "os";
|
|
47603
47644
|
function getAuthFilePath() {
|
|
47604
|
-
return
|
|
47645
|
+
return join14(getDataDir(), "auth.json");
|
|
47605
47646
|
}
|
|
47606
47647
|
function getAuthFilePathReadOnly() {
|
|
47607
|
-
return
|
|
47648
|
+
return join14(getDataDirReadOnly(), "auth.json");
|
|
47608
47649
|
}
|
|
47609
47650
|
function legacyAuthFilePath() {
|
|
47610
|
-
return
|
|
47651
|
+
return join14(process.env["HOME"] || process.env["USERPROFILE"] || homedir5(), ".skills", "auth.json");
|
|
47611
47652
|
}
|
|
47612
47653
|
function getAuthConfig() {
|
|
47613
47654
|
if (cachedConfig !== undefined)
|
|
47614
47655
|
return cachedConfig;
|
|
47615
47656
|
try {
|
|
47616
|
-
const file =
|
|
47617
|
-
const raw =
|
|
47657
|
+
const file = existsSync14(getAuthFilePath()) ? getAuthFilePath() : legacyAuthFilePath();
|
|
47658
|
+
const raw = readFileSync11(file, "utf-8");
|
|
47618
47659
|
const config = JSON.parse(raw);
|
|
47619
47660
|
if (!config.apiKey) {
|
|
47620
47661
|
cachedConfig = null;
|
|
@@ -47652,8 +47693,8 @@ function getApiKey() {
|
|
|
47652
47693
|
}
|
|
47653
47694
|
function getAuthConfigReadOnly() {
|
|
47654
47695
|
try {
|
|
47655
|
-
const file =
|
|
47656
|
-
const raw =
|
|
47696
|
+
const file = existsSync14(getAuthFilePathReadOnly()) ? getAuthFilePathReadOnly() : legacyAuthFilePath();
|
|
47697
|
+
const raw = readFileSync11(file, "utf-8");
|
|
47657
47698
|
const config = JSON.parse(raw);
|
|
47658
47699
|
if (!config.apiKey)
|
|
47659
47700
|
return null;
|
|
@@ -48545,28 +48586,28 @@ __export(exports_skillinfo, {
|
|
|
48545
48586
|
generateEnvExample: () => generateEnvExample,
|
|
48546
48587
|
detectProjectSkills: () => detectProjectSkills
|
|
48547
48588
|
});
|
|
48548
|
-
import { existsSync as
|
|
48549
|
-
import { join as
|
|
48589
|
+
import { existsSync as existsSync15, readFileSync as readFileSync12 } from "fs";
|
|
48590
|
+
import { join as join15 } from "path";
|
|
48550
48591
|
function isInstructionSkillDir(skillPath, meta) {
|
|
48551
48592
|
if (meta?.kind === "instruction")
|
|
48552
48593
|
return true;
|
|
48553
|
-
const skillMdPath =
|
|
48554
|
-
if (!
|
|
48594
|
+
const skillMdPath = join15(skillPath, "SKILL.md");
|
|
48595
|
+
if (!existsSync15(skillMdPath))
|
|
48555
48596
|
return false;
|
|
48556
48597
|
try {
|
|
48557
|
-
return parseSkillFrontmatter(
|
|
48598
|
+
return parseSkillFrontmatter(readFileSync12(skillMdPath, "utf-8"))?.kind === "instruction";
|
|
48558
48599
|
} catch {
|
|
48559
48600
|
return false;
|
|
48560
48601
|
}
|
|
48561
48602
|
}
|
|
48562
48603
|
function getSkillDocs(name) {
|
|
48563
48604
|
const skillPath = getSkillPath(name);
|
|
48564
|
-
if (!
|
|
48605
|
+
if (!existsSync15(skillPath))
|
|
48565
48606
|
return null;
|
|
48566
48607
|
return {
|
|
48567
|
-
skillMd: readIfExists(
|
|
48568
|
-
readme: readIfExists(
|
|
48569
|
-
claudeMd: readIfExists(
|
|
48608
|
+
skillMd: readIfExists(join15(skillPath, "SKILL.md")),
|
|
48609
|
+
readme: readIfExists(join15(skillPath, "README.md")),
|
|
48610
|
+
claudeMd: readIfExists(join15(skillPath, "CLAUDE.md"))
|
|
48570
48611
|
};
|
|
48571
48612
|
}
|
|
48572
48613
|
function getSkillBestDoc(name) {
|
|
@@ -48577,11 +48618,11 @@ function getSkillBestDoc(name) {
|
|
|
48577
48618
|
}
|
|
48578
48619
|
function getSkillRequirements(name) {
|
|
48579
48620
|
const skillPath = getSkillPath(name);
|
|
48580
|
-
if (!
|
|
48621
|
+
if (!existsSync15(skillPath))
|
|
48581
48622
|
return null;
|
|
48582
48623
|
const texts = [];
|
|
48583
48624
|
for (const file of ["SKILL.md", "README.md", "CLAUDE.md", ".env.example", ".env.local.example"]) {
|
|
48584
|
-
const content = readIfExists(
|
|
48625
|
+
const content = readIfExists(join15(skillPath, file));
|
|
48585
48626
|
if (content)
|
|
48586
48627
|
texts.push(content);
|
|
48587
48628
|
}
|
|
@@ -48620,10 +48661,10 @@ function getSkillRequirements(name) {
|
|
|
48620
48661
|
const skillName = normalizeSkillName(name);
|
|
48621
48662
|
let cliCommand = `skills run ${skillName}`;
|
|
48622
48663
|
let dependencies = {};
|
|
48623
|
-
const pkgPath =
|
|
48624
|
-
if (
|
|
48664
|
+
const pkgPath = join15(skillPath, "package.json");
|
|
48665
|
+
if (existsSync15(pkgPath)) {
|
|
48625
48666
|
try {
|
|
48626
|
-
const pkg = JSON.parse(
|
|
48667
|
+
const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
|
|
48627
48668
|
dependencies = pkg.dependencies || {};
|
|
48628
48669
|
} catch {}
|
|
48629
48670
|
}
|
|
@@ -48640,9 +48681,9 @@ function isHostedPremiumSkill(skillName, meta) {
|
|
|
48640
48681
|
function isPackageResolvable(pkgName, fromDir) {
|
|
48641
48682
|
let dir = fromDir;
|
|
48642
48683
|
while (true) {
|
|
48643
|
-
if (
|
|
48684
|
+
if (existsSync15(join15(dir, "node_modules", pkgName, "package.json")))
|
|
48644
48685
|
return true;
|
|
48645
|
-
const parent =
|
|
48686
|
+
const parent = join15(dir, "..");
|
|
48646
48687
|
if (parent === dir)
|
|
48647
48688
|
return false;
|
|
48648
48689
|
dir = parent;
|
|
@@ -48662,7 +48703,7 @@ async function runSkill(name, args, options = {}) {
|
|
|
48662
48703
|
const meta = getSkill(name);
|
|
48663
48704
|
const canonicalName = meta?.name ?? name;
|
|
48664
48705
|
const skillPath = getSkillPath(canonicalName);
|
|
48665
|
-
if (!
|
|
48706
|
+
if (!existsSync15(skillPath)) {
|
|
48666
48707
|
return { exitCode: 1, error: `Skill '${name}' not found` };
|
|
48667
48708
|
}
|
|
48668
48709
|
if (isInstructionSkillDir(skillPath, meta)) {
|
|
@@ -48671,13 +48712,13 @@ async function runSkill(name, args, options = {}) {
|
|
|
48671
48712
|
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
48713
|
};
|
|
48673
48714
|
}
|
|
48674
|
-
const pkgPath =
|
|
48675
|
-
if (!
|
|
48715
|
+
const pkgPath = join15(skillPath, "package.json");
|
|
48716
|
+
if (!existsSync15(pkgPath)) {
|
|
48676
48717
|
return { exitCode: 1, error: `No package.json in skill '${name}'` };
|
|
48677
48718
|
}
|
|
48678
48719
|
let entryPoint;
|
|
48679
48720
|
try {
|
|
48680
|
-
const pkg = JSON.parse(
|
|
48721
|
+
const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
|
|
48681
48722
|
if (pkg.bin) {
|
|
48682
48723
|
const binValues = Object.values(pkg.bin);
|
|
48683
48724
|
entryPoint = binValues[0];
|
|
@@ -48691,12 +48732,12 @@ async function runSkill(name, args, options = {}) {
|
|
|
48691
48732
|
} catch {
|
|
48692
48733
|
return { exitCode: 1, error: `Failed to parse package.json for skill '${name}'` };
|
|
48693
48734
|
}
|
|
48694
|
-
const entryPath =
|
|
48695
|
-
if (!
|
|
48735
|
+
const entryPath = join15(skillPath, entryPoint);
|
|
48736
|
+
if (!existsSync15(entryPath)) {
|
|
48696
48737
|
return { exitCode: 1, error: `Entry point '${entryPoint}' not found in skill '${name}'` };
|
|
48697
48738
|
}
|
|
48698
|
-
const nodeModules =
|
|
48699
|
-
if (!
|
|
48739
|
+
const nodeModules = join15(skillPath, "node_modules");
|
|
48740
|
+
if (!existsSync15(nodeModules)) {
|
|
48700
48741
|
const install = Bun.spawn(["bun", "install", "--no-save"], {
|
|
48701
48742
|
cwd: skillPath,
|
|
48702
48743
|
stdout: "pipe",
|
|
@@ -48723,15 +48764,15 @@ async function runSkill(name, args, options = {}) {
|
|
|
48723
48764
|
return { exitCode };
|
|
48724
48765
|
}
|
|
48725
48766
|
function detectProjectSkills(cwd2 = process.cwd()) {
|
|
48726
|
-
const pkgPath =
|
|
48727
|
-
if (!
|
|
48767
|
+
const pkgPath = join15(cwd2, "package.json");
|
|
48768
|
+
if (!existsSync15(pkgPath)) {
|
|
48728
48769
|
const alwaysRecommend = ["market-research-report", "repo-onboarding-report", "blog-article"];
|
|
48729
48770
|
const recommended2 = alwaysRecommend.map((name) => loadRegistry().find((s) => s.name === name)).filter((s) => s !== undefined);
|
|
48730
48771
|
return { detected: [], recommended: recommended2 };
|
|
48731
48772
|
}
|
|
48732
48773
|
let pkg;
|
|
48733
48774
|
try {
|
|
48734
|
-
pkg = JSON.parse(
|
|
48775
|
+
pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
|
|
48735
48776
|
} catch {
|
|
48736
48777
|
const alwaysRecommend = ["market-research-report", "repo-onboarding-report", "blog-article"];
|
|
48737
48778
|
const recommended2 = alwaysRecommend.map((name) => loadRegistry().find((s) => s.name === name)).filter((s) => s !== undefined);
|
|
@@ -48851,7 +48892,7 @@ function generateSkillMd(name) {
|
|
|
48851
48892
|
if (!meta)
|
|
48852
48893
|
return null;
|
|
48853
48894
|
const skillPath = getSkillPath(name);
|
|
48854
|
-
if (!
|
|
48895
|
+
if (!existsSync15(skillPath))
|
|
48855
48896
|
return null;
|
|
48856
48897
|
const frontmatter = [
|
|
48857
48898
|
"---",
|
|
@@ -48860,13 +48901,13 @@ function generateSkillMd(name) {
|
|
|
48860
48901
|
"---"
|
|
48861
48902
|
].join(`
|
|
48862
48903
|
`);
|
|
48863
|
-
const readme = readIfExists(
|
|
48864
|
-
const claudeMd = readIfExists(
|
|
48904
|
+
const readme = readIfExists(join15(skillPath, "README.md"));
|
|
48905
|
+
const claudeMd = readIfExists(join15(skillPath, "CLAUDE.md"));
|
|
48865
48906
|
let cliCommand = null;
|
|
48866
|
-
const pkgPath =
|
|
48867
|
-
if (
|
|
48907
|
+
const pkgPath = join15(skillPath, "package.json");
|
|
48908
|
+
if (existsSync15(pkgPath)) {
|
|
48868
48909
|
try {
|
|
48869
|
-
const pkg = JSON.parse(
|
|
48910
|
+
const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
|
|
48870
48911
|
if (pkg.bin) {
|
|
48871
48912
|
const binKeys = Object.keys(pkg.bin);
|
|
48872
48913
|
if (binKeys.length > 0)
|
|
@@ -48939,8 +48980,8 @@ function extractEnvVars(text) {
|
|
|
48939
48980
|
}
|
|
48940
48981
|
function readIfExists(path) {
|
|
48941
48982
|
try {
|
|
48942
|
-
if (
|
|
48943
|
-
return
|
|
48983
|
+
if (existsSync15(path)) {
|
|
48984
|
+
return readFileSync12(path, "utf-8");
|
|
48944
48985
|
}
|
|
48945
48986
|
} catch {}
|
|
48946
48987
|
return null;
|
|
@@ -48975,8 +49016,8 @@ var exports_introspect = {};
|
|
|
48975
49016
|
__export(exports_introspect, {
|
|
48976
49017
|
registerIntrospect: () => registerIntrospect
|
|
48977
49018
|
});
|
|
48978
|
-
import { existsSync as
|
|
48979
|
-
import { join as
|
|
49019
|
+
import { existsSync as existsSync16, readFileSync as readFileSync13 } from "fs";
|
|
49020
|
+
import { join as join16 } from "path";
|
|
48980
49021
|
import { execSync } from "child_process";
|
|
48981
49022
|
function registerIntrospect(parent) {
|
|
48982
49023
|
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 +49238,36 @@ function handleDiff(name, options) {
|
|
|
49197
49238
|
const bare = name;
|
|
49198
49239
|
const normalized = normalizePortableSkillName(bare);
|
|
49199
49240
|
const sourcePath = getSkillPath(bare);
|
|
49200
|
-
const canonicalDir =
|
|
49201
|
-
const canonicalSkillMd =
|
|
49241
|
+
const canonicalDir = join16(resolveCorpusRoot(), normalized);
|
|
49242
|
+
const canonicalSkillMd = join16(canonicalDir, "SKILL.md");
|
|
49202
49243
|
const canonical = {
|
|
49203
|
-
present:
|
|
49244
|
+
present: existsSync16(canonicalSkillMd),
|
|
49204
49245
|
path: canonicalDir,
|
|
49205
|
-
...
|
|
49206
|
-
...
|
|
49246
|
+
...existsSync16(canonicalSkillMd) ? { hash: hashSkillMarkdownFile(canonicalSkillMd) } : {},
|
|
49247
|
+
...existsSync16(canonicalSkillMd) ? { stub: isPointerSkillMd(readFileSync13(canonicalSkillMd, "utf-8")) } : {}
|
|
49207
49248
|
};
|
|
49208
49249
|
const pinned = getInstalledSkills().includes(bare);
|
|
49209
49250
|
const installMeta = getInstallMeta();
|
|
49210
49251
|
const installedVersion = installMeta.skills[bare]?.version ?? "unknown";
|
|
49211
|
-
const registryPkgPath =
|
|
49252
|
+
const registryPkgPath = join16(sourcePath, "package.json");
|
|
49212
49253
|
let registryVersion = "unknown";
|
|
49213
|
-
if (
|
|
49254
|
+
if (existsSync16(registryPkgPath)) {
|
|
49214
49255
|
try {
|
|
49215
|
-
registryVersion = JSON.parse(
|
|
49256
|
+
registryVersion = JSON.parse(readFileSync13(registryPkgPath, "utf-8")).version || "unknown";
|
|
49216
49257
|
} catch {}
|
|
49217
49258
|
}
|
|
49218
49259
|
const upToDate = installedVersion === registryVersion;
|
|
49219
49260
|
const homes = [];
|
|
49220
49261
|
for (const agent of SYNC_AGENTS) {
|
|
49221
|
-
const dir =
|
|
49222
|
-
const present =
|
|
49223
|
-
const managed =
|
|
49224
|
-
const skillMdPath =
|
|
49225
|
-
const hash = present &&
|
|
49262
|
+
const dir = join16(agentGlobalSkillsDir(agent), normalized);
|
|
49263
|
+
const present = existsSync16(dir);
|
|
49264
|
+
const managed = existsSync16(join16(dir, SYNC_MARKER_FILE));
|
|
49265
|
+
const skillMdPath = join16(dir, "SKILL.md");
|
|
49266
|
+
const hash = present && existsSync16(skillMdPath) ? hashSkillMarkdownFile(skillMdPath) : undefined;
|
|
49226
49267
|
let stub;
|
|
49227
|
-
if (present &&
|
|
49268
|
+
if (present && existsSync16(skillMdPath)) {
|
|
49228
49269
|
try {
|
|
49229
|
-
stub = isPointerSkillMd(
|
|
49270
|
+
stub = isPointerSkillMd(readFileSync13(skillMdPath, "utf-8"));
|
|
49230
49271
|
} catch {
|
|
49231
49272
|
stub = undefined;
|
|
49232
49273
|
}
|
|
@@ -49759,8 +49800,8 @@ var exports_init = {};
|
|
|
49759
49800
|
__export(exports_init, {
|
|
49760
49801
|
registerSetup: () => registerSetup
|
|
49761
49802
|
});
|
|
49762
|
-
import { existsSync as
|
|
49763
|
-
import { join as
|
|
49803
|
+
import { existsSync as existsSync17, readFileSync as readFileSync14, writeFileSync as writeFileSync8, appendFileSync } from "fs";
|
|
49804
|
+
import { join as join17 } from "path";
|
|
49764
49805
|
function registerSetup(parent) {
|
|
49765
49806
|
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
49807
|
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 +49885,7 @@ Use: skills render`));
|
|
|
49844
49885
|
lines.push(`# Used by: ${skills.join(", ")}`);
|
|
49845
49886
|
lines.push(`${envVar}=`);
|
|
49846
49887
|
}
|
|
49847
|
-
writeFileSync8(
|
|
49888
|
+
writeFileSync8(join17(cwd2, ".env.example"), lines.join(`
|
|
49848
49889
|
`) + `
|
|
49849
49890
|
`);
|
|
49850
49891
|
envVarCount = envMap.size;
|
|
@@ -49852,9 +49893,9 @@ Use: skills render`));
|
|
|
49852
49893
|
console.log(source_default.green(`\u2713 Generated .env.example (${envVarCount} variables from ${installed.length} skills)`));
|
|
49853
49894
|
} else if (!options.json)
|
|
49854
49895
|
console.log(source_default.dim(" No environment variables detected across pinned skills"));
|
|
49855
|
-
const gitignorePath =
|
|
49896
|
+
const gitignorePath = join17(cwd2, ".gitignore");
|
|
49856
49897
|
const gitignoreEntries = [".skills/runs/", ".skills/exports/", ".skills/tmp/"];
|
|
49857
|
-
let gitignoreContent =
|
|
49898
|
+
let gitignoreContent = existsSync17(gitignorePath) ? readFileSync14(gitignorePath, "utf-8") : "";
|
|
49858
49899
|
let gitignoreUpdated = false;
|
|
49859
49900
|
const missingEntries = gitignoreEntries.filter((entry) => !gitignoreContent.includes(entry));
|
|
49860
49901
|
if (missingEntries.length > 0) {
|
|
@@ -49900,7 +49941,7 @@ async function handleImport(file, options) {
|
|
|
49900
49941
|
if (file === "-")
|
|
49901
49942
|
raw = await new Response(process.stdin).text();
|
|
49902
49943
|
else {
|
|
49903
|
-
if (!
|
|
49944
|
+
if (!existsSync17(file)) {
|
|
49904
49945
|
const error = `File not found: ${file}`;
|
|
49905
49946
|
if (options.json)
|
|
49906
49947
|
console.log(JSON.stringify({ imported: 0, error }));
|
|
@@ -49909,7 +49950,7 @@ async function handleImport(file, options) {
|
|
|
49909
49950
|
process.exitCode = 1;
|
|
49910
49951
|
return;
|
|
49911
49952
|
}
|
|
49912
|
-
raw =
|
|
49953
|
+
raw = readFileSync14(file, "utf-8");
|
|
49913
49954
|
}
|
|
49914
49955
|
} catch (err) {
|
|
49915
49956
|
const error = `Failed to read file: ${err.message}`;
|
|
@@ -50006,24 +50047,24 @@ var init_init = __esm(() => {
|
|
|
50006
50047
|
});
|
|
50007
50048
|
|
|
50008
50049
|
// src/lib/home-adoption.ts
|
|
50009
|
-
import { existsSync as
|
|
50050
|
+
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
50051
|
import { homedir as homedir6 } from "os";
|
|
50011
|
-
import { join as
|
|
50052
|
+
import { join as join18 } from "path";
|
|
50012
50053
|
function indexCanonicalCorpus(corpusRoot) {
|
|
50013
50054
|
const byName = new Map;
|
|
50014
|
-
if (!
|
|
50055
|
+
if (!existsSync18(corpusRoot))
|
|
50015
50056
|
return byName;
|
|
50016
50057
|
let entries = [];
|
|
50017
50058
|
try {
|
|
50018
|
-
entries =
|
|
50059
|
+
entries = readdirSync9(corpusRoot);
|
|
50019
50060
|
} catch {
|
|
50020
50061
|
return byName;
|
|
50021
50062
|
}
|
|
50022
50063
|
for (const entry of entries.sort()) {
|
|
50023
50064
|
if (entry.startsWith("."))
|
|
50024
50065
|
continue;
|
|
50025
|
-
const skillMd =
|
|
50026
|
-
if (!
|
|
50066
|
+
const skillMd = join18(corpusRoot, entry, "SKILL.md");
|
|
50067
|
+
if (!existsSync18(skillMd))
|
|
50027
50068
|
continue;
|
|
50028
50069
|
try {
|
|
50029
50070
|
byName.set(entry, hashSkillMarkdownFile(skillMd));
|
|
@@ -50039,33 +50080,33 @@ function scanUnmarkedHomes(options = {}) {
|
|
|
50039
50080
|
const scan = { adoptable: [], conflicts: [], unknown: [], managed: 0 };
|
|
50040
50081
|
for (const agent of agents) {
|
|
50041
50082
|
const home = agentGlobalSkillsDir(agent, homeDir);
|
|
50042
|
-
if (!
|
|
50083
|
+
if (!existsSync18(home))
|
|
50043
50084
|
continue;
|
|
50044
50085
|
let entries = [];
|
|
50045
50086
|
try {
|
|
50046
|
-
entries =
|
|
50087
|
+
entries = readdirSync9(home);
|
|
50047
50088
|
} catch {
|
|
50048
50089
|
continue;
|
|
50049
50090
|
}
|
|
50050
50091
|
for (const skill of entries.sort()) {
|
|
50051
50092
|
if (skill.startsWith("."))
|
|
50052
50093
|
continue;
|
|
50053
|
-
const dir =
|
|
50094
|
+
const dir = join18(home, skill);
|
|
50054
50095
|
try {
|
|
50055
|
-
if (!
|
|
50096
|
+
if (!statSync9(dir).isDirectory())
|
|
50056
50097
|
continue;
|
|
50057
50098
|
} catch {
|
|
50058
50099
|
continue;
|
|
50059
50100
|
}
|
|
50060
|
-
if (
|
|
50101
|
+
if (existsSync18(join18(dir, SYNC_MARKER_FILE))) {
|
|
50061
50102
|
scan.managed += 1;
|
|
50062
50103
|
continue;
|
|
50063
50104
|
}
|
|
50064
|
-
const skillMdPath =
|
|
50065
|
-
if (!
|
|
50105
|
+
const skillMdPath = join18(dir, "SKILL.md");
|
|
50106
|
+
if (!existsSync18(skillMdPath))
|
|
50066
50107
|
continue;
|
|
50067
50108
|
const hash = hashSkillMarkdownFile(skillMdPath);
|
|
50068
|
-
const mtime =
|
|
50109
|
+
const mtime = statSync9(skillMdPath).mtime.toISOString();
|
|
50069
50110
|
const entry = { agent, skill, home, path: dir, hash, mtime };
|
|
50070
50111
|
const canonicalHash = index.get(skill);
|
|
50071
50112
|
if (canonicalHash === undefined) {
|
|
@@ -50082,11 +50123,11 @@ function scanUnmarkedHomes(options = {}) {
|
|
|
50082
50123
|
function appendConflictsLedger(appDir, conflicts) {
|
|
50083
50124
|
if (conflicts.length === 0)
|
|
50084
50125
|
return;
|
|
50085
|
-
const ledgerPath =
|
|
50126
|
+
const ledgerPath = join18(appDir, CONFLICTS_LEDGER_FILE);
|
|
50086
50127
|
let ledger = { version: 1, entries: [] };
|
|
50087
|
-
if (
|
|
50128
|
+
if (existsSync18(ledgerPath)) {
|
|
50088
50129
|
try {
|
|
50089
|
-
const parsed = JSON.parse(
|
|
50130
|
+
const parsed = JSON.parse(readFileSync15(ledgerPath, "utf-8"));
|
|
50090
50131
|
if (parsed && typeof parsed === "object" && Array.isArray(parsed.entries)) {
|
|
50091
50132
|
ledger = parsed;
|
|
50092
50133
|
}
|
|
@@ -50102,9 +50143,9 @@ function appendConflictsLedger(appDir, conflicts) {
|
|
|
50102
50143
|
`);
|
|
50103
50144
|
}
|
|
50104
50145
|
function writeRollbackRecord(mode, entries, appDir = getDataDir()) {
|
|
50105
|
-
const dir =
|
|
50146
|
+
const dir = join18(appDir, ROLLBACK_DIRNAME);
|
|
50106
50147
|
mkdirSync8(dir, { recursive: true });
|
|
50107
|
-
const file =
|
|
50148
|
+
const file = join18(dir, `${mode}-${Date.now()}.json`);
|
|
50108
50149
|
const record = { version: 1, mode, timestamp: new Date().toISOString(), entries };
|
|
50109
50150
|
writeFileSync9(file, `${JSON.stringify(record, null, 2)}
|
|
50110
50151
|
`);
|
|
@@ -50115,7 +50156,7 @@ function adoptUnmarkedHomes(options = {}) {
|
|
|
50115
50156
|
if (!options.apply) {
|
|
50116
50157
|
return { ...scan, applied: false };
|
|
50117
50158
|
}
|
|
50118
|
-
const appDir = options.homeDir ?
|
|
50159
|
+
const appDir = options.homeDir ? join18(options.homeDir, ".hasna", "skills") : getDataDir();
|
|
50119
50160
|
const markers = scan.adoptable.map((entry) => {
|
|
50120
50161
|
const marker = {
|
|
50121
50162
|
managedBy: SYNC_MARKER_MANAGED_BY,
|
|
@@ -50123,7 +50164,7 @@ function adoptUnmarkedHomes(options = {}) {
|
|
|
50123
50164
|
source: "adopted",
|
|
50124
50165
|
syncedAt: new Date().toISOString()
|
|
50125
50166
|
};
|
|
50126
|
-
writeFileSync9(
|
|
50167
|
+
writeFileSync9(join18(entry.path, SYNC_MARKER_FILE), `${JSON.stringify(marker, null, 2)}
|
|
50127
50168
|
`);
|
|
50128
50169
|
return { agent: entry.agent, skill: entry.skill, path: entry.path, hash: entry.hash, marker };
|
|
50129
50170
|
});
|
|
@@ -50142,47 +50183,47 @@ function pruneStrayHomes(options = {}) {
|
|
|
50142
50183
|
const candidates = [];
|
|
50143
50184
|
for (const agent of agents) {
|
|
50144
50185
|
const home = agentGlobalSkillsDir(agent, homeDir);
|
|
50145
|
-
if (!
|
|
50186
|
+
if (!existsSync18(home))
|
|
50146
50187
|
continue;
|
|
50147
50188
|
let entries = [];
|
|
50148
50189
|
try {
|
|
50149
|
-
entries =
|
|
50190
|
+
entries = readdirSync9(home);
|
|
50150
50191
|
} catch {
|
|
50151
50192
|
continue;
|
|
50152
50193
|
}
|
|
50153
50194
|
for (const skill of entries.sort()) {
|
|
50154
50195
|
if (skill.startsWith("."))
|
|
50155
50196
|
continue;
|
|
50156
|
-
const dir =
|
|
50197
|
+
const dir = join18(home, skill);
|
|
50157
50198
|
try {
|
|
50158
|
-
if (!
|
|
50199
|
+
if (!statSync9(dir).isDirectory())
|
|
50159
50200
|
continue;
|
|
50160
50201
|
} catch {
|
|
50161
50202
|
continue;
|
|
50162
50203
|
}
|
|
50163
|
-
const markerPath =
|
|
50164
|
-
if (!
|
|
50204
|
+
const markerPath = join18(dir, SYNC_MARKER_FILE);
|
|
50205
|
+
if (!existsSync18(markerPath))
|
|
50165
50206
|
continue;
|
|
50166
50207
|
if (index.has(skill))
|
|
50167
50208
|
continue;
|
|
50168
50209
|
let marker;
|
|
50169
50210
|
try {
|
|
50170
|
-
const parsed = JSON.parse(
|
|
50211
|
+
const parsed = JSON.parse(readFileSync15(markerPath, "utf-8"));
|
|
50171
50212
|
if (!parsed || typeof parsed !== "object" || typeof parsed.managedBy !== "string")
|
|
50172
50213
|
continue;
|
|
50173
50214
|
marker = parsed;
|
|
50174
50215
|
} catch {
|
|
50175
50216
|
continue;
|
|
50176
50217
|
}
|
|
50177
|
-
const skillMdPath =
|
|
50178
|
-
const hash =
|
|
50218
|
+
const skillMdPath = join18(dir, "SKILL.md");
|
|
50219
|
+
const hash = existsSync18(skillMdPath) ? hashSkillMarkdownFile(skillMdPath) : "";
|
|
50179
50220
|
candidates.push({ agent, skill, home, path: dir, hash, marker });
|
|
50180
50221
|
}
|
|
50181
50222
|
}
|
|
50182
50223
|
if (!options.apply) {
|
|
50183
50224
|
return { candidates, pruned: 0, dryRun: true };
|
|
50184
50225
|
}
|
|
50185
|
-
const appDir = options.homeDir ?
|
|
50226
|
+
const appDir = options.homeDir ? join18(options.homeDir, ".hasna", "skills") : getDataDir();
|
|
50186
50227
|
const rollbackFile = writeRollbackRecord("prune", candidates.map(({ agent, skill, path, hash, marker }) => ({ agent, skill, path, hash, marker })), appDir);
|
|
50187
50228
|
for (const candidate of candidates) {
|
|
50188
50229
|
rmSync5(candidate.path, { recursive: true, force: true });
|
|
@@ -50198,9 +50239,9 @@ var init_home_adoption = __esm(() => {
|
|
|
50198
50239
|
});
|
|
50199
50240
|
|
|
50200
50241
|
// src/lib/home-census.ts
|
|
50201
|
-
import { existsSync as
|
|
50242
|
+
import { existsSync as existsSync19, readFileSync as readFileSync16, readdirSync as readdirSync10, statSync as statSync10 } from "fs";
|
|
50202
50243
|
import { homedir as homedir7 } from "os";
|
|
50203
|
-
import { join as
|
|
50244
|
+
import { join as join19 } from "path";
|
|
50204
50245
|
function sortEntries(entries) {
|
|
50205
50246
|
return entries.sort((a, b) => {
|
|
50206
50247
|
const left = `${a.agent}/${a.skill}/${a.kind}`;
|
|
@@ -50219,29 +50260,29 @@ function censusHomeDrift(options = {}) {
|
|
|
50219
50260
|
let homesChecked = 0;
|
|
50220
50261
|
for (const agent of agents) {
|
|
50221
50262
|
const home = agentGlobalSkillsDir(agent, homeDir);
|
|
50222
|
-
if (!
|
|
50263
|
+
if (!existsSync19(home))
|
|
50223
50264
|
continue;
|
|
50224
50265
|
homesChecked += 1;
|
|
50225
50266
|
const present = new Set;
|
|
50226
50267
|
let dirEntries = [];
|
|
50227
50268
|
try {
|
|
50228
|
-
dirEntries =
|
|
50269
|
+
dirEntries = readdirSync10(home);
|
|
50229
50270
|
} catch {
|
|
50230
50271
|
continue;
|
|
50231
50272
|
}
|
|
50232
50273
|
for (const skill of dirEntries.sort()) {
|
|
50233
50274
|
if (skill.startsWith("."))
|
|
50234
50275
|
continue;
|
|
50235
|
-
const dir =
|
|
50276
|
+
const dir = join19(home, skill);
|
|
50236
50277
|
try {
|
|
50237
|
-
if (!
|
|
50278
|
+
if (!statSync10(dir).isDirectory())
|
|
50238
50279
|
continue;
|
|
50239
50280
|
} catch {
|
|
50240
50281
|
continue;
|
|
50241
50282
|
}
|
|
50242
50283
|
present.add(skill);
|
|
50243
|
-
const markerPath =
|
|
50244
|
-
if (!
|
|
50284
|
+
const markerPath = join19(dir, SYNC_MARKER_FILE);
|
|
50285
|
+
if (!existsSync19(markerPath)) {
|
|
50245
50286
|
unmarked += 1;
|
|
50246
50287
|
continue;
|
|
50247
50288
|
}
|
|
@@ -50251,8 +50292,8 @@ function censusHomeDrift(options = {}) {
|
|
|
50251
50292
|
entries.push({ agent, skill, kind: "stray-in-home", path: dir });
|
|
50252
50293
|
continue;
|
|
50253
50294
|
}
|
|
50254
|
-
const skillMdPath =
|
|
50255
|
-
if (!
|
|
50295
|
+
const skillMdPath = join19(dir, "SKILL.md");
|
|
50296
|
+
if (!existsSync19(skillMdPath)) {
|
|
50256
50297
|
entries.push({ agent, skill, kind: "diverged", path: dir, canonicalHash });
|
|
50257
50298
|
continue;
|
|
50258
50299
|
}
|
|
@@ -50260,14 +50301,14 @@ function censusHomeDrift(options = {}) {
|
|
|
50260
50301
|
if (homeHash !== canonicalHash) {
|
|
50261
50302
|
let homeStub;
|
|
50262
50303
|
try {
|
|
50263
|
-
homeStub = isPointerSkillMd(
|
|
50304
|
+
homeStub = isPointerSkillMd(readFileSync16(skillMdPath, "utf-8"));
|
|
50264
50305
|
} catch {
|
|
50265
50306
|
homeStub = undefined;
|
|
50266
50307
|
}
|
|
50267
50308
|
let canonicalStub;
|
|
50268
|
-
const canonicalSkillMd =
|
|
50309
|
+
const canonicalSkillMd = join19(corpusRoot, skill, "SKILL.md");
|
|
50269
50310
|
try {
|
|
50270
|
-
canonicalStub = isPointerSkillMd(
|
|
50311
|
+
canonicalStub = isPointerSkillMd(readFileSync16(canonicalSkillMd, "utf-8"));
|
|
50271
50312
|
} catch {
|
|
50272
50313
|
canonicalStub = undefined;
|
|
50273
50314
|
}
|
|
@@ -50280,7 +50321,7 @@ function censusHomeDrift(options = {}) {
|
|
|
50280
50321
|
agent,
|
|
50281
50322
|
skill: name,
|
|
50282
50323
|
kind: "missing-from-home",
|
|
50283
|
-
path:
|
|
50324
|
+
path: join19(home, name),
|
|
50284
50325
|
canonicalHash
|
|
50285
50326
|
});
|
|
50286
50327
|
}
|
|
@@ -50306,8 +50347,8 @@ var exports_diagnostic = {};
|
|
|
50306
50347
|
__export(exports_diagnostic, {
|
|
50307
50348
|
registerDiagnostic: () => registerDiagnostic
|
|
50308
50349
|
});
|
|
50309
|
-
import { existsSync as
|
|
50310
|
-
import { join as
|
|
50350
|
+
import { existsSync as existsSync20, readFileSync as readFileSync17, readdirSync as readdirSync11, statSync as statSync11, writeFileSync as writeFileSync10 } from "fs";
|
|
50351
|
+
import { join as join20 } from "path";
|
|
50311
50352
|
import { execSync as execSync2 } from "child_process";
|
|
50312
50353
|
function registerDiagnostic(parent) {
|
|
50313
50354
|
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 +50464,7 @@ Skills Test (${results.length} skill${results.length === 1 ? "" : "s"}):
|
|
|
50423
50464
|
}
|
|
50424
50465
|
function handleAuth(name, options) {
|
|
50425
50466
|
const cwd2 = process.cwd();
|
|
50426
|
-
const envFilePath =
|
|
50467
|
+
const envFilePath = join20(cwd2, ".env");
|
|
50427
50468
|
if (options.set) {
|
|
50428
50469
|
const eqIdx = options.set.indexOf("=");
|
|
50429
50470
|
if (eqIdx === -1) {
|
|
@@ -50445,7 +50486,7 @@ function handleAuth(name, options) {
|
|
|
50445
50486
|
process.exitCode = 1;
|
|
50446
50487
|
return;
|
|
50447
50488
|
}
|
|
50448
|
-
let existing =
|
|
50489
|
+
let existing = existsSync20(envFilePath) ? readFileSync17(envFilePath, "utf-8") : "";
|
|
50449
50490
|
const keyPattern = new RegExp(`^${key}=.*$`, "m");
|
|
50450
50491
|
const updated = keyPattern.test(existing) ? existing.replace(keyPattern, `${key}=${value}`) : existing.endsWith(`
|
|
50451
50492
|
`) || existing === "" ? existing + `${key}=${value}
|
|
@@ -50511,11 +50552,11 @@ function handleWhoami(options) {
|
|
|
50511
50552
|
const agentConfigs = [];
|
|
50512
50553
|
for (const agent of AGENT_TARGETS) {
|
|
50513
50554
|
const agentSkillsPath = getAgentSkillsDir(agent, "global");
|
|
50514
|
-
const exists =
|
|
50555
|
+
const exists = existsSync20(agentSkillsPath);
|
|
50515
50556
|
let skillCount = 0;
|
|
50516
50557
|
if (exists)
|
|
50517
50558
|
try {
|
|
50518
|
-
skillCount =
|
|
50559
|
+
skillCount = readdirSync11(agentSkillsPath).filter((f) => !f.startsWith(".") && statSync11(join20(agentSkillsPath, f)).isDirectory()).length;
|
|
50519
50560
|
} catch {}
|
|
50520
50561
|
agentConfigs.push({ agent, label: AGENT_LABELS[agent], path: agentSkillsPath, exists, skillCount });
|
|
50521
50562
|
}
|
|
@@ -50549,11 +50590,11 @@ function handleOutdated(options) {
|
|
|
50549
50590
|
for (const name of installed) {
|
|
50550
50591
|
const installedVersion = meta.skills[name]?.version ?? "unknown";
|
|
50551
50592
|
const registryPath = getSkillPath(name);
|
|
50552
|
-
const registryPkgPath =
|
|
50593
|
+
const registryPkgPath = join20(registryPath, "package.json");
|
|
50553
50594
|
let registryVersion = "unknown";
|
|
50554
|
-
if (
|
|
50595
|
+
if (existsSync20(registryPkgPath))
|
|
50555
50596
|
try {
|
|
50556
|
-
registryVersion = JSON.parse(
|
|
50597
|
+
registryVersion = JSON.parse(readFileSync17(registryPkgPath, "utf-8")).version || "unknown";
|
|
50557
50598
|
} catch {}
|
|
50558
50599
|
if (installedVersion !== registryVersion)
|
|
50559
50600
|
pins.push({ skill: name, installedVersion, registryVersion });
|
|
@@ -50817,20 +50858,20 @@ var init_runs = __esm(() => {
|
|
|
50817
50858
|
|
|
50818
50859
|
// src/lib/run-state.ts
|
|
50819
50860
|
import { createHash as createHash2, randomBytes } from "crypto";
|
|
50820
|
-
import { existsSync as
|
|
50821
|
-
import { extname, join as
|
|
50861
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync9, readFileSync as readFileSync18, readdirSync as readdirSync12, statSync as statSync12, writeFileSync as writeFileSync11 } from "fs";
|
|
50862
|
+
import { extname, join as join21, relative as relative2 } from "path";
|
|
50822
50863
|
function createSkillRun(params, targetDir = process.cwd()) {
|
|
50823
50864
|
const now3 = new Date;
|
|
50824
50865
|
const id = createRunId(now3);
|
|
50825
50866
|
const day = now3.toISOString().slice(0, 10);
|
|
50826
50867
|
const skillName = normalizeSkillName(params.skill);
|
|
50827
50868
|
const root = getProjectStateDir(targetDir);
|
|
50828
|
-
const runDir =
|
|
50829
|
-
const logsDir =
|
|
50830
|
-
const exportDir =
|
|
50869
|
+
const runDir = join21(root, "runs", day, id);
|
|
50870
|
+
const logsDir = join21(runDir, "logs");
|
|
50871
|
+
const exportDir = join21(root, "exports", skillName, id);
|
|
50831
50872
|
mkdirSync9(logsDir, { recursive: true });
|
|
50832
50873
|
mkdirSync9(exportDir, { recursive: true });
|
|
50833
|
-
mkdirSync9(
|
|
50874
|
+
mkdirSync9(join21(root, "tmp"), { recursive: true });
|
|
50834
50875
|
const record = {
|
|
50835
50876
|
id,
|
|
50836
50877
|
skill: skillName,
|
|
@@ -50881,27 +50922,27 @@ function updateSkillRun(context, patch) {
|
|
|
50881
50922
|
return context.record;
|
|
50882
50923
|
}
|
|
50883
50924
|
function writeRunLogs(context, stdout = "", stderr = "") {
|
|
50884
|
-
writeFileSync11(
|
|
50885
|
-
writeFileSync11(
|
|
50925
|
+
writeFileSync11(join21(context.logsDir, "stdout.log"), stdout);
|
|
50926
|
+
writeFileSync11(join21(context.logsDir, "stderr.log"), stderr);
|
|
50886
50927
|
}
|
|
50887
50928
|
function appendRunEvent(context, event, data = {}) {
|
|
50888
50929
|
const line = JSON.stringify({ ts: new Date().toISOString(), event, ...data }) + `
|
|
50889
50930
|
`;
|
|
50890
|
-
const path =
|
|
50891
|
-
const previous =
|
|
50931
|
+
const path = join21(context.runDir, "events.ndjson");
|
|
50932
|
+
const previous = existsSync21(path) ? readFileSync18(path, "utf-8") : "";
|
|
50892
50933
|
writeFileSync11(path, previous + line);
|
|
50893
50934
|
}
|
|
50894
50935
|
function listSkillRuns(targetDir = process.cwd(), limit = 50) {
|
|
50895
|
-
const runsRoot =
|
|
50896
|
-
if (!
|
|
50936
|
+
const runsRoot = join21(getProjectStateDir(targetDir), "runs");
|
|
50937
|
+
if (!existsSync21(runsRoot))
|
|
50897
50938
|
return [];
|
|
50898
50939
|
const records = [];
|
|
50899
|
-
for (const day of
|
|
50900
|
-
const dayDir =
|
|
50901
|
-
if (!
|
|
50940
|
+
for (const day of readdirSync12(runsRoot).sort().reverse()) {
|
|
50941
|
+
const dayDir = join21(runsRoot, day);
|
|
50942
|
+
if (!statSync12(dayDir).isDirectory())
|
|
50902
50943
|
continue;
|
|
50903
|
-
for (const runId of
|
|
50904
|
-
const record = readRunRecord(
|
|
50944
|
+
for (const runId of readdirSync12(dayDir).sort().reverse()) {
|
|
50945
|
+
const record = readRunRecord(join21(dayDir, runId));
|
|
50905
50946
|
if (record)
|
|
50906
50947
|
records.push(record);
|
|
50907
50948
|
if (records.length >= limit)
|
|
@@ -50911,11 +50952,11 @@ function listSkillRuns(targetDir = process.cwd(), limit = 50) {
|
|
|
50911
50952
|
return records;
|
|
50912
50953
|
}
|
|
50913
50954
|
function findSkillRun(runId, targetDir = process.cwd()) {
|
|
50914
|
-
const runsRoot =
|
|
50915
|
-
if (!
|
|
50955
|
+
const runsRoot = join21(getProjectStateDir(targetDir), "runs");
|
|
50956
|
+
if (!existsSync21(runsRoot))
|
|
50916
50957
|
return null;
|
|
50917
|
-
for (const day of
|
|
50918
|
-
const record = readRunRecord(
|
|
50958
|
+
for (const day of readdirSync12(runsRoot)) {
|
|
50959
|
+
const record = readRunRecord(join21(runsRoot, day, runId));
|
|
50919
50960
|
if (record)
|
|
50920
50961
|
return record;
|
|
50921
50962
|
}
|
|
@@ -50932,23 +50973,23 @@ function skillRunEnv(context) {
|
|
|
50932
50973
|
};
|
|
50933
50974
|
}
|
|
50934
50975
|
function getRunExportDir(runId, skill, targetDir = process.cwd()) {
|
|
50935
|
-
return
|
|
50976
|
+
return join21(getProjectStateDir(targetDir), "exports", normalizeSkillName(skill), runId);
|
|
50936
50977
|
}
|
|
50937
50978
|
function writeRunRecord(context) {
|
|
50938
|
-
writeFileSync11(
|
|
50979
|
+
writeFileSync11(join21(context.runDir, "run.json"), JSON.stringify(context.record, null, 2) + `
|
|
50939
50980
|
`);
|
|
50940
50981
|
}
|
|
50941
50982
|
function writeArtifactsManifest(context, artifacts) {
|
|
50942
|
-
writeFileSync11(
|
|
50983
|
+
writeFileSync11(join21(context.runDir, "artifacts.json"), JSON.stringify({ runId: context.record.id, artifacts }, null, 2) + `
|
|
50943
50984
|
`);
|
|
50944
50985
|
}
|
|
50945
50986
|
function collectRunArtifacts(context) {
|
|
50946
|
-
if (!
|
|
50987
|
+
if (!existsSync21(context.exportDir))
|
|
50947
50988
|
return [];
|
|
50948
50989
|
const artifacts = [];
|
|
50949
50990
|
for (const path of walkFiles(context.exportDir)) {
|
|
50950
|
-
const stat =
|
|
50951
|
-
const bytes =
|
|
50991
|
+
const stat = statSync12(path);
|
|
50992
|
+
const bytes = readFileSync18(path);
|
|
50952
50993
|
artifacts.push({
|
|
50953
50994
|
path: toProjectRelative(context.targetDir, path),
|
|
50954
50995
|
mime: mimeForPath(path),
|
|
@@ -50959,20 +51000,20 @@ function collectRunArtifacts(context) {
|
|
|
50959
51000
|
return artifacts.sort((a, b) => a.path.localeCompare(b.path));
|
|
50960
51001
|
}
|
|
50961
51002
|
function readRunRecord(runDir) {
|
|
50962
|
-
const path =
|
|
50963
|
-
if (!
|
|
51003
|
+
const path = join21(runDir, "run.json");
|
|
51004
|
+
if (!existsSync21(path))
|
|
50964
51005
|
return null;
|
|
50965
51006
|
try {
|
|
50966
|
-
return JSON.parse(
|
|
51007
|
+
return JSON.parse(readFileSync18(path, "utf-8"));
|
|
50967
51008
|
} catch {
|
|
50968
51009
|
return null;
|
|
50969
51010
|
}
|
|
50970
51011
|
}
|
|
50971
51012
|
function walkFiles(dir) {
|
|
50972
51013
|
const files = [];
|
|
50973
|
-
for (const entry of
|
|
50974
|
-
const full =
|
|
50975
|
-
if (
|
|
51014
|
+
for (const entry of readdirSync12(dir)) {
|
|
51015
|
+
const full = join21(dir, entry);
|
|
51016
|
+
if (statSync12(full).isDirectory())
|
|
50976
51017
|
files.push(...walkFiles(full));
|
|
50977
51018
|
else
|
|
50978
51019
|
files.push(full);
|
|
@@ -68186,6 +68227,43 @@ var init_discovery_tools = __esm(() => {
|
|
|
68186
68227
|
init_helpers();
|
|
68187
68228
|
});
|
|
68188
68229
|
|
|
68230
|
+
// src/lib/run-routing.ts
|
|
68231
|
+
var exports_run_routing = {};
|
|
68232
|
+
__export(exports_run_routing, {
|
|
68233
|
+
resolveRunRouting: () => resolveRunRouting,
|
|
68234
|
+
resolveConfiguredRunRouting: () => resolveConfiguredRunRouting,
|
|
68235
|
+
isServerOwnedSkill: () => isServerOwnedSkill
|
|
68236
|
+
});
|
|
68237
|
+
function isServerOwnedSkill(skill) {
|
|
68238
|
+
return skill.serverOwned === true;
|
|
68239
|
+
}
|
|
68240
|
+
function resolveRunRouting(skill, apiKey, apiUrl) {
|
|
68241
|
+
if (!isServerOwnedSkill(skill))
|
|
68242
|
+
return { route: "local" };
|
|
68243
|
+
if (!apiUrl) {
|
|
68244
|
+
return {
|
|
68245
|
+
route: "error",
|
|
68246
|
+
code: "REMOTE_REQUIRES_ORIGIN",
|
|
68247
|
+
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)`
|
|
68248
|
+
};
|
|
68249
|
+
}
|
|
68250
|
+
if (!apiKey) {
|
|
68251
|
+
return {
|
|
68252
|
+
route: "error",
|
|
68253
|
+
code: "REMOTE_REQUIRES_CREDENTIAL",
|
|
68254
|
+
error: `${skill.name} is a server-owned skill. Run: skills auth login`
|
|
68255
|
+
};
|
|
68256
|
+
}
|
|
68257
|
+
return { route: "remote", apiKey };
|
|
68258
|
+
}
|
|
68259
|
+
function resolveConfiguredRunRouting(skill) {
|
|
68260
|
+
return resolveRunRouting(skill, getApiKey(), resolveApiUrl());
|
|
68261
|
+
}
|
|
68262
|
+
var init_run_routing = __esm(() => {
|
|
68263
|
+
init_api_url();
|
|
68264
|
+
init_auth_store();
|
|
68265
|
+
});
|
|
68266
|
+
|
|
68189
68267
|
// src/lib/remote-client.ts
|
|
68190
68268
|
var exports_remote_client = {};
|
|
68191
68269
|
__export(exports_remote_client, {
|
|
@@ -68486,8 +68564,8 @@ var init_remote_client = __esm(() => {
|
|
|
68486
68564
|
});
|
|
68487
68565
|
|
|
68488
68566
|
// src/mcp/operation-tools.ts
|
|
68489
|
-
import { existsSync as
|
|
68490
|
-
import { join as
|
|
68567
|
+
import { existsSync as existsSync22, readdirSync as readdirSync13, statSync as statSync13 } from "fs";
|
|
68568
|
+
import { join as join22 } from "path";
|
|
68491
68569
|
function registerOperationTools(server) {
|
|
68492
68570
|
server.registerTool("scaffold_skill", {
|
|
68493
68571
|
title: "Scaffold Skill",
|
|
@@ -68695,7 +68773,6 @@ function registerOperationTools(server) {
|
|
|
68695
68773
|
if (!skill) {
|
|
68696
68774
|
return mcpError("SKILL_NOT_FOUND", `Skill '${name}' not found`, findSimilarSkills(name));
|
|
68697
68775
|
}
|
|
68698
|
-
const { getApiKey: getApiKey2 } = await Promise.resolve().then(() => (init_auth_store(), exports_auth_store));
|
|
68699
68776
|
const {
|
|
68700
68777
|
ARTICLE_GENERATION_SLUG: ARTICLE_GENERATION_SLUG2,
|
|
68701
68778
|
validateBlogArticleRunOptions: validateBlogArticleRunOptions2
|
|
@@ -68709,24 +68786,24 @@ function registerOperationTools(server) {
|
|
|
68709
68786
|
return mcpError("INVALID_BLOG_ARTICLE_OPTIONS", validation.errors.join(" "));
|
|
68710
68787
|
}
|
|
68711
68788
|
}
|
|
68712
|
-
const
|
|
68713
|
-
const hostedRuntime = false;
|
|
68789
|
+
const routing = resolveConfiguredRunRouting(skill);
|
|
68714
68790
|
const runContext = createSkillRun({
|
|
68715
68791
|
skill: skillName,
|
|
68716
68792
|
args: runArgs,
|
|
68717
|
-
remote:
|
|
68793
|
+
remote: routing.route === "remote"
|
|
68718
68794
|
});
|
|
68719
|
-
if (
|
|
68720
|
-
const error2 =
|
|
68795
|
+
if (routing.route === "error") {
|
|
68796
|
+
const error2 = routing.error;
|
|
68721
68797
|
writeRunLogs(runContext, "", error2 + `
|
|
68722
68798
|
`);
|
|
68723
68799
|
const run = completeSkillRun(runContext, { status: "failed", error: error2 });
|
|
68724
|
-
|
|
68800
|
+
const suggestions = routing.code === "REMOTE_REQUIRES_ORIGIN" ? ["skills setup --api-url <url>", "skills auth login"] : ["skills auth login"];
|
|
68801
|
+
return mcpError(routing.code, `${error2}. Local run metadata: ${run.paths.runDir}/run.json`, suggestions);
|
|
68725
68802
|
}
|
|
68726
|
-
if (
|
|
68803
|
+
if (routing.route === "remote") {
|
|
68727
68804
|
try {
|
|
68728
68805
|
const { RemoteSkillsClient: RemoteSkillsClient2 } = await Promise.resolve().then(() => (init_remote_client(), exports_remote_client));
|
|
68729
|
-
const client = new RemoteSkillsClient2(apiKey);
|
|
68806
|
+
const client = new RemoteSkillsClient2(routing.apiKey);
|
|
68730
68807
|
const run = await client.submitRun(skillName, runInput, runArgs);
|
|
68731
68808
|
if (run.error) {
|
|
68732
68809
|
writeRunLogs(runContext, "", String(run.error) + `
|
|
@@ -68885,13 +68962,13 @@ function registerOperationTools(server) {
|
|
|
68885
68962
|
const agents = [];
|
|
68886
68963
|
for (const agent of AGENT_TARGETS) {
|
|
68887
68964
|
const agentSkillsPath = getAgentSkillsDir(agent, "global");
|
|
68888
|
-
const exists =
|
|
68965
|
+
const exists = existsSync22(agentSkillsPath);
|
|
68889
68966
|
let skillCount = 0;
|
|
68890
68967
|
if (exists) {
|
|
68891
68968
|
try {
|
|
68892
|
-
skillCount =
|
|
68893
|
-
const full =
|
|
68894
|
-
return !f.startsWith(".") &&
|
|
68969
|
+
skillCount = readdirSync13(agentSkillsPath).filter((f) => {
|
|
68970
|
+
const full = join22(agentSkillsPath, f);
|
|
68971
|
+
return !f.startsWith(".") && statSync13(full).isDirectory();
|
|
68895
68972
|
}).length;
|
|
68896
68973
|
} catch {}
|
|
68897
68974
|
}
|
|
@@ -68943,19 +69020,20 @@ var init_operation_tools = __esm(() => {
|
|
|
68943
69020
|
init_run_state();
|
|
68944
69021
|
init_portable_skills();
|
|
68945
69022
|
init_helpers();
|
|
69023
|
+
init_run_routing();
|
|
68946
69024
|
});
|
|
68947
69025
|
|
|
68948
69026
|
// src/lib/feedback.ts
|
|
68949
|
-
import { existsSync as
|
|
68950
|
-
import { dirname as dirname7, join as
|
|
69027
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync10 } from "fs";
|
|
69028
|
+
import { dirname as dirname7, join as join23 } from "path";
|
|
68951
69029
|
import { Database } from "bun:sqlite";
|
|
68952
69030
|
function getFeedbackDbPath() {
|
|
68953
|
-
return
|
|
69031
|
+
return join23(getDataDir(), "skills.db");
|
|
68954
69032
|
}
|
|
68955
69033
|
function getFeedbackDb() {
|
|
68956
69034
|
const dbPath = getFeedbackDbPath();
|
|
68957
69035
|
const dir = dirname7(dbPath);
|
|
68958
|
-
if (!
|
|
69036
|
+
if (!existsSync23(dir))
|
|
68959
69037
|
mkdirSync10(dir, { recursive: true });
|
|
68960
69038
|
const db = new Database(dbPath);
|
|
68961
69039
|
db.exec("PRAGMA journal_mode = WAL");
|
|
@@ -69129,24 +69207,24 @@ var init_resource_meta_tools = __esm(() => {
|
|
|
69129
69207
|
});
|
|
69130
69208
|
|
|
69131
69209
|
// src/lib/scheduler.ts
|
|
69132
|
-
import { existsSync as
|
|
69133
|
-
import { join as
|
|
69210
|
+
import { existsSync as existsSync24, readFileSync as readFileSync19, writeFileSync as writeFileSync12, mkdirSync as mkdirSync11 } from "fs";
|
|
69211
|
+
import { join as join24 } from "path";
|
|
69134
69212
|
function getSchedulesPath(targetDir = process.cwd()) {
|
|
69135
|
-
return
|
|
69213
|
+
return join24(targetDir, ".skills", "schedules.json");
|
|
69136
69214
|
}
|
|
69137
69215
|
function loadSchedules(targetDir = process.cwd()) {
|
|
69138
69216
|
const path = getSchedulesPath(targetDir);
|
|
69139
|
-
if (
|
|
69217
|
+
if (existsSync24(path)) {
|
|
69140
69218
|
try {
|
|
69141
|
-
return JSON.parse(
|
|
69219
|
+
return JSON.parse(readFileSync19(path, "utf-8"));
|
|
69142
69220
|
} catch {}
|
|
69143
69221
|
}
|
|
69144
69222
|
return { version: 1, schedules: [] };
|
|
69145
69223
|
}
|
|
69146
69224
|
function saveSchedules(data, targetDir = process.cwd()) {
|
|
69147
69225
|
const path = getSchedulesPath(targetDir);
|
|
69148
|
-
const dir =
|
|
69149
|
-
if (!
|
|
69226
|
+
const dir = join24(targetDir, ".skills");
|
|
69227
|
+
if (!existsSync24(dir))
|
|
69150
69228
|
mkdirSync11(dir, { recursive: true });
|
|
69151
69229
|
writeFileSync12(path, JSON.stringify(data, null, 2));
|
|
69152
69230
|
}
|
|
@@ -69446,14 +69524,14 @@ var init_schedule_tools = __esm(() => {
|
|
|
69446
69524
|
// src/lib/native-storage.ts
|
|
69447
69525
|
import { createHash as createHash3, createHmac as createHmac2 } from "crypto";
|
|
69448
69526
|
import {
|
|
69449
|
-
existsSync as
|
|
69527
|
+
existsSync as existsSync25,
|
|
69450
69528
|
mkdirSync as mkdirSync12,
|
|
69451
|
-
readFileSync as
|
|
69452
|
-
readdirSync as
|
|
69453
|
-
statSync as
|
|
69529
|
+
readFileSync as readFileSync20,
|
|
69530
|
+
readdirSync as readdirSync14,
|
|
69531
|
+
statSync as statSync14,
|
|
69454
69532
|
writeFileSync as writeFileSync13
|
|
69455
69533
|
} from "fs";
|
|
69456
|
-
import { dirname as dirname8, join as
|
|
69534
|
+
import { dirname as dirname8, join as join25, normalize as normalize3, relative as relative3, sep as sep2 } from "path";
|
|
69457
69535
|
function resolveSkillsNativeStorageConfig(env3 = process.env) {
|
|
69458
69536
|
assertNoRetiredModeEnvVars(env3, {
|
|
69459
69537
|
app: SKILLS_ENV_NAMESPACE,
|
|
@@ -69494,7 +69572,7 @@ function getSkillsNativeStorageStatus(options = {}) {
|
|
|
69494
69572
|
local: {
|
|
69495
69573
|
dataDir: getDataDir(),
|
|
69496
69574
|
projectStateDir: getProjectStateDir(targetDir),
|
|
69497
|
-
feedbackDbPath:
|
|
69575
|
+
feedbackDbPath: join25(getDataDir(), "skills.db")
|
|
69498
69576
|
},
|
|
69499
69577
|
remote: {
|
|
69500
69578
|
databaseConfigured: Boolean(config2.databaseUrl),
|
|
@@ -69514,9 +69592,9 @@ function getStorageStatus(options = {}) {
|
|
|
69514
69592
|
function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
|
|
69515
69593
|
const projectStateDir = getProjectStateDir(targetDir);
|
|
69516
69594
|
const files = [];
|
|
69517
|
-
if (
|
|
69595
|
+
if (existsSync25(projectStateDir)) {
|
|
69518
69596
|
for (const filePath of walkFiles2(projectStateDir)) {
|
|
69519
|
-
const bytes =
|
|
69597
|
+
const bytes = readFileSync20(filePath);
|
|
69520
69598
|
const relativePath = toPosix(relative3(targetDir, filePath));
|
|
69521
69599
|
files.push({
|
|
69522
69600
|
path: relativePath,
|
|
@@ -69574,9 +69652,9 @@ function parsePositiveInteger(value) {
|
|
|
69574
69652
|
}
|
|
69575
69653
|
function walkFiles2(dir) {
|
|
69576
69654
|
const files = [];
|
|
69577
|
-
for (const entry of
|
|
69578
|
-
const full =
|
|
69579
|
-
const stats =
|
|
69655
|
+
for (const entry of readdirSync14(dir)) {
|
|
69656
|
+
const full = join25(dir, entry);
|
|
69657
|
+
const stats = statSync14(full);
|
|
69580
69658
|
if (stats.isDirectory())
|
|
69581
69659
|
files.push(...walkFiles2(full));
|
|
69582
69660
|
else
|
|
@@ -70119,9 +70197,9 @@ var init_mcp2 = __esm(() => {
|
|
|
70119
70197
|
});
|
|
70120
70198
|
|
|
70121
70199
|
// src/cli/commands/runtime-mcp.ts
|
|
70122
|
-
import { existsSync as
|
|
70200
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync13, readFileSync as readFileSync21, writeFileSync as writeFileSync14 } from "fs";
|
|
70123
70201
|
import { homedir as homedir8 } from "os";
|
|
70124
|
-
import { dirname as dirname9, join as
|
|
70202
|
+
import { dirname as dirname9, join as join26 } from "path";
|
|
70125
70203
|
async function handleMcp(options) {
|
|
70126
70204
|
if (options.register) {
|
|
70127
70205
|
let agents;
|
|
@@ -70163,24 +70241,24 @@ async function registerMcpForAgent(agent, command) {
|
|
|
70163
70241
|
case "codex":
|
|
70164
70242
|
return registerCodexMcp(command);
|
|
70165
70243
|
case "gemini":
|
|
70166
|
-
return registerJsonMcpServer(agent,
|
|
70244
|
+
return registerJsonMcpServer(agent, join26(homedir8(), ".gemini", "settings.json"), "mcpServers", {
|
|
70167
70245
|
command,
|
|
70168
70246
|
args: []
|
|
70169
70247
|
});
|
|
70170
70248
|
case "pi":
|
|
70171
|
-
return registerJsonMcpServer(agent,
|
|
70249
|
+
return registerJsonMcpServer(agent, join26(homedir8(), ".pi", "agent", "mcp.json"), "mcpServers", {
|
|
70172
70250
|
command,
|
|
70173
70251
|
args: []
|
|
70174
70252
|
});
|
|
70175
70253
|
case "opencode":
|
|
70176
70254
|
return registerOpenCodeMcp(command);
|
|
70177
70255
|
case "cursor":
|
|
70178
|
-
return registerJsonMcpServer(agent,
|
|
70256
|
+
return registerJsonMcpServer(agent, join26(homedir8(), ".cursor", "mcp.json"), "mcpServers", {
|
|
70179
70257
|
command,
|
|
70180
70258
|
args: []
|
|
70181
70259
|
});
|
|
70182
70260
|
case "windsurf":
|
|
70183
|
-
return registerJsonMcpServer(agent,
|
|
70261
|
+
return registerJsonMcpServer(agent, join26(homedir8(), ".windsurf", "mcp.json"), "mcpServers", {
|
|
70184
70262
|
command,
|
|
70185
70263
|
args: []
|
|
70186
70264
|
});
|
|
@@ -70203,7 +70281,7 @@ async function registerClaudeMcp(command) {
|
|
|
70203
70281
|
if (exitCode === 0) {
|
|
70204
70282
|
return { agent: "claude", success: true, command: cliCommand };
|
|
70205
70283
|
}
|
|
70206
|
-
const fallback = registerJsonMcpServer("claude",
|
|
70284
|
+
const fallback = registerJsonMcpServer("claude", join26(homedir8(), ".claude", ".mcp.json"), "mcpServers", {
|
|
70207
70285
|
command,
|
|
70208
70286
|
args: []
|
|
70209
70287
|
});
|
|
@@ -70213,7 +70291,7 @@ async function registerClaudeMcp(command) {
|
|
|
70213
70291
|
error: fallback.success ? undefined : `claude exited with ${exitCode}: ${(stderr || stdout).trim()}`
|
|
70214
70292
|
};
|
|
70215
70293
|
} catch (err) {
|
|
70216
|
-
const fallback = registerJsonMcpServer("claude",
|
|
70294
|
+
const fallback = registerJsonMcpServer("claude", join26(homedir8(), ".claude", ".mcp.json"), "mcpServers", {
|
|
70217
70295
|
command,
|
|
70218
70296
|
args: []
|
|
70219
70297
|
});
|
|
@@ -70225,11 +70303,11 @@ async function registerClaudeMcp(command) {
|
|
|
70225
70303
|
}
|
|
70226
70304
|
}
|
|
70227
70305
|
function registerCodexMcp(command) {
|
|
70228
|
-
const path =
|
|
70306
|
+
const path = join26(homedir8(), ".codex", "config.toml");
|
|
70229
70307
|
const config2 = `[mcp_servers.${MCP_SERVER_NAME}]
|
|
70230
70308
|
command = ${JSON.stringify(command)}`;
|
|
70231
70309
|
try {
|
|
70232
|
-
const current =
|
|
70310
|
+
const current = existsSync26(path) ? readFileSync21(path, "utf-8") : "";
|
|
70233
70311
|
writeTextFile(path, upsertTomlSection(current, `[mcp_servers.${MCP_SERVER_NAME}]`, `command = ${JSON.stringify(command)}`));
|
|
70234
70312
|
return { agent: "codex", success: true, path, config: config2 };
|
|
70235
70313
|
} catch (err) {
|
|
@@ -70237,7 +70315,7 @@ command = ${JSON.stringify(command)}`;
|
|
|
70237
70315
|
}
|
|
70238
70316
|
}
|
|
70239
70317
|
function registerOpenCodeMcp(command) {
|
|
70240
|
-
const path =
|
|
70318
|
+
const path = join26(homedir8(), ".config", "opencode", "opencode.json");
|
|
70241
70319
|
const config2 = JSON.stringify({
|
|
70242
70320
|
$schema: "https://opencode.ai/config.json",
|
|
70243
70321
|
mcp: {
|
|
@@ -70279,9 +70357,9 @@ function registerJsonMcpServer(agent, path, containerKey, server2) {
|
|
|
70279
70357
|
}
|
|
70280
70358
|
}
|
|
70281
70359
|
function readJsonObject2(path) {
|
|
70282
|
-
if (!
|
|
70360
|
+
if (!existsSync26(path))
|
|
70283
70361
|
return {};
|
|
70284
|
-
const raw =
|
|
70362
|
+
const raw = readFileSync21(path, "utf-8").trim();
|
|
70285
70363
|
if (!raw)
|
|
70286
70364
|
return {};
|
|
70287
70365
|
const parsed = JSON.parse(raw);
|
|
@@ -70325,8 +70403,8 @@ function findCommandOnPath(command) {
|
|
|
70325
70403
|
for (const dir of pathValue.split(":")) {
|
|
70326
70404
|
if (!dir)
|
|
70327
70405
|
continue;
|
|
70328
|
-
const candidate =
|
|
70329
|
-
if (
|
|
70406
|
+
const candidate = join26(dir, command);
|
|
70407
|
+
if (existsSync26(candidate))
|
|
70330
70408
|
return candidate;
|
|
70331
70409
|
}
|
|
70332
70410
|
return command;
|
|
@@ -70346,7 +70424,7 @@ __export(exports_runtime, {
|
|
|
70346
70424
|
registerRuntime: () => registerRuntime
|
|
70347
70425
|
});
|
|
70348
70426
|
import { mkdirSync as mkdirSync14, writeFileSync as writeFileSync15 } from "fs";
|
|
70349
|
-
import { dirname as dirname10, join as
|
|
70427
|
+
import { dirname as dirname10, join as join27 } from "path";
|
|
70350
70428
|
import { createInterface } from "readline";
|
|
70351
70429
|
function registerRuntime(parent) {
|
|
70352
70430
|
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));
|
|
@@ -70493,31 +70571,29 @@ async function handleRun(name, args2, options) {
|
|
|
70493
70571
|
return;
|
|
70494
70572
|
}
|
|
70495
70573
|
}
|
|
70496
|
-
const
|
|
70574
|
+
const routing = resolveConfiguredRunRouting(skill);
|
|
70497
70575
|
const runContext = createSkillRun({
|
|
70498
70576
|
skill: skill.name,
|
|
70499
70577
|
args: args2,
|
|
70500
70578
|
prompt,
|
|
70501
|
-
remote:
|
|
70579
|
+
remote: routing.route === "remote"
|
|
70502
70580
|
});
|
|
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 + `
|
|
70581
|
+
if (routing.route === "error") {
|
|
70582
|
+
const error2 = routing.error;
|
|
70583
|
+
writeRunLogs(runContext, "", error2 + `
|
|
70509
70584
|
`);
|
|
70510
|
-
|
|
70511
|
-
|
|
70512
|
-
|
|
70513
|
-
|
|
70514
|
-
|
|
70515
|
-
|
|
70516
|
-
|
|
70517
|
-
|
|
70585
|
+
const run = completeSkillRun(runContext, { status: "failed", error: error2 });
|
|
70586
|
+
if (options.json)
|
|
70587
|
+
console.log(JSON.stringify({ contractVersion: REMOTE_SKILL_RUN_CONTRACT_VERSION, skill: skill.name, args: args2, exitCode: 1, remote: true, error: error2, run }, null, 2));
|
|
70588
|
+
else
|
|
70589
|
+
console.error(source_default.red(error2));
|
|
70590
|
+
process.exitCode = 1;
|
|
70591
|
+
return;
|
|
70592
|
+
}
|
|
70593
|
+
if (routing.route === "remote") {
|
|
70518
70594
|
try {
|
|
70519
70595
|
const { RemoteSkillsClient: RemoteSkillsClient2 } = await Promise.resolve().then(() => (init_remote_client(), exports_remote_client));
|
|
70520
|
-
const client = new RemoteSkillsClient2(apiKey);
|
|
70596
|
+
const client = new RemoteSkillsClient2(routing.apiKey);
|
|
70521
70597
|
const run = await client.submitRun(skill.name, {}, args2);
|
|
70522
70598
|
if (run.error) {
|
|
70523
70599
|
writeRunLogs(runContext, "", String(run.error) + `
|
|
@@ -70830,7 +70906,7 @@ async function handleExportsDownload(runId, options) {
|
|
|
70830
70906
|
if (!response.ok)
|
|
70831
70907
|
throw new Error(`download failed for artifact ${artifactId}: ${response.status}`);
|
|
70832
70908
|
const relativePath = safeArtifactRelativePath(typeof artifact.relativePath === "string" ? artifact.relativePath : artifact.fileName, String(artifact.fileName || artifactId));
|
|
70833
|
-
const outputPath =
|
|
70909
|
+
const outputPath = join27(exportDir, relativePath);
|
|
70834
70910
|
mkdirSync14(dirname10(outputPath), { recursive: true });
|
|
70835
70911
|
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
70836
70912
|
writeFileSync15(outputPath, bytes);
|
|
@@ -71049,6 +71125,7 @@ var init_runtime = __esm(() => {
|
|
|
71049
71125
|
init_runs();
|
|
71050
71126
|
init_run_state();
|
|
71051
71127
|
init_runtime_mcp();
|
|
71128
|
+
init_run_routing();
|
|
71052
71129
|
});
|
|
71053
71130
|
|
|
71054
71131
|
// src/cli/commands/completion.ts
|
|
@@ -71195,8 +71272,8 @@ var exports_create_sync_config = {};
|
|
|
71195
71272
|
__export(exports_create_sync_config, {
|
|
71196
71273
|
registerCreateSync: () => registerCreateSync
|
|
71197
71274
|
});
|
|
71198
|
-
import { existsSync as
|
|
71199
|
-
import { join as
|
|
71275
|
+
import { existsSync as existsSync27, writeFileSync as writeFileSync16, mkdirSync as mkdirSync15 } from "fs";
|
|
71276
|
+
import { join as join28 } from "path";
|
|
71200
71277
|
function registerCreateSync(parent) {
|
|
71201
71278
|
const configCmd = parent.command("config").description("Manage skills configuration");
|
|
71202
71279
|
configCmd.command("show", { isDefault: true }).option("--json", "Output as JSON", false).description("Show current merged configuration").action((options) => {
|
|
@@ -71262,13 +71339,13 @@ function registerCreateSync(parent) {
|
|
|
71262
71339
|
const pp = getConfigPath("project");
|
|
71263
71340
|
if (options.json) {
|
|
71264
71341
|
console.log(JSON.stringify({
|
|
71265
|
-
global: { path: gp, exists:
|
|
71266
|
-
project: { path: pp, exists:
|
|
71342
|
+
global: { path: gp, exists: existsSync27(gp) },
|
|
71343
|
+
project: { path: pp, exists: existsSync27(pp) }
|
|
71267
71344
|
}, null, 2));
|
|
71268
71345
|
return;
|
|
71269
71346
|
}
|
|
71270
|
-
console.log(`${source_default.cyan("global")}: ${gp}${
|
|
71271
|
-
console.log(`${source_default.cyan("project")}: ${pp}${
|
|
71347
|
+
console.log(`${source_default.cyan("global")}: ${gp}${existsSync27(gp) ? source_default.green(" (exists)") : source_default.dim(" (not found)")}`);
|
|
71348
|
+
console.log(`${source_default.cyan("project")}: ${pp}${existsSync27(pp) ? source_default.green(" (exists)") : source_default.dim(" (not found)")}`);
|
|
71272
71349
|
});
|
|
71273
71350
|
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
71351
|
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 +71354,8 @@ function handleCreate(name, options) {
|
|
|
71277
71354
|
const bare = name.trim();
|
|
71278
71355
|
const dirName = bare;
|
|
71279
71356
|
const baseDir = getPortableSkillsRoot();
|
|
71280
|
-
const skillDir =
|
|
71281
|
-
if (
|
|
71357
|
+
const skillDir = join28(baseDir, dirName);
|
|
71358
|
+
if (existsSync27(skillDir)) {
|
|
71282
71359
|
console.log(options.json ? JSON.stringify({ error: `Skill '${bare}' already exists at ${skillDir}` }) : source_default.red(`Skill '${bare}' already exists at ${skillDir}`));
|
|
71283
71360
|
process.exitCode = 1;
|
|
71284
71361
|
return;
|
|
@@ -71286,8 +71363,8 @@ function handleCreate(name, options) {
|
|
|
71286
71363
|
const description = options.description || `${bare} skill`;
|
|
71287
71364
|
const tags = options.tags ? options.tags.split(",").map((t) => t.trim()).filter(Boolean) : [bare];
|
|
71288
71365
|
const displayName2 = bare.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
71289
|
-
mkdirSync15(
|
|
71290
|
-
writeFileSync16(
|
|
71366
|
+
mkdirSync15(join28(skillDir, "src"), { recursive: true });
|
|
71367
|
+
writeFileSync16(join28(skillDir, "SKILL.md"), [
|
|
71291
71368
|
"---",
|
|
71292
71369
|
`name: ${bare}`,
|
|
71293
71370
|
`description: ${description}`,
|
|
@@ -71307,11 +71384,11 @@ function handleCreate(name, options) {
|
|
|
71307
71384
|
""
|
|
71308
71385
|
].join(`
|
|
71309
71386
|
`));
|
|
71310
|
-
writeFileSync16(
|
|
71387
|
+
writeFileSync16(join28(skillDir, "src", "index.ts"), [`#!/usr/bin/env bun`, `/**`, ` * ${displayName2} \u2014 ${description}`, ` */`, "", `console.log("${displayName2}");`, ""].join(`
|
|
71311
71388
|
`));
|
|
71312
|
-
writeFileSync16(
|
|
71389
|
+
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
71390
|
`);
|
|
71314
|
-
writeFileSync16(
|
|
71391
|
+
writeFileSync16(join28(skillDir, "tsconfig.json"), JSON.stringify({ compilerOptions: { target: "ES2022", module: "ESNext", moduleResolution: "bundler", strict: true, outDir: "dist" }, include: ["src/**/*.ts"] }, null, 2) + `
|
|
71315
71392
|
`);
|
|
71316
71393
|
clearRegistryCache();
|
|
71317
71394
|
if (options.json)
|
|
@@ -71320,8 +71397,8 @@ function handleCreate(name, options) {
|
|
|
71320
71397
|
console.log(source_default.green(`\u2713 Created custom skill '${bare}' at ${skillDir}`));
|
|
71321
71398
|
console.log(source_default.dim(` Category: ${options.category}`));
|
|
71322
71399
|
console.log(source_default.dim(` Tags: ${tags.join(", ")}`));
|
|
71323
|
-
console.log(` ${source_default.cyan("Edit:")} ${
|
|
71324
|
-
console.log(` ${source_default.cyan("Run:")} bun ${
|
|
71400
|
+
console.log(` ${source_default.cyan("Edit:")} ${join28(skillDir, "src", "index.ts")}`);
|
|
71401
|
+
console.log(` ${source_default.cyan("Run:")} bun ${join28(skillDir, "src", "index.ts")}`);
|
|
71325
71402
|
}
|
|
71326
71403
|
}
|
|
71327
71404
|
function handleSync(names, options) {
|
|
@@ -71783,6 +71860,14 @@ async function executeScheduledSkill(skillName, args2, options) {
|
|
|
71783
71860
|
const skill = getSkill2(skillName);
|
|
71784
71861
|
if (!skill)
|
|
71785
71862
|
throw new Error(`Skill '${skillName}' not found`);
|
|
71863
|
+
const { resolveConfiguredRunRouting: resolveConfiguredRunRouting2 } = await Promise.resolve().then(() => (init_run_routing(), exports_run_routing));
|
|
71864
|
+
const routing = resolveConfiguredRunRouting2(skill);
|
|
71865
|
+
if (routing.route === "error") {
|
|
71866
|
+
throw new Error(`${routing.code}: ${routing.error}`);
|
|
71867
|
+
}
|
|
71868
|
+
if (routing.route === "remote") {
|
|
71869
|
+
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}`);
|
|
71870
|
+
}
|
|
71786
71871
|
const { runSkill: runSkill2 } = await Promise.resolve().then(() => (init_skillinfo(), exports_skillinfo));
|
|
71787
71872
|
const result2 = await runSkill2(skill.name, args2);
|
|
71788
71873
|
if (result2.exitCode !== 0) {
|
|
@@ -71920,8 +72005,8 @@ var init_revision = __esm(() => {
|
|
|
71920
72005
|
|
|
71921
72006
|
// src/lib/skill-bundle.ts
|
|
71922
72007
|
import { createHash as createHash5 } from "crypto";
|
|
71923
|
-
import { readFileSync as
|
|
71924
|
-
import { join as
|
|
72008
|
+
import { readFileSync as readFileSync22, readdirSync as readdirSync15, statSync as statSync15 } from "fs";
|
|
72009
|
+
import { join as join29, relative as relative5 } from "path";
|
|
71925
72010
|
function isDotenvFile(lower) {
|
|
71926
72011
|
if (lower === ".env" || lower.startsWith(".env."))
|
|
71927
72012
|
return true;
|
|
@@ -71958,8 +72043,8 @@ function collectSkillBundleEntries(dir) {
|
|
|
71958
72043
|
return entries.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
71959
72044
|
}
|
|
71960
72045
|
function walk(root, current, out) {
|
|
71961
|
-
for (const entry of
|
|
71962
|
-
const absolute =
|
|
72046
|
+
for (const entry of readdirSync15(current, { withFileTypes: true })) {
|
|
72047
|
+
const absolute = join29(current, entry.name);
|
|
71963
72048
|
const rel = relative5(root, absolute).split("\\").join("/");
|
|
71964
72049
|
const isRootLevel = !rel.includes("/");
|
|
71965
72050
|
if (ANY_SEGMENT_EXCLUDES.has(entry.name.toLowerCase()))
|
|
@@ -71980,10 +72065,10 @@ function walk(root, current, out) {
|
|
|
71980
72065
|
continue;
|
|
71981
72066
|
if (isCredentialFile(entry.name))
|
|
71982
72067
|
continue;
|
|
71983
|
-
const stats =
|
|
72068
|
+
const stats = statSync15(absolute);
|
|
71984
72069
|
out.push({
|
|
71985
72070
|
path: rel,
|
|
71986
|
-
bytes: ownBytes(
|
|
72071
|
+
bytes: ownBytes(readFileSync22(absolute)),
|
|
71987
72072
|
mode: stats.mode & 64 ? 493 : 420
|
|
71988
72073
|
});
|
|
71989
72074
|
}
|
|
@@ -72269,8 +72354,8 @@ var init_skill_bundles = __esm(() => {
|
|
|
72269
72354
|
});
|
|
72270
72355
|
|
|
72271
72356
|
// src/lib/pull.ts
|
|
72272
|
-
import { existsSync as
|
|
72273
|
-
import { dirname as dirname12, join as
|
|
72357
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync17, mkdtempSync as mkdtempSync3, readFileSync as readFileSync23, renameSync as renameSync4, rmSync as rmSync6, writeFileSync as writeFileSync18 } from "fs";
|
|
72358
|
+
import { dirname as dirname12, join as join30 } from "path";
|
|
72274
72359
|
async function pullSkills(options = {}) {
|
|
72275
72360
|
const client = options.client !== undefined ? options.client : createRemoteSkillsClient();
|
|
72276
72361
|
if (!client) {
|
|
@@ -72315,7 +72400,7 @@ async function pullOne(client, rawName, corpusOptions, verify) {
|
|
|
72315
72400
|
return reconcileTombstone(slug, corpusOptions);
|
|
72316
72401
|
}
|
|
72317
72402
|
if (bundleResponse.status === 404) {
|
|
72318
|
-
const marker = readPullMarker(
|
|
72403
|
+
const marker = readPullMarker(join30(getPortableSkillsRoot(corpusOptions), slug));
|
|
72319
72404
|
if (marker && typeof marker.revisionId === "string" && marker.revisionId) {
|
|
72320
72405
|
return { name: slug, success: true, purged: true, removed: false };
|
|
72321
72406
|
}
|
|
@@ -72346,7 +72431,7 @@ async function pullOne(client, rawName, corpusOptions, verify) {
|
|
|
72346
72431
|
return { name: slug, success: false, error: `Skill '${slug}' was not found on the configured Skills instance.` };
|
|
72347
72432
|
}
|
|
72348
72433
|
if (!meta?.revisionId) {
|
|
72349
|
-
const marker = readPullMarker(
|
|
72434
|
+
const marker = readPullMarker(join30(getPortableSkillsRoot(corpusOptions), slug));
|
|
72350
72435
|
if (marker && typeof marker.revisionId === "string" && marker.revisionId) {
|
|
72351
72436
|
return { name: slug, success: true, purged: true, removed: false };
|
|
72352
72437
|
}
|
|
@@ -72360,7 +72445,7 @@ async function pullOne(client, rawName, corpusOptions, verify) {
|
|
|
72360
72445
|
}
|
|
72361
72446
|
throw error2;
|
|
72362
72447
|
}
|
|
72363
|
-
const written =
|
|
72448
|
+
const written = installCorpusSkillAtomically({ name: slug, skillMd, meta }, corpusOptions);
|
|
72364
72449
|
writePullMarker(written.path, {
|
|
72365
72450
|
skill: slug,
|
|
72366
72451
|
version: written.manifest.version,
|
|
@@ -72403,8 +72488,8 @@ function provenRevision(meta, slug, bundle) {
|
|
|
72403
72488
|
return declared;
|
|
72404
72489
|
}
|
|
72405
72490
|
function reconcileTombstone(slug, corpusOptions) {
|
|
72406
|
-
const target =
|
|
72407
|
-
if (!
|
|
72491
|
+
const target = join30(getPortableSkillsRoot(corpusOptions), slug);
|
|
72492
|
+
if (!existsSync28(join30(target, PULL_MARKER_FILE))) {
|
|
72408
72493
|
return { name: slug, success: true, tombstoned: true, removed: false, leftInPlace: true };
|
|
72409
72494
|
}
|
|
72410
72495
|
rmSync6(target, { recursive: true, force: true });
|
|
@@ -72412,7 +72497,7 @@ function reconcileTombstone(slug, corpusOptions) {
|
|
|
72412
72497
|
}
|
|
72413
72498
|
function readPullMarker(dir) {
|
|
72414
72499
|
try {
|
|
72415
|
-
return JSON.parse(
|
|
72500
|
+
return JSON.parse(readFileSync23(join30(dir, PULL_MARKER_FILE), "utf-8"));
|
|
72416
72501
|
} catch {
|
|
72417
72502
|
return null;
|
|
72418
72503
|
}
|
|
@@ -72533,14 +72618,14 @@ function verifyBundleResponseBytes(buffer, response, verify = {}) {
|
|
|
72533
72618
|
function installBundleAtomically(name, entries, options = {}, marker = {}) {
|
|
72534
72619
|
const root = getPortableSkillsRoot(options);
|
|
72535
72620
|
mkdirSync17(root, { recursive: true });
|
|
72536
|
-
const target =
|
|
72537
|
-
const created = !
|
|
72538
|
-
const staging =
|
|
72621
|
+
const target = join30(root, name);
|
|
72622
|
+
const created = !existsSync28(target);
|
|
72623
|
+
const staging = mkdtempSync3(join30(root, `.pull-${name}-`));
|
|
72539
72624
|
let moved = false;
|
|
72540
72625
|
let backup = null;
|
|
72541
72626
|
try {
|
|
72542
72627
|
for (const entry of entries) {
|
|
72543
|
-
const destination =
|
|
72628
|
+
const destination = join30(staging, entry.path);
|
|
72544
72629
|
mkdirSync17(dirname12(destination), { recursive: true });
|
|
72545
72630
|
writeFileSync18(destination, entry.bytes, { mode: entry.mode });
|
|
72546
72631
|
}
|
|
@@ -72552,9 +72637,9 @@ function installBundleAtomically(name, entries, options = {}, marker = {}) {
|
|
|
72552
72637
|
...marker.signature ? { signature: marker.signature } : {},
|
|
72553
72638
|
...marker.revisionId ? { revisionId: marker.revisionId } : {}
|
|
72554
72639
|
});
|
|
72555
|
-
if (
|
|
72556
|
-
backup =
|
|
72557
|
-
renameSync4(target,
|
|
72640
|
+
if (existsSync28(target)) {
|
|
72641
|
+
backup = mkdtempSync3(join30(root, `.pull-backup-${name}-`));
|
|
72642
|
+
renameSync4(target, join30(backup, name));
|
|
72558
72643
|
moved = true;
|
|
72559
72644
|
}
|
|
72560
72645
|
renameSync4(staging, target);
|
|
@@ -72562,9 +72647,9 @@ function installBundleAtomically(name, entries, options = {}, marker = {}) {
|
|
|
72562
72647
|
rmSync6(backup, { recursive: true, force: true });
|
|
72563
72648
|
} catch (error2) {
|
|
72564
72649
|
rmSync6(staging, { recursive: true, force: true });
|
|
72565
|
-
if (moved && backup &&
|
|
72650
|
+
if (moved && backup && existsSync28(join30(backup, name))) {
|
|
72566
72651
|
try {
|
|
72567
|
-
renameSync4(
|
|
72652
|
+
renameSync4(join30(backup, name), target);
|
|
72568
72653
|
} catch {}
|
|
72569
72654
|
}
|
|
72570
72655
|
throw error2;
|
|
@@ -72583,7 +72668,7 @@ function writePullMarker(dir, record3) {
|
|
|
72583
72668
|
...record3.revisionId ? { revisionId: record3.revisionId } : {},
|
|
72584
72669
|
syncedAt: new Date().toISOString()
|
|
72585
72670
|
};
|
|
72586
|
-
writeFileSync18(
|
|
72671
|
+
writeFileSync18(join30(dir, PULL_MARKER_FILE), `${JSON.stringify(marker, null, 2)}
|
|
72587
72672
|
`);
|
|
72588
72673
|
}
|
|
72589
72674
|
async function safeMeta(client, slug) {
|
|
@@ -72754,8 +72839,8 @@ __export(exports_publish, {
|
|
|
72754
72839
|
pushSkill: () => pushSkill,
|
|
72755
72840
|
PushSkillError: () => PushSkillError
|
|
72756
72841
|
});
|
|
72757
|
-
import { existsSync as
|
|
72758
|
-
import { join as
|
|
72842
|
+
import { existsSync as existsSync29, readFileSync as readFileSync24 } from "fs";
|
|
72843
|
+
import { join as join31 } from "path";
|
|
72759
72844
|
function registerPublish(parent) {
|
|
72760
72845
|
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
72846
|
try {
|
|
@@ -72796,8 +72881,8 @@ async function pushSkill(name, options = {}) {
|
|
|
72796
72881
|
}
|
|
72797
72882
|
const manifest = readPortableSkillManifest(skill.path, skill.name);
|
|
72798
72883
|
const packed = packSkillBundle(skill.path, { maxUnpackedBytes: MAX_UNPACKED_BYTES });
|
|
72799
|
-
const skillMdPath =
|
|
72800
|
-
const skillMd =
|
|
72884
|
+
const skillMdPath = join31(skill.path, "SKILL.md");
|
|
72885
|
+
const skillMd = existsSync29(skillMdPath) ? readFileSync24(skillMdPath, "utf-8") : undefined;
|
|
72801
72886
|
const base2 = {
|
|
72802
72887
|
slug: skill.name,
|
|
72803
72888
|
path: skill.path,
|
|
@@ -72823,7 +72908,7 @@ async function pushSkill(name, options = {}) {
|
|
|
72823
72908
|
description: manifest.description,
|
|
72824
72909
|
category: manifest.category ?? "Development Tools",
|
|
72825
72910
|
tags: manifest.tags ?? [],
|
|
72826
|
-
kind: manifest.kind ?? "
|
|
72911
|
+
kind: manifest.kind ?? "instruction",
|
|
72827
72912
|
version: options.version ?? manifest.version,
|
|
72828
72913
|
source: "custom",
|
|
72829
72914
|
bundleSha256: packed.sha256,
|
|
@@ -73568,11 +73653,11 @@ var init_storage = __esm(() => {
|
|
|
73568
73653
|
});
|
|
73569
73654
|
|
|
73570
73655
|
// src/lib/registry-reconcile.ts
|
|
73571
|
-
import { existsSync as
|
|
73572
|
-
import { join as
|
|
73656
|
+
import { existsSync as existsSync30, readFileSync as readFileSync25, statSync as statSync16, writeFileSync as writeFileSync19 } from "fs";
|
|
73657
|
+
import { join as join32 } from "path";
|
|
73573
73658
|
function isDirectory2(path) {
|
|
73574
73659
|
try {
|
|
73575
|
-
return
|
|
73660
|
+
return statSync16(path).isDirectory();
|
|
73576
73661
|
} catch {
|
|
73577
73662
|
return false;
|
|
73578
73663
|
}
|
|
@@ -73580,15 +73665,15 @@ function isDirectory2(path) {
|
|
|
73580
73665
|
function migrationNeeded(options) {
|
|
73581
73666
|
if (options.rootDir)
|
|
73582
73667
|
return false;
|
|
73583
|
-
const appDir = options.homeDir ?
|
|
73584
|
-
return !(isOwnerLayoutMigrated(appDir) && isDirectory2(
|
|
73668
|
+
const appDir = options.homeDir ? join32(options.homeDir, ".hasna", "skills") : getDataDir();
|
|
73669
|
+
return !(isOwnerLayoutMigrated(appDir) && isDirectory2(join32(appDir, SKILLS_CACHE_DIRNAME)));
|
|
73585
73670
|
}
|
|
73586
73671
|
function readBaseline(skillDir) {
|
|
73587
|
-
const markerPath =
|
|
73588
|
-
if (!
|
|
73672
|
+
const markerPath = join32(skillDir, PULL_MARKER_FILE);
|
|
73673
|
+
if (!existsSync30(markerPath))
|
|
73589
73674
|
return;
|
|
73590
73675
|
try {
|
|
73591
|
-
const marker = JSON.parse(
|
|
73676
|
+
const marker = JSON.parse(readFileSync25(markerPath, "utf-8"));
|
|
73592
73677
|
return {
|
|
73593
73678
|
...typeof marker.contentHash === "string" && marker.contentHash ? { contentHash: marker.contentHash } : {},
|
|
73594
73679
|
...typeof marker.version === "string" && marker.version ? { version: marker.version } : {}
|
|
@@ -73598,11 +73683,11 @@ function readBaseline(skillDir) {
|
|
|
73598
73683
|
}
|
|
73599
73684
|
}
|
|
73600
73685
|
function readCursor(root) {
|
|
73601
|
-
const path =
|
|
73602
|
-
if (!
|
|
73686
|
+
const path = join32(root, SYNC_CURSOR_FILE);
|
|
73687
|
+
if (!existsSync30(path))
|
|
73603
73688
|
return { runCount: 0 };
|
|
73604
73689
|
try {
|
|
73605
|
-
const cursor = JSON.parse(
|
|
73690
|
+
const cursor = JSON.parse(readFileSync25(path, "utf-8"));
|
|
73606
73691
|
return { runCount: typeof cursor.runCount === "number" ? cursor.runCount : 0 };
|
|
73607
73692
|
} catch {
|
|
73608
73693
|
return { runCount: 0 };
|
|
@@ -73611,12 +73696,12 @@ function readCursor(root) {
|
|
|
73611
73696
|
function resolveCorpusRootReadOnly(options) {
|
|
73612
73697
|
if (options.rootDir)
|
|
73613
73698
|
return { root: options.rootDir, migrationPending: false };
|
|
73614
|
-
const appDir = options.homeDir ?
|
|
73615
|
-
const cache3 =
|
|
73699
|
+
const appDir = options.homeDir ? join32(options.homeDir, ".hasna", "skills") : getDataDirReadOnly();
|
|
73700
|
+
const cache3 = join32(appDir, SKILLS_CACHE_DIRNAME);
|
|
73616
73701
|
if (isOwnerLayoutMigrated(appDir) && isDirectory2(cache3)) {
|
|
73617
73702
|
return { root: cache3, migrationPending: false };
|
|
73618
73703
|
}
|
|
73619
|
-
return { root:
|
|
73704
|
+
return { root: join32(appDir, INSTALLED_SKILLS_DIRNAME), migrationPending: true };
|
|
73620
73705
|
}
|
|
73621
73706
|
function remoteRowToSkill(record3) {
|
|
73622
73707
|
const slug = typeof record3.slug === "string" ? record3.slug : typeof record3.name === "string" ? record3.name : undefined;
|
|
@@ -73630,7 +73715,7 @@ function remoteRowToSkill(record3) {
|
|
|
73630
73715
|
}
|
|
73631
73716
|
function recheckLocalSide(plannedLocal, localDir, ops = {
|
|
73632
73717
|
pack: (dir) => packSkillBundle(dir).sha256,
|
|
73633
|
-
exists:
|
|
73718
|
+
exists: existsSync30
|
|
73634
73719
|
}) {
|
|
73635
73720
|
let localNow;
|
|
73636
73721
|
try {
|
|
@@ -73748,7 +73833,7 @@ async function reconcileRegistry(options = {}) {
|
|
|
73748
73833
|
for (const slug of allSlugs) {
|
|
73749
73834
|
const local = locals.get(slug);
|
|
73750
73835
|
const remote = remotes.get(slug);
|
|
73751
|
-
const baseline = local ? readBaseline(
|
|
73836
|
+
const baseline = local ? readBaseline(join32(root, slug)) : undefined;
|
|
73752
73837
|
const { state, reason } = classifySkill(local, remote, baseline);
|
|
73753
73838
|
let { action, reason: actionReason } = resolveAction(state, direction, conflict);
|
|
73754
73839
|
if (state === "remote-only" && isDigestless(remote)) {
|
|
@@ -73807,7 +73892,7 @@ async function reconcileRegistry(options = {}) {
|
|
|
73807
73892
|
try {
|
|
73808
73893
|
await pushSkill(slug, { rootDir: root, client });
|
|
73809
73894
|
const pushed = locals.get(slug);
|
|
73810
|
-
writePullMarker(
|
|
73895
|
+
writePullMarker(join32(root, slug), {
|
|
73811
73896
|
skill: slug,
|
|
73812
73897
|
...pushed?.version ? { version: pushed.version } : {},
|
|
73813
73898
|
...pushed?.sha256 ? { contentHash: pushed.sha256 } : {},
|
|
@@ -73879,7 +73964,7 @@ async function reconcileRegistry(options = {}) {
|
|
|
73879
73964
|
runCount: readCursor(root).runCount + 1,
|
|
73880
73965
|
summary
|
|
73881
73966
|
};
|
|
73882
|
-
writeFileSync19(
|
|
73967
|
+
writeFileSync19(join32(root, SYNC_CURSOR_FILE), `${JSON.stringify(cursor, null, 2)}
|
|
73883
73968
|
`);
|
|
73884
73969
|
return {
|
|
73885
73970
|
corpusRoot: root,
|