@hasna/skills 0.10.19 → 0.10.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/index.js CHANGED
@@ -36868,7 +36868,7 @@ var package_default;
36868
36868
  var init_package = __esm(() => {
36869
36869
  package_default = {
36870
36870
  name: "@hasna/skills",
36871
- version: "0.10.19",
36871
+ version: "0.10.22",
36872
36872
  description: "Skills library for AI coding agents",
36873
36873
  type: "module",
36874
36874
  bin: {
@@ -39931,12 +39931,14 @@ function assertAgentPolicyCollections(policy) {
39931
39931
  }
39932
39932
  if (bridge.codexPluginSkills !== undefined)
39933
39933
  for (const control of array(bridge.codexPluginSkills, 4096)) {
39934
- requireBound(object(control) && Object.keys(control).every((key) => ["name", "pluginId", "namespace", "pluginParent", "manifestSha256", "appSha256"].includes(key)));
39934
+ requireBound(object(control) && Object.keys(control).every((key) => ["name", "pluginId", "namespace", "pluginParent", "manifestSha256", "appSha256", "remotePluginId"].includes(key)));
39935
39935
  text(control.name, 129);
39936
39936
  text(control.pluginId, 1024);
39937
39937
  text(control.namespace, 64);
39938
39938
  text(control.pluginParent);
39939
39939
  requireBound(isAbsolute2(control.pluginParent) && resolve3(control.pluginParent) === control.pluginParent && /^[a-f0-9]{64}$/.test(control.manifestSha256));
39940
+ if (control.remotePluginId !== undefined)
39941
+ requireBound(typeof control.remotePluginId === "string" && /^[A-Za-z0-9_~-]{1,1024}$/.test(control.remotePluginId));
39940
39942
  if (control.appSha256 !== undefined)
39941
39943
  requireBound(typeof control.appSha256 === "string" && /^[a-f0-9]{64}$/.test(control.appSha256));
39942
39944
  }
@@ -39959,8 +39961,8 @@ function assertAgentPolicyCollections(policy) {
39959
39961
  text(source.path);
39960
39962
  requireBound(source.sha256 === null || typeof source.sha256 === "string" && /^[a-f0-9]{64}$/.test(source.sha256));
39961
39963
  if (source.hashMode !== undefined)
39962
- requireBound(["bytes", "path-bytes", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1", "claude-settings-v2", "claude-settings-v3", "claude-marketplace-registry-v2", "codex-settings-v1"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
39963
- if (source.hashMode === "codex-settings-v1")
39964
+ requireBound(["bytes", "path-bytes", "claude-plugin-registry", "claude-marketplace-registry", "claude-settings-v1", "claude-settings-v2", "claude-settings-v3", "claude-marketplace-registry-v2", "codex-settings-v1", "codex-settings-v2"].includes(source.hashMode) && source.format === undefined && source.fields === undefined && (source.hashMode === "bytes" || source.sha256 !== null));
39965
+ if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2")
39964
39966
  requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute2(source.path) && resolve3(source.path) === source.path && basename2(source.path) === "config.toml");
39965
39967
  if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3")
39966
39968
  requireBound(agent === "claude" && value.agent === "claude" && value.method === "reviewed" && !/[\x00-\x1f\x7f]/.test(source.path) && isAbsolute2(source.path) && resolve3(source.path) === source.path && basename2(source.path) === "settings.json");
@@ -50884,6 +50886,28 @@ var init_claude_settings_witness = __esm(() => {
50884
50886
  PERSISTED_EFFORT_LEVELS = new Set(["low", "medium", "high", "xhigh"]);
50885
50887
  });
50886
50888
 
50889
+ // src/lib/codex-native-compatibility.ts
50890
+ function supportsCodexNativeCapability(version, capability) {
50891
+ return typeof version === "string" && Object.hasOwn(MEASURED_CODEX_CAPABILITIES, version) && MEASURED_CODEX_CAPABILITIES[version].includes(capability);
50892
+ }
50893
+ var MEASURED_CODEX_CAPABILITIES, SUPPORTED_CODEX_HOOK_VERSIONS;
50894
+ var init_codex_native_compatibility = __esm(() => {
50895
+ MEASURED_CODEX_CAPABILITIES = {
50896
+ "codex-cli 0.153.0": ["hooks"],
50897
+ "codex-cli 0.154.0": ["hooks"],
50898
+ "codex-cli 0.155.0": ["hooks"],
50899
+ "codex-cli 0.155.1": ["hooks"],
50900
+ "codex-cli 0.156.1": ["hooks"],
50901
+ "codex-cli 0.157.0": ["hooks"],
50902
+ "codex-cli 0.157.1": ["hooks"],
50903
+ "codex-cli 0.158.0": ["hooks"],
50904
+ "codex-cli 0.159.0": ["hooks"],
50905
+ "codex-cli 0.159.2": ["hooks", "qualified-skill-catalog"],
50906
+ "codex-cli 0.160.0": ["hooks", "qualified-skill-catalog"]
50907
+ };
50908
+ SUPPORTED_CODEX_HOOK_VERSIONS = Object.freeze(Object.keys(MEASURED_CODEX_CAPABILITIES).filter((version) => supportsCodexNativeCapability(version, "hooks")));
50909
+ });
50910
+
50887
50911
  // src/lib/codex-hook-rpc.ts
50888
50912
  import { execFile, spawn as spawn2 } from "child_process";
50889
50913
  import { realpathSync as realpathSync3, statSync as statSync7 } from "fs";
@@ -50906,7 +50930,7 @@ async function connectCodexHookRpc(options) {
50906
50930
  } catch {
50907
50931
  throw new Error("CODEX_HOOK_TRUST_NATIVE_UNAVAILABLE");
50908
50932
  }
50909
- if (!SUPPORTED_CODEX_HOOK_VERSIONS.includes(version))
50933
+ if (!supportsCodexNativeCapability(version, "hooks"))
50910
50934
  throw new Error("CODEX_HOOK_TRUST_NATIVE_UNSUPPORTED_VERSION");
50911
50935
  const current = statSync7(binary);
50912
50936
  if (realpathSync3(found) !== binary || ["dev", "ino", "size", "mtimeMs", "ctimeMs"].some((k) => stat[k] !== current[k]))
@@ -51025,9 +51049,9 @@ async function connectCodexHookRpc(options) {
51025
51049
  throw new Error("CODEX_HOOK_TRUST_NATIVE_UNSUPPORTED: native hooks/list and versioned config writes are required");
51026
51050
  }
51027
51051
  }
51028
- var SUPPORTED_CODEX_HOOK_VERSIONS;
51029
51052
  var init_codex_hook_rpc = __esm(() => {
51030
- SUPPORTED_CODEX_HOOK_VERSIONS = ["codex-cli 0.153.0", "codex-cli 0.154.0", "codex-cli 0.155.0", "codex-cli 0.155.1", "codex-cli 0.156.1", "codex-cli 0.157.0", "codex-cli 0.157.1", "codex-cli 0.158.0", "codex-cli 0.159.0", "codex-cli 0.159.2"];
51053
+ init_codex_native_compatibility();
51054
+ init_codex_native_compatibility();
51031
51055
  });
51032
51056
 
51033
51057
  // src/lib/codex-native-skill-catalog.ts
@@ -51052,6 +51076,47 @@ function projectCodexNativeSkillCatalog(response, cwd2) {
51052
51076
  return { name: value.name, path: value.path, enabled: value.enabled, pluginId: value.pluginId ?? null };
51053
51077
  });
51054
51078
  }
51079
+ function projectCodexInstalledPlugins(response) {
51080
+ if (!object4(response) || !Array.isArray(response.marketplaces) || !Array.isArray(response.marketplaceLoadErrors) || response.marketplaceLoadErrors.length !== 0 || response.marketplaces.length > MAX_SKILLS)
51081
+ refuse();
51082
+ const plugins = [];
51083
+ for (const marketplace of response.marketplaces) {
51084
+ if (!object4(marketplace) || !scalar(marketplace.name, MAX_NAME_BYTES) || !Array.isArray(marketplace.plugins) || marketplace.plugins.length > MAX_SKILLS)
51085
+ refuse();
51086
+ for (const value of marketplace.plugins) {
51087
+ if (!object4(value) || !scalar(value.id, MAX_PLUGIN_ID_BYTES) || !scalar(value.name, MAX_NAME_BYTES) || value.id !== `${value.name}@${marketplace.name}`)
51088
+ refuse();
51089
+ plugins.push({
51090
+ ...value,
51091
+ marketplace: marketplace.name,
51092
+ sourceType: object4(value.source) && value.source.type === "remote" ? "remote" : undefined
51093
+ });
51094
+ }
51095
+ }
51096
+ return projectCodexInstalledPluginEntries(plugins);
51097
+ }
51098
+ function projectCodexInstalledPluginEntries(value) {
51099
+ if (!Array.isArray(value) || value.length > MAX_SKILLS)
51100
+ refuse();
51101
+ const ids = new Set;
51102
+ return value.map((item) => {
51103
+ if (!object4(item) || !scalar(item.id, MAX_PLUGIN_ID_BYTES) || !scalar(item.name, MAX_NAME_BYTES) || typeof item.installed !== "boolean" || typeof item.enabled !== "boolean" || item.localVersion !== null && !scalar(item.localVersion, MAX_NAME_BYTES) || item.remotePluginId !== undefined && item.remotePluginId !== null && !remotePluginIdentifier(item.remotePluginId) || item.sourceType !== undefined && item.sourceType !== "remote")
51104
+ refuse();
51105
+ const at2 = item.id.lastIndexOf("@");
51106
+ if (at2 < 1 || item.id.slice(0, at2) !== item.name || at2 === item.id.length - 1 || ids.has(item.id))
51107
+ refuse();
51108
+ ids.add(item.id);
51109
+ return {
51110
+ id: item.id,
51111
+ name: item.name,
51112
+ installed: item.installed,
51113
+ enabled: item.enabled,
51114
+ localVersion: item.localVersion ?? null,
51115
+ ...item.sourceType === "remote" ? { sourceType: "remote" } : {},
51116
+ ...item.remotePluginId == null ? {} : { remotePluginId: item.remotePluginId }
51117
+ };
51118
+ });
51119
+ }
51055
51120
  async function captureCodexNativeSkillCatalog(options, connect = connectCodexHookRpc) {
51056
51121
  if (!absolutePath2(options.cwd) || !absolutePath2(options.home))
51057
51122
  refuse();
@@ -51062,10 +51127,16 @@ async function captureCodexNativeSkillCatalog(options, connect = connectCodexHoo
51062
51127
  ...options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }
51063
51128
  });
51064
51129
  try {
51065
- if (!SUPPORTED_NAME_CONTROL_VERSIONS.has(rpc.version))
51130
+ if (!supportsCodexNativeCapability(rpc.version, "qualified-skill-catalog"))
51066
51131
  throw new Error("CODEX_NATIVE_SKILL_CATALOG_UNSUPPORTED_VERSION");
51067
51132
  const response = await rpc.request("skills/list", { cwds: [options.cwd], forceReload: true });
51068
- return { version: rpc.version, cwd: options.cwd, skills: projectCodexNativeSkillCatalog(response, options.cwd) };
51133
+ const installed = await rpc.request("plugin/installed", { cwds: [options.cwd] });
51134
+ return {
51135
+ version: rpc.version,
51136
+ cwd: options.cwd,
51137
+ skills: projectCodexNativeSkillCatalog(response, options.cwd),
51138
+ plugins: projectCodexInstalledPlugins(installed)
51139
+ };
51069
51140
  } finally {
51070
51141
  await rpc.close();
51071
51142
  }
@@ -51107,18 +51178,33 @@ function isCodexNativeSkillDisabled(skill, rules) {
51107
51178
  }
51108
51179
  return disabled;
51109
51180
  }
51110
- var MAX_SKILLS = 4096, MAX_NAME_BYTES = 1024, MAX_PATH_BYTES = 16384, SUPPORTED_NAME_CONTROL_VERSIONS, object4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value), scalar = (value, max2) => typeof value === "string" && value.length > 0 && value.trim() === value && Buffer.byteLength(value, "utf8") <= max2 && !/[\u0000-\u001f\u007f]/u.test(value), absolutePath2 = (value) => scalar(value, MAX_PATH_BYTES) && isAbsolute10(value);
51181
+ var MAX_SKILLS = 4096, MAX_NAME_BYTES = 1024, MAX_PATH_BYTES = 16384, MAX_PLUGIN_ID_BYTES = 1024, object4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value), scalar = (value, max2) => typeof value === "string" && value.length > 0 && value.trim() === value && Buffer.byteLength(value, "utf8") <= max2 && !/[\u0000-\u001f\u007f]/u.test(value), remotePluginIdentifier = (value) => typeof value === "string" && /^[A-Za-z0-9_~-]{1,1024}$/.test(value), absolutePath2 = (value) => scalar(value, MAX_PATH_BYTES) && isAbsolute10(value);
51111
51182
  var init_codex_native_skill_catalog = __esm(() => {
51112
51183
  init_codex_hook_rpc();
51113
- SUPPORTED_NAME_CONTROL_VERSIONS = new Set(["codex-cli 0.159.2"]);
51184
+ init_codex_native_compatibility();
51114
51185
  });
51115
51186
 
51116
51187
  // src/lib/codex-plugin-skill-controls.ts
51117
- import { dirname as dirname10, join as join18, resolve as resolve10, sep as sep4 } from "path";
51188
+ import { basename as basename5, dirname as dirname10, join as join18, relative as relative4, resolve as resolve10, sep as sep4 } from "path";
51118
51189
  import { lstatSync as lstatSync12, readdirSync as readdirSync6, readlinkSync as readlinkSync3, realpathSync as realpathSync5 } from "fs";
51119
51190
  function refuse2() {
51120
51191
  throw new Error("CODEX_NATIVE_SKILL_IDENTITY_UNSUPPORTED: review native plugin names and hook controls");
51121
51192
  }
51193
+ function remoteInstallationMatches(parent, remotePluginId, read2) {
51194
+ try {
51195
+ if (!remotePluginIdentifier(remotePluginId) || !lstatSync12(parent).isDirectory() || realpathSync5(parent) !== parent)
51196
+ return false;
51197
+ const path = join18(parent, ".codex-remote-plugin-install.json"), stat = lstatSync12(path, { throwIfNoEntry: false });
51198
+ if (!stat?.isFile() || stat.isSymbolicLink() || stat.size > 16384)
51199
+ return false;
51200
+ const text2 = read2(path);
51201
+ hashNativeJsonControls(text2);
51202
+ const value = JSON.parse(text2);
51203
+ return Boolean(value && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 2 && value.schema_version === 1 && value.remote_plugin_id === remotePluginId);
51204
+ } catch {
51205
+ return false;
51206
+ }
51207
+ }
51122
51208
  function appControls(path, read2) {
51123
51209
  const text2 = read2(path);
51124
51210
  let value, sha2562;
@@ -51154,6 +51240,9 @@ function rootControls(root, read2) {
51154
51240
  }
51155
51241
  if (!manifest || typeof manifest !== "object" || Array.isArray(manifest) || !identifier2(manifest.name))
51156
51242
  refuse2();
51243
+ const cacheVersion = basename5(root), declaredVersion = manifest.version === undefined ? "" : typeof manifest.version === "string" ? manifest.version.trim() : null;
51244
+ if (declaredVersion === null || (declaredVersion ? declaredVersion !== cacheVersion : cacheVersion !== CODEX_DEFAULT_AGENT_PLUGIN_VERSION))
51245
+ refuse2();
51157
51246
  if (manifest.hooks !== undefined || manifest.mcpServers !== undefined || manifest.commands !== undefined || manifest.apps !== undefined && manifest.apps !== "./.app.json" || ["hooks", ".mcp.json"].some((path) => lstatSync12(join18(root, path), { throwIfNoEntry: false })))
51158
51247
  refuse2();
51159
51248
  const app = join18(root, ".app.json"), present = lstatSync12(app, { throwIfNoEntry: false });
@@ -51205,6 +51294,10 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache3, controls, read2) {
51205
51294
  for (const parent of new Set(controls.map((control) => control.pluginParent))) {
51206
51295
  if (!parent.startsWith(cache3 + sep4) || !lstatSync12(parent, { throwIfNoEntry: false })?.isDirectory())
51207
51296
  return false;
51297
+ for (const control of controls.filter((control2) => control2.pluginParent === parent)) {
51298
+ if (control.remotePluginId !== undefined && !remoteInstallationMatches(parent, control.remotePluginId, read2))
51299
+ return false;
51300
+ }
51208
51301
  const names = readdirSync6(parent);
51209
51302
  entries += names.length;
51210
51303
  if (entries > 4096)
@@ -51230,22 +51323,56 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache3, controls, read2) {
51230
51323
  return false;
51231
51324
  }
51232
51325
  }
51233
- function reviewCodexPluginSkillControls(catalog, documents, cache3, cwd2, read2) {
51234
- if (catalog?.version !== "codex-cli 0.159.2" || catalog.cwd !== cwd2)
51326
+ function reviewCodexPluginSkillControls(catalog, documents, cache3, cwd2, read2, rules) {
51327
+ if (!supportsCodexNativeCapability(catalog?.version, "qualified-skill-catalog") || catalog.cwd !== cwd2)
51235
51328
  refuse2();
51236
51329
  const skills = projectCodexNativeSkillCatalog({ data: [{ cwd: cwd2, errors: [], skills: catalog.skills }] }, cwd2);
51237
51330
  const allowed = new Set(documents), result2 = [];
51238
- for (const skill of skills) {
51239
- if (!allowed.has(skill.path) || !skill.path.startsWith(cache3 + sep4))
51331
+ let installedPlugins;
51332
+ try {
51333
+ installedPlugins = projectCodexInstalledPluginEntries(catalog.plugins ?? []);
51334
+ } catch {
51335
+ refuse2();
51336
+ }
51337
+ const candidates = catalog.plugins === undefined ? skills.map((skill) => skill.path).filter((path) => allowed.has(path)) : allowed;
51338
+ for (const document3 of candidates) {
51339
+ if (!document3.startsWith(cache3 + sep4))
51240
51340
  continue;
51241
- if (skills.filter((other) => other.name === skill.name).length !== 1)
51341
+ const parsed = identity4(document3, cache3, read2);
51342
+ if (parsed.name === "skills-cli" || parsed.name.endsWith(":skills-cli"))
51242
51343
  refuse2();
51243
- if (!skill.pluginId || skill.name === "skills-cli" || skill.name.endsWith(":skills-cli"))
51344
+ const cacheParts = relative4(cache3, parsed.pluginParent).split(sep4);
51345
+ if (cacheParts.length !== 2 || cacheParts.some((part) => !identifier2(part)))
51244
51346
  refuse2();
51245
- const parsed = identity4(skill.path, cache3, read2);
51246
- if (parsed.name !== skill.name)
51347
+ const [marketplace, pluginName] = cacheParts;
51348
+ if (pluginName !== parsed.namespace)
51247
51349
  refuse2();
51248
- result2.push({ ...parsed, pluginId: skill.pluginId });
51350
+ const expectedPluginId = `${pluginName}@${marketplace}`;
51351
+ const listed = skills.filter((skill) => skill.path === document3);
51352
+ if (listed.length > 1)
51353
+ refuse2();
51354
+ let remotePluginId;
51355
+ if (listed.length === 1) {
51356
+ if (listed[0].name !== parsed.name || listed[0].pluginId !== expectedPluginId)
51357
+ refuse2();
51358
+ } else {
51359
+ const installed = installedPlugins.filter((plugin2) => plugin2.id === expectedPluginId && plugin2.name === pluginName);
51360
+ if (installed.length !== 1 || !installed[0].installed || !installed[0].enabled)
51361
+ refuse2();
51362
+ const plugin = installed[0];
51363
+ if (plugin.localVersion !== null) {
51364
+ if (plugin.localVersion !== basename5(dirname10(dirname10(dirname10(document3)))))
51365
+ continue;
51366
+ } else {
51367
+ if (plugin.sourceType !== "remote" || !plugin.remotePluginId || !remoteInstallationMatches(parsed.pluginParent, plugin.remotePluginId, read2) || !lstatSync12(document3).isFile() || realpathSync5(document3) !== document3)
51368
+ refuse2();
51369
+ remotePluginId = plugin.remotePluginId;
51370
+ }
51371
+ const exactPathDeny = Array.isArray(rules) && rules.some((rule) => rule?.path === document3 && rule?.enabled === false);
51372
+ if (!exactPathDeny || !isCodexNativeSkillDisabled({ name: parsed.name, path: document3, pluginId: expectedPluginId, enabled: true }, rules))
51373
+ refuse2();
51374
+ }
51375
+ result2.push({ ...parsed, pluginId: expectedPluginId, ...remotePluginId ? { remotePluginId } : {} });
51249
51376
  }
51250
51377
  if (!result2.length || new Set(result2.map((item) => item.name)).size !== result2.length)
51251
51378
  refuse2();
@@ -51261,7 +51388,7 @@ function isReviewedCodexPluginSkillDisabled(document3, cache3, controls, rules,
51261
51388
  return false;
51262
51389
  }
51263
51390
  const reviewed = controls.find((item) => item.name === parsed.name && item.namespace === parsed.namespace && item.pluginParent === parsed.pluginParent && item.manifestSha256 === parsed.manifestSha256 && item.appSha256 === parsed.appSha256);
51264
- if (!reviewed)
51391
+ if (!reviewed || reviewed.remotePluginId !== undefined && !remoteInstallationMatches(reviewed.pluginParent, reviewed.remotePluginId, read2))
51265
51392
  return false;
51266
51393
  return isCodexNativeSkillDisabled({ name: parsed.name, path: document3, pluginId: reviewed.pluginId, enabled: true }, rules);
51267
51394
  }
@@ -51279,13 +51406,14 @@ enabled = false
51279
51406
  }
51280
51407
  return text2;
51281
51408
  }
51282
- var identifier2 = (v) => typeof v === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(v);
51409
+ var identifier2 = (v) => typeof v === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(v), CODEX_DEFAULT_AGENT_PLUGIN_VERSION = "1.0.0";
51283
51410
  var init_codex_plugin_skill_controls = __esm(() => {
51284
51411
  init_claude_settings_witness();
51412
+ init_codex_native_compatibility();
51285
51413
  init_codex_native_skill_catalog();
51286
51414
  });
51287
51415
 
51288
- // src/lib/codex-settings-witness.ts
51416
+ // src/lib/codex-settings-witness-v1.ts
51289
51417
  import { createHash as createHash9 } from "crypto";
51290
51418
  function need3(value) {
51291
51419
  if (!value)
@@ -51376,21 +51504,173 @@ function captureCodexSettings(path, budget = { remaining: 256 * 1024 * 1024 }) {
51376
51504
  const text2 = readNativeSettingsWitnessFile(path, budget, "config.toml");
51377
51505
  return { path, hashMode: "codex-settings-v1", sha256: hashCodexSettingsReplacement(text2) };
51378
51506
  }
51507
+ var sha = (text2) => createHash9("sha256").update(text2).digest("hex"), EFFORT, VERBOSITY;
51508
+ var init_codex_settings_witness_v1 = __esm(() => {
51509
+ init_claude_settings_witness();
51510
+ EFFORT = new Set(["none", "minimal", "low", "medium", "high", "xhigh"]);
51511
+ VERBOSITY = new Set(["low", "medium", "high"]);
51512
+ });
51513
+
51514
+ // src/lib/codex-settings-witness.ts
51515
+ import { createHash as createHash10 } from "crypto";
51516
+ function need4(value) {
51517
+ if (!value)
51518
+ throw new Error("Invalid Codex settings witness");
51519
+ }
51520
+ function isRecord3(value) {
51521
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
51522
+ }
51523
+ function isDate2(value) {
51524
+ return value instanceof Date;
51525
+ }
51526
+ function numericTokens2(text2) {
51527
+ const result2 = [];
51528
+ for (let at2 = 0;at2 < text2.length; ) {
51529
+ const char = text2[at2];
51530
+ if (char === "#") {
51531
+ while (at2 < text2.length && text2[at2] !== `
51532
+ `)
51533
+ at2++;
51534
+ continue;
51535
+ }
51536
+ if (char === '"' || char === "'") {
51537
+ const quote = char, triple = text2.slice(at2, at2 + 3) === quote.repeat(3);
51538
+ at2 += triple ? 3 : 1;
51539
+ while (at2 < text2.length) {
51540
+ if (quote === '"' && text2[at2] === "\\") {
51541
+ at2 += 2;
51542
+ continue;
51543
+ }
51544
+ if (text2.slice(at2, at2 + (triple ? 3 : 1)) === quote.repeat(triple ? 3 : 1)) {
51545
+ at2 += triple ? 3 : 1;
51546
+ break;
51547
+ }
51548
+ at2++;
51549
+ }
51550
+ continue;
51551
+ }
51552
+ if (/[0-9+-]/.test(char)) {
51553
+ const start = at2;
51554
+ while (at2 < text2.length && !/[\s,\]{}#=]/.test(text2[at2]))
51555
+ at2++;
51556
+ if (at2 > start) {
51557
+ result2.push(text2.slice(start, at2));
51558
+ continue;
51559
+ }
51560
+ }
51561
+ at2++;
51562
+ }
51563
+ return result2.sort();
51564
+ }
51565
+ function canonical4(value, depth = 0, budget = { remaining: 65536 }) {
51566
+ need4(depth <= 32 && --budget.remaining >= 0);
51567
+ if (value === null)
51568
+ return ["null"];
51569
+ if (typeof value === "string")
51570
+ return ["string", value];
51571
+ if (typeof value === "boolean")
51572
+ return ["boolean", value];
51573
+ if (typeof value === "number") {
51574
+ need4(Number.isFinite(value));
51575
+ return ["number", String(value)];
51576
+ }
51577
+ if (isDate2(value)) {
51578
+ need4(Number.isFinite(value.getTime()));
51579
+ return ["date", value.toISOString()];
51580
+ }
51581
+ if (Array.isArray(value))
51582
+ return ["array", value.map((child) => canonical4(child, depth + 1, budget))];
51583
+ need4(isRecord3(value));
51584
+ return ["object", Object.entries(value).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, child]) => [key, canonical4(child, depth + 1, budget)])];
51585
+ }
51586
+ function normalize3(config) {
51587
+ if (isRecord3(config.hooks)) {
51588
+ delete config.hooks.state;
51589
+ if (!Object.keys(config.hooks).length)
51590
+ delete config.hooks;
51591
+ }
51592
+ if (isRecord3(config.skills) && Array.isArray(config.skills.config)) {
51593
+ const skills = config.skills;
51594
+ const retained = skills.config.filter((entry) => !disablesOneSkill(entry));
51595
+ if (retained.length !== skills.config.length) {
51596
+ if (retained.length)
51597
+ skills.config = retained;
51598
+ else
51599
+ delete skills.config;
51600
+ }
51601
+ if (!Object.keys(skills).length)
51602
+ delete config.skills;
51603
+ }
51604
+ inference(config);
51605
+ if (isRecord3(config.profiles)) {
51606
+ for (const profile of Object.values(config.profiles))
51607
+ if (isRecord3(profile))
51608
+ inference(profile);
51609
+ }
51610
+ }
51611
+ function disablesOneSkill(entry) {
51612
+ if (!isRecord3(entry) || entry.enabled !== false)
51613
+ return false;
51614
+ const keys2 = Object.keys(entry);
51615
+ if (!keys2.every((key) => key === "path" || key === "name" || key === "enabled"))
51616
+ return false;
51617
+ const selector = ["path", "name"].filter((key) => Object.hasOwn(entry, key));
51618
+ return selector.length === 1 && typeof entry[selector[0]] === "string" && entry[selector[0]].length > 0;
51619
+ }
51620
+ function inference(target) {
51621
+ for (const key of INFERENCE)
51622
+ if (Object.hasOwn(target, key)) {
51623
+ const value = target[key];
51624
+ if (key === "model")
51625
+ need4(typeof value === "string" && MODEL.test(value));
51626
+ else
51627
+ need4(typeof value === "string" && (key === "model_reasoning_effort" ? EFFORT2.has(value) : VERBOSITY2.has(value)));
51628
+ delete target[key];
51629
+ }
51630
+ }
51631
+ function settingsDigest2(text2) {
51632
+ let config;
51633
+ try {
51634
+ config = Bun.TOML.parse(text2);
51635
+ } catch {
51636
+ throw new Error("Invalid Codex settings witness");
51637
+ }
51638
+ need4(isRecord3(config));
51639
+ normalize3(config);
51640
+ return sha2(`hasna.skills.codex-settings.v2\x00${JSON.stringify([canonical4(config), numericTokens2(text2)])}`);
51641
+ }
51642
+ function hashCodexSettingsReplacementV2(text2, budget = { remaining: 256 * 1024 * 1024 }) {
51643
+ need4(Buffer.byteLength(text2) <= 1024 * 1024 && budget.remaining >= Buffer.byteLength(text2));
51644
+ budget.remaining -= Buffer.byteLength(text2);
51645
+ return settingsDigest2(text2);
51646
+ }
51647
+ function captureCodexSettingsV2(path, budget = { remaining: 256 * 1024 * 1024 }) {
51648
+ const text2 = readNativeSettingsWitnessFile(path, budget, "config.toml");
51649
+ return { path, hashMode: "codex-settings-v2", sha256: settingsDigest2(text2) };
51650
+ }
51651
+ function readCodexSettingsPreimage(path, budget = { remaining: 2 * 1024 * 1024 }) {
51652
+ return readNativeSettingsWitnessFile(path, budget, "config.toml");
51653
+ }
51379
51654
  function upgradeCodexSettingsWitness(previous, reviewedSettingsPath) {
51380
- need3(previous && Object.keys(previous).every((key) => ["path", "hashMode", "sha256"].includes(key)) && (previous.hashMode === undefined || previous.hashMode === "bytes") && /^[a-f0-9]{64}$/.test(previous.sha256));
51655
+ need4(previous && Object.keys(previous).every((key) => ["path", "hashMode", "sha256"].includes(key)) && (previous.hashMode === undefined || previous.hashMode === "bytes" || previous.hashMode === "codex-settings-v1") && /^[a-f0-9]{64}$/.test(previous.sha256));
51381
51656
  const budget = { remaining: 2 * 1024 * 1024 };
51382
51657
  const before2 = readNativeSettingsWitnessFile(reviewedSettingsPath, budget, "config.toml"), current = readNativeSettingsWitnessFile(previous.path, budget, "config.toml");
51383
- need3(sha(before2) === previous.sha256);
51384
- const sha2562 = hashCodexSettingsReplacement(current);
51385
- if (hashCodexSettingsReplacement(before2) !== sha2562)
51658
+ need4((previous.hashMode === "codex-settings-v1" ? hashCodexSettingsReplacement(before2) : sha2(before2)) === previous.sha256);
51659
+ const sha2562 = settingsDigest2(current);
51660
+ if (settingsDigest2(before2) !== sha2562)
51386
51661
  throw new Error("Codex non-preference settings changed; explicit discovery review required");
51387
- return { path: previous.path, hashMode: "codex-settings-v1", sha256: sha2562 };
51662
+ return { path: previous.path, hashMode: "codex-settings-v2", sha256: sha2562 };
51388
51663
  }
51389
- var sha = (text2) => createHash9("sha256").update(text2).digest("hex"), EFFORT, VERBOSITY;
51664
+ var sha2 = (text2) => createHash10("sha256").update(text2).digest("hex"), EFFORT2, VERBOSITY2, MODEL, CODEX_DISCOVERY_PROJECTION_FIELDS, INFERENCE;
51390
51665
  var init_codex_settings_witness = __esm(() => {
51666
+ init_codex_settings_witness_v1();
51667
+ init_codex_settings_witness_v1();
51391
51668
  init_claude_settings_witness();
51392
- EFFORT = new Set(["none", "minimal", "low", "medium", "high", "xhigh"]);
51393
- VERBOSITY = new Set(["low", "medium", "high"]);
51669
+ EFFORT2 = new Set(["none", "minimal", "low", "medium", "high", "xhigh"]);
51670
+ VERBOSITY2 = new Set(["low", "medium", "high"]);
51671
+ MODEL = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$/;
51672
+ CODEX_DISCOVERY_PROJECTION_FIELDS = ["plugins", "marketplaces", "skills"];
51673
+ INFERENCE = ["model", "model_reasoning_effort", "model_verbosity"];
51394
51674
  });
51395
51675
 
51396
51676
  // src/lib/managed-policy.ts
@@ -51479,7 +51759,7 @@ var init_managed_policy = __esm(() => {
51479
51759
  });
51480
51760
 
51481
51761
  // src/lib/agent-bridge.ts
51482
- import { createHash as createHash10 } from "crypto";
51762
+ import { createHash as createHash11 } from "crypto";
51483
51763
  import { lstatSync as lstatSync14, readFileSync as readFileSync12, readdirSync as readdirSync7 } from "fs";
51484
51764
  import { join as join20 } from "path";
