@hasna/skills 0.8.7 → 0.8.8

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
@@ -70,6 +70,22 @@ skills hook install --agent all --selection-profile default --json
70
70
  skills hook install --agent all --selection-profile default --apply --json
71
71
  ```
72
72
 
73
+ Native migration includes the current directory, every ancestor, and the global
74
+ agent directories. Use `--project /path/to/project` to include another project
75
+ and its ancestors. This matches the prompt hook's project discovery, including
76
+ skills inherited from a parent workspace. Preview the JSON inventory before
77
+ applying it; archived copies retain recovery receipts. A drift refusal reports
78
+ the affected paths without printing their skill documents.
79
+
80
+ Claude hook installation sets `syncClaudeAiSkills: false` in user settings to
81
+ stop [account skill synchronization](https://code.claude.com/docs/en/skills#skills-synced-from-claudeai)
82
+ from recreating native copies. The prompt hook checks that setting. Vendor
83
+ migration also inventories `~/.claude/plugins/synced/` and archives its skill
84
+ documents while preserving other plugin files. Whole-plugin synchronization
85
+ remains unchanged because synced plugins can also provide hooks, MCP servers,
86
+ and language servers. A later plugin download that restores a skill document
87
+ will trigger another drift refusal and require review.
88
+
73
89
  Native hook invocations must use their installed adapter's selection profile.
74
90
  An old client command or environment override naming another profile refuses
75
91
  before synchronization or context loading. Review the hook installation and
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.8.7",
36871
+ version: "0.8.8",
36872
36872
  description: "Skills library for AI coding agents",
36873
36873
  type: "module",
36874
36874
  bin: {
@@ -51228,11 +51228,26 @@ function treeHash(root) {
51228
51228
  visit2(root);
51229
51229
  return hash2.digest("hex");
51230
51230
  }
51231
+ function projectAncestorDirectories(projects) {
51232
+ const directories = new Set;
51233
+ for (const project of projects) {
51234
+ for (let path = resolve10(project), depth = 0;; depth++) {
51235
+ if (depth >= 100)
51236
+ throw new Error("NATIVE_SKILL_DRIFT: project ancestor discovery limit exceeded");
51237
+ directories.add(path);
51238
+ const parent = dirname10(path);
51239
+ if (parent === path)
51240
+ break;
51241
+ path = parent;
51242
+ }
51243
+ }
51244
+ return [...directories];
51245
+ }
51231
51246
  function inventoryNativeSkills(home = homedir3(), options = {}) {
51232
51247
  const aliases = rootAliases(home, options.allowRootAliases);
51233
51248
  const roots = ROOTS.map(([agent, path]) => [agent, canonicalAgentPath(join21(home, path), aliases)]);
51234
51249
  const bridgePaths = Object.values(AGENT_ADAPTERS).map((adapter) => canonicalAgentPath(join21(home, adapter.root, CLI_BRIDGE_NAME), aliases));
51235
- for (const project of new Set([...options.projectDirs ?? [], ...options.projectDir ? [options.projectDir] : []].map((path) => resolve10(path)))) {
51250
+ for (const project of projectAncestorDirectories([...options.projectDirs ?? [], ...options.projectDir ? [options.projectDir] : []])) {
51236
51251
  for (const [agent, path] of ROOTS)
51237
51252
  roots.push([agent, canonicalAgentPath(join21(project, path), aliases)]);
51238
51253
  }
@@ -51335,6 +51350,7 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
51335
51350
  if (options.includeVendor) {
51336
51351
  for (const agent of ["codex", "claude"])
51337
51352
  scanRoot(agent, canonicalAgentPath(join21(home, `.${agent}`, "plugins", "cache"), aliases), true, true);
51353
+ scanRoot("claude", canonicalAgentPath(join21(home, ".claude", "plugins", "synced"), aliases), true);
51338
51354
  scanRoot("gemini", join21(home, ".gemini", "extensions"), true);
51339
51355
  }
51340
51356
  const configured = options.configured ? INTEGRATION_AGENTS.flatMap((agent) => resolveAgentDiscovery({ home, agent, reviewed: options.discoveryInputs, canonical: (path) => canonicalAgentPath(path, aliases) }).roots.map((path) => ({ agent, path }))) : [];
@@ -51399,6 +51415,7 @@ function configureHooks(config, agent, command, profileId, nativeReady) {
51399
51415
  config.permissions.deny = nativeReady ? denied.filter((rule) => rule !== "Skill") : [...new Set([...denied, "Skill"])];
51400
51416
  config.permissions.allow = nativeReady ? [...new Set([...allowed, `Skill(${CLI_BRIDGE_NAME})`])] : allowed;
51401
51417
  config.disableBundledSkills = true;
51418
+ config.syncClaudeAiSkills = false;
51402
51419
  }
51403
51420
  if (agent === "gemini") {
51404
51421
  config.skills ??= {};
@@ -51811,18 +51828,7 @@ function assertManagedAgentBridge(agent, options = {}) {
51811
51828
  const expected = canonicalAgentPath(join21(home, AGENT_ADAPTERS[agent].root, CLI_BRIDGE_NAME), aliases);
51812
51829
  if (!isOwnedCliBridge(expected, [expected]))
51813
51830
  throw new Error("NATIVE_SKILL_DRIFT: the native Skills bridge is missing or modified; repair it before continuing");
51814
- const roots = new Set;
51815
- for (const project of [options.projectDir ?? process.cwd(), ...options.projectDirs ?? [], ...agent === "hermes" && process.env.TERMINAL_CWD ? [process.cwd()] : []]) {
51816
- for (let path = resolve10(project), depth = 0;; depth++) {
51817
- if (depth >= 100)
51818
- throw new Error("NATIVE_SKILL_DRIFT: project ancestor discovery limit exceeded");
51819
- roots.add(path);
51820
- const parent = dirname10(path);
51821
- if (parent === path)
51822
- break;
51823
- path = parent;
51824
- }
51825
- }
51831
+ const roots = projectAncestorDirectories([options.projectDir ?? process.cwd(), ...options.projectDirs ?? [], ...agent === "hermes" && process.env.TERMINAL_CWD ? [process.cwd()] : []]);
51826
51832
  const visible = (entry) => entry.agent === agent || ["codex", "gemini", "opencode", "hermes"].includes(agent) && entry.path.includes(`${sep5}.agents${sep5}skills${sep5}`) || agent === "opencode" && entry.agent === "claude";
51827
51833
  assertProjectDiscovery(agent, [...roots], home, (path) => canonicalAgentPath(path, aliases));
51828
51834
  const configPath = canonicalAgentPath(join21(home, AGENT_ADAPTERS[agent].config), aliases), config = agent === "hermes" ? parseHermesConfig(readOptional(configPath)) : jsonObject(readOptional(configPath), configPath);
@@ -51849,6 +51855,8 @@ function assertManagedAgentBridge(agent, options = {}) {
51849
51855
  }
51850
51856
  if (agent === "claude" && (config.disableBundledSkills !== true || config.disableAllHooks === true || !config.permissions?.allow?.includes(`Skill(${CLI_BRIDGE_NAME})`) || config.permissions?.deny?.includes("Skill")))
51851
51857
  throw new Error("NATIVE_SKILL_DRIFT: Claude bridge or bundled-skill protection changed; retire copies and run skills hook install");
51858
+ if (agent === "claude" && config.syncClaudeAiSkills !== false)
51859
+ throw new Error("NATIVE_SKILL_DRIFT: Claude account skill synchronization is not disabled (syncClaudeAiSkills); run skills hook install to prevent native copies from returning");
51852
51860
  if (agent === "gemini" && (config.hooksConfig?.enabled === false || config.skills?.enabled !== true || !["antigravity-support", "skill-creator"].every((name) => config.skills?.disabled?.includes(name)) || config.skills?.disabled?.includes(CLI_BRIDGE_NAME)))
51853
51861
  throw new Error("NATIVE_SKILL_DRIFT: Gemini bridge or bundled-skill protection changed; run skills hook install");
51854
51862
  }
@@ -51880,8 +51888,15 @@ function assertManagedAgentBridge(agent, options = {}) {
51880
51888
  throw new Error(`NATIVE_SKILL_DRIFT: ${error.message}`);
51881
51889
  }
51882
51890
  const inventory = inventoryNativeSkills(home, { includeVendor: true, guardHermes: agent === "hermes", projectDirs: [...roots], agentRoots: discovery.roots.map((path) => ({ agent, path })), allowRootAliases: aliases.length > 0 });
51883
- if (inventory.some((entry) => visible(entry) && !entry.bridge && !disabledBuiltin(entry)))
51884
- throw new Error("NATIVE_SKILL_DRIFT: unexpected native skill copies were found; review skills migrate native --include-unmanaged --include-vendor before continuing");
51891
+ const unexpected = inventory.filter((entry) => visible(entry) && !entry.bridge && !disabledBuiltin(entry));
51892
+ if (unexpected.length) {
51893
+ const paths = unexpected.slice(0, 3).map((entry) => {
51894
+ const escaped = JSON.stringify(entry.path).replace(/[\u007f-\u009f\u061c\u200e\u200f\u2028-\u202e\u2066-\u2069]/g, (character) => `\\u${character.charCodeAt(0).toString(16).padStart(4, "0")}`);
51895
+ return escaped.length > 768 ? `${escaped.slice(0, 384)}...${escaped.slice(-381)}` : escaped;
51896
+ });
51897
+ const remaining = unexpected.length - paths.length;
51898
+ throw new Error(`NATIVE_SKILL_DRIFT: ${unexpected.length} unexpected native skill copies were found: ${paths.join(", ")}${remaining ? `; ${remaining} more` : ""}. Review skills migrate native --project <working-directory> --include-unmanaged --include-vendor --json before continuing; it inventories that directory and its ancestors. Use --apply after reviewing the archive plan.`);
51899
+ }
51885
51900
  recheckRootAliases(aliases);
51886
51901
  }
51887
51902
  function normalizeAgentHookPrompt(agent, event, prompt) {
@@ -105609,10 +105624,10 @@ function registerAgentIntegration(parent) {
105609
105624
  }
105610
105625
  });
105611
105626
  const migrate = parent.command("migrate").description("Preserve and retire native agent skill copies");
105612
- migrate.command("native").option("--project <directory>", "Also inventory native skills in a project directory").option("--include-unmanaged", "Archive user-authored skills as well as Skills-managed copies", false).option("--include-vendor", "Retire vendor SKILL.md discovery files while preserving plugin scripts and assets", false).option("--discovery-inputs <file>", "Advanced reviewed active plugin roots and source hashes").option("--allow-root-aliases", "Allow home .claude/.codex aliases to existing directories within this home", false).option("--apply", "Move selected skills to private archives outside agent discovery roots", false).option("--json", "Output inventory and archive receipt as JSON", false).description("Inventory native skill copies; preserve complete directories before retiring them").action(async (options) => {
105627
+ migrate.command("native").option("--project <directory>", "Also inventory a project and its ancestors (the current directory and its ancestors are always included)").option("--include-unmanaged", "Archive user-authored skills as well as Skills-managed copies", false).option("--include-vendor", "Retire vendor SKILL.md discovery files while preserving plugin scripts and assets", false).option("--discovery-inputs <file>", "Advanced reviewed active plugin roots and source hashes").option("--allow-root-aliases", "Allow home .claude/.codex aliases to existing directories within this home", false).option("--apply", "Move selected skills to private archives outside agent discovery roots", false).option("--json", "Output inventory and archive receipt as JSON", false).description("Inventory native skill copies; preserve complete directories before retiring them").action(async (options) => {
105613
105628
  try {
105614
105629
  const discoveryInputs = options.discoveryInputs ? JSON.parse(readFileSync37(options.discoveryInputs, "utf8")) : undefined;
105615
- const inventory = inventoryNativeSkills(undefined, { projectDir: options.project, includeVendor: options.includeVendor, configured: options.includeVendor, discoveryInputs, allowRootAliases: options.allowRootAliases });
105630
+ const inventory = inventoryNativeSkills(undefined, { projectDirs: [process.cwd(), ...options.project ? [options.project] : []], includeVendor: options.includeVendor, configured: options.includeVendor, discoveryInputs, allowRootAliases: options.allowRootAliases });
105616
105631
  const result2 = options.apply ? archiveNativeSkills(inventory, { includeUnmanaged: options.includeUnmanaged, includeVendor: options.includeVendor, allowRootAliases: options.allowRootAliases }) : { entries: [] };
105617
105632
  if (options.json)
105618
105633
  await writeCliOutput(JSON.stringify({ applied: options.apply, inventory, ...result2 }));
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.8.7",
20022
+ version: "0.8.8",
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.8.7",
10
+ version: "0.8.8",
11
11
  description: "Skills library for AI coding agents",
12
12
  type: "module",
13
13
  bin: {
package/bin/server.js CHANGED
@@ -83749,7 +83749,7 @@ var require_protocols9 = __commonJS((exports) => {
83749
83749
  // package.json
83750
83750
  var package_default = {
83751
83751
  name: "@hasna/skills",
83752
- version: "0.8.7",
83752
+ version: "0.8.8",
83753
83753
  description: "Skills library for AI coding agents",
83754
83754
  type: "module",
83755
83755
  bin: {
package/bin/worker.js CHANGED
@@ -76168,7 +76168,7 @@ import { randomUUID as randomUUID6 } from "crypto";
76168
76168
  // package.json
76169
76169
  var package_default = {
76170
76170
  name: "@hasna/skills",
76171
- version: "0.8.7",
76171
+ version: "0.8.8",
76172
76172
  description: "Skills library for AI coding agents",
76173
76173
  type: "module",
76174
76174
  bin: {
package/dist/index.js CHANGED
@@ -11693,11 +11693,26 @@ function treeHash(root) {
11693
11693
  visit2(root);
11694
11694
  return hash2.digest("hex");
11695
11695
  }
11696
+ function projectAncestorDirectories(projects) {
11697
+ const directories = new Set;
11698
+ for (const project of projects) {
11699
+ for (let path = resolve9(project), depth = 0;; depth++) {
11700
+ if (depth >= 100)
11701
+ throw new Error("NATIVE_SKILL_DRIFT: project ancestor discovery limit exceeded");
11702
+ directories.add(path);
11703
+ const parent = dirname10(path);
11704
+ if (parent === path)
11705
+ break;
11706
+ path = parent;
11707
+ }
11708
+ }
11709
+ return [...directories];
11710
+ }
11696
11711
  function inventoryNativeSkills(home = homedir2(), options = {}) {
11697
11712
  const aliases = rootAliases(home, options.allowRootAliases);
11698
11713
  const roots = ROOTS.map(([agent, path]) => [agent, canonicalAgentPath(join17(home, path), aliases)]);
11699
11714
  const bridgePaths = Object.values(AGENT_ADAPTERS).map((adapter) => canonicalAgentPath(join17(home, adapter.root, CLI_BRIDGE_NAME), aliases));
11700
- for (const project of new Set([...options.projectDirs ?? [], ...options.projectDir ? [options.projectDir] : []].map((path) => resolve9(path)))) {
11715
+ for (const project of projectAncestorDirectories([...options.projectDirs ?? [], ...options.projectDir ? [options.projectDir] : []])) {
11701
11716
  for (const [agent, path] of ROOTS)
11702
11717
  roots.push([agent, canonicalAgentPath(join17(project, path), aliases)]);
11703
11718
  }
@@ -11800,6 +11815,7 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
11800
11815
  if (options.includeVendor) {
11801
11816
  for (const agent of ["codex", "claude"])
11802
11817
  scanRoot(agent, canonicalAgentPath(join17(home, `.${agent}`, "plugins", "cache"), aliases), true, true);
11818
+ scanRoot("claude", canonicalAgentPath(join17(home, ".claude", "plugins", "synced"), aliases), true);
11803
11819
  scanRoot("gemini", join17(home, ".gemini", "extensions"), true);
11804
11820
  }
11805
11821
  const configured = options.configured ? INTEGRATION_AGENTS.flatMap((agent) => resolveAgentDiscovery({ home, agent, reviewed: options.discoveryInputs, canonical: (path) => canonicalAgentPath(path, aliases) }).roots.map((path) => ({ agent, path }))) : [];
@@ -11864,6 +11880,7 @@ function configureHooks(config, agent, command, profileId, nativeReady) {
11864
11880
  config.permissions.deny = nativeReady ? denied.filter((rule) => rule !== "Skill") : [...new Set([...denied, "Skill"])];
11865
11881
  config.permissions.allow = nativeReady ? [...new Set([...allowed, `Skill(${CLI_BRIDGE_NAME})`])] : allowed;
11866
11882
  config.disableBundledSkills = true;
11883
+ config.syncClaudeAiSkills = false;
11867
11884
  }
11868
11885
  if (agent === "gemini") {
11869
11886
  config.skills ??= {};
@@ -37705,7 +37722,7 @@ import { dirname as dirname14, relative as relative7 } from "path";
37705
37722
  // package.json
37706
37723
  var package_default = {
37707
37724
  name: "@hasna/skills",
37708
- version: "0.8.7",
37725
+ version: "0.8.8",
37709
37726
  description: "Skills library for AI coding agents",
37710
37727
  type: "module",
37711
37728
  bin: {
package/dist/sdk/index.js CHANGED
@@ -96141,7 +96141,7 @@ async function resolveExecutionGrant(input) {
96141
96141
  // package.json
96142
96142
  var package_default = {
96143
96143
  name: "@hasna/skills",
96144
- version: "0.8.7",
96144
+ version: "0.8.8",
96145
96145
  description: "Skills library for AI coding agents",
96146
96146
  type: "module",
96147
96147
  bin: {
@@ -97782,11 +97782,26 @@ function treeHash(root) {
97782
97782
  visit2(root);
97783
97783
  return hash2.digest("hex");
97784
97784
  }
97785
+ function projectAncestorDirectories(projects) {
97786
+ const directories = new Set;
97787
+ for (const project of projects) {
97788
+ for (let path = resolve8(project), depth = 0;; depth++) {
97789
+ if (depth >= 100)
97790
+ throw new Error("NATIVE_SKILL_DRIFT: project ancestor discovery limit exceeded");
97791
+ directories.add(path);
97792
+ const parent = dirname9(path);
97793
+ if (parent === path)
97794
+ break;
97795
+ path = parent;
97796
+ }
97797
+ }
97798
+ return [...directories];
97799
+ }
97785
97800
  function inventoryNativeSkills(home = homedir2(), options = {}) {
97786
97801
  const aliases = rootAliases(home, options.allowRootAliases);
97787
97802
  const roots = ROOTS.map(([agent, path]) => [agent, canonicalAgentPath(join16(home, path), aliases)]);
97788
97803
  const bridgePaths = Object.values(AGENT_ADAPTERS).map((adapter) => canonicalAgentPath(join16(home, adapter.root, CLI_BRIDGE_NAME), aliases));
97789
- for (const project of new Set([...options.projectDirs ?? [], ...options.projectDir ? [options.projectDir] : []].map((path) => resolve8(path)))) {
97804
+ for (const project of projectAncestorDirectories([...options.projectDirs ?? [], ...options.projectDir ? [options.projectDir] : []])) {
97790
97805
  for (const [agent, path] of ROOTS)
97791
97806
  roots.push([agent, canonicalAgentPath(join16(project, path), aliases)]);
97792
97807
  }
@@ -97889,6 +97904,7 @@ function inventoryNativeSkills(home = homedir2(), options = {}) {
97889
97904
  if (options.includeVendor) {
97890
97905
  for (const agent of ["codex", "claude"])
97891
97906
  scanRoot(agent, canonicalAgentPath(join16(home, `.${agent}`, "plugins", "cache"), aliases), true, true);
97907
+ scanRoot("claude", canonicalAgentPath(join16(home, ".claude", "plugins", "synced"), aliases), true);
97892
97908
  scanRoot("gemini", join16(home, ".gemini", "extensions"), true);
97893
97909
  }
97894
97910
  const configured = options.configured ? INTEGRATION_AGENTS.flatMap((agent) => resolveAgentDiscovery({ home, agent, reviewed: options.discoveryInputs, canonical: (path) => canonicalAgentPath(path, aliases) }).roots.map((path) => ({ agent, path }))) : [];
@@ -97953,6 +97969,7 @@ function configureHooks(config, agent, command, profileId, nativeReady) {
97953
97969
  config.permissions.deny = nativeReady ? denied.filter((rule) => rule !== "Skill") : [...new Set([...denied, "Skill"])];
97954
97970
  config.permissions.allow = nativeReady ? [...new Set([...allowed, `Skill(${CLI_BRIDGE_NAME})`])] : allowed;
97955
97971
  config.disableBundledSkills = true;
97972
+ config.syncClaudeAiSkills = false;
97956
97973
  }
97957
97974
  if (agent === "gemini") {
97958
97975
  config.skills ??= {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/skills",
3
- "version": "0.8.7",
3
+ "version": "0.8.8",
4
4
  "description": "Skills library for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {