@hasna/skills 0.9.8 → 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.8",
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;
@@ -108301,10 +108306,10 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
108301
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 }));
108302
108307
  const admitted = intent.admitted ?? intent.hooks;
108303
108308
  const configSha256 = intent.configSha256 ?? configBefore.sha256, configVersion = intent.configVersion ?? intent.expectedVersion;
108304
- 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 };
108305
108310
  need4(makePlanDigest(digestInput) === intent.planDigest, "RECONCILE_PLAN_CHANGED");
108306
108311
  need4(isDeepStrictEqual6(intent.hooks, admitted.filter((hook) => !hook.enabled || hook.trustStatus !== "trusted")), "RECONCILE_INTENT_HOOKS_CHANGED");
108307
- 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");
108308
108313
  const policyCurrent = snapshot(join56(dataDir3, "agent-policy.json"), true);
108309
108314
  let supersededBinding = false;
108310
108315
  if (policyCurrent.sha256 !== policyBefore.sha256) {
@@ -108342,8 +108347,11 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
108342
108347
  verifyReleaseArtifact(options.releaseProof, skillsCli);
108343
108348
  const skillsBindingChanged = !isDeepStrictEqual6(skillsCli.receipt, intent.skillsCli);
108344
108349
  need4(!skillsBindingChanged || supersededBinding, "RECONCILE_SKILLS_BINDING_CHANGED");
108345
- const alias = binding.rootAliases?.find((item) => item.agent === "codex"), codexHome = alias?.target ?? join56(home, ".codex"), hooksPath = join56(codexHome, "hooks.json");
108346
- need4(resolve22(intent.configPath) === resolve22(join56(codexHome, "config.toml")), "RECONCILE_CONFIG_PATH_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);
108347
108355
  const hooksCurrent = snapshot(hooksPath);
108348
108356
  if (hooksCurrent.sha256 !== intent.hooksSha256 && hooksCurrent.sha256 !== hooksBefore.sha256) {
108349
108357
  need4(supersededBinding, "RECONCILE_HOOKS_CHANGED");
@@ -108391,12 +108399,12 @@ async function reconcileCodexNativeHooks(options, connect = connectCodexHookRpc)
108391
108399
  }
108392
108400
  }
108393
108401
  const config2 = await rpc.request("config/read", { includeLayers: true, cwd: home });
108394
- 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);
108395
108403
  need4(layers?.length === 1 && !layers[0].disabledReason && isDeepStrictEqual6(layers[0].config, current), "RECONCILE_NATIVE_CONFIG_MISMATCH");
108396
108404
  const finalDiscovery = await rpc.request("hooks/list", { cwds: [home] });
108397
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");
108398
108406
  const finalConfig = await rpc.request("config/read", { includeLayers: true, cwd: home });
108399
- 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);
108400
108408
  need4(finalLayers?.length === 1 && isDeepStrictEqual6(finalLayers[0].config, current), "RECONCILE_NATIVE_CONFIG_CHANGED");
108401
108409
  unchanged2(stoppedFile);
108402
108410
  unchanged2(intentFile);
@@ -108426,7 +108434,10 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
108426
108434
  const policyFile = snapshot(join56(dataDir3, "agent-policy.json"), true), policy = parseManagedSkillPolicy(policyFile.text);
108427
108435
  const binding = policy.bridge, alias = binding.rootAliases?.find((item) => item.agent === "codex");
108428
108436
  const skillsCli = bindSkillsCli(binding.commands.codex, options.reviewedSkillsCli);
108429
- 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");
108430
108441
  const hooksFile = snapshot(hooksPath), configFile = snapshot(configPath, true), original = structure(configFile.text);
108431
108442
  const declarations = JSON.parse(hooksFile.text).hooks, expected = [];
108432
108443
  for (const [event, [nativeEvent, label]] of Object.entries(eventNames)) {
@@ -108457,7 +108468,7 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
108457
108468
  });
108458
108469
  const discovered = await list2(), admitted = admit(discovered);
108459
108470
  const config2 = await rpc.request("config/read", { includeLayers: true, cwd: home });
108460
- 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);
108461
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");
108462
108473
  need4(config2.config && config2.config.features?.hooks !== false, "NATIVE_HOOKS_DISABLED");
108463
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");
@@ -108471,9 +108482,9 @@ async function enrollCodexNativeHooks(options = {}, connect = connectCodexHookRp
108471
108482
  unchanged2(configFile);
108472
108483
  };
108473
108484
  checkInputs();
108474
- 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 };
108475
108486
  const planDigest = makePlanDigest(digestInput);
108476
- 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 };
108477
108488
  if (options.apply)
108478
108489
  need4(options.reviewedPlanDigest === planDigest, "PLAN_CHANGED: run the dry-run again and pass its reviewed --plan-digest with --apply");
108479
108490
  const parent = join56(dataDir3, "native-hook-trust");
@@ -108727,7 +108738,7 @@ function registerAgentIntegration(parent) {
108727
108738
  throw new Error("Native trust enrollment requires --agent codex");
108728
108739
  if (options.agent !== "codex")
108729
108740
  throw new Error("Native trust enrollment currently supports --agent codex only");
108730
- 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 });
108731
108742
  if (options.json)
108732
108743
  await writeCliOutput(JSON.stringify(result2));
108733
108744
  else
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.8",
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.8",
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.8",
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.8",
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.8",
11451
+ version: "0.9.9",
11452
11452
  description: "Skills library for AI coding agents",
11453
11453
  type: "module",
11454
11454
  bin: {
@@ -4,6 +4,7 @@ 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;
@@ -69,6 +70,7 @@ export declare function enrollCodexNativeHooks(options?: CodexNativeHookTrustOpt
69
70
  manifestSha256: string;
70
71
  };
71
72
  nativeVersion: string;
73
+ nativeConfigPath: string;
72
74
  ownedNativeProcessId: number | undefined;
73
75
  agent: string;
74
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.8",
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.8",
3
+ "version": "0.9.9",
4
4
  "description": "Skills library for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {