@kolatts/pncli 5.1.0 → 5.3.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
@@ -14,7 +14,7 @@ import {
14
14
  import {
15
15
  createHttpClient,
16
16
  validateAlationAccessToken
17
- } from "./chunk-FAMJPKO4.js";
17
+ } from "./chunk-2J2HAFKO.js";
18
18
  import {
19
19
  ExitCode,
20
20
  fail,
@@ -447,34 +447,34 @@ function parseAdoRemote(remoteUrl, adoBaseUrl) {
447
447
  } catch {
448
448
  baseHostname = adoBaseUrl.replace(/\/$/, "").replace(/^https?:\/\//, "").split(/[:/]/)[0].toLowerCase();
449
449
  }
450
- let path10 = remoteUrl;
450
+ let path11 = remoteUrl;
451
451
  let remoteHostname = "";
452
- const sshProtoMatch = path10.match(/^ssh:\/\/[^@]*@?([^/:]+)(?::\d+)?(.*)/);
452
+ const sshProtoMatch = path11.match(/^ssh:\/\/[^@]*@?([^/:]+)(?::\d+)?(.*)/);
453
453
  if (sshProtoMatch) {
454
454
  remoteHostname = sshProtoMatch[1].toLowerCase();
455
- path10 = sshProtoMatch[2];
455
+ path11 = sshProtoMatch[2];
456
456
  } else {
457
- const gitAtMatch = path10.match(/^git@([^:]+)(?::\d+)?:(.*)/);
457
+ const gitAtMatch = path11.match(/^git@([^:]+)(?::\d+)?:(.*)/);
458
458
  if (gitAtMatch) {
459
459
  remoteHostname = gitAtMatch[1].toLowerCase();
460
- path10 = "/" + gitAtMatch[2];
460
+ path11 = "/" + gitAtMatch[2];
461
461
  } else {
462
- const httpsMatch = path10.match(/^https?:\/\/([^/:]+)(?::\d+)?(.*)/);
462
+ const httpsMatch = path11.match(/^https?:\/\/([^/:]+)(?::\d+)?(.*)/);
463
463
  if (httpsMatch) {
464
464
  remoteHostname = httpsMatch[1].toLowerCase();
465
- path10 = httpsMatch[2];
465
+ path11 = httpsMatch[2];
466
466
  }
467
467
  }
468
468
  }
469
469
  if (!remoteHostname || remoteHostname !== baseHostname) return null;
470
- path10 = path10.replace(/\.git$/, "");
471
- const gitIdx = path10.indexOf("/_git/");
472
- const sshIdx = path10.indexOf("/_ssh/");
470
+ path11 = path11.replace(/\.git$/, "");
471
+ const gitIdx = path11.indexOf("/_git/");
472
+ const sshIdx = path11.indexOf("/_ssh/");
473
473
  const markerIdx = gitIdx !== -1 ? gitIdx : sshIdx;
474
474
  if (markerIdx === -1) return null;
475
- const repo = decodeURIComponent(path10.slice(markerIdx + 6));
475
+ const repo = decodeURIComponent(path11.slice(markerIdx + 6));
476
476
  if (!repo) return null;
477
- const before = path10.slice(1, markerIdx);
477
+ const before = path11.slice(1, markerIdx);
478
478
  const parts = before.split("/").filter(Boolean);
479
479
  if (parts.length < 2) return null;
480
480
  const project = decodeURIComponent(parts[parts.length - 1]);
@@ -587,30 +587,30 @@ var BitbucketClient = class {
587
587
  );
588
588
  }
589
589
  async createPR(opts) {
590
- return this.http.bitbucket(
591
- `${API}/projects/${opts.project}/repos/${opts.repo}/pull-requests`,
592
- {
593
- method: "POST",
594
- body: {
595
- title: opts.title,
596
- description: opts.description,
597
- fromRef: {
598
- id: `refs/heads/${opts.source}`,
599
- repository: {
600
- slug: opts.repo,
601
- project: { key: opts.project }
602
- }
603
- },
604
- toRef: {
605
- id: `refs/heads/${opts.target}`,
606
- repository: {
607
- slug: opts.repo,
608
- project: { key: opts.project }
609
- }
610
- },
611
- reviewers: (opts.reviewers ?? []).map((name) => ({ user: { name } }))
590
+ const body = {
591
+ title: opts.title,
592
+ description: opts.description,
593
+ fromRef: {
594
+ id: `refs/heads/${opts.source}`,
595
+ repository: {
596
+ slug: opts.repo,
597
+ project: { key: opts.project }
598
+ }
599
+ },
600
+ toRef: {
601
+ id: `refs/heads/${opts.target}`,
602
+ repository: {
603
+ slug: opts.repo,
604
+ project: { key: opts.project }
612
605
  }
613
606
  }
607
+ };
608
+ if (opts.reviewers && opts.reviewers.length > 0) {
609
+ body.reviewers = opts.reviewers.map((name) => ({ user: { name } }));
610
+ }
611
+ return this.http.bitbucket(
612
+ `${API}/projects/${opts.project}/repos/${opts.repo}/pull-requests`,
613
+ { method: "POST", body }
614
614
  );
615
615
  }
616
616
  async updatePR(opts) {
@@ -1861,7 +1861,7 @@ function registerBitbucketCommands(program2) {
1861
1861
  const { client, project, repo } = getClient2(bb, { project: opts.project, repo: opts.repo });
1862
1862
  const config = loadConfig({ configPath: bb.optsWithGlobals().config });
1863
1863
  const target = opts.target ?? config.defaults.bitbucket?.targetBranch ?? "main";
1864
- const reviewers = opts.reviewers ? opts.reviewers.split(",").map((s) => s.trim()) : [];
1864
+ const reviewers = opts.reviewers ? opts.reviewers.split(",").map((s) => s.trim()) : void 0;
1865
1865
  const data = await client.createPR({ project, repo, title: opts.title, source: opts.source, target, description: opts.description, reviewers });
1866
1866
  success(data, "bitbucket", "create-pr", start);
1867
1867
  } catch (err) {
@@ -1885,7 +1885,7 @@ function registerBitbucketCommands(program2) {
1885
1885
  throw new PncliError("--repos must contain at least one repository slug", 1);
1886
1886
  }
1887
1887
  const title = opts.title ?? `Promote ${opts.from} to ${opts.to}`;
1888
- const reviewers = opts.reviewers ? opts.reviewers.split(",").map((s) => s.trim()) : [];
1888
+ const reviewers = opts.reviewers ? opts.reviewers.split(",").map((s) => s.trim()) : void 0;
1889
1889
  const results = [];
1890
1890
  let created = 0;
1891
1891
  let nothingToPromote = 0;
@@ -2001,21 +2001,21 @@ function registerBitbucketCommands(program2) {
2001
2001
  fail(err, "bitbucket", "reply-comment", start);
2002
2002
  }
2003
2003
  });
2004
- bb.command("resolve-comment").description("Resolve a comment on a pull request").requiredOption("--pr <pr-id>", "Pull request ID").requiredOption("--comment-id <id>", "Comment ID").option("--version <n>", "Comment version", "0").action(async (opts) => {
2004
+ bb.command("resolve-comment").description("Resolve a comment on a pull request").requiredOption("--pr <pr-id>", "Pull request ID").requiredOption("--comment-id <id>", "Comment ID").option("--comment-version <n>", "Comment version, as reported by list-comments", "0").action(async (opts) => {
2005
2005
  const start = Date.now();
2006
2006
  try {
2007
2007
  const { client, project, repo } = getClient2(bb);
2008
- await client.resolveComment(project, repo, parseInt(opts.pr, 10), parseInt(opts.commentId, 10), parseInt(opts.version ?? "0", 10));
2008
+ await client.resolveComment(project, repo, parseInt(opts.pr, 10), parseInt(opts.commentId, 10), parseInt(opts.commentVersion ?? "0", 10));
2009
2009
  success({ resolved: true }, "bitbucket", "resolve-comment", start);
2010
2010
  } catch (err) {
2011
2011
  fail(err, "bitbucket", "resolve-comment", start);
2012
2012
  }
2013
2013
  });
2014
- bb.command("delete-comment").description("Delete a comment on a pull request").requiredOption("--pr <pr-id>", "Pull request ID").requiredOption("--comment-id <id>", "Comment ID").option("--version <n>", "Comment version", "0").action(async (opts) => {
2014
+ bb.command("delete-comment").description("Delete a comment on a pull request").requiredOption("--pr <pr-id>", "Pull request ID").requiredOption("--comment-id <id>", "Comment ID").option("--comment-version <n>", "Comment version, as reported by list-comments", "0").action(async (opts) => {
2015
2015
  const start = Date.now();
2016
2016
  try {
2017
2017
  const { client, project, repo } = getClient2(bb);
2018
- await client.deleteComment(project, repo, parseInt(opts.pr, 10), parseInt(opts.commentId, 10), parseInt(opts.version ?? "0", 10));
2018
+ await client.deleteComment(project, repo, parseInt(opts.pr, 10), parseInt(opts.commentId, 10), parseInt(opts.commentVersion ?? "0", 10));
2019
2019
  success({ deleted: true }, "bitbucket", "delete-comment", start);
2020
2020
  } catch (err) {
2021
2021
  fail(err, "bitbucket", "delete-comment", start);
@@ -2306,8 +2306,8 @@ var GitHubClient = class {
2306
2306
  );
2307
2307
  }
2308
2308
  async createRepo(opts) {
2309
- const path10 = opts.org ? `/orgs/${opts.org}/repos` : "/user/repos";
2310
- return this.http.github(path10, {
2309
+ const path11 = opts.org ? `/orgs/${opts.org}/repos` : "/user/repos";
2310
+ return this.http.github(path11, {
2311
2311
  method: "POST",
2312
2312
  body: {
2313
2313
  name: opts.name,
@@ -6272,8 +6272,8 @@ async function runCredentialChecks(cfg, http) {
6272
6272
  } else {
6273
6273
  try {
6274
6274
  const collection = cfg.defaults.ado?.collection;
6275
- const path10 = collection ? `/${encodeURIComponent(collection)}/_apis/connectionData?api-version=7.1-preview.1` : "/_apis/projectCollections?api-version=7.1";
6276
- await http.ado(path10, { timeoutMs: 1e4 });
6275
+ const path11 = collection ? `/${encodeURIComponent(collection)}/_apis/connectionData?api-version=7.1-preview.1` : "/_apis/projectCollections?api-version=7.1";
6276
+ await http.ado(path11, { timeoutMs: 1e4 });
6277
6277
  results.ado = { status: "valid", message: "ok" };
6278
6278
  } catch (err) {
6279
6279
  results.ado = categorize(err);
@@ -6511,9 +6511,9 @@ async function runCredentialChecks(cfg, http) {
6511
6511
  }
6512
6512
 
6513
6513
  // src/services/skills/commands.ts
6514
- import fs2 from "fs";
6515
- import path7 from "path";
6516
- import os from "os";
6514
+ import fs3 from "fs";
6515
+ import path8 from "path";
6516
+ import os2 from "os";
6517
6517
  import { fileURLToPath } from "url";
6518
6518
  import { execFileSync as execFileSync3 } from "child_process";
6519
6519
  import select from "@inquirer/select";
@@ -6540,6 +6540,170 @@ function getPncliVersion() {
6540
6540
  return cached;
6541
6541
  }
6542
6542
 
6543
+ // src/services/skills/instructions.ts
6544
+ import fs2 from "fs";
6545
+ import path7 from "path";
6546
+ import os from "os";
6547
+ var INSTRUCTIONS_SUBDIR = "instructions";
6548
+ var INSTRUCTION_SOURCE_FILES = ["AGENTS.md", "CLAUDE.md"];
6549
+ var AGENT_INSTRUCTION_SPECS = {
6550
+ "codex": {
6551
+ file: () => path7.join(process.env.CODEX_HOME || path7.join(os.homedir(), ".codex"), "AGENTS.md"),
6552
+ sources: ["AGENTS.md", "CLAUDE.md"]
6553
+ },
6554
+ "github-copilot": {
6555
+ file: () => path7.join(process.env.COPILOT_HOME || path7.join(os.homedir(), ".copilot"), "copilot-instructions.md"),
6556
+ sources: ["AGENTS.md", "CLAUDE.md"]
6557
+ },
6558
+ "claude-code": {
6559
+ file: () => path7.join(process.env.CLAUDE_CONFIG_DIR || path7.join(os.homedir(), ".claude"), "CLAUDE.md"),
6560
+ sources: ["CLAUDE.md", "AGENTS.md"]
6561
+ }
6562
+ };
6563
+ var INSTRUCTION_AGENTS = Object.keys(AGENT_INSTRUCTION_SPECS);
6564
+ function agentInstructionsFile(agent) {
6565
+ const spec = AGENT_INSTRUCTION_SPECS[agent];
6566
+ if (!spec) throw new Error(`Unknown agent: "${agent}". Use: ${INSTRUCTION_AGENTS.join(" | ")}`);
6567
+ return path7.resolve(spec.file());
6568
+ }
6569
+ function findMarketplaceInstructions(marketplacePath) {
6570
+ const dir = path7.join(marketplacePath, INSTRUCTIONS_SUBDIR);
6571
+ return INSTRUCTION_SOURCE_FILES.map((file) => ({ file, path: path7.join(dir, file) })).filter((entry) => {
6572
+ try {
6573
+ return fs2.statSync(entry.path).isFile();
6574
+ } catch {
6575
+ return false;
6576
+ }
6577
+ });
6578
+ }
6579
+ function pickInstructionSource(agent, shipped) {
6580
+ const spec = AGENT_INSTRUCTION_SPECS[agent];
6581
+ if (!spec) throw new Error(`Unknown agent: "${agent}". Use: ${INSTRUCTION_AGENTS.join(" | ")}`);
6582
+ for (const wanted of spec.sources) {
6583
+ const match = shipped.find((s) => s.file === wanted);
6584
+ if (match) return match;
6585
+ }
6586
+ return null;
6587
+ }
6588
+ var MARKER_PREFIX = "pncli:instructions";
6589
+ function escapeRegExp(s) {
6590
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
6591
+ }
6592
+ function assertSafeName(name) {
6593
+ if (!name.trim() || name.includes("-->") || name.includes('"') || /[\r\n]/.test(name)) {
6594
+ throw new Error(`Marketplace name "${name}" cannot be used as an instructions block marker.`);
6595
+ }
6596
+ }
6597
+ function beginMarker(marketplaceName) {
6598
+ assertSafeName(marketplaceName);
6599
+ return `<!-- ${MARKER_PREFIX} marketplace="${marketplaceName}" begin -->`;
6600
+ }
6601
+ function endMarker(marketplaceName) {
6602
+ assertSafeName(marketplaceName);
6603
+ return `<!-- ${MARKER_PREFIX} marketplace="${marketplaceName}" end -->`;
6604
+ }
6605
+ function blockPattern(marketplaceName) {
6606
+ const begin = escapeRegExp(beginMarker(marketplaceName));
6607
+ const end = escapeRegExp(endMarker(marketplaceName));
6608
+ return new RegExp(`${begin}\\r?\\n[\\s\\S]*?${end}`);
6609
+ }
6610
+ function renderManagedBlock(marketplaceName, body, sourceFile) {
6611
+ const trimmed = body.replace(/\r\n/g, "\n").trim();
6612
+ return [
6613
+ beginMarker(marketplaceName),
6614
+ `<!-- Managed by pncli from ${sourceFile} in marketplace "${marketplaceName}". Edits here are overwritten on the next sync; remove with: pncli skills marketplace instructions remove ${marketplaceName} -->`,
6615
+ trimmed,
6616
+ endMarker(marketplaceName)
6617
+ ].join("\n");
6618
+ }
6619
+ function detectEol(content) {
6620
+ return /\r\n/.test(content) ? "\r\n" : "\n";
6621
+ }
6622
+ function upsertManagedBlock(existing, marketplaceName, block) {
6623
+ const eol = detectEol(existing);
6624
+ const rendered = block.replace(/\n/g, eol);
6625
+ const pattern = blockPattern(marketplaceName);
6626
+ const match = pattern.exec(existing);
6627
+ if (match) {
6628
+ if (match[0] === rendered) return { content: existing, action: "unchanged" };
6629
+ return { content: existing.slice(0, match.index) + rendered + existing.slice(match.index + match[0].length), action: "updated" };
6630
+ }
6631
+ const separator = existing.length === 0 ? "" : eol;
6632
+ return { content: `${existing}${separator}${rendered}${eol}`, action: "added" };
6633
+ }
6634
+ function removeManagedBlock(existing, marketplaceName) {
6635
+ const match = blockPattern(marketplaceName).exec(existing);
6636
+ if (!match) return { content: existing, removed: false };
6637
+ const eol = detectEol(existing);
6638
+ let start = match.index;
6639
+ let end = start + match[0].length;
6640
+ if (existing.startsWith(eol, end)) end += eol.length;
6641
+ if (start > 0 && existing.slice(0, start).endsWith(eol)) start -= eol.length;
6642
+ else if (start === 0 && existing.startsWith(eol, end)) end += eol.length;
6643
+ return { content: existing.slice(0, start) + existing.slice(end), removed: true };
6644
+ }
6645
+ function listManagedBlocks(content) {
6646
+ const re = new RegExp(`<!-- ${escapeRegExp(MARKER_PREFIX)} marketplace="([^"]*)" begin -->`, "g");
6647
+ return Array.from(content.matchAll(re)).map((m) => m[1]);
6648
+ }
6649
+ function readFileOrEmpty(file) {
6650
+ try {
6651
+ return fs2.readFileSync(file, "utf8");
6652
+ } catch {
6653
+ return "";
6654
+ }
6655
+ }
6656
+ function applyMarketplaceInstructions(marketplacePath, marketplaceName, agents) {
6657
+ const shipped = findMarketplaceInstructions(marketplacePath);
6658
+ return agents.map((agent) => {
6659
+ const file = agentInstructionsFile(agent);
6660
+ const source = pickInstructionSource(agent, shipped);
6661
+ if (!source) return { agent, file, source: null, action: "skipped" };
6662
+ const body = fs2.readFileSync(source.path, "utf8");
6663
+ const block = renderManagedBlock(marketplaceName, body, `${INSTRUCTIONS_SUBDIR}/${source.file}`);
6664
+ const { content, action } = upsertManagedBlock(readFileOrEmpty(file), marketplaceName, block);
6665
+ if (action !== "unchanged") {
6666
+ fs2.mkdirSync(path7.dirname(file), { recursive: true });
6667
+ fs2.writeFileSync(file, content, "utf8");
6668
+ }
6669
+ return { agent, file, source: `${INSTRUCTIONS_SUBDIR}/${source.file}`, action };
6670
+ });
6671
+ }
6672
+ function removeMarketplaceInstructions(marketplaceName, agents) {
6673
+ return agents.map((agent) => {
6674
+ const file = agentInstructionsFile(agent);
6675
+ const existing = readFileOrEmpty(file);
6676
+ const { content, removed } = removeManagedBlock(existing, marketplaceName);
6677
+ if (removed) fs2.writeFileSync(file, content, "utf8");
6678
+ return { agent, file, removed };
6679
+ });
6680
+ }
6681
+ function marketplaceInstructionsStatus(marketplacePath, marketplaceName, agents) {
6682
+ const shipped = marketplacePath && fs2.existsSync(marketplacePath) ? findMarketplaceInstructions(marketplacePath) : [];
6683
+ return agents.map((agent) => {
6684
+ const file = agentInstructionsFile(agent);
6685
+ const fileExists = fs2.existsSync(file);
6686
+ const existing = fileExists ? readFileOrEmpty(file) : "";
6687
+ const installed = listManagedBlocks(existing).includes(marketplaceName);
6688
+ const source = pickInstructionSource(agent, shipped);
6689
+ let upToDate = null;
6690
+ if (installed && source) {
6691
+ const block = renderManagedBlock(marketplaceName, fs2.readFileSync(source.path, "utf8"), `${INSTRUCTIONS_SUBDIR}/${source.file}`);
6692
+ upToDate = upsertManagedBlock(existing, marketplaceName, block).action === "unchanged";
6693
+ } else if (installed) {
6694
+ upToDate = false;
6695
+ }
6696
+ return {
6697
+ agent,
6698
+ file,
6699
+ fileExists,
6700
+ source: source ? `${INSTRUCTIONS_SUBDIR}/${source.file}` : null,
6701
+ installed,
6702
+ upToDate
6703
+ };
6704
+ });
6705
+ }
6706
+
6543
6707
  // src/services/skills/commands.ts
6544
6708
  var BACK = "__back__";
6545
6709
  var ALL_MARKETPLACES = "__all_marketplaces__";
@@ -6564,7 +6728,7 @@ function repoNameFromUrl(url) {
6564
6728
  }
6565
6729
  }
6566
6730
  function defaultMarketplacePath(url) {
6567
- return path7.join(os.homedir(), ".agents", "marketplaces", repoNameFromUrl(url));
6731
+ return path8.join(os2.homedir(), ".agents", "marketplaces", repoNameFromUrl(url));
6568
6732
  }
6569
6733
  function marketplaceLabel(m) {
6570
6734
  return m.name ?? repoNameFromUrl(m.repoUrl ?? "");
@@ -6619,9 +6783,9 @@ function assertInteractive(hint) {
6619
6783
  }
6620
6784
  }
6621
6785
  var AGENT_PATHS = {
6622
- "codex": { project: ".agents/skills", user: path7.join(os.homedir(), ".agents/skills") },
6623
- "github-copilot": { project: ".github/skills", user: path7.join(os.homedir(), ".copilot/skills") },
6624
- "claude-code": { project: ".claude/skills", user: path7.join(os.homedir(), ".claude/skills") }
6786
+ "codex": { project: ".agents/skills", user: path8.join(os2.homedir(), ".agents/skills") },
6787
+ "github-copilot": { project: ".github/skills", user: path8.join(os2.homedir(), ".copilot/skills") },
6788
+ "claude-code": { project: ".claude/skills", user: path8.join(os2.homedir(), ".claude/skills") }
6625
6789
  };
6626
6790
  var DEFAULT_AGENT = "codex";
6627
6791
  var AGENT_CHOICES = Object.keys(AGENT_PATHS).join(" | ");
@@ -6648,23 +6812,23 @@ function findGitRoot(from = process.cwd()) {
6648
6812
  encoding: "utf8",
6649
6813
  stdio: ["pipe", "pipe", "pipe"]
6650
6814
  }).trim();
6651
- return root ? path7.resolve(root) : null;
6815
+ return root ? path8.resolve(root) : null;
6652
6816
  } catch {
6653
6817
  return null;
6654
6818
  }
6655
6819
  }
6656
6820
  function resolveProjectPath(relativePath) {
6657
6821
  const root = findGitRoot();
6658
- return root ? path7.resolve(root, relativePath) : path7.resolve(relativePath);
6822
+ return root ? path8.resolve(root, relativePath) : path8.resolve(relativePath);
6659
6823
  }
6660
6824
  function resolveScopedPath(agentPaths, scope) {
6661
- return scope === "project" ? resolveProjectPath(agentPaths.project) : path7.resolve(agentPaths.user);
6825
+ return scope === "project" ? resolveProjectPath(agentPaths.project) : path8.resolve(agentPaths.user);
6662
6826
  }
6663
6827
  function hasInstalledPncliSkill() {
6664
6828
  try {
6665
6829
  for (const agentPaths of Object.values(AGENT_PATHS)) {
6666
6830
  for (const scope of ["project", "user"]) {
6667
- if (fs2.existsSync(path7.join(resolveScopedPath(agentPaths, scope), "pncli", "SKILL.md"))) {
6831
+ if (fs3.existsSync(path8.join(resolveScopedPath(agentPaths, scope), "pncli", "SKILL.md"))) {
6668
6832
  return true;
6669
6833
  }
6670
6834
  }
@@ -6674,20 +6838,30 @@ function hasInstalledPncliSkill() {
6674
6838
  return false;
6675
6839
  }
6676
6840
  function resolveTargetDir(opts) {
6677
- if (opts.target) return path7.resolve(opts.target);
6841
+ if (opts.target) return path8.resolve(opts.target);
6678
6842
  const agentConfig = resolveAgentPaths(resolveAgentName(opts));
6679
6843
  return resolveScopedPath(agentConfig, opts.scope ?? "user");
6680
6844
  }
6845
+ function resolveInstallTargets(opts, scope = "user") {
6846
+ if (opts.allAgents) {
6847
+ if (opts.claude || opts.agent) {
6848
+ throw new Error("--all-agents cannot be combined with --claude or --agent");
6849
+ }
6850
+ return Object.entries(AGENT_PATHS).map(([agent2, paths]) => ({ agent: agent2, target: resolveScopedPath(paths, scope) }));
6851
+ }
6852
+ const agent = resolveAgentName(opts);
6853
+ return [{ agent, target: resolveScopedPath(resolveAgentPaths(agent), scope) }];
6854
+ }
6681
6855
  function getBundledSkillsDir() {
6682
6856
  try {
6683
6857
  const thisFile = fileURLToPath(import.meta.url);
6684
- return path7.resolve(path7.dirname(thisFile), "..", "skills");
6858
+ return path8.resolve(path8.dirname(thisFile), "..", "skills");
6685
6859
  } catch {
6686
6860
  return "";
6687
6861
  }
6688
6862
  }
6689
6863
  function getInstalledMetaPath(targetDir) {
6690
- return path7.join(targetDir, ".pncli-installed.json");
6864
+ return path8.join(targetDir, ".pncli-installed.json");
6691
6865
  }
6692
6866
  var SKILL_ORIGIN_FILENAME = "pncli-origin.json";
6693
6867
  var DISABLED_SUBDIR = ".pncli-disabled";
@@ -6698,13 +6872,13 @@ function readInstalledMeta(targetDir) {
6698
6872
  return { version: 1, skills: {} };
6699
6873
  }
6700
6874
  function getSkillOriginPath(skillDir) {
6701
- return path7.join(skillDir, SKILL_ORIGIN_FILENAME);
6875
+ return path8.join(skillDir, SKILL_ORIGIN_FILENAME);
6702
6876
  }
6703
6877
  function readSkillOrigin(skillDir) {
6704
6878
  const originPath = getSkillOriginPath(skillDir);
6705
- if (!fs2.existsSync(originPath)) return null;
6879
+ if (!fs3.existsSync(originPath)) return null;
6706
6880
  try {
6707
- const raw = JSON.parse(fs2.readFileSync(originPath, "utf8"));
6881
+ const raw = JSON.parse(fs3.readFileSync(originPath, "utf8"));
6708
6882
  if (raw && raw.version === 1 && raw.source) return raw;
6709
6883
  } catch {
6710
6884
  }
@@ -6716,7 +6890,7 @@ function matchesMarketplaceFilter(record, filter) {
6716
6890
  function resolveSkillRecord(meta, targetDir, skillName) {
6717
6891
  const fromMeta = meta.skills[skillName];
6718
6892
  if (fromMeta) return fromMeta;
6719
- const perSkill = readSkillOrigin(path7.join(targetDir, skillName));
6893
+ const perSkill = readSkillOrigin(path8.join(targetDir, skillName));
6720
6894
  if (!perSkill) return null;
6721
6895
  return {
6722
6896
  source: perSkill.source,
@@ -6729,28 +6903,28 @@ function resolveSkillRecord(meta, targetDir, skillName) {
6729
6903
  };
6730
6904
  }
6731
6905
  function listActiveSkillDirs(targetDir) {
6732
- if (!fs2.existsSync(targetDir)) return [];
6733
- return fs2.readdirSync(targetDir).filter((name) => {
6906
+ if (!fs3.existsSync(targetDir)) return [];
6907
+ return fs3.readdirSync(targetDir).filter((name) => {
6734
6908
  if (name.startsWith(".")) return false;
6735
- const dir = path7.join(targetDir, name);
6909
+ const dir = path8.join(targetDir, name);
6736
6910
  try {
6737
- if (!fs2.statSync(dir).isDirectory()) return false;
6911
+ if (!fs3.statSync(dir).isDirectory()) return false;
6738
6912
  } catch {
6739
6913
  return false;
6740
6914
  }
6741
- return fs2.existsSync(path7.join(dir, "SKILL.md"));
6915
+ return fs3.existsSync(path8.join(dir, "SKILL.md"));
6742
6916
  });
6743
6917
  }
6744
6918
  function disablePluginSkills(targetDir, plugin, marketplaceFilter) {
6745
- const resolvedTarget = path7.resolve(targetDir);
6746
- const stashDir = path7.join(targetDir, DISABLED_SUBDIR);
6919
+ const resolvedTarget = path8.resolve(targetDir);
6920
+ const stashDir = path8.join(targetDir, DISABLED_SUBDIR);
6747
6921
  const meta = readInstalledMeta(targetDir);
6748
6922
  const disabled = [];
6749
6923
  const alreadyDisabled = [];
6750
6924
  const skipped = [];
6751
6925
  for (const skillName of listActiveSkillDirs(targetDir)) {
6752
- const skillDir = path7.resolve(targetDir, skillName);
6753
- if (!skillDir.startsWith(resolvedTarget + path7.sep)) continue;
6926
+ const skillDir = path8.resolve(targetDir, skillName);
6927
+ if (!skillDir.startsWith(resolvedTarget + path8.sep)) continue;
6754
6928
  const record = resolveSkillRecord(meta, targetDir, skillName);
6755
6929
  if (!record || record.source !== "marketplace") {
6756
6930
  skipped.push(skillName);
@@ -6760,10 +6934,10 @@ function disablePluginSkills(targetDir, plugin, marketplaceFilter) {
6760
6934
  skipped.push(skillName);
6761
6935
  continue;
6762
6936
  }
6763
- const stashDest = path7.join(stashDir, skillName);
6764
- fs2.mkdirSync(stashDir, { recursive: true });
6765
- if (fs2.existsSync(stashDest)) fs2.rmSync(stashDest, { recursive: true, force: true });
6766
- fs2.renameSync(skillDir, stashDest);
6937
+ const stashDest = path8.join(stashDir, skillName);
6938
+ fs3.mkdirSync(stashDir, { recursive: true });
6939
+ if (fs3.existsSync(stashDest)) fs3.rmSync(stashDest, { recursive: true, force: true });
6940
+ fs3.renameSync(skillDir, stashDest);
6767
6941
  delete meta.skills[skillName];
6768
6942
  meta.disabled = meta.disabled ?? {};
6769
6943
  meta.disabled[skillName] = record;
@@ -6775,13 +6949,13 @@ function disablePluginSkills(targetDir, plugin, marketplaceFilter) {
6775
6949
  }
6776
6950
  }
6777
6951
  if (disabled.length > 0) {
6778
- fs2.writeFileSync(getInstalledMetaPath(targetDir), JSON.stringify(meta, null, 2), "utf8");
6952
+ fs3.writeFileSync(getInstalledMetaPath(targetDir), JSON.stringify(meta, null, 2), "utf8");
6779
6953
  }
6780
6954
  return { disabled, alreadyDisabled, skipped };
6781
6955
  }
6782
6956
  function enablePluginSkills(targetDir, plugin, marketplaceFilter) {
6783
- const resolvedTarget = path7.resolve(targetDir);
6784
- const stashDir = path7.join(targetDir, DISABLED_SUBDIR);
6957
+ const resolvedTarget = path8.resolve(targetDir);
6958
+ const stashDir = path8.join(targetDir, DISABLED_SUBDIR);
6785
6959
  const meta = readInstalledMeta(targetDir);
6786
6960
  const enabled = [];
6787
6961
  const stashMissing = [];
@@ -6792,27 +6966,27 @@ function enablePluginSkills(targetDir, plugin, marketplaceFilter) {
6792
6966
  skipped.push(skillName);
6793
6967
  continue;
6794
6968
  }
6795
- const dest = path7.resolve(targetDir, skillName);
6796
- if (!dest.startsWith(resolvedTarget + path7.sep)) {
6969
+ const dest = path8.resolve(targetDir, skillName);
6970
+ if (!dest.startsWith(resolvedTarget + path8.sep)) {
6797
6971
  skipped.push(skillName);
6798
6972
  continue;
6799
6973
  }
6800
- const stashSrc = path7.join(stashDir, skillName);
6801
- if (!fs2.existsSync(stashSrc)) {
6974
+ const stashSrc = path8.join(stashDir, skillName);
6975
+ if (!fs3.existsSync(stashSrc)) {
6802
6976
  stashMissing.push(skillName);
6803
6977
  continue;
6804
6978
  }
6805
- if (fs2.existsSync(dest)) fs2.rmSync(dest, { recursive: true, force: true });
6806
- fs2.renameSync(stashSrc, dest);
6979
+ if (fs3.existsSync(dest)) fs3.rmSync(dest, { recursive: true, force: true });
6980
+ fs3.renameSync(stashSrc, dest);
6807
6981
  meta.skills[skillName] = record;
6808
6982
  delete meta.disabled[skillName];
6809
6983
  enabled.push(skillName);
6810
6984
  }
6811
- if (fs2.existsSync(stashDir) && fs2.readdirSync(stashDir).length === 0) {
6812
- fs2.rmdirSync(stashDir);
6985
+ if (fs3.existsSync(stashDir) && fs3.readdirSync(stashDir).length === 0) {
6986
+ fs3.rmdirSync(stashDir);
6813
6987
  }
6814
6988
  if (enabled.length > 0) {
6815
- fs2.writeFileSync(getInstalledMetaPath(targetDir), JSON.stringify(meta, null, 2), "utf8");
6989
+ fs3.writeFileSync(getInstalledMetaPath(targetDir), JSON.stringify(meta, null, 2), "utf8");
6816
6990
  }
6817
6991
  return { enabled, stashMissing, skipped, hadDisabled: disabledEntries.length > 0 };
6818
6992
  }
@@ -6878,11 +7052,11 @@ function getInstalledPluginsForMarketplace(targetDir, marketplaceName, repoUrl)
6878
7052
  function readCustomTargets(globalConfig) {
6879
7053
  const raw = globalConfig.skillsTargets;
6880
7054
  if (!Array.isArray(raw)) return [];
6881
- return [...new Set(raw.filter((t) => typeof t === "string" && t.length > 0).map((t) => path7.resolve(t)))];
7055
+ return [...new Set(raw.filter((t) => typeof t === "string" && t.length > 0).map((t) => path8.resolve(t)))];
6882
7056
  }
6883
7057
  function rememberCustomTarget(configPath, targetDir) {
6884
- const resolved = path7.resolve(targetDir);
6885
- const builtIn = Object.values(AGENT_PATHS).flatMap((a) => [path7.resolve(a.user), resolveProjectPath(a.project)]);
7058
+ const resolved = path8.resolve(targetDir);
7059
+ const builtIn = Object.values(AGENT_PATHS).flatMap((a) => [path8.resolve(a.user), resolveProjectPath(a.project)]);
6886
7060
  if (builtIn.includes(resolved)) return false;
6887
7061
  const existing = loadJsonFile(configPath) ?? {};
6888
7062
  const targets = readCustomTargets(existing);
@@ -6891,7 +7065,7 @@ function rememberCustomTarget(configPath, targetDir) {
6891
7065
  return true;
6892
7066
  }
6893
7067
  function forgetCustomTarget(configPath, targetDir) {
6894
- const resolved = path7.resolve(targetDir);
7068
+ const resolved = path8.resolve(targetDir);
6895
7069
  const existing = loadJsonFile(configPath) ?? {};
6896
7070
  const targets = readCustomTargets(existing);
6897
7071
  if (!targets.includes(resolved)) return false;
@@ -6899,12 +7073,12 @@ function forgetCustomTarget(configPath, targetDir) {
6899
7073
  return true;
6900
7074
  }
6901
7075
  function summarizeLocation(agent, scope, targetDir) {
6902
- const resolved = path7.resolve(targetDir);
7076
+ const resolved = path8.resolve(targetDir);
6903
7077
  const base = {
6904
7078
  agent,
6905
7079
  scope,
6906
7080
  path: resolved,
6907
- exists: fs2.existsSync(resolved),
7081
+ exists: fs3.existsSync(resolved),
6908
7082
  totalSkills: 0,
6909
7083
  marketplaceSkills: 0,
6910
7084
  bundledSkills: 0,
@@ -6923,8 +7097,8 @@ function summarizeLocation(agent, scope, targetDir) {
6923
7097
  }
6924
7098
  const disabledNames = Object.keys(meta.disabled ?? {});
6925
7099
  base.disabledSkills = disabledNames.length;
6926
- const stashDir = path7.join(resolved, DISABLED_SUBDIR);
6927
- base.disabledStashMissing = disabledNames.filter((name) => !fs2.existsSync(path7.join(stashDir, name)));
7100
+ const stashDir = path8.join(resolved, DISABLED_SUBDIR);
7101
+ base.disabledStashMissing = disabledNames.filter((name) => !fs3.existsSync(path8.join(stashDir, name)));
6928
7102
  return base;
6929
7103
  }
6930
7104
  function listKnownLocations(globalConfig) {
@@ -6949,7 +7123,7 @@ function collectSkillStatus(globalConfig, locations) {
6949
7123
  const { byName, byUrl } = buildMarketplaceIndex(getAllMarketplaces(globalConfig));
6950
7124
  const remoteCache = /* @__PURE__ */ new Map();
6951
7125
  const remoteFor = (localPath) => {
6952
- if (!localPath || !fs2.existsSync(localPath)) return null;
7126
+ if (!localPath || !fs3.existsSync(localPath)) return null;
6953
7127
  if (!remoteCache.has(localPath)) remoteCache.set(localPath, getRepoRemoteUrl(localPath));
6954
7128
  return remoteCache.get(localPath) ?? null;
6955
7129
  };
@@ -6962,7 +7136,7 @@ function collectSkillStatus(globalConfig, locations) {
6962
7136
  const registered = (recordedName ? byName.get(recordedName) : void 0) ?? (record?.installedFrom ? byUrl.get(record.installedFrom) : void 0) ?? null;
6963
7137
  records.push({
6964
7138
  skill: skillName,
6965
- path: enabled ? path7.join(location.path, skillName) : path7.join(location.path, DISABLED_SUBDIR, skillName),
7139
+ path: enabled ? path8.join(location.path, skillName) : path8.join(location.path, DISABLED_SUBDIR, skillName),
6966
7140
  agent: location.agent,
6967
7141
  scope: location.scope,
6968
7142
  location: location.path,
@@ -6995,16 +7169,16 @@ function recordInstalledSkills(targetDir, skillNames, record) {
6995
7169
  for (const skillName of skillNames) {
6996
7170
  const fullRecord = { pncliVersion: getPncliVersion(), ...record, installedAt: now };
6997
7171
  meta.skills[skillName] = fullRecord;
6998
- const skillDir = path7.join(targetDir, skillName);
6999
- if (fs2.existsSync(skillDir)) {
7172
+ const skillDir = path8.join(targetDir, skillName);
7173
+ if (fs3.existsSync(skillDir)) {
7000
7174
  const origin = { version: 1, ...fullRecord };
7001
7175
  try {
7002
- fs2.writeFileSync(getSkillOriginPath(skillDir), JSON.stringify(origin, null, 2), "utf8");
7176
+ fs3.writeFileSync(getSkillOriginPath(skillDir), JSON.stringify(origin, null, 2), "utf8");
7003
7177
  } catch {
7004
7178
  }
7005
7179
  }
7006
7180
  }
7007
- fs2.writeFileSync(getInstalledMetaPath(targetDir), JSON.stringify(meta, null, 2), "utf8");
7181
+ fs3.writeFileSync(getInstalledMetaPath(targetDir), JSON.stringify(meta, null, 2), "utf8");
7008
7182
  }
7009
7183
  function findStaleBundledSkills(targetDir) {
7010
7184
  const currentVersion = getPncliVersion();
@@ -7080,8 +7254,8 @@ function upsertMarketplace(all, entry) {
7080
7254
  }
7081
7255
  }
7082
7256
  function cloneOrReuseMarketplace(url, resolvedPath, opts, marketplaceName) {
7083
- const hasGit = fs2.existsSync(path7.join(resolvedPath, ".git"));
7084
- if (fs2.existsSync(resolvedPath) && !hasGit && fs2.readdirSync(resolvedPath).length > 0) {
7257
+ const hasGit = fs3.existsSync(path8.join(resolvedPath, ".git"));
7258
+ if (fs3.existsSync(resolvedPath) && !hasGit && fs3.readdirSync(resolvedPath).length > 0) {
7085
7259
  throw new Error(`Directory already exists and is not a git repo: ${resolvedPath}`);
7086
7260
  }
7087
7261
  if (hasGit) {
@@ -7138,7 +7312,7 @@ function installPluginsForMarketplace(marketplacePath, marketplaceName, repoUrl,
7138
7312
  const branch = detectRepoBranch(marketplacePath);
7139
7313
  for (const pluginName of pluginNames) {
7140
7314
  const skillsSrc = resolveSkillsSrc(marketplacePath, pluginName);
7141
- if (!fs2.existsSync(skillsSrc)) {
7315
+ if (!fs3.existsSync(skillsSrc)) {
7142
7316
  results[pluginName] = { installed: [], failed: [] };
7143
7317
  warn(`No skills directory found for plugin "${pluginName}" in "${marketplaceName}" \u2014 skipping.`);
7144
7318
  continue;
@@ -7152,61 +7326,108 @@ function installPluginsForMarketplace(marketplacePath, marketplaceName, repoUrl,
7152
7326
  results[pluginName] = { installed, failed };
7153
7327
  totalInstalled += installed.length;
7154
7328
  for (const skill of installed) {
7155
- warn(` ${skill}: ${path7.join(skillsSrc, skill)} \u2192 ${path7.join(targetDir, skill)}`);
7329
+ log(` ${skill}: ${path8.join(skillsSrc, skill)} \u2192 ${path8.join(targetDir, skill)}`);
7156
7330
  }
7157
7331
  if (failed.length > 0) {
7158
7332
  warn(`Skipped ${failed.length} skill(s) with invalid names in "${pluginName}": ${failed.join(", ")}`);
7159
7333
  }
7160
7334
  }
7335
+ warn(`Installed ${totalInstalled} skill(s) from ${pluginNames.length} plugin(s) in "${marketplaceName}" to ${targetDir}`);
7161
7336
  return { results, totalInstalled };
7162
7337
  }
7163
- function installAllPlugins(resolvedPath, marketplaceName, url, targetDir) {
7338
+ function installMarketplaceToTarget(m, marketplacePath, pluginChoices, pluginFilter, target, opts) {
7339
+ const marketplaceName = marketplaceLabel(m);
7340
+ const base = { agent: target.agent, target: target.target };
7341
+ const installedHere = getInstalledPluginsForMarketplace(target.target, marketplaceName, m.repoUrl).filter((name) => pluginChoices.some((p) => p.name === name));
7342
+ let requested;
7343
+ if (pluginFilter === "all") {
7344
+ if (opts.installedOnly) {
7345
+ if (installedHere.length === 0) {
7346
+ warn(`No installed plugins from "${marketplaceName}" in ${target.target} \u2014 skipping. Run marketplace sync without --installed-only to install plugins.`);
7347
+ return { ...base, plugins: {}, total: 0, skipped: true, installedOnly: true, message: "No installed plugins found \u2014 nothing to sync." };
7348
+ }
7349
+ requested = installedHere;
7350
+ } else {
7351
+ requested = pluginChoices.map((p) => p.name);
7352
+ }
7353
+ } else {
7354
+ requested = [pluginFilter];
7355
+ }
7356
+ const missing = requested.filter((name) => !installedHere.includes(name));
7357
+ if (!opts.updated && !opts.force) {
7358
+ if (missing.length === 0) {
7359
+ return { ...base, plugins: {}, total: 0, skipped: true, message: "No changes detected \u2014 skipping install. Use --force to reinstall anyway." };
7360
+ }
7361
+ requested = missing;
7362
+ }
7363
+ const { results, totalInstalled } = installPluginsForMarketplace(marketplacePath, marketplaceName, m.repoUrl, requested, target.target);
7364
+ return { ...base, plugins: results, total: totalInstalled };
7365
+ }
7366
+ function applyInstructionsForTargets(m, marketplacePath, targets, enabled) {
7367
+ if (!enabled || findMarketplaceInstructions(marketplacePath).length === 0) return void 0;
7368
+ const results = applyMarketplaceInstructions(marketplacePath, marketplaceLabel(m), targets.map((t) => t.agent));
7369
+ for (const r of results) {
7370
+ if (r.action === "added" || r.action === "updated") warn(`Instructions ${r.action} in ${r.file} (from ${r.source})`);
7371
+ }
7372
+ return results;
7373
+ }
7374
+ function shapeSyncResult(marketplaceName, updated, pluginFilter, targetResults, extras) {
7375
+ const tail = {
7376
+ marketplaceUpdated: updated,
7377
+ ...extras.installedOnly ? { installedOnly: true } : {},
7378
+ ...extras.instructions ? { instructions: extras.instructions } : {}
7379
+ };
7380
+ if (targetResults.length === 1) {
7381
+ const r = targetResults[0];
7382
+ if (r.skipped) {
7383
+ return { marketplace: marketplaceName, updated: false, skipped: true, target: r.target, message: r.message, ...tail };
7384
+ }
7385
+ if (pluginFilter === "all") {
7386
+ return { marketplace: marketplaceName, plugins: r.plugins, total: r.total, target: r.target, ...tail };
7387
+ }
7388
+ const single = r.plugins[pluginFilter] ?? { installed: [], failed: [] };
7389
+ return { marketplace: marketplaceName, plugin: pluginFilter, installed: single.installed, failed: single.failed, total: single.installed.length, target: r.target, ...tail };
7390
+ }
7391
+ return {
7392
+ marketplace: marketplaceName,
7393
+ ...pluginFilter === "all" ? {} : { plugin: pluginFilter },
7394
+ targets: targetResults,
7395
+ total: targetResults.reduce((sum, r) => sum + r.total, 0),
7396
+ ...tail
7397
+ };
7398
+ }
7399
+ function installAllPlugins(m, resolvedPath, targets) {
7164
7400
  const pluginChoices = resolvePluginChoices(resolvedPath);
7165
7401
  if (pluginChoices.length === 0) {
7166
7402
  warn("No plugins found in marketplace. Check the marketplace repository structure.");
7167
- return { pluginResults: {}, totalInstalled: 0 };
7403
+ return targets.map((t) => ({ ...t, plugins: {}, total: 0 }));
7168
7404
  }
7169
- warn(`Installing ${pluginChoices.length} plugin(s) to ${targetDir}...`);
7170
- const { results, totalInstalled } = installPluginsForMarketplace(resolvedPath, marketplaceName, url, pluginChoices.map((p) => p.name), targetDir);
7171
- return { pluginResults: results, totalInstalled };
7405
+ return targets.map((t) => installMarketplaceToTarget(m, resolvedPath, pluginChoices, "all", t, { updated: true, force: true, installedOnly: false }));
7406
+ }
7407
+ function isBareMarketplaceSync(plugin, opts) {
7408
+ return plugin === void 0 && !opts.marketplace && !opts.force;
7172
7409
  }
7173
- function syncMarketplacePlugins(m, targetDir, force, pluginFilter, installedOnly = false) {
7410
+ function syncMarketplacePlugins(m, targets, pluginFilter, opts) {
7174
7411
  const marketplaceName = marketplaceLabel(m);
7175
7412
  try {
7176
7413
  const marketplacePath = m.localPath;
7177
- if (!marketplacePath || !fs2.existsSync(marketplacePath)) {
7414
+ if (!marketplacePath || !fs3.existsSync(marketplacePath)) {
7178
7415
  warn(`Marketplace "${marketplaceName}" local path not found \u2014 skipping.`);
7179
7416
  return { marketplace: marketplaceName, skipped: true, message: "Local path not found." };
7180
7417
  }
7181
7418
  const { updated } = pullMarketplace(marketplacePath, m.repoUrl, m.token, marketplaceName);
7182
- if (!updated && !force) {
7183
- return { marketplace: marketplaceName, marketplaceUpdated: false, skipped: true, message: "No changes detected \u2014 skipping install. Use --force to reinstall anyway." };
7184
- }
7185
7419
  const pluginChoices = resolvePluginChoices(marketplacePath);
7186
7420
  if (pluginChoices.length === 0) {
7187
7421
  warn(`No plugins found in marketplace "${marketplaceName}" \u2014 skipping.`);
7188
7422
  return { marketplace: marketplaceName, skipped: true, message: "No plugins found." };
7189
7423
  }
7190
- let pluginNames;
7191
- if (pluginFilter === "all") {
7192
- if (installedOnly) {
7193
- const installed = getInstalledPluginsForMarketplace(targetDir, marketplaceName, m.repoUrl).filter((name) => pluginChoices.some((p) => p.name === name));
7194
- if (installed.length === 0) {
7195
- warn(`No installed plugins found for "${marketplaceName}" \u2014 skipping. Run marketplace sync without --installed-only to install plugins.`);
7196
- return { marketplace: marketplaceName, skipped: true, installedOnly: true, message: "No installed plugins found \u2014 nothing to sync." };
7197
- }
7198
- pluginNames = installed;
7199
- } else {
7200
- pluginNames = pluginChoices.map((p) => p.name);
7201
- }
7202
- } else if (pluginChoices.some((p) => p.name === pluginFilter)) {
7203
- pluginNames = [pluginFilter];
7204
- } else {
7424
+ if (pluginFilter !== "all" && !pluginChoices.some((p) => p.name === pluginFilter)) {
7205
7425
  warn(`Plugin "${pluginFilter}" not found in "${marketplaceName}" \u2014 skipping.`);
7206
7426
  return { marketplace: marketplaceName, skipped: true, message: `Plugin "${pluginFilter}" not found.` };
7207
7427
  }
7208
- const { results, totalInstalled } = installPluginsForMarketplace(marketplacePath, marketplaceName, m.repoUrl, pluginNames, targetDir);
7209
- return { marketplace: marketplaceName, plugins: results, total: totalInstalled, marketplaceUpdated: updated };
7428
+ const targetResults = targets.map((t) => installMarketplaceToTarget(m, marketplacePath, pluginChoices, pluginFilter, t, { updated, ...opts }));
7429
+ const instructions = applyInstructionsForTargets(m, marketplacePath, targets, opts.instructions);
7430
+ return shapeSyncResult(marketplaceName, updated, pluginFilter, targetResults, { installedOnly: opts.installedOnly, instructions });
7210
7431
  } catch (err) {
7211
7432
  const message = err instanceof Error ? err.message : String(err);
7212
7433
  warn(`Marketplace "${marketplaceName}" failed \u2014 skipping. ${message}`);
@@ -7214,7 +7435,7 @@ function syncMarketplacePlugins(m, targetDir, force, pluginFilter, installedOnly
7214
7435
  }
7215
7436
  }
7216
7437
  function performMarketplaceAdd(url, localPath, opts) {
7217
- const resolvedPath = path7.resolve(localPath ?? defaultMarketplacePath(url));
7438
+ const resolvedPath = path8.resolve(localPath ?? defaultMarketplacePath(url));
7218
7439
  const marketplaceName = opts.name ?? repoNameFromUrl(url);
7219
7440
  cloneOrReuseMarketplace(url, resolvedPath, opts, marketplaceName);
7220
7441
  const configPath = getGlobalConfigPath();
@@ -7227,17 +7448,18 @@ function performMarketplaceAdd(url, localPath, opts) {
7227
7448
  };
7228
7449
  upsertMarketplace(all, entry);
7229
7450
  saveMarketplaces(configPath, existing, all);
7230
- const targetDir = resolveAgentPaths(resolveAgentName(opts)).user;
7231
- const { pluginResults, totalInstalled } = installAllPlugins(resolvedPath, marketplaceName, url, targetDir);
7451
+ const targets = resolveInstallTargets(opts);
7452
+ const targetResults = installAllPlugins(entry, resolvedPath, targets);
7453
+ const instructions = applyInstructionsForTargets(entry, resolvedPath, targets, opts.instructions !== false);
7232
7454
  return {
7233
7455
  name: marketplaceName,
7234
7456
  repoUrl: url,
7235
7457
  localPath: resolvedPath,
7236
7458
  branch: opts.branch ?? null,
7237
7459
  tokenConfigured: !!opts.token,
7238
- plugins: pluginResults,
7239
- total: totalInstalled,
7240
- target: targetDir
7460
+ // One target keeps the flat shape earlier versions emitted; several nest under `targets`.
7461
+ ...targetResults.length === 1 ? { plugins: targetResults[0].plugins, total: targetResults[0].total, target: targetResults[0].target } : { targets: targetResults, total: targetResults.reduce((sum, r) => sum + r.total, 0) },
7462
+ ...instructions ? { instructions } : {}
7241
7463
  };
7242
7464
  }
7243
7465
  function performMarketplaceRemove(name) {
@@ -7271,8 +7493,8 @@ function listBundledSkillDirs() {
7271
7493
  let skillDirs = [];
7272
7494
  if (bundledDir !== "") {
7273
7495
  try {
7274
- skillDirs = fs2.readdirSync(bundledDir).filter(
7275
- (name) => fs2.existsSync(path7.join(bundledDir, name, "SKILL.md"))
7496
+ skillDirs = fs3.readdirSync(bundledDir).filter(
7497
+ (name) => fs3.existsSync(path8.join(bundledDir, name, "SKILL.md"))
7276
7498
  );
7277
7499
  } catch {
7278
7500
  }
@@ -7283,37 +7505,37 @@ function listBundledSkillDirs() {
7283
7505
  return skillDirs;
7284
7506
  }
7285
7507
  function installBundledSkillsTo(targetDir, skillDirs) {
7286
- const resolvedTarget = path7.resolve(targetDir);
7508
+ const resolvedTarget = path8.resolve(targetDir);
7287
7509
  const bundledDir = getBundledSkillsDir();
7288
7510
  const installed = [];
7289
7511
  const failed = [];
7290
7512
  for (const skillName of skillDirs) {
7291
- const existingDir = path7.resolve(targetDir, skillName);
7292
- if (!existingDir.startsWith(resolvedTarget + path7.sep)) continue;
7293
- if (fs2.existsSync(existingDir)) {
7294
- fs2.rmSync(existingDir, { recursive: true, force: true });
7513
+ const existingDir = path8.resolve(targetDir, skillName);
7514
+ if (!existingDir.startsWith(resolvedTarget + path8.sep)) continue;
7515
+ if (fs3.existsSync(existingDir)) {
7516
+ fs3.rmSync(existingDir, { recursive: true, force: true });
7295
7517
  }
7296
7518
  }
7297
- warn(`Installing ${skillDirs.length} bundled skill(s) to ${targetDir}...`);
7519
+ log(`Installing ${skillDirs.length} bundled skill(s) to ${targetDir}...`);
7298
7520
  for (const skillName of skillDirs) {
7299
- const skillDir = path7.resolve(targetDir, skillName);
7300
- if (!skillDir.startsWith(resolvedTarget + path7.sep)) {
7521
+ const skillDir = path8.resolve(targetDir, skillName);
7522
+ if (!skillDir.startsWith(resolvedTarget + path8.sep)) {
7301
7523
  failed.push(skillName);
7302
7524
  continue;
7303
7525
  }
7304
7526
  try {
7305
- const mdFiles = fs2.readdirSync(path7.join(bundledDir, skillName)).filter((f) => f.endsWith(".md"));
7306
- fs2.mkdirSync(skillDir, { recursive: true });
7527
+ const mdFiles = fs3.readdirSync(path8.join(bundledDir, skillName)).filter((f) => f.endsWith(".md"));
7528
+ fs3.mkdirSync(skillDir, { recursive: true });
7307
7529
  for (const mdFile of mdFiles) {
7308
- const content = fs2.readFileSync(path7.join(bundledDir, skillName, mdFile), "utf8");
7309
- fs2.writeFileSync(path7.join(skillDir, mdFile), content, "utf8");
7530
+ const content = fs3.readFileSync(path8.join(bundledDir, skillName, mdFile), "utf8");
7531
+ fs3.writeFileSync(path8.join(skillDir, mdFile), content, "utf8");
7310
7532
  }
7311
7533
  installed.push(skillName);
7312
7534
  } catch {
7313
7535
  failed.push(skillName);
7314
7536
  }
7315
7537
  }
7316
- warn(`Installed ${installed.length} skill(s) to ${targetDir}`);
7538
+ warn(`Installed ${installed.length} bundled skill(s) to ${targetDir}`);
7317
7539
  if (failed.length > 0) {
7318
7540
  warn(`Failed to install: ${failed.join(", ")}`);
7319
7541
  }
@@ -7321,8 +7543,28 @@ function installBundledSkillsTo(targetDir, skillDirs) {
7321
7543
  return { installed, failed };
7322
7544
  }
7323
7545
  function registerSkillsCommands(program2) {
7324
- const skills = program2.command("skills").description(`Manage agent skills (${AGENT_CHOICES})`);
7325
- skills.command("install").description("Install pncli skills into the current repo").option("--agent <agent>", `Target agent host: ${AGENT_CHOICES}`, DEFAULT_AGENT).option("--scope <scope>", "Installation scope: project | user", "project").option("--claude", "Shorthand for --agent claude-code").option("--all-agents", "Install to every supported agent host in one run").option("--target <dir>", "Override install directory (ignores --agent and --scope)").action((opts, cmd) => {
7546
+ const skills = program2.command("skills").description(`Install bundled pncli skills and org plugins from git marketplaces (${AGENT_CHOICES})`);
7547
+ skills.addHelpText("after", `
7548
+ Where skills go:
7549
+ --agent codex (default) \u2192 .agents/skills (project) or ~/.agents/skills (user); read by Codex and GitHub Copilot
7550
+ --agent github-copilot \u2192 .github/skills or ~/.copilot/skills
7551
+ --agent claude-code \u2192 .claude/skills or ~/.claude/skills (--claude is a shorthand)
7552
+ --all-agents \u2192 every host above in one run
7553
+
7554
+ Bundled skills (ship with pncli, refresh after upgrading):
7555
+ pncli skills install --all-agents # into this repo, every agent host
7556
+ pncli skills install --all-agents --scope user # for every repo on this machine
7557
+
7558
+ Org plugins (skills and AGENTS.md/CLAUDE.md from a git-hosted marketplace):
7559
+ pncli skills marketplace add <git-url> --all-agents # register, clone, install everything
7560
+ pncli skills marketplace sync --marketplace all --all-agents
7561
+ pncli skills marketplace manage # interactive: toggle plugins, add/remove marketplaces
7562
+ pncli skills marketplace --help # the full plugin workflow
7563
+
7564
+ Check what is installed:
7565
+ pncli skills status | pncli skills locations | pncli doctor
7566
+ `);
7567
+ skills.command("install").description("Install the bundled pncli skills (project scope by default; --scope user for every repo)").option("--agent <agent>", `Target agent host: ${AGENT_CHOICES}`, DEFAULT_AGENT).option("--scope <scope>", "Installation scope: project | user", "project").option("--claude", "Shorthand for --agent claude-code").option("--all-agents", "Install to every supported agent host in one run").option("--target <dir>", "Override install directory (ignores --agent and --scope)").action((opts, cmd) => {
7326
7568
  const start = Date.now();
7327
7569
  try {
7328
7570
  const agentExplicit = cmd.getOptionValueSource("agent") === "cli";
@@ -7332,10 +7574,9 @@ function registerSkillsCommands(program2) {
7332
7574
  const scope = opts.scope === "user" ? "user" : "project";
7333
7575
  const skillDirs = listBundledSkillDirs();
7334
7576
  if (opts.allAgents) {
7335
- const targets = Object.entries(AGENT_PATHS).map(([agent, agentPaths]) => {
7336
- const targetDir2 = resolveScopedPath(agentPaths, scope);
7337
- const { installed: installed2, failed: failed2 } = installBundledSkillsTo(targetDir2, skillDirs);
7338
- return { agent, target: targetDir2, installed: installed2, failed: failed2, total: installed2.length };
7577
+ const targets = resolveInstallTargets({ allAgents: true }, scope).map(({ agent, target }) => {
7578
+ const { installed: installed2, failed: failed2 } = installBundledSkillsTo(target, skillDirs);
7579
+ return { agent, target, installed: installed2, failed: failed2, total: installed2.length };
7339
7580
  });
7340
7581
  success({
7341
7582
  targets,
@@ -7346,7 +7587,7 @@ function registerSkillsCommands(program2) {
7346
7587
  return;
7347
7588
  }
7348
7589
  const agentName = resolveAgentName(opts);
7349
- const targetDir = opts.target ? path7.resolve(opts.target) : resolveScopedPath(resolveAgentPaths(agentName), scope);
7590
+ const targetDir = opts.target ? path8.resolve(opts.target) : resolveScopedPath(resolveAgentPaths(agentName), scope);
7350
7591
  const { installed, failed } = installBundledSkillsTo(targetDir, skillDirs);
7351
7592
  let tracked = false;
7352
7593
  if (opts.target && installed.length > 0) {
@@ -7375,12 +7616,12 @@ function registerSkillsCommands(program2) {
7375
7616
  try {
7376
7617
  let targetDir;
7377
7618
  if (opts.target) {
7378
- targetDir = path7.resolve(opts.target);
7619
+ targetDir = path8.resolve(opts.target);
7379
7620
  } else {
7380
7621
  const agentConfig = resolveAgentPaths(resolveAgentName(opts));
7381
7622
  targetDir = resolveScopedPath(agentConfig, opts.scope === "user" ? "user" : "project");
7382
7623
  }
7383
- if (!fs2.existsSync(targetDir)) {
7624
+ if (!fs3.existsSync(targetDir)) {
7384
7625
  success({
7385
7626
  skills: [],
7386
7627
  total: 0,
@@ -7391,13 +7632,13 @@ function registerSkillsCommands(program2) {
7391
7632
  return;
7392
7633
  }
7393
7634
  const meta = readInstalledMeta(targetDir);
7394
- const skillDirs = fs2.readdirSync(targetDir).filter((name) => {
7635
+ const skillDirs = fs3.readdirSync(targetDir).filter((name) => {
7395
7636
  if (name.startsWith(".")) return false;
7396
- const skillPath = path7.join(targetDir, name, "SKILL.md");
7397
- return fs2.existsSync(skillPath);
7637
+ const skillPath = path8.join(targetDir, name, "SKILL.md");
7638
+ return fs3.existsSync(skillPath);
7398
7639
  });
7399
7640
  const skillsList = skillDirs.map((name) => {
7400
- const content = fs2.readFileSync(path7.join(targetDir, name, "SKILL.md"), "utf8");
7641
+ const content = fs3.readFileSync(path8.join(targetDir, name, "SKILL.md"), "utf8");
7401
7642
  const frontmatter = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
7402
7643
  const data = {};
7403
7644
  const metadata = {};
@@ -7450,24 +7691,24 @@ function registerSkillsCommands(program2) {
7450
7691
  try {
7451
7692
  let targetDir;
7452
7693
  if (opts.target) {
7453
- targetDir = path7.resolve(opts.target);
7694
+ targetDir = path8.resolve(opts.target);
7454
7695
  } else {
7455
7696
  const agentConfig = resolveAgentPaths(resolveAgentName(opts));
7456
7697
  targetDir = resolveScopedPath(agentConfig, opts.scope === "project" ? "project" : "user");
7457
7698
  }
7458
- const resolvedTarget = path7.resolve(targetDir);
7459
- const skillDir = path7.resolve(targetDir, name);
7460
- if (!skillDir.startsWith(resolvedTarget + path7.sep)) {
7699
+ const resolvedTarget = path8.resolve(targetDir);
7700
+ const skillDir = path8.resolve(targetDir, name);
7701
+ if (!skillDir.startsWith(resolvedTarget + path8.sep)) {
7461
7702
  throw new Error(`Invalid skill name: "${name}"`);
7462
7703
  }
7463
- if (!fs2.existsSync(skillDir)) {
7704
+ if (!fs3.existsSync(skillDir)) {
7464
7705
  throw new Error(`Skill "${name}" not found at ${skillDir}`);
7465
7706
  }
7466
7707
  const meta = readInstalledMeta(targetDir);
7467
7708
  const record = meta.skills[name];
7468
- fs2.rmSync(skillDir, { recursive: true, force: true });
7709
+ fs3.rmSync(skillDir, { recursive: true, force: true });
7469
7710
  delete meta.skills[name];
7470
- fs2.writeFileSync(getInstalledMetaPath(targetDir), JSON.stringify(meta, null, 2), "utf8");
7711
+ fs3.writeFileSync(getInstalledMetaPath(targetDir), JSON.stringify(meta, null, 2), "utf8");
7471
7712
  success({
7472
7713
  uninstalled: name,
7473
7714
  target: targetDir,
@@ -7538,7 +7779,7 @@ function registerSkillsCommands(program2) {
7538
7779
  const start = Date.now();
7539
7780
  try {
7540
7781
  const configPath = getGlobalConfigPath();
7541
- const resolved = path7.resolve(dir);
7782
+ const resolved = path8.resolve(dir);
7542
7783
  const forgotten = forgetCustomTarget(configPath, resolved);
7543
7784
  if (!forgotten) {
7544
7785
  warn(`${resolved} is not a tracked custom target \u2014 nothing to forget.`);
@@ -7552,16 +7793,28 @@ function registerSkillsCommands(program2) {
7552
7793
  fail(err, "skills", "forget-target", start);
7553
7794
  }
7554
7795
  });
7555
- const marketplace = skills.command("marketplace").description("Manage git-hosted skills marketplaces");
7556
- function withMarketplaceAddOptions(cmd) {
7557
- return cmd.argument("<url>", "Git clone URL of the marketplace repository").argument("[localPath]", "Local directory to clone into (default: ~/.agents/marketplaces/<repo-name>)").option("--name <name>", "Human-readable name for this marketplace (default: derived from URL)").option("--branch <branch>", "Branch to clone (default: remote HEAD)").option("--token <token>", "HTTP access token for authenticated clone and pull (GitHub PAT or Bitbucket token)").option("--agent <agent>", `Target agent host for plugin install: ${AGENT_CHOICES} (default: ${DEFAULT_AGENT})`).option("--claude", "Shorthand for --agent claude-code");
7558
- }
7559
- withMarketplaceAddOptions(
7560
- marketplace.command("add").description("Register a new marketplace, clone it, and install all its plugins")
7561
- ).action((url, localPath, opts) => marketplaceAddAction(url, localPath, opts, "marketplace-add"));
7562
- withMarketplaceAddOptions(
7563
- marketplace.command("setup").description("Alias for `marketplace add` \u2014 clone a marketplace and install all its plugins")
7564
- ).action((url, localPath, opts) => marketplaceAddAction(url, localPath, opts, "marketplace-setup"));
7796
+ const marketplace = skills.command("marketplace").description("Org plugins from git-hosted marketplaces: add, sync, enable/disable, and shipped AGENTS.md/CLAUDE.md");
7797
+ marketplace.addHelpText("after", `
7798
+ Workflow:
7799
+ pncli skills marketplace add <git-url> --all-agents # register + clone + install every plugin
7800
+ pncli skills marketplace sync --marketplace all --all-agents # pull and refresh everything installed
7801
+ pncli skills marketplace plugins <name> # browse a marketplace without installing
7802
+ pncli skills marketplace manage # interactive hub (toggle, add, remove)
7803
+ pncli skills marketplace disable <plugin> / enable <plugin> # switch a plugin off without deleting it
7804
+
7805
+ Shipped instructions:
7806
+ A marketplace may ship instructions/AGENTS.md and/or instructions/CLAUDE.md. add and sync merge
7807
+ them into each agent's user-level file (~/.codex/AGENTS.md, ~/.copilot/copilot-instructions.md,
7808
+ ~/.claude/CLAUDE.md) as a marked block that never touches your own content.
7809
+ pncli skills marketplace instructions list | install | remove <name>
7810
+
7811
+ Plugin skills always install at user scope. --agent picks the host (default: ${DEFAULT_AGENT}); --all-agents covers all of them.
7812
+ `);
7813
+ marketplace.command("add").alias("setup").description("Register a new marketplace, clone it, install all its plugins, and apply its shipped AGENTS.md / CLAUDE.md (`setup` is an alias)").argument("<url>", "Git clone URL of the marketplace repository").argument("[localPath]", "Local directory to clone into (default: ~/.agents/marketplaces/<repo-name>)").option("--name <name>", "Human-readable name for this marketplace (default: derived from URL)").option("--branch <branch>", "Branch to clone (default: remote HEAD)").option("--token <token>", "HTTP access token for authenticated clone and pull (GitHub PAT or Bitbucket token)").option("--agent <agent>", `Target agent host for plugin install: ${AGENT_CHOICES} (default: ${DEFAULT_AGENT})`).option("--claude", "Shorthand for --agent claude-code").option("--all-agents", "Install to every supported agent host in one run").option("--no-instructions", "Do not apply the shipped AGENTS.md / CLAUDE.md to user-level instructions files").action((url, localPath, opts) => {
7814
+ const marketplaceIdx = process.argv.indexOf("marketplace");
7815
+ const invokedAs = marketplaceIdx !== -1 && process.argv[marketplaceIdx + 1] === "setup" ? "marketplace-setup" : "marketplace-add";
7816
+ return marketplaceAddAction(url, localPath, opts, invokedAs);
7817
+ });
7565
7818
  marketplace.command("list").description("List all registered marketplaces").action(() => {
7566
7819
  const start = Date.now();
7567
7820
  try {
@@ -7573,7 +7826,7 @@ function registerSkillsCommands(program2) {
7573
7826
  repoUrl: m.repoUrl,
7574
7827
  localPath: m.localPath,
7575
7828
  tokenConfigured: !!m.token,
7576
- upstreamRemote: m.localPath && fs2.existsSync(m.localPath) ? getRepoRemoteUrl(m.localPath) : null
7829
+ upstreamRemote: m.localPath && fs3.existsSync(m.localPath) ? getRepoRemoteUrl(m.localPath) : null
7577
7830
  })),
7578
7831
  total: all.length
7579
7832
  }, "skills", "marketplace-list", start);
@@ -7590,7 +7843,7 @@ function registerSkillsCommands(program2) {
7590
7843
  if (!found) {
7591
7844
  throw new Error(`Marketplace "${name}" not found. Run: pncli skills marketplace list`);
7592
7845
  }
7593
- if (!found.localPath || !fs2.existsSync(found.localPath)) {
7846
+ if (!found.localPath || !fs3.existsSync(found.localPath)) {
7594
7847
  throw new Error(`Marketplace "${marketplaceLabel(found)}" local path not found at ${found.localPath ?? "(not set)"}. Run: pncli skills marketplace add <url>`);
7595
7848
  }
7596
7849
  const plugins = resolvePluginChoices(found.localPath);
@@ -7611,7 +7864,7 @@ function registerSkillsCommands(program2) {
7611
7864
  fail(err, "skills", "marketplace-remove", start);
7612
7865
  }
7613
7866
  });
7614
- 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: ${AGENT_CHOICES} (default: ${DEFAULT_AGENT})`).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)').option("--installed-only", "Only sync plugins that are already installed \u2014 skip plugins newly added to the marketplace").action(async (plugin, opts) => {
7867
+ marketplace.command("sync").description("With no arguments, refreshes every already-installed plugin from every marketplace (same as --marketplace all --installed-only). Pass --force, a plugin, or --marketplace to get the interactive picker instead.").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: ${AGENT_CHOICES} (default: ${DEFAULT_AGENT})`).option("--claude", "Shorthand for --agent claude-code").option("--all-agents", "Install to every supported agent host in one run").option("--force", 'Reinstall even if a marketplace has no new changes (applies to single-plugin and "all" installs alike)').option("--installed-only", "Only sync plugins that are already installed \u2014 skip plugins newly added to the marketplace").option("--no-instructions", "Do not apply the shipped AGENTS.md / CLAUDE.md to user-level instructions files").action(async (plugin, opts) => {
7615
7868
  const start = Date.now();
7616
7869
  try {
7617
7870
  const configPath = getGlobalConfigPath();
@@ -7619,12 +7872,13 @@ function registerSkillsCommands(program2) {
7619
7872
  if (allMarketplaces.length === 0) {
7620
7873
  throw new Error("No marketplaces configured. Run: pncli skills marketplace add <url>");
7621
7874
  }
7622
- const targetDir = resolveAgentPaths(resolveAgentName(opts)).user;
7623
- const force = opts.force ?? false;
7624
- const installedOnly = opts.installedOnly ?? false;
7625
- if (opts.marketplace === "all") {
7626
- const results = allMarketplaces.map((m) => syncMarketplacePlugins(m, targetDir, force, plugin ?? "all", installedOnly));
7627
- success({ allMarketplaces: true, marketplaces: results, target: targetDir }, "skills", "marketplace-sync", start);
7875
+ const bareSync = isBareMarketplaceSync(plugin, opts);
7876
+ const targets = resolveInstallTargets(opts);
7877
+ const syncOpts = { force: opts.force ?? false, installedOnly: bareSync ? true : opts.installedOnly ?? false, instructions: opts.instructions !== false };
7878
+ const targetSummary = targets.length === 1 ? { target: targets[0].target } : { targets: targets.map((t) => t.target) };
7879
+ if (opts.marketplace === "all" || bareSync) {
7880
+ const results = allMarketplaces.map((m) => syncMarketplacePlugins(m, targets, plugin ?? "all", syncOpts));
7881
+ success({ allMarketplaces: true, marketplaces: results, ...targetSummary }, "skills", "marketplace-sync", start);
7628
7882
  return;
7629
7883
  }
7630
7884
  let selectedMarketplace;
@@ -7647,12 +7901,12 @@ function registerSkillsCommands(program2) {
7647
7901
  choices: [
7648
7902
  { value: ALL_MARKETPLACES, name: "All marketplaces \u2014 sync every plugin from every marketplace" },
7649
7903
  // Index-based values: labels alone aren't guaranteed unique (two marketplaces can share a derived name).
7650
- ...allMarketplaces.map((m, i) => ({ value: String(i), name: `${marketplaceLabel(m)} \u2014 ${m.repoUrl ?? ""}` }))
7904
+ ...allMarketplaces.map((m2, i) => ({ value: String(i), name: `${marketplaceLabel(m2)} \u2014 ${m2.repoUrl ?? ""}` }))
7651
7905
  ]
7652
7906
  });
7653
7907
  if (chosen === ALL_MARKETPLACES) {
7654
- const results2 = allMarketplaces.map((m) => syncMarketplacePlugins(m, targetDir, force, selectedPlugin ?? "all", installedOnly));
7655
- success({ allMarketplaces: true, marketplaces: results2, target: targetDir }, "skills", "marketplace-sync", start);
7908
+ const results = allMarketplaces.map((m2) => syncMarketplacePlugins(m2, targets, selectedPlugin ?? "all", syncOpts));
7909
+ success({ allMarketplaces: true, marketplaces: results, ...targetSummary }, "skills", "marketplace-sync", start);
7656
7910
  return;
7657
7911
  }
7658
7912
  selectedMarketplace = allMarketplaces[Number(chosen)];
@@ -7662,7 +7916,7 @@ function registerSkillsCommands(program2) {
7662
7916
  }
7663
7917
  const marketplaceName = marketplaceLabel(selectedMarketplace);
7664
7918
  const marketplacePath = selectedMarketplace.localPath;
7665
- if (!marketplacePath || !fs2.existsSync(marketplacePath)) {
7919
+ if (!marketplacePath || !fs3.existsSync(marketplacePath)) {
7666
7920
  throw new Error(`Marketplace "${marketplaceName}" local path not found at ${marketplacePath ?? "(not set)"}. Run: pncli skills marketplace add <url>`);
7667
7921
  }
7668
7922
  const { updated } = pullMarketplace(marketplacePath, selectedMarketplace.repoUrl, selectedMarketplace.token, marketplaceName);
@@ -7688,55 +7942,94 @@ function registerSkillsCommands(program2) {
7688
7942
  } else if (selectedPlugin !== "all" && !pluginChoices.some((p) => p.name === selectedPlugin)) {
7689
7943
  throw new Error(`Plugin "${selectedPlugin}" not found in "${marketplaceName}". Available: ${pluginChoices.map((p) => p.name).join(", ")}`);
7690
7944
  }
7691
- if (!updated && !force) {
7692
- success({
7693
- marketplace: marketplaceName,
7694
- marketplaceUpdated: false,
7695
- updated: false,
7696
- skipped: true,
7697
- message: `No changes detected in "${marketplaceName}" \u2014 skipping install. Use --force to reinstall anyway.`
7698
- }, "skills", "marketplace-sync", start);
7699
- return;
7945
+ const m = selectedMarketplace;
7946
+ const targetResults = targets.map((t) => installMarketplaceToTarget(m, marketplacePath, pluginChoices, selectedPlugin, t, { updated, force: syncOpts.force, installedOnly: syncOpts.installedOnly }));
7947
+ const instructions2 = applyInstructionsForTargets(m, marketplacePath, targets, syncOpts.instructions);
7948
+ success(
7949
+ shapeSyncResult(marketplaceName, updated, selectedPlugin, targetResults, { installedOnly: syncOpts.installedOnly, instructions: instructions2 }),
7950
+ "skills",
7951
+ "marketplace-sync",
7952
+ start
7953
+ );
7954
+ return;
7955
+ }
7956
+ } catch (err) {
7957
+ fail(err, "skills", "marketplace-sync", start);
7958
+ }
7959
+ });
7960
+ const instructions = marketplace.command("instructions").description("Manage the AGENTS.md / CLAUDE.md a marketplace ships (merged as a marked block into each agent's user-level instructions file)");
7961
+ function resolveInstructionAgents(opts) {
7962
+ return resolveInstallTargets(opts).map((t) => t.agent);
7963
+ }
7964
+ function findMarketplaceOrThrow(all, name) {
7965
+ const found = all.find((m) => m.name === name || m.repoUrl === name);
7966
+ if (!found) throw new Error(`Marketplace "${name}" not found. Run: pncli skills marketplace list`);
7967
+ return found;
7968
+ }
7969
+ instructions.command("list").description("Show which marketplaces ship instructions and whether each agent's user-level file has them installed and current").option("--marketplace <name>", "Only report this marketplace (name or clone URL)").action((opts) => {
7970
+ const start = Date.now();
7971
+ try {
7972
+ const all = loadMarketplaces(getGlobalConfigPath());
7973
+ const selected = opts.marketplace ? [findMarketplaceOrThrow(all, opts.marketplace)] : all;
7974
+ const agents = Object.keys(AGENT_PATHS);
7975
+ const marketplaces = selected.map((m) => {
7976
+ const shipped = m.localPath && fs3.existsSync(m.localPath) ? findMarketplaceInstructions(m.localPath).map((s) => s.file) : [];
7977
+ return {
7978
+ marketplace: marketplaceLabel(m),
7979
+ localPath: m.localPath ?? null,
7980
+ ships: shipped,
7981
+ agents: marketplaceInstructionsStatus(m.localPath, marketplaceLabel(m), agents)
7982
+ };
7983
+ });
7984
+ success({
7985
+ files: Object.fromEntries(agents.map((a) => [a, agentInstructionsFile(a)])),
7986
+ marketplaces,
7987
+ hint: marketplaces.some((m) => m.ships.length > 0) ? "Apply with: pncli skills marketplace instructions install --all-agents" : "No registered marketplace ships an instructions/AGENTS.md or instructions/CLAUDE.md."
7988
+ }, "skills", "marketplace-instructions-list", start);
7989
+ } catch (err) {
7990
+ fail(err, "skills", "marketplace-instructions-list", start);
7991
+ }
7992
+ });
7993
+ instructions.command("install").description("Apply (or refresh) the shipped instructions of one or every marketplace into the agent's user-level file").option("--marketplace <name>", "Marketplace to apply (name or clone URL); default: every registered marketplace that ships instructions").option("--agent <agent>", `Target agent host: ${AGENT_CHOICES} (default: ${DEFAULT_AGENT})`).option("--claude", "Shorthand for --agent claude-code").option("--all-agents", "Apply to every supported agent host in one run").action((opts) => {
7994
+ const start = Date.now();
7995
+ try {
7996
+ const all = loadMarketplaces(getGlobalConfigPath());
7997
+ if (all.length === 0) throw new Error("No marketplaces configured. Run: pncli skills marketplace add <url>");
7998
+ const agents = resolveInstructionAgents(opts);
7999
+ const selected = opts.marketplace ? [findMarketplaceOrThrow(all, opts.marketplace)] : all;
8000
+ const results = selected.map((m) => {
8001
+ const name = marketplaceLabel(m);
8002
+ if (!m.localPath || !fs3.existsSync(m.localPath)) {
8003
+ return { marketplace: name, skipped: true, message: "Local path not found. Run: pncli skills marketplace add <url>" };
7700
8004
  }
7701
- let pluginNames;
7702
- if (selectedPlugin === "all") {
7703
- if (installedOnly) {
7704
- const installed = getInstalledPluginsForMarketplace(targetDir, marketplaceName, selectedMarketplace.repoUrl).filter((name) => pluginChoices.some((p) => p.name === name));
7705
- if (installed.length === 0) {
7706
- success({
7707
- marketplace: marketplaceName,
7708
- skipped: true,
7709
- installedOnly: true,
7710
- message: `No installed plugins found for "${marketplaceName}" \u2014 run marketplace sync without --installed-only to install plugins.`
7711
- }, "skills", "marketplace-sync", start);
7712
- return;
7713
- }
7714
- pluginNames = installed;
7715
- } else {
7716
- pluginNames = pluginChoices.map((p) => p.name);
7717
- }
7718
- } else {
7719
- pluginNames = [selectedPlugin];
8005
+ if (findMarketplaceInstructions(m.localPath).length === 0) {
8006
+ return { marketplace: name, skipped: true, message: `Ships no instructions/AGENTS.md or instructions/CLAUDE.md.` };
7720
8007
  }
7721
- const { results, totalInstalled } = installPluginsForMarketplace(marketplacePath, marketplaceName, selectedMarketplace.repoUrl, pluginNames, targetDir);
7722
- if (selectedPlugin === "all") {
7723
- success({ marketplace: marketplaceName, plugins: results, total: totalInstalled, target: targetDir, marketplaceUpdated: updated, ...installedOnly ? { installedOnly: true } : {} }, "skills", "marketplace-sync", start);
7724
- } else {
7725
- const single = results[selectedPlugin] ?? { installed: [], failed: [] };
7726
- success({
7727
- marketplace: marketplaceName,
7728
- plugin: selectedPlugin,
7729
- installed: single.installed,
7730
- failed: single.failed,
7731
- total: single.installed.length,
7732
- target: targetDir,
7733
- marketplaceUpdated: updated
7734
- }, "skills", "marketplace-sync", start);
8008
+ const applied = applyMarketplaceInstructions(m.localPath, name, agents);
8009
+ for (const r of applied) {
8010
+ if (r.action === "added" || r.action === "updated") warn(`Instructions ${r.action} in ${r.file} (from ${r.source})`);
7735
8011
  }
7736
- return;
8012
+ return { marketplace: name, agents: applied };
8013
+ });
8014
+ if (opts.marketplace && "skipped" in results[0]) throw new Error(`Marketplace "${results[0].marketplace}": ${results[0].message}`);
8015
+ success({ marketplaces: results, agents }, "skills", "marketplace-instructions-install", start);
8016
+ } catch (err) {
8017
+ fail(err, "skills", "marketplace-instructions-install", start);
8018
+ }
8019
+ });
8020
+ instructions.command("remove").description("Strip a marketplace's instructions block from the agent's user-level file (everything else in the file is kept)").argument("<marketplace>", "Marketplace name (or clone URL). Works even after the marketplace has been removed from config.").option("--agent <agent>", `Target agent host: ${AGENT_CHOICES} (default: ${DEFAULT_AGENT})`).option("--claude", "Shorthand for --agent claude-code").option("--all-agents", "Remove from every supported agent host in one run").action((marketplaceName, opts) => {
8021
+ const start = Date.now();
8022
+ try {
8023
+ const agents = resolveInstructionAgents(opts);
8024
+ const registered = loadMarketplaces(getGlobalConfigPath()).find((m) => m.name === marketplaceName || m.repoUrl === marketplaceName);
8025
+ const name = registered ? marketplaceLabel(registered) : marketplaceName;
8026
+ const results = removeMarketplaceInstructions(name, agents);
8027
+ for (const r of results) {
8028
+ if (r.removed) warn(`Instructions block for "${name}" removed from ${r.file}`);
7737
8029
  }
8030
+ success({ marketplace: name, agents: results, removed: results.filter((r) => r.removed).length }, "skills", "marketplace-instructions-remove", start);
7738
8031
  } catch (err) {
7739
- fail(err, "skills", "marketplace-sync", start);
8032
+ fail(err, "skills", "marketplace-instructions-remove", start);
7740
8033
  }
7741
8034
  });
7742
8035
  marketplace.command("purge-plugin").description("Remove all skills installed from a specific plugin (or all plugins in a marketplace)").argument("<plugin>", 'Plugin name to purge, or "all" to remove every skill from the marketplace').option("--marketplace <name>", "Restrict purge to skills from this marketplace (by name or repo URL)").option("--agent <agent>", `Target agent host: ${AGENT_CHOICES} (default: ${DEFAULT_AGENT})`).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) => {
@@ -7744,31 +8037,31 @@ function registerSkillsCommands(program2) {
7744
8037
  try {
7745
8038
  let targetDir;
7746
8039
  if (opts.target) {
7747
- targetDir = path7.resolve(opts.target);
8040
+ targetDir = path8.resolve(opts.target);
7748
8041
  } else {
7749
8042
  const agentConfig = resolveAgentPaths(resolveAgentName(opts));
7750
8043
  targetDir = resolveScopedPath(agentConfig, opts.scope ?? "user");
7751
8044
  }
7752
- const resolvedTarget = path7.resolve(targetDir);
7753
- if (!fs2.existsSync(targetDir)) {
8045
+ const resolvedTarget = path8.resolve(targetDir);
8046
+ if (!fs3.existsSync(targetDir)) {
7754
8047
  success({ removed: [], total: 0, target: targetDir, message: "No skills directory found." }, "skills", "marketplace-purge-plugin", start);
7755
8048
  return;
7756
8049
  }
7757
8050
  const meta = readInstalledMeta(targetDir);
7758
8051
  const removed = [];
7759
8052
  const skipped = [];
7760
- const skillDirs = fs2.readdirSync(targetDir).filter((name) => {
8053
+ const skillDirs = fs3.readdirSync(targetDir).filter((name) => {
7761
8054
  if (name.startsWith(".")) return false;
7762
- const p = path7.join(targetDir, name);
8055
+ const p = path8.join(targetDir, name);
7763
8056
  try {
7764
- return fs2.statSync(p).isDirectory();
8057
+ return fs3.statSync(p).isDirectory();
7765
8058
  } catch {
7766
8059
  return false;
7767
8060
  }
7768
8061
  });
7769
8062
  for (const skillName of skillDirs) {
7770
- const skillDir = path7.resolve(targetDir, skillName);
7771
- if (!skillDir.startsWith(resolvedTarget + path7.sep)) continue;
8063
+ const skillDir = path8.resolve(targetDir, skillName);
8064
+ if (!skillDir.startsWith(resolvedTarget + path8.sep)) continue;
7772
8065
  let record = meta.skills[skillName] ?? null;
7773
8066
  if (!record) {
7774
8067
  const perSkill = readSkillOrigin(skillDir);
@@ -7793,12 +8086,12 @@ function registerSkillsCommands(program2) {
7793
8086
  skipped.push(skillName);
7794
8087
  continue;
7795
8088
  }
7796
- fs2.rmSync(skillDir, { recursive: true, force: true });
8089
+ fs3.rmSync(skillDir, { recursive: true, force: true });
7797
8090
  delete meta.skills[skillName];
7798
8091
  removed.push(skillName);
7799
8092
  }
7800
8093
  if (removed.length > 0) {
7801
- fs2.writeFileSync(getInstalledMetaPath(targetDir), JSON.stringify(meta, null, 2), "utf8");
8094
+ fs3.writeFileSync(getInstalledMetaPath(targetDir), JSON.stringify(meta, null, 2), "utf8");
7802
8095
  }
7803
8096
  success({
7804
8097
  removed,
@@ -7816,7 +8109,7 @@ function registerSkillsCommands(program2) {
7816
8109
  const start = Date.now();
7817
8110
  try {
7818
8111
  const targetDir = resolveTargetDir(opts);
7819
- if (!fs2.existsSync(targetDir)) {
8112
+ if (!fs3.existsSync(targetDir)) {
7820
8113
  success({ disabled: [], total: 0, target: targetDir, message: "No skills directory found." }, "skills", "marketplace-disable", start);
7821
8114
  return;
7822
8115
  }
@@ -7828,7 +8121,7 @@ function registerSkillsCommands(program2) {
7828
8121
  total: result.disabled.length,
7829
8122
  target: targetDir,
7830
8123
  plugin,
7831
- stash: path7.join(targetDir, DISABLED_SUBDIR),
8124
+ stash: path8.join(targetDir, DISABLED_SUBDIR),
7832
8125
  ...opts.marketplace ? { marketplace: opts.marketplace } : {}
7833
8126
  }, "skills", "marketplace-disable", start);
7834
8127
  } catch (err) {
@@ -7839,7 +8132,7 @@ function registerSkillsCommands(program2) {
7839
8132
  const start = Date.now();
7840
8133
  try {
7841
8134
  const targetDir = resolveTargetDir(opts);
7842
- if (!fs2.existsSync(targetDir)) {
8135
+ if (!fs3.existsSync(targetDir)) {
7843
8136
  success({ enabled: [], total: 0, target: targetDir, message: "No skills directory found." }, "skills", "marketplace-enable", start);
7844
8137
  return;
7845
8138
  }
@@ -7864,29 +8157,48 @@ function registerSkillsCommands(program2) {
7864
8157
  fail(err, "skills", "marketplace-enable", start);
7865
8158
  }
7866
8159
  });
7867
- marketplace.command("manage").description("Manage marketplaces and plugins: toggle plugins on/off, add or remove marketplaces (interactive)").option("--agent <agent>", `Target agent host: ${AGENT_CHOICES} (default: ${DEFAULT_AGENT})`).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) => {
8160
+ marketplace.command("manage").description("Manage marketplaces and plugins: toggle plugins on/off, sync every marketplace, apply shipped AGENTS.md / CLAUDE.md, add or remove marketplaces (interactive)").option("--agent <agent>", `Target agent host: ${AGENT_CHOICES} (default: ${DEFAULT_AGENT})`).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) => {
7868
8161
  const start = Date.now();
7869
8162
  try {
7870
- assertInteractive("Use `pncli skills marketplace enable|disable <plugin>`, `add <url>`, and `remove <name>` to manage non-interactively.");
8163
+ assertInteractive("Use `pncli skills marketplace enable|disable <plugin>`, `sync --marketplace all`, `instructions install`, `add <url>`, and `remove <name>` to manage non-interactively.");
7871
8164
  const targetDir = resolveTargetDir(opts);
7872
8165
  const enabledPlugins = [];
7873
8166
  const disabledPlugins = [];
7874
8167
  const stashMissing = [];
7875
8168
  const addedMarketplaces = [];
7876
8169
  const removedMarketplaces = [];
8170
+ const syncedMarketplaces = /* @__PURE__ */ new Map();
8171
+ const appliedInstructions = /* @__PURE__ */ new Map();
8172
+ const instructionAgents = opts.target ? [] : [resolveAgentName(opts)];
7877
8173
  for (; ; ) {
7878
- const states = fs2.existsSync(targetDir) ? listPluginStates(targetDir) : [];
8174
+ const states = fs3.existsSync(targetDir) ? listPluginStates(targetDir) : [];
7879
8175
  const registered = loadMarketplaces(getGlobalConfigPath());
8176
+ const shipping = registered.filter((m) => m.localPath && fs3.existsSync(m.localPath) && findMarketplaceInstructions(m.localPath).length > 0);
7880
8177
  const action = await select({
7881
8178
  message: `Manage skills marketplaces (target: ${targetDir}):`,
7882
8179
  choices: [
7883
8180
  ...states.length > 0 ? [{ value: "toggle", name: `Toggle plugins on/off (${states.length} installed)` }] : [],
8181
+ ...registered.length > 0 ? [{ value: "sync", name: `Sync every marketplace (${registered.length} registered)` }] : [],
8182
+ ...shipping.length > 0 && instructionAgents.length > 0 ? [{ value: "instructions", name: `Apply shipped AGENTS.md / CLAUDE.md (${shipping.length} marketplace(s) ship them)` }] : [],
7884
8183
  { value: "add", name: "Add a marketplace" },
7885
8184
  ...registered.length > 0 ? [{ value: "remove", name: `Remove a marketplace (${registered.length} registered)` }] : [],
7886
8185
  { value: "done", name: "Done" }
7887
8186
  ]
7888
8187
  });
7889
8188
  if (action === "done") break;
8189
+ if (action === "sync") {
8190
+ const syncTargets = [{ agent: opts.target ? "custom" : resolveAgentName(opts), target: targetDir }];
8191
+ for (const m of registered) {
8192
+ syncedMarketplaces.set(marketplaceLabel(m), syncMarketplacePlugins(m, syncTargets, "all", { force: false, installedOnly: false, instructions: instructionAgents.length > 0 }));
8193
+ }
8194
+ continue;
8195
+ }
8196
+ if (action === "instructions") {
8197
+ for (const m of shipping) {
8198
+ appliedInstructions.set(marketplaceLabel(m), { marketplace: marketplaceLabel(m), agents: applyMarketplaceInstructions(m.localPath, marketplaceLabel(m), instructionAgents) });
8199
+ }
8200
+ continue;
8201
+ }
7890
8202
  if (action === "toggle") {
7891
8203
  const sorted = [...states].sort((a, b) => (a.marketplace ?? "").localeCompare(b.marketplace ?? "") || a.plugin.localeCompare(b.plugin));
7892
8204
  const choices = [];
@@ -7936,7 +8248,9 @@ function registerSkillsCommands(program2) {
7936
8248
  addedMarketplaces.push(performMarketplaceAdd(url, void 0, {
7937
8249
  name: name || void 0,
7938
8250
  agent: opts.agent,
7939
- claude: opts.claude
8251
+ claude: opts.claude,
8252
+ // A custom --target has no agent host to map instructions onto.
8253
+ instructions: instructionAgents.length > 0
7940
8254
  }));
7941
8255
  } else if (action === "remove") {
7942
8256
  const chosen = await select({
@@ -7957,6 +8271,8 @@ function registerSkillsCommands(program2) {
7957
8271
  disabled: disabledPlugins,
7958
8272
  addedMarketplaces,
7959
8273
  removedMarketplaces,
8274
+ syncedMarketplaces: [...syncedMarketplaces.values()],
8275
+ appliedInstructions: [...appliedInstructions.values()],
7960
8276
  target: targetDir,
7961
8277
  ...stashMissing.length > 0 ? {
7962
8278
  stashMissing,
@@ -7971,15 +8287,15 @@ function registerSkillsCommands(program2) {
7971
8287
  const start = Date.now();
7972
8288
  try {
7973
8289
  const userDir = resolveAgentPaths(resolveAgentName(opts)).user;
7974
- if (!fs2.existsSync(userDir)) {
8290
+ if (!fs3.existsSync(userDir)) {
7975
8291
  success({ removed: 0, target: userDir, message: "No user-level skills directory found \u2014 nothing to purge." }, "skills", "purge-user", start);
7976
8292
  return;
7977
8293
  }
7978
- const skillDirs = fs2.readdirSync(userDir).filter((name) => {
8294
+ const skillDirs = fs3.readdirSync(userDir).filter((name) => {
7979
8295
  if (name.startsWith(".")) return false;
7980
- const p = path7.join(userDir, name);
8296
+ const p = path8.join(userDir, name);
7981
8297
  try {
7982
- return fs2.statSync(p).isDirectory();
8298
+ return fs3.statSync(p).isDirectory();
7983
8299
  } catch {
7984
8300
  return false;
7985
8301
  }
@@ -7995,13 +8311,13 @@ Re-run with --force to confirm, or use \`pncli skills marketplace purge-plugin\`
7995
8311
  );
7996
8312
  }
7997
8313
  for (const name of skillDirs) {
7998
- const skillDir = path7.resolve(userDir, name);
7999
- if (!skillDir.startsWith(path7.resolve(userDir) + path7.sep)) continue;
8000
- fs2.rmSync(skillDir, { recursive: true, force: true });
8314
+ const skillDir = path8.resolve(userDir, name);
8315
+ if (!skillDir.startsWith(path8.resolve(userDir) + path8.sep)) continue;
8316
+ fs3.rmSync(skillDir, { recursive: true, force: true });
8001
8317
  }
8002
8318
  const metaPath = getInstalledMetaPath(userDir);
8003
- if (fs2.existsSync(metaPath)) {
8004
- fs2.writeFileSync(metaPath, JSON.stringify({ version: 1, skills: {} }, null, 2), "utf8");
8319
+ if (fs3.existsSync(metaPath)) {
8320
+ fs3.writeFileSync(metaPath, JSON.stringify({ version: 1, skills: {} }, null, 2), "utf8");
8005
8321
  }
8006
8322
  success({ removed: skillDirs.length, skills: skillDirs, target: userDir }, "skills", "purge-user", start);
8007
8323
  } catch (err) {
@@ -8010,46 +8326,46 @@ Re-run with --force to confirm, or use \`pncli skills marketplace purge-plugin\`
8010
8326
  });
8011
8327
  }
8012
8328
  function resolvePluginChoices(marketplacePath) {
8013
- const marketplaceJsonPath = path7.join(marketplacePath, ".claude-plugin", "marketplace.json");
8014
- if (fs2.existsSync(marketplaceJsonPath)) {
8329
+ const marketplaceJsonPath = path8.join(marketplacePath, ".claude-plugin", "marketplace.json");
8330
+ if (fs3.existsSync(marketplaceJsonPath)) {
8015
8331
  try {
8016
- const meta = JSON.parse(fs2.readFileSync(marketplaceJsonPath, "utf8"));
8332
+ const meta = JSON.parse(fs3.readFileSync(marketplaceJsonPath, "utf8"));
8017
8333
  if (Array.isArray(meta.plugins) && meta.plugins.length > 0) {
8018
8334
  return meta.plugins.map((p) => ({ name: p.name, description: p.description ?? "" }));
8019
8335
  }
8020
8336
  } catch {
8021
8337
  }
8022
8338
  }
8023
- const pluginsDir = path7.join(marketplacePath, "plugins");
8024
- if (fs2.existsSync(pluginsDir)) {
8025
- return fs2.readdirSync(pluginsDir).filter((name) => fs2.statSync(path7.join(pluginsDir, name)).isDirectory()).map((name) => ({ name, description: "" }));
8339
+ const pluginsDir = path8.join(marketplacePath, "plugins");
8340
+ if (fs3.existsSync(pluginsDir)) {
8341
+ return fs3.readdirSync(pluginsDir).filter((name) => fs3.statSync(path8.join(pluginsDir, name)).isDirectory()).map((name) => ({ name, description: "" }));
8026
8342
  }
8027
8343
  return [];
8028
8344
  }
8029
8345
  function resolveSkillsSrc(marketplacePath, selectedPlugin) {
8030
- const pluginsBase = path7.resolve(marketplacePath, "plugins");
8031
- const skillsSrc = path7.resolve(pluginsBase, selectedPlugin, "skills");
8032
- if (!skillsSrc.startsWith(pluginsBase + path7.sep)) {
8346
+ const pluginsBase = path8.resolve(marketplacePath, "plugins");
8347
+ const skillsSrc = path8.resolve(pluginsBase, selectedPlugin, "skills");
8348
+ if (!skillsSrc.startsWith(pluginsBase + path8.sep)) {
8033
8349
  throw new Error(`Invalid plugin name: "${selectedPlugin}"`);
8034
8350
  }
8035
8351
  return skillsSrc;
8036
8352
  }
8037
8353
  function copyPluginSkills(skillsSrc, targetDir, meta) {
8038
- fs2.mkdirSync(targetDir, { recursive: true });
8039
- const resolvedTarget = path7.resolve(targetDir);
8040
- const skillNames = fs2.readdirSync(skillsSrc).filter(
8041
- (name) => fs2.statSync(path7.join(skillsSrc, name)).isDirectory()
8354
+ fs3.mkdirSync(targetDir, { recursive: true });
8355
+ const resolvedTarget = path8.resolve(targetDir);
8356
+ const skillNames = fs3.readdirSync(skillsSrc).filter(
8357
+ (name) => fs3.statSync(path8.join(skillsSrc, name)).isDirectory()
8042
8358
  );
8043
8359
  const installed = [];
8044
8360
  const failed = [];
8045
8361
  for (const skillName of skillNames) {
8046
- const dest = path7.resolve(targetDir, skillName);
8047
- if (!dest.startsWith(resolvedTarget + path7.sep)) {
8362
+ const dest = path8.resolve(targetDir, skillName);
8363
+ if (!dest.startsWith(resolvedTarget + path8.sep)) {
8048
8364
  failed.push(skillName);
8049
8365
  continue;
8050
8366
  }
8051
- fs2.rmSync(dest, { recursive: true, force: true });
8052
- fs2.cpSync(path7.join(skillsSrc, skillName), dest, { recursive: true });
8367
+ fs3.rmSync(dest, { recursive: true, force: true });
8368
+ fs3.cpSync(path8.join(skillsSrc, skillName), dest, { recursive: true });
8053
8369
  installed.push(skillName);
8054
8370
  }
8055
8371
  if (meta) {
@@ -8066,7 +8382,7 @@ function copyPluginSkills(skillsSrc, targetDir, meta) {
8066
8382
 
8067
8383
  // src/services/config/commands.ts
8068
8384
  import chalk from "chalk";
8069
- import fs3 from "fs";
8385
+ import fs4 from "fs";
8070
8386
  function registerConfigCommands(program2) {
8071
8387
  const config = program2.command("config").description("Manage pncli configuration");
8072
8388
  config.command("init").description("Setup wizard for service credentials (interactive)").option("--repo", "Write repo config (.pncli.json) instead of global config").action(async (opts) => {
@@ -8180,8 +8496,8 @@ function registerConfigCommands(program2) {
8180
8496
  if (cfg.ado.baseUrl) {
8181
8497
  try {
8182
8498
  const collection = cfg.defaults.ado?.collection;
8183
- const path10 = collection ? `/${encodeURIComponent(collection)}/_apis/connectionData?api-version=7.1-preview.1` : "/_apis/projectCollections?api-version=7.1";
8184
- await http.ado(path10);
8499
+ const path11 = collection ? `/${encodeURIComponent(collection)}/_apis/connectionData?api-version=7.1-preview.1` : "/_apis/projectCollections?api-version=7.1";
8500
+ await http.ado(path11);
8185
8501
  results.ado = { ok: true, message: "connected" };
8186
8502
  } catch (err) {
8187
8503
  results.ado = { ok: false, message: err instanceof Error ? err.message : String(err) };
@@ -9059,7 +9375,7 @@ async function initGlobalConfig(start) {
9059
9375
  });
9060
9376
  alationUserId = await input2({
9061
9377
  message: "Alation user ID (numeric):",
9062
- validate: (v) => /^\d+$/.test(v.trim()) || "Must be a positive integer"
9378
+ validate: (v) => /^[1-9]\d*$/.test(v.trim()) || "Must be a positive integer"
9063
9379
  });
9064
9380
  if (alationBaseUrl && alationRefreshToken && alationUserId) {
9065
9381
  process.stderr.write("\n Verifying connection...\n");
@@ -9312,7 +9628,7 @@ async function initRepoConfig(start) {
9312
9628
  process.exitCode = ExitCode.SUCCESS;
9313
9629
  return;
9314
9630
  }
9315
- if (fs3.existsSync(".pncli.json")) {
9631
+ if (fs4.existsSync(".pncli.json")) {
9316
9632
  const overwrite = await confirm({
9317
9633
  message: ".pncli.json already exists. Overwrite?",
9318
9634
  default: false
@@ -9346,14 +9662,14 @@ async function initRepoConfig(start) {
9346
9662
  }
9347
9663
 
9348
9664
  // src/services/doctor/commands.ts
9349
- import fs4 from "fs";
9350
- import path8 from "path";
9665
+ import fs5 from "fs";
9666
+ import path9 from "path";
9351
9667
  function checkConfigFile(filePath) {
9352
- if (!fs4.existsSync(filePath)) {
9668
+ if (!fs5.existsSync(filePath)) {
9353
9669
  return { path: filePath, exists: false, valid: false, message: "not present" };
9354
9670
  }
9355
9671
  try {
9356
- JSON.parse(fs4.readFileSync(filePath, "utf8"));
9672
+ JSON.parse(fs5.readFileSync(filePath, "utf8"));
9357
9673
  return { path: filePath, exists: true, valid: true, message: "ok" };
9358
9674
  } catch (err) {
9359
9675
  return {
@@ -9364,7 +9680,7 @@ function checkConfigFile(filePath) {
9364
9680
  };
9365
9681
  }
9366
9682
  }
9367
- function buildProblems(globalFile, repoFile, credentials, skillLocations) {
9683
+ function buildProblems(globalFile, repoFile, credentials, skillLocations, marketplaces = []) {
9368
9684
  const problems = [];
9369
9685
  for (const file of [globalFile, repoFile]) {
9370
9686
  if (file.exists && !file.valid) {
@@ -9415,16 +9731,32 @@ function buildProblems(globalFile, repoFile, credentials, skillLocations) {
9415
9731
  fix: "Refresh them with: pncli skills install"
9416
9732
  });
9417
9733
  }
9734
+ for (const m of marketplaces.filter((m2) => !m2.cloneExists)) {
9735
+ problems.push({
9736
+ area: "marketplaces",
9737
+ message: `Marketplace "${m.name}" is registered but its clone is missing (${m.localPath ?? "no local path"})`,
9738
+ fix: `Re-clone it with: pncli skills marketplace add ${m.repoUrl ?? "<url>"}`
9739
+ });
9740
+ }
9741
+ const marketplaceSkillTotal = skillLocations.reduce((sum, l) => sum + (l.marketplaceSkills ?? 0), 0);
9742
+ const liveMarketplaces = marketplaces.filter((m) => m.cloneExists).length;
9743
+ if (liveMarketplaces > 0 && marketplaceSkillTotal === 0) {
9744
+ problems.push({
9745
+ area: "marketplaces",
9746
+ message: `${liveMarketplaces} marketplace(s) registered but no plugin skills are installed from any of them`,
9747
+ fix: "Run: pncli skills marketplace sync --marketplace all --all-agents"
9748
+ });
9749
+ }
9418
9750
  return problems;
9419
9751
  }
9420
9752
  function registerDoctorCommands(program2) {
9421
- program2.command("doctor").description("Diagnose pncli setup: config files, credentials, and agent skills").option("--offline", "Skip credential checks (no network calls)").action(async (cmdOpts) => {
9753
+ program2.command("doctor").description("Diagnose pncli setup: config files, credentials, agent skills, and skills marketplaces").option("--offline", "Skip credential checks (no network calls)").action(async (cmdOpts) => {
9422
9754
  const start = Date.now();
9423
9755
  try {
9424
9756
  const opts = program2.optsWithGlobals();
9425
9757
  const globalFile = checkConfigFile(opts.config ?? getGlobalConfigPath());
9426
9758
  const repoRoot = findGitRoot() ?? process.cwd();
9427
- const repoFile = checkConfigFile(path8.join(repoRoot, ".pncli.json"));
9759
+ const repoFile = checkConfigFile(path9.join(repoRoot, ".pncli.json"));
9428
9760
  let credentials = null;
9429
9761
  let credentialsSkipped = cmdOpts.offline ? "--offline" : null;
9430
9762
  if (!cmdOpts.offline) {
@@ -9442,9 +9774,16 @@ function registerDoctorCommands(program2) {
9442
9774
  path: l.path,
9443
9775
  exists: l.exists,
9444
9776
  totalSkills: l.totalSkills,
9777
+ marketplaceSkills: l.marketplaceSkills,
9445
9778
  staleSkills: l.exists ? findStaleBundledSkills(l.path) : []
9446
9779
  }));
9447
- const problems = buildProblems(globalFile, repoFile, credentials, skillLocations);
9780
+ const marketplaces = getAllMarketplaces(globalConfig).map((m) => ({
9781
+ name: m.name ?? m.repoUrl ?? "(unnamed)",
9782
+ repoUrl: m.repoUrl ?? null,
9783
+ localPath: m.localPath ?? null,
9784
+ cloneExists: !!m.localPath && fs5.existsSync(m.localPath)
9785
+ }));
9786
+ const problems = buildProblems(globalFile, repoFile, credentials, skillLocations, marketplaces);
9448
9787
  if (credentials) {
9449
9788
  const statuses = Object.values(credentials).map((r) => r.status);
9450
9789
  if (statuses.includes("invalid")) process.exitCode = ExitCode.AUTH_ERROR;
@@ -9463,6 +9802,10 @@ function registerDoctorCommands(program2) {
9463
9802
  locations: skillLocations,
9464
9803
  staleTotal: skillLocations.reduce((sum, l) => sum + l.staleSkills.length, 0)
9465
9804
  },
9805
+ marketplaces: {
9806
+ registered: marketplaces,
9807
+ hint: marketplaces.length === 0 ? "No org marketplaces registered. Add one with: pncli skills marketplace add <git-url> --all-agents" : "Refresh with: pncli skills marketplace sync --marketplace all --all-agents"
9808
+ },
9466
9809
  problems
9467
9810
  }, "doctor", "check", start);
9468
9811
  } catch (err) {
@@ -9852,8 +10195,8 @@ function registerAdoProjectCommands(ado) {
9852
10195
  }
9853
10196
 
9854
10197
  // src/services/ado/commands/work.ts
9855
- import fs5 from "fs";
9856
- import path9 from "path";
10198
+ import fs6 from "fs";
10199
+ import path10 from "path";
9857
10200
 
9858
10201
  // src/services/ado/input-schema.ts
9859
10202
  var ADO_WORK_INPUT_FILE_SCHEMA = {
@@ -10094,11 +10437,11 @@ function registerAdoWorkCommands(ado) {
10094
10437
  const attachments = await workClient.listAttachments(collection, parseInt(opts.id, 10));
10095
10438
  const attachment = attachments.find((a) => a.id === opts.attachmentId);
10096
10439
  if (!attachment) throw new PncliError(`Attachment not found: ${opts.attachmentId}`, 1);
10097
- const outDir = opts.dir ?? path9.join(process.cwd(), ".pncli");
10098
- fs5.mkdirSync(outDir, { recursive: true });
10099
- const outPath = path9.join(outDir, path9.basename(attachment.name));
10440
+ const outDir = opts.dir ?? path10.join(process.cwd(), ".pncli");
10441
+ fs6.mkdirSync(outDir, { recursive: true });
10442
+ const outPath = path10.join(outDir, path10.basename(attachment.name));
10100
10443
  const buffer = await workClient.downloadAttachment(attachment.url);
10101
- fs5.writeFileSync(outPath, buffer);
10444
+ fs6.writeFileSync(outPath, buffer);
10102
10445
  success({ saved: outPath, name: attachment.name, size: buffer.length }, "ado", "work-download-attachment", start);
10103
10446
  } catch (err) {
10104
10447
  fail(err, "ado", "work-download-attachment", start);
@@ -10132,10 +10475,10 @@ function registerAdoWorkCommands(ado) {
10132
10475
  const types = await discoverTypes(workClient, collection, project);
10133
10476
  if (opts.save) {
10134
10477
  const globalConfigPath = getGlobalConfigPath(globalOpts.config);
10135
- const fs8 = await import("fs");
10136
- const existing = JSON.parse(fs8.readFileSync(globalConfigPath, "utf8") || "{}");
10478
+ const fs9 = await import("fs");
10479
+ const existing = JSON.parse(fs9.readFileSync(globalConfigPath, "utf8") || "{}");
10137
10480
  existing.ado = { ...existing.ado ?? {}, discoveredTypes: types };
10138
- fs8.writeFileSync(globalConfigPath, JSON.stringify(existing, null, 2) + "\n", "utf8");
10481
+ fs9.writeFileSync(globalConfigPath, JSON.stringify(existing, null, 2) + "\n", "utf8");
10139
10482
  warn(`Saved ${types.length} types to ${globalConfigPath}`);
10140
10483
  }
10141
10484
  success(types, "ado", "work-types", start);
@@ -10164,11 +10507,11 @@ function registerAdoWorkCommands(ado) {
10164
10507
  ) : allFields;
10165
10508
  if (opts.save) {
10166
10509
  const globalConfigPath = getGlobalConfigPath(globalOpts.config);
10167
- const fs8 = await import("fs");
10168
- const existing = JSON.parse(fs8.readFileSync(globalConfigPath, "utf8") || "{}");
10510
+ const fs9 = await import("fs");
10511
+ const existing = JSON.parse(fs9.readFileSync(globalConfigPath, "utf8") || "{}");
10169
10512
  const aliases = buildDefaultAliases(allFields);
10170
10513
  existing.ado = { ...existing.ado ?? {}, discoveredFields: allFields, fieldAliases: aliases };
10171
- fs8.writeFileSync(globalConfigPath, JSON.stringify(existing, null, 2) + "\n", "utf8");
10514
+ fs9.writeFileSync(globalConfigPath, JSON.stringify(existing, null, 2) + "\n", "utf8");
10172
10515
  warn(`Saved ${allFields.length} fields and ${Object.keys(aliases).length} aliases to ${globalConfigPath}`);
10173
10516
  }
10174
10517
  success(fields, "ado", "work-fields", start);
@@ -10469,7 +10812,7 @@ function registerAdoRepoCommands(ado) {
10469
10812
  const config = lc({ configPath: globalOpts.config });
10470
10813
  const { collection, project, repo: repo2, gitClient } = getAdoContext(ado, true);
10471
10814
  const { AdoCoreClient: AdoCoreClient2 } = await import("./core-SWYVXOQ4.js");
10472
- const { createHttpClient: createHttpClient2 } = await import("./http-TAINU2LF.js");
10815
+ const { createHttpClient: createHttpClient2 } = await import("./http-V7PZD7LE.js");
10473
10816
  const http = createHttpClient2(config, Boolean(globalOpts.dryRun));
10474
10817
  const coreClient = new AdoCoreClient2(http);
10475
10818
  const me = await coreClient.getConnectionData(collection);
@@ -10939,18 +11282,18 @@ var ArtifactoryClient = class {
10939
11282
  }
10940
11283
  });
10941
11284
  }
10942
- async getStorageInfo(repo, path10) {
10943
- const cleanPath = path10.startsWith("/") ? path10.slice(1) : path10;
11285
+ async getStorageInfo(repo, path11) {
11286
+ const cleanPath = path11.startsWith("/") ? path11.slice(1) : path11;
10944
11287
  return this.http.artifactory(`${API9}/storage/${repo}/${cleanPath}`);
10945
11288
  }
10946
- async getProperties(repo, path10) {
10947
- const cleanPath = path10.startsWith("/") ? path10.slice(1) : path10;
11289
+ async getProperties(repo, path11) {
11290
+ const cleanPath = path11.startsWith("/") ? path11.slice(1) : path11;
10948
11291
  return this.http.artifactory(`${API9}/storage/${repo}/${cleanPath}`, {
10949
11292
  params: { properties: "" }
10950
11293
  });
10951
11294
  }
10952
- async setProperties(repo, path10, properties, opts = {}) {
10953
- const cleanPath = path10.startsWith("/") ? path10.slice(1) : path10;
11295
+ async setProperties(repo, path11, properties, opts = {}) {
11296
+ const cleanPath = path11.startsWith("/") ? path11.slice(1) : path11;
10954
11297
  const propString = Object.entries(properties).map(([k, v]) => `${k}=${v}`).join(";");
10955
11298
  await this.http.artifactory(`${API9}/storage/${repo}/${cleanPath}`, {
10956
11299
  method: "PUT",
@@ -11032,27 +11375,27 @@ function registerArtifactoryCommands(program2) {
11032
11375
  fail(err, "artifactory", "repos", start);
11033
11376
  }
11034
11377
  });
11035
- art.command("artifact-info <repo> <path>").description("Get metadata for an artifact or folder (checksums, size, timestamps)").action(async (repo, path10) => {
11378
+ art.command("artifact-info <repo> <path>").description("Get metadata for an artifact or folder (checksums, size, timestamps)").action(async (repo, path11) => {
11036
11379
  const start = Date.now();
11037
11380
  try {
11038
11381
  const client = getClient8(program2);
11039
- const data = await client.getStorageInfo(repo, path10);
11382
+ const data = await client.getStorageInfo(repo, path11);
11040
11383
  success(data, "artifactory", "artifact-info", start);
11041
11384
  } catch (err) {
11042
11385
  fail(err, "artifactory", "artifact-info", start);
11043
11386
  }
11044
11387
  });
11045
- art.command("properties-get <repo> <path>").description("Read custom properties on an artifact").action(async (repo, path10) => {
11388
+ art.command("properties-get <repo> <path>").description("Read custom properties on an artifact").action(async (repo, path11) => {
11046
11389
  const start = Date.now();
11047
11390
  try {
11048
11391
  const client = getClient8(program2);
11049
- const data = await client.getProperties(repo, path10);
11392
+ const data = await client.getProperties(repo, path11);
11050
11393
  success(data, "artifactory", "properties-get", start);
11051
11394
  } catch (err) {
11052
11395
  fail(err, "artifactory", "properties-get", start);
11053
11396
  }
11054
11397
  });
11055
- 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, path10, keyvals, opts) => {
11398
+ 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, path11, keyvals, opts) => {
11056
11399
  const start = Date.now();
11057
11400
  try {
11058
11401
  if (!keyvals.length) throw new PncliError("Provide at least one key=value pair");
@@ -11063,8 +11406,8 @@ function registerArtifactoryCommands(program2) {
11063
11406
  properties[kv.slice(0, eq)] = kv.slice(eq + 1);
11064
11407
  }
11065
11408
  const client = getClient8(program2);
11066
- await client.setProperties(repo, path10, properties, { recursive: opts.recursive });
11067
- success({ repo, path: path10, properties }, "artifactory", "properties-set", start);
11409
+ await client.setProperties(repo, path11, properties, { recursive: opts.recursive });
11410
+ success({ repo, path: path11, properties }, "artifactory", "properties-set", start);
11068
11411
  } catch (err) {
11069
11412
  fail(err, "artifactory", "properties-set", start);
11070
11413
  }
@@ -11382,8 +11725,8 @@ function registerSonatypeIqCommands(program2) {
11382
11725
  const startTime = Date.now();
11383
11726
  try {
11384
11727
  const http = getHttpClient(program2);
11385
- const path10 = opts.organizationId ? `/api/v2/policies/organization/${encodeURIComponent(opts.organizationId)}` : "/api/v2/policies";
11386
- const data = await http.sonatypeiq(path10);
11728
+ const path11 = opts.organizationId ? `/api/v2/policies/organization/${encodeURIComponent(opts.organizationId)}` : "/api/v2/policies";
11729
+ const data = await http.sonatypeiq(path11);
11387
11730
  success(data, "sonatypeiq", "policies list", startTime);
11388
11731
  } catch (err) {
11389
11732
  fail(err, "sonatypeiq", "policies list", startTime);
@@ -12078,7 +12421,7 @@ function registerLogscaleCommands(program2) {
12078
12421
  }
12079
12422
 
12080
12423
  // src/services/splitio/commands.ts
12081
- import fs6 from "fs";
12424
+ import fs7 from "fs";
12082
12425
  import confirm2 from "@inquirer/confirm";
12083
12426
  function getHttp4(program2) {
12084
12427
  const opts = program2.optsWithGlobals();
@@ -12090,9 +12433,9 @@ function getHttp4(program2) {
12090
12433
  function loadInputFile(filePath) {
12091
12434
  let raw;
12092
12435
  if (filePath === "-") {
12093
- raw = fs6.readFileSync(process.stdin.fd, "utf8");
12436
+ raw = fs7.readFileSync(process.stdin.fd, "utf8");
12094
12437
  } else {
12095
- raw = fs6.readFileSync(filePath, "utf8");
12438
+ raw = fs7.readFileSync(filePath, "utf8");
12096
12439
  }
12097
12440
  try {
12098
12441
  return JSON.parse(raw);
@@ -12143,7 +12486,7 @@ function registerSplitioCommands(program2) {
12143
12486
  try {
12144
12487
  const http = getHttp4(program2);
12145
12488
  const data = await http.splitio(
12146
- `/internal/api/v2/workspaces/${encodeURIComponent(opts.workspace)}/environments`
12489
+ `/internal/api/v2/environments/ws/${encodeURIComponent(opts.workspace)}`
12147
12490
  );
12148
12491
  success(
12149
12492
  { count: data.objects.length, environments: data.objects },
@@ -12161,12 +12504,14 @@ function registerSplitioCommands(program2) {
12161
12504
  try {
12162
12505
  const http = getHttp4(program2);
12163
12506
  const params = {
12164
- wsId: opts.workspace,
12165
12507
  limit: parseInt(opts.limit, 10),
12166
12508
  offset: parseInt(opts.offset, 10)
12167
12509
  };
12168
12510
  if (opts.flagSet) params["flagSetName"] = opts.flagSet;
12169
- const data = await http.splitio("/internal/api/v2/splits", { params });
12511
+ const data = await http.splitio(
12512
+ `/internal/api/v2/splits/ws/${encodeURIComponent(opts.workspace)}`,
12513
+ { params }
12514
+ );
12170
12515
  success(
12171
12516
  { count: data.objects.length, totalCount: data.totalCount, flags: data.objects },
12172
12517
  "splitio",
@@ -12183,14 +12528,12 @@ function registerSplitioCommands(program2) {
12183
12528
  const http = getHttp4(program2);
12184
12529
  if (opts.environment) {
12185
12530
  const data = await http.splitio(
12186
- `/internal/api/v2/splits/${encodeURIComponent(opts.flag)}/environments/${encodeURIComponent(opts.environment)}`,
12187
- { params: { wsId: opts.workspace } }
12531
+ `/internal/api/v2/splits/ws/${encodeURIComponent(opts.workspace)}/name/${encodeURIComponent(opts.flag)}/environment/${encodeURIComponent(opts.environment)}`
12188
12532
  );
12189
12533
  success(data, "splitio", "flags get", start);
12190
12534
  } else {
12191
12535
  const data = await http.splitio(
12192
- `/internal/api/v2/splits/${encodeURIComponent(opts.flag)}`,
12193
- { params: { wsId: opts.workspace } }
12536
+ `/internal/api/v2/splits/ws/${encodeURIComponent(opts.workspace)}/name/${encodeURIComponent(opts.flag)}`
12194
12537
  );
12195
12538
  success(data, "splitio", "flags get", start);
12196
12539
  }
@@ -12215,7 +12558,7 @@ function registerSplitioCommands(program2) {
12215
12558
  },
12216
12559
  workspace: { id: opts.workspace }
12217
12560
  };
12218
- const data = await http.splitio("/internal/api/v2/changeRequests", {
12561
+ const data = await http.splitio(`/internal/api/v2/changeRequests/ws/${encodeURIComponent(opts.workspace)}`, {
12219
12562
  method: "POST",
12220
12563
  body
12221
12564
  });
@@ -12232,8 +12575,7 @@ function registerSplitioCommands(program2) {
12232
12575
  }
12233
12576
  const http = getHttp4(program2);
12234
12577
  const current = await http.splitio(
12235
- `/internal/api/v2/splits/${encodeURIComponent(opts.flag)}/environments/${encodeURIComponent(opts.environment)}`,
12236
- { params: { wsId: opts.workspace } }
12578
+ `/internal/api/v2/splits/ws/${encodeURIComponent(opts.workspace)}/name/${encodeURIComponent(opts.flag)}/environment/${encodeURIComponent(opts.environment)}`
12237
12579
  );
12238
12580
  const rules = current.rules ?? [];
12239
12581
  const idx = parseInt(opts.ruleIndex, 10);
@@ -12257,7 +12599,7 @@ function registerSplitioCommands(program2) {
12257
12599
  },
12258
12600
  workspace: { id: opts.workspace }
12259
12601
  };
12260
- const data = await http.splitio("/internal/api/v2/changeRequests", {
12602
+ const data = await http.splitio(`/internal/api/v2/changeRequests/ws/${encodeURIComponent(opts.workspace)}`, {
12261
12603
  method: "POST",
12262
12604
  body
12263
12605
  });
@@ -12271,8 +12613,7 @@ function registerSplitioCommands(program2) {
12271
12613
  try {
12272
12614
  const http = getHttp4(program2);
12273
12615
  const current = await http.splitio(
12274
- `/internal/api/v2/splits/${encodeURIComponent(opts.flag)}/environments/${encodeURIComponent(opts.environment)}`,
12275
- { params: { wsId: opts.workspace } }
12616
+ `/internal/api/v2/splits/ws/${encodeURIComponent(opts.workspace)}/name/${encodeURIComponent(opts.flag)}/environment/${encodeURIComponent(opts.environment)}`
12276
12617
  );
12277
12618
  await confirmWrite(opts, `SET_DEFAULT ${opts.treatment} on ${opts.flag} in ${opts.environment}`);
12278
12619
  const body = {
@@ -12288,7 +12629,7 @@ function registerSplitioCommands(program2) {
12288
12629
  },
12289
12630
  workspace: { id: opts.workspace }
12290
12631
  };
12291
- const data = await http.splitio("/internal/api/v2/changeRequests", {
12632
+ const data = await http.splitio(`/internal/api/v2/changeRequests/ws/${encodeURIComponent(opts.workspace)}`, {
12292
12633
  method: "POST",
12293
12634
  body
12294
12635
  });
@@ -12310,7 +12651,7 @@ function registerSplitioCommands(program2) {
12310
12651
  split: { name: opts.flag, environment: { id: opts.environment } },
12311
12652
  workspace: { id: opts.workspace }
12312
12653
  };
12313
- const data = await http.splitio("/internal/api/v2/changeRequests", {
12654
+ const data = await http.splitio(`/internal/api/v2/changeRequests/ws/${encodeURIComponent(opts.workspace)}`, {
12314
12655
  method: "POST",
12315
12656
  body
12316
12657
  });
@@ -12338,7 +12679,7 @@ function registerSplitioCommands(program2) {
12338
12679
  split: { name: entry.flag, environment: { id: opts.environment } },
12339
12680
  workspace: { id: opts.workspace }
12340
12681
  };
12341
- const cr = await http.splitio("/internal/api/v2/changeRequests", {
12682
+ const cr = await http.splitio(`/internal/api/v2/changeRequests/ws/${encodeURIComponent(opts.workspace)}`, {
12342
12683
  method: "POST",
12343
12684
  body
12344
12685
  });
@@ -12367,7 +12708,7 @@ function registerSplitioCommands(program2) {
12367
12708
  split: { name: opts.flag, environment: { id: opts.environment } },
12368
12709
  workspace: { id: opts.workspace }
12369
12710
  };
12370
- const data = await http.splitio("/internal/api/v2/changeRequests", {
12711
+ const data = await http.splitio(`/internal/api/v2/changeRequests/ws/${encodeURIComponent(opts.workspace)}`, {
12371
12712
  method: "POST",
12372
12713
  body
12373
12714
  });
@@ -12387,7 +12728,7 @@ function registerSplitioCommands(program2) {
12387
12728
  split: { name: opts.flag, environment: { id: opts.environment } },
12388
12729
  workspace: { id: opts.workspace }
12389
12730
  };
12390
- const data = await http.splitio("/internal/api/v2/changeRequests", {
12731
+ const data = await http.splitio(`/internal/api/v2/changeRequests/ws/${encodeURIComponent(opts.workspace)}`, {
12391
12732
  method: "POST",
12392
12733
  body
12393
12734
  });
@@ -12407,7 +12748,7 @@ function registerSplitioCommands(program2) {
12407
12748
  split: { name: opts.flag },
12408
12749
  workspace: { id: opts.workspace }
12409
12750
  };
12410
- const data = await http.splitio("/internal/api/v2/changeRequests", {
12751
+ const data = await http.splitio(`/internal/api/v2/changeRequests/ws/${encodeURIComponent(opts.workspace)}`, {
12411
12752
  method: "POST",
12412
12753
  body
12413
12754
  });
@@ -12422,14 +12763,13 @@ function registerSplitioCommands(program2) {
12422
12763
  try {
12423
12764
  const http = getHttp4(program2);
12424
12765
  const params = {
12425
- wsId: opts.workspace,
12426
12766
  limit: parseInt(opts.limit, 10),
12427
12767
  offset: parseInt(opts.offset, 10)
12428
12768
  };
12429
12769
  if (opts.environment) params["environmentId"] = opts.environment;
12430
12770
  if (opts.status) params["status"] = opts.status;
12431
12771
  const data = await http.splitio(
12432
- "/internal/api/v2/changeRequests",
12772
+ `/internal/api/v2/changeRequests/ws/${encodeURIComponent(opts.workspace)}`,
12433
12773
  { params }
12434
12774
  );
12435
12775
  success(
@@ -12627,7 +12967,7 @@ function registerFigmaCommands(program2) {
12627
12967
  }
12628
12968
 
12629
12969
  // src/services/alation/commands.ts
12630
- import fs7 from "fs";
12970
+ import fs8 from "fs";
12631
12971
  var MAX_PAGE = 1e3;
12632
12972
  function parseIntOption(value, flag) {
12633
12973
  if (value === void 0) return void 0;
@@ -12740,8 +13080,8 @@ function getHttp6(program2) {
12740
13080
  Boolean(opts.dryRun)
12741
13081
  );
12742
13082
  }
12743
- async function getOne(http, path10, id, what) {
12744
- const rows = await http.alation(path10, { params: { id, limit: 1 } });
13083
+ async function getOne(http, path11, id, what) {
13084
+ const rows = await http.alation(path11, { params: { id, limit: 1 } });
12745
13085
  const row = Array.isArray(rows) ? rows.find((r) => r.id === id) ?? rows[0] : void 0;
12746
13086
  if (!row) throw new PncliError(`${what} ${id} not found`, 404);
12747
13087
  return row;
@@ -12791,7 +13131,7 @@ function registerAlationCommands(program2) {
12791
13131
  const opts = program2.optsWithGlobals();
12792
13132
  const config = loadConfig({ configPath: opts.config });
12793
13133
  if (opts.dryRun) {
12794
- fs7.writeSync(process.stderr.fd, `DRY RUN: POST ${config.alation.baseUrl ?? "<alation.baseUrl>"}/integration/v1/createAPIAccessToken/ (token exchange skipped)
13134
+ fs8.writeSync(process.stderr.fd, `DRY RUN: POST ${config.alation.baseUrl ?? "<alation.baseUrl>"}/integration/v1/createAPIAccessToken/ (token exchange skipped)
12795
13135
  `);
12796
13136
  process.exitCode = ExitCode.SUCCESS;
12797
13137
  throw new PncliError("dry-run", 0);
@@ -13035,7 +13375,7 @@ if (!process.env.PNCLI_VERIFY_TLS) {
13035
13375
  process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
13036
13376
  }
13037
13377
  await configureProxy();
13038
- var TAGLINE = "One command does what three meetings couldn't.";
13378
+ var TAGLINE = "Connectivity without MCP.";
13039
13379
  var program = new Command3();
13040
13380
  program.name("pncli").description(`The Paperwork Nightmare CLI \u2014 ${TAGLINE}`).version(`${getPncliVersion()} \u2014 ${TAGLINE}`, "-v, --version").option("--pretty", "Human-readable formatted output", false).option("--verbose", "Include full response metadata", false).option("--debug", "Print diagnostic traces (method, URL, status) for all API calls \u2014 does not log credentials", false).option("--dry-run", "Print API requests without executing", false).option("--config <path>", "Override global config file location").option("--output-file <path>", "Write JSON output to file instead of stdout");
13041
13381
  program.hook("preAction", (thisCommand) => {
@@ -13099,9 +13439,16 @@ Services:
13099
13439
  figma Figma (files, comments, version history)
13100
13440
  alation Alation (data sources, schemas, tables, columns, search, Document Hubs)
13101
13441
  config Manage pncli configuration
13102
- doctor Diagnose pncli setup (config files, credentials, agent skills)
13442
+ doctor Diagnose pncli setup (config files, credentials, agent skills, marketplaces)
13103
13443
  skills Install and manage agent skills (Codex, GitHub Copilot, Claude Code)
13104
13444
  jwt JWT token utilities (decode header and payload)
13445
+
13446
+ Agent skills and org plugins:
13447
+ pncli skills install --all-agents Bundled pncli skills into this repo, every agent host
13448
+ pncli skills marketplace add <git-url> --all-agents Org plugins (skills + AGENTS.md/CLAUDE.md) from a git marketplace
13449
+ pncli skills marketplace sync Pull and refresh everything installed from marketplaces
13450
+ pncli skills marketplace manage Interactive: toggle plugins, add/remove marketplaces
13451
+ pncli skills --help Every install location and command
13105
13452
  `);
13106
13453
  program.parseAsync(process.argv).catch((err) => {
13107
13454
  if (process.exitCode !== void 0) return;