@hasna/skills 0.9.7 → 0.9.9

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/README.md CHANGED
@@ -120,6 +120,12 @@ skills hook trust --agent codex --apply --plan-digest <reviewed-plan-digest> --j
120
120
 
121
121
  Review the commands, current hashes, and existing trust/enable state in the
122
122
  plan. Apply refuses if the plan, package, declarations, or configuration changed.
123
+ The plan preserves the native `CODEX_HOME` choice. When unset, Codex uses
124
+ the lexical `~/.codex` path; an explicit `CODEX_HOME` resolves canonically.
125
+ Only the home root and an explicitly admitted canonical root-alias target
126
+ are accepted. Those views have separate hook identities even when they reach
127
+ the same files; enrolling one preserves the other's trust entries. Keep the
128
+ same `CODEX_HOME` choice for enrollment and the consuming agent.
123
129
  It enrolls the current exact definitions, including reviewed modified hooks,
124
130
  and preserves unrelated trust, settings, and comments. A private journal keeps
125
131
  the pre-write configuration; a failed write or verification requires journal
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.9.7",
36871
+ version: "0.9.9",
36872
36872
  description: "Skills library for AI coding agents",
36873
36873
  type: "module",
36874
36874
  bin: {
@@ -107920,9 +107920,14 @@ async function connectCodexHookRpc(options) {
107920
107920
  const current = statSync20(binary);
107921
107921
  if (realpathSync11(found) !== binary || ["dev", "ino", "size", "mtimeMs", "ctimeMs"].some((k) => stat3[k] !== current[k]))
107922
107922
  throw new Error("CODEX_HOOK_TRUST_NATIVE_EXECUTABLE_CHANGED");
107923
+ const env3 = { ...process.env, HOME: options.home, NO_COLOR: "1" };
107924
+ if (options.codexHome === undefined)
107925
+ delete env3.CODEX_HOME;
107926
+ else
107927
+ env3.CODEX_HOME = options.codexHome;
107923
107928
  const child = spawn3(binary, ["app-server", "--strict-config", "--stdio"], {
107924
107929
  cwd: options.home,
107925
- env: { ...process.env, HOME: options.home, CODEX_HOME: options.codexHome, NO_COLOR: "1" },
107930
+ env: env3,
107926
107931
  stdio: ["pipe", "pipe", "pipe"]
107927
107932
  });
107928
107933
  const pending = new Map;
@@ -108256,11 +108261,33 @@ var init_codex_hook_trust_identity = __esm(() => {
108256
108261
  });
108257
108262
 
108258
108263
  // src/lib/agent-codex-trust.ts
108259
- import { lstatSync as lstatSync28, mkdirSync as mkdirSync25, readdirSync as readdirSync20 } from "fs";
108264
+ import { lstatSync as lstatSync28, mkdirSync as mkdirSync25, readdirSync as readdirSync20, readFileSync as readFileSync37, realpathSync as realpathSync13, statSync as statSync21 } from "fs";
108260
108265
  import { createHash as createHash26, randomUUID as randomUUID10 } from "crypto";
108261
- import { join as join56, resolve as resolve22 } from "path";
108266
+ import { execFileSync } from "child_process";
108267
+ import { dirname as dirname30, isAbsolute as isAbsolute25, join as join56, resolve as resolve22 } from "path";
108262
108268
  import { homedir as homedir11 } from "os";
108263
108269
  import { isDeepStrictEqual as isDeepStrictEqual6 } from "util";
108270
+ function verifyReleaseArtifact(proof, skillsCli) {
108271
+ need4(isAbsolute25(proof.packageTarPath) && !proof.packageTarPath.includes("\x00"), "RECONCILE_RELEASE_PROVENANCE_PATH");
108272
+ const tarPath = realpathSync13(proof.packageTarPath);
108273
+ need4(statSync21(tarPath).isFile(), "RECONCILE_RELEASE_PROVENANCE_PATH");
108274
+ const tarBytes = readFileSync37(tarPath);
108275
+ need4(tarBytes.byteLength === proof.packageTarBytes && createHash26("sha256").update(tarBytes).digest("hex") === proof.packageTarSha256, "RECONCILE_RELEASE_ARTIFACT_CHANGED");
108276
+ const packageRoot = dirname30(dirname30(realpathSync13(skillsCli.receipt.path)));
108277
+ const manifest = readFileSync37(join56(packageRoot, "package.json"));
108278
+ need4(createHash26("sha256").update(manifest).digest("hex") === skillsCli.receipt.manifestSha256 && skillsCli.receipt.manifestSha256 === proof.manifestSha256, "RECONCILE_RELEASE_MANIFEST_CHANGED");
108279
+ need4(createHash26("sha256").update(readFileSync37(skillsCli.receipt.path)).digest("hex") === proof.executableSha256 && skillsCli.receipt.sha256 === proof.executableSha256, "RECONCILE_RELEASE_EXECUTABLE_CHANGED");
108280
+ const members2 = [["package/package.json", manifest], ["package/bin/index.js", readFileSync37(skillsCli.receipt.path)]];
108281
+ for (const [member, expected] of members2) {
108282
+ let actual;
108283
+ try {
108284
+ actual = execFileSync("tar", ["-xOf", tarPath, member], { maxBuffer: 32 * 1024 * 1024 });
108285
+ } catch {
108286
+ throw new Error("RECONCILE_RELEASE_ARTIFACT_MEMBER_MISSING");
108287
+ }
108288
+ need4(Buffer.compare(actual, expected) === 0, "RECONCILE_RELEASE_ARTIFACT_MEMBER_CHANGED");
108289
+ }
108290
+ }
108264
108291
  async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc) {
108265
108292
  let rpc;
108266
108293
  try {
@@ -108279,30 +108306,61 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
108279
108306
  const declarations = intent.declarations ?? intent.hooks.map((hook) => ({ event: hook.event, key: `${join56(home, ".codex/hooks.json")}${hook.key.slice(hook.key.indexOf(".codex/hooks.json") + ".codex/hooks.json".length)}`, command: hook.command }));
108280
108307
  const admitted = intent.admitted ?? intent.hooks;
108281
108308
  const configSha256 = intent.configSha256 ?? configBefore.sha256, configVersion = intent.configVersion ?? intent.expectedVersion;
108282
- const digestInput = { version: 1, home: intent.home ?? home, configPath: intent.configPath, configSha256, configVersion, policySha256: intent.policySha256, hooksSha256: intent.hooksSha256, skillsCli: intent.skillsCli, nativeVersion: intent.nativeVersion, declarations, admitted };
108309
+ 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 };
108283
108310
  need4(makePlanDigest(digestInput) === intent.planDigest, "RECONCILE_PLAN_CHANGED");
108284
108311
  need4(isDeepStrictEqual6(intent.hooks, admitted.filter((hook) => !hook.enabled || hook.trustStatus !== "trusted")), "RECONCILE_INTENT_HOOKS_CHANGED");
108285
- need4(configBefore.sha256 === intent.beforeSha256 && hooksBefore.sha256 === intent.hooksSha256 && policyBefore.sha256 === intent.policySha256, "RECONCILE_JOURNAL_CHANGED");
108312
+ need4(configBefore.sha256 === (intent.beforeSha256 ?? intent.configSha256) && hooksBefore.sha256 === intent.hooksSha256 && policyBefore.sha256 === intent.policySha256, "RECONCILE_JOURNAL_CHANGED");
108313
+ const policyCurrent = snapshot(join56(dataDir3, "agent-policy.json"), true);
108314
+ let supersededBinding = false;
108315
+ if (policyCurrent.sha256 !== policyBefore.sha256) {
108316
+ need4(options.supersedeBinding === true, "RECONCILE_POLICY_CHANGED");
108317
+ const oldPolicy = JSON.parse(policyBefore.text), currentPolicy = JSON.parse(policyCurrent.text);
108318
+ need4(isDeepStrictEqual6(withoutCodexCommand(oldPolicy), withoutCodexCommand(currentPolicy)), "RECONCILE_POLICY_CHANGED");
108319
+ supersededBinding = true;
108320
+ }
108321
+ if (supersededBinding) {
108322
+ need4(Array.isArray(intent.nativeHooks) && intent.nativeHooks.length > 0, "RECONCILE_NATIVE_INVENTORY_REQUIRED");
108323
+ const proof = options.releaseProof;
108324
+ need4(!!proof && isAbsolute25(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");
108325
+ }
108286
108326
  const currentConfig = snapshot(intent.configPath, true);
108287
108327
  const managedKeys = intent.hooks.map((h) => h.key);
108288
- need4(codexTrustReconcileWitness(configBefore.text, managedKeys) === codexTrustReconcileWitness(currentConfig.text, managedKeys), "RECONCILE_UNRELATED_CONFIG_CHANGED");
108289
- need4(codexTrustUnmanagedSemantic(configBefore.text, managedKeys) === codexTrustUnmanagedSemantic(currentConfig.text, managedKeys), "RECONCILE_UNRELATED_CONFIG_CHANGED");
108328
+ const witnessSame = codexTrustReconcileWitness(configBefore.text, managedKeys) === codexTrustReconcileWitness(currentConfig.text, managedKeys);
108329
+ const unmanagedSame = codexTrustUnmanagedSemantic(configBefore.text, managedKeys) === codexTrustUnmanagedSemantic(currentConfig.text, managedKeys);
108330
+ need4(unmanagedSame && (witnessSame || supersededBinding), "RECONCILE_UNRELATED_CONFIG_CHANGED");
108290
108331
  const before2 = structure(configBefore.text), current = structure(currentConfig.text), expectedConfig = structuredClone(before2);
108291
108332
  expectedConfig.hooks ??= {};
108292
108333
  expectedConfig.hooks.state ??= {};
108293
108334
  for (const hook of intent.hooks)
108294
108335
  expectedConfig.hooks.state[hook.key] = { ...expectedConfig.hooks.state[hook.key], enabled: true, trusted_hash: hook.currentHash };
108295
- need4(isDeepStrictEqual6(expectedConfig, current), "RECONCILE_CONFIG_DRIFT");
108296
- const policyCurrent = snapshot(join56(dataDir3, "agent-policy.json"), true);
108297
- need4(policyCurrent.sha256 === policyBefore.sha256, "RECONCILE_POLICY_CHANGED");
108298
- const policy = parseManagedSkillPolicy(policyBefore.text), binding = policy.bridge;
108336
+ if (supersededBinding) {
108337
+ for (const hook of intent.hooks) {
108338
+ const state = current.hooks?.state?.[hook.key];
108339
+ need4(state?.enabled === true && typeof state.trusted_hash === "string" && /^sha256:[a-f0-9]{64}$/.test(state.trusted_hash), "RECONCILE_CONFIG_DRIFT");
108340
+ }
108341
+ } else
108342
+ need4(isDeepStrictEqual6(expectedConfig, current), "RECONCILE_CONFIG_DRIFT");
108343
+ const policy = parseManagedSkillPolicy(policyCurrent.text), binding = policy.bridge;
108299
108344
  assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home });
108300
108345
  const skillsCli = bindSkillsCli(binding.commands.codex, options.reviewedSkillsCli);
108301
- need4(isDeepStrictEqual6(skillsCli.receipt, intent.skillsCli), "RECONCILE_SKILLS_BINDING_CHANGED");
108302
- const alias = binding.rootAliases?.find((item) => item.agent === "codex"), codexHome = alias?.target ?? join56(home, ".codex"), hooksPath = join56(codexHome, "hooks.json");
108303
- need4(resolve22(intent.configPath) === resolve22(join56(codexHome, "config.toml")), "RECONCILE_CONFIG_PATH_CHANGED");
108346
+ if (supersededBinding)
108347
+ verifyReleaseArtifact(options.releaseProof, skillsCli);
108348
+ const skillsBindingChanged = !isDeepStrictEqual6(skillsCli.receipt, intent.skillsCli);
108349
+ need4(!skillsBindingChanged || supersededBinding, "RECONCILE_SKILLS_BINDING_CHANGED");
108350
+ const alias = binding.rootAliases?.find((item) => item.agent === "codex"), physicalRoot = alias?.target ?? join56(home, ".codex"), hooksPath = join56(physicalRoot, "hooks.json");
108351
+ need4(resolve22(intent.configPath) === resolve22(join56(physicalRoot, "config.toml")), "RECONCILE_CONFIG_PATH_CHANGED");
108352
+ const nativeConfigPath = intent.nativeConfigPath ?? intent.configPath;
108353
+ need4([join56(home, ".codex/config.toml"), join56(physicalRoot, "config.toml")].includes(nativeConfigPath), "RECONCILE_NATIVE_CONFIG_PATH_CHANGED");
108354
+ const codexHome = nativeConfigPath !== intent.configPath ? undefined : dirname30(nativeConfigPath);
108304
108355
  const hooksCurrent = snapshot(hooksPath);
108305
- need4(hooksCurrent.sha256 === intent.hooksSha256 || hooksCurrent.sha256 === hooksBefore.sha256, "RECONCILE_HOOKS_CHANGED");
108356
+ if (hooksCurrent.sha256 !== intent.hooksSha256 && hooksCurrent.sha256 !== hooksBefore.sha256) {
108357
+ need4(supersededBinding, "RECONCILE_HOOKS_CHANGED");
108358
+ const currentDeclarations = JSON.parse(hooksCurrent.text).hooks;
108359
+ for (const [event, [nativeEvent]] of Object.entries(eventNames)) {
108360
+ const command = renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, event);
108361
+ need4(isDeepStrictEqual6(currentDeclarations?.[event], [{ hooks: [{ type: "command", command, timeout: 15 }] }]), "RECONCILE_BINDING_HOOK_CHANGED");
108362
+ }
108363
+ }
108306
108364
  rpc = await connect({ command: options.codexCommand ?? "codex", home, codexHome });
108307
108365
  need4(rpc.version === intent.nativeVersion, "RECONCILE_NATIVE_VERSION_CHANGED");
108308
108366
  const discovered = await rpc.request("hooks/list", { cwds: [home] });
@@ -108312,12 +108370,15 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
108312
108370
  if (recordedNativeHooks)
108313
108371
  need4(nativeHooks.length === recordedNativeHooks.length, "RECONCILE_NATIVE_HOOK_LIST_CHANGED");
108314
108372
  const plannedKeys = new Set(intent.hooks.map((hook) => hook.key));
108373
+ let nativeTrustPending = false;
108315
108374
  for (const expected of recordedNativeHooks ?? []) {
108316
108375
  const matches2 = nativeHooks.filter((hook) => hook.key === expected.key);
108317
108376
  need4(matches2.length === 1, "RECONCILE_NATIVE_HOOK_LIST_CHANGED");
108318
108377
  const actual = safeNativeHook(matches2[0]);
108319
108378
  const stable = (hook) => {
108320
108379
  const { enabled, trustStatus, ...identity4 } = hook;
108380
+ if (supersededBinding)
108381
+ delete identity4.command;
108321
108382
  return identity4;
108322
108383
  };
108323
108384
  need4(isDeepStrictEqual6(stable(actual), stable(expected)), "RECONCILE_NATIVE_IDENTITY_CHANGED");
@@ -108328,15 +108389,22 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
108328
108389
  const matches2 = nativeHooks.filter((h2) => h2.key === wanted.key || h2.key === wanted.key.replace(join56(home, ".codex/hooks.json"), hooksPath));
108329
108390
  need4(matches2.length === 1, "RECONCILE_NATIVE_IDENTITY_CHANGED");
108330
108391
  const h = matches2[0];
108331
- need4(h.enabled === true && h.trustStatus === "trusted" && h.currentHash === wanted.currentHash, "RECONCILE_NATIVE_STATE_INCOMPLETE");
108392
+ const trusted = h.trustStatus === "trusted";
108393
+ need4(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");
108394
+ if (!trusted)
108395
+ nativeTrustPending = true;
108396
+ if (supersededBinding) {
108397
+ const nativeToCliEvent = { userPromptSubmit: "UserPromptSubmit", sessionStart: "SessionStart", subagentStart: "SubagentStart" };
108398
+ need4(h.command === renderAgentHookCommand(binding.commands.codex, "codex", binding.profiles.codex, nativeToCliEvent[wanted.event] ?? ""), "RECONCILE_BINDING_HOOK_CHANGED");
108399
+ }
108332
108400
  }
108333
108401
  const config2 = await rpc.request("config/read", { includeLayers: true, cwd: home });
108334
- const layers = config2?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === intent.configPath && !layer.name.profile);
108402
+ const layers = config2?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
108335
108403
  need4(layers?.length === 1 && !layers[0].disabledReason && isDeepStrictEqual6(layers[0].config, current), "RECONCILE_NATIVE_CONFIG_MISMATCH");
108336
108404
  const finalDiscovery = await rpc.request("hooks/list", { cwds: [home] });
108337
108405
  need4(Array.isArray(finalDiscovery?.data) && finalDiscovery.data.length === 1 && finalDiscovery.data[0].cwd === home && !finalDiscovery.data[0].errors?.length && !finalDiscovery.data[0].warnings?.length && (!recordedNativeHooks || isDeepStrictEqual6(finalDiscovery.data[0].hooks.map(safeNativeHook), nativeHooks.map(safeNativeHook))), "RECONCILE_NATIVE_STATE_CHANGED");
108338
108406
  const finalConfig = await rpc.request("config/read", { includeLayers: true, cwd: home });
108339
- const finalLayers = finalConfig?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === intent.configPath && !layer.name.profile);
108407
+ const finalLayers = finalConfig?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
108340
108408
  need4(finalLayers?.length === 1 && isDeepStrictEqual6(finalLayers[0].config, current), "RECONCILE_NATIVE_CONFIG_CHANGED");
