@hasna/skills 0.1.37 → 0.1.39
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 +315 -89
- package/bin/mcp.js +34 -9
- package/dist/index.js +20 -7
- package/package.json +1 -1
- package/skills/_common/auth.ts +8 -12
- package/skills/_common/http-client.ts +4 -4
- package/skills/audio/SKILL.md +1 -1
- package/skills/codefix/package.json +4 -4
- package/skills/codefix/src/index-local.ts +2 -1
- package/skills/codefix/src/index.ts +2 -108
- package/skills/convert/SKILL.md +2 -2
- package/skills/convert/package.json +4 -4
- package/skills/convert/src/index-local.ts +11 -12
- package/skills/convert/src/index.ts +2 -108
- package/skills/deploy/package.json +3 -3
- package/skills/deploy/src/http-client.ts +4 -4
- package/skills/deploy/src/index-local.ts +2 -1
- package/skills/deploy/src/index.ts +2 -109
- package/skills/extract/package.json +4 -4
- package/skills/extract/src/index-local.ts +2 -1
- package/skills/extract/src/index.ts +2 -108
- package/skills/image/SKILL.md +2 -2
- package/skills/music/SKILL.md +1 -1
- package/skills/transcript/SKILL.md +2 -2
- package/skills/video/SKILL.md +1 -1
- package/skills/write/SKILL.md +2 -2
- package/skills/write/package.json +4 -4
- package/skills/write/src/index-local.ts +2 -1
- package/skills/write/src/index.ts +2 -108
package/bin/mcp.js
CHANGED
|
@@ -6934,6 +6934,7 @@ var init_pricing = __esm(() => {
|
|
|
6934
6934
|
init_skill_aliases();
|
|
6935
6935
|
MUSIC_ALBUM_SONG_COUNTS = [7, 14, 21];
|
|
6936
6936
|
PREMIUM_SKILLS = [
|
|
6937
|
+
{ slug: "icon-pack", displayName: "Icon Pack", tier: "premium", costCents: 200, providers: ["hosted"], description: "Hosted coordinated icon pack with SVGs, transparent PNGs, size variants, and manifest" },
|
|
6937
6938
|
{ slug: "logo-design", displayName: "Logo Design", tier: "premium", costCents: 50, providers: ["hosted"], description: "Hosted multi-variant logo package with transparent PNGs, vector-style SVGs, usage notes, and manifest" },
|
|
6938
6939
|
{ slug: "deepresearch", displayName: "Deep Research", tier: "premium", costCents: 20, providers: ["exa"], description: "Agentic web research with semantic search and synthesis" },
|
|
6939
6940
|
{ slug: "playlist-maker", displayName: "Playlist Maker", tier: "premium", costCents: 30, providers: ["exa", "gemini-3-pro"], description: "Curated playlist with research, track selection, and album art" },
|
|
@@ -7207,6 +7208,8 @@ function clearAuthConfig() {
|
|
|
7207
7208
|
function getApiKey() {
|
|
7208
7209
|
if (process.env.SKILLS_API_KEY)
|
|
7209
7210
|
return process.env.SKILLS_API_KEY;
|
|
7211
|
+
if (process.env.SKILL_API_KEY)
|
|
7212
|
+
return process.env.SKILL_API_KEY;
|
|
7210
7213
|
return getAuthConfig()?.apiKey || null;
|
|
7211
7214
|
}
|
|
7212
7215
|
function normalizeSkillsApiOrigin(apiUrl) {
|
|
@@ -21793,7 +21796,7 @@ class StdioServerTransport {
|
|
|
21793
21796
|
// package.json
|
|
21794
21797
|
var package_default = {
|
|
21795
21798
|
name: "@hasna/skills",
|
|
21796
|
-
version: "0.1.
|
|
21799
|
+
version: "0.1.39",
|
|
21797
21800
|
description: "Skills library for AI coding agents",
|
|
21798
21801
|
type: "module",
|
|
21799
21802
|
bin: {
|
|
@@ -31785,7 +31788,8 @@ function getSkillRequirements(name) {
|
|
|
31785
31788
|
envVars.delete(envVar);
|
|
31786
31789
|
}
|
|
31787
31790
|
}
|
|
31788
|
-
envVars.
|
|
31791
|
+
envVars.delete("SKILL_API_KEY");
|
|
31792
|
+
envVars.add("SKILLS_API_KEY");
|
|
31789
31793
|
}
|
|
31790
31794
|
const systemDeps = new Set;
|
|
31791
31795
|
const depPatterns = [
|
|
@@ -32032,6 +32036,10 @@ var runArgsSchema = {
|
|
|
32032
32036
|
default: [],
|
|
32033
32037
|
description: "CLI-style string arguments passed to the skill."
|
|
32034
32038
|
};
|
|
32039
|
+
var paidRunApprovalSchema = {
|
|
32040
|
+
type: "boolean",
|
|
32041
|
+
description: "Set true only after the user has approved the quoted cost for a paid hosted run."
|
|
32042
|
+
};
|
|
32035
32043
|
var errorSchema = objectSchema({
|
|
32036
32044
|
code: stringSchema("Stable error code."),
|
|
32037
32045
|
message: stringSchema("Human-readable error message."),
|
|
@@ -32259,11 +32267,16 @@ var toolContracts = [
|
|
|
32259
32267
|
name: "run_skill",
|
|
32260
32268
|
title: "Run Skill",
|
|
32261
32269
|
description: "Run a skill locally or through a configured remote runner.",
|
|
32262
|
-
params: ["name", "input?", "args?"],
|
|
32270
|
+
params: ["name", "input?", "args?", "approved?"],
|
|
32263
32271
|
category: "execution",
|
|
32264
32272
|
sideEffects: "local-process-or-remote-run",
|
|
32265
32273
|
stable: true,
|
|
32266
|
-
inputSchema: objectSchema({
|
|
32274
|
+
inputSchema: objectSchema({
|
|
32275
|
+
name: skillNameInput,
|
|
32276
|
+
input: runInputSchema,
|
|
32277
|
+
args: runArgsSchema,
|
|
32278
|
+
approved: paidRunApprovalSchema
|
|
32279
|
+
}, ["name"]),
|
|
32267
32280
|
outputSchema: runOutputSchema
|
|
32268
32281
|
},
|
|
32269
32282
|
{
|
|
@@ -32722,8 +32735,8 @@ function sanitizePublicDiscoveryText(text) {
|
|
|
32722
32735
|
function publicDiscoveryEnvVars(skillName, envVars) {
|
|
32723
32736
|
if (!isPremiumSkill(skillName))
|
|
32724
32737
|
return envVars;
|
|
32725
|
-
const filtered = envVars.filter((envVar) => !VENDOR_ENV_PREFIXES.some((prefix) => envVar.startsWith(prefix)));
|
|
32726
|
-
return filtered.includes("
|
|
32738
|
+
const filtered = envVars.filter((envVar) => envVar !== "SKILL_API_KEY" && !VENDOR_ENV_PREFIXES.some((prefix) => envVar.startsWith(prefix)));
|
|
32739
|
+
return filtered.includes("SKILLS_API_KEY") ? filtered : ["SKILLS_API_KEY", ...filtered];
|
|
32727
32740
|
}
|
|
32728
32741
|
function publicDiscoveryDependencies(skillName, dependencies) {
|
|
32729
32742
|
if (!isPremiumSkill(skillName))
|
|
@@ -32739,7 +32752,7 @@ function publicDiscoveryDocumentation(skill, documentation) {
|
|
|
32739
32752
|
`# ${skill.displayName || skill.name}`,
|
|
32740
32753
|
sanitizePublicDiscoveryText(skill.description),
|
|
32741
32754
|
`Pricing: ${getPublicSkillPricing(skill.name).formattedCost}.`,
|
|
32742
|
-
"Set `
|
|
32755
|
+
"Set `SKILLS_API_KEY` or run `skills auth login` for hosted runtime execution. Runtime routing and model selection are managed by the hosted Skills runtime."
|
|
32743
32756
|
].join(`
|
|
32744
32757
|
|
|
32745
32758
|
`);
|
|
@@ -33262,9 +33275,10 @@ function registerOperationTools(server) {
|
|
|
33262
33275
|
inputSchema: {
|
|
33263
33276
|
name: exports_external.string(),
|
|
33264
33277
|
input: exports_external.record(exports_external.string(), exports_external.unknown()).optional(),
|
|
33265
|
-
args: exports_external.array(exports_external.string()).optional()
|
|
33278
|
+
args: exports_external.array(exports_external.string()).optional(),
|
|
33279
|
+
approved: exports_external.boolean().optional()
|
|
33266
33280
|
}
|
|
33267
|
-
}, async ({ name, input, args }) => {
|
|
33281
|
+
}, async ({ name, input, args, approved }) => {
|
|
33268
33282
|
const skill = getSkill(name);
|
|
33269
33283
|
if (!skill) {
|
|
33270
33284
|
return mcpError("SKILL_NOT_FOUND", `Skill '${name}' not found`, findSimilarSkills(name));
|
|
@@ -33302,6 +33316,17 @@ function registerOperationTools(server) {
|
|
|
33302
33316
|
const run = completeSkillRun(runContext, { status: "failed", error: error48, costCents });
|
|
33303
33317
|
return mcpError("AUTH_REQUIRED", `${error48}. Local run metadata: ${run.paths.runDir}/run.json`, ["skills auth login"]);
|
|
33304
33318
|
}
|
|
33319
|
+
if (isPremiumSkill2(skillName) && apiKey && approved !== true) {
|
|
33320
|
+
const cost = formatCost2(costCents ?? 0);
|
|
33321
|
+
const error48 = `${skillName} is a paid hosted skill (${cost}). Call quote_skill first, then call run_skill with approved: true after user approval.`;
|
|
33322
|
+
writeRunLogs(runContext, "", error48 + `
|
|
33323
|
+
`);
|
|
33324
|
+
const run = completeSkillRun(runContext, { status: "failed", error: error48, costCents });
|
|
33325
|
+
return mcpError("APPROVAL_REQUIRED", `${error48}. Local run metadata: ${run.paths.runDir}/run.json`, [
|
|
33326
|
+
"quote_skill",
|
|
33327
|
+
"run_skill approved=true"
|
|
33328
|
+
]);
|
|
33329
|
+
}
|
|
33305
33330
|
if (isPremiumSkill2(skillName) && apiKey) {
|
|
33306
33331
|
try {
|
|
33307
33332
|
const { RemoteSkillsClient: RemoteSkillsClient2 } = await Promise.resolve().then(() => (init_remote_client(), exports_remote_client));
|
package/dist/index.js
CHANGED
|
@@ -2658,6 +2658,7 @@ var MUSIC_ALBUM_SLUG = "music-album";
|
|
|
2658
2658
|
var MUSIC_ALBUM_SONG_COUNTS = [7, 14, 21];
|
|
2659
2659
|
var MUSIC_ALBUM_COST_CENTS_PER_SONG = 150;
|
|
2660
2660
|
var PREMIUM_SKILLS = [
|
|
2661
|
+
{ slug: "icon-pack", displayName: "Icon Pack", tier: "premium", costCents: 200, providers: ["hosted"], description: "Hosted coordinated icon pack with SVGs, transparent PNGs, size variants, and manifest" },
|
|
2661
2662
|
{ slug: "logo-design", displayName: "Logo Design", tier: "premium", costCents: 50, providers: ["hosted"], description: "Hosted multi-variant logo package with transparent PNGs, vector-style SVGs, usage notes, and manifest" },
|
|
2662
2663
|
{ slug: "deepresearch", displayName: "Deep Research", tier: "premium", costCents: 20, providers: ["exa"], description: "Agentic web research with semantic search and synthesis" },
|
|
2663
2664
|
{ slug: "playlist-maker", displayName: "Playlist Maker", tier: "premium", costCents: 30, providers: ["exa", "gemini-3-pro"], description: "Curated playlist with research, track selection, and album art" },
|
|
@@ -3157,7 +3158,8 @@ function getSkillRequirements(name) {
|
|
|
3157
3158
|
envVars.delete(envVar);
|
|
3158
3159
|
}
|
|
3159
3160
|
}
|
|
3160
|
-
envVars.
|
|
3161
|
+
envVars.delete("SKILL_API_KEY");
|
|
3162
|
+
envVars.add("SKILLS_API_KEY");
|
|
3161
3163
|
}
|
|
3162
3164
|
const systemDeps = new Set;
|
|
3163
3165
|
const depPatterns = [
|
|
@@ -17076,6 +17078,8 @@ function getAuthConfig() {
|
|
|
17076
17078
|
function getApiKey() {
|
|
17077
17079
|
if (process.env.SKILLS_API_KEY)
|
|
17078
17080
|
return process.env.SKILLS_API_KEY;
|
|
17081
|
+
if (process.env.SKILL_API_KEY)
|
|
17082
|
+
return process.env.SKILL_API_KEY;
|
|
17079
17083
|
return getAuthConfig()?.apiKey || null;
|
|
17080
17084
|
}
|
|
17081
17085
|
function normalizeSkillsApiOrigin(apiUrl) {
|
|
@@ -17331,8 +17335,8 @@ function sanitizePublicDiscoveryText(text) {
|
|
|
17331
17335
|
function publicDiscoveryEnvVars(skillName, envVars) {
|
|
17332
17336
|
if (!isPremiumSkill(skillName))
|
|
17333
17337
|
return envVars;
|
|
17334
|
-
const filtered = envVars.filter((envVar) => !VENDOR_ENV_PREFIXES.some((prefix) => envVar.startsWith(prefix)));
|
|
17335
|
-
return filtered.includes("
|
|
17338
|
+
const filtered = envVars.filter((envVar) => envVar !== "SKILL_API_KEY" && !VENDOR_ENV_PREFIXES.some((prefix) => envVar.startsWith(prefix)));
|
|
17339
|
+
return filtered.includes("SKILLS_API_KEY") ? filtered : ["SKILLS_API_KEY", ...filtered];
|
|
17336
17340
|
}
|
|
17337
17341
|
function publicDiscoveryDependencies(skillName, dependencies) {
|
|
17338
17342
|
if (!isPremiumSkill(skillName))
|
|
@@ -17348,7 +17352,7 @@ function publicDiscoveryDocumentation(skill, documentation) {
|
|
|
17348
17352
|
`# ${skill.displayName || skill.name}`,
|
|
17349
17353
|
sanitizePublicDiscoveryText(skill.description),
|
|
17350
17354
|
`Pricing: ${getPublicSkillPricing(skill.name).formattedCost}.`,
|
|
17351
|
-
"Set `
|
|
17355
|
+
"Set `SKILLS_API_KEY` or run `skills auth login` for hosted runtime execution. Runtime routing and model selection are managed by the hosted Skills runtime."
|
|
17352
17356
|
].join(`
|
|
17353
17357
|
|
|
17354
17358
|
`);
|
|
@@ -18031,7 +18035,7 @@ import { dirname as dirname3, relative as relative2 } from "path";
|
|
|
18031
18035
|
// package.json
|
|
18032
18036
|
var package_default = {
|
|
18033
18037
|
name: "@hasna/skills",
|
|
18034
|
-
version: "0.1.
|
|
18038
|
+
version: "0.1.39",
|
|
18035
18039
|
description: "Skills library for AI coding agents",
|
|
18036
18040
|
type: "module",
|
|
18037
18041
|
bin: {
|
|
@@ -18230,6 +18234,10 @@ var runArgsSchema = {
|
|
|
18230
18234
|
default: [],
|
|
18231
18235
|
description: "CLI-style string arguments passed to the skill."
|
|
18232
18236
|
};
|
|
18237
|
+
var paidRunApprovalSchema = {
|
|
18238
|
+
type: "boolean",
|
|
18239
|
+
description: "Set true only after the user has approved the quoted cost for a paid hosted run."
|
|
18240
|
+
};
|
|
18233
18241
|
var errorSchema = objectSchema({
|
|
18234
18242
|
code: stringSchema("Stable error code."),
|
|
18235
18243
|
message: stringSchema("Human-readable error message."),
|
|
@@ -18457,11 +18465,16 @@ var toolContracts = [
|
|
|
18457
18465
|
name: "run_skill",
|
|
18458
18466
|
title: "Run Skill",
|
|
18459
18467
|
description: "Run a skill locally or through a configured remote runner.",
|
|
18460
|
-
params: ["name", "input?", "args?"],
|
|
18468
|
+
params: ["name", "input?", "args?", "approved?"],
|
|
18461
18469
|
category: "execution",
|
|
18462
18470
|
sideEffects: "local-process-or-remote-run",
|
|
18463
18471
|
stable: true,
|
|
18464
|
-
inputSchema: objectSchema({
|
|
18472
|
+
inputSchema: objectSchema({
|
|
18473
|
+
name: skillNameInput,
|
|
18474
|
+
input: runInputSchema,
|
|
18475
|
+
args: runArgsSchema,
|
|
18476
|
+
approved: paidRunApprovalSchema
|
|
18477
|
+
}, ["name"]),
|
|
18465
18478
|
outputSchema: runOutputSchema
|
|
18466
18479
|
},
|
|
18467
18480
|
{
|
package/package.json
CHANGED
package/skills/_common/auth.ts
CHANGED
|
@@ -4,28 +4,24 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
export function checkSkillAuth(): void {
|
|
7
|
-
const
|
|
7
|
+
const skillsApiKey = process.env.SKILLS_API_KEY || process.env.SKILL_API_KEY;
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
console.error('❌ Error: SKILL_API_KEY environment variable not set');
|
|
9
|
+
if (!skillsApiKey) {
|
|
10
|
+
console.error('Error: SKILLS_API_KEY environment variable not set');
|
|
12
11
|
console.error('');
|
|
13
|
-
console.error('To use
|
|
12
|
+
console.error('To use hosted execution, set your SKILLS_API_KEY:');
|
|
14
13
|
console.error('');
|
|
15
|
-
console.error(' export
|
|
14
|
+
console.error(' export SKILLS_API_KEY=your-api-key-here');
|
|
16
15
|
console.error('');
|
|
17
|
-
console.error('
|
|
16
|
+
console.error('You can also use the root `skills auth login` command.');
|
|
18
17
|
process.exit(1);
|
|
19
18
|
}
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
console.error('❌ Error: Invalid SKILL_API_KEY format');
|
|
20
|
+
if (!skillsApiKey.startsWith('sk-skill-')) {
|
|
21
|
+
console.error('Error: Invalid SKILLS_API_KEY format');
|
|
24
22
|
console.error('Expected format: sk-skill-xxxxxxxxxxxx');
|
|
25
23
|
process.exit(1);
|
|
26
24
|
}
|
|
27
|
-
|
|
28
|
-
// Key is valid - skill can proceed
|
|
29
25
|
}
|
|
30
26
|
|
|
31
27
|
/**
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Usage: import and call executeSkill() from your skill CLI
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
const SKILL_API_URL = process.env.SKILL_API_URL || "https://
|
|
8
|
+
const SKILL_API_URL = process.env.SKILLS_API_URL || process.env.SKILL_API_URL || "https://skills.md/api/v1";
|
|
9
9
|
|
|
10
10
|
export interface SkillRequest {
|
|
11
11
|
skill: string;
|
|
@@ -33,12 +33,12 @@ export async function executeSkill(request: SkillRequest): Promise<SkillResponse
|
|
|
33
33
|
const url = `${SKILL_API_URL}/${skill}/`;
|
|
34
34
|
|
|
35
35
|
// Get API key from environment
|
|
36
|
-
const apiKey = process.env.SKILL_API_KEY;
|
|
36
|
+
const apiKey = process.env.SKILLS_API_KEY || process.env.SKILL_API_KEY;
|
|
37
37
|
if (!apiKey) {
|
|
38
38
|
return {
|
|
39
39
|
success: false,
|
|
40
|
-
error: "Missing
|
|
41
|
-
details: "Set
|
|
40
|
+
error: "Missing SKILLS_API_KEY",
|
|
41
|
+
details: "Set SKILLS_API_KEY environment variable or run `skills auth login`"
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
44
|
|
package/skills/audio/SKILL.md
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
"version": "1.0.0",
|
|
4
4
|
"description": "Code quality CLI for auto-linting, formatting, and fixing code issues",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "src/index.ts",
|
|
6
|
+
"main": "src/index-local.ts",
|
|
7
7
|
"bin": {
|
|
8
|
-
"codefix": "src/index.ts"
|
|
8
|
+
"codefix": "src/index-local.ts"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
|
-
"start": "bun run src/index.ts",
|
|
12
|
-
"dev": "bun run --watch src/index.ts"
|
|
11
|
+
"start": "bun run src/index-local.ts",
|
|
12
|
+
"dev": "bun run --watch src/index-local.ts"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {},
|
|
15
15
|
"devDependencies": {
|
|
@@ -13,7 +13,7 @@ const SKILL_META = {
|
|
|
13
13
|
description: 'Code quality CLI for auto-linting, formatting, and fixing code issues',
|
|
14
14
|
version: '1.0.0',
|
|
15
15
|
commands: `Use: codefix --help`,
|
|
16
|
-
requiredEnvVars: [
|
|
16
|
+
requiredEnvVars: [],
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
if (await handleInstallCommand(SKILL_META, process.argv.slice(2))) {
|
|
@@ -49,6 +49,7 @@ function parseArgs(): {
|
|
|
49
49
|
verbose?: boolean;
|
|
50
50
|
} {
|
|
51
51
|
const args = process.argv.slice(2);
|
|
52
|
+
if (args[0] === '--help' || args[0] === '-h') args[0] = 'help';
|
|
52
53
|
const parsed: Record<string, unknown> = { command: args[0] || 'help' };
|
|
53
54
|
|
|
54
55
|
for (let i = 1; i < args.length; i++) {
|
|
@@ -1,110 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* Calls the remote skill API server
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { executeAndSave, executeSkill, handleInstallCommand } from '../../_common';
|
|
9
|
-
|
|
10
|
-
// Skill metadata for install command
|
|
11
|
-
const SKILL_META = {
|
|
12
|
-
name: 'codefix',
|
|
13
|
-
description: 'Codefix skill - calls remote API',
|
|
14
|
-
version: '1.0.0',
|
|
15
|
-
commands: `codefix <command> [options]`,
|
|
16
|
-
requiredEnvVars: ['SKILL_API_KEY'],
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
// Handle install/uninstall commands
|
|
20
|
-
if (await handleInstallCommand(SKILL_META, process.argv.slice(2))) {
|
|
21
|
-
process.exit(0);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Parse command line arguments
|
|
25
|
-
function parseArgs(): Record<string, string | boolean> {
|
|
26
|
-
const args = process.argv.slice(2);
|
|
27
|
-
const parsed: Record<string, string | boolean> = {};
|
|
28
|
-
|
|
29
|
-
for (let i = 0; i < args.length; i++) {
|
|
30
|
-
if (args[i].startsWith('--')) {
|
|
31
|
-
const key = args[i].slice(2);
|
|
32
|
-
const value = args[i + 1];
|
|
33
|
-
if (value && !value.startsWith('--')) {
|
|
34
|
-
parsed[key] = value;
|
|
35
|
-
i++;
|
|
36
|
-
} else {
|
|
37
|
-
parsed[key] = true;
|
|
38
|
-
}
|
|
39
|
-
} else if (!parsed.command) {
|
|
40
|
-
parsed.command = args[i];
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return parsed;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Main logic
|
|
48
|
-
async function main() {
|
|
49
|
-
const args = parseArgs();
|
|
50
|
-
const command = (args.command as string) || 'help';
|
|
51
|
-
|
|
52
|
-
if (command === 'help' || args.help) {
|
|
53
|
-
console.log(`Skill Codefix CLI
|
|
54
|
-
|
|
55
|
-
USAGE:
|
|
56
|
-
codefix <command> [options]
|
|
57
|
-
|
|
58
|
-
COMMANDS:
|
|
59
|
-
Call with any command and it will be forwarded to the remote API server
|
|
60
|
-
|
|
61
|
-
EXAMPLES:
|
|
62
|
-
codefix generate --provider <provider> [options]`);
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Extract all parameters
|
|
67
|
-
const { command: cmd, ...params } = args;
|
|
68
|
-
|
|
69
|
-
// Check if output file is expected (for file-generating skills)
|
|
70
|
-
const fileSkills = ['audio', 'image', 'video', 'emoji'];
|
|
71
|
-
const isFileSkill = fileSkills.includes('codefix');
|
|
72
|
-
|
|
73
|
-
if (isFileSkill && params.output) {
|
|
74
|
-
// Skill that generates files
|
|
75
|
-
const success = await executeAndSave({
|
|
76
|
-
skill: 'codefix',
|
|
77
|
-
command: cmd,
|
|
78
|
-
...params,
|
|
79
|
-
});
|
|
80
|
-
process.exit(success ? 0 : 1);
|
|
81
|
-
} else {
|
|
82
|
-
// Skill that returns JSON/text
|
|
83
|
-
const result = await executeSkill({
|
|
84
|
-
skill: 'codefix',
|
|
85
|
-
command: cmd,
|
|
86
|
-
...params,
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
if (result instanceof Blob) {
|
|
90
|
-
console.error('❌ Unexpected binary response');
|
|
91
|
-
process.exit(1);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (result.success && result.output) {
|
|
95
|
-
console.log(result.output);
|
|
96
|
-
} else {
|
|
97
|
-
console.error(`❌ Error: ${result.error}`);
|
|
98
|
-
if (result.details) {
|
|
99
|
-
console.error(` ${result.details}`);
|
|
100
|
-
}
|
|
101
|
-
process.exit(1);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Run main
|
|
107
|
-
main().catch((error) => {
|
|
108
|
-
console.error('❌ Fatal error:', error.message);
|
|
109
|
-
process.exit(1);
|
|
110
|
-
});
|
|
3
|
+
// Keep the package root on the local implementation; hosted execution goes through the root Skills CLI.
|
|
4
|
+
import "./index-local";
|
package/skills/convert/SKILL.md
CHANGED
|
@@ -9,7 +9,7 @@ description: File format conversion and transformation CLI between images, PDFs,
|
|
|
9
9
|
|
|
10
10
|
File format conversion skill with AI-powered extraction capabilities. Converts between images, PDFs, documents, and data formats with optional quality control and AI cleanup.
|
|
11
11
|
|
|
12
|
-
This CLI is API-backed. Set `
|
|
12
|
+
This CLI is API-backed. Set `SKILLS_API_KEY` when routing through the hosted skills/connectors runtime; provider-specific keys are managed by that runtime.
|
|
13
13
|
|
|
14
14
|
## Category
|
|
15
15
|
|
|
@@ -65,7 +65,7 @@ bun run src/index.ts formats
|
|
|
65
65
|
- `openai` - GPT-4o AI
|
|
66
66
|
|
|
67
67
|
### API Key
|
|
68
|
-
- `
|
|
68
|
+
- `SKILLS_API_KEY` - Hosted runtime access. Provider credentials for AI features are managed remotely.
|
|
69
69
|
|
|
70
70
|
## Conversion Categories
|
|
71
71
|
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
"version": "1.0.0",
|
|
4
4
|
"description": "File format conversion CLI - convert between images, PDFs, documents, and data formats with AI-powered extraction",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "src/index.ts",
|
|
6
|
+
"main": "src/index-local.ts",
|
|
7
7
|
"bin": {
|
|
8
|
-
"convert": "src/index.ts"
|
|
8
|
+
"convert": "src/index-local.ts"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
|
-
"start": "bun run src/index.ts",
|
|
12
|
-
"dev": "bun run --watch src/index.ts"
|
|
11
|
+
"start": "bun run src/index-local.ts",
|
|
12
|
+
"dev": "bun run --watch src/index-local.ts"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"@anthropic-ai/sdk": "^0.36.3",
|
|
@@ -13,7 +13,7 @@ const SKILL_META = {
|
|
|
13
13
|
description: 'File format conversion CLI - convert between images, PDFs, documents, and data formats with AI-powered extraction',
|
|
14
14
|
version: '1.0.0',
|
|
15
15
|
commands: `Use: convert --help`,
|
|
16
|
-
requiredEnvVars: [
|
|
16
|
+
requiredEnvVars: [],
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
if (await handleInstallCommand(SKILL_META, process.argv.slice(2))) {
|
|
@@ -37,17 +37,6 @@ import {
|
|
|
37
37
|
requiresAI,
|
|
38
38
|
getFormatCategory,
|
|
39
39
|
} from './types';
|
|
40
|
-
import {
|
|
41
|
-
convertImage,
|
|
42
|
-
convertDocument,
|
|
43
|
-
convertData,
|
|
44
|
-
convertWithAI,
|
|
45
|
-
pdfToText,
|
|
46
|
-
imagesToPdf,
|
|
47
|
-
getPdfMetadata,
|
|
48
|
-
getImageMetadata,
|
|
49
|
-
} from './converters';
|
|
50
|
-
|
|
51
40
|
// Parse command line arguments
|
|
52
41
|
function parseArgs(): {
|
|
53
42
|
command: string;
|
|
@@ -68,6 +57,7 @@ function parseArgs(): {
|
|
|
68
57
|
recursive?: boolean;
|
|
69
58
|
} {
|
|
70
59
|
const args = process.argv.slice(2);
|
|
60
|
+
if (args[0] === '--help' || args[0] === '-h') args[0] = 'help';
|
|
71
61
|
const parsed: Record<string, unknown> = { command: args[0] || 'help' };
|
|
72
62
|
|
|
73
63
|
for (let i = 1; i < args.length; i++) {
|
|
@@ -284,6 +274,7 @@ async function showInfo(filePath: string): Promise<void> {
|
|
|
284
274
|
// Format-specific info
|
|
285
275
|
if (category === 'image') {
|
|
286
276
|
try {
|
|
277
|
+
const { getImageMetadata } = await import('./converters/image');
|
|
287
278
|
const metadata = await getImageMetadata(filePath);
|
|
288
279
|
console.log(`Dimensions: ${metadata.width}x${metadata.height}`);
|
|
289
280
|
console.log(`Channels: ${metadata.channels}`);
|
|
@@ -292,6 +283,7 @@ async function showInfo(filePath: string): Promise<void> {
|
|
|
292
283
|
}
|
|
293
284
|
} else if (format === 'pdf') {
|
|
294
285
|
try {
|
|
286
|
+
const { getPdfMetadata } = await import('./converters/pdf');
|
|
295
287
|
const metadata = await getPdfMetadata(filePath);
|
|
296
288
|
console.log(`Pages: ${metadata.pageCount}`);
|
|
297
289
|
if (metadata.title) console.log(`Title: ${metadata.title}`);
|
|
@@ -334,11 +326,13 @@ async function convert(options: ConvertOptions): Promise<ConvertResult> {
|
|
|
334
326
|
duration: 0,
|
|
335
327
|
};
|
|
336
328
|
}
|
|
329
|
+
const { convertWithAI } = await import('./converters/ai');
|
|
337
330
|
return convertWithAI(options);
|
|
338
331
|
}
|
|
339
332
|
|
|
340
333
|
// Image to image
|
|
341
334
|
if (inputCategory === 'image' && outputCategory === 'image') {
|
|
335
|
+
const { convertImage } = await import('./converters/image');
|
|
342
336
|
return convertImage(options);
|
|
343
337
|
}
|
|
344
338
|
|
|
@@ -350,21 +344,25 @@ async function convert(options: ConvertOptions): Promise<ConvertResult> {
|
|
|
350
344
|
|
|
351
345
|
// PDF to text
|
|
352
346
|
if (inputFormat === 'pdf' && outputFormat === 'txt') {
|
|
347
|
+
const { pdfToText } = await import('./converters/pdf');
|
|
353
348
|
return pdfToText(options);
|
|
354
349
|
}
|
|
355
350
|
|
|
356
351
|
// Document conversions
|
|
357
352
|
if (inputCategory === 'document' || outputCategory === 'document') {
|
|
353
|
+
const { convertDocument } = await import('./converters/document');
|
|
358
354
|
return convertDocument(options);
|
|
359
355
|
}
|
|
360
356
|
|
|
361
357
|
// Data conversions
|
|
362
358
|
if (inputCategory === 'data' || outputCategory === 'data') {
|
|
359
|
+
const { convertData } = await import('./converters/data');
|
|
363
360
|
return convertData(options);
|
|
364
361
|
}
|
|
365
362
|
|
|
366
363
|
// Markup conversions
|
|
367
364
|
if (inputCategory === 'markup' || outputCategory === 'markup') {
|
|
365
|
+
const { convertDocument } = await import('./converters/document');
|
|
368
366
|
return convertDocument(options);
|
|
369
367
|
}
|
|
370
368
|
|
|
@@ -399,6 +397,7 @@ async function main(): Promise<void> {
|
|
|
399
397
|
|
|
400
398
|
// Check if multiple inputs for PDF creation
|
|
401
399
|
if (args.inputs && args.inputs.length > 1 && args.format === 'pdf') {
|
|
400
|
+
const { imagesToPdf } = await import('./converters/pdf');
|
|
402
401
|
console.log(`\nCombining ${args.inputs.length} images into PDF...`);
|
|
403
402
|
const result = await imagesToPdf(
|
|
404
403
|
args.inputs,
|
|
@@ -1,110 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* Calls the remote skill API server
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { executeAndSave, executeSkill, handleInstallCommand } from '../../_common';
|
|
9
|
-
|
|
10
|
-
// Skill metadata for install command
|
|
11
|
-
const SKILL_META = {
|
|
12
|
-
name: 'convert',
|
|
13
|
-
description: 'Convert skill - calls remote API',
|
|
14
|
-
version: '1.0.0',
|
|
15
|
-
commands: `convert <command> [options]`,
|
|
16
|
-
requiredEnvVars: ['SKILL_API_KEY'],
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
// Handle install/uninstall commands
|
|
20
|
-
if (await handleInstallCommand(SKILL_META, process.argv.slice(2))) {
|
|
21
|
-
process.exit(0);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Parse command line arguments
|
|
25
|
-
function parseArgs(): Record<string, string | boolean> {
|
|
26
|
-
const args = process.argv.slice(2);
|
|
27
|
-
const parsed: Record<string, string | boolean> = {};
|
|
28
|
-
|
|
29
|
-
for (let i = 0; i < args.length; i++) {
|
|
30
|
-
if (args[i].startsWith('--')) {
|
|
31
|
-
const key = args[i].slice(2);
|
|
32
|
-
const value = args[i + 1];
|
|
33
|
-
if (value && !value.startsWith('--')) {
|
|
34
|
-
parsed[key] = value;
|
|
35
|
-
i++;
|
|
36
|
-
} else {
|
|
37
|
-
parsed[key] = true;
|
|
38
|
-
}
|
|
39
|
-
} else if (!parsed.command) {
|
|
40
|
-
parsed.command = args[i];
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return parsed;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Main logic
|
|
48
|
-
async function main() {
|
|
49
|
-
const args = parseArgs();
|
|
50
|
-
const command = (args.command as string) || 'help';
|
|
51
|
-
|
|
52
|
-
if (command === 'help' || args.help) {
|
|
53
|
-
console.log(`Skill Convert CLI
|
|
54
|
-
|
|
55
|
-
USAGE:
|
|
56
|
-
convert <command> [options]
|
|
57
|
-
|
|
58
|
-
COMMANDS:
|
|
59
|
-
Call with any command and it will be forwarded to the remote API server
|
|
60
|
-
|
|
61
|
-
EXAMPLES:
|
|
62
|
-
convert generate --provider <provider> [options]`);
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Extract all parameters
|
|
67
|
-
const { command: cmd, ...params } = args;
|
|
68
|
-
|
|
69
|
-
// Check if output file is expected (for file-generating skills)
|
|
70
|
-
const fileSkills = ['audio', 'image', 'video', 'emoji'];
|
|
71
|
-
const isFileSkill = fileSkills.includes('convert');
|
|
72
|
-
|
|
73
|
-
if (isFileSkill && params.output) {
|
|
74
|
-
// Skill that generates files
|
|
75
|
-
const success = await executeAndSave({
|
|
76
|
-
skill: 'convert',
|
|
77
|
-
command: cmd,
|
|
78
|
-
...params,
|
|
79
|
-
});
|
|
80
|
-
process.exit(success ? 0 : 1);
|
|
81
|
-
} else {
|
|
82
|
-
// Skill that returns JSON/text
|
|
83
|
-
const result = await executeSkill({
|
|
84
|
-
skill: 'convert',
|
|
85
|
-
command: cmd,
|
|
86
|
-
...params,
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
if (result instanceof Blob) {
|
|
90
|
-
console.error('❌ Unexpected binary response');
|
|
91
|
-
process.exit(1);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (result.success && result.output) {
|
|
95
|
-
console.log(result.output);
|
|
96
|
-
} else {
|
|
97
|
-
console.error(`❌ Error: ${result.error}`);
|
|
98
|
-
if (result.details) {
|
|
99
|
-
console.error(` ${result.details}`);
|
|
100
|
-
}
|
|
101
|
-
process.exit(1);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Run main
|
|
107
|
-
main().catch((error) => {
|
|
108
|
-
console.error('❌ Fatal error:', error.message);
|
|
109
|
-
process.exit(1);
|
|
110
|
-
});
|
|
3
|
+
// Keep the package root on the local implementation; hosted execution goes through the root Skills CLI.
|
|
4
|
+
import "./index-local";
|