skills 1.5.16 → 1.5.18

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/cli.mjs +89 -72
  2. package/package.json +2 -2
package/dist/cli.mjs CHANGED
@@ -9,7 +9,6 @@ import { require_dist } from "./_chunks/libs/@vercel/detect-agent.mjs";
9
9
  import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "fs";
10
10
  import { basename, dirname, extname, isAbsolute, join, normalize, relative, resolve, sep } from "path";
11
11
  import { fileURLToPath } from "url";
12
- import { createHash } from "node:crypto";
13
12
  import { stripVTControlCharacters } from "node:util";
14
13
  import { homedir, platform, tmpdir } from "os";
15
14
  import * as readline from "readline";
@@ -18,7 +17,8 @@ import { promisify } from "util";
18
17
  import { execFile, execSync, spawn, spawnSync } from "child_process";
19
18
  import { access, chmod, cp, lstat, mkdir, mkdtemp, readFile, readdir, readlink, realpath, rm, stat, symlink, writeFile } from "fs/promises";
20
19
  import { parse } from "yaml";
21
- import { createHash as createHash$1 } from "crypto";
20
+ import { createHash } from "crypto";
21
+ import { createHash as createHash$1 } from "node:crypto";
22
22
  import { gunzipSync, inflateRawSync } from "node:zlib";
23
23
  var import_picocolors = /* @__PURE__ */ __toESM(require_picocolors(), 1);
