@hasna/skills 0.10.11 → 0.10.14

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.11",
36871
+ version: "0.10.14",
36872
36872
  description: "Skills library for AI coding agents",
36873
36873
  type: "module",
36874
36874
  bin: {
@@ -50694,6 +50694,195 @@ var init_agent_bridge = __esm(() => {
50694
50694
 
50695
50695
  // src/lib/agent-codex.ts
50696
50696
  import { isDeepStrictEqual as isDeepStrictEqual3 } from "util";
50697
+ function splitTopLevel(value, delimiter) {
50698
+ const result2 = [];
50699
+ let start = 0, square = 0, curly = 0, quote = null, escaped = false;
50700
+ for (let index = 0;index < value.length; index++) {
50701
+ const char = value[index];
50702
+ if (quote === "double") {
50703
+ if (escaped)
50704
+ escaped = false;
50705
+ else if (char === "\\")
50706
+ escaped = true;
50707
+ else if (char === '"')
50708
+ quote = null;
50709
+ continue;
50710
+ }
50711
+ if (quote === "literal") {
50712
+ if (char === "'")
50713
+ quote = null;
50714
+ continue;
50715
+ }
50716
+ if (char === '"') {
50717
+ quote = "double";
50718
+ continue;
50719
+ }
50720
+ if (char === "'") {
50721
+ quote = "literal";
50722
+ continue;
50723
+ }
50724
+ if (char === "[")
50725
+ square++;
50726
+ else if (char === "]") {
50727
+ if (--square < 0)
50728
+ return null;
50729
+ } else if (char === "{")
50730
+ curly++;
50731
+ else if (char === "}") {
50732
+ if (--curly < 0)
50733
+ return null;
50734
+ } else if (char === delimiter && square === 0 && curly === 0) {
50735
+ result2.push(value.slice(start, index));
50736
+ start = index + 1;
50737
+ }
50738
+ }
50739
+ if (quote !== null || square !== 0 || curly !== 0)
50740
+ return null;
50741
+ result2.push(value.slice(start));
50742
+ return result2;
50743
+ }
50744
+ function inlineArrayEnd(value) {
50745
+ if (!value.startsWith("["))
50746
+ return null;
50747
+ let square = 0, curly = 0, quote = null, escaped = false;
50748
+ for (let index = 0;index < value.length; index++) {
50749
+ const char = value[index];
50750
+ if (quote === "double") {
50751
+ if (escaped)
50752
+ escaped = false;
50753
+ else if (char === "\\")
50754
+ escaped = true;
50755
+ else if (char === '"')
50756
+ quote = null;
50757
+ continue;
50758
+ }
50759
+ if (quote === "literal") {
50760
+ if (char === "'")
50761
+ quote = null;
50762
+ continue;
50763
+ }
50764
+ if (char === '"') {
50765
+ quote = "double";
50766
+ continue;
50767
+ }
50768
+ if (char === "'") {
50769
+ quote = "literal";
50770
+ continue;
50771
+ }
50772
+ if (char === "[")
50773
+ square++;
50774
+ else if (char === "]") {
50775
+ if (--square < 0)
50776
+ return null;
50777
+ if (square === 0 && curly === 0)
50778
+ return index;
50779
+ } else if (char === "{")
50780
+ curly++;
50781
+ else if (char === "}") {
50782
+ if (--curly < 0)
50783
+ return null;
50784
+ }
50785
+ }
50786
+ return null;
50787
+ }
50788
+ function inlineRowsAsTables(value, newline) {
50789
+ const end = inlineArrayEnd(value);
50790
+ if (end === null || value.slice(end + 1).trim() !== "" || value.includes(`
50791
+ `) || value.includes("\r"))
50792
+ return null;
50793
+ const elements = splitTopLevel(value.slice(1, end), ",");
50794
+ if (!elements)
50795
+ return null;
50796
+ const rows = elements.map((element) => element.trim()).filter(Boolean);
50797
+ if (rows.length === 0)
50798
+ return "";
50799
+ const sections = [];
50800
+ for (const row of rows) {
50801
+ if (!row.startsWith("{") || !row.endsWith("}"))
50802
+ return null;
50803
+ const fields = splitTopLevel(row.slice(1, -1), ",");
50804
+ if (!fields)
50805
+ return null;
50806
+ const lines = fields.map((field) => field.trim()).filter(Boolean);
50807
+ if (lines.some((line) => !/^(?:path|name|enabled)\s*=/.test(line)))
50808
+ return null;
50809
+ const keys2 = lines.map((line) => line.slice(0, line.indexOf("=")).trim());
50810
+ if (new Set(keys2).size !== keys2.length)
50811
+ return null;
50812
+ sections.push(`[[skills.config]]${newline}${lines.join(newline)}${newline}`);
50813
+ }
50814
+ return sections.join("");
50815
+ }
50816
+ function normalizeCodexInlinePathConfig(text2) {
50817
+ const before2 = Bun.TOML.parse(text2);
50818
+ if (!Array.isArray(before2.skills?.config))
50819
+ return text2;
50820
+ if (before2.skills.config.length === 0)
50821
+ throw codexPathConfigRefusal();
50822
+ const expectedWithoutConfig = structuredClone(before2);
50823
+ delete expectedWithoutConfig.skills.config;
50824
+ try {
50825
+ if (isDeepStrictEqual3(Bun.TOML.parse(text2.replace(CODEX_SKILL_CONFIG_SECTIONS, "")), expectedWithoutConfig))
50826
+ return text2;
50827
+ } catch {}
50828
+ const matches2 = [];
50829
+ for (const assignment of text2.matchAll(/^([ \t]*config[ \t]*=[ \t]*)(.*?)(\r?)$/gm)) {
50830
+ const rawValue = assignment[2].trimEnd();
50831
+ let quote = null, escaped = false, comment = "";
50832
+ for (let index = 0;index < rawValue.length; index++) {
50833
+ const char = rawValue[index];
50834
+ if (quote === "double") {
50835
+ if (escaped)
50836
+ escaped = false;
50837
+ else if (char === "\\")
50838
+ escaped = true;
50839
+ else if (char === '"')
50840
+ quote = null;
50841
+ continue;
50842
+ }
50843
+ if (quote === "literal") {
50844
+ if (char === "'")
50845
+ quote = null;
50846
+ continue;
50847
+ }
50848
+ if (char === '"')
50849
+ quote = "double";
50850
+ else if (char === "'")
50851
+ quote = "literal";
50852
+ else if (char === "#") {
50853
+ comment = rawValue.slice(index);
50854
+ break;
50855
+ }
50856
+ }
50857
+ const value = comment ? rawValue.slice(0, rawValue.length - comment.length).trimEnd() : rawValue;
50858
+ const tableSections = inlineRowsAsTables(value, text2.includes(`\r
50859
+ `) ? `\r
50860
+ ` : `
50861
+ `);
50862
+ if (tableSections === null)
50863
+ continue;
50864
+ const start = assignment.index;
50865
+ const end = start + assignment[0].length;
50866
+ const withoutAssignment = text2.slice(0, start) + (comment ? comment : "") + assignment[3] + text2.slice(end);
50867
+ const separator = withoutAssignment.endsWith(`
50868
+ `) ? withoutAssignment.endsWith(`
50869
+
50870
+ `) ? "" : `
50871
+ ` : `
50872
+
50873
+ `;
50874
+ const candidate = withoutAssignment + (tableSections ? separator + tableSections : "");
50875
+ try {
50876
+ const after2 = Bun.TOML.parse(candidate);
50877
+ const expected = structuredClone(before2);
50878
+ if (isDeepStrictEqual3(after2, expected))
50879
+ matches2.push(candidate);
50880
+ } catch {}
50881
+ }
50882
+ if (matches2.length !== 1)
50883
+ throw codexPathConfigRefusal();
50884
+ return matches2[0];
50885
+ }
50697
50886
  function assertCodexPathConfigEditable(text2) {
50698
50887
  const before2 = Bun.TOML.parse(text2);
50699
50888
  if (before2.skills?.config === undefined)
@@ -50704,8 +50893,12 @@ function assertCodexPathConfigEditable(text2) {
50704
50893
  const withoutSections = Bun.TOML.parse(text2.replace(CODEX_SKILL_CONFIG_SECTIONS, ""));
50705
50894
  if (isDeepStrictEqual3(withoutSections, expected))
50706
50895
  return;
50896
+ const normalized = normalizeCodexInlinePathConfig(text2);
50897
+ const withoutNormalizedSections = Bun.TOML.parse(normalized.replace(CODEX_SKILL_CONFIG_SECTIONS, ""));
50898
+ if (isDeepStrictEqual3(withoutNormalizedSections, expected))
50899
+ return;
50707
50900
  } catch {}
50708
- throw new Error("Codex skill path controls require ordinary [[skills.config]] TOML tables; preserve and convert inline or dotted config arrays before running skills hook install");
50901
+ throw codexPathConfigRefusal();
50709
50902
  }
50710
50903
  function disableCodexBundledSkills(text2) {
50711
50904
  const before2 = Bun.TOML.parse(text2);
@@ -50764,7 +50957,7 @@ function disableCodexBundledSkills(text2) {
50764
50957
  throw refuse();
50765
50958
  return [...candidates][0];
50766
50959
  }
50767
- var CODEX_SKILL_CONFIG_SECTIONS;
50960
+ var CODEX_SKILL_CONFIG_SECTIONS, codexPathConfigRefusal = () => new Error("Codex skill path controls require ordinary [[skills.config]] TOML tables or a native single-line inline array; preserve and review unsupported inline, dotted, or malformed definitions before running skills hook install");
50768
50961
  var init_agent_codex = __esm(() => {
50769
50962
  CODEX_SKILL_CONFIG_SECTIONS = /^\[\[skills\.config\]\][^\n]*(?:\n(?!\s*\[)[^\n]*)*/gm;
50770
50963
  });
@@ -51300,11 +51493,12 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
51300
51493
  return false;
51301
51494
  if (scan.hasSkills) {
51302
51495
  const targetSkills = entries.filter((entry) => entry.agent === agent && entry.vendor && (entry.path === target || entry.path.startsWith(target + sep4)));
51496
+ if (path === options.reviewedCacheAlias && targetSkills.length > 0)
51497
+ reviewedCacheAliasFound = true;
51303
51498
  if (agent === "codex" && targetSkills.length > 0 && targetSkills.every((entry) => disabledVendorPaths.has(entry.path)))
51304
51499
  return true;
51305
51500
  if (path !== options.reviewedCacheAlias)
51306
51501
  return false;
51307
- reviewedCacheAliasFound = true;
51308
51502
  }
51309
51503
  return true;
51310
51504
  }
@@ -51503,7 +51697,7 @@ function configureHooks(config, agent, command, profileId, nativeReady) {
51503
51697
  }
51504
51698
  function disableCodexSkills(text2, skills, aliases, bridgePath) {
51505
51699
  const bundled = disableCodexBundledSkills(text2);
51506
- let result2 = bundled;
51700
+ let result2 = normalizeCodexInlinePathConfig(bundled);
51507
51701
  const bridgeSelector = (entry) => typeof entry.name === "string" && entry.name.trim() === CLI_BRIDGE_NAME || typeof entry.path === "string" && [resolve10(bridgePath), resolve10(join20(bridgePath, "SKILL.md"))].includes(canonicalAgentPath(entry.path, aliases));
51508
51702
  const previousConfig = Bun.TOML.parse(bundled).skills?.config;
51509
51703
  if (previousConfig !== undefined && (!Array.isArray(previousConfig) || previousConfig.some((entry) => !entry || typeof entry !== "object" || entry.path !== undefined && entry.name !== undefined)))
@@ -51572,7 +51766,7 @@ function planAgentIntegration(options) {
51572
51766
  return resolveAgentDiscovery({ home, agent, reviewed: options.discoveryInputs, retainedReview, canonical: (path) => canonicalAgentPath(path, aliases) });
51573
51767
  });
51574
51768
  const codexConfig = options.agents.includes("codex") ? Bun.TOML.parse(readOptional(canonicalAgentPath(join20(home, ".codex", "config.toml"), aliases)) ?? "") : {};
51575
- const nativeSkills = inventoryNativeSkills(home, { includeVendor: true, guardHermes: options.agents.includes("hermes"), agents: options.agents, projectDir: options.projectDir, agentRoots: discoveries.flatMap((binding) => binding.roots.map((path) => ({ agent: binding.agent, path }))), allowRootAliases: options.allowRootAliases, disabledVendorPaths: disabledCodexSkillPaths(codexConfig, aliases) });
51769
+ const nativeSkills = inventoryNativeSkills(home, { includeVendor: true, guardHermes: options.agents.includes("hermes"), agents: options.agents, projectDir: options.projectDir, agentRoots: discoveries.flatMap((binding) => binding.roots.map((path) => ({ agent: binding.agent, path }))), allowRootAliases: options.allowRootAliases, reviewedCacheAlias: options.reviewedCacheAlias, disabledVendorPaths: disabledCodexSkillPaths(codexConfig, aliases) });
51576
51770
  const changes = [];
51577
51771
  for (const agent of [...new Set(options.agents)]) {
51578
51772
  if (!INTEGRATION_AGENTS.includes(agent))
@@ -110622,7 +110816,7 @@ async function connectCodexHookRpc(options) {
110622
110816
  }
110623
110817
  var SUPPORTED_CODEX_HOOK_VERSIONS;
110624
110818
  var init_codex_hook_rpc = __esm(() => {
110625
- SUPPORTED_CODEX_HOOK_VERSIONS = ["codex-cli 0.153.0", "codex-cli 0.154.0", "codex-cli 0.155.0", "codex-cli 0.155.1", "codex-cli 0.156.1", "codex-cli 0.157.0", "codex-cli 0.157.1"];
110819
+ SUPPORTED_CODEX_HOOK_VERSIONS = ["codex-cli 0.153.0", "codex-cli 0.154.0", "codex-cli 0.155.0", "codex-cli 0.155.1", "codex-cli 0.156.1", "codex-cli 0.157.0", "codex-cli 0.157.1", "codex-cli 0.158.0", "codex-cli 0.159.0"];
110626
110820
  });
110627
110821
 
110628
110822
  // src/lib/codex-hook-trust-identity.ts
@@ -111213,10 +111407,10 @@ function registerAgentIntegration(parent) {
111213
111407
  hook.command("agents").option("--json", "Output the adapter capability inventory", false).description("Show maintained native adapters and explicit coverage limits").action(async () => {
111214
111408
  await writeCliOutput(JSON.stringify({ agents: INTEGRATION_AGENTS.map((agent) => ({ agent, bridge: true, ...AGENT_ADAPTERS[agent] })), inventoryOnly: ["codewith", "windsurf", "pi", "amp", "cline", "roo", "copilot"], limitations: ["Cursor prompt hooks gate submission; selected context is injected at session start only.", "Native discovery checks cover known home roots and current project ancestors. External plugin hook injection and arbitrary added directories require separate review.", "Hermes injects selected prompt context, but native pre_llm_call fails open. Exact native hook trust, bundled reseeding opt-out, native payload retirement and a supervised pre-tool guard are required. Child failures block explicitly; native host/supervisor death is not a universal fail-closed guarantee.", "Restart agents and use their normal hook trust controls after installation."] }, null, 2));
111215
111409
  });
111216
- hook.command("install").option("--agent <agent>", `Agent to configure: ${INTEGRATION_AGENTS.join(", ")}, all`, "all").option("--command <path>", "Skills executable used by the hook (preserves existing binding; new agents use skills)").option("--selection-profile <id>", "Selection profile (preserves existing binding; new agents use default)").option("--include-vendor", "Retained for compatibility; vendor system skills are always inventoried and disabled", false).option("--discovery-inputs <file>", "Advanced reviewed active plugin roots and source hashes for unsupported registrations").option("--allow-root-aliases", "Allow home .claude/.codex aliases to existing directories within this home", false).option("--apply", "Apply the plan, preserving prior configuration in private backups", false).option("--json", "Output a receipt as JSON", false).description("Plan or install one Skills CLI bridge plus native prompt hooks").action(async (options) => {
111410
+ hook.command("install").option("--agent <agent>", `Agent to configure: ${INTEGRATION_AGENTS.join(", ")}, all`, "all").option("--command <path>", "Skills executable used by the hook (preserves existing binding; new agents use skills)").option("--selection-profile <id>", "Selection profile (preserves existing binding; new agents use default)").option("--include-vendor", "Retained for compatibility; vendor system skills are always inventoried and disabled", false).option("--discovery-inputs <file>", "Advanced reviewed active plugin roots and source hashes for unsupported registrations").option("--reviewed-cache-alias <path>", "Exact skill-containing vendor cache alias reviewed for this hook plan").option("--allow-root-aliases", "Allow home .claude/.codex aliases to existing directories within this home", false).option("--apply", "Apply the plan, preserving prior configuration in private backups", false).option("--json", "Output a receipt as JSON", false).description("Plan or install one Skills CLI bridge plus native prompt hooks").action(async (options) => {
111217
111411
  try {
111218
111412
  const discoveryInputs = options.discoveryInputs ? JSON.parse(readFileSync41(options.discoveryInputs, "utf8")) : undefined;
111219
- const plan = planAgentIntegration({ agents: agents(options.agent), command: options.command, profileId: options.selectionProfile, includeVendor: options.includeVendor, discoveryInputs, allowRootAliases: options.allowRootAliases });
111413
+ const plan = planAgentIntegration({ agents: agents(options.agent), command: options.command, profileId: options.selectionProfile, includeVendor: options.includeVendor, discoveryInputs, allowRootAliases: options.allowRootAliases, reviewedCacheAlias: options.reviewedCacheAlias });
111220
111414
  const result2 = options.apply ? applyAgentIntegration(plan) : { changed: [], backups: [] };
111221
111415
  const receipt = { applied: options.apply, planned: plan.changes.map((change) => change.path), ...result2, rootAliases: plan.rootAliases ?? [], discovery: plan.discoveryAfter, nativeSkills: plan.nativeSkills.map((entry) => ({ agent: entry.agent, path: entry.path, managed: entry.managed, vendor: entry.vendor, system: entry.system === true, bridge: entry.bridge === true })), requiresNativeRetirement: plan.nativeSkills.some((entry) => !entry.bridge && !entry.system) };
111222
111416
  if (options.json)