@kolatts/pncli 5.0.0 → 5.0.2

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
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ assertValidCustomFields,
3
4
  getGlobalConfigPath,
4
5
  loadConfig,
5
6
  loadJsonFile,
@@ -9,13 +10,12 @@ import {
9
10
  setRepoConfigValue,
10
11
  writeGlobalConfig,
11
12
  writeRepoConfig
12
- } from "./chunk-3JICA4FZ.js";
13
+ } from "./chunk-GRKPFSQD.js";
13
14
  import {
14
15
  createHttpClient
15
- } from "./chunk-EC6VSC6G.js";
16
+ } from "./chunk-5Q4VM6GO.js";
16
17
  import {
17
18
  ExitCode,
18
- PncliError,
19
19
  fail,
20
20
  log,
21
21
  setGlobalOptions,
@@ -23,7 +23,10 @@ import {
23
23
  success,
24
24
  warn,
25
25
  writeRawOutput
26
- } from "./chunk-HZF6WQPU.js";
26
+ } from "./chunk-BOFSNQQ2.js";
27
+ import {
28
+ PncliError
29
+ } from "./chunk-HRNOAQDN.js";
27
30
  import {
28
31
  AdoCoreClient
29
32
  } from "./chunk-VDL32PSG.js";
@@ -604,7 +607,7 @@ var BitbucketClient = class {
604
607
  project: { key: opts.project }
605
608
  }
606
609
  },
607
- reviewers: (opts.reviewers ?? []).map((slug) => ({ user: { slug } }))
610
+ reviewers: (opts.reviewers ?? []).map((name) => ({ user: { name } }))
608
611
  }
609
612
  }
610
613
  );
