dimcode-linux-arm64 0.0.78 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/dimcode CHANGED
Binary file
@@ -14,7 +14,8 @@ import { stripVTControlCharacters } from "node:util";
14
14
  import { homedir, platform, tmpdir } from "os";
15
15
  import * as readline from "readline";
16
16
  import { Writable } from "stream";
17
- import { execSync, spawnSync } from "child_process";
17
+ import { promisify } from "util";
18
+ import { execFile, execSync, spawn, spawnSync } from "child_process";
18
19
  import { access, cp, lstat, mkdir, mkdtemp, readFile, readdir, readlink, realpath, rm, stat, symlink, writeFile } from "fs/promises";
19
20
  import { parse } from "yaml";
20
21
  import { createHash } from "crypto";
@@ -319,6 +320,7 @@ async function searchMultiselect(options) {
319
320
  const lockedTitle = `${import_picocolors.default.bold(lockedSection.title)} ${import_picocolors.default.dim("── always included")}`;
320
321
  lines.push(`${S_BAR} ${S_BAR_H}${S_BAR_H} ${lockedTitle} ${S_BAR_H.repeat(12)}`);
321
322
  for (const item of lockedSection.items) lines.push(`${S_BAR} ${S_BULLET} ${import_picocolors.default.bold(item.label)}`);
323
+ if (lockedSection.hiddenCount && lockedSection.hiddenCount > 0) lines.push(`${S_BAR} ${import_picocolors.default.dim(`...and ${lockedSection.hiddenCount} more`)}`);
322
324
  lines.push(`${S_BAR}`);
323
325
  lines.push(`${S_BAR} ${S_BAR_H}${S_BAR_H} ${import_picocolors.default.bold("Additional agents")} ${S_BAR_H.repeat(29)}`);
324
326
  }
@@ -434,6 +436,7 @@ const CLONE_TIMEOUT_MS = (() => {
434
436
  const parsed = Number.parseInt(raw, 10);
435
437
  return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_CLONE_TIMEOUT_MS;
436
438
  })();
439
+ const execFileAsync = promisify(execFile);
437
440
  var GitCloneError = class extends Error {
438
441
  url;
439
442
  isTimeout;
@@ -446,14 +449,58 @@ var GitCloneError = class extends Error {
446
449
  this.isAuthError = isAuthError;
447
450
  }
448
451
  };