108341
108409
  unchanged2(stoppedFile);
108342
108410
  unchanged2(intentFile);
@@ -108348,7 +108416,7 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
108348
108416
  unchanged2(currentConfig);
108349
108417
  skillsCli.recheck();
108350
108418
  assertManagedAgentBridge("codex", { home, dataDir: dataDir3, projectDir: home });
108351
- const receipt = { version: 1, status: "reconciled", reconciled: true, automaticRollback: false, journal, planDigest: intent.planDigest, nativeVersion: rpc.version, nativeStateVerified: true, nativeExecutionVerified: false, configSha256: currentConfig.sha256, hooksSha256: hooksCurrent.sha256, policySha256: policyBefore.sha256, skillsCli: skillsCli.receipt, nativeInventoryScope: recordedNativeHooks ? "complete" : "declared-managed-hooks-only", unrelatedNativeHooksPreserved: !!recordedNativeHooks, unrelatedSettingsAndCommentsPreserved: true };
108419
+ const receipt = { version: 1, status: supersededBinding ? "superseded" : "reconciled", reconciled: true, supersededBinding, automaticRollback: false, journal, planDigest: intent.planDigest, nativeVersion: rpc.version, nativeStateVerified: !nativeTrustPending, nativeTrustPending, 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 };
108352
108420
  save2(join56(journal, "receipt.json"), json2(receipt));
