@hasna/skills 0.10.77 → 0.10.79

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
@@ -36888,7 +36888,7 @@ var package_default;
36888
36888
  var init_package = __esm(() => {
36889
36889
  package_default = {
36890
36890
  name: "@hasna/skills",
36891
- version: "0.10.77",
36891
+ version: "0.10.79",
36892
36892
  description: "Skills library for AI coding agents",
36893
36893
  type: "module",
36894
36894
  bin: {
@@ -40398,7 +40398,8 @@ var init_codex_native_compatibility = __esm(() => {
40398
40398
  "codex-cli 0.160.1": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
40399
40399
  "codex-cli 0.161.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
40400
40400
  "codex-cli 0.162.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
40401
- "codex-cli 0.162.1": ["hooks", "qualified-skill-catalog", "installed-plugin-review"]
40401
+ "codex-cli 0.162.1": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
40402
+ "codex-cli 0.163.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"]
40402
40403
  };
40403
40404
  SUPPORTED_CODEX_HOOK_VERSIONS = Object.freeze(Object.keys(MEASURED_CODEX_CAPABILITIES).filter((version) => supportsCodexNativeCapability(version, "hooks")));
40404
40405
  });
@@ -66746,6 +66747,24 @@ var init_remote_workspace_selection = __esm(() => {
66746
66747
 
66747
66748
  // src/lib/remote-private-publications.ts
66748
66749
  import { createHash as createHash30 } from "crypto";
66750
+ function checkedPrivateSkillCreate(value) {
66751
+ const refuse6 = (field3, accepted) => {
66752
+ throw new PrivatePublicationError("INVALID_SKILL_CREATE_INPUT", `Invalid ${field3}. ${accepted}`);
66753
+ };
66754
+ if (!record7(value) || !Object.keys(value).every((key2) => ["slug", "displayName", "description", "visibility", "confirm"].includes(key2)))
66755
+ return refuse6("create input", "Provide only slug, displayName, description, visibility and confirm.");
66756
+ if (value.confirm !== true)
66757
+ throw new PrivatePublicationError("SKILL_CREATE_CONFIRM_REQUIRED", "Explicit confirmation is required to create this skill.");
66758
+ if (typeof value.slug !== "string" || value.slug.length > 128 || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(value.slug))
66759
+ return refuse6("slug", "Use lowercase kebab-case, at most 128 characters.");
66760
+ if (typeof value.displayName !== "string" || !value.displayName.trim() || value.displayName.length > 256 || /[\p{Cc}\p{Cs}\u2028\u2029]/u.test(value.displayName))
66761
+ return refuse6("displayName", "Use nonempty text, at most 256 characters, without control characters.");
66762
+ if (value.description !== undefined && (typeof value.description !== "string" || Buffer.byteLength(value.description) > 8192 || /[\p{Cc}\p{Cs}]/u.test(value.description.replace(/[\r\n\t]/g, ""))))
66763
+ return refuse6("description", "Use text of at most 8192 UTF-8 bytes, without control characters other than tabs and newlines.");
66764
+ if (value.visibility !== undefined && value.visibility !== "private" && value.visibility !== "team")
66765
+ return refuse6("visibility", "Use private or team.");
66766
+ return Object.freeze({ slug: value.slug, displayName: value.displayName.trim(), description: value.description ?? "", visibility: value.visibility ?? "private" });
66767
+ }
66749
66768
  function checkedPublicationDeclaration(value) {
66750
66769
  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 || !hash4(value.archiveSha256) || !Number.isSafeInteger(value.archiveByteSize) || Number(value.archiveByteSize) < 1 || Number(value.archiveByteSize) > PRIVATE_PUBLICATION_MAX_BYTES)
66751
66770
  return bad();
@@ -66765,11 +66784,11 @@ function checkedPublicationView(value, skillId, intentId, declaration) {
66765
66784
  return invalid3();
66766
66785
  return Object.freeze({ ...value });
66767
66786
  }
66768
- async function boundedJson(url, init, token, mutation, budget2 = 15000, signal) {
66787
+ async function boundedJson(url, init, token, mutation, budget2 = 15000, signal, create3 = false) {
66769
66788
  const controller = new AbortController;
66770
66789
  let reader;
66771
66790
  let response;
66772
- const timeout = new PrivatePublicationError("PUBLICATION_UNCONFIRMED", "No confirmed publication result. Inspect the saved intent before retrying.", mutation);
66791
+ const timeout = new PrivatePublicationError(create3 ? "SKILL_CREATE_UNCONFIRMED" : "PUBLICATION_UNCONFIRMED", create3 ? "Skill creation could not be confirmed. Inspect the workspace for this slug before another create; do not retry automatically." : "No confirmed publication result. Inspect the saved intent before retrying.", mutation);
66773
66792
  let timer;
66774
66793
  let abort;
66775
66794
  try {
@@ -66809,11 +66828,19 @@ async function boundedJson(url, init, token, mutation, budget2 = 15000, signal)
66809
66828
  return invalid3();
66810
66829
  }
66811
66830
  if (!response.ok) {
66812
- const code = record7(body) && typeof body.code === "string" && Object.hasOwn(failures, body.code) ? body.code : null;
66813
- if (code && failures[code][0] === response.status)
66814
- throw new PrivatePublicationError(code, failures[code][1], mutation && code === "PUBLICATION_UNCERTAIN", response.status);
66831
+ const known = create3 ? skillCreateFailures : failures;
66832
+ const code = record7(body) && typeof body.code === "string" && Object.hasOwn(known, body.code) ? body.code : null;
66833
+ if (code && known[code][0] === response.status)
66834
+ throw new PrivatePublicationError(code, known[code][1], mutation && code === "PUBLICATION_UNCERTAIN", response.status);
66835
+ if (create3) {
66836
+ if (response.status >= 500)
66837
+ throw timeout;
66838
+ throw new PrivatePublicationError("SKILL_CREATE_REQUEST_FAILED", "The server refused skill creation.", false, response.status);
66839
+ }
66815
66840
  throw new PrivatePublicationError("PUBLICATION_REQUEST_FAILED", "The publication request was refused. Inspect its status before retrying.", mutation && response.status >= 500, response.status);
66816
66841
  }
66842
+ if (create3 && response.status !== 201)
66843
+ return invalid3();
66817
66844
  return body;
66818
66845
  })(), new Promise((_, reject2) => {
66819
66846
  abort = () => {
@@ -66860,6 +66887,15 @@ class RemotePrivatePublicationsClient {
66860
66887
  this.membershipId = checked.user.membershipId;
66861
66888
  Object.freeze(this);
66862
66889
  }
66890
+ async createSkill(input, options = {}) {
66891
+ const body = checkedPrivateSkillCreate(input);
66892
+ if (options.timeoutMs !== undefined && (!Number.isSafeInteger(options.timeoutMs) || options.timeoutMs < 1 || options.timeoutMs > 15000))
66893
+ throw new PrivatePublicationError("INVALID_SKILL_CREATE_INPUT", "Invalid timeoutMs. Use an integer from 1 to 15000.");
66894
+ const value = await boundedJson(skillsApiRequestUrl(this.apiOrigin, "/api/v1/skills"), { method: "POST", body: JSON.stringify(body) }, this.#token, true, options.timeoutMs, options.signal, true);
66895
+ if (!record7(value) || !publicationUuid(value.id) || value.slug !== body.slug || value.displayName !== body.displayName || value.description !== body.description || value.visibility !== body.visibility || value.sourceType !== "private_hosted" || !record7(value.metadata) || value.metadata.ownerOrganizationId !== this.organizationId)
66896
+ throw new PrivatePublicationError("SKILL_CREATE_UNCONFIRMED", "Skill creation returned an unbound result. Inspect the workspace for this slug before another create; do not retry automatically.", true);
66897
+ return Object.freeze({ id: value.id, slug: body.slug, visibility: body.visibility, sourceType: "private_hosted", ownerOrganizationId: this.organizationId });
66898
+ }
66863
66899
  async getCapability(options = {}) {
66864
66900
  if (options.timeoutMs !== undefined && (!Number.isSafeInteger(options.timeoutMs) || options.timeoutMs < 1 || options.timeoutMs > 15000))
66865
66901
  return bad();
@@ -67002,7 +67038,7 @@ class RemotePrivatePublicationsClient {
67002
67038
  }
67003
67039
  }
67004
67040
  }
67005
- var PRIVATE_PUBLICATION_MAX_BYTES, failures, PrivatePublicationError, bad = () => {
67041
+ var PRIVATE_PUBLICATION_MAX_BYTES, skillCreateFailures, failures, PrivatePublicationError, bad = () => {
67006
67042
  throw new PrivatePublicationError("INVALID_PUBLICATION_INPUT", "Invalid publication input or recovery data.");
67007
67043
  }, invalid3 = () => {
67008
67044
  throw new PrivatePublicationError("INVALID_PUBLICATION_RESPONSE", "The server returned an invalid publication result.");
@@ -67012,6 +67048,16 @@ var init_remote_private_publications = __esm(() => {
67012
67048
  init_remote_workspace_selection();
67013
67049
  init_skill_contract();
67014
67050
  PRIVATE_PUBLICATION_MAX_BYTES = 16 * 1024 * 1024;
67051
+ skillCreateFailures = {
67052
+ INVALID_SLUG: [400, "Provide a lowercase kebab-case skill slug."],
67053
+ INVALID_DISPLAY_NAME: [400, "Provide a nonempty skill display name."],
67054
+ INVALID_VISIBILITY: [400, "Use private or team visibility for source publication."],
67055
+ SESSION_EXPIRED: [401, "Sign in again before creating a private skill."],
67056
+ INTERACTIVE_SESSION_REQUIRED: [403, "An interactive account session is required to create a private skill."],
67057
+ ACCOUNT_UNAVAILABLE: [403, "The current account membership cannot create a private skill."],
67058
+ PLAN_REQUIRED: [403, "Private and team skills require the Pro plan."],
67059
+ SLUG_CONFLICT: [409, "This skill slug already exists. Inspect the existing skill before publishing."]
67060
+ };
67015
67061
  failures = {
67016
67062
  INVALID_REQUEST: [400, "The publication request is invalid."],
67017
67063
  SESSION_EXPIRED: [401, "Sign in again to manage this publication."],
@@ -88997,6 +89043,7 @@ function normalizeRemoteSkill(skill) {
88997
89043
  if (!name)
88998
89044
  throw new Error("Remote skill requires name or slug");
88999
89045
  return {
89046
+ ...skill.id !== undefined ? { id: skill.id } : {},
89000
89047
  name,
89001
89048
  displayName: skill.displayName || titleize(name),
89002
89049
  description: skill.description || "",
@@ -89115,11 +89162,12 @@ var init_remote_registry = __esm(() => {
89115
89162
  details: exports_external.array(exports_external.string()).optional()
89116
89163
  }).passthrough();
89117
89164
  remoteSkillSchema = exports_external.object({
89165
+ id: exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/).optional(),
89118
89166
  name: exports_external.string().min(1).optional(),
89119
89167
  slug: exports_external.string().min(1).optional(),
89120
89168
  displayName: exports_external.string().optional(),
89121
89169
  description: exports_external.string().optional(),
89122
- category: exports_external.string().optional(),
89170
+ category: exports_external.string().nullable().optional(),
89123
89171
  tags: exports_external.array(exports_external.string()).optional(),
89124
89172
  dependencies: exports_external.array(exports_external.string()).optional(),
89125
89173
  version: exports_external.string().optional(),
@@ -99568,6 +99616,43 @@ var init_run_state = __esm(() => {
99568
99616
  init_project_state();
99569
99617
  });
99570
99618
 
99619
+ // src/lib/mcp-registration-environment.ts
99620
+ import { isAbsolute as isAbsolute33 } from "path";
99621
+ function skillsMcpRegistrationEnvironment(env3 = process.env, origin) {
99622
+ const result2 = {};
99623
+ const profile = selectedSkillsProfile(env3);
99624
+ if (profile)
99625
+ result2[CREDENTIAL_PROFILE_ENV_KEY] = profile;
99626
+ for (const key2 of ["HASNA_HOME", "HASNA_CONFIG_HOME"]) {
99627
+ const value = env3[key2];
99628
+ if (value === undefined)
99629
+ continue;
99630
+ if (!isAbsolute33(value) || /[\x00-\x1f\x7f]/.test(value))
99631
+ throw new Error(`Invalid ${key2}; expected an absolute configuration path`);
99632
+ result2[key2] = value;
99633
+ }
99634
+ if (origin !== undefined || urlKeys2.some((key2) => env3[key2] !== undefined)) {
99635
+ try {
99636
+ const source = origin === undefined ? env3 : { ...env3, ...Object.fromEntries(urlKeys2.map((key2) => [key2, origin])) };
99637
+ const configured = configuredSkillsApiUrl(source);
99638
+ if (!configured)
99639
+ throw new Error;
99640
+ for (const key2 of urlKeys2)
99641
+ result2[key2] = configured.value;
99642
+ } catch {
99643
+ throw new Error("Invalid Skills MCP API URL; expected matching HTTPS or loopback HTTP origins without credentials, query or fragment");
99644
+ }
99645
+ }
99646
+ return Object.freeze(result2);
99647
+ }
99648
+ var urlKeys2;
99649
+ var init_mcp_registration_environment = __esm(() => {
99650
+ init_transport();
99651
+ init_instance_credentials();
99652
+ init_fleet_credentials();
99653
+ urlKeys2 = clientTransportEnvKeys("skills").apiUrlKeys;
99654
+ });
99655
+
99571
99656
  // node_modules/@modelcontextprotocol/sdk/dist/esm/types.js
99572
99657
  function assertCompleteRequestPrompt(request2) {
99573
99658
  if (request2.params.ref.type !== "ref/prompt") {
@@ -111906,7 +111991,7 @@ var init_recurring_customer = __esm(() => {
111906
111991
 
111907
111992
  // src/lib/recurring-recovery.ts
111908
111993
  import { constants as constants26, closeSync as closeSync27, fsyncSync as fsyncSync8, fstatSync as fstatSync27, lstatSync as lstatSync37, mkdirSync as mkdirSync21, openSync as openSync27, readSync as readSync19, realpathSync as realpathSync17, renameSync as renameSync12, unlinkSync as unlinkSync8, writeFileSync as writeFileSync19 } from "fs";
111909
- import { dirname as dirname35, isAbsolute as isAbsolute33, join as join59, resolve as resolve34 } from "path";
111994
+ import { dirname as dirname35, isAbsolute as isAbsolute34, join as join59, resolve as resolve34 } from "path";
111910
111995
  import { randomUUID as randomUUID8 } from "crypto";
111911
111996
 
111912
111997
  class RecoveryOwner {
@@ -111914,7 +111999,7 @@ class RecoveryOwner {
111914
111999
  parents = [];
111915
112000
  constructor(directory2) {
111916
112001
  this.directory = directory2;
111917
- if (!isAbsolute33(directory2) || resolve34(directory2) !== directory2 || realpathSync17(directory2) !== directory2)
112002
+ if (!isAbsolute34(directory2) || resolve34(directory2) !== directory2 || realpathSync17(directory2) !== directory2)
111918
112003
  invalid6();
111919
112004
  for (let path = directory2;; path = dirname35(path)) {
111920
112005
  const stat3 = lstatSync37(path);
@@ -112049,7 +112134,7 @@ function base2(customer, organizationId) {
112049
112134
  };
112050
112135
  }
112051
112136
  function create3(directory2, intent) {
112052
- if (!isAbsolute33(directory2) || resolve34(directory2) !== directory2 || realpathSync17(dirname35(directory2)) !== dirname35(directory2))
112137
+ if (!isAbsolute34(directory2) || resolve34(directory2) !== directory2 || realpathSync17(dirname35(directory2)) !== dirname35(directory2))
112053
112138
  invalid6();
112054
112139
  mkdirSync21(directory2, { mode: 448 });
112055
112140
  const owner2 = new RecoveryOwner(directory2), checked = intentSchema.parse(intent), intentSha256 = canonicalJsonSha256(checked);
@@ -112212,7 +112297,7 @@ var init_recurring_recovery = __esm(() => {
112212
112297
  });
112213
112298
 
112214
112299
  // src/lib/recurring-surface.ts
112215
- import { isAbsolute as isAbsolute34 } from "path";
112300
+ import { isAbsolute as isAbsolute35 } from "path";
112216
112301
  function recurringMcpSchema(action) {
112217
112302
  return action === "activate" ? recurringSurfaceSchemas.activate.extend({ code, confirm: exports_external.literal(true) }) : recurringSurfaceSchemas[action];
112218
112303
  }
@@ -112317,7 +112402,7 @@ var init_recurring_surface = __esm(() => {
112317
112402
  uuid12 = exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/);
112318
112403
  context = { userId: uuid12.optional(), membershipId: uuid12.optional() };
112319
112404
  page2 = { limit: exports_external.number().int().min(1).max(100).optional(), cursor: exports_external.string().min(1).max(2048).optional() };
112320
- directory2 = exports_external.string().max(4096).refine(isAbsolute34, "Use an absolute recovery directory");
112405
+ directory2 = exports_external.string().max(4096).refine(isAbsolute35, "Use an absolute recovery directory");
112321
112406
  email4 = exports_external.string().trim().toLowerCase().email().max(254);
112322
112407
  code = exports_external.string().regex(/^\d{6}$/);
112323
112408
  recurringSurfaceSchemas = {
@@ -115103,15 +115188,42 @@ var init_remote_invitation_tools = __esm(() => {
115103
115188
  });
115104
115189
 
115105
115190
  // src/lib/private-publication-customer.ts
115191
+ function preparePrivatePublicationSession(requested) {
115192
+ const selectors = [
115193
+ "HASNA_PROFILE",
115194
+ "HASNA_HOME",
115195
+ "HASNA_CONFIG_HOME",
115196
+ "HASNA_STATION",
115197
+ "HASNA_SKILLS_API_URL",
115198
+ "SKILLS_API_URL",
115199
+ "HASNA_SKILLS_API_KEY_OVERRIDE",
115200
+ "HASNA_SKILLS_API_KEY_REF",
115201
+ "HASNA_SKILLS_API_KEY",
115202
+ "SKILLS_API_KEY"
115203
+ ];
115204
+ const before2 = new Map(selectors.map((key2) => [key2, process.env[key2]]));
115205
+ const profile = selectedSkillsProfile(process.env), pending = prepareProfileWorkspace("Manage private publications");
115206
+ const captured = requested ? { ...requested } : undefined;
115207
+ const unchanged3 = () => {
115208
+ if (selectors.some((key2) => process.env[key2] !== before2.get(key2)) || selectedSkillsProfile(process.env) !== profile)
115209
+ throw new PrivatePublicationError("PUBLICATION_TARGET_CHANGED", "The selected profile or server changed during verification. Start again with a stable target; no skill action was sent.");
115210
+ };
115211
+ return { origin: pending.origin, async verify(email5, code2) {
115212
+ unchanged3();
115213
+ const target = await pending.resolve();
115214
+ const context2 = captured ?? target.context;
115215
+ if (!context2 || !publicationUuid(context2.userId) || !publicationUuid(context2.membershipId) || target.context && (context2.userId !== target.context.userId || context2.membershipId !== target.context.membershipId))
115216
+ throw new PrivatePublicationError("PUBLICATION_CONTEXT_REQUIRED", "Provide the observed user and membership IDs, or select an enrolled workspace profile.");
115217
+ unchanged3();
115218
+ target.unchanged();
115219
+ const client2 = await new RemoteSkillsAuthClient(target.origin).openPrivatePublications(email5, code2, context2);
115220
+ unchanged3();
115221
+ target.unchanged();
115222
+ return client2;
115223
+ } };
115224
+ }
115106
115225
  async function privatePublicationSession(email5, code2, requested) {
115107
- const target = await captureProfileWorkspace("Manage private publications");
115108
- const context2 = requested ?? target.context;
115109
- if (!context2 || !publicationUuid(context2.userId) || !publicationUuid(context2.membershipId) || target.context && (context2.userId !== target.context.userId || context2.membershipId !== target.context.membershipId))
115110
- throw new PrivatePublicationError("PUBLICATION_CONTEXT_REQUIRED", "Provide the observed user and membership IDs, or select an enrolled workspace profile.");
115111
- target.unchanged();
115112
- const client2 = await new RemoteSkillsAuthClient(target.origin).openPrivatePublications(email5, code2, context2);
115113
- target.unchanged();
115114
- return client2;
115226
+ return preparePrivatePublicationSession(requested).verify(email5, code2);
115115
115227
  }
115116
115228
  function privatePublicationCustomerError(error61) {
115117
115229
  return error61 instanceof PrivatePublicationError ? { error: error61.message, code: error61.code, uncertain: error61.uncertain } : { error: "The publication action could not be confirmed. Preserve the recovery directory and inspect the same intent; credentials were not changed.", code: "PUBLICATION_ACTION_UNCONFIRMED", uncertain: true };
@@ -115120,14 +115232,15 @@ var init_private_publication_customer = __esm(() => {
115120
115232
  init_remote_auth();
115121
115233
  init_remote_private_publications();
115122
115234
  init_workspace_profile();
115235
+ init_instance_credentials();
115123
115236
  });
115124
115237
 
115125
115238
  // src/lib/private-publication-recovery.ts
115126
115239
  import { constants as constants27, closeSync as closeSync28, fsyncSync as fsyncSync9, fstatSync as fstatSync28, lstatSync as lstatSync38, mkdirSync as mkdirSync25, openSync as openSync28, readSync as readSync20, realpathSync as realpathSync18, renameSync as renameSync13, unlinkSync as unlinkSync9, writeFileSync as writeFileSync22 } from "fs";
115127
- import { dirname as dirname38, isAbsolute as isAbsolute35, join as join64, resolve as resolve35 } from "path";
115240
+ import { dirname as dirname38, isAbsolute as isAbsolute36, join as join64, resolve as resolve35 } from "path";
115128
115241
  import { randomUUID as randomUUID9 } from "crypto";
115129
115242
  function safeDirectory(directory3) {
115130
- if (!isAbsolute35(directory3) || directory3 !== resolve35(directory3) || realpathSync18(directory3) !== directory3)
115243
+ if (!isAbsolute36(directory3) || directory3 !== resolve35(directory3) || realpathSync18(directory3) !== directory3)
115131
115244
  return fail5();
115132
115245
  for (let path = directory3;; path = dirname38(path)) {
115133
115246
  const stat3 = lstatSync38(path);
@@ -115265,7 +115378,7 @@ async function preparePrivatePublication(client2, sourceDirectory, recoveryDirec
115265
115378
  phase: "prepared",
115266
115379
  intent: null
115267
115380
  };
115268
- if (!isAbsolute35(recoveryDirectory) || resolve35(recoveryDirectory) !== recoveryDirectory || realpathSync18(dirname38(recoveryDirectory)) !== dirname38(recoveryDirectory))
115381
+ if (!isAbsolute36(recoveryDirectory) || resolve35(recoveryDirectory) !== recoveryDirectory || realpathSync18(dirname38(recoveryDirectory)) !== dirname38(recoveryDirectory))
115269
115382
  return fail5();
115270
115383
  mkdirSync25(recoveryDirectory, { mode: 448 });
115271
115384
  safeDirectory(recoveryDirectory);
@@ -115366,10 +115479,10 @@ var init_private_publication_recovery = __esm(() => {
115366
115479
  });
115367
115480
 
115368
115481
  // src/mcp/private-publication-tools.ts
115369
- import { isAbsolute as isAbsolute36 } from "path";
115482
+ import { isAbsolute as isAbsolute37 } from "path";
115370
115483
  function registerPrivatePublicationTools(server) {
115371
115484
  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}$/);
115372
- const directory3 = exports_external.string().max(4096).refine(isAbsolute36, "Use an absolute local directory");
115485
+ const directory3 = exports_external.string().max(4096).refine(isAbsolute37, "Use an absolute local directory");
115373
115486
  const verification2 = { email: exports_external.string().email().max(254), code: exports_external.string().regex(/^\d{6}$/), userId: uuid9, membershipId: uuid9, recoveryDirectory: directory3 };
115374
115487
  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.";
115375
115488
  const handler = (action) => async (value) => {
@@ -115830,14 +115943,18 @@ var exports_runtime_mcp = {};
115830
115943
  __export(exports_runtime_mcp, {
115831
115944
  handleMcp: () => handleMcp
115832
115945
  });
115833
- import { existsSync as existsSync33, mkdirSync as mkdirSync26, readFileSync as readFileSync42, writeFileSync as writeFileSync23 } from "fs";
115946
+ import { existsSync as existsSync33, lstatSync as lstatSync39, mkdirSync as mkdirSync26, readFileSync as readFileSync42, renameSync as renameSync14, rmdirSync as rmdirSync4, statSync as statSync22, writeFileSync as writeFileSync23 } from "fs";
115947
+ import { randomUUID as randomUUID10 } from "crypto";
115834
115948
  import { homedir as homedir10 } from "os";
115835
- import { dirname as dirname39, join as join65 } from "path";
115949
+ import { dirname as dirname39, isAbsolute as isAbsolute38, join as join65 } from "path";
115950
+ import { isDeepStrictEqual as isDeepStrictEqual16, stripVTControlCharacters } from "util";
115836
115951
  async function handleMcp(options) {
115837
115952
  if (options.register) {
115838
115953
  let agents;
115954
+ let environment;
115839
115955
  try {
115840
115956
  agents = resolveAgents(options.register);
115957
+ environment = skillsMcpRegistrationEnvironment(process.env, options.apiUrl);
115841
115958
  } catch (err) {
115842
115959
  const error61 = err.message;
115843
115960
  if (options.json) {
@@ -115851,7 +115968,7 @@ async function handleMcp(options) {
115851
115968
  const command = findCommandOnPath(MCP_COMMAND_NAME);
115852
115969
  const results2 = [];
115853
115970
  for (const agent of agents) {
115854
- const result2 = await registerMcpForAgent(agent, command);
115971
+ const result2 = await registerMcpForAgent(agent, command, environment);
115855
115972
  results2.push(result2);
115856
115973
  if (!options.json) {
115857
115974
  const label = result2.path ? `${agent} (${result2.path})` : agent;
@@ -115868,96 +115985,193 @@ async function handleMcp(options) {
115868
115985
  const { startMcpStdio: startMcpStdio2 } = await Promise.resolve().then(() => (init_mcp2(), exports_mcp));
115869
115986
  await startMcpStdio2();
115870
115987
  }
115871
- async function registerMcpForAgent(agent, command) {
115988
+ async function registerMcpForAgent(agent, command, environment) {
115989
+ const server2 = { command, args: ["--stdio"], ...Object.keys(environment).length ? { env: environment } : {} };
115872
115990
  switch (agent) {
115873
115991
  case "claude":
115874
- return registerClaudeMcp(command);
115992
+ return registerClaudeMcp(command, server2, environment);
115875
115993
  case "codex":
115876
- return registerCodexMcp(command);
115994
+ return registerCodexMcp(command, environment);
115877
115995
  case "gemini":
115878
- return registerJsonMcpServer(agent, join65(homedir10(), ".gemini", "settings.json"), "mcpServers", {
115879
- command,
115880
- args: []
115881
- });
115996
+ return registerJsonMcpServer(agent, join65(homedir10(), ".gemini", "settings.json"), "mcpServers", server2);
115882
115997
  case "pi":
115883
- return registerJsonMcpServer(agent, join65(homedir10(), ".pi", "agent", "mcp.json"), "mcpServers", {
115884
- command,
115885
- args: []
115886
- });
115998
+ return registerJsonMcpServer(agent, join65(homedir10(), ".pi", "agent", "mcp.json"), "mcpServers", server2);
115887
115999
  case "opencode":
115888
- return registerOpenCodeMcp(command);
116000
+ return registerOpenCodeMcp(command, environment);
115889
116001
  case "cursor":
115890
- return registerJsonMcpServer(agent, join65(homedir10(), ".cursor", "mcp.json"), "mcpServers", {
115891
- command,
115892
- args: []
115893
- });
116002
+ return registerJsonMcpServer(agent, join65(homedir10(), ".cursor", "mcp.json"), "mcpServers", server2);
115894
116003
  case "windsurf":
115895
- return registerJsonMcpServer(agent, join65(homedir10(), ".windsurf", "mcp.json"), "mcpServers", {
115896
- command,
115897
- args: []
115898
- });
116004
+ return registerJsonMcpServer(agent, join65(homedir10(), ".windsurf", "mcp.json"), "mcpServers", server2);
115899
116005
  default:
115900
116006
  return { agent, success: false, error: `Unknown agent: ${agent}. Available: ${AGENT_TARGETS.join(", ")}, all` };
115901
116007
  }
115902
116008
  }
115903
- async function registerClaudeMcp(command) {
115904
- const cliCommand = `claude mcp add -s user ${MCP_SERVER_NAME} -- ${command}`;
116009
+ async function registerClaudeMcp(command, server2, environment) {
116010
+ const args2 = ["claude", "mcp", "add", "-s", "user", ...Object.entries(environment).flatMap(([key2, value]) => ["--env", `${key2}=${value}`]), "--transport", "stdio", MCP_SERVER_NAME, "--", command, "--stdio"];
116011
+ const cliCommand = args2.map(skillsShellArgument).join(" ");
116012
+ const desired = { type: "stdio", ...server2, env: environment };
115905
116013
  try {
115906
- const proc = Bun.spawn(["claude", "mcp", "add", "-s", "user", MCP_SERVER_NAME, "--", command], {
115907
- stdout: "pipe",
115908
- stderr: "pipe"
116014
+ const path = claudeUserConfigPath();
116015
+ const before2 = withClaudeConfigLock(path, () => {
116016
+ if (claudeUserConfigPath() !== path)
116017
+ throw new Error;
116018
+ const bytes = readClaudeConfig(path);
116019
+ if (bytes !== null) {
116020
+ const backup = `${path}.skills-mcp-${randomUUID10()}.backup`;
116021
+ writeFileSync23(backup, bytes, { flag: "wx", mode: 384 });
116022
+ if (!readFileSync42(backup).equals(bytes))
116023
+ throw new Error;
116024
+ }
116025
+ return bytes;
115909
116026
  });
115910
- const [stdout, stderr, exitCode] = await Promise.all([
115911
- new Response(proc.stdout).text(),
115912
- new Response(proc.stderr).text(),
115913
- proc.exited
115914
- ]);
115915
- if (exitCode === 0) {
115916
- return { agent: "claude", success: true, command: cliCommand };
116027
+ let exitCode, duplicateAccepted = false, cliUnavailable = false;
116028
+ const proc = (() => {
116029
+ try {
116030
+ return Bun.spawn(args2, { stdout: "pipe", stderr: "pipe" });
116031
+ } catch (error61) {
116032
+ if (!isPlainObject4(error61) || error61.code !== "ENOENT")
116033
+ throw new Error;
116034
+ cliUnavailable = true;
116035
+ return;
116036
+ }
116037
+ })();
116038
+ if (proc) {
116039
+ const [stdout, stderr, status] = await Promise.all([
116040
+ new Response(proc.stdout).text(),
116041
+ new Response(proc.stderr).text(),
116042
+ proc.exited
116043
+ ]);
116044
+ exitCode = status;
116045
+ const diagnostic = stripVTControlCharacters(stderr).trim();
116046
+ duplicateAccepted = exitCode === 1 && stdout.trim() === "" && (diagnostic === `MCP server ${MCP_SERVER_NAME} already exists in user config` || diagnostic === `Error: MCP server ${MCP_SERVER_NAME} already exists in user config`);
116047
+ if (exitCode !== 0 && !duplicateAccepted)
116048
+ throw new Error;
115917
116049
  }
115918
- const fallback = registerJsonMcpServer("claude", join65(homedir10(), ".claude", ".mcp.json"), "mcpServers", {
115919
- command,
115920
- args: []
115921
- });
115922
- return {
115923
- ...fallback,
115924
- command: cliCommand,
115925
- error: fallback.success ? undefined : `claude exited with ${exitCode}: ${(stderr || stdout).trim()}`
115926
- };
115927
- } catch (err) {
115928
- const fallback = registerJsonMcpServer("claude", join65(homedir10(), ".claude", ".mcp.json"), "mcpServers", {
115929
- command,
115930
- args: []
116050
+ return withClaudeConfigLock(path, () => {
116051
+ if (claudeUserConfigPath() !== path)
116052
+ throw new Error;
116053
+ const current = readClaudeConfig(path);
116054
+ const previous = parseClaudeConfig(before2), data = parseClaudeConfig(current);
116055
+ if (exitCode === 0) {
116056
+ const actual = isPlainObject4(data.mcpServers) ? data.mcpServers[MCP_SERVER_NAME] : undefined;
116057
+ if (!isDeepStrictEqual16(withoutClaudeSkills(previous), withoutClaudeSkills(data)) || !isPlainObject4(actual) || !isDeepStrictEqual16({ ...actual, env: actual.env ?? {} }, desired))
116058
+ throw new Error;
116059
+ } else {
116060
+ if (!cliUnavailable && (!duplicateAccepted || !isPlainObject4(previous.mcpServers) || !previous.mcpServers[MCP_SERVER_NAME]))
116061
+ throw new Error;
116062
+ if (before2 === null ? current !== null : current === null || !current.equals(before2))
116063
+ throw new Error;
116064
+ data.mcpServers = { ...data.mcpServers, [MCP_SERVER_NAME]: desired };
116065
+ const next = Buffer.from(`${JSON.stringify(data, null, 2)}
116066
+ `);
116067
+ const temporary = `${path}.skills-mcp-${randomUUID10()}.tmp`;
116068
+ writeFileSync23(temporary, next, { flag: "wx", mode: 384 });
116069
+ if (!readFileSync42(temporary).equals(next))
116070
+ throw new Error;
116071
+ const latest = readClaudeConfig(path);
116072
+ if (claudeUserConfigPath() !== path || (before2 === null ? latest !== null : latest === null || !latest.equals(before2)))
116073
+ throw new Error;
116074
+ renameSync14(temporary, path);
116075
+ if (!readFileSync42(path).equals(next))
116076
+ throw new Error;
116077
+ }
116078
+ return { agent: "claude", success: true, path, command: cliCommand };
115931
116079
  });
116080
+ } catch {
115932
116081
  return {
115933
- ...fallback,
116082
+ agent: "claude",
116083
+ success: false,
115934
116084
  command: cliCommand,
115935
- error: fallback.success ? undefined : err.message
116085
+ error: "Could not safely update the Claude user MCP configuration; native admission or config checks refused the update"
115936
116086
  };
115937
116087
  }
115938
116088
  }
115939
- function registerCodexMcp(command) {
116089
+ function claudeUserConfigPath() {
116090
+ const override = process.env.CLAUDE_CONFIG_DIR;
116091
+ if (override !== undefined && (!override || !isAbsolute38(override) || /[\x00-\x1f\x7f]/.test(override)))
116092
+ throw new Error;
116093
+ const modern = join65(override || homedir10(), process.env.CLAUDE_CODE_CUSTOM_OAUTH_URL ? ".claude-custom-oauth.json" : ".claude.json");
116094
+ const legacy = join65(override ?? join65(homedir10(), ".claude"), ".config.json");
116095
+ if (existsSync33(legacy)) {
116096
+ const info = lstatSync39(legacy);
116097
+ if (!info.isFile())
116098
+ throw new Error;
116099
+ if (info.size > 0 || (info.mode & 146) !== 0 && !existsSync33(modern))
116100
+ return legacy;
116101
+ }
116102
+ return modern;
116103
+ }
116104
+ function readClaudeConfig(path) {
116105
+ if (!existsSync33(path))
116106
+ return null;
116107
+ const info = lstatSync39(path);
116108
+ if (!info.isFile() || info.size > 16777216)
116109
+ throw new Error;
116110
+ const bytes = readFileSync42(path);
116111
+ parseClaudeConfig(bytes);
116112
+ return bytes;
116113
+ }
116114
+ function parseClaudeConfig(bytes) {
116115
+ const data = bytes === null ? {} : JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
116116
+ if (!isPlainObject4(data) || data.mcpServers !== undefined && !isPlainObject4(data.mcpServers))
116117
+ throw new Error;
116118
+ return data;
116119
+ }
116120
+ function withoutClaudeSkills(data) {
116121
+ const rest2 = { ...data }, servers = { ...data.mcpServers };
116122
+ delete servers[MCP_SERVER_NAME];
116123
+ if (Object.keys(servers).length)
116124
+ rest2.mcpServers = servers;
116125
+ else
116126
+ delete rest2.mcpServers;
116127
+ return rest2;
116128
+ }
116129
+ function withClaudeConfigLock(path, action) {
116130
+ mkdirSync26(dirname39(path), { recursive: true });
116131
+ const lock = `${path}.lock`;
116132
+ mkdirSync26(lock, { mode: 448 });
116133
+ const owned = statSync22(lock);
116134
+ try {
116135
+ return action();
116136
+ } finally {
116137
+ const current = lstatSync39(lock);
116138
+ if (current.isDirectory() && current.dev === owned.dev && current.ino === owned.ino) {
116139
+ rmdirSync4(lock);
116140
+ }
116141
+ }
116142
+ }
116143
+ function registerCodexMcp(command, environment) {
115940
116144
  const path = join65(homedir10(), ".codex", "config.toml");
116145
+ const body = `command = ${JSON.stringify(command)}
116146
+ args = ["--stdio"]${Object.keys(environment).length ? `
116147
+ env = { ${Object.entries(environment).map(([key2, value]) => `${JSON.stringify(key2)} = ${JSON.stringify(value)}`).join(", ")} }` : ""}`;
115941
116148
  const config2 = `[mcp_servers.${MCP_SERVER_NAME}]
115942
- command = ${JSON.stringify(command)}`;
116149
+ ${body}`;
115943
116150
  try {
115944
116151
  const current = existsSync33(path) ? readFileSync42(path, "utf-8") : "";
115945
- writeTextFile(path, upsertTomlSection(current, `[mcp_servers.${MCP_SERVER_NAME}]`, `command = ${JSON.stringify(command)}`));
116152
+ const before2 = Bun.TOML.parse(current);
116153
+ const next = upsertTomlSection(current, `[mcp_servers.${MCP_SERVER_NAME}]`, body);
116154
+ const after2 = Bun.TOML.parse(next);
116155
+ if (!isDeepStrictEqual16(withoutSkillsMcp(before2), withoutSkillsMcp(after2)))
116156
+ throw new Error;
116157
+ writeTextFile(path, next);
115946
116158
  return { agent: "codex", success: true, path, config: config2 };
115947
116159
  } catch (err) {
115948
- return { agent: "codex", success: false, path, config: config2, error: err.message };
116160
+ return { agent: "codex", success: false, path, config: config2, error: "Could not update the Codex MCP configuration" };
115949
116161
  }
115950
116162
  }
115951
- function registerOpenCodeMcp(command) {
116163
+ function registerOpenCodeMcp(command, environment) {
115952
116164
  const path = join65(homedir10(), ".config", "opencode", "opencode.json");
116165
+ const server2 = {
116166
+ type: "local",
116167
+ command: [command, "--stdio"],
116168
+ enabled: true,
116169
+ ...Object.keys(environment).length ? { environment } : {}
116170
+ };
115953
116171
  const config2 = JSON.stringify({
115954
116172
  $schema: "https://opencode.ai/config.json",
115955
116173
  mcp: {
115956
- [MCP_SERVER_NAME]: {
115957
- type: "local",
115958
- command: [command],
115959
- enabled: true
115960
- }
116174
+ [MCP_SERVER_NAME]: server2
115961
116175
  }
115962
116176
  }, null, 2);
115963
116177
  try {
@@ -115965,16 +116179,12 @@ function registerOpenCodeMcp(command) {
115965
116179
  if (!data.$schema)
115966
116180
  data.$schema = "https://opencode.ai/config.json";
115967
116181
  const mcp = isPlainObject4(data.mcp) ? data.mcp : {};
115968
- mcp[MCP_SERVER_NAME] = {
115969
- type: "local",
115970
- command: [command],
115971
- enabled: true
115972
- };
116182
+ mcp[MCP_SERVER_NAME] = server2;
115973
116183
  data.mcp = mcp;
115974
116184
  writeJsonObject(path, data);
115975
116185
  return { agent: "opencode", success: true, path, config: config2 };
115976
116186
  } catch (err) {
115977
- return { agent: "opencode", success: false, path, config: config2, error: err.message };
116187
+ return { agent: "opencode", success: false, path, config: config2, error: "Could not update the OpenCode MCP configuration" };
115978
116188
  }
115979
116189
  }
115980
116190
  function registerJsonMcpServer(agent, path, containerKey, server2) {
@@ -115987,7 +116197,7 @@ function registerJsonMcpServer(agent, path, containerKey, server2) {
115987
116197
  writeJsonObject(path, data);
115988
116198
  return { agent, success: true, path, config: config2 };
115989
116199
  } catch (err) {
115990
- return { agent, success: false, path, config: config2, error: err.message };
116200
+ return { agent, success: false, path, config: config2, error: "Could not update the agent MCP configuration" };
115991
116201
  }
115992
116202
  }
115993
116203
  function readJsonObject2(path) {
@@ -116014,24 +116224,37 @@ function writeTextFile(path, content) {
116014
116224
  function upsertTomlSection(content, header, body) {
116015
116225
  const sectionLines = [header, ...body.trim().split(/\r?\n/)];
116016
116226
  const lines = content.trimEnd() ? content.trimEnd().split(/\r?\n/) : [];
116017
- const start = lines.findIndex((line) => line.trim() === header);
116018
- if (start === -1) {
116019
- const prefix = lines.length ? [...lines, ""] : [];
116020
- return [...prefix, ...sectionLines, ""].join(`
116021
- `);
116022
- }
116023
- let end = lines.length;
116024
- for (let i = start + 1;i < lines.length; i++) {
116025
- if (/^\s*\[[^\]]+\]\s*$/.test(lines[i])) {
116026
- end = i;
116027
- break;
116227
+ const result2 = [];
116228
+ let owned = false, inserted = false;
116229
+ for (const line of lines) {
116230
+ if (/^\s*\[/.test(line)) {
116231
+ owned = /^\s*\[\s*(?:mcp_servers|"mcp_servers"|'mcp_servers')\s*\.\s*(?:skills|"skills"|'skills')\s*(?:\.|\])/.test(line);
116232
+ if (owned && !inserted) {
116233
+ result2.push(...sectionLines, "");
116234
+ inserted = true;
116235
+ }
116028
116236
  }
116237
+ if (!owned)
116238
+ result2.push(line);
116029
116239
  }
116030
- lines.splice(start, end - start, ...sectionLines);
116031
- return `${lines.join(`
116240
+ if (!inserted)
116241
+ result2.push(...result2.length ? [""] : [], ...sectionLines);
116242
+ return `${result2.join(`
116032
116243
  `)}
116033
116244
  `;
116034
116245
  }
116246
+ function withoutSkillsMcp(config2) {
116247
+ const preserved = { ...config2 };
116248
+ if (isPlainObject4(preserved.mcp_servers)) {
116249
+ const servers = { ...preserved.mcp_servers };
116250
+ delete servers[MCP_SERVER_NAME];
116251
+ if (Object.keys(servers).length)
116252
+ preserved.mcp_servers = servers;
116253
+ else
116254
+ delete preserved.mcp_servers;
116255
+ }
116256
+ return preserved;
116257
+ }
116035
116258
  function findCommandOnPath(command) {
116036
116259
  const pathValue = process.env.PATH || "";
116037
116260
  for (const dir of pathValue.split(":")) {
@@ -116050,6 +116273,8 @@ var MCP_SERVER_NAME = "skills", MCP_COMMAND_NAME = "skills-mcp";
116050
116273
  var init_runtime_mcp = __esm(() => {
116051
116274
  init_source();
116052
116275
  init_installer();
116276
+ init_credential_profile_command();
116277
+ init_mcp_registration_environment();
116053
116278
  });
116054
116279
 
116055
116280
  // src/cli/commands/remote-account.ts
@@ -116243,7 +116468,7 @@ var init_reviewed_runtime_lock = __esm(() => {
116243
116468
  });
116244
116469
 
116245
116470
  // src/cli/commands/runtime-copyfile.ts
116246
- import { createHash as createHash40, randomUUID as randomUUID10 } from "crypto";
116471
+ import { createHash as createHash40, randomUUID as randomUUID11 } from "crypto";
116247
116472
  import { Readable } from "stream";
116248
116473
  import { createGunzip as createGunzip2 } from "zlib";
116249
116474
  import { spawnSync as spawnSync6 } from "child_process";
@@ -116251,16 +116476,16 @@ import {
116251
116476
  chmodSync as chmodSync4,
116252
116477
  copyFileSync,
116253
116478
  existsSync as existsSync34,
116254
- lstatSync as lstatSync39,
116479
+ lstatSync as lstatSync40,
116255
116480
  mkdirSync as mkdirSync27,
116256
116481
  readFileSync as readFileSync43,
116257
116482
  readdirSync as readdirSync24,
116258
116483
  readlinkSync as readlinkSync8,
116259
116484
  realpathSync as realpathSync19,
116260
- renameSync as renameSync14,
116485
+ renameSync as renameSync15,
116261
116486
  writeFileSync as writeFileSync24
116262
116487
  } from "fs";
116263
- import { basename as basename21, delimiter as delimiter3, dirname as dirname40, isAbsolute as isAbsolute37, join as join66, relative as relative13, resolve as resolve36, sep as sep18 } from "path";
116488
+ import { basename as basename21, delimiter as delimiter3, dirname as dirname40, isAbsolute as isAbsolute39, join as join66, relative as relative13, resolve as resolve36, sep as sep18 } from "path";
116264
116489
  function oldLauncherState(item) {
116265
116490
  if (item.oldShape === "pinned")
116266
116491
  return { shape: "pinned", runtime: item.oldRuntime, cwd: item.oldCwd, target: item.oldTarget, sha256: item.oldSha256, format: item.oldFormat, profile: item.oldProfile };
@@ -116286,7 +116511,7 @@ function assertLauncherRecordShapes(item, expectedProfile) {
116286
116511
  throw new Error("RECEIPT_LAUNCHER_SHAPE_INVALID");
116287
116512
  continue;
116288
116513
  }
116289
- if (shape !== "pinned" || typeof runtime !== "string" || !isAbsolute37(runtime) || typeof cwd2 !== "string" || !isAbsolute37(cwd2) || typeof sha7 !== "string" || !hex4.test(sha7)) {
116514
+ if (shape !== "pinned" || typeof runtime !== "string" || !isAbsolute39(runtime) || typeof cwd2 !== "string" || !isAbsolute39(cwd2) || typeof sha7 !== "string" || !hex4.test(sha7)) {
116290
116515
  throw new Error("RECEIPT_LAUNCHER_SHAPE_INVALID");
116291
116516
  }
116292
116517
  const target = side === "old" ? item.oldTarget : item.newTarget;
@@ -116314,7 +116539,7 @@ function verifyTargetPrerequisites(manifest, packageRoot, home, cwd2, pathValue)
116314
116539
  throw new Error("RUNTIME_PREREQUISITE_CONTRACT_INVALID");
116315
116540
  }
116316
116541
  const entry = join66(packageRoot, contract.entry);
116317
- if (!entryExists(entry) || !lstatSync39(entry).isFile() || lstatSync39(entry).isSymbolicLink())
116542
+ if (!entryExists(entry) || !lstatSync40(entry).isFile() || lstatSync40(entry).isSymbolicLink())
116318
116543
  throw new Error("RUNTIME_PREREQUISITE_ENTRY_MISSING");
116319
116544
  const entrySha256 = hash6(readFileSync43(entry));
116320
116545
  const env3 = { HOME: home, PATH: pathValue, BUN_RUNTIME_TRANSPILER_CACHE_PATH: "0" };
@@ -116373,11 +116598,11 @@ function hash6(bytes) {
116373
116598
  }
116374
116599
  function isWithin(parent, child2) {
116375
116600
  const rel = relative13(parent, child2);
116376
- return rel === "" || !rel.startsWith(`..${sep18}`) && rel !== ".." && !isAbsolute37(rel);
116601
+ return rel === "" || !rel.startsWith(`..${sep18}`) && rel !== ".." && !isAbsolute39(rel);
116377
116602
  }
116378
116603
  function entryExists(path) {
116379
116604
  try {
116380
- lstatSync39(path);
116605
+ lstatSync40(path);
116381
116606
  return true;
116382
116607
  } catch {
116383
116608
  return false;
@@ -116389,7 +116614,7 @@ function assertNoSymlinkAncestors(path) {
116389
116614
  let current = sep18;
116390
116615
  for (const part of parts) {
116391
116616
  current = join66(current, part);
116392
- const stat3 = lstatSync39(current);
116617
+ const stat3 = lstatSync40(current);
116393
116618
  if (stat3.isSymbolicLink())
116394
116619
  throw new Error("PATH_ANCESTOR_SYMLINK_UNSUPPORTED");
116395
116620
  if (!stat3.isDirectory())
@@ -116404,17 +116629,17 @@ function acquireRuntimeLock(runtimeRoot) {
116404
116629
  throw new Error("RUNTIME_UPDATE_LOCKED");
116405
116630
  }
116406
116631
  try {
116407
- writeJsonPrivate(join66(lockPath, "lock.json"), { operationId: randomUUID10(), pid: process.pid, startedAt: new Date().toISOString() });
116632
+ writeJsonPrivate(join66(lockPath, "lock.json"), { operationId: randomUUID11(), pid: process.pid, startedAt: new Date().toISOString() });
116408
116633
  } catch {
116409
116634
  try {
116410
- renameSync14(lockPath, join66(runtimeRoot, `.copyfile-update-lock-incomplete-${randomUUID10()}`));
116635
+ renameSync15(lockPath, join66(runtimeRoot, `.copyfile-update-lock-incomplete-${randomUUID11()}`));
116411
116636
  } catch {}
116412
116637
  throw new Error("RUNTIME_LOCK_INITIALIZATION_FAILED");
116413
116638
  }
116414
116639
  return () => {
116415
- const released = join66(runtimeRoot, `.copyfile-update-lock-released-${randomUUID10()}`);
116640
+ const released = join66(runtimeRoot, `.copyfile-update-lock-released-${randomUUID11()}`);
116416
116641
  writeJsonPrivate(join66(lockPath, "released.json"), { completedAt: new Date().toISOString() });
116417
- renameSync14(lockPath, released);
116642
+ renameSync15(lockPath, released);
116418
116643
  };
116419
116644
  }
116420
116645
  function packageBins(pkg) {
@@ -116422,7 +116647,7 @@ function packageBins(pkg) {
116422
116647
  const entries = typeof raw === "string" ? [[PACKAGE_NAME.slice(PACKAGE_NAME.lastIndexOf("/") + 1), raw]] : raw && typeof raw === "object" && !Array.isArray(raw) ? Object.entries(raw) : [];
116423
116648
  const output2 = {};
116424
116649
  for (const [name, value] of entries) {
116425
- if (!/^[a-zA-Z0-9._-]+$/.test(name) || typeof value !== "string" || !value || isAbsolute37(value)) {
116650
+ if (!/^[a-zA-Z0-9._-]+$/.test(name) || typeof value !== "string" || !value || isAbsolute39(value)) {
116426
116651
  throw new Error("PACKAGE_BIN_INVALID");
116427
116652
  }
116428
116653
  const normalized2 = value.replaceAll("\\", "/");
@@ -116450,7 +116675,7 @@ function resolveRuntimeLayout(homeInput, pathInput) {
116450
116675
  const home = realpathSync19(homeInput);
116451
116676
  const runtimeRoot = join66(home, ".hasna", "skills", "runtime");
116452
116677
  assertNoSymlinkAncestors(runtimeRoot);
116453
- const runtimeRootStat = lstatSync39(runtimeRoot);
116678
+ const runtimeRootStat = lstatSync40(runtimeRoot);
116454
116679
  if (!runtimeRootStat.isDirectory() || runtimeRootStat.isSymbolicLink() || (runtimeRootStat.mode & 63) !== 0) {
116455
116680
  throw new Error("RUNTIME_ROOT_NOT_PRIVATE");
116456
116681
  }
@@ -116509,7 +116734,7 @@ function resolveRuntimeLayout(homeInput, pathInput) {
116509
116734
  if (actual !== join66(currentPackageRoot, target))
116510
116735
  continue;
116511
116736
  const newTarget = join66(runtimeRoot, "__target__", "node_modules", "@hasna", "skills", target);
116512
- const backupPath = `${path}.skills-prev-${randomUUID10()}`;
116737
+ const backupPath = `${path}.skills-prev-${randomUUID11()}`;
116513
116738
  if (launcher.kind === "symlink") {
116514
116739
  if (resolve36(dirname40(path), launcher.linkTarget) !== actual)
116515
116740
  throw new Error("LAUNCHER_SYMLINK_CHAIN_UNSUPPORTED");
@@ -116722,7 +116947,7 @@ function readTree(root2, includeModes, excludeNpmDependencies = false) {
116722
116947
  for (const item of readdirSync24(dir).sort()) {
116723
116948
  const path = join66(dir, item);
116724
116949
  const rel = prefix ? `${prefix}/${item}` : item;
116725
- const stat3 = lstatSync39(path);
116950
+ const stat3 = lstatSync40(path);
116726
116951
  if (excludeNpmDependencies && !prefix && item === "node_modules") {
116727
116952
  if (!stat3.isDirectory() || stat3.isSymbolicLink())
116728
116953
  throw new Error("INSTALLED_DEPENDENCY_DIRECTORY_UNSAFE");
@@ -116758,14 +116983,14 @@ function readTree(root2, includeModes, excludeNpmDependencies = false) {
116758
116983
  return { entries, digest: hash6(new TextEncoder().encode(JSON.stringify(entries))) };
116759
116984
  }
116760
116985
  function normalizeModes(root2) {
116761
- const rootStat = lstatSync39(root2);
116986
+ const rootStat = lstatSync40(root2);
116762
116987
  if (!rootStat.isDirectory() || rootStat.isSymbolicLink())
116763
116988
  throw new Error("RUNTIME_ENTRY_TYPE_UNSUPPORTED");
116764
116989
  chmodSync4(root2, rootStat.mode & 493);
116765
116990
  const walk2 = (dir) => {
116766
116991
  for (const item of readdirSync24(dir)) {
116767
116992
  const path = join66(dir, item);
116768
- const stat3 = lstatSync39(path);
116993
+ const stat3 = lstatSync40(path);
116769
116994
  if (stat3.isSymbolicLink())
116770
116995
  continue;
116771
116996
  if (stat3.isDirectory()) {
@@ -116815,7 +117040,7 @@ function verifyPreimageManifest(runtimePath, receipt, home) {
116815
117040
  throw new Error("PREIMAGE_CONFIG_BINDING_INVALID");
116816
117041
  if (config2.present) {
116817
117042
  const backup = join66(runtimePath, "preimage", "configs", relativePath);
116818
- const stat3 = lstatSync39(backup);
117043
+ const stat3 = lstatSync40(backup);
116819
117044
  const saved = readFileSync43(backup);
116820
117045
  if (!stat3.isFile() || stat3.isSymbolicLink() || hash6(saved) !== config2.sha256 || saved.byteLength !== config2.byteSize)
116821
117046
  throw new Error("PREIMAGE_CONFIG_DRIFT");
@@ -116829,7 +117054,7 @@ function captureConfigPreimages(home, stage) {
116829
117054
  const sourcePath = join66(home, relativePath);
116830
117055
  if (!entryExists(sourcePath))
116831
117056
  return { sourcePath, relativePath, present: false };
116832
- const stat3 = lstatSync39(sourcePath);
117057
+ const stat3 = lstatSync40(sourcePath);
116833
117058
  if (!stat3.isFile() || stat3.isSymbolicLink())
116834
117059
  throw new Error("CONFIG_PREIMAGE_NOT_REGULAR_FILE");
116835
117060
  const bytes = readFileSync43(sourcePath);
@@ -116849,7 +117074,7 @@ function assertConfigUnchanged(configs) {
116849
117074
  if (present2 !== config2.present)
116850
117075
  throw new Error("CONFIG_DRIFT_DURING_UPDATE");
116851
117076
  if (present2) {
116852
- const stat3 = lstatSync39(config2.sourcePath);
117077
+ const stat3 = lstatSync40(config2.sourcePath);
116853
117078
  if (!stat3.isFile() || stat3.isSymbolicLink() || hash6(readFileSync43(config2.sourcePath)) !== config2.sha256) {
116854
117079
  throw new Error("CONFIG_DRIFT_DURING_UPDATE");
116855
117080
  }
@@ -116948,7 +117173,7 @@ function replaceLauncher(item) {
116948
117173
  const oldState = oldLauncherState(item), newState = newLauncherState(item);
116949
117174
  if (!launcherIs(item.path, oldState) || entryExists(item.backupPath))
116950
117175
  throw new Error("LAUNCHER_PREIMAGE_DRIFT");
116951
- const temp = `${item.path}.skills-next-${randomUUID10()}`;
117176
+ const temp = `${item.path}.skills-next-${randomUUID11()}`;
116952
117177
  try {
116953
117178
  materializeLauncher(item.backupPath, oldState);
116954
117179
  } catch {
@@ -116963,15 +117188,15 @@ function replaceLauncher(item) {
116963
117188
  }
116964
117189
  if (!launcherIs(temp, newState))
116965
117190
  throw new Error("LAUNCHER_NEW_LINK_READBACK_MISMATCH");
116966
- renameSync14(temp, item.path);
117191
+ renameSync15(temp, item.path);
116967
117192
  }
116968
117193
  function atomicJson(path, value) {
116969
- const temp = `${path}.next-${randomUUID10()}`;
117194
+ const temp = `${path}.next-${randomUUID11()}`;
116970
117195
  const bytes = Buffer.from(`${JSON.stringify(value, null, 2)}
116971
117196
  `);
116972
117197
  writeFileSync24(temp, bytes, { flag: "wx", mode: 384 });
116973
117198
  chmodSync4(temp, 384);
116974
- renameSync14(temp, path);
117199
+ renameSync15(temp, path);
116975
117200
  if (!readFileSync43(path).equals(bytes))
116976
117201
  throw new Error("RECEIPT_READBACK_MISMATCH");
116977
117202
  }
@@ -116988,10 +117213,10 @@ function persistReceipt(path, value) {
116988
117213
  const historyRoot = join66(dirname40(path), "receipt-history");
116989
117214
  if (!entryExists(historyRoot))
116990
117215
  mkdirSync27(historyRoot, { mode: 448 });
116991
- const historyStat = lstatSync39(historyRoot);
117216
+ const historyStat = lstatSync40(historyRoot);
116992
117217
  if (!historyStat.isDirectory() || historyStat.isSymbolicLink() || (historyStat.mode & 63) !== 0)
116993
117218
  throw new Error("RECEIPT_HISTORY_NOT_PRIVATE");
116994
- const historyPath = join66(historyRoot, `${value.id}-${String(prior.state)}-${randomUUID10()}.json`);
117219
+ const historyPath = join66(historyRoot, `${value.id}-${String(prior.state)}-${randomUUID11()}.json`);
116995
117220
  writeFileSync24(historyPath, priorBytes, { flag: "wx", mode: 256 });
116996
117221
  chmodSync4(historyPath, 256);
116997
117222
  if (!readFileSync43(historyPath).equals(priorBytes))
@@ -117012,10 +117237,10 @@ function persistAliasReceipt(path, value) {
117012
117237
  const history = join66(dirname40(path), "history");
117013
117238
  if (!entryExists(history))
117014
117239
  mkdirSync27(history, { mode: 448 });
117015
- const historyStat = lstatSync39(history);
117240
+ const historyStat = lstatSync40(history);
117016
117241
  if (!historyStat.isDirectory() || historyStat.isSymbolicLink() || (historyStat.mode & 63) !== 0)
117017
117242
  throw new Error("ALIAS_RECEIPT_HISTORY_UNSAFE");
117018
- const saved = join66(history, `${value.id}-${String(prior.state)}-${randomUUID10()}.json`);
117243
+ const saved = join66(history, `${value.id}-${String(prior.state)}-${randomUUID11()}.json`);
117019
117244
  writeFileSync24(saved, priorBytes, { flag: "wx", mode: 256 });
117020
117245
  chmodSync4(saved, 256);
117021
117246
  if (!readFileSync43(saved).equals(priorBytes))
@@ -117026,7 +117251,7 @@ function persistAliasReceipt(path, value) {
117026
117251
  function assertOwnedSafePath(path, home, requireWritable = false) {
117027
117252
  assertNoSymlinkAncestors(path);
117028
117253
  for (let current = path;; current = dirname40(current)) {
117029
- const stat3 = lstatSync39(current);
117254
+ const stat3 = lstatSync40(current);
117030
117255
  if (!stat3.isDirectory() || ![0, process.getuid?.() ?? -1].includes(stat3.uid) || stat3.mode & 18)
117031
117256
  throw new Error("ALIAS_PATH_UNSAFE");
117032
117257
  if (current === path && requireWritable && (stat3.uid !== (process.getuid?.() ?? -1) || (stat3.mode & 128) === 0))
@@ -117074,7 +117299,7 @@ function inspectAliasPackageChain(home, aliasPath, oldLinkTarget, oldTarget, bin
117074
117299
  assertOwnedSafePath(dirname40(packageLinkPath), home);
117075
117300
  let stat3, packageLinkTarget, resolved;
117076
117301
  try {
117077
- stat3 = lstatSync39(packageLinkPath);
117302
+ stat3 = lstatSync40(packageLinkPath);
117078
117303
  packageLinkTarget = readlinkSync8(packageLinkPath);
117079
117304
  resolved = realpathSync19(packageLinkPath);
117080
117305
  } catch {
@@ -117097,7 +117322,7 @@ function validateAliasSource(home, name, actual) {
117097
117322
  }
117098
117323
  assertOwnedSafePath(packageRoot, home);
117099
117324
  const manifestPath = join66(packageRoot, "package.json");
117100
- const manifestStat = lstatSync39(manifestPath), binaryStat = lstatSync39(actual);
117325
+ const manifestStat = lstatSync40(manifestPath), binaryStat = lstatSync40(actual);
117101
117326
  if (!manifestStat.isFile() || manifestStat.isSymbolicLink() || !binaryStat.isFile() || binaryStat.isSymbolicLink() || ![0, process.getuid?.() ?? -1].includes(manifestStat.uid) || ![0, process.getuid?.() ?? -1].includes(binaryStat.uid) || manifestStat.mode & 18)
117102
117327
  throw new Error("ALIAS_SOURCE_UNSAFE");
117103
117328
  const pkg = readPackage(manifestPath);
@@ -117113,7 +117338,7 @@ function adoptCopyfileAliases(options = {}) {
117113
117338
  const launcherRuntime = pinnedLauncherRuntime();
117114
117339
  pinnedLauncherState(launcherRuntime, currentRuntime, join66(layout.currentPackageRoot, layout.bin.skills ?? "bin/index.js"));
117115
117340
  const releaseLock = acquireRuntimeLock(layout.runtimeRoot);
117116
- const id2 = randomUUID10();
117341
+ const id2 = randomUUID11();
117117
117342
  const aliases = [];
117118
117343
  const receiptDir = join66(currentRuntime, "alias-adoptions");
117119
117344
  const receiptPath = join66(receiptDir, `${id2}.json`);
@@ -117130,7 +117355,7 @@ function adoptCopyfileAliases(options = {}) {
117130
117355
  if (!entryExists(path))
117131
117356
  continue;
117132
117357
  assertOwnedSafePath(dir, home, true);
117133
- const stat3 = lstatSync39(path);
117358
+ const stat3 = lstatSync40(path);
117134
117359
  if (stat3.uid !== (process.getuid?.() ?? -1))
117135
117360
  throw new Error("ALIAS_LINK_NOT_OWNED");
117136
117361
  let launcher;
@@ -117169,7 +117394,7 @@ function adoptCopyfileAliases(options = {}) {
117169
117394
  if (!aliases.length)
117170
117395
  return { adopted: true, version: layout.currentVersion, aliasCount: 0 };
117171
117396
  mkdirSync27(receiptDir, { recursive: true, mode: 448 });
117172
- const receiptDirStat = lstatSync39(receiptDir);
117397
+ const receiptDirStat = lstatSync40(receiptDir);
117173
117398
  if (!receiptDirStat.isDirectory() || receiptDirStat.isSymbolicLink() || receiptDirStat.mode & 63)
117174
117399
  throw new Error("ALIAS_RECEIPT_DIRECTORY_UNSAFE");
117175
117400
  receipt = {
@@ -117234,9 +117459,9 @@ function adoptCopyfileAliases(options = {}) {
117234
117459
  if (entryExists(after2))
117235
117460
  throw new Error("ALIAS_AFTER_COLLISION");
117236
117461
  materializeLauncher(after2, newLauncherState(item));
117237
- const temp = `${item.path}.skills-alias-rollback-${randomUUID10()}`;
117462
+ const temp = `${item.path}.skills-alias-rollback-${randomUUID11()}`;
117238
117463
  materializeLauncher(temp, oldLauncherState(item));
117239
- renameSync14(temp, item.path);
117464
+ renameSync15(temp, item.path);
117240
117465
  if (!launcherIs(item.path, oldLauncherState(item)))
117241
117466
  throw new Error("ALIAS_ROLLBACK_READBACK_MISMATCH");
117242
117467
  receipt.rollbackCompletedAliases = [...receipt.rollbackCompletedAliases, item.path];
@@ -117287,7 +117512,7 @@ function rollbackCopyfileAliases(receiptId, options = {}) {
117287
117512
  const source = validateAliasSource(home, name, item.oldTarget);
117288
117513
  if (source.version !== item.oldVersion || source.binarySha256 !== item.oldBinarySha256)
117289
117514
  throw new Error("ALIAS_PREIMAGE_DRIFT");
117290
- const stat3 = lstatSync39(item.path);
117515
+ const stat3 = lstatSync40(item.path);
117291
117516
  if (stat3.uid !== (process.getuid?.() ?? -1))
117292
117517
  throw new Error("ALIAS_LINK_DRIFT");
117293
117518
  let current;
@@ -117322,9 +117547,9 @@ function rollbackCopyfileAliases(receiptId, options = {}) {
117322
117547
  throw new Error("ALIAS_AFTER_DRIFT");
117323
117548
  if (launcherTarget(item.path) !== item.newTarget)
117324
117549
  throw new Error("ALIAS_TARGET_DRIFT");
117325
- const temp = `${item.path}.skills-alias-rollback-${randomUUID10()}`;
117550
+ const temp = `${item.path}.skills-alias-rollback-${randomUUID11()}`;
117326
117551
  materializeLauncher(temp, oldLauncherState(item));
117327
- renameSync14(temp, item.path);
117552
+ renameSync15(temp, item.path);
117328
117553
  if (!launcherIs(item.path, oldLauncherState(item)))
117329
117554
  throw new Error("ALIAS_ROLLBACK_READBACK_MISMATCH");
117330
117555
  receipt.rollbackCompletedAliases = [...new Set([...receipt.rollbackCompletedAliases, item.path])];
@@ -117353,10 +117578,10 @@ async function updateCopyfileRuntime(version2, options = {}) {
117353
117578
  throw new Error("REVIEWED_LOCK_INPUT_PAIR_REQUIRED");
117354
117579
  if (!policy)
117355
117580
  throw new Error("REVIEWED_LOCK_RELEASE_AGE_REQUIRED");
117356
- if (!isAbsolute37(options.reviewedLock))
117581
+ if (!isAbsolute39(options.reviewedLock))
117357
117582
  throw new Error("REVIEWED_LOCK_ABSOLUTE_PATH_REQUIRED");
117358
117583
  assertNoSymlinkAncestors(dirname40(options.reviewedLock));
117359
- const stat3 = lstatSync39(options.reviewedLock);
117584
+ const stat3 = lstatSync40(options.reviewedLock);
117360
117585
  if (!stat3.isFile() || stat3.isSymbolicLink() || stat3.nlink !== 1 || stat3.uid !== process.getuid?.() || stat3.mode & 63 || stat3.size > 8 * 1024 * 1024)
117361
117586
  throw new Error("REVIEWED_LOCK_FILE_UNSAFE");
117362
117587
  reviewedLockBytes = readFileSync43(options.reviewedLock);
@@ -117377,10 +117602,10 @@ async function updateCopyfileRuntime(version2, options = {}) {
117377
117602
  throw new Error("REGISTRY_ORIGIN_INVALID");
117378
117603
  if (origin.username || origin.password || origin.search || origin.hash)
117379
117604
  throw new Error("REGISTRY_ORIGIN_INVALID");
117380
- const runtimeRootStat = lstatSync39(layout.runtimeRoot);
117605
+ const runtimeRootStat = lstatSync40(layout.runtimeRoot);
117381
117606
  if ((runtimeRootStat.mode & 63) !== 0)
117382
117607
  throw new Error("RUNTIME_ROOT_NOT_PRIVATE");
117383
- const id2 = randomUUID10();
117608
+ const id2 = randomUUID11();
117384
117609
  const stagePath = join66(layout.runtimeRoot, `.stage-${version2}-${id2}`);
117385
117610
  const finalPath = join66(layout.runtimeRoot, `${version2}-copyfile`);
117386
117611
  const launcherRuntime = pinnedLauncherRuntime();
@@ -117493,7 +117718,7 @@ async function updateCopyfileRuntime(version2, options = {}) {
117493
117718
  persistReceipt(join66(stagePath, "rollout-receipt.json"), receipt);
117494
117719
  const finalNodeModules = join66(stagePackage, "node_modules");
117495
117720
  const stagedNodeModules = join66(stagePath, "node_modules");
117496
- renameSync14(finalNodeModules, stagedNodeModules);
117721
+ renameSync15(finalNodeModules, stagedNodeModules);
117497
117722
  copyFileSync(join66(stagePackage, "package-lock.json"), join66(stagePath, "install-lock.json"));
117498
117723
  chmodSync4(join66(stagePath, "install-lock.json"), 384);
117499
117724
  const stagedTree = readTree(stagedNodeModules, true);
@@ -117502,7 +117727,7 @@ async function updateCopyfileRuntime(version2, options = {}) {
117502
117727
  receipt.targetPackageRoot = join66(finalPath, "node_modules", "@hasna", "skills");
117503
117728
  receipt.runtimeTreeSha256 = stagedTree.digest;
117504
117729
  persistReceipt(join66(stagePath, "rollout-receipt.json"), receipt);
117505
- renameSync14(stagePath, finalPath);
117730
+ renameSync15(stagePath, finalPath);
117506
117731
  moved = true;
117507
117732
  const finalReceiptBytes = Buffer.from(`${JSON.stringify(receipt, null, 2)}
117508
117733
  `);
@@ -117540,7 +117765,7 @@ async function updateCopyfileRuntime(version2, options = {}) {
117540
117765
  throw new Error("ROLLBACK_PRESERVATION_PATH_EXISTS");
117541
117766
  materializeLauncher(afterPath, newLauncherState(item));
117542
117767
  materializeLauncher(temp, oldLauncherState(item));
117543
- renameSync14(temp, item.path);
117768
+ renameSync15(temp, item.path);
117544
117769
  } catch {
117545
117770
  rollbackFailed = true;
117546
117771
  }
@@ -117568,7 +117793,7 @@ function rollbackCopyfileRuntime(receiptId, options = {}) {
117568
117793
  throw new Error("HOME_NOT_FOUND");
117569
117794
  const runtimeRoot = join66(realpathSync19(home), ".hasna", "skills", "runtime");
117570
117795
  assertNoSymlinkAncestors(runtimeRoot);
117571
- const rootStat = lstatSync39(runtimeRoot);
117796
+ const rootStat = lstatSync40(runtimeRoot);
117572
117797
  if (!rootStat.isDirectory() || rootStat.isSymbolicLink() || (rootStat.mode & 63) !== 0)
117573
117798
  throw new Error("RUNTIME_ROOT_NOT_PRIVATE");
117574
117799
  const releaseLock = acquireRuntimeLock(runtimeRoot);
@@ -117609,7 +117834,7 @@ function rollbackCopyfileRuntime(receiptId, options = {}) {
117609
117834
  const seen = new Set;
117610
117835
  for (const item of receipt.launchers) {
117611
117836
  const bin = oldBins[basename21(item.path)];
117612
- if (!bin || !isAbsolute37(item.path) || seen.has(item.path) || item.oldTarget !== join66(receipt.currentPackageRoot, bin) || item.newTarget !== join66(receipt.targetPackageRoot, bin) || !/^.+\.skills-prev-[0-9a-f-]{36}$/.test(item.backupPath) || !item.backupPath.startsWith(`${item.path}.skills-prev-`) || typeof item.oldLinkTarget !== "string" || resolve36(dirname40(item.path), item.oldLinkTarget) !== item.oldTarget)
117837
+ if (!bin || !isAbsolute39(item.path) || seen.has(item.path) || item.oldTarget !== join66(receipt.currentPackageRoot, bin) || item.newTarget !== join66(receipt.targetPackageRoot, bin) || !/^.+\.skills-prev-[0-9a-f-]{36}$/.test(item.backupPath) || !item.backupPath.startsWith(`${item.path}.skills-prev-`) || typeof item.oldLinkTarget !== "string" || resolve36(dirname40(item.path), item.oldLinkTarget) !== item.oldTarget)
117613
117838
  throw new Error("RECEIPT_LAUNCHER_BINDING_INVALID");
117614
117839
  assertNoSymlinkAncestors(dirname40(item.path));
117615
117840
  assertLauncherRecordShapes(item, launcherProfileForBin(basename21(item.path), bin));
@@ -117641,9 +117866,9 @@ function rollbackCopyfileRuntime(receiptId, options = {}) {
117641
117866
  const afterPath = `${item.path}.skills-after-${receiptId}`;
117642
117867
  if (!entryExists(afterPath))
117643
117868
  materializeLauncher(afterPath, newLauncherState(item));
117644
- const temp = `${item.path}.skills-rollback-${receiptId}-${randomUUID10()}`;
117869
+ const temp = `${item.path}.skills-rollback-${receiptId}-${randomUUID11()}`;
117645
117870
  materializeLauncher(temp, oldLauncherState(item));
117646
- renameSync14(temp, item.path);
117871
+ renameSync15(temp, item.path);
117647
117872
  receipt.rollbackCompletedLaunchers = [...new Set([...receipt.rollbackCompletedLaunchers, item.path])];
117648
117873
  persistReceipt(receiptPath, receipt);
117649
117874
  }
@@ -117676,9 +117901,9 @@ __export(exports_runtime, {
117676
117901
  selectedSkillsCommand: () => selectedSkillsCommand,
117677
117902
  registerRuntime: () => registerRuntime
117678
117903
  });
117679
- import { createHash as createHash41, randomUUID as randomUUID11 } from "crypto";
117680
- import { lstatSync as lstatSync40, mkdirSync as mkdirSync28, readFileSync as readFileSync44, writeFileSync as writeFileSync25 } from "fs";
117681
- import { basename as basename22, isAbsolute as isAbsolute38, join as join67 } from "path";
117904
+ import { createHash as createHash41, randomUUID as randomUUID12 } from "crypto";
117905
+ import { lstatSync as lstatSync41, mkdirSync as mkdirSync28, readFileSync as readFileSync44, writeFileSync as writeFileSync25 } from "fs";
117906
+ import { basename as basename22, isAbsolute as isAbsolute40, join as join67 } from "path";
117682
117907
  import { createInterface } from "readline";
117683
117908
  function registerRuntime(parent) {
117684
117909
  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) => {
@@ -117746,7 +117971,11 @@ function registerRuntime(parent) {
117746
117971
  await handleMcp(options);
117747
117972
  }));
117748
117973
  const setup = parent.command("setup").description("Point this CLI at a Skills API server, or register agent integrations").option("--api-url <url>", "Skills API origin to send remote work to").option("--global", "Accepted for compatibility; the API origin is always per-user", false).option("--json", "Output setup result as JSON", false).action(async (options) => handleSetup(options));
117749
- setup.command("agents").option("--json", "Output registration result as JSON", false).description("Register the Skills MCP server with all supported agents").action(async (options) => handleMcp({ register: "all", json: options.json }));
117974
+ setup.command("agents").option("--json", "Output registration result as JSON", false).description("Register the Skills MCP server with all supported agents").action(async (options, command) => handleMcp({
117975
+ register: "all",
117976
+ json: options.json,
117977
+ apiUrl: command.parent?.opts().apiUrl
117978
+ }));
117750
117979
  parent.command("self-update").description("Update @hasna/skills to the latest version").option("--json", "Output result as JSON", false).option("--version <version>", "Install this exact @hasna/skills version as a staged copyfile runtime").option("--min-release-age <days>", "Require a positive integer dependency release age in days for an exact-version update").option("--min-release-age-exclude <pattern>", "Exclude matching package identities from the release-age policy (repeatable)", (pattern, prior) => [...prior, pattern], []).option("--reviewed-lock <path>", "Install from this private absolute package-lock.json path without resolving dependency ranges").option("--reviewed-lock-sha256 <sha256>", "Exact reviewed SHA-256 of the supplied package-lock.json").option("--rollback <receipt-id>", "Restore launcher links from an exact copyfile rollout receipt").option("--adopt-aliases", "Switch verified legacy @hasna/skills aliases to the active copyfile runtime").option("--rollback-aliases <receipt-id>", "Restore aliases from an exact adoption receipt").action(async (options) => {
117751
117980
  if ((options.reviewedLock !== undefined || options.reviewedLockSha256 !== undefined) && (!options.version || options.rollback || options.adoptAliases || options.rollbackAliases)) {
117752
117981
  console.error(JSON.stringify({ error: "REVIEWED_LOCK_REQUIRES_EXACT_VERSION" }));
@@ -117877,7 +118106,7 @@ Updating ${name}...
117877
118106
  async function readUpdatedVersion(bunExecutable) {
117878
118107
  const output2 = await readUpdateCommand([bunExecutable, "pm", "bin", "-g"]);
117879
118108
  const globalBin = output2.replace(/\r?\n$/, "");
117880
- if (!globalBin || !isAbsolute38(globalBin) || /[\r\n\0]/.test(globalBin))
118109
+ if (!globalBin || !isAbsolute40(globalBin) || /[\r\n\0]/.test(globalBin))
117881
118110
  throw new Error("Update bin discovery failed");
117882
118111
  const installed = Bun.which("skills", { PATH: globalBin, cwd: globalBin });
117883
118112
  const selected = Bun.which("skills");
@@ -118156,7 +118385,7 @@ async function handleRun(name, args2, options, separatorBeforeSkill) {
118156
118385
  if (!Number.isFinite(timeoutMs) || timeoutMs < 1 || timeoutMs > 1200000 || !Number.isFinite(intervalMs) || intervalMs < 100 || intervalMs > 60000)
118157
118386
  throw new Error("Invalid cloud polling bounds");
118158
118387
  const client3 = await CloudExecutionClient.configured();
118159
- const admitted = await client3.submit(slug2, version2, input2, options.idempotencyKey ?? randomUUID11(), selected?.selection);
118388
+ const admitted = await client3.submit(slug2, version2, input2, options.idempotencyKey ?? randomUUID12(), selected?.selection);
118160
118389
  if (options.wait)
118161
118390
  console.error(JSON.stringify({ executionId: admitted.id, status: admitted.status }));
118162
118391
  const result3 = options.wait ? await client3.wait(admitted.id, { timeoutMs, intervalMs }) : admitted;
@@ -118213,7 +118442,7 @@ async function handleRun(name, args2, options, separatorBeforeSkill) {
118213
118442
  try {
118214
118443
  parsePollingOptions(options);
118215
118444
  inputFiles = (options.file ?? []).map((path) => {
118216
- const info = lstatSync40(path);
118445
+ const info = lstatSync41(path);
118217
118446
  if (!info.isFile() || info.size > 20 * 1024 * 1024)
118218
118447
  throw new Error("Input must be a regular file no larger than 20 MiB");
118219
118448
  return { name: basename22(path), bytes: new Uint8Array(readFileSync44(path)) };
@@ -118643,7 +118872,7 @@ function ensureSafeExportParent(root2, relativePath) {
118643
118872
  if (part)
118644
118873
  parent = join67(parent, part);
118645
118874
  try {
118646
- if (!lstatSync40(parent).isDirectory() || lstatSync40(parent).isSymbolicLink())
118875
+ if (!lstatSync41(parent).isDirectory() || lstatSync41(parent).isSymbolicLink())
118647
118876
  throw new Error("Unsafe artifact directory");
118648
118877
  } catch (error61) {
118649
118878
  if (error61.code !== "ENOENT")
@@ -118938,7 +119167,7 @@ var exports_recurring = {};
118938
119167
  __export(exports_recurring, {
118939
119168
  registerRecurringCommands: () => registerRecurringCommands
118940
119169
  });
118941
- import { constants as constants28, closeSync as closeSync29, fstatSync as fstatSync29, lstatSync as lstatSync41, openSync as openSync29, readSync as readSync21 } from "fs";
119170
+ import { constants as constants28, closeSync as closeSync29, fstatSync as fstatSync29, lstatSync as lstatSync42, openSync as openSync29, readSync as readSync21 } from "fs";
118942
119171
  import { createInterface as createInterface2 } from "readline";
118943
119172
  function readRequest(path) {
118944
119173
  const fd = openSync29(path, constants28.O_RDONLY | constants28.O_NOFOLLOW | constants28.O_NONBLOCK);
@@ -118954,7 +119183,7 @@ function readRequest(path) {
118954
119183
  break;
118955
119184
  length += n2;
118956
119185
  }
118957
- const after2 = fstatSync29(fd), current = lstatSync41(path);
119186
+ const after2 = fstatSync29(fd), current = lstatSync42(path);
118958
119187
  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())
118959
119188
  throw new RecurringInputError;
118960
119189
  return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, length)));
@@ -119238,7 +119467,7 @@ var init_completion = __esm(() => {
119238
119467
  });
119239
119468
 
119240
119469
  // src/lib/portable-snapshot-filter.ts
119241
- import { readdirSync as readdirSync25, statSync as statSync22 } from "fs";
119470
+ import { readdirSync as readdirSync25, statSync as statSync23 } from "fs";
119242
119471
  import { homedir as homedir11 } from "os";
119243
119472
  import { join as join68, sep as sep19 } from "path";
119244
119473
  function isExcludedSkillFileName(fileName) {
@@ -119306,7 +119535,7 @@ function walkEntries(absoluteRoot) {
119306
119535
  }
119307
119536
  function isRegularFile(filePath) {
119308
119537
  try {
119309
- return statSync22(filePath).isFile();
119538
+ return statSync23(filePath).isFile();
119310
119539
  } catch {
119311
119540
  return false;
119312
119541
  }
@@ -119392,10 +119621,10 @@ import {
119392
119621
  copyFileSync as copyFileSync2,
119393
119622
  mkdirSync as mkdirSync29,
119394
119623
  readFileSync as readFileSync45,
119395
- statSync as statSync23,
119624
+ statSync as statSync24,
119396
119625
  writeFileSync as writeFileSync26
119397
119626
  } from "fs";
119398
- import { dirname as dirname42, isAbsolute as isAbsolute39, relative as relative14, resolve as resolve37, sep as sep20 } from "path";
119627
+ import { dirname as dirname42, isAbsolute as isAbsolute41, relative as relative14, resolve as resolve37, sep as sep20 } from "path";
119399
119628
  function validateStationId(stationId) {
119400
119629
  if (!/^[a-z0-9-]+$/.test(stationId)) {
119401
119630
  throw new StationSnapshotError("INVALID_STATION", `station id must be a slug, got: ${stationId}`);
@@ -119432,7 +119661,7 @@ function scanHome(definition, homesRoot) {
119432
119661
  skipped.push({ relativePath: entry.relativePath, reason: "not-regular-file" });
119433
119662
  continue;
119434
119663
  }
119435
- const info = statSync23(entry.fullPath);
119664
+ const info = statSync24(entry.fullPath);
119436
119665
  portable.push({
119437
119666
  relativePath: entry.relativePath,
119438
119667
  fullPath: entry.fullPath,
@@ -119501,7 +119730,7 @@ function writeStationSnapshot(options) {
119501
119730
  for (const plan of plans) {
119502
119731
  const destination = resolve37(repoRoot, plan.destination);
119503
119732
  const destinationRelative = relative14(repoRoot, destination);
119504
- if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep20) || isAbsolute39(destinationRelative)) {
119733
+ if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep20) || isAbsolute41(destinationRelative)) {
119505
119734
  throw new StationSnapshotError("DESTINATION_ESCAPE", `destination escapes repo root: ${plan.destination}`);
119506
119735
  }
119507
119736
  let existingDigest = null;
@@ -119974,7 +120203,7 @@ var init_create_sync_config = __esm(() => {
119974
120203
  });
119975
120204
 
119976
120205
  // src/lib/agent-install-selection.ts
119977
- import { lstatSync as lstatSync42 } from "fs";
120206
+ import { lstatSync as lstatSync43 } from "fs";
119978
120207
  import { dirname as dirname43, join as join70, resolve as resolve38 } from "path";
119979
120208
  import { homedir as homedir12 } from "os";
119980
120209
  function detectedIntegrationAgents(options = {}) {
@@ -119988,7 +120217,7 @@ function detectedIntegrationAgents(options = {}) {
119988
120217
  throw new Error("Invalid existing bridge agent inventory");
119989
120218
  const present2 = (path) => {
119990
120219
  try {
119991
- return lstatSync42(path, { throwIfNoEntry: false }) !== undefined;
120220
+ return lstatSync43(path, { throwIfNoEntry: false }) !== undefined;
119992
120221
  } catch {
119993
120222
  throw new Error("Agent presence cannot be inspected; review native configuration before hook installation");
119994
120223
  }
@@ -120018,7 +120247,7 @@ var init_agent_install_selection = __esm(() => {
120018
120247
  });
120019
120248
 
120020
120249
  // src/lib/codex-native-config.ts
120021
- import { isDeepStrictEqual as isDeepStrictEqual16 } from "util";
120250
+ import { isDeepStrictEqual as isDeepStrictEqual17 } from "util";
120022
120251
  function isRecord8(value) {
120023
120252
  if (!value || typeof value !== "object")
120024
120253
  return false;
@@ -120040,7 +120269,7 @@ function decimalIdentity(text4) {
120040
120269
  return `${match[1]}${coefficient}e${exponent}`;
120041
120270
  }
120042
120271
  function codexNativeConfigEqual(native, expected) {
120043
- if (isDeepStrictEqual16(native, expected))
120272
+ if (isDeepStrictEqual17(native, expected))
120044
120273
  return true;
120045
120274
  if (typeof expected === "number") {
120046
120275
  if (!Number.isFinite(expected) || !isRecord8(native))
@@ -120064,11 +120293,11 @@ var NUMBER_TAG = "$serde_json::private::Number";
120064
120293
  var init_codex_native_config = () => {};
120065
120294
 
120066
120295
  // src/lib/codex-hook-trust-identity.ts
120067
- import { lstatSync as lstatSync43, realpathSync as realpathSync20 } from "fs";
120068
- import { dirname as dirname44, isAbsolute as isAbsolute40, join as join71, resolve as resolve39 } from "path";
120069
- import { isDeepStrictEqual as isDeepStrictEqual17 } from "util";
120296
+ import { lstatSync as lstatSync44, realpathSync as realpathSync20 } from "fs";
120297
+ import { dirname as dirname44, isAbsolute as isAbsolute42, join as join71, resolve as resolve39 } from "path";
120298
+ import { isDeepStrictEqual as isDeepStrictEqual18 } from "util";
120070
120299
  function commandPhysical(command) {
120071
- need8(typeof command === "string" && isAbsolute40(command) && !command.includes("\x00") && resolve39(command) === command, COMMAND_NOT_CANONICAL);
120300
+ need8(typeof command === "string" && isAbsolute42(command) && !command.includes("\x00") && resolve39(command) === command, COMMAND_NOT_CANONICAL);
120072
120301
  const physical = realpathSync20(command);
120073
120302
  let spelled;
120074
120303
  try {
@@ -120079,7 +120308,7 @@ function commandPhysical(command) {
120079
120308
  safeParents(spelled);
120080
120309
  let direct = false;
120081
120310
  try {
120082
- const leaf = lstatSync43(spelled);
120311
+ const leaf = lstatSync44(spelled);
120083
120312
  direct = leaf.isSymbolicLink() ? trustedAncestorOwner(leaf.uid) && directAliasTarget(spelled) === physical : spelled === physical;
120084
120313
  } catch {}
120085
120314
  need8(direct, COMMAND_ALIAS_UNSAFE);
@@ -120123,7 +120352,7 @@ function targetUnchanged(command, target) {
120123
120352
  assertPinnedRuntime(target.runtime);
120124
120353
  }
120125
120354
  function inspectRecordedSkillsCli(command, expected) {
120126
- need8(isAbsolute40(command) && !command.includes("\x00"), "RECONCILE_RECORDED_COMMAND_REQUIRED");
120355
+ need8(isAbsolute42(command) && !command.includes("\x00"), "RECONCILE_RECORDED_COMMAND_REQUIRED");
120127
120356
  const target = skillsCommandTarget(command), resolved = target.entry;
120128
120357
  const cli = snapshot(resolved, false, { readOnlyPackage: true });
120129
120358
  const manifest = snapshot(join71(dirname44(dirname44(resolved)), "package.json"), false, { readOnlyPackage: true });
@@ -120131,7 +120360,7 @@ function inspectRecordedSkillsCli(command, expected) {
120131
120360
  need8(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved === join71(dirname44(manifest.file), "bin/index.js"), "SKILLS_PACKAGE_MISMATCH");
120132
120361
  need8((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
120133
120362
  const receipt = { path: resolved, version: pkg.version, sha256: cli.sha256, manifestSha256: manifest.sha256 };
120134
- need8(isDeepStrictEqual17(receipt, expected), "RECONCILE_SKILLS_BINDING_CHANGED");
120363
+ need8(isDeepStrictEqual18(receipt, expected), "RECONCILE_SKILLS_BINDING_CHANGED");
120135
120364
  return { receipt, recheck() {
120136
120365
  targetUnchanged(command, target);
120137
120366
  unchanged2(cli);
@@ -120142,7 +120371,7 @@ function bindSkillsCli(command, reviewed) {
120142
120371
  const normal = Bun.which("skills", { PATH: process.env.PATH });
120143
120372
  need8(normal, "SKILLS_COMMAND_UNAVAILABLE");
120144
120373
  const normalTarget = skillsCommandTarget(normal), resolved = normalTarget.entry;
120145
- const bound = isAbsolute40(command) ? command : command === "skills" ? normal : undefined;
120374
+ const bound = isAbsolute42(command) ? command : command === "skills" ? normal : undefined;
120146
120375
  need8(bound, "SKILLS_COMMAND_MISMATCH");
120147
120376
  const boundTarget = skillsCommandTarget(bound);
120148
120377
  need8(boundTarget.entry === resolved, "SKILLS_COMMAND_MISMATCH");
@@ -120201,19 +120430,19 @@ var init_codex_hook_trust_identity = __esm(() => {
120201
120430
  });
120202
120431
 
120203
120432
  // src/lib/codex-hook-policy-recovery.ts
120204
- import { isDeepStrictEqual as isDeepStrictEqual18 } from "util";
120433
+ import { isDeepStrictEqual as isDeepStrictEqual19 } from "util";
120205
120434
  function reviewedClaudeDiscoveryChange(beforeText, currentText, options) {
120206
120435
  need8(typeof options.reason === "string" && options.reason.trim().length > 0 && options.reason.length <= 512 && !/[\x00-\x1f\x7f]/.test(options.reason), "RECONCILE_RECOVERY_REASON_REQUIRED");
120207
120436
  need8(options.reviewedPlanDigest === undefined || /^[a-f0-9]{64}$/.test(options.reviewedPlanDigest), "RECONCILE_RECOVERY_PLAN_CHANGED");
120208
120437
  const before2 = parseManagedSkillPolicy(beforeText), current = parseManagedSkillPolicy(currentText);
120209
120438
  const oldDiscovery = before2.bridge?.discovery?.claude, newDiscovery = current.bridge?.discovery?.claude;
120210
120439
  need8(oldDiscovery?.agent === "claude" && newDiscovery?.agent === "claude" && oldDiscovery.method === "reviewed" && newDiscovery.method === "reviewed", "RECONCILE_POLICY_CHANGED");
120211
- const changes = ["roots", "sources"].filter((key2) => !isDeepStrictEqual18(oldDiscovery[key2], newDiscovery[key2])).map((key2) => ({ path: `bridge.discovery.claude.${key2}`, before: oldDiscovery[key2], after: newDiscovery[key2] }));
120440
+ const changes = ["roots", "sources"].filter((key2) => !isDeepStrictEqual19(oldDiscovery[key2], newDiscovery[key2])).map((key2) => ({ path: `bridge.discovery.claude.${key2}`, before: oldDiscovery[key2], after: newDiscovery[key2] }));
120212
120441
  need8(changes.length > 0, "RECONCILE_POLICY_CHANGED");
120213
120442
  const compared = structuredClone(current);
120214
120443
  compared.bridge.discovery.claude.roots = oldDiscovery.roots;
120215
120444
  compared.bridge.discovery.claude.sources = oldDiscovery.sources;
120216
- need8(isDeepStrictEqual18(before2, compared), "RECONCILE_POLICY_CHANGED");
120445
+ need8(isDeepStrictEqual19(before2, compared), "RECONCILE_POLICY_CHANGED");
120217
120446
  verifyAgentDiscovery(newDiscovery);
120218
120447
  return { reason: options.reason, changes };
120219
120448
  }
@@ -120224,16 +120453,16 @@ var init_codex_hook_policy_recovery = __esm(() => {
120224
120453
  });
120225
120454
 
120226
120455
  // src/lib/agent-codex-trust.ts
120227
- import { lstatSync as lstatSync44, mkdirSync as mkdirSync30, readdirSync as readdirSync26, readFileSync as readFileSync46, realpathSync as realpathSync21, statSync as statSync24 } from "fs";
120228
- import { createHash as createHash43, randomUUID as randomUUID12 } from "crypto";
120456
+ import { lstatSync as lstatSync45, mkdirSync as mkdirSync30, readdirSync as readdirSync26, readFileSync as readFileSync46, realpathSync as realpathSync21, statSync as statSync25 } from "fs";
120457
+ import { createHash as createHash43, randomUUID as randomUUID13 } from "crypto";
120229
120458
  import { execFileSync as execFileSync2 } from "child_process";
120230
- import { dirname as dirname45, isAbsolute as isAbsolute41, join as join72, resolve as resolve40 } from "path";
120459
+ import { dirname as dirname45, isAbsolute as isAbsolute43, join as join72, resolve as resolve40 } from "path";
120231
120460
  import { homedir as homedir13 } from "os";
120232
- import { isDeepStrictEqual as isDeepStrictEqual19 } from "util";
120461
+ import { isDeepStrictEqual as isDeepStrictEqual20 } from "util";
120233
120462
  function verifyReleaseArtifact(proof, skillsCli) {
120234
- need8(isAbsolute41(proof.packageTarPath) && !proof.packageTarPath.includes("\x00"), "RECONCILE_RELEASE_PROVENANCE_PATH");
120463
+ need8(isAbsolute43(proof.packageTarPath) && !proof.packageTarPath.includes("\x00"), "RECONCILE_RELEASE_PROVENANCE_PATH");
120235
120464
  const tarPath = realpathSync21(proof.packageTarPath);
120236
- need8(statSync24(tarPath).isFile(), "RECONCILE_RELEASE_PROVENANCE_PATH");
120465
+ need8(statSync25(tarPath).isFile(), "RECONCILE_RELEASE_PROVENANCE_PATH");
120237
120466
  const tarBytes = readFileSync46(tarPath);
120238
120467
  need8(tarBytes.byteLength === proof.packageTarBytes && createHash43("sha256").update(tarBytes).digest("hex") === proof.packageTarSha256, "RECONCILE_RELEASE_ARTIFACT_CHANGED");
120239
120468
  const packageRoot = dirname45(dirname45(realpathSync21(skillsCli.receipt.path)));
@@ -120257,10 +120486,10 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
120257
120486
  const home = resolve40(options.home ?? homedir13()), dataDir3 = resolve40(options.dataDir ?? getDataDirReadOnly());
120258
120487
  const parent = resolve40(join72(dataDir3, "native-hook-trust")), journal = resolve40(options.journal);
120259
120488
  need8(journal.startsWith(parent + "/") && /^[a-f0-9-]{36}$/.test(journal.slice(parent.length + 1)), "RECONCILE_JOURNAL_PATH");
120260
- const dir = lstatSync44(journal, { throwIfNoEntry: false });
120489
+ const dir = lstatSync45(journal, { throwIfNoEntry: false });
120261
120490
  need8(!!dir && dir.isDirectory() && !dir.isSymbolicLink() && dir.uid === process.getuid() && (dir.mode & 511) === 448, "UNSAFE_JOURNAL");
120262
- need8(!lstatSync44(join72(journal, "receipt.json"), { throwIfNoEntry: false }), "RECONCILE_ALREADY_COMPLETE");
120263
- need8(lstatSync44(join72(journal, "stopped.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_JOURNAL_INCOMPLETE");
120491
+ need8(!lstatSync45(join72(journal, "receipt.json"), { throwIfNoEntry: false }), "RECONCILE_ALREADY_COMPLETE");
120492
+ need8(lstatSync45(join72(journal, "stopped.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_JOURNAL_INCOMPLETE");
120264
120493
  const stoppedFile = snapshot(join72(journal, "stopped.json"), true);
120265
120494
  const intentFile = snapshot(join72(journal, "intent.json"), true), intent = JSON.parse(intentFile.text);
120266
120495
  const configBefore = snapshot(join72(journal, "config.before.toml"), true), hooksBefore = snapshot(join72(journal, "hooks.before.json"), true), policyBefore = snapshot(join72(journal, "policy.before.json"), true);
@@ -120271,7 +120500,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
120271
120500
  const configSha256 = intent.configSha256 ?? configBefore.sha256, configVersion = intent.configVersion ?? intent.expectedVersion;
120272
120501
  const digestInput = { version: 1, home: intent.home ?? home, configPath: intent.configPath, ...intent.nativeConfigPath !== undefined ? { nativeConfigPath: intent.nativeConfigPath } : {}, configSha256, configVersion, policySha256: intent.policySha256, hooksSha256: intent.hooksSha256, skillsCli: intent.skillsCli, nativeVersion: intent.nativeVersion, declarations, admitted };
120273
120502
  need8(makePlanDigest(digestInput) === intent.planDigest, "RECONCILE_PLAN_CHANGED");
120274
- need8(isDeepStrictEqual19(intent.hooks, admitted.filter((hook) => !hook.enabled || hook.trustStatus !== "trusted")), "RECONCILE_INTENT_HOOKS_CHANGED");
120503
+ need8(isDeepStrictEqual20(intent.hooks, admitted.filter((hook) => !hook.enabled || hook.trustStatus !== "trusted")), "RECONCILE_INTENT_HOOKS_CHANGED");
120275
120504
  need8(configBefore.sha256 === (intent.beforeSha256 ?? intent.configSha256) && hooksBefore.sha256 === intent.hooksSha256 && policyBefore.sha256 === intent.policySha256, "RECONCILE_JOURNAL_CHANGED");
120276
120505
  const policyCurrent = snapshot(join72(dataDir3, "agent-policy.json"), true);
120277
120506
  const { claudeDiscoveryRecovery: claudeRecovery, nativeHookAdditionsRecovery: additionsRecovery } = options;
@@ -120284,13 +120513,13 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
120284
120513
  if (policyCurrent.sha256 !== policyBefore.sha256 && !claudeRecovery) {
120285
120514
  need8(options.supersedeBinding === true, "RECONCILE_POLICY_CHANGED");
120286
120515
  const oldPolicy = JSON.parse(policyBefore.text), currentPolicy = JSON.parse(policyCurrent.text);
120287
- need8(isDeepStrictEqual19(withoutCodexCommand(oldPolicy), withoutCodexCommand(currentPolicy)), "RECONCILE_POLICY_CHANGED");
120516
+ need8(isDeepStrictEqual20(withoutCodexCommand(oldPolicy), withoutCodexCommand(currentPolicy)), "RECONCILE_POLICY_CHANGED");
120288
120517
  supersededBinding = true;
120289
120518
  }
120290
120519
  if (supersededBinding || recovery) {
120291
120520
  need8(Array.isArray(intent.nativeHooks) && intent.nativeHooks.length > 0, "RECONCILE_NATIVE_INVENTORY_REQUIRED");
120292
120521
  const proof = options.releaseProof;
120293
- need8(!!proof && isAbsolute41(proof.packageTarPath) && /^[a-f0-9]{64}$/.test(proof.packageTarSha256) && Number.isInteger(proof.packageTarBytes) && proof.packageTarBytes > 0 && /^[a-f0-9]{64}$/.test(proof.manifestSha256) && /^[a-f0-9]{64}$/.test(proof.executableSha256), "RECONCILE_RELEASE_PROVENANCE_REQUIRED");
120522
+ need8(!!proof && isAbsolute43(proof.packageTarPath) && /^[a-f0-9]{64}$/.test(proof.packageTarSha256) && Number.isInteger(proof.packageTarBytes) && proof.packageTarBytes > 0 && /^[a-f0-9]{64}$/.test(proof.manifestSha256) && /^[a-f0-9]{64}$/.test(proof.executableSha256), "RECONCILE_RELEASE_PROVENANCE_REQUIRED");
120294
120523
  }
120295
120524
  const currentConfig = snapshot(intent.configPath, true);
120296
120525
  const policy = parseManagedSkillPolicy(policyCurrent.text), binding = policy.bridge;
@@ -120320,7 +120549,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
120320
120549
  need8(state?.enabled === true && typeof state.trusted_hash === "string" && /^sha256:[a-f0-9]{64}$/.test(state.trusted_hash), "RECONCILE_CONFIG_DRIFT");
120321
120550
  }
120322
120551
  } else
120323
- need8(isDeepStrictEqual19(expectedConfig, current), "RECONCILE_CONFIG_DRIFT");
120552
+ need8(isDeepStrictEqual20(expectedConfig, current), "RECONCILE_CONFIG_DRIFT");
120324
120553
  const configDiscoveryRecovery = recovery && binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, configBefore, currentConfig, intent.hooks, additions?.trustProof) : undefined;
120325
120554
  assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: configDiscoveryRecovery });
120326
120555
  const recoveryCli = recovery ? bindSkillsCli("skills", options.reviewedSkillsCli) : undefined;
@@ -120329,14 +120558,14 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
120329
120558
  const skillsCli = recovery ? inspectRecordedSkillsCli(binding.commands.codex, intent.skillsCli) : bindSkillsCli(binding.commands.codex, options.reviewedSkillsCli);
120330
120559
  if (supersededBinding)
120331
120560
  verifyReleaseArtifact(options.releaseProof, skillsCli);
120332
- const skillsBindingChanged = !isDeepStrictEqual19(skillsCli.receipt, intent.skillsCli);
120561
+ const skillsBindingChanged = !isDeepStrictEqual20(skillsCli.receipt, intent.skillsCli);
120333
120562
  need8(!skillsBindingChanged || supersededBinding, "RECONCILE_SKILLS_BINDING_CHANGED");
120334
120563
  if (!additions && hooksCurrent.sha256 !== intent.hooksSha256 && hooksCurrent.sha256 !== hooksBefore.sha256) {
120335
120564
  need8(supersededBinding, "RECONCILE_HOOKS_CHANGED");
120336
120565
  const currentDeclarations = JSON.parse(hooksCurrent.text).hooks;
120337
120566
  for (const [event, [nativeEvent]] of Object.entries(eventNames)) {
120338
120567
  const command = renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, event);
120339
- need8(isDeepStrictEqual19(currentDeclarations?.[event], [{ hooks: [{ type: "command", command, timeout: 15 }] }]), "RECONCILE_BINDING_HOOK_CHANGED");
120568
+ need8(isDeepStrictEqual20(currentDeclarations?.[event], [{ hooks: [{ type: "command", command, timeout: 15 }] }]), "RECONCILE_BINDING_HOOK_CHANGED");
120340
120569
  }
120341
120570
  }
120342
120571
  rpc = await connect({ command: options.codexCommand ?? "codex", home, codexHome });
@@ -120359,9 +120588,9 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
120359
120588
  delete identity6.command;
120360
120589
  return identity6;
120361
120590
  };
120362
- need8(isDeepStrictEqual19(stable(actual), stable(expected)), "RECONCILE_NATIVE_IDENTITY_CHANGED");
120591
+ need8(isDeepStrictEqual20(stable(actual), stable(expected)), "RECONCILE_NATIVE_IDENTITY_CHANGED");
120363
120592
  if (!plannedKeys.has(expected.key))
120364
- need8(isDeepStrictEqual19(actual, expected), "RECONCILE_UNRELATED_HOOK_CHANGED");
120593
+ need8(isDeepStrictEqual20(actual, expected), "RECONCILE_UNRELATED_HOOK_CHANGED");
120365
120594
  }
120366
120595
  for (const wanted of intent.hooks) {
120367
120596
  const matches2 = nativeHooks.filter((h2) => h2.key === wanted.key || h2.key === wanted.key.replace(join72(home, ".codex/hooks.json"), hooksPath));
@@ -120380,7 +120609,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
120380
120609
  const layers = config2?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
120381
120610
  need8(layers?.length === 1 && !layers[0].disabledReason && codexNativeConfigEqual(layers[0].config, current), "RECONCILE_NATIVE_CONFIG_MISMATCH");
120382
120611
  const finalDiscovery = await rpc.request("hooks/list", { cwds: [home] });
120383
- need8(Array.isArray(finalDiscovery?.data) && finalDiscovery.data.length === 1 && finalDiscovery.data[0].cwd === home && !finalDiscovery.data[0].errors?.length && !finalDiscovery.data[0].warnings?.length && (!recordedNativeHooks || isDeepStrictEqual19(finalDiscovery.data[0].hooks.map(safeNativeHook), nativeHooks.map(safeNativeHook))), "RECONCILE_NATIVE_STATE_CHANGED");
120612
+ need8(Array.isArray(finalDiscovery?.data) && finalDiscovery.data.length === 1 && finalDiscovery.data[0].cwd === home && !finalDiscovery.data[0].errors?.length && !finalDiscovery.data[0].warnings?.length && (!recordedNativeHooks || isDeepStrictEqual20(finalDiscovery.data[0].hooks.map(safeNativeHook), nativeHooks.map(safeNativeHook))), "RECONCILE_NATIVE_STATE_CHANGED");
120384
120613
  const finalConfig = await rpc.request("config/read", { includeLayers: true, cwd: home });
120385
120614
  const finalLayers = finalConfig?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
120386
120615
  need8(finalLayers?.length === 1 && !finalLayers[0].disabledReason && codexNativeConfigEqual(finalLayers[0].config, current), "RECONCILE_NATIVE_CONFIG_CHANGED");
@@ -120435,7 +120664,7 @@ async function enrollCodexNativeHooksUnlocked(options, connect, admission) {
120435
120664
  const binding = policy.bridge, alias = binding.rootAliases?.find((item) => item.agent === "codex");
120436
120665
  const skillsCli = bindSkillsCli(binding.commands.codex, options.reviewedSkillsCli);
120437
120666
  const physicalRoot = alias?.target ?? join72(home, ".codex"), hooksPath = join72(physicalRoot, "hooks.json"), configPath = join72(physicalRoot, "config.toml");
120438
- need8(options.codexHome === undefined || isAbsolute41(options.codexHome) && [join72(home, ".codex"), physicalRoot].includes(options.codexHome), "NATIVE_HOME_NOT_ADMITTED");
120667
+ need8(options.codexHome === undefined || isAbsolute43(options.codexHome) && [join72(home, ".codex"), physicalRoot].includes(options.codexHome), "NATIVE_HOME_NOT_ADMITTED");
120439
120668
  const codexHome = options.codexHome === undefined ? undefined : physicalRoot;
120440
120669
  const nativeConfigPath = join72(codexHome ?? join72(home, ".codex"), "config.toml");
120441
120670
  const hooksFile = snapshot(hooksPath), configFile = snapshot(configPath, true), original = structure3(configFile.text);
@@ -120445,7 +120674,7 @@ async function enrollCodexNativeHooksUnlocked(options, connect, admission) {
120445
120674
  const groups = declarations[event];
120446
120675
  need8(Array.isArray(groups), "DECLARATION_CHANGED");
120447
120676
  const matches2 = groups.flatMap((group, gi) => (group.hooks ?? []).flatMap((entry, hi) => entry.command === command ? [{ group, entry, gi, hi }] : []));
120448
- need8(matches2.length === 1 && isDeepStrictEqual19(matches2[0].group, { hooks: [{ type: "command", command, timeout: 15 }] }), "DECLARATION_CHANGED");
120677
+ need8(matches2.length === 1 && isDeepStrictEqual20(matches2[0].group, { hooks: [{ type: "command", command, timeout: 15 }] }), "DECLARATION_CHANGED");
120449
120678
  expected.push({ event: nativeEvent, key: `${join72(home, ".codex/hooks.json")}:${label}:${matches2[0].gi}:${matches2[0].hi}`, command });
120450
120679
  }
120451
120680
  codexTrustTextWitness(configFile.text, expected.map((h) => h.key));
@@ -120491,27 +120720,27 @@ async function enrollCodexNativeHooksUnlocked(options, connect, admission) {
120491
120720
  if (options.apply)
120492
120721
  need8(options.reviewedPlanDigest === planDigest, "PLAN_CHANGED: run the dry-run again and pass its reviewed --plan-digest with --apply");
120493
120722
  const parent = join72(dataDir3, "native-hook-trust");
120494
- const st = lstatSync44(parent, { throwIfNoEntry: false });
120723
+ const st = lstatSync45(parent, { throwIfNoEntry: false });
120495
120724
  if (st) {
120496
120725
  need8(st.isDirectory() && !st.isSymbolicLink() && st.uid === process.getuid() && (st.mode & 511) === 448, "UNSAFE_JOURNAL");
120497
120726
  const priorJournals = readdirSync26(parent);
120498
120727
  need8(priorJournals.length < 1000, "JOURNAL_BOUND");
120499
120728
  for (const name of priorJournals) {
120500
120729
  need8(/^[a-f0-9-]{36}$/.test(name), "UNSAFE_JOURNAL");
120501
- need8(lstatSync44(join72(parent, name, "receipt.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_REQUIRED: inspect the incomplete private journal before applying again");
120730
+ need8(lstatSync45(join72(parent, name, "receipt.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_REQUIRED: inspect the incomplete private journal before applying again");
120502
120731
  }
120503
120732
  }
120504
120733
  if (!options.apply || !planned.length)
120505
120734
  return baseReceipt;
120506
120735
  if (!st)
120507
120736
  mkdirSync30(parent, { mode: 448 });
120508
- journal = join72(parent, randomUUID12());
120737
+ journal = join72(parent, randomUUID13());
120509
120738
  mkdirSync30(journal, { mode: 448 });
120510
120739
  save(join72(journal, "config.before.toml"), configFile.bytes);
120511
120740
  save(join72(journal, "hooks.before.json"), hooksFile.bytes);
120512
120741
  save(join72(journal, "policy.before.json"), policyFile.bytes);
120513
120742
  save(join72(journal, "intent.json"), json2({ ...digestInput, planDigest, hooks: planned, nativeHooks: discovered.map(safeNativeHook), ...codexAdmissionReceipt(admission) }));
120514
- need8(isDeepStrictEqual19(admit(await list2()), admitted), "NATIVE_DISCOVERY_CHANGED");
120743
+ need8(isDeepStrictEqual20(admit(await list2()), admitted), "NATIVE_DISCOVERY_CHANGED");
120515
120744
  checkInputs();
120516
120745
  let result2;
120517
120746
  try {
@@ -120525,7 +120754,7 @@ async function enrollCodexNativeHooksUnlocked(options, connect, admission) {
120525
120754
  expectedConfig.hooks.state ??= {};
120526
120755
  for (const h of planned)
120527
120756
  expectedConfig.hooks.state[h.key] = { ...expectedConfig.hooks.state[h.key], enabled: true, trusted_hash: h.currentHash };
120528
- need8(isDeepStrictEqual19(structure3(after2.text), expectedConfig) && codexTrustTextWitness(after2.text, keys4) === preservationText, "PRESERVATION_FAILED");
120757
+ need8(isDeepStrictEqual20(structure3(after2.text), expectedConfig) && codexTrustTextWitness(after2.text, keys4) === preservationText, "PRESERVATION_FAILED");
120529
120758
  const savedConfig = snapshot(join72(journal, "config.before.toml"), true);
120530
120759
  need8(savedConfig.sha256 === configFile.sha256, "JOURNAL_CHANGED");
120531
120760
  const discoveryTransition = binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, savedConfig, after2, planned) : undefined;
@@ -120533,8 +120762,8 @@ async function enrollCodexNativeHooksUnlocked(options, connect, admission) {
120533
120762
  unchanged2(hooksFile);
120534
120763
  assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: discoveryTransition });
120535
120764
  const current = await list2(), confirmed = admit(current);
120536
- need8(confirmed.every((h) => h.enabled && h.trustStatus === "trusted") && isDeepStrictEqual19(confirmed.map((h) => [h.key, h.currentHash]), admitted.map((h) => [h.key, h.currentHash])), "NATIVE_NOT_ELIGIBLE");
120537
- need8(isDeepStrictEqual19(current.filter((h) => !keys4.includes(h.key)), discovered.filter((h) => !keys4.includes(h.key))), "UNRELATED_HOOK_CHANGED");
120765
+ need8(confirmed.every((h) => h.enabled && h.trustStatus === "trusted") && isDeepStrictEqual20(confirmed.map((h) => [h.key, h.currentHash]), admitted.map((h) => [h.key, h.currentHash])), "NATIVE_NOT_ELIGIBLE");
120766
+ need8(isDeepStrictEqual20(current.filter((h) => !keys4.includes(h.key)), discovered.filter((h) => !keys4.includes(h.key))), "UNRELATED_HOOK_CHANGED");
120538
120767
  unchanged2(after2);
120539
120768
  unchanged2(savedConfig);
120540
120769
  unchanged2(hooksFile);
@@ -120667,9 +120896,9 @@ var init_codex_native_trust = __esm(() => {
120667
120896
 
120668
120897
  // src/lib/claude-prospective-review.ts
120669
120898
  import { createHash as createHash45 } from "crypto";
120670
- import { lstatSync as lstatSync45, readFileSync as readFileSync48, readdirSync as readdirSync27, realpathSync as realpathSync22 } from "fs";
120671
- import { basename as basename23, dirname as dirname46, isAbsolute as isAbsolute42, join as join74, relative as relative15, resolve as resolve42, sep as sep21 } from "path";
120672
- import { isDeepStrictEqual as isDeepStrictEqual20 } from "util";
120899
+ import { lstatSync as lstatSync46, readFileSync as readFileSync48, readdirSync as readdirSync27, realpathSync as realpathSync22 } from "fs";
120900
+ import { basename as basename23, dirname as dirname46, isAbsolute as isAbsolute44, join as join74, relative as relative15, resolve as resolve42, sep as sep21 } from "path";
120901
+ import { isDeepStrictEqual as isDeepStrictEqual21 } from "util";
120673
120902
  function hashClaudeDiscoveryBinding(binding) {
120674
120903
  return sha8(JSON.stringify(binding));
120675
120904
  }
@@ -120719,7 +120948,7 @@ function keys4(value, expected, name) {
120719
120948
  refuse8(`${name} has an unsupported shape`);
120720
120949
  }
120721
120950
  function abs(path, name) {
120722
- if (typeof path !== "string" || !path || path.length > 4096 || /[\x00-\x1f\x7f]/.test(path) || !isAbsolute42(path) || resolve42(path) !== path)
120951
+ if (typeof path !== "string" || !path || path.length > 4096 || /[\x00-\x1f\x7f]/.test(path) || !isAbsolute44(path) || resolve42(path) !== path)
120723
120952
  refuse8(`${name} must be a normalized absolute path`);
120724
120953
  }
120725
120954
  function validUtcTimestamp(value) {
@@ -120728,23 +120957,23 @@ function validUtcTimestamp(value) {
120728
120957
  function safeFile(path, name) {
120729
120958
  abs(path, name);
120730
120959
  for (let at2 = dirname46(path);; at2 = dirname46(at2)) {
120731
- const stat4 = lstatSync45(at2, { throwIfNoEntry: false });
120960
+ const stat4 = lstatSync46(at2, { throwIfNoEntry: false });
120732
120961
  if (!stat4?.isDirectory() || stat4.isSymbolicLink())
120733
120962
  refuse8(`${name} traverses a symlink or non-directory`);
120734
120963
  if (at2 === dirname46(at2))
120735
120964
  break;
120736
120965
  }
120737
- const stat3 = lstatSync45(path, { throwIfNoEntry: false });
120966
+ const stat3 = lstatSync46(path, { throwIfNoEntry: false });
120738
120967
  if (!stat3?.isFile() || stat3.isSymbolicLink() || stat3.size > MAX_CANDIDATE_BYTES)
120739
120968
  refuse8(`${name} is not a bounded regular file`);
120740
120969
  return readFileSync48(path);
120741
120970
  }
120742
120971
  function canonicalDir(path, name) {
120743
120972
  abs(path, name);
120744
- if (realpathSync22(path) !== path || !lstatSync45(path).isDirectory())
120973
+ if (realpathSync22(path) !== path || !lstatSync46(path).isDirectory())
120745
120974
  refuse8(`${name} is not a canonical directory`);
120746
120975
  for (let at2 = path;; at2 = dirname46(at2)) {
120747
- const stat3 = lstatSync45(at2);
120976
+ const stat3 = lstatSync46(at2);
120748
120977
  if (!stat3.isDirectory() || stat3.isSymbolicLink())
120749
120978
  refuse8(`${name} traverses a symlink`);
120750
120979
  if (at2 === dirname46(at2))
@@ -120756,7 +120985,7 @@ function captureClaudeProspectiveCandidateClosure(root2) {
120756
120985
  const entries = [];
120757
120986
  let bytes = 0;
120758
120987
  const walk2 = (directory3) => {
120759
- const beforeDirectory = lstatSync45(directory3);
120988
+ const beforeDirectory = lstatSync46(directory3);
120760
120989
  const names = readdirSync27(directory3).sort();
120761
120990
  if (new Set(names).size !== names.length)
120762
120991
  refuse8("candidate contains ambiguous directory entries");
@@ -120766,7 +120995,7 @@ function captureClaudeProspectiveCandidateClosure(root2) {
120766
120995
  const path = join74(directory3, name), rel = relative15(root2, path).split(sep21).join("/");
120767
120996
  if (entries.length >= MAX_CANDIDATE_FILES)
120768
120997
  refuse8("candidate closure exceeds its member limit");
120769
- const stat3 = lstatSync45(path);
120998
+ const stat3 = lstatSync46(path);
120770
120999
  if (stat3.isSymbolicLink())
120771
121000
  refuse8("candidate closure contains a symlink");
120772
121001
  if (stat3.isDirectory()) {
@@ -120776,14 +121005,14 @@ function captureClaudeProspectiveCandidateClosure(root2) {
120776
121005
  bytes += stat3.size;
120777
121006
  if (bytes > MAX_CANDIDATE_BYTES)
120778
121007
  refuse8("candidate closure exceeds its byte limit");
120779
- const content = safeFile(path, "candidate member"), after2 = lstatSync45(path);
121008
+ const content = safeFile(path, "candidate member"), after2 = lstatSync46(path);
120780
121009
  if (!after2.isFile() || after2.dev !== stat3.dev || after2.ino !== stat3.ino || after2.size !== stat3.size || after2.mtimeMs !== stat3.mtimeMs || after2.ctimeMs !== stat3.ctimeMs)
120781
121010
  refuse8("candidate member changed while being read");
120782
121011
  entries.push([rel, "file", sha8(content)]);
120783
121012
  } else
120784
121013
  refuse8("candidate closure contains a special file");
120785
121014
  }
120786
- const afterDirectory = lstatSync45(directory3);
121015
+ const afterDirectory = lstatSync46(directory3);
120787
121016
  if (!afterDirectory.isDirectory() || afterDirectory.dev !== beforeDirectory.dev || afterDirectory.ino !== beforeDirectory.ino || afterDirectory.mtimeMs !== beforeDirectory.mtimeMs || afterDirectory.ctimeMs !== beforeDirectory.ctimeMs)
120788
121017
  refuse8("candidate directory changed while being read");
120789
121018
  };
@@ -120807,11 +121036,11 @@ function captureClaudeInstallerCandidate(root2, policyPath) {
120807
121036
  if (names.has(row2.name))
120808
121037
  refuse8("candidate catalog repeats a plugin name");
120809
121038
  names.add(row2.name);
120810
- if (typeof row2.source !== "string" || isAbsolute42(row2.source) || /[\\\x00-\x1f\x7f]/.test(row2.source))
121039
+ if (typeof row2.source !== "string" || isAbsolute44(row2.source) || /[\\\x00-\x1f\x7f]/.test(row2.source))
120811
121040
  refuse8("candidate catalog plugin source is invalid");
120812
121041
  const pluginRoot = resolve42(root2, row2.source);
120813
121042
  const relativeRoot = relative15(root2, pluginRoot);
120814
- if (!relativeRoot || relativeRoot === "." || relativeRoot === ".." || relativeRoot.startsWith(`..${sep21}`) || isAbsolute42(relativeRoot))
121043
+ if (!relativeRoot || relativeRoot === "." || relativeRoot === ".." || relativeRoot.startsWith(`..${sep21}`) || isAbsolute44(relativeRoot))
120815
121044
  refuse8("candidate plugin source escapes the candidate root");
120816
121045
  const path = join74(pluginRoot, ".claude-plugin/plugin.json");
120817
121046
  return { plugin: row2.name, ...captureClaudePluginManifestFile(path) };
@@ -120830,7 +121059,7 @@ function captureClaudeInstallerCandidate(root2, policyPath) {
120830
121059
  }
120831
121060
  function readWitness(path, expected, name) {
120832
121061
  abs(path, `${name} path`);
120833
- const stat3 = lstatSync45(path, { throwIfNoEntry: false });
121062
+ const stat3 = lstatSync46(path, { throwIfNoEntry: false });
120834
121063
  if (expected === null) {
120835
121064
  if (stat3)
120836
121065
  refuse8(`${name} was absent at review but is now present`);
@@ -120882,7 +121111,7 @@ function unreviewedProjectSettingsRefusal(path, expected, name) {
120882
121111
  return null;
120883
121112
  }
120884
121113
  function jsonFile(path, name) {
120885
- const stat3 = lstatSync45(path, { throwIfNoEntry: false });
121114
+ const stat3 = lstatSync46(path, { throwIfNoEntry: false });
120886
121115
  if (!stat3)
120887
121116
  return null;
120888
121117
  let value;
@@ -120914,7 +121143,7 @@ function assertNoUnprojectedSkillPayload(root2, catalogPath, marketplace, plugin
120914
121143
  const walk2 = (directory3) => {
120915
121144
  for (const name of readdirSync27(directory3).sort()) {
120916
121145
  const path = join74(directory3, name), rel = relative15(root2, path).split(sep21).join("/");
120917
- const stat3 = lstatSync45(path);
121146
+ const stat3 = lstatSync46(path);
120918
121147
  if (stat3.isDirectory())
120919
121148
  walk2(path);
120920
121149
  else if (stat3.isFile()) {
@@ -120980,7 +121209,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
120980
121209
  refuse8("CLAUDE_CODE_PLUGIN_CACHE_DIR overrides are unsupported by this prospective schema; bind and review the actual cache root first");
120981
121210
  if (request2.native.pluginRoot !== pluginRoot)
120982
121211
  refuse8("Claude plugin root differs from the supported standard plugins directory; Cowork and custom cache roots require a separately bound schema");
120983
- const pluginRootStat = lstatSync45(pluginRoot, { throwIfNoEntry: false });
121212
+ const pluginRootStat = lstatSync46(pluginRoot, { throwIfNoEntry: false });
120984
121213
  if (pluginRootStat && (!pluginRootStat.isDirectory() || pluginRootStat.isSymbolicLink()))
120985
121214
  refuse8("Claude plugin root is not a regular directory");
120986
121215
  keys4(request2.candidate, ["marketplace", "root", "catalogPath", "catalogSha256", "closureSha256", "plugins", ...hasOwn2(request2.candidate, "releaseManifest") ? ["releaseManifest"] : [], ...hasOwn2(request2.candidate, "functionHooksEnv") ? ["functionHooksEnv"] : [], ...hasOwn2(request2.candidate, "settingsMarketplaceSource") ? ["settingsMarketplaceSource"] : []], "candidate");
@@ -120992,7 +121221,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
120992
121221
  refuse8("candidate must select between one and 32 plugins from one marketplace");
120993
121222
  if (candidate2.functionHooksEnv !== undefined && candidate2.functionHooksEnv !== "1")
120994
121223
  refuse8("function-hook environment mutation only supports the explicit value 1");
120995
- const settingsMarketplaceWriterVersions = ["2.1.276", "2.1.278", "2.1.282", "2.1.287", "2.1.293", "2.1.296", "2.1.299", "2.1.300"];
121224
+ const settingsMarketplaceWriterVersions = ["2.1.276", "2.1.278", "2.1.282", "2.1.287", "2.1.293", "2.1.296", "2.1.299", "2.1.300", "2.1.301", "2.1.302"];
120996
121225
  const nativeVersion = request2.native.executable.version;
120997
121226
  const measuredSettingsWriter = settingsMarketplaceWriterVersions.some((version2) => nativeVersion === version2 || nativeVersion === `${version2} (Claude Code)`);
120998
121227
  if (hasOwn2(candidate2, "settingsMarketplaceSource") && (candidate2.settingsMarketplaceSource !== "directory" || request2.scope.kind !== "user" || !measuredSettingsWriter))
@@ -121046,7 +121275,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
121046
121275
  refuse8("plugin manifest must be under a plugin root inside the frozen marketplace closure");
121047
121276
  const pluginRoot2 = dirname46(dirname46(selected.manifestPath));
121048
121277
  const relativePluginRoot = relative15(candidate2.root, pluginRoot2);
121049
- if (!relativePluginRoot || relativePluginRoot === "." || relativePluginRoot === ".." || relativePluginRoot.startsWith(`..${sep21}`) || isAbsolute42(relativePluginRoot))
121278
+ if (!relativePluginRoot || relativePluginRoot === "." || relativePluginRoot === ".." || relativePluginRoot.startsWith(`..${sep21}`) || isAbsolute44(relativePluginRoot))
121050
121279
  refuse8("plugin root must be a child of the frozen marketplace root");
121051
121280
  canonicalDir(pluginRoot2, "candidate plugin root");
121052
121281
  if (!SHA256.test(selected.manifestSha256))
@@ -121080,7 +121309,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
121080
121309
  const sourcePath = selectedEntry.source;
121081
121310
  const sourceRelativePath = relative15(candidate2.root, pluginRoot2).split(sep21).join("/");
121082
121311
  const expectedSourcePath = sourceRelativePath === "." ? "./" : `./${sourceRelativePath}`;
121083
- if (typeof sourcePath !== "string" || isAbsolute42(sourcePath) || sourcePath !== expectedSourcePath || resolve42(dirname46(dirname46(candidate2.catalogPath)), sourcePath) !== pluginRoot2)
121312
+ if (typeof sourcePath !== "string" || isAbsolute44(sourcePath) || sourcePath !== expectedSourcePath || resolve42(dirname46(dirname46(candidate2.catalogPath)), sourcePath) !== pluginRoot2)
121084
121313
  refuse8("marketplace source does not resolve to the frozen plugin closure; external source mapping is not supported by this schema");
121085
121314
  const entry = captureClaudeMarketplaceEntry(candidate2.catalogPath, candidate2.marketplace, selected.plugin);
121086
121315
  if (entry.sha256.length !== 64)
@@ -121141,7 +121370,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
121141
121370
  refuse8("Skills discovery preimage differs from its reviewed binding");
121142
121371
  assertProjectDiscovery("claude", [request2.scope.projectPath], request2.native.home, canonical9, binding);
121143
121372
  const stored = snapshot2.value.bridge?.discovery?.claude;
121144
- if (!stored || !isDeepStrictEqual20(stored, binding) || snapshot2.value.bridge?.home !== request2.native.home)
121373
+ if (!stored || !isDeepStrictEqual21(stored, binding) || snapshot2.value.bridge?.home !== request2.native.home)
121145
121374
  refuse8("Skills policy does not bind the reviewed current Claude discovery");
121146
121375
  assertExemptUnchanged();
121147
121376
  const delta = request2.delta;
@@ -121299,7 +121528,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
121299
121528
  refuse8("current known marketplace autoUpdate is not a boolean");
121300
121529
  }
121301
121530
  }
121302
- if (!isDeepStrictEqual20(delta.settingsAfter, settingsAfter))
121531
+ if (!isDeepStrictEqual21(delta.settingsAfter, settingsAfter))
121303
121532
  refuse8("complete settings document differs from the exact selected plugin/options/environment/marketplace operations");
121304
121533
  const marketplaceRowBefore = marketplaces?.[candidate2.marketplace];
121305
121534
  if (marketplaceRowBefore !== undefined && !object11(marketplaceRowBefore))
@@ -121311,7 +121540,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
121311
121540
  if (marketplaceRowBefore?.lastUpdated !== undefined && !validUtcTimestamp(marketplaceRowBefore.lastUpdated))
121312
121541
  refuse8("current marketplace update timestamp is invalid");
121313
121542
  const targetMarketplaceLocation = candidate2.root;
121314
- const sameMarketplaceSource = isDeepStrictEqual20(marketplaceRowBefore?.source, { source: "directory", path: candidate2.root }) && marketplaceRowBefore?.installLocation === targetMarketplaceLocation;
121543
+ const sameMarketplaceSource = isDeepStrictEqual21(marketplaceRowBefore?.source, { source: "directory", path: candidate2.root }) && marketplaceRowBefore?.installLocation === targetMarketplaceLocation;
121315
121544
  const afterMarketplace = {
121316
121545
  source: { source: "directory", path: candidate2.root },
121317
121546
  installLocation: targetMarketplaceLocation,
@@ -121320,7 +121549,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
121320
121549
  };
121321
121550
  const marketplacesAfter = marketplaces ? structuredClone(marketplaces) : {};
121322
121551
  marketplacesAfter[candidate2.marketplace] = afterMarketplace;
121323
- if (!isDeepStrictEqual20(delta.knownMarketplacesAfter, marketplacesAfter))
121552
+ if (!isDeepStrictEqual21(delta.knownMarketplacesAfter, marketplacesAfter))
121324
121553
  refuse8("complete marketplace document differs from the exact selected-directory marketplace operation");
121325
121554
  const installedAfter = registrations ? structuredClone(registrations) : { version: 2, plugins: {} };
121326
121555
  if (installedAfter.plugins === undefined)
@@ -121340,7 +121569,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
121340
121569
  nextRows[index] = targetRegistration;
121341
121570
  installedAfter.plugins[pluginId2] = nextRows;
121342
121571
  }
121343
- if (!isDeepStrictEqual20(delta.installedPluginsAfter, installedAfter))
121572
+ if (!isDeepStrictEqual21(delta.installedPluginsAfter, installedAfter))
121344
121573
  refuse8("complete installed plugin document changes an unrelated registration or has target rows not derived from every selected candidate");
121345
121574
  assertExemptUnchanged();
121346
121575
  const semanticDocumentsSha256 = sha8(canonicalJson3({ settings: settingsAfter, knownMarketplaces: marketplacesAfter, installedPlugins: installedAfter }));
@@ -121419,7 +121648,7 @@ var init_claude_prospective_review = __esm(() => {
121419
121648
 
121420
121649
  // src/lib/self-spawn.ts
121421
121650
  import { realpathSync as realpathSync23 } from "fs";
121422
- import { dirname as dirname47, isAbsolute as isAbsolute43, sep as sep22 } from "path";
121651
+ import { dirname as dirname47, isAbsolute as isAbsolute45, sep as sep22 } from "path";
121423
121652
  function selfSpawnRoot(entry) {
121424
121653
  const index = entry.indexOf(INSTALLED_PACKAGE);
121425
121654
  const root2 = index > 0 ? entry.slice(0, index) : dirname47(entry);
@@ -121432,7 +121661,7 @@ function selfSpawnRoot(entry) {
121432
121661
  function selfSpawnCommand(args2, options = {}) {
121433
121662
  const runtime = options.runtime ?? process.execPath;
121434
121663
  const entry = options.entry ?? process.argv[1];
121435
- if (!runtime || !isAbsolute43(runtime) || !entry || !isAbsolute43(entry))
121664
+ if (!runtime || !isAbsolute45(runtime) || !entry || !isAbsolute45(entry))
121436
121665
  throw new Error("SKILLS_SELF_SPAWN_ENTRY_UNRESOLVED");
121437
121666
  const root2 = selfSpawnRoot(entry);
121438
121667
  const env3 = pinnedLauncherEnvironment(options.env ?? process.env);
@@ -121538,8 +121767,8 @@ var init_claude_installer_binding = __esm(() => {
121538
121767
  });
121539
121768
 
121540
121769
  // src/cli/commands/claude-installer-capture.ts
121541
- import { closeSync as closeSync30, constants as constants29, fstatSync as fstatSync30, lstatSync as lstatSync46, openSync as openSync30, readSync as readSync22 } from "fs";
121542
- import { isAbsolute as isAbsolute44, resolve as resolve43 } from "path";
121770
+ import { closeSync as closeSync30, constants as constants29, fstatSync as fstatSync30, lstatSync as lstatSync47, openSync as openSync30, readSync as readSync22 } from "fs";
121771
+ import { isAbsolute as isAbsolute46, resolve as resolve43 } from "path";
121543
121772
  function need11(condition, code2) {
121544
121773
  if (!condition)
121545
121774
  throw new CaptureRefusal(code2);
@@ -121553,11 +121782,11 @@ function exactKeys5(value, expected, operation) {
121553
121782
  }
121554
121783
  }
121555
121784
  function canonicalPath2(value) {
121556
- need11(typeof value === "string" && isAbsolute44(value) && resolve43(value) === value && !/[\x00-\x1f\x7f]/.test(value), "INVALID_PATH: path fields must be normalized absolute paths without control characters");
121785
+ need11(typeof value === "string" && isAbsolute46(value) && resolve43(value) === value && !/[\x00-\x1f\x7f]/.test(value), "INVALID_PATH: path fields must be normalized absolute paths without control characters");
121557
121786
  }
121558
121787
  function readRequest2(path) {
121559
121788
  canonicalPath2(path);
121560
- const before2 = lstatSync46(path, { throwIfNoEntry: false });
121789
+ const before2 = lstatSync47(path, { throwIfNoEntry: false });
121561
121790
  if (!before2?.isFile() || before2.isSymbolicLink() || before2.size > MAX_REQUEST_BYTES)
121562
121791
  throw new CaptureRefusal("INVALID_REQUEST_FILE: --request must name a regular non-symlink JSON file no larger than 64 KiB");
121563
121792
  const fd = openSync30(path, constants29.O_RDONLY | (constants29.O_NOFOLLOW ?? 0) | constants29.O_NONBLOCK);
@@ -121572,7 +121801,7 @@ function readRequest2(path) {
121572
121801
  break;
121573
121802
  length += count;
121574
121803
  }
121575
- const after2 = fstatSync30(fd), current = lstatSync46(path);
121804
+ const after2 = fstatSync30(fd), current = lstatSync47(path);
121576
121805
  need11(length <= MAX_REQUEST_BYTES && length === opened.size && after2.size === opened.size && after2.mtimeMs === opened.mtimeMs && after2.ctimeMs === opened.ctimeMs && current.dev === opened.dev && current.ino === opened.ino && current.mtimeMs === opened.mtimeMs && current.ctimeMs === opened.ctimeMs, "INVALID_REQUEST_FILE: --request must remain unchanged while read");
121577
121806
  try {
121578
121807
  return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, length)));
@@ -121724,10 +121953,10 @@ var exports_agent_integration = {};
121724
121953
  __export(exports_agent_integration, {
121725
121954
  registerAgentIntegration: () => registerAgentIntegration
121726
121955
  });
121727
- import { existsSync as existsSync36, lstatSync as lstatSync47, readFileSync as readFileSync49, readSync as readSync23, writeFileSync as writeFileSync27 } from "fs";
121956
+ import { existsSync as existsSync36, lstatSync as lstatSync48, readFileSync as readFileSync49, readSync as readSync23, writeFileSync as writeFileSync27 } from "fs";
121728
121957
  import { createHash as createHash47 } from "crypto";
121729
121958
  import { homedir as homedir14 } from "os";
121730
- import { basename as basename24, isAbsolute as isAbsolute45, resolve as resolve44 } from "path";
121959
+ import { basename as basename24, isAbsolute as isAbsolute47, resolve as resolve44 } from "path";
121731
121960
  function pinnedHookProfile(input3, configuredProfile) {
121732
121961
  try {
121733
121962
  const parsed = parseSkillContextInput(JSON.stringify(input3));
@@ -121862,7 +122091,7 @@ function registerAgentIntegration(parent) {
121862
122091
  });
121863
122092
  hook.command("native-catalog").requiredOption("--cwd <path>", "Absolute project directory observed by native Codex skills/list").requiredOption("--output <file>", "New private file for the projected native catalog").option("--codex-command <path>", "Installed Codex executable used by the native client", "codex").option("--json", "Output bounded capture metadata as JSON", false).description("Capture a reviewed Codex native skill catalog for exact hook enrollment").action(async (options) => {
121864
122093
  try {
121865
- if (!isAbsolute45(options.cwd) || !isAbsolute45(options.output))
122094
+ if (!isAbsolute47(options.cwd) || !isAbsolute47(options.output))
121866
122095
  throw new Error("CODEX_NATIVE_SKILL_CATALOG_ABSOLUTE_PATH_REQUIRED");
121867
122096
  if (existsSync36(options.output))
121868
122097
  throw new Error("CODEX_NATIVE_SKILL_CATALOG_OUTPUT_EXISTS");
@@ -121886,7 +122115,7 @@ function registerAgentIntegration(parent) {
121886
122115
  throw new Error("CODEX_NATIVE_SKILL_CATALOG_OUTPUT_EXISTS");
121887
122116
  throw error61;
121888
122117
  }
121889
- const written = lstatSync47(options.output);
122118
+ const written = lstatSync48(options.output);
121890
122119
  if (!written.isFile() || written.isSymbolicLink() || (written.mode & 63) !== 0 || readFileSync49(options.output, "utf8") !== bytes)
121891
122120
  throw new Error("CODEX_NATIVE_SKILL_CATALOG_READBACK_FAILED");
121892
122121
  const receipt = {
@@ -121953,9 +122182,9 @@ function registerAgentIntegration(parent) {
121953
122182
  });
121954
122183
  hook.command("review-claude-candidate").requiredOption("--request <file>", "Frozen skills.claude-plugin-prospective-review/v1 JSON request").option("--json", "Return the validation-only receipt as JSON", false).description("Validate a prospective Claude plugin candidate and current preimages without changing native state; Harnesses must compare native and Skills paths against installed package-owned resolvers before trusting the receipt").action(async (options) => {
121955
122184
  try {
121956
- if (!isAbsolute45(options.request))
122185
+ if (!isAbsolute47(options.request))
121957
122186
  throw new Error("CLAUDE_CANDIDATE_REVIEW_REFUSED: --request must be an absolute path");
121958
- const stat3 = lstatSync47(options.request);
122187
+ const stat3 = lstatSync48(options.request);
121959
122188
  if (!stat3.isFile() || stat3.isSymbolicLink() || stat3.size > 1024 * 1024)
121960
122189
  throw new Error("CLAUDE_CANDIDATE_REVIEW_REFUSED: request must be a regular file no larger than 1 MiB");
121961
122190
  const requestBytes = readFileSync49(options.request);
@@ -122091,12 +122320,12 @@ function registerAgentIntegration(parent) {
122091
122320
  input3.hook_event_name = event;
122092
122321
  const projects = [process.cwd()];
122093
122322
  if (input3.cwd !== undefined) {
122094
- if (typeof input3.cwd !== "string" || !isAbsolute45(input3.cwd) || input3.cwd.includes("\x00"))
122323
+ if (typeof input3.cwd !== "string" || !isAbsolute47(input3.cwd) || input3.cwd.includes("\x00"))
122095
122324
  throw new Error("Invalid native hook working directory");
122096
122325
  projects.push(input3.cwd);
122097
122326
  }
122098
122327
  if (options.agent === "cursor") {
122099
- if (!Array.isArray(input3.workspace_roots) || input3.workspace_roots.length > 32 || input3.workspace_roots.some((path) => typeof path !== "string" || !isAbsolute45(path) || path.includes("\x00")))
122328
+ if (!Array.isArray(input3.workspace_roots) || input3.workspace_roots.length > 32 || input3.workspace_roots.some((path) => typeof path !== "string" || !isAbsolute47(path) || path.includes("\x00")))
122100
122329
  throw new Error("Invalid Cursor workspace roots");
122101
122330
  projects.push(...input3.workspace_roots);
122102
122331
  input3.cwd ??= input3.workspace_roots[0] ?? process.cwd();
@@ -122887,7 +123116,7 @@ import {
122887
123116
  mkdirSync as mkdirSync31,
122888
123117
  readdirSync as readdirSync28,
122889
123118
  readFileSync as readFileSync50,
122890
- statSync as statSync25,
123119
+ statSync as statSync26,
122891
123120
  writeFileSync as writeFileSync30
122892
123121
  } from "fs";
122893
123122
  import { dirname as dirname48, join as join76, resolve as resolve45, sep as sep23 } from "path";
@@ -122984,7 +123213,7 @@ function planStationHydration(stationId, repoRoot) {
122984
123213
  });
122985
123214
  continue;
122986
123215
  }
122987
- const info = statSync25(entry.fullPath);
123216
+ const info = statSync26(entry.fullPath);
122988
123217
  const manifestHash = manifestHashes.get(`${agent}${MANIFEST_HASH_KEY_SEP}${homeRelative}`) ?? null;
122989
123218
  let verified = false;
122990
123219
  if (manifestHash !== null) {
@@ -123241,10 +123470,10 @@ var init_hydrate = __esm(() => {
123241
123470
  });
123242
123471
 
123243
123472
  // src/lib/prepare-skill.ts
123244
- import { createHash as createHash49, randomUUID as randomUUID13 } from "crypto";
123245
- import { chmodSync as chmodSync5, existsSync as existsSync37, lstatSync as lstatSync48, mkdirSync as mkdirSync32, mkdtempSync as mkdtempSync7, readFileSync as readFileSync51, readdirSync as readdirSync29, renameSync as renameSync15, rmSync as rmSync10, writeFileSync as writeFileSync31 } from "fs";
123473
+ import { createHash as createHash49, randomUUID as randomUUID14 } from "crypto";
123474
+ import { chmodSync as chmodSync5, existsSync as existsSync37, lstatSync as lstatSync49, mkdirSync as mkdirSync32, mkdtempSync as mkdtempSync7, readFileSync as readFileSync51, readdirSync as readdirSync29, renameSync as renameSync16, rmSync as rmSync10, writeFileSync as writeFileSync31 } from "fs";
123246
123475
  import { tmpdir as tmpdir2 } from "os";
123247
- import { dirname as dirname49, isAbsolute as isAbsolute46, join as join77, relative as relative16, resolve as resolve46, sep as sep24 } from "path";
123476
+ import { dirname as dirname49, isAbsolute as isAbsolute48, join as join77, relative as relative16, resolve as resolve46, sep as sep24 } from "path";
123248
123477
  function prepareSkill(name, options) {
123249
123478
  const normalized2 = normalizePortableSkillName(name);
123250
123479
  if (!new RegExp(SEMVER_PATTERN).test(options.version))
@@ -123316,11 +123545,11 @@ ${validation.issues.map((issue2) => `${issue2.code}: ${issue2.message}`).join(`
123316
123545
  if (snapshot2(path).identity !== before2.identity)
123317
123546
  throw new Error("Skill changed during preparation; review the draft and run prepare again.");
123318
123547
  if (changed3 && !options.dryRun) {
123319
- const temporary = join77(path, `.skill-prepare-${randomUUID13()}.tmp`);
123548
+ const temporary = join77(path, `.skill-prepare-${randomUUID14()}.tmp`);
123320
123549
  try {
123321
123550
  writeFileSync31(temporary, candidateBytes, { flag: "wx", mode: manifestFile.mode });
123322
123551
  chmodSync5(temporary, manifestFile.mode);
123323
- renameSync15(temporary, join77(path, "skill.json"));
123552
+ renameSync16(temporary, join77(path, "skill.json"));
123324
123553
  } finally {
123325
123554
  rmSync10(temporary, { force: true });
123326
123555
  }
@@ -123351,7 +123580,7 @@ function validateRuntimeEntrypoint(candidate2, root2) {
123351
123580
  if (typeof entry !== "string")
123352
123581
  return;
123353
123582
  const target = resolve46(root2, entry), rel = relative16(root2, target);
123354
- if (isAbsolute46(entry) || /^[a-zA-Z]:/.test(entry) || entry.includes("\\") || !rel || rel === ".." || rel.startsWith(`..${sep24}`) || isAbsolute46(rel) || !existsSync37(target) || !lstatSync48(target).isFile()) {
123583
+ if (isAbsolute48(entry) || /^[a-zA-Z]:/.test(entry) || entry.includes("\\") || !rel || rel === ".." || rel.startsWith(`..${sep24}`) || isAbsolute48(rel) || !existsSync37(target) || !lstatSync49(target).isFile()) {
123355
123584
  throw new Error("Executable runtime.entrypoint must name an existing regular file inside the skill directory.");
123356
123585
  }
123357
123586
  }
@@ -123436,7 +123665,7 @@ function compareVersions(left, right) {
123436
123665
  return 0;
123437
123666
  }
123438
123667
  function snapshot2(root2) {
123439
- const rootStat = lstatSync48(root2);
123668
+ const rootStat = lstatSync49(root2);
123440
123669
  if (rootStat.isSymbolicLink() || !rootStat.isDirectory())
123441
123670
  throw new Error("Skill root must be a real directory, not a symlink.");
123442
123671
  const files = [], directories = [];
@@ -123449,7 +123678,7 @@ function snapshot2(root2) {
123449
123678
  const path = relative17 ? `${relative17}/${name}` : name;
123450
123679
  if (++count > 20000)
123451
123680
  throw new Error("Skill exceeds the preparation entry limit (20000).");
123452
- const absolute = join77(root2, path), stat3 = lstatSync48(absolute);
123681
+ const absolute = join77(root2, path), stat3 = lstatSync49(absolute);
123453
123682
  if (stat3.isSymbolicLink())
123454
123683
  throw new Error(`Skill contains a symlink: ${path}. No files were changed.`);
123455
123684
  if (stat3.isDirectory() && name === "node_modules")
@@ -123942,8 +124171,8 @@ var init_registry_sync = __esm(() => {
123942
124171
  });
123943
124172
 
123944
124173
  // src/lib/review-export.ts
123945
- import { constants as constants32, closeSync as closeSync33, existsSync as existsSync38, fstatSync as fstatSync33, fsyncSync as fsyncSync10, lstatSync as lstatSync49, openSync as openSync33, realpathSync as realpathSync24, statSync as statSync26, writeFileSync as writeFileSync33 } from "fs";
123946
- import { basename as basename25, dirname as dirname51, isAbsolute as isAbsolute47, join as join78, parse as parse13, resolve as resolve47, sep as sep25 } from "path";
124174
+ import { constants as constants32, closeSync as closeSync33, existsSync as existsSync38, fstatSync as fstatSync33, fsyncSync as fsyncSync10, lstatSync as lstatSync50, openSync as openSync33, realpathSync as realpathSync24, statSync as statSync27, writeFileSync as writeFileSync33 } from "fs";
124175
+ import { basename as basename25, dirname as dirname51, isAbsolute as isAbsolute49, join as join78, parse as parse13, resolve as resolve47, sep as sep25 } from "path";
123947
124176
  function exactVersion(spec) {
123948
124177
  const at2 = spec.indexOf("@");
123949
124178
  const slug2 = spec.slice(0, at2);
@@ -123954,14 +124183,14 @@ function exactVersion(spec) {
123954
124183
  return { slug: slug2, version: version2 };
123955
124184
  }
123956
124185
  function assertPrivateDestination(output2) {
123957
- if (!isAbsolute47(output2) || resolve47(output2) !== output2 || !basename25(output2).endsWith(".tar.gz")) {
124186
+ if (!isAbsolute49(output2) || resolve47(output2) !== output2 || !basename25(output2).endsWith(".tar.gz")) {
123958
124187
  throw new Error("Review output must be an absolute, normalized .tar.gz path.");
123959
124188
  }
123960
124189
  const parent = dirname51(output2);
123961
- if (realpathSync24(parent) !== parent || lstatSync49(parent).isSymbolicLink()) {
124190
+ if (realpathSync24(parent) !== parent || lstatSync50(parent).isSymbolicLink()) {
123962
124191
  throw new Error("Review output parent must be a real directory, not a symlink.");
123963
124192
  }
123964
- const parentStat = statSync26(parent);
124193
+ const parentStat = statSync27(parent);
123965
124194
  if (!parentStat.isDirectory() || (parentStat.mode & 63) !== 0 || process.getuid && parentStat.uid !== process.getuid()) {
123966
124195
  throw new Error("Review output parent must be an owner-only directory (mode 0700).");
123967
124196
  }
@@ -124549,17 +124778,20 @@ __export(exports_private_publications, {
124549
124778
  registerPrivatePublications: () => registerPrivatePublications
124550
124779
  });
124551
124780
  import { resolve as resolve48 } from "path";
124552
- function verifyOptions(options, action) {
124781
+ function verifySessionOptions(options) {
124553
124782
  if (options.userId === undefined !== (options.membershipId === undefined) || options.userId !== undefined && (!publicationUuid(options.userId) || !publicationUuid(options.membershipId)))
124554
124783
  throw new PrivatePublicationError("PUBLICATION_CONTEXT_REQUIRED", "Provide both observed --user-id and --membership-id UUIDs.");
124784
+ if (!options.codeStdin && (options.json || !process.stdin.isTTY || !process.stderr.isTTY))
124785
+ throw new PrivatePublicationError("PUBLICATION_CODE_REQUIRED", "Use --code-stdin with a fresh code for noninteractive publishing.");
124786
+ }
124787
+ function verifyOptions(options, action) {
124788
+ verifySessionOptions(options);
124555
124789
  if ((action === "publish" || action === "resume" || action === "cancel") && options.confirm !== true)
124556
124790
  throw new PrivatePublicationError("PUBLICATION_CONFIRM_REQUIRED", "Use --confirm to approve this publication action.");
124557
124791
  if (action === "publish" && (!publicationUuid(options.skillId) || Boolean(options.expectEmpty) === (options.expectedCurrentVersion !== undefined) || options.expectedCurrentVersion !== undefined && !publicationUuid(options.expectedCurrentVersion) || options.idempotencyKey !== undefined && !publicationUuid(options.idempotencyKey)))
124558
124792
  throw new PrivatePublicationError("INVALID_PUBLICATION_INPUT", "Provide --skill-id and exactly one of --expect-empty or --expected-current-version; optional --idempotency-key must be a UUID.");
124559
124793
  if (options.waitSeconds !== undefined && (!/^(?:0|[1-9]\d{0,2})$/.test(options.waitSeconds) || Number(options.waitSeconds) > 300))
124560
124794
  throw new PrivatePublicationError("INVALID_PUBLICATION_INPUT", "Use --wait-seconds from 0 to 300.");
124561
- if (!options.codeStdin && (options.json || !process.stdin.isTTY || !process.stderr.isTTY))
124562
- throw new PrivatePublicationError("PUBLICATION_CODE_REQUIRED", "Use --code-stdin with a fresh code for noninteractive publishing.");
124563
124795
  }
124564
124796
  function print2(result2, json3) {
124565
124797
  if (json3)
@@ -124573,7 +124805,39 @@ function print2(result2, json3) {
124573
124805
  process.exitCode = 2;
124574
124806
  }
124575
124807
  function registerPrivatePublications(parent) {
124576
- const group = parent.command("publication").description("Publish and reconcile private source versions on a compatible hosted server; execution is separate");
124808
+ const group = parent.command("publication").description("Create private skills, publish and reconcile source versions on a compatible hosted server; execution is separate");
124809
+ group.command("create").allowExcessArguments(false).description("Create a private or team skill using fresh session verification (requires Pro)").argument("<slug>", "Lowercase kebab-case skill slug").requiredOption("--display-name <name>", "Skill display name").option("--description <text>", "Skill description", "").option("--visibility <visibility>", "private or team", "private").requiredOption("--email <email>", "Account email for fresh interactive verification").option("--user-id <uuid>", "Observed account UUID (required without an enrolled named profile)").option("--membership-id <uuid>", "Observed workspace membership UUID").option("--code-stdin", "Read a fresh six-digit verification code from stdin").option("--confirm", "Explicitly approve skill creation").option("--json", "Output validated skill identifiers without credentials or server free text").action(async (slug2, options) => {
124810
+ try {
124811
+ const body = checkedPrivateSkillCreate({ slug: slug2, displayName: options.displayName, description: options.description, visibility: options.visibility, confirm: options.confirm });
124812
+ verifySessionOptions(options);
124813
+ const context2 = options.userId ? { userId: options.userId, membershipId: options.membershipId } : undefined;
124814
+ const pending = preparePrivatePublicationSession(context2);
124815
+ let code2;
124816
+ if (options.codeStdin)
124817
+ code2 = await readCode();
124818
+ else {
124819
+ await new RemoteSkillsAuthClient(pending.origin).requestCode(options.email);
124820
+ code2 = await promptCode();
124821
+ }
124822
+ if (code2 === null)
124823
+ return;
124824
+ const client2 = await pending.verify(options.email, code2);
124825
+ const result2 = await client2.createSkill({ ...body, confirm: true });
124826
+ if (options.json)
124827
+ console.log(JSON.stringify(result2));
124828
+ else {
124829
+ console.log(`Created ${result2.visibility} skill: ${result2.slug}`);
124830
+ console.log(`Skill ID: ${result2.id}`);
124831
+ }
124832
+ } catch (error61) {
124833
+ const result2 = error61 instanceof PrivatePublicationError ? privatePublicationCustomerError(error61) : { error: "Unable to verify the selected account and workspace for skill creation. Check the server, membership and fresh code; no credential was saved.", code: "SKILL_CREATE_SESSION_UNAVAILABLE", uncertain: false };
124834
+ if (options.json)
124835
+ console.log(JSON.stringify(result2));
124836
+ else
124837
+ console.error(result2.error);
124838
+ process.exitCode = 1;
124839
+ }
124840
+ });
124577
124841
  const publishCommand = group.command("publish").allowExcessArguments(false).description("Publish private source with explicit current-version comparison").requiredOption("--recovery-dir <directory>", "New recovery directory for publish; existing directory for other actions").requiredOption("--email <email>", "Account email for fresh interactive verification").option("--user-id <uuid>", "Observed account UUID (required without an enrolled named profile)").option("--membership-id <uuid>", "Observed workspace membership UUID").option("--code-stdin", "Read a fresh six-digit verification code from stdin").option("--json", "Output a safe result without session credentials or upload URLs").option("--confirm", "Explicitly approve this action").argument("<directory>", "Validated local skill directory").requiredOption("--skill-id <uuid>", "Existing private/team skill UUID").option("--expected-current-version <uuid>", "Compare against the observed current version UUID").option("--expect-empty", "Require the skill to have no current version").option("--idempotency-key <uuid>", "Stable intent key; generated and saved before begin when omitted").option("--wait-seconds <seconds>", "Bounded status wait from 0 to 300", "60");
124578
124842
  const statusCommand = group.command("status").allowExcessArguments(false).description("Inspect the exact saved publication").requiredOption("--recovery-dir <directory>", "New recovery directory for publish; existing directory for other actions").requiredOption("--email <email>", "Account email for fresh interactive verification").option("--user-id <uuid>", "Observed account UUID (required without an enrolled named profile)").option("--membership-id <uuid>", "Observed workspace membership UUID").option("--code-stdin", "Read a fresh six-digit verification code from stdin").option("--json", "Output a safe result without session credentials or upload URLs");
124579
124843
  const resumeCommand = group.command("resume").allowExcessArguments(false).description("Reconcile the saved intent without creating a replacement").requiredOption("--recovery-dir <directory>", "New recovery directory for publish; existing directory for other actions").requiredOption("--email <email>", "Account email for fresh interactive verification").option("--user-id <uuid>", "Observed account UUID (required without an enrolled named profile)").option("--membership-id <uuid>", "Observed workspace membership UUID").option("--code-stdin", "Read a fresh six-digit verification code from stdin").option("--json", "Output a safe result without session credentials or upload URLs").option("--confirm", "Explicitly approve this action").option("--wait-seconds <seconds>", "Bounded status wait from 0 to 300", "60");
@@ -124583,17 +124847,18 @@ function registerPrivatePublications(parent) {
124583
124847
  const options = action === "publish" ? args2[1] : args2[0];
124584
124848
  try {
124585
124849
  verifyOptions(options, action);
124850
+ const context2 = options.userId ? { userId: options.userId, membershipId: options.membershipId } : undefined;
124851
+ const pending = preparePrivatePublicationSession(context2);
124586
124852
  let code2;
124587
124853
  if (options.codeStdin)
124588
124854
  code2 = await readCode();
124589
124855
  else {
124590
- await new RemoteSkillsAuthClient(getApiUrl("Publish private skills")).requestCode(options.email);
124856
+ await new RemoteSkillsAuthClient(pending.origin).requestCode(options.email);
124591
124857
  code2 = await promptCode();
124592
124858
  }
124593
124859
  if (code2 === null)
124594
124860
  return;
124595
- const context2 = options.userId ? { userId: options.userId, membershipId: options.membershipId } : undefined;
124596
- const client2 = await privatePublicationSession(options.email, code2, context2), directory3 = resolve48(options.recoveryDir);
124861
+ const client2 = await pending.verify(options.email, code2), directory3 = resolve48(options.recoveryDir);
124597
124862
  if (action === "publish")
124598
124863
  await preparePrivatePublication(client2, resolve48(args2[0]), directory3, { skillId: options.skillId, expectedCurrentVersionId: options.expectedCurrentVersion ?? null, idempotencyKey: options.idempotencyKey });
124599
124864
  const result2 = action === "publish" || action === "resume" ? await continuePrivatePublication(client2, directory3, { confirm: true, waitMs: Number(options.waitSeconds) * 1000 }) : await inspectPrivatePublication(client2, directory3, action === "cancel");
@@ -124611,7 +124876,6 @@ function registerPrivatePublications(parent) {
124611
124876
  }
124612
124877
  var init_private_publications = __esm(() => {
124613
124878
  init_remote_auth();
124614
- init_auth_store();
124615
124879
  init_private_publication_customer();
124616
124880
  init_private_publication_recovery();
124617
124881
  init_remote_private_publications();
@@ -124890,7 +125154,7 @@ Skipped. Run it any time: ${skillsCommand("setup agents", target)}`));
124890
125154
  return;
124891
125155
  }
124892
125156
  const { handleMcp: handleMcp2 } = await Promise.resolve().then(() => (init_runtime_mcp(), exports_runtime_mcp));
124893
- await handleMcp2({ register: "all", json: false });
125157
+ await handleMcp2({ register: "all", json: false, apiUrl: target.origin });
124894
125158
  process.exitCode = before2 ?? 0;
124895
125159
  }
124896
125160
  function promptHidden(question) {
@@ -126062,11 +126326,11 @@ var init_storage2 = __esm(() => {
126062
126326
  });
126063
126327
 
126064
126328
  // src/lib/registry-reconcile.ts
126065
- import { existsSync as existsSync40, readFileSync as readFileSync53, statSync as statSync27, writeFileSync as writeFileSync34 } from "fs";
126329
+ import { existsSync as existsSync40, readFileSync as readFileSync53, statSync as statSync28, writeFileSync as writeFileSync34 } from "fs";
126066
126330
  import { join as join80 } from "path";
126067
126331
  function isDirectory2(path) {
126068
126332
  try {
126069
- return statSync27(path).isDirectory();
126333
+ return statSync28(path).isDirectory();
126070
126334
  } catch {
126071
126335
  return false;
126072
126336
  }