@hasna/skills 0.1.31 → 0.1.33
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 -30
- package/bin/index.js +577 -282
- package/bin/mcp.js +102 -39
- package/dist/cli/commands/runtime.d.ts +1 -1
- package/dist/cli/onboarding.d.ts +13 -0
- package/dist/index.js +88 -26
- package/dist/lib/config.d.ts +1 -1
- package/dist/lib/skill-validation.d.ts +2 -0
- package/package.json +1 -1
- package/skills/ad-creative-pack/package.json +4 -7
- package/skills/api-docs-portal/package.json +5 -3
- package/skills/audio/package.json +4 -22
- package/skills/audio-transcript-pack/package.json +3 -2
- package/skills/blog-article/package.json +5 -21
- package/skills/brand-kit/package.json +4 -7
- package/skills/brand-photo-shoot/package.json +3 -2
- package/skills/browse/package.json +4 -33
- package/skills/contract-review-report/package.json +3 -2
- package/skills/customer-feedback-report/package.json +3 -2
- package/skills/deepresearch/package.json +4 -37
- package/skills/domainpurchase/SKILL.md +14 -31
- package/skills/domainpurchase/package.json +3 -8
- package/skills/email-sequence/package.json +4 -7
- package/skills/generate-book-cover/package.json +5 -23
- package/skills/icon-pack/package.json +4 -22
- package/skills/image/package.json +4 -22
- package/skills/invoice-reconciliation/package.json +3 -2
- package/skills/landing-page-pack/package.json +4 -7
- package/skills/logo-design/package.json +4 -2
- package/skills/managemcp/CLAUDE.md +9 -43
- package/skills/managemcp/README.md +12 -198
- package/skills/managemcp/package.json +2 -10
- package/skills/managemcp/tsconfig.json +1 -3
- package/skills/market-research-report/package.json +5 -4
- package/skills/meeting-pack/package.json +3 -2
- package/skills/migration-plan-pack/package.json +3 -2
- package/skills/music/package.json +4 -20
- package/skills/music-album/package.json +3 -2
- package/skills/one-page-website/package.json +3 -2
- package/skills/pdf-read/package.json +5 -23
- package/skills/pdf-to-dataset/package.json +5 -4
- package/skills/pdf-to-markdown/package.json +5 -4
- package/skills/performance-audit-report/package.json +3 -2
- package/skills/photo-album/package.json +4 -2
- package/skills/pitch-deck/package.json +5 -3
- package/skills/playlist-maker/package.json +4 -2
- package/skills/product-mockup/package.json +3 -2
- package/skills/proposal-pack/package.json +5 -4
- package/skills/read-pdf/package.json +4 -29
- package/skills/remove-background/package.json +5 -21
- package/skills/repo-onboarding-report/package.json +3 -2
- package/skills/sdk-generator/package.json +3 -2
- package/skills/security-audit-report/package.json +5 -4
- package/skills/seo-content-pack/package.json +5 -3
- package/skills/short-video-pack/package.json +3 -2
- package/skills/slide-deck-generator/package.json +3 -2
- package/skills/sms/README.md +18 -56
- package/skills/sms/package.json +1 -3
- package/skills/sms/tsconfig.json +1 -2
- package/skills/social-content-calendar/package.json +4 -7
- package/skills/test-suite-generator/package.json +5 -4
- package/skills/transcript/package.json +4 -23
- package/skills/video/package.json +4 -24
- package/skills/video-highlight-pack/package.json +3 -2
- package/skills/voiceover-jingle-pack/package.json +3 -2
- package/skills/webcrawling/package.json +4 -32
- package/skills/domainpurchase/.env.example +0 -7
- package/skills/domainpurchase/src/lib/api-client.ts +0 -571
- package/skills/domainpurchase/src/lib/config.ts +0 -209
- package/skills/domainpurchase/src/lib/installer.ts +0 -165
- package/skills/managemcp/.env.example +0 -16
- package/skills/managemcp/scripts/migrate.ts +0 -57
- package/skills/managemcp/scripts/seed.ts +0 -58
- package/skills/managemcp/src/db/index.ts +0 -37
- package/skills/managemcp/src/lib/api-client.ts +0 -108
- package/skills/managemcp/src/lib/config.ts +0 -34
- package/skills/managemcp/src/lib/installer.ts +0 -140
- package/skills/managemcp/src/lib/service-dir.ts +0 -119
- package/skills/sms/scripts/buy-number.ts +0 -63
- package/skills/sms/scripts/test-send.ts +0 -67
- package/skills/sms/src/server.ts +0 -351
- package/skills/sms/src/sse-server.ts +0 -279
package/bin/mcp.js
CHANGED
|
@@ -6921,7 +6921,13 @@ function formatCost(cents) {
|
|
|
6921
6921
|
return `$${(cents / 100).toFixed(2)}`;
|
|
6922
6922
|
}
|
|
6923
6923
|
function getAllPremiumSlugs() {
|
|
6924
|
-
return [
|
|
6924
|
+
return [
|
|
6925
|
+
...new Set([
|
|
6926
|
+
...PREMIUM_SKILLS.map((skill) => skill.slug),
|
|
6927
|
+
...MEDIA_GENERATION_PRICES.map((price) => price.slug),
|
|
6928
|
+
ARTICLE_GENERATION_SLUG
|
|
6929
|
+
])
|
|
6930
|
+
].sort();
|
|
6925
6931
|
}
|
|
6926
6932
|
var MUSIC_ALBUM_SLUG = "music-album", MUSIC_ALBUM_SONG_COUNTS, MUSIC_ALBUM_COST_CENTS_PER_SONG = 150, PREMIUM_SKILLS, ARTICLE_GENERATION_SLUG = "blog-article", ARTICLE_MAX_COUNT = 12, ARTICLE_COUNT_ERROR, ARTICLE_INTERNAL_COST_CENTS = 5, ARTICLE_MARKUP_MULTIPLIER = 5, ARTICLE_USER_COST_CENTS, ARTICLE_TONES, ARTICLE_LENGTHS, MEDIA_GENERATION_PRICES, premiumIndex, mediaSlugs;
|
|
6927
6933
|
var init_pricing = __esm(() => {
|
|
@@ -7064,12 +7070,19 @@ import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync
|
|
|
7064
7070
|
import { join as join6, dirname as dirname2 } from "path";
|
|
7065
7071
|
import { homedir as homedir3 } from "os";
|
|
7066
7072
|
function validKeys() {
|
|
7067
|
-
return [...Object.keys(ENUM_KEYS), ...STRING_KEYS];
|
|
7073
|
+
return ["mode", ...Object.keys(ENUM_KEYS), ...STRING_KEYS];
|
|
7074
|
+
}
|
|
7075
|
+
function allowedValues(key) {
|
|
7076
|
+
if (key === "mode")
|
|
7077
|
+
return MODE_VALUES;
|
|
7078
|
+
return ENUM_KEYS[key];
|
|
7068
7079
|
}
|
|
7069
7080
|
function normalizeConfigValue(key, value) {
|
|
7070
7081
|
if (typeof value !== "string")
|
|
7071
7082
|
return;
|
|
7072
|
-
|
|
7083
|
+
if (key === "mode")
|
|
7084
|
+
return MODE_ALIASES[value.trim().toLowerCase()];
|
|
7085
|
+
const allowed = allowedValues(key);
|
|
7073
7086
|
if (allowed)
|
|
7074
7087
|
return allowed.includes(value) ? value : undefined;
|
|
7075
7088
|
if (key === "apiUrl") {
|
|
@@ -7127,15 +7140,23 @@ function loadConfig() {
|
|
|
7127
7140
|
const projectConfig = readConfigFile(getConfigPath("project"));
|
|
7128
7141
|
return { ...globalConfig2, ...projectConfig };
|
|
7129
7142
|
}
|
|
7130
|
-
var ENUM_KEYS, STRING_KEYS;
|
|
7143
|
+
var ENUM_KEYS, STRING_KEYS, MODE_VALUES, MODE_ALIASES;
|
|
7131
7144
|
var init_config = __esm(() => {
|
|
7132
7145
|
ENUM_KEYS = {
|
|
7133
|
-
mode: ["local", "skills.md"],
|
|
7134
7146
|
defaultAgent: ["claude", "codex", "gemini", "pi", "opencode", "all"],
|
|
7135
7147
|
defaultScope: ["global", "project"],
|
|
7136
7148
|
format: ["compact", "json", "csv"]
|
|
7137
7149
|
};
|
|
7138
7150
|
STRING_KEYS = ["apiUrl"];
|
|
7151
|
+
MODE_VALUES = ["local", "hosted"];
|
|
7152
|
+
MODE_ALIASES = {
|
|
7153
|
+
local: "local",
|
|
7154
|
+
offline: "local",
|
|
7155
|
+
hosted: "hosted",
|
|
7156
|
+
remote: "hosted",
|
|
7157
|
+
"skills.md": "hosted",
|
|
7158
|
+
skillsmd: "hosted"
|
|
7159
|
+
};
|
|
7139
7160
|
});
|
|
7140
7161
|
|
|
7141
7162
|
// src/lib/auth-store.ts
|
|
@@ -7148,14 +7169,14 @@ __export(exports_auth_store, {
|
|
|
7148
7169
|
getApiKey: () => getApiKey,
|
|
7149
7170
|
clearAuthConfig: () => clearAuthConfig
|
|
7150
7171
|
});
|
|
7151
|
-
import { mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync4, unlinkSync } from "fs";
|
|
7172
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync4, unlinkSync } from "fs";
|
|
7152
7173
|
import { join as join7 } from "path";
|
|
7153
7174
|
import { homedir as homedir4 } from "os";
|
|
7154
7175
|
function getAuthConfig() {
|
|
7155
7176
|
if (cachedConfig !== undefined)
|
|
7156
7177
|
return cachedConfig;
|
|
7157
7178
|
try {
|
|
7158
|
-
const raw = readFileSync7(AUTH_FILE, "utf-8");
|
|
7179
|
+
const raw = readFileSync7(existsSync7(AUTH_FILE) ? AUTH_FILE : LEGACY_AUTH_FILE, "utf-8");
|
|
7159
7180
|
const config2 = JSON.parse(raw);
|
|
7160
7181
|
if (!config2.apiKey || !config2.email) {
|
|
7161
7182
|
cachedConfig = null;
|
|
@@ -7169,7 +7190,7 @@ function getAuthConfig() {
|
|
|
7169
7190
|
}
|
|
7170
7191
|
}
|
|
7171
7192
|
function saveAuthConfig(config2) {
|
|
7172
|
-
mkdirSync4(AUTH_DIR, { recursive: true });
|
|
7193
|
+
mkdirSync4(AUTH_DIR, { recursive: true, mode: 448 });
|
|
7173
7194
|
writeFileSync4(AUTH_FILE, JSON.stringify(config2, null, 2) + `
|
|
7174
7195
|
`, { mode: 384 });
|
|
7175
7196
|
cachedConfig = config2;
|
|
@@ -7178,6 +7199,9 @@ function clearAuthConfig() {
|
|
|
7178
7199
|
try {
|
|
7179
7200
|
unlinkSync(AUTH_FILE);
|
|
7180
7201
|
} catch {}
|
|
7202
|
+
try {
|
|
7203
|
+
unlinkSync(LEGACY_AUTH_FILE);
|
|
7204
|
+
} catch {}
|
|
7181
7205
|
cachedConfig = null;
|
|
7182
7206
|
}
|
|
7183
7207
|
function getApiKey() {
|
|
@@ -7200,11 +7224,12 @@ function normalizeSkillsApiOrigin(apiUrl) {
|
|
|
7200
7224
|
function getApiUrl() {
|
|
7201
7225
|
return normalizeSkillsApiOrigin(process.env.SKILLS_API_URL || loadConfig().apiUrl || "https://skills.md");
|
|
7202
7226
|
}
|
|
7203
|
-
var AUTH_DIR, AUTH_FILE, cachedConfig;
|
|
7227
|
+
var AUTH_DIR, AUTH_FILE, LEGACY_AUTH_FILE, cachedConfig;
|
|
7204
7228
|
var init_auth_store = __esm(() => {
|
|
7205
7229
|
init_config();
|
|
7206
|
-
AUTH_DIR = join7(homedir4(), ".skills");
|
|
7230
|
+
AUTH_DIR = join7(homedir4(), ".hasna", "skills");
|
|
7207
7231
|
AUTH_FILE = join7(AUTH_DIR, "auth.json");
|
|
7232
|
+
LEGACY_AUTH_FILE = join7(homedir4(), ".skills", "auth.json");
|
|
7208
7233
|
});
|
|
7209
7234
|
|
|
7210
7235
|
// src/lib/remote-client.ts
|
|
@@ -21768,7 +21793,7 @@ class StdioServerTransport {
|
|
|
21768
21793
|
// package.json
|
|
21769
21794
|
var package_default = {
|
|
21770
21795
|
name: "@hasna/skills",
|
|
21771
|
-
version: "0.1.
|
|
21796
|
+
version: "0.1.33",
|
|
21772
21797
|
description: "Skills library for AI coding agents",
|
|
21773
21798
|
type: "module",
|
|
21774
21799
|
bin: {
|
|
@@ -32882,7 +32907,7 @@ function registerDiscoveryTools(server) {
|
|
|
32882
32907
|
}
|
|
32883
32908
|
|
|
32884
32909
|
// src/mcp/operation-tools.ts
|
|
32885
|
-
import { existsSync as
|
|
32910
|
+
import { existsSync as existsSync8, readdirSync as readdirSync3, statSync as statSync2 } from "fs";
|
|
32886
32911
|
import { join as join8 } from "path";
|
|
32887
32912
|
|
|
32888
32913
|
// src/lib/run-state.ts
|
|
@@ -33271,13 +33296,13 @@ function registerOperationTools(server) {
|
|
|
33271
33296
|
});
|
|
33272
33297
|
if (isPremiumSkill2(skillName) && !apiKey) {
|
|
33273
33298
|
const cost = formatCost2(costCents ?? 0);
|
|
33274
|
-
const error48 = `${skillName} is a hosted skill (${cost}). Run: skills setup --mode
|
|
33299
|
+
const error48 = `${skillName} is a hosted skill (${cost}). Run: skills setup --mode hosted && skills auth login`;
|
|
33275
33300
|
writeRunLogs(runContext, "", error48 + `
|
|
33276
33301
|
`);
|
|
33277
33302
|
const run = completeSkillRun(runContext, { status: "failed", error: error48, costCents });
|
|
33278
33303
|
return mcpError("AUTH_REQUIRED", `${error48}. Local run metadata: ${run.paths.runDir}/run.json`, ["skills auth login"]);
|
|
33279
33304
|
}
|
|
33280
|
-
if (apiKey) {
|
|
33305
|
+
if (isPremiumSkill2(skillName) && apiKey) {
|
|
33281
33306
|
try {
|
|
33282
33307
|
const { RemoteSkillsClient: RemoteSkillsClient2 } = await Promise.resolve().then(() => (init_remote_client(), exports_remote_client));
|
|
33283
33308
|
const client = new RemoteSkillsClient2(apiKey);
|
|
@@ -33307,14 +33332,11 @@ function registerOperationTools(server) {
|
|
|
33307
33332
|
nextActions: remoteRunNextActions(remoteRunId)
|
|
33308
33333
|
});
|
|
33309
33334
|
} catch (err) {
|
|
33310
|
-
|
|
33311
|
-
|
|
33312
|
-
const error48 = `Hosted skill ${skillName} requires skills.md access: ${err.message}`;
|
|
33313
|
-
writeRunLogs(runContext, "", error48 + `
|
|
33335
|
+
const error48 = `Hosted skill ${skillName} requires hosted access: ${err.message}`;
|
|
33336
|
+
writeRunLogs(runContext, "", error48 + `
|
|
33314
33337
|
`);
|
|
33315
|
-
|
|
33316
|
-
|
|
33317
|
-
}
|
|
33338
|
+
const localRun2 = completeSkillRun(runContext, { status: "failed", error: error48 });
|
|
33339
|
+
return mcpError("PLATFORM_ERROR", `${error48}. Local run metadata: ${localRun2.paths.runDir}/run.json`);
|
|
33318
33340
|
}
|
|
33319
33341
|
}
|
|
33320
33342
|
const result = await runSkill(skillName, runArgs, {
|
|
@@ -33350,7 +33372,7 @@ function registerOperationTools(server) {
|
|
|
33350
33372
|
const { getApiKey: getApiKey2 } = await Promise.resolve().then(() => (init_auth_store(), exports_auth_store));
|
|
33351
33373
|
const apiKey = getApiKey2();
|
|
33352
33374
|
if (!apiKey) {
|
|
33353
|
-
return mcpError("AUTH_REQUIRED", "Remote run status requires
|
|
33375
|
+
return mcpError("AUTH_REQUIRED", "Remote run status requires hosted access. Run: skills auth login", ["skills auth login"]);
|
|
33354
33376
|
}
|
|
33355
33377
|
const localRun = findSkillRun(run_id);
|
|
33356
33378
|
const remoteRunId = localRun?.remoteRunId || run_id;
|
|
@@ -33436,7 +33458,7 @@ function registerOperationTools(server) {
|
|
|
33436
33458
|
const agents = [];
|
|
33437
33459
|
for (const agent of AGENT_TARGETS) {
|
|
33438
33460
|
const agentSkillsPath = getAgentSkillsDir(agent, "global");
|
|
33439
|
-
const exists =
|
|
33461
|
+
const exists = existsSync8(agentSkillsPath);
|
|
33440
33462
|
let skillCount = 0;
|
|
33441
33463
|
if (exists) {
|
|
33442
33464
|
try {
|
|
@@ -33462,7 +33484,7 @@ function registerOperationTools(server) {
|
|
|
33462
33484
|
}
|
|
33463
33485
|
|
|
33464
33486
|
// src/lib/feedback.ts
|
|
33465
|
-
import { existsSync as
|
|
33487
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync5 } from "fs";
|
|
33466
33488
|
import { homedir as homedir5 } from "os";
|
|
33467
33489
|
import { dirname as dirname3, join as join9 } from "path";
|
|
33468
33490
|
import { Database } from "bun:sqlite";
|
|
@@ -33472,7 +33494,7 @@ function getFeedbackDbPath() {
|
|
|
33472
33494
|
function getFeedbackDb() {
|
|
33473
33495
|
const dbPath = getFeedbackDbPath();
|
|
33474
33496
|
const dir = dirname3(dbPath);
|
|
33475
|
-
if (!
|
|
33497
|
+
if (!existsSync9(dir))
|
|
33476
33498
|
mkdirSync5(dir, { recursive: true });
|
|
33477
33499
|
const db = new Database(dbPath);
|
|
33478
33500
|
db.exec("PRAGMA journal_mode = WAL");
|
|
@@ -33621,14 +33643,14 @@ function registerResourceMetaTools(server) {
|
|
|
33621
33643
|
}
|
|
33622
33644
|
|
|
33623
33645
|
// src/lib/scheduler.ts
|
|
33624
|
-
import { existsSync as
|
|
33646
|
+
import { existsSync as existsSync10, readFileSync as readFileSync8, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6 } from "fs";
|
|
33625
33647
|
import { join as join10 } from "path";
|
|
33626
33648
|
function getSchedulesPath(targetDir = process.cwd()) {
|
|
33627
33649
|
return join10(targetDir, ".skills", "schedules.json");
|
|
33628
33650
|
}
|
|
33629
33651
|
function loadSchedules(targetDir = process.cwd()) {
|
|
33630
33652
|
const path = getSchedulesPath(targetDir);
|
|
33631
|
-
if (
|
|
33653
|
+
if (existsSync10(path)) {
|
|
33632
33654
|
try {
|
|
33633
33655
|
return JSON.parse(readFileSync8(path, "utf-8"));
|
|
33634
33656
|
} catch {}
|
|
@@ -33638,7 +33660,7 @@ function loadSchedules(targetDir = process.cwd()) {
|
|
|
33638
33660
|
function saveSchedules(data, targetDir = process.cwd()) {
|
|
33639
33661
|
const path = getSchedulesPath(targetDir);
|
|
33640
33662
|
const dir = join10(targetDir, ".skills");
|
|
33641
|
-
if (!
|
|
33663
|
+
if (!existsSync10(dir))
|
|
33642
33664
|
mkdirSync6(dir, { recursive: true });
|
|
33643
33665
|
writeFileSync5(path, JSON.stringify(data, null, 2));
|
|
33644
33666
|
}
|
|
@@ -33799,7 +33821,8 @@ function removeSchedule(idOrName, targetDir) {
|
|
|
33799
33821
|
}
|
|
33800
33822
|
|
|
33801
33823
|
// src/lib/skill-validation.ts
|
|
33802
|
-
|
|
33824
|
+
init_pricing();
|
|
33825
|
+
import { existsSync as existsSync11, lstatSync, readFileSync as readFileSync9, readdirSync as readdirSync4, statSync as statSync3 } from "fs";
|
|
33803
33826
|
import { isAbsolute, join as join11, normalize } from "path";
|
|
33804
33827
|
var DOC_FILES = ["SKILL.md", "README.md", "CLAUDE.md"];
|
|
33805
33828
|
var RESERVED_SKILL_ENTRIES = new Set([
|
|
@@ -33863,6 +33886,25 @@ function isSafeRelativePath(value) {
|
|
|
33863
33886
|
const normalized = normalize(value).replace(/\\/g, "/");
|
|
33864
33887
|
return normalized !== ".." && !normalized.startsWith("../") && !normalized.includes("/../");
|
|
33865
33888
|
}
|
|
33889
|
+
function isHostedPackageMetadata(pkg) {
|
|
33890
|
+
const skills = asRecord(pkg.skills);
|
|
33891
|
+
if (!skills)
|
|
33892
|
+
return false;
|
|
33893
|
+
const runtime = typeof skills.runtime === "string" ? skills.runtime.trim().toLowerCase() : "";
|
|
33894
|
+
const source = typeof skills.source === "string" ? skills.source.trim().toLowerCase() : "";
|
|
33895
|
+
return runtime === "hosted" || source === "remote" || source === "private-hosted";
|
|
33896
|
+
}
|
|
33897
|
+
function isHostedMetadataSkill(skillName, frontmatter, registryMeta, packageDeclaresHosted) {
|
|
33898
|
+
if (packageDeclaresHosted)
|
|
33899
|
+
return true;
|
|
33900
|
+
if (isPremiumSkill(skillName))
|
|
33901
|
+
return true;
|
|
33902
|
+
if (frontmatter?.source === "private-hosted")
|
|
33903
|
+
return true;
|
|
33904
|
+
if (frontmatter?.source === "remote" && !registryMeta?.tags.includes("local"))
|
|
33905
|
+
return true;
|
|
33906
|
+
return false;
|
|
33907
|
+
}
|
|
33866
33908
|
function parseSkillFrontmatter(content) {
|
|
33867
33909
|
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
33868
33910
|
if (!match)
|
|
@@ -33912,11 +33954,13 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
33912
33954
|
const bareName = name;
|
|
33913
33955
|
const issues = [];
|
|
33914
33956
|
const warnings = [];
|
|
33957
|
+
let packageDeclaresHosted = false;
|
|
33958
|
+
let packageSkillSource;
|
|
33915
33959
|
const metadata = {
|
|
33916
33960
|
binCommands: [],
|
|
33917
33961
|
docFiles: []
|
|
33918
33962
|
};
|
|
33919
|
-
if (!
|
|
33963
|
+
if (!existsSync11(skillPath)) {
|
|
33920
33964
|
add(issues, "skill.dir_missing", `Skill directory not found: ${skillPath}`);
|
|
33921
33965
|
return {
|
|
33922
33966
|
name: bareName,
|
|
@@ -33943,14 +33987,14 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
33943
33987
|
}
|
|
33944
33988
|
}
|
|
33945
33989
|
for (const docFile of DOC_FILES) {
|
|
33946
|
-
if (
|
|
33990
|
+
if (existsSync11(join11(skillPath, docFile)))
|
|
33947
33991
|
metadata.docFiles.push(docFile);
|
|
33948
33992
|
}
|
|
33949
33993
|
if (metadata.docFiles.length === 0) {
|
|
33950
33994
|
add(issues, "skill.docs_missing", "Missing documentation file: expected SKILL.md, README.md, or CLAUDE.md");
|
|
33951
33995
|
}
|
|
33952
33996
|
const skillMdPath = join11(skillPath, "SKILL.md");
|
|
33953
|
-
if (
|
|
33997
|
+
if (existsSync11(skillMdPath)) {
|
|
33954
33998
|
const frontmatter = parseSkillFrontmatter(readFileSync9(skillMdPath, "utf-8"));
|
|
33955
33999
|
if (!frontmatter) {
|
|
33956
34000
|
add(warnings, "skill.frontmatter_missing", "SKILL.md has no YAML frontmatter");
|
|
@@ -33985,7 +34029,7 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
33985
34029
|
add(warnings, "skill.skill_md_missing", "Missing SKILL.md; registry docs may need generated agent-facing instructions");
|
|
33986
34030
|
}
|
|
33987
34031
|
const pkgPath = join11(skillPath, "package.json");
|
|
33988
|
-
if (!
|
|
34032
|
+
if (!existsSync11(pkgPath)) {
|
|
33989
34033
|
add(issues, "package.missing", "Missing package.json");
|
|
33990
34034
|
} else {
|
|
33991
34035
|
try {
|
|
@@ -33994,6 +34038,13 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
33994
34038
|
if (!packageRecord) {
|
|
33995
34039
|
add(issues, "package.invalid_shape", "package.json must be an object");
|
|
33996
34040
|
} else {
|
|
34041
|
+
packageDeclaresHosted = isHostedPackageMetadata(pkg);
|
|
34042
|
+
const skillsRecord = asRecord(pkg.skills);
|
|
34043
|
+
if (skillsRecord && typeof skillsRecord.source === "string") {
|
|
34044
|
+
packageSkillSource = skillsRecord.source;
|
|
34045
|
+
}
|
|
34046
|
+
const hostedMetadata2 = isHostedMetadataSkill(bareName, metadata.skillMdFrontmatter, registryMeta, packageDeclaresHosted);
|
|
34047
|
+
metadata.runtime = hostedMetadata2 ? "hosted" : "local";
|
|
33997
34048
|
if (typeof pkg.name === "string") {
|
|
33998
34049
|
metadata.packageName = pkg.name;
|
|
33999
34050
|
if (pkg.name !== bareName) {
|
|
@@ -34010,12 +34061,18 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
34010
34061
|
...metadata.provenance ?? { directoryName: bareName },
|
|
34011
34062
|
...typeof pkg.name === "string" ? { packageName: pkg.name } : {},
|
|
34012
34063
|
...typeof pkg.version === "string" && pkg.version.trim() ? { packageVersion: pkg.version } : {},
|
|
34013
|
-
...registryMeta?.source ? { registrySource: registryMeta.source } : {}
|
|
34064
|
+
...registryMeta?.source ? { registrySource: registryMeta.source } : {},
|
|
34065
|
+
...packageSkillSource ? { packageSkillSource } : {}
|
|
34014
34066
|
};
|
|
34015
34067
|
const binRecord = asRecord(pkg.bin);
|
|
34016
34068
|
if (!binRecord || Object.keys(binRecord).length === 0) {
|
|
34017
|
-
|
|
34069
|
+
if (!hostedMetadata2) {
|
|
34070
|
+
add(issues, "package.bin_missing", "package.json missing non-empty bin object");
|
|
34071
|
+
}
|
|
34018
34072
|
} else {
|
|
34073
|
+
if (hostedMetadata2) {
|
|
34074
|
+
add(issues, "package.hosted_bin_forbidden", "Hosted metadata packages must not expose a local bin entry");
|
|
34075
|
+
}
|
|
34019
34076
|
for (const [command, target] of Object.entries(binRecord)) {
|
|
34020
34077
|
if (!VALID_BIN_COMMAND.test(command)) {
|
|
34021
34078
|
add(issues, "package.bin_command_invalid", `package.json bin command '${command}' must use lowercase letters, numbers, dots, underscores, or hyphens`);
|
|
@@ -34030,7 +34087,7 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
34030
34087
|
continue;
|
|
34031
34088
|
}
|
|
34032
34089
|
const targetPath = join11(skillPath, target);
|
|
34033
|
-
if (!
|
|
34090
|
+
if (!existsSync11(targetPath)) {
|
|
34034
34091
|
add(warnings, "package.bin_target_missing", `package.json bin '${command}' target '${target}' is not present before build`);
|
|
34035
34092
|
} else if (statSync3(targetPath).isDirectory()) {
|
|
34036
34093
|
add(issues, "package.bin_target_directory", `package.json bin '${command}' target '${target}' must point to a file, not a directory`);
|
|
@@ -34042,13 +34099,19 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
34042
34099
|
add(issues, "package.invalid_json", `package.json is invalid JSON: ${error48.message}`);
|
|
34043
34100
|
}
|
|
34044
34101
|
}
|
|
34102
|
+
const hostedMetadata = isHostedMetadataSkill(bareName, metadata.skillMdFrontmatter, registryMeta, packageDeclaresHosted);
|
|
34103
|
+
metadata.runtime = hostedMetadata ? "hosted" : "local";
|
|
34045
34104
|
const srcDir = join11(skillPath, "src");
|
|
34046
|
-
if (
|
|
34105
|
+
if (hostedMetadata) {
|
|
34106
|
+
if (existsSync11(srcDir)) {
|
|
34107
|
+
add(issues, "skill.hosted_source_forbidden", "Hosted metadata skills must not include local implementation source");
|
|
34108
|
+
}
|
|
34109
|
+
} else if (!existsSync11(srcDir)) {
|
|
34047
34110
|
add(issues, "skill.src_missing", "Missing src/ directory");
|
|
34048
|
-
} else if (!
|
|
34111
|
+
} else if (!existsSync11(join11(srcDir, "index.ts")) && !existsSync11(join11(srcDir, "index.js"))) {
|
|
34049
34112
|
add(issues, "skill.src_index_missing", "Missing src/index.ts or src/index.js");
|
|
34050
34113
|
} else {
|
|
34051
|
-
const indexPath =
|
|
34114
|
+
const indexPath = existsSync11(join11(srcDir, "index.ts")) ? join11(srcDir, "index.ts") : join11(srcDir, "index.js");
|
|
34052
34115
|
const size = statSync3(indexPath).size;
|
|
34053
34116
|
if (size < 50)
|
|
34054
34117
|
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;
|