@hasna/skills 0.10.76 → 0.10.78

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.76",
36891
+ version: "0.10.78",
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
  });
@@ -50455,6 +50456,40 @@ var init_codex_settings_witness_v1 = __esm(() => {
50455
50456
  VERBOSITY = new Set(["low", "medium", "high"]);
50456
50457
  });
50457
50458
 
50459
+ // src/lib/codex-plugin-capability-paths.ts
50460
+ function foldCodexPluginEntryName(name) {
50461
+ return name.toUpperCase().toLowerCase();
50462
+ }
50463
+ function codexPluginRootCapabilityEntry(name) {
50464
+ const folded = foldCodexPluginEntryName(name);
50465
+ return CODEX_PLUGIN_ROOT_CAPABILITY_ENTRIES.includes(folded) ? folded : null;
50466
+ }
50467
+ function isCodexSkillDocumentName(name) {
50468
+ return foldCodexPluginEntryName(name) === "skill.md";
50469
+ }
50470
+ var CODEX_PLUGIN_MANIFEST_LOCATIONS, CODEX_PLUGIN_MANIFEST_DIRECTORIES, CODEX_PLUGIN_ROOT_CAPABILITY_ENTRIES;
50471
+ var init_codex_plugin_capability_paths = __esm(() => {
50472
+ CODEX_PLUGIN_MANIFEST_LOCATIONS = Object.freeze([
50473
+ "plugin.json",
50474
+ ".codex-plugin/plugin.json",
50475
+ ".claude-plugin/plugin.json",
50476
+ ".cursor-plugin/plugin.json"
50477
+ ]);
50478
+ CODEX_PLUGIN_MANIFEST_DIRECTORIES = Object.freeze([".codex-plugin", ".claude-plugin", ".cursor-plugin"]);
50479
+ CODEX_PLUGIN_ROOT_CAPABILITY_ENTRIES = Object.freeze([
50480
+ "plugin.json",
50481
+ ".codex-plugin",
50482
+ ".claude-plugin",
50483
+ ".cursor-plugin",
50484
+ "hooks",
50485
+ "hooks.json",
50486
+ ".mcp.json",
50487
+ ".app.json",
50488
+ "commands",
50489
+ "agents"
50490
+ ]);
50491
+ });
50492
+
50458
50493
  // src/lib/codex-hook-mcp-dependencies.ts
50459
50494
  import { createHash as createHash13 } from "crypto";
50460
50495
  import { basename as basename6, dirname as dirname11, isAbsolute as isAbsolute11, join as join17, resolve as resolve12, sep as sep4 } from "path";
@@ -50599,15 +50634,13 @@ function captureCodexHookMcpDependencies(configPath, reviewed, configText, chang
50599
50634
  }
50600
50635
  };
50601
50636
  const root = join17(cacheRoot, identity3, selectCodexPluginVersion(versions, selectionBudget));
50602
- const agent = read2(join17(root, "plugin.json"));
50637
+ const [agentPluginManifest, ...legacyManifests] = CODEX_PLUGIN_MANIFEST_LOCATIONS;
50638
+ const agent = read2(join17(root, agentPluginManifest));
50603
50639
  if (agent !== null) {
50604
50640
  const schema = JSON.parse(agent).$schema;
50605
50641
  need5(typeof schema !== "string" || !schema.startsWith("https://agent-plugins.org/schemas/"));
50606
50642
  }
50607
- const codex = read2(join17(root, ".codex-plugin/plugin.json"));
50608
- const claude = read2(join17(root, ".claude-plugin/plugin.json"));
50609
- const cursor = read2(join17(root, ".cursor-plugin/plugin.json"));
50610
- const text2 = codex ?? claude ?? cursor;
50643
+ const text2 = legacyManifests.map((location) => read2(join17(root, location))).find((value) => value !== null) ?? null;
50611
50644
  if (text2 === null)
50612
50645
  continue;
50613
50646
  const manifest = JSON.parse(text2);
@@ -50629,6 +50662,7 @@ var init_codex_hook_mcp_dependencies = __esm(() => {
50629
50662
  init_claude_settings_witness();
50630
50663
  init_agent_discovery_directories();
50631
50664
  init_agent_discovery_bytes();
50665
+ init_codex_plugin_capability_paths();
50632
50666
  events = new Set(["PreToolUse", "PermissionRequest", "PostToolUse", "PreCompact", "PostCompact", "SessionStart", "SessionEnd", "UserPromptSubmit", "SubagentStart", "SubagentStop", "Stop", "Interrupt"]);
50633
50667
  });
50634
50668
 