51485
51765
  function isOwnedCliBridge(path, expectedPaths) {
@@ -51513,7 +51793,7 @@ Use the Skills CLI as the skill authority for this station.
51513
51793
  This bridge contains no skill payloads. Do not copy skill content into agent-native skill directories or load other native skill copies. If a Skills command refuses authority, selection, integrity, or native drift, report that refusal and use its repair guidance; do not substitute bundled or stale local content. Explicit local draft authoring remains available.
51514
51794
  `, CLI_BRIDGE_DIGEST, CLI_BRIDGE_FILES;
51515
51795
  var init_agent_bridge = __esm(() => {
51516
- CLI_BRIDGE_DIGEST = createHash10("sha256").update(markdown).digest("hex");
51796
+ CLI_BRIDGE_DIGEST = createHash11("sha256").update(markdown).digest("hex");
51517
51797
  CLI_BRIDGE_FILES = Object.freeze({
51518
51798
  "SKILL.md": markdown,
51519
51799
  ".hasna-skills.json": `${JSON.stringify({ managedBy: "@hasna/skills", kind: "cli-bridge", version: CLI_BRIDGE_VERSION, protocol: "selection-v1", contentSha256: CLI_BRIDGE_DIGEST }, null, 2)}
@@ -51792,9 +52072,10 @@ var init_agent_codex = __esm(() => {
51792
52072
  });
51793
52073
 
51794
52074
  // src/lib/agent-integration.ts
51795
- import { createHash as createHash11, randomUUID as randomUUID5 } from "crypto";
52075
+ import { createHash as createHash12, randomUUID as randomUUID5 } from "crypto";
52076
+ import { isDeepStrictEqual as isDeepStrictEqual4 } from "util";
51796
52077
  import { existsSync as existsSync12, lstatSync as lstatSync15, statSync as statSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync13, readdirSync as readdirSync8, opendirSync as opendirSync3, readlinkSync as readlinkSync4, realpathSync as realpathSync6, renameSync as renameSync2, rmdirSync as rmdirSync2, writeFileSync as writeFileSync4, unlinkSync as unlinkSync3, chmodSync, openSync as openSync8, closeSync as closeSync8, fsyncSync as fsyncSync2, fstatSync as fstatSync8, readSync as readSync6, constants as constants8, linkSync } from "fs";
51797
- import { dirname as dirname11, join as join21, resolve as resolve11, relative as relative4, isAbsolute as isAbsolute11, sep as sep5 } from "path";
52078
+ import { dirname as dirname11, join as join21, resolve as resolve11, relative as relative5, isAbsolute as isAbsolute11, sep as sep5 } from "path";
51798
52079
  import { homedir as homedir3 } from "os";
51799
52080
  function assertSafePath(path) {
51800
52081
  let cursor = resolve11(path);
@@ -51818,7 +52099,7 @@ function readRootAlias(home, agent) {
51818
52099
  const targetStat = lstatSync15(targetPath, { throwIfNoEntry: false });
51819
52100
  if (!targetStat?.isDirectory())
51820
52101
  throw new Error(`Agent root alias must target an existing directory: ${alias}`);
51821
- const target = realpathSync6(targetPath), inside = relative4(realHome, target);
52102
+ const target = realpathSync6(targetPath), inside = relative5(realHome, target);
51822
52103
  if (!inside || inside === ".." || inside.startsWith(`..${sep5}`) || isAbsolute11(inside))
51823
52104
  throw new Error(`Agent root alias target must be inside the real home: ${alias}`);
51824
52105
  return { agent, home: realHome, alias, target, link: link2, aliasIdentity: `${stat.dev}:${stat.ino}:${stat.ctimeNs}`, targetIdentity: `${targetStat.dev}:${targetStat.ino}` };
@@ -51836,7 +52117,7 @@ function rootAliases(home, allowed = false) {
51836
52117
  }
51837
52118
  function canonicalAgentPath(path, aliases) {
51838
52119
  const absolute = resolve11(path), binding = aliases.find((item) => absolute === item.alias || absolute.startsWith(item.alias + sep5));
51839
- return binding ? join21(binding.target, relative4(binding.alias, absolute)) : absolute;
52120
+ return binding ? join21(binding.target, relative5(binding.alias, absolute)) : absolute;
51840
52121
  }
51841
52122
  function disabledCodexSkillPaths(config, aliases) {
51842
52123
  const skills = config.skills;
@@ -51901,13 +52182,13 @@ function readNativeBytes(path, maximum = 64 * 1024 * 1024) {
51901
52182
  }
51902
52183
  }
51903
52184
  function treeHash(root) {
51904
- const hash2 = createHash11("sha256");
52185
+ const hash2 = createHash12("sha256");
51905
52186
  let bytes = 0, files = 0;
51906
52187
  function visit2(path) {
51907
52188
  const stat = lstatSync15(path);
51908
52189
  if (stat.isSymbolicLink())
51909
52190
  throw new Error(`Refusing symlink in skill: ${path}`);
51910
- const rel = relative4(root, path);
52191
+ const rel = relative5(root, path);
51911
52192
  if (stat.isDirectory()) {
51912
52193
  hash2.update(`d\x00${rel}\x00`);
51913
52194
  for (const name of readdirSync8(path).sort())
@@ -51928,7 +52209,7 @@ function treeHash(root) {
51928
52209
  return hash2.digest("hex");
51929
52210
  }
51930
52211
  function parseNativeMigrationTargetManifest(input) {
51931
- const digest = sha2(input);
52212
+ const digest = sha3(input);
51932
52213
  let value;
51933
52214
  try {
51934
52215
  value = JSON.parse(input.toString());
@@ -51958,7 +52239,7 @@ function parseNativeMigrationTargetManifest(input) {
51958
52239
  assertSafePath(projectRoot);
51959
52240
  if (isAbsolute11(item.path) || item.path.includes("\\") || item.path.length === 0 || item.path.includes("\x00"))
51960
52241
  throw new Error(`Native migration target path must be normalized and project-relative: ${item.path}`);
51961
- const resolved = resolve11(projectRoot, item.path), normalized = relative4(projectRoot, resolved);
52242
+ const resolved = resolve11(projectRoot, item.path), normalized = relative5(projectRoot, resolved);
51962
52243
  if (!normalized || normalized === ".." || normalized.startsWith(`..${sep5}`) || isAbsolute11(normalized) || normalized !== item.path)
51963
52244
  throw new Error(`Native migration target path escapes or is not normalized: ${item.path}`);
51964
52245
  if (!/^[0-9a-f]{64}$/.test(item.treeSha256))
@@ -51980,7 +52261,7 @@ function selectNativeMigrationTargets(inventory, manifest) {
51980
52261
  const identities = new Set;
51981
52262
  const selected = [];
51982
52263
  for (const target of manifest.targets) {
51983
- const projectRoot = resolve11(target.projectRoot), normalized = relative4(projectRoot, resolve11(projectRoot, target.path));
52264
+ const projectRoot = resolve11(target.projectRoot), normalized = relative5(projectRoot, resolve11(projectRoot, target.path));
51984
52265
  if (!isAbsolute11(target.projectRoot) || projectRoot !== target.projectRoot || !existsSync12(projectRoot) || !lstatSync15(projectRoot).isDirectory())
51985
52266
  throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
51986
52267
  assertSafePath(projectRoot);
@@ -52333,9 +52614,9 @@ function planAgentIntegration(options) {
52333
52614
  const observedNativeSources = [];
52334
52615
  const codexPluginSkills = options.codexNativeCatalog ? reviewCodexPluginSkillControls(options.codexNativeCatalog, nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor).map((entry) => join21(entry.path, "SKILL.md")), canonicalAgentPath(join21(home, ".codex/plugins/cache"), aliases), resolve11(options.projectDir ?? home), (path) => {
52335
52616
  const bytes = readNativeBytes(path, 1024 * 1024);
52336
- observedNativeSources.push({ path, sha256: sha2(bytes) });
52617
+ observedNativeSources.push({ path, sha256: sha3(bytes) });
52337
52618
  return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
52338
- }) : policy.bridge?.codexPluginSkills ?? [];
52619
+ }, codexConfig.skills?.config ?? []) : policy.bridge?.codexPluginSkills ?? [];
52339
52620
  const changes = [];
52340
52621
  for (const agent of [...new Set(options.agents)]) {
52341
52622
  if (!INTEGRATION_AGENTS.includes(agent))
@@ -52361,7 +52642,7 @@ function planAgentIntegration(options) {
52361
52642
  throw new Error("Refusing to overwrite an unrecognized Hermes supervisor");
52362
52643
  if (supervisorBefore !== supervisorAfter)
52363
52644
  changes.push({ path: supervisorPath, before: supervisorBefore, after: supervisorAfter });
52364
- const supervisor = { path: supervisorPath, runtime: process.execPath, sha256: sha2(supervisorAfter) };
52645
+ const supervisor = { path: supervisorPath, runtime: process.execPath, sha256: sha3(supervisorAfter) };
52365
52646
  const after3 = configureHermesHooks(before2, supervisor, previous);
52366
52647
  if (before2 !== after3)
52367
52648
  changes.push({ path, before: before2, after: after3 });
@@ -52408,12 +52689,12 @@ function planAgentIntegration(options) {
52408
52689
  agents: [...new Set([...priorAgents, ...options.agents])].sort(),
52409
52690
  home: resolve11(home),
52410
52691
  includeVendor: true,
52411
- ...options.agents.includes("hermes") ? { supervisors: { ...policy.bridge?.supervisors, hermes: { path: join21(dataDir3, "agent-hooks", "hermes.js"), runtime: process.execPath, sha256: sha2(renderHermesSupervisor(bindings.get("hermes").command, bindings.get("hermes").profileId)) } } } : {},
52692
+ ...options.agents.includes("hermes") ? { supervisors: { ...policy.bridge?.supervisors, hermes: { path: join21(dataDir3, "agent-hooks", "hermes.js"), runtime: process.execPath, sha256: sha3(renderHermesSupervisor(bindings.get("hermes").command, bindings.get("hermes").profileId)) } } } : {},
52412
52693
  commands: { ...policy.bridge?.commands, ...Object.fromEntries([...bindings].map(([agent, binding]) => [agent, binding.command])) },
52413
52694
  profiles: Object.fromEntries([...new Set([...priorAgents, ...options.agents])].sort().map((agent) => [agent, bindings.get(agent)?.profileId ?? policy.bridge?.profiles?.[agent] ?? policy.profileId])),
52414
52695
  disabledBuiltins: options.agents.includes("codex") ? nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor && entry.path.startsWith(canonicalAgentPath(join21(home, ".codex", "skills", ".system"), aliases) + sep5)).map((entry) => ({ path: entry.path, hash: entry.hash })) : policy.bridge?.disabledBuiltins ?? [],
52415
52696
  rootAliases: aliases,
52416
- ...codexPluginSkills.length ? { codexPluginSkills, codexPluginSkillReview: options.codexNativeCatalog ? { version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, catalogSha256: sha2(JSON.stringify({ version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, skills: projectCodexNativeSkillCatalog({ data: [{ cwd: options.codexNativeCatalog.cwd, errors: [], skills: options.codexNativeCatalog.skills }] }, options.codexNativeCatalog.cwd) })), configSha256: changes.find((change) => change.path === canonicalAgentPath(join21(home, ".codex/config.toml"), aliases))?.before === null ? null : sha2(readOptional(canonicalAgentPath(join21(home, ".codex/config.toml"), aliases)) ?? "") } : policy.bridge?.codexPluginSkillReview } : {},
52697
+ ...codexPluginSkills.length ? { codexPluginSkills, codexPluginSkillReview: options.codexNativeCatalog ? { version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, catalogSha256: sha3(JSON.stringify({ version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, skills: projectCodexNativeSkillCatalog({ data: [{ cwd: options.codexNativeCatalog.cwd, errors: [], skills: options.codexNativeCatalog.skills }] }, options.codexNativeCatalog.cwd), ...options.codexNativeCatalog.plugins === undefined ? {} : { plugins: projectCodexInstalledPluginEntries(options.codexNativeCatalog.plugins) } })), configSha256: changes.find((change) => change.path === canonicalAgentPath(join21(home, ".codex/config.toml"), aliases))?.before === null ? null : sha3(readOptional(canonicalAgentPath(join21(home, ".codex/config.toml"), aliases)) ?? "") } : policy.bridge?.codexPluginSkillReview } : {},
52417
52698
  discovery: { ...policy.bridge?.discovery, ...Object.fromEntries(discoveryAfter.map((binding) => [binding.agent, binding])) }
52418
52699
  } };
52419
52700
  const serializedPolicy = serializeManagedSkillPolicy(nextPolicy);
@@ -52451,7 +52732,7 @@ function atomicWrite2(path, content) {
52451
52732
  function planAgentSettingsWitnessUpgrade(options) {
52452
52733
  const home = resolve11(options.home ?? homedir3()), dataDir3 = options.dataDir ?? getDataDirReadOnly();
52453
52734
  const snapshot = readManagedSkillPolicySnapshot(dataDir3);
52454
- if (!snapshot || sha2(snapshot.text) !== options.expectedPolicySha256)
52735
+ if (!snapshot || sha3(snapshot.text) !== options.expectedPolicySha256)
52455
52736
  throw new Error("Managed policy preimage changed");
52456
52737
  const policy = snapshot.value, aliases = policy.bridge?.rootAliases ?? [];
52457
52738
  recheckRootAliases(aliases);
@@ -52460,7 +52741,7 @@ function planAgentSettingsWitnessUpgrade(options) {
52460
52741
  throw new Error("Settings witness upgrade requires an existing reviewed native binding");
52461
52742
  const configPath = canonicalAgentPath(join21(home, options.agent === "claude" ? ".claude/settings.json" : ".codex/config.toml"), aliases);
52462
52743
  const settings = readOptional(configPath);
52463
- if (settings === null || sha2(settings) !== options.expectedSettingsSha256)
52744
+ if (settings === null || sha3(settings) !== options.expectedSettingsSha256)
52464
52745
  throw new Error("Native settings preimage changed");
52465
52746
  const sources = binding.sources.filter((source) => source.path === configPath && source.format === undefined && source.fields === undefined);
52466
52747
  if (sources.length !== 1)
@@ -52468,15 +52749,40 @@ function planAgentSettingsWitnessUpgrade(options) {
52468
52749
  const previous = sources[0];
52469
52750
  if (typeof previous.sha256 !== "string")
52470
52751
  throw new Error("Settings witness upgrade requires a preserved settings preimage");
52752
+ const replaced = [previous];
52753
+ if (options.agent === "codex") {
52754
+ if (previous.hashMode !== undefined && previous.hashMode !== "bytes" && previous.hashMode !== "codex-settings-v1")
52755
+ throw new Error("Codex settings witness upgrade requires a preserved raw or codex-settings-v1 configuration witness");
52756
+ const preimage = readCodexSettingsPreimage(options.reviewedPreimage);
52757
+ for (const source of binding.sources) {
52758
+ if (source === previous || source.path !== configPath)
52759
+ continue;
52760
+ const fields = source.fields;
52761
+ if (source.hashMode !== undefined || source.format !== "toml" || !Array.isArray(fields) || !isDeepStrictEqual4(fields, [...CODEX_DISCOVERY_PROJECTION_FIELDS]) || typeof source.sha256 !== "string")
52762
+ throw new Error("Codex settings witness upgrade found an unrecognized configuration witness");
52763
+ if (projectNativeDiscoveryFields(preimage, "toml", fields, configPath) !== source.sha256)
52764
+ throw new Error("Reviewed preimage does not explain the Codex discovery projection witness");
52765
+ replaced.push(source);
52766
+ }
52767
+ }
52471
52768
  const next = options.agent === "claude" ? upgradeClaudeSettingsWitness(previous, options.reviewedPreimage) : upgradeCodexSettingsWitness(previous, options.reviewedPreimage);
52472
- const replacement = { ...binding, sources: binding.sources.map((source) => source === previous ? next : source) };
52769
+ const rebound = [];
52770
+ for (const source of binding.sources) {
52771
+ if (!replaced.includes(source)) {
52772
+ rebound.push(source);
52773
+ continue;
52774
+ }
52775
+ if (source === replaced[0])
52776
+ rebound.push(next);
52777
+ }
52778
+ const replacement = { ...binding, sources: rebound };
52473
52779
  verifyAgentDiscovery(replacement);
52474
52780
  const after2 = serializeManagedSkillPolicy({ ...policy, bridge: { ...policy.bridge, discovery: { ...policy.bridge.discovery, [options.agent]: replacement } } });
52475
- return { dataDir: dataDir3, profileId: policy.profileId, changes: [{ path: join21(dataDir3, "agent-policy.json"), before: snapshot.text, after: after2 }], nativeSkills: [], observedPolicy: { path: join21(dataDir3, "agent-policy.json"), before: snapshot.text }, observedSettings: { path: configPath, before: settings }, discoveryBefore: [replacement], discoveryAfter: [replacement], rootAliases: aliases, managedAgentChecks: { home, agents: [options.agent] }, settingsWitnessUpgrade: { agent: options.agent, path: configPath, fromHashMode: previous.hashMode ?? "bytes", fromSha256: previous.sha256, toHashMode: next.hashMode, toSha256: next.sha256, reviewedPreimage: options.reviewedPreimage, currentSettingsSha256: options.expectedSettingsSha256 } };
52781
+ return { dataDir: dataDir3, profileId: policy.profileId, changes: [{ path: join21(dataDir3, "agent-policy.json"), before: snapshot.text, after: after2 }], nativeSkills: [], observedPolicy: { path: join21(dataDir3, "agent-policy.json"), before: snapshot.text }, observedSettings: { path: configPath, before: settings }, discoveryBefore: [replacement], discoveryAfter: [replacement], rootAliases: aliases, managedAgentChecks: { home, agents: [options.agent] }, settingsWitnessUpgrade: { agent: options.agent, path: configPath, fromHashMode: previous.hashMode ?? "bytes", fromSha256: previous.sha256, toHashMode: next.hashMode, toSha256: next.sha256, reviewedPreimage: options.reviewedPreimage, currentSettingsSha256: options.expectedSettingsSha256, replacedWitnesses: replaced.map((source) => ({ hashMode: source.hashMode ?? "bytes", sha256: source.sha256 })) } };
52476
52782
  }
52477
52783
  function applyAgentIntegration(plan) {
52478
52784
  for (const source of plan.observedNativeSources ?? [])
52479
- if (sha2(readNativeBytes(source.path, 1024 * 1024)) !== source.sha256)
52785
+ if (sha3(readNativeBytes(source.path, 1024 * 1024)) !== source.sha256)
52480
52786
  throw new Error("Native identity source changed after planning");
52481
52787
  if (plan.observedSettings && readOptional(plan.observedSettings.path) !== plan.observedSettings.before)
52482
52788
  throw new Error("Native settings changed after witness planning");
@@ -52496,7 +52802,7 @@ function applyAgentIntegration(plan) {
52496
52802
  const upgrade = plan.settingsWitnessUpgrade;
52497
52803
  if (!plan.managedAgentChecks || !plan.observedPolicy?.before)
52498
52804
  throw new Error("Invalid settings witness upgrade plan");
52499
- const verified = planAgentSettingsWitnessUpgrade({ agent: upgrade.agent, reviewedPreimage: upgrade.reviewedPreimage, home: plan.managedAgentChecks.home, dataDir: plan.dataDir, expectedPolicySha256: sha2(plan.observedPolicy.before), expectedSettingsSha256: upgrade.currentSettingsSha256 });
52805
+ const verified = planAgentSettingsWitnessUpgrade({ agent: upgrade.agent, reviewedPreimage: upgrade.reviewedPreimage, home: plan.managedAgentChecks.home, dataDir: plan.dataDir, expectedPolicySha256: sha3(plan.observedPolicy.before), expectedSettingsSha256: upgrade.currentSettingsSha256 });
52500
52806
  if (JSON.stringify(verified.changes) !== JSON.stringify(plan.changes) || JSON.stringify(verified.settingsWitnessUpgrade) !== JSON.stringify(upgrade))
52501
52807
  throw new Error("Settings witness upgrade plan changed");
52502
52808
  provenDiscovery = verified.discoveryBefore[0];
@@ -52524,7 +52830,7 @@ function applyAgentIntegration(plan) {
52524
52830
  chmodSync(backupRoot, 448);
52525
52831
  for (const [index, change] of plan.changes.entries())
52526
52832
  if (change.before !== null) {
52527
- const backup = join21(backupRoot, `${index}-${sha2(change.path).slice(0, 12)}.backup`);
52833
+ const backup = join21(backupRoot, `${index}-${sha3(change.path).slice(0, 12)}.backup`);
52528
52834
  writeFileSync4(backup, change.before, { mode: 384, flag: "wx" });
52529
52835
  if (readFileSync13(backup, "utf8") !== change.before)
52530
52836
  throw new Error("Native configuration preservation readback failed");
@@ -52543,7 +52849,7 @@ function applyAgentIntegration(plan) {
52543
52849
  }
52544
52850
  recheckRootAliases(aliases);
52545
52851
  for (const source of plan.observedNativeSources ?? [])
52546
- if (sha2(readNativeBytes(source.path, 1024 * 1024)) !== source.sha256)
52852
+ if (sha3(readNativeBytes(source.path, 1024 * 1024)) !== source.sha256)
52547
52853
  throw new Error("Native identity source changed during application");
52548
52854
  if (plan.observedSettings && readOptional(plan.observedSettings.path) !== plan.observedSettings.before)
52549
52855
  throw new Error("Native settings changed during witness application");
@@ -52555,7 +52861,7 @@ function applyAgentIntegration(plan) {
52555
52861
  }
52556
52862
  for (const agent of plan.managedAgentChecks?.agents ?? [])
52557
52863
  assertManagedAgentBridge(agent, { home: plan.managedAgentChecks.home, dataDir: plan.dataDir, projectDir: plan.managedAgentChecks.home });
52558
- atomicWrite2(join21(backupRoot, "receipt.json"), JSON.stringify({ version: 1, changes: written.map((change) => ({ path: change.path, beforeHash: change.before === null ? null : sha2(change.before), afterHash: sha2(change.after) })), backups, ...aliases.length ? { rootAliases: aliases } : {} }) + `
52864
+ atomicWrite2(join21(backupRoot, "receipt.json"), JSON.stringify({ version: 1, changes: written.map((change) => ({ path: change.path, beforeHash: change.before === null ? null : sha3(change.before), afterHash: sha3(change.after) })), backups, ...aliases.length ? { rootAliases: aliases } : {} }) + `
52559
52865
  `);
52560
52866
  } catch (error) {
52561
52867
  for (const change of written.reverse()) {
@@ -52634,8 +52940,8 @@ function archiveNativeSkills(inventory, options) {
52634
52940
  const operationId = randomUUID5(), archiveRoot = join21(options.dataDir ?? getDataDir(), "migration", operationId, "native"), receiptPath = join21(archiveRoot, "receipt.json");
52635
52941
  const entries = selected.map((entry, index) => ({
52636
52942
  source: entry.vendor ? join21(entry.path, "SKILL.md") : entry.path,
52637
- archive: join21(archiveRoot, `${index}-${sha2(entry.path).slice(0, 12)}`),
52638
- hash: entry.vendor ? sha2(readNativeBytes(join21(entry.path, "SKILL.md"))) : entry.hash,
52943
+ archive: join21(archiveRoot, `${index}-${sha3(entry.path).slice(0, 12)}`),
52944
+ hash: entry.vendor ? sha3(readNativeBytes(join21(entry.path, "SKILL.md"))) : entry.hash,
52639
52945
  ...entry.vendor ? { discoveryOnly: true } : {},
52640
52946
  status: "planned"
52641
52947
  }));
@@ -52646,7 +52952,7 @@ function archiveNativeSkills(inventory, options) {
52646
52952
  const stat = lstatSync15(entry.archive);
52647
52953
  if (entry.discoveryOnly ? !stat.isFile() : !stat.isDirectory())
52648
52954
  throw new Error("Archive type changed");
52649
- if ((entry.discoveryOnly ? sha2(readNativeBytes(entry.archive)) : treeHash(entry.archive)) !== entry.hash)
52955
+ if ((entry.discoveryOnly ? sha3(readNativeBytes(entry.archive)) : treeHash(entry.archive)) !== entry.hash)
52650
52956
  throw new Error("Archive bytes changed");
52651
52957
  };
52652
52958
  assertSafePath(archiveRoot);
@@ -52766,7 +53072,7 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
52766
53072
  throw new Error("NATIVE_SKILL_DRIFT: the hook selection profile differs from its managed binding; restart the native client after reviewing skills hook install");
52767
53073
  if (agent === "hermes") {
52768
53074
  const supervisor = binding.supervisors?.hermes;
52769
- if (supervisor?.path !== join21(dataDir3, "agent-hooks", "hermes.js") || supervisor?.sha256 !== sha2(renderHermesSupervisor(command, profile)))
53075
+ if (supervisor?.path !== join21(dataDir3, "agent-hooks", "hermes.js") || supervisor?.sha256 !== sha3(renderHermesSupervisor(command, profile)))
52770
53076
  throw new Error("NATIVE_SKILL_DRIFT: Hermes supervisor binding changed; run skills hook install");
52771
53077
  assertHermesProtection(home, config, command, profile, supervisor);
52772
53078
  } else if (agent === "opencode") {
@@ -52882,7 +53188,7 @@ function assertNativeExportAllowed(dataDir3 = getDataDirReadOnly()) {
52882
53188
  if (requiresCliSkillLoading(dataDir3))
52883
53189
  throw new Error("NATIVE_SKILL_EXPORT_DISABLED: this station loads skills through the Skills CLI; use skills sync --selection-profile <id>");
52884
53190
  }
52885
- var sha2 = (data) => createHash11("sha256").update(data).digest("hex"), HOOK_EVENTS, ROOTS, SKILLS_LOADING_POLICY = "Skills loading policy: discover skills with `skills list` or `skills search`, and read selected instructions with `skills load <slug>`. Use `skills sync` to refresh the shared profile. The only native skill is the owned skills-cli bridge. Create and edit payload skills in the Skills authoring workspace; do not copy payload instructions into native discovery folders. Context loading does not authorize execution; use `skills run` only when the task calls for running a skill.";
53191
+ var sha3 = (data) => createHash12("sha256").update(data).digest("hex"), HOOK_EVENTS, ROOTS, SKILLS_LOADING_POLICY = "Skills loading policy: discover skills with `skills list` or `skills search`, and read selected instructions with `skills load <slug>`. Use `skills sync` to refresh the shared profile. The only native skill is the owned skills-cli bridge. Create and edit payload skills in the Skills authoring workspace; do not copy payload instructions into native discovery folders. Context loading does not authorize execution; use `skills run` only when the task calls for running a skill.";
52886
53192
  var init_agent_integration = __esm(() => {
52887
53193
  init_codex_plugin_skill_controls();
52888
53194
  init_codex_native_skill_catalog();
@@ -53051,7 +53357,7 @@ import {
53051
53357
  writeFileSync as writeFileSync6
53052
53358
  } from "fs";
53053
53359
  import { homedir as homedir4 } from "os";
53054
- import { basename as basename5, dirname as dirname12, join as join25 } from "path";
53360
+ import { basename as basename6, dirname as dirname12, join as join25 } from "path";
53055
53361
  function isSkillsOwnershipMarker(marker) {
53056
53362
  return typeof marker === "object" && marker !== null && Object.hasOwn(marker, "managedBy") && marker.managedBy === SYNC_MARKER_MANAGED_BY;
53057
53363
  }
@@ -53285,7 +53591,7 @@ function writeManagedSkillDir(dir, skillMd, options) {
53285
53591
  return { action, path: skillMdPath };
53286
53592
  const parentDir = dirname12(dir);
53287
53593
  mkdirSync7(parentDir, { recursive: true });
53288
- const transactionDir = mkdtempSync(join25(parentDir, `.hasna-skills-write-${basename5(dir)}-`));
53594
+ const transactionDir = mkdtempSync(join25(parentDir, `.hasna-skills-write-${basename6(dir)}-`));
53289
53595
  const candidateDir = join25(transactionDir, "candidate");
53290
53596
  const backupDir = join25(transactionDir, "backup");
53291
53597
  const candidateSkillMdPath = join25(candidateDir, "SKILL.md");
@@ -54464,7 +54770,7 @@ var init_selection_resolver = __esm(() => {
54464
54770
  });
54465
54771
 
54466
54772
  // src/lib/plugin-projection.ts
54467
- import { createHash as createHash12 } from "crypto";
54773
+ import { createHash as createHash13 } from "crypto";
54468
54774
  import { posix } from "path";
54469
54775
  function pluginRefusal(message) {
54470
54776
  throw new SkillSelectionError("PLUGIN_ADMISSION_REFUSED", message);
@@ -54657,7 +54963,7 @@ function buildPluginProjection(entries) {
54657
54963
  files.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
54658
54964
  return { manifest, payloads: manifest.payloads, files, witnesses: pluginFileWitnesses(files), originalTreeDigest, projectionTreeDigest: pluginTreeDigest(files), removed: removed.length ? pluginFileWitnesses(removed) : [] };
54659
54965
  }
54660
- var PLUGIN_PROJECTION_MANIFEST = "plugin-projection.json", PLUGIN_PROJECTION_LIMITS, pluginHash = (bytes) => createHash12("sha256").update(bytes).digest("hex"), MANIFEST_FIELDS;
54966
+ var PLUGIN_PROJECTION_MANIFEST = "plugin-projection.json", PLUGIN_PROJECTION_LIMITS, pluginHash = (bytes) => createHash13("sha256").update(bytes).digest("hex"), MANIFEST_FIELDS;
54661
54967
  var init_plugin_projection = __esm(() => {
54662
54968
  init_selection_cache();
54663
54969
  PLUGIN_PROJECTION_LIMITS = Object.freeze({ files: 1024, bytes: 64 * 1024 * 1024, fileBytes: 16 * 1024 * 1024, metadataBytes: 512 * 1024, registrations: 64, history: 128 });
@@ -54665,7 +54971,7 @@ var init_plugin_projection = __esm(() => {
54665
54971
  });
54666
54972
 
54667
54973
  // src/lib/plugin-projection-store.ts
54668
- import { createHash as createHash13, randomUUID as randomUUID6 } from "crypto";
54974
+ import { createHash as createHash14, randomUUID as randomUUID6 } from "crypto";
54669
54975
  import { constants as constants9, closeSync as closeSync9, fchmodSync, fstatSync as fstatSync9, fsyncSync as fsyncSync3, linkSync as linkSync2, lstatSync as lstatSync17, mkdirSync as mkdirSync9, openSync as openSync9, opendirSync as opendirSync4, readSync as readSync7, renameSync as renameSync5, rmdirSync as rmdirSync3, rmSync as rmSync4, unlinkSync as unlinkSync4, writeSync as writeSync2 } from "fs";
54670
54976
  import { dirname as dirname13, isAbsolute as isAbsolute12, join as join29, parse as parse5, resolve as resolve12 } from "path";
54671
54977
  function stat(path) {
@@ -54677,7 +54983,7 @@ function stat(path) {
54677
54983
  return pluginRefusal("Cannot inspect plugin filesystem entry");
54678
54984
  }
54679
54985
  }
54680
- function canonical4(path) {
54986
+ function canonical5(path) {
54681
54987
  pluginNeed(typeof path === "string" && path.length <= 8192 && isAbsolute12(path) && resolve12(path) === path && !/[\x00-\x1f\x7f]/.test(path), "Plugin storage paths must be canonical absolute paths");
54682
54988
  }
54683
54989
  function owner(stats, system = false) {
@@ -54688,7 +54994,7 @@ function same3(left, right, identityOnly = false) {
54688
54994
  pluginNeed(right && left.dev === right.dev && left.ino === right.ino && left.mode === right.mode && left.uid === right.uid && left.gid === right.gid && (identityOnly || left.size === right.size && left.nlink === right.nlink && left.mtimeNs === right.mtimeNs && left.ctimeNs === right.ctimeNs), "Plugin filesystem entry changed during access");
54689
54995
  }
54690
54996
  function ancestors(path, create3 = false) {
54691
- canonical4(path);
54997
+ canonical5(path);
54692
54998
  const result2 = [], parent = dirname13(path), filesystemRoot = parse5(parent).root;
54693
54999
  let current = filesystemRoot;
54694
55000
  for (const segment of ["", ...parent.slice(filesystemRoot.length).split("/").filter(Boolean)]) {
@@ -54798,7 +55104,7 @@ function directoryNames(path) {
54798
55104
  function snapshotPluginTree(root, options = {}) {
54799
55105
  const chain = ancestors(root), entries = [], files = [], directories = [];
54800
55106
  let bytes = 0, visited = 0;
54801
- const visit2 = (directory, relative5) => {
55107
+ const visit2 = (directory, relative6) => {
54802
55108
  const before2 = stat(directory);
54803
55109
  pluginNeed(before2 && before2.isDirectory() && !before2.isSymbolicLink(), "Plugin tree must contain real directories");
54804
55110
  const names = directoryNames(directory);
@@ -54806,18 +55112,18 @@ function snapshotPluginTree(root, options = {}) {
54806
55112
  directories.push({ path: directory, stat: before2, names });
54807
55113
  for (const name of names) {
54808
55114
  pluginNeed(++visited <= PLUGIN_PROJECTION_LIMITS.files * 50, "Plugin tree membership exceeds its limit");
54809
- const path = relative5 ? `${relative5}/${name}` : name;
55115
+ const path = relative6 ? `${relative6}/${name}` : name;
54810
55116
  pluginNeed(new TextEncoder().encode(path).byteLength <= 100 && !/[\\:\x00-\x1f\x7f]/u.test(path), "Plugin entry path exceeds its limit or is unsafe");
54811
55117
  const absolute = join29(directory, name), entryStat = stat(absolute);
54812
55118
  pluginNeed(entryStat, "Plugin tree member disappeared");
54813
- if (relative5 === "" && name === ".orphaned_at" && (options.nativeRuntime === "claude-2.1.274" || options.nativeRuntime === "claude-2.1.276")) {
55119
+ if (relative6 === "" && name === ".orphaned_at" && (options.nativeRuntime === "claude-2.1.274" || options.nativeRuntime === "claude-2.1.276")) {
54814
55120
  const bytes2 = readBytes(absolute, 32, "native-pin");
54815
55121
  pluginNeed(/^[1-9][0-9]{12}$/.test(new TextDecoder().decode(bytes2)), "Malformed native orphan timestamp");
54816
55122
  same3(entryStat, stat(absolute));
54817
55123
  files.push({ path: absolute, stat: entryStat });
54818
55124
  continue;
54819
55125
  }
54820
- if (relative5 === "" && name === ".in_use" && (options.nativeRuntime === "claude-2.1.274" || options.nativeRuntime === "claude-2.1.276")) {
55126
+ if (relative6 === "" && name === ".in_use" && (options.nativeRuntime === "claude-2.1.274" || options.nativeRuntime === "claude-2.1.276")) {
54821
55127
  pluginNeed(entryStat.isDirectory() && !entryStat.isSymbolicLink(), "Native plugin pins require a real directory");
54822
55128
  owner(entryStat);
54823
55129
  const pins = directoryNames(absolute);
@@ -55003,7 +55309,7 @@ function pluginExecutableDigest(path) {
55003
55309
  const opened = fstatSync9(fd, { bigint: true });
55004
55310
  same3(before2, opened);
55005
55311
  fileShape(opened, maximum, "executable");
55006
- const hash2 = createHash13("sha256"), buffer = new Uint8Array(64 * 1024);
55312
+ const hash2 = createHash14("sha256"), buffer = new Uint8Array(64 * 1024);
55007
55313
  let remaining = Number(opened.size);
55008
55314
  while (remaining > 0) {
55009
55315
  const count = readSync7(fd, buffer, 0, Math.min(buffer.byteLength, remaining), null);
@@ -55439,7 +55745,7 @@ var init_plugin_admission = __esm(() => {
55439
55745
 
55440
55746
  // src/lib/plugin-discovery.ts
55441
55747
  import { closeSync as closeSync10, constants as constants10, fstatSync as fstatSync10, lstatSync as lstatSync18, openSync as openSync10, opendirSync as opendirSync5, readSync as readSync8 } from "fs";
55442
- import { basename as basename6, dirname as dirname14, isAbsolute as isAbsolute14, join as join31, resolve as resolve14 } from "path";
55748
+ import { basename as basename7, dirname as dirname14, isAbsolute as isAbsolute14, join as join31, resolve as resolve14 } from "path";
55443
55749
  function validateManagedPluginWitnesses(value) {
55444
55750
  pluginNeed(Array.isArray(value) && value.length > 0 && value.length <= PLUGIN_PROJECTION_LIMITS.registrations, "Invalid managed plugin witness collection");
55445
55751
  const seen = new Set;
@@ -55522,7 +55828,7 @@ function hashManagedPluginRegistry(path, managed) {
55522
55828
  pluginNeed(/^(?:[A-Za-z0-9][A-Za-z0-9._+-]*-)?[a-f0-9]{12}$/.test(row.version) && row.installPath === join31(cacheRoot, row.version), "Managed plugin cache path or version is outside its registration");
55523
55829
  const approval = (producer) => {
55524
55830
  pluginText(producer);
55525
- const digest = `sha256:${basename6(producer)}`;
55831
+ const digest = `sha256:${basename7(producer)}`;
55526
55832
  const receipt2 = readPluginAdmissionReceipt(witness.storeRoot, witness.bindingId, digest);
55527
55833
  pluginNeed(receipt2.materializedPath === producer, "Managed producer path is not an approved immutable projection");
55528
55834
  if (!verified.has(producer)) {
@@ -55586,21 +55892,21 @@ var init_plugin_discovery = __esm(() => {
55586
55892
  });
55587
55893
 
55588
55894
  // src/lib/claude-marketplace-registry.ts
55589
- import { createHash as createHash14 } from "crypto";
55895
+ import { createHash as createHash15 } from "crypto";
55590
55896
  import { closeSync as closeSync11, constants as constants11, fstatSync as fstatSync11, lstatSync as lstatSync19, openSync as openSync11, readSync as readSync9 } from "fs";
55591
- import { basename as basename7, dirname as dirname15, isAbsolute as isAbsolute15, resolve as resolve15 } from "path";
55592
- function need4(value, reason) {
55897
+ import { basename as basename8, dirname as dirname15, isAbsolute as isAbsolute15, resolve as resolve15 } from "path";
55898
+ function need5(value, reason) {
55593
55899
  if (!value)
55594
55900
  throw new Error(`Claude marketplace registry ${reason}`);
55595
55901
  }
55596
55902
  function absolutePath3(value) {
55597
- need4(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute15(value) && resolve15(value) === value, "requires a normalized absolute path");
55903
+ need5(typeof value === "string" && value.length > 0 && value.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.pathCharacters && !/[\x00-\x1f\x7f]/.test(value) && isAbsolute15(value) && resolve15(value) === value, "requires a normalized absolute path");
55598
55904
  }
55599
55905
  function parents2(path) {
55600
55906
  const result2 = [];
55601
55907
  for (let at2 = dirname15(path);; at2 = dirname15(at2)) {
55602
55908
  const stat2 = lstatSync19(at2, { bigint: true });
55603
- need4(stat2.isDirectory() && !stat2.isSymbolicLink(), "path traverses a symlink or non-directory");
55909
+ need5(stat2.isDirectory() && !stat2.isSymbolicLink(), "path traverses a symlink or non-directory");
55604
55910
  result2.push([at2, stat2]);
55605
55911
  if (at2 === dirname15(at2))
55606
55912
  return result2;
@@ -55608,15 +55914,15 @@ function parents2(path) {
55608
55914
  }
55609
55915
  function readRegistry2(path, budget) {
55610
55916
  absolutePath3(path);
55611
- need4(basename7(path) === "known_marketplaces.json", "requires known_marketplaces.json");
55612
- need4(Number.isSafeInteger(budget.remaining) && budget.remaining >= 0, "has an invalid byte budget");
55917
+ need5(basename8(path) === "known_marketplaces.json", "requires known_marketplaces.json");
55918
+ need5(Number.isSafeInteger(budget.remaining) && budget.remaining >= 0, "has an invalid byte budget");
55613
55919
  const ancestors2 = parents2(path), initial2 = lstatSync19(path, { bigint: true });
55614
- need4(initial2.isFile() && !initial2.isSymbolicLink() && initial2.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
55615
- need4(initial2.size <= BigInt(budget.remaining), "exceeds its aggregate byte limit");
55920
+ need5(initial2.isFile() && !initial2.isSymbolicLink() && initial2.size <= BigInt(CLAUDE_MARKETPLACE_REGISTRY_LIMITS.bytes), "is not a bounded regular file");
55921
+ need5(initial2.size <= BigInt(budget.remaining), "exceeds its aggregate byte limit");
55616
55922
  const fd = openSync11(path, constants11.O_RDONLY | constants11.O_NOFOLLOW | constants11.O_NONBLOCK);
55617
55923
  try {
55618
55924
  const opened = fstatSync11(fd, { bigint: true });
55619
- need4(opened.isFile() && sameFile2(initial2, opened), "changed during open");
55925
+ need5(opened.isFile() && sameFile2(initial2, opened), "changed during open");
55620
55926
  const bytes = Buffer.alloc(Number(opened.size) + 1);
55621
55927
  let length = 0;
55622
55928
  while (length < bytes.length) {
@@ -55626,10 +55932,10 @@ function readRegistry2(path, budget) {
55626
55932
  length += count;
55627
55933
  }
55628
55934
  const after2 = fstatSync11(fd, { bigint: true }), current = lstatSync19(path, { bigint: true });
55629
- need4(current.isFile() && sameFile2(opened, after2) && sameFile2(after2, current) && BigInt(length) === opened.size, "changed during read");
55935
+ need5(current.isFile() && sameFile2(opened, after2) && sameFile2(after2, current) && BigInt(length) === opened.size, "changed during read");
55630
55936
  for (const [ancestor, before2] of ancestors2) {
55631
55937
  const now3 = lstatSync19(ancestor, { bigint: true });
55632
- need4(now3.isDirectory() && before2.dev === now3.dev && before2.ino === now3.ino && before2.mode === now3.mode, "parent changed during read");
55938
+ need5(now3.isDirectory() && before2.dev === now3.dev && before2.ino === now3.ino && before2.mode === now3.mode, "parent changed during read");
55633
55939
  }
55634
55940
  budget.remaining -= length;
55635
55941
  try {
@@ -55649,7 +55955,7 @@ function parse6(text2) {
55649
55955
  at2++;
55650
55956
  };
55651
55957
  function string() {
55652
- need4(text2[at2] === '"', "contains invalid JSON");
55958
+ need5(text2[at2] === '"', "contains invalid JSON");
55653
55959
  const start = at2++;
55654
55960
  while (at2 < text2.length) {
55655
55961
  const character = text2[at2++];
@@ -55660,7 +55966,7 @@ function parse6(text2) {
55660
55966
  } catch {
55661
55967
  throw new Error("Claude marketplace registry contains invalid JSON string");
55662
55968
  }
55663
- need4(value2.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.stringCharacters, "exceeds its string limit");
55969
+ need5(value2.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.stringCharacters, "exceeds its string limit");
55664
55970
  return value2;
55665
55971
  }
55666
55972
  if (character === "\\")
@@ -55669,7 +55975,7 @@ function parse6(text2) {
55669
55975
  throw new Error("Claude marketplace registry contains an unterminated JSON string");
55670
55976
  }
55671
55977
  function value(depth) {
55672
- need4(depth <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.depth && ++nodes <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.nodes, "exceeds its nesting or node limit");
55978
+ need5(depth <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.depth && ++nodes <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.nodes, "exceeds its nesting or node limit");
55673
55979
  space();
55674
55980
  const character = text2[at2];
55675
55981
  if (character === '"')
@@ -55683,17 +55989,17 @@ function parse6(text2) {
55683
55989
  if (object5) {
55684
55990
  space();
55685
55991
  const key = string();
55686
- need4(!keys2.has(key), "contains a duplicate JSON key");
55992
+ need5(!keys2.has(key), "contains a duplicate JSON key");
55687
55993
  keys2.add(key);
55688
55994
  space();
55689
- need4(text2[at2++] === ":", "contains invalid JSON");
55995
+ need5(text2[at2++] === ":", "contains invalid JSON");
55690
55996
  entries.push([key, value(depth + 1)]);
55691
55997
  } else
55692
55998
  items.push(value(depth + 1));
55693
55999
  space();
55694
56000
  if (text2[at2] === end)
55695
56001
  break;
55696
- need4(text2[at2++] === ",", "contains invalid JSON");
56002
+ need5(text2[at2++] === ",", "contains invalid JSON");
55697
56003
  }
55698
56004
  at2++;
55699
56005
  return object5 ? { kind: "object", entries } : { kind: "array", items };
@@ -55705,21 +56011,21 @@ function parse6(text2) {
55705
56011
  }
55706
56012
  numberPattern.lastIndex = at2;
55707
56013
  const number = numberPattern.exec(text2);
55708
- need4(number, "contains invalid JSON");
56014
+ need5(number, "contains invalid JSON");
55709
56015
  at2 += number[0].length;
55710
56016
  return { kind: "number", value: number[0] };
55711
56017
  }
55712
56018
  const root2 = value(0);
55713
56019
  space();
55714
- need4(at2 === text2.length && root2.kind === "object", "requires a JSON object without trailing content");
55715
- need4(root2.entries.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.rows, "exceeds its marketplace row limit");
56020
+ need5(at2 === text2.length && root2.kind === "object", "requires a JSON object without trailing content");
56021
+ need5(root2.entries.length <= CLAUDE_MARKETPLACE_REGISTRY_LIMITS.rows, "exceeds its marketplace row limit");
55716
56022
  return root2;
55717
56023
  }
55718
56024
  function exactKeys(value, keys2) {
55719
56025
  return value?.kind === "object" && value.entries.length === keys2.length && value.entries.every(([key]) => keys2.includes(key));
55720
56026
  }
55721
56027
  function textField(value) {
55722
- need4(value?.kind === "string" && value.value.length > 0 && !/[\x00-\x1f\x7f]/.test(value.value), "contains an invalid recognized field");
56028
+ need5(value?.kind === "string" && value.value.length > 0 && !/[\x00-\x1f\x7f]/.test(value.value), "contains an invalid recognized field");
55723
56029
  return value.value;
55724
56030
  }
55725
56031
  function normalizeRow(row, version = 1) {
@@ -55727,7 +56033,7 @@ function normalizeRow(row, version = 1) {
55727
56033
  if (version !== 2 || !exactKeys(row, ["source", "installLocation", "lastUpdated", "autoUpdate"]))
55728
56034
  return;
55729
56035
  const autoUpdate = field(row, "autoUpdate");
55730
- need4(autoUpdate?.kind === "literal" && (autoUpdate.value === "true" || autoUpdate.value === "false"), "contains an invalid automatic-update preference");
56036
+ need5(autoUpdate?.kind === "literal" && (autoUpdate.value === "true" || autoUpdate.value === "false"), "contains an invalid automatic-update preference");
55731
56037
  }
55732
56038
  const source = field(row, "source");
55733
56039
  if (source?.kind !== "object")
@@ -55743,23 +56049,23 @@ function normalizeRow(row, version = 1) {
55743
56049
  absolutePath3(sourceLocation);
55744
56050
  absolutePath3(textField(field(row, "installLocation")));
55745
56051
  const updated = textField(field(row, "lastUpdated"));
55746
- need4(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(updated), "contains an invalid recognized update timestamp");
56052
+ need5(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(updated), "contains an invalid recognized update timestamp");
55747
56053
  const millis = Date.parse(updated);
55748
- need4(Number.isFinite(millis) && new Date(millis).toISOString() === updated, "contains an invalid recognized update timestamp");
56054
+ need5(Number.isFinite(millis) && new Date(millis).toISOString() === updated, "contains an invalid recognized update timestamp");
55749
56055
  row.entries = row.entries.map(([key, value]) => [key, key === "lastUpdated" ? { kind: "validated-update-time" } : value]);
55750
56056
  }
55751
56057
  function captureClaudeMarketplaceRegistry(path, budget = { remaining: 256 * 1024 * 1024 }) {
55752
56058
  const value = parse6(readRegistry2(path, budget));
55753
56059
  for (const [, row] of value.entries)
55754
56060
  normalizeRow(row);
55755
- const sha2562 = createHash14("sha256").update("hasna.skills.claude-marketplace-registry.v1\x00").update(JSON.stringify(value)).digest("hex");
56061
+ const sha2562 = createHash15("sha256").update("hasna.skills.claude-marketplace-registry.v1\x00").update(JSON.stringify(value)).digest("hex");
55756
56062
  return { path, hashMode: "claude-marketplace-registry", sha256: sha2562 };
55757
56063
  }
55758
56064
  function captureClaudeMarketplaceRegistryV2(path, budget = { remaining: 256 * 1024 * 1024 }) {
55759
56065
  const value = parse6(readRegistry2(path, budget));
55760
56066
  for (const [, row] of value.entries)
55761
56067
  normalizeRow(row, 2);
55762
- const sha2562 = createHash14("sha256").update("hasna.skills.claude-marketplace-registry.v2\x00").update(JSON.stringify(value)).digest("hex");
56068
+ const sha2562 = createHash15("sha256").update("hasna.skills.claude-marketplace-registry.v2\x00").update(JSON.stringify(value)).digest("hex");
55763
56069
  return { path, hashMode: "claude-marketplace-registry-v2", sha256: sha2562 };
55764
56070
  }
55765
56071
  var CLAUDE_MARKETPLACE_REGISTRY_LIMITS, sameFile2 = (a, b) => a.dev === b.dev && a.ino === b.ino && a.mode === b.mode && a.uid === b.uid && a.gid === b.gid && a.nlink === b.nlink && a.size === b.size && a.mtimeNs === b.mtimeNs && a.ctimeNs === b.ctimeNs, field = (object5, key) => object5.entries.find(([name]) => name === key)?.[1];
@@ -55769,17 +56075,17 @@ var init_claude_marketplace_registry = __esm(() => {
55769
56075
 
55770
56076
  // src/lib/codex-hook-trust-files.ts
55771
56077
  import { closeSync as closeSync12, constants as constants12, fstatSync as fstatSync12, fsyncSync as fsyncSync4, lstatSync as lstatSync20, openSync as openSync12, readSync as readSync10, writeFileSync as writeFileSync8 } from "fs";
55772
- import { createHash as createHash15 } from "crypto";
56078
+ import { createHash as createHash16 } from "crypto";
55773
56079
  import { dirname as dirname16 } from "path";
55774
- function need5(value, code) {
56080
+ function need6(value, code) {
55775
56081
  if (!value)
55776
56082
  throw new Error(`CODEX_HOOK_TRUST_${code}`);
55777
56083
  }
55778
56084
  function safeParents(file) {
55779
56085
  for (let p = dirname16(file);; p = dirname16(p)) {
55780
56086
  const s = lstatSync20(p);
55781
- need5(s.isDirectory() && !s.isSymbolicLink(), "UNSAFE_PARENT");
55782
- need5((s.mode & 18) === 0 || s.uid === 0 && (s.mode & 512) !== 0, "UNSAFE_PARENT");
56087
+ need6(s.isDirectory() && !s.isSymbolicLink(), "UNSAFE_PARENT");
56088
+ need6((s.mode & 18) === 0 || s.uid === 0 && (s.mode & 512) !== 0, "UNSAFE_PARENT");
55783
56089
  if (dirname16(p) === p)
55784
56090
  break;
55785
56091
  }
@@ -55788,12 +56094,12 @@ function snapshot(file, privateFile = false, options = {}) {
55788
56094
  const readOnlyPackage = options.readOnlyPackage === true && !privateFile;
55789
56095
  safeParents(file);
55790
56096
  const initial2 = lstatSync20(file, { bigint: true });
55791
- need5(initial2.isFile() && initial2.uid === BigInt(process.getuid()) && (initial2.nlink === 1n || readOnlyPackage && initial2.nlink > 1n) && (initial2.mode & 0o022n) === 0n && (!privateFile || (initial2.mode & 0o777n) === 0o600n), "UNSAFE_FILE");
55792
- need5(initial2.size <= 8n * 1024n * 1024n, "FILE_BOUND");
56097
+ need6(initial2.isFile() && initial2.uid === BigInt(process.getuid()) && (initial2.nlink === 1n || readOnlyPackage && initial2.nlink > 1n) && (initial2.mode & 0o022n) === 0n && (!privateFile || (initial2.mode & 0o777n) === 0o600n), "UNSAFE_FILE");
56098
+ need6(initial2.size <= 8n * 1024n * 1024n, "FILE_BOUND");
55793
56099
  const fd = openSync12(file, constants12.O_RDONLY | constants12.O_NOFOLLOW | constants12.O_NONBLOCK);
55794
56100
  try {
55795
56101
  const before2 = fstatSync12(fd, { bigint: true });
55796
- need5(sameStat(initial2, before2), "INPUT_CHANGED");
56102
+ need6(sameStat(initial2, before2), "INPUT_CHANGED");
55797
56103
  const bytes = Buffer.alloc(Number(before2.size) + 1);
55798
56104
  let length = 0;
55799
56105
  while (length < bytes.length) {
@@ -55802,16 +56108,16 @@ function snapshot(file, privateFile = false, options = {}) {
55802
56108
  break;
55803
56109
  length += n2;
55804
56110
  }
55805
- need5(length === Number(before2.size) && sameStat(before2, fstatSync12(fd, { bigint: true })) && sameStat(before2, lstatSync20(file, { bigint: true })), "INPUT_CHANGED");
56111
+ need6(length === Number(before2.size) && sameStat(before2, fstatSync12(fd, { bigint: true })) && sameStat(before2, lstatSync20(file, { bigint: true })), "INPUT_CHANGED");
55806
56112
  const content = bytes.subarray(0, length), text2 = new TextDecoder("utf-8", { fatal: true }).decode(content);
55807
- return { file, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before2, sha256: createHash15("sha256").update(content).digest("hex") };
56113
+ return { file, privateFile, readOnlyPackage, text: text2, bytes: content, stat: before2, sha256: createHash16("sha256").update(content).digest("hex") };
55808
56114
  } finally {
55809
56115
  closeSync12(fd);
55810
56116
  }
55811
56117
  }
55812
56118
  function unchanged2(before2) {
55813
56119
  const after2 = snapshot(before2.file, before2.privateFile, before2.readOnlyPackage ? { readOnlyPackage: true } : {});
55814
- need5(sameStat(before2.stat, after2.stat) && after2.sha256 === before2.sha256, "INPUT_CHANGED");
56120
+ need6(sameStat(before2.stat, after2.stat) && after2.sha256 === before2.sha256, "INPUT_CHANGED");
55815
56121
  }
55816
56122
  function save(file, content) {
55817
56123
  safeParents(file);
@@ -55827,7 +56133,7 @@ var sameStat = (a, b) => ["dev", "ino", "uid", "nlink", "mode", "size", "mtimeNs
55827
56133
  var init_codex_hook_trust_files = () => {};
55828
56134
 
55829
56135
  // src/lib/codex-hook-trust-layout.ts
55830
- import { isDeepStrictEqual as isDeepStrictEqual4 } from "util";
56136
+ import { isDeepStrictEqual as isDeepStrictEqual5 } from "util";
55831
56137
  function codexTrustTextWitness(text2, keys2, canonicalize = true) {
55832
56138
  const parsed = Bun.TOML.parse(text2), wanted = new Set(keys2);
55833
56139
  const headers = [...text2.matchAll(/^[ \t]*(\[[^\r\n]+\])[ \t]*(#[^\r\n]*)?(?:\r?\n|$)/gm)];
@@ -55892,7 +56198,7 @@ function codexTrustTextWitness(text2, keys2, canonicalize = true) {
55892
56198
  if (expected.hooks)
55893
56199
  delete expected.hooks.state;
55894
56200
  try {
55895
- if (!isDeepStrictEqual4(prune(Bun.TOML.parse(noState)), prune(expected)))
56201
+ if (!isDeepStrictEqual5(prune(Bun.TOML.parse(noState)), prune(expected)))
55896
56202
  throw fail2();
55897
56203
  } catch {
55898
56204
  throw fail2();
@@ -55962,55 +56268,55 @@ var init_codex_hook_trust_layout = () => {};
55962
56268
 
55963
56269
  // src/lib/codex-hook-additions-review.ts
55964
56270
  import { isAbsolute as isAbsolute16 } from "path";
55965
- import { isDeepStrictEqual as isDeepStrictEqual5 } from "util";
56271
+ import { isDeepStrictEqual as isDeepStrictEqual6 } from "util";
55966
56272
  function exactKeys2(value, keys2) {
55967
- need5(value && typeof value === "object" && !Array.isArray(value) && isDeepStrictEqual5(Object.keys(value).sort(), [...keys2].sort()), "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
56273
+ need6(value && typeof value === "object" && !Array.isArray(value) && isDeepStrictEqual6(Object.keys(value).sort(), [...keys2].sort()), "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
55968
56274
  }
55969
56275
  function readReviewedAdditionTrustStates(proof, before2, current, journalHooks) {
55970
56276
  const captured = proofs.get(proof);
55971
- need5(!!captured && captured.before.file === before2.file && captured.before.sha256 === before2.sha256 && captured.current.file === current.file && captured.current.sha256 === current.sha256 && isDeepStrictEqual5(captured.journalHooks, journalHooks.map(({ key, currentHash }) => ({ key, currentHash }))), "RECONCILE_ADDITIONS_PROOF_CHANGED");
56277
+ need6(!!captured && captured.before.file === before2.file && captured.before.sha256 === before2.sha256 && captured.current.file === current.file && captured.current.sha256 === current.sha256 && isDeepStrictEqual6(captured.journalHooks, journalHooks.map(({ key, currentHash }) => ({ key, currentHash }))), "RECONCILE_ADDITIONS_PROOF_CHANGED");
55972
56278
  captured.recheck();
55973
56279
  unchanged2(before2);
55974
56280
  unchanged2(current);
55975
56281
  return captured.states;
55976
56282
  }
55977
56283
  function reviewNativeHookAdditions(options) {
55978
- need5(isAbsolute16(options.path), "RECONCILE_ADDITIONS_REVIEW_PATH");
56284
+ need6(isAbsolute16(options.path), "RECONCILE_ADDITIONS_REVIEW_PATH");
55979
56285
  const reviewFile = snapshot(options.path, true), review = JSON.parse(reviewFile.text);
55980
56286
  exactKeys2(review, ["version", "kind", "reason", "producerEvidence", "journalIntentSha256", "policySha256", "configCurrentSha256", "hooksCurrentSha256", "producerBefore", "additions"]);
55981
- need5((review.version === 1 || review.version === 2) && review.kind === "native-hook-additions" && text2(review.reason) && text2(review.producerEvidence), "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
56287
+ need6((review.version === 1 || review.version === 2) && review.kind === "native-hook-additions" && text2(review.reason) && text2(review.producerEvidence), "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
55982
56288
  for (const [name, expected] of [["journalIntentSha256", options.intent.sha256], ["policySha256", options.policy.sha256], ["configCurrentSha256", options.configCurrent.sha256], ["hooksCurrentSha256", options.hooksCurrent.sha256]])
55983
- need5(hash2(review[name]) && review[name] === expected, "RECONCILE_ADDITIONS_REVIEW_CHANGED");
56289
+ need6(hash2(review[name]) && review[name] === expected, "RECONCILE_ADDITIONS_REVIEW_CHANGED");
55984
56290
  exactKeys2(review.producerBefore, ["configPath", "configSha256", "hooksPath", "hooksSha256"]);
55985
56291
  const before2 = review.producerBefore;
55986
- need5(isAbsolute16(before2.configPath) && isAbsolute16(before2.hooksPath) && hash2(before2.configSha256) && hash2(before2.hooksSha256), "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
56292
+ need6(isAbsolute16(before2.configPath) && isAbsolute16(before2.hooksPath) && hash2(before2.configSha256) && hash2(before2.hooksSha256), "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
55987
56293
  const producerConfig = snapshot(before2.configPath, true), producerHooks = snapshot(before2.hooksPath, true);
55988
- need5(producerConfig.sha256 === before2.configSha256 && producerHooks.sha256 === before2.hooksSha256 && producerHooks.sha256 === options.hooksBefore.sha256, "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
56294
+ need6(producerConfig.sha256 === before2.configSha256 && producerHooks.sha256 === before2.hooksSha256 && producerHooks.sha256 === options.hooksBefore.sha256, "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
55989
56295
  const original = structure(options.configBefore.text), producer = structure(producerConfig.text), expectedProducer = structuredClone(original), originalKeys = options.journalHooks.map((hook) => hook.key);
55990
56296
  expectedProducer.hooks ??= {};
55991
56297
  expectedProducer.hooks.state ??= {};
55992
56298
  for (const hook of options.journalHooks)
55993
56299
  expectedProducer.hooks.state[hook.key] = { ...expectedProducer.hooks.state[hook.key], enabled: true, trusted_hash: hook.currentHash };
55994
- need5(isDeepStrictEqual5(expectedProducer, producer) && codexTrustReconcileWitness(options.configBefore.text, originalKeys) === codexTrustReconcileWitness(producerConfig.text, originalKeys) && codexTrustUnmanagedSemantic(options.configBefore.text, originalKeys) === codexTrustUnmanagedSemantic(producerConfig.text, originalKeys), "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
55995
- need5(Array.isArray(review.additions) && review.additions.length > 0 && review.additions.length <= 20, "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
56300
+ need6(isDeepStrictEqual6(expectedProducer, producer) && codexTrustReconcileWitness(options.configBefore.text, originalKeys) === codexTrustReconcileWitness(producerConfig.text, originalKeys) && codexTrustUnmanagedSemantic(options.configBefore.text, originalKeys) === codexTrustUnmanagedSemantic(producerConfig.text, originalKeys), "RECONCILE_ADDITIONS_PRODUCER_PREIMAGE");
56301
+ need6(Array.isArray(review.additions) && review.additions.length > 0 && review.additions.length <= 20, "RECONCILE_ADDITIONS_REVIEW_SCHEMA");
55996
56302
  const expectedHooks = JSON.parse(options.hooksBefore.text), currentHooks = JSON.parse(options.hooksCurrent.text), expectedConfig = structuredClone(producer);
55997
- need5(expectedHooks.hooks && typeof expectedHooks.hooks === "object" && !Array.isArray(expectedHooks.hooks), "RECONCILE_ADDITIONS_DECLARATIONS");
56303
+ need6(expectedHooks.hooks && typeof expectedHooks.hooks === "object" && !Array.isArray(expectedHooks.hooks), "RECONCILE_ADDITIONS_DECLARATIONS");
55998
56304
  const added = [], states = [], seen = new Set, commands = new Set(options.recordedNativeHooks.map((hook) => hook.command));
55999
56305
  for (const addition of review.additions) {
56000
56306
  exactKeys2(addition, review.version === 1 ? ["event", "nativeHook"] : ["event", "nativeHook", "trustState"]);
56001
- need5(Object.hasOwn(review.version === 1 ? events : matchedEvents, addition.event), "RECONCILE_ADDITIONS_DECLARATIONS");
56307
+ need6(Object.hasOwn(review.version === 1 ? events : matchedEvents, addition.event), "RECONCILE_ADDITIONS_DECLARATIONS");
56002
56308
  const { event, nativeHook: hook } = addition;
56003
56309
  exactKeys2(hook, nativeKeys);
56004
56310
  const groups = expectedHooks.hooks[event] ?? [];
56005
- need5(Array.isArray(groups), "RECONCILE_ADDITIONS_DECLARATIONS");
56311
+ need6(Array.isArray(groups), "RECONCILE_ADDITIONS_DECLARATIONS");
56006
56312
  const key = `${options.nativeHooksPath}:${matchedEvents[event][1]}:${groups.length}:0`;
56007
- need5(hook.key === key && !seen.has(key) && !options.recordedNativeHooks.some((originalHook) => originalHook.key === key) && !Object.hasOwn(expectedConfig.hooks.state, key), "RECONCILE_ADDITIONS_IDENTITY");
56008
- need5(hook.eventName === matchedEvents[event][0] && hook.handlerType === "command" && (review.version === 2 ? v2Command(hook.command) : text2(hook.command, 16384)) && !commands.has(hook.command) && Number.isInteger(hook.timeoutSec) && hook.timeoutSec > 0 && hook.timeoutSec <= 60 && (event === "PreToolUse" ? text2(hook.matcher) : hook.matcher === null) && hook.async === false && hook.statusMessage === null && hook.additionalContextLimit === null && hook.sourcePath === options.nativeHooksPath && hook.source === "user" && hook.pluginId === null && hook.isManaged === false && /^sha256:[a-f0-9]{64}$/.test(hook.currentHash) && hook.enabled === true && hook.trustStatus === "trusted", "RECONCILE_ADDITIONS_IDENTITY");
56313
+ need6(hook.key === key && !seen.has(key) && !options.recordedNativeHooks.some((originalHook) => originalHook.key === key) && !Object.hasOwn(expectedConfig.hooks.state, key), "RECONCILE_ADDITIONS_IDENTITY");
56314
+ need6(hook.eventName === matchedEvents[event][0] && hook.handlerType === "command" && (review.version === 2 ? v2Command(hook.command) : text2(hook.command, 16384)) && !commands.has(hook.command) && Number.isInteger(hook.timeoutSec) && hook.timeoutSec > 0 && hook.timeoutSec <= 60 && (event === "PreToolUse" ? text2(hook.matcher) : hook.matcher === null) && hook.async === false && hook.statusMessage === null && hook.additionalContextLimit === null && hook.sourcePath === options.nativeHooksPath && hook.source === "user" && hook.pluginId === null && hook.isManaged === false && /^sha256:[a-f0-9]{64}$/.test(hook.currentHash) && hook.enabled === true && hook.trustStatus === "trusted", "RECONCILE_ADDITIONS_IDENTITY");
56009
56315
  let trustState = { enabled: true, trusted_hash: hook.currentHash };
56010
56316
  if (review.version === 2) {
56011
56317
  const state = addition.trustState;
56012
56318
  exactKeys2(state, state && Object.hasOwn(state, "enabled") ? ["enabled", "trusted_hash"] : ["trusted_hash"]);
56013
- need5(state.trusted_hash === hook.currentHash && (!Object.hasOwn(state, "enabled") || state.enabled === true), "RECONCILE_ADDITIONS_TRUST_STATE");
56319
+ need6(state.trusted_hash === hook.currentHash && (!Object.hasOwn(state, "enabled") || state.enabled === true), "RECONCILE_ADDITIONS_TRUST_STATE");
56014
56320
  trustState = { ...state };
56015
56321
  }
56016
56322
  seen.add(key);
@@ -56020,9 +56326,9 @@ function reviewNativeHookAdditions(options) {
56020
56326
  expectedHooks.hooks[event] = [...groups, { ...event === "PreToolUse" ? { matcher: hook.matcher } : {}, hooks: [{ type: "command", command: hook.command, timeout: hook.timeoutSec }] }];
56021
56327
  expectedConfig.hooks.state[key] = trustState;
56022
56328
  }
56023
- need5(isDeepStrictEqual5(expectedHooks, currentHooks), "RECONCILE_ADDITIONS_DECLARATIONS");
56329
+ need6(isDeepStrictEqual6(expectedHooks, currentHooks), "RECONCILE_ADDITIONS_DECLARATIONS");
56024
56330
  const keys2 = added.map((hook) => hook.key);
56025
- need5(isDeepStrictEqual5(expectedConfig, structure(options.configCurrent.text)) && codexTrustReconcileWitness(producerConfig.text, keys2) === codexTrustReconcileWitness(options.configCurrent.text, keys2) && codexTrustUnmanagedSemantic(producerConfig.text, keys2) === codexTrustUnmanagedSemantic(options.configCurrent.text, keys2), "RECONCILE_ADDITIONS_CONFIG");
56331
+ need6(isDeepStrictEqual6(expectedConfig, structure(options.configCurrent.text)) && codexTrustReconcileWitness(producerConfig.text, keys2) === codexTrustReconcileWitness(options.configCurrent.text, keys2) && codexTrustUnmanagedSemantic(producerConfig.text, keys2) === codexTrustUnmanagedSemantic(options.configCurrent.text, keys2), "RECONCILE_ADDITIONS_CONFIG");
56026
56332
  const inputs = [reviewFile, producerConfig, producerHooks, options.intent, options.policy, options.configBefore, options.configCurrent, options.hooksBefore, options.hooksCurrent];
56027
56333
  const recheck = () => {
56028
56334
  for (const input of inputs)
@@ -56044,8 +56350,8 @@ var init_codex_hook_additions_review = __esm(() => {
56044
56350
  });
56045
56351
 
56046
56352
  // src/lib/codex-hook-discovery-recovery.ts
56047
- import { createHash as createHash16 } from "crypto";
56048
- import { isDeepStrictEqual as isDeepStrictEqual6 } from "util";
56353
+ import { createHash as createHash17 } from "crypto";
56354
+ import { isDeepStrictEqual as isDeepStrictEqual7 } from "util";
56049
56355
  function createCodexHookDiscoveryRecovery(binding, before2, current, hooks, additions) {
56050
56356
  const journalHooks = hooks.map(({ key, currentHash }) => ({ key, currentHash }));
56051
56357
  const additionStates = additions ? readReviewedAdditionTrustStates(additions, before2, current, journalHooks) : [];
@@ -56056,16 +56362,16 @@ function createCodexHookDiscoveryRecovery(binding, before2, current, hooks, addi
56056
56362
  const raw = binding.sources.filter((source) => source.path === current.file && source.hashMode === "bytes");
56057
56363
  if (!raw.some((source) => source.sha256 !== current.sha256))
56058
56364
  return;
56059
- need5(binding.agent === "codex" && binding.method === "reviewed" && raw.length === 1 && raw[0].sha256 === before2.sha256 && before2.sha256 !== current.sha256, "RECONCILE_DISCOVERY_CONFIG_WITNESS");
56060
- need5(raw[0].format === undefined && raw[0].fields === undefined && raw[0].managedPlugins === undefined, "RECONCILE_DISCOVERY_CONFIG_WITNESS");
56365
+ need6(binding.agent === "codex" && binding.method === "reviewed" && raw.length === 1 && raw[0].sha256 === before2.sha256 && before2.sha256 !== current.sha256, "RECONCILE_DISCOVERY_CONFIG_WITNESS");
56366
+ need6(raw[0].format === undefined && raw[0].fields === undefined && raw[0].managedPlugins === undefined, "RECONCILE_DISCOVERY_CONFIG_WITNESS");
56061
56367
  const typed = binding.sources.filter((source) => source.path === current.file && source.format === "toml");
56062
- need5(typed.length === 1 && typed[0].hashMode === undefined && isDeepStrictEqual6(typed[0].fields, fields), "RECONCILE_DISCOVERY_TYPED_WITNESS");
56368
+ need6(typed.length === 1 && typed[0].hashMode === undefined && isDeepStrictEqual7(typed[0].fields, fields), "RECONCILE_DISCOVERY_TYPED_WITNESS");
56063
56369
  const original = structure2(before2.text), actual = structure2(current.text);
56064
56370
  const project = (value) => Object.fromEntries(fields.map((field2) => [field2, value[field2] ?? null]));
56065
- const projection = sha3(JSON.stringify(project(original)));
56066
- need5(typed[0].sha256 === projection && sha3(JSON.stringify(project(actual))) === projection && isDeepStrictEqual6(project(original), project(actual)), "RECONCILE_DISCOVERY_TYPED_WITNESS");
56371
+ const projection = sha4(JSON.stringify(project(original)));
56372
+ need6(typed[0].sha256 === projection && sha4(JSON.stringify(project(actual))) === projection && isDeepStrictEqual7(project(original), project(actual)), "RECONCILE_DISCOVERY_TYPED_WITNESS");
56067
56373
  const keys2 = [...journalHooks.map((hook) => hook.key), ...additionStates.map((hook) => hook.key)];
56068
- need5(journalHooks.length > 0 && keys2.length <= 100 && new Set(keys2).size === keys2.length && journalHooks.every((hook) => typeof hook.key === "string" && /^sha256:[a-f0-9]{64}$/.test(hook.currentHash)), "RECONCILE_DISCOVERY_TRUST_WITNESS");
56374
+ need6(journalHooks.length > 0 && keys2.length <= 100 && new Set(keys2).size === keys2.length && journalHooks.every((hook) => typeof hook.key === "string" && /^sha256:[a-f0-9]{64}$/.test(hook.currentHash)), "RECONCILE_DISCOVERY_TRUST_WITNESS");
56069
56375
  const expected = structuredClone(original);
56070
56376
  expected.hooks ??= {};
56071
56377
  expected.hooks.state ??= {};
@@ -56073,16 +56379,16 @@ function createCodexHookDiscoveryRecovery(binding, before2, current, hooks, addi
56073
56379
  expected.hooks.state[hook.key] = { ...expected.hooks.state[hook.key], enabled: true, trusted_hash: hook.currentHash };
56074
56380
  for (const { key, state } of additionStates)
56075
56381
  expected.hooks.state[key] = { ...state };
56076
- need5(isDeepStrictEqual6(expected, actual) && codexTrustReconcileWitness(before2.text, keys2) === codexTrustReconcileWitness(current.text, keys2) && codexTrustUnmanagedSemantic(before2.text, keys2) === codexTrustUnmanagedSemantic(current.text, keys2), "RECONCILE_DISCOVERY_TRUST_WITNESS");
56382
+ need6(isDeepStrictEqual7(expected, actual) && codexTrustReconcileWitness(before2.text, keys2) === codexTrustReconcileWitness(current.text, keys2) && codexTrustUnmanagedSemantic(before2.text, keys2) === codexTrustUnmanagedSemantic(current.text, keys2), "RECONCILE_DISCOVERY_TRUST_WITNESS");
56077
56383
  unchanged2(before2);
56078
56384
  unchanged2(current);
56079
- const witness = Object.freeze({ configPath: current.file, beforeSha256: before2.sha256, currentSha256: current.sha256, discoverySha256: sha3(JSON.stringify(binding)), typedProjectionSha256: projection });
56385
+ const witness = Object.freeze({ configPath: current.file, beforeSha256: before2.sha256, currentSha256: current.sha256, discoverySha256: sha4(JSON.stringify(binding)), typedProjectionSha256: projection });
56080
56386
  proofs2.set(witness, { before: before2, current, recheckAdditions });
56081
56387
  return witness;
56082
56388
  }
56083
56389
  function assertCodexHookDiscoveryRecovery(binding, witness) {
56084
56390
  const proof = proofs2.get(witness);
56085
- need5(!!proof && binding.agent === "codex" && witness.discoverySha256 === sha3(JSON.stringify(binding)), "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
56391
+ need6(!!proof && binding.agent === "codex" && witness.discoverySha256 === sha4(JSON.stringify(binding)), "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
56086
56392
  unchanged2(proof.before);
56087
56393
  unchanged2(proof.current);
56088
56394
  proof.recheckAdditions();
@@ -56091,23 +56397,24 @@ function verifiesCodexHookDiscoverySource(binding, source, currentDigest, witnes
56091
56397
  if (!witness || source.path !== witness.configPath || source.hashMode !== "bytes")
56092
56398
  return false;
56093
56399
  assertCodexHookDiscoveryRecovery(binding, witness);
56094
- need5(source.sha256 === witness.beforeSha256 && currentDigest === witness.currentSha256, "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
56400
+ need6(source.sha256 === witness.beforeSha256 && currentDigest === witness.currentSha256, "RECONCILE_DISCOVERY_RECOVERY_CHANGED");
56095
56401
  return true;
56096
56402
  }
56097
- var sha3 = (text3) => createHash16("sha256").update(text3).digest("hex"), fields, structure2 = (text3) => JSON.parse(JSON.stringify(Bun.TOML.parse(text3))), proofs2;
56403
+ var sha4 = (text3) => createHash17("sha256").update(text3).digest("hex"), fields, structure2 = (text3) => JSON.parse(JSON.stringify(Bun.TOML.parse(text3))), proofs2;
56098
56404
  var init_codex_hook_discovery_recovery = __esm(() => {
56099
56405
  init_codex_hook_trust_files();
56100
56406
  init_codex_hook_trust_layout();
56101
56407
  init_codex_hook_additions_review();
56102
- fields = ["plugins", "marketplaces", "skills"];
56408
+ init_codex_settings_witness();
56409
+ fields = [...CODEX_DISCOVERY_PROJECTION_FIELDS];
56103
56410
  proofs2 = new WeakMap;
56104
56411
  });
56105
56412
 
56106
56413
  // src/lib/agent-discovery.ts
56107
- import { createHash as createHash17 } from "crypto";
56414
+ import { createHash as createHash18 } from "crypto";
56108
56415
  import { lstatSync as lstatSync21, readFileSync as readFileSync18, readdirSync as readdirSync11, realpathSync as realpathSync7 } from "fs";
56109
- import { basename as basename8, dirname as dirname17, isAbsolute as isAbsolute17, join as join32, resolve as resolve16, sep as sep6 } from "path";
56110
- import { isDeepStrictEqual as isDeepStrictEqual7 } from "util";
56416
+ import { basename as basename9, dirname as dirname17, isAbsolute as isAbsolute17, join as join32, resolve as resolve16, sep as sep6 } from "path";
56417
+ import { isDeepStrictEqual as isDeepStrictEqual8 } from "util";
56111
56418
  function parseConfig(text3, path, toml = false) {
56112
56419
  try {
56113
56420
  const value = toml ? Bun.TOML.parse(text3) : JSON.parse(text3);
@@ -56139,14 +56446,26 @@ function read2(path, changes) {
56139
56446
  throw new Error(`Unsupported or oversized native discovery input: ${path}`);
56140
56447
  return readFileSync18(path, "utf8");
56141
56448
  }
56449
+ function projectNativeDiscoveryFields(text3, format, fields2, path) {
56450
+ const object5 = format === "yaml" ? parseHermesConfig(text3) : parseConfig(text3, path, format === "toml");
56451
+ if (!object5 || typeof object5 !== "object" || Array.isArray(object5))
56452
+ throw new Error("Expected native discovery configuration object");
56453
+ return digest(JSON.stringify(Object.fromEntries(fields2.map((field2) => [field2, object5[field2] ?? null]))));
56454
+ }
56455
+ function isSupersededCodexProjection(agent, configPath, source) {
56456
+ return agent === "codex" && source.path === configPath && source.format === "toml" && isDeepStrictEqual8(source.fields, [...CODEX_DISCOVERY_PROJECTION_FIELDS]);
56457
+ }
56458
+ function supersedesCodexProjection(sources, configPath) {
56459
+ return sources.some((source) => source.path === configPath && source.hashMode === "codex-settings-v2");
56460
+ }
56142
56461
  function projected(source, changes, budget = discoveryByteBudget()) {
56143
- if (source.hashMode === "codex-settings-v1") {
56462
+ if (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2") {
56144
56463
  if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
56145
56464
  throw new Error("Codex settings witnesses require exact typed metadata");
56146
- const current = captureCodexSettings(source.path, budget).sha256;
56465
+ const current = (source.hashMode === "codex-settings-v2" ? captureCodexSettingsV2 : captureCodexSettings)(source.path, budget).sha256;
56147
56466
  if (current !== source.sha256)
56148
56467
  throw new Error(`Native discovery input changed; run skills hook install with a fresh discovery review: ${source.path}`);
56149
- return changes?.has(source.path) ? hashCodexSettingsReplacement(changes.get(source.path), budget) : current;
56468
+ return changes?.has(source.path) ? (source.hashMode === "codex-settings-v2" ? hashCodexSettingsReplacementV2 : hashCodexSettingsReplacement)(changes.get(source.path), budget) : current;
56150
56469
  }
56151
56470
  if (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") {
56152
56471
  if (source.format !== undefined || source.fields !== undefined || source.managedPlugins !== undefined || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256))
@@ -56185,10 +56504,7 @@ function projected(source, changes, budget = discoveryByteBudget()) {
56185
56504
  return null;
56186
56505
  if (!source.format)
56187
56506
  return digest(text3);
56188
- const object5 = source.format === "yaml" ? parseHermesConfig(text3) : parseConfig(text3, source.path, source.format === "toml");
56189
- if (!object5 || typeof object5 !== "object" || Array.isArray(object5))
56190
- throw new Error("Expected native discovery configuration object");
56191
- return digest(JSON.stringify(Object.fromEntries((source.fields ?? []).map((field2) => [field2, object5[field2] ?? null]))));
56507
+ return projectNativeDiscoveryFields(text3, source.format, source.fields ?? [], source.path);
56192
56508
  }
56193
56509
  function verifyAgentDiscovery(binding, codexRecovery) {
56194
56510
  if (codexRecovery)
@@ -56216,9 +56532,9 @@ function verifyAgentDiscovery(binding, codexRecovery) {
56216
56532
  safe4(root2);
56217
56533
  }
56218
56534
  function assertMarketplaceBinding(binding, source) {
56219
- if (source.hashMode === "codex-settings-v1" && (binding.agent !== "codex" || binding.method !== "reviewed" || basename8(source.path) !== "config.toml"))
56535
+ if ((source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2") && (binding.agent !== "codex" || binding.method !== "reviewed" || basename9(source.path) !== "config.toml"))
56220
56536
  throw new Error("Codex settings witnesses require explicit reviewed Codex configuration");
56221
- if ((source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") && (binding.agent !== "claude" || binding.method !== "reviewed" || basename8(source.path) !== "settings.json"))
56537
+ if ((source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || source.hashMode === "claude-settings-v3") && (binding.agent !== "claude" || binding.method !== "reviewed" || basename9(source.path) !== "settings.json"))
56222
56538
  throw new Error("Claude settings witnesses require explicit reviewed Claude configuration");
56223
56539
  if ((source.hashMode === "claude-marketplace-registry" || source.hashMode === "claude-marketplace-registry-v2") && (binding.agent !== "claude" || binding.method !== "reviewed"))
56224
56540
  throw new Error("Claude marketplace witnesses require explicit reviewed Claude discovery");
@@ -56233,8 +56549,8 @@ function rebindAgentDiscovery(binding, changes) {
56233
56549
  return { ...source, sha256: sha2562 };
56234
56550
  }) };
56235
56551
  }
56236
- function assertProjectDiscovery(agent, directories, home, canonical5 = resolve16, reviewed) {
56237
- const homeConfigPath = canonical5(agentDiscoveryConfigPath(home, agent));
56552
+ function assertProjectDiscovery(agent, directories, home, canonical6 = resolve16, reviewed) {
56553
+ const homeConfigPath = canonical6(agentDiscoveryConfigPath(home, agent));
56238
56554
  for (const directory of directories) {
56239
56555
  const isHome = resolve16(directory) === resolve16(home);
56240
56556
  if (agent === "hermes") {
@@ -56245,7 +56561,7 @@ function assertProjectDiscovery(agent, directories, home, canonical5 = resolve16
56245
56561
  continue;
56246
56562
  const paths = agent === "claude" ? [...isHome ? [] : [".claude/settings.json"], ".claude/settings.local.json"] : agent === "codex" ? [".codex/config.toml"] : agent === "gemini" ? [".gemini/settings.json"] : agent === "opencode" ? ["opencode.json", "opencode.jsonc", ".opencode/opencode.json", ".opencode/opencode.jsonc"] : [".cursor/hooks.json"];
56247
56563
  for (const suffix of paths) {
56248
- const path = canonical5(join32(directory, suffix)), raw = read2(path);
56564
+ const path = canonical6(join32(directory, suffix)), raw = read2(path);
56249
56565
  if (raw === null)
56250
56566
  continue;
56251
56567
  const isRootAliasedHomeConfig = agent === "claude" && suffix === ".claude/settings.json" || agent === "codex" && suffix === ".codex/config.toml";
@@ -56261,14 +56577,14 @@ function assertProjectDiscovery(agent, directories, home, canonical5 = resolve16
56261
56577
  const managed = reviewed.sources.flatMap((source) => source.hashMode === "claude-plugin-registry" ? source.managedPlugins ?? [] : []);
56262
56578
  if (exact && projected(exact) === exact.sha256 && managed.length) {
56263
56579
  const bindings = managed.map((item) => readPluginBinding(item.storeRoot, item.bindingId));
56264
- admittedPlugins = Object.entries(config.enabledPlugins).every(([id, enabled]) => typeof enabled === "boolean" && bindings.some((binding) => binding.target.pluginId === id && binding.target.registrations.some((scope) => scope.scope === "project" && scope.projectPath === canonical5(directory))));
56580
+ admittedPlugins = Object.entries(config.enabledPlugins).every(([id, enabled]) => typeof enabled === "boolean" && bindings.some((binding) => binding.target.pluginId === id && binding.target.registrations.some((scope) => scope.scope === "project" && scope.projectPath === canonical6(directory))));
56265
56581
  }
56266
56582
  }
56267
56583
  if (keys2.some((key) => config[key] !== undefined && !(key === "enabledPlugins" && admittedPlugins)) || config.disableAllHooks === true || config.disableBundledSkills === false || config.hooksConfig?.enabled === false || config.permission?.skill !== undefined || config.permissions?.deny?.some((rule) => typeof rule === "string" && /^Skill(?:\(|$)/.test(rule)))
56268
56584
  throw new Error(`NATIVE_SKILL_DRIFT: higher-precedence project skill or hook configuration requires review: ${path}`);
56269
56585
  }
56270
56586
  if (agent === "claude") {
56271
- const commands = canonical5(join32(directory, ".claude/commands"));
56587
+ const commands = canonical6(join32(directory, ".claude/commands"));
56272
56588
  safe4(commands);
56273
56589
  if (lstatSync21(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync11(commands).length)
56274
56590
  throw new Error("NATIVE_SKILL_DRIFT: legacy project command discovery requires a dedicated format adapter");
@@ -56279,10 +56595,10 @@ function agentDiscoveryConfigPath(home, agent) {
56279
56595
  return join32(home, agent === "hermes" ? ".hermes/config.yaml" : agent === "opencode" ? ".config/opencode/opencode.json" : `.${agent}/${agent === "codex" ? "config.toml" : agent === "cursor" ? "hooks.json" : "settings.json"}`);
56280
56596
  }
56281
56597
  function resolveAgentDiscovery(options) {
56282
- const canonical5 = options.canonical ?? resolve16, home = resolve16(options.home), agent = options.agent;
56598
+ const canonical6 = options.canonical ?? resolve16, home = resolve16(options.home), agent = options.agent;
56283
56599
  const sources = [], roots = new Set, builtinNames = [];
56284
56600
  const witness = (path, format, fields2) => {
56285
- const source = { path: canonical5(path), sha256: null, ...format ? { format, fields: fields2 } : {} };
56601
+ const source = { path: canonical6(path), sha256: null, ...format ? { format, fields: fields2 } : {} };
56286
56602
  source.sha256 = projected(source);
56287
56603
  sources.push(source);
56288
56604
  return read2(source.path);
@@ -56290,7 +56606,7 @@ function resolveAgentDiscovery(options) {
56290
56606
  if (agent === "hermes")
56291
56607
  assertHermesEnvironment(home);
56292
56608
  const configPath = agentDiscoveryConfigPath(home, agent);
56293
- const configText = witness(configPath, agent === "hermes" ? "yaml" : agent === "codex" ? "toml" : "json", agent === "hermes" ? ["skills", "plugins", "hooks"] : agent === "claude" ? ["enabledPlugins", "extraKnownMarketplaces"] : agent === "codex" ? ["plugins", "marketplaces", "skills"] : agent === "gemini" ? ["skills", "extensions", "security"] : agent === "opencode" ? ["plugin", "skills"] : ["version"]);
56609
+ const configText = witness(configPath, agent === "hermes" ? "yaml" : agent === "codex" ? "toml" : "json", agent === "hermes" ? ["skills", "plugins", "hooks"] : agent === "claude" ? ["enabledPlugins", "extraKnownMarketplaces"] : agent === "codex" ? [...CODEX_DISCOVERY_PROJECTION_FIELDS] : agent === "gemini" ? ["skills", "extensions", "security"] : agent === "opencode" ? ["plugin", "skills"] : ["version"]);
56294
56610
  const config = configText === null ? {} : agent === "hermes" ? parseHermesConfig(configText) : parseConfig(configText, configPath, agent === "codex");
56295
56611
  const unresolved = (detail) => {
56296
56612
  throw new Error(`Native discovery is unresolved (${agent}: ${detail}); provide a reviewed --discovery-inputs file`);
@@ -56349,11 +56665,12 @@ function resolveAgentDiscovery(options) {
56349
56665
  if (retained.agent !== agent || retained.method !== "reviewed")
56350
56666
  unresolved("invalid retained review");
56351
56667
  verifyAgentDiscovery(retained);
56352
- if (!retained.sources.some((source) => source.path === canonical5(configPath) && source.format === undefined && source.fields === undefined))
56668
+ if (!retained.sources.some((source) => source.path === canonical6(configPath) && source.format === undefined && source.fields === undefined))
56353
56669
  unresolved("retained review is missing the full agent configuration source");
56354
- if (retained.sources.some((source) => (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "codex-settings-v1")) && source.path !== canonical5(configPath)))
56670
+ if (retained.sources.some((source) => (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2"))) && source.path !== canonical6(configPath)))
56355
56671
  unresolved("retained settings witness names another configuration source");
56356
- if (sources.some((source) => !retained.sources.some((saved) => isDeepStrictEqual7(saved, source))) || [...roots].some((root2) => !retained.roots.includes(root2)) || agent === "gemini" && JSON.stringify(retained.builtinNames) !== JSON.stringify(builtinNames))
56672
+ const covered = supersedesCodexProjection(retained.sources, canonical6(configPath)) ? sources.filter((source) => !isSupersededCodexProjection(agent, canonical6(configPath), source)) : sources;
56673
+ if (covered.some((source) => !retained.sources.some((saved) => isDeepStrictEqual8(saved, source))) || [...roots].some((root2) => !retained.roots.includes(root2)) || agent === "gemini" && JSON.stringify(retained.builtinNames) !== JSON.stringify(builtinNames))
56357
56674
  unresolved("retained review is missing current runtime discovery coverage");
56358
56675
  return retained;
56359
56676
  }
@@ -56367,14 +56684,15 @@ function resolveAgentDiscovery(options) {
56367
56684
  if (review.sources.some((source) => source.format !== undefined || source.fields !== undefined))
56368
56685
  throw new Error("Explicit discovery reviews require full source-file hashes");
56369
56686
  verifyAgentDiscovery(supplied);
56370
- if (review.sources.some((source) => (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || source.hashMode === "codex-settings-v1")) && source.path !== canonical5(configPath)))
56687
+ if (review.sources.some((source) => (source.hashMode === "claude-settings-v1" || source.hashMode === "claude-settings-v2" || (source.hashMode === "claude-settings-v3" || (source.hashMode === "codex-settings-v1" || source.hashMode === "codex-settings-v2"))) && source.path !== canonical6(configPath)))
56371
56688
  throw new Error("Semantic settings witnesses must name the configured Claude configuration source");
56372
- if (!review.sources.some((source) => source.path === canonical5(configPath)))
56689
+ if (!review.sources.some((source) => source.path === canonical6(configPath)))
56373
56690
  throw new Error("Discovery review must include the agent configuration source");
56374
- return { ...supplied, roots: [...new Set([...roots, ...supplied.roots])].sort(), sources: [...sources, ...review.sources], ...agent === "gemini" ? { builtinNames } : {} };
56691
+ const reviewedSources = supersedesCodexProjection(review.sources, canonical6(configPath)) ? sources.filter((source) => !isSupersededCodexProjection(agent, canonical6(configPath), source)) : sources;
56692
+ return { ...supplied, roots: [...new Set([...roots, ...supplied.roots])].sort(), sources: [...reviewedSources, ...review.sources], ...agent === "gemini" ? { builtinNames } : {} };
56375
56693
  }
56376
56694
  function plugin(root2) {
56377
- root2 = canonical5(root2);
56695
+ root2 = canonical6(root2);
56378
56696
  safe4(root2);
56379
56697
  const manifestPath = join32(root2, agent === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json");
56380
56698
  const raw = witness(manifestPath);
@@ -56406,7 +56724,7 @@ function resolveAgentDiscovery(options) {
56406
56724
  if (agent === "claude") {
56407
56725
  const registrations = witness(join32(home, ".claude/plugins/installed_plugins.json"));
56408
56726
  const installed = registrations === null ? {} : parseConfig(registrations, join32(home, ".claude/plugins/installed_plugins.json")).plugins;
56409
- const commands = canonical5(join32(home, ".claude/commands"));
56727
+ const commands = canonical6(join32(home, ".claude/commands"));
56410
56728
  safe4(commands);
56411
56729
  if (lstatSync21(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync11(commands).length)
56412
56730
  unresolved("legacy home command discovery requires a dedicated format adapter");
@@ -56480,9 +56798,9 @@ function resolveAgentDiscovery(options) {
56480
56798
  roots.add(join32(root2, "skills"));
56481
56799
  }
56482
56800
  }
56483
- return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join32(home, ".hermes/plugins"), join32(home, ".hermes/hermes-agent")].map((path) => canonical5(path))) } : {} };
56801
+ return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join32(home, ".hermes/plugins"), join32(home, ".hermes/hermes-agent")].map((path) => canonical6(path))) } : {} };
56484
56802
  }
56485
- var digest = (text3) => createHash17("sha256").update(text3).digest("hex");
56803
+ var digest = (text3) => createHash18("sha256").update(text3).digest("hex");
56486
56804
  var init_agent_discovery = __esm(() => {
56487
56805
  init_agent_policy_limits();
56488
56806
  init_agent_hermes();
@@ -56501,7 +56819,7 @@ var init_agent_discovery = __esm(() => {
56501
56819
  // src/lib/authoring-path.ts
56502
56820
  import { lstatSync as lstatSync22, realpathSync as realpathSync8 } from "fs";
56503
56821
  import { homedir as homedir7 } from "os";
56504
- import { basename as basename9, dirname as dirname18, join as join33, resolve as resolve17, sep as sep7 } from "path";
56822
+ import { basename as basename10, dirname as dirname18, join as join33, resolve as resolve17, sep as sep7 } from "path";
56505
56823
  function pathParts(path) {
56506
56824
  return resolve17(path).split(sep7).filter(Boolean);
56507
56825
  }
@@ -56520,7 +56838,7 @@ function physicalPath(path) {
56520
56838
  let cursor = resolve17(path);
56521
56839
  const suffix = [];
56522
56840
  while (!lstatSync22(cursor, { throwIfNoEntry: false })) {
56523
- suffix.unshift(basename9(cursor));
56841
+ suffix.unshift(basename10(cursor));
56524
56842
  const parent = dirname18(cursor);
56525
56843
  if (parent === cursor)
56526
56844
  return resolve17(path);
@@ -56615,7 +56933,7 @@ import {
56615
56933
  statSync as statSync11,
56616
56934
  writeFileSync as writeFileSync9
56617
56935
  } from "fs";
56618
- import { basename as basename10, dirname as dirname19, isAbsolute as isAbsolute18, join as join34, normalize as normalize3, relative as relative5, resolve as resolve18, sep as sep8 } from "path";
56936
+ import { basename as basename11, dirname as dirname19, isAbsolute as isAbsolute18, join as join34, normalize as normalize4, relative as relative6, resolve as resolve18, sep as sep8 } from "path";
56619
56937
  function getPortableSkillsRoot(options = {}) {
56620
56938
  return resolvePortableSkillsRoot(options, true);
56621
56939
  }
@@ -56713,7 +57031,7 @@ function scaffoldPortableSkill(name, options = {}) {
56713
57031
  return { name: skillName, path: skillPath, manifest, created: true };
56714
57032
  }
56715
57033
  function portPortableSkillDirectory(sourceDir, options = {}) {
56716
- const absoluteSource = normalize3(sourceDir);
57034
+ const absoluteSource = normalize4(sourceDir);
56717
57035
  if (!existsSync18(absoluteSource) || !statSync11(absoluteSource).isDirectory()) {
56718
57036
  throw new Error(`Import directory not found: ${sourceDir}`);
56719
57037
  }
@@ -56763,7 +57081,7 @@ function physicalImportPath(path) {
56763
57081
  let ancestor = resolve18(path);
56764
57082
  const suffix = [];
56765
57083
  while (!existsSync18(ancestor)) {
56766
- suffix.unshift(basename10(ancestor));
57084
+ suffix.unshift(basename11(ancestor));
56767
57085
  ancestor = dirname19(ancestor);
56768
57086
  }
56769
57087
  return join34(realpathSync9(ancestor), ...suffix);
@@ -56772,7 +57090,7 @@ function assertDisjointImportPaths(source, destination) {
56772
57090
  const sourcePath = realpathSync9(source);
56773
57091
  const destinationPath = physicalImportPath(destination);
56774
57092
  const contains2 = (parent, child) => {
56775
- const path = relative5(parent, child);
57093
+ const path = relative6(parent, child);
56776
57094
  return path === "" || !isAbsolute18(path) && path !== ".." && !path.startsWith(`..${sep8}`);
56777
57095
  };
56778
57096
  if (contains2(sourcePath, destinationPath) || contains2(destinationPath, sourcePath)) {
@@ -56780,7 +57098,7 @@ function assertDisjointImportPaths(source, destination) {
56780
57098
  }
56781
57099
  }
56782
57100
  function portPortableSkill(sourcePath, options = {}) {
56783
- const absoluteSource = normalize3(sourcePath);
57101
+ const absoluteSource = normalize4(sourcePath);
56784
57102
  if (!existsSync18(absoluteSource) || !statSync11(absoluteSource).isDirectory()) {
56785
57103
  throw new Error(`Skill source directory not found: ${sourcePath}`);
56786
57104
  }
@@ -56788,8 +57106,8 @@ function portPortableSkill(sourcePath, options = {}) {
56788
57106
  const explicitName = options.name != null;
56789
57107
  const skillName = normalizeNewPortableSkillName(options.name ?? inferred.name);
56790
57108
  if (isOfficialSkillName(skillName) && !options.allowShadow) {
56791
- const sourceSlug = safeNormalizeName(basename10(absoluteSource));
56792
- const via = explicitName ? `Name '${skillName}' matches a bundled official skill.` : `Inferred name '${skillName}'${sourceSlug && sourceSlug !== skillName ? ` (from source folder '${basename10(absoluteSource)}')` : ""} matches a bundled official skill.`;
57109
+ const sourceSlug = safeNormalizeName(basename11(absoluteSource));
57110
+ const via = explicitName ? `Name '${skillName}' matches a bundled official skill.` : `Inferred name '${skillName}'${sourceSlug && sourceSlug !== skillName ? ` (from source folder '${basename11(absoluteSource)}')` : ""} matches a bundled official skill.`;
56793
57111
  throw new Error(`${via} Importing it would shadow the official '${skillName}'. ` + `Pass --name to choose a different name, or --allow-shadow to override deliberately.`);
56794
57112
  }
56795
57113
  const readOnlyDestination = join34(resolvePortableSkillsRoot(options, false), skillName);
@@ -56992,7 +57310,7 @@ function safeIsDirectory(path) {
56992
57310
  function isSafeRelativePath2(value) {
56993
57311
  if (!value.trim() || isAbsolute18(value))
56994
57312
  return false;
56995
- const normalized = normalize3(value).replace(/\\/g, "/");
57313
+ const normalized = normalize4(value).replace(/\\/g, "/");
56996
57314
  return normalized !== ".." && !normalized.startsWith("../") && !normalized.includes("/../");
56997
57315
  }
56998
57316
  function add4(target, code, message) {
@@ -58998,13 +59316,13 @@ var require_cli_spinners = __commonJS((exports, module) => {
58998
59316
 
58999
59317
  // src/lib/auth-store.ts
59000
59318
  import { chmodSync as chmodSync2, existsSync as existsSync20, mkdirSync as mkdirSync11, readFileSync as readFileSync20, renameSync as renameSync7, statSync as statSync12, unlinkSync as unlinkSync5, writeFileSync as writeFileSync10 } from "fs";
59001
- import { basename as basename11, dirname as dirname20, join as join36 } from "path";
59319
+ import { basename as basename12, dirname as dirname20, join as join36 } from "path";
59002
59320
  function getAuthFilePath(env3 = process.env) {
59003
59321
  return skillsCredentialFilePath(env3);
59004
59322
  }
59005
59323
  function getIdentityFilePath(env3 = process.env) {
59006
59324
  const file = skillsCredentialFilePath(env3);
59007
- return join36(dirname20(file), basename11(file).replace(/^credentials/, "identity") + ".json");
59325
+ return join36(dirname20(file), basename12(file).replace(/^credentials/, "identity") + ".json");
59008
59326
  }
59009
59327
  function getAuthIdentity(env3 = process.env) {
59010
59328
  return readIdentity(env3);
@@ -59418,7 +59736,7 @@ var init_remote_workspace_selection = __esm(() => {
59418
59736
  });
59419
59737
 
59420
59738
  // src/lib/remote-private-publications.ts
59421
- import { createHash as createHash18 } from "crypto";
59739
+ import { createHash as createHash19 } from "crypto";
59422
59740
  function checkedPublicationDeclaration(value) {
59423
59741
  if (!exact(value, ["idempotencyKey", "version", "expectedCurrentVersionId", "manifestText", "archiveSha256", "archiveByteSize"]) || !publicationUuid(value.idempotencyKey) || !(value.expectedCurrentVersionId === null || publicationUuid(value.expectedCurrentVersionId)) || typeof value.version !== "string" || !value.version || value.version.length > 128 || /[\p{Cc}\p{Cs}]/u.test(value.version) || typeof value.manifestText !== "string" || Buffer.byteLength(value.manifestText) > 16384 || !hash3(value.archiveSha256) || !Number.isSafeInteger(value.archiveByteSize) || Number(value.archiveByteSize) < 1 || Number(value.archiveByteSize) > PRIVATE_PUBLICATION_MAX_BYTES)
59424
59742
  return bad();
@@ -59679,7 +59997,7 @@ var PRIVATE_PUBLICATION_MAX_BYTES, failures, PrivatePublicationError, bad = () =
59679
59997
  throw new PrivatePublicationError("INVALID_PUBLICATION_INPUT", "Invalid publication input or recovery data.");
59680
59998
  }, invalid3 = () => {
59681
59999
  throw new PrivatePublicationError("INVALID_PUBLICATION_RESPONSE", "The server returned an invalid publication result.");
59682
- }, publicationUuid = (v) => typeof v === "string" && /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(v), hash3 = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v), record4 = (v) => !!v && typeof v === "object" && !Array.isArray(v), exact = (v, keys2) => record4(v) && Object.keys(v).sort().join(",") === keys2.sort().join(","), date = (v) => typeof v === "string" && /^\d{4}-\d\d-\d\dT[0-9:.]+(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/.test(v) && Number.isFinite(Date.parse(v)), publicationSha256 = (bytes) => createHash18("sha256").update(bytes).digest("hex");
60000
+ }, publicationUuid = (v) => typeof v === "string" && /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(v), hash3 = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v), record4 = (v) => !!v && typeof v === "object" && !Array.isArray(v), exact = (v, keys2) => record4(v) && Object.keys(v).sort().join(",") === keys2.sort().join(","), date = (v) => typeof v === "string" && /^\d{4}-\d\d-\d\dT[0-9:.]+(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/.test(v) && Number.isFinite(Date.parse(v)), publicationSha256 = (bytes) => createHash19("sha256").update(bytes).digest("hex");
59683
60001
  var init_remote_private_publications = __esm(() => {
59684
60002
  init_fleet_credentials();
59685
60003
  init_remote_workspace_selection();
@@ -63218,15 +63536,15 @@ var init_schemas = __esm(() => {
63218
63536
  } catch (_err) {}
63219
63537
  }
63220
63538
  const input = payload.value;
63221
- const isDate2 = input instanceof Date;
63222
- const isValidDate = isDate2 && !Number.isNaN(input.getTime());
63539
+ const isDate3 = input instanceof Date;
63540
+ const isValidDate = isDate3 && !Number.isNaN(input.getTime());
63223
63541
  if (isValidDate)
63224
63542
  return payload;
63225
63543
  payload.issues.push({
63226
63544
  expected: "date",
63227
63545
  code: "invalid_type",
63228
63546
  input,
63229
- ...isDate2 ? { received: "Invalid Date" } : {},
63547
+ ...isDate3 ? { received: "Invalid Date" } : {},
63230
63548
  inst
63231
63549
  });
63232
63550
  return payload;
@@ -79068,7 +79386,7 @@ var init_v4 = __esm(() => {
79068
79386
  });
79069
79387
 
79070
79388
  // src/lib/canonical-json.ts
79071
- import { createHash as createHash19 } from "crypto";
79389
+ import { createHash as createHash20 } from "crypto";
79072
79390
  function canonicalJson2(value, maximumBytes = 2 * 1024 * 1024) {
79073
79391
  return canonicalJsonAtDepth(value, maximumBytes, 64);
79074
79392
  }
@@ -79112,7 +79430,7 @@ function canonicalJsonAtDepth(value, maximumBytes, maximumDepth) {
79112
79430
  return visit3(value, 0);
79113
79431
  }
79114
79432
  function canonicalJsonSha256(value, maximumBytes) {
79115
- return createHash19("sha256").update(canonicalJson2(value, maximumBytes)).digest("hex");
79433
+ return createHash20("sha256").update(canonicalJson2(value, maximumBytes)).digest("hex");
79116
79434
  }
79117
79435
  var init_canonical_json = () => {};
79118
79436
 
@@ -79447,7 +79765,7 @@ var init_remote_recurring = __esm(() => {
79447
79765
 
79448
79766
  // src/lib/remote-run-contract.ts
79449
79767
  function normalizeRemoteSkillRunContract(payload, fallbackSkill) {
79450
- const record8 = isRecord3(payload) ? payload : {};
79768
+ const record8 = isRecord4(payload) ? payload : {};
79451
79769
  return {
79452
79770
  contractVersion: REMOTE_SKILL_RUN_CONTRACT_VERSION,
79453
79771
  ...pickString(record8, "id"),
@@ -79469,7 +79787,7 @@ function normalizeRemoteSkillRunContract(payload, fallbackSkill) {
79469
79787
  ...hasOwn(record8, "details") ? { details: record8.details } : {}
79470
79788
  };
79471
79789
  }
79472
- function isRecord3(value) {
79790
+ function isRecord4(value) {
79473
79791
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
79474
79792
  }
79475
79793
  function hasOwn(record8, key) {
@@ -79608,7 +79926,7 @@ var init_remote_credit_checkout = __esm(() => {
79608
79926
 
79609
79927
  // src/lib/remote-profile.ts
79610
79928
  function customerNamePatch(input2, field2) {
79611
- if (!isRecord4(input2) || Object.keys(input2).length !== 1 || !Object.hasOwn(input2, field2))
79929
+ if (!isRecord5(input2) || Object.keys(input2).length !== 1 || !Object.hasOwn(input2, field2))
79612
79930
  throw new Error("Provide only the requested name field.");
79613
79931
  const value = input2[field2];
79614
79932
  if (typeof value !== "string" || /[\p{Cc}\p{Cs}\u2028\u2029]/u.test(value) || !value.trim() || [...value.trim()].length > 100) {
@@ -79616,22 +79934,22 @@ function customerNamePatch(input2, field2) {
79616
79934
  }
79617
79935
  return { [field2]: value.trim() };
79618
79936
  }
79619
- function isRecord4(value) {
79937
+ function isRecord5(value) {
79620
79938
  return !!value && typeof value === "object" && !Array.isArray(value);
79621
79939
  }
79622
79940
  function string4(value) {
79623
79941
  return typeof value === "string" && value.length > 0;
79624
79942
  }
79625
79943
  function parseUpdatedProfile(value) {
79626
- const user = isRecord4(value) && value.user;
79627
- if (!isRecord4(user) || !string4(user.id) || !string4(user.email) || !(user.displayName === null || typeof user.displayName === "string") || typeof user.role !== "string" || !["owner", "admin", "member", "viewer"].includes(user.role)) {
79944
+ const user = isRecord5(value) && value.user;
79945
+ if (!isRecord5(user) || !string4(user.id) || !string4(user.email) || !(user.displayName === null || typeof user.displayName === "string") || typeof user.role !== "string" || !["owner", "admin", "member", "viewer"].includes(user.role)) {
79628
79946
  throw new Error("The server returned an invalid account profile.");
79629
79947
  }
79630
79948
  return { user: { id: user.id, email: user.email, displayName: user.displayName, role: user.role } };
79631
79949
  }
79632
79950
  function parseUpdatedWorkspace(value) {
79633
- const organization2 = isRecord4(value) && value.organization;
79634
- if (!isRecord4(organization2) || !string4(organization2.id) || !string4(organization2.slug) || !string4(organization2.name)) {
79951
+ const organization2 = isRecord5(value) && value.organization;
79952
+ if (!isRecord5(organization2) || !string4(organization2.id) || !string4(organization2.slug) || !string4(organization2.name)) {
79635
79953
  throw new Error("The server returned an invalid workspace.");
79636
79954
  }
79637
79955
  return { organization: { id: organization2.id, slug: organization2.slug, name: organization2.name } };
@@ -80813,7 +81131,7 @@ async function requestAuthApi(instance, path, options) {
80813
81131
  const text4 = await res.text();
80814
81132
  const body = text4 ? parseJsonBody(text4) : {};
80815
81133
  if (!res.ok) {
80816
- const record9 = isRecord5(body) ? body : {};
81134
+ const record9 = isRecord6(body) ? body : {};
80817
81135
  const detail = typeof record9.detail === "string" ? record9.detail : undefined;
80818
81136
  const error61 = typeof record9.error === "string" ? record9.error : undefined;
80819
81137
  const code = typeof record9.code === "string" ? record9.code : undefined;
@@ -80841,7 +81159,7 @@ function condenseErrorBody(text4) {
80841
81159
  return collapsed;
80842
81160
  return `${collapsed.slice(0, MAX_ERROR_DETAIL_LENGTH - 1).trimEnd()}\u2026`;
80843
81161
  }
80844
- function isRecord5(value) {
81162
+ function isRecord6(value) {
80845
81163
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
80846
81164
  }
80847
81165
 
@@ -81026,10 +81344,10 @@ var init_remote_auth = __esm(() => {
81026
81344
  });
81027
81345
 
81028
81346
  // src/lib/sign-in.ts
81029
- import { createHash as createHash20 } from "crypto";
81347
+ import { createHash as createHash21 } from "crypto";
81030
81348
  import { chmodSync as chmodSync3, mkdirSync as mkdirSync12, readFileSync as readFileSync21, readdirSync as readdirSync14, renameSync as renameSync8, unlinkSync as unlinkSync6, writeFileSync as writeFileSync11 } from "fs";
81031
- import { basename as basename12, dirname as dirname21, join as join37 } from "path";
81032
- function isRecord6(value) {
81349
+ import { basename as basename13, dirname as dirname21, join as join37 } from "path";
81350
+ function isRecord7(value) {
81033
81351
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
81034
81352
  }
81035
81353
  function boundedText(value, max2 = 2048) {
@@ -81054,7 +81372,7 @@ function clampIntervalMs(seconds) {
81054
81372
  return Math.min(MAX_INTERVAL_MS, Math.max(MIN_INTERVAL_MS, Math.round(seconds * 1000)));
81055
81373
  }
81056
81374
  function parseDeviceAuthorizationStart(body) {
81057
- const record9 = isRecord6(body) ? body : {};
81375
+ const record9 = isRecord7(body) ? body : {};
81058
81376
  if (typeof record9.error === "string") {
81059
81377
  throw new Error(typeof record9.detail === "string" ? record9.detail : record9.error);
81060
81378
  }
@@ -81088,7 +81406,7 @@ function pollDeviceToken(origin, deviceCode) {
81088
81406
  });
81089
81407
  }
81090
81408
  function deviceErrorCode(error61) {
81091
- if (!(error61 instanceof HostedApiError) && !(isRecord6(error61) && error61.name === "HostedApiError"))
81409
+ if (!(error61 instanceof HostedApiError) && !(isRecord7(error61) && error61.name === "HostedApiError"))
81092
81410
  return;
81093
81411
  const failure = error61;
81094
81412
  const named = [failure.code, failure.detail, failure.message].find((value) => value === "slow_down" || value === "authorization_pending" || value === "expired_token" || value === "invalid_device_code" || value === "access_denied");
@@ -81149,7 +81467,7 @@ async function pollDeviceAuthorization(input2) {
81149
81467
  throw error61;
81150
81468
  }
81151
81469
  }
81152
- const record9 = isRecord6(body) ? body : {};
81470
+ const record9 = isRecord7(body) ? body : {};
81153
81471
  const code = typeof record9.error === "string" ? record9.error : undefined;
81154
81472
  if (code === "authorization_pending" || code === undefined && record9.status === "pending") {
81155
81473
  await wait();
@@ -81173,11 +81491,11 @@ async function pollDeviceAuthorization(input2) {
81173
81491
  }
81174
81492
  function pendingDeviceSignInStem(env3) {
81175
81493
  const file2 = skillsCredentialFilePath(env3);
81176
- return { dir: dirname21(file2), stem: basename12(file2).replace(/^credentials/, "device-login") };
81494
+ return { dir: dirname21(file2), stem: basename13(file2).replace(/^credentials/, "device-login") };
81177
81495
  }
81178
81496
  function pendingDeviceSignInPath(origin, env3 = process.env) {
81179
81497
  const { dir, stem } = pendingDeviceSignInStem(env3);
81180
- return join37(dir, `${stem}-${createHash20("sha256").update(origin).digest("hex").slice(0, 16)}.json`);
81498
+ return join37(dir, `${stem}-${createHash21("sha256").update(origin).digest("hex").slice(0, 16)}.json`);
81181
81499
  }
81182
81500
  function savePendingDeviceSignIn(origin, start, env3 = process.env, now3 = Date.now()) {
81183
81501
  const path = pendingDeviceSignInPath(origin, env3);
@@ -81207,7 +81525,7 @@ function loadPendingDeviceSignIn(origin, env3 = process.env, now3 = Date.now())
81207
81525
  } catch {
81208
81526
  return null;
81209
81527
  }
81210
- if (!isRecord6(parsed))
81528
+ if (!isRecord7(parsed))
81211
81529
  return null;
81212
81530
  const deviceCode = boundedText(parsed.deviceCode, 512);
81213
81531
  const userCode = boundedText(parsed.userCode, 64);
@@ -81249,7 +81567,7 @@ function pendingDeviceSignInOrigins(env3 = process.env, now3 = Date.now()) {
81249
81567
  continue;
81250
81568
  try {
81251
81569
  const parsed = JSON.parse(readFileSync21(join37(location.dir, entry), "utf8"));
81252
- if (isRecord6(parsed) && typeof parsed.origin === "string" && Number(parsed.expiresAt) > now3 && pendingDeviceSignInPath(parsed.origin, env3) === join37(location.dir, entry))
81570
+ if (isRecord7(parsed) && typeof parsed.origin === "string" && Number(parsed.expiresAt) > now3 && pendingDeviceSignInPath(parsed.origin, env3) === join37(location.dir, entry))
81253
81571
  origins.push(parsed.origin);
81254
81572
  } catch {}
81255
81573
  }
@@ -81291,7 +81609,7 @@ async function persistSignIn(result2, origin, env3 = process.env, issuedBy = "si
81291
81609
  headers: { Authorization: `Bearer ${result2.token}` },
81292
81610
  body: JSON.stringify({ name: "cli" })
81293
81611
  });
81294
- apiKey = isRecord6(created) && typeof created.key === "string" && created.key.trim() ? created.key : undefined;
81612
+ apiKey = isRecord7(created) && typeof created.key === "string" && created.key.trim() ? created.key : undefined;
81295
81613
  }
81296
81614
  if (!apiKey)
81297
81615
  throw new Error("Sign-in succeeded but the server returned no API key");
@@ -81330,7 +81648,7 @@ async function revokeStoredKey(origin, apiKey) {
81330
81648
  }
81331
81649
  return { outcome: "failed", detail: "the server could not be reached" };
81332
81650
  }
81333
- if (isRecord6(body) && body.revoked === true)
81651
+ if (isRecord7(body) && body.revoked === true)
81334
81652
  return { outcome: "revoked" };
81335
81653
  return { outcome: "not_revoked", detail: "the server answered without confirming revocation" };
81336
81654
  }
@@ -81454,10 +81772,10 @@ async function readSignedInAccount(env3 = process.env) {
81454
81772
  const body = await new RemoteSkillsAuthClient(connection.apiOrigin).request("/api/auth/whoami", {
81455
81773
  headers: { Authorization: `Bearer ${connection.apiKey}` }
81456
81774
  });
81457
- const record9 = isRecord6(body) ? body : {};
81458
- const data = isRecord6(record9.data) ? record9.data : {};
81459
- const user = isRecord6(record9.user) ? record9.user : isRecord6(data.user) ? data.user : {};
81460
- const organization2 = isRecord6(record9.organization) ? record9.organization : isRecord6(data.organization) ? data.organization : {};
81775
+ const record9 = isRecord7(body) ? body : {};
81776
+ const data = isRecord7(record9.data) ? record9.data : {};
81777
+ const user = isRecord7(record9.user) ? record9.user : isRecord7(data.user) ? data.user : {};
81778
+ const organization2 = isRecord7(record9.organization) ? record9.organization : isRecord7(data.organization) ? data.organization : {};
81461
81779
  const email4 = boundedText(user.email, 320);
81462
81780
  const org = boundedText(organization2.slug, 200) ?? boundedText(organization2.name, 200);
81463
81781
  return { ...base2, ...email4 ? { email: email4 } : {}, ...org ? { organization: org } : {} };
@@ -81872,7 +82190,7 @@ function optionPrefix(program2, args) {
81872
82190
  }
81873
82191
 
81874
82192
  // src/lib/revision.ts
81875
- import { createHash as createHash21 } from "crypto";
82193
+ import { createHash as createHash22 } from "crypto";
81876
82194
  function revisionIdOf(content) {
81877
82195
  const canonicalContent = {
81878
82196
  slug: content.slug,
@@ -81892,8 +82210,8 @@ function revisionIdOf(content) {
81892
82210
  canonicalContent.archiveReason = content.archiveReason ?? null;
81893
82211
  canonicalContent.replacementSlug = content.replacementSlug ?? null;
81894
82212
  }
81895
- const canonical5 = JSON.stringify(canonicalContent);
81896
- return createHash21("sha256").update(canonical5).digest("hex");
82213
+ const canonical6 = JSON.stringify(canonicalContent);
82214
+ return createHash22("sha256").update(canonical6).digest("hex");
81897
82215
  }
81898
82216
  var REVISION_ID_PATTERN;
81899
82217
  var init_revision = __esm(() => {
@@ -82342,7 +82660,7 @@ var init_pull = __esm(() => {
82342
82660
  });
82343
82661
 
82344
82662
  // src/lib/skill-context.ts
82345
- import { createHash as createHash22 } from "crypto";
82663
+ import { createHash as createHash23 } from "crypto";
82346
82664
  import { resolve as resolve19 } from "path";
82347
82665
  function words2(value) {
82348
82666
  return new Set(value.toLowerCase().match(/[a-z0-9]+/g) ?? []);
@@ -82358,9 +82676,9 @@ async function buildSkillContext(input2, options = {}) {
82358
82676
  if (prompt.length > 128 * 1024 || (input2.paths?.length ?? 0) > 100 || (input2.skills?.length ?? 0) > 100) {
82359
82677
  throw new SkillSelectionError("CONTEXT_INPUT_TOO_LARGE", "The Skills context input exceeds its size limit.");
82360
82678
  }
82361
- const maxChars = options.maxChars ?? 8000;
82679
+ const maxChars = options.maxChars;
82362
82680
  const maxSkills = options.maxSkills ?? 3;
82363
- if (!Number.isInteger(maxChars) || maxChars < 512 || maxChars > 64000 || !Number.isInteger(maxSkills) || maxSkills < 1 || maxSkills > 20) {
82681
+ if (maxChars !== undefined && (!Number.isInteger(maxChars) || maxChars < 512 || maxChars > 64000) || !Number.isInteger(maxSkills) || maxSkills < 1 || maxSkills > 20) {
82364
82682
  throw new SkillSelectionError("INVALID_CONTEXT_BUDGET", "Context limits must be 512\u201364000 characters and 1\u201320 skills.");
82365
82683
  }
82366
82684
  const profileId = input2.profileId ?? "default";
@@ -82417,7 +82735,7 @@ async function buildSkillContext(input2, options = {}) {
82417
82735
  const { content } = readSelectedDocument(entries);
82418
82736
  const section = `Skill ${selection.slug}@${selection.version} (${selection.bundleDigest}; ${reason})
82419
82737
  ${content}`;
82420
- if (chars + section.length + (sections.length ? 2 : 0) > maxChars) {
82738
+ if (maxChars !== undefined && chars + section.length + (sections.length ? 2 : 0) > maxChars) {
82421
82739
  omitted.push({ slug: selection.slug, version: selection.version, reason: "context-budget", loadCommand });
82422
82740
  continue;
82423
82741
  }
@@ -82431,7 +82749,7 @@ ${content}`;
82431
82749
  `);
82432
82750
  const receipt = {
82433
82751
  schemaVersion: 1,
82434
- id: createHash22("sha256").update(JSON.stringify({ profile: profile.profileRevision, sessionId, selections, omitted })).digest("hex"),
82752
+ id: createHash23("sha256").update(JSON.stringify({ profile: profile.profileRevision, sessionId, selections, omitted })).digest("hex"),
82435
82753
  profileId: profile.profileId,
82436
82754
  profileRevision: profile.profileRevision,
82437
82755
  authority: profile.authority,
@@ -82453,8 +82771,8 @@ var init_skill_context = __esm(() => {
82453
82771
  });
82454
82772
 
82455
82773
  // src/lib/session-reconciliation.ts
82456
- import { createHash as createHash23 } from "crypto";
82457
- import { isDeepStrictEqual as isDeepStrictEqual8 } from "util";
82774
+ import { createHash as createHash24 } from "crypto";
82775
+ import { isDeepStrictEqual as isDeepStrictEqual9 } from "util";
82458
82776
  function exactTimestamp(value) {
82459
82777
  const parsed = value === undefined ? Number.NaN : Date.parse(value);
82460
82778
  if (!Number.isFinite(parsed) || new Date(parsed).toISOString() !== value) {
@@ -82511,7 +82829,7 @@ async function reconcileSkillSessionIfSafe(sessionId, profileId, options = {}) {
82511
82829
  for (const key of old.loaded) {
82512
82830
  const previous = oldByKey.get(key);
82513
82831
  const current = targetBySlug.get(previous.slug);
82514
- if (!current || !isDeepStrictEqual8({ ...previous, profileRevision: target.profileRevision }, current)) {
82832
+ if (!current || !isDeepStrictEqual9({ ...previous, profileRevision: target.profileRevision }, current)) {
82515
82833
  throw new SkillSelectionError("SESSION_RECONCILIATION_REQUIRED", "A loaded Skills selection was removed or changed; review skills sessions reconcile before changing this session's pin.");
82516
82834
  }
82517
82835
  }
@@ -82593,7 +82911,7 @@ async function reconcileSkillSession(input2, options = {}) {
82593
82911
  const result2 = replaceSkillSession(skillSessionSnapshotBinding(snapshot2), replacement, { ...plan, planDigest }, options, () => assertPlanWindow(issuedAt, expiresAt, (options.now ?? Date.now)()));
82594
82912
  return { applied: true, plan, planDigest, ...result2 };
82595
82913
  }
82596
- var SESSION_RECONCILIATION_PLAN_TTL_MS, digest3 = (value) => createHash23("sha256").update(JSON.stringify(value)).digest("hex");
82914
+ var SESSION_RECONCILIATION_PLAN_TTL_MS, digest3 = (value) => createHash24("sha256").update(JSON.stringify(value)).digest("hex");
82597
82915
  var init_session_reconciliation = __esm(() => {
82598
82916
  init_profile_client();
82599
82917
  init_selection_cache();
@@ -82673,7 +82991,7 @@ Preserved original receipt: ${result2.archivePath}` : `Planned one session recon
82673
82991
  reportContextError(error61, options.json);
82674
82992
  }
82675
82993
  });
82676
- parent.command("context [prompt]").description("Select bounded, versioned skill context for this prompt without running skills").option("--stdin", "Read native hook JSON or a prompt from stdin", false).option("--selection-profile <id>", "Selection profile (separate from the credential --profile)").option("--cached", "Use only an explicitly selected verified cache, at most 24 hours old", false).option("--auto-reconcile-safe", "For managed hooks, archive and renew an expired session only when all loaded selections are unchanged", false).option("--session <id>", "Keep the same skill versions across this session").option("--restore", "Re-emit loaded session context after compaction or resume", false).option("--max-chars <count>", "Maximum injected characters", "8000").option("--max-skills <count>", "Maximum loaded skills", "3").option("--json", "Return context and selection receipts as JSON", false).action(async (prompt, options) => {
82994
+ parent.command("context [prompt]").description("Select bounded, versioned skill context for this prompt without running skills").option("--stdin", "Read native hook JSON or a prompt from stdin", false).option("--selection-profile <id>", "Selection profile (separate from the credential --profile)").option("--cached", "Use only an explicitly selected verified cache, at most 24 hours old", false).option("--auto-reconcile-safe", "For managed hooks, archive and renew an expired session only when all loaded selections are unchanged", false).option("--session <id>", "Keep the same skill versions across this session").option("--restore", "Re-emit loaded session context after compaction or resume", false).option("--max-chars <count>", "Optional maximum injected characters").option("--max-skills <count>", "Maximum loaded skills", "3").option("--json", "Return context and selection receipts as JSON", false).action(async (prompt, options) => {
82677
82995
  try {
82678
82996
  if (options.autoReconcileSafe && !options.cached)
82679
82997
  throw new SkillSelectionError("INVALID_CONTEXT_INPUT", "--auto-reconcile-safe requires --cached.");
@@ -82682,7 +83000,7 @@ Preserved original receipt: ${result2.archivePath}` : `Planned one session recon
82682
83000
  input2.cwd ??= process.cwd();
82683
83001
  input2.sessionId = options.session ?? input2.sessionId;
82684
83002
  input2.restore ||= options.restore;
82685
- const resolverOptions = { ...contextResolverOptions(options), maxChars: Number(options.maxChars), maxSkills: Number(options.maxSkills) };
83003
+ const resolverOptions = { ...contextResolverOptions(options), ...options.maxChars === undefined ? {} : { maxChars: Number(options.maxChars) }, maxSkills: Number(options.maxSkills) };
82686
83004
  let result2;
82687
83005
  try {
82688
83006
  result2 = await buildSkillContext(input2, resolverOptions);
@@ -83729,7 +84047,7 @@ function handleDiff(name, options) {
83729
84047
  const sourcePath = getSkillPath(bare);
83730
84048
  const canonicalDir = join39(resolveCorpusRoot(), normalized);
83731
84049
  const canonicalSkillMd = join39(canonicalDir, "SKILL.md");
83732
- const canonical5 = {
84050
+ const canonical6 = {
83733
84051
  present: existsSync22(canonicalSkillMd),
83734
84052
  path: canonicalDir,
83735
84053
  ...existsSync22(canonicalSkillMd) ? { hash: hashSkillMarkdownFile(canonicalSkillMd) } : {},
@@ -83761,7 +84079,7 @@ function handleDiff(name, options) {
83761
84079
  stub = undefined;
83762
84080
  }
83763
84081
  }
83764
- const diverged = present && canonical5.present && managed && hash5 !== canonical5.hash;
84082
+ const diverged = present && canonical6.present && managed && hash5 !== canonical6.hash;
83765
84083
  homes.push({
83766
84084
  agent,
83767
84085
  path: dir,
@@ -83776,7 +84094,7 @@ function handleDiff(name, options) {
83776
84094
  if (options.json) {
83777
84095
  console.log(JSON.stringify({
83778
84096
  name: bare,
83779
- canonical: canonical5,
84097
+ canonical: canonical6,
83780
84098
  pinned,
83781
84099
  installedVersion,
83782
84100
  registryVersion,
@@ -83784,10 +84102,10 @@ function handleDiff(name, options) {
83784
84102
  homes
83785
84103
  }, null, 2));
83786
84104
  } else {
83787
- if (!canonical5.present) {
84105
+ if (!canonical6.present) {
83788
84106
  console.log(source_default.yellow(`${bare}: no canonical corpus entry`));
83789
84107
  } else {
83790
- console.log(source_default.dim(`${bare} canonical: ${canonical5.hash?.slice(0, 12)}\u2026`));
84108
+ console.log(source_default.dim(`${bare} canonical: ${canonical6.hash?.slice(0, 12)}\u2026`));
83791
84109
  }
83792
84110
  if (pinned) {
83793
84111
  console.log(upToDate ? source_default.green(`\u2713 pin is up to date (${installedVersion})`) : source_default.yellow(`pin metadata differs: ${installedVersion} \u2192 ${registryVersion}`));
@@ -83798,14 +84116,14 @@ function handleDiff(name, options) {
83798
84116
  } else if (!home.managed) {
83799
84117
  console.log(`${source_default.dim("\u2022")} ${home.agent}: ${source_default.yellow("unmarked (adoption candidate)")}`);
83800
84118
  } else if (home.diverged) {
83801
- const stubNote = home.stub === true ? " (home is a pointer stub; canonical holds content)" : canonical5.stub === true ? " (home holds content; canonical renders a pointer stub \u2014 sync refuses to replace it)" : "";
83802
- console.log(`${source_default.red("\u2717")} ${home.agent}: ${source_default.red("diverged")} ${source_default.dim(home.hash?.slice(0, 12))} \u2260 ${source_default.dim(canonical5.hash?.slice(0, 12))}${stubNote}`);
84119
+ const stubNote = home.stub === true ? " (home is a pointer stub; canonical holds content)" : canonical6.stub === true ? " (home holds content; canonical renders a pointer stub \u2014 sync refuses to replace it)" : "";
84120
+ console.log(`${source_default.red("\u2717")} ${home.agent}: ${source_default.red("diverged")} ${source_default.dim(home.hash?.slice(0, 12))} \u2260 ${source_default.dim(canonical6.hash?.slice(0, 12))}${stubNote}`);
83803
84121
  } else {
83804
84122
  console.log(`${source_default.green("\u2713")} ${home.agent}: ${source_default.green("matches canonical")}`);
83805
84123
  }
83806
84124
  }
83807
84125
  }
83808
- if (divergedHomes.length > 0 || homes.length > 0 && !canonical5.present)
84126
+ if (divergedHomes.length > 0 || homes.length > 0 && !canonical6.present)
83809
84127
  process.exitCode = 1;
83810
84128
  }
83811
84129
  var init_introspect = __esm(() => {
@@ -87111,7 +87429,7 @@ var init_execution_grants = __esm(() => {
87111
87429
  });
87112
87430
 
87113
87431
  // src/lib/execution-grant-client.ts
87114
- import { isDeepStrictEqual as isDeepStrictEqual9 } from "util";
87432
+ import { isDeepStrictEqual as isDeepStrictEqual10 } from "util";
87115
87433
  function id(value) {
87116
87434
  if (!grantIdentifier(value))
87117
87435
  throw new Error("Invalid execution grant profile or revision identifier.");
@@ -87163,7 +87481,7 @@ async function saveExecutionGrantPolicy(profileId, grants, revision) {
87163
87481
  headers: revision === undefined ? { "If-None-Match": "*" } : { "If-Match": `"${revision}"` },
87164
87482
  body: JSON.stringify({ grants: snapshot2 })
87165
87483
  }));
87166
- if (policy.profileId !== profileId || policy.previousRevision !== (revision ?? null) || !isDeepStrictEqual9(policy.grants, snapshot2)) {
87484
+ if (policy.profileId !== profileId || policy.previousRevision !== (revision ?? null) || !isDeepStrictEqual10(policy.grants, snapshot2)) {
87167
87485
  throw new Error("The API did not preserve the reviewed execution grant policy; read it before retrying.");
87168
87486
  }
87169
87487
  return policy;
@@ -87174,7 +87492,7 @@ async function resolveExecutionGrant(input2) {
87174
87492
  if (!grantRecord(value) || Object.keys(value).length !== 3 || !grantIdentifier(value.policyRevision) || !grantIdentifier(value.grantId) || !grantRecord(value.bindings)) {
87175
87493
  throw new SkillSelectionError("INVALID_EXECUTION_GRANT", "The Skills API returned an invalid execution grant.");
87176
87494
  }
87177
- if (!isDeepStrictEqual9(value.bindings.selection, snapshot2.selection) || !isDeepStrictEqual9(value.bindings.consumer, snapshot2.consumer)) {
87495
+ if (!isDeepStrictEqual10(value.bindings.selection, snapshot2.selection) || !isDeepStrictEqual10(value.bindings.consumer, snapshot2.consumer)) {
87178
87496
  throw new SkillSelectionError("EXECUTION_GRANT_SCOPE_MISMATCH", "The Skills API returned a grant for a different selection or consumer.");
87179
87497
  }
87180
87498
  return value;
@@ -87193,7 +87511,7 @@ __export(exports_selected_run, {
87193
87511
  prepareSelectedSecretBindings: () => prepareSelectedSecretBindings,
87194
87512
  executeSelectedLocal: () => executeSelectedLocal
87195
87513
  });
87196
- import { createHash as createHash24 } from "crypto";
87514
+ import { createHash as createHash25 } from "crypto";
87197
87515
  import { spawn as spawn3 } from "child_process";
87198
87516
  import { mkdirSync as mkdirSync15, mkdtempSync as mkdtempSync4, writeFileSync as writeFileSync15, realpathSync as realpathSync11 } from "fs";
87199
87517
  import { dirname as dirname23, join as join45, resolve as resolve20 } from "path";
@@ -87319,7 +87637,7 @@ async function executeSelectedLocal(selected, options = {}) {
87319
87637
  selection: selection2,
87320
87638
  target: "local",
87321
87639
  runtime: runtimeName,
87322
- inputDigest: `sha256:${createHash24("sha256").update(input2).digest("hex")}`,
87640
+ inputDigest: `sha256:${createHash25("sha256").update(input2).digest("hex")}`,
87323
87641
  runDirectory,
87324
87642
  ...executionGrant ? { executionGrant } : {},
87325
87643
  ...bindings ? { secretBinding: { schema: bindings.schema, selection: bindings.selection, consumer: bindings.consumer, secretsAuthority: bindings.secretsAuthority, bindings: bindings.bindings } } : {},
@@ -91536,9 +91854,9 @@ var init_runs = __esm(() => {
91536
91854
  });
91537
91855
 
91538
91856
  // src/lib/run-state.ts
91539
- import { createHash as createHash25, randomBytes } from "crypto";
91857
+ import { createHash as createHash26, randomBytes } from "crypto";
91540
91858
  import { existsSync as existsSync27, mkdirSync as mkdirSync16, readFileSync as readFileSync32, readdirSync as readdirSync18, statSync as statSync16, writeFileSync as writeFileSync16 } from "fs";
91541
- import { extname, join as join46, relative as relative6 } from "path";
91859
+ import { extname, join as join46, relative as relative7 } from "path";
91542
91860
  function createSkillRun(params, targetDir = process.cwd()) {
91543
91861
  const now3 = new Date;
91544
91862
  const id2 = createRunId(now3);
@@ -91673,7 +91991,7 @@ function collectRunArtifacts(context) {
91673
91991
  artifacts.push({
91674
91992
  path: toProjectRelative(context.targetDir, path),
91675
91993
  mime: mimeForPath(path),
91676
- sha256: createHash25("sha256").update(bytes).digest("hex"),
91994
+ sha256: createHash26("sha256").update(bytes).digest("hex"),
91677
91995
  sizeBytes: stat2.size
91678
91996
  });
91679
91997
  }
@@ -91704,7 +92022,7 @@ function createRunId(now3) {
91704
92022
  return `run_${now3.getTime().toString(36)}_${randomBytes(4).toString("hex")}`;
91705
92023
  }
91706
92024
  function toProjectRelative(targetDir, path) {
91707
- const rel = relative6(targetDir, path).split(/[\\/]/).join("/");
92025
+ const rel = relative7(targetDir, path).split(/[\\/]/).join("/");
91708
92026
  return rel.startsWith(".") ? rel : `./${rel}`;
91709
92027
  }
91710
92028
  function mimeForPath(path) {
@@ -97399,8 +97717,8 @@ var require_resolve = __commonJS((exports) => {
97399
97717
  }
97400
97718
  return count;
97401
97719
  }
97402
- function getFullPath(resolver, id2 = "", normalize4) {
97403
- if (normalize4 !== false)
97720
+ function getFullPath(resolver, id2 = "", normalize5) {
97721
+ if (normalize5 !== false)
97404
97722
  id2 = normalizeId(id2);
97405
97723
  const p = resolver.parse(id2);
97406
97724
  return _getFullPath(resolver, p);
@@ -98959,7 +99277,7 @@ var require_fast_uri = __commonJS((exports, module) => {
98959
99277
  }
98960
99278
  return decodedScheme;
98961
99279
  }
98962
- function normalize4(uri, options) {
99280
+ function normalize5(uri, options) {
98963
99281
  if (typeof uri === "string") {
98964
99282
  uri = normalizeString(uri, options);
98965
99283
  } else if (typeof uri === "object") {
@@ -99000,49 +99318,49 @@ var require_fast_uri = __commonJS((exports, module) => {
99000
99318
  schemelessOptions.skipEscape = true;
99001
99319
  return serialize(resolved, schemelessOptions);
99002
99320
  }
99003
- function resolveComponent(base2, relative7, options, skipNormalization) {
99321
+ function resolveComponent(base2, relative8, options, skipNormalization) {
99004
99322
  const target = {};
99005
99323
  if (!skipNormalization) {
99006
99324
  base2 = parse12(serialize(base2, options), options);
99007
- relative7 = parse12(serialize(relative7, options), options);
99325
+ relative8 = parse12(serialize(relative8, options), options);
99008
99326
  }
99009
99327
  options = options || {};
99010
- if (!options.tolerant && relative7.scheme) {
99011
- target.scheme = relative7.scheme;
99012
- target.userinfo = relative7.userinfo;
99013
- target.host = relative7.host;
99014
- target.port = relative7.port;
99015
- target.path = removeDotSegments(relative7.path || "");
99016
- target.query = relative7.query;
99328
+ if (!options.tolerant && relative8.scheme) {
99329
+ target.scheme = relative8.scheme;
99330
+ target.userinfo = relative8.userinfo;
99331
+ target.host = relative8.host;
99332
+ target.port = relative8.port;
99333
+ target.path = removeDotSegments(relative8.path || "");
99334
+ target.query = relative8.query;
99017
99335
  } else {
99018
- if (relative7.userinfo !== undefined || relative7.host !== undefined || relative7.port !== undefined) {
99019
- target.userinfo = relative7.userinfo;
99020
- target.host = relative7.host;
99021
- target.port = relative7.port;
99022
- target.path = removeDotSegments(relative7.path || "");
99023
- target.query = relative7.query;
99336
+ if (relative8.userinfo !== undefined || relative8.host !== undefined || relative8.port !== undefined) {
99337
+ target.userinfo = relative8.userinfo;
99338
+ target.host = relative8.host;
99339
+ target.port = relative8.port;
99340
+ target.path = removeDotSegments(relative8.path || "");
99341
+ target.query = relative8.query;
99024
99342
  } else {
99025
- if (!relative7.path) {
99343
+ if (!relative8.path) {
99026
99344
  target.path = base2.path;
99027
- if (relative7.query !== undefined) {
99028
- target.query = relative7.query;
99345
+ if (relative8.query !== undefined) {
99346
+ target.query = relative8.query;
99029
99347
  } else {
99030
99348
  target.query = base2.query;
99031
99349
  }
99032
99350
  } else {
99033
- if (relative7.path[0] === "/") {
99034
- target.path = removeDotSegments(relative7.path);
99351
+ if (relative8.path[0] === "/") {
99352
+ target.path = removeDotSegments(relative8.path);
99035
99353
  } else {
99036
99354
  if ((base2.userinfo !== undefined || base2.host !== undefined || base2.port !== undefined) && !base2.path) {
99037
- target.path = "/" + relative7.path;
99355
+ target.path = "/" + relative8.path;
99038
99356
  } else if (!base2.path) {
99039
- target.path = relative7.path;
99357
+ target.path = relative8.path;
99040
99358
  } else {
99041
- target.path = base2.path.slice(0, base2.path.lastIndexOf("/") + 1) + relative7.path;
99359
+ target.path = base2.path.slice(0, base2.path.lastIndexOf("/") + 1) + relative8.path;
99042
99360
  }
99043
99361
  target.path = removeDotSegments(target.path);
99044
99362
  }
99045
- target.query = relative7.query;
99363
+ target.query = relative8.query;
99046
99364
  }
99047
99365
  target.userinfo = base2.userinfo;
99048
99366
  target.host = base2.host;
@@ -99050,7 +99368,7 @@ var require_fast_uri = __commonJS((exports, module) => {
99050
99368
  }
99051
99369
  target.scheme = base2.scheme;
99052
99370
  }
99053
- target.fragment = relative7.fragment;
99371
+ target.fragment = relative8.fragment;
99054
99372
  return target;
99055
99373
  }
99056
99374
  function equal(uriA, uriB, options) {
@@ -99336,7 +99654,7 @@ var require_fast_uri = __commonJS((exports, module) => {
99336
99654
  }
99337
99655
  var fastUri = {
99338
99656
  SCHEMES,
99339
- normalize: normalize4,
99657
+ normalize: normalize5,
99340
99658
  resolve: resolve21,
99341
99659
  resolveComponent,
99342
99660
  equal,
@@ -104346,7 +104664,7 @@ async function continueRecurringRecovery(customer, directory, options) {
104346
104664
  throw error61;
104347
104665
  }
104348
104666
  }
104349
- var uuid11, sha4, common2, intentSchema, stateSchema, invalid6 = () => {
104667
+ var uuid11, sha5, common2, intentSchema, stateSchema, invalid6 = () => {
104350
104668
  throw new RecurringCustomerError("RECURRING_RECOVERY_INVALID", "The original recovery directory or record is invalid or changed. Preserve it; do not create a replacement activation automatically.");
104351
104669
  };
104352
104670
  var init_recurring_recovery = __esm(() => {
@@ -104356,7 +104674,7 @@ var init_recurring_recovery = __esm(() => {
104356
104674
  init_remote_recurring();
104357
104675
  init_recurring_customer();
104358
104676
  uuid11 = exports_external.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/);
104359
- sha4 = exports_external.string().regex(/^[a-f0-9]{64}$/);
104677
+ sha5 = exports_external.string().regex(/^[a-f0-9]{64}$/);
104360
104678
  common2 = exports_external.object({
104361
104679
  contractVersion: exports_external.literal(1),
104362
104680
  apiOrigin: exports_external.string().min(1).max(4096),
@@ -104369,7 +104687,7 @@ var init_recurring_recovery = __esm(() => {
104369
104687
  common2.extend({
104370
104688
  operation: exports_external.literal("activate"),
104371
104689
  draftId: uuid11,
104372
- termsSha256: sha4,
104690
+ termsSha256: sha5,
104373
104691
  approvalDeadline: exports_external.string().datetime(),
104374
104692
  approval: recurringActivationSchema
104375
104693
  }).strict(),
@@ -104377,7 +104695,7 @@ var init_recurring_recovery = __esm(() => {
104377
104695
  ]);
104378
104696
  stateSchema = exports_external.object({
104379
104697
  contractVersion: exports_external.literal(1),
104380
- intentSha256: sha4,
104698
+ intentSha256: sha5,
104381
104699
  phase: exports_external.enum(["prepared", "pending", "observed"]),
104382
104700
  consentId: uuid11.nullable()
104383
104701
  }).strict();
@@ -106921,7 +107239,7 @@ var init_schedule_tools = __esm(() => {
106921
107239
  });
106922
107240
 
106923
107241
  // src/lib/native-storage.ts
106924
- import { createHash as createHash26, createHmac as createHmac3 } from "crypto";
107242
+ import { createHash as createHash27, createHmac as createHmac3 } from "crypto";
106925
107243
  import {
106926
107244
  existsSync as existsSync31,
106927
107245
  mkdirSync as mkdirSync21,
@@ -106930,7 +107248,7 @@ import {
106930
107248
  statSync as statSync18,
106931
107249
  writeFileSync as writeFileSync20
106932
107250
  } from "fs";
106933
- import { dirname as dirname27, join as join52, normalize as normalize4, relative as relative7, sep as sep9 } from "path";
107251
+ import { dirname as dirname27, join as join52, normalize as normalize5, relative as relative8, sep as sep9 } from "path";
106934
107252
  function resolveSkillsNativeStorageConfig(env3 = process.env) {
106935
107253
  assertNoRetiredModeEnvVars(env3, {
106936
107254
  app: SKILLS_ENV_NAMESPACE,
@@ -106994,11 +107312,11 @@ function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
106994
107312
  if (existsSync31(projectStateDir)) {
106995
107313
  for (const filePath of walkFiles2(projectStateDir)) {
106996
107314
  const bytes = readFileSync35(filePath);
106997
- const relativePath = toPosix(relative7(targetDir, filePath));
107315
+ const relativePath = toPosix(relative8(targetDir, filePath));
106998
107316
  files.push({
106999
107317
  path: relativePath,
107000
107318
  sizeBytes: bytes.byteLength,
107001
- sha256: createHash26("sha256").update(bytes).digest("hex"),
107319
+ sha256: createHash27("sha256").update(bytes).digest("hex"),
107002
107320
  ...options.includeFileContents ? { contentBase64: Buffer.from(bytes).toString("base64") } : {}
107003
107321
  });
107004
107322
  }
@@ -108180,7 +108498,7 @@ var init_remote_account2 = __esm(() => {
108180
108498
  });
108181
108499
 
108182
108500
  // src/cli/commands/runtime-copyfile.ts
108183
- import { createHash as createHash27, randomUUID as randomUUID9 } from "crypto";
108501
+ import { createHash as createHash28, randomUUID as randomUUID9 } from "crypto";
108184
108502
  import { Readable } from "stream";
108185
108503
  import { createGunzip as createGunzip2 } from "zlib";
108186
108504
  import {
@@ -108197,17 +108515,17 @@ import {
108197
108515
  symlinkSync,
108198
108516
  writeFileSync as writeFileSync23
108199
108517
  } from "fs";
108200
- import { basename as basename13, delimiter, dirname as dirname30, isAbsolute as isAbsolute24, join as join55, relative as relative8, resolve as resolve23, sep as sep10 } from "path";
108518
+ import { basename as basename14, delimiter, dirname as dirname30, isAbsolute as isAbsolute24, join as join55, relative as relative9, resolve as resolve23, sep as sep10 } from "path";
108201
108519
  function object9(value, code2) {
108202
108520
  if (!value || typeof value !== "object" || Array.isArray(value))
108203
108521
  throw new Error(code2);
108204
108522
  return value;
108205
108523
  }
108206
108524
  function hash5(bytes) {
108207
- return createHash27("sha256").update(bytes).digest("hex");
108525
+ return createHash28("sha256").update(bytes).digest("hex");
108208
108526
  }
108209
108527
  function isWithin(parent, child) {
108210
- const rel = relative8(parent, child);
108528
+ const rel = relative9(parent, child);
108211
108529
  return rel === "" || !rel.startsWith(`..${sep10}`) && rel !== ".." && !isAbsolute24(rel);
108212
108530
  }
108213
108531
  function entryExists(path) {
@@ -108302,7 +108620,7 @@ function resolveRuntimeLayout(homeInput, pathInput) {
108302
108620
  assertNoSymlinkAncestors(currentPackageRoot);
108303
108621
  if (!isWithin(runtimeRoot, currentPackageRoot))
108304
108622
  throw new Error("ACTIVE_RUNTIME_OUTSIDE_COPYFILE_ROOT");
108305
- const relativePackage = relative8(runtimeRoot, currentPackageRoot).split(sep10);
108623
+ const relativePackage = relative9(runtimeRoot, currentPackageRoot).split(sep10);
108306
108624
  if (relativePackage.length !== 4 || relativePackage[1] !== "node_modules" || relativePackage[2] !== "@hasna" || relativePackage[3] !== "skills") {
108307
108625
  throw new Error("ACTIVE_RUNTIME_LAYOUT_UNSUPPORTED");
108308
108626
  }
@@ -108355,7 +108673,7 @@ function verifyIntegrity(bytes, integrity) {
108355
108673
  const match = /^sha512-([A-Za-z0-9+/]+={0,2})$/.exec(integrity);
108356
108674
  if (!match)
108357
108675
  throw new Error("REGISTRY_INTEGRITY_UNSUPPORTED");
108358
- const actual = createHash27("sha512").update(bytes).digest("base64");
108676
+ const actual = createHash28("sha512").update(bytes).digest("base64");
108359
108677
  if (actual !== match[1])
108360
108678
  throw new Error("TARBALL_INTEGRITY_MISMATCH");
108361
108679
  }
@@ -108856,7 +109174,7 @@ function inspectAliasPackageChain(home, aliasPath, oldLinkTarget, oldTarget, bin
108856
109174
  function validateAliasSource(home, name, actual) {
108857
109175
  const packageRoot = dirname30(dirname30(actual));
108858
109176
  const roots = [join55(home, ".hasna", "skills", "runtime"), join55(home, ".bun", "install"), join55(home, ".local", "lib", "node_modules")];
108859
- if (basename13(packageRoot) !== "skills" || basename13(dirname30(packageRoot)) !== "@hasna" || !roots.some((root2) => isWithin(root2, packageRoot))) {
109177
+ if (basename14(packageRoot) !== "skills" || basename14(dirname30(packageRoot)) !== "@hasna" || !roots.some((root2) => isWithin(root2, packageRoot))) {
108860
109178
  throw new Error("ALIAS_SOURCE_ROOT_UNSUPPORTED");
108861
109179
  }
108862
109180
  assertOwnedSafePath(packageRoot, home);
@@ -108934,8 +109252,8 @@ function adoptCopyfileAliases(options = {}) {
108934
109252
  for (const item of aliases) {
108935
109253
  if (readlinkSync5(item.path) !== item.oldLinkTarget || realpathSync14(item.path) !== item.oldTarget)
108936
109254
  throw new Error("ALIAS_CHANGED_BEFORE_SWITCH");
108937
- inspectAliasPackageChain(home, item.path, item.oldLinkTarget, item.oldTarget, layout.bin[basename13(item.path)], item.chain, true);
108938
- const source = validateAliasSource(home, basename13(item.path), item.oldTarget);
109255
+ inspectAliasPackageChain(home, item.path, item.oldLinkTarget, item.oldTarget, layout.bin[basename14(item.path)], item.chain, true);
109256
+ const source = validateAliasSource(home, basename14(item.path), item.oldTarget);
108939
109257
  if (source.version !== item.oldVersion || source.binarySha256 !== item.oldBinarySha256)
108940
109258
  throw new Error("ALIAS_SOURCE_DRIFT");
108941
109259
  receipt.state = "switching";
@@ -108944,11 +109262,11 @@ function adoptCopyfileAliases(options = {}) {
108944
109262
  replaceLink(item.path, item.newTarget, item.backupPath, item.oldLinkTarget, item.oldTarget);
108945
109263
  if (realpathSync14(item.path) !== item.newTarget || realpathSync14(item.backupPath) !== item.oldTarget)
108946
109264
  throw new Error("ALIAS_SWITCH_READBACK_MISMATCH");
108947
- inspectAliasPackageChain(home, item.path, item.oldLinkTarget, item.oldTarget, layout.bin[basename13(item.path)], item.chain, true);
109265
+ inspectAliasPackageChain(home, item.path, item.oldLinkTarget, item.oldTarget, layout.bin[basename14(item.path)], item.chain, true);
108948
109266
  options.onAliasSwitched?.(item.path);
108949
109267
  }
108950
109268
  for (const item of aliases) {
108951
- inspectAliasPackageChain(home, item.path, item.oldLinkTarget, item.oldTarget, layout.bin[basename13(item.path)], item.chain, true);
109269
+ inspectAliasPackageChain(home, item.path, item.oldLinkTarget, item.oldTarget, layout.bin[basename14(item.path)], item.chain, true);
108952
109270
  if (readlinkSync5(item.backupPath) !== item.oldLinkTarget || realpathSync14(item.backupPath) !== item.oldTarget)
108953
109271
  throw new Error("ALIAS_BACKUP_DRIFT");
108954
109272
  }
@@ -108961,16 +109279,16 @@ function adoptCopyfileAliases(options = {}) {
108961
109279
  for (const item of [...aliases].reverse()) {
108962
109280
  try {
108963
109281
  if (!entryExists(item.backupPath)) {
108964
- inspectAliasPackageChain(home, item.path, item.oldLinkTarget, item.oldTarget, layout.bin[basename13(item.path)], item.chain, true);
108965
- const source2 = validateAliasSource(home, basename13(item.path), item.oldTarget);
109282
+ inspectAliasPackageChain(home, item.path, item.oldLinkTarget, item.oldTarget, layout.bin[basename14(item.path)], item.chain, true);
109283
+ const source2 = validateAliasSource(home, basename14(item.path), item.oldTarget);
108966
109284
  if (!entryExists(item.path) || readlinkSync5(item.path) !== item.oldLinkTarget || realpathSync14(item.path) !== item.oldTarget || source2.version !== item.oldVersion || source2.binarySha256 !== item.oldBinarySha256)
108967
109285
  failed = true;
108968
109286
  continue;
108969
109287
  }
108970
109288
  if (readlinkSync5(item.backupPath) !== item.oldLinkTarget || realpathSync14(item.backupPath) !== item.oldTarget)
108971
109289
  throw new Error("ALIAS_BACKUP_DRIFT");
108972
- inspectAliasPackageChain(home, item.path, item.oldLinkTarget, item.oldTarget, layout.bin[basename13(item.path)], item.chain, true);
108973
- const source = validateAliasSource(home, basename13(item.path), item.oldTarget);
109290
+ inspectAliasPackageChain(home, item.path, item.oldLinkTarget, item.oldTarget, layout.bin[basename14(item.path)], item.chain, true);
109291
+ const source = validateAliasSource(home, basename14(item.path), item.oldTarget);
108974
109292
  if (source.version !== item.oldVersion || source.binarySha256 !== item.oldBinarySha256)
108975
109293
  throw new Error("ALIAS_SOURCE_DRIFT");
108976
109294
  if (realpathSync14(item.path) === item.oldTarget && readlinkSync5(item.path) === item.oldLinkTarget)
@@ -109023,7 +109341,7 @@ function rollbackCopyfileAliases(receiptId, options = {}) {
109023
109341
  throw new Error("ALIAS_RECEIPT_BINDING_INVALID");
109024
109342
  const seen = new Set;
109025
109343
  for (const item of receipt.aliases) {
109026
- const name = basename13(item.path), target = layout.bin[name];
109344
+ const name = basename14(item.path), target = layout.bin[name];
109027
109345
  if (!target || seen.has(item.path) || !aliasDirs(home).includes(dirname30(item.path)) || item.newTarget !== join55(layout.currentPackageRoot, target) || item.backupPath !== `${item.path}.skills-alias-prev-${receiptId}` || item.chain !== undefined && (!item.chain || typeof item.chain !== "object" || typeof item.chain.packageLinkPath !== "string" || typeof item.chain.packageLinkTarget !== "string")) {
109028
109346
  throw new Error("ALIAS_RECEIPT_LAUNCHER_INVALID");
109029
109347
  }
@@ -109072,7 +109390,7 @@ function rollbackCopyfileAliases(receiptId, options = {}) {
109072
109390
  restored++;
109073
109391
  }
109074
109392
  for (const item of receipt.aliases) {
109075
- inspectAliasPackageChain(home, item.path, item.oldLinkTarget, item.oldTarget, layout.bin[basename13(item.path)], item.chain, true);
109393
+ inspectAliasPackageChain(home, item.path, item.oldLinkTarget, item.oldTarget, layout.bin[basename14(item.path)], item.chain, true);
109076
109394
  }
109077
109395
  receipt.state = "rolled-back";
109078
109396
  persistAliasReceipt(receiptPath, receipt);
@@ -109105,7 +109423,7 @@ async function updateCopyfileRuntime(version2, options = {}) {
109105
109423
  const releaseLock = acquireRuntimeLock(layout.runtimeRoot);
109106
109424
  const stagePath = join55(layout.runtimeRoot, `.stage-${version2}-${id2}`);
109107
109425
  const finalPath = join55(layout.runtimeRoot, `${version2}-copyfile`);
109108
- const launchers = layout.launchers.map((item) => ({ ...item, newTarget: join55(finalPath, "node_modules", "@hasna", "skills", layout.bin[basename13(item.path)]) }));
109426
+ const launchers = layout.launchers.map((item) => ({ ...item, newTarget: join55(finalPath, "node_modules", "@hasna", "skills", layout.bin[basename14(item.path)]) }));
109109
109427
  let switched = [];
109110
109428
  let moved = false;
109111
109429
  try {
@@ -109288,7 +109606,7 @@ function rollbackCopyfileRuntime(receiptId, options = {}) {
109288
109606
  const switched = [];
109289
109607
  const seen = new Set;
109290
109608
  for (const item of receipt.launchers) {
109291
- const bin = oldBins[basename13(item.path)];
109609
+ const bin = oldBins[basename14(item.path)];
109292
109610
  if (!bin || !isAbsolute24(item.path) || seen.has(item.path) || item.oldTarget !== join55(receipt.currentPackageRoot, bin) || item.newTarget !== join55(receipt.targetPackageRoot, bin) || !/^.+\.skills-prev-[0-9a-f-]{36}$/.test(item.backupPath) || !item.backupPath.startsWith(`${item.path}.skills-prev-`) || typeof item.oldLinkTarget !== "string" || resolve23(dirname30(item.path), item.oldLinkTarget) !== item.oldTarget)
109293
109611
  throw new Error("RECEIPT_LAUNCHER_BINDING_INVALID");
109294
109612
  assertNoSymlinkAncestors(dirname30(item.path));
@@ -109356,9 +109674,9 @@ var exports_runtime = {};
109356
109674
  __export(exports_runtime, {
109357
109675
  registerRuntime: () => registerRuntime
109358
109676
  });
109359
- import { createHash as createHash28, randomUUID as randomUUID10 } from "crypto";
109677
+ import { createHash as createHash29, randomUUID as randomUUID10 } from "crypto";
109360
109678
  import { lstatSync as lstatSync29, mkdirSync as mkdirSync25, readFileSync as readFileSync38, realpathSync as realpathSync15, writeFileSync as writeFileSync24 } from "fs";
109361
- import { basename as basename14, isAbsolute as isAbsolute25, join as join56 } from "path";
109679
+ import { basename as basename15, isAbsolute as isAbsolute25, join as join56 } from "path";
109362
109680
  import { createInterface } from "readline";
109363
109681
  function registerRuntime(parent) {
109364
109682
  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) => {
@@ -109397,7 +109715,7 @@ function registerRuntime(parent) {
109397
109715
  if (!expected)
109398
109716
  throw new Error("Cloud artifact not found");
109399
109717
  const bytes = await client2.download(id2, name);
109400
- if (bytes.length !== expected.byteSize || createHash28("sha256").update(bytes).digest("hex") !== expected.sha256)
109718
+ if (bytes.length !== expected.byteSize || createHash29("sha256").update(bytes).digest("hex") !== expected.sha256)
109401
109719
  throw new Error("Cloud artifact integrity verification failed");
109402
109720
  writeFileSync24(options.output, bytes, { flag: "wx", mode: 384 });
109403
109721
  console.log(JSON.stringify({ path: options.output, sha256: expected.sha256, byteSize: bytes.length }));
@@ -109871,7 +110189,7 @@ async function handleRun(name, args2, options, separatorBeforeSkill) {
109871
110189
  const info = lstatSync29(path);
109872
110190
  if (!info.isFile() || info.size > 20 * 1024 * 1024)
109873
110191
  throw new Error("Input must be a regular file no larger than 20 MiB");
109874
- return { name: basename14(path), bytes: new Uint8Array(readFileSync38(path)) };
110192
+ return { name: basename15(path), bytes: new Uint8Array(readFileSync38(path)) };
109875
110193
  });
109876
110194
  describeRemoteFiles(inputFiles);
109877
110195
  client2 = new RemoteSkillsClient(routing.apiKey, routing.apiOrigin);
@@ -111040,7 +111358,7 @@ var init_portable_snapshot_filter = __esm(() => {
111040
111358
  });
111041
111359
 
111042
111360
  // src/lib/station-snapshot.ts
111043
- import { createHash as createHash29 } from "crypto";
111361
+ import { createHash as createHash30 } from "crypto";
111044
111362
  import {
111045
111363
  copyFileSync as copyFileSync2,
111046
111364
  mkdirSync as mkdirSync26,
@@ -111048,14 +111366,14 @@ import {
111048
111366
  statSync as statSync20,
111049
111367
  writeFileSync as writeFileSync25
111050
111368
  } from "fs";
111051
- import { dirname as dirname32, isAbsolute as isAbsolute26, relative as relative9, resolve as resolve24, sep as sep12 } from "path";
111369
+ import { dirname as dirname32, isAbsolute as isAbsolute26, relative as relative10, resolve as resolve24, sep as sep12 } from "path";
111052
111370
  function validateStationId(stationId) {
111053
111371
  if (!/^[a-z0-9-]+$/.test(stationId)) {
111054
111372
  throw new StationSnapshotError("INVALID_STATION", `station id must be a slug, got: ${stationId}`);
111055
111373
  }
111056
111374
  }
111057
111375
  function sha256File(filePath) {
111058
- return createHash29("sha256").update(readFileSync39(filePath)).digest("hex");
111376
+ return createHash30("sha256").update(readFileSync39(filePath)).digest("hex");
111059
111377
  }
111060
111378
  function scanHome(definition, homesRoot) {
111061
111379
  const homePath = homePathFor(definition, homesRoot);
@@ -111153,7 +111471,7 @@ function writeStationSnapshot(options) {
111153
111471
  const untouched = [];
111154
111472
  for (const plan of plans) {
111155
111473
  const destination = resolve24(repoRoot, plan.destination);
111156
- const destinationRelative = relative9(repoRoot, destination);
111474
+ const destinationRelative = relative10(repoRoot, destination);
111157
111475
  if (destinationRelative.startsWith("..") || destinationRelative.startsWith(sep12) || isAbsolute26(destinationRelative)) {
111158
111476
  throw new StationSnapshotError("DESTINATION_ESCAPE", `destination escapes repo root: ${plan.destination}`);
111159
111477
  }
@@ -111627,8 +111945,8 @@ var init_create_sync_config = __esm(() => {
111627
111945
  });
111628
111946
 
111629
111947
  // src/lib/codex-native-config.ts
111630
- import { isDeepStrictEqual as isDeepStrictEqual10 } from "util";
111631
- function isRecord7(value) {
111948
+ import { isDeepStrictEqual as isDeepStrictEqual11 } from "util";
111949
+ function isRecord8(value) {
111632
111950
  if (!value || typeof value !== "object")
111633
111951
  return false;
111634
111952
  const prototype = Object.getPrototypeOf(value);
@@ -111649,10 +111967,10 @@ function decimalIdentity(text4) {
111649
111967
  return `${match[1]}${coefficient}e${exponent}`;
111650
111968
  }
111651
111969
  function codexNativeConfigEqual(native, expected) {
111652
- if (isDeepStrictEqual10(native, expected))
111970
+ if (isDeepStrictEqual11(native, expected))
111653
111971
  return true;
111654
111972
  if (typeof expected === "number") {
111655
- if (!Number.isFinite(expected) || !isRecord7(native))
111973
+ if (!Number.isFinite(expected) || !isRecord8(native))
111656
111974
  return false;
111657
111975
  const keys3 = Object.keys(native);
111658
111976
  const value = native[NUMBER_TAG];
@@ -111664,7 +111982,7 @@ function codexNativeConfigEqual(native, expected) {
111664
111982
  if (Array.isArray(native) || Array.isArray(expected)) {
111665
111983
  return Array.isArray(native) && Array.isArray(expected) && native.length === expected.length && native.every((value, index) => codexNativeConfigEqual(value, expected[index]));
111666
111984
  }
111667
- if (!isRecord7(native) || !isRecord7(expected))
111985
+ if (!isRecord8(native) || !isRecord8(expected))
111668
111986
  return false;
111669
111987
  const actual = native, wanted = expected;
111670
111988
  return Object.keys(actual).length === Object.keys(wanted).length && Object.keys(wanted).every((key) => Object.hasOwn(actual, key) && codexNativeConfigEqual(actual[key], wanted[key]));
@@ -111675,42 +111993,42 @@ var init_codex_native_config = () => {};
111675
111993
  // src/lib/codex-hook-trust-identity.ts
111676
111994
  import { realpathSync as realpathSync16 } from "fs";
111677
111995
  import { dirname as dirname33, isAbsolute as isAbsolute27, join as join59 } from "path";
111678
- import { isDeepStrictEqual as isDeepStrictEqual11 } from "util";
111996
+ import { isDeepStrictEqual as isDeepStrictEqual12 } from "util";
111679
111997
  function inspectRecordedSkillsCli(command, expected) {
111680
- need5(isAbsolute27(command) && !command.includes("\x00"), "RECONCILE_RECORDED_COMMAND_REQUIRED");
111998
+ need6(isAbsolute27(command) && !command.includes("\x00"), "RECONCILE_RECORDED_COMMAND_REQUIRED");
111681
111999
  const resolved = realpathSync16(command);
111682
112000
  const cli = snapshot(resolved, false, { readOnlyPackage: true });
111683
112001
  const manifest = snapshot(join59(dirname33(dirname33(resolved)), "package.json"), false, { readOnlyPackage: true });
111684
112002
  const pkg = JSON.parse(manifest.text);
111685
- need5(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved === join59(dirname33(manifest.file), "bin/index.js"), "SKILLS_PACKAGE_MISMATCH");
111686
- need5((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
112003
+ need6(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved === join59(dirname33(manifest.file), "bin/index.js"), "SKILLS_PACKAGE_MISMATCH");
112004
+ need6((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
111687
112005
  const receipt = { path: resolved, version: pkg.version, sha256: cli.sha256, manifestSha256: manifest.sha256 };
111688
- need5(isDeepStrictEqual11(receipt, expected), "RECONCILE_SKILLS_BINDING_CHANGED");
112006
+ need6(isDeepStrictEqual12(receipt, expected), "RECONCILE_SKILLS_BINDING_CHANGED");
111689
112007
  return { receipt, recheck() {
111690
- need5(realpathSync16(command) === resolved, "SKILLS_COMMAND_CHANGED");
112008
+ need6(realpathSync16(command) === resolved, "SKILLS_COMMAND_CHANGED");
111691
112009
  unchanged2(cli);
111692
112010
  unchanged2(manifest);
111693
112011
  } };
111694
112012
  }
111695
112013
  function bindSkillsCli(command, reviewed) {
111696
112014
  const normal = Bun.which("skills", { PATH: process.env.PATH });
111697
- need5(normal, "SKILLS_COMMAND_UNAVAILABLE");
112015
+ need6(normal, "SKILLS_COMMAND_UNAVAILABLE");
111698
112016
  const resolved = realpathSync16(normal);
111699
112017
  const bound = isAbsolute27(command) ? command : command === "skills" ? normal : undefined;
111700
- need5(bound && realpathSync16(bound) === resolved, "SKILLS_COMMAND_MISMATCH");
112018
+ need6(bound && realpathSync16(bound) === resolved, "SKILLS_COMMAND_MISMATCH");
111701
112019
  const entrypoint = reviewed?.path ?? process.argv[1];
111702
- need5(entrypoint && realpathSync16(entrypoint) === resolved, "SKILLS_ENTRYPOINT_MISMATCH");
112020
+ need6(entrypoint && realpathSync16(entrypoint) === resolved, "SKILLS_ENTRYPOINT_MISMATCH");
111703
112021
  const cli = snapshot(resolved, false, { readOnlyPackage: true });
111704
112022
  const manifest = snapshot(join59(dirname33(dirname33(resolved)), "package.json"), false, { readOnlyPackage: true });
111705
112023
  const pkg = JSON.parse(manifest.text);
111706
- need5(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved === join59(dirname33(manifest.file), "bin/index.js"), "SKILLS_PACKAGE_MISMATCH");
112024
+ need6(pkg.name === "@hasna/skills" && /^\d+\.\d+\.\d+$/.test(pkg.version) && pkg.bin?.skills === "bin/index.js" && resolved === join59(dirname33(manifest.file), "bin/index.js"), "SKILLS_PACKAGE_MISMATCH");
111707
112025
  if (reviewed)
111708
- need5(/^[a-f0-9]{64}$/.test(reviewed.sha256) && reviewed.sha256 === cli.sha256 && reviewed.version === pkg.version, "SKILLS_RELEASE_MISMATCH");
111709
- need5((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
112026
+ need6(/^[a-f0-9]{64}$/.test(reviewed.sha256) && reviewed.sha256 === cli.sha256 && reviewed.version === pkg.version, "SKILLS_RELEASE_MISMATCH");
112027
+ need6((cli.stat.mode & 0o100n) !== 0n, "SKILLS_COMMAND_NOT_EXECUTABLE");
111710
112028
  return {
111711
112029
  receipt: { path: resolved, version: pkg.version, sha256: cli.sha256, manifestSha256: manifest.sha256 },
111712
112030
  recheck() {
111713
- need5(Bun.which("skills", { PATH: process.env.PATH }) === normal && realpathSync16(normal) === resolved && realpathSync16(bound) === resolved && realpathSync16(entrypoint) === resolved, "SKILLS_COMMAND_CHANGED");
112031
+ need6(Bun.which("skills", { PATH: process.env.PATH }) === normal && realpathSync16(normal) === resolved && realpathSync16(bound) === resolved && realpathSync16(entrypoint) === resolved, "SKILLS_COMMAND_CHANGED");
111714
112032
  unchanged2(cli);
111715
112033
  unchanged2(manifest);
111716
112034
  }
@@ -111721,19 +112039,19 @@ var init_codex_hook_trust_identity = __esm(() => {
111721
112039
  });
111722
112040
 
111723
112041
  // src/lib/codex-hook-policy-recovery.ts
111724
- import { isDeepStrictEqual as isDeepStrictEqual12 } from "util";
112042
+ import { isDeepStrictEqual as isDeepStrictEqual13 } from "util";
111725
112043
  function reviewedClaudeDiscoveryChange(beforeText, currentText, options) {
111726
- need5(typeof options.reason === "string" && options.reason.trim().length > 0 && options.reason.length <= 512 && !/[\x00-\x1f\x7f]/.test(options.reason), "RECONCILE_RECOVERY_REASON_REQUIRED");
111727
- need5(options.reviewedPlanDigest === undefined || /^[a-f0-9]{64}$/.test(options.reviewedPlanDigest), "RECONCILE_RECOVERY_PLAN_CHANGED");
112044
+ need6(typeof options.reason === "string" && options.reason.trim().length > 0 && options.reason.length <= 512 && !/[\x00-\x1f\x7f]/.test(options.reason), "RECONCILE_RECOVERY_REASON_REQUIRED");
112045
+ need6(options.reviewedPlanDigest === undefined || /^[a-f0-9]{64}$/.test(options.reviewedPlanDigest), "RECONCILE_RECOVERY_PLAN_CHANGED");
111728
112046
  const before2 = parseManagedSkillPolicy(beforeText), current = parseManagedSkillPolicy(currentText);
111729
112047
  const oldDiscovery = before2.bridge?.discovery?.claude, newDiscovery = current.bridge?.discovery?.claude;
111730
- need5(oldDiscovery?.agent === "claude" && newDiscovery?.agent === "claude" && oldDiscovery.method === "reviewed" && newDiscovery.method === "reviewed", "RECONCILE_POLICY_CHANGED");
111731
- const changes = ["roots", "sources"].filter((key) => !isDeepStrictEqual12(oldDiscovery[key], newDiscovery[key])).map((key) => ({ path: `bridge.discovery.claude.${key}`, before: oldDiscovery[key], after: newDiscovery[key] }));
111732
- need5(changes.length > 0, "RECONCILE_POLICY_CHANGED");
112048
+ need6(oldDiscovery?.agent === "claude" && newDiscovery?.agent === "claude" && oldDiscovery.method === "reviewed" && newDiscovery.method === "reviewed", "RECONCILE_POLICY_CHANGED");
112049
+ const changes = ["roots", "sources"].filter((key) => !isDeepStrictEqual13(oldDiscovery[key], newDiscovery[key])).map((key) => ({ path: `bridge.discovery.claude.${key}`, before: oldDiscovery[key], after: newDiscovery[key] }));
112050
+ need6(changes.length > 0, "RECONCILE_POLICY_CHANGED");
111733
112051
  const compared = structuredClone(current);
111734
112052
  compared.bridge.discovery.claude.roots = oldDiscovery.roots;
111735
112053
  compared.bridge.discovery.claude.sources = oldDiscovery.sources;
111736
- need5(isDeepStrictEqual12(before2, compared), "RECONCILE_POLICY_CHANGED");
112054
+ need6(isDeepStrictEqual13(before2, compared), "RECONCILE_POLICY_CHANGED");
111737
112055
  verifyAgentDiscovery(newDiscovery);
111738
112056
  return { reason: options.reason, changes };
111739
112057
  }
@@ -111745,21 +112063,21 @@ var init_codex_hook_policy_recovery = __esm(() => {
111745
112063
 
111746
112064
  // src/lib/agent-codex-trust.ts
111747
112065
  import { lstatSync as lstatSync31, mkdirSync as mkdirSync27, readdirSync as readdirSync23, readFileSync as readFileSync40, realpathSync as realpathSync17, statSync as statSync21 } from "fs";
111748
- import { createHash as createHash30, randomUUID as randomUUID11 } from "crypto";
112066
+ import { createHash as createHash31, randomUUID as randomUUID11 } from "crypto";
111749
112067
  import { execFileSync } from "child_process";
111750
112068
  import { dirname as dirname34, isAbsolute as isAbsolute28, join as join60, resolve as resolve25 } from "path";
111751
112069
  import { homedir as homedir12 } from "os";
111752
- import { isDeepStrictEqual as isDeepStrictEqual13 } from "util";
112070
+ import { isDeepStrictEqual as isDeepStrictEqual14 } from "util";
111753
112071
  function verifyReleaseArtifact(proof, skillsCli) {
111754
- need5(isAbsolute28(proof.packageTarPath) && !proof.packageTarPath.includes("\x00"), "RECONCILE_RELEASE_PROVENANCE_PATH");
112072
+ need6(isAbsolute28(proof.packageTarPath) && !proof.packageTarPath.includes("\x00"), "RECONCILE_RELEASE_PROVENANCE_PATH");
111755
112073
  const tarPath = realpathSync17(proof.packageTarPath);
111756
- need5(statSync21(tarPath).isFile(), "RECONCILE_RELEASE_PROVENANCE_PATH");
112074
+ need6(statSync21(tarPath).isFile(), "RECONCILE_RELEASE_PROVENANCE_PATH");
111757
112075
  const tarBytes = readFileSync40(tarPath);
111758
- need5(tarBytes.byteLength === proof.packageTarBytes && createHash30("sha256").update(tarBytes).digest("hex") === proof.packageTarSha256, "RECONCILE_RELEASE_ARTIFACT_CHANGED");
112076
+ need6(tarBytes.byteLength === proof.packageTarBytes && createHash31("sha256").update(tarBytes).digest("hex") === proof.packageTarSha256, "RECONCILE_RELEASE_ARTIFACT_CHANGED");
111759
112077
  const packageRoot = dirname34(dirname34(realpathSync17(skillsCli.receipt.path)));
111760
112078
  const manifest = readFileSync40(join60(packageRoot, "package.json"));
111761
- need5(createHash30("sha256").update(manifest).digest("hex") === skillsCli.receipt.manifestSha256 && skillsCli.receipt.manifestSha256 === proof.manifestSha256, "RECONCILE_RELEASE_MANIFEST_CHANGED");
111762
- need5(createHash30("sha256").update(readFileSync40(skillsCli.receipt.path)).digest("hex") === proof.executableSha256 && skillsCli.receipt.sha256 === proof.executableSha256, "RECONCILE_RELEASE_EXECUTABLE_CHANGED");
112079
+ need6(createHash31("sha256").update(manifest).digest("hex") === skillsCli.receipt.manifestSha256 && skillsCli.receipt.manifestSha256 === proof.manifestSha256, "RECONCILE_RELEASE_MANIFEST_CHANGED");
112080
+ need6(createHash31("sha256").update(readFileSync40(skillsCli.receipt.path)).digest("hex") === proof.executableSha256 && skillsCli.receipt.sha256 === proof.executableSha256, "RECONCILE_RELEASE_EXECUTABLE_CHANGED");
111763
112081
  const members2 = [["package/package.json", manifest], ["package/bin/index.js", readFileSync40(skillsCli.receipt.path)]];
111764
112082
  for (const [member, expected] of members2) {
111765
112083
  let actual;
@@ -111768,7 +112086,7 @@ function verifyReleaseArtifact(proof, skillsCli) {
111768
112086
  } catch {
111769
112087
  throw new Error("RECONCILE_RELEASE_ARTIFACT_MEMBER_MISSING");
111770
112088
  }
111771
- need5(Buffer.compare(actual, expected) === 0, "RECONCILE_RELEASE_ARTIFACT_MEMBER_CHANGED");
112089
+ need6(Buffer.compare(actual, expected) === 0, "RECONCILE_RELEASE_ARTIFACT_MEMBER_CHANGED");
111772
112090
  }
111773
112091
  }
111774
112092
  async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc) {
@@ -111776,48 +112094,48 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
111776
112094
  try {
111777
112095
  const home = resolve25(options.home ?? homedir12()), dataDir3 = resolve25(options.dataDir ?? getDataDirReadOnly());
111778
112096
  const parent = resolve25(join60(dataDir3, "native-hook-trust")), journal = resolve25(options.journal);
111779
- need5(journal.startsWith(parent + "/") && /^[a-f0-9-]{36}$/.test(journal.slice(parent.length + 1)), "RECONCILE_JOURNAL_PATH");
112097
+ need6(journal.startsWith(parent + "/") && /^[a-f0-9-]{36}$/.test(journal.slice(parent.length + 1)), "RECONCILE_JOURNAL_PATH");
111780
112098
  const dir = lstatSync31(journal, { throwIfNoEntry: false });
111781
- need5(!!dir && dir.isDirectory() && !dir.isSymbolicLink() && dir.uid === process.getuid() && (dir.mode & 511) === 448, "UNSAFE_JOURNAL");
111782
- need5(!lstatSync31(join60(journal, "receipt.json"), { throwIfNoEntry: false }), "RECONCILE_ALREADY_COMPLETE");
111783
- need5(lstatSync31(join60(journal, "stopped.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_JOURNAL_INCOMPLETE");
112099
+ need6(!!dir && dir.isDirectory() && !dir.isSymbolicLink() && dir.uid === process.getuid() && (dir.mode & 511) === 448, "UNSAFE_JOURNAL");
112100
+ need6(!lstatSync31(join60(journal, "receipt.json"), { throwIfNoEntry: false }), "RECONCILE_ALREADY_COMPLETE");
112101
+ need6(lstatSync31(join60(journal, "stopped.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_JOURNAL_INCOMPLETE");
111784
112102
  const stoppedFile = snapshot(join60(journal, "stopped.json"), true);
111785
112103
  const intentFile = snapshot(join60(journal, "intent.json"), true), intent = JSON.parse(intentFile.text);
111786
112104
  const configBefore = snapshot(join60(journal, "config.before.toml"), true), hooksBefore = snapshot(join60(journal, "hooks.before.json"), true), policyBefore = snapshot(join60(journal, "policy.before.json"), true);
111787
112105
  const legacyIntent = intent.home === undefined && intent.configSha256 === undefined && intent.configVersion === undefined && intent.declarations === undefined && intent.admitted === undefined && intent.nativeHooks === undefined;
111788
- need5(intent.version === 1 && /^[a-f0-9]{64}$/.test(intent.planDigest) && typeof intent.configPath === "string" && /^[a-f0-9]{64}$/.test(intent.policySha256) && /^[a-f0-9]{64}$/.test(intent.hooksSha256) && Array.isArray(intent.hooks) && intent.hooks.length > 0 && intent.hooks.length <= 100 && (legacyIntent || typeof intent.home === "string" && intent.home === home && /^[a-f0-9]{64}$/.test(intent.configSha256) && typeof intent.configVersion === "string" && Array.isArray(intent.declarations) && Array.isArray(intent.admitted) && Array.isArray(intent.nativeHooks)), "RECONCILE_INTENT_INVALID");
112106
+ need6(intent.version === 1 && /^[a-f0-9]{64}$/.test(intent.planDigest) && typeof intent.configPath === "string" && /^[a-f0-9]{64}$/.test(intent.policySha256) && /^[a-f0-9]{64}$/.test(intent.hooksSha256) && Array.isArray(intent.hooks) && intent.hooks.length > 0 && intent.hooks.length <= 100 && (legacyIntent || typeof intent.home === "string" && intent.home === home && /^[a-f0-9]{64}$/.test(intent.configSha256) && typeof intent.configVersion === "string" && Array.isArray(intent.declarations) && Array.isArray(intent.admitted) && Array.isArray(intent.nativeHooks)), "RECONCILE_INTENT_INVALID");
111789
112107
  const declarations = intent.declarations ?? intent.hooks.map((hook) => ({ event: hook.event, key: `${join60(home, ".codex/hooks.json")}${hook.key.slice(hook.key.indexOf(".codex/hooks.json") + ".codex/hooks.json".length)}`, command: hook.command }));
111790
112108
  const admitted = intent.admitted ?? intent.hooks;
111791
112109
  const configSha256 = intent.configSha256 ?? configBefore.sha256, configVersion = intent.configVersion ?? intent.expectedVersion;
111792
112110
  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 };
111793
- need5(makePlanDigest(digestInput) === intent.planDigest, "RECONCILE_PLAN_CHANGED");
111794
- need5(isDeepStrictEqual13(intent.hooks, admitted.filter((hook) => !hook.enabled || hook.trustStatus !== "trusted")), "RECONCILE_INTENT_HOOKS_CHANGED");
111795
- need5(configBefore.sha256 === (intent.beforeSha256 ?? intent.configSha256) && hooksBefore.sha256 === intent.hooksSha256 && policyBefore.sha256 === intent.policySha256, "RECONCILE_JOURNAL_CHANGED");
112111
+ need6(makePlanDigest(digestInput) === intent.planDigest, "RECONCILE_PLAN_CHANGED");
112112
+ need6(isDeepStrictEqual14(intent.hooks, admitted.filter((hook) => !hook.enabled || hook.trustStatus !== "trusted")), "RECONCILE_INTENT_HOOKS_CHANGED");
112113
+ need6(configBefore.sha256 === (intent.beforeSha256 ?? intent.configSha256) && hooksBefore.sha256 === intent.hooksSha256 && policyBefore.sha256 === intent.policySha256, "RECONCILE_JOURNAL_CHANGED");
111796
112114
  const policyCurrent = snapshot(join60(dataDir3, "agent-policy.json"), true);
111797
112115
  const { claudeDiscoveryRecovery: claudeRecovery, nativeHookAdditionsRecovery: additionsRecovery } = options;
111798
112116
  const recovery = claudeRecovery ?? additionsRecovery;
111799
- need5(!recovery || !options.supersedeBinding, "RECONCILE_RECOVERY_MODE_CONFLICT");
111800
- need5(!claudeRecovery || !additionsRecovery || claudeRecovery.reviewedPlanDigest === additionsRecovery.reviewedPlanDigest, "RECONCILE_RECOVERY_MODE_CONFLICT");
111801
- need5(recovery?.reviewedPlanDigest === undefined || /^[a-f0-9]{64}$/.test(recovery.reviewedPlanDigest), "RECONCILE_RECOVERY_PLAN_CHANGED");
112117
+ need6(!recovery || !options.supersedeBinding, "RECONCILE_RECOVERY_MODE_CONFLICT");
112118
+ need6(!claudeRecovery || !additionsRecovery || claudeRecovery.reviewedPlanDigest === additionsRecovery.reviewedPlanDigest, "RECONCILE_RECOVERY_MODE_CONFLICT");
112119
+ need6(recovery?.reviewedPlanDigest === undefined || /^[a-f0-9]{64}$/.test(recovery.reviewedPlanDigest), "RECONCILE_RECOVERY_PLAN_CHANGED");
111802
112120
  const policyChange = claudeRecovery ? reviewedClaudeDiscoveryChange(policyBefore.text, policyCurrent.text, claudeRecovery) : undefined;
111803
112121
  let supersededBinding = false;
111804
112122
  if (policyCurrent.sha256 !== policyBefore.sha256 && !claudeRecovery) {
111805
- need5(options.supersedeBinding === true, "RECONCILE_POLICY_CHANGED");
112123
+ need6(options.supersedeBinding === true, "RECONCILE_POLICY_CHANGED");
111806
112124
  const oldPolicy = JSON.parse(policyBefore.text), currentPolicy = JSON.parse(policyCurrent.text);
111807
- need5(isDeepStrictEqual13(withoutCodexCommand(oldPolicy), withoutCodexCommand(currentPolicy)), "RECONCILE_POLICY_CHANGED");
112125
+ need6(isDeepStrictEqual14(withoutCodexCommand(oldPolicy), withoutCodexCommand(currentPolicy)), "RECONCILE_POLICY_CHANGED");
111808
112126
  supersededBinding = true;
111809
112127
  }
111810
112128
  if (supersededBinding || recovery) {
111811
- need5(Array.isArray(intent.nativeHooks) && intent.nativeHooks.length > 0, "RECONCILE_NATIVE_INVENTORY_REQUIRED");
112129
+ need6(Array.isArray(intent.nativeHooks) && intent.nativeHooks.length > 0, "RECONCILE_NATIVE_INVENTORY_REQUIRED");
111812
112130
  const proof = options.releaseProof;
111813
- need5(!!proof && isAbsolute28(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");
112131
+ need6(!!proof && isAbsolute28(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");
111814
112132
  }
111815
112133
  const currentConfig = snapshot(intent.configPath, true);
111816
112134
  const policy = parseManagedSkillPolicy(policyCurrent.text), binding = policy.bridge;
111817
112135
  const alias = binding.rootAliases?.find((item) => item.agent === "codex"), physicalRoot = alias?.target ?? join60(home, ".codex"), hooksPath = join60(physicalRoot, "hooks.json");
111818
- need5(resolve25(intent.configPath) === resolve25(join60(physicalRoot, "config.toml")), "RECONCILE_CONFIG_PATH_CHANGED");
112136
+ need6(resolve25(intent.configPath) === resolve25(join60(physicalRoot, "config.toml")), "RECONCILE_CONFIG_PATH_CHANGED");
111819
112137
  const nativeConfigPath = intent.nativeConfigPath ?? intent.configPath;
111820
- need5([join60(home, ".codex/config.toml"), join60(physicalRoot, "config.toml")].includes(nativeConfigPath), "RECONCILE_NATIVE_CONFIG_PATH_CHANGED");
112138
+ need6([join60(home, ".codex/config.toml"), join60(physicalRoot, "config.toml")].includes(nativeConfigPath), "RECONCILE_NATIVE_CONFIG_PATH_CHANGED");
111821
112139
  const codexHome = nativeConfigPath !== intent.configPath ? undefined : dirname34(nativeConfigPath);
111822
112140
  const hooksCurrent = snapshot(hooksPath);
111823
112141
  const additions = additionsRecovery ? reviewNativeHookAdditions({ path: additionsRecovery.path, intent: intentFile, policy: policyCurrent, configBefore, configCurrent: currentConfig, hooksBefore, hooksCurrent, nativeHooksPath: join60(dirname34(nativeConfigPath), "hooks.json"), journalHooks: intent.hooks, recordedNativeHooks: intent.nativeHooks }) : undefined;
@@ -111825,7 +112143,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
111825
112143
  const managedKeys = managedHooks.map((h) => h.key);
111826
112144
  const witnessSame = codexTrustReconcileWitness(configBefore.text, managedKeys) === codexTrustReconcileWitness(currentConfig.text, managedKeys);
111827
112145
  const unmanagedSame = codexTrustUnmanagedSemantic(configBefore.text, managedKeys) === codexTrustUnmanagedSemantic(currentConfig.text, managedKeys);
111828
- need5(unmanagedSame && (witnessSame || supersededBinding), "RECONCILE_UNRELATED_CONFIG_CHANGED");
112146
+ need6(unmanagedSame && (witnessSame || supersededBinding), "RECONCILE_UNRELATED_CONFIG_CHANGED");
111829
112147
  const before2 = structure3(configBefore.text), current = structure3(currentConfig.text), expectedConfig = structuredClone(before2);
111830
112148
  expectedConfig.hooks ??= {};
111831
112149
  expectedConfig.hooks.state ??= {};
@@ -111837,10 +112155,10 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
111837
112155
  if (supersededBinding) {
111838
112156
  for (const hook of intent.hooks) {
111839
112157
  const state = current.hooks?.state?.[hook.key];
111840
- need5(state?.enabled === true && typeof state.trusted_hash === "string" && /^sha256:[a-f0-9]{64}$/.test(state.trusted_hash), "RECONCILE_CONFIG_DRIFT");
112158
+ need6(state?.enabled === true && typeof state.trusted_hash === "string" && /^sha256:[a-f0-9]{64}$/.test(state.trusted_hash), "RECONCILE_CONFIG_DRIFT");
111841
112159
  }
111842
112160
  } else
111843
- need5(isDeepStrictEqual13(expectedConfig, current), "RECONCILE_CONFIG_DRIFT");
112161
+ need6(isDeepStrictEqual14(expectedConfig, current), "RECONCILE_CONFIG_DRIFT");
111844
112162
  const configDiscoveryRecovery = recovery && binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, configBefore, currentConfig, intent.hooks, additions?.trustProof) : undefined;
111845
112163
  assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: configDiscoveryRecovery });
111846
112164
  const recoveryCli = recovery ? bindSkillsCli("skills", options.reviewedSkillsCli) : undefined;
@@ -111849,29 +112167,29 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
111849
112167
  const skillsCli = recovery ? inspectRecordedSkillsCli(binding.commands.codex, intent.skillsCli) : bindSkillsCli(binding.commands.codex, options.reviewedSkillsCli);
111850
112168
  if (supersededBinding)
111851
112169
  verifyReleaseArtifact(options.releaseProof, skillsCli);
111852
- const skillsBindingChanged = !isDeepStrictEqual13(skillsCli.receipt, intent.skillsCli);
111853
- need5(!skillsBindingChanged || supersededBinding, "RECONCILE_SKILLS_BINDING_CHANGED");
112170
+ const skillsBindingChanged = !isDeepStrictEqual14(skillsCli.receipt, intent.skillsCli);
112171
+ need6(!skillsBindingChanged || supersededBinding, "RECONCILE_SKILLS_BINDING_CHANGED");
111854
112172
  if (!additions && hooksCurrent.sha256 !== intent.hooksSha256 && hooksCurrent.sha256 !== hooksBefore.sha256) {
111855
- need5(supersededBinding, "RECONCILE_HOOKS_CHANGED");
112173
+ need6(supersededBinding, "RECONCILE_HOOKS_CHANGED");
111856
112174
  const currentDeclarations = JSON.parse(hooksCurrent.text).hooks;
111857
112175
  for (const [event, [nativeEvent]] of Object.entries(eventNames)) {
111858
112176
  const command = renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, event);
111859
- need5(isDeepStrictEqual13(currentDeclarations?.[event], [{ hooks: [{ type: "command", command, timeout: 15 }] }]), "RECONCILE_BINDING_HOOK_CHANGED");
112177
+ need6(isDeepStrictEqual14(currentDeclarations?.[event], [{ hooks: [{ type: "command", command, timeout: 15 }] }]), "RECONCILE_BINDING_HOOK_CHANGED");
111860
112178
  }
111861
112179
  }
111862
112180
  rpc = await connect({ command: options.codexCommand ?? "codex", home, codexHome });
111863
- need5(rpc.version === intent.nativeVersion, "RECONCILE_NATIVE_VERSION_CHANGED");
112181
+ need6(rpc.version === intent.nativeVersion, "RECONCILE_NATIVE_VERSION_CHANGED");
111864
112182
  const discovered = await rpc.request("hooks/list", { cwds: [home] });
111865
- need5(Array.isArray(discovered?.data) && discovered.data.length === 1 && discovered.data[0].cwd === home && !discovered.data[0].errors?.length && !discovered.data[0].warnings?.length, "RECONCILE_NATIVE_DISCOVERY_REFUSED");
112183
+ need6(Array.isArray(discovered?.data) && discovered.data.length === 1 && discovered.data[0].cwd === home && !discovered.data[0].errors?.length && !discovered.data[0].warnings?.length, "RECONCILE_NATIVE_DISCOVERY_REFUSED");
111866
112184
  const nativeHooks = discovered.data[0].hooks;
111867
112185
  const recordedNativeHooks = intent.nativeHooks;
111868
112186
  if (recordedNativeHooks)
111869
- need5(nativeHooks.length === recordedNativeHooks.length + (additions?.hooks.length ?? 0), "RECONCILE_NATIVE_HOOK_LIST_CHANGED");
112187
+ need6(nativeHooks.length === recordedNativeHooks.length + (additions?.hooks.length ?? 0), "RECONCILE_NATIVE_HOOK_LIST_CHANGED");
111870
112188
  const plannedKeys = new Set(intent.hooks.map((hook) => hook.key));
111871
112189
  let nativeTrustPending = false;
111872
112190
  for (const expected of [...recordedNativeHooks ?? [], ...additions?.hooks ?? []]) {
111873
112191
  const matches2 = nativeHooks.filter((hook) => hook.key === expected.key);
111874
- need5(matches2.length === 1, "RECONCILE_NATIVE_HOOK_LIST_CHANGED");
112192
+ need6(matches2.length === 1, "RECONCILE_NATIVE_HOOK_LIST_CHANGED");
111875
112193
  const actual = safeNativeHook(matches2[0]);
111876
112194
  const stable = (hook) => {
111877
112195
  const { enabled, trustStatus, ...identity5 } = hook;
@@ -111879,35 +112197,35 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
111879
112197
  delete identity5.command;
111880
112198
  return identity5;
111881
112199
  };
111882
- need5(isDeepStrictEqual13(stable(actual), stable(expected)), "RECONCILE_NATIVE_IDENTITY_CHANGED");
112200
+ need6(isDeepStrictEqual14(stable(actual), stable(expected)), "RECONCILE_NATIVE_IDENTITY_CHANGED");
111883
112201
  if (!plannedKeys.has(expected.key))
111884
- need5(isDeepStrictEqual13(actual, expected), "RECONCILE_UNRELATED_HOOK_CHANGED");
112202
+ need6(isDeepStrictEqual14(actual, expected), "RECONCILE_UNRELATED_HOOK_CHANGED");
111885
112203
  }
111886
112204
  for (const wanted of intent.hooks) {
111887
112205
  const matches2 = nativeHooks.filter((h2) => h2.key === wanted.key || h2.key === wanted.key.replace(join60(home, ".codex/hooks.json"), hooksPath));
111888
- need5(matches2.length === 1, "RECONCILE_NATIVE_IDENTITY_CHANGED");
112206
+ need6(matches2.length === 1, "RECONCILE_NATIVE_IDENTITY_CHANGED");
111889
112207
  const h = matches2[0];
111890
112208
  const trusted = h.trustStatus === "trusted";
111891
- need5(h.enabled === true && (trusted || supersededBinding && h.trustStatus === "modified") && (h.currentHash === wanted.currentHash || supersededBinding && /^sha256:[a-f0-9]{64}$/.test(h.currentHash)), "RECONCILE_NATIVE_STATE_INCOMPLETE");
112209
+ need6(h.enabled === true && (trusted || supersededBinding && h.trustStatus === "modified") && (h.currentHash === wanted.currentHash || supersededBinding && /^sha256:[a-f0-9]{64}$/.test(h.currentHash)), "RECONCILE_NATIVE_STATE_INCOMPLETE");
111892
112210
  if (!trusted)
111893
112211
  nativeTrustPending = true;
111894
112212
  if (supersededBinding) {
111895
112213
  const nativeToCliEvent = { userPromptSubmit: "UserPromptSubmit", sessionStart: "SessionStart", subagentStart: "SubagentStart" };
111896
- need5(h.command === renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, nativeToCliEvent[wanted.event] ?? ""), "RECONCILE_BINDING_HOOK_CHANGED");
112214
+ need6(h.command === renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, nativeToCliEvent[wanted.event] ?? ""), "RECONCILE_BINDING_HOOK_CHANGED");
111897
112215
  }
111898
112216
  }
111899
112217
  const config2 = await rpc.request("config/read", { includeLayers: true, cwd: home });
111900
112218
  const layers = config2?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
111901
- need5(layers?.length === 1 && !layers[0].disabledReason && codexNativeConfigEqual(layers[0].config, current), "RECONCILE_NATIVE_CONFIG_MISMATCH");
112219
+ need6(layers?.length === 1 && !layers[0].disabledReason && codexNativeConfigEqual(layers[0].config, current), "RECONCILE_NATIVE_CONFIG_MISMATCH");
111902
112220
  const finalDiscovery = await rpc.request("hooks/list", { cwds: [home] });
111903
- need5(Array.isArray(finalDiscovery?.data) && finalDiscovery.data.length === 1 && finalDiscovery.data[0].cwd === home && !finalDiscovery.data[0].errors?.length && !finalDiscovery.data[0].warnings?.length && (!recordedNativeHooks || isDeepStrictEqual13(finalDiscovery.data[0].hooks.map(safeNativeHook), nativeHooks.map(safeNativeHook))), "RECONCILE_NATIVE_STATE_CHANGED");
112221
+ need6(Array.isArray(finalDiscovery?.data) && finalDiscovery.data.length === 1 && finalDiscovery.data[0].cwd === home && !finalDiscovery.data[0].errors?.length && !finalDiscovery.data[0].warnings?.length && (!recordedNativeHooks || isDeepStrictEqual14(finalDiscovery.data[0].hooks.map(safeNativeHook), nativeHooks.map(safeNativeHook))), "RECONCILE_NATIVE_STATE_CHANGED");
111904
112222
  const finalConfig = await rpc.request("config/read", { includeLayers: true, cwd: home });
111905
112223
  const finalLayers = finalConfig?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
111906
- need5(finalLayers?.length === 1 && !finalLayers[0].disabledReason && codexNativeConfigEqual(finalLayers[0].config, current), "RECONCILE_NATIVE_CONFIG_CHANGED");
112224
+ need6(finalLayers?.length === 1 && !finalLayers[0].disabledReason && codexNativeConfigEqual(finalLayers[0].config, current), "RECONCILE_NATIVE_CONFIG_CHANGED");
111907
112225
  if (recovery) {
111908
112226
  for (const response of [config2, finalConfig]) {
111909
112227
  const layerIndex = response.layers.findIndex((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
111910
- need5(response.config && response.config.features?.hooks !== false && response.layers.slice(0, layerIndex).every((layer) => layer.config?.hooks === undefined && layer.config?.features?.hooks === undefined), "RECONCILE_NATIVE_CONFIG_OVERRIDDEN");
112228
+ need6(response.config && response.config.features?.hooks !== false && response.layers.slice(0, layerIndex).every((layer) => layer.config?.hooks === undefined && layer.config?.features?.hooks === undefined), "RECONCILE_NATIVE_CONFIG_OVERRIDDEN");
111911
112229
  }
111912
112230
  recoveryCli.recheck();
111913
112231
  verifyReleaseArtifact(options.releaseProof, recoveryCli);
@@ -111928,7 +112246,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
111928
112246
  const recoveryPlan = recovery ? { version: 1, kind: additions ? claudeRecovery ? "claude-discovery-and-native-hook-additions" : "native-hook-additions" : "claude-discovery-only", journal, journalIntentSha256: intentFile.sha256, stoppedSha256: stoppedFile.sha256, originalPlanDigest: intent.planDigest, policyBeforeSha256: policyBefore.sha256, policyCurrentSha256: policyCurrent.sha256, configBeforeSha256: configBefore.sha256, configCurrentSha256: currentConfig.sha256, ...configDiscoveryRecovery ? { configDiscoveryRecovery } : {}, ...additions ? { nativeHookAdditions: additions.receipt } : {}, hooksSha256: hooksCurrent.sha256, nativeConfigPath, nativeVersion: rpc.version, nativeInventorySha256: makePlanDigest(nativeHooks.map(safeNativeHook)), recordedNativeInventorySha256: makePlanDigest(recordedNativeHooks), boundSkillsCli: skillsCli.receipt, recoveryCli: recoveryCli.receipt, releaseProof: options.releaseProof, ...policyChange } : undefined;
111929
112247
  const recoveryPlanDigest = recoveryPlan ? makePlanDigest(recoveryPlan) : undefined;
111930
112248
  if (recovery?.reviewedPlanDigest !== undefined)
111931
- need5(recovery.reviewedPlanDigest === recoveryPlanDigest, "RECONCILE_RECOVERY_PLAN_CHANGED");
112249
+ need6(recovery.reviewedPlanDigest === recoveryPlanDigest, "RECONCILE_RECOVERY_PLAN_CHANGED");
111932
112250
  const preview2 = !!recovery && recovery.reviewedPlanDigest === undefined;
111933
112251
  const receipt = { version: 1, status: preview2 ? "recovery-review-required" : supersededBinding ? "superseded" : "reconciled", reconciled: !preview2, supersededBinding, automaticRollback: false, journal, planDigest: intent.planDigest, nativeVersion: rpc.version, nativeStateVerified: !nativeTrustPending, nativeTrustPending, bindingRefreshRequired: !!configDiscoveryRecovery, nativeExecutionVerified: false, configSha256: currentConfig.sha256, hooksSha256: hooksCurrent.sha256, policySha256: policyBefore.sha256, policyBeforeSha256: policyBefore.sha256, policyCurrentSha256: policyCurrent.sha256, previousSkillsCli: intent.skillsCli, skillsCli: skillsCli.receipt, releaseProof: options.releaseProof, nativeInventoryScope: recordedNativeHooks ? "complete" : "declared-managed-hooks-only", unrelatedNativeHooksPreserved: !!recordedNativeHooks, unrelatedSettingsAndCommentsPreserved: true, ...recoveryPlan ? { recoveryPlan, recoveryPlanDigest } : {} };
111934
112252
  if (preview2)
@@ -111951,7 +112269,7 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
111951
112269
  const binding = policy.bridge, alias = binding.rootAliases?.find((item) => item.agent === "codex");
111952
112270
  const skillsCli = bindSkillsCli(binding.commands.codex, options.reviewedSkillsCli);
111953
112271
  const physicalRoot = alias?.target ?? join60(home, ".codex"), hooksPath = join60(physicalRoot, "hooks.json"), configPath = join60(physicalRoot, "config.toml");
111954
- need5(options.codexHome === undefined || isAbsolute28(options.codexHome) && [join60(home, ".codex"), physicalRoot].includes(options.codexHome), "NATIVE_HOME_NOT_ADMITTED");
112272
+ need6(options.codexHome === undefined || isAbsolute28(options.codexHome) && [join60(home, ".codex"), physicalRoot].includes(options.codexHome), "NATIVE_HOME_NOT_ADMITTED");
111955
112273
  const codexHome = options.codexHome === undefined ? undefined : physicalRoot;
111956
112274
  const nativeConfigPath = join60(codexHome ?? join60(home, ".codex"), "config.toml");
111957
112275
  const hooksFile = snapshot(hooksPath), configFile = snapshot(configPath, true), original = structure3(configFile.text);
@@ -111959,38 +112277,38 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
111959
112277
  for (const [event, [nativeEvent, label]] of Object.entries(eventNames)) {
111960
112278
  const command = renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, event);
111961
112279
  const groups = declarations[event];
111962
- need5(Array.isArray(groups), "DECLARATION_CHANGED");
112280
+ need6(Array.isArray(groups), "DECLARATION_CHANGED");
111963
112281
  const matches2 = groups.flatMap((group, gi) => (group.hooks ?? []).flatMap((entry, hi) => entry.command === command ? [{ group, entry, gi, hi }] : []));
111964
- need5(matches2.length === 1 && isDeepStrictEqual13(matches2[0].group, { hooks: [{ type: "command", command, timeout: 15 }] }), "DECLARATION_CHANGED");
112282
+ need6(matches2.length === 1 && isDeepStrictEqual14(matches2[0].group, { hooks: [{ type: "command", command, timeout: 15 }] }), "DECLARATION_CHANGED");
111965
112283
  expected.push({ event: nativeEvent, key: `${join60(home, ".codex/hooks.json")}:${label}:${matches2[0].gi}:${matches2[0].hi}`, command });
111966
112284
  }
111967
112285
  codexTrustTextWitness(configFile.text, expected.map((h) => h.key));
111968
112286
  rpc = await connect({ command: options.codexCommand ?? "codex", home, codexHome });
111969
- need5(SUPPORTED_CODEX_HOOK_VERSIONS.includes(rpc.version), "NATIVE_UNSUPPORTED_VERSION");
112287
+ need6(SUPPORTED_CODEX_HOOK_VERSIONS.includes(rpc.version), "NATIVE_UNSUPPORTED_VERSION");
111970
112288
  const list2 = async () => {
111971
112289
  const response = await rpc.request("hooks/list", { cwds: [home] });
111972
112290
  const nativeRoots = [...new Set([physicalRoot, join60(home, ".codex")])];
111973
112291
  const coexistenceWarnings = nativeRoots.flatMap((hooksRoot) => nativeRoots.map((configRoot) => `loading hooks from both ${join60(hooksRoot, "hooks.json")} and ${join60(configRoot, "config.toml")}; prefer a single representation for this layer`));
111974
112292
  const entry = response?.data?.[0];
111975
- need5(Array.isArray(response?.data) && response.data.length === 1 && entry.cwd === home && Array.isArray(entry.hooks) && entry.hooks.length <= 1e4 && Array.isArray(entry.errors) && entry.errors.length === 0 && Array.isArray(entry.warnings) && entry.warnings.length <= 1 && entry.warnings.every((warning) => typeof warning === "string" && coexistenceWarnings.includes(warning)), "NATIVE_DISCOVERY_REFUSED");
112293
+ need6(Array.isArray(response?.data) && response.data.length === 1 && entry.cwd === home && Array.isArray(entry.hooks) && entry.hooks.length <= 1e4 && Array.isArray(entry.errors) && entry.errors.length === 0 && Array.isArray(entry.warnings) && entry.warnings.length <= 1 && entry.warnings.every((warning) => typeof warning === "string" && coexistenceWarnings.includes(warning)), "NATIVE_DISCOVERY_REFUSED");
111976
112294
  return response.data[0].hooks;
111977
112295
  };
111978
112296
  const admit = (hooks) => expected.map((wanted) => {
111979
112297
  const canonicalKey = wanted.key.replace(join60(home, ".codex/hooks.json"), hooksPath);
111980
112298
  const matches2 = hooks.filter((h2) => h2.key === wanted.key || h2.key === canonicalKey);
111981
- need5(matches2.length === 1, "AMBIGUOUS_IDENTITY");
112299
+ need6(matches2.length === 1, "AMBIGUOUS_IDENTITY");
111982
112300
  const h = matches2[0];
111983
- need5(h.eventName === wanted.event && h.handlerType === "command" && h.command === wanted.command && h.matcher === null && h.timeoutSec === 15 && h.async === false && h.statusMessage === null && h.additionalContextLimit === null && [hooksPath, join60(home, ".codex/hooks.json")].includes(h.sourcePath) && h.source === "user" && h.pluginId === null && h.isManaged === false && /^sha256:[a-f0-9]{64}$/.test(h.currentHash) && typeof h.enabled === "boolean", "NATIVE_IDENTITY_CHANGED");
111984
- need5(hooks.filter((other) => other.command === wanted.command).length === 1, "AMBIGUOUS_IDENTITY");
111985
- need5(["trusted", "untrusted", "modified"].includes(h.trustStatus), "UNKNOWN_TRUST_STATUS");
112301
+ need6(h.eventName === wanted.event && h.handlerType === "command" && h.command === wanted.command && h.matcher === null && h.timeoutSec === 15 && h.async === false && h.statusMessage === null && h.additionalContextLimit === null && [hooksPath, join60(home, ".codex/hooks.json")].includes(h.sourcePath) && h.source === "user" && h.pluginId === null && h.isManaged === false && /^sha256:[a-f0-9]{64}$/.test(h.currentHash) && typeof h.enabled === "boolean", "NATIVE_IDENTITY_CHANGED");
112302
+ need6(hooks.filter((other) => other.command === wanted.command).length === 1, "AMBIGUOUS_IDENTITY");
112303
+ need6(["trusted", "untrusted", "modified"].includes(h.trustStatus), "UNKNOWN_TRUST_STATUS");
111986
112304
  return { key: h.key, event: wanted.event, command: wanted.command, handlerType: h.handlerType, timeoutSec: h.timeoutSec, sourcePath: h.sourcePath, currentHash: h.currentHash, enabled: h.enabled, trustStatus: h.trustStatus };
111987
112305
  });
111988
112306
  const discovered = await list2(), admitted = admit(discovered);
111989
112307
  const config2 = await rpc.request("config/read", { includeLayers: true, cwd: home });
111990
112308
  const layers = config2?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
111991
- need5(layers?.length === 1 && /^sha256:[a-f0-9]{64}$/.test(layers[0].version) && !layers[0].disabledReason && codexNativeConfigEqual(layers[0].config, original), "NATIVE_CONFIG_MISMATCH");
111992
- need5(config2.config && config2.config.features?.hooks !== false, "NATIVE_HOOKS_DISABLED");
111993
- need5(config2.layers.slice(0, config2.layers.indexOf(layers[0])).every((layer) => layer.config?.hooks === undefined && layer.config?.features?.hooks === undefined), "NATIVE_CONFIG_OVERRIDDEN");
112309
+ need6(layers?.length === 1 && /^sha256:[a-f0-9]{64}$/.test(layers[0].version) && !layers[0].disabledReason && codexNativeConfigEqual(layers[0].config, original), "NATIVE_CONFIG_MISMATCH");
112310
+ need6(config2.config && config2.config.features?.hooks !== false, "NATIVE_HOOKS_DISABLED");
112311
+ need6(config2.layers.slice(0, config2.layers.indexOf(layers[0])).every((layer) => layer.config?.hooks === undefined && layer.config?.features?.hooks === undefined), "NATIVE_CONFIG_OVERRIDDEN");
111994
112312
  const keys3 = admitted.map((h) => h.key), planned = admitted.filter((h) => !h.enabled || h.trustStatus !== "trusted");
111995
112313
  const preservationText = codexTrustTextWitness(configFile.text, keys3);
111996
112314
  const checkInputs = () => {
@@ -112005,16 +112323,16 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
112005
112323
  const planDigest = makePlanDigest(digestInput);
112006
112324
  const baseReceipt = { planDigest, skillsCli: skillsCli.receipt, nativeVersion: rpc.version, nativeConfigPath, ownedNativeProcessId: rpc.processId, agent: "codex", applied: false, planned, nativeEligible: planned.length === 0, bindingRefreshRequired: false, transport: "owned-stdio-process", existingSessionsReloaded: false, nativeExecutionVerified: false };
112007
112325
  if (options.apply)
112008
- need5(options.reviewedPlanDigest === planDigest, "PLAN_CHANGED: run the dry-run again and pass its reviewed --plan-digest with --apply");
112326
+ need6(options.reviewedPlanDigest === planDigest, "PLAN_CHANGED: run the dry-run again and pass its reviewed --plan-digest with --apply");
112009
112327
  const parent = join60(dataDir3, "native-hook-trust");
112010
112328
  const st = lstatSync31(parent, { throwIfNoEntry: false });
112011
112329
  if (st) {
112012
- need5(st.isDirectory() && !st.isSymbolicLink() && st.uid === process.getuid() && (st.mode & 511) === 448, "UNSAFE_JOURNAL");
112330
+ need6(st.isDirectory() && !st.isSymbolicLink() && st.uid === process.getuid() && (st.mode & 511) === 448, "UNSAFE_JOURNAL");
112013
112331
  const priorJournals = readdirSync23(parent);
112014
- need5(priorJournals.length < 1000, "JOURNAL_BOUND");
112332
+ need6(priorJournals.length < 1000, "JOURNAL_BOUND");
112015
112333
  for (const name of priorJournals) {
112016
- need5(/^[a-f0-9-]{36}$/.test(name), "UNSAFE_JOURNAL");
112017
- need5(lstatSync31(join60(parent, name, "receipt.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_REQUIRED: inspect the incomplete private journal before applying again");
112334
+ need6(/^[a-f0-9-]{36}$/.test(name), "UNSAFE_JOURNAL");
112335
+ need6(lstatSync31(join60(parent, name, "receipt.json"), { throwIfNoEntry: false })?.isFile(), "RECONCILE_REQUIRED: inspect the incomplete private journal before applying again");
112018
112336
  }
112019
112337
  }
112020
112338
  if (!options.apply || !planned.length)
@@ -112027,7 +112345,7 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
112027
112345
  save(join60(journal, "hooks.before.json"), hooksFile.bytes);
112028
112346
  save(join60(journal, "policy.before.json"), policyFile.bytes);
112029
112347
  save(join60(journal, "intent.json"), json2({ ...digestInput, planDigest, hooks: planned, nativeHooks: discovered.map(safeNativeHook) }));
112030
- need5(isDeepStrictEqual13(admit(await list2()), admitted), "NATIVE_DISCOVERY_CHANGED");
112348
+ need6(isDeepStrictEqual14(admit(await list2()), admitted), "NATIVE_DISCOVERY_CHANGED");
112031
112349
  checkInputs();
112032
112350
  let result2;
112033
112351
  try {
@@ -112035,22 +112353,22 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
112035
112353
  } catch {
112036
112354
  throw new Error("CODEX_HOOK_TRUST_NATIVE_WRITE_FAILED: reconcile the private journal before retrying");
112037
112355
  }
112038
- need5(result2?.status === "ok" && result2.filePath === configPath && /^sha256:[a-f0-9]{64}$/.test(result2.version), "NATIVE_WRITE_OVERRIDDEN");
112356
+ need6(result2?.status === "ok" && result2.filePath === configPath && /^sha256:[a-f0-9]{64}$/.test(result2.version), "NATIVE_WRITE_OVERRIDDEN");
112039
112357
  const after2 = snapshot(configPath, true), expectedConfig = structuredClone(original);
112040
112358
  expectedConfig.hooks ??= {};
112041
112359
  expectedConfig.hooks.state ??= {};
112042
112360
  for (const h of planned)
112043
112361
  expectedConfig.hooks.state[h.key] = { ...expectedConfig.hooks.state[h.key], enabled: true, trusted_hash: h.currentHash };
112044
- need5(isDeepStrictEqual13(structure3(after2.text), expectedConfig) && codexTrustTextWitness(after2.text, keys3) === preservationText, "PRESERVATION_FAILED");
112362
+ need6(isDeepStrictEqual14(structure3(after2.text), expectedConfig) && codexTrustTextWitness(after2.text, keys3) === preservationText, "PRESERVATION_FAILED");
112045
112363
  const savedConfig = snapshot(join60(journal, "config.before.toml"), true);
112046
- need5(savedConfig.sha256 === configFile.sha256, "JOURNAL_CHANGED");
112364
+ need6(savedConfig.sha256 === configFile.sha256, "JOURNAL_CHANGED");
112047
112365
  const discoveryTransition = binding.discovery?.codex ? createCodexHookDiscoveryRecovery(binding.discovery.codex, savedConfig, after2, planned) : undefined;
112048
112366
  unchanged2(policyFile);
112049
112367
  unchanged2(hooksFile);
112050
112368
  assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home, codexDiscoveryRecovery: discoveryTransition });
112051
112369
  const current = await list2(), confirmed = admit(current);
112052
- need5(confirmed.every((h) => h.enabled && h.trustStatus === "trusted") && isDeepStrictEqual13(confirmed.map((h) => [h.key, h.currentHash]), admitted.map((h) => [h.key, h.currentHash])), "NATIVE_NOT_ELIGIBLE");
112053
- need5(isDeepStrictEqual13(current.filter((h) => !keys3.includes(h.key)), discovered.filter((h) => !keys3.includes(h.key))), "UNRELATED_HOOK_CHANGED");
112370
+ need6(confirmed.every((h) => h.enabled && h.trustStatus === "trusted") && isDeepStrictEqual14(confirmed.map((h) => [h.key, h.currentHash]), admitted.map((h) => [h.key, h.currentHash])), "NATIVE_NOT_ELIGIBLE");
112371
+ need6(isDeepStrictEqual14(current.filter((h) => !keys3.includes(h.key)), discovered.filter((h) => !keys3.includes(h.key))), "UNRELATED_HOOK_CHANGED");
112054
112372
  unchanged2(after2);
112055
112373
  unchanged2(savedConfig);
112056
112374
  unchanged2(hooksFile);
@@ -112073,7 +112391,7 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
112073
112391
  }
112074
112392
  }
112075
112393
  var json2 = (value) => JSON.stringify(value, null, 2) + `
112076
- `, structure3 = (text4) => JSON.parse(JSON.stringify(Bun.TOML.parse(text4))), eventNames, makePlanDigest = (value) => createHash30("sha256").update(json2(value)).digest("hex"), safeNativeHook = (hook) => ({ key: hook.key, eventName: hook.eventName, handlerType: hook.handlerType, command: hook.command, matcher: hook.matcher, timeoutSec: hook.timeoutSec, async: hook.async, statusMessage: hook.statusMessage, additionalContextLimit: hook.additionalContextLimit, sourcePath: hook.sourcePath, source: hook.source, pluginId: hook.pluginId, isManaged: hook.isManaged, currentHash: hook.currentHash, enabled: hook.enabled, trustStatus: hook.trustStatus }), withoutCodexCommand = (value) => {
112394
+ `, structure3 = (text4) => JSON.parse(JSON.stringify(Bun.TOML.parse(text4))), eventNames, makePlanDigest = (value) => createHash31("sha256").update(json2(value)).digest("hex"), safeNativeHook = (hook) => ({ key: hook.key, eventName: hook.eventName, handlerType: hook.handlerType, command: hook.command, matcher: hook.matcher, timeoutSec: hook.timeoutSec, async: hook.async, statusMessage: hook.statusMessage, additionalContextLimit: hook.additionalContextLimit, sourcePath: hook.sourcePath, source: hook.source, pluginId: hook.pluginId, isManaged: hook.isManaged, currentHash: hook.currentHash, enabled: hook.enabled, trustStatus: hook.trustStatus }), withoutCodexCommand = (value) => {
112077
112395
  const copy = structuredClone(value);
112078
112396
  if (copy?.bridge?.commands && Object.hasOwn(copy.bridge.commands, "codex"))
112079
112397
  copy.bridge.commands.codex = "<reviewed-codex-binding>";
@@ -112213,7 +112531,7 @@ __export(exports_agent_integration, {
112213
112531
  registerAgentIntegration: () => registerAgentIntegration
112214
112532
  });
112215
112533
  import { existsSync as existsSync35, lstatSync as lstatSync32, readFileSync as readFileSync41, writeFileSync as writeFileSync26 } from "fs";
112216
- import { createHash as createHash31 } from "crypto";
112534
+ import { createHash as createHash32 } from "crypto";
112217
112535
  import { homedir as homedir13 } from "os";
112218
112536
  import { isAbsolute as isAbsolute29 } from "path";
112219
112537
  function pinnedHookProfile(input3, configuredProfile) {
@@ -112311,7 +112629,7 @@ function registerAgentIntegration(parent) {
112311
112629
  skillCount: catalog.skills.length,
112312
112630
  output: options.output,
112313
112631
  bytes: Buffer.byteLength(bytes),
112314
- sha256: createHash31("sha256").update(bytes).digest("hex")
112632
+ sha256: createHash32("sha256").update(bytes).digest("hex")
112315
112633
  };
112316
112634
  await writeCliOutput(options.json ? JSON.stringify(receipt) : `Captured ${receipt.skillCount} native Codex skill(s) in ${receipt.output}.`);
112317
112635
  } catch (error61) {
@@ -112320,10 +112638,10 @@ function registerAgentIntegration(parent) {
112320
112638
  process.exitCode = 1;
112321
112639
  }
112322
112640
  });
112323
- hook.command("witness").requiredOption("--kind <kind>", "claude-settings-v3, claude-settings-v2, codex-settings-v1 or claude-marketplace-registry-v2").requiredOption("--path <path>", "Canonical absolute path to the reviewed settings or registry file").option("--json", "Output the discovery witness as JSON", false).description("Capture an explicit versioned review witness without installing it").action(async (options) => {
112324
- const capture2 = options.kind === "codex-settings-v1" ? captureCodexSettings : options.kind === "claude-settings-v3" ? captureClaudeSettingsV3 : options.kind === "claude-settings-v2" ? captureClaudeSettingsV2 : options.kind === "claude-marketplace-registry-v2" ? captureClaudeMarketplaceRegistryV2 : null;
112641
+ hook.command("witness").requiredOption("--kind <kind>", "claude-settings-v3, claude-settings-v2, codex-settings-v2, codex-settings-v1 or claude-marketplace-registry-v2").requiredOption("--path <path>", "Canonical absolute path to the reviewed settings or registry file").option("--json", "Output the discovery witness as JSON", false).description("Capture an explicit versioned review witness without installing it").action(async (options) => {
112642
+ const capture2 = options.kind === "codex-settings-v2" ? captureCodexSettingsV2 : options.kind === "codex-settings-v1" ? captureCodexSettings : options.kind === "claude-settings-v3" ? captureClaudeSettingsV3 : options.kind === "claude-settings-v2" ? captureClaudeSettingsV2 : options.kind === "claude-marketplace-registry-v2" ? captureClaudeMarketplaceRegistryV2 : null;
112325
112643
  if (!capture2)
112326
- throw new Error("Unsupported witness kind; select claude-settings-v3, claude-settings-v2, codex-settings-v1 or claude-marketplace-registry-v2");
112644
+ throw new Error("Unsupported witness kind; select claude-settings-v3, claude-settings-v2, codex-settings-v2, codex-settings-v1 or claude-marketplace-registry-v2");
112327
112645
  await writeCliOutput(JSON.stringify(capture2(options.path), null, 2));
112328
112646
  });
112329
112647
  hook.command("rebind-settings").requiredOption("--agent <agent>", "claude or codex").requiredOption("--reviewed-preimage <path>", "Exact preserved legacy settings.json or config.toml").requiredOption("--expected-policy-sha256 <sha256>", "Exact current managed policy bytes").requiredOption("--expected-settings-sha256 <sha256>", "Exact current native settings bytes").option("--apply", "Apply the explicit semantic witness upgrade with preservation and readback", false).option("--json", "Return the metadata-only plan or receipt", false).description("Explicitly migrate a legacy native settings witness after proving only known preferences changed").action(async (options) => {
@@ -112342,7 +112660,7 @@ function registerAgentIntegration(parent) {
112342
112660
  hook.command("agents").option("--json", "Output the adapter capability inventory", false).description("Show maintained native adapters and explicit coverage limits").action(async () => {
112343
112661
  await writeCliOutput(JSON.stringify({ agents: INTEGRATION_AGENTS.map((agent) => ({ agent, bridge: true, ...AGENT_ADAPTERS[agent] })), inventoryOnly: ["codewith", "windsurf", "pi", "amp", "cline", "roo", "copilot"], limitations: ["Cursor prompt hooks gate submission; selected context is injected at session start only.", "Native discovery checks cover known home roots and current project ancestors. External plugin hook injection and arbitrary added directories require separate review.", "Hermes injects selected prompt context, but native pre_llm_call fails open. Exact native hook trust, bundled reseeding opt-out, native payload retirement and a supervised pre-tool guard are required. Child failures block explicitly; native host/supervisor death is not a universal fail-closed guarantee.", "Restart agents and use their normal hook trust controls after installation."] }, null, 2));
112344
112662
  });
112345
- hook.command("install").option("--agent <agent>", `Agent to configure: ${INTEGRATION_AGENTS.join(", ")}, all`, "all").option("--command <path>", "Skills executable used by the hook (preserves existing binding; new agents use skills)").option("--selection-profile <id>", "Selection profile (preserves existing binding; new agents use default)").option("--include-vendor", "Retained for compatibility; vendor system skills are always inventoried and disabled", false).option("--discovery-inputs <file>", "Advanced reviewed active plugin roots and source hashes for unsupported registrations").option("--codex-native-catalog <file>", "Reviewed native0.159.2 skills/list receipt for exact qualified plugin-name disables").option("--reviewed-cache-alias <path>", "Exact skill-containing vendor cache alias reviewed for this hook plan").option("--allow-root-aliases", "Allow home .claude/.codex aliases to existing directories within this home", false).option("--apply", "Apply the plan, preserving prior configuration in private backups", false).option("--json", "Output a receipt as JSON", false).description("Plan or install one Skills CLI bridge plus native prompt hooks").action(async (options) => {
112663
+ hook.command("install").option("--agent <agent>", `Agent to configure: ${INTEGRATION_AGENTS.join(", ")}, all`, "all").option("--command <path>", "Skills executable used by the hook (preserves existing binding; new agents use skills)").option("--selection-profile <id>", "Selection profile (preserves existing binding; new agents use default)").option("--include-vendor", "Retained for compatibility; vendor system skills are always inventoried and disabled", false).option("--discovery-inputs <file>", "Advanced reviewed active plugin roots and source hashes for unsupported registrations").option("--codex-native-catalog <file>", "Reviewed supported Codex skill and installed-plugin receipt for exact qualified-name disables").option("--reviewed-cache-alias <path>", "Exact skill-containing vendor cache alias reviewed for this hook plan").option("--allow-root-aliases", "Allow home .claude/.codex aliases to existing directories within this home", false).option("--apply", "Apply the plan, preserving prior configuration in private backups", false).option("--json", "Output a receipt as JSON", false).description("Plan or install one Skills CLI bridge plus native prompt hooks").action(async (options) => {
112346
112664
  try {
112347
112665
  const discoveryInputs = options.discoveryInputs ? JSON.parse(readFileSync41(options.discoveryInputs, "utf8")) : undefined;
112348
112666
  const plan = planAgentIntegration({ projectDir: process.cwd(), agents: agents(options.agent), command: options.command, profileId: options.selectionProfile, includeVendor: options.includeVendor, discoveryInputs, allowRootAliases: options.allowRootAliases, reviewedCacheAlias: options.reviewedCacheAlias, codexNativeCatalog: options.codexNativeCatalog ? JSON.parse(readFileSync41(options.codexNativeCatalog, "utf8")) : undefined });
@@ -112825,7 +113143,7 @@ var init_grants = __esm(() => {
112825
113143
  });
112826
113144
 
112827
113145
  // src/lib/station-hydrate.ts
112828
- import { createHash as createHash32 } from "crypto";
113146
+ import { createHash as createHash33 } from "crypto";
112829
113147
  import {
112830
113148
  copyFileSync as copyFileSync3,
112831
113149
  mkdirSync as mkdirSync28,
@@ -113028,7 +113346,7 @@ function skillSha256(skill) {
113028
113346
  return sha256File(skill.files[0].winner.fullPath);
113029
113347
  }
113030
113348
  const joined = skill.files.map((file2) => sha256File(file2.winner.fullPath));
113031
- return createHash32("sha256").update(joined.sort().join(`
113349
+ return createHash33("sha256").update(joined.sort().join(`
113032
113350
  `)).digest("hex");
113033
113351
  }
113034
113352
  function writeStationHydration(options) {
@@ -113185,10 +113503,10 @@ var init_hydrate = __esm(() => {
113185
113503
  });
113186
113504
 
113187
113505
  // src/lib/prepare-skill.ts
113188
- import { createHash as createHash33, randomUUID as randomUUID12 } from "crypto";
113506
+ import { createHash as createHash34, randomUUID as randomUUID12 } from "crypto";
113189
113507
  import { chmodSync as chmodSync5, existsSync as existsSync36, lstatSync as lstatSync33, mkdirSync as mkdirSync29, mkdtempSync as mkdtempSync6, readFileSync as readFileSync43, readdirSync as readdirSync25, renameSync as renameSync14, rmSync as rmSync9, writeFileSync as writeFileSync30 } from "fs";
113190
113508
  import { tmpdir as tmpdir2 } from "os";
113191
- import { dirname as dirname36, isAbsolute as isAbsolute30, join as join62, relative as relative10, resolve as resolve27, sep as sep14 } from "path";
113509
+ import { dirname as dirname36, isAbsolute as isAbsolute30, join as join62, relative as relative11, resolve as resolve27, sep as sep14 } from "path";
113192
113510
  function prepareSkill(name, options) {
113193
113511
  const normalized = normalizePortableSkillName(name);
113194
113512
  if (!new RegExp(SEMVER_PATTERN).test(options.version))
@@ -113202,7 +113520,7 @@ function prepareSkill(name, options) {
113202
113520
  let manifest;
113203
113521
  try {
113204
113522
  const parsed = JSON.parse(manifestFile.bytes.toString("utf8"));
113205
- if (!isRecord8(parsed))
113523
+ if (!isRecord9(parsed))
113206
113524
  throw new Error("not an object");
113207
113525
  manifest = parsed;
113208
113526
  } catch {
@@ -113224,7 +113542,7 @@ function prepareSkill(name, options) {
113224
113542
  if (documentKind !== undefined && documentKind !== kind) {
113225
113543
  throw new Error("SKILL.md kind conflicts with the candidate skill.json kind. Review and align both declarations (or remove the optional frontmatter kind), then prepare again; no files were changed.");
113226
113544
  }
113227
- if (manifest.provenance !== undefined && !isRecord8(manifest.provenance))
113545
+ if (manifest.provenance !== undefined && !isRecord9(manifest.provenance))
113228
113546
  throw new Error("skill.json provenance must be an object.");
113229
113547
  const provenance = manifest.provenance;
113230
113548
  const candidate2 = { ...manifest, version: options.version, kind, provenance: { ...provenance } };
@@ -113289,17 +113607,17 @@ function escapedRelativePath(path) {
113289
113607
  return JSON.stringify(bounded);
113290
113608
  }
113291
113609
  function validateRuntimeEntrypoint(candidate2, root2) {
113292
- if (candidate2.kind !== "executable" || !isRecord8(candidate2.runtime))
113610
+ if (candidate2.kind !== "executable" || !isRecord9(candidate2.runtime))
113293
113611
  return;
113294
113612
  const entry = candidate2.runtime.entrypoint;
113295
113613
  if (typeof entry !== "string")
113296
113614
  return;
113297
- const target = resolve27(root2, entry), rel = relative10(root2, target);
113615
+ const target = resolve27(root2, entry), rel = relative11(root2, target);
113298
113616
  if (isAbsolute30(entry) || /^[a-zA-Z]:/.test(entry) || entry.includes("\\") || !rel || rel === ".." || rel.startsWith(`..${sep14}`) || isAbsolute30(rel) || !existsSync36(target) || !lstatSync33(target).isFile()) {
113299
113617
  throw new Error("Executable runtime.entrypoint must name an existing regular file inside the skill directory.");
113300
113618
  }
113301
113619
  }
113302
- function isRecord8(value) {
113620
+ function isRecord9(value) {
113303
113621
  return typeof value === "object" && value !== null && !Array.isArray(value);
113304
113622
  }
113305
113623
  function validateRawCandidate(candidate2) {
@@ -113324,7 +113642,7 @@ function validateRawCandidate(candidate2) {
113324
113642
  if (!Array.isArray(items))
113325
113643
  throw new Error(`skill.json ${field2} must be an array.`);
113326
113644
  for (const item of items) {
113327
- if (!isRecord8(item) || typeof item.name !== "string" || !item.name.trim())
113645
+ if (!isRecord9(item) || typeof item.name !== "string" || !item.name.trim())
113328
113646
  throw new Error(`Invalid skill.json ${field2} name.`);
113329
113647
  if (field2 === "inputs" && (typeof item.type !== "string" || !item.type.trim() || item.required !== undefined && typeof item.required !== "boolean"))
113330
113648
  throw new Error("Invalid skill.json input type or required flag.");
@@ -113343,7 +113661,7 @@ function validateRawCandidate(candidate2) {
113343
113661
  }
113344
113662
  }
113345
113663
  function validateRuntimeEntrypointCompatibility(candidate2) {
113346
- if (candidate2.kind !== "executable" || !isRecord8(candidate2.runtime))
113664
+ if (candidate2.kind !== "executable" || !isRecord9(candidate2.runtime))
113347
113665
  return;
113348
113666
  const runtime = candidate2.runtime.runtime;
113349
113667
  const entrypoint = candidate2.runtime.entrypoint;
@@ -113384,13 +113702,13 @@ function snapshot2(root2) {
113384
113702
  if (rootStat.isSymbolicLink() || !rootStat.isDirectory())
113385
113703
  throw new Error("Skill root must be a real directory, not a symlink.");
113386
113704
  const files = [], directories = [];
113387
- const hash6 = createHash33("sha256").update(`${rootStat.dev}:${rootStat.ino}\x00`);
113705
+ const hash6 = createHash34("sha256").update(`${rootStat.dev}:${rootStat.ino}\x00`);
113388
113706
  let count = 0, bytes = 0;
113389
- const walk2 = (relative11) => {
113390
- for (const name of readdirSync25(join62(root2, relative11)).sort()) {
113391
- if (IGNORED.has(name.toLowerCase()) || !relative11 && ROOT_IGNORED.has(name.toLowerCase()))
113707
+ const walk2 = (relative12) => {
113708
+ for (const name of readdirSync25(join62(root2, relative12)).sort()) {
113709
+ if (IGNORED.has(name.toLowerCase()) || !relative12 && ROOT_IGNORED.has(name.toLowerCase()))
113392
113710
  continue;
113393
- const path = relative11 ? `${relative11}/${name}` : name;
113711
+ const path = relative12 ? `${relative12}/${name}` : name;
113394
113712
  if (++count > 20000)
113395
113713
  throw new Error("Skill exceeds the preparation entry limit (20000).");
113396
113714
  const absolute = join62(root2, path), stat3 = lstatSync33(absolute);
@@ -113809,7 +114127,7 @@ var init_schedule = __esm(() => {
113809
114127
 
113810
114128
  // src/lib/registry-sync.ts
113811
114129
  import { mkdirSync as mkdirSync30, writeFileSync as writeFileSync31 } from "fs";
113812
- import { dirname as dirname37, relative as relative11 } from "path";
114130
+ import { dirname as dirname37, relative as relative12 } from "path";
113813
114131
  function createRegistrySyncArtifact(options = {}) {
113814
114132
  const profile = options.profile ?? "all";
113815
114133
  const includeDocs = options.includeDocs ?? true;
@@ -113821,7 +114139,7 @@ function createRegistrySyncArtifact(options = {}) {
113821
114139
  const registry2 = [...loadRegistryProfile(profile)].sort((a, b) => a.name.localeCompare(b.name));
113822
114140
  const skills = registry2.map((skill) => {
113823
114141
  const skillPath = getSkillPath(skill.name);
113824
- const directory2 = relative11(process.cwd(), skillPath) || skillPath;
114142
+ const directory2 = relative12(process.cwd(), skillPath) || skillPath;
113825
114143
  const validation = includeValidation ? validateSkillDirectory(skill.name, skillPath, skill) : undefined;
113826
114144
  const docs = includeDocs ? buildDocs(skill.name) : undefined;
113827
114145
  return {
@@ -113887,7 +114205,7 @@ var init_registry_sync = __esm(() => {
113887
114205
 
113888
114206
  // src/lib/review-export.ts
113889
114207
  import { constants as constants22, closeSync as closeSync25, existsSync as existsSync37, fstatSync as fstatSync25, fsyncSync as fsyncSync7, lstatSync as lstatSync34, openSync as openSync25, realpathSync as realpathSync18, statSync as statSync23, writeFileSync as writeFileSync32 } from "fs";
113890
- import { basename as basename15, dirname as dirname38, isAbsolute as isAbsolute31, join as join63, parse as parse12, resolve as resolve28, sep as sep15 } from "path";
114208
+ import { basename as basename16, dirname as dirname38, isAbsolute as isAbsolute31, join as join63, parse as parse12, resolve as resolve28, sep as sep15 } from "path";
113891
114209
  function exactVersion(spec) {
113892
114210
  const at2 = spec.indexOf("@");
113893
114211
  const slug2 = spec.slice(0, at2);
@@ -113898,7 +114216,7 @@ function exactVersion(spec) {
113898
114216
  return { slug: slug2, version: version2 };
113899
114217
  }
113900
114218
  function assertPrivateDestination(output2) {
113901
- if (!isAbsolute31(output2) || resolve28(output2) !== output2 || !basename15(output2).endsWith(".tar.gz")) {
114219
+ if (!isAbsolute31(output2) || resolve28(output2) !== output2 || !basename16(output2).endsWith(".tar.gz")) {
113902
114220
  throw new Error("Review output must be an absolute, normalized .tar.gz path.");
113903
114221
  }
113904
114222
  const parent = dirname38(output2);
@@ -114670,7 +114988,7 @@ async function apiRequest(path, options, instance) {
114670
114988
  const origin = instance ?? getApiUrl(`${(options?.method || "GET").toUpperCase()} ${path}`);
114671
114989
  return new RemoteSkillsAuthClient(origin).request(path, options);
114672
114990
  }
114673
- function isRecord9(value) {
114991
+ function isRecord10(value) {
114674
114992
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
114675
114993
  }
114676
114994
  function commandErrorPayload(err, fallback) {
@@ -114684,11 +115002,11 @@ function commandErrorPayload(err, fallback) {
114684
115002
  ...err.apiUrl ? { apiUrl: err.apiUrl } : {}
114685
115003
  };
114686
115004
  }
114687
- const code2 = isRecord9(err) && typeof err.code === "string" ? err.code : undefined;
115005
+ const code2 = isRecord10(err) && typeof err.code === "string" ? err.code : undefined;
114688
115006
  return {
114689
115007
  error: err?.message || fallback,
114690
115008
  ...code2 ? { code: code2 } : {},
114691
- ...isRecord9(err) && Array.isArray(err.next) ? { next: err.next } : {}
115009
+ ...isRecord10(err) && Array.isArray(err.next) ? { next: err.next } : {}
114692
115010
  };
114693
115011
  }
114694
115012
  function writeCommandError(err, fallback, json3) {
@@ -114713,7 +115031,7 @@ function stringField2(value) {
114713
115031
  return typeof value === "string" && value.length > 0 ? value : undefined;
114714
115032
  }
114715
115033
  function recordField(value) {
114716
- return isRecord9(value) ? value : undefined;
115034
+ return isRecord10(value) ? value : undefined;
114717
115035
  }
114718
115036
  function identityApiKey(live) {
114719
115037
  const root2 = recordField(live);
@@ -115186,7 +115504,7 @@ async function runWhoami(options) {
115186
115504
  } catch {}
115187
115505
  payload.permissions = { publish: access?.permissions?.publish ?? null, profilesWrite: access?.permissions?.profilesWrite ?? null };
115188
115506
  const apiKey = identityApiKey(res);
115189
- if (access?.scopes && (apiKey === undefined || isRecord9(apiKey) && !Object.hasOwn(apiKey, "scopes"))) {
115507
+ if (access?.scopes && (apiKey === undefined || isRecord10(apiKey) && !Object.hasOwn(apiKey, "scopes"))) {
115190
115508
  payload.scopes = access.scopes;
115191
115509
  }
115192
115510
  if (options.json) {