108353
108421
  return receipt;
108354
108422
  } catch (error61) {
@@ -108366,7 +108434,10 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
108366
108434
  const policyFile = snapshot(join56(dataDir3, "agent-policy.json"), true), policy = parseManagedSkillPolicy(policyFile.text);
108367
108435
  const binding = policy.bridge, alias = binding.rootAliases?.find((item) => item.agent === "codex");
108368
108436
  const skillsCli = bindSkillsCli(binding.commands.codex, options.reviewedSkillsCli);
108369
- const codexHome = alias?.target ?? join56(home, ".codex"), hooksPath = join56(codexHome, "hooks.json"), configPath = join56(codexHome, "config.toml");
108437
+ const physicalRoot = alias?.target ?? join56(home, ".codex"), hooksPath = join56(physicalRoot, "hooks.json"), configPath = join56(physicalRoot, "config.toml");
108438
+ need4(options.codexHome === undefined || isAbsolute25(options.codexHome) && [join56(home, ".codex"), physicalRoot].includes(options.codexHome), "NATIVE_HOME_NOT_ADMITTED");
108439
+ const codexHome = options.codexHome === undefined ? undefined : physicalRoot;
108440
+ const nativeConfigPath = join56(codexHome ?? join56(home, ".codex"), "config.toml");
108370
108441
  const hooksFile = snapshot(hooksPath), configFile = snapshot(configPath, true), original = structure(configFile.text);
108371
108442
  const declarations = JSON.parse(hooksFile.text).hooks, expected = [];
108372
108443
  for (const [event, [nativeEvent, label]] of Object.entries(eventNames)) {
@@ -108397,7 +108468,7 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
108397
108468
  });
