@hasnatools/skills 0.1.8 → 0.1.10
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/dist/index.js +779 -86
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -20709,6 +20709,12 @@ async function getMarketplaceSkills(options) {
|
|
|
20709
20709
|
const query = params.toString();
|
|
20710
20710
|
return apiRequest(`/skills${query ? `?${query}` : ""}`);
|
|
20711
20711
|
}
|
|
20712
|
+
async function getSkill(slug) {
|
|
20713
|
+
return apiRequest(`/skills/${slug}`);
|
|
20714
|
+
}
|
|
20715
|
+
async function downloadSkill(slug) {
|
|
20716
|
+
return apiRequest(`/skills/${slug}/download?format=json`);
|
|
20717
|
+
}
|
|
20712
20718
|
async function installSkill(slug) {
|
|
20713
20719
|
return apiRequest(`/skills/${slug}/install`);
|
|
20714
20720
|
}
|
|
@@ -20916,6 +20922,7 @@ async function logoutCommand() {
|
|
|
20916
20922
|
clearApiKey();
|
|
20917
20923
|
console.log(source_default.green("✓") + " Logged out successfully");
|
|
20918
20924
|
}
|
|
20925
|
+
var indigo = source_default.hex("#6366f1");
|
|
20919
20926
|
async function whoamiCommand() {
|
|
20920
20927
|
const apiKey = getApiKey();
|
|
20921
20928
|
if (!apiKey) {
|
|
@@ -20932,12 +20939,18 @@ async function whoamiCommand() {
|
|
|
20932
20939
|
}
|
|
20933
20940
|
spinner.stop();
|
|
20934
20941
|
console.log();
|
|
20935
|
-
console.log(
|
|
20942
|
+
console.log(indigo.bold("Account Information"));
|
|
20936
20943
|
console.log();
|
|
20937
|
-
console.log(" Email: " +
|
|
20938
|
-
console.log(" Name: " + result.data.name);
|
|
20944
|
+
console.log(" Email: " + indigo(result.data.email));
|
|
20945
|
+
console.log(" Name: " + (result.data.name || source_default.dim("Not set")));
|
|
20939
20946
|
console.log(" Plan: " + source_default.bold(result.data.plan));
|
|
20940
|
-
console.log(
|
|
20947
|
+
console.log();
|
|
20948
|
+
console.log(indigo.bold("Organization"));
|
|
20949
|
+
console.log();
|
|
20950
|
+
console.log(" Name: " + (result.data.tenantName || source_default.dim("Personal")));
|
|
20951
|
+
console.log(" Slug: " + indigo(result.data.tenantSlug || result.data.tenantId));
|
|
20952
|
+
console.log();
|
|
20953
|
+
console.log(source_default.dim("Run `skills credits` to check your balance"));
|
|
20941
20954
|
console.log();
|
|
20942
20955
|
}
|
|
20943
20956
|
function sleep(ms) {
|
|
@@ -21080,9 +21093,179 @@ async function uninstallCommand(slug, options = {}) {
|
|
|
21080
21093
|
}
|
|
21081
21094
|
}
|
|
21082
21095
|
|
|
21096
|
+
// src/commands/download.ts
|
|
21097
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
21098
|
+
import { join as join4, normalize, basename, dirname, isAbsolute } from "path";
|
|
21099
|
+
var indigo2 = source_default.hex("#6366f1");
|
|
21100
|
+
function validateFilename(filename) {
|
|
21101
|
+
if (!filename || filename.trim() === "") {
|
|
21102
|
+
return null;
|
|
21103
|
+
}
|
|
21104
|
+
if (isAbsolute(filename)) {
|
|
21105
|
+
return null;
|
|
21106
|
+
}
|
|
21107
|
+
const normalized = normalize(filename);
|
|
21108
|
+
if (normalized.startsWith("..") || normalized.includes("/../") || normalized.includes("\\..\\")) {
|
|
21109
|
+
return null;
|
|
21110
|
+
}
|
|
21111
|
+
if (normalized.startsWith("/") || normalized.startsWith("\\")) {
|
|
21112
|
+
return null;
|
|
21113
|
+
}
|
|
21114
|
+
if (filename.includes("\x00")) {
|
|
21115
|
+
return null;
|
|
21116
|
+
}
|
|
21117
|
+
const rootFile = normalized.split(/[/\\]/)[0];
|
|
21118
|
+
if (rootFile.startsWith(".") && rootFile !== ".") {
|
|
21119
|
+
return null;
|
|
21120
|
+
}
|
|
21121
|
+
const allowedExtensions = [
|
|
21122
|
+
".md",
|
|
21123
|
+
".ts",
|
|
21124
|
+
".js",
|
|
21125
|
+
".mjs",
|
|
21126
|
+
".cjs",
|
|
21127
|
+
".json",
|
|
21128
|
+
".yaml",
|
|
21129
|
+
".yml",
|
|
21130
|
+
".txt",
|
|
21131
|
+
".sh",
|
|
21132
|
+
".bash",
|
|
21133
|
+
".zsh",
|
|
21134
|
+
".py",
|
|
21135
|
+
".rb",
|
|
21136
|
+
".go",
|
|
21137
|
+
".rs",
|
|
21138
|
+
".css",
|
|
21139
|
+
".html",
|
|
21140
|
+
".svg",
|
|
21141
|
+
".toml",
|
|
21142
|
+
".env.example"
|
|
21143
|
+
];
|
|
21144
|
+
const ext = filename.substring(filename.lastIndexOf(".")).toLowerCase();
|
|
21145
|
+
const hasValidExtension = allowedExtensions.some((allowed) => filename.toLowerCase().endsWith(allowed));
|
|
21146
|
+
const isKnownFile = ["LICENSE", "README", "CHANGELOG", "AUTHORS", "CONTRIBUTORS"].some((known) => basename(filename).toUpperCase() === known);
|
|
21147
|
+
if (!hasValidExtension && !isKnownFile && ext.length > 0) {
|
|
21148
|
+
console.log(source_default.yellow(` Skipping file with disallowed extension: ${filename}`));
|
|
21149
|
+
return null;
|
|
21150
|
+
}
|
|
21151
|
+
return normalized;
|
|
21152
|
+
}
|
|
21153
|
+
function validateSlug(slug) {
|
|
21154
|
+
const validSlugPattern = /^[a-z0-9][a-z0-9-_]*[a-z0-9]$|^[a-z0-9]$/i;
|
|
21155
|
+
return validSlugPattern.test(slug) && slug.length <= 64;
|
|
21156
|
+
}
|
|
21157
|
+
function safeJoin(basePath, relativePath) {
|
|
21158
|
+
const validated = validateFilename(relativePath);
|
|
21159
|
+
if (!validated) {
|
|
21160
|
+
return null;
|
|
21161
|
+
}
|
|
21162
|
+
const fullPath = join4(basePath, validated);
|
|
21163
|
+
const normalizedBase = normalize(basePath);
|
|
21164
|
+
const normalizedFull = normalize(fullPath);
|
|
21165
|
+
if (!normalizedFull.startsWith(normalizedBase)) {
|
|
21166
|
+
return null;
|
|
21167
|
+
}
|
|
21168
|
+
return fullPath;
|
|
21169
|
+
}
|
|
21170
|
+
async function downloadCommand(slug, options = {}) {
|
|
21171
|
+
if (!slug || slug.trim() === "") {
|
|
21172
|
+
console.log(source_default.yellow("Please provide a skill name"));
|
|
21173
|
+
console.log(source_default.dim("Usage: skills download <name>"));
|
|
21174
|
+
return;
|
|
21175
|
+
}
|
|
21176
|
+
if (!validateSlug(slug)) {
|
|
21177
|
+
console.log(source_default.red("Invalid skill name format"));
|
|
21178
|
+
console.log(source_default.dim("Skill names can only contain letters, numbers, hyphens, and underscores"));
|
|
21179
|
+
return;
|
|
21180
|
+
}
|
|
21181
|
+
const isLocal = options.local ?? false;
|
|
21182
|
+
const target = options.target ?? getDefaultTarget();
|
|
21183
|
+
let installDir;
|
|
21184
|
+
if (isLocal) {
|
|
21185
|
+
if (!hasLocalConfig()) {
|
|
21186
|
+
console.log(source_default.yellow("Not in a skills.md project"));
|
|
21187
|
+
console.log(source_default.dim("Run `skills init` first or download globally (default)"));
|
|
21188
|
+
return;
|
|
21189
|
+
}
|
|
21190
|
+
installDir = target === "claude" ? getProjectClaudeSkillsDir() : getProjectCodexSkillsDir();
|
|
21191
|
+
} else {
|
|
21192
|
+
installDir = target === "claude" ? getClaudeSkillsDir() : getCodexSkillsDir();
|
|
21193
|
+
}
|
|
21194
|
+
const spinner = ora(`Checking skill "${slug}"...`).start();
|
|
21195
|
+
try {
|
|
21196
|
+
const skillInfo = await getSkill(slug);
|
|
21197
|
+
if (skillInfo.error || !skillInfo.data) {
|
|
21198
|
+
spinner.fail("Skill not found");
|
|
21199
|
+
console.error(source_default.red(skillInfo.error || `Could not find skill: ${slug}`));
|
|
21200
|
+
return;
|
|
21201
|
+
}
|
|
21202
|
+
spinner.text = `Downloading ${skillInfo.data.name}...`;
|
|
21203
|
+
const result = await downloadSkill(slug);
|
|
21204
|
+
if (result.error || !result.data) {
|
|
21205
|
+
if (result.status === 404) {
|
|
21206
|
+
spinner.fail("Skill not available for download");
|
|
21207
|
+
console.log();
|
|
21208
|
+
console.log(source_default.yellow("This skill is not downloadable."));
|
|
21209
|
+
console.log(source_default.dim("Some skills are remote-execution only to protect source code."));
|
|
21210
|
+
console.log();
|
|
21211
|
+
console.log(source_default.dim("You can still use this skill via:"));
|
|
21212
|
+
console.log(` skills install ${slug}`);
|
|
21213
|
+
console.log(` skills run ${slug} -- "your prompt"`);
|
|
21214
|
+
} else {
|
|
21215
|
+
spinner.fail("Download failed");
|
|
21216
|
+
console.error(source_default.red(result.error || "Unknown error"));
|
|
21217
|
+
}
|
|
21218
|
+
return;
|
|
21219
|
+
}
|
|
21220
|
+
spinner.text = `Installing ${result.data.name}...`;
|
|
21221
|
+
const { name, version, files } = result.data;
|
|
21222
|
+
const skillDir = join4(installDir, `skill-${slug}`);
|
|
21223
|
+
const exportsDir = join4(skillDir, "exports");
|
|
21224
|
+
const logsDir = join4(skillDir, "logs");
|
|
21225
|
+
mkdirSync3(skillDir, { recursive: true });
|
|
21226
|
+
mkdirSync3(exportsDir, { recursive: true });
|
|
21227
|
+
mkdirSync3(logsDir, { recursive: true });
|
|
21228
|
+
let filesWritten = 0;
|
|
21229
|
+
let filesSkipped = 0;
|
|
21230
|
+
for (const [relativePath, content] of Object.entries(files)) {
|
|
21231
|
+
const safePath = safeJoin(skillDir, relativePath);
|
|
21232
|
+
if (!safePath) {
|
|
21233
|
+
console.log(source_default.yellow(` Skipping unsafe path: ${relativePath}`));
|
|
21234
|
+
filesSkipped++;
|
|
21235
|
+
continue;
|
|
21236
|
+
}
|
|
21237
|
+
const parentDir = dirname(safePath);
|
|
21238
|
+
if (!existsSync4(parentDir)) {
|
|
21239
|
+
mkdirSync3(parentDir, { recursive: true });
|
|
21240
|
+
}
|
|
21241
|
+
writeFileSync4(safePath, content, "utf-8");
|
|
21242
|
+
filesWritten++;
|
|
21243
|
+
}
|
|
21244
|
+
spinner.succeed(`Downloaded ${source_default.bold(name)} v${version}`);
|
|
21245
|
+
console.log();
|
|
21246
|
+
console.log(indigo2.bold("Download Summary"));
|
|
21247
|
+
console.log();
|
|
21248
|
+
console.log(source_default.green(" ✓") + ` Location: ${source_default.dim(skillDir)}`);
|
|
21249
|
+
console.log(source_default.green(" ✓") + ` Files written: ${source_default.bold(filesWritten)}`);
|
|
21250
|
+
if (filesSkipped > 0) {
|
|
21251
|
+
console.log(source_default.yellow(" ⚠") + ` Files skipped: ${source_default.bold(filesSkipped)}`);
|
|
21252
|
+
}
|
|
21253
|
+
console.log(source_default.green(" ✓") + ` Target: ${source_default.bold(target)}`);
|
|
21254
|
+
console.log(source_default.green(" ✓") + ` Scope: ${isLocal ? "project" : "global"}`);
|
|
21255
|
+
console.log();
|
|
21256
|
+
console.log(source_default.dim("This skill includes source code. You can:"));
|
|
21257
|
+
console.log(source_default.dim(" • Read and modify the code locally"));
|
|
21258
|
+
console.log(source_default.dim(" • Run it via remote API:") + ` skills run ${slug}`);
|
|
21259
|
+
console.log();
|
|
21260
|
+
} catch (error) {
|
|
21261
|
+
spinner.fail("Download failed");
|
|
21262
|
+
console.error(source_default.red(error instanceof Error ? error.message : "Unknown error"));
|
|
21263
|
+
}
|
|
21264
|
+
}
|
|
21265
|
+
|
|
21083
21266
|
// src/commands/list.ts
|
|
21084
|
-
import { existsSync as
|
|
21085
|
-
import { join as
|
|
21267
|
+
import { existsSync as existsSync5, readdirSync, readFileSync as readFileSync2 } from "fs";
|
|
21268
|
+
import { join as join5 } from "path";
|
|
21086
21269
|
async function listCommand(options = {}) {
|
|
21087
21270
|
const isGlobal = options.global ?? false;
|
|
21088
21271
|
const target = options.target ?? getDefaultTarget();
|
|
@@ -21128,15 +21311,15 @@ async function listCommand(options = {}) {
|
|
|
21128
21311
|
}
|
|
21129
21312
|
const installedSkills = [];
|
|
21130
21313
|
for (const dir of dirs) {
|
|
21131
|
-
if (!
|
|
21314
|
+
if (!existsSync5(dir))
|
|
21132
21315
|
continue;
|
|
21133
21316
|
const entries = readdirSync(dir, { withFileTypes: true });
|
|
21134
21317
|
for (const entry of entries) {
|
|
21135
21318
|
if (!entry.isDirectory())
|
|
21136
21319
|
continue;
|
|
21137
|
-
const skillDir =
|
|
21138
|
-
const skillMdPath =
|
|
21139
|
-
if (!
|
|
21320
|
+
const skillDir = join5(dir, entry.name);
|
|
21321
|
+
const skillMdPath = join5(skillDir, "SKILL.md");
|
|
21322
|
+
if (!existsSync5(skillMdPath))
|
|
21140
21323
|
continue;
|
|
21141
21324
|
const content = readFileSync2(skillMdPath, "utf-8");
|
|
21142
21325
|
const frontmatter = parseFrontmatter(content);
|
|
@@ -21283,8 +21466,8 @@ function getNestedValue(obj, path6) {
|
|
|
21283
21466
|
}
|
|
21284
21467
|
|
|
21285
21468
|
// src/commands/run.ts
|
|
21286
|
-
import { existsSync as
|
|
21287
|
-
import { join as
|
|
21469
|
+
import { existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, appendFileSync } from "fs";
|
|
21470
|
+
import { join as join6 } from "path";
|
|
21288
21471
|
async function runCommand(slug, options = {}) {
|
|
21289
21472
|
if (!slug || slug.trim() === "") {
|
|
21290
21473
|
console.log(source_default.yellow("Please provide a skill name"));
|
|
@@ -21298,8 +21481,8 @@ async function runCommand(slug, options = {}) {
|
|
|
21298
21481
|
console.log(source_default.dim("Run `skills install " + slug + "` to install it"));
|
|
21299
21482
|
return;
|
|
21300
21483
|
}
|
|
21301
|
-
const skillMdPath =
|
|
21302
|
-
if (!
|
|
21484
|
+
const skillMdPath = join6(skillDir, "SKILL.md");
|
|
21485
|
+
if (!existsSync6(skillMdPath)) {
|
|
21303
21486
|
console.log(source_default.red(`Invalid skill: missing SKILL.md`));
|
|
21304
21487
|
return;
|
|
21305
21488
|
}
|
|
@@ -21334,16 +21517,16 @@ Stderr:`));
|
|
|
21334
21517
|
}
|
|
21335
21518
|
console.log();
|
|
21336
21519
|
console.log(source_default.dim("─".repeat(60)));
|
|
21337
|
-
const exportsDir =
|
|
21338
|
-
const logsDir =
|
|
21339
|
-
if (!
|
|
21340
|
-
|
|
21520
|
+
const exportsDir = join6(skillDir, "exports");
|
|
21521
|
+
const logsDir = join6(skillDir, "logs");
|
|
21522
|
+
if (!existsSync6(exportsDir)) {
|
|
21523
|
+
mkdirSync4(exportsDir, { recursive: true });
|
|
21341
21524
|
}
|
|
21342
|
-
if (!
|
|
21343
|
-
|
|
21525
|
+
if (!existsSync6(logsDir)) {
|
|
21526
|
+
mkdirSync4(logsDir, { recursive: true });
|
|
21344
21527
|
}
|
|
21345
21528
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
21346
|
-
const logFile =
|
|
21529
|
+
const logFile = join6(logsDir, `log_${timestamp}.txt`);
|
|
21347
21530
|
const logContent = [
|
|
21348
21531
|
`Execution ID: ${executionId}`,
|
|
21349
21532
|
`Skill: ${slug}`,
|
|
@@ -21359,21 +21542,21 @@ Stderr:`));
|
|
|
21359
21542
|
${stderr}` : ""
|
|
21360
21543
|
].join(`
|
|
21361
21544
|
`);
|
|
21362
|
-
|
|
21545
|
+
writeFileSync5(logFile, logContent);
|
|
21363
21546
|
const savedExports = [];
|
|
21364
21547
|
if (exportFiles && exportFiles.length > 0) {
|
|
21365
21548
|
for (const file of exportFiles) {
|
|
21366
|
-
const exportPath =
|
|
21549
|
+
const exportPath = join6(exportsDir, `export_${timestamp}_${file.filename}`);
|
|
21367
21550
|
const fileContent = Buffer.from(file.content, "base64");
|
|
21368
|
-
|
|
21551
|
+
writeFileSync5(exportPath, fileContent);
|
|
21369
21552
|
savedExports.push(exportPath);
|
|
21370
21553
|
}
|
|
21371
21554
|
}
|
|
21372
21555
|
if (logFiles && logFiles.length > 0) {
|
|
21373
21556
|
for (const file of logFiles) {
|
|
21374
|
-
const logPath =
|
|
21557
|
+
const logPath = join6(logsDir, `server_${timestamp}_${file.filename}`);
|
|
21375
21558
|
const fileContent = Buffer.from(file.content, "base64");
|
|
21376
|
-
|
|
21559
|
+
writeFileSync5(logPath, fileContent);
|
|
21377
21560
|
}
|
|
21378
21561
|
}
|
|
21379
21562
|
saveExecutionHistory({
|
|
@@ -21406,7 +21589,7 @@ function saveExecutionHistory(entry) {
|
|
|
21406
21589
|
if (!projectOutputDir) {
|
|
21407
21590
|
return;
|
|
21408
21591
|
}
|
|
21409
|
-
const historyFile =
|
|
21592
|
+
const historyFile = join6(projectOutputDir, "execution-history.jsonl");
|
|
21410
21593
|
try {
|
|
21411
21594
|
appendFileSync(historyFile, JSON.stringify(entry) + `
|
|
21412
21595
|
`);
|
|
@@ -21430,12 +21613,12 @@ function findSkillDir(slug, target) {
|
|
|
21430
21613
|
}
|
|
21431
21614
|
searchDirs.push(target === "claude" ? getClaudeSkillsDir() : getCodexSkillsDir());
|
|
21432
21615
|
for (const dir of searchDirs) {
|
|
21433
|
-
const newSkillDir =
|
|
21434
|
-
if (
|
|
21616
|
+
const newSkillDir = join6(dir, `skill-${slug}`);
|
|
21617
|
+
if (existsSync6(newSkillDir)) {
|
|
21435
21618
|
return newSkillDir;
|
|
21436
21619
|
}
|
|
21437
|
-
const oldSkillDir =
|
|
21438
|
-
if (
|
|
21620
|
+
const oldSkillDir = join6(dir, slug);
|
|
21621
|
+
if (existsSync6(oldSkillDir)) {
|
|
21439
21622
|
return oldSkillDir;
|
|
21440
21623
|
}
|
|
21441
21624
|
}
|
|
@@ -21499,8 +21682,8 @@ function parseSkillMd(content) {
|
|
|
21499
21682
|
|
|
21500
21683
|
// src/commands/generate.ts
|
|
21501
21684
|
import { spawn } from "child_process";
|
|
21502
|
-
import { existsSync as
|
|
21503
|
-
import { join as
|
|
21685
|
+
import { existsSync as existsSync7 } from "fs";
|
|
21686
|
+
import { join as join7 } from "path";
|
|
21504
21687
|
import { homedir as homedir3 } from "os";
|
|
21505
21688
|
var MEDIA_TYPES = ["image", "video", "audio", "text"];
|
|
21506
21689
|
var LOCAL_SKILLS = {
|
|
@@ -21509,14 +21692,14 @@ var LOCAL_SKILLS = {
|
|
|
21509
21692
|
audio: "generate-audio"
|
|
21510
21693
|
};
|
|
21511
21694
|
function findLocalSkill(skillName) {
|
|
21512
|
-
const globalDir =
|
|
21513
|
-
if (
|
|
21695
|
+
const globalDir = join7(homedir3(), ".claude", "skills", skillName);
|
|
21696
|
+
if (existsSync7(globalDir)) {
|
|
21514
21697
|
return globalDir;
|
|
21515
21698
|
}
|
|
21516
21699
|
const projectRoot = findProjectRoot();
|
|
21517
21700
|
if (projectRoot) {
|
|
21518
|
-
const projectDir =
|
|
21519
|
-
if (
|
|
21701
|
+
const projectDir = join7(projectRoot, ".claude", "skills", skillName);
|
|
21702
|
+
if (existsSync7(projectDir)) {
|
|
21520
21703
|
return projectDir;
|
|
21521
21704
|
}
|
|
21522
21705
|
}
|
|
@@ -21524,8 +21707,8 @@ function findLocalSkill(skillName) {
|
|
|
21524
21707
|
}
|
|
21525
21708
|
async function runLocalSkill(skillDir, args) {
|
|
21526
21709
|
return new Promise((resolve) => {
|
|
21527
|
-
const skillMdPath =
|
|
21528
|
-
if (!
|
|
21710
|
+
const skillMdPath = join7(skillDir, "SKILL.md");
|
|
21711
|
+
if (!existsSync7(skillMdPath)) {
|
|
21529
21712
|
resolve(false);
|
|
21530
21713
|
return;
|
|
21531
21714
|
}
|
|
@@ -21538,7 +21721,7 @@ async function runLocalSkill(skillDir, args) {
|
|
|
21538
21721
|
const runScript = match[1].trim();
|
|
21539
21722
|
const fullCommand = args.length > 0 ? `${runScript} ${args.join(" ")}` : runScript;
|
|
21540
21723
|
const projectRoot = findProjectRoot();
|
|
21541
|
-
const skillsOutputDir = projectRoot ?
|
|
21724
|
+
const skillsOutputDir = projectRoot ? join7(projectRoot, ".skills") : null;
|
|
21542
21725
|
const child = spawn(fullCommand, {
|
|
21543
21726
|
cwd: skillDir,
|
|
21544
21727
|
shell: true,
|
|
@@ -21602,7 +21785,7 @@ async function generateCommand(mediaType, prompt, options = {}) {
|
|
|
21602
21785
|
console.log();
|
|
21603
21786
|
const spinner = ora("Sending request...").start();
|
|
21604
21787
|
try {
|
|
21605
|
-
const response = await makeApiRequest("/
|
|
21788
|
+
const response = await makeApiRequest("/generate", {
|
|
21606
21789
|
method: "POST",
|
|
21607
21790
|
body: JSON.stringify({
|
|
21608
21791
|
mediaType,
|
|
@@ -21656,7 +21839,7 @@ async function jobsCommand(jobId) {
|
|
|
21656
21839
|
}
|
|
21657
21840
|
const spinner = ora("Fetching jobs...").start();
|
|
21658
21841
|
try {
|
|
21659
|
-
const endpoint = jobId ? `/
|
|
21842
|
+
const endpoint = jobId ? `/jobs/${jobId}` : "/jobs";
|
|
21660
21843
|
const response = await makeApiRequest(endpoint);
|
|
21661
21844
|
if (!response.ok) {
|
|
21662
21845
|
const error = await response.json();
|
|
@@ -21730,18 +21913,122 @@ function formatStatus(status) {
|
|
|
21730
21913
|
}
|
|
21731
21914
|
|
|
21732
21915
|
// src/commands/history.ts
|
|
21733
|
-
import { existsSync as
|
|
21734
|
-
import { join as
|
|
21916
|
+
import { existsSync as existsSync8, readFileSync as readFileSync4, readdirSync as readdirSync2, statSync } from "fs";
|
|
21917
|
+
import { join as join8 } from "path";
|
|
21918
|
+
var indigo3 = source_default.hex("#6366f1");
|
|
21735
21919
|
async function historyCommand(options = {}) {
|
|
21920
|
+
if (options.local) {
|
|
21921
|
+
return localHistoryCommand(options);
|
|
21922
|
+
}
|
|
21923
|
+
const apiKey = getApiKey();
|
|
21924
|
+
if (!apiKey) {
|
|
21925
|
+
console.log(source_default.yellow("Not logged in - showing local history only"));
|
|
21926
|
+
console.log(source_default.dim("Run `skills login` to see remote execution history"));
|
|
21927
|
+
console.log();
|
|
21928
|
+
return localHistoryCommand(options);
|
|
21929
|
+
}
|
|
21930
|
+
const spinner = ora("Fetching execution history...").start();
|
|
21931
|
+
try {
|
|
21932
|
+
const params = new URLSearchParams;
|
|
21933
|
+
if (options.skill)
|
|
21934
|
+
params.set("skill", options.skill);
|
|
21935
|
+
if (options.limit)
|
|
21936
|
+
params.set("limit", String(options.limit));
|
|
21937
|
+
if (options.status)
|
|
21938
|
+
params.set("status", options.status);
|
|
21939
|
+
const query = params.toString();
|
|
21940
|
+
const response = await makeApiRequest(`/me/executions${query ? `?${query}` : ""}`);
|
|
21941
|
+
if (!response.ok) {
|
|
21942
|
+
const error = await response.json().catch(() => ({ error: "Unknown error" }));
|
|
21943
|
+
spinner.fail("Failed to fetch history");
|
|
21944
|
+
console.log(source_default.red(error.error));
|
|
21945
|
+
return;
|
|
21946
|
+
}
|
|
21947
|
+
const result = await response.json();
|
|
21948
|
+
spinner.stop();
|
|
21949
|
+
const { executions, pagination, counts } = result;
|
|
21950
|
+
console.log();
|
|
21951
|
+
console.log(indigo3.bold("Execution History"));
|
|
21952
|
+
console.log(source_default.dim(`Total: ${counts.all} | Completed: ${counts.completed} | Failed: ${counts.failed} | Pending: ${counts.pending}`));
|
|
21953
|
+
console.log();
|
|
21954
|
+
if (executions.length === 0) {
|
|
21955
|
+
console.log(source_default.dim("No executions found"));
|
|
21956
|
+
console.log(source_default.dim("Run a skill with `skills run <name>` to start tracking"));
|
|
21957
|
+
return;
|
|
21958
|
+
}
|
|
21959
|
+
for (const exec of executions) {
|
|
21960
|
+
const date = new Date(exec.createdAt);
|
|
21961
|
+
const dateStr = date.toLocaleDateString();
|
|
21962
|
+
const timeStr = date.toLocaleTimeString();
|
|
21963
|
+
const statusIcon = getStatusIcon(exec.status);
|
|
21964
|
+
const durationStr = exec.durationMs ? formatDuration2(exec.durationMs) : "-";
|
|
21965
|
+
console.log(`${statusIcon} ${source_default.bold(exec.skillSlug || exec.skillName || "Unknown")} ${source_default.dim(`(${dateStr} ${timeStr})`)}`);
|
|
21966
|
+
console.log(` ${source_default.dim("ID:")} ${exec.id.slice(0, 8)}...`);
|
|
21967
|
+
console.log(` ${source_default.dim("Status:")} ${formatStatus2(exec.status)}`);
|
|
21968
|
+
console.log(` ${source_default.dim("Duration:")} ${durationStr}`);
|
|
21969
|
+
if (exec.creditsUsed > 0) {
|
|
21970
|
+
console.log(` ${source_default.dim("Credits:")} ${indigo3(String(exec.creditsUsed))}`);
|
|
21971
|
+
}
|
|
21972
|
+
if (exec.outputType) {
|
|
21973
|
+
console.log(` ${source_default.dim("Output:")} ${exec.outputType}`);
|
|
21974
|
+
}
|
|
21975
|
+
if (exec.exports && exec.exports.length > 0) {
|
|
21976
|
+
console.log(` ${source_default.dim("Exports:")} ${exec.exports.length} file(s)`);
|
|
21977
|
+
if (options.verbose) {
|
|
21978
|
+
for (const exp of exec.exports) {
|
|
21979
|
+
console.log(` ${source_default.dim("→")} ${exp.filename}`);
|
|
21980
|
+
}
|
|
21981
|
+
}
|
|
21982
|
+
}
|
|
21983
|
+
if (exec.errorMessage && options.verbose) {
|
|
21984
|
+
console.log(` ${source_default.dim("Error:")} ${source_default.red(exec.errorMessage)}`);
|
|
21985
|
+
}
|
|
21986
|
+
console.log();
|
|
21987
|
+
}
|
|
21988
|
+
if (pagination.hasMore) {
|
|
21989
|
+
console.log(source_default.dim(`Showing ${executions.length} of ${pagination.total} executions`));
|
|
21990
|
+
console.log(source_default.dim(`Use --limit to see more`));
|
|
21991
|
+
}
|
|
21992
|
+
console.log(source_default.dim("View all at: https://skills.md/dashboard/executions"));
|
|
21993
|
+
} catch (error) {
|
|
21994
|
+
spinner.fail("Request failed");
|
|
21995
|
+
console.log(source_default.red(error instanceof Error ? error.message : "Unknown error"));
|
|
21996
|
+
}
|
|
21997
|
+
}
|
|
21998
|
+
function getStatusIcon(status) {
|
|
21999
|
+
switch (status) {
|
|
22000
|
+
case "completed":
|
|
22001
|
+
return source_default.green("✓");
|
|
22002
|
+
case "failed":
|
|
22003
|
+
return source_default.red("✗");
|
|
22004
|
+
case "pending":
|
|
22005
|
+
return source_default.yellow("◌");
|
|
22006
|
+
default:
|
|
22007
|
+
return source_default.dim("○");
|
|
22008
|
+
}
|
|
22009
|
+
}
|
|
22010
|
+
function formatStatus2(status) {
|
|
22011
|
+
switch (status) {
|
|
22012
|
+
case "completed":
|
|
22013
|
+
return source_default.green("completed");
|
|
22014
|
+
case "failed":
|
|
22015
|
+
return source_default.red("failed");
|
|
22016
|
+
case "pending":
|
|
22017
|
+
return source_default.yellow("pending");
|
|
22018
|
+
default:
|
|
22019
|
+
return source_default.dim(status || "unknown");
|
|
22020
|
+
}
|
|
22021
|
+
}
|
|
22022
|
+
async function localHistoryCommand(options) {
|
|
21736
22023
|
const projectOutputDir = getProjectSkillsOutputDir();
|
|
21737
22024
|
if (!projectOutputDir) {
|
|
21738
22025
|
console.log(source_default.yellow("No project initialized"));
|
|
21739
22026
|
console.log(source_default.dim("Run `skills init` first"));
|
|
21740
22027
|
return;
|
|
21741
22028
|
}
|
|
21742
|
-
const historyFile =
|
|
21743
|
-
if (!
|
|
21744
|
-
console.log(source_default.dim("No execution history found"));
|
|
22029
|
+
const historyFile = join8(projectOutputDir, "execution-history.jsonl");
|
|
22030
|
+
if (!existsSync8(historyFile)) {
|
|
22031
|
+
console.log(source_default.dim("No local execution history found"));
|
|
21745
22032
|
console.log(source_default.dim("Run a skill with `skills run <name>` to start tracking"));
|
|
21746
22033
|
return;
|
|
21747
22034
|
}
|
|
@@ -21765,7 +22052,7 @@ async function historyCommand(options = {}) {
|
|
|
21765
22052
|
return;
|
|
21766
22053
|
}
|
|
21767
22054
|
console.log();
|
|
21768
|
-
console.log(
|
|
22055
|
+
console.log(indigo3.bold("Local Execution History"));
|
|
21769
22056
|
console.log(source_default.dim(`Showing ${entries.length} most recent execution(s)`));
|
|
21770
22057
|
console.log();
|
|
21771
22058
|
for (const entry of entries) {
|
|
@@ -21788,7 +22075,7 @@ async function historyCommand(options = {}) {
|
|
|
21788
22075
|
}
|
|
21789
22076
|
}
|
|
21790
22077
|
}
|
|
21791
|
-
if (options.verbose &&
|
|
22078
|
+
if (options.verbose && existsSync8(entry.logFile)) {
|
|
21792
22079
|
console.log(` ${source_default.dim("Log:")} ${entry.logFile}`);
|
|
21793
22080
|
}
|
|
21794
22081
|
console.log();
|
|
@@ -21797,16 +22084,16 @@ async function historyCommand(options = {}) {
|
|
|
21797
22084
|
async function exportsCommand(slug, options = {}) {
|
|
21798
22085
|
const target = options.target || getDefaultTarget();
|
|
21799
22086
|
const skillsDir = target === "claude" ? getProjectClaudeSkillsDir() : getProjectCodexSkillsDir();
|
|
21800
|
-
let skillDir =
|
|
21801
|
-
if (!
|
|
21802
|
-
skillDir =
|
|
22087
|
+
let skillDir = join8(skillsDir, `skill-${slug}`);
|
|
22088
|
+
if (!existsSync8(skillDir)) {
|
|
22089
|
+
skillDir = join8(skillsDir, slug);
|
|
21803
22090
|
}
|
|
21804
|
-
if (!
|
|
22091
|
+
if (!existsSync8(skillDir)) {
|
|
21805
22092
|
console.log(source_default.red(`Skill "${slug}" not found`));
|
|
21806
22093
|
return;
|
|
21807
22094
|
}
|
|
21808
|
-
const exportsDir =
|
|
21809
|
-
if (!
|
|
22095
|
+
const exportsDir = join8(skillDir, "exports");
|
|
22096
|
+
if (!existsSync8(exportsDir)) {
|
|
21810
22097
|
console.log(source_default.dim(`No exports found for "${slug}"`));
|
|
21811
22098
|
return;
|
|
21812
22099
|
}
|
|
@@ -21816,11 +22103,11 @@ async function exportsCommand(slug, options = {}) {
|
|
|
21816
22103
|
return;
|
|
21817
22104
|
}
|
|
21818
22105
|
console.log();
|
|
21819
|
-
console.log(
|
|
22106
|
+
console.log(indigo3.bold(`Exports for ${slug}`));
|
|
21820
22107
|
console.log(source_default.dim(`Directory: ${exportsDir}`));
|
|
21821
22108
|
console.log();
|
|
21822
22109
|
const fileInfos = files.map((file) => {
|
|
21823
|
-
const filePath =
|
|
22110
|
+
const filePath = join8(exportsDir, file);
|
|
21824
22111
|
const stats = statSync(filePath);
|
|
21825
22112
|
return { file, filePath, mtime: stats.mtime, size: stats.size };
|
|
21826
22113
|
}).sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
|
|
@@ -21837,16 +22124,16 @@ async function exportsCommand(slug, options = {}) {
|
|
|
21837
22124
|
async function logsCommand(slug, options = {}) {
|
|
21838
22125
|
const target = options.target || getDefaultTarget();
|
|
21839
22126
|
const skillsDir = target === "claude" ? getProjectClaudeSkillsDir() : getProjectCodexSkillsDir();
|
|
21840
|
-
let skillDir =
|
|
21841
|
-
if (!
|
|
21842
|
-
skillDir =
|
|
22127
|
+
let skillDir = join8(skillsDir, `skill-${slug}`);
|
|
22128
|
+
if (!existsSync8(skillDir)) {
|
|
22129
|
+
skillDir = join8(skillsDir, slug);
|
|
21843
22130
|
}
|
|
21844
|
-
if (!
|
|
22131
|
+
if (!existsSync8(skillDir)) {
|
|
21845
22132
|
console.log(source_default.red(`Skill "${slug}" not found`));
|
|
21846
22133
|
return;
|
|
21847
22134
|
}
|
|
21848
|
-
const logsDir =
|
|
21849
|
-
if (!
|
|
22135
|
+
const logsDir = join8(skillDir, "logs");
|
|
22136
|
+
if (!existsSync8(logsDir)) {
|
|
21850
22137
|
console.log(source_default.dim(`No logs found for "${slug}"`));
|
|
21851
22138
|
return;
|
|
21852
22139
|
}
|
|
@@ -21857,19 +22144,19 @@ async function logsCommand(slug, options = {}) {
|
|
|
21857
22144
|
}
|
|
21858
22145
|
files.sort().reverse();
|
|
21859
22146
|
const latestLog = files[0];
|
|
21860
|
-
const logPath =
|
|
22147
|
+
const logPath = join8(logsDir, latestLog);
|
|
21861
22148
|
console.log();
|
|
21862
|
-
console.log(
|
|
22149
|
+
console.log(indigo3.bold(`Latest Log for ${slug}`));
|
|
21863
22150
|
console.log(source_default.dim(`File: ${logPath}`));
|
|
21864
22151
|
console.log(source_default.dim("─".repeat(60)));
|
|
21865
22152
|
console.log();
|
|
21866
22153
|
const content = readFileSync4(logPath, "utf-8");
|
|
21867
|
-
const
|
|
22154
|
+
const logLines = content.split(`
|
|
21868
22155
|
`);
|
|
21869
22156
|
const tailLines = options.tail || 50;
|
|
21870
|
-
if (
|
|
22157
|
+
if (logLines.length > tailLines) {
|
|
21871
22158
|
console.log(source_default.dim(`... (showing last ${tailLines} lines)`));
|
|
21872
|
-
console.log(
|
|
22159
|
+
console.log(logLines.slice(-tailLines).join(`
|
|
21873
22160
|
`));
|
|
21874
22161
|
} else {
|
|
21875
22162
|
console.log(content);
|
|
@@ -21899,7 +22186,7 @@ function formatBytes(bytes) {
|
|
|
21899
22186
|
}
|
|
21900
22187
|
|
|
21901
22188
|
// src/commands/marketplace.ts
|
|
21902
|
-
var
|
|
22189
|
+
var indigo4 = source_default.hex("#6366f1");
|
|
21903
22190
|
async function marketplaceCommand(options = {}) {
|
|
21904
22191
|
const spinner = ora("Fetching skills from marketplace...").start();
|
|
21905
22192
|
const limit = options.limit || 20;
|
|
@@ -21922,36 +22209,36 @@ async function marketplaceCommand(options = {}) {
|
|
|
21922
22209
|
return;
|
|
21923
22210
|
}
|
|
21924
22211
|
console.log();
|
|
21925
|
-
console.log(
|
|
22212
|
+
console.log(indigo4.bold(`Skills Marketplace`) + source_default.dim(` (page ${page}/${totalPages}, ${total} total skills)`));
|
|
21926
22213
|
console.log();
|
|
21927
22214
|
for (const skill of skills) {
|
|
21928
|
-
const verified = skill.isVerified ?
|
|
22215
|
+
const verified = skill.isVerified ? indigo4(" ✓") : "";
|
|
21929
22216
|
const downloads = skill.downloadCount > 0 ? source_default.dim(` (${skill.downloadCount} installs)`) : "";
|
|
21930
22217
|
console.log(" " + source_default.bold(skill.name) + verified + source_default.dim(` v${skill.version}`) + downloads);
|
|
21931
22218
|
console.log(" " + source_default.dim(skill.description || "No description"));
|
|
21932
|
-
console.log(" " +
|
|
22219
|
+
console.log(" " + indigo4(`skills install ${skill.slug}`));
|
|
21933
22220
|
console.log();
|
|
21934
22221
|
}
|
|
21935
22222
|
console.log(source_default.dim("─".repeat(50)));
|
|
21936
22223
|
if (totalPages > 1) {
|
|
21937
22224
|
const navHints = [];
|
|
21938
22225
|
if (page > 1) {
|
|
21939
|
-
navHints.push(`${
|
|
22226
|
+
navHints.push(`${indigo4(`skills marketplace -p ${page - 1}`)} for previous`);
|
|
21940
22227
|
}
|
|
21941
22228
|
if (page < totalPages) {
|
|
21942
|
-
navHints.push(`${
|
|
22229
|
+
navHints.push(`${indigo4(`skills marketplace -p ${page + 1}`)} for next`);
|
|
21943
22230
|
}
|
|
21944
22231
|
if (navHints.length > 0) {
|
|
21945
22232
|
console.log(source_default.dim(navHints.join(" | ")));
|
|
21946
22233
|
}
|
|
21947
22234
|
}
|
|
21948
|
-
console.log(source_default.dim(`Run ${
|
|
21949
|
-
console.log(source_default.dim(`Run ${
|
|
22235
|
+
console.log(source_default.dim(`Run ${indigo4("skills install <name>")} to install a skill`));
|
|
22236
|
+
console.log(source_default.dim(`Run ${indigo4("skills search <query>")} to search for specific skills`));
|
|
21950
22237
|
}
|
|
21951
22238
|
|
|
21952
22239
|
// src/commands/feedback.ts
|
|
21953
22240
|
var import_prompts2 = __toESM(require_prompts3(), 1);
|
|
21954
|
-
var
|
|
22241
|
+
var indigo5 = source_default.hex("#6366f1");
|
|
21955
22242
|
var indigoBold = source_default.hex("#6366f1").bold;
|
|
21956
22243
|
async function submitFeedback(type, title, description) {
|
|
21957
22244
|
const spinner = ora("Submitting feedback...").start();
|
|
@@ -21973,7 +22260,7 @@ async function submitFeedback(type, title, description) {
|
|
|
21973
22260
|
}
|
|
21974
22261
|
spinner.succeed("Feedback submitted!");
|
|
21975
22262
|
console.log();
|
|
21976
|
-
console.log(
|
|
22263
|
+
console.log(indigo5(" Thank you for your feedback! \uD83D\uDE4F"));
|
|
21977
22264
|
console.log(source_default.dim(" We'll review it and get back to you if needed."));
|
|
21978
22265
|
return true;
|
|
21979
22266
|
} catch (error) {
|
|
@@ -21989,7 +22276,7 @@ async function feedbackCommand(options = {}) {
|
|
|
21989
22276
|
const apiKey = getApiKey();
|
|
21990
22277
|
if (!apiKey) {
|
|
21991
22278
|
console.log(source_default.yellow("⚠") + " You need to be logged in to submit feedback.");
|
|
21992
|
-
console.log(source_default.dim(" Run ") +
|
|
22279
|
+
console.log(source_default.dim(" Run ") + indigo5("skills login") + source_default.dim(" first."));
|
|
21993
22280
|
console.log();
|
|
21994
22281
|
return;
|
|
21995
22282
|
}
|
|
@@ -22041,10 +22328,384 @@ Feedback cancelled.`));
|
|
|
22041
22328
|
console.log();
|
|
22042
22329
|
}
|
|
22043
22330
|
|
|
22331
|
+
// src/commands/info.ts
|
|
22332
|
+
var indigo6 = source_default.hex("#6366f1");
|
|
22333
|
+
async function infoCommand(name) {
|
|
22334
|
+
const spinner = ora("Fetching skill info...").start();
|
|
22335
|
+
const result = await getSkill(name);
|
|
22336
|
+
if (result.error || !result.data) {
|
|
22337
|
+
spinner.fail("Skill not found");
|
|
22338
|
+
console.error(source_default.red(result.error || "Unknown error"));
|
|
22339
|
+
return;
|
|
22340
|
+
}
|
|
22341
|
+
spinner.stop();
|
|
22342
|
+
const skill = result.data;
|
|
22343
|
+
console.log();
|
|
22344
|
+
console.log(indigo6.bold(skill.name) + (skill.isVerified ? indigo6(" ✓") : ""));
|
|
22345
|
+
console.log(source_default.dim(`v${skill.version}`));
|
|
22346
|
+
console.log();
|
|
22347
|
+
if (skill.description) {
|
|
22348
|
+
console.log(skill.description);
|
|
22349
|
+
console.log();
|
|
22350
|
+
}
|
|
22351
|
+
console.log(source_default.dim("─".repeat(50)));
|
|
22352
|
+
console.log();
|
|
22353
|
+
const details = [
|
|
22354
|
+
["Slug", skill.slug],
|
|
22355
|
+
["Version", skill.version],
|
|
22356
|
+
["Category", skill.category?.name || "Uncategorized"],
|
|
22357
|
+
["License", skill.license || "Not specified"],
|
|
22358
|
+
["Downloads", skill.downloadCount.toLocaleString()],
|
|
22359
|
+
["Verified", skill.isVerified ? source_default.green("Yes") : "No"],
|
|
22360
|
+
["Remote Execution", skill.isRemoteExecution ? source_default.green("Yes") : "No"],
|
|
22361
|
+
["Credits/Run", (skill.creditsPerExecution ?? 0) > 0 ? indigo6(String(skill.creditsPerExecution)) : source_default.green("Free")]
|
|
22362
|
+
];
|
|
22363
|
+
for (const [label, value] of details) {
|
|
22364
|
+
console.log(` ${source_default.dim(label.padEnd(18))} ${value}`);
|
|
22365
|
+
}
|
|
22366
|
+
if (skill.tags && skill.tags.length > 0) {
|
|
22367
|
+
console.log();
|
|
22368
|
+
console.log(` ${source_default.dim("Tags".padEnd(18))} ${skill.tags.map((t) => source_default.dim(`#${t.name}`)).join(" ")}`);
|
|
22369
|
+
}
|
|
22370
|
+
console.log();
|
|
22371
|
+
console.log(source_default.dim("─".repeat(50)));
|
|
22372
|
+
console.log();
|
|
22373
|
+
console.log(` ${source_default.dim("Install:")} ${indigo6(`skills install ${skill.slug}`)}`);
|
|
22374
|
+
if (skill.isRemoteExecution) {
|
|
22375
|
+
console.log(` ${source_default.dim("Run:")} ${indigo6(`skills run ${skill.slug}`)}`);
|
|
22376
|
+
}
|
|
22377
|
+
console.log();
|
|
22378
|
+
}
|
|
22379
|
+
|
|
22380
|
+
// src/commands/credits.ts
|
|
22381
|
+
var indigo7 = source_default.hex("#6366f1");
|
|
22382
|
+
async function creditsCommand() {
|
|
22383
|
+
const apiKey = getApiKey();
|
|
22384
|
+
if (!apiKey) {
|
|
22385
|
+
console.log(source_default.yellow("Not logged in"));
|
|
22386
|
+
console.log(source_default.dim("Run `skills login` to authenticate"));
|
|
22387
|
+
return;
|
|
22388
|
+
}
|
|
22389
|
+
const spinner = ora("Fetching credits...").start();
|
|
22390
|
+
const result = await getCurrentUser();
|
|
22391
|
+
if (result.error || !result.data) {
|
|
22392
|
+
spinner.fail("Failed to fetch credits");
|
|
22393
|
+
console.error(source_default.red(result.error || "Unknown error"));
|
|
22394
|
+
return;
|
|
22395
|
+
}
|
|
22396
|
+
spinner.stop();
|
|
22397
|
+
const { creditsBalance, plan, tenantName } = result.data;
|
|
22398
|
+
console.log();
|
|
22399
|
+
console.log(indigo7.bold("Credits Balance"));
|
|
22400
|
+
console.log();
|
|
22401
|
+
console.log(" " + indigo7.bold(creditsBalance.toLocaleString()) + " credits");
|
|
22402
|
+
console.log();
|
|
22403
|
+
console.log(source_default.dim("─".repeat(30)));
|
|
22404
|
+
console.log();
|
|
22405
|
+
console.log(" Plan: " + source_default.bold(plan));
|
|
22406
|
+
console.log(" Org: " + (tenantName || source_default.dim("Personal")));
|
|
22407
|
+
console.log();
|
|
22408
|
+
console.log(source_default.dim("Purchase more at https://skills.md/billing"));
|
|
22409
|
+
console.log();
|
|
22410
|
+
}
|
|
22411
|
+
|
|
22412
|
+
// src/commands/update.ts
|
|
22413
|
+
import { existsSync as existsSync9, readdirSync as readdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync6 } from "fs";
|
|
22414
|
+
import { join as join9 } from "path";
|
|
22415
|
+
var indigo8 = source_default.hex("#6366f1");
|
|
22416
|
+
function parseFrontmatter2(content) {
|
|
22417
|
+
const result = {};
|
|
22418
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
22419
|
+
if (!match)
|
|
22420
|
+
return result;
|
|
22421
|
+
const frontmatter = match[1];
|
|
22422
|
+
const lines = frontmatter.split(`
|
|
22423
|
+
`);
|
|
22424
|
+
for (const line of lines) {
|
|
22425
|
+
const colonIndex = line.indexOf(":");
|
|
22426
|
+
if (colonIndex === -1)
|
|
22427
|
+
continue;
|
|
22428
|
+
const key = line.slice(0, colonIndex).trim();
|
|
22429
|
+
let value = line.slice(colonIndex + 1).trim();
|
|
22430
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
22431
|
+
value = value.slice(1, -1);
|
|
22432
|
+
}
|
|
22433
|
+
result[key] = value;
|
|
22434
|
+
}
|
|
22435
|
+
return result;
|
|
22436
|
+
}
|
|
22437
|
+
async function updateCommand(skillName, options = {}) {
|
|
22438
|
+
const target = options.target ?? getDefaultTarget();
|
|
22439
|
+
const skillsDir = target === "claude" ? getClaudeSkillsDir() : getCodexSkillsDir();
|
|
22440
|
+
if (!existsSync9(skillsDir)) {
|
|
22441
|
+
console.log(source_default.dim("No skills installed"));
|
|
22442
|
+
return;
|
|
22443
|
+
}
|
|
22444
|
+
const entries = readdirSync3(skillsDir, { withFileTypes: true });
|
|
22445
|
+
const installedSkills = [];
|
|
22446
|
+
for (const entry of entries) {
|
|
22447
|
+
if (!entry.isDirectory() || !entry.name.startsWith("skill-"))
|
|
22448
|
+
continue;
|
|
22449
|
+
const skillDir = join9(skillsDir, entry.name);
|
|
22450
|
+
const skillMdPath = join9(skillDir, "SKILL.md");
|
|
22451
|
+
if (!existsSync9(skillMdPath))
|
|
22452
|
+
continue;
|
|
22453
|
+
const content = readFileSync5(skillMdPath, "utf-8");
|
|
22454
|
+
const frontmatter = parseFrontmatter2(content);
|
|
22455
|
+
const slug = entry.name.replace("skill-", "");
|
|
22456
|
+
if (skillName && slug !== skillName && frontmatter.name !== skillName) {
|
|
22457
|
+
continue;
|
|
22458
|
+
}
|
|
22459
|
+
installedSkills.push({
|
|
22460
|
+
slug,
|
|
22461
|
+
name: frontmatter.name || slug,
|
|
22462
|
+
version: frontmatter.version || "unknown",
|
|
22463
|
+
dir: skillDir
|
|
22464
|
+
});
|
|
22465
|
+
}
|
|
22466
|
+
if (installedSkills.length === 0) {
|
|
22467
|
+
if (skillName) {
|
|
22468
|
+
console.log(source_default.yellow(`Skill "${skillName}" not found`));
|
|
22469
|
+
} else {
|
|
22470
|
+
console.log(source_default.dim("No skills installed"));
|
|
22471
|
+
}
|
|
22472
|
+
return;
|
|
22473
|
+
}
|
|
22474
|
+
console.log();
|
|
22475
|
+
console.log(indigo8.bold("Updating Skills"));
|
|
22476
|
+
console.log();
|
|
22477
|
+
let updated = 0;
|
|
22478
|
+
let upToDate = 0;
|
|
22479
|
+
let failed = 0;
|
|
22480
|
+
for (const skill of installedSkills) {
|
|
22481
|
+
const spinner = ora(`Checking ${skill.name}...`).start();
|
|
22482
|
+
try {
|
|
22483
|
+
const result = await installSkill(skill.slug);
|
|
22484
|
+
if (result.error || !result.data) {
|
|
22485
|
+
spinner.fail(`${skill.name}: Failed to fetch`);
|
|
22486
|
+
failed++;
|
|
22487
|
+
continue;
|
|
22488
|
+
}
|
|
22489
|
+
const newVersion = result.data.version;
|
|
22490
|
+
const currentVersion = skill.version;
|
|
22491
|
+
if (newVersion !== currentVersion) {
|
|
22492
|
+
writeFileSync6(join9(skill.dir, "SKILL.md"), result.data.skillMdContent);
|
|
22493
|
+
spinner.succeed(`${skill.name}: ${source_default.dim(currentVersion)} ${indigo8("→")} ${indigo8(newVersion)}`);
|
|
22494
|
+
updated++;
|
|
22495
|
+
} else {
|
|
22496
|
+
spinner.succeed(`${skill.name}: ${source_default.dim(`v${currentVersion}`)} ${source_default.green("(up to date)")}`);
|
|
22497
|
+
upToDate++;
|
|
22498
|
+
}
|
|
22499
|
+
} catch (error) {
|
|
22500
|
+
spinner.fail(`${skill.name}: Error`);
|
|
22501
|
+
failed++;
|
|
22502
|
+
}
|
|
22503
|
+
}
|
|
22504
|
+
console.log();
|
|
22505
|
+
console.log(source_default.dim("─".repeat(40)));
|
|
22506
|
+
console.log();
|
|
22507
|
+
const summary = [];
|
|
22508
|
+
if (updated > 0)
|
|
22509
|
+
summary.push(indigo8(`${updated} updated`));
|
|
22510
|
+
if (upToDate > 0)
|
|
22511
|
+
summary.push(source_default.green(`${upToDate} up to date`));
|
|
22512
|
+
if (failed > 0)
|
|
22513
|
+
summary.push(source_default.red(`${failed} failed`));
|
|
22514
|
+
console.log(" " + summary.join(", "));
|
|
22515
|
+
console.log();
|
|
22516
|
+
}
|
|
22517
|
+
|
|
22518
|
+
// src/commands/upgrade.ts
|
|
22519
|
+
import { execSync } from "child_process";
|
|
22520
|
+
var indigo9 = source_default.hex("#6366f1");
|
|
22521
|
+
var PACKAGE_NAME = "@hasnatools/skills";
|
|
22522
|
+
async function upgradeCommand() {
|
|
22523
|
+
console.log();
|
|
22524
|
+
console.log(indigo9.bold("Upgrade Skills CLI"));
|
|
22525
|
+
console.log();
|
|
22526
|
+
const currentVersion = process.env.npm_package_version || getInstalledVersion();
|
|
22527
|
+
console.log(` Current: ${source_default.dim(`v${currentVersion}`)}`);
|
|
22528
|
+
const spinner = ora("Checking for updates...").start();
|
|
22529
|
+
try {
|
|
22530
|
+
const latestVersion = execSync(`npm view ${PACKAGE_NAME} version`, {
|
|
22531
|
+
encoding: "utf-8",
|
|
22532
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
22533
|
+
}).trim();
|
|
22534
|
+
if (latestVersion === currentVersion) {
|
|
22535
|
+
spinner.succeed("Already on latest version");
|
|
22536
|
+
console.log();
|
|
22537
|
+
return;
|
|
22538
|
+
}
|
|
22539
|
+
spinner.text = `Upgrading to v${latestVersion}...`;
|
|
22540
|
+
const pm = detectPackageManager();
|
|
22541
|
+
const upgradeCmd = pm === "bun" ? `bun install -g ${PACKAGE_NAME}@latest` : pm === "yarn" ? `yarn global add ${PACKAGE_NAME}@latest` : pm === "pnpm" ? `pnpm add -g ${PACKAGE_NAME}@latest` : `npm install -g ${PACKAGE_NAME}@latest`;
|
|
22542
|
+
execSync(upgradeCmd, {
|
|
22543
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
22544
|
+
});
|
|
22545
|
+
spinner.succeed(`Upgraded to ${indigo9(`v${latestVersion}`)}`);
|
|
22546
|
+
console.log();
|
|
22547
|
+
console.log(source_default.dim(" Restart your terminal to use the new version"));
|
|
22548
|
+
console.log();
|
|
22549
|
+
} catch (error) {
|
|
22550
|
+
spinner.fail("Upgrade failed");
|
|
22551
|
+
console.log();
|
|
22552
|
+
console.log(source_default.red(" " + (error instanceof Error ? error.message : "Unknown error")));
|
|
22553
|
+
console.log();
|
|
22554
|
+
console.log(source_default.dim(" Try manually: npm install -g " + PACKAGE_NAME + "@latest"));
|
|
22555
|
+
console.log();
|
|
22556
|
+
}
|
|
22557
|
+
}
|
|
22558
|
+
function getInstalledVersion() {
|
|
22559
|
+
try {
|
|
22560
|
+
const output = execSync(`npm list -g ${PACKAGE_NAME} --depth=0 --json`, {
|
|
22561
|
+
encoding: "utf-8",
|
|
22562
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
22563
|
+
});
|
|
22564
|
+
const data = JSON.parse(output);
|
|
22565
|
+
return data.dependencies?.[PACKAGE_NAME]?.version || "unknown";
|
|
22566
|
+
} catch {
|
|
22567
|
+
return "unknown";
|
|
22568
|
+
}
|
|
22569
|
+
}
|
|
22570
|
+
function detectPackageManager() {
|
|
22571
|
+
try {
|
|
22572
|
+
execSync("bun --version", { stdio: ["pipe", "pipe", "pipe"] });
|
|
22573
|
+
return "bun";
|
|
22574
|
+
} catch {}
|
|
22575
|
+
try {
|
|
22576
|
+
execSync("pnpm --version", { stdio: ["pipe", "pipe", "pipe"] });
|
|
22577
|
+
return "pnpm";
|
|
22578
|
+
} catch {}
|
|
22579
|
+
try {
|
|
22580
|
+
execSync("yarn --version", { stdio: ["pipe", "pipe", "pipe"] });
|
|
22581
|
+
return "yarn";
|
|
22582
|
+
} catch {}
|
|
22583
|
+
return "npm";
|
|
22584
|
+
}
|
|
22585
|
+
|
|
22586
|
+
// src/commands/doctor.ts
|
|
22587
|
+
import { existsSync as existsSync10 } from "fs";
|
|
22588
|
+
import { execSync as execSync2 } from "child_process";
|
|
22589
|
+
var indigo10 = source_default.hex("#6366f1");
|
|
22590
|
+
async function doctorCommand() {
|
|
22591
|
+
console.log();
|
|
22592
|
+
console.log(indigo10.bold("Skills Doctor"));
|
|
22593
|
+
console.log(source_default.dim("Checking your environment..."));
|
|
22594
|
+
console.log();
|
|
22595
|
+
const results = [];
|
|
22596
|
+
const spinner1 = ora("Checking Node.js...").start();
|
|
22597
|
+
try {
|
|
22598
|
+
const nodeVersion = process.version;
|
|
22599
|
+
const major = parseInt(nodeVersion.slice(1).split(".")[0], 10);
|
|
22600
|
+
if (major >= 18) {
|
|
22601
|
+
spinner1.succeed(`Node.js ${nodeVersion}`);
|
|
22602
|
+
results.push({ name: "Node.js", status: "ok", message: nodeVersion });
|
|
22603
|
+
} else {
|
|
22604
|
+
spinner1.warn(`Node.js ${nodeVersion} (v18+ recommended)`);
|
|
22605
|
+
results.push({ name: "Node.js", status: "warn", message: `${nodeVersion} (v18+ recommended)` });
|
|
22606
|
+
}
|
|
22607
|
+
} catch {
|
|
22608
|
+
spinner1.fail("Node.js not found");
|
|
22609
|
+
results.push({ name: "Node.js", status: "error", message: "Not found" });
|
|
22610
|
+
}
|
|
22611
|
+
const spinner2 = ora("Checking Bun...").start();
|
|
22612
|
+
try {
|
|
22613
|
+
const bunVersion = execSync2("bun --version", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
22614
|
+
spinner2.succeed(`Bun v${bunVersion}`);
|
|
22615
|
+
results.push({ name: "Bun", status: "ok", message: `v${bunVersion}` });
|
|
22616
|
+
} catch {
|
|
22617
|
+
spinner2.info("Bun not installed (optional)");
|
|
22618
|
+
results.push({ name: "Bun", status: "warn", message: "Not installed (optional)" });
|
|
22619
|
+
}
|
|
22620
|
+
const spinner3 = ora("Checking API connectivity...").start();
|
|
22621
|
+
const endpoint = getApiEndpoint();
|
|
22622
|
+
try {
|
|
22623
|
+
const response = await fetch(`${endpoint}/status`, {
|
|
22624
|
+
method: "GET",
|
|
22625
|
+
signal: AbortSignal.timeout(1e4)
|
|
22626
|
+
});
|
|
22627
|
+
if (response.ok) {
|
|
22628
|
+
spinner3.succeed(`API reachable (${endpoint})`);
|
|
22629
|
+
results.push({ name: "API", status: "ok", message: endpoint });
|
|
22630
|
+
} else {
|
|
22631
|
+
spinner3.warn(`API returned ${response.status}`);
|
|
22632
|
+
results.push({ name: "API", status: "warn", message: `Status ${response.status}` });
|
|
22633
|
+
}
|
|
22634
|
+
} catch (error) {
|
|
22635
|
+
spinner3.fail("API unreachable");
|
|
22636
|
+
results.push({ name: "API", status: "error", message: error instanceof Error ? error.message : "Connection failed" });
|
|
22637
|
+
}
|
|
22638
|
+
const spinner4 = ora("Checking authentication...").start();
|
|
22639
|
+
const apiKey = getApiKey();
|
|
22640
|
+
if (apiKey) {
|
|
22641
|
+
try {
|
|
22642
|
+
const response = await fetch(`${endpoint}/me`, {
|
|
22643
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
22644
|
+
signal: AbortSignal.timeout(1e4)
|
|
22645
|
+
});
|
|
22646
|
+
if (response.ok) {
|
|
22647
|
+
const data = await response.json();
|
|
22648
|
+
spinner4.succeed(`Authenticated as ${data.email}`);
|
|
22649
|
+
results.push({ name: "Auth", status: "ok", message: data.email });
|
|
22650
|
+
} else if (response.status === 401) {
|
|
22651
|
+
spinner4.warn("API key invalid or expired");
|
|
22652
|
+
results.push({ name: "Auth", status: "warn", message: "Invalid/expired key" });
|
|
22653
|
+
} else {
|
|
22654
|
+
spinner4.warn(`Auth check returned ${response.status}`);
|
|
22655
|
+
results.push({ name: "Auth", status: "warn", message: `Status ${response.status}` });
|
|
22656
|
+
}
|
|
22657
|
+
} catch {
|
|
22658
|
+
spinner4.warn("Could not verify authentication");
|
|
22659
|
+
results.push({ name: "Auth", status: "warn", message: "Verification failed" });
|
|
22660
|
+
}
|
|
22661
|
+
} else {
|
|
22662
|
+
spinner4.info("Not logged in");
|
|
22663
|
+
results.push({ name: "Auth", status: "warn", message: "Not logged in" });
|
|
22664
|
+
}
|
|
22665
|
+
const spinner5 = ora("Checking Claude skills directory...").start();
|
|
22666
|
+
const claudeDir = getClaudeSkillsDir();
|
|
22667
|
+
if (existsSync10(claudeDir)) {
|
|
22668
|
+
spinner5.succeed(`Claude skills: ${claudeDir}`);
|
|
22669
|
+
results.push({ name: "Claude Dir", status: "ok", message: claudeDir });
|
|
22670
|
+
} else {
|
|
22671
|
+
spinner5.info("Claude skills directory not found");
|
|
22672
|
+
results.push({ name: "Claude Dir", status: "warn", message: "Not found (will be created on install)" });
|
|
22673
|
+
}
|
|
22674
|
+
const spinner6 = ora("Checking Codex skills directory...").start();
|
|
22675
|
+
const codexDir = getCodexSkillsDir();
|
|
22676
|
+
if (existsSync10(codexDir)) {
|
|
22677
|
+
spinner6.succeed(`Codex skills: ${codexDir}`);
|
|
22678
|
+
results.push({ name: "Codex Dir", status: "ok", message: codexDir });
|
|
22679
|
+
} else {
|
|
22680
|
+
spinner6.info("Codex skills directory not found");
|
|
22681
|
+
results.push({ name: "Codex Dir", status: "warn", message: "Not found (will be created on install)" });
|
|
22682
|
+
}
|
|
22683
|
+
console.log();
|
|
22684
|
+
console.log(source_default.dim("─".repeat(50)));
|
|
22685
|
+
console.log();
|
|
22686
|
+
const okCount = results.filter((r) => r.status === "ok").length;
|
|
22687
|
+
const warnCount = results.filter((r) => r.status === "warn").length;
|
|
22688
|
+
const errorCount = results.filter((r) => r.status === "error").length;
|
|
22689
|
+
if (errorCount > 0) {
|
|
22690
|
+
console.log(source_default.red.bold(` ${errorCount} error(s) found`));
|
|
22691
|
+
}
|
|
22692
|
+
if (warnCount > 0) {
|
|
22693
|
+
console.log(source_default.yellow(` ${warnCount} warning(s)`));
|
|
22694
|
+
}
|
|
22695
|
+
if (okCount === results.length) {
|
|
22696
|
+
console.log(indigo10.bold(" All checks passed!"));
|
|
22697
|
+
}
|
|
22698
|
+
console.log();
|
|
22699
|
+
if (!apiKey) {
|
|
22700
|
+
console.log(source_default.dim(" Run `skills login` to authenticate"));
|
|
22701
|
+
}
|
|
22702
|
+
console.log();
|
|
22703
|
+
}
|
|
22704
|
+
|
|
22044
22705
|
// src/index.ts
|
|
22045
|
-
var
|
|
22706
|
+
var indigo11 = source_default.hex("#6366f1");
|
|
22046
22707
|
var program2 = new Command;
|
|
22047
|
-
program2.name("skills").description("CLI for skills.md - AI Agent Skills Marketplace").version("0.1.
|
|
22708
|
+
program2.name("skills").description("CLI for skills.md - AI Agent Skills Marketplace").version("0.1.10");
|
|
22048
22709
|
program2.command("init").description("Initialize skills.md in current project").option("-f, --force", "Force re-initialization (removes existing .skills/)").action((options) => {
|
|
22049
22710
|
initCommand({ force: options.force });
|
|
22050
22711
|
});
|
|
@@ -22073,6 +22734,12 @@ program2.command("uninstall <name>").alias("remove").description("Uninstall a sk
|
|
|
22073
22734
|
target: options.target
|
|
22074
22735
|
});
|
|
22075
22736
|
});
|
|
22737
|
+
program2.command("download <name>").alias("dl").description("Download a skill with full source code (if available)").option("-l, --local", "Download to current project instead of global").option("-t, --target <target>", "Target platform (claude, codex)").action((name, options) => {
|
|
22738
|
+
downloadCommand(name, {
|
|
22739
|
+
local: options.local,
|
|
22740
|
+
target: options.target
|
|
22741
|
+
});
|
|
22742
|
+
});
|
|
22076
22743
|
program2.command("list").alias("ls").description("List installed skills").option("-g, --global", "List only global skills").option("-t, --target <target>", "Target platform (claude, codex)").option("-r, --remote", "List remote installations").action((options) => {
|
|
22077
22744
|
listCommand({
|
|
22078
22745
|
global: options.global,
|
|
@@ -22101,11 +22768,13 @@ program2.command("generate <mediaType> <prompt>").alias("gen").description("Gene
|
|
|
22101
22768
|
});
|
|
22102
22769
|
});
|
|
22103
22770
|
program2.command("jobs [jobId]").description("List generation jobs or view job details").action(jobsCommand);
|
|
22104
|
-
program2.command("history").description("View execution history").option("-s, --skill <name>", "Filter by skill name").option("-n, --limit <number>", "Limit number of entries", "20").option("-v, --verbose", "Show detailed output").action((options) => {
|
|
22771
|
+
program2.command("history").description("View execution history").option("-s, --skill <name>", "Filter by skill name").option("-n, --limit <number>", "Limit number of entries", "20").option("-v, --verbose", "Show detailed output").option("--status <status>", "Filter by status (completed, failed, pending)").option("-l, --local", "Show local history only (skip API)").action((options) => {
|
|
22105
22772
|
historyCommand({
|
|
22106
22773
|
skill: options.skill,
|
|
22107
22774
|
limit: parseInt(options.limit, 10),
|
|
22108
|
-
verbose: options.verbose
|
|
22775
|
+
verbose: options.verbose,
|
|
22776
|
+
status: options.status,
|
|
22777
|
+
local: options.local
|
|
22109
22778
|
});
|
|
22110
22779
|
});
|
|
22111
22780
|
program2.command("exports <skill>").description("View exported files for a skill").option("-t, --target <target>", "Target platform (claude, codex)").action((skill, options) => {
|
|
@@ -22124,8 +22793,15 @@ program2.command("feedback").description("Submit feedback, bug reports, or featu
|
|
|
22124
22793
|
message: options.message
|
|
22125
22794
|
});
|
|
22126
22795
|
});
|
|
22796
|
+
program2.command("info <name>").description("Show detailed information about a skill").action(infoCommand);
|
|
22797
|
+
program2.command("credits").description("Check your credits balance").action(creditsCommand);
|
|
22798
|
+
program2.command("update [skill]").description("Update installed skills to latest versions").option("-t, --target <target>", "Target platform (claude, codex)").action((skill, options) => {
|
|
22799
|
+
updateCommand(skill, { target: options.target });
|
|
22800
|
+
});
|
|
22801
|
+
program2.command("upgrade").description("Upgrade the Skills CLI to the latest version").action(upgradeCommand);
|
|
22802
|
+
program2.command("doctor").description("Check your environment and diagnose issues").action(doctorCommand);
|
|
22127
22803
|
program2.addHelpText("after", `
|
|
22128
|
-
${
|
|
22804
|
+
${indigo11.bold("Examples:")}
|
|
22129
22805
|
${source_default.dim("# Initialize in current project")}
|
|
22130
22806
|
$ skills init
|
|
22131
22807
|
|
|
@@ -22153,6 +22829,8 @@ ${indigo3.bold("Examples:")}
|
|
|
22153
22829
|
${source_default.dim("# View execution history")}
|
|
22154
22830
|
$ skills history
|
|
22155
22831
|
$ skills history --skill image-generator
|
|
22832
|
+
$ skills history --status completed
|
|
22833
|
+
$ skills history --local
|
|
22156
22834
|
|
|
22157
22835
|
${source_default.dim("# View exports for a skill")}
|
|
22158
22836
|
$ skills exports image-generator
|
|
@@ -22163,7 +22841,22 @@ ${indigo3.bold("Examples:")}
|
|
|
22163
22841
|
${source_default.dim("# Submit feedback")}
|
|
22164
22842
|
$ skills feedback
|
|
22165
22843
|
|
|
22166
|
-
${
|
|
22167
|
-
$
|
|
22844
|
+
${source_default.dim("# Get skill info")}
|
|
22845
|
+
$ skills info code-review
|
|
22846
|
+
|
|
22847
|
+
${source_default.dim("# Check credits balance")}
|
|
22848
|
+
$ skills credits
|
|
22849
|
+
|
|
22850
|
+
${source_default.dim("# Update installed skills")}
|
|
22851
|
+
$ skills update
|
|
22852
|
+
|
|
22853
|
+
${source_default.dim("# Upgrade CLI")}
|
|
22854
|
+
$ skills upgrade
|
|
22855
|
+
|
|
22856
|
+
${source_default.dim("# Check environment")}
|
|
22857
|
+
$ skills doctor
|
|
22858
|
+
|
|
22859
|
+
${indigo11.bold("Documentation:")}
|
|
22860
|
+
${indigo11("https://skills.md/docs")}
|
|
22168
22861
|
`);
|
|
22169
22862
|
program2.parse();
|