@hasna/skills 0.1.15 → 0.1.16
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 +27 -10
- package/bin/mcp.js +6 -2
- package/dist/index.js +19 -3
- package/dist/lib/config.d.ts +8 -1
- package/dist/lib/registry.d.ts +2 -1
- package/package.json +2 -1
package/bin/index.js
CHANGED
|
@@ -1914,7 +1914,7 @@ var package_default;
|
|
|
1914
1914
|
var init_package = __esm(() => {
|
|
1915
1915
|
package_default = {
|
|
1916
1916
|
name: "@hasna/skills",
|
|
1917
|
-
version: "0.1.
|
|
1917
|
+
version: "0.1.16",
|
|
1918
1918
|
description: "Skills library for AI coding agents",
|
|
1919
1919
|
type: "module",
|
|
1920
1920
|
bin: {
|
|
@@ -1974,6 +1974,7 @@ var init_package = __esm(() => {
|
|
|
1974
1974
|
typescript: "^5"
|
|
1975
1975
|
},
|
|
1976
1976
|
dependencies: {
|
|
1977
|
+
"@hasna/cloud": "^0.1.0",
|
|
1977
1978
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
1978
1979
|
chalk: "^5.3.0",
|
|
1979
1980
|
commander: "^12.1.0",
|
|
@@ -2070,7 +2071,10 @@ function loadRegistry(cwd) {
|
|
|
2070
2071
|
return _registryCache;
|
|
2071
2072
|
}
|
|
2072
2073
|
const official = SKILLS.map((s) => ({ ...s, source: "official" }));
|
|
2073
|
-
const
|
|
2074
|
+
const globalCustomNew = discoverSkillsInDir(join(homedir(), ".hasna", "skills", "custom"));
|
|
2075
|
+
const globalCustomOld = discoverSkillsInDir(join(homedir(), ".skills"));
|
|
2076
|
+
const oldNames = new Set(globalCustomNew.map((s) => s.name));
|
|
2077
|
+
const globalCustom = [...globalCustomNew, ...globalCustomOld.filter((s) => !oldNames.has(s.name))];
|
|
2074
2078
|
const projectCustom = discoverSkillsInDir(join(cwd || process.cwd(), ".skills", "custom-skills"));
|
|
2075
2079
|
const customNames = new Set([...globalCustom, ...projectCustom].map((s) => s.name));
|
|
2076
2080
|
const filtered = official.filter((s) => !customNames.has(s.name));
|
|
@@ -37366,7 +37370,7 @@ init_installer();
|
|
|
37366
37370
|
init_skillinfo();
|
|
37367
37371
|
|
|
37368
37372
|
// src/lib/config.ts
|
|
37369
|
-
import { existsSync as existsSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
37373
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, copyFileSync } from "fs";
|
|
37370
37374
|
import { join as join4, dirname as dirname2 } from "path";
|
|
37371
37375
|
import { homedir as homedir3 } from "os";
|
|
37372
37376
|
var VALID_KEYS = {
|
|
@@ -37374,9 +37378,22 @@ var VALID_KEYS = {
|
|
|
37374
37378
|
defaultScope: ["global", "project"],
|
|
37375
37379
|
format: ["compact", "json", "csv"]
|
|
37376
37380
|
};
|
|
37381
|
+
function getDataDir() {
|
|
37382
|
+
const home = process.env["HOME"] || process.env["USERPROFILE"] || homedir3();
|
|
37383
|
+
const newDir = join4(home, ".hasna", "skills");
|
|
37384
|
+
const oldConfigFile = join4(home, ".skillsrc");
|
|
37385
|
+
if (existsSync4(oldConfigFile) && !existsSync4(join4(newDir, "config.json"))) {
|
|
37386
|
+
mkdirSync2(newDir, { recursive: true });
|
|
37387
|
+
try {
|
|
37388
|
+
copyFileSync(oldConfigFile, join4(newDir, "config.json"));
|
|
37389
|
+
} catch {}
|
|
37390
|
+
}
|
|
37391
|
+
mkdirSync2(newDir, { recursive: true });
|
|
37392
|
+
return newDir;
|
|
37393
|
+
}
|
|
37377
37394
|
function getConfigPath(scope) {
|
|
37378
37395
|
if (scope === "global") {
|
|
37379
|
-
return join4(
|
|
37396
|
+
return join4(getDataDir(), "config.json");
|
|
37380
37397
|
}
|
|
37381
37398
|
return join4(process.cwd(), "skills.config.json");
|
|
37382
37399
|
}
|
|
@@ -39028,11 +39045,11 @@ configCmd.command("path").description("Show configuration file paths").action(()
|
|
|
39028
39045
|
console.log(`${chalk2.cyan("global")}: ${globalPath}${existsSync8(globalPath) ? chalk2.green(" (exists)") : chalk2.dim(" (not found)")}`);
|
|
39029
39046
|
console.log(`${chalk2.cyan("project")}: ${projectPath}${existsSync8(projectPath) ? chalk2.green(" (exists)") : chalk2.dim(" (not found)")}`);
|
|
39030
39047
|
});
|
|
39031
|
-
program2.command("create").argument("<name>", "Skill name (e.g. my-tool)").option("--category <category>", "Skill category", "Development Tools").option("--description <description>", "Short description of what the skill does").option("--tags <tags>", "Comma-separated tags (e.g. api,testing,automation)").option("--global", "Create in ~/.skills/ instead of .skills/custom-skills/", false).option("--json", "Output result as JSON", false).description("Scaffold a new custom skill directory").action((name, options) => {
|
|
39048
|
+
program2.command("create").argument("<name>", "Skill name (e.g. my-tool)").option("--category <category>", "Skill category", "Development Tools").option("--description <description>", "Short description of what the skill does").option("--tags <tags>", "Comma-separated tags (e.g. api,testing,automation)").option("--global", "Create in ~/.hasna/skills/custom/ instead of .skills/custom-skills/", false).option("--json", "Output result as JSON", false).description("Scaffold a new custom skill directory").action((name, options) => {
|
|
39032
39049
|
const { homedir: homedir4 } = __require("os");
|
|
39033
39050
|
const bare = name.replace(/^skill-/, "");
|
|
39034
39051
|
const dirName = `skill-${bare}`;
|
|
39035
|
-
const baseDir = options.global ? join8(homedir4(), ".skills") : join8(process.cwd(), ".skills", "custom-skills");
|
|
39052
|
+
const baseDir = options.global ? join8(homedir4(), ".hasna", "skills", "custom") : join8(process.cwd(), ".skills", "custom-skills");
|
|
39036
39053
|
const skillDir = join8(baseDir, dirName);
|
|
39037
39054
|
if (existsSync8(skillDir)) {
|
|
39038
39055
|
if (options.json) {
|
|
@@ -39112,7 +39129,7 @@ program2.command("create").argument("<name>", "Skill name (e.g. my-tool)").optio
|
|
|
39112
39129
|
console.log(` ${chalk2.cyan("Docs:")} ${join8(skillDir, "SKILL.md")}`);
|
|
39113
39130
|
}
|
|
39114
39131
|
});
|
|
39115
|
-
program2.command("sync").option("--to <agent>", "Push custom skills to agent: claude, codex, gemini, pi, opencode, or all").option("--from <agent>", "List agent skills and show which are unknown to the registry").option("--register", "With --from: copy unknown agent skills into ~/.skills/ to add them to the registry", false).option("--scope <scope>", "Agent install scope: global or project", "global").option("--json", "Output as JSON", false).description("Sync custom skills with agent directories (--to or --from)").action((options) => {
|
|
39132
|
+
program2.command("sync").option("--to <agent>", "Push custom skills to agent: claude, codex, gemini, pi, opencode, or all").option("--from <agent>", "List agent skills and show which are unknown to the registry").option("--register", "With --from: copy unknown agent skills into ~/.hasna/skills/custom/ to add them to the registry", false).option("--scope <scope>", "Agent install scope: global or project", "global").option("--json", "Output as JSON", false).description("Sync custom skills with agent directories (--to or --from)").action((options) => {
|
|
39116
39133
|
const { homedir: homedir4 } = __require("os");
|
|
39117
39134
|
if (!options.to && !options.from) {
|
|
39118
39135
|
console.error(chalk2.red("Specify --to <agent> or --from <agent>"));
|
|
@@ -39150,7 +39167,7 @@ program2.command("sync").option("--to <agent>", "Push custom skills to agent: cl
|
|
|
39150
39167
|
}
|
|
39151
39168
|
const unknown3 = found.filter((s) => !s.inRegistry);
|
|
39152
39169
|
if (options.register && unknown3.length > 0) {
|
|
39153
|
-
const globalSkillsDir = join8(homedir4(), ".skills");
|
|
39170
|
+
const globalSkillsDir = join8(homedir4(), ".hasna", "skills", "custom");
|
|
39154
39171
|
const registered = [];
|
|
39155
39172
|
for (const s of unknown3) {
|
|
39156
39173
|
const srcSkillMd = join8(s.path, "SKILL.md");
|
|
@@ -39168,7 +39185,7 @@ program2.command("sync").option("--to <agent>", "Push custom skills to agent: cl
|
|
|
39168
39185
|
console.log(JSON.stringify({ agentDir, skills: found, registered }));
|
|
39169
39186
|
} else {
|
|
39170
39187
|
for (const name of registered) {
|
|
39171
|
-
console.log(chalk2.green(`\u2713 Registered '${name}' into ~/.skills/ (global custom)`));
|
|
39188
|
+
console.log(chalk2.green(`\u2713 Registered '${name}' into ~/.hasna/skills/custom/ (global custom)`));
|
|
39172
39189
|
}
|
|
39173
39190
|
if (registered.length === 0)
|
|
39174
39191
|
console.log(chalk2.dim("No new skills to register (all SKILL.md files missing)"));
|
|
@@ -39187,7 +39204,7 @@ Agent skills in ~/.${agentName}/skills/ (${found.length} found):
|
|
|
39187
39204
|
}
|
|
39188
39205
|
if (unknown3.length > 0) {
|
|
39189
39206
|
console.log("");
|
|
39190
|
-
console.log(chalk2.dim(`Tip: ${unknown3.length} skill(s) not in registry. Run with --register to add them to ~/.skills/.`));
|
|
39207
|
+
console.log(chalk2.dim(`Tip: ${unknown3.length} skill(s) not in registry. Run with --register to add them to ~/.hasna/skills/custom/.`));
|
|
39191
39208
|
}
|
|
39192
39209
|
}
|
|
39193
39210
|
return;
|
package/bin/mcp.js
CHANGED
|
@@ -28566,7 +28566,7 @@ import { join as join5 } from "path";
|
|
|
28566
28566
|
// package.json
|
|
28567
28567
|
var package_default = {
|
|
28568
28568
|
name: "@hasna/skills",
|
|
28569
|
-
version: "0.1.
|
|
28569
|
+
version: "0.1.16",
|
|
28570
28570
|
description: "Skills library for AI coding agents",
|
|
28571
28571
|
type: "module",
|
|
28572
28572
|
bin: {
|
|
@@ -28626,6 +28626,7 @@ var package_default = {
|
|
|
28626
28626
|
typescript: "^5"
|
|
28627
28627
|
},
|
|
28628
28628
|
dependencies: {
|
|
28629
|
+
"@hasna/cloud": "^0.1.0",
|
|
28629
28630
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
28630
28631
|
chalk: "^5.3.0",
|
|
28631
28632
|
commander: "^12.1.0",
|
|
@@ -30174,7 +30175,10 @@ function loadRegistry(cwd) {
|
|
|
30174
30175
|
return _registryCache;
|
|
30175
30176
|
}
|
|
30176
30177
|
const official = SKILLS.map((s) => ({ ...s, source: "official" }));
|
|
30177
|
-
const
|
|
30178
|
+
const globalCustomNew = discoverSkillsInDir(join(homedir(), ".hasna", "skills", "custom"));
|
|
30179
|
+
const globalCustomOld = discoverSkillsInDir(join(homedir(), ".skills"));
|
|
30180
|
+
const oldNames = new Set(globalCustomNew.map((s) => s.name));
|
|
30181
|
+
const globalCustom = [...globalCustomNew, ...globalCustomOld.filter((s) => !oldNames.has(s.name))];
|
|
30178
30182
|
const projectCustom = discoverSkillsInDir(join(cwd || process.cwd(), ".skills", "custom-skills"));
|
|
30179
30183
|
const customNames = new Set([...globalCustom, ...projectCustom].map((s) => s.name));
|
|
30180
30184
|
const filtered = official.filter((s) => !customNames.has(s.name));
|
package/dist/index.js
CHANGED
|
@@ -1524,7 +1524,10 @@ function loadRegistry(cwd) {
|
|
|
1524
1524
|
return _registryCache;
|
|
1525
1525
|
}
|
|
1526
1526
|
const official = SKILLS.map((s) => ({ ...s, source: "official" }));
|
|
1527
|
-
const
|
|
1527
|
+
const globalCustomNew = discoverSkillsInDir(join(homedir(), ".hasna", "skills", "custom"));
|
|
1528
|
+
const globalCustomOld = discoverSkillsInDir(join(homedir(), ".skills"));
|
|
1529
|
+
const oldNames = new Set(globalCustomNew.map((s) => s.name));
|
|
1530
|
+
const globalCustom = [...globalCustomNew, ...globalCustomOld.filter((s) => !oldNames.has(s.name))];
|
|
1528
1531
|
const projectCustom = discoverSkillsInDir(join(cwd || process.cwd(), ".skills", "custom-skills"));
|
|
1529
1532
|
const customNames = new Set([...globalCustom, ...projectCustom].map((s) => s.name));
|
|
1530
1533
|
const filtered = official.filter((s) => !customNames.has(s.name));
|
|
@@ -2216,7 +2219,7 @@ function readIfExists(path) {
|
|
|
2216
2219
|
return null;
|
|
2217
2220
|
}
|
|
2218
2221
|
// src/lib/config.ts
|
|
2219
|
-
import { existsSync as existsSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
2222
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, copyFileSync } from "fs";
|
|
2220
2223
|
import { join as join4, dirname as dirname2 } from "path";
|
|
2221
2224
|
import { homedir as homedir3 } from "os";
|
|
2222
2225
|
var VALID_KEYS = {
|
|
@@ -2224,9 +2227,22 @@ var VALID_KEYS = {
|
|
|
2224
2227
|
defaultScope: ["global", "project"],
|
|
2225
2228
|
format: ["compact", "json", "csv"]
|
|
2226
2229
|
};
|
|
2230
|
+
function getDataDir() {
|
|
2231
|
+
const home = process.env["HOME"] || process.env["USERPROFILE"] || homedir3();
|
|
2232
|
+
const newDir = join4(home, ".hasna", "skills");
|
|
2233
|
+
const oldConfigFile = join4(home, ".skillsrc");
|
|
2234
|
+
if (existsSync4(oldConfigFile) && !existsSync4(join4(newDir, "config.json"))) {
|
|
2235
|
+
mkdirSync2(newDir, { recursive: true });
|
|
2236
|
+
try {
|
|
2237
|
+
copyFileSync(oldConfigFile, join4(newDir, "config.json"));
|
|
2238
|
+
} catch {}
|
|
2239
|
+
}
|
|
2240
|
+
mkdirSync2(newDir, { recursive: true });
|
|
2241
|
+
return newDir;
|
|
2242
|
+
}
|
|
2227
2243
|
function getConfigPath(scope) {
|
|
2228
2244
|
if (scope === "global") {
|
|
2229
|
-
return join4(
|
|
2245
|
+
return join4(getDataDir(), "config.json");
|
|
2230
2246
|
}
|
|
2231
2247
|
return join4(process.cwd(), "skills.config.json");
|
|
2232
2248
|
}
|
package/dist/lib/config.d.ts
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Loads configuration from:
|
|
5
5
|
* 1. Project-local: ./skills.config.json (highest priority)
|
|
6
|
-
* 2. Global: ~/.
|
|
6
|
+
* 2. Global: ~/.hasna/skills/config.json (JSON format, lowest priority)
|
|
7
|
+
* (backward compat: also checks ~/.skillsrc)
|
|
7
8
|
*
|
|
8
9
|
* Values from the project config override global config.
|
|
9
10
|
*/
|
|
@@ -13,6 +14,12 @@ export interface SkillsConfig {
|
|
|
13
14
|
format?: "compact" | "json" | "csv";
|
|
14
15
|
}
|
|
15
16
|
export type ConfigScope = "global" | "project";
|
|
17
|
+
/**
|
|
18
|
+
* Get the data directory for skills global config/data.
|
|
19
|
+
* New default: ~/.hasna/skills/
|
|
20
|
+
* Auto-migrates from ~/.skillsrc if the new config doesn't exist yet.
|
|
21
|
+
*/
|
|
22
|
+
export declare function getDataDir(): string;
|
|
16
23
|
/**
|
|
17
24
|
* Get the config file path for a given scope
|
|
18
25
|
*/
|
package/dist/lib/registry.d.ts
CHANGED
|
@@ -15,7 +15,8 @@ export type Category = (typeof CATEGORIES)[number];
|
|
|
15
15
|
export declare const SKILLS: SkillMeta[];
|
|
16
16
|
/**
|
|
17
17
|
* Load the full registry: official skills merged with custom skills from:
|
|
18
|
-
* - ~/.skills/ (global custom)
|
|
18
|
+
* - ~/.hasna/skills/custom/ (global custom, new path)
|
|
19
|
+
* - ~/.skills/ (global custom, legacy path)
|
|
19
20
|
* - ./.custom-skills/ (project-level custom, relative to cwd)
|
|
20
21
|
*
|
|
21
22
|
* Custom skills with the same name as official skills take precedence.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/skills",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
4
4
|
"description": "Skills library for AI coding agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
"typescript": "^5"
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
|
+
"@hasna/cloud": "^0.1.0",
|
|
63
64
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
64
65
|
"chalk": "^5.3.0",
|
|
65
66
|
"commander": "^12.1.0",
|