@hasna/skills 0.10.19 → 0.10.20

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
@@ -36868,7 +36868,7 @@ var package_default;
36868
36868
  var init_package = __esm(() => {
36869
36869
  package_default = {
36870
36870
  name: "@hasna/skills",
36871
- version: "0.10.19",
36871
+ version: "0.10.20",
36872
36872
  description: "Skills library for AI coding agents",
36873
36873
  type: "module",
36874
36874
  bin: {
@@ -51052,6 +51052,35 @@ function projectCodexNativeSkillCatalog(response, cwd2) {
51052
51052
  return { name: value.name, path: value.path, enabled: value.enabled, pluginId: value.pluginId ?? null };
51053
51053
  });
51054
51054
  }
51055
+ function projectCodexInstalledPlugins(response) {
51056
+ if (!object4(response) || !Array.isArray(response.marketplaces) || !Array.isArray(response.marketplaceLoadErrors) || response.marketplaceLoadErrors.length !== 0 || response.marketplaces.length > MAX_SKILLS)
51057
+ refuse();
51058
+ const plugins = [];
51059
+ for (const marketplace of response.marketplaces) {
51060
+ if (!object4(marketplace) || !scalar(marketplace.name, MAX_NAME_BYTES) || !Array.isArray(marketplace.plugins) || marketplace.plugins.length > MAX_SKILLS)
51061
+ refuse();
51062
+ for (const value of marketplace.plugins) {
51063
+ if (!object4(value) || !scalar(value.id, MAX_PLUGIN_ID_BYTES) || !scalar(value.name, MAX_NAME_BYTES) || value.id !== `${value.name}@${marketplace.name}`)
51064
+ refuse();
51065
+ plugins.push({ ...value, marketplace: marketplace.name });
51066
+ }
51067
+ }
51068
+ return projectCodexInstalledPluginEntries(plugins);
51069
+ }
51070
+ function projectCodexInstalledPluginEntries(value) {
51071
+ if (!Array.isArray(value) || value.length > MAX_SKILLS)
51072
+ refuse();
51073
+ const ids = new Set;
51074
+ return value.map((item) => {
51075
+ if (!object4(item) || !scalar(item.id, MAX_PLUGIN_ID_BYTES) || !scalar(item.name, MAX_NAME_BYTES) || typeof item.installed !== "boolean" || typeof item.enabled !== "boolean" || item.localVersion !== null && !scalar(item.localVersion, MAX_NAME_BYTES))
51076
+ refuse();
51077
+ const at2 = item.id.lastIndexOf("@");
51078
+ if (at2 < 1 || item.id.slice(0, at2) !== item.name || at2 === item.id.length - 1 || ids.has(item.id))
51079
+ refuse();
51080
+ ids.add(item.id);
51081
+ return { id: item.id, name: item.name, installed: item.installed, enabled: item.enabled, localVersion: item.localVersion ?? null };
51082
+ });
51083
+ }
51055
51084
  async function captureCodexNativeSkillCatalog(options, connect = connectCodexHookRpc) {
51056
51085
  if (!absolutePath2(options.cwd) || !absolutePath2(options.home))
51057
51086
  refuse();
@@ -51065,7 +51094,13 @@ async function captureCodexNativeSkillCatalog(options, connect = connectCodexHoo
51065
51094
  if (!SUPPORTED_NAME_CONTROL_VERSIONS.has(rpc.version))
51066
51095
  throw new Error("CODEX_NATIVE_SKILL_CATALOG_UNSUPPORTED_VERSION");
51067
51096
  const response = await rpc.request("skills/list", { cwds: [options.cwd], forceReload: true });
51068
- return { version: rpc.version, cwd: options.cwd, skills: projectCodexNativeSkillCatalog(response, options.cwd) };
51097
+ const installed = await rpc.request("plugin/installed", { cwds: [options.cwd] });
51098
+ return {
51099
+ version: rpc.version,
51100
+ cwd: options.cwd,
51101
+ skills: projectCodexNativeSkillCatalog(response, options.cwd),
51102
+ plugins: projectCodexInstalledPlugins(installed)
51103
+ };
51069
51104
  } finally {
51070
51105
  await rpc.close();
51071
51106
  }
@@ -51107,14 +51142,14 @@ function isCodexNativeSkillDisabled(skill, rules) {
51107
51142
  }
51108
51143
  return disabled;
51109
51144
  }
51110
- var MAX_SKILLS = 4096, MAX_NAME_BYTES = 1024, MAX_PATH_BYTES = 16384, SUPPORTED_NAME_CONTROL_VERSIONS, object4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value), scalar = (value, max2) => typeof value === "string" && value.length > 0 && value.trim() === value && Buffer.byteLength(value, "utf8") <= max2 && !/[\u0000-\u001f\u007f]/u.test(value), absolutePath2 = (value) => scalar(value, MAX_PATH_BYTES) && isAbsolute10(value);
51145
+ var MAX_SKILLS = 4096, MAX_NAME_BYTES = 1024, MAX_PATH_BYTES = 16384, MAX_PLUGIN_ID_BYTES = 1024, SUPPORTED_NAME_CONTROL_VERSIONS, object4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value), scalar = (value, max2) => typeof value === "string" && value.length > 0 && value.trim() === value && Buffer.byteLength(value, "utf8") <= max2 && !/[\u0000-\u001f\u007f]/u.test(value), absolutePath2 = (value) => scalar(value, MAX_PATH_BYTES) && isAbsolute10(value);
51111
51146
  var init_codex_native_skill_catalog = __esm(() => {
51112
51147
  init_codex_hook_rpc();
51113
51148
  SUPPORTED_NAME_CONTROL_VERSIONS = new Set(["codex-cli 0.159.2"]);
51114
51149
  });
51115
51150
 
51116
51151
  // src/lib/codex-plugin-skill-controls.ts
51117
- import { dirname as dirname10, join as join18, resolve as resolve10, sep as sep4 } from "path";
51152
+ import { basename as basename5, dirname as dirname10, join as join18, relative as relative4, resolve as resolve10, sep as sep4 } from "path";
51118
51153
  import { lstatSync as lstatSync12, readdirSync as readdirSync6, readlinkSync as readlinkSync3, realpathSync as realpathSync5 } from "fs";
51119
51154
  function refuse2() {
51120
51155
  throw new Error("CODEX_NATIVE_SKILL_IDENTITY_UNSUPPORTED: review native plugin names and hook controls");
@@ -51154,6 +51189,9 @@ function rootControls(root, read2) {
51154
51189
  }
51155
51190
  if (!manifest || typeof manifest !== "object" || Array.isArray(manifest) || !identifier2(manifest.name))
51156
51191
  refuse2();
51192
+ const cacheVersion = basename5(root), declaredVersion = manifest.version === undefined ? "" : typeof manifest.version === "string" ? manifest.version.trim() : null;
51193
+ if (declaredVersion === null || (declaredVersion ? declaredVersion !== cacheVersion : cacheVersion !== CODEX_DEFAULT_AGENT_PLUGIN_VERSION))
51194
+ refuse2();
51157
51195
  if (manifest.hooks !== undefined || manifest.mcpServers !== undefined || manifest.commands !== undefined || manifest.apps !== undefined && manifest.apps !== "./.app.json" || ["hooks", ".mcp.json"].some((path) => lstatSync12(join18(root, path), { throwIfNoEntry: false })))
51158
51196
  refuse2();
51159
51197
  const app = join18(root, ".app.json"), present = lstatSync12(app, { throwIfNoEntry: false });
@@ -51230,22 +51268,48 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache3, controls, read2) {
51230
51268
  return false;
51231
51269
  }
51232
51270
  }