108398
108469
  const discovered = await list2(), admitted = admit(discovered);
108399
108470
  const config2 = await rpc.request("config/read", { includeLayers: true, cwd: home });
108400
- const layers = config2?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === configPath && !layer.name.profile);
108471
+ const layers = config2?.layers?.filter((layer) => layer.name?.type === "user" && layer.name.file === nativeConfigPath && !layer.name.profile);
108401
108472
  need4(layers?.length === 1 && /^sha256:[a-f0-9]{64}$/.test(layers[0].version) && !layers[0].disabledReason && isDeepStrictEqual6(layers[0].config, original), "NATIVE_CONFIG_MISMATCH");
108402
108473
  need4(config2.config && config2.config.features?.hooks !== false, "NATIVE_HOOKS_DISABLED");
108403
108474
  need4(config2.layers.slice(0, config2.layers.indexOf(layers[0])).every((layer) => layer.config?.hooks === undefined && layer.config?.features?.hooks === undefined), "NATIVE_CONFIG_OVERRIDDEN");
@@ -108411,9 +108482,9 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
108411
108482
  unchanged2(configFile);
108412
108483
  };
108413
108484
  checkInputs();
108414
- const digestInput = { version: 1, home, configPath, configSha256: configFile.sha256, configVersion: layers[0].version, policySha256: policyFile.sha256, hooksSha256: hooksFile.sha256, skillsCli: skillsCli.receipt, nativeVersion: rpc.version, declarations: expected, admitted };
108485
+ const digestInput = { version: 1, home, configPath, ...nativeConfigPath !== configPath ? { nativeConfigPath } : {}, configSha256: configFile.sha256, configVersion: layers[0].version, policySha256: policyFile.sha256, hooksSha256: hooksFile.sha256, skillsCli: skillsCli.receipt, nativeVersion: rpc.version, declarations: expected, admitted };
108415
108486
  const planDigest = makePlanDigest(digestInput);
108416
- const baseReceipt = { planDigest, skillsCli: skillsCli.receipt, nativeVersion: rpc.version, ownedNativeProcessId: rpc.processId, agent: "codex", applied: false, planned, nativeEligible: planned.length === 0, transport: "owned-stdio-process", existingSessionsReloaded: false, nativeExecutionVerified: false };
108487
+ const baseReceipt = { planDigest, skillsCli: skillsCli.receipt, nativeVersion: rpc.version, nativeConfigPath, ownedNativeProcessId: rpc.processId, agent: "codex", applied: false, planned, nativeEligible: planned.length === 0, transport: "owned-stdio-process", existingSessionsReloaded: false, nativeExecutionVerified: false };
108417
108488
  if (options.apply)
108418
108489
  need4(options.reviewedPlanDigest === planDigest, "PLAN_CHANGED: run the dry-run again and pass its reviewed --plan-digest with --apply");
108419
108490
  const parent = join56(dataDir3, "native-hook-trust");
@@ -108478,7 +108549,12 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
108478
108549
  }
108479
108550
  }