449
- async function cloneRepo(url, ref) {
450
- const tempDir = await mkdtemp(join(tmpdir(), "skills-"));
451
- const git = esm_default({
452
+ function parseGitHubRepoUrl(url) {
453
+ const sshMatch = url.match(/^git@github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/i);
454
+ if (sshMatch) {
455
+ const owner = sshMatch[1];
456
+ const repo = sshMatch[2];
457
+ return {
458
+ owner,
459
+ repo,
460
+ slug: `${owner}/${repo}`,
461
+ sshUrl: `git@github.com:${owner}/${repo}.git`
462
+ };
463
+ }
464
+ try {
465
+ const parsed = new URL(url);
466
+ if (parsed.hostname !== "github.com") return null;
467
+ const match = parsed.pathname.match(/^\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/);
468
+ if (!match) return null;
469
+ const owner = match[1];
470
+ const repo = match[2];
471
+ return {
472
+ owner,
473
+ repo,
474
+ slug: `${owner}/${repo}`,
475
+ sshUrl: `git@github.com:${owner}/${repo}.git`
476
+ };
477
+ } catch {
478
+ return null;
479
+ }
480
+ }
481
+ function isGitHubHttpsCloneUrl(url) {
482
+ try {
483
+ const parsed = new URL(url);
484
+ return parsed.protocol === "https:" && parsed.hostname === "github.com";
485
+ } catch {
486
+ return false;
487
+ }
488
+ }
489
+ function isGitHubSsoAuthError(message) {
490
+ const lower = message.toLowerCase();
491
+ return lower.includes("saml sso") || lower.includes("enforced sso") || lower.includes("enabled or enforced saml") || lower.includes("re-authorize the oauth application");
492
+ }
493
+ function isAuthFailure(message) {
494
+ 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);
495
+ }
496
+ function createGitClient(extraEnv) {
497
+ return esm_default({
452
498
  timeout: { block: CLONE_TIMEOUT_MS },
453
499
  env: {
454
500
  ...process.env,
455
501
  GIT_TERMINAL_PROMPT: "0",
456
- GIT_LFS_SKIP_SMUDGE: "1"
502
+ GIT_LFS_SKIP_SMUDGE: "1",
503
+ ...extraEnv
457
504
  },
458
505
  config: [
459
506
  "filter.lfs.required=false",
@@ -462,25 +509,98 @@ async function cloneRepo(url, ref) {
462
509
  "filter.lfs.process="
463
510
  ]
464
511
  });
512
+ }
513
+ async function resetTempDir(dir) {
514
+ await rm(dir, {
515
+ recursive: true,
516
+ force: true
517
+ }).catch(() => {});
518
+ await mkdir(dir, { recursive: true });
519
+ }
520
+ async function tryGhClone(repo, tempDir, ref) {
521
+ let cloneTarget = repo.slug;
522
+ try {
523
+ const { stdout, stderr } = await execFileAsync("gh", [
524
+ "auth",
525
+ "status",
526
+ "-h",
527
+ "github.com"
528
+ ], {
529
+ timeout: 5e3,
530
+ env: {
531
+ ...process.env,
532
+ GIT_TERMINAL_PROMPT: "0"
533
+ }
534
+ });
535
+ const statusOutput = `${stdout}${stderr}`;
536
+ if (/Git operations protocol:\s+ssh/i.test(statusOutput)) cloneTarget = repo.sshUrl;
537
+ } catch {
538
+ return false;
539
+ }
540
+ await execFileAsync("gh", [
541
+ "repo",
542
+ "clone",
543
+ cloneTarget,
544
+ tempDir,
545
+ "--",
546
+ ...ref ? [
547
+ "--depth=1",
548
+ "--branch",
549
+ ref
550
+ ] : ["--depth=1"]
551
+ ], {
552
+ timeout: CLONE_TIMEOUT_MS,
553
+ env: {
554
+ ...process.env,
555
+ GIT_TERMINAL_PROMPT: "0"
556
+ }
557
+ });
558
+ return true;
559
+ }
560
+ function buildGitHubAuthError(url, repo, message) {
561
+ if (repo && isGitHubSsoAuthError(message)) return `GitHub blocked HTTPS access to ${url} because the organization enforces SAML SSO.\n skills tried your existing git credentials and available fallbacks, but none succeeded.\n - Re-authorize your GitHub credentials/app for that org's SSO policy\n - Or rerun with SSH: npx skills add ${repo.sshUrl}\n - Verify access with: gh auth status -h github.com or ssh -T git@github.com`;
562
+ if (repo) return `Authentication failed for ${url}.\n - For private repos, ensure you have access\n - Retry with SSH: npx skills add ${repo.sshUrl}\n - Check access with: gh auth status -h github.com or ssh -T git@github.com`;
563
+ return `Authentication failed for ${url}.\n - For private repos, ensure you have access\n - For SSH: Check your keys with 'ssh -T git@github.com'\n - For HTTPS: Run 'gh auth login' or configure git credentials`;
564
+ }
565
+ async function cloneRepo(url, ref) {
566
+ const tempDir = await mkdtemp(join(tmpdir(), "skills-"));
465
567
  const cloneOptions = ref ? [
466
568
  "--depth",
467
569
  "1",
468
570
  "--branch",
469
571
  ref
470
572
  ] : ["--depth", "1"];
573
+ const repo = parseGitHubRepoUrl(url);
471
574
  try {
472
- await git.clone(url, tempDir, cloneOptions);
575
+ await createGitClient().clone(url, tempDir, cloneOptions);
473
576
  return tempDir;
474
577
  } catch (error) {
578
+ const errorMessage = error instanceof Error ? error.message : String(error);
579
+ const isTimeout = errorMessage.includes("block timeout") || errorMessage.includes("timed out");
580
+ const isAuthError = isAuthFailure(errorMessage);
581
+ if (isTimeout) {
582
+ await rm(tempDir, {
583
+ recursive: true,
584
+ force: true
585
+ }).catch(() => {});
586
+ throw new GitCloneError(`Clone timed out after ${Math.round(CLONE_TIMEOUT_MS / 1e3)}s. Common causes:\n - Large repository: raise the timeout with SKILLS_CLONE_TIMEOUT_MS=600000 (10m)\n - Slow network: retry, or clone manually and pass the local path to 'skills add'\n - Private repo without credentials: ensure auth is configured\n - For SSH: ssh-add -l (to check loaded keys)\n - For HTTPS: gh auth status (if using GitHub CLI)`, url, true, false);
587
+ }
588
+ if (isAuthError && repo && isGitHubHttpsCloneUrl(url)) {
589
+ try {
590
+ await resetTempDir(tempDir);
591
+ if (await tryGhClone(repo, tempDir, ref)) return tempDir;
592
+ } catch {}
593
+ try {
594
+ await resetTempDir(tempDir);
595
+ await createGitClient({ GIT_SSH_COMMAND: process.env.GIT_SSH_COMMAND ?? "ssh -o BatchMode=yes" }).clone(repo.sshUrl, tempDir, cloneOptions);
596
+ return tempDir;
597
+ } catch {}
598
+ }
475
599
  await rm(tempDir, {
476
600
  recursive: true,
477
601
  force: true
478
602
  }).catch(() => {});
479
- const errorMessage = error instanceof Error ? error.message : String(error);
480
- const isTimeout = errorMessage.includes("block timeout") || errorMessage.includes("timed out");
481
- const isAuthError = errorMessage.includes("Authentication failed") || errorMessage.includes("could not read Username") || errorMessage.includes("Permission denied") || errorMessage.includes("Repository not found");
482
- if (isTimeout) throw new GitCloneError(`Clone timed out after ${Math.round(CLONE_TIMEOUT_MS / 1e3)}s. Common causes:\n - Large repository: raise the timeout with SKILLS_CLONE_TIMEOUT_MS=600000 (10m)\n - Slow network: retry, or clone manually and pass the local path to 'skills add'\n - Private repo without credentials: ensure auth is configured\n - For SSH: ssh-add -l (to check loaded keys)\n - For HTTPS: gh auth status (if using GitHub CLI)`, url, true, false);
483
- if (isAuthError) throw new GitCloneError(`Authentication failed for ${url}.\n - For private repos, ensure you have access\n - For SSH: Check your keys with 'ssh -T git@github.com'\n - For HTTPS: Run 'gh auth login' or configure git credentials`, url, false, true);
603
+ if (isAuthError) throw new GitCloneError(buildGitHubAuthError(url, repo, errorMessage), url, false, true);
484
604
  throw new GitCloneError(`Failed to clone ${url}: ${errorMessage}`, url, false, false);
485
605
  }
486
606
  }
@@ -818,6 +938,8 @@ const configHome = xdgConfig ?? join(home, ".config");
818
938
  const codexHome = process.env.CODEX_HOME?.trim() || join(home, ".codex");
819
939
  const claudeHome = process.env.CLAUDE_CONFIG_DIR?.trim() || join(home, ".claude");
820
940
  const vibeHome = process.env.VIBE_HOME?.trim() || join(home, ".vibe");
941
+ const hermesHome = process.env.HERMES_HOME?.trim() || join(home, ".hermes");
942
+ const autohandHome = process.env.AUTOHAND_HOME?.trim() || join(home, ".autohand");
821
943
  const zedAppDataHome = process.env.APPDATA?.trim();
822
944
  const zedFlatpakConfigHome = process.env.FLATPAK_XDG_CONFIG_HOME?.trim();
823
945
  function getOpenClawGlobalSkillsDir(homeDir = home, pathExists = existsSync) {
@@ -854,6 +976,33 @@ const agents = {
854
976
  return existsSync(join(home, ".gemini/antigravity"));
855
977
  }
856
978
  },
979
+ "antigravity-cli": {
980
+ name: "antigravity-cli",
981
+ displayName: "Antigravity CLI",
982
+ skillsDir: ".agents/skills",
983
+ globalSkillsDir: join(home, ".gemini/antigravity-cli/skills"),
984
+ detectInstalled: async () => {
985
+ return existsSync(join(home, ".gemini/antigravity-cli"));
986
+ }
987
+ },
988
+ astrbot: {
989
+ name: "astrbot",
990
+ displayName: "AstrBot",
991
+ skillsDir: "data/skills",
992
+ globalSkillsDir: join(home, ".astrbot/data/skills"),
993
+ detectInstalled: async () => {
994
+ return existsSync(join(process.cwd(), "data/skills")) || existsSync(join(home, ".astrbot"));
995
+ }
996
+ },
997
+ "autohand-code": {
998
+ name: "autohand-code",
999
+ displayName: "Autohand Code CLI",
1000
+ skillsDir: ".autohand/skills",
1001
+ globalSkillsDir: join(autohandHome, "skills"),
1002
+ detectInstalled: async () => {
1003
+ return existsSync(autohandHome);
1004
+ }
1005
+ },
857
1006
  augment: {
858
1007
  name: "augment",
859
1008
  displayName: "Augment",
@@ -1012,6 +1161,7 @@ const agents = {
1012
1161
  displayName: "Dexto",
1013
1162
  skillsDir: ".agents/skills",
1014
1163
  globalSkillsDir: join(home, ".agents/skills"),
1164
+ showInUniversalPrompt: false,
1015
1165
  detectInstalled: async () => {
1016
1166
  return existsSync(join(home, ".dexto"));
1017
1167
  }
@@ -1030,6 +1180,7 @@ const agents = {
1030
1180
  displayName: "Firebender",
1031
1181
  skillsDir: ".agents/skills",
1032
1182
  globalSkillsDir: join(home, ".firebender/skills"),
1183
+ showInUniversalPrompt: false,
1033
1184
  detectInstalled: async () => {
1034
1185
  return existsSync(join(home, ".firebender"));
1035
1186
  }
@@ -1074,9 +1225,27 @@ const agents = {
1074
1225
  name: "hermes-agent",
1075
1226
  displayName: "Hermes Agent",
1076
1227
  skillsDir: ".hermes/skills",
1077
- globalSkillsDir: join(home, ".hermes/skills"),
1228
+ globalSkillsDir: join(hermesHome, "skills"),
1078
1229
  detectInstalled: async () => {
1079
- return existsSync(join(home, ".hermes"));
1230
+ return existsSync(hermesHome);
1231
+ }
1232
+ },
1233
+ "inference-sh": {
1234
+ name: "inference-sh",
1235
+ displayName: "inference.sh",
1236
+ skillsDir: ".inferencesh/skills",
1237
+ globalSkillsDir: join(home, ".inferencesh/skills"),
1238
+ detectInstalled: async () => {
1239
+ return existsSync(join(home, ".inferencesh"));
1240
+ }
1241
+ },
1242
+ jazz: {
1243
+ name: "jazz",
1244
+ displayName: "Jazz",
1245
+ skillsDir: ".jazz/skills",
1246
+ globalSkillsDir: join(home, ".jazz/skills"),
1247
+ detectInstalled: async () => {
1248
+ return existsSync(join(home, ".jazz")) || existsSync(join(process.cwd(), ".jazz"));
1080
1249
  }
1081
1250
  },
1082
1251
  junie: {
@@ -1106,13 +1275,13 @@ const agents = {
1106
1275
  return existsSync(join(home, ".kilocode"));
1107
1276
  }
1108
1277
  },
1109
- "kimi-cli": {
1110
- name: "kimi-cli",
1278
+ "kimi-code-cli": {
1279
+ name: "kimi-code-cli",
1111
1280
  displayName: "Kimi Code CLI",
1112
1281
  skillsDir: ".agents/skills",
1113
- globalSkillsDir: join(home, ".config/agents/skills"),
1282
+ globalSkillsDir: join(home, ".agents/skills"),
1114
1283
  detectInstalled: async () => {
1115
- return existsSync(join(home, ".kimi"));
1284
+ return existsSync(join(home, ".kimi-code")) || existsSync(join(home, ".kimi"));
1116
1285
  }
1117
1286
  },
1118
1287
  "kiro-cli": {
@@ -1133,6 +1302,25 @@ const agents = {
1133
1302
  return existsSync(join(home, ".kode"));
1134
1303
  }
1135
1304
  },
1305
+ lingma: {
1306
+ name: "lingma",
1307
+ displayName: "Lingma",
1308
+ skillsDir: ".lingma/skills",
1309
+ globalSkillsDir: join(home, ".lingma/skills"),
1310
+ detectInstalled: async () => {
1311
+ return existsSync(join(home, ".lingma"));
1312
+ }
1313
+ },
1314
+ loaf: {
1315
+ name: "loaf",
1316
+ displayName: "Loaf",
1317
+ skillsDir: ".agents/skills",
1318
+ globalSkillsDir: join(home, ".agents/skills"),
1319
+ showInUniversalPrompt: false,
1320
+ detectInstalled: async () => {
1321
+ return existsSync(join(home, ".loaf"));
1322
+ }
1323
+ },
1136
1324
  mcpjam: {
1137
1325
  name: "mcpjam",
1138
1326
  displayName: "MCPJam",
@@ -1151,6 +1339,15 @@ const agents = {
1151
1339
  return existsSync(vibeHome);
1152
1340
  }
1153
1341
  },
1342
+ moxby: {
1343
+ name: "moxby",
1344
+ displayName: "Moxby",
1345
+ skillsDir: ".moxby/skills",
1346
+ globalSkillsDir: join(home, ".moxby/skills"),
1347
+ detectInstalled: async () => {
1348
+ return existsSync(join(home, ".moxby"));
1349
+ }
1350
+ },
1154
1351
  mux: {
1155
1352
  name: "mux",
1156
1353
  displayName: "Mux",
@@ -1178,6 +1375,15 @@ const agents = {
1178
1375
  return existsSync(join(home, ".openhands"));
1179
1376
  }
1180
1377
  },
1378
+ ona: {
1379
+ name: "ona",
1380
+ displayName: "Ona",
1381
+ skillsDir: ".ona/skills",
1382
+ globalSkillsDir: join(home, ".ona/skills"),
1383
+ detectInstalled: async () => {
1384
+ return existsSync(join(home, ".ona"));
1385
+ }
1386
+ },
1181
1387
  pi: {
1182
1388
  name: "pi",
1183
1389
  displayName: "Pi",
@@ -1196,6 +1402,15 @@ const agents = {
1196
1402
  return existsSync(join(home, ".qoder"));
1197
1403
  }
1198
1404
  },
1405
+ "qoder-cn": {
1406
+ name: "qoder-cn",
1407
+ displayName: "Qoder CN",
1408
+ skillsDir: ".qoder/skills",
1409
+ globalSkillsDir: join(home, ".qoder-cn/skills"),
1410
+ detectInstalled: async () => {
1411
+ return existsSync(join(home, ".qoder-cn"));
1412
+ }
1413
+ },
1199
1414
  "qwen-code": {
1200
1415
  name: "qwen-code",
1201
1416
  displayName: "Qwen Code",
@@ -1215,6 +1430,15 @@ const agents = {
1215
1430
  return existsSync(join(process.cwd(), ".replit"));
1216
1431
  }
1217
1432
  },
1433
+ reasonix: {
1434
+ name: "reasonix",
1435
+ displayName: "Reasonix",
1436
+ skillsDir: ".reasonix/skills",
1437
+ globalSkillsDir: join(home, ".reasonix/skills"),
1438
+ detectInstalled: async () => {
1439
+ return existsSync(join(home, ".reasonix"));
1440
+ }
1441
+ },
1218
1442
  rovodev: {
1219
1443
  name: "rovodev",
1220
1444
  displayName: "Rovo Dev",
@@ -1242,6 +1466,24 @@ const agents = {
1242
1466
  return existsSync(join(home, ".tabnine"));
1243
1467
  }
1244
1468
  },
1469
+ terramind: {
1470
+ name: "terramind",
1471
+ displayName: "Terramind",
1472
+ skillsDir: ".terramind/skills",
1473
+ globalSkillsDir: join(home, ".terramind/skills"),
1474
+ detectInstalled: async () => {
1475
+ return existsSync(join(home, ".terramind"));
1476
+ }
1477
+ },
1478
+ tinycloud: {
1479
+ name: "tinycloud",
1480
+ displayName: "Tinycloud",
1481
+ skillsDir: ".tinycloud/skills",
1482
+ globalSkillsDir: join(home, ".tinycloud/skills"),
1483
+ detectInstalled: async () => {
1484
+ return existsSync(join(home, ".tinycloud"));
1485
+ }
1486
+ },
1245
1487
  trae: {
1246
1488
  name: "trae",
1247
1489
  displayName: "Trae",
@@ -1296,6 +1538,15 @@ const agents = {
1296
1538
  return existsSync(join(home, ".zencoder"));
1297
1539
  }
1298
1540
  },
1541
+ zenflow: {
1542
+ name: "zenflow",
1543
+ displayName: "Zenflow",
1544
+ skillsDir: ".zencoder/skills",
1545
+ globalSkillsDir: join(home, ".zencoder/skills"),
1546
+ detectInstalled: async () => {
1547
+ return existsSync(join(home, ".zencoder"));
1548
+ }
1549
+ },
1299
1550
  neovate: {
1300
1551
  name: "neovate",
1301
1552
  displayName: "Neovate",
@@ -1314,6 +1565,16 @@ const agents = {
1314
1565
  return existsSync(join(home, ".pochi"));
1315
1566
  }
1316
1567
  },
1568
+ promptscript: {
1569
+ name: "promptscript",
1570
+ displayName: "PromptScript",
1571
+ skillsDir: ".agents/skills",
1572
+ globalSkillsDir: void 0,
1573
+ showInUniversalPrompt: false,
1574
+ detectInstalled: async () => {
1575
+ return existsSync(join(process.cwd(), ".promptscript")) || existsSync(join(process.cwd(), "promptscript.yaml"));
1576
+ }
1577
+ },
1317
1578
  adal: {
1318
1579
  name: "adal",
1319
1580
  displayName: "AdaL",
@@ -1341,6 +1602,9 @@ async function detectInstalledAgents() {
1341
1602
  function getUniversalAgents() {
1342
1603
  return Object.entries(agents).filter(([_, config]) => config.skillsDir === ".agents/skills" && config.showInUniversalList !== false).map(([type]) => type);
1343
1604
  }
1605
+ function getVisibleUniversalAgents() {
1606
+ return Object.entries(agents).filter(([_, config]) => config.skillsDir === ".agents/skills" && config.showInUniversalList !== false && config.showInUniversalPrompt !== false).map(([type]) => type);
1607
+ }
1344
1608
  function getNonUniversalAgents() {
1345
1609
  return Object.entries(agents).filter(([_, config]) => config.skillsDir !== ".agents/skills").map(([type]) => type);
1346
1610
  }
@@ -1352,7 +1616,7 @@ const SKILLS_SUBDIR = "skills";
1352
1616
  function sanitizeName(name) {
1353
1617
  return name.toLowerCase().replace(/[^a-z0-9._]+/g, "-").replace(/^[.\-]+|[.\-]+$/g, "").substring(0, 255) || "unnamed-skill";
1354
1618
  }
1355
- function isPathSafe(basePath, targetPath) {
1619
+ function isPathSafe$1(basePath, targetPath) {
1356
1620
  const normalizedBase = normalize(resolve(basePath));
1357
1621
  const normalizedTarget = normalize(resolve(targetPath));
1358
1622
  return normalizedTarget.startsWith(normalizedBase + sep) || normalizedTarget === normalizedBase;
@@ -1442,13 +1706,13 @@ async function installSkillForAgent(skill, agentType, options = {}) {
1442
1706
  const agentBase = getAgentBaseDir(agentType, isGlobal, cwd);
1443
1707
  const agentDir = join(agentBase, skillName);
1444
1708
  const installMode = options.mode ?? "symlink";
1445
- if (!isPathSafe(canonicalBase, canonicalDir)) return {
1709
+ if (!isPathSafe$1(canonicalBase, canonicalDir)) return {
1446
1710
  success: false,
1447
1711
  path: agentDir,
1448
1712
  mode: installMode,
1449
1713
  error: "Invalid skill name: potential path traversal detected"
1450
1714
  };
1451
- if (!isPathSafe(agentBase, agentDir)) return {
1715
+ if (!isPathSafe$1(agentBase, agentDir)) return {
1452
1716
  success: false,
1453
1717
  path: agentDir,
1454
1718
  mode: installMode,
@@ -1507,21 +1771,21 @@ async function installSkillForAgent(skill, agentType, options = {}) {
1507
1771
  };
1508
1772
  }
1509
1773
  }
1510
- const EXCLUDE_FILES = new Set(["metadata.json"]);
1511
- const EXCLUDE_DIRS = new Set([
1774
+ const EXCLUDE_FILES$1 = new Set(["metadata.json"]);
1775
+ const EXCLUDE_DIRS$1 = new Set([
1512
1776
  ".git",
1513
1777
  "__pycache__",
1514
1778
  "__pypackages__"
1515
1779
  ]);
1516
- const isExcluded = (name, isDirectory = false) => {
1517
- if (EXCLUDE_FILES.has(name)) return true;
1518
- if (isDirectory && EXCLUDE_DIRS.has(name)) return true;
1780
+ const isExcluded$1 = (name, isDirectory = false) => {
1781
+ if (EXCLUDE_FILES$1.has(name)) return true;
1782
+ if (isDirectory && EXCLUDE_DIRS$1.has(name)) return true;
1519
1783
  return false;
1520
1784
  };
1521
1785
  async function copyDirectory(src, dest) {
1522
1786
  await mkdir(dest, { recursive: true });
1523
1787
  const entries = await readdir(src, { withFileTypes: true });
1524
- await Promise.all(entries.filter((entry) => !isExcluded(entry.name, entry.isDirectory())).map(async (entry) => {
1788
+ await Promise.all(entries.filter((entry) => !isExcluded$1(entry.name, entry.isDirectory())).map(async (entry) => {
1525
1789
  const srcPath = join(src, entry.name);
1526
1790
  const destPath = join(dest, entry.name);
1527
1791
  if (entry.isDirectory()) await copyDirectory(srcPath, destPath);
@@ -1542,7 +1806,7 @@ async function isSkillInstalled(skillName, agentType, options = {}) {
1542
1806
  if (options.global && agent.globalSkillsDir === void 0) return false;
1543
1807
  const targetBase = options.global ? agent.globalSkillsDir : join(options.cwd || process.cwd(), agent.skillsDir);
1544
1808
  const skillDir = join(targetBase, sanitized);
1545
- if (!isPathSafe(targetBase, skillDir)) return false;
1809
+ if (!isPathSafe$1(targetBase, skillDir)) return false;
1546
1810
  try {
1547
1811
  await access(skillDir);
1548
1812
  return true;
@@ -1556,14 +1820,14 @@ function getInstallPath(skillName, agentType, options = {}) {
1556
1820
  const sanitized = sanitizeName(skillName);
1557
1821
  const targetBase = getAgentBaseDir(agentType, options.global ?? false, options.cwd);
1558
1822
  const installPath = join(targetBase, sanitized);
1559
- if (!isPathSafe(targetBase, installPath)) throw new Error("Invalid skill name: potential path traversal detected");
1823
+ if (!isPathSafe$1(targetBase, installPath)) throw new Error("Invalid skill name: potential path traversal detected");
1560
1824
  return installPath;
1561
1825
  }
1562
1826
  function getCanonicalPath(skillName, options = {}) {
1563
1827
  const sanitized = sanitizeName(skillName);
1564
1828
  const canonicalBase = getCanonicalSkillsDir(options.global ?? false, options.cwd);
1565
1829
  const canonicalPath = join(canonicalBase, sanitized);
1566
- if (!isPathSafe(canonicalBase, canonicalPath)) throw new Error("Invalid skill name: potential path traversal detected");
1830
+ if (!isPathSafe$1(canonicalBase, canonicalPath)) throw new Error("Invalid skill name: potential path traversal detected");
1567
1831
  return canonicalPath;
1568
1832
  }
1569
1833
  async function installWellKnownSkillForAgent(skill, agentType, options = {}) {
@@ -1582,13 +1846,13 @@ async function installWellKnownSkillForAgent(skill, agentType, options = {}) {
1582
1846
  const canonicalDir = join(canonicalBase, skillName);
1583
1847
  const agentBase = getAgentBaseDir(agentType, isGlobal, cwd);
1584
1848
  const agentDir = join(agentBase, skillName);
1585
- if (!isPathSafe(canonicalBase, canonicalDir)) return {
1849
+ if (!isPathSafe$1(canonicalBase, canonicalDir)) return {
1586
1850
  success: false,
1587
1851
  path: agentDir,
1588
1852
  mode: installMode,
1589
1853
  error: "Invalid skill name: potential path traversal detected"
1590
1854
  };
1591
- if (!isPathSafe(agentBase, agentDir)) return {
1855
+ if (!isPathSafe$1(agentBase, agentDir)) return {
1592
1856
  success: false,
1593
1857
  path: agentDir,
1594
1858
  mode: installMode,
@@ -1597,7 +1861,7 @@ async function installWellKnownSkillForAgent(skill, agentType, options = {}) {
1597
1861
  async function writeSkillFiles(targetDir) {
1598
1862
  for (const [filePath, content] of skill.files) {
1599
1863
  const fullPath = join(targetDir, filePath);
1600
- if (!isPathSafe(targetDir, fullPath)) continue;
1864
+ if (!isPathSafe$1(targetDir, fullPath)) continue;
1601
1865
  const parentDir = dirname(fullPath);
1602
1866
  if (parentDir !== targetDir) await mkdir(parentDir, { recursive: true });
1603
1867
  await writeFile(fullPath, content);
@@ -1663,13 +1927,13 @@ async function installBlobSkillForAgent(skill, agentType, options = {}) {
1663
1927
  const canonicalDir = join(canonicalBase, skillName);
1664
1928
  const agentBase = getAgentBaseDir(agentType, isGlobal, cwd);
1665
1929
  const agentDir = join(agentBase, skillName);
1666
- if (!isPathSafe(canonicalBase, canonicalDir)) return {
1930
+ if (!isPathSafe$1(canonicalBase, canonicalDir)) return {
1667
1931
  success: false,
1668
1932
  path: agentDir,
1669
1933
  mode: installMode,
1670
1934
  error: "Invalid skill name: potential path traversal detected"
1671
1935
  };
1672
- if (!isPathSafe(agentBase, agentDir)) return {
1936
+ if (!isPathSafe$1(agentBase, agentDir)) return {
1673
1937
  success: false,
1674
1938
  path: agentDir,
1675
1939
  mode: installMode,
@@ -1678,7 +1942,7 @@ async function installBlobSkillForAgent(skill, agentType, options = {}) {
1678
1942
  async function writeSkillFiles(targetDir) {
1679
1943
  for (const file of skill.files) {
1680
1944
  const fullPath = join(targetDir, file.path);
1681
- if (!isPathSafe(targetDir, fullPath)) continue;
1945
+ if (!isPathSafe$1(targetDir, fullPath)) continue;
1682
1946
  const parentDir = dirname(fullPath);
1683
1947
  if (parentDir !== targetDir) await mkdir(parentDir, { recursive: true });
1684
1948
  await writeFile(fullPath, file.contents, "utf-8");
@@ -1810,7 +2074,7 @@ async function listInstalledSkills(options = {}) {
1810
2074
  for (const agentType of agentsToCheck) {
1811
2075
  const agent = agents[agentType];
1812
2076
  if (scope.global && agent.globalSkillsDir === void 0) continue;
1813
- const agentBase = scope.global ? agent.globalSkillsDir : join(cwd, agent.skillsDir);
2077
+ const agentBase = getAgentBaseDir(agentType, scope.global, cwd);
1814
2078
  let found = false;
1815
2079
  const possibleNames = Array.from(new Set([
1816
2080
  entry.name,
@@ -1819,7 +2083,7 @@ async function listInstalledSkills(options = {}) {
1819
2083
  ]));
1820
2084
  for (const possibleName of possibleNames) {
1821
2085
  const agentSkillDir = join(agentBase, possibleName);
1822
- if (!isPathSafe(agentBase, agentSkillDir)) continue;
2086
+ if (!isPathSafe$1(agentBase, agentSkillDir)) continue;
1823
2087
  try {
1824
2088
  await access(agentSkillDir);
1825
2089
  found = true;
@@ -1831,7 +2095,7 @@ async function listInstalledSkills(options = {}) {
1831
2095
  for (const agentEntry of agentEntries) {
1832
2096
  const candidateDir = join(agentBase, agentEntry.name);
1833
2097
  if (!await isDirEntryOrSymlinkToDir(agentEntry, candidateDir)) continue;
1834
- if (!isPathSafe(agentBase, candidateDir)) continue;
2098
+ if (!isPathSafe$1(agentBase, candidateDir)) continue;
1835
2099
  try {
1836
2100
  const candidateSkillMd = join(candidateDir, "SKILL.md");
1837
2101
  await stat(candidateSkillMd);
@@ -2754,7 +3018,7 @@ async function tryBlobInstall(ownerRepo, options = {}) {
2754
3018
  tree
2755
3019
  };
2756
3020
  }
2757
- var version$1 = "1.5.9";
3021
+ var version$1 = "1.5.10";
2758
3022
  const isCancelled$1 = (value) => typeof value === "symbol";
2759
3023
  async function isSourcePrivate(source) {
2760
3024
  const ownerRepo = parseOwnerRepo(source);
@@ -2894,13 +3158,15 @@ async function promptForAgents(message, choices) {
2894
3158
  async function selectAgentsInteractive(options) {
2895
3159
  const supportsGlobalFilter = (a) => !options.global || agents[a].globalSkillsDir;
2896
3160
  const universalAgents = getUniversalAgents().filter(supportsGlobalFilter);
3161
+ const visibleUniversalAgents = getVisibleUniversalAgents().filter(supportsGlobalFilter);
2897
3162
  const otherAgents = getNonUniversalAgents().filter(supportsGlobalFilter);
2898
3163
  const universalSection = {
2899
3164
  title: "Universal (.agents/skills)",
2900
- items: universalAgents.map((a) => ({
3165
+ items: visibleUniversalAgents.map((a) => ({
2901
3166
  value: a,
2902
3167
  label: agents[a].displayName
2903
- }))
3168
+ })),
3169
+ hiddenCount: universalAgents.length - visibleUniversalAgents.length
2904
3170
  };
2905
3171
  const otherChoices = otherAgents.map((a) => ({
2906
3172
  value: a,
@@ -4210,6 +4476,7 @@ async function runSync(args, options = {}) {
4210
4476
  let targetAgents;
4211
4477
  const validAgents = Object.keys(agents);
4212
4478
  const universalAgents = getUniversalAgents();
4479
+ const visibleUniversalAgents = getVisibleUniversalAgents();
4213
4480
  if (options.agent?.includes("*")) {
4214
4481
  targetAgents = validAgents;
4215
4482
  M.info(`Installing to all ${targetAgents.length} agents`);
@@ -4240,10 +4507,11 @@ async function runSync(args, options = {}) {
4240
4507
  initialSelected: [],
4241
4508
  lockedSection: {
4242
4509
  title: "Universal (.agents/skills)",
4243
- items: universalAgents.map((a) => ({
4510
+ items: visibleUniversalAgents.map((a) => ({
4244
4511
  value: a,
4245
4512
  label: agents[a].displayName
4246
- }))
4513
+ })),
4514
+ hiddenCount: universalAgents.length - visibleUniversalAgents.length
4247
4515
  }
4248
4516
  });
4249
4517
  if (isCancelled(selected)) {
@@ -4266,10 +4534,11 @@ async function runSync(args, options = {}) {
4266
4534
  initialSelected: installedAgents.filter((a) => !universalAgents.includes(a)),
4267
4535
  lockedSection: {
4268
4536
  title: "Universal (.agents/skills)",
4269
- items: universalAgents.map((a) => ({
4537
+ items: visibleUniversalAgents.map((a) => ({
4270
4538
  value: a,
4271
4539
  label: agents[a].displayName
4272
- }))
4540
+ })),
4541
+ hiddenCount: universalAgents.length - visibleUniversalAgents.length
4273
4542
  }
4274
4543
  });
4275
4544
  if (isCancelled(selected)) {
@@ -4500,13 +4769,14 @@ async function runList(args) {
4500
4769
  else console.log(`${DIM$2}Try listing global skills with -g${RESET$2}`);
4501
4770
  return;
4502
4771
  }
4503
- function printSkill(skill, indent = false) {
4772
+ function printSkill(skill, indent = false, maxNameLength = 0, maxPathLength = 0) {
4504
4773
  const prefix = indent ? " " : "";
4505
4774
  const shortPath = shortenPath(skill.canonicalPath, cwd);
4506
4775
  const agentNames = skill.agents.map((a) => agents[a].displayName);
4507
4776
  const agentInfo = skill.agents.length > 0 ? formatList(agentNames) : `${YELLOW}not linked${RESET$2}`;
4508
- console.log(`${prefix}${CYAN}${sanitizeMetadata(skill.name)}${RESET$2} ${DIM$2}${shortPath}${RESET$2}`);
4509
- console.log(`${prefix} ${DIM$2}Agents:${RESET$2} ${agentInfo}`);
4777
+ const paddedName = sanitizeMetadata(skill.name).padEnd(maxNameLength);
4778
+ const paddedPath = shortPath.padEnd(maxPathLength);
4779
+ console.log(`${prefix}${CYAN}${paddedName}${RESET$2} ${DIM$2}${paddedPath}${RESET$2} ${DIM$2}Agents:${RESET$2} ${agentInfo}`);
4510
4780
  }
4511
4781
  console.log(`${BOLD$2}${scopeLabel} Skills${RESET$2}`);
4512
4782
  console.log();
@@ -4526,16 +4796,42 @@ async function runList(args) {
4526
4796
  const title = group.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
4527
4797
  console.log(`${BOLD$2}${title}${RESET$2}`);
4528
4798
  const skills = groupedSkills[group];
4529
- if (skills) for (const skill of skills) printSkill(skill, true);
4799
+ if (skills) {
4800
+ let maxNameLength = 0;
4801
+ let maxPathLength = 0;
4802
+ for (const skill of skills) {
4803
+ const nameLength = sanitizeMetadata(skill.name).length;
4804
+ const pathLength = shortenPath(skill.canonicalPath, cwd).length;
4805
+ if (nameLength > maxNameLength) maxNameLength = nameLength;
4806
+ if (pathLength > maxPathLength) maxPathLength = pathLength;
4807
+ }
4808
+ for (const skill of skills) printSkill(skill, true, maxNameLength, maxPathLength);
4809
+ }
4530
4810
  console.log();
4531
4811
  }
4532
4812
  if (ungroupedSkills.length > 0) {
4533
4813
  console.log(`${BOLD$2}General${RESET$2}`);
4534
- for (const skill of ungroupedSkills) printSkill(skill, true);
4814
+ let maxNameLength = 0;
4815
+ let maxPathLength = 0;
4816
+ for (const skill of ungroupedSkills) {
4817
+ const nameLength = sanitizeMetadata(skill.name).length;
4818
+ const pathLength = shortenPath(skill.canonicalPath, cwd).length;
4819
+ if (nameLength > maxNameLength) maxNameLength = nameLength;
4820
+ if (pathLength > maxPathLength) maxPathLength = pathLength;
4821
+ }
4822
+ for (const skill of ungroupedSkills) printSkill(skill, true, maxNameLength, maxPathLength);
4535
4823
  console.log();
4536
4824
  }
4537
4825
  } else {
4538
- for (const skill of installedSkills) printSkill(skill);
4826
+ let maxNameLength = 0;
4827
+ let maxPathLength = 0;
4828
+ for (const skill of installedSkills) {
4829
+ const nameLength = sanitizeMetadata(skill.name).length;
4830
+ const pathLength = shortenPath(skill.canonicalPath, cwd).length;
4831
+ if (nameLength > maxNameLength) maxNameLength = nameLength;
4832
+ if (pathLength > maxPathLength) maxPathLength = pathLength;
4833
+ }
4834
+ for (const skill of installedSkills) printSkill(skill, false, maxNameLength, maxPathLength);
4539
4835
  console.log();
4540
4836
  }
4541
4837
  }
@@ -4745,7 +5041,19 @@ function deriveSkillFolder(skillPath) {
4745
5041
  if (folder.endsWith("/")) folder = folder.slice(0, -1);
4746
5042
  return folder;
4747
5043
  }
5044
+ function supportsAppendedSubpath(source) {
5045
+ if (source.startsWith("git@")) return false;
5046
+ if (source.endsWith(".git")) return false;
5047
+ if (source.startsWith("http://") || source.startsWith("https://")) try {
5048
+ const host = new URL(source).hostname;
5049
+ return host === "github.com" || host === "gitlab.com";
5050
+ } catch {
5051
+ return false;
5052
+ }
5053
+ return true;
5054
+ }
4748
5055
  function appendFolderAndRef(source, skillPath, ref) {
5056
+ if (!supportsAppendedSubpath(source)) return formatSourceInput(source, ref);
4749
5057
  const folder = deriveSkillFolder(skillPath);
4750
5058
  const withFolder = folder ? `${source}/${folder}` : source;
4751
5059
  return ref ? `${withFolder}#${ref}` : withFolder;
@@ -4946,13 +5254,21 @@ async function updateGlobalSkills(options = {}) {
4946
5254
  }
4947
5255
  for (const [source, itemsForSource] of bySource) {
4948
5256
  const firstEntry = itemsForSource[0].entry;
5257
+ const sourceUrl = firstEntry.sourceUrl || firstEntry.source;
5258
+ let tempDir = null;
4949
5259
  process.stdout.write(`\r${DIM$1}Checking skills from source: ${source}${RESET$1}\x1b[K\n`);
4950
5260
  try {
4951
- const tree = await fetchRepoTree(source, firstEntry.ref, getGitHubToken);
4952
- if (tree) {
5261
+ if (firstEntry.sourceType === "github") {
5262
+ const tree = await fetchRepoTree(source, firstEntry.ref, getGitHubToken);
5263
+ if (!tree) {
5264
+ console.log(` ${DIM$1}✗ Failed to fetch tree for ${source}${RESET$1}`);
5265
+ continue;
5266
+ }
4953
5267
  const discoveredPaths = findSkillMdPaths(tree);
4954
- await checkAndPromptForDeletions(source, Object.entries(lock.skills).filter(([_, entry]) => entry.source === source).map(([name, _]) => name), lock.skills, true, options, discoveredPaths);
5268
+ const deletedSkills = await checkAndPromptForDeletions(source, Object.entries(lock.skills).filter(([_, entry]) => entry.source === source).map(([name, _]) => name), lock.skills, true, options, discoveredPaths);
5269
+ const deletedSkillSet = new Set(deletedSkills);
4955
5270
  for (const { name: skillName, entry } of itemsForSource) {
5271
+ if (deletedSkillSet.has(skillName)) continue;
4956
5272
  const latestHash = getSkillFolderHashFromTree(tree, entry.skillPath);
4957
5273
  if (latestHash && latestHash !== entry.skillFolderHash) updates.push({
4958
5274
  name: skillName,
@@ -4960,9 +5276,29 @@ async function updateGlobalSkills(options = {}) {
4960
5276
  entry
4961
5277
  });
4962
5278
  }
4963
- } else console.log(` ${DIM$1}✗ Failed to fetch tree for ${source}${RESET$1}`);
5279
+ continue;
5280
+ }
5281
+ tempDir = await cloneRepo(sourceUrl, firstEntry.ref);
5282
+ const discoveredPaths = (await discoverSkills(tempDir)).map((skill) => {
5283
+ return join(relative(tempDir, skill.path), "SKILL.md").split(sep).join("/");
5284
+ });
5285
+ const deletedSkills = await checkAndPromptForDeletions(source, Object.entries(lock.skills).filter(([_, entry]) => entry.source === source).map(([name, _]) => name), lock.skills, true, options, discoveredPaths);
5286
+ const deletedSkillSet = new Set(deletedSkills);
5287
+ for (const { name: skillName, entry } of itemsForSource) {
5288
+ if (deletedSkillSet.has(skillName)) continue;
5289
+ const skillPath = entry.skillPath;
5290
+ if (!discoveredPaths.includes(skillPath)) continue;
5291
+ const latestHash = await computeSkillFolderHash(join(tempDir, dirname(skillPath)));
5292
+ if (latestHash && latestHash !== entry.skillFolderHash) updates.push({
5293
+ name: skillName,
5294
+ source,
5295
+ entry
5296
+ });
5297
+ }
4964
5298
  } catch (error) {
4965
- console.log(` ${DIM$1}✗ Error checking skills from ${source}${RESET$1}`);
5299
+ console.log(` ${DIM$1}✗ Failed to check skills from ${source}${RESET$1}`);
5300
+ } finally {
5301
+ if (tempDir) await cleanupTempDir(tempDir);
4966
5302
  }
4967
5303
  }
4968
5304
  if (checkable.length > 0) process.stdout.write("\r\x1B[K");
@@ -5191,6 +5527,368 @@ async function runUpdate(args = []) {
5191
5527
  });
5192
5528
  console.log();
5193
5529
  }
5530
+ const BLOB_ALLOWED_OWNERS = [
5531
+ "vercel",
5532
+ "vercel-labs",
5533
+ "heygen-com"
5534
+ ];
5535
+ const EXCLUDE_FILES = new Set(["metadata.json"]);
5536
+ const EXCLUDE_DIRS = new Set([
5537
+ ".git",
5538
+ "__pycache__",
5539
+ "__pypackages__"
5540
+ ]);
5541
+ const USE_AGENT_CONFIGS = {
5542
+ "claude-code": {
5543
+ command: "claude",
5544
+ args: []
5545
+ },
5546
+ codex: {
5547
+ command: "codex",
5548
+ args: []
5549
+ }
5550
+ };
5551
+ const SUPPORTED_USE_AGENTS = Object.keys(USE_AGENT_CONFIGS);
5552
+ function parseUseOptions(args) {
5553
+ const source = [];
5554
+ const options = {};
5555
+ const errors = [];
5556
+ for (let i = 0; i < args.length; i++) {
5557
+ const arg = args[i];
5558
+ if (!arg) continue;
5559
+ if (arg === "--help" || arg === "-h") options.help = true;
5560
+ else if (arg === "--full-depth") options.fullDepth = true;
5561
+ else if (arg === "--dangerously-accept-openclaw-risks") options.dangerouslyAcceptOpenclawRisks = true;
5562
+ else if (arg === "--skill" || arg === "-s") {
5563
+ const value = args[i + 1];
5564
+ if (!value || value.startsWith("-")) errors.push(`${arg} requires a skill name`);
5565
+ else if (options.skill) {
5566
+ errors.push("Only one --skill value can be provided");
5567
+ i++;
5568
+ } else {
5569
+ options.skill = value;
5570
+ i++;
5571
+ }
5572
+ } else if (arg === "--agent" || arg === "-a") {
5573
+ options.agent = options.agent || [];
5574
+ i++;
5575
+ let nextArg = args[i];
5576
+ const startCount = options.agent.length;
5577
+ while (i < args.length && nextArg && !nextArg.startsWith("-")) {
5578
+ options.agent.push(nextArg);
5579
+ i++;
5580
+ nextArg = args[i];
5581
+ }
5582
+ if (options.agent.length === startCount) errors.push(`${arg} requires an agent name`);
5583
+ i--;
5584
+ } else if (arg.startsWith("-")) errors.push(`Unknown option: ${arg}`);
5585
+ else source.push(arg);
5586
+ }
5587
+ errors.push(...validateUseAgentOption(options.agent));
5588
+ return {
5589
+ source,
5590
+ options,
5591
+ errors
5592
+ };
5593
+ }
5594
+ function buildUsePrompt(input) {
5595
+ const sections = [
5596
+ "You are being given a Skill to execute for the user's next request.",
5597
+ "Use the following SKILL.md as your instructions:",
5598
+ `<SKILL.md>\n${input.skillMd}\n</SKILL.md>`
5599
+ ];
5600
+ if (input.hasSupportingFiles && input.supportDir) sections.push(`Supporting files for this skill were downloaded to:\n${input.supportDir}\n\nWhen the SKILL.md references relative paths, read them from that directory.`);
5601
+ return sections.join("\n\n") + "\n";
5602
+ }
5603
+ async function materializeUseSkill(skill) {
5604
+ const tempRoot = await mkdtemp(join(tmpdir(), "skills-use-"));
5605
+ const skillDir = join(tempRoot, sanitizeName(skill.directoryName || skill.name));
5606
+ if (!isPathSafe(tempRoot, skillDir)) throw new Error("Invalid skill name: potential path traversal detected");
5607
+ await mkdir(skillDir, { recursive: true });
5608
+ if (skill.kind === "blob") await writeSnapshotFiles(skillDir, skill.files);
5609
+ else if (skill.kind === "well-known") await writeMapFiles(skillDir, skill.files);
5610
+ else await copySkillDirectory(skill.path, skillDir);
5611
+ return {
5612
+ tempRoot,
5613
+ skillDir,
5614
+ skillMd: skill.rawContent ?? await readFile(join(skillDir, "SKILL.md"), "utf-8"),
5615
+ hasSupportingFiles: await containsSupportingFiles(skillDir, skillDir)
5616
+ };
5617
+ }
5618
+ async function runUse(sourceArgs, options = {}, parseErrors = []) {
5619
+ let cloneTempDir = null;
5620
+ try {
5621
+ if (options.help) {
5622
+ console.log(getUseHelp());
5623
+ return;
5624
+ }
5625
+ if (parseErrors.length > 0) fail(parseErrors.join("\n"));
5626
+ if (sourceArgs.length === 0) fail(`Missing required argument: source\n\n${getUseHelp()}`);
5627
+ if (sourceArgs.length > 1) fail(`Expected one source, received ${sourceArgs.length}: ${sourceArgs.join(", ")}`);
5628
+ const useAgent = options.agent?.[0];
5629
+ if (useAgent && !USE_AGENT_CONFIGS[useAgent]) fail(formatUnsupportedAgentError(useAgent));
5630
+ const source = sourceArgs[0];
5631
+ const parsed = parseSource(source);
5632
+ if (getOwnerRepo(parsed)?.split("/")[0]?.toLowerCase() === "openclaw" && !options.dangerouslyAcceptOpenclawRisks) fail([
5633
+ "OpenClaw skills are unverified community submissions.",
5634
+ "Skills run with full agent permissions and could be malicious.",
5635
+ `If you understand the risks, re-run with: skills use ${source} --dangerously-accept-openclaw-risks`
5636
+ ].join("\n"));
5637
+ const selector = resolveSelector(parsed.skillFilter, options.skill);
5638
+ const includeInternal = selector !== void 0;
5639
+ let selectedSkill;
5640
+ if (parsed.type === "well-known") selectedSkill = selectWellKnownSkill(await wellKnownProvider.fetchAllSkills(parsed.url), selector, source);
5641
+ else {
5642
+ let skills;
5643
+ let blobResult = null;
5644
+ if (parsed.type === "local") {
5645
+ if (!existsSync(parsed.localPath)) fail(`Local path does not exist: ${parsed.localPath}`);
5646
+ skills = await discoverSkills(parsed.localPath, parsed.subpath, {
5647
+ includeInternal,
5648
+ fullDepth: options.fullDepth
5649
+ });
5650
+ } else if (parsed.type === "github" && !options.fullDepth) {
5651
+ const ownerRepo = getOwnerRepo(parsed);
5652
+ const owner = ownerRepo?.split("/")[0]?.toLowerCase();
5653
+ if (ownerRepo && owner && BLOB_ALLOWED_OWNERS.includes(owner)) blobResult = await tryBlobInstall(ownerRepo, {
5654
+ subpath: parsed.subpath,
5655
+ skillFilter: selector,
5656
+ ref: parsed.ref,
5657
+ getToken: getGitHubToken,
5658
+ includeInternal
5659
+ });
5660
+ if (blobResult) skills = blobResult.skills;
5661
+ else {
5662
+ cloneTempDir = await cloneRepo(parsed.url, parsed.ref);
5663
+ skills = await discoverSkills(cloneTempDir, parsed.subpath, {
5664
+ includeInternal,
5665
+ fullDepth: options.fullDepth
5666
+ });
5667
+ }
5668
+ } else {
5669
+ cloneTempDir = await cloneRepo(parsed.url, parsed.ref);
5670
+ skills = await discoverSkills(cloneTempDir, parsed.subpath, {
5671
+ includeInternal,
5672
+ fullDepth: options.fullDepth
5673
+ });
5674
+ }
5675
+ const selected = selectSkill(skills, selector, source);
5676
+ if (blobResult && isBlobSkill(selected)) selectedSkill = {
5677
+ kind: "blob",
5678
+ name: selected.name,
5679
+ directoryName: selected.name,
5680
+ rawContent: selected.rawContent ?? getSkillMdFromSnapshot(selected.files),
5681
+ files: selected.files
5682
+ };
5683
+ else selectedSkill = {
5684
+ kind: "disk",
5685
+ name: selected.name,
5686
+ directoryName: selected.name,
5687
+ rawContent: selected.rawContent,
5688
+ path: selected.path
5689
+ };
5690
+ }
5691
+ const materialized = await materializeUseSkill(selectedSkill);
5692
+ await cleanupClone(cloneTempDir);
5693
+ cloneTempDir = null;
5694
+ const prompt = buildUsePrompt({
5695
+ skillMd: materialized.skillMd,
5696
+ supportDir: materialized.skillDir,
5697
+ hasSupportingFiles: materialized.hasSupportingFiles
5698
+ });
5699
+ if (useAgent) {
5700
+ const exitCode = await launchAgentInteractively(useAgent, prompt);
5701
+ if (exitCode !== 0) process.exit(exitCode);
5702
+ return;
5703
+ }
5704
+ process.stdout.write(prompt);
5705
+ } catch (error) {
5706
+ await cleanupClone(cloneTempDir);
5707
+ if (error instanceof GitCloneError) fail(error.message);
5708
+ if (error instanceof UseCommandError) fail(error.message);
5709
+ fail(error instanceof Error ? error.message : "Unknown error");
5710
+ }
5711
+ }
5712
+ async function launchAgentInteractively(agent, prompt, spawnImpl = spawnAgent) {
5713
+ const config = USE_AGENT_CONFIGS[agent];
5714
+ if (!config) throw new UseCommandError(formatUnsupportedAgentError(agent));
5715
+ return new Promise((resolve, reject) => {
5716
+ const child = spawnImpl(config.command, [...config.args, prompt], { stdio: "inherit" });
5717
+ let settled = false;
5718
+ child.on("error", (error) => {
5719
+ if (settled) return;
5720
+ settled = true;
5721
+ if (error.code === "ENOENT") {
5722
+ reject(new UseCommandError(`Could not launch ${agents[agent].displayName}: command not found: ${config.command}`));
5723
+ return;
5724
+ }
5725
+ reject(error);
5726
+ });
5727
+ child.on("close", (code) => {
5728
+ if (settled) return;
5729
+ settled = true;
5730
+ resolve(code ?? 1);
5731
+ });
5732
+ });
5733
+ }
5734
+ function spawnAgent(command, args) {
5735
+ return spawn(command, args, { stdio: "inherit" });
5736
+ }
5737
+ function getUseHelp() {
5738
+ return `Usage: skills use <source>[@<skill>] [options]
5739
+
5740
+ Generate a prompt for using one skill without installing it.
5741
+
5742
+ Options:
5743
+ -s, --skill <skill> Select the skill to use
5744
+ -a, --agent <agent> Start one supported agent interactively (${SUPPORTED_USE_AGENTS.join(", ")})
5745
+ --full-depth Search nested directories like skills add --full-depth
5746
+ --dangerously-accept-openclaw-risks
5747
+ Allow unverified OpenClaw community skills
5748
+ -h, --help Show this help message
5749
+
5750
+ Examples:
5751
+ skills use vercel-labs/agent-skills@nextjs | claude
5752
+ skills use vercel-labs/agent-skills --skill nextjs --agent claude-code
5753
+ skills use vercel-labs/agent-skills@nextjs --agent codex`;
5754
+ }
5755
+ function resolveSelector(sourceSelector, optionSelector) {
5756
+ if (sourceSelector && optionSelector) {
5757
+ if (sourceSelector.toLowerCase() !== optionSelector.toLowerCase()) throw new UseCommandError(`Conflicting skill selectors: source selects "${sourceSelector}" but --skill selects "${optionSelector}". Provide one selector.`);
5758
+ return optionSelector;
5759
+ }
5760
+ return optionSelector ?? sourceSelector;
5761
+ }
5762
+ function selectSkill(skills, selector, source) {
5763
+ if (skills.length === 0) throw new UseCommandError("No valid skills found. Skills require a SKILL.md with name and description.");
5764
+ if (!selector) {
5765
+ if (skills.length === 1) return skills[0];
5766
+ throw new UseCommandError(formatMultipleSkillsError(source, skills.map(getSkillDisplayName)));
5767
+ }
5768
+ const selected = filterSkills(skills, [selector]);
5769
+ if (selected.length === 0) throw new UseCommandError(formatNoMatchError(selector, skills.map(getSkillDisplayName)));
5770
+ if (selected.length > 1) throw new UseCommandError(`Skill selector "${selector}" matched multiple skills.`);
5771
+ return selected[0];
5772
+ }
5773
+ function selectWellKnownSkill(skills, selector, source) {
5774
+ if (skills.length === 0) throw new UseCommandError("No skills found at this URL. Make sure the server has a /.well-known/agent-skills/index.json or /.well-known/skills/index.json file.");
5775
+ let selected;
5776
+ if (!selector) {
5777
+ if (skills.length !== 1) throw new UseCommandError(formatMultipleSkillsError(source, skills.map((s) => s.installName)));
5778
+ selected = skills;
5779
+ } else {
5780
+ selected = skills.filter((skill) => skill.installName.toLowerCase() === selector.toLowerCase() || skill.name.toLowerCase() === selector.toLowerCase());
5781
+ if (selected.length === 0) throw new UseCommandError(formatNoMatchError(selector, skills.map((s) => s.installName)));
5782
+ if (selected.length > 1) throw new UseCommandError(`Skill selector "${selector}" matched multiple skills.`);
5783
+ }
5784
+ const skill = selected[0];
5785
+ return {
5786
+ kind: "well-known",
5787
+ name: skill.name,
5788
+ directoryName: skill.installName,
5789
+ rawContent: skill.content,
5790
+ files: skill.files
5791
+ };
5792
+ }
5793
+ function formatMultipleSkillsError(source, names) {
5794
+ return [
5795
+ "This source contains multiple skills. Specify exactly one skill:",
5796
+ ...names.map((name) => ` - ${name}`),
5797
+ "",
5798
+ `Examples:\n skills use ${source}@${names[0] ?? "<skill>"}\n skills use ${source} --skill ${names[0] ?? "<skill>"}`
5799
+ ].join("\n");
5800
+ }
5801
+ function formatNoMatchError(selector, names) {
5802
+ return [
5803
+ `No matching skill found for: ${selector}`,
5804
+ "Available skills:",
5805
+ ...names.map((name) => ` - ${name}`)
5806
+ ].join("\n");
5807
+ }
5808
+ function validateUseAgentOption(agentValues) {
5809
+ if (!agentValues || agentValues.length === 0) return [];
5810
+ const errors = [];
5811
+ const validAgents = Object.keys(agents);
5812
+ const invalidAgents = agentValues.filter((agent) => agent !== "*" && !validAgents.includes(agent));
5813
+ if (agentValues.includes("*")) errors.push("skills use --agent does not support '*'; specify exactly one agent.");
5814
+ if (agentValues.length > 1) errors.push("skills use --agent accepts exactly one agent.");
5815
+ if (invalidAgents.length > 0) errors.push(`Invalid agents: ${invalidAgents.join(", ")}\nValid agents: ${validAgents.join(", ")}`);
5816
+ return errors;
5817
+ }
5818
+ function formatUnsupportedAgentError(agent) {
5819
+ return [`Running ${agents[agent].displayName} is not supported yet.`, `Supported agents for skills use --agent: ${SUPPORTED_USE_AGENTS.join(", ")}`].join("\n");
5820
+ }
5821
+ async function writeSnapshotFiles(targetDir, files) {
5822
+ for (const file of files) await writeSafeFile(targetDir, file.path, file.contents);
5823
+ }
5824
+ async function writeMapFiles(targetDir, files) {
5825
+ for (const [path, contents] of files) await writeSafeFile(targetDir, path, contents);
5826
+ }
5827
+ async function writeSafeFile(targetDir, filePath, contents) {
5828
+ const fullPath = join(targetDir, filePath);
5829
+ if (!isPathSafe(targetDir, fullPath)) return;
5830
+ await mkdir(dirname(fullPath), { recursive: true });
5831
+ if (typeof contents === "string") await writeFile(fullPath, contents, "utf-8");
5832
+ else await writeFile(fullPath, contents);
5833
+ }
5834
+ async function copySkillDirectory(src, dest) {
5835
+ await mkdir(dest, { recursive: true });
5836
+ const entries = await readdir(src, { withFileTypes: true });
5837
+ await Promise.all(entries.filter((entry) => !isExcluded(entry.name, entry.isDirectory())).map(async (entry) => {
5838
+ const srcPath = join(src, entry.name);
5839
+ const destPath = join(dest, entry.name);
5840
+ if (!isPathSafe(dest, destPath)) return;
5841
+ if (entry.isDirectory()) {
5842
+ await copySkillDirectory(srcPath, destPath);
5843
+ return;
5844
+ }
5845
+ try {
5846
+ await cp(srcPath, destPath, {
5847
+ dereference: true,
5848
+ recursive: true
5849
+ });
5850
+ } catch (err) {
5851
+ if (err instanceof Error && "code" in err && err.code === "ENOENT" && entry.isSymbolicLink()) {
5852
+ console.error(`Skipping broken symlink: ${srcPath}`);
5853
+ return;
5854
+ }
5855
+ throw err;
5856
+ }
5857
+ }));
5858
+ }
5859
+ async function containsSupportingFiles(rootDir, currentDir) {
5860
+ const entries = await readdir(currentDir, { withFileTypes: true });
5861
+ for (const entry of entries) {
5862
+ const entryPath = join(currentDir, entry.name);
5863
+ const relPath = relative(rootDir, entryPath).split(sep).join("/");
5864
+ if (entry.isDirectory()) {
5865
+ if (await containsSupportingFiles(rootDir, entryPath)) return true;
5866
+ } else if (relPath.toLowerCase() !== "skill.md") return true;
5867
+ }
5868
+ return false;
5869
+ }
5870
+ function isBlobSkill(skill) {
5871
+ return Array.isArray(skill.files);
5872
+ }
5873
+ function getSkillMdFromSnapshot(files) {
5874
+ return files.find((file) => file.path.toLowerCase() === "skill.md")?.contents ?? "";
5875
+ }
5876
+ function isExcluded(name, isDirectory) {
5877
+ return EXCLUDE_FILES.has(name) || isDirectory && EXCLUDE_DIRS.has(name);
5878
+ }
5879
+ function isPathSafe(basePath, targetPath) {
5880
+ const normalizedBase = normalize(resolve(basePath));
5881
+ const normalizedTarget = normalize(resolve(targetPath));
5882
+ return normalizedTarget.startsWith(normalizedBase + sep) || normalizedTarget === normalizedBase;
5883
+ }
5884
+ async function cleanupClone(tempDir) {
5885
+ if (tempDir) await cleanupTempDir(tempDir).catch(() => {});
5886
+ }
5887
+ function fail(message) {
5888
+ console.error(message);
5889
+ process.exit(1);
5890
+ }
5891
+ var UseCommandError = class extends Error {};
5194
5892
  const __dirname = dirname(fileURLToPath(import.meta.url));
5195
5893
  function getVersion() {
5196
5894
  try {
@@ -5234,6 +5932,7 @@ function showBanner() {
5234
5932
  console.log(`${DIM}The open agent skills ecosystem${RESET}`);
5235
5933
  console.log();
5236
5934
  console.log(` ${DIM}$${RESET} ${TEXT}npx skills add ${DIM}<package>${RESET} ${DIM}Add a new skill${RESET}`);
5935
+ console.log(` ${DIM}$${RESET} ${TEXT}npx skills use ${DIM}<package>@<skill>${RESET} ${DIM}Use a skill without installing${RESET}`);
5237
5936
  console.log(` ${DIM}$${RESET} ${TEXT}npx skills remove${RESET} ${DIM}Remove installed skills${RESET}`);
5238
5937
  console.log(` ${DIM}$${RESET} ${TEXT}npx skills list${RESET} ${DIM}List installed skills${RESET}`);
5239
5938
  console.log(` ${DIM}$${RESET} ${TEXT}npx skills find ${DIM}[query]${RESET} ${DIM}Search for skills${RESET}`);
@@ -5257,6 +5956,8 @@ ${BOLD}Manage Skills:${RESET}
5257
5956
  add <package> Add a skill package (alias: a)
5258
5957
  e.g. vercel-labs/agent-skills
5259
5958
  https://github.com/vercel-labs/agent-skills
5959
+ use <package>@<skill>
5960
+ Generate a prompt for using one skill without installing it
5260
5961
  remove [skills] Remove installed skills
5261
5962
  list, ls List installed skills
5262
5963
  find [query] Search for skills interactively
@@ -5284,6 +5985,13 @@ ${BOLD}Add Options:${RESET}
5284
5985
  --all Shorthand for --skill '*' --agent '*' -y
5285
5986
  --full-depth Search all subdirectories even when a root SKILL.md exists
5286
5987
 
5988
+ ${BOLD}Use Options:${RESET}
5989
+ -s, --skill <skill> Specify the skill to use
5990
+ -a, --agent <agent> Start one supported agent interactively
5991
+ --full-depth Search all subdirectories even when a root SKILL.md exists
5992
+ --dangerously-accept-openclaw-risks
5993
+ Allow unverified OpenClaw community skills
5994
+
5287
5995
  ${BOLD}Remove Options:${RESET}
5288
5996
  -g, --global Remove from global scope
5289
5997
  -a, --agent <agents> Remove from specific agents (use '*' for all agents)
@@ -5306,6 +6014,8 @@ ${BOLD}Options:${RESET}
5306
6014
 
5307
6015
  ${BOLD}Examples:${RESET}
5308
6016
  ${DIM}$${RESET} skills add vercel-labs/agent-skills
6017
+ ${DIM}$${RESET} skills use vercel-labs/agent-skills@vercel-optimize | claude
6018
+ ${DIM}$${RESET} skills use vercel-labs/agent-skills --skill vercel-optimize --agent claude-code
5309
6019
  ${DIM}$${RESET} skills add vercel-labs/agent-skills -g
5310
6020
  ${DIM}$${RESET} skills add vercel-labs/agent-skills --agent claude-code cursor
5311
6021
  ${DIM}$${RESET} skills add vercel-labs/agent-skills --skill pr-review commit
@@ -5442,6 +6152,11 @@ async function main() {
5442
6152
  await runAdd(addSource, addOpts);
5443
6153
  break;
5444
6154
  }
6155
+ case "use": {
6156
+ const { source: useSource, options: useOptions, errors: useErrors } = parseUseOptions(restArgs);
6157
+ await runUse(useSource, useOptions, useErrors);
6158
+ break;
6159
+ }
5445
6160
  case "remove":
5446
6161
  case "rm":
5447
6162
  case "r":
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skills",
3
- "version": "1.5.9",
3
+ "version": "1.5.10",
4
4
  "description": "The open agent skills ecosystem",
5
5
  "type": "module",
6
6
  "bin": {
@@ -39,6 +39,9 @@
39
39
  "aider-desk",
40
40
  "amp",
41
41
  "antigravity",
42
+ "antigravity-cli",
43
+ "astrbot",
44
+ "autohand-code",
42
45
  "augment",
43
46
  "bob",
44
47
  "claude-code",
@@ -64,31 +67,44 @@
64
67
  "github-copilot",
65
68
  "goose",
66
69
  "hermes-agent",
70
+ "inference-sh",
71
+ "jazz",
67
72
  "junie",
68
73
  "iflow-cli",
69
74
  "kilo",
70
- "kimi-cli",
75
+ "kimi-code-cli",
71
76
  "kiro-cli",
72
77
  "kode",
78
+ "lingma",
79
+ "loaf",
73
80
  "mcpjam",
74
81
  "mistral-vibe",
82
+ "moxby",
75
83
  "mux",
76
84
  "opencode",
77
85
  "openhands",
86
+ "ona",
78
87
  "pi",
79
88
  "qoder",
89
+ "qoder-cn",
80
90
  "qwen-code",
81
91
  "replit",
92
+ "reasonix",
82
93
  "rovodev",
83
94
  "roo",
84
95
  "tabnine-cli",
96
+ "terramind",
97
+ "tinycloud",
85
98
  "trae",
86
99
  "trae-cn",
87
100
  "warp",
88
101
  "windsurf",
102
+ "zed",
89
103
  "zencoder",
104
+ "zenflow",
90
105
  "neovate",
91
106
  "pochi",
107
+ "promptscript",
92
108
  "adal",
93
109
  "universal"
94
110
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dimcode-linux-arm64",
3
- "version": "0.0.78",
3
+ "version": "0.1.0",
4
4
  "description": "dimcode binary for Linux ARM64",
5
5
  "os": [
6
6
  "linux"