@kolatts/pncli 1.20.0 → 1.22.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/dist/cli.js CHANGED
@@ -20,7 +20,7 @@ import {
20
20
  success,
21
21
  warn,
22
22
  writeRawOutput
23
- } from "./chunk-PC4AHQCN.js";
23
+ } from "./chunk-PZWGOMIQ.js";
24
24
  import {
25
25
  AdoCoreClient
26
26
  } from "./chunk-VDL32PSG.js";
@@ -421,34 +421,34 @@ function parseAdoRemote(remoteUrl, adoBaseUrl) {
421
421
  } catch {
422
422
  baseHostname = adoBaseUrl.replace(/\/$/, "").replace(/^https?:\/\//, "").split(/[:/]/)[0].toLowerCase();
423
423
  }
424
- let path8 = remoteUrl;
424
+ let path9 = remoteUrl;
425
425
  let remoteHostname = "";
426
- const sshProtoMatch = path8.match(/^ssh:\/\/[^@]*@?([^/:]+)(?::\d+)?(.*)/);
426
+ const sshProtoMatch = path9.match(/^ssh:\/\/[^@]*@?([^/:]+)(?::\d+)?(.*)/);
427
427
  if (sshProtoMatch) {
428
428
  remoteHostname = sshProtoMatch[1].toLowerCase();
429
- path8 = sshProtoMatch[2];
429
+ path9 = sshProtoMatch[2];
430
430
  } else {
431
- const gitAtMatch = path8.match(/^git@([^:]+)(?::\d+)?:(.*)/);
431
+ const gitAtMatch = path9.match(/^git@([^:]+)(?::\d+)?:(.*)/);
432
432
  if (gitAtMatch) {
433
433
  remoteHostname = gitAtMatch[1].toLowerCase();
434
- path8 = "/" + gitAtMatch[2];
434
+ path9 = "/" + gitAtMatch[2];
435
435
  } else {
436
- const httpsMatch = path8.match(/^https?:\/\/([^/:]+)(?::\d+)?(.*)/);
436
+ const httpsMatch = path9.match(/^https?:\/\/([^/:]+)(?::\d+)?(.*)/);
437
437
  if (httpsMatch) {
438
438
  remoteHostname = httpsMatch[1].toLowerCase();
439
- path8 = httpsMatch[2];
439
+ path9 = httpsMatch[2];
440
440
  }
441
441
  }
442
442
  }
443
443
  if (!remoteHostname || remoteHostname !== baseHostname) return null;
444
- path8 = path8.replace(/\.git$/, "");
445
- const gitIdx = path8.indexOf("/_git/");
446
- const sshIdx = path8.indexOf("/_ssh/");
444
+ path9 = path9.replace(/\.git$/, "");
445
+ const gitIdx = path9.indexOf("/_git/");
446
+ const sshIdx = path9.indexOf("/_ssh/");
447
447
  const markerIdx = gitIdx !== -1 ? gitIdx : sshIdx;
448
448
  if (markerIdx === -1) return null;
449
- const repo = decodeURIComponent(path8.slice(markerIdx + 6));
449
+ const repo = decodeURIComponent(path9.slice(markerIdx + 6));
450
450
  if (!repo) return null;
451
- const before = path8.slice(1, markerIdx);
451
+ const before = path9.slice(1, markerIdx);
452
452
  const parts = before.split("/").filter(Boolean);
453
453
  if (parts.length < 2) return null;
454
454
  const project = decodeURIComponent(parts[parts.length - 1]);
@@ -744,6 +744,12 @@ var BitbucketClient = class {
744
744
  const pr = await this.getPR(project, repo, prId);
745
745
  return pr.reviewers;
746
746
  }
747
+ async addReviewer(project, repo, prId, username) {
748
+ return this.http.bitbucket(
749
+ `${API}/projects/${project}/repos/${repo}/pull-requests/${prId}/participants`,
750
+ { method: "POST", body: { user: { name: username }, role: "REVIEWER" } }
751
+ );
752
+ }
747
753
  async listBuilds(project, repo, prId) {
748
754
  const commits = await this.http.bitbucket(
749
755
  `${API}/projects/${project}/repos/${repo}/pull-requests/${prId}/commits`,
@@ -1384,6 +1390,13 @@ function getDefaults(program2) {
1384
1390
  priority: config.defaults.jira?.priority
1385
1391
  };
1386
1392
  }
1393
+ function resolveJqlInput(jql, jqlFile) {
1394
+ const raw = resolveTextInput(jql, jqlFile, "jql");
1395
+ if (raw === void 0) throw new PncliError("Must specify --jql or --jql-file", 1);
1396
+ const trimmed = raw.trim();
1397
+ if (!trimmed) throw new PncliError("JQL query is empty", 1);
1398
+ return trimmed;
1399
+ }
1387
1400
  function registerJiraCommands(program2) {
1388
1401
  const jira = program2.command("jira").description("Jira Data Cloud operations");
1389
1402
  jira.command("get-issue").description("Get a Jira issue by key").requiredOption("--key <issue-key>", "Issue key (e.g. PROJ-123)").action(async (opts) => {
@@ -1533,12 +1546,13 @@ function registerJiraCommands(program2) {
1533
1546
  fail(err, "jira", "list-comments", start);
1534
1547
  }
1535
1548
  });
1536
- jira.command("search").description("Search Jira issues with JQL (consider --output-file for large results)").requiredOption("--jql <query>", "JQL query string").option("--max-results <n>", "Maximum number of results").action(async (opts) => {
1549
+ jira.command("search").description("Search Jira issues with JQL (consider --output-file for large results)").option("--jql <query>", "JQL query string").option("--jql-file <path>", "Path to a file containing the JQL query ('-' = stdin)").option("--max-results <n>", "Maximum number of results").action(async (opts) => {
1537
1550
  const start = Date.now();
1538
1551
  try {
1539
1552
  const { client, fieldMap, customFields } = getClientAndFields(program2);
1553
+ const jql = resolveJqlInput(opts.jql, opts.jqlFile);
1540
1554
  const maxResults = opts.maxResults ? parseInt(opts.maxResults, 10) : void 0;
1541
- const translatedJql = translateJql(opts.jql, fieldMap);
1555
+ const translatedJql = translateJql(jql, fieldMap);
1542
1556
  const data = await client.search(translatedJql, maxResults, customFields);
1543
1557
  const translatedIssues = data.issues.map((issue) => ({
1544
1558
  ...issue,
@@ -1986,6 +2000,16 @@ function registerBitbucketCommands(program2) {
1986
2000
  fail(err, "bitbucket", "list-reviewers", start);
1987
2001
  }
1988
2002
  });
2003
+ bb.command("add-reviewer").description("Add a reviewer to a pull request").requiredOption("--pr <pr-id>", "Pull request ID").requiredOption("--user <username>", "Username to add as a reviewer").action(async (opts) => {
2004
+ const start = Date.now();
2005
+ try {
2006
+ const { client, project, repo } = getClient2(bb);
2007
+ const data = await client.addReviewer(project, repo, parseInt(opts.pr, 10), opts.user);
2008
+ success(data, "bitbucket", "add-reviewer", start);
2009
+ } catch (err) {
2010
+ fail(err, "bitbucket", "add-reviewer", start);
2011
+ }
2012
+ });
1989
2013
  bb.command("list-builds").description("List build statuses for a pull request").requiredOption("--pr <pr-id>", "Pull request ID").action(async (opts) => {
1990
2014
  const start = Date.now();
1991
2015
  try {
@@ -2200,8 +2224,8 @@ var GitHubClient = class {
2200
2224
  );
2201
2225
  }
2202
2226
  async createRepo(opts) {
2203
- const path8 = opts.org ? `/orgs/${opts.org}/repos` : "/user/repos";
2204
- return this.http.github(path8, {
2227
+ const path9 = opts.org ? `/orgs/${opts.org}/repos` : "/user/repos";
2228
+ return this.http.github(path9, {
2205
2229
  method: "POST",
2206
2230
  body: {
2207
2231
  name: opts.name,
@@ -2540,7 +2564,8 @@ function registerGitHubCommands(program2) {
2540
2564
  }
2541
2565
 
2542
2566
  // src/services/confluence/commands.ts
2543
- import { existsSync as existsSync2 } from "fs";
2567
+ import { existsSync as existsSync2, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
2568
+ import path2 from "path";
2544
2569
 
2545
2570
  // src/services/confluence/client.ts
2546
2571
  import { readFileSync as readFileSync4 } from "fs";
@@ -2702,6 +2727,19 @@ var ConfluenceClient = class {
2702
2727
  );
2703
2728
  return result.results;
2704
2729
  }
2730
+ async getAttachment(attachmentId) {
2731
+ return this.http.confluence(`${API3}/content/${attachmentId}`);
2732
+ }
2733
+ async downloadAttachment(attachment) {
2734
+ const downloadPath = attachment._links.download;
2735
+ if (!downloadPath) {
2736
+ throw new PncliError(
2737
+ `Content ${attachment.id} has no download link \u2014 is it an attachment? (title: ${attachment.title})`,
2738
+ 1
2739
+ );
2740
+ }
2741
+ return this.http.confluenceBuffer(downloadPath);
2742
+ }
2705
2743
  async deleteAttachment(attachmentId) {
2706
2744
  return this.http.confluence(`${API3}/content/${attachmentId}`, { method: "DELETE" });
2707
2745
  }
@@ -2721,6 +2759,11 @@ var ConfluenceClient = class {
2721
2759
  };
2722
2760
 
2723
2761
  // src/services/confluence/commands.ts
2762
+ function resolveAttachmentPath(outDir, title) {
2763
+ const segments = title.split(/[\\/]/).filter((s) => s !== "" && s !== "." && s !== "..");
2764
+ const name = segments.pop() ?? "attachment";
2765
+ return path2.join(outDir, name);
2766
+ }
2724
2767
  function xmlParseHint(err, bodyContent, convertedFromMarkdown = false) {
2725
2768
  if (!(err instanceof Error)) return null;
2726
2769
  const m = err.message.match(/at \[row,col\]=\{(\d+),(\d+)\}/);
@@ -2970,6 +3013,21 @@ ${hint}`, status, url), "confluence", "update-page", start);
2970
3013
  fail(err, "confluence", "upload-attachment", start);
2971
3014
  }
2972
3015
  });
3016
+ confluence.command("download-attachment").description("Download a Confluence attachment to .pncli/ (or --dir)").requiredOption("--id <attachment-id>", "Attachment content ID").option("--dir <path>", "Output directory (default: .pncli relative to cwd)").action(async (opts) => {
3017
+ const start = Date.now();
3018
+ try {
3019
+ const client = getClient4(program2);
3020
+ const attachment = await client.getAttachment(opts.id);
3021
+ const outDir = opts.dir ?? path2.join(process.cwd(), ".pncli");
3022
+ mkdirSync2(outDir, { recursive: true });
3023
+ const outPath = resolveAttachmentPath(outDir, attachment.title);
3024
+ const buffer = await client.downloadAttachment(attachment);
3025
+ writeFileSync2(outPath, buffer);
3026
+ success({ saved: outPath, filename: attachment.title, size: buffer.length }, "confluence", "download-attachment", start);
3027
+ } catch (err) {
3028
+ fail(err, "confluence", "download-attachment", start);
3029
+ }
3030
+ });
2973
3031
  confluence.command("delete-attachment").description("Delete an attachment from Confluence by its content ID (moves it to the trash; does not permanently purge it)").requiredOption("--id <attachment-id>", "Attachment content ID").action(async (opts) => {
2974
3032
  const start = Date.now();
2975
3033
  try {
@@ -3533,23 +3591,23 @@ import { Option as Option2 } from "commander";
3533
3591
 
3534
3592
  // src/services/deps/parsers/index.ts
3535
3593
  import fs from "fs";
3536
- import path5 from "path";
3594
+ import path6 from "path";
3537
3595
  import { execSync as execSync3, execFileSync as execFileSync2 } from "child_process";
3538
3596
 
3539
3597
  // src/services/deps/parsers/npm.ts
3540
- import path2 from "path";
3598
+ import path3 from "path";
3541
3599
  function findNpmManifests(files) {
3542
3600
  const lockFiles = new Set(
3543
3601
  files.filter((f) => {
3544
- const base = path2.basename(f);
3602
+ const base = path3.basename(f);
3545
3603
  return base === "package-lock.json" || base === "yarn.lock" || base === "pnpm-lock.yaml";
3546
3604
  })
3547
3605
  );
3548
3606
  const manifests = [];
3549
3607
  for (const file of files) {
3550
- if (path2.basename(file) !== "package.json") continue;
3608
+ if (path3.basename(file) !== "package.json") continue;
3551
3609
  if (file.split("/").includes("node_modules")) continue;
3552
- const dir = path2.dirname(file);
3610
+ const dir = path3.dirname(file);
3553
3611
  let lockFile;
3554
3612
  for (const lf of ["package-lock.json", "yarn.lock", "pnpm-lock.yaml"]) {
3555
3613
  const candidate = dir === "." ? lf : `${dir}/${lf}`;
@@ -3564,7 +3622,7 @@ function findNpmManifests(files) {
3564
3622
  }
3565
3623
  function parseNpmPackages(content, manifest, opts, lockContent) {
3566
3624
  if (lockContent && manifest.lockFile) {
3567
- const base = path2.basename(manifest.lockFile);
3625
+ const base = path3.basename(manifest.lockFile);
3568
3626
  if (base === "package-lock.json") {
3569
3627
  const pkgs = parsePackageLock(lockContent, manifest.lockFile, opts);
3570
3628
  if (pkgs.length > 0) return pkgs;
@@ -3712,26 +3770,26 @@ function parsePnpmLock(content, lockFilePath, opts, packageJsonContent) {
3712
3770
  }
3713
3771
 
3714
3772
  // src/services/deps/parsers/nuget.ts
3715
- import path3 from "path";
3773
+ import path4 from "path";
3716
3774
  var PROJ_EXTENSIONS = /* @__PURE__ */ new Set([".csproj", ".fsproj", ".vbproj"]);
3717
3775
  function findNugetManifests(files) {
3718
3776
  const lockFiles = /* @__PURE__ */ new Map();
3719
3777
  for (const f of files) {
3720
- if (path3.basename(f) === "packages.lock.json") {
3721
- lockFiles.set(path3.dirname(f), f);
3778
+ if (path4.basename(f) === "packages.lock.json") {
3779
+ lockFiles.set(path4.dirname(f), f);
3722
3780
  }
3723
3781
  }
3724
3782
  const manifests = [];
3725
3783
  for (const file of files) {
3726
- const base = path3.basename(file);
3727
- const ext = path3.extname(file);
3784
+ const base = path4.basename(file);
3785
+ const ext = path4.extname(file);
3728
3786
  if (PROJ_EXTENSIONS.has(ext) || base === "packages.config") {
3729
- const dir = path3.dirname(file);
3787
+ const dir = path4.dirname(file);
3730
3788
  const lockFile = lockFiles.get(dir);
3731
3789
  manifests.push({ file, ecosystem: "nuget", lockFile });
3732
3790
  }
3733
3791
  if (base === "Directory.Packages.props") {
3734
- const dir = path3.dirname(file);
3792
+ const dir = path4.dirname(file);
3735
3793
  manifests.push({ file, ecosystem: "nuget", lockFile: lockFiles.get(dir) });
3736
3794
  }
3737
3795
  }
@@ -3750,7 +3808,7 @@ function findNugetManifests(files) {
3750
3808
  return deduped;
3751
3809
  }
3752
3810
  function parseNugetPackages(content, manifest, opts, lockContent, propsContent) {
3753
- const base = path3.basename(manifest.file);
3811
+ const base = path4.basename(manifest.file);
3754
3812
  if (lockContent) {
3755
3813
  return parsePackagesLock(lockContent, manifest.lockFile ?? manifest.file, opts);
3756
3814
  }
@@ -3871,14 +3929,14 @@ function parsePackagesLock(content, filePath, opts) {
3871
3929
  }
3872
3930
 
3873
3931
  // src/services/deps/parsers/maven.ts
3874
- import path4 from "path";
3932
+ import path5 from "path";
3875
3933
  function findMavenManifests(files) {
3876
- const lockFiles = new Set(files.filter((f) => path4.basename(f) === "gradle.lockfile"));
3934
+ const lockFiles = new Set(files.filter((f) => path5.basename(f) === "gradle.lockfile"));
3877
3935
  const manifests = [];
3878
3936
  for (const file of files) {
3879
- const base = path4.basename(file);
3937
+ const base = path5.basename(file);
3880
3938
  if (base === "pom.xml" || base === "build.gradle" || base === "build.gradle.kts") {
3881
- const dir = path4.dirname(file);
3939
+ const dir = path5.dirname(file);
3882
3940
  const lockCandidate = dir === "." ? "gradle.lockfile" : `${dir}/gradle.lockfile`;
3883
3941
  const lockFile = lockFiles.has(lockCandidate) ? lockCandidate : void 0;
3884
3942
  manifests.push({ file, ecosystem: "maven", lockFile });
@@ -3887,7 +3945,7 @@ function findMavenManifests(files) {
3887
3945
  return manifests;
3888
3946
  }
3889
3947
  function parseMavenPackages(content, manifest, opts, lockContent) {
3890
- const base = path4.basename(manifest.file);
3948
+ const base = path5.basename(manifest.file);
3891
3949
  if (lockContent && manifest.lockFile) {
3892
3950
  return parseGradleLock(lockContent, manifest.lockFile, opts);
3893
3951
  }
@@ -4048,7 +4106,7 @@ function getRepoFiles(repoRoot) {
4048
4106
  }
4049
4107
  function readFile(repoRoot, relPath) {
4050
4108
  try {
4051
- return fs.readFileSync(path5.join(repoRoot, relPath), "utf8");
4109
+ return fs.readFileSync(path6.join(repoRoot, relPath), "utf8");
4052
4110
  } catch {
4053
4111
  return null;
4054
4112
  }
@@ -4066,13 +4124,13 @@ function readFileAtRef(repoRoot, ref, relPath) {
4066
4124
  }
4067
4125
  }
4068
4126
  function findPropsContent(manifestFile, readFn) {
4069
- let dir = path5.dirname(manifestFile);
4127
+ let dir = path6.dirname(manifestFile);
4070
4128
  for (let depth = 0; depth < 10; depth++) {
4071
4129
  const candidate = dir === "." ? "Directory.Packages.props" : `${dir}/Directory.Packages.props`;
4072
4130
  const content = readFn(candidate);
4073
4131
  if (content) return content;
4074
4132
  if (dir === ".") break;
4075
- dir = path5.dirname(dir);
4133
+ dir = path6.dirname(dir);
4076
4134
  }
4077
4135
  return null;
4078
4136
  }
@@ -5514,7 +5572,7 @@ import chalk from "chalk";
5514
5572
  import fs2 from "fs";
5515
5573
  function registerConfigCommands(program2) {
5516
5574
  const config = program2.command("config").description("Manage pncli configuration");
5517
- config.command("init").description("Interactive setup wizard").option("--repo", "Write repo config (.pncli.json) instead of global config").action(async (opts) => {
5575
+ config.command("init").description("Setup wizard for service credentials (interactive)").option("--repo", "Write repo config (.pncli.json) instead of global config").action(async (opts) => {
5518
5576
  const start = Date.now();
5519
5577
  try {
5520
5578
  if (opts.repo) {
@@ -5625,8 +5683,8 @@ function registerConfigCommands(program2) {
5625
5683
  if (cfg.ado.baseUrl) {
5626
5684
  try {
5627
5685
  const collection = cfg.defaults.ado?.collection;
5628
- const path8 = collection ? `/${encodeURIComponent(collection)}/_apis/connectionData?api-version=7.1-preview.1` : "/_apis/projectCollections?api-version=7.1";
5629
- await http.ado(path8);
5686
+ const path9 = collection ? `/${encodeURIComponent(collection)}/_apis/connectionData?api-version=7.1-preview.1` : "/_apis/projectCollections?api-version=7.1";
5687
+ await http.ado(path9);
5630
5688
  results.ado = { ok: true, message: "connected" };
5631
5689
  } catch (err) {
5632
5690
  results.ado = { ok: false, message: err instanceof Error ? err.message : String(err) };
@@ -5851,8 +5909,8 @@ function registerConfigCommands(program2) {
5851
5909
  } else {
5852
5910
  try {
5853
5911
  const collection = cfg.defaults.ado?.collection;
5854
- const path8 = collection ? `/${encodeURIComponent(collection)}/_apis/connectionData?api-version=7.1-preview.1` : "/_apis/projectCollections?api-version=7.1";
5855
- await http.ado(path8, { timeoutMs: 1e4 });
5912
+ const path9 = collection ? `/${encodeURIComponent(collection)}/_apis/connectionData?api-version=7.1-preview.1` : "/_apis/projectCollections?api-version=7.1";
5913
+ await http.ado(path9, { timeoutMs: 1e4 });
5856
5914
  results.ado = { status: "valid", message: "ok" };
5857
5915
  } catch (err) {
5858
5916
  results.ado = categorize2(err);
@@ -7247,7 +7305,7 @@ function registerAdoProjectCommands(ado) {
7247
7305
 
7248
7306
  // src/services/ado/commands/work.ts
7249
7307
  import fs3 from "fs";
7250
- import path6 from "path";
7308
+ import path7 from "path";
7251
7309
 
7252
7310
  // src/services/ado/input-schema.ts
7253
7311
  var ADO_WORK_INPUT_FILE_SCHEMA = {
@@ -7488,9 +7546,9 @@ function registerAdoWorkCommands(ado) {
7488
7546
  const attachments = await workClient.listAttachments(collection, parseInt(opts.id, 10));
7489
7547
  const attachment = attachments.find((a) => a.id === opts.attachmentId);
7490
7548
  if (!attachment) throw new PncliError(`Attachment not found: ${opts.attachmentId}`, 1);
7491
- const outDir = opts.dir ?? path6.join(process.cwd(), ".pncli");
7549
+ const outDir = opts.dir ?? path7.join(process.cwd(), ".pncli");
7492
7550
  fs3.mkdirSync(outDir, { recursive: true });
7493
- const outPath = path6.join(outDir, path6.basename(attachment.name));
7551
+ const outPath = path7.join(outDir, path7.basename(attachment.name));
7494
7552
  const buffer = await workClient.downloadAttachment(attachment.url);
7495
7553
  fs3.writeFileSync(outPath, buffer);
7496
7554
  success({ saved: outPath, name: attachment.name, size: buffer.length }, "ado", "work-download-attachment", start);
@@ -7650,7 +7708,7 @@ function registerAdoRepoCommands(ado) {
7650
7708
  fail(err, "ado", "repo-get-pr", start);
7651
7709
  }
7652
7710
  });
7653
- repo.command("create-pr").description("Create a pull request").requiredOption("--title <title>", "PR title").requiredOption("--source <branch>", "Source branch").option("--target <branch>", "Target branch (default: main)", "main").option("--description <text>", "PR description").option("--reviewers <ids>", "Comma-separated reviewer IDs or display names").action(async (opts) => {
7711
+ repo.command("create-pr").description("Create a pull request").requiredOption("--title <title>", "PR title").requiredOption("--source <branch>", "Source branch").option("--target <branch>", "Target branch (default: main)", "main").option("--description <text>", "PR description").option("--reviewers <ids>", "Comma-separated reviewer IDs or display names").option("--draft", "Create as a draft pull request").action(async (opts) => {
7654
7712
  const start = Date.now();
7655
7713
  try {
7656
7714
  const { collection, project, repo: repo2, gitClient } = getAdoContext(ado, true);
@@ -7660,14 +7718,15 @@ function registerAdoRepoCommands(ado) {
7660
7718
  description: opts.description,
7661
7719
  sourceRefName: `refs/heads/${opts.source}`,
7662
7720
  targetRefName: `refs/heads/${opts.target}`,
7663
- reviewers
7721
+ reviewers,
7722
+ ...opts.draft !== void 0 ? { isDraft: opts.draft } : {}
7664
7723
  });
7665
7724
  success(data, "ado", "repo-create-pr", start);
7666
7725
  } catch (err) {
7667
7726
  fail(err, "ado", "repo-create-pr", start);
7668
7727
  }
7669
7728
  });
7670
- repo.command("update-pr").description("Update a pull request").requiredOption("--id <n>", "Pull request ID").option("--title <title>", "New title").option("--description <text>", "New description").option("--reviewers <ids>", "Comma-separated reviewer IDs").action(async (opts) => {
7729
+ repo.command("update-pr").description("Update a pull request").requiredOption("--id <n>", "Pull request ID").option("--title <title>", "New title").option("--description <text>", "New description").option("--reviewers <ids>", "Comma-separated reviewer IDs").option("--draft <bool>", "Set draft status: true|false").action(async (opts) => {
7671
7730
  const start = Date.now();
7672
7731
  try {
7673
7732
  const { collection, project, repo: repo2, gitClient } = getAdoContext(ado, true);
@@ -7676,6 +7735,7 @@ function registerAdoRepoCommands(ado) {
7676
7735
  if (opts.title) body.title = opts.title;
7677
7736
  if (opts.description !== void 0) body.description = opts.description;
7678
7737
  if (reviewers) body.reviewers = reviewers;
7738
+ if (opts.draft !== void 0) body.isDraft = opts.draft === "true";
7679
7739
  const data = await gitClient.updatePR(collection, project, repo2, parseInt(opts.id, 10), body);
7680
7740
  success(data, "ado", "repo-update-pr", start);
7681
7741
  } catch (err) {
@@ -7861,7 +7921,7 @@ function registerAdoRepoCommands(ado) {
7861
7921
  const config = lc({ configPath: globalOpts.config });
7862
7922
  const { collection, project, repo: repo2, gitClient } = getAdoContext(ado, true);
7863
7923
  const { AdoCoreClient: AdoCoreClient2 } = await import("./core-SWYVXOQ4.js");
7864
- const { createHttpClient: createHttpClient2 } = await import("./http-IXJA4TMS.js");
7924
+ const { createHttpClient: createHttpClient2 } = await import("./http-52YHD3ZL.js");
7865
7925
  const http = createHttpClient2(config, Boolean(globalOpts.dryRun));
7866
7926
  const coreClient = new AdoCoreClient2(http);
7867
7927
  const me = await coreClient.getConnectionData(collection);
@@ -8262,18 +8322,18 @@ var ArtifactoryClient = class {
8262
8322
  }
8263
8323
  });
8264
8324
  }
8265
- async getStorageInfo(repo, path8) {
8266
- const cleanPath = path8.startsWith("/") ? path8.slice(1) : path8;
8325
+ async getStorageInfo(repo, path9) {
8326
+ const cleanPath = path9.startsWith("/") ? path9.slice(1) : path9;
8267
8327
  return this.http.artifactory(`${API9}/storage/${repo}/${cleanPath}`);
8268
8328
  }
8269
- async getProperties(repo, path8) {
8270
- const cleanPath = path8.startsWith("/") ? path8.slice(1) : path8;
8329
+ async getProperties(repo, path9) {
8330
+ const cleanPath = path9.startsWith("/") ? path9.slice(1) : path9;
8271
8331
  return this.http.artifactory(`${API9}/storage/${repo}/${cleanPath}`, {
8272
8332
  params: { properties: "" }
8273
8333
  });
8274
8334
  }
8275
- async setProperties(repo, path8, properties, opts = {}) {
8276
- const cleanPath = path8.startsWith("/") ? path8.slice(1) : path8;
8335
+ async setProperties(repo, path9, properties, opts = {}) {
8336
+ const cleanPath = path9.startsWith("/") ? path9.slice(1) : path9;
8277
8337
  const propString = Object.entries(properties).map(([k, v]) => `${k}=${v}`).join(";");
8278
8338
  await this.http.artifactory(`${API9}/storage/${repo}/${cleanPath}`, {
8279
8339
  method: "PUT",
@@ -8355,27 +8415,27 @@ function registerArtifactoryCommands(program2) {
8355
8415
  fail(err, "artifactory", "repos", start);
8356
8416
  }
8357
8417
  });
8358
- art.command("artifact-info <repo> <path>").description("Get metadata for an artifact or folder (checksums, size, timestamps)").action(async (repo, path8) => {
8418
+ art.command("artifact-info <repo> <path>").description("Get metadata for an artifact or folder (checksums, size, timestamps)").action(async (repo, path9) => {
8359
8419
  const start = Date.now();
8360
8420
  try {
8361
8421
  const client = getClient8(program2);
8362
- const data = await client.getStorageInfo(repo, path8);
8422
+ const data = await client.getStorageInfo(repo, path9);
8363
8423
  success(data, "artifactory", "artifact-info", start);
8364
8424
  } catch (err) {
8365
8425
  fail(err, "artifactory", "artifact-info", start);
8366
8426
  }
8367
8427
  });
8368
- art.command("properties-get <repo> <path>").description("Read custom properties on an artifact").action(async (repo, path8) => {
8428
+ art.command("properties-get <repo> <path>").description("Read custom properties on an artifact").action(async (repo, path9) => {
8369
8429
  const start = Date.now();
8370
8430
  try {
8371
8431
  const client = getClient8(program2);
8372
- const data = await client.getProperties(repo, path8);
8432
+ const data = await client.getProperties(repo, path9);
8373
8433
  success(data, "artifactory", "properties-get", start);
8374
8434
  } catch (err) {
8375
8435
  fail(err, "artifactory", "properties-get", start);
8376
8436
  }
8377
8437
  });
8378
- art.command("properties-set <repo> <path> [keyvals...]").description("Set custom properties on an artifact (format: key=value key=value...)").option("--recursive", "Apply recursively to folder contents", false).action(async (repo, path8, keyvals, opts) => {
8438
+ art.command("properties-set <repo> <path> [keyvals...]").description("Set custom properties on an artifact (format: key=value key=value...)").option("--recursive", "Apply recursively to folder contents", false).action(async (repo, path9, keyvals, opts) => {
8379
8439
  const start = Date.now();
8380
8440
  try {
8381
8441
  if (!keyvals.length) throw new PncliError("Provide at least one key=value pair");
@@ -8386,8 +8446,8 @@ function registerArtifactoryCommands(program2) {
8386
8446
  properties[kv.slice(0, eq)] = kv.slice(eq + 1);
8387
8447
  }
8388
8448
  const client = getClient8(program2);
8389
- await client.setProperties(repo, path8, properties, { recursive: opts.recursive });
8390
- success({ repo, path: path8, properties }, "artifactory", "properties-set", start);
8449
+ await client.setProperties(repo, path9, properties, { recursive: opts.recursive });
8450
+ success({ repo, path: path9, properties }, "artifactory", "properties-set", start);
8391
8451
  } catch (err) {
8392
8452
  fail(err, "artifactory", "properties-set", start);
8393
8453
  }
@@ -8994,8 +9054,8 @@ function registerSonatypeIqCommands(program2) {
8994
9054
  const startTime = Date.now();
8995
9055
  try {
8996
9056
  const http = getHttpClient(program2);
8997
- const path8 = opts.organizationId ? `/api/v2/policies/organization/${encodeURIComponent(opts.organizationId)}` : "/api/v2/policies";
8998
- const data = await http.sonatypeiq(path8);
9057
+ const path9 = opts.organizationId ? `/api/v2/policies/organization/${encodeURIComponent(opts.organizationId)}` : "/api/v2/policies";
9058
+ const data = await http.sonatypeiq(path9);
8999
9059
  success(data, "sonatypeiq", "policies list", startTime);
9000
9060
  } catch (err) {
9001
9061
  fail(err, "sonatypeiq", "policies list", startTime);
@@ -9005,11 +9065,13 @@ function registerSonatypeIqCommands(program2) {
9005
9065
 
9006
9066
  // src/services/skills/commands.ts
9007
9067
  import fs4 from "fs";
9008
- import path7 from "path";
9068
+ import path8 from "path";
9009
9069
  import os from "os";
9010
9070
  import { fileURLToPath } from "url";
9011
9071
  import { execFileSync as execFileSync3 } from "child_process";
9012
9072
  import select from "@inquirer/select";
9073
+ import checkbox, { Separator } from "@inquirer/checkbox";
9074
+ import input2 from "@inquirer/input";
9013
9075
  var BACK = "__back__";
9014
9076
  var ALL_MARKETPLACES = "__all_marketplaces__";
9015
9077
  function injectTokenIntoUrl(url, token) {
@@ -9033,7 +9095,7 @@ function repoNameFromUrl(url) {
9033
9095
  }
9034
9096
  }
9035
9097
  function defaultMarketplacePath(url) {
9036
- return path7.join(os.homedir(), ".agents", "marketplaces", repoNameFromUrl(url));
9098
+ return path8.join(os.homedir(), ".agents", "marketplaces", repoNameFromUrl(url));
9037
9099
  }
9038
9100
  function marketplaceLabel(m) {
9039
9101
  return m.name ?? repoNameFromUrl(m.repoUrl ?? "");
@@ -9047,8 +9109,8 @@ function assertInteractive(hint) {
9047
9109
  }
9048
9110
  }
9049
9111
  var AGENT_PATHS = {
9050
- "github-copilot": { project: ".agents/skills", user: path7.join(os.homedir(), ".copilot/skills") },
9051
- "claude-code": { project: ".claude/skills", user: path7.join(os.homedir(), ".claude/skills") }
9112
+ "github-copilot": { project: ".agents/skills", user: path8.join(os.homedir(), ".agents/skills") },
9113
+ "claude-code": { project: ".claude/skills", user: path8.join(os.homedir(), ".claude/skills") }
9052
9114
  };
9053
9115
  function resolveAgentName(opts) {
9054
9116
  return opts.claude ? "claude-code" : opts.agent ?? "github-copilot";
@@ -9060,18 +9122,25 @@ function resolveAgentPaths(agentName) {
9060
9122
  }
9061
9123
  return agentConfig;
9062
9124
  }
9125
+ function resolveTargetDir(opts) {
9126
+ if (opts.target) return path8.resolve(opts.target);
9127
+ const agentConfig = resolveAgentPaths(resolveAgentName(opts));
9128
+ const scopePath = (opts.scope ?? "user") === "project" ? agentConfig.project : agentConfig.user;
9129
+ return path8.resolve(scopePath);
9130
+ }
9063
9131
  function getBundledSkillsDir() {
9064
9132
  try {
9065
9133
  const thisFile = fileURLToPath(import.meta.url);
9066
- return path7.resolve(path7.dirname(thisFile), "..", "skills");
9134
+ return path8.resolve(path8.dirname(thisFile), "..", "skills");
9067
9135
  } catch {
9068
9136
  return "";
9069
9137
  }
9070
9138
  }
9071
9139
  function getInstalledMetaPath(targetDir) {
9072
- return path7.join(targetDir, ".pncli-installed.json");
9140
+ return path8.join(targetDir, ".pncli-installed.json");
9073
9141
  }
9074
9142
  var SKILL_ORIGIN_FILENAME = "pncli-origin.json";
9143
+ var DISABLED_SUBDIR = ".pncli-disabled";
9075
9144
  function readInstalledMeta(targetDir) {
9076
9145
  const metaPath = getInstalledMetaPath(targetDir);
9077
9146
  const raw = loadJsonFile(metaPath);
@@ -9079,7 +9148,7 @@ function readInstalledMeta(targetDir) {
9079
9148
  return { version: 1, skills: {} };
9080
9149
  }
9081
9150
  function getSkillOriginPath(skillDir) {
9082
- return path7.join(skillDir, SKILL_ORIGIN_FILENAME);
9151
+ return path8.join(skillDir, SKILL_ORIGIN_FILENAME);
9083
9152
  }
9084
9153
  function readSkillOrigin(skillDir) {
9085
9154
  const originPath = getSkillOriginPath(skillDir);
@@ -9091,6 +9160,132 @@ function readSkillOrigin(skillDir) {
9091
9160
  }
9092
9161
  return null;
9093
9162
  }
9163
+ function matchesMarketplaceFilter(record, filter) {
9164
+ return !filter || record.marketplace === filter || record.installedFrom === filter;
9165
+ }
9166
+ function resolveSkillRecord(meta, targetDir, skillName) {
9167
+ const fromMeta = meta.skills[skillName];
9168
+ if (fromMeta) return fromMeta;
9169
+ const perSkill = readSkillOrigin(path8.join(targetDir, skillName));
9170
+ if (!perSkill) return null;
9171
+ return {
9172
+ source: perSkill.source,
9173
+ marketplace: perSkill.marketplace,
9174
+ plugin: perSkill.plugin,
9175
+ installedFrom: perSkill.installedFrom,
9176
+ branch: perSkill.branch,
9177
+ installedAt: perSkill.installedAt
9178
+ };
9179
+ }
9180
+ function listActiveSkillDirs(targetDir) {
9181
+ return fs4.readdirSync(targetDir).filter((name) => {
9182
+ if (name.startsWith(".")) return false;
9183
+ const p = path8.join(targetDir, name);
9184
+ try {
9185
+ return fs4.statSync(p).isDirectory();
9186
+ } catch {
9187
+ return false;
9188
+ }
9189
+ });
9190
+ }
9191
+ function disablePluginSkills(targetDir, plugin, marketplaceFilter) {
9192
+ const resolvedTarget = path8.resolve(targetDir);
9193
+ const stashDir = path8.join(targetDir, DISABLED_SUBDIR);
9194
+ const meta = readInstalledMeta(targetDir);
9195
+ const disabled = [];
9196
+ const alreadyDisabled = [];
9197
+ const skipped = [];
9198
+ for (const skillName of listActiveSkillDirs(targetDir)) {
9199
+ const skillDir = path8.resolve(targetDir, skillName);
9200
+ if (!skillDir.startsWith(resolvedTarget + path8.sep)) continue;
9201
+ const record = resolveSkillRecord(meta, targetDir, skillName);
9202
+ if (!record || record.source !== "marketplace") {
9203
+ skipped.push(skillName);
9204
+ continue;
9205
+ }
9206
+ if (!matchesMarketplaceFilter(record, marketplaceFilter) || record.plugin !== plugin) {
9207
+ skipped.push(skillName);
9208
+ continue;
9209
+ }
9210
+ const stashDest = path8.join(stashDir, skillName);
9211
+ fs4.mkdirSync(stashDir, { recursive: true });
9212
+ if (fs4.existsSync(stashDest)) fs4.rmSync(stashDest, { recursive: true, force: true });
9213
+ fs4.renameSync(skillDir, stashDest);
9214
+ delete meta.skills[skillName];
9215
+ meta.disabled = meta.disabled ?? {};
9216
+ meta.disabled[skillName] = record;
9217
+ disabled.push(skillName);
9218
+ }
9219
+ for (const [skillName, record] of Object.entries(meta.disabled ?? {})) {
9220
+ if (record.plugin === plugin && matchesMarketplaceFilter(record, marketplaceFilter) && !disabled.includes(skillName)) {
9221
+ alreadyDisabled.push(skillName);
9222
+ }
9223
+ }
9224
+ if (disabled.length > 0) {
9225
+ fs4.writeFileSync(getInstalledMetaPath(targetDir), JSON.stringify(meta, null, 2), "utf8");
9226
+ }
9227
+ return { disabled, alreadyDisabled, skipped };
9228
+ }
9229
+ function enablePluginSkills(targetDir, plugin, marketplaceFilter) {
9230
+ const resolvedTarget = path8.resolve(targetDir);
9231
+ const stashDir = path8.join(targetDir, DISABLED_SUBDIR);
9232
+ const meta = readInstalledMeta(targetDir);
9233
+ const enabled = [];
9234
+ const stashMissing = [];
9235
+ const skipped = [];
9236
+ const disabledEntries = Object.entries(meta.disabled ?? {});
9237
+ for (const [skillName, record] of disabledEntries) {
9238
+ if (record.plugin !== plugin || !matchesMarketplaceFilter(record, marketplaceFilter)) {
9239
+ skipped.push(skillName);
9240
+ continue;
9241
+ }
9242
+ const dest = path8.resolve(targetDir, skillName);
9243
+ if (!dest.startsWith(resolvedTarget + path8.sep)) {
9244
+ skipped.push(skillName);
9245
+ continue;
9246
+ }
9247
+ const stashSrc = path8.join(stashDir, skillName);
9248
+ if (!fs4.existsSync(stashSrc)) {
9249
+ stashMissing.push(skillName);
9250
+ continue;
9251
+ }
9252
+ if (fs4.existsSync(dest)) fs4.rmSync(dest, { recursive: true, force: true });
9253
+ fs4.renameSync(stashSrc, dest);
9254
+ meta.skills[skillName] = record;
9255
+ delete meta.disabled[skillName];
9256
+ enabled.push(skillName);
9257
+ }
9258
+ if (fs4.existsSync(stashDir) && fs4.readdirSync(stashDir).length === 0) {
9259
+ fs4.rmdirSync(stashDir);
9260
+ }
9261
+ if (enabled.length > 0) {
9262
+ fs4.writeFileSync(getInstalledMetaPath(targetDir), JSON.stringify(meta, null, 2), "utf8");
9263
+ }
9264
+ return { enabled, stashMissing, skipped, hadDisabled: disabledEntries.length > 0 };
9265
+ }
9266
+ function listPluginStates(targetDir) {
9267
+ const meta = readInstalledMeta(targetDir);
9268
+ const byKey = /* @__PURE__ */ new Map();
9269
+ const bucketFor = (record) => {
9270
+ if (record.source !== "marketplace" || !record.plugin) return null;
9271
+ const marketplaceName = record.marketplace ?? record.installedFrom;
9272
+ const key = `${marketplaceName ?? ""}\0${record.plugin}`;
9273
+ let state = byKey.get(key);
9274
+ if (!state) {
9275
+ state = { plugin: record.plugin, marketplace: marketplaceName, activeSkills: [], disabledSkills: [] };
9276
+ byKey.set(key, state);
9277
+ }
9278
+ return state;
9279
+ };
9280
+ for (const skillName of listActiveSkillDirs(targetDir)) {
9281
+ const record = resolveSkillRecord(meta, targetDir, skillName);
9282
+ if (record) bucketFor(record)?.activeSkills.push(skillName);
9283
+ }
9284
+ for (const [skillName, record] of Object.entries(meta.disabled ?? {})) {
9285
+ bucketFor(record)?.disabledSkills.push(skillName);
9286
+ }
9287
+ return [...byKey.values()].sort((a, b) => a.plugin.localeCompare(b.plugin));
9288
+ }
9094
9289
  function detectRepoBranch(repoPath) {
9095
9290
  try {
9096
9291
  const result = execFileSync3("git", ["-C", repoPath, "rev-parse", "--abbrev-ref", "HEAD"], {
@@ -9109,7 +9304,7 @@ function recordInstalledSkills(targetDir, skillNames, record) {
9109
9304
  for (const skillName of skillNames) {
9110
9305
  const fullRecord = { ...record, installedAt: now };
9111
9306
  meta.skills[skillName] = fullRecord;
9112
- const skillDir = path7.join(targetDir, skillName);
9307
+ const skillDir = path8.join(targetDir, skillName);
9113
9308
  if (fs4.existsSync(skillDir)) {
9114
9309
  const origin = { version: 1, ...fullRecord };
9115
9310
  try {
@@ -9179,7 +9374,7 @@ function upsertMarketplace(all, entry) {
9179
9374
  }
9180
9375
  }
9181
9376
  function cloneOrReuseMarketplace(url, resolvedPath, opts) {
9182
- const hasGit = fs4.existsSync(path7.join(resolvedPath, ".git"));
9377
+ const hasGit = fs4.existsSync(path8.join(resolvedPath, ".git"));
9183
9378
  if (fs4.existsSync(resolvedPath) && !hasGit && fs4.readdirSync(resolvedPath).length > 0) {
9184
9379
  throw new Error(`Directory already exists and is not a git repo: ${resolvedPath}`);
9185
9380
  }
@@ -9247,7 +9442,7 @@ function installPluginsForMarketplace(marketplacePath, marketplaceName, repoUrl,
9247
9442
  results[pluginName] = { installed, failed };
9248
9443
  totalInstalled += installed.length;
9249
9444
  for (const skill of installed) {
9250
- warn(` ${skill}: ${path7.join(skillsSrc, skill)} \u2192 ${path7.join(targetDir, skill)}`);
9445
+ warn(` ${skill}: ${path8.join(skillsSrc, skill)} \u2192 ${path8.join(targetDir, skill)}`);
9251
9446
  }
9252
9447
  if (failed.length > 0) {
9253
9448
  warn(`Skipped ${failed.length} skill(s) with invalid names in "${pluginName}": ${failed.join(", ")}`);
@@ -9299,34 +9494,55 @@ function syncMarketplacePlugins(m, targetDir, force, pluginFilter) {
9299
9494
  return { marketplace: marketplaceName, skipped: true, error: message };
9300
9495
  }
9301
9496
  }
9497
+ function performMarketplaceAdd(url, localPath, opts) {
9498
+ const resolvedPath = path8.resolve(localPath ?? defaultMarketplacePath(url));
9499
+ const marketplaceName = opts.name ?? repoNameFromUrl(url);
9500
+ cloneOrReuseMarketplace(url, resolvedPath, opts);
9501
+ const configPath = getGlobalConfigPath();
9502
+ const { existing, all } = loadMarketplacesConfig(configPath);
9503
+ const entry = {
9504
+ name: marketplaceName,
9505
+ repoUrl: url,
9506
+ localPath: resolvedPath,
9507
+ ...opts.token ? { token: opts.token } : {}
9508
+ };
9509
+ upsertMarketplace(all, entry);
9510
+ saveMarketplaces(configPath, existing, all);
9511
+ const targetDir = resolveAgentPaths(resolveAgentName(opts)).user;
9512
+ const { pluginResults, totalInstalled } = installAllPlugins(resolvedPath, marketplaceName, url, targetDir);
9513
+ return {
9514
+ name: marketplaceName,
9515
+ repoUrl: url,
9516
+ localPath: resolvedPath,
9517
+ branch: opts.branch ?? null,
9518
+ tokenConfigured: !!opts.token,
9519
+ plugins: pluginResults,
9520
+ total: totalInstalled,
9521
+ target: targetDir
9522
+ };
9523
+ }
9524
+ function performMarketplaceRemove(name) {
9525
+ const configPath = getGlobalConfigPath();
9526
+ const { existing, all } = loadMarketplacesConfig(configPath);
9527
+ const idx = all.findIndex((m) => m.name === name || m.repoUrl === name);
9528
+ if (idx === -1) {
9529
+ throw new Error(`Marketplace "${name}" not found. Run: pncli skills marketplace list`);
9530
+ }
9531
+ const removed = all.splice(idx, 1)[0];
9532
+ saveMarketplaces(configPath, existing, all);
9533
+ return {
9534
+ removed: {
9535
+ name: marketplaceLabel(removed),
9536
+ repoUrl: removed.repoUrl,
9537
+ localPath: removed.localPath
9538
+ },
9539
+ remaining: all.length
9540
+ };
9541
+ }
9302
9542
  async function marketplaceAddAction(url, localPath, opts, commandName) {
9303
9543
  const start = Date.now();
9304
9544
  try {
9305
- const resolvedPath = path7.resolve(localPath ?? defaultMarketplacePath(url));
9306
- const marketplaceName = opts.name ?? repoNameFromUrl(url);
9307
- cloneOrReuseMarketplace(url, resolvedPath, opts);
9308
- const configPath = getGlobalConfigPath();
9309
- const { existing, all } = loadMarketplacesConfig(configPath);
9310
- const entry = {
9311
- name: marketplaceName,
9312
- repoUrl: url,
9313
- localPath: resolvedPath,
9314
- ...opts.token ? { token: opts.token } : {}
9315
- };
9316
- upsertMarketplace(all, entry);
9317
- saveMarketplaces(configPath, existing, all);
9318
- const targetDir = resolveAgentPaths(resolveAgentName(opts)).user;
9319
- const { pluginResults, totalInstalled } = installAllPlugins(resolvedPath, marketplaceName, url, targetDir);
9320
- success({
9321
- name: marketplaceName,
9322
- repoUrl: url,
9323
- localPath: resolvedPath,
9324
- branch: opts.branch ?? null,
9325
- tokenConfigured: !!opts.token,
9326
- plugins: pluginResults,
9327
- total: totalInstalled,
9328
- target: targetDir
9329
- }, "skills", commandName, start);
9545
+ success(performMarketplaceAdd(url, localPath, opts), "skills", commandName, start);
9330
9546
  } catch (err) {
9331
9547
  fail(err, "skills", commandName, start);
9332
9548
  }
@@ -9338,19 +9554,19 @@ function registerSkillsCommands(program2) {
9338
9554
  try {
9339
9555
  let targetDir;
9340
9556
  if (opts.target) {
9341
- targetDir = path7.resolve(opts.target);
9557
+ targetDir = path8.resolve(opts.target);
9342
9558
  } else {
9343
9559
  const agentConfig = resolveAgentPaths(opts.agent);
9344
9560
  const scopePath = opts.scope === "user" ? agentConfig.user : agentConfig.project;
9345
- targetDir = path7.resolve(scopePath);
9561
+ targetDir = path8.resolve(scopePath);
9346
9562
  }
9347
- const resolvedTarget = path7.resolve(targetDir);
9563
+ const resolvedTarget = path8.resolve(targetDir);
9348
9564
  const bundledDir = getBundledSkillsDir();
9349
9565
  let skillDirs = [];
9350
9566
  if (bundledDir !== "") {
9351
9567
  try {
9352
9568
  skillDirs = fs4.readdirSync(bundledDir).filter(
9353
- (name) => fs4.existsSync(path7.join(bundledDir, name, "SKILL.md"))
9569
+ (name) => fs4.existsSync(path8.join(bundledDir, name, "SKILL.md"))
9354
9570
  );
9355
9571
  } catch {
9356
9572
  }
@@ -9361,25 +9577,25 @@ function registerSkillsCommands(program2) {
9361
9577
  const installed = [];
9362
9578
  const failed = [];
9363
9579
  for (const skillName of skillDirs) {
9364
- const existingDir = path7.resolve(targetDir, skillName);
9365
- if (!existingDir.startsWith(resolvedTarget + path7.sep)) continue;
9580
+ const existingDir = path8.resolve(targetDir, skillName);
9581
+ if (!existingDir.startsWith(resolvedTarget + path8.sep)) continue;
9366
9582
  if (fs4.existsSync(existingDir)) {
9367
9583
  fs4.rmSync(existingDir, { recursive: true, force: true });
9368
9584
  }
9369
9585
  }
9370
9586
  warn(`Installing ${skillDirs.length} bundled skill(s) to ${targetDir}...`);
9371
9587
  for (const skillName of skillDirs) {
9372
- const skillDir = path7.resolve(targetDir, skillName);
9373
- if (!skillDir.startsWith(resolvedTarget + path7.sep)) {
9588
+ const skillDir = path8.resolve(targetDir, skillName);
9589
+ if (!skillDir.startsWith(resolvedTarget + path8.sep)) {
9374
9590
  failed.push(skillName);
9375
9591
  continue;
9376
9592
  }
9377
9593
  try {
9378
- const mdFiles = fs4.readdirSync(path7.join(bundledDir, skillName)).filter((f) => f.endsWith(".md"));
9594
+ const mdFiles = fs4.readdirSync(path8.join(bundledDir, skillName)).filter((f) => f.endsWith(".md"));
9379
9595
  fs4.mkdirSync(skillDir, { recursive: true });
9380
9596
  for (const mdFile of mdFiles) {
9381
- const content = fs4.readFileSync(path7.join(bundledDir, skillName, mdFile), "utf8");
9382
- fs4.writeFileSync(path7.join(skillDir, mdFile), content, "utf8");
9597
+ const content = fs4.readFileSync(path8.join(bundledDir, skillName, mdFile), "utf8");
9598
+ fs4.writeFileSync(path8.join(skillDir, mdFile), content, "utf8");
9383
9599
  }
9384
9600
  installed.push(skillName);
9385
9601
  } catch {
@@ -9409,11 +9625,11 @@ function registerSkillsCommands(program2) {
9409
9625
  try {
9410
9626
  let targetDir;
9411
9627
  if (opts.target) {
9412
- targetDir = path7.resolve(opts.target);
9628
+ targetDir = path8.resolve(opts.target);
9413
9629
  } else {
9414
9630
  const agentConfig = resolveAgentPaths(opts.agent);
9415
9631
  const scopePath = opts.scope === "user" ? agentConfig.user : agentConfig.project;
9416
- targetDir = path7.resolve(scopePath);
9632
+ targetDir = path8.resolve(scopePath);
9417
9633
  }
9418
9634
  if (!fs4.existsSync(targetDir)) {
9419
9635
  success({ skills: [], message: `No skills directory found at ${targetDir}. Run: pncli skills install` }, "skills", "list", start);
@@ -9422,11 +9638,11 @@ function registerSkillsCommands(program2) {
9422
9638
  const meta = readInstalledMeta(targetDir);
9423
9639
  const skillDirs = fs4.readdirSync(targetDir).filter((name) => {
9424
9640
  if (name.startsWith(".")) return false;
9425
- const skillPath = path7.join(targetDir, name, "SKILL.md");
9641
+ const skillPath = path8.join(targetDir, name, "SKILL.md");
9426
9642
  return fs4.existsSync(skillPath);
9427
9643
  });
9428
9644
  const skillsList = skillDirs.map((name) => {
9429
- const content = fs4.readFileSync(path7.join(targetDir, name, "SKILL.md"), "utf8");
9645
+ const content = fs4.readFileSync(path8.join(targetDir, name, "SKILL.md"), "utf8");
9430
9646
  const frontmatter = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
9431
9647
  const data = {};
9432
9648
  const metadata = {};
@@ -9470,15 +9686,15 @@ function registerSkillsCommands(program2) {
9470
9686
  try {
9471
9687
  let targetDir;
9472
9688
  if (opts.target) {
9473
- targetDir = path7.resolve(opts.target);
9689
+ targetDir = path8.resolve(opts.target);
9474
9690
  } else {
9475
9691
  const agentConfig = resolveAgentPaths(resolveAgentName(opts));
9476
9692
  const scopePath = opts.scope === "project" ? agentConfig.project : agentConfig.user;
9477
- targetDir = path7.resolve(scopePath);
9693
+ targetDir = path8.resolve(scopePath);
9478
9694
  }
9479
- const resolvedTarget = path7.resolve(targetDir);
9480
- const skillDir = path7.resolve(targetDir, name);
9481
- if (!skillDir.startsWith(resolvedTarget + path7.sep)) {
9695
+ const resolvedTarget = path8.resolve(targetDir);
9696
+ const skillDir = path8.resolve(targetDir, name);
9697
+ if (!skillDir.startsWith(resolvedTarget + path8.sep)) {
9482
9698
  throw new Error(`Invalid skill name: "${name}"`);
9483
9699
  }
9484
9700
  if (!fs4.existsSync(skillDir)) {
@@ -9552,27 +9768,12 @@ function registerSkillsCommands(program2) {
9552
9768
  marketplace.command("remove").description("Remove a registered marketplace from the config (does not delete the local clone)").argument("<name>", "Name of the marketplace to remove").action((name) => {
9553
9769
  const start = Date.now();
9554
9770
  try {
9555
- const configPath = getGlobalConfigPath();
9556
- const { existing, all } = loadMarketplacesConfig(configPath);
9557
- const idx = all.findIndex((m) => m.name === name || m.repoUrl === name);
9558
- if (idx === -1) {
9559
- throw new Error(`Marketplace "${name}" not found. Run: pncli skills marketplace list`);
9560
- }
9561
- const removed = all.splice(idx, 1)[0];
9562
- saveMarketplaces(configPath, existing, all);
9563
- success({
9564
- removed: {
9565
- name: marketplaceLabel(removed),
9566
- repoUrl: removed.repoUrl,
9567
- localPath: removed.localPath
9568
- },
9569
- remaining: all.length
9570
- }, "skills", "marketplace-remove", start);
9771
+ success(performMarketplaceRemove(name), "skills", "marketplace-remove", start);
9571
9772
  } catch (err) {
9572
9773
  fail(err, "skills", "marketplace-remove", start);
9573
9774
  }
9574
9775
  });
9575
- marketplace.command("sync").description("Pull latest marketplace content and install plugin skills").argument("[plugin]", 'Plugin name to install, or "all" to install every plugin (skips interactive selection)').option("--marketplace <name>", 'Marketplace name to sync, or "all" to sync every registered marketplace (skips interactive selection)').option("--agent <agent>", "Target agent host: github-copilot | claude-code (default: github-copilot)").option("--claude", "Shorthand for --agent claude-code").option("--force", 'Reinstall even if a marketplace has no new changes (applies to single-plugin and "all" installs alike)').action(async (plugin, opts) => {
9776
+ marketplace.command("sync").description("Pull latest marketplace content and install plugin skills (interactive picker when no plugin is given)").argument("[plugin]", 'Plugin name to install, or "all" to install every plugin (skips interactive selection)').option("--marketplace <name>", 'Marketplace name to sync, or "all" to sync every registered marketplace (skips interactive selection)').option("--agent <agent>", "Target agent host: github-copilot | claude-code (default: github-copilot)").option("--claude", "Shorthand for --agent claude-code").option("--force", 'Reinstall even if a marketplace has no new changes (applies to single-plugin and "all" installs alike)').action(async (plugin, opts) => {
9576
9777
  const start = Date.now();
9577
9778
  try {
9578
9779
  const configPath = getGlobalConfigPath();
@@ -9685,13 +9886,13 @@ function registerSkillsCommands(program2) {
9685
9886
  try {
9686
9887
  let targetDir;
9687
9888
  if (opts.target) {
9688
- targetDir = path7.resolve(opts.target);
9889
+ targetDir = path8.resolve(opts.target);
9689
9890
  } else {
9690
9891
  const agentConfig = resolveAgentPaths(resolveAgentName(opts));
9691
9892
  const scopePath = (opts.scope ?? "user") === "project" ? agentConfig.project : agentConfig.user;
9692
- targetDir = path7.resolve(scopePath);
9893
+ targetDir = path8.resolve(scopePath);
9693
9894
  }
9694
- const resolvedTarget = path7.resolve(targetDir);
9895
+ const resolvedTarget = path8.resolve(targetDir);
9695
9896
  if (!fs4.existsSync(targetDir)) {
9696
9897
  success({ removed: [], total: 0, target: targetDir, message: "No skills directory found." }, "skills", "marketplace-purge-plugin", start);
9697
9898
  return;
@@ -9701,7 +9902,7 @@ function registerSkillsCommands(program2) {
9701
9902
  const skipped = [];
9702
9903
  const skillDirs = fs4.readdirSync(targetDir).filter((name) => {
9703
9904
  if (name.startsWith(".")) return false;
9704
- const p = path7.join(targetDir, name);
9905
+ const p = path8.join(targetDir, name);
9705
9906
  try {
9706
9907
  return fs4.statSync(p).isDirectory();
9707
9908
  } catch {
@@ -9709,8 +9910,8 @@ function registerSkillsCommands(program2) {
9709
9910
  }
9710
9911
  });
9711
9912
  for (const skillName of skillDirs) {
9712
- const skillDir = path7.resolve(targetDir, skillName);
9713
- if (!skillDir.startsWith(resolvedTarget + path7.sep)) continue;
9913
+ const skillDir = path8.resolve(targetDir, skillName);
9914
+ if (!skillDir.startsWith(resolvedTarget + path8.sep)) continue;
9714
9915
  let record = meta.skills[skillName] ?? null;
9715
9916
  if (!record) {
9716
9917
  const perSkill = readSkillOrigin(skillDir);
@@ -9754,6 +9955,161 @@ function registerSkillsCommands(program2) {
9754
9955
  fail(err, "skills", "marketplace-purge-plugin", start);
9755
9956
  }
9756
9957
  });
9958
+ marketplace.command("disable").description("Temporarily deactivate a plugin's skills without deleting them (re-enable with `marketplace enable`)").argument("<plugin>", "Plugin name to disable").option("--marketplace <name>", "Restrict to skills from this marketplace (by name or repo URL)").option("--agent <agent>", "Target agent host: github-copilot | claude-code (default: github-copilot)").option("--claude", "Shorthand for --agent claude-code").option("--scope <scope>", "Installation scope: project | user (default: user)").option("--target <dir>", "Override skills directory").action((plugin, opts) => {
9959
+ const start = Date.now();
9960
+ try {
9961
+ const targetDir = resolveTargetDir(opts);
9962
+ if (!fs4.existsSync(targetDir)) {
9963
+ success({ disabled: [], total: 0, target: targetDir, message: "No skills directory found." }, "skills", "marketplace-disable", start);
9964
+ return;
9965
+ }
9966
+ const result = disablePluginSkills(targetDir, plugin, opts.marketplace);
9967
+ success({
9968
+ disabled: result.disabled,
9969
+ alreadyDisabled: result.alreadyDisabled,
9970
+ skipped: result.skipped.length,
9971
+ total: result.disabled.length,
9972
+ target: targetDir,
9973
+ plugin,
9974
+ stash: path8.join(targetDir, DISABLED_SUBDIR),
9975
+ ...opts.marketplace ? { marketplace: opts.marketplace } : {}
9976
+ }, "skills", "marketplace-disable", start);
9977
+ } catch (err) {
9978
+ fail(err, "skills", "marketplace-disable", start);
9979
+ }
9980
+ });
9981
+ marketplace.command("enable").description("Re-activate a previously disabled plugin's skills").argument("<plugin>", "Plugin name to enable").option("--marketplace <name>", "Restrict to skills from this marketplace (by name or repo URL)").option("--agent <agent>", "Target agent host: github-copilot | claude-code (default: github-copilot)").option("--claude", "Shorthand for --agent claude-code").option("--scope <scope>", "Installation scope: project | user (default: user)").option("--target <dir>", "Override skills directory").action((plugin, opts) => {
9982
+ const start = Date.now();
9983
+ try {
9984
+ const targetDir = resolveTargetDir(opts);
9985
+ if (!fs4.existsSync(targetDir)) {
9986
+ success({ enabled: [], total: 0, target: targetDir, message: "No skills directory found." }, "skills", "marketplace-enable", start);
9987
+ return;
9988
+ }
9989
+ const result = enablePluginSkills(targetDir, plugin, opts.marketplace);
9990
+ if (!result.hadDisabled) {
9991
+ success({ enabled: [], total: 0, target: targetDir, plugin, message: `No disabled skills found for plugin "${plugin}".` }, "skills", "marketplace-enable", start);
9992
+ return;
9993
+ }
9994
+ success({
9995
+ enabled: result.enabled,
9996
+ skipped: result.skipped.length,
9997
+ total: result.enabled.length,
9998
+ target: targetDir,
9999
+ plugin,
10000
+ ...result.stashMissing.length > 0 ? {
10001
+ stashMissing: result.stashMissing,
10002
+ warning: `Skills marked disabled but missing from the stash were left as-is. Re-install the plugin (pncli skills marketplace sync ${plugin}) to restore them.`
10003
+ } : {},
10004
+ ...opts.marketplace ? { marketplace: opts.marketplace } : {}
10005
+ }, "skills", "marketplace-enable", start);
10006
+ } catch (err) {
10007
+ fail(err, "skills", "marketplace-enable", start);
10008
+ }
10009
+ });
10010
+ marketplace.command("manage").description("Manage marketplaces and plugins: toggle plugins on/off, add or remove marketplaces (interactive)").option("--agent <agent>", "Target agent host: github-copilot | claude-code (default: github-copilot)").option("--claude", "Shorthand for --agent claude-code").option("--scope <scope>", "Installation scope: project | user (default: user)").option("--target <dir>", "Override skills directory").action(async (opts) => {
10011
+ const start = Date.now();
10012
+ try {
10013
+ assertInteractive("Use `pncli skills marketplace enable|disable <plugin>`, `add <url>`, and `remove <name>` to manage non-interactively.");
10014
+ const targetDir = resolveTargetDir(opts);
10015
+ const enabledPlugins = [];
10016
+ const disabledPlugins = [];
10017
+ const stashMissing = [];
10018
+ const addedMarketplaces = [];
10019
+ const removedMarketplaces = [];
10020
+ for (; ; ) {
10021
+ const states = fs4.existsSync(targetDir) ? listPluginStates(targetDir) : [];
10022
+ const registered = loadMarketplaces(getGlobalConfigPath());
10023
+ const action = await select({
10024
+ message: `Manage skills marketplaces (target: ${targetDir}):`,
10025
+ choices: [
10026
+ ...states.length > 0 ? [{ value: "toggle", name: `Toggle plugins on/off (${states.length} installed)` }] : [],
10027
+ { value: "add", name: "Add a marketplace" },
10028
+ ...registered.length > 0 ? [{ value: "remove", name: `Remove a marketplace (${registered.length} registered)` }] : [],
10029
+ { value: "done", name: "Done" }
10030
+ ]
10031
+ });
10032
+ if (action === "done") break;
10033
+ if (action === "toggle") {
10034
+ const sorted = [...states].sort((a, b) => (a.marketplace ?? "").localeCompare(b.marketplace ?? "") || a.plugin.localeCompare(b.plugin));
10035
+ const choices = [];
10036
+ let lastMarketplace = null;
10037
+ sorted.forEach((state, index) => {
10038
+ const marketplaceName = state.marketplace ?? "(unknown marketplace)";
10039
+ if (marketplaceName !== lastMarketplace) {
10040
+ choices.push(new Separator(`\u2500\u2500 ${marketplaceName} \u2500\u2500`));
10041
+ lastMarketplace = marketplaceName;
10042
+ }
10043
+ const active = state.activeSkills.length;
10044
+ const stashed = state.disabledSkills.length;
10045
+ const skillCount = stashed === 0 ? `${active} skill${active === 1 ? "" : "s"}` : active === 0 ? `${stashed} skill${stashed === 1 ? "" : "s"}, disabled` : `${active} active, ${stashed} disabled`;
10046
+ choices.push({ name: `${state.plugin} (${skillCount})`, value: index, checked: active > 0 });
10047
+ });
10048
+ const checkedIndexes = await checkbox({
10049
+ message: "Toggle plugins (space toggles, enter applies):",
10050
+ choices,
10051
+ pageSize: 15
10052
+ });
10053
+ const wanted = new Set(checkedIndexes);
10054
+ sorted.forEach((state, index) => {
10055
+ if (wanted.has(index)) {
10056
+ if (state.disabledSkills.length === 0) return;
10057
+ const result = enablePluginSkills(targetDir, state.plugin, state.marketplace);
10058
+ stashMissing.push(...result.stashMissing);
10059
+ if (result.enabled.length > 0) {
10060
+ enabledPlugins.push({ plugin: state.plugin, marketplace: state.marketplace, skills: result.enabled });
10061
+ }
10062
+ } else {
10063
+ if (state.activeSkills.length === 0) return;
10064
+ const result = disablePluginSkills(targetDir, state.plugin, state.marketplace);
10065
+ if (result.disabled.length > 0) {
10066
+ disabledPlugins.push({ plugin: state.plugin, marketplace: state.marketplace, skills: result.disabled });
10067
+ }
10068
+ }
10069
+ });
10070
+ } else if (action === "add") {
10071
+ const url = (await input2({
10072
+ message: "Git clone URL of the marketplace repository:",
10073
+ validate: (v) => v.trim().length > 0 || "URL is required"
10074
+ })).trim();
10075
+ const name = (await input2({
10076
+ message: "Marketplace name:",
10077
+ default: repoNameFromUrl(url)
10078
+ })).trim();
10079
+ addedMarketplaces.push(performMarketplaceAdd(url, void 0, {
10080
+ name: name || void 0,
10081
+ agent: opts.agent,
10082
+ claude: opts.claude
10083
+ }));
10084
+ } else if (action === "remove") {
10085
+ const chosen = await select({
10086
+ message: "Remove which marketplace? (the local clone is kept on disk)",
10087
+ choices: [
10088
+ // Index-based values: labels alone aren't guaranteed unique (two marketplaces can share a derived name).
10089
+ ...registered.map((m, i) => ({ value: String(i), name: `${marketplaceLabel(m)} \u2014 ${m.repoUrl ?? ""}` })),
10090
+ { value: BACK, name: "\u2190 Back" }
10091
+ ]
10092
+ });
10093
+ if (chosen === BACK) continue;
10094
+ const target = registered[Number(chosen)];
10095
+ removedMarketplaces.push(performMarketplaceRemove(target.repoUrl ?? marketplaceLabel(target)));
10096
+ }
10097
+ }
10098
+ success({
10099
+ enabled: enabledPlugins,
10100
+ disabled: disabledPlugins,
10101
+ addedMarketplaces,
10102
+ removedMarketplaces,
10103
+ target: targetDir,
10104
+ ...stashMissing.length > 0 ? {
10105
+ stashMissing,
10106
+ warning: "Skills marked disabled but missing from the stash were left as-is. Re-install their plugin (pncli skills marketplace sync <plugin>) to restore them."
10107
+ } : {}
10108
+ }, "skills", "marketplace-manage", start);
10109
+ } catch (err) {
10110
+ fail(err, "skills", "marketplace-manage", start);
10111
+ }
10112
+ });
9757
10113
  skills.command("purge-user").description("Remove all skills from the user-level skills folder for the target agent").option("--agent <agent>", "Target agent host: github-copilot | claude-code (default: github-copilot)").option("--claude", "Shorthand for --agent claude-code").option("--force", "Skip confirmation \u2014 remove all skills without prompting").action((opts) => {
9758
10114
  const start = Date.now();
9759
10115
  try {
@@ -9764,7 +10120,7 @@ function registerSkillsCommands(program2) {
9764
10120
  }
9765
10121
  const skillDirs = fs4.readdirSync(userDir).filter((name) => {
9766
10122
  if (name.startsWith(".")) return false;
9767
- const p = path7.join(userDir, name);
10123
+ const p = path8.join(userDir, name);
9768
10124
  try {
9769
10125
  return fs4.statSync(p).isDirectory();
9770
10126
  } catch {
@@ -9782,8 +10138,8 @@ Re-run with --force to confirm, or use \`pncli skills marketplace purge-plugin\`
9782
10138
  );
9783
10139
  }
9784
10140
  for (const name of skillDirs) {
9785
- const skillDir = path7.resolve(userDir, name);
9786
- if (!skillDir.startsWith(path7.resolve(userDir) + path7.sep)) continue;
10141
+ const skillDir = path8.resolve(userDir, name);
10142
+ if (!skillDir.startsWith(path8.resolve(userDir) + path8.sep)) continue;
9787
10143
  fs4.rmSync(skillDir, { recursive: true, force: true });
9788
10144
  }
9789
10145
  const metaPath = getInstalledMetaPath(userDir);
@@ -9797,7 +10153,7 @@ Re-run with --force to confirm, or use \`pncli skills marketplace purge-plugin\`
9797
10153
  });
9798
10154
  }
9799
10155
  function resolvePluginChoices(marketplacePath) {
9800
- const marketplaceJsonPath = path7.join(marketplacePath, ".claude-plugin", "marketplace.json");
10156
+ const marketplaceJsonPath = path8.join(marketplacePath, ".claude-plugin", "marketplace.json");
9801
10157
  if (fs4.existsSync(marketplaceJsonPath)) {
9802
10158
  try {
9803
10159
  const meta = JSON.parse(fs4.readFileSync(marketplaceJsonPath, "utf8"));
@@ -9807,36 +10163,36 @@ function resolvePluginChoices(marketplacePath) {
9807
10163
  } catch {
9808
10164
  }
9809
10165
  }
9810
- const pluginsDir = path7.join(marketplacePath, "plugins");
10166
+ const pluginsDir = path8.join(marketplacePath, "plugins");
9811
10167
  if (fs4.existsSync(pluginsDir)) {
9812
- return fs4.readdirSync(pluginsDir).filter((name) => fs4.statSync(path7.join(pluginsDir, name)).isDirectory()).map((name) => ({ name, description: "" }));
10168
+ return fs4.readdirSync(pluginsDir).filter((name) => fs4.statSync(path8.join(pluginsDir, name)).isDirectory()).map((name) => ({ name, description: "" }));
9813
10169
  }
9814
10170
  return [];
9815
10171
  }
9816
10172
  function resolveSkillsSrc(marketplacePath, selectedPlugin) {
9817
- const pluginsBase = path7.resolve(marketplacePath, "plugins");
9818
- const skillsSrc = path7.resolve(pluginsBase, selectedPlugin, "skills");
9819
- if (!skillsSrc.startsWith(pluginsBase + path7.sep)) {
10173
+ const pluginsBase = path8.resolve(marketplacePath, "plugins");
10174
+ const skillsSrc = path8.resolve(pluginsBase, selectedPlugin, "skills");
10175
+ if (!skillsSrc.startsWith(pluginsBase + path8.sep)) {
9820
10176
  throw new Error(`Invalid plugin name: "${selectedPlugin}"`);
9821
10177
  }
9822
10178
  return skillsSrc;
9823
10179
  }
9824
10180
  function copyPluginSkills(skillsSrc, targetDir, meta) {
9825
10181
  fs4.mkdirSync(targetDir, { recursive: true });
9826
- const resolvedTarget = path7.resolve(targetDir);
10182
+ const resolvedTarget = path8.resolve(targetDir);
9827
10183
  const skillNames = fs4.readdirSync(skillsSrc).filter(
9828
- (name) => fs4.statSync(path7.join(skillsSrc, name)).isDirectory()
10184
+ (name) => fs4.statSync(path8.join(skillsSrc, name)).isDirectory()
9829
10185
  );
9830
10186
  const installed = [];
9831
10187
  const failed = [];
9832
10188
  for (const skillName of skillNames) {
9833
- const dest = path7.resolve(targetDir, skillName);
9834
- if (!dest.startsWith(resolvedTarget + path7.sep)) {
10189
+ const dest = path8.resolve(targetDir, skillName);
10190
+ if (!dest.startsWith(resolvedTarget + path8.sep)) {
9835
10191
  failed.push(skillName);
9836
10192
  continue;
9837
10193
  }
9838
10194
  fs4.rmSync(dest, { recursive: true, force: true });
9839
- fs4.cpSync(path7.join(skillsSrc, skillName), dest, { recursive: true });
10195
+ fs4.cpSync(path8.join(skillsSrc, skillName), dest, { recursive: true });
9840
10196
  installed.push(skillName);
9841
10197
  }
9842
10198
  if (meta) {
@@ -9852,8 +10208,8 @@ function copyPluginSkills(skillsSrc, targetDir, meta) {
9852
10208
  }
9853
10209
 
9854
10210
  // src/services/jwt/commands.ts
9855
- function base64urlDecode(input2) {
9856
- const base64 = input2.replace(/-/g, "+").replace(/_/g, "/");
10211
+ function base64urlDecode(input3) {
10212
+ const base64 = input3.replace(/-/g, "+").replace(/_/g, "/");
9857
10213
  const padded = base64 + "=".repeat((4 - base64.length % 4) % 4);
9858
10214
  return Buffer.from(padded, "base64").toString("utf8");
9859
10215
  }