@hasna/skills 0.8.10 → 0.8.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/index.js CHANGED
@@ -36868,7 +36868,7 @@ var package_default;
36868
36868
  var init_package = __esm(() => {
36869
36869
  package_default = {
36870
36870
  name: "@hasna/skills",
36871
- version: "0.8.10",
36871
+ version: "0.8.11",
36872
36872
  description: "Skills library for AI coding agents",
36873
36873
  type: "module",
36874
36874
  bin: {
@@ -36930,10 +36930,11 @@ var init_package = __esm(() => {
36930
36930
  typecheck: "tsc --noEmit",
36931
36931
  "verify:release": "bun run scripts/release-guard.ts",
36932
36932
  "verify:consumer-types": "bun run scripts/consumer-types.ts",
36933
- prepare: "bun run build:js",
36934
- prepack: "bun run build && bun run verify:release && bun run verify:consumer-types",
36933
+ prepack: "bun run verify:generated && bun run verify:release && bun run verify:consumer-types",
36935
36934
  prepublishOnly: "bun run verify:producer && bun run typecheck && bun run test",
36936
- "verify:producer": "bun run scripts/release-dependencies.ts"
36935
+ "verify:producer": "bun run scripts/release-dependencies.ts",
36936
+ "verify:generated": "HASNA_SKILLS_RELEASE_ARTIFACT_TEST=1 bun test src/lib/release-artifacts.test.ts",
36937
+ "verify:consumer-credentials": "bun run scripts/consumer-credentials.ts"
36937
36938
  },
36938
36939
  keywords: [
36939
36940
  "skills",
@@ -36955,7 +36956,6 @@ var init_package = __esm(() => {
36955
36956
  license: "Apache-2.0",
36956
36957
  devDependencies: {
36957
36958
  "@hasna/contracts": "1.1.0",
36958
- "@hasna/secrets": "0.4.2",
36959
36959
  "@types/bun": "1.3.14",
36960
36960
  "@types/node": "25.2.3",
36961
36961
  "@types/react": "^18.2.0",
@@ -36968,6 +36968,7 @@ var init_package = __esm(() => {
36968
36968
  "@aws-sdk/client-ecs": "^3.1079.0",
36969
36969
  "@aws-sdk/client-s3": "^3.1079.0",
36970
36970
  "@hasna/events": "0.1.18",
36971
+ "@hasna/secrets": "0.4.2",
36971
36972
  "@modelcontextprotocol/sdk": "^1.26.0",
36972
36973
  chalk: "^5.3.0",
36973
36974
  commander: "^12.1.0",
@@ -42784,14 +42785,15 @@ function profileSelectionSnapshot(selections) {
42784
42785
  var MAX_PROFILE_SELECTIONS = 4096, MAX_PROFILE_DOCUMENT_BYTES, MAX_SKILL_SESSION_ID_CHARS = 256, PROFILE_SESSION_ENVELOPE_BYTES, MAX_RESOLVED_PROFILE_BYTES, LEGACY_PROFILE_SELECTIONS = 256, LEGACY_PROFILE_DOCUMENT_BYTES = 1e6;
42785
42786
  var init_profile_limits = __esm(() => {
42786
42787
  MAX_PROFILE_DOCUMENT_BYTES = 8 * 1024 * 1024;
42787
- PROFILE_SESSION_ENVELOPE_BYTES = MAX_PROFILE_SELECTIONS * 67 + MAX_SKILL_SESSION_ID_CHARS * 6 + 256;
42788
+ PROFILE_SESSION_ENVELOPE_BYTES = MAX_PROFILE_SELECTIONS * 67 + MAX_SKILL_SESSION_ID_CHARS * 12 + 512;
42788
42789
  MAX_RESOLVED_PROFILE_BYTES = MAX_PROFILE_DOCUMENT_BYTES - PROFILE_SESSION_ENVELOPE_BYTES;
42789
42790
  });
42790
42791
 
42791
42792
  // src/lib/selection-cache.ts
42792
42793
  import { createHash as createHash3, randomUUID as randomUUID3 } from "crypto";
42793
- import { closeSync, constants as constants2, fstatSync, lstatSync as lstatSync3, mkdirSync as mkdirSync4, openSync, readSync, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync4 } from "fs";
42794
+ import { closeSync, constants as constants2, fstatSync, fsyncSync, lstatSync as lstatSync3, mkdirSync as mkdirSync4, openSync, readSync, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync4 } from "fs";
42794
42795
  import { dirname as dirname4, join as join14, parse, resolve as resolve4 } from "path";
42796
+ import { isDeepStrictEqual as isDeepStrictEqual2 } from "util";
42795
42797
  function selectionCacheRoot(options = {}) {
42796
42798
  return resolve4(options.cacheDir ?? join14(getDataDirReadOnly(), "selection-cache"));
42797
42799
  }
@@ -42895,12 +42897,21 @@ function writeSelectionJson(path, value) {
42895
42897
  throw new SkillSelectionError("RECEIPT_TOO_LARGE", "The Skills selection receipt exceeds its size limit.");
42896
42898
  atomicWrite(path, bytes, 384);
42897
42899
  }
42898
- function atomicWrite(path, bytes, mode) {
42900
+ function atomicWrite(path, bytes, mode, durable = false) {
42899
42901
  assertRegularPath(path, true);
42900
42902
  const temporary = join14(dirname4(path), `.selection-${randomUUID3()}.tmp`);
42901
42903
  try {
42902
- writeFileSync4(temporary, bytes, { flag: "wx", mode });
42904
+ const fd = openSync(temporary, constants2.O_WRONLY | constants2.O_CREAT | constants2.O_EXCL | constants2.O_NOFOLLOW, mode);
42905
+ try {
42906
+ writeFileSync4(fd, bytes);
42907
+ if (durable)
42908
+ fsyncSync(fd);
42909
+ } finally {
42910
+ closeSync(fd);
42911
+ }
42903
42912
  renameSync2(temporary, path);
42913
+ if (durable)
42914
+ syncDirectory(dirname4(path));
42904
42915
  } finally {
42905
42916
  try {
42906
42917
  unlinkSync(temporary);
@@ -43019,16 +43030,190 @@ function sessionReceiptPath(sessionId, options = {}) {
43019
43030
  throw new SkillSelectionError("INVALID_SESSION", `A Skills session id must contain 1\u2013${MAX_SKILL_SESSION_ID_CHARS} characters.`);
43020
43031
  return join14(selectionCacheRoot(options), "sessions", `${hash(sessionId)}.json`);
43021
43032
  }
43022
- function readSkillSession(sessionId, options = {}) {
43023
- const receipt = readSelectionJson(sessionReceiptPath(sessionId, options));
43024
- if (receipt) {
43025
- validateSelectionReceipt(receipt);
43026
- const keys2 = new Set(receipt.profile.selections.map(selectionKey));
43027
- if (receipt.sessionId !== sessionId || !Array.isArray(receipt.loaded) || receipt.loaded.length > keys2.size || new Set(receipt.loaded).size !== receipt.loaded.length || !receipt.loaded.every((key) => keys2.has(key))) {
43028
- throw new SkillSelectionError("INVALID_RECEIPT", "The Skills session receipt is invalid.");
43033
+ function skillSessionGeneration(receipt) {
43034
+ return receipt.generation ?? 0;
43035
+ }
43036
+ function validateSkillSessionBinding(binding) {
43037
+ if (!binding || typeof binding.sessionId !== "string" || !binding.sessionId.trim() || binding.sessionId.length > MAX_SKILL_SESSION_ID_CHARS || !Number.isSafeInteger(binding.generation) || binding.generation < 0 || !/^[a-f0-9]{64}$/.test(binding.receiptSha256)) {
43038
+ throw new SkillSelectionError("INVALID_RECEIPT", "The Skills session receipt contains an invalid parent snapshot binding.");
43039
+ }
43040
+ }
43041
+ function validateSkillSessionReceipt(receipt, sessionId) {
43042
+ validateSelectionReceipt(receipt);
43043
+ const keys2 = new Set(receipt.profile.selections.map(selectionKey));
43044
+ if (receipt.sessionId !== sessionId || !Array.isArray(receipt.loaded) || receipt.loaded.length > keys2.size || new Set(receipt.loaded).size !== receipt.loaded.length || !receipt.loaded.every((key) => keys2.has(key)) || receipt.generation !== undefined && (!Number.isSafeInteger(receipt.generation) || receipt.generation < 1)) {
43045
+ throw new SkillSelectionError("INVALID_RECEIPT", "The Skills session receipt is invalid.");
43046
+ }
43047
+ if (receipt.parent) {
43048
+ validateSkillSessionBinding(receipt.parent);
43049
+ if (receipt.parent.sessionId === sessionId)
43050
+ throw new SkillSelectionError("INVALID_RECEIPT", "A Skills child session cannot name itself as its parent.");
43051
+ }
43052
+ }
43053
+ function readSkillSessionSnapshotIfExists(sessionId, options = {}) {
43054
+ const path = sessionReceiptPath(sessionId, options), bytes = readRegularFile(path, MAX_PROFILE_DOCUMENT_BYTES);
43055
+ if (!bytes)
43056
+ return null;
43057
+ let receipt;
43058
+ try {
43059
+ receipt = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
43060
+ } catch {
43061
+ throw new SkillSelectionError("INVALID_RECEIPT", "The Skills session receipt is unreadable.");
43062
+ }
43063
+ validateSkillSessionReceipt(receipt, sessionId);
43064
+ const sha256 = sha256Hex(bytes);
43065
+ return { path, bytes, receipt, sha256, sessionId, generation: skillSessionGeneration(receipt), receiptSha256: sha256 };
43066
+ }
43067
+ function readSkillSessionSnapshot(sessionId, options = {}) {
43068
+ const snapshot = readSkillSessionSnapshotIfExists(sessionId, options);
43069
+ if (!snapshot)
43070
+ throw new SkillSelectionError("SESSION_NOT_FOUND", "The requested Skills session receipt does not exist.");
43071
+ return snapshot;
43072
+ }
43073
+ function skillSessionSnapshotBinding(snapshot) {
43074
+ return { sessionId: snapshot.sessionId, generation: snapshot.generation, receiptSha256: snapshot.receiptSha256 };
43075
+ }
43076
+ function withSessionWriteLocks(sessionIds, options, action) {
43077
+ const operationId = randomUUID3();
43078
+ const locks = [...new Set(sessionIds)].map((sessionId) => ({ sessionId, path: `${sessionReceiptPath(sessionId, options)}.write-lock` })).sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
43079
+ const owned = [];
43080
+ const assertOwned = () => {
43081
+ for (const lock of owned) {
43082
+ const current = lstatSync3(lock.path, { throwIfNoEntry: false });
43083
+ if (!current?.isFile() || current.dev !== lock.dev || current.ino !== lock.ino) {
43084
+ throw new SkillSelectionError("SESSION_WRITE_LOCK_CHANGED", "A session write lock changed during the operation; no replacement is permitted.");
43085
+ }
43086
+ }
43087
+ };
43088
+ try {
43089
+ for (const lock of locks) {
43090
+ assertRegularPath(lock.path, true);
43091
+ let fd;
43092
+ try {
43093
+ fd = openSync(lock.path, constants2.O_WRONLY | constants2.O_CREAT | constants2.O_EXCL | constants2.O_NOFOLLOW, 384);
43094
+ } catch (error) {
43095
+ if (error.code === "EEXIST")
43096
+ throw new SkillSelectionError("SESSION_WRITE_LOCKED", "Another Skills process owns a required session write lock; retry after it completes. A surviving lock requires explicit recovery review.");
43097
+ throw error;
43098
+ }
43099
+ const stat = fstatSync(fd);
43100
+ owned.push({ path: lock.path, fd, dev: stat.dev, ino: stat.ino });
43101
+ writeFileSync4(fd, `${JSON.stringify({ schemaVersion: 1, operationId, sessionId: lock.sessionId, pid: process.pid })}
43102
+ `);
43103
+ }
43104
+ return action(assertOwned);
43105
+ } finally {
43106
+ for (const lock of owned.reverse()) {
43107
+ closeSync(lock.fd);
43108
+ const current = lstatSync3(lock.path, { throwIfNoEntry: false });
43109
+ if (current?.isFile() && current.dev === lock.dev && current.ino === lock.ino)
43110
+ unlinkSync(lock.path);
43029
43111
  }
43030
43112
  }
43031
- return receipt;
43113
+ }
43114
+ function withSessionWriteLock(sessionId, options, action) {
43115
+ return withSessionWriteLocks([sessionId], options, action);
43116
+ }
43117
+ function sameSnapshot(actual, expected) {
43118
+ return actual === null ? expected === null : expected !== null && actual.sessionId === expected.sessionId && actual.generation === expected.generation && actual.receiptSha256 === expected.receiptSha256;
43119
+ }
43120
+ function nextSkillSessionGeneration(generation) {
43121
+ if (!Number.isSafeInteger(generation) || generation < 0 || generation >= Number.MAX_SAFE_INTEGER) {
43122
+ throw new SkillSelectionError("SESSION_GENERATION_EXHAUSTED", "The Skills session generation cannot advance safely; preserve the receipt and review recovery before continuing.");
43123
+ }
43124
+ return generation + 1;
43125
+ }
43126
+ function parentChanged() {
43127
+ throw new SkillSelectionError("SESSION_PARENT_CHANGED", "The parent Skills session changed while the child was resolving; resolve the child again from the current parent pin.");
43128
+ }
43129
+ function writeSkillSession(receipt, expected, options = {}) {
43130
+ validateSkillSessionReceipt(receipt, receipt.sessionId);
43131
+ if (expected.parent)
43132
+ validateSkillSessionBinding(expected.parent);
43133
+ if (expected.parent?.sessionId === receipt.sessionId)
43134
+ throw new SkillSelectionError("INVALID_RECEIPT", "A Skills child session cannot name itself as its parent.");
43135
+ const lockIds = expected.parent ? [receipt.sessionId, expected.parent.sessionId] : [receipt.sessionId];
43136
+ withSessionWriteLocks(lockIds, options, (assertOwned) => {
43137
+ const current = readSkillSessionSnapshotIfExists(receipt.sessionId, options);
43138
+ if (!sameSnapshot(current, expected.current) || current && !isDeepStrictEqual2(current.receipt.profile, receipt.profile)) {
43139
+ throw new SkillSelectionError("SESSION_RECEIPT_CHANGED", "The Skills session receipt changed while context was loading; resolve context again without replacing the current pin.");
43140
+ }
43141
+ let parent = null;
43142
+ if (expected.parent) {
43143
+ parent = readSkillSessionSnapshotIfExists(expected.parent.sessionId, options);
43144
+ if (!sameSnapshot(parent, expected.parent) || !parent || !isDeepStrictEqual2(parent.receipt.profile, receipt.profile))
43145
+ parentChanged();
43146
+ }
43147
+ const generation = nextSkillSessionGeneration(current?.generation ?? 0);
43148
+ const next = current ? { ...current.receipt, generation, loaded: [...new Set([...current.receipt.loaded, ...receipt.loaded])] } : { ...receipt, generation, ...expected.parent ? { parent: expected.parent } : {} };
43149
+ assertOwned();
43150
+ if (expected.parent) {
43151
+ parent = readSkillSessionSnapshotIfExists(expected.parent.sessionId, options);
43152
+ if (!sameSnapshot(parent, expected.parent))
43153
+ parentChanged();
43154
+ }
43155
+ writeSelectionJson(sessionReceiptPath(receipt.sessionId, options), next);
43156
+ });
43157
+ }
43158
+ function syncDirectory(path) {
43159
+ assertRegularPath(path);
43160
+ const fd = openSync(path, constants2.O_RDONLY | constants2.O_DIRECTORY | constants2.O_NOFOLLOW);
43161
+ try {
43162
+ fsyncSync(fd);
43163
+ } finally {
43164
+ closeSync(fd);
43165
+ }
43166
+ }
43167
+ function archiveBytes(path, bytes) {
43168
+ assertRegularPath(path, true);
43169
+ const fd = openSync(path, constants2.O_WRONLY | constants2.O_CREAT | constants2.O_EXCL | constants2.O_NOFOLLOW, 384);
43170
+ try {
43171
+ writeFileSync4(fd, bytes);
43172
+ fsyncSync(fd);
43173
+ } finally {
43174
+ closeSync(fd);
43175
+ }
43176
+ }
43177
+ function replaceSkillSession(expected, replacement, plan, options = {}, beforeCommit = () => {}) {
43178
+ validateSkillSessionReceipt(replacement, replacement.sessionId);
43179
+ const bytes = Buffer.from(`${JSON.stringify(replacement)}
43180
+ `);
43181
+ if (bytes.length > MAX_PROFILE_DOCUMENT_BYTES)
43182
+ throw new SkillSelectionError("RECEIPT_TOO_LARGE", "The Skills selection receipt exceeds its size limit.");
43183
+ return withSessionWriteLock(replacement.sessionId, options, (assertOwned) => {
43184
+ const before2 = readSkillSessionSnapshot(replacement.sessionId, options);
43185
+ if (!sameSnapshot(before2, expected))
43186
+ throw new SkillSelectionError("SESSION_RECEIPT_CHANGED", "The Skills session receipt generation or bytes changed after review; inspect it and prepare a new plan.");
43187
+ if (replacement.generation !== nextSkillSessionGeneration(before2.generation))
43188
+ throw new SkillSelectionError("SESSION_GENERATION_CHANGED", "The replacement Skills session must advance exactly one generation.");
43189
+ if (before2.receipt.profile.authority !== replacement.profile.authority || before2.receipt.profile.workspaceId !== replacement.profile.workspaceId) {
43190
+ throw new SkillSelectionError("PROFILE_IDENTITY_MISMATCH", "A session reconciliation cannot change its Skills authority or workspace.");
43191
+ }
43192
+ const directory = join14(selectionCacheRoot(options), "session-reconciliations", randomUUID3());
43193
+ const archivePath = join14(directory, "original.json"), replacementPath = join14(directory, "replacement.json"), receiptPath = join14(directory, "receipt.json");
43194
+ const afterSha256 = sha256Hex(bytes);
43195
+ archiveBytes(archivePath, before2.bytes);
43196
+ archiveBytes(replacementPath, bytes);
43197
+ const receipt = { schemaVersion: 1, status: "prepared", sessionId: replacement.sessionId, beforeGeneration: before2.generation, afterGeneration: replacement.generation, beforeSha256: before2.sha256, afterSha256, archivePath, replacementPath, plan };
43198
+ archiveBytes(receiptPath, Buffer.from(`${JSON.stringify(receipt)}
43199
+ `));
43200
+ syncDirectory(directory);
43201
+ syncDirectory(dirname4(directory));
43202
+ syncDirectory(selectionCacheRoot(options));
43203
+ if (sha256Hex(readRegularFile(archivePath, MAX_PROFILE_DOCUMENT_BYTES)) !== before2.sha256 || !sameSnapshot(readSkillSessionSnapshot(replacement.sessionId, options), expected)) {
43204
+ throw new SkillSelectionError("SESSION_RECEIPT_CHANGED", "The session or its preservation archive changed before replacement; retained evidence must be reviewed.");
43205
+ }
43206
+ beforeCommit();
43207
+ assertOwned();
43208
+ try {
43209
+ atomicWrite(before2.path, bytes, 384, true);
43210
+ atomicWrite(receiptPath, Buffer.from(`${JSON.stringify({ ...receipt, status: "applied" })}
43211
+ `), 384, true);
43212
+ } catch {
43213
+ throw new SkillSelectionError("SESSION_RECONCILIATION_INCOMPLETE", `Inspect sessions show and the preserved operation receipt at ${receiptPath} before any retry; replacement may already have committed.`);
43214
+ }
43215
+ return { archivePath, receiptPath, beforeSha256: before2.sha256, afterSha256 };
43216
+ });
43032
43217
  }
43033
43218
  var SkillSelectionError, MAX_CACHED_PROFILE_AGE_MS, SELECTION_LOCK_FILE = "selection.lock.json";
43034
43219
  var init_selection_cache = __esm(() => {
@@ -43048,6 +43233,7 @@ var init_selection_cache = __esm(() => {
43048
43233
  });
43049
43234
 
43050
43235
  // src/lib/agent-policy-limits.ts
43236
+ import { basename as basename3, isAbsolute as isAbsolute3, resolve as resolve5 } from "path";
43051
43237
  function object(value) {
43052
43238
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
43053
43239
  }
@@ -43112,7 +43298,9 @@ function assertAgentPolicyCollections(policy) {
43112
43298
  text(source.path);
43113
43299
  requireBound(source.sha256 === null || typeof source.sha256 === "string" && /^[a-f0-9]{64}$/.test(source.sha256));
43114
43300
  if (source.hashMode !== undefined)
43115
- requireBound(["bytes", "path-bytes", "claude-plugin-registry"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
43301
+ 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));
43302
+ if (source.hashMode === "claude-marketplace-registry")
43303
+ requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute3(source.path) && resolve5(source.path) === source.path && basename3(source.path) === "known_marketplaces.json");
43116
43304
  if (source.hashMode === "claude-plugin-registry") {
43117
43305
  requireBound(agent === "claude");
43118
43306
  const managed = array(source.managedPlugins, 64);
@@ -50265,7 +50453,7 @@ var init_dist = __esm(() => {
50265
50453
  });
50266
50454
 
50267
50455
  // src/lib/agent-hermes.ts
50268
- import { dirname as dirname5, isAbsolute as isAbsolute3, join as join17, resolve as resolve5 } from "path";
50456
+ import { dirname as dirname5, isAbsolute as isAbsolute4, join as join17, resolve as resolve6 } from "path";
50269
50457
  import { lstatSync as lstatSync6, readFileSync as readFileSync10, opendirSync } from "fs";
50270
50458
  function object2(value) {
50271
50459
  return Boolean(value && typeof value === "object" && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null));
@@ -50301,7 +50489,7 @@ function quoted(value) {
50301
50489
  return `'${value.replace(/'/g, `'\\''`)}'`;
50302
50490
  }
50303
50491
  function hermesHookDefinitions(supervisor) {
50304
- if (!isAbsolute3(supervisor.runtime) || !isAbsolute3(supervisor.path))
50492
+ if (!isAbsolute4(supervisor.runtime) || !isAbsolute4(supervisor.path))
50305
50493
  throw new Error("Expected absolute Hermes supervisor paths");
50306
50494
  const entry = (event) => ({ command: `${quoted(supervisor.runtime)} ${quoted(supervisor.path)} --event ${event}`, timeout: 15, ...event === "pre_tool_call" ? { fail_closed: true } : {} });
50307
50495
  return { pre_llm_call: entry("pre_llm_call"), pre_tool_call: entry("pre_tool_call") };
@@ -50337,7 +50525,7 @@ function assertHermesEnvironment(home) {
50337
50525
  throw new Error(`NATIVE_SKILL_DRIFT: Hermes ${variable} requires a dedicated discovery adapter; unset it before using this adapter`);
50338
50526
  }
50339
50527
  const selected = process.env.HERMES_HOME?.trim();
50340
- if (selected && (!isAbsolute3(selected) || resolve5(selected) !== join17(resolve5(home), ".hermes")))
50528
+ if (selected && (!isAbsolute4(selected) || resolve6(selected) !== join17(resolve6(home), ".hermes")))
50341
50529
  throw new Error("NATIVE_SKILL_DRIFT: custom Hermes homes/profiles require their own reviewed bridge");
50342
50530
  if (process.env.HERMES_ENABLE_PROJECT_PLUGINS?.trim() && !["0", "false", "no", "off"].includes(process.env.HERMES_ENABLE_PROJECT_PLUGINS.trim().toLowerCase()))
50343
50531
  throw new Error("NATIVE_SKILL_DRIFT: Hermes project plugins require a dedicated discovery review");
@@ -50360,7 +50548,7 @@ function assertHermesProtection(home, config, command, profile, supervisor) {
50360
50548
  assertHermesEnvironment(home);
50361
50549
  if (read(join17(home, ".hermes", HERMES_OPT_OUT)) === null)
50362
50550
  throw new Error("NATIVE_SKILL_DRIFT: Hermes bundled skill reseeding is not disabled; run skills hook install");
50363
- if (!supervisor || !isAbsolute3(supervisor.path) || supervisor.runtime !== process.execPath || read(supervisor.path) !== renderHermesSupervisor(command, profile))
50551
+ if (!supervisor || !isAbsolute4(supervisor.path) || supervisor.runtime !== process.execPath || read(supervisor.path) !== renderHermesSupervisor(command, profile))
50364
50552
  throw new Error("NATIVE_SKILL_DRIFT: Hermes owned supervisor changed; run skills hook install");
50365
50553
  const raw = read(join17(home, ".hermes/shell-hooks-allowlist.json"));
50366
50554
  let trust;
@@ -50386,7 +50574,7 @@ function assertHermesProtection(home, config, command, profile, supervisor) {
50386
50574
  }
50387
50575
  function assertNoHermesLegacyShadow(root) {
50388
50576
  let entries = 0;
50389
- for (let cursor = resolve5(root);; cursor = dirname5(cursor)) {
50577
+ for (let cursor = resolve6(root);; cursor = dirname5(cursor)) {
50390
50578
  if (lstatSync6(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
50391
50579
  throw new Error("NATIVE_SKILL_DRIFT: symlink Hermes legacy discovery root");
50392
50580
  if (dirname5(cursor) === cursor)
@@ -50490,13 +50678,13 @@ var init_agent_hermes = __esm(() => {
50490
50678
  // src/lib/agent-discovery-directories.ts
50491
50679
  import { createHash as createHash5 } from "crypto";
50492
50680
  import { lstatSync as lstatSync7, opendirSync as opendirSync2 } from "fs";
50493
- import { dirname as dirname6, isAbsolute as isAbsolute4, join as join18, resolve as resolve6 } from "path";
50681
+ import { dirname as dirname6, isAbsolute as isAbsolute5, join as join18, resolve as resolve7 } from "path";
50494
50682
  function need(value, message) {
50495
50683
  if (!value)
50496
50684
  throw new Error(message);
50497
50685
  }
50498
50686
  function safe(path) {
50499
- need(typeof path === "string" && path.length <= AGENT_POLICY_LIMITS.pathCharacters && isAbsolute4(path) && resolve6(path) === path && !path.includes("\x00"), "Expected a canonical absolute discovery directory path");
50687
+ need(typeof path === "string" && path.length <= AGENT_POLICY_LIMITS.pathCharacters && isAbsolute5(path) && resolve7(path) === path && !path.includes("\x00"), "Expected a canonical absolute discovery directory path");
50500
50688
  for (let cursor = path;; cursor = dirname6(cursor)) {
50501
50689
  need(!lstatSync7(cursor, { throwIfNoEntry: false })?.isSymbolicLink(), "Refusing symlink native discovery directory");
50502
50690
  if (dirname6(cursor) === cursor)
@@ -50564,12 +50752,12 @@ var init_agent_discovery_directories = __esm(() => {
50564
50752
  // src/lib/agent-discovery-bytes.ts
50565
50753
  import { createHash as createHash6 } from "crypto";
50566
50754
  import { closeSync as closeSync3, constants as constants4, fstatSync as fstatSync3, lstatSync as lstatSync8, openSync as openSync3, readSync as readSync3 } from "fs";
50567
- import { dirname as dirname7, isAbsolute as isAbsolute5, resolve as resolve7 } from "path";
50755
+ import { dirname as dirname7, isAbsolute as isAbsolute6, resolve as resolve8 } from "path";
50568
50756
  function discoveryByteBudget() {
50569
50757
  return { remaining: AGENT_POLICY_LIMITS.discoveryRawTotalBytes };
50570
50758
  }
50571
50759
  function safe2(path) {
50572
- if (typeof path !== "string" || !isAbsolute5(path) || path !== resolve7(path) || path.length > AGENT_POLICY_LIMITS.pathCharacters || path.includes("\x00"))
50760
+ if (typeof path !== "string" || !isAbsolute6(path) || path !== resolve8(path) || path.length > AGENT_POLICY_LIMITS.pathCharacters || path.includes("\x00"))
50573
50761
  throw new Error("Expected a canonical absolute raw discovery path");
50574
50762
  for (let cursor = path;; cursor = dirname7(cursor)) {
50575
50763
  if (lstatSync8(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
@@ -50635,7 +50823,7 @@ var init_agent_discovery_bytes = __esm(() => {
50635
50823
  // src/lib/agent-discovery-path-bytes.ts
50636
50824
  import { createHash as createHash7 } from "crypto";
50637
50825
  import { lstatSync as lstatSync9, readlinkSync } from "fs";
50638
- import { dirname as dirname8, isAbsolute as isAbsolute6, join as join19, parse as parse2, resolve as resolve8, sep as sep3 } from "path";
50826
+ import { dirname as dirname8, isAbsolute as isAbsolute7, join as join19, parse as parse2, resolve as resolve9, sep as sep3 } from "path";
50639
50827
  function identity3(stat, mutable = false) {
50640
50828
  return {
50641
50829
  dev: String(stat.dev),
@@ -50647,7 +50835,7 @@ function identity3(stat, mutable = false) {
50647
50835
  };
50648
50836
  }
50649
50837
  function canonical(path) {
50650
- if (typeof path !== "string" || !isAbsolute6(path) || path !== resolve8(path) || path.length > AGENT_POLICY_LIMITS.pathCharacters || path.includes("\x00") || Buffer.from(path).toString("utf8") !== path)
50838
+ if (typeof path !== "string" || !isAbsolute7(path) || path !== resolve9(path) || path.length > AGENT_POLICY_LIMITS.pathCharacters || path.includes("\x00") || Buffer.from(path).toString("utf8") !== path)
50651
50839
  throw new Error("Expected a canonical absolute discovery path");
50652
50840
  }
50653
50841
  function trace(path) {
@@ -50696,11 +50884,11 @@ function trace(path) {
50696
50884
  if (!target || target.includes("\x00") || Buffer.byteLength(target) > AGENT_POLICY_LIMITS.pathCharacters || !after2.isSymbolicLink() || JSON.stringify(identity3(stat, true)) !== JSON.stringify(identity3(after2, true)))
50697
50885
  throw new Error("Discovery link changed during read");
50698
50886
  record2(candidate, { type: "link", target, ...identity3(stat, true) });
50699
- if (isAbsolute6(target)) {
50887
+ if (isAbsolute7(target)) {
50700
50888
  cursor = parse2(target).root;
50701
50889
  root();
50702
50890
  }
50703
- const remainder = isAbsolute6(target) ? target.slice(parse2(target).root.length) : target;
50891
+ const remainder = isAbsolute7(target) ? target.slice(parse2(target).root.length) : target;
50704
50892
  pending = [...remainder.split(sep3), ...pending];
50705
50893
  if (pending.length + steps > AGENT_POLICY_LIMITS.discoveryPathSteps)
50706
50894
  throw new Error("Discovery path step limit exceeded");
@@ -50756,12 +50944,12 @@ import { spawnSync } from "child_process";
50756
50944
  import { closeSync as closeSync22, fstatSync as fstatSync22, openSync as openSync22, readFileSync as readFileSync22 } from "fs";
50757
50945
  import { O_NOFOLLOW as O_NOFOLLOW2, O_NONBLOCK as O_NONBLOCK2, O_RDONLY as O_RDONLY2 } from "constants";
50758
50946
  import { hostname as osHostname } from "os";
50759
- import { isAbsolute as isAbsolute7, join as join22 } from "path";
50947
+ import { isAbsolute as isAbsolute8, join as join22 } from "path";
50760
50948
  import { createRequire } from "module";
50761
50949
  import { fileURLToPath as fileURLToPath2 } from "url";
50762
50950
  import { closeSync as closeSync4, fstatSync as fstatSync4, lstatSync as lstatSync10, openSync as openSync4, readFileSync as readFileSync11, realpathSync as realpathSync3, statSync as statSync7 } from "fs";
50763
50951
  import { O_NOFOLLOW, O_NONBLOCK, O_RDONLY } from "constants";
50764
- import { basename as basename3, dirname as dirname9, join as join20, relative as relative4, sep as sep4 } from "path";
50952
+ import { basename as basename4, dirname as dirname9, join as join20, relative as relative4, sep as sep4 } from "path";
50765
50953
  import { fileURLToPath, pathToFileURL } from "url";
50766
50954
  function envToken(name) {
50767
50955
  return name.toUpperCase().replace(/-/g, "_");
@@ -50866,7 +51054,7 @@ function entryPoint(directory) {
50866
51054
  function resolveInstalledSecrets(parentUrl) {
50867
51055
  let directory = dirname9(fileURLToPath(parentUrl));
50868
51056
  for (;; ) {
50869
- if (basename3(directory) !== "node_modules") {
51057
+ if (basename4(directory) !== "node_modules") {
50870
51058
  const candidate = join20(directory, "node_modules", PACKAGE);
50871
51059
  let absent = false;
50872
51060
  try {
@@ -50891,7 +51079,7 @@ function homeDir(env3) {
50891
51079
  }
50892
51080
  function absoluteOverride(env3, key) {
50893
51081
  const value = env3[key]?.trim();
50894
- return value && isAbsolute7(value) ? value : null;
51082
+ return value && isAbsolute8(value) ? value : null;
50895
51083
  }
50896
51084
  function hasnaHomeDir(env3) {
50897
51085
  const override = absoluteOverride(env3, HASNA_HOME_ENV_KEY);
@@ -51709,6 +51897,7 @@ __export(exports_fleet_credentials, {
51709
51897
  SKILLS_API_URL_ENV: () => SKILLS_API_URL_ENV,
51710
51898
  SKILLS_API_KEY_ENV_KEYS: () => SKILLS_API_KEY_ENV_KEYS,
51711
51899
  SKILLS_API_KEY_ENV: () => SKILLS_API_KEY_ENV,
51900
+ REDACTED_VAULT_REFERENCE: () => REDACTED_VAULT_REFERENCE,
51712
51901
  MissingSkillsFleetError: () => MissingSkillsFleetError
51713
51902
  });
51714
51903
  function isCredentialResolutionError(error) {
@@ -51717,10 +51906,15 @@ function isCredentialResolutionError(error) {
51717
51906
  function isSkillsFleetCredentialError(error) {
51718
51907
  return error instanceof SkillsFleetCredentialError || typeof error === "object" && error !== null && error.name === "SkillsFleetCredentialError";
51719
51908
  }
51720
- function asSkillsFleetCredentialError(error) {
51909
+ function redactVaultReference(message, vaultReference) {
51910
+ if (!vaultReference)
51911
+ return message;
51912
+ return message.split(vaultReference).join(REDACTED_VAULT_REFERENCE);
51913
+ }
51914
+ function asSkillsFleetCredentialError(error, vaultReference) {
51721
51915
  if (!isCredentialResolutionError(error))
51722
51916
  return null;
51723
- return new SkillsFleetCredentialError(error.message, "MISSING_API_CREDENTIAL");
51917
+ return new SkillsFleetCredentialError(redactVaultReference(error.message, vaultReference), "MISSING_API_CREDENTIAL");
51724
51918
  }
51725
51919
  function normalizeSkillsApiOrigin(apiUrl) {
51726
51920
  const url = new URL(apiUrl);
@@ -51907,7 +52101,7 @@ async function resolveSkillsConnection(env3 = process.env, options = {}) {
51907
52101
  try {
51908
52102
  completed = await completePointerCredential(SKILLS_APP, pointer, env3);
51909
52103
  } catch (error) {
51910
- const translated = asSkillsFleetCredentialError(error);
52104
+ const translated = asSkillsFleetCredentialError(error, pointer.pointerVaultKey);
51911
52105
  if (translated)
51912
52106
  throw translated;
51913
52107
  throw error;
@@ -51963,7 +52157,7 @@ function requireSkillsFleet(action = "This command", env3 = process.env, options
51963
52157
  return fleet;
51964
52158
  throw new MissingSkillsFleetError(action);
51965
52159
  }
51966
- var SKILLS_APP = "skills", ENV_KEYS, SKILLS_API_URL_ENV_KEYS, SKILLS_API_KEY_ENV_KEYS, SKILLS_API_URL_ENV, SKILLS_API_KEY_ENV, SkillsFleetCredentialError, localNoticePrinted = false, MissingSkillsFleetError;
52160
+ var SKILLS_APP = "skills", ENV_KEYS, SKILLS_API_URL_ENV_KEYS, SKILLS_API_KEY_ENV_KEYS, SKILLS_API_URL_ENV, SKILLS_API_KEY_ENV, SkillsFleetCredentialError, REDACTED_VAULT_REFERENCE = "[redacted vault reference]", localNoticePrinted = false, MissingSkillsFleetError;
51967
52161
  var init_fleet_credentials = __esm(() => {
51968
52162
  init_transport();
51969
52163
  init_instance_credentials();
@@ -52909,11 +53103,18 @@ async function syncSelectionProfile(profileId, options = {}) {
52909
53103
  return { profile, receipt, changed, downloaded, stationReported };
52910
53104
  }
52911
53105
  async function resolveSelectionContext(profileId, options = {}) {
52912
- const session = options.sessionId ? readSkillSession(options.sessionId, options) : null;
52913
- const parentSession = !session && options.parentSessionId ? readSkillSession(options.parentSessionId, options) : null;
53106
+ const sessionState = options.sessionId ? readSkillSessionSnapshotIfExists(options.sessionId, options) : null;
53107
+ const session = sessionState?.receipt ?? null;
53108
+ const parentState = !session && options.parentSessionId ? readSkillSessionSnapshotIfExists(options.parentSessionId, options) : null;
53109
+ if (!session && options.parentSessionId && !parentState) {
53110
+ throw new SkillSelectionError("SESSION_PARENT_NOT_FOUND", "A child Skills session requires an existing parent receipt so its inherited pin can be bound exactly.");
53111
+ }
53112
+ const parentSession = parentState?.receipt ?? null;
53113
+ const sessionSnapshot = sessionState ? skillSessionSnapshotBinding(sessionState) : null;
53114
+ const parentSnapshot = parentState ? skillSessionSnapshotBinding(parentState) : undefined;
52914
53115
  const project = options.projectDir ? readProjectSelection(options.projectDir) : null;
52915
53116
  if (session && session.profile.profileId !== profileId || parentSession && parentSession.profile.profileId !== profileId || project && project.profile.profileId !== profileId) {
52916
- throw new SkillSelectionError("PROFILE_LOCK_MISMATCH", "The session or project is pinned to a different Skills profile. Select that profile or explicitly sync the new selection.");
53117
+ throw new SkillSelectionError("PROFILE_LOCK_MISMATCH", "The session or project is pinned to a different Skills profile. Select the pinned profile, or review skills sessions reconcile for an intentional session change and explicit project sync for a project change.");
52917
53118
  }
52918
53119
  if (options.cached) {
52919
53120
  const receipt2 = session ?? parentSession ?? project ?? readSelectionProfile(profileId, options);
@@ -52921,7 +53122,7 @@ async function resolveSelectionContext(profileId, options = {}) {
52921
53122
  throw new SkillSelectionError("CACHED_PROFILE_MISSING", "No verified Skills profile is cached; authenticate and sync it first.");
52922
53123
  assertFreshCachedProfile(receipt2, options);
52923
53124
  assertBinding(receipt2.profile, options);
52924
- return { receipt: receipt2, session, inheritedLoaded: parentSession?.loaded };
53125
+ return { receipt: receipt2, session, sessionSnapshot, parentSnapshot, inheritedLoaded: parentSession?.loaded };
52925
53126
  }
52926
53127
  const client = options.client ?? await createProfileClient();
52927
53128
  const current = await client.resolveProfile(profileId);
@@ -52934,7 +53135,7 @@ async function resolveSelectionContext(profileId, options = {}) {
52934
53135
  throw new SkillSelectionError("PROFILE_IDENTITY_MISMATCH", "The pinned selection belongs to another Skills authority or workspace.");
52935
53136
  }
52936
53137
  const receipt = locked ?? { schemaVersion: 1, verifiedAt: new Date((options.now ?? Date.now)()).toISOString(), profile: current };
52937
- return { receipt, session, client, inheritedLoaded: parentSession?.loaded };
53138
+ return { receipt, session, sessionSnapshot, parentSnapshot, client, inheritedLoaded: parentSession?.loaded };
52938
53139
  }
52939
53140
  function assertBinding(profile, options) {
52940
53141
  if (options.authority !== undefined && profile.authority !== options.authority || options.workspaceId !== undefined && profile.workspaceId !== options.workspaceId) {
@@ -52973,7 +53174,7 @@ async function loadSelectedSkill(spec, profileId, options = {}) {
52973
53174
  sessionId: options.sessionId,
52974
53175
  loaded: [...new Set([...context.session?.loaded ?? [], selectionKey(selection)])]
52975
53176
  };
52976
- writeSelectionJson(sessionReceiptPath(options.sessionId, options), session);
53177
+ writeSkillSession(session, { current: context.sessionSnapshot, parent: context.parentSnapshot }, options);
52977
53178
  }
52978
53179
  return { content, selection, receipt };
52979
53180
  }
@@ -53214,8 +53415,8 @@ var init_plugin_projection = __esm(() => {
53214
53415
 
53215
53416
  // src/lib/plugin-projection-store.ts
53216
53417
  import { createHash as createHash10, randomUUID as randomUUID5 } from "crypto";
53217
- import { constants as constants7, closeSync as closeSync7, fchmodSync, fstatSync as fstatSync7, fsyncSync, linkSync, lstatSync as lstatSync13, mkdirSync as mkdirSync6, openSync as openSync7, opendirSync as opendirSync3, readSync as readSync5, renameSync as renameSync3, rmdirSync as rmdirSync2, rmSync as rmSync2, unlinkSync as unlinkSync3, writeSync as writeSync2 } from "fs";
53218
- import { dirname as dirname10, isAbsolute as isAbsolute8, join as join25, parse as parse4, resolve as resolve9 } from "path";
53418
+ import { constants as constants7, closeSync as closeSync7, fchmodSync, fstatSync as fstatSync7, fsyncSync as fsyncSync2, linkSync, lstatSync as lstatSync13, mkdirSync as mkdirSync6, openSync as openSync7, opendirSync as opendirSync3, readSync as readSync5, renameSync as renameSync3, rmdirSync as rmdirSync2, rmSync as rmSync2, unlinkSync as unlinkSync3, writeSync as writeSync2 } from "fs";
53419
+ import { dirname as dirname10, isAbsolute as isAbsolute9, join as join25, parse as parse4, resolve as resolve10 } from "path";
53219
53420
  function stat(path) {
53220
53421
  try {
53221
53422
  return lstatSync13(path, { bigint: true });
@@ -53226,7 +53427,7 @@ function stat(path) {
53226
53427
  }
53227
53428
  }
53228
53429
  function canonical2(path) {
53229
- pluginNeed(typeof path === "string" && path.length <= 8192 && isAbsolute8(path) && resolve9(path) === path && !/[\x00-\x1f\x7f]/.test(path), "Plugin storage paths must be canonical absolute paths");
53430
+ pluginNeed(typeof path === "string" && path.length <= 8192 && isAbsolute9(path) && resolve10(path) === path && !/[\x00-\x1f\x7f]/.test(path), "Plugin storage paths must be canonical absolute paths");
53230
53431
  }
53231
53432
  function owner(stats, system = false) {
53232
53433
  const current = uid();
@@ -53435,7 +53636,7 @@ function writeExclusive(path, bytes, mode) {
53435
53636
  pluginNeed(count > 0, "Plugin file write did not progress");
53436
53637
  offset += count;
53437
53638
  }
53438
- fsyncSync(fd);
53639
+ fsyncSync2(fd);
53439
53640
  } catch (error) {
53440
53641
  if (created) {
53441
53642
  same3(created, stat(path), true);
@@ -53608,7 +53809,7 @@ var init_selected_manifest = __esm(() => {
53608
53809
 
53609
53810
  // src/lib/plugin-admission.ts
53610
53811
  import { homedir as homedir3 } from "os";
53611
- import { isAbsolute as isAbsolute9, join as join26, resolve as resolve10 } from "path";
53812
+ import { isAbsolute as isAbsolute10, join as join26, resolve as resolve11 } from "path";
53612
53813
  function pluginAdmissionRoot() {
53613
53814
  return join26(homedir3(), ".hasna", "skills", "plugin-admission");
53614
53815
  }
@@ -53621,7 +53822,7 @@ function validatePluginTarget(value) {
53621
53822
  for (const registration of value.registrations) {
53622
53823
  pluginKeys(registration, ["scope", "projectPath"]);
53623
53824
  pluginNeed(registration.scope === "user" || registration.scope === "project", "Unsupported plugin registration scope");
53624
- pluginNeed(registration.scope === "user" ? registration.projectPath === null : typeof registration.projectPath === "string" && isAbsolute9(registration.projectPath) && resolve10(registration.projectPath) === registration.projectPath, "Plugin scope requires its exact project path");
53825
+ pluginNeed(registration.scope === "user" ? registration.projectPath === null : typeof registration.projectPath === "string" && isAbsolute10(registration.projectPath) && resolve11(registration.projectPath) === registration.projectPath, "Plugin scope requires its exact project path");
53625
53826
  const key = JSON.stringify([registration.scope, registration.projectPath]);
53626
53827
  pluginNeed(!scopes.has(key), "Duplicate plugin registration scope");
53627
53828
  scopes.add(key);
@@ -53629,7 +53830,7 @@ function validatePluginTarget(value) {
53629
53830
  for (const key of ["native", "resolver"]) {
53630
53831
  pluginKeys(value[key], key === "native" ? ["version", "executable", "digest"] : ["executable", "digest"]);
53631
53832
  pluginText(value[key].executable);
53632
- pluginNeed(isAbsolute9(value[key].executable) && resolve10(value[key].executable) === value[key].executable, "Plugin executable must have a canonical absolute path");
53833
+ pluginNeed(isAbsolute10(value[key].executable) && resolve11(value[key].executable) === value[key].executable, "Plugin executable must have a canonical absolute path");
53633
53834
  pluginDigest(value[key].digest);
53634
53835
  }
53635
53836
  pluginNeed(["2.1.274", "2.1.276"].includes(value.native.version), "Plugin admission requires a certified Claude command-source runtime (2.1.274 or 2.1.276)");
@@ -53779,7 +53980,7 @@ function pluginResolverCommand(binding) {
53779
53980
  }
53780
53981
  function root(options) {
53781
53982
  const path = options.storeRoot ?? pluginAdmissionRoot();
53782
- pluginNeed(isAbsolute9(path) && resolve10(path) === path, "Invalid plugin admission store root");
53983
+ pluginNeed(isAbsolute10(path) && resolve11(path) === path, "Invalid plugin admission store root");
53783
53984
  return path;
53784
53985
  }
53785
53986
  function pluginBindingPath(storeRoot, id) {
@@ -53987,7 +54188,7 @@ var init_plugin_admission = __esm(() => {
53987
54188
 
53988
54189
  // src/lib/plugin-discovery.ts
53989
54190
  import { closeSync as closeSync8, constants as constants8, fstatSync as fstatSync8, lstatSync as lstatSync14, openSync as openSync8, opendirSync as opendirSync4, readSync as readSync6 } from "fs";
53990
- import { basename as basename4, dirname as dirname11, isAbsolute as isAbsolute10, join as join27, resolve as resolve11 } from "path";
54191
+ import { basename as basename5, dirname as dirname11, isAbsolute as isAbsolute11, join as join27, resolve as resolve12 } from "path";
53991
54192
  function validateManagedPluginWitnesses(value) {
53992
54193
  pluginNeed(Array.isArray(value) && value.length > 0 && value.length <= PLUGIN_PROJECTION_LIMITS.registrations, "Invalid managed plugin witness collection");
53993
54194
  const seen = new Set;
@@ -53996,12 +54197,12 @@ function validateManagedPluginWitnesses(value) {
53996
54197
  pluginNeed(typeof item.bindingId === "string" && /^[a-f0-9]{64}$/.test(item.bindingId) && !seen.has(item.bindingId), "Invalid or duplicate managed plugin witness");
53997
54198
  seen.add(item.bindingId);
53998
54199
  pluginText(item.storeRoot);
53999
- pluginNeed(isAbsolute10(item.storeRoot) && resolve11(item.storeRoot) === item.storeRoot, "Invalid plugin receipt store path");
54200
+ pluginNeed(isAbsolute11(item.storeRoot) && resolve12(item.storeRoot) === item.storeRoot, "Invalid plugin receipt store path");
54000
54201
  }
54001
54202
  }
54002
54203
  function safe3(path) {
54003
54204
  pluginText(path);
54004
- pluginNeed(isAbsolute10(path) && resolve11(path) === path, "Invalid plugin registry path");
54205
+ pluginNeed(isAbsolute11(path) && resolve12(path) === path, "Invalid plugin registry path");
54005
54206
  for (let at2 = path;; at2 = dirname11(at2)) {
54006
54207
  pluginNeed(!lstatSync14(at2, { throwIfNoEntry: false })?.isSymbolicLink(), "Plugin registry path traverses a symlink");
54007
54208
  if (at2 === dirname11(at2))
@@ -54070,7 +54271,7 @@ function hashManagedPluginRegistry(path, managed) {
54070
54271
  pluginNeed(/^(?:[A-Za-z0-9][A-Za-z0-9._+-]*-)?[a-f0-9]{12}$/.test(row.version) && row.installPath === join27(cacheRoot, row.version), "Managed plugin cache path or version is outside its registration");
54071
54272
  const approval = (producer) => {
54072
54273
  pluginText(producer);
54073
- const digest = `sha256:${basename4(producer)}`;
54274
+ const digest = `sha256:${basename5(producer)}`;
54074
54275
  const receipt2 = readPluginAdmissionReceipt(witness.storeRoot, witness.bindingId, digest);
54075
54276
  pluginNeed(receipt2.materializedPath === producer, "Managed producer path is not an approved immutable projection");
54076
54277
  if (!verified.has(producer)) {
@@ -54133,10 +54334,181 @@ var init_plugin_discovery = __esm(() => {
54133
54334
  init_plugin_projection_store();
54134
54335
  });
54135
54336
 
54136
- // src/lib/agent-discovery.ts
54337
+ // src/lib/claude-marketplace-registry.ts
54137
54338
  import { createHash as createHash11 } from "crypto";
54138
- import { lstatSync as lstatSync15, readFileSync as readFileSync14, readdirSync as readdirSync9, realpathSync as realpathSync4 } from "fs";
54139
- import { dirname as dirname12, isAbsolute as isAbsolute11, join as join28, resolve as resolve12, sep as sep5 } from "path";
54339
+ import { closeSync as closeSync9, constants as constants9, fstatSync as fstatSync9, lstatSync as lstatSync15, openSync as openSync9, readSync as readSync7 } from "fs";
54340
+ import { basename as basename6, dirname as dirname12, isAbsolute as isAbsolute12, resolve as resolve13 } from "path";
54341
+ function need2(value, reason) {
54342
+ if (!value)
54343
+ throw new Error(`Claude marketplace registry ${reason}`);
54344
+ }
54345
+ function absolutePath(value) {
54346
+ need2(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute12(value) && resolve13(value) === value, "requires a normalized absolute path");
54347
+ }
54348
+ function parents(path) {
54349
+ const result2 = [];
54350
+ for (let at2 = dirname12(path);; at2 = dirname12(at2)) {
54351
+ const stat2 = lstatSync15(at2, { bigint: true });
54352
+ need2(stat2.isDirectory() && !stat2.isSymbolicLink(), "path traverses a symlink or non-directory");
54353
+ result2.push([at2, stat2]);
54354
+ if (at2 === dirname12(at2))
54355
+ return result2;
54356
+ }
54357
+ }
54358
+ function readRegistry2(path, budget) {
54359
+ absolutePath(path);
54360
+ need2(basename6(path) === "known_marketplaces.json", "requires known_marketplaces.json");
54361
+ need2(Number.isSafeInteger(budget.remaining) && budget.remaining >= 0, "has an invalid byte budget");
54362
+ const ancestors2 = parents(path), initial2 = lstatSync15(path, { bigint: true });
54363
+ need2(initial2.isFile() && !initial2.isSymbolicLink() && initial2.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
54364
+ need2(initial2.size <= BigInt(budget.remaining), "exceeds its aggregate byte limit");
54365
+ const fd = openSync9(path, constants9.O_RDONLY | constants9.O_NOFOLLOW | constants9.O_NONBLOCK);
54366
+ try {
54367
+ const opened = fstatSync9(fd, { bigint: true });
54368
+ need2(opened.isFile() && sameFile(initial2, opened), "changed during open");
54369
+ const bytes = Buffer.alloc(Number(opened.size) + 1);
54370
+ let length = 0;
54371
+ while (length < bytes.length) {
54372
+ const count = readSync7(fd, bytes, length, bytes.length - length, null);
54373
+ if (!count)
54374
+ break;
54375
+ length += count;
54376
+ }
54377
+ const after2 = fstatSync9(fd, { bigint: true }), current = lstatSync15(path, { bigint: true });
54378
+ need2(current.isFile() && sameFile(opened, after2) && sameFile(after2, current) && BigInt(length) === opened.size, "changed during read");
54379
+ for (const [ancestor, before2] of ancestors2) {
54380
+ const now3 = lstatSync15(ancestor, { bigint: true });
54381
+ need2(now3.isDirectory() && before2.dev === now3.dev && before2.ino === now3.ino && before2.mode === now3.mode, "parent changed during read");
54382
+ }
54383
+ budget.remaining -= length;
54384
+ try {
54385
+ return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes.subarray(0, length));
54386
+ } catch {
54387
+ throw new Error("Claude marketplace registry is not strict UTF-8");
54388
+ }
54389
+ } finally {
54390
+ closeSync9(fd);
54391
+ }
54392
+ }
54393
+ function parse5(text2) {
54394
+ let at2 = 0, nodes = 0;
54395
+ const numberPattern = /-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?/y;
54396
+ const space = () => {
54397
+ while (at2 < text2.length && /[\x20\t\r\n]/.test(text2[at2]))
54398
+ at2++;
54399
+ };
54400
+ function string() {
54401
+ need2(text2[at2] === '"', "contains invalid JSON");
54402
+ const start = at2++;
54403
+ while (at2 < text2.length) {
54404
+ const character = text2[at2++];
54405
+ if (character === '"') {
54406
+ let value2;
54407
+ try {
54408
+ value2 = JSON.parse(text2.slice(start, at2));
54409
+ } catch {
54410
+ throw new Error("Claude marketplace registry contains invalid JSON string");
54411
+ }
54412
+ need2(value2.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.stringCharacters, "exceeds its string limit");
54413
+ return value2;
54414
+ }
54415
+ if (character === "\\")
54416
+ at2++;
54417
+ }
54418
+ throw new Error("Claude marketplace registry contains an unterminated JSON string");
54419
+ }
54420
+ function value(depth) {
54421
+ need2(depth <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.depth && ++nodes <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.nodes, "exceeds its nesting or node limit");
54422
+ space();
54423
+ const character = text2[at2];
54424
+ if (character === '"')
54425
+ return { kind: "string", value: string() };
54426
+ if (character === "{" || character === "[") {
54427
+ at2++;
54428
+ space();
54429
+ const object4 = character === "{", end = object4 ? "}" : "]", entries = [], items = [], keys2 = new Set;
54430
+ if (text2[at2] !== end)
54431
+ while (true) {
54432
+ if (object4) {
54433
+ space();
54434
+ const key = string();
54435
+ need2(!keys2.has(key), "contains a duplicate JSON key");
54436
+ keys2.add(key);
54437
+ space();
54438
+ need2(text2[at2++] === ":", "contains invalid JSON");
54439
+ entries.push([key, value(depth + 1)]);
54440
+ } else
54441
+ items.push(value(depth + 1));
54442
+ space();
54443
+ if (text2[at2] === end)
54444
+ break;
54445
+ need2(text2[at2++] === ",", "contains invalid JSON");
54446
+ }
54447
+ at2++;
54448
+ return object4 ? { kind: "object", entries } : { kind: "array", items };
54449
+ }
54450
+ for (const literal of ["true", "false", "null"])
54451
+ if (text2.startsWith(literal, at2)) {
54452
+ at2 += literal.length;
54453
+ return { kind: "literal", value: literal };
54454
+ }
54455
+ numberPattern.lastIndex = at2;
54456
+ const number = numberPattern.exec(text2);
54457
+ need2(number, "contains invalid JSON");
54458
+ at2 += number[0].length;
54459
+ return { kind: "number", value: number[0] };
54460
+ }
54461
+ const root2 = value(0);
54462
+ space();
54463
+ need2(at2 === text2.length && root2.kind === "object", "requires a JSON object without trailing content");
54464
+ need2(root2.entries.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.rows, "exceeds its marketplace row limit");
54465
+ return root2;
54466
+ }
54467
+ function exactKeys(value, keys2) {
54468
+ return value?.kind === "object" && value.entries.length === keys2.length && value.entries.every(([key]) => keys2.includes(key));
54469
+ }
54470
+ function textField(value) {
54471
+ need2(value?.kind === "string" && value.value.length > 0 && !/[\x00-\x1f\x7f]/.test(value.value), "contains an invalid recognized field");
54472
+ return value.value;
54473
+ }
54474
+ function normalizeRow(row) {
54475
+ if (!exactKeys(row, ["source", "installLocation", "lastUpdated"]))
54476
+ return;
54477
+ const source = field(row, "source");
54478
+ if (source?.kind !== "object")
54479
+ return;
54480
+ const type = field(source, "source");
54481
+ if (type?.kind !== "string" || !["github", "directory"].includes(type.value))
54482
+ return;
54483
+ const location = type.value === "github" ? "repo" : "path";
54484
+ if (!exactKeys(source, ["source", location]))
54485
+ return;
54486
+ const sourceLocation = textField(field(source, location));
54487
+ if (type.value === "directory")
54488
+ absolutePath(sourceLocation);
54489
+ absolutePath(textField(field(row, "installLocation")));
54490
+ const updated = textField(field(row, "lastUpdated"));
54491
+ need2(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(updated), "contains an invalid recognized update timestamp");
54492
+ const millis = Date.parse(updated);
54493
+ need2(Number.isFinite(millis) && new Date(millis).toISOString() === updated, "contains an invalid recognized update timestamp");
54494
+ row.entries = row.entries.map(([key, value]) => [key, key === "lastUpdated" ? { kind: "validated-update-time" } : value]);
54495
+ }
54496
+ function captureClaudeMarketplaceRegistry(path, budget = { remaining: 256 * 1024 * 1024 }) {
54497
+ const value = parse5(readRegistry2(path, budget));
54498
+ for (const [, row] of value.entries)
54499
+ normalizeRow(row);
54500
+ const sha2562 = createHash11("sha256").update("hasna.skills.claude-marketplace-registry.v1\x00").update(JSON.stringify(value)).digest("hex");
54501
+ return { path, hashMode: "claude-marketplace-registry", sha256: sha2562 };
54502
+ }
54503
+ var CLAUDE_MARKETPLACE_REGISTRY_LIMITS, sameFile = (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, field = (object4, key) => object4.entries.find(([name]) => name === key)?.[1];
54504
+ var init_claude_marketplace_registry = __esm(() => {
54505
+ CLAUDE_MARKETPLACE_REGISTRY_LIMITS = Object.freeze({ bytes: 1024 * 1024, rows: 1024, depth: 32, nodes: 65536, stringCharacters: 16384, pathCharacters: 4096 });
54506
+ });
54507
+
54508
+ // src/lib/agent-discovery.ts
54509
+ import { createHash as createHash12 } from "crypto";
54510
+ import { lstatSync as lstatSync16, readFileSync as readFileSync14, readdirSync as readdirSync9, realpathSync as realpathSync4 } from "fs";
54511
+ import { dirname as dirname13, isAbsolute as isAbsolute13, join as join28, resolve as resolve14, sep as sep5 } from "path";
54140
54512
  function parseConfig(text2, path, toml = false) {
54141
54513
  try {
54142
54514
  const value = toml ? Bun.TOML.parse(text2) : JSON.parse(text2);
@@ -54148,12 +54520,12 @@ function parseConfig(text2, path, toml = false) {
54148
54520
  }
54149
54521
  }
54150
54522
  function safe4(path) {
54151
- if (!isAbsolute11(path) || path.includes("\x00"))
54523
+ if (!isAbsolute13(path) || path.includes("\x00"))
54152
54524
  throw new Error("Expected an absolute native discovery path");
54153
- for (let cursor = path;; cursor = dirname12(cursor)) {
54154
- if (lstatSync15(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
54525
+ for (let cursor = path;; cursor = dirname13(cursor)) {
54526
+ if (lstatSync16(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
54155
54527
  throw new Error(`Refusing symlink native discovery input: ${cursor}`);
54156
- if (dirname12(cursor) === cursor)
54528
+ if (dirname13(cursor) === cursor)
54157
54529
  break;
54158
54530
  }
54159
54531
  }
@@ -54161,7 +54533,7 @@ function read2(path, changes) {
54161
54533
  safe4(path);
54162
54534
  if (changes?.has(path))
54163
54535
  return changes.get(path);
54164
- const stat2 = lstatSync15(path, { throwIfNoEntry: false });
54536
+ const stat2 = lstatSync16(path, { throwIfNoEntry: false });
54165
54537
  if (!stat2)
54166
54538
  return null;
54167
54539
  if (!stat2.isFile() || stat2.size > 16 * 1024 * 1024)
@@ -54169,6 +54541,14 @@ function read2(path, changes) {
54169
54541
  return readFileSync14(path, "utf8");
54170
54542
  }
54171
54543
  function projected(source, changes, budget = discoveryByteBudget()) {
54544
+ if (source.hashMode === "claude-marketplace-registry") {
54545
+ 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))
54546
+ throw new Error("Claude marketplace witnesses require an exact reviewed registry without synthetic changes");
54547
+ const sha2562 = captureClaudeMarketplaceRegistry(source.path, budget).sha256;
54548
+ if (sha2562 !== source.sha256)
54549
+ throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
54550
+ return sha2562;
54551
+ }
54172
54552
  if (source.hashMode === "claude-plugin-registry") {
54173
54553
  if (source.format !== undefined || source.fields !== undefined || !source.managedPlugins || changes?.has(source.path))
54174
54554
  throw new Error("Managed plugin registry witnesses require verified native registrations");
@@ -54193,7 +54573,7 @@ function projected(source, changes, budget = discoveryByteBudget()) {
54193
54573
  const object4 = source.format === "yaml" ? parseHermesConfig(text2) : parseConfig(text2, source.path, source.format === "toml");
54194
54574
  if (!object4 || typeof object4 !== "object" || Array.isArray(object4))
54195
54575
  throw new Error("Expected native discovery configuration object");
54196
- return digest(JSON.stringify(Object.fromEntries((source.fields ?? []).map((field) => [field, object4[field] ?? null]))));
54576
+ return digest(JSON.stringify(Object.fromEntries((source.fields ?? []).map((field2) => [field2, object4[field2] ?? null]))));
54197
54577
  }
54198
54578
  function verifyAgentDiscovery(binding) {
54199
54579
  if (!binding || !Array.isArray(binding.sources) || !Array.isArray(binding.roots) || binding.sources.length > AGENT_POLICY_LIMITS.discoverySources || binding.roots.length > AGENT_POLICY_LIMITS.discoveryRoots)
@@ -54204,9 +54584,10 @@ function verifyAgentDiscovery(binding) {
54204
54584
  verifyDiscoveryDirectories(binding.directories);
54205
54585
  const budget = discoveryByteBudget();
54206
54586
  for (const source of binding.sources) {
54587
+ assertMarketplaceBinding(binding, source);
54207
54588
  if (source.hashMode === "claude-plugin-registry" && binding.agent !== "claude")
54208
54589
  throw new Error("Managed Claude registry witnesses cannot apply to another agent");
54209
- if (source.format !== undefined && (!["json", "toml", "yaml"].includes(source.format) || !Array.isArray(source.fields) || !source.fields.length || source.fields.length > 64 || source.fields.some((field) => typeof field !== "string" || !field)))
54590
+ if (source.format !== undefined && (!["json", "toml", "yaml"].includes(source.format) || !Array.isArray(source.fields) || !source.fields.length || source.fields.length > 64 || source.fields.some((field2) => typeof field2 !== "string" || !field2)))
54210
54591
  throw new Error("Invalid native discovery projection");
54211
54592
  if (source.sha256 !== null && !/^[a-f0-9]{64}$/.test(source.sha256))
54212
54593
  throw new Error("Invalid native discovery digest");
@@ -54216,13 +54597,20 @@ function verifyAgentDiscovery(binding) {
54216
54597
  for (const root2 of binding.roots)
54217
54598
  safe4(root2);
54218
54599
  }
54600
+ function assertMarketplaceBinding(binding, source) {
54601
+ if (source.hashMode === "claude-marketplace-registry" && (binding.agent !== "claude" || binding.method !== "reviewed"))
54602
+ throw new Error("Claude marketplace witnesses require explicit reviewed Claude discovery");
54603
+ }
54219
54604
  function rebindAgentDiscovery(binding, changes) {
54220
54605
  const budget = discoveryByteBudget();
54221
- return { ...binding, sources: binding.sources.map((source) => ({ ...source, sha256: projected(source, changes, budget) })) };
54606
+ return { ...binding, sources: binding.sources.map((source) => {
54607
+ assertMarketplaceBinding(binding, source);
54608
+ return { ...source, sha256: projected(source, changes, budget) };
54609
+ }) };
54222
54610
  }
54223
- function assertProjectDiscovery(agent, directories, home, canonical3 = resolve12, reviewed) {
54611
+ function assertProjectDiscovery(agent, directories, home, canonical3 = resolve14, reviewed) {
54224
54612
  for (const directory of directories) {
54225
- const isHome = resolve12(directory) === resolve12(home);
54613
+ const isHome = resolve14(directory) === resolve14(home);
54226
54614
  if (agent === "hermes") {
54227
54615
  assertHermesEnvironment(home);
54228
54616
  continue;
@@ -54253,13 +54641,13 @@ function assertProjectDiscovery(agent, directories, home, canonical3 = resolve12
54253
54641
  if (agent === "claude") {
54254
54642
  const commands = canonical3(join28(directory, ".claude/commands"));
54255
54643
  safe4(commands);
54256
- if (lstatSync15(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync9(commands).length)
54644
+ if (lstatSync16(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync9(commands).length)
54257
54645
  throw new Error("NATIVE_SKILL_DRIFT: legacy project command discovery requires a dedicated format adapter");
54258
54646
  }
54259
54647
  }
54260
54648
  }
54261
54649
  function resolveAgentDiscovery(options) {
54262
- const canonical3 = options.canonical ?? resolve12, home = resolve12(options.home), agent = options.agent;
54650
+ const canonical3 = options.canonical ?? resolve14, home = resolve14(options.home), agent = options.agent;
54263
54651
  const sources = [], roots = new Set, builtinNames = [];
54264
54652
  const witness = (path, format, fields) => {
54265
54653
  const source = { path: canonical3(path), sha256: null, ...format ? { format, fields } : {} };
@@ -54290,7 +54678,7 @@ function resolveAgentDiscovery(options) {
54290
54678
  continue;
54291
54679
  if (normalized.startsWith("~") && normalized !== "~" && !normalized.startsWith("~/"))
54292
54680
  unresolved("user-specific tilde expansion requires a separate discovery adapter");
54293
- const path = normalized === "~" ? home : normalized.startsWith("~/") ? join28(home, normalized.slice(2)) : resolve12(home, ".hermes", normalized);
54681
+ const path = normalized === "~" ? home : normalized.startsWith("~/") ? join28(home, normalized.slice(2)) : resolve14(home, ".hermes", normalized);
54294
54682
  safe4(path);
54295
54683
  roots.add(path);
54296
54684
  }
@@ -54299,21 +54687,21 @@ function resolveAgentDiscovery(options) {
54299
54687
  const executable = Bun.which("gemini");
54300
54688
  if (executable) {
54301
54689
  let packageRoot;
54302
- for (let directory = dirname12(realpathSync4(executable)), depth = 0;depth < 8; directory = dirname12(directory), depth++) {
54690
+ for (let directory = dirname13(realpathSync4(executable)), depth = 0;depth < 8; directory = dirname13(directory), depth++) {
54303
54691
  const path = join28(directory, "package.json"), raw = read2(path);
54304
54692
  if (raw !== null && parseConfig(raw, path).name === "@google/gemini-cli") {
54305
54693
  packageRoot = directory;
54306
54694
  witness(path);
54307
54695
  break;
54308
54696
  }
54309
- if (dirname12(directory) === directory)
54697
+ if (dirname13(directory) === directory)
54310
54698
  break;
54311
54699
  }
54312
54700
  if (!packageRoot)
54313
54701
  unresolved("installed Gemini package layout is not recognized");
54314
54702
  const builtinRoot = join28(packageRoot, "bundle/builtin");
54315
54703
  safe4(builtinRoot);
54316
- if (!lstatSync15(builtinRoot, { throwIfNoEntry: false })?.isDirectory())
54704
+ if (!lstatSync16(builtinRoot, { throwIfNoEntry: false })?.isDirectory())
54317
54705
  unresolved("installed Gemini builtin root is missing");
54318
54706
  for (const name of readdirSync9(builtinRoot).sort()) {
54319
54707
  const text2 = witness(join28(builtinRoot, name, "SKILL.md"));
@@ -54351,7 +54739,7 @@ function resolveAgentDiscovery(options) {
54351
54739
  unresolved("plugin hooks require a separate no-skill-injection review");
54352
54740
  const commands = join28(root2, "commands");
54353
54741
  safe4(commands);
54354
- if (agent === "claude" && (manifest.commands !== undefined || lstatSync15(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync9(commands).length))
54742
+ if (agent === "claude" && (manifest.commands !== undefined || lstatSync16(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync9(commands).length))
54355
54743
  unresolved("legacy command discovery requires retirement or a dedicated format adapter");
54356
54744
  const rootSkill = witness(join28(root2, "SKILL.md"));
54357
54745
  if (rootSkill !== null)
@@ -54362,10 +54750,10 @@ function resolveAgentDiscovery(options) {
54362
54750
  if (agent === "claude")
54363
54751
  roots.add(join28(root2, "skills"));
54364
54752
  for (const value of declared) {
54365
- const path = resolve12(root2, value);
54753
+ const path = resolve14(root2, value);
54366
54754
  if (path !== root2 && !path.startsWith(root2 + sep5))
54367
54755
  unresolved("plugin skill path escapes its root");
54368
- roots.add(path.endsWith(`${sep5}SKILL.md`) ? dirname12(path) : path);
54756
+ roots.add(path.endsWith(`${sep5}SKILL.md`) ? dirname13(path) : path);
54369
54757
  }
54370
54758
  }
54371
54759
  if (agent === "claude") {
@@ -54373,7 +54761,7 @@ function resolveAgentDiscovery(options) {
54373
54761
  const installed = registrations === null ? {} : parseConfig(registrations, join28(home, ".claude/plugins/installed_plugins.json")).plugins;
54374
54762
  const commands = canonical3(join28(home, ".claude/commands"));
54375
54763
  safe4(commands);
54376
- if (lstatSync15(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync9(commands).length)
54764
+ if (lstatSync16(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync9(commands).length)
54377
54765
  unresolved("legacy home command discovery requires a dedicated format adapter");
54378
54766
  for (const [id, enabled] of Object.entries(config.enabledPlugins ?? {})) {
54379
54767
  if (enabled === false)
@@ -54393,7 +54781,7 @@ function resolveAgentDiscovery(options) {
54393
54781
  unresolved("unsupported plugin enablement");
54394
54782
  const split2 = id.lastIndexOf("@"), name = id.slice(0, split2), marketplace = id.slice(split2 + 1);
54395
54783
  const market = config.marketplaces?.[marketplace] ?? (marketplace === "personal" ? { source_type: "local", source: home } : undefined);
54396
- if (split2 < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !isAbsolute11(market.source))
54784
+ if (split2 < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !isAbsolute13(market.source))
54397
54785
  unresolved("enabled plugin marketplace is not an explicit local source");
54398
54786
  const catalogText = witness(join28(market.source, ".agents/plugins/marketplace.json"));
54399
54787
  if (catalogText === null)
@@ -54401,7 +54789,7 @@ function resolveAgentDiscovery(options) {
54401
54789
  const catalog = parseConfig(catalogText, join28(market.source, ".agents/plugins/marketplace.json")), matches2 = Array.isArray(catalog.plugins) ? catalog.plugins.filter((item) => item.name === name) : [];
54402
54790
  if (matches2.length !== 1 || matches2[0]?.source?.source !== "local" || typeof matches2[0]?.source?.path !== "string")
54403
54791
  unresolved("plugin catalog source is missing or ambiguous");
54404
- plugin(resolve12(market.source, matches2[0].source.path));
54792
+ plugin(resolve14(market.source, matches2[0].source.path));
54405
54793
  }
54406
54794
  } else if (agent === "opencode") {
54407
54795
  if (witness(join28(home, ".config/opencode/opencode.jsonc")) !== null || witness(join28(home, ".config/opencode/config.json")) !== null)
@@ -54409,18 +54797,18 @@ function resolveAgentDiscovery(options) {
54409
54797
  if ((config.plugin?.length ?? 0) > 0 || config.skills?.urls?.length)
54410
54798
  unresolved("external plugin or remote skill source");
54411
54799
  for (const path of config.skills?.paths ?? []) {
54412
- if (typeof path !== "string" || !isAbsolute11(path))
54800
+ if (typeof path !== "string" || !isAbsolute13(path))
54413
54801
  unresolved("relative or malformed added skill root");
54414
54802
  roots.add(path);
54415
54803
  }
54416
54804
  const localPlugins = join28(home, ".config/opencode/plugins");
54417
54805
  safe4(localPlugins);
54418
- if (lstatSync15(localPlugins, { throwIfNoEntry: false }) && readdirSync9(localPlugins).some((name) => name !== "skills-cli.js"))
54806
+ if (lstatSync16(localPlugins, { throwIfNoEntry: false }) && readdirSync9(localPlugins).some((name) => name !== "skills-cli.js"))
54419
54807
  unresolved("additional local plugin hooks require review");
54420
54808
  } else if (agent === "hermes") {
54421
54809
  for (const directory of [join28(home, ".hermes/plugins"), join28(home, ".hermes/hermes-agent")]) {
54422
54810
  safe4(directory);
54423
- if (lstatSync15(directory, { throwIfNoEntry: false }))
54811
+ if (lstatSync16(directory, { throwIfNoEntry: false }))
54424
54812
  unresolved("installed runtime/plugin discovery requires reviewed source bindings");
54425
54813
  }
54426
54814
  if (Bun.which("hermes") || Object.keys(config.plugins ?? {}).length)
@@ -54430,11 +54818,11 @@ function resolveAgentDiscovery(options) {
54430
54818
  unresolved("custom extension or skill paths");
54431
54819
  const directory = join28(home, ".gemini/extensions");
54432
54820
  safe4(directory);
54433
- if (lstatSync15(directory, { throwIfNoEntry: false }))
54821
+ if (lstatSync16(directory, { throwIfNoEntry: false }))
54434
54822
  for (const name of readdirSync9(directory)) {
54435
54823
  const root2 = join28(directory, name);
54436
54824
  safe4(root2);
54437
- if (!lstatSync15(root2)?.isDirectory())
54825
+ if (!lstatSync16(root2)?.isDirectory())
54438
54826
  continue;
54439
54827
  const raw = witness(join28(root2, "gemini-extension.json"));
54440
54828
  if (raw === null)
@@ -54447,7 +54835,7 @@ function resolveAgentDiscovery(options) {
54447
54835
  }
54448
54836
  return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join28(home, ".hermes/plugins"), join28(home, ".hermes/hermes-agent")].map((path) => canonical3(path))) } : {} };
54449
54837
  }
54450
- var digest = (text2) => createHash11("sha256").update(text2).digest("hex");
54838
+ var digest = (text2) => createHash12("sha256").update(text2).digest("hex");
54451
54839
  var init_agent_discovery = __esm(() => {
54452
54840
  init_agent_policy_limits();
54453
54841
  init_agent_hermes();
@@ -54456,6 +54844,7 @@ var init_agent_discovery = __esm(() => {
54456
54844
  init_agent_discovery_path_bytes();
54457
54845
  init_plugin_discovery();
54458
54846
  init_plugin_admission();
54847
+ init_claude_marketplace_registry();
54459
54848
  init_agent_discovery_directories();
54460
54849
  });
54461
54850
 
@@ -54540,7 +54929,7 @@ var init_agent_adapters = __esm(() => {
54540
54929
  });
54541
54930
 
54542
54931
  // src/lib/agent-codex.ts
54543
- import { isDeepStrictEqual as isDeepStrictEqual2 } from "util";
54932
+ import { isDeepStrictEqual as isDeepStrictEqual3 } from "util";
54544
54933
  function assertCodexPathConfigEditable(text2) {
54545
54934
  const before2 = Bun.TOML.parse(text2);
54546
54935
  if (before2.skills?.config === undefined)
@@ -54549,7 +54938,7 @@ function assertCodexPathConfigEditable(text2) {
54549
54938
  delete expected.skills.config;
54550
54939
  try {
54551
54940
  const withoutSections = Bun.TOML.parse(text2.replace(CODEX_SKILL_CONFIG_SECTIONS, ""));
54552
- if (isDeepStrictEqual2(withoutSections, expected))
54941
+ if (isDeepStrictEqual3(withoutSections, expected))
54553
54942
  return;
54554
54943
  } catch {}
54555
54944
  throw new Error("Codex skill path controls require ordinary [[skills.config]] TOML tables; preserve and convert inline or dotted config arrays before running skills hook install");
@@ -54587,7 +54976,7 @@ function disableCodexBundledSkills(text2) {
54587
54976
  const candidates = new Set;
54588
54977
  const consider = (candidate2) => {
54589
54978
  try {
54590
- if (isDeepStrictEqual2(Bun.TOML.parse(candidate2), expected))
54979
+ if (isDeepStrictEqual3(Bun.TOML.parse(candidate2), expected))
54591
54980
  candidates.add(candidate2);
54592
54981
  } catch {}
54593
54982
  };
@@ -54617,16 +55006,16 @@ var init_agent_codex = __esm(() => {
54617
55006
  });
54618
55007
 
54619
55008
  // src/lib/agent-integration.ts
54620
- import { createHash as createHash12, randomUUID as randomUUID6 } from "crypto";
54621
- import { existsSync as existsSync15, lstatSync as lstatSync16, statSync as statSync8, mkdirSync as mkdirSync7, readFileSync as readFileSync15, 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 openSync9, closeSync as closeSync9, fsyncSync as fsyncSync2, fstatSync as fstatSync9, readSync as readSync7, constants as constants9, linkSync as linkSync2 } from "fs";
54622
- import { dirname as dirname13, join as join29, resolve as resolve13, relative as relative5, isAbsolute as isAbsolute12, sep as sep6 } from "path";
55009
+ import { createHash as createHash13, randomUUID as randomUUID6 } from "crypto";
55010
+ import { existsSync as existsSync15, lstatSync as lstatSync17, statSync as statSync8, mkdirSync as mkdirSync7, readFileSync as readFileSync15, 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 constants10, linkSync as linkSync2 } from "fs";
55011
+ import { dirname as dirname14, join as join29, resolve as resolve15, relative as relative5, isAbsolute as isAbsolute14, sep as sep6 } from "path";
54623
55012
  import { homedir as homedir4 } from "os";
54624
55013
  function assertSafePath(path) {
54625
- let cursor = resolve13(path);
55014
+ let cursor = resolve15(path);
54626
55015
  while (true) {
54627
- if (lstatSync16(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
55016
+ if (lstatSync17(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
54628
55017
  throw new Error(`Refusing symlink path: ${cursor}`);
54629
- const parent = dirname13(cursor);
55018
+ const parent = dirname14(cursor);
54630
55019
  if (parent === cursor)
54631
55020
  return;
54632
55021
  cursor = parent;
@@ -54635,16 +55024,16 @@ function assertSafePath(path) {
54635
55024
  function readRootAlias(home, agent) {
54636
55025
  assertSafePath(home);
54637
55026
  const realHome = realpathSync5(home), alias = join29(realHome, `.${agent}`);
54638
- const stat2 = lstatSync16(alias, { throwIfNoEntry: false, bigint: true });
55027
+ const stat2 = lstatSync17(alias, { throwIfNoEntry: false, bigint: true });
54639
55028
  if (!stat2?.isSymbolicLink())
54640
55029
  throw new Error(`Agent root alias changed after planning: ${alias}`);
54641
- const link2 = readlinkSync2(alias), targetPath = resolve13(dirname13(alias), link2);
55030
+ const link2 = readlinkSync2(alias), targetPath = resolve15(dirname14(alias), link2);
54642
55031
  assertSafePath(targetPath);
54643
- const targetStat = lstatSync16(targetPath, { throwIfNoEntry: false });
55032
+ const targetStat = lstatSync17(targetPath, { throwIfNoEntry: false });
54644
55033
  if (!targetStat?.isDirectory())
54645
55034
  throw new Error(`Agent root alias must target an existing directory: ${alias}`);
54646
55035
  const target = realpathSync5(targetPath), inside = relative5(realHome, target);
54647
- if (!inside || inside === ".." || inside.startsWith(`..${sep6}`) || isAbsolute12(inside))
55036
+ if (!inside || inside === ".." || inside.startsWith(`..${sep6}`) || isAbsolute14(inside))
54648
55037
  throw new Error(`Agent root alias target must be inside the real home: ${alias}`);
54649
55038
  return { agent, home: realHome, alias, target, link: link2, aliasIdentity: `${stat2.dev}:${stat2.ino}:${stat2.ctimeNs}`, targetIdentity: `${targetStat.dev}:${targetStat.ino}` };
54650
55039
  }
@@ -54653,14 +55042,14 @@ function rootAliases(home, allowed = false) {
54653
55042
  return [];
54654
55043
  const result2 = [];
54655
55044
  for (const agent of ["claude", "codex"])
54656
- if (lstatSync16(join29(home, `.${agent}`), { throwIfNoEntry: false })?.isSymbolicLink())
55045
+ if (lstatSync17(join29(home, `.${agent}`), { throwIfNoEntry: false })?.isSymbolicLink())
54657
55046
  result2.push(readRootAlias(home, agent));
54658
55047
  if (result2.some((item, index) => result2.slice(index + 1).some((other) => item.target === other.target || item.target.startsWith(other.target + sep6) || other.target.startsWith(item.target + sep6))))
54659
55048
  throw new Error("Agent root alias targets must not overlap");
54660
55049
  return result2;
54661
55050
  }
54662
55051
  function canonicalAgentPath(path, aliases) {
54663
- const absolute = resolve13(path), binding = aliases.find((item) => absolute === item.alias || absolute.startsWith(item.alias + sep6));
55052
+ const absolute = resolve15(path), binding = aliases.find((item) => absolute === item.alias || absolute.startsWith(item.alias + sep6));
54664
55053
  return binding ? join29(binding.target, relative5(binding.alias, absolute)) : absolute;
54665
55054
  }
54666
55055
  function recheckRootAliases(aliases) {
@@ -54674,35 +55063,35 @@ function recheckRootAliases(aliases) {
54674
55063
  }
54675
55064
  function readNativeBytes(path, maximum = 64 * 1024 * 1024) {
54676
55065
  assertSafePath(path);
54677
- const before2 = lstatSync16(path);
55066
+ const before2 = lstatSync17(path);
54678
55067
  if (!before2.isFile() || before2.size > maximum)
54679
55068
  throw new Error("Unsupported or oversized native skill file");
54680
- const descriptor = openSync9(path, constants9.O_RDONLY | constants9.O_NOFOLLOW | constants9.O_NONBLOCK);
55069
+ const descriptor = openSync10(path, constants10.O_RDONLY | constants10.O_NOFOLLOW | constants10.O_NONBLOCK);
54681
55070
  try {
54682
- const opened = fstatSync9(descriptor);
55071
+ const opened = fstatSync10(descriptor);
54683
55072
  if (!opened.isFile() || opened.dev !== before2.dev || opened.ino !== before2.ino || opened.size !== before2.size)
54684
55073
  throw new Error("Native skill file changed while reading");
54685
55074
  const bytes = Buffer.allocUnsafe(before2.size + 1);
54686
55075
  let length = 0;
54687
55076
  while (length < bytes.length) {
54688
- const count = readSync7(descriptor, bytes, length, bytes.length - length, null);
55077
+ const count = readSync8(descriptor, bytes, length, bytes.length - length, null);
54689
55078
  if (!count)
54690
55079
  break;
54691
55080
  length += count;
54692
55081
  }
54693
- const after2 = fstatSync9(descriptor);
55082
+ const after2 = fstatSync10(descriptor);
54694
55083
  if (length !== before2.size || after2.size !== before2.size || after2.mtimeMs !== opened.mtimeMs || after2.ctimeMs !== opened.ctimeMs)
54695
55084
  throw new Error("Native skill file changed while reading");
54696
55085
  return bytes.subarray(0, length);
54697
55086
  } finally {
54698
- closeSync9(descriptor);
55087
+ closeSync10(descriptor);
54699
55088
  }
54700
55089
  }
54701
55090
  function treeHash(root2) {
54702
- const hash2 = createHash12("sha256");
55091
+ const hash2 = createHash13("sha256");
54703
55092
  let bytes = 0, files = 0;
54704
55093
  function visit2(path) {
54705
- const stat2 = lstatSync16(path);
55094
+ const stat2 = lstatSync17(path);
54706
55095
  if (stat2.isSymbolicLink())
54707
55096
  throw new Error(`Refusing symlink in skill: ${path}`);
54708
55097
  const rel = relative5(root2, path);
@@ -54728,11 +55117,11 @@ function treeHash(root2) {
54728
55117
  function projectAncestorDirectories(projects) {
54729
55118
  const directories = new Set;
54730
55119
  for (const project of projects) {
54731
- for (let path = resolve13(project), depth = 0;; depth++) {
55120
+ for (let path = resolve15(project), depth = 0;; depth++) {
54732
55121
  if (depth >= 100)
54733
55122
  throw new Error("NATIVE_SKILL_DRIFT: project ancestor discovery limit exceeded");
54734
55123
  directories.add(path);
54735
- const parent = dirname13(path);
55124
+ const parent = dirname14(path);
54736
55125
  if (parent === path)
54737
55126
  break;
54738
55127
  path = parent;
@@ -54759,10 +55148,10 @@ function inventoryNativeSkills(home = homedir4(), options = {}) {
54759
55148
  throw new Error("Native skill discovery metadata limit exceeded");
54760
55149
  }
54761
55150
  function emptySiblingCacheAlias(path, parent) {
54762
- const link2 = readlinkSync2(path), target = resolve13(parent, link2);
54763
- if (dirname13(target) !== parent || (isAbsolute12(link2) ? link2 !== target : dirname13(link2) !== "."))
55151
+ const link2 = readlinkSync2(path), target = resolve15(parent, link2);
55152
+ if (dirname14(target) !== parent || (isAbsolute14(link2) ? link2 !== target : dirname14(link2) !== "."))
54764
55153
  return false;
54765
- if (!lstatSync16(target, { throwIfNoEntry: false })?.isDirectory())
55154
+ if (!lstatSync17(target, { throwIfNoEntry: false })?.isDirectory())
54766
55155
  return false;
54767
55156
  const scan = cacheScans.get(target);
54768
55157
  return Boolean(scan?.complete && !scan.hasSkills && scan.entries <= maxAliasProofEntries);
@@ -54774,7 +55163,7 @@ function inventoryNativeSkills(home = homedir4(), options = {}) {
54774
55163
  assertSafePath(path);
54775
55164
  if (!existsSync15(path))
54776
55165
  return scan;
54777
- const stat2 = lstatSync16(path);
55166
+ const stat2 = lstatSync17(path);
54778
55167
  if (stat2.isFile())
54779
55168
  return scan;
54780
55169
  if (!stat2.isDirectory())
@@ -54793,7 +55182,7 @@ function inventoryNativeSkills(home = homedir4(), options = {}) {
54793
55182
  }
54794
55183
  const bridge = !vendor && isOwnedCliBridge(path, bridgePaths);
54795
55184
  const rootAlias = aliases.find((item) => path === item.target || path.startsWith(item.target + sep6));
54796
- entries.push({ agent, path, hash: treeHash(path), managed, vendor, ...agent === "codex" && path.startsWith(canonicalAgentPath(join29(home, ".codex", "skills", ".system"), aliases) + sep6) ? { system: true } : {}, ...bridge ? { bridge: true, bridgeHome: resolve13(home) } : {}, ...rootAlias ? { rootAlias } : {} });
55185
+ entries.push({ agent, path, hash: treeHash(path), managed, vendor, ...agent === "codex" && path.startsWith(canonicalAgentPath(join29(home, ".codex", "skills", ".system"), aliases) + sep6) ? { system: true } : {}, ...bridge ? { bridge: true, bridgeHome: resolve15(home) } : {}, ...rootAlias ? { rootAlias } : {} });
54797
55186
  return scan;
54798
55187
  }
54799
55188
  if (depth > (vendor ? 32 : 3))
@@ -54820,7 +55209,7 @@ function inventoryNativeSkills(home = homedir4(), options = {}) {
54820
55209
  if (isVendor && !options.includeVendor)
54821
55210
  continue;
54822
55211
  const child = join29(path, name);
54823
- if (isVendor && lstatSync16(child, { throwIfNoEntry: false })?.isSymbolicLink()) {
55212
+ if (isVendor && lstatSync17(child, { throwIfNoEntry: false })?.isSymbolicLink()) {
54824
55213
  const target = statSync8(child, { throwIfNoEntry: false });
54825
55214
  if (target?.isFile() || pluginCache && target?.isDirectory() && emptySiblingCacheAlias(child, path)) {
54826
55215
  scan.entries++;
@@ -54942,7 +55331,7 @@ function configureHooks(config, agent, command, profileId, nativeReady) {
54942
55331
  function disableCodexSkills(text2, skills, aliases, bridgePath) {
54943
55332
  const bundled = disableCodexBundledSkills(text2);
54944
55333
  let result2 = bundled;
54945
- const bridgeSelector = (entry) => typeof entry.name === "string" && entry.name.trim() === CLI_BRIDGE_NAME || typeof entry.path === "string" && [resolve13(bridgePath), resolve13(join29(bridgePath, "SKILL.md"))].includes(canonicalAgentPath(entry.path, aliases));
55334
+ const bridgeSelector = (entry) => typeof entry.name === "string" && entry.name.trim() === CLI_BRIDGE_NAME || typeof entry.path === "string" && [resolve15(bridgePath), resolve15(join29(bridgePath, "SKILL.md"))].includes(canonicalAgentPath(entry.path, aliases));
54946
55335
  const previousConfig = Bun.TOML.parse(bundled).skills?.config;
54947
55336
  if (previousConfig !== undefined && (!Array.isArray(previousConfig) || previousConfig.some((entry) => !entry || typeof entry !== "object" || entry.path !== undefined && entry.name !== undefined)))
54948
55337
  throw new Error("Codex skill controls require one path or name selector per [[skills.config]] entry; review ambiguous entries before running skills hook install");
@@ -54954,7 +55343,7 @@ function disableCodexSkills(text2, skills, aliases, bridgePath) {
54954
55343
  result2 = result2.replace(CODEX_SKILL_CONFIG_SECTIONS, (section) => {
54955
55344
  const parsed = Bun.TOML.parse(section);
54956
55345
  const declared = parsed.skills?.config?.[0];
54957
- if (!declared || !(skill.enabled && bridgeSelector(declared)) && !(typeof declared.path === "string" && [resolve13(path), resolve13(skill.path)].includes(canonicalAgentPath(declared.path, aliases))))
55346
+ if (!declared || !(skill.enabled && bridgeSelector(declared)) && !(typeof declared.path === "string" && [resolve15(path), resolve15(skill.path)].includes(canonicalAgentPath(declared.path, aliases))))
54958
55347
  return section;
54959
55348
  found = true;
54960
55349
  return /^\s*enabled\s*=/m.test(section) ? section.replace(/^\s*enabled\s*=.*$/m, `enabled = ${skill.enabled}`) : `${section.trimEnd()}
@@ -54984,9 +55373,9 @@ function planAgentIntegration(options) {
54984
55373
  throw new Error("Invalid existing Skills bridge policy");
54985
55374
  if (policy.bridge?.agents !== undefined && (!Array.isArray(policy.bridge.agents) || policy.bridge.agents.some((agent) => !INTEGRATION_AGENTS.includes(agent))))
54986
55375
  throw new Error("Invalid existing bridge agent inventory");
54987
- for (const field of ["commands", "profiles"])
54988
- if (policy.bridge?.[field] !== undefined && (!policy.bridge[field] || typeof policy.bridge[field] !== "object" || Array.isArray(policy.bridge[field]) || Object.entries(policy.bridge[field]).some(([key, value]) => !INTEGRATION_AGENTS.includes(key) || typeof value !== "string" || !value || value.includes("\x00"))))
54989
- throw new Error(`Invalid existing bridge ${field} binding`);
55376
+ for (const field2 of ["commands", "profiles"])
55377
+ if (policy.bridge?.[field2] !== undefined && (!policy.bridge[field2] || typeof policy.bridge[field2] !== "object" || Array.isArray(policy.bridge[field2]) || Object.entries(policy.bridge[field2]).some(([key, value]) => !INTEGRATION_AGENTS.includes(key) || typeof value !== "string" || !value || value.includes("\x00"))))
55378
+ throw new Error(`Invalid existing bridge ${field2} binding`);
54990
55379
  const priorAgents = policy.bridge?.agents ?? [];
54991
55380
  const profileId = options.profileId ?? policy.profileId ?? "default";
54992
55381
  const validateProfile = (value) => {
@@ -55072,7 +55461,7 @@ function planAgentIntegration(options) {
55072
55461
  version: CLI_BRIDGE_VERSION,
55073
55462
  digest: CLI_BRIDGE_DIGEST,
55074
55463
  agents: [...new Set([...priorAgents, ...options.agents])].sort(),
55075
- home: resolve13(home),
55464
+ home: resolve15(home),
55076
55465
  includeVendor: true,
55077
55466
  ...options.agents.includes("hermes") ? { supervisors: { ...policy.bridge?.supervisors, hermes: { path: join29(dataDir3, "agent-hooks", "hermes.js"), runtime: process.execPath, sha256: sha(renderHermesSupervisor(bindings.get("hermes").command, bindings.get("hermes").profileId)) } } } : {},
55078
55467
  commands: { ...policy.bridge?.commands, ...Object.fromEntries([...bindings].map(([agent, binding]) => [agent, binding.command])) },
@@ -55089,7 +55478,7 @@ function planAgentIntegration(options) {
55089
55478
  }
55090
55479
  function atomicWrite2(path, content) {
55091
55480
  assertSafePath(path);
55092
- mkdirSync7(dirname13(path), { recursive: true, mode: 448 });
55481
+ mkdirSync7(dirname14(path), { recursive: true, mode: 448 });
55093
55482
  const temporary = `${path}.skills-${randomUUID6()}`;
55094
55483
  try {
55095
55484
  writeFileSync5(temporary, content, { mode: 384, flag: "wx" });
@@ -55102,10 +55491,10 @@ function atomicWrite2(path, content) {
55102
55491
  function applyAgentIntegration(plan) {
55103
55492
  const policyPath = join29(plan.dataDir, "agent-policy.json");
55104
55493
  assertSafePath(policyPath);
55105
- const currentText = (path) => resolve13(path) === resolve13(policyPath) ? readManagedSkillPolicySnapshot(plan.dataDir)?.text ?? null : readOptional(path);
55494
+ const currentText = (path) => resolve15(path) === resolve15(policyPath) ? readManagedSkillPolicySnapshot(plan.dataDir)?.text ?? null : readOptional(path);
55106
55495
  readManagedSkillPolicySnapshot(plan.dataDir);
55107
55496
  for (const change of plan.changes)
55108
- if (resolve13(change.path) === resolve13(policyPath))
55497
+ if (resolve15(change.path) === resolve15(policyPath))
55109
55498
  parseManagedSkillPolicy(change.after);
55110
55499
  const aliases = plan.rootAliases ?? [];
55111
55500
  recheckRootAliases(aliases);
@@ -55135,7 +55524,7 @@ function applyAgentIntegration(plan) {
55135
55524
  recheckRootAliases(aliases);
55136
55525
  if (currentText(change.path) !== change.before)
55137
55526
  throw new Error(`Configuration changed after planning: ${change.path}`);
55138
- for (let directory = dirname13(change.path);!existsSync15(directory); directory = dirname13(directory))
55527
+ for (let directory = dirname14(change.path);!existsSync15(directory); directory = dirname14(directory))
55139
55528
  createdDirectories.add(directory);
55140
55529
  const after2 = change.after;
55141
55530
  atomicWrite2(change.path, after2);
@@ -55175,11 +55564,11 @@ function applyAgentIntegration(plan) {
55175
55564
  }
55176
55565
  function syncArchiveDirectory(path) {
55177
55566
  assertSafePath(path);
55178
- const descriptor = openSync9(path, constants9.O_RDONLY | constants9.O_DIRECTORY | constants9.O_NOFOLLOW | constants9.O_NONBLOCK);
55567
+ const descriptor = openSync10(path, constants10.O_RDONLY | constants10.O_DIRECTORY | constants10.O_NOFOLLOW | constants10.O_NONBLOCK);
55179
55568
  try {
55180
- fsyncSync2(descriptor);
55569
+ fsyncSync3(descriptor);
55181
55570
  } finally {
55182
- closeSync9(descriptor);
55571
+ closeSync10(descriptor);
55183
55572
  }
55184
55573
  }
55185
55574
  function writeArchiveJournal(path, value) {
@@ -55187,18 +55576,18 @@ function writeArchiveJournal(path, value) {
55187
55576
  const temporary = `${path}.skills-${randomUUID6()}`;
55188
55577
  let descriptor;
55189
55578
  try {
55190
- descriptor = openSync9(temporary, constants9.O_WRONLY | constants9.O_CREAT | constants9.O_EXCL | constants9.O_NOFOLLOW, 384);
55579
+ descriptor = openSync10(temporary, constants10.O_WRONLY | constants10.O_CREAT | constants10.O_EXCL | constants10.O_NOFOLLOW, 384);
55191
55580
  writeFileSync5(descriptor, `${JSON.stringify(value)}
55192
55581
  `);
55193
- fsyncSync2(descriptor);
55194
- closeSync9(descriptor);
55582
+ fsyncSync3(descriptor);
55583
+ closeSync10(descriptor);
55195
55584
  descriptor = undefined;
55196
55585
  renameSync4(temporary, path);
55197
- syncArchiveDirectory(dirname13(path));
55586
+ syncArchiveDirectory(dirname14(path));
55198
55587
  } finally {
55199
55588
  if (descriptor !== undefined)
55200
- closeSync9(descriptor);
55201
- if (lstatSync16(temporary, { throwIfNoEntry: false }))
55589
+ closeSync10(descriptor);
55590
+ if (lstatSync17(temporary, { throwIfNoEntry: false }))
55202
55591
  unlinkSync4(temporary);
55203
55592
  }
55204
55593
  }
@@ -55231,7 +55620,7 @@ function archiveNativeSkills(inventory, options) {
55231
55620
  const moved = [];
55232
55621
  const verifyArchive = (entry) => {
55233
55622
  assertSafePath(entry.archive);
55234
- const stat2 = lstatSync16(entry.archive);
55623
+ const stat2 = lstatSync17(entry.archive);
55235
55624
  if (entry.discoveryOnly ? !stat2.isFile() : !stat2.isDirectory())
55236
55625
  throw new Error("Archive type changed");
55237
55626
  if ((entry.discoveryOnly ? sha(readNativeBytes(entry.archive)) : treeHash(entry.archive)) !== entry.hash)
@@ -55239,14 +55628,14 @@ function archiveNativeSkills(inventory, options) {
55239
55628
  };
55240
55629
  assertSafePath(archiveRoot);
55241
55630
  const created = [];
55242
- for (let path = archiveRoot;!existsSync15(path); path = dirname13(path))
55631
+ for (let path = archiveRoot;!existsSync15(path); path = dirname14(path))
55243
55632
  created.push(path);
55244
55633
  mkdirSync7(archiveRoot, { recursive: true, mode: 448 });
55245
55634
  try {
55246
55635
  for (const directory of created)
55247
55636
  syncArchiveDirectory(directory);
55248
55637
  if (created.length)
55249
- syncArchiveDirectory(dirname13(created.at(-1)));
55638
+ syncArchiveDirectory(dirname14(created.at(-1)));
55250
55639
  writeArchiveJournal(receiptPath, journal);
55251
55640
  for (const [index, entry] of selected.entries()) {
55252
55641
  recheckRootAliases(aliases);
@@ -55258,7 +55647,7 @@ function archiveNativeSkills(inventory, options) {
55258
55647
  writeArchiveJournal(receiptPath, journal);
55259
55648
  renameSync4(move.source, move.archive);
55260
55649
  moved.push(move);
55261
- syncArchiveDirectory(dirname13(move.source));
55650
+ syncArchiveDirectory(dirname14(move.source));
55262
55651
  syncArchiveDirectory(archiveRoot);
55263
55652
  verifyArchive(move);
55264
55653
  move.status = "archived";
@@ -55279,7 +55668,7 @@ function archiveNativeSkills(inventory, options) {
55279
55668
  recheckRootAliases(aliases);
55280
55669
  assertSafePath(entry.source);
55281
55670
  assertSafePath(entry.archive);
55282
- if (lstatSync16(entry.source, { throwIfNoEntry: false })) {
55671
+ if (lstatSync17(entry.source, { throwIfNoEntry: false })) {
55283
55672
  entry.status = "recovery-required";
55284
55673
  entry.conflict = "source-occupied";
55285
55674
  continue;
@@ -55293,10 +55682,10 @@ function archiveNativeSkills(inventory, options) {
55293
55682
  }
55294
55683
  if (entry.discoveryOnly) {
55295
55684
  linkSync2(entry.archive, entry.source);
55296
- syncArchiveDirectory(dirname13(entry.source));
55685
+ syncArchiveDirectory(dirname14(entry.source));
55297
55686
  unlinkSync4(entry.archive);
55298
55687
  } else {
55299
- if (lstatSync16(entry.source, { throwIfNoEntry: false })) {
55688
+ if (lstatSync17(entry.source, { throwIfNoEntry: false })) {
55300
55689
  entry.status = "recovery-required";
55301
55690
  entry.conflict = "source-occupied";
55302
55691
  continue;
@@ -55304,7 +55693,7 @@ function archiveNativeSkills(inventory, options) {
55304
55693
  renameSync4(entry.archive, entry.source);
55305
55694
  }
55306
55695
  entry.status = "restored";
55307
- syncArchiveDirectory(dirname13(entry.source));
55696
+ syncArchiveDirectory(dirname14(entry.source));
55308
55697
  syncArchiveDirectory(archiveRoot);
55309
55698
  } catch {
55310
55699
  entry.status = "recovery-required";
@@ -55324,7 +55713,7 @@ function archiveNativeSkills(inventory, options) {
55324
55713
  return { entries: entries.map(({ status, conflict, ...entry }) => entry), receiptPath, ...aliases.length ? { rootAliases: aliases } : {} };
55325
55714
  }
55326
55715
  function assertManagedAgentBridge(agent, options = {}) {
55327
- const home = resolve13(options.home ?? homedir4()), dataDir3 = options.dataDir ?? getDataDirReadOnly();
55716
+ const home = resolve15(options.home ?? homedir4()), dataDir3 = options.dataDir ?? getDataDirReadOnly();
55328
55717
  assertSafePath(join29(dataDir3, "agent-policy.json"));
55329
55718
  const snapshot = readManagedSkillPolicySnapshot(dataDir3);
55330
55719
  if (!snapshot)
@@ -55447,7 +55836,7 @@ function assertNativeExportAllowed(dataDir3 = getDataDirReadOnly()) {
55447
55836
  if (requiresCliSkillLoading(dataDir3))
55448
55837
  throw new Error("NATIVE_SKILL_EXPORT_DISABLED: this station loads skills through the Skills CLI; use skills sync --selection-profile <id>");
55449
55838
  }
55450
- var sha = (data) => createHash12("sha256").update(data).digest("hex"), HOOK_EVENTS, ROOTS, SKILLS_LOADING_POLICY = "Skills loading policy: discover skills with `skills list` or `skills search`, and read selected instructions with `skills load <slug>`. Use `skills sync` to refresh the shared profile. The only native skill is the owned skills-cli bridge. Create and edit payload skills in the Skills authoring workspace; do not copy payload instructions into native discovery folders. Context loading does not authorize execution; use `skills run` only when the task calls for running a skill.";
55839
+ var sha = (data) => createHash13("sha256").update(data).digest("hex"), HOOK_EVENTS, ROOTS, SKILLS_LOADING_POLICY = "Skills loading policy: discover skills with `skills list` or `skills search`, and read selected instructions with `skills load <slug>`. Use `skills sync` to refresh the shared profile. The only native skill is the owned skills-cli bridge. Create and edit payload skills in the Skills authoring workspace; do not copy payload instructions into native discovery folders. Context loading does not authorize execution; use `skills run` only when the task calls for running a skill.";
55451
55840
  var init_agent_integration = __esm(() => {
55452
55841
  init_config();
55453
55842
  init_managed_policy();
@@ -55615,7 +56004,7 @@ var init_home_migration = __esm(() => {
55615
56004
  import {
55616
56005
  cpSync as cpSync2,
55617
56006
  existsSync as existsSync17,
55618
- lstatSync as lstatSync17,
56007
+ lstatSync as lstatSync18,
55619
56008
  mkdirSync as mkdirSync9,
55620
56009
  mkdtempSync as mkdtempSync2,
55621
56010
  readFileSync as readFileSync16,
@@ -55626,14 +56015,14 @@ import {
55626
56015
  writeFileSync as writeFileSync7
55627
56016
  } from "fs";
55628
56017
  import { homedir as homedir5 } from "os";
55629
- import { basename as basename5, dirname as dirname14, join as join31 } from "path";
56018
+ import { basename as basename7, dirname as dirname15, join as join31 } from "path";
55630
56019
  function isSkillsOwnershipMarker(marker) {
55631
56020
  return typeof marker === "object" && marker !== null && Object.hasOwn(marker, "managedBy") && marker.managedBy === SYNC_MARKER_MANAGED_BY;
55632
56021
  }
55633
56022
  function hasSkillsOwnershipMarker(dir) {
55634
56023
  const path = join31(dir, SYNC_MARKER_FILE);
55635
56024
  try {
55636
- if (!lstatSync17(path).isFile())
56025
+ if (!lstatSync18(path).isFile())
55637
56026
  return false;
55638
56027
  const marker = JSON.parse(readFileSync16(path, "utf8"));
55639
56028
  return isSkillsOwnershipMarker(marker);
@@ -55858,9 +56247,9 @@ function writeManagedSkillDir(dir, skillMd, options) {
55858
56247
  const action = dirExists ? "update" : "create";
55859
56248
  if (options.dryRun)
55860
56249
  return { action, path: skillMdPath };
55861
- const parentDir = dirname14(dir);
56250
+ const parentDir = dirname15(dir);
55862
56251
  mkdirSync9(parentDir, { recursive: true });
55863
- const transactionDir = mkdtempSync2(join31(parentDir, `.hasna-skills-write-${basename5(dir)}-`));
56252
+ const transactionDir = mkdtempSync2(join31(parentDir, `.hasna-skills-write-${basename7(dir)}-`));
55864
56253
  const candidateDir = join31(transactionDir, "candidate");
55865
56254
  const backupDir = join31(transactionDir, "backup");
55866
56255
  const candidateSkillMdPath = join31(candidateDir, "SKILL.md");
@@ -57710,7 +58099,7 @@ var _parse = (_Err) => {
57710
58099
  return result2.value;
57711
58100
  };
57712
58101
  return fn;
57713
- }, parse5, _parseAsync = (_Err) => {
58102
+ }, parse6, _parseAsync = (_Err) => {
57714
58103
  const fn = async (schema, value, _ctx, params) => {
57715
58104
  const ctx = _ctx ? { ..._ctx, async: true } : { async: true };
57716
58105
  let result2 = schema._zod.run({ value, issues: [] }, ctx);
@@ -57755,16 +58144,16 @@ var _parse = (_Err) => {
57755
58144
  result2 = await result2;
57756
58145
  return result2.issues.length === 0;
57757
58146
  }, _encode = (_Err) => {
57758
- const parse6 = _parse(_Err);
58147
+ const parse7 = _parse(_Err);
57759
58148
  const fn = (schema, value, _ctx, _params) => {
57760
58149
  const ctx = _ctx ? { ..._ctx, direction: "backward" } : { direction: "backward" };
57761
- return parse6(schema, value, ctx, finalizeParams(fn, _params));
58150
+ return parse7(schema, value, ctx, finalizeParams(fn, _params));
57762
58151
  };
57763
58152
  return fn;
57764
58153
  }, encode, _decode = (_Err) => {
57765
- const parse6 = _parse(_Err);
58154
+ const parse7 = _parse(_Err);
57766
58155
  const fn = (schema, value, _ctx, _params) => {
57767
- return parse6(schema, value, _ctx, finalizeParams(fn, _params));
58156
+ return parse7(schema, value, _ctx, finalizeParams(fn, _params));
57768
58157
  };
57769
58158
  return fn;
57770
58159
  }, decode, _encodeAsync = (_Err) => {
@@ -57795,7 +58184,7 @@ var init_parse = __esm(() => {
57795
58184
  init_core();
57796
58185
  init_errors();
57797
58186
  init_util();
57798
- parse5 = /* @__PURE__ */ _parse($ZodRealError);
58187
+ parse6 = /* @__PURE__ */ _parse($ZodRealError);
57799
58188
  parseAsync = /* @__PURE__ */ _parseAsync($ZodRealError);
57800
58189
  safeParse = /* @__PURE__ */ _safeParse($ZodRealError);
57801
58190
  safeParseAsync = /* @__PURE__ */ _safeParseAsync($ZodRealError);
@@ -59758,14 +60147,14 @@ var init_schemas = __esm(() => {
59758
60147
  const shape = zod.def.shape;
59759
60148
  const propValues = {};
59760
60149
  for (const key in shape) {
59761
- const field = shape[key]._zod;
59762
- if (field.values) {
60150
+ const field2 = shape[key]._zod;
60151
+ if (field2.values) {
59763
60152
  if (!Object.prototype.hasOwnProperty.call(propValues, key)) {
59764
60153
  assignProp(propValues, key, new Set);
59765
60154
  }
59766
- for (const v of field.values)
60155
+ for (const v of field2.values)
59767
60156
  propValues[key].add(v);
59768
- if (field.optin !== undefined)
60157
+ if (field2.optin !== undefined)
59769
60158
  propValues[key].add(undefined);
59770
60159
  }
59771
60160
  }
@@ -60720,10 +61109,10 @@ var init_schemas = __esm(() => {
60720
61109
  throw new Error("implement() must be called with a function");
60721
61110
  }
60722
61111
  return Object.defineProperty(function(...args) {
60723
- const parsedArgs = inst._def.input ? parse5(inst._def.input, args) : args;
61112
+ const parsedArgs = inst._def.input ? parse6(inst._def.input, args) : args;
60724
61113
  const result2 = Reflect.apply(func, this, parsedArgs);
60725
61114
  if (inst._def.output) {
60726
- return parse5(inst._def.output, result2);
61115
+ return parse6(inst._def.output, result2);
60727
61116
  }
60728
61117
  return result2;
60729
61118
  }, "_zod", { value: inst._zod, enumerable: false });
@@ -72040,11 +72429,11 @@ var formatMap, stringProcessor = (schema, ctx, _json, _params) => {
72040
72429
  }
72041
72430
  const allKeys = new Set(Object.keys(shape));
72042
72431
  const requiredKeys = new Set([...allKeys].filter((key) => {
72043
- const field = def.shape[key];
72432
+ const field2 = def.shape[key];
72044
72433
  if (ctx.io === "input") {
72045
- return inputOptin(field) === undefined;
72434
+ return inputOptin(field2) === undefined;
72046
72435
  } else {
72047
- return field._zod.optout === undefined;
72436
+ return field2._zod.optout === undefined;
72048
72437
  }
72049
72438
  }));
72050
72439
  if (requiredKeys.size > 0) {
@@ -72424,7 +72813,7 @@ __export(exports_core2, {
72424
72813
  prettifyError: () => prettifyError,
72425
72814
  parseURLObject: () => parseURLObject,
72426
72815
  parseAsync: () => parseAsync,
72427
- parse: () => parse5,
72816
+ parse: () => parse6,
72428
72817
  meta: () => meta,
72429
72818
  mergeValues: () => mergeValues,
72430
72819
  memoizer: () => memoizer,
@@ -72814,12 +73203,12 @@ var init_errors2 = __esm(() => {
72814
73203
  });
72815
73204
 
72816
73205
  // node_modules/zod/v4/classic/parse.js
72817
- var parse7, parseAsync2, safeParse2, safeParseAsync2, encode2, decode2, encodeAsync2, decodeAsync2, safeEncode2, safeDecode2, safeEncodeAsync2, safeDecodeAsync2;
73206
+ var parse8, parseAsync2, safeParse2, safeParseAsync2, encode2, decode2, encodeAsync2, decodeAsync2, safeEncode2, safeDecode2, safeEncodeAsync2, safeDecodeAsync2;
72818
73207
  var init_parse2 = __esm(() => {
72819
73208
  init_core2();
72820
73209
  init_errors2();
72821
73210
  init_core2();
72822
- parse7 = /* @__PURE__ */ _parse(ZodRealError);
73211
+ parse8 = /* @__PURE__ */ _parse(ZodRealError);
72823
73212
  parseAsync2 = /* @__PURE__ */ _parseAsync(ZodRealError);
72824
73213
  safeParse2 = /* @__PURE__ */ _safeParse(ZodRealError);
72825
73214
  safeParseAsync2 = /* @__PURE__ */ _safeParseAsync(ZodRealError);
@@ -73620,7 +74009,7 @@ var init_schemas2 = __esm(() => {
73620
74009
  exports_util.own(this, "~standard", value);
73621
74010
  },
73622
74011
  parse: function _parse2(data, params) {
73623
- return parse7(this, data, params, { callee: _parse2 });
74012
+ return parse8(this, data, params, { callee: _parse2 });
73624
74013
  },
73625
74014
  parseAsync: async function _parseAsync2(data, params) {
73626
74015
  return await parseAsync2(this, data, params, { callee: _parseAsync2 });
@@ -75313,7 +75702,7 @@ __export(exports_external, {
75313
75702
  pipe: () => pipe,
75314
75703
  partialRecord: () => partialRecord,
75315
75704
  parseAsync: () => parseAsync2,
75316
- parse: () => parse7,
75705
+ parse: () => parse8,
75317
75706
  overwrite: () => _overwrite,
75318
75707
  output: () => output,
75319
75708
  optional: () => optional,
@@ -75794,7 +76183,7 @@ var init_v4 = __esm(() => {
75794
76183
  });
75795
76184
 
75796
76185
  // src/lib/canonical-json.ts
75797
- import { createHash as createHash13 } from "crypto";
76186
+ import { createHash as createHash14 } from "crypto";
75798
76187
  function canonicalJson2(value, maximumBytes = 2 * 1024 * 1024) {
75799
76188
  return canonicalJsonAtDepth(value, maximumBytes, 64);
75800
76189
  }
@@ -75838,7 +76227,7 @@ function canonicalJsonAtDepth(value, maximumBytes, maximumDepth) {
75838
76227
  return visit3(value, 0);
75839
76228
  }
75840
76229
  function canonicalJsonSha256(value, maximumBytes) {
75841
- return createHash13("sha256").update(canonicalJson2(value, maximumBytes)).digest("hex");
76230
+ return createHash14("sha256").update(canonicalJson2(value, maximumBytes)).digest("hex");
75842
76231
  }
75843
76232
  var init_canonical_json = () => {};
75844
76233
 
@@ -76592,13 +76981,13 @@ var init_remote_workspace_leave = __esm(() => {
76592
76981
 
76593
76982
  // src/lib/auth-store.ts
76594
76983
  import { chmodSync as chmodSync2, existsSync as existsSync20, mkdirSync as mkdirSync11, readFileSync as readFileSync19, renameSync as renameSync7, statSync as statSync11, unlinkSync as unlinkSync5, writeFileSync as writeFileSync9 } from "fs";
76595
- import { basename as basename6, dirname as dirname15, join as join34 } from "path";
76984
+ import { basename as basename8, dirname as dirname16, join as join34 } from "path";
76596
76985
  function getAuthFilePath(env3 = process.env) {
76597
76986
  return skillsCredentialFilePath(env3);
76598
76987
  }
76599
76988
  function getIdentityFilePath(env3 = process.env) {
76600
76989
  const file2 = skillsCredentialFilePath(env3);
76601
- return join34(dirname15(file2), basename6(file2).replace(/^credentials/, "identity") + ".json");
76990
+ return join34(dirname16(file2), basename8(file2).replace(/^credentials/, "identity") + ".json");
76602
76991
  }
76603
76992
  function getAuthIdentity(env3 = process.env) {
76604
76993
  return readIdentity(env3);
@@ -76614,10 +77003,10 @@ function readIdentity(env3 = process.env) {
76614
77003
  if (selected && normalizeSkillsApiOrigin(bound) !== selected)
76615
77004
  return {};
76616
77005
  const identity4 = {};
76617
- for (const field of ["email", "orgId", "orgSlug", "userId"]) {
76618
- const value = record6[field];
77006
+ for (const field2 of ["email", "orgId", "orgSlug", "userId"]) {
77007
+ const value = record6[field2];
76619
77008
  if (typeof value === "string" && value.length > 0)
76620
- identity4[field] = value;
77009
+ identity4[field2] = value;
76621
77010
  }
76622
77011
  return identity4;
76623
77012
  } catch {
@@ -76632,7 +77021,7 @@ function getAuthConfig(env3 = process.env, options = {}) {
76632
77021
  }
76633
77022
  function writeCredentialValues(values2, env3 = process.env) {
76634
77023
  const file2 = skillsCredentialFilePath(env3);
76635
- mkdirSync11(dirname15(file2), { recursive: true, mode: 448 });
77024
+ mkdirSync11(dirname16(file2), { recursive: true, mode: 448 });
76636
77025
  const lines = [];
76637
77026
  const written = new Set;
76638
77027
  if (existsSync20(file2)) {
@@ -76700,10 +77089,10 @@ function saveAuthConfig(config2, env3 = process.env, authenticatedOrigin) {
76700
77089
  const apiUrl = authenticatedOrigin ? normalizeSkillsApiOrigin(authenticatedOrigin) : resolveSkillsApiOrigin(env3)?.origin ?? defaultFleetGatewayBaseUrl("skills");
76701
77090
  const file2 = writeCredentialValues({ SKILLS_API_KEY: null, SKILLS_API_URL: null, [SKILLS_API_KEY_REF]: null, [SKILLS_API_KEY_ENV]: apiKey, [SKILLS_BOUND_API_URL]: apiUrl, [SKILLS_API_URL_ENV]: apiUrl }, env3);
76702
77091
  const identity4 = {};
76703
- for (const field of ["email", "orgId", "orgSlug", "userId"]) {
76704
- const value = config2[field];
77092
+ for (const field2 of ["email", "orgId", "orgSlug", "userId"]) {
77093
+ const value = config2[field2];
76705
77094
  if (typeof value === "string" && value.length > 0)
76706
- identity4[field] = value;
77095
+ identity4[field2] = value;
76707
77096
  }
76708
77097
  const identityFile = getIdentityFilePath(env3);
76709
77098
  if (Object.keys(identity4).length > 0) {
@@ -76896,15 +77285,44 @@ var init_remote_account = __esm(() => {
76896
77285
  };
76897
77286
  });
76898
77287
 
77288
+ // src/lib/remote-credit-checkout.ts
77289
+ function creditCheckoutRequestKey(value) {
77290
+ if (value === undefined)
77291
+ return crypto.randomUUID();
77292
+ if (typeof value !== "string" || !creditCheckoutKeyPattern.test(value))
77293
+ throw new Error("Checkout idempotency key must be 8-255 URL-safe characters");
77294
+ return value;
77295
+ }
77296
+ function creditCheckoutFailure(value, status, key) {
77297
+ if (!value || typeof value !== "object" || Array.isArray(value))
77298
+ return { code: "CREDIT_CHECKOUT_UNCONFIRMED" };
77299
+ const row = value;
77300
+ if (row.requestIdempotencyKey !== undefined && row.requestIdempotencyKey !== key)
77301
+ return { code: "CREDIT_CHECKOUT_UNCONFIRMED" };
77302
+ const code = status === 409 && row.error === "credit checkout in_progress" ? "CREDIT_CHECKOUT_IN_PROGRESS" : status === 409 && row.error === "credit checkout expired" && row.requestIdempotencyKey === key ? "CREDIT_CHECKOUT_EXPIRED" : status === 409 && row.error === "credit checkout fulfilled" && row.requestIdempotencyKey === key ? "CREDIT_CHECKOUT_FULFILLED" : "CREDIT_CHECKOUT_UNCONFIRMED";
77303
+ const delay2 = row.retryAfterSeconds;
77304
+ return { code, ...code === "CREDIT_CHECKOUT_IN_PROGRESS" || status === 503 && row.error === "credit checkout creation unresolved" ? typeof delay2 === "number" && Number.isSafeInteger(delay2) && delay2 > 0 && delay2 <= 3600 ? { retryAfterSeconds: delay2 } : {} : {} };
77305
+ }
77306
+ var creditCheckoutKeyPattern, creditCheckoutMessages;
77307
+ var init_remote_credit_checkout = __esm(() => {
77308
+ creditCheckoutKeyPattern = /^[A-Za-z0-9._:-]{8,255}$/;
77309
+ creditCheckoutMessages = {
77310
+ CREDIT_CHECKOUT_UNCONFIRMED: "Checkout creation could not be confirmed. Keep the request idempotency key, inspect billing, and use the same key for an explicit retry on the same server, account and pack. No automatic retry was made.",
77311
+ CREDIT_CHECKOUT_IN_PROGRESS: "This checkout is still being created. Wait before explicitly retrying the same server, account and pack with the same request idempotency key. No automatic retry was made.",
77312
+ CREDIT_CHECKOUT_EXPIRED: "This checkout has expired. Inspect billing before deliberately starting a new purchase with a new request idempotency key. Do not retry this checkout automatically.",
77313
+ CREDIT_CHECKOUT_FULFILLED: "This checkout is already fulfilled. Inspect the account balance; do not create another checkout to recover this purchase."
77314
+ };
77315
+ });
77316
+
76899
77317
  // src/lib/remote-profile.ts
76900
- function customerNamePatch(input2, field) {
76901
- if (!isRecord4(input2) || Object.keys(input2).length !== 1 || !Object.hasOwn(input2, field))
77318
+ function customerNamePatch(input2, field2) {
77319
+ if (!isRecord4(input2) || Object.keys(input2).length !== 1 || !Object.hasOwn(input2, field2))
76902
77320
  throw new Error("Provide only the requested name field.");
76903
- const value = input2[field];
77321
+ const value = input2[field2];
76904
77322
  if (typeof value !== "string" || /[\p{Cc}\p{Cs}\u2028\u2029]/u.test(value) || !value.trim() || [...value.trim()].length > 100) {
76905
77323
  throw new Error("Use a name of 1\u2013100 characters without control characters or newlines.");
76906
77324
  }
76907
- return { [field]: value.trim() };
77325
+ return { [field2]: value.trim() };
76908
77326
  }
76909
77327
  function isRecord4(value) {
76910
77328
  return !!value && typeof value === "object" && !Array.isArray(value);
@@ -76941,10 +77359,10 @@ async function readQuoteUnavailableCode(response) {
76941
77359
  let timer;
76942
77360
  let deadlineExceeded = false;
76943
77361
  const expired = Symbol("quote body deadline");
76944
- const deadline = new Promise((resolve14) => {
77362
+ const deadline = new Promise((resolve16) => {
76945
77363
  timer = setTimeout(() => {
76946
77364
  deadlineExceeded = true;
76947
- resolve14(expired);
77365
+ resolve16(expired);
76948
77366
  reader.cancel().catch(() => {});
76949
77367
  }, 1500);
76950
77368
  });
@@ -77059,6 +77477,7 @@ __export(exports_remote_client, {
77059
77477
  RemoteRouteUnsupportedError: () => RemoteRouteUnsupportedError,
77060
77478
  RemoteRequestError: () => RemoteRequestError,
77061
77479
  RemoteQuoteUnavailableError: () => RemoteQuoteUnavailableError,
77480
+ RemoteCreditCheckoutError: () => RemoteCreditCheckoutError,
77062
77481
  RemoteCapabilityUnavailableError: () => RemoteCapabilityUnavailableError
77063
77482
  });
77064
77483
 
@@ -77509,14 +77928,43 @@ class RemoteSkillsClient {
77509
77928
  async listCreditPacks() {
77510
77929
  return parseRemoteCreditPacks(await (await this.requestNewRoute("/api/v1/billing/credits")).json());
77511
77930
  }
77512
- async createCreditCheckout(packId) {
77931
+ async createCreditCheckout(packId, options = {}) {
77932
+ const requestIdempotencyKey = creditCheckoutRequestKey(options.idempotencyKey);
77513
77933
  const packs = await this.listCreditPacks();
77514
77934
  if (!packs.some((pack) => pack.id === packId))
77515
77935
  throw new Error("Choose a credit pack returned by skills credits packs");
77516
- return parseRemoteCheckout(await (await this.requestNewRoute("/api/v1/billing/credits", {
77517
- method: "POST",
77518
- body: JSON.stringify({ packId })
77519
- })).json());
77936
+ let response;
77937
+ try {
77938
+ response = await this.request("/api/v1/billing/credits", {
77939
+ method: "POST",
77940
+ body: JSON.stringify({ packId, idempotencyKey: requestIdempotencyKey })
77941
+ });
77942
+ } catch {
77943
+ throw new RemoteCreditCheckoutError("CREDIT_CHECKOUT_UNCONFIRMED", 0, requestIdempotencyKey);
77944
+ }
77945
+ if (response.status === 404 || response.status === 405) {
77946
+ response.body?.cancel().catch(() => {});
77947
+ throw new RemoteRouteUnsupportedError("/api/v1/billing/credits", response.status, this.apiUrl);
77948
+ }
77949
+ let value;
77950
+ try {
77951
+ value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(await readBoundedResponse(response, 4096)));
77952
+ } catch {
77953
+ throw new RemoteCreditCheckoutError("CREDIT_CHECKOUT_UNCONFIRMED", response.status, requestIdempotencyKey);
77954
+ }
77955
+ if (!response.ok) {
77956
+ const failure = creditCheckoutFailure(value, response.status, requestIdempotencyKey);
77957
+ throw new RemoteCreditCheckoutError(failure.code, response.status, requestIdempotencyKey, failure.retryAfterSeconds);
77958
+ }
77959
+ try {
77960
+ const checkout = parseRemoteCheckout(value);
77961
+ const echo = value.requestIdempotencyKey;
77962
+ if (echo !== undefined && echo !== requestIdempotencyKey)
77963
+ throw new Error("checkout request key changed");
77964
+ return { ...checkout, requestIdempotencyKey };
77965
+ } catch {
77966
+ throw new RemoteCreditCheckoutError("CREDIT_CHECKOUT_UNCONFIRMED", response.status, requestIdempotencyKey);
77967
+ }
77520
77968
  }
77521
77969
  async getUsage() {
77522
77970
  return this.arrayResponse("/api/v1/billing/usage");
@@ -77749,13 +78197,13 @@ class RemoteSkillsClient {
77749
78197
  return normalizeUpdatedSincePage(await response.json());
77750
78198
  }
77751
78199
  }
77752
- function requireOptionalString(record7, field) {
77753
- if (record7[field] === undefined)
78200
+ function requireOptionalString(record7, field2) {
78201
+ if (record7[field2] === undefined)
77754
78202
  return;
77755
- if (typeof record7[field] !== "string") {
77756
- throw new Error(`Remote payload did not match the expected contract (${field} must be a string when present)`);
78203
+ if (typeof record7[field2] !== "string") {
78204
+ throw new Error(`Remote payload did not match the expected contract (${field2} must be a string when present)`);
77757
78205
  }
77758
- return record7[field];
78206
+ return record7[field2];
77759
78207
  }
77760
78208
  function isVersionRecord(value) {
77761
78209
  return value !== null && typeof value === "object" && !Array.isArray(value);
@@ -77886,7 +78334,7 @@ async function createRemoteSkillsClient(env3 = process.env) {
77886
78334
  function createRemoteSkillsClientReadOnly(env3 = process.env) {
77887
78335
  return createRemoteSkillsClient(env3);
77888
78336
  }
77889
- var RemoteRouteUnsupportedError, RemoteRequestError, RemoteQuoteUnavailableError, RemoteWorkspaceMemberError, RemoteWorkspaceSelectionError, RemoteCapabilityUnavailableError, INVALID_SKILL_VERSION_RESPONSE = "Remote skill version payload did not match the expected contract.";
78337
+ var RemoteRouteUnsupportedError, RemoteRequestError, RemoteCreditCheckoutError, RemoteQuoteUnavailableError, RemoteWorkspaceMemberError, RemoteWorkspaceSelectionError, RemoteCapabilityUnavailableError, INVALID_SKILL_VERSION_RESPONSE = "Remote skill version payload did not match the expected contract.";
77890
78338
  var init_remote_client = __esm(() => {
77891
78339
  init_remote_recurring();
77892
78340
  init_remote_invitations();
@@ -77898,6 +78346,7 @@ var init_remote_client = __esm(() => {
77898
78346
  init_fleet_credentials();
77899
78347
  init_remote_account();
77900
78348
  init_remote_files();
78349
+ init_remote_credit_checkout();
77901
78350
  init_remote_quote_errors();
77902
78351
  init_remote_permissions();
77903
78352
  RemoteRouteUnsupportedError = class RemoteRouteUnsupportedError extends Error {
@@ -77922,6 +78371,19 @@ var init_remote_client = __esm(() => {
77922
78371
  this.name = "RemoteRequestError";
77923
78372
  }
77924
78373
  };
78374
+ RemoteCreditCheckoutError = class RemoteCreditCheckoutError extends RemoteRequestError {
78375
+ code;
78376
+ requestIdempotencyKey;
78377
+ retryAfterSeconds;
78378
+ constructor(code, status, requestIdempotencyKey, retryAfterSeconds) {
78379
+ super("/api/v1/billing/credits", status);
78380
+ this.code = code;
78381
+ this.requestIdempotencyKey = requestIdempotencyKey;
78382
+ this.retryAfterSeconds = retryAfterSeconds;
78383
+ this.name = "RemoteCreditCheckoutError";
78384
+ this.message = creditCheckoutMessages[code];
78385
+ }
78386
+ };
77925
78387
  RemoteQuoteUnavailableError = class RemoteQuoteUnavailableError extends RemoteRequestError {
77926
78388
  code;
77927
78389
  constructor(path, code) {
@@ -77962,7 +78424,7 @@ var init_remote_client = __esm(() => {
77962
78424
  });
77963
78425
 
77964
78426
  // src/lib/revision.ts
77965
- import { createHash as createHash14 } from "crypto";
78427
+ import { createHash as createHash15 } from "crypto";
77966
78428
  function revisionIdOf(content) {
77967
78429
  const canonical3 = JSON.stringify({
77968
78430
  slug: content.slug,
@@ -77977,7 +78439,7 @@ function revisionIdOf(content) {
77977
78439
  bundleSha256: content.bundleSha256 ?? null,
77978
78440
  bundleByteSize: content.bundleByteSize ?? null
77979
78441
  });
77980
- return createHash14("sha256").update(canonical3).digest("hex");
78442
+ return createHash15("sha256").update(canonical3).digest("hex");
77981
78443
  }
77982
78444
  var REVISION_ID_PATTERN;
77983
78445
  var init_revision = __esm(() => {
@@ -78007,7 +78469,7 @@ var init_skill_bundles = __esm(() => {
78007
78469
 
78008
78470
  // src/lib/pull.ts
78009
78471
  import { existsSync as existsSync21, mkdirSync as mkdirSync12, mkdtempSync as mkdtempSync3, readFileSync as readFileSync20, renameSync as renameSync8, rmSync as rmSync6, writeFileSync as writeFileSync10 } from "fs";
78010
- import { dirname as dirname16, join as join35 } from "path";
78472
+ import { dirname as dirname17, join as join35 } from "path";
78011
78473
  async function pullSkills(options = {}) {
78012
78474
  const client2 = options.client !== undefined ? options.client : await createRemoteSkillsClient();
78013
78475
  if (!client2) {
@@ -78311,7 +78773,7 @@ function installBundleAtomically(name, entries, options = {}, marker = {}) {
78311
78773
  try {
78312
78774
  for (const entry of entries) {
78313
78775
  const destination = join35(staging, entry.path);
78314
- mkdirSync12(dirname16(destination), { recursive: true });
78776
+ mkdirSync12(dirname17(destination), { recursive: true });
78315
78777
  writeFileSync10(destination, entry.bytes, { mode: entry.mode });
78316
78778
  }
78317
78779
  writePullMarker(staging, {
@@ -78426,8 +78888,8 @@ var init_pull = __esm(() => {
78426
78888
  });
78427
78889
 
78428
78890
  // src/lib/skill-context.ts
78429
- import { createHash as createHash15 } from "crypto";
78430
- import { resolve as resolve14 } from "path";
78891
+ import { createHash as createHash16 } from "crypto";
78892
+ import { resolve as resolve16 } from "path";
78431
78893
  function words2(value) {
78432
78894
  return new Set(value.toLowerCase().match(/[a-z0-9]+/g) ?? []);
78433
78895
  }
@@ -78462,7 +78924,7 @@ async function buildSkillContext(input2, options = {}) {
78462
78924
  const promptWords = words2(prompt);
78463
78925
  const promptNames = new Set(prompt.toLowerCase().match(/[a-z0-9]+(?:-[a-z0-9]+)*/g) ?? []);
78464
78926
  const loaded = new Set(resolved.session?.loaded ?? []);
78465
- const paths = [...input2.paths ?? [], ...input2.cwd ? [input2.cwd, resolve14(input2.cwd)] : []];
78927
+ const paths = [...input2.paths ?? [], ...input2.cwd ? [input2.cwd, resolve16(input2.cwd)] : []];
78466
78928
  const candidates = profile.selections.map((selection) => {
78467
78929
  const key = selectionKey(selection);
78468
78930
  if (input2.restore && loaded.has(key))
@@ -78515,7 +78977,7 @@ ${content}`;
78515
78977
  `);
78516
78978
  const receipt = {
78517
78979
  schemaVersion: 1,
78518
- id: createHash15("sha256").update(JSON.stringify({ profile: profile.profileRevision, sessionId, selections, omitted })).digest("hex"),
78980
+ id: createHash16("sha256").update(JSON.stringify({ profile: profile.profileRevision, sessionId, selections, omitted })).digest("hex"),
78519
78981
  profileId: profile.profileId,
78520
78982
  profileRevision: profile.profileRevision,
78521
78983
  authority: profile.authority,
@@ -78527,7 +78989,7 @@ ${content}`;
78527
78989
  selections
78528
78990
  };
78529
78991
  if (sessionId)
78530
- writeSelectionJson(sessionReceiptPath(sessionId, options), { ...resolved.receipt, sessionId, loaded: [...loaded] });
78992
+ writeSkillSession({ ...resolved.receipt, sessionId, loaded: [...loaded] }, { current: resolved.sessionSnapshot, parent: resolved.parentSnapshot }, options);
78531
78993
  return { context, selections, omitted, receipt };
78532
78994
  }
78533
78995
  var init_skill_context = __esm(() => {
@@ -78536,6 +78998,107 @@ var init_skill_context = __esm(() => {
78536
78998
  init_selected_document();
78537
78999
  });
78538
79000
 
79001
+ // src/lib/session-reconciliation.ts
79002
+ import { createHash as createHash17 } from "crypto";
79003
+ function exactTimestamp(value) {
79004
+ const parsed = value === undefined ? Number.NaN : Date.parse(value);
79005
+ if (!Number.isFinite(parsed) || new Date(parsed).toISOString() !== value) {
79006
+ throw new SkillSelectionError("SESSION_PLAN_WINDOW_INVALID", "The reviewed plan must include its exact canonical issuedAt and expiresAt timestamps.");
79007
+ }
79008
+ return parsed;
79009
+ }
79010
+ function assertPlanWindow(issuedAt, expiresAt, now3) {
79011
+ const issued = exactTimestamp(issuedAt), expires = exactTimestamp(expiresAt);
79012
+ if (expires - issued !== SESSION_RECONCILIATION_PLAN_TTL_MS) {
79013
+ throw new SkillSelectionError("SESSION_PLAN_WINDOW_INVALID", "A session reconciliation approval is valid for exactly five minutes and cannot be extended by the caller.");
79014
+ }
79015
+ if (now3 < issued || now3 >= expires) {
79016
+ throw new SkillSelectionError("SESSION_PLAN_EXPIRED", "The reviewed session reconciliation plan is not currently valid; inspect the receipt and prepare a new plan.");
79017
+ }
79018
+ }
79019
+ function inspectSkillSession(sessionId, options = {}) {
79020
+ const snapshot = readSkillSessionSnapshot(sessionId, options), { receipt } = snapshot;
79021
+ return {
79022
+ sessionId,
79023
+ path: snapshot.path,
79024
+ receiptSha256: snapshot.sha256,
79025
+ generation: snapshot.generation,
79026
+ verifiedAt: receipt.verifiedAt,
79027
+ authority: receipt.profile.authority,
79028
+ workspaceId: receipt.profile.workspaceId,
79029
+ profileId: receipt.profile.profileId,
79030
+ profileRevision: receipt.profile.profileRevision,
79031
+ selectionCount: receipt.profile.selections.length,
79032
+ loadedCount: receipt.loaded.length
79033
+ };
79034
+ }
79035
+ async function reconcileSkillSession(input2, options = {}) {
79036
+ if (![input2.fromProfile, input2.fromRevision, input2.selectionProfile, input2.profileRevision].every((value) => typeof value === "string" && value.trim()) || !/^[a-f0-9]{64}$/.test(input2.receiptSha256)) {
79037
+ throw new SkillSelectionError("INVALID_SESSION_RECONCILIATION", "Name the exact old receipt SHA256, old profile/revision and intended target profile/revision.");
79038
+ }
79039
+ if (input2.apply && (!input2.planDigest || !input2.planIssuedAt || !input2.planExpiresAt)) {
79040
+ throw new SkillSelectionError("SESSION_PLAN_REQUIRED", "Review the session reconciliation plan and provide its exact digest, issuedAt and expiresAt before applying it.");
79041
+ }
79042
+ if (!input2.apply && (input2.planDigest !== undefined || input2.planIssuedAt !== undefined || input2.planExpiresAt !== undefined)) {
79043
+ throw new SkillSelectionError("SESSION_PLAN_WINDOW_INVALID", "Plan timestamps are minted by the planner and may only be replayed with --apply.");
79044
+ }
79045
+ const now3 = (options.now ?? Date.now)();
79046
+ const issuedAt = input2.apply ? input2.planIssuedAt : new Date(now3).toISOString();
79047
+ const expiresAt = input2.apply ? input2.planExpiresAt : new Date(now3 + SESSION_RECONCILIATION_PLAN_TTL_MS).toISOString();
79048
+ if (input2.apply)
79049
+ assertPlanWindow(issuedAt, expiresAt, now3);
79050
+ const snapshot = readSkillSessionSnapshot(input2.sessionId, options), old = snapshot.receipt;
79051
+ if (snapshot.sha256 !== input2.receiptSha256 || old.profile.profileId !== input2.fromProfile || old.profile.profileRevision !== input2.fromRevision) {
79052
+ throw new SkillSelectionError("SESSION_RECEIPT_CHANGED", "The current session receipt does not match the reviewed old bytes, profile and revision.");
79053
+ }
79054
+ const client2 = options.client ?? await createProfileClient();
79055
+ const target = structuredClone(await client2.resolveProfile(input2.selectionProfile));
79056
+ validateResolvedProfile(target, client2.authority);
79057
+ if (target.profileId !== input2.selectionProfile || target.profileRevision !== input2.profileRevision) {
79058
+ throw new SkillSelectionError("SESSION_TARGET_CHANGED", "The API selection profile does not match the intended target revision; review the current selection before proceeding.");
79059
+ }
79060
+ if (old.profile.authority !== target.authority || old.profile.workspaceId !== target.workspaceId) {
79061
+ throw new SkillSelectionError("PROFILE_IDENTITY_MISMATCH", "A session reconciliation cannot change its Skills authority or workspace.");
79062
+ }
79063
+ const targetKeys = new Set(target.selections.map(selectionKey));
79064
+ const loaded = old.loaded.filter((key) => targetKeys.has(key));
79065
+ const replacementGeneration = nextSkillSessionGeneration(snapshot.generation);
79066
+ const plan = {
79067
+ schemaVersion: 1,
79068
+ issuedAt,
79069
+ expiresAt,
79070
+ sessionId: input2.sessionId,
79071
+ sessionPath: snapshot.path,
79072
+ before: { receiptSha256: snapshot.sha256, generation: snapshot.generation, profileId: old.profile.profileId, profileRevision: old.profile.profileRevision, selectionCount: old.profile.selections.length },
79073
+ target: { authority: target.authority, workspaceId: target.workspaceId, profileId: target.profileId, profileRevision: target.profileRevision, profileSha256: digest3(target), selectionCount: target.selections.length },
79074
+ replacementGeneration,
79075
+ retainedLoadedCount: loaded.length,
79076
+ retiredLoadedCount: old.loaded.length - loaded.length,
79077
+ scope: "Only this receipt; existing child sessions, project locks, shared profiles, hooks and running processes are unchanged."
79078
+ };
79079
+ const planDigest = digest3(plan);
79080
+ if (input2.planDigest !== undefined && input2.planDigest !== planDigest)
79081
+ throw new SkillSelectionError("SESSION_PLAN_CHANGED", "The session reconciliation plan differs from the reviewed plan.");
79082
+ if (!input2.apply)
79083
+ return { applied: false, plan, planDigest, archivePath: undefined, receiptPath: undefined, beforeSha256: snapshot.sha256, afterSha256: undefined };
79084
+ assertPlanWindow(issuedAt, expiresAt, (options.now ?? Date.now)());
79085
+ const replacement = {
79086
+ ...old,
79087
+ generation: replacementGeneration,
79088
+ verifiedAt: new Date((options.now ?? Date.now)()).toISOString(),
79089
+ profile: target,
79090
+ loaded
79091
+ };
79092
+ const result2 = replaceSkillSession(skillSessionSnapshotBinding(snapshot), replacement, { ...plan, planDigest }, options, () => assertPlanWindow(issuedAt, expiresAt, (options.now ?? Date.now)()));
79093
+ return { applied: true, plan, planDigest, ...result2 };
79094
+ }
79095
+ var SESSION_RECONCILIATION_PLAN_TTL_MS, digest3 = (value) => createHash17("sha256").update(JSON.stringify(value)).digest("hex");
79096
+ var init_session_reconciliation = __esm(() => {
79097
+ init_profile_client();
79098
+ init_selection_cache();
79099
+ SESSION_RECONCILIATION_PLAN_TTL_MS = 5 * 60 * 1000;
79100
+ });
79101
+
78539
79102
  // src/cli/commands/context.ts
78540
79103
  var exports_context = {};
78541
79104
  __export(exports_context, {
@@ -78545,7 +79108,7 @@ __export(exports_context, {
78545
79108
  parseSkillContextInput: () => parseSkillContextInput,
78546
79109
  contextResolverOptions: () => contextResolverOptions
78547
79110
  });
78548
- import { readSync as readSync8 } from "fs";
79111
+ import { readSync as readSync9 } from "fs";
78549
79112
  function selectedProfileId(explicit) {
78550
79113
  return explicit ?? process.env.HASNA_SKILLS_SELECTION_PROFILE ?? readManagedSkillPolicy()?.profileId ?? "default";
78551
79114
  }
@@ -78559,6 +79122,25 @@ function contextResolverOptions(options) {
78559
79122
  return { cached: true, authority };
78560
79123
  }
78561
79124
  function registerContextCommands(parent) {
79125
+ const sessions = parent.command("sessions").description("Inspect exact session pins and explicitly reconcile one reviewed receipt");
79126
+ sessions.command("show <id>").option("--json", "Return metadata as JSON", false).description("Inspect one session receipt without displaying payloads or changing its pin").action(async (id, options) => {
79127
+ try {
79128
+ const result2 = inspectSkillSession(id);
79129
+ await writeCliOutput(options.json ? JSON.stringify(result2) : `${JSON.stringify(id)}: ${result2.profileId} at ${result2.profileRevision}
79130
+ Receipt SHA256: ${result2.receiptSha256}`);
79131
+ } catch (error61) {
79132
+ reportContextError(error61, options.json);
79133
+ }
79134
+ });
79135
+ sessions.command("reconcile <id>").requiredOption("--from-profile <id>", "Expected current session profile").requiredOption("--from-revision <revision>", "Expected current session profile revision").requiredOption("--receipt-sha256 <sha256>", "Expected exact current receipt bytes").requiredOption("--selection-profile <id>", "Intended target selection profile").requiredOption("--profile-revision <revision>", "Expected current API target revision").option("--apply", "Archive the old receipt and atomically apply the reviewed plan", false).option("--plan-digest <sha256>", "Exact reviewed plan digest; required with --apply").option("--plan-issued-at <timestamp>", "Exact reviewed plan issuedAt; required with --apply").option("--plan-expires-at <timestamp>", "Exact reviewed plan expiresAt; required with --apply").option("--json", "Return the plan or application receipt as JSON", false).description("Plan an intentional migration of one session pin; ordinary hooks never migrate pins").action(async (id, options) => {
79136
+ try {
79137
+ const result2 = await reconcileSkillSession({ ...options, sessionId: id });
79138
+ await writeCliOutput(options.json ? JSON.stringify(result2) : result2.applied ? `Reconciled ${JSON.stringify(id)} to ${result2.plan.target.profileId} at ${result2.plan.target.profileRevision}.
79139
+ Preserved original receipt: ${result2.archivePath}` : `Planned one session reconciliation. Review --json output, then use --apply --plan-digest ${result2.planDigest} --plan-issued-at ${result2.plan.issuedAt} --plan-expires-at ${result2.plan.expiresAt}.`);
79140
+ } catch (error61) {
79141
+ reportContextError(error61, options.json);
79142
+ }
79143
+ });
78562
79144
  parent.command("load <skill>").description("Load an exact API-selected skill and return its version/digest receipt").option("--selection-profile <id>", "Selection profile (separate from the credential --profile)").option("--cached", "Use only an explicitly selected verified cache, at most 24 hours old", false).option("--session <id>", "Pin this load to a session").option("--file <path>", "Read an exact bundle file (default: SKILL.md, README.md, then CLAUDE.md)").option("--json", "Return content and provenance as JSON", false).action(async (skill, options) => {
78563
79145
  try {
78564
79146
  const result2 = await loadSelectedSkill(skill, selectedProfileId(options.selectionProfile), {
@@ -78604,7 +79186,7 @@ async function readContextStdin() {
78604
79186
  let size2 = 0;
78605
79187
  while (true) {
78606
79188
  const chunk2 = Buffer.allocUnsafe(8192);
78607
- const count = readSync8(0, chunk2, 0, chunk2.length, null);
79189
+ const count = readSync9(0, chunk2, 0, chunk2.length, null);
78608
79190
  if (count === 0)
78609
79191
  break;
78610
79192
  size2 += count;
@@ -78662,6 +79244,7 @@ var init_context = __esm(() => {
78662
79244
  init_selection_resolver();
78663
79245
  init_selection_cache();
78664
79246
  init_managed_policy();
79247
+ init_session_reconciliation();
78665
79248
  });
78666
79249
 
78667
79250
  // src/cli/commands/profile-sync.ts
@@ -79080,12 +79663,12 @@ function handleBrowseError(error61) {
79080
79663
  async function writeJson(value, space) {
79081
79664
  const text3 = `${JSON.stringify(value, null, space)}
79082
79665
  `;
79083
- await new Promise((resolve15, reject2) => {
79666
+ await new Promise((resolve17, reject2) => {
79084
79667
  process.stdout.write(text3, (error61) => {
79085
79668
  if (error61)
79086
79669
  reject2(error61);
79087
79670
  else
79088
- resolve15();
79671
+ resolve17();
79089
79672
  });
79090
79673
  });
79091
79674
  }
@@ -80429,7 +81012,7 @@ var init_init = __esm(() => {
80429
81012
  });
80430
81013
 
80431
81014
  // src/lib/home-adoption.ts
80432
- import { constants as constants10, closeSync as closeSync10, fstatSync as fstatSync10, lstatSync as lstatSync18, openSync as openSync10, readSync as readSync9, existsSync as existsSync24, mkdirSync as mkdirSync13, readdirSync as readdirSync13, readFileSync as readFileSync25, rmSync as rmSync7, statSync as statSync12, writeFileSync as writeFileSync12 } from "fs";
81015
+ import { constants as constants11, closeSync as closeSync11, fstatSync as fstatSync11, lstatSync as lstatSync19, openSync as openSync11, readSync as readSync10, existsSync as existsSync24, mkdirSync as mkdirSync13, readdirSync as readdirSync13, readFileSync as readFileSync25, rmSync as rmSync7, statSync as statSync12, writeFileSync as writeFileSync12 } from "fs";
80433
81016
  import { homedir as homedir7 } from "os";
80434
81017
  import { join as join38 } from "path";
80435
81018
  function indexCanonicalCorpus(corpusRoot) {
@@ -80584,25 +81167,25 @@ function adoptUnmarkedHomes(options = {}) {
80584
81167
  function pruneOwnership(dir) {
80585
81168
  let descriptor;
80586
81169
  try {
80587
- const directory = lstatSync18(dir);
81170
+ const directory = lstatSync19(dir);
80588
81171
  if (!directory.isDirectory())
80589
81172
  return;
80590
- const markerPath = join38(dir, SYNC_MARKER_FILE), markerPathBefore = lstatSync18(markerPath);
81173
+ const markerPath = join38(dir, SYNC_MARKER_FILE), markerPathBefore = lstatSync19(markerPath);
80591
81174
  if (!markerPathBefore.isFile())
80592
81175
  return;
80593
- descriptor = openSync10(markerPath, constants10.O_RDONLY | constants10.O_NOFOLLOW | constants10.O_NONBLOCK);
80594
- const before2 = fstatSync10(descriptor);
81176
+ descriptor = openSync11(markerPath, constants11.O_RDONLY | constants11.O_NOFOLLOW | constants11.O_NONBLOCK);
81177
+ const before2 = fstatSync11(descriptor);
80595
81178
  if (!before2.isFile() || before2.dev !== markerPathBefore.dev || before2.ino !== markerPathBefore.ino || before2.size !== markerPathBefore.size || before2.mtimeMs !== markerPathBefore.mtimeMs || before2.ctimeMs !== markerPathBefore.ctimeMs || before2.size < 1 || before2.size > 65536)
80596
81179
  return;
80597
81180
  const bytes = Buffer.alloc(before2.size + 1);
80598
81181
  let length = 0;
80599
81182
  while (length < bytes.length) {
80600
- const count = readSync9(descriptor, bytes, length, bytes.length - length, length);
81183
+ const count = readSync10(descriptor, bytes, length, bytes.length - length, length);
80601
81184
  if (!count)
80602
81185
  break;
80603
81186
  length += count;
80604
81187
  }
80605
- const after2 = fstatSync10(descriptor), current = lstatSync18(dir), markerPathAfter = lstatSync18(markerPath);
81188
+ const after2 = fstatSync11(descriptor), current = lstatSync19(dir), markerPathAfter = lstatSync19(markerPath);
80606
81189
  if (!markerPathAfter.isFile() || markerPathAfter.dev !== before2.dev || markerPathAfter.ino !== before2.ino || markerPathAfter.size !== before2.size || markerPathAfter.mtimeMs !== before2.mtimeMs || markerPathAfter.ctimeMs !== before2.ctimeMs || length !== before2.size || after2.size !== before2.size || after2.mtimeMs !== before2.mtimeMs || after2.ctimeMs !== before2.ctimeMs || !current.isDirectory() || current.dev !== directory.dev || current.ino !== directory.ino)
80607
81190
  return;
80608
81191
  const text3 = bytes.subarray(0, length).toString("utf8"), marker = JSON.parse(text3);
@@ -80613,7 +81196,7 @@ function pruneOwnership(dir) {
80613
81196
  return;
80614
81197
  } finally {
80615
81198
  if (descriptor !== undefined)
80616
- closeSync10(descriptor);
81199
+ closeSync11(descriptor);
80617
81200
  }
80618
81201
  }
80619
81202
  function pruneStrayHomes(options = {}) {
@@ -80798,7 +81381,7 @@ var init_home_census = __esm(() => {
80798
81381
  });
80799
81382
 
80800
81383
  // src/cli/env-assignment.ts
80801
- import { closeSync as closeSync11, constants as constants11, fstatSync as fstatSync11, ftruncateSync as ftruncateSync2, lstatSync as lstatSync19, openSync as openSync11, readFileSync as readFileSync27, writeSync as writeSync3 } from "fs";
81384
+ import { closeSync as closeSync12, constants as constants12, fstatSync as fstatSync12, ftruncateSync as ftruncateSync2, lstatSync as lstatSync20, openSync as openSync12, readFileSync as readFileSync27, writeSync as writeSync3 } from "fs";
80802
81385
  function serializeValue(value) {
80803
81386
  if (controls.test(value))
80804
81387
  throw new EnvAssignmentError("Environment values cannot contain control characters or newlines.");
@@ -80877,7 +81460,7 @@ function setEnvAssignment(path, assignment) {
80877
81460
  try {
80878
81461
  const previous = (() => {
80879
81462
  try {
80880
- return lstatSync19(path);
81463
+ return lstatSync20(path);
80881
81464
  } catch (error61) {
80882
81465
  if (error61.code === "ENOENT")
80883
81466
  return;
@@ -80886,8 +81469,8 @@ function setEnvAssignment(path, assignment) {
80886
81469
  })();
80887
81470
  if (previous && !previous.isFile())
80888
81471
  throw new EnvAssignmentError("The project .env must be a regular file, not a symlink or special file.");
80889
- descriptor = openSync11(path, previous ? constants11.O_RDWR | constants11.O_NOFOLLOW | constants11.O_NONBLOCK : constants11.O_WRONLY | constants11.O_CREAT | constants11.O_EXCL | constants11.O_NOFOLLOW, 384);
80890
- const opened = fstatSync11(descriptor);
81472
+ descriptor = openSync12(path, previous ? constants12.O_RDWR | constants12.O_NOFOLLOW | constants12.O_NONBLOCK : constants12.O_WRONLY | constants12.O_CREAT | constants12.O_EXCL | constants12.O_NOFOLLOW, 384);
81473
+ const opened = fstatSync12(descriptor);
80891
81474
  if (!opened.isFile() || previous && (opened.ino !== previous.ino || opened.dev !== previous.dev)) {
80892
81475
  throw new EnvAssignmentError("The project .env changed while opening it; retry with a regular file.");
80893
81476
  }
@@ -80914,7 +81497,7 @@ function setEnvAssignment(path, assignment) {
80914
81497
  throw new EnvAssignmentError("Cannot safely read or write the project .env file.");
80915
81498
  } finally {
80916
81499
  if (descriptor !== undefined)
80917
- closeSync11(descriptor);
81500
+ closeSync12(descriptor);
80918
81501
  }
80919
81502
  }
80920
81503
  var INVALID_LAYOUT = "Cannot safely update .env with multiline or unsupported assignments. Use single-line KEY=VALUE entries or edit the file manually.", controls, EnvAssignmentError;
@@ -81397,12 +81980,12 @@ function parseExecution(value) {
81397
81980
  ].includes(v.status) || typeof v.skill !== "string" || typeof v.version !== "string" || !Array.isArray(v.artifacts))
81398
81981
  throw Error("Unsupported cloud execution response");
81399
81982
  runId(v.id);
81400
- for (const field of [
81983
+ for (const field2 of [
81401
81984
  "bundleDigest",
81402
81985
  "inputDigest",
81403
81986
  "runtimeImageDigest"
81404
81987
  ])
81405
- if (typeof v[field] !== "string" || !/^(sha256:)?[a-f0-9]{64}$/.test(v[field]))
81988
+ if (typeof v[field2] !== "string" || !/^(sha256:)?[a-f0-9]{64}$/.test(v[field2]))
81406
81989
  throw Error("Invalid cloud execution integrity receipt");
81407
81990
  return v;
81408
81991
  }
@@ -81423,11 +82006,11 @@ var init_cloud_executions = __esm(() => {
81423
82006
  // node_modules/@hasna/secrets/dist/sdk.js
81424
82007
  import { isIP as isIP3 } from "net";
81425
82008
  import { spawnSync as spawnSync2 } from "child_process";
81426
- import { closeSync as closeSync12, fstatSync as fstatSync12, openSync as openSync12, readFileSync as readFileSync29 } from "fs";
82009
+ import { closeSync as closeSync13, fstatSync as fstatSync13, openSync as openSync13, readFileSync as readFileSync29 } from "fs";
81427
82010
  import { O_NOFOLLOW as O_NOFOLLOW3, O_NONBLOCK as O_NONBLOCK3, O_RDONLY as O_RDONLY3 } from "constants";
81428
82011
  import { createRequire as createRequire2 } from "module";
81429
82012
  import { hostname as osHostname2 } from "os";
81430
- import { isAbsolute as isAbsolute13, join as join41 } from "path";
82013
+ import { isAbsolute as isAbsolute15, join as join41 } from "path";
81431
82014
  import { createRequire as createRequire22 } from "module";
81432
82015
  function envToken2(name) {
81433
82016
  return name.toUpperCase().replace(/-/g, "_");
@@ -81451,7 +82034,7 @@ function homeDir2(env3) {
81451
82034
  }
81452
82035
  function absoluteOverride2(env3, key) {
81453
82036
  const value = env3[key]?.trim();
81454
- return value && isAbsolute13(value) ? value : null;
82037
+ return value && isAbsolute15(value) ? value : null;
81455
82038
  }
81456
82039
  function hasnaHomeDir2(env3) {
81457
82040
  const override = absoluteOverride2(env3, HASNA_HOME_ENV_KEY2);
@@ -81528,7 +82111,7 @@ function readAppConfigFile2(path) {
81528
82111
  };
81529
82112
  let fd = -1;
81530
82113
  try {
81531
- fd = openSync12(path, O_RDONLY3 | O_NOFOLLOW3 | O_NONBLOCK3);
82114
+ fd = openSync13(path, O_RDONLY3 | O_NOFOLLOW3 | O_NONBLOCK3);
81532
82115
  } catch (error61) {
81533
82116
  const code = error61.code;
81534
82117
  if (code === "ENOENT" || code === "ENOTDIR")
@@ -81538,7 +82121,7 @@ function readAppConfigFile2(path) {
81538
82121
  unsafe(`the path could not be opened (${code ?? "unknown error"})`);
81539
82122
  }
81540
82123
  try {
81541
- const before2 = fstatSync12(fd);
82124
+ const before2 = fstatSync13(fd);
81542
82125
  if (!before2.isFile())
81543
82126
  unsafe("the path is not a regular file");
81544
82127
  if (!configFileModeAllowed2(before2.mode)) {
@@ -81550,14 +82133,14 @@ function readAppConfigFile2(path) {
81550
82133
  if (before2.size > MAX_CREDENTIAL_FILE_BYTES2)
81551
82134
  unsafe("the file exceeds the size limit");
81552
82135
  const bytes = readFileSync29(fd);
81553
- const after2 = fstatSync12(fd);
82136
+ const after2 = fstatSync13(fd);
81554
82137
  if (!configFileReadsCoherent2(before2, after2)) {
81555
82138
  unsafe("the file changed while being read");
81556
82139
  }
81557
82140
  return parseEnvFile2(bytes.toString("utf8"));
81558
82141
  } finally {
81559
82142
  if (fd !== -1)
81560
- closeSync12(fd);
82143
+ closeSync13(fd);
81561
82144
  }
81562
82145
  }
81563
82146
  function readCredentialFile2(path, apiKeyKeys) {
@@ -82588,7 +83171,7 @@ function createSecretsClientFromEnv(env3 = process.env, overrides = {}) {
82588
83171
  });
82589
83172
  return new SecretsClient({ ...clientOverrides, baseUrl, apiKey });
82590
83173
  }
82591
- var __esm2 = (fn, res) => () => (fn && (res = fn(fn = 0)), res), CREDENTIAL_PROFILE_ENV_KEY2 = "HASNA_PROFILE", CredentialResolutionError2, CredentialFileUnsafeError2, HASNA_HOME_ENV_KEY2 = "HASNA_HOME", HASNA_CONFIG_HOME_ENV_KEY2 = "HASNA_CONFIG_HOME", KEYCHAIN_STATION_ENV_KEY2 = "HASNA_STATION", HASNA_HOME_DIR2 = ".hasna", CONFIG_SUBDIR2 = "config", CREDENTIALS_FILE2 = "credentials", KEYCHAIN_SECURITY_BIN2 = "/usr/bin/security", KEYCHAIN_SERVICE_PREFIX2 = "hasna.credentials", KEYCHAIN_ITEM_NOT_FOUND_STATUS2 = 44, KEYCHAIN_SPAWN_TIMEOUT_MS2 = 1e4, MAX_CREDENTIAL_FILE_BYTES2, SAFE_APP_SLUG2, SAFE_PROFILE2, ILLEGAL_IN_HEADER_VALUE2, VAULT_POINTER_SHAPE2, CREDENTIAL_SHAPED_KEY2, INSPECT_CUSTOM2, CREDENTIAL_SEAL2, CALLER_SUPPLIED_CREDENTIAL_PROVIDER_SOURCE = "caller-supplied CredentialProvider", AMBIENT_ENVIRONMENT2, SECRETS_PACKAGE_SPECIFIER, requireSecretsSdk2, DEFAULT_FLEET_GATEWAY_ORIGIN2 = "https://api.hasna.com", DEFAULT_AUTHORITY_SOURCE = "default", ASCII_CONTROL_PATTERN2, DNS_LABEL_PATTERN2, ClientTransportConfigurationError2, HasnaHttpError, DEFAULT_RETRY_STATUSES, IDEMPOTENT_METHODS2, AUTHORITY_OVERRIDE_HEADERS2, defaultSleep = (ms) => new Promise((resolve15) => setTimeout(resolve15, ms)), init_transport2, MAX_CREDENTIAL_FILE_BYTES22, INSPECT_CUSTOM22, CREDENTIAL_SEAL22, AMBIENT_ENVIRONMENT22, SECRETS_PACKAGE_SPECIFIER2, requireSecretsSdk22, IDEMPOTENT_METHODS22, AUTHORITY_OVERRIDE_HEADERS22, init_storage, PATHS_RESOLVER_APP_SLUG_RE3, SQLITE_SIDECAR_FILES, LEGACY_SERVICE_FILES, init_data_dir, SecretsTestIsolationError, TEST_ENTRYPOINT_RE, init_test_isolation, init_client, ApiError;
83174
+ var __esm2 = (fn, res) => () => (fn && (res = fn(fn = 0)), res), CREDENTIAL_PROFILE_ENV_KEY2 = "HASNA_PROFILE", CredentialResolutionError2, CredentialFileUnsafeError2, HASNA_HOME_ENV_KEY2 = "HASNA_HOME", HASNA_CONFIG_HOME_ENV_KEY2 = "HASNA_CONFIG_HOME", KEYCHAIN_STATION_ENV_KEY2 = "HASNA_STATION", HASNA_HOME_DIR2 = ".hasna", CONFIG_SUBDIR2 = "config", CREDENTIALS_FILE2 = "credentials", KEYCHAIN_SECURITY_BIN2 = "/usr/bin/security", KEYCHAIN_SERVICE_PREFIX2 = "hasna.credentials", KEYCHAIN_ITEM_NOT_FOUND_STATUS2 = 44, KEYCHAIN_SPAWN_TIMEOUT_MS2 = 1e4, MAX_CREDENTIAL_FILE_BYTES2, SAFE_APP_SLUG2, SAFE_PROFILE2, ILLEGAL_IN_HEADER_VALUE2, VAULT_POINTER_SHAPE2, CREDENTIAL_SHAPED_KEY2, INSPECT_CUSTOM2, CREDENTIAL_SEAL2, CALLER_SUPPLIED_CREDENTIAL_PROVIDER_SOURCE = "caller-supplied CredentialProvider", AMBIENT_ENVIRONMENT2, SECRETS_PACKAGE_SPECIFIER, requireSecretsSdk2, DEFAULT_FLEET_GATEWAY_ORIGIN2 = "https://api.hasna.com", DEFAULT_AUTHORITY_SOURCE = "default", ASCII_CONTROL_PATTERN2, DNS_LABEL_PATTERN2, ClientTransportConfigurationError2, HasnaHttpError, DEFAULT_RETRY_STATUSES, IDEMPOTENT_METHODS2, AUTHORITY_OVERRIDE_HEADERS2, defaultSleep = (ms) => new Promise((resolve17) => setTimeout(resolve17, ms)), init_transport2, MAX_CREDENTIAL_FILE_BYTES22, INSPECT_CUSTOM22, CREDENTIAL_SEAL22, AMBIENT_ENVIRONMENT22, SECRETS_PACKAGE_SPECIFIER2, requireSecretsSdk22, IDEMPOTENT_METHODS22, AUTHORITY_OVERRIDE_HEADERS22, init_storage, PATHS_RESOLVER_APP_SLUG_RE3, SQLITE_SIDECAR_FILES, LEGACY_SERVICE_FILES, init_data_dir, SecretsTestIsolationError, TEST_ENTRYPOINT_RE, init_test_isolation, init_client, ApiError;
82592
83175
  var init_sdk = __esm(() => {
82593
83176
  init_transport2 = __esm2(() => {
82594
83177
  CredentialResolutionError2 = class CredentialResolutionError3 extends Error {
@@ -82723,7 +83306,7 @@ var init_sdk = __esm(() => {
82723
83306
  });
82724
83307
 
82725
83308
  // src/lib/execution-secrets.ts
82726
- import { constants as constants12, closeSync as closeSync13, fstatSync as fstatSync13, openSync as openSync13, readSync as readSync10, realpathSync as realpathSync6 } from "fs";
83309
+ import { constants as constants13, closeSync as closeSync14, fstatSync as fstatSync14, openSync as openSync14, readSync as readSync11, realpathSync as realpathSync6 } from "fs";
82727
83310
  import { hostname as stationHostname } from "os";
82728
83311
  function selectedSecretBindingsTemplate(scope, names, createClient2 = createSecretsClientFromEnv) {
82729
83312
  let secretsAuthority;
@@ -82747,7 +83330,7 @@ function refuse(code, message) {
82747
83330
  function record7(value) {
82748
83331
  return !!value && typeof value === "object" && !Array.isArray(value);
82749
83332
  }
82750
- function exactKeys(value, keys2) {
83333
+ function exactKeys2(value, keys2) {
82751
83334
  return Object.keys(value).length === keys2.length && keys2.every((key) => Object.hasOwn(value, key));
82752
83335
  }
82753
83336
  function identifier2(value) {
@@ -82767,13 +83350,13 @@ function declaredSecretNames(value) {
82767
83350
  function readSelectedSecretBindings(path) {
82768
83351
  let fd;
82769
83352
  try {
82770
- fd = openSync13(path, constants12.O_RDONLY | constants12.O_NOFOLLOW | constants12.O_NONBLOCK);
82771
- const stat2 = fstatSync13(fd);
83353
+ fd = openSync14(path, constants13.O_RDONLY | constants13.O_NOFOLLOW | constants13.O_NONBLOCK);
83354
+ const stat2 = fstatSync14(fd);
82772
83355
  if (!stat2.isFile() || stat2.size > 65536)
82773
83356
  throw new Error;
82774
83357
  const bytes = Buffer.alloc(65537);
82775
83358
  let size2 = 0, count;
82776
- while ((count = readSync10(fd, bytes, size2, bytes.length - size2, null)) > 0) {
83359
+ while ((count = readSync11(fd, bytes, size2, bytes.length - size2, null)) > 0) {
82777
83360
  size2 += count;
82778
83361
  if (size2 > 65536)
82779
83362
  throw new Error;
@@ -82783,11 +83366,11 @@ function readSelectedSecretBindings(path) {
82783
83366
  return refuse("INVALID_SECRET_BINDINGS", "Secret bindings must be a regular JSON file of at most 64 KiB, containing reference names only.");
82784
83367
  } finally {
82785
83368
  if (fd !== undefined)
82786
- closeSync13(fd);
83369
+ closeSync14(fd);
82787
83370
  }
82788
83371
  }
82789
83372
  function validateSelectedSecretBindings(value, scope, names) {
82790
- if (!record7(value) || !exactKeys(value, ["schema", "selection", "consumer", "secretsAuthority", "bindings"]) || value.schema !== "hasna.skills-secret-bindings.v1" || !record7(value.selection) || !exactKeys(value.selection, ["authority", "workspaceId", "profileId", "profileRevision", "slug", "version", "bundleDigest"]) || !record7(value.consumer) || !exactKeys(value.consumer, ["stationId", "workspaceDirectory"]) || !record7(value.bindings)) {
83373
+ if (!record7(value) || !exactKeys2(value, ["schema", "selection", "consumer", "secretsAuthority", "bindings"]) || value.schema !== "hasna.skills-secret-bindings.v1" || !record7(value.selection) || !exactKeys2(value.selection, ["authority", "workspaceId", "profileId", "profileRevision", "slug", "version", "bundleDigest"]) || !record7(value.consumer) || !exactKeys2(value.consumer, ["stationId", "workspaceDirectory"]) || !record7(value.bindings)) {
82791
83374
  return refuse("INVALID_SECRET_BINDINGS", "Secret bindings do not match the hasna.skills-secret-bindings.v1 contract.");
82792
83375
  }
82793
83376
  for (const [key, expected] of Object.entries({ authority: scope.selection.authority, workspaceId: scope.selection.workspaceId, profileId: scope.profileId, profileRevision: scope.selection.profileRevision, slug: scope.selection.slug, version: scope.selection.version, bundleDigest: scope.selection.bundleDigest })) {
@@ -82812,7 +83395,7 @@ function validateSelectedSecretBindings(value, scope, names) {
82812
83395
  } catch {
82813
83396
  return refuse("INVALID_SECRET_BINDINGS", "Secret bindings require a canonical HTTPS Secrets /v1 authority (loopback HTTP is allowed).");
82814
83397
  }
82815
- if (!exactKeys(value.bindings, names) || Object.values(value.bindings).some((key) => !identifier2(key) || !/^[A-Za-z0-9][A-Za-z0-9._/-]*$/.test(key) || key.split("/").some((part) => !part || part === "." || part === ".."))) {
83398
+ if (!exactKeys2(value.bindings, names) || Object.values(value.bindings).some((key) => !identifier2(key) || !/^[A-Za-z0-9][A-Za-z0-9._/-]*$/.test(key) || key.split("/").some((part) => !part || part === "." || part === ".."))) {
82816
83399
  return refuse("INVALID_SECRET_BINDINGS", "Bind every declared environment name exactly once to a vault key; undeclared bindings and values are refused.");
82817
83400
  }
82818
83401
  return structuredClone(value);
@@ -82990,7 +83573,7 @@ var init_execution_grants = __esm(() => {
82990
83573
  });
82991
83574
 
82992
83575
  // src/lib/execution-grant-client.ts
82993
- import { isDeepStrictEqual as isDeepStrictEqual3 } from "util";
83576
+ import { isDeepStrictEqual as isDeepStrictEqual4 } from "util";
82994
83577
  function id(value) {
82995
83578
  if (!grantIdentifier(value))
82996
83579
  throw new Error("Invalid execution grant profile or revision identifier.");
@@ -83042,7 +83625,7 @@ async function saveExecutionGrantPolicy(profileId, grants, revision) {
83042
83625
  headers: revision === undefined ? { "If-None-Match": "*" } : { "If-Match": `"${revision}"` },
83043
83626
  body: JSON.stringify({ grants: snapshot })
83044
83627
  }));
83045
- if (policy.profileId !== profileId || policy.previousRevision !== (revision ?? null) || !isDeepStrictEqual3(policy.grants, snapshot)) {
83628
+ if (policy.profileId !== profileId || policy.previousRevision !== (revision ?? null) || !isDeepStrictEqual4(policy.grants, snapshot)) {
83046
83629
  throw new Error("The API did not preserve the reviewed execution grant policy; read it before retrying.");
83047
83630
  }
83048
83631
  return policy;
@@ -83053,7 +83636,7 @@ async function resolveExecutionGrant(input2) {
83053
83636
  if (!grantRecord(value) || Object.keys(value).length !== 3 || !grantIdentifier(value.policyRevision) || !grantIdentifier(value.grantId) || !grantRecord(value.bindings)) {
83054
83637
  throw new SkillSelectionError("INVALID_EXECUTION_GRANT", "The Skills API returned an invalid execution grant.");
83055
83638
  }
83056
- if (!isDeepStrictEqual3(value.bindings.selection, snapshot.selection) || !isDeepStrictEqual3(value.bindings.consumer, snapshot.consumer)) {
83639
+ if (!isDeepStrictEqual4(value.bindings.selection, snapshot.selection) || !isDeepStrictEqual4(value.bindings.consumer, snapshot.consumer)) {
83057
83640
  throw new SkillSelectionError("EXECUTION_GRANT_SCOPE_MISMATCH", "The Skills API returned a grant for a different selection or consumer.");
83058
83641
  }
83059
83642
  return value;
@@ -83072,10 +83655,10 @@ __export(exports_selected_run, {
83072
83655
  prepareSelectedSecretBindings: () => prepareSelectedSecretBindings,
83073
83656
  executeSelectedLocal: () => executeSelectedLocal
83074
83657
  });
83075
- import { createHash as createHash16 } from "crypto";
83658
+ import { createHash as createHash18 } from "crypto";
83076
83659
  import { spawn as spawn2 } from "child_process";
83077
83660
  import { mkdirSync as mkdirSync14, mkdtempSync as mkdtempSync4, writeFileSync as writeFileSync13, realpathSync as realpathSync7 } from "fs";
83078
- import { dirname as dirname17, join as join42, resolve as resolve15 } from "path";
83661
+ import { dirname as dirname18, join as join42, resolve as resolve17 } from "path";
83079
83662
  import { tmpdir, hostname as stationHostname2 } from "os";
83080
83663
  async function resolveSelectedRun(spec, profileId, options = {}) {
83081
83664
  const context = await resolveSelectionContext(profileId, options);
@@ -83164,11 +83747,11 @@ async function executeSelectedLocal(selected, options = {}) {
83164
83747
  throw new SkillSelectionError("INVALID_BUNDLE_PATH", "The execution bundle path exceeds its limit.");
83165
83748
  });
83166
83749
  const destination = join42(runDirectory, entry.path);
83167
- mkdirSync14(dirname17(destination), { recursive: true, mode: 448 });
83750
+ mkdirSync14(dirname18(destination), { recursive: true, mode: 448 });
83168
83751
  writeFileSync13(destination, entry.bytes, { flag: "wx", mode: entry.mode & 511 });
83169
83752
  }
83170
83753
  env3.SKILLS_INPUT_JSON = input2;
83171
- env3.SKILLS_WORKSPACE_DIR = resolve15(options.cwd ?? process.cwd());
83754
+ env3.SKILLS_WORKSPACE_DIR = resolve17(options.cwd ?? process.cwd());
83172
83755
  env3.SKILLS_RUN_DIR = runDirectory;
83173
83756
  if (runtime.version) {
83174
83757
  const version2 = await subprocess([executable, ...runtimeName === "bun" ? ["--no-env-file"] : [], "--version"], runDirectory, env3, "", Math.min(timeoutMs, 5000));
@@ -83198,7 +83781,7 @@ async function executeSelectedLocal(selected, options = {}) {
83198
83781
  selection: selection2,
83199
83782
  target: "local",
83200
83783
  runtime: runtimeName,
83201
- inputDigest: `sha256:${createHash16("sha256").update(input2).digest("hex")}`,
83784
+ inputDigest: `sha256:${createHash18("sha256").update(input2).digest("hex")}`,
83202
83785
  runDirectory,
83203
83786
  ...executionGrant ? { executionGrant } : {},
83204
83787
  ...bindings ? { secretBinding: { schema: bindings.schema, selection: bindings.selection, consumer: bindings.consumer, secretsAuthority: bindings.secretsAuthority, bindings: bindings.bindings } } : {},
@@ -87415,7 +87998,7 @@ var init_runs = __esm(() => {
87415
87998
  });
87416
87999
 
87417
88000
  // src/lib/run-state.ts
87418
- import { createHash as createHash17, randomBytes } from "crypto";
88001
+ import { createHash as createHash19, randomBytes } from "crypto";
87419
88002
  import { existsSync as existsSync27, mkdirSync as mkdirSync15, readFileSync as readFileSync30, readdirSync as readdirSync16, statSync as statSync15, writeFileSync as writeFileSync14 } from "fs";
87420
88003
  import { extname, join as join43, relative as relative6 } from "path";
87421
88004
  function createSkillRun(params, targetDir = process.cwd()) {
@@ -87552,7 +88135,7 @@ function collectRunArtifacts(context) {
87552
88135
  artifacts.push({
87553
88136
  path: toProjectRelative(context.targetDir, path),
87554
88137
  mime: mimeForPath(path),
87555
- sha256: createHash17("sha256").update(bytes).digest("hex"),
88138
+ sha256: createHash19("sha256").update(bytes).digest("hex"),
87556
88139
  sizeBytes: stat2.size
87557
88140
  });
87558
88141
  }
@@ -88555,12 +89138,12 @@ class StdioServerTransport {
88555
89138
  this.onclose?.();
88556
89139
  }
88557
89140
  send(message) {
88558
- return new Promise((resolve16) => {
89141
+ return new Promise((resolve18) => {
88559
89142
  const json2 = serializeMessage(message);
88560
89143
  if (this._stdout.write(json2)) {
88561
- resolve16();
89144
+ resolve18();
88562
89145
  } else {
88563
- this._stdout.once("drain", resolve16);
89146
+ this._stdout.once("drain", resolve18);
88564
89147
  }
88565
89148
  });
88566
89149
  }
@@ -88602,7 +89185,7 @@ var init_schemas3 = __esm(() => {
88602
89185
  own(this, "with", value);
88603
89186
  },
88604
89187
  parse(data, params) {
88605
- return parse5(this, data, params, { callee: this.parse });
89188
+ return parse6(this, data, params, { callee: this.parse });
88606
89189
  },
88607
89190
  parseAsync(data, params) {
88608
89191
  return parseAsync(this, data, params, { callee: this.parseAsync });
@@ -90746,7 +91329,7 @@ class Protocol {
90746
91329
  return;
90747
91330
  }
90748
91331
  const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1000;
90749
- await new Promise((resolve16) => setTimeout(resolve16, pollInterval));
91332
+ await new Promise((resolve18) => setTimeout(resolve18, pollInterval));
90750
91333
  options?.signal?.throwIfAborted();
90751
91334
  }
90752
91335
  } catch (error61) {
@@ -90758,7 +91341,7 @@ class Protocol {
90758
91341
  }
90759
91342
  request(request2, resultSchema, options) {
90760
91343
  const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
90761
- return new Promise((resolve16, reject2) => {
91344
+ return new Promise((resolve18, reject2) => {
90762
91345
  const earlyReject = (error61) => {
90763
91346
  reject2(error61);
90764
91347
  };
@@ -90836,7 +91419,7 @@ class Protocol {
90836
91419
  if (!parseResult.success) {
90837
91420
  reject2(parseResult.error);
90838
91421
  } else {
90839
- resolve16(parseResult.data);
91422
+ resolve18(parseResult.data);
90840
91423
  }
90841
91424
  } catch (error61) {
90842
91425
  reject2(error61);
@@ -91027,12 +91610,12 @@ class Protocol {
91027
91610
  interval = task.pollInterval;
91028
91611
  }
91029
91612
  } catch {}
91030
- return new Promise((resolve16, reject2) => {
91613
+ return new Promise((resolve18, reject2) => {
91031
91614
  if (signal.aborted) {
91032
91615
  reject2(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
91033
91616
  return;
91034
91617
  }
91035
- const timeoutId = setTimeout(resolve16, interval);
91618
+ const timeoutId = setTimeout(resolve18, interval);
91036
91619
  signal.addEventListener("abort", () => {
91037
91620
  clearTimeout(timeoutId);
91038
91621
  reject2(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
@@ -91509,11 +92092,11 @@ var require_codegen = __commonJS((exports) => {
91509
92092
  const rhs = this.rhs === undefined ? "" : ` = ${this.rhs}`;
91510
92093
  return `${varKind} ${this.name}${rhs};` + _n;
91511
92094
  }
91512
- optimizeNames(names, constants13) {
92095
+ optimizeNames(names, constants14) {
91513
92096
  if (!names[this.name.str])
91514
92097
  return;
91515
92098
  if (this.rhs)
91516
- this.rhs = optimizeExpr(this.rhs, names, constants13);
92099
+ this.rhs = optimizeExpr(this.rhs, names, constants14);
91517
92100
  return this;
91518
92101
  }
91519
92102
  get names() {
@@ -91531,10 +92114,10 @@ var require_codegen = __commonJS((exports) => {
91531
92114
  render({ _n }) {
91532
92115
  return `${this.lhs} = ${this.rhs};` + _n;
91533
92116
  }
91534
- optimizeNames(names, constants13) {
92117
+ optimizeNames(names, constants14) {
91535
92118
  if (this.lhs instanceof code_1.Name && !names[this.lhs.str] && !this.sideEffects)
91536
92119
  return;
91537
- this.rhs = optimizeExpr(this.rhs, names, constants13);
92120
+ this.rhs = optimizeExpr(this.rhs, names, constants14);
91538
92121
  return this;
91539
92122
  }
91540
92123
  get names() {
@@ -91600,8 +92183,8 @@ var require_codegen = __commonJS((exports) => {
91600
92183
  optimizeNodes() {
91601
92184
  return `${this.code}` ? this : undefined;
91602
92185
  }
91603
- optimizeNames(names, constants13) {
91604
- this.code = optimizeExpr(this.code, names, constants13);
92186
+ optimizeNames(names, constants14) {
92187
+ this.code = optimizeExpr(this.code, names, constants14);
91605
92188
  return this;
91606
92189
  }
91607
92190
  get names() {
@@ -91631,12 +92214,12 @@ var require_codegen = __commonJS((exports) => {
91631
92214
  }
91632
92215
  return nodes.length > 0 ? this : undefined;
91633
92216
  }
91634
- optimizeNames(names, constants13) {
92217
+ optimizeNames(names, constants14) {
91635
92218
  const { nodes } = this;
91636
92219
  let i = nodes.length;
91637
92220
  while (i--) {
91638
92221
  const n2 = nodes[i];
91639
- if (n2.optimizeNames(names, constants13))
92222
+ if (n2.optimizeNames(names, constants14))
91640
92223
  continue;
91641
92224
  subtractNames(names, n2.names);
91642
92225
  nodes.splice(i, 1);
@@ -91693,12 +92276,12 @@ var require_codegen = __commonJS((exports) => {
91693
92276
  return;
91694
92277
  return this;
91695
92278
  }
91696
- optimizeNames(names, constants13) {
92279
+ optimizeNames(names, constants14) {
91697
92280
  var _a3;
91698
- this.else = (_a3 = this.else) === null || _a3 === undefined ? undefined : _a3.optimizeNames(names, constants13);
91699
- if (!(super.optimizeNames(names, constants13) || this.else))
92281
+ this.else = (_a3 = this.else) === null || _a3 === undefined ? undefined : _a3.optimizeNames(names, constants14);
92282
+ if (!(super.optimizeNames(names, constants14) || this.else))
91700
92283
  return;
91701
- this.condition = optimizeExpr(this.condition, names, constants13);
92284
+ this.condition = optimizeExpr(this.condition, names, constants14);
91702
92285
  return this;
91703
92286
  }
91704
92287
  get names() {
@@ -91723,10 +92306,10 @@ var require_codegen = __commonJS((exports) => {
91723
92306
  render(opts) {
91724
92307
  return `for(${this.iteration})` + super.render(opts);
91725
92308
  }
91726
- optimizeNames(names, constants13) {
91727
- if (!super.optimizeNames(names, constants13))
92309
+ optimizeNames(names, constants14) {
92310
+ if (!super.optimizeNames(names, constants14))
91728
92311
  return;
91729
- this.iteration = optimizeExpr(this.iteration, names, constants13);
92312
+ this.iteration = optimizeExpr(this.iteration, names, constants14);
91730
92313
  return this;
91731
92314
  }
91732
92315
  get names() {
@@ -91764,10 +92347,10 @@ var require_codegen = __commonJS((exports) => {
91764
92347
  render(opts) {
91765
92348
  return `for(${this.varKind} ${this.name} ${this.loop} ${this.iterable})` + super.render(opts);
91766
92349
  }
91767
- optimizeNames(names, constants13) {
91768
- if (!super.optimizeNames(names, constants13))
92350
+ optimizeNames(names, constants14) {
92351
+ if (!super.optimizeNames(names, constants14))
91769
92352
  return;
91770
- this.iterable = optimizeExpr(this.iterable, names, constants13);
92353
+ this.iterable = optimizeExpr(this.iterable, names, constants14);
91771
92354
  return this;
91772
92355
  }
91773
92356
  get names() {
@@ -91812,11 +92395,11 @@ var require_codegen = __commonJS((exports) => {
91812
92395
  (_b = this.finally) === null || _b === undefined || _b.optimizeNodes();
91813
92396
  return this;
91814
92397
  }
91815
- optimizeNames(names, constants13) {
92398
+ optimizeNames(names, constants14) {
91816
92399
  var _a3, _b;
91817
- super.optimizeNames(names, constants13);
91818
- (_a3 = this.catch) === null || _a3 === undefined || _a3.optimizeNames(names, constants13);
91819
- (_b = this.finally) === null || _b === undefined || _b.optimizeNames(names, constants13);
92400
+ super.optimizeNames(names, constants14);
92401
+ (_a3 = this.catch) === null || _a3 === undefined || _a3.optimizeNames(names, constants14);
92402
+ (_b = this.finally) === null || _b === undefined || _b.optimizeNames(names, constants14);
91820
92403
  return this;
91821
92404
  }
91822
92405
  get names() {
@@ -92090,7 +92673,7 @@ var require_codegen = __commonJS((exports) => {
92090
92673
  function addExprNames(names, from) {
92091
92674
  return from instanceof code_1._CodeOrName ? addNames(names, from.names) : names;
92092
92675
  }
92093
- function optimizeExpr(expr, names, constants13) {
92676
+ function optimizeExpr(expr, names, constants14) {
92094
92677
  if (expr instanceof code_1.Name)
92095
92678
  return replaceName(expr);
92096
92679
  if (!canOptimize(expr))
@@ -92105,14 +92688,14 @@ var require_codegen = __commonJS((exports) => {
92105
92688
  return items;
92106
92689
  }, []));
92107
92690
  function replaceName(n2) {
92108
- const c = constants13[n2.str];
92691
+ const c = constants14[n2.str];
92109
92692
  if (c === undefined || names[n2.str] !== 1)
92110
92693
  return n2;
92111
92694
  delete names[n2.str];
92112
92695
  return c;
92113
92696
  }
92114
92697
  function canOptimize(e2) {
92115
- return e2 instanceof code_1._Code && e2._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants13[c.str] !== undefined);
92698
+ return e2 instanceof code_1._Code && e2._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants14[c.str] !== undefined);
92116
92699
  }
92117
92700
  }
92118
92701
  function subtractNames(names, from) {
@@ -94017,7 +94600,7 @@ var require_compile = __commonJS((exports) => {
94017
94600
  const schOrFunc = root2.refs[ref];
94018
94601
  if (schOrFunc)
94019
94602
  return schOrFunc;
94020
- let _sch = resolve16.call(this, root2, ref);
94603
+ let _sch = resolve18.call(this, root2, ref);
94021
94604
  if (_sch === undefined) {
94022
94605
  const schema = (_a3 = root2.localRefs) === null || _a3 === undefined ? undefined : _a3[ref];
94023
94606
  const { schemaId } = this.opts;
@@ -94044,7 +94627,7 @@ var require_compile = __commonJS((exports) => {
94044
94627
  function sameSchemaEnv(s1, s2) {
94045
94628
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
94046
94629
  }
94047
- function resolve16(root2, ref) {
94630
+ function resolve18(root2, ref) {
94048
94631
  let sch;
94049
94632
  while (typeof (sch = this.refs[ref]) == "string")
94050
94633
  ref = sch;
@@ -94842,11 +95425,11 @@ var require_fast_uri = __commonJS((exports, module) => {
94842
95425
  if (typeof uri === "string") {
94843
95426
  uri = normalizeString(uri, options);
94844
95427
  } else if (typeof uri === "object") {
94845
- uri = parse10(serialize(uri, options), options);
95428
+ uri = parse11(serialize(uri, options), options);
94846
95429
  }
94847
95430
  return uri;
94848
95431
  }
94849
- function resolve16(baseURI, relativeURI, options) {
95432
+ function resolve18(baseURI, relativeURI, options) {
94850
95433
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
94851
95434
  const {
94852
95435
  parsed: baseParsed,
@@ -94882,8 +95465,8 @@ var require_fast_uri = __commonJS((exports, module) => {
94882
95465
  function resolveComponent(base2, relative7, options, skipNormalization) {
94883
95466
  const target = {};
94884
95467
  if (!skipNormalization) {
94885
- base2 = parse10(serialize(base2, options), options);
94886
- relative7 = parse10(serialize(relative7, options), options);
95468
+ base2 = parse11(serialize(base2, options), options);
95469
+ relative7 = parse11(serialize(relative7, options), options);
94887
95470
  }
94888
95471
  options = options || {};
94889
95472
  if (!options.tolerant && relative7.scheme) {
@@ -95183,7 +95766,7 @@ var require_fast_uri = __commonJS((exports, module) => {
95183
95766
  }
95184
95767
  return { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme };
95185
95768
  }
95186
- function parse10(uri, opts) {
95769
+ function parse11(uri, opts) {
95187
95770
  return parseWithStatus(uri, opts).parsed;
95188
95771
  }
95189
95772
  function normalizeString(uri, opts) {
@@ -95216,11 +95799,11 @@ var require_fast_uri = __commonJS((exports, module) => {
95216
95799
  var fastUri = {
95217
95800
  SCHEMES,
95218
95801
  normalize: normalize3,
95219
- resolve: resolve16,
95802
+ resolve: resolve18,
95220
95803
  resolveComponent,
95221
95804
  equal,
95222
95805
  serialize,
95223
- parse: parse10
95806
+ parse: parse11
95224
95807
  };
95225
95808
  module.exports = fastUri;
95226
95809
  module.exports.default = fastUri;
@@ -99002,7 +99585,7 @@ class McpServer {
99002
99585
  let task = createTaskResult.task;
99003
99586
  const pollInterval = task.pollInterval ?? 5000;
99004
99587
  while (task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled") {
99005
- await new Promise((resolve16) => setTimeout(resolve16, pollInterval));
99588
+ await new Promise((resolve18) => setTimeout(resolve18, pollInterval));
99006
99589
  const updatedTask = await extra.taskStore.getTask(taskId);
99007
99590
  if (!updatedTask) {
99008
99591
  throw new McpError(ErrorCode.InternalError, `Task ${taskId} not found during polling`);
@@ -99045,11 +99628,11 @@ class McpServer {
99045
99628
  return EMPTY_COMPLETION_RESULT;
99046
99629
  }
99047
99630
  const promptShape = getObjectShape(prompt.argsSchema);
99048
- const field = promptShape?.[request2.params.argument.name];
99049
- if (!isCompletable(field)) {
99631
+ const field2 = promptShape?.[request2.params.argument.name];
99632
+ if (!isCompletable(field2)) {
99050
99633
  return EMPTY_COMPLETION_RESULT;
99051
99634
  }
99052
- const completer = getCompleter(field);
99635
+ const completer = getCompleter(field2);
99053
99636
  if (!completer) {
99054
99637
  return EMPTY_COMPLETION_RESULT;
99055
99638
  }
@@ -99321,8 +99904,8 @@ class McpServer {
99321
99904
  };
99322
99905
  this._registeredPrompts[name] = registeredPrompt;
99323
99906
  if (argsSchema) {
99324
- const hasCompletable = Object.values(argsSchema).some((field) => {
99325
- const inner = field instanceof ZodOptional ? field._def?.innerType : field;
99907
+ const hasCompletable = Object.values(argsSchema).some((field2) => {
99908
+ const inner = field2 instanceof ZodOptional ? field2._def?.innerType : field2;
99326
99909
  return isCompletable(inner);
99327
99910
  });
99328
99911
  if (hasCompletable) {
@@ -99514,9 +100097,9 @@ function promptArgumentsFromSchema(schema) {
99514
100097
  const shape = getObjectShape(schema);
99515
100098
  if (!shape)
99516
100099
  return [];
99517
- return Object.entries(shape).map(([name, field]) => {
99518
- const description = getSchemaDescription(field);
99519
- const isOptional = isSchemaOptional(field);
100100
+ return Object.entries(shape).map(([name, field2]) => {
100101
+ const description = getSchemaDescription(field2);
100102
+ const isOptional = isSchemaOptional(field2);
99520
100103
  return {
99521
100104
  name,
99522
100105
  description,
@@ -99575,7 +100158,7 @@ var init_remote_customer_operations = __esm(() => {
99575
100158
  { name: "list_remote_skills", title: "List Remote Skills", parameter: null, mutates: false, invoke: (client2) => client2.listSkills() },
99576
100159
  { name: "get_billing_status", title: "Get Billing Status", parameter: null, mutates: false, invoke: (client2) => client2.getBillingStatus() },
99577
100160
  { name: "list_credit_packs", title: "List Credit Packs", parameter: null, mutates: false, invoke: (client2) => client2.listCreditPacks() },
99578
- { name: "create_credit_checkout", title: "Create Credit Checkout", parameter: "pack_id", mutates: true, invoke: (client2, value) => client2.createCreditCheckout(value) },
100161
+ { name: "create_credit_checkout", title: "Create Credit Checkout", parameter: "pack_id", mutates: true, invoke: (client2, value, options) => client2.createCreditCheckout(value, options) },
99579
100162
  { name: "get_billing_usage", title: "Get Billing Usage", parameter: null, mutates: false, invoke: (client2) => client2.getUsage() },
99580
100163
  { name: "list_invoices", title: "List Invoices", parameter: null, mutates: false, invoke: (client2) => client2.listInvoices() },
99581
100164
  { name: "create_billing_checkout", title: "Create Billing Checkout", parameter: null, mutates: true, invoke: (client2) => client2.createBillingCheckout() },
@@ -99689,7 +100272,7 @@ var init_remote_invitation_recovery = __esm(() => {
99689
100272
  });
99690
100273
 
99691
100274
  // src/lib/remote-private-publications.ts
99692
- import { createHash as createHash18 } from "crypto";
100275
+ import { createHash as createHash20 } from "crypto";
99693
100276
  function checkedPublicationDeclaration(value) {
99694
100277
  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)
99695
100278
  return bad();
@@ -99934,12 +100517,12 @@ class RemotePrivatePublicationsClient {
99934
100517
  previous = view;
99935
100518
  if (!["queued", "verifying"].includes(view.state) || Date.now() >= until)
99936
100519
  return view;
99937
- await new Promise((resolve16) => {
100520
+ await new Promise((resolve18) => {
99938
100521
  const timer = setTimeout(done, Math.min(1000, until - Date.now()));
99939
100522
  function done() {
99940
100523
  clearTimeout(timer);
99941
100524
  options.signal?.removeEventListener("abort", done);
99942
- resolve16();
100525
+ resolve18();
99943
100526
  }
99944
100527
  options.signal?.addEventListener("abort", done, { once: true });
99945
100528
  });
@@ -99950,7 +100533,7 @@ var PRIVATE_PUBLICATION_MAX_BYTES, failures2, PrivatePublicationError, bad = ()
99950
100533
  throw new PrivatePublicationError("INVALID_PUBLICATION_INPUT", "Invalid publication input or recovery data.");
99951
100534
  }, invalid5 = () => {
99952
100535
  throw new PrivatePublicationError("INVALID_PUBLICATION_RESPONSE", "The server returned an invalid publication result.");
99953
- }, publicationUuid = (v) => typeof v === "string" && /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(v), hash3 = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v), record10 = (v) => !!v && typeof v === "object" && !Array.isArray(v), exact = (v, keys3) => record10(v) && Object.keys(v).sort().join(",") === keys3.sort().join(","), date6 = (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)), publicationSha256 = (bytes) => createHash18("sha256").update(bytes).digest("hex");
100536
+ }, publicationUuid = (v) => typeof v === "string" && /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(v), hash3 = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v), record10 = (v) => !!v && typeof v === "object" && !Array.isArray(v), exact = (v, keys3) => record10(v) && Object.keys(v).sort().join(",") === keys3.sort().join(","), date6 = (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)), publicationSha256 = (bytes) => createHash20("sha256").update(bytes).digest("hex");
99954
100537
  var init_remote_private_publications = __esm(() => {
99955
100538
  init_fleet_credentials();
99956
100539
  init_remote_workspace_selection();
@@ -100227,11 +100810,11 @@ var init_remote_auth = __esm(() => {
100227
100810
  });
100228
100811
 
100229
100812
  // src/lib/workspace-profile.ts
100230
- import { constants as constants13, closeSync as closeSync14, fstatSync as fstatSync14, lstatSync as lstatSync20, mkdirSync as mkdirSync16, mkdtempSync as mkdtempSync5, openSync as openSync14, readFileSync as readFileSync31, renameSync as renameSync9, rmSync as rmSync8, writeFileSync as writeFileSync15 } from "fs";
100231
- import { dirname as dirname18, join as join44 } from "path";
100813
+ import { constants as constants14, closeSync as closeSync15, fstatSync as fstatSync15, lstatSync as lstatSync21, mkdirSync as mkdirSync16, mkdtempSync as mkdtempSync5, openSync as openSync15, readFileSync as readFileSync31, renameSync as renameSync9, rmSync as rmSync8, writeFileSync as writeFileSync15 } from "fs";
100814
+ import { dirname as dirname19, join as join44 } from "path";
100232
100815
  function stat2(path) {
100233
100816
  try {
100234
- return lstatSync20(path);
100817
+ return lstatSync21(path);
100235
100818
  } catch (error61) {
100236
100819
  if (error61.code === "ENOENT")
100237
100820
  return null;
@@ -100241,14 +100824,14 @@ function stat2(path) {
100241
100824
  function safeText(file2) {
100242
100825
  if (stat2(file2) === null)
100243
100826
  return null;
100244
- const fd = openSync14(file2, constants13.O_RDONLY | constants13.O_NOFOLLOW | constants13.O_NONBLOCK);
100827
+ const fd = openSync15(file2, constants14.O_RDONLY | constants14.O_NOFOLLOW | constants14.O_NONBLOCK);
100245
100828
  try {
100246
- const s = fstatSync14(fd);
100829
+ const s = fstatSync15(fd);
100247
100830
  if (!s.isFile() || s.size > 65536 || ![256, 384].includes(s.mode & 4095) || process.getuid && s.uid !== process.getuid())
100248
100831
  return fail2("The selected profile must use bounded owner-only regular files.");
100249
100832
  return readFileSync31(fd, "utf8");
100250
100833
  } finally {
100251
- closeSync14(fd);
100834
+ closeSync15(fd);
100252
100835
  }
100253
100836
  }
100254
100837
  function checkIdentityMetadata(file2, identity4) {
@@ -100313,18 +100896,18 @@ async function prepareWorkspaceEnrollment(membershipId, source = process.env) {
100313
100896
  `);
100314
100897
  if (Buffer.byteLength(credentialBody("x".repeat(8192)), "utf8") > 65536)
100315
100898
  return fail2("The selected profile has insufficient space for a bounded credential. Reduce its unrelated configuration before signing in.");
100316
- const parents = [];
100317
- for (let path = dirname18(file2);; path = dirname18(path)) {
100899
+ const parents2 = [];
100900
+ for (let path = dirname19(file2);; path = dirname19(path)) {
100318
100901
  const before2 = stat2(path);
100319
100902
  if (before2 && (!before2.isDirectory() || before2.isSymbolicLink()))
100320
100903
  return fail2("The profile directory must not be a symbolic link.");
100321
- parents.push([path, before2]);
100322
- if (path === dirname18(path))
100904
+ parents2.push([path, before2]);
100905
+ if (path === dirname19(path))
100323
100906
  break;
100324
100907
  }
100325
100908
  const unchanged2 = () => {
100326
100909
  unchangedFiles();
100327
- for (const [path, before2] of parents) {
100910
+ for (const [path, before2] of parents2) {
100328
100911
  const now3 = stat2(path);
100329
100912
  if (!before2 ? now3 !== null : !now3 || !now3.isDirectory() || before2.dev !== now3.dev || before2.ino !== now3.ino)
100330
100913
  changed();
@@ -100378,14 +100961,14 @@ async function prepareWorkspaceEnrollment(membershipId, source = process.env) {
100378
100961
  return fail2("The new profile exceeds the credential reader size limit.");
100379
100962
  const identity4 = JSON.stringify({ email: verified.user.email, userId: verified.user.id, orgId: verified.organization.id, orgSlug: verified.organization.slug, apiUrl: origin }, null, 2) + `
100380
100963
  `;
100381
- mkdirSync16(dirname18(file2), { recursive: true, mode: 448 });
100382
- const temp = mkdtempSync5(join44(dirname18(file2), ".workspace-login-"));
100964
+ mkdirSync16(dirname19(file2), { recursive: true, mode: 448 });
100965
+ const temp = mkdtempSync5(join44(dirname19(file2), ".workspace-login-"));
100383
100966
  let identityInstalled = false;
100384
100967
  try {
100385
100968
  writeFileSync15(join44(temp, "credentials"), body, { mode: 384, flag: "wx" });
100386
100969
  writeFileSync15(join44(temp, "identity"), identity4, { mode: 384, flag: "wx" });
100387
100970
  unchangedFiles();
100388
- for (const [path, before2] of parents) {
100971
+ for (const [path, before2] of parents2) {
100389
100972
  const now3 = stat2(path);
100390
100973
  if (!now3 || !now3.isDirectory() || now3.isSymbolicLink() || before2 && (before2.dev !== now3.dev || before2.ino !== now3.ino))
100391
100974
  changed();
@@ -100595,8 +101178,8 @@ var init_recurring_customer = __esm(() => {
100595
101178
  });
100596
101179
 
100597
101180
  // src/lib/recurring-recovery.ts
100598
- import { constants as constants14, closeSync as closeSync15, fsyncSync as fsyncSync3, fstatSync as fstatSync15, lstatSync as lstatSync21, mkdirSync as mkdirSync17, openSync as openSync15, readSync as readSync11, realpathSync as realpathSync8, renameSync as renameSync10, unlinkSync as unlinkSync6, writeFileSync as writeFileSync16 } from "fs";
100599
- import { dirname as dirname19, isAbsolute as isAbsolute14, join as join45, resolve as resolve16 } from "path";
101181
+ import { constants as constants15, closeSync as closeSync16, fsyncSync as fsyncSync4, fstatSync as fstatSync16, lstatSync as lstatSync22, mkdirSync as mkdirSync17, openSync as openSync16, readSync as readSync12, realpathSync as realpathSync8, renameSync as renameSync10, unlinkSync as unlinkSync6, writeFileSync as writeFileSync16 } from "fs";
101182
+ import { dirname as dirname20, isAbsolute as isAbsolute16, join as join45, resolve as resolve18 } from "path";
100600
101183
  import { randomUUID as randomUUID7 } from "crypto";
100601
101184
 
100602
101185
  class RecoveryOwner {
@@ -100604,14 +101187,14 @@ class RecoveryOwner {
100604
101187
  parents = [];
100605
101188
  constructor(directory) {
100606
101189
  this.directory = directory;
100607
- if (!isAbsolute14(directory) || resolve16(directory) !== directory || realpathSync8(directory) !== directory)
101190
+ if (!isAbsolute16(directory) || resolve18(directory) !== directory || realpathSync8(directory) !== directory)
100608
101191
  invalid6();
100609
- for (let path = directory;; path = dirname19(path)) {
100610
- const stat3 = lstatSync21(path);
101192
+ for (let path = directory;; path = dirname20(path)) {
101193
+ const stat3 = lstatSync22(path);
100611
101194
  if (!stat3.isDirectory() || stat3.isSymbolicLink())
100612
101195
  invalid6();
100613
101196
  this.parents.push({ path, dev: stat3.dev, ino: stat3.ino });
100614
- if (path === dirname19(path))
101197
+ if (path === dirname20(path))
100615
101198
  break;
100616
101199
  }
100617
101200
  this.assert();
@@ -100620,59 +101203,59 @@ class RecoveryOwner {
100620
101203
  if (realpathSync8(this.directory) !== this.directory)
100621
101204
  invalid6();
100622
101205
  for (const prior of this.parents) {
100623
- const now3 = lstatSync21(prior.path);
101206
+ const now3 = lstatSync22(prior.path);
100624
101207
  if (!now3.isDirectory() || now3.isSymbolicLink() || now3.dev !== prior.dev || now3.ino !== prior.ino)
100625
101208
  invalid6();
100626
101209
  }
100627
- const own2 = lstatSync21(this.directory);
101210
+ const own2 = lstatSync22(this.directory);
100628
101211
  if ((own2.mode & 511) !== 448 || (own2.mode & 3584) !== 0 || process.getuid && own2.uid !== process.getuid())
100629
101212
  invalid6();
100630
101213
  }
100631
101214
  read(name) {
100632
101215
  this.assert();
100633
- const fd = openSync15(join45(this.directory, name), constants14.O_RDONLY | constants14.O_NOFOLLOW | constants14.O_NONBLOCK);
101216
+ const fd = openSync16(join45(this.directory, name), constants15.O_RDONLY | constants15.O_NOFOLLOW | constants15.O_NONBLOCK);
100634
101217
  try {
100635
- const before2 = fstatSync15(fd);
101218
+ const before2 = fstatSync16(fd);
100636
101219
  if (!before2.isFile() || before2.nlink !== 1 || (before2.mode & 4095) !== 384 || before2.size < 1 || before2.size > 8192 || process.getuid && before2.uid !== process.getuid())
100637
101220
  invalid6();
100638
101221
  const bytes = Buffer.alloc(before2.size + 1);
100639
101222
  let size2 = 0;
100640
101223
  while (size2 < bytes.length) {
100641
- const n2 = readSync11(fd, bytes, size2, bytes.length - size2, size2);
101224
+ const n2 = readSync12(fd, bytes, size2, bytes.length - size2, size2);
100642
101225
  if (!n2)
100643
101226
  break;
100644
101227
  size2 += n2;
100645
101228
  }
100646
- const after2 = fstatSync15(fd), path = lstatSync21(join45(this.directory, name));
101229
+ const after2 = fstatSync16(fd), path = lstatSync22(join45(this.directory, name));
100647
101230
  if (size2 !== before2.size || after2.size !== before2.size || before2.mtimeMs !== after2.mtimeMs || before2.ctimeMs !== after2.ctimeMs || path.dev !== before2.dev || path.ino !== before2.ino || !path.isFile() || path.isSymbolicLink())
100648
101231
  invalid6();
100649
101232
  this.assert();
100650
101233
  return new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, size2));
100651
101234
  } finally {
100652
- closeSync15(fd);
101235
+ closeSync16(fd);
100653
101236
  }
100654
101237
  }
100655
101238
  write(name, value) {
100656
101239
  this.assert();
100657
101240
  const bytes = canonicalJson2(value, 8192) + `
100658
101241
  `;
100659
- const fd = openSync15(join45(this.directory, name), constants14.O_WRONLY | constants14.O_CREAT | constants14.O_EXCL | constants14.O_NOFOLLOW, 384);
101242
+ const fd = openSync16(join45(this.directory, name), constants15.O_WRONLY | constants15.O_CREAT | constants15.O_EXCL | constants15.O_NOFOLLOW, 384);
100660
101243
  try {
100661
101244
  writeFileSync16(fd, bytes);
100662
- fsyncSync3(fd);
101245
+ fsyncSync4(fd);
100663
101246
  } finally {
100664
- closeSync15(fd);
101247
+ closeSync16(fd);
100665
101248
  }
100666
101249
  this.assert();
100667
101250
  this.sync();
100668
101251
  }
100669
101252
  sync() {
100670
101253
  this.assert();
100671
- const fd = openSync15(this.directory, constants14.O_RDONLY | constants14.O_NOFOLLOW);
101254
+ const fd = openSync16(this.directory, constants15.O_RDONLY | constants15.O_NOFOLLOW);
100672
101255
  try {
100673
- fsyncSync3(fd);
101256
+ fsyncSync4(fd);
100674
101257
  } finally {
100675
- closeSync15(fd);
101258
+ closeSync16(fd);
100676
101259
  }
100677
101260
  }
100678
101261
  saveState(state, expected) {
@@ -100690,20 +101273,20 @@ class RecoveryOwner {
100690
101273
  this.assert();
100691
101274
  let fd;
100692
101275
  try {
100693
- fd = openSync15(join45(this.directory, "operation.lock"), constants14.O_WRONLY | constants14.O_CREAT | constants14.O_EXCL | constants14.O_NOFOLLOW, 384);
101276
+ fd = openSync16(join45(this.directory, "operation.lock"), constants15.O_WRONLY | constants15.O_CREAT | constants15.O_EXCL | constants15.O_NOFOLLOW, 384);
100694
101277
  } catch {
100695
101278
  throw new RecurringCustomerError("RECURRING_RECOVERY_BUSY", "Recovery is locked. Confirm the original process has stopped before explicitly reconciling the retained lock; no request was retried.");
100696
101279
  }
100697
- const owner2 = fstatSync15(fd);
101280
+ const owner2 = fstatSync16(fd);
100698
101281
  try {
100699
101282
  writeFileSync16(fd, JSON.stringify({ pid: process.pid }));
100700
- fsyncSync3(fd);
101283
+ fsyncSync4(fd);
100701
101284
  this.sync();
100702
101285
  return await action();
100703
101286
  } finally {
100704
- closeSync15(fd);
101287
+ closeSync16(fd);
100705
101288
  this.assert();
100706
- const now3 = lstatSync21(join45(this.directory, "operation.lock"));
101289
+ const now3 = lstatSync22(join45(this.directory, "operation.lock"));
100707
101290
  if (owner2.dev !== now3.dev || owner2.ino !== now3.ino || !now3.isFile() || now3.isSymbolicLink())
100708
101291
  invalid6();
100709
101292
  unlinkSync6(join45(this.directory, "operation.lock"));
@@ -100739,7 +101322,7 @@ function base2(customer, organizationId) {
100739
101322
  };
100740
101323
  }
100741
101324
  function create3(directory, intent) {
100742
- if (!isAbsolute14(directory) || resolve16(directory) !== directory || realpathSync8(dirname19(directory)) !== dirname19(directory))
101325
+ if (!isAbsolute16(directory) || resolve18(directory) !== directory || realpathSync8(dirname20(directory)) !== dirname20(directory))
100743
101326
  invalid6();
100744
101327
  mkdirSync17(directory, { mode: 448 });
100745
101328
  const owner2 = new RecoveryOwner(directory), checked = intentSchema.parse(intent), intentSha256 = canonicalJsonSha256(checked);
@@ -100902,7 +101485,7 @@ var init_recurring_recovery = __esm(() => {
100902
101485
  });
100903
101486
 
100904
101487
  // src/lib/recurring-surface.ts
100905
- import { isAbsolute as isAbsolute15 } from "path";
101488
+ import { isAbsolute as isAbsolute17 } from "path";
100906
101489
  function recurringMcpSchema(action) {
100907
101490
  return action === "activate" ? recurringSurfaceSchemas.activate.extend({ code, confirm: exports_external.literal(true) }) : recurringSurfaceSchemas[action];
100908
101491
  }
@@ -101007,7 +101590,7 @@ var init_recurring_surface = __esm(() => {
101007
101590
  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}$/);
101008
101591
  context = { userId: uuid13.optional(), membershipId: uuid13.optional() };
101009
101592
  page2 = { limit: exports_external.number().int().min(1).max(100).optional(), cursor: exports_external.string().min(1).max(2048).optional() };
101010
- directory = exports_external.string().max(4096).refine(isAbsolute15, "Use an absolute recovery directory");
101593
+ directory = exports_external.string().max(4096).refine(isAbsolute17, "Use an absolute recovery directory");
101011
101594
  email4 = exports_external.string().trim().toLowerCase().email().max(254);
101012
101595
  code = exports_external.string().regex(/^\d{6}$/);
101013
101596
  recurringSurfaceSchemas = {
@@ -101976,11 +102559,11 @@ var init_mcp_contracts = __esm(() => {
101976
102559
  name: operation.name,
101977
102560
  title: operation.title,
101978
102561
  description: `${operation.title} on the configured server; unavailable capabilities fail explicitly.`,
101979
- params: operation.parameter ? [operation.parameter] : [],
102562
+ params: operation.parameter ? [operation.parameter, ...operation.name === "create_credit_checkout" ? ["idempotency_key?"] : []] : [],
101980
102563
  category: "execution",
101981
102564
  sideEffects: operation.mutates ? "local-process-or-remote-run" : "none",
101982
102565
  stable: true,
101983
- inputSchema: objectSchema(operation.parameter ? { [operation.parameter]: stringSchema("Server resource identifier.") } : {}, operation.parameter ? [operation.parameter] : []),
102566
+ inputSchema: objectSchema(operation.parameter ? { [operation.parameter]: stringSchema("Server resource identifier."), ...operation.name === "create_credit_checkout" ? { idempotency_key: { type: "string", pattern: "^[A-Za-z0-9._:-]{8,255}$", description: "Caller-owned key retained before submission; reuse only for explicit recovery of the same server/account/pack." } } : {} } : {}, operation.parameter ? [operation.parameter] : []),
101984
102567
  outputSchema: { oneOf: [objectSchema({}, [], "Server response.", true), { type: "array", items: objectSchema({}, [], "Server record.", true) }] }
101985
102568
  }));
101986
102569
  remoteCustomerContracts.push({
@@ -102913,14 +103496,14 @@ var init_operation_tools = __esm(() => {
102913
103496
 
102914
103497
  // src/lib/feedback.ts
102915
103498
  import { appendFileSync as appendFileSync2, existsSync as existsSync29, mkdirSync as mkdirSync18 } from "fs";
102916
- import { dirname as dirname20, join as join47 } from "path";
103499
+ import { dirname as dirname21, join as join47 } from "path";
102917
103500
  import { Database } from "bun:sqlite";
102918
103501
  function getFeedbackDbPath() {
102919
103502
  return join47(getDataDir(), "skills.db");
102920
103503
  }
102921
103504
  function getFeedbackDb() {
102922
103505
  const dbPath = getFeedbackDbPath();
102923
- const dir = dirname20(dbPath);
103506
+ const dir = dirname21(dbPath);
102924
103507
  if (!existsSync29(dir))
102925
103508
  mkdirSync18(dir, { recursive: true });
102926
103509
  const db = new Database(dbPath);
@@ -102949,7 +103532,7 @@ function saveFeedback(input2) {
102949
103532
  const category = input2.category ?? "general";
102950
103533
  if (isApiMode()) {
102951
103534
  const path = join47(getDataDir(), "feedback.jsonl");
102952
- const dir = dirname20(path);
103535
+ const dir = dirname21(path);
102953
103536
  if (!existsSync29(dir))
102954
103537
  mkdirSync18(dir, { recursive: true });
102955
103538
  appendFileSync2(path, JSON.stringify({ message, category, email: input2.email ?? null, agent: input2.agent ?? null, version: input2.version ?? null, createdAt: new Date().toISOString() }) + `
@@ -103427,7 +104010,7 @@ var init_schedule_tools = __esm(() => {
103427
104010
  });
103428
104011
 
103429
104012
  // src/lib/native-storage.ts
103430
- import { createHash as createHash19, createHmac as createHmac3 } from "crypto";
104013
+ import { createHash as createHash21, createHmac as createHmac3 } from "crypto";
103431
104014
  import {
103432
104015
  existsSync as existsSync31,
103433
104016
  mkdirSync as mkdirSync20,
@@ -103436,7 +104019,7 @@ import {
103436
104019
  statSync as statSync17,
103437
104020
  writeFileSync as writeFileSync18
103438
104021
  } from "fs";
103439
- import { dirname as dirname21, join as join49, normalize as normalize3, relative as relative7, sep as sep7 } from "path";
104022
+ import { dirname as dirname22, join as join49, normalize as normalize3, relative as relative7, sep as sep7 } from "path";
103440
104023
  function resolveSkillsNativeStorageConfig(env3 = process.env) {
103441
104024
  assertNoRetiredModeEnvVars(env3, {
103442
104025
  app: SKILLS_ENV_NAMESPACE,
@@ -103504,7 +104087,7 @@ function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
103504
104087
  files.push({
103505
104088
  path: relativePath,
103506
104089
  sizeBytes: bytes.byteLength,
103507
- sha256: createHash19("sha256").update(bytes).digest("hex"),
104090
+ sha256: createHash21("sha256").update(bytes).digest("hex"),
103508
104091
  ...options.includeFileContents ? { contentBase64: Buffer.from(bytes).toString("base64") } : {}
103509
104092
  });
103510
104093
  }
@@ -103796,20 +104379,20 @@ var init_private_publication_customer = __esm(() => {
103796
104379
  });
103797
104380
 
103798
104381
  // src/lib/private-publication-recovery.ts
103799
- import { constants as constants15, closeSync as closeSync16, fsyncSync as fsyncSync4, fstatSync as fstatSync16, lstatSync as lstatSync22, mkdirSync as mkdirSync21, openSync as openSync16, readSync as readSync12, realpathSync as realpathSync9, renameSync as renameSync11, unlinkSync as unlinkSync7, writeFileSync as writeFileSync19 } from "fs";
103800
- import { dirname as dirname22, isAbsolute as isAbsolute16, join as join50, resolve as resolve17 } from "path";
104382
+ import { constants as constants16, closeSync as closeSync17, fsyncSync as fsyncSync5, fstatSync as fstatSync17, lstatSync as lstatSync23, mkdirSync as mkdirSync21, openSync as openSync17, readSync as readSync13, realpathSync as realpathSync9, renameSync as renameSync11, unlinkSync as unlinkSync7, writeFileSync as writeFileSync19 } from "fs";
104383
+ import { dirname as dirname23, isAbsolute as isAbsolute18, join as join50, resolve as resolve19 } from "path";
103801
104384
  import { randomUUID as randomUUID8 } from "crypto";
103802
104385
  function safeDirectory(directory2) {
103803
- if (!isAbsolute16(directory2) || directory2 !== resolve17(directory2) || realpathSync9(directory2) !== directory2)
104386
+ if (!isAbsolute18(directory2) || directory2 !== resolve19(directory2) || realpathSync9(directory2) !== directory2)
103804
104387
  return fail3();
103805
- for (let path = directory2;; path = dirname22(path)) {
103806
- const stat3 = lstatSync22(path);
104388
+ for (let path = directory2;; path = dirname23(path)) {
104389
+ const stat3 = lstatSync23(path);
103807
104390
  if (!stat3.isDirectory() || stat3.isSymbolicLink())
103808
104391
  return fail3();
103809
- if (path === dirname22(path))
104392
+ if (path === dirname23(path))
103810
104393
  break;
103811
104394
  }
103812
- const own2 = lstatSync22(directory2);
104395
+ const own2 = lstatSync23(directory2);
103813
104396
  if ((own2.mode & 63) !== 0 || process.getuid && own2.uid !== process.getuid())
103814
104397
  return fail3();
103815
104398
  return { dev: own2.dev, ino: own2.ino };
@@ -103821,35 +104404,35 @@ function unchangedDirectory(directory2, identity4) {
103821
104404
  }
103822
104405
  function readOwned(directory2, name, max2) {
103823
104406
  const identity4 = safeDirectory(directory2), file2 = join50(directory2, name);
103824
- const fd = openSync16(file2, constants15.O_RDONLY | constants15.O_NOFOLLOW);
104407
+ const fd = openSync17(file2, constants16.O_RDONLY | constants16.O_NOFOLLOW);
103825
104408
  try {
103826
- const stat3 = fstatSync16(fd);
104409
+ const stat3 = fstatSync17(fd);
103827
104410
  if (!stat3.isFile() || stat3.nlink !== 1 || stat3.size > max2 || stat3.size < 1 || (stat3.mode & 63) !== 0 || process.getuid && stat3.uid !== process.getuid())
103828
104411
  return fail3();
103829
104412
  const buffer = Buffer.alloc(Math.min(max2, stat3.size) + 1);
103830
104413
  let length = 0;
103831
104414
  while (length < buffer.length) {
103832
- const count = readSync12(fd, buffer, length, buffer.length - length, length);
104415
+ const count = readSync13(fd, buffer, length, buffer.length - length, length);
103833
104416
  if (count === 0)
103834
104417
  break;
103835
104418
  length += count;
103836
104419
  }
103837
- const bytes = buffer.subarray(0, length), after2 = fstatSync16(fd);
104420
+ const bytes = buffer.subarray(0, length), after2 = fstatSync17(fd);
103838
104421
  unchangedDirectory(directory2, identity4);
103839
104422
  if (bytes.length !== stat3.size || stat3.size !== after2.size || stat3.mtimeMs !== after2.mtimeMs || stat3.ctimeMs !== after2.ctimeMs)
103840
104423
  return fail3();
103841
104424
  return bytes;
103842
104425
  } finally {
103843
- closeSync16(fd);
104426
+ closeSync17(fd);
103844
104427
  }
103845
104428
  }
103846
104429
  function writeOwned(directory2, name, bytes) {
103847
- const fd = openSync16(join50(directory2, name), constants15.O_WRONLY | constants15.O_CREAT | constants15.O_EXCL | constants15.O_NOFOLLOW, 384);
104430
+ const fd = openSync17(join50(directory2, name), constants16.O_WRONLY | constants16.O_CREAT | constants16.O_EXCL | constants16.O_NOFOLLOW, 384);
103848
104431
  try {
103849
104432
  writeFileSync19(fd, bytes);
103850
- fsyncSync4(fd);
104433
+ fsyncSync5(fd);
103851
104434
  } finally {
103852
- closeSync16(fd);
104435
+ closeSync17(fd);
103853
104436
  }
103854
104437
  }
103855
104438
  function save(directory2, value) {
@@ -103858,11 +104441,11 @@ function save(directory2, value) {
103858
104441
  `);
103859
104442
  unchangedDirectory(directory2, identity4);
103860
104443
  renameSync11(join50(directory2, temporary), join50(directory2, "receipt.json"));
103861
- const fd = openSync16(directory2, constants15.O_RDONLY | constants15.O_NOFOLLOW);
104444
+ const fd = openSync17(directory2, constants16.O_RDONLY | constants16.O_NOFOLLOW);
103862
104445
  try {
103863
- fsyncSync4(fd);
104446
+ fsyncSync5(fd);
103864
104447
  } finally {
103865
- closeSync16(fd);
104448
+ closeSync17(fd);
103866
104449
  }
103867
104450
  }
103868
104451
  function bind2(client2, receipt) {
@@ -103873,20 +104456,20 @@ async function locked(directory2, action) {
103873
104456
  const identity4 = safeDirectory(directory2), file2 = join50(directory2, "operation.lock");
103874
104457
  let fd;
103875
104458
  try {
103876
- fd = openSync16(file2, constants15.O_WRONLY | constants15.O_CREAT | constants15.O_EXCL | constants15.O_NOFOLLOW, 384);
104459
+ fd = openSync17(file2, constants16.O_WRONLY | constants16.O_CREAT | constants16.O_EXCL | constants16.O_NOFOLLOW, 384);
103877
104460
  } catch {
103878
104461
  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.");
103879
104462
  }
103880
- const lock = fstatSync16(fd);
104463
+ const lock = fstatSync17(fd);
103881
104464
  try {
103882
104465
  writeFileSync19(fd, JSON.stringify({ pid: process.pid }) + `
103883
104466
  `);
103884
- fsyncSync4(fd);
104467
+ fsyncSync5(fd);
103885
104468
  return await action();
103886
104469
  } finally {
103887
- closeSync16(fd);
104470
+ closeSync17(fd);
103888
104471
  unchangedDirectory(directory2, identity4);
103889
- const now3 = lstatSync22(file2);
104472
+ const now3 = lstatSync23(file2);
103890
104473
  if (now3.dev !== lock.dev || now3.ino !== lock.ino || !now3.isFile() || now3.isSymbolicLink())
103891
104474
  fail3();
103892
104475
  unlinkSync7(file2);
@@ -103938,15 +104521,15 @@ async function preparePrivatePublication(client2, sourceDirectory, recoveryDirec
103938
104521
  phase: "prepared",
103939
104522
  intent: null
103940
104523
  };
103941
- if (!isAbsolute16(recoveryDirectory) || resolve17(recoveryDirectory) !== recoveryDirectory || realpathSync9(dirname22(recoveryDirectory)) !== dirname22(recoveryDirectory))
104524
+ if (!isAbsolute18(recoveryDirectory) || resolve19(recoveryDirectory) !== recoveryDirectory || realpathSync9(dirname23(recoveryDirectory)) !== dirname23(recoveryDirectory))
103942
104525
  return fail3();
103943
104526
  mkdirSync21(recoveryDirectory, { mode: 448 });
103944
104527
  safeDirectory(recoveryDirectory);
103945
- const parent = openSync16(dirname22(recoveryDirectory), constants15.O_RDONLY | constants15.O_NOFOLLOW);
104528
+ const parent = openSync17(dirname23(recoveryDirectory), constants16.O_RDONLY | constants16.O_NOFOLLOW);
103946
104529
  try {
103947
- fsyncSync4(parent);
104530
+ fsyncSync5(parent);
103948
104531
  } finally {
103949
- closeSync16(parent);
104532
+ closeSync17(parent);
103950
104533
  }
103951
104534
  writeOwned(recoveryDirectory, "bundle.tgz", packed.bytes);
103952
104535
  save(recoveryDirectory, receipt);
@@ -104039,10 +104622,10 @@ var init_private_publication_recovery = __esm(() => {
104039
104622
  });
104040
104623
 
104041
104624
  // src/mcp/private-publication-tools.ts
104042
- import { isAbsolute as isAbsolute17 } from "path";
104625
+ import { isAbsolute as isAbsolute19 } from "path";
104043
104626
  function registerPrivatePublicationTools(server) {
104044
104627
  const uuid9 = exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/);
104045
- const directory2 = exports_external.string().max(4096).refine(isAbsolute17, "Use an absolute local directory");
104628
+ const directory2 = exports_external.string().max(4096).refine(isAbsolute19, "Use an absolute local directory");
104046
104629
  const verification2 = { email: exports_external.string().email().max(254), code: exports_external.string().regex(/^\d{6}$/), userId: uuid9, membershipId: uuid9, recoveryDirectory: directory2 };
104047
104630
  const description = "Manage a private source publication using fresh workspace-bound verification and a host-local recovery directory. Publishing requires explicit UUID current-version comparison and upload consent. Resume reuses immutable saved bytes and intent; an uncertain PUT is finalized for server verification, never uploaded twice. Sessions and signed URLs are not returned or persisted. Private execution is unavailable. Host request history may contain the supplied verification code.";
104048
104631
  const handler = (action) => async (value) => {
@@ -104197,6 +104780,14 @@ function registerRemoteCustomerTools(server) {
104197
104780
  });
104198
104781
  }
104199
104782
  for (const operation of REMOTE_CUSTOMER_OPERATIONS) {
104783
+ if (operation.name === "create_credit_checkout") {
104784
+ server.registerTool(operation.name, {
104785
+ title: operation.title,
104786
+ description: "Create one external checkout link on the selected Skills server. Retain an idempotency_key before calling and reuse it only for explicit recovery on the same server, account and pack. No automatic retries; payment requires customer confirmation.",
104787
+ inputSchema: { pack_id: exports_external.string().min(1), idempotency_key: exports_external.string().regex(/^[A-Za-z0-9._:-]{8,255}$/).optional() }
104788
+ }, ({ pack_id, idempotency_key }) => callRemote((client2) => operation.invoke(client2, pack_id, { idempotencyKey: idempotency_key })));
104789
+ continue;
104790
+ }
104200
104791
  const inputSchema = {};
104201
104792
  if (operation.parameter)
104202
104793
  inputSchema[operation.parameter] = exports_external.string().min(1);
@@ -104273,6 +104864,15 @@ async function callRemote(action) {
104273
104864
  return mcpError("AUTH_REQUIRED", "Configure a Skills API and sign in with skills auth login");
104274
104865
  return mcpJson(await action(client2));
104275
104866
  } catch (error61) {
104867
+ if (error61 instanceof RemoteCreditCheckoutError) {
104868
+ return { ...mcpJson({
104869
+ code: error61.code,
104870
+ message: error61.message,
104871
+ status: error61.status,
104872
+ requestIdempotencyKey: error61.requestIdempotencyKey,
104873
+ ...error61.retryAfterSeconds === undefined ? {} : { retryAfterSeconds: error61.retryAfterSeconds }
104874
+ }), isError: true };
104875
+ }
104276
104876
  if (error61 instanceof RemoteCapabilityUnavailableError) {
104277
104877
  return { ...mcpJson({ code: error61.code, message: error61.message, status: error61.status }), isError: true };
104278
104878
  }
@@ -104385,7 +104985,7 @@ var init_mcp2 = __esm(() => {
104385
104985
  // src/cli/commands/runtime-mcp.ts
104386
104986
  import { existsSync as existsSync32, mkdirSync as mkdirSync22, readFileSync as readFileSync34, writeFileSync as writeFileSync20 } from "fs";
104387
104987
  import { homedir as homedir9 } from "os";
104388
- import { dirname as dirname23, join as join51 } from "path";
104988
+ import { dirname as dirname24, join as join51 } from "path";
104389
104989
  async function handleMcp(options) {
104390
104990
  if (options.register) {
104391
104991
  let agents;
@@ -104559,7 +105159,7 @@ function writeJsonObject(path, data) {
104559
105159
  `);
104560
105160
  }
104561
105161
  function writeTextFile(path, content) {
104562
- mkdirSync22(dirname23(path), { recursive: true });
105162
+ mkdirSync22(dirname24(path), { recursive: true });
104563
105163
  writeFileSync20(path, content.endsWith(`
104564
105164
  `) ? content : `${content}
104565
105165
  `);
@@ -104622,7 +105222,7 @@ function registerRemoteAccount(parent) {
104622
105222
  billing.command("portal").option("--json", "Output as JSON", false).description("Create an external customer billing portal link").action((options) => execute(options, (client2) => client2.createBillingPortal()));
104623
105223
  const credits = parent.command("credits").description("Inspect and purchase credits from the configured server");
104624
105224
  credits.command("packs").option("--json", "Output as JSON", false).action((options) => execute(options, (client2) => client2.listCreditPacks()));
104625
- credits.command("buy").argument("<pack-id>", "An ID returned by credits packs").option("--json", "Output as JSON", false).description("Create an external checkout link; payment is confirmed in the browser").action((packId, options) => execute(options, (client2) => client2.createCreditCheckout(packId)));
105225
+ credits.command("buy").argument("<pack-id>", "An ID returned by credits packs").option("--json", "Output as JSON", false).option("--idempotency-key <key>", "Retain and reuse this request key for explicit checkout recovery").description("Create an external checkout link; payment is confirmed in the browser. No automatic retries.").action((packId, options) => execute(options, (client2) => client2.createCreditCheckout(packId, { idempotencyKey: options.idempotencyKey })));
104626
105226
  }
104627
105227
  async function execute(options, action) {
104628
105228
  try {
@@ -104633,6 +105233,23 @@ async function execute(options, action) {
104633
105233
  console.log(JSON.stringify(result2, null, 2));
104634
105234
  } catch (error61) {
104635
105235
  const message = error61 instanceof Error ? error61.message : "The Skills server request failed";
105236
+ if (error61 instanceof RemoteCreditCheckoutError) {
105237
+ const result2 = {
105238
+ error: error61.message,
105239
+ code: error61.code,
105240
+ status: error61.status,
105241
+ requestIdempotencyKey: error61.requestIdempotencyKey,
105242
+ ...error61.retryAfterSeconds === undefined ? {} : { retryAfterSeconds: error61.retryAfterSeconds }
105243
+ };
105244
+ if (options.json)
105245
+ console.log(JSON.stringify(result2));
105246
+ else
105247
+ console.error(`${error61.message}
105248
+ Request key: ${error61.requestIdempotencyKey}` + (error61.code === "CREDIT_CHECKOUT_UNCONFIRMED" || error61.code === "CREDIT_CHECKOUT_IN_PROGRESS" ? `
105249
+ For explicit recovery, pass this key with --idempotency-key. Keep the same server, account and pack.` : ""));
105250
+ process.exitCode = 1;
105251
+ return;
105252
+ }
104636
105253
  if (options.json)
104637
105254
  console.log(JSON.stringify({
104638
105255
  error: message,
@@ -104652,9 +105269,9 @@ var exports_runtime = {};
104652
105269
  __export(exports_runtime, {
104653
105270
  registerRuntime: () => registerRuntime
104654
105271
  });
104655
- import { createHash as createHash20, randomUUID as randomUUID9 } from "crypto";
104656
- import { lstatSync as lstatSync23, mkdirSync as mkdirSync23, readFileSync as readFileSync35, realpathSync as realpathSync10, writeFileSync as writeFileSync21 } from "fs";
104657
- import { basename as basename7, isAbsolute as isAbsolute18, join as join52 } from "path";
105272
+ import { createHash as createHash22, randomUUID as randomUUID9 } from "crypto";
105273
+ import { lstatSync as lstatSync24, mkdirSync as mkdirSync23, readFileSync as readFileSync35, realpathSync as realpathSync10, writeFileSync as writeFileSync21 } from "fs";
105274
+ import { basename as basename9, isAbsolute as isAbsolute20, join as join52 } from "path";
104658
105275
  import { createInterface } from "readline";
104659
105276
  function registerRuntime(parent) {
104660
105277
  parent.command("run").argument("<skill>", "Skill name").argument("[args...]", "Arguments to pass to the skill; use -- to end Skills options").allowUnknownOption(true).passThroughOptions(true).option("--json", "Output result as JSON", false).option("--remote", "Run on the configured server, using its catalog and quote", false).option("--target <target>", "Execution target: local or cloud").option("--secret-bindings <path>", "Reviewed, exact-selection local execution vault bindings (JSON file)").option("--secret-bindings-template", "Print a scoped bindings template without resolving secrets or running the skill", false).option("--input <json>", "Structured cloud execution input").option("--skill-version <version>", "Exact selected skill version").option("--selection-profile <id>", "Selected Skills profile").option("--session <id>", "Pinned Skills session").option("--cached", "Use the explicit verified selected cache", false).option("--yes", "Approve the server's quoted credit cost for this run", false).option("--idempotency-key <key>", "Reuse this key when retrying the same remote submission").option("--file <path>", "Attach a local input file to a remote run (repeatable)", (value, prior) => [...prior, value], []).option("--wait", "Poll remote runs until a terminal status", false).option("--poll-interval-ms <ms>", "Remote polling interval in milliseconds", "1000").option("--poll-timeout-ms <ms>", "Maximum time to wait for a remote run", "300000").description("Run a skill directly").action(async (name, args2, options, command) => {
@@ -104684,7 +105301,7 @@ function registerRuntime(parent) {
104684
105301
  if (!expected)
104685
105302
  throw new Error("Cloud artifact not found");
104686
105303
  const bytes = await client2.download(id2, name);
104687
- if (bytes.length !== expected.byteSize || createHash20("sha256").update(bytes).digest("hex") !== expected.sha256)
105304
+ if (bytes.length !== expected.byteSize || createHash22("sha256").update(bytes).digest("hex") !== expected.sha256)
104688
105305
  throw new Error("Cloud artifact integrity verification failed");
104689
105306
  writeFileSync21(options.output, bytes, { flag: "wx", mode: 384 });
104690
105307
  console.log(JSON.stringify({ path: options.output, sha256: expected.sha256, byteSize: bytes.length }));
@@ -104772,7 +105389,7 @@ Updating ${name}...
104772
105389
  async function readUpdatedVersion(bunExecutable) {
104773
105390
  const output2 = await readUpdateCommand([bunExecutable, "pm", "bin", "-g"]);
104774
105391
  const globalBin = output2.replace(/\r?\n$/, "");
104775
- if (!globalBin || !isAbsolute18(globalBin) || /[\r\n\0]/.test(globalBin))
105392
+ if (!globalBin || !isAbsolute20(globalBin) || /[\r\n\0]/.test(globalBin))
104776
105393
  throw new Error("Update bin discovery failed");
104777
105394
  const installed = Bun.which("skills", { PATH: globalBin, cwd: globalBin });
104778
105395
  const selected = Bun.which("skills");
@@ -104908,14 +105525,14 @@ function requireHttpUrl(value) {
104908
105525
  }
104909
105526
  function promptLine(question) {
104910
105527
  const rl = createInterface({ input: process.stdin, output: process.stdout });
104911
- return new Promise((resolve18) => {
105528
+ return new Promise((resolve20) => {
104912
105529
  let settled = false;
104913
105530
  const finish = (answer) => {
104914
105531
  if (settled)
104915
105532
  return;
104916
105533
  settled = true;
104917
105534
  rl.close();
104918
- resolve18(answer);
105535
+ resolve20(answer);
104919
105536
  };
104920
105537
  rl.once("SIGINT", () => finish(null));
104921
105538
  rl.once("close", () => finish(null));
@@ -105092,10 +105709,10 @@ async function handleRun(name, args2, options, separatorBeforeSkill) {
105092
105709
  try {
105093
105710
  parsePollingOptions(options);
105094
105711
  inputFiles = (options.file ?? []).map((path) => {
105095
- const info = lstatSync23(path);
105712
+ const info = lstatSync24(path);
105096
105713
  if (!info.isFile() || info.size > 20 * 1024 * 1024)
105097
105714
  throw new Error("Input must be a regular file no larger than 20 MiB");
105098
- return { name: basename7(path), bytes: new Uint8Array(readFileSync35(path)) };
105715
+ return { name: basename9(path), bytes: new Uint8Array(readFileSync35(path)) };
105099
105716
  });
105100
105717
  describeRemoteFiles(inputFiles);
105101
105718
  client2 = new RemoteSkillsClient(routing.apiKey, routing.apiOrigin);
@@ -105522,7 +106139,7 @@ function ensureSafeExportParent(root2, relativePath) {
105522
106139
  if (part)
105523
106140
  parent = join52(parent, part);
105524
106141
  try {
105525
- if (!lstatSync23(parent).isDirectory() || lstatSync23(parent).isSymbolicLink())
106142
+ if (!lstatSync24(parent).isDirectory() || lstatSync24(parent).isSymbolicLink())
105526
106143
  throw new Error("Unsafe artifact directory");
105527
106144
  } catch (error61) {
105528
106145
  if (error61.code !== "ENOENT")
@@ -105560,7 +106177,7 @@ async function pollRemoteRun(client2, runId2, options) {
105560
106177
  const remaining = deadline - Date.now();
105561
106178
  if (remaining <= 0)
105562
106179
  break;
105563
- await new Promise((resolve18) => setTimeout(resolve18, Math.min(options.intervalMs, remaining)));
106180
+ await new Promise((resolve20) => setTimeout(resolve20, Math.min(options.intervalMs, remaining)));
105564
106181
  }
105565
106182
  return {
105566
106183
  run: current ?? { id: runId2, status: "queued" },
@@ -105752,7 +106369,7 @@ async function readCode() {
105752
106369
  function promptCode() {
105753
106370
  const { stdin, stderr: output2 } = process;
105754
106371
  const { isRaw: wasRaw, readableFlowing: wasFlowing } = stdin;
105755
- return new Promise((resolve18) => {
106372
+ return new Promise((resolve20) => {
105756
106373
  let value = "", settled = false;
105757
106374
  const finish = (answer) => {
105758
106375
  if (settled)
@@ -105769,7 +106386,7 @@ function promptCode() {
105769
106386
  `);
105770
106387
  if (answer === null)
105771
106388
  process.exitCode = 130;
105772
- resolve18(answer);
106389
+ resolve20(answer);
105773
106390
  };
105774
106391
  const cancel = () => finish(null);
105775
106392
  const keypress = (text3, key) => {
@@ -105814,37 +106431,37 @@ var exports_recurring = {};
105814
106431
  __export(exports_recurring, {
105815
106432
  registerRecurringCommands: () => registerRecurringCommands
105816
106433
  });
105817
- import { constants as constants16, closeSync as closeSync17, fstatSync as fstatSync17, lstatSync as lstatSync24, openSync as openSync17, readSync as readSync13 } from "fs";
106434
+ import { constants as constants17, closeSync as closeSync18, fstatSync as fstatSync18, lstatSync as lstatSync25, openSync as openSync18, readSync as readSync14 } from "fs";
105818
106435
  import { createInterface as createInterface2 } from "readline";
105819
106436
  function readRequest(path) {
105820
- const fd = openSync17(path, constants16.O_RDONLY | constants16.O_NOFOLLOW | constants16.O_NONBLOCK);
106437
+ const fd = openSync18(path, constants17.O_RDONLY | constants17.O_NOFOLLOW | constants17.O_NONBLOCK);
105821
106438
  try {
105822
- const before2 = fstatSync17(fd);
106439
+ const before2 = fstatSync18(fd);
105823
106440
  if (!before2.isFile() || before2.size > 1048576 || before2.size < 1)
105824
106441
  throw new RecurringInputError;
105825
106442
  const bytes = Buffer.alloc(before2.size + 1);
105826
106443
  let length = 0;
105827
106444
  while (length < bytes.length) {
105828
- const n2 = readSync13(fd, bytes, length, bytes.length - length, length);
106445
+ const n2 = readSync14(fd, bytes, length, bytes.length - length, length);
105829
106446
  if (!n2)
105830
106447
  break;
105831
106448
  length += n2;
105832
106449
  }
105833
- const after2 = fstatSync17(fd), current = lstatSync24(path);
106450
+ const after2 = fstatSync18(fd), current = lstatSync25(path);
105834
106451
  if (length !== before2.size || after2.size !== before2.size || before2.mtimeMs !== after2.mtimeMs || before2.ctimeMs !== after2.ctimeMs || current.dev !== before2.dev || current.ino !== before2.ino || !current.isFile() || current.isSymbolicLink())
105835
106452
  throw new RecurringInputError;
105836
106453
  return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, length)));
105837
106454
  } catch {
105838
106455
  throw new RecurringInputError;
105839
106456
  } finally {
105840
- closeSync17(fd);
106457
+ closeSync18(fd);
105841
106458
  }
105842
106459
  }
105843
106460
  async function acceptAtTerminal(draft) {
105844
- await new Promise((resolve18, reject2) => process.stderr.write(`${jsonText(draft)}
106461
+ await new Promise((resolve20, reject2) => process.stderr.write(`${jsonText(draft)}
105845
106462
  This grants an additional recurring budget. Each occurrence reprices within the approved ceilings. Revocation prevents new authority; an already-authorized attempt may finish, and cancellation is separate.
105846
- `, (error61) => error61 ? reject2(error61) : resolve18()));
105847
- return new Promise((resolve18) => {
106463
+ `, (error61) => error61 ? reject2(error61) : resolve20()));
106464
+ return new Promise((resolve20) => {
105848
106465
  const rl = createInterface2({ input: process.stdin, output: process.stderr });
105849
106466
  let settled = false;
105850
106467
  const finish = (accepted) => {
@@ -105855,7 +106472,7 @@ This grants an additional recurring budget. Each occurrence reprices within the
105855
106472
  rl.close();
105856
106473
  if (!accepted)
105857
106474
  process.exitCode = 130;
105858
- resolve18(accepted);
106475
+ resolve20(accepted);
105859
106476
  };
105860
106477
  const timer = setTimeout(() => finish(false), 5 * 60 * 1000);
105861
106478
  rl.once("SIGINT", () => finish(false));
@@ -106263,7 +106880,7 @@ var init_portable_snapshot_filter = __esm(() => {
106263
106880
  });
106264
106881
 
106265
106882
  // src/lib/station-snapshot.ts
106266
- import { createHash as createHash21 } from "crypto";
106883
+ import { createHash as createHash23 } from "crypto";
106267
106884
  import {
106268
106885
  copyFileSync,
106269
106886
  mkdirSync as mkdirSync24,
@@ -106271,14 +106888,14 @@ import {
106271
106888
  statSync as statSync19,
106272
106889
  writeFileSync as writeFileSync22
106273
106890
  } from "fs";
106274
- import { dirname as dirname25, isAbsolute as isAbsolute19, relative as relative8, resolve as resolve18, sep as sep9 } from "path";
106891
+ import { dirname as dirname26, isAbsolute as isAbsolute21, relative as relative8, resolve as resolve20, sep as sep9 } from "path";
106275
106892
  function validateStationId(stationId) {
106276
106893
  if (!/^[a-z0-9-]+$/.test(stationId)) {
106277
106894
  throw new StationSnapshotError("INVALID_STATION", `station id must be a slug, got: ${stationId}`);
106278
106895
  }
106279
106896
  }
106280
106897
  function sha256File(filePath) {
106281
- return createHash21("sha256").update(readFileSync36(filePath)).digest("hex");
106898
+ return createHash23("sha256").update(readFileSync36(filePath)).digest("hex");
106282
106899
  }
106283
106900
  function scanHome(definition, homesRoot) {
106284
106901
  const homePath = homePathFor(definition, homesRoot);
@@ -106349,7 +106966,7 @@ function humanHomes(scanned) {
106349
106966
  }));
106350
106967
  }
106351
106968
  function writeStationSnapshot(options) {
106352
- const repoRoot = resolve18(options.repoRoot ?? process.cwd());
106969
+ const repoRoot = resolve20(options.repoRoot ?? process.cwd());
106353
106970
  const { scanned, plans, totalBytes } = planStationSnapshot(options);
106354
106971
  const manifestFiles = plans.map((plan) => ({
106355
106972
  relativePath: plan.source.relativePath,
@@ -106375,9 +106992,9 @@ function writeStationSnapshot(options) {
106375
106992
  const conflicts = [];
106376
106993
  const untouched = [];
106377
106994
  for (const plan of plans) {
106378
- const destination = resolve18(repoRoot, plan.destination);
106995
+ const destination = resolve20(repoRoot, plan.destination);
106379
106996
  const destinationRelative = relative8(repoRoot, destination);
106380
- if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep9) || isAbsolute19(destinationRelative)) {
106997
+ if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep9) || isAbsolute21(destinationRelative)) {
106381
106998
  throw new StationSnapshotError("DESTINATION_ESCAPE", `destination escapes repo root: ${plan.destination}`);
106382
106999
  }
106383
107000
  let existingDigest = null;
@@ -106398,8 +107015,8 @@ function writeStationSnapshot(options) {
106398
107015
  }
106399
107016
  let written = 0;
106400
107017
  for (const plan of untouched) {
106401
- const destination = resolve18(repoRoot, plan.destination);
106402
- mkdirSync24(dirname25(destination), { recursive: true });
107018
+ const destination = resolve20(repoRoot, plan.destination);
107019
+ mkdirSync24(dirname26(destination), { recursive: true });
106403
107020
  copyFileSync(plan.source.fullPath, destination);
106404
107021
  written += 1;
106405
107022
  }
@@ -106417,8 +107034,8 @@ function writeStationSnapshot(options) {
106417
107034
  },
106418
107035
  files: manifestFiles
106419
107036
  };
106420
- const manifestPath = resolve18(repoRoot, "resources", options.stationId, "skills", "sync-manifest.json");
106421
- mkdirSync24(dirname25(manifestPath), { recursive: true });
107037
+ const manifestPath = resolve20(repoRoot, "resources", options.stationId, "skills", "sync-manifest.json");
107038
+ mkdirSync24(dirname26(manifestPath), { recursive: true });
106422
107039
  writeFileSync22(manifestPath, `${JSON.stringify(manifest, null, 2)}
106423
107040
  `);
106424
107041
  return {
@@ -106852,10 +107469,10 @@ var init_create_sync_config = __esm(() => {
106852
107469
  // src/lib/codex-hook-rpc.ts
106853
107470
  import { execFile, spawn as spawn3 } from "child_process";
106854
107471
  import { realpathSync as realpathSync11, statSync as statSync20 } from "fs";
106855
- import { isAbsolute as isAbsolute20 } from "path";
107472
+ import { isAbsolute as isAbsolute22 } from "path";
106856
107473
  import { promisify } from "util";
106857
107474
  async function connectCodexHookRpc(options) {
106858
- const found = isAbsolute20(options.command) ? options.command : Bun.which(options.command, { PATH: process.env.PATH });
107475
+ const found = isAbsolute22(options.command) ? options.command : Bun.which(options.command, { PATH: process.env.PATH });
106859
107476
  if (!found)
106860
107477
  throw new Error("CODEX_HOOK_TRUST_NATIVE_UNAVAILABLE: install Codex or pass --codex-command");
106861
107478
  const binary = realpathSync11(found), stat3 = statSync20(binary);
@@ -106941,13 +107558,13 @@ async function connectCodexHookRpc(options) {
106941
107558
  request(method2, params) {
106942
107559
  if (stopped)
106943
107560
  return Promise.reject(new Error("CODEX_HOOK_TRUST_NATIVE_RPC_CLOSED"));
106944
- return new Promise((resolve19, reject2) => {
107561
+ return new Promise((resolve21, reject2) => {
106945
107562
  const id2 = nextId++;
106946
107563
  const timer = setTimeout(() => {
106947
107564
  fail4();
106948
107565
  child.kill();
106949
107566
  }, 20000);
106950
- pending.set(id2, { resolve: resolve19, reject: reject2, timer });
107567
+ pending.set(id2, { resolve: resolve21, reject: reject2, timer });
106951
107568
  child.stdin.write(JSON.stringify({ id: id2, method: method2, params }) + `
106952
107569
  `);
106953
107570
  });
@@ -106957,14 +107574,14 @@ async function connectCodexHookRpc(options) {
106957
107574
  child.stdin.end();
106958
107575
  if (child.exitCode !== null || child.signalCode !== null)
106959
107576
  return;
106960
- await new Promise((resolve19) => {
107577
+ await new Promise((resolve21) => {
106961
107578
  const timer = setTimeout(() => {
106962
107579
  child.kill();
106963
- resolve19();
107580
+ resolve21();
106964
107581
  }, 1000);
106965
107582
  child.once("exit", () => {
106966
107583
  clearTimeout(timer);
106967
- resolve19();
107584
+ resolve21();
106968
107585
  });
106969
107586
  });
106970
107587
  }
@@ -106985,7 +107602,7 @@ var init_codex_hook_rpc = __esm(() => {
106985
107602
  });
106986
107603
 
106987
107604
  // src/lib/codex-hook-trust-layout.ts
106988
- import { isDeepStrictEqual as isDeepStrictEqual4 } from "util";
107605
+ import { isDeepStrictEqual as isDeepStrictEqual5 } from "util";
106989
107606
  function codexTrustTextWitness(text3, keys3) {
106990
107607
  const parsed = Bun.TOML.parse(text3), wanted = new Set(keys3);
106991
107608
  const headers = [...text3.matchAll(/^[ \t]*(\[[^\r\n]+\])[ \t]*(#[^\r\n]*)?(?:\r?\n|$)/gm)];
@@ -107032,11 +107649,11 @@ function codexTrustTextWitness(text3, keys3) {
107032
107649
  comments.push(line);
107033
107650
  continue;
107034
107651
  }
107035
- const field = /^[ \t]*(?:enabled|trusted_hash)[ \t]*=[ \t]*(?:true|false|"(?:[^"\\]|\\.)*"|'[^']*')[ \t]*(#[^\r\n]*)?$/.exec(line);
107036
- if (!field)
107652
+ const field2 = /^[ \t]*(?:enabled|trusted_hash)[ \t]*=[ \t]*(?:true|false|"(?:[^"\\]|\\.)*"|'[^']*')[ \t]*(#[^\r\n]*)?$/.exec(line);
107653
+ if (!field2)
107037
107654
  throw fail4();
107038
- if (field[1])
107039
- comments.push(field[1]);
107655
+ if (field2[1])
107656
+ comments.push(field2[1]);
107040
107657
  }
107041
107658
  replacements2.push({ start, end, comments: comments.join(`
107042
107659
  `) + `
@@ -107050,7 +107667,7 @@ function codexTrustTextWitness(text3, keys3) {
107050
107667
  if (expected.hooks)
107051
107668
  delete expected.hooks.state;
107052
107669
  try {
107053
- if (!isDeepStrictEqual4(prune(Bun.TOML.parse(noState)), prune(expected)))
107670
+ if (!isDeepStrictEqual5(prune(Bun.TOML.parse(noState)), prune(expected)))
107054
107671
  throw fail4();
107055
107672
  } catch {
107056
107673
  throw fail4();
@@ -107071,59 +107688,59 @@ var fail4 = () => new Error('CODEX_HOOK_TRUST_UNSUPPORTED_LAYOUT: preserve and c
107071
107688
  var init_codex_hook_trust_layout = () => {};
107072
107689
 
107073
107690
  // src/lib/codex-hook-trust-files.ts
107074
- import { closeSync as closeSync18, constants as constants17, fstatSync as fstatSync18, fsyncSync as fsyncSync5, lstatSync as lstatSync25, openSync as openSync18, readSync as readSync14, writeFileSync as writeFileSync23 } from "fs";
107075
- import { createHash as createHash22 } from "crypto";
107076
- import { dirname as dirname26 } from "path";
107077
- function need2(value, code2) {
107691
+ import { closeSync as closeSync19, constants as constants18, fstatSync as fstatSync19, fsyncSync as fsyncSync6, lstatSync as lstatSync26, openSync as openSync19, readSync as readSync15, writeFileSync as writeFileSync23 } from "fs";
107692
+ import { createHash as createHash24 } from "crypto";
107693
+ import { dirname as dirname27 } from "path";
107694
+ function need3(value, code2) {
107078
107695
  if (!value)
107079
107696
  throw new Error(`CODEX_HOOK_TRUST_${code2}`);
107080
107697
  }
107081
107698
  function safeParents(file2) {
107082
- for (let p = dirname26(file2);; p = dirname26(p)) {
107083
- const s = lstatSync25(p);
107084
- need2(s.isDirectory() && !s.isSymbolicLink(), "UNSAFE_PARENT");
107085
- need2((s.mode & 18) === 0 || s.uid === 0 && (s.mode & 512) !== 0, "UNSAFE_PARENT");
107086
- if (dirname26(p) === p)
107699
+ for (let p = dirname27(file2);; p = dirname27(p)) {
107700
+ const s = lstatSync26(p);
107701
+ need3(s.isDirectory() && !s.isSymbolicLink(), "UNSAFE_PARENT");
107702
+ need3((s.mode & 18) === 0 || s.uid === 0 && (s.mode & 512) !== 0, "UNSAFE_PARENT");
107703
+ if (dirname27(p) === p)
107087
107704
  break;
107088
107705
  }
107089
107706
  }
107090
107707
  function snapshot(file2, privateFile = false, options = {}) {
107091
107708
  const readOnlyPackage = options.readOnlyPackage === true && !privateFile;
107092
107709
  safeParents(file2);
107093
- const initial2 = lstatSync25(file2, { bigint: true });
107094
- need2(initial2.isFile() && initial2.uid === BigInt(process.getuid()) && (initial2.nlink === 1n || readOnlyPackage && initial2.nlink > 1n) && (initial2.mode & 0o022n) === 0n && (!privateFile || (initial2.mode & 0o777n) === 0o600n), "UNSAFE_FILE");
107095
- need2(initial2.size <= 8n * 1024n * 1024n, "FILE_BOUND");
107096
- const fd = openSync18(file2, constants17.O_RDONLY | constants17.O_NOFOLLOW | constants17.O_NONBLOCK);
107710
+ const initial2 = lstatSync26(file2, { bigint: true });
107711
+ need3(initial2.isFile() && initial2.uid === BigInt(process.getuid()) && (initial2.nlink === 1n || readOnlyPackage && initial2.nlink > 1n) && (initial2.mode & 0o022n) === 0n && (!privateFile || (initial2.mode & 0o777n) === 0o600n), "UNSAFE_FILE");
107712
+ need3(initial2.size <= 8n * 1024n * 1024n, "FILE_BOUND");
107713
+ const fd = openSync19(file2, constants18.O_RDONLY | constants18.O_NOFOLLOW | constants18.O_NONBLOCK);
107097
107714
  try {
107098
- const before2 = fstatSync18(fd, { bigint: true });
107099
- need2(sameStat(initial2, before2), "INPUT_CHANGED");
107715
+ const before2 = fstatSync19(fd, { bigint: true });
107716
+ need3(sameStat(initial2, before2), "INPUT_CHANGED");
107100
107717
  const bytes = Buffer.alloc(Number(before2.size) + 1);
107101
107718
  let length = 0;
107102
107719
  while (length < bytes.length) {
107103
- const n2 = readSync14(fd, bytes, length, bytes.length - length, null);
107720
+ const n2 = readSync15(fd, bytes, length, bytes.length - length, null);
107104
107721
  if (!n2)
107105
107722
  break;
107106
107723
  length += n2;
107107
107724
  }
107108
- need2(length === Number(before2.size) && sameStat(before2, fstatSync18(fd, { bigint: true })) && sameStat(before2, lstatSync25(file2, { bigint: true })), "INPUT_CHANGED");
107725
+ need3(length === Number(before2.size) && sameStat(before2, fstatSync19(fd, { bigint: true })) && sameStat(before2, lstatSync26(file2, { bigint: true })), "INPUT_CHANGED");
107109
107726
  const content = bytes.subarray(0, length), text3 = new TextDecoder("utf-8", { fatal: true }).decode(content);
107110
- return { file: file2, privateFile, readOnlyPackage, text: text3, bytes: content, stat: before2, sha256: createHash22("sha256").update(content).digest("hex") };
107727
+ return { file: file2, privateFile, readOnlyPackage, text: text3, bytes: content, stat: before2, sha256: createHash24("sha256").update(content).digest("hex") };
107111
107728
  } finally {
107112
- closeSync18(fd);
107729
+ closeSync19(fd);
107113
107730
  }
107114
107731
  }
107115
107732
  function unchanged2(before2) {
107116
107733
  const after2 = snapshot(before2.file, before2.privateFile, before2.readOnlyPackage ? { readOnlyPackage: true } : {});
107117
- need2(sameStat(before2.stat, after2.stat) && after2.sha256 === before2.sha256, "INPUT_CHANGED");
107734
+ need3(sameStat(before2.stat, after2.stat) && after2.sha256 === before2.sha256, "INPUT_CHANGED");
107118
107735
  }
107119
107736
  function save2(file2, content) {
107120
107737
  safeParents(file2);
107121
- const fd = openSync18(file2, constants17.O_WRONLY | constants17.O_CREAT | constants17.O_EXCL | constants17.O_NOFOLLOW, 384);
107738
+ const fd = openSync19(file2, constants18.O_WRONLY | constants18.O_CREAT | constants18.O_EXCL | constants18.O_NOFOLLOW, 384);
107122
107739
  try {
107123
107740
  writeFileSync23(fd, content);
107124
- fsyncSync5(fd);
107741
+ fsyncSync6(fd);
107125
107742
  } finally {
107126
- closeSync18(fd);
107743
+ closeSync19(fd);
107127
107744
  }
107128
107745
  }
107129
107746
  var sameStat = (a, b) => ["dev", "ino", "uid", "nlink", "mode", "size", "mtimeNs", "ctimeNs"].every((key) => a[key] === b[key]);
@@ -107131,26 +107748,26 @@ var init_codex_hook_trust_files = () => {};
107131
107748
 
107132
107749
  // src/lib/codex-hook-trust-identity.ts
107133
107750
  import { realpathSync as realpathSync12 } from "fs";
107134
- import { dirname as dirname27, isAbsolute as isAbsolute21, join as join55 } from "path";
107751
+ import { dirname as dirname28, isAbsolute as isAbsolute23, join as join55 } from "path";
107135
107752
  function bindSkillsCli(command, reviewed) {
107136
107753
  const normal = Bun.which("skills", { PATH: process.env.PATH });
107137
- need2(normal, "SKILLS_COMMAND_UNAVAILABLE");
107754
+ need3(normal, "SKILLS_COMMAND_UNAVAILABLE");
107138
107755
  const resolved = realpathSync12(normal);
107139
- const bound = isAbsolute21(command) ? command : command === "skills" ? normal : undefined;
107140
- need2(bound && realpathSync12(bound) === resolved, "SKILLS_COMMAND_MISMATCH");
107756
+ const bound = isAbsolute23(command) ? command : command === "skills" ? normal : undefined;
107757
+ need3(bound && realpathSync12(bound) === resolved, "SKILLS_COMMAND_MISMATCH");
107141
107758
  const entrypoint = reviewed?.path ?? process.argv[1];
107142
- need2(entrypoint && realpathSync12(entrypoint) === resolved, "SKILLS_ENTRYPOINT_MISMATCH");
107759
+ need3(entrypoint && realpathSync12(entrypoint) === resolved, "SKILLS_ENTRYPOINT_MISMATCH");
107143
107760
  const cli = snapshot(resolved, false, { readOnlyPackage: true });
107144
- const manifest = snapshot(join55(dirname27(dirname27(resolved)), "package.json"), false, { readOnlyPackage: true });
107761
+ const manifest = snapshot(join55(dirname28(dirname28(resolved)), "package.json"), false, { readOnlyPackage: true });
107145
107762
  const pkg = JSON.parse(manifest.text);
107146
- need2(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved === join55(dirname27(manifest.file), "bin/index.js"), "SKILLS_PACKAGE_MISMATCH");
107763
+ need3(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved === join55(dirname28(manifest.file), "bin/index.js"), "SKILLS_PACKAGE_MISMATCH");
107147
107764
  if (reviewed)
107148
- need2(/^[a-f0-9]{64}$/.test(reviewed.sha256) && reviewed.sha256 === cli.sha256 && reviewed.version === pkg.version, "SKILLS_RELEASE_MISMATCH");
107149
- need2((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
107765
+ need3(/^[a-f0-9]{64}$/.test(reviewed.sha256) && reviewed.sha256 === cli.sha256 && reviewed.version === pkg.version, "SKILLS_RELEASE_MISMATCH");
107766
+ need3((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
107150
107767
  return {
107151
107768
  receipt: { path: resolved, version: pkg.version, sha256: cli.sha256, manifestSha256: manifest.sha256 },
107152
107769
  recheck() {
107153
- need2(Bun.which("skills", { PATH: process.env.PATH }) === normal && realpathSync12(normal) === resolved && realpathSync12(bound) === resolved && realpathSync12(entrypoint) === resolved, "SKILLS_COMMAND_CHANGED");
107770
+ need3(Bun.which("skills", { PATH: process.env.PATH }) === normal && realpathSync12(normal) === resolved && realpathSync12(bound) === resolved && realpathSync12(entrypoint) === resolved, "SKILLS_COMMAND_CHANGED");
107154
107771
  unchanged2(cli);
107155
107772
  unchanged2(manifest);
107156
107773
  }
@@ -107161,15 +107778,15 @@ var init_codex_hook_trust_identity = __esm(() => {
107161
107778
  });
107162
107779
 
107163
107780
  // src/lib/agent-codex-trust.ts
107164
- import { lstatSync as lstatSync26, mkdirSync as mkdirSync25, readdirSync as readdirSync20 } from "fs";
107165
- import { createHash as createHash23, randomUUID as randomUUID10 } from "crypto";
107166
- import { join as join56, resolve as resolve19 } from "path";
107781
+ import { lstatSync as lstatSync27, mkdirSync as mkdirSync25, readdirSync as readdirSync20 } from "fs";
107782
+ import { createHash as createHash25, randomUUID as randomUUID10 } from "crypto";
107783
+ import { join as join56, resolve as resolve21 } from "path";
107167
107784
  import { homedir as homedir11 } from "os";
107168
- import { isDeepStrictEqual as isDeepStrictEqual5 } from "util";
107785
+ import { isDeepStrictEqual as isDeepStrictEqual6 } from "util";
107169
107786
  async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRpc) {
107170
107787
  let rpc, journal;
107171
107788
  try {
107172
- const home = resolve19(options.home ?? homedir11()), dataDir3 = resolve19(options.dataDir ?? getDataDirReadOnly());
107789
+ const home = resolve21(options.home ?? homedir11()), dataDir3 = resolve21(options.dataDir ?? getDataDirReadOnly());
107173
107790
  assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home });
107174
107791
  const policyFile = snapshot(join56(dataDir3, "agent-policy.json"), true), policy = parseManagedSkillPolicy(policyFile.text);
107175
107792
  const binding = policy.bridge, alias = binding.rootAliases?.find((item) => item.agent === "codex");
@@ -107180,35 +107797,35 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
107180
107797
  for (const [event, [nativeEvent, label]] of Object.entries(eventNames)) {
107181
107798
  const command = renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, event);
107182
107799
  const groups = declarations[event];
107183
- need2(Array.isArray(groups), "DECLARATION_CHANGED");
107800
+ need3(Array.isArray(groups), "DECLARATION_CHANGED");
107184
107801
  const matches2 = groups.flatMap((group, gi) => (group.hooks ?? []).flatMap((entry, hi) => entry.command === command ? [{ group, entry, gi, hi }] : []));
107185
- need2(matches2.length === 1 && isDeepStrictEqual5(matches2[0].group, { hooks: [{ type: "command", command, timeout: 15 }] }), "DECLARATION_CHANGED");
107802
+ need3(matches2.length === 1 && isDeepStrictEqual6(matches2[0].group, { hooks: [{ type: "command", command, timeout: 15 }] }), "DECLARATION_CHANGED");
107186
107803
  expected.push({ event: nativeEvent, key: `${join56(home, ".codex/hooks.json")}:${label}:${matches2[0].gi}:${matches2[0].hi}`, command });
107187
107804
  }
107188
107805
  codexTrustTextWitness(configFile.text, expected.map((h) => h.key));
107189
107806
  rpc = await connect({ command: options.codexCommand ?? "codex", home, codexHome });
107190
- need2(SUPPORTED_CODEX_HOOK_VERSIONS.includes(rpc.version), "NATIVE_UNSUPPORTED_VERSION");
107807
+ need3(SUPPORTED_CODEX_HOOK_VERSIONS.includes(rpc.version), "NATIVE_UNSUPPORTED_VERSION");
107191
107808
  const list2 = async () => {
107192
107809
  const response = await rpc.request("hooks/list", { cwds: [home] });
107193
- need2(Array.isArray(response?.data) && response.data.length === 1 && response.data[0].cwd === home && Array.isArray(response.data[0].hooks) && response.data[0].hooks.length <= 1e4 && !response.data[0].errors?.length && !response.data[0].warnings?.length, "NATIVE_DISCOVERY_REFUSED");
107810
+ need3(Array.isArray(response?.data) && response.data.length === 1 && response.data[0].cwd === home && Array.isArray(response.data[0].hooks) && response.data[0].hooks.length <= 1e4 && !response.data[0].errors?.length && !response.data[0].warnings?.length, "NATIVE_DISCOVERY_REFUSED");
107194
107811
  return response.data[0].hooks;
107195
107812
  };
107196
107813
  const admit = (hooks) => expected.map((wanted) => {
107197
107814
  const canonicalKey = wanted.key.replace(join56(home, ".codex/hooks.json"), hooksPath);
107198
107815
  const matches2 = hooks.filter((h2) => h2.key === wanted.key || h2.key === canonicalKey);
107199
- need2(matches2.length === 1, "AMBIGUOUS_IDENTITY");
107816
+ need3(matches2.length === 1, "AMBIGUOUS_IDENTITY");
107200
107817
  const h = matches2[0];
107201
- need2(h.eventName === wanted.event && h.handlerType === "command" && h.command === wanted.command && h.matcher === null && h.timeoutSec === 15 && h.async === false && h.statusMessage === null && h.additionalContextLimit === null && [hooksPath, join56(home, ".codex/hooks.json")].includes(h.sourcePath) && h.source === "user" && h.pluginId === null && h.isManaged === false && /^sha256:[a-f0-9]{64}$/.test(h.currentHash) && typeof h.enabled === "boolean", "NATIVE_IDENTITY_CHANGED");
107202
- need2(hooks.filter((other) => other.command === wanted.command).length === 1, "AMBIGUOUS_IDENTITY");
107203
- need2(["trusted", "untrusted", "modified"].includes(h.trustStatus), "UNKNOWN_TRUST_STATUS");
107818
+ need3(h.eventName === wanted.event && h.handlerType === "command" && h.command === wanted.command && h.matcher === null && h.timeoutSec === 15 && h.async === false && h.statusMessage === null && h.additionalContextLimit === null && [hooksPath, join56(home, ".codex/hooks.json")].includes(h.sourcePath) && h.source === "user" && h.pluginId === null && h.isManaged === false && /^sha256:[a-f0-9]{64}$/.test(h.currentHash) && typeof h.enabled === "boolean", "NATIVE_IDENTITY_CHANGED");
107819
+ need3(hooks.filter((other) => other.command === wanted.command).length === 1, "AMBIGUOUS_IDENTITY");
107820
+ need3(["trusted", "untrusted", "modified"].includes(h.trustStatus), "UNKNOWN_TRUST_STATUS");
107204
107821
  return { key: h.key, event: wanted.event, command: wanted.command, handlerType: h.handlerType, timeoutSec: h.timeoutSec, sourcePath: h.sourcePath, currentHash: h.currentHash, enabled: h.enabled, trustStatus: h.trustStatus };
107205
107822
  });
107206
107823
  const discovered = await list2(), admitted = admit(discovered);
107207
107824
  const config2 = await rpc.request("config/read", { includeLayers: true, cwd: home });
107208
107825
  const layers = config2?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === configPath && !layer.name.profile);
107209
- need2(layers?.length === 1 && /^sha256:[a-f0-9]{64}$/.test(layers[0].version) && !layers[0].disabledReason && isDeepStrictEqual5(layers[0].config, original), "NATIVE_CONFIG_MISMATCH");
107210
- need2(config2.config && config2.config.features?.hooks !== false, "NATIVE_HOOKS_DISABLED");
107211
- need2(config2.layers.slice(0, config2.layers.indexOf(layers[0])).every((layer) => layer.config?.hooks === undefined && layer.config?.features?.hooks === undefined), "NATIVE_CONFIG_OVERRIDDEN");
107826
+ need3(layers?.length === 1 && /^sha256:[a-f0-9]{64}$/.test(layers[0].version) && !layers[0].disabledReason && isDeepStrictEqual6(layers[0].config, original), "NATIVE_CONFIG_MISMATCH");
107827
+ need3(config2.config && config2.config.features?.hooks !== false, "NATIVE_HOOKS_DISABLED");
107828
+ need3(config2.layers.slice(0, config2.layers.indexOf(layers[0])).every((layer) => layer.config?.hooks === undefined && layer.config?.features?.hooks === undefined), "NATIVE_CONFIG_OVERRIDDEN");
107212
107829
  const keys3 = admitted.map((h) => h.key), planned = admitted.filter((h) => !h.enabled || h.trustStatus !== "trusted");
107213
107830
  const preservationText = codexTrustTextWitness(configFile.text, keys3);
107214
107831
  const checkInputs = () => {
@@ -107219,19 +107836,19 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
107219
107836
  unchanged2(configFile);
107220
107837
  };
107221
107838
  checkInputs();
107222
- const planDigest = createHash23("sha256").update(json2({ version: 1, home, configPath, configSha256: configFile.sha256, configVersion: layers[0].version, policySha256: policyFile.sha256, hooksSha256: hooksFile.sha256, skillsCli: skillsCli.receipt, nativeVersion: rpc.version, declarations: expected, admitted })).digest("hex");
107839
+ const planDigest = createHash25("sha256").update(json2({ version: 1, home, configPath, configSha256: configFile.sha256, configVersion: layers[0].version, policySha256: policyFile.sha256, hooksSha256: hooksFile.sha256, skillsCli: skillsCli.receipt, nativeVersion: rpc.version, declarations: expected, admitted })).digest("hex");
107223
107840
  const baseReceipt = { planDigest, skillsCli: skillsCli.receipt, nativeVersion: rpc.version, ownedNativeProcessId: rpc.processId, agent: "codex", applied: false, planned, nativeEligible: planned.length === 0, transport: "owned-stdio-process", existingSessionsReloaded: false, nativeExecutionVerified: false };
107224
107841
  if (options.apply)
107225
- need2(options.reviewedPlanDigest === planDigest, "PLAN_CHANGED: run the dry-run again and pass its reviewed --plan-digest with --apply");
107842
+ need3(options.reviewedPlanDigest === planDigest, "PLAN_CHANGED: run the dry-run again and pass its reviewed --plan-digest with --apply");
107226
107843
  const parent = join56(dataDir3, "native-hook-trust");
107227
- const st = lstatSync26(parent, { throwIfNoEntry: false });
107844
+ const st = lstatSync27(parent, { throwIfNoEntry: false });
107228
107845
  if (st) {
107229
- need2(st.isDirectory() && !st.isSymbolicLink() && st.uid === process.getuid() && (st.mode & 511) === 448, "UNSAFE_JOURNAL");
107846
+ need3(st.isDirectory() && !st.isSymbolicLink() && st.uid === process.getuid() && (st.mode & 511) === 448, "UNSAFE_JOURNAL");
107230
107847
  const priorJournals = readdirSync20(parent);
107231
- need2(priorJournals.length < 1000, "JOURNAL_BOUND");
107848
+ need3(priorJournals.length < 1000, "JOURNAL_BOUND");
107232
107849
  for (const name of priorJournals) {
107233
- need2(/^[a-f0-9-]{36}$/.test(name), "UNSAFE_JOURNAL");
107234
- need2(lstatSync26(join56(parent, name, "receipt.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_REQUIRED: inspect the incomplete private journal before applying again");
107850
+ need3(/^[a-f0-9-]{36}$/.test(name), "UNSAFE_JOURNAL");
107851
+ need3(lstatSync27(join56(parent, name, "receipt.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_REQUIRED: inspect the incomplete private journal before applying again");
107235
107852
  }
107236
107853
  }
107237
107854
  if (!options.apply || !planned.length)
@@ -107244,7 +107861,7 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
107244
107861
  save2(join56(journal, "hooks.before.json"), hooksFile.bytes);
107245
107862
  save2(join56(journal, "policy.before.json"), policyFile.bytes);
107246
107863
  save2(join56(journal, "intent.json"), json2({ version: 1, planDigest, skillsCli: skillsCli.receipt, nativeVersion: rpc.version, configPath, beforeSha256: configFile.sha256, hooksSha256: hooksFile.sha256, policySha256: policyFile.sha256, expectedVersion: layers[0].version, hooks: planned }));
107247
- need2(isDeepStrictEqual5(admit(await list2()), admitted), "NATIVE_DISCOVERY_CHANGED");
107864
+ need3(isDeepStrictEqual6(admit(await list2()), admitted), "NATIVE_DISCOVERY_CHANGED");
107248
107865
  checkInputs();
107249
107866
  let result2;
107250
107867
  try {
@@ -107252,19 +107869,19 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
107252
107869
  } catch {
107253
107870
  throw new Error("CODEX_HOOK_TRUST_NATIVE_WRITE_FAILED: reconcile the private journal before retrying");
107254
107871
  }
107255
- need2(result2?.status === "ok" && result2.filePath === configPath && /^sha256:[a-f0-9]{64}$/.test(result2.version), "NATIVE_WRITE_OVERRIDDEN");
107872
+ need3(result2?.status === "ok" && result2.filePath === configPath && /^sha256:[a-f0-9]{64}$/.test(result2.version), "NATIVE_WRITE_OVERRIDDEN");
107256
107873
  const after2 = snapshot(configPath, true), expectedConfig = structuredClone(original);
107257
107874
  expectedConfig.hooks ??= {};
107258
107875
  expectedConfig.hooks.state ??= {};
107259
107876
  for (const h of planned)
107260
107877
  expectedConfig.hooks.state[h.key] = { ...expectedConfig.hooks.state[h.key], enabled: true, trusted_hash: h.currentHash };
107261
- need2(isDeepStrictEqual5(structure(after2.text), expectedConfig) && codexTrustTextWitness(after2.text, keys3) === preservationText, "PRESERVATION_FAILED");
107878
+ need3(isDeepStrictEqual6(structure(after2.text), expectedConfig) && codexTrustTextWitness(after2.text, keys3) === preservationText, "PRESERVATION_FAILED");
107262
107879
  unchanged2(policyFile);
107263
107880
  unchanged2(hooksFile);
107264
107881
  assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home });
107265
107882
  const current = await list2(), confirmed = admit(current);
107266
- need2(confirmed.every((h) => h.enabled && h.trustStatus === "trusted") && isDeepStrictEqual5(confirmed.map((h) => [h.key, h.currentHash]), admitted.map((h) => [h.key, h.currentHash])), "NATIVE_NOT_ELIGIBLE");
107267
- need2(isDeepStrictEqual5(current.filter((h) => !keys3.includes(h.key)), discovered.filter((h) => !keys3.includes(h.key))), "UNRELATED_HOOK_CHANGED");
107883
+ need3(confirmed.every((h) => h.enabled && h.trustStatus === "trusted") && isDeepStrictEqual6(confirmed.map((h) => [h.key, h.currentHash]), admitted.map((h) => [h.key, h.currentHash])), "NATIVE_NOT_ELIGIBLE");
107884
+ need3(isDeepStrictEqual6(current.filter((h) => !keys3.includes(h.key)), discovered.filter((h) => !keys3.includes(h.key))), "UNRELATED_HOOK_CHANGED");
107268
107885
  unchanged2(after2);
107269
107886
  unchanged2(hooksFile);
107270
107887
  unchanged2(policyFile);
@@ -107298,39 +107915,142 @@ var init_agent_codex_trust = __esm(() => {
107298
107915
  eventNames = { UserPromptSubmit: ["userPromptSubmit", "user_prompt_submit"], SessionStart: ["sessionStart", "session_start"], SubagentStart: ["subagentStart", "subagent_start"] };
107299
107916
  });
107300
107917
 
107918
+ // src/lib/hook-diagnostics.ts
107919
+ function hookChildError(stdout, stage) {
107920
+ let code2;
107921
+ if (stdout.length <= 16 * 1024) {
107922
+ try {
107923
+ code2 = JSON.parse(stdout)?.error?.code;
107924
+ } catch {}
107925
+ }
107926
+ return new HookDiagnosticError(typeof code2 === "string" && CONTEXT_ERROR_CODES.has(code2) ? code2 : "SKILLS_CONTEXT_FAILED", stage);
107927
+ }
107928
+ function hookFailureReason(error61, profileId) {
107929
+ const owned = error61 instanceof HookDiagnosticError;
107930
+ const code2 = owned && (CONTEXT_ERROR_CODES.has(error61.code) || ["SKILLS_HOOK_TIMEOUT", "SKILLS_HOOK_INVALID_RESPONSE"].includes(error61.code)) ? error61.code : "SKILLS_HOOK_FAILED";
107931
+ const profile = typeof profileId === "string" && /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(profileId) && !profileId.includes("..") ? profileId : undefined;
107932
+ const identity4 = [profile ? `profile=${profile}` : undefined, owned ? `stage=${error61.stage}` : undefined].filter(Boolean).join(", ");
107933
+ const prefix = `Skills context is unavailable [${code2}]${identity4 ? ` (${identity4})` : ""}.`;
107934
+ if (code2 === "PROFILE_LOCK_MISMATCH") {
107935
+ return `${prefix} This session or project is pinned to a different profile. Inspect the session with skills sessions show <session-id> --json; review skills sessions reconcile for an intentional session change, or explicit project sync for a project change. Sync alone does not change that pin.`;
107936
+ }
107937
+ if (code2.startsWith("SESSION_")) {
107938
+ return `${prefix} Inspect the session with skills sessions show <session-id> --json and review its parent or concurrent writer before retrying. Do not remove or rewrite its receipt to bypass this refusal.`;
107939
+ }
107940
+ if (["PROFILE_IDENTITY_MISMATCH", "BUNDLE_DIGEST_MISMATCH", "BUNDLE_IDENTITY_MISMATCH", "INVALID_RECEIPT", "INVALID_CACHE_FILE", "UNSAFE_CACHE_PATH"].includes(code2)) {
107941
+ return `${prefix} Verify the selected authority and receipt integrity before repairing the profile; do not bypass verification or substitute another cache.`;
107942
+ }
107943
+ const selected = profile ?? "<id>";
107944
+ return `${prefix} Run skills sync --selection-profile ${selected} --json, then diagnose with skills context --stdin --json --cached --selection-profile ${selected} using the same hook session and working-directory fields. Do not include credentials in diagnostic input.`;
107945
+ }
107946
+ var CONTEXT_ERROR_CODES, HookDiagnosticError;
107947
+ var init_hook_diagnostics = __esm(() => {
107948
+ CONTEXT_ERROR_CODES = new Set([
107949
+ "SKILLS_CONTEXT_FAILED",
107950
+ "PROFILE_LOCK_MISMATCH",
107951
+ "PROFILE_IDENTITY_MISMATCH",
107952
+ "PROFILE_APPLIED_REPORT_FAILED",
107953
+ "CACHED_AUTHORITY_REQUIRED",
107954
+ "CACHED_PROFILE_EXPIRED",
107955
+ "CACHED_PROFILE_MISSING",
107956
+ "CACHED_BUNDLE_MISSING",
107957
+ "INVALID_CONTEXT_INPUT",
107958
+ "CONTEXT_INPUT_TOO_LARGE",
107959
+ "INVALID_CONTEXT_BUDGET",
107960
+ "INVALID_SELECTION",
107961
+ "INVALID_SELECTION_ALIASES",
107962
+ "INVALID_RECEIPT",
107963
+ "INVALID_CACHE_FILE",
107964
+ "UNSAFE_CACHE_PATH",
107965
+ "RECEIPT_TOO_LARGE",
107966
+ "BUNDLE_DIGEST_MISMATCH",
107967
+ "BUNDLE_IDENTITY_MISMATCH",
107968
+ "BUNDLE_UNAVAILABLE",
107969
+ "BUNDLE_TOO_LARGE",
107970
+ "SKILL_NOT_SELECTED",
107971
+ "INVALID_SESSION",
107972
+ "SESSION_PARENT_NOT_FOUND",
107973
+ "SESSION_NOT_FOUND",
107974
+ "SESSION_GENERATION_CHANGED",
107975
+ "SESSION_GENERATION_EXHAUSTED",
107976
+ "SESSION_PARENT_CHANGED",
107977
+ "SESSION_RECEIPT_CHANGED",
107978
+ "SESSION_RECONCILIATION_INCOMPLETE",
107979
+ "SESSION_WRITE_LOCKED",
107980
+ "SESSION_WRITE_LOCK_CHANGED"
107981
+ ]);
107982
+ HookDiagnosticError = class HookDiagnosticError extends Error {
107983
+ code;
107984
+ stage;
107985
+ constructor(code2, stage) {
107986
+ super("Skills hook operation failed");
107987
+ this.code = code2;
107988
+ this.stage = stage;
107989
+ }
107990
+ };
107991
+ });
107992
+
107301
107993
  // src/cli/commands/agent-integration.ts
107302
107994
  var exports_agent_integration = {};
107303
107995
  __export(exports_agent_integration, {
107304
107996
  registerAgentIntegration: () => registerAgentIntegration
107305
107997
  });
107306
107998
  import { readFileSync as readFileSync37 } from "fs";
107307
- import { isAbsolute as isAbsolute22 } from "path";
107999
+ import { isAbsolute as isAbsolute24 } from "path";
108000
+ function pinnedHookProfile(input3, configuredProfile) {
108001
+ try {
108002
+ const parsed = parseSkillContextInput(JSON.stringify(input3));
108003
+ if (!parsed.sessionId)
108004
+ return configuredProfile;
108005
+ const sessionId = parsed.agentId ? `${parsed.sessionId}:${parsed.agentId}` : parsed.sessionId;
108006
+ const session = readSkillSessionSnapshotIfExists(sessionId);
108007
+ const parent = !session && parsed.agentId ? readSkillSessionSnapshotIfExists(parsed.sessionId) : null;
108008
+ return session?.receipt.profile.profileId ?? parent?.receipt.profile.profileId ?? configuredProfile;
108009
+ } catch (error61) {
108010
+ if (error61 instanceof SkillSelectionError)
108011
+ throw new HookDiagnosticError(error61.code, "context");
108012
+ throw error61;
108013
+ }
108014
+ }
107308
108015
  async function contextForHook(input3, profileId, cached2, deadline) {
107309
108016
  const remaining = deadline - Date.now();
107310
108017
  if (remaining <= 0)
107311
- throw new Error("Skills hook deadline exceeded");
108018
+ throw new HookDiagnosticError("SKILLS_HOOK_TIMEOUT", "context");
107312
108019
  const args2 = [process.execPath, process.argv[1], "context", "--stdin", "--json", "--selection-profile", profileId];
107313
108020
  if (cached2)
107314
108021
  args2.push("--cached");
107315
108022
  const child = Bun.spawn(args2, { stdin: new Blob([JSON.stringify(input3)]), stdout: "pipe", stderr: "pipe", env: { ...process.env, NO_COLOR: "1" } });
107316
- const timer = setTimeout(() => child.kill("SIGKILL"), Math.min(6500, remaining));
108023
+ let timedOut = false;
108024
+ const timer = setTimeout(() => {
108025
+ timedOut = true;
108026
+ child.kill("SIGKILL");
108027
+ }, Math.min(6500, remaining));
107317
108028
  let result2;
107318
108029
  let status;
108030
+ let output2;
107319
108031
  try {
107320
108032
  const [stdout, , exitCode] = await Promise.all([new Response(child.stdout).text(), new Response(child.stderr).text(), child.exited]);
108033
+ if (timedOut)
108034
+ throw new HookDiagnosticError("SKILLS_HOOK_TIMEOUT", "context");
107321
108035
  status = exitCode;
107322
- result2 = JSON.parse(stdout);
108036
+ output2 = stdout;
107323
108037
  } finally {
107324
108038
  clearTimeout(timer);
107325
108039
  }
107326
108040
  if (status !== 0) {
107327
- if (cached2 && RECOVERABLE_CONTEXT_CACHE_ERRORS.has(result2?.error?.code)) {
108041
+ const failure = hookChildError(output2, "context");
108042
+ if (cached2 && RECOVERABLE_CONTEXT_CACHE_ERRORS.has(failure.code)) {
107328
108043
  return contextForHook(input3, profileId, false, deadline);
107329
108044
  }
107330
- throw new Error("Skills context could not be resolved");
108045
+ throw failure;
108046
+ }
108047
+ try {
108048
+ result2 = JSON.parse(output2);
108049
+ } catch {
108050
+ throw new HookDiagnosticError("SKILLS_HOOK_INVALID_RESPONSE", "context");
107331
108051
  }
107332
108052
  if (typeof result2?.context !== "string")
107333
- throw new Error("Invalid Skills context response");
108053
+ throw new HookDiagnosticError("SKILLS_HOOK_INVALID_RESPONSE", "context");
107334
108054
  return result2;
107335
108055
  }
107336
108056
  function agents(value) {
@@ -107377,6 +108097,7 @@ function registerAgentIntegration(parent) {
107377
108097
  hook.command("user-prompt").requiredOption("--agent <agent>", `Native payload/output adapter: ${INTEGRATION_AGENTS.join(", ")}`).option("--event <event>", "Native lifecycle event supplied by the installed adapter").option("--selection-profile <id>", "Selection profile to load").description("Read native lifecycle JSON on stdin and return selected context").action(async (options) => {
107378
108098
  const deadline = Date.now() + 12000;
107379
108099
  let event = options.agent === "hermes" && options.event === "pre_tool_call" ? "pre_tool_call" : "UserPromptSubmit";
108100
+ let selectionProfile;
107380
108101
  try {
107381
108102
  if (agents(options.agent).length !== 1)
107382
108103
  throw new Error("A hook invocation requires one agent");
@@ -107393,18 +108114,18 @@ function registerAgentIntegration(parent) {
107393
108114
  input3.hook_event_name = event;
107394
108115
  const projects = [process.cwd()];
107395
108116
  if (input3.cwd !== undefined) {
107396
- if (typeof input3.cwd !== "string" || !isAbsolute22(input3.cwd) || input3.cwd.includes("\x00"))
108117
+ if (typeof input3.cwd !== "string" || !isAbsolute24(input3.cwd) || input3.cwd.includes("\x00"))
107397
108118
  throw new Error("Invalid native hook working directory");
107398
108119
  projects.push(input3.cwd);
107399
108120
  }
107400
108121
  if (options.agent === "cursor") {
107401
- if (!Array.isArray(input3.workspace_roots) || input3.workspace_roots.length > 32 || input3.workspace_roots.some((path) => typeof path !== "string" || !isAbsolute22(path) || path.includes("\x00")))
108122
+ if (!Array.isArray(input3.workspace_roots) || input3.workspace_roots.length > 32 || input3.workspace_roots.some((path) => typeof path !== "string" || !isAbsolute24(path) || path.includes("\x00")))
107402
108123
  throw new Error("Invalid Cursor workspace roots");
107403
108124
  projects.push(...input3.workspace_roots);
107404
108125
  input3.cwd ??= input3.workspace_roots[0] ?? process.cwd();
107405
108126
  input3.session_id ??= input3.conversation_id;
107406
108127
  }
107407
- const selectionProfile = selectedProfileId(options.selectionProfile);
108128
+ selectionProfile = selectedProfileId(options.selectionProfile);
107408
108129
  if (options.agent === "hermes" && event === "pre_tool_call") {
107409
108130
  assertManagedAgentBridge("hermes", { projectDirs: projects, profileId: selectionProfile });
107410
108131
  assertHermesTool(input3);
@@ -107426,17 +108147,24 @@ function registerAgentIntegration(parent) {
107426
108147
  if (event === "SessionStart") {
107427
108148
  const remaining = deadline - Date.now();
107428
108149
  if (remaining <= 0)
107429
- throw new Error("Skills hook deadline exceeded");
108150
+ throw new HookDiagnosticError("SKILLS_HOOK_TIMEOUT", "sync");
107430
108151
  const refresh = Bun.spawn([process.execPath, process.argv[1], "sync", "--selection-profile", selectionProfile, "--json"], { stdin: "ignore", stdout: "pipe", stderr: "pipe", env: { ...process.env, NO_COLOR: "1" } });
107431
- const timer = setTimeout(() => refresh.kill("SIGKILL"), Math.min(6500, remaining));
108152
+ let timedOut = false;
108153
+ const timer = setTimeout(() => {
108154
+ timedOut = true;
108155
+ refresh.kill("SIGKILL");
108156
+ }, Math.min(6500, remaining));
107432
108157
  try {
107433
- const [, , status] = await Promise.all([new Response(refresh.stdout).text(), new Response(refresh.stderr).text(), refresh.exited]);
108158
+ const [stdout, , status] = await Promise.all([new Response(refresh.stdout).text(), new Response(refresh.stderr).text(), refresh.exited]);
108159
+ if (timedOut)
108160
+ throw new HookDiagnosticError("SKILLS_HOOK_TIMEOUT", "sync");
107434
108161
  if (status !== 0)
107435
- throw new Error("Session profile refresh failed");
108162
+ throw hookChildError(stdout, "sync");
107436
108163
  } finally {
107437
108164
  clearTimeout(timer);
107438
108165
  }
107439
108166
  }
108167
+ selectionProfile = pinnedHookProfile(input3, selectionProfile);
107440
108168
  const result2 = await contextForHook(input3, selectionProfile, true, deadline);
107441
108169
  const output2 = hookContextOutput(event, result2);
107442
108170
  if (options.agent === "hermes") {
@@ -107449,7 +108177,7 @@ function registerAgentIntegration(parent) {
107449
108177
  await writeCliOutput(JSON.stringify(output2));
107450
108178
  }
107451
108179
  } catch (error61) {
107452
- const reason = error61 instanceof Error && error61.message.startsWith("NATIVE_SKILL_DRIFT:") ? error61.message : "Skills context is unavailable. Run skills sync --selection-profile <id> and skills context --stdin --json to diagnose the selected profile.";
108180
+ const reason = error61 instanceof Error && error61.message.startsWith("NATIVE_SKILL_DRIFT:") ? error61.message : hookFailureReason(error61, selectionProfile);
107453
108181
  if (options.agent === "hermes") {
107454
108182
  await writeCliOutput(JSON.stringify(event === "pre_tool_call" ? { action: "block", message: reason } : { context: `Required Skills context is unavailable. ${reason} Do not substitute native skill payloads; stop and repair the bridge before task actions.` }));
107455
108183
  } else if (options.agent === "claude" && event === "PreToolUse")
@@ -107489,6 +108217,8 @@ var init_agent_integration2 = __esm(() => {
107489
108217
  init_agent_adapters();
107490
108218
  init_agent_integration();
107491
108219
  init_agent_codex_trust();
108220
+ init_hook_diagnostics();
108221
+ init_selection_cache();
107492
108222
  RECOVERABLE_CONTEXT_CACHE_ERRORS = new Set(["CACHED_PROFILE_EXPIRED", "CACHED_PROFILE_MISSING", "CACHED_BUNDLE_MISSING"]);
107493
108223
  });
107494
108224
 
@@ -107627,17 +108357,17 @@ var exports_profiles = {};
107627
108357
  __export(exports_profiles, {
107628
108358
  registerProfiles: () => registerProfiles
107629
108359
  });
107630
- import { closeSync as closeSync19, constants as constants18, fstatSync as fstatSync19, openSync as openSync19, readSync as readSync15, writeFileSync as writeFileSync24 } from "fs";
108360
+ import { closeSync as closeSync20, constants as constants19, fstatSync as fstatSync20, openSync as openSync20, readSync as readSync16, writeFileSync as writeFileSync24 } from "fs";
107631
108361
  function readProfileInput(path) {
107632
- const fd = openSync19(path, constants18.O_RDONLY | constants18.O_NONBLOCK);
108362
+ const fd = openSync20(path, constants19.O_RDONLY | constants19.O_NONBLOCK);
107633
108363
  try {
107634
- const stat3 = fstatSync19(fd);
108364
+ const stat3 = fstatSync20(fd);
107635
108365
  if (!stat3.isFile() || stat3.size > MAX_PROFILE_DOCUMENT_BYTES)
107636
108366
  throw new Error("Profile input exceeds the size limit or is not a regular file");
107637
108367
  const bytes = Buffer.alloc(MAX_PROFILE_DOCUMENT_BYTES + 1);
107638
108368
  let size2 = 0;
107639
108369
  while (size2 < bytes.length) {
107640
- const read3 = readSync15(fd, bytes, size2, bytes.length - size2, null);
108370
+ const read3 = readSync16(fd, bytes, size2, bytes.length - size2, null);
107641
108371
  if (!read3)
107642
108372
  break;
107643
108373
  size2 += read3;
@@ -107646,7 +108376,7 @@ function readProfileInput(path) {
107646
108376
  throw new Error("Profile input exceeds the size limit");
107647
108377
  return new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, size2));
107648
108378
  } finally {
107649
- closeSync19(fd);
108379
+ closeSync20(fd);
107650
108380
  }
107651
108381
  }
107652
108382
  function registerProfiles(parent) {
@@ -107697,23 +108427,23 @@ __export(exports_grants, {
107697
108427
  registerGrants: () => registerGrants
107698
108428
  });
107699
108429
  import {
107700
- constants as constants19,
107701
- closeSync as closeSync20,
107702
- fstatSync as fstatSync20,
107703
- openSync as openSync20,
107704
- readSync as readSync16,
108430
+ constants as constants20,
108431
+ closeSync as closeSync21,
108432
+ fstatSync as fstatSync21,
108433
+ openSync as openSync21,
108434
+ readSync as readSync17,
107705
108435
  writeFileSync as writeFileSync25
107706
108436
  } from "fs";
107707
108437
  function readInput(path) {
107708
- const fd = openSync20(path, constants19.O_RDONLY | constants19.O_NONBLOCK);
108438
+ const fd = openSync21(path, constants20.O_RDONLY | constants20.O_NONBLOCK);
107709
108439
  try {
107710
- const stat3 = fstatSync20(fd);
108440
+ const stat3 = fstatSync21(fd);
107711
108441
  if (!stat3.isFile() || stat3.size > MAX_EXECUTION_GRANT_BYTES)
107712
108442
  throw new Error("Grant input must be a regular file within the policy size limit.");
107713
108443
  const bytes = Buffer.alloc(MAX_EXECUTION_GRANT_BYTES + 1);
107714
108444
  let size2 = 0;
107715
108445
  while (size2 < bytes.length) {
107716
- const count = readSync16(fd, bytes, size2, bytes.length - size2, null);
108446
+ const count = readSync17(fd, bytes, size2, bytes.length - size2, null);
107717
108447
  if (!count)
107718
108448
  break;
107719
108449
  size2 += count;
@@ -107726,7 +108456,7 @@ function readInput(path) {
107726
108456
  throw new Error("Grant input must be a JSON document containing a grants array.");
107727
108457
  }
107728
108458
  } finally {
107729
- closeSync20(fd);
108459
+ closeSync21(fd);
107730
108460
  }
107731
108461
  }
107732
108462
  function registerGrants(parent) {
@@ -107762,7 +108492,7 @@ var init_grants = __esm(() => {
107762
108492
  });
107763
108493
 
107764
108494
  // src/lib/station-hydrate.ts
107765
- import { createHash as createHash24 } from "crypto";
108495
+ import { createHash as createHash26 } from "crypto";
107766
108496
  import {
107767
108497
  copyFileSync as copyFileSync2,
107768
108498
  mkdirSync as mkdirSync26,
@@ -107771,7 +108501,7 @@ import {
107771
108501
  statSync as statSync21,
107772
108502
  writeFileSync as writeFileSync26
107773
108503
  } from "fs";
107774
- import { dirname as dirname28, join as join57, resolve as resolve20, sep as sep10 } from "path";
108504
+ import { dirname as dirname29, join as join57, resolve as resolve22, sep as sep10 } from "path";
107775
108505
  function fail5(code2, message, detail = []) {
107776
108506
  throw new StationSnapshotError(code2, message, detail);
107777
108507
  }
@@ -107965,12 +108695,12 @@ function skillSha256(skill) {
107965
108695
  return sha256File(skill.files[0].winner.fullPath);
107966
108696
  }
107967
108697
  const joined = skill.files.map((file2) => sha256File(file2.winner.fullPath));
107968
- return createHash24("sha256").update(joined.sort().join(`
108698
+ return createHash26("sha256").update(joined.sort().join(`
107969
108699
  `)).digest("hex");
107970
108700
  }
107971
108701
  function writeStationHydration(options) {
107972
- const repoRoot = resolve20(options.repoRoot ?? process.cwd());
107973
- const cacheRoot = resolve20(options.cacheRoot ?? resolveCorpusRoot());
108702
+ const repoRoot = resolve22(options.repoRoot ?? process.cwd());
108703
+ const cacheRoot = resolve22(options.cacheRoot ?? resolveCorpusRoot());
107974
108704
  const plan = planStationHydration(options.stationId, repoRoot);
107975
108705
  const resultSkills = plan.winners.map((skill) => ({
107976
108706
  ident: skill.ident,
@@ -108004,13 +108734,13 @@ function writeStationHydration(options) {
108004
108734
  for (const skill of plan.winners) {
108005
108735
  for (const file2 of skill.files) {
108006
108736
  const destination = join57(cacheRoot, skill.ident, file2.withinIdent);
108007
- const digest3 = sha256File(file2.winner.fullPath);
108737
+ const digest4 = sha256File(file2.winner.fullPath);
108008
108738
  let existingDigest = null;
108009
108739
  try {
108010
108740
  existingDigest = sha256File(destination);
108011
108741
  } catch {}
108012
108742
  if (existingDigest !== null) {
108013
- if (existingDigest === digest3) {
108743
+ if (existingDigest === digest4) {
108014
108744
  continue;
108015
108745
  }
108016
108746
  conflicts.push(`existing destination differs from snapshot winner: ${destination}`);
@@ -108024,7 +108754,7 @@ function writeStationHydration(options) {
108024
108754
  }
108025
108755
  let written = 0;
108026
108756
  for (const entry of toWrite) {
108027
- mkdirSync26(dirname28(entry.destination), { recursive: true });
108757
+ mkdirSync26(dirname29(entry.destination), { recursive: true });
108028
108758
  copyFileSync2(entry.fullPath, entry.destination);
108029
108759
  written += 1;
108030
108760
  }
@@ -108045,8 +108775,8 @@ function writeStationHydration(options) {
108045
108775
  },
108046
108776
  skills: resultSkills
108047
108777
  };
108048
- const hydrationManifestPath = join57(dirname28(cacheRoot), `hydration-${options.stationId}.json`);
108049
- mkdirSync26(dirname28(hydrationManifestPath), { recursive: true });
108778
+ const hydrationManifestPath = join57(dirname29(cacheRoot), `hydration-${options.stationId}.json`);
108779
+ mkdirSync26(dirname29(hydrationManifestPath), { recursive: true });
108050
108780
  writeFileSync26(hydrationManifestPath, `${JSON.stringify(hydration, null, 2)}
108051
108781
  `);
108052
108782
  return {
@@ -108122,10 +108852,10 @@ var init_hydrate = __esm(() => {
108122
108852
  });
108123
108853
 
108124
108854
  // src/lib/prepare-skill.ts
108125
- import { createHash as createHash25, randomUUID as randomUUID11 } from "crypto";
108126
- import { chmodSync as chmodSync3, existsSync as existsSync34, lstatSync as lstatSync27, mkdirSync as mkdirSync27, mkdtempSync as mkdtempSync6, readFileSync as readFileSync39, readdirSync as readdirSync22, renameSync as renameSync12, rmSync as rmSync9, writeFileSync as writeFileSync27 } from "fs";
108855
+ import { createHash as createHash27, randomUUID as randomUUID11 } from "crypto";
108856
+ import { chmodSync as chmodSync3, existsSync as existsSync34, lstatSync as lstatSync28, mkdirSync as mkdirSync27, mkdtempSync as mkdtempSync6, readFileSync as readFileSync39, readdirSync as readdirSync22, renameSync as renameSync12, rmSync as rmSync9, writeFileSync as writeFileSync27 } from "fs";
108127
108857
  import { tmpdir as tmpdir2 } from "os";
108128
- import { dirname as dirname29, isAbsolute as isAbsolute23, join as join58, relative as relative9, resolve as resolve21, sep as sep11 } from "path";
108858
+ import { dirname as dirname30, isAbsolute as isAbsolute25, join as join58, relative as relative9, resolve as resolve23, sep as sep11 } from "path";
108129
108859
  function prepareSkill(name, options) {
108130
108860
  const normalized = normalizePortableSkillName(name);
108131
108861
  if (!new RegExp(SEMVER_PATTERN).test(options.version))
@@ -108170,7 +108900,7 @@ function prepareSkill(name, options) {
108170
108900
  mkdirSync27(join58(staging, directory2), { recursive: true });
108171
108901
  for (const file2 of before2.files) {
108172
108902
  const destination = join58(staging, file2.path);
108173
- mkdirSync27(dirname29(destination), { recursive: true });
108903
+ mkdirSync27(dirname30(destination), { recursive: true });
108174
108904
  writeFileSync27(destination, file2.bytes, { mode: file2.mode });
108175
108905
  }
108176
108906
  const stagedManifest = join58(staging, "skill.json");
@@ -108230,8 +108960,8 @@ function validateRuntimeEntrypoint(candidate2, root2) {
108230
108960
  const entry = candidate2.runtime.entrypoint;
108231
108961
  if (typeof entry !== "string")
108232
108962
  return;
108233
- const target = resolve21(root2, entry), rel = relative9(root2, target);
108234
- if (isAbsolute23(entry) || /^[a-zA-Z]:/.test(entry) || entry.includes("\\") || !rel || rel === ".." || rel.startsWith(`..${sep11}`) || isAbsolute23(rel) || !existsSync34(target) || !lstatSync27(target).isFile()) {
108963
+ const target = resolve23(root2, entry), rel = relative9(root2, target);
108964
+ if (isAbsolute25(entry) || /^[a-zA-Z]:/.test(entry) || entry.includes("\\") || !rel || rel === ".." || rel.startsWith(`..${sep11}`) || isAbsolute25(rel) || !existsSync34(target) || !lstatSync28(target).isFile()) {
108235
108965
  throw new Error("Executable runtime.entrypoint must name an existing regular file inside the skill directory.");
108236
108966
  }
108237
108967
  }
@@ -108239,31 +108969,31 @@ function isRecord6(value) {
108239
108969
  return typeof value === "object" && value !== null && !Array.isArray(value);
108240
108970
  }
108241
108971
  function validateRawCandidate(candidate2) {
108242
- for (const field of ["standard", "name", "description", "version"]) {
108243
- if (typeof candidate2[field] !== "string" || !candidate2[field].trim())
108244
- throw new Error(`skill.json ${field} is required.`);
108972
+ for (const field2 of ["standard", "name", "description", "version"]) {
108973
+ if (typeof candidate2[field2] !== "string" || !candidate2[field2].trim())
108974
+ throw new Error(`skill.json ${field2} is required.`);
108245
108975
  }
108246
- for (const field of ["displayName", "category"]) {
108247
- if (candidate2[field] !== undefined && (typeof candidate2[field] !== "string" || !candidate2[field].trim()))
108248
- throw new Error(`Invalid skill.json ${field}.`);
108976
+ for (const field2 of ["displayName", "category"]) {
108977
+ if (candidate2[field2] !== undefined && (typeof candidate2[field2] !== "string" || !candidate2[field2].trim()))
108978
+ throw new Error(`Invalid skill.json ${field2}.`);
108249
108979
  }
108250
108980
  if (candidate2.tags !== undefined && (!Array.isArray(candidate2.tags) || candidate2.tags.some((tag) => typeof tag !== "string" || !tag.trim())))
108251
108981
  throw new Error("Invalid skill.json tags.");
108252
108982
  const issues = validatePortableManifestContract(candidate2, { strict: true });
108253
108983
  if (issues.length)
108254
108984
  throw new Error(`Invalid skill.json: ${issues.map((issue2) => issue2.code).join(", ")}`);
108255
- for (const field of ["inputs", "commands"]) {
108256
- const items = candidate2[field];
108985
+ for (const field2 of ["inputs", "commands"]) {
108986
+ const items = candidate2[field2];
108257
108987
  if (items === undefined)
108258
108988
  continue;
108259
108989
  if (!Array.isArray(items))
108260
- throw new Error(`skill.json ${field} must be an array.`);
108990
+ throw new Error(`skill.json ${field2} must be an array.`);
108261
108991
  for (const item of items) {
108262
108992
  if (!isRecord6(item) || typeof item.name !== "string" || !item.name.trim())
108263
- throw new Error(`Invalid skill.json ${field} name.`);
108264
- if (field === "inputs" && (typeof item.type !== "string" || !item.type.trim() || item.required !== undefined && typeof item.required !== "boolean"))
108993
+ throw new Error(`Invalid skill.json ${field2} name.`);
108994
+ if (field2 === "inputs" && (typeof item.type !== "string" || !item.type.trim() || item.required !== undefined && typeof item.required !== "boolean"))
108265
108995
  throw new Error("Invalid skill.json input type or required flag.");
108266
- if (field === "commands") {
108996
+ if (field2 === "commands") {
108267
108997
  if (!/^[a-z0-9][a-z0-9._-]*$/.test(item.name))
108268
108998
  throw new Error("Invalid skill.json command name.");
108269
108999
  for (const target of ["entry", "command"])
@@ -108303,11 +109033,11 @@ function compareVersions(left, right) {
108303
109033
  return 0;
108304
109034
  }
108305
109035
  function snapshot2(root2) {
108306
- const rootStat = lstatSync27(root2);
109036
+ const rootStat = lstatSync28(root2);
108307
109037
  if (rootStat.isSymbolicLink() || !rootStat.isDirectory())
108308
109038
  throw new Error("Skill root must be a real directory, not a symlink.");
108309
109039
  const files = [], directories = [];
108310
- const hash4 = createHash25("sha256").update(`${rootStat.dev}:${rootStat.ino}\x00`);
109040
+ const hash4 = createHash27("sha256").update(`${rootStat.dev}:${rootStat.ino}\x00`);
108311
109041
  let count = 0, bytes = 0;
108312
109042
  const walk2 = (relative10) => {
108313
109043
  for (const name of readdirSync22(join58(root2, relative10)).sort()) {
@@ -108316,7 +109046,7 @@ function snapshot2(root2) {
108316
109046
  const path = relative10 ? `${relative10}/${name}` : name;
108317
109047
  if (++count > 20000)
108318
109048
  throw new Error("Skill exceeds the preparation entry limit (20000).");
108319
- const absolute = join58(root2, path), stat3 = lstatSync27(absolute);
109049
+ const absolute = join58(root2, path), stat3 = lstatSync28(absolute);
108320
109050
  if (stat3.isSymbolicLink())
108321
109051
  throw new Error(`Skill contains a symlink: ${path}. No files were changed.`);
108322
109052
  if (stat3.isDirectory() && name === "node_modules")
@@ -108731,7 +109461,7 @@ var init_schedule = __esm(() => {
108731
109461
 
108732
109462
  // src/lib/registry-sync.ts
108733
109463
  import { mkdirSync as mkdirSync28, writeFileSync as writeFileSync28 } from "fs";
108734
- import { dirname as dirname30, relative as relative10 } from "path";
109464
+ import { dirname as dirname31, relative as relative10 } from "path";
108735
109465
  function createRegistrySyncArtifact(options = {}) {
108736
109466
  const profile = options.profile ?? "all";
108737
109467
  const includeDocs = options.includeDocs ?? true;
@@ -108788,7 +109518,7 @@ function createRegistrySyncArtifact(options = {}) {
108788
109518
  };
108789
109519
  }
108790
109520
  function writeRegistrySyncArtifact(path, artifact) {
108791
- mkdirSync28(dirname30(path), { recursive: true });
109521
+ mkdirSync28(dirname31(path), { recursive: true });
108792
109522
  writeFileSync28(path, `${JSON.stringify(artifact, null, 2)}
108793
109523
  `);
108794
109524
  }
@@ -108821,12 +109551,12 @@ function registerRegistry(parent) {
108821
109551
  async function writeJson2(value, space) {
108822
109552
  const text3 = `${JSON.stringify(value, null, space)}
108823
109553
  `;
108824
- await new Promise((resolve22, reject2) => {
109554
+ await new Promise((resolve24, reject2) => {
108825
109555
  process.stdout.write(text3, (error61) => {
108826
109556
  if (error61)
108827
109557
  reject2(error61);
108828
109558
  else
108829
- resolve22();
109559
+ resolve24();
108830
109560
  });
108831
109561
  });
108832
109562
  }
@@ -109283,7 +110013,7 @@ var exports_private_publications = {};
109283
110013
  __export(exports_private_publications, {
109284
110014
  registerPrivatePublications: () => registerPrivatePublications
109285
110015
  });
109286
- import { resolve as resolve22 } from "path";
110016
+ import { resolve as resolve24 } from "path";
109287
110017
  function verifyOptions(options, action) {
109288
110018
  if (options.userId === undefined !== (options.membershipId === undefined) || options.userId !== undefined && (!publicationUuid(options.userId) || !publicationUuid(options.membershipId)))
109289
110019
  throw new PrivatePublicationError("PUBLICATION_CONTEXT_REQUIRED", "Provide both observed --user-id and --membership-id UUIDs.");
@@ -109328,9 +110058,9 @@ function registerPrivatePublications(parent) {
109328
110058
  if (code2 === null)
109329
110059
  return;
109330
110060
  const context2 = options.userId ? { userId: options.userId, membershipId: options.membershipId } : undefined;
109331
- const client2 = await privatePublicationSession(options.email, code2, context2), directory2 = resolve22(options.recoveryDir);
110061
+ const client2 = await privatePublicationSession(options.email, code2, context2), directory2 = resolve24(options.recoveryDir);
109332
110062
  if (action === "publish")
109333
- await preparePrivatePublication(client2, resolve22(args2[0]), directory2, { skillId: options.skillId, expectedCurrentVersionId: options.expectedCurrentVersion ?? null, idempotencyKey: options.idempotencyKey });
110063
+ await preparePrivatePublication(client2, resolve24(args2[0]), directory2, { skillId: options.skillId, expectedCurrentVersionId: options.expectedCurrentVersion ?? null, idempotencyKey: options.idempotencyKey });
109334
110064
  const result2 = action === "publish" || action === "resume" ? await continuePrivatePublication(client2, directory2, { confirm: true, waitMs: Number(options.waitSeconds) * 1000 }) : await inspectPrivatePublication(client2, directory2, action === "cancel");
109335
110065
  print2(result2, options.json);
109336
110066
  } catch (error61) {
@@ -109431,7 +110161,7 @@ __export(exports_auth, {
109431
110161
  import { createInterface as createInterface3 } from "readline";
109432
110162
  function prompt(question) {
109433
110163
  const rl = createInterface3({ input: process.stdin, output: process.stdout });
109434
- return new Promise((resolve23) => {
110164
+ return new Promise((resolve25) => {
109435
110165
  let settled = false;
109436
110166
  const finish = (answer) => {
109437
110167
  if (settled)
@@ -109440,7 +110170,7 @@ function prompt(question) {
109440
110170
  rl.close();
109441
110171
  if (answer === null)
109442
110172
  process.exitCode = 130;
109443
- resolve23(answer);
110173
+ resolve25(answer);
109444
110174
  };
109445
110175
  rl.once("SIGINT", () => finish(null));
109446
110176
  rl.once("close", () => finish(null));
@@ -109548,7 +110278,7 @@ function printWhoami(payload) {
109548
110278
  console.log(source_default.dim("(offline \u2014 showing cached info)"));
109549
110279
  }
109550
110280
  function sleep(ms) {
109551
- return new Promise((resolve23) => setTimeout(resolve23, ms));
110281
+ return new Promise((resolve25) => setTimeout(resolve25, ms));
109552
110282
  }
109553
110283
  function browserCommand(url2) {
109554
110284
  if (process.platform === "darwin")
@@ -110050,7 +110780,7 @@ function promptInvitationProof(kind) {
110050
110780
  const label = kind === "token" ? "invitation token" : "recovery code";
110051
110781
  const character = kind === "token" ? /^[A-Za-z0-9_-]$/ : /^\d$/;
110052
110782
  const { stdin, stderr: output2 } = process, wasRaw = stdin.isRaw, wasFlowing = stdin.readableFlowing;
110053
- return new Promise((resolve23) => {
110783
+ return new Promise((resolve25) => {
110054
110784
  let value = "", settled = false, overflow = false;
110055
110785
  const finish = (answer) => {
110056
110786
  if (settled)
@@ -110067,7 +110797,7 @@ function promptInvitationProof(kind) {
110067
110797
  `);
110068
110798
  if (answer === null)
110069
110799
  process.exitCode = 130;
110070
- resolve23(answer);
110800
+ resolve25(answer);
110071
110801
  };
110072
110802
  const cancel = () => finish(null);
110073
110803
  const keypress = (text3, key) => {
@@ -110777,8 +111507,8 @@ async function currentRemoteDigest(client2, slug2) {
110777
111507
  }
110778
111508
  if (!body || typeof body !== "object")
110779
111509
  return;
110780
- const digest3 = body.bundleSha256;
110781
- return typeof digest3 === "string" && digest3 ? digest3 : undefined;
111510
+ const digest4 = body.bundleSha256;
111511
+ return typeof digest4 === "string" && digest4 ? digest4 : undefined;
110782
111512
  }
110783
111513
  async function reconcileRegistry(options = {}) {
110784
111514
  const conflict = options.conflict ?? "skip";