@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/mcp.js
CHANGED
|
@@ -6905,24 +6905,24 @@ __export(exports_auth_store, {
|
|
|
6905
6905
|
getApiKey: () => getApiKey,
|
|
6906
6906
|
clearAuthConfig: () => clearAuthConfig
|
|
6907
6907
|
});
|
|
6908
|
-
import { existsSync as
|
|
6909
|
-
import { dirname as dirname5, join as
|
|
6908
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync11, writeFileSync as writeFileSync6, unlinkSync } from "fs";
|
|
6909
|
+
import { dirname as dirname5, join as join12 } from "path";
|
|
6910
6910
|
import { homedir as homedir3 } from "os";
|
|
6911
6911
|
function getAuthFilePath() {
|
|
6912
|
-
return
|
|
6912
|
+
return join12(getDataDir(), "auth.json");
|
|
6913
6913
|
}
|
|
6914
6914
|
function getAuthFilePathReadOnly() {
|
|
6915
|
-
return
|
|
6915
|
+
return join12(getDataDirReadOnly(), "auth.json");
|
|
6916
6916
|
}
|
|
6917
6917
|
function legacyAuthFilePath() {
|
|
6918
|
-
return
|
|
6918
|
+
return join12(process.env["HOME"] || process.env["USERPROFILE"] || homedir3(), ".skills", "auth.json");
|
|
6919
6919
|
}
|
|
6920
6920
|
function getAuthConfig() {
|
|
6921
6921
|
if (cachedConfig !== undefined)
|
|
6922
6922
|
return cachedConfig;
|
|
6923
6923
|
try {
|
|
6924
|
-
const file =
|
|
6925
|
-
const raw =
|
|
6924
|
+
const file = existsSync12(getAuthFilePath()) ? getAuthFilePath() : legacyAuthFilePath();
|
|
6925
|
+
const raw = readFileSync11(file, "utf-8");
|
|
6926
6926
|
const config2 = JSON.parse(raw);
|
|
6927
6927
|
if (!config2.apiKey) {
|
|
6928
6928
|
cachedConfig = null;
|
|
@@ -6960,8 +6960,8 @@ function getApiKey() {
|
|
|
6960
6960
|
}
|
|
6961
6961
|
function getAuthConfigReadOnly() {
|
|
6962
6962
|
try {
|
|
6963
|
-
const file =
|
|
6964
|
-
const raw =
|
|
6963
|
+
const file = existsSync12(getAuthFilePathReadOnly()) ? getAuthFilePathReadOnly() : legacyAuthFilePath();
|
|
6964
|
+
const raw = readFileSync11(file, "utf-8");
|
|
6965
6965
|
const config2 = JSON.parse(raw);
|
|
6966
6966
|
if (!config2.apiKey)
|
|
6967
6967
|
return null;
|
|
@@ -12943,7 +12943,7 @@ class StdioServerTransport {
|
|
|
12943
12943
|
// package.json
|
|
12944
12944
|
var package_default = {
|
|
12945
12945
|
name: "@hasna/skills",
|
|
12946
|
-
version: "0.1.
|
|
12946
|
+
version: "0.1.66",
|
|
12947
12947
|
description: "Skills library for AI coding agents",
|
|
12948
12948
|
type: "module",
|
|
12949
12949
|
bin: {
|
|
@@ -20879,22 +20879,23 @@ var EMPTY_COMPLETION_RESULT = {
|
|
|
20879
20879
|
|
|
20880
20880
|
// src/lib/registry.ts
|
|
20881
20881
|
init_config();
|
|
20882
|
-
import { existsSync as
|
|
20883
|
-
import { join as
|
|
20882
|
+
import { existsSync as existsSync7, readFileSync as readFileSync6, readdirSync as readdirSync6 } from "fs";
|
|
20883
|
+
import { join as join7 } from "path";
|
|
20884
20884
|
|
|
20885
20885
|
// src/lib/portable-skills.ts
|
|
20886
20886
|
init_config();
|
|
20887
20887
|
import {
|
|
20888
20888
|
cpSync as cpSync2,
|
|
20889
|
-
existsSync as
|
|
20889
|
+
existsSync as existsSync6,
|
|
20890
20890
|
mkdirSync as mkdirSync3,
|
|
20891
|
-
|
|
20891
|
+
mkdtempSync,
|
|
20892
|
+
readdirSync as readdirSync5,
|
|
20892
20893
|
renameSync,
|
|
20893
20894
|
rmSync,
|
|
20894
|
-
statSync as
|
|
20895
|
+
statSync as statSync6,
|
|
20895
20896
|
writeFileSync as writeFileSync3
|
|
20896
20897
|
} from "fs";
|
|
20897
|
-
import { basename as basename2, dirname as dirname3, isAbsolute as isAbsolute2, join as
|
|
20898
|
+
import { basename as basename2, dirname as dirname3, isAbsolute as isAbsolute2, join as join6, normalize as normalize2 } from "path";
|
|
20898
20899
|
|
|
20899
20900
|
// src/lib/registry-data/development-tools.ts
|
|
20900
20901
|
var DEVELOPMENT_TOOLS_SKILLS = [
|
|
@@ -21605,11 +21606,9 @@ var SKILLS = [
|
|
|
21605
21606
|
...EVENT_MANAGEMENT_SKILLS
|
|
21606
21607
|
];
|
|
21607
21608
|
|
|
21608
|
-
// src/lib/skill-validation.ts
|
|
21609
|
-
import { existsSync as existsSync2, lstatSync, readFileSync as readFileSync2, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
21610
|
-
import { isAbsolute, join as join2, normalize } from "path";
|
|
21611
|
-
|
|
21612
21609
|
// src/lib/hosted-skill-set.ts
|
|
21610
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
21611
|
+
import { join as join2 } from "path";
|
|
21613
21612
|
var HOSTED_RUNTIMES = new Set(["hosted"]);
|
|
21614
21613
|
var HOSTED_SOURCES = new Set(["remote", "private-hosted"]);
|
|
21615
21614
|
function normalizeMarker(value) {
|
|
@@ -21621,6 +21620,16 @@ function isHostedMetadataPackage(pkg) {
|
|
|
21621
21620
|
return false;
|
|
21622
21621
|
return HOSTED_RUNTIMES.has(normalizeMarker(skills.runtime)) || HOSTED_SOURCES.has(normalizeMarker(skills.source));
|
|
21623
21622
|
}
|
|
21623
|
+
function isHostedMetadataSkillDir(skillDir) {
|
|
21624
|
+
const pkgPath = join2(skillDir, "package.json");
|
|
21625
|
+
if (!existsSync2(pkgPath))
|
|
21626
|
+
return false;
|
|
21627
|
+
try {
|
|
21628
|
+
return isHostedMetadataPackage(JSON.parse(readFileSync2(pkgPath, "utf8")));
|
|
21629
|
+
} catch {
|
|
21630
|
+
return false;
|
|
21631
|
+
}
|
|
21632
|
+
}
|
|
21624
21633
|
var HOSTED_METADATA_SET_EMPTY_ERROR = [
|
|
21625
21634
|
"The hosted metadata skill set is empty, but the packaging guards that depend on it",
|
|
21626
21635
|
"only mean anything while it is non-empty: an empty set makes every one of them pass",
|
|
@@ -21637,6 +21646,8 @@ var BRACE_SOURCE_EXCLUSION = new RegExp(`^!skills/\\{(${SLUG}(?:,${SLUG})+)\\}/s
|
|
|
21637
21646
|
var SINGLE_SOURCE_EXCLUSION = new RegExp(`^!skills/(${SLUG})/src$`);
|
|
21638
21647
|
|
|
21639
21648
|
// src/lib/skill-validation.ts
|
|
21649
|
+
import { existsSync as existsSync3, lstatSync, readFileSync as readFileSync3, readdirSync as readdirSync3, statSync as statSync3 } from "fs";
|
|
21650
|
+
import { isAbsolute, join as join3, normalize } from "path";
|
|
21640
21651
|
var VALID_SKILL_KINDS = ["executable", "instruction"];
|
|
21641
21652
|
var DOC_FILES = ["SKILL.md", "README.md", "CLAUDE.md"];
|
|
21642
21653
|
var RESERVED_SKILL_ENTRIES = new Set([
|
|
@@ -21690,7 +21701,7 @@ function add(target, code, message) {
|
|
|
21690
21701
|
target.push({ code, message });
|
|
21691
21702
|
}
|
|
21692
21703
|
function readJsonFile(path) {
|
|
21693
|
-
return JSON.parse(
|
|
21704
|
+
return JSON.parse(readFileSync3(path, "utf-8"));
|
|
21694
21705
|
}
|
|
21695
21706
|
function asRecord(value) {
|
|
21696
21707
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
|
|
@@ -21774,7 +21785,7 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
21774
21785
|
binCommands: [],
|
|
21775
21786
|
docFiles: []
|
|
21776
21787
|
};
|
|
21777
|
-
if (!
|
|
21788
|
+
if (!existsSync3(skillPath)) {
|
|
21778
21789
|
add(issues, "skill.dir_missing", `Skill directory not found: ${skillPath}`);
|
|
21779
21790
|
return {
|
|
21780
21791
|
name: bareName,
|
|
@@ -21788,8 +21799,8 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
21788
21799
|
if (!VALID_BIN_COMMAND.test(bareName)) {
|
|
21789
21800
|
add(issues, "skill.name_invalid", `Skill name '${bareName}' must use lowercase letters, numbers, dots, underscores, or hyphens`);
|
|
21790
21801
|
}
|
|
21791
|
-
for (const entry of
|
|
21792
|
-
const entryPath =
|
|
21802
|
+
for (const entry of readdirSync3(skillPath).sort()) {
|
|
21803
|
+
const entryPath = join3(skillPath, entry);
|
|
21793
21804
|
if (RESERVED_SKILL_ENTRIES.has(entry)) {
|
|
21794
21805
|
add(issues, "skill.reserved_file", `Reserved file '${entry}' is not allowed in skill packages`);
|
|
21795
21806
|
}
|
|
@@ -21801,15 +21812,15 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
21801
21812
|
}
|
|
21802
21813
|
}
|
|
21803
21814
|
for (const docFile of DOC_FILES) {
|
|
21804
|
-
if (
|
|
21815
|
+
if (existsSync3(join3(skillPath, docFile)))
|
|
21805
21816
|
metadata.docFiles.push(docFile);
|
|
21806
21817
|
}
|
|
21807
21818
|
if (metadata.docFiles.length === 0) {
|
|
21808
21819
|
add(issues, "skill.docs_missing", "Missing documentation file: expected SKILL.md, README.md, or CLAUDE.md");
|
|
21809
21820
|
}
|
|
21810
|
-
const skillMdPath =
|
|
21811
|
-
if (
|
|
21812
|
-
const frontmatter = parseSkillFrontmatter(
|
|
21821
|
+
const skillMdPath = join3(skillPath, "SKILL.md");
|
|
21822
|
+
if (existsSync3(skillMdPath)) {
|
|
21823
|
+
const frontmatter = parseSkillFrontmatter(readFileSync3(skillMdPath, "utf-8"));
|
|
21813
21824
|
if (!frontmatter) {
|
|
21814
21825
|
add(warnings, "skill.frontmatter_missing", "SKILL.md has no YAML frontmatter");
|
|
21815
21826
|
} else {
|
|
@@ -21851,8 +21862,8 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
21851
21862
|
}
|
|
21852
21863
|
metadata.kind = resolvedKind;
|
|
21853
21864
|
const isInstruction = resolvedKind === "instruction";
|
|
21854
|
-
const pkgPath =
|
|
21855
|
-
if (!
|
|
21865
|
+
const pkgPath = join3(skillPath, "package.json");
|
|
21866
|
+
if (!existsSync3(pkgPath)) {
|
|
21856
21867
|
if (!isInstruction)
|
|
21857
21868
|
add(issues, "package.missing", "Missing package.json");
|
|
21858
21869
|
} else {
|
|
@@ -21910,10 +21921,10 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
21910
21921
|
add(issues, "package.bin_target_unsafe", `package.json bin '${command}' target '${target}' must stay inside the skill directory`);
|
|
21911
21922
|
continue;
|
|
21912
21923
|
}
|
|
21913
|
-
const targetPath =
|
|
21914
|
-
if (!
|
|
21924
|
+
const targetPath = join3(skillPath, target);
|
|
21925
|
+
if (!existsSync3(targetPath)) {
|
|
21915
21926
|
add(warnings, "package.bin_target_missing", `package.json bin '${command}' target '${target}' is not present before build`);
|
|
21916
|
-
} else if (
|
|
21927
|
+
} else if (statSync3(targetPath).isDirectory()) {
|
|
21917
21928
|
add(issues, "package.bin_target_directory", `package.json bin '${command}' target '${target}' must point to a file, not a directory`);
|
|
21918
21929
|
}
|
|
21919
21930
|
}
|
|
@@ -21928,18 +21939,18 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
21928
21939
|
metadata.runtime = "none";
|
|
21929
21940
|
} else {
|
|
21930
21941
|
metadata.runtime = hostedMetadata ? "hosted" : "local";
|
|
21931
|
-
const srcDir =
|
|
21942
|
+
const srcDir = join3(skillPath, "src");
|
|
21932
21943
|
if (hostedMetadata) {
|
|
21933
|
-
if (
|
|
21944
|
+
if (existsSync3(srcDir)) {
|
|
21934
21945
|
add(issues, "skill.hosted_source_forbidden", "Hosted metadata skills must not include local implementation source");
|
|
21935
21946
|
}
|
|
21936
|
-
} else if (!
|
|
21947
|
+
} else if (!existsSync3(srcDir)) {
|
|
21937
21948
|
add(issues, "skill.src_missing", "Missing src/ directory");
|
|
21938
|
-
} else if (!
|
|
21949
|
+
} else if (!existsSync3(join3(srcDir, "index.ts")) && !existsSync3(join3(srcDir, "index.js"))) {
|
|
21939
21950
|
add(issues, "skill.src_index_missing", "Missing src/index.ts or src/index.js");
|
|
21940
21951
|
} else {
|
|
21941
|
-
const indexPath =
|
|
21942
|
-
const size =
|
|
21952
|
+
const indexPath = existsSync3(join3(srcDir, "index.ts")) ? join3(srcDir, "index.ts") : join3(srcDir, "index.js");
|
|
21953
|
+
const size = statSync3(indexPath).size;
|
|
21943
21954
|
if (size < 50)
|
|
21944
21955
|
add(warnings, "skill.src_index_minimal", `Source entry point is very small (${size}B)`);
|
|
21945
21956
|
}
|
|
@@ -21956,8 +21967,8 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
21956
21967
|
|
|
21957
21968
|
// src/lib/skill-hash.ts
|
|
21958
21969
|
import { createHash } from "crypto";
|
|
21959
|
-
import { existsSync as
|
|
21960
|
-
import { join as
|
|
21970
|
+
import { existsSync as existsSync4, readdirSync as readdirSync4, readFileSync as readFileSync4, statSync as statSync4 } from "fs";
|
|
21971
|
+
import { join as join4, sep } from "path";
|
|
21961
21972
|
var CONTENT_HASH_ALGORITHM = "sha256";
|
|
21962
21973
|
var HASH_EXCLUDE_DIRS = new Set([".git", "node_modules", "dist", "build", ".turbo"]);
|
|
21963
21974
|
var HASH_COVERAGE = [
|
|
@@ -22016,10 +22027,10 @@ function collectBundleFiles(skillPath) {
|
|
|
22016
22027
|
if (seen.has(entry))
|
|
22017
22028
|
continue;
|
|
22018
22029
|
seen.add(entry);
|
|
22019
|
-
const absolute =
|
|
22020
|
-
if (!
|
|
22030
|
+
const absolute = join4(skillPath, entry);
|
|
22031
|
+
if (!existsSync4(absolute))
|
|
22021
22032
|
continue;
|
|
22022
|
-
if (
|
|
22033
|
+
if (statSync4(absolute).isDirectory())
|
|
22023
22034
|
collectDirectory(files, absolute, entry);
|
|
22024
22035
|
else
|
|
22025
22036
|
collectFile(files, absolute, entry);
|
|
@@ -22027,14 +22038,14 @@ function collectBundleFiles(skillPath) {
|
|
|
22027
22038
|
return files.sort((a, b) => a.rel < b.rel ? -1 : a.rel > b.rel ? 1 : 0);
|
|
22028
22039
|
}
|
|
22029
22040
|
function collectDirectory(files, dir, rel) {
|
|
22030
|
-
for (const entry of
|
|
22041
|
+
for (const entry of readdirSync4(dir).sort()) {
|
|
22031
22042
|
if (entry.startsWith("."))
|
|
22032
22043
|
continue;
|
|
22033
|
-
const absolute =
|
|
22044
|
+
const absolute = join4(dir, entry);
|
|
22034
22045
|
const childRel = `${rel}/${entry}`;
|
|
22035
22046
|
let stats;
|
|
22036
22047
|
try {
|
|
22037
|
-
stats =
|
|
22048
|
+
stats = statSync4(absolute);
|
|
22038
22049
|
} catch {
|
|
22039
22050
|
continue;
|
|
22040
22051
|
}
|
|
@@ -22050,7 +22061,7 @@ function collectDirectory(files, dir, rel) {
|
|
|
22050
22061
|
}
|
|
22051
22062
|
}
|
|
22052
22063
|
function collectFile(files, absolute, rel) {
|
|
22053
|
-
const buffer =
|
|
22064
|
+
const buffer = readFileSync4(absolute);
|
|
22054
22065
|
if (rel === "skill.json") {
|
|
22055
22066
|
files.push({ rel: rel.split(sep).join("/"), content: new TextEncoder().encode(canonicalizeManifest(new TextDecoder().decode(buffer))) });
|
|
22056
22067
|
return;
|
|
@@ -22250,14 +22261,14 @@ function validateRuntimeContract(manifest, issues, strict) {
|
|
|
22250
22261
|
// src/lib/portable-skills-files.ts
|
|
22251
22262
|
import {
|
|
22252
22263
|
cpSync,
|
|
22253
|
-
existsSync as
|
|
22264
|
+
existsSync as existsSync5,
|
|
22254
22265
|
lstatSync as lstatSync2,
|
|
22255
22266
|
mkdirSync as mkdirSync2,
|
|
22256
|
-
readFileSync as
|
|
22267
|
+
readFileSync as readFileSync5,
|
|
22257
22268
|
realpathSync,
|
|
22258
22269
|
writeFileSync as writeFileSync2
|
|
22259
22270
|
} from "fs";
|
|
22260
|
-
import { basename, dirname as dirname2, join as
|
|
22271
|
+
import { basename, dirname as dirname2, join as join5, relative } from "path";
|
|
22261
22272
|
var ANY_SEGMENT_COPY_EXCLUDES = new Set([
|
|
22262
22273
|
".git",
|
|
22263
22274
|
".DS_Store",
|
|
@@ -22300,12 +22311,12 @@ function normalizePortableSkillName(name) {
|
|
|
22300
22311
|
return normalized;
|
|
22301
22312
|
}
|
|
22302
22313
|
function readPortableSkillManifest(skillPath, fallbackName = basename(skillPath)) {
|
|
22303
|
-
const skillJsonPath =
|
|
22304
|
-
const skillMdPath =
|
|
22305
|
-
const pkgPath =
|
|
22306
|
-
const jsonManifest =
|
|
22307
|
-
const frontmatter =
|
|
22308
|
-
const pkg =
|
|
22314
|
+
const skillJsonPath = join5(skillPath, "skill.json");
|
|
22315
|
+
const skillMdPath = join5(skillPath, "SKILL.md");
|
|
22316
|
+
const pkgPath = join5(skillPath, "package.json");
|
|
22317
|
+
const jsonManifest = existsSync5(skillJsonPath) ? readJsonObject(skillJsonPath) : undefined;
|
|
22318
|
+
const frontmatter = existsSync5(skillMdPath) ? parseSkillFrontmatter(readFileSync5(skillMdPath, "utf-8")) ?? undefined : undefined;
|
|
22319
|
+
const pkg = existsSync5(pkgPath) ? readJsonObject(pkgPath) : undefined;
|
|
22309
22320
|
const name = normalizePortableSkillName(stringField(jsonManifest, "name") ?? frontmatter?.name ?? stringValue(pkg?.name) ?? fallbackName);
|
|
22310
22321
|
const description = stringField(jsonManifest, "description") ?? frontmatter?.description ?? stringValue(pkg?.description) ?? `${name} skill`;
|
|
22311
22322
|
const version2 = stringField(jsonManifest, "version") ?? frontmatter?.version ?? stringValue(pkg?.version) ?? PORTABLE_SKILL_DEFAULT_VERSION;
|
|
@@ -22351,7 +22362,7 @@ function createInstructionManifest(name, options) {
|
|
|
22351
22362
|
}
|
|
22352
22363
|
function writeInstructionSkillTemplate(skillPath, manifest) {
|
|
22353
22364
|
mkdirSync2(skillPath, { recursive: true });
|
|
22354
|
-
writeFileSync2(
|
|
22365
|
+
writeFileSync2(join5(skillPath, "SKILL.md"), renderInstructionSkillMd(manifest));
|
|
22355
22366
|
writeSkillJsonWithHash(skillPath, manifest);
|
|
22356
22367
|
}
|
|
22357
22368
|
function renderInstructionSkillMd(manifest) {
|
|
@@ -22400,12 +22411,12 @@ function createPortableManifest(name, options) {
|
|
|
22400
22411
|
};
|
|
22401
22412
|
}
|
|
22402
22413
|
function writePortableSkillTemplate(skillPath, manifest) {
|
|
22403
|
-
mkdirSync2(
|
|
22404
|
-
writeFileSync2(
|
|
22405
|
-
writeFileSync2(
|
|
22406
|
-
writeFileSync2(
|
|
22407
|
-
writeFileSync2(
|
|
22408
|
-
writeFileSync2(
|
|
22414
|
+
mkdirSync2(join5(skillPath, "src"), { recursive: true });
|
|
22415
|
+
writeFileSync2(join5(skillPath, "SKILL.md"), renderSkillMd(manifest));
|
|
22416
|
+
writeFileSync2(join5(skillPath, "AGENTS.md"), renderAgentsMd(manifest));
|
|
22417
|
+
writeFileSync2(join5(skillPath, "package.json"), renderPackageJson(manifest));
|
|
22418
|
+
writeFileSync2(join5(skillPath, "tsconfig.json"), renderTsconfig());
|
|
22419
|
+
writeFileSync2(join5(skillPath, "src", "index.ts"), renderEntrypoint(manifest));
|
|
22409
22420
|
writeSkillJsonWithHash(skillPath, manifest);
|
|
22410
22421
|
}
|
|
22411
22422
|
function fillContractDefaults(manifest, entrypoint) {
|
|
@@ -22430,7 +22441,7 @@ function writeSkillJsonWithHash(skillPath, manifest) {
|
|
|
22430
22441
|
content_hash: undefined
|
|
22431
22442
|
}
|
|
22432
22443
|
};
|
|
22433
|
-
writeFileSync2(
|
|
22444
|
+
writeFileSync2(join5(skillPath, "skill.json"), `${JSON.stringify({ ...existing, ...renderSkillJsonObject(withoutHash) }, null, 2)}
|
|
22434
22445
|
`);
|
|
22435
22446
|
const hash = computeContentHash(skillPath);
|
|
22436
22447
|
const withHash = {
|
|
@@ -22440,16 +22451,16 @@ function writeSkillJsonWithHash(skillPath, manifest) {
|
|
|
22440
22451
|
content_hash: hash
|
|
22441
22452
|
}
|
|
22442
22453
|
};
|
|
22443
|
-
writeFileSync2(
|
|
22454
|
+
writeFileSync2(join5(skillPath, "skill.json"), `${JSON.stringify({ ...existing, ...renderSkillJsonObject(withHash) }, null, 2)}
|
|
22444
22455
|
`);
|
|
22445
22456
|
return withHash;
|
|
22446
22457
|
}
|
|
22447
22458
|
function readExistingSkillJson(skillPath) {
|
|
22448
|
-
const path =
|
|
22449
|
-
if (!
|
|
22459
|
+
const path = join5(skillPath, "skill.json");
|
|
22460
|
+
if (!existsSync5(path))
|
|
22450
22461
|
return {};
|
|
22451
22462
|
try {
|
|
22452
|
-
const parsed = JSON.parse(
|
|
22463
|
+
const parsed = JSON.parse(readFileSync5(path, "utf-8"));
|
|
22453
22464
|
return isRecord2(parsed) ? parsed : {};
|
|
22454
22465
|
} catch {
|
|
22455
22466
|
return {};
|
|
@@ -22479,28 +22490,28 @@ function ensurePortableSkillFiles(skillPath, manifest) {
|
|
|
22479
22490
|
tags: next.tags?.length ? next.tags : ["custom", next.name]
|
|
22480
22491
|
};
|
|
22481
22492
|
const entry = next.commands[0]?.entry ?? "src/index.ts";
|
|
22482
|
-
if (entry && !
|
|
22483
|
-
mkdirSync2(dirname2(
|
|
22484
|
-
writeFileSync2(
|
|
22493
|
+
if (entry && !existsSync5(join5(skillPath, entry))) {
|
|
22494
|
+
mkdirSync2(dirname2(join5(skillPath, entry)), { recursive: true });
|
|
22495
|
+
writeFileSync2(join5(skillPath, entry), renderEntrypoint(next));
|
|
22485
22496
|
}
|
|
22486
|
-
if (!
|
|
22487
|
-
writeFileSync2(
|
|
22497
|
+
if (!existsSync5(join5(skillPath, "SKILL.md")))
|
|
22498
|
+
writeFileSync2(join5(skillPath, "SKILL.md"), renderSkillMd(next));
|
|
22488
22499
|
else
|
|
22489
|
-
writeFileSync2(
|
|
22490
|
-
if (!
|
|
22491
|
-
writeFileSync2(
|
|
22500
|
+
writeFileSync2(join5(skillPath, "SKILL.md"), ensureSkillMdFrontmatter(readFileSync5(join5(skillPath, "SKILL.md"), "utf-8"), next));
|
|
22501
|
+
if (!existsSync5(join5(skillPath, "AGENTS.md")))
|
|
22502
|
+
writeFileSync2(join5(skillPath, "AGENTS.md"), renderAgentsMd(next));
|
|
22492
22503
|
ensurePackageJson(skillPath, next);
|
|
22493
|
-
if (!
|
|
22494
|
-
writeFileSync2(
|
|
22504
|
+
if (!existsSync5(join5(skillPath, "tsconfig.json")))
|
|
22505
|
+
writeFileSync2(join5(skillPath, "tsconfig.json"), renderTsconfig());
|
|
22495
22506
|
writeSkillJsonWithHash(skillPath, next);
|
|
22496
22507
|
return readPortableSkillManifest(skillPath, next.name);
|
|
22497
22508
|
}
|
|
22498
22509
|
function ensurePackageJson(skillPath, manifest) {
|
|
22499
|
-
const pkgPath =
|
|
22510
|
+
const pkgPath = join5(skillPath, "package.json");
|
|
22500
22511
|
const first = manifest.commands[0] ?? { name: manifest.name, entry: "src/index.ts" };
|
|
22501
22512
|
const commandName = normalizePortableSkillName(first.name || manifest.name);
|
|
22502
22513
|
const entry = (first.entry ?? "src/index.ts").replace(/^\.\//, "");
|
|
22503
|
-
if (!
|
|
22514
|
+
if (!existsSync5(pkgPath)) {
|
|
22504
22515
|
writeFileSync2(pkgPath, renderPackageJson(manifest));
|
|
22505
22516
|
return;
|
|
22506
22517
|
}
|
|
@@ -22543,8 +22554,8 @@ function ensureInstructionSkillFiles(skillPath, manifest) {
|
|
|
22543
22554
|
inputs: [],
|
|
22544
22555
|
commands: []
|
|
22545
22556
|
};
|
|
22546
|
-
if (!
|
|
22547
|
-
writeFileSync2(
|
|
22557
|
+
if (!existsSync5(join5(skillPath, "SKILL.md"))) {
|
|
22558
|
+
writeFileSync2(join5(skillPath, "SKILL.md"), renderSkillMd(next));
|
|
22548
22559
|
}
|
|
22549
22560
|
writeSkillJsonWithHash(skillPath, next);
|
|
22550
22561
|
return readPortableSkillManifest(skillPath, next.name);
|
|
@@ -22795,7 +22806,7 @@ function inferPackageCommands(pkg, fallbackName) {
|
|
|
22795
22806
|
return;
|
|
22796
22807
|
}
|
|
22797
22808
|
function readJsonObject(path) {
|
|
22798
|
-
const parsed = JSON.parse(
|
|
22809
|
+
const parsed = JSON.parse(readFileSync5(path, "utf-8"));
|
|
22799
22810
|
if (!isRecord2(parsed))
|
|
22800
22811
|
throw new Error(`${basename(path)} must contain a JSON object`);
|
|
22801
22812
|
return parsed;
|
|
@@ -22827,36 +22838,36 @@ var LEGACY_CUSTOM_DIRNAME = "custom";
|
|
|
22827
22838
|
function getPortableSkillsRoot(options = {}) {
|
|
22828
22839
|
if (options.rootDir)
|
|
22829
22840
|
return options.rootDir;
|
|
22830
|
-
const appDir = options.homeDir ?
|
|
22831
|
-
const cache =
|
|
22841
|
+
const appDir = options.homeDir ? join6(options.homeDir, ".hasna", "skills") : getDataDir();
|
|
22842
|
+
const cache = join6(appDir, SKILLS_CACHE_DIRNAME);
|
|
22832
22843
|
if (isOwnerLayoutMigrated(appDir) && safeIsDirectory(cache))
|
|
22833
22844
|
return cache;
|
|
22834
|
-
const installed =
|
|
22845
|
+
const installed = join6(appDir, INSTALLED_SKILLS_DIRNAME);
|
|
22835
22846
|
migrateLegacySkillLayout(appDir, installed);
|
|
22836
22847
|
return installed;
|
|
22837
22848
|
}
|
|
22838
22849
|
function looksLikeSkillDirectory(path) {
|
|
22839
22850
|
if (!safeIsDirectory(path))
|
|
22840
22851
|
return false;
|
|
22841
|
-
return
|
|
22852
|
+
return existsSync6(join6(path, "SKILL.md")) || existsSync6(join6(path, "skill.json")) || existsSync6(join6(path, "package.json"));
|
|
22842
22853
|
}
|
|
22843
22854
|
function migrateLegacySkillLayout(appDir, installed) {
|
|
22844
22855
|
if (!safeIsDirectory(appDir))
|
|
22845
22856
|
return;
|
|
22846
22857
|
const candidates = [];
|
|
22847
22858
|
try {
|
|
22848
|
-
for (const entry of
|
|
22859
|
+
for (const entry of readdirSync5(appDir)) {
|
|
22849
22860
|
if (entry.startsWith(".") || entry === INSTALLED_SKILLS_DIRNAME)
|
|
22850
22861
|
continue;
|
|
22851
|
-
const path =
|
|
22862
|
+
const path = join6(appDir, entry);
|
|
22852
22863
|
if (entry === LEGACY_CUSTOM_DIRNAME) {
|
|
22853
22864
|
if (!safeIsDirectory(path))
|
|
22854
22865
|
continue;
|
|
22855
22866
|
try {
|
|
22856
|
-
for (const nested of
|
|
22867
|
+
for (const nested of readdirSync5(path)) {
|
|
22857
22868
|
if (nested.startsWith("."))
|
|
22858
22869
|
continue;
|
|
22859
|
-
const nestedPath =
|
|
22870
|
+
const nestedPath = join6(path, nested);
|
|
22860
22871
|
if (looksLikeSkillDirectory(nestedPath))
|
|
22861
22872
|
candidates.push({ from: nestedPath, name: nested });
|
|
22862
22873
|
}
|
|
@@ -22870,10 +22881,10 @@ function migrateLegacySkillLayout(appDir, installed) {
|
|
|
22870
22881
|
return;
|
|
22871
22882
|
}
|
|
22872
22883
|
for (const { from, name } of candidates) {
|
|
22873
|
-
const target =
|
|
22874
|
-
if (
|
|
22884
|
+
const target = join6(installed, name);
|
|
22885
|
+
if (existsSync6(target))
|
|
22875
22886
|
continue;
|
|
22876
|
-
const staging =
|
|
22887
|
+
const staging = join6(installed, `.migrating-${name}-${process.pid}`);
|
|
22877
22888
|
try {
|
|
22878
22889
|
rmSync(staging, { recursive: true, force: true });
|
|
22879
22890
|
cpSync2(from, staging, { recursive: true, errorOnExist: false });
|
|
@@ -22886,7 +22897,7 @@ function migrateLegacySkillLayout(appDir, installed) {
|
|
|
22886
22897
|
}
|
|
22887
22898
|
}
|
|
22888
22899
|
function getPortableSkillPath(name, options = {}) {
|
|
22889
|
-
return
|
|
22900
|
+
return join6(getPortableSkillsRoot(options), normalizePortableSkillName(name));
|
|
22890
22901
|
}
|
|
22891
22902
|
function findPortableSkill(name, options = {}) {
|
|
22892
22903
|
let normalized;
|
|
@@ -22896,7 +22907,7 @@ function findPortableSkill(name, options = {}) {
|
|
|
22896
22907
|
return null;
|
|
22897
22908
|
}
|
|
22898
22909
|
const path = getPortableSkillPath(normalized, options);
|
|
22899
|
-
if (!
|
|
22910
|
+
if (!existsSync6(path) || !statSync6(path).isDirectory())
|
|
22900
22911
|
return null;
|
|
22901
22912
|
try {
|
|
22902
22913
|
return summarizePortableSkill(path, normalized);
|
|
@@ -22909,10 +22920,10 @@ function listPortableSkills(options = {}) {
|
|
|
22909
22920
|
if (!safeIsDirectory(root))
|
|
22910
22921
|
return [];
|
|
22911
22922
|
const skills = [];
|
|
22912
|
-
for (const entry of
|
|
22923
|
+
for (const entry of readdirSync5(root).sort()) {
|
|
22913
22924
|
if (entry.startsWith("."))
|
|
22914
22925
|
continue;
|
|
22915
|
-
const path =
|
|
22926
|
+
const path = join6(root, entry);
|
|
22916
22927
|
if (!safeIsDirectory(path))
|
|
22917
22928
|
continue;
|
|
22918
22929
|
try {
|
|
@@ -22934,7 +22945,8 @@ function listPortableSkillMetas(options = {}) {
|
|
|
22934
22945
|
tags: manifest.tags || ["custom"],
|
|
22935
22946
|
version: skill.version,
|
|
22936
22947
|
...manifest.kind ? { kind: manifest.kind } : {},
|
|
22937
|
-
source: "custom"
|
|
22948
|
+
source: "custom",
|
|
22949
|
+
...isHostedMetadataSkillDir(skill.path) ? { serverOwned: true } : {}
|
|
22938
22950
|
};
|
|
22939
22951
|
});
|
|
22940
22952
|
}
|
|
@@ -22945,8 +22957,8 @@ function isOfficialSkillName(name) {
|
|
|
22945
22957
|
function scaffoldPortableSkill(name, options = {}) {
|
|
22946
22958
|
const skillName = normalizePortableSkillName(name);
|
|
22947
22959
|
const root = getPortableSkillsRoot(options);
|
|
22948
|
-
const skillPath =
|
|
22949
|
-
if (
|
|
22960
|
+
const skillPath = join6(root, skillName);
|
|
22961
|
+
if (existsSync6(skillPath)) {
|
|
22950
22962
|
if (!options.overwrite)
|
|
22951
22963
|
throw new Error(`Skill '${skillName}' already exists at ${skillPath}`);
|
|
22952
22964
|
rmSync(skillPath, { recursive: true, force: true });
|
|
@@ -22964,7 +22976,7 @@ function scaffoldPortableSkill(name, options = {}) {
|
|
|
22964
22976
|
}
|
|
22965
22977
|
function portPortableSkill(sourcePath, options = {}) {
|
|
22966
22978
|
const absoluteSource = normalize2(sourcePath);
|
|
22967
|
-
if (!
|
|
22979
|
+
if (!existsSync6(absoluteSource) || !statSync6(absoluteSource).isDirectory()) {
|
|
22968
22980
|
throw new Error(`Skill source directory not found: ${sourcePath}`);
|
|
22969
22981
|
}
|
|
22970
22982
|
const inferred = readPortableSkillManifest(absoluteSource, basename2(absoluteSource));
|
|
@@ -22976,8 +22988,8 @@ function portPortableSkill(sourcePath, options = {}) {
|
|
|
22976
22988
|
throw new Error(`${via} Importing it would shadow the official '${skillName}'. ` + `Pass --name to choose a different name, or --allow-shadow to override deliberately.`);
|
|
22977
22989
|
}
|
|
22978
22990
|
const root = getPortableSkillsRoot(options);
|
|
22979
|
-
const destination =
|
|
22980
|
-
if (
|
|
22991
|
+
const destination = join6(root, skillName);
|
|
22992
|
+
if (existsSync6(destination)) {
|
|
22981
22993
|
if (!options.overwrite)
|
|
22982
22994
|
throw new Error(`Skill '${skillName}' already exists at ${destination}`);
|
|
22983
22995
|
rmSync(destination, { recursive: true, force: true });
|
|
@@ -23005,10 +23017,10 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
23005
23017
|
const issues = [...base.issues];
|
|
23006
23018
|
const warnings = [...base.warnings];
|
|
23007
23019
|
let manifest;
|
|
23008
|
-
if (
|
|
23009
|
-
const skillJsonPath =
|
|
23010
|
-
const skillMdPath =
|
|
23011
|
-
if (!
|
|
23020
|
+
if (existsSync6(skillPath)) {
|
|
23021
|
+
const skillJsonPath = join6(skillPath, "skill.json");
|
|
23022
|
+
const skillMdPath = join6(skillPath, "SKILL.md");
|
|
23023
|
+
if (!existsSync6(skillJsonPath) && !existsSync6(skillMdPath)) {
|
|
23012
23024
|
add3(issues, "portable.manifest_missing", "Missing portable manifest: expected SKILL.md frontmatter and/or skill.json");
|
|
23013
23025
|
}
|
|
23014
23026
|
try {
|
|
@@ -23027,7 +23039,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
23027
23039
|
add3(issues, "portable.version_missing", "Portable manifest missing version");
|
|
23028
23040
|
}
|
|
23029
23041
|
const contractIssues = validatePortableManifestContract(manifest, {
|
|
23030
|
-
strict:
|
|
23042
|
+
strict: existsSync6(join6(skillPath, "skill.json")),
|
|
23031
23043
|
skillPath
|
|
23032
23044
|
});
|
|
23033
23045
|
for (const issue2 of contractIssues)
|
|
@@ -23063,10 +23075,10 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
23063
23075
|
add3(issues, "portable.command_entry_unsafe", `Command '${command.name}' entry '${command.entry}' must stay inside the skill directory`);
|
|
23064
23076
|
continue;
|
|
23065
23077
|
}
|
|
23066
|
-
const entryPath =
|
|
23067
|
-
if (!
|
|
23078
|
+
const entryPath = join6(skillPath, command.entry);
|
|
23079
|
+
if (!existsSync6(entryPath))
|
|
23068
23080
|
add3(issues, "portable.command_entry_missing", `Command '${command.name}' entry '${command.entry}' is missing`);
|
|
23069
|
-
else if (
|
|
23081
|
+
else if (statSync6(entryPath).isDirectory())
|
|
23070
23082
|
add3(issues, "portable.command_entry_directory", `Command '${command.name}' entry '${command.entry}' must be a file`);
|
|
23071
23083
|
}
|
|
23072
23084
|
}
|
|
@@ -23074,7 +23086,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
23074
23086
|
} catch (error2) {
|
|
23075
23087
|
add3(issues, "portable.manifest_invalid", error2.message);
|
|
23076
23088
|
}
|
|
23077
|
-
if (manifest?.kind !== "instruction" && !
|
|
23089
|
+
if (manifest?.kind !== "instruction" && !existsSync6(join6(skillPath, "AGENTS.md"))) {
|
|
23078
23090
|
add3(issues, "portable.agents_missing", "Missing AGENTS.md with build-out instructions for coding agents");
|
|
23079
23091
|
}
|
|
23080
23092
|
}
|
|
@@ -23106,7 +23118,7 @@ function summarizePortableSkill(skillPath, fallbackName) {
|
|
|
23106
23118
|
}
|
|
23107
23119
|
function safeIsDirectory(path) {
|
|
23108
23120
|
try {
|
|
23109
|
-
return
|
|
23121
|
+
return statSync6(path).isDirectory();
|
|
23110
23122
|
} catch {
|
|
23111
23123
|
return false;
|
|
23112
23124
|
}
|
|
@@ -23332,20 +23344,20 @@ function parseSkillMdFrontmatter(content) {
|
|
|
23332
23344
|
return Object.keys(result).length > 0 ? result : null;
|
|
23333
23345
|
}
|
|
23334
23346
|
function discoverSkillsInDir(dir, source = "custom") {
|
|
23335
|
-
if (!
|
|
23347
|
+
if (!existsSync7(dir))
|
|
23336
23348
|
return [];
|
|
23337
23349
|
const result = [];
|
|
23338
23350
|
try {
|
|
23339
|
-
const entries =
|
|
23351
|
+
const entries = readdirSync6(dir, { withFileTypes: true });
|
|
23340
23352
|
for (const entry of entries) {
|
|
23341
23353
|
if (!entry.isDirectory())
|
|
23342
23354
|
continue;
|
|
23343
|
-
const skillMdPath =
|
|
23344
|
-
if (!
|
|
23355
|
+
const skillMdPath = join7(dir, entry.name, "SKILL.md");
|
|
23356
|
+
if (!existsSync7(skillMdPath))
|
|
23345
23357
|
continue;
|
|
23346
23358
|
let content;
|
|
23347
23359
|
try {
|
|
23348
|
-
content =
|
|
23360
|
+
content = readFileSync6(skillMdPath, "utf-8");
|
|
23349
23361
|
} catch {
|
|
23350
23362
|
continue;
|
|
23351
23363
|
}
|
|
@@ -23360,6 +23372,7 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
23360
23372
|
category: fm.category || "Development Tools",
|
|
23361
23373
|
tags: fm.tags || [],
|
|
23362
23374
|
...fm.kind ? { kind: fm.kind } : {},
|
|
23375
|
+
...isHostedMetadataSkillDir(join7(dir, entry.name)) ? { serverOwned: true } : {},
|
|
23363
23376
|
source
|
|
23364
23377
|
});
|
|
23365
23378
|
}
|
|
@@ -23368,20 +23381,20 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
23368
23381
|
}
|
|
23369
23382
|
function findExtensionSkillPath(name) {
|
|
23370
23383
|
const config2 = loadConfig();
|
|
23371
|
-
if (!config2.extensionsDir || !
|
|
23384
|
+
if (!config2.extensionsDir || !existsSync7(config2.extensionsDir))
|
|
23372
23385
|
return null;
|
|
23373
23386
|
try {
|
|
23374
|
-
const entries =
|
|
23387
|
+
const entries = readdirSync6(config2.extensionsDir, { withFileTypes: true });
|
|
23375
23388
|
for (const entry of entries) {
|
|
23376
23389
|
if (!entry.isDirectory())
|
|
23377
23390
|
continue;
|
|
23378
|
-
const skillDir =
|
|
23379
|
-
const skillMdPath =
|
|
23380
|
-
if (!
|
|
23391
|
+
const skillDir = join7(config2.extensionsDir, entry.name);
|
|
23392
|
+
const skillMdPath = join7(skillDir, "SKILL.md");
|
|
23393
|
+
if (!existsSync7(skillMdPath))
|
|
23381
23394
|
continue;
|
|
23382
23395
|
let content;
|
|
23383
23396
|
try {
|
|
23384
|
-
content =
|
|
23397
|
+
content = readFileSync6(skillMdPath, "utf-8");
|
|
23385
23398
|
} catch {
|
|
23386
23399
|
continue;
|
|
23387
23400
|
}
|
|
@@ -23414,7 +23427,7 @@ function loadRegistry(cwd) {
|
|
|
23414
23427
|
const official = SKILLS.map((s) => ({ ...s, source: "official" }));
|
|
23415
23428
|
const extensions = config2.extensionsDir ? discoverSkillsInDir(config2.extensionsDir, "extension") : [];
|
|
23416
23429
|
const portableCustom = listPortableSkillMetas();
|
|
23417
|
-
const legacyCustom = discoverSkillsInDir(
|
|
23430
|
+
const legacyCustom = discoverSkillsInDir(join7(dataDir, "custom"));
|
|
23418
23431
|
const globalCustom = mergeCustomSkills([...legacyCustom, ...portableCustom]);
|
|
23419
23432
|
registryCache = mergeSkillRegistryLists(official, extensions, globalCustom);
|
|
23420
23433
|
registryCacheTime = now;
|
|
@@ -23450,8 +23463,8 @@ function mergeCustomSkills(skills) {
|
|
|
23450
23463
|
}
|
|
23451
23464
|
|
|
23452
23465
|
// src/lib/installer.ts
|
|
23453
|
-
import { existsSync as
|
|
23454
|
-
import { dirname as dirname4, join as
|
|
23466
|
+
import { existsSync as existsSync9, readFileSync as readFileSync8, rmSync as rmSync2 } from "fs";
|
|
23467
|
+
import { dirname as dirname4, join as join9 } from "path";
|
|
23455
23468
|
import { homedir as homedir2 } from "os";
|
|
23456
23469
|
import { fileURLToPath } from "url";
|
|
23457
23470
|
|
|
@@ -23468,8 +23481,8 @@ function normalizeSkillName(name) {
|
|
|
23468
23481
|
init_config();
|
|
23469
23482
|
|
|
23470
23483
|
// src/lib/project-state.ts
|
|
23471
|
-
import { existsSync as
|
|
23472
|
-
import { join as
|
|
23484
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
23485
|
+
import { join as join8 } from "path";
|
|
23473
23486
|
var VALID_PIN_SOURCES = [
|
|
23474
23487
|
"official",
|
|
23475
23488
|
"custom",
|
|
@@ -23484,17 +23497,17 @@ var SKILLS_PROJECT_DIR = ".skills";
|
|
|
23484
23497
|
var PROJECT_CONFIG_FILE = "project.json";
|
|
23485
23498
|
var DEFAULT_EXPORT_DIR = ".skills/exports";
|
|
23486
23499
|
function getProjectStateDir(targetDir = process.cwd()) {
|
|
23487
|
-
return
|
|
23500
|
+
return join8(targetDir, SKILLS_PROJECT_DIR);
|
|
23488
23501
|
}
|
|
23489
23502
|
function getProjectConfigPath(targetDir = process.cwd()) {
|
|
23490
|
-
return
|
|
23503
|
+
return join8(getProjectStateDir(targetDir), PROJECT_CONFIG_FILE);
|
|
23491
23504
|
}
|
|
23492
23505
|
function loadProjectConfig(targetDir = process.cwd()) {
|
|
23493
23506
|
const path = getProjectConfigPath(targetDir);
|
|
23494
|
-
if (!
|
|
23507
|
+
if (!existsSync8(path))
|
|
23495
23508
|
return null;
|
|
23496
23509
|
try {
|
|
23497
|
-
return normalizeProjectConfig(JSON.parse(
|
|
23510
|
+
return normalizeProjectConfig(JSON.parse(readFileSync7(path, "utf-8")));
|
|
23498
23511
|
} catch {
|
|
23499
23512
|
return null;
|
|
23500
23513
|
}
|
|
@@ -23593,12 +23606,12 @@ var __dirname2 = dirname4(fileURLToPath(import.meta.url));
|
|
|
23593
23606
|
function findSkillsDir() {
|
|
23594
23607
|
let dir = __dirname2;
|
|
23595
23608
|
for (let i = 0;i < 5; i++) {
|
|
23596
|
-
const candidate =
|
|
23597
|
-
if (
|
|
23609
|
+
const candidate = join9(dir, "skills");
|
|
23610
|
+
if (existsSync9(candidate) && !dir.includes(".skills"))
|
|
23598
23611
|
return candidate;
|
|
23599
23612
|
dir = dirname4(dir);
|
|
23600
23613
|
}
|
|
23601
|
-
return
|
|
23614
|
+
return join9(__dirname2, "..", "skills");
|
|
23602
23615
|
}
|
|
23603
23616
|
var SKILLS_DIR = findSkillsDir();
|
|
23604
23617
|
function getSkillPath(name) {
|
|
@@ -23606,13 +23619,13 @@ function getSkillPath(name) {
|
|
|
23606
23619
|
const portable = findPortableSkill(skillName);
|
|
23607
23620
|
if (portable)
|
|
23608
23621
|
return portable.path;
|
|
23609
|
-
const legacyCustomPath =
|
|
23610
|
-
if (
|
|
23622
|
+
const legacyCustomPath = join9(getDataDir(), "custom", skillName);
|
|
23623
|
+
if (existsSync9(legacyCustomPath))
|
|
23611
23624
|
return legacyCustomPath;
|
|
23612
23625
|
const extensionPath = findExtensionSkillPath(skillName);
|
|
23613
23626
|
if (extensionPath)
|
|
23614
23627
|
return extensionPath;
|
|
23615
|
-
return
|
|
23628
|
+
return join9(SKILLS_DIR, skillName);
|
|
23616
23629
|
}
|
|
23617
23630
|
function getCanonicalSkillName(name) {
|
|
23618
23631
|
return getSkill(name)?.name ?? resolveSkillAlias(normalizeSkillSlug(name));
|
|
@@ -23621,7 +23634,7 @@ function installSkill(name, options = {}) {
|
|
|
23621
23634
|
const { targetDir = process.cwd(), overwrite = false } = options;
|
|
23622
23635
|
const canonicalName = getCanonicalSkillName(name);
|
|
23623
23636
|
const skillName = normalizeSkillName(canonicalName);
|
|
23624
|
-
if (!
|
|
23637
|
+
if (!existsSync9(getSkillPath(name))) {
|
|
23625
23638
|
const knownOfficial = Boolean(getSkill(name));
|
|
23626
23639
|
return {
|
|
23627
23640
|
skill: canonicalName,
|
|
@@ -23676,11 +23689,11 @@ function getAgentSkillsDir(agent, scope = "global", projectDir) {
|
|
|
23676
23689
|
const base = projectDir || process.cwd();
|
|
23677
23690
|
switch (agent) {
|
|
23678
23691
|
case "pi":
|
|
23679
|
-
return scope === "project" ?
|
|
23692
|
+
return scope === "project" ? join9(base, ".pi", "skills") : join9(homedir2(), ".pi", "agent", "skills");
|
|
23680
23693
|
case "opencode":
|
|
23681
|
-
return scope === "project" ?
|
|
23694
|
+
return scope === "project" ? join9(base, ".opencode", "skills") : join9(homedir2(), ".config", "opencode", "skills");
|
|
23682
23695
|
default:
|
|
23683
|
-
return scope === "project" ?
|
|
23696
|
+
return scope === "project" ? join9(base, `.${agent}`, "skills") : join9(homedir2(), `.${agent}`, "skills");
|
|
23684
23697
|
}
|
|
23685
23698
|
}
|
|
23686
23699
|
function warnMissingDependencies(name, targetDir) {
|
|
@@ -23695,11 +23708,11 @@ function warnMissingDependencies(name, targetDir) {
|
|
|
23695
23708
|
}
|
|
23696
23709
|
}
|
|
23697
23710
|
function readBundledSkillVersion(name) {
|
|
23698
|
-
const pkgPath =
|
|
23699
|
-
if (!
|
|
23711
|
+
const pkgPath = join9(getSkillPath(name), "package.json");
|
|
23712
|
+
if (!existsSync9(pkgPath))
|
|
23700
23713
|
return "unknown";
|
|
23701
23714
|
try {
|
|
23702
|
-
const pkg = JSON.parse(
|
|
23715
|
+
const pkg = JSON.parse(readFileSync8(pkgPath, "utf-8"));
|
|
23703
23716
|
return pkg.version || "unknown";
|
|
23704
23717
|
} catch {
|
|
23705
23718
|
return "unknown";
|
|
@@ -23707,16 +23720,16 @@ function readBundledSkillVersion(name) {
|
|
|
23707
23720
|
}
|
|
23708
23721
|
|
|
23709
23722
|
// src/lib/skillinfo.ts
|
|
23710
|
-
import { existsSync as
|
|
23711
|
-
import { join as
|
|
23723
|
+
import { existsSync as existsSync10, readFileSync as readFileSync9 } from "fs";
|
|
23724
|
+
import { join as join10 } from "path";
|
|
23712
23725
|
function isInstructionSkillDir(skillPath, meta) {
|
|
23713
23726
|
if (meta?.kind === "instruction")
|
|
23714
23727
|
return true;
|
|
23715
|
-
const skillMdPath =
|
|
23716
|
-
if (!
|
|
23728
|
+
const skillMdPath = join10(skillPath, "SKILL.md");
|
|
23729
|
+
if (!existsSync10(skillMdPath))
|
|
23717
23730
|
return false;
|
|
23718
23731
|
try {
|
|
23719
|
-
return parseSkillFrontmatter(
|
|
23732
|
+
return parseSkillFrontmatter(readFileSync9(skillMdPath, "utf-8"))?.kind === "instruction";
|
|
23720
23733
|
} catch {
|
|
23721
23734
|
return false;
|
|
23722
23735
|
}
|
|
@@ -23739,12 +23752,12 @@ var HOSTED_PROVIDER_ENV_PREFIXES = [
|
|
|
23739
23752
|
];
|
|
23740
23753
|
function getSkillDocs(name) {
|
|
23741
23754
|
const skillPath = getSkillPath(name);
|
|
23742
|
-
if (!
|
|
23755
|
+
if (!existsSync10(skillPath))
|
|
23743
23756
|
return null;
|
|
23744
23757
|
return {
|
|
23745
|
-
skillMd: readIfExists(
|
|
23746
|
-
readme: readIfExists(
|
|
23747
|
-
claudeMd: readIfExists(
|
|
23758
|
+
skillMd: readIfExists(join10(skillPath, "SKILL.md")),
|
|
23759
|
+
readme: readIfExists(join10(skillPath, "README.md")),
|
|
23760
|
+
claudeMd: readIfExists(join10(skillPath, "CLAUDE.md"))
|
|
23748
23761
|
};
|
|
23749
23762
|
}
|
|
23750
23763
|
function getSkillBestDoc(name) {
|
|
@@ -23755,11 +23768,11 @@ function getSkillBestDoc(name) {
|
|
|
23755
23768
|
}
|
|
23756
23769
|
function getSkillRequirements(name) {
|
|
23757
23770
|
const skillPath = getSkillPath(name);
|
|
23758
|
-
if (!
|
|
23771
|
+
if (!existsSync10(skillPath))
|
|
23759
23772
|
return null;
|
|
23760
23773
|
const texts = [];
|
|
23761
23774
|
for (const file of ["SKILL.md", "README.md", "CLAUDE.md", ".env.example", ".env.local.example"]) {
|
|
23762
|
-
const content = readIfExists(
|
|
23775
|
+
const content = readIfExists(join10(skillPath, file));
|
|
23763
23776
|
if (content)
|
|
23764
23777
|
texts.push(content);
|
|
23765
23778
|
}
|
|
@@ -23798,10 +23811,10 @@ function getSkillRequirements(name) {
|
|
|
23798
23811
|
const skillName = normalizeSkillName(name);
|
|
23799
23812
|
let cliCommand = `skills run ${skillName}`;
|
|
23800
23813
|
let dependencies = {};
|
|
23801
|
-
const pkgPath =
|
|
23802
|
-
if (
|
|
23814
|
+
const pkgPath = join10(skillPath, "package.json");
|
|
23815
|
+
if (existsSync10(pkgPath)) {
|
|
23803
23816
|
try {
|
|
23804
|
-
const pkg = JSON.parse(
|
|
23817
|
+
const pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
|
|
23805
23818
|
dependencies = pkg.dependencies || {};
|
|
23806
23819
|
} catch {}
|
|
23807
23820
|
}
|
|
@@ -23819,7 +23832,7 @@ async function runSkill(name, args, options = {}) {
|
|
|
23819
23832
|
const meta = getSkill(name);
|
|
23820
23833
|
const canonicalName = meta?.name ?? name;
|
|
23821
23834
|
const skillPath = getSkillPath(canonicalName);
|
|
23822
|
-
if (!
|
|
23835
|
+
if (!existsSync10(skillPath)) {
|
|
23823
23836
|
return { exitCode: 1, error: `Skill '${name}' not found` };
|
|
23824
23837
|
}
|
|
23825
23838
|
if (isInstructionSkillDir(skillPath, meta)) {
|
|
@@ -23828,13 +23841,13 @@ async function runSkill(name, args, options = {}) {
|
|
|
23828
23841
|
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'.`
|
|
23829
23842
|
};
|
|
23830
23843
|
}
|
|
23831
|
-
const pkgPath =
|
|
23832
|
-
if (!
|
|
23844
|
+
const pkgPath = join10(skillPath, "package.json");
|
|
23845
|
+
if (!existsSync10(pkgPath)) {
|
|
23833
23846
|
return { exitCode: 1, error: `No package.json in skill '${name}'` };
|
|
23834
23847
|
}
|
|
23835
23848
|
let entryPoint;
|
|
23836
23849
|
try {
|
|
23837
|
-
const pkg = JSON.parse(
|
|
23850
|
+
const pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
|
|
23838
23851
|
if (pkg.bin) {
|
|
23839
23852
|
const binValues = Object.values(pkg.bin);
|
|
23840
23853
|
entryPoint = binValues[0];
|
|
@@ -23848,12 +23861,12 @@ async function runSkill(name, args, options = {}) {
|
|
|
23848
23861
|
} catch {
|
|
23849
23862
|
return { exitCode: 1, error: `Failed to parse package.json for skill '${name}'` };
|
|
23850
23863
|
}
|
|
23851
|
-
const entryPath =
|
|
23852
|
-
if (!
|
|
23864
|
+
const entryPath = join10(skillPath, entryPoint);
|
|
23865
|
+
if (!existsSync10(entryPath)) {
|
|
23853
23866
|
return { exitCode: 1, error: `Entry point '${entryPoint}' not found in skill '${name}'` };
|
|
23854
23867
|
}
|
|
23855
|
-
const nodeModules =
|
|
23856
|
-
if (!
|
|
23868
|
+
const nodeModules = join10(skillPath, "node_modules");
|
|
23869
|
+
if (!existsSync10(nodeModules)) {
|
|
23857
23870
|
const install = Bun.spawn(["bun", "install", "--no-save"], {
|
|
23858
23871
|
cwd: skillPath,
|
|
23859
23872
|
stdout: "pipe",
|
|
@@ -23880,15 +23893,15 @@ async function runSkill(name, args, options = {}) {
|
|
|
23880
23893
|
return { exitCode };
|
|
23881
23894
|
}
|
|
23882
23895
|
function detectProjectSkills(cwd = process.cwd()) {
|
|
23883
|
-
const pkgPath =
|
|
23884
|
-
if (!
|
|
23896
|
+
const pkgPath = join10(cwd, "package.json");
|
|
23897
|
+
if (!existsSync10(pkgPath)) {
|
|
23885
23898
|
const alwaysRecommend = ["market-research-report", "repo-onboarding-report", "blog-article"];
|
|
23886
23899
|
const recommended2 = alwaysRecommend.map((name) => loadRegistry().find((s) => s.name === name)).filter((s) => s !== undefined);
|
|
23887
23900
|
return { detected: [], recommended: recommended2 };
|
|
23888
23901
|
}
|
|
23889
23902
|
let pkg;
|
|
23890
23903
|
try {
|
|
23891
|
-
pkg = JSON.parse(
|
|
23904
|
+
pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
|
|
23892
23905
|
} catch {
|
|
23893
23906
|
const alwaysRecommend = ["market-research-report", "repo-onboarding-report", "blog-article"];
|
|
23894
23907
|
const recommended2 = alwaysRecommend.map((name) => loadRegistry().find((s) => s.name === name)).filter((s) => s !== undefined);
|
|
@@ -23977,8 +23990,8 @@ function extractEnvVars(text) {
|
|
|
23977
23990
|
}
|
|
23978
23991
|
function readIfExists(path) {
|
|
23979
23992
|
try {
|
|
23980
|
-
if (
|
|
23981
|
-
return
|
|
23993
|
+
if (existsSync10(path)) {
|
|
23994
|
+
return readFileSync9(path, "utf-8");
|
|
23982
23995
|
}
|
|
23983
23996
|
} catch {}
|
|
23984
23997
|
return null;
|
|
@@ -25560,25 +25573,25 @@ function registerDiscoveryTools(server) {
|
|
|
25560
25573
|
}
|
|
25561
25574
|
|
|
25562
25575
|
// src/mcp/operation-tools.ts
|
|
25563
|
-
import { existsSync as
|
|
25564
|
-
import { join as
|
|
25576
|
+
import { existsSync as existsSync13, readdirSync as readdirSync8, statSync as statSync8 } from "fs";
|
|
25577
|
+
import { join as join13 } from "path";
|
|
25565
25578
|
|
|
25566
25579
|
// src/lib/run-state.ts
|
|
25567
25580
|
import { createHash as createHash2, randomBytes } from "crypto";
|
|
25568
|
-
import { existsSync as
|
|
25569
|
-
import { extname, join as
|
|
25581
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync5, readFileSync as readFileSync10, readdirSync as readdirSync7, statSync as statSync7, writeFileSync as writeFileSync5 } from "fs";
|
|
25582
|
+
import { extname, join as join11, relative as relative2 } from "path";
|
|
25570
25583
|
function createSkillRun(params, targetDir = process.cwd()) {
|
|
25571
25584
|
const now = new Date;
|
|
25572
25585
|
const id = createRunId(now);
|
|
25573
25586
|
const day = now.toISOString().slice(0, 10);
|
|
25574
25587
|
const skillName = normalizeSkillName(params.skill);
|
|
25575
25588
|
const root = getProjectStateDir(targetDir);
|
|
25576
|
-
const runDir =
|
|
25577
|
-
const logsDir =
|
|
25578
|
-
const exportDir =
|
|
25589
|
+
const runDir = join11(root, "runs", day, id);
|
|
25590
|
+
const logsDir = join11(runDir, "logs");
|
|
25591
|
+
const exportDir = join11(root, "exports", skillName, id);
|
|
25579
25592
|
mkdirSync5(logsDir, { recursive: true });
|
|
25580
25593
|
mkdirSync5(exportDir, { recursive: true });
|
|
25581
|
-
mkdirSync5(
|
|
25594
|
+
mkdirSync5(join11(root, "tmp"), { recursive: true });
|
|
25582
25595
|
const record3 = {
|
|
25583
25596
|
id,
|
|
25584
25597
|
skill: skillName,
|
|
@@ -25629,22 +25642,22 @@ function updateSkillRun(context, patch) {
|
|
|
25629
25642
|
return context.record;
|
|
25630
25643
|
}
|
|
25631
25644
|
function writeRunLogs(context, stdout = "", stderr = "") {
|
|
25632
|
-
writeFileSync5(
|
|
25633
|
-
writeFileSync5(
|
|
25645
|
+
writeFileSync5(join11(context.logsDir, "stdout.log"), stdout);
|
|
25646
|
+
writeFileSync5(join11(context.logsDir, "stderr.log"), stderr);
|
|
25634
25647
|
}
|
|
25635
25648
|
function appendRunEvent(context, event, data = {}) {
|
|
25636
25649
|
const line = JSON.stringify({ ts: new Date().toISOString(), event, ...data }) + `
|
|
25637
25650
|
`;
|
|
25638
|
-
const path =
|
|
25639
|
-
const previous =
|
|
25651
|
+
const path = join11(context.runDir, "events.ndjson");
|
|
25652
|
+
const previous = existsSync11(path) ? readFileSync10(path, "utf-8") : "";
|
|
25640
25653
|
writeFileSync5(path, previous + line);
|
|
25641
25654
|
}
|
|
25642
25655
|
function findSkillRun(runId, targetDir = process.cwd()) {
|
|
25643
|
-
const runsRoot =
|
|
25644
|
-
if (!
|
|
25656
|
+
const runsRoot = join11(getProjectStateDir(targetDir), "runs");
|
|
25657
|
+
if (!existsSync11(runsRoot))
|
|
25645
25658
|
return null;
|
|
25646
|
-
for (const day of
|
|
25647
|
-
const record3 = readRunRecord(
|
|
25659
|
+
for (const day of readdirSync7(runsRoot)) {
|
|
25660
|
+
const record3 = readRunRecord(join11(runsRoot, day, runId));
|
|
25648
25661
|
if (record3)
|
|
25649
25662
|
return record3;
|
|
25650
25663
|
}
|
|
@@ -25661,20 +25674,20 @@ function skillRunEnv(context) {
|
|
|
25661
25674
|
};
|
|
25662
25675
|
}
|
|
25663
25676
|
function writeRunRecord(context) {
|
|
25664
|
-
writeFileSync5(
|
|
25677
|
+
writeFileSync5(join11(context.runDir, "run.json"), JSON.stringify(context.record, null, 2) + `
|
|
25665
25678
|
`);
|
|
25666
25679
|
}
|
|
25667
25680
|
function writeArtifactsManifest(context, artifacts) {
|
|
25668
|
-
writeFileSync5(
|
|
25681
|
+
writeFileSync5(join11(context.runDir, "artifacts.json"), JSON.stringify({ runId: context.record.id, artifacts }, null, 2) + `
|
|
25669
25682
|
`);
|
|
25670
25683
|
}
|
|
25671
25684
|
function collectRunArtifacts(context) {
|
|
25672
|
-
if (!
|
|
25685
|
+
if (!existsSync11(context.exportDir))
|
|
25673
25686
|
return [];
|
|
25674
25687
|
const artifacts = [];
|
|
25675
25688
|
for (const path of walkFiles(context.exportDir)) {
|
|
25676
|
-
const stat =
|
|
25677
|
-
const bytes =
|
|
25689
|
+
const stat = statSync7(path);
|
|
25690
|
+
const bytes = readFileSync10(path);
|
|
25678
25691
|
artifacts.push({
|
|
25679
25692
|
path: toProjectRelative(context.targetDir, path),
|
|
25680
25693
|
mime: mimeForPath(path),
|
|
@@ -25685,20 +25698,20 @@ function collectRunArtifacts(context) {
|
|
|
25685
25698
|
return artifacts.sort((a, b) => a.path.localeCompare(b.path));
|
|
25686
25699
|
}
|
|
25687
25700
|
function readRunRecord(runDir) {
|
|
25688
|
-
const path =
|
|
25689
|
-
if (!
|
|
25701
|
+
const path = join11(runDir, "run.json");
|
|
25702
|
+
if (!existsSync11(path))
|
|
25690
25703
|
return null;
|
|
25691
25704
|
try {
|
|
25692
|
-
return JSON.parse(
|
|
25705
|
+
return JSON.parse(readFileSync10(path, "utf-8"));
|
|
25693
25706
|
} catch {
|
|
25694
25707
|
return null;
|
|
25695
25708
|
}
|
|
25696
25709
|
}
|
|
25697
25710
|
function walkFiles(dir) {
|
|
25698
25711
|
const files = [];
|
|
25699
|
-
for (const entry of
|
|
25700
|
-
const full =
|
|
25701
|
-
if (
|
|
25712
|
+
for (const entry of readdirSync7(dir)) {
|
|
25713
|
+
const full = join11(dir, entry);
|
|
25714
|
+
if (statSync7(full).isDirectory())
|
|
25702
25715
|
files.push(...walkFiles(full));
|
|
25703
25716
|
else
|
|
25704
25717
|
files.push(full);
|
|
@@ -25742,6 +25755,34 @@ function mimeForPath(path) {
|
|
|
25742
25755
|
return "application/octet-stream";
|
|
25743
25756
|
}
|
|
25744
25757
|
}
|
|
25758
|
+
// src/lib/run-routing.ts
|
|
25759
|
+
init_api_url();
|
|
25760
|
+
init_auth_store();
|
|
25761
|
+
function isServerOwnedSkill(skill) {
|
|
25762
|
+
return skill.serverOwned === true;
|
|
25763
|
+
}
|
|
25764
|
+
function resolveRunRouting(skill, apiKey, apiUrl) {
|
|
25765
|
+
if (!isServerOwnedSkill(skill))
|
|
25766
|
+
return { route: "local" };
|
|
25767
|
+
if (!apiUrl) {
|
|
25768
|
+
return {
|
|
25769
|
+
route: "error",
|
|
25770
|
+
code: "REMOTE_REQUIRES_ORIGIN",
|
|
25771
|
+
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)`
|
|
25772
|
+
};
|
|
25773
|
+
}
|
|
25774
|
+
if (!apiKey) {
|
|
25775
|
+
return {
|
|
25776
|
+
route: "error",
|
|
25777
|
+
code: "REMOTE_REQUIRES_CREDENTIAL",
|
|
25778
|
+
error: `${skill.name} is a server-owned skill. Run: skills auth login`
|
|
25779
|
+
};
|
|
25780
|
+
}
|
|
25781
|
+
return { route: "remote", apiKey };
|
|
25782
|
+
}
|
|
25783
|
+
function resolveConfiguredRunRouting(skill) {
|
|
25784
|
+
return resolveRunRouting(skill, getApiKey(), resolveApiUrl());
|
|
25785
|
+
}
|
|
25745
25786
|
|
|
25746
25787
|
// src/mcp/operation-tools.ts
|
|
25747
25788
|
function registerOperationTools(server) {
|
|
@@ -25951,7 +25992,6 @@ function registerOperationTools(server) {
|
|
|
25951
25992
|
if (!skill) {
|
|
25952
25993
|
return mcpError("SKILL_NOT_FOUND", `Skill '${name}' not found`, findSimilarSkills(name));
|
|
25953
25994
|
}
|
|
25954
|
-
const { getApiKey: getApiKey2 } = await Promise.resolve().then(() => (init_auth_store(), exports_auth_store));
|
|
25955
25995
|
const {
|
|
25956
25996
|
ARTICLE_GENERATION_SLUG: ARTICLE_GENERATION_SLUG2,
|
|
25957
25997
|
validateBlogArticleRunOptions: validateBlogArticleRunOptions2
|
|
@@ -25965,24 +26005,24 @@ function registerOperationTools(server) {
|
|
|
25965
26005
|
return mcpError("INVALID_BLOG_ARTICLE_OPTIONS", validation.errors.join(" "));
|
|
25966
26006
|
}
|
|
25967
26007
|
}
|
|
25968
|
-
const
|
|
25969
|
-
const hostedRuntime = false;
|
|
26008
|
+
const routing = resolveConfiguredRunRouting(skill);
|
|
25970
26009
|
const runContext = createSkillRun({
|
|
25971
26010
|
skill: skillName,
|
|
25972
26011
|
args: runArgs,
|
|
25973
|
-
remote:
|
|
26012
|
+
remote: routing.route === "remote"
|
|
25974
26013
|
});
|
|
25975
|
-
if (
|
|
25976
|
-
const error2 =
|
|
26014
|
+
if (routing.route === "error") {
|
|
26015
|
+
const error2 = routing.error;
|
|
25977
26016
|
writeRunLogs(runContext, "", error2 + `
|
|
25978
26017
|
`);
|
|
25979
26018
|
const run = completeSkillRun(runContext, { status: "failed", error: error2 });
|
|
25980
|
-
|
|
26019
|
+
const suggestions = routing.code === "REMOTE_REQUIRES_ORIGIN" ? ["skills setup --api-url <url>", "skills auth login"] : ["skills auth login"];
|
|
26020
|
+
return mcpError(routing.code, `${error2}. Local run metadata: ${run.paths.runDir}/run.json`, suggestions);
|
|
25981
26021
|
}
|
|
25982
|
-
if (
|
|
26022
|
+
if (routing.route === "remote") {
|
|
25983
26023
|
try {
|
|
25984
26024
|
const { RemoteSkillsClient: RemoteSkillsClient2 } = await Promise.resolve().then(() => (init_remote_client(), exports_remote_client));
|
|
25985
|
-
const client = new RemoteSkillsClient2(apiKey);
|
|
26025
|
+
const client = new RemoteSkillsClient2(routing.apiKey);
|
|
25986
26026
|
const run = await client.submitRun(skillName, runInput, runArgs);
|
|
25987
26027
|
if (run.error) {
|
|
25988
26028
|
writeRunLogs(runContext, "", String(run.error) + `
|
|
@@ -26141,13 +26181,13 @@ function registerOperationTools(server) {
|
|
|
26141
26181
|
const agents = [];
|
|
26142
26182
|
for (const agent of AGENT_TARGETS) {
|
|
26143
26183
|
const agentSkillsPath = getAgentSkillsDir(agent, "global");
|
|
26144
|
-
const exists =
|
|
26184
|
+
const exists = existsSync13(agentSkillsPath);
|
|
26145
26185
|
let skillCount = 0;
|
|
26146
26186
|
if (exists) {
|
|
26147
26187
|
try {
|
|
26148
|
-
skillCount =
|
|
26149
|
-
const full =
|
|
26150
|
-
return !f.startsWith(".") &&
|
|
26188
|
+
skillCount = readdirSync8(agentSkillsPath).filter((f) => {
|
|
26189
|
+
const full = join13(agentSkillsPath, f);
|
|
26190
|
+
return !f.startsWith(".") && statSync8(full).isDirectory();
|
|
26151
26191
|
}).length;
|
|
26152
26192
|
} catch {}
|
|
26153
26193
|
}
|
|
@@ -26193,16 +26233,16 @@ function compactRunToolPayload(payload, detailHint) {
|
|
|
26193
26233
|
|
|
26194
26234
|
// src/lib/feedback.ts
|
|
26195
26235
|
init_config();
|
|
26196
|
-
import { existsSync as
|
|
26197
|
-
import { dirname as dirname6, join as
|
|
26236
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync7 } from "fs";
|
|
26237
|
+
import { dirname as dirname6, join as join14 } from "path";
|
|
26198
26238
|
import { Database } from "bun:sqlite";
|
|
26199
26239
|
function getFeedbackDbPath() {
|
|
26200
|
-
return
|
|
26240
|
+
return join14(getDataDir(), "skills.db");
|
|
26201
26241
|
}
|
|
26202
26242
|
function getFeedbackDb() {
|
|
26203
26243
|
const dbPath = getFeedbackDbPath();
|
|
26204
26244
|
const dir = dirname6(dbPath);
|
|
26205
|
-
if (!
|
|
26245
|
+
if (!existsSync14(dir))
|
|
26206
26246
|
mkdirSync7(dir, { recursive: true });
|
|
26207
26247
|
const db = new Database(dbPath);
|
|
26208
26248
|
db.exec("PRAGMA journal_mode = WAL");
|
|
@@ -26361,24 +26401,24 @@ function registerResourceMetaTools(server) {
|
|
|
26361
26401
|
}
|
|
26362
26402
|
|
|
26363
26403
|
// src/lib/scheduler.ts
|
|
26364
|
-
import { existsSync as
|
|
26365
|
-
import { join as
|
|
26404
|
+
import { existsSync as existsSync15, readFileSync as readFileSync12, writeFileSync as writeFileSync7, mkdirSync as mkdirSync8 } from "fs";
|
|
26405
|
+
import { join as join15 } from "path";
|
|
26366
26406
|
function getSchedulesPath(targetDir = process.cwd()) {
|
|
26367
|
-
return
|
|
26407
|
+
return join15(targetDir, ".skills", "schedules.json");
|
|
26368
26408
|
}
|
|
26369
26409
|
function loadSchedules(targetDir = process.cwd()) {
|
|
26370
26410
|
const path = getSchedulesPath(targetDir);
|
|
26371
|
-
if (
|
|
26411
|
+
if (existsSync15(path)) {
|
|
26372
26412
|
try {
|
|
26373
|
-
return JSON.parse(
|
|
26413
|
+
return JSON.parse(readFileSync12(path, "utf-8"));
|
|
26374
26414
|
} catch {}
|
|
26375
26415
|
}
|
|
26376
26416
|
return { version: 1, schedules: [] };
|
|
26377
26417
|
}
|
|
26378
26418
|
function saveSchedules(data, targetDir = process.cwd()) {
|
|
26379
26419
|
const path = getSchedulesPath(targetDir);
|
|
26380
|
-
const dir =
|
|
26381
|
-
if (!
|
|
26420
|
+
const dir = join15(targetDir, ".skills");
|
|
26421
|
+
if (!existsSync15(dir))
|
|
26382
26422
|
mkdirSync8(dir, { recursive: true });
|
|
26383
26423
|
writeFileSync7(path, JSON.stringify(data, null, 2));
|
|
26384
26424
|
}
|
|
@@ -26641,14 +26681,14 @@ function registerScheduleTools(server) {
|
|
|
26641
26681
|
init_config();
|
|
26642
26682
|
import { createHash as createHash3, createHmac } from "crypto";
|
|
26643
26683
|
import {
|
|
26644
|
-
existsSync as
|
|
26684
|
+
existsSync as existsSync16,
|
|
26645
26685
|
mkdirSync as mkdirSync9,
|
|
26646
|
-
readFileSync as
|
|
26647
|
-
readdirSync as
|
|
26648
|
-
statSync as
|
|
26686
|
+
readFileSync as readFileSync13,
|
|
26687
|
+
readdirSync as readdirSync9,
|
|
26688
|
+
statSync as statSync9,
|
|
26649
26689
|
writeFileSync as writeFileSync8
|
|
26650
26690
|
} from "fs";
|
|
26651
|
-
import { dirname as dirname7, join as
|
|
26691
|
+
import { dirname as dirname7, join as join16, normalize as normalize3, relative as relative3, sep as sep2 } from "path";
|
|
26652
26692
|
init_retired_settings();
|
|
26653
26693
|
var SKILLS_STORAGE_TABLES = [
|
|
26654
26694
|
"skills_sync_records",
|
|
@@ -26725,7 +26765,7 @@ function getSkillsNativeStorageStatus(options = {}) {
|
|
|
26725
26765
|
local: {
|
|
26726
26766
|
dataDir: getDataDir(),
|
|
26727
26767
|
projectStateDir: getProjectStateDir(targetDir),
|
|
26728
|
-
feedbackDbPath:
|
|
26768
|
+
feedbackDbPath: join16(getDataDir(), "skills.db")
|
|
26729
26769
|
},
|
|
26730
26770
|
remote: {
|
|
26731
26771
|
databaseConfigured: Boolean(config2.databaseUrl),
|
|
@@ -26745,9 +26785,9 @@ function getStorageStatus(options = {}) {
|
|
|
26745
26785
|
function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
|
|
26746
26786
|
const projectStateDir = getProjectStateDir(targetDir);
|
|
26747
26787
|
const files = [];
|
|
26748
|
-
if (
|
|
26788
|
+
if (existsSync16(projectStateDir)) {
|
|
26749
26789
|
for (const filePath of walkFiles2(projectStateDir)) {
|
|
26750
|
-
const bytes =
|
|
26790
|
+
const bytes = readFileSync13(filePath);
|
|
26751
26791
|
const relativePath = toPosix(relative3(targetDir, filePath));
|
|
26752
26792
|
files.push({
|
|
26753
26793
|
path: relativePath,
|
|
@@ -26828,9 +26868,9 @@ function parsePositiveInteger(value) {
|
|
|
26828
26868
|
}
|
|
26829
26869
|
function walkFiles2(dir) {
|
|
26830
26870
|
const files = [];
|
|
26831
|
-
for (const entry of
|
|
26832
|
-
const full =
|
|
26833
|
-
const stats =
|
|
26871
|
+
for (const entry of readdirSync9(dir)) {
|
|
26872
|
+
const full = join16(dir, entry);
|
|
26873
|
+
const stats = statSync9(full);
|
|
26834
26874
|
if (stats.isDirectory())
|
|
26835
26875
|
files.push(...walkFiles2(full));
|
|
26836
26876
|
else
|