108480
108551
  var json2 = (value) => JSON.stringify(value, null, 2) + `
108481
- `, structure = (text3) => JSON.parse(JSON.stringify(Bun.TOML.parse(text3))), eventNames, makePlanDigest = (value) => createHash26("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 });
108552
+ `, structure = (text3) => JSON.parse(JSON.stringify(Bun.TOML.parse(text3))), eventNames, makePlanDigest = (value) => createHash26("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) => {
108553
+ const copy = structuredClone(value);
108554
+ if (copy?.bridge?.commands && Object.hasOwn(copy.bridge.commands, "codex"))
108555
+ copy.bridge.commands.codex = "<reviewed-codex-binding>";
108556
+ return copy;
108557
+ };
108482
108558
  var init_agent_codex_trust = __esm(() => {
108483
108559
  init_config();
108484
108560
  init_managed_policy();
@@ -108571,8 +108647,8 @@ var exports_agent_integration = {};
108571
108647
  __export(exports_agent_integration, {
108572
108648
  registerAgentIntegration: () => registerAgentIntegration
108573
108649
  });
108574
- import { readFileSync as readFileSync37 } from "fs";
108575
- import { isAbsolute as isAbsolute25 } from "path";
108650
+ import { readFileSync as readFileSync38 } from "fs";
108651
+ import { isAbsolute as isAbsolute26 } from "path";
108576
108652
  function pinnedHookProfile(input3, configuredProfile) {
108577
108653
  try {
108578
108654
  const parsed = parseSkillContextInput(JSON.stringify(input3));
@@ -108643,7 +108719,7 @@ function registerAgentIntegration(parent) {
108643
108719
  });
108644
108720
  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("--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) => {
108645
108721
  try {
108646
- const discoveryInputs = options.discoveryInputs ? JSON.parse(readFileSync37(options.discoveryInputs, "utf8")) : undefined;
108722
+ const discoveryInputs = options.discoveryInputs ? JSON.parse(readFileSync38(options.discoveryInputs, "utf8")) : undefined;
108647
108723
  const plan = planAgentIntegration({ agents: agents(options.agent), command: options.command, profileId: options.selectionProfile, includeVendor: options.includeVendor, discoveryInputs, allowRootAliases: options.allowRootAliases });
108648
108724
  const result2 = options.apply ? applyAgentIntegration(plan) : { changed: [], backups: [] };
108649
108725
  const receipt = { applied: options.apply, planned: plan.changes.map((change) => change.path), ...result2, rootAliases: plan.rootAliases ?? [], discovery: plan.discoveryAfter, nativeSkills: plan.nativeSkills.map((entry) => ({ agent: entry.agent, path: entry.path, managed: entry.managed, vendor: entry.vendor, system: entry.system === true, bridge: entry.bridge === true })), requiresNativeRetirement: plan.nativeSkills.some((entry) => !entry.bridge && !entry.system) };
@@ -108662,7 +108738,7 @@ function registerAgentIntegration(parent) {
108662
108738
  throw new Error("Native trust enrollment requires --agent codex");
108663
108739
  if (options.agent !== "codex")
108664
108740
  throw new Error("Native trust enrollment currently supports --agent codex only");
108665
- const result2 = await enrollCodexNativeHooks({ codexCommand: options.codexCommand, apply: options.apply, reviewedPlanDigest: options.planDigest });
108741
+ const result2 = await enrollCodexNativeHooks({ codexCommand: options.codexCommand, codexHome: process.env.CODEX_HOME, apply: options.apply, reviewedPlanDigest: options.planDigest });
108666
108742
  if (options.json)
108667
108743
  await writeCliOutput(JSON.stringify(result2));
108668
108744
  else
@@ -108672,11 +108748,15 @@ function registerAgentIntegration(parent) {
108672
108748
  process.exitCode = 1;
108673
108749
  }
108674
108750
  });
108675
- trust.command("reconcile").requiredOption("--agent <agent>", "Native trust adapter (codex)").requiredOption("--journal <path>", "Private incomplete native trust journal to inspect").option("--codex-command <path>", "Installed Codex executable used for its native configuration API", "codex").option("--json", "Output the reconciliation receipt", false).description("Verify an interrupted Codex native trust write and resolve its private journal").action(async (options) => {
108751
+ trust.command("reconcile").requiredOption("--agent <agent>", "Native trust adapter (codex)").requiredOption("--journal <path>", "Private incomplete native trust journal to inspect").option("--codex-command <path>", "Installed Codex executable used for its native configuration API", "codex").option("--supersede-binding", "Resolve a stale journal only when current policy differs solely by the reviewed Codex CLI binding", false).option("--skills-package-tar <path>", "Exact package tarball consumed by the reviewed executable").option("--skills-package-tar-sha256 <sha256>", "SHA-256 of the reviewed Skills package tarball").option("--skills-package-tar-bytes <bytes>", "Byte length of the reviewed Skills package tarball").option("--skills-package-manifest-sha256 <sha256>", "SHA-256 of the reviewed Skills package manifest").option("--skills-executable-sha256 <sha256>", "SHA-256 of the reviewed running Skills executable").option("--json", "Output the reconciliation receipt", false).description("Verify an interrupted Codex native trust write and resolve its private journal").action(async (options) => {
108676
108752
  try {
108677
108753
  if (options.agent !== "codex")
108678
108754
  throw new Error("Native trust reconciliation currently supports --agent codex only");
108679
- const result2 = await reconcileCodexNativeHooks({ journal: options.journal, codexCommand: options.codexCommand });
108755
+ const proofFields = [options.skillsPackageTar, options.skillsPackageTarSha256, options.skillsPackageTarBytes, options.skillsPackageManifestSha256, options.skillsExecutableSha256];
108756
+ if (proofFields.some((value) => value !== undefined) && proofFields.some((value) => value === undefined))
108757
+ throw new Error("Release provenance requires package tar path, tar hash/bytes, manifest hash, and executable hash together");
108758
+ const releaseProof = proofFields.every((value) => value !== undefined) ? { packageTarPath: options.skillsPackageTar, packageTarSha256: options.skillsPackageTarSha256, packageTarBytes: Number(options.skillsPackageTarBytes), manifestSha256: options.skillsPackageManifestSha256, executableSha256: options.skillsExecutableSha256 } : undefined;
108759
+ const result2 = await reconcileCodexNativeHooks({ journal: options.journal, codexCommand: options.codexCommand, supersedeBinding: options.supersedeBinding, releaseProof });
108680
108760
  if (options.json)
108681
108761
  await writeCliOutput(JSON.stringify(result2));
108682
108762
  else
@@ -108693,7 +108773,7 @@ function registerAgentIntegration(parent) {
108693
108773
  try {
108694
108774
  if (agents(options.agent).length !== 1)
108695
108775
  throw new Error("A hook invocation requires one agent");
108696
- const inputText = readFileSync37(0, "utf8");
108776
+ const inputText = readFileSync38(0, "utf8");
108697
108777
  if (inputText.length > 1024 * 1024)
108698
108778
  throw new Error("Hook input is too large");
108699
108779
  let input3 = JSON.parse(inputText);
@@ -108706,12 +108786,12 @@ function registerAgentIntegration(parent) {
108706
108786
  input3.hook_event_name = event;
108707
108787
  const projects = [process.cwd()];
108708
108788
  if (input3.cwd !== undefined) {
108709
- if (typeof input3.cwd !== "string" || !isAbsolute25(input3.cwd) || input3.cwd.includes("\x00"))
108789
+ if (typeof input3.cwd !== "string" || !isAbsolute26(input3.cwd) || input3.cwd.includes("\x00"))
108710
108790
  throw new Error("Invalid native hook working directory");
108711
108791
  projects.push(input3.cwd);
108712
108792
  }
108713
108793
  if (options.agent === "cursor") {
108714
- if (!Array.isArray(input3.workspace_roots) || input3.workspace_roots.length > 32 || input3.workspace_roots.some((path) => typeof path !== "string" || !isAbsolute25(path) || path.includes("\x00")))
108794
+ if (!Array.isArray(input3.workspace_roots) || input3.workspace_roots.length > 32 || input3.workspace_roots.some((path) => typeof path !== "string" || !isAbsolute26(path) || path.includes("\x00")))
108715
108795
  throw new Error("Invalid Cursor workspace roots");
108716
108796
  projects.push(...input3.workspace_roots);
108717
108797
  input3.cwd ??= input3.workspace_roots[0] ?? process.cwd();
@@ -108789,7 +108869,7 @@ function registerAgentIntegration(parent) {
108789
108869
  const migrate = parent.command("migrate").description("Preserve and retire native agent skill copies");
108790
108870
  migrate.command("native").option("--project <directory>", "Also inventory a project and its ancestors (the current directory and its ancestors are always included)").option("--include-unmanaged", "Archive user-authored skills as well as Skills-managed copies", false).option("--include-vendor", "Retire vendor SKILL.md discovery files while preserving plugin scripts and assets", false).option("--target-manifest <file>", "Reviewed exact native migration target manifest").option("--discovery-inputs <file>", "Advanced reviewed active plugin roots and source hashes").option("--allow-root-aliases", "Allow home .claude/.codex aliases to existing directories within this home", false).option("--apply", "Move selected skills to private archives outside agent discovery roots", false).option("--json", "Output inventory and archive receipt as JSON", false).description("Inventory native skill copies; preserve complete directories before retiring them").action(async (options) => {
108791
108871
  try {
108792
- const discoveryInputs = options.discoveryInputs ? JSON.parse(readFileSync37(options.discoveryInputs, "utf8")) : undefined;
108872
+ const discoveryInputs = options.discoveryInputs ? JSON.parse(readFileSync38(options.discoveryInputs, "utf8")) : undefined;
108793
108873
  if (options.targetManifest && (options.includeUnmanaged || options.includeVendor))
108794
108874
  throw new Error("--target-manifest cannot be combined with broad native migration selectors");
108795
108875
  const targetManifest = options.targetManifest ? readNativeMigrationTargetManifest(options.targetManifest) : undefined;
@@ -109094,11 +109174,11 @@ import {
109094
109174
  copyFileSync as copyFileSync2,
109095
109175
  mkdirSync as mkdirSync26,
109096
109176
  readdirSync as readdirSync21,
109097
- readFileSync as readFileSync38,
109098
- statSync as statSync21,
109177
+ readFileSync as readFileSync39,
109178
+ statSync as statSync22,
109099
109179
  writeFileSync as writeFileSync26
109100
109180
  } from "fs";
109101
- import { dirname as dirname30, join as join57, resolve as resolve23, sep as sep10 } from "path";
109181
+ import { dirname as dirname31, join as join57, resolve as resolve23, sep as sep10 } from "path";
109102
109182
  function fail5(code2, message, detail = []) {
109103
109183
  throw new StationSnapshotError(code2, message, detail);
109104
109184
  }
@@ -109110,7 +109190,7 @@ function readSnapshotManifest(repoRoot, stationId) {
109110
109190
  const manifestPath = join57(snapshotRoot, "sync-manifest.json");
109111
109191
  let manifest;
109112
109192
  try {
109113
- manifest = JSON.parse(readFileSync38(manifestPath, "utf8"));
109193
+ manifest = JSON.parse(readFileSync39(manifestPath, "utf8"));
109114
109194
  } catch (error61) {
109115
109195
  fail5("MANIFEST_UNREADABLE", `cannot read snapshot manifest: ${manifestPath}: ${error61.message}`);
109116
109196
  }
@@ -109192,7 +109272,7 @@ function planStationHydration(stationId, repoRoot) {
109192
109272
  });
109193
109273
  continue;
109194
109274
  }
109195
- const info = statSync21(entry.fullPath);
109275
+ const info = statSync22(entry.fullPath);
109196
109276
  const manifestHash = manifestHashes.get(`${agent}${MANIFEST_HASH_KEY_SEP}${homeRelative}`) ?? null;
109197
109277
  let verified = false;
109198
109278
  if (manifestHash !== null) {
@@ -109246,7 +109326,7 @@ function planStationHydration(stationId, repoRoot) {
109246
109326
  for (const copy of copies) {
109247
109327
  let isStub = false;
109248
109328
  try {
109249
- isStub = isPointerSkillMd(readFileSync38(copy.fullPath, "utf8"));
109329
+ isStub = isPointerSkillMd(readFileSync39(copy.fullPath, "utf8"));
109250
109330
  } catch {
109251
109331
  isStub = false;
109252
109332
  }
@@ -109351,7 +109431,7 @@ function writeStationHydration(options) {
109351
109431
  }
109352
109432
  let written = 0;
109353
109433
  for (const entry of toWrite) {
109354
- mkdirSync26(dirname30(entry.destination), { recursive: true });
109434
+ mkdirSync26(dirname31(entry.destination), { recursive: true });
109355
109435
  copyFileSync2(entry.fullPath, entry.destination);
109356
109436
  written += 1;
109357
109437
  }
@@ -109372,8 +109452,8 @@ function writeStationHydration(options) {
109372
109452
  },
109373
109453
  skills: resultSkills
109374
109454
  };
109375
- const hydrationManifestPath = join57(dirname30(cacheRoot), `hydration-${options.stationId}.json`);
109376
- mkdirSync26(dirname30(hydrationManifestPath), { recursive: true });
109455
+ const hydrationManifestPath = join57(dirname31(cacheRoot), `hydration-${options.stationId}.json`);
109456
+ mkdirSync26(dirname31(hydrationManifestPath), { recursive: true });
109377
109457
  writeFileSync26(hydrationManifestPath, `${JSON.stringify(hydration, null, 2)}
109378
109458
  `);
109379
109459
  return {
@@ -109450,9 +109530,9 @@ var init_hydrate = __esm(() => {
109450
109530
 
109451
109531
  // src/lib/prepare-skill.ts
109452
109532
  import { createHash as createHash28, randomUUID as randomUUID11 } from "crypto";
109453
- import { chmodSync as chmodSync3, existsSync as existsSync34, lstatSync as lstatSync29, mkdirSync as mkdirSync27, mkdtempSync as mkdtempSync6, readFileSync as readFileSync39, readdirSync as readdirSync22, renameSync as renameSync12, rmSync as rmSync9, writeFileSync as writeFileSync27 } from "fs";
109533
+ import { chmodSync as chmodSync3, existsSync as existsSync34, lstatSync as lstatSync29, mkdirSync as mkdirSync27, mkdtempSync as mkdtempSync6, readFileSync as readFileSync40, readdirSync as readdirSync22, renameSync as renameSync12, rmSync as rmSync9, writeFileSync as writeFileSync27 } from "fs";
109454
109534
  import { tmpdir as tmpdir2 } from "os";
109455
- import { dirname as dirname31, isAbsolute as isAbsolute26, join as join58, relative as relative9, resolve as resolve24, sep as sep11 } from "path";
109535
+ import { dirname as dirname32, isAbsolute as isAbsolute27, join as join58, relative as relative9, resolve as resolve24, sep as sep11 } from "path";
109456
109536
  function prepareSkill(name, options) {
109457
109537
  const normalized = normalizePortableSkillName(name);
109458
109538
  if (!new RegExp(SEMVER_PATTERN).test(options.version))
@@ -109497,7 +109577,7 @@ function prepareSkill(name, options) {
109497
109577
  mkdirSync27(join58(staging, directory2), { recursive: true });
109498
109578
  for (const file2 of before2.files) {
109499
109579
  const destination = join58(staging, file2.path);
109500
- mkdirSync27(dirname31(destination), { recursive: true });
109580
+ mkdirSync27(dirname32(destination), { recursive: true });
109501
109581
  writeFileSync27(destination, file2.bytes, { mode: file2.mode });
109502
109582
  }
109503
109583
  const stagedManifest = join58(staging, "skill.json");
@@ -109558,7 +109638,7 @@ function validateRuntimeEntrypoint(candidate2, root2) {
109558
109638
  if (typeof entry !== "string")
109559
109639
  return;
109560
109640
  const target = resolve24(root2, entry), rel = relative9(root2, target);
109561
- if (isAbsolute26(entry) || /^[a-zA-Z]:/.test(entry) || entry.includes("\\") || !rel || rel === ".." || rel.startsWith(`..${sep11}`) || isAbsolute26(rel) || !existsSync34(target) || !lstatSync29(target).isFile()) {
109641
+ if (isAbsolute27(entry) || /^[a-zA-Z]:/.test(entry) || entry.includes("\\") || !rel || rel === ".." || rel.startsWith(`..${sep11}`) || isAbsolute27(rel) || !existsSync34(target) || !lstatSync29(target).isFile()) {
109562
109642
  throw new Error("Executable runtime.entrypoint must name an existing regular file inside the skill directory.");
109563
109643
  }
109564
109644
  }
@@ -109669,7 +109749,7 @@ function snapshot2(root2) {
109669
109749
  bytes += stat3.size;
109670
109750
  if (bytes > 50000000)
109671
109751
  throw new Error("Skill exceeds the preparation size limit (50000000 bytes).");
109672
- const content = readFileSync39(absolute);
109752
+ const content = readFileSync40(absolute);
109673
109753
  if (content.length !== stat3.size)
109674
109754
  throw new Error("Skill changed during preparation.");
109675
109755
  files.push({ path, bytes: content, mode: stat3.mode & 511 });
@@ -110071,7 +110151,7 @@ var init_schedule = __esm(() => {
110071
110151
 
110072
110152
  // src/lib/registry-sync.ts
110073
110153
  import { mkdirSync as mkdirSync28, writeFileSync as writeFileSync28 } from "fs";
110074
- import { dirname as dirname32, relative as relative10 } from "path";
110154
+ import { dirname as dirname33, relative as relative10 } from "path";
110075
110155
  function createRegistrySyncArtifact(options = {}) {
110076
110156
  const profile = options.profile ?? "all";
110077
110157
  const includeDocs = options.includeDocs ?? true;
@@ -110128,7 +110208,7 @@ function createRegistrySyncArtifact(options = {}) {
110128
110208
  };
110129
110209
  }
110130
110210
  function writeRegistrySyncArtifact(path, artifact) {
110131
- mkdirSync28(dirname32(path), { recursive: true });
110211
+ mkdirSync28(dirname33(path), { recursive: true });
110132
110212
  writeFileSync28(path, `${JSON.stringify(artifact, null, 2)}
110133
110213
  `);
110134
110214
  }
@@ -110349,8 +110429,8 @@ __export(exports_publish, {
110349
110429
  buildVersionManifest: () => buildVersionManifest,
110350
110430
  PushSkillError: () => PushSkillError
110351
110431
  });
110352
- import { execFileSync } from "child_process";
110353
- import { existsSync as existsSync35, readFileSync as readFileSync40 } from "fs";
110432
+ import { execFileSync as execFileSync2 } from "child_process";
110433
+ import { existsSync as existsSync35, readFileSync as readFileSync41 } from "fs";
110354
110434
  import { hostname as hostname4 } from "os";
110355
110435
  import { join as join59 } from "path";
110356
110436
  function registerPublish(parent) {
@@ -110405,7 +110485,7 @@ async function pushSkill(name, options = {}) {
110405
110485
  await verifyPackedCanonicalHash(skill.name, packed);
110406
110486
  const versionManifest = buildVersionManifest(skill.path, packed);
110407
110487
  const skillMdPath = join59(skill.path, "SKILL.md");
110408
- const skillMd = existsSync35(skillMdPath) ? readFileSync40(skillMdPath, "utf-8") : undefined;
110488
+ const skillMd = existsSync35(skillMdPath) ? readFileSync41(skillMdPath, "utf-8") : undefined;
110409
110489
  const base3 = {
110410
110490
  slug: skill.name,
110411
110491
  path: skill.path,
@@ -110562,7 +110642,7 @@ function sanitizeGitRemote(url2) {
110562
110642
  }
110563
110643
  function gitValue(dir, args2) {
110564
110644
  try {
110565
- const out = execFileSync("git", ["-C", dir, ...args2], { stdio: ["ignore", "pipe", "ignore"], encoding: "utf-8" }).trim();
110645
+ const out = execFileSync2("git", ["-C", dir, ...args2], { stdio: ["ignore", "pipe", "ignore"], encoding: "utf-8" }).trim();
110566
110646
  return out || null;
110567
110647
  } catch {
110568
110648
  return null;
@@ -112026,11 +112106,11 @@ var init_storage2 = __esm(() => {
112026
112106
  });
112027
112107
 
112028
112108
  // src/lib/registry-reconcile.ts
112029
- import { existsSync as existsSync36, readFileSync as readFileSync41, statSync as statSync22, writeFileSync as writeFileSync29 } from "fs";
112109
+ import { existsSync as existsSync36, readFileSync as readFileSync42, statSync as statSync23, writeFileSync as writeFileSync29 } from "fs";
112030
112110
  import { join as join60 } from "path";
112031
112111
  function isDirectory2(path) {
112032
112112
  try {
112033
- return statSync22(path).isDirectory();
112113
+ return statSync23(path).isDirectory();
112034
112114
  } catch {
112035
112115
  return false;
112036
112116
  }
@@ -112046,7 +112126,7 @@ function readBaseline(skillDir) {
112046
112126
  if (!existsSync36(markerPath))
112047
112127
  return;
112048
112128
  try {
112049
- const marker = JSON.parse(readFileSync41(markerPath, "utf-8"));
112129
+ const marker = JSON.parse(readFileSync42(markerPath, "utf-8"));
112050
112130
  if (!isSkillsOwnershipMarker(marker))
112051
112131
  return;
112052
112132
  return {
@@ -112062,7 +112142,7 @@ function readCursor(root2) {
112062
112142
  if (!existsSync36(path))
112063
112143
  return { runCount: 0 };
112064
112144
  try {
112065
- const cursor2 = JSON.parse(readFileSync41(path, "utf-8"));
112145
+ const cursor2 = JSON.parse(readFileSync42(path, "utf-8"));
112066
112146
  return { runCount: typeof cursor2.runCount === "number" ? cursor2.runCount : 0 };
112067
112147
  } catch {
112068
112148
  return { runCount: 0 };
package/bin/mcp.js CHANGED
@@ -20019,7 +20019,7 @@ var package_default;
20019
20019
  var init_package = __esm(() => {
20020
20020
  package_default = {
20021
20021
  name: "@hasna/skills",
20022
- version: "0.9.7",
20022
+ version: "0.9.9",
20023
20023
  description: "Skills library for AI coding agents",
20024
20024
  type: "module",
20025
20025
  bin: {
package/bin/migrate.js CHANGED
@@ -7,7 +7,7 @@ import { join as join5 } from "path";
7
7
  // package.json
8
8
  var package_default = {
9
9
  name: "@hasna/skills",
10
- version: "0.9.7",
10
+ version: "0.9.9",
11
11
  description: "Skills library for AI coding agents",
12
12
  type: "module",
13
13
  bin: {
package/bin/server.js CHANGED
@@ -24122,7 +24122,7 @@ var init_dist_es9 = __esm(() => {
24122
24122
  // package.json
24123
24123
  var package_default = {
24124
24124
  name: "@hasna/skills",
24125
- version: "0.9.7",
24125
+ version: "0.9.9",
24126
24126
  description: "Skills library for AI coding agents",
24127
24127
  type: "module",
24128
24128
  bin: {
package/bin/worker.js CHANGED
@@ -24125,7 +24125,7 @@ import { randomUUID as randomUUID6 } from "crypto";
24125
24125
  // package.json
24126
24126
  var package_default = {
24127
24127
  name: "@hasna/skills",
24128
- version: "0.9.7",
24128
+ version: "0.9.9",
24129
24129
  description: "Skills library for AI coding agents",
24130
24130
  type: "module",
24131
24131
  bin: {
package/dist/index.js CHANGED
@@ -11448,7 +11448,7 @@ import { isAbsolute as isAbsolute10, join as join20, resolve as resolve10 } from
11448
11448
  // package.json
11449
11449
  var package_default = {
11450
11450
  name: "@hasna/skills",
11451
- version: "0.9.7",
11451
+ version: "0.9.9",
11452
11452
  description: "Skills library for AI coding agents",
11453
11453
  type: "module",
11454
11454
  bin: {
@@ -4,16 +4,26 @@ export interface CodexNativeHookTrustOptions {
4
4
  home?: string;
5
5
  dataDir?: string;
6
6
  codexCommand?: string;
7
+ codexHome?: string;
7
8
  apply?: boolean;
8
9
  reviewedPlanDigest?: string;
9
10
  reviewedSkillsCli?: ReviewedSkillsCli;
10
11
  }
12
+ export interface SkillsCliReleaseProof {
13
+ packageTarPath: string;
14
+ packageTarSha256: string;
15
+ packageTarBytes: number;
16
+ manifestSha256: string;
17
+ executableSha256: string;
18
+ }
11
19
  export interface CodexNativeHookReconcileOptions {
12
20
  home?: string;
13
21
  dataDir?: string;
14
22
  codexCommand?: string;
15
23
  journal: string;
16
24
  reviewedSkillsCli?: ReviewedSkillsCli;
25
+ releaseProof?: SkillsCliReleaseProof;
26
+ supersedeBinding?: boolean;
17
27
  }
18
28
  type Connect = typeof connectCodexHookRpc;
19
29
  /** Resolve an interrupted native write only after the native consumer and every
@@ -24,21 +34,27 @@ export declare function reconcileCodexNativeHooks(options: CodexNativeHookReconc
24
34
  version: number;
25
35
  status: string;
26
36
  reconciled: boolean;
37
+ supersededBinding: boolean;
27
38
  automaticRollback: boolean;
28
39
  journal: string;
29
40
  planDigest: any;
30
41
  nativeVersion: string;
31
42
  nativeStateVerified: boolean;
43
+ nativeTrustPending: boolean;
32
44
  nativeExecutionVerified: boolean;
33
45
  configSha256: string;
34
46
  hooksSha256: string;
35
47
  policySha256: string;
48
+ policyBeforeSha256: string;
49
+ policyCurrentSha256: string;
50
+ previousSkillsCli: any;
36
51
  skillsCli: {
37
52
  path: string;
38
53
  version: string;
39
54
  sha256: string;
40
55
  manifestSha256: string;
41
56
  };
57
+ releaseProof: SkillsCliReleaseProof | undefined;
42
58
  nativeInventoryScope: string;
43
59
  unrelatedNativeHooksPreserved: boolean;
44
60
  unrelatedSettingsAndCommentsPreserved: boolean;
@@ -54,6 +70,7 @@ export declare function enrollCodexNativeHooks(options?: CodexNativeHookTrustOpt
54
70
  manifestSha256: string;
55
71
  };
56
72
  nativeVersion: string;
73
+ nativeConfigPath: string;
57
74
  ownedNativeProcessId: number | undefined;
58
75
  agent: string;
59
76
  applied: boolean;
@@ -9,5 +9,5 @@ export interface CodexHookRpc {
9
9
  export declare function connectCodexHookRpc(options: {
10
10
  command: string;
11
11
  home: string;
12
- codexHome: string;
12
+ codexHome?: string;
13
13
  }): Promise<CodexHookRpc>;
package/dist/sdk/index.js CHANGED
@@ -32373,7 +32373,7 @@ var init_event_sink = __esm(() => {
32373
32373
  // package.json
32374
32374
  var package_default = {
32375
32375
  name: "@hasna/skills",
32376
- version: "0.9.7",
32376
+ version: "0.9.9",
32377
32377
  description: "Skills library for AI coding agents",
32378
32378
  type: "module",
32379
32379
  bin: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/skills",
3
- "version": "0.9.7",
3
+ "version": "0.9.9",
4
4
  "description": "Skills library for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {