@hasna/skills 0.10.30 → 0.10.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/index.js CHANGED
@@ -36868,7 +36868,7 @@ var package_default;
36868
36868
  var init_package = __esm(() => {
36869
36869
  package_default = {
36870
36870
  name: "@hasna/skills",
36871
- version: "0.10.30",
36871
+ version: "0.10.31",
36872
36872
  description: "Skills library for AI coding agents",
36873
36873
  type: "module",
36874
36874
  bin: {
@@ -51369,6 +51369,29 @@ function mcpControls(path, read2) {
51369
51369
  refuse2();
51370
51370
  return sha2562;
51371
51371
  }
51372
+ function isBundledCleanupHooks(root, namespace, value) {
51373
+ const object5 = (v) => Boolean(v && typeof v === "object" && !Array.isArray(v));
51374
+ const exactKeys = (v, keys2) => Object.keys(v).length === keys2.length && keys2.every((key) => Object.hasOwn(v, key));
51375
+ if (basename5(dirname10(root)) !== namespace || basename5(dirname10(dirname10(root))) !== "openai-bundled")
51376
+ return false;
51377
+ const server = namespace === "unified-computer-use" ? "cua_repl" : ["browser", "chrome", "chrome-dev", "chrome-internal", "computer-use"].includes(namespace) ? "node_repl" : undefined;
51378
+ if (!server || !object5(value) || !exactKeys(value, ["hooks"]) || !object5(value.hooks))
51379
+ return false;
51380
+ const events = Object.entries(value.hooks);
51381
+ if (!events.length || events.length > 3)
51382
+ return false;
51383
+ for (const [event, groups] of events) {
51384
+ if (!["Interrupt", "SubagentStop", "Stop"].includes(event) || !Array.isArray(groups) || groups.length !== 1)
51385
+ return false;
51386
+ const group = groups[0];
51387
+ if (!object5(group) || !exactKeys(group, ["hooks"]) || !Array.isArray(group.hooks) || group.hooks.length !== 1)
51388
+ return false;
51389
+ const handler = group.hooks[0];
51390
+ if (!object5(handler) || !exactKeys(handler, ["type", "server", "tool", "input"]) || handler.type !== "mcp_tool" || handler.server !== server || handler.tool !== "turn_ended" || !object5(handler.input) || !exactKeys(handler.input, ["hook_event_name", "session_id", "turn_id"]) || handler.input.hook_event_name !== "${hook_event_name}" || handler.input.turn_id !== "${turn_id}" || handler.input.session_id !== (event === "SubagentStop" ? "${agent_id}" : "${session_id}"))
51391
+ return false;
51392
+ }
51393
+ return true;
51394
+ }
51372
51395
  function rootControls(root, read2) {
51373
51396
  const manifestPath = join18(root, ".codex-plugin/plugin.json"), manifestFile = lstatSync12(manifestPath, { throwIfNoEntry: false });
51374
51397
  if (!lstatSync12(join18(root, ".codex-plugin"), { throwIfNoEntry: false })?.isDirectory() || !manifestFile?.isFile() || manifestFile.size > 1024 * 1024)
@@ -51386,9 +51409,11 @@ function rootControls(root, read2) {
51386
51409
  const cacheVersion = basename5(root), declaredVersion = manifest.version === undefined ? "" : typeof manifest.version === "string" ? manifest.version.trim() : null;
51387
51410
  if (declaredVersion === null || (declaredVersion ? declaredVersion !== cacheVersion : cacheVersion !== CODEX_DEFAULT_AGENT_PLUGIN_VERSION))
51388
51411
  refuse2();
51389
- if (manifest.hooks !== undefined || manifest.commands !== undefined || manifest.mcpServers !== undefined && manifest.mcpServers !== "./.mcp.json" || manifest.apps !== undefined && manifest.apps !== "./.app.json" || lstatSync12(join18(root, "hooks"), { throwIfNoEntry: false }))
51412
+ if (manifest.hooks !== undefined && !isBundledCleanupHooks(root, manifest.name, manifest.hooks) || manifest.commands !== undefined || manifest.mcpServers !== undefined && manifest.mcpServers !== "./.mcp.json" || manifest.apps !== undefined && manifest.apps !== "./.app.json" || lstatSync12(join18(root, "hooks"), { throwIfNoEntry: false }))
51390
51413
  refuse2();
51391
51414
  const mcp = join18(root, ".mcp.json"), mcpPresent = lstatSync12(mcp, { throwIfNoEntry: false });
51415
+ if (manifest.hooks !== undefined && (manifest.mcpServers !== undefined || mcpPresent))
51416
+ refuse2();
51392
51417
  if (mcpPresent && (!mcpPresent.isFile() || mcpPresent.isSymbolicLink() || mcpPresent.size > 1024 * 1024 || realpathSync5(mcp) !== mcp))
51393
51418
  refuse2();
51394
51419
  if (Boolean(mcpPresent) !== (manifest.mcpServers !== undefined))
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.30",
20022
+ version: "0.10.31",
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.10.30",
10
+ version: "0.10.31",
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.10.30",
24125
+ version: "0.10.31",
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.10.30",
24128
+ version: "0.10.31",
24129
24129
  description: "Skills library for AI coding agents",
24130
24130
  type: "module",
24131
24131
  bin: {
package/dist/index.js CHANGED
@@ -10917,7 +10917,7 @@ function replaceSkillSession(expected, replacement, plan, options = {}, beforeCo
10917
10917
  // package.json
10918
10918
  var package_default = {
10919
10919
  name: "@hasna/skills",
10920
- version: "0.10.30",
10920
+ version: "0.10.31",
10921
10921
  description: "Skills library for AI coding agents",
10922
10922
  type: "module",
10923
10923
  bin: {
@@ -13509,6 +13509,29 @@ function mcpControls(path, read2) {
13509
13509
  refuse2();
13510
13510
  return sha2562;
13511
13511
  }
13512
+ function isBundledCleanupHooks(root, namespace, value) {
13513
+ const object5 = (v) => Boolean(v && typeof v === "object" && !Array.isArray(v));
13514
+ const exactKeys = (v, keys) => Object.keys(v).length === keys.length && keys.every((key) => Object.hasOwn(v, key));
13515
+ if (basename5(dirname10(root)) !== namespace || basename5(dirname10(dirname10(root))) !== "openai-bundled")
13516
+ return false;
13517
+ const server = namespace === "unified-computer-use" ? "cua_repl" : ["browser", "chrome", "chrome-dev", "chrome-internal", "computer-use"].includes(namespace) ? "node_repl" : undefined;
13518
+ if (!server || !object5(value) || !exactKeys(value, ["hooks"]) || !object5(value.hooks))
13519
+ return false;
13520
+ const events = Object.entries(value.hooks);
13521
+ if (!events.length || events.length > 3)
13522
+ return false;
13523
+ for (const [event, groups] of events) {
13524
+ if (!["Interrupt", "SubagentStop", "Stop"].includes(event) || !Array.isArray(groups) || groups.length !== 1)
13525
+ return false;
13526
+ const group = groups[0];
13527
+ if (!object5(group) || !exactKeys(group, ["hooks"]) || !Array.isArray(group.hooks) || group.hooks.length !== 1)
13528
+ return false;
13529
+ const handler = group.hooks[0];
13530
+ if (!object5(handler) || !exactKeys(handler, ["type", "server", "tool", "input"]) || handler.type !== "mcp_tool" || handler.server !== server || handler.tool !== "turn_ended" || !object5(handler.input) || !exactKeys(handler.input, ["hook_event_name", "session_id", "turn_id"]) || handler.input.hook_event_name !== "${hook_event_name}" || handler.input.turn_id !== "${turn_id}" || handler.input.session_id !== (event === "SubagentStop" ? "${agent_id}" : "${session_id}"))
13531
+ return false;
13532
+ }
13533
+ return true;
13534
+ }
13512
13535
  function rootControls(root, read2) {
13513
13536
  const manifestPath = join14(root, ".codex-plugin/plugin.json"), manifestFile = lstatSync12(manifestPath, { throwIfNoEntry: false });
13514
13537
  if (!lstatSync12(join14(root, ".codex-plugin"), { throwIfNoEntry: false })?.isDirectory() || !manifestFile?.isFile() || manifestFile.size > 1024 * 1024)
@@ -13526,9 +13549,11 @@ function rootControls(root, read2) {
13526
13549
  const cacheVersion = basename5(root), declaredVersion = manifest.version === undefined ? "" : typeof manifest.version === "string" ? manifest.version.trim() : null;
13527
13550
  if (declaredVersion === null || (declaredVersion ? declaredVersion !== cacheVersion : cacheVersion !== CODEX_DEFAULT_AGENT_PLUGIN_VERSION))
13528
13551
  refuse2();
13529
- if (manifest.hooks !== undefined || manifest.commands !== undefined || manifest.mcpServers !== undefined && manifest.mcpServers !== "./.mcp.json" || manifest.apps !== undefined && manifest.apps !== "./.app.json" || lstatSync12(join14(root, "hooks"), { throwIfNoEntry: false }))
13552
+ if (manifest.hooks !== undefined && !isBundledCleanupHooks(root, manifest.name, manifest.hooks) || manifest.commands !== undefined || manifest.mcpServers !== undefined && manifest.mcpServers !== "./.mcp.json" || manifest.apps !== undefined && manifest.apps !== "./.app.json" || lstatSync12(join14(root, "hooks"), { throwIfNoEntry: false }))
13530
13553
  refuse2();
13531
13554
  const mcp = join14(root, ".mcp.json"), mcpPresent = lstatSync12(mcp, { throwIfNoEntry: false });
13555
+ if (manifest.hooks !== undefined && (manifest.mcpServers !== undefined || mcpPresent))
13556
+ refuse2();
13532
13557
  if (mcpPresent && (!mcpPresent.isFile() || mcpPresent.isSymbolicLink() || mcpPresent.size > 1024 * 1024 || realpathSync5(mcp) !== mcp))
13533
13558
  refuse2();
13534
13559
  if (Boolean(mcpPresent) !== (manifest.mcpServers !== undefined))
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.30",
32376
+ version: "0.10.31",
32377
32377
  description: "Skills library for AI coding agents",
32378
32378
  type: "module",
32379
32379
  bin: {
@@ -38451,6 +38451,29 @@ function mcpControls(path, read) {
38451
38451
  refuse3();
38452
38452
  return sha2562;
38453
38453
  }
38454
+ function isBundledCleanupHooks(root, namespace, value) {
38455
+ const object3 = (v) => Boolean(v && typeof v === "object" && !Array.isArray(v));
38456
+ const exactKeys2 = (v, keys2) => Object.keys(v).length === keys2.length && keys2.every((key) => Object.hasOwn(v, key));
38457
+ if (basename3(dirname5(root)) !== namespace || basename3(dirname5(dirname5(root))) !== "openai-bundled")
38458
+ return false;
38459
+ const server = namespace === "unified-computer-use" ? "cua_repl" : ["browser", "chrome", "chrome-dev", "chrome-internal", "computer-use"].includes(namespace) ? "node_repl" : undefined;
38460
+ if (!server || !object3(value) || !exactKeys2(value, ["hooks"]) || !object3(value.hooks))
38461
+ return false;
38462
+ const events = Object.entries(value.hooks);
38463
+ if (!events.length || events.length > 3)
38464
+ return false;
38465
+ for (const [event, groups] of events) {
38466
+ if (!["Interrupt", "SubagentStop", "Stop"].includes(event) || !Array.isArray(groups) || groups.length !== 1)
38467
+ return false;
38468
+ const group = groups[0];
38469
+ if (!object3(group) || !exactKeys2(group, ["hooks"]) || !Array.isArray(group.hooks) || group.hooks.length !== 1)
38470
+ return false;
38471
+ const handler = group.hooks[0];
38472
+ if (!object3(handler) || !exactKeys2(handler, ["type", "server", "tool", "input"]) || handler.type !== "mcp_tool" || handler.server !== server || handler.tool !== "turn_ended" || !object3(handler.input) || !exactKeys2(handler.input, ["hook_event_name", "session_id", "turn_id"]) || handler.input.hook_event_name !== "${hook_event_name}" || handler.input.turn_id !== "${turn_id}" || handler.input.session_id !== (event === "SubagentStop" ? "${agent_id}" : "${session_id}"))
38473
+ return false;
38474
+ }
38475
+ return true;
38476
+ }
38454
38477
  function rootControls(root, read) {
38455
38478
  const manifestPath = join10(root, ".codex-plugin/plugin.json"), manifestFile = lstatSync6(manifestPath, { throwIfNoEntry: false });
38456
38479
  if (!lstatSync6(join10(root, ".codex-plugin"), { throwIfNoEntry: false })?.isDirectory() || !manifestFile?.isFile() || manifestFile.size > 1024 * 1024)
@@ -38468,9 +38491,11 @@ function rootControls(root, read) {
38468
38491
  const cacheVersion = basename3(root), declaredVersion = manifest.version === undefined ? "" : typeof manifest.version === "string" ? manifest.version.trim() : null;
38469
38492
  if (declaredVersion === null || (declaredVersion ? declaredVersion !== cacheVersion : cacheVersion !== CODEX_DEFAULT_AGENT_PLUGIN_VERSION))
38470
38493
  refuse3();
38471
- if (manifest.hooks !== undefined || manifest.commands !== undefined || manifest.mcpServers !== undefined && manifest.mcpServers !== "./.mcp.json" || manifest.apps !== undefined && manifest.apps !== "./.app.json" || lstatSync6(join10(root, "hooks"), { throwIfNoEntry: false }))
38494
+ if (manifest.hooks !== undefined && !isBundledCleanupHooks(root, manifest.name, manifest.hooks) || manifest.commands !== undefined || manifest.mcpServers !== undefined && manifest.mcpServers !== "./.mcp.json" || manifest.apps !== undefined && manifest.apps !== "./.app.json" || lstatSync6(join10(root, "hooks"), { throwIfNoEntry: false }))
38472
38495
  refuse3();
38473
38496
  const mcp = join10(root, ".mcp.json"), mcpPresent = lstatSync6(mcp, { throwIfNoEntry: false });
38497
+ if (manifest.hooks !== undefined && (manifest.mcpServers !== undefined || mcpPresent))
38498
+ refuse3();
38474
38499
  if (mcpPresent && (!mcpPresent.isFile() || mcpPresent.isSymbolicLink() || mcpPresent.size > 1024 * 1024 || realpathSync5(mcp) !== mcp))
38475
38500
  refuse3();
38476
38501
  if (Boolean(mcpPresent) !== (manifest.mcpServers !== undefined))
@@ -364,3 +364,24 @@ their exact witnesses and trust state; they must still pass their own consumer
364
364
  checks before use. The plan's `managedAgentChecks.agents` and `nativeSkills`
365
365
  describe this scoped runtime check, not a fleet health result. A path-identity
366
366
  witness intersecting the write still refuses instead of adopting a new inode.
367
+
368
+ ## Codex bundled cleanup controls
369
+
370
+ Qualified native skill review supports a narrow subset of Codex 0.159.2 and
371
+ 0.160.0's bundled cleanup hooks. The identities `browser`, `chrome`, `chrome-dev`,
372
+ `chrome-internal` and `computer-use` in `openai-bundled` may call
373
+ `node_repl.turn_ended`; `unified-computer-use` may call `cua_repl.turn_ended`.
374
+ Only `Interrupt`, `SubagentStop` and `Stop` are accepted, with one group and one
375
+ MCP handler per event. Inputs are the exact native event, turn and session
376
+ placeholders; `SubagentStop` uses the child `agent_id` for its session value.
377
+ Commands, matchers, other arguments, external hook files and a plugin MCP
378
+ declaration alongside these hooks remain refused. Apps cleanup routing requires
379
+ connector identity from a native tool catalog and is not admitted by this path.
380
+
381
+ The complete inline hooks stay in the manifest fingerprint across cache versions,
382
+ including after all native skill bodies disappear. A changed hook fails guarded
383
+ apply and subsequent discovery checks. This review preserves native cleanup;
384
+ it neither enables plugins nor grants hook trust, browser authority or signing.
385
+ The upstream contracts are
386
+ [0.159.2 bundled hooks](https://github.com/openai/codex/blob/ff6aec96948b70d94983af2641a6b67c94faeff5/codex-rs/plugin/src/bundled_hooks.rs)
387
+ and [0.160.0 bundled hooks](https://github.com/openai/codex/blob/a956835d020762cb2b570053af06f643a11c0ecc/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.30",
3
+ "version": "0.10.31",
4
4
  "description": "Skills library for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {