@kolatts/pncli 6.0.0 → 6.2.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
@@ -28,13 +28,13 @@ import {
28
28
  windowsListCredentials,
29
29
  writeGlobalConfig,
30
30
  writeRepoConfig
31
- } from "./chunk-WDWAPTVC.js";
31
+ } from "./chunk-GHZMFNSX.js";
32
32
  import {
33
33
  configureTls,
34
34
  createHttpClient,
35
35
  describeFetchError,
36
36
  validateAlationAccessToken
37
- } from "./chunk-4FR4WGNR.js";
37
+ } from "./chunk-RZV64BWP.js";
38
38
  import {
39
39
  ExitCode,
40
40
  fail,
@@ -44,7 +44,7 @@ import {
44
44
  success,
45
45
  warn,
46
46
  writeRawOutput
47
- } from "./chunk-BOFSNQQ2.js";
47
+ } from "./chunk-MBJ4ZYL7.js";
48
48
  import {
49
49
  PncliError
50
50
  } from "./chunk-HRNOAQDN.js";
@@ -579,6 +579,20 @@ function getGitContext(config) {
579
579
  return { root, branch, project, repo, ado: adoContext, github: githubContext };
580
580
  }
581
581
 
582
+ // src/lib/dates.ts
583
+ function parseDateOption(flag, value) {
584
+ const date = new Date(value);
585
+ if (Number.isNaN(date.getTime())) {
586
+ throw new PncliError(`Invalid ${flag} value "${value}". Use an ISO 8601 date such as 2025-01-31 or 2025-01-31T09:00:00Z.`, 1);
587
+ }
588
+ return date;
589
+ }
590
+ function inDateRange(time, after, before) {
591
+ if (after && time < after.getTime()) return false;
592
+ if (before && time >= before.getTime()) return false;
593
+ return true;
594
+ }
595
+
582
596
  // src/services/bitbucket/client.ts
583
597
  var API = "/rest/api/1.0";