@@ -52942,15 +52976,17 @@ function codexVendorConfigCandidates(text2, cache3, options = {}) {
52942
52976
  var CODEX_VENDOR_MARKETPLACES, CODEX_REMOTE_VENDOR_MARKETPLACES, identifier3 = (value) => typeof value === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(value), record4 = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value)), directory = (path) => {
52943
52977
  const stat2 = lstatSync14(path, { throwIfNoEntry: false });
52944
52978
  return Boolean(stat2?.isDirectory() && !stat2.isSymbolicLink());
52945
- }, OTHER_PLUGIN_CONTROLS, VENDOR_MANIFEST_KEYS, DEFAULT_SKILLS_PATHS, VENDOR_APP_DECLARATION = "./.app.json", MAX_SUBTREE_ENTRIES = 20000, MAX_SUBTREE_DEPTH = 32, hiddenName = (name) => name.startsWith(".") || name === "node_modules", isSkillDocument = (name) => name.toLowerCase() === "skill.md", present = (path) => lstatSync14(path, { throwIfNoEntry: false }) !== undefined, holdsOtherControl = (path) => readdirSync7(path).some((name) => OTHER_PLUGIN_CONTROLS.includes(name.toLowerCase())), MAX_TRAILING_VENDOR_ROWS = 16, MAX_VENDOR_TABLES = 8, MAX_CONFIG_CANDIDATES = 128, HEADER;
52979
+ }, OTHER_PLUGIN_CONTROLS, VENDOR_MANIFEST_KEYS, DEFAULT_SKILLS_PATHS, VENDOR_APP_DECLARATION = "./.app.json", MAX_SUBTREE_ENTRIES = 20000, MAX_SUBTREE_DEPTH = 32, hiddenName = (name) => name.startsWith(".") || name === "node_modules", isSkillDocument, present = (path) => lstatSync14(path, { throwIfNoEntry: false }) !== undefined, holdsOtherControl = (path) => readdirSync7(path).some((name) => OTHER_PLUGIN_CONTROLS.includes(codexPluginRootCapabilityEntry(name) ?? "")), MAX_TRAILING_VENDOR_ROWS = 16, MAX_VENDOR_TABLES = 8, MAX_CONFIG_CANDIDATES = 128, HEADER;
52946
52980
  var init_codex_vendor_refresh = __esm(() => {
52947
52981
  init_claude_settings_witness();
52948
52982
  init_codex_plugin_skill_controls();
52983
+ init_codex_plugin_capability_paths();
52949
52984
  CODEX_VENDOR_MARKETPLACES = Object.freeze(["openai-bundled", "openai-curated", "openai-curated-remote"]);
52950
52985
  CODEX_REMOTE_VENDOR_MARKETPLACES = Object.freeze(["openai-curated-remote"]);
52951
- OTHER_PLUGIN_CONTROLS = Object.freeze(["plugin.json", ".claude-plugin", ".cursor-plugin", "hooks", "hooks.json", ".mcp.json", "commands", "agents"]);
52986
+ OTHER_PLUGIN_CONTROLS = Object.freeze(CODEX_PLUGIN_ROOT_CAPABILITY_ENTRIES.filter((entry) => entry !== ".codex-plugin" && entry !== ".app.json"));
52952
52987
  VENDOR_MANIFEST_KEYS = Object.freeze(["name", "version", "description", "author", "homepage", "repository", "license", "keywords", "interface", "skills", "apps"]);
52953
52988
  DEFAULT_SKILLS_PATHS = Object.freeze(["./skills", "./skills/"]);
52989
+ isSkillDocument = isCodexSkillDocumentName;
52954
52990
  HEADER = /^[ \t]*(\[\[|\[)[ \t]*([^[\]\r\n]+?)[ \t]*(\]\]|\])[ \t]*(?:#[^\r\n]*)?\r?\n?$/;
52955
52991
  });
52956
52992
 
@@ -54056,6 +54092,10 @@ function skillsFileHasCredential(file) {
54056
54092
  return false;
54057
54093
  return /^\s*(?:export\s+)?(?:HASNA_SKILLS_API_KEY|SKILLS_API_KEY|HASNA_SKILLS_API_KEY_REF)\s*=\s*\S/m.test(text2);
54058
54094
  }
54095
+ function skillsFileHasVaultReference(file) {
54096
+ const text2 = readMetadataText(file);
54097
+ return text2 !== null && /^\s*(?:export\s+)?HASNA_SKILLS_API_KEY_REF\s*=\s*\S/m.test(text2);
54098
+ }
54059
54099
  var SKILLS_BOUND_API_URL = "HASNA_SKILLS_BOUND_API_URL";
54060
54100
  var init_instance_credentials = __esm(() => {
54061
54101
  init_transport();
@@ -54090,6 +54130,25 @@ var init_local_opt_in = __esm(() => {
54090
54130
  // src/lib/product-default.ts
54091
54131
  var SKILLS_PRODUCT_DEFAULT_ORIGIN = "https://skills.md";
54092
54132
 
54133
+ // src/lib/credential-profile-command.ts
54134
+ function skillsShellArgument(value) {
54135
+ return /^[A-Za-z0-9._:/-]+$/.test(value) ? value : `'${value.replace(/'/g, "'\\''")}'`;
54136
+ }
54137
+ function skillsApiUrlEnvironment(origin) {
54138
+ return urlKeys.map((name) => `${name}=${skillsShellArgument(origin)}`).join(" ");
54139
+ }
54140
+ function skillsProfileCommand(command, env3 = process.env, origin) {
54141
+ const profile = selectedSkillsProfile(env3);
54142
+ const prefix = origin && urlKeys.some((name) => env3[name]?.trim()) ? `${skillsApiUrlEnvironment(origin)} ` : "";
54143
+ return `${prefix}skills${profile ? ` --profile ${profile}` : ""} ${command}`;
54144
+ }
54145
+ var urlKeys;
54146
+ var init_credential_profile_command = __esm(() => {
54147
+ init_instance_credentials();
54148
+ init_transport();
54149
+ urlKeys = clientTransportEnvKeys("skills").apiUrlKeys;
54150
+ });
54151
+
54093
54152
  // src/lib/fleet-credentials.ts
54094
54153
  var exports_fleet_credentials = {};
54095
54154
  __export(exports_fleet_credentials, {
@@ -54114,6 +54173,8 @@ __export(exports_fleet_credentials, {
54114
54173
  gatewaySignInRefusal: () => gatewaySignInRefusal,
54115
54174
  credentialPairing: () => credentialPairing,
54116
54175
  configuredSkillsApiUrl: () => configuredSkillsApiUrl,
54176
+ captureSkillsSignInTarget: () => captureSkillsSignInTarget,
54177
+ assertSkillsSignInCredentialReplaceable: () => assertSkillsSignInCredentialReplaceable,
54117
54178
  SkillsFleetCredentialError: () => SkillsFleetCredentialError,
54118
54179
  SKILLS_LOCAL_OPT_IN_ENV_KEYS: () => SKILLS_LOCAL_OPT_IN_ENV_KEYS,
54119
54180
  SKILLS_CREDENTIAL_TIERS: () => SKILLS_CREDENTIAL_TIERS,
@@ -54419,8 +54480,24 @@ function gatewaySignInRefusal(target) {
54419
54480
  if (normalizeSkillsApiOrigin(target.origin) !== normalizeSkillsApiOrigin(defaultFleetGatewayBaseUrl(SKILLS_APP)))
54420
54481
  return null;
54421
54482
  const cause = target.credentialSource ? `${target.credentialSource} holds a Skills credential for the internal gateway` : target.source === "--url" ? "--url names the internal gateway" : `${target.source} selects the internal gateway`;
54422
- const unset2 = target.credentialSource ?? (target.source === "--url" ? null : target.source);
54423
- return new SkillsFleetCredentialError(`${cause}, which has no sign-in service. Nothing was sent.` + (unset2 ? ` To sign in to the default server instead, first unset ${unset2} (or remove it from where it is stored), then run: skills login.` : ""), "GATEWAY_AUTH_UNAVAILABLE", unset2 ? [`unset ${unset2}`, "skills login"] : undefined);
54483
+ const command = (SKILLS_API_URL_ENV_KEYS.includes(target.source) ? `${skillsApiUrlEnvironment(SKILLS_PRODUCT_DEFAULT_ORIGIN)} ` : "") + "skills --profile <new-profile> login";
54484
+ return new SkillsFleetCredentialError(`${cause}, which has no sign-in service. Nothing was sent. ` + `Keep the fleet configuration and use a separate profile for product sign-in: ${command}.`, "GATEWAY_AUTH_UNAVAILABLE", [command]);
54485
+ }
54486
+ function assertSkillsSignInCredentialReplaceable(env3 = process.env, profile) {
54487
+ const files = skillsProfileCredentialFiles(env3, profile);
54488
+ const verifyUnchanged = captureSkillsCredentialFiles(files);
54489
+ const gateway = normalizeSkillsApiOrigin(defaultFleetGatewayBaseUrl(SKILLS_APP));
54490
+ const command = (SKILLS_API_URL_ENV_KEYS.some((name) => env3[name]?.trim()) ? `${skillsApiUrlEnvironment(SKILLS_PRODUCT_DEFAULT_ORIGIN)} ` : "") + "skills --profile <new-profile> login";
54491
+ for (const file of files) {
54492
+ if (!skillsFileHasCredential(file))
54493
+ continue;
54494
+ const metadata = readSkillsInstanceMetadata(file);
54495
+ const instance = metadata.binding ?? metadata.apiUrl;
54496
+ if (skillsFileHasVaultReference(file) || !instance || normalizeSkillsApiOrigin(instance) === gateway) {
54497
+ throw new SkillsFleetCredentialError("The selected profile contains a protected fleet credential or vault reference. Nothing was sent or changed. " + `Use a separate profile for product sign-in: ${command}.`, "STORED_CREDENTIAL_PROTECTED", [command]);
54498
+ }
54499
+ }
54500
+ verifyUnchanged();
54424
54501
  }
54425
54502
  function explicitSignInOrigin(url) {
54426
54503
  if (!url.trim() || /[\x00-\x1f\x7f]/.test(url)) {
@@ -54448,13 +54525,15 @@ function resolveSkillsSignInOrigin(env3 = process.env, options = {}, explicitUrl
54448
54525
  const snapshot = snapshotSkillsEnvironment(env3);
54449
54526
  const resolvedOptions = snapshotSkillsOptions(env3, options);
54450
54527
  const profile = resolvedOptions.credentials?.profile;
54528
+ assertSkillsSignInCredentialReplaceable(snapshot, profile);
54451
54529
  const configured = configuredSkillsApiUrl(snapshot, resolvedOptions.credentials?.keychain, profile);
54452
54530
  const declared = configured && configured.source !== "default" ? configured : null;
54453
54531
  if (explicitUrl !== undefined) {
54454
54532
  const origin = explicitSignInOrigin(explicitUrl);
54455
54533
  const storedHere = declared ? skillsProfileCredentialFiles(snapshot, profile).includes(declared.source) : false;
54456
54534
  if (declared && !storedHere && normalizeSkillsApiOrigin(declared.value) !== origin) {
54457
- throw new SkillsFleetCredentialError(`--url ${origin} conflicts with ${declared.source}, which outranks the saved configuration and would ` + `shadow the key this sign-in stores. Unset ${declared.source} or pass the same URL.`, "INVALID_API_URL");
54535
+ const command = `${skillsApiUrlEnvironment(origin)} skills --profile <new-profile> login`;
54536
+ throw new SkillsFleetCredentialError(`--url ${origin} conflicts with ${declared.source}, which outranks the saved configuration and would ` + `shadow the key this sign-in stores. Keep the existing configuration and use a separate process and profile: ${command}.`, "INVALID_API_URL", [command]);
54458
54537
  }
54459
54538
  return { origin, source: "--url" };
54460
54539
  }
@@ -54486,6 +54565,14 @@ function resolveSkillsSignInOrigin(env3 = process.env, options = {}, explicitUrl
54486
54565
  throw error;
54487
54566
  }
54488
54567
  }
54568
+ function captureSkillsSignInTarget(env3 = process.env, options = {}, explicitUrl) {
54569
+ const snapshot = snapshotSkillsEnvironment(env3);
54570
+ const profile = options.credentials?.profile ?? selectedCliSkillsCredentialProfile();
54571
+ const unchanged2 = captureSkillsCredentialFiles(skillsProfileCredentialFiles(snapshot, profile));
54572
+ const target = resolveSkillsSignInOrigin(env3, options, explicitUrl);
54573
+ unchanged2();
54574
+ return { ...target, unchanged: unchanged2 };
54575
+ }
54489
54576
  function requireSkillsFleet(action = "This command", env3 = process.env, options = {}) {
54490
54577
  const fleet = resolveSkillsFleet(env3, options);
54491
54578
  if (fleet.mode === "hosted")
@@ -54497,6 +54584,7 @@ var init_fleet_credentials = __esm(() => {
54497
54584
  init_transport();
54498
54585
  init_instance_credentials();
54499
54586
  init_local_opt_in();
54587
+ init_credential_profile_command();
54500
54588
  init_local_opt_in();
54501
54589
  ENV_KEYS = clientTransportEnvKeys(SKILLS_APP);
54502
54590
  SKILLS_API_URL_ENV_KEYS = ENV_KEYS.apiUrlKeys;
@@ -56074,14 +56162,23 @@ function assertParents(cacheRoot, controls, appOnlyParents, hookParents, files,
56074
56162
  continue;
56075
56163
  const parent = join28(cacheRoot, parts[0], parts[1]);
56076
56164
  const root = join28(parent, parts[2]);
56077
- const base2 = parts[parts.length - 1];
56078
- if (parts.includes(".codex-plugin") && (parts.length < 4 || parts[3] !== ".codex-plugin" || (parts.length === 4 ? base2 !== ".codex-plugin" : parts.length !== 5 || base2 !== "plugin.json")))
56165
+ const base2 = parts[parts.length - 1], folded = foldCodexPluginEntryName(base2);
56166
+ if (parts.length === 3 && (codexPluginRootCapabilityEntry(base2) !== null || isCodexSkillDocumentName(base2)))
56167
+ refuse4();
56168
+ const rootEntry = parts.length >= 4 ? codexPluginRootCapabilityEntry(parts[3]) : null;
56169
+ if (rootEntry !== null && rootEntry !== parts[3])
56170
+ refuse4();
56171
+ if (rootEntry !== null && !SEMANTIC_BOUND_ROOT_ENTRIES.includes(rootEntry))
56079
56172
  refuse4();
56080
- if ([".app.json", ".mcp.json"].includes(base2) && (parts.length !== 4 || dirname18(member) !== root))
56173
+ if (isCodexSkillDocumentName(base2) && base2 !== "SKILL.md")
56081
56174
  refuse4();
56082
- if ([".app.json", ".mcp.json"].includes(base2) && hookParents.some((reviewed) => reviewed.pluginParent === parent))
56175
+ if (parts.some((part) => CODEX_PLUGIN_MANIFEST_DIRECTORIES.includes(foldCodexPluginEntryName(part))) && (parts.length < 4 || parts[3] !== ".codex-plugin" || (parts.length === 4 ? base2 !== ".codex-plugin" : parts.length !== 5 || base2 !== "plugin.json")))
56083
56176
  refuse4();
56084
- if ((parts[3] === "hooks" || base2 === "hooks.json") && (![4, 5].includes(parts.length) || parts[3] !== "hooks" || (parts.length === 4 ? base2 !== "hooks" : base2 !== "hooks.json") || !hookParents.some((reviewed) => reviewed.pluginParent === join28(cacheRoot, parts[0], parts[1]))))
56177
+ if ([".app.json", ".mcp.json"].includes(folded) && (parts.length !== 4 || dirname18(member) !== root))
56178
+ refuse4();
56179
+ if ([".app.json", ".mcp.json"].includes(folded) && hookParents.some((reviewed) => reviewed.pluginParent === parent))
56180
+ refuse4();
56181
+ if ((rootEntry === "hooks" || folded === "hooks.json") && (![4, 5].includes(parts.length) || parts[3] !== "hooks" || (parts.length === 4 ? base2 !== "hooks" : base2 !== "hooks.json") || !hookParents.some((reviewed) => reviewed.pluginParent === join28(cacheRoot, parts[0], parts[1]))))
56085
56182
  refuse4();
56086
56183
  }
56087
56184
  }
@@ -56303,13 +56400,15 @@ function assertCodexSemanticCacheWitnessUnchanged(previous, current) {
56303
56400
  if (hash2(priorProjection) !== previous.sha256 || hash2(currentProjection) !== current.sha256 || canonical8(comparable(priorProjection)) !== canonical8(comparable(currentProjection)))
56304
56401
  refuse4();
56305
56402
  }
56306
- var CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA = "hasna.codex-semantic-cache-witness.v1", identifier5 = (value) => typeof value === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(value), digest = (value) => typeof value === "string" && /^[a-f0-9]{64}$/.test(value), refuse4 = () => {
56403
+ var CODEX_SEMANTIC_CACHE_WITNESS_SCHEMA = "hasna.codex-semantic-cache-witness.v1", SEMANTIC_BOUND_ROOT_ENTRIES, identifier5 = (value) => typeof value === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(value), digest = (value) => typeof value === "string" && /^[a-f0-9]{64}$/.test(value), refuse4 = () => {
56307
56404
  throw new Error("CODEX_SEMANTIC_CACHE_WITNESS_UNSUPPORTED: review Codex plugin cache identity and controls");
56308
56405
  }, MAX_DOCUMENT_BYTES, MAX_RECEIPT_BYTES, codexHookEvents;
56309
56406
  var init_codex_semantic_cache_witness = __esm(() => {
56310
56407
  init_claude_settings_witness();
56311
56408
  init_codex_plugin_skill_controls();
56312
56409
  init_codex_native_skill_catalog();
56410
+ init_codex_plugin_capability_paths();
56411
+ SEMANTIC_BOUND_ROOT_ENTRIES = Object.freeze([".codex-plugin", ".app.json", ".mcp.json", "hooks"]);
56313
56412
  MAX_DOCUMENT_BYTES = 1024 * 1024;
56314
56413
  MAX_RECEIPT_BYTES = 16 * 1024;
56315
56414
  codexHookEvents = new Set([
@@ -66250,7 +66349,8 @@ function getAuthConfig(env3 = process.env, options = {}) {
66250
66349
  return null;
66251
66350
  return { apiKey: fleet.apiKey, ...readIdentity(env3) };
66252
66351
  }
66253
- function writeCredentialValues(values2, env3 = process.env) {
66352
+ function writeCredentialValues(values2, env3 = process.env, beforeWrite) {
66353
+ beforeWrite?.();
66254
66354
  const file = skillsCredentialFilePath(env3);
66255
66355
  mkdirSync14(dirname29(file), { recursive: true, mode: 448 });
66256
66356
  const lines = [];
@@ -66279,9 +66379,16 @@ function writeCredentialValues(values2, env3 = process.env) {
66279
66379
  `) + `
66280
66380
  `;
66281
66381
  const temp = `${file}.tmp-${process.pid}`;
66282
- writeFileSync11(temp, body, { mode: 384 });
66283
- chmodSync2(temp, 384);
66284
- renameSync8(temp, file);
66382
+ writeFileSync11(temp, body, { mode: 384, flag: "wx" });
66383
+ try {
66384
+ chmodSync2(temp, 384);
66385
+ beforeWrite?.();
66386
+ renameSync8(temp, file);
66387
+ } finally {
66388
+ try {
66389
+ unlinkSync6(temp);
66390
+ } catch {}
66391
+ }
66285
66392
  return file;
66286
66393
  }
66287
66394
  function readCredentialValue(key2, env3 = process.env) {
@@ -66325,7 +66432,14 @@ function safeOrigin(url) {
66325
66432
  return null;
66326
66433
  }
66327
66434
  }
66328
- function saveAuthConfig(config, env3 = process.env, authenticatedOrigin, issuedBy) {
66435
+ function saveAuthConfig(config, env3 = process.env, authenticatedOrigin, issuedBy, assertUnchanged) {
66436
+ const unchanged3 = assertUnchanged ?? captureSkillsCredentialFiles(skillsProfileCredentialFiles(env3));
66437
+ const beforeWrite = () => {
66438
+ unchanged3();
66439
+ if (issuedBy)
66440
+ assertSkillsSignInCredentialReplaceable(env3);
66441
+ };
66442
+ beforeWrite();
66329
66443
  const apiKey = config.apiKey.trim();
66330
66444
  if (!apiKey)
66331
66445
  throw new Error("Refusing to store an empty Skills API key.");
@@ -66337,7 +66451,7 @@ function saveAuthConfig(config, env3 = process.env, authenticatedOrigin, issuedB
66337
66451
  const previous = readIdentityRecord(env3);
66338
66452
  const loginWroteBefore = previous?.urlWrittenBy === "login" && typeof previous.apiUrl === "string" && safeOrigin(previous.apiUrl) === apiUrl;
66339
66453
  const urlWrittenByLogin = issuedBy !== undefined && (!previousUrl || safeOrigin(previousUrl) !== apiUrl || loginWroteBefore);
66340
- const file = writeCredentialValues({ SKILLS_API_KEY: null, SKILLS_API_URL: null, [SKILLS_API_KEY_REF]: null, [SKILLS_API_KEY_ENV]: apiKey, [SKILLS_BOUND_API_URL]: apiUrl, [SKILLS_API_URL_ENV]: apiUrl }, env3);
66454
+ const file = writeCredentialValues({ SKILLS_API_KEY: null, SKILLS_API_URL: null, [SKILLS_API_KEY_REF]: null, [SKILLS_API_KEY_ENV]: apiKey, [SKILLS_BOUND_API_URL]: apiUrl, [SKILLS_API_URL_ENV]: apiUrl }, env3, beforeWrite);
66341
66455
  const identity6 = {};
66342
66456
  for (const field3 of ["email", "orgId", "orgSlug", "userId"]) {
66343
66457
  const value = config[field3];
@@ -66633,6 +66747,24 @@ var init_remote_workspace_selection = __esm(() => {
66633
66747
 
66634
66748
  // src/lib/remote-private-publications.ts
66635
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
+ }
66636
66768
  function checkedPublicationDeclaration(value) {
66637
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)
66638
66770
  return bad();
@@ -66652,11 +66784,11 @@ function checkedPublicationView(value, skillId, intentId, declaration) {
66652
66784
  return invalid3();
66653
66785
  return Object.freeze({ ...value });
66654
66786
  }
66655
- async function boundedJson(url, init, token, mutation, budget2 = 15000, signal) {
66787
+ async function boundedJson(url, init, token, mutation, budget2 = 15000, signal, create3 = false) {
66656
66788
  const controller = new AbortController;
66657
66789
  let reader;
66658
66790
  let response;
66659
- 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);
66660
66792
  let timer;
66661
66793
  let abort;
66662
66794
  try {
@@ -66696,11 +66828,19 @@ async function boundedJson(url, init, token, mutation, budget2 = 15000, signal)
66696
66828
  return invalid3();
66697
66829
  }
66698
66830
  if (!response.ok) {
66699
- const code = record7(body) && typeof body.code === "string" && Object.hasOwn(failures, body.code) ? body.code : null;
66700
- if (code && failures[code][0] === response.status)
66701
- 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
+ }
66702
66840
  throw new PrivatePublicationError("PUBLICATION_REQUEST_FAILED", "The publication request was refused. Inspect its status before retrying.", mutation && response.status >= 500, response.status);
66703
66841
  }
66842
+ if (create3 && response.status !== 201)
66843
+ return invalid3();
66704
66844
  return body;
66705
66845
  })(), new Promise((_, reject2) => {
66706
66846
  abort = () => {
@@ -66747,6 +66887,15 @@ class RemotePrivatePublicationsClient {
66747
66887
  this.membershipId = checked.user.membershipId;
66748
66888
  Object.freeze(this);
66749
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
+ }
66750
66899
  async getCapability(options = {}) {
66751
66900
  if (options.timeoutMs !== undefined && (!Number.isSafeInteger(options.timeoutMs) || options.timeoutMs < 1 || options.timeoutMs > 15000))
66752
66901
  return bad();
@@ -66889,7 +67038,7 @@ class RemotePrivatePublicationsClient {
66889
67038
  }
66890
67039
  }
66891
67040
  }
66892
- var PRIVATE_PUBLICATION_MAX_BYTES, failures, PrivatePublicationError, bad = () => {
67041
+ var PRIVATE_PUBLICATION_MAX_BYTES, skillCreateFailures, failures, PrivatePublicationError, bad = () => {
66893
67042
  throw new PrivatePublicationError("INVALID_PUBLICATION_INPUT", "Invalid publication input or recovery data.");
66894
67043
  }, invalid3 = () => {
66895
67044
  throw new PrivatePublicationError("INVALID_PUBLICATION_RESPONSE", "The server returned an invalid publication result.");
@@ -66899,6 +67048,16 @@ var init_remote_private_publications = __esm(() => {
66899
67048
  init_remote_workspace_selection();
66900
67049
  init_skill_contract();
66901
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
+ };
66902
67061
  failures = {
66903
67062
  INVALID_REQUEST: [400, "The publication request is invalid."],
66904
67063
  SESSION_EXPIRED: [401, "Sign in again to manage this publication."],
@@ -88497,7 +88656,10 @@ function clearPendingDeviceSignIn(env3 = process.env, origin) {
88497
88656
  }
88498
88657
  }
88499
88658
  }
88500
- async function persistSignIn(result2, origin, env3 = process.env, issuedBy = "sign-in") {
88659
+ async function persistSignIn(result2, origin, env3 = process.env, issuedBy = "sign-in", assertUnchanged) {
88660
+ const unchanged3 = assertUnchanged ?? captureSkillsCredentialFiles(skillsProfileCredentialFiles(env3));
88661
+ unchanged3();
88662
+ assertSkillsSignInCredentialReplaceable(env3);
88501
88663
  let apiKey = typeof result2.apiKey === "string" && result2.apiKey.trim() ? result2.apiKey : undefined;
88502
88664
  if (!apiKey && typeof result2.token === "string" && result2.token) {
88503
88665
  const created = await new RemoteSkillsAuthClient(origin).request("/api/auth/keys", {
@@ -88515,7 +88677,7 @@ async function persistSignIn(result2, origin, env3 = process.env, issuedBy = "si
88515
88677
  ...boundedText(result2.organization?.id) ? { orgId: result2.organization.id } : {},
88516
88678
  ...boundedText(result2.organization?.slug) ? { orgSlug: result2.organization.slug } : {},
88517
88679
  ...boundedText(result2.user?.id) ? { userId: result2.user.id } : {}
88518
- }, env3, origin, issuedBy);
88680
+ }, env3, origin, issuedBy, unchanged3);
88519
88681
  }
88520
88682
  function manualRevocationHint(origin) {
88521
88683
  if (origin === SKILLS_PRODUCT_DEFAULT_ORIGIN) {
@@ -88881,6 +89043,7 @@ function normalizeRemoteSkill(skill) {
88881
89043
  if (!name)
88882
89044
  throw new Error("Remote skill requires name or slug");
88883
89045
  return {
89046
+ ...skill.id !== undefined ? { id: skill.id } : {},
88884
89047
  name,
88885
89048
  displayName: skill.displayName || titleize(name),
88886
89049
  description: skill.description || "",
@@ -88999,11 +89162,12 @@ var init_remote_registry = __esm(() => {
88999
89162
  details: exports_external.array(exports_external.string()).optional()
89000
89163
  }).passthrough();
89001
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(),
89002
89166
  name: exports_external.string().min(1).optional(),
89003
89167
  slug: exports_external.string().min(1).optional(),
89004
89168
  displayName: exports_external.string().optional(),
89005
89169
  description: exports_external.string().optional(),
89006
- category: exports_external.string().optional(),
89170
+ category: exports_external.string().nullable().optional(),
89007
89171
  tags: exports_external.array(exports_external.string()).optional(),
89008
89172
  dependencies: exports_external.array(exports_external.string()).optional(),
89009
89173
  version: exports_external.string().optional(),
@@ -99452,6 +99616,43 @@ var init_run_state = __esm(() => {
99452
99616
  init_project_state();
99453
99617
  });
99454
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
+
99455
99656
  // node_modules/@modelcontextprotocol/sdk/dist/esm/types.js
99456
99657
  function assertCompleteRequestPrompt(request2) {
99457
99658
  if (request2.params.ref.type !== "ref/prompt") {
@@ -111493,6 +111694,7 @@ async function prepareWorkspaceEnrollment(membershipId, source = process.env) {
111493
111694
  const env3 = { ...source }, profile = selectedSkillsProfile(env3);
111494
111695
  if (!profile)
111495
111696
  return fail4("Workspace login requires an explicit HASNA_PROFILE name.");
111697
+ assertSkillsSignInCredentialReplaceable(env3);
111496
111698
  if (["HASNA_SKILLS_API_KEY_OVERRIDE", "HASNA_SKILLS_API_KEY_REF", "HASNA_SKILLS_API_KEY", "SKILLS_API_KEY"].some((name) => env3[name]?.trim()))
111497
111699
  return fail4("Clear injected API keys before enrolling a named workspace profile.");
111498
111700
  const origin = getApiUrl("Sign in to a workspace", env3);
@@ -111789,7 +111991,7 @@ var init_recurring_customer = __esm(() => {
111789
111991
 
111790
111992
  // src/lib/recurring-recovery.ts
111791
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";
111792
- 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";
111793
111995
  import { randomUUID as randomUUID8 } from "crypto";
111794
111996
 
111795
111997
  class RecoveryOwner {
@@ -111797,7 +111999,7 @@ class RecoveryOwner {
111797
111999
  parents = [];
111798
112000
  constructor(directory2) {
111799
112001
  this.directory = directory2;
111800
- if (!isAbsolute33(directory2) || resolve34(directory2) !== directory2 || realpathSync17(directory2) !== directory2)
112002
+ if (!isAbsolute34(directory2) || resolve34(directory2) !== directory2 || realpathSync17(directory2) !== directory2)
111801
112003
  invalid6();
111802
112004
  for (let path = directory2;; path = dirname35(path)) {
111803
112005
  const stat3 = lstatSync37(path);
@@ -111932,7 +112134,7 @@ function base2(customer, organizationId) {
111932
112134
  };
111933
112135
  }
111934
112136
  function create3(directory2, intent) {
111935
- if (!isAbsolute33(directory2) || resolve34(directory2) !== directory2 || realpathSync17(dirname35(directory2)) !== dirname35(directory2))
112137
+ if (!isAbsolute34(directory2) || resolve34(directory2) !== directory2 || realpathSync17(dirname35(directory2)) !== dirname35(directory2))
111936
112138
  invalid6();
111937
112139
  mkdirSync21(directory2, { mode: 448 });
111938
112140
  const owner2 = new RecoveryOwner(directory2), checked = intentSchema.parse(intent), intentSha256 = canonicalJsonSha256(checked);
@@ -112095,7 +112297,7 @@ var init_recurring_recovery = __esm(() => {
112095
112297
  });
112096
112298
 
112097
112299
  // src/lib/recurring-surface.ts
112098
- import { isAbsolute as isAbsolute34 } from "path";
112300
+ import { isAbsolute as isAbsolute35 } from "path";
112099
112301
  function recurringMcpSchema(action) {
112100
112302
  return action === "activate" ? recurringSurfaceSchemas.activate.extend({ code, confirm: exports_external.literal(true) }) : recurringSurfaceSchemas[action];
112101
112303
  }
@@ -112200,7 +112402,7 @@ var init_recurring_surface = __esm(() => {
112200
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}$/);
112201
112403
  context = { userId: uuid12.optional(), membershipId: uuid12.optional() };
112202
112404
  page2 = { limit: exports_external.number().int().min(1).max(100).optional(), cursor: exports_external.string().min(1).max(2048).optional() };
112203
- 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");
112204
112406
  email4 = exports_external.string().trim().toLowerCase().email().max(254);
112205
112407
  code = exports_external.string().regex(/^\d{6}$/);
112206
112408
  recurringSurfaceSchemas = {
@@ -114986,15 +115188,42 @@ var init_remote_invitation_tools = __esm(() => {
114986
115188
  });
114987
115189
 
114988
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
+ }
114989
115225
  async function privatePublicationSession(email5, code2, requested) {
114990
- const target = await captureProfileWorkspace("Manage private publications");
114991
- const context2 = requested ?? target.context;
114992
- if (!context2 || !publicationUuid(context2.userId) || !publicationUuid(context2.membershipId) || target.context && (context2.userId !== target.context.userId || context2.membershipId !== target.context.membershipId))
114993
- throw new PrivatePublicationError("PUBLICATION_CONTEXT_REQUIRED", "Provide the observed user and membership IDs, or select an enrolled workspace profile.");
114994
- target.unchanged();
114995
- const client2 = await new RemoteSkillsAuthClient(target.origin).openPrivatePublications(email5, code2, context2);
114996
- target.unchanged();
114997
- return client2;
115226
+ return preparePrivatePublicationSession(requested).verify(email5, code2);
114998
115227
  }
114999
115228
  function privatePublicationCustomerError(error61) {
115000
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 };
@@ -115003,14 +115232,15 @@ var init_private_publication_customer = __esm(() => {
115003
115232
  init_remote_auth();
115004
115233
  init_remote_private_publications();
115005
115234
  init_workspace_profile();
115235
+ init_instance_credentials();
115006
115236
  });
115007
115237
 
115008
115238
  // src/lib/private-publication-recovery.ts
115009
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";
115010
- 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";
115011
115241
  import { randomUUID as randomUUID9 } from "crypto";
115012
115242
  function safeDirectory(directory3) {
115013
- if (!isAbsolute35(directory3) || directory3 !== resolve35(directory3) || realpathSync18(directory3) !== directory3)
115243
+ if (!isAbsolute36(directory3) || directory3 !== resolve35(directory3) || realpathSync18(directory3) !== directory3)
115014
115244
  return fail5();
115015
115245
  for (let path = directory3;; path = dirname38(path)) {
115016
115246
  const stat3 = lstatSync38(path);
@@ -115148,7 +115378,7 @@ async function preparePrivatePublication(client2, sourceDirectory, recoveryDirec
115148
115378
  phase: "prepared",
115149
115379
  intent: null
115150
115380
  };
115151
- if (!isAbsolute35(recoveryDirectory) || resolve35(recoveryDirectory) !== recoveryDirectory || realpathSync18(dirname38(recoveryDirectory)) !== dirname38(recoveryDirectory))
115381
+ if (!isAbsolute36(recoveryDirectory) || resolve35(recoveryDirectory) !== recoveryDirectory || realpathSync18(dirname38(recoveryDirectory)) !== dirname38(recoveryDirectory))
115152
115382
  return fail5();
115153
115383
  mkdirSync25(recoveryDirectory, { mode: 448 });
115154
115384
  safeDirectory(recoveryDirectory);
@@ -115249,10 +115479,10 @@ var init_private_publication_recovery = __esm(() => {
115249
115479
  });
115250
115480
 
115251
115481
  // src/mcp/private-publication-tools.ts
115252
- import { isAbsolute as isAbsolute36 } from "path";
115482
+ import { isAbsolute as isAbsolute37 } from "path";
115253
115483
  function registerPrivatePublicationTools(server) {
115254
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}$/);
115255
- 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");
115256
115486
  const verification2 = { email: exports_external.string().email().max(254), code: exports_external.string().regex(/^\d{6}$/), userId: uuid9, membershipId: uuid9, recoveryDirectory: directory3 };
115257
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.";
115258
115488
  const handler = (action) => async (value) => {
@@ -115713,14 +115943,18 @@ var exports_runtime_mcp = {};
115713
115943
  __export(exports_runtime_mcp, {
115714
115944
  handleMcp: () => handleMcp
115715
115945
  });
115716
- 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";
115717
115948
  import { homedir as homedir10 } from "os";
115718
- 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";
115719
115951
  async function handleMcp(options) {
115720
115952
  if (options.register) {
115721
115953
  let agents;
115954
+ let environment;
115722
115955
  try {
115723
115956
  agents = resolveAgents(options.register);
115957
+ environment = skillsMcpRegistrationEnvironment(process.env, options.apiUrl);
115724
115958
  } catch (err) {
115725
115959
  const error61 = err.message;
115726
115960
  if (options.json) {
@@ -115734,7 +115968,7 @@ async function handleMcp(options) {
115734
115968
  const command = findCommandOnPath(MCP_COMMAND_NAME);
115735
115969
  const results2 = [];
115736
115970
  for (const agent of agents) {
115737
- const result2 = await registerMcpForAgent(agent, command);
115971
+ const result2 = await registerMcpForAgent(agent, command, environment);
115738
115972
  results2.push(result2);
115739
115973
  if (!options.json) {
115740
115974
  const label = result2.path ? `${agent} (${result2.path})` : agent;
@@ -115751,96 +115985,193 @@ async function handleMcp(options) {
115751
115985
  const { startMcpStdio: startMcpStdio2 } = await Promise.resolve().then(() => (init_mcp2(), exports_mcp));
115752
115986
  await startMcpStdio2();
115753
115987
  }
115754
- async function registerMcpForAgent(agent, command) {
115988
+ async function registerMcpForAgent(agent, command, environment) {
115989
+ const server2 = { command, args: ["--stdio"], ...Object.keys(environment).length ? { env: environment } : {} };
115755
115990
  switch (agent) {
115756
115991
  case "claude":
115757
- return registerClaudeMcp(command);
115992
+ return registerClaudeMcp(command, server2, environment);
115758
115993
  case "codex":
115759
- return registerCodexMcp(command);
115994
+ return registerCodexMcp(command, environment);
115760
115995
  case "gemini":
115761
- return registerJsonMcpServer(agent, join65(homedir10(), ".gemini", "settings.json"), "mcpServers", {
115762
- command,
115763
- args: []
115764
- });
115996
+ return registerJsonMcpServer(agent, join65(homedir10(), ".gemini", "settings.json"), "mcpServers", server2);
115765
115997
  case "pi":
115766
- return registerJsonMcpServer(agent, join65(homedir10(), ".pi", "agent", "mcp.json"), "mcpServers", {
115767
- command,
115768
- args: []
115769
- });
115998
+ return registerJsonMcpServer(agent, join65(homedir10(), ".pi", "agent", "mcp.json"), "mcpServers", server2);
115770
115999
  case "opencode":
115771
- return registerOpenCodeMcp(command);
116000
+ return registerOpenCodeMcp(command, environment);
115772
116001
  case "cursor":
115773
- return registerJsonMcpServer(agent, join65(homedir10(), ".cursor", "mcp.json"), "mcpServers", {
115774
- command,
115775
- args: []
115776
- });
116002
+ return registerJsonMcpServer(agent, join65(homedir10(), ".cursor", "mcp.json"), "mcpServers", server2);
115777
116003
  case "windsurf":
115778
- return registerJsonMcpServer(agent, join65(homedir10(), ".windsurf", "mcp.json"), "mcpServers", {
115779
- command,
115780
- args: []
115781
- });
116004
+ return registerJsonMcpServer(agent, join65(homedir10(), ".windsurf", "mcp.json"), "mcpServers", server2);
115782
116005
  default:
115783
116006
  return { agent, success: false, error: `Unknown agent: ${agent}. Available: ${AGENT_TARGETS.join(", ")}, all` };
115784
116007
  }
115785
116008
  }
115786
- async function registerClaudeMcp(command) {
115787
- 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 };
115788
116013
  try {
115789
- const proc = Bun.spawn(["claude", "mcp", "add", "-s", "user", MCP_SERVER_NAME, "--", command], {
115790
- stdout: "pipe",
115791
- 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;
115792
116026
  });
115793
- const [stdout, stderr, exitCode] = await Promise.all([
115794
- new Response(proc.stdout).text(),
115795
- new Response(proc.stderr).text(),
115796
- proc.exited
115797
- ]);
115798
- if (exitCode === 0) {
115799
- 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;
115800
116049
  }
115801
- const fallback = registerJsonMcpServer("claude", join65(homedir10(), ".claude", ".mcp.json"), "mcpServers", {
115802
- command,
115803
- args: []
115804
- });
115805
- return {
115806
- ...fallback,
115807
- command: cliCommand,
115808
- error: fallback.success ? undefined : `claude exited with ${exitCode}: ${(stderr || stdout).trim()}`
115809
- };
115810
- } catch (err) {
115811
- const fallback = registerJsonMcpServer("claude", join65(homedir10(), ".claude", ".mcp.json"), "mcpServers", {
115812
- command,
115813
- 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 };
115814
116079
  });
116080
+ } catch {
115815
116081
  return {
115816
- ...fallback,
116082
+ agent: "claude",
116083
+ success: false,
115817
116084
  command: cliCommand,
115818
- 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"
115819
116086
  };
115820
116087
  }
115821
116088
  }
115822
- 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) {
115823
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(", ")} }` : ""}`;
115824
116148
  const config2 = `[mcp_servers.${MCP_SERVER_NAME}]
115825
- command = ${JSON.stringify(command)}`;
116149
+ ${body}`;
115826
116150
  try {
115827
116151
  const current = existsSync33(path) ? readFileSync42(path, "utf-8") : "";
115828
- 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);
115829
116158
  return { agent: "codex", success: true, path, config: config2 };
115830
116159
  } catch (err) {
115831
- 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" };
115832
116161
  }
115833
116162
  }
115834
- function registerOpenCodeMcp(command) {
116163
+ function registerOpenCodeMcp(command, environment) {
115835
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
+ };
115836
116171
  const config2 = JSON.stringify({
115837
116172
  $schema: "https://opencode.ai/config.json",
115838
116173
  mcp: {
115839
- [MCP_SERVER_NAME]: {
115840
- type: "local",
115841
- command: [command],
115842
- enabled: true
115843
- }
116174
+ [MCP_SERVER_NAME]: server2
115844
116175
  }
115845
116176
  }, null, 2);
115846
116177
  try {
@@ -115848,16 +116179,12 @@ function registerOpenCodeMcp(command) {
115848
116179
  if (!data.$schema)
115849
116180
  data.$schema = "https://opencode.ai/config.json";
115850
116181
  const mcp = isPlainObject4(data.mcp) ? data.mcp : {};
115851
- mcp[MCP_SERVER_NAME] = {
115852
- type: "local",
115853
- command: [command],
115854
- enabled: true
115855
- };
116182
+ mcp[MCP_SERVER_NAME] = server2;
115856
116183
  data.mcp = mcp;
115857
116184
  writeJsonObject(path, data);
115858
116185
  return { agent: "opencode", success: true, path, config: config2 };
115859
116186
  } catch (err) {
115860
- 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" };
115861
116188
  }
115862
116189
  }
115863
116190
  function registerJsonMcpServer(agent, path, containerKey, server2) {
@@ -115870,7 +116197,7 @@ function registerJsonMcpServer(agent, path, containerKey, server2) {
115870
116197
  writeJsonObject(path, data);
115871
116198
  return { agent, success: true, path, config: config2 };
115872
116199
  } catch (err) {
115873
- 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" };
115874
116201
  }
115875
116202
  }
115876
116203
  function readJsonObject2(path) {
@@ -115897,24 +116224,37 @@ function writeTextFile(path, content) {
115897
116224
  function upsertTomlSection(content, header, body) {
115898
116225
  const sectionLines = [header, ...body.trim().split(/\r?\n/)];
115899
116226
  const lines = content.trimEnd() ? content.trimEnd().split(/\r?\n/) : [];
115900
- const start = lines.findIndex((line) => line.trim() === header);
115901
- if (start === -1) {
115902
- const prefix = lines.length ? [...lines, ""] : [];
115903
- return [...prefix, ...sectionLines, ""].join(`
115904
- `);
115905
- }
115906
- let end = lines.length;
115907
- for (let i = start + 1;i < lines.length; i++) {
115908
- if (/^\s*\[[^\]]+\]\s*$/.test(lines[i])) {
115909
- end = i;
115910
- 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
+ }
115911
116236
  }
116237
+ if (!owned)
116238
+ result2.push(line);
115912
116239
  }
115913
- lines.splice(start, end - start, ...sectionLines);
115914
- return `${lines.join(`
116240
+ if (!inserted)
116241
+ result2.push(...result2.length ? [""] : [], ...sectionLines);
116242
+ return `${result2.join(`
115915
116243
  `)}
115916
116244
  `;
115917
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
+ }
115918
116258
  function findCommandOnPath(command) {
115919
116259
  const pathValue = process.env.PATH || "";
115920
116260
  for (const dir of pathValue.split(":")) {
@@ -115933,6 +116273,8 @@ var MCP_SERVER_NAME = "skills", MCP_COMMAND_NAME = "skills-mcp";
115933
116273
  var init_runtime_mcp = __esm(() => {
115934
116274
  init_source();
115935
116275
  init_installer();
116276
+ init_credential_profile_command();
116277
+ init_mcp_registration_environment();
115936
116278
  });
115937
116279
 
115938
116280
  // src/cli/commands/remote-account.ts
@@ -116126,7 +116468,7 @@ var init_reviewed_runtime_lock = __esm(() => {
116126
116468
  });
116127
116469
 
116128
116470
  // src/cli/commands/runtime-copyfile.ts
116129
- import { createHash as createHash40, randomUUID as randomUUID10 } from "crypto";
116471
+ import { createHash as createHash40, randomUUID as randomUUID11 } from "crypto";
116130
116472
  import { Readable } from "stream";
116131
116473
  import { createGunzip as createGunzip2 } from "zlib";
116132
116474
  import { spawnSync as spawnSync6 } from "child_process";
@@ -116134,16 +116476,16 @@ import {
116134
116476
  chmodSync as chmodSync4,
116135
116477
  copyFileSync,
116136
116478
  existsSync as existsSync34,
116137
- lstatSync as lstatSync39,
116479
+ lstatSync as lstatSync40,
116138
116480
  mkdirSync as mkdirSync27,
116139
116481
  readFileSync as readFileSync43,
116140
116482
  readdirSync as readdirSync24,
116141
116483
  readlinkSync as readlinkSync8,
116142
116484
  realpathSync as realpathSync19,
116143
- renameSync as renameSync14,
116485
+ renameSync as renameSync15,
116144
116486
  writeFileSync as writeFileSync24
116145
116487
  } from "fs";
116146
- 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";
116147
116489
  function oldLauncherState(item) {
116148
116490
  if (item.oldShape === "pinned")
116149
116491
  return { shape: "pinned", runtime: item.oldRuntime, cwd: item.oldCwd, target: item.oldTarget, sha256: item.oldSha256, format: item.oldFormat, profile: item.oldProfile };
@@ -116169,7 +116511,7 @@ function assertLauncherRecordShapes(item, expectedProfile) {
116169
116511
  throw new Error("RECEIPT_LAUNCHER_SHAPE_INVALID");
116170
116512
  continue;
116171
116513
  }
116172
- 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)) {
116173
116515
  throw new Error("RECEIPT_LAUNCHER_SHAPE_INVALID");
116174
116516
  }
116175
116517
  const target = side === "old" ? item.oldTarget : item.newTarget;
@@ -116197,7 +116539,7 @@ function verifyTargetPrerequisites(manifest, packageRoot, home, cwd2, pathValue)
116197
116539
  throw new Error("RUNTIME_PREREQUISITE_CONTRACT_INVALID");
116198
116540
  }
116199
116541
  const entry = join66(packageRoot, contract.entry);
116200
- if (!entryExists(entry) || !lstatSync39(entry).isFile() || lstatSync39(entry).isSymbolicLink())
116542
+ if (!entryExists(entry) || !lstatSync40(entry).isFile() || lstatSync40(entry).isSymbolicLink())
116201
116543
  throw new Error("RUNTIME_PREREQUISITE_ENTRY_MISSING");
116202
116544
  const entrySha256 = hash6(readFileSync43(entry));
116203
116545
  const env3 = { HOME: home, PATH: pathValue, BUN_RUNTIME_TRANSPILER_CACHE_PATH: "0" };
@@ -116256,11 +116598,11 @@ function hash6(bytes) {
116256
116598
  }
116257
116599
  function isWithin(parent, child2) {
116258
116600
  const rel = relative13(parent, child2);
116259
- return rel === "" || !rel.startsWith(`..${sep18}`) && rel !== ".." && !isAbsolute37(rel);
116601
+ return rel === "" || !rel.startsWith(`..${sep18}`) && rel !== ".." && !isAbsolute39(rel);
116260
116602
  }
116261
116603
  function entryExists(path) {
116262
116604
  try {
116263
- lstatSync39(path);
116605
+ lstatSync40(path);
116264
116606
  return true;
116265
116607
  } catch {
116266
116608
  return false;
@@ -116272,7 +116614,7 @@ function assertNoSymlinkAncestors(path) {
116272
116614
  let current = sep18;
116273
116615
  for (const part of parts) {
116274
116616
  current = join66(current, part);
116275
- const stat3 = lstatSync39(current);
116617
+ const stat3 = lstatSync40(current);
116276
116618
  if (stat3.isSymbolicLink())
116277
116619
  throw new Error("PATH_ANCESTOR_SYMLINK_UNSUPPORTED");
116278
116620
  if (!stat3.isDirectory())
@@ -116287,17 +116629,17 @@ function acquireRuntimeLock(runtimeRoot) {
116287
116629
  throw new Error("RUNTIME_UPDATE_LOCKED");
116288
116630
  }
116289
116631
  try {
116290
- 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() });
116291
116633
  } catch {
116292
116634
  try {
116293
- renameSync14(lockPath, join66(runtimeRoot, `.copyfile-update-lock-incomplete-${randomUUID10()}`));
116635
+ renameSync15(lockPath, join66(runtimeRoot, `.copyfile-update-lock-incomplete-${randomUUID11()}`));
116294
116636
  } catch {}
116295
116637
  throw new Error("RUNTIME_LOCK_INITIALIZATION_FAILED");
116296
116638
  }
116297
116639
  return () => {
116298
- const released = join66(runtimeRoot, `.copyfile-update-lock-released-${randomUUID10()}`);
116640
+ const released = join66(runtimeRoot, `.copyfile-update-lock-released-${randomUUID11()}`);
116299
116641
  writeJsonPrivate(join66(lockPath, "released.json"), { completedAt: new Date().toISOString() });
116300
- renameSync14(lockPath, released);
116642
+ renameSync15(lockPath, released);
116301
116643
  };
116302
116644
  }
116303
116645
  function packageBins(pkg) {
@@ -116305,7 +116647,7 @@ function packageBins(pkg) {
116305
116647
  const entries = typeof raw === "string" ? [[PACKAGE_NAME.slice(PACKAGE_NAME.lastIndexOf("/") + 1), raw]] : raw && typeof raw === "object" && !Array.isArray(raw) ? Object.entries(raw) : [];
116306
116648
  const output2 = {};
116307
116649
  for (const [name, value] of entries) {
116308
- 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)) {
116309
116651
  throw new Error("PACKAGE_BIN_INVALID");
116310
116652
  }
116311
116653
  const normalized2 = value.replaceAll("\\", "/");
@@ -116333,7 +116675,7 @@ function resolveRuntimeLayout(homeInput, pathInput) {
116333
116675
  const home = realpathSync19(homeInput);
116334
116676
  const runtimeRoot = join66(home, ".hasna", "skills", "runtime");
116335
116677
  assertNoSymlinkAncestors(runtimeRoot);
116336
- const runtimeRootStat = lstatSync39(runtimeRoot);
116678
+ const runtimeRootStat = lstatSync40(runtimeRoot);
116337
116679
  if (!runtimeRootStat.isDirectory() || runtimeRootStat.isSymbolicLink() || (runtimeRootStat.mode & 63) !== 0) {
116338
116680
  throw new Error("RUNTIME_ROOT_NOT_PRIVATE");
116339
116681
  }
@@ -116392,7 +116734,7 @@ function resolveRuntimeLayout(homeInput, pathInput) {
116392
116734
  if (actual !== join66(currentPackageRoot, target))
116393
116735
  continue;
116394
116736
  const newTarget = join66(runtimeRoot, "__target__", "node_modules", "@hasna", "skills", target);
116395
- const backupPath = `${path}.skills-prev-${randomUUID10()}`;
116737
+ const backupPath = `${path}.skills-prev-${randomUUID11()}`;
116396
116738
  if (launcher.kind === "symlink") {
116397
116739
  if (resolve36(dirname40(path), launcher.linkTarget) !== actual)
116398
116740
  throw new Error("LAUNCHER_SYMLINK_CHAIN_UNSUPPORTED");
@@ -116605,7 +116947,7 @@ function readTree(root2, includeModes, excludeNpmDependencies = false) {
116605
116947
  for (const item of readdirSync24(dir).sort()) {
116606
116948
  const path = join66(dir, item);
116607
116949
  const rel = prefix ? `${prefix}/${item}` : item;
116608
- const stat3 = lstatSync39(path);
116950
+ const stat3 = lstatSync40(path);
116609
116951
  if (excludeNpmDependencies && !prefix && item === "node_modules") {
116610
116952
  if (!stat3.isDirectory() || stat3.isSymbolicLink())
116611
116953
  throw new Error("INSTALLED_DEPENDENCY_DIRECTORY_UNSAFE");
@@ -116641,14 +116983,14 @@ function readTree(root2, includeModes, excludeNpmDependencies = false) {
116641
116983
  return { entries, digest: hash6(new TextEncoder().encode(JSON.stringify(entries))) };
116642
116984
  }
116643
116985
  function normalizeModes(root2) {
116644
- const rootStat = lstatSync39(root2);
116986
+ const rootStat = lstatSync40(root2);
116645
116987
  if (!rootStat.isDirectory() || rootStat.isSymbolicLink())
116646
116988
  throw new Error("RUNTIME_ENTRY_TYPE_UNSUPPORTED");
116647
116989
  chmodSync4(root2, rootStat.mode & 493);
116648
116990
  const walk2 = (dir) => {
116649
116991
  for (const item of readdirSync24(dir)) {
116650
116992
  const path = join66(dir, item);
116651
- const stat3 = lstatSync39(path);
116993
+ const stat3 = lstatSync40(path);
116652
116994
  if (stat3.isSymbolicLink())
116653
116995
  continue;
116654
116996
  if (stat3.isDirectory()) {
@@ -116698,7 +117040,7 @@ function verifyPreimageManifest(runtimePath, receipt, home) {
116698
117040
  throw new Error("PREIMAGE_CONFIG_BINDING_INVALID");
116699
117041
  if (config2.present) {
116700
117042
  const backup = join66(runtimePath, "preimage", "configs", relativePath);
116701
- const stat3 = lstatSync39(backup);
117043
+ const stat3 = lstatSync40(backup);
116702
117044
  const saved = readFileSync43(backup);
116703
117045
  if (!stat3.isFile() || stat3.isSymbolicLink() || hash6(saved) !== config2.sha256 || saved.byteLength !== config2.byteSize)
116704
117046
  throw new Error("PREIMAGE_CONFIG_DRIFT");
@@ -116712,7 +117054,7 @@ function captureConfigPreimages(home, stage) {
116712
117054
  const sourcePath = join66(home, relativePath);
116713
117055
  if (!entryExists(sourcePath))
116714
117056
  return { sourcePath, relativePath, present: false };
116715
- const stat3 = lstatSync39(sourcePath);
117057
+ const stat3 = lstatSync40(sourcePath);
116716
117058
  if (!stat3.isFile() || stat3.isSymbolicLink())
116717
117059
  throw new Error("CONFIG_PREIMAGE_NOT_REGULAR_FILE");
116718
117060
  const bytes = readFileSync43(sourcePath);
@@ -116732,7 +117074,7 @@ function assertConfigUnchanged(configs) {
116732
117074
  if (present2 !== config2.present)
116733
117075
  throw new Error("CONFIG_DRIFT_DURING_UPDATE");
116734
117076
  if (present2) {
116735
- const stat3 = lstatSync39(config2.sourcePath);
117077
+ const stat3 = lstatSync40(config2.sourcePath);
116736
117078
  if (!stat3.isFile() || stat3.isSymbolicLink() || hash6(readFileSync43(config2.sourcePath)) !== config2.sha256) {
116737
117079
  throw new Error("CONFIG_DRIFT_DURING_UPDATE");
116738
117080
  }
@@ -116831,7 +117173,7 @@ function replaceLauncher(item) {
116831
117173
  const oldState = oldLauncherState(item), newState = newLauncherState(item);
116832
117174
  if (!launcherIs(item.path, oldState) || entryExists(item.backupPath))
116833
117175
  throw new Error("LAUNCHER_PREIMAGE_DRIFT");
116834
- const temp = `${item.path}.skills-next-${randomUUID10()}`;
117176
+ const temp = `${item.path}.skills-next-${randomUUID11()}`;
116835
117177
  try {
116836
117178
  materializeLauncher(item.backupPath, oldState);
116837
117179
  } catch {
@@ -116846,15 +117188,15 @@ function replaceLauncher(item) {
116846
117188
  }
116847
117189
  if (!launcherIs(temp, newState))
116848
117190
  throw new Error("LAUNCHER_NEW_LINK_READBACK_MISMATCH");
116849
- renameSync14(temp, item.path);
117191
+ renameSync15(temp, item.path);
116850
117192
  }
116851
117193
  function atomicJson(path, value) {
116852
- const temp = `${path}.next-${randomUUID10()}`;
117194
+ const temp = `${path}.next-${randomUUID11()}`;
116853
117195
  const bytes = Buffer.from(`${JSON.stringify(value, null, 2)}
116854
117196
  `);
116855
117197
  writeFileSync24(temp, bytes, { flag: "wx", mode: 384 });
116856
117198
  chmodSync4(temp, 384);
116857
- renameSync14(temp, path);
117199
+ renameSync15(temp, path);
116858
117200
  if (!readFileSync43(path).equals(bytes))
116859
117201
  throw new Error("RECEIPT_READBACK_MISMATCH");
116860
117202
  }
@@ -116871,10 +117213,10 @@ function persistReceipt(path, value) {
116871
117213
  const historyRoot = join66(dirname40(path), "receipt-history");
116872
117214
  if (!entryExists(historyRoot))
116873
117215
  mkdirSync27(historyRoot, { mode: 448 });
116874
- const historyStat = lstatSync39(historyRoot);
117216
+ const historyStat = lstatSync40(historyRoot);
116875
117217
  if (!historyStat.isDirectory() || historyStat.isSymbolicLink() || (historyStat.mode & 63) !== 0)
116876
117218
  throw new Error("RECEIPT_HISTORY_NOT_PRIVATE");
116877
- const historyPath = join66(historyRoot, `${value.id}-${String(prior.state)}-${randomUUID10()}.json`);
117219
+ const historyPath = join66(historyRoot, `${value.id}-${String(prior.state)}-${randomUUID11()}.json`);
116878
117220
  writeFileSync24(historyPath, priorBytes, { flag: "wx", mode: 256 });
116879
117221
  chmodSync4(historyPath, 256);
116880
117222
  if (!readFileSync43(historyPath).equals(priorBytes))
@@ -116895,10 +117237,10 @@ function persistAliasReceipt(path, value) {
116895
117237
  const history = join66(dirname40(path), "history");
116896
117238
  if (!entryExists(history))
116897
117239
  mkdirSync27(history, { mode: 448 });
116898
- const historyStat = lstatSync39(history);
117240
+ const historyStat = lstatSync40(history);
116899
117241
  if (!historyStat.isDirectory() || historyStat.isSymbolicLink() || (historyStat.mode & 63) !== 0)
116900
117242
  throw new Error("ALIAS_RECEIPT_HISTORY_UNSAFE");
116901
- const saved = join66(history, `${value.id}-${String(prior.state)}-${randomUUID10()}.json`);
117243
+ const saved = join66(history, `${value.id}-${String(prior.state)}-${randomUUID11()}.json`);
116902
117244
  writeFileSync24(saved, priorBytes, { flag: "wx", mode: 256 });
116903
117245
  chmodSync4(saved, 256);
116904
117246
  if (!readFileSync43(saved).equals(priorBytes))
@@ -116909,7 +117251,7 @@ function persistAliasReceipt(path, value) {
116909
117251
  function assertOwnedSafePath(path, home, requireWritable = false) {
116910
117252
  assertNoSymlinkAncestors(path);
116911
117253
  for (let current = path;; current = dirname40(current)) {
116912
- const stat3 = lstatSync39(current);
117254
+ const stat3 = lstatSync40(current);
116913
117255
  if (!stat3.isDirectory() || ![0, process.getuid?.() ?? -1].includes(stat3.uid) || stat3.mode & 18)
116914
117256
  throw new Error("ALIAS_PATH_UNSAFE");
116915
117257
  if (current === path && requireWritable && (stat3.uid !== (process.getuid?.() ?? -1) || (stat3.mode & 128) === 0))
@@ -116957,7 +117299,7 @@ function inspectAliasPackageChain(home, aliasPath, oldLinkTarget, oldTarget, bin
116957
117299
  assertOwnedSafePath(dirname40(packageLinkPath), home);
116958
117300
  let stat3, packageLinkTarget, resolved;
116959
117301
  try {
116960
- stat3 = lstatSync39(packageLinkPath);
117302
+ stat3 = lstatSync40(packageLinkPath);
116961
117303
  packageLinkTarget = readlinkSync8(packageLinkPath);
116962
117304
  resolved = realpathSync19(packageLinkPath);
116963
117305
  } catch {
@@ -116980,7 +117322,7 @@ function validateAliasSource(home, name, actual) {
116980
117322
  }
116981
117323
  assertOwnedSafePath(packageRoot, home);
116982
117324
  const manifestPath = join66(packageRoot, "package.json");
116983
- const manifestStat = lstatSync39(manifestPath), binaryStat = lstatSync39(actual);
117325
+ const manifestStat = lstatSync40(manifestPath), binaryStat = lstatSync40(actual);
116984
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)
116985
117327
  throw new Error("ALIAS_SOURCE_UNSAFE");
116986
117328
  const pkg = readPackage(manifestPath);
@@ -116996,7 +117338,7 @@ function adoptCopyfileAliases(options = {}) {
116996
117338
  const launcherRuntime = pinnedLauncherRuntime();
116997
117339
  pinnedLauncherState(launcherRuntime, currentRuntime, join66(layout.currentPackageRoot, layout.bin.skills ?? "bin/index.js"));
116998
117340
  const releaseLock = acquireRuntimeLock(layout.runtimeRoot);
116999
- const id2 = randomUUID10();
117341
+ const id2 = randomUUID11();
117000
117342
  const aliases = [];
117001
117343
  const receiptDir = join66(currentRuntime, "alias-adoptions");
117002
117344
  const receiptPath = join66(receiptDir, `${id2}.json`);
@@ -117013,7 +117355,7 @@ function adoptCopyfileAliases(options = {}) {
117013
117355
  if (!entryExists(path))
117014
117356
  continue;
117015
117357
  assertOwnedSafePath(dir, home, true);
117016
- const stat3 = lstatSync39(path);
117358
+ const stat3 = lstatSync40(path);
117017
117359
  if (stat3.uid !== (process.getuid?.() ?? -1))
117018
117360
  throw new Error("ALIAS_LINK_NOT_OWNED");
117019
117361
  let launcher;
@@ -117052,7 +117394,7 @@ function adoptCopyfileAliases(options = {}) {
117052
117394
  if (!aliases.length)
117053
117395
  return { adopted: true, version: layout.currentVersion, aliasCount: 0 };
117054
117396
  mkdirSync27(receiptDir, { recursive: true, mode: 448 });
117055
- const receiptDirStat = lstatSync39(receiptDir);
117397
+ const receiptDirStat = lstatSync40(receiptDir);
117056
117398
  if (!receiptDirStat.isDirectory() || receiptDirStat.isSymbolicLink() || receiptDirStat.mode & 63)
117057
117399
  throw new Error("ALIAS_RECEIPT_DIRECTORY_UNSAFE");
117058
117400
  receipt = {
@@ -117117,9 +117459,9 @@ function adoptCopyfileAliases(options = {}) {
117117
117459
  if (entryExists(after2))
117118
117460
  throw new Error("ALIAS_AFTER_COLLISION");
117119
117461
  materializeLauncher(after2, newLauncherState(item));
117120
- const temp = `${item.path}.skills-alias-rollback-${randomUUID10()}`;
117462
+ const temp = `${item.path}.skills-alias-rollback-${randomUUID11()}`;
117121
117463
  materializeLauncher(temp, oldLauncherState(item));
117122
- renameSync14(temp, item.path);
117464
+ renameSync15(temp, item.path);
117123
117465
  if (!launcherIs(item.path, oldLauncherState(item)))
117124
117466
  throw new Error("ALIAS_ROLLBACK_READBACK_MISMATCH");
117125
117467
  receipt.rollbackCompletedAliases = [...receipt.rollbackCompletedAliases, item.path];
@@ -117170,7 +117512,7 @@ function rollbackCopyfileAliases(receiptId, options = {}) {
117170
117512
  const source = validateAliasSource(home, name, item.oldTarget);
117171
117513
  if (source.version !== item.oldVersion || source.binarySha256 !== item.oldBinarySha256)
117172
117514
  throw new Error("ALIAS_PREIMAGE_DRIFT");
117173
- const stat3 = lstatSync39(item.path);
117515
+ const stat3 = lstatSync40(item.path);
117174
117516
  if (stat3.uid !== (process.getuid?.() ?? -1))
117175
117517
  throw new Error("ALIAS_LINK_DRIFT");
117176
117518
  let current;
@@ -117205,9 +117547,9 @@ function rollbackCopyfileAliases(receiptId, options = {}) {
117205
117547
  throw new Error("ALIAS_AFTER_DRIFT");
117206
117548
  if (launcherTarget(item.path) !== item.newTarget)
117207
117549
  throw new Error("ALIAS_TARGET_DRIFT");
117208
- const temp = `${item.path}.skills-alias-rollback-${randomUUID10()}`;
117550
+ const temp = `${item.path}.skills-alias-rollback-${randomUUID11()}`;
117209
117551
  materializeLauncher(temp, oldLauncherState(item));
117210
- renameSync14(temp, item.path);
117552
+ renameSync15(temp, item.path);
117211
117553
  if (!launcherIs(item.path, oldLauncherState(item)))
117212
117554
  throw new Error("ALIAS_ROLLBACK_READBACK_MISMATCH");
117213
117555
  receipt.rollbackCompletedAliases = [...new Set([...receipt.rollbackCompletedAliases, item.path])];
@@ -117236,10 +117578,10 @@ async function updateCopyfileRuntime(version2, options = {}) {
117236
117578
  throw new Error("REVIEWED_LOCK_INPUT_PAIR_REQUIRED");
117237
117579
  if (!policy)
117238
117580
  throw new Error("REVIEWED_LOCK_RELEASE_AGE_REQUIRED");
117239
- if (!isAbsolute37(options.reviewedLock))
117581
+ if (!isAbsolute39(options.reviewedLock))
117240
117582
  throw new Error("REVIEWED_LOCK_ABSOLUTE_PATH_REQUIRED");
117241
117583
  assertNoSymlinkAncestors(dirname40(options.reviewedLock));
117242
- const stat3 = lstatSync39(options.reviewedLock);
117584
+ const stat3 = lstatSync40(options.reviewedLock);
117243
117585
  if (!stat3.isFile() || stat3.isSymbolicLink() || stat3.nlink !== 1 || stat3.uid !== process.getuid?.() || stat3.mode & 63 || stat3.size > 8 * 1024 * 1024)
117244
117586
  throw new Error("REVIEWED_LOCK_FILE_UNSAFE");
117245
117587
  reviewedLockBytes = readFileSync43(options.reviewedLock);
@@ -117260,10 +117602,10 @@ async function updateCopyfileRuntime(version2, options = {}) {
117260
117602
  throw new Error("REGISTRY_ORIGIN_INVALID");
117261
117603
  if (origin.username || origin.password || origin.search || origin.hash)
117262
117604
  throw new Error("REGISTRY_ORIGIN_INVALID");
117263
- const runtimeRootStat = lstatSync39(layout.runtimeRoot);
117605
+ const runtimeRootStat = lstatSync40(layout.runtimeRoot);
117264
117606
  if ((runtimeRootStat.mode & 63) !== 0)
117265
117607
  throw new Error("RUNTIME_ROOT_NOT_PRIVATE");
117266
- const id2 = randomUUID10();
117608
+ const id2 = randomUUID11();
117267
117609
  const stagePath = join66(layout.runtimeRoot, `.stage-${version2}-${id2}`);
117268
117610
  const finalPath = join66(layout.runtimeRoot, `${version2}-copyfile`);
117269
117611
  const launcherRuntime = pinnedLauncherRuntime();
@@ -117376,7 +117718,7 @@ async function updateCopyfileRuntime(version2, options = {}) {
117376
117718
  persistReceipt(join66(stagePath, "rollout-receipt.json"), receipt);
117377
117719
  const finalNodeModules = join66(stagePackage, "node_modules");
117378
117720
  const stagedNodeModules = join66(stagePath, "node_modules");
117379
- renameSync14(finalNodeModules, stagedNodeModules);
117721
+ renameSync15(finalNodeModules, stagedNodeModules);
117380
117722
  copyFileSync(join66(stagePackage, "package-lock.json"), join66(stagePath, "install-lock.json"));
117381
117723
  chmodSync4(join66(stagePath, "install-lock.json"), 384);
117382
117724
  const stagedTree = readTree(stagedNodeModules, true);
@@ -117385,7 +117727,7 @@ async function updateCopyfileRuntime(version2, options = {}) {
117385
117727
  receipt.targetPackageRoot = join66(finalPath, "node_modules", "@hasna", "skills");
117386
117728
  receipt.runtimeTreeSha256 = stagedTree.digest;
117387
117729
  persistReceipt(join66(stagePath, "rollout-receipt.json"), receipt);
117388
- renameSync14(stagePath, finalPath);
117730
+ renameSync15(stagePath, finalPath);
117389
117731
  moved = true;
117390
117732
  const finalReceiptBytes = Buffer.from(`${JSON.stringify(receipt, null, 2)}
117391
117733
  `);
@@ -117423,7 +117765,7 @@ async function updateCopyfileRuntime(version2, options = {}) {
117423
117765
  throw new Error("ROLLBACK_PRESERVATION_PATH_EXISTS");
117424
117766
  materializeLauncher(afterPath, newLauncherState(item));
117425
117767
  materializeLauncher(temp, oldLauncherState(item));
117426
- renameSync14(temp, item.path);
117768
+ renameSync15(temp, item.path);
117427
117769
  } catch {
117428
117770
  rollbackFailed = true;
117429
117771
  }
@@ -117451,7 +117793,7 @@ function rollbackCopyfileRuntime(receiptId, options = {}) {
117451
117793
  throw new Error("HOME_NOT_FOUND");
117452
117794
  const runtimeRoot = join66(realpathSync19(home), ".hasna", "skills", "runtime");
117453
117795
  assertNoSymlinkAncestors(runtimeRoot);
117454
- const rootStat = lstatSync39(runtimeRoot);
117796
+ const rootStat = lstatSync40(runtimeRoot);
117455
117797
  if (!rootStat.isDirectory() || rootStat.isSymbolicLink() || (rootStat.mode & 63) !== 0)
117456
117798
  throw new Error("RUNTIME_ROOT_NOT_PRIVATE");
117457
117799
  const releaseLock = acquireRuntimeLock(runtimeRoot);
@@ -117492,7 +117834,7 @@ function rollbackCopyfileRuntime(receiptId, options = {}) {
117492
117834
  const seen = new Set;
117493
117835
  for (const item of receipt.launchers) {
117494
117836
  const bin = oldBins[basename21(item.path)];
117495
- 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)
117496
117838
  throw new Error("RECEIPT_LAUNCHER_BINDING_INVALID");
117497
117839
  assertNoSymlinkAncestors(dirname40(item.path));
117498
117840
  assertLauncherRecordShapes(item, launcherProfileForBin(basename21(item.path), bin));
@@ -117524,9 +117866,9 @@ function rollbackCopyfileRuntime(receiptId, options = {}) {
117524
117866
  const afterPath = `${item.path}.skills-after-${receiptId}`;
117525
117867
  if (!entryExists(afterPath))
117526
117868
  materializeLauncher(afterPath, newLauncherState(item));
117527
- const temp = `${item.path}.skills-rollback-${receiptId}-${randomUUID10()}`;
117869
+ const temp = `${item.path}.skills-rollback-${receiptId}-${randomUUID11()}`;
117528
117870
  materializeLauncher(temp, oldLauncherState(item));
117529
- renameSync14(temp, item.path);
117871
+ renameSync15(temp, item.path);
117530
117872
  receipt.rollbackCompletedLaunchers = [...new Set([...receipt.rollbackCompletedLaunchers, item.path])];
117531
117873
  persistReceipt(receiptPath, receipt);
117532
117874
  }
@@ -117559,9 +117901,9 @@ __export(exports_runtime, {
117559
117901
  selectedSkillsCommand: () => selectedSkillsCommand,
117560
117902
  registerRuntime: () => registerRuntime
117561
117903
  });
117562
- import { createHash as createHash41, randomUUID as randomUUID11 } from "crypto";
117563
- import { lstatSync as lstatSync40, mkdirSync as mkdirSync28, readFileSync as readFileSync44, writeFileSync as writeFileSync25 } from "fs";
117564
- 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";
117565
117907
  import { createInterface } from "readline";
117566
117908
  function registerRuntime(parent) {
117567
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) => {
@@ -117629,7 +117971,11 @@ function registerRuntime(parent) {
117629
117971
  await handleMcp(options);
117630
117972
  }));
117631
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));
117632
- 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
+ }));
117633
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) => {
117634
117980
  if ((options.reviewedLock !== undefined || options.reviewedLockSha256 !== undefined) && (!options.version || options.rollback || options.adoptAliases || options.rollbackAliases)) {
117635
117981
  console.error(JSON.stringify({ error: "REVIEWED_LOCK_REQUIRES_EXACT_VERSION" }));
@@ -117760,7 +118106,7 @@ Updating ${name}...
117760
118106
  async function readUpdatedVersion(bunExecutable) {
117761
118107
  const output2 = await readUpdateCommand([bunExecutable, "pm", "bin", "-g"]);
117762
118108
  const globalBin = output2.replace(/\r?\n$/, "");
117763
- if (!globalBin || !isAbsolute38(globalBin) || /[\r\n\0]/.test(globalBin))
118109
+ if (!globalBin || !isAbsolute40(globalBin) || /[\r\n\0]/.test(globalBin))
117764
118110
  throw new Error("Update bin discovery failed");
117765
118111
  const installed = Bun.which("skills", { PATH: globalBin, cwd: globalBin });
117766
118112
  const selected = Bun.which("skills");
@@ -118039,7 +118385,7 @@ async function handleRun(name, args2, options, separatorBeforeSkill) {
118039
118385
  if (!Number.isFinite(timeoutMs) || timeoutMs < 1 || timeoutMs > 1200000 || !Number.isFinite(intervalMs) || intervalMs < 100 || intervalMs > 60000)
118040
118386
  throw new Error("Invalid cloud polling bounds");
118041
118387
  const client3 = await CloudExecutionClient.configured();
118042
- 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);
118043
118389
  if (options.wait)
118044
118390
  console.error(JSON.stringify({ executionId: admitted.id, status: admitted.status }));
118045
118391
  const result3 = options.wait ? await client3.wait(admitted.id, { timeoutMs, intervalMs }) : admitted;
@@ -118096,7 +118442,7 @@ async function handleRun(name, args2, options, separatorBeforeSkill) {
118096
118442
  try {
118097
118443
  parsePollingOptions(options);
118098
118444
  inputFiles = (options.file ?? []).map((path) => {
118099
- const info = lstatSync40(path);
118445
+ const info = lstatSync41(path);
118100
118446
  if (!info.isFile() || info.size > 20 * 1024 * 1024)
118101
118447
  throw new Error("Input must be a regular file no larger than 20 MiB");
118102
118448
  return { name: basename22(path), bytes: new Uint8Array(readFileSync44(path)) };
@@ -118526,7 +118872,7 @@ function ensureSafeExportParent(root2, relativePath) {
118526
118872
  if (part)
118527
118873
  parent = join67(parent, part);
118528
118874
  try {
118529
- if (!lstatSync40(parent).isDirectory() || lstatSync40(parent).isSymbolicLink())
118875
+ if (!lstatSync41(parent).isDirectory() || lstatSync41(parent).isSymbolicLink())
118530
118876
  throw new Error("Unsafe artifact directory");
118531
118877
  } catch (error61) {
118532
118878
  if (error61.code !== "ENOENT")
@@ -118821,7 +119167,7 @@ var exports_recurring = {};
118821
119167
  __export(exports_recurring, {
118822
119168
  registerRecurringCommands: () => registerRecurringCommands
118823
119169
  });
118824
- 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";
118825
119171
  import { createInterface as createInterface2 } from "readline";
118826
119172
  function readRequest(path) {
118827
119173
  const fd = openSync29(path, constants28.O_RDONLY | constants28.O_NOFOLLOW | constants28.O_NONBLOCK);
@@ -118837,7 +119183,7 @@ function readRequest(path) {
118837
119183
  break;
118838
119184
  length += n2;
118839
119185
  }
118840
- const after2 = fstatSync29(fd), current = lstatSync41(path);
119186
+ const after2 = fstatSync29(fd), current = lstatSync42(path);
118841
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())
118842
119188
  throw new RecurringInputError;
118843
119189
  return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, length)));
@@ -119121,7 +119467,7 @@ var init_completion = __esm(() => {
119121
119467
  });
119122
119468
 
119123
119469
  // src/lib/portable-snapshot-filter.ts
119124
- import { readdirSync as readdirSync25, statSync as statSync22 } from "fs";
119470
+ import { readdirSync as readdirSync25, statSync as statSync23 } from "fs";
119125
119471
  import { homedir as homedir11 } from "os";
119126
119472
  import { join as join68, sep as sep19 } from "path";
119127
119473
  function isExcludedSkillFileName(fileName) {
@@ -119189,7 +119535,7 @@ function walkEntries(absoluteRoot) {
119189
119535
  }
119190
119536
  function isRegularFile(filePath) {
119191
119537
  try {
119192
- return statSync22(filePath).isFile();
119538
+ return statSync23(filePath).isFile();
119193
119539
  } catch {
119194
119540
  return false;
119195
119541
  }
@@ -119275,10 +119621,10 @@ import {
119275
119621
  copyFileSync as copyFileSync2,
119276
119622
  mkdirSync as mkdirSync29,
119277
119623
  readFileSync as readFileSync45,
119278
- statSync as statSync23,
119624
+ statSync as statSync24,
119279
119625
  writeFileSync as writeFileSync26
119280
119626
  } from "fs";
119281
- 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";
119282
119628
  function validateStationId(stationId) {
119283
119629
  if (!/^[a-z0-9-]+$/.test(stationId)) {
119284
119630
  throw new StationSnapshotError("INVALID_STATION", `station id must be a slug, got: ${stationId}`);
@@ -119315,7 +119661,7 @@ function scanHome(definition, homesRoot) {
119315
119661
  skipped.push({ relativePath: entry.relativePath, reason: "not-regular-file" });
119316
119662
  continue;
119317
119663
  }
119318
- const info = statSync23(entry.fullPath);
119664
+ const info = statSync24(entry.fullPath);
119319
119665
  portable.push({
119320
119666
  relativePath: entry.relativePath,
119321
119667
  fullPath: entry.fullPath,
@@ -119384,7 +119730,7 @@ function writeStationSnapshot(options) {
119384
119730
  for (const plan of plans) {
119385
119731
  const destination = resolve37(repoRoot, plan.destination);
119386
119732
  const destinationRelative = relative14(repoRoot, destination);
119387
- if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep20) || isAbsolute39(destinationRelative)) {
119733
+ if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep20) || isAbsolute41(destinationRelative)) {
119388
119734
  throw new StationSnapshotError("DESTINATION_ESCAPE", `destination escapes repo root: ${plan.destination}`);
119389
119735
  }
119390
119736
  let existingDigest = null;
@@ -119857,7 +120203,7 @@ var init_create_sync_config = __esm(() => {
119857
120203
  });
119858
120204
 
119859
120205
  // src/lib/agent-install-selection.ts
119860
- import { lstatSync as lstatSync42 } from "fs";
120206
+ import { lstatSync as lstatSync43 } from "fs";
119861
120207
  import { dirname as dirname43, join as join70, resolve as resolve38 } from "path";
119862
120208
  import { homedir as homedir12 } from "os";
119863
120209
  function detectedIntegrationAgents(options = {}) {
@@ -119871,7 +120217,7 @@ function detectedIntegrationAgents(options = {}) {
119871
120217
  throw new Error("Invalid existing bridge agent inventory");
119872
120218
  const present2 = (path) => {
119873
120219
  try {
119874
- return lstatSync42(path, { throwIfNoEntry: false }) !== undefined;
120220
+ return lstatSync43(path, { throwIfNoEntry: false }) !== undefined;
119875
120221
  } catch {
119876
120222
  throw new Error("Agent presence cannot be inspected; review native configuration before hook installation");
119877
120223
  }
@@ -119901,7 +120247,7 @@ var init_agent_install_selection = __esm(() => {
119901
120247
  });
119902
120248
 
119903
120249
  // src/lib/codex-native-config.ts
119904
- import { isDeepStrictEqual as isDeepStrictEqual16 } from "util";
120250
+ import { isDeepStrictEqual as isDeepStrictEqual17 } from "util";
119905
120251
  function isRecord8(value) {
119906
120252
  if (!value || typeof value !== "object")
119907
120253
  return false;
@@ -119923,7 +120269,7 @@ function decimalIdentity(text4) {
119923
120269
  return `${match[1]}${coefficient}e${exponent}`;
119924
120270
  }
119925
120271
  function codexNativeConfigEqual(native, expected) {
119926
- if (isDeepStrictEqual16(native, expected))
120272
+ if (isDeepStrictEqual17(native, expected))
119927
120273
  return true;
119928
120274
  if (typeof expected === "number") {
119929
120275
  if (!Number.isFinite(expected) || !isRecord8(native))
@@ -119947,11 +120293,11 @@ var NUMBER_TAG = "$serde_json::private::Number";
119947
120293
  var init_codex_native_config = () => {};
119948
120294
 
119949
120295
  // src/lib/codex-hook-trust-identity.ts
119950
- import { lstatSync as lstatSync43, realpathSync as realpathSync20 } from "fs";
119951
- import { dirname as dirname44, isAbsolute as isAbsolute40, join as join71, resolve as resolve39 } from "path";
119952
- 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";
119953
120299
  function commandPhysical(command) {
119954
- 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);
119955
120301
  const physical = realpathSync20(command);
119956
120302
  let spelled;
119957
120303
  try {
@@ -119962,7 +120308,7 @@ function commandPhysical(command) {
119962
120308
  safeParents(spelled);
119963
120309
  let direct = false;
119964
120310
  try {
119965
- const leaf = lstatSync43(spelled);
120311
+ const leaf = lstatSync44(spelled);
119966
120312
  direct = leaf.isSymbolicLink() ? trustedAncestorOwner(leaf.uid) && directAliasTarget(spelled) === physical : spelled === physical;
119967
120313
  } catch {}
119968
120314
  need8(direct, COMMAND_ALIAS_UNSAFE);
@@ -120006,7 +120352,7 @@ function targetUnchanged(command, target) {
120006
120352
  assertPinnedRuntime(target.runtime);
120007
120353
  }
120008
120354
  function inspectRecordedSkillsCli(command, expected) {
120009
- need8(isAbsolute40(command) && !command.includes("\x00"), "RECONCILE_RECORDED_COMMAND_REQUIRED");
120355
+ need8(isAbsolute42(command) && !command.includes("\x00"), "RECONCILE_RECORDED_COMMAND_REQUIRED");
120010
120356
  const target = skillsCommandTarget(command), resolved = target.entry;
120011
120357
  const cli = snapshot(resolved, false, { readOnlyPackage: true });
120012
120358
  const manifest = snapshot(join71(dirname44(dirname44(resolved)), "package.json"), false, { readOnlyPackage: true });
@@ -120014,7 +120360,7 @@ function inspectRecordedSkillsCli(command, expected) {
120014
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");
120015
120361
  need8((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
120016
120362
  const receipt = { path: resolved, version: pkg.version, sha256: cli.sha256, manifestSha256: manifest.sha256 };
120017
- need8(isDeepStrictEqual17(receipt, expected), "RECONCILE_SKILLS_BINDING_CHANGED");
120363
+ need8(isDeepStrictEqual18(receipt, expected), "RECONCILE_SKILLS_BINDING_CHANGED");
120018
120364
  return { receipt, recheck() {
120019
120365
  targetUnchanged(command, target);
120020
120366
  unchanged2(cli);
@@ -120025,7 +120371,7 @@ function bindSkillsCli(command, reviewed) {
120025
120371
  const normal = Bun.which("skills", { PATH: process.env.PATH });
120026
120372
  need8(normal, "SKILLS_COMMAND_UNAVAILABLE");
120027
120373
  const normalTarget = skillsCommandTarget(normal), resolved = normalTarget.entry;
120028
- const bound = isAbsolute40(command) ? command : command === "skills" ? normal : undefined;
120374
+ const bound = isAbsolute42(command) ? command : command === "skills" ? normal : undefined;
120029
120375
  need8(bound, "SKILLS_COMMAND_MISMATCH");
120030
120376
  const boundTarget = skillsCommandTarget(bound);
120031
120377
  need8(boundTarget.entry === resolved, "SKILLS_COMMAND_MISMATCH");
@@ -120084,19 +120430,19 @@ var init_codex_hook_trust_identity = __esm(() => {
120084
120430
  });
120085
120431
 
120086
120432
  // src/lib/codex-hook-policy-recovery.ts
120087
- import { isDeepStrictEqual as isDeepStrictEqual18 } from "util";
120433
+ import { isDeepStrictEqual as isDeepStrictEqual19 } from "util";
120088
120434
  function reviewedClaudeDiscoveryChange(beforeText, currentText, options) {
120089
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");
120090
120436
  need8(options.reviewedPlanDigest === undefined || /^[a-f0-9]{64}$/.test(options.reviewedPlanDigest), "RECONCILE_RECOVERY_PLAN_CHANGED");
120091
120437
  const before2 = parseManagedSkillPolicy(beforeText), current = parseManagedSkillPolicy(currentText);
120092
120438
  const oldDiscovery = before2.bridge?.discovery?.claude, newDiscovery = current.bridge?.discovery?.claude;
120093
120439
  need8(oldDiscovery?.agent === "claude" && newDiscovery?.agent === "claude" && oldDiscovery.method === "reviewed" && newDiscovery.method === "reviewed", "RECONCILE_POLICY_CHANGED");
120094
- 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] }));
120095
120441
  need8(changes.length > 0, "RECONCILE_POLICY_CHANGED");
120096
120442
  const compared = structuredClone(current);
120097
120443
  compared.bridge.discovery.claude.roots = oldDiscovery.roots;
120098
120444
  compared.bridge.discovery.claude.sources = oldDiscovery.sources;
120099
- need8(isDeepStrictEqual18(before2, compared), "RECONCILE_POLICY_CHANGED");
120445
+ need8(isDeepStrictEqual19(before2, compared), "RECONCILE_POLICY_CHANGED");
120100
120446
  verifyAgentDiscovery(newDiscovery);
120101
120447
  return { reason: options.reason, changes };
120102
120448
  }
@@ -120107,16 +120453,16 @@ var init_codex_hook_policy_recovery = __esm(() => {
120107
120453
  });
120108
120454
 
120109
120455
  // src/lib/agent-codex-trust.ts
120110
- import { lstatSync as lstatSync44, mkdirSync as mkdirSync30, readdirSync as readdirSync26, readFileSync as readFileSync46, realpathSync as realpathSync21, statSync as statSync24 } from "fs";
120111
- 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";
120112
120458
  import { execFileSync as execFileSync2 } from "child_process";
120113
- 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";
120114
120460
  import { homedir as homedir13 } from "os";
120115
- import { isDeepStrictEqual as isDeepStrictEqual19 } from "util";
120461
+ import { isDeepStrictEqual as isDeepStrictEqual20 } from "util";
120116
120462
  function verifyReleaseArtifact(proof, skillsCli) {
120117
- 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");
120118
120464
  const tarPath = realpathSync21(proof.packageTarPath);
120119
- need8(statSync24(tarPath).isFile(), "RECONCILE_RELEASE_PROVENANCE_PATH");
120465
+ need8(statSync25(tarPath).isFile(), "RECONCILE_RELEASE_PROVENANCE_PATH");
120120
120466
  const tarBytes = readFileSync46(tarPath);
120121
120467
  need8(tarBytes.byteLength === proof.packageTarBytes && createHash43("sha256").update(tarBytes).digest("hex") === proof.packageTarSha256, "RECONCILE_RELEASE_ARTIFACT_CHANGED");
120122
120468
  const packageRoot = dirname45(dirname45(realpathSync21(skillsCli.receipt.path)));
@@ -120140,10 +120486,10 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
120140
120486
  const home = resolve40(options.home ?? homedir13()), dataDir3 = resolve40(options.dataDir ?? getDataDirReadOnly());
120141
120487
  const parent = resolve40(join72(dataDir3, "native-hook-trust")), journal = resolve40(options.journal);
120142
120488
  need8(journal.startsWith(parent + "/") && /^[a-f0-9-]{36}$/.test(journal.slice(parent.length + 1)), "RECONCILE_JOURNAL_PATH");
120143
- const dir = lstatSync44(journal, { throwIfNoEntry: false });
120489
+ const dir = lstatSync45(journal, { throwIfNoEntry: false });
120144
120490
  need8(!!dir && dir.isDirectory() && !dir.isSymbolicLink() && dir.uid === process.getuid() && (dir.mode & 511) === 448, "UNSAFE_JOURNAL");
120145
- need8(!lstatSync44(join72(journal, "receipt.json"), { throwIfNoEntry: false }), "RECONCILE_ALREADY_COMPLETE");
120146
- 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");
120147
120493
  const stoppedFile = snapshot(join72(journal, "stopped.json"), true);
120148
120494
  const intentFile = snapshot(join72(journal, "intent.json"), true), intent = JSON.parse(intentFile.text);
120149
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);
@@ -120154,7 +120500,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
120154
120500
  const configSha256 = intent.configSha256 ?? configBefore.sha256, configVersion = intent.configVersion ?? intent.expectedVersion;
120155
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 };
120156
120502
  need8(makePlanDigest(digestInput) === intent.planDigest, "RECONCILE_PLAN_CHANGED");
120157
- 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");
120158
120504
  need8(configBefore.sha256 === (intent.beforeSha256 ?? intent.configSha256) && hooksBefore.sha256 === intent.hooksSha256 && policyBefore.sha256 === intent.policySha256, "RECONCILE_JOURNAL_CHANGED");
120159
120505
  const policyCurrent = snapshot(join72(dataDir3, "agent-policy.json"), true);
120160
120506
  const { claudeDiscoveryRecovery: claudeRecovery, nativeHookAdditionsRecovery: additionsRecovery } = options;
@@ -120167,13 +120513,13 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
120167
120513
  if (policyCurrent.sha256 !== policyBefore.sha256 && !claudeRecovery) {
120168
120514
  need8(options.supersedeBinding === true, "RECONCILE_POLICY_CHANGED");
120169
120515
  const oldPolicy = JSON.parse(policyBefore.text), currentPolicy = JSON.parse(policyCurrent.text);
120170
- need8(isDeepStrictEqual19(withoutCodexCommand(oldPolicy), withoutCodexCommand(currentPolicy)), "RECONCILE_POLICY_CHANGED");
120516
+ need8(isDeepStrictEqual20(withoutCodexCommand(oldPolicy), withoutCodexCommand(currentPolicy)), "RECONCILE_POLICY_CHANGED");
120171
120517
  supersededBinding = true;
120172
120518
  }
120173
120519
  if (supersededBinding || recovery) {
120174
120520
  need8(Array.isArray(intent.nativeHooks) && intent.nativeHooks.length > 0, "RECONCILE_NATIVE_INVENTORY_REQUIRED");
120175
120521
  const proof = options.releaseProof;
120176
- 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");
120177
120523
  }
120178
120524
  const currentConfig = snapshot(intent.configPath, true);
120179
120525
  const policy = parseManagedSkillPolicy(policyCurrent.text), binding = policy.bridge;
@@ -120203,7 +120549,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
120203
120549
  need8(state?.enabled === true && typeof state.trusted_hash === "string" && /^sha256:[a-f0-9]{64}$/.test(state.trusted_hash), "RECONCILE_CONFIG_DRIFT");
120204
120550
  }
120205
120551
  } else
120206
- need8(isDeepStrictEqual19(expectedConfig, current), "RECONCILE_CONFIG_DRIFT");
120552
+ need8(isDeepStrictEqual20(expectedConfig, current), "RECONCILE_CONFIG_DRIFT");
120207
120553
  const configDiscoveryRecovery = recovery && binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, configBefore, currentConfig, intent.hooks, additions?.trustProof) : undefined;
120208
120554
  assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: configDiscoveryRecovery });
120209
120555
  const recoveryCli = recovery ? bindSkillsCli("skills", options.reviewedSkillsCli) : undefined;
@@ -120212,14 +120558,14 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
120212
120558
  const skillsCli = recovery ? inspectRecordedSkillsCli(binding.commands.codex, intent.skillsCli) : bindSkillsCli(binding.commands.codex, options.reviewedSkillsCli);
120213
120559
  if (supersededBinding)
120214
120560
  verifyReleaseArtifact(options.releaseProof, skillsCli);
120215
- const skillsBindingChanged = !isDeepStrictEqual19(skillsCli.receipt, intent.skillsCli);
120561
+ const skillsBindingChanged = !isDeepStrictEqual20(skillsCli.receipt, intent.skillsCli);
120216
120562
  need8(!skillsBindingChanged || supersededBinding, "RECONCILE_SKILLS_BINDING_CHANGED");
120217
120563
  if (!additions && hooksCurrent.sha256 !== intent.hooksSha256 && hooksCurrent.sha256 !== hooksBefore.sha256) {
120218
120564
  need8(supersededBinding, "RECONCILE_HOOKS_CHANGED");
120219
120565
  const currentDeclarations = JSON.parse(hooksCurrent.text).hooks;
120220
120566
  for (const [event, [nativeEvent]] of Object.entries(eventNames)) {
120221
120567
  const command = renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, event);
120222
- 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");
120223
120569
  }
120224
120570
  }
120225
120571
  rpc = await connect({ command: options.codexCommand ?? "codex", home, codexHome });
@@ -120242,9 +120588,9 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
120242
120588
  delete identity6.command;
120243
120589
  return identity6;
120244
120590
  };
120245
- need8(isDeepStrictEqual19(stable(actual), stable(expected)), "RECONCILE_NATIVE_IDENTITY_CHANGED");
120591
+ need8(isDeepStrictEqual20(stable(actual), stable(expected)), "RECONCILE_NATIVE_IDENTITY_CHANGED");
120246
120592
  if (!plannedKeys.has(expected.key))
120247
- need8(isDeepStrictEqual19(actual, expected), "RECONCILE_UNRELATED_HOOK_CHANGED");
120593
+ need8(isDeepStrictEqual20(actual, expected), "RECONCILE_UNRELATED_HOOK_CHANGED");
120248
120594
  }
120249
120595
  for (const wanted of intent.hooks) {
120250
120596
  const matches2 = nativeHooks.filter((h2) => h2.key === wanted.key || h2.key === wanted.key.replace(join72(home, ".codex/hooks.json"), hooksPath));
@@ -120263,7 +120609,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
120263
120609
  const layers = config2?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
120264
120610
  need8(layers?.length === 1 && !layers[0].disabledReason && codexNativeConfigEqual(layers[0].config, current), "RECONCILE_NATIVE_CONFIG_MISMATCH");
120265
120611
  const finalDiscovery = await rpc.request("hooks/list", { cwds: [home] });
120266
- 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");
120267
120613
  const finalConfig = await rpc.request("config/read", { includeLayers: true, cwd: home });
120268
120614
  const finalLayers = finalConfig?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
120269
120615
  need8(finalLayers?.length === 1 && !finalLayers[0].disabledReason && codexNativeConfigEqual(finalLayers[0].config, current), "RECONCILE_NATIVE_CONFIG_CHANGED");
@@ -120318,7 +120664,7 @@ async function enrollCodexNativeHooksUnlocked(options, connect, admission) {
120318
120664
  const binding = policy.bridge, alias = binding.rootAliases?.find((item) => item.agent === "codex");
120319
120665
  const skillsCli = bindSkillsCli(binding.commands.codex, options.reviewedSkillsCli);
120320
120666
  const physicalRoot = alias?.target ?? join72(home, ".codex"), hooksPath = join72(physicalRoot, "hooks.json"), configPath = join72(physicalRoot, "config.toml");
120321
- 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");
120322
120668
  const codexHome = options.codexHome === undefined ? undefined : physicalRoot;
120323
120669
  const nativeConfigPath = join72(codexHome ?? join72(home, ".codex"), "config.toml");
120324
120670
  const hooksFile = snapshot(hooksPath), configFile = snapshot(configPath, true), original = structure3(configFile.text);
@@ -120328,7 +120674,7 @@ async function enrollCodexNativeHooksUnlocked(options, connect, admission) {
120328
120674
  const groups = declarations[event];
120329
120675
  need8(Array.isArray(groups), "DECLARATION_CHANGED");
120330
120676
  const matches2 = groups.flatMap((group, gi) => (group.hooks ?? []).flatMap((entry, hi) => entry.command === command ? [{ group, entry, gi, hi }] : []));
120331
- 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");
120332
120678
  expected.push({ event: nativeEvent, key: `${join72(home, ".codex/hooks.json")}:${label}:${matches2[0].gi}:${matches2[0].hi}`, command });
120333
120679
  }
120334
120680
  codexTrustTextWitness(configFile.text, expected.map((h) => h.key));
@@ -120374,27 +120720,27 @@ async function enrollCodexNativeHooksUnlocked(options, connect, admission) {
120374
120720
  if (options.apply)
120375
120721
  need8(options.reviewedPlanDigest === planDigest, "PLAN_CHANGED: run the dry-run again and pass its reviewed --plan-digest with --apply");
120376
120722
  const parent = join72(dataDir3, "native-hook-trust");
120377
- const st = lstatSync44(parent, { throwIfNoEntry: false });
120723
+ const st = lstatSync45(parent, { throwIfNoEntry: false });
120378
120724
  if (st) {
120379
120725
  need8(st.isDirectory() && !st.isSymbolicLink() && st.uid === process.getuid() && (st.mode & 511) === 448, "UNSAFE_JOURNAL");
120380
120726
  const priorJournals = readdirSync26(parent);
120381
120727
  need8(priorJournals.length < 1000, "JOURNAL_BOUND");
120382
120728
  for (const name of priorJournals) {
120383
120729
  need8(/^[a-f0-9-]{36}$/.test(name), "UNSAFE_JOURNAL");
120384
- 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");
120385
120731
  }
120386
120732
  }
120387
120733
  if (!options.apply || !planned.length)
120388
120734
  return baseReceipt;
120389
120735
  if (!st)
120390
120736
  mkdirSync30(parent, { mode: 448 });
120391
- journal = join72(parent, randomUUID12());
120737
+ journal = join72(parent, randomUUID13());
120392
120738
  mkdirSync30(journal, { mode: 448 });
120393
120739
  save(join72(journal, "config.before.toml"), configFile.bytes);
120394
120740
  save(join72(journal, "hooks.before.json"), hooksFile.bytes);
120395
120741
  save(join72(journal, "policy.before.json"), policyFile.bytes);
120396
120742
  save(join72(journal, "intent.json"), json2({ ...digestInput, planDigest, hooks: planned, nativeHooks: discovered.map(safeNativeHook), ...codexAdmissionReceipt(admission) }));
120397
- need8(isDeepStrictEqual19(admit(await list2()), admitted), "NATIVE_DISCOVERY_CHANGED");
120743
+ need8(isDeepStrictEqual20(admit(await list2()), admitted), "NATIVE_DISCOVERY_CHANGED");
120398
120744
  checkInputs();
120399
120745
  let result2;
120400
120746
  try {
@@ -120408,7 +120754,7 @@ async function enrollCodexNativeHooksUnlocked(options, connect, admission) {
120408
120754
  expectedConfig.hooks.state ??= {};
120409
120755
  for (const h of planned)
120410
120756
  expectedConfig.hooks.state[h.key] = { ...expectedConfig.hooks.state[h.key], enabled: true, trusted_hash: h.currentHash };
120411
- 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");
120412
120758
  const savedConfig = snapshot(join72(journal, "config.before.toml"), true);
120413
120759
  need8(savedConfig.sha256 === configFile.sha256, "JOURNAL_CHANGED");
120414
120760
  const discoveryTransition = binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, savedConfig, after2, planned) : undefined;
@@ -120416,8 +120762,8 @@ async function enrollCodexNativeHooksUnlocked(options, connect, admission) {
120416
120762
  unchanged2(hooksFile);
120417
120763
  assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: discoveryTransition });
120418
120764
  const current = await list2(), confirmed = admit(current);
120419
- 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");
120420
- 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");
120421
120767
  unchanged2(after2);
120422
120768
  unchanged2(savedConfig);
120423
120769
  unchanged2(hooksFile);
@@ -120550,9 +120896,9 @@ var init_codex_native_trust = __esm(() => {
120550
120896
 
120551
120897
  // src/lib/claude-prospective-review.ts
120552
120898
  import { createHash as createHash45 } from "crypto";
120553
- import { lstatSync as lstatSync45, readFileSync as readFileSync48, readdirSync as readdirSync27, realpathSync as realpathSync22 } from "fs";
120554
- import { basename as basename23, dirname as dirname46, isAbsolute as isAbsolute42, join as join74, relative as relative15, resolve as resolve42, sep as sep21 } from "path";
120555
- 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";
120556
120902
  function hashClaudeDiscoveryBinding(binding) {
120557
120903
  return sha8(JSON.stringify(binding));
120558
120904
  }
@@ -120602,7 +120948,7 @@ function keys4(value, expected, name) {
120602
120948
  refuse8(`${name} has an unsupported shape`);
120603
120949
  }
120604
120950
  function abs(path, name) {
120605
- 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)
120606
120952
  refuse8(`${name} must be a normalized absolute path`);
120607
120953
  }
120608
120954
  function validUtcTimestamp(value) {
@@ -120611,23 +120957,23 @@ function validUtcTimestamp(value) {
120611
120957
  function safeFile(path, name) {
120612
120958
  abs(path, name);
120613
120959
  for (let at2 = dirname46(path);; at2 = dirname46(at2)) {
120614
- const stat4 = lstatSync45(at2, { throwIfNoEntry: false });
120960
+ const stat4 = lstatSync46(at2, { throwIfNoEntry: false });
120615
120961
  if (!stat4?.isDirectory() || stat4.isSymbolicLink())
120616
120962
  refuse8(`${name} traverses a symlink or non-directory`);
120617
120963
  if (at2 === dirname46(at2))
120618
120964
  break;
120619
120965
  }
120620
- const stat3 = lstatSync45(path, { throwIfNoEntry: false });
120966
+ const stat3 = lstatSync46(path, { throwIfNoEntry: false });
120621
120967
  if (!stat3?.isFile() || stat3.isSymbolicLink() || stat3.size > MAX_CANDIDATE_BYTES)
120622
120968
  refuse8(`${name} is not a bounded regular file`);
120623
120969
  return readFileSync48(path);
120624
120970
  }
120625
120971
  function canonicalDir(path, name) {
120626
120972
  abs(path, name);
120627
- if (realpathSync22(path) !== path || !lstatSync45(path).isDirectory())
120973
+ if (realpathSync22(path) !== path || !lstatSync46(path).isDirectory())
120628
120974
  refuse8(`${name} is not a canonical directory`);
120629
120975
  for (let at2 = path;; at2 = dirname46(at2)) {
120630
- const stat3 = lstatSync45(at2);
120976
+ const stat3 = lstatSync46(at2);
120631
120977
  if (!stat3.isDirectory() || stat3.isSymbolicLink())
120632
120978
  refuse8(`${name} traverses a symlink`);
120633
120979
  if (at2 === dirname46(at2))
@@ -120639,7 +120985,7 @@ function captureClaudeProspectiveCandidateClosure(root2) {
120639
120985
  const entries = [];
120640
120986
  let bytes = 0;
120641
120987
  const walk2 = (directory3) => {
120642
- const beforeDirectory = lstatSync45(directory3);
120988
+ const beforeDirectory = lstatSync46(directory3);
120643
120989
  const names = readdirSync27(directory3).sort();
120644
120990
  if (new Set(names).size !== names.length)
120645
120991
  refuse8("candidate contains ambiguous directory entries");
@@ -120649,7 +120995,7 @@ function captureClaudeProspectiveCandidateClosure(root2) {
120649
120995
  const path = join74(directory3, name), rel = relative15(root2, path).split(sep21).join("/");
120650
120996
  if (entries.length >= MAX_CANDIDATE_FILES)
120651
120997
  refuse8("candidate closure exceeds its member limit");
120652
- const stat3 = lstatSync45(path);
120998
+ const stat3 = lstatSync46(path);
120653
120999
  if (stat3.isSymbolicLink())
120654
121000
  refuse8("candidate closure contains a symlink");
120655
121001
  if (stat3.isDirectory()) {
@@ -120659,14 +121005,14 @@ function captureClaudeProspectiveCandidateClosure(root2) {
120659
121005
  bytes += stat3.size;
120660
121006
  if (bytes > MAX_CANDIDATE_BYTES)
120661
121007
  refuse8("candidate closure exceeds its byte limit");
120662
- const content = safeFile(path, "candidate member"), after2 = lstatSync45(path);
121008
+ const content = safeFile(path, "candidate member"), after2 = lstatSync46(path);
120663
121009
  if (!after2.isFile() || after2.dev !== stat3.dev || after2.ino !== stat3.ino || after2.size !== stat3.size || after2.mtimeMs !== stat3.mtimeMs || after2.ctimeMs !== stat3.ctimeMs)
120664
121010
  refuse8("candidate member changed while being read");
120665
121011
  entries.push([rel, "file", sha8(content)]);
120666
121012
  } else
120667
121013
  refuse8("candidate closure contains a special file");
120668
121014
  }
120669
- const afterDirectory = lstatSync45(directory3);
121015
+ const afterDirectory = lstatSync46(directory3);
120670
121016
  if (!afterDirectory.isDirectory() || afterDirectory.dev !== beforeDirectory.dev || afterDirectory.ino !== beforeDirectory.ino || afterDirectory.mtimeMs !== beforeDirectory.mtimeMs || afterDirectory.ctimeMs !== beforeDirectory.ctimeMs)
120671
121017
  refuse8("candidate directory changed while being read");
120672
121018
  };
@@ -120690,11 +121036,11 @@ function captureClaudeInstallerCandidate(root2, policyPath) {
120690
121036
  if (names.has(row2.name))
120691
121037
  refuse8("candidate catalog repeats a plugin name");
120692
121038
  names.add(row2.name);
120693
- 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))
120694
121040
  refuse8("candidate catalog plugin source is invalid");
120695
121041
  const pluginRoot = resolve42(root2, row2.source);
120696
121042
  const relativeRoot = relative15(root2, pluginRoot);
120697
- if (!relativeRoot || relativeRoot === "." || relativeRoot === ".." || relativeRoot.startsWith(`..${sep21}`) || isAbsolute42(relativeRoot))
121043
+ if (!relativeRoot || relativeRoot === "." || relativeRoot === ".." || relativeRoot.startsWith(`..${sep21}`) || isAbsolute44(relativeRoot))
120698
121044
  refuse8("candidate plugin source escapes the candidate root");
120699
121045
  const path = join74(pluginRoot, ".claude-plugin/plugin.json");
120700
121046
  return { plugin: row2.name, ...captureClaudePluginManifestFile(path) };
@@ -120713,7 +121059,7 @@ function captureClaudeInstallerCandidate(root2, policyPath) {
120713
121059
  }
120714
121060
  function readWitness(path, expected, name) {
120715
121061
  abs(path, `${name} path`);
120716
- const stat3 = lstatSync45(path, { throwIfNoEntry: false });
121062
+ const stat3 = lstatSync46(path, { throwIfNoEntry: false });
120717
121063
  if (expected === null) {
120718
121064
  if (stat3)
120719
121065
  refuse8(`${name} was absent at review but is now present`);
@@ -120765,7 +121111,7 @@ function unreviewedProjectSettingsRefusal(path, expected, name) {
120765
121111
  return null;
120766
121112
  }
120767
121113
  function jsonFile(path, name) {
120768
- const stat3 = lstatSync45(path, { throwIfNoEntry: false });
121114
+ const stat3 = lstatSync46(path, { throwIfNoEntry: false });
120769
121115
  if (!stat3)
120770
121116
  return null;
120771
121117
  let value;
@@ -120797,7 +121143,7 @@ function assertNoUnprojectedSkillPayload(root2, catalogPath, marketplace, plugin
120797
121143
  const walk2 = (directory3) => {
120798
121144
  for (const name of readdirSync27(directory3).sort()) {
120799
121145
  const path = join74(directory3, name), rel = relative15(root2, path).split(sep21).join("/");
120800
- const stat3 = lstatSync45(path);
121146
+ const stat3 = lstatSync46(path);
120801
121147
  if (stat3.isDirectory())
120802
121148
  walk2(path);
120803
121149
  else if (stat3.isFile()) {
@@ -120863,7 +121209,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
120863
121209
  refuse8("CLAUDE_CODE_PLUGIN_CACHE_DIR overrides are unsupported by this prospective schema; bind and review the actual cache root first");
120864
121210
  if (request2.native.pluginRoot !== pluginRoot)
120865
121211
  refuse8("Claude plugin root differs from the supported standard plugins directory; Cowork and custom cache roots require a separately bound schema");
120866
- const pluginRootStat = lstatSync45(pluginRoot, { throwIfNoEntry: false });
121212
+ const pluginRootStat = lstatSync46(pluginRoot, { throwIfNoEntry: false });
120867
121213
  if (pluginRootStat && (!pluginRootStat.isDirectory() || pluginRootStat.isSymbolicLink()))
120868
121214
  refuse8("Claude plugin root is not a regular directory");
120869
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");
@@ -120929,7 +121275,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
120929
121275
  refuse8("plugin manifest must be under a plugin root inside the frozen marketplace closure");
120930
121276
  const pluginRoot2 = dirname46(dirname46(selected.manifestPath));
120931
121277
  const relativePluginRoot = relative15(candidate2.root, pluginRoot2);
120932
- if (!relativePluginRoot || relativePluginRoot === "." || relativePluginRoot === ".." || relativePluginRoot.startsWith(`..${sep21}`) || isAbsolute42(relativePluginRoot))
121278
+ if (!relativePluginRoot || relativePluginRoot === "." || relativePluginRoot === ".." || relativePluginRoot.startsWith(`..${sep21}`) || isAbsolute44(relativePluginRoot))
120933
121279
  refuse8("plugin root must be a child of the frozen marketplace root");
120934
121280
  canonicalDir(pluginRoot2, "candidate plugin root");
120935
121281
  if (!SHA256.test(selected.manifestSha256))
@@ -120963,7 +121309,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
120963
121309
  const sourcePath = selectedEntry.source;
120964
121310
  const sourceRelativePath = relative15(candidate2.root, pluginRoot2).split(sep21).join("/");
120965
121311
  const expectedSourcePath = sourceRelativePath === "." ? "./" : `./${sourceRelativePath}`;
120966
- 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)
120967
121313
  refuse8("marketplace source does not resolve to the frozen plugin closure; external source mapping is not supported by this schema");
120968
121314
  const entry = captureClaudeMarketplaceEntry(candidate2.catalogPath, candidate2.marketplace, selected.plugin);
120969
121315
  if (entry.sha256.length !== 64)
@@ -121024,7 +121370,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
121024
121370
  refuse8("Skills discovery preimage differs from its reviewed binding");
121025
121371
  assertProjectDiscovery("claude", [request2.scope.projectPath], request2.native.home, canonical9, binding);
121026
121372
  const stored = snapshot2.value.bridge?.discovery?.claude;
121027
- 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)
121028
121374
  refuse8("Skills policy does not bind the reviewed current Claude discovery");
121029
121375
  assertExemptUnchanged();
121030
121376
  const delta = request2.delta;
@@ -121182,7 +121528,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
121182
121528
  refuse8("current known marketplace autoUpdate is not a boolean");
121183
121529
  }
121184
121530
  }
121185
- if (!isDeepStrictEqual20(delta.settingsAfter, settingsAfter))
121531
+ if (!isDeepStrictEqual21(delta.settingsAfter, settingsAfter))
121186
121532
  refuse8("complete settings document differs from the exact selected plugin/options/environment/marketplace operations");
121187
121533
  const marketplaceRowBefore = marketplaces?.[candidate2.marketplace];
121188
121534
  if (marketplaceRowBefore !== undefined && !object11(marketplaceRowBefore))
@@ -121194,7 +121540,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
121194
121540
  if (marketplaceRowBefore?.lastUpdated !== undefined && !validUtcTimestamp(marketplaceRowBefore.lastUpdated))
121195
121541
  refuse8("current marketplace update timestamp is invalid");
121196
121542
  const targetMarketplaceLocation = candidate2.root;
121197
- 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;
121198
121544
  const afterMarketplace = {
121199
121545
  source: { source: "directory", path: candidate2.root },
121200
121546
  installLocation: targetMarketplaceLocation,
@@ -121203,7 +121549,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
121203
121549
  };
121204
121550
  const marketplacesAfter = marketplaces ? structuredClone(marketplaces) : {};
121205
121551
  marketplacesAfter[candidate2.marketplace] = afterMarketplace;
121206
- if (!isDeepStrictEqual20(delta.knownMarketplacesAfter, marketplacesAfter))
121552
+ if (!isDeepStrictEqual21(delta.knownMarketplacesAfter, marketplacesAfter))
121207
121553
  refuse8("complete marketplace document differs from the exact selected-directory marketplace operation");
121208
121554
  const installedAfter = registrations ? structuredClone(registrations) : { version: 2, plugins: {} };
121209
121555
  if (installedAfter.plugins === undefined)
@@ -121223,7 +121569,7 @@ function reviewClaudeProspectiveCandidate(request2, requestFileSha256) {
121223
121569
  nextRows[index] = targetRegistration;
121224
121570
  installedAfter.plugins[pluginId2] = nextRows;
121225
121571
  }
121226
- if (!isDeepStrictEqual20(delta.installedPluginsAfter, installedAfter))
121572
+ if (!isDeepStrictEqual21(delta.installedPluginsAfter, installedAfter))
121227
121573
  refuse8("complete installed plugin document changes an unrelated registration or has target rows not derived from every selected candidate");
121228
121574
  assertExemptUnchanged();
121229
121575
  const semanticDocumentsSha256 = sha8(canonicalJson3({ settings: settingsAfter, knownMarketplaces: marketplacesAfter, installedPlugins: installedAfter }));
@@ -121302,7 +121648,7 @@ var init_claude_prospective_review = __esm(() => {
121302
121648
 
121303
121649
  // src/lib/self-spawn.ts
121304
121650
  import { realpathSync as realpathSync23 } from "fs";
121305
- 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";
121306
121652
  function selfSpawnRoot(entry) {
121307
121653
  const index = entry.indexOf(INSTALLED_PACKAGE);
121308
121654
  const root2 = index > 0 ? entry.slice(0, index) : dirname47(entry);
@@ -121315,7 +121661,7 @@ function selfSpawnRoot(entry) {
121315
121661
  function selfSpawnCommand(args2, options = {}) {
121316
121662
  const runtime = options.runtime ?? process.execPath;
121317
121663
  const entry = options.entry ?? process.argv[1];
121318
- if (!runtime || !isAbsolute43(runtime) || !entry || !isAbsolute43(entry))
121664
+ if (!runtime || !isAbsolute45(runtime) || !entry || !isAbsolute45(entry))
121319
121665
  throw new Error("SKILLS_SELF_SPAWN_ENTRY_UNRESOLVED");
121320
121666
  const root2 = selfSpawnRoot(entry);
121321
121667
  const env3 = pinnedLauncherEnvironment(options.env ?? process.env);
@@ -121421,8 +121767,8 @@ var init_claude_installer_binding = __esm(() => {
121421
121767
  });
121422
121768
 
121423
121769
  // src/cli/commands/claude-installer-capture.ts
121424
- import { closeSync as closeSync30, constants as constants29, fstatSync as fstatSync30, lstatSync as lstatSync46, openSync as openSync30, readSync as readSync22 } from "fs";
121425
- 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";
121426
121772
  function need11(condition, code2) {
121427
121773
  if (!condition)
121428
121774
  throw new CaptureRefusal(code2);
@@ -121436,11 +121782,11 @@ function exactKeys5(value, expected, operation) {
121436
121782
  }
121437
121783
  }
121438
121784
  function canonicalPath2(value) {
121439
- 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");
121440
121786
  }
121441
121787
  function readRequest2(path) {
121442
121788
  canonicalPath2(path);
121443
- const before2 = lstatSync46(path, { throwIfNoEntry: false });
121789
+ const before2 = lstatSync47(path, { throwIfNoEntry: false });
121444
121790
  if (!before2?.isFile() || before2.isSymbolicLink() || before2.size > MAX_REQUEST_BYTES)
121445
121791
  throw new CaptureRefusal("INVALID_REQUEST_FILE: --request must name a regular non-symlink JSON file no larger than 64 KiB");
121446
121792
  const fd = openSync30(path, constants29.O_RDONLY | (constants29.O_NOFOLLOW ?? 0) | constants29.O_NONBLOCK);
@@ -121455,7 +121801,7 @@ function readRequest2(path) {
121455
121801
  break;
121456
121802
  length += count;
121457
121803
  }
121458
- const after2 = fstatSync30(fd), current = lstatSync46(path);
121804
+ const after2 = fstatSync30(fd), current = lstatSync47(path);
121459
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");
121460
121806
  try {
121461
121807
  return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, length)));
@@ -121607,10 +121953,10 @@ var exports_agent_integration = {};
121607
121953
  __export(exports_agent_integration, {
121608
121954
  registerAgentIntegration: () => registerAgentIntegration
121609
121955
  });
121610
- 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";
121611
121957
  import { createHash as createHash47 } from "crypto";
121612
121958
  import { homedir as homedir14 } from "os";
121613
- 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";
121614
121960
  function pinnedHookProfile(input3, configuredProfile) {
121615
121961
  try {
121616
121962
  const parsed = parseSkillContextInput(JSON.stringify(input3));
@@ -121745,7 +122091,7 @@ function registerAgentIntegration(parent) {
121745
122091
  });
121746
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) => {
121747
122093
  try {
121748
- if (!isAbsolute45(options.cwd) || !isAbsolute45(options.output))
122094
+ if (!isAbsolute47(options.cwd) || !isAbsolute47(options.output))
121749
122095
  throw new Error("CODEX_NATIVE_SKILL_CATALOG_ABSOLUTE_PATH_REQUIRED");
121750
122096
  if (existsSync36(options.output))
121751
122097
  throw new Error("CODEX_NATIVE_SKILL_CATALOG_OUTPUT_EXISTS");
@@ -121769,7 +122115,7 @@ function registerAgentIntegration(parent) {
121769
122115
  throw new Error("CODEX_NATIVE_SKILL_CATALOG_OUTPUT_EXISTS");
121770
122116
  throw error61;
121771
122117
  }
121772
- const written = lstatSync47(options.output);
122118
+ const written = lstatSync48(options.output);
121773
122119
  if (!written.isFile() || written.isSymbolicLink() || (written.mode & 63) !== 0 || readFileSync49(options.output, "utf8") !== bytes)
121774
122120
  throw new Error("CODEX_NATIVE_SKILL_CATALOG_READBACK_FAILED");
121775
122121
  const receipt = {
@@ -121836,9 +122182,9 @@ function registerAgentIntegration(parent) {
121836
122182
  });
121837
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) => {
121838
122184
  try {
121839
- if (!isAbsolute45(options.request))
122185
+ if (!isAbsolute47(options.request))
121840
122186
  throw new Error("CLAUDE_CANDIDATE_REVIEW_REFUSED: --request must be an absolute path");
121841
- const stat3 = lstatSync47(options.request);
122187
+ const stat3 = lstatSync48(options.request);
121842
122188
  if (!stat3.isFile() || stat3.isSymbolicLink() || stat3.size > 1024 * 1024)
121843
122189
  throw new Error("CLAUDE_CANDIDATE_REVIEW_REFUSED: request must be a regular file no larger than 1 MiB");
121844
122190
  const requestBytes = readFileSync49(options.request);
@@ -121974,12 +122320,12 @@ function registerAgentIntegration(parent) {
121974
122320
  input3.hook_event_name = event;
121975
122321
  const projects = [process.cwd()];
121976
122322
  if (input3.cwd !== undefined) {
121977
- 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"))
121978
122324
  throw new Error("Invalid native hook working directory");
121979
122325
  projects.push(input3.cwd);
121980
122326
  }
121981
122327
  if (options.agent === "cursor") {
121982
- 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")))
121983
122329
  throw new Error("Invalid Cursor workspace roots");
121984
122330
  projects.push(...input3.workspace_roots);
121985
122331
  input3.cwd ??= input3.workspace_roots[0] ?? process.cwd();
@@ -122770,7 +123116,7 @@ import {
122770
123116
  mkdirSync as mkdirSync31,
122771
123117
  readdirSync as readdirSync28,
122772
123118
  readFileSync as readFileSync50,
122773
- statSync as statSync25,
123119
+ statSync as statSync26,
122774
123120
  writeFileSync as writeFileSync30
122775
123121
  } from "fs";
122776
123122
  import { dirname as dirname48, join as join76, resolve as resolve45, sep as sep23 } from "path";
@@ -122867,7 +123213,7 @@ function planStationHydration(stationId, repoRoot) {
122867
123213
  });
122868
123214
  continue;
122869
123215
  }
122870
- const info = statSync25(entry.fullPath);
123216
+ const info = statSync26(entry.fullPath);
122871
123217
  const manifestHash = manifestHashes.get(`${agent}${MANIFEST_HASH_KEY_SEP}${homeRelative}`) ?? null;
122872
123218
  let verified = false;
122873
123219
  if (manifestHash !== null) {
@@ -123124,10 +123470,10 @@ var init_hydrate = __esm(() => {
123124
123470
  });
123125
123471
 
123126
123472
  // src/lib/prepare-skill.ts
123127
- import { createHash as createHash49, randomUUID as randomUUID13 } from "crypto";
123128
- 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";
123129
123475
  import { tmpdir as tmpdir2 } from "os";
123130
- 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";
123131
123477
  function prepareSkill(name, options) {
123132
123478
  const normalized2 = normalizePortableSkillName(name);
123133
123479
  if (!new RegExp(SEMVER_PATTERN).test(options.version))
@@ -123199,11 +123545,11 @@ ${validation.issues.map((issue2) => `${issue2.code}: ${issue2.message}`).join(`
123199
123545
  if (snapshot2(path).identity !== before2.identity)
123200
123546
  throw new Error("Skill changed during preparation; review the draft and run prepare again.");
123201
123547
  if (changed3 && !options.dryRun) {
123202
- const temporary = join77(path, `.skill-prepare-${randomUUID13()}.tmp`);
123548
+ const temporary = join77(path, `.skill-prepare-${randomUUID14()}.tmp`);
123203
123549
  try {
123204
123550
  writeFileSync31(temporary, candidateBytes, { flag: "wx", mode: manifestFile.mode });
123205
123551
  chmodSync5(temporary, manifestFile.mode);
123206
- renameSync15(temporary, join77(path, "skill.json"));
123552
+ renameSync16(temporary, join77(path, "skill.json"));
123207
123553
  } finally {
123208
123554
  rmSync10(temporary, { force: true });
123209
123555
  }
@@ -123234,7 +123580,7 @@ function validateRuntimeEntrypoint(candidate2, root2) {
123234
123580
  if (typeof entry !== "string")
123235
123581
  return;
123236
123582
  const target = resolve46(root2, entry), rel = relative16(root2, target);
123237
- 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()) {
123238
123584
  throw new Error("Executable runtime.entrypoint must name an existing regular file inside the skill directory.");
123239
123585
  }
123240
123586
  }
@@ -123319,7 +123665,7 @@ function compareVersions(left, right) {
123319
123665
  return 0;
123320
123666
  }
123321
123667
  function snapshot2(root2) {
123322
- const rootStat = lstatSync48(root2);
123668
+ const rootStat = lstatSync49(root2);
123323
123669
  if (rootStat.isSymbolicLink() || !rootStat.isDirectory())
123324
123670
  throw new Error("Skill root must be a real directory, not a symlink.");
123325
123671
  const files = [], directories = [];
@@ -123332,7 +123678,7 @@ function snapshot2(root2) {
123332
123678
  const path = relative17 ? `${relative17}/${name}` : name;
123333
123679
  if (++count > 20000)
123334
123680
  throw new Error("Skill exceeds the preparation entry limit (20000).");
123335
- const absolute = join77(root2, path), stat3 = lstatSync48(absolute);
123681
+ const absolute = join77(root2, path), stat3 = lstatSync49(absolute);
123336
123682
  if (stat3.isSymbolicLink())
123337
123683
  throw new Error(`Skill contains a symlink: ${path}. No files were changed.`);
123338
123684
  if (stat3.isDirectory() && name === "node_modules")
@@ -123825,8 +124171,8 @@ var init_registry_sync = __esm(() => {
123825
124171
  });
123826
124172
 
123827
124173
  // src/lib/review-export.ts
123828
- 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";
123829
- 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";
123830
124176
  function exactVersion(spec) {
123831
124177
  const at2 = spec.indexOf("@");
123832
124178
  const slug2 = spec.slice(0, at2);
@@ -123837,14 +124183,14 @@ function exactVersion(spec) {
123837
124183
  return { slug: slug2, version: version2 };
123838
124184
  }
123839
124185
  function assertPrivateDestination(output2) {
123840
- if (!isAbsolute47(output2) || resolve47(output2) !== output2 || !basename25(output2).endsWith(".tar.gz")) {
124186
+ if (!isAbsolute49(output2) || resolve47(output2) !== output2 || !basename25(output2).endsWith(".tar.gz")) {
123841
124187
  throw new Error("Review output must be an absolute, normalized .tar.gz path.");
123842
124188
  }
123843
124189
  const parent = dirname51(output2);
123844
- if (realpathSync24(parent) !== parent || lstatSync49(parent).isSymbolicLink()) {
124190
+ if (realpathSync24(parent) !== parent || lstatSync50(parent).isSymbolicLink()) {
123845
124191
  throw new Error("Review output parent must be a real directory, not a symlink.");
123846
124192
  }
123847
- const parentStat = statSync26(parent);
124193
+ const parentStat = statSync27(parent);
123848
124194
  if (!parentStat.isDirectory() || (parentStat.mode & 63) !== 0 || process.getuid && parentStat.uid !== process.getuid()) {
123849
124195
  throw new Error("Review output parent must be an owner-only directory (mode 0700).");
123850
124196
  }
@@ -124432,17 +124778,20 @@ __export(exports_private_publications, {
124432
124778
  registerPrivatePublications: () => registerPrivatePublications
124433
124779
  });
124434
124780
  import { resolve as resolve48 } from "path";
124435
- function verifyOptions(options, action) {
124781
+ function verifySessionOptions(options) {
124436
124782
  if (options.userId === undefined !== (options.membershipId === undefined) || options.userId !== undefined && (!publicationUuid(options.userId) || !publicationUuid(options.membershipId)))
124437
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);
124438
124789
  if ((action === "publish" || action === "resume" || action === "cancel") && options.confirm !== true)
124439
124790
  throw new PrivatePublicationError("PUBLICATION_CONFIRM_REQUIRED", "Use --confirm to approve this publication action.");
124440
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)))
124441
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.");
124442
124793
  if (options.waitSeconds !== undefined && (!/^(?:0|[1-9]\d{0,2})$/.test(options.waitSeconds) || Number(options.waitSeconds) > 300))
124443
124794
  throw new PrivatePublicationError("INVALID_PUBLICATION_INPUT", "Use --wait-seconds from 0 to 300.");
124444
- if (!options.codeStdin && (options.json || !process.stdin.isTTY || !process.stderr.isTTY))
124445
- throw new PrivatePublicationError("PUBLICATION_CODE_REQUIRED", "Use --code-stdin with a fresh code for noninteractive publishing.");
124446
124795
  }
124447
124796
  function print2(result2, json3) {
124448
124797
  if (json3)
@@ -124456,7 +124805,39 @@ function print2(result2, json3) {
124456
124805
  process.exitCode = 2;
124457
124806
  }
124458
124807
  function registerPrivatePublications(parent) {
124459
- 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
+ });
124460
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");
124461
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");
124462
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");
@@ -124466,17 +124847,18 @@ function registerPrivatePublications(parent) {
124466
124847
  const options = action === "publish" ? args2[1] : args2[0];
124467
124848
  try {
124468
124849
  verifyOptions(options, action);
124850
+ const context2 = options.userId ? { userId: options.userId, membershipId: options.membershipId } : undefined;
124851
+ const pending = preparePrivatePublicationSession(context2);
124469
124852
  let code2;
124470
124853
  if (options.codeStdin)
124471
124854
  code2 = await readCode();
124472
124855
  else {
124473
- await new RemoteSkillsAuthClient(getApiUrl("Publish private skills")).requestCode(options.email);
124856
+ await new RemoteSkillsAuthClient(pending.origin).requestCode(options.email);
124474
124857
  code2 = await promptCode();
124475
124858
  }
124476
124859
  if (code2 === null)
124477
124860
  return;
124478
- const context2 = options.userId ? { userId: options.userId, membershipId: options.membershipId } : undefined;
124479
- 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);
124480
124862
  if (action === "publish")
124481
124863
  await preparePrivatePublication(client2, resolve48(args2[0]), directory3, { skillId: options.skillId, expectedCurrentVersionId: options.expectedCurrentVersion ?? null, idempotencyKey: options.idempotencyKey });
124482
124864
  const result2 = action === "publish" || action === "resume" ? await continuePrivatePublication(client2, directory3, { confirm: true, waitMs: Number(options.waitSeconds) * 1000 }) : await inspectPrivatePublication(client2, directory3, action === "cancel");
@@ -124494,7 +124876,6 @@ function registerPrivatePublications(parent) {
124494
124876
  }
124495
124877
  var init_private_publications = __esm(() => {
124496
124878
  init_remote_auth();
124497
- init_auth_store();
124498
124879
  init_private_publication_customer();
124499
124880
  init_private_publication_recovery();
124500
124881
  init_remote_private_publications();
@@ -124513,6 +124894,14 @@ async function codeFor(client2, options) {
124513
124894
  return promptCode();
124514
124895
  }
124515
124896
  function errorResult(error61, json3) {
124897
+ if (error61 instanceof SkillsFleetCredentialError) {
124898
+ if (json3)
124899
+ console.log(JSON.stringify({ error: error61.message, code: error61.code, next: error61.next }));
124900
+ else
124901
+ console.error(error61.message);
124902
+ process.exitCode = 1;
124903
+ return;
124904
+ }
124516
124905
  const message = error61 instanceof NameInputError || error61 instanceof WorkspaceProfileError ? error61.message : "Unable to complete workspace sign-in. Check the selected server, profile, account and fresh verification code.";
124517
124906
  if (json3)
124518
124907
  console.log(JSON.stringify({ error: message }));
@@ -124566,6 +124955,7 @@ One workspace key saved. Use HASNA_PROFILE=${result2.profile} for subsequent com
124566
124955
  }
124567
124956
  var init_workspace_selection = __esm(() => {
124568
124957
  init_auth_store();
124958
+ init_fleet_credentials();
124569
124959
  init_remote_auth();
124570
124960
  init_workspace_profile();
124571
124961
  init_customer_verification();
@@ -124711,7 +125101,7 @@ function printWhoami(payload) {
124711
125101
  }
124712
125102
  function signInTarget(url2, json3) {
124713
125103
  try {
124714
- const target = resolveSkillsSignInOrigin(process.env, {}, url2);
125104
+ const target = captureSkillsSignInTarget(process.env, {}, url2);
124715
125105
  const refusal3 = gatewaySignInRefusal(target);
124716
125106
  if (refusal3)
124717
125107
  throw refusal3;
@@ -124722,7 +125112,10 @@ function signInTarget(url2, json3) {
124722
125112
  }
124723
125113
  }
124724
125114
  function targetFlag(target) {
124725
- return target.source === "--url" ? ` --url ${target.origin}` : "";
125115
+ return target.source === "--url" ? ` --url ${skillsShellArgument(target.origin)}` : "";
125116
+ }
125117
+ function skillsCommand(command, target) {
125118
+ return skillsProfileCommand(command, process.env, target.origin);
124726
125119
  }
124727
125120
  async function finishSignIn(result2, target, json3) {
124728
125121
  const email5 = result2.user?.email;
@@ -124734,7 +125127,7 @@ async function finishSignIn(result2, target, json3) {
124734
125127
  ...organization2 ? { organization: organization2 } : {},
124735
125128
  ...result2.firstLogin !== undefined ? { firstLogin: result2.firstLogin } : {},
124736
125129
  apiUrl: target.origin,
124737
- next: ["skills setup agents"]
125130
+ next: [skillsCommand("setup agents", target)]
124738
125131
  }));
124739
125132
  return;
124740
125133
  }
@@ -124744,24 +125137,24 @@ async function finishSignIn(result2, target, json3) {
124744
125137
  console.log(source_default.dim(` Organization: ${result2.organization.name}`));
124745
125138
  console.log(source_default.dim(` Server: ${target.origin}`));
124746
125139
  console.log(source_default.dim(` API key saved to ${getAuthFilePath()}`));
124747
- await offerAgentSetup();
125140
+ await offerAgentSetup(target);
124748
125141
  }
124749
- async function offerAgentSetup() {
125142
+ async function offerAgentSetup(target) {
124750
125143
  const before2 = process.exitCode;
124751
125144
  const answer = await prompt(`
124752
- Register Skills with your coding agents now (skills setup agents)? [Y/n] `);
125145
+ Register Skills with your coding agents now (${skillsCommand("setup agents", target)})? [Y/n] `);
124753
125146
  if (answer === null) {
124754
125147
  process.exitCode = before2 ?? 0;
124755
125148
  console.log(source_default.dim(`
124756
- Skipped. Run it any time: skills setup agents`));
125149
+ Skipped. Run it any time: ${skillsCommand("setup agents", target)}`));
124757
125150
  return;
124758
125151
  }
124759
125152
  if (answer !== "" && !/^y(es)?$/i.test(answer)) {
124760
- console.log(source_default.dim("Skipped. Run it any time: skills setup agents"));
125153
+ console.log(source_default.dim(`Skipped. Run it any time: ${skillsCommand("setup agents", target)}`));
124761
125154
  return;
124762
125155
  }
124763
125156
  const { handleMcp: handleMcp2 } = await Promise.resolve().then(() => (init_runtime_mcp(), exports_runtime_mcp));
124764
- await handleMcp2({ register: "all", json: false });
125157
+ await handleMcp2({ register: "all", json: false, apiUrl: target.origin });
124765
125158
  process.exitCode = before2 ?? 0;
124766
125159
  }
124767
125160
  function promptHidden(question) {
@@ -124834,7 +125227,7 @@ async function doLogin(email5, code2, json3, target) {
124834
125227
  if (!json3)
124835
125228
  console.log(source_default.green("\u2713 Code sent to " + email5));
124836
125229
  if (json3 || !isTTY || !process.stderr.isTTY) {
124837
- console.log(JSON.stringify({ status: "code_sent", email: email5, message: `Supply the fresh six-digit code on stdin to: skills login --email ${email5} --code-stdin${targetFlag(target)}` }));
125230
+ console.log(JSON.stringify({ status: "code_sent", email: email5, message: `Supply the fresh six-digit code on stdin to: ${skillsCommand("login", target)} --email ${skillsShellArgument(email5)} --code-stdin${targetFlag(target)}` }));
124838
125231
  return;
124839
125232
  }
124840
125233
  const answer = await promptCode();
@@ -124844,6 +125237,7 @@ async function doLogin(email5, code2, json3, target) {
124844
125237
  }
124845
125238
  let verifyRes;
124846
125239
  try {
125240
+ target.unchanged?.();
124847
125241
  verifyRes = await apiRequest("/api/auth/verify", {
124848
125242
  method: "POST",
124849
125243
  body: JSON.stringify({ email: email5, code: code2 })
@@ -124857,7 +125251,7 @@ async function doLogin(email5, code2, json3, target) {
124857
125251
  return;
124858
125252
  }
124859
125253
  try {
124860
- await persistSignIn(verifyRes, origin, env3, "sign-in");
125254
+ await persistSignIn(verifyRes, origin, env3, "sign-in", target.unchanged);
124861
125255
  } catch (err) {
124862
125256
  writeCommandError(err, "Login succeeded but API key creation failed", json3);
124863
125257
  return;
@@ -124886,6 +125280,7 @@ async function doApiKeyLogin(apiKey, json3, target) {
124886
125280
  }
124887
125281
  let whoami;
124888
125282
  try {
125283
+ target.unchanged?.();
124889
125284
  whoami = await apiRequest("/api/auth/whoami", {
124890
125285
  headers: { Authorization: `Bearer ${trimmed}` }
124891
125286
  }, origin);
@@ -124898,20 +125293,25 @@ async function doApiKeyLogin(apiKey, json3, target) {
124898
125293
  const orgId = stringField2(identity6.orgId);
124899
125294
  const orgSlug = stringField2(identity6.organization);
124900
125295
  const userId = stringField2(identity6.userId);
124901
- saveAuthConfig({
124902
- apiKey: trimmed,
124903
- ...email5 ? { email: email5 } : {},
124904
- ...orgId ? { orgId } : {},
124905
- ...orgSlug ? { orgSlug } : {},
124906
- ...userId ? { userId } : {}
124907
- }, env3, origin, "api-key");
125296
+ try {
125297
+ saveAuthConfig({
125298
+ apiKey: trimmed,
125299
+ ...email5 ? { email: email5 } : {},
125300
+ ...orgId ? { orgId } : {},
125301
+ ...orgSlug ? { orgSlug } : {},
125302
+ ...userId ? { userId } : {}
125303
+ }, env3, origin, "api-key", target.unchanged);
125304
+ } catch (error61) {
125305
+ writeCommandError(error61, "API key verified but the selected profile changed", json3);
125306
+ return;
125307
+ }
124908
125308
  if (json3 || !isTTY) {
124909
- console.log(JSON.stringify({ ...identity6, status: "authenticated", apiUrl: origin, next: ["skills setup agents"] }, null, 2));
125309
+ console.log(JSON.stringify({ ...identity6, status: "authenticated", apiUrl: origin, next: [skillsCommand("setup agents", target)] }, null, 2));
124910
125310
  return;
124911
125311
  }
124912
125312
  printWhoami(identity6);
124913
125313
  console.log(source_default.dim(`Server: ${origin}`));
124914
- await offerAgentSetup();
125314
+ await offerAgentSetup(target);
124915
125315
  }
124916
125316
  function printDeviceCode(session, resumed, write) {
124917
125317
  write(source_default.bold(resumed ? `
@@ -124932,12 +125332,12 @@ async function doDeviceLogin(options, target) {
124932
125332
  const origin = target.origin;
124933
125333
  const json3 = Boolean(options.json);
124934
125334
  const interactive = Boolean(isTTY && !json3);
124935
- const next = `skills login --poll${targetFlag(target)}`;
125335
+ const next = `${skillsCommand("login", target)} --poll${targetFlag(target)}`;
124936
125336
  let session = options.poll ? loadPendingDeviceSignIn(origin, env3) : null;
124937
125337
  if (options.poll && !session) {
124938
125338
  const others = pendingDeviceSignInOrigins(env3).filter((other) => other !== origin);
124939
125339
  if (others.length > 0) {
124940
- writeCommandError(new Error(`No pending sign-in for ${origin}. Pending: ${others.map((other) => `skills login --poll --url ${other}`).join("; ")}`), "No pending sign-in", json3);
125340
+ writeCommandError(new Error(`No pending sign-in for ${origin}. Pending: ${others.map((other) => `${skillsProfileCommand("login", process.env, other)} --poll --url ${skillsShellArgument(other)}`).join("; ")}`), "No pending sign-in", json3);
124941
125341
  return;
124942
125342
  }
124943
125343
  }
@@ -124988,7 +125388,10 @@ Waiting for authentication...`));
124988
125388
  try {
124989
125389
  const deviceCode = session.deviceCode;
124990
125390
  outcome = await pollDeviceAuthorization({
124991
- poll: () => pollDeviceToken(origin, deviceCode),
125391
+ poll: () => {
125392
+ target.unchanged?.();
125393
+ return pollDeviceToken(origin, deviceCode);
125394
+ },
124992
125395
  intervalSeconds: session.interval,
124993
125396
  deadline: Math.min(Date.now() + timeoutMs, session.expiresAt),
124994
125397
  onSlowDown: (intervalMs) => {
@@ -125002,8 +125405,8 @@ Waiting for authentication...`));
125002
125405
  }
125003
125406
  if (outcome.status !== "authorized") {
125004
125407
  const ended = {
125005
- expired: "The sign-in code expired before it was approved. Start again: skills login",
125006
- invalid: "The server no longer recognises this sign-in code. Start again: skills login",
125408
+ expired: `The sign-in code expired before it was approved. Start again: ${skillsCommand("login", target)}${targetFlag(target)}`,
125409
+ invalid: `The server no longer recognises this sign-in code. Start again: ${skillsCommand("login", target)}${targetFlag(target)}`,
125007
125410
  denied: "Sign-in was denied in the browser.",
125008
125411
  timeout: `Device login timed out before browser authentication completed. Resume with: ${next}`,
125009
125412
  cancelled: "Sign-in cancelled."
@@ -125019,7 +125422,7 @@ Waiting for authentication...`));
125019
125422
  return;
125020
125423
  }
125021
125424
  try {
125022
- await persistSignIn(outcome.result, origin, env3, "sign-in");
125425
+ await persistSignIn(outcome.result, origin, env3, "sign-in", target.unchanged);
125023
125426
  } catch (err) {
125024
125427
  writeCommandError(err, "Login succeeded but API key creation failed", json3);
125025
125428
  return;
@@ -125271,6 +125674,7 @@ var init_auth = __esm(() => {
125271
125674
  init_auth_store();
125272
125675
  init_fleet_credentials();
125273
125676
  init_remote_client();
125677
+ init_credential_profile_command();
125274
125678
  init_sign_in();
125275
125679
  init_remote_auth();
125276
125680
  isTTY = process.stdin.isTTY && process.stdout.isTTY;
@@ -125922,11 +126326,11 @@ var init_storage2 = __esm(() => {
125922
126326
  });
125923
126327
 
125924
126328
  // src/lib/registry-reconcile.ts
125925
- 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";
125926
126330
  import { join as join80 } from "path";
125927
126331
  function isDirectory2(path) {
125928
126332
  try {
125929
- return statSync27(path).isDirectory();
126333
+ return statSync28(path).isDirectory();
125930
126334
  } catch {
125931
126335
  return false;
125932
126336
  }
@@ -133962,6 +134366,7 @@ function InstallProgress({
133962
134366
  // src/cli/components/AccountView.tsx
133963
134367
  var import_react29 = __toESM(require_react(), 1);
133964
134368
  init_fleet_credentials();
134369
+ init_credential_profile_command();
133965
134370
  init_sign_in();
133966
134371
  var jsx_dev_runtime6 = __toESM(require_jsx_dev_runtime(), 1);
133967
134372
  var SLASH_COMMANDS = [
@@ -134021,7 +134426,7 @@ function AccountView({ action, argument, onDone }) {
134021
134426
  });
134022
134427
  return;
134023
134428
  }
134024
- const target = resolveSkillsSignInOrigin(process.env, {}, argument);
134429
+ const target = captureSkillsSignInTarget(process.env, {}, argument);
134025
134430
  const refusal3 = gatewaySignInRefusal(target);
134026
134431
  if (refusal3)
134027
134432
  throw refusal3;
@@ -134032,13 +134437,16 @@ function AccountView({ action, argument, onDone }) {
134032
134437
  update2({ kind: "waiting", userCode: start.userCode, url: url2, origin: target.origin });
134033
134438
  openVerificationPage(url2, target.origin);
134034
134439
  const outcome = await pollDeviceAuthorization({
134035
- poll: () => pollDeviceToken(target.origin, start.deviceCode),
134440
+ poll: () => {
134441
+ target.unchanged?.();
134442
+ return pollDeviceToken(target.origin, start.deviceCode);
134443
+ },
134036
134444
  intervalSeconds: start.interval,
134037
134445
  deadline: Date.now() + start.expiresIn * 1000,
134038
134446
  signal: controller.signal
134039
134447
  });
134040
134448
  if (outcome.status === "authorized") {
134041
- await persistSignIn(outcome.result, target.origin);
134449
+ await persistSignIn(outcome.result, target.origin, process.env, "sign-in", target.unchanged);
134042
134450
  const email4 = outcome.result.user?.email;
134043
134451
  update2({
134044
134452
  kind: "done",
@@ -134046,16 +134454,17 @@ function AccountView({ action, argument, onDone }) {
134046
134454
  lines: [
134047
134455
  { text: email4 ? `Signed in as ${email4}` : "Signed in", tone: "good" },
134048
134456
  { text: `Server: ${target.origin}`, tone: "dim" },
134049
- { text: "Register Skills with your agents from a shell: skills setup agents", tone: "dim" }
134457
+ { text: `Register Skills with your agents from a shell: ${skillsProfileCommand("setup agents", process.env, target.origin)}`, tone: "dim" }
134050
134458
  ]
134051
134459
  });
134052
134460
  return;
134053
134461
  }
134462
+ const retry = argument !== undefined ? `/login ${target.origin}` : "/login";
134054
134463
  const ended = {
134055
- expired: "The sign-in code expired before it was approved. Type /login to start again.",
134056
- invalid: "The server no longer recognises this sign-in code. Type /login to start again.",
134464
+ expired: `The sign-in code expired before it was approved. Type ${retry} to start again.`,
134465
+ invalid: `The server no longer recognises this sign-in code. Type ${retry} to start again.`,
134057
134466
  denied: "Sign-in was denied in the browser.",
134058
- timeout: "Sign-in timed out. Type /login to start again.",
134467
+ timeout: `Sign-in timed out. Type ${retry} to start again.`,
134059
134468
  cancelled: "Sign-in cancelled."
134060
134469
  }[outcome.status];
134061
134470
  update2({ kind: "done", changed: false, lines: [{ text: ended, tone: "bad" }] });