@@ -613,7 +616,7 @@ var BitbucketClient = class {
613
616
  const body = { version: opts.version };
614
617
  if (opts.title) body.title = opts.title;
615
618
  if (opts.description !== void 0) body.description = opts.description;
616
- if (opts.reviewers) body.reviewers = opts.reviewers.map((slug) => ({ user: { slug } }));
619
+ if (opts.reviewers) body.reviewers = opts.reviewers.map((name) => ({ user: { name } }));
617
620
  return this.http.bitbucket(
618
621
  `${API}/projects/${opts.project}/repos/${opts.repo}/pull-requests/${opts.id}`,
619
622
  { method: "PUT", body }
@@ -1228,6 +1231,7 @@ function collectMetaFields(projects, issueType) {
1228
1231
  function buildFieldMap(fields) {
1229
1232
  const byName = /* @__PURE__ */ new Map();
1230
1233
  const byId = /* @__PURE__ */ new Map();
1234
+ assertValidCustomFields(fields);
1231
1235
  for (const f of fields) {
1232
1236
  byName.set(f.name.toLowerCase(), f);
1233
1237
  byId.set(f.id, f);
@@ -6553,6 +6557,47 @@ function marketplaceLabel(m) {
6553
6557
  function scrubToken(msg) {
6554
6558
  return msg.replace(/x-(?:token-auth|access-token):[^@]+@/g, "x-token-auth:***@");
6555
6559
  }
6560
+ function isConfiguredGitHubHost(repoUrl, githubBaseUrl) {
6561
+ try {
6562
+ const host = new URL(repoUrl).hostname;
6563
+ if (host === "github.com") return true;
6564
+ if (!githubBaseUrl) return false;
6565
+ return new URL(githubBaseUrl).hostname === host;
6566
+ } catch {
6567
+ return false;
6568
+ }
6569
+ }
6570
+ function resolveMarketplaceToken(explicitToken, repoUrl) {
6571
+ if (explicitToken) return explicitToken;
6572
+ if (!repoUrl) return void 0;
6573
+ const resolved = loadConfig();
6574
+ if (!isConfiguredGitHubHost(repoUrl, resolved.github.baseUrl)) return void 0;
6575
+ return resolved.github.token;
6576
+ }
6577
+ var GIT_AUTH_FAILURE_PATTERNS = [
6578
+ /invalid username or (password|token)/i,
6579
+ /authentication failed/i,
6580
+ /could not read username/i,
6581
+ /could not read password/i,
6582
+ /support for password authentication was removed/i
6583
+ ];
6584
+ var GIT_NOT_FOUND_PATTERNS = [/repository not found/i];
6585
+ function describeGitFailure(rawMessage, marketplaceName, tokenSource) {
6586
+ const msg = scrubToken(rawMessage);
6587
+ if (GIT_AUTH_FAILURE_PATTERNS.some((p) => p.test(msg))) {
6588
+ const hint = tokenSource === "explicit" ? `The token configured for marketplace "${marketplaceName}" was rejected \u2014 it may be expired, revoked, or missing required scopes. Update it with: pncli skills marketplace add <url> --token <new-token>` : tokenSource === "fallback" ? `The GitHub token pncli is using (PNCLI_GITHUB_TOKEN / GITHUB_TOKEN / github.token) was rejected for marketplace "${marketplaceName}" \u2014 it may be expired, revoked, or missing required scopes for this repo. Rotate that token, or set one specifically for this marketplace: pncli skills marketplace add <url> --token <new-token>` : `Marketplace "${marketplaceName}" requires authentication but no token is configured. Add one with: pncli skills marketplace add <url> --token <token>`;
6589
+ return new Error(`${hint}
6590
+
6591
+ Git reported: ${msg}`);
6592
+ }
6593
+ if (GIT_NOT_FOUND_PATTERNS.some((p) => p.test(msg))) {
6594
+ const hint = tokenSource === "explicit" ? `Repository for marketplace "${marketplaceName}" was not found \u2014 check the URL and that the configured token has access to it.` : tokenSource === "fallback" ? `Repository for marketplace "${marketplaceName}" was not found \u2014 check the URL and that pncli's configured GitHub token has access to it.` : `Repository for marketplace "${marketplaceName}" was not found \u2014 if it's private, add a token: pncli skills marketplace add <url> --token <token>`;
6595
+ return new Error(`${hint}
6596
+
6597
+ Git reported: ${msg}`);
6598
+ }
6599
+ return new Error(msg);
6600
+ }
6556
6601
  function assertInteractive(hint) {
6557
6602
  if (!process.stdin.isTTY) {
6558
6603
  throw new Error(`This selection requires an interactive terminal. ${hint}`);
@@ -7019,7 +7064,7 @@ function upsertMarketplace(all, entry) {
7019
7064
  all.push(entry);
7020
7065
  }
7021
7066
  }
7022
- function cloneOrReuseMarketplace(url, resolvedPath, opts) {
7067
+ function cloneOrReuseMarketplace(url, resolvedPath, opts, marketplaceName) {
7023
7068
  const hasGit = fs2.existsSync(path7.join(resolvedPath, ".git"));
7024
7069
  if (fs2.existsSync(resolvedPath) && !hasGit && fs2.readdirSync(resolvedPath).length > 0) {
7025
7070
  throw new Error(`Directory already exists and is not a git repo: ${resolvedPath}`);
@@ -7028,9 +7073,10 @@ function cloneOrReuseMarketplace(url, resolvedPath, opts) {
7028
7073
  warn(`Directory already contains a git repo at ${resolvedPath} \u2014 skipping clone, updating config and re-installing plugins.`);
7029
7074
  return;
7030
7075
  }
7076
+ const resolvedToken = resolveMarketplaceToken(opts.token, url);
7031
7077
  const branchLabel = opts.branch ?? "remote default";
7032
7078
  warn(`Cloning ${url} (branch: ${branchLabel}) \u2192 ${resolvedPath}...`);
7033
- const cloneUrl = opts.token ? injectTokenIntoUrl(url, opts.token) : url;
7079
+ const cloneUrl = resolvedToken ? injectTokenIntoUrl(url, resolvedToken) : url;
7034
7080
  const cloneArgs = ["clone"];
7035
7081
  if (opts.branch) cloneArgs.push("--branch", opts.branch);
7036
7082
  cloneArgs.push(cloneUrl, resolvedPath);
@@ -7045,15 +7091,17 @@ function cloneOrReuseMarketplace(url, resolvedPath, opts) {
7045
7091
  }
7046
7092
  if (!cloneActuallySucceeded) {
7047
7093
  const msg = e instanceof Error ? e.message : String(e);
7048
- throw new Error(scrubToken(msg));
7094
+ const tokenSource = opts.token ? "explicit" : resolvedToken ? "fallback" : "none";
7095
+ throw describeGitFailure(msg, marketplaceName, tokenSource);
7049
7096
  }
7050
7097
  }
7051
7098
  }
7052
7099
  function pullMarketplace(marketplacePath, repoUrl, token, marketplaceName) {
7100
+ const resolvedToken = resolveMarketplaceToken(token, repoUrl);
7053
7101
  warn(`Pulling latest content for "${marketplaceName}"...`);
7054
7102
  const gitArgs = ["-C", marketplacePath];
7055
- if (repoUrl && token) {
7056
- gitArgs.push("-c", `remote.origin.url=${injectTokenIntoUrl(repoUrl, token)}`);
7103
+ if (repoUrl && resolvedToken) {
7104
+ gitArgs.push("-c", `remote.origin.url=${injectTokenIntoUrl(repoUrl, resolvedToken)}`);
7057
7105
  }
7058
7106
  gitArgs.push("pull");
7059
7107
  let pullOutput;
@@ -7061,7 +7109,8 @@ function pullMarketplace(marketplacePath, repoUrl, token, marketplaceName) {
7061
7109
  pullOutput = execFileSync3("git", gitArgs, { encoding: "utf8", stdio: ["inherit", "pipe", "pipe"], env: { ...process.env, LANG: "C", LC_ALL: "C" } });
7062
7110
  } catch (e) {
7063
7111
  const msg = e instanceof Error ? e.message : String(e);
7064
- throw new Error(scrubToken(msg));
7112
+ const tokenSource = token ? "explicit" : resolvedToken ? "fallback" : "none";
7113
+ throw describeGitFailure(msg, marketplaceName, tokenSource);
7065
7114
  }
7066
7115
  const updated = !pullOutput.includes("Already up to date");
7067
7116
  if (pullOutput.trim() && updated) warn(pullOutput.trim());
@@ -7152,7 +7201,7 @@ function syncMarketplacePlugins(m, targetDir, force, pluginFilter, installedOnly
7152
7201
  function performMarketplaceAdd(url, localPath, opts) {
7153
7202
  const resolvedPath = path7.resolve(localPath ?? defaultMarketplacePath(url));
7154
7203
  const marketplaceName = opts.name ?? repoNameFromUrl(url);
7155
- cloneOrReuseMarketplace(url, resolvedPath, opts);
7204
+ cloneOrReuseMarketplace(url, resolvedPath, opts, marketplaceName);
7156
7205
  const configPath = getGlobalConfigPath();
7157
7206
  const { existing, all } = loadMarketplacesConfig(configPath);
7158
7207
  const entry = {
@@ -10342,11 +10391,11 @@ function registerAdoRepoCommands(ado) {
10342
10391
  const start = Date.now();
10343
10392
  try {
10344
10393
  const globalOpts = ado.optsWithGlobals();
10345
- const { loadConfig: lc } = await import("./config-7FK4MAQC.js");
10394
+ const { loadConfig: lc } = await import("./config-ZVQMQ6B2.js");
10346
10395
  const config = lc({ configPath: globalOpts.config });
10347
10396
  const { collection, project, repo: repo2, gitClient } = getAdoContext(ado, true);
10348
10397
  const { AdoCoreClient: AdoCoreClient2 } = await import("./core-SWYVXOQ4.js");
10349
- const { createHttpClient: createHttpClient2 } = await import("./http-M5GQGXVF.js");
10398
+ const { createHttpClient: createHttpClient2 } = await import("./http-RX7E2V5C.js");
10350
10399
  const http = createHttpClient2(config, Boolean(globalOpts.dryRun));
10351
10400
  const coreClient = new AdoCoreClient2(http);
10352
10401
  const me = await coreClient.getConnectionData(collection);
@@ -12356,7 +12405,7 @@ function registerFigmaCommands(program2) {
12356
12405
  const figma = program2.command("figma").description("Figma design operations (files, comments, versions)");
12357
12406
  figma.command("file").description("Get a Figma file \u2014 metadata, structure, and component/style inventory").argument("<file-key-or-url>", "Figma file key or full Figma URL (https://www.figma.com/design/<key>/...)").option("--document", "Include the full document node tree (can be large; omitted by default)").action(async (fileKeyOrUrl, opts) => {
12358
12407
  const start = Date.now();
12359
- const { success: success2, fail: fail2 } = await import("./output-XT3WT5L5.js");
12408
+ const { success: success2, fail: fail2 } = await import("./output-HDUIIXUI.js");
12360
12409
  try {
12361
12410
  const fileKey = parseFileKey(fileKeyOrUrl);
12362
12411
  const params = {};
@@ -12388,7 +12437,7 @@ function registerFigmaCommands(program2) {
12388
12437
  });
12389
12438
  figma.command("comments").description("Get comments on a Figma file").argument("<file-key-or-url>", "Figma file key or full Figma URL").option("--as-of <date>", "ISO 8601 timestamp \u2014 return only comments created before this time").action(async (fileKeyOrUrl, opts) => {
12390
12439
  const start = Date.now();
12391
- const { success: success2, fail: fail2 } = await import("./output-XT3WT5L5.js");
12440
+ const { success: success2, fail: fail2 } = await import("./output-HDUIIXUI.js");
12392
12441
  try {
12393
12442
  const fileKey = parseFileKey(fileKeyOrUrl);
12394
12443
  const params = {};
@@ -12406,7 +12455,7 @@ function registerFigmaCommands(program2) {
12406
12455
  });
12407
12456
  figma.command("versions").description("Get the version history of a Figma file").argument("<file-key-or-url>", "Figma file key or full Figma URL").action(async (fileKeyOrUrl) => {
12408
12457
  const start = Date.now();
12409
- const { success: success2, fail: fail2 } = await import("./output-XT3WT5L5.js");
12458
+ const { success: success2, fail: fail2 } = await import("./output-HDUIIXUI.js");
12410
12459
  try {
12411
12460
  const fileKey = parseFileKey(fileKeyOrUrl);
12412
12461
  const data = await getHttp5(program2).figma(`/v1/files/${encodeURIComponent(fileKey)}/versions`);
@@ -12422,7 +12471,7 @@ function registerFigmaCommands(program2) {
12422
12471
  });
12423
12472
  figma.command("project-files").description("List files in a Figma project").argument("<project-id>", "Figma project ID (visible in the project URL)").action(async (projectId) => {
12424
12473
  const start = Date.now();
12425
- const { success: success2, fail: fail2 } = await import("./output-XT3WT5L5.js");
12474
+ const { success: success2, fail: fail2 } = await import("./output-HDUIIXUI.js");
12426
12475
  try {
12427
12476
  const data = await getHttp5(program2).figma(`/v1/projects/${encodeURIComponent(projectId)}/files`);
12428
12477
  success2(
@@ -12437,7 +12486,7 @@ function registerFigmaCommands(program2) {
12437
12486
  });
12438
12487
  figma.command("me").description("Get the current Figma user (useful for verifying credentials)").action(async () => {
12439
12488
  const start = Date.now();
12440
- const { success: success2, fail: fail2 } = await import("./output-XT3WT5L5.js");
12489
+ const { success: success2, fail: fail2 } = await import("./output-HDUIIXUI.js");
12441
12490
  try {
12442
12491
  const data = await getHttp5(program2).figma("/v1/me");
12443
12492
  success2(data, "figma", "me", start);