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