584
598
  var BitbucketClient = class {
@@ -587,19 +601,32 @@ var BitbucketClient = class {
587
601
  }
588
602
  http;
589
603
  async listPRs(opts) {
590
- return this.http.paginate(
604
+ const userFilters = {};
605
+ let n = 1;
606
+ if (opts.author) {
607
+ userFilters[`username.${n}`] = opts.author;
608
+ userFilters[`role.${n}`] = "AUTHOR";
609
+ n++;
610
+ }
611
+ if (opts.reviewer) {
612
+ userFilters[`username.${n}`] = opts.reviewer;
613
+ userFilters[`role.${n}`] = "REVIEWER";
614
+ }
615
+ const prs = await this.http.paginate(
591
616
  (start, limit) => this.http.bitbucket(
592
617
  `${API}/projects/${opts.project}/repos/${opts.repo}/pull-requests`,
593
618
  {
594
619
  params: {
595
620
  state: opts.state ?? "OPEN",
596
- ...opts.author ? { "author.username": opts.author } : {},
621
+ ...userFilters,
597
622
  start,
598
623
  limit
599
624
  }
600
625
  }
601
626
  )
602
627
  );
628
+ if (!opts.createdAfter && !opts.createdBefore) return prs;
629
+ return prs.filter((pr) => inDateRange(pr.createdDate, opts.createdAfter, opts.createdBefore));
603
630
  }
604
631
  async getPR(project, repo, id2) {
605
632
  return this.http.bitbucket(
@@ -716,8 +743,8 @@ var BitbucketClient = class {
716
743
  }
717
744
  async resolveComment(project, repo, prId, commentId, version) {
718
745
  await this.http.bitbucket(
719
- `${API}/projects/${project}/repos/${repo}/pull-requests/${prId}/comments/${commentId}/resolve`,
720
- { method: "PUT", params: { version } }
746
+ `${API}/projects/${project}/repos/${repo}/pull-requests/${prId}/comments/${commentId}`,
747
+ { method: "PUT", body: { version, threadResolved: true } }
721
748
  );
722
749
  }
723
750
  async deleteComment(project, repo, prId, commentId, version) {
@@ -790,6 +817,12 @@ var BitbucketClient = class {
790
817
  const pr = await this.getPR(project, repo, prId);
791
818
  return pr.reviewers;
792
819
  }
820
+ async listDefaultReviewers(project, repo) {
821
+ const result = await this.http.bitbucket(
822
+ `/rest/default-reviewers/1.0/projects/${encodeURIComponent(project)}/repos/${encodeURIComponent(repo)}/conditions`
823
+ );
824
+ return Array.isArray(result) ? result : [];
825
+ }
793
826
  async addReviewer(project, repo, prId, username) {
794
827
  return this.http.bitbucket(
795
828
  `${API}/projects/${project}/repos/${repo}/pull-requests/${prId}/participants`,
@@ -2110,23 +2143,28 @@ var JiraClient = class {
2110
2143
  }
2111
2144
  });
2112
2145
  }
2113
- async search(jql, maxResults, customFields) {
2146
+ async search(jql, maxResults, customFields, startAt, fieldsOverride) {
2114
2147
  const standardFields = ["summary", "status", "priority", "assignee", "issuetype", "project", "created", "updated", "labels", "reporter"];
2115
- const fields = customFields?.length ? [...standardFields, ...customFields.map((f) => f.id)] : standardFields;
2116
- if (maxResults !== void 0) {
2117
- return this.http.jira(`${API2}/search`, {
2148
+ const fields = fieldsOverride?.length ? fieldsOverride : customFields?.length ? [...standardFields, ...customFields.map((f) => f.id)] : standardFields;
2149
+ const first = startAt ?? 0;
2150
+ const issues = [];
2151
+ let total = 0;
2152
+ let next = first;
2153
+ while (true) {
2154
+ const pageSize = maxResults === void 0 ? 100 : Math.min(100, maxResults - issues.length);
2155
+ if (pageSize <= 0 && issues.length > 0) break;
2156
+ const page = await this.http.jira(`${API2}/search`, {
2118
2157
  method: "POST",
2119
- body: { jql, maxResults, fields }
2158
+ body: { jql, startAt: next, maxResults: pageSize, fields }
2120
2159
  });
2160
+ const items = page.issues ?? [];
2161
+ issues.push(...items);
2162
+ total = page.total;
2163
+ next += items.length;
2164
+ if (next >= total || items.length === 0) break;
2165
+ if (maxResults !== void 0 && issues.length >= maxResults) break;
2121
2166
  }
2122
- const allIssues = await this.http.jiraPaginate(async (startAt, max) => {
2123
- const result = await this.http.jira(`${API2}/search`, {
2124
- method: "POST",
2125
- body: { jql, startAt, maxResults: max, fields }
2126
- });
2127
- return { ...result, values: result.issues };
2128
- });
2129
- return { issues: allIssues, total: allIssues.length, startAt: 0, maxResults: allIssues.length };
2167
+ return { issues, total, startAt: first, maxResults: issues.length };
2130
2168
  }
2131
2169
  async fetchFields() {
2132
2170
  const fields = await this.http.jira(`${API2}/field`);
@@ -2277,6 +2315,10 @@ var JiraClient = class {
2277
2315
  function schemaToPncliType(schema) {
2278
2316
  if (!schema) return void 0;
2279
2317
  const custom = schema.custom ?? "";
2318
+ if (custom.endsWith(":gh-epic-link")) return "string";
2319
+ if (custom.endsWith(":gh-sprint")) return "number";
2320
+ if (custom.endsWith(":gh-lexo-rank")) return "string";
2321
+ if (custom.endsWith(":jpo-custom-field-parent")) return "string";
2280
2322
  if (custom.includes("cascadingselect")) return "cascading-select";
2281
2323
  if (custom.includes("multicheckboxes") || custom.includes("multiselect")) return "multi-select";
2282
2324
  if (custom.includes("select") || custom.includes("radiobuttons")) return "select";
@@ -2521,6 +2563,13 @@ function resolveJqlInput(jql, jqlFile) {
2521
2563
  if (!trimmed) throw new PncliError("JQL query is empty", 1);
2522
2564
  return trimmed;
2523
2565
  }
2566
+ function parseStartAt(raw) {
2567
+ if (raw === void 0) return void 0;
2568
+ if (!/^\d+$/.test(raw)) {
2569
+ throw new PncliError(`--start-at must be a non-negative integer, got "${raw}"`, 1);
2570
+ }
2571
+ return parseInt(raw, 10);
2572
+ }
2524
2573
  function registerJiraCommands(program2) {
2525
2574
  const jira = program2.command("jira").description("Jira Data Cloud operations");
2526
2575
  jira.command("get-issue").description("Get a Jira issue by key").requiredOption("--key <issue-key>", "Issue key (e.g. PROJ-123)").action(async (opts) => {
@@ -2680,14 +2729,24 @@ function registerJiraCommands(program2) {
2680
2729
  fail(err, "jira", "list-comments", start);
2681
2730
  }
2682
2731
  });
2683
- jira.command("search").description("Search Jira issues with JQL (consider --output-file for large results)").option("--jql <query>", "JQL query string").option("--jql-file <path>", "Path to a file containing the JQL query ('-' = stdin)").option("--max-results <n>", "Maximum number of results").action(async (opts) => {
2732
+ jira.command("search").description("Search Jira issues with JQL (consider --output-file for large results)").option("--jql <query>", "JQL query string").option("--jql-file <path>", "Path to a file containing the JQL query ('-' = stdin)").option("--max-results <n>", "Maximum number of results").option("--start-at <n>", "Index of the first result to return (for resuming or paging)").option("--fields <list>", 'Comma-separated fields to return instead of the default set (names or ids, e.g. summary,status,"Story Points")').action(async (opts) => {
2684
2733
  const start = Date.now();
2685
2734
  try {
2686
2735
  const { client, fieldMap, customFields } = getClientAndFields(program2);
2687
2736
  const jql = resolveJqlInput(opts.jql, opts.jqlFile);
2737
+ let fieldsOverride;
2738
+ if (opts.fields !== void 0) {
2739
+ fieldsOverride = opts.fields.split(",").map((s) => s.trim()).filter(Boolean).map((name) => {
2740
+ const id2 = resolveFieldKey(name, fieldMap);
2741
+ if (id2 === void 0) throw new PncliError(`Unknown field in --fields: "${name}". Use a field id or a registered custom field name.`, 1);
2742
+ return id2;
2743
+ });
2744
+ if (fieldsOverride.length === 0) throw new PncliError("--fields must list at least one field", 1);
2745
+ }
2688
2746
  const maxResults = opts.maxResults ? parseInt(opts.maxResults, 10) : void 0;
2747
+ const startAt = parseStartAt(opts.startAt);
2689
2748
  const translatedJql = translateJql(jql, fieldMap);
2690
- const data = await client.search(translatedJql, maxResults, customFields);
2749
+ const data = await client.search(translatedJql, maxResults, customFields, startAt, fieldsOverride);
2691
2750
  const translatedIssues = data.issues.map((issue) => ({
2692
2751
  ...issue,
2693
2752
  fields: translateFieldsInOutput(issue.fields, fieldMap)
@@ -2932,11 +2991,13 @@ function registerBitbucketCommands(program2) {
2932
2991
  fail(err, "bitbucket", "create-repo", start);
2933
2992
  }
2934
2993
  });
2935
- bb.command("list-prs").description("List pull requests").option("--state <state>", "PR state: OPEN|MERGED|DECLINED|ALL", "OPEN").option("--author <username>", "Filter by author username").option("--reviewer <username>", "Filter by reviewer username").action(async (opts) => {
2994
+ bb.command("list-prs").description("List pull requests").option("--state <state>", "PR state: OPEN|MERGED|DECLINED|ALL", "OPEN").option("--author <username>", "Filter by author username").option("--reviewer <username>", "Filter by reviewer username").option("--created-after <date>", "Only PRs created on/after this ISO 8601 date (e.g. 2025-01-31)").option("--created-before <date>", "Only PRs created before this ISO 8601 date").action(async (opts) => {
2936
2995
  const start = Date.now();
2937
2996
  try {
2997
+ const createdAfter = opts.createdAfter ? parseDateOption("--created-after", opts.createdAfter) : void 0;
2998
+ const createdBefore = opts.createdBefore ? parseDateOption("--created-before", opts.createdBefore) : void 0;
2938
2999
  const { client, project, repo } = getClient2(bb);
2939
- const data = await client.listPRs({ project, repo, state: opts.state, author: opts.author, reviewer: opts.reviewer });
3000
+ const data = await client.listPRs({ project, repo, state: opts.state, author: opts.author, reviewer: opts.reviewer, createdAfter, createdBefore });
2940
3001
  success(data, "bitbucket", "list-prs", start);
2941
3002
  } catch (err) {
2942
3003
  fail(err, "bitbucket", "list-prs", start);
@@ -3015,8 +3076,8 @@ function registerBitbucketCommands(program2) {
3015
3076
  const { client, project, repo } = getClient2(bb);
3016
3077
  const prId = parseInt(opts.id, 10);
3017
3078
  const pr = await client.getPR(project, repo, prId);
3018
- const reviewers = opts.reviewers ? opts.reviewers.split(",").map((s) => s.trim()) : void 0;
3019
- const data = await client.updatePR({ project, repo, id: prId, title: opts.title, description: opts.description, reviewers, version: pr.version });
3079
+ const reviewers = opts.reviewers ? opts.reviewers.split(",").map((s) => s.trim()) : (pr.reviewers ?? []).map((r) => r.user.name);
3080
+ const data = await client.updatePR({ project, repo, id: prId, title: opts.title ?? pr.title, description: opts.description ?? pr.description, reviewers, version: pr.version });
3020
3081
  success(data, "bitbucket", "update-pr", start);
3021
3082
  } catch (err) {
3022
3083
  fail(err, "bitbucket", "update-pr", start);
@@ -3098,7 +3159,7 @@ function registerBitbucketCommands(program2) {
3098
3159
  fail(err, "bitbucket", "reply-comment", start);
3099
3160
  }
3100
3161
  });
3101
- 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) => {
3162
+ bb.command("resolve-comment").description("Resolve a comment thread on a pull request (use the root comment ID, not a reply)").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) => {
3102
3163
  const start = Date.now();
3103
3164
  try {
3104
3165
  const { client, project, repo } = getClient2(bb);
@@ -3179,6 +3240,16 @@ function registerBitbucketCommands(program2) {
3179
3240
  fail(err, "bitbucket", "list-reviewers", start);
3180
3241
  }
3181
3242
  });
3243
+ bb.command("list-default-reviewers").description("List the default-reviewer conditions configured for a repository").action(async () => {
3244
+ const start = Date.now();
3245
+ try {
3246
+ const { client, project, repo } = getClient2(bb);
3247
+ const data = await client.listDefaultReviewers(project, repo);
3248
+ success(data, "bitbucket", "list-default-reviewers", start);
3249
+ } catch (err) {
3250
+ fail(err, "bitbucket", "list-default-reviewers", start);
3251
+ }
3252
+ });
3182
3253
  bb.command("add-reviewer").description("Add a reviewer to a pull request").requiredOption("--pr <pr-id>", "Pull request ID").requiredOption("--user <username>", "Username to add as a reviewer").action(async (opts) => {
3183
3254
  const start = Date.now();
3184
3255
  try {
@@ -3221,7 +3292,7 @@ var GitHubClient = class {
3221
3292
  }
3222
3293
  http;
3223
3294
  async listPRs(opts) {
3224
- return this.http.githubPaginate(
3295
+ const prs = await this.http.githubPaginate(
3225
3296
  (page, perPage) => this.http.github(
3226
3297
  `/repos/${opts.owner}/${opts.repo}/pulls`,
3227
3298
  {
@@ -3235,6 +3306,10 @@ var GitHubClient = class {
3235
3306
  }
3236
3307
  )
3237
3308
  );
3309
+ const author = opts.author?.toLowerCase();
3310
+ return prs.filter(
3311
+ (pr) => (!author || pr.user?.login?.toLowerCase() === author) && inDateRange(Date.parse(pr.created_at), opts.createdAfter, opts.createdBefore)
3312
+ );
3238
3313
  }
3239
3314
  async getPR(owner, repo, pullNumber) {
3240
3315
  return this.http.github(`/repos/${owner}/${repo}/pulls/${pullNumber}`);
@@ -3777,16 +3852,21 @@ function registerGitHubCommands(program2) {
3777
3852
  fail(err, "github", "create-issue", start);
3778
3853
  }
3779
3854
  });
3780
- gh.command("list-prs").description("List pull requests").addOption(new Option("--state <state>", "PR state").choices(["open", "closed", "all"]).default("open")).option("--head <branch>", "Filter by head branch (user:branch)").option("--base <branch>", "Filter by base branch").action(async (opts) => {
3855
+ gh.command("list-prs").description("List pull requests").addOption(new Option("--state <state>", "PR state").choices(["open", "closed", "all"]).default("open")).option("--head <branch>", "Filter by head branch (user:branch)").option("--base <branch>", "Filter by base branch").option("--author <login>", "Filter by author login").option("--created-after <date>", "Only PRs created on/after this ISO 8601 date (e.g. 2025-01-31)").option("--created-before <date>", "Only PRs created before this ISO 8601 date").action(async (opts) => {
3781
3856
  const start = Date.now();
3782
3857
  try {
3858
+ const createdAfter = opts.createdAfter ? parseDateOption("--created-after", opts.createdAfter) : void 0;
3859
+ const createdBefore = opts.createdBefore ? parseDateOption("--created-before", opts.createdBefore) : void 0;
3783
3860
  const { client, owner, repo } = getClient3(gh);
3784
3861
  const data = await client.listPRs({
3785
3862
  owner,
3786
3863
  repo,
3787
3864
  state: opts.state,
3788
3865
  head: opts.head,
3789
- base: opts.base
3866
+ base: opts.base,
3867
+ author: opts.author,
3868
+ createdAfter,
3869
+ createdBefore
3790
3870
  });
3791
3871
  success(data, "github", "list-prs", start);
3792
3872
  } catch (err) {
@@ -7109,7 +7189,7 @@ var AdoWorkClient = class {
7109
7189
  const result = await this.http.ado(
7110
7190
  `/${encodeURIComponent(collection)}/${encodeURIComponent(project)}/_apis/wit/workItems/${workItemId}/comments?api-version=${API_PREVIEW}`
7111
7191
  );
7112
- return result.value ?? [];
7192
+ return result.comments ?? result.value ?? [];
7113
7193
  }
7114
7194
  async addComment(collection, project, workItemId, text) {
7115
7195
  return this.http.ado(
@@ -7356,7 +7436,7 @@ function registerSauceLabsCommands(program2) {
7356
7436
  function run(action, fn) {
7357
7437
  return async (...args) => {
7358
7438
  const start = Date.now();
7359
- const { success: success2, fail: fail2 } = await import("./output-HDUIIXUI.js");
7439
+ const { success: success2, fail: fail2 } = await import("./output-XE6XDAAR.js");
7360
7440
  try {
7361
7441
  success2(await fn(getHttp(program2), ...args), SERVICE, action, start);
7362
7442
  } catch (err) {
@@ -7982,6 +8062,18 @@ async function runCredentialChecks(cfg, http) {
7982
8062
  results.logscale = categorize(err);
7983
8063
  }
7984
8064
  }
8065
+ if (!cfg.elasticsearch.apiKey) {
8066
+ results.elasticsearch = { status: "blank", message: "not configured" };
8067
+ } else if (!cfg.elasticsearch.baseUrl) {
8068
+ results.elasticsearch = { status: "error", message: "baseUrl not configured" };
8069
+ } else {
8070
+ try {
8071
+ await http.elasticsearch("/_cluster/health", { timeoutMs: 1e4 });
8072
+ results.elasticsearch = { status: "valid", message: "ok" };
8073
+ } catch (err) {
8074
+ results.elasticsearch = categorize(err);
8075
+ }
8076
+ }
7985
8077
  if (!cfg.splitio.adminApiKey) {
7986
8078
  results.splitio = { status: "blank", message: "not configured" };
7987
8079
  } else if (!cfg.splitio.baseUrl) {
@@ -9417,7 +9509,7 @@ function pullMarketplace(marketplacePath, m, marketplaceName) {
9417
9509
  }
9418
9510
  const updated = !pullOutput.includes("Already up to date");
9419
9511
  if (pullOutput.trim() && updated) warn(pullOutput.trim());
9420
- warn(updated ? `"${marketplaceName}" updated.` : `"${marketplaceName}" already up to date \u2014 no changes to sync.`);
9512
+ warn(updated ? `"${marketplaceName}" updated.` : `"${marketplaceName}" already up to date \u2014 refreshing installed plugins from the local clone.`);
9421
9513
  return { updated };
9422
9514
  }
9423
9515
  function installPluginsForMarketplace(marketplacePath, marketplaceName, repoUrl, pluginNames, targetDir) {
@@ -9467,13 +9559,6 @@ function installMarketplaceToTarget(m, marketplacePath, pluginChoices, pluginFil
9467
9559
  } else {
9468
9560
  requested = [pluginFilter];
9469
9561
  }
9470
- const missing = requested.filter((name) => !installedHere.includes(name));
9471
- if (!opts.updated && !opts.force) {
9472
- if (missing.length === 0) {
9473
- return { ...base, plugins: {}, total: 0, skipped: true, message: "No changes detected \u2014 skipping install. Use --force to reinstall anyway." };
9474
- }
9475
- requested = missing;
9476
- }
9477
9562
  const { results, totalInstalled } = installPluginsForMarketplace(marketplacePath, marketplaceName, m.repoUrl, requested, target.target);
9478
9563
  return { ...base, plugins: results, total: totalInstalled };
9479
9564
  }
@@ -10107,7 +10192,7 @@ Plugin skills always install at user scope. --agent picks the host (default: ${D
10107
10192
  fail(err, "skills", "marketplace-remove", start);
10108
10193
  }
10109
10194
  });
10110
- 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) => {
10195
+ 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", "Opt into the interactive picker instead of the installed-only shorthand (plugins are always refreshed from the local clone, with or without new upstream changes)").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) => {
10111
10196
  const start = Date.now();
10112
10197
  try {
10113
10198
  const configPath = getGlobalConfigPath();
@@ -10600,19 +10685,31 @@ function copyPluginSkills(skillsSrc, targetDir, meta) {
10600
10685
  (name) => fs6.statSync(path11.join(skillsSrc, name)).isDirectory()
10601
10686
  );
10602
10687
  const installed = [];
10688
+ const active = [];
10603
10689
  const failed = [];
10690
+ const disabledHere = meta ? readInstalledMeta(targetDir).disabled ?? {} : {};
10604
10691
  for (const skillName of skillNames) {
10605
10692
  const dest = path11.resolve(targetDir, skillName);
10606
10693
  if (!dest.startsWith(resolvedTarget + path11.sep)) {
10607
10694
  failed.push(skillName);
10608
10695
  continue;
10609
10696
  }
10697
+ const stashed = disabledHere[skillName];
10698
+ if (meta && stashed && stashed.plugin === meta.plugin) {
10699
+ const stashDest = path11.join(targetDir, DISABLED_SUBDIR, skillName);
10700
+ fs6.mkdirSync(path11.dirname(stashDest), { recursive: true });
10701
+ fs6.rmSync(stashDest, { recursive: true, force: true });
10702
+ fs6.cpSync(path11.join(skillsSrc, skillName), stashDest, { recursive: true });
10703
+ installed.push(skillName);
10704
+ continue;
10705
+ }
10610
10706
  fs6.rmSync(dest, { recursive: true, force: true });
10611
10707
  fs6.cpSync(path11.join(skillsSrc, skillName), dest, { recursive: true });
10612
10708
  installed.push(skillName);
10709
+ active.push(skillName);
10613
10710
  }
10614
10711
  if (meta) {
10615
- recordInstalledSkills(targetDir, installed, {
10712
+ recordInstalledSkills(targetDir, active, {
10616
10713
  source: "marketplace",
10617
10714
  marketplace: meta.marketplace,
10618
10715
  plugin: meta.plugin,
@@ -10911,6 +11008,16 @@ function registerConfigCommands(program2) {
10911
11008
  } else {
10912
11009
  results.logscale = { ok: null, message: "not configured" };
10913
11010
  }
11011
+ if (cfg.elasticsearch.baseUrl && cfg.elasticsearch.apiKey) {
11012
+ try {
11013
+ await http.elasticsearch("/_cluster/health");
11014
+ results.elasticsearch = { ok: true, message: "connected" };
11015
+ } catch (err) {
11016
+ results.elasticsearch = { ok: false, message: err instanceof Error ? err.message : String(err) };
11017
+ }
11018
+ } else {
11019
+ results.elasticsearch = { ok: null, message: "not configured" };
11020
+ }
10914
11021
  if (cfg.splitio.baseUrl && cfg.splitio.adminApiKey) {
10915
11022
  try {
10916
11023
  await http.splitio("/internal/api/v2/workspaces");
@@ -10995,6 +11102,7 @@ function registerConfigCommands(program2) {
10995
11102
  "dynatrace_platform",
10996
11103
  ...dynamicEnvKeys,
10997
11104
  "logscale",
11105
+ "elasticsearch",
10998
11106
  "splitio",
10999
11107
  "figma",
11000
11108
  "alation",
@@ -11550,6 +11658,40 @@ async function initGlobalConfig(start) {
11550
11658
  }
11551
11659
  }
11552
11660
  }
11661
+ process.stderr.write("\n\u2500\u2500 Elasticsearch \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n");
11662
+ const useElasticsearch = await confirm({
11663
+ message: "Configure Elasticsearch for log and document searches?",
11664
+ default: false
11665
+ });
11666
+ let elasticsearchBaseUrl = "";
11667
+ let elasticsearchApiKey = "";
11668
+ if (useElasticsearch) {
11669
+ elasticsearchBaseUrl = await input2({
11670
+ message: "Elasticsearch base URL (e.g. https://elasticsearch.imagile.dev:9200):",
11671
+ default: ""
11672
+ });
11673
+ elasticsearchApiKey = await password2({
11674
+ message: 'Elasticsearch API key (the base64 "encoded" value from Kibana \u2192 Stack Management \u2192 API keys):'
11675
+ });
11676
+ if (elasticsearchBaseUrl && elasticsearchApiKey) {
11677
+ process.stderr.write("\n Verifying connection...\n");
11678
+ try {
11679
+ const tempConfig = {
11680
+ ...loadConfig(),
11681
+ elasticsearch: {
11682
+ baseUrl: normalizeBaseUrl(elasticsearchBaseUrl),
11683
+ apiKey: elasticsearchApiKey
11684
+ }
11685
+ };
11686
+ const tempHttp = createHttpClient(tempConfig);
11687
+ await tempHttp.elasticsearch("/_cluster/health");
11688
+ process.stderr.write(" Connected.\n");
11689
+ } catch (err) {
11690
+ warn(`Could not connect to Elasticsearch: ${err instanceof Error ? err.message : String(err)}`);
11691
+ warn("Config will be saved anyway. Check your URL and API key and re-run pncli config init or pncli config test.");
11692
+ }
11693
+ }
11694
+ }
11553
11695
  process.stderr.write("\n\u2500\u2500 Split.IO \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n");
11554
11696
  const useSplitio = await confirm({
11555
11697
  message: "Configure Split.IO for feature flag administration?",
@@ -11847,6 +11989,12 @@ async function initGlobalConfig(start) {
11847
11989
  token: logscaleToken || void 0
11848
11990
  }
11849
11991
  } : {},
11992
+ ...useElasticsearch && elasticsearchBaseUrl ? {
11993
+ elasticsearch: {
11994
+ baseUrl: normalizeBaseUrl(elasticsearchBaseUrl),
11995
+ apiKey: elasticsearchApiKey || void 0
11996
+ }
11997
+ } : {},
11850
11998
  ...useSplitio && splitioBaseUrl ? {
11851
11999
  splitio: {
11852
12000
  baseUrl: normalizeBaseUrl(splitioBaseUrl),
@@ -12314,6 +12462,7 @@ function registerDoctorCommands(program2) {
12314
12462
 
12315
12463
  // src/services/ado/client/git.ts
12316
12464
  var API7 = "7.1";
12465
+ var REQUIRED_REVIEWERS_POLICY_TYPE = "fd2167ab-b0be-447a-8ec8-39368250530e";
12317
12466
  var AdoGitClient = class {
12318
12467
  constructor(http) {
12319
12468
  this.http = http;
@@ -12348,6 +12497,10 @@ var AdoGitClient = class {
12348
12497
  "searchCriteria.status": opts.status ?? "active",
12349
12498
  ...opts.creatorAlias ? { "searchCriteria.creatorId": opts.creatorAlias } : {},
12350
12499
  ...opts.reviewerAlias ? { "searchCriteria.reviewerId": opts.reviewerAlias } : {},
12500
+ // minTime/maxTime only take effect alongside queryTimeRangeType.
12501
+ ...opts.createdAfter || opts.createdBefore ? { "searchCriteria.queryTimeRangeType": "created" } : {},
12502
+ ...opts.createdAfter ? { "searchCriteria.minTime": opts.createdAfter.toISOString() } : {},
12503
+ ...opts.createdBefore ? { "searchCriteria.maxTime": opts.createdBefore.toISOString() } : {},
12351
12504
  "$top": pageSize,
12352
12505
  "$skip": skip
12353
12506
  };
@@ -12409,6 +12562,20 @@ var AdoGitClient = class {
12409
12562
  const pr = await this.getPR(collection, project, repo, prId);
12410
12563
  return pr.reviewers;
12411
12564
  }
12565
+ /**
12566
+ * Default reviewers in Azure DevOps are "Required reviewers" branch policies.
12567
+ * Returns the policy configurations of that type whose scope covers the repo
12568
+ * (a scope entry with a null repositoryId applies project-wide).
12569
+ */
12570
+ async listDefaultReviewers(collection, project, repo) {
12571
+ const repoInfo = await this.getRepo(collection, project, repo);
12572
+ const result = await this.http.ado(
12573
+ `/${encodeURIComponent(collection)}/${encodeURIComponent(project)}/_apis/policy/configurations?api-version=${API7}`
12574
+ );
12575
+ return (result.value ?? []).filter(
12576
+ (c) => c.type?.id === REQUIRED_REVIEWERS_POLICY_TYPE && (c.settings?.scope ?? []).some((s) => !s.repositoryId || s.repositoryId === repoInfo.id)
12577
+ );
12578
+ }
12412
12579
  // ── Threads / Comments ────────────────────────────────────────────
12413
12580
  async listThreads(collection, project, repo, prId) {
12414
12581
  const result = await this.http.ado(
@@ -13073,14 +13240,18 @@ function registerAdoRepoCommands(ado) {
13073
13240
  fail(err, "ado", "repo-get", start);
13074
13241
  }
13075
13242
  });
13076
- repo.command("list-prs").description("List pull requests").option("--state <state>", "PR state: active|abandoned|completed|all", "active").option("--creator <alias>", "Filter by creator").option("--reviewer <alias>", "Filter by reviewer").action(async (opts) => {
13243
+ repo.command("list-prs").description("List pull requests").option("--state <state>", "PR state: active|abandoned|completed|all", "active").option("--creator <alias>", "Filter by creator").option("--reviewer <alias>", "Filter by reviewer").option("--created-after <date>", "Only PRs created on/after this ISO 8601 date (e.g. 2025-01-31)").option("--created-before <date>", "Only PRs created before this ISO 8601 date").action(async (opts) => {
13077
13244
  const start = Date.now();
13078
13245
  try {
13246
+ const createdAfter = opts.createdAfter ? parseDateOption("--created-after", opts.createdAfter) : void 0;
13247
+ const createdBefore = opts.createdBefore ? parseDateOption("--created-before", opts.createdBefore) : void 0;
13079
13248
  const { collection, project, repo: repo2, gitClient } = getAdoContext(ado, true);
13080
13249
  const data = await gitClient.listPRs(collection, project, repo2, {
13081
13250
  status: opts.state,
13082
13251
  creatorAlias: opts.creator,
13083
- reviewerAlias: opts.reviewer
13252
+ reviewerAlias: opts.reviewer,
13253
+ createdAfter,
13254
+ createdBefore
13084
13255
  });
13085
13256
  success(data, "ado", "repo-list-prs", start);
13086
13257
  } catch (err) {
@@ -13301,16 +13472,26 @@ function registerAdoRepoCommands(ado) {
13301
13472
  fail(err, "ado", "repo-list-reviewers", start);
13302
13473
  }
13303
13474
  });
13475
+ repo.command("list-default-reviewers").description("List required-reviewer branch policies (default reviewers) that apply to the repository").action(async () => {
13476
+ const start = Date.now();
13477
+ try {
13478
+ const { collection, project, repo: repo2, gitClient } = getAdoContext(ado, true);
13479
+ const data = await gitClient.listDefaultReviewers(collection, project, repo2);
13480
+ success(data, "ado", "repo-list-default-reviewers", start);
13481
+ } catch (err) {
13482
+ fail(err, "ado", "repo-list-default-reviewers", start);
13483
+ }
13484
+ });
13304
13485
  const voteCmd = (name, description, vote, action) => {
13305
13486
  repo.command(name).description(description).requiredOption("--pr <n>", "Pull request ID").action(async (opts) => {
13306
13487
  const start = Date.now();
13307
13488
  try {
13308
13489
  const globalOpts = ado.optsWithGlobals();
13309
- const { loadConfig: lc } = await import("./config-5LC7ZTEP.js");
13490
+ const { loadConfig: lc } = await import("./config-DYIXSPLA.js");
13310
13491
  const config = lc({ configPath: globalOpts.config });
13311
13492
  const { collection, project, repo: repo2, gitClient } = getAdoContext(ado, true);
13312
13493
  const { AdoCoreClient: AdoCoreClient2 } = await import("./core-SWYVXOQ4.js");
13313
- const { createHttpClient: createHttpClient2 } = await import("./http-DJSGEGD6.js");
13494
+ const { createHttpClient: createHttpClient2 } = await import("./http-F24ORY6C.js");
13314
13495
  const http = createHttpClient2(config, Boolean(globalOpts.dryRun));
13315
13496
  const coreClient = new AdoCoreClient2(http);
13316
13497
  const me = await coreClient.getConnectionData(collection);
@@ -14498,6 +14679,55 @@ function registerOpenShiftCommands(program2) {
14498
14679
  fail(err, "openshift", "pods", start);
14499
14680
  }
14500
14681
  });
14682
+ oc.command("deployments").description("List Deployments (or OpenShift DeploymentConfigs with --deployment-configs) for a namespace, read-only. Use --raw to return the full unmodified objects.").requiredOption("--namespace <ns>", "Kubernetes namespace").option("--label-selector <selector>", "Label selector (e.g. app=my-app)").option("--deployment-configs", "Read OpenShift DeploymentConfigs (apps.openshift.io/v1) instead of Deployments (apps/v1)", false).option("--raw", "Return full objects without summarization (includes pod template, env vars, strategy, etc.)", false).action(async (opts) => {
14683
+ const start = Date.now();
14684
+ try {
14685
+ const http = getHttp2(oc);
14686
+ const params = {};
14687
+ if (opts.labelSelector) params["labelSelector"] = opts.labelSelector;
14688
+ const kind = opts.deploymentConfigs ? "DeploymentConfig" : "Deployment";
14689
+ const path14 = opts.deploymentConfigs ? `/apis/apps.openshift.io/v1/namespaces/${encodeURIComponent(opts.namespace)}/deploymentconfigs` : `/apis/apps/v1/namespaces/${encodeURIComponent(opts.namespace)}/deployments`;
14690
+ const list = await http.openshift(path14, { params });
14691
+ if (opts.raw) {
14692
+ success(
14693
+ { namespace: opts.namespace, kind, count: list.items.length, deployments: list.items },
14694
+ "openshift",
14695
+ "deployments",
14696
+ start
14697
+ );
14698
+ return;
14699
+ }
14700
+ const deployments = list.items.map((d) => {
14701
+ const desired = d.spec.replicas ?? 0;
14702
+ const status = d.status ?? {};
14703
+ const entry = {
14704
+ name: d.metadata.name,
14705
+ ready: `${status.readyReplicas ?? 0}/${desired}`,
14706
+ desiredReplicas: desired,
14707
+ readyReplicas: status.readyReplicas ?? 0,
14708
+ updatedReplicas: status.updatedReplicas ?? 0,
14709
+ availableReplicas: status.availableReplicas ?? 0,
14710
+ unavailableReplicas: status.unavailableReplicas ?? 0,
14711
+ age: podAge(d.metadata.creationTimestamp),
14712
+ images: (d.spec.template?.spec?.containers ?? []).map((c) => ({ name: c.name, image: c.image }))
14713
+ };
14714
+ if (d.spec.strategy?.type) entry["strategy"] = d.spec.strategy.type;
14715
+ if (status.latestVersion !== void 0) entry["latestVersion"] = status.latestVersion;
14716
+ const problems = (status.conditions ?? []).filter(
14717
+ (c) => c.type === "Available" && c.status === "False" || c.type === "Progressing" && c.status === "False" || c.type === "ReplicaFailure"
14718
+ );
14719
+ if (problems.length > 0) {
14720
+ entry["conditions"] = problems.map((c) => ({ type: c.type, status: c.status, reason: c.reason, message: c.message }));
14721
+ }
14722
+ if (d.metadata.labels && Object.keys(d.metadata.labels).length > 0) entry["labels"] = d.metadata.labels;
14723
+ return entry;
14724
+ });
14725
+ deployments.sort((a, b) => (b["unavailableReplicas"] ?? 0) - (a["unavailableReplicas"] ?? 0));
14726
+ success({ namespace: opts.namespace, kind, count: deployments.length, deployments }, "openshift", "deployments", start);
14727
+ } catch (err) {
14728
+ fail(err, "openshift", "deployments", start);
14729
+ }
14730
+ });
14501
14731
  oc.command("events").description("List Warning events for a namespace \u2014 pre-filtered for LLM analysis").requiredOption("--namespace <ns>", "Kubernetes namespace").option("--field-selector <selector>", "Additional field selector (e.g. involvedObject.name=my-pod)").option("--all", "Include Normal events in addition to Warning events", false).action(async (opts) => {
14502
14732
  const start = Date.now();
14503
14733
  try {
@@ -14922,10 +15152,121 @@ function registerLogscaleCommands(program2) {
14922
15152
  });
14923
15153
  }
14924
15154
 
15155
+ // src/services/elasticsearch/commands.ts
15156
+ function getHttp5(program2) {
15157
+ const opts = program2.optsWithGlobals();
15158
+ return createHttpClient(
15159
+ loadConfig({ configPath: opts.config }),
15160
+ Boolean(opts.dryRun)
15161
+ );
15162
+ }
15163
+ function parseJsonOption(raw, flag) {
15164
+ let parsed;
15165
+ try {
15166
+ parsed = JSON.parse(raw);
15167
+ } catch {
15168
+ throw new PncliError(`${flag} must be valid JSON. Example: ${flag} '{"match_all":{}}'`);
15169
+ }
15170
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
15171
+ throw new PncliError(`${flag} must be a JSON object.`);
15172
+ }
15173
+ return parsed;
15174
+ }
15175
+ function parsePositiveInt(raw, flag) {
15176
+ const n = Number(raw);
15177
+ if (!Number.isInteger(n) || n < 0) throw new PncliError(`${flag} must be a non-negative integer.`);
15178
+ return n;
15179
+ }
15180
+ function indexPath(index) {
15181
+ return index.split(",").map((s) => encodeURIComponent(s.trim())).join(",");
15182
+ }
15183
+ function buildQuery(opts) {
15184
+ if (opts.query && opts.q) throw new PncliError("Use either --query or --q, not both.");
15185
+ if (opts.query) return parseJsonOption(opts.query, "--query");
15186
+ if (opts.q) return { query_string: { query: opts.q } };
15187
+ return { match_all: {} };
15188
+ }
15189
+ function registerElasticsearchCommands(program2) {
15190
+ const es = program2.command("elasticsearch").description("Elasticsearch search operations");
15191
+ const cluster = es.command("cluster").description("Cluster operations");
15192
+ cluster.command("health").description("Show cluster health (status, node and shard counts)").action(async () => {
15193
+ const start = Date.now();
15194
+ try {
15195
+ const data = await getHttp5(program2).elasticsearch("/_cluster/health");
15196
+ success(data, "elasticsearch", "cluster health", start);
15197
+ } catch (err) {
15198
+ fail(err, "elasticsearch", "cluster health", start);
15199
+ }
15200
+ });
15201
+ const indices = es.command("indices").description("Index operations");
15202
+ indices.command("list").description("List indices with health, document count and size").option("--pattern <pattern>", 'Index name or wildcard pattern (e.g. "logs-*")').action(async (opts) => {
15203
+ const start = Date.now();
15204
+ try {
15205
+ const path14 = opts.pattern ? `/_cat/indices/${indexPath(opts.pattern)}` : "/_cat/indices";
15206
+ const data = await getHttp5(program2).elasticsearch(path14, {
15207
+ params: { format: "json", h: "index,health,status,docs.count,store.size,pri,rep" }
15208
+ });
15209
+ success({ count: data.length, indices: data }, "elasticsearch", "indices list", start);
15210
+ } catch (err) {
15211
+ fail(err, "elasticsearch", "indices list", start);
15212
+ }
15213
+ });
15214
+ es.command("search").description("Search one or more indices with Query DSL JSON or a query string").requiredOption("--index <name>", "Index, data stream, alias or wildcard pattern; comma-separate several").option("--query <json>", `Query DSL clause as JSON (e.g. '{"match":{"message":"error"}}')`).option("--q <query-string>", 'Lucene query string (e.g. "level:error AND service:api")').option("--sort <field:order>", 'Sort, e.g. "@timestamp:desc"').option("--source <fields>", "Comma-separated fields to return (_source filtering)").option("--size <n>", "Maximum number of hits to return", "100").option("--from <n>", "Offset of the first hit", "0").option("--timeout-ms <ms>", "Client-side HTTP timeout in milliseconds", "30000").action(async (opts) => {
15215
+ const ts = Date.now();
15216
+ try {
15217
+ const body = {
15218
+ query: buildQuery(opts),
15219
+ size: parsePositiveInt(opts.size, "--size"),
15220
+ from: parsePositiveInt(opts.from, "--from")
15221
+ };
15222
+ if (opts.sort) {
15223
+ const [field, order] = opts.sort.split(":");
15224
+ body.sort = [{ [field]: { order: order ?? "asc" } }];
15225
+ }
15226
+ if (opts.source) body._source = opts.source.split(",").map((s) => s.trim()).filter(Boolean);
15227
+ const data = await getHttp5(program2).elasticsearch(
15228
+ `/${indexPath(opts.index)}/_search`,
15229
+ { method: "POST", body, timeoutMs: parsePositiveInt(opts.timeoutMs, "--timeout-ms") }
15230
+ );
15231
+ const total = data.hits?.total;
15232
+ const hits = data.hits?.hits ?? [];
15233
+ success(
15234
+ {
15235
+ index: opts.index,
15236
+ took: data.took,
15237
+ timedOut: data.timed_out ?? false,
15238
+ total: typeof total === "object" ? total?.value : total,
15239
+ totalRelation: typeof total === "object" ? total?.relation : void 0,
15240
+ hitCount: hits.length,
15241
+ hits,
15242
+ aggregations: data.aggregations
15243
+ },
15244
+ "elasticsearch",
15245
+ "search",
15246
+ ts
15247
+ );
15248
+ } catch (err) {
15249
+ fail(err, "elasticsearch", "search", ts);
15250
+ }
15251
+ });
15252
+ es.command("count").description("Count documents matching a query").requiredOption("--index <name>", "Index, data stream, alias or wildcard pattern; comma-separate several").option("--query <json>", "Query DSL clause as JSON").option("--q <query-string>", "Lucene query string").action(async (opts) => {
15253
+ const start = Date.now();
15254
+ try {
15255
+ const data = await getHttp5(program2).elasticsearch(
15256
+ `/${indexPath(opts.index)}/_count`,
15257
+ { method: "POST", body: { query: buildQuery(opts) } }
15258
+ );
15259
+ success({ index: opts.index, count: data.count }, "elasticsearch", "count", start);
15260
+ } catch (err) {
15261
+ fail(err, "elasticsearch", "count", start);
15262
+ }
15263
+ });
15264
+ }
15265
+
14925
15266
  // src/services/splitio/commands.ts
14926
15267
  import fs11 from "fs";
14927
15268
  import confirm2 from "@inquirer/confirm";
14928
- function getHttp5(program2) {
15269
+ function getHttp6(program2) {
14929
15270
  const opts = program2.optsWithGlobals();
14930
15271
  return createHttpClient(
14931
15272
  loadConfig({ configPath: opts.config }),
@@ -14970,7 +15311,7 @@ function registerSplitioCommands(program2) {
14970
15311
  workspaces.command("list").description("List all Split.IO workspaces").action(async () => {
14971
15312
  const start = Date.now();
14972
15313
  try {
14973
- const http = getHttp5(program2);
15314
+ const http = getHttp6(program2);
14974
15315
  const data = await http.splitio("/internal/api/v2/workspaces");
14975
15316
  success(
14976
15317
  { count: data.objects.length, workspaces: data.objects },
@@ -14986,7 +15327,7 @@ function registerSplitioCommands(program2) {
14986
15327
  environments.command("list").description("List environments in a workspace").requiredOption("--workspace <id>", "Workspace ID").action(async (opts) => {
14987
15328
  const start = Date.now();
14988
15329
  try {
14989
- const http = getHttp5(program2);
15330
+ const http = getHttp6(program2);
14990
15331
  const data = await http.splitio(
14991
15332
  `/internal/api/v2/environments/ws/${encodeURIComponent(opts.workspace)}`
14992
15333
  );
@@ -15004,7 +15345,7 @@ function registerSplitioCommands(program2) {
15004
15345
  flags.command("list").description("List feature flags in a workspace").requiredOption("--workspace <id>", "Workspace ID").option("--limit <n>", "Maximum number of flags to return", "50").option("--offset <n>", "Pagination offset", "0").option("--flag-set <name>", "Filter by flag set name").action(async (opts) => {
15005
15346
  const start = Date.now();
15006
15347
  try {
15007
- const http = getHttp5(program2);
15348
+ const http = getHttp6(program2);
15008
15349
  const params = {
15009
15350
  limit: parseInt(opts.limit, 10),
15010
15351
  offset: parseInt(opts.offset, 10)
@@ -15027,7 +15368,7 @@ function registerSplitioCommands(program2) {
15027
15368
  flags.command("get").description("Get a flag definition").requiredOption("--workspace <id>", "Workspace ID").requiredOption("--flag <name>", "Feature flag name").option("--environment <id>", "Environment ID \u2014 include targeting rules for this environment").action(async (opts) => {
15028
15369
  const start = Date.now();
15029
15370
  try {
15030
- const http = getHttp5(program2);
15371
+ const http = getHttp6(program2);
15031
15372
  if (opts.environment) {
15032
15373
  const data = await http.splitio(
15033
15374
  `/internal/api/v2/splits/ws/${encodeURIComponent(opts.workspace)}/name/${encodeURIComponent(opts.flag)}/environment/${encodeURIComponent(opts.environment)}`
@@ -15049,7 +15390,7 @@ function registerSplitioCommands(program2) {
15049
15390
  if (!opts.inputFile) throw new PncliError("--input-file is required for flags update");
15050
15391
  const definition = loadInputFile(opts.inputFile);
15051
15392
  await confirmWrite(opts, `UPDATE ${opts.flag} in ${opts.environment}`);
15052
- const http = getHttp5(program2);
15393
+ const http = getHttp6(program2);
15053
15394
  const body = {
15054
15395
  ...buildCrBase(opts),
15055
15396
  operationType: "UPDATE_SPLIT_DEFINITION",
@@ -15075,7 +15416,7 @@ function registerSplitioCommands(program2) {
15075
15416
  if (!opts.treatment && !opts.weights) {
15076
15417
  throw new PncliError("Either --treatment or --weights must be specified");
15077
15418
  }
15078
- const http = getHttp5(program2);
15419
+ const http = getHttp6(program2);
15079
15420
  const current = await http.splitio(
15080
15421
  `/internal/api/v2/splits/ws/${encodeURIComponent(opts.workspace)}/name/${encodeURIComponent(opts.flag)}/environment/${encodeURIComponent(opts.environment)}`
15081
15422
  );
@@ -15113,7 +15454,7 @@ function registerSplitioCommands(program2) {
15113
15454
  flags.command("set-default").description("Update the fallback default rule for traffic matching no targeting rule").requiredOption("--workspace <id>", "Workspace ID").requiredOption("--flag <name>", "Feature flag name").requiredOption("--environment <id>", "Environment ID").requiredOption("--treatment <name>", "Treatment to assign as the default").requiredOption("--mnemonic <text>", "Short Change Request title (mnemonic)").requiredOption("--description <text>", "Change Request description").requiredOption("--change-number <CHG>", "Change request number (e.g. CHG0001234)").option("--approvers <ids>", "Comma-separated Split user IDs required to approve this CR").option("--yes", "Skip interactive confirmation prompt").action(async (opts) => {
15114
15455
  const start = Date.now();
15115
15456
  try {
15116
- const http = getHttp5(program2);
15457
+ const http = getHttp6(program2);
15117
15458
  const current = await http.splitio(
15118
15459
  `/internal/api/v2/splits/ws/${encodeURIComponent(opts.workspace)}/name/${encodeURIComponent(opts.flag)}/environment/${encodeURIComponent(opts.environment)}`
15119
15460
  );
@@ -15146,7 +15487,7 @@ function registerSplitioCommands(program2) {
15146
15487
  const enable = opts.enabled.toLowerCase() !== "false" && opts.enabled !== "0";
15147
15488
  const opType = enable ? "RESTORE_SPLIT" : "KILL_SPLIT";
15148
15489
  await confirmWrite(opts, `${opType} ${opts.flag} in ${opts.environment}`);
15149
- const http = getHttp5(program2);
15490
+ const http = getHttp6(program2);
15150
15491
  const body = {
15151
15492
  ...buildCrBase(opts),
15152
15493
  operationType: opType,
@@ -15169,7 +15510,7 @@ function registerSplitioCommands(program2) {
15169
15510
  const entries = loadInputFile(opts.inputFile);
15170
15511
  if (!Array.isArray(entries)) throw new PncliError("Input file must be a JSON array of {flag, enabled} objects");
15171
15512
  await confirmWrite(opts, `BATCH_TOGGLE ${entries.length} flags in ${opts.environment}`);
15172
- const http = getHttp5(program2);
15513
+ const http = getHttp6(program2);
15173
15514
  const results = [];
15174
15515
  for (const entry of entries) {
15175
15516
  try {
@@ -15203,7 +15544,7 @@ function registerSplitioCommands(program2) {
15203
15544
  const start = Date.now();
15204
15545
  try {
15205
15546
  await confirmWrite(opts, `KILL ${opts.flag} in ${opts.environment}`);
15206
- const http = getHttp5(program2);
15547
+ const http = getHttp6(program2);
15207
15548
  const body = {
15208
15549
  ...buildCrBase(opts),
15209
15550
  operationType: "KILL_SPLIT",
@@ -15223,7 +15564,7 @@ function registerSplitioCommands(program2) {
15223
15564
  const start = Date.now();
15224
15565
  try {
15225
15566
  await confirmWrite(opts, `RESTORE ${opts.flag} in ${opts.environment}`);
15226
- const http = getHttp5(program2);
15567
+ const http = getHttp6(program2);
15227
15568
  const body = {
15228
15569
  ...buildCrBase(opts),
15229
15570
  operationType: "RESTORE_SPLIT",
@@ -15243,7 +15584,7 @@ function registerSplitioCommands(program2) {
15243
15584
  const start = Date.now();
15244
15585
  try {
15245
15586
  await confirmWrite(opts, `ARCHIVE ${opts.flag}`);
15246
- const http = getHttp5(program2);
15587
+ const http = getHttp6(program2);
15247
15588
  const body = {
15248
15589
  ...buildCrBase(opts),
15249
15590
  operationType: "ARCHIVE_SPLIT",
@@ -15263,7 +15604,7 @@ function registerSplitioCommands(program2) {
15263
15604
  changeRequests.command("list").description("List Change Requests for a workspace").requiredOption("--workspace <id>", "Workspace ID").option("--environment <id>", "Filter by environment ID").option("--status <status>", "Filter by status (REQUESTED, APPROVED, REJECTED, PUBLISHED)").option("--limit <n>", "Maximum number of results", "25").option("--offset <n>", "Pagination offset", "0").action(async (opts) => {
15264
15605
  const start = Date.now();
15265
15606
  try {
15266
- const http = getHttp5(program2);
15607
+ const http = getHttp6(program2);
15267
15608
  const params = {
15268
15609
  limit: parseInt(opts.limit, 10),
15269
15610
  offset: parseInt(opts.offset, 10)
@@ -15287,7 +15628,7 @@ function registerSplitioCommands(program2) {
15287
15628
  changeRequests.command("get").description("Get a Change Request by ID").requiredOption("--id <id>", "Change Request ID").action(async (opts) => {
15288
15629
  const start = Date.now();
15289
15630
  try {
15290
- const http = getHttp5(program2);
15631
+ const http = getHttp6(program2);
15291
15632
  const data = await http.splitio(
15292
15633
  `/internal/api/v2/changeRequests/${encodeURIComponent(opts.id)}`
15293
15634
  );
@@ -15339,7 +15680,7 @@ function findNodeIdInUrl(url) {
15339
15680
  if (!new URL(url).searchParams.has("node-id")) return void 0;
15340
15681
  return parseNodeId(url);
15341
15682
  }
15342
- function getHttp6(program2) {
15683
+ function getHttp7(program2) {
15343
15684
  const opts = program2.optsWithGlobals();
15344
15685
  return createHttpClient(
15345
15686
  loadConfig({ configPath: opts.config }),
@@ -15350,12 +15691,12 @@ function registerFigmaCommands(program2) {
15350
15691
  const figma = program2.command("figma").description("Figma design operations (files, comments, versions)");
15351
15692
  figma.command("file").description("Get a Figma file \u2014 metadata, structure, and component/style inventory (or a single node with --node-id)").argument("<file-key-or-url>", "Figma file key or full Figma URL (https://www.figma.com/design/<key>/...); a node-id query param is auto-detected").option("--document", "Include the full document node tree (can be large; omitted by default)").option("--node-id <id>", "Fetch only this node and its descendants instead of the whole file (overrides any node-id detected in the URL)").action(async (fileKeyOrUrl, opts) => {
15352
15693
  const start = Date.now();
15353
- const { success: success2, fail: fail2 } = await import("./output-HDUIIXUI.js");
15694
+ const { success: success2, fail: fail2 } = await import("./output-XE6XDAAR.js");
15354
15695
  try {
15355
15696
  const fileKey = parseFileKey(fileKeyOrUrl);
15356
15697
  const nodeId = opts.nodeId ? parseNodeId(opts.nodeId) : isUrl(fileKeyOrUrl) ? findNodeIdInUrl(fileKeyOrUrl) : void 0;
15357
15698
  if (nodeId) {
15358
- const data2 = await getHttp6(program2).figma(
15699
+ const data2 = await getHttp7(program2).figma(
15359
15700
  `/v1/files/${encodeURIComponent(fileKey)}/nodes`,
15360
15701
  { params: { ids: nodeId } }
15361
15702
  );
@@ -15384,7 +15725,7 @@ function registerFigmaCommands(program2) {
15384
15725
  if (!opts.document) {
15385
15726
  params["depth"] = 1;
15386
15727
  }
15387
- const data = await getHttp6(program2).figma(`/v1/files/${encodeURIComponent(fileKey)}`, { params });
15728
+ const data = await getHttp7(program2).figma(`/v1/files/${encodeURIComponent(fileKey)}`, { params });
15388
15729
  success2(
15389
15730
  {
15390
15731
  fileKey,
@@ -15409,12 +15750,12 @@ function registerFigmaCommands(program2) {
15409
15750
  });
15410
15751
  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) => {
15411
15752
  const start = Date.now();
15412
- const { success: success2, fail: fail2 } = await import("./output-HDUIIXUI.js");
15753
+ const { success: success2, fail: fail2 } = await import("./output-XE6XDAAR.js");
15413
15754
  try {
15414
15755
  const fileKey = parseFileKey(fileKeyOrUrl);
15415
15756
  const params = {};
15416
15757
  if (opts.asOf) params["as_of"] = opts.asOf;
15417
- const data = await getHttp6(program2).figma(`/v1/files/${encodeURIComponent(fileKey)}/comments`, { params });
15758
+ const data = await getHttp7(program2).figma(`/v1/files/${encodeURIComponent(fileKey)}/comments`, { params });
15418
15759
  success2(
15419
15760
  { fileKey, count: data.comments.length, comments: data.comments },
15420
15761
  "figma",
@@ -15427,10 +15768,10 @@ function registerFigmaCommands(program2) {
15427
15768
  });
15428
15769
  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) => {
15429
15770
  const start = Date.now();
15430
- const { success: success2, fail: fail2 } = await import("./output-HDUIIXUI.js");
15771
+ const { success: success2, fail: fail2 } = await import("./output-XE6XDAAR.js");
15431
15772
  try {
15432
15773
  const fileKey = parseFileKey(fileKeyOrUrl);
15433
- const data = await getHttp6(program2).figma(`/v1/files/${encodeURIComponent(fileKey)}/versions`);
15774
+ const data = await getHttp7(program2).figma(`/v1/files/${encodeURIComponent(fileKey)}/versions`);
15434
15775
  success2(
15435
15776
  { fileKey, count: data.versions.length, versions: data.versions },
15436
15777
  "figma",
@@ -15443,9 +15784,9 @@ function registerFigmaCommands(program2) {
15443
15784
  });
15444
15785
  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) => {
15445
15786
  const start = Date.now();
15446
- const { success: success2, fail: fail2 } = await import("./output-HDUIIXUI.js");
15787
+ const { success: success2, fail: fail2 } = await import("./output-XE6XDAAR.js");
15447
15788
  try {
15448
- const data = await getHttp6(program2).figma(`/v1/projects/${encodeURIComponent(projectId)}/files`);
15789
+ const data = await getHttp7(program2).figma(`/v1/projects/${encodeURIComponent(projectId)}/files`);
15449
15790
  success2(
15450
15791
  { projectId, count: data.files.length, files: data.files },
15451
15792
  "figma",
@@ -15458,9 +15799,9 @@ function registerFigmaCommands(program2) {
15458
15799
  });
15459
15800
  figma.command("me").description("Get the current Figma user (useful for verifying credentials)").action(async () => {
15460
15801
  const start = Date.now();
15461
- const { success: success2, fail: fail2 } = await import("./output-HDUIIXUI.js");
15802
+ const { success: success2, fail: fail2 } = await import("./output-XE6XDAAR.js");
15462
15803
  try {
15463
- const data = await getHttp6(program2).figma("/v1/me");
15804
+ const data = await getHttp7(program2).figma("/v1/me");
15464
15805
  success2(data, "figma", "me", start);
15465
15806
  } catch (err) {
15466
15807
  fail2(err, "figma", "me", start);
@@ -15575,7 +15916,7 @@ var ALATION_DOCUMENT_INPUT_FILE_EXAMPLE = {
15575
15916
  template: 7,
15576
15917
  fields: { "10001": "Team Data Platform" }
15577
15918
  };
15578
- function getHttp7(program2) {
15919
+ function getHttp8(program2) {
15579
15920
  const opts = program2.optsWithGlobals();
15580
15921
  return createHttpClient(
15581
15922
  loadConfig({ configPath: opts.config }),
@@ -15651,7 +15992,7 @@ function registerAlationCommands(program2) {
15651
15992
  const params = {};
15652
15993
  if (opts.includeUndeployed) params.include_undeployed = true;
15653
15994
  if (opts.includeHidden) params.include_hidden = true;
15654
- const data = await getHttp7(program2).alation("integration/v1/datasource/", { params });
15995
+ const data = await getHttp8(program2).alation("integration/v1/datasource/", { params });
15655
15996
  success({ count: data.length, datasources: data }, "alation", "datasource-list", start);
15656
15997
  } catch (err) {
15657
15998
  fail(err, "alation", "datasource-list", start);
@@ -15661,7 +16002,7 @@ function registerAlationCommands(program2) {
15661
16002
  const start = Date.now();
15662
16003
  try {
15663
16004
  const dsId = parsePositiveId(id2, "data source ID");
15664
- const data = await getHttp7(program2).alation(`integration/v1/datasource/${dsId}/`);
16005
+ const data = await getHttp8(program2).alation(`integration/v1/datasource/${dsId}/`);
15665
16006
  success(data, "alation", "datasource-get", start);
15666
16007
  } catch (err) {
15667
16008
  fail(err, "alation", "datasource-get", start);
@@ -15674,7 +16015,7 @@ function registerAlationCommands(program2) {
15674
16015
  const params = { ...pageParams(opts) };
15675
16016
  if (opts.ds) params.ds_id = parsePositiveId(opts.ds, "--ds");
15676
16017
  if (opts.name) params.name = opts.name;
15677
- const data = await getHttp7(program2).alation("integration/v2/schema/", { params });
16018
+ const data = await getHttp8(program2).alation("integration/v2/schema/", { params });
15678
16019
  success({ count: data.length, limit: params.limit, skip: params.skip, schemas: data }, "alation", "schema-list", start);
15679
16020
  } catch (err) {
15680
16021
  fail(err, "alation", "schema-list", start);
@@ -15683,7 +16024,7 @@ function registerAlationCommands(program2) {
15683
16024
  schema.command("get").description("Get a schema by ID").argument("<id>", "Schema ID").action(async (id2) => {
15684
16025
  const start = Date.now();
15685
16026
  try {
15686
- const data = await getOne(getHttp7(program2), "integration/v2/schema/", parsePositiveId(id2, "schema ID"), "Schema");
16027
+ const data = await getOne(getHttp8(program2), "integration/v2/schema/", parsePositiveId(id2, "schema ID"), "Schema");
15687
16028
  success(data, "alation", "schema-get", start);
15688
16029
  } catch (err) {
15689
16030
  fail(err, "alation", "schema-get", start);
@@ -15699,7 +16040,7 @@ function registerAlationCommands(program2) {
15699
16040
  if (opts.schemaName) params.schema_name = opts.schemaName;
15700
16041
  if (opts.name) params.name = opts.name;
15701
16042
  if (opts.search) params.name__icontains = opts.search;
15702
- const data = await getHttp7(program2).alation("integration/v2/table/", { params });
16043
+ const data = await getHttp8(program2).alation("integration/v2/table/", { params });
15703
16044
  success({ count: data.length, limit: params.limit, skip: params.skip, tables: data }, "alation", "table-list", start);
15704
16045
  } catch (err) {
15705
16046
  fail(err, "alation", "table-list", start);
@@ -15708,7 +16049,7 @@ function registerAlationCommands(program2) {
15708
16049
  table.command("get").description("Get a table by ID, optionally with its columns").argument("<id>", "Table ID").option("--columns", "Also fetch the table's columns (up to 1000)").action(async (id2, opts) => {
15709
16050
  const start = Date.now();
15710
16051
  try {
15711
- const http = getHttp7(program2);
16052
+ const http = getHttp8(program2);
15712
16053
  const tableId = parsePositiveId(id2, "table ID");
15713
16054
  const data = await getOne(http, "integration/v2/table/", tableId, "Table");
15714
16055
  if (opts.columns) {
@@ -15737,7 +16078,7 @@ function registerAlationCommands(program2) {
15737
16078
  if (opts.ds) params.ds_id = parsePositiveId(opts.ds, "--ds");
15738
16079
  if (opts.name) params.name = opts.name;
15739
16080
  if (opts.search) params.name__icontains = opts.search;
15740
- const data = await getHttp7(program2).alation("integration/v2/column/", { params });
16081
+ const data = await getHttp8(program2).alation("integration/v2/column/", { params });
15741
16082
  success({ count: data.length, limit: params.limit, skip: params.skip, columns: data }, "alation", "column-list", start);
15742
16083
  } catch (err) {
15743
16084
  fail(err, "alation", "column-list", start);
@@ -15746,7 +16087,7 @@ function registerAlationCommands(program2) {
15746
16087
  column.command("get").description("Get a column by ID").argument("<id>", "Column ID").action(async (id2) => {
15747
16088
  const start = Date.now();
15748
16089
  try {
15749
- const data = await getOne(getHttp7(program2), "integration/v2/column/", parsePositiveId(id2, "column ID"), "Column");
16090
+ const data = await getOne(getHttp8(program2), "integration/v2/column/", parsePositiveId(id2, "column ID"), "Column");
15750
16091
  success(data, "alation", "column-get", start);
15751
16092
  } catch (err) {
15752
16093
  fail(err, "alation", "column-get", start);
@@ -15761,7 +16102,7 @@ function registerAlationCommands(program2) {
15761
16102
  const params = { q: query, limit, offset };
15762
16103
  const otypes = parseOtypes(opts.otype);
15763
16104
  if (otypes) params.filters = JSON.stringify({ otypes });
15764
- const data = await getHttp7(program2).alation("integration/v1/search/", { params });
16105
+ const data = await getHttp8(program2).alation("integration/v1/search/", { params });
15765
16106
  success(
15766
16107
  { query, total: data.total, limit: data.limit, offset: data.offset, fullSearchUrl: data.full_search_url, results: data.results },
15767
16108
  "alation",
@@ -15780,7 +16121,7 @@ function registerAlationCommands(program2) {
15780
16121
  if (opts.hub) params.document_hub_id = parsePositiveId(opts.hub, "--hub");
15781
16122
  if (opts.parent) params.parent_folder_id = parsePositiveId(opts.parent, "--parent");
15782
16123
  if (opts.search) params.search = opts.search;
15783
- const data = await getHttp7(program2).alation("integration/v2/folder/", { params });
16124
+ const data = await getHttp8(program2).alation("integration/v2/folder/", { params });
15784
16125
  success({ count: data.length, limit: params.limit, skip: params.skip, folders: data }, "alation", "folder-list", start);
15785
16126
  } catch (err) {
15786
16127
  fail(err, "alation", "folder-list", start);
@@ -15789,7 +16130,7 @@ function registerAlationCommands(program2) {
15789
16130
  folder.command("get").description("Get a Document Hub folder by ID").argument("<id>", "Folder ID").action(async (id2) => {
15790
16131
  const start = Date.now();
15791
16132
  try {
15792
- const data = await getOne(getHttp7(program2), "integration/v2/folder/", parsePositiveId(id2, "folder ID"), "Folder");
16133
+ const data = await getOne(getHttp8(program2), "integration/v2/folder/", parsePositiveId(id2, "folder ID"), "Folder");
15793
16134
  success(data, "alation", "folder-get", start);
15794
16135
  } catch (err) {
15795
16136
  fail(err, "alation", "folder-get", start);
@@ -15805,7 +16146,7 @@ function registerAlationCommands(program2) {
15805
16146
  if (opts.parentDocument) params.parent_document_id = parsePositiveId(opts.parentDocument, "--parent-document");
15806
16147
  if (opts.search) params.search = opts.search;
15807
16148
  if (opts.deleted) params.deleted = true;
15808
- const data = await getHttp7(program2).alation("integration/v2/document/", { params });
16149
+ const data = await getHttp8(program2).alation("integration/v2/document/", { params });
15809
16150
  success({ count: data.length, limit: params.limit, skip: params.skip, documents: data }, "alation", "document-list", start);
15810
16151
  } catch (err) {
15811
16152
  fail(err, "alation", "document-list", start);
@@ -15814,7 +16155,7 @@ function registerAlationCommands(program2) {
15814
16155
  document.command("get").description("Get a document by ID, including its custom field values").argument("<id>", "Document ID").action(async (id2) => {
15815
16156
  const start = Date.now();
15816
16157
  try {
15817
- const data = await getOne(getHttp7(program2), "integration/v2/document/", parsePositiveId(id2, "document ID"), "Document");
16158
+ const data = await getOne(getHttp8(program2), "integration/v2/document/", parsePositiveId(id2, "document ID"), "Document");
15818
16159
  success(data, "alation", "document-get", start);
15819
16160
  } catch (err) {
15820
16161
  fail(err, "alation", "document-get", start);
@@ -15835,7 +16176,7 @@ function registerAlationCommands(program2) {
15835
16176
  for (const [key, flag] of [["title", "--title"], ["document_hub_id", "--hub"], ["parent_folder_id", "--folder"]]) {
15836
16177
  if (payload[key] === void 0) throw new PncliError(`${flag} is required to create a document (or set it in --input-file)`, 1);
15837
16178
  }
15838
- const data = await getHttp7(program2).alation("integration/v2/document/", { method: "POST", body: [payload] });
16179
+ const data = await getHttp8(program2).alation("integration/v2/document/", { method: "POST", body: [payload] });
15839
16180
  success({ jobId: data.job_id, document: payload, ...overrides.length ? { overrides } : {} }, "alation", "document-create", start);
15840
16181
  } catch (err) {
15841
16182
  fail(err, "alation", "document-create", start);
@@ -15853,7 +16194,7 @@ function registerAlationCommands(program2) {
15853
16194
  throw new PncliError("Nothing to update. Pass --title, --description, --folder, or --input-file.", 1);
15854
16195
  }
15855
16196
  const body = [{ id: documentId, ...payload }];
15856
- const data = await getHttp7(program2).alation("integration/v2/document/", { method: "PUT", body });
16197
+ const data = await getHttp8(program2).alation("integration/v2/document/", { method: "PUT", body });
15857
16198
  success({ jobId: data.job_id, document: body[0], ...overrides.length ? { overrides } : {} }, "alation", "document-update", start);
15858
16199
  } catch (err) {
15859
16200
  fail(err, "alation", "document-update", start);
@@ -15864,7 +16205,7 @@ function registerAlationCommands(program2) {
15864
16205
  const start = Date.now();
15865
16206
  try {
15866
16207
  const jobId = parsePositiveId(id2, "job ID");
15867
- const data = await getHttp7(program2).alation("api/v1/bulk_metadata/job/", { params: { id: jobId } });
16208
+ const data = await getHttp8(program2).alation("api/v1/bulk_metadata/job/", { params: { id: jobId } });
15868
16209
  success({ jobId, ...data }, "alation", "job-get", start);
15869
16210
  } catch (err) {
15870
16211
  fail(err, "alation", "job-get", start);
@@ -15913,6 +16254,7 @@ registerJwtCommands(program);
15913
16254
  registerOpenShiftCommands(program);
15914
16255
  registerDynatraceCommands(program);
15915
16256
  registerLogscaleCommands(program);
16257
+ registerElasticsearchCommands(program);
15916
16258
  registerSplitioCommands(program);
15917
16259
  registerFigmaCommands(program);
15918
16260
  registerAlationCommands(program);
@@ -15933,9 +16275,10 @@ Services:
15933
16275
  checkmarx Checkmarx One (projects, scans, scan statistics)
15934
16276
  contrast Contrast IAST (applications, vulnerability findings, libraries)
15935
16277
  sonatypeiq Sonatype IQ Server (applications, organizations, policies)
15936
- openshift OpenShift / Kubernetes (pods, events, logs, metrics)
16278
+ openshift OpenShift / Kubernetes (pods, deployments, events, logs, metrics)
15937
16279
  dynatrace Dynatrace (services, entities, problems, traces, Kubernetes workloads)
15938
16280
  logscale LogScale (log query, repositories)
16281
+ elasticsearch Elasticsearch (search, count, indices, cluster health)
15939
16282
  splitio Split.IO (feature flags, Change Requests)
15940
16283
  figma Figma (files, comments, version history)
15941
16284
  alation Alation (data sources, schemas, tables, columns, search, Document Hubs)