@hasna/skills 0.10.50 → 0.10.51

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
@@ -592,10 +592,13 @@ skills hook native-catalog --cwd /absolute/project --output /private/catalog.jso
592
592
  skills hook install --agent codex --codex-native-catalog /private/catalog.json --json
593
593
  ```
594
594
 
595
- Codex 0.159.2 and 0.160.0 have measured qualified-name catalog support. Native
596
- transport, capture and review use one capability registry. Unmeasured releases
597
- refuse until the native catalog/name-denial and hook-dispatch acceptance tests
598
- pass; an RPC handshake alone does not establish those semantics.
595
+ Codex 0.159.2, 0.160.0 and 0.160.1 have measured qualified-name catalog support.
596
+ Native transport, capture and review use one capability registry of exact
597
+ releases. Unmeasured releases, including 0.160.2 and 0.161.0, refuse until the
598
+ native catalog/name-denial and hook-dispatch acceptance tests pass; an RPC
599
+ handshake alone does not establish those semantics. Admitting a release does not
600
+ admit its corpus: the transport still requires the existing native corpus
601
+ admission (see `docs/codex-corpus-writers.md`).
599
602
 
600
603
  The capture refuses an existing output file, writes mode `0600`, verifies the
601
604
  exact bytes, and reports only version, directory, count, file path and SHA-256.
@@ -643,7 +646,7 @@ different extant, witnessed user version. Individual missing files, current
643
646
  registered roots, aliases and registration changes still refuse; historical
644
647
  source hashes and typed settings witnesses remain intact.
645
648
 
646
- For a Codex 0.160.0 remote refresh omitted by an existing qualified-name disable,
649
+ For a Codex 0.160.0 or 0.160.1 remote refresh omitted by an existing qualified-name disable,
647
650
  a fresh native catalog and discovery review can plan the new exact path disable
648
651
  in the same transaction. The remote installation receipt, namespace and capability
649
652
  controls must match; conflicting enable rules, unknown names and ambiguous
package/bin/index.js CHANGED
@@ -36888,7 +36888,7 @@ var package_default;
36888
36888
  var init_package = __esm(() => {
36889
36889
  package_default = {
36890
36890
  name: "@hasna/skills",
36891
- version: "0.10.50",
36891
+ version: "0.10.51",
36892
36892
  description: "Skills library for AI coding agents",
36893
36893
  type: "module",
36894
36894
  bin: {
@@ -40269,6 +40269,29 @@ var init_sumi_settings_witness = __esm(() => {
40269
40269
  SUMI_DISCOVERY_PROJECTION_FIELDS = ["skills", "plugin", "plugins", "permissions"];
40270
40270
  });
40271
40271
 
40272
+ // src/lib/codex-native-compatibility.ts
40273
+ function supportsCodexNativeCapability(version, capability) {
40274
+ return typeof version === "string" && Object.hasOwn(MEASURED_CODEX_CAPABILITIES, version) && MEASURED_CODEX_CAPABILITIES[version].includes(capability);
40275
+ }
40276
+ var MEASURED_CODEX_CAPABILITIES, SUPPORTED_CODEX_HOOK_VERSIONS;
40277
+ var init_codex_native_compatibility = __esm(() => {
40278
+ MEASURED_CODEX_CAPABILITIES = {
40279
+ "codex-cli 0.153.0": ["hooks"],
40280
+ "codex-cli 0.154.0": ["hooks"],
40281
+ "codex-cli 0.155.0": ["hooks"],
40282
+ "codex-cli 0.155.1": ["hooks"],
40283
+ "codex-cli 0.156.1": ["hooks"],
40284
+ "codex-cli 0.157.0": ["hooks"],
40285
+ "codex-cli 0.157.1": ["hooks"],
40286
+ "codex-cli 0.158.0": ["hooks"],
40287
+ "codex-cli 0.159.0": ["hooks"],
40288
+ "codex-cli 0.159.2": ["hooks", "qualified-skill-catalog"],
40289
+ "codex-cli 0.160.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
40290
+ "codex-cli 0.160.1": ["hooks", "qualified-skill-catalog", "installed-plugin-review"]
40291
+ };
40292
+ SUPPORTED_CODEX_HOOK_VERSIONS = Object.freeze(Object.keys(MEASURED_CODEX_CAPABILITIES).filter((version) => supportsCodexNativeCapability(version, "hooks")));
40293
+ });
40294
+
40272
40295
  // src/lib/agent-policy-limits.ts
40273
40296
  import { basename as basename3, isAbsolute as isAbsolute3, join as join11, resolve as resolve4, sep as sep2 } from "path";
40274
40297
  function object(value) {
@@ -40335,7 +40358,7 @@ function assertAgentPolicyCollections(policy) {
40335
40358
  }
40336
40359
  if (bridge.codexInactivePlugins !== undefined) {
40337
40360
  const controls = array(bridge.codexInactivePlugins, 4096), ids = new Set;
40338
- requireBound(controls.length === 0 || object(bridge.codexPluginSkillReview) && bridge.codexPluginSkillReview.version === "codex-cli 0.160.0" && typeof bridge.codexPluginSkillReview.catalogSha256 === "string" && /^[a-f0-9]{64}$/.test(bridge.codexPluginSkillReview.catalogSha256));
40361
+ requireBound(controls.length === 0 || object(bridge.codexPluginSkillReview) && supportsCodexNativeCapability(bridge.codexPluginSkillReview.version, "installed-plugin-review") && typeof bridge.codexPluginSkillReview.catalogSha256 === "string" && /^[a-f0-9]{64}$/.test(bridge.codexPluginSkillReview.catalogSha256));
40339
40362
  for (const control of controls) {
40340
40363
  requireBound(object(control) && Object.keys(control).every((key) => ["pluginId", "namespace", "pluginParent", "sourceType", "sourceSha256"].includes(key)));
40341
40364
  text(control.pluginId, 1024);
@@ -40387,7 +40410,7 @@ function assertAgentPolicyCollections(policy) {
40387
40410
  }
40388
40411
  if (value.codexInstallationInputs !== undefined) {
40389
40412
  const proof = record(value.codexInstallationInputs, 4), inputs = array(proof.plugins, 4096), ids = new Set;
40390
- requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && proof.version === "codex-cli 0.160.0" && typeof proof.catalogSha256 === "string" && /^[a-f0-9]{64}$/.test(proof.catalogSha256) && inputs.length > 0 && object(bridge.codexPluginSkillReview) && bridge.codexPluginSkillReview.version === proof.version && bridge.codexPluginSkillReview.catalogSha256 === proof.catalogSha256);
40413
+ requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && supportsCodexNativeCapability(proof.version, "installed-plugin-review") && typeof proof.catalogSha256 === "string" && /^[a-f0-9]{64}$/.test(proof.catalogSha256) && inputs.length > 0 && object(bridge.codexPluginSkillReview) && bridge.codexPluginSkillReview.version === proof.version && bridge.codexPluginSkillReview.catalogSha256 === proof.catalogSha256);
40391
40414
  for (const input of inputs) {
40392
40415
  requireBound(object(input) && Object.keys(input).every((key) => ["pluginId", "namespace", "pluginParent", "sourceRoot", "sourceSha256"].includes(key)));
40393
40416
  text(input.pluginId, 1024);
@@ -40452,6 +40475,7 @@ function assertAgentPolicyCollections(policy) {
40452
40475
  }
40453
40476
  var AGENT_POLICY_LIMITS;
40454
40477
  var init_agent_policy_limits = __esm(() => {
40478
+ init_codex_native_compatibility();
40455
40479
  AGENT_POLICY_LIMITS = Object.freeze({ bytes: 1024 * 1024, agents: 16, discoverySources: 2048, discoveryRawSourceBytes: 64 * 1024 * 1024, discoveryRawTotalBytes: 256 * 1024 * 1024, discoveryPathLinks: 40, discoveryPathSteps: 256, discoveryPathSourceMetadataBytes: 64 * 1024, discoveryPathTotalMetadataBytes: 8 * 1024 * 1024, discoveryRoots: 512, discoveryDirectories: 64, discoveryDirectoryEntries: 20000, discoveryDirectoryBytes: 8 * 1024 * 1024, builtinNames: 2048, rootAliases: 2, fields: 64, pathCharacters: 4096 });
40456
40480
  });
40457
40481
 
@@ -51575,28 +51599,6 @@ function isCodexLocalStdioMcpServer(name, server) {
51575
51599
  }
51576
51600
  }
51577
51601
 
51578
- // src/lib/codex-native-compatibility.ts
51579
- function supportsCodexNativeCapability(version, capability) {
51580
- return typeof version === "string" && Object.hasOwn(MEASURED_CODEX_CAPABILITIES, version) && MEASURED_CODEX_CAPABILITIES[version].includes(capability);
51581
- }
51582
- var MEASURED_CODEX_CAPABILITIES, SUPPORTED_CODEX_HOOK_VERSIONS;
51583
- var init_codex_native_compatibility = __esm(() => {
51584
- MEASURED_CODEX_CAPABILITIES = {
51585
- "codex-cli 0.153.0": ["hooks"],
51586
- "codex-cli 0.154.0": ["hooks"],
51587
- "codex-cli 0.155.0": ["hooks"],
51588
- "codex-cli 0.155.1": ["hooks"],
51589
- "codex-cli 0.156.1": ["hooks"],
51590
- "codex-cli 0.157.0": ["hooks"],
51591
- "codex-cli 0.157.1": ["hooks"],
51592
- "codex-cli 0.158.0": ["hooks"],
51593
- "codex-cli 0.159.0": ["hooks"],
51594
- "codex-cli 0.159.2": ["hooks", "qualified-skill-catalog"],
51595
- "codex-cli 0.160.0": ["hooks", "qualified-skill-catalog"]
51596
- };
51597
- SUPPORTED_CODEX_HOOK_VERSIONS = Object.freeze(Object.keys(MEASURED_CODEX_CAPABILITIES).filter((version) => supportsCodexNativeCapability(version, "hooks")));
51598
- });
51599
-
51600
51602
  // src/lib/codex-hook-rpc.ts
51601
51603
  import { join as join20 } from "path";
51602
51604
  import { execFile, spawn as spawn2 } from "child_process";
@@ -52193,6 +52195,7 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache3, controls, read2, rules
52193
52195
  function reviewCodexPluginControls(catalog, documents, cache3, cwd2, read2, rules, pluginSettings, plannedRules, denials = []) {
52194
52196
  if (!supportsCodexNativeCapability(catalog?.version, "qualified-skill-catalog") || catalog.cwd !== cwd2)
52195
52197
  refuse2();
52198
+ const installedPluginReview = supportsCodexNativeCapability(catalog.version, "installed-plugin-review");
52196
52199
  if (!Array.isArray(denials) || denials.length > 4096 || new Set(denials.map((item) => item?.path)).size !== denials.length || denials.some((item) => !item || Object.keys(item).sort().join(",") !== "name,path,sha256" || typeof item.name !== "string" || typeof item.path !== "string" || !/^[a-f0-9]{64}$/.test(item.sha256)))
52197
52200
  refuse2();
52198
52201
  const usedDenials = new Set;
@@ -52224,7 +52227,7 @@ function reviewCodexPluginControls(catalog, documents, cache3, cwd2, read2, rule
52224
52227
  if (listed.length > 1)
52225
52228
  refuse2();
52226
52229
  const installed = installedPlugins.filter((plugin) => plugin.id === expectedPluginId && plugin.name === pluginName);
52227
- if (catalog.version === "codex-cli 0.160.0" && installed.length === 1 && installed[0].installed && installed[0].localVersion === basename6(located.root) && installed[0].sourceType === "local" && codexPluginSourceIsConfigControlled(installed[0])) {
52230
+ if (installedPluginReview && installed.length === 1 && installed[0].installed && installed[0].localVersion === basename6(located.root) && installed[0].sourceType === "local" && codexPluginSourceIsConfigControlled(installed[0])) {
52228
52231
  const plugin = installed[0], input = { pluginId: expectedPluginId, namespace: located.namespace, pluginParent: located.pluginParent, sourceRoot: plugin.sourcePath, sourceSha256: plugin.sourceSha256 };
52229
52232
  if (input.sourceRoot !== located.root && !input.sourceRoot.startsWith(cache3 + sep6) && (lstatSync13(input.sourceRoot, { throwIfNoEntry: false }) || documents.some((path) => path.startsWith(input.sourceRoot + sep6)))) {
52230
52233
  if (skills.some((skill) => skill.path === input.sourceRoot || skill.path.startsWith(input.sourceRoot + sep6)) || !sourceInputUnchanged(input, cache3, read2))
@@ -52233,7 +52236,7 @@ function reviewCodexPluginControls(catalog, documents, cache3, cwd2, read2, rule
52233
52236
  }
52234
52237
  }
52235
52238
  const settings = pluginSettings && typeof pluginSettings === "object" && !Array.isArray(pluginSettings) ? pluginSettings : undefined;
52236
- if (catalog.version === "codex-cli 0.160.0" && !listed.length && !skills.some((skill) => skill.pluginId === expectedPluginId) && installed.length === 1 && installed[0].installed && !installed[0].enabled && codexPluginSourceIsConfigControlled(installed[0]) && settings && Object.hasOwn(settings, expectedPluginId) && settings[expectedPluginId]?.enabled === false) {
52239
+ if (installedPluginReview && !listed.length && !skills.some((skill) => skill.pluginId === expectedPluginId) && installed.length === 1 && installed[0].installed && !installed[0].enabled && codexPluginSourceIsConfigControlled(installed[0]) && settings && Object.hasOwn(settings, expectedPluginId) && settings[expectedPluginId]?.enabled === false) {
52237
52240
  if (!Array.isArray(rules))
52238
52241
  refuse2();
52239
52242
  const exactPathDeny = rules.some((rule) => rule?.path === document3 && rule?.enabled === false);
@@ -52266,12 +52269,12 @@ function reviewCodexPluginControls(catalog, documents, cache3, cwd2, read2, rule
52266
52269
  const exactPathDeny = Array.isArray(rules) && rules.some((rule) => rule?.path === document3 && rule?.enabled === false);
52267
52270
  const nativeSkill = { name: parsed.name, path: document3, pluginId: expectedPluginId, enabled: true };
52268
52271
  const denial = denials.find((item) => item.path === document3);
52269
- const explicitDeny = denial !== undefined && remotePluginId !== undefined && catalog.version === "codex-cli 0.160.0" && denial.name === parsed.name && denial.sha256 === createHash12("sha256").update(read2(document3)).digest("hex") && Array.isArray(rules) && !rules.some((rule) => (rule?.path === document3 || typeof rule?.name === "string" && rule.name.trim() === parsed.name) && rule.enabled !== false) && Array.isArray(plannedRules) && plannedRules.some((rule) => rule?.path === document3 && rule.enabled === false);
52272
+ const explicitDeny = denial !== undefined && remotePluginId !== undefined && installedPluginReview && denial.name === parsed.name && denial.sha256 === createHash12("sha256").update(read2(document3)).digest("hex") && Array.isArray(rules) && !rules.some((rule) => (rule?.path === document3 || typeof rule?.name === "string" && rule.name.trim() === parsed.name) && rule.enabled !== false) && Array.isArray(plannedRules) && plannedRules.some((rule) => rule?.path === document3 && rule.enabled === false);
52270
52273
  if (denial && !explicitDeny)
52271
52274
  refuse2();
52272
52275
  if (explicitDeny)
52273
52276
  usedDenials.add(document3);
52274
- const plannedPathDeny = catalog.version === "codex-cli 0.160.0" && remotePluginId !== undefined && Array.isArray(rules) && rules.some((rule) => typeof rule?.name === "string" && rule.name.trim() === parsed.name && rule.enabled === false) && !rules.some((rule) => (rule?.path === document3 || typeof rule?.name === "string" && rule.name.trim() === parsed.name) && rule.enabled !== false) && Array.isArray(plannedRules) && plannedRules.some((rule) => rule?.path === document3 && rule.enabled === false) && isCodexNativeSkillDisabled(nativeSkill, plannedRules);
52277
+ const plannedPathDeny = installedPluginReview && remotePluginId !== undefined && Array.isArray(rules) && rules.some((rule) => typeof rule?.name === "string" && rule.name.trim() === parsed.name && rule.enabled === false) && !rules.some((rule) => (rule?.path === document3 || typeof rule?.name === "string" && rule.name.trim() === parsed.name) && rule.enabled !== false) && Array.isArray(plannedRules) && plannedRules.some((rule) => rule?.path === document3 && rule.enabled === false) && isCodexNativeSkillDisabled(nativeSkill, plannedRules);
52275
52278
  if (!explicitDeny && (!exactPathDeny && !plannedPathDeny || !isCodexNativeSkillDisabled(nativeSkill, rules)))
52276
52279
  refuse2();
52277
52280
  }
@@ -55052,7 +55055,7 @@ function planAgentIntegration(options) {
55052
55055
  const { codexInstallationInputs: previousInputs, ...current } = rebound;
55053
55056
  const inputs = codexPluginSourceInputs.map((input) => input.sourceRoot);
55054
55057
  const directories = options.codexNativeCatalog || !previousInputs ? captureDiscoveryDirectories((binding.directories ?? []).filter((directory) => inputs.some((root) => root.startsWith(directory.path + sep7))).map((directory) => directory.path), inputs) : previousInputs.directories;
55055
- const installed = codexPluginSourceInputs.length ? { ...current, codexInstallationInputs: { version: "codex-cli 0.160.0", catalogSha256: codexPluginSkillReview.catalogSha256, plugins: codexPluginSourceInputs, ...directories?.length ? { directories } : {} } } : current;
55058
+ const installed = codexPluginSourceInputs.length ? { ...current, codexInstallationInputs: { version: codexPluginSkillReview.version, catalogSha256: codexPluginSkillReview.catalogSha256, plugins: codexPluginSourceInputs, ...directories?.length ? { directories } : {} } } : current;
55056
55059
  return captureRetiredCodexDiscovery(installed, codexPluginSkills, Bun.TOML.parse(changes.find((change) => change.path === canonicalAgentPath(join28(home, ".codex/config.toml"), aliases))?.after ?? codexConfigBefore ?? "").skills?.config ?? []);
55057
55060
  });
55058
55061
  const nextPolicy = { ...policy, version: 1, loading: "cli", profileId, bridge: {
@@ -59325,7 +59328,7 @@ function codexInstallationRoots(binding) {
59325
59328
  const proof = binding.codexInstallationInputs;
59326
59329
  if (proof === undefined)
59327
59330
  return [];
59328
- if (binding.agent !== "codex" || binding.method !== "reviewed" || proof.version !== "codex-cli 0.160.0" || !/^[a-f0-9]{64}$/.test(proof.catalogSha256) || !Array.isArray(proof.plugins) || !proof.plugins.length)
59331
+ if (binding.agent !== "codex" || binding.method !== "reviewed" || !supportsCodexNativeCapability(proof.version, "installed-plugin-review") || !/^[a-f0-9]{64}$/.test(proof.catalogSha256) || !Array.isArray(proof.plugins) || !proof.plugins.length)
59329
59332
  throw new Error("Invalid native installation input proof");
59330
59333
  const cache3 = dirname19(dirname19(proof.plugins[0].pluginParent));
59331
59334
  const config = join37(dirname19(dirname19(cache3)), "config.toml"), home = dirname19(dirname19(dirname19(cache3)));
@@ -59720,6 +59723,7 @@ var init_agent_discovery = __esm(() => {
59720
59723
  init_codex_plugin_skill_controls();
59721
59724
  init_agent_sumi();
59722
59725
  init_native_discovery_roots();
59726
+ init_codex_native_compatibility();
59723
59727
  init_agent_discovery_directories();
59724
59728
  });
59725
59729
 
@@ -1909,7 +1909,7 @@ var {
1909
1909
  // src/server/maintenance-entry.ts
1910
1910
  import { closeSync, constants, fstatSync, lstatSync, openSync, readSync } from "fs";
1911
1911
  import { createHash as createHash3 } from "crypto";
1912
- var {SQL: SQL2 } = globalThis.Bun;
1912
+ var {SQL: SQL3 } = globalThis.Bun;
1913
1913
 
1914
1914
  // src/server/execution-grant-store.ts
1915
1915
  import { randomUUID } from "crypto";
@@ -3991,6 +3991,140 @@ async function inspectEnrollment(databaseUrl, input) {
3991
3991
  }
3992
3992
  }
3993
3993
 
3994
+ // src/server/schema-census.ts
3995
+ var {SQL: SQL2 } = globalThis.Bun;
3996
+
3997
+ class SchemaCensusError extends Error {
3998
+ code;
3999
+ constructor(code) {
4000
+ super(code);
4001
+ this.code = code;
4002
+ this.name = "SchemaCensusError";
4003
+ }
4004
+ }
4005
+ var refuse2 = (code) => {
4006
+ throw new SchemaCensusError(code);
4007
+ };
4008
+ var FIXED_SCHEMA = "public";
4009
+ var STATEMENT_TIMEOUT_MS = 5000;
4010
+ var LOCK_TIMEOUT_MS = 1000;
4011
+ var MAX_MIGRATION_VERSIONS = 128;
4012
+ var MAX_MIGRATION_VERSION_CHARS = 64;
4013
+ var MAX_IDENTIFIER_CHARS = 128;
4014
+ var MAX_SERVER_VERSION_CHARS = 256;
4015
+ var MAX_CENSUS_BYTES = 16 * 1024;
4016
+ var boundedText = (value, max) => {
4017
+ if (typeof value !== "string" || value.length === 0 || /[\u0000-\u001f\u007f]/.test(value))
4018
+ return refuse2("CENSUS_INVALID_RESULT");
4019
+ if (value.length > max)
4020
+ return refuse2("CENSUS_OUTPUT_UNBOUNDED");
4021
+ return value;
4022
+ };
4023
+ var boundedCount = (value) => {
4024
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0)
4025
+ return refuse2("CENSUS_INVALID_RESULT");
4026
+ return value;
4027
+ };
4028
+ async function inspectSchemaCensus(databaseUrl) {
4029
+ try {
4030
+ const url = new URL(databaseUrl);
4031
+ if (!["postgres:", "postgresql:"].includes(url.protocol) || !url.hostname)
4032
+ refuse2("CENSUS_POSTGRES_REQUIRED");
4033
+ } catch {
4034
+ refuse2("CENSUS_POSTGRES_REQUIRED");
4035
+ }
4036
+ let sql;
4037
+ try {
4038
+ sql = new SQL2(databaseUrl, { max: 1, connectionTimeout: 5, idleTimeout: 5 });
4039
+ return await sql.begin("ISOLATION LEVEL REPEATABLE READ READ ONLY", async (tx) => {
4040
+ await tx.unsafe("SET LOCAL statement_timeout = '5s'");
4041
+ await tx.unsafe("SET LOCAL lock_timeout = '1s'");
4042
+ const mode = await tx`SELECT current_setting('transaction_read_only') AS read_only,
4043
+ current_setting('transaction_isolation') AS isolation,
4044
+ current_setting('statement_timeout') AS statement_timeout,
4045
+ current_setting('lock_timeout') AS lock_timeout`;
4046
+ if (mode.length !== 1 || mode[0].read_only !== "on" || mode[0].isolation !== "repeatable read" || mode[0].statement_timeout !== "5s" || mode[0].lock_timeout !== "1s") {
4047
+ refuse2("CENSUS_FAILED");
4048
+ }
4049
+ const identity = await tx`SELECT current_database() AS database, current_user AS role,
4050
+ version() AS server_version, current_schema() AS schema`;
4051
+ if (identity.length !== 1)
4052
+ refuse2("CENSUS_INVALID_RESULT");
4053
+ const database = boundedText(identity[0].database, MAX_IDENTIFIER_CHARS);
4054
+ const role = boundedText(identity[0].role, MAX_IDENTIFIER_CHARS);
4055
+ const serverVersion = boundedText(identity[0].server_version, MAX_SERVER_VERSION_CHARS);
4056
+ if (identity[0].schema !== FIXED_SCHEMA)
4057
+ refuse2("CENSUS_TARGET_MISMATCH");
4058
+ const ledger = await tx`SELECT version FROM public.schema_migrations ORDER BY version LIMIT ${MAX_MIGRATION_VERSIONS + 1}`;
4059
+ if (ledger.length > MAX_MIGRATION_VERSIONS)
4060
+ refuse2("CENSUS_OUTPUT_UNBOUNDED");
4061
+ const versions = ledger.map((row) => boundedText(row.version, MAX_MIGRATION_VERSION_CHARS));
4062
+ const registryCount = await tx`SELECT count(*)::int AS rows FROM public.skills_registry`;
4063
+ const versionCount = await tx`SELECT count(*)::int AS rows FROM public.skills_versions`;
4064
+ if (registryCount.length !== 1 || versionCount.length !== 1)
4065
+ refuse2("CENSUS_INVALID_RESULT");
4066
+ const registryRows = boundedCount(registryCount[0].rows);
4067
+ const versionRows = boundedCount(versionCount[0].rows);
4068
+ const groups = await tx`SELECT lifecycle, (tombstoned_at IS NOT NULL) AS tombstoned, count(*)::int AS rows
4069
+ FROM public.skills_registry GROUP BY 1, 2 LIMIT 5`;
4070
+ if (groups.length > 4)
4071
+ refuse2("CENSUS_INVALID_RESULT");
4072
+ const lifecycle = { active: { live: 0, tombstoned: 0 }, archived: { live: 0, tombstoned: 0 } };
4073
+ for (const group of groups) {
4074
+ const name = group.lifecycle;
4075
+ const tombstoned = group.tombstoned;
4076
+ if (name !== "active" && name !== "archived" || typeof tombstoned !== "boolean")
4077
+ return refuse2("CENSUS_INVALID_RESULT");
4078
+ lifecycle[name][tombstoned ? "tombstoned" : "live"] = boundedCount(group.rows);
4079
+ }
4080
+ const epochColumn = await tx`SELECT count(*)::int AS rows FROM information_schema.columns
4081
+ WHERE table_schema = ${FIXED_SCHEMA} AND table_name = 'skills_registry' AND column_name = 'authorization_epoch'`;
4082
+ if (epochColumn.length !== 1)
4083
+ refuse2("CENSUS_INVALID_RESULT");
4084
+ const epochPresent = boundedCount(epochColumn[0].rows);
4085
+ if (epochPresent > 1)
4086
+ refuse2("CENSUS_INVALID_RESULT");
4087
+ let authorizationEpoch;
4088
+ if (epochPresent === 0)
4089
+ authorizationEpoch = { exists: false };
4090
+ else {
4091
+ const epochNulls = await tx`SELECT count(*)::int AS rows FROM public.skills_registry WHERE authorization_epoch IS NULL`;
4092
+ if (epochNulls.length !== 1)
4093
+ refuse2("CENSUS_INVALID_RESULT");
4094
+ authorizationEpoch = { exists: true, nullCount: boundedCount(epochNulls[0].rows) };
4095
+ }
4096
+ const result = {
4097
+ status: "inspected",
4098
+ database,
4099
+ role,
4100
+ serverVersion,
4101
+ schema: FIXED_SCHEMA,
4102
+ transaction: { readOnly: true, isolation: "repeatable read", statementTimeoutMs: STATEMENT_TIMEOUT_MS, lockTimeoutMs: LOCK_TIMEOUT_MS },
4103
+ migrations: { count: versions.length, versions },
4104
+ registry: { rows: registryRows },
4105
+ versions: { rows: versionRows },
4106
+ lifecycle,
4107
+ authorizationEpoch
4108
+ };
4109
+ if (Buffer.byteLength(JSON.stringify(result), "utf8") > MAX_CENSUS_BYTES)
4110
+ refuse2("CENSUS_OUTPUT_UNBOUNDED");
4111
+ return result;
4112
+ });
4113
+ } catch (error) {
4114
+ if (error instanceof SchemaCensusError)
4115
+ throw error;
4116
+ const state2 = error instanceof SQL2.PostgresError ? error.errno : undefined;
4117
+ const code = state2 === "42P01" || state2 === "42703" ? "CENSUS_SCHEMA_UNAVAILABLE" : state2 === "42501" ? "CENSUS_ACCESS_DENIED" : state2 === "25006" ? "CENSUS_WRITE_REFUSED" : state2 === "57014" || state2 === "55P03" ? "CENSUS_TIMEOUT" : ["08000", "08001", "08003", "08004", "08006", "08007", "08P01", "28000", "28P01", "57P03"].includes(state2 ?? "") ? "CENSUS_CONNECTION_FAILED" : "CENSUS_FAILED";
4118
+ throw new SchemaCensusError(code);
4119
+ } finally {
4120
+ try {
4121
+ await sql?.close({ timeout: 1 });
4122
+ } catch {
4123
+ throw new SchemaCensusError("CENSUS_FAILED");
4124
+ }
4125
+ }
4126
+ }
4127
+
3994
4128
  // src/server/maintenance-entry.ts
3995
4129
  class InspectionInputError extends Error {
3996
4130
  code;
@@ -3999,6 +4133,14 @@ class InspectionInputError extends Error {
3999
4133
  this.code = code;
4000
4134
  }
4001
4135
  }
4136
+
4137
+ class SchemaCensusInputError extends Error {
4138
+ code;
4139
+ constructor(code) {
4140
+ super(code);
4141
+ this.code = code;
4142
+ }
4143
+ }
4002
4144
  var MAX_MANIFEST_BYTES = 32 * 1024;
4003
4145
  function sha256(value) {
4004
4146
  return createHash3("sha256").update(value).digest("hex");
@@ -4109,6 +4251,41 @@ function readInspectionManifest(path, receiptPath) {
4109
4251
  }
4110
4252
  return parsed;
4111
4253
  }
4254
+ function readSchemaCensusManifest(path, receiptPath) {
4255
+ let input;
4256
+ let parsed;
4257
+ try {
4258
+ input = readBoundedJson(path);
4259
+ const value = input.value;
4260
+ if (!value || typeof value !== "object" || Array.isArray(value))
4261
+ throw new Error;
4262
+ const fields = ["app", "operation", "manifestVersion", "operationId", "stationId", "keyId", "orgId", "expiresAt", "manifestDigest"];
4263
+ if (Object.keys(value).length !== fields.length || fields.some((field) => !Object.hasOwn(value, field)))
4264
+ throw new Error;
4265
+ if (value.app !== "skills" || value.operation !== "inspect-schema" || value.manifestVersion !== 1)
4266
+ throw new Error;
4267
+ for (const field of ["operationId", "stationId", "keyId", "orgId"]) {
4268
+ const item = value[field];
4269
+ if (typeof item !== "string" || item.trim().length === 0 || item.length > 256 || /[\u0000-\u001f\u007f]/.test(item))
4270
+ throw new Error;
4271
+ }
4272
+ if (typeof value.expiresAt !== "string" || value.expiresAt.length > 64 || !Number.isFinite(Date.parse(value.expiresAt)) || Date.parse(value.expiresAt) <= Date.now())
4273
+ throw new Error;
4274
+ if (typeof value.manifestDigest !== "string" || !/^[a-f0-9]{64}$/.test(value.manifestDigest))
4275
+ throw new Error;
4276
+ if (sha256(canonical(value)) !== value.manifestDigest)
4277
+ throw new Error;
4278
+ parsed = value;
4279
+ } catch {
4280
+ throw new SchemaCensusInputError("INVALID_CENSUS_MANIFEST");
4281
+ }
4282
+ try {
4283
+ verifyOperatorReceipt(input, readBoundedJson(receiptPath).value);
4284
+ } catch {
4285
+ throw new SchemaCensusInputError("INVALID_OPERATOR_RECEIPT");
4286
+ }
4287
+ return parsed;
4288
+ }
4112
4289
  function registerMaintenance(parent) {
4113
4290
  const maintenance = parent.command("maintenance").description("Run protected, metadata-only Skills maintenance operations");
4114
4291
  maintenance.command("inspect-enrollment").description("Inspect one enrollment with a database-enforced read-only snapshot").requiredOption("--manifest <path>", "Fresh inspection authorization supplied by the protected task wrapper").requiredOption("--operator-receipt <path>", "Verified actor receipt written by the protected task wrapper").option("--json", "Output a safe JSON receipt", false).action(async (options) => {
@@ -4133,6 +4310,26 @@ function registerMaintenance(parent) {
4133
4310
  process.exitCode = 1;
4134
4311
  }
4135
4312
  });
4313
+ maintenance.command("inspect-schema").description("Census the fixed Skills schema and migration ledger with a database-enforced read-only snapshot").requiredOption("--manifest <path>", "Fresh census authorization supplied by the protected task wrapper").requiredOption("--operator-receipt <path>", "Verified actor receipt written by the protected task wrapper").option("--json", "Output a safe JSON receipt", false).action(async (options) => {
4314
+ try {
4315
+ const manifest = readSchemaCensusManifest(options.manifest, options.operatorReceipt);
4316
+ const census = await inspectSchemaCensus(process.env.HASNA_SKILLS_DATABASE_URL ?? "");
4317
+ console.log(JSON.stringify({
4318
+ ...census,
4319
+ operationId: manifest.operationId,
4320
+ keyId: manifest.keyId,
4321
+ orgId: manifest.orgId,
4322
+ stationId: manifest.stationId
4323
+ }));
4324
+ } catch (error) {
4325
+ const code = error instanceof SchemaCensusInputError || error instanceof SchemaCensusError ? error.code : "CENSUS_FAILED";
4326
+ if (options.json || !process.stdout.isTTY)
4327
+ console.log(JSON.stringify({ status: "failed", code }));
4328
+ else
4329
+ console.error(code);
4330
+ process.exitCode = 1;
4331
+ }
4332
+ });
4136
4333
  maintenance.command("enroll-publish").requiredOption("--manifest <path>", "Bounded target manifest supplied by the protected task wrapper").requiredOption("--operator-receipt <path>", "Verified actor receipt written by the protected task wrapper").option("--apply", "Commit the bounded scope update; defaults to dry-run", false).option("--json", "Output a safe JSON receipt", false).action(async (options) => {
4137
4334
  let manifest;
4138
4335
  let store;
@@ -4167,7 +4364,7 @@ function registerMaintenance(parent) {
4167
4364
  process.exitCode = 1;
4168
4365
  } catch (error) {
4169
4366
  const message = error instanceof Error ? error.message : "";
4170
- const state2 = error instanceof SQL2.PostgresError ? error.errno : undefined;
4367
+ const state2 = error instanceof SQL3.PostgresError ? error.errno : undefined;
4171
4368
  const code = state2 === "42P01" || state2 === "42703" ? "MAINTENANCE_SCHEMA_UNAVAILABLE" : state2 === "42501" ? "MAINTENANCE_ACCESS_DENIED" : state2 === "25006" ? "MAINTENANCE_WRITE_REFUSED" : state2 === "57014" || state2 === "55P03" ? "MAINTENANCE_TIMEOUT" : ["08000", "08001", "08003", "08004", "08006", "08007", "08P01", "28000", "28P01", "57P03"].includes(state2 ?? "") ? "MAINTENANCE_CONNECTION_FAILED" : message.includes("expired") || message.includes("expiry") ? "INVALID_EXPIRY" : message.includes("receipt") || message.includes("operator") ? "INVALID_OPERATOR_RECEIPT" : message.includes("manifest") || message.includes("input") ? "INVALID_MANIFEST" : message.includes("database") || message.includes("store") ? "STORE_UNAVAILABLE" : "MAINTENANCE_FAILED";
4172
4369
  if (options.json || !process.stdout.isTTY)
4173
4370
  console.log(JSON.stringify({ status: "failed", code }));
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.10.50",
20022
+ version: "0.10.51",
20023
20023
  description: "Skills library for AI coding agents",
20024
20024
  type: "module",
20025
20025
  bin: {
@@ -38538,6 +38538,29 @@ var init_sumi_settings_witness = __esm(() => {
38538
38538
  SUMI_DISCOVERY_PROJECTION_FIELDS = ["skills", "plugin", "plugins", "permissions"];
38539
38539
  });
38540
38540
 
38541
+ // src/lib/codex-native-compatibility.ts
38542
+ function supportsCodexNativeCapability(version2, capability) {
38543
+ return typeof version2 === "string" && Object.hasOwn(MEASURED_CODEX_CAPABILITIES, version2) && MEASURED_CODEX_CAPABILITIES[version2].includes(capability);
38544
+ }
38545
+ var MEASURED_CODEX_CAPABILITIES, SUPPORTED_CODEX_HOOK_VERSIONS;
38546
+ var init_codex_native_compatibility = __esm(() => {
38547
+ MEASURED_CODEX_CAPABILITIES = {
38548
+ "codex-cli 0.153.0": ["hooks"],
38549
+ "codex-cli 0.154.0": ["hooks"],
38550
+ "codex-cli 0.155.0": ["hooks"],
38551
+ "codex-cli 0.155.1": ["hooks"],
38552
+ "codex-cli 0.156.1": ["hooks"],
38553
+ "codex-cli 0.157.0": ["hooks"],
38554
+ "codex-cli 0.157.1": ["hooks"],
38555
+ "codex-cli 0.158.0": ["hooks"],
38556
+ "codex-cli 0.159.0": ["hooks"],
38557
+ "codex-cli 0.159.2": ["hooks", "qualified-skill-catalog"],
38558
+ "codex-cli 0.160.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
38559
+ "codex-cli 0.160.1": ["hooks", "qualified-skill-catalog", "installed-plugin-review"]
38560
+ };
38561
+ SUPPORTED_CODEX_HOOK_VERSIONS = Object.freeze(Object.keys(MEASURED_CODEX_CAPABILITIES).filter((version2) => supportsCodexNativeCapability(version2, "hooks")));
38562
+ });
38563
+
38541
38564
  // src/lib/agent-policy-limits.ts
38542
38565
  import { basename as basename4, isAbsolute as isAbsolute4, join as join10, resolve as resolve3, sep as sep3 } from "path";
38543
38566
  function object4(value) {
@@ -38604,7 +38627,7 @@ function assertAgentPolicyCollections(policy) {
38604
38627
  }
38605
38628
  if (bridge.codexInactivePlugins !== undefined) {
38606
38629
  const controls = array3(bridge.codexInactivePlugins, 4096), ids = new Set;
38607
- requireBound(controls.length === 0 || object4(bridge.codexPluginSkillReview) && bridge.codexPluginSkillReview.version === "codex-cli 0.160.0" && typeof bridge.codexPluginSkillReview.catalogSha256 === "string" && /^[a-f0-9]{64}$/.test(bridge.codexPluginSkillReview.catalogSha256));
38630
+ requireBound(controls.length === 0 || object4(bridge.codexPluginSkillReview) && supportsCodexNativeCapability(bridge.codexPluginSkillReview.version, "installed-plugin-review") && typeof bridge.codexPluginSkillReview.catalogSha256 === "string" && /^[a-f0-9]{64}$/.test(bridge.codexPluginSkillReview.catalogSha256));
38608
38631
  for (const control of controls) {
38609
38632
  requireBound(object4(control) && Object.keys(control).every((key) => ["pluginId", "namespace", "pluginParent", "sourceType", "sourceSha256"].includes(key)));
38610
38633
  text(control.pluginId, 1024);
@@ -38656,7 +38679,7 @@ function assertAgentPolicyCollections(policy) {
38656
38679
  }
38657
38680
  if (value.codexInstallationInputs !== undefined) {
38658
38681
  const proof = record3(value.codexInstallationInputs, 4), inputs = array3(proof.plugins, 4096), ids = new Set;
38659
- requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && proof.version === "codex-cli 0.160.0" && typeof proof.catalogSha256 === "string" && /^[a-f0-9]{64}$/.test(proof.catalogSha256) && inputs.length > 0 && object4(bridge.codexPluginSkillReview) && bridge.codexPluginSkillReview.version === proof.version && bridge.codexPluginSkillReview.catalogSha256 === proof.catalogSha256);
38682
+ requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && supportsCodexNativeCapability(proof.version, "installed-plugin-review") && typeof proof.catalogSha256 === "string" && /^[a-f0-9]{64}$/.test(proof.catalogSha256) && inputs.length > 0 && object4(bridge.codexPluginSkillReview) && bridge.codexPluginSkillReview.version === proof.version && bridge.codexPluginSkillReview.catalogSha256 === proof.catalogSha256);
38660
38683
  for (const input2 of inputs) {
38661
38684
  requireBound(object4(input2) && Object.keys(input2).every((key) => ["pluginId", "namespace", "pluginParent", "sourceRoot", "sourceSha256"].includes(key)));
38662
38685
  text(input2.pluginId, 1024);
@@ -38721,6 +38744,7 @@ function assertAgentPolicyCollections(policy) {
38721
38744
  }
38722
38745
  var AGENT_POLICY_LIMITS;
38723
38746
  var init_agent_policy_limits = __esm(() => {
38747
+ init_codex_native_compatibility();
38724
38748
  AGENT_POLICY_LIMITS = Object.freeze({ bytes: 1024 * 1024, agents: 16, discoverySources: 2048, discoveryRawSourceBytes: 64 * 1024 * 1024, discoveryRawTotalBytes: 256 * 1024 * 1024, discoveryPathLinks: 40, discoveryPathSteps: 256, discoveryPathSourceMetadataBytes: 64 * 1024, discoveryPathTotalMetadataBytes: 8 * 1024 * 1024, discoveryRoots: 512, discoveryDirectories: 64, discoveryDirectoryEntries: 20000, discoveryDirectoryBytes: 8 * 1024 * 1024, builtinNames: 2048, rootAliases: 2, fields: 64, pathCharacters: 4096 });
38725
38749
  });
38726
38750
 
@@ -47952,28 +47976,6 @@ function isCodexLocalStdioMcpServer(name, server) {
47952
47976
  }
47953
47977
  }
47954
47978
 
47955
- // src/lib/codex-native-compatibility.ts
47956
- function supportsCodexNativeCapability(version2, capability) {
47957
- return typeof version2 === "string" && Object.hasOwn(MEASURED_CODEX_CAPABILITIES, version2) && MEASURED_CODEX_CAPABILITIES[version2].includes(capability);
47958
- }
47959
- var MEASURED_CODEX_CAPABILITIES, SUPPORTED_CODEX_HOOK_VERSIONS;
47960
- var init_codex_native_compatibility = __esm(() => {
47961
- MEASURED_CODEX_CAPABILITIES = {
47962
- "codex-cli 0.153.0": ["hooks"],
47963
- "codex-cli 0.154.0": ["hooks"],
47964
- "codex-cli 0.155.0": ["hooks"],
47965
- "codex-cli 0.155.1": ["hooks"],
47966
- "codex-cli 0.156.1": ["hooks"],
47967
- "codex-cli 0.157.0": ["hooks"],
47968
- "codex-cli 0.157.1": ["hooks"],
47969
- "codex-cli 0.158.0": ["hooks"],
47970
- "codex-cli 0.159.0": ["hooks"],
47971
- "codex-cli 0.159.2": ["hooks", "qualified-skill-catalog"],
47972
- "codex-cli 0.160.0": ["hooks", "qualified-skill-catalog"]
47973
- };
47974
- SUPPORTED_CODEX_HOOK_VERSIONS = Object.freeze(Object.keys(MEASURED_CODEX_CAPABILITIES).filter((version2) => supportsCodexNativeCapability(version2, "hooks")));
47975
- });
47976
-
47977
47979
  // src/lib/codex-hook-rpc.ts
47978
47980
  var init_codex_hook_rpc = __esm(() => {
47979
47981
  init_codex_corpus_write();
@@ -50795,7 +50797,7 @@ function codexInstallationRoots(binding) {
50795
50797
  const proof = binding.codexInstallationInputs;
50796
50798
  if (proof === undefined)
50797
50799
  return [];
50798
- if (binding.agent !== "codex" || binding.method !== "reviewed" || proof.version !== "codex-cli 0.160.0" || !/^[a-f0-9]{64}$/.test(proof.catalogSha256) || !Array.isArray(proof.plugins) || !proof.plugins.length)
50800
+ if (binding.agent !== "codex" || binding.method !== "reviewed" || !supportsCodexNativeCapability(proof.version, "installed-plugin-review") || !/^[a-f0-9]{64}$/.test(proof.catalogSha256) || !Array.isArray(proof.plugins) || !proof.plugins.length)
50799
50801
  throw new Error("Invalid native installation input proof");
50800
50802
  const cache = dirname15(dirname15(proof.plugins[0].pluginParent));
50801
50803
  const config2 = join26(dirname15(dirname15(cache)), "config.toml"), home = dirname15(dirname15(dirname15(cache)));
@@ -51122,6 +51124,7 @@ var init_agent_discovery = __esm(() => {
51122
51124
  init_codex_plugin_skill_controls();
51123
51125
  init_agent_sumi();
51124
51126
  init_native_discovery_roots();
51127
+ init_codex_native_compatibility();
51125
51128
  init_agent_discovery_directories();
51126
51129
  });
51127
51130
 
package/bin/migrate.js CHANGED
@@ -25,7 +25,7 @@ import { join as join5 } from "path";
25
25
  // package.json
26
26
  var package_default = {
27
27
  name: "@hasna/skills",
28
- version: "0.10.50",
28
+ version: "0.10.51",
29
29
  description: "Skills library for AI coding agents",
30
30
  type: "module",
31
31
  bin: {
package/bin/server.js CHANGED
@@ -24140,7 +24140,7 @@ restoreLaunchCwd();
24140
24140
  // package.json
24141
24141
  var package_default = {
24142
24142
  name: "@hasna/skills",
24143
- version: "0.10.50",
24143
+ version: "0.10.51",
24144
24144
  description: "Skills library for AI coding agents",
24145
24145
  type: "module",
24146
24146
  bin: {
package/bin/worker.js CHANGED
@@ -24143,7 +24143,7 @@ import { randomUUID as randomUUID6 } from "crypto";
24143
24143
  // package.json
24144
24144
  var package_default = {
24145
24145
  name: "@hasna/skills",
24146
- version: "0.10.50",
24146
+ version: "0.10.51",
24147
24147
  description: "Skills library for AI coding agents",
24148
24148
  type: "module",
24149
24149
  bin: {
package/dist/index.js CHANGED
@@ -9380,6 +9380,28 @@ function upgradeSumiSettingsWitness(previous, reviewedSettingsPath) {
9380
9380
 
9381
9381
  // src/lib/agent-policy-limits.ts
9382
9382
  import { basename as basename3, isAbsolute as isAbsolute3, join as join7, resolve as resolve3, sep as sep2 } from "path";
9383
+
9384
+ // src/lib/codex-native-compatibility.ts
9385
+ var MEASURED_CODEX_CAPABILITIES = {
9386
+ "codex-cli 0.153.0": ["hooks"],
9387
+ "codex-cli 0.154.0": ["hooks"],
9388
+ "codex-cli 0.155.0": ["hooks"],
9389
+ "codex-cli 0.155.1": ["hooks"],
9390
+ "codex-cli 0.156.1": ["hooks"],
9391
+ "codex-cli 0.157.0": ["hooks"],
9392
+ "codex-cli 0.157.1": ["hooks"],
9393
+ "codex-cli 0.158.0": ["hooks"],
9394
+ "codex-cli 0.159.0": ["hooks"],
9395
+ "codex-cli 0.159.2": ["hooks", "qualified-skill-catalog"],
9396
+ "codex-cli 0.160.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
9397
+ "codex-cli 0.160.1": ["hooks", "qualified-skill-catalog", "installed-plugin-review"]
9398
+ };
9399
+ function supportsCodexNativeCapability(version, capability) {
9400
+ return typeof version === "string" && Object.hasOwn(MEASURED_CODEX_CAPABILITIES, version) && MEASURED_CODEX_CAPABILITIES[version].includes(capability);
9401
+ }
9402
+ var SUPPORTED_CODEX_HOOK_VERSIONS = Object.freeze(Object.keys(MEASURED_CODEX_CAPABILITIES).filter((version) => supportsCodexNativeCapability(version, "hooks")));
9403
+
9404
+ // src/lib/agent-policy-limits.ts
9383
9405
  var AGENT_POLICY_LIMITS = Object.freeze({ bytes: 1024 * 1024, agents: 16, discoverySources: 2048, discoveryRawSourceBytes: 64 * 1024 * 1024, discoveryRawTotalBytes: 256 * 1024 * 1024, discoveryPathLinks: 40, discoveryPathSteps: 256, discoveryPathSourceMetadataBytes: 64 * 1024, discoveryPathTotalMetadataBytes: 8 * 1024 * 1024, discoveryRoots: 512, discoveryDirectories: 64, discoveryDirectoryEntries: 20000, discoveryDirectoryBytes: 8 * 1024 * 1024, builtinNames: 2048, rootAliases: 2, fields: 64, pathCharacters: 4096 });
9384
9406
  function object(value) {
9385
9407
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
@@ -9445,7 +9467,7 @@ function assertAgentPolicyCollections(policy) {
9445
9467
  }
9446
9468
  if (bridge.codexInactivePlugins !== undefined) {
9447
9469
  const controls = array(bridge.codexInactivePlugins, 4096), ids = new Set;
9448
- requireBound(controls.length === 0 || object(bridge.codexPluginSkillReview) && bridge.codexPluginSkillReview.version === "codex-cli 0.160.0" && typeof bridge.codexPluginSkillReview.catalogSha256 === "string" && /^[a-f0-9]{64}$/.test(bridge.codexPluginSkillReview.catalogSha256));
9470
+ requireBound(controls.length === 0 || object(bridge.codexPluginSkillReview) && supportsCodexNativeCapability(bridge.codexPluginSkillReview.version, "installed-plugin-review") && typeof bridge.codexPluginSkillReview.catalogSha256 === "string" && /^[a-f0-9]{64}$/.test(bridge.codexPluginSkillReview.catalogSha256));
9449
9471
  for (const control of controls) {
9450
9472
  requireBound(object(control) && Object.keys(control).every((key) => ["pluginId", "namespace", "pluginParent", "sourceType", "sourceSha256"].includes(key)));
9451
9473
  text(control.pluginId, 1024);
@@ -9497,7 +9519,7 @@ function assertAgentPolicyCollections(policy) {
9497
9519
  }
9498
9520
  if (value.codexInstallationInputs !== undefined) {
9499
9521
  const proof = record(value.codexInstallationInputs, 4), inputs = array(proof.plugins, 4096), ids = new Set;
9500
- requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && proof.version === "codex-cli 0.160.0" && typeof proof.catalogSha256 === "string" && /^[a-f0-9]{64}$/.test(proof.catalogSha256) && inputs.length > 0 && object(bridge.codexPluginSkillReview) && bridge.codexPluginSkillReview.version === proof.version && bridge.codexPluginSkillReview.catalogSha256 === proof.catalogSha256);
9522
+ requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && supportsCodexNativeCapability(proof.version, "installed-plugin-review") && typeof proof.catalogSha256 === "string" && /^[a-f0-9]{64}$/.test(proof.catalogSha256) && inputs.length > 0 && object(bridge.codexPluginSkillReview) && bridge.codexPluginSkillReview.version === proof.version && bridge.codexPluginSkillReview.catalogSha256 === proof.catalogSha256);
9501
9523
  for (const input of inputs) {
9502
9524
  requireBound(object(input) && Object.keys(input).every((key) => ["pluginId", "namespace", "pluginParent", "sourceRoot", "sourceSha256"].includes(key)));
9503
9525
  text(input.pluginId, 1024);
@@ -11596,7 +11618,7 @@ function replaceSkillSession(expected, replacement, plan, options = {}, beforeCo
11596
11618
  // package.json
11597
11619
  var package_default = {
11598
11620
  name: "@hasna/skills",
11599
- version: "0.10.50",
11621
+ version: "0.10.51",
11600
11622
  description: "Skills library for AI coding agents",
11601
11623
  type: "module",
11602
11624
  bin: {
@@ -13684,25 +13706,6 @@ function isCodexLocalStdioMcpServer(name, server) {
13684
13706
  import { basename as basename6, dirname as dirname11, join as join17, relative as relative5, resolve as resolve10, sep as sep6 } from "path";
13685
13707
  import { lstatSync as lstatSync13, readdirSync as readdirSync6, readlinkSync as readlinkSync3, realpathSync as realpathSync6 } from "fs";
13686
13708
 
13687
- // src/lib/codex-native-compatibility.ts
13688
- var MEASURED_CODEX_CAPABILITIES = {
13689
- "codex-cli 0.153.0": ["hooks"],
13690
- "codex-cli 0.154.0": ["hooks"],
13691
- "codex-cli 0.155.0": ["hooks"],
13692
- "codex-cli 0.155.1": ["hooks"],
13693
- "codex-cli 0.156.1": ["hooks"],
13694
- "codex-cli 0.157.0": ["hooks"],
13695
- "codex-cli 0.157.1": ["hooks"],
13696
- "codex-cli 0.158.0": ["hooks"],
13697
- "codex-cli 0.159.0": ["hooks"],
13698
- "codex-cli 0.159.2": ["hooks", "qualified-skill-catalog"],
13699
- "codex-cli 0.160.0": ["hooks", "qualified-skill-catalog"]
13700
- };
13701
- function supportsCodexNativeCapability(version, capability) {
13702
- return typeof version === "string" && Object.hasOwn(MEASURED_CODEX_CAPABILITIES, version) && MEASURED_CODEX_CAPABILITIES[version].includes(capability);
13703
- }
13704
- var SUPPORTED_CODEX_HOOK_VERSIONS = Object.freeze(Object.keys(MEASURED_CODEX_CAPABILITIES).filter((version) => supportsCodexNativeCapability(version, "hooks")));
13705
-
13706
13709
  // src/lib/codex-native-skill-catalog.ts
13707
13710
  import { realpathSync as realpathSync5 } from "fs";
13708
13711
  import { isAbsolute as isAbsolute11, normalize as normalize2 } from "path";
@@ -14297,6 +14300,7 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache, controls, read2, rules)
14297
14300
  function reviewCodexPluginControls(catalog, documents, cache, cwd, read2, rules, pluginSettings, plannedRules, denials = []) {
14298
14301
  if (!supportsCodexNativeCapability(catalog?.version, "qualified-skill-catalog") || catalog.cwd !== cwd)
14299
14302
  refuse2();
14303
+ const installedPluginReview = supportsCodexNativeCapability(catalog.version, "installed-plugin-review");
14300
14304
  if (!Array.isArray(denials) || denials.length > 4096 || new Set(denials.map((item) => item?.path)).size !== denials.length || denials.some((item) => !item || Object.keys(item).sort().join(",") !== "name,path,sha256" || typeof item.name !== "string" || typeof item.path !== "string" || !/^[a-f0-9]{64}$/.test(item.sha256)))
14301
14305
  refuse2();
14302
14306
  const usedDenials = new Set;
@@ -14328,7 +14332,7 @@ function reviewCodexPluginControls(catalog, documents, cache, cwd, read2, rules,
14328
14332
  if (listed.length > 1)
14329
14333
  refuse2();
14330
14334
  const installed = installedPlugins.filter((plugin) => plugin.id === expectedPluginId && plugin.name === pluginName);
14331
- if (catalog.version === "codex-cli 0.160.0" && installed.length === 1 && installed[0].installed && installed[0].localVersion === basename6(located.root) && installed[0].sourceType === "local" && codexPluginSourceIsConfigControlled(installed[0])) {
14335
+ if (installedPluginReview && installed.length === 1 && installed[0].installed && installed[0].localVersion === basename6(located.root) && installed[0].sourceType === "local" && codexPluginSourceIsConfigControlled(installed[0])) {
14332
14336
  const plugin = installed[0], input = { pluginId: expectedPluginId, namespace: located.namespace, pluginParent: located.pluginParent, sourceRoot: plugin.sourcePath, sourceSha256: plugin.sourceSha256 };
14333
14337
  if (input.sourceRoot !== located.root && !input.sourceRoot.startsWith(cache + sep6) && (lstatSync13(input.sourceRoot, { throwIfNoEntry: false }) || documents.some((path) => path.startsWith(input.sourceRoot + sep6)))) {
14334
14338
  if (skills.some((skill) => skill.path === input.sourceRoot || skill.path.startsWith(input.sourceRoot + sep6)) || !sourceInputUnchanged(input, cache, read2))
@@ -14337,7 +14341,7 @@ function reviewCodexPluginControls(catalog, documents, cache, cwd, read2, rules,
14337
14341
  }
14338
14342
  }
14339
14343
  const settings = pluginSettings && typeof pluginSettings === "object" && !Array.isArray(pluginSettings) ? pluginSettings : undefined;
14340
- if (catalog.version === "codex-cli 0.160.0" && !listed.length && !skills.some((skill) => skill.pluginId === expectedPluginId) && installed.length === 1 && installed[0].installed && !installed[0].enabled && codexPluginSourceIsConfigControlled(installed[0]) && settings && Object.hasOwn(settings, expectedPluginId) && settings[expectedPluginId]?.enabled === false) {
14344
+ if (installedPluginReview && !listed.length && !skills.some((skill) => skill.pluginId === expectedPluginId) && installed.length === 1 && installed[0].installed && !installed[0].enabled && codexPluginSourceIsConfigControlled(installed[0]) && settings && Object.hasOwn(settings, expectedPluginId) && settings[expectedPluginId]?.enabled === false) {
14341
14345
  if (!Array.isArray(rules))
14342
14346
  refuse2();
14343
14347
  const exactPathDeny = rules.some((rule) => rule?.path === document2 && rule?.enabled === false);
@@ -14370,12 +14374,12 @@ function reviewCodexPluginControls(catalog, documents, cache, cwd, read2, rules,
14370
14374
  const exactPathDeny = Array.isArray(rules) && rules.some((rule) => rule?.path === document2 && rule?.enabled === false);
14371
14375
  const nativeSkill = { name: parsed.name, path: document2, pluginId: expectedPluginId, enabled: true };
14372
14376
  const denial = denials.find((item) => item.path === document2);
14373
- const explicitDeny = denial !== undefined && remotePluginId !== undefined && catalog.version === "codex-cli 0.160.0" && denial.name === parsed.name && denial.sha256 === createHash12("sha256").update(read2(document2)).digest("hex") && Array.isArray(rules) && !rules.some((rule) => (rule?.path === document2 || typeof rule?.name === "string" && rule.name.trim() === parsed.name) && rule.enabled !== false) && Array.isArray(plannedRules) && plannedRules.some((rule) => rule?.path === document2 && rule.enabled === false);
14377
+ const explicitDeny = denial !== undefined && remotePluginId !== undefined && installedPluginReview && denial.name === parsed.name && denial.sha256 === createHash12("sha256").update(read2(document2)).digest("hex") && Array.isArray(rules) && !rules.some((rule) => (rule?.path === document2 || typeof rule?.name === "string" && rule.name.trim() === parsed.name) && rule.enabled !== false) && Array.isArray(plannedRules) && plannedRules.some((rule) => rule?.path === document2 && rule.enabled === false);
14374
14378
  if (denial && !explicitDeny)
14375
14379
  refuse2();
14376
14380
  if (explicitDeny)
14377
14381
  usedDenials.add(document2);
14378
- const plannedPathDeny = catalog.version === "codex-cli 0.160.0" && remotePluginId !== undefined && Array.isArray(rules) && rules.some((rule) => typeof rule?.name === "string" && rule.name.trim() === parsed.name && rule.enabled === false) && !rules.some((rule) => (rule?.path === document2 || typeof rule?.name === "string" && rule.name.trim() === parsed.name) && rule.enabled !== false) && Array.isArray(plannedRules) && plannedRules.some((rule) => rule?.path === document2 && rule.enabled === false) && isCodexNativeSkillDisabled(nativeSkill, plannedRules);
14382
+ const plannedPathDeny = installedPluginReview && remotePluginId !== undefined && Array.isArray(rules) && rules.some((rule) => typeof rule?.name === "string" && rule.name.trim() === parsed.name && rule.enabled === false) && !rules.some((rule) => (rule?.path === document2 || typeof rule?.name === "string" && rule.name.trim() === parsed.name) && rule.enabled !== false) && Array.isArray(plannedRules) && plannedRules.some((rule) => rule?.path === document2 && rule.enabled === false) && isCodexNativeSkillDisabled(nativeSkill, plannedRules);
14379
14383
  if (!explicitDeny && (!exactPathDeny && !plannedPathDeny || !isCodexNativeSkillDisabled(nativeSkill, rules)))
14380
14384
  refuse2();
14381
14385
  }
@@ -16963,7 +16967,7 @@ function planAgentIntegration(options) {
16963
16967
  const { codexInstallationInputs: previousInputs, ...current } = rebound;
16964
16968
  const inputs = codexPluginSourceInputs.map((input) => input.sourceRoot);
16965
16969
  const directories = options.codexNativeCatalog || !previousInputs ? captureDiscoveryDirectories((binding.directories ?? []).filter((directory) => inputs.some((root) => root.startsWith(directory.path + sep7))).map((directory) => directory.path), inputs) : previousInputs.directories;
16966
- const installed = codexPluginSourceInputs.length ? { ...current, codexInstallationInputs: { version: "codex-cli 0.160.0", catalogSha256: codexPluginSkillReview.catalogSha256, plugins: codexPluginSourceInputs, ...directories?.length ? { directories } : {} } } : current;
16970
+ const installed = codexPluginSourceInputs.length ? { ...current, codexInstallationInputs: { version: codexPluginSkillReview.version, catalogSha256: codexPluginSkillReview.catalogSha256, plugins: codexPluginSourceInputs, ...directories?.length ? { directories } : {} } } : current;
16967
16971
  return captureRetiredCodexDiscovery(installed, codexPluginSkills, Bun.TOML.parse(changes.find((change) => change.path === canonicalAgentPath(join23(home, ".codex/config.toml"), aliases))?.after ?? codexConfigBefore ?? "").skills?.config ?? []);
16968
16972
  });
16969
16973
  const nextPolicy = { ...policy, version: 1, loading: "cli", profileId, bridge: {
@@ -20637,7 +20641,7 @@ function codexInstallationRoots(binding) {
20637
20641
  const proof = binding.codexInstallationInputs;
20638
20642
  if (proof === undefined)
20639
20643
  return [];
20640
- if (binding.agent !== "codex" || binding.method !== "reviewed" || proof.version !== "codex-cli 0.160.0" || !/^[a-f0-9]{64}$/.test(proof.catalogSha256) || !Array.isArray(proof.plugins) || !proof.plugins.length)
20644
+ if (binding.agent !== "codex" || binding.method !== "reviewed" || !supportsCodexNativeCapability(proof.version, "installed-plugin-review") || !/^[a-f0-9]{64}$/.test(proof.catalogSha256) || !Array.isArray(proof.plugins) || !proof.plugins.length)
20641
20645
  throw new Error("Invalid native installation input proof");
20642
20646
  const cache = dirname19(dirname19(proof.plugins[0].pluginParent));
20643
20647
  const config = join32(dirname19(dirname19(cache)), "config.toml"), home = dirname19(dirname19(dirname19(cache)));
@@ -28,7 +28,7 @@ export interface AgentDiscoveryBinding {
28
28
  }>;
29
29
  };
30
30
  codexInstallationInputs?: {
31
- version: "codex-cli 0.160.0";
31
+ version: string;
32
32
  catalogSha256: string;
33
33
  plugins: CodexPluginSourceInput[];
34
34
  directories?: DiscoveryDirectory[];
@@ -1,3 +1,6 @@
1
- export type CodexNativeCapability = "hooks" | "qualified-skill-catalog";
1
+ /** `installed-plugin-review`: the 0.160 `plugin/installed` source identities and
2
+ * plugin loader semantics behind local installation inputs, inert disabled
3
+ * nonremote plugins and remote refresh denials. */
4
+ export type CodexNativeCapability = "hooks" | "qualified-skill-catalog" | "installed-plugin-review";
2
5
  export declare function supportsCodexNativeCapability(version: unknown, capability: CodexNativeCapability): boolean;
3
6
  export declare const SUPPORTED_CODEX_HOOK_VERSIONS: readonly string[];
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.10.50",
32376
+ version: "0.10.51",
32377
32377
  description: "Skills library for AI coding agents",
32378
32378
  type: "module",
32379
32379
  bin: {
@@ -38426,7 +38426,8 @@ var MEASURED_CODEX_CAPABILITIES = {
38426
38426
  "codex-cli 0.158.0": ["hooks"],
38427
38427
  "codex-cli 0.159.0": ["hooks"],
38428
38428
  "codex-cli 0.159.2": ["hooks", "qualified-skill-catalog"],
38429
- "codex-cli 0.160.0": ["hooks", "qualified-skill-catalog"]
38429
+ "codex-cli 0.160.0": ["hooks", "qualified-skill-catalog", "installed-plugin-review"],
38430
+ "codex-cli 0.160.1": ["hooks", "qualified-skill-catalog", "installed-plugin-review"]
38430
38431
  };
38431
38432
  function supportsCodexNativeCapability(version, capability) {
38432
38433
  return typeof version === "string" && Object.hasOwn(MEASURED_CODEX_CAPABILITIES, version) && MEASURED_CODEX_CAPABILITIES[version].includes(capability);
@@ -39027,6 +39028,7 @@ function reviewedCodexPluginCapabilitiesUnchanged(cache, controls, read, rules)
39027
39028
  function reviewCodexPluginControls(catalog, documents, cache, cwd, read, rules, pluginSettings, plannedRules, denials = []) {
39028
39029
  if (!supportsCodexNativeCapability(catalog?.version, "qualified-skill-catalog") || catalog.cwd !== cwd)
39029
39030
  refuse3();
39031
+ const installedPluginReview = supportsCodexNativeCapability(catalog.version, "installed-plugin-review");
39030
39032
  if (!Array.isArray(denials) || denials.length > 4096 || new Set(denials.map((item) => item?.path)).size !== denials.length || denials.some((item) => !item || Object.keys(item).sort().join(",") !== "name,path,sha256" || typeof item.name !== "string" || typeof item.path !== "string" || !/^[a-f0-9]{64}$/.test(item.sha256)))
39031
39033
  refuse3();
39032
39034
  const usedDenials = new Set;
@@ -39058,7 +39060,7 @@ function reviewCodexPluginControls(catalog, documents, cache, cwd, read, rules,
39058
39060
  if (listed.length > 1)
39059
39061
  refuse3();
39060
39062
  const installed = installedPlugins.filter((plugin) => plugin.id === expectedPluginId && plugin.name === pluginName);
39061
- if (catalog.version === "codex-cli 0.160.0" && installed.length === 1 && installed[0].installed && installed[0].localVersion === basename4(located.root) && installed[0].sourceType === "local" && codexPluginSourceIsConfigControlled(installed[0])) {
39063
+ if (installedPluginReview && installed.length === 1 && installed[0].installed && installed[0].localVersion === basename4(located.root) && installed[0].sourceType === "local" && codexPluginSourceIsConfigControlled(installed[0])) {
39062
39064
  const plugin = installed[0], input = { pluginId: expectedPluginId, namespace: located.namespace, pluginParent: located.pluginParent, sourceRoot: plugin.sourcePath, sourceSha256: plugin.sourceSha256 };
39063
39065
  if (input.sourceRoot !== located.root && !input.sourceRoot.startsWith(cache + sep3) && (lstatSync7(input.sourceRoot, { throwIfNoEntry: false }) || documents.some((path) => path.startsWith(input.sourceRoot + sep3)))) {
39064
39066
  if (skills.some((skill) => skill.path === input.sourceRoot || skill.path.startsWith(input.sourceRoot + sep3)) || !sourceInputUnchanged(input, cache, read))
@@ -39067,7 +39069,7 @@ function reviewCodexPluginControls(catalog, documents, cache, cwd, read, rules,
39067
39069
  }
39068
39070
  }
39069
39071
  const settings = pluginSettings && typeof pluginSettings === "object" && !Array.isArray(pluginSettings) ? pluginSettings : undefined;
39070
- if (catalog.version === "codex-cli 0.160.0" && !listed.length && !skills.some((skill) => skill.pluginId === expectedPluginId) && installed.length === 1 && installed[0].installed && !installed[0].enabled && codexPluginSourceIsConfigControlled(installed[0]) && settings && Object.hasOwn(settings, expectedPluginId) && settings[expectedPluginId]?.enabled === false) {
39072
+ if (installedPluginReview && !listed.length && !skills.some((skill) => skill.pluginId === expectedPluginId) && installed.length === 1 && installed[0].installed && !installed[0].enabled && codexPluginSourceIsConfigControlled(installed[0]) && settings && Object.hasOwn(settings, expectedPluginId) && settings[expectedPluginId]?.enabled === false) {
39071
39073
  if (!Array.isArray(rules))
39072
39074
  refuse3();
39073
39075
  const exactPathDeny = rules.some((rule) => rule?.path === document && rule?.enabled === false);
@@ -39100,12 +39102,12 @@ function reviewCodexPluginControls(catalog, documents, cache, cwd, read, rules,
39100
39102
  const exactPathDeny = Array.isArray(rules) && rules.some((rule) => rule?.path === document && rule?.enabled === false);
39101
39103
  const nativeSkill = { name: parsed.name, path: document, pluginId: expectedPluginId, enabled: true };
39102
39104
  const denial = denials.find((item) => item.path === document);
39103
- const explicitDeny = denial !== undefined && remotePluginId !== undefined && catalog.version === "codex-cli 0.160.0" && denial.name === parsed.name && denial.sha256 === createHash8("sha256").update(read(document)).digest("hex") && Array.isArray(rules) && !rules.some((rule) => (rule?.path === document || typeof rule?.name === "string" && rule.name.trim() === parsed.name) && rule.enabled !== false) && Array.isArray(plannedRules) && plannedRules.some((rule) => rule?.path === document && rule.enabled === false);
39105
+ const explicitDeny = denial !== undefined && remotePluginId !== undefined && installedPluginReview && denial.name === parsed.name && denial.sha256 === createHash8("sha256").update(read(document)).digest("hex") && Array.isArray(rules) && !rules.some((rule) => (rule?.path === document || typeof rule?.name === "string" && rule.name.trim() === parsed.name) && rule.enabled !== false) && Array.isArray(plannedRules) && plannedRules.some((rule) => rule?.path === document && rule.enabled === false);
39104
39106
  if (denial && !explicitDeny)
39105
39107
  refuse3();
39106
39108
  if (explicitDeny)
39107
39109
  usedDenials.add(document);
39108
- const plannedPathDeny = catalog.version === "codex-cli 0.160.0" && remotePluginId !== undefined && Array.isArray(rules) && rules.some((rule) => typeof rule?.name === "string" && rule.name.trim() === parsed.name && rule.enabled === false) && !rules.some((rule) => (rule?.path === document || typeof rule?.name === "string" && rule.name.trim() === parsed.name) && rule.enabled !== false) && Array.isArray(plannedRules) && plannedRules.some((rule) => rule?.path === document && rule.enabled === false) && isCodexNativeSkillDisabled(nativeSkill, plannedRules);
39110
+ const plannedPathDeny = installedPluginReview && remotePluginId !== undefined && Array.isArray(rules) && rules.some((rule) => typeof rule?.name === "string" && rule.name.trim() === parsed.name && rule.enabled === false) && !rules.some((rule) => (rule?.path === document || typeof rule?.name === "string" && rule.name.trim() === parsed.name) && rule.enabled !== false) && Array.isArray(plannedRules) && plannedRules.some((rule) => rule?.path === document && rule.enabled === false) && isCodexNativeSkillDisabled(nativeSkill, plannedRules);
39109
39111
  if (!explicitDeny && (!exactPathDeny && !plannedPathDeny || !isCodexNativeSkillDisabled(nativeSkill, rules)))
39110
39112
  refuse3();
39111
39113
  }
@@ -40353,7 +40355,7 @@ function assertAgentPolicyCollections(policy) {
40353
40355
  }
40354
40356
  if (bridge.codexInactivePlugins !== undefined) {
40355
40357
  const controls = array(bridge.codexInactivePlugins, 4096), ids = new Set;
40356
- requireBound(controls.length === 0 || object4(bridge.codexPluginSkillReview) && bridge.codexPluginSkillReview.version === "codex-cli 0.160.0" && typeof bridge.codexPluginSkillReview.catalogSha256 === "string" && /^[a-f0-9]{64}$/.test(bridge.codexPluginSkillReview.catalogSha256));
40358
+ requireBound(controls.length === 0 || object4(bridge.codexPluginSkillReview) && supportsCodexNativeCapability(bridge.codexPluginSkillReview.version, "installed-plugin-review") && typeof bridge.codexPluginSkillReview.catalogSha256 === "string" && /^[a-f0-9]{64}$/.test(bridge.codexPluginSkillReview.catalogSha256));
40357
40359
  for (const control of controls) {
40358
40360
  requireBound(object4(control) && Object.keys(control).every((key) => ["pluginId", "namespace", "pluginParent", "sourceType", "sourceSha256"].includes(key)));
40359
40361
  text(control.pluginId, 1024);
@@ -40405,7 +40407,7 @@ function assertAgentPolicyCollections(policy) {
40405
40407
  }
40406
40408
  if (value.codexInstallationInputs !== undefined) {
40407
40409
  const proof = record3(value.codexInstallationInputs, 4), inputs = array(proof.plugins, 4096), ids = new Set;
40408
- requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && proof.version === "codex-cli 0.160.0" && typeof proof.catalogSha256 === "string" && /^[a-f0-9]{64}$/.test(proof.catalogSha256) && inputs.length > 0 && object4(bridge.codexPluginSkillReview) && bridge.codexPluginSkillReview.version === proof.version && bridge.codexPluginSkillReview.catalogSha256 === proof.catalogSha256);
40410
+ requireBound(agent === "codex" && value.agent === "codex" && value.method === "reviewed" && supportsCodexNativeCapability(proof.version, "installed-plugin-review") && typeof proof.catalogSha256 === "string" && /^[a-f0-9]{64}$/.test(proof.catalogSha256) && inputs.length > 0 && object4(bridge.codexPluginSkillReview) && bridge.codexPluginSkillReview.version === proof.version && bridge.codexPluginSkillReview.catalogSha256 === proof.catalogSha256);
40409
40411
  for (const input of inputs) {
40410
40412
  requireBound(object4(input) && Object.keys(input).every((key) => ["pluginId", "namespace", "pluginParent", "sourceRoot", "sourceSha256"].includes(key)));
40411
40413
  text(input.pluginId, 1024);
@@ -43487,7 +43489,7 @@ function codexInstallationRoots(binding) {
43487
43489
  const proof = binding.codexInstallationInputs;
43488
43490
  if (proof === undefined)
43489
43491
  return [];
43490
- if (binding.agent !== "codex" || binding.method !== "reviewed" || proof.version !== "codex-cli 0.160.0" || !/^[a-f0-9]{64}$/.test(proof.catalogSha256) || !Array.isArray(proof.plugins) || !proof.plugins.length)
43492
+ if (binding.agent !== "codex" || binding.method !== "reviewed" || !supportsCodexNativeCapability(proof.version, "installed-plugin-review") || !/^[a-f0-9]{64}$/.test(proof.catalogSha256) || !Array.isArray(proof.plugins) || !proof.plugins.length)
43491
43493
  throw new Error("Invalid native installation input proof");
43492
43494
  const cache = dirname16(dirname16(proof.plugins[0].pluginParent));
43493
43495
  const config = join26(dirname16(dirname16(cache)), "config.toml"), home = dirname16(dirname16(dirname16(cache)));
@@ -45083,7 +45085,7 @@ function planAgentIntegration(options) {
45083
45085
  const { codexInstallationInputs: previousInputs, ...current } = rebound;
45084
45086
  const inputs = codexPluginSourceInputs.map((input) => input.sourceRoot);
45085
45087
  const directories = options.codexNativeCatalog || !previousInputs ? captureDiscoveryDirectories((binding.directories ?? []).filter((directory) => inputs.some((root2) => root2.startsWith(directory.path + sep7))).map((directory) => directory.path), inputs) : previousInputs.directories;
45086
- const installed = codexPluginSourceInputs.length ? { ...current, codexInstallationInputs: { version: "codex-cli 0.160.0", catalogSha256: codexPluginSkillReview.catalogSha256, plugins: codexPluginSourceInputs, ...directories?.length ? { directories } : {} } } : current;
45088
+ const installed = codexPluginSourceInputs.length ? { ...current, codexInstallationInputs: { version: codexPluginSkillReview.version, catalogSha256: codexPluginSkillReview.catalogSha256, plugins: codexPluginSourceInputs, ...directories?.length ? { directories } : {} } } : current;
45087
45089
  return captureRetiredCodexDiscovery(installed, codexPluginSkills, Bun.TOML.parse(changes.find((change) => change.path === canonicalAgentPath(join27(home, ".codex/config.toml"), aliases))?.after ?? codexConfigBefore ?? "").skills?.config ?? []);
45088
45090
  });
45089
45091
  const nextPolicy = { ...policy, version: 1, loading: "cli", profileId, bridge: {
@@ -9,7 +9,21 @@ type InspectionManifest = EnrollmentInspectionInput & {
9
9
  expiresAt: string;
10
10
  manifestDigest: string;
11
11
  };
12
+ /** The schema census has its own authorization; no enrollment or inspection manifest can authorize it. */
13
+ type SchemaCensusManifest = {
14
+ app: "skills";
15
+ operation: "inspect-schema";
16
+ manifestVersion: 1;
17
+ operationId: string;
18
+ stationId: string;
19
+ keyId: string;
20
+ orgId: string;
21
+ expiresAt: string;
22
+ manifestDigest: string;
23
+ };
12
24
  /** Inspection has its own authorization; a failed enrollment manifest cannot authorize it. */
13
25
  export declare function readInspectionManifest(path: string, receiptPath: string): InspectionManifest;
26
+ /** The census has its own authorization; a failed enrollment or inspection manifest cannot authorize it. */
27
+ export declare function readSchemaCensusManifest(path: string, receiptPath: string): SchemaCensusManifest;
14
28
  export declare function registerMaintenance(parent: Command): void;
15
29
  export {};
@@ -0,0 +1,77 @@
1
+ /**
2
+ * One fixed, closed census of the Skills database maintenance surface.
3
+ *
4
+ * Why it exists (I6-00024): a production migration is held until the exact
5
+ * current registry, version ledger and migration ledger are read from the live
6
+ * database. The enrollment inspection answers a different question (one
7
+ * operator key), and no existing reader returns the fixed aggregate + ledger
8
+ * census. This module is that reader, and it is deliberately shaped so it
9
+ * cannot become a general SQL console:
10
+ *
11
+ * - No target, query, schema or table input exists. The only argument is the
12
+ * database URL, and the operation refuses to run unless the connection
13
+ * resolves to the fixed public schema the Skills store uses.
14
+ * - Every owned-table read is schema-qualified to `public`. A connection whose
15
+ * search path falls through to a later schema cannot substitute another
16
+ * schema's tables: a missing public table refuses (CENSUS_SCHEMA_UNAVAILABLE)
17
+ * instead of counting rows that do not belong to the fixed target.
18
+ * - The transaction is READ ONLY, REPEATABLE READ, with a five-second
19
+ * statement timeout and a one-second lock timeout, asserted from inside the
20
+ * read path rather than assumed.
21
+ * - The output is a closed shape with per-field size bounds, a bounded
22
+ * migration ledger and a total serialized-size gate. Nothing is truncated
23
+ * silently: a census that would exceed a bound refuses instead.
24
+ * - Nothing imports the application store: no initialization, migrations,
25
+ * backfills or writes happen on this path.
26
+ */
27
+ export interface SchemaCensusResult {
28
+ status: "inspected";
29
+ database: string;
30
+ role: string;
31
+ serverVersion: string;
32
+ schema: "public";
33
+ transaction: {
34
+ readOnly: true;
35
+ isolation: "repeatable read";
36
+ statementTimeoutMs: number;
37
+ lockTimeoutMs: number;
38
+ };
39
+ migrations: {
40
+ count: number;
41
+ versions: string[];
42
+ };
43
+ registry: {
44
+ rows: number;
45
+ };
46
+ versions: {
47
+ rows: number;
48
+ };
49
+ lifecycle: {
50
+ active: {
51
+ live: number;
52
+ tombstoned: number;
53
+ };
54
+ archived: {
55
+ live: number;
56
+ tombstoned: number;
57
+ };
58
+ };
59
+ authorizationEpoch: {
60
+ exists: false;
61
+ } | {
62
+ exists: true;
63
+ nullCount: number;
64
+ };
65
+ }
66
+ type CensusCode = "CENSUS_POSTGRES_REQUIRED" | "CENSUS_SCHEMA_UNAVAILABLE" | "CENSUS_ACCESS_DENIED" | "CENSUS_WRITE_REFUSED" | "CENSUS_TIMEOUT" | "CENSUS_CONNECTION_FAILED" | "CENSUS_TARGET_MISMATCH" | "CENSUS_INVALID_RESULT" | "CENSUS_OUTPUT_UNBOUNDED" | "CENSUS_FAILED";
67
+ export declare class SchemaCensusError extends Error {
68
+ readonly code: CensusCode;
69
+ constructor(code: CensusCode);
70
+ }
71
+ /**
72
+ * Census metadata only. Deliberately does not import or initialize the application store.
73
+ *
74
+ * @param databaseUrl explicit PostgreSQL URL; there is no implicit localhost fallback.
75
+ */
76
+ export declare function inspectSchemaCensus(databaseUrl: string): Promise<SchemaCensusResult>;
77
+ export {};
@@ -404,8 +404,8 @@ witness intersecting the write still refuses instead of adopting a new inode.
404
404
 
405
405
  ## Codex bundled cleanup controls
406
406
 
407
- Qualified native skill review supports a narrow subset of Codex 0.159.2 and
408
- 0.160.0's bundled cleanup hooks. The identities `browser`, `chrome`, `chrome-dev`,
407
+ Qualified native skill review supports a narrow subset of Codex 0.159.2,
408
+ 0.160.0 and 0.160.1's bundled cleanup hooks. The identities `browser`, `chrome`, `chrome-dev`,
409
409
  `chrome-internal` and `computer-use` in `openai-bundled` may call
410
410
  `node_repl.turn_ended`; `unified-computer-use` may call `cua_repl.turn_ended`.
411
411
  Only `Interrupt`, `SubagentStop` and `Stop` are accepted, with one group and one
@@ -421,4 +421,6 @@ apply and subsequent discovery checks. This review preserves native cleanup;
421
421
  it neither enables plugins nor grants hook trust, browser authority or signing.
422
422
  The upstream contracts are
423
423
  [0.159.2 bundled hooks](https://github.com/openai/codex/blob/ff6aec96948b70d94983af2641a6b67c94faeff5/codex-rs/plugin/src/bundled_hooks.rs)
424
- and [0.160.0 bundled hooks](https://github.com/openai/codex/blob/a956835d020762cb2b570053af06f643a11c0ecc/codex-rs/plugin/src/bundled_hooks.rs).
424
+ and [0.160.0 bundled hooks](https://github.com/openai/codex/blob/a956835d020762cb2b570053af06f643a11c0ecc/codex-rs/plugin/src/bundled_hooks.rs);
425
+ 0.160.1 carries the identical file
426
+ ([0.160.1 bundled hooks](https://github.com/openai/codex/blob/d27764b82f7118f674371e6d6e76271d9d606edb/codex-rs/plugin/src/bundled_hooks.rs)).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/skills",
3
- "version": "0.10.50",
3
+ "version": "0.10.51",
4
4
  "description": "Skills library for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {