@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 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.70",
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
- // src/lib/config.ts
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 (!existsSync3(sourceDir))
38049
+ if (!existsSync4(sourceDir))
37932
38050
  return;
37933
38051
  mkdirSync(targetDir, { recursive: true });
37934
38052
  for (const entry of readdirSync(sourceDir)) {
37935
- const sourcePath = join3(sourceDir, entry);
37936
- const targetPath = join3(targetDir, entry);
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 (!existsSync3(targetPath))
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 existsSync3(join3(appDir, SKILLS_CACHE_DIRNAME, LAYOUT_MIGRATION_RECORD));
38087
+ return existsSync4(join5(appDir, SKILLS_CACHE_DIRNAME, LAYOUT_MIGRATION_RECORD));
37970
38088
  }
37971
38089
  function getDataDir() {
37972
- const override = process.env[DATA_DIR_ENV];
37973
- if (override) {
37974
- try {
37975
- mkdirSync(override, { recursive: true });
37976
- } catch {}
37977
- return override;
37978
- }
37979
- const home = process.env["HOME"] || process.env["USERPROFILE"] || homedir2();
37980
- const newDir = join3(home, ".hasna", "skills");
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, newDir);
38100
+ mergeDirectoryContents(oldDir, root);
37986
38101
  } catch {}
37987
- if (existsSync3(oldConfigFile) && !existsSync3(join3(newDir, "config.json"))) {
38102
+ if (existsSync4(oldConfigFile) && !existsSync4(join5(root, "config.json"))) {
37988
38103
  try {
37989
- copyFileSync(oldConfigFile, join3(newDir, "config.json"));
38104
+ copyFileSync(oldConfigFile, join5(root, "config.json"));
37990
38105
  } catch {}
37991
38106
  }
37992
- return newDir;
38107
+ return root;
37993
38108
  }
37994
38109
  function getDataDirReadOnly() {
37995
- const override = process.env[DATA_DIR_ENV];
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 join3(getDataDirReadOnly(), "config.json");
38003
- return join3(process.cwd(), "skills.config.json");
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 (existsSync3(canonicalConfigPath)) {
38120
+ if (existsSync4(canonicalConfigPath)) {
38009
38121
  globalConfig = readConfigFile(canonicalConfigPath);
38010
- } else if (process.env[DATA_DIR_ENV] !== undefined) {
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 join3(process.env["HOME"] || process.env["USERPROFILE"] || homedir2(), ".skillsrc");
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 join3(getDataDir(), "config.json");
38135
+ return join5(getDataDir(), "config.json");
38024
38136
  }
38025
- return join3(process.cwd(), "skills.config.json");
38137
+ return join5(process.cwd(), "skills.config.json");
38026
38138
  }
38027
38139
  function readConfigFile(path) {
38028
- if (!existsSync3(path))
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 (existsSync3(filePath)) {
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 (!existsSync3(dir)) {
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 (!existsSync3(filePath))
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, DATA_DIR_ENV = "HASNA_SKILLS_DIR", INSTALLED_SKILLS_DIRNAME = "installed", SKILLS_CACHE_DIRNAME = "skills", LAYOUT_MIGRATION_RECORD = ".layout-migration.json";
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 existsSync4, readFileSync as readFileSync3, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
38908
- import { join as join4 } from "path";
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 = join4(skillDir, "package.json");
38920
- if (!existsSync4(pkgPath))
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 existsSync5, lstatSync, readFileSync as readFileSync4, readdirSync as readdirSync3, statSync as statSync3 } from "fs";
38949
- import { isAbsolute, join as join5, normalize } from "path";
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 (!existsSync5(skillPath)) {
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 = join5(skillPath, entry);
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 (existsSync5(join5(skillPath, docFile)))
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 = join5(skillPath, "SKILL.md");
39072
- if (existsSync5(skillMdPath)) {
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 = join5(skillPath, "package.json");
39116
- if (!existsSync5(pkgPath)) {
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 = join5(skillPath, target);
39175
- if (!existsSync5(targetPath)) {
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 = join5(skillPath, "src");
39306
+ const srcDir = join7(skillPath, "src");
39193
39307
  if (hostedMetadata) {
39194
- if (existsSync5(srcDir)) {
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 (!existsSync5(srcDir)) {
39311
+ } else if (!existsSync6(srcDir)) {
39198
39312
  add2(issues, "skill.src_missing", "Missing src/ directory");
39199
- } else if (!existsSync5(join5(srcDir, "index.ts")) && !existsSync5(join5(srcDir, "index.js"))) {
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 = existsSync5(join5(srcDir, "index.ts")) ? join5(srcDir, "index.ts") : join5(srcDir, "index.js");
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 existsSync6, readdirSync as readdirSync4, readFileSync as readFileSync5, statSync as statSync4 } from "fs";
39274
- import { join as join6, sep } from "path";
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 = join6(skillPath, entry);
39321
- if (!existsSync6(absolute))
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 = join6(dir, entry);
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 existsSync7,
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 join7, relative } from "path";
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 = join7(skillPath, "skill.json");
39621
- const skillMdPath = join7(skillPath, "SKILL.md");
39622
- const pkgPath = join7(skillPath, "package.json");
39623
- const jsonManifest = existsSync7(skillJsonPath) ? readJsonObject(skillJsonPath) : undefined;
39624
- const frontmatter = existsSync7(skillMdPath) ? parseSkillFrontmatter(readFileSync6(skillMdPath, "utf-8")) ?? undefined : undefined;
39625
- const pkg = existsSync7(pkgPath) ? readJsonObject(pkgPath) : undefined;
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(join7(skillPath, "SKILL.md"), renderInstructionSkillMd(manifest));
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(join7(skillPath, "src"), { recursive: true });
39721
- writeFileSync2(join7(skillPath, "SKILL.md"), renderSkillMd(manifest));
39722
- writeFileSync2(join7(skillPath, "AGENTS.md"), renderAgentsMd(manifest));
39723
- writeFileSync2(join7(skillPath, "package.json"), renderPackageJson(manifest));
39724
- writeFileSync2(join7(skillPath, "tsconfig.json"), renderTsconfig());
39725
- writeFileSync2(join7(skillPath, "src", "index.ts"), renderEntrypoint(manifest));
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(join7(skillPath, "skill.json"), `${JSON.stringify({ ...existing, ...renderSkillJsonObject(withoutHash) }, null, 2)}
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(join7(skillPath, "skill.json"), `${JSON.stringify({ ...existing, ...renderSkillJsonObject(withHash) }, null, 2)}
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 = join7(skillPath, "skill.json");
39766
- if (!existsSync7(path))
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 && !existsSync7(join7(skillPath, entry))) {
39800
- mkdirSync2(dirname2(join7(skillPath, entry)), { recursive: true });
39801
- writeFileSync2(join7(skillPath, entry), renderEntrypoint(next));
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 (!existsSync7(join7(skillPath, "SKILL.md")))
39804
- writeFileSync2(join7(skillPath, "SKILL.md"), renderSkillMd(next));
39917
+ if (!existsSync8(join9(skillPath, "SKILL.md")))
39918
+ writeFileSync2(join9(skillPath, "SKILL.md"), renderSkillMd(next));
39805
39919
  else
39806
- writeFileSync2(join7(skillPath, "SKILL.md"), ensureSkillMdFrontmatter(readFileSync6(join7(skillPath, "SKILL.md"), "utf-8"), next));
39807
- if (!existsSync7(join7(skillPath, "AGENTS.md")))
39808
- writeFileSync2(join7(skillPath, "AGENTS.md"), renderAgentsMd(next));
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 (!existsSync7(join7(skillPath, "tsconfig.json")))
39811
- writeFileSync2(join7(skillPath, "tsconfig.json"), renderTsconfig());
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 = join7(skillPath, "package.json");
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 (!existsSync7(pkgPath)) {
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 (!existsSync7(join7(skillPath, "SKILL.md"))) {
39864
- writeFileSync2(join7(skillPath, "SKILL.md"), renderSkillMd(next));
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 existsSync8,
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 join8, normalize as normalize2 } from "path";
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 ? join8(options.homeDir, ".hasna", "skills") : getDataDir();
40185
- const cache3 = join8(appDir, SKILLS_CACHE_DIRNAME);
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 = join8(appDir, INSTALLED_SKILLS_DIRNAME);
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 existsSync8(join8(path, "SKILL.md")) || existsSync8(join8(path, "skill.json")) || existsSync8(join8(path, "package.json"));
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 = join8(appDir, entry);
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 = join8(path, nested);
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 = join8(installed, name);
40228
- if (existsSync8(target))
40341
+ const target = join10(installed, name);
40342
+ if (existsSync9(target))
40229
40343
  continue;
40230
- const staging = join8(installed, `.migrating-${name}-${process.pid}`);
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 join8(getPortableSkillsRoot(options), normalizePortableSkillName(name));
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 (!existsSync8(path) || !statSync6(path).isDirectory())
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 = join8(root, entry);
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 = join8(root, skillName);
40303
- if (existsSync8(skillPath)) {
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 (!existsSync8(absoluteSource) || !statSync6(absoluteSource).isDirectory()) {
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 = join8(absoluteSource, entryName);
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 existsSync8(join8(dir, "SKILL.md")) || existsSync8(join8(dir, "skill.json")) || existsSync8(join8(dir, "package.json"));
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 (!existsSync8(absoluteSource) || !statSync6(absoluteSource).isDirectory()) {
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 = join8(root, skillName);
40380
- if (existsSync8(destination)) {
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 = join8(root, name);
40423
- const created = !existsSync8(target);
40536
+ const target = join10(root, name);
40537
+ const created = !existsSync9(target);
40424
40538
  mkdirSync3(root, { recursive: true });
40425
- const staging = mkdtempSync(join8(root, `.pull-${name}-`));
40539
+ const staging = mkdtempSync(join10(root, `.pull-${name}-`));
40426
40540
  let moved = false;
40427
40541
  let backup = null;
40428
40542
  try {
40429
- writeFileSync3(join8(staging, "SKILL.md"), input.skillMd);
40543
+ writeFileSync3(join10(staging, "SKILL.md"), input.skillMd);
40430
40544
  const manifest = buildCorpusManifest(input, name);
40431
40545
  writeSkillJsonWithHash(staging, manifest);
40432
- if (existsSync8(target)) {
40433
- backup = mkdtempSync(join8(root, `.pull-backup-${name}-`));
40434
- renameSync(target, join8(backup, name));
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 && existsSync8(join8(backup, name))) {
40557
+ if (moved && backup && existsSync9(join10(backup, name))) {
40444
40558
  try {
40445
- renameSync(join8(backup, name), target);
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 (existsSync8(skillPath)) {
40458
- const skillJsonPath = join8(skillPath, "skill.json");
40459
- const skillMdPath = join8(skillPath, "SKILL.md");
40460
- if (!existsSync8(skillJsonPath) && !existsSync8(skillMdPath)) {
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: existsSync8(join8(skillPath, "skill.json")),
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 = join8(skillPath, command.entry);
40516
- if (!existsSync8(entryPath))
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" && !existsSync8(join8(skillPath, "AGENTS.md"))) {
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 existsSync9, readFileSync as readFileSync7, readdirSync as readdirSync6 } from "fs";
40796
- import { join as join9 } from "path";
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 (!existsSync9(dir))
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 = join9(dir, entry.name, "SKILL.md");
40841
- if (!existsSync9(skillMdPath))
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(join9(dir, entry.name)) ? { serverOwned: true } : {},
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 || !existsSync9(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 = join9(config.extensionsDir, entry.name);
40877
- const skillMdPath = join9(skillDir, "SKILL.md");
40878
- if (!existsSync9(skillMdPath))
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 dataDir = getDataDir();
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(join9(dataDir, "custom"));
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 existsSync10, mkdirSync as mkdirSync4, readdirSync as readdirSync7, renameSync as renameSync2, rmSync as rmSync2, statSync as statSync7, writeFileSync as writeFileSync4 } from "fs";
42611
- import { join as join10 } from "path";
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 join10(appDir, SKILLS_CACHE_DIRNAME, LAYOUT_MIGRATION_RECORD);
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 ? join10(homeDir, ".hasna", "skills") : getDataDir();
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 existsSync10(join10(path, "SKILL.md")) || existsSync10(join10(path, "skill.json")) || existsSync10(join10(path, "package.json"));
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 (!existsSync10(appDir))
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(join10(appDir, entry)))
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 = join10(appDir, name);
42654
- if (!existsSync10(dir)) {
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 = join10(appDir, SKILLS_CACHE_DIRNAME);
42663
- const installed = join10(appDir, INSTALLED_SKILLS_DIRNAME);
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 (existsSync10(cache3)) {
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 = existsSync10(installed);
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 (!existsSync10(dir))
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 (existsSync10(cache3)) {
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(join10(appDir, name), join10(cache3, name));
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 existsSync11,
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 homedir3 } from "os";
42758
- import { basename as basename3, dirname as dirname4, join as join11 } from "path";
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 = homedir3()) {
42884
+ function agentGlobalSkillsDir(agent, homeDir = homedir5()) {
42771
42885
  switch (agent) {
42772
42886
  case "opencode":
42773
- return join11(homeDir, ".config", "opencode", "skills");
42887
+ return join13(homeDir, ".config", "opencode", "skills");
42774
42888
  default:
42775
- return join11(homeDir, `.${agent}`, "skills");
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 = join11(source, sub);
42834
- if (existsSync11(candidate) && isDirectory(candidate))
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 = join11(path, entry);
42963
+ const candidate = join13(path, entry);
42850
42964
  if (!isDirectory(candidate))
42851
42965
  return false;
42852
- return existsSync11(join11(candidate, "SKILL.md")) || existsSync11(join11(candidate, "skill.json")) || existsSync11(join11(candidate, "package.json"));
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 ?? homedir3();
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: join11(agentGlobalSkillsDir(agent, homeDir), name, "SKILL.md"),
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 ?? homedir3();
42921
- const dir = join11(agentGlobalSkillsDir(params.agent, homeDir), params.skill);
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 = join11(dir, "SKILL.md");
42939
- const markerPath = join11(dir, SYNC_MARKER_FILE);
42940
- const dirExists = existsSync11(dir);
42941
- const managed = existsSync11(markerPath);
42942
- const hasSkillMd = existsSync11(skillMdPath);
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(join11(parentDir, `.hasna-skills-write-${basename3(dir)}-`));
42978
- const candidateDir = join11(transactionDir, "candidate");
42979
- const backupDir = join11(transactionDir, "backup");
42980
- const candidateSkillMdPath = join11(candidateDir, "SKILL.md");
42981
- const candidateMarkerPath = join11(candidateDir, SYNC_MARKER_FILE);
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 && existsSync11(backupDir)) {
43122
+ if (originalMoved && existsSync12(backupDir)) {
43009
43123
  try {
43010
- if (existsSync11(dir))
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 = join11(skillPath, "SKILL.md");
43032
- if (existsSync11(skillMdPath))
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 existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "fs";
43070
- import { join as join12 } from "path";
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 join12(targetDir, SKILLS_PROJECT_DIR);
43186
+ return join14(targetDir, SKILLS_PROJECT_DIR);
43073
43187
  }
43074
43188
  function getProjectConfigPath(targetDir = process.cwd()) {
43075
- return join12(getProjectStateDir(targetDir), PROJECT_CONFIG_FILE);
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 (!existsSync12(path))
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 existsSync13, readFileSync as readFileSync10, rmSync as rmSync4 } from "fs";
43237
- import { dirname as dirname5, join as join13 } from "path";
43238
- import { homedir as homedir4 } from "os";
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 = join13(dir, "skills");
43244
- if (existsSync13(candidate) && !dir.includes(".skills"))
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 join13(__dirname2, "..", "skills");
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 = join13(getDataDir(), "custom", skillName);
43256
- if (existsSync13(legacyCustomPath))
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 join13(SKILLS_DIR, skillName);
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 existsSync13(getSkillPath(name));
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 (!existsSync13(getSkillPath(name))) {
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 (!existsSync13(getSkillPath(name))) {
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 (!existsSync13(sourcePath))
43458
+ if (!existsSync14(sourcePath))
43345
43459
  return null;
43346
43460
  let skillMd = "";
43347
- const skillMdPath = join13(sourcePath, "SKILL.md");
43348
- if (existsSync13(skillMdPath)) {
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" ? join13(base2, ".pi", "skills") : join13(homedir4(), ".pi", "agent", "skills");
43543
+ return scope === "project" ? join15(base2, ".pi", "skills") : join15(homedir6(), ".pi", "agent", "skills");
43430
43544
  case "opencode":
43431
- return scope === "project" ? join13(base2, ".opencode", "skills") : join13(homedir4(), ".config", "opencode", "skills");
43545
+ return scope === "project" ? join15(base2, ".opencode", "skills") : join15(homedir6(), ".config", "opencode", "skills");
43432
43546
  default:
43433
- return scope === "project" ? join13(base2, `.${agent}`, "skills") : join13(homedir4(), `.${agent}`, "skills");
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 join13(getAgentSkillsDir(agent, scope, projectDir), skillName);
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 (!existsSync13(getSkillPath(name))) {
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 (!existsSync13(join13(dir, SYNC_MARKER_FILE)))
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 = join13(sourcePath, "SKILL.md");
43474
- if (existsSync13(skillMdPath))
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 (!existsSync13(sourcePath))
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(join13(sourcePath, "README.md")) || readFileIfExists(join13(sourcePath, "CLAUDE.md"));
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 = join13(getSkillPath(name), "package.json");
43528
- if (!existsSync13(pkgPath))
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 existsSync13(path) ? readFileSync10(path, "utf-8") : null;
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 existsSync14, mkdirSync as mkdirSync7, readFileSync as readFileSync11, writeFileSync as writeFileSync7, unlinkSync } from "fs";
47658
- import { dirname as dirname6, join as join14 } from "path";
47659
- import { homedir as homedir5 } from "os";
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 join14(getDataDir(), "auth.json");
47775
+ return join16(getDataDir(), "auth.json");
47662
47776
  }
47663
47777
  function getAuthFilePathReadOnly() {
47664
- return join14(getDataDirReadOnly(), "auth.json");
47778
+ return join16(getDataDirReadOnly(), "auth.json");
47665
47779
  }
47666
47780
  function legacyAuthFilePath() {
47667
- return join14(process.env["HOME"] || process.env["USERPROFILE"] || homedir5(), ".skills", "auth.json");
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 = existsSync14(getAuthFilePath()) ? getAuthFilePath() : legacyAuthFilePath();
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 = existsSync14(getAuthFilePathReadOnly()) ? getAuthFilePathReadOnly() : legacyAuthFilePath();
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((resolve, reject2) => {
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
- resolve();
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 existsSync15, readFileSync as readFileSync12 } from "fs";
48606
- import { join as join15 } from "path";
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 = join15(skillPath, "SKILL.md");
48611
- if (!existsSync15(skillMdPath))
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 (!existsSync15(skillPath))
48735
+ if (!existsSync16(skillPath))
48622
48736
  return null;
48623
48737
  return {
48624
- skillMd: readIfExists(join15(skillPath, "SKILL.md")),
48625
- readme: readIfExists(join15(skillPath, "README.md")),
48626
- claudeMd: readIfExists(join15(skillPath, "CLAUDE.md"))
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 (!existsSync15(skillPath))
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(join15(skillPath, file));
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 = join15(skillPath, "package.json");
48681
- if (existsSync15(pkgPath)) {
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 (existsSync15(join15(dir, "node_modules", pkgName, "package.json")))
48814
+ if (existsSync16(join17(dir, "node_modules", pkgName, "package.json")))
48701
48815
  return true;
48702
- const parent = join15(dir, "..");
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 (!existsSync15(skillPath)) {
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 = join15(skillPath, "package.json");
48732
- if (!existsSync15(pkgPath)) {
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 = join15(skillPath, entryPoint);
48752
- if (!existsSync15(entryPath)) {
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 = join15(skillPath, "node_modules");
48756
- if (!existsSync15(nodeModules)) {
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 = join15(cwd2, "package.json");
48784
- if (!existsSync15(pkgPath)) {
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 (!existsSync15(skillPath))
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(join15(skillPath, "README.md"));
48921
- const claudeMd = readIfExists(join15(skillPath, "CLAUDE.md"));
49034
+ const readme = readIfExists(join17(skillPath, "README.md"));
49035
+ const claudeMd = readIfExists(join17(skillPath, "CLAUDE.md"));
48922
49036
  let cliCommand = null;
48923
- const pkgPath = join15(skillPath, "package.json");
48924
- if (existsSync15(pkgPath)) {
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 (existsSync15(path)) {
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 existsSync16, readFileSync as readFileSync13 } from "fs";
49036
- import { join as join16 } from "path";
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 = join16(resolveCorpusRoot(), normalized);
49258
- const canonicalSkillMd = join16(canonicalDir, "SKILL.md");
49371
+ const canonicalDir = join18(resolveCorpusRoot(), normalized);
49372
+ const canonicalSkillMd = join18(canonicalDir, "SKILL.md");
49259
49373
  const canonical = {
49260
- present: existsSync16(canonicalSkillMd),
49374
+ present: existsSync17(canonicalSkillMd),
49261
49375
  path: canonicalDir,
49262
- ...existsSync16(canonicalSkillMd) ? { hash: hashSkillMarkdownFile(canonicalSkillMd) } : {},
49263
- ...existsSync16(canonicalSkillMd) ? { stub: isPointerSkillMd(readFileSync13(canonicalSkillMd, "utf-8")) } : {}
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 = join16(sourcePath, "package.json");
49382
+ const registryPkgPath = join18(sourcePath, "package.json");
49269
49383
  let registryVersion = "unknown";
49270
- if (existsSync16(registryPkgPath)) {
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 = join16(agentGlobalSkillsDir(agent), normalized);
49279
- const present = existsSync16(dir);
49280
- const managed = existsSync16(join16(dir, SYNC_MARKER_FILE));
49281
- const skillMdPath = join16(dir, "SKILL.md");
49282
- const hash = present && existsSync16(skillMdPath) ? hashSkillMarkdownFile(skillMdPath) : undefined;
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 && existsSync16(skillMdPath)) {
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 existsSync17, readFileSync as readFileSync14, writeFileSync as writeFileSync8, appendFileSync } from "fs";
49820
- import { join as join17 } from "path";
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(join17(cwd2, ".env.example"), lines.join(`
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 = join17(cwd2, ".gitignore");
50026
+ const gitignorePath = join19(cwd2, ".gitignore");
49913
50027
  const gitignoreEntries = [".skills/runs/", ".skills/exports/", ".skills/tmp/"];
49914
- let gitignoreContent = existsSync17(gitignorePath) ? readFileSync14(gitignorePath, "utf-8") : "";
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 (!existsSync17(file)) {
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 existsSync18, mkdirSync as mkdirSync8, readdirSync as readdirSync9, readFileSync as readFileSync15, rmSync as rmSync5, statSync as statSync9, writeFileSync as writeFileSync9 } from "fs";
50067
- import { homedir as homedir6 } from "os";
50068
- import { join as join18 } from "path";
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 (!existsSync18(corpusRoot))
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 = join18(corpusRoot, entry, "SKILL.md");
50083
- if (!existsSync18(skillMd))
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 ?? homedir6();
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 (!existsSync18(home))
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 = join18(home, skill);
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 (existsSync18(join18(dir, SYNC_MARKER_FILE))) {
50231
+ if (existsSync19(join20(dir, SYNC_MARKER_FILE))) {
50118
50232
  scan.managed += 1;
50119
50233
  continue;
50120
50234
  }
50121
- const skillMdPath = join18(dir, "SKILL.md");
50122
- if (!existsSync18(skillMdPath))
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 = join18(appDir, CONFLICTS_LEDGER_FILE);
50256
+ const ledgerPath = join20(appDir, CONFLICTS_LEDGER_FILE);
50143
50257
  let ledger = { version: 1, entries: [] };
50144
- if (existsSync18(ledgerPath)) {
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 = join18(appDir, ROLLBACK_DIRNAME);
50276
+ const dir = join20(appDir, ROLLBACK_DIRNAME);
50163
50277
  mkdirSync8(dir, { recursive: true });
50164
- const file = join18(dir, `${mode}-${Date.now()}.json`);
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 ? join18(options.homeDir, ".hasna", "skills") : getDataDir();
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(join18(entry.path, SYNC_MARKER_FILE), `${JSON.stringify(marker, null, 2)}
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 ?? homedir6();
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 (!existsSync18(home))
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 = join18(home, skill);
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 = join18(dir, SYNC_MARKER_FILE);
50221
- if (!existsSync18(markerPath))
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 = join18(dir, "SKILL.md");
50235
- const hash = existsSync18(skillMdPath) ? hashSkillMarkdownFile(skillMdPath) : "";
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 ? join18(options.homeDir, ".hasna", "skills") : getDataDir();
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 existsSync19, readFileSync as readFileSync16, readdirSync as readdirSync10, statSync as statSync10 } from "fs";
50259
- import { homedir as homedir7 } from "os";
50260
- import { join as join19 } from "path";
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 ?? homedir7();
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 (!existsSync19(home))
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 = join19(home, skill);
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 = join19(dir, SYNC_MARKER_FILE);
50301
- if (!existsSync19(markerPath)) {
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 = join19(dir, "SKILL.md");
50312
- if (!existsSync19(skillMdPath)) {
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 = join19(corpusRoot, skill, "SKILL.md");
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: join19(home, name),
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 existsSync20, readFileSync as readFileSync17, readdirSync as readdirSync11, statSync as statSync11, writeFileSync as writeFileSync10 } from "fs";
50367
- import { join as join20 } from "path";
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 = join20(cwd2, ".env");
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 = existsSync20(envFilePath) ? readFileSync17(envFilePath, "utf-8") : "";
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 = existsSync20(agentSkillsPath);
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(join20(agentSkillsPath, f)).isDirectory()).length;
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 = join20(registryPath, "package.json");
50723
+ const registryPkgPath = join22(registryPath, "package.json");
50610
50724
  let registryVersion = "unknown";
50611
- if (existsSync20(registryPkgPath))
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 existsSync21, mkdirSync as mkdirSync9, readFileSync as readFileSync18, readdirSync as readdirSync12, statSync as statSync12, writeFileSync as writeFileSync11 } from "fs";
50878
- import { extname, join as join21, relative as relative2 } from "path";
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 = join21(root, "runs", day, id);
50886
- const logsDir = join21(runDir, "logs");
50887
- const exportDir = join21(root, "exports", skillName, id);
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(join21(root, "tmp"), { recursive: true });
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(join21(context.logsDir, "stdout.log"), stdout);
50942
- writeFileSync11(join21(context.logsDir, "stderr.log"), stderr);
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 = join21(context.runDir, "events.ndjson");
50948
- const previous = existsSync21(path) ? readFileSync18(path, "utf-8") : "";
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 = join21(getProjectStateDir(targetDir), "runs");
50953
- if (!existsSync21(runsRoot))
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 = join21(runsRoot, day);
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(join21(dayDir, runId));
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 = join21(getProjectStateDir(targetDir), "runs");
50972
- if (!existsSync21(runsRoot))
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(join21(runsRoot, day, runId));
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 join21(getProjectStateDir(targetDir), "exports", normalizeSkillName(skill), runId);
51106
+ return join23(getProjectStateDir(targetDir), "exports", normalizeSkillName(skill), runId);
50993
51107
  }
50994
51108
  function writeRunRecord(context) {
50995
- writeFileSync11(join21(context.runDir, "run.json"), JSON.stringify(context.record, null, 2) + `
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(join21(context.runDir, "artifacts.json"), JSON.stringify({ runId: context.record.id, artifacts }, null, 2) + `
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 (!existsSync21(context.exportDir))
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 = join21(runDir, "run.json");
51020
- if (!existsSync21(path))
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 = join21(dir, entry);
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((resolve) => {
56715
+ return new Promise((resolve2) => {
56602
56716
  const json = serializeMessage(message);
56603
56717
  if (this._stdout.write(json)) {
56604
- resolve();
56718
+ resolve2();
56605
56719
  } else {
56606
- this._stdout.once("drain", resolve);
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((resolve) => setTimeout(resolve, pollInterval));
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((resolve, reject2) => {
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
- resolve(parseResult.data);
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((resolve, reject2) => {
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(resolve, interval);
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 = resolve.call(this, root, ref);
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 resolve(root, ref) {
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, isIP2) {
62372
- const re = isIP2 ? HOST_DELIM_NO_COLON_RE : HOST_DELIM_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 resolve(baseURI, relativeURI, options) {
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 isIP2 = false;
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
- isIP2 = ipv6result.isIPV6;
62984
+ isIP = ipv6result.isIPV6;
62871
62985
  } else {
62872
- isIP2 = true;
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) && isIP2 === false && nonSimpleDomain(parsed.host)) {
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), isIP2);
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((resolve) => setTimeout(resolve, pollInterval));
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 existsSync22, readdirSync as readdirSync13, statSync as statSync13 } from "fs";
68683
- import { join as join22 } from "path";
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 = existsSync22(agentSkillsPath);
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 = join22(agentSkillsPath, f);
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 existsSync23, mkdirSync as mkdirSync10 } from "fs";
69143
- import { dirname as dirname7, join as join23 } from "path";
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 join23(getDataDir(), "skills.db");
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 (!existsSync23(dir))
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 existsSync24, readFileSync as readFileSync19, writeFileSync as writeFileSync12, mkdirSync as mkdirSync11 } from "fs";
69326
- import { join as join24 } from "path";
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 join24(targetDir, ".skills", "schedules.json");
69442
+ return join26(targetDir, ".skills", "schedules.json");
69329
69443
  }
69330
69444
  function loadSchedules(targetDir = process.cwd()) {
69331
69445
  const path = getSchedulesPath(targetDir);
69332
- if (existsSync24(path)) {
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 = join24(targetDir, ".skills");
69342
- if (!existsSync24(dir))
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 existsSync25,
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 join25, normalize as normalize3, relative as relative3, sep as sep2 } from "path";
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: join25(getDataDir(), "skills.db")
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 (existsSync25(projectStateDir)) {
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 = join25(dir, entry);
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 init_dist = __esm(() => {
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
- init_dist();
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 existsSync26, mkdirSync as mkdirSync13, readFileSync as readFileSync21, writeFileSync as writeFileSync14 } from "fs";
70321
- import { homedir as homedir8 } from "os";
70322
- import { dirname as dirname9, join as join26 } from "path";
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, join26(homedir8(), ".gemini", "settings.json"), "mcpServers", {
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, join26(homedir8(), ".pi", "agent", "mcp.json"), "mcpServers", {
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, join26(homedir8(), ".cursor", "mcp.json"), "mcpServers", {
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, join26(homedir8(), ".windsurf", "mcp.json"), "mcpServers", {
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", join26(homedir8(), ".claude", ".mcp.json"), "mcpServers", {
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", join26(homedir8(), ".claude", ".mcp.json"), "mcpServers", {
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 = join26(homedir8(), ".codex", "config.toml");
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 = existsSync26(path) ? readFileSync21(path, "utf-8") : "";
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 = join26(homedir8(), ".config", "opencode", "opencode.json");
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 (!existsSync26(path))
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 = join26(dir, command);
70528
- if (existsSync26(candidate))
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 join27 } from "path";
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((resolve) => {
70787
+ return new Promise((resolve2) => {
70674
70788
  rl.question(source_default.bold(question), (answer) => {
70675
70789
  rl.close();
70676
- resolve(answer.trim());
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 = join27(exportDir, relativePath);
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((resolve) => setTimeout(resolve, Math.min(options.intervalMs, remaining)));
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 existsSync27, writeFileSync as writeFileSync16, mkdirSync as mkdirSync15 } from "fs";
71404
- import { join as join28 } from "path";
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: existsSync27(gp) },
71471
- project: { path: pp, exists: existsSync27(pp) }
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}${existsSync27(gp) ? source_default.green(" (exists)") : source_default.dim(" (not found)")}`);
71476
- console.log(`${source_default.cyan("project")}: ${pp}${existsSync27(pp) ? source_default.green(" (exists)") : source_default.dim(" (not found)")}`);
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 baseDir = getPortableSkillsRoot();
71485
- const skillDir = join28(baseDir, dirName);
71486
- if (existsSync27(skillDir)) {
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
- mkdirSync15(join28(skillDir, "src"), { recursive: true });
71495
- writeFileSync16(join28(skillDir, "SKILL.md"), [
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
- writeFileSync16(join28(skillDir, "src", "index.ts"), [`#!/usr/bin/env bun`, `/**`, ` * ${displayName2} \u2014 ${description}`, ` */`, "", `console.log("${displayName2}");`, ""].join(`
71961
+ writeFileSync17(join31(skillDir, "src", "index.ts"), [`#!/usr/bin/env bun`, `/**`, ` * ${displayName2} \u2014 ${description}`, ` */`, "", `console.log("${displayName2}");`, ""].join(`
71516
71962
  `));
71517
- writeFileSync16(join28(skillDir, "package.json"), JSON.stringify({ name: bare, version: "0.1.0", description, bin: { [bare]: "./src/index.ts" }, scripts: { dev: `bun src/index.ts` }, dependencies: {} }, null, 2) + `
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
- writeFileSync16(join28(skillDir, "tsconfig.json"), JSON.stringify({ compilerOptions: { target: "ES2022", module: "ESNext", moduleResolution: "bundler", strict: true, outDir: "dist" }, include: ["src/**/*.ts"] }, null, 2) + `
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:")} ${join28(skillDir, "src", "index.ts")}`);
71529
- console.log(` ${source_default.cyan("Run:")} bun ${join28(skillDir, "src", "index.ts")}`);
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 mkdirSync16, writeFileSync as writeFileSync17 } from "fs";
72035
- import { dirname as dirname11, relative as relative4 } from "path";
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 = relative4(process.cwd(), skillPath) || skillPath;
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
- mkdirSync16(dirname11(path), { recursive: true });
72093
- writeFileSync17(path, `${JSON.stringify(artifact, null, 2)}
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 createHash4 } from "crypto";
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 createHash4("sha256").update(canonical).digest("hex");
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 createHash5 } from "crypto";
72136
- import { readFileSync as readFileSync22, readdirSync as readdirSync15, statSync as statSync15 } from "fs";
72137
- import { join as join29, relative as relative5 } from "path";
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 createHash5("sha256").update(bytes).digest("hex");
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 readdirSync15(current, { withFileTypes: true })) {
72175
- const absolute = join29(current, entry.name);
72176
- const rel = relative5(root, absolute).split("\\").join("/");
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 = statSync15(absolute);
73069
+ const stats = statSync18(absolute);
72197
73070
  out.push({
72198
73071
  path: rel,
72199
- bytes: ownBytes(readFileSync22(absolute)),
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 existsSync28, mkdirSync as mkdirSync17, mkdtempSync as mkdtempSync3, readFileSync as readFileSync23, renameSync as renameSync4, rmSync as rmSync6, writeFileSync as writeFileSync18 } from "fs";
72486
- import { dirname as dirname12, join as join30 } from "path";
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(join30(getPortableSkillsRoot(corpusOptions), slug));
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(join30(getPortableSkillsRoot(corpusOptions), slug));
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 = join30(getPortableSkillsRoot(corpusOptions), slug);
72620
- if (!existsSync28(join30(target, PULL_MARKER_FILE))) {
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(readFileSync23(join30(dir, PULL_MARKER_FILE), "utf-8"));
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
- mkdirSync17(root, { recursive: true });
72749
- const target = join30(root, name);
72750
- const created = !existsSync28(target);
72751
- const staging = mkdtempSync3(join30(root, `.pull-${name}-`));
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 = join30(staging, entry.path);
72757
- mkdirSync17(dirname12(destination), { recursive: true });
72758
- writeFileSync18(destination, entry.bytes, { mode: entry.mode });
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 (existsSync28(target)) {
72769
- backup = mkdtempSync3(join30(root, `.pull-backup-${name}-`));
72770
- renameSync4(target, join30(backup, name));
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 && existsSync28(join30(backup, name))) {
73651
+ if (moved && backup && existsSync29(join34(backup, name))) {
72779
73652
  try {
72780
- renameSync4(join30(backup, name), target);
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
- writeFileSync18(join30(dir, PULL_MARKER_FILE), `${JSON.stringify(marker, null, 2)}
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((resolve, reject2) => {
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
- resolve();
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 existsSync29, readFileSync as readFileSync24 } from "fs";
72971
- import { join as join31 } from "path";
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 = join31(skill.path, "SKILL.md");
73013
- const skillMd = existsSync29(skillMdPath) ? readFileSync24(skillMdPath, "utf-8") : undefined;
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((resolve) => {
74003
+ return new Promise((resolve4) => {
73131
74004
  rl.question(question, (answer) => {
73132
74005
  rl.close();
73133
- resolve(answer.trim());
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((resolve) => setTimeout(resolve, ms));
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 existsSync30, readFileSync as readFileSync25, statSync as statSync16, writeFileSync as writeFileSync19 } from "fs";
73785
- import { join as join32 } from "path";
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 statSync16(path).isDirectory();
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 ? join32(options.homeDir, ".hasna", "skills") : getDataDir();
73797
- return !(isOwnerLayoutMigrated(appDir) && isDirectory2(join32(appDir, SKILLS_CACHE_DIRNAME)));
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 = join32(skillDir, PULL_MARKER_FILE);
73801
- if (!existsSync30(markerPath))
74673
+ const markerPath = join36(skillDir, PULL_MARKER_FILE);
74674
+ if (!existsSync31(markerPath))
73802
74675
  return;
73803
74676
  try {
73804
- const marker = JSON.parse(readFileSync25(markerPath, "utf-8"));
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 = join32(root, SYNC_CURSOR_FILE);
73815
- if (!existsSync30(path))
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(readFileSync25(path, "utf-8"));
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 ? join32(options.homeDir, ".hasna", "skills") : getDataDirReadOnly();
73828
- const cache3 = join32(appDir, SKILLS_CACHE_DIRNAME);
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: join32(appDir, INSTALLED_SKILLS_DIRNAME), migrationPending: true };
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: existsSync30
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(join32(root, slug)) : undefined;
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(join32(root, slug), {
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
- writeFileSync19(join32(root, SYNC_CURSOR_FILE), `${JSON.stringify(cursor, null, 2)}
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
- // ../events/dist/commander.js
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)(webhookUrl, {
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));