@hasnatools/skills 0.1.7 → 0.1.9
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 +699 -96
- 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,
|
|
@@ -21730,8 +21913,8 @@ 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";
|
|
21735
21918
|
async function historyCommand(options = {}) {
|
|
21736
21919
|
const projectOutputDir = getProjectSkillsOutputDir();
|
|
21737
21920
|
if (!projectOutputDir) {
|
|
@@ -21739,8 +21922,8 @@ async function historyCommand(options = {}) {
|
|
|
21739
21922
|
console.log(source_default.dim("Run `skills init` first"));
|
|
21740
21923
|
return;
|
|
21741
21924
|
}
|
|
21742
|
-
const historyFile =
|
|
21743
|
-
if (!
|
|
21925
|
+
const historyFile = join8(projectOutputDir, "execution-history.jsonl");
|
|
21926
|
+
if (!existsSync8(historyFile)) {
|
|
21744
21927
|
console.log(source_default.dim("No execution history found"));
|
|
21745
21928
|
console.log(source_default.dim("Run a skill with `skills run <name>` to start tracking"));
|
|
21746
21929
|
return;
|
|
@@ -21788,7 +21971,7 @@ async function historyCommand(options = {}) {
|
|
|
21788
21971
|
}
|
|
21789
21972
|
}
|
|
21790
21973
|
}
|
|
21791
|
-
if (options.verbose &&
|
|
21974
|
+
if (options.verbose && existsSync8(entry.logFile)) {
|
|
21792
21975
|
console.log(` ${source_default.dim("Log:")} ${entry.logFile}`);
|
|
21793
21976
|
}
|
|
21794
21977
|
console.log();
|
|
@@ -21797,16 +21980,16 @@ async function historyCommand(options = {}) {
|
|
|
21797
21980
|
async function exportsCommand(slug, options = {}) {
|
|
21798
21981
|
const target = options.target || getDefaultTarget();
|
|
21799
21982
|
const skillsDir = target === "claude" ? getProjectClaudeSkillsDir() : getProjectCodexSkillsDir();
|
|
21800
|
-
let skillDir =
|
|
21801
|
-
if (!
|
|
21802
|
-
skillDir =
|
|
21983
|
+
let skillDir = join8(skillsDir, `skill-${slug}`);
|
|
21984
|
+
if (!existsSync8(skillDir)) {
|
|
21985
|
+
skillDir = join8(skillsDir, slug);
|
|
21803
21986
|
}
|
|
21804
|
-
if (!
|
|
21987
|
+
if (!existsSync8(skillDir)) {
|
|
21805
21988
|
console.log(source_default.red(`Skill "${slug}" not found`));
|
|
21806
21989
|
return;
|
|
21807
21990
|
}
|
|
21808
|
-
const exportsDir =
|
|
21809
|
-
if (!
|
|
21991
|
+
const exportsDir = join8(skillDir, "exports");
|
|
21992
|
+
if (!existsSync8(exportsDir)) {
|
|
21810
21993
|
console.log(source_default.dim(`No exports found for "${slug}"`));
|
|
21811
21994
|
return;
|
|
21812
21995
|
}
|
|
@@ -21820,7 +22003,7 @@ async function exportsCommand(slug, options = {}) {
|
|
|
21820
22003
|
console.log(source_default.dim(`Directory: ${exportsDir}`));
|
|
21821
22004
|
console.log();
|
|
21822
22005
|
const fileInfos = files.map((file) => {
|
|
21823
|
-
const filePath =
|
|
22006
|
+
const filePath = join8(exportsDir, file);
|
|
21824
22007
|
const stats = statSync(filePath);
|
|
21825
22008
|
return { file, filePath, mtime: stats.mtime, size: stats.size };
|
|
21826
22009
|
}).sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
|
|
@@ -21837,16 +22020,16 @@ async function exportsCommand(slug, options = {}) {
|
|
|
21837
22020
|
async function logsCommand(slug, options = {}) {
|
|
21838
22021
|
const target = options.target || getDefaultTarget();
|
|
21839
22022
|
const skillsDir = target === "claude" ? getProjectClaudeSkillsDir() : getProjectCodexSkillsDir();
|
|
21840
|
-
let skillDir =
|
|
21841
|
-
if (!
|
|
21842
|
-
skillDir =
|
|
22023
|
+
let skillDir = join8(skillsDir, `skill-${slug}`);
|
|
22024
|
+
if (!existsSync8(skillDir)) {
|
|
22025
|
+
skillDir = join8(skillsDir, slug);
|
|
21843
22026
|
}
|
|
21844
|
-
if (!
|
|
22027
|
+
if (!existsSync8(skillDir)) {
|
|
21845
22028
|
console.log(source_default.red(`Skill "${slug}" not found`));
|
|
21846
22029
|
return;
|
|
21847
22030
|
}
|
|
21848
|
-
const logsDir =
|
|
21849
|
-
if (!
|
|
22031
|
+
const logsDir = join8(skillDir, "logs");
|
|
22032
|
+
if (!existsSync8(logsDir)) {
|
|
21850
22033
|
console.log(source_default.dim(`No logs found for "${slug}"`));
|
|
21851
22034
|
return;
|
|
21852
22035
|
}
|
|
@@ -21857,7 +22040,7 @@ async function logsCommand(slug, options = {}) {
|
|
|
21857
22040
|
}
|
|
21858
22041
|
files.sort().reverse();
|
|
21859
22042
|
const latestLog = files[0];
|
|
21860
|
-
const logPath =
|
|
22043
|
+
const logPath = join8(logsDir, latestLog);
|
|
21861
22044
|
console.log();
|
|
21862
22045
|
console.log(source_default.bold(`Latest Log for ${slug}`));
|
|
21863
22046
|
console.log(source_default.dim(`File: ${logPath}`));
|
|
@@ -21899,7 +22082,7 @@ function formatBytes(bytes) {
|
|
|
21899
22082
|
}
|
|
21900
22083
|
|
|
21901
22084
|
// src/commands/marketplace.ts
|
|
21902
|
-
var
|
|
22085
|
+
var indigo3 = source_default.hex("#6366f1");
|
|
21903
22086
|
async function marketplaceCommand(options = {}) {
|
|
21904
22087
|
const spinner = ora("Fetching skills from marketplace...").start();
|
|
21905
22088
|
const limit = options.limit || 20;
|
|
@@ -21922,37 +22105,66 @@ async function marketplaceCommand(options = {}) {
|
|
|
21922
22105
|
return;
|
|
21923
22106
|
}
|
|
21924
22107
|
console.log();
|
|
21925
|
-
console.log(
|
|
22108
|
+
console.log(indigo3.bold(`Skills Marketplace`) + source_default.dim(` (page ${page}/${totalPages}, ${total} total skills)`));
|
|
21926
22109
|
console.log();
|
|
21927
22110
|
for (const skill of skills) {
|
|
21928
|
-
const verified = skill.isVerified ?
|
|
22111
|
+
const verified = skill.isVerified ? indigo3(" ✓") : "";
|
|
21929
22112
|
const downloads = skill.downloadCount > 0 ? source_default.dim(` (${skill.downloadCount} installs)`) : "";
|
|
21930
22113
|
console.log(" " + source_default.bold(skill.name) + verified + source_default.dim(` v${skill.version}`) + downloads);
|
|
21931
22114
|
console.log(" " + source_default.dim(skill.description || "No description"));
|
|
21932
|
-
console.log(" " +
|
|
22115
|
+
console.log(" " + indigo3(`skills install ${skill.slug}`));
|
|
21933
22116
|
console.log();
|
|
21934
22117
|
}
|
|
21935
22118
|
console.log(source_default.dim("─".repeat(50)));
|
|
21936
22119
|
if (totalPages > 1) {
|
|
21937
22120
|
const navHints = [];
|
|
21938
22121
|
if (page > 1) {
|
|
21939
|
-
navHints.push(`${
|
|
22122
|
+
navHints.push(`${indigo3(`skills marketplace -p ${page - 1}`)} for previous`);
|
|
21940
22123
|
}
|
|
21941
22124
|
if (page < totalPages) {
|
|
21942
|
-
navHints.push(`${
|
|
22125
|
+
navHints.push(`${indigo3(`skills marketplace -p ${page + 1}`)} for next`);
|
|
21943
22126
|
}
|
|
21944
22127
|
if (navHints.length > 0) {
|
|
21945
22128
|
console.log(source_default.dim(navHints.join(" | ")));
|
|
21946
22129
|
}
|
|
21947
22130
|
}
|
|
21948
|
-
console.log(source_default.dim(`Run ${
|
|
21949
|
-
console.log(source_default.dim(`Run ${
|
|
22131
|
+
console.log(source_default.dim(`Run ${indigo3("skills install <name>")} to install a skill`));
|
|
22132
|
+
console.log(source_default.dim(`Run ${indigo3("skills search <query>")} to search for specific skills`));
|
|
21950
22133
|
}
|
|
21951
22134
|
|
|
21952
22135
|
// src/commands/feedback.ts
|
|
21953
22136
|
var import_prompts2 = __toESM(require_prompts3(), 1);
|
|
21954
|
-
var
|
|
22137
|
+
var indigo4 = source_default.hex("#6366f1");
|
|
21955
22138
|
var indigoBold = source_default.hex("#6366f1").bold;
|
|
22139
|
+
async function submitFeedback(type, title, description) {
|
|
22140
|
+
const spinner = ora("Submitting feedback...").start();
|
|
22141
|
+
try {
|
|
22142
|
+
const res = await makeApiRequest("/feedback", {
|
|
22143
|
+
method: "POST",
|
|
22144
|
+
body: JSON.stringify({
|
|
22145
|
+
type,
|
|
22146
|
+
title,
|
|
22147
|
+
description,
|
|
22148
|
+
page: "cli"
|
|
22149
|
+
})
|
|
22150
|
+
});
|
|
22151
|
+
if (!res.ok) {
|
|
22152
|
+
const data = await res.json();
|
|
22153
|
+
spinner.fail("Failed to submit feedback");
|
|
22154
|
+
console.log(source_default.red(" " + (data.error || "Unknown error")));
|
|
22155
|
+
return false;
|
|
22156
|
+
}
|
|
22157
|
+
spinner.succeed("Feedback submitted!");
|
|
22158
|
+
console.log();
|
|
22159
|
+
console.log(indigo4(" Thank you for your feedback! \uD83D\uDE4F"));
|
|
22160
|
+
console.log(source_default.dim(" We'll review it and get back to you if needed."));
|
|
22161
|
+
return true;
|
|
22162
|
+
} catch (error) {
|
|
22163
|
+
spinner.fail("Failed to submit feedback");
|
|
22164
|
+
console.log(source_default.red(" " + (error instanceof Error ? error.message : "Network error")));
|
|
22165
|
+
return false;
|
|
22166
|
+
}
|
|
22167
|
+
}
|
|
21956
22168
|
async function feedbackCommand(options = {}) {
|
|
21957
22169
|
console.log();
|
|
21958
22170
|
console.log(indigoBold("\uD83D\uDCDD Submit Feedback"));
|
|
@@ -21960,7 +22172,18 @@ async function feedbackCommand(options = {}) {
|
|
|
21960
22172
|
const apiKey = getApiKey();
|
|
21961
22173
|
if (!apiKey) {
|
|
21962
22174
|
console.log(source_default.yellow("⚠") + " You need to be logged in to submit feedback.");
|
|
21963
|
-
console.log(source_default.dim(" Run ") +
|
|
22175
|
+
console.log(source_default.dim(" Run ") + indigo4("skills login") + source_default.dim(" first."));
|
|
22176
|
+
console.log();
|
|
22177
|
+
return;
|
|
22178
|
+
}
|
|
22179
|
+
if (options.type && options.title && options.message) {
|
|
22180
|
+
const validTypes = ["bug", "feature", "improvement", "other"];
|
|
22181
|
+
if (!validTypes.includes(options.type)) {
|
|
22182
|
+
console.log(source_default.red(" Invalid type. Must be one of: " + validTypes.join(", ")));
|
|
22183
|
+
console.log();
|
|
22184
|
+
return;
|
|
22185
|
+
}
|
|
22186
|
+
await submitFeedback(options.type, options.title, options.message);
|
|
21964
22187
|
console.log();
|
|
21965
22188
|
return;
|
|
21966
22189
|
}
|
|
@@ -21975,7 +22198,7 @@ async function feedbackCommand(options = {}) {
|
|
|
21975
22198
|
{ title: "\uD83D\uDCA1 Improvement", value: "improvement" },
|
|
21976
22199
|
{ title: "\uD83D\uDCAC Other", value: "other" }
|
|
21977
22200
|
],
|
|
21978
|
-
initial: options.type === "bug" ? 0 : options.type === "feature" ? 1 : 0
|
|
22201
|
+
initial: options.type === "bug" ? 0 : options.type === "feature" ? 1 : options.type === "improvement" ? 2 : options.type === "other" ? 3 : 0
|
|
21979
22202
|
},
|
|
21980
22203
|
{
|
|
21981
22204
|
type: "text",
|
|
@@ -21997,38 +22220,388 @@ async function feedbackCommand(options = {}) {
|
|
|
21997
22220
|
Feedback cancelled.`));
|
|
21998
22221
|
return;
|
|
21999
22222
|
}
|
|
22000
|
-
|
|
22001
|
-
|
|
22002
|
-
|
|
22003
|
-
|
|
22004
|
-
|
|
22005
|
-
|
|
22006
|
-
|
|
22007
|
-
|
|
22008
|
-
|
|
22009
|
-
|
|
22223
|
+
await submitFeedback(response.type, response.title, response.description);
|
|
22224
|
+
console.log();
|
|
22225
|
+
}
|
|
22226
|
+
|
|
22227
|
+
// src/commands/info.ts
|
|
22228
|
+
var indigo5 = source_default.hex("#6366f1");
|
|
22229
|
+
async function infoCommand(name) {
|
|
22230
|
+
const spinner = ora("Fetching skill info...").start();
|
|
22231
|
+
const result = await getSkill(name);
|
|
22232
|
+
if (result.error || !result.data) {
|
|
22233
|
+
spinner.fail("Skill not found");
|
|
22234
|
+
console.error(source_default.red(result.error || "Unknown error"));
|
|
22235
|
+
return;
|
|
22236
|
+
}
|
|
22237
|
+
spinner.stop();
|
|
22238
|
+
const skill = result.data;
|
|
22239
|
+
console.log();
|
|
22240
|
+
console.log(indigo5.bold(skill.name) + (skill.isVerified ? indigo5(" ✓") : ""));
|
|
22241
|
+
console.log(source_default.dim(`v${skill.version}`));
|
|
22242
|
+
console.log();
|
|
22243
|
+
if (skill.description) {
|
|
22244
|
+
console.log(skill.description);
|
|
22245
|
+
console.log();
|
|
22246
|
+
}
|
|
22247
|
+
console.log(source_default.dim("─".repeat(50)));
|
|
22248
|
+
console.log();
|
|
22249
|
+
const details = [
|
|
22250
|
+
["Slug", skill.slug],
|
|
22251
|
+
["Version", skill.version],
|
|
22252
|
+
["Category", skill.category?.name || "Uncategorized"],
|
|
22253
|
+
["License", skill.license || "Not specified"],
|
|
22254
|
+
["Downloads", skill.downloadCount.toLocaleString()],
|
|
22255
|
+
["Verified", skill.isVerified ? source_default.green("Yes") : "No"],
|
|
22256
|
+
["Remote Execution", skill.isRemoteExecution ? source_default.green("Yes") : "No"],
|
|
22257
|
+
["Credits/Run", (skill.creditsPerExecution ?? 0) > 0 ? indigo5(String(skill.creditsPerExecution)) : source_default.green("Free")]
|
|
22258
|
+
];
|
|
22259
|
+
for (const [label, value] of details) {
|
|
22260
|
+
console.log(` ${source_default.dim(label.padEnd(18))} ${value}`);
|
|
22261
|
+
}
|
|
22262
|
+
if (skill.tags && skill.tags.length > 0) {
|
|
22263
|
+
console.log();
|
|
22264
|
+
console.log(` ${source_default.dim("Tags".padEnd(18))} ${skill.tags.map((t) => source_default.dim(`#${t.name}`)).join(" ")}`);
|
|
22265
|
+
}
|
|
22266
|
+
console.log();
|
|
22267
|
+
console.log(source_default.dim("─".repeat(50)));
|
|
22268
|
+
console.log();
|
|
22269
|
+
console.log(` ${source_default.dim("Install:")} ${indigo5(`skills install ${skill.slug}`)}`);
|
|
22270
|
+
if (skill.isRemoteExecution) {
|
|
22271
|
+
console.log(` ${source_default.dim("Run:")} ${indigo5(`skills run ${skill.slug}`)}`);
|
|
22272
|
+
}
|
|
22273
|
+
console.log();
|
|
22274
|
+
}
|
|
22275
|
+
|
|
22276
|
+
// src/commands/credits.ts
|
|
22277
|
+
var indigo6 = source_default.hex("#6366f1");
|
|
22278
|
+
async function creditsCommand() {
|
|
22279
|
+
const apiKey = getApiKey();
|
|
22280
|
+
if (!apiKey) {
|
|
22281
|
+
console.log(source_default.yellow("Not logged in"));
|
|
22282
|
+
console.log(source_default.dim("Run `skills login` to authenticate"));
|
|
22283
|
+
return;
|
|
22284
|
+
}
|
|
22285
|
+
const spinner = ora("Fetching credits...").start();
|
|
22286
|
+
const result = await getCurrentUser();
|
|
22287
|
+
if (result.error || !result.data) {
|
|
22288
|
+
spinner.fail("Failed to fetch credits");
|
|
22289
|
+
console.error(source_default.red(result.error || "Unknown error"));
|
|
22290
|
+
return;
|
|
22291
|
+
}
|
|
22292
|
+
spinner.stop();
|
|
22293
|
+
const { creditsBalance, plan, tenantName } = result.data;
|
|
22294
|
+
console.log();
|
|
22295
|
+
console.log(indigo6.bold("Credits Balance"));
|
|
22296
|
+
console.log();
|
|
22297
|
+
console.log(" " + indigo6.bold(creditsBalance.toLocaleString()) + " credits");
|
|
22298
|
+
console.log();
|
|
22299
|
+
console.log(source_default.dim("─".repeat(30)));
|
|
22300
|
+
console.log();
|
|
22301
|
+
console.log(" Plan: " + source_default.bold(plan));
|
|
22302
|
+
console.log(" Org: " + (tenantName || source_default.dim("Personal")));
|
|
22303
|
+
console.log();
|
|
22304
|
+
console.log(source_default.dim("Purchase more at https://skills.md/billing"));
|
|
22305
|
+
console.log();
|
|
22306
|
+
}
|
|
22307
|
+
|
|
22308
|
+
// src/commands/update.ts
|
|
22309
|
+
import { existsSync as existsSync9, readdirSync as readdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync6 } from "fs";
|
|
22310
|
+
import { join as join9 } from "path";
|
|
22311
|
+
var indigo7 = source_default.hex("#6366f1");
|
|
22312
|
+
function parseFrontmatter2(content) {
|
|
22313
|
+
const result = {};
|
|
22314
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
22315
|
+
if (!match)
|
|
22316
|
+
return result;
|
|
22317
|
+
const frontmatter = match[1];
|
|
22318
|
+
const lines = frontmatter.split(`
|
|
22319
|
+
`);
|
|
22320
|
+
for (const line of lines) {
|
|
22321
|
+
const colonIndex = line.indexOf(":");
|
|
22322
|
+
if (colonIndex === -1)
|
|
22323
|
+
continue;
|
|
22324
|
+
const key = line.slice(0, colonIndex).trim();
|
|
22325
|
+
let value = line.slice(colonIndex + 1).trim();
|
|
22326
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
22327
|
+
value = value.slice(1, -1);
|
|
22328
|
+
}
|
|
22329
|
+
result[key] = value;
|
|
22330
|
+
}
|
|
22331
|
+
return result;
|
|
22332
|
+
}
|
|
22333
|
+
async function updateCommand(skillName, options = {}) {
|
|
22334
|
+
const target = options.target ?? getDefaultTarget();
|
|
22335
|
+
const skillsDir = target === "claude" ? getClaudeSkillsDir() : getCodexSkillsDir();
|
|
22336
|
+
if (!existsSync9(skillsDir)) {
|
|
22337
|
+
console.log(source_default.dim("No skills installed"));
|
|
22338
|
+
return;
|
|
22339
|
+
}
|
|
22340
|
+
const entries = readdirSync3(skillsDir, { withFileTypes: true });
|
|
22341
|
+
const installedSkills = [];
|
|
22342
|
+
for (const entry of entries) {
|
|
22343
|
+
if (!entry.isDirectory() || !entry.name.startsWith("skill-"))
|
|
22344
|
+
continue;
|
|
22345
|
+
const skillDir = join9(skillsDir, entry.name);
|
|
22346
|
+
const skillMdPath = join9(skillDir, "SKILL.md");
|
|
22347
|
+
if (!existsSync9(skillMdPath))
|
|
22348
|
+
continue;
|
|
22349
|
+
const content = readFileSync5(skillMdPath, "utf-8");
|
|
22350
|
+
const frontmatter = parseFrontmatter2(content);
|
|
22351
|
+
const slug = entry.name.replace("skill-", "");
|
|
22352
|
+
if (skillName && slug !== skillName && frontmatter.name !== skillName) {
|
|
22353
|
+
continue;
|
|
22354
|
+
}
|
|
22355
|
+
installedSkills.push({
|
|
22356
|
+
slug,
|
|
22357
|
+
name: frontmatter.name || slug,
|
|
22358
|
+
version: frontmatter.version || "unknown",
|
|
22359
|
+
dir: skillDir
|
|
22010
22360
|
});
|
|
22011
|
-
|
|
22012
|
-
|
|
22013
|
-
|
|
22014
|
-
console.log(source_default.
|
|
22361
|
+
}
|
|
22362
|
+
if (installedSkills.length === 0) {
|
|
22363
|
+
if (skillName) {
|
|
22364
|
+
console.log(source_default.yellow(`Skill "${skillName}" not found`));
|
|
22365
|
+
} else {
|
|
22366
|
+
console.log(source_default.dim("No skills installed"));
|
|
22367
|
+
}
|
|
22368
|
+
return;
|
|
22369
|
+
}
|
|
22370
|
+
console.log();
|
|
22371
|
+
console.log(indigo7.bold("Updating Skills"));
|
|
22372
|
+
console.log();
|
|
22373
|
+
let updated = 0;
|
|
22374
|
+
let upToDate = 0;
|
|
22375
|
+
let failed = 0;
|
|
22376
|
+
for (const skill of installedSkills) {
|
|
22377
|
+
const spinner = ora(`Checking ${skill.name}...`).start();
|
|
22378
|
+
try {
|
|
22379
|
+
const result = await installSkill(skill.slug);
|
|
22380
|
+
if (result.error || !result.data) {
|
|
22381
|
+
spinner.fail(`${skill.name}: Failed to fetch`);
|
|
22382
|
+
failed++;
|
|
22383
|
+
continue;
|
|
22384
|
+
}
|
|
22385
|
+
const newVersion = result.data.version;
|
|
22386
|
+
const currentVersion = skill.version;
|
|
22387
|
+
if (newVersion !== currentVersion) {
|
|
22388
|
+
writeFileSync6(join9(skill.dir, "SKILL.md"), result.data.skillMdContent);
|
|
22389
|
+
spinner.succeed(`${skill.name}: ${source_default.dim(currentVersion)} ${indigo7("→")} ${indigo7(newVersion)}`);
|
|
22390
|
+
updated++;
|
|
22391
|
+
} else {
|
|
22392
|
+
spinner.succeed(`${skill.name}: ${source_default.dim(`v${currentVersion}`)} ${source_default.green("(up to date)")}`);
|
|
22393
|
+
upToDate++;
|
|
22394
|
+
}
|
|
22395
|
+
} catch (error) {
|
|
22396
|
+
spinner.fail(`${skill.name}: Error`);
|
|
22397
|
+
failed++;
|
|
22398
|
+
}
|
|
22399
|
+
}
|
|
22400
|
+
console.log();
|
|
22401
|
+
console.log(source_default.dim("─".repeat(40)));
|
|
22402
|
+
console.log();
|
|
22403
|
+
const summary = [];
|
|
22404
|
+
if (updated > 0)
|
|
22405
|
+
summary.push(indigo7(`${updated} updated`));
|
|
22406
|
+
if (upToDate > 0)
|
|
22407
|
+
summary.push(source_default.green(`${upToDate} up to date`));
|
|
22408
|
+
if (failed > 0)
|
|
22409
|
+
summary.push(source_default.red(`${failed} failed`));
|
|
22410
|
+
console.log(" " + summary.join(", "));
|
|
22411
|
+
console.log();
|
|
22412
|
+
}
|
|
22413
|
+
|
|
22414
|
+
// src/commands/upgrade.ts
|
|
22415
|
+
import { execSync } from "child_process";
|
|
22416
|
+
var indigo8 = source_default.hex("#6366f1");
|
|
22417
|
+
var PACKAGE_NAME = "@hasnatools/skills";
|
|
22418
|
+
async function upgradeCommand() {
|
|
22419
|
+
console.log();
|
|
22420
|
+
console.log(indigo8.bold("Upgrade Skills CLI"));
|
|
22421
|
+
console.log();
|
|
22422
|
+
const currentVersion = process.env.npm_package_version || getInstalledVersion();
|
|
22423
|
+
console.log(` Current: ${source_default.dim(`v${currentVersion}`)}`);
|
|
22424
|
+
const spinner = ora("Checking for updates...").start();
|
|
22425
|
+
try {
|
|
22426
|
+
const latestVersion = execSync(`npm view ${PACKAGE_NAME} version`, {
|
|
22427
|
+
encoding: "utf-8",
|
|
22428
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
22429
|
+
}).trim();
|
|
22430
|
+
if (latestVersion === currentVersion) {
|
|
22431
|
+
spinner.succeed("Already on latest version");
|
|
22432
|
+
console.log();
|
|
22015
22433
|
return;
|
|
22016
22434
|
}
|
|
22017
|
-
spinner.
|
|
22435
|
+
spinner.text = `Upgrading to v${latestVersion}...`;
|
|
22436
|
+
const pm = detectPackageManager();
|
|
22437
|
+
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`;
|
|
22438
|
+
execSync(upgradeCmd, {
|
|
22439
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
22440
|
+
});
|
|
22441
|
+
spinner.succeed(`Upgraded to ${indigo8(`v${latestVersion}`)}`);
|
|
22442
|
+
console.log();
|
|
22443
|
+
console.log(source_default.dim(" Restart your terminal to use the new version"));
|
|
22018
22444
|
console.log();
|
|
22019
|
-
console.log(indigo2(" Thank you for your feedback! \uD83D\uDE4F"));
|
|
22020
|
-
console.log(source_default.dim(" We'll review it and get back to you if needed."));
|
|
22021
22445
|
} catch (error) {
|
|
22022
|
-
spinner.fail("
|
|
22023
|
-
console.log(
|
|
22446
|
+
spinner.fail("Upgrade failed");
|
|
22447
|
+
console.log();
|
|
22448
|
+
console.log(source_default.red(" " + (error instanceof Error ? error.message : "Unknown error")));
|
|
22449
|
+
console.log();
|
|
22450
|
+
console.log(source_default.dim(" Try manually: npm install -g " + PACKAGE_NAME + "@latest"));
|
|
22451
|
+
console.log();
|
|
22452
|
+
}
|
|
22453
|
+
}
|
|
22454
|
+
function getInstalledVersion() {
|
|
22455
|
+
try {
|
|
22456
|
+
const output = execSync(`npm list -g ${PACKAGE_NAME} --depth=0 --json`, {
|
|
22457
|
+
encoding: "utf-8",
|
|
22458
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
22459
|
+
});
|
|
22460
|
+
const data = JSON.parse(output);
|
|
22461
|
+
return data.dependencies?.[PACKAGE_NAME]?.version || "unknown";
|
|
22462
|
+
} catch {
|
|
22463
|
+
return "unknown";
|
|
22464
|
+
}
|
|
22465
|
+
}
|
|
22466
|
+
function detectPackageManager() {
|
|
22467
|
+
try {
|
|
22468
|
+
execSync("bun --version", { stdio: ["pipe", "pipe", "pipe"] });
|
|
22469
|
+
return "bun";
|
|
22470
|
+
} catch {}
|
|
22471
|
+
try {
|
|
22472
|
+
execSync("pnpm --version", { stdio: ["pipe", "pipe", "pipe"] });
|
|
22473
|
+
return "pnpm";
|
|
22474
|
+
} catch {}
|
|
22475
|
+
try {
|
|
22476
|
+
execSync("yarn --version", { stdio: ["pipe", "pipe", "pipe"] });
|
|
22477
|
+
return "yarn";
|
|
22478
|
+
} catch {}
|
|
22479
|
+
return "npm";
|
|
22480
|
+
}
|
|
22481
|
+
|
|
22482
|
+
// src/commands/doctor.ts
|
|
22483
|
+
import { existsSync as existsSync10 } from "fs";
|
|
22484
|
+
import { execSync as execSync2 } from "child_process";
|
|
22485
|
+
var indigo9 = source_default.hex("#6366f1");
|
|
22486
|
+
async function doctorCommand() {
|
|
22487
|
+
console.log();
|
|
22488
|
+
console.log(indigo9.bold("Skills Doctor"));
|
|
22489
|
+
console.log(source_default.dim("Checking your environment..."));
|
|
22490
|
+
console.log();
|
|
22491
|
+
const results = [];
|
|
22492
|
+
const spinner1 = ora("Checking Node.js...").start();
|
|
22493
|
+
try {
|
|
22494
|
+
const nodeVersion = process.version;
|
|
22495
|
+
const major = parseInt(nodeVersion.slice(1).split(".")[0], 10);
|
|
22496
|
+
if (major >= 18) {
|
|
22497
|
+
spinner1.succeed(`Node.js ${nodeVersion}`);
|
|
22498
|
+
results.push({ name: "Node.js", status: "ok", message: nodeVersion });
|
|
22499
|
+
} else {
|
|
22500
|
+
spinner1.warn(`Node.js ${nodeVersion} (v18+ recommended)`);
|
|
22501
|
+
results.push({ name: "Node.js", status: "warn", message: `${nodeVersion} (v18+ recommended)` });
|
|
22502
|
+
}
|
|
22503
|
+
} catch {
|
|
22504
|
+
spinner1.fail("Node.js not found");
|
|
22505
|
+
results.push({ name: "Node.js", status: "error", message: "Not found" });
|
|
22506
|
+
}
|
|
22507
|
+
const spinner2 = ora("Checking Bun...").start();
|
|
22508
|
+
try {
|
|
22509
|
+
const bunVersion = execSync2("bun --version", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
22510
|
+
spinner2.succeed(`Bun v${bunVersion}`);
|
|
22511
|
+
results.push({ name: "Bun", status: "ok", message: `v${bunVersion}` });
|
|
22512
|
+
} catch {
|
|
22513
|
+
spinner2.info("Bun not installed (optional)");
|
|
22514
|
+
results.push({ name: "Bun", status: "warn", message: "Not installed (optional)" });
|
|
22515
|
+
}
|
|
22516
|
+
const spinner3 = ora("Checking API connectivity...").start();
|
|
22517
|
+
const endpoint = getApiEndpoint();
|
|
22518
|
+
try {
|
|
22519
|
+
const response = await fetch(`${endpoint}/status`, {
|
|
22520
|
+
method: "GET",
|
|
22521
|
+
signal: AbortSignal.timeout(1e4)
|
|
22522
|
+
});
|
|
22523
|
+
if (response.ok) {
|
|
22524
|
+
spinner3.succeed(`API reachable (${endpoint})`);
|
|
22525
|
+
results.push({ name: "API", status: "ok", message: endpoint });
|
|
22526
|
+
} else {
|
|
22527
|
+
spinner3.warn(`API returned ${response.status}`);
|
|
22528
|
+
results.push({ name: "API", status: "warn", message: `Status ${response.status}` });
|
|
22529
|
+
}
|
|
22530
|
+
} catch (error) {
|
|
22531
|
+
spinner3.fail("API unreachable");
|
|
22532
|
+
results.push({ name: "API", status: "error", message: error instanceof Error ? error.message : "Connection failed" });
|
|
22533
|
+
}
|
|
22534
|
+
const spinner4 = ora("Checking authentication...").start();
|
|
22535
|
+
const apiKey = getApiKey();
|
|
22536
|
+
if (apiKey) {
|
|
22537
|
+
try {
|
|
22538
|
+
const response = await fetch(`${endpoint}/me`, {
|
|
22539
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
22540
|
+
signal: AbortSignal.timeout(1e4)
|
|
22541
|
+
});
|
|
22542
|
+
if (response.ok) {
|
|
22543
|
+
const data = await response.json();
|
|
22544
|
+
spinner4.succeed(`Authenticated as ${data.email}`);
|
|
22545
|
+
results.push({ name: "Auth", status: "ok", message: data.email });
|
|
22546
|
+
} else if (response.status === 401) {
|
|
22547
|
+
spinner4.warn("API key invalid or expired");
|
|
22548
|
+
results.push({ name: "Auth", status: "warn", message: "Invalid/expired key" });
|
|
22549
|
+
} else {
|
|
22550
|
+
spinner4.warn(`Auth check returned ${response.status}`);
|
|
22551
|
+
results.push({ name: "Auth", status: "warn", message: `Status ${response.status}` });
|
|
22552
|
+
}
|
|
22553
|
+
} catch {
|
|
22554
|
+
spinner4.warn("Could not verify authentication");
|
|
22555
|
+
results.push({ name: "Auth", status: "warn", message: "Verification failed" });
|
|
22556
|
+
}
|
|
22557
|
+
} else {
|
|
22558
|
+
spinner4.info("Not logged in");
|
|
22559
|
+
results.push({ name: "Auth", status: "warn", message: "Not logged in" });
|
|
22560
|
+
}
|
|
22561
|
+
const spinner5 = ora("Checking Claude skills directory...").start();
|
|
22562
|
+
const claudeDir = getClaudeSkillsDir();
|
|
22563
|
+
if (existsSync10(claudeDir)) {
|
|
22564
|
+
spinner5.succeed(`Claude skills: ${claudeDir}`);
|
|
22565
|
+
results.push({ name: "Claude Dir", status: "ok", message: claudeDir });
|
|
22566
|
+
} else {
|
|
22567
|
+
spinner5.info("Claude skills directory not found");
|
|
22568
|
+
results.push({ name: "Claude Dir", status: "warn", message: "Not found (will be created on install)" });
|
|
22569
|
+
}
|
|
22570
|
+
const spinner6 = ora("Checking Codex skills directory...").start();
|
|
22571
|
+
const codexDir = getCodexSkillsDir();
|
|
22572
|
+
if (existsSync10(codexDir)) {
|
|
22573
|
+
spinner6.succeed(`Codex skills: ${codexDir}`);
|
|
22574
|
+
results.push({ name: "Codex Dir", status: "ok", message: codexDir });
|
|
22575
|
+
} else {
|
|
22576
|
+
spinner6.info("Codex skills directory not found");
|
|
22577
|
+
results.push({ name: "Codex Dir", status: "warn", message: "Not found (will be created on install)" });
|
|
22578
|
+
}
|
|
22579
|
+
console.log();
|
|
22580
|
+
console.log(source_default.dim("─".repeat(50)));
|
|
22581
|
+
console.log();
|
|
22582
|
+
const okCount = results.filter((r) => r.status === "ok").length;
|
|
22583
|
+
const warnCount = results.filter((r) => r.status === "warn").length;
|
|
22584
|
+
const errorCount = results.filter((r) => r.status === "error").length;
|
|
22585
|
+
if (errorCount > 0) {
|
|
22586
|
+
console.log(source_default.red.bold(` ${errorCount} error(s) found`));
|
|
22587
|
+
}
|
|
22588
|
+
if (warnCount > 0) {
|
|
22589
|
+
console.log(source_default.yellow(` ${warnCount} warning(s)`));
|
|
22590
|
+
}
|
|
22591
|
+
if (okCount === results.length) {
|
|
22592
|
+
console.log(indigo9.bold(" All checks passed!"));
|
|
22593
|
+
}
|
|
22594
|
+
console.log();
|
|
22595
|
+
if (!apiKey) {
|
|
22596
|
+
console.log(source_default.dim(" Run `skills login` to authenticate"));
|
|
22024
22597
|
}
|
|
22025
22598
|
console.log();
|
|
22026
22599
|
}
|
|
22027
22600
|
|
|
22028
22601
|
// src/index.ts
|
|
22029
|
-
var
|
|
22602
|
+
var indigo10 = source_default.hex("#6366f1");
|
|
22030
22603
|
var program2 = new Command;
|
|
22031
|
-
program2.name("skills").description("CLI for skills.md - AI Agent Skills Marketplace").version("0.1.
|
|
22604
|
+
program2.name("skills").description("CLI for skills.md - AI Agent Skills Marketplace").version("0.1.9");
|
|
22032
22605
|
program2.command("init").description("Initialize skills.md in current project").option("-f, --force", "Force re-initialization (removes existing .skills/)").action((options) => {
|
|
22033
22606
|
initCommand({ force: options.force });
|
|
22034
22607
|
});
|
|
@@ -22057,6 +22630,12 @@ program2.command("uninstall <name>").alias("remove").description("Uninstall a sk
|
|
|
22057
22630
|
target: options.target
|
|
22058
22631
|
});
|
|
22059
22632
|
});
|
|
22633
|
+
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) => {
|
|
22634
|
+
downloadCommand(name, {
|
|
22635
|
+
local: options.local,
|
|
22636
|
+
target: options.target
|
|
22637
|
+
});
|
|
22638
|
+
});
|
|
22060
22639
|
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) => {
|
|
22061
22640
|
listCommand({
|
|
22062
22641
|
global: options.global,
|
|
@@ -22101,13 +22680,22 @@ program2.command("logs <skill>").description("View execution logs for a skill").
|
|
|
22101
22680
|
tail: parseInt(options.tail, 10)
|
|
22102
22681
|
});
|
|
22103
22682
|
});
|
|
22104
|
-
program2.command("feedback").description("Submit feedback, bug reports, or feature requests").option("-t, --type <type>", "Feedback type (bug, feature, improvement, other)").action((options) => {
|
|
22683
|
+
program2.command("feedback").description("Submit feedback, bug reports, or feature requests").option("-t, --type <type>", "Feedback type (bug, feature, improvement, other)").option("--title <title>", "Feedback title (required for non-interactive mode)").option("-m, --message <message>", "Feedback description (required for non-interactive mode)").action((options) => {
|
|
22105
22684
|
feedbackCommand({
|
|
22106
|
-
type: options.type
|
|
22685
|
+
type: options.type,
|
|
22686
|
+
title: options.title,
|
|
22687
|
+
message: options.message
|
|
22107
22688
|
});
|
|
22108
22689
|
});
|
|
22690
|
+
program2.command("info <name>").description("Show detailed information about a skill").action(infoCommand);
|
|
22691
|
+
program2.command("credits").description("Check your credits balance").action(creditsCommand);
|
|
22692
|
+
program2.command("update [skill]").description("Update installed skills to latest versions").option("-t, --target <target>", "Target platform (claude, codex)").action((skill, options) => {
|
|
22693
|
+
updateCommand(skill, { target: options.target });
|
|
22694
|
+
});
|
|
22695
|
+
program2.command("upgrade").description("Upgrade the Skills CLI to the latest version").action(upgradeCommand);
|
|
22696
|
+
program2.command("doctor").description("Check your environment and diagnose issues").action(doctorCommand);
|
|
22109
22697
|
program2.addHelpText("after", `
|
|
22110
|
-
${
|
|
22698
|
+
${indigo10.bold("Examples:")}
|
|
22111
22699
|
${source_default.dim("# Initialize in current project")}
|
|
22112
22700
|
$ skills init
|
|
22113
22701
|
|
|
@@ -22145,7 +22733,22 @@ ${indigo3.bold("Examples:")}
|
|
|
22145
22733
|
${source_default.dim("# Submit feedback")}
|
|
22146
22734
|
$ skills feedback
|
|
22147
22735
|
|
|
22148
|
-
${
|
|
22149
|
-
$
|
|
22736
|
+
${source_default.dim("# Get skill info")}
|
|
22737
|
+
$ skills info code-review
|
|
22738
|
+
|
|
22739
|
+
${source_default.dim("# Check credits balance")}
|
|
22740
|
+
$ skills credits
|
|
22741
|
+
|
|
22742
|
+
${source_default.dim("# Update installed skills")}
|
|
22743
|
+
$ skills update
|
|
22744
|
+
|
|
22745
|
+
${source_default.dim("# Upgrade CLI")}
|
|
22746
|
+
$ skills upgrade
|
|
22747
|
+
|
|
22748
|
+
${source_default.dim("# Check environment")}
|
|
22749
|
+
$ skills doctor
|
|
22750
|
+
|
|
22751
|
+
${indigo10.bold("Documentation:")}
|
|
22752
|
+
${indigo10("https://skills.md/docs")}
|
|
22150
22753
|
`);
|
|
22151
22754
|
program2.parse();
|