24
24
  function getOwnerRepo(parsed) {
@@ -319,7 +319,7 @@ async function searchMultiselect(options) {
319
319
  const lockedTitle = `${import_picocolors.default.bold(lockedSection.title)} ${import_picocolors.default.dim("── always included")}`;
320
320
  lines.push(`${S_BAR} ${S_BAR_H}${S_BAR_H} ${lockedTitle} ${S_BAR_H.repeat(12)}`);
321
321
  for (const item of lockedSection.items) lines.push(`${S_BAR} ${S_BULLET} ${import_picocolors.default.bold(item.label)}`);
322
- if (lockedSection.hiddenCount && lockedSection.hiddenCount > 0) lines.push(`${S_BAR} ${import_picocolors.default.dim(`...and ${lockedSection.hiddenCount} more`)}`);
322
+ if (lockedSection.hiddenCount && lockedSection.hiddenCount > 0) lines.push(`${S_BAR} ${import_picocolors.default.dim(`…and ${lockedSection.hiddenCount} more`)}`);
323
323
  lines.push(`${S_BAR}`);
324
324
  lines.push(`${S_BAR} ${S_BAR_H}${S_BAR_H} ${import_picocolors.default.bold("Additional agents")} ${S_BAR_H.repeat(29)}`);
325
325
  }
@@ -492,23 +492,44 @@ function isGitHubSsoAuthError(message) {
492
492
  function isAuthFailure(message) {
493
493
  return message.includes("Authentication failed") || message.includes("could not read Username") || message.includes("Permission denied") || message.includes("Repository not found") || message.includes("requested URL returned error: 403") || isGitHubSsoAuthError(message);
494
494
  }
495
- function createGitClient(extraEnv) {
496
- return esm_default({
495
+ function createGitClient(sshCommand) {
496
+ const git = esm_default({
497
497
  timeout: { block: CLONE_TIMEOUT_MS },
498
- env: {
499
- ...process.env,
500
- GIT_TERMINAL_PROMPT: "0",
501
- GIT_LFS_SKIP_SMUDGE: "1",
502
- ...extraEnv
503
- },
504
498
  config: [
505
499
  "filter.lfs.required=false",
506
500
  "filter.lfs.smudge=",
507
501
  "filter.lfs.clean=",
508
502
  "filter.lfs.process="
509
503
  ],
510
- unsafe: { allowUnsafeFilter: true }
504
+ unsafe: {
505
+ allowUnsafeAlias: true,
506
+ allowUnsafeAskPass: true,
507
+ allowUnsafeConfigEnvCount: true,
508
+ allowUnsafeConfigPaths: true,
509
+ allowUnsafeCredentialHelper: true,
510
+ allowUnsafeDiffExternal: true,
511
+ allowUnsafeDiffTextConv: true,
512
+ allowUnsafeEditor: true,
513
+ allowUnsafeFilter: true,
514
+ allowUnsafeFsMonitor: true,
515
+ allowUnsafeGpgProgram: true,
516
+ allowUnsafeGitProxy: true,
517
+ allowUnsafeHooksPath: true,
518
+ allowUnsafeMergeDriver: true,
519
+ allowUnsafePack: true,
520
+ allowUnsafePager: true,
521
+ allowUnsafeProtocolOverride: true,
522
+ allowUnsafeSshCommand: true,
523
+ allowUnsafeTemplateDir: true
524
+ }
511
525
  });
526
+ git.env({
527
+ ...process.env,
528
+ GIT_TERMINAL_PROMPT: "0",
529
+ GIT_LFS_SKIP_SMUDGE: "1",
530
+ ...sshCommand ? { GIT_SSH_COMMAND: sshCommand } : {}
531
+ });
532
+ return git;
512
533
  }
513
534
  async function resetTempDir(dir) {
514
535
  await rm(dir, {
@@ -593,7 +614,7 @@ async function cloneRepo(url, ref) {
593
614
  } catch {}
594
615
  try {
595
616
  await resetTempDir(tempDir);
596
- await createGitClient({ GIT_SSH_COMMAND: process.env.GIT_SSH_COMMAND ?? "ssh -o BatchMode=yes" }).clone(repo.sshUrl, tempDir, cloneOptions);
617
+ await createGitClient(process.env.GIT_SSH_COMMAND ?? "ssh -o BatchMode=yes").clone(repo.sshUrl, tempDir, cloneOptions);
597
618
  return tempDir;
598
619
  } catch {}
599
620
  }
@@ -721,7 +742,7 @@ async function computeSkillFolderHash(skillDir) {
721
742
  const files = [];
722
743
  await collectFiles(skillDir, skillDir, files);
723
744
  files.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
724
- const hash = createHash$1("sha256");
745
+ const hash = createHash("sha256");
725
746
  for (const file of files) {
726
747
  hash.update(file.relativePath);
727
748
  hash.update(file.content);
@@ -795,6 +816,9 @@ function normalizeSkillName(name) {
795
816
  function normalizeRelativePath(path) {
796
817
  return path.split(sep).join("/").replace(/\/+/g, "/");
797
818
  }
819
+ function isRecord(value) {
820
+ return typeof value === "object" && value !== null && !Array.isArray(value);
821
+ }
798
822
  function shouldInstallInternalSkills() {
799
823
  const envValue = process.env.INSTALL_INTERNAL_SKILLS;
800
824
  return envValue === "1" || envValue === "true";
@@ -812,13 +836,14 @@ async function parseSkillMd(skillMdPath, options) {
812
836
  const { data } = parseFrontmatter(content);
813
837
  if (!data.name || !data.description) return null;
814
838
  if (typeof data.name !== "string" || typeof data.description !== "string") return null;
815
- if (data.metadata?.internal === true && !shouldInstallInternalSkills() && !options?.includeInternal) return null;
839
+ const metadata = isRecord(data.metadata) ? data.metadata : void 0;
840
+ if (metadata?.internal === true && !shouldInstallInternalSkills() && !options?.includeInternal) return null;
816
841
  return {
817
842
  name: sanitizeMetadata(data.name),
818
843
  description: sanitizeMetadata(data.description),
819
844
  path: dirname(skillMdPath),
820
845
  rawContent: content,
821
- metadata: data.metadata
846
+ metadata
822
847
  };
823
848
  } catch {
824
849
  return null;
@@ -2680,7 +2705,7 @@ var WellKnownProvider = class {
2680
2705
  }
2681
2706
  }
2682
2707
  computeDigest(bytes) {
2683
- return `sha256:${createHash("sha256").update(bytes).digest("hex")}`;
2708
+ return `sha256:${createHash$1("sha256").update(bytes).digest("hex")}`;
2684
2709
  }
2685
2710
  extractArchive(bytes, artifactUrl, contentType) {
2686
2711
  if (this.isZipArchive(bytes, artifactUrl, contentType)) return this.extractZip(bytes);
@@ -2849,7 +2874,7 @@ function getGitHubToken() {
2849
2874
  if (process.env.GITHUB_TOKEN) return process.env.GITHUB_TOKEN;
2850
2875
  if (process.env.GH_TOKEN) return process.env.GH_TOKEN;
2851
2876
  if (!_ghWarningShown) {
2852
- process.stderr.write(`${import_picocolors.default.yellow("│")} ${import_picocolors.default.yellow("GitHub rate limit reached")} using your ${import_picocolors.default.cyan("gh")} login to continue.\n${import_picocolors.default.yellow("")} ${import_picocolors.default.dim(`Tip: set ${import_picocolors.default.cyan("GITHUB_TOKEN")} to avoid this prompt, or use ${import_picocolors.default.cyan("--full-depth")} to clone instead.\n`)}`);
2877
+ process.stderr.write(`${import_picocolors.default.dim("│ GitHub API request limit reached; checking existing ")}${import_picocolors.default.cyan("gh")}${import_picocolors.default.dim(" authentication…\n")}`);
2853
2878
  _ghWarningShown = true;
2854
2879
  }
2855
2880
  try {
@@ -3103,7 +3128,7 @@ async function fetchSkillDownload(source, slug) {
3103
3128
  }
3104
3129
  }
3105
3130
  function computeSnapshotHash(files) {
3106
- const hash = createHash("sha256");
3131
+ const hash = createHash$1("sha256");
3107
3132
  for (const file of [...files].sort((a, b) => a.path.localeCompare(b.path))) {
3108
3133
  hash.update(file.path);
3109
3134
  hash.update(file.contents);
@@ -3183,7 +3208,7 @@ async function tryBlobInstall(ownerRepo, options = {}) {
3183
3208
  tree
3184
3209
  };
3185
3210
  }
3186
- var version$1 = "1.5.16";
3211
+ var version$1 = "1.5.18";
3187
3212
  const isCancelled$1 = (value) => typeof value === "symbol";
3188
3213
  const EVE_AGENT_LABEL = "eve agent";
3189
3214
  async function isSourcePrivate(source) {
@@ -3254,12 +3279,6 @@ function shortenPath$2(fullPath, cwd) {
3254
3279
  if (fullPath === cwd || fullPath.startsWith(cwd + sep)) return "." + fullPath.slice(cwd.length);
3255
3280
  return fullPath;
3256
3281
  }
3257
- function computeSingleFileSkillHash(contents) {
3258
- const hash = createHash("sha256");
3259
- hash.update("SKILL.md");
3260
- hash.update(contents);
3261
- return hash.digest("hex");
3262
- }
3263
3282
  function formatList$1(items, maxShow = 5) {
3264
3283
  if (items.length <= maxShow) return items.join(", ");
3265
3284
  const shown = items.slice(0, maxShow);
@@ -3409,7 +3428,7 @@ async function selectAgentsInteractive(options) {
3409
3428
  }
3410
3429
  setVersion(version$1);
3411
3430
  async function handleWellKnownSkills(source, url, options, spinner) {
3412
- spinner.start("Discovering skills from well-known endpoint...");
3431
+ spinner.start("Discovering skills from well-known endpoint");
3413
3432
  const skills = await wellKnownProvider.fetchAllSkills(url);
3414
3433
  if (skills.length === 0) {
3415
3434
  spinner.stop(import_picocolors.default.red("No skills found"));
@@ -3459,7 +3478,7 @@ async function handleWellKnownSkills(source, url, options, spinner) {
3459
3478
  options: skills.map((s) => ({
3460
3479
  value: s,
3461
3480
  label: s.installName,
3462
- hint: s.description.length > 60 ? s.description.slice(0, 57) + "..." : s.description
3481
+ hint: s.description.length > 60 ? s.description.slice(0, 57) + "" : s.description
3463
3482
  })),
3464
3483
  required: true
3465
3484
  });
@@ -3483,7 +3502,7 @@ async function handleWellKnownSkills(source, url, options, spinner) {
3483
3502
  }
3484
3503
  targetAgents = options.agent;
3485
3504
  } else {
3486
- spinner.start("Loading agents...");
3505
+ spinner.start("Loading agents");
3487
3506
  const installedAgents = await detectInstalledAgents();
3488
3507
  const totalAgents = Object.keys(agents).length;
3489
3508
  spinner.stop(`${totalAgents} agents`);
@@ -3593,7 +3612,7 @@ async function handleWellKnownSkills(source, url, options, spinner) {
3593
3612
  }
3594
3613
  const sourceIdentifier = wellKnownProvider.getSourceIdentifier(url);
3595
3614
  const wellKnownPrivacyPromise = isSourcePrivate(sourceIdentifier).catch(() => null);
3596
- spinner.start("Installing skills...");
3615
+ spinner.start("Installing skills");
3597
3616
  const results = [];
3598
3617
  for (const skill of selectedSkills) for (const agent of targetAgents) {
3599
3618
  const result = await installWellKnownSkillForAgent(skill, agent, {
@@ -3663,9 +3682,13 @@ async function handleWellKnownSkills(source, url, options, spinner) {
3663
3682
  const firstResult = skillResults[0];
3664
3683
  if (firstResult.mode === "copy") {
3665
3684
  resultLines.push(`${import_picocolors.default.green("✓")} ${skillName} ${import_picocolors.default.dim("(copied)")}`);
3685
+ const shortPathsSet = /* @__PURE__ */ new Set();
3666
3686
  for (const r of skillResults) {
3667
3687
  const shortPath = shortenPath$2(r.path, cwd);
3668
- resultLines.push(` ${import_picocolors.default.dim("→")} ${shortPath}`);
3688
+ if (!shortPathsSet.has(shortPath)) {
3689
+ shortPathsSet.add(shortPath);
3690
+ resultLines.push(` ${import_picocolors.default.dim("→")} ${shortPath}`);
3691
+ }
3669
3692
  }
3670
3693
  } else {
3671
3694
  if (firstResult.canonicalPath) {
@@ -3731,7 +3754,7 @@ async function runAdd(args, options = {}) {
3731
3754
  let tempDir = null;
3732
3755
  try {
3733
3756
  const spinner$3 = spinner();
3734
- spinner$3.start("Parsing source...");
3757
+ spinner$3.start("Parsing source");
3735
3758
  const parsed = parseSource(source);
3736
3759
  spinner$3.stop(`Source: ${parsed.type === "local" ? parsed.localPath : parsed.url}${parsed.ref ? ` @ ${import_picocolors.default.yellow(parsed.ref)}` : ""}${parsed.subpath ? ` (${parsed.subpath})` : ""}${parsed.skillFilter ? ` ${import_picocolors.default.dim("@")}${import_picocolors.default.cyan(parsed.skillFilter)}` : ""}`);
3737
3760
  const ownerRepoRaw = getOwnerRepo(parsed);
@@ -3753,14 +3776,14 @@ async function runAdd(args, options = {}) {
3753
3776
  let skills;
3754
3777
  let blobResult = null;
3755
3778
  if (parsed.type === "local") {
3756
- spinner$3.start("Validating local path...");
3779
+ spinner$3.start("Validating local path");
3757
3780
  if (!existsSync(parsed.localPath)) {
3758
3781
  spinner$3.stop(import_picocolors.default.red("Path not found"));
3759
3782
  outro(import_picocolors.default.red(`Local path does not exist: ${parsed.localPath}`));
3760
3783
  process.exit(1);
3761
3784
  }
3762
3785
  spinner$3.stop("Local path validated");
3763
- spinner$3.start("Discovering skills...");
3786
+ spinner$3.start("Discovering skills");
3764
3787
  skills = await discoverSkills(parsed.localPath, parsed.subpath, {
3765
3788
  includeInternal,
3766
3789
  fullDepth: options.fullDepth
@@ -3775,7 +3798,7 @@ async function runAdd(args, options = {}) {
3775
3798
  const owner = ownerRepo?.split("/")[0]?.toLowerCase();
3776
3799
  const isSelfHostedRepo = !!ownerRepo && Object.hasOwn(BLOB_ALLOWED_REPOS, ownerRepo.toLowerCase());
3777
3800
  if (ownerRepo && owner && (isSelfHostedRepo || BLOB_ALLOWED_OWNERS.includes(owner))) {
3778
- spinner$3.start("Fetching skills...");
3801
+ spinner$3.start("Fetching skills");
3779
3802
  blobResult = await tryBlobInstall(ownerRepo, {
3780
3803
  subpath: parsed.subpath,
3781
3804
  skillFilter: parsed.skillFilter,
@@ -3783,26 +3806,26 @@ async function runAdd(args, options = {}) {
3783
3806
  getToken: getGitHubToken,
3784
3807
  includeInternal
3785
3808
  });
3786
- if (!blobResult) spinner$3.stop(import_picocolors.default.dim("Falling back to clone..."));
3809
+ if (!blobResult) spinner$3.stop(import_picocolors.default.dim("Falling back to clone"));
3787
3810
  }
3788
3811
  if (blobResult) {
3789
3812
  skills = blobResult.skills;
3790
3813
  spinner$3.stop(`Found ${import_picocolors.default.green(skills.length)} skill${skills.length > 1 ? "s" : ""}`);
3791
3814
  } else {
3792
- spinner$3.start("Cloning repository...");
3815
+ spinner$3.start("Cloning repository");
3793
3816
  tempDir = await cloneRepo(parsed.url, parsed.ref);
3794
3817
  spinner$3.stop("Repository cloned");
3795
- spinner$3.start("Discovering skills...");
3818
+ spinner$3.start("Discovering skills");
3796
3819
  skills = await discoverSkills(tempDir, parsed.subpath, {
3797
3820
  includeInternal,
3798
3821
  fullDepth: options.fullDepth
3799
3822
  });
3800
3823
  }
3801
3824
  } else {
3802
- spinner$3.start("Cloning repository...");
3825
+ spinner$3.start("Cloning repository");
3803
3826
  tempDir = await cloneRepo(parsed.url, parsed.ref);
3804
3827
  spinner$3.stop("Repository cloned");
3805
- spinner$3.start("Discovering skills...");
3828
+ spinner$3.start("Discovering skills");
3806
3829
  skills = await discoverSkills(tempDir, parsed.subpath, {
3807
3830
  includeInternal,
3808
3831
  fullDepth: options.fullDepth
@@ -3887,7 +3910,7 @@ async function runAdd(args, options = {}) {
3887
3910
  grouped[groupName].push({
3888
3911
  value: s,
3889
3912
  label: getSkillDisplayName(s),
3890
- hint: s.description.length > 60 ? s.description.slice(0, 57) + "..." : s.description
3913
+ hint: s.description.length > 60 ? s.description.slice(0, 57) + "" : s.description
3891
3914
  });
3892
3915
  }
3893
3916
  selected = await groupMultiselect({
@@ -3900,7 +3923,7 @@ async function runAdd(args, options = {}) {
3900
3923
  options: sortedSkills.map((s) => ({
3901
3924
  value: s,
3902
3925
  label: getSkillDisplayName(s),
3903
- hint: s.description.length > 60 ? s.description.slice(0, 57) + "..." : s.description
3926
+ hint: s.description.length > 60 ? s.description.slice(0, 57) + "" : s.description
3904
3927
  })),
3905
3928
  required: true
3906
3929
  });
@@ -3928,7 +3951,7 @@ async function runAdd(args, options = {}) {
3928
3951
  }
3929
3952
  targetAgents = options.agent;
3930
3953
  } else {
3931
- spinner$3.start("Loading agents...");
3954
+ spinner$3.start("Loading agents");
3932
3955
  const installedAgents = await detectInstalledAgents();
3933
3956
  const totalAgents = Object.keys(agents).length;
3934
3957
  spinner$3.stop(`${totalAgents} agents`);
@@ -4131,7 +4154,7 @@ async function runAdd(args, options = {}) {
4131
4154
  process.exit(0);
4132
4155
  }
4133
4156
  }
4134
- spinner$3.start("Installing skills...");
4157
+ spinner$3.start("Installing skills");
4135
4158
  const results = [];
4136
4159
  for (const skill of selectedSkills) for (const target of installTargets) {
4137
4160
  const { agent, subagent } = target;
@@ -4146,17 +4169,7 @@ async function runAdd(args, options = {}) {
4146
4169
  mode: installMode,
4147
4170
  eveSubagent: subagent
4148
4171
  });
4149
- } else if (tempDir && skill.path === tempDir && skill.rawContent) result = await installBlobSkillForAgent({
4150
- installName: skill.name,
4151
- files: [{
4152
- path: "SKILL.md",
4153
- contents: skill.rawContent
4154
- }]
4155
- }, agent, {
4156
- global: installGlobally,
4157
- mode: installMode
4158
- });
4159
- else result = await installSkillForAgent(skill, agent, {
4172
+ } else result = await installSkillForAgent(skill, agent, {
4160
4173
  global: installGlobally,
4161
4174
  mode: installMode,
4162
4175
  eveSubagent: subagent
@@ -4237,7 +4250,7 @@ async function runAdd(args, options = {}) {
4237
4250
  for (const skill of selectedSkills) {
4238
4251
  const skillDisplayName = getSkillDisplayName(skill);
4239
4252
  if (successfulSkillNames.has(skillDisplayName)) try {
4240
- const computedHash = blobResult && "snapshotHash" in skill ? skill.snapshotHash : tempDir && skill.path === tempDir && skill.rawContent ? computeSingleFileSkillHash(skill.rawContent) : await computeSkillFolderHash(skill.path);
4253
+ const computedHash = blobResult && "snapshotHash" in skill ? skill.snapshotHash : await computeSkillFolderHash(skill.path);
4241
4254
  const skillPathValue = skillFiles[skill.name];
4242
4255
  await addSkillToLocalLock(skill.name, {
4243
4256
  source: lockSource || parsed.url,
@@ -4275,9 +4288,13 @@ async function runAdd(args, options = {}) {
4275
4288
  const firstResult = skillResults[0];
4276
4289
  if (firstResult.mode === "copy") {
4277
4290
  resultLines.push(`${import_picocolors.default.green("✓")} ${entry.skill} ${import_picocolors.default.dim("(copied)")}`);
4291
+ const shortPathsSet = /* @__PURE__ */ new Set();
4278
4292
  for (const r of skillResults) {
4279
4293
  const shortPath = shortenPath$2(r.path, cwd);
4280
- resultLines.push(` ${import_picocolors.default.dim("→")} ${shortPath}`);
4294
+ if (!shortPathsSet.has(shortPath)) {
4295
+ shortPathsSet.add(shortPath);
4296
+ resultLines.push(` ${import_picocolors.default.dim("→")} ${shortPath}`);
4297
+ }
4281
4298
  }
4282
4299
  } else {
4283
4300
  if (firstResult.canonicalPath) {
@@ -4355,7 +4372,7 @@ async function promptForFindSkills(options, targetAgents) {
4355
4372
  const findSkillsAgents = targetAgents?.filter((a) => a !== "replit");
4356
4373
  if (!findSkillsAgents || findSkillsAgents.length === 0) return;
4357
4374
  console.log();
4358
- log.step("Installing find-skills skill...");
4375
+ log.step("Installing find-skills skill");
4359
4376
  try {
4360
4377
  await runAdd(["vercel-labs/skills"], {
4361
4378
  skill: ["find-skills"],
@@ -4528,7 +4545,7 @@ async function runSearchPrompt(initialQuery = "", owner) {
4528
4545
  lines.push(`${TEXT$2}Search skills:${RESET$3} ${query}${cursor}`);
4529
4546
  lines.push("");
4530
4547
  if (!query || query.length < 2) lines.push(`${DIM$3}Start typing to search (min 2 chars)${RESET$3}`);
4531
- else if (results.length === 0 && loading) lines.push(`${DIM$3}Searching...${RESET$3}`);
4548
+ else if (results.length === 0 && loading) lines.push(`${DIM$3}Searching…${RESET$3}`);
4532
4549
  else if (results.length === 0) lines.push(`${DIM$3}No skills found${RESET$3}`);
4533
4550
  else {
4534
4551
  const visible = results.slice(0, 8);
@@ -4540,7 +4557,7 @@ async function runSearchPrompt(initialQuery = "", owner) {
4540
4557
  const source = skill.source ? ` ${DIM$3}${skill.source}${RESET$3}` : "";
4541
4558
  const installs = formatInstalls(skill.installs);
4542
4559
  const installsBadge = installs ? ` ${CYAN$1}${installs}${RESET$3}` : "";
4543
- const loadingIndicator = loading && i === 0 ? ` ${DIM$3}...${RESET$3}` : "";
4560
+ const loadingIndicator = loading && i === 0 ? ` ${DIM$3}…${RESET$3}` : "";
4544
4561
  lines.push(` ${arrow} ${name}${source}${installsBadge}${loadingIndicator}`);
4545
4562
  }
4546
4563
  }
@@ -4694,7 +4711,7 @@ ${DIM$3} 2) npx skills add <owner/repo@skill>${RESET$3}`;
4694
4711
  const pkg = selected.source || selected.slug;
4695
4712
  const skillName = selected.name;
4696
4713
  console.log();
4697
- console.log(`${TEXT$2}Installing ${BOLD$3}${skillName}${RESET$3} from ${DIM$3}${pkg}${RESET$3}...`);
4714
+ console.log(`${TEXT$2}Installing ${BOLD$3}${skillName}${RESET$3} from ${DIM$3}${pkg}${RESET$3}…`);
4698
4715
  console.log();
4699
4716
  const { source, options: addOptions } = parseAddOptions([
4700
4717
  pkg,
@@ -4797,7 +4814,7 @@ async function runSync(args, options = {}) {
4797
4814
  if (!agentResult.isAgent) intro(import_picocolors.default.bgCyan(import_picocolors.default.black(" skills experimental_sync ")));
4798
4815
  if (agentResult.isAgent) log.info(import_picocolors.default.bgCyan(import_picocolors.default.black(import_picocolors.default.bold(` ${agentResult.agent.name} `))) + " Agent detected — installing non-interactively");
4799
4816
  const spinner$2 = spinner();
4800
- spinner$2.start("Scanning node_modules for skills...");
4817
+ spinner$2.start("Scanning node_modules for skills");
4801
4818
  const discoveredSkills = await discoverNodeModuleSkills(cwd);
4802
4819
  if (discoveredSkills.length === 0) {
4803
4820
  spinner$2.stop(import_picocolors.default.yellow("No skills found"));
@@ -4850,7 +4867,7 @@ async function runSync(args, options = {}) {
4850
4867
  }
4851
4868
  targetAgents = options.agent;
4852
4869
  } else {
4853
- spinner$2.start("Loading agents...");
4870
+ spinner$2.start("Loading agents");
4854
4871
  const installedAgents = await detectInstalledAgents();
4855
4872
  const totalAgents = Object.keys(agents).length;
4856
4873
  spinner$2.stop(`${totalAgents} agents`);
@@ -4924,7 +4941,7 @@ async function runSync(args, options = {}) {
4924
4941
  process.exit(0);
4925
4942
  }
4926
4943
  }
4927
- spinner$2.start("Syncing skills...");
4944
+ spinner$2.start("Syncing skills");
4928
4945
  const results = [];
4929
4946
  for (const skill of toInstall) for (const agent of targetAgents) {
4930
4947
  const result = await installSkillForAgent(skill, agent, {
@@ -5261,7 +5278,7 @@ async function removeCommand(skillNames, options) {
5261
5278
  const isGlobal = options.global ?? false;
5262
5279
  const cwd = process.cwd();
5263
5280
  const spinner$1 = spinner();
5264
- spinner$1.start("Scanning for installed skills...");
5281
+ spinner$1.start("Scanning for installed skills");
5265
5282
  const skillNamesSet = /* @__PURE__ */ new Set();
5266
5283
  const scanDir = async (dir) => {
5267
5284
  try {
@@ -5335,7 +5352,7 @@ async function removeCommand(skillNames, options) {
5335
5352
  process.exit(0);
5336
5353
  }
5337
5354
  }
5338
- spinner$1.start("Removing skills...");
5355
+ spinner$1.start("Removing skills");
5339
5356
  const results = [];
5340
5357
  for (const skillName of selectedSkills) try {
5341
5358
  const canonicalPath = getCanonicalPath(skillName, {
@@ -5586,7 +5603,7 @@ async function checkAndPromptForDeletions(source, allLockedForSource, lockSkills
5586
5603
  else {
5587
5604
  const confirmed = await confirm({ message: `Would you like to remove the local copies of these deleted skills?` });
5588
5605
  if (confirmed && !isCancel(confirmed)) for (const s of deletedSkills) {
5589
- console.log(`${DIM$1}Removing${RESET$1} ${s}...`);
5606
+ console.log(`${DIM$1}Removing${RESET$1} ${s}…`);
5590
5607
  await removeCommand([s], {
5591
5608
  yes: true,
5592
5609
  global: isGlobal
@@ -5720,7 +5737,7 @@ async function updateGlobalSkills(options = {}) {
5720
5737
  console.log();
5721
5738
  for (const update of updates) {
5722
5739
  const safeName = sanitizeMetadata(update.name);
5723
- console.log(`${TEXT$1}Updating ${safeName}...${RESET$1}`);
5740
+ console.log(`${TEXT$1}Updating ${safeName}…${RESET$1}`);
5724
5741
  const installUrl = buildUpdateInstallSource(update.entry);
5725
5742
  if (!installUrl) {
5726
5743
  failCount++;
@@ -5801,7 +5818,7 @@ async function updateProjectSkills(options = {}) {
5801
5818
  if (hasUniversal) targetParts.push("Universal");
5802
5819
  targetParts.push(...targetAgentNames);
5803
5820
  if (targetParts.length > 0) console.log(`${TEXT$1}Updating for: ${targetParts.join(", ")}${RESET$1}`);
5804
- console.log(`${TEXT$1}Refreshing ${updatable.length} skill(s)...${RESET$1}`);
5821
+ console.log(`${TEXT$1}Refreshing ${updatable.length} skill(s)…${RESET$1}`);
5805
5822
  console.log();
5806
5823
  const bySource = /* @__PURE__ */ new Map();
5807
5824
  for (const skill of updatable) {
@@ -5846,7 +5863,7 @@ async function updateProjectSkills(options = {}) {
5846
5863
  const remainingSkills = skillsForSource.filter((s) => !deletedSkills.includes(s.name));
5847
5864
  for (const skill of remainingSkills) {
5848
5865
  const safeName = sanitizeMetadata(skill.name);
5849
- console.log(`${TEXT$1}Updating ${safeName}...${RESET$1}`);
5866
+ console.log(`${TEXT$1}Updating ${safeName}…${RESET$1}`);
5850
5867
  const installUrl = buildLocalUpdateSource(skill.entry);
5851
5868
  if (!installUrl) {
5852
5869
  failCount++;
@@ -5900,8 +5917,8 @@ function printLegacyProjectSkills(legacy) {
5900
5917
  async function runUpdate(args = []) {
5901
5918
  const options = parseUpdateOptions(args);
5902
5919
  const scope = await resolveUpdateScope(options);
5903
- if (options.skills) console.log(`${TEXT$1}Updating ${options.skills.join(", ")}...${RESET$1}`);
5904
- else console.log(`${TEXT$1}Checking for skill updates...${RESET$1}`);
5920
+ if (options.skills) console.log(`${TEXT$1}Updating ${options.skills.join(", ")}…${RESET$1}`);
5921
+ else console.log(`${TEXT$1}Checking for skill updates…${RESET$1}`);
5905
5922
  console.log();
5906
5923
  let totalSuccess = 0;
5907
5924
  let totalFail = 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skills",
3
- "version": "1.5.16",
3
+ "version": "1.5.18",
4
4
  "description": "The open agent skills ecosystem",
5
5
  "type": "module",
6
6
  "bin": {
@@ -130,7 +130,7 @@
130
130
  "obuild": "^0.4.22",
131
131
  "picocolors": "^1.1.1",
132
132
  "prettier": "^3.8.1",
133
- "simple-git": "^3.27.0",
133
+ "simple-git": "^3.36.0",
134
134
  "typescript": "^5.9.3",
135
135
  "vitest": "^4.0.17",
136
136
  "xdg-basedir": "^5.1.0"