@hasna/skills 0.8.11 → 0.9.1

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/dist/index.js CHANGED
@@ -8323,6 +8323,7 @@ function readManifest(skillPath, fallbackName, normalizeName) {
8323
8323
  const version = readDeclaredSkillVersion(skillPath) ?? PORTABLE_SKILL_DEFAULT_VERSION;
8324
8324
  const kind = parseSkillKind(stringField(jsonManifest, "kind") ?? frontmatter?.kind);
8325
8325
  const commands = parseManifestCommands(jsonManifest) ?? (kind === "instruction" ? [] : inferPackageCommands(pkg, name)) ?? [];
8326
+ const runtime = parseManifestRuntime(jsonManifest) ?? inferRuntimeFromCommands(commands);
8326
8327
  return {
8327
8328
  $schema: stringField(jsonManifest, "$schema") ?? PORTABLE_SKILL_SCHEMA,
8328
8329
  standard: stringField(jsonManifest, "standard") ?? PORTABLE_SKILL_STANDARD,
@@ -8335,7 +8336,7 @@ function readManifest(skillPath, fallbackName, normalizeName) {
8335
8336
  ...kind ? { kind } : {},
8336
8337
  inputs: kind === "instruction" ? parseManifestInputs(jsonManifest) ?? [] : parseManifestInputs(jsonManifest) ?? DEFAULT_INPUTS,
8337
8338
  commands,
8338
- ...parseManifestRuntime(jsonManifest) ? { runtime: parseManifestRuntime(jsonManifest) } : {},
8339
+ ...runtime ? { runtime } : {},
8339
8340
  ...parseManifestProvenance(jsonManifest) ? { provenance: parseManifestProvenance(jsonManifest) } : {}
8340
8341
  };
8341
8342
  }
@@ -8854,6 +8855,12 @@ function inferPackageCommands(pkg, fallbackName) {
8854
8855
  }
8855
8856
  return;
8856
8857
  }
