@hasna/skills 0.1.70 → 0.1.72
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/bin/index.js +1376 -852
- package/bin/mcp.js +342 -232
- package/bin/migrate.js +149 -40
- package/bin/server.js +212 -100
- package/bin/worker.js +151 -45
- package/dist/cli/commands/hydrate.d.ts +2 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1058 -304
- package/dist/lib/app-home.d.ts +85 -0
- package/dist/lib/config.d.ts +9 -10
- package/dist/lib/portable-snapshot-filter.d.ts +48 -0
- package/dist/lib/station-hydrate.d.ts +105 -0
- package/dist/lib/station-snapshot.d.ts +96 -0
- package/dist/sdk/index.js +518 -630
- package/dist/storage.js +155 -43
- package/package.json +2 -1
package/bin/mcp.js
CHANGED
|
@@ -6679,10 +6679,123 @@ var init_retired_settings = __esm(() => {
|
|
|
6679
6679
|
};
|
|
6680
6680
|
});
|
|
6681
6681
|
|
|
6682
|
-
//
|
|
6683
|
-
import { existsSync, readFileSync, writeFileSync, mkdirSync, copyFileSync, readdirSync, statSync } from "fs";
|
|
6684
|
-
import { join, dirname } from "path";
|
|
6682
|
+
// ../../node_modules/.bun/@hasna+paths@0.1.0/node_modules/@hasna/paths/dist/index.js
|
|
6685
6683
|
import { homedir } from "os";
|
|
6684
|
+
import { join } from "path";
|
|
6685
|
+
function assertApp(app) {
|
|
6686
|
+
if (typeof app !== "string" || app.length === 0) {
|
|
6687
|
+
throw new TypeError("paths: app must be a non-empty string");
|
|
6688
|
+
}
|
|
6689
|
+
if (!APP_SLUG_RE.test(app)) {
|
|
6690
|
+
throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
|
|
6691
|
+
}
|
|
6692
|
+
}
|
|
6693
|
+
function envOf(options) {
|
|
6694
|
+
return options.env ?? process.env;
|
|
6695
|
+
}
|
|
6696
|
+
function envValue(options, kind) {
|
|
6697
|
+
const value = envOf(options)[KIND_ENV[kind]];
|
|
6698
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
6699
|
+
}
|
|
6700
|
+
function isMacOS(platform) {
|
|
6701
|
+
return platform === "darwin";
|
|
6702
|
+
}
|
|
6703
|
+
function baseDir(kind, options) {
|
|
6704
|
+
const override = envValue(options, kind);
|
|
6705
|
+
if (override)
|
|
6706
|
+
return override;
|
|
6707
|
+
const home = options.home ?? homedir();
|
|
6708
|
+
const platform = options.platform ?? process.platform;
|
|
6709
|
+
if (isMacOS(platform)) {
|
|
6710
|
+
switch (kind) {
|
|
6711
|
+
case "config":
|
|
6712
|
+
case "data":
|
|
6713
|
+
return join(home, "Library", "Application Support", "Hasna");
|
|
6714
|
+
case "cache":
|
|
6715
|
+
return join(home, "Library", "Caches", "Hasna");
|
|
6716
|
+
case "state":
|
|
6717
|
+
return join(home, "Library", "Logs", "Hasna");
|
|
6718
|
+
}
|
|
6719
|
+
}
|
|
6720
|
+
switch (kind) {
|
|
6721
|
+
case "config":
|
|
6722
|
+
return join(home, ".config", "hasna");
|
|
6723
|
+
case "data":
|
|
6724
|
+
return join(home, ".local", "share", "hasna");
|
|
6725
|
+
case "state":
|
|
6726
|
+
return join(home, ".local", "state", "hasna");
|
|
6727
|
+
case "cache":
|
|
6728
|
+
return join(home, ".cache", "hasna");
|
|
6729
|
+
}
|
|
6730
|
+
}
|
|
6731
|
+
function resolvePath(kind, options) {
|
|
6732
|
+
assertApp(options.app);
|
|
6733
|
+
const appSegment = options.internal === true ? join("internal", options.app) : options.app;
|
|
6734
|
+
return join(baseDir(kind, options), appSegment);
|
|
6735
|
+
}
|
|
6736
|
+
function dataDir(options) {
|
|
6737
|
+
return resolvePath("data", options);
|
|
6738
|
+
}
|
|
6739
|
+
var KIND_ENV, APP_SLUG_RE;
|
|
6740
|
+
var init_dist = __esm(() => {
|
|
6741
|
+
KIND_ENV = {
|
|
6742
|
+
config: "HASNA_CONFIG_HOME",
|
|
6743
|
+
data: "HASNA_DATA_HOME",
|
|
6744
|
+
state: "HASNA_STATE_HOME",
|
|
6745
|
+
cache: "HASNA_CACHE_HOME"
|
|
6746
|
+
};
|
|
6747
|
+
APP_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
6748
|
+
});
|
|
6749
|
+
|
|
6750
|
+
// src/lib/app-home.ts
|
|
6751
|
+
import { existsSync } from "fs";
|
|
6752
|
+
import { homedir as homedir2 } from "os";
|
|
6753
|
+
import { join as join2, resolve } from "path";
|
|
6754
|
+
function effectiveHome() {
|
|
6755
|
+
return process.env["HOME"] || process.env["USERPROFILE"] || homedir2() || "/tmp";
|
|
6756
|
+
}
|
|
6757
|
+
function legacyDataRoot() {
|
|
6758
|
+
return join2(effectiveHome(), ".hasna", "skills");
|
|
6759
|
+
}
|
|
6760
|
+
function resolverDataRoot(home = effectiveHome()) {
|
|
6761
|
+
return dataDir({ app: "skills", home });
|
|
6762
|
+
}
|
|
6763
|
+
function adoptResolverDataRoot(resolved, env = process.env) {
|
|
6764
|
+
const dataOverride = env.HASNA_DATA_HOME;
|
|
6765
|
+
if (typeof dataOverride === "string" && dataOverride.trim().length > 0)
|
|
6766
|
+
return true;
|
|
6767
|
+
return existsSync(join2(resolved, DEFAULT_SQLITE_FILENAME)) || existsSync(join2(resolved, GLOBAL_CONFIG_FILENAME));
|
|
6768
|
+
}
|
|
6769
|
+
function exactDataRoot() {
|
|
6770
|
+
for (const key of [DATA_DIR_ENV, HASNA_SKILLS_HOME_ENV, SKILLS_HOME_ENV]) {
|
|
6771
|
+
const dir = process.env[key]?.trim();
|
|
6772
|
+
if (dir)
|
|
6773
|
+
return resolve(dir);
|
|
6774
|
+
}
|
|
6775
|
+
return;
|
|
6776
|
+
}
|
|
6777
|
+
function hasExactOverride(env = process.env) {
|
|
6778
|
+
return Boolean(env[DATA_DIR_ENV]?.trim()) || Boolean(env[HASNA_SKILLS_HOME_ENV]?.trim()) || Boolean(env[SKILLS_HOME_ENV]?.trim());
|
|
6779
|
+
}
|
|
6780
|
+
function hasOperatorOverride(env = process.env) {
|
|
6781
|
+
return hasExactOverride(env) || Boolean(env.HASNA_DATA_HOME?.trim());
|
|
6782
|
+
}
|
|
6783
|
+
function getDataRoot() {
|
|
6784
|
+
const exact = exactDataRoot();
|
|
6785
|
+
if (exact)
|
|
6786
|
+
return exact;
|
|
6787
|
+
const resolved = resolverDataRoot();
|
|
6788
|
+
return adoptResolverDataRoot(resolved) ? resolve(resolved) : resolve(legacyDataRoot());
|
|
6789
|
+
}
|
|
6790
|
+
var DATA_DIR_ENV = "HASNA_SKILLS_DIR", HASNA_SKILLS_HOME_ENV = "HASNA_SKILLS_HOME", SKILLS_HOME_ENV = "SKILLS_HOME", DEFAULT_SQLITE_FILENAME = "server.db", GLOBAL_CONFIG_FILENAME = "config.json";
|
|
6791
|
+
var init_app_home = __esm(() => {
|
|
6792
|
+
init_dist();
|
|
6793
|
+
});
|
|
6794
|
+
|
|
6795
|
+
// src/lib/config.ts
|
|
6796
|
+
import { existsSync as existsSync2, readFileSync, writeFileSync, mkdirSync, copyFileSync, readdirSync, statSync } from "fs";
|
|
6797
|
+
import { join as join3, dirname } from "path";
|
|
6798
|
+
import { homedir as homedir3 } from "os";
|
|
6686
6799
|
function validKeys() {
|
|
6687
6800
|
return [...Object.keys(ENUM_KEYS), ...STRING_KEYS];
|
|
6688
6801
|
}
|
|
@@ -6690,19 +6803,19 @@ function allowedValues(key) {
|
|
|
6690
6803
|
return ENUM_KEYS[key];
|
|
6691
6804
|
}
|
|
6692
6805
|
function mergeDirectoryContents(sourceDir, targetDir) {
|
|
6693
|
-
if (!
|
|
6806
|
+
if (!existsSync2(sourceDir))
|
|
6694
6807
|
return;
|
|
6695
6808
|
mkdirSync(targetDir, { recursive: true });
|
|
6696
6809
|
for (const entry of readdirSync(sourceDir)) {
|
|
6697
|
-
const sourcePath =
|
|
6698
|
-
const targetPath =
|
|
6810
|
+
const sourcePath = join3(sourceDir, entry);
|
|
6811
|
+
const targetPath = join3(targetDir, entry);
|
|
6699
6812
|
try {
|
|
6700
6813
|
const sourceStat = statSync(sourcePath);
|
|
6701
6814
|
if (sourceStat.isDirectory()) {
|
|
6702
6815
|
mergeDirectoryContents(sourcePath, targetPath);
|
|
6703
6816
|
continue;
|
|
6704
6817
|
}
|
|
6705
|
-
if (!
|
|
6818
|
+
if (!existsSync2(targetPath))
|
|
6706
6819
|
copyFileSync(sourcePath, targetPath);
|
|
6707
6820
|
} catch {}
|
|
6708
6821
|
}
|
|
@@ -6728,48 +6841,42 @@ function normalizeConfigValue(key, value) {
|
|
|
6728
6841
|
return;
|
|
6729
6842
|
}
|
|
6730
6843
|
function isOwnerLayoutMigrated(appDir) {
|
|
6731
|
-
return
|
|
6844
|
+
return existsSync2(join3(appDir, SKILLS_CACHE_DIRNAME, LAYOUT_MIGRATION_RECORD));
|
|
6732
6845
|
}
|
|
6733
6846
|
function getDataDir() {
|
|
6734
|
-
const
|
|
6735
|
-
if (override) {
|
|
6736
|
-
try {
|
|
6737
|
-
mkdirSync(override, { recursive: true });
|
|
6738
|
-
} catch {}
|
|
6739
|
-
return override;
|
|
6740
|
-
}
|
|
6741
|
-
const home = process.env["HOME"] || process.env["USERPROFILE"] || homedir();
|
|
6742
|
-
const newDir = join(home, ".hasna", "skills");
|
|
6743
|
-
const oldDir = join(home, ".skills");
|
|
6744
|
-
const oldConfigFile = join(home, ".skillsrc");
|
|
6745
|
-
mkdirSync(newDir, { recursive: true });
|
|
6847
|
+
const root = getDataRoot();
|
|
6746
6848
|
try {
|
|
6747
|
-
|
|
6849
|
+
mkdirSync(root, { recursive: true });
|
|
6748
6850
|
} catch {}
|
|
6749
|
-
if (
|
|
6851
|
+
if (hasOperatorOverride())
|
|
6852
|
+
return root;
|
|
6853
|
+
const home = effectiveHome();
|
|
6854
|
+
const oldDir = join3(home, ".skills");
|
|
6855
|
+
const oldConfigFile = join3(home, ".skillsrc");
|
|
6856
|
+
try {
|
|
6857
|
+
mergeDirectoryContents(oldDir, root);
|
|
6858
|
+
} catch {}
|
|
6859
|
+
if (existsSync2(oldConfigFile) && !existsSync2(join3(root, "config.json"))) {
|
|
6750
6860
|
try {
|
|
6751
|
-
copyFileSync(oldConfigFile,
|
|
6861
|
+
copyFileSync(oldConfigFile, join3(root, "config.json"));
|
|
6752
6862
|
} catch {}
|
|
6753
6863
|
}
|
|
6754
|
-
return
|
|
6864
|
+
return root;
|
|
6755
6865
|
}
|
|
6756
6866
|
function getDataDirReadOnly() {
|
|
6757
|
-
|
|
6758
|
-
if (override)
|
|
6759
|
-
return override;
|
|
6760
|
-
return join(process.env["HOME"] || process.env["USERPROFILE"] || homedir(), ".hasna", "skills");
|
|
6867
|
+
return getDataRoot();
|
|
6761
6868
|
}
|
|
6762
6869
|
function getConfigPathReadOnly(scope) {
|
|
6763
6870
|
if (scope === "global")
|
|
6764
|
-
return
|
|
6765
|
-
return
|
|
6871
|
+
return join3(getDataDirReadOnly(), "config.json");
|
|
6872
|
+
return join3(process.cwd(), "skills.config.json");
|
|
6766
6873
|
}
|
|
6767
6874
|
function loadConfigReadOnly() {
|
|
6768
6875
|
const canonicalConfigPath = getConfigPathReadOnly("global");
|
|
6769
6876
|
let globalConfig2;
|
|
6770
|
-
if (
|
|
6877
|
+
if (existsSync2(canonicalConfigPath)) {
|
|
6771
6878
|
globalConfig2 = readConfigFile(canonicalConfigPath);
|
|
6772
|
-
} else if (
|
|
6879
|
+
} else if (hasOperatorOverride()) {
|
|
6773
6880
|
globalConfig2 = {};
|
|
6774
6881
|
} else {
|
|
6775
6882
|
globalConfig2 = readConfigFile(legacyConfigFilePath());
|
|
@@ -6778,16 +6885,16 @@ function loadConfigReadOnly() {
|
|
|
6778
6885
|
return { ...globalConfig2, ...projectConfig };
|
|
6779
6886
|
}
|
|
6780
6887
|
function legacyConfigFilePath() {
|
|
6781
|
-
return
|
|
6888
|
+
return join3(process.env["HOME"] || process.env["USERPROFILE"] || homedir3(), ".skillsrc");
|
|
6782
6889
|
}
|
|
6783
6890
|
function getConfigPath(scope) {
|
|
6784
6891
|
if (scope === "global") {
|
|
6785
|
-
return
|
|
6892
|
+
return join3(getDataDir(), "config.json");
|
|
6786
6893
|
}
|
|
6787
|
-
return
|
|
6894
|
+
return join3(process.cwd(), "skills.config.json");
|
|
6788
6895
|
}
|
|
6789
6896
|
function readConfigFile(path) {
|
|
6790
|
-
if (!
|
|
6897
|
+
if (!existsSync2(path))
|
|
6791
6898
|
return {};
|
|
6792
6899
|
let parsed;
|
|
6793
6900
|
try {
|
|
@@ -6811,9 +6918,11 @@ function loadConfig() {
|
|
|
6811
6918
|
const projectConfig = readConfigFile(getConfigPath("project"));
|
|
6812
6919
|
return { ...globalConfig2, ...projectConfig };
|
|
6813
6920
|
}
|
|
6814
|
-
var ENUM_KEYS, STRING_KEYS,
|
|
6921
|
+
var ENUM_KEYS, STRING_KEYS, INSTALLED_SKILLS_DIRNAME = "installed", SKILLS_CACHE_DIRNAME = "skills", LAYOUT_MIGRATION_RECORD = ".layout-migration.json";
|
|
6815
6922
|
var init_config = __esm(() => {
|
|
6816
6923
|
init_retired_settings();
|
|
6924
|
+
init_app_home();
|
|
6925
|
+
init_app_home();
|
|
6817
6926
|
ENUM_KEYS = {
|
|
6818
6927
|
defaultAgent: ["claude", "codex", "gemini", "pi", "opencode", "all"],
|
|
6819
6928
|
defaultScope: ["global", "project"],
|
|
@@ -6905,23 +7014,23 @@ __export(exports_auth_store, {
|
|
|
6905
7014
|
getApiKey: () => getApiKey,
|
|
6906
7015
|
clearAuthConfig: () => clearAuthConfig
|
|
6907
7016
|
});
|
|
6908
|
-
import { existsSync as
|
|
6909
|
-
import { dirname as dirname5, join as
|
|
6910
|
-
import { homedir as
|
|
7017
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync6, readFileSync as readFileSync11, writeFileSync as writeFileSync6, unlinkSync } from "fs";
|
|
7018
|
+
import { dirname as dirname5, join as join14 } from "path";
|
|
7019
|
+
import { homedir as homedir5 } from "os";
|
|
6911
7020
|
function getAuthFilePath() {
|
|
6912
|
-
return
|
|
7021
|
+
return join14(getDataDir(), "auth.json");
|
|
6913
7022
|
}
|
|
6914
7023
|
function getAuthFilePathReadOnly() {
|
|
6915
|
-
return
|
|
7024
|
+
return join14(getDataDirReadOnly(), "auth.json");
|
|
6916
7025
|
}
|
|
6917
7026
|
function legacyAuthFilePath() {
|
|
6918
|
-
return
|
|
7027
|
+
return join14(process.env["HOME"] || process.env["USERPROFILE"] || homedir5(), ".skills", "auth.json");
|
|
6919
7028
|
}
|
|
6920
7029
|
function getAuthConfig() {
|
|
6921
7030
|
if (cachedConfig !== undefined)
|
|
6922
7031
|
return cachedConfig;
|
|
6923
7032
|
try {
|
|
6924
|
-
const file =
|
|
7033
|
+
const file = existsSync13(getAuthFilePath()) ? getAuthFilePath() : legacyAuthFilePath();
|
|
6925
7034
|
const raw = readFileSync11(file, "utf-8");
|
|
6926
7035
|
const config2 = JSON.parse(raw);
|
|
6927
7036
|
if (!config2.apiKey) {
|
|
@@ -6960,7 +7069,7 @@ function getApiKey() {
|
|
|
6960
7069
|
}
|
|
6961
7070
|
function getAuthConfigReadOnly() {
|
|
6962
7071
|
try {
|
|
6963
|
-
const file =
|
|
7072
|
+
const file = existsSync13(getAuthFilePathReadOnly()) ? getAuthFilePathReadOnly() : legacyAuthFilePath();
|
|
6964
7073
|
const raw = readFileSync11(file, "utf-8");
|
|
6965
7074
|
const config2 = JSON.parse(raw);
|
|
6966
7075
|
if (!config2.apiKey)
|
|
@@ -12943,7 +13052,7 @@ class StdioServerTransport {
|
|
|
12943
13052
|
// package.json
|
|
12944
13053
|
var package_default = {
|
|
12945
13054
|
name: "@hasna/skills",
|
|
12946
|
-
version: "0.1.
|
|
13055
|
+
version: "0.1.72",
|
|
12947
13056
|
description: "Skills library for AI coding agents",
|
|
12948
13057
|
type: "module",
|
|
12949
13058
|
bin: {
|
|
@@ -13035,6 +13144,7 @@ var package_default = {
|
|
|
13035
13144
|
"@aws-sdk/client-ecs": "^3.1079.0",
|
|
13036
13145
|
"@aws-sdk/client-s3": "^3.1079.0",
|
|
13037
13146
|
"@hasna/events": "0.1.16",
|
|
13147
|
+
"@hasna/paths": "0.1.0",
|
|
13038
13148
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
13039
13149
|
chalk: "^5.3.0",
|
|
13040
13150
|
commander: "^12.1.0",
|
|
@@ -20887,14 +20997,14 @@ var EMPTY_COMPLETION_RESULT = {
|
|
|
20887
20997
|
|
|
20888
20998
|
// src/lib/registry.ts
|
|
20889
20999
|
init_config();
|
|
20890
|
-
import { existsSync as
|
|
20891
|
-
import { join as
|
|
21000
|
+
import { existsSync as existsSync8, readFileSync as readFileSync6, readdirSync as readdirSync6 } from "fs";
|
|
21001
|
+
import { join as join9 } from "path";
|
|
20892
21002
|
|
|
20893
21003
|
// src/lib/portable-skills.ts
|
|
20894
21004
|
init_config();
|
|
20895
21005
|
import {
|
|
20896
21006
|
cpSync as cpSync2,
|
|
20897
|
-
existsSync as
|
|
21007
|
+
existsSync as existsSync7,
|
|
20898
21008
|
mkdirSync as mkdirSync3,
|
|
20899
21009
|
mkdtempSync,
|
|
20900
21010
|
readdirSync as readdirSync5,
|
|
@@ -20903,7 +21013,7 @@ import {
|
|
|
20903
21013
|
statSync as statSync6,
|
|
20904
21014
|
writeFileSync as writeFileSync3
|
|
20905
21015
|
} from "fs";
|
|
20906
|
-
import { basename as basename2, dirname as dirname3, isAbsolute as isAbsolute2, join as
|
|
21016
|
+
import { basename as basename2, dirname as dirname3, isAbsolute as isAbsolute2, join as join8, normalize as normalize2 } from "path";
|
|
20907
21017
|
|
|
20908
21018
|
// src/lib/registry-data/development-tools.ts
|
|
20909
21019
|
var DEVELOPMENT_TOOLS_SKILLS = [
|
|
@@ -21623,8 +21733,8 @@ var SKILLS = [
|
|
|
21623
21733
|
];
|
|
21624
21734
|
|
|
21625
21735
|
// src/lib/hosted-skill-set.ts
|
|
21626
|
-
import { existsSync as
|
|
21627
|
-
import { join as
|
|
21736
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
21737
|
+
import { join as join4 } from "path";
|
|
21628
21738
|
var HOSTED_RUNTIMES = new Set(["hosted"]);
|
|
21629
21739
|
var HOSTED_SOURCES = new Set(["remote", "private-hosted"]);
|
|
21630
21740
|
function normalizeMarker(value) {
|
|
@@ -21637,8 +21747,8 @@ function isHostedMetadataPackage(pkg) {
|
|
|
21637
21747
|
return HOSTED_RUNTIMES.has(normalizeMarker(skills.runtime)) || HOSTED_SOURCES.has(normalizeMarker(skills.source));
|
|
21638
21748
|
}
|
|
21639
21749
|
function isHostedMetadataSkillDir(skillDir) {
|
|
21640
|
-
const pkgPath =
|
|
21641
|
-
if (!
|
|
21750
|
+
const pkgPath = join4(skillDir, "package.json");
|
|
21751
|
+
if (!existsSync3(pkgPath))
|
|
21642
21752
|
return false;
|
|
21643
21753
|
try {
|
|
21644
21754
|
return isHostedMetadataPackage(JSON.parse(readFileSync2(pkgPath, "utf8")));
|
|
@@ -21662,8 +21772,8 @@ var BRACE_SOURCE_EXCLUSION = new RegExp(`^!skills/\\{(${SLUG}(?:,${SLUG})+)\\}/s
|
|
|
21662
21772
|
var SINGLE_SOURCE_EXCLUSION = new RegExp(`^!skills/(${SLUG})/src$`);
|
|
21663
21773
|
|
|
21664
21774
|
// src/lib/skill-validation.ts
|
|
21665
|
-
import { existsSync as
|
|
21666
|
-
import { isAbsolute, join as
|
|
21775
|
+
import { existsSync as existsSync4, lstatSync, readFileSync as readFileSync3, readdirSync as readdirSync3, statSync as statSync3 } from "fs";
|
|
21776
|
+
import { isAbsolute, join as join5, normalize } from "path";
|
|
21667
21777
|
var VALID_SKILL_KINDS = ["executable", "instruction"];
|
|
21668
21778
|
var DOC_FILES = ["SKILL.md", "README.md", "CLAUDE.md"];
|
|
21669
21779
|
var RESERVED_SKILL_ENTRIES = new Set([
|
|
@@ -21801,7 +21911,7 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
21801
21911
|
binCommands: [],
|
|
21802
21912
|
docFiles: []
|
|
21803
21913
|
};
|
|
21804
|
-
if (!
|
|
21914
|
+
if (!existsSync4(skillPath)) {
|
|
21805
21915
|
add(issues, "skill.dir_missing", `Skill directory not found: ${skillPath}`);
|
|
21806
21916
|
return {
|
|
21807
21917
|
name: bareName,
|
|
@@ -21816,7 +21926,7 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
21816
21926
|
add(issues, "skill.name_invalid", `Skill name '${bareName}' must use lowercase letters, numbers, dots, underscores, or hyphens`);
|
|
21817
21927
|
}
|
|
21818
21928
|
for (const entry of readdirSync3(skillPath).sort()) {
|
|
21819
|
-
const entryPath =
|
|
21929
|
+
const entryPath = join5(skillPath, entry);
|
|
21820
21930
|
if (RESERVED_SKILL_ENTRIES.has(entry)) {
|
|
21821
21931
|
add(issues, "skill.reserved_file", `Reserved file '${entry}' is not allowed in skill packages`);
|
|
21822
21932
|
}
|
|
@@ -21828,14 +21938,14 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
21828
21938
|
}
|
|
21829
21939
|
}
|
|
21830
21940
|
for (const docFile of DOC_FILES) {
|
|
21831
|
-
if (
|
|
21941
|
+
if (existsSync4(join5(skillPath, docFile)))
|
|
21832
21942
|
metadata.docFiles.push(docFile);
|
|
21833
21943
|
}
|
|
21834
21944
|
if (metadata.docFiles.length === 0) {
|
|
21835
21945
|
add(issues, "skill.docs_missing", "Missing documentation file: expected SKILL.md, README.md, or CLAUDE.md");
|
|
21836
21946
|
}
|
|
21837
|
-
const skillMdPath =
|
|
21838
|
-
if (
|
|
21947
|
+
const skillMdPath = join5(skillPath, "SKILL.md");
|
|
21948
|
+
if (existsSync4(skillMdPath)) {
|
|
21839
21949
|
const frontmatter = parseSkillFrontmatter(readFileSync3(skillMdPath, "utf-8"));
|
|
21840
21950
|
if (!frontmatter) {
|
|
21841
21951
|
add(warnings, "skill.frontmatter_missing", "SKILL.md has no YAML frontmatter");
|
|
@@ -21878,8 +21988,8 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
21878
21988
|
}
|
|
21879
21989
|
metadata.kind = resolvedKind;
|
|
21880
21990
|
const isInstruction = resolvedKind === "instruction";
|
|
21881
|
-
const pkgPath =
|
|
21882
|
-
if (!
|
|
21991
|
+
const pkgPath = join5(skillPath, "package.json");
|
|
21992
|
+
if (!existsSync4(pkgPath)) {
|
|
21883
21993
|
if (!isInstruction)
|
|
21884
21994
|
add(issues, "package.missing", "Missing package.json");
|
|
21885
21995
|
} else {
|
|
@@ -21937,8 +22047,8 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
21937
22047
|
add(issues, "package.bin_target_unsafe", `package.json bin '${command}' target '${target}' must stay inside the skill directory`);
|
|
21938
22048
|
continue;
|
|
21939
22049
|
}
|
|
21940
|
-
const targetPath =
|
|
21941
|
-
if (!
|
|
22050
|
+
const targetPath = join5(skillPath, target);
|
|
22051
|
+
if (!existsSync4(targetPath)) {
|
|
21942
22052
|
add(warnings, "package.bin_target_missing", `package.json bin '${command}' target '${target}' is not present before build`);
|
|
21943
22053
|
} else if (statSync3(targetPath).isDirectory()) {
|
|
21944
22054
|
add(issues, "package.bin_target_directory", `package.json bin '${command}' target '${target}' must point to a file, not a directory`);
|
|
@@ -21955,17 +22065,17 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
21955
22065
|
metadata.runtime = "none";
|
|
21956
22066
|
} else {
|
|
21957
22067
|
metadata.runtime = hostedMetadata ? "hosted" : "local";
|
|
21958
|
-
const srcDir =
|
|
22068
|
+
const srcDir = join5(skillPath, "src");
|
|
21959
22069
|
if (hostedMetadata) {
|
|
21960
|
-
if (
|
|
22070
|
+
if (existsSync4(srcDir)) {
|
|
21961
22071
|
add(issues, "skill.hosted_source_forbidden", "Hosted metadata skills must not include local implementation source");
|
|
21962
22072
|
}
|
|
21963
|
-
} else if (!
|
|
22073
|
+
} else if (!existsSync4(srcDir)) {
|
|
21964
22074
|
add(issues, "skill.src_missing", "Missing src/ directory");
|
|
21965
|
-
} else if (!
|
|
22075
|
+
} else if (!existsSync4(join5(srcDir, "index.ts")) && !existsSync4(join5(srcDir, "index.js"))) {
|
|
21966
22076
|
add(issues, "skill.src_index_missing", "Missing src/index.ts or src/index.js");
|
|
21967
22077
|
} else {
|
|
21968
|
-
const indexPath =
|
|
22078
|
+
const indexPath = existsSync4(join5(srcDir, "index.ts")) ? join5(srcDir, "index.ts") : join5(srcDir, "index.js");
|
|
21969
22079
|
const size = statSync3(indexPath).size;
|
|
21970
22080
|
if (size < 50)
|
|
21971
22081
|
add(warnings, "skill.src_index_minimal", `Source entry point is very small (${size}B)`);
|
|
@@ -21983,8 +22093,8 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
21983
22093
|
|
|
21984
22094
|
// src/lib/skill-hash.ts
|
|
21985
22095
|
import { createHash } from "crypto";
|
|
21986
|
-
import { existsSync as
|
|
21987
|
-
import { join as
|
|
22096
|
+
import { existsSync as existsSync5, readdirSync as readdirSync4, readFileSync as readFileSync4, statSync as statSync4 } from "fs";
|
|
22097
|
+
import { join as join6, sep } from "path";
|
|
21988
22098
|
var CONTENT_HASH_ALGORITHM = "sha256";
|
|
21989
22099
|
var HASH_EXCLUDE_DIRS = new Set([".git", "node_modules", "dist", "build", ".turbo"]);
|
|
21990
22100
|
var HASH_COVERAGE = [
|
|
@@ -22043,8 +22153,8 @@ function collectBundleFiles(skillPath) {
|
|
|
22043
22153
|
if (seen.has(entry))
|
|
22044
22154
|
continue;
|
|
22045
22155
|
seen.add(entry);
|
|
22046
|
-
const absolute =
|
|
22047
|
-
if (!
|
|
22156
|
+
const absolute = join6(skillPath, entry);
|
|
22157
|
+
if (!existsSync5(absolute))
|
|
22048
22158
|
continue;
|
|
22049
22159
|
if (statSync4(absolute).isDirectory())
|
|
22050
22160
|
collectDirectory(files, absolute, entry);
|
|
@@ -22057,7 +22167,7 @@ function collectDirectory(files, dir, rel) {
|
|
|
22057
22167
|
for (const entry of readdirSync4(dir).sort()) {
|
|
22058
22168
|
if (entry.startsWith("."))
|
|
22059
22169
|
continue;
|
|
22060
|
-
const absolute =
|
|
22170
|
+
const absolute = join6(dir, entry);
|
|
22061
22171
|
const childRel = `${rel}/${entry}`;
|
|
22062
22172
|
let stats;
|
|
22063
22173
|
try {
|
|
@@ -22277,14 +22387,14 @@ function validateRuntimeContract(manifest, issues, strict) {
|
|
|
22277
22387
|
// src/lib/portable-skills-files.ts
|
|
22278
22388
|
import {
|
|
22279
22389
|
cpSync,
|
|
22280
|
-
existsSync as
|
|
22390
|
+
existsSync as existsSync6,
|
|
22281
22391
|
lstatSync as lstatSync2,
|
|
22282
22392
|
mkdirSync as mkdirSync2,
|
|
22283
22393
|
readFileSync as readFileSync5,
|
|
22284
22394
|
realpathSync,
|
|
22285
22395
|
writeFileSync as writeFileSync2
|
|
22286
22396
|
} from "fs";
|
|
22287
|
-
import { basename, dirname as dirname2, join as
|
|
22397
|
+
import { basename, dirname as dirname2, join as join7, relative } from "path";
|
|
22288
22398
|
var ANY_SEGMENT_COPY_EXCLUDES = new Set([
|
|
22289
22399
|
".git",
|
|
22290
22400
|
".DS_Store",
|
|
@@ -22327,12 +22437,12 @@ function normalizePortableSkillName(name) {
|
|
|
22327
22437
|
return normalized;
|
|
22328
22438
|
}
|
|
22329
22439
|
function readPortableSkillManifest(skillPath, fallbackName = basename(skillPath)) {
|
|
22330
|
-
const skillJsonPath =
|
|
22331
|
-
const skillMdPath =
|
|
22332
|
-
const pkgPath =
|
|
22333
|
-
const jsonManifest =
|
|
22334
|
-
const frontmatter =
|
|
22335
|
-
const pkg =
|
|
22440
|
+
const skillJsonPath = join7(skillPath, "skill.json");
|
|
22441
|
+
const skillMdPath = join7(skillPath, "SKILL.md");
|
|
22442
|
+
const pkgPath = join7(skillPath, "package.json");
|
|
22443
|
+
const jsonManifest = existsSync6(skillJsonPath) ? readJsonObject(skillJsonPath) : undefined;
|
|
22444
|
+
const frontmatter = existsSync6(skillMdPath) ? parseSkillFrontmatter(readFileSync5(skillMdPath, "utf-8")) ?? undefined : undefined;
|
|
22445
|
+
const pkg = existsSync6(pkgPath) ? readJsonObject(pkgPath) : undefined;
|
|
22336
22446
|
const name = normalizePortableSkillName(stringField(jsonManifest, "name") ?? frontmatter?.name ?? stringValue(pkg?.name) ?? fallbackName);
|
|
22337
22447
|
const description = stringField(jsonManifest, "description") ?? frontmatter?.description ?? stringValue(pkg?.description) ?? `${name} skill`;
|
|
22338
22448
|
const version2 = stringField(jsonManifest, "version") ?? frontmatter?.version ?? stringValue(pkg?.version) ?? PORTABLE_SKILL_DEFAULT_VERSION;
|
|
@@ -22378,7 +22488,7 @@ function createInstructionManifest(name, options) {
|
|
|
22378
22488
|
}
|
|
22379
22489
|
function writeInstructionSkillTemplate(skillPath, manifest) {
|
|
22380
22490
|
mkdirSync2(skillPath, { recursive: true });
|
|
22381
|
-
writeFileSync2(
|
|
22491
|
+
writeFileSync2(join7(skillPath, "SKILL.md"), renderInstructionSkillMd(manifest));
|
|
22382
22492
|
writeSkillJsonWithHash(skillPath, manifest);
|
|
22383
22493
|
}
|
|
22384
22494
|
function renderInstructionSkillMd(manifest) {
|
|
@@ -22427,12 +22537,12 @@ function createPortableManifest(name, options) {
|
|
|
22427
22537
|
};
|
|
22428
22538
|
}
|
|
22429
22539
|
function writePortableSkillTemplate(skillPath, manifest) {
|
|
22430
|
-
mkdirSync2(
|
|
22431
|
-
writeFileSync2(
|
|
22432
|
-
writeFileSync2(
|
|
22433
|
-
writeFileSync2(
|
|
22434
|
-
writeFileSync2(
|
|
22435
|
-
writeFileSync2(
|
|
22540
|
+
mkdirSync2(join7(skillPath, "src"), { recursive: true });
|
|
22541
|
+
writeFileSync2(join7(skillPath, "SKILL.md"), renderSkillMd(manifest));
|
|
22542
|
+
writeFileSync2(join7(skillPath, "AGENTS.md"), renderAgentsMd(manifest));
|
|
22543
|
+
writeFileSync2(join7(skillPath, "package.json"), renderPackageJson(manifest));
|
|
22544
|
+
writeFileSync2(join7(skillPath, "tsconfig.json"), renderTsconfig());
|
|
22545
|
+
writeFileSync2(join7(skillPath, "src", "index.ts"), renderEntrypoint(manifest));
|
|
22436
22546
|
writeSkillJsonWithHash(skillPath, manifest);
|
|
22437
22547
|
}
|
|
22438
22548
|
function fillContractDefaults(manifest, entrypoint) {
|
|
@@ -22457,7 +22567,7 @@ function writeSkillJsonWithHash(skillPath, manifest) {
|
|
|
22457
22567
|
content_hash: undefined
|
|
22458
22568
|
}
|
|
22459
22569
|
};
|
|
22460
|
-
writeFileSync2(
|
|
22570
|
+
writeFileSync2(join7(skillPath, "skill.json"), `${JSON.stringify({ ...existing, ...renderSkillJsonObject(withoutHash) }, null, 2)}
|
|
22461
22571
|
`);
|
|
22462
22572
|
const hash = computeContentHash(skillPath);
|
|
22463
22573
|
const withHash = {
|
|
@@ -22467,13 +22577,13 @@ function writeSkillJsonWithHash(skillPath, manifest) {
|
|
|
22467
22577
|
content_hash: hash
|
|
22468
22578
|
}
|
|
22469
22579
|
};
|
|
22470
|
-
writeFileSync2(
|
|
22580
|
+
writeFileSync2(join7(skillPath, "skill.json"), `${JSON.stringify({ ...existing, ...renderSkillJsonObject(withHash) }, null, 2)}
|
|
22471
22581
|
`);
|
|
22472
22582
|
return withHash;
|
|
22473
22583
|
}
|
|
22474
22584
|
function readExistingSkillJson(skillPath) {
|
|
22475
|
-
const path =
|
|
22476
|
-
if (!
|
|
22585
|
+
const path = join7(skillPath, "skill.json");
|
|
22586
|
+
if (!existsSync6(path))
|
|
22477
22587
|
return {};
|
|
22478
22588
|
try {
|
|
22479
22589
|
const parsed = JSON.parse(readFileSync5(path, "utf-8"));
|
|
@@ -22506,28 +22616,28 @@ function ensurePortableSkillFiles(skillPath, manifest) {
|
|
|
22506
22616
|
tags: next.tags?.length ? next.tags : ["custom", next.name]
|
|
22507
22617
|
};
|
|
22508
22618
|
const entry = next.commands[0]?.entry ?? "src/index.ts";
|
|
22509
|
-
if (entry && !
|
|
22510
|
-
mkdirSync2(dirname2(
|
|
22511
|
-
writeFileSync2(
|
|
22619
|
+
if (entry && !existsSync6(join7(skillPath, entry))) {
|
|
22620
|
+
mkdirSync2(dirname2(join7(skillPath, entry)), { recursive: true });
|
|
22621
|
+
writeFileSync2(join7(skillPath, entry), renderEntrypoint(next));
|
|
22512
22622
|
}
|
|
22513
|
-
if (!
|
|
22514
|
-
writeFileSync2(
|
|
22623
|
+
if (!existsSync6(join7(skillPath, "SKILL.md")))
|
|
22624
|
+
writeFileSync2(join7(skillPath, "SKILL.md"), renderSkillMd(next));
|
|
22515
22625
|
else
|
|
22516
|
-
writeFileSync2(
|
|
22517
|
-
if (!
|
|
22518
|
-
writeFileSync2(
|
|
22626
|
+
writeFileSync2(join7(skillPath, "SKILL.md"), ensureSkillMdFrontmatter(readFileSync5(join7(skillPath, "SKILL.md"), "utf-8"), next));
|
|
22627
|
+
if (!existsSync6(join7(skillPath, "AGENTS.md")))
|
|
22628
|
+
writeFileSync2(join7(skillPath, "AGENTS.md"), renderAgentsMd(next));
|
|
22519
22629
|
ensurePackageJson(skillPath, next);
|
|
22520
|
-
if (!
|
|
22521
|
-
writeFileSync2(
|
|
22630
|
+
if (!existsSync6(join7(skillPath, "tsconfig.json")))
|
|
22631
|
+
writeFileSync2(join7(skillPath, "tsconfig.json"), renderTsconfig());
|
|
22522
22632
|
writeSkillJsonWithHash(skillPath, next);
|
|
22523
22633
|
return readPortableSkillManifest(skillPath, next.name);
|
|
22524
22634
|
}
|
|
22525
22635
|
function ensurePackageJson(skillPath, manifest) {
|
|
22526
|
-
const pkgPath =
|
|
22636
|
+
const pkgPath = join7(skillPath, "package.json");
|
|
22527
22637
|
const first = manifest.commands[0] ?? { name: manifest.name, entry: "src/index.ts" };
|
|
22528
22638
|
const commandName = normalizePortableSkillName(first.name || manifest.name);
|
|
22529
22639
|
const entry = (first.entry ?? "src/index.ts").replace(/^\.\//, "");
|
|
22530
|
-
if (!
|
|
22640
|
+
if (!existsSync6(pkgPath)) {
|
|
22531
22641
|
writeFileSync2(pkgPath, renderPackageJson(manifest));
|
|
22532
22642
|
return;
|
|
22533
22643
|
}
|
|
@@ -22570,8 +22680,8 @@ function ensureInstructionSkillFiles(skillPath, manifest) {
|
|
|
22570
22680
|
inputs: [],
|
|
22571
22681
|
commands: []
|
|
22572
22682
|
};
|
|
22573
|
-
if (!
|
|
22574
|
-
writeFileSync2(
|
|
22683
|
+
if (!existsSync6(join7(skillPath, "SKILL.md"))) {
|
|
22684
|
+
writeFileSync2(join7(skillPath, "SKILL.md"), renderSkillMd(next));
|
|
22575
22685
|
}
|
|
22576
22686
|
writeSkillJsonWithHash(skillPath, next);
|
|
22577
22687
|
return readPortableSkillManifest(skillPath, next.name);
|
|
@@ -22854,18 +22964,18 @@ var LEGACY_CUSTOM_DIRNAME = "custom";
|
|
|
22854
22964
|
function getPortableSkillsRoot(options = {}) {
|
|
22855
22965
|
if (options.rootDir)
|
|
22856
22966
|
return options.rootDir;
|
|
22857
|
-
const appDir = options.homeDir ?
|
|
22858
|
-
const cache =
|
|
22967
|
+
const appDir = options.homeDir ? join8(options.homeDir, ".hasna", "skills") : getDataDir();
|
|
22968
|
+
const cache = join8(appDir, SKILLS_CACHE_DIRNAME);
|
|
22859
22969
|
if (isOwnerLayoutMigrated(appDir) && safeIsDirectory(cache))
|
|
22860
22970
|
return cache;
|
|
22861
|
-
const installed =
|
|
22971
|
+
const installed = join8(appDir, INSTALLED_SKILLS_DIRNAME);
|
|
22862
22972
|
migrateLegacySkillLayout(appDir, installed);
|
|
22863
22973
|
return installed;
|
|
22864
22974
|
}
|
|
22865
22975
|
function looksLikeSkillDirectory(path) {
|
|
22866
22976
|
if (!safeIsDirectory(path))
|
|
22867
22977
|
return false;
|
|
22868
|
-
return
|
|
22978
|
+
return existsSync7(join8(path, "SKILL.md")) || existsSync7(join8(path, "skill.json")) || existsSync7(join8(path, "package.json"));
|
|
22869
22979
|
}
|
|
22870
22980
|
function migrateLegacySkillLayout(appDir, installed) {
|
|
22871
22981
|
if (!safeIsDirectory(appDir))
|
|
@@ -22875,7 +22985,7 @@ function migrateLegacySkillLayout(appDir, installed) {
|
|
|
22875
22985
|
for (const entry of readdirSync5(appDir)) {
|
|
22876
22986
|
if (entry.startsWith(".") || entry === INSTALLED_SKILLS_DIRNAME)
|
|
22877
22987
|
continue;
|
|
22878
|
-
const path =
|
|
22988
|
+
const path = join8(appDir, entry);
|
|
22879
22989
|
if (entry === LEGACY_CUSTOM_DIRNAME) {
|
|
22880
22990
|
if (!safeIsDirectory(path))
|
|
22881
22991
|
continue;
|
|
@@ -22883,7 +22993,7 @@ function migrateLegacySkillLayout(appDir, installed) {
|
|
|
22883
22993
|
for (const nested of readdirSync5(path)) {
|
|
22884
22994
|
if (nested.startsWith("."))
|
|
22885
22995
|
continue;
|
|
22886
|
-
const nestedPath =
|
|
22996
|
+
const nestedPath = join8(path, nested);
|
|
22887
22997
|
if (looksLikeSkillDirectory(nestedPath))
|
|
22888
22998
|
candidates.push({ from: nestedPath, name: nested });
|
|
22889
22999
|
}
|
|
@@ -22897,10 +23007,10 @@ function migrateLegacySkillLayout(appDir, installed) {
|
|
|
22897
23007
|
return;
|
|
22898
23008
|
}
|
|
22899
23009
|
for (const { from, name } of candidates) {
|
|
22900
|
-
const target =
|
|
22901
|
-
if (
|
|
23010
|
+
const target = join8(installed, name);
|
|
23011
|
+
if (existsSync7(target))
|
|
22902
23012
|
continue;
|
|
22903
|
-
const staging =
|
|
23013
|
+
const staging = join8(installed, `.migrating-${name}-${process.pid}`);
|
|
22904
23014
|
try {
|
|
22905
23015
|
rmSync(staging, { recursive: true, force: true });
|
|
22906
23016
|
cpSync2(from, staging, { recursive: true, errorOnExist: false });
|
|
@@ -22913,7 +23023,7 @@ function migrateLegacySkillLayout(appDir, installed) {
|
|
|
22913
23023
|
}
|
|
22914
23024
|
}
|
|
22915
23025
|
function getPortableSkillPath(name, options = {}) {
|
|
22916
|
-
return
|
|
23026
|
+
return join8(getPortableSkillsRoot(options), normalizePortableSkillName(name));
|
|
22917
23027
|
}
|
|
22918
23028
|
function findPortableSkill(name, options = {}) {
|
|
22919
23029
|
let normalized;
|
|
@@ -22923,7 +23033,7 @@ function findPortableSkill(name, options = {}) {
|
|
|
22923
23033
|
return null;
|
|
22924
23034
|
}
|
|
22925
23035
|
const path = getPortableSkillPath(normalized, options);
|
|
22926
|
-
if (!
|
|
23036
|
+
if (!existsSync7(path) || !statSync6(path).isDirectory())
|
|
22927
23037
|
return null;
|
|
22928
23038
|
try {
|
|
22929
23039
|
return summarizePortableSkill(path, normalized);
|
|
@@ -22939,7 +23049,7 @@ function listPortableSkills(options = {}) {
|
|
|
22939
23049
|
for (const entry of readdirSync5(root).sort()) {
|
|
22940
23050
|
if (entry.startsWith("."))
|
|
22941
23051
|
continue;
|
|
22942
|
-
const path =
|
|
23052
|
+
const path = join8(root, entry);
|
|
22943
23053
|
if (!safeIsDirectory(path))
|
|
22944
23054
|
continue;
|
|
22945
23055
|
try {
|
|
@@ -22973,8 +23083,8 @@ function isOfficialSkillName(name) {
|
|
|
22973
23083
|
function scaffoldPortableSkill(name, options = {}) {
|
|
22974
23084
|
const skillName = normalizePortableSkillName(name);
|
|
22975
23085
|
const root = getPortableSkillsRoot(options);
|
|
22976
|
-
const skillPath =
|
|
22977
|
-
if (
|
|
23086
|
+
const skillPath = join8(root, skillName);
|
|
23087
|
+
if (existsSync7(skillPath)) {
|
|
22978
23088
|
if (!options.overwrite)
|
|
22979
23089
|
throw new Error(`Skill '${skillName}' already exists at ${skillPath}`);
|
|
22980
23090
|
rmSync(skillPath, { recursive: true, force: true });
|
|
@@ -22992,7 +23102,7 @@ function scaffoldPortableSkill(name, options = {}) {
|
|
|
22992
23102
|
}
|
|
22993
23103
|
function portPortableSkill(sourcePath, options = {}) {
|
|
22994
23104
|
const absoluteSource = normalize2(sourcePath);
|
|
22995
|
-
if (!
|
|
23105
|
+
if (!existsSync7(absoluteSource) || !statSync6(absoluteSource).isDirectory()) {
|
|
22996
23106
|
throw new Error(`Skill source directory not found: ${sourcePath}`);
|
|
22997
23107
|
}
|
|
22998
23108
|
const inferred = readPortableSkillManifest(absoluteSource, basename2(absoluteSource));
|
|
@@ -23004,8 +23114,8 @@ function portPortableSkill(sourcePath, options = {}) {
|
|
|
23004
23114
|
throw new Error(`${via} Importing it would shadow the official '${skillName}'. ` + `Pass --name to choose a different name, or --allow-shadow to override deliberately.`);
|
|
23005
23115
|
}
|
|
23006
23116
|
const root = getPortableSkillsRoot(options);
|
|
23007
|
-
const destination =
|
|
23008
|
-
if (
|
|
23117
|
+
const destination = join8(root, skillName);
|
|
23118
|
+
if (existsSync7(destination)) {
|
|
23009
23119
|
if (!options.overwrite)
|
|
23010
23120
|
throw new Error(`Skill '${skillName}' already exists at ${destination}`);
|
|
23011
23121
|
rmSync(destination, { recursive: true, force: true });
|
|
@@ -23033,10 +23143,10 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
23033
23143
|
const issues = [...base.issues];
|
|
23034
23144
|
const warnings = [...base.warnings];
|
|
23035
23145
|
let manifest;
|
|
23036
|
-
if (
|
|
23037
|
-
const skillJsonPath =
|
|
23038
|
-
const skillMdPath =
|
|
23039
|
-
if (!
|
|
23146
|
+
if (existsSync7(skillPath)) {
|
|
23147
|
+
const skillJsonPath = join8(skillPath, "skill.json");
|
|
23148
|
+
const skillMdPath = join8(skillPath, "SKILL.md");
|
|
23149
|
+
if (!existsSync7(skillJsonPath) && !existsSync7(skillMdPath)) {
|
|
23040
23150
|
add3(issues, "portable.manifest_missing", "Missing portable manifest: expected SKILL.md frontmatter and/or skill.json");
|
|
23041
23151
|
}
|
|
23042
23152
|
try {
|
|
@@ -23055,7 +23165,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
23055
23165
|
add3(issues, "portable.version_missing", "Portable manifest missing version");
|
|
23056
23166
|
}
|
|
23057
23167
|
const contractIssues = validatePortableManifestContract(manifest, {
|
|
23058
|
-
strict:
|
|
23168
|
+
strict: existsSync7(join8(skillPath, "skill.json")),
|
|
23059
23169
|
skillPath
|
|
23060
23170
|
});
|
|
23061
23171
|
for (const issue2 of contractIssues)
|
|
@@ -23091,8 +23201,8 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
23091
23201
|
add3(issues, "portable.command_entry_unsafe", `Command '${command.name}' entry '${command.entry}' must stay inside the skill directory`);
|
|
23092
23202
|
continue;
|
|
23093
23203
|
}
|
|
23094
|
-
const entryPath =
|
|
23095
|
-
if (!
|
|
23204
|
+
const entryPath = join8(skillPath, command.entry);
|
|
23205
|
+
if (!existsSync7(entryPath))
|
|
23096
23206
|
add3(issues, "portable.command_entry_missing", `Command '${command.name}' entry '${command.entry}' is missing`);
|
|
23097
23207
|
else if (statSync6(entryPath).isDirectory())
|
|
23098
23208
|
add3(issues, "portable.command_entry_directory", `Command '${command.name}' entry '${command.entry}' must be a file`);
|
|
@@ -23102,7 +23212,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
23102
23212
|
} catch (error2) {
|
|
23103
23213
|
add3(issues, "portable.manifest_invalid", error2.message);
|
|
23104
23214
|
}
|
|
23105
|
-
if (manifest?.kind !== "instruction" && !
|
|
23215
|
+
if (manifest?.kind !== "instruction" && !existsSync7(join8(skillPath, "AGENTS.md"))) {
|
|
23106
23216
|
add3(issues, "portable.agents_missing", "Missing AGENTS.md with build-out instructions for coding agents");
|
|
23107
23217
|
}
|
|
23108
23218
|
}
|
|
@@ -23360,7 +23470,7 @@ function parseSkillMdFrontmatter(content) {
|
|
|
23360
23470
|
return Object.keys(result).length > 0 ? result : null;
|
|
23361
23471
|
}
|
|
23362
23472
|
function discoverSkillsInDir(dir, source = "custom") {
|
|
23363
|
-
if (!
|
|
23473
|
+
if (!existsSync8(dir))
|
|
23364
23474
|
return [];
|
|
23365
23475
|
const result = [];
|
|
23366
23476
|
try {
|
|
@@ -23368,8 +23478,8 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
23368
23478
|
for (const entry of entries) {
|
|
23369
23479
|
if (!entry.isDirectory())
|
|
23370
23480
|
continue;
|
|
23371
|
-
const skillMdPath =
|
|
23372
|
-
if (!
|
|
23481
|
+
const skillMdPath = join9(dir, entry.name, "SKILL.md");
|
|
23482
|
+
if (!existsSync8(skillMdPath))
|
|
23373
23483
|
continue;
|
|
23374
23484
|
let content;
|
|
23375
23485
|
try {
|
|
@@ -23388,7 +23498,7 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
23388
23498
|
category: fm.category || "Development Tools",
|
|
23389
23499
|
tags: fm.tags || [],
|
|
23390
23500
|
...fm.kind ? { kind: fm.kind } : {},
|
|
23391
|
-
...isHostedMetadataSkillDir(
|
|
23501
|
+
...isHostedMetadataSkillDir(join9(dir, entry.name)) ? { serverOwned: true } : {},
|
|
23392
23502
|
source
|
|
23393
23503
|
});
|
|
23394
23504
|
}
|
|
@@ -23397,16 +23507,16 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
23397
23507
|
}
|
|
23398
23508
|
function findExtensionSkillPath(name) {
|
|
23399
23509
|
const config2 = loadConfig();
|
|
23400
|
-
if (!config2.extensionsDir || !
|
|
23510
|
+
if (!config2.extensionsDir || !existsSync8(config2.extensionsDir))
|
|
23401
23511
|
return null;
|
|
23402
23512
|
try {
|
|
23403
23513
|
const entries = readdirSync6(config2.extensionsDir, { withFileTypes: true });
|
|
23404
23514
|
for (const entry of entries) {
|
|
23405
23515
|
if (!entry.isDirectory())
|
|
23406
23516
|
continue;
|
|
23407
|
-
const skillDir =
|
|
23408
|
-
const skillMdPath =
|
|
23409
|
-
if (!
|
|
23517
|
+
const skillDir = join9(config2.extensionsDir, entry.name);
|
|
23518
|
+
const skillMdPath = join9(skillDir, "SKILL.md");
|
|
23519
|
+
if (!existsSync8(skillMdPath))
|
|
23410
23520
|
continue;
|
|
23411
23521
|
let content;
|
|
23412
23522
|
try {
|
|
@@ -23438,12 +23548,12 @@ function loadRegistry(cwd) {
|
|
|
23438
23548
|
if (registryCache && registryCacheKey === rootKey && now - registryCacheTime < REGISTRY_CACHE_TTL) {
|
|
23439
23549
|
return registryCache;
|
|
23440
23550
|
}
|
|
23441
|
-
const
|
|
23551
|
+
const dataDir2 = getDataDir();
|
|
23442
23552
|
const config2 = loadConfig();
|
|
23443
23553
|
const official = SKILLS.map((s) => ({ ...s, source: "official" }));
|
|
23444
23554
|
const extensions = config2.extensionsDir ? discoverSkillsInDir(config2.extensionsDir, "extension") : [];
|
|
23445
23555
|
const portableCustom = listPortableSkillMetas();
|
|
23446
|
-
const legacyCustom = discoverSkillsInDir(
|
|
23556
|
+
const legacyCustom = discoverSkillsInDir(join9(dataDir2, "custom"));
|
|
23447
23557
|
const globalCustom = mergeCustomSkills([...legacyCustom, ...portableCustom]);
|
|
23448
23558
|
registryCache = mergeSkillRegistryLists(official, extensions, globalCustom);
|
|
23449
23559
|
registryCacheTime = now;
|
|
@@ -23479,9 +23589,9 @@ function mergeCustomSkills(skills) {
|
|
|
23479
23589
|
}
|
|
23480
23590
|
|
|
23481
23591
|
// src/lib/installer.ts
|
|
23482
|
-
import { existsSync as
|
|
23483
|
-
import { dirname as dirname4, join as
|
|
23484
|
-
import { homedir as
|
|
23592
|
+
import { existsSync as existsSync10, readFileSync as readFileSync8, rmSync as rmSync2 } from "fs";
|
|
23593
|
+
import { dirname as dirname4, join as join11 } from "path";
|
|
23594
|
+
import { homedir as homedir4 } from "os";
|
|
23485
23595
|
import { fileURLToPath } from "url";
|
|
23486
23596
|
|
|
23487
23597
|
// src/lib/home-migration.ts
|
|
@@ -23497,8 +23607,8 @@ function normalizeSkillName(name) {
|
|
|
23497
23607
|
init_config();
|
|
23498
23608
|
|
|
23499
23609
|
// src/lib/project-state.ts
|
|
23500
|
-
import { existsSync as
|
|
23501
|
-
import { join as
|
|
23610
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
23611
|
+
import { join as join10 } from "path";
|
|
23502
23612
|
var VALID_PIN_SOURCES = [
|
|
23503
23613
|
"official",
|
|
23504
23614
|
"custom",
|
|
@@ -23513,14 +23623,14 @@ var SKILLS_PROJECT_DIR = ".skills";
|
|
|
23513
23623
|
var PROJECT_CONFIG_FILE = "project.json";
|
|
23514
23624
|
var DEFAULT_EXPORT_DIR = ".skills/exports";
|
|
23515
23625
|
function getProjectStateDir(targetDir = process.cwd()) {
|
|
23516
|
-
return
|
|
23626
|
+
return join10(targetDir, SKILLS_PROJECT_DIR);
|
|
23517
23627
|
}
|
|
23518
23628
|
function getProjectConfigPath(targetDir = process.cwd()) {
|
|
23519
|
-
return
|
|
23629
|
+
return join10(getProjectStateDir(targetDir), PROJECT_CONFIG_FILE);
|
|
23520
23630
|
}
|
|
23521
23631
|
function loadProjectConfig(targetDir = process.cwd()) {
|
|
23522
23632
|
const path = getProjectConfigPath(targetDir);
|
|
23523
|
-
if (!
|
|
23633
|
+
if (!existsSync9(path))
|
|
23524
23634
|
return null;
|
|
23525
23635
|
try {
|
|
23526
23636
|
return normalizeProjectConfig(JSON.parse(readFileSync7(path, "utf-8")));
|
|
@@ -23622,12 +23732,12 @@ var __dirname2 = dirname4(fileURLToPath(import.meta.url));
|
|
|
23622
23732
|
function findSkillsDir() {
|
|
23623
23733
|
let dir = __dirname2;
|
|
23624
23734
|
for (let i = 0;i < 5; i++) {
|
|
23625
|
-
const candidate =
|
|
23626
|
-
if (
|
|
23735
|
+
const candidate = join11(dir, "skills");
|
|
23736
|
+
if (existsSync10(candidate) && !dir.includes(".skills"))
|
|
23627
23737
|
return candidate;
|
|
23628
23738
|
dir = dirname4(dir);
|
|
23629
23739
|
}
|
|
23630
|
-
return
|
|
23740
|
+
return join11(__dirname2, "..", "skills");
|
|
23631
23741
|
}
|
|
23632
23742
|
var SKILLS_DIR = findSkillsDir();
|
|
23633
23743
|
function getSkillPath(name) {
|
|
@@ -23635,13 +23745,13 @@ function getSkillPath(name) {
|
|
|
23635
23745
|
const portable = findPortableSkill(skillName);
|
|
23636
23746
|
if (portable)
|
|
23637
23747
|
return portable.path;
|
|
23638
|
-
const legacyCustomPath =
|
|
23639
|
-
if (
|
|
23748
|
+
const legacyCustomPath = join11(getDataDir(), "custom", skillName);
|
|
23749
|
+
if (existsSync10(legacyCustomPath))
|
|
23640
23750
|
return legacyCustomPath;
|
|
23641
23751
|
const extensionPath = findExtensionSkillPath(skillName);
|
|
23642
23752
|
if (extensionPath)
|
|
23643
23753
|
return extensionPath;
|
|
23644
|
-
return
|
|
23754
|
+
return join11(SKILLS_DIR, skillName);
|
|
23645
23755
|
}
|
|
23646
23756
|
function getCanonicalSkillName(name) {
|
|
23647
23757
|
return getSkill(name)?.name ?? resolveSkillAlias(normalizeSkillSlug(name));
|
|
@@ -23650,7 +23760,7 @@ function installSkill(name, options = {}) {
|
|
|
23650
23760
|
const { targetDir = process.cwd(), overwrite = false } = options;
|
|
23651
23761
|
const canonicalName = getCanonicalSkillName(name);
|
|
23652
23762
|
const skillName = normalizeSkillName(canonicalName);
|
|
23653
|
-
if (!
|
|
23763
|
+
if (!existsSync10(getSkillPath(name))) {
|
|
23654
23764
|
const knownOfficial = Boolean(getSkill(name));
|
|
23655
23765
|
return {
|
|
23656
23766
|
skill: canonicalName,
|
|
@@ -23705,11 +23815,11 @@ function getAgentSkillsDir(agent, scope = "global", projectDir) {
|
|
|
23705
23815
|
const base = projectDir || process.cwd();
|
|
23706
23816
|
switch (agent) {
|
|
23707
23817
|
case "pi":
|
|
23708
|
-
return scope === "project" ?
|
|
23818
|
+
return scope === "project" ? join11(base, ".pi", "skills") : join11(homedir4(), ".pi", "agent", "skills");
|
|
23709
23819
|
case "opencode":
|
|
23710
|
-
return scope === "project" ?
|
|
23820
|
+
return scope === "project" ? join11(base, ".opencode", "skills") : join11(homedir4(), ".config", "opencode", "skills");
|
|
23711
23821
|
default:
|
|
23712
|
-
return scope === "project" ?
|
|
23822
|
+
return scope === "project" ? join11(base, `.${agent}`, "skills") : join11(homedir4(), `.${agent}`, "skills");
|
|
23713
23823
|
}
|
|
23714
23824
|
}
|
|
23715
23825
|
function warnMissingDependencies(name, targetDir) {
|
|
@@ -23724,8 +23834,8 @@ function warnMissingDependencies(name, targetDir) {
|
|
|
23724
23834
|
}
|
|
23725
23835
|
}
|
|
23726
23836
|
function readBundledSkillVersion(name) {
|
|
23727
|
-
const pkgPath =
|
|
23728
|
-
if (!
|
|
23837
|
+
const pkgPath = join11(getSkillPath(name), "package.json");
|
|
23838
|
+
if (!existsSync10(pkgPath))
|
|
23729
23839
|
return "unknown";
|
|
23730
23840
|
try {
|
|
23731
23841
|
const pkg = JSON.parse(readFileSync8(pkgPath, "utf-8"));
|
|
@@ -23736,13 +23846,13 @@ function readBundledSkillVersion(name) {
|
|
|
23736
23846
|
}
|
|
23737
23847
|
|
|
23738
23848
|
// src/lib/skillinfo.ts
|
|
23739
|
-
import { existsSync as
|
|
23740
|
-
import { join as
|
|
23849
|
+
import { existsSync as existsSync11, readFileSync as readFileSync9 } from "fs";
|
|
23850
|
+
import { join as join12 } from "path";
|
|
23741
23851
|
function isInstructionSkillDir(skillPath, meta) {
|
|
23742
23852
|
if (meta?.kind === "instruction")
|
|
23743
23853
|
return true;
|
|
23744
|
-
const skillMdPath =
|
|
23745
|
-
if (!
|
|
23854
|
+
const skillMdPath = join12(skillPath, "SKILL.md");
|
|
23855
|
+
if (!existsSync11(skillMdPath))
|
|
23746
23856
|
return false;
|
|
23747
23857
|
try {
|
|
23748
23858
|
return parseSkillFrontmatter(readFileSync9(skillMdPath, "utf-8"))?.kind === "instruction";
|
|
@@ -23768,12 +23878,12 @@ var HOSTED_PROVIDER_ENV_PREFIXES = [
|
|
|
23768
23878
|
];
|
|
23769
23879
|
function getSkillDocs(name) {
|
|
23770
23880
|
const skillPath = getSkillPath(name);
|
|
23771
|
-
if (!
|
|
23881
|
+
if (!existsSync11(skillPath))
|
|
23772
23882
|
return null;
|
|
23773
23883
|
return {
|
|
23774
|
-
skillMd: readIfExists(
|
|
23775
|
-
readme: readIfExists(
|
|
23776
|
-
claudeMd: readIfExists(
|
|
23884
|
+
skillMd: readIfExists(join12(skillPath, "SKILL.md")),
|
|
23885
|
+
readme: readIfExists(join12(skillPath, "README.md")),
|
|
23886
|
+
claudeMd: readIfExists(join12(skillPath, "CLAUDE.md"))
|
|
23777
23887
|
};
|
|
23778
23888
|
}
|
|
23779
23889
|
function getSkillBestDoc(name) {
|
|
@@ -23784,11 +23894,11 @@ function getSkillBestDoc(name) {
|
|
|
23784
23894
|
}
|
|
23785
23895
|
function getSkillRequirements(name) {
|
|
23786
23896
|
const skillPath = getSkillPath(name);
|
|
23787
|
-
if (!
|
|
23897
|
+
if (!existsSync11(skillPath))
|
|
23788
23898
|
return null;
|
|
23789
23899
|
const texts = [];
|
|
23790
23900
|
for (const file of ["SKILL.md", "README.md", "CLAUDE.md", ".env.example", ".env.local.example"]) {
|
|
23791
|
-
const content = readIfExists(
|
|
23901
|
+
const content = readIfExists(join12(skillPath, file));
|
|
23792
23902
|
if (content)
|
|
23793
23903
|
texts.push(content);
|
|
23794
23904
|
}
|
|
@@ -23827,8 +23937,8 @@ function getSkillRequirements(name) {
|
|
|
23827
23937
|
const skillName = normalizeSkillName(name);
|
|
23828
23938
|
let cliCommand = `skills run ${skillName}`;
|
|
23829
23939
|
let dependencies = {};
|
|
23830
|
-
const pkgPath =
|
|
23831
|
-
if (
|
|
23940
|
+
const pkgPath = join12(skillPath, "package.json");
|
|
23941
|
+
if (existsSync11(pkgPath)) {
|
|
23832
23942
|
try {
|
|
23833
23943
|
const pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
|
|
23834
23944
|
dependencies = pkg.dependencies || {};
|
|
@@ -23848,7 +23958,7 @@ async function runSkill(name, args, options = {}) {
|
|
|
23848
23958
|
const meta = getSkill(name);
|
|
23849
23959
|
const canonicalName = meta?.name ?? name;
|
|
23850
23960
|
const skillPath = getSkillPath(canonicalName);
|
|
23851
|
-
if (!
|
|
23961
|
+
if (!existsSync11(skillPath)) {
|
|
23852
23962
|
return { exitCode: 1, error: `Skill '${name}' not found` };
|
|
23853
23963
|
}
|
|
23854
23964
|
if (isInstructionSkillDir(skillPath, meta)) {
|
|
@@ -23857,8 +23967,8 @@ async function runSkill(name, args, options = {}) {
|
|
|
23857
23967
|
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'.`
|
|
23858
23968
|
};
|
|
23859
23969
|
}
|
|
23860
|
-
const pkgPath =
|
|
23861
|
-
if (!
|
|
23970
|
+
const pkgPath = join12(skillPath, "package.json");
|
|
23971
|
+
if (!existsSync11(pkgPath)) {
|
|
23862
23972
|
return { exitCode: 1, error: `No package.json in skill '${name}'` };
|
|
23863
23973
|
}
|
|
23864
23974
|
let entryPoint;
|
|
@@ -23877,12 +23987,12 @@ async function runSkill(name, args, options = {}) {
|
|
|
23877
23987
|
} catch {
|
|
23878
23988
|
return { exitCode: 1, error: `Failed to parse package.json for skill '${name}'` };
|
|
23879
23989
|
}
|
|
23880
|
-
const entryPath =
|
|
23881
|
-
if (!
|
|
23990
|
+
const entryPath = join12(skillPath, entryPoint);
|
|
23991
|
+
if (!existsSync11(entryPath)) {
|
|
23882
23992
|
return { exitCode: 1, error: `Entry point '${entryPoint}' not found in skill '${name}'` };
|
|
23883
23993
|
}
|
|
23884
|
-
const nodeModules =
|
|
23885
|
-
if (!
|
|
23994
|
+
const nodeModules = join12(skillPath, "node_modules");
|
|
23995
|
+
if (!existsSync11(nodeModules)) {
|
|
23886
23996
|
const install = Bun.spawn(["bun", "install", "--no-save"], {
|
|
23887
23997
|
cwd: skillPath,
|
|
23888
23998
|
stdout: "pipe",
|
|
@@ -23909,8 +24019,8 @@ async function runSkill(name, args, options = {}) {
|
|
|
23909
24019
|
return { exitCode };
|
|
23910
24020
|
}
|
|
23911
24021
|
function detectProjectSkills(cwd = process.cwd()) {
|
|
23912
|
-
const pkgPath =
|
|
23913
|
-
if (!
|
|
24022
|
+
const pkgPath = join12(cwd, "package.json");
|
|
24023
|
+
if (!existsSync11(pkgPath)) {
|
|
23914
24024
|
const alwaysRecommend = ["market-research-report", "repo-onboarding-report", "blog-article"];
|
|
23915
24025
|
const recommended2 = alwaysRecommend.map((name) => loadRegistry().find((s) => s.name === name)).filter((s) => s !== undefined);
|
|
23916
24026
|
return { detected: [], recommended: recommended2 };
|
|
@@ -24006,7 +24116,7 @@ function extractEnvVars(text) {
|
|
|
24006
24116
|
}
|
|
24007
24117
|
function readIfExists(path) {
|
|
24008
24118
|
try {
|
|
24009
|
-
if (
|
|
24119
|
+
if (existsSync11(path)) {
|
|
24010
24120
|
return readFileSync9(path, "utf-8");
|
|
24011
24121
|
}
|
|
24012
24122
|
} catch {}
|
|
@@ -25589,25 +25699,25 @@ function registerDiscoveryTools(server) {
|
|
|
25589
25699
|
}
|
|
25590
25700
|
|
|
25591
25701
|
// src/mcp/operation-tools.ts
|
|
25592
|
-
import { existsSync as
|
|
25593
|
-
import { join as
|
|
25702
|
+
import { existsSync as existsSync14, readdirSync as readdirSync8, statSync as statSync8 } from "fs";
|
|
25703
|
+
import { join as join15 } from "path";
|
|
25594
25704
|
|
|
25595
25705
|
// src/lib/run-state.ts
|
|
25596
25706
|
import { createHash as createHash2, randomBytes } from "crypto";
|
|
25597
|
-
import { existsSync as
|
|
25598
|
-
import { extname, join as
|
|
25707
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync5, readFileSync as readFileSync10, readdirSync as readdirSync7, statSync as statSync7, writeFileSync as writeFileSync5 } from "fs";
|
|
25708
|
+
import { extname, join as join13, relative as relative2 } from "path";
|
|
25599
25709
|
function createSkillRun(params, targetDir = process.cwd()) {
|
|
25600
25710
|
const now = new Date;
|
|
25601
25711
|
const id = createRunId(now);
|
|
25602
25712
|
const day = now.toISOString().slice(0, 10);
|
|
25603
25713
|
const skillName = normalizeSkillName(params.skill);
|
|
25604
25714
|
const root = getProjectStateDir(targetDir);
|
|
25605
|
-
const runDir =
|
|
25606
|
-
const logsDir =
|
|
25607
|
-
const exportDir =
|
|
25715
|
+
const runDir = join13(root, "runs", day, id);
|
|
25716
|
+
const logsDir = join13(runDir, "logs");
|
|
25717
|
+
const exportDir = join13(root, "exports", skillName, id);
|
|
25608
25718
|
mkdirSync5(logsDir, { recursive: true });
|
|
25609
25719
|
mkdirSync5(exportDir, { recursive: true });
|
|
25610
|
-
mkdirSync5(
|
|
25720
|
+
mkdirSync5(join13(root, "tmp"), { recursive: true });
|
|
25611
25721
|
const record3 = {
|
|
25612
25722
|
id,
|
|
25613
25723
|
skill: skillName,
|
|
@@ -25658,22 +25768,22 @@ function updateSkillRun(context, patch) {
|
|
|
25658
25768
|
return context.record;
|
|
25659
25769
|
}
|
|
25660
25770
|
function writeRunLogs(context, stdout = "", stderr = "") {
|
|
25661
|
-
writeFileSync5(
|
|
25662
|
-
writeFileSync5(
|
|
25771
|
+
writeFileSync5(join13(context.logsDir, "stdout.log"), stdout);
|
|
25772
|
+
writeFileSync5(join13(context.logsDir, "stderr.log"), stderr);
|
|
25663
25773
|
}
|
|
25664
25774
|
function appendRunEvent(context, event, data = {}) {
|
|
25665
25775
|
const line = JSON.stringify({ ts: new Date().toISOString(), event, ...data }) + `
|
|
25666
25776
|
`;
|
|
25667
|
-
const path =
|
|
25668
|
-
const previous =
|
|
25777
|
+
const path = join13(context.runDir, "events.ndjson");
|
|
25778
|
+
const previous = existsSync12(path) ? readFileSync10(path, "utf-8") : "";
|
|
25669
25779
|
writeFileSync5(path, previous + line);
|
|
25670
25780
|
}
|
|
25671
25781
|
function findSkillRun(runId, targetDir = process.cwd()) {
|
|
25672
|
-
const runsRoot =
|
|
25673
|
-
if (!
|
|
25782
|
+
const runsRoot = join13(getProjectStateDir(targetDir), "runs");
|
|
25783
|
+
if (!existsSync12(runsRoot))
|
|
25674
25784
|
return null;
|
|
25675
25785
|
for (const day of readdirSync7(runsRoot)) {
|
|
25676
|
-
const record3 = readRunRecord(
|
|
25786
|
+
const record3 = readRunRecord(join13(runsRoot, day, runId));
|
|
25677
25787
|
if (record3)
|
|
25678
25788
|
return record3;
|
|
25679
25789
|
}
|
|
@@ -25690,15 +25800,15 @@ function skillRunEnv(context) {
|
|
|
25690
25800
|
};
|
|
25691
25801
|
}
|
|
25692
25802
|
function writeRunRecord(context) {
|
|
25693
|
-
writeFileSync5(
|
|
25803
|
+
writeFileSync5(join13(context.runDir, "run.json"), JSON.stringify(context.record, null, 2) + `
|
|
25694
25804
|
`);
|
|
25695
25805
|
}
|
|
25696
25806
|
function writeArtifactsManifest(context, artifacts) {
|
|
25697
|
-
writeFileSync5(
|
|
25807
|
+
writeFileSync5(join13(context.runDir, "artifacts.json"), JSON.stringify({ runId: context.record.id, artifacts }, null, 2) + `
|
|
25698
25808
|
`);
|
|
25699
25809
|
}
|
|
25700
25810
|
function collectRunArtifacts(context) {
|
|
25701
|
-
if (!
|
|
25811
|
+
if (!existsSync12(context.exportDir))
|
|
25702
25812
|
return [];
|
|
25703
25813
|
const artifacts = [];
|
|
25704
25814
|
for (const path of walkFiles(context.exportDir)) {
|
|
@@ -25714,8 +25824,8 @@ function collectRunArtifacts(context) {
|
|
|
25714
25824
|
return artifacts.sort((a, b) => a.path.localeCompare(b.path));
|
|
25715
25825
|
}
|
|
25716
25826
|
function readRunRecord(runDir) {
|
|
25717
|
-
const path =
|
|
25718
|
-
if (!
|
|
25827
|
+
const path = join13(runDir, "run.json");
|
|
25828
|
+
if (!existsSync12(path))
|
|
25719
25829
|
return null;
|
|
25720
25830
|
try {
|
|
25721
25831
|
return JSON.parse(readFileSync10(path, "utf-8"));
|
|
@@ -25726,7 +25836,7 @@ function readRunRecord(runDir) {
|
|
|
25726
25836
|
function walkFiles(dir) {
|
|
25727
25837
|
const files = [];
|
|
25728
25838
|
for (const entry of readdirSync7(dir)) {
|
|
25729
|
-
const full =
|
|
25839
|
+
const full = join13(dir, entry);
|
|
25730
25840
|
if (statSync7(full).isDirectory())
|
|
25731
25841
|
files.push(...walkFiles(full));
|
|
25732
25842
|
else
|
|
@@ -26197,12 +26307,12 @@ function registerOperationTools(server) {
|
|
|
26197
26307
|
const agents = [];
|
|
26198
26308
|
for (const agent of AGENT_TARGETS) {
|
|
26199
26309
|
const agentSkillsPath = getAgentSkillsDir(agent, "global");
|
|
26200
|
-
const exists =
|
|
26310
|
+
const exists = existsSync14(agentSkillsPath);
|
|
26201
26311
|
let skillCount = 0;
|
|
26202
26312
|
if (exists) {
|
|
26203
26313
|
try {
|
|
26204
26314
|
skillCount = readdirSync8(agentSkillsPath).filter((f) => {
|
|
26205
|
-
const full =
|
|
26315
|
+
const full = join15(agentSkillsPath, f);
|
|
26206
26316
|
return !f.startsWith(".") && statSync8(full).isDirectory();
|
|
26207
26317
|
}).length;
|
|
26208
26318
|
} catch {}
|
|
@@ -26249,16 +26359,16 @@ function compactRunToolPayload(payload, detailHint) {
|
|
|
26249
26359
|
|
|
26250
26360
|
// src/lib/feedback.ts
|
|
26251
26361
|
init_config();
|
|
26252
|
-
import { existsSync as
|
|
26253
|
-
import { dirname as dirname6, join as
|
|
26362
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync7 } from "fs";
|
|
26363
|
+
import { dirname as dirname6, join as join16 } from "path";
|
|
26254
26364
|
import { Database } from "bun:sqlite";
|
|
26255
26365
|
function getFeedbackDbPath() {
|
|
26256
|
-
return
|
|
26366
|
+
return join16(getDataDir(), "skills.db");
|
|
26257
26367
|
}
|
|
26258
26368
|
function getFeedbackDb() {
|
|
26259
26369
|
const dbPath = getFeedbackDbPath();
|
|
26260
26370
|
const dir = dirname6(dbPath);
|
|
26261
|
-
if (!
|
|
26371
|
+
if (!existsSync15(dir))
|
|
26262
26372
|
mkdirSync7(dir, { recursive: true });
|
|
26263
26373
|
const db = new Database(dbPath);
|
|
26264
26374
|
db.exec("PRAGMA journal_mode = WAL");
|
|
@@ -26417,14 +26527,14 @@ function registerResourceMetaTools(server) {
|
|
|
26417
26527
|
}
|
|
26418
26528
|
|
|
26419
26529
|
// src/lib/scheduler.ts
|
|
26420
|
-
import { existsSync as
|
|
26421
|
-
import { join as
|
|
26530
|
+
import { existsSync as existsSync16, readFileSync as readFileSync12, writeFileSync as writeFileSync7, mkdirSync as mkdirSync8 } from "fs";
|
|
26531
|
+
import { join as join17 } from "path";
|
|
26422
26532
|
function getSchedulesPath(targetDir = process.cwd()) {
|
|
26423
|
-
return
|
|
26533
|
+
return join17(targetDir, ".skills", "schedules.json");
|
|
26424
26534
|
}
|
|
26425
26535
|
function loadSchedules(targetDir = process.cwd()) {
|
|
26426
26536
|
const path = getSchedulesPath(targetDir);
|
|
26427
|
-
if (
|
|
26537
|
+
if (existsSync16(path)) {
|
|
26428
26538
|
try {
|
|
26429
26539
|
return JSON.parse(readFileSync12(path, "utf-8"));
|
|
26430
26540
|
} catch {}
|
|
@@ -26433,8 +26543,8 @@ function loadSchedules(targetDir = process.cwd()) {
|
|
|
26433
26543
|
}
|
|
26434
26544
|
function saveSchedules(data, targetDir = process.cwd()) {
|
|
26435
26545
|
const path = getSchedulesPath(targetDir);
|
|
26436
|
-
const dir =
|
|
26437
|
-
if (!
|
|
26546
|
+
const dir = join17(targetDir, ".skills");
|
|
26547
|
+
if (!existsSync16(dir))
|
|
26438
26548
|
mkdirSync8(dir, { recursive: true });
|
|
26439
26549
|
writeFileSync7(path, JSON.stringify(data, null, 2));
|
|
26440
26550
|
}
|
|
@@ -26697,14 +26807,14 @@ function registerScheduleTools(server) {
|
|
|
26697
26807
|
init_config();
|
|
26698
26808
|
import { createHash as createHash3, createHmac } from "crypto";
|
|
26699
26809
|
import {
|
|
26700
|
-
existsSync as
|
|
26810
|
+
existsSync as existsSync17,
|
|
26701
26811
|
mkdirSync as mkdirSync9,
|
|
26702
26812
|
readFileSync as readFileSync13,
|
|
26703
26813
|
readdirSync as readdirSync9,
|
|
26704
26814
|
statSync as statSync9,
|
|
26705
26815
|
writeFileSync as writeFileSync8
|
|
26706
26816
|
} from "fs";
|
|
26707
|
-
import { dirname as dirname7, join as
|
|
26817
|
+
import { dirname as dirname7, join as join18, normalize as normalize3, relative as relative3, sep as sep2 } from "path";
|
|
26708
26818
|
init_retired_settings();
|
|
26709
26819
|
var SKILLS_STORAGE_TABLES = [
|
|
26710
26820
|
"skills_sync_records",
|
|
@@ -26781,7 +26891,7 @@ function getSkillsNativeStorageStatus(options = {}) {
|
|
|
26781
26891
|
local: {
|
|
26782
26892
|
dataDir: getDataDir(),
|
|
26783
26893
|
projectStateDir: getProjectStateDir(targetDir),
|
|
26784
|
-
feedbackDbPath:
|
|
26894
|
+
feedbackDbPath: join18(getDataDir(), "skills.db")
|
|
26785
26895
|
},
|
|
26786
26896
|
remote: {
|
|
26787
26897
|
databaseConfigured: Boolean(config2.databaseUrl),
|
|
@@ -26801,7 +26911,7 @@ function getStorageStatus(options = {}) {
|
|
|
26801
26911
|
function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
|
|
26802
26912
|
const projectStateDir = getProjectStateDir(targetDir);
|
|
26803
26913
|
const files = [];
|
|
26804
|
-
if (
|
|
26914
|
+
if (existsSync17(projectStateDir)) {
|
|
26805
26915
|
for (const filePath of walkFiles2(projectStateDir)) {
|
|
26806
26916
|
const bytes = readFileSync13(filePath);
|
|
26807
26917
|
const relativePath = toPosix(relative3(targetDir, filePath));
|
|
@@ -26885,7 +26995,7 @@ function parsePositiveInteger(value) {
|
|
|
26885
26995
|
function walkFiles2(dir) {
|
|
26886
26996
|
const files = [];
|
|
26887
26997
|
for (const entry of readdirSync9(dir)) {
|
|
26888
|
-
const full =
|
|
26998
|
+
const full = join18(dir, entry);
|
|
26889
26999
|
const stats = statSync9(full);
|
|
26890
27000
|
if (stats.isDirectory())
|
|
26891
27001
|
files.push(...walkFiles2(full));
|
|
@@ -27433,7 +27543,7 @@ var responseViaResponseObject = async (res, outgoing, options = {}) => {
|
|
|
27433
27543
|
});
|
|
27434
27544
|
if (!chunk) {
|
|
27435
27545
|
if (i === 1) {
|
|
27436
|
-
await new Promise((
|
|
27546
|
+
await new Promise((resolve2) => setTimeout(resolve2));
|
|
27437
27547
|
maxReadCount = 3;
|
|
27438
27548
|
continue;
|
|
27439
27549
|
}
|
|
@@ -27990,9 +28100,9 @@ data:
|
|
|
27990
28100
|
const initRequest = messages.find((m) => isInitializeRequest(m));
|
|
27991
28101
|
const clientProtocolVersion = initRequest ? initRequest.params.protocolVersion : req.headers.get("mcp-protocol-version") ?? DEFAULT_NEGOTIATED_PROTOCOL_VERSION;
|
|
27992
28102
|
if (this._enableJsonResponse) {
|
|
27993
|
-
return new Promise((
|
|
28103
|
+
return new Promise((resolve2) => {
|
|
27994
28104
|
this._streamMapping.set(streamId, {
|
|
27995
|
-
resolveJson:
|
|
28105
|
+
resolveJson: resolve2,
|
|
27996
28106
|
cleanup: () => {
|
|
27997
28107
|
this._streamMapping.delete(streamId);
|
|
27998
28108
|
}
|
|
@@ -28340,19 +28450,19 @@ async function connectMcpForNode() {
|
|
|
28340
28450
|
return { server: server2, transport };
|
|
28341
28451
|
}
|
|
28342
28452
|
function readBody(req) {
|
|
28343
|
-
return new Promise((
|
|
28453
|
+
return new Promise((resolve2, reject) => {
|
|
28344
28454
|
const chunks = [];
|
|
28345
28455
|
req.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
|
|
28346
28456
|
req.on("end", () => {
|
|
28347
28457
|
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
28348
28458
|
if (!raw.trim()) {
|
|
28349
|
-
|
|
28459
|
+
resolve2(undefined);
|
|
28350
28460
|
return;
|
|
28351
28461
|
}
|
|
28352
28462
|
try {
|
|
28353
|
-
|
|
28463
|
+
resolve2(JSON.parse(raw));
|
|
28354
28464
|
} catch {
|
|
28355
|
-
|
|
28465
|
+
resolve2(undefined);
|
|
28356
28466
|
}
|
|
28357
28467
|
});
|
|
28358
28468
|
req.on("error", reject);
|
|
@@ -28394,9 +28504,9 @@ async function startSkillsMcpHttpServer(options = {}) {
|
|
|
28394
28504
|
}
|
|
28395
28505
|
}
|
|
28396
28506
|
});
|
|
28397
|
-
await new Promise((
|
|
28507
|
+
await new Promise((resolve2, reject) => {
|
|
28398
28508
|
httpServer.once("error", reject);
|
|
28399
|
-
httpServer.listen(port, hostname2, () =>
|
|
28509
|
+
httpServer.listen(port, hostname2, () => resolve2());
|
|
28400
28510
|
});
|
|
28401
28511
|
const address = httpServer.address();
|
|
28402
28512
|
const listenPort = typeof address === "object" && address ? address.port : port;
|