@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/index.js
CHANGED
|
@@ -36860,7 +36860,7 @@ var package_default;
|
|
|
36860
36860
|
var init_package = __esm(() => {
|
|
36861
36861
|
package_default = {
|
|
36862
36862
|
name: "@hasna/skills",
|
|
36863
|
-
version: "0.1.
|
|
36863
|
+
version: "0.1.72",
|
|
36864
36864
|
description: "Skills library for AI coding agents",
|
|
36865
36865
|
type: "module",
|
|
36866
36866
|
bin: {
|
|
@@ -36952,6 +36952,7 @@ var init_package = __esm(() => {
|
|
|
36952
36952
|
"@aws-sdk/client-ecs": "^3.1079.0",
|
|
36953
36953
|
"@aws-sdk/client-s3": "^3.1079.0",
|
|
36954
36954
|
"@hasna/events": "0.1.16",
|
|
36955
|
+
"@hasna/paths": "0.1.0",
|
|
36955
36956
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
36956
36957
|
chalk: "^5.3.0",
|
|
36957
36958
|
commander: "^12.1.0",
|
|
@@ -37917,10 +37918,127 @@ var init_retired_settings = __esm(() => {
|
|
|
37917
37918
|
};
|
|
37918
37919
|
});
|
|
37919
37920
|
|
|
37920
|
-
//
|
|
37921
|
-
import { existsSync as existsSync3, readFileSync as readFileSync2, writeFileSync, mkdirSync, copyFileSync, readdirSync, statSync } from "fs";
|
|
37922
|
-
import { join as join3, dirname } from "path";
|
|
37921
|
+
// ../../node_modules/.bun/@hasna+paths@0.1.0/node_modules/@hasna/paths/dist/index.js
|
|
37923
37922
|
import { homedir as homedir2 } from "os";
|
|
37923
|
+
import { join as join3 } from "path";
|
|
37924
|
+
function assertApp(app) {
|
|
37925
|
+
if (typeof app !== "string" || app.length === 0) {
|
|
37926
|
+
throw new TypeError("paths: app must be a non-empty string");
|
|
37927
|
+
}
|
|
37928
|
+
if (!APP_SLUG_RE.test(app)) {
|
|
37929
|
+
throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
|
|
37930
|
+
}
|
|
37931
|
+
}
|
|
37932
|
+
function envOf(options) {
|
|
37933
|
+
return options.env ?? process.env;
|
|
37934
|
+
}
|
|
37935
|
+
function envValue(options, kind) {
|
|
37936
|
+
const value = envOf(options)[KIND_ENV[kind]];
|
|
37937
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
37938
|
+
}
|
|
37939
|
+
function isMacOS(platform2) {
|
|
37940
|
+
return platform2 === "darwin";
|
|
37941
|
+
}
|
|
37942
|
+
function baseDir(kind, options) {
|
|
37943
|
+
const override = envValue(options, kind);
|
|
37944
|
+
if (override)
|
|
37945
|
+
return override;
|
|
37946
|
+
const home = options.home ?? homedir2();
|
|
37947
|
+
const platform2 = options.platform ?? process.platform;
|
|
37948
|
+
if (isMacOS(platform2)) {
|
|
37949
|
+
switch (kind) {
|
|
37950
|
+
case "config":
|
|
37951
|
+
case "data":
|
|
37952
|
+
return join3(home, "Library", "Application Support", "Hasna");
|
|
37953
|
+
case "cache":
|
|
37954
|
+
return join3(home, "Library", "Caches", "Hasna");
|
|
37955
|
+
case "state":
|
|
37956
|
+
return join3(home, "Library", "Logs", "Hasna");
|
|
37957
|
+
}
|
|
37958
|
+
}
|
|
37959
|
+
switch (kind) {
|
|
37960
|
+
case "config":
|
|
37961
|
+
return join3(home, ".config", "hasna");
|
|
37962
|
+
case "data":
|
|
37963
|
+
return join3(home, ".local", "share", "hasna");
|
|
37964
|
+
case "state":
|
|
37965
|
+
return join3(home, ".local", "state", "hasna");
|
|
37966
|
+
case "cache":
|
|
37967
|
+
return join3(home, ".cache", "hasna");
|
|
37968
|
+
}
|
|
37969
|
+
}
|
|
37970
|
+
function resolvePath(kind, options) {
|
|
37971
|
+
assertApp(options.app);
|
|
37972
|
+
const appSegment = options.internal === true ? join3("internal", options.app) : options.app;
|
|
37973
|
+
return join3(baseDir(kind, options), appSegment);
|
|
37974
|
+
}
|
|
37975
|
+
function dataDir(options) {
|
|
37976
|
+
return resolvePath("data", options);
|
|
37977
|
+
}
|
|
37978
|
+
var KIND_ENV, APP_SLUG_RE;
|
|
37979
|
+
var init_dist = __esm(() => {
|
|
37980
|
+
KIND_ENV = {
|
|
37981
|
+
config: "HASNA_CONFIG_HOME",
|
|
37982
|
+
data: "HASNA_DATA_HOME",
|
|
37983
|
+
state: "HASNA_STATE_HOME",
|
|
37984
|
+
cache: "HASNA_CACHE_HOME"
|
|
37985
|
+
};
|
|
37986
|
+
APP_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
37987
|
+
});
|
|
37988
|
+
|
|
37989
|
+
// src/lib/app-home.ts
|
|
37990
|
+
import { existsSync as existsSync3 } from "fs";
|
|
37991
|
+
import { homedir as homedir3 } from "os";
|
|
37992
|
+
import { join as join4, resolve } from "path";
|
|
37993
|
+
function effectiveHome() {
|
|
37994
|
+
return process.env["HOME"] || process.env["USERPROFILE"] || homedir3() || "/tmp";
|
|
37995
|
+
}
|
|
37996
|
+
function legacyDataRoot() {
|
|
37997
|
+
return join4(effectiveHome(), ".hasna", "skills");
|
|
37998
|
+
}
|
|
37999
|
+
function resolverDataRoot(home = effectiveHome()) {
|
|
38000
|
+
return dataDir({ app: "skills", home });
|
|
38001
|
+
}
|
|
38002
|
+
function adoptResolverDataRoot(resolved, env3 = process.env) {
|
|
38003
|
+
const dataOverride = env3.HASNA_DATA_HOME;
|
|
38004
|
+
if (typeof dataOverride === "string" && dataOverride.trim().length > 0)
|
|
38005
|
+
return true;
|
|
38006
|
+
return existsSync3(join4(resolved, DEFAULT_SQLITE_FILENAME)) || existsSync3(join4(resolved, GLOBAL_CONFIG_FILENAME));
|
|
38007
|
+
}
|
|
38008
|
+
function exactDataRoot() {
|
|
38009
|
+
for (const key of [DATA_DIR_ENV, HASNA_SKILLS_HOME_ENV, SKILLS_HOME_ENV]) {
|
|
38010
|
+
const dir = process.env[key]?.trim();
|
|
38011
|
+
if (dir)
|
|
38012
|
+
return resolve(dir);
|
|
38013
|
+
}
|
|
38014
|
+
return;
|
|
38015
|
+
}
|
|
38016
|
+
function hasExactOverride(env3 = process.env) {
|
|
38017
|
+
return Boolean(env3[DATA_DIR_ENV]?.trim()) || Boolean(env3[HASNA_SKILLS_HOME_ENV]?.trim()) || Boolean(env3[SKILLS_HOME_ENV]?.trim());
|
|
38018
|
+
}
|
|
38019
|
+
function hasOperatorOverride(env3 = process.env) {
|
|
38020
|
+
return hasExactOverride(env3) || Boolean(env3.HASNA_DATA_HOME?.trim());
|
|
38021
|
+
}
|
|
38022
|
+
function getDataRoot() {
|
|
38023
|
+
const exact = exactDataRoot();
|
|
38024
|
+
if (exact)
|
|
38025
|
+
return exact;
|
|
38026
|
+
const resolved = resolverDataRoot();
|
|
38027
|
+
return adoptResolverDataRoot(resolved) ? resolve(resolved) : resolve(legacyDataRoot());
|
|
38028
|
+
}
|
|
38029
|
+
function skillsDataRootForHome(home) {
|
|
38030
|
+
const resolved = resolverDataRoot(home);
|
|
38031
|
+
return adoptResolverDataRoot(resolved) ? resolve(resolved) : resolve(join4(home, ".hasna", "skills"));
|
|
38032
|
+
}
|
|
38033
|
+
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";
|
|
38034
|
+
var init_app_home = __esm(() => {
|
|
38035
|
+
init_dist();
|
|
38036
|
+
});
|
|
38037
|
+
|
|
38038
|
+
// src/lib/config.ts
|
|
38039
|
+
import { existsSync as existsSync4, readFileSync as readFileSync2, writeFileSync, mkdirSync, copyFileSync, readdirSync, statSync } from "fs";
|
|
38040
|
+
import { join as join5, dirname } from "path";
|
|
38041
|
+
import { homedir as homedir4 } from "os";
|
|
37924
38042
|
function validKeys() {
|
|
37925
38043
|
return [...Object.keys(ENUM_KEYS), ...STRING_KEYS];
|
|
37926
38044
|
}
|
|
@@ -37928,19 +38046,19 @@ function allowedValues(key) {
|
|
|
37928
38046
|
return ENUM_KEYS[key];
|
|
37929
38047
|
}
|
|
37930
38048
|
function mergeDirectoryContents(sourceDir, targetDir) {
|
|
37931
|
-
if (!
|
|
38049
|
+
if (!existsSync4(sourceDir))
|
|
37932
38050
|
return;
|
|
37933
38051
|
mkdirSync(targetDir, { recursive: true });
|
|
37934
38052
|
for (const entry of readdirSync(sourceDir)) {
|
|
37935
|
-
const sourcePath =
|
|
37936
|
-
const targetPath =
|
|
38053
|
+
const sourcePath = join5(sourceDir, entry);
|
|
38054
|
+
const targetPath = join5(targetDir, entry);
|
|
37937
38055
|
try {
|
|
37938
38056
|
const sourceStat = statSync(sourcePath);
|
|
37939
38057
|
if (sourceStat.isDirectory()) {
|
|
37940
38058
|
mergeDirectoryContents(sourcePath, targetPath);
|
|
37941
38059
|
continue;
|
|
37942
38060
|
}
|
|
37943
|
-
if (!
|
|
38061
|
+
if (!existsSync4(targetPath))
|
|
37944
38062
|
copyFileSync(sourcePath, targetPath);
|
|
37945
38063
|
} catch {}
|
|
37946
38064
|
}
|
|
@@ -37966,48 +38084,42 @@ function normalizeConfigValue(key, value) {
|
|
|
37966
38084
|
return;
|
|
37967
38085
|
}
|
|
37968
38086
|
function isOwnerLayoutMigrated(appDir) {
|
|
37969
|
-
return
|
|
38087
|
+
return existsSync4(join5(appDir, SKILLS_CACHE_DIRNAME, LAYOUT_MIGRATION_RECORD));
|
|
37970
38088
|
}
|
|
37971
38089
|
function getDataDir() {
|
|
37972
|
-
const
|
|
37973
|
-
|
|
37974
|
-
|
|
37975
|
-
|
|
37976
|
-
|
|
37977
|
-
return
|
|
37978
|
-
|
|
37979
|
-
const
|
|
37980
|
-
const
|
|
37981
|
-
const oldDir = join3(home, ".skills");
|
|
37982
|
-
const oldConfigFile = join3(home, ".skillsrc");
|
|
37983
|
-
mkdirSync(newDir, { recursive: true });
|
|
38090
|
+
const root = getDataRoot();
|
|
38091
|
+
try {
|
|
38092
|
+
mkdirSync(root, { recursive: true });
|
|
38093
|
+
} catch {}
|
|
38094
|
+
if (hasOperatorOverride())
|
|
38095
|
+
return root;
|
|
38096
|
+
const home = effectiveHome();
|
|
38097
|
+
const oldDir = join5(home, ".skills");
|
|
38098
|
+
const oldConfigFile = join5(home, ".skillsrc");
|
|
37984
38099
|
try {
|
|
37985
|
-
mergeDirectoryContents(oldDir,
|
|
38100
|
+
mergeDirectoryContents(oldDir, root);
|
|
37986
38101
|
} catch {}
|
|
37987
|
-
if (
|
|
38102
|
+
if (existsSync4(oldConfigFile) && !existsSync4(join5(root, "config.json"))) {
|
|
37988
38103
|
try {
|
|
37989
|
-
copyFileSync(oldConfigFile,
|
|
38104
|
+
copyFileSync(oldConfigFile, join5(root, "config.json"));
|
|
37990
38105
|
} catch {}
|
|
37991
38106
|
}
|
|
37992
|
-
return
|
|
38107
|
+
return root;
|
|
37993
38108
|
}
|
|
37994
38109
|
function getDataDirReadOnly() {
|
|
37995
|
-
|
|
37996
|
-
if (override)
|
|
37997
|
-
return override;
|
|
37998
|
-
return join3(process.env["HOME"] || process.env["USERPROFILE"] || homedir2(), ".hasna", "skills");
|
|
38110
|
+
return getDataRoot();
|
|
37999
38111
|
}
|
|
38000
38112
|
function getConfigPathReadOnly(scope) {
|
|
38001
38113
|
if (scope === "global")
|
|
38002
|
-
return
|
|
38003
|
-
return
|
|
38114
|
+
return join5(getDataDirReadOnly(), "config.json");
|
|
38115
|
+
return join5(process.cwd(), "skills.config.json");
|
|
38004
38116
|
}
|
|
38005
38117
|
function loadConfigReadOnly() {
|
|
38006
38118
|
const canonicalConfigPath = getConfigPathReadOnly("global");
|
|
38007
38119
|
let globalConfig;
|
|
38008
|
-
if (
|
|
38120
|
+
if (existsSync4(canonicalConfigPath)) {
|
|
38009
38121
|
globalConfig = readConfigFile(canonicalConfigPath);
|
|
38010
|
-
} else if (
|
|
38122
|
+
} else if (hasOperatorOverride()) {
|
|
38011
38123
|
globalConfig = {};
|
|
38012
38124
|
} else {
|
|
38013
38125
|
globalConfig = readConfigFile(legacyConfigFilePath());
|
|
@@ -38016,16 +38128,16 @@ function loadConfigReadOnly() {
|
|
|
38016
38128
|
return { ...globalConfig, ...projectConfig };
|
|
38017
38129
|
}
|
|
38018
38130
|
function legacyConfigFilePath() {
|
|
38019
|
-
return
|
|
38131
|
+
return join5(process.env["HOME"] || process.env["USERPROFILE"] || homedir4(), ".skillsrc");
|
|
38020
38132
|
}
|
|
38021
38133
|
function getConfigPath(scope) {
|
|
38022
38134
|
if (scope === "global") {
|
|
38023
|
-
return
|
|
38135
|
+
return join5(getDataDir(), "config.json");
|
|
38024
38136
|
}
|
|
38025
|
-
return
|
|
38137
|
+
return join5(process.cwd(), "skills.config.json");
|
|
38026
38138
|
}
|
|
38027
38139
|
function readConfigFile(path) {
|
|
38028
|
-
if (!
|
|
38140
|
+
if (!existsSync4(path))
|
|
38029
38141
|
return {};
|
|
38030
38142
|
let parsed;
|
|
38031
38143
|
try {
|
|
@@ -38061,7 +38173,7 @@ function saveConfig(key, value, scope = "project") {
|
|
|
38061
38173
|
}
|
|
38062
38174
|
const filePath = getConfigPath(scope);
|
|
38063
38175
|
let existing = {};
|
|
38064
|
-
if (
|
|
38176
|
+
if (existsSync4(filePath)) {
|
|
38065
38177
|
try {
|
|
38066
38178
|
existing = JSON.parse(readFileSync2(filePath, "utf-8"));
|
|
38067
38179
|
if (typeof existing !== "object" || existing === null || Array.isArray(existing)) {
|
|
@@ -38072,7 +38184,7 @@ function saveConfig(key, value, scope = "project") {
|
|
|
38072
38184
|
}
|
|
38073
38185
|
} else {
|
|
38074
38186
|
const dir = dirname(filePath);
|
|
38075
|
-
if (!
|
|
38187
|
+
if (!existsSync4(dir)) {
|
|
38076
38188
|
mkdirSync(dir, { recursive: true });
|
|
38077
38189
|
}
|
|
38078
38190
|
}
|
|
@@ -38086,7 +38198,7 @@ function unsetConfig(key, scope = "project") {
|
|
|
38086
38198
|
throw new Error(`Unknown config key: ${key}. Valid keys: ${validKeys().join(", ")}`);
|
|
38087
38199
|
}
|
|
38088
38200
|
const filePath = getConfigPath(scope);
|
|
38089
|
-
if (!
|
|
38201
|
+
if (!existsSync4(filePath))
|
|
38090
38202
|
return false;
|
|
38091
38203
|
let existing;
|
|
38092
38204
|
try {
|
|
@@ -38104,9 +38216,11 @@ function unsetConfig(key, scope = "project") {
|
|
|
38104
38216
|
`);
|
|
38105
38217
|
return true;
|
|
38106
38218
|
}
|
|
38107
|
-
var ENUM_KEYS, STRING_KEYS,
|
|
38219
|
+
var ENUM_KEYS, STRING_KEYS, INSTALLED_SKILLS_DIRNAME = "installed", SKILLS_CACHE_DIRNAME = "skills", LAYOUT_MIGRATION_RECORD = ".layout-migration.json";
|
|
38108
38220
|
var init_config = __esm(() => {
|
|
38109
38221
|
init_retired_settings();
|
|
38222
|
+
init_app_home();
|
|
38223
|
+
init_app_home();
|
|
38110
38224
|
ENUM_KEYS = {
|
|
38111
38225
|
defaultAgent: ["claude", "codex", "gemini", "pi", "opencode", "all"],
|
|
38112
38226
|
defaultScope: ["global", "project"],
|
|
@@ -38904,8 +39018,8 @@ var init_registry_data = __esm(() => {
|
|
|
38904
39018
|
});
|
|
38905
39019
|
|
|
38906
39020
|
// src/lib/hosted-skill-set.ts
|
|
38907
|
-
import { existsSync as
|
|
38908
|
-
import { join as
|
|
39021
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
39022
|
+
import { join as join6 } from "path";
|
|
38909
39023
|
function normalizeMarker(value) {
|
|
38910
39024
|
return typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
38911
39025
|
}
|
|
@@ -38916,8 +39030,8 @@ function isHostedMetadataPackage(pkg) {
|
|
|
38916
39030
|
return HOSTED_RUNTIMES.has(normalizeMarker(skills.runtime)) || HOSTED_SOURCES.has(normalizeMarker(skills.source));
|
|
38917
39031
|
}
|
|
38918
39032
|
function isHostedMetadataSkillDir(skillDir) {
|
|
38919
|
-
const pkgPath =
|
|
38920
|
-
if (!
|
|
39033
|
+
const pkgPath = join6(skillDir, "package.json");
|
|
39034
|
+
if (!existsSync5(pkgPath))
|
|
38921
39035
|
return false;
|
|
38922
39036
|
try {
|
|
38923
39037
|
return isHostedMetadataPackage(JSON.parse(readFileSync3(pkgPath, "utf8")));
|
|
@@ -38945,8 +39059,8 @@ var init_hosted_skill_set = __esm(() => {
|
|
|
38945
39059
|
});
|
|
38946
39060
|
|
|
38947
39061
|
// src/lib/skill-validation.ts
|
|
38948
|
-
import { existsSync as
|
|
38949
|
-
import { isAbsolute, join as
|
|
39062
|
+
import { existsSync as existsSync6, lstatSync, readFileSync as readFileSync4, readdirSync as readdirSync3, statSync as statSync3 } from "fs";
|
|
39063
|
+
import { isAbsolute, join as join7, normalize } from "path";
|
|
38950
39064
|
function add2(target, code, message) {
|
|
38951
39065
|
target.push({ code, message });
|
|
38952
39066
|
}
|
|
@@ -39035,7 +39149,7 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
39035
39149
|
binCommands: [],
|
|
39036
39150
|
docFiles: []
|
|
39037
39151
|
};
|
|
39038
|
-
if (!
|
|
39152
|
+
if (!existsSync6(skillPath)) {
|
|
39039
39153
|
add2(issues, "skill.dir_missing", `Skill directory not found: ${skillPath}`);
|
|
39040
39154
|
return {
|
|
39041
39155
|
name: bareName,
|
|
@@ -39050,7 +39164,7 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
39050
39164
|
add2(issues, "skill.name_invalid", `Skill name '${bareName}' must use lowercase letters, numbers, dots, underscores, or hyphens`);
|
|
39051
39165
|
}
|
|
39052
39166
|
for (const entry of readdirSync3(skillPath).sort()) {
|
|
39053
|
-
const entryPath =
|
|
39167
|
+
const entryPath = join7(skillPath, entry);
|
|
39054
39168
|
if (RESERVED_SKILL_ENTRIES.has(entry)) {
|
|
39055
39169
|
add2(issues, "skill.reserved_file", `Reserved file '${entry}' is not allowed in skill packages`);
|
|
39056
39170
|
}
|
|
@@ -39062,14 +39176,14 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
39062
39176
|
}
|
|
39063
39177
|
}
|
|
39064
39178
|
for (const docFile of DOC_FILES) {
|
|
39065
|
-
if (
|
|
39179
|
+
if (existsSync6(join7(skillPath, docFile)))
|
|
39066
39180
|
metadata.docFiles.push(docFile);
|
|
39067
39181
|
}
|
|
39068
39182
|
if (metadata.docFiles.length === 0) {
|
|
39069
39183
|
add2(issues, "skill.docs_missing", "Missing documentation file: expected SKILL.md, README.md, or CLAUDE.md");
|
|
39070
39184
|
}
|
|
39071
|
-
const skillMdPath =
|
|
39072
|
-
if (
|
|
39185
|
+
const skillMdPath = join7(skillPath, "SKILL.md");
|
|
39186
|
+
if (existsSync6(skillMdPath)) {
|
|
39073
39187
|
const frontmatter = parseSkillFrontmatter(readFileSync4(skillMdPath, "utf-8"));
|
|
39074
39188
|
if (!frontmatter) {
|
|
39075
39189
|
add2(warnings, "skill.frontmatter_missing", "SKILL.md has no YAML frontmatter");
|
|
@@ -39112,8 +39226,8 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
39112
39226
|
}
|
|
39113
39227
|
metadata.kind = resolvedKind;
|
|
39114
39228
|
const isInstruction = resolvedKind === "instruction";
|
|
39115
|
-
const pkgPath =
|
|
39116
|
-
if (!
|
|
39229
|
+
const pkgPath = join7(skillPath, "package.json");
|
|
39230
|
+
if (!existsSync6(pkgPath)) {
|
|
39117
39231
|
if (!isInstruction)
|
|
39118
39232
|
add2(issues, "package.missing", "Missing package.json");
|
|
39119
39233
|
} else {
|
|
@@ -39171,8 +39285,8 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
39171
39285
|
add2(issues, "package.bin_target_unsafe", `package.json bin '${command}' target '${target}' must stay inside the skill directory`);
|
|
39172
39286
|
continue;
|
|
39173
39287
|
}
|
|
39174
|
-
const targetPath =
|
|
39175
|
-
if (!
|
|
39288
|
+
const targetPath = join7(skillPath, target);
|
|
39289
|
+
if (!existsSync6(targetPath)) {
|
|
39176
39290
|
add2(warnings, "package.bin_target_missing", `package.json bin '${command}' target '${target}' is not present before build`);
|
|
39177
39291
|
} else if (statSync3(targetPath).isDirectory()) {
|
|
39178
39292
|
add2(issues, "package.bin_target_directory", `package.json bin '${command}' target '${target}' must point to a file, not a directory`);
|
|
@@ -39189,17 +39303,17 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
39189
39303
|
metadata.runtime = "none";
|
|
39190
39304
|
} else {
|
|
39191
39305
|
metadata.runtime = hostedMetadata ? "hosted" : "local";
|
|
39192
|
-
const srcDir =
|
|
39306
|
+
const srcDir = join7(skillPath, "src");
|
|
39193
39307
|
if (hostedMetadata) {
|
|
39194
|
-
if (
|
|
39308
|
+
if (existsSync6(srcDir)) {
|
|
39195
39309
|
add2(issues, "skill.hosted_source_forbidden", "Hosted metadata skills must not include local implementation source");
|
|
39196
39310
|
}
|
|
39197
|
-
} else if (!
|
|
39311
|
+
} else if (!existsSync6(srcDir)) {
|
|
39198
39312
|
add2(issues, "skill.src_missing", "Missing src/ directory");
|
|
39199
|
-
} else if (!
|
|
39313
|
+
} else if (!existsSync6(join7(srcDir, "index.ts")) && !existsSync6(join7(srcDir, "index.js"))) {
|
|
39200
39314
|
add2(issues, "skill.src_index_missing", "Missing src/index.ts or src/index.js");
|
|
39201
39315
|
} else {
|
|
39202
|
-
const indexPath =
|
|
39316
|
+
const indexPath = existsSync6(join7(srcDir, "index.ts")) ? join7(srcDir, "index.ts") : join7(srcDir, "index.js");
|
|
39203
39317
|
const size2 = statSync3(indexPath).size;
|
|
39204
39318
|
if (size2 < 50)
|
|
39205
39319
|
add2(warnings, "skill.src_index_minimal", `Source entry point is very small (${size2}B)`);
|
|
@@ -39270,8 +39384,8 @@ var init_skill_validation = __esm(() => {
|
|
|
39270
39384
|
|
|
39271
39385
|
// src/lib/skill-hash.ts
|
|
39272
39386
|
import { createHash } from "crypto";
|
|
39273
|
-
import { existsSync as
|
|
39274
|
-
import { join as
|
|
39387
|
+
import { existsSync as existsSync7, readdirSync as readdirSync4, readFileSync as readFileSync5, statSync as statSync4 } from "fs";
|
|
39388
|
+
import { join as join8, sep } from "path";
|
|
39275
39389
|
function normalizeLineEndings(content) {
|
|
39276
39390
|
return content.replace(/\r\n/g, `
|
|
39277
39391
|
`).replace(/\r/g, `
|
|
@@ -39317,8 +39431,8 @@ function collectBundleFiles(skillPath) {
|
|
|
39317
39431
|
if (seen.has(entry))
|
|
39318
39432
|
continue;
|
|
39319
39433
|
seen.add(entry);
|
|
39320
|
-
const absolute =
|
|
39321
|
-
if (!
|
|
39434
|
+
const absolute = join8(skillPath, entry);
|
|
39435
|
+
if (!existsSync7(absolute))
|
|
39322
39436
|
continue;
|
|
39323
39437
|
if (statSync4(absolute).isDirectory())
|
|
39324
39438
|
collectDirectory(files, absolute, entry);
|
|
@@ -39331,7 +39445,7 @@ function collectDirectory(files, dir, rel) {
|
|
|
39331
39445
|
for (const entry of readdirSync4(dir).sort()) {
|
|
39332
39446
|
if (entry.startsWith("."))
|
|
39333
39447
|
continue;
|
|
39334
|
-
const absolute =
|
|
39448
|
+
const absolute = join8(dir, entry);
|
|
39335
39449
|
const childRel = `${rel}/${entry}`;
|
|
39336
39450
|
let stats;
|
|
39337
39451
|
try {
|
|
@@ -39586,14 +39700,14 @@ var init_skill_contract = __esm(() => {
|
|
|
39586
39700
|
// src/lib/portable-skills-files.ts
|
|
39587
39701
|
import {
|
|
39588
39702
|
cpSync,
|
|
39589
|
-
existsSync as
|
|
39703
|
+
existsSync as existsSync8,
|
|
39590
39704
|
lstatSync as lstatSync2,
|
|
39591
39705
|
mkdirSync as mkdirSync2,
|
|
39592
39706
|
readFileSync as readFileSync6,
|
|
39593
39707
|
realpathSync,
|
|
39594
39708
|
writeFileSync as writeFileSync2
|
|
39595
39709
|
} from "fs";
|
|
39596
|
-
import { basename, dirname as dirname2, join as
|
|
39710
|
+
import { basename, dirname as dirname2, join as join9, relative } from "path";
|
|
39597
39711
|
function defaultRuntimeContract(entrypoint = "src/index.ts") {
|
|
39598
39712
|
return {
|
|
39599
39713
|
runtime: "bun",
|
|
@@ -39617,12 +39731,12 @@ function normalizePortableSkillName(name) {
|
|
|
39617
39731
|
return normalized;
|
|
39618
39732
|
}
|
|
39619
39733
|
function readPortableSkillManifest(skillPath, fallbackName = basename(skillPath)) {
|
|
39620
|
-
const skillJsonPath =
|
|
39621
|
-
const skillMdPath =
|
|
39622
|
-
const pkgPath =
|
|
39623
|
-
const jsonManifest =
|
|
39624
|
-
const frontmatter =
|
|
39625
|
-
const pkg =
|
|
39734
|
+
const skillJsonPath = join9(skillPath, "skill.json");
|
|
39735
|
+
const skillMdPath = join9(skillPath, "SKILL.md");
|
|
39736
|
+
const pkgPath = join9(skillPath, "package.json");
|
|
39737
|
+
const jsonManifest = existsSync8(skillJsonPath) ? readJsonObject(skillJsonPath) : undefined;
|
|
39738
|
+
const frontmatter = existsSync8(skillMdPath) ? parseSkillFrontmatter(readFileSync6(skillMdPath, "utf-8")) ?? undefined : undefined;
|
|
39739
|
+
const pkg = existsSync8(pkgPath) ? readJsonObject(pkgPath) : undefined;
|
|
39626
39740
|
const name = normalizePortableSkillName(stringField(jsonManifest, "name") ?? frontmatter?.name ?? stringValue(pkg?.name) ?? fallbackName);
|
|
39627
39741
|
const description = stringField(jsonManifest, "description") ?? frontmatter?.description ?? stringValue(pkg?.description) ?? `${name} skill`;
|
|
39628
39742
|
const version = stringField(jsonManifest, "version") ?? frontmatter?.version ?? stringValue(pkg?.version) ?? PORTABLE_SKILL_DEFAULT_VERSION;
|
|
@@ -39668,7 +39782,7 @@ function createInstructionManifest(name, options) {
|
|
|
39668
39782
|
}
|
|
39669
39783
|
function writeInstructionSkillTemplate(skillPath, manifest) {
|
|
39670
39784
|
mkdirSync2(skillPath, { recursive: true });
|
|
39671
|
-
writeFileSync2(
|
|
39785
|
+
writeFileSync2(join9(skillPath, "SKILL.md"), renderInstructionSkillMd(manifest));
|
|
39672
39786
|
writeSkillJsonWithHash(skillPath, manifest);
|
|
39673
39787
|
}
|
|
39674
39788
|
function renderInstructionSkillMd(manifest) {
|
|
@@ -39717,12 +39831,12 @@ function createPortableManifest(name, options) {
|
|
|
39717
39831
|
};
|
|
39718
39832
|
}
|
|
39719
39833
|
function writePortableSkillTemplate(skillPath, manifest) {
|
|
39720
|
-
mkdirSync2(
|
|
39721
|
-
writeFileSync2(
|
|
39722
|
-
writeFileSync2(
|
|
39723
|
-
writeFileSync2(
|
|
39724
|
-
writeFileSync2(
|
|
39725
|
-
writeFileSync2(
|
|
39834
|
+
mkdirSync2(join9(skillPath, "src"), { recursive: true });
|
|
39835
|
+
writeFileSync2(join9(skillPath, "SKILL.md"), renderSkillMd(manifest));
|
|
39836
|
+
writeFileSync2(join9(skillPath, "AGENTS.md"), renderAgentsMd(manifest));
|
|
39837
|
+
writeFileSync2(join9(skillPath, "package.json"), renderPackageJson(manifest));
|
|
39838
|
+
writeFileSync2(join9(skillPath, "tsconfig.json"), renderTsconfig());
|
|
39839
|
+
writeFileSync2(join9(skillPath, "src", "index.ts"), renderEntrypoint(manifest));
|
|
39726
39840
|
writeSkillJsonWithHash(skillPath, manifest);
|
|
39727
39841
|
}
|
|
39728
39842
|
function fillContractDefaults(manifest, entrypoint) {
|
|
@@ -39747,7 +39861,7 @@ function writeSkillJsonWithHash(skillPath, manifest) {
|
|
|
39747
39861
|
content_hash: undefined
|
|
39748
39862
|
}
|
|
39749
39863
|
};
|
|
39750
|
-
writeFileSync2(
|
|
39864
|
+
writeFileSync2(join9(skillPath, "skill.json"), `${JSON.stringify({ ...existing, ...renderSkillJsonObject(withoutHash) }, null, 2)}
|
|
39751
39865
|
`);
|
|
39752
39866
|
const hash = computeContentHash(skillPath);
|
|
39753
39867
|
const withHash = {
|
|
@@ -39757,13 +39871,13 @@ function writeSkillJsonWithHash(skillPath, manifest) {
|
|
|
39757
39871
|
content_hash: hash
|
|
39758
39872
|
}
|
|
39759
39873
|
};
|
|
39760
|
-
writeFileSync2(
|
|
39874
|
+
writeFileSync2(join9(skillPath, "skill.json"), `${JSON.stringify({ ...existing, ...renderSkillJsonObject(withHash) }, null, 2)}
|
|
39761
39875
|
`);
|
|
39762
39876
|
return withHash;
|
|
39763
39877
|
}
|
|
39764
39878
|
function readExistingSkillJson(skillPath) {
|
|
39765
|
-
const path =
|
|
39766
|
-
if (!
|
|
39879
|
+
const path = join9(skillPath, "skill.json");
|
|
39880
|
+
if (!existsSync8(path))
|
|
39767
39881
|
return {};
|
|
39768
39882
|
try {
|
|
39769
39883
|
const parsed = JSON.parse(readFileSync6(path, "utf-8"));
|
|
@@ -39796,28 +39910,28 @@ function ensurePortableSkillFiles(skillPath, manifest) {
|
|
|
39796
39910
|
tags: next.tags?.length ? next.tags : ["custom", next.name]
|
|
39797
39911
|
};
|
|
39798
39912
|
const entry = next.commands[0]?.entry ?? "src/index.ts";
|
|
39799
|
-
if (entry && !
|
|
39800
|
-
mkdirSync2(dirname2(
|
|
39801
|
-
writeFileSync2(
|
|
39913
|
+
if (entry && !existsSync8(join9(skillPath, entry))) {
|
|
39914
|
+
mkdirSync2(dirname2(join9(skillPath, entry)), { recursive: true });
|
|
39915
|
+
writeFileSync2(join9(skillPath, entry), renderEntrypoint(next));
|
|
39802
39916
|
}
|
|
39803
|
-
if (!
|
|
39804
|
-
writeFileSync2(
|
|
39917
|
+
if (!existsSync8(join9(skillPath, "SKILL.md")))
|
|
39918
|
+
writeFileSync2(join9(skillPath, "SKILL.md"), renderSkillMd(next));
|
|
39805
39919
|
else
|
|
39806
|
-
writeFileSync2(
|
|
39807
|
-
if (!
|
|
39808
|
-
writeFileSync2(
|
|
39920
|
+
writeFileSync2(join9(skillPath, "SKILL.md"), ensureSkillMdFrontmatter(readFileSync6(join9(skillPath, "SKILL.md"), "utf-8"), next));
|
|
39921
|
+
if (!existsSync8(join9(skillPath, "AGENTS.md")))
|
|
39922
|
+
writeFileSync2(join9(skillPath, "AGENTS.md"), renderAgentsMd(next));
|
|
39809
39923
|
ensurePackageJson(skillPath, next);
|
|
39810
|
-
if (!
|
|
39811
|
-
writeFileSync2(
|
|
39924
|
+
if (!existsSync8(join9(skillPath, "tsconfig.json")))
|
|
39925
|
+
writeFileSync2(join9(skillPath, "tsconfig.json"), renderTsconfig());
|
|
39812
39926
|
writeSkillJsonWithHash(skillPath, next);
|
|
39813
39927
|
return readPortableSkillManifest(skillPath, next.name);
|
|
39814
39928
|
}
|
|
39815
39929
|
function ensurePackageJson(skillPath, manifest) {
|
|
39816
|
-
const pkgPath =
|
|
39930
|
+
const pkgPath = join9(skillPath, "package.json");
|
|
39817
39931
|
const first = manifest.commands[0] ?? { name: manifest.name, entry: "src/index.ts" };
|
|
39818
39932
|
const commandName = normalizePortableSkillName(first.name || manifest.name);
|
|
39819
39933
|
const entry = (first.entry ?? "src/index.ts").replace(/^\.\//, "");
|
|
39820
|
-
if (!
|
|
39934
|
+
if (!existsSync8(pkgPath)) {
|
|
39821
39935
|
writeFileSync2(pkgPath, renderPackageJson(manifest));
|
|
39822
39936
|
return;
|
|
39823
39937
|
}
|
|
@@ -39860,8 +39974,8 @@ function ensureInstructionSkillFiles(skillPath, manifest) {
|
|
|
39860
39974
|
inputs: [],
|
|
39861
39975
|
commands: []
|
|
39862
39976
|
};
|
|
39863
|
-
if (!
|
|
39864
|
-
writeFileSync2(
|
|
39977
|
+
if (!existsSync8(join9(skillPath, "SKILL.md"))) {
|
|
39978
|
+
writeFileSync2(join9(skillPath, "SKILL.md"), renderSkillMd(next));
|
|
39865
39979
|
}
|
|
39866
39980
|
writeSkillJsonWithHash(skillPath, next);
|
|
39867
39981
|
return readPortableSkillManifest(skillPath, next.name);
|
|
@@ -40168,7 +40282,7 @@ var init_portable_skills_files = __esm(() => {
|
|
|
40168
40282
|
// src/lib/portable-skills.ts
|
|
40169
40283
|
import {
|
|
40170
40284
|
cpSync as cpSync2,
|
|
40171
|
-
existsSync as
|
|
40285
|
+
existsSync as existsSync9,
|
|
40172
40286
|
mkdirSync as mkdirSync3,
|
|
40173
40287
|
mkdtempSync,
|
|
40174
40288
|
readdirSync as readdirSync5,
|
|
@@ -40177,22 +40291,22 @@ import {
|
|
|
40177
40291
|
statSync as statSync6,
|
|
40178
40292
|
writeFileSync as writeFileSync3
|
|
40179
40293
|
} from "fs";
|
|
40180
|
-
import { basename as basename2, dirname as dirname3, isAbsolute as isAbsolute2, join as
|
|
40294
|
+
import { basename as basename2, dirname as dirname3, isAbsolute as isAbsolute2, join as join10, normalize as normalize2 } from "path";
|
|
40181
40295
|
function getPortableSkillsRoot(options = {}) {
|
|
40182
40296
|
if (options.rootDir)
|
|
40183
40297
|
return options.rootDir;
|
|
40184
|
-
const appDir = options.homeDir ?
|
|
40185
|
-
const cache3 =
|
|
40298
|
+
const appDir = options.homeDir ? join10(options.homeDir, ".hasna", "skills") : getDataDir();
|
|
40299
|
+
const cache3 = join10(appDir, SKILLS_CACHE_DIRNAME);
|
|
40186
40300
|
if (isOwnerLayoutMigrated(appDir) && safeIsDirectory(cache3))
|
|
40187
40301
|
return cache3;
|
|
40188
|
-
const installed =
|
|
40302
|
+
const installed = join10(appDir, INSTALLED_SKILLS_DIRNAME);
|
|
40189
40303
|
migrateLegacySkillLayout(appDir, installed);
|
|
40190
40304
|
return installed;
|
|
40191
40305
|
}
|
|
40192
40306
|
function looksLikeSkillDirectory(path) {
|
|
40193
40307
|
if (!safeIsDirectory(path))
|
|
40194
40308
|
return false;
|
|
40195
|
-
return
|
|
40309
|
+
return existsSync9(join10(path, "SKILL.md")) || existsSync9(join10(path, "skill.json")) || existsSync9(join10(path, "package.json"));
|
|
40196
40310
|
}
|
|
40197
40311
|
function migrateLegacySkillLayout(appDir, installed) {
|
|
40198
40312
|
if (!safeIsDirectory(appDir))
|
|
@@ -40202,7 +40316,7 @@ function migrateLegacySkillLayout(appDir, installed) {
|
|
|
40202
40316
|
for (const entry of readdirSync5(appDir)) {
|
|
40203
40317
|
if (entry.startsWith(".") || entry === INSTALLED_SKILLS_DIRNAME)
|
|
40204
40318
|
continue;
|
|
40205
|
-
const path =
|
|
40319
|
+
const path = join10(appDir, entry);
|
|
40206
40320
|
if (entry === LEGACY_CUSTOM_DIRNAME) {
|
|
40207
40321
|
if (!safeIsDirectory(path))
|
|
40208
40322
|
continue;
|
|
@@ -40210,7 +40324,7 @@ function migrateLegacySkillLayout(appDir, installed) {
|
|
|
40210
40324
|
for (const nested of readdirSync5(path)) {
|
|
40211
40325
|
if (nested.startsWith("."))
|
|
40212
40326
|
continue;
|
|
40213
|
-
const nestedPath =
|
|
40327
|
+
const nestedPath = join10(path, nested);
|
|
40214
40328
|
if (looksLikeSkillDirectory(nestedPath))
|
|
40215
40329
|
candidates.push({ from: nestedPath, name: nested });
|
|
40216
40330
|
}
|
|
@@ -40224,10 +40338,10 @@ function migrateLegacySkillLayout(appDir, installed) {
|
|
|
40224
40338
|
return;
|
|
40225
40339
|
}
|
|
40226
40340
|
for (const { from, name } of candidates) {
|
|
40227
|
-
const target =
|
|
40228
|
-
if (
|
|
40341
|
+
const target = join10(installed, name);
|
|
40342
|
+
if (existsSync9(target))
|
|
40229
40343
|
continue;
|
|
40230
|
-
const staging =
|
|
40344
|
+
const staging = join10(installed, `.migrating-${name}-${process.pid}`);
|
|
40231
40345
|
try {
|
|
40232
40346
|
rmSync(staging, { recursive: true, force: true });
|
|
40233
40347
|
cpSync2(from, staging, { recursive: true, errorOnExist: false });
|
|
@@ -40240,7 +40354,7 @@ function migrateLegacySkillLayout(appDir, installed) {
|
|
|
40240
40354
|
}
|
|
40241
40355
|
}
|
|
40242
40356
|
function getPortableSkillPath(name, options = {}) {
|
|
40243
|
-
return
|
|
40357
|
+
return join10(getPortableSkillsRoot(options), normalizePortableSkillName(name));
|
|
40244
40358
|
}
|
|
40245
40359
|
function findPortableSkill(name, options = {}) {
|
|
40246
40360
|
let normalized;
|
|
@@ -40250,7 +40364,7 @@ function findPortableSkill(name, options = {}) {
|
|
|
40250
40364
|
return null;
|
|
40251
40365
|
}
|
|
40252
40366
|
const path = getPortableSkillPath(normalized, options);
|
|
40253
|
-
if (!
|
|
40367
|
+
if (!existsSync9(path) || !statSync6(path).isDirectory())
|
|
40254
40368
|
return null;
|
|
40255
40369
|
try {
|
|
40256
40370
|
return summarizePortableSkill(path, normalized);
|
|
@@ -40266,7 +40380,7 @@ function listPortableSkills(options = {}) {
|
|
|
40266
40380
|
for (const entry of readdirSync5(root).sort()) {
|
|
40267
40381
|
if (entry.startsWith("."))
|
|
40268
40382
|
continue;
|
|
40269
|
-
const path =
|
|
40383
|
+
const path = join10(root, entry);
|
|
40270
40384
|
if (!safeIsDirectory(path))
|
|
40271
40385
|
continue;
|
|
40272
40386
|
try {
|
|
@@ -40299,8 +40413,8 @@ function isOfficialSkillName(name) {
|
|
|
40299
40413
|
function scaffoldPortableSkill(name, options = {}) {
|
|
40300
40414
|
const skillName = normalizePortableSkillName(name);
|
|
40301
40415
|
const root = getPortableSkillsRoot(options);
|
|
40302
|
-
const skillPath =
|
|
40303
|
-
if (
|
|
40416
|
+
const skillPath = join10(root, skillName);
|
|
40417
|
+
if (existsSync9(skillPath)) {
|
|
40304
40418
|
if (!options.overwrite)
|
|
40305
40419
|
throw new Error(`Skill '${skillName}' already exists at ${skillPath}`);
|
|
40306
40420
|
rmSync(skillPath, { recursive: true, force: true });
|
|
@@ -40318,7 +40432,7 @@ function scaffoldPortableSkill(name, options = {}) {
|
|
|
40318
40432
|
}
|
|
40319
40433
|
function portPortableSkillDirectory(sourceDir, options = {}) {
|
|
40320
40434
|
const absoluteSource = normalize2(sourceDir);
|
|
40321
|
-
if (!
|
|
40435
|
+
if (!existsSync9(absoluteSource) || !statSync6(absoluteSource).isDirectory()) {
|
|
40322
40436
|
throw new Error(`Import directory not found: ${sourceDir}`);
|
|
40323
40437
|
}
|
|
40324
40438
|
const continueOnError = options.continueOnError ?? true;
|
|
@@ -40331,7 +40445,7 @@ function portPortableSkillDirectory(sourceDir, options = {}) {
|
|
|
40331
40445
|
const skipped = [];
|
|
40332
40446
|
const entries = readdirSync5(absoluteSource, { withFileTypes: true }).map((entry) => entry.name).filter((entryName) => !entryName.startsWith(".")).sort();
|
|
40333
40447
|
for (const entryName of entries) {
|
|
40334
|
-
const childPath =
|
|
40448
|
+
const childPath = join10(absoluteSource, entryName);
|
|
40335
40449
|
if (!safeIsDirectory(childPath))
|
|
40336
40450
|
continue;
|
|
40337
40451
|
if (!isSkillCandidate(childPath)) {
|
|
@@ -40360,11 +40474,11 @@ function portPortableSkillDirectory(sourceDir, options = {}) {
|
|
|
40360
40474
|
};
|
|
40361
40475
|
}
|
|
40362
40476
|
function isSkillCandidate(dir) {
|
|
40363
|
-
return
|
|
40477
|
+
return existsSync9(join10(dir, "SKILL.md")) || existsSync9(join10(dir, "skill.json")) || existsSync9(join10(dir, "package.json"));
|
|
40364
40478
|
}
|
|
40365
40479
|
function portPortableSkill(sourcePath, options = {}) {
|
|
40366
40480
|
const absoluteSource = normalize2(sourcePath);
|
|
40367
|
-
if (!
|
|
40481
|
+
if (!existsSync9(absoluteSource) || !statSync6(absoluteSource).isDirectory()) {
|
|
40368
40482
|
throw new Error(`Skill source directory not found: ${sourcePath}`);
|
|
40369
40483
|
}
|
|
40370
40484
|
const inferred = readPortableSkillManifest(absoluteSource, basename2(absoluteSource));
|
|
@@ -40376,8 +40490,8 @@ function portPortableSkill(sourcePath, options = {}) {
|
|
|
40376
40490
|
throw new Error(`${via} Importing it would shadow the official '${skillName}'. ` + `Pass --name to choose a different name, or --allow-shadow to override deliberately.`);
|
|
40377
40491
|
}
|
|
40378
40492
|
const root = getPortableSkillsRoot(options);
|
|
40379
|
-
const destination =
|
|
40380
|
-
if (
|
|
40493
|
+
const destination = join10(root, skillName);
|
|
40494
|
+
if (existsSync9(destination)) {
|
|
40381
40495
|
if (!options.overwrite)
|
|
40382
40496
|
throw new Error(`Skill '${skillName}' already exists at ${destination}`);
|
|
40383
40497
|
rmSync(destination, { recursive: true, force: true });
|
|
@@ -40419,19 +40533,19 @@ function buildCorpusManifest(input, name) {
|
|
|
40419
40533
|
function installCorpusSkillAtomically(input, options = {}) {
|
|
40420
40534
|
const name = normalizePortableSkillName(input.name);
|
|
40421
40535
|
const root = getPortableSkillsRoot(options);
|
|
40422
|
-
const target =
|
|
40423
|
-
const created = !
|
|
40536
|
+
const target = join10(root, name);
|
|
40537
|
+
const created = !existsSync9(target);
|
|
40424
40538
|
mkdirSync3(root, { recursive: true });
|
|
40425
|
-
const staging = mkdtempSync(
|
|
40539
|
+
const staging = mkdtempSync(join10(root, `.pull-${name}-`));
|
|
40426
40540
|
let moved = false;
|
|
40427
40541
|
let backup = null;
|
|
40428
40542
|
try {
|
|
40429
|
-
writeFileSync3(
|
|
40543
|
+
writeFileSync3(join10(staging, "SKILL.md"), input.skillMd);
|
|
40430
40544
|
const manifest = buildCorpusManifest(input, name);
|
|
40431
40545
|
writeSkillJsonWithHash(staging, manifest);
|
|
40432
|
-
if (
|
|
40433
|
-
backup = mkdtempSync(
|
|
40434
|
-
renameSync(target,
|
|
40546
|
+
if (existsSync9(target)) {
|
|
40547
|
+
backup = mkdtempSync(join10(root, `.pull-backup-${name}-`));
|
|
40548
|
+
renameSync(target, join10(backup, name));
|
|
40435
40549
|
moved = true;
|
|
40436
40550
|
}
|
|
40437
40551
|
renameSync(staging, target);
|
|
@@ -40440,9 +40554,9 @@ function installCorpusSkillAtomically(input, options = {}) {
|
|
|
40440
40554
|
return { name, path: target, manifest, created };
|
|
40441
40555
|
} catch (error) {
|
|
40442
40556
|
rmSync(staging, { recursive: true, force: true });
|
|
40443
|
-
if (moved && backup &&
|
|
40557
|
+
if (moved && backup && existsSync9(join10(backup, name))) {
|
|
40444
40558
|
try {
|
|
40445
|
-
renameSync(
|
|
40559
|
+
renameSync(join10(backup, name), target);
|
|
40446
40560
|
} catch {}
|
|
40447
40561
|
}
|
|
40448
40562
|
throw error;
|
|
@@ -40454,10 +40568,10 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
40454
40568
|
const issues = [...base2.issues];
|
|
40455
40569
|
const warnings = [...base2.warnings];
|
|
40456
40570
|
let manifest;
|
|
40457
|
-
if (
|
|
40458
|
-
const skillJsonPath =
|
|
40459
|
-
const skillMdPath =
|
|
40460
|
-
if (!
|
|
40571
|
+
if (existsSync9(skillPath)) {
|
|
40572
|
+
const skillJsonPath = join10(skillPath, "skill.json");
|
|
40573
|
+
const skillMdPath = join10(skillPath, "SKILL.md");
|
|
40574
|
+
if (!existsSync9(skillJsonPath) && !existsSync9(skillMdPath)) {
|
|
40461
40575
|
add4(issues, "portable.manifest_missing", "Missing portable manifest: expected SKILL.md frontmatter and/or skill.json");
|
|
40462
40576
|
}
|
|
40463
40577
|
try {
|
|
@@ -40476,7 +40590,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
40476
40590
|
add4(issues, "portable.version_missing", "Portable manifest missing version");
|
|
40477
40591
|
}
|
|
40478
40592
|
const contractIssues = validatePortableManifestContract(manifest, {
|
|
40479
|
-
strict:
|
|
40593
|
+
strict: existsSync9(join10(skillPath, "skill.json")),
|
|
40480
40594
|
skillPath
|
|
40481
40595
|
});
|
|
40482
40596
|
for (const issue of contractIssues)
|
|
@@ -40512,8 +40626,8 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
40512
40626
|
add4(issues, "portable.command_entry_unsafe", `Command '${command.name}' entry '${command.entry}' must stay inside the skill directory`);
|
|
40513
40627
|
continue;
|
|
40514
40628
|
}
|
|
40515
|
-
const entryPath =
|
|
40516
|
-
if (!
|
|
40629
|
+
const entryPath = join10(skillPath, command.entry);
|
|
40630
|
+
if (!existsSync9(entryPath))
|
|
40517
40631
|
add4(issues, "portable.command_entry_missing", `Command '${command.name}' entry '${command.entry}' is missing`);
|
|
40518
40632
|
else if (statSync6(entryPath).isDirectory())
|
|
40519
40633
|
add4(issues, "portable.command_entry_directory", `Command '${command.name}' entry '${command.entry}' must be a file`);
|
|
@@ -40523,7 +40637,7 @@ function validatePortableSkillDirectory(name, skillPath) {
|
|
|
40523
40637
|
} catch (error) {
|
|
40524
40638
|
add4(issues, "portable.manifest_invalid", error.message);
|
|
40525
40639
|
}
|
|
40526
|
-
if (manifest?.kind !== "instruction" && !
|
|
40640
|
+
if (manifest?.kind !== "instruction" && !existsSync9(join10(skillPath, "AGENTS.md"))) {
|
|
40527
40641
|
add4(issues, "portable.agents_missing", "Missing AGENTS.md with build-out instructions for coding agents");
|
|
40528
40642
|
}
|
|
40529
40643
|
}
|
|
@@ -40792,8 +40906,8 @@ __export(exports_registry, {
|
|
|
40792
40906
|
CATEGORIES: () => CATEGORIES,
|
|
40793
40907
|
BASIC_SKILL_NAMES: () => BASIC_SKILL_NAMES
|
|
40794
40908
|
});
|
|
40795
|
-
import { existsSync as
|
|
40796
|
-
import { join as
|
|
40909
|
+
import { existsSync as existsSync10, readFileSync as readFileSync7, readdirSync as readdirSync6 } from "fs";
|
|
40910
|
+
import { join as join11 } from "path";
|
|
40797
40911
|
function isBasicSkillName(name) {
|
|
40798
40912
|
return BASIC_SKILL_NAMES.includes(name);
|
|
40799
40913
|
}
|
|
@@ -40829,7 +40943,7 @@ function parseSkillMdFrontmatter(content) {
|
|
|
40829
40943
|
return Object.keys(result2).length > 0 ? result2 : null;
|
|
40830
40944
|
}
|
|
40831
40945
|
function discoverSkillsInDir(dir, source = "custom") {
|
|
40832
|
-
if (!
|
|
40946
|
+
if (!existsSync10(dir))
|
|
40833
40947
|
return [];
|
|
40834
40948
|
const result2 = [];
|
|
40835
40949
|
try {
|
|
@@ -40837,8 +40951,8 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
40837
40951
|
for (const entry of entries) {
|
|
40838
40952
|
if (!entry.isDirectory())
|
|
40839
40953
|
continue;
|
|
40840
|
-
const skillMdPath =
|
|
40841
|
-
if (!
|
|
40954
|
+
const skillMdPath = join11(dir, entry.name, "SKILL.md");
|
|
40955
|
+
if (!existsSync10(skillMdPath))
|
|
40842
40956
|
continue;
|
|
40843
40957
|
let content;
|
|
40844
40958
|
try {
|
|
@@ -40857,7 +40971,7 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
40857
40971
|
category: fm.category || "Development Tools",
|
|
40858
40972
|
tags: fm.tags || [],
|
|
40859
40973
|
...fm.kind ? { kind: fm.kind } : {},
|
|
40860
|
-
...isHostedMetadataSkillDir(
|
|
40974
|
+
...isHostedMetadataSkillDir(join11(dir, entry.name)) ? { serverOwned: true } : {},
|
|
40861
40975
|
source
|
|
40862
40976
|
});
|
|
40863
40977
|
}
|
|
@@ -40866,16 +40980,16 @@ function discoverSkillsInDir(dir, source = "custom") {
|
|
|
40866
40980
|
}
|
|
40867
40981
|
function findExtensionSkillPath(name) {
|
|
40868
40982
|
const config = loadConfig();
|
|
40869
|
-
if (!config.extensionsDir || !
|
|
40983
|
+
if (!config.extensionsDir || !existsSync10(config.extensionsDir))
|
|
40870
40984
|
return null;
|
|
40871
40985
|
try {
|
|
40872
40986
|
const entries = readdirSync6(config.extensionsDir, { withFileTypes: true });
|
|
40873
40987
|
for (const entry of entries) {
|
|
40874
40988
|
if (!entry.isDirectory())
|
|
40875
40989
|
continue;
|
|
40876
|
-
const skillDir =
|
|
40877
|
-
const skillMdPath =
|
|
40878
|
-
if (!
|
|
40990
|
+
const skillDir = join11(config.extensionsDir, entry.name);
|
|
40991
|
+
const skillMdPath = join11(skillDir, "SKILL.md");
|
|
40992
|
+
if (!existsSync10(skillMdPath))
|
|
40879
40993
|
continue;
|
|
40880
40994
|
let content;
|
|
40881
40995
|
try {
|
|
@@ -40903,12 +41017,12 @@ function loadRegistry(cwd2) {
|
|
|
40903
41017
|
if (registryCache && registryCacheKey === rootKey && now3 - registryCacheTime < REGISTRY_CACHE_TTL) {
|
|
40904
41018
|
return registryCache;
|
|
40905
41019
|
}
|
|
40906
|
-
const
|
|
41020
|
+
const dataDir2 = getDataDir();
|
|
40907
41021
|
const config = loadConfig();
|
|
40908
41022
|
const official = SKILLS.map((s) => ({ ...s, source: "official" }));
|
|
40909
41023
|
const extensions = config.extensionsDir ? discoverSkillsInDir(config.extensionsDir, "extension") : [];
|
|
40910
41024
|
const portableCustom = listPortableSkillMetas();
|
|
40911
|
-
const legacyCustom = discoverSkillsInDir(
|
|
41025
|
+
const legacyCustom = discoverSkillsInDir(join11(dataDir2, "custom"));
|
|
40912
41026
|
const globalCustom = mergeCustomSkills([...legacyCustom, ...portableCustom]);
|
|
40913
41027
|
registryCache = mergeSkillRegistryLists(official, extensions, globalCustom);
|
|
40914
41028
|
registryCacheTime = now3;
|
|
@@ -42607,16 +42721,16 @@ var require_cli_spinners = __commonJS((exports, module) => {
|
|
|
42607
42721
|
});
|
|
42608
42722
|
|
|
42609
42723
|
// src/lib/home-migration.ts
|
|
42610
|
-
import { existsSync as
|
|
42611
|
-
import { join as
|
|
42724
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync4, readdirSync as readdirSync7, renameSync as renameSync2, rmSync as rmSync2, statSync as statSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
42725
|
+
import { join as join12 } from "path";
|
|
42612
42726
|
function layoutMigrationRecordPath(appDir) {
|
|
42613
|
-
return
|
|
42727
|
+
return join12(appDir, SKILLS_CACHE_DIRNAME, LAYOUT_MIGRATION_RECORD);
|
|
42614
42728
|
}
|
|
42615
42729
|
function resolveCorpusRoot(options = {}) {
|
|
42616
42730
|
return getPortableSkillsRoot(options);
|
|
42617
42731
|
}
|
|
42618
42732
|
function migrationAppDir(homeDir) {
|
|
42619
|
-
return homeDir ?
|
|
42733
|
+
return homeDir ? join12(homeDir, ".hasna", "skills") : getDataDir();
|
|
42620
42734
|
}
|
|
42621
42735
|
function looksLikeSkillDirectory2(path) {
|
|
42622
42736
|
try {
|
|
@@ -42625,11 +42739,11 @@ function looksLikeSkillDirectory2(path) {
|
|
|
42625
42739
|
} catch {
|
|
42626
42740
|
return false;
|
|
42627
42741
|
}
|
|
42628
|
-
return
|
|
42742
|
+
return existsSync11(join12(path, "SKILL.md")) || existsSync11(join12(path, "skill.json")) || existsSync11(join12(path, "package.json"));
|
|
42629
42743
|
}
|
|
42630
42744
|
function listLegacyFlatSkillDirs(appDir) {
|
|
42631
42745
|
const legacy = [];
|
|
42632
|
-
if (!
|
|
42746
|
+
if (!existsSync11(appDir))
|
|
42633
42747
|
return legacy;
|
|
42634
42748
|
let entries = [];
|
|
42635
42749
|
try {
|
|
@@ -42643,15 +42757,15 @@ function listLegacyFlatSkillDirs(appDir) {
|
|
|
42643
42757
|
if (entry === SKILLS_CACHE_DIRNAME || entry === INSTALLED_SKILLS_DIRNAME || entry === LEGACY_CUSTOM_DIRNAME2 || entry === LOGS_DIRNAME || entry === OUTPUTS_DIRNAME) {
|
|
42644
42758
|
continue;
|
|
42645
42759
|
}
|
|
42646
|
-
if (looksLikeSkillDirectory2(
|
|
42760
|
+
if (looksLikeSkillDirectory2(join12(appDir, entry)))
|
|
42647
42761
|
legacy.push(entry);
|
|
42648
42762
|
}
|
|
42649
42763
|
return legacy;
|
|
42650
42764
|
}
|
|
42651
42765
|
function createLazyDirs(appDir, created) {
|
|
42652
42766
|
for (const name of [LOGS_DIRNAME, OUTPUTS_DIRNAME]) {
|
|
42653
|
-
const dir =
|
|
42654
|
-
if (!
|
|
42767
|
+
const dir = join12(appDir, name);
|
|
42768
|
+
if (!existsSync11(dir)) {
|
|
42655
42769
|
mkdirSync4(dir, { recursive: true });
|
|
42656
42770
|
created.push(dir);
|
|
42657
42771
|
}
|
|
@@ -42659,14 +42773,14 @@ function createLazyDirs(appDir, created) {
|
|
|
42659
42773
|
}
|
|
42660
42774
|
function migrateOwnerLayout(options = {}) {
|
|
42661
42775
|
const appDir = migrationAppDir(options.homeDir);
|
|
42662
|
-
const cache3 =
|
|
42663
|
-
const installed =
|
|
42776
|
+
const cache3 = join12(appDir, SKILLS_CACHE_DIRNAME);
|
|
42777
|
+
const installed = join12(appDir, INSTALLED_SKILLS_DIRNAME);
|
|
42664
42778
|
const moved = [];
|
|
42665
42779
|
const created = [];
|
|
42666
42780
|
if (isOwnerLayoutMigrated(appDir)) {
|
|
42667
42781
|
return { status: "already-migrated", moved, created };
|
|
42668
42782
|
}
|
|
42669
|
-
if (
|
|
42783
|
+
if (existsSync11(cache3)) {
|
|
42670
42784
|
let entries = [];
|
|
42671
42785
|
try {
|
|
42672
42786
|
entries = readdirSync7(cache3);
|
|
@@ -42680,7 +42794,7 @@ function migrateOwnerLayout(options = {}) {
|
|
|
42680
42794
|
};
|
|
42681
42795
|
}
|
|
42682
42796
|
}
|
|
42683
|
-
const installedPresent =
|
|
42797
|
+
const installedPresent = existsSync11(installed);
|
|
42684
42798
|
const legacy = listLegacyFlatSkillDirs(appDir);
|
|
42685
42799
|
const planned = [...installedPresent ? [INSTALLED_SKILLS_DIRNAME] : [], ...legacy];
|
|
42686
42800
|
if (!installedPresent && legacy.length === 0) {
|
|
@@ -42693,7 +42807,7 @@ function migrateOwnerLayout(options = {}) {
|
|
|
42693
42807
|
}
|
|
42694
42808
|
const collisionNames = new Set;
|
|
42695
42809
|
for (const dir of [cache3, ...installedPresent ? [installed] : []]) {
|
|
42696
|
-
if (!
|
|
42810
|
+
if (!existsSync11(dir))
|
|
42697
42811
|
continue;
|
|
42698
42812
|
try {
|
|
42699
42813
|
for (const entry of readdirSync7(dir))
|
|
@@ -42710,7 +42824,7 @@ function migrateOwnerLayout(options = {}) {
|
|
|
42710
42824
|
};
|
|
42711
42825
|
}
|
|
42712
42826
|
}
|
|
42713
|
-
if (
|
|
42827
|
+
if (existsSync11(cache3)) {
|
|
42714
42828
|
rmSync2(cache3, { recursive: true, force: true });
|
|
42715
42829
|
}
|
|
42716
42830
|
if (installedPresent) {
|
|
@@ -42720,7 +42834,7 @@ function migrateOwnerLayout(options = {}) {
|
|
|
42720
42834
|
mkdirSync4(cache3, { recursive: true });
|
|
42721
42835
|
}
|
|
42722
42836
|
for (const name of legacy) {
|
|
42723
|
-
renameSync2(
|
|
42837
|
+
renameSync2(join12(appDir, name), join12(cache3, name));
|
|
42724
42838
|
moved.push(name);
|
|
42725
42839
|
}
|
|
42726
42840
|
createLazyDirs(appDir, created);
|
|
@@ -42744,7 +42858,7 @@ var init_home_migration = __esm(() => {
|
|
|
42744
42858
|
// src/lib/agent-sync.ts
|
|
42745
42859
|
import {
|
|
42746
42860
|
cpSync as cpSync3,
|
|
42747
|
-
existsSync as
|
|
42861
|
+
existsSync as existsSync12,
|
|
42748
42862
|
mkdirSync as mkdirSync5,
|
|
42749
42863
|
mkdtempSync as mkdtempSync2,
|
|
42750
42864
|
readFileSync as readFileSync8,
|
|
@@ -42754,8 +42868,8 @@ import {
|
|
|
42754
42868
|
statSync as statSync8,
|
|
42755
42869
|
writeFileSync as writeFileSync5
|
|
42756
42870
|
} from "fs";
|
|
42757
|
-
import { homedir as
|
|
42758
|
-
import { basename as basename3, dirname as dirname4, join as
|
|
42871
|
+
import { homedir as homedir5 } from "os";
|
|
42872
|
+
import { basename as basename3, dirname as dirname4, join as join13 } from "path";
|
|
42759
42873
|
function isSyncAgent(value) {
|
|
42760
42874
|
return SYNC_AGENTS.includes(value);
|
|
42761
42875
|
}
|
|
@@ -42767,12 +42881,12 @@ function resolveSyncAgents(arg) {
|
|
|
42767
42881
|
}
|
|
42768
42882
|
return [arg];
|
|
42769
42883
|
}
|
|
42770
|
-
function agentGlobalSkillsDir(agent, homeDir =
|
|
42884
|
+
function agentGlobalSkillsDir(agent, homeDir = homedir5()) {
|
|
42771
42885
|
switch (agent) {
|
|
42772
42886
|
case "opencode":
|
|
42773
|
-
return
|
|
42887
|
+
return join13(homeDir, ".config", "opencode", "skills");
|
|
42774
42888
|
default:
|
|
42775
|
-
return
|
|
42889
|
+
return join13(homeDir, `.${agent}`, "skills");
|
|
42776
42890
|
}
|
|
42777
42891
|
}
|
|
42778
42892
|
function adaptSkillMdForAgent(skillMd, agent) {
|
|
@@ -42830,8 +42944,8 @@ function resolveSyncCorpus(options = {}) {
|
|
|
42830
42944
|
function packageSourceRoots(source) {
|
|
42831
42945
|
const roots = [];
|
|
42832
42946
|
for (const sub of ["skills"]) {
|
|
42833
|
-
const candidate =
|
|
42834
|
-
if (
|
|
42947
|
+
const candidate = join13(source, sub);
|
|
42948
|
+
if (existsSync12(candidate) && isDirectory(candidate))
|
|
42835
42949
|
roots.push(candidate);
|
|
42836
42950
|
}
|
|
42837
42951
|
if (roots.length > 0)
|
|
@@ -42846,10 +42960,10 @@ function containsSkillDirectories(path) {
|
|
|
42846
42960
|
return false;
|
|
42847
42961
|
}
|
|
42848
42962
|
return entries.some((entry) => {
|
|
42849
|
-
const candidate =
|
|
42963
|
+
const candidate = join13(path, entry);
|
|
42850
42964
|
if (!isDirectory(candidate))
|
|
42851
42965
|
return false;
|
|
42852
|
-
return
|
|
42966
|
+
return existsSync12(join13(candidate, "SKILL.md")) || existsSync12(join13(candidate, "skill.json")) || existsSync12(join13(candidate, "package.json"));
|
|
42853
42967
|
});
|
|
42854
42968
|
}
|
|
42855
42969
|
function isDirectory(path) {
|
|
@@ -42862,7 +42976,7 @@ function isDirectory(path) {
|
|
|
42862
42976
|
function syncSkillsToAgents(options = {}) {
|
|
42863
42977
|
const requested = normalizeRequested(options.names);
|
|
42864
42978
|
const agents = options.agents?.length ? options.agents : [...SYNC_AGENTS];
|
|
42865
|
-
const homeDir = options.homeDir ??
|
|
42979
|
+
const homeDir = options.homeDir ?? homedir5();
|
|
42866
42980
|
const { roots, source } = resolveSyncCorpus(options);
|
|
42867
42981
|
const corpus = listPortableSkillsAcrossRoots(roots);
|
|
42868
42982
|
const byName = new Map(corpus.map((skill) => [skill.name, skill]));
|
|
@@ -42888,7 +43002,7 @@ function syncSkillsToAgents(options = {}) {
|
|
|
42888
43002
|
actions.push({
|
|
42889
43003
|
skill: name,
|
|
42890
43004
|
agent,
|
|
42891
|
-
path:
|
|
43005
|
+
path: join13(agentGlobalSkillsDir(agent, homeDir), name, "SKILL.md"),
|
|
42892
43006
|
action: "skip",
|
|
42893
43007
|
reason: "not found in this machine's corpus"
|
|
42894
43008
|
});
|
|
@@ -42917,8 +43031,8 @@ function syncSkillsToAgents(options = {}) {
|
|
|
42917
43031
|
return { actions };
|
|
42918
43032
|
}
|
|
42919
43033
|
function writeManagedAgentSkill(params) {
|
|
42920
|
-
const homeDir = params.homeDir ??
|
|
42921
|
-
const dir =
|
|
43034
|
+
const homeDir = params.homeDir ?? homedir5();
|
|
43035
|
+
const dir = join13(agentGlobalSkillsDir(params.agent, homeDir), params.skill);
|
|
42922
43036
|
const result2 = writeManagedSkillDir(dir, params.skillMd, {
|
|
42923
43037
|
skill: params.skill,
|
|
42924
43038
|
source: params.source,
|
|
@@ -42935,11 +43049,11 @@ function writeManagedAgentSkill(params) {
|
|
|
42935
43049
|
};
|
|
42936
43050
|
}
|
|
42937
43051
|
function writeManagedSkillDir(dir, skillMd, options) {
|
|
42938
|
-
const skillMdPath =
|
|
42939
|
-
const markerPath =
|
|
42940
|
-
const dirExists =
|
|
42941
|
-
const managed =
|
|
42942
|
-
const hasSkillMd =
|
|
43052
|
+
const skillMdPath = join13(dir, "SKILL.md");
|
|
43053
|
+
const markerPath = join13(dir, SYNC_MARKER_FILE);
|
|
43054
|
+
const dirExists = existsSync12(dir);
|
|
43055
|
+
const managed = existsSync12(markerPath);
|
|
43056
|
+
const hasSkillMd = existsSync12(skillMdPath);
|
|
42943
43057
|
if (dirExists && !managed && !hasSkillMd) {
|
|
42944
43058
|
return {
|
|
42945
43059
|
action: "skip",
|
|
@@ -42974,11 +43088,11 @@ function writeManagedSkillDir(dir, skillMd, options) {
|
|
|
42974
43088
|
return { action, path: skillMdPath };
|
|
42975
43089
|
const parentDir = dirname4(dir);
|
|
42976
43090
|
mkdirSync5(parentDir, { recursive: true });
|
|
42977
|
-
const transactionDir = mkdtempSync2(
|
|
42978
|
-
const candidateDir =
|
|
42979
|
-
const backupDir =
|
|
42980
|
-
const candidateSkillMdPath =
|
|
42981
|
-
const candidateMarkerPath =
|
|
43091
|
+
const transactionDir = mkdtempSync2(join13(parentDir, `.hasna-skills-write-${basename3(dir)}-`));
|
|
43092
|
+
const candidateDir = join13(transactionDir, "candidate");
|
|
43093
|
+
const backupDir = join13(transactionDir, "backup");
|
|
43094
|
+
const candidateSkillMdPath = join13(candidateDir, "SKILL.md");
|
|
43095
|
+
const candidateMarkerPath = join13(candidateDir, SYNC_MARKER_FILE);
|
|
42982
43096
|
const marker = {
|
|
42983
43097
|
managedBy: SYNC_MARKER_MANAGED_BY,
|
|
42984
43098
|
skill: options.skill,
|
|
@@ -43005,9 +43119,9 @@ function writeManagedSkillDir(dir, skillMd, options) {
|
|
|
43005
43119
|
}
|
|
43006
43120
|
renameDirectory(candidateDir, dir);
|
|
43007
43121
|
} catch (error) {
|
|
43008
|
-
if (originalMoved &&
|
|
43122
|
+
if (originalMoved && existsSync12(backupDir)) {
|
|
43009
43123
|
try {
|
|
43010
|
-
if (
|
|
43124
|
+
if (existsSync12(dir))
|
|
43011
43125
|
rmSync3(dir, { recursive: true, force: true });
|
|
43012
43126
|
renameDirectory(backupDir, dir);
|
|
43013
43127
|
originalMoved = false;
|
|
@@ -43028,8 +43142,8 @@ function writeManagedSkillDir(dir, skillMd, options) {
|
|
|
43028
43142
|
}
|
|
43029
43143
|
function sourceSkillMd(skillPath, name, description, kind, preferBundledDocs = false) {
|
|
43030
43144
|
if (kind === undefined || kind === "instruction" || preferBundledDocs) {
|
|
43031
|
-
const skillMdPath =
|
|
43032
|
-
if (
|
|
43145
|
+
const skillMdPath = join13(skillPath, "SKILL.md");
|
|
43146
|
+
if (existsSync12(skillMdPath))
|
|
43033
43147
|
return readFileSync8(skillMdPath, "utf-8");
|
|
43034
43148
|
}
|
|
43035
43149
|
return pointerSkillMd(name, description);
|
|
@@ -43066,17 +43180,17 @@ function normalizeSkillName(name) {
|
|
|
43066
43180
|
}
|
|
43067
43181
|
|
|
43068
43182
|
// src/lib/project-state.ts
|
|
43069
|
-
import { existsSync as
|
|
43070
|
-
import { join as
|
|
43183
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync6, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "fs";
|
|
43184
|
+
import { join as join14 } from "path";
|
|
43071
43185
|
function getProjectStateDir(targetDir = process.cwd()) {
|
|
43072
|
-
return
|
|
43186
|
+
return join14(targetDir, SKILLS_PROJECT_DIR);
|
|
43073
43187
|
}
|
|
43074
43188
|
function getProjectConfigPath(targetDir = process.cwd()) {
|
|
43075
|
-
return
|
|
43189
|
+
return join14(getProjectStateDir(targetDir), PROJECT_CONFIG_FILE);
|
|
43076
43190
|
}
|
|
43077
43191
|
function loadProjectConfig(targetDir = process.cwd()) {
|
|
43078
43192
|
const path = getProjectConfigPath(targetDir);
|
|
43079
|
-
if (!
|
|
43193
|
+
if (!existsSync13(path))
|
|
43080
43194
|
return null;
|
|
43081
43195
|
try {
|
|
43082
43196
|
return normalizeProjectConfig(JSON.parse(readFileSync9(path, "utf-8")));
|
|
@@ -43233,44 +43347,44 @@ __export(exports_installer, {
|
|
|
43233
43347
|
AGENT_TARGETS: () => AGENT_TARGETS,
|
|
43234
43348
|
AGENT_LABELS: () => AGENT_LABELS
|
|
43235
43349
|
});
|
|
43236
|
-
import { existsSync as
|
|
43237
|
-
import { dirname as dirname5, join as
|
|
43238
|
-
import { homedir as
|
|
43350
|
+
import { existsSync as existsSync14, readFileSync as readFileSync10, rmSync as rmSync4 } from "fs";
|
|
43351
|
+
import { dirname as dirname5, join as join15 } from "path";
|
|
43352
|
+
import { homedir as homedir6 } from "os";
|
|
43239
43353
|
import { fileURLToPath } from "url";
|
|
43240
43354
|
function findSkillsDir() {
|
|
43241
43355
|
let dir = __dirname2;
|
|
43242
43356
|
for (let i = 0;i < 5; i++) {
|
|
43243
|
-
const candidate =
|
|
43244
|
-
if (
|
|
43357
|
+
const candidate = join15(dir, "skills");
|
|
43358
|
+
if (existsSync14(candidate) && !dir.includes(".skills"))
|
|
43245
43359
|
return candidate;
|
|
43246
43360
|
dir = dirname5(dir);
|
|
43247
43361
|
}
|
|
43248
|
-
return
|
|
43362
|
+
return join15(__dirname2, "..", "skills");
|
|
43249
43363
|
}
|
|
43250
43364
|
function getSkillPath(name) {
|
|
43251
43365
|
const skillName = normalizeSkillName(getCanonicalSkillName(name));
|
|
43252
43366
|
const portable = findPortableSkill(skillName);
|
|
43253
43367
|
if (portable)
|
|
43254
43368
|
return portable.path;
|
|
43255
|
-
const legacyCustomPath =
|
|
43256
|
-
if (
|
|
43369
|
+
const legacyCustomPath = join15(getDataDir(), "custom", skillName);
|
|
43370
|
+
if (existsSync14(legacyCustomPath))
|
|
43257
43371
|
return legacyCustomPath;
|
|
43258
43372
|
const extensionPath = findExtensionSkillPath(skillName);
|
|
43259
43373
|
if (extensionPath)
|
|
43260
43374
|
return extensionPath;
|
|
43261
|
-
return
|
|
43375
|
+
return join15(SKILLS_DIR, skillName);
|
|
43262
43376
|
}
|
|
43263
43377
|
function getCanonicalSkillName(name) {
|
|
43264
43378
|
return getSkill(name)?.name ?? resolveSkillAlias(normalizeSkillSlug(name));
|
|
43265
43379
|
}
|
|
43266
43380
|
function skillExists(name) {
|
|
43267
|
-
return
|
|
43381
|
+
return existsSync14(getSkillPath(name));
|
|
43268
43382
|
}
|
|
43269
43383
|
function installSkill(name, options = {}) {
|
|
43270
43384
|
const { targetDir = process.cwd(), overwrite = false } = options;
|
|
43271
43385
|
const canonicalName = getCanonicalSkillName(name);
|
|
43272
43386
|
const skillName = normalizeSkillName(canonicalName);
|
|
43273
|
-
if (!
|
|
43387
|
+
if (!existsSync14(getSkillPath(name))) {
|
|
43274
43388
|
const knownOfficial = Boolean(getSkill(name));
|
|
43275
43389
|
return {
|
|
43276
43390
|
skill: canonicalName,
|
|
@@ -43320,7 +43434,7 @@ function installRemoteSkill(skill, options = {}) {
|
|
|
43320
43434
|
}
|
|
43321
43435
|
function installSkillSource(name, _options = {}) {
|
|
43322
43436
|
const canonicalName = getCanonicalSkillName(name);
|
|
43323
|
-
if (!
|
|
43437
|
+
if (!existsSync14(getSkillPath(name))) {
|
|
43324
43438
|
return { skill: canonicalName, success: false, error: `Skill '${name}' not found`, mode: "source" };
|
|
43325
43439
|
}
|
|
43326
43440
|
return {
|
|
@@ -43341,11 +43455,11 @@ function installSkillManifest(manifest, _options = {}) {
|
|
|
43341
43455
|
}
|
|
43342
43456
|
function createLocalSkillManifest(name, generateSkillMd) {
|
|
43343
43457
|
const sourcePath = getSkillPath(name);
|
|
43344
|
-
if (!
|
|
43458
|
+
if (!existsSync14(sourcePath))
|
|
43345
43459
|
return null;
|
|
43346
43460
|
let skillMd = "";
|
|
43347
|
-
const skillMdPath =
|
|
43348
|
-
if (
|
|
43461
|
+
const skillMdPath = join15(sourcePath, "SKILL.md");
|
|
43462
|
+
if (existsSync14(skillMdPath)) {
|
|
43349
43463
|
skillMd = readFileSync10(skillMdPath, "utf-8");
|
|
43350
43464
|
} else if (generateSkillMd) {
|
|
43351
43465
|
skillMd = generateSkillMd(name) ?? "";
|
|
@@ -43426,20 +43540,20 @@ function getAgentSkillsDir(agent, scope = "global", projectDir) {
|
|
|
43426
43540
|
const base2 = projectDir || process.cwd();
|
|
43427
43541
|
switch (agent) {
|
|
43428
43542
|
case "pi":
|
|
43429
|
-
return scope === "project" ?
|
|
43543
|
+
return scope === "project" ? join15(base2, ".pi", "skills") : join15(homedir6(), ".pi", "agent", "skills");
|
|
43430
43544
|
case "opencode":
|
|
43431
|
-
return scope === "project" ?
|
|
43545
|
+
return scope === "project" ? join15(base2, ".opencode", "skills") : join15(homedir6(), ".config", "opencode", "skills");
|
|
43432
43546
|
default:
|
|
43433
|
-
return scope === "project" ?
|
|
43547
|
+
return scope === "project" ? join15(base2, `.${agent}`, "skills") : join15(homedir6(), `.${agent}`, "skills");
|
|
43434
43548
|
}
|
|
43435
43549
|
}
|
|
43436
43550
|
function getAgentSkillPath(name, agent, scope = "global", projectDir) {
|
|
43437
43551
|
const skillName = normalizeSkillName(getCanonicalSkillName(name));
|
|
43438
|
-
return
|
|
43552
|
+
return join15(getAgentSkillsDir(agent, scope, projectDir), skillName);
|
|
43439
43553
|
}
|
|
43440
43554
|
function installSkillForAgent(name, options, generateSkillMd) {
|
|
43441
43555
|
const canonicalName = getCanonicalSkillName(name);
|
|
43442
|
-
if (!
|
|
43556
|
+
if (!existsSync14(getSkillPath(name))) {
|
|
43443
43557
|
return { skill: canonicalName, success: false, error: `Skill '${name}' not found` };
|
|
43444
43558
|
}
|
|
43445
43559
|
const scope = options.scope ?? "global";
|
|
@@ -43463,15 +43577,15 @@ function removeSkillForAgent(name, options) {
|
|
|
43463
43577
|
const canonicalName = getCanonicalSkillName(name);
|
|
43464
43578
|
const scope = options.scope ?? "global";
|
|
43465
43579
|
const dir = getAgentSkillPath(canonicalName, options.agent, scope, options.projectDir);
|
|
43466
|
-
if (!
|
|
43580
|
+
if (!existsSync14(join15(dir, SYNC_MARKER_FILE)))
|
|
43467
43581
|
return false;
|
|
43468
43582
|
rmSync4(dir, { recursive: true, force: true });
|
|
43469
43583
|
return true;
|
|
43470
43584
|
}
|
|
43471
43585
|
function resolveAgentSkillMd(name, generateSkillMd) {
|
|
43472
43586
|
const sourcePath = getSkillPath(name);
|
|
43473
|
-
const skillMdPath =
|
|
43474
|
-
if (
|
|
43587
|
+
const skillMdPath = join15(sourcePath, "SKILL.md");
|
|
43588
|
+
if (existsSync14(skillMdPath))
|
|
43475
43589
|
return readFileSync10(skillMdPath, "utf-8");
|
|
43476
43590
|
if (generateSkillMd)
|
|
43477
43591
|
return generateSkillMd(name);
|
|
@@ -43490,7 +43604,7 @@ function warnMissingDependencies(name, targetDir) {
|
|
|
43490
43604
|
}
|
|
43491
43605
|
function generateMinimalSkillMd(name) {
|
|
43492
43606
|
const sourcePath = getSkillPath(name);
|
|
43493
|
-
if (!
|
|
43607
|
+
if (!existsSync14(sourcePath))
|
|
43494
43608
|
return null;
|
|
43495
43609
|
const canonicalName = getCanonicalSkillName(name);
|
|
43496
43610
|
const meta = getSkill(canonicalName);
|
|
@@ -43505,7 +43619,7 @@ function generateMinimalSkillMd(name) {
|
|
|
43505
43619
|
"---",
|
|
43506
43620
|
""
|
|
43507
43621
|
].filter(Boolean);
|
|
43508
|
-
const fallbackDoc = readFileIfExists(
|
|
43622
|
+
const fallbackDoc = readFileIfExists(join15(sourcePath, "README.md")) || readFileIfExists(join15(sourcePath, "CLAUDE.md"));
|
|
43509
43623
|
if (fallbackDoc)
|
|
43510
43624
|
return `${frontmatter.join(`
|
|
43511
43625
|
`)}${fallbackDoc.trim()}
|
|
@@ -43524,8 +43638,8 @@ skills run ${canonicalName}
|
|
|
43524
43638
|
`;
|
|
43525
43639
|
}
|
|
43526
43640
|
function readBundledSkillVersion(name) {
|
|
43527
|
-
const pkgPath =
|
|
43528
|
-
if (!
|
|
43641
|
+
const pkgPath = join15(getSkillPath(name), "package.json");
|
|
43642
|
+
if (!existsSync14(pkgPath))
|
|
43529
43643
|
return "unknown";
|
|
43530
43644
|
try {
|
|
43531
43645
|
const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
|
|
@@ -43535,7 +43649,7 @@ function readBundledSkillVersion(name) {
|
|
|
43535
43649
|
}
|
|
43536
43650
|
}
|
|
43537
43651
|
function readFileIfExists(path) {
|
|
43538
|
-
return
|
|
43652
|
+
return existsSync14(path) ? readFileSync10(path, "utf-8") : null;
|
|
43539
43653
|
}
|
|
43540
43654
|
function loadProjectConfigCompat(targetDir) {
|
|
43541
43655
|
return loadProjectConfig(targetDir);
|
|
@@ -47654,23 +47768,23 @@ __export(exports_auth_store, {
|
|
|
47654
47768
|
getApiKey: () => getApiKey,
|
|
47655
47769
|
clearAuthConfig: () => clearAuthConfig
|
|
47656
47770
|
});
|
|
47657
|
-
import { existsSync as
|
|
47658
|
-
import { dirname as dirname6, join as
|
|
47659
|
-
import { homedir as
|
|
47771
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync7, readFileSync as readFileSync11, writeFileSync as writeFileSync7, unlinkSync } from "fs";
|
|
47772
|
+
import { dirname as dirname6, join as join16 } from "path";
|
|
47773
|
+
import { homedir as homedir7 } from "os";
|
|
47660
47774
|
function getAuthFilePath() {
|
|
47661
|
-
return
|
|
47775
|
+
return join16(getDataDir(), "auth.json");
|
|
47662
47776
|
}
|
|
47663
47777
|
function getAuthFilePathReadOnly() {
|
|
47664
|
-
return
|
|
47778
|
+
return join16(getDataDirReadOnly(), "auth.json");
|
|
47665
47779
|
}
|
|
47666
47780
|
function legacyAuthFilePath() {
|
|
47667
|
-
return
|
|
47781
|
+
return join16(process.env["HOME"] || process.env["USERPROFILE"] || homedir7(), ".skills", "auth.json");
|
|
47668
47782
|
}
|
|
47669
47783
|
function getAuthConfig() {
|
|
47670
47784
|
if (cachedConfig !== undefined)
|
|
47671
47785
|
return cachedConfig;
|
|
47672
47786
|
try {
|
|
47673
|
-
const file =
|
|
47787
|
+
const file = existsSync15(getAuthFilePath()) ? getAuthFilePath() : legacyAuthFilePath();
|
|
47674
47788
|
const raw = readFileSync11(file, "utf-8");
|
|
47675
47789
|
const config = JSON.parse(raw);
|
|
47676
47790
|
if (!config.apiKey) {
|
|
@@ -47709,7 +47823,7 @@ function getApiKey() {
|
|
|
47709
47823
|
}
|
|
47710
47824
|
function getAuthConfigReadOnly() {
|
|
47711
47825
|
try {
|
|
47712
|
-
const file =
|
|
47826
|
+
const file = existsSync15(getAuthFilePathReadOnly()) ? getAuthFilePathReadOnly() : legacyAuthFilePath();
|
|
47713
47827
|
const raw = readFileSync11(file, "utf-8");
|
|
47714
47828
|
const config = JSON.parse(raw);
|
|
47715
47829
|
if (!config.apiKey)
|
|
@@ -48266,12 +48380,12 @@ function handleBrowseError(error) {
|
|
|
48266
48380
|
async function writeJson(value, space) {
|
|
48267
48381
|
const text = `${JSON.stringify(value, null, space)}
|
|
48268
48382
|
`;
|
|
48269
|
-
await new Promise((
|
|
48383
|
+
await new Promise((resolve2, reject2) => {
|
|
48270
48384
|
process.stdout.write(text, (error) => {
|
|
48271
48385
|
if (error)
|
|
48272
48386
|
reject2(error);
|
|
48273
48387
|
else
|
|
48274
|
-
|
|
48388
|
+
resolve2();
|
|
48275
48389
|
});
|
|
48276
48390
|
});
|
|
48277
48391
|
}
|
|
@@ -48602,13 +48716,13 @@ __export(exports_skillinfo, {
|
|
|
48602
48716
|
generateEnvExample: () => generateEnvExample,
|
|
48603
48717
|
detectProjectSkills: () => detectProjectSkills
|
|
48604
48718
|
});
|
|
48605
|
-
import { existsSync as
|
|
48606
|
-
import { join as
|
|
48719
|
+
import { existsSync as existsSync16, readFileSync as readFileSync12 } from "fs";
|
|
48720
|
+
import { join as join17 } from "path";
|
|
48607
48721
|
function isInstructionSkillDir(skillPath, meta) {
|
|
48608
48722
|
if (meta?.kind === "instruction")
|
|
48609
48723
|
return true;
|
|
48610
|
-
const skillMdPath =
|
|
48611
|
-
if (!
|
|
48724
|
+
const skillMdPath = join17(skillPath, "SKILL.md");
|
|
48725
|
+
if (!existsSync16(skillMdPath))
|
|
48612
48726
|
return false;
|
|
48613
48727
|
try {
|
|
48614
48728
|
return parseSkillFrontmatter(readFileSync12(skillMdPath, "utf-8"))?.kind === "instruction";
|
|
@@ -48618,12 +48732,12 @@ function isInstructionSkillDir(skillPath, meta) {
|
|
|
48618
48732
|
}
|
|
48619
48733
|
function getSkillDocs(name) {
|
|
48620
48734
|
const skillPath = getSkillPath(name);
|
|
48621
|
-
if (!
|
|
48735
|
+
if (!existsSync16(skillPath))
|
|
48622
48736
|
return null;
|
|
48623
48737
|
return {
|
|
48624
|
-
skillMd: readIfExists(
|
|
48625
|
-
readme: readIfExists(
|
|
48626
|
-
claudeMd: readIfExists(
|
|
48738
|
+
skillMd: readIfExists(join17(skillPath, "SKILL.md")),
|
|
48739
|
+
readme: readIfExists(join17(skillPath, "README.md")),
|
|
48740
|
+
claudeMd: readIfExists(join17(skillPath, "CLAUDE.md"))
|
|
48627
48741
|
};
|
|
48628
48742
|
}
|
|
48629
48743
|
function getSkillBestDoc(name) {
|
|
@@ -48634,11 +48748,11 @@ function getSkillBestDoc(name) {
|
|
|
48634
48748
|
}
|
|
48635
48749
|
function getSkillRequirements(name) {
|
|
48636
48750
|
const skillPath = getSkillPath(name);
|
|
48637
|
-
if (!
|
|
48751
|
+
if (!existsSync16(skillPath))
|
|
48638
48752
|
return null;
|
|
48639
48753
|
const texts = [];
|
|
48640
48754
|
for (const file of ["SKILL.md", "README.md", "CLAUDE.md", ".env.example", ".env.local.example"]) {
|
|
48641
|
-
const content = readIfExists(
|
|
48755
|
+
const content = readIfExists(join17(skillPath, file));
|
|
48642
48756
|
if (content)
|
|
48643
48757
|
texts.push(content);
|
|
48644
48758
|
}
|
|
@@ -48677,8 +48791,8 @@ function getSkillRequirements(name) {
|
|
|
48677
48791
|
const skillName = normalizeSkillName(name);
|
|
48678
48792
|
let cliCommand = `skills run ${skillName}`;
|
|
48679
48793
|
let dependencies = {};
|
|
48680
|
-
const pkgPath =
|
|
48681
|
-
if (
|
|
48794
|
+
const pkgPath = join17(skillPath, "package.json");
|
|
48795
|
+
if (existsSync16(pkgPath)) {
|
|
48682
48796
|
try {
|
|
48683
48797
|
const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
|
|
48684
48798
|
dependencies = pkg.dependencies || {};
|
|
@@ -48697,9 +48811,9 @@ function isHostedPremiumSkill(skillName, meta) {
|
|
|
48697
48811
|
function isPackageResolvable(pkgName, fromDir) {
|
|
48698
48812
|
let dir = fromDir;
|
|
48699
48813
|
while (true) {
|
|
48700
|
-
if (
|
|
48814
|
+
if (existsSync16(join17(dir, "node_modules", pkgName, "package.json")))
|
|
48701
48815
|
return true;
|
|
48702
|
-
const parent =
|
|
48816
|
+
const parent = join17(dir, "..");
|
|
48703
48817
|
if (parent === dir)
|
|
48704
48818
|
return false;
|
|
48705
48819
|
dir = parent;
|
|
@@ -48719,7 +48833,7 @@ async function runSkill(name, args, options = {}) {
|
|
|
48719
48833
|
const meta = getSkill(name);
|
|
48720
48834
|
const canonicalName = meta?.name ?? name;
|
|
48721
48835
|
const skillPath = getSkillPath(canonicalName);
|
|
48722
|
-
if (!
|
|
48836
|
+
if (!existsSync16(skillPath)) {
|
|
48723
48837
|
return { exitCode: 1, error: `Skill '${name}' not found` };
|
|
48724
48838
|
}
|
|
48725
48839
|
if (isInstructionSkillDir(skillPath, meta)) {
|
|
@@ -48728,8 +48842,8 @@ async function runSkill(name, args, options = {}) {
|
|
|
48728
48842
|
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'.`
|
|
48729
48843
|
};
|
|
48730
48844
|
}
|
|
48731
|
-
const pkgPath =
|
|
48732
|
-
if (!
|
|
48845
|
+
const pkgPath = join17(skillPath, "package.json");
|
|
48846
|
+
if (!existsSync16(pkgPath)) {
|
|
48733
48847
|
return { exitCode: 1, error: `No package.json in skill '${name}'` };
|
|
48734
48848
|
}
|
|
48735
48849
|
let entryPoint;
|
|
@@ -48748,12 +48862,12 @@ async function runSkill(name, args, options = {}) {
|
|
|
48748
48862
|
} catch {
|
|
48749
48863
|
return { exitCode: 1, error: `Failed to parse package.json for skill '${name}'` };
|
|
48750
48864
|
}
|
|
48751
|
-
const entryPath =
|
|
48752
|
-
if (!
|
|
48865
|
+
const entryPath = join17(skillPath, entryPoint);
|
|
48866
|
+
if (!existsSync16(entryPath)) {
|
|
48753
48867
|
return { exitCode: 1, error: `Entry point '${entryPoint}' not found in skill '${name}'` };
|
|
48754
48868
|
}
|
|
48755
|
-
const nodeModules =
|
|
48756
|
-
if (!
|
|
48869
|
+
const nodeModules = join17(skillPath, "node_modules");
|
|
48870
|
+
if (!existsSync16(nodeModules)) {
|
|
48757
48871
|
const install = Bun.spawn(["bun", "install", "--no-save"], {
|
|
48758
48872
|
cwd: skillPath,
|
|
48759
48873
|
stdout: "pipe",
|
|
@@ -48780,8 +48894,8 @@ async function runSkill(name, args, options = {}) {
|
|
|
48780
48894
|
return { exitCode };
|
|
48781
48895
|
}
|
|
48782
48896
|
function detectProjectSkills(cwd2 = process.cwd()) {
|
|
48783
|
-
const pkgPath =
|
|
48784
|
-
if (!
|
|
48897
|
+
const pkgPath = join17(cwd2, "package.json");
|
|
48898
|
+
if (!existsSync16(pkgPath)) {
|
|
48785
48899
|
const alwaysRecommend = ["market-research-report", "repo-onboarding-report", "blog-article"];
|
|
48786
48900
|
const recommended2 = alwaysRecommend.map((name) => loadRegistry().find((s) => s.name === name)).filter((s) => s !== undefined);
|
|
48787
48901
|
return { detected: [], recommended: recommended2 };
|
|
@@ -48908,7 +49022,7 @@ function generateSkillMd(name) {
|
|
|
48908
49022
|
if (!meta)
|
|
48909
49023
|
return null;
|
|
48910
49024
|
const skillPath = getSkillPath(name);
|
|
48911
|
-
if (!
|
|
49025
|
+
if (!existsSync16(skillPath))
|
|
48912
49026
|
return null;
|
|
48913
49027
|
const frontmatter = [
|
|
48914
49028
|
"---",
|
|
@@ -48917,11 +49031,11 @@ function generateSkillMd(name) {
|
|
|
48917
49031
|
"---"
|
|
48918
49032
|
].join(`
|
|
48919
49033
|
`);
|
|
48920
|
-
const readme = readIfExists(
|
|
48921
|
-
const claudeMd = readIfExists(
|
|
49034
|
+
const readme = readIfExists(join17(skillPath, "README.md"));
|
|
49035
|
+
const claudeMd = readIfExists(join17(skillPath, "CLAUDE.md"));
|
|
48922
49036
|
let cliCommand = null;
|
|
48923
|
-
const pkgPath =
|
|
48924
|
-
if (
|
|
49037
|
+
const pkgPath = join17(skillPath, "package.json");
|
|
49038
|
+
if (existsSync16(pkgPath)) {
|
|
48925
49039
|
try {
|
|
48926
49040
|
const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
|
|
48927
49041
|
if (pkg.bin) {
|
|
@@ -48996,7 +49110,7 @@ function extractEnvVars(text) {
|
|
|
48996
49110
|
}
|
|
48997
49111
|
function readIfExists(path) {
|
|
48998
49112
|
try {
|
|
48999
|
-
if (
|
|
49113
|
+
if (existsSync16(path)) {
|
|
49000
49114
|
return readFileSync12(path, "utf-8");
|
|
49001
49115
|
}
|
|
49002
49116
|
} catch {}
|
|
@@ -49032,8 +49146,8 @@ var exports_introspect = {};
|
|
|
49032
49146
|
__export(exports_introspect, {
|
|
49033
49147
|
registerIntrospect: () => registerIntrospect
|
|
49034
49148
|
});
|
|
49035
|
-
import { existsSync as
|
|
49036
|
-
import { join as
|
|
49149
|
+
import { existsSync as existsSync17, readFileSync as readFileSync13 } from "fs";
|
|
49150
|
+
import { join as join18 } from "path";
|
|
49037
49151
|
import { execSync } from "child_process";
|
|
49038
49152
|
function registerIntrospect(parent) {
|
|
49039
49153
|
parent.command("info").argument("<skill>", "Skill name").option("--json", "Output as JSON", false).option("--brief", "Single line: name \u2014 description [category] (tags: ...)", false).option("--remote", "Use remote registry from SKILLS_API_URL or config apiUrl", false).description("Show details about a specific skill").action((name, options) => {
|
|
@@ -49254,20 +49368,20 @@ function handleDiff(name, options) {
|
|
|
49254
49368
|
const bare = name;
|
|
49255
49369
|
const normalized = normalizePortableSkillName(bare);
|
|
49256
49370
|
const sourcePath = getSkillPath(bare);
|
|
49257
|
-
const canonicalDir =
|
|
49258
|
-
const canonicalSkillMd =
|
|
49371
|
+
const canonicalDir = join18(resolveCorpusRoot(), normalized);
|
|
49372
|
+
const canonicalSkillMd = join18(canonicalDir, "SKILL.md");
|
|
49259
49373
|
const canonical = {
|
|
49260
|
-
present:
|
|
49374
|
+
present: existsSync17(canonicalSkillMd),
|
|
49261
49375
|
path: canonicalDir,
|
|
49262
|
-
...
|
|
49263
|
-
...
|
|
49376
|
+
...existsSync17(canonicalSkillMd) ? { hash: hashSkillMarkdownFile(canonicalSkillMd) } : {},
|
|
49377
|
+
...existsSync17(canonicalSkillMd) ? { stub: isPointerSkillMd(readFileSync13(canonicalSkillMd, "utf-8")) } : {}
|
|
49264
49378
|
};
|
|
49265
49379
|
const pinned = getInstalledSkills().includes(bare);
|
|
49266
49380
|
const installMeta = getInstallMeta();
|
|
49267
49381
|
const installedVersion = installMeta.skills[bare]?.version ?? "unknown";
|
|
49268
|
-
const registryPkgPath =
|
|
49382
|
+
const registryPkgPath = join18(sourcePath, "package.json");
|
|
49269
49383
|
let registryVersion = "unknown";
|
|
49270
|
-
if (
|
|
49384
|
+
if (existsSync17(registryPkgPath)) {
|
|
49271
49385
|
try {
|
|
49272
49386
|
registryVersion = JSON.parse(readFileSync13(registryPkgPath, "utf-8")).version || "unknown";
|
|
49273
49387
|
} catch {}
|
|
@@ -49275,13 +49389,13 @@ function handleDiff(name, options) {
|
|
|
49275
49389
|
const upToDate = installedVersion === registryVersion;
|
|
49276
49390
|
const homes = [];
|
|
49277
49391
|
for (const agent of SYNC_AGENTS) {
|
|
49278
|
-
const dir =
|
|
49279
|
-
const present =
|
|
49280
|
-
const managed =
|
|
49281
|
-
const skillMdPath =
|
|
49282
|
-
const hash = present &&
|
|
49392
|
+
const dir = join18(agentGlobalSkillsDir(agent), normalized);
|
|
49393
|
+
const present = existsSync17(dir);
|
|
49394
|
+
const managed = existsSync17(join18(dir, SYNC_MARKER_FILE));
|
|
49395
|
+
const skillMdPath = join18(dir, "SKILL.md");
|
|
49396
|
+
const hash = present && existsSync17(skillMdPath) ? hashSkillMarkdownFile(skillMdPath) : undefined;
|
|
49283
49397
|
let stub;
|
|
49284
|
-
if (present &&
|
|
49398
|
+
if (present && existsSync17(skillMdPath)) {
|
|
49285
49399
|
try {
|
|
49286
49400
|
stub = isPointerSkillMd(readFileSync13(skillMdPath, "utf-8"));
|
|
49287
49401
|
} catch {
|
|
@@ -49816,8 +49930,8 @@ var exports_init = {};
|
|
|
49816
49930
|
__export(exports_init, {
|
|
49817
49931
|
registerSetup: () => registerSetup
|
|
49818
49932
|
});
|
|
49819
|
-
import { existsSync as
|
|
49820
|
-
import { join as
|
|
49933
|
+
import { existsSync as existsSync18, readFileSync as readFileSync14, writeFileSync as writeFileSync8, appendFileSync } from "fs";
|
|
49934
|
+
import { join as join19 } from "path";
|
|
49821
49935
|
function registerSetup(parent) {
|
|
49822
49936
|
parent.command("init").option("--json", "Output as JSON", false).option("--for <agent>", "Detect project type and show MCP registration guidance for agent").option("--scope <scope>", "Deprecated; agent skill-folder installs are disabled", "global").description("Initialize project for pinned skills (.env.example, .gitignore)").action((options) => handleInit(options));
|
|
49823
49937
|
parent.command("export").option("--json", "Output as JSON (default behavior)", false).description("Export pinned skills to JSON for sharing or backup").action((_options) => handleExport());
|
|
@@ -49901,7 +50015,7 @@ Use: skills render`));
|
|
|
49901
50015
|
lines.push(`# Used by: ${skills.join(", ")}`);
|
|
49902
50016
|
lines.push(`${envVar}=`);
|
|
49903
50017
|
}
|
|
49904
|
-
writeFileSync8(
|
|
50018
|
+
writeFileSync8(join19(cwd2, ".env.example"), lines.join(`
|
|
49905
50019
|
`) + `
|
|
49906
50020
|
`);
|
|
49907
50021
|
envVarCount = envMap.size;
|
|
@@ -49909,9 +50023,9 @@ Use: skills render`));
|
|
|
49909
50023
|
console.log(source_default.green(`\u2713 Generated .env.example (${envVarCount} variables from ${installed.length} skills)`));
|
|
49910
50024
|
} else if (!options.json)
|
|
49911
50025
|
console.log(source_default.dim(" No environment variables detected across pinned skills"));
|
|
49912
|
-
const gitignorePath =
|
|
50026
|
+
const gitignorePath = join19(cwd2, ".gitignore");
|
|
49913
50027
|
const gitignoreEntries = [".skills/runs/", ".skills/exports/", ".skills/tmp/"];
|
|
49914
|
-
let gitignoreContent =
|
|
50028
|
+
let gitignoreContent = existsSync18(gitignorePath) ? readFileSync14(gitignorePath, "utf-8") : "";
|
|
49915
50029
|
let gitignoreUpdated = false;
|
|
49916
50030
|
const missingEntries = gitignoreEntries.filter((entry) => !gitignoreContent.includes(entry));
|
|
49917
50031
|
if (missingEntries.length > 0) {
|
|
@@ -49957,7 +50071,7 @@ async function handleImport(file, options) {
|
|
|
49957
50071
|
if (file === "-")
|
|
49958
50072
|
raw = await new Response(process.stdin).text();
|
|
49959
50073
|
else {
|
|
49960
|
-
if (!
|
|
50074
|
+
if (!existsSync18(file)) {
|
|
49961
50075
|
const error = `File not found: ${file}`;
|
|
49962
50076
|
if (options.json)
|
|
49963
50077
|
console.log(JSON.stringify({ imported: 0, error }));
|
|
@@ -50063,12 +50177,12 @@ var init_init = __esm(() => {
|
|
|
50063
50177
|
});
|
|
50064
50178
|
|
|
50065
50179
|
// src/lib/home-adoption.ts
|
|
50066
|
-
import { existsSync as
|
|
50067
|
-
import { homedir as
|
|
50068
|
-
import { join as
|
|
50180
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync8, readdirSync as readdirSync9, readFileSync as readFileSync15, rmSync as rmSync5, statSync as statSync9, writeFileSync as writeFileSync9 } from "fs";
|
|
50181
|
+
import { homedir as homedir8 } from "os";
|
|
50182
|
+
import { join as join20 } from "path";
|
|
50069
50183
|
function indexCanonicalCorpus(corpusRoot) {
|
|
50070
50184
|
const byName = new Map;
|
|
50071
|
-
if (!
|
|
50185
|
+
if (!existsSync19(corpusRoot))
|
|
50072
50186
|
return byName;
|
|
50073
50187
|
let entries = [];
|
|
50074
50188
|
try {
|
|
@@ -50079,8 +50193,8 @@ function indexCanonicalCorpus(corpusRoot) {
|
|
|
50079
50193
|
for (const entry of entries.sort()) {
|
|
50080
50194
|
if (entry.startsWith("."))
|
|
50081
50195
|
continue;
|
|
50082
|
-
const skillMd =
|
|
50083
|
-
if (!
|
|
50196
|
+
const skillMd = join20(corpusRoot, entry, "SKILL.md");
|
|
50197
|
+
if (!existsSync19(skillMd))
|
|
50084
50198
|
continue;
|
|
50085
50199
|
try {
|
|
50086
50200
|
byName.set(entry, hashSkillMarkdownFile(skillMd));
|
|
@@ -50089,14 +50203,14 @@ function indexCanonicalCorpus(corpusRoot) {
|
|
|
50089
50203
|
return byName;
|
|
50090
50204
|
}
|
|
50091
50205
|
function scanUnmarkedHomes(options = {}) {
|
|
50092
|
-
const homeDir = options.homeDir ??
|
|
50206
|
+
const homeDir = options.homeDir ?? homedir8();
|
|
50093
50207
|
const corpusRoot = resolveCorpusRoot(options);
|
|
50094
50208
|
const index = indexCanonicalCorpus(corpusRoot);
|
|
50095
50209
|
const agents = options.agents?.length ? options.agents : [...SYNC_AGENTS];
|
|
50096
50210
|
const scan = { adoptable: [], conflicts: [], unknown: [], managed: 0 };
|
|
50097
50211
|
for (const agent of agents) {
|
|
50098
50212
|
const home = agentGlobalSkillsDir(agent, homeDir);
|
|
50099
|
-
if (!
|
|
50213
|
+
if (!existsSync19(home))
|
|
50100
50214
|
continue;
|
|
50101
50215
|
let entries = [];
|
|
50102
50216
|
try {
|
|
@@ -50107,19 +50221,19 @@ function scanUnmarkedHomes(options = {}) {
|
|
|
50107
50221
|
for (const skill of entries.sort()) {
|
|
50108
50222
|
if (skill.startsWith("."))
|
|
50109
50223
|
continue;
|
|
50110
|
-
const dir =
|
|
50224
|
+
const dir = join20(home, skill);
|
|
50111
50225
|
try {
|
|
50112
50226
|
if (!statSync9(dir).isDirectory())
|
|
50113
50227
|
continue;
|
|
50114
50228
|
} catch {
|
|
50115
50229
|
continue;
|
|
50116
50230
|
}
|
|
50117
|
-
if (
|
|
50231
|
+
if (existsSync19(join20(dir, SYNC_MARKER_FILE))) {
|
|
50118
50232
|
scan.managed += 1;
|
|
50119
50233
|
continue;
|
|
50120
50234
|
}
|
|
50121
|
-
const skillMdPath =
|
|
50122
|
-
if (!
|
|
50235
|
+
const skillMdPath = join20(dir, "SKILL.md");
|
|
50236
|
+
if (!existsSync19(skillMdPath))
|
|
50123
50237
|
continue;
|
|
50124
50238
|
const hash = hashSkillMarkdownFile(skillMdPath);
|
|
50125
50239
|
const mtime = statSync9(skillMdPath).mtime.toISOString();
|
|
@@ -50139,9 +50253,9 @@ function scanUnmarkedHomes(options = {}) {
|
|
|
50139
50253
|
function appendConflictsLedger(appDir, conflicts) {
|
|
50140
50254
|
if (conflicts.length === 0)
|
|
50141
50255
|
return;
|
|
50142
|
-
const ledgerPath =
|
|
50256
|
+
const ledgerPath = join20(appDir, CONFLICTS_LEDGER_FILE);
|
|
50143
50257
|
let ledger = { version: 1, entries: [] };
|
|
50144
|
-
if (
|
|
50258
|
+
if (existsSync19(ledgerPath)) {
|
|
50145
50259
|
try {
|
|
50146
50260
|
const parsed = JSON.parse(readFileSync15(ledgerPath, "utf-8"));
|
|
50147
50261
|
if (parsed && typeof parsed === "object" && Array.isArray(parsed.entries)) {
|
|
@@ -50159,9 +50273,9 @@ function appendConflictsLedger(appDir, conflicts) {
|
|
|
50159
50273
|
`);
|
|
50160
50274
|
}
|
|
50161
50275
|
function writeRollbackRecord(mode, entries, appDir = getDataDir()) {
|
|
50162
|
-
const dir =
|
|
50276
|
+
const dir = join20(appDir, ROLLBACK_DIRNAME);
|
|
50163
50277
|
mkdirSync8(dir, { recursive: true });
|
|
50164
|
-
const file =
|
|
50278
|
+
const file = join20(dir, `${mode}-${Date.now()}.json`);
|
|
50165
50279
|
const record = { version: 1, mode, timestamp: new Date().toISOString(), entries };
|
|
50166
50280
|
writeFileSync9(file, `${JSON.stringify(record, null, 2)}
|
|
50167
50281
|
`);
|
|
@@ -50172,7 +50286,7 @@ function adoptUnmarkedHomes(options = {}) {
|
|
|
50172
50286
|
if (!options.apply) {
|
|
50173
50287
|
return { ...scan, applied: false };
|
|
50174
50288
|
}
|
|
50175
|
-
const appDir = options.homeDir ?
|
|
50289
|
+
const appDir = options.homeDir ? join20(options.homeDir, ".hasna", "skills") : getDataDir();
|
|
50176
50290
|
const markers = scan.adoptable.map((entry) => {
|
|
50177
50291
|
const marker = {
|
|
50178
50292
|
managedBy: SYNC_MARKER_MANAGED_BY,
|
|
@@ -50180,7 +50294,7 @@ function adoptUnmarkedHomes(options = {}) {
|
|
|
50180
50294
|
source: "adopted",
|
|
50181
50295
|
syncedAt: new Date().toISOString()
|
|
50182
50296
|
};
|
|
50183
|
-
writeFileSync9(
|
|
50297
|
+
writeFileSync9(join20(entry.path, SYNC_MARKER_FILE), `${JSON.stringify(marker, null, 2)}
|
|
50184
50298
|
`);
|
|
50185
50299
|
return { agent: entry.agent, skill: entry.skill, path: entry.path, hash: entry.hash, marker };
|
|
50186
50300
|
});
|
|
@@ -50192,14 +50306,14 @@ function adoptUnmarkedHomes(options = {}) {
|
|
|
50192
50306
|
return { ...scan, applied: true, rollbackFile };
|
|
50193
50307
|
}
|
|
50194
50308
|
function pruneStrayHomes(options = {}) {
|
|
50195
|
-
const homeDir = options.homeDir ??
|
|
50309
|
+
const homeDir = options.homeDir ?? homedir8();
|
|
50196
50310
|
const corpusRoot = resolveCorpusRoot(options);
|
|
50197
50311
|
const index = indexCanonicalCorpus(corpusRoot);
|
|
50198
50312
|
const agents = options.agents?.length ? options.agents : [...SYNC_AGENTS];
|
|
50199
50313
|
const candidates = [];
|
|
50200
50314
|
for (const agent of agents) {
|
|
50201
50315
|
const home = agentGlobalSkillsDir(agent, homeDir);
|
|
50202
|
-
if (!
|
|
50316
|
+
if (!existsSync19(home))
|
|
50203
50317
|
continue;
|
|
50204
50318
|
let entries = [];
|
|
50205
50319
|
try {
|
|
@@ -50210,15 +50324,15 @@ function pruneStrayHomes(options = {}) {
|
|
|
50210
50324
|
for (const skill of entries.sort()) {
|
|
50211
50325
|
if (skill.startsWith("."))
|
|
50212
50326
|
continue;
|
|
50213
|
-
const dir =
|
|
50327
|
+
const dir = join20(home, skill);
|
|
50214
50328
|
try {
|
|
50215
50329
|
if (!statSync9(dir).isDirectory())
|
|
50216
50330
|
continue;
|
|
50217
50331
|
} catch {
|
|
50218
50332
|
continue;
|
|
50219
50333
|
}
|
|
50220
|
-
const markerPath =
|
|
50221
|
-
if (!
|
|
50334
|
+
const markerPath = join20(dir, SYNC_MARKER_FILE);
|
|
50335
|
+
if (!existsSync19(markerPath))
|
|
50222
50336
|
continue;
|
|
50223
50337
|
if (index.has(skill))
|
|
50224
50338
|
continue;
|
|
@@ -50231,15 +50345,15 @@ function pruneStrayHomes(options = {}) {
|
|
|
50231
50345
|
} catch {
|
|
50232
50346
|
continue;
|
|
50233
50347
|
}
|
|
50234
|
-
const skillMdPath =
|
|
50235
|
-
const hash =
|
|
50348
|
+
const skillMdPath = join20(dir, "SKILL.md");
|
|
50349
|
+
const hash = existsSync19(skillMdPath) ? hashSkillMarkdownFile(skillMdPath) : "";
|
|
50236
50350
|
candidates.push({ agent, skill, home, path: dir, hash, marker });
|
|
50237
50351
|
}
|
|
50238
50352
|
}
|
|
50239
50353
|
if (!options.apply) {
|
|
50240
50354
|
return { candidates, pruned: 0, dryRun: true };
|
|
50241
50355
|
}
|
|
50242
|
-
const appDir = options.homeDir ?
|
|
50356
|
+
const appDir = options.homeDir ? join20(options.homeDir, ".hasna", "skills") : getDataDir();
|
|
50243
50357
|
const rollbackFile = writeRollbackRecord("prune", candidates.map(({ agent, skill, path, hash, marker }) => ({ agent, skill, path, hash, marker })), appDir);
|
|
50244
50358
|
for (const candidate of candidates) {
|
|
50245
50359
|
rmSync5(candidate.path, { recursive: true, force: true });
|
|
@@ -50255,9 +50369,9 @@ var init_home_adoption = __esm(() => {
|
|
|
50255
50369
|
});
|
|
50256
50370
|
|
|
50257
50371
|
// src/lib/home-census.ts
|
|
50258
|
-
import { existsSync as
|
|
50259
|
-
import { homedir as
|
|
50260
|
-
import { join as
|
|
50372
|
+
import { existsSync as existsSync20, readFileSync as readFileSync16, readdirSync as readdirSync10, statSync as statSync10 } from "fs";
|
|
50373
|
+
import { homedir as homedir9 } from "os";
|
|
50374
|
+
import { join as join21 } from "path";
|
|
50261
50375
|
function sortEntries(entries) {
|
|
50262
50376
|
return entries.sort((a, b) => {
|
|
50263
50377
|
const left = `${a.agent}/${a.skill}/${a.kind}`;
|
|
@@ -50266,7 +50380,7 @@ function sortEntries(entries) {
|
|
|
50266
50380
|
});
|
|
50267
50381
|
}
|
|
50268
50382
|
function censusHomeDrift(options = {}) {
|
|
50269
|
-
const homeDir = options.homeDir ??
|
|
50383
|
+
const homeDir = options.homeDir ?? homedir9();
|
|
50270
50384
|
const corpusRoot = resolveCorpusRoot(options);
|
|
50271
50385
|
const index = indexCanonicalCorpus(corpusRoot);
|
|
50272
50386
|
const agents = options.agents?.length ? options.agents : [...SYNC_AGENTS];
|
|
@@ -50276,7 +50390,7 @@ function censusHomeDrift(options = {}) {
|
|
|
50276
50390
|
let homesChecked = 0;
|
|
50277
50391
|
for (const agent of agents) {
|
|
50278
50392
|
const home = agentGlobalSkillsDir(agent, homeDir);
|
|
50279
|
-
if (!
|
|
50393
|
+
if (!existsSync20(home))
|
|
50280
50394
|
continue;
|
|
50281
50395
|
homesChecked += 1;
|
|
50282
50396
|
const present = new Set;
|
|
@@ -50289,7 +50403,7 @@ function censusHomeDrift(options = {}) {
|
|
|
50289
50403
|
for (const skill of dirEntries.sort()) {
|
|
50290
50404
|
if (skill.startsWith("."))
|
|
50291
50405
|
continue;
|
|
50292
|
-
const dir =
|
|
50406
|
+
const dir = join21(home, skill);
|
|
50293
50407
|
try {
|
|
50294
50408
|
if (!statSync10(dir).isDirectory())
|
|
50295
50409
|
continue;
|
|
@@ -50297,8 +50411,8 @@ function censusHomeDrift(options = {}) {
|
|
|
50297
50411
|
continue;
|
|
50298
50412
|
}
|
|
50299
50413
|
present.add(skill);
|
|
50300
|
-
const markerPath =
|
|
50301
|
-
if (!
|
|
50414
|
+
const markerPath = join21(dir, SYNC_MARKER_FILE);
|
|
50415
|
+
if (!existsSync20(markerPath)) {
|
|
50302
50416
|
unmarked += 1;
|
|
50303
50417
|
continue;
|
|
50304
50418
|
}
|
|
@@ -50308,8 +50422,8 @@ function censusHomeDrift(options = {}) {
|
|
|
50308
50422
|
entries.push({ agent, skill, kind: "stray-in-home", path: dir });
|
|
50309
50423
|
continue;
|
|
50310
50424
|
}
|
|
50311
|
-
const skillMdPath =
|
|
50312
|
-
if (!
|
|
50425
|
+
const skillMdPath = join21(dir, "SKILL.md");
|
|
50426
|
+
if (!existsSync20(skillMdPath)) {
|
|
50313
50427
|
entries.push({ agent, skill, kind: "diverged", path: dir, canonicalHash });
|
|
50314
50428
|
continue;
|
|
50315
50429
|
}
|
|
@@ -50322,7 +50436,7 @@ function censusHomeDrift(options = {}) {
|
|
|
50322
50436
|
homeStub = undefined;
|
|
50323
50437
|
}
|
|
50324
50438
|
let canonicalStub;
|
|
50325
|
-
const canonicalSkillMd =
|
|
50439
|
+
const canonicalSkillMd = join21(corpusRoot, skill, "SKILL.md");
|
|
50326
50440
|
try {
|
|
50327
50441
|
canonicalStub = isPointerSkillMd(readFileSync16(canonicalSkillMd, "utf-8"));
|
|
50328
50442
|
} catch {
|
|
@@ -50337,7 +50451,7 @@ function censusHomeDrift(options = {}) {
|
|
|
50337
50451
|
agent,
|
|
50338
50452
|
skill: name,
|
|
50339
50453
|
kind: "missing-from-home",
|
|
50340
|
-
path:
|
|
50454
|
+
path: join21(home, name),
|
|
50341
50455
|
canonicalHash
|
|
50342
50456
|
});
|
|
50343
50457
|
}
|
|
@@ -50363,8 +50477,8 @@ var exports_diagnostic = {};
|
|
|
50363
50477
|
__export(exports_diagnostic, {
|
|
50364
50478
|
registerDiagnostic: () => registerDiagnostic
|
|
50365
50479
|
});
|
|
50366
|
-
import { existsSync as
|
|
50367
|
-
import { join as
|
|
50480
|
+
import { existsSync as existsSync21, readFileSync as readFileSync17, readdirSync as readdirSync11, statSync as statSync11, writeFileSync as writeFileSync10 } from "fs";
|
|
50481
|
+
import { join as join22 } from "path";
|
|
50368
50482
|
import { execSync as execSync2 } from "child_process";
|
|
50369
50483
|
function registerDiagnostic(parent) {
|
|
50370
50484
|
parent.command("doctor").option("--json", "Output as JSON", false).description("Check env vars, system deps, and readiness for pinned skills").action((options) => handleDoctor(options));
|
|
@@ -50480,7 +50594,7 @@ Skills Test (${results.length} skill${results.length === 1 ? "" : "s"}):
|
|
|
50480
50594
|
}
|
|
50481
50595
|
function handleAuth(name, options) {
|
|
50482
50596
|
const cwd2 = process.cwd();
|
|
50483
|
-
const envFilePath =
|
|
50597
|
+
const envFilePath = join22(cwd2, ".env");
|
|
50484
50598
|
if (options.set) {
|
|
50485
50599
|
const eqIdx = options.set.indexOf("=");
|
|
50486
50600
|
if (eqIdx === -1) {
|
|
@@ -50502,7 +50616,7 @@ function handleAuth(name, options) {
|
|
|
50502
50616
|
process.exitCode = 1;
|
|
50503
50617
|
return;
|
|
50504
50618
|
}
|
|
50505
|
-
let existing =
|
|
50619
|
+
let existing = existsSync21(envFilePath) ? readFileSync17(envFilePath, "utf-8") : "";
|
|
50506
50620
|
const keyPattern = new RegExp(`^${key}=.*$`, "m");
|
|
50507
50621
|
const updated = keyPattern.test(existing) ? existing.replace(keyPattern, `${key}=${value}`) : existing.endsWith(`
|
|
50508
50622
|
`) || existing === "" ? existing + `${key}=${value}
|
|
@@ -50568,11 +50682,11 @@ function handleWhoami(options) {
|
|
|
50568
50682
|
const agentConfigs = [];
|
|
50569
50683
|
for (const agent of AGENT_TARGETS) {
|
|
50570
50684
|
const agentSkillsPath = getAgentSkillsDir(agent, "global");
|
|
50571
|
-
const exists =
|
|
50685
|
+
const exists = existsSync21(agentSkillsPath);
|
|
50572
50686
|
let skillCount = 0;
|
|
50573
50687
|
if (exists)
|
|
50574
50688
|
try {
|
|
50575
|
-
skillCount = readdirSync11(agentSkillsPath).filter((f) => !f.startsWith(".") && statSync11(
|
|
50689
|
+
skillCount = readdirSync11(agentSkillsPath).filter((f) => !f.startsWith(".") && statSync11(join22(agentSkillsPath, f)).isDirectory()).length;
|
|
50576
50690
|
} catch {}
|
|
50577
50691
|
agentConfigs.push({ agent, label: AGENT_LABELS[agent], path: agentSkillsPath, exists, skillCount });
|
|
50578
50692
|
}
|
|
@@ -50606,9 +50720,9 @@ function handleOutdated(options) {
|
|
|
50606
50720
|
for (const name of installed) {
|
|
50607
50721
|
const installedVersion = meta.skills[name]?.version ?? "unknown";
|
|
50608
50722
|
const registryPath = getSkillPath(name);
|
|
50609
|
-
const registryPkgPath =
|
|
50723
|
+
const registryPkgPath = join22(registryPath, "package.json");
|
|
50610
50724
|
let registryVersion = "unknown";
|
|
50611
|
-
if (
|
|
50725
|
+
if (existsSync21(registryPkgPath))
|
|
50612
50726
|
try {
|
|
50613
50727
|
registryVersion = JSON.parse(readFileSync17(registryPkgPath, "utf-8")).version || "unknown";
|
|
50614
50728
|
} catch {}
|
|
@@ -50874,20 +50988,20 @@ var init_runs = __esm(() => {
|
|
|
50874
50988
|
|
|
50875
50989
|
// src/lib/run-state.ts
|
|
50876
50990
|
import { createHash as createHash2, randomBytes } from "crypto";
|
|
50877
|
-
import { existsSync as
|
|
50878
|
-
import { extname, join as
|
|
50991
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync9, readFileSync as readFileSync18, readdirSync as readdirSync12, statSync as statSync12, writeFileSync as writeFileSync11 } from "fs";
|
|
50992
|
+
import { extname, join as join23, relative as relative2 } from "path";
|
|
50879
50993
|
function createSkillRun(params, targetDir = process.cwd()) {
|
|
50880
50994
|
const now3 = new Date;
|
|
50881
50995
|
const id = createRunId(now3);
|
|
50882
50996
|
const day = now3.toISOString().slice(0, 10);
|
|
50883
50997
|
const skillName = normalizeSkillName(params.skill);
|
|
50884
50998
|
const root = getProjectStateDir(targetDir);
|
|
50885
|
-
const runDir =
|
|
50886
|
-
const logsDir =
|
|
50887
|
-
const exportDir =
|
|
50999
|
+
const runDir = join23(root, "runs", day, id);
|
|
51000
|
+
const logsDir = join23(runDir, "logs");
|
|
51001
|
+
const exportDir = join23(root, "exports", skillName, id);
|
|
50888
51002
|
mkdirSync9(logsDir, { recursive: true });
|
|
50889
51003
|
mkdirSync9(exportDir, { recursive: true });
|
|
50890
|
-
mkdirSync9(
|
|
51004
|
+
mkdirSync9(join23(root, "tmp"), { recursive: true });
|
|
50891
51005
|
const record = {
|
|
50892
51006
|
id,
|
|
50893
51007
|
skill: skillName,
|
|
@@ -50938,27 +51052,27 @@ function updateSkillRun(context, patch) {
|
|
|
50938
51052
|
return context.record;
|
|
50939
51053
|
}
|
|
50940
51054
|
function writeRunLogs(context, stdout = "", stderr = "") {
|
|
50941
|
-
writeFileSync11(
|
|
50942
|
-
writeFileSync11(
|
|
51055
|
+
writeFileSync11(join23(context.logsDir, "stdout.log"), stdout);
|
|
51056
|
+
writeFileSync11(join23(context.logsDir, "stderr.log"), stderr);
|
|
50943
51057
|
}
|
|
50944
51058
|
function appendRunEvent(context, event, data = {}) {
|
|
50945
51059
|
const line = JSON.stringify({ ts: new Date().toISOString(), event, ...data }) + `
|
|
50946
51060
|
`;
|
|
50947
|
-
const path =
|
|
50948
|
-
const previous =
|
|
51061
|
+
const path = join23(context.runDir, "events.ndjson");
|
|
51062
|
+
const previous = existsSync22(path) ? readFileSync18(path, "utf-8") : "";
|
|
50949
51063
|
writeFileSync11(path, previous + line);
|
|
50950
51064
|
}
|
|
50951
51065
|
function listSkillRuns(targetDir = process.cwd(), limit = 50) {
|
|
50952
|
-
const runsRoot =
|
|
50953
|
-
if (!
|
|
51066
|
+
const runsRoot = join23(getProjectStateDir(targetDir), "runs");
|
|
51067
|
+
if (!existsSync22(runsRoot))
|
|
50954
51068
|
return [];
|
|
50955
51069
|
const records = [];
|
|
50956
51070
|
for (const day of readdirSync12(runsRoot).sort().reverse()) {
|
|
50957
|
-
const dayDir =
|
|
51071
|
+
const dayDir = join23(runsRoot, day);
|
|
50958
51072
|
if (!statSync12(dayDir).isDirectory())
|
|
50959
51073
|
continue;
|
|
50960
51074
|
for (const runId of readdirSync12(dayDir).sort().reverse()) {
|
|
50961
|
-
const record = readRunRecord(
|
|
51075
|
+
const record = readRunRecord(join23(dayDir, runId));
|
|
50962
51076
|
if (record)
|
|
50963
51077
|
records.push(record);
|
|
50964
51078
|
if (records.length >= limit)
|
|
@@ -50968,11 +51082,11 @@ function listSkillRuns(targetDir = process.cwd(), limit = 50) {
|
|
|
50968
51082
|
return records;
|
|
50969
51083
|
}
|
|
50970
51084
|
function findSkillRun(runId, targetDir = process.cwd()) {
|
|
50971
|
-
const runsRoot =
|
|
50972
|
-
if (!
|
|
51085
|
+
const runsRoot = join23(getProjectStateDir(targetDir), "runs");
|
|
51086
|
+
if (!existsSync22(runsRoot))
|
|
50973
51087
|
return null;
|
|
50974
51088
|
for (const day of readdirSync12(runsRoot)) {
|
|
50975
|
-
const record = readRunRecord(
|
|
51089
|
+
const record = readRunRecord(join23(runsRoot, day, runId));
|
|
50976
51090
|
if (record)
|
|
50977
51091
|
return record;
|
|
50978
51092
|
}
|
|
@@ -50989,18 +51103,18 @@ function skillRunEnv(context) {
|
|
|
50989
51103
|
};
|
|
50990
51104
|
}
|
|
50991
51105
|
function getRunExportDir(runId, skill, targetDir = process.cwd()) {
|
|
50992
|
-
return
|
|
51106
|
+
return join23(getProjectStateDir(targetDir), "exports", normalizeSkillName(skill), runId);
|
|
50993
51107
|
}
|
|
50994
51108
|
function writeRunRecord(context) {
|
|
50995
|
-
writeFileSync11(
|
|
51109
|
+
writeFileSync11(join23(context.runDir, "run.json"), JSON.stringify(context.record, null, 2) + `
|
|
50996
51110
|
`);
|
|
50997
51111
|
}
|
|
50998
51112
|
function writeArtifactsManifest(context, artifacts) {
|
|
50999
|
-
writeFileSync11(
|
|
51113
|
+
writeFileSync11(join23(context.runDir, "artifacts.json"), JSON.stringify({ runId: context.record.id, artifacts }, null, 2) + `
|
|
51000
51114
|
`);
|
|
51001
51115
|
}
|
|
51002
51116
|
function collectRunArtifacts(context) {
|
|
51003
|
-
if (!
|
|
51117
|
+
if (!existsSync22(context.exportDir))
|
|
51004
51118
|
return [];
|
|
51005
51119
|
const artifacts = [];
|
|
51006
51120
|
for (const path of walkFiles(context.exportDir)) {
|
|
@@ -51016,8 +51130,8 @@ function collectRunArtifacts(context) {
|
|
|
51016
51130
|
return artifacts.sort((a, b) => a.path.localeCompare(b.path));
|
|
51017
51131
|
}
|
|
51018
51132
|
function readRunRecord(runDir) {
|
|
51019
|
-
const path =
|
|
51020
|
-
if (!
|
|
51133
|
+
const path = join23(runDir, "run.json");
|
|
51134
|
+
if (!existsSync22(path))
|
|
51021
51135
|
return null;
|
|
51022
51136
|
try {
|
|
51023
51137
|
return JSON.parse(readFileSync18(path, "utf-8"));
|
|
@@ -51028,7 +51142,7 @@ function readRunRecord(runDir) {
|
|
|
51028
51142
|
function walkFiles(dir) {
|
|
51029
51143
|
const files = [];
|
|
51030
51144
|
for (const entry of readdirSync12(dir)) {
|
|
51031
|
-
const full =
|
|
51145
|
+
const full = join23(dir, entry);
|
|
51032
51146
|
if (statSync12(full).isDirectory())
|
|
51033
51147
|
files.push(...walkFiles(full));
|
|
51034
51148
|
else
|
|
@@ -56598,12 +56712,12 @@ class StdioServerTransport {
|
|
|
56598
56712
|
this.onclose?.();
|
|
56599
56713
|
}
|
|
56600
56714
|
send(message) {
|
|
56601
|
-
return new Promise((
|
|
56715
|
+
return new Promise((resolve2) => {
|
|
56602
56716
|
const json = serializeMessage(message);
|
|
56603
56717
|
if (this._stdout.write(json)) {
|
|
56604
|
-
|
|
56718
|
+
resolve2();
|
|
56605
56719
|
} else {
|
|
56606
|
-
this._stdout.once("drain",
|
|
56720
|
+
this._stdout.once("drain", resolve2);
|
|
56607
56721
|
}
|
|
56608
56722
|
});
|
|
56609
56723
|
}
|
|
@@ -58778,7 +58892,7 @@ class Protocol {
|
|
|
58778
58892
|
return;
|
|
58779
58893
|
}
|
|
58780
58894
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1000;
|
|
58781
|
-
await new Promise((
|
|
58895
|
+
await new Promise((resolve2) => setTimeout(resolve2, pollInterval));
|
|
58782
58896
|
options?.signal?.throwIfAborted();
|
|
58783
58897
|
}
|
|
58784
58898
|
} catch (error2) {
|
|
@@ -58790,7 +58904,7 @@ class Protocol {
|
|
|
58790
58904
|
}
|
|
58791
58905
|
request(request, resultSchema, options) {
|
|
58792
58906
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
58793
|
-
return new Promise((
|
|
58907
|
+
return new Promise((resolve2, reject2) => {
|
|
58794
58908
|
const earlyReject = (error2) => {
|
|
58795
58909
|
reject2(error2);
|
|
58796
58910
|
};
|
|
@@ -58868,7 +58982,7 @@ class Protocol {
|
|
|
58868
58982
|
if (!parseResult.success) {
|
|
58869
58983
|
reject2(parseResult.error);
|
|
58870
58984
|
} else {
|
|
58871
|
-
|
|
58985
|
+
resolve2(parseResult.data);
|
|
58872
58986
|
}
|
|
58873
58987
|
} catch (error2) {
|
|
58874
58988
|
reject2(error2);
|
|
@@ -59059,12 +59173,12 @@ class Protocol {
|
|
|
59059
59173
|
interval = task.pollInterval;
|
|
59060
59174
|
}
|
|
59061
59175
|
} catch {}
|
|
59062
|
-
return new Promise((
|
|
59176
|
+
return new Promise((resolve2, reject2) => {
|
|
59063
59177
|
if (signal.aborted) {
|
|
59064
59178
|
reject2(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
59065
59179
|
return;
|
|
59066
59180
|
}
|
|
59067
|
-
const timeoutId = setTimeout(
|
|
59181
|
+
const timeoutId = setTimeout(resolve2, interval);
|
|
59068
59182
|
signal.addEventListener("abort", () => {
|
|
59069
59183
|
clearTimeout(timeoutId);
|
|
59070
59184
|
reject2(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -62049,7 +62163,7 @@ var require_compile = __commonJS((exports) => {
|
|
|
62049
62163
|
const schOrFunc = root.refs[ref];
|
|
62050
62164
|
if (schOrFunc)
|
|
62051
62165
|
return schOrFunc;
|
|
62052
|
-
let _sch =
|
|
62166
|
+
let _sch = resolve2.call(this, root, ref);
|
|
62053
62167
|
if (_sch === undefined) {
|
|
62054
62168
|
const schema = (_a = root.localRefs) === null || _a === undefined ? undefined : _a[ref];
|
|
62055
62169
|
const { schemaId } = this.opts;
|
|
@@ -62076,7 +62190,7 @@ var require_compile = __commonJS((exports) => {
|
|
|
62076
62190
|
function sameSchemaEnv(s1, s2) {
|
|
62077
62191
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
62078
62192
|
}
|
|
62079
|
-
function
|
|
62193
|
+
function resolve2(root, ref) {
|
|
62080
62194
|
let sch;
|
|
62081
62195
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
62082
62196
|
ref = sch;
|
|
@@ -62368,8 +62482,8 @@ var require_utils = __commonJS((exports, module) => {
|
|
|
62368
62482
|
var HOST_DELIMS = { "@": "%40", "/": "%2F", "?": "%3F", "#": "%23", ":": "%3A" };
|
|
62369
62483
|
var HOST_DELIM_RE = /[@/?#:]/g;
|
|
62370
62484
|
var HOST_DELIM_NO_COLON_RE = /[@/?#]/g;
|
|
62371
|
-
function reescapeHostDelimiters(host,
|
|
62372
|
-
const re =
|
|
62485
|
+
function reescapeHostDelimiters(host, isIP) {
|
|
62486
|
+
const re = isIP ? HOST_DELIM_NO_COLON_RE : HOST_DELIM_RE;
|
|
62373
62487
|
re.lastIndex = 0;
|
|
62374
62488
|
return host.replace(re, (ch) => HOST_DELIMS[ch]);
|
|
62375
62489
|
}
|
|
@@ -62662,7 +62776,7 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
62662
62776
|
}
|
|
62663
62777
|
return uri;
|
|
62664
62778
|
}
|
|
62665
|
-
function
|
|
62779
|
+
function resolve2(baseURI, relativeURI, options) {
|
|
62666
62780
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
62667
62781
|
const { parsed: baseParsed, malformedAuthorityOrPort: baseMalformed } = parseWithStatus(baseURI, schemelessOptions);
|
|
62668
62782
|
const { parsed: relativeParsed, malformedAuthorityOrPort: relativeMalformed } = parseWithStatus(relativeURI, schemelessOptions);
|
|
@@ -62818,7 +62932,7 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
62818
62932
|
fragment: undefined
|
|
62819
62933
|
};
|
|
62820
62934
|
let malformedAuthorityOrPort = false;
|
|
62821
|
-
let
|
|
62935
|
+
let isIP = false;
|
|
62822
62936
|
if (options.reference === "suffix") {
|
|
62823
62937
|
if (options.scheme) {
|
|
62824
62938
|
uri = options.scheme + ":" + uri;
|
|
@@ -62867,9 +62981,9 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
62867
62981
|
if (ipv4result === false) {
|
|
62868
62982
|
const ipv6result = normalizeIPv6(parsed.host);
|
|
62869
62983
|
parsed.host = ipv6result.host.toLowerCase();
|
|
62870
|
-
|
|
62984
|
+
isIP = ipv6result.isIPV6;
|
|
62871
62985
|
} else {
|
|
62872
|
-
|
|
62986
|
+
isIP = true;
|
|
62873
62987
|
}
|
|
62874
62988
|
}
|
|
62875
62989
|
if (parsed.scheme === undefined && parsed.userinfo === undefined && parsed.host === undefined && parsed.port === undefined && parsed.query === undefined && !parsed.path) {
|
|
@@ -62886,7 +63000,7 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
62886
63000
|
}
|
|
62887
63001
|
const schemeHandler = getSchemeHandler(options.scheme || parsed.scheme);
|
|
62888
63002
|
if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport)) {
|
|
62889
|
-
if (parsed.host && (options.domainHost || schemeHandler && schemeHandler.domainHost) &&
|
|
63003
|
+
if (parsed.host && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP === false && nonSimpleDomain(parsed.host)) {
|
|
62890
63004
|
try {
|
|
62891
63005
|
parsed.host = new URL("http://" + parsed.host).hostname;
|
|
62892
63006
|
} catch (e) {
|
|
@@ -62900,7 +63014,7 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
62900
63014
|
parsed.scheme = unescape(parsed.scheme);
|
|
62901
63015
|
}
|
|
62902
63016
|
if (parsed.host !== undefined) {
|
|
62903
|
-
parsed.host = reescapeHostDelimiters(unescape(parsed.host),
|
|
63017
|
+
parsed.host = reescapeHostDelimiters(unescape(parsed.host), isIP);
|
|
62904
63018
|
}
|
|
62905
63019
|
}
|
|
62906
63020
|
if (parsed.path) {
|
|
@@ -62947,7 +63061,7 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
62947
63061
|
var fastUri = {
|
|
62948
63062
|
SCHEMES,
|
|
62949
63063
|
normalize: normalize3,
|
|
62950
|
-
resolve,
|
|
63064
|
+
resolve: resolve2,
|
|
62951
63065
|
resolveComponent,
|
|
62952
63066
|
equal,
|
|
62953
63067
|
serialize,
|
|
@@ -66733,7 +66847,7 @@ class McpServer {
|
|
|
66733
66847
|
let task = createTaskResult.task;
|
|
66734
66848
|
const pollInterval = task.pollInterval ?? 5000;
|
|
66735
66849
|
while (task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled") {
|
|
66736
|
-
await new Promise((
|
|
66850
|
+
await new Promise((resolve2) => setTimeout(resolve2, pollInterval));
|
|
66737
66851
|
const updatedTask = await extra.taskStore.getTask(taskId);
|
|
66738
66852
|
if (!updatedTask) {
|
|
66739
66853
|
throw new McpError(ErrorCode.InternalError, `Task ${taskId} not found during polling`);
|
|
@@ -68679,8 +68793,8 @@ var init_remote_client = __esm(() => {
|
|
|
68679
68793
|
});
|
|
68680
68794
|
|
|
68681
68795
|
// src/mcp/operation-tools.ts
|
|
68682
|
-
import { existsSync as
|
|
68683
|
-
import { join as
|
|
68796
|
+
import { existsSync as existsSync23, readdirSync as readdirSync13, statSync as statSync13 } from "fs";
|
|
68797
|
+
import { join as join24 } from "path";
|
|
68684
68798
|
function registerOperationTools(server) {
|
|
68685
68799
|
server.registerTool("scaffold_skill", {
|
|
68686
68800
|
title: "Scaffold Skill",
|
|
@@ -69077,12 +69191,12 @@ function registerOperationTools(server) {
|
|
|
69077
69191
|
const agents = [];
|
|
69078
69192
|
for (const agent of AGENT_TARGETS) {
|
|
69079
69193
|
const agentSkillsPath = getAgentSkillsDir(agent, "global");
|
|
69080
|
-
const exists =
|
|
69194
|
+
const exists = existsSync23(agentSkillsPath);
|
|
69081
69195
|
let skillCount = 0;
|
|
69082
69196
|
if (exists) {
|
|
69083
69197
|
try {
|
|
69084
69198
|
skillCount = readdirSync13(agentSkillsPath).filter((f) => {
|
|
69085
|
-
const full =
|
|
69199
|
+
const full = join24(agentSkillsPath, f);
|
|
69086
69200
|
return !f.startsWith(".") && statSync13(full).isDirectory();
|
|
69087
69201
|
}).length;
|
|
69088
69202
|
} catch {}
|
|
@@ -69139,16 +69253,16 @@ var init_operation_tools = __esm(() => {
|
|
|
69139
69253
|
});
|
|
69140
69254
|
|
|
69141
69255
|
// src/lib/feedback.ts
|
|
69142
|
-
import { existsSync as
|
|
69143
|
-
import { dirname as dirname7, join as
|
|
69256
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync10 } from "fs";
|
|
69257
|
+
import { dirname as dirname7, join as join25 } from "path";
|
|
69144
69258
|
import { Database } from "bun:sqlite";
|
|
69145
69259
|
function getFeedbackDbPath() {
|
|
69146
|
-
return
|
|
69260
|
+
return join25(getDataDir(), "skills.db");
|
|
69147
69261
|
}
|
|
69148
69262
|
function getFeedbackDb() {
|
|
69149
69263
|
const dbPath = getFeedbackDbPath();
|
|
69150
69264
|
const dir = dirname7(dbPath);
|
|
69151
|
-
if (!
|
|
69265
|
+
if (!existsSync24(dir))
|
|
69152
69266
|
mkdirSync10(dir, { recursive: true });
|
|
69153
69267
|
const db = new Database(dbPath);
|
|
69154
69268
|
db.exec("PRAGMA journal_mode = WAL");
|
|
@@ -69322,14 +69436,14 @@ var init_resource_meta_tools = __esm(() => {
|
|
|
69322
69436
|
});
|
|
69323
69437
|
|
|
69324
69438
|
// src/lib/scheduler.ts
|
|
69325
|
-
import { existsSync as
|
|
69326
|
-
import { join as
|
|
69439
|
+
import { existsSync as existsSync25, readFileSync as readFileSync19, writeFileSync as writeFileSync12, mkdirSync as mkdirSync11 } from "fs";
|
|
69440
|
+
import { join as join26 } from "path";
|
|
69327
69441
|
function getSchedulesPath(targetDir = process.cwd()) {
|
|
69328
|
-
return
|
|
69442
|
+
return join26(targetDir, ".skills", "schedules.json");
|
|
69329
69443
|
}
|
|
69330
69444
|
function loadSchedules(targetDir = process.cwd()) {
|
|
69331
69445
|
const path = getSchedulesPath(targetDir);
|
|
69332
|
-
if (
|
|
69446
|
+
if (existsSync25(path)) {
|
|
69333
69447
|
try {
|
|
69334
69448
|
return JSON.parse(readFileSync19(path, "utf-8"));
|
|
69335
69449
|
} catch {}
|
|
@@ -69338,8 +69452,8 @@ function loadSchedules(targetDir = process.cwd()) {
|
|
|
69338
69452
|
}
|
|
69339
69453
|
function saveSchedules(data, targetDir = process.cwd()) {
|
|
69340
69454
|
const path = getSchedulesPath(targetDir);
|
|
69341
|
-
const dir =
|
|
69342
|
-
if (!
|
|
69455
|
+
const dir = join26(targetDir, ".skills");
|
|
69456
|
+
if (!existsSync25(dir))
|
|
69343
69457
|
mkdirSync11(dir, { recursive: true });
|
|
69344
69458
|
writeFileSync12(path, JSON.stringify(data, null, 2));
|
|
69345
69459
|
}
|
|
@@ -69639,14 +69753,14 @@ var init_schedule_tools = __esm(() => {
|
|
|
69639
69753
|
// src/lib/native-storage.ts
|
|
69640
69754
|
import { createHash as createHash3, createHmac as createHmac2 } from "crypto";
|
|
69641
69755
|
import {
|
|
69642
|
-
existsSync as
|
|
69756
|
+
existsSync as existsSync26,
|
|
69643
69757
|
mkdirSync as mkdirSync12,
|
|
69644
69758
|
readFileSync as readFileSync20,
|
|
69645
69759
|
readdirSync as readdirSync14,
|
|
69646
69760
|
statSync as statSync14,
|
|
69647
69761
|
writeFileSync as writeFileSync13
|
|
69648
69762
|
} from "fs";
|
|
69649
|
-
import { dirname as dirname8, join as
|
|
69763
|
+
import { dirname as dirname8, join as join27, normalize as normalize3, relative as relative3, sep as sep2 } from "path";
|
|
69650
69764
|
function resolveSkillsNativeStorageConfig(env3 = process.env) {
|
|
69651
69765
|
assertNoRetiredModeEnvVars(env3, {
|
|
69652
69766
|
app: SKILLS_ENV_NAMESPACE,
|
|
@@ -69687,7 +69801,7 @@ function getSkillsNativeStorageStatus(options = {}) {
|
|
|
69687
69801
|
local: {
|
|
69688
69802
|
dataDir: getDataDir(),
|
|
69689
69803
|
projectStateDir: getProjectStateDir(targetDir),
|
|
69690
|
-
feedbackDbPath:
|
|
69804
|
+
feedbackDbPath: join27(getDataDir(), "skills.db")
|
|
69691
69805
|
},
|
|
69692
69806
|
remote: {
|
|
69693
69807
|
databaseConfigured: Boolean(config2.databaseUrl),
|
|
@@ -69707,7 +69821,7 @@ function getStorageStatus(options = {}) {
|
|
|
69707
69821
|
function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
|
|
69708
69822
|
const projectStateDir = getProjectStateDir(targetDir);
|
|
69709
69823
|
const files = [];
|
|
69710
|
-
if (
|
|
69824
|
+
if (existsSync26(projectStateDir)) {
|
|
69711
69825
|
for (const filePath of walkFiles2(projectStateDir)) {
|
|
69712
69826
|
const bytes = readFileSync20(filePath);
|
|
69713
69827
|
const relativePath = toPosix(relative3(targetDir, filePath));
|
|
@@ -69768,7 +69882,7 @@ function parsePositiveInteger(value) {
|
|
|
69768
69882
|
function walkFiles2(dir) {
|
|
69769
69883
|
const files = [];
|
|
69770
69884
|
for (const entry of readdirSync14(dir)) {
|
|
69771
|
-
const full =
|
|
69885
|
+
const full = join27(dir, entry);
|
|
69772
69886
|
const stats = statSync14(full);
|
|
69773
69887
|
if (stats.isDirectory())
|
|
69774
69888
|
files.push(...walkFiles2(full));
|
|
@@ -69976,7 +70090,7 @@ var GlobalRequest, Request, newHeadersFromIncoming = (incoming) => {
|
|
|
69976
70090
|
}
|
|
69977
70091
|
return new Request(url, init);
|
|
69978
70092
|
}, getRequestCache, requestCache, incomingKey, urlKey, headersKey, abortControllerKey, getAbortController, requestPrototype, responseCache, getResponseCache, cacheKey, GlobalResponse, Response2, outgoingEnded, incomingDraining, MAX_DRAIN_BYTES;
|
|
69979
|
-
var
|
|
70093
|
+
var init_dist2 = __esm(() => {
|
|
69980
70094
|
GlobalRequest = global.Request;
|
|
69981
70095
|
Request = class extends GlobalRequest {
|
|
69982
70096
|
constructor(input, options) {
|
|
@@ -70266,7 +70380,7 @@ var init_webStandardStreamableHttp = __esm(() => {
|
|
|
70266
70380
|
|
|
70267
70381
|
// ../../node_modules/.bun/@modelcontextprotocol+sdk@1.30.0/node_modules/@modelcontextprotocol/sdk/dist/esm/server/streamableHttp.js
|
|
70268
70382
|
var init_streamableHttp = __esm(() => {
|
|
70269
|
-
|
|
70383
|
+
init_dist2();
|
|
70270
70384
|
init_webStandardStreamableHttp();
|
|
70271
70385
|
});
|
|
70272
70386
|
|
|
@@ -70317,9 +70431,9 @@ var init_mcp2 = __esm(() => {
|
|
|
70317
70431
|
});
|
|
70318
70432
|
|
|
70319
70433
|
// src/cli/commands/runtime-mcp.ts
|
|
70320
|
-
import { existsSync as
|
|
70321
|
-
import { homedir as
|
|
70322
|
-
import { dirname as dirname9, join as
|
|
70434
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync13, readFileSync as readFileSync21, writeFileSync as writeFileSync14 } from "fs";
|
|
70435
|
+
import { homedir as homedir10 } from "os";
|
|
70436
|
+
import { dirname as dirname9, join as join28 } from "path";
|
|
70323
70437
|
async function handleMcp(options) {
|
|
70324
70438
|
if (options.register) {
|
|
70325
70439
|
let agents;
|
|
@@ -70362,24 +70476,24 @@ async function registerMcpForAgent(agent, command) {
|
|
|
70362
70476
|
case "codex":
|
|
70363
70477
|
return registerCodexMcp(command);
|
|
70364
70478
|
case "gemini":
|
|
70365
|
-
return registerJsonMcpServer(agent,
|
|
70479
|
+
return registerJsonMcpServer(agent, join28(homedir10(), ".gemini", "settings.json"), "mcpServers", {
|
|
70366
70480
|
command,
|
|
70367
70481
|
args: []
|
|
70368
70482
|
});
|
|
70369
70483
|
case "pi":
|
|
70370
|
-
return registerJsonMcpServer(agent,
|
|
70484
|
+
return registerJsonMcpServer(agent, join28(homedir10(), ".pi", "agent", "mcp.json"), "mcpServers", {
|
|
70371
70485
|
command,
|
|
70372
70486
|
args: []
|
|
70373
70487
|
});
|
|
70374
70488
|
case "opencode":
|
|
70375
70489
|
return registerOpenCodeMcp(command);
|
|
70376
70490
|
case "cursor":
|
|
70377
|
-
return registerJsonMcpServer(agent,
|
|
70491
|
+
return registerJsonMcpServer(agent, join28(homedir10(), ".cursor", "mcp.json"), "mcpServers", {
|
|
70378
70492
|
command,
|
|
70379
70493
|
args: []
|
|
70380
70494
|
});
|
|
70381
70495
|
case "windsurf":
|
|
70382
|
-
return registerJsonMcpServer(agent,
|
|
70496
|
+
return registerJsonMcpServer(agent, join28(homedir10(), ".windsurf", "mcp.json"), "mcpServers", {
|
|
70383
70497
|
command,
|
|
70384
70498
|
args: []
|
|
70385
70499
|
});
|
|
@@ -70402,7 +70516,7 @@ async function registerClaudeMcp(command) {
|
|
|
70402
70516
|
if (exitCode === 0) {
|
|
70403
70517
|
return { agent: "claude", success: true, command: cliCommand };
|
|
70404
70518
|
}
|
|
70405
|
-
const fallback = registerJsonMcpServer("claude",
|
|
70519
|
+
const fallback = registerJsonMcpServer("claude", join28(homedir10(), ".claude", ".mcp.json"), "mcpServers", {
|
|
70406
70520
|
command,
|
|
70407
70521
|
args: []
|
|
70408
70522
|
});
|
|
@@ -70412,7 +70526,7 @@ async function registerClaudeMcp(command) {
|
|
|
70412
70526
|
error: fallback.success ? undefined : `claude exited with ${exitCode}: ${(stderr || stdout).trim()}`
|
|
70413
70527
|
};
|
|
70414
70528
|
} catch (err) {
|
|
70415
|
-
const fallback = registerJsonMcpServer("claude",
|
|
70529
|
+
const fallback = registerJsonMcpServer("claude", join28(homedir10(), ".claude", ".mcp.json"), "mcpServers", {
|
|
70416
70530
|
command,
|
|
70417
70531
|
args: []
|
|
70418
70532
|
});
|
|
@@ -70424,11 +70538,11 @@ async function registerClaudeMcp(command) {
|
|
|
70424
70538
|
}
|
|
70425
70539
|
}
|
|
70426
70540
|
function registerCodexMcp(command) {
|
|
70427
|
-
const path =
|
|
70541
|
+
const path = join28(homedir10(), ".codex", "config.toml");
|
|
70428
70542
|
const config2 = `[mcp_servers.${MCP_SERVER_NAME}]
|
|
70429
70543
|
command = ${JSON.stringify(command)}`;
|
|
70430
70544
|
try {
|
|
70431
|
-
const current =
|
|
70545
|
+
const current = existsSync27(path) ? readFileSync21(path, "utf-8") : "";
|
|
70432
70546
|
writeTextFile(path, upsertTomlSection(current, `[mcp_servers.${MCP_SERVER_NAME}]`, `command = ${JSON.stringify(command)}`));
|
|
70433
70547
|
return { agent: "codex", success: true, path, config: config2 };
|
|
70434
70548
|
} catch (err) {
|
|
@@ -70436,7 +70550,7 @@ command = ${JSON.stringify(command)}`;
|
|
|
70436
70550
|
}
|
|
70437
70551
|
}
|
|
70438
70552
|
function registerOpenCodeMcp(command) {
|
|
70439
|
-
const path =
|
|
70553
|
+
const path = join28(homedir10(), ".config", "opencode", "opencode.json");
|
|
70440
70554
|
const config2 = JSON.stringify({
|
|
70441
70555
|
$schema: "https://opencode.ai/config.json",
|
|
70442
70556
|
mcp: {
|
|
@@ -70478,7 +70592,7 @@ function registerJsonMcpServer(agent, path, containerKey, server2) {
|
|
|
70478
70592
|
}
|
|
70479
70593
|
}
|
|
70480
70594
|
function readJsonObject2(path) {
|
|
70481
|
-
if (!
|
|
70595
|
+
if (!existsSync27(path))
|
|
70482
70596
|
return {};
|
|
70483
70597
|
const raw = readFileSync21(path, "utf-8").trim();
|
|
70484
70598
|
if (!raw)
|
|
@@ -70524,8 +70638,8 @@ function findCommandOnPath(command) {
|
|
|
70524
70638
|
for (const dir of pathValue.split(":")) {
|
|
70525
70639
|
if (!dir)
|
|
70526
70640
|
continue;
|
|
70527
|
-
const candidate =
|
|
70528
|
-
if (
|
|
70641
|
+
const candidate = join28(dir, command);
|
|
70642
|
+
if (existsSync27(candidate))
|
|
70529
70643
|
return candidate;
|
|
70530
70644
|
}
|
|
70531
70645
|
return command;
|
|
@@ -70545,7 +70659,7 @@ __export(exports_runtime, {
|
|
|
70545
70659
|
registerRuntime: () => registerRuntime
|
|
70546
70660
|
});
|
|
70547
70661
|
import { mkdirSync as mkdirSync14, writeFileSync as writeFileSync15 } from "fs";
|
|
70548
|
-
import { dirname as dirname10, join as
|
|
70662
|
+
import { dirname as dirname10, join as join29 } from "path";
|
|
70549
70663
|
import { createInterface } from "readline";
|
|
70550
70664
|
function registerRuntime(parent) {
|
|
70551
70665
|
parent.command("run").argument("<skill>", "Skill name").argument("[args...]", "Arguments to pass to the skill").allowUnknownOption(true).passThroughOptions(true).option("--json", "Output result as JSON", false).option("--wait", "Poll remote runs until a terminal status", false).option("--poll-interval-ms <ms>", "Remote polling interval in milliseconds", "1000").option("--poll-timeout-ms <ms>", "Maximum time to wait for a remote run", "300000").description("Run a skill directly").action(async (name, args2, options) => handleRun(name, args2, options));
|
|
@@ -70670,10 +70784,10 @@ async function handleSetup(options) {
|
|
|
70670
70784
|
}
|
|
70671
70785
|
function promptLine(question) {
|
|
70672
70786
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
70673
|
-
return new Promise((
|
|
70787
|
+
return new Promise((resolve2) => {
|
|
70674
70788
|
rl.question(source_default.bold(question), (answer) => {
|
|
70675
70789
|
rl.close();
|
|
70676
|
-
|
|
70790
|
+
resolve2(answer.trim());
|
|
70677
70791
|
});
|
|
70678
70792
|
});
|
|
70679
70793
|
}
|
|
@@ -71034,7 +71148,7 @@ async function handleExportsDownload(runId, options) {
|
|
|
71034
71148
|
if (!response.ok)
|
|
71035
71149
|
throw new Error(`download failed for artifact ${artifactId}: ${response.status}`);
|
|
71036
71150
|
const relativePath = safeArtifactRelativePath(typeof artifact.relativePath === "string" ? artifact.relativePath : artifact.fileName, String(artifact.fileName || artifactId));
|
|
71037
|
-
const outputPath =
|
|
71151
|
+
const outputPath = join29(exportDir, relativePath);
|
|
71038
71152
|
mkdirSync14(dirname10(outputPath), { recursive: true });
|
|
71039
71153
|
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
71040
71154
|
writeFileSync15(outputPath, bytes);
|
|
@@ -71094,7 +71208,7 @@ async function pollRemoteRun(client, runId, options) {
|
|
|
71094
71208
|
const remaining = deadline - Date.now();
|
|
71095
71209
|
if (remaining <= 0)
|
|
71096
71210
|
break;
|
|
71097
|
-
await new Promise((
|
|
71211
|
+
await new Promise((resolve2) => setTimeout(resolve2, Math.min(options.intervalMs, remaining)));
|
|
71098
71212
|
}
|
|
71099
71213
|
return {
|
|
71100
71214
|
run: current ?? { id: runId, status: "queued" },
|
|
@@ -71395,13 +71509,345 @@ var init_completion = __esm(() => {
|
|
|
71395
71509
|
categoryNames = CATEGORIES.map((c) => c);
|
|
71396
71510
|
});
|
|
71397
71511
|
|
|
71512
|
+
// src/lib/portable-snapshot-filter.ts
|
|
71513
|
+
import { readdirSync as readdirSync15, statSync as statSync15 } from "fs";
|
|
71514
|
+
import { homedir as homedir11 } from "os";
|
|
71515
|
+
import { join as join30, sep as sep3 } from "path";
|
|
71516
|
+
function isExcludedSkillFileName(fileName) {
|
|
71517
|
+
if (EXCLUDE_FILE_NAMES.has(fileName)) {
|
|
71518
|
+
return true;
|
|
71519
|
+
}
|
|
71520
|
+
return EXCLUDE_FILE_PATTERNS.some((pattern) => pattern.test(fileName));
|
|
71521
|
+
}
|
|
71522
|
+
function isPortableWithinSkill(relativeParts) {
|
|
71523
|
+
if (relativeParts.length < 2) {
|
|
71524
|
+
return false;
|
|
71525
|
+
}
|
|
71526
|
+
const [, second] = relativeParts;
|
|
71527
|
+
if (PORTABLE_TOP_LEVEL.has(second)) {
|
|
71528
|
+
return relativeParts.length === 2;
|
|
71529
|
+
}
|
|
71530
|
+
if (relativeParts.length < 3) {
|
|
71531
|
+
return false;
|
|
71532
|
+
}
|
|
71533
|
+
return PORTABLE_SUBDIRS.has(second);
|
|
71534
|
+
}
|
|
71535
|
+
function homePathFor(definition, homesRoot) {
|
|
71536
|
+
const home = homesRoot ?? homedir11();
|
|
71537
|
+
if (definition.subClass === "skills" || definition.subClass === "custom") {
|
|
71538
|
+
return join30(skillsDataRootForHome(home), definition.name);
|
|
71539
|
+
}
|
|
71540
|
+
if (definition.agent === "opencode") {
|
|
71541
|
+
return join30(home, ".config", "opencode", "skills");
|
|
71542
|
+
}
|
|
71543
|
+
return join30(home, `.${definition.agent}`, "skills");
|
|
71544
|
+
}
|
|
71545
|
+
function destinationFor(definition, stationId, relativePath) {
|
|
71546
|
+
const category = definition.subClass === "agent-homes" ? join30("agent-homes", definition.agent ?? "") : definition.name;
|
|
71547
|
+
return join30("resources", stationId, "skills", category, ...relativePath.split(sep3));
|
|
71548
|
+
}
|
|
71549
|
+
function walkEntries(absoluteRoot) {
|
|
71550
|
+
let entries;
|
|
71551
|
+
try {
|
|
71552
|
+
entries = readdirSync15(absoluteRoot, { withFileTypes: true });
|
|
71553
|
+
} catch {
|
|
71554
|
+
return [];
|
|
71555
|
+
}
|
|
71556
|
+
const output = [];
|
|
71557
|
+
for (const entry of entries) {
|
|
71558
|
+
const childFull = join30(absoluteRoot, entry.name);
|
|
71559
|
+
if (entry.isSymbolicLink()) {
|
|
71560
|
+
output.push({ kind: "symlink", relativePath: entry.name, fullPath: childFull });
|
|
71561
|
+
continue;
|
|
71562
|
+
}
|
|
71563
|
+
if (entry.isDirectory()) {
|
|
71564
|
+
if (EXCLUDE_DIR_NAMES.has(entry.name) || EXCLUDE_DIR_PATTERNS.some((pattern) => pattern.test(entry.name))) {
|
|
71565
|
+
continue;
|
|
71566
|
+
}
|
|
71567
|
+
const nested = walkEntries(childFull);
|
|
71568
|
+
for (const item of nested) {
|
|
71569
|
+
output.push({ ...item, relativePath: join30(entry.name, item.relativePath) });
|
|
71570
|
+
}
|
|
71571
|
+
continue;
|
|
71572
|
+
}
|
|
71573
|
+
if (entry.isFile()) {
|
|
71574
|
+
output.push({ kind: "file", relativePath: entry.name, fullPath: childFull });
|
|
71575
|
+
}
|
|
71576
|
+
}
|
|
71577
|
+
return output;
|
|
71578
|
+
}
|
|
71579
|
+
function isRegularFile(filePath) {
|
|
71580
|
+
try {
|
|
71581
|
+
return statSync15(filePath).isFile();
|
|
71582
|
+
} catch {
|
|
71583
|
+
return false;
|
|
71584
|
+
}
|
|
71585
|
+
}
|
|
71586
|
+
var SYNC_HOMES, EXCLUDE_DIR_NAMES, EXCLUDE_DIR_PATTERNS, EXCLUDE_FILE_NAMES, EXCLUDE_FILE_PATTERNS, PORTABLE_TOP_LEVEL, PORTABLE_SUBDIRS, REFUSED_SCANNER_FLAGGED;
|
|
71587
|
+
var init_portable_snapshot_filter = __esm(() => {
|
|
71588
|
+
init_app_home();
|
|
71589
|
+
SYNC_HOMES = [
|
|
71590
|
+
{ name: "skills", subClass: "skills", agent: null },
|
|
71591
|
+
{ name: "custom", subClass: "custom", agent: null },
|
|
71592
|
+
{ name: "claude", subClass: "agent-homes", agent: "claude" },
|
|
71593
|
+
{ name: "codewith", subClass: "agent-homes", agent: "codewith" },
|
|
71594
|
+
{ name: "codex", subClass: "agent-homes", agent: "codex" },
|
|
71595
|
+
{ name: "opencode", subClass: "agent-homes", agent: "opencode" },
|
|
71596
|
+
{ name: "cursor", subClass: "agent-homes", agent: "cursor" }
|
|
71597
|
+
];
|
|
71598
|
+
EXCLUDE_DIR_NAMES = new Set([
|
|
71599
|
+
".git",
|
|
71600
|
+
"node_modules",
|
|
71601
|
+
"__pycache__",
|
|
71602
|
+
".cache",
|
|
71603
|
+
".pytest_cache",
|
|
71604
|
+
".mypy_cache",
|
|
71605
|
+
".ruff_cache"
|
|
71606
|
+
]);
|
|
71607
|
+
EXCLUDE_DIR_PATTERNS = [
|
|
71608
|
+
/^\.merge-pr\.rollback-/
|
|
71609
|
+
];
|
|
71610
|
+
EXCLUDE_FILE_NAMES = new Set([
|
|
71611
|
+
".DS_Store",
|
|
71612
|
+
"package-lock.json",
|
|
71613
|
+
"pnpm-lock.yaml",
|
|
71614
|
+
"yarn.lock",
|
|
71615
|
+
"Cargo.lock"
|
|
71616
|
+
]);
|
|
71617
|
+
EXCLUDE_FILE_PATTERNS = [
|
|
71618
|
+
/^\._/,
|
|
71619
|
+
/\.bak$/,
|
|
71620
|
+
/\.orig$/,
|
|
71621
|
+
/\.rej$/,
|
|
71622
|
+
/~$/,
|
|
71623
|
+
/\.pyc$/,
|
|
71624
|
+
/\.pyo$/,
|
|
71625
|
+
/\.log$/,
|
|
71626
|
+
/\.db$/,
|
|
71627
|
+
/\.sqlite(\d)?$/,
|
|
71628
|
+
/^bun\.lock/,
|
|
71629
|
+
/\.env($|\.)/,
|
|
71630
|
+
/\.pem$/,
|
|
71631
|
+
/\.key$/,
|
|
71632
|
+
/\.p12$/,
|
|
71633
|
+
/\.pfx$/,
|
|
71634
|
+
/\.jks$/,
|
|
71635
|
+
/^id_rsa/,
|
|
71636
|
+
/^id_ed25519/,
|
|
71637
|
+
/^credentials/
|
|
71638
|
+
];
|
|
71639
|
+
PORTABLE_TOP_LEVEL = new Set(["SKILL.md", "skill.json"]);
|
|
71640
|
+
PORTABLE_SUBDIRS = new Set(["scripts", "assets", "references"]);
|
|
71641
|
+
REFUSED_SCANNER_FLAGGED = new Set([
|
|
71642
|
+
"aws-cross-account-app-migration/SKILL.md",
|
|
71643
|
+
"aws-cross-account-app-migration/scripts/selftest.sh",
|
|
71644
|
+
"gateway-serve/SKILL.md",
|
|
71645
|
+
"infinity-drain/SKILL.md",
|
|
71646
|
+
"infinity-run/SKILL.md",
|
|
71647
|
+
"oss-saas-code-cleanup/SKILL.md",
|
|
71648
|
+
"repo-project-familiarization/scripts/repo_shape.py",
|
|
71649
|
+
"repo-project-familiarization/scripts/session_history.py",
|
|
71650
|
+
"scale-check/SKILL.md",
|
|
71651
|
+
"standard-align-repo/SKILL.md",
|
|
71652
|
+
"standard-build-iapp/SKILL.md",
|
|
71653
|
+
"standard-build-oss/SKILL.md",
|
|
71654
|
+
"skill-image/SKILL.md",
|
|
71655
|
+
"skill-scale-check/SKILL.md",
|
|
71656
|
+
"sqlite-to-rds-parity-migrate/scripts/parity-migrate.ts",
|
|
71657
|
+
"pdf-operations/scripts/pdf_ops.py"
|
|
71658
|
+
]);
|
|
71659
|
+
});
|
|
71660
|
+
|
|
71661
|
+
// src/lib/station-snapshot.ts
|
|
71662
|
+
import { createHash as createHash4 } from "crypto";
|
|
71663
|
+
import {
|
|
71664
|
+
copyFileSync as copyFileSync2,
|
|
71665
|
+
mkdirSync as mkdirSync15,
|
|
71666
|
+
readFileSync as readFileSync22,
|
|
71667
|
+
statSync as statSync16,
|
|
71668
|
+
writeFileSync as writeFileSync16
|
|
71669
|
+
} from "fs";
|
|
71670
|
+
import { dirname as dirname11, isAbsolute as isAbsolute3, relative as relative4, resolve as resolve2, sep as sep4 } from "path";
|
|
71671
|
+
function validateStationId(stationId) {
|
|
71672
|
+
if (!/^[a-z0-9-]+$/.test(stationId)) {
|
|
71673
|
+
throw new StationSnapshotError("INVALID_STATION", `station id must be a slug, got: ${stationId}`);
|
|
71674
|
+
}
|
|
71675
|
+
}
|
|
71676
|
+
function sha256File(filePath) {
|
|
71677
|
+
return createHash4("sha256").update(readFileSync22(filePath)).digest("hex");
|
|
71678
|
+
}
|
|
71679
|
+
function scanHome(definition, homesRoot) {
|
|
71680
|
+
const homePath = homePathFor(definition, homesRoot);
|
|
71681
|
+
const entries = walkEntries(homePath);
|
|
71682
|
+
const portable = [];
|
|
71683
|
+
const skipped = [];
|
|
71684
|
+
for (const entry of entries) {
|
|
71685
|
+
const relativeParts = entry.relativePath.split(sep4);
|
|
71686
|
+
const fileName = relativeParts[relativeParts.length - 1];
|
|
71687
|
+
if (entry.kind === "symlink") {
|
|
71688
|
+
skipped.push({ relativePath: entry.relativePath, reason: "symlink" });
|
|
71689
|
+
continue;
|
|
71690
|
+
}
|
|
71691
|
+
if (!isPortableWithinSkill(relativeParts)) {
|
|
71692
|
+
skipped.push({ relativePath: entry.relativePath, reason: "not-portable" });
|
|
71693
|
+
continue;
|
|
71694
|
+
}
|
|
71695
|
+
if (isExcludedSkillFileName(fileName)) {
|
|
71696
|
+
skipped.push({ relativePath: entry.relativePath, reason: "excluded" });
|
|
71697
|
+
continue;
|
|
71698
|
+
}
|
|
71699
|
+
if (REFUSED_SCANNER_FLAGGED.has(entry.relativePath)) {
|
|
71700
|
+
skipped.push({ relativePath: entry.relativePath, reason: "refused-scanner-flagged" });
|
|
71701
|
+
continue;
|
|
71702
|
+
}
|
|
71703
|
+
if (!isRegularFile(entry.fullPath)) {
|
|
71704
|
+
skipped.push({ relativePath: entry.relativePath, reason: "not-regular-file" });
|
|
71705
|
+
continue;
|
|
71706
|
+
}
|
|
71707
|
+
const info = statSync16(entry.fullPath);
|
|
71708
|
+
portable.push({
|
|
71709
|
+
relativePath: entry.relativePath,
|
|
71710
|
+
fullPath: entry.fullPath,
|
|
71711
|
+
size: info.size,
|
|
71712
|
+
mtimeMs: info.mtimeMs,
|
|
71713
|
+
mtimeIso: info.mtime.toISOString()
|
|
71714
|
+
});
|
|
71715
|
+
}
|
|
71716
|
+
return { definition, homePath, portable, skipped };
|
|
71717
|
+
}
|
|
71718
|
+
function planStationSnapshot(options) {
|
|
71719
|
+
validateStationId(options.stationId);
|
|
71720
|
+
const scanned = SYNC_HOMES.map((definition) => scanHome(definition, options.homesRoot));
|
|
71721
|
+
const symlinks = scanned.reduce((sum2, item) => sum2 + item.skipped.filter((entry) => entry.reason === "symlink").length, 0);
|
|
71722
|
+
if (symlinks > 0) {
|
|
71723
|
+
throw new StationSnapshotError("SYMLINKS_REFUSED", `${symlinks} symlink(s) inside skill homes; symlinks are refused (fail closed)`);
|
|
71724
|
+
}
|
|
71725
|
+
const plans = [];
|
|
71726
|
+
for (const item of scanned) {
|
|
71727
|
+
for (const file of item.portable) {
|
|
71728
|
+
plans.push({
|
|
71729
|
+
definition: item.definition,
|
|
71730
|
+
source: file,
|
|
71731
|
+
destination: destinationFor(item.definition, options.stationId, file.relativePath),
|
|
71732
|
+
digest: sha256File(file.fullPath)
|
|
71733
|
+
});
|
|
71734
|
+
}
|
|
71735
|
+
}
|
|
71736
|
+
const totalBytes = plans.reduce((sum2, plan) => sum2 + plan.source.size, 0);
|
|
71737
|
+
return { scanned, plans, totalBytes };
|
|
71738
|
+
}
|
|
71739
|
+
function humanHomes(scanned) {
|
|
71740
|
+
return scanned.map((item) => ({
|
|
71741
|
+
name: item.definition.name,
|
|
71742
|
+
homePath: item.homePath,
|
|
71743
|
+
files: item.portable.length,
|
|
71744
|
+
skipped: item.skipped.length
|
|
71745
|
+
}));
|
|
71746
|
+
}
|
|
71747
|
+
function writeStationSnapshot(options) {
|
|
71748
|
+
const repoRoot = resolve2(options.repoRoot ?? process.cwd());
|
|
71749
|
+
const { scanned, plans, totalBytes } = planStationSnapshot(options);
|
|
71750
|
+
const manifestFiles = plans.map((plan) => ({
|
|
71751
|
+
relativePath: plan.source.relativePath,
|
|
71752
|
+
destination: plan.destination,
|
|
71753
|
+
subClass: plan.definition.subClass,
|
|
71754
|
+
agent: plan.definition.agent,
|
|
71755
|
+
sha256: plan.digest,
|
|
71756
|
+
sourceMtimeMs: plan.source.mtimeMs,
|
|
71757
|
+
sourceMtimeIso: plan.source.mtimeIso,
|
|
71758
|
+
size: plan.source.size
|
|
71759
|
+
}));
|
|
71760
|
+
const base2 = {
|
|
71761
|
+
stationId: options.stationId,
|
|
71762
|
+
mode: "dry-run",
|
|
71763
|
+
repoRoot,
|
|
71764
|
+
stats: { files: plans.length, bytes: totalBytes },
|
|
71765
|
+
homes: humanHomes(scanned),
|
|
71766
|
+
files: manifestFiles
|
|
71767
|
+
};
|
|
71768
|
+
if (options.dryRun !== false) {
|
|
71769
|
+
return base2;
|
|
71770
|
+
}
|
|
71771
|
+
const conflicts = [];
|
|
71772
|
+
const untouched = [];
|
|
71773
|
+
for (const plan of plans) {
|
|
71774
|
+
const destination = resolve2(repoRoot, plan.destination);
|
|
71775
|
+
const destinationRelative = relative4(repoRoot, destination);
|
|
71776
|
+
if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep4) || isAbsolute3(destinationRelative)) {
|
|
71777
|
+
throw new StationSnapshotError("DESTINATION_ESCAPE", `destination escapes repo root: ${plan.destination}`);
|
|
71778
|
+
}
|
|
71779
|
+
let existingDigest = null;
|
|
71780
|
+
try {
|
|
71781
|
+
existingDigest = sha256File(destination);
|
|
71782
|
+
} catch {}
|
|
71783
|
+
if (existingDigest !== null) {
|
|
71784
|
+
if (existingDigest === plan.digest) {
|
|
71785
|
+
continue;
|
|
71786
|
+
}
|
|
71787
|
+
conflicts.push(`existing destination differs from staged source: ${plan.destination}`);
|
|
71788
|
+
continue;
|
|
71789
|
+
}
|
|
71790
|
+
untouched.push(plan);
|
|
71791
|
+
}
|
|
71792
|
+
if (conflicts.length > 0) {
|
|
71793
|
+
throw new StationSnapshotError("CONFLICT", `${conflicts.length} conflict(s); terminal non-acceptance, nothing written`, conflicts);
|
|
71794
|
+
}
|
|
71795
|
+
let written = 0;
|
|
71796
|
+
for (const plan of untouched) {
|
|
71797
|
+
const destination = resolve2(repoRoot, plan.destination);
|
|
71798
|
+
mkdirSync15(dirname11(destination), { recursive: true });
|
|
71799
|
+
copyFileSync2(plan.source.fullPath, destination);
|
|
71800
|
+
written += 1;
|
|
71801
|
+
}
|
|
71802
|
+
const unchanged = plans.length - untouched.length;
|
|
71803
|
+
const manifest = {
|
|
71804
|
+
schema: STATION_SYNC_MANIFEST_SCHEMA,
|
|
71805
|
+
stationId: options.stationId,
|
|
71806
|
+
syncedAt: new Date().toISOString(),
|
|
71807
|
+
producer: STATION_SNAPSHOT_PRODUCER,
|
|
71808
|
+
stats: {
|
|
71809
|
+
written,
|
|
71810
|
+
unchanged,
|
|
71811
|
+
files: plans.length,
|
|
71812
|
+
bytes: totalBytes
|
|
71813
|
+
},
|
|
71814
|
+
files: manifestFiles
|
|
71815
|
+
};
|
|
71816
|
+
const manifestPath = resolve2(repoRoot, "resources", options.stationId, "skills", "sync-manifest.json");
|
|
71817
|
+
mkdirSync15(dirname11(manifestPath), { recursive: true });
|
|
71818
|
+
writeFileSync16(manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
71819
|
+
`);
|
|
71820
|
+
return {
|
|
71821
|
+
...base2,
|
|
71822
|
+
mode: "populate",
|
|
71823
|
+
stats: { files: plans.length, bytes: totalBytes, written, unchanged },
|
|
71824
|
+
manifestPath
|
|
71825
|
+
};
|
|
71826
|
+
}
|
|
71827
|
+
var STATION_SYNC_MANIFEST_SCHEMA = "hasna.fleet-resources.skills-sync-manifest/v1", STATION_SNAPSHOT_PRODUCER, StationSnapshotError;
|
|
71828
|
+
var init_station_snapshot = __esm(() => {
|
|
71829
|
+
init_package();
|
|
71830
|
+
init_portable_snapshot_filter();
|
|
71831
|
+
STATION_SNAPSHOT_PRODUCER = { name: "@hasna/skills", version: package_default.version };
|
|
71832
|
+
StationSnapshotError = class StationSnapshotError extends Error {
|
|
71833
|
+
code;
|
|
71834
|
+
detail;
|
|
71835
|
+
constructor(code, message, detail = []) {
|
|
71836
|
+
super(message);
|
|
71837
|
+
this.name = "StationSnapshotError";
|
|
71838
|
+
this.code = code;
|
|
71839
|
+
this.detail = detail;
|
|
71840
|
+
}
|
|
71841
|
+
};
|
|
71842
|
+
});
|
|
71843
|
+
|
|
71398
71844
|
// src/cli/commands/create-sync-config.ts
|
|
71399
71845
|
var exports_create_sync_config = {};
|
|
71400
71846
|
__export(exports_create_sync_config, {
|
|
71401
71847
|
registerCreateSync: () => registerCreateSync
|
|
71402
71848
|
});
|
|
71403
|
-
import { existsSync as
|
|
71404
|
-
import { join as
|
|
71849
|
+
import { existsSync as existsSync28, writeFileSync as writeFileSync17, mkdirSync as mkdirSync16 } from "fs";
|
|
71850
|
+
import { join as join31 } from "path";
|
|
71405
71851
|
function registerCreateSync(parent) {
|
|
71406
71852
|
const configCmd = parent.command("config").description("Manage skills configuration");
|
|
71407
71853
|
configCmd.command("show", { isDefault: true }).option("--json", "Output as JSON", false).description("Show current merged configuration").action((options) => {
|
|
@@ -71467,23 +71913,23 @@ function registerCreateSync(parent) {
|
|
|
71467
71913
|
const pp = getConfigPath("project");
|
|
71468
71914
|
if (options.json) {
|
|
71469
71915
|
console.log(JSON.stringify({
|
|
71470
|
-
global: { path: gp, exists:
|
|
71471
|
-
project: { path: pp, exists:
|
|
71916
|
+
global: { path: gp, exists: existsSync28(gp) },
|
|
71917
|
+
project: { path: pp, exists: existsSync28(pp) }
|
|
71472
71918
|
}, null, 2));
|
|
71473
71919
|
return;
|
|
71474
71920
|
}
|
|
71475
|
-
console.log(`${source_default.cyan("global")}: ${gp}${
|
|
71476
|
-
console.log(`${source_default.cyan("project")}: ${pp}${
|
|
71921
|
+
console.log(`${source_default.cyan("global")}: ${gp}${existsSync28(gp) ? source_default.green(" (exists)") : source_default.dim(" (not found)")}`);
|
|
71922
|
+
console.log(`${source_default.cyan("project")}: ${pp}${existsSync28(pp) ? source_default.green(" (exists)") : source_default.dim(" (not found)")}`);
|
|
71477
71923
|
});
|
|
71478
71924
|
parent.command("create").argument("<name>", "Skill name (e.g. my-tool)").option("--category <category>", "Skill category", "Development Tools").option("--description <description>", "Short description of what the skill does").option("--tags <tags>", "Comma-separated tags (e.g. api,testing,automation)").option("--global", "Deprecated; custom skills are always global", false).option("--json", "Output result as JSON", false).description("Scaffold a new custom skill directory").action((name, options) => handleCreate(name, options));
|
|
71479
|
-
parent.command("sync").alias("render").argument("[names...]", "Skills to sync (default: every skill in this machine's corpus)").option("--for <agent>", `Target one agent (${SYNC_AGENTS.join(", ")}, or all)`, "all").option("--all", "Sync every corpus skill (the default)", false).option("--source <path>", "Canonical corpus source: a directory of skill folders, or a package root with skills/ (overrides $SKILLS_SOURCE)").option("--dry-run", "Show what would be written without touching any agent folder", false).option("--force", "Adopt an unmanaged skill that already has SKILL.md; other unmarked directories are never overwritten", false).option("--check", "Home drift census (missing-from-home / stray-in-home / diverged); exits non-zero on drift, writes nothing", false).option("--adopt", "Unmarked-home adoption mode: hash unmarked home skills against the corpus; exact matches are marked (dry-run by default)", false).option("--prune", "Prune mode: list (or with --apply, remove) marked home skill dirs that have no canonical corpus entry", false).option("--apply", "Write adoption markers / conflicts ledger, or perform prune removals", false).option("--json", "Output as JSON", false).description("Write corpus skills into each coding agent's global skills folder, per-tool adapted").action((names, options) => handleSync(names, options));
|
|
71925
|
+
parent.command("sync").alias("render").argument("[names...]", "Skills to sync (default: every skill in this machine's corpus)").option("--for <agent>", `Target one agent (${SYNC_AGENTS.join(", ")}, or all)`, "all").option("--all", "Sync every corpus skill (the default)", false).option("--source <path>", "Canonical corpus source: a directory of skill folders, or a package root with skills/ (overrides $SKILLS_SOURCE)").option("--dry-run", "Show what would be written without touching any agent folder", false).option("--force", "Adopt an unmanaged skill that already has SKILL.md; other unmarked directories are never overwritten", false).option("--check", "Home drift census (missing-from-home / stray-in-home / diverged); exits non-zero on drift, writes nothing", false).option("--adopt", "Unmarked-home adoption mode: hash unmarked home skills against the corpus; exact matches are marked (dry-run by default)", false).option("--prune", "Prune mode: list (or with --apply, remove) marked home skill dirs that have no canonical corpus entry", false).option("--apply", "Write adoption markers / conflicts ledger, or perform prune removals", false).option("--json", "Output as JSON", false).option("--station <id>", "Per-station snapshot mode: snapshot the installed skill homes into resources/<station>/skills with a v3 sync-manifest (dry-run by default; --populate writes)").option("--populate", "Write the per-station snapshot (station mode; the default is dry-run)", false).option("--repo-root <path>", "Station snapshot destination repo root (default: cwd)").option("--homes-root <dir>", "Build the station snapshot from a staged mirror of the skill homes instead of this machine's $HOME").description("Write corpus skills into each coding agent's global skills folder, per-tool adapted; with --station, snapshot the homes into a reviewed snapshot repo instead").action((names, options) => handleSync(names, options));
|
|
71480
71926
|
}
|
|
71481
71927
|
function handleCreate(name, options) {
|
|
71482
71928
|
const bare = name.trim();
|
|
71483
71929
|
const dirName = bare;
|
|
71484
|
-
const
|
|
71485
|
-
const skillDir =
|
|
71486
|
-
if (
|
|
71930
|
+
const baseDir2 = getPortableSkillsRoot();
|
|
71931
|
+
const skillDir = join31(baseDir2, dirName);
|
|
71932
|
+
if (existsSync28(skillDir)) {
|
|
71487
71933
|
console.log(options.json ? JSON.stringify({ error: `Skill '${bare}' already exists at ${skillDir}` }) : source_default.red(`Skill '${bare}' already exists at ${skillDir}`));
|
|
71488
71934
|
process.exitCode = 1;
|
|
71489
71935
|
return;
|
|
@@ -71491,8 +71937,8 @@ function handleCreate(name, options) {
|
|
|
71491
71937
|
const description = options.description || `${bare} skill`;
|
|
71492
71938
|
const tags = options.tags ? options.tags.split(",").map((t) => t.trim()).filter(Boolean) : [bare];
|
|
71493
71939
|
const displayName2 = bare.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
71494
|
-
|
|
71495
|
-
|
|
71940
|
+
mkdirSync16(join31(skillDir, "src"), { recursive: true });
|
|
71941
|
+
writeFileSync17(join31(skillDir, "SKILL.md"), [
|
|
71496
71942
|
"---",
|
|
71497
71943
|
`name: ${bare}`,
|
|
71498
71944
|
`description: ${description}`,
|
|
@@ -71512,11 +71958,11 @@ function handleCreate(name, options) {
|
|
|
71512
71958
|
""
|
|
71513
71959
|
].join(`
|
|
71514
71960
|
`));
|
|
71515
|
-
|
|
71961
|
+
writeFileSync17(join31(skillDir, "src", "index.ts"), [`#!/usr/bin/env bun`, `/**`, ` * ${displayName2} \u2014 ${description}`, ` */`, "", `console.log("${displayName2}");`, ""].join(`
|
|
71516
71962
|
`));
|
|
71517
|
-
|
|
71963
|
+
writeFileSync17(join31(skillDir, "package.json"), JSON.stringify({ name: bare, version: "0.1.0", description, bin: { [bare]: "./src/index.ts" }, scripts: { dev: `bun src/index.ts` }, dependencies: {} }, null, 2) + `
|
|
71518
71964
|
`);
|
|
71519
|
-
|
|
71965
|
+
writeFileSync17(join31(skillDir, "tsconfig.json"), JSON.stringify({ compilerOptions: { target: "ES2022", module: "ESNext", moduleResolution: "bundler", strict: true, outDir: "dist" }, include: ["src/**/*.ts"] }, null, 2) + `
|
|
71520
71966
|
`);
|
|
71521
71967
|
clearRegistryCache();
|
|
71522
71968
|
if (options.json)
|
|
@@ -71525,11 +71971,15 @@ function handleCreate(name, options) {
|
|
|
71525
71971
|
console.log(source_default.green(`\u2713 Created custom skill '${bare}' at ${skillDir}`));
|
|
71526
71972
|
console.log(source_default.dim(` Category: ${options.category}`));
|
|
71527
71973
|
console.log(source_default.dim(` Tags: ${tags.join(", ")}`));
|
|
71528
|
-
console.log(` ${source_default.cyan("Edit:")} ${
|
|
71529
|
-
console.log(` ${source_default.cyan("Run:")} bun ${
|
|
71974
|
+
console.log(` ${source_default.cyan("Edit:")} ${join31(skillDir, "src", "index.ts")}`);
|
|
71975
|
+
console.log(` ${source_default.cyan("Run:")} bun ${join31(skillDir, "src", "index.ts")}`);
|
|
71530
71976
|
}
|
|
71531
71977
|
}
|
|
71532
71978
|
function handleSync(names, options) {
|
|
71979
|
+
if (options.station) {
|
|
71980
|
+
handleStationSnapshot(names, options);
|
|
71981
|
+
return;
|
|
71982
|
+
}
|
|
71533
71983
|
const modes = [options.check, options.adopt, options.prune].filter(Boolean).length;
|
|
71534
71984
|
if (modes > 1) {
|
|
71535
71985
|
const message = "--check, --adopt, and --prune are mutually exclusive";
|
|
@@ -71590,6 +72040,68 @@ function handleSync(names, options) {
|
|
|
71590
72040
|
process.exitCode = 1;
|
|
71591
72041
|
}
|
|
71592
72042
|
}
|
|
72043
|
+
function handleStationSnapshot(names, options) {
|
|
72044
|
+
const station = options.station;
|
|
72045
|
+
if (!station)
|
|
72046
|
+
return;
|
|
72047
|
+
if (options.populate && options.dryRun) {
|
|
72048
|
+
const message = "--populate and --dry-run are mutually exclusive";
|
|
72049
|
+
if (options.json)
|
|
72050
|
+
console.log(JSON.stringify({ error: message }));
|
|
72051
|
+
else
|
|
72052
|
+
console.error(source_default.red(message));
|
|
72053
|
+
process.exitCode = 1;
|
|
72054
|
+
return;
|
|
72055
|
+
}
|
|
72056
|
+
const incompatible = names.length > 0 || options.check || options.adopt || options.prune || options.force || options.all || options.source !== undefined;
|
|
72057
|
+
if (incompatible) {
|
|
72058
|
+
const message = "--station (per-station snapshot mode) cannot be combined with corpus->home sync names, --check, --adopt, --prune, --force, --all, or --source";
|
|
72059
|
+
if (options.json)
|
|
72060
|
+
console.log(JSON.stringify({ error: message }));
|
|
72061
|
+
else
|
|
72062
|
+
console.error(source_default.red(message));
|
|
72063
|
+
process.exitCode = 1;
|
|
72064
|
+
return;
|
|
72065
|
+
}
|
|
72066
|
+
try {
|
|
72067
|
+
const result2 = writeStationSnapshot({
|
|
72068
|
+
stationId: station,
|
|
72069
|
+
repoRoot: options.repoRoot,
|
|
72070
|
+
homesRoot: options.homesRoot,
|
|
72071
|
+
dryRun: !options.populate
|
|
72072
|
+
});
|
|
72073
|
+
if (result2.mode === "dry-run") {
|
|
72074
|
+
if (options.json) {
|
|
72075
|
+
console.log(JSON.stringify({
|
|
72076
|
+
stationId: result2.stationId,
|
|
72077
|
+
mode: "dry-run",
|
|
72078
|
+
stats: { files: result2.stats.files, bytes: result2.stats.bytes },
|
|
72079
|
+
homes: Object.fromEntries(result2.homes.map((home) => [
|
|
72080
|
+
home.name,
|
|
72081
|
+
{ homePath: home.homePath, files: home.files, skipped: home.skipped }
|
|
72082
|
+
]))
|
|
72083
|
+
}, null, 2));
|
|
72084
|
+
return;
|
|
72085
|
+
}
|
|
72086
|
+
console.log(`DRY-RUN station=${result2.stationId} files=${result2.stats.files} bytes=${result2.stats.bytes}`);
|
|
72087
|
+
for (const home of result2.homes) {
|
|
72088
|
+
console.log(` ${home.name}: ${home.files} files, ${home.skipped} skipped`);
|
|
72089
|
+
}
|
|
72090
|
+
return;
|
|
72091
|
+
}
|
|
72092
|
+
console.log(`POPULATE station=${result2.stationId} written=${result2.stats.written} unchanged=${result2.stats.unchanged} total=${result2.stats.files} bytes=${result2.stats.bytes}`);
|
|
72093
|
+
} catch (error2) {
|
|
72094
|
+
if (error2 instanceof StationSnapshotError) {
|
|
72095
|
+
for (const line of error2.detail)
|
|
72096
|
+
console.error(`CONFLICT ${line}`);
|
|
72097
|
+
console.error(`FAIL ${error2.message}`);
|
|
72098
|
+
process.exitCode = 2;
|
|
72099
|
+
} else {
|
|
72100
|
+
console.error(`FAIL ${error2.stack ?? error2.message}`);
|
|
72101
|
+
process.exitCode = 1;
|
|
72102
|
+
}
|
|
72103
|
+
}
|
|
72104
|
+
}
|
|
71593
72105
|
function handleSyncCheck(json) {
|
|
71594
72106
|
const census = censusHomeDrift();
|
|
71595
72107
|
if (json) {
|
|
@@ -71701,6 +72213,367 @@ var init_create_sync_config = __esm(() => {
|
|
|
71701
72213
|
init_agent_sync();
|
|
71702
72214
|
init_home_adoption();
|
|
71703
72215
|
init_home_census();
|
|
72216
|
+
init_station_snapshot();
|
|
72217
|
+
});
|
|
72218
|
+
|
|
72219
|
+
// src/lib/station-hydrate.ts
|
|
72220
|
+
import { createHash as createHash5 } from "crypto";
|
|
72221
|
+
import {
|
|
72222
|
+
copyFileSync as copyFileSync3,
|
|
72223
|
+
mkdirSync as mkdirSync17,
|
|
72224
|
+
readdirSync as readdirSync16,
|
|
72225
|
+
readFileSync as readFileSync23,
|
|
72226
|
+
statSync as statSync17,
|
|
72227
|
+
writeFileSync as writeFileSync18
|
|
72228
|
+
} from "fs";
|
|
72229
|
+
import { dirname as dirname12, join as join32, resolve as resolve3, sep as sep5 } from "path";
|
|
72230
|
+
function fail2(code, message, detail = []) {
|
|
72231
|
+
throw new StationSnapshotError(code, message, detail);
|
|
72232
|
+
}
|
|
72233
|
+
function snapshotRootFor(repoRoot, stationId) {
|
|
72234
|
+
return join32(repoRoot, "resources", stationId, "skills");
|
|
72235
|
+
}
|
|
72236
|
+
function readSnapshotManifest(repoRoot, stationId) {
|
|
72237
|
+
const snapshotRoot = snapshotRootFor(repoRoot, stationId);
|
|
72238
|
+
const manifestPath = join32(snapshotRoot, "sync-manifest.json");
|
|
72239
|
+
let manifest;
|
|
72240
|
+
try {
|
|
72241
|
+
manifest = JSON.parse(readFileSync23(manifestPath, "utf8"));
|
|
72242
|
+
} catch (error2) {
|
|
72243
|
+
fail2("MANIFEST_UNREADABLE", `cannot read snapshot manifest: ${manifestPath}: ${error2.message}`);
|
|
72244
|
+
}
|
|
72245
|
+
const sourceSnapshotSha = sha256File(manifestPath);
|
|
72246
|
+
return { manifest, manifestPath, sourceSnapshotSha };
|
|
72247
|
+
}
|
|
72248
|
+
function planStationHydration(stationId, repoRoot) {
|
|
72249
|
+
validateStationId(stationId);
|
|
72250
|
+
const { manifest, sourceSnapshotSha } = readSnapshotManifest(repoRoot, stationId);
|
|
72251
|
+
const snapshotRoot = snapshotRootFor(repoRoot, stationId);
|
|
72252
|
+
const manifestHashes = new Map;
|
|
72253
|
+
for (const file of manifest.files ?? []) {
|
|
72254
|
+
const relativePath = file.relativePath;
|
|
72255
|
+
const agent = file.agent;
|
|
72256
|
+
if (agent && relativePath) {
|
|
72257
|
+
manifestHashes.set(`${agent}${MANIFEST_HASH_KEY_SEP}${relativePath}`, file.sha256);
|
|
72258
|
+
}
|
|
72259
|
+
}
|
|
72260
|
+
const candidates = [];
|
|
72261
|
+
const symlinks = [];
|
|
72262
|
+
const hashMismatches = [];
|
|
72263
|
+
const skippedByRule = [];
|
|
72264
|
+
for (const agent of SYNC_AGENTS) {
|
|
72265
|
+
const agentRoot = join32(snapshotRoot, "agent-homes", agent);
|
|
72266
|
+
let identEntries;
|
|
72267
|
+
try {
|
|
72268
|
+
identEntries = readdirSync16(agentRoot, { withFileTypes: true });
|
|
72269
|
+
} catch {
|
|
72270
|
+
continue;
|
|
72271
|
+
}
|
|
72272
|
+
for (const identEntry of identEntries) {
|
|
72273
|
+
if (!identEntry.isDirectory() || identEntry.name.startsWith(".")) {
|
|
72274
|
+
continue;
|
|
72275
|
+
}
|
|
72276
|
+
const identRoot = join32(agentRoot, identEntry.name);
|
|
72277
|
+
const entries = walkEntries(identRoot);
|
|
72278
|
+
for (const entry of entries) {
|
|
72279
|
+
const relativeParts = [identEntry.name, ...entry.relativePath.split(sep5)];
|
|
72280
|
+
if (entry.kind === "symlink") {
|
|
72281
|
+
symlinks.push({ ident: identEntry.name, agent, relativePath: entry.relativePath });
|
|
72282
|
+
continue;
|
|
72283
|
+
}
|
|
72284
|
+
if (!isPortableWithinSkill(relativeParts)) {
|
|
72285
|
+
skippedByRule.push({
|
|
72286
|
+
ident: identEntry.name,
|
|
72287
|
+
agent,
|
|
72288
|
+
relativePath: entry.relativePath,
|
|
72289
|
+
reason: "not-portable"
|
|
72290
|
+
});
|
|
72291
|
+
continue;
|
|
72292
|
+
}
|
|
72293
|
+
const fileName = relativeParts[relativeParts.length - 1];
|
|
72294
|
+
if (isExcludedSkillFileName(fileName)) {
|
|
72295
|
+
skippedByRule.push({
|
|
72296
|
+
ident: identEntry.name,
|
|
72297
|
+
agent,
|
|
72298
|
+
relativePath: entry.relativePath,
|
|
72299
|
+
reason: "excluded"
|
|
72300
|
+
});
|
|
72301
|
+
continue;
|
|
72302
|
+
}
|
|
72303
|
+
const withinIdent = relativeParts.slice(1).join(sep5);
|
|
72304
|
+
const homeRelative = relativeParts.join(sep5);
|
|
72305
|
+
if (REFUSED_SCANNER_FLAGGED.has(homeRelative)) {
|
|
72306
|
+
skippedByRule.push({
|
|
72307
|
+
ident: identEntry.name,
|
|
72308
|
+
agent,
|
|
72309
|
+
relativePath: entry.relativePath,
|
|
72310
|
+
reason: "refused-scanner-flagged"
|
|
72311
|
+
});
|
|
72312
|
+
continue;
|
|
72313
|
+
}
|
|
72314
|
+
if (!isRegularFile(entry.fullPath)) {
|
|
72315
|
+
skippedByRule.push({
|
|
72316
|
+
ident: identEntry.name,
|
|
72317
|
+
agent,
|
|
72318
|
+
relativePath: entry.relativePath,
|
|
72319
|
+
reason: "not-regular-file"
|
|
72320
|
+
});
|
|
72321
|
+
continue;
|
|
72322
|
+
}
|
|
72323
|
+
const info = statSync17(entry.fullPath);
|
|
72324
|
+
const manifestHash = manifestHashes.get(`${agent}${MANIFEST_HASH_KEY_SEP}${homeRelative}`) ?? null;
|
|
72325
|
+
let verified = false;
|
|
72326
|
+
if (manifestHash !== null) {
|
|
72327
|
+
verified = sha256File(entry.fullPath) === manifestHash;
|
|
72328
|
+
if (!verified) {
|
|
72329
|
+
hashMismatches.push({
|
|
72330
|
+
ident: identEntry.name,
|
|
72331
|
+
agent,
|
|
72332
|
+
relativePath: entry.relativePath
|
|
72333
|
+
});
|
|
72334
|
+
}
|
|
72335
|
+
}
|
|
72336
|
+
candidates.push({
|
|
72337
|
+
ident: identEntry.name,
|
|
72338
|
+
agent,
|
|
72339
|
+
withinIdent,
|
|
72340
|
+
fullPath: entry.fullPath,
|
|
72341
|
+
size: info.size,
|
|
72342
|
+
mtimeMs: info.mtimeMs,
|
|
72343
|
+
manifestHash,
|
|
72344
|
+
verified
|
|
72345
|
+
});
|
|
72346
|
+
}
|
|
72347
|
+
}
|
|
72348
|
+
}
|
|
72349
|
+
if (symlinks.length > 0) {
|
|
72350
|
+
fail2("SYMLINKS_REFUSED", `${symlinks.length} symlink(s) inside the snapshot; symlinks are refused (fail closed)`);
|
|
72351
|
+
}
|
|
72352
|
+
if (hashMismatches.length > 0) {
|
|
72353
|
+
fail2("MANIFEST_HASH_MISMATCH", `${hashMismatches.length} snapshot file(s) no longer match their sync-manifest sha256; ` + "stale or tampered content is refused (fail closed), nothing written \u2014 re-run sync to refresh the manifest", hashMismatches.map((mismatch) => `agent-homes/${mismatch.agent}/${mismatch.ident}/${mismatch.relativePath}`));
|
|
72354
|
+
}
|
|
72355
|
+
const byIdent = new Map;
|
|
72356
|
+
for (const candidate of candidates) {
|
|
72357
|
+
const group = byIdent.get(candidate.ident) ?? [];
|
|
72358
|
+
group.push(candidate);
|
|
72359
|
+
byIdent.set(candidate.ident, group);
|
|
72360
|
+
}
|
|
72361
|
+
const winners = [];
|
|
72362
|
+
for (const [ident, group] of byIdent) {
|
|
72363
|
+
const byFile = new Map;
|
|
72364
|
+
for (const candidate of group) {
|
|
72365
|
+
const copies = byFile.get(candidate.withinIdent) ?? [];
|
|
72366
|
+
copies.push(candidate);
|
|
72367
|
+
byFile.set(candidate.withinIdent, copies);
|
|
72368
|
+
}
|
|
72369
|
+
const files = [];
|
|
72370
|
+
for (const [withinIdent, copies] of byFile) {
|
|
72371
|
+
let eligible = copies;
|
|
72372
|
+
if (withinIdent === "SKILL.md") {
|
|
72373
|
+
const content = [];
|
|
72374
|
+
for (const copy of copies) {
|
|
72375
|
+
let isStub = false;
|
|
72376
|
+
try {
|
|
72377
|
+
isStub = isPointerSkillMd(readFileSync23(copy.fullPath, "utf8"));
|
|
72378
|
+
} catch {
|
|
72379
|
+
isStub = false;
|
|
72380
|
+
}
|
|
72381
|
+
if (!isStub)
|
|
72382
|
+
content.push(copy);
|
|
72383
|
+
}
|
|
72384
|
+
if (content.length > 0) {
|
|
72385
|
+
eligible = content;
|
|
72386
|
+
}
|
|
72387
|
+
}
|
|
72388
|
+
eligible.sort((left, right) => {
|
|
72389
|
+
const leftHash = left.verified;
|
|
72390
|
+
const rightHash = right.verified;
|
|
72391
|
+
if (leftHash !== rightHash) {
|
|
72392
|
+
return leftHash ? -1 : 1;
|
|
72393
|
+
}
|
|
72394
|
+
if (right.mtimeMs !== left.mtimeMs) {
|
|
72395
|
+
return right.mtimeMs - left.mtimeMs;
|
|
72396
|
+
}
|
|
72397
|
+
return SYNC_AGENTS.indexOf(left.agent) - SYNC_AGENTS.indexOf(right.agent);
|
|
72398
|
+
});
|
|
72399
|
+
const winner = eligible[0];
|
|
72400
|
+
files.push({
|
|
72401
|
+
withinIdent,
|
|
72402
|
+
winner,
|
|
72403
|
+
alternates: copies.filter((copy) => copy !== winner).map((copy) => copy.agent)
|
|
72404
|
+
});
|
|
72405
|
+
}
|
|
72406
|
+
files.sort((left, right) => left.withinIdent.localeCompare(right.withinIdent));
|
|
72407
|
+
winners.push({ ident, files });
|
|
72408
|
+
}
|
|
72409
|
+
winners.sort((left, right) => left.ident.localeCompare(right.ident));
|
|
72410
|
+
const totalFiles = winners.reduce((sum2, skill) => sum2 + skill.files.length, 0);
|
|
72411
|
+
const totalBytes = winners.reduce((sum2, skill) => sum2 + skill.files.reduce((inner, file) => inner + file.winner.size, 0), 0);
|
|
72412
|
+
return { manifest, sourceSnapshotSha, winners, skippedByRule, totalFiles, totalBytes };
|
|
72413
|
+
}
|
|
72414
|
+
function skillSha256(skill) {
|
|
72415
|
+
const skillMd = skill.files.find((file) => file.withinIdent === "SKILL.md");
|
|
72416
|
+
if (skillMd) {
|
|
72417
|
+
return sha256File(skillMd.winner.fullPath);
|
|
72418
|
+
}
|
|
72419
|
+
if (skill.files.length === 1) {
|
|
72420
|
+
return sha256File(skill.files[0].winner.fullPath);
|
|
72421
|
+
}
|
|
72422
|
+
const joined = skill.files.map((file) => sha256File(file.winner.fullPath));
|
|
72423
|
+
return createHash5("sha256").update(joined.sort().join(`
|
|
72424
|
+
`)).digest("hex");
|
|
72425
|
+
}
|
|
72426
|
+
function writeStationHydration(options) {
|
|
72427
|
+
const repoRoot = resolve3(options.repoRoot ?? process.cwd());
|
|
72428
|
+
const cacheRoot = resolve3(options.cacheRoot ?? resolveCorpusRoot());
|
|
72429
|
+
const plan = planStationHydration(options.stationId, repoRoot);
|
|
72430
|
+
const resultSkills = plan.winners.map((skill) => ({
|
|
72431
|
+
ident: skill.ident,
|
|
72432
|
+
files: skill.files.map((file) => ({
|
|
72433
|
+
relativePath: file.withinIdent,
|
|
72434
|
+
sourceAgent: file.winner.agent,
|
|
72435
|
+
sourceMtimeMs: file.winner.mtimeMs,
|
|
72436
|
+
size: file.winner.size
|
|
72437
|
+
})),
|
|
72438
|
+
sha256: skillSha256(skill)
|
|
72439
|
+
}));
|
|
72440
|
+
const base2 = {
|
|
72441
|
+
stationId: options.stationId,
|
|
72442
|
+
mode: "dry-run",
|
|
72443
|
+
cacheRoot,
|
|
72444
|
+
snapshotRoot: snapshotRootFor(repoRoot, options.stationId),
|
|
72445
|
+
sourceSnapshotSha: plan.sourceSnapshotSha,
|
|
72446
|
+
stats: {
|
|
72447
|
+
idents: plan.winners.length,
|
|
72448
|
+
files: plan.totalFiles,
|
|
72449
|
+
bytes: plan.totalBytes
|
|
72450
|
+
},
|
|
72451
|
+
winners: plan.winners,
|
|
72452
|
+
skills: resultSkills
|
|
72453
|
+
};
|
|
72454
|
+
if (options.dryRun !== false) {
|
|
72455
|
+
return base2;
|
|
72456
|
+
}
|
|
72457
|
+
const conflicts = [];
|
|
72458
|
+
const toWrite = [];
|
|
72459
|
+
for (const skill of plan.winners) {
|
|
72460
|
+
for (const file of skill.files) {
|
|
72461
|
+
const destination = join32(cacheRoot, skill.ident, file.withinIdent);
|
|
72462
|
+
const digest = sha256File(file.winner.fullPath);
|
|
72463
|
+
let existingDigest = null;
|
|
72464
|
+
try {
|
|
72465
|
+
existingDigest = sha256File(destination);
|
|
72466
|
+
} catch {}
|
|
72467
|
+
if (existingDigest !== null) {
|
|
72468
|
+
if (existingDigest === digest) {
|
|
72469
|
+
continue;
|
|
72470
|
+
}
|
|
72471
|
+
conflicts.push(`existing destination differs from snapshot winner: ${destination}`);
|
|
72472
|
+
continue;
|
|
72473
|
+
}
|
|
72474
|
+
toWrite.push({ destination, fullPath: file.winner.fullPath });
|
|
72475
|
+
}
|
|
72476
|
+
}
|
|
72477
|
+
if (conflicts.length > 0) {
|
|
72478
|
+
fail2("CONFLICT", `${conflicts.length} conflict(s); terminal non-acceptance, nothing written`, conflicts);
|
|
72479
|
+
}
|
|
72480
|
+
let written = 0;
|
|
72481
|
+
for (const entry of toWrite) {
|
|
72482
|
+
mkdirSync17(dirname12(entry.destination), { recursive: true });
|
|
72483
|
+
copyFileSync3(entry.fullPath, entry.destination);
|
|
72484
|
+
written += 1;
|
|
72485
|
+
}
|
|
72486
|
+
const unchanged = plan.totalFiles - written;
|
|
72487
|
+
const hydration = {
|
|
72488
|
+
schema: STATION_HYDRATION_MANIFEST_SCHEMA,
|
|
72489
|
+
stationId: options.stationId,
|
|
72490
|
+
hydratedAt: new Date().toISOString(),
|
|
72491
|
+
producer: STATION_HYDRATION_PRODUCER,
|
|
72492
|
+
sourceSnapshotSha: plan.sourceSnapshotSha,
|
|
72493
|
+
cacheRoot,
|
|
72494
|
+
stats: {
|
|
72495
|
+
idents: plan.winners.length,
|
|
72496
|
+
written,
|
|
72497
|
+
unchanged,
|
|
72498
|
+
files: plan.totalFiles,
|
|
72499
|
+
bytes: plan.totalBytes
|
|
72500
|
+
},
|
|
72501
|
+
skills: resultSkills
|
|
72502
|
+
};
|
|
72503
|
+
const hydrationManifestPath = join32(dirname12(cacheRoot), `hydration-${options.stationId}.json`);
|
|
72504
|
+
mkdirSync17(dirname12(hydrationManifestPath), { recursive: true });
|
|
72505
|
+
writeFileSync18(hydrationManifestPath, `${JSON.stringify(hydration, null, 2)}
|
|
72506
|
+
`);
|
|
72507
|
+
return {
|
|
72508
|
+
...base2,
|
|
72509
|
+
mode: "apply",
|
|
72510
|
+
stats: { ...base2.stats, written, unchanged },
|
|
72511
|
+
manifestPath: hydrationManifestPath
|
|
72512
|
+
};
|
|
72513
|
+
}
|
|
72514
|
+
var STATION_HYDRATION_MANIFEST_SCHEMA = "hasna.fleet-resources.skills-hydration-manifest/v1", STATION_HYDRATION_PRODUCER, MANIFEST_HASH_KEY_SEP;
|
|
72515
|
+
var init_station_hydrate = __esm(() => {
|
|
72516
|
+
init_package();
|
|
72517
|
+
init_agent_sync();
|
|
72518
|
+
init_home_migration();
|
|
72519
|
+
init_portable_snapshot_filter();
|
|
72520
|
+
init_station_snapshot();
|
|
72521
|
+
STATION_HYDRATION_PRODUCER = { name: "@hasna/skills", version: package_default.version };
|
|
72522
|
+
MANIFEST_HASH_KEY_SEP = String.fromCharCode(0);
|
|
72523
|
+
});
|
|
72524
|
+
|
|
72525
|
+
// src/cli/commands/hydrate.ts
|
|
72526
|
+
var exports_hydrate = {};
|
|
72527
|
+
__export(exports_hydrate, {
|
|
72528
|
+
registerHydrate: () => registerHydrate
|
|
72529
|
+
});
|
|
72530
|
+
function registerHydrate(parent) {
|
|
72531
|
+
parent.command("hydrate").description("Hydrate the canonical dedup corpus cache from a reviewed per-station skills snapshot").requiredOption("--station <id>", "Station id (slug) naming the snapshot under resources/<id>/skills").option("--apply", "Write into the corpus cache (the default is dry-run)", false).option("--dry-run", "Report without writing anything (the default)", false).option("--cache-root <dir>", "Override the destination corpus cache (used to stage another station's cache before rsync)").option("--repo-root <path>", "Repo root holding resources/<station>/skills (default: cwd)").action((options) => {
|
|
72532
|
+
handleHydrate(options);
|
|
72533
|
+
});
|
|
72534
|
+
}
|
|
72535
|
+
function handleHydrate(options) {
|
|
72536
|
+
if (options.apply && options.dryRun) {
|
|
72537
|
+
console.error(source_default.red("--apply and --dry-run are mutually exclusive"));
|
|
72538
|
+
process.exitCode = 2;
|
|
72539
|
+
return;
|
|
72540
|
+
}
|
|
72541
|
+
let result2;
|
|
72542
|
+
try {
|
|
72543
|
+
result2 = writeStationHydration({
|
|
72544
|
+
stationId: options.station,
|
|
72545
|
+
repoRoot: options.repoRoot,
|
|
72546
|
+
cacheRoot: options.cacheRoot,
|
|
72547
|
+
dryRun: !options.apply
|
|
72548
|
+
});
|
|
72549
|
+
} catch (error2) {
|
|
72550
|
+
if (error2 instanceof StationSnapshotError) {
|
|
72551
|
+
for (const line of error2.detail)
|
|
72552
|
+
console.error(`CONFLICT ${line}`);
|
|
72553
|
+
console.error(`FAIL ${error2.message}`);
|
|
72554
|
+
process.exitCode = 2;
|
|
72555
|
+
} else {
|
|
72556
|
+
console.error(`FAIL ${error2.stack ?? error2.message}`);
|
|
72557
|
+
process.exitCode = 1;
|
|
72558
|
+
}
|
|
72559
|
+
return;
|
|
72560
|
+
}
|
|
72561
|
+
if (result2.mode === "dry-run") {
|
|
72562
|
+
console.log(`DRY-RUN station=${result2.stationId} idents=${result2.stats.idents} files=${result2.stats.files} bytes=${result2.stats.bytes}`);
|
|
72563
|
+
console.log(` cache-root=${result2.cacheRoot} snapshot-sha=${result2.sourceSnapshotSha.slice(0, 12)}`);
|
|
72564
|
+
for (const skill of result2.winners) {
|
|
72565
|
+
const merged = skill.files.length > 1 ? ` (${skill.files.length} files, alternates: ${skill.files.map((file) => file.alternates.length > 0 ? `${file.withinIdent}<-${file.alternates.join(",")}` : null).filter(Boolean).join("; ") || "none"})` : "";
|
|
72566
|
+
console.log(` ${skill.ident}${merged}`);
|
|
72567
|
+
}
|
|
72568
|
+
return;
|
|
72569
|
+
}
|
|
72570
|
+
console.log(`HYDRATE station=${result2.stationId} idents=${result2.stats.idents} written=${result2.stats.written} unchanged=${result2.stats.unchanged} files=${result2.stats.files} bytes=${result2.stats.bytes}`);
|
|
72571
|
+
console.log(` manifest=${result2.manifestPath} snapshot-sha=${result2.sourceSnapshotSha}`);
|
|
72572
|
+
}
|
|
72573
|
+
var init_hydrate = __esm(() => {
|
|
72574
|
+
init_source();
|
|
72575
|
+
init_station_snapshot();
|
|
72576
|
+
init_station_hydrate();
|
|
71704
72577
|
});
|
|
71705
72578
|
|
|
71706
72579
|
// src/cli/commands/portable-skills.ts
|
|
@@ -72031,8 +72904,8 @@ var init_schedule = __esm(() => {
|
|
|
72031
72904
|
});
|
|
72032
72905
|
|
|
72033
72906
|
// src/lib/registry-sync.ts
|
|
72034
|
-
import { mkdirSync as
|
|
72035
|
-
import { dirname as
|
|
72907
|
+
import { mkdirSync as mkdirSync18, writeFileSync as writeFileSync19 } from "fs";
|
|
72908
|
+
import { dirname as dirname13, relative as relative5 } from "path";
|
|
72036
72909
|
function createRegistrySyncArtifact(options = {}) {
|
|
72037
72910
|
const profile = options.profile ?? "all";
|
|
72038
72911
|
const includeDocs = options.includeDocs ?? true;
|
|
@@ -72044,7 +72917,7 @@ function createRegistrySyncArtifact(options = {}) {
|
|
|
72044
72917
|
const registry2 = [...loadRegistryProfile(profile)].sort((a, b) => a.name.localeCompare(b.name));
|
|
72045
72918
|
const skills = registry2.map((skill) => {
|
|
72046
72919
|
const skillPath = getSkillPath(skill.name);
|
|
72047
|
-
const directory =
|
|
72920
|
+
const directory = relative5(process.cwd(), skillPath) || skillPath;
|
|
72048
72921
|
const validation = includeValidation ? validateSkillDirectory(skill.name, skillPath, skill) : undefined;
|
|
72049
72922
|
const docs = includeDocs ? buildDocs(skill.name) : undefined;
|
|
72050
72923
|
return {
|
|
@@ -72089,8 +72962,8 @@ function createRegistrySyncArtifact(options = {}) {
|
|
|
72089
72962
|
};
|
|
72090
72963
|
}
|
|
72091
72964
|
function writeRegistrySyncArtifact(path, artifact) {
|
|
72092
|
-
|
|
72093
|
-
|
|
72965
|
+
mkdirSync18(dirname13(path), { recursive: true });
|
|
72966
|
+
writeFileSync19(path, `${JSON.stringify(artifact, null, 2)}
|
|
72094
72967
|
`);
|
|
72095
72968
|
}
|
|
72096
72969
|
function buildDocs(name) {
|
|
@@ -72109,7 +72982,7 @@ var init_registry_sync = __esm(() => {
|
|
|
72109
72982
|
});
|
|
72110
72983
|
|
|
72111
72984
|
// src/lib/revision.ts
|
|
72112
|
-
import { createHash as
|
|
72985
|
+
import { createHash as createHash6 } from "crypto";
|
|
72113
72986
|
function revisionIdOf(content) {
|
|
72114
72987
|
const canonical = JSON.stringify({
|
|
72115
72988
|
slug: content.slug,
|
|
@@ -72124,7 +72997,7 @@ function revisionIdOf(content) {
|
|
|
72124
72997
|
bundleSha256: content.bundleSha256 ?? null,
|
|
72125
72998
|
bundleByteSize: content.bundleByteSize ?? null
|
|
72126
72999
|
});
|
|
72127
|
-
return
|
|
73000
|
+
return createHash6("sha256").update(canonical).digest("hex");
|
|
72128
73001
|
}
|
|
72129
73002
|
var REVISION_ID_PATTERN;
|
|
72130
73003
|
var init_revision = __esm(() => {
|
|
@@ -72132,9 +73005,9 @@ var init_revision = __esm(() => {
|
|
|
72132
73005
|
});
|
|
72133
73006
|
|
|
72134
73007
|
// src/lib/skill-bundle.ts
|
|
72135
|
-
import { createHash as
|
|
72136
|
-
import { readFileSync as
|
|
72137
|
-
import { join as
|
|
73008
|
+
import { createHash as createHash7 } from "crypto";
|
|
73009
|
+
import { readFileSync as readFileSync24, readdirSync as readdirSync17, statSync as statSync18 } from "fs";
|
|
73010
|
+
import { join as join33, relative as relative6 } from "path";
|
|
72138
73011
|
function isDotenvFile(lower) {
|
|
72139
73012
|
if (lower === ".env" || lower.startsWith(".env."))
|
|
72140
73013
|
return true;
|
|
@@ -72163,7 +73036,7 @@ function ownBytes(view) {
|
|
|
72163
73036
|
return out;
|
|
72164
73037
|
}
|
|
72165
73038
|
function sha256Hex(bytes) {
|
|
72166
|
-
return
|
|
73039
|
+
return createHash7("sha256").update(bytes).digest("hex");
|
|
72167
73040
|
}
|
|
72168
73041
|
function collectSkillBundleEntries(dir) {
|
|
72169
73042
|
const entries = [];
|
|
@@ -72171,9 +73044,9 @@ function collectSkillBundleEntries(dir) {
|
|
|
72171
73044
|
return entries.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
72172
73045
|
}
|
|
72173
73046
|
function walk(root, current, out) {
|
|
72174
|
-
for (const entry of
|
|
72175
|
-
const absolute =
|
|
72176
|
-
const rel =
|
|
73047
|
+
for (const entry of readdirSync17(current, { withFileTypes: true })) {
|
|
73048
|
+
const absolute = join33(current, entry.name);
|
|
73049
|
+
const rel = relative6(root, absolute).split("\\").join("/");
|
|
72177
73050
|
const isRootLevel = !rel.includes("/");
|
|
72178
73051
|
if (ANY_SEGMENT_EXCLUDES.has(entry.name.toLowerCase()))
|
|
72179
73052
|
continue;
|
|
@@ -72193,10 +73066,10 @@ function walk(root, current, out) {
|
|
|
72193
73066
|
continue;
|
|
72194
73067
|
if (isCredentialFile(entry.name))
|
|
72195
73068
|
continue;
|
|
72196
|
-
const stats =
|
|
73069
|
+
const stats = statSync18(absolute);
|
|
72197
73070
|
out.push({
|
|
72198
73071
|
path: rel,
|
|
72199
|
-
bytes: ownBytes(
|
|
73072
|
+
bytes: ownBytes(readFileSync24(absolute)),
|
|
72200
73073
|
mode: stats.mode & 64 ? 493 : 420
|
|
72201
73074
|
});
|
|
72202
73075
|
}
|
|
@@ -72482,8 +73355,8 @@ var init_skill_bundles = __esm(() => {
|
|
|
72482
73355
|
});
|
|
72483
73356
|
|
|
72484
73357
|
// src/lib/pull.ts
|
|
72485
|
-
import { existsSync as
|
|
72486
|
-
import { dirname as
|
|
73358
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync19, mkdtempSync as mkdtempSync3, readFileSync as readFileSync25, renameSync as renameSync4, rmSync as rmSync6, writeFileSync as writeFileSync20 } from "fs";
|
|
73359
|
+
import { dirname as dirname14, join as join34 } from "path";
|
|
72487
73360
|
async function pullSkills(options = {}) {
|
|
72488
73361
|
const client = options.client !== undefined ? options.client : createRemoteSkillsClient();
|
|
72489
73362
|
if (!client) {
|
|
@@ -72528,7 +73401,7 @@ async function pullOne(client, rawName, corpusOptions, verify) {
|
|
|
72528
73401
|
return reconcileTombstone(slug, corpusOptions);
|
|
72529
73402
|
}
|
|
72530
73403
|
if (bundleResponse.status === 404) {
|
|
72531
|
-
const marker = readPullMarker(
|
|
73404
|
+
const marker = readPullMarker(join34(getPortableSkillsRoot(corpusOptions), slug));
|
|
72532
73405
|
if (marker && typeof marker.revisionId === "string" && marker.revisionId) {
|
|
72533
73406
|
return { name: slug, success: true, purged: true, removed: false };
|
|
72534
73407
|
}
|
|
@@ -72559,7 +73432,7 @@ async function pullOne(client, rawName, corpusOptions, verify) {
|
|
|
72559
73432
|
return { name: slug, success: false, error: `Skill '${slug}' was not found on the configured Skills instance.` };
|
|
72560
73433
|
}
|
|
72561
73434
|
if (!meta?.revisionId) {
|
|
72562
|
-
const marker = readPullMarker(
|
|
73435
|
+
const marker = readPullMarker(join34(getPortableSkillsRoot(corpusOptions), slug));
|
|
72563
73436
|
if (marker && typeof marker.revisionId === "string" && marker.revisionId) {
|
|
72564
73437
|
return { name: slug, success: true, purged: true, removed: false };
|
|
72565
73438
|
}
|
|
@@ -72616,8 +73489,8 @@ function provenRevision(meta, slug, bundle) {
|
|
|
72616
73489
|
return declared;
|
|
72617
73490
|
}
|
|
72618
73491
|
function reconcileTombstone(slug, corpusOptions) {
|
|
72619
|
-
const target =
|
|
72620
|
-
if (!
|
|
73492
|
+
const target = join34(getPortableSkillsRoot(corpusOptions), slug);
|
|
73493
|
+
if (!existsSync29(join34(target, PULL_MARKER_FILE))) {
|
|
72621
73494
|
return { name: slug, success: true, tombstoned: true, removed: false, leftInPlace: true };
|
|
72622
73495
|
}
|
|
72623
73496
|
rmSync6(target, { recursive: true, force: true });
|
|
@@ -72625,7 +73498,7 @@ function reconcileTombstone(slug, corpusOptions) {
|
|
|
72625
73498
|
}
|
|
72626
73499
|
function readPullMarker(dir) {
|
|
72627
73500
|
try {
|
|
72628
|
-
return JSON.parse(
|
|
73501
|
+
return JSON.parse(readFileSync25(join34(dir, PULL_MARKER_FILE), "utf-8"));
|
|
72629
73502
|
} catch {
|
|
72630
73503
|
return null;
|
|
72631
73504
|
}
|
|
@@ -72745,17 +73618,17 @@ function verifyBundleResponseBytes(buffer, response, verify = {}) {
|
|
|
72745
73618
|
}
|
|
72746
73619
|
function installBundleAtomically(name, entries, options = {}, marker = {}) {
|
|
72747
73620
|
const root = getPortableSkillsRoot(options);
|
|
72748
|
-
|
|
72749
|
-
const target =
|
|
72750
|
-
const created = !
|
|
72751
|
-
const staging = mkdtempSync3(
|
|
73621
|
+
mkdirSync19(root, { recursive: true });
|
|
73622
|
+
const target = join34(root, name);
|
|
73623
|
+
const created = !existsSync29(target);
|
|
73624
|
+
const staging = mkdtempSync3(join34(root, `.pull-${name}-`));
|
|
72752
73625
|
let moved = false;
|
|
72753
73626
|
let backup = null;
|
|
72754
73627
|
try {
|
|
72755
73628
|
for (const entry of entries) {
|
|
72756
|
-
const destination =
|
|
72757
|
-
|
|
72758
|
-
|
|
73629
|
+
const destination = join34(staging, entry.path);
|
|
73630
|
+
mkdirSync19(dirname14(destination), { recursive: true });
|
|
73631
|
+
writeFileSync20(destination, entry.bytes, { mode: entry.mode });
|
|
72759
73632
|
}
|
|
72760
73633
|
writePullMarker(staging, {
|
|
72761
73634
|
skill: name,
|
|
@@ -72765,9 +73638,9 @@ function installBundleAtomically(name, entries, options = {}, marker = {}) {
|
|
|
72765
73638
|
...marker.signature ? { signature: marker.signature } : {},
|
|
72766
73639
|
...marker.revisionId ? { revisionId: marker.revisionId } : {}
|
|
72767
73640
|
});
|
|
72768
|
-
if (
|
|
72769
|
-
backup = mkdtempSync3(
|
|
72770
|
-
renameSync4(target,
|
|
73641
|
+
if (existsSync29(target)) {
|
|
73642
|
+
backup = mkdtempSync3(join34(root, `.pull-backup-${name}-`));
|
|
73643
|
+
renameSync4(target, join34(backup, name));
|
|
72771
73644
|
moved = true;
|
|
72772
73645
|
}
|
|
72773
73646
|
renameSync4(staging, target);
|
|
@@ -72775,9 +73648,9 @@ function installBundleAtomically(name, entries, options = {}, marker = {}) {
|
|
|
72775
73648
|
rmSync6(backup, { recursive: true, force: true });
|
|
72776
73649
|
} catch (error2) {
|
|
72777
73650
|
rmSync6(staging, { recursive: true, force: true });
|
|
72778
|
-
if (moved && backup &&
|
|
73651
|
+
if (moved && backup && existsSync29(join34(backup, name))) {
|
|
72779
73652
|
try {
|
|
72780
|
-
renameSync4(
|
|
73653
|
+
renameSync4(join34(backup, name), target);
|
|
72781
73654
|
} catch {}
|
|
72782
73655
|
}
|
|
72783
73656
|
throw error2;
|
|
@@ -72796,7 +73669,7 @@ function writePullMarker(dir, record3) {
|
|
|
72796
73669
|
...record3.revisionId ? { revisionId: record3.revisionId } : {},
|
|
72797
73670
|
syncedAt: new Date().toISOString()
|
|
72798
73671
|
};
|
|
72799
|
-
|
|
73672
|
+
writeFileSync20(join34(dir, PULL_MARKER_FILE), `${JSON.stringify(marker, null, 2)}
|
|
72800
73673
|
`);
|
|
72801
73674
|
}
|
|
72802
73675
|
async function safeMeta(client, slug) {
|
|
@@ -72870,12 +73743,12 @@ function registerRegistry(parent) {
|
|
|
72870
73743
|
async function writeJson2(value, space) {
|
|
72871
73744
|
const text = `${JSON.stringify(value, null, space)}
|
|
72872
73745
|
`;
|
|
72873
|
-
await new Promise((
|
|
73746
|
+
await new Promise((resolve4, reject2) => {
|
|
72874
73747
|
process.stdout.write(text, (error2) => {
|
|
72875
73748
|
if (error2)
|
|
72876
73749
|
reject2(error2);
|
|
72877
73750
|
else
|
|
72878
|
-
|
|
73751
|
+
resolve4();
|
|
72879
73752
|
});
|
|
72880
73753
|
});
|
|
72881
73754
|
}
|
|
@@ -72967,8 +73840,8 @@ __export(exports_publish, {
|
|
|
72967
73840
|
pushSkill: () => pushSkill,
|
|
72968
73841
|
PushSkillError: () => PushSkillError
|
|
72969
73842
|
});
|
|
72970
|
-
import { existsSync as
|
|
72971
|
-
import { join as
|
|
73843
|
+
import { existsSync as existsSync30, readFileSync as readFileSync26 } from "fs";
|
|
73844
|
+
import { join as join35 } from "path";
|
|
72972
73845
|
function registerPublish(parent) {
|
|
72973
73846
|
parent.command("push").argument("<name>", "Name of a skill in the local corpus (~/.hasna/skills/installed or the migrated ~/.hasna/skills/skills)").option("--version <version>", "Override the version recorded on the instance").option("--dry-run", "Pack and validate without uploading", false).option("--json", "Output result as JSON", false).description("Publish a local skill to the configured skills instance").action(async (name, options) => {
|
|
72974
73847
|
try {
|
|
@@ -73009,8 +73882,8 @@ async function pushSkill(name, options = {}) {
|
|
|
73009
73882
|
}
|
|
73010
73883
|
const manifest = readPortableSkillManifest(skill.path, skill.name);
|
|
73011
73884
|
const packed = packSkillBundle(skill.path, { maxUnpackedBytes: MAX_UNPACKED_BYTES });
|
|
73012
|
-
const skillMdPath =
|
|
73013
|
-
const skillMd =
|
|
73885
|
+
const skillMdPath = join35(skill.path, "SKILL.md");
|
|
73886
|
+
const skillMd = existsSync30(skillMdPath) ? readFileSync26(skillMdPath, "utf-8") : undefined;
|
|
73014
73887
|
const base2 = {
|
|
73015
73888
|
slug: skill.name,
|
|
73016
73889
|
path: skill.path,
|
|
@@ -73127,10 +74000,10 @@ __export(exports_auth, {
|
|
|
73127
74000
|
import { createInterface as createInterface2 } from "readline";
|
|
73128
74001
|
function prompt(question) {
|
|
73129
74002
|
const rl = createInterface2({ input: process.stdin, output: process.stdout });
|
|
73130
|
-
return new Promise((
|
|
74003
|
+
return new Promise((resolve4) => {
|
|
73131
74004
|
rl.question(question, (answer) => {
|
|
73132
74005
|
rl.close();
|
|
73133
|
-
|
|
74006
|
+
resolve4(answer.trim());
|
|
73134
74007
|
});
|
|
73135
74008
|
});
|
|
73136
74009
|
}
|
|
@@ -73280,7 +74153,7 @@ function printWhoami(payload) {
|
|
|
73280
74153
|
console.log(source_default.dim("(offline \u2014 showing cached info)"));
|
|
73281
74154
|
}
|
|
73282
74155
|
function sleep(ms) {
|
|
73283
|
-
return new Promise((
|
|
74156
|
+
return new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
73284
74157
|
}
|
|
73285
74158
|
function browserCommand(url) {
|
|
73286
74159
|
if (process.platform === "darwin")
|
|
@@ -73781,11 +74654,11 @@ var init_storage = __esm(() => {
|
|
|
73781
74654
|
});
|
|
73782
74655
|
|
|
73783
74656
|
// src/lib/registry-reconcile.ts
|
|
73784
|
-
import { existsSync as
|
|
73785
|
-
import { join as
|
|
74657
|
+
import { existsSync as existsSync31, readFileSync as readFileSync27, statSync as statSync19, writeFileSync as writeFileSync21 } from "fs";
|
|
74658
|
+
import { join as join36 } from "path";
|
|
73786
74659
|
function isDirectory2(path) {
|
|
73787
74660
|
try {
|
|
73788
|
-
return
|
|
74661
|
+
return statSync19(path).isDirectory();
|
|
73789
74662
|
} catch {
|
|
73790
74663
|
return false;
|
|
73791
74664
|
}
|
|
@@ -73793,15 +74666,15 @@ function isDirectory2(path) {
|
|
|
73793
74666
|
function migrationNeeded(options) {
|
|
73794
74667
|
if (options.rootDir)
|
|
73795
74668
|
return false;
|
|
73796
|
-
const appDir = options.homeDir ?
|
|
73797
|
-
return !(isOwnerLayoutMigrated(appDir) && isDirectory2(
|
|
74669
|
+
const appDir = options.homeDir ? join36(options.homeDir, ".hasna", "skills") : getDataDir();
|
|
74670
|
+
return !(isOwnerLayoutMigrated(appDir) && isDirectory2(join36(appDir, SKILLS_CACHE_DIRNAME)));
|
|
73798
74671
|
}
|
|
73799
74672
|
function readBaseline(skillDir) {
|
|
73800
|
-
const markerPath =
|
|
73801
|
-
if (!
|
|
74673
|
+
const markerPath = join36(skillDir, PULL_MARKER_FILE);
|
|
74674
|
+
if (!existsSync31(markerPath))
|
|
73802
74675
|
return;
|
|
73803
74676
|
try {
|
|
73804
|
-
const marker = JSON.parse(
|
|
74677
|
+
const marker = JSON.parse(readFileSync27(markerPath, "utf-8"));
|
|
73805
74678
|
return {
|
|
73806
74679
|
...typeof marker.contentHash === "string" && marker.contentHash ? { contentHash: marker.contentHash } : {},
|
|
73807
74680
|
...typeof marker.version === "string" && marker.version ? { version: marker.version } : {}
|
|
@@ -73811,11 +74684,11 @@ function readBaseline(skillDir) {
|
|
|
73811
74684
|
}
|
|
73812
74685
|
}
|
|
73813
74686
|
function readCursor(root) {
|
|
73814
|
-
const path =
|
|
73815
|
-
if (!
|
|
74687
|
+
const path = join36(root, SYNC_CURSOR_FILE);
|
|
74688
|
+
if (!existsSync31(path))
|
|
73816
74689
|
return { runCount: 0 };
|
|
73817
74690
|
try {
|
|
73818
|
-
const cursor = JSON.parse(
|
|
74691
|
+
const cursor = JSON.parse(readFileSync27(path, "utf-8"));
|
|
73819
74692
|
return { runCount: typeof cursor.runCount === "number" ? cursor.runCount : 0 };
|
|
73820
74693
|
} catch {
|
|
73821
74694
|
return { runCount: 0 };
|
|
@@ -73824,12 +74697,12 @@ function readCursor(root) {
|
|
|
73824
74697
|
function resolveCorpusRootReadOnly(options) {
|
|
73825
74698
|
if (options.rootDir)
|
|
73826
74699
|
return { root: options.rootDir, migrationPending: false };
|
|
73827
|
-
const appDir = options.homeDir ?
|
|
73828
|
-
const cache3 =
|
|
74700
|
+
const appDir = options.homeDir ? join36(options.homeDir, ".hasna", "skills") : getDataDirReadOnly();
|
|
74701
|
+
const cache3 = join36(appDir, SKILLS_CACHE_DIRNAME);
|
|
73829
74702
|
if (isOwnerLayoutMigrated(appDir) && isDirectory2(cache3)) {
|
|
73830
74703
|
return { root: cache3, migrationPending: false };
|
|
73831
74704
|
}
|
|
73832
|
-
return { root:
|
|
74705
|
+
return { root: join36(appDir, INSTALLED_SKILLS_DIRNAME), migrationPending: true };
|
|
73833
74706
|
}
|
|
73834
74707
|
function remoteRowToSkill(record3) {
|
|
73835
74708
|
const slug = typeof record3.slug === "string" ? record3.slug : typeof record3.name === "string" ? record3.name : undefined;
|
|
@@ -73843,7 +74716,7 @@ function remoteRowToSkill(record3) {
|
|
|
73843
74716
|
}
|
|
73844
74717
|
function recheckLocalSide(plannedLocal, localDir, ops = {
|
|
73845
74718
|
pack: (dir) => packSkillBundle(dir).sha256,
|
|
73846
|
-
exists:
|
|
74719
|
+
exists: existsSync31
|
|
73847
74720
|
}) {
|
|
73848
74721
|
let localNow;
|
|
73849
74722
|
try {
|
|
@@ -73961,7 +74834,7 @@ async function reconcileRegistry(options = {}) {
|
|
|
73961
74834
|
for (const slug of allSlugs) {
|
|
73962
74835
|
const local = locals.get(slug);
|
|
73963
74836
|
const remote = remotes.get(slug);
|
|
73964
|
-
const baseline = local ? readBaseline(
|
|
74837
|
+
const baseline = local ? readBaseline(join36(root, slug)) : undefined;
|
|
73965
74838
|
const { state, reason } = classifySkill(local, remote, baseline);
|
|
73966
74839
|
let { action, reason: actionReason } = resolveAction(state, direction, conflict);
|
|
73967
74840
|
if (state === "remote-only" && isDigestless(remote)) {
|
|
@@ -74020,7 +74893,7 @@ async function reconcileRegistry(options = {}) {
|
|
|
74020
74893
|
try {
|
|
74021
74894
|
await pushSkill(slug, { rootDir: root, client });
|
|
74022
74895
|
const pushed = locals.get(slug);
|
|
74023
|
-
writePullMarker(
|
|
74896
|
+
writePullMarker(join36(root, slug), {
|
|
74024
74897
|
skill: slug,
|
|
74025
74898
|
...pushed?.version ? { version: pushed.version } : {},
|
|
74026
74899
|
...pushed?.sha256 ? { contentHash: pushed.sha256 } : {},
|
|
@@ -74092,7 +74965,7 @@ async function reconcileRegistry(options = {}) {
|
|
|
74092
74965
|
runCount: readCursor(root).runCount + 1,
|
|
74093
74966
|
summary
|
|
74094
74967
|
};
|
|
74095
|
-
|
|
74968
|
+
writeFileSync21(join36(root, SYNC_CURSOR_FILE), `${JSON.stringify(cursor, null, 2)}
|
|
74096
74969
|
`);
|
|
74097
74970
|
return {
|
|
74098
74971
|
corpusRoot: root,
|
|
@@ -79222,19 +80095,15 @@ var import_react21 = __toESM(require_react(), 1);
|
|
|
79222
80095
|
// src/cli/index.tsx
|
|
79223
80096
|
init_esm();
|
|
79224
80097
|
|
|
79225
|
-
//
|
|
80098
|
+
// ../../node_modules/.bun/@hasna+events@0.1.16/node_modules/@hasna/events/dist/commander.js
|
|
79226
80099
|
import { chmod, mkdir, readFile, rename, writeFile } from "fs/promises";
|
|
79227
80100
|
import { Buffer as Buffer22 } from "buffer";
|
|
79228
80101
|
import { existsSync as existsSync2 } from "fs";
|
|
79229
80102
|
import { homedir } from "os";
|
|
79230
80103
|
import { join as join2 } from "path";
|
|
79231
80104
|
import { createHmac, timingSafeEqual } from "crypto";
|
|
79232
|
-
import { lookup as dnsLookup } from "dns/promises";
|
|
79233
|
-
import { isIP } from "net";
|
|
79234
80105
|
import { randomUUID } from "crypto";
|
|
79235
80106
|
import { spawn } from "child_process";
|
|
79236
|
-
import { request as nodeHttpRequest } from "http";
|
|
79237
|
-
import { request as nodeHttpsRequest } from "https";
|
|
79238
80107
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
79239
80108
|
function getPathValue(input, path) {
|
|
79240
80109
|
return path.split(".").reduce((value, part) => {
|
|
@@ -79637,214 +80506,6 @@ function signPayload(secret, timestamp, body) {
|
|
|
79637
80506
|
const digest = createHmac("sha256", secret).update(buildSignatureBase(timestamp, body)).digest("hex");
|
|
79638
80507
|
return `sha256=${digest}`;
|
|
79639
80508
|
}
|
|
79640
|
-
var DEFAULT_MAX_REDIRECTS = 5;
|
|
79641
|
-
var IPV4_PRIVATE_RANGES = [
|
|
79642
|
-
[0, 16777215],
|
|
79643
|
-
[167772160, 184549375],
|
|
79644
|
-
[1681915904, 1686110207],
|
|
79645
|
-
[2130706432, 2147483647],
|
|
79646
|
-
[2851995648, 2852061183],
|
|
79647
|
-
[2886729728, 2887778303],
|
|
79648
|
-
[3221225472, 3221225727],
|
|
79649
|
-
[3221225984, 3221226239],
|
|
79650
|
-
[3227017984, 3227018239],
|
|
79651
|
-
[3232235520, 3232301055],
|
|
79652
|
-
[3323068416, 3323199487],
|
|
79653
|
-
[3325256704, 3325256959],
|
|
79654
|
-
[3405803776, 3405804031],
|
|
79655
|
-
[3758096384, 4294967295]
|
|
79656
|
-
];
|
|
79657
|
-
var IPV6_SPECIAL_PREFIXES = [
|
|
79658
|
-
{ groups: [0, 0, 0, 0, 0, 0, 0, 0], bits: 128 },
|
|
79659
|
-
{ groups: [0, 0, 0, 0, 0, 0, 0, 1], bits: 128 },
|
|
79660
|
-
{ groups: [0, 0, 0, 0, 0, 65535, 0, 0], bits: 96 },
|
|
79661
|
-
{ groups: [100, 65435, 0, 0, 0, 0, 0, 0], bits: 96 },
|
|
79662
|
-
{ groups: [256, 0, 0, 0, 0, 0, 0, 0], bits: 64 },
|
|
79663
|
-
{ groups: [8193, 0, 0, 0, 0, 0, 0, 0], bits: 32 },
|
|
79664
|
-
{ groups: [8193, 2, 0, 0, 0, 0, 0, 0], bits: 48 },
|
|
79665
|
-
{ groups: [8193, 16, 0, 0, 0, 0, 0, 0], bits: 28 },
|
|
79666
|
-
{ groups: [8193, 3512, 0, 0, 0, 0, 0, 0], bits: 32 },
|
|
79667
|
-
{ groups: [8194, 0, 0, 0, 0, 0, 0, 0], bits: 16 },
|
|
79668
|
-
{ groups: [16383, 0, 0, 0, 0, 0, 0, 0], bits: 20 },
|
|
79669
|
-
{ groups: [64512, 0, 0, 0, 0, 0, 0, 0], bits: 7 },
|
|
79670
|
-
{ groups: [65152, 0, 0, 0, 0, 0, 0, 0], bits: 10 },
|
|
79671
|
-
{ groups: [65216, 0, 0, 0, 0, 0, 0, 0], bits: 10 },
|
|
79672
|
-
{ groups: [65280, 0, 0, 0, 0, 0, 0, 0], bits: 8 }
|
|
79673
|
-
];
|
|
79674
|
-
function isPrivateAddress(address) {
|
|
79675
|
-
const normalized = stripZoneId(address);
|
|
79676
|
-
const version = isIP(normalized);
|
|
79677
|
-
if (version === 4) {
|
|
79678
|
-
const integer = ipv4ToInt(normalized);
|
|
79679
|
-
if (integer === undefined)
|
|
79680
|
-
return true;
|
|
79681
|
-
return IPV4_PRIVATE_RANGES.some(([low, high]) => integer >= low && integer <= high);
|
|
79682
|
-
}
|
|
79683
|
-
if (version === 6) {
|
|
79684
|
-
const groups = ipv6Groups(normalized);
|
|
79685
|
-
if (!groups)
|
|
79686
|
-
return true;
|
|
79687
|
-
for (const prefix of IPV6_SPECIAL_PREFIXES) {
|
|
79688
|
-
if (!ipv6MatchesPrefix(groups, prefix.groups, prefix.bits))
|
|
79689
|
-
continue;
|
|
79690
|
-
if (prefix.bits === 96 && groups[5] === 65535) {
|
|
79691
|
-
return isPrivateAddress(ipv4IntToString(groups[6] << 16 | groups[7]));
|
|
79692
|
-
}
|
|
79693
|
-
if (prefix.bits === 16 && groups[0] === 8194) {
|
|
79694
|
-
return isPrivateAddress(ipv4IntToString(groups[1] << 16 | groups[2]));
|
|
79695
|
-
}
|
|
79696
|
-
return true;
|
|
79697
|
-
}
|
|
79698
|
-
return false;
|
|
79699
|
-
}
|
|
79700
|
-
return true;
|
|
79701
|
-
}
|
|
79702
|
-
async function resolveWebhookTarget(url, policy = {}) {
|
|
79703
|
-
const hostname = normalizeHostname(url.hostname);
|
|
79704
|
-
const allowlist = (policy.allowPrivateHosts ?? []).map((entry) => normalizeHostname(entry.toLowerCase()));
|
|
79705
|
-
if (allowlist.includes(hostname)) {
|
|
79706
|
-
const version2 = isIP(hostname);
|
|
79707
|
-
if (version2 === 4 || version2 === 6) {
|
|
79708
|
-
return { hostname, addresses: [hostname] };
|
|
79709
|
-
}
|
|
79710
|
-
const lookup2 = policy.lookup ?? defaultTargetLookup;
|
|
79711
|
-
let resolved2;
|
|
79712
|
-
try {
|
|
79713
|
-
resolved2 = await lookup2(hostname);
|
|
79714
|
-
} catch {
|
|
79715
|
-
throw new Error(`Webhook target ${hostname} could not be resolved`);
|
|
79716
|
-
}
|
|
79717
|
-
if (!Array.isArray(resolved2) || resolved2.length === 0) {
|
|
79718
|
-
throw new Error(`Webhook target ${hostname} resolved to no addresses`);
|
|
79719
|
-
}
|
|
79720
|
-
const addresses = resolved2.map((entry) => normalizeHostname(entry.address));
|
|
79721
|
-
return { hostname, addresses };
|
|
79722
|
-
}
|
|
79723
|
-
const version = isIP(hostname);
|
|
79724
|
-
if (version === 4 || version === 6) {
|
|
79725
|
-
if (isPrivateAddress(hostname)) {
|
|
79726
|
-
throw new Error(`Webhook target ${hostname} is a private or special-use address`);
|
|
79727
|
-
}
|
|
79728
|
-
return { hostname, addresses: [hostname] };
|
|
79729
|
-
}
|
|
79730
|
-
const lookup = policy.lookup ?? defaultTargetLookup;
|
|
79731
|
-
let resolved;
|
|
79732
|
-
try {
|
|
79733
|
-
resolved = await lookup(hostname);
|
|
79734
|
-
} catch {
|
|
79735
|
-
throw new Error(`Webhook target ${hostname} could not be resolved`);
|
|
79736
|
-
}
|
|
79737
|
-
if (!Array.isArray(resolved) || resolved.length === 0) {
|
|
79738
|
-
throw new Error(`Webhook target ${hostname} resolved to no addresses`);
|
|
79739
|
-
}
|
|
79740
|
-
const allowed = [];
|
|
79741
|
-
for (const entry of resolved) {
|
|
79742
|
-
const address = normalizeHostname(entry.address);
|
|
79743
|
-
if (isPrivateAddress(address)) {
|
|
79744
|
-
if (allowlist.includes(address)) {
|
|
79745
|
-
allowed.push(address);
|
|
79746
|
-
continue;
|
|
79747
|
-
}
|
|
79748
|
-
throw new Error(`Webhook target ${hostname} resolves to private or special-use address ${address}`);
|
|
79749
|
-
}
|
|
79750
|
-
allowed.push(address);
|
|
79751
|
-
}
|
|
79752
|
-
if (allowed.length === 0) {
|
|
79753
|
-
throw new Error(`Webhook target ${hostname} resolved to no public addresses`);
|
|
79754
|
-
}
|
|
79755
|
-
return { hostname, addresses: allowed };
|
|
79756
|
-
}
|
|
79757
|
-
function normalizeMaxRedirects(value) {
|
|
79758
|
-
if (value === undefined)
|
|
79759
|
-
return DEFAULT_MAX_REDIRECTS;
|
|
79760
|
-
if (!Number.isInteger(value) || value < 0)
|
|
79761
|
-
throw new Error("webhookTargetPolicy.maxRedirects must be a non-negative integer");
|
|
79762
|
-
return value;
|
|
79763
|
-
}
|
|
79764
|
-
var defaultTargetLookup = async (hostname) => {
|
|
79765
|
-
return dnsLookup(hostname, { all: true, verbatim: false });
|
|
79766
|
-
};
|
|
79767
|
-
function normalizeHostname(hostname) {
|
|
79768
|
-
const lower = hostname.toLowerCase();
|
|
79769
|
-
if (lower.startsWith("[") && lower.endsWith("]"))
|
|
79770
|
-
return lower.slice(1, -1);
|
|
79771
|
-
return lower;
|
|
79772
|
-
}
|
|
79773
|
-
function stripZoneId(address) {
|
|
79774
|
-
const percent = address.indexOf("%");
|
|
79775
|
-
return percent === -1 ? address : address.slice(0, percent);
|
|
79776
|
-
}
|
|
79777
|
-
function ipv4ToInt(address) {
|
|
79778
|
-
const parts = address.split(".");
|
|
79779
|
-
if (parts.length !== 4)
|
|
79780
|
-
return;
|
|
79781
|
-
let value = 0;
|
|
79782
|
-
for (const part of parts) {
|
|
79783
|
-
if (!/^\d{1,3}$/.test(part))
|
|
79784
|
-
return;
|
|
79785
|
-
const octet = Number(part);
|
|
79786
|
-
if (octet > 255)
|
|
79787
|
-
return;
|
|
79788
|
-
value = value << 8 | octet;
|
|
79789
|
-
}
|
|
79790
|
-
return value >>> 0;
|
|
79791
|
-
}
|
|
79792
|
-
function ipv4IntToString(integer) {
|
|
79793
|
-
return [
|
|
79794
|
-
integer >>> 24 & 255,
|
|
79795
|
-
integer >>> 16 & 255,
|
|
79796
|
-
integer >>> 8 & 255,
|
|
79797
|
-
integer & 255
|
|
79798
|
-
].join(".");
|
|
79799
|
-
}
|
|
79800
|
-
function ipv6Groups(address) {
|
|
79801
|
-
const raw = stripZoneId(address);
|
|
79802
|
-
const doubleColon = raw.indexOf("::");
|
|
79803
|
-
const headText = doubleColon === -1 ? raw : raw.slice(0, doubleColon);
|
|
79804
|
-
const tailText = doubleColon === -1 ? "" : raw.slice(doubleColon + 2);
|
|
79805
|
-
const parseGroups = (text) => {
|
|
79806
|
-
if (text === "")
|
|
79807
|
-
return [];
|
|
79808
|
-
const out = [];
|
|
79809
|
-
for (const part of text.split(":")) {
|
|
79810
|
-
if (part.includes(".")) {
|
|
79811
|
-
const v4 = ipv4ToInt(part);
|
|
79812
|
-
if (v4 === undefined)
|
|
79813
|
-
return;
|
|
79814
|
-
out.push(v4 >>> 16 & 65535, v4 & 65535);
|
|
79815
|
-
} else {
|
|
79816
|
-
if (!/^[0-9a-fA-F]{1,4}$/.test(part))
|
|
79817
|
-
return;
|
|
79818
|
-
out.push(parseInt(part, 16));
|
|
79819
|
-
}
|
|
79820
|
-
}
|
|
79821
|
-
return out;
|
|
79822
|
-
};
|
|
79823
|
-
const head2 = parseGroups(headText);
|
|
79824
|
-
if (!head2)
|
|
79825
|
-
return;
|
|
79826
|
-
const tail2 = parseGroups(tailText);
|
|
79827
|
-
if (!tail2)
|
|
79828
|
-
return;
|
|
79829
|
-
const total = head2.length + tail2.length;
|
|
79830
|
-
if (doubleColon === -1) {
|
|
79831
|
-
return total === 8 ? head2 : undefined;
|
|
79832
|
-
}
|
|
79833
|
-
if (total >= 8)
|
|
79834
|
-
return;
|
|
79835
|
-
return [...head2, ...new Array(8 - total).fill(0), ...tail2];
|
|
79836
|
-
}
|
|
79837
|
-
function ipv6MatchesPrefix(groups, prefixGroups, prefixBits) {
|
|
79838
|
-
let remaining = prefixBits;
|
|
79839
|
-
for (let index = 0;index < prefixGroups.length && remaining > 0; index += 1) {
|
|
79840
|
-
const take2 = Math.min(16, remaining);
|
|
79841
|
-
const mask = 65535 << 16 - take2 & 65535;
|
|
79842
|
-
if ((groups[index] & mask) !== (prefixGroups[index] & mask))
|
|
79843
|
-
return false;
|
|
79844
|
-
remaining -= take2;
|
|
79845
|
-
}
|
|
79846
|
-
return true;
|
|
79847
|
-
}
|
|
79848
80509
|
function now2() {
|
|
79849
80510
|
return new Date().toISOString();
|
|
79850
80511
|
}
|
|
@@ -79875,18 +80536,9 @@ function buildWebhookRequest(event, channel, options = {}) {
|
|
|
79875
80536
|
}
|
|
79876
80537
|
return { body, headers };
|
|
79877
80538
|
}
|
|
79878
|
-
function normalizeWebhookUrl(raw) {
|
|
79879
|
-
const url = new URL(raw);
|
|
79880
|
-
if (url.username !== "" || url.password !== "") {
|
|
79881
|
-
url.username = "";
|
|
79882
|
-
url.password = "";
|
|
79883
|
-
}
|
|
79884
|
-
return url.toString();
|
|
79885
|
-
}
|
|
79886
80539
|
async function dispatchWebhook(event, channel, options = {}) {
|
|
79887
80540
|
if (!channel.webhook)
|
|
79888
80541
|
throw new Error(`Channel ${channel.id} has no webhook config`);
|
|
79889
|
-
const webhookUrl = normalizeWebhookUrl(channel.webhook.url);
|
|
79890
80542
|
const startedAt = now2();
|
|
79891
80543
|
let secret = channel.webhook.secret;
|
|
79892
80544
|
if (channel.webhook.secretRef) {
|
|
@@ -79903,14 +80555,10 @@ async function dispatchWebhook(event, channel, options = {}) {
|
|
|
79903
80555
|
}
|
|
79904
80556
|
const timestamp = (options.now?.() ?? new Date).toISOString();
|
|
79905
80557
|
const { body, headers } = buildWebhookRequest(event, channel, { secret, timestamp });
|
|
79906
|
-
const validateTargets = options.webhookTargetPolicy !== undefined || options.fetchImpl === undefined;
|
|
79907
|
-
if (validateTargets) {
|
|
79908
|
-
return dispatchValidatedWebhook(event, channel, { body, headers, startedAt, options });
|
|
79909
|
-
}
|
|
79910
80558
|
const controller = new AbortController;
|
|
79911
80559
|
const timeout = setTimeout(() => controller.abort(), channel.webhook.timeoutMs ?? 15000);
|
|
79912
80560
|
try {
|
|
79913
|
-
const response = await (options.fetchImpl ?? fetch)(
|
|
80561
|
+
const response = await (options.fetchImpl ?? fetch)(channel.webhook.url, {
|
|
79914
80562
|
method: "POST",
|
|
79915
80563
|
headers,
|
|
79916
80564
|
body,
|
|
@@ -79938,130 +80586,6 @@ async function dispatchWebhook(event, channel, options = {}) {
|
|
|
79938
80586
|
clearTimeout(timeout);
|
|
79939
80587
|
}
|
|
79940
80588
|
}
|
|
79941
|
-
function isRedirectStatus(status) {
|
|
79942
|
-
return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
|
|
79943
|
-
}
|
|
79944
|
-
function redirectKeepsBody(status) {
|
|
79945
|
-
return status === 307 || status === 308;
|
|
79946
|
-
}
|
|
79947
|
-
async function pinnedNativeRequest(target, addresses, method2, headers, body, signal, tls) {
|
|
79948
|
-
const isHttps = target.protocol === "https:";
|
|
79949
|
-
if (!isHttps && target.protocol !== "http:") {
|
|
79950
|
-
throw new Error(`Webhook target uses unsupported protocol ${target.protocol}`);
|
|
79951
|
-
}
|
|
79952
|
-
const defaultPort = isHttps ? 443 : 80;
|
|
79953
|
-
const port = target.port ? Number(target.port) : defaultPort;
|
|
79954
|
-
const requestOptions = {
|
|
79955
|
-
hostname: target.hostname,
|
|
79956
|
-
port,
|
|
79957
|
-
path: `${target.pathname}${target.search}`,
|
|
79958
|
-
method: method2,
|
|
79959
|
-
headers,
|
|
79960
|
-
...tls?.ca ? { ca: tls.ca } : {},
|
|
79961
|
-
lookup: (hostname, _options, callback) => {
|
|
79962
|
-
const entries = addresses.map((address) => ({
|
|
79963
|
-
address,
|
|
79964
|
-
family: address.includes(":") ? 6 : 4
|
|
79965
|
-
}));
|
|
79966
|
-
callback(null, entries);
|
|
79967
|
-
}
|
|
79968
|
-
};
|
|
79969
|
-
return new Promise((resolve, reject2) => {
|
|
79970
|
-
const request = isHttps ? nodeHttpsRequest(requestOptions, onResponse) : nodeHttpRequest(requestOptions, onResponse);
|
|
79971
|
-
const onAbort = () => {
|
|
79972
|
-
const error = new Error("The operation was aborted.");
|
|
79973
|
-
error.name = "AbortError";
|
|
79974
|
-
request.destroy(error);
|
|
79975
|
-
};
|
|
79976
|
-
if (signal.aborted)
|
|
79977
|
-
onAbort();
|
|
79978
|
-
else
|
|
79979
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
79980
|
-
request.on("error", reject2);
|
|
79981
|
-
if (body !== undefined)
|
|
79982
|
-
request.write(body);
|
|
79983
|
-
request.end();
|
|
79984
|
-
function onResponse(response) {
|
|
79985
|
-
const chunks = [];
|
|
79986
|
-
response.on("data", (chunk2) => chunks.push(Buffer.from(chunk2)));
|
|
79987
|
-
response.on("error", reject2);
|
|
79988
|
-
response.on("end", () => {
|
|
79989
|
-
const headersRecord = {};
|
|
79990
|
-
for (const [name, value] of Object.entries(response.headers)) {
|
|
79991
|
-
if (typeof value === "string")
|
|
79992
|
-
headersRecord[name] = value;
|
|
79993
|
-
else if (Array.isArray(value))
|
|
79994
|
-
headersRecord[name] = value.join(", ");
|
|
79995
|
-
}
|
|
79996
|
-
resolve(new Response(Buffer.concat(chunks), { status: response.statusCode ?? 200, headers: headersRecord }));
|
|
79997
|
-
});
|
|
79998
|
-
}
|
|
79999
|
-
});
|
|
80000
|
-
}
|
|
80001
|
-
async function dispatchValidatedWebhook(event, channel, input) {
|
|
80002
|
-
const { body, headers, startedAt, options } = input;
|
|
80003
|
-
const webhook = channel.webhook;
|
|
80004
|
-
if (!webhook)
|
|
80005
|
-
throw new Error(`Channel ${channel.id} has no webhook config`);
|
|
80006
|
-
const policy = options.webhookTargetPolicy ?? {};
|
|
80007
|
-
const maxRedirects = normalizeMaxRedirects(policy.maxRedirects);
|
|
80008
|
-
const controller = new AbortController;
|
|
80009
|
-
const timeout = setTimeout(() => controller.abort(), webhook.timeoutMs ?? 15000);
|
|
80010
|
-
try {
|
|
80011
|
-
let target = new URL(normalizeWebhookUrl(webhook.url));
|
|
80012
|
-
let requestHeaders = headers;
|
|
80013
|
-
let method2 = "POST";
|
|
80014
|
-
let requestBody = body;
|
|
80015
|
-
let redirectsFollowed = 0;
|
|
80016
|
-
for (;; ) {
|
|
80017
|
-
const resolved = await resolveWebhookTarget(target, policy).catch((error) => {
|
|
80018
|
-
throw new Error(`Webhook target rejected by SSRF guard: ${error.message}`);
|
|
80019
|
-
});
|
|
80020
|
-
const response = options.fetchImpl ? await options.fetchImpl(target, {
|
|
80021
|
-
method: method2,
|
|
80022
|
-
headers: requestHeaders,
|
|
80023
|
-
body: requestBody,
|
|
80024
|
-
signal: controller.signal,
|
|
80025
|
-
redirect: "manual"
|
|
80026
|
-
}) : await pinnedNativeRequest(target, resolved.addresses, method2, requestHeaders, requestBody, controller.signal, options.tls);
|
|
80027
|
-
const location = response.headers.get("location");
|
|
80028
|
-
if (isRedirectStatus(response.status) && location) {
|
|
80029
|
-
if (redirectsFollowed >= maxRedirects) {
|
|
80030
|
-
return failedAttempt(startedAt, `Webhook target exceeded ${maxRedirects} redirects`);
|
|
80031
|
-
}
|
|
80032
|
-
redirectsFollowed += 1;
|
|
80033
|
-
const next = new URL(location, target);
|
|
80034
|
-
target = next;
|
|
80035
|
-
if (!redirectKeepsBody(response.status)) {
|
|
80036
|
-
method2 = "GET";
|
|
80037
|
-
requestBody = undefined;
|
|
80038
|
-
requestHeaders = Object.fromEntries(Object.entries(requestHeaders).filter(([name]) => name.toLowerCase() !== "content-type" && name.toLowerCase() !== "content-length"));
|
|
80039
|
-
}
|
|
80040
|
-
continue;
|
|
80041
|
-
}
|
|
80042
|
-
const responseBody = truncate2(await response.text());
|
|
80043
|
-
return {
|
|
80044
|
-
attempt: 1,
|
|
80045
|
-
status: response.ok ? "success" : "failed",
|
|
80046
|
-
startedAt,
|
|
80047
|
-
completedAt: now2(),
|
|
80048
|
-
responseStatus: response.status,
|
|
80049
|
-
responseBody,
|
|
80050
|
-
error: response.ok ? undefined : `Webhook returned HTTP ${response.status}`
|
|
80051
|
-
};
|
|
80052
|
-
}
|
|
80053
|
-
} catch (error) {
|
|
80054
|
-
return {
|
|
80055
|
-
attempt: 1,
|
|
80056
|
-
status: "failed",
|
|
80057
|
-
startedAt,
|
|
80058
|
-
completedAt: now2(),
|
|
80059
|
-
error: error instanceof Error ? error.message : String(error)
|
|
80060
|
-
};
|
|
80061
|
-
} finally {
|
|
80062
|
-
clearTimeout(timeout);
|
|
80063
|
-
}
|
|
80064
|
-
}
|
|
80065
80589
|
function failedAttempt(startedAt, error) {
|
|
80066
80590
|
return {
|
|
80067
80591
|
attempt: 1,
|
|
@@ -80271,9 +80795,7 @@ class EventsClient {
|
|
|
80271
80795
|
this.transportOptions = {
|
|
80272
80796
|
fetchImpl: options.fetchImpl,
|
|
80273
80797
|
secretResolver: options.secretResolver,
|
|
80274
|
-
now: options.now
|
|
80275
|
-
tls: options.tls,
|
|
80276
|
-
webhookTargetPolicy: options.webhookTargetPolicy
|
|
80798
|
+
now: options.now
|
|
80277
80799
|
};
|
|
80278
80800
|
this.catalog = options.catalog ?? defaultEventTypeCatalog;
|
|
80279
80801
|
this.validateCatalogTypes = options.validateCatalogTypes ?? false;
|
|
@@ -81904,6 +82426,8 @@ var { registerCompletion: registerCompletion2 } = await Promise.resolve().then((
|
|
|
81904
82426
|
registerCompletion2(program2);
|
|
81905
82427
|
var { registerCreateSync: registerCreateSync2 } = await Promise.resolve().then(() => (init_create_sync_config(), exports_create_sync_config));
|
|
81906
82428
|
registerCreateSync2(program2);
|
|
82429
|
+
var { registerHydrate: registerHydrate2 } = await Promise.resolve().then(() => (init_hydrate(), exports_hydrate));
|
|
82430
|
+
registerHydrate2(program2);
|
|
81907
82431
|
var { registerPortableSkillCommands: registerPortableSkillCommands2 } = await Promise.resolve().then(() => (init_portable_skills2(), exports_portable_skills));
|
|
81908
82432
|
registerPortableSkillCommands2(program2);
|
|
81909
82433
|
var { registerSchedule: registerSchedule2 } = await Promise.resolve().then(() => (init_schedule(), exports_schedule));
|