8858
+ function inferRuntimeFromCommands(commands) {
8859
+ const entrypoint = commands.find((command) => command.entry)?.entry;
8860
+ if (!entrypoint || !entrypoint.toLowerCase().endsWith(".py"))
8861
+ return;
8862
+ return { ...defaultRuntimeContract(entrypoint), runtime: "python3" };
8863
+ }
8857
8864
  function readJsonObject(path) {
8858
8865
  const parsed = JSON.parse(readFileSync5(path, "utf-8"));
8859
8866
  if (!isRecord2(parsed))
@@ -9650,7 +9657,7 @@ import { homedir as homedir5 } from "os";
9650
9657
  import {
9651
9658
  cpSync as cpSync2,
9652
9659
  existsSync as existsSync12,
9653
- lstatSync as lstatSync18,
9660
+ lstatSync as lstatSync19,
9654
9661
  mkdirSync as mkdirSync8,
9655
9662
  mkdtempSync as mkdtempSync2,
9656
9663
  readFileSync as readFileSync15,
@@ -9661,12 +9668,12 @@ import {
9661
9668
  writeFileSync as writeFileSync6
9662
9669
  } from "fs";
9663
9670
  import { homedir as homedir4 } from "os";
9664
- import { basename as basename7, dirname as dirname15, join as join26 } from "path";
9671
+ import { basename as basename9, dirname as dirname16, join as join26 } from "path";
9665
9672
 
9666
9673
  // src/lib/agent-integration.ts
9667
- import { createHash as createHash13, randomUUID as randomUUID3 } from "crypto";
9668
- import { existsSync as existsSync11, lstatSync as lstatSync17, statSync as statSync8, mkdirSync as mkdirSync7, readFileSync as readFileSync14, readdirSync as readdirSync10, opendirSync as opendirSync5, readlinkSync as readlinkSync2, realpathSync as realpathSync5, renameSync as renameSync4, rmdirSync as rmdirSync3, writeFileSync as writeFileSync5, unlinkSync as unlinkSync4, chmodSync, openSync as openSync10, closeSync as closeSync10, fsyncSync as fsyncSync3, fstatSync as fstatSync10, readSync as readSync8, constants as constants9, linkSync as linkSync2 } from "fs";
9669
- import { dirname as dirname14, join as join25, resolve as resolve14, relative as relative5, isAbsolute as isAbsolute14, sep as sep6 } from "path";
9674
+ import { createHash as createHash14, randomUUID as randomUUID3 } from "crypto";
9675
+ import { existsSync as existsSync11, lstatSync as lstatSync18, statSync as statSync8, mkdirSync as mkdirSync7, readFileSync as readFileSync14, readdirSync as readdirSync10, opendirSync as opendirSync5, readlinkSync as readlinkSync2, realpathSync as realpathSync5, renameSync as renameSync4, rmdirSync as rmdirSync3, writeFileSync as writeFileSync5, unlinkSync as unlinkSync4, chmodSync, openSync as openSync11, closeSync as closeSync11, fsyncSync as fsyncSync3, fstatSync as fstatSync11, readSync as readSync9, constants as constants10, linkSync as linkSync2 } from "fs";
9676
+ import { dirname as dirname15, join as join25, resolve as resolve15, relative as relative5, isAbsolute as isAbsolute15, sep as sep6 } from "path";
9670
9677
  import { homedir as homedir3 } from "os";
9671
9678
 
9672
9679
  // src/lib/managed-policy.ts
@@ -10807,7 +10814,9 @@ function assertAgentPolicyCollections(policy) {
10807
10814
  text(source.path);
10808
10815
  requireBound(source.sha256 === null || typeof source.sha256 === "string" && /^[a-f0-9]{64}$/.test(source.sha256));
10809
10816
  if (source.hashMode !== undefined)
10810
- requireBound(["bytes", "path-bytes", "claude-plugin-registry", "claude-marketplace-registry"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
10817
+ requireBound(["bytes", "path-bytes", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
10818
+ if (source.hashMode === "claude-settings-v1")
10819
+ requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute3(source.path) && resolve4(source.path) === source.path && basename3(source.path) === "settings.json");
10811
10820
  if (source.hashMode === "claude-marketplace-registry")
10812
10821
  requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute3(source.path) && resolve4(source.path) === source.path && basename3(source.path) === "known_marketplaces.json");
10813
10822
  if (source.hashMode === "claude-plugin-registry") {
@@ -10961,9 +10970,9 @@ function isOwnedCliBridge(path, expectedPaths) {
10961
10970
  }
10962
10971
 
10963
10972
  // src/lib/agent-discovery.ts
10964
- import { createHash as createHash12 } from "crypto";
10965
- import { lstatSync as lstatSync16, readFileSync as readFileSync13, readdirSync as readdirSync9, realpathSync as realpathSync4 } from "fs";
10966
- import { dirname as dirname13, isAbsolute as isAbsolute13, join as join23, resolve as resolve13, sep as sep5 } from "path";
10973
+ import { createHash as createHash13 } from "crypto";
10974
+ import { lstatSync as lstatSync17, readFileSync as readFileSync13, readdirSync as readdirSync9, realpathSync as realpathSync4 } from "fs";
10975
+ import { basename as basename8, dirname as dirname14, isAbsolute as isAbsolute14, join as join23, resolve as resolve14, sep as sep5 } from "path";
10967
10976
 
10968
10977
  // node_modules/yaml/dist/index.js
10969
10978
  var composer = require_composer();
@@ -11439,7 +11448,7 @@ import { isAbsolute as isAbsolute10, join as join20, resolve as resolve10 } from
11439
11448
  // package.json
11440
11449
  var package_default = {
11441
11450
  name: "@hasna/skills",
11442
- version: "0.8.11",
11451
+ version: "0.9.1",
11443
11452
  description: "Skills library for AI coding agents",
11444
11453
  type: "module",
11445
11454
  bin: {
@@ -14931,8 +14940,228 @@ function captureClaudeMarketplaceRegistry(path, budget = { remaining: 256 * 1024
14931
14940
  return { path, hashMode: "claude-marketplace-registry", sha256: sha2562 };
14932
14941
  }
14933
14942
 
14943
+ // src/lib/claude-settings-witness.ts
14944
+ import { createHash as createHash12 } from "crypto";
14945
+ import { closeSync as closeSync10, constants as constants9, fstatSync as fstatSync10, lstatSync as lstatSync16, openSync as openSync10, readSync as readSync8 } from "fs";
14946
+ import { basename as basename7, dirname as dirname13, isAbsolute as isAbsolute13, resolve as resolve13 } from "path";
14947
+ var CLAUDE_SETTINGS_WITNESS_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
14948
+ function need3(value, reason) {
14949
+ if (!value)
14950
+ throw new Error(`Claude settings witness ${reason}`);
14951
+ }
14952
+ function absolutePath2(value) {
14953
+ need3(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_SETTINGS_WITNESS_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute13(value) && resolve13(value) === value, "requires a normalized absolute path");
14954
+ }
14955
+ var sameFile2 = (a, b) => a.dev === b.dev && a.ino === b.ino && a.mode === b.mode && a.uid === b.uid && a.gid === b.gid && a.nlink === b.nlink && a.size === b.size && a.mtimeNs === b.mtimeNs && a.ctimeNs === b.ctimeNs;
14956
+ function parents2(path) {
14957
+ const result = [];
14958
+ for (let at = dirname13(path);; at = dirname13(at)) {
14959
+ const stat2 = lstatSync16(at, { bigint: true });
14960
+ need3(stat2.isDirectory() && !stat2.isSymbolicLink(), "path traverses a symlink or non-directory");
14961
+ result.push([at, stat2]);
14962
+ if (at === dirname13(at))
14963
+ return result;
14964
+ }
14965
+ }
14966
+ function readSettings(path, budget) {
14967
+ absolutePath2(path);
14968
+ need3(basename7(path) === "settings.json", "requires settings.json");
14969
+ need3(Number.isSafeInteger(budget.remaining) && budget.remaining >= 0, "has an invalid byte budget");
14970
+ const ancestors2 = parents2(path), initial = lstatSync16(path, { bigint: true });
14971
+ need3(initial.isFile() && !initial.isSymbolicLink() && initial.size <= BigInt(CLAUDE_SETTINGS_WITNESS_LIMITS.bytes), "is not a bounded regular file");
14972
+ need3(initial.size <= BigInt(budget.remaining), "exceeds its aggregate byte limit");
14973
+ const fd = openSync10(path, constants9.O_RDONLY | constants9.O_NOFOLLOW | constants9.O_NONBLOCK);
14974
+ try {
14975
+ const opened = fstatSync10(fd, { bigint: true });
14976
+ need3(opened.isFile() && sameFile2(initial, opened), "changed during open");
14977
+ const bytes = Buffer.alloc(Number(opened.size) + 1);
14978
+ let length = 0;
14979
+ while (length < bytes.length) {
14980
+ const count = readSync8(fd, bytes, length, bytes.length - length, null);
14981
+ if (!count)
14982
+ break;
14983
+ length += count;
14984
+ }
14985
+ const after = fstatSync10(fd, { bigint: true }), current = lstatSync16(path, { bigint: true });
14986
+ need3(current.isFile() && sameFile2(opened, after) && sameFile2(after, current) && BigInt(length) === opened.size, "changed during read");
14987
+ for (const [ancestor, before] of ancestors2) {
14988
+ const now = lstatSync16(ancestor, { bigint: true });
14989
+ need3(now.isDirectory() && before.dev === now.dev && before.ino === now.ino && before.mode === now.mode, "parent changed during read");
14990
+ }
14991
+ budget.remaining -= length;
14992
+ try {
14993
+ return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes.subarray(0, length));
14994
+ } catch {
14995
+ throw new Error("Claude settings witness is not strict UTF-8");
14996
+ }
14997
+ } finally {
14998
+ closeSync10(fd);
14999
+ }
15000
+ }
15001
+ function parse6(text2) {
15002
+ let at = 0, nodes = 0;
15003
+ const numberPattern = /-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?/y;
15004
+ const space = () => {
15005
+ while (at < text2.length && /[\x20\t\r\n]/.test(text2[at]))
15006
+ at++;
15007
+ };
15008
+ function string() {
15009
+ need3(text2[at] === '"', "contains invalid JSON");
15010
+ const start = at++;
15011
+ while (at < text2.length) {
15012
+ const character = text2[at++];
15013
+ if (character === '"') {
15014
+ let value2;
15015
+ try {
15016
+ value2 = JSON.parse(text2.slice(start, at));
15017
+ } catch {
15018
+ throw new Error("Claude settings witness contains invalid JSON string");
15019
+ }
15020
+ need3(value2.length <= CLAUDE_SETTINGS_WITNESS_LIMITS.stringCharacters, "exceeds its string limit");
15021
+ return value2;
15022
+ }
15023
+ if (character === "\\")
15024
+ at++;
15025
+ }
15026
+ throw new Error("Claude settings witness contains an unterminated JSON string");
15027
+ }
15028
+ function value(depth) {
15029
+ need3(depth <= CLAUDE_SETTINGS_WITNESS_LIMITS.depth && ++nodes <= CLAUDE_SETTINGS_WITNESS_LIMITS.nodes, "exceeds its nesting or node limit");
15030
+ space();
15031
+ const character = text2[at];
15032
+ if (character === '"')
15033
+ return { kind: "string", value: string() };
15034
+ if (character === "{" || character === "[") {
15035
+ at++;
15036
+ space();
15037
+ const object4 = character === "{", end = object4 ? "}" : "]", entries = [], items = [], keys = new Set;
15038
+ if (text2[at] !== end)
15039
+ while (true) {
15040
+ if (object4) {
15041
+ space();
15042
+ const key = string();
15043
+ need3(!keys.has(key), "contains a duplicate JSON key");
15044
+ keys.add(key);
15045
+ space();
15046
+ need3(text2[at++] === ":", "contains invalid JSON");
15047
+ entries.push([key, value(depth + 1)]);
15048
+ } else
15049
+ items.push(value(depth + 1));
15050
+ space();
15051
+ if (text2[at] === end)
15052
+ break;
15053
+ need3(text2[at++] === ",", "contains invalid JSON");
15054
+ }
15055
+ at++;
15056
+ return object4 ? { kind: "object", entries } : { kind: "array", items };
15057
+ }
15058
+ for (const literal of ["true", "false", "null"])
15059
+ if (text2.startsWith(literal, at)) {
15060
+ at += literal.length;
15061
+ return { kind: "literal", value: literal };
15062
+ }
15063
+ numberPattern.lastIndex = at;
15064
+ const number = numberPattern.exec(text2);
15065
+ need3(number, "contains invalid JSON");
15066
+ at += number[0].length;
15067
+ return { kind: "number", value: number[0] };
15068
+ }
15069
+ const root2 = value(0);
15070
+ space();
15071
+ need3(at === text2.length && root2.kind === "object", "requires a JSON object without trailing content");
15072
+ need3(root2.entries.length <= CLAUDE_SETTINGS_WITNESS_LIMITS.rows, "exceeds its settings field limit");
15073
+ return root2;
15074
+ }
15075
+ var BOOLEAN_PREFERENCES = new Set([
15076
+ "autoScrollEnabled",
15077
+ "axScreenReader",
15078
+ "emojiCompletionEnabled",
15079
+ "prefersReducedMotion",
15080
+ "showTurnDuration",
15081
+ "spinnerTipsEnabled",
15082
+ "syntaxHighlightingDisabled",
15083
+ "terminalProgressBarEnabled",
15084
+ "terminalTitleFromRename",
15085
+ "verbose",
15086
+ "wheelScrollAccelerationEnabled"
15087
+ ]);
15088
+ var ENUM_PREFERENCES = Object.freeze({
15089
+ editorMode: ["normal", "vim"],
15090
+ tui: ["default", "fullscreen"],
15091
+ viewMode: ["default", "verbose", "focus"]
15092
+ });
15093
+ var BUILTIN_MODEL_SELECTIONS = new Set([
15094
+ "default",
15095
+ "best",
15096
+ "fable",
15097
+ "fable[1m]",
15098
+ "sonnet",
15099
+ "sonnet[1m]",
15100
+ "opus",
15101
+ "opus[1m]",
15102
+ "haiku",
15103
+ "opusplan",
15104
+ "claude-fable-5-1",
15105
+ "claude-fable-5",
15106
+ "claude-fable-5[1m]",
15107
+ "claude-opus-5",
15108
+ "claude-sonnet-5",
15109
+ "claude-haiku-4-5-20251001",
15110
+ "claude-opus-4-6",
15111
+ "claude-sonnet-4-5",
15112
+ "claude-sonnet-4-5-20250929",
15113
+ "claude-opus-4-8",
15114
+ "claude-opus-4-8[1m]",
15115
+ "claude-opus-4-7",
15116
+ "claude-sonnet-4-6",
15117
+ "claude-opus-4-5-20251101",
15118
+ "claude-opus-4-5",
15119
+ "claude-haiku-4-5",
15120
+ "claude-fable-5-1[1m]",
15121
+ "claude-opus-5[1m]",
15122
+ "claude-opus-4-7[1m]",
15123
+ "claude-opus-4-6[1m]",
15124
+ "claude-sonnet-4-6[1m]"
15125
+ ]);
15126
+ function canonical3(value) {
15127
+ if (value.kind === "object")
15128
+ return { kind: "object", entries: value.entries.map(([key, child]) => [key, canonical3(child)]).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0) };
15129
+ if (value.kind === "array")
15130
+ return { kind: "array", items: value.items.map(canonical3) };
15131
+ return value;
15132
+ }
15133
+ function settingsDigest(text2) {
15134
+ const value = parse6(text2);
15135
+ value.entries = value.entries.filter(([key, child]) => {
15136
+ if (key === "model") {
15137
+ need3(child.kind === "string", "contains an invalid model selection");
15138
+ return !BUILTIN_MODEL_SELECTIONS.has(child.value);
15139
+ }
15140
+ if (BOOLEAN_PREFERENCES.has(key)) {
15141
+ need3(child.kind === "literal" && (child.value === "true" || child.value === "false"), "contains an invalid display preference");
15142
+ return false;
15143
+ }
15144
+ if (Object.hasOwn(ENUM_PREFERENCES, key)) {
15145
+ need3(child.kind === "string" && ENUM_PREFERENCES[key].includes(child.value), "contains an invalid display preference");
15146
+ return false;
15147
+ }
15148
+ return true;
15149
+ });
15150
+ return createHash12("sha256").update("hasna.skills.claude-settings.v1\x00").update(JSON.stringify(canonical3(value))).digest("hex");
15151
+ }
15152
+ function hashClaudeSettingsReplacement(text2, budget) {
15153
+ need3(typeof text2 === "string", "requires settings text");
15154
+ const bytes = Buffer.byteLength(text2);
15155
+ need3(bytes <= CLAUDE_SETTINGS_WITNESS_LIMITS.bytes && Number.isSafeInteger(budget.remaining) && budget.remaining >= bytes, "exceeds its byte limit");
15156
+ budget.remaining -= bytes;
15157
+ return settingsDigest(text2);
15158
+ }
15159
+ function captureClaudeSettings(path, budget = { remaining: 256 * 1024 * 1024 }) {
15160
+ return { path, hashMode: "claude-settings-v1", sha256: settingsDigest(readSettings(path, budget)) };
15161
+ }
15162
+
14934
15163
  // src/lib/agent-discovery.ts
14935
- var digest = (text2) => createHash12("sha256").update(text2).digest("hex");
15164
+ var digest = (text2) => createHash13("sha256").update(text2).digest("hex");
14936
15165
  function parseConfig(text2, path, toml = false) {
14937
15166
  try {
14938
15167
  const value = toml ? Bun.TOML.parse(text2) : JSON.parse(text2);
@@ -14944,12 +15173,12 @@ function parseConfig(text2, path, toml = false) {
14944
15173
  }
14945
15174
  }
14946
15175
  function safe4(path) {
14947
- if (!isAbsolute13(path) || path.includes("\x00"))
15176
+ if (!isAbsolute14(path) || path.includes("\x00"))
14948
15177
  throw new Error("Expected an absolute native discovery path");
14949
- for (let cursor = path;; cursor = dirname13(cursor)) {
14950
- if (lstatSync16(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
15178
+ for (let cursor = path;; cursor = dirname14(cursor)) {
15179
+ if (lstatSync17(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
14951
15180
  throw new Error(`Refusing symlink native discovery input: ${cursor}`);
14952
- if (dirname13(cursor) === cursor)
15181
+ if (dirname14(cursor) === cursor)
14953
15182
  break;
14954
15183
  }
14955
15184
  }
@@ -14957,7 +15186,7 @@ function read(path, changes) {
14957
15186
  safe4(path);
14958
15187
  if (changes?.has(path))
14959
15188
  return changes.get(path);
14960
- const stat2 = lstatSync16(path, { throwIfNoEntry: false });
15189
+ const stat2 = lstatSync17(path, { throwIfNoEntry: false });
14961
15190
  if (!stat2)
14962
15191
  return null;
14963
15192
  if (!stat2.isFile() || stat2.size > 16 * 1024 * 1024)
@@ -14965,6 +15194,14 @@ function read(path, changes) {
14965
15194
  return readFileSync13(path, "utf8");
14966
15195
  }
14967
15196
  function projected(source, changes, budget = discoveryByteBudget()) {
15197
+ if (source.hashMode === "claude-settings-v1") {
15198
+ if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
15199
+ throw new Error("Claude settings witnesses require exact typed metadata");
15200
+ const current = captureClaudeSettings(source.path, budget).sha256;
15201
+ if (current !== source.sha256)
15202
+ throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
15203
+ return changes?.has(source.path) ? hashClaudeSettingsReplacement(changes.get(source.path), budget) : current;
15204
+ }
14968
15205
  if (source.hashMode === "claude-marketplace-registry") {
14969
15206
  if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256) || changes?.has(source.path))
14970
15207
  throw new Error("Claude marketplace witnesses require an exact reviewed registry without synthetic changes");
@@ -15022,6 +15259,8 @@ function verifyAgentDiscovery(binding) {
15022
15259
  safe4(root2);
15023
15260
  }
15024
15261
  function assertMarketplaceBinding(binding, source) {
15262
+ if (source.hashMode === "claude-settings-v1" && (binding.agent !== "claude" || binding.method !== "reviewed" || basename8(source.path) !== "settings.json"))
15263
+ throw new Error("Claude settings witnesses require explicit reviewed Claude configuration");
15025
15264
  if (source.hashMode === "claude-marketplace-registry" && (binding.agent !== "claude" || binding.method !== "reviewed"))
15026
15265
  throw new Error("Claude marketplace witnesses require explicit reviewed Claude discovery");
15027
15266
  }
@@ -15045,10 +15284,10 @@ function captureDiscoveryPathSources(paths) {
15045
15284
  return paths.map((path) => ({ path, hashMode: "path-bytes", sha256: hashDiscoveryPathFile(path, budget) }));
15046
15285
  }
15047
15286
  function resolveAgentDiscovery(options) {
15048
- const canonical3 = options.canonical ?? resolve13, home = resolve13(options.home), agent = options.agent;
15287
+ const canonical4 = options.canonical ?? resolve14, home = resolve14(options.home), agent = options.agent;
15049
15288
  const sources = [], roots = new Set, builtinNames = [];
15050
15289
  const witness = (path, format, fields) => {
15051
- const source = { path: canonical3(path), sha256: null, ...format ? { format, fields } : {} };
15290
+ const source = { path: canonical4(path), sha256: null, ...format ? { format, fields } : {} };
15052
15291
  source.sha256 = projected(source);
15053
15292
  sources.push(source);
15054
15293
  return read(source.path);
@@ -15076,7 +15315,7 @@ function resolveAgentDiscovery(options) {
15076
15315
  continue;
15077
15316
  if (normalized.startsWith("~") && normalized !== "~" && !normalized.startsWith("~/"))
15078
15317
  unresolved("user-specific tilde expansion requires a separate discovery adapter");
15079
- const path = normalized === "~" ? home : normalized.startsWith("~/") ? join23(home, normalized.slice(2)) : resolve13(home, ".hermes", normalized);
15318
+ const path = normalized === "~" ? home : normalized.startsWith("~/") ? join23(home, normalized.slice(2)) : resolve14(home, ".hermes", normalized);
15080
15319
  safe4(path);
15081
15320
  roots.add(path);
15082
15321
  }
@@ -15085,21 +15324,21 @@ function resolveAgentDiscovery(options) {
15085
15324
  const executable = Bun.which("gemini");
15086
15325
  if (executable) {
15087
15326
  let packageRoot;
15088
- for (let directory = dirname13(realpathSync4(executable)), depth = 0;depth < 8; directory = dirname13(directory), depth++) {
15327
+ for (let directory = dirname14(realpathSync4(executable)), depth = 0;depth < 8; directory = dirname14(directory), depth++) {
15089
15328
  const path = join23(directory, "package.json"), raw = read(path);
15090
15329
  if (raw !== null && parseConfig(raw, path).name === "@google/gemini-cli") {
15091
15330
  packageRoot = directory;
15092
15331
  witness(path);
15093
15332
  break;
15094
15333
  }
15095
- if (dirname13(directory) === directory)
15334
+ if (dirname14(directory) === directory)
15096
15335
  break;
15097
15336
  }
15098
15337
  if (!packageRoot)
15099
15338
  unresolved("installed Gemini package layout is not recognized");
15100
15339
  const builtinRoot = join23(packageRoot, "bundle/builtin");
15101
15340
  safe4(builtinRoot);
15102
- if (!lstatSync16(builtinRoot, { throwIfNoEntry: false })?.isDirectory())
15341
+ if (!lstatSync17(builtinRoot, { throwIfNoEntry: false })?.isDirectory())
15103
15342
  unresolved("installed Gemini builtin root is missing");
15104
15343
  for (const name of readdirSync9(builtinRoot).sort()) {
15105
15344
  const text2 = witness(join23(builtinRoot, name, "SKILL.md"));
@@ -15120,12 +15359,14 @@ function resolveAgentDiscovery(options) {
15120
15359
  if (review.sources.some((source) => source.format !== undefined || source.fields !== undefined))
15121
15360
  throw new Error("Explicit discovery reviews require full source-file hashes");
15122
15361
  verifyAgentDiscovery(supplied);
15123
- if (!review.sources.some((source) => source.path === canonical3(configPath)))
15362
+ if (review.sources.some((source) => source.hashMode === "claude-settings-v1" && source.path !== canonical4(configPath)))
15363
+ throw new Error("Semantic settings witnesses must name the configured Claude configuration source");
15364
+ if (!review.sources.some((source) => source.path === canonical4(configPath)))
15124
15365
  throw new Error("Discovery review must include the agent configuration source");
15125
15366
  return { ...supplied, roots: [...new Set([...roots, ...supplied.roots])].sort(), sources: [...sources, ...review.sources], ...agent === "gemini" ? { builtinNames } : {} };
15126
15367
  }
15127
15368
  function plugin(root2) {
15128
- root2 = canonical3(root2);
15369
+ root2 = canonical4(root2);
15129
15370
  safe4(root2);
15130
15371
  const manifestPath = join23(root2, agent === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json");
15131
15372
  const raw = witness(manifestPath);
@@ -15137,7 +15378,7 @@ function resolveAgentDiscovery(options) {
15137
15378
  unresolved("plugin hooks require a separate no-skill-injection review");
15138
15379
  const commands = join23(root2, "commands");
15139
15380
  safe4(commands);
15140
- if (agent === "claude" && (manifest.commands !== undefined || lstatSync16(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync9(commands).length))
15381
+ if (agent === "claude" && (manifest.commands !== undefined || lstatSync17(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync9(commands).length))
15141
15382
  unresolved("legacy command discovery requires retirement or a dedicated format adapter");
15142
15383
  const rootSkill = witness(join23(root2, "SKILL.md"));
15143
15384
  if (rootSkill !== null)
@@ -15148,18 +15389,18 @@ function resolveAgentDiscovery(options) {
15148
15389
  if (agent === "claude")
15149
15390
  roots.add(join23(root2, "skills"));
15150
15391
  for (const value of declared) {
15151
- const path = resolve13(root2, value);
15392
+ const path = resolve14(root2, value);
15152
15393
  if (path !== root2 && !path.startsWith(root2 + sep5))
15153
15394
  unresolved("plugin skill path escapes its root");
15154
- roots.add(path.endsWith(`${sep5}SKILL.md`) ? dirname13(path) : path);
15395
+ roots.add(path.endsWith(`${sep5}SKILL.md`) ? dirname14(path) : path);
15155
15396
  }
15156
15397
  }
15157
15398
  if (agent === "claude") {
15158
15399
  const registrations = witness(join23(home, ".claude/plugins/installed_plugins.json"));
15159
15400
  const installed = registrations === null ? {} : parseConfig(registrations, join23(home, ".claude/plugins/installed_plugins.json")).plugins;
15160
- const commands = canonical3(join23(home, ".claude/commands"));
15401
+ const commands = canonical4(join23(home, ".claude/commands"));
15161
15402
  safe4(commands);
15162
- if (lstatSync16(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync9(commands).length)
15403
+ if (lstatSync17(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync9(commands).length)
15163
15404
  unresolved("legacy home command discovery requires a dedicated format adapter");
15164
15405
  for (const [id, enabled] of Object.entries(config.enabledPlugins ?? {})) {
15165
15406
  if (enabled === false)
@@ -15179,7 +15420,7 @@ function resolveAgentDiscovery(options) {
15179
15420
  unresolved("unsupported plugin enablement");
15180
15421
  const split = id.lastIndexOf("@"), name = id.slice(0, split), marketplace = id.slice(split + 1);
15181
15422
  const market = config.marketplaces?.[marketplace] ?? (marketplace === "personal" ? { source_type: "local", source: home } : undefined);
15182
- if (split < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !isAbsolute13(market.source))
15423
+ if (split < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !isAbsolute14(market.source))
15183
15424
  unresolved("enabled plugin marketplace is not an explicit local source");
15184
15425
  const catalogText = witness(join23(market.source, ".agents/plugins/marketplace.json"));
15185
15426
  if (catalogText === null)
@@ -15187,7 +15428,7 @@ function resolveAgentDiscovery(options) {
15187
15428
  const catalog = parseConfig(catalogText, join23(market.source, ".agents/plugins/marketplace.json")), matches = Array.isArray(catalog.plugins) ? catalog.plugins.filter((item) => item.name === name) : [];
15188
15429
  if (matches.length !== 1 || matches[0]?.source?.source !== "local" || typeof matches[0]?.source?.path !== "string")
15189
15430
  unresolved("plugin catalog source is missing or ambiguous");
15190
- plugin(resolve13(market.source, matches[0].source.path));
15431
+ plugin(resolve14(market.source, matches[0].source.path));
15191
15432
  }
15192
15433
  } else if (agent === "opencode") {
15193
15434
  if (witness(join23(home, ".config/opencode/opencode.jsonc")) !== null || witness(join23(home, ".config/opencode/config.json")) !== null)
@@ -15195,18 +15436,18 @@ function resolveAgentDiscovery(options) {
15195
15436
  if ((config.plugin?.length ?? 0) > 0 || config.skills?.urls?.length)
15196
15437
  unresolved("external plugin or remote skill source");
15197
15438
  for (const path of config.skills?.paths ?? []) {
15198
- if (typeof path !== "string" || !isAbsolute13(path))
15439
+ if (typeof path !== "string" || !isAbsolute14(path))
15199
15440
  unresolved("relative or malformed added skill root");
15200
15441
  roots.add(path);
15201
15442
  }
15202
15443
  const localPlugins = join23(home, ".config/opencode/plugins");
15203
15444
  safe4(localPlugins);
15204
- if (lstatSync16(localPlugins, { throwIfNoEntry: false }) && readdirSync9(localPlugins).some((name) => name !== "skills-cli.js"))
15445
+ if (lstatSync17(localPlugins, { throwIfNoEntry: false }) && readdirSync9(localPlugins).some((name) => name !== "skills-cli.js"))
15205
15446
  unresolved("additional local plugin hooks require review");
15206
15447
  } else if (agent === "hermes") {
15207
15448
  for (const directory of [join23(home, ".hermes/plugins"), join23(home, ".hermes/hermes-agent")]) {
15208
15449
  safe4(directory);
15209
- if (lstatSync16(directory, { throwIfNoEntry: false }))
15450
+ if (lstatSync17(directory, { throwIfNoEntry: false }))
15210
15451
  unresolved("installed runtime/plugin discovery requires reviewed source bindings");
15211
15452
  }
15212
15453
  if (Bun.which("hermes") || Object.keys(config.plugins ?? {}).length)
@@ -15216,11 +15457,11 @@ function resolveAgentDiscovery(options) {
15216
15457
  unresolved("custom extension or skill paths");
15217
15458
  const directory = join23(home, ".gemini/extensions");
15218
15459
  safe4(directory);
15219
- if (lstatSync16(directory, { throwIfNoEntry: false }))
15460
+ if (lstatSync17(directory, { throwIfNoEntry: false }))
15220
15461
  for (const name of readdirSync9(directory)) {
15221
15462
  const root2 = join23(directory, name);
15222
15463
  safe4(root2);
15223
- if (!lstatSync16(root2)?.isDirectory())
15464
+ if (!lstatSync17(root2)?.isDirectory())
15224
15465
  continue;
15225
15466
  const raw = witness(join23(root2, "gemini-extension.json"));
15226
15467
  if (raw === null)
@@ -15231,7 +15472,7 @@ function resolveAgentDiscovery(options) {
15231
15472
  roots.add(join23(root2, "skills"));
15232
15473
  }
15233
15474
  }
15234
- return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join23(home, ".hermes/plugins"), join23(home, ".hermes/hermes-agent")].map((path) => canonical3(path))) } : {} };
15475
+ return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join23(home, ".hermes/plugins"), join23(home, ".hermes/hermes-agent")].map((path) => canonical4(path))) } : {} };
15235
15476
  }
15236
15477
 
15237
15478
  // src/lib/agent-adapters.ts
@@ -15375,7 +15616,7 @@ function disableCodexBundledSkills(text2) {
15375
15616
  }
15376
15617
 
15377
15618
  // src/lib/agent-integration.ts
15378
- var sha = (data) => createHash13("sha256").update(data).digest("hex");
15619
+ var sha = (data) => createHash14("sha256").update(data).digest("hex");
15379
15620
  var ROOTS = [
15380
15621
  ["claude", ".claude/skills"],
15381
15622
  ["codex", ".codex/skills"],
@@ -15394,11 +15635,11 @@ var ROOTS = [
15394
15635
  ["copilot", ".github/skills"]
15395
15636
  ];
15396
15637
  function assertSafePath(path) {
15397
- let cursor = resolve14(path);
15638
+ let cursor = resolve15(path);
15398
15639
  while (true) {
15399
- if (lstatSync17(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
15640
+ if (lstatSync18(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
15400
15641
  throw new Error(`Refusing symlink path: ${cursor}`);
15401
- const parent = dirname14(cursor);
15642
+ const parent = dirname15(cursor);
15402
15643
  if (parent === cursor)
15403
15644
  return;
15404
15645
  cursor = parent;
@@ -15407,16 +15648,16 @@ function assertSafePath(path) {
15407
15648
  function readRootAlias(home, agent) {
15408
15649
  assertSafePath(home);
15409
15650
  const realHome = realpathSync5(home), alias = join25(realHome, `.${agent}`);
15410
- const stat2 = lstatSync17(alias, { throwIfNoEntry: false, bigint: true });
15651
+ const stat2 = lstatSync18(alias, { throwIfNoEntry: false, bigint: true });
15411
15652
  if (!stat2?.isSymbolicLink())
15412
15653
  throw new Error(`Agent root alias changed after planning: ${alias}`);
15413
- const link = readlinkSync2(alias), targetPath = resolve14(dirname14(alias), link);
15654
+ const link = readlinkSync2(alias), targetPath = resolve15(dirname15(alias), link);
15414
15655
  assertSafePath(targetPath);
15415
- const targetStat = lstatSync17(targetPath, { throwIfNoEntry: false });
15656
+ const targetStat = lstatSync18(targetPath, { throwIfNoEntry: false });
15416
15657
  if (!targetStat?.isDirectory())
15417
15658
  throw new Error(`Agent root alias must target an existing directory: ${alias}`);
15418
15659
  const target = realpathSync5(targetPath), inside = relative5(realHome, target);
15419
- if (!inside || inside === ".." || inside.startsWith(`..${sep6}`) || isAbsolute14(inside))
15660
+ if (!inside || inside === ".." || inside.startsWith(`..${sep6}`) || isAbsolute15(inside))
15420
15661
  throw new Error(`Agent root alias target must be inside the real home: ${alias}`);
15421
15662
  return { agent, home: realHome, alias, target, link, aliasIdentity: `${stat2.dev}:${stat2.ino}:${stat2.ctimeNs}`, targetIdentity: `${targetStat.dev}:${targetStat.ino}` };
15422
15663
  }
@@ -15425,14 +15666,14 @@ function rootAliases(home, allowed = false) {
15425
15666
  return [];
15426
15667
  const result = [];
15427
15668
  for (const agent of ["claude", "codex"])
15428
- if (lstatSync17(join25(home, `.${agent}`), { throwIfNoEntry: false })?.isSymbolicLink())
15669
+ if (lstatSync18(join25(home, `.${agent}`), { throwIfNoEntry: false })?.isSymbolicLink())
15429
15670
  result.push(readRootAlias(home, agent));
15430
15671
  if (result.some((item, index) => result.slice(index + 1).some((other) => item.target === other.target || item.target.startsWith(other.target + sep6) || other.target.startsWith(item.target + sep6))))
15431
15672
  throw new Error("Agent root alias targets must not overlap");
15432
15673
  return result;
15433
15674
  }
15434
15675
  function canonicalAgentPath(path, aliases) {
15435
- const absolute = resolve14(path), binding = aliases.find((item) => absolute === item.alias || absolute.startsWith(item.alias + sep6));
15676
+ const absolute = resolve15(path), binding = aliases.find((item) => absolute === item.alias || absolute.startsWith(item.alias + sep6));
15436
15677
  return binding ? join25(binding.target, relative5(binding.alias, absolute)) : absolute;
15437
15678
  }
15438
15679
  function recheckRootAliases(aliases) {
@@ -15446,35 +15687,35 @@ function recheckRootAliases(aliases) {
15446
15687
  }
15447
15688
  function readNativeBytes(path, maximum = 64 * 1024 * 1024) {
15448
15689
  assertSafePath(path);
15449
- const before = lstatSync17(path);
15690
+ const before = lstatSync18(path);
15450
15691
  if (!before.isFile() || before.size > maximum)
15451
15692
  throw new Error("Unsupported or oversized native skill file");
15452
- const descriptor = openSync10(path, constants9.O_RDONLY | constants9.O_NOFOLLOW | constants9.O_NONBLOCK);
15693
+ const descriptor = openSync11(path, constants10.O_RDONLY | constants10.O_NOFOLLOW | constants10.O_NONBLOCK);
15453
15694
  try {
15454
- const opened = fstatSync10(descriptor);
15695
+ const opened = fstatSync11(descriptor);
15455
15696
  if (!opened.isFile() || opened.dev !== before.dev || opened.ino !== before.ino || opened.size !== before.size)
15456
15697
  throw new Error("Native skill file changed while reading");
15457
15698
  const bytes = Buffer.allocUnsafe(before.size + 1);
15458
15699
  let length = 0;
15459
15700
  while (length < bytes.length) {
15460
- const count = readSync8(descriptor, bytes, length, bytes.length - length, null);
15701
+ const count = readSync9(descriptor, bytes, length, bytes.length - length, null);
15461
15702
  if (!count)
15462
15703
  break;
15463
15704
  length += count;
15464
15705
  }
15465
- const after = fstatSync10(descriptor);
15706
+ const after = fstatSync11(descriptor);
15466
15707
  if (length !== before.size || after.size !== before.size || after.mtimeMs !== opened.mtimeMs || after.ctimeMs !== opened.ctimeMs)
15467
15708
  throw new Error("Native skill file changed while reading");
15468
15709
  return bytes.subarray(0, length);
15469
15710
  } finally {
15470
- closeSync10(descriptor);
15711
+ closeSync11(descriptor);
15471
15712
  }
15472
15713
  }
15473
15714
  function treeHash(root2) {
15474
- const hash2 = createHash13("sha256");
15715
+ const hash2 = createHash14("sha256");
15475
15716
  let bytes = 0, files = 0;
15476
15717
  function visit2(path) {
15477
- const stat2 = lstatSync17(path);
15718
+ const stat2 = lstatSync18(path);
15478
15719
  if (stat2.isSymbolicLink())
15479
15720
  throw new Error(`Refusing symlink in skill: ${path}`);
15480
15721
  const rel = relative5(root2, path);
@@ -15500,11 +15741,11 @@ function treeHash(root2) {
15500
15741
  function projectAncestorDirectories(projects) {
15501
15742
  const directories = new Set;
15502
15743
  for (const project of projects) {
15503
- for (let path = resolve14(project), depth = 0;; depth++) {
15744
+ for (let path = resolve15(project), depth = 0;; depth++) {
15504
15745
  if (depth >= 100)
15505
15746
  throw new Error("NATIVE_SKILL_DRIFT: project ancestor discovery limit exceeded");
15506
15747
  directories.add(path);
15507
- const parent = dirname14(path);
15748
+ const parent = dirname15(path);
15508
15749
  if (parent === path)
15509
15750
  break;
15510
15751
  path = parent;
@@ -15531,10 +15772,10 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
15531
15772
  throw new Error("Native skill discovery metadata limit exceeded");
15532
15773
  }
15533
15774
  function emptySiblingCacheAlias(path, parent) {
15534
- const link = readlinkSync2(path), target = resolve14(parent, link);
15535
- if (dirname14(target) !== parent || (isAbsolute14(link) ? link !== target : dirname14(link) !== "."))
15775
+ const link = readlinkSync2(path), target = resolve15(parent, link);
15776
+ if (dirname15(target) !== parent || (isAbsolute15(link) ? link !== target : dirname15(link) !== "."))
15536
15777
  return false;
15537
- if (!lstatSync17(target, { throwIfNoEntry: false })?.isDirectory())
15778
+ if (!lstatSync18(target, { throwIfNoEntry: false })?.isDirectory())
15538
15779
  return false;
15539
15780
  const scan = cacheScans.get(target);
15540
15781
  return Boolean(scan?.complete && !scan.hasSkills && scan.entries <= maxAliasProofEntries);
@@ -15546,7 +15787,7 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
15546
15787
  assertSafePath(path);
15547
15788
  if (!existsSync11(path))
15548
15789
  return scan;
15549
- const stat2 = lstatSync17(path);
15790
+ const stat2 = lstatSync18(path);
15550
15791
  if (stat2.isFile())
15551
15792
  return scan;
15552
15793
  if (!stat2.isDirectory())
@@ -15565,7 +15806,7 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
15565
15806
  }
15566
15807
  const bridge = !vendor && isOwnedCliBridge(path, bridgePaths);
15567
15808
  const rootAlias = aliases.find((item) => path === item.target || path.startsWith(item.target + sep6));
15568
- entries.push({ agent, path, hash: treeHash(path), managed, vendor, ...agent === "codex" && path.startsWith(canonicalAgentPath(join25(home, ".codex", "skills", ".system"), aliases) + sep6) ? { system: true } : {}, ...bridge ? { bridge: true, bridgeHome: resolve14(home) } : {}, ...rootAlias ? { rootAlias } : {} });
15809
+ entries.push({ agent, path, hash: treeHash(path), managed, vendor, ...agent === "codex" && path.startsWith(canonicalAgentPath(join25(home, ".codex", "skills", ".system"), aliases) + sep6) ? { system: true } : {}, ...bridge ? { bridge: true, bridgeHome: resolve15(home) } : {}, ...rootAlias ? { rootAlias } : {} });
15569
15810
  return scan;
15570
15811
  }
15571
15812
  if (depth > (vendor ? 32 : 3))
@@ -15592,7 +15833,7 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
15592
15833
  if (isVendor && !options.includeVendor)
15593
15834
  continue;
15594
15835
  const child = join25(path, name);
15595
- if (isVendor && lstatSync17(child, { throwIfNoEntry: false })?.isSymbolicLink()) {
15836
+ if (isVendor && lstatSync18(child, { throwIfNoEntry: false })?.isSymbolicLink()) {
15596
15837
  const target = statSync8(child, { throwIfNoEntry: false });
15597
15838
  if (target?.isFile() || pluginCache && target?.isDirectory() && emptySiblingCacheAlias(child, path)) {
15598
15839
  scan.entries++;
@@ -15714,7 +15955,7 @@ function configureHooks(config, agent, command, profileId, nativeReady) {
15714
15955
  function disableCodexSkills(text2, skills, aliases, bridgePath) {
15715
15956
  const bundled = disableCodexBundledSkills(text2);
15716
15957
  let result = bundled;
15717
- const bridgeSelector = (entry) => typeof entry.name === "string" && entry.name.trim() === CLI_BRIDGE_NAME || typeof entry.path === "string" && [resolve14(bridgePath), resolve14(join25(bridgePath, "SKILL.md"))].includes(canonicalAgentPath(entry.path, aliases));
15958
+ const bridgeSelector = (entry) => typeof entry.name === "string" && entry.name.trim() === CLI_BRIDGE_NAME || typeof entry.path === "string" && [resolve15(bridgePath), resolve15(join25(bridgePath, "SKILL.md"))].includes(canonicalAgentPath(entry.path, aliases));
15718
15959
  const previousConfig = Bun.TOML.parse(bundled).skills?.config;
15719
15960
  if (previousConfig !== undefined && (!Array.isArray(previousConfig) || previousConfig.some((entry) => !entry || typeof entry !== "object" || entry.path !== undefined && entry.name !== undefined)))
15720
15961
  throw new Error("Codex skill controls require one path or name selector per [[skills.config]] entry; review ambiguous entries before running skills hook install");
@@ -15726,7 +15967,7 @@ function disableCodexSkills(text2, skills, aliases, bridgePath) {
15726
15967
  result = result.replace(CODEX_SKILL_CONFIG_SECTIONS, (section) => {
15727
15968
  const parsed = Bun.TOML.parse(section);
15728
15969
  const declared = parsed.skills?.config?.[0];
15729
- if (!declared || !(skill.enabled && bridgeSelector(declared)) && !(typeof declared.path === "string" && [resolve14(path), resolve14(skill.path)].includes(canonicalAgentPath(declared.path, aliases))))
15970
+ if (!declared || !(skill.enabled && bridgeSelector(declared)) && !(typeof declared.path === "string" && [resolve15(path), resolve15(skill.path)].includes(canonicalAgentPath(declared.path, aliases))))
15730
15971
  return section;
15731
15972
  found = true;
15732
15973
  return /^\s*enabled\s*=/m.test(section) ? section.replace(/^\s*enabled\s*=.*$/m, `enabled = ${skill.enabled}`) : `${section.trimEnd()}
@@ -15844,7 +16085,7 @@ function planAgentIntegration(options) {
15844
16085
  version: CLI_BRIDGE_VERSION,
15845
16086
  digest: CLI_BRIDGE_DIGEST,
15846
16087
  agents: [...new Set([...priorAgents, ...options.agents])].sort(),
15847
- home: resolve14(home),
16088
+ home: resolve15(home),
15848
16089
  includeVendor: true,
15849
16090
  ...options.agents.includes("hermes") ? { supervisors: { ...policy.bridge?.supervisors, hermes: { path: join25(dataDir2, "agent-hooks", "hermes.js"), runtime: process.execPath, sha256: sha(renderHermesSupervisor(bindings.get("hermes").command, bindings.get("hermes").profileId)) } } } : {},
15850
16091
  commands: { ...policy.bridge?.commands, ...Object.fromEntries([...bindings].map(([agent, binding]) => [agent, binding.command])) },
@@ -15861,7 +16102,7 @@ function planAgentIntegration(options) {
15861
16102
  }
15862
16103
  function atomicWrite2(path, content) {
15863
16104
  assertSafePath(path);
15864
- mkdirSync7(dirname14(path), { recursive: true, mode: 448 });
16105
+ mkdirSync7(dirname15(path), { recursive: true, mode: 448 });
15865
16106
  const temporary = `${path}.skills-${randomUUID3()}`;
15866
16107
  try {
15867
16108
  writeFileSync5(temporary, content, { mode: 384, flag: "wx" });
@@ -15874,10 +16115,10 @@ function atomicWrite2(path, content) {
15874
16115
  function applyAgentIntegration(plan) {
15875
16116
  const policyPath = join25(plan.dataDir, "agent-policy.json");
15876
16117
  assertSafePath(policyPath);
15877
- const currentText = (path) => resolve14(path) === resolve14(policyPath) ? readManagedSkillPolicySnapshot(plan.dataDir)?.text ?? null : readOptional(path);
16118
+ const currentText = (path) => resolve15(path) === resolve15(policyPath) ? readManagedSkillPolicySnapshot(plan.dataDir)?.text ?? null : readOptional(path);
15878
16119
  readManagedSkillPolicySnapshot(plan.dataDir);
15879
16120
  for (const change of plan.changes)
15880
- if (resolve14(change.path) === resolve14(policyPath))
16121
+ if (resolve15(change.path) === resolve15(policyPath))
15881
16122
  parseManagedSkillPolicy(change.after);
15882
16123
  const aliases = plan.rootAliases ?? [];
15883
16124
  recheckRootAliases(aliases);
@@ -15907,7 +16148,7 @@ function applyAgentIntegration(plan) {
15907
16148
  recheckRootAliases(aliases);
15908
16149
  if (currentText(change.path) !== change.before)
15909
16150
  throw new Error(`Configuration changed after planning: ${change.path}`);
15910
- for (let directory = dirname14(change.path);!existsSync11(directory); directory = dirname14(directory))
16151
+ for (let directory = dirname15(change.path);!existsSync11(directory); directory = dirname15(directory))
15911
16152
  createdDirectories.add(directory);
15912
16153
  const after = change.after;
15913
16154
  atomicWrite2(change.path, after);
@@ -15947,11 +16188,11 @@ function applyAgentIntegration(plan) {
15947
16188
  }
15948
16189
  function syncArchiveDirectory(path) {
15949
16190
  assertSafePath(path);
15950
- const descriptor = openSync10(path, constants9.O_RDONLY | constants9.O_DIRECTORY | constants9.O_NOFOLLOW | constants9.O_NONBLOCK);
16191
+ const descriptor = openSync11(path, constants10.O_RDONLY | constants10.O_DIRECTORY | constants10.O_NOFOLLOW | constants10.O_NONBLOCK);
15951
16192
  try {
15952
16193
  fsyncSync3(descriptor);
15953
16194
  } finally {
15954
- closeSync10(descriptor);
16195
+ closeSync11(descriptor);
15955
16196
  }
15956
16197
  }
15957
16198
  function writeArchiveJournal(path, value) {
@@ -15959,18 +16200,18 @@ function writeArchiveJournal(path, value) {
15959
16200
  const temporary = `${path}.skills-${randomUUID3()}`;
15960
16201
  let descriptor;
15961
16202
  try {
15962
- descriptor = openSync10(temporary, constants9.O_WRONLY | constants9.O_CREAT | constants9.O_EXCL | constants9.O_NOFOLLOW, 384);
16203
+ descriptor = openSync11(temporary, constants10.O_WRONLY | constants10.O_CREAT | constants10.O_EXCL | constants10.O_NOFOLLOW, 384);
15963
16204
  writeFileSync5(descriptor, `${JSON.stringify(value)}
15964
16205
  `);
15965
16206
  fsyncSync3(descriptor);
15966
- closeSync10(descriptor);
16207
+ closeSync11(descriptor);
15967
16208
  descriptor = undefined;
15968
16209
  renameSync4(temporary, path);
15969
- syncArchiveDirectory(dirname14(path));
16210
+ syncArchiveDirectory(dirname15(path));
15970
16211
  } finally {
15971
16212
  if (descriptor !== undefined)
15972
- closeSync10(descriptor);
15973
- if (lstatSync17(temporary, { throwIfNoEntry: false }))
16213
+ closeSync11(descriptor);
16214
+ if (lstatSync18(temporary, { throwIfNoEntry: false }))
15974
16215
  unlinkSync4(temporary);
15975
16216
  }
15976
16217
  }
@@ -16003,7 +16244,7 @@ function archiveNativeSkills(inventory, options) {
16003
16244
  const moved = [];
16004
16245
  const verifyArchive = (entry) => {
16005
16246
  assertSafePath(entry.archive);
16006
- const stat2 = lstatSync17(entry.archive);
16247
+ const stat2 = lstatSync18(entry.archive);
16007
16248
  if (entry.discoveryOnly ? !stat2.isFile() : !stat2.isDirectory())
16008
16249
  throw new Error("Archive type changed");
16009
16250
  if ((entry.discoveryOnly ? sha(readNativeBytes(entry.archive)) : treeHash(entry.archive)) !== entry.hash)
@@ -16011,14 +16252,14 @@ function archiveNativeSkills(inventory, options) {
16011
16252
  };
16012
16253
  assertSafePath(archiveRoot);
16013
16254
  const created = [];
16014
- for (let path = archiveRoot;!existsSync11(path); path = dirname14(path))
16255
+ for (let path = archiveRoot;!existsSync11(path); path = dirname15(path))
16015
16256
  created.push(path);
16016
16257
  mkdirSync7(archiveRoot, { recursive: true, mode: 448 });
16017
16258
  try {
16018
16259
  for (const directory of created)
16019
16260
  syncArchiveDirectory(directory);
16020
16261
  if (created.length)
16021
- syncArchiveDirectory(dirname14(created.at(-1)));
16262
+ syncArchiveDirectory(dirname15(created.at(-1)));
16022
16263
  writeArchiveJournal(receiptPath, journal);
16023
16264
  for (const [index, entry] of selected.entries()) {
16024
16265
  recheckRootAliases(aliases);
@@ -16030,7 +16271,7 @@ function archiveNativeSkills(inventory, options) {
16030
16271
  writeArchiveJournal(receiptPath, journal);
16031
16272
  renameSync4(move.source, move.archive);
16032
16273
  moved.push(move);
16033
- syncArchiveDirectory(dirname14(move.source));
16274
+ syncArchiveDirectory(dirname15(move.source));
16034
16275
  syncArchiveDirectory(archiveRoot);
16035
16276
  verifyArchive(move);
16036
16277
  move.status = "archived";
@@ -16051,7 +16292,7 @@ function archiveNativeSkills(inventory, options) {
16051
16292
  recheckRootAliases(aliases);
16052
16293
  assertSafePath(entry.source);
16053
16294
  assertSafePath(entry.archive);
16054
- if (lstatSync17(entry.source, { throwIfNoEntry: false })) {
16295
+ if (lstatSync18(entry.source, { throwIfNoEntry: false })) {
16055
16296
  entry.status = "recovery-required";
16056
16297
  entry.conflict = "source-occupied";
16057
16298
  continue;
@@ -16065,10 +16306,10 @@ function archiveNativeSkills(inventory, options) {
16065
16306
  }
16066
16307
  if (entry.discoveryOnly) {
16067
16308
  linkSync2(entry.archive, entry.source);
16068
- syncArchiveDirectory(dirname14(entry.source));
16309
+ syncArchiveDirectory(dirname15(entry.source));
16069
16310
  unlinkSync4(entry.archive);
16070
16311
  } else {
16071
- if (lstatSync17(entry.source, { throwIfNoEntry: false })) {
16312
+ if (lstatSync18(entry.source, { throwIfNoEntry: false })) {
16072
16313
  entry.status = "recovery-required";
16073
16314
  entry.conflict = "source-occupied";
16074
16315
  continue;
@@ -16076,7 +16317,7 @@ function archiveNativeSkills(inventory, options) {
16076
16317
  renameSync4(entry.archive, entry.source);
16077
16318
  }
16078
16319
  entry.status = "restored";
16079
- syncArchiveDirectory(dirname14(entry.source));
16320
+ syncArchiveDirectory(dirname15(entry.source));
16080
16321
  syncArchiveDirectory(archiveRoot);
16081
16322
  } catch {
16082
16323
  entry.status = "recovery-required";
@@ -16115,7 +16356,7 @@ function isSkillsOwnershipMarker(marker) {
16115
16356
  function hasSkillsOwnershipMarker(dir) {
16116
16357
  const path = join26(dir, SYNC_MARKER_FILE);
16117
16358
  try {
16118
- if (!lstatSync18(path).isFile())
16359
+ if (!lstatSync19(path).isFile())
16119
16360
  return false;
16120
16361
  const marker = JSON.parse(readFileSync15(path, "utf8"));
16121
16362
  return isSkillsOwnershipMarker(marker);
@@ -16341,9 +16582,9 @@ function writeManagedSkillDir(dir, skillMd, options) {
16341
16582
  const action = dirExists ? "update" : "create";
16342
16583
  if (options.dryRun)
16343
16584
  return { action, path: skillMdPath };
16344
- const parentDir = dirname15(dir);
16585
+ const parentDir = dirname16(dir);
16345
16586
  mkdirSync8(parentDir, { recursive: true });
16346
- const transactionDir = mkdtempSync2(join26(parentDir, `.hasna-skills-write-${basename7(dir)}-`));
16587
+ const transactionDir = mkdtempSync2(join26(parentDir, `.hasna-skills-write-${basename9(dir)}-`));
16347
16588
  const candidateDir = join26(transactionDir, "candidate");
16348
16589
  const backupDir = join26(transactionDir, "backup");
16349
16590
  const candidateSkillMdPath = join26(candidateDir, "SKILL.md");
@@ -16832,7 +17073,7 @@ function loadProjectConfigCompat(targetDir) {
16832
17073
  return loadProjectConfig(targetDir);
16833
17074
  }
16834
17075
  // src/lib/run-state.ts
16835
- import { createHash as createHash14, randomBytes } from "crypto";
17076
+ import { createHash as createHash15, randomBytes } from "crypto";
16836
17077
  import { existsSync as existsSync15, mkdirSync as mkdirSync10, readFileSync as readFileSync18, readdirSync as readdirSync12, statSync as statSync10, writeFileSync as writeFileSync8 } from "fs";
16837
17078
  import { extname, join as join29, relative as relative6 } from "path";
16838
17079
  function createSkillRun(params, targetDir = process.cwd()) {
@@ -16959,7 +17200,7 @@ function collectRunArtifacts(context) {
16959
17200
  artifacts.push({
16960
17201
  path: toProjectRelative(context.targetDir, path),
16961
17202
  mime: mimeForPath(path),
16962
- sha256: createHash14("sha256").update(bytes).digest("hex"),
17203
+ sha256: createHash15("sha256").update(bytes).digest("hex"),
16963
17204
  sizeBytes: stat2.size
16964
17205
  });
16965
17206
  }
@@ -17087,7 +17328,7 @@ __export(exports_external, {
17087
17328
  pipe: () => pipe,
17088
17329
  partialRecord: () => partialRecord,
17089
17330
  parseAsync: () => parseAsync2,
17090
- parse: () => parse8,
17331
+ parse: () => parse9,
17091
17332
  overwrite: () => _overwrite,
17092
17333
  output: () => output,
17093
17334
  optional: () => optional,
@@ -17307,7 +17548,7 @@ __export(exports_core2, {
17307
17548
  prettifyError: () => prettifyError,
17308
17549
  parseURLObject: () => parseURLObject,
17309
17550
  parseAsync: () => parseAsync,
17310
- parse: () => parse6,
17551
+ parse: () => parse7,
17311
17552
  meta: () => meta,
17312
17553
  mergeValues: () => mergeValues,
17313
17554
  memoizer: () => memoizer,
@@ -18761,7 +19002,7 @@ var _parse = (_Err) => {
18761
19002
  };
18762
19003
  return fn;
18763
19004
  };
18764
- var parse6 = /* @__PURE__ */ _parse($ZodRealError);
19005
+ var parse7 = /* @__PURE__ */ _parse($ZodRealError);
18765
19006
  var _parseAsync = (_Err) => {
18766
19007
  const fn = async (schema, value, _ctx, params) => {
18767
19008
  const ctx = _ctx ? { ..._ctx, async: true } : { async: true };
@@ -18832,18 +19073,18 @@ var validateAsync = async (schema, value, _ctx) => {
18832
19073
  return result.issues.length === 0;
18833
19074
  };
18834
19075
  var _encode = (_Err) => {
18835
- const parse7 = _parse(_Err);
19076
+ const parse8 = _parse(_Err);
18836
19077
  const fn = (schema, value, _ctx, _params) => {
18837
19078
  const ctx = _ctx ? { ..._ctx, direction: "backward" } : { direction: "backward" };
18838
- return parse7(schema, value, ctx, finalizeParams(fn, _params));
19079
+ return parse8(schema, value, ctx, finalizeParams(fn, _params));
18839
19080
  };
18840
19081
  return fn;
18841
19082
  };
18842
19083
  var encode = /* @__PURE__ */ _encode($ZodRealError);
18843
19084
  var _decode = (_Err) => {
18844
- const parse7 = _parse(_Err);
19085
+ const parse8 = _parse(_Err);
18845
19086
  const fn = (schema, value, _ctx, _params) => {
18846
- return parse7(schema, value, _ctx, finalizeParams(fn, _params));
19087
+ return parse8(schema, value, _ctx, finalizeParams(fn, _params));
18847
19088
  };
18848
19089
  return fn;
18849
19090
  };
@@ -21766,10 +22007,10 @@ var $ZodFunction = /* @__PURE__ */ $constructor("$ZodFunction", (inst, def) => {
21766
22007
  throw new Error("implement() must be called with a function");
21767
22008
  }
21768
22009
  return Object.defineProperty(function(...args) {
21769
- const parsedArgs = inst._def.input ? parse6(inst._def.input, args) : args;
22010
+ const parsedArgs = inst._def.input ? parse7(inst._def.input, args) : args;
21770
22011
  const result = Reflect.apply(func, this, parsedArgs);
21771
22012
  if (inst._def.output) {
21772
- return parse6(inst._def.output, result);
22013
+ return parse7(inst._def.output, result);
21773
22014
  }
21774
22015
  return result;
21775
22016
  }, "_zod", { value: inst._zod, enumerable: false });
@@ -33407,7 +33648,7 @@ var ZodRealError = /* @__PURE__ */ $constructor("ZodError", initializer2, undefi
33407
33648
  });
33408
33649
 
33409
33650
  // node_modules/zod/v4/classic/parse.js
33410
- var parse8 = /* @__PURE__ */ _parse(ZodRealError);
33651
+ var parse9 = /* @__PURE__ */ _parse(ZodRealError);
33411
33652
  var parseAsync2 = /* @__PURE__ */ _parseAsync(ZodRealError);
33412
33653
  var safeParse2 = /* @__PURE__ */ _safeParse(ZodRealError);
33413
33654
  var safeParseAsync2 = /* @__PURE__ */ _safeParseAsync(ZodRealError);
@@ -33543,7 +33784,7 @@ var ZodType = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
33543
33784
  exports_util.own(this, "~standard", value);
33544
33785
  },
33545
33786
  parse: function _parse2(data, params) {
33546
- return parse8(this, data, params, { callee: _parse2 });
33787
+ return parse9(this, data, params, { callee: _parse2 });
33547
33788
  },
33548
33789
  parseAsync: async function _parseAsync2(data, params) {
33549
33790
  return await parseAsync2(this, data, params, { callee: _parseAsync2 });
@@ -35720,6 +35961,8 @@ var remoteSkillSchema = exports_external.object({
35720
35961
  tags: exports_external.array(exports_external.string()).optional(),
35721
35962
  dependencies: exports_external.array(exports_external.string()).optional(),
35722
35963
  version: exports_external.string().optional(),
35964
+ revisionId: exports_external.union([exports_external.string().regex(/^[\x21-\x7e]+$/), exports_external.null()]).optional(),
35965
+ lifecycle: exports_external.enum(["active", "archived"]).optional(),
35723
35966
  availability: remoteAvailabilitySchema.optional()
35724
35967
  }).passthrough().refine((skill) => skill.name || skill.slug, {
35725
35968
  message: "Remote skill requires name or slug"
@@ -35782,6 +36025,8 @@ function normalizeRemoteSkill(skill) {
35782
36025
  tags: skill.tags || ["remote"],
35783
36026
  dependencies: skill.dependencies,
35784
36027
  ...skill.version ? { version: skill.version } : {},
36028
+ ...skill.revisionId !== undefined ? { revisionId: skill.revisionId } : {},
36029
+ ...skill.lifecycle ? { lifecycle: skill.lifecycle } : {},
35785
36030
  availability: normalizeRemoteAvailability(skill.availability),
35786
36031
  source: "remote"
35787
36032
  };
@@ -36374,7 +36619,7 @@ function clone2(value) {
36374
36619
  return value === undefined ? undefined : JSON.parse(JSON.stringify(value));
36375
36620
  }
36376
36621
  // src/lib/canonical-json.ts
36377
- import { createHash as createHash15 } from "crypto";
36622
+ import { createHash as createHash16 } from "crypto";
36378
36623
  function canonicalJson2(value, maximumBytes = 2 * 1024 * 1024) {
36379
36624
  return canonicalJsonAtDepth(value, maximumBytes, 64);
36380
36625
  }
@@ -36418,7 +36663,7 @@ function canonicalJsonAtDepth(value, maximumBytes, maximumDepth) {
36418
36663
  return visit3(value, 0);
36419
36664
  }
36420
36665
  function canonicalJsonSha256(value, maximumBytes) {
36421
- return createHash15("sha256").update(canonicalJson2(value, maximumBytes)).digest("hex");
36666
+ return createHash16("sha256").update(canonicalJson2(value, maximumBytes)).digest("hex");
36422
36667
  }
36423
36668
 
36424
36669
  // src/lib/remote-recurring-contract.ts
@@ -37379,10 +37624,10 @@ async function readQuoteUnavailableCode(response) {
37379
37624
  let timer;
37380
37625
  let deadlineExceeded = false;
37381
37626
  const expired = Symbol("quote body deadline");
37382
- const deadline = new Promise((resolve15) => {
37627
+ const deadline = new Promise((resolve16) => {
37383
37628
  timer = setTimeout(() => {
37384
37629
  deadlineExceeded = true;
37385
- resolve15(expired);
37630
+ resolve16(expired);
37386
37631
  reader.cancel().catch(() => {});
37387
37632
  }, 1500);
37388
37633
  });
@@ -37498,6 +37743,18 @@ class RemoteRequestError extends Error {
37498
37743
  this.name = "RemoteRequestError";
37499
37744
  }
37500
37745
  }
37746
+ var KNOWN_SKILL_LIFECYCLE_CODES = new Set(["SKILL_ARCHIVE_PROFILE_CONFLICT", "LIFECYCLE_ROLE_REQUIRED"]);
37747
+
37748
+ class RemoteSkillLifecycleError extends RemoteRequestError {
37749
+ code;
37750
+ constructor(path, status, code) {
37751
+ super(path, status);
37752
+ this.name = "RemoteSkillLifecycleError";
37753
+ const safeCode = code !== undefined && KNOWN_SKILL_LIFECYCLE_CODES.has(code) ? code : undefined;
37754
+ this.code = safeCode;
37755
+ this.message = `Skill lifecycle update was refused (HTTP ${status}${safeCode ? `, code ${safeCode}` : ""})`;
37756
+ }
37757
+ }
37501
37758
 
37502
37759
  class RemoteCreditCheckoutError extends RemoteRequestError {
37503
37760
  code;
@@ -37678,6 +37935,39 @@ class RemoteSkillsClient {
37678
37935
  })();
37679
37936
  return this.capabilities;
37680
37937
  }
37938
+ async addSkillPublishScope(keyId, expectedScopes, expectedOrgId) {
37939
+ if (!/^[A-Za-z0-9_-]+$/.test(keyId))
37940
+ throw new Error("Invalid API key id");
37941
+ if (!/^[A-Za-z0-9_-]{1,256}$/.test(expectedOrgId))
37942
+ throw new Error("Invalid expected organization id");
37943
+ if (!Array.isArray(expectedScopes) || expectedScopes.length > 32 || expectedScopes.some((scope) => typeof scope !== "string" || scope.length > 128 || !/^(?:\*|[a-z][a-z0-9_-]*:(?:\*|[a-z][a-z0-9_-]*))$/.test(scope)) || new Set(expectedScopes).size !== expectedScopes.length)
37944
+ throw new Error("Invalid expected API key scopes");
37945
+ const path = `/api/v1/admin/keys/${encodeURIComponent(keyId)}/scopes`;
37946
+ const response = await this.request(path, { method: "PATCH", body: JSON.stringify({ expected_scopes: expectedScopes, add_scopes: ["skills:publish"] }) });
37947
+ if (!response.ok)
37948
+ throw new RemoteRequestError(path, response.status);
37949
+ let value;
37950
+ try {
37951
+ value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(await readBoundedResponse(response, 64 * 1024)));
37952
+ } catch {
37953
+ throw new Error("Invalid API key scope update response");
37954
+ }
37955
+ if (!value || typeof value !== "object" || Array.isArray(value))
37956
+ throw new Error("Invalid API key scope update response");
37957
+ const body = value;
37958
+ const returnedId = body.keyId;
37959
+ const orgId = body.orgId;
37960
+ const scopes = body.scopes;
37961
+ if (returnedId !== keyId || typeof orgId !== "string" || !orgId || expectedOrgId !== undefined && orgId !== expectedOrgId || !Array.isArray(scopes) || scopes.some((scope) => typeof scope !== "string") || body.updated !== true) {
37962
+ throw new Error("Invalid API key scope update response");
37963
+ }
37964
+ const returnedScopes = scopes;
37965
+ const expectedResult = expectedScopes.includes("skills:publish") ? expectedScopes : [...expectedScopes, "skills:publish"];
37966
+ if (returnedScopes.length !== expectedResult.length || expectedResult.some((scope, index) => returnedScopes[index] !== scope)) {
37967
+ throw new Error("API key scope update response did not preserve the expected scopes");
37968
+ }
37969
+ return { keyId, orgId, scopes: [...returnedScopes], updated: true };
37970
+ }
37681
37971
  async submitQuotedRun(slug2, input2 = {}, args = [], approval = {}) {
37682
37972
  runQuoteReceipt(approval.quoteReceipt);
37683
37973
  ({ input: input2, args, approval } = JSON.parse(JSON.stringify({ input: input2, args, approval })));
@@ -38195,6 +38485,19 @@ class RemoteSkillsClient {
38195
38485
  async deleteSkill(slug2) {
38196
38486
  return this.request(`/api/v1/skills/${encodeURIComponent(slug2)}`, { method: "DELETE" });
38197
38487
  }
38488
+ async setSkillLifecycle(slug2, lifecycle, options) {
38489
+ const path = `/api/v1/skills/${encodeURIComponent(slug2)}/lifecycle`;
38490
+ const response = await this.request(path, {
38491
+ method: "PATCH",
38492
+ headers: { "If-Match": options.expectedRevisionId },
38493
+ body: JSON.stringify({ lifecycle, ...options.reason ? { reason: options.reason } : {}, ...options.replacementSlug ? { replacementSlug: options.replacementSlug } : {} })
38494
+ });
38495
+ if (!response.ok) {
38496
+ const code = await readResponseCode(response);
38497
+ throw new RemoteSkillLifecycleError(path, response.status, code);
38498
+ }
38499
+ return response.json();
38500
+ }
38198
38501
  async downloadSkillBundle(slug2) {
38199
38502
  return this.request(`/api/v1/skills/${encodeURIComponent(slug2)}/bundle`, { method: "GET" });
38200
38503
  }
@@ -38347,9 +38650,13 @@ function normalizeSkillSummaryList(payload) {
38347
38650
  return payload.map(normalizeSkillSummary);
38348
38651
  }
38349
38652
  async function responseBodyCarriesCode(response, codes) {
38653
+ const code = await readResponseCode(response);
38654
+ return code !== undefined && codes.includes(code);
38655
+ }
38656
+ async function readResponseCode(response) {
38350
38657
  const reader = response.body?.getReader();
38351
38658
  if (!reader)
38352
- return false;
38659
+ return;
38353
38660
  const maximum = 8 * 1024;
38354
38661
  let deadline;
38355
38662
  const expired = new Promise((_, reject) => {
@@ -38364,7 +38671,7 @@ async function responseBodyCarriesCode(response, codes) {
38364
38671
  break;
38365
38672
  size += next.value.byteLength;
38366
38673
  if (size > maximum)
38367
- return false;
38674
+ return;
38368
38675
  chunks.push(next.value);
38369
38676
  }
38370
38677
  const bytes = new Uint8Array(size);
@@ -38375,11 +38682,11 @@ async function responseBodyCarriesCode(response, codes) {
38375
38682
  }
38376
38683
  const payload = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
38377
38684
  if (!payload || typeof payload !== "object" || Array.isArray(payload) || !Object.hasOwn(payload, "code"))
38378
- return false;
38685
+ return;
38379
38686
  const code = payload.code;
38380
- return typeof code === "string" && codes.includes(code);
38687
+ return typeof code === "string" && /^[A-Z][A-Z0-9_:-]{0,127}$/.test(code) ? code : undefined;
38381
38688
  } catch {
38382
- return false;
38689
+ return;
38383
38690
  } finally {
38384
38691
  clearTimeout(deadline);
38385
38692
  reader.cancel().catch(() => {});
@@ -38610,10 +38917,10 @@ function recordScheduleRun(id, status, targetDir) {
38610
38917
  saveSchedules(data, targetDir);
38611
38918
  }
38612
38919
  // src/lib/revision.ts
38613
- import { createHash as createHash16 } from "crypto";
38920
+ import { createHash as createHash17 } from "crypto";
38614
38921
  var REVISION_ID_PATTERN = /^[0-9a-f]{64}$/;
38615
38922
  function revisionIdOf(content) {
38616
- const canonical3 = JSON.stringify({
38923
+ const canonicalContent = {
38617
38924
  slug: content.slug,
38618
38925
  displayName: content.displayName,
38619
38926
  description: content.description,
@@ -38625,15 +38932,21 @@ function revisionIdOf(content) {
38625
38932
  skillMd: content.skillMd ?? null,
38626
38933
  bundleSha256: content.bundleSha256 ?? null,
38627
38934
  bundleByteSize: content.bundleByteSize ?? null
38628
- });
38629
- return createHash16("sha256").update(canonical3).digest("hex");
38935
+ };
38936
+ if (content.lifecycle === "archived" || content.archiveReason !== undefined || content.replacementSlug !== undefined) {
38937
+ canonicalContent.lifecycle = content.lifecycle ?? "active";
38938
+ canonicalContent.archiveReason = content.archiveReason ?? null;
38939
+ canonicalContent.replacementSlug = content.replacementSlug ?? null;
38940
+ }
38941
+ const canonical4 = JSON.stringify(canonicalContent);
38942
+ return createHash17("sha256").update(canonical4).digest("hex");
38630
38943
  }
38631
38944
  function revisionIdOfRecord(record7) {
38632
38945
  return revisionIdOf(record7);
38633
38946
  }
38634
38947
  // src/lib/pull.ts
38635
38948
  import { existsSync as existsSync17, mkdirSync as mkdirSync12, mkdtempSync as mkdtempSync3, readFileSync as readFileSync20, renameSync as renameSync6, rmSync as rmSync5, writeFileSync as writeFileSync10 } from "fs";
38636
- import { dirname as dirname16, join as join31 } from "path";
38949
+ import { dirname as dirname17, join as join31 } from "path";
38637
38950
 
38638
38951
  // src/lib/skill-bundles.ts
38639
38952
  import { createHmac, timingSafeEqual } from "crypto";
@@ -38975,7 +39288,7 @@ function installBundleAtomically(name, entries, options = {}, marker = {}) {
38975
39288
  try {
38976
39289
  for (const entry of entries) {
38977
39290
  const destination = join31(staging, entry.path);
38978
- mkdirSync12(dirname16(destination), { recursive: true });
39291
+ mkdirSync12(dirname17(destination), { recursive: true });
38979
39292
  writeFileSync10(destination, entry.bytes, { mode: entry.mode });
38980
39293
  }
38981
39294
  writePullMarker(staging, {
@@ -39069,7 +39382,7 @@ function splitNameVersion(raw) {
39069
39382
  return version2 ? { name, version: version2 } : { name };
39070
39383
  }
39071
39384
  // src/lib/recurring-surface.ts
39072
- import { isAbsolute as isAbsolute15 } from "path";
39385
+ import { isAbsolute as isAbsolute16 } from "path";
39073
39386
 
39074
39387
  // src/lib/remote-invitation-recovery.ts
39075
39388
  class InvitationEmailInputError extends Error {
@@ -39167,7 +39480,7 @@ async function requestInvitationEmail(origin, action, input2) {
39167
39480
  }
39168
39481
 
39169
39482
  // src/lib/remote-private-publications.ts
39170
- import { createHash as createHash17 } from "crypto";
39483
+ import { createHash as createHash18 } from "crypto";
39171
39484
  var PRIVATE_PUBLICATION_MAX_BYTES = 16 * 1024 * 1024;
39172
39485
  var failures2 = {
39173
39486
  INVALID_REQUEST: [400, "The publication request is invalid."],
@@ -39214,7 +39527,7 @@ var hash3 = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v);
39214
39527
  var record8 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
39215
39528
  var exact = (v, keys) => record8(v) && Object.keys(v).sort().join(",") === keys.sort().join(",");
39216
39529
  var date5 = (v) => typeof v === "string" && /^\d{4}-\d\d-\d\dT[0-9:.]+(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/.test(v) && Number.isFinite(Date.parse(v));
39217
- var publicationSha256 = (bytes) => createHash17("sha256").update(bytes).digest("hex");
39530
+ var publicationSha256 = (bytes) => createHash18("sha256").update(bytes).digest("hex");
39218
39531
  function checkedPublicationDeclaration(value) {
39219
39532
  if (!exact(value, ["idempotencyKey", "version", "expectedCurrentVersionId", "manifestText", "archiveSha256", "archiveByteSize"]) || !publicationUuid(value.idempotencyKey) || !(value.expectedCurrentVersionId === null || publicationUuid(value.expectedCurrentVersionId)) || typeof value.version !== "string" || !value.version || value.version.length > 128 || /[\p{Cc}\p{Cs}]/u.test(value.version) || typeof value.manifestText !== "string" || Buffer.byteLength(value.manifestText) > 16384 || !hash3(value.archiveSha256) || !Number.isSafeInteger(value.archiveByteSize) || Number(value.archiveByteSize) < 1 || Number(value.archiveByteSize) > PRIVATE_PUBLICATION_MAX_BYTES)
39220
39533
  return bad();
@@ -39459,12 +39772,12 @@ class RemotePrivatePublicationsClient {
39459
39772
  previous = view;
39460
39773
  if (!["queued", "verifying"].includes(view.state) || Date.now() >= until)
39461
39774
  return view;
39462
- await new Promise((resolve15) => {
39775
+ await new Promise((resolve16) => {
39463
39776
  const timer = setTimeout(done, Math.min(1000, until - Date.now()));
39464
39777
  function done() {
39465
39778
  clearTimeout(timer);
39466
39779
  options.signal?.removeEventListener("abort", done);
39467
- resolve15();
39780
+ resolve16();
39468
39781
  }
39469
39782
  options.signal?.addEventListener("abort", done, { once: true });
39470
39783
  });
@@ -39728,7 +40041,7 @@ var stateSchema = exports_external.object({
39728
40041
  var uuid13 = exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/);
39729
40042
  var context = { userId: uuid13.optional(), membershipId: uuid13.optional() };
39730
40043
  var page2 = { limit: exports_external.number().int().min(1).max(100).optional(), cursor: exports_external.string().min(1).max(2048).optional() };
39731
- var directory = exports_external.string().max(4096).refine(isAbsolute15, "Use an absolute recovery directory");
40044
+ var directory = exports_external.string().max(4096).refine(isAbsolute16, "Use an absolute recovery directory");
39732
40045
  var email4 = exports_external.string().trim().toLowerCase().email().max(254);
39733
40046
  var code = exports_external.string().regex(/^\d{6}$/);
39734
40047
  var recurringSurfaceSchemas = {
@@ -39879,7 +40192,7 @@ function findSkillsParityForMcpTool(tool) {
39879
40192
  }
39880
40193
  // src/lib/registry-sync.ts
39881
40194
  import { mkdirSync as mkdirSync13, writeFileSync as writeFileSync11 } from "fs";
39882
- import { dirname as dirname17, relative as relative7 } from "path";
40195
+ import { dirname as dirname18, relative as relative7 } from "path";
39883
40196
  function createRegistrySyncArtifact(options = {}) {
39884
40197
  const profile = options.profile ?? "all";
39885
40198
  const includeDocs = options.includeDocs ?? true;
@@ -39936,7 +40249,7 @@ function createRegistrySyncArtifact(options = {}) {
39936
40249
  };
39937
40250
  }
39938
40251
  function writeRegistrySyncArtifact(path, artifact) {
39939
- mkdirSync13(dirname17(path), { recursive: true });
40252
+ mkdirSync13(dirname18(path), { recursive: true });
39940
40253
  writeFileSync11(path, `${JSON.stringify(artifact, null, 2)}
39941
40254
  `);
39942
40255
  }
@@ -41021,14 +41334,14 @@ function clone3(value) {
41021
41334
  }
41022
41335
  // src/lib/feedback.ts
41023
41336
  import { appendFileSync, existsSync as existsSync18, mkdirSync as mkdirSync14 } from "fs";
41024
- import { dirname as dirname18, join as join32 } from "path";
41337
+ import { dirname as dirname19, join as join32 } from "path";
41025
41338
  import { Database } from "bun:sqlite";
41026
41339
  function getFeedbackDbPath() {
41027
41340
  return join32(getDataDir(), "skills.db");
41028
41341
  }
41029
41342
  function getFeedbackDb() {
41030
41343
  const dbPath = getFeedbackDbPath();
41031
- const dir = dirname18(dbPath);
41344
+ const dir = dirname19(dbPath);
41032
41345
  if (!existsSync18(dir))
41033
41346
  mkdirSync14(dir, { recursive: true });
41034
41347
  const db = new Database(dbPath);
@@ -41057,7 +41370,7 @@ function saveFeedback(input2) {
41057
41370
  const category = input2.category ?? "general";
41058
41371
  if (isApiMode()) {
41059
41372
  const path = join32(getDataDir(), "feedback.jsonl");
41060
- const dir = dirname18(path);
41373
+ const dir = dirname19(path);
41061
41374
  if (!existsSync18(dir))
41062
41375
  mkdirSync14(dir, { recursive: true });
41063
41376
  appendFileSync(path, JSON.stringify({ message, category, email: input2.email ?? null, agent: input2.agent ?? null, version: input2.version ?? null, createdAt: new Date().toISOString() }) + `
@@ -41080,7 +41393,7 @@ function isApiMode(env = process.env) {
41080
41393
  }
41081
41394
  }
41082
41395
  // src/lib/native-storage.ts
41083
- import { createHash as createHash18, createHmac as createHmac2 } from "crypto";
41396
+ import { createHash as createHash19, createHmac as createHmac2 } from "crypto";
41084
41397
  import {
41085
41398
  existsSync as existsSync19,
41086
41399
  mkdirSync as mkdirSync15,
@@ -41089,7 +41402,7 @@ import {
41089
41402
  statSync as statSync11,
41090
41403
  writeFileSync as writeFileSync12
41091
41404
  } from "fs";
41092
- import { dirname as dirname19, join as join33, normalize as normalize3, relative as relative8, sep as sep7 } from "path";
41405
+ import { dirname as dirname20, join as join33, normalize as normalize3, relative as relative8, sep as sep7 } from "path";
41093
41406
  var SKILLS_STORAGE_TABLES = [
41094
41407
  "skills_sync_records",
41095
41408
  "skills_sync_cursors"
@@ -41256,7 +41569,7 @@ function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
41256
41569
  files.push({
41257
41570
  path: relativePath,
41258
41571
  sizeBytes: bytes.byteLength,
41259
- sha256: createHash18("sha256").update(bytes).digest("hex"),
41572
+ sha256: createHash19("sha256").update(bytes).digest("hex"),
41260
41573
  ...options.includeFileContents ? { contentBase64: Buffer.from(bytes).toString("base64") } : {}
41261
41574
  });
41262
41575
  }
@@ -41275,18 +41588,18 @@ function importSkillsLocalSnapshot(snapshot, targetDir = process.cwd(), options
41275
41588
  skipped += 1;
41276
41589
  continue;
41277
41590
  }
41278
- const absolutePath2 = resolveSnapshotPath(targetDir, file2.path);
41279
- if (existsSync19(absolutePath2) && !options.overwrite) {
41591
+ const absolutePath3 = resolveSnapshotPath(targetDir, file2.path);
41592
+ if (existsSync19(absolutePath3) && !options.overwrite) {
41280
41593
  skipped += 1;
41281
41594
  continue;
41282
41595
  }
41283
41596
  const bytes = Buffer.from(file2.contentBase64, "base64");
41284
- const hash4 = createHash18("sha256").update(bytes).digest("hex");
41597
+ const hash4 = createHash19("sha256").update(bytes).digest("hex");
41285
41598
  if (hash4 !== file2.sha256) {
41286
41599
  throw new Error(`Snapshot file checksum mismatch: ${file2.path}`);
41287
41600
  }
41288
- mkdirSync15(dirname19(absolutePath2), { recursive: true });
41289
- writeFileSync12(absolutePath2, bytes);
41601
+ mkdirSync15(dirname20(absolutePath3), { recursive: true });
41602
+ writeFileSync12(absolutePath3, bytes);
41290
41603
  written += 1;
41291
41604
  }
41292
41605
  return { written, skipped };
@@ -41613,7 +41926,7 @@ function toIsoString(value) {
41613
41926
  return Number.isNaN(date6.getTime()) ? value : date6.toISOString();
41614
41927
  }
41615
41928
  function sha256Hex2(value) {
41616
- return createHash18("sha256").update(value).digest("hex");
41929
+ return createHash19("sha256").update(value).digest("hex");
41617
41930
  }
41618
41931
  function normalizeHeaders(headers) {
41619
41932
  const result = {};
@@ -41665,7 +41978,7 @@ function toArrayBuffer(bytes) {
41665
41978
  return buffer;
41666
41979
  }
41667
41980
  // src/lib/station-snapshot.ts
41668
- import { createHash as createHash19 } from "crypto";
41981
+ import { createHash as createHash20 } from "crypto";
41669
41982
  import {
41670
41983
  copyFileSync,
41671
41984
  mkdirSync as mkdirSync16,
@@ -41673,7 +41986,7 @@ import {
41673
41986
  statSync as statSync13,
41674
41987
  writeFileSync as writeFileSync13
41675
41988
  } from "fs";
41676
- import { dirname as dirname20, isAbsolute as isAbsolute16, relative as relative9, resolve as resolve15, sep as sep9 } from "path";
41989
+ import { dirname as dirname21, isAbsolute as isAbsolute17, relative as relative9, resolve as resolve16, sep as sep9 } from "path";
41677
41990
 
41678
41991
  // src/lib/portable-snapshot-filter.ts
41679
41992
  import { readdirSync as readdirSync14, statSync as statSync12 } from "fs";
@@ -41840,7 +42153,7 @@ function validateStationId(stationId) {
41840
42153
  }
41841
42154
  }
41842
42155
  function sha256File(filePath) {
41843
- return createHash19("sha256").update(readFileSync23(filePath)).digest("hex");
42156
+ return createHash20("sha256").update(readFileSync23(filePath)).digest("hex");
41844
42157
  }
41845
42158
  function scanHome(definition, homesRoot) {
41846
42159
  const homePath = homePathFor(definition, homesRoot);
@@ -41911,7 +42224,7 @@ function humanHomes(scanned) {
41911
42224
  }));
41912
42225
  }
41913
42226
  function writeStationSnapshot(options) {
41914
- const repoRoot = resolve15(options.repoRoot ?? process.cwd());
42227
+ const repoRoot = resolve16(options.repoRoot ?? process.cwd());
41915
42228
  const { scanned, plans, totalBytes } = planStationSnapshot(options);
41916
42229
  const manifestFiles = plans.map((plan) => ({
41917
42230
  relativePath: plan.source.relativePath,
@@ -41937,9 +42250,9 @@ function writeStationSnapshot(options) {
41937
42250
  const conflicts = [];
41938
42251
  const untouched = [];
41939
42252
  for (const plan of plans) {
41940
- const destination = resolve15(repoRoot, plan.destination);
42253
+ const destination = resolve16(repoRoot, plan.destination);
41941
42254
  const destinationRelative = relative9(repoRoot, destination);
41942
- if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep9) || isAbsolute16(destinationRelative)) {
42255
+ if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep9) || isAbsolute17(destinationRelative)) {
41943
42256
  throw new StationSnapshotError("DESTINATION_ESCAPE", `destination escapes repo root: ${plan.destination}`);
41944
42257
  }
41945
42258
  let existingDigest = null;
@@ -41960,8 +42273,8 @@ function writeStationSnapshot(options) {
41960
42273
  }
41961
42274
  let written = 0;
41962
42275
  for (const plan of untouched) {
41963
- const destination = resolve15(repoRoot, plan.destination);
41964
- mkdirSync16(dirname20(destination), { recursive: true });
42276
+ const destination = resolve16(repoRoot, plan.destination);
42277
+ mkdirSync16(dirname21(destination), { recursive: true });
41965
42278
  copyFileSync(plan.source.fullPath, destination);
41966
42279
  written += 1;
41967
42280
  }
@@ -41979,8 +42292,8 @@ function writeStationSnapshot(options) {
41979
42292
  },
41980
42293
  files: manifestFiles
41981
42294
  };
41982
- const manifestPath = resolve15(repoRoot, "resources", options.stationId, "skills", "sync-manifest.json");
41983
- mkdirSync16(dirname20(manifestPath), { recursive: true });
42295
+ const manifestPath = resolve16(repoRoot, "resources", options.stationId, "skills", "sync-manifest.json");
42296
+ mkdirSync16(dirname21(manifestPath), { recursive: true });
41984
42297
  writeFileSync13(manifestPath, `${JSON.stringify(manifest, null, 2)}
41985
42298
  `);
41986
42299
  return {
@@ -41991,7 +42304,7 @@ function writeStationSnapshot(options) {
41991
42304
  };
41992
42305
  }
41993
42306
  // src/lib/station-hydrate.ts
41994
- import { createHash as createHash20 } from "crypto";
42307
+ import { createHash as createHash21 } from "crypto";
41995
42308
  import {
41996
42309
  copyFileSync as copyFileSync2,
41997
42310
  mkdirSync as mkdirSync17,
@@ -42000,7 +42313,7 @@ import {
42000
42313
  statSync as statSync14,
42001
42314
  writeFileSync as writeFileSync14
42002
42315
  } from "fs";
42003
- import { dirname as dirname21, join as join35, resolve as resolve16, sep as sep10 } from "path";
42316
+ import { dirname as dirname22, join as join35, resolve as resolve17, sep as sep10 } from "path";
42004
42317
  var STATION_HYDRATION_MANIFEST_SCHEMA = "hasna.fleet-resources.skills-hydration-manifest/v1";
42005
42318
  var STATION_HYDRATION_PRODUCER = { name: "@hasna/skills", version: package_default.version };
42006
42319
  var MANIFEST_HASH_KEY_SEP = String.fromCharCode(0);
@@ -42197,12 +42510,12 @@ function skillSha256(skill) {
42197
42510
  return sha256File(skill.files[0].winner.fullPath);
42198
42511
  }
42199
42512
  const joined = skill.files.map((file2) => sha256File(file2.winner.fullPath));
42200
- return createHash20("sha256").update(joined.sort().join(`
42513
+ return createHash21("sha256").update(joined.sort().join(`
42201
42514
  `)).digest("hex");
42202
42515
  }
42203
42516
  function writeStationHydration(options) {
42204
- const repoRoot = resolve16(options.repoRoot ?? process.cwd());
42205
- const cacheRoot = resolve16(options.cacheRoot ?? resolveCorpusRoot());
42517
+ const repoRoot = resolve17(options.repoRoot ?? process.cwd());
42518
+ const cacheRoot = resolve17(options.cacheRoot ?? resolveCorpusRoot());
42206
42519
  const plan = planStationHydration(options.stationId, repoRoot);
42207
42520
  const resultSkills = plan.winners.map((skill) => ({
42208
42521
  ident: skill.ident,
@@ -42256,7 +42569,7 @@ function writeStationHydration(options) {
42256
42569
  }
42257
42570
  let written = 0;
42258
42571
  for (const entry of toWrite) {
42259
- mkdirSync17(dirname21(entry.destination), { recursive: true });
42572
+ mkdirSync17(dirname22(entry.destination), { recursive: true });
42260
42573
  copyFileSync2(entry.fullPath, entry.destination);
42261
42574
  written += 1;
42262
42575
  }
@@ -42277,8 +42590,8 @@ function writeStationHydration(options) {
42277
42590
  },
42278
42591
  skills: resultSkills
42279
42592
  };
42280
- const hydrationManifestPath = join35(dirname21(cacheRoot), `hydration-${options.stationId}.json`);
42281
- mkdirSync17(dirname21(hydrationManifestPath), { recursive: true });
42593
+ const hydrationManifestPath = join35(dirname22(cacheRoot), `hydration-${options.stationId}.json`);
42594
+ mkdirSync17(dirname22(hydrationManifestPath), { recursive: true });
42282
42595
  writeFileSync14(hydrationManifestPath, `${JSON.stringify(hydration, null, 2)}
42283
42596
  `);
42284
42597
  return {
@@ -42289,23 +42602,23 @@ function writeStationHydration(options) {
42289
42602
  };
42290
42603
  }
42291
42604
  // src/lib/private-publication-recovery.ts
42292
- import { constants as constants10, closeSync as closeSync11, fsyncSync as fsyncSync4, fstatSync as fstatSync11, lstatSync as lstatSync19, mkdirSync as mkdirSync18, openSync as openSync11, readSync as readSync9, realpathSync as realpathSync6, renameSync as renameSync7, unlinkSync as unlinkSync5, writeFileSync as writeFileSync15 } from "fs";
42293
- import { dirname as dirname22, isAbsolute as isAbsolute17, join as join36, resolve as resolve17 } from "path";
42605
+ import { constants as constants11, closeSync as closeSync12, fsyncSync as fsyncSync4, fstatSync as fstatSync12, lstatSync as lstatSync20, mkdirSync as mkdirSync18, openSync as openSync12, readSync as readSync10, realpathSync as realpathSync6, renameSync as renameSync7, unlinkSync as unlinkSync5, writeFileSync as writeFileSync15 } from "fs";
42606
+ import { dirname as dirname23, isAbsolute as isAbsolute18, join as join36, resolve as resolve18 } from "path";
42294
42607
  import { randomUUID as randomUUID4 } from "crypto";
42295
42608
  var fail2 = () => {
42296
42609
  throw new PrivatePublicationError("PUBLICATION_RECOVERY_INVALID", "The recovery directory is invalid or changed. Preserve it and inspect the existing intent; do not start a replacement automatically.");
42297
42610
  };
42298
42611
  function safeDirectory(directory2) {
42299
- if (!isAbsolute17(directory2) || directory2 !== resolve17(directory2) || realpathSync6(directory2) !== directory2)
42612
+ if (!isAbsolute18(directory2) || directory2 !== resolve18(directory2) || realpathSync6(directory2) !== directory2)
42300
42613
  return fail2();
42301
- for (let path = directory2;; path = dirname22(path)) {
42302
- const stat2 = lstatSync19(path);
42614
+ for (let path = directory2;; path = dirname23(path)) {
42615
+ const stat2 = lstatSync20(path);
42303
42616
  if (!stat2.isDirectory() || stat2.isSymbolicLink())
42304
42617
  return fail2();
42305
- if (path === dirname22(path))
42618
+ if (path === dirname23(path))
42306
42619
  break;
42307
42620
  }
42308
- const own2 = lstatSync19(directory2);
42621
+ const own2 = lstatSync20(directory2);
42309
42622
  if ((own2.mode & 63) !== 0 || process.getuid && own2.uid !== process.getuid())
42310
42623
  return fail2();
42311
42624
  return { dev: own2.dev, ino: own2.ino };
@@ -42317,35 +42630,35 @@ function unchangedDirectory(directory2, identity3) {
42317
42630
  }
42318
42631
  function readOwned(directory2, name, max) {
42319
42632
  const identity3 = safeDirectory(directory2), file2 = join36(directory2, name);
42320
- const fd = openSync11(file2, constants10.O_RDONLY | constants10.O_NOFOLLOW);
42633
+ const fd = openSync12(file2, constants11.O_RDONLY | constants11.O_NOFOLLOW);
42321
42634
  try {
42322
- const stat2 = fstatSync11(fd);
42635
+ const stat2 = fstatSync12(fd);
42323
42636
  if (!stat2.isFile() || stat2.nlink !== 1 || stat2.size > max || stat2.size < 1 || (stat2.mode & 63) !== 0 || process.getuid && stat2.uid !== process.getuid())
42324
42637
  return fail2();
42325
42638
  const buffer = Buffer.alloc(Math.min(max, stat2.size) + 1);
42326
42639
  let length = 0;
42327
42640
  while (length < buffer.length) {
42328
- const count = readSync9(fd, buffer, length, buffer.length - length, length);
42641
+ const count = readSync10(fd, buffer, length, buffer.length - length, length);
42329
42642
  if (count === 0)
42330
42643
  break;
42331
42644
  length += count;
42332
42645
  }
42333
- const bytes = buffer.subarray(0, length), after = fstatSync11(fd);
42646
+ const bytes = buffer.subarray(0, length), after = fstatSync12(fd);
42334
42647
  unchangedDirectory(directory2, identity3);
42335
42648
  if (bytes.length !== stat2.size || stat2.size !== after.size || stat2.mtimeMs !== after.mtimeMs || stat2.ctimeMs !== after.ctimeMs)
42336
42649
  return fail2();
42337
42650
  return bytes;
42338
42651
  } finally {
42339
- closeSync11(fd);
42652
+ closeSync12(fd);
42340
42653
  }
42341
42654
  }
42342
42655
  function writeOwned(directory2, name, bytes) {
42343
- const fd = openSync11(join36(directory2, name), constants10.O_WRONLY | constants10.O_CREAT | constants10.O_EXCL | constants10.O_NOFOLLOW, 384);
42656
+ const fd = openSync12(join36(directory2, name), constants11.O_WRONLY | constants11.O_CREAT | constants11.O_EXCL | constants11.O_NOFOLLOW, 384);
42344
42657
  try {
42345
42658
  writeFileSync15(fd, bytes);
42346
42659
  fsyncSync4(fd);
42347
42660
  } finally {
42348
- closeSync11(fd);
42661
+ closeSync12(fd);
42349
42662
  }
42350
42663
  }
42351
42664
  function save(directory2, value) {
@@ -42354,11 +42667,11 @@ function save(directory2, value) {
42354
42667
  `);
42355
42668
  unchangedDirectory(directory2, identity3);
42356
42669
  renameSync7(join36(directory2, temporary), join36(directory2, "receipt.json"));
42357
- const fd = openSync11(directory2, constants10.O_RDONLY | constants10.O_NOFOLLOW);
42670
+ const fd = openSync12(directory2, constants11.O_RDONLY | constants11.O_NOFOLLOW);
42358
42671
  try {
42359
42672
  fsyncSync4(fd);
42360
42673
  } finally {
42361
- closeSync11(fd);
42674
+ closeSync12(fd);
42362
42675
  }
42363
42676
  }
42364
42677
  function bind(client2, receipt) {
@@ -42369,20 +42682,20 @@ async function locked(directory2, action) {
42369
42682
  const identity3 = safeDirectory(directory2), file2 = join36(directory2, "operation.lock");
42370
42683
  let fd;
42371
42684
  try {
42372
- fd = openSync11(file2, constants10.O_WRONLY | constants10.O_CREAT | constants10.O_EXCL | constants10.O_NOFOLLOW, 384);
42685
+ fd = openSync12(file2, constants11.O_WRONLY | constants11.O_CREAT | constants11.O_EXCL | constants11.O_NOFOLLOW, 384);
42373
42686
  } catch {
42374
42687
  throw new PrivatePublicationError("PUBLICATION_RECOVERY_BUSY", "Another operation holds this recovery directory. If it crashed, confirm that process has stopped before explicitly removing operation.lock and resuming.");
42375
42688
  }
42376
- const lock = fstatSync11(fd);
42689
+ const lock = fstatSync12(fd);
42377
42690
  try {
42378
42691
  writeFileSync15(fd, JSON.stringify({ pid: process.pid }) + `
42379
42692
  `);
42380
42693
  fsyncSync4(fd);
42381
42694
  return await action();
42382
42695
  } finally {
42383
- closeSync11(fd);
42696
+ closeSync12(fd);
42384
42697
  unchangedDirectory(directory2, identity3);
42385
- const now = lstatSync19(file2);
42698
+ const now = lstatSync20(file2);
42386
42699
  if (now.dev !== lock.dev || now.ino !== lock.ino || !now.isFile() || now.isSymbolicLink())
42387
42700
  fail2();
42388
42701
  unlinkSync5(file2);
@@ -42434,15 +42747,15 @@ async function preparePrivatePublication(client2, sourceDirectory, recoveryDirec
42434
42747
  phase: "prepared",
42435
42748
  intent: null
42436
42749
  };
42437
- if (!isAbsolute17(recoveryDirectory) || resolve17(recoveryDirectory) !== recoveryDirectory || realpathSync6(dirname22(recoveryDirectory)) !== dirname22(recoveryDirectory))
42750
+ if (!isAbsolute18(recoveryDirectory) || resolve18(recoveryDirectory) !== recoveryDirectory || realpathSync6(dirname23(recoveryDirectory)) !== dirname23(recoveryDirectory))
42438
42751
  return fail2();
42439
42752
  mkdirSync18(recoveryDirectory, { mode: 448 });
42440
42753
  safeDirectory(recoveryDirectory);
42441
- const parent = openSync11(dirname22(recoveryDirectory), constants10.O_RDONLY | constants10.O_NOFOLLOW);
42754
+ const parent = openSync12(dirname23(recoveryDirectory), constants11.O_RDONLY | constants11.O_NOFOLLOW);
42442
42755
  try {
42443
42756
  fsyncSync4(parent);
42444
42757
  } finally {
42445
- closeSync11(parent);
42758
+ closeSync12(parent);
42446
42759
  }
42447
42760
  writeOwned(recoveryDirectory, "bundle.tgz", packed.bytes);
42448
42761
  save(recoveryDirectory, receipt);
@@ -42525,8 +42838,8 @@ async function inspectLocked(client2, directory2, cancel) {
42525
42838
  return privatePublicationResult(directory2, receipt);
42526
42839
  }
42527
42840
  // src/lib/skill-context.ts
42528
- import { createHash as createHash21 } from "crypto";
42529
- import { resolve as resolve18 } from "path";
42841
+ import { createHash as createHash22 } from "crypto";
42842
+ import { resolve as resolve19 } from "path";
42530
42843
  function words(value) {
42531
42844
  return new Set(value.toLowerCase().match(/[a-z0-9]+/g) ?? []);
42532
42845
  }
@@ -42561,7 +42874,7 @@ async function buildSkillContext(input2, options = {}) {
42561
42874
  const promptWords = words(prompt);
42562
42875
  const promptNames = new Set(prompt.toLowerCase().match(/[a-z0-9]+(?:-[a-z0-9]+)*/g) ?? []);
42563
42876
  const loaded = new Set(resolved.session?.loaded ?? []);
42564
- const paths = [...input2.paths ?? [], ...input2.cwd ? [input2.cwd, resolve18(input2.cwd)] : []];
42877
+ const paths = [...input2.paths ?? [], ...input2.cwd ? [input2.cwd, resolve19(input2.cwd)] : []];
42565
42878
  const candidates = profile.selections.map((selection) => {
42566
42879
  const key = selectionKey(selection);
42567
42880
  if (input2.restore && loaded.has(key))
@@ -42614,7 +42927,7 @@ ${content}`;
42614
42927
  `);
42615
42928
  const receipt = {
42616
42929
  schemaVersion: 1,
42617
- id: createHash21("sha256").update(JSON.stringify({ profile: profile.profileRevision, sessionId, selections, omitted })).digest("hex"),
42930
+ id: createHash22("sha256").update(JSON.stringify({ profile: profile.profileRevision, sessionId, selections, omitted })).digest("hex"),
42618
42931
  profileId: profile.profileId,
42619
42932
  profileRevision: profile.profileRevision,
42620
42933
  authority: profile.authority,
@@ -42630,9 +42943,9 @@ ${content}`;
42630
42943
  return { context: context2, selections, omitted, receipt };
42631
42944
  }
42632
42945
  // src/lib/session-reconciliation.ts
42633
- import { createHash as createHash22 } from "crypto";
42946
+ import { createHash as createHash23 } from "crypto";
42634
42947
  var SESSION_RECONCILIATION_PLAN_TTL_MS = 5 * 60 * 1000;
42635
- var digest3 = (value) => createHash22("sha256").update(JSON.stringify(value)).digest("hex");
42948
+ var digest3 = (value) => createHash23("sha256").update(JSON.stringify(value)).digest("hex");
42636
42949
  function exactTimestamp(value) {
42637
42950
  const parsed = value === undefined ? Number.NaN : Date.parse(value);
42638
42951
  if (!Number.isFinite(parsed) || new Date(parsed).toISOString() !== value) {
@@ -42921,6 +43234,7 @@ export {
42921
43234
  captureDiscoveryPathSources,
42922
43235
  captureDiscoveryDirectories,
42923
43236
  captureDiscoveryByteSources,
43237
+ captureClaudeSettings,
42924
43238
  captureClaudeMarketplaceRegistry,
42925
43239
  canonicalizeManifest,
42926
43240
  buildSkillsS3ObjectUrl,