@hasna/skills 0.1.31 → 0.1.32
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 +35 -15
- package/bin/index.js +524 -272
- package/bin/mcp.js +49 -30
- package/dist/cli/onboarding.d.ts +13 -0
- package/dist/index.js +39 -23
- package/dist/lib/config.d.ts +1 -1
- package/package.json +1 -1
package/bin/mcp.js
CHANGED
|
@@ -7064,12 +7064,19 @@ import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync
|
|
|
7064
7064
|
import { join as join6, dirname as dirname2 } from "path";
|
|
7065
7065
|
import { homedir as homedir3 } from "os";
|
|
7066
7066
|
function validKeys() {
|
|
7067
|
-
return [...Object.keys(ENUM_KEYS), ...STRING_KEYS];
|
|
7067
|
+
return ["mode", ...Object.keys(ENUM_KEYS), ...STRING_KEYS];
|
|
7068
|
+
}
|
|
7069
|
+
function allowedValues(key) {
|
|
7070
|
+
if (key === "mode")
|
|
7071
|
+
return MODE_VALUES;
|
|
7072
|
+
return ENUM_KEYS[key];
|
|
7068
7073
|
}
|
|
7069
7074
|
function normalizeConfigValue(key, value) {
|
|
7070
7075
|
if (typeof value !== "string")
|
|
7071
7076
|
return;
|
|
7072
|
-
|
|
7077
|
+
if (key === "mode")
|
|
7078
|
+
return MODE_ALIASES[value.trim().toLowerCase()];
|
|
7079
|
+
const allowed = allowedValues(key);
|
|
7073
7080
|
if (allowed)
|
|
7074
7081
|
return allowed.includes(value) ? value : undefined;
|
|
7075
7082
|
if (key === "apiUrl") {
|
|
@@ -7127,15 +7134,23 @@ function loadConfig() {
|
|
|
7127
7134
|
const projectConfig = readConfigFile(getConfigPath("project"));
|
|
7128
7135
|
return { ...globalConfig2, ...projectConfig };
|
|
7129
7136
|
}
|
|
7130
|
-
var ENUM_KEYS, STRING_KEYS;
|
|
7137
|
+
var ENUM_KEYS, STRING_KEYS, MODE_VALUES, MODE_ALIASES;
|
|
7131
7138
|
var init_config = __esm(() => {
|
|
7132
7139
|
ENUM_KEYS = {
|
|
7133
|
-
mode: ["local", "skills.md"],
|
|
7134
7140
|
defaultAgent: ["claude", "codex", "gemini", "pi", "opencode", "all"],
|
|
7135
7141
|
defaultScope: ["global", "project"],
|
|
7136
7142
|
format: ["compact", "json", "csv"]
|
|
7137
7143
|
};
|
|
7138
7144
|
STRING_KEYS = ["apiUrl"];
|
|
7145
|
+
MODE_VALUES = ["local", "hosted"];
|
|
7146
|
+
MODE_ALIASES = {
|
|
7147
|
+
local: "local",
|
|
7148
|
+
offline: "local",
|
|
7149
|
+
hosted: "hosted",
|
|
7150
|
+
remote: "hosted",
|
|
7151
|
+
"skills.md": "hosted",
|
|
7152
|
+
skillsmd: "hosted"
|
|
7153
|
+
};
|
|
7139
7154
|
});
|
|
7140
7155
|
|
|
7141
7156
|
// src/lib/auth-store.ts
|
|
@@ -7148,14 +7163,14 @@ __export(exports_auth_store, {
|
|
|
7148
7163
|
getApiKey: () => getApiKey,
|
|
7149
7164
|
clearAuthConfig: () => clearAuthConfig
|
|
7150
7165
|
});
|
|
7151
|
-
import { mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync4, unlinkSync } from "fs";
|
|
7166
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync4, unlinkSync } from "fs";
|
|
7152
7167
|
import { join as join7 } from "path";
|
|
7153
7168
|
import { homedir as homedir4 } from "os";
|
|
7154
7169
|
function getAuthConfig() {
|
|
7155
7170
|
if (cachedConfig !== undefined)
|
|
7156
7171
|
return cachedConfig;
|
|
7157
7172
|
try {
|
|
7158
|
-
const raw = readFileSync7(AUTH_FILE, "utf-8");
|
|
7173
|
+
const raw = readFileSync7(existsSync7(AUTH_FILE) ? AUTH_FILE : LEGACY_AUTH_FILE, "utf-8");
|
|
7159
7174
|
const config2 = JSON.parse(raw);
|
|
7160
7175
|
if (!config2.apiKey || !config2.email) {
|
|
7161
7176
|
cachedConfig = null;
|
|
@@ -7169,7 +7184,7 @@ function getAuthConfig() {
|
|
|
7169
7184
|
}
|
|
7170
7185
|
}
|
|
7171
7186
|
function saveAuthConfig(config2) {
|
|
7172
|
-
mkdirSync4(AUTH_DIR, { recursive: true });
|
|
7187
|
+
mkdirSync4(AUTH_DIR, { recursive: true, mode: 448 });
|
|
7173
7188
|
writeFileSync4(AUTH_FILE, JSON.stringify(config2, null, 2) + `
|
|
7174
7189
|
`, { mode: 384 });
|
|
7175
7190
|
cachedConfig = config2;
|
|
@@ -7178,6 +7193,9 @@ function clearAuthConfig() {
|
|
|
7178
7193
|
try {
|
|
7179
7194
|
unlinkSync(AUTH_FILE);
|
|
7180
7195
|
} catch {}
|
|
7196
|
+
try {
|
|
7197
|
+
unlinkSync(LEGACY_AUTH_FILE);
|
|
7198
|
+
} catch {}
|
|
7181
7199
|
cachedConfig = null;
|
|
7182
7200
|
}
|
|
7183
7201
|
function getApiKey() {
|
|
@@ -7200,11 +7218,12 @@ function normalizeSkillsApiOrigin(apiUrl) {
|
|
|
7200
7218
|
function getApiUrl() {
|
|
7201
7219
|
return normalizeSkillsApiOrigin(process.env.SKILLS_API_URL || loadConfig().apiUrl || "https://skills.md");
|
|
7202
7220
|
}
|
|
7203
|
-
var AUTH_DIR, AUTH_FILE, cachedConfig;
|
|
7221
|
+
var AUTH_DIR, AUTH_FILE, LEGACY_AUTH_FILE, cachedConfig;
|
|
7204
7222
|
var init_auth_store = __esm(() => {
|
|
7205
7223
|
init_config();
|
|
7206
|
-
AUTH_DIR = join7(homedir4(), ".skills");
|
|
7224
|
+
AUTH_DIR = join7(homedir4(), ".hasna", "skills");
|
|
7207
7225
|
AUTH_FILE = join7(AUTH_DIR, "auth.json");
|
|
7226
|
+
LEGACY_AUTH_FILE = join7(homedir4(), ".skills", "auth.json");
|
|
7208
7227
|
});
|
|
7209
7228
|
|
|
7210
7229
|
// src/lib/remote-client.ts
|
|
@@ -21768,7 +21787,7 @@ class StdioServerTransport {
|
|
|
21768
21787
|
// package.json
|
|
21769
21788
|
var package_default = {
|
|
21770
21789
|
name: "@hasna/skills",
|
|
21771
|
-
version: "0.1.
|
|
21790
|
+
version: "0.1.32",
|
|
21772
21791
|
description: "Skills library for AI coding agents",
|
|
21773
21792
|
type: "module",
|
|
21774
21793
|
bin: {
|
|
@@ -32882,7 +32901,7 @@ function registerDiscoveryTools(server) {
|
|
|
32882
32901
|
}
|
|
32883
32902
|
|
|
32884
32903
|
// src/mcp/operation-tools.ts
|
|
32885
|
-
import { existsSync as
|
|
32904
|
+
import { existsSync as existsSync8, readdirSync as readdirSync3, statSync as statSync2 } from "fs";
|
|
32886
32905
|
import { join as join8 } from "path";
|
|
32887
32906
|
|
|
32888
32907
|
// src/lib/run-state.ts
|
|
@@ -33271,7 +33290,7 @@ function registerOperationTools(server) {
|
|
|
33271
33290
|
});
|
|
33272
33291
|
if (isPremiumSkill2(skillName) && !apiKey) {
|
|
33273
33292
|
const cost = formatCost2(costCents ?? 0);
|
|
33274
|
-
const error48 = `${skillName} is a hosted skill (${cost}). Run: skills setup --mode
|
|
33293
|
+
const error48 = `${skillName} is a hosted skill (${cost}). Run: skills setup --mode hosted && skills auth login`;
|
|
33275
33294
|
writeRunLogs(runContext, "", error48 + `
|
|
33276
33295
|
`);
|
|
33277
33296
|
const run = completeSkillRun(runContext, { status: "failed", error: error48, costCents });
|
|
@@ -33307,9 +33326,9 @@ function registerOperationTools(server) {
|
|
|
33307
33326
|
nextActions: remoteRunNextActions(remoteRunId)
|
|
33308
33327
|
});
|
|
33309
33328
|
} catch (err) {
|
|
33310
|
-
console.error(`[skills]
|
|
33329
|
+
console.error(`[skills] hosted API failed for ${skillName}, falling back to local:`, err.message);
|
|
33311
33330
|
if (isPremiumSkill2(skillName)) {
|
|
33312
|
-
const error48 = `Hosted skill ${skillName} requires
|
|
33331
|
+
const error48 = `Hosted skill ${skillName} requires hosted access: ${err.message}`;
|
|
33313
33332
|
writeRunLogs(runContext, "", error48 + `
|
|
33314
33333
|
`);
|
|
33315
33334
|
const localRun2 = completeSkillRun(runContext, { status: "failed", error: error48 });
|
|
@@ -33350,7 +33369,7 @@ function registerOperationTools(server) {
|
|
|
33350
33369
|
const { getApiKey: getApiKey2 } = await Promise.resolve().then(() => (init_auth_store(), exports_auth_store));
|
|
33351
33370
|
const apiKey = getApiKey2();
|
|
33352
33371
|
if (!apiKey) {
|
|
33353
|
-
return mcpError("AUTH_REQUIRED", "Remote run status requires
|
|
33372
|
+
return mcpError("AUTH_REQUIRED", "Remote run status requires hosted access. Run: skills auth login", ["skills auth login"]);
|
|
33354
33373
|
}
|
|
33355
33374
|
const localRun = findSkillRun(run_id);
|
|
33356
33375
|
const remoteRunId = localRun?.remoteRunId || run_id;
|
|
@@ -33436,7 +33455,7 @@ function registerOperationTools(server) {
|
|
|
33436
33455
|
const agents = [];
|
|
33437
33456
|
for (const agent of AGENT_TARGETS) {
|
|
33438
33457
|
const agentSkillsPath = getAgentSkillsDir(agent, "global");
|
|
33439
|
-
const exists =
|
|
33458
|
+
const exists = existsSync8(agentSkillsPath);
|
|
33440
33459
|
let skillCount = 0;
|
|
33441
33460
|
if (exists) {
|
|
33442
33461
|
try {
|
|
@@ -33462,7 +33481,7 @@ function registerOperationTools(server) {
|
|
|
33462
33481
|
}
|
|
33463
33482
|
|
|
33464
33483
|
// src/lib/feedback.ts
|
|
33465
|
-
import { existsSync as
|
|
33484
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync5 } from "fs";
|
|
33466
33485
|
import { homedir as homedir5 } from "os";
|
|
33467
33486
|
import { dirname as dirname3, join as join9 } from "path";
|
|
33468
33487
|
import { Database } from "bun:sqlite";
|
|
@@ -33472,7 +33491,7 @@ function getFeedbackDbPath() {
|
|
|
33472
33491
|
function getFeedbackDb() {
|
|
33473
33492
|
const dbPath = getFeedbackDbPath();
|
|
33474
33493
|
const dir = dirname3(dbPath);
|
|
33475
|
-
if (!
|
|
33494
|
+
if (!existsSync9(dir))
|
|
33476
33495
|
mkdirSync5(dir, { recursive: true });
|
|
33477
33496
|
const db = new Database(dbPath);
|
|
33478
33497
|
db.exec("PRAGMA journal_mode = WAL");
|
|
@@ -33621,14 +33640,14 @@ function registerResourceMetaTools(server) {
|
|
|
33621
33640
|
}
|
|
33622
33641
|
|
|
33623
33642
|
// src/lib/scheduler.ts
|
|
33624
|
-
import { existsSync as
|
|
33643
|
+
import { existsSync as existsSync10, readFileSync as readFileSync8, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6 } from "fs";
|
|
33625
33644
|
import { join as join10 } from "path";
|
|
33626
33645
|
function getSchedulesPath(targetDir = process.cwd()) {
|
|
33627
33646
|
return join10(targetDir, ".skills", "schedules.json");
|
|
33628
33647
|
}
|
|
33629
33648
|
function loadSchedules(targetDir = process.cwd()) {
|
|
33630
33649
|
const path = getSchedulesPath(targetDir);
|
|
33631
|
-
if (
|
|
33650
|
+
if (existsSync10(path)) {
|
|
33632
33651
|
try {
|
|
33633
33652
|
return JSON.parse(readFileSync8(path, "utf-8"));
|
|
33634
33653
|
} catch {}
|
|
@@ -33638,7 +33657,7 @@ function loadSchedules(targetDir = process.cwd()) {
|
|
|
33638
33657
|
function saveSchedules(data, targetDir = process.cwd()) {
|
|
33639
33658
|
const path = getSchedulesPath(targetDir);
|
|
33640
33659
|
const dir = join10(targetDir, ".skills");
|
|
33641
|
-
if (!
|
|
33660
|
+
if (!existsSync10(dir))
|
|
33642
33661
|
mkdirSync6(dir, { recursive: true });
|
|
33643
33662
|
writeFileSync5(path, JSON.stringify(data, null, 2));
|
|
33644
33663
|
}
|
|
@@ -33799,7 +33818,7 @@ function removeSchedule(idOrName, targetDir) {
|
|
|
33799
33818
|
}
|
|
33800
33819
|
|
|
33801
33820
|
// src/lib/skill-validation.ts
|
|
33802
|
-
import { existsSync as
|
|
33821
|
+
import { existsSync as existsSync11, lstatSync, readFileSync as readFileSync9, readdirSync as readdirSync4, statSync as statSync3 } from "fs";
|
|
33803
33822
|
import { isAbsolute, join as join11, normalize } from "path";
|
|
33804
33823
|
var DOC_FILES = ["SKILL.md", "README.md", "CLAUDE.md"];
|
|
33805
33824
|
var RESERVED_SKILL_ENTRIES = new Set([
|
|
@@ -33916,7 +33935,7 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
33916
33935
|
binCommands: [],
|
|
33917
33936
|
docFiles: []
|
|
33918
33937
|
};
|
|
33919
|
-
if (!
|
|
33938
|
+
if (!existsSync11(skillPath)) {
|
|
33920
33939
|
add(issues, "skill.dir_missing", `Skill directory not found: ${skillPath}`);
|
|
33921
33940
|
return {
|
|
33922
33941
|
name: bareName,
|
|
@@ -33943,14 +33962,14 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
33943
33962
|
}
|
|
33944
33963
|
}
|
|
33945
33964
|
for (const docFile of DOC_FILES) {
|
|
33946
|
-
if (
|
|
33965
|
+
if (existsSync11(join11(skillPath, docFile)))
|
|
33947
33966
|
metadata.docFiles.push(docFile);
|
|
33948
33967
|
}
|
|
33949
33968
|
if (metadata.docFiles.length === 0) {
|
|
33950
33969
|
add(issues, "skill.docs_missing", "Missing documentation file: expected SKILL.md, README.md, or CLAUDE.md");
|
|
33951
33970
|
}
|
|
33952
33971
|
const skillMdPath = join11(skillPath, "SKILL.md");
|
|
33953
|
-
if (
|
|
33972
|
+
if (existsSync11(skillMdPath)) {
|
|
33954
33973
|
const frontmatter = parseSkillFrontmatter(readFileSync9(skillMdPath, "utf-8"));
|
|
33955
33974
|
if (!frontmatter) {
|
|
33956
33975
|
add(warnings, "skill.frontmatter_missing", "SKILL.md has no YAML frontmatter");
|
|
@@ -33985,7 +34004,7 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
33985
34004
|
add(warnings, "skill.skill_md_missing", "Missing SKILL.md; registry docs may need generated agent-facing instructions");
|
|
33986
34005
|
}
|
|
33987
34006
|
const pkgPath = join11(skillPath, "package.json");
|
|
33988
|
-
if (!
|
|
34007
|
+
if (!existsSync11(pkgPath)) {
|
|
33989
34008
|
add(issues, "package.missing", "Missing package.json");
|
|
33990
34009
|
} else {
|
|
33991
34010
|
try {
|
|
@@ -34030,7 +34049,7 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
34030
34049
|
continue;
|
|
34031
34050
|
}
|
|
34032
34051
|
const targetPath = join11(skillPath, target);
|
|
34033
|
-
if (!
|
|
34052
|
+
if (!existsSync11(targetPath)) {
|
|
34034
34053
|
add(warnings, "package.bin_target_missing", `package.json bin '${command}' target '${target}' is not present before build`);
|
|
34035
34054
|
} else if (statSync3(targetPath).isDirectory()) {
|
|
34036
34055
|
add(issues, "package.bin_target_directory", `package.json bin '${command}' target '${target}' must point to a file, not a directory`);
|
|
@@ -34043,12 +34062,12 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
34043
34062
|
}
|
|
34044
34063
|
}
|
|
34045
34064
|
const srcDir = join11(skillPath, "src");
|
|
34046
|
-
if (!
|
|
34065
|
+
if (!existsSync11(srcDir)) {
|
|
34047
34066
|
add(issues, "skill.src_missing", "Missing src/ directory");
|
|
34048
|
-
} else if (!
|
|
34067
|
+
} else if (!existsSync11(join11(srcDir, "index.ts")) && !existsSync11(join11(srcDir, "index.js"))) {
|
|
34049
34068
|
add(issues, "skill.src_index_missing", "Missing src/index.ts or src/index.js");
|
|
34050
34069
|
} else {
|
|
34051
|
-
const indexPath =
|
|
34070
|
+
const indexPath = existsSync11(join11(srcDir, "index.ts")) ? join11(srcDir, "index.ts") : join11(srcDir, "index.js");
|
|
34052
34071
|
const size = statSync3(indexPath).size;
|
|
34053
34072
|
if (size < 50)
|
|
34054
34073
|
add(warnings, "skill.src_index_minimal", `Source entry point is very small (${size}B)`);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
import { type SkillsConfig } from "../lib/config.js";
|
|
3
|
+
export interface FirstRunOnboardingInput {
|
|
4
|
+
argv: string[];
|
|
5
|
+
commandName?: string;
|
|
6
|
+
config: SkillsConfig;
|
|
7
|
+
isInteractive: boolean;
|
|
8
|
+
testMode?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function getRootCommandName(actionCommand: Command): string;
|
|
11
|
+
export declare function shouldShowFirstRunOnboarding(input: FirstRunOnboardingInput): boolean;
|
|
12
|
+
export declare function getFirstRunOnboardingMessage(): string;
|
|
13
|
+
export declare function maybePrintFirstRunOnboarding(actionCommand: Command, argv: string[], isInteractive: boolean): void;
|
package/dist/index.js
CHANGED
|
@@ -3395,19 +3395,34 @@ import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync
|
|
|
3395
3395
|
import { join as join6, dirname as dirname2 } from "path";
|
|
3396
3396
|
import { homedir as homedir3 } from "os";
|
|
3397
3397
|
var ENUM_KEYS = {
|
|
3398
|
-
mode: ["local", "skills.md"],
|
|
3399
3398
|
defaultAgent: ["claude", "codex", "gemini", "pi", "opencode", "all"],
|
|
3400
3399
|
defaultScope: ["global", "project"],
|
|
3401
3400
|
format: ["compact", "json", "csv"]
|
|
3402
3401
|
};
|
|
3403
3402
|
var STRING_KEYS = ["apiUrl"];
|
|
3403
|
+
var MODE_VALUES = ["local", "hosted"];
|
|
3404
|
+
var MODE_ALIASES = {
|
|
3405
|
+
local: "local",
|
|
3406
|
+
offline: "local",
|
|
3407
|
+
hosted: "hosted",
|
|
3408
|
+
remote: "hosted",
|
|
3409
|
+
"skills.md": "hosted",
|
|
3410
|
+
skillsmd: "hosted"
|
|
3411
|
+
};
|
|
3404
3412
|
function validKeys() {
|
|
3405
|
-
return [...Object.keys(ENUM_KEYS), ...STRING_KEYS];
|
|
3413
|
+
return ["mode", ...Object.keys(ENUM_KEYS), ...STRING_KEYS];
|
|
3414
|
+
}
|
|
3415
|
+
function allowedValues(key) {
|
|
3416
|
+
if (key === "mode")
|
|
3417
|
+
return MODE_VALUES;
|
|
3418
|
+
return ENUM_KEYS[key];
|
|
3406
3419
|
}
|
|
3407
3420
|
function normalizeConfigValue(key, value) {
|
|
3408
3421
|
if (typeof value !== "string")
|
|
3409
3422
|
return;
|
|
3410
|
-
|
|
3423
|
+
if (key === "mode")
|
|
3424
|
+
return MODE_ALIASES[value.trim().toLowerCase()];
|
|
3425
|
+
const allowed = allowedValues(key);
|
|
3411
3426
|
if (allowed)
|
|
3412
3427
|
return allowed.includes(value) ? value : undefined;
|
|
3413
3428
|
if (key === "apiUrl") {
|
|
@@ -3471,7 +3486,7 @@ function saveConfig(key, value, scope = "project") {
|
|
|
3471
3486
|
}
|
|
3472
3487
|
const normalized = normalizeConfigValue(key, value);
|
|
3473
3488
|
if (normalized === undefined) {
|
|
3474
|
-
const allowed =
|
|
3489
|
+
const allowed = allowedValues(key);
|
|
3475
3490
|
throw new Error(allowed ? `Invalid value '${value}' for ${key}. Allowed: ${allowed.join(", ")}` : `Invalid value '${value}' for ${key}. Expected an http(s) URL`);
|
|
3476
3491
|
}
|
|
3477
3492
|
const filePath = getConfigPath(scope);
|
|
@@ -17028,17 +17043,18 @@ function date4(params) {
|
|
|
17028
17043
|
// node_modules/zod/v4/classic/external.js
|
|
17029
17044
|
config(en_default());
|
|
17030
17045
|
// src/lib/auth-store.ts
|
|
17031
|
-
import { mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync4, unlinkSync } from "fs";
|
|
17046
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync4, unlinkSync } from "fs";
|
|
17032
17047
|
import { join as join7 } from "path";
|
|
17033
17048
|
import { homedir as homedir4 } from "os";
|
|
17034
|
-
var AUTH_DIR = join7(homedir4(), ".skills");
|
|
17049
|
+
var AUTH_DIR = join7(homedir4(), ".hasna", "skills");
|
|
17035
17050
|
var AUTH_FILE = join7(AUTH_DIR, "auth.json");
|
|
17051
|
+
var LEGACY_AUTH_FILE = join7(homedir4(), ".skills", "auth.json");
|
|
17036
17052
|
var cachedConfig;
|
|
17037
17053
|
function getAuthConfig() {
|
|
17038
17054
|
if (cachedConfig !== undefined)
|
|
17039
17055
|
return cachedConfig;
|
|
17040
17056
|
try {
|
|
17041
|
-
const raw = readFileSync7(AUTH_FILE, "utf-8");
|
|
17057
|
+
const raw = readFileSync7(existsSync7(AUTH_FILE) ? AUTH_FILE : LEGACY_AUTH_FILE, "utf-8");
|
|
17042
17058
|
const config2 = JSON.parse(raw);
|
|
17043
17059
|
if (!config2.apiKey || !config2.email) {
|
|
17044
17060
|
cachedConfig = null;
|
|
@@ -17472,14 +17488,14 @@ function createRemoteSkillsClient() {
|
|
|
17472
17488
|
return new RemoteSkillsClient(apiKey);
|
|
17473
17489
|
}
|
|
17474
17490
|
// src/lib/scheduler.ts
|
|
17475
|
-
import { existsSync as
|
|
17491
|
+
import { existsSync as existsSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5 } from "fs";
|
|
17476
17492
|
import { join as join8 } from "path";
|
|
17477
17493
|
function getSchedulesPath(targetDir = process.cwd()) {
|
|
17478
17494
|
return join8(targetDir, ".skills", "schedules.json");
|
|
17479
17495
|
}
|
|
17480
17496
|
function loadSchedules(targetDir = process.cwd()) {
|
|
17481
17497
|
const path = getSchedulesPath(targetDir);
|
|
17482
|
-
if (
|
|
17498
|
+
if (existsSync8(path)) {
|
|
17483
17499
|
try {
|
|
17484
17500
|
return JSON.parse(readFileSync8(path, "utf-8"));
|
|
17485
17501
|
} catch {}
|
|
@@ -17489,7 +17505,7 @@ function loadSchedules(targetDir = process.cwd()) {
|
|
|
17489
17505
|
function saveSchedules(data, targetDir = process.cwd()) {
|
|
17490
17506
|
const path = getSchedulesPath(targetDir);
|
|
17491
17507
|
const dir = join8(targetDir, ".skills");
|
|
17492
|
-
if (!
|
|
17508
|
+
if (!existsSync8(dir))
|
|
17493
17509
|
mkdirSync5(dir, { recursive: true });
|
|
17494
17510
|
writeFileSync5(path, JSON.stringify(data, null, 2));
|
|
17495
17511
|
}
|
|
@@ -17676,7 +17692,7 @@ function recordScheduleRun(id, status, targetDir) {
|
|
|
17676
17692
|
saveSchedules(data, targetDir);
|
|
17677
17693
|
}
|
|
17678
17694
|
// src/lib/skill-validation.ts
|
|
17679
|
-
import { existsSync as
|
|
17695
|
+
import { existsSync as existsSync9, lstatSync, readFileSync as readFileSync9, readdirSync as readdirSync3, statSync as statSync2 } from "fs";
|
|
17680
17696
|
import { isAbsolute, join as join9, normalize } from "path";
|
|
17681
17697
|
var DOC_FILES = ["SKILL.md", "README.md", "CLAUDE.md"];
|
|
17682
17698
|
var RESERVED_SKILL_ENTRIES = new Set([
|
|
@@ -17793,7 +17809,7 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
17793
17809
|
binCommands: [],
|
|
17794
17810
|
docFiles: []
|
|
17795
17811
|
};
|
|
17796
|
-
if (!
|
|
17812
|
+
if (!existsSync9(skillPath)) {
|
|
17797
17813
|
add(issues, "skill.dir_missing", `Skill directory not found: ${skillPath}`);
|
|
17798
17814
|
return {
|
|
17799
17815
|
name: bareName,
|
|
@@ -17820,14 +17836,14 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
17820
17836
|
}
|
|
17821
17837
|
}
|
|
17822
17838
|
for (const docFile of DOC_FILES) {
|
|
17823
|
-
if (
|
|
17839
|
+
if (existsSync9(join9(skillPath, docFile)))
|
|
17824
17840
|
metadata.docFiles.push(docFile);
|
|
17825
17841
|
}
|
|
17826
17842
|
if (metadata.docFiles.length === 0) {
|
|
17827
17843
|
add(issues, "skill.docs_missing", "Missing documentation file: expected SKILL.md, README.md, or CLAUDE.md");
|
|
17828
17844
|
}
|
|
17829
17845
|
const skillMdPath = join9(skillPath, "SKILL.md");
|
|
17830
|
-
if (
|
|
17846
|
+
if (existsSync9(skillMdPath)) {
|
|
17831
17847
|
const frontmatter = parseSkillFrontmatter(readFileSync9(skillMdPath, "utf-8"));
|
|
17832
17848
|
if (!frontmatter) {
|
|
17833
17849
|
add(warnings, "skill.frontmatter_missing", "SKILL.md has no YAML frontmatter");
|
|
@@ -17862,7 +17878,7 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
17862
17878
|
add(warnings, "skill.skill_md_missing", "Missing SKILL.md; registry docs may need generated agent-facing instructions");
|
|
17863
17879
|
}
|
|
17864
17880
|
const pkgPath = join9(skillPath, "package.json");
|
|
17865
|
-
if (!
|
|
17881
|
+
if (!existsSync9(pkgPath)) {
|
|
17866
17882
|
add(issues, "package.missing", "Missing package.json");
|
|
17867
17883
|
} else {
|
|
17868
17884
|
try {
|
|
@@ -17907,7 +17923,7 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
17907
17923
|
continue;
|
|
17908
17924
|
}
|
|
17909
17925
|
const targetPath = join9(skillPath, target);
|
|
17910
|
-
if (!
|
|
17926
|
+
if (!existsSync9(targetPath)) {
|
|
17911
17927
|
add(warnings, "package.bin_target_missing", `package.json bin '${command}' target '${target}' is not present before build`);
|
|
17912
17928
|
} else if (statSync2(targetPath).isDirectory()) {
|
|
17913
17929
|
add(issues, "package.bin_target_directory", `package.json bin '${command}' target '${target}' must point to a file, not a directory`);
|
|
@@ -17920,12 +17936,12 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
17920
17936
|
}
|
|
17921
17937
|
}
|
|
17922
17938
|
const srcDir = join9(skillPath, "src");
|
|
17923
|
-
if (!
|
|
17939
|
+
if (!existsSync9(srcDir)) {
|
|
17924
17940
|
add(issues, "skill.src_missing", "Missing src/ directory");
|
|
17925
|
-
} else if (!
|
|
17941
|
+
} else if (!existsSync9(join9(srcDir, "index.ts")) && !existsSync9(join9(srcDir, "index.js"))) {
|
|
17926
17942
|
add(issues, "skill.src_index_missing", "Missing src/index.ts or src/index.js");
|
|
17927
17943
|
} else {
|
|
17928
|
-
const indexPath =
|
|
17944
|
+
const indexPath = existsSync9(join9(srcDir, "index.ts")) ? join9(srcDir, "index.ts") : join9(srcDir, "index.js");
|
|
17929
17945
|
const size = statSync2(indexPath).size;
|
|
17930
17946
|
if (size < 50)
|
|
17931
17947
|
add(warnings, "skill.src_index_minimal", `Source entry point is very small (${size}B)`);
|
|
@@ -17948,7 +17964,7 @@ function validateRegistryConsistency(registry2, skillsDir) {
|
|
|
17948
17964
|
seen.add(name);
|
|
17949
17965
|
return false;
|
|
17950
17966
|
})));
|
|
17951
|
-
const skillDirs =
|
|
17967
|
+
const skillDirs = existsSync9(skillsDir) ? readdirSync3(skillsDir).filter((entry) => {
|
|
17952
17968
|
const fullPath = join9(skillsDir, entry);
|
|
17953
17969
|
return !entry.startsWith(".") && entry !== "_common" && statSync2(fullPath).isDirectory();
|
|
17954
17970
|
}) : [];
|
|
@@ -17969,7 +17985,7 @@ import { dirname as dirname3, relative as relative2 } from "path";
|
|
|
17969
17985
|
// package.json
|
|
17970
17986
|
var package_default = {
|
|
17971
17987
|
name: "@hasna/skills",
|
|
17972
|
-
version: "0.1.
|
|
17988
|
+
version: "0.1.32",
|
|
17973
17989
|
description: "Skills library for AI coding agents",
|
|
17974
17990
|
type: "module",
|
|
17975
17991
|
bin: {
|
|
@@ -18763,7 +18779,7 @@ function clone2(value) {
|
|
|
18763
18779
|
return JSON.parse(JSON.stringify(value));
|
|
18764
18780
|
}
|
|
18765
18781
|
// src/lib/feedback.ts
|
|
18766
|
-
import { existsSync as
|
|
18782
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync7 } from "fs";
|
|
18767
18783
|
import { homedir as homedir5 } from "os";
|
|
18768
18784
|
import { dirname as dirname4, join as join10 } from "path";
|
|
18769
18785
|
import { Database } from "bun:sqlite";
|
|
@@ -18773,7 +18789,7 @@ function getFeedbackDbPath() {
|
|
|
18773
18789
|
function getFeedbackDb() {
|
|
18774
18790
|
const dbPath = getFeedbackDbPath();
|
|
18775
18791
|
const dir = dirname4(dbPath);
|
|
18776
|
-
if (!
|
|
18792
|
+
if (!existsSync10(dir))
|
|
18777
18793
|
mkdirSync7(dir, { recursive: true });
|
|
18778
18794
|
const db = new Database(dbPath);
|
|
18779
18795
|
db.exec("PRAGMA journal_mode = WAL");
|
package/dist/lib/config.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* Values from the project config override global config.
|
|
10
10
|
*/
|
|
11
11
|
export interface SkillsConfig {
|
|
12
|
-
mode?: "local" | "
|
|
12
|
+
mode?: "local" | "hosted";
|
|
13
13
|
defaultAgent?: "claude" | "codex" | "gemini" | "pi" | "opencode" | "all";
|
|
14
14
|
defaultScope?: "global" | "project";
|
|
15
15
|
format?: "compact" | "json" | "csv";
|