@hasnatools/skills 0.1.22 → 0.1.23

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.
Files changed (2) hide show
  1. package/dist/index.js +132 -33
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -21024,7 +21024,7 @@ async function searchCommand(query) {
21024
21024
  }
21025
21025
 
21026
21026
  // src/commands/install.ts
21027
- import { existsSync as existsSync3, writeFileSync as writeFileSync3 } from "fs";
21027
+ import { existsSync as existsSync3, writeFileSync as writeFileSync3, readFileSync as readFileSync2 } from "fs";
21028
21028
  import { join as join3 } from "path";
21029
21029
 
21030
21030
  // src/lib/theme.ts
@@ -21110,6 +21110,25 @@ function completionBanner(title) {
21110
21110
  }
21111
21111
 
21112
21112
  // src/commands/install.ts
21113
+ var SKILLS_MD_MARKER = "<!-- skills.md:managed -->";
21114
+ function isSkillsMdManaged(skillDir) {
21115
+ const skillMdPath = join3(skillDir, "SKILL.md");
21116
+ if (!existsSync3(skillMdPath)) {
21117
+ return false;
21118
+ }
21119
+ try {
21120
+ const content = readFileSync2(skillMdPath, "utf-8");
21121
+ return content.includes(SKILLS_MD_MARKER);
21122
+ } catch {
21123
+ return false;
21124
+ }
21125
+ }
21126
+ function addSkillsMdMarker(content) {
21127
+ return `${content.trim()}
21128
+
21129
+ ${SKILLS_MD_MARKER}
21130
+ `;
21131
+ }
21113
21132
  async function installCommand(slug, options = {}) {
21114
21133
  if (options.all) {
21115
21134
  return installAllSkills(options);
@@ -21153,7 +21172,7 @@ async function installCommand(slug, options = {}) {
21153
21172
  ensureSkillsDir(skillDir);
21154
21173
  ensureSkillsDir(exportsDir);
21155
21174
  ensureSkillsDir(logsDir);
21156
- writeFileSync3(join3(skillDir, "SKILL.md"), skill.skillMdContent);
21175
+ writeFileSync3(join3(skillDir, "SKILL.md"), addSkillsMdMarker(skill.skillMdContent));
21157
21176
  if (apiKey) {
21158
21177
  await installSkillRemote(slug);
21159
21178
  }
@@ -21236,7 +21255,7 @@ async function installAllSkills(options) {
21236
21255
  ensureSkillsDir(skillDir);
21237
21256
  ensureSkillsDir(exportsDir);
21238
21257
  ensureSkillsDir(logsDir);
21239
- writeFileSync3(join3(skillDir, "SKILL.md"), skillData.skillMdContent);
21258
+ writeFileSync3(join3(skillDir, "SKILL.md"), addSkillsMdMarker(skillData.skillMdContent));
21240
21259
  if (apiKey) {
21241
21260
  try {
21242
21261
  await installSkillRemote(skill.slug);
@@ -21278,7 +21297,7 @@ async function installAllSkills(options) {
21278
21297
  console.error(colors.error(error instanceof Error ? error.message : "Unknown error"));
21279
21298
  }
21280
21299
  }
21281
- function getInstalledSkills2(installDir) {
21300
+ function getInstalledSkillsWithStatus(installDir) {
21282
21301
  const { readdirSync, statSync } = __require("fs");
21283
21302
  if (!existsSync3(installDir)) {
21284
21303
  return [];
@@ -21288,11 +21307,29 @@ function getInstalledSkills2(installDir) {
21288
21307
  return entries.filter((entry) => {
21289
21308
  const fullPath = join3(installDir, entry);
21290
21309
  return statSync(fullPath).isDirectory() && entry.startsWith("skill-");
21291
- }).map((entry) => entry.replace(/^skill-/, ""));
21310
+ }).map((entry) => {
21311
+ const slug = entry.replace(/^skill-/, "");
21312
+ const skillDir = join3(installDir, entry);
21313
+ return {
21314
+ slug,
21315
+ isManaged: isSkillsMdManaged(skillDir)
21316
+ };
21317
+ });
21292
21318
  } catch {
21293
21319
  return [];
21294
21320
  }
21295
21321
  }
21322
+ function getInstalledSkills2(installDir) {
21323
+ return getInstalledSkillsWithStatus(installDir).map((s) => s.slug);
21324
+ }
21325
+ async function isMarketplaceSkill(slug) {
21326
+ try {
21327
+ const result = await getSkill(slug);
21328
+ return !result.error && !!result.data;
21329
+ } catch {
21330
+ return false;
21331
+ }
21332
+ }
21296
21333
  async function uninstallCommand(slug, options = {}) {
21297
21334
  const isLocal = options.local ?? false;
21298
21335
  const target = options.target ?? getDefaultTarget();
@@ -21343,6 +21380,26 @@ async function uninstallCommand(slug, options = {}) {
21343
21380
  return;
21344
21381
  }
21345
21382
  }
21383
+ const isManaged = isSkillsMdManaged(skillDir);
21384
+ if (!isManaged && !options.force) {
21385
+ const spinner2 = ora({
21386
+ text: `Verifying "${skillSlug}"...`,
21387
+ color: "magenta"
21388
+ }).start();
21389
+ const inMarketplace = await isMarketplaceSkill(skillSlug);
21390
+ spinner2.stop();
21391
+ if (!inMarketplace) {
21392
+ console.log(colors.error(`${symbols.error} Cannot uninstall "${skillSlug}"`));
21393
+ console.log();
21394
+ console.log(colors.warning("This skill was NOT installed via skills.md CLI."));
21395
+ console.log(colors.warning("It appears to be a user-created or custom skill."));
21396
+ console.log();
21397
+ console.log(colors.dim("To protect your work, skills.md will not delete this skill."));
21398
+ console.log(colors.dim("If you really want to delete it, remove it manually:"));
21399
+ console.log(` ${command(`rm -rf "${skillDir}"`)}`);
21400
+ return;
21401
+ }
21402
+ }
21346
21403
  const spinner = ora({
21347
21404
  text: `Uninstalling "${skillSlug}"...`,
21348
21405
  color: "magenta"
@@ -21432,8 +21489,10 @@ async function uninstallMultipleSkills(slugs, installDir, target, isLocal, force
21432
21489
  }
21433
21490
  }
21434
21491
  async function uninstallAllSkills(installDir, target, isLocal, force) {
21435
- const installed = getInstalledSkills2(installDir);
21436
- if (installed.length === 0) {
21492
+ const allSkills = getInstalledSkillsWithStatus(installDir);
21493
+ const managedSkills = allSkills.filter((s) => s.isManaged);
21494
+ const userSkills = allSkills.filter((s) => !s.isManaged);
21495
+ if (allSkills.length === 0) {
21437
21496
  console.log(colors.dim("No skills installed"));
21438
21497
  return;
21439
21498
  }
@@ -21441,24 +21500,51 @@ async function uninstallAllSkills(installDir, target, isLocal, force) {
21441
21500
  console.log(keyValue("Target", colors.primaryBold(target)));
21442
21501
  console.log(keyValue("Scope", colors.primaryBold(isLocal ? "project" : "global")));
21443
21502
  console.log(keyValue("Directory", path6(installDir)));
21444
- console.log(keyValue("Skills found", count(installed.length)));
21445
21503
  console.log();
21446
- console.log(colors.warning("The following skills will be removed:"));
21504
+ console.log(keyValue("skills.md managed", colors.warning(String(managedSkills.length))));
21505
+ console.log(keyValue("User-created (protected)", colors.success(String(userSkills.length))));
21506
+ console.log();
21507
+ if (managedSkills.length === 0) {
21508
+ console.log(colors.success(`${symbols.success} No skills.md managed skills to uninstall`));
21509
+ if (userSkills.length > 0) {
21510
+ console.log();
21511
+ console.log(colors.dim("Your custom skills are safe:"));
21512
+ userSkills.slice(0, 10).forEach((s) => {
21513
+ console.log(` ${colors.success(symbols.bullet)} ${skillName(s.slug)}`);
21514
+ });
21515
+ if (userSkills.length > 10) {
21516
+ console.log(colors.dim(` ... and ${userSkills.length - 10} more`));
21517
+ }
21518
+ }
21519
+ return;
21520
+ }
21521
+ console.log(colors.warning("The following skills.md skills will be removed:"));
21447
21522
  console.log();
21448
- const displayCount = Math.min(installed.length, 15);
21523
+ const displayCount = Math.min(managedSkills.length, 15);
21449
21524
  for (let i = 0;i < displayCount; i++) {
21450
- console.log(` ${colors.warning(symbols.bullet)} ${skillName(installed[i])}`);
21525
+ console.log(` ${colors.warning(symbols.bullet)} ${skillName(managedSkills[i].slug)}`);
21451
21526
  }
21452
- if (installed.length > displayCount) {
21453
- console.log(colors.dim(` ... and ${installed.length - displayCount} more`));
21527
+ if (managedSkills.length > displayCount) {
21528
+ console.log(colors.dim(` ... and ${managedSkills.length - displayCount} more`));
21454
21529
  }
21455
21530
  console.log();
21531
+ if (userSkills.length > 0) {
21532
+ console.log(colors.success("The following user-created skills will be PROTECTED:"));
21533
+ console.log();
21534
+ userSkills.slice(0, 5).forEach((s) => {
21535
+ console.log(` ${colors.success(symbols.success)} ${skillName(s.slug)}`);
21536
+ });
21537
+ if (userSkills.length > 5) {
21538
+ console.log(colors.dim(` ... and ${userSkills.length - 5} more`));
21539
+ }
21540
+ console.log();
21541
+ }
21456
21542
  if (!force) {
21457
21543
  const prompts2 = (await Promise.resolve().then(() => __toESM(require_prompts3(), 1))).default;
21458
21544
  const response = await prompts2({
21459
21545
  type: "confirm",
21460
21546
  name: "confirm",
21461
- message: `Uninstall all ${installed.length} skill(s)?`,
21547
+ message: `Uninstall ${managedSkills.length} skills.md skill(s)?`,
21462
21548
  initial: false
21463
21549
  });
21464
21550
  if (!response.confirm) {
@@ -21467,13 +21553,13 @@ async function uninstallAllSkills(installDir, target, isLocal, force) {
21467
21553
  }
21468
21554
  console.log();
21469
21555
  }
21470
- const total = installed.length;
21556
+ const total = managedSkills.length;
21471
21557
  const results = {
21472
21558
  success: [],
21473
21559
  failed: []
21474
21560
  };
21475
- for (let i = 0;i < installed.length; i++) {
21476
- const slug = installed[i];
21561
+ for (let i = 0;i < managedSkills.length; i++) {
21562
+ const slug = managedSkills[i].slug;
21477
21563
  const current = i + 1;
21478
21564
  const percent = Math.round(current / total * 100);
21479
21565
  const padWidth = String(total).length;
@@ -21495,7 +21581,7 @@ async function uninstallAllSkills(installDir, target, isLocal, force) {
21495
21581
  process.stdout.write("\r\x1B[K");
21496
21582
  completionBanner("Uninstall Complete");
21497
21583
  if (results.success.length > 0) {
21498
- console.log(successItem(`Uninstalled: ${colors.successBold(String(results.success.length))} skills`));
21584
+ console.log(successItem(`Uninstalled: ${colors.successBold(String(results.success.length))} skills.md skills`));
21499
21585
  }
21500
21586
  if (results.failed.length > 0) {
21501
21587
  console.log(errorItem(`Failed: ${colors.errorBold(String(results.failed.length))} skills`));
@@ -21508,6 +21594,10 @@ async function uninstallAllSkills(installDir, target, isLocal, force) {
21508
21594
  console.log(colors.dim(` ... and ${results.failed.length - 5} more`));
21509
21595
  }
21510
21596
  }
21597
+ if (userSkills.length > 0) {
21598
+ console.log();
21599
+ console.log(colors.success(`${symbols.success} Protected ${userSkills.length} user-created skill(s)`));
21600
+ }
21511
21601
  console.log();
21512
21602
  console.log(colors.dim("Reinstall skills with:"));
21513
21603
  console.log(` ${command("skills install --all")}`);
@@ -21684,7 +21774,7 @@ async function downloadCommand(slug, options = {}) {
21684
21774
  }
21685
21775
 
21686
21776
  // src/commands/list.ts
21687
- import { existsSync as existsSync5, readdirSync, readFileSync as readFileSync2 } from "fs";
21777
+ import { existsSync as existsSync5, readdirSync, readFileSync as readFileSync3 } from "fs";
21688
21778
  import { join as join5 } from "path";
21689
21779
  async function listCommand(options = {}) {
21690
21780
  const isGlobal = options.global ?? false;
@@ -21741,7 +21831,7 @@ async function listCommand(options = {}) {
21741
21831
  const skillMdPath = join5(skillDir, "SKILL.md");
21742
21832
  if (!existsSync5(skillMdPath))
21743
21833
  continue;
21744
- const content = readFileSync2(skillMdPath, "utf-8");
21834
+ const content = readFileSync3(skillMdPath, "utf-8");
21745
21835
  const frontmatter = parseFrontmatter(content);
21746
21836
  installedSkills.push({
21747
21837
  slug: entry.name,
@@ -21971,7 +22061,7 @@ async function cli2faCommand(action) {
21971
22061
  }
21972
22062
 
21973
22063
  // src/commands/run.ts
21974
- import { existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, appendFileSync } from "fs";
22064
+ import { existsSync as existsSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, appendFileSync } from "fs";
21975
22065
  import { join as join6 } from "path";
21976
22066
  async function runCommand(slug, options = {}) {
21977
22067
  if (!slug || slug.trim() === "") {
@@ -21991,7 +22081,7 @@ async function runCommand(slug, options = {}) {
21991
22081
  console.log(source_default.red(`Invalid skill: missing SKILL.md`));
21992
22082
  return;
21993
22083
  }
21994
- const content = readFileSync3(skillMdPath, "utf-8");
22084
+ const content = readFileSync4(skillMdPath, "utf-8");
21995
22085
  const { frontmatter } = parseSkillMd(content);
21996
22086
  console.log();
21997
22087
  console.log(source_default.bold(frontmatter.name || slug) + source_default.dim(` v${frontmatter.version || "unknown"}`));
@@ -22418,7 +22508,7 @@ function formatStatus(status) {
22418
22508
  }
22419
22509
 
22420
22510
  // src/commands/history.ts
22421
- import { existsSync as existsSync8, readFileSync as readFileSync4, readdirSync as readdirSync2, statSync } from "fs";
22511
+ import { existsSync as existsSync8, readFileSync as readFileSync5, readdirSync as readdirSync2, statSync } from "fs";
22422
22512
  import { join as join8 } from "path";
22423
22513
  var indigo4 = source_default.hex("#6366f1");
22424
22514
  async function historyCommand(options = {}) {
@@ -22537,7 +22627,7 @@ async function localHistoryCommand(options) {
22537
22627
  console.log(source_default.dim("Run a skill with `skills run <name>` to start tracking"));
22538
22628
  return;
22539
22629
  }
22540
- const content = readFileSync4(historyFile, "utf-8");
22630
+ const content = readFileSync5(historyFile, "utf-8");
22541
22631
  const lines = content.trim().split(`
22542
22632
  `).filter((line) => line.trim());
22543
22633
  let entries = [];
@@ -22655,7 +22745,7 @@ async function logsCommand(slug, options = {}) {
22655
22745
  console.log(source_default.dim(`File: ${logPath}`));
22656
22746
  console.log(source_default.dim("─".repeat(60)));
22657
22747
  console.log();
22658
- const content = readFileSync4(logPath, "utf-8");
22748
+ const content = readFileSync5(logPath, "utf-8");
22659
22749
  const logLines = content.split(`
22660
22750
  `);
22661
22751
  const tailLines = options.tail || 50;
@@ -23034,7 +23124,7 @@ async function buyCreditsCommand(amount) {
23034
23124
  }
23035
23125
 
23036
23126
  // src/commands/update.ts
23037
- import { existsSync as existsSync9, readdirSync as readdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync6 } from "fs";
23127
+ import { existsSync as existsSync9, readdirSync as readdirSync3, readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "fs";
23038
23128
  import { join as join9 } from "path";
23039
23129
  var indigo9 = source_default.hex("#6366f1");
23040
23130
  function parseFrontmatter2(content) {
@@ -23074,7 +23164,7 @@ async function updateCommand(skillName2, options = {}) {
23074
23164
  const skillMdPath = join9(skillDir, "SKILL.md");
23075
23165
  if (!existsSync9(skillMdPath))
23076
23166
  continue;
23077
- const content = readFileSync5(skillMdPath, "utf-8");
23167
+ const content = readFileSync6(skillMdPath, "utf-8");
23078
23168
  const frontmatter = parseFrontmatter2(content);
23079
23169
  const slug = entry.name.replace("skill-", "");
23080
23170
  if (skillName2 && slug !== skillName2 && frontmatter.name !== skillName2) {
@@ -23112,9 +23202,18 @@ async function updateCommand(skillName2, options = {}) {
23112
23202
  }
23113
23203
  const newVersion = result.data.version;
23114
23204
  const currentVersion = skill.version;
23115
- if (newVersion !== currentVersion) {
23116
- writeFileSync6(join9(skill.dir, "SKILL.md"), result.data.skillMdContent);
23117
- spinner.succeed(`${skill.name}: ${source_default.dim(currentVersion)} ${indigo9("→")} ${indigo9(newVersion)}`);
23205
+ const skillMdPath = join9(skill.dir, "SKILL.md");
23206
+ const currentContent = readFileSync6(skillMdPath, "utf-8");
23207
+ const newContent = result.data.skillMdContent;
23208
+ const contentChanged = currentContent !== newContent;
23209
+ const versionChanged = newVersion !== currentVersion;
23210
+ if (contentChanged || options.force) {
23211
+ writeFileSync6(skillMdPath, newContent);
23212
+ if (versionChanged) {
23213
+ spinner.succeed(`${skill.name}: ${source_default.dim(currentVersion)} ${indigo9("→")} ${indigo9(newVersion)}`);
23214
+ } else {
23215
+ spinner.succeed(`${skill.name}: ${indigo9("refreshed")} ${source_default.dim(`v${currentVersion}`)}`);
23216
+ }
23118
23217
  updated++;
23119
23218
  } else {
23120
23219
  spinner.succeed(`${skill.name}: ${source_default.dim(`v${currentVersion}`)} ${source_default.green("(up to date)")}`);
@@ -23329,7 +23428,7 @@ async function doctorCommand() {
23329
23428
  // src/index.ts
23330
23429
  var indigo12 = colors.primary;
23331
23430
  var program2 = new Command;
23332
- program2.name("skills").description("CLI for skills.md - AI Agent Skills Marketplace").version("0.1.22");
23431
+ program2.name("skills").description("CLI for skills.md - AI Agent Skills Marketplace").version("0.1.23");
23333
23432
  program2.command("init").description("Initialize skills.md in current project").option("-f, --force", "Force re-initialization (removes existing .skills/)").action((options) => {
23334
23433
  initCommand({ force: options.force });
23335
23434
  });
@@ -23426,8 +23525,8 @@ var creditsCmd = program2.command("credits").description("Manage credits");
23426
23525
  creditsCmd.command("balance").alias("bal").description("Check your credits balance").action(creditsCommand);
23427
23526
  creditsCmd.command("buy <amount>").description("Purchase credits ($5-$500)").action(buyCreditsCommand);
23428
23527
  creditsCmd.action(creditsCommand);
23429
- program2.command("update [skill]").description("Update installed skills to latest versions").option("-t, --target <target>", "Target platform (claude, codex)").action((skill, options) => {
23430
- updateCommand(skill, { target: options.target });
23528
+ program2.command("update [skill]").description("Update installed skills (refreshes SKILL.md from server)").option("-t, --target <target>", "Target platform (claude, codex)").option("-f, --force", "Force update even if content matches").action((skill, options) => {
23529
+ updateCommand(skill, { target: options.target, force: options.force });
23431
23530
  });
23432
23531
  program2.command("upgrade").description("Upgrade the Skills CLI to the latest version").action(upgradeCommand);
23433
23532
  program2.command("doctor").description("Check your environment and diagnose issues").action(doctorCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasnatools/skills",
3
- "version": "0.1.22",
3
+ "version": "0.1.23",
4
4
  "description": "CLI for skills.md - AI Agent Skills Marketplace",
5
5
  "type": "module",
6
6
  "bin": {