@hasna/skills 0.1.32 → 0.1.34
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 +1 -16
- package/bin/index.js +57 -14
- package/bin/mcp.js +57 -13
- package/dist/cli/commands/runtime.d.ts +1 -1
- package/dist/index.js +51 -5
- 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/README.md +13 -256
- package/skills/browse/SKILL.md +24 -45
- 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/CLAUDE.md +6 -39
- package/skills/deepresearch/README.md +15 -150
- package/skills/deepresearch/SKILL.md +23 -32
- 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/README.md +13 -183
- 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/CLAUDE.md +6 -17
- package/skills/webcrawling/README.md +13 -66
- package/skills/webcrawling/package.json +4 -32
- package/skills/browse/.env.example +0 -14
- package/skills/deepresearch/.env.example +0 -9
- 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/image/.env.example +0 -12
- package/skills/image/PROJECT_OVERVIEW.md +0 -216
- package/skills/image/QUICKSTART.md +0 -111
- 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/skills/transcript/.env.example +0 -10
- package/skills/webcrawling/.env.example +0 -2
package/README.md
CHANGED
|
@@ -113,7 +113,6 @@ requirements explicitly document local provider use.
|
|
|
113
113
|
| `skills schedule list` | | List all schedules (enabled/disabled/last run) |
|
|
114
114
|
| `skills mcp` | | Start MCP server on stdio |
|
|
115
115
|
| `skills mcp --register claude` | | Register the Skills MCP server in an agent config (also `codex`, `gemini`, `opencode`, `all`) |
|
|
116
|
-
| `skills serve` | | Start the HTTP dashboard on localhost |
|
|
117
116
|
| `skills self-update` | | Update this package to the latest version |
|
|
118
117
|
| `skills completion <shell>` | | Generate shell completions (bash, zsh, fish) |
|
|
119
118
|
|
|
@@ -224,22 +223,12 @@ Hosted account, billing, and credit management use the configured hosted API.
|
|
|
224
223
|
The public package only stores local configuration and CLI credentials; Stripe,
|
|
225
224
|
customer records, and hosted execution remain platform concerns.
|
|
226
225
|
|
|
227
|
-
## Dashboard
|
|
228
|
-
|
|
229
|
-
```bash
|
|
230
|
-
skills serve # Start HTTP server (opens browser automatically)
|
|
231
|
-
skills serve --no-open # Start without opening the browser
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
Dashboard features: searchable/filterable skills table, detail dialogs, stats cards, dark/light/system theme, oklch color tokens.
|
|
235
|
-
|
|
236
226
|
## Project Structure
|
|
237
227
|
|
|
238
228
|
```
|
|
239
229
|
src/
|
|
240
230
|
├── cli/index.tsx # Commander.js CLI + Ink TUI
|
|
241
231
|
├── mcp/index.ts # MCP server (stdio) with ~20 tools
|
|
242
|
-
├── server/serve.ts # Bun.serve HTTP server + REST API
|
|
243
232
|
├── lib/
|
|
244
233
|
│ ├── registry.ts # 202+ entries, search, categories, tags
|
|
245
234
|
│ ├── installer.ts # Project pins and disabled source-copy paths
|
|
@@ -254,9 +243,7 @@ src/
|
|
|
254
243
|
|
|
255
244
|
skills/ # 202+ public skill contracts and local OSS skills
|
|
256
245
|
├── _common/ # Shared utilities
|
|
257
|
-
└── */ # Local skills include src/;
|
|
258
|
-
|
|
259
|
-
dashboard/ # Next.js + React 19 + Tailwind v4 app
|
|
246
|
+
└── */ # Local skills include src/; hosted skills are metadata-only
|
|
260
247
|
```
|
|
261
248
|
|
|
262
249
|
## Project Runtime State
|
|
@@ -283,8 +270,6 @@ belong in `~/.cache/skills` or the remote API, not inside project `.skills`.
|
|
|
283
270
|
bun install
|
|
284
271
|
bun run build # Build CLI, MCP, library, and types
|
|
285
272
|
bun run dev # Run CLI in dev mode (no build needed)
|
|
286
|
-
bun run dashboard:dev # Vite dev server for web dashboard
|
|
287
|
-
bun run server:dev # HTTP server with --watch
|
|
288
273
|
bun test # Run all tests
|
|
289
274
|
bun run typecheck # TypeScript type checking
|
|
290
275
|
```
|
package/bin/index.js
CHANGED
|
@@ -1910,7 +1910,7 @@ var package_default;
|
|
|
1910
1910
|
var init_package = __esm(() => {
|
|
1911
1911
|
package_default = {
|
|
1912
1912
|
name: "@hasna/skills",
|
|
1913
|
-
version: "0.1.
|
|
1913
|
+
version: "0.1.34",
|
|
1914
1914
|
description: "Skills library for AI coding agents",
|
|
1915
1915
|
type: "module",
|
|
1916
1916
|
bin: {
|
|
@@ -6648,7 +6648,13 @@ function formatCost(cents) {
|
|
|
6648
6648
|
return `$${(cents / 100).toFixed(2)}`;
|
|
6649
6649
|
}
|
|
6650
6650
|
function getAllPremiumSlugs() {
|
|
6651
|
-
return [
|
|
6651
|
+
return [
|
|
6652
|
+
...new Set([
|
|
6653
|
+
...PREMIUM_SKILLS.map((skill) => skill.slug),
|
|
6654
|
+
...MEDIA_GENERATION_PRICES.map((price) => price.slug),
|
|
6655
|
+
ARTICLE_GENERATION_SLUG
|
|
6656
|
+
])
|
|
6657
|
+
].sort();
|
|
6652
6658
|
}
|
|
6653
6659
|
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;
|
|
6654
6660
|
var init_pricing = __esm(() => {
|
|
@@ -21971,6 +21977,25 @@ function isSafeRelativePath(value) {
|
|
|
21971
21977
|
const normalized = normalize(value).replace(/\\/g, "/");
|
|
21972
21978
|
return normalized !== ".." && !normalized.startsWith("../") && !normalized.includes("/../");
|
|
21973
21979
|
}
|
|
21980
|
+
function isHostedPackageMetadata(pkg) {
|
|
21981
|
+
const skills = asRecord(pkg.skills);
|
|
21982
|
+
if (!skills)
|
|
21983
|
+
return false;
|
|
21984
|
+
const runtime = typeof skills.runtime === "string" ? skills.runtime.trim().toLowerCase() : "";
|
|
21985
|
+
const source = typeof skills.source === "string" ? skills.source.trim().toLowerCase() : "";
|
|
21986
|
+
return runtime === "hosted" || source === "remote" || source === "private-hosted";
|
|
21987
|
+
}
|
|
21988
|
+
function isHostedMetadataSkill(skillName, frontmatter, registryMeta, packageDeclaresHosted) {
|
|
21989
|
+
if (packageDeclaresHosted)
|
|
21990
|
+
return true;
|
|
21991
|
+
if (isPremiumSkill(skillName))
|
|
21992
|
+
return true;
|
|
21993
|
+
if (frontmatter?.source === "private-hosted")
|
|
21994
|
+
return true;
|
|
21995
|
+
if (frontmatter?.source === "remote" && !registryMeta?.tags.includes("local"))
|
|
21996
|
+
return true;
|
|
21997
|
+
return false;
|
|
21998
|
+
}
|
|
21974
21999
|
function parseSkillFrontmatter(content) {
|
|
21975
22000
|
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
21976
22001
|
if (!match)
|
|
@@ -22020,6 +22045,8 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
22020
22045
|
const bareName = name;
|
|
22021
22046
|
const issues = [];
|
|
22022
22047
|
const warnings = [];
|
|
22048
|
+
let packageDeclaresHosted = false;
|
|
22049
|
+
let packageSkillSource;
|
|
22023
22050
|
const metadata = {
|
|
22024
22051
|
binCommands: [],
|
|
22025
22052
|
docFiles: []
|
|
@@ -22102,6 +22129,13 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
22102
22129
|
if (!packageRecord) {
|
|
22103
22130
|
add(issues, "package.invalid_shape", "package.json must be an object");
|
|
22104
22131
|
} else {
|
|
22132
|
+
packageDeclaresHosted = isHostedPackageMetadata(pkg);
|
|
22133
|
+
const skillsRecord = asRecord(pkg.skills);
|
|
22134
|
+
if (skillsRecord && typeof skillsRecord.source === "string") {
|
|
22135
|
+
packageSkillSource = skillsRecord.source;
|
|
22136
|
+
}
|
|
22137
|
+
const hostedMetadata2 = isHostedMetadataSkill(bareName, metadata.skillMdFrontmatter, registryMeta, packageDeclaresHosted);
|
|
22138
|
+
metadata.runtime = hostedMetadata2 ? "hosted" : "local";
|
|
22105
22139
|
if (typeof pkg.name === "string") {
|
|
22106
22140
|
metadata.packageName = pkg.name;
|
|
22107
22141
|
if (pkg.name !== bareName) {
|
|
@@ -22118,12 +22152,18 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
22118
22152
|
...metadata.provenance ?? { directoryName: bareName },
|
|
22119
22153
|
...typeof pkg.name === "string" ? { packageName: pkg.name } : {},
|
|
22120
22154
|
...typeof pkg.version === "string" && pkg.version.trim() ? { packageVersion: pkg.version } : {},
|
|
22121
|
-
...registryMeta?.source ? { registrySource: registryMeta.source } : {}
|
|
22155
|
+
...registryMeta?.source ? { registrySource: registryMeta.source } : {},
|
|
22156
|
+
...packageSkillSource ? { packageSkillSource } : {}
|
|
22122
22157
|
};
|
|
22123
22158
|
const binRecord = asRecord(pkg.bin);
|
|
22124
22159
|
if (!binRecord || Object.keys(binRecord).length === 0) {
|
|
22125
|
-
|
|
22160
|
+
if (!hostedMetadata2) {
|
|
22161
|
+
add(issues, "package.bin_missing", "package.json missing non-empty bin object");
|
|
22162
|
+
}
|
|
22126
22163
|
} else {
|
|
22164
|
+
if (hostedMetadata2) {
|
|
22165
|
+
add(issues, "package.hosted_bin_forbidden", "Hosted metadata packages must not expose a local bin entry");
|
|
22166
|
+
}
|
|
22127
22167
|
for (const [command, target] of Object.entries(binRecord)) {
|
|
22128
22168
|
if (!VALID_BIN_COMMAND.test(command)) {
|
|
22129
22169
|
add(issues, "package.bin_command_invalid", `package.json bin command '${command}' must use lowercase letters, numbers, dots, underscores, or hyphens`);
|
|
@@ -22150,8 +22190,14 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
22150
22190
|
add(issues, "package.invalid_json", `package.json is invalid JSON: ${error48.message}`);
|
|
22151
22191
|
}
|
|
22152
22192
|
}
|
|
22193
|
+
const hostedMetadata = isHostedMetadataSkill(bareName, metadata.skillMdFrontmatter, registryMeta, packageDeclaresHosted);
|
|
22194
|
+
metadata.runtime = hostedMetadata ? "hosted" : "local";
|
|
22153
22195
|
const srcDir = join7(skillPath, "src");
|
|
22154
|
-
if (
|
|
22196
|
+
if (hostedMetadata) {
|
|
22197
|
+
if (existsSync7(srcDir)) {
|
|
22198
|
+
add(issues, "skill.hosted_source_forbidden", "Hosted metadata skills must not include local implementation source");
|
|
22199
|
+
}
|
|
22200
|
+
} else if (!existsSync7(srcDir)) {
|
|
22155
22201
|
add(issues, "skill.src_missing", "Missing src/ directory");
|
|
22156
22202
|
} else if (!existsSync7(join7(srcDir, "index.ts")) && !existsSync7(join7(srcDir, "index.js"))) {
|
|
22157
22203
|
add(issues, "skill.src_index_missing", "Missing src/index.ts or src/index.js");
|
|
@@ -22172,6 +22218,7 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
22172
22218
|
}
|
|
22173
22219
|
var DOC_FILES, RESERVED_SKILL_ENTRIES, KNOWN_TOP_LEVEL_ENTRIES, VALID_PROVENANCE_SOURCES, VALID_BIN_COMMAND;
|
|
22174
22220
|
var init_skill_validation = __esm(() => {
|
|
22221
|
+
init_pricing();
|
|
22175
22222
|
DOC_FILES = ["SKILL.md", "README.md", "CLAUDE.md"];
|
|
22176
22223
|
RESERVED_SKILL_ENTRIES = new Set([
|
|
22177
22224
|
".env",
|
|
@@ -39522,7 +39569,7 @@ function registerOperationTools(server) {
|
|
|
39522
39569
|
const run = completeSkillRun(runContext, { status: "failed", error: error48, costCents });
|
|
39523
39570
|
return mcpError("AUTH_REQUIRED", `${error48}. Local run metadata: ${run.paths.runDir}/run.json`, ["skills auth login"]);
|
|
39524
39571
|
}
|
|
39525
|
-
if (apiKey) {
|
|
39572
|
+
if (isPremiumSkill2(skillName) && apiKey) {
|
|
39526
39573
|
try {
|
|
39527
39574
|
const { RemoteSkillsClient: RemoteSkillsClient2 } = await Promise.resolve().then(() => (init_remote_client(), exports_remote_client));
|
|
39528
39575
|
const client = new RemoteSkillsClient2(apiKey);
|
|
@@ -39552,14 +39599,11 @@ function registerOperationTools(server) {
|
|
|
39552
39599
|
nextActions: remoteRunNextActions(remoteRunId)
|
|
39553
39600
|
});
|
|
39554
39601
|
} catch (err) {
|
|
39555
|
-
|
|
39556
|
-
|
|
39557
|
-
const error48 = `Hosted skill ${skillName} requires hosted access: ${err.message}`;
|
|
39558
|
-
writeRunLogs(runContext, "", error48 + `
|
|
39602
|
+
const error48 = `Hosted skill ${skillName} requires hosted access: ${err.message}`;
|
|
39603
|
+
writeRunLogs(runContext, "", error48 + `
|
|
39559
39604
|
`);
|
|
39560
|
-
|
|
39561
|
-
|
|
39562
|
-
}
|
|
39605
|
+
const localRun2 = completeSkillRun(runContext, { status: "failed", error: error48 });
|
|
39606
|
+
return mcpError("PLATFORM_ERROR", `${error48}. Local run metadata: ${localRun2.paths.runDir}/run.json`);
|
|
39563
39607
|
}
|
|
39564
39608
|
}
|
|
39565
39609
|
const result = await runSkill(skillName, runArgs, {
|
|
@@ -41549,7 +41593,6 @@ var init_completion = __esm(() => {
|
|
|
41549
41593
|
"categories",
|
|
41550
41594
|
"tags",
|
|
41551
41595
|
"mcp",
|
|
41552
|
-
"serve",
|
|
41553
41596
|
"self-update",
|
|
41554
41597
|
"completion",
|
|
41555
41598
|
"export",
|
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(() => {
|
|
@@ -21787,7 +21793,7 @@ class StdioServerTransport {
|
|
|
21787
21793
|
// package.json
|
|
21788
21794
|
var package_default = {
|
|
21789
21795
|
name: "@hasna/skills",
|
|
21790
|
-
version: "0.1.
|
|
21796
|
+
version: "0.1.34",
|
|
21791
21797
|
description: "Skills library for AI coding agents",
|
|
21792
21798
|
type: "module",
|
|
21793
21799
|
bin: {
|
|
@@ -33296,7 +33302,7 @@ function registerOperationTools(server) {
|
|
|
33296
33302
|
const run = completeSkillRun(runContext, { status: "failed", error: error48, costCents });
|
|
33297
33303
|
return mcpError("AUTH_REQUIRED", `${error48}. Local run metadata: ${run.paths.runDir}/run.json`, ["skills auth login"]);
|
|
33298
33304
|
}
|
|
33299
|
-
if (apiKey) {
|
|
33305
|
+
if (isPremiumSkill2(skillName) && apiKey) {
|
|
33300
33306
|
try {
|
|
33301
33307
|
const { RemoteSkillsClient: RemoteSkillsClient2 } = await Promise.resolve().then(() => (init_remote_client(), exports_remote_client));
|
|
33302
33308
|
const client = new RemoteSkillsClient2(apiKey);
|
|
@@ -33326,14 +33332,11 @@ function registerOperationTools(server) {
|
|
|
33326
33332
|
nextActions: remoteRunNextActions(remoteRunId)
|
|
33327
33333
|
});
|
|
33328
33334
|
} catch (err) {
|
|
33329
|
-
|
|
33330
|
-
|
|
33331
|
-
const error48 = `Hosted skill ${skillName} requires hosted access: ${err.message}`;
|
|
33332
|
-
writeRunLogs(runContext, "", error48 + `
|
|
33335
|
+
const error48 = `Hosted skill ${skillName} requires hosted access: ${err.message}`;
|
|
33336
|
+
writeRunLogs(runContext, "", error48 + `
|
|
33333
33337
|
`);
|
|
33334
|
-
|
|
33335
|
-
|
|
33336
|
-
}
|
|
33338
|
+
const localRun2 = completeSkillRun(runContext, { status: "failed", error: error48 });
|
|
33339
|
+
return mcpError("PLATFORM_ERROR", `${error48}. Local run metadata: ${localRun2.paths.runDir}/run.json`);
|
|
33337
33340
|
}
|
|
33338
33341
|
}
|
|
33339
33342
|
const result = await runSkill(skillName, runArgs, {
|
|
@@ -33818,6 +33821,7 @@ function removeSchedule(idOrName, targetDir) {
|
|
|
33818
33821
|
}
|
|
33819
33822
|
|
|
33820
33823
|
// src/lib/skill-validation.ts
|
|
33824
|
+
init_pricing();
|
|
33821
33825
|
import { existsSync as existsSync11, lstatSync, readFileSync as readFileSync9, readdirSync as readdirSync4, statSync as statSync3 } from "fs";
|
|
33822
33826
|
import { isAbsolute, join as join11, normalize } from "path";
|
|
33823
33827
|
var DOC_FILES = ["SKILL.md", "README.md", "CLAUDE.md"];
|
|
@@ -33882,6 +33886,25 @@ function isSafeRelativePath(value) {
|
|
|
33882
33886
|
const normalized = normalize(value).replace(/\\/g, "/");
|
|
33883
33887
|
return normalized !== ".." && !normalized.startsWith("../") && !normalized.includes("/../");
|
|
33884
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
|
+
}
|
|
33885
33908
|
function parseSkillFrontmatter(content) {
|
|
33886
33909
|
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
33887
33910
|
if (!match)
|
|
@@ -33931,6 +33954,8 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
33931
33954
|
const bareName = name;
|
|
33932
33955
|
const issues = [];
|
|
33933
33956
|
const warnings = [];
|
|
33957
|
+
let packageDeclaresHosted = false;
|
|
33958
|
+
let packageSkillSource;
|
|
33934
33959
|
const metadata = {
|
|
33935
33960
|
binCommands: [],
|
|
33936
33961
|
docFiles: []
|
|
@@ -34013,6 +34038,13 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
34013
34038
|
if (!packageRecord) {
|
|
34014
34039
|
add(issues, "package.invalid_shape", "package.json must be an object");
|
|
34015
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";
|
|
34016
34048
|
if (typeof pkg.name === "string") {
|
|
34017
34049
|
metadata.packageName = pkg.name;
|
|
34018
34050
|
if (pkg.name !== bareName) {
|
|
@@ -34029,12 +34061,18 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
34029
34061
|
...metadata.provenance ?? { directoryName: bareName },
|
|
34030
34062
|
...typeof pkg.name === "string" ? { packageName: pkg.name } : {},
|
|
34031
34063
|
...typeof pkg.version === "string" && pkg.version.trim() ? { packageVersion: pkg.version } : {},
|
|
34032
|
-
...registryMeta?.source ? { registrySource: registryMeta.source } : {}
|
|
34064
|
+
...registryMeta?.source ? { registrySource: registryMeta.source } : {},
|
|
34065
|
+
...packageSkillSource ? { packageSkillSource } : {}
|
|
34033
34066
|
};
|
|
34034
34067
|
const binRecord = asRecord(pkg.bin);
|
|
34035
34068
|
if (!binRecord || Object.keys(binRecord).length === 0) {
|
|
34036
|
-
|
|
34069
|
+
if (!hostedMetadata2) {
|
|
34070
|
+
add(issues, "package.bin_missing", "package.json missing non-empty bin object");
|
|
34071
|
+
}
|
|
34037
34072
|
} else {
|
|
34073
|
+
if (hostedMetadata2) {
|
|
34074
|
+
add(issues, "package.hosted_bin_forbidden", "Hosted metadata packages must not expose a local bin entry");
|
|
34075
|
+
}
|
|
34038
34076
|
for (const [command, target] of Object.entries(binRecord)) {
|
|
34039
34077
|
if (!VALID_BIN_COMMAND.test(command)) {
|
|
34040
34078
|
add(issues, "package.bin_command_invalid", `package.json bin command '${command}' must use lowercase letters, numbers, dots, underscores, or hyphens`);
|
|
@@ -34061,8 +34099,14 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
34061
34099
|
add(issues, "package.invalid_json", `package.json is invalid JSON: ${error48.message}`);
|
|
34062
34100
|
}
|
|
34063
34101
|
}
|
|
34102
|
+
const hostedMetadata = isHostedMetadataSkill(bareName, metadata.skillMdFrontmatter, registryMeta, packageDeclaresHosted);
|
|
34103
|
+
metadata.runtime = hostedMetadata ? "hosted" : "local";
|
|
34064
34104
|
const srcDir = join11(skillPath, "src");
|
|
34065
|
-
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)) {
|
|
34066
34110
|
add(issues, "skill.src_missing", "Missing src/ directory");
|
|
34067
34111
|
} else if (!existsSync11(join11(srcDir, "index.ts")) && !existsSync11(join11(srcDir, "index.js"))) {
|
|
34068
34112
|
add(issues, "skill.src_index_missing", "Missing src/index.ts or src/index.js");
|
package/dist/index.js
CHANGED
|
@@ -3094,7 +3094,13 @@ function formatCost(cents) {
|
|
|
3094
3094
|
return `$${(cents / 100).toFixed(2)}`;
|
|
3095
3095
|
}
|
|
3096
3096
|
function getAllPremiumSlugs() {
|
|
3097
|
-
return [
|
|
3097
|
+
return [
|
|
3098
|
+
...new Set([
|
|
3099
|
+
...PREMIUM_SKILLS.map((skill) => skill.slug),
|
|
3100
|
+
...MEDIA_GENERATION_PRICES.map((price) => price.slug),
|
|
3101
|
+
ARTICLE_GENERATION_SLUG
|
|
3102
|
+
])
|
|
3103
|
+
].sort();
|
|
3098
3104
|
}
|
|
3099
3105
|
|
|
3100
3106
|
// src/lib/skillinfo.ts
|
|
@@ -17756,6 +17762,25 @@ function isSafeRelativePath(value) {
|
|
|
17756
17762
|
const normalized = normalize(value).replace(/\\/g, "/");
|
|
17757
17763
|
return normalized !== ".." && !normalized.startsWith("../") && !normalized.includes("/../");
|
|
17758
17764
|
}
|
|
17765
|
+
function isHostedPackageMetadata(pkg) {
|
|
17766
|
+
const skills = asRecord(pkg.skills);
|
|
17767
|
+
if (!skills)
|
|
17768
|
+
return false;
|
|
17769
|
+
const runtime = typeof skills.runtime === "string" ? skills.runtime.trim().toLowerCase() : "";
|
|
17770
|
+
const source = typeof skills.source === "string" ? skills.source.trim().toLowerCase() : "";
|
|
17771
|
+
return runtime === "hosted" || source === "remote" || source === "private-hosted";
|
|
17772
|
+
}
|
|
17773
|
+
function isHostedMetadataSkill(skillName, frontmatter, registryMeta, packageDeclaresHosted) {
|
|
17774
|
+
if (packageDeclaresHosted)
|
|
17775
|
+
return true;
|
|
17776
|
+
if (isPremiumSkill(skillName))
|
|
17777
|
+
return true;
|
|
17778
|
+
if (frontmatter?.source === "private-hosted")
|
|
17779
|
+
return true;
|
|
17780
|
+
if (frontmatter?.source === "remote" && !registryMeta?.tags.includes("local"))
|
|
17781
|
+
return true;
|
|
17782
|
+
return false;
|
|
17783
|
+
}
|
|
17759
17784
|
function parseSkillFrontmatter(content) {
|
|
17760
17785
|
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
17761
17786
|
if (!match)
|
|
@@ -17805,6 +17830,8 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
17805
17830
|
const bareName = name;
|
|
17806
17831
|
const issues = [];
|
|
17807
17832
|
const warnings = [];
|
|
17833
|
+
let packageDeclaresHosted = false;
|
|
17834
|
+
let packageSkillSource;
|
|
17808
17835
|
const metadata = {
|
|
17809
17836
|
binCommands: [],
|
|
17810
17837
|
docFiles: []
|
|
@@ -17887,6 +17914,13 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
17887
17914
|
if (!packageRecord) {
|
|
17888
17915
|
add(issues, "package.invalid_shape", "package.json must be an object");
|
|
17889
17916
|
} else {
|
|
17917
|
+
packageDeclaresHosted = isHostedPackageMetadata(pkg);
|
|
17918
|
+
const skillsRecord = asRecord(pkg.skills);
|
|
17919
|
+
if (skillsRecord && typeof skillsRecord.source === "string") {
|
|
17920
|
+
packageSkillSource = skillsRecord.source;
|
|
17921
|
+
}
|
|
17922
|
+
const hostedMetadata2 = isHostedMetadataSkill(bareName, metadata.skillMdFrontmatter, registryMeta, packageDeclaresHosted);
|
|
17923
|
+
metadata.runtime = hostedMetadata2 ? "hosted" : "local";
|
|
17890
17924
|
if (typeof pkg.name === "string") {
|
|
17891
17925
|
metadata.packageName = pkg.name;
|
|
17892
17926
|
if (pkg.name !== bareName) {
|
|
@@ -17903,12 +17937,18 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
17903
17937
|
...metadata.provenance ?? { directoryName: bareName },
|
|
17904
17938
|
...typeof pkg.name === "string" ? { packageName: pkg.name } : {},
|
|
17905
17939
|
...typeof pkg.version === "string" && pkg.version.trim() ? { packageVersion: pkg.version } : {},
|
|
17906
|
-
...registryMeta?.source ? { registrySource: registryMeta.source } : {}
|
|
17940
|
+
...registryMeta?.source ? { registrySource: registryMeta.source } : {},
|
|
17941
|
+
...packageSkillSource ? { packageSkillSource } : {}
|
|
17907
17942
|
};
|
|
17908
17943
|
const binRecord = asRecord(pkg.bin);
|
|
17909
17944
|
if (!binRecord || Object.keys(binRecord).length === 0) {
|
|
17910
|
-
|
|
17945
|
+
if (!hostedMetadata2) {
|
|
17946
|
+
add(issues, "package.bin_missing", "package.json missing non-empty bin object");
|
|
17947
|
+
}
|
|
17911
17948
|
} else {
|
|
17949
|
+
if (hostedMetadata2) {
|
|
17950
|
+
add(issues, "package.hosted_bin_forbidden", "Hosted metadata packages must not expose a local bin entry");
|
|
17951
|
+
}
|
|
17912
17952
|
for (const [command, target] of Object.entries(binRecord)) {
|
|
17913
17953
|
if (!VALID_BIN_COMMAND.test(command)) {
|
|
17914
17954
|
add(issues, "package.bin_command_invalid", `package.json bin command '${command}' must use lowercase letters, numbers, dots, underscores, or hyphens`);
|
|
@@ -17935,8 +17975,14 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
|
|
|
17935
17975
|
add(issues, "package.invalid_json", `package.json is invalid JSON: ${error48.message}`);
|
|
17936
17976
|
}
|
|
17937
17977
|
}
|
|
17978
|
+
const hostedMetadata = isHostedMetadataSkill(bareName, metadata.skillMdFrontmatter, registryMeta, packageDeclaresHosted);
|
|
17979
|
+
metadata.runtime = hostedMetadata ? "hosted" : "local";
|
|
17938
17980
|
const srcDir = join9(skillPath, "src");
|
|
17939
|
-
if (
|
|
17981
|
+
if (hostedMetadata) {
|
|
17982
|
+
if (existsSync9(srcDir)) {
|
|
17983
|
+
add(issues, "skill.hosted_source_forbidden", "Hosted metadata skills must not include local implementation source");
|
|
17984
|
+
}
|
|
17985
|
+
} else if (!existsSync9(srcDir)) {
|
|
17940
17986
|
add(issues, "skill.src_missing", "Missing src/ directory");
|
|
17941
17987
|
} else if (!existsSync9(join9(srcDir, "index.ts")) && !existsSync9(join9(srcDir, "index.js"))) {
|
|
17942
17988
|
add(issues, "skill.src_index_missing", "Missing src/index.ts or src/index.js");
|
|
@@ -17985,7 +18031,7 @@ import { dirname as dirname3, relative as relative2 } from "path";
|
|
|
17985
18031
|
// package.json
|
|
17986
18032
|
var package_default = {
|
|
17987
18033
|
name: "@hasna/skills",
|
|
17988
|
-
version: "0.1.
|
|
18034
|
+
version: "0.1.34",
|
|
17989
18035
|
description: "Skills library for AI coding agents",
|
|
17990
18036
|
type: "module",
|
|
17991
18037
|
bin: {
|
|
@@ -16,6 +16,7 @@ export interface SkillValidationResult {
|
|
|
16
16
|
docFiles: string[];
|
|
17
17
|
skillMdFrontmatter?: SkillFrontmatter;
|
|
18
18
|
provenance?: SkillValidationProvenance;
|
|
19
|
+
runtime?: "local" | "hosted";
|
|
19
20
|
};
|
|
20
21
|
}
|
|
21
22
|
export interface RegistryConsistencyResult {
|
|
@@ -39,6 +40,7 @@ export interface SkillValidationProvenance {
|
|
|
39
40
|
packageVersion?: string;
|
|
40
41
|
frontmatterSource?: string;
|
|
41
42
|
registrySource?: string;
|
|
43
|
+
packageSkillSource?: string;
|
|
42
44
|
}
|
|
43
45
|
export declare function parseSkillFrontmatter(content: string): SkillFrontmatter | null;
|
|
44
46
|
export declare function validateSkillDirectory(name: string, skillPath: string, registryMeta?: SkillMeta): SkillValidationResult;
|
package/package.json
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ad-creative-pack",
|
|
3
3
|
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
4
5
|
"description": "Hosted premium paid ad creative artifact generator",
|
|
5
6
|
"type": "module",
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
"dependencies": {},
|
|
10
|
-
"devDependencies": {
|
|
11
|
-
"@types/bun": "latest",
|
|
12
|
-
"typescript": "^5.7.0"
|
|
7
|
+
"skills": {
|
|
8
|
+
"runtime": "hosted",
|
|
9
|
+
"source": "remote"
|
|
13
10
|
}
|
|
14
11
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "api-docs-portal",
|
|
3
3
|
"version": "0.1.0",
|
|
4
|
-
"type": "module",
|
|
5
4
|
"private": true,
|
|
6
|
-
"
|
|
7
|
-
|
|
5
|
+
"description": "Hosted skill metadata for api-docs-portal",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"skills": {
|
|
8
|
+
"runtime": "hosted",
|
|
9
|
+
"source": "remote"
|
|
8
10
|
}
|
|
9
11
|
}
|
|
@@ -1,29 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "audio",
|
|
3
3
|
"version": "1.0.0",
|
|
4
|
+
"private": true,
|
|
4
5
|
"description": "Generate speech and audio using provider-cost AI backends",
|
|
5
|
-
"main": "src/index.ts",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
"scripts": {
|
|
11
|
-
"start": "bun run src/index.ts",
|
|
12
|
-
"generate": "bun run src/index.ts generate"
|
|
13
|
-
},
|
|
14
|
-
"keywords": [
|
|
15
|
-
"audio-generation",
|
|
16
|
-
"speech",
|
|
17
|
-
"tts",
|
|
18
|
-
"ai",
|
|
19
|
-
"openai",
|
|
20
|
-
"minimax",
|
|
21
|
-
"gemini"
|
|
22
|
-
],
|
|
23
|
-
"devDependencies": {
|
|
24
|
-
"@types/bun": "latest"
|
|
25
|
-
},
|
|
26
|
-
"peerDependencies": {
|
|
27
|
-
"typescript": "^5.0.0"
|
|
7
|
+
"skills": {
|
|
8
|
+
"runtime": "hosted",
|
|
9
|
+
"source": "remote"
|
|
28
10
|
}
|
|
29
11
|
}
|
|
@@ -1,27 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "blog-article",
|
|
3
3
|
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
4
5
|
"description": "Hosted premium blog article artifact generator",
|
|
5
6
|
"type": "module",
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"dev": "bun run src/index.ts",
|
|
11
|
-
"build": "bun build src/index.ts --outdir dist --target node",
|
|
12
|
-
"typecheck": "tsc --noEmit"
|
|
13
|
-
},
|
|
14
|
-
"dependencies": {},
|
|
15
|
-
"devDependencies": {
|
|
16
|
-
"@types/bun": "latest",
|
|
17
|
-
"typescript": "^5.7.0"
|
|
18
|
-
},
|
|
19
|
-
"publishConfig": {
|
|
20
|
-
"access": "restricted",
|
|
21
|
-
"registry": "https://registry.npmjs.org/"
|
|
22
|
-
},
|
|
23
|
-
"files": [
|
|
24
|
-
"src",
|
|
25
|
-
"tsconfig.json"
|
|
26
|
-
]
|
|
7
|
+
"skills": {
|
|
8
|
+
"runtime": "hosted",
|
|
9
|
+
"source": "remote"
|
|
10
|
+
}
|
|
27
11
|
}
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brand-kit",
|
|
3
3
|
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
4
5
|
"description": "Hosted premium brand kit artifact generator",
|
|
5
6
|
"type": "module",
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
"dependencies": {},
|
|
10
|
-
"devDependencies": {
|
|
11
|
-
"@types/bun": "latest",
|
|
12
|
-
"typescript": "^5.7.0"
|
|
7
|
+
"skills": {
|
|
8
|
+
"runtime": "hosted",
|
|
9
|
+
"source": "remote"
|
|
13
10
|
}
|
|
14
11
|
}
|