51233
- function reviewCodexPluginSkillControls(catalog, documents, cache3, cwd2, read2) {
51271
+ function reviewCodexPluginSkillControls(catalog, documents, cache3, cwd2, read2, rules) {
51234
51272
  if (catalog?.version !== "codex-cli 0.159.2" || catalog.cwd !== cwd2)
51235
51273
  refuse2();
51236
51274
  const skills = projectCodexNativeSkillCatalog({ data: [{ cwd: cwd2, errors: [], skills: catalog.skills }] }, cwd2);
51237
51275
  const allowed = new Set(documents), result2 = [];
51238
- for (const skill of skills) {
51239
- if (!allowed.has(skill.path) || !skill.path.startsWith(cache3 + sep4))
51276
+ let installedPlugins;
51277
+ try {
51278
+ installedPlugins = projectCodexInstalledPluginEntries(catalog.plugins ?? []);
51279
+ } catch {
51280
+ refuse2();
51281
+ }
51282
+ const candidates = catalog.plugins === undefined ? skills.map((skill) => skill.path).filter((path) => allowed.has(path)) : allowed;
51283
+ for (const document3 of candidates) {
51284
+ if (!document3.startsWith(cache3 + sep4))
51240
51285
  continue;
51241
- if (skills.filter((other) => other.name === skill.name).length !== 1)
51286
+ const parsed = identity4(document3, cache3, read2);
51287
+ if (parsed.name === "skills-cli" || parsed.name.endsWith(":skills-cli"))
51288
+ refuse2();
51289
+ const cacheParts = relative4(cache3, parsed.pluginParent).split(sep4);
51290
+ if (cacheParts.length !== 2 || cacheParts.some((part) => !identifier2(part)))
51242
51291
  refuse2();
51243
- if (!skill.pluginId || skill.name === "skills-cli" || skill.name.endsWith(":skills-cli"))
51292
+ const [marketplace, pluginName] = cacheParts;
51293
+ if (pluginName !== parsed.namespace)
51244
51294
  refuse2();
51245
- const parsed = identity4(skill.path, cache3, read2);
51246
- if (parsed.name !== skill.name)
51295
+ const expectedPluginId = `${pluginName}@${marketplace}`;
51296
+ const listed = skills.filter((skill) => skill.path === document3);
51297
+ if (listed.length > 1)
51247
51298
  refuse2();
51248
- result2.push({ ...parsed, pluginId: skill.pluginId });
51299
+ if (listed.length === 1) {
51300
+ if (listed[0].name !== parsed.name || listed[0].pluginId !== expectedPluginId)
51301
+ refuse2();
51302
+ } else {
51303
+ const installed = installedPlugins.filter((plugin) => plugin.id === expectedPluginId && plugin.name === pluginName);
51304
+ if (installed.length !== 1 || !installed[0].installed || !installed[0].enabled || !installed[0].localVersion)
51305
+ refuse2();
51306
+ if (installed[0].localVersion !== basename5(dirname10(dirname10(dirname10(document3)))))
51307
+ continue;
51308
+ const exactPathDeny = Array.isArray(rules) && rules.some((rule) => rule?.path === document3 && rule?.enabled === false);
51309
+ if (!exactPathDeny || !isCodexNativeSkillDisabled({ name: parsed.name, path: document3, pluginId: expectedPluginId, enabled: true }, rules))
51310
+ refuse2();
51311
+ }
51312
+ result2.push({ ...parsed, pluginId: expectedPluginId });
51249
51313
  }
51250
51314
  if (!result2.length || new Set(result2.map((item) => item.name)).size !== result2.length)
51251
51315
  refuse2();
@@ -51279,7 +51343,7 @@ enabled = false
51279
51343
  }
51280
51344
  return text2;
51281
51345
  }
51282
- var identifier2 = (v) => typeof v === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(v);
51346
+ var identifier2 = (v) => typeof v === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(v), CODEX_DEFAULT_AGENT_PLUGIN_VERSION = "1.0.0";
51283
51347
  var init_codex_plugin_skill_controls = __esm(() => {
51284
51348
  init_claude_settings_witness();
51285
51349
  init_codex_native_skill_catalog();
@@ -51794,7 +51858,7 @@ var init_agent_codex = __esm(() => {
51794
51858
  // src/lib/agent-integration.ts
51795
51859
  import { createHash as createHash11, randomUUID as randomUUID5 } from "crypto";
51796
51860
  import { existsSync as existsSync12, lstatSync as lstatSync15, statSync as statSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync13, readdirSync as readdirSync8, opendirSync as opendirSync3, readlinkSync as readlinkSync4, realpathSync as realpathSync6, renameSync as renameSync2, rmdirSync as rmdirSync2, writeFileSync as writeFileSync4, unlinkSync as unlinkSync3, chmodSync, openSync as openSync8, closeSync as closeSync8, fsyncSync as fsyncSync2, fstatSync as fstatSync8, readSync as readSync6, constants as constants8, linkSync } from "fs";
51797
- import { dirname as dirname11, join as join21, resolve as resolve11, relative as relative4, isAbsolute as isAbsolute11, sep as sep5 } from "path";
51861
+ import { dirname as dirname11, join as join21, resolve as resolve11, relative as relative5, isAbsolute as isAbsolute11, sep as sep5 } from "path";
51798
51862
  import { homedir as homedir3 } from "os";
51799
51863
  function assertSafePath(path) {
51800
51864
  let cursor = resolve11(path);
@@ -51818,7 +51882,7 @@ function readRootAlias(home, agent) {
51818
51882
  const targetStat = lstatSync15(targetPath, { throwIfNoEntry: false });
51819
51883
  if (!targetStat?.isDirectory())
51820
51884
  throw new Error(`Agent root alias must target an existing directory: ${alias}`);
51821
- const target = realpathSync6(targetPath), inside = relative4(realHome, target);
51885
+ const target = realpathSync6(targetPath), inside = relative5(realHome, target);
51822
51886
  if (!inside || inside === ".." || inside.startsWith(`..${sep5}`) || isAbsolute11(inside))
51823
51887
  throw new Error(`Agent root alias target must be inside the real home: ${alias}`);
51824
51888
  return { agent, home: realHome, alias, target, link: link2, aliasIdentity: `${stat.dev}:${stat.ino}:${stat.ctimeNs}`, targetIdentity: `${targetStat.dev}:${targetStat.ino}` };
@@ -51836,7 +51900,7 @@ function rootAliases(home, allowed = false) {
51836
51900
  }
51837
51901
  function canonicalAgentPath(path, aliases) {
51838
51902
  const absolute = resolve11(path), binding = aliases.find((item) => absolute === item.alias || absolute.startsWith(item.alias + sep5));
51839
- return binding ? join21(binding.target, relative4(binding.alias, absolute)) : absolute;
51903
+ return binding ? join21(binding.target, relative5(binding.alias, absolute)) : absolute;
51840
51904
  }
51841
51905
  function disabledCodexSkillPaths(config, aliases) {
51842
51906
  const skills = config.skills;
@@ -51907,7 +51971,7 @@ function treeHash(root) {
51907
51971
  const stat = lstatSync15(path);
51908
51972
  if (stat.isSymbolicLink())
51909
51973
  throw new Error(`Refusing symlink in skill: ${path}`);
51910
- const rel = relative4(root, path);
51974
+ const rel = relative5(root, path);
51911
51975
  if (stat.isDirectory()) {
51912
51976
  hash2.update(`d\x00${rel}\x00`);
51913
51977
  for (const name of readdirSync8(path).sort())
@@ -51958,7 +52022,7 @@ function parseNativeMigrationTargetManifest(input) {
51958
52022
  assertSafePath(projectRoot);
51959
52023
  if (isAbsolute11(item.path) || item.path.includes("\\") || item.path.length === 0 || item.path.includes("\x00"))
51960
52024
  throw new Error(`Native migration target path must be normalized and project-relative: ${item.path}`);
51961
- const resolved = resolve11(projectRoot, item.path), normalized = relative4(projectRoot, resolved);
52025
+ const resolved = resolve11(projectRoot, item.path), normalized = relative5(projectRoot, resolved);
51962
52026
  if (!normalized || normalized === ".." || normalized.startsWith(`..${sep5}`) || isAbsolute11(normalized) || normalized !== item.path)
51963
52027
  throw new Error(`Native migration target path escapes or is not normalized: ${item.path}`);
51964
52028
  if (!/^[0-9a-f]{64}$/.test(item.treeSha256))
@@ -51980,7 +52044,7 @@ function selectNativeMigrationTargets(inventory, manifest) {
51980
52044
  const identities = new Set;
51981
52045
  const selected = [];
51982
52046
  for (const target of manifest.targets) {
51983
- const projectRoot = resolve11(target.projectRoot), normalized = relative4(projectRoot, resolve11(projectRoot, target.path));
52047
+ const projectRoot = resolve11(target.projectRoot), normalized = relative5(projectRoot, resolve11(projectRoot, target.path));
51984
52048
  if (!isAbsolute11(target.projectRoot) || projectRoot !== target.projectRoot || !existsSync12(projectRoot) || !lstatSync15(projectRoot).isDirectory())
51985
52049
  throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
51986
52050
  assertSafePath(projectRoot);
@@ -52335,7 +52399,7 @@ function planAgentIntegration(options) {
52335
52399
  const bytes = readNativeBytes(path, 1024 * 1024);
52336
52400
  observedNativeSources.push({ path, sha256: sha2(bytes) });
52337
52401
  return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
52338
- }) : policy.bridge?.codexPluginSkills ?? [];
52402
+ }, codexConfig.skills?.config ?? []) : policy.bridge?.codexPluginSkills ?? [];
52339
52403
  const changes = [];
52340
52404
  for (const agent of [...new Set(options.agents)]) {
52341
52405
  if (!INTEGRATION_AGENTS.includes(agent))
@@ -52413,7 +52477,7 @@ function planAgentIntegration(options) {
52413
52477
  profiles: Object.fromEntries([...new Set([...priorAgents, ...options.agents])].sort().map((agent) => [agent, bindings.get(agent)?.profileId ?? policy.bridge?.profiles?.[agent] ?? policy.profileId])),
52414
52478
  disabledBuiltins: options.agents.includes("codex") ? nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor && entry.path.startsWith(canonicalAgentPath(join21(home, ".codex", "skills", ".system"), aliases) + sep5)).map((entry) => ({ path: entry.path, hash: entry.hash })) : policy.bridge?.disabledBuiltins ?? [],
52415
52479
  rootAliases: aliases,
52416
- ...codexPluginSkills.length ? { codexPluginSkills, codexPluginSkillReview: options.codexNativeCatalog ? { version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, catalogSha256: sha2(JSON.stringify({ version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, skills: projectCodexNativeSkillCatalog({ data: [{ cwd: options.codexNativeCatalog.cwd, errors: [], skills: options.codexNativeCatalog.skills }] }, options.codexNativeCatalog.cwd) })), configSha256: changes.find((change) => change.path === canonicalAgentPath(join21(home, ".codex/config.toml"), aliases))?.before === null ? null : sha2(readOptional(canonicalAgentPath(join21(home, ".codex/config.toml"), aliases)) ?? "") } : policy.bridge?.codexPluginSkillReview } : {},
52480
+ ...codexPluginSkills.length ? { codexPluginSkills, codexPluginSkillReview: options.codexNativeCatalog ? { version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, catalogSha256: sha2(JSON.stringify({ version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, skills: projectCodexNativeSkillCatalog({ data: [{ cwd: options.codexNativeCatalog.cwd, errors: [], skills: options.codexNativeCatalog.skills }] }, options.codexNativeCatalog.cwd), ...options.codexNativeCatalog.plugins === undefined ? {} : { plugins: projectCodexInstalledPluginEntries(options.codexNativeCatalog.plugins) } })), configSha256: changes.find((change) => change.path === canonicalAgentPath(join21(home, ".codex/config.toml"), aliases))?.before === null ? null : sha2(readOptional(canonicalAgentPath(join21(home, ".codex/config.toml"), aliases)) ?? "") } : policy.bridge?.codexPluginSkillReview } : {},
52417
52481
  discovery: { ...policy.bridge?.discovery, ...Object.fromEntries(discoveryAfter.map((binding) => [binding.agent, binding])) }
52418
52482
  } };
52419
52483
  const serializedPolicy = serializeManagedSkillPolicy(nextPolicy);
@@ -53051,7 +53115,7 @@ import {
53051
53115
  writeFileSync as writeFileSync6
53052
53116
  } from "fs";
53053
53117
  import { homedir as homedir4 } from "os";
53054
- import { basename as basename5, dirname as dirname12, join as join25 } from "path";
53118
+ import { basename as basename6, dirname as dirname12, join as join25 } from "path";
53055
53119
  function isSkillsOwnershipMarker(marker) {
53056
53120
  return typeof marker === "object" && marker !== null && Object.hasOwn(marker, "managedBy") && marker.managedBy === SYNC_MARKER_MANAGED_BY;
53057
53121
  }
@@ -53285,7 +53349,7 @@ function writeManagedSkillDir(dir, skillMd, options) {
53285
53349
  return { action, path: skillMdPath };
53286
53350
  const parentDir = dirname12(dir);
53287
53351
  mkdirSync7(parentDir, { recursive: true });
53288
- const transactionDir = mkdtempSync(join25(parentDir, `.hasna-skills-write-${basename5(dir)}-`));
53352
+ const transactionDir = mkdtempSync(join25(parentDir, `.hasna-skills-write-${basename6(dir)}-`));
53289
53353
  const candidateDir = join25(transactionDir, "candidate");
53290
53354
  const backupDir = join25(transactionDir, "backup");
53291
53355
  const candidateSkillMdPath = join25(candidateDir, "SKILL.md");
@@ -54798,7 +54862,7 @@ function directoryNames(path) {
54798
54862
  function snapshotPluginTree(root, options = {}) {
54799
54863
  const chain = ancestors(root), entries = [], files = [], directories = [];
54800
54864
  let bytes = 0, visited = 0;
54801
- const visit2 = (directory, relative5) => {
54865
+ const visit2 = (directory, relative6) => {
54802
54866
  const before2 = stat(directory);
54803
54867
  pluginNeed(before2 && before2.isDirectory() && !before2.isSymbolicLink(), "Plugin tree must contain real directories");
54804
54868
  const names = directoryNames(directory);
@@ -54806,18 +54870,18 @@ function snapshotPluginTree(root, options = {}) {
54806
54870
  directories.push({ path: directory, stat: before2, names });
54807
54871
  for (const name of names) {
54808
54872
  pluginNeed(++visited <= PLUGIN_PROJECTION_LIMITS.files * 50, "Plugin tree membership exceeds its limit");
54809
- const path = relative5 ? `${relative5}/${name}` : name;
54873
+ const path = relative6 ? `${relative6}/${name}` : name;
54810
54874
  pluginNeed(new TextEncoder().encode(path).byteLength <= 100 && !/[\\:\x00-\x1f\x7f]/u.test(path), "Plugin entry path exceeds its limit or is unsafe");
54811
54875
  const absolute = join29(directory, name), entryStat = stat(absolute);
54812
54876
  pluginNeed(entryStat, "Plugin tree member disappeared");
54813
- if (relative5 === "" && name === ".orphaned_at" && (options.nativeRuntime === "claude-2.1.274" || options.nativeRuntime === "claude-2.1.276")) {
54877
+ if (relative6 === "" && name === ".orphaned_at" && (options.nativeRuntime === "claude-2.1.274" || options.nativeRuntime === "claude-2.1.276")) {
54814
54878
  const bytes2 = readBytes(absolute, 32, "native-pin");
54815
54879
  pluginNeed(/^[1-9][0-9]{12}$/.test(new TextDecoder().decode(bytes2)), "Malformed native orphan timestamp");
54816
54880
  same3(entryStat, stat(absolute));
54817
54881
  files.push({ path: absolute, stat: entryStat });
54818
54882
  continue;
54819
54883
  }
54820
- if (relative5 === "" && name === ".in_use" && (options.nativeRuntime === "claude-2.1.274" || options.nativeRuntime === "claude-2.1.276")) {
54884
+ if (relative6 === "" && name === ".in_use" && (options.nativeRuntime === "claude-2.1.274" || options.nativeRuntime === "claude-2.1.276")) {
54821
54885
  pluginNeed(entryStat.isDirectory() && !entryStat.isSymbolicLink(), "Native plugin pins require a real directory");
54822
54886
  owner(entryStat);
54823
54887
  const pins = directoryNames(absolute);
@@ -55439,7 +55503,7 @@ var init_plugin_admission = __esm(() => {
55439
55503
 
55440
55504
  // src/lib/plugin-discovery.ts
55441
55505
  import { closeSync as closeSync10, constants as constants10, fstatSync as fstatSync10, lstatSync as lstatSync18, openSync as openSync10, opendirSync as opendirSync5, readSync as readSync8 } from "fs";
55442
- import { basename as basename6, dirname as dirname14, isAbsolute as isAbsolute14, join as join31, resolve as resolve14 } from "path";
55506
+ import { basename as basename7, dirname as dirname14, isAbsolute as isAbsolute14, join as join31, resolve as resolve14 } from "path";
55443
55507
  function validateManagedPluginWitnesses(value) {
55444
55508
  pluginNeed(Array.isArray(value) && value.length > 0 && value.length <= PLUGIN_PROJECTION_LIMITS.registrations, "Invalid managed plugin witness collection");
55445
55509
  const seen = new Set;
@@ -55522,7 +55586,7 @@ function hashManagedPluginRegistry(path, managed) {
55522
55586
  pluginNeed(/^(?:[A-Za-z0-9][A-Za-z0-9._+-]*-)?[a-f0-9]{12}$/.test(row.version) && row.installPath === join31(cacheRoot, row.version), "Managed plugin cache path or version is outside its registration");
55523
55587
  const approval = (producer) => {
55524
55588
  pluginText(producer);
55525
- const digest = `sha256:${basename6(producer)}`;
55589
+ const digest = `sha256:${basename7(producer)}`;
55526
55590
  const receipt2 = readPluginAdmissionReceipt(witness.storeRoot, witness.bindingId, digest);
55527
55591
  pluginNeed(receipt2.materializedPath === producer, "Managed producer path is not an approved immutable projection");
55528
55592
  if (!verified.has(producer)) {
@@ -55588,7 +55652,7 @@ var init_plugin_discovery = __esm(() => {
55588
55652
  // src/lib/claude-marketplace-registry.ts
55589
55653
  import { createHash as createHash14 } from "crypto";
55590
55654
  import { closeSync as closeSync11, constants as constants11, fstatSync as fstatSync11, lstatSync as lstatSync19, openSync as openSync11, readSync as readSync9 } from "fs";
55591
- import { basename as basename7, dirname as dirname15, isAbsolute as isAbsolute15, resolve as resolve15 } from "path";
55655
+ import { basename as basename8, dirname as dirname15, isAbsolute as isAbsolute15, resolve as resolve15 } from "path";
55592
55656
  function need4(value, reason) {
55593
55657
  if (!value)
55594
55658
  throw new Error(`Claude marketplace registry ${reason}`);
@@ -55608,7 +55672,7 @@ function parents2(path) {
55608
55672
  }
55609
55673
  function readRegistry2(path, budget) {
55610
55674
  absolutePath3(path);
55611
- need4(basename7(path) === "known_marketplaces.json", "requires known_marketplaces.json");
55675
+ need4(basename8(path) === "known_marketplaces.json", "requires known_marketplaces.json");
55612
55676
  need4(Number.isSafeInteger(budget.remaining) && budget.remaining >= 0, "has an invalid byte budget");
55613
55677
  const ancestors2 = parents2(path), initial2 = lstatSync19(path, { bigint: true });
55614
55678
  need4(initial2.isFile() && !initial2.isSymbolicLink() && initial2.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
@@ -56106,7 +56170,7 @@ var init_codex_hook_discovery_recovery = __esm(() => {
56106
56170
  // src/lib/agent-discovery.ts
56107
56171
  import { createHash as createHash17 } from "crypto";
56108
56172
  import { lstatSync as lstatSync21, readFileSync as readFileSync18, readdirSync as readdirSync11, realpathSync as realpathSync7 } from "fs";
56109
- import { basename as basename8, dirname as dirname17, isAbsolute as isAbsolute17, join as join32, resolve as resolve16, sep as sep6 } from "path";
56173
+ import { basename as basename9, dirname as dirname17, isAbsolute as isAbsolute17, join as join32, resolve as resolve16, sep as sep6 } from "path";
56110
56174
  import { isDeepStrictEqual as isDeepStrictEqual7 } from "util";
56111
56175
  function parseConfig(text3, path, toml = false) {
56112
56176
  try {
@@ -56216,9 +56280,9 @@ function verifyAgentDiscovery(binding, codexRecovery) {
56216
56280
  safe4(root2);
56217
56281
  }
56218
56282
  function assertMarketplaceBinding(binding, source) {
56219
- if (source.hashMode === "codex-settings-v1" && (binding.agent !== "codex" || binding.method !== "reviewed" || basename8(source.path) !== "config.toml"))
56283
+ if (source.hashMode === "codex-settings-v1" && (binding.agent !== "codex" || binding.method !== "reviewed" || basename9(source.path) !== "config.toml"))
56220
56284
  throw new Error("Codex settings witnesses require explicit reviewed Codex configuration");
56221
- if ((source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") && (binding.agent !== "claude" || binding.method !== "reviewed" || basename8(source.path) !== "settings.json"))
56285
+ if ((source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") && (binding.agent !== "claude" || binding.method !== "reviewed" || basename9(source.path) !== "settings.json"))
56222
56286
  throw new Error("Claude settings witnesses require explicit reviewed Claude configuration");
56223
56287
  if ((source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2") && (binding.agent !== "claude" || binding.method !== "reviewed"))
56224
56288
  throw new Error("Claude marketplace witnesses require explicit reviewed Claude discovery");
@@ -56501,7 +56565,7 @@ var init_agent_discovery = __esm(() => {
56501
56565
  // src/lib/authoring-path.ts
56502
56566
  import { lstatSync as lstatSync22, realpathSync as realpathSync8 } from "fs";
56503
56567
  import { homedir as homedir7 } from "os";
56504
- import { basename as basename9, dirname as dirname18, join as join33, resolve as resolve17, sep as sep7 } from "path";
56568
+ import { basename as basename10, dirname as dirname18, join as join33, resolve as resolve17, sep as sep7 } from "path";
56505
56569
  function pathParts(path) {
56506
56570
  return resolve17(path).split(sep7).filter(Boolean);
56507
56571
  }
@@ -56520,7 +56584,7 @@ function physicalPath(path) {
56520
56584
  let cursor = resolve17(path);
56521
56585
  const suffix = [];
56522
56586
  while (!lstatSync22(cursor, { throwIfNoEntry: false })) {
56523
- suffix.unshift(basename9(cursor));
56587
+ suffix.unshift(basename10(cursor));
56524
56588
  const parent = dirname18(cursor);
56525
56589
  if (parent === cursor)
56526
56590
  return resolve17(path);
@@ -56615,7 +56679,7 @@ import {
56615
56679
  statSync as statSync11,
56616
56680
  writeFileSync as writeFileSync9
56617
56681
  } from "fs";
56618
- import { basename as basename10, dirname as dirname19, isAbsolute as isAbsolute18, join as join34, normalize as normalize3, relative as relative5, resolve as resolve18, sep as sep8 } from "path";
56682
+ import { basename as basename11, dirname as dirname19, isAbsolute as isAbsolute18, join as join34, normalize as normalize3, relative as relative6, resolve as resolve18, sep as sep8 } from "path";
56619
56683
  function getPortableSkillsRoot(options = {}) {
56620
56684
  return resolvePortableSkillsRoot(options, true);
56621
56685
  }
@@ -56763,7 +56827,7 @@ function physicalImportPath(path) {
56763
56827
  let ancestor = resolve18(path);
56764
56828
  const suffix = [];
56765
56829
  while (!existsSync18(ancestor)) {
56766
- suffix.unshift(basename10(ancestor));
56830
+ suffix.unshift(basename11(ancestor));
56767
56831
  ancestor = dirname19(ancestor);
56768
56832
  }
56769
56833
  return join34(realpathSync9(ancestor), ...suffix);
@@ -56772,7 +56836,7 @@ function assertDisjointImportPaths(source, destination) {
56772
56836
  const sourcePath = realpathSync9(source);
56773
56837
  const destinationPath = physicalImportPath(destination);
56774
56838
  const contains2 = (parent, child) => {
56775
- const path = relative5(parent, child);
56839
+ const path = relative6(parent, child);
56776
56840
  return path === "" || !isAbsolute18(path) && path !== ".." && !path.startsWith(`..${sep8}`);
56777
56841
  };
56778
56842
  if (contains2(sourcePath, destinationPath) || contains2(destinationPath, sourcePath)) {
@@ -56788,8 +56852,8 @@ function portPortableSkill(sourcePath, options = {}) {
56788
56852
  const explicitName = options.name != null;
56789
56853
  const skillName = normalizeNewPortableSkillName(options.name ?? inferred.name);
56790
56854
  if (isOfficialSkillName(skillName) && !options.allowShadow) {
56791
- const sourceSlug = safeNormalizeName(basename10(absoluteSource));
56792
- const via = explicitName ? `Name '${skillName}' matches a bundled official skill.` : `Inferred name '${skillName}'${sourceSlug && sourceSlug !== skillName ? ` (from source folder '${basename10(absoluteSource)}')` : ""} matches a bundled official skill.`;
56855
+ const sourceSlug = safeNormalizeName(basename11(absoluteSource));
56856
+ const via = explicitName ? `Name '${skillName}' matches a bundled official skill.` : `Inferred name '${skillName}'${sourceSlug && sourceSlug !== skillName ? ` (from source folder '${basename11(absoluteSource)}')` : ""} matches a bundled official skill.`;
56793
56857
  throw new Error(`${via} Importing it would shadow the official '${skillName}'. ` + `Pass --name to choose a different name, or --allow-shadow to override deliberately.`);
56794
56858
  }
56795
56859
  const readOnlyDestination = join34(resolvePortableSkillsRoot(options, false), skillName);
@@ -58998,13 +59062,13 @@ var require_cli_spinners = __commonJS((exports, module) => {
58998
59062
 
58999
59063
  // src/lib/auth-store.ts
59000
59064
  import { chmodSync as chmodSync2, existsSync as existsSync20, mkdirSync as mkdirSync11, readFileSync as readFileSync20, renameSync as renameSync7, statSync as statSync12, unlinkSync as unlinkSync5, writeFileSync as writeFileSync10 } from "fs";
59001
- import { basename as basename11, dirname as dirname20, join as join36 } from "path";
59065
+ import { basename as basename12, dirname as dirname20, join as join36 } from "path";
59002
59066
  function getAuthFilePath(env3 = process.env) {
59003
59067
  return skillsCredentialFilePath(env3);
59004
59068
  }
59005
59069
  function getIdentityFilePath(env3 = process.env) {
59006
59070
  const file = skillsCredentialFilePath(env3);
59007
- return join36(dirname20(file), basename11(file).replace(/^credentials/, "identity") + ".json");
59071
+ return join36(dirname20(file), basename12(file).replace(/^credentials/, "identity") + ".json");
59008
59072
  }
59009
59073
  function getAuthIdentity(env3 = process.env) {
59010
59074
  return readIdentity(env3);
@@ -81028,7 +81092,7 @@ var init_remote_auth = __esm(() => {
81028
81092
  // src/lib/sign-in.ts
81029
81093
  import { createHash as createHash20 } from "crypto";
81030
81094
  import { chmodSync as chmodSync3, mkdirSync as mkdirSync12, readFileSync as readFileSync21, readdirSync as readdirSync14, renameSync as renameSync8, unlinkSync as unlinkSync6, writeFileSync as writeFileSync11 } from "fs";
81031
- import { basename as basename12, dirname as dirname21, join as join37 } from "path";
81095
+ import { basename as basename13, dirname as dirname21, join as join37 } from "path";
81032
81096
  function isRecord6(value) {
81033
81097
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
81034
81098
  }
@@ -81173,7 +81237,7 @@ async function pollDeviceAuthorization(input2) {
81173
81237
  }
81174
81238
  function pendingDeviceSignInStem(env3) {
81175
81239
  const file2 = skillsCredentialFilePath(env3);
81176
- return { dir: dirname21(file2), stem: basename12(file2).replace(/^credentials/, "device-login") };
81240
+ return { dir: dirname21(file2), stem: basename13(file2).replace(/^credentials/, "device-login") };
81177
81241
  }
81178
81242
  function pendingDeviceSignInPath(origin, env3 = process.env) {
81179
81243
  const { dir, stem } = pendingDeviceSignInStem(env3);
@@ -82358,9 +82422,9 @@ async function buildSkillContext(input2, options = {}) {
82358
82422
  if (prompt.length > 128 * 1024 || (input2.paths?.length ?? 0) > 100 || (input2.skills?.length ?? 0) > 100) {
82359
82423
  throw new SkillSelectionError("CONTEXT_INPUT_TOO_LARGE", "The Skills context input exceeds its size limit.");
82360
82424
  }
82361
- const maxChars = options.maxChars ?? 8000;
82425
+ const maxChars = options.maxChars;
82362
82426
  const maxSkills = options.maxSkills ?? 3;
82363
- if (!Number.isInteger(maxChars) || maxChars < 512 || maxChars > 64000 || !Number.isInteger(maxSkills) || maxSkills < 1 || maxSkills > 20) {
82427
+ if (maxChars !== undefined && (!Number.isInteger(maxChars) || maxChars < 512 || maxChars > 64000) || !Number.isInteger(maxSkills) || maxSkills < 1 || maxSkills > 20) {
82364
82428
  throw new SkillSelectionError("INVALID_CONTEXT_BUDGET", "Context limits must be 512\u201364000 characters and 1\u201320 skills.");
82365
82429
  }
82366
82430
  const profileId = input2.profileId ?? "default";
@@ -82417,7 +82481,7 @@ async function buildSkillContext(input2, options = {}) {
82417
82481
  const { content } = readSelectedDocument(entries);
82418
82482
  const section = `Skill ${selection.slug}@${selection.version} (${selection.bundleDigest}; ${reason})
82419
82483
  ${content}`;
82420
- if (chars + section.length + (sections.length ? 2 : 0) > maxChars) {
82484
+ if (maxChars !== undefined && chars + section.length + (sections.length ? 2 : 0) > maxChars) {
82421
82485
  omitted.push({ slug: selection.slug, version: selection.version, reason: "context-budget", loadCommand });
82422
82486
  continue;
82423
82487
  }
@@ -82673,7 +82737,7 @@ Preserved original receipt: ${result2.archivePath}` : `Planned one session recon
82673
82737
  reportContextError(error61, options.json);
82674
82738
  }
82675
82739
  });
82676
- parent.command("context [prompt]").description("Select bounded, versioned skill context for this prompt without running skills").option("--stdin", "Read native hook JSON or a prompt from stdin", false).option("--selection-profile <id>", "Selection profile (separate from the credential --profile)").option("--cached", "Use only an explicitly selected verified cache, at most 24 hours old", false).option("--auto-reconcile-safe", "For managed hooks, archive and renew an expired session only when all loaded selections are unchanged", false).option("--session <id>", "Keep the same skill versions across this session").option("--restore", "Re-emit loaded session context after compaction or resume", false).option("--max-chars <count>", "Maximum injected characters", "8000").option("--max-skills <count>", "Maximum loaded skills", "3").option("--json", "Return context and selection receipts as JSON", false).action(async (prompt, options) => {
82740
+ parent.command("context [prompt]").description("Select bounded, versioned skill context for this prompt without running skills").option("--stdin", "Read native hook JSON or a prompt from stdin", false).option("--selection-profile <id>", "Selection profile (separate from the credential --profile)").option("--cached", "Use only an explicitly selected verified cache, at most 24 hours old", false).option("--auto-reconcile-safe", "For managed hooks, archive and renew an expired session only when all loaded selections are unchanged", false).option("--session <id>", "Keep the same skill versions across this session").option("--restore", "Re-emit loaded session context after compaction or resume", false).option("--max-chars <count>", "Optional maximum injected characters").option("--max-skills <count>", "Maximum loaded skills", "3").option("--json", "Return context and selection receipts as JSON", false).action(async (prompt, options) => {
82677
82741
  try {
82678
82742
  if (options.autoReconcileSafe && !options.cached)
82679
82743
  throw new SkillSelectionError("INVALID_CONTEXT_INPUT", "--auto-reconcile-safe requires --cached.");
@@ -82682,7 +82746,7 @@ Preserved original receipt: ${result2.archivePath}` : `Planned one session recon
82682
82746
  input2.cwd ??= process.cwd();
82683
82747
  input2.sessionId = options.session ?? input2.sessionId;
82684
82748
  input2.restore ||= options.restore;
82685
- const resolverOptions = { ...contextResolverOptions(options), maxChars: Number(options.maxChars), maxSkills: Number(options.maxSkills) };
82749
+ const resolverOptions = { ...contextResolverOptions(options), ...options.maxChars === undefined ? {} : { maxChars: Number(options.maxChars) }, maxSkills: Number(options.maxSkills) };
82686
82750
  let result2;
82687
82751
  try {
82688
82752
  result2 = await buildSkillContext(input2, resolverOptions);
@@ -91538,7 +91602,7 @@ var init_runs = __esm(() => {
91538
91602
  // src/lib/run-state.ts
91539
91603
  import { createHash as createHash25, randomBytes } from "crypto";
91540
91604
  import { existsSync as existsSync27, mkdirSync as mkdirSync16, readFileSync as readFileSync32, readdirSync as readdirSync18, statSync as statSync16, writeFileSync as writeFileSync16 } from "fs";
91541
- import { extname, join as join46, relative as relative6 } from "path";
91605
+ import { extname, join as join46, relative as relative7 } from "path";
91542
91606
  function createSkillRun(params, targetDir = process.cwd()) {
91543
91607
  const now3 = new Date;
91544
91608
  const id2 = createRunId(now3);
@@ -91704,7 +91768,7 @@ function createRunId(now3) {
91704
91768
  return `run_${now3.getTime().toString(36)}_${randomBytes(4).toString("hex")}`;
91705
91769
  }
91706
91770
  function toProjectRelative(targetDir, path) {
91707
- const rel = relative6(targetDir, path).split(/[\\/]/).join("/");
91771
+ const rel = relative7(targetDir, path).split(/[\\/]/).join("/");
91708
91772
  return rel.startsWith(".") ? rel : `./${rel}`;
91709
91773
  }
91710
91774
  function mimeForPath(path) {
@@ -99000,49 +99064,49 @@ var require_fast_uri = __commonJS((exports, module) => {
99000
99064
  schemelessOptions.skipEscape = true;
99001
99065
  return serialize(resolved, schemelessOptions);
99002
99066
  }
99003
- function resolveComponent(base2, relative7, options, skipNormalization) {
99067
+ function resolveComponent(base2, relative8, options, skipNormalization) {
99004
99068
  const target = {};
99005
99069
  if (!skipNormalization) {
99006
99070
  base2 = parse12(serialize(base2, options), options);
99007
- relative7 = parse12(serialize(relative7, options), options);
99071
+ relative8 = parse12(serialize(relative8, options), options);
99008
99072
  }
99009
99073
  options = options || {};
99010
- if (!options.tolerant && relative7.scheme) {
99011
- target.scheme = relative7.scheme;
99012
- target.userinfo = relative7.userinfo;
99013
- target.host = relative7.host;
99014
- target.port = relative7.port;
99015
- target.path = removeDotSegments(relative7.path || "");
99016
- target.query = relative7.query;
99074
+ if (!options.tolerant && relative8.scheme) {
99075
+ target.scheme = relative8.scheme;
99076
+ target.userinfo = relative8.userinfo;
99077
+ target.host = relative8.host;
99078
+ target.port = relative8.port;
99079
+ target.path = removeDotSegments(relative8.path || "");
99080
+ target.query = relative8.query;
99017
99081
  } else {
99018
- if (relative7.userinfo !== undefined || relative7.host !== undefined || relative7.port !== undefined) {
99019
- target.userinfo = relative7.userinfo;
99020
- target.host = relative7.host;
99021
- target.port = relative7.port;
99022
- target.path = removeDotSegments(relative7.path || "");
99023
- target.query = relative7.query;
99082
+ if (relative8.userinfo !== undefined || relative8.host !== undefined || relative8.port !== undefined) {
99083
+ target.userinfo = relative8.userinfo;
99084
+ target.host = relative8.host;
99085
+ target.port = relative8.port;
99086
+ target.path = removeDotSegments(relative8.path || "");
99087
+ target.query = relative8.query;
99024
99088
  } else {
99025
- if (!relative7.path) {
99089
+ if (!relative8.path) {
99026
99090
  target.path = base2.path;
99027
- if (relative7.query !== undefined) {
99028
- target.query = relative7.query;
99091
+ if (relative8.query !== undefined) {
99092
+ target.query = relative8.query;
99029
99093
  } else {
99030
99094
  target.query = base2.query;
99031
99095
  }
99032
99096
  } else {
99033
- if (relative7.path[0] === "/") {
99034
- target.path = removeDotSegments(relative7.path);
99097
+ if (relative8.path[0] === "/") {
99098
+ target.path = removeDotSegments(relative8.path);
99035
99099
  } else {
99036
99100
  if ((base2.userinfo !== undefined || base2.host !== undefined || base2.port !== undefined) && !base2.path) {
99037
- target.path = "/" + relative7.path;
99101
+ target.path = "/" + relative8.path;
99038
99102
  } else if (!base2.path) {
99039
- target.path = relative7.path;
99103
+ target.path = relative8.path;
99040
99104
  } else {
99041
- target.path = base2.path.slice(0, base2.path.lastIndexOf("/") + 1) + relative7.path;
99105
+ target.path = base2.path.slice(0, base2.path.lastIndexOf("/") + 1) + relative8.path;
99042
99106
  }
99043
99107
  target.path = removeDotSegments(target.path);
99044
99108
  }
99045
- target.query = relative7.query;
99109
+ target.query = relative8.query;
99046
99110
  }
99047
99111
  target.userinfo = base2.userinfo;
99048
99112
  target.host = base2.host;
@@ -99050,7 +99114,7 @@ var require_fast_uri = __commonJS((exports, module) => {
99050
99114
  }
99051
99115
  target.scheme = base2.scheme;
99052
99116
  }
99053
- target.fragment = relative7.fragment;
99117
+ target.fragment = relative8.fragment;
99054
99118
  return target;
99055
99119
  }
99056
99120
  function equal(uriA, uriB, options) {
@@ -106930,7 +106994,7 @@ import {
106930
106994
  statSync as statSync18,
106931
106995
  writeFileSync as writeFileSync20
106932
106996
  } from "fs";
106933
- import { dirname as dirname27, join as join52, normalize as normalize4, relative as relative7, sep as sep9 } from "path";
106997
+ import { dirname as dirname27, join as join52, normalize as normalize4, relative as relative8, sep as sep9 } from "path";
106934
106998
  function resolveSkillsNativeStorageConfig(env3 = process.env) {
106935
106999
  assertNoRetiredModeEnvVars(env3, {
106936
107000
  app: SKILLS_ENV_NAMESPACE,
@@ -106994,7 +107058,7 @@ function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
106994
107058
  if (existsSync31(projectStateDir)) {
106995
107059
  for (const filePath of walkFiles2(projectStateDir)) {
106996
107060
  const bytes = readFileSync35(filePath);
106997
- const relativePath = toPosix(relative7(targetDir, filePath));
107061
+ const relativePath = toPosix(relative8(targetDir, filePath));
106998
107062
  files.push({
106999
107063
  path: relativePath,
107000
107064
  sizeBytes: bytes.byteLength,
@@ -108197,7 +108261,7 @@ import {
108197
108261
  symlinkSync,
108198
108262
  writeFileSync as writeFileSync23
108199
108263
  } from "fs";
108200
- import { basename as basename13, delimiter, dirname as dirname30, isAbsolute as isAbsolute24, join as join55, relative as relative8, resolve as resolve23, sep as sep10 } from "path";
108264
+ import { basename as basename14, delimiter, dirname as dirname30, isAbsolute as isAbsolute24, join as join55, relative as relative9, resolve as resolve23, sep as sep10 } from "path";
108201
108265
  function object9(value, code2) {
108202
108266
  if (!value || typeof value !== "object" || Array.isArray(value))
108203
108267
  throw new Error(code2);
@@ -108207,7 +108271,7 @@ function hash5(bytes) {
108207
108271
  return createHash27("sha256").update(bytes).digest("hex");
108208
108272
  }
108209
108273
  function isWithin(parent, child) {
108210
- const rel = relative8(parent, child);
108274
+ const rel = relative9(parent, child);
108211
108275
  return rel === "" || !rel.startsWith(`..${sep10}`) && rel !== ".." && !isAbsolute24(rel);
108212
108276
  }
108213
108277
  function entryExists(path) {
@@ -108302,7 +108366,7 @@ function resolveRuntimeLayout(homeInput, pathInput) {
108302
108366
  assertNoSymlinkAncestors(currentPackageRoot);
108303
108367
  if (!isWithin(runtimeRoot, currentPackageRoot))
108304
108368
  throw new Error("ACTIVE_RUNTIME_OUTSIDE_COPYFILE_ROOT");
108305
- const relativePackage = relative8(runtimeRoot, currentPackageRoot).split(sep10);
108369
+ const relativePackage = relative9(runtimeRoot, currentPackageRoot).split(sep10);
108306
108370
  if (relativePackage.length !== 4 || relativePackage[1] !== "node_modules" || relativePackage[2] !== "@hasna" || relativePackage[3] !== "skills") {
108307
108371
  throw new Error("ACTIVE_RUNTIME_LAYOUT_UNSUPPORTED");
108308
108372
  }
@@ -108856,7 +108920,7 @@ function inspectAliasPackageChain(home, aliasPath, oldLinkTarget, oldTarget, bin
108856
108920
  function validateAliasSource(home, name, actual) {
108857
108921
  const packageRoot = dirname30(dirname30(actual));
108858
108922
  const roots = [join55(home, ".hasna", "skills", "runtime"), join55(home, ".bun", "install"), join55(home, ".local", "lib", "node_modules")];
108859
- if (basename13(packageRoot) !== "skills" || basename13(dirname30(packageRoot)) !== "@hasna" || !roots.some((root2) => isWithin(root2, packageRoot))) {
108923
+ if (basename14(packageRoot) !== "skills" || basename14(dirname30(packageRoot)) !== "@hasna" || !roots.some((root2) => isWithin(root2, packageRoot))) {
108860
108924
  throw new Error("ALIAS_SOURCE_ROOT_UNSUPPORTED");
108861
108925
  }
108862
108926
  assertOwnedSafePath(packageRoot, home);
@@ -108934,8 +108998,8 @@ function adoptCopyfileAliases(options = {}) {
108934
108998
  for (const item of aliases) {
108935
108999
  if (readlinkSync5(item.path) !== item.oldLinkTarget || realpathSync14(item.path) !== item.oldTarget)
108936
109000
  throw new Error("ALIAS_CHANGED_BEFORE_SWITCH");
108937
- inspectAliasPackageChain(home, item.path, item.oldLinkTarget, item.oldTarget, layout.bin[basename13(item.path)], item.chain, true);
108938
- const source = validateAliasSource(home, basename13(item.path), item.oldTarget);
109001
+ inspectAliasPackageChain(home, item.path, item.oldLinkTarget, item.oldTarget, layout.bin[basename14(item.path)], item.chain, true);
109002
+ const source = validateAliasSource(home, basename14(item.path), item.oldTarget);
108939
109003
  if (source.version !== item.oldVersion || source.binarySha256 !== item.oldBinarySha256)
108940
109004
  throw new Error("ALIAS_SOURCE_DRIFT");
108941
109005
  receipt.state = "switching";
@@ -108944,11 +109008,11 @@ function adoptCopyfileAliases(options = {}) {
108944
109008
  replaceLink(item.path, item.newTarget, item.backupPath, item.oldLinkTarget, item.oldTarget);
108945
109009
  if (realpathSync14(item.path) !== item.newTarget || realpathSync14(item.backupPath) !== item.oldTarget)
108946
109010
  throw new Error("ALIAS_SWITCH_READBACK_MISMATCH");
108947
- inspectAliasPackageChain(home, item.path, item.oldLinkTarget, item.oldTarget, layout.bin[basename13(item.path)], item.chain, true);
109011
+ inspectAliasPackageChain(home, item.path, item.oldLinkTarget, item.oldTarget, layout.bin[basename14(item.path)], item.chain, true);
108948
109012
  options.onAliasSwitched?.(item.path);
108949
109013
  }
108950
109014
  for (const item of aliases) {
108951
- inspectAliasPackageChain(home, item.path, item.oldLinkTarget, item.oldTarget, layout.bin[basename13(item.path)], item.chain, true);
109015
+ inspectAliasPackageChain(home, item.path, item.oldLinkTarget, item.oldTarget, layout.bin[basename14(item.path)], item.chain, true);
108952
109016
  if (readlinkSync5(item.backupPath) !== item.oldLinkTarget || realpathSync14(item.backupPath) !== item.oldTarget)
108953
109017
  throw new Error("ALIAS_BACKUP_DRIFT");
108954
109018
  }
@@ -108961,16 +109025,16 @@ function adoptCopyfileAliases(options = {}) {
108961
109025
  for (const item of [...aliases].reverse()) {
108962
109026
  try {
108963
109027
  if (!entryExists(item.backupPath)) {
108964
- inspectAliasPackageChain(home, item.path, item.oldLinkTarget, item.oldTarget, layout.bin[basename13(item.path)], item.chain, true);
108965
- const source2 = validateAliasSource(home, basename13(item.path), item.oldTarget);
109028
+ inspectAliasPackageChain(home, item.path, item.oldLinkTarget, item.oldTarget, layout.bin[basename14(item.path)], item.chain, true);
109029
+ const source2 = validateAliasSource(home, basename14(item.path), item.oldTarget);
108966
109030
  if (!entryExists(item.path) || readlinkSync5(item.path) !== item.oldLinkTarget || realpathSync14(item.path) !== item.oldTarget || source2.version !== item.oldVersion || source2.binarySha256 !== item.oldBinarySha256)
108967
109031
  failed = true;
108968
109032
  continue;
108969
109033
  }
108970
109034
  if (readlinkSync5(item.backupPath) !== item.oldLinkTarget || realpathSync14(item.backupPath) !== item.oldTarget)
108971
109035
  throw new Error("ALIAS_BACKUP_DRIFT");
108972
- inspectAliasPackageChain(home, item.path, item.oldLinkTarget, item.oldTarget, layout.bin[basename13(item.path)], item.chain, true);
108973
- const source = validateAliasSource(home, basename13(item.path), item.oldTarget);
109036
+ inspectAliasPackageChain(home, item.path, item.oldLinkTarget, item.oldTarget, layout.bin[basename14(item.path)], item.chain, true);
109037
+ const source = validateAliasSource(home, basename14(item.path), item.oldTarget);
108974
109038
  if (source.version !== item.oldVersion || source.binarySha256 !== item.oldBinarySha256)
108975
109039
  throw new Error("ALIAS_SOURCE_DRIFT");
108976
109040
  if (realpathSync14(item.path) === item.oldTarget && readlinkSync5(item.path) === item.oldLinkTarget)
@@ -109023,7 +109087,7 @@ function rollbackCopyfileAliases(receiptId, options = {}) {
109023
109087
  throw new Error("ALIAS_RECEIPT_BINDING_INVALID");
109024
109088
  const seen = new Set;
109025
109089
  for (const item of receipt.aliases) {
109026
- const name = basename13(item.path), target = layout.bin[name];
109090
+ const name = basename14(item.path), target = layout.bin[name];
109027
109091
  if (!target || seen.has(item.path) || !aliasDirs(home).includes(dirname30(item.path)) || item.newTarget !== join55(layout.currentPackageRoot, target) || item.backupPath !== `${item.path}.skills-alias-prev-${receiptId}` || item.chain !== undefined && (!item.chain || typeof item.chain !== "object" || typeof item.chain.packageLinkPath !== "string" || typeof item.chain.packageLinkTarget !== "string")) {
109028
109092
  throw new Error("ALIAS_RECEIPT_LAUNCHER_INVALID");
109029
109093
  }
@@ -109072,7 +109136,7 @@ function rollbackCopyfileAliases(receiptId, options = {}) {
109072
109136
  restored++;
109073
109137
  }
109074
109138
  for (const item of receipt.aliases) {
109075
- inspectAliasPackageChain(home, item.path, item.oldLinkTarget, item.oldTarget, layout.bin[basename13(item.path)], item.chain, true);
109139
+ inspectAliasPackageChain(home, item.path, item.oldLinkTarget, item.oldTarget, layout.bin[basename14(item.path)], item.chain, true);
109076
109140
  }
109077
109141
  receipt.state = "rolled-back";
109078
109142
  persistAliasReceipt(receiptPath, receipt);
@@ -109105,7 +109169,7 @@ async function updateCopyfileRuntime(version2, options = {}) {
109105
109169
  const releaseLock = acquireRuntimeLock(layout.runtimeRoot);
109106
109170
  const stagePath = join55(layout.runtimeRoot, `.stage-${version2}-${id2}`);
109107
109171
  const finalPath = join55(layout.runtimeRoot, `${version2}-copyfile`);
109108
- const launchers = layout.launchers.map((item) => ({ ...item, newTarget: join55(finalPath, "node_modules", "@hasna", "skills", layout.bin[basename13(item.path)]) }));
109172
+ const launchers = layout.launchers.map((item) => ({ ...item, newTarget: join55(finalPath, "node_modules", "@hasna", "skills", layout.bin[basename14(item.path)]) }));
109109
109173
  let switched = [];
109110
109174
  let moved = false;
109111
109175
  try {
@@ -109288,7 +109352,7 @@ function rollbackCopyfileRuntime(receiptId, options = {}) {
109288
109352
  const switched = [];
109289
109353
  const seen = new Set;
109290
109354
  for (const item of receipt.launchers) {
109291
- const bin = oldBins[basename13(item.path)];
109355
+ const bin = oldBins[basename14(item.path)];
109292
109356
  if (!bin || !isAbsolute24(item.path) || seen.has(item.path) || item.oldTarget !== join55(receipt.currentPackageRoot, bin) || item.newTarget !== join55(receipt.targetPackageRoot, bin) || !/^.+\.skills-prev-[0-9a-f-]{36}$/.test(item.backupPath) || !item.backupPath.startsWith(`${item.path}.skills-prev-`) || typeof item.oldLinkTarget !== "string" || resolve23(dirname30(item.path), item.oldLinkTarget) !== item.oldTarget)
109293
109357
  throw new Error("RECEIPT_LAUNCHER_BINDING_INVALID");
109294
109358
  assertNoSymlinkAncestors(dirname30(item.path));
@@ -109358,7 +109422,7 @@ __export(exports_runtime, {
109358
109422
  });
109359
109423
  import { createHash as createHash28, randomUUID as randomUUID10 } from "crypto";
109360
109424
  import { lstatSync as lstatSync29, mkdirSync as mkdirSync25, readFileSync as readFileSync38, realpathSync as realpathSync15, writeFileSync as writeFileSync24 } from "fs";
109361
- import { basename as basename14, isAbsolute as isAbsolute25, join as join56 } from "path";
109425
+ import { basename as basename15, isAbsolute as isAbsolute25, join as join56 } from "path";
109362
109426
  import { createInterface } from "readline";
109363
109427
  function registerRuntime(parent) {
109364
109428
  parent.command("run").argument("<skill>", "Skill name").argument("[args...]", "Arguments to pass to the skill; use -- to end Skills options").allowUnknownOption(true).passThroughOptions(true).option("--json", "Output result as JSON", false).option("--remote", "Run on the configured server, using its catalog and quote", false).option("--target <target>", "Execution target: local or cloud").option("--secret-bindings <path>", "Reviewed, exact-selection local execution vault bindings (JSON file)").option("--secret-bindings-template", "Print a scoped bindings template without resolving secrets or running the skill", false).option("--input <json>", "Structured cloud execution input").option("--skill-version <version>", "Exact selected skill version").option("--selection-profile <id>", "Selected Skills profile").option("--session <id>", "Pinned Skills session").option("--cached", "Use the explicit verified selected cache", false).option("--yes", "Approve the server's quoted credit cost for this run", false).option("--idempotency-key <key>", "Reuse this key when retrying the same remote submission").option("--file <path>", "Attach a local input file to a remote run (repeatable)", (value, prior) => [...prior, value], []).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, command) => {
@@ -109871,7 +109935,7 @@ async function handleRun(name, args2, options, separatorBeforeSkill) {
109871
109935
  const info = lstatSync29(path);
109872
109936
  if (!info.isFile() || info.size > 20 * 1024 * 1024)
109873
109937
  throw new Error("Input must be a regular file no larger than 20 MiB");
109874
- return { name: basename14(path), bytes: new Uint8Array(readFileSync38(path)) };
109938
+ return { name: basename15(path), bytes: new Uint8Array(readFileSync38(path)) };
109875
109939
  });
109876
109940
  describeRemoteFiles(inputFiles);
109877
109941
  client2 = new RemoteSkillsClient(routing.apiKey, routing.apiOrigin);
@@ -111048,7 +111112,7 @@ import {
111048
111112
  statSync as statSync20,
111049
111113
  writeFileSync as writeFileSync25
111050
111114
  } from "fs";
111051
- import { dirname as dirname32, isAbsolute as isAbsolute26, relative as relative9, resolve as resolve24, sep as sep12 } from "path";
111115
+ import { dirname as dirname32, isAbsolute as isAbsolute26, relative as relative10, resolve as resolve24, sep as sep12 } from "path";
111052
111116
  function validateStationId(stationId) {
111053
111117
  if (!/^[a-z0-9-]+$/.test(stationId)) {
111054
111118
  throw new StationSnapshotError("INVALID_STATION", `station id must be a slug, got: ${stationId}`);
@@ -111153,7 +111217,7 @@ function writeStationSnapshot(options) {
111153
111217
  const untouched = [];
111154
111218
  for (const plan of plans) {
111155
111219
  const destination = resolve24(repoRoot, plan.destination);
111156
- const destinationRelative = relative9(repoRoot, destination);
111220
+ const destinationRelative = relative10(repoRoot, destination);
111157
111221
  if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep12) || isAbsolute26(destinationRelative)) {
111158
111222
  throw new StationSnapshotError("DESTINATION_ESCAPE", `destination escapes repo root: ${plan.destination}`);
111159
111223
  }
@@ -112342,7 +112406,7 @@ function registerAgentIntegration(parent) {
112342
112406
  hook.command("agents").option("--json", "Output the adapter capability inventory", false).description("Show maintained native adapters and explicit coverage limits").action(async () => {
112343
112407
  await writeCliOutput(JSON.stringify({ agents: INTEGRATION_AGENTS.map((agent) => ({ agent, bridge: true, ...AGENT_ADAPTERS[agent] })), inventoryOnly: ["codewith", "windsurf", "pi", "amp", "cline", "roo", "copilot"], limitations: ["Cursor prompt hooks gate submission; selected context is injected at session start only.", "Native discovery checks cover known home roots and current project ancestors. External plugin hook injection and arbitrary added directories require separate review.", "Hermes injects selected prompt context, but native pre_llm_call fails open. Exact native hook trust, bundled reseeding opt-out, native payload retirement and a supervised pre-tool guard are required. Child failures block explicitly; native host/supervisor death is not a universal fail-closed guarantee.", "Restart agents and use their normal hook trust controls after installation."] }, null, 2));
112344
112408
  });
112345
- hook.command("install").option("--agent <agent>", `Agent to configure: ${INTEGRATION_AGENTS.join(", ")}, all`, "all").option("--command <path>", "Skills executable used by the hook (preserves existing binding; new agents use skills)").option("--selection-profile <id>", "Selection profile (preserves existing binding; new agents use default)").option("--include-vendor", "Retained for compatibility; vendor system skills are always inventoried and disabled", false).option("--discovery-inputs <file>", "Advanced reviewed active plugin roots and source hashes for unsupported registrations").option("--codex-native-catalog <file>", "Reviewed native0.159.2 skills/list receipt for exact qualified plugin-name disables").option("--reviewed-cache-alias <path>", "Exact skill-containing vendor cache alias reviewed for this hook plan").option("--allow-root-aliases", "Allow home .claude/.codex aliases to existing directories within this home", false).option("--apply", "Apply the plan, preserving prior configuration in private backups", false).option("--json", "Output a receipt as JSON", false).description("Plan or install one Skills CLI bridge plus native prompt hooks").action(async (options) => {
112409
+ hook.command("install").option("--agent <agent>", `Agent to configure: ${INTEGRATION_AGENTS.join(", ")}, all`, "all").option("--command <path>", "Skills executable used by the hook (preserves existing binding; new agents use skills)").option("--selection-profile <id>", "Selection profile (preserves existing binding; new agents use default)").option("--include-vendor", "Retained for compatibility; vendor system skills are always inventoried and disabled", false).option("--discovery-inputs <file>", "Advanced reviewed active plugin roots and source hashes for unsupported registrations").option("--codex-native-catalog <file>", "Reviewed Codex 0.159.2 skill and installed-plugin receipt for exact qualified-name disables").option("--reviewed-cache-alias <path>", "Exact skill-containing vendor cache alias reviewed for this hook plan").option("--allow-root-aliases", "Allow home .claude/.codex aliases to existing directories within this home", false).option("--apply", "Apply the plan, preserving prior configuration in private backups", false).option("--json", "Output a receipt as JSON", false).description("Plan or install one Skills CLI bridge plus native prompt hooks").action(async (options) => {
112346
112410
  try {
112347
112411
  const discoveryInputs = options.discoveryInputs ? JSON.parse(readFileSync41(options.discoveryInputs, "utf8")) : undefined;
112348
112412
  const plan = planAgentIntegration({ projectDir: process.cwd(), agents: agents(options.agent), command: options.command, profileId: options.selectionProfile, includeVendor: options.includeVendor, discoveryInputs, allowRootAliases: options.allowRootAliases, reviewedCacheAlias: options.reviewedCacheAlias, codexNativeCatalog: options.codexNativeCatalog ? JSON.parse(readFileSync41(options.codexNativeCatalog, "utf8")) : undefined });
@@ -113188,7 +113252,7 @@ var init_hydrate = __esm(() => {
113188
113252
  import { createHash as createHash33, randomUUID as randomUUID12 } from "crypto";
113189
113253
  import { chmodSync as chmodSync5, existsSync as existsSync36, lstatSync as lstatSync33, mkdirSync as mkdirSync29, mkdtempSync as mkdtempSync6, readFileSync as readFileSync43, readdirSync as readdirSync25, renameSync as renameSync14, rmSync as rmSync9, writeFileSync as writeFileSync30 } from "fs";
113190
113254
  import { tmpdir as tmpdir2 } from "os";
113191
- import { dirname as dirname36, isAbsolute as isAbsolute30, join as join62, relative as relative10, resolve as resolve27, sep as sep14 } from "path";
113255
+ import { dirname as dirname36, isAbsolute as isAbsolute30, join as join62, relative as relative11, resolve as resolve27, sep as sep14 } from "path";
113192
113256
  function prepareSkill(name, options) {
113193
113257
  const normalized = normalizePortableSkillName(name);
113194
113258
  if (!new RegExp(SEMVER_PATTERN).test(options.version))
@@ -113294,7 +113358,7 @@ function validateRuntimeEntrypoint(candidate2, root2) {
113294
113358
  const entry = candidate2.runtime.entrypoint;
113295
113359
  if (typeof entry !== "string")
113296
113360
  return;
113297
- const target = resolve27(root2, entry), rel = relative10(root2, target);
113361
+ const target = resolve27(root2, entry), rel = relative11(root2, target);
113298
113362
  if (isAbsolute30(entry) || /^[a-zA-Z]:/.test(entry) || entry.includes("\\") || !rel || rel === ".." || rel.startsWith(`..${sep14}`) || isAbsolute30(rel) || !existsSync36(target) || !lstatSync33(target).isFile()) {
113299
113363
  throw new Error("Executable runtime.entrypoint must name an existing regular file inside the skill directory.");
113300
113364
  }
@@ -113386,11 +113450,11 @@ function snapshot2(root2) {
113386
113450
  const files = [], directories = [];
113387
113451
  const hash6 = createHash33("sha256").update(`${rootStat.dev}:${rootStat.ino}\x00`);
113388
113452
  let count = 0, bytes = 0;
113389
- const walk2 = (relative11) => {
113390
- for (const name of readdirSync25(join62(root2, relative11)).sort()) {
113391
- if (IGNORED.has(name.toLowerCase()) || !relative11 && ROOT_IGNORED.has(name.toLowerCase()))
113453
+ const walk2 = (relative12) => {
113454
+ for (const name of readdirSync25(join62(root2, relative12)).sort()) {
113455
+ if (IGNORED.has(name.toLowerCase()) || !relative12 && ROOT_IGNORED.has(name.toLowerCase()))
113392
113456
  continue;
113393
- const path = relative11 ? `${relative11}/${name}` : name;
113457
+ const path = relative12 ? `${relative12}/${name}` : name;
113394
113458
  if (++count > 20000)
113395
113459
  throw new Error("Skill exceeds the preparation entry limit (20000).");
113396
113460
  const absolute = join62(root2, path), stat3 = lstatSync33(absolute);
@@ -113809,7 +113873,7 @@ var init_schedule = __esm(() => {
113809
113873
 
113810
113874
  // src/lib/registry-sync.ts
113811
113875
  import { mkdirSync as mkdirSync30, writeFileSync as writeFileSync31 } from "fs";
113812
- import { dirname as dirname37, relative as relative11 } from "path";
113876
+ import { dirname as dirname37, relative as relative12 } from "path";
113813
113877
  function createRegistrySyncArtifact(options = {}) {
113814
113878
  const profile = options.profile ?? "all";
113815
113879
  const includeDocs = options.includeDocs ?? true;
@@ -113821,7 +113885,7 @@ function createRegistrySyncArtifact(options = {}) {
113821
113885
  const registry2 = [...loadRegistryProfile(profile)].sort((a, b) => a.name.localeCompare(b.name));
113822
113886
  const skills = registry2.map((skill) => {
113823
113887
  const skillPath = getSkillPath(skill.name);
113824
- const directory2 = relative11(process.cwd(), skillPath) || skillPath;
113888
+ const directory2 = relative12(process.cwd(), skillPath) || skillPath;
113825
113889
  const validation = includeValidation ? validateSkillDirectory(skill.name, skillPath, skill) : undefined;
113826
113890
  const docs = includeDocs ? buildDocs(skill.name) : undefined;
113827
113891
  return {
@@ -113887,7 +113951,7 @@ var init_registry_sync = __esm(() => {
113887
113951
 
113888
113952
  // src/lib/review-export.ts
113889
113953
  import { constants as constants22, closeSync as closeSync25, existsSync as existsSync37, fstatSync as fstatSync25, fsyncSync as fsyncSync7, lstatSync as lstatSync34, openSync as openSync25, realpathSync as realpathSync18, statSync as statSync23, writeFileSync as writeFileSync32 } from "fs";
113890
- import { basename as basename15, dirname as dirname38, isAbsolute as isAbsolute31, join as join63, parse as parse12, resolve as resolve28, sep as sep15 } from "path";
113954
+ import { basename as basename16, dirname as dirname38, isAbsolute as isAbsolute31, join as join63, parse as parse12, resolve as resolve28, sep as sep15 } from "path";
113891
113955
  function exactVersion(spec) {
113892
113956
  const at2 = spec.indexOf("@");
113893
113957
  const slug2 = spec.slice(0, at2);
@@ -113898,7 +113962,7 @@ function exactVersion(spec) {
113898
113962
  return { slug: slug2, version: version2 };
113899
113963
  }
113900
113964
  function assertPrivateDestination(output2) {
113901
- if (!isAbsolute31(output2) || resolve28(output2) !== output2 || !basename15(output2).endsWith(".tar.gz")) {
113965
+ if (!isAbsolute31(output2) || resolve28(output2) !== output2 || !basename16(output2).endsWith(".tar.gz")) {
113902
113966
  throw new Error("Review output must be an absolute, normalized .tar.gz path.");
113903
113967
  }
113904
113968
  const parent = dirname38(output2);