@kolatts/pncli 6.1.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.
@@ -74,6 +74,7 @@ function success(data, service, action, startTime, overrides) {
74
74
  }
75
75
  }
76
76
  function fail(err, service, action, startTime) {
77
+ if (err instanceof PncliError && err.status === 0 && err.message === "dry-run") throw err;
77
78
  const errorDetail = {
78
79
  status: err instanceof PncliError ? err.status : 1,
79
80
  message: err instanceof Error ? err.message : String(err),
@@ -140,4 +141,4 @@ export {
140
141
  debug,
141
142
  warn
142
143
  };
143
- //# sourceMappingURL=chunk-BOFSNQQ2.js.map
144
+ //# sourceMappingURL=chunk-MBJ4ZYL7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/output.ts","../src/lib/exitCodes.ts"],"sourcesContent":["import fs from 'fs';\nimport chalk from 'chalk';\nimport type { Meta, SuccessEnvelope, ErrorEnvelope, ErrorDetail } from '../types/common.js';\nimport { PncliError } from './errors.js';\nimport { ExitCode, exitCodeFromStatus } from './exitCodes.js';\n\nlet globalOptions = { pretty: false, verbose: false, debug: false };\nlet globalUser: { email: string | undefined; userId: string | undefined } = { email: undefined, userId: undefined };\nlet outputFile: string | undefined;\n\nexport function setGlobalOptions(opts: { pretty: boolean; verbose: boolean; debug?: boolean; outputFile?: string }): void {\n globalOptions = { pretty: opts.pretty, verbose: opts.verbose, debug: opts.debug ?? false };\n outputFile = opts.outputFile;\n}\n\nexport function isDebugEnabled(): boolean {\n return globalOptions.debug;\n}\n\nexport function setGlobalUser(user: { email: string | undefined; userId: string | undefined }): void {\n globalUser = user;\n}\n\nfunction buildMeta(service: string, action: string, startTime: number, overrides?: string[]): Meta {\n return {\n service,\n action,\n timestamp: new Date().toISOString(),\n duration_ms: Date.now() - startTime,\n user: (globalUser.email ?? globalUser.userId) ? globalUser : undefined,\n overrides: overrides && overrides.length > 0 ? overrides : undefined\n };\n}\n\nfunction writeToFile(filePath: string, content: string): void {\n try {\n fs.writeFileSync(filePath, content, 'utf8');\n } catch (writeErr) {\n process.stderr.write(\n `Warning: could not write to output file \"${filePath}\": ${(writeErr as NodeJS.ErrnoException).message}\\n`\n );\n process.exitCode = ExitCode.GENERAL_ERROR;\n }\n}\n\nexport function success<T>(data: T, service: string, action: string, startTime: number, overrides?: string[]): void {\n const envelope: SuccessEnvelope<T> = {\n ok: true,\n data,\n meta: buildMeta(service, action, startTime, overrides)\n };\n const out = (globalOptions.pretty ? JSON.stringify(envelope, null, 2) : JSON.stringify(envelope)) + '\\n';\n if (outputFile) {\n writeToFile(outputFile, out);\n } else {\n process.stdout.write(out);\n }\n}\n\nexport function fail(\n err: unknown,\n service: string,\n action: string,\n startTime: number\n): never {\n // The dry-run sentinel is a successful outcome: http.ts already printed the request\n // and set exitCode to SUCCESS. Don't render it as an error envelope or remap status 0.\n if (err instanceof PncliError && err.status === 0 && err.message === 'dry-run') throw err;\n\n const errorDetail: ErrorDetail = {\n status: err instanceof PncliError ? err.status : 1,\n message: err instanceof Error ? err.message : String(err),\n url: err instanceof PncliError ? (err.url ?? null) : null,\n retryAfterSeconds: err instanceof PncliError ? err.retryAfterSeconds : undefined\n };\n\n const envelope: ErrorEnvelope = {\n ok: false,\n error: errorDetail,\n meta: buildMeta(service, action, startTime)\n };\n\n const msg = globalOptions.pretty\n ? chalk.red('✗ Error: ') + errorDetail.message\n : null;\n\n if (msg) process.stderr.write(msg + '\\n');\n\n const output = (globalOptions.pretty ? JSON.stringify(envelope, null, 2) : JSON.stringify(envelope)) + '\\n';\n const exitCode = err instanceof PncliError ? exitCodeFromStatus(err.status) : ExitCode.GENERAL_ERROR;\n if (outputFile) {\n writeToFile(outputFile, output);\n } else {\n try {\n fs.writeSync(process.stdout.fd, output);\n } catch (writeErr) {\n if ((writeErr as NodeJS.ErrnoException).code !== 'EPIPE') throw writeErr;\n }\n }\n process.exitCode = exitCode;\n throw new PncliError(errorDetail.message, errorDetail.status);\n}\n\nexport function writeRawOutput(content: string): void {\n if (outputFile) {\n writeToFile(outputFile, content);\n } else {\n process.stdout.write(content);\n }\n}\n\nexport function log(message: string): void {\n if (globalOptions.verbose) {\n process.stderr.write(\n (globalOptions.pretty ? chalk.gray('▸ ') : '') + message + '\\n'\n );\n }\n}\n\nexport function debug(message: string): void {\n if (globalOptions.debug) {\n process.stderr.write(\n (globalOptions.pretty ? chalk.cyan('⬡ ') : '') + message + '\\n'\n );\n }\n}\n\nexport function warn(message: string): void {\n process.stderr.write(\n (globalOptions.pretty ? chalk.yellow('⚠ ') : '') + message + '\\n'\n );\n}\n","export const ExitCode = {\n SUCCESS: 0,\n GENERAL_ERROR: 1,\n USAGE_ERROR: 2,\n NETWORK_ERROR: 69, // EX_UNAVAILABLE from sysexits.h\n AUTH_ERROR: 77, // EX_NOPERM from sysexits.h\n CONFIG_ERROR: 78, // EX_CONFIG from sysexits.h\n} as const;\n\nexport type ExitCode = (typeof ExitCode)[keyof typeof ExitCode];\n\nexport function exitCodeFromStatus(httpStatus: number): ExitCode {\n if (httpStatus === 401 || httpStatus === 403) return ExitCode.AUTH_ERROR;\n if (httpStatus === 0) return ExitCode.NETWORK_ERROR;\n return ExitCode.GENERAL_ERROR;\n}\n"],"mappings":"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","names":[]}
@@ -4,7 +4,7 @@ import {
4
4
  debug,
5
5
  isDebugEnabled,
6
6
  log
7
- } from "./chunk-BOFSNQQ2.js";
7
+ } from "./chunk-MBJ4ZYL7.js";
8
8
  import {
9
9
  PncliError
10
10
  } from "./chunk-HRNOAQDN.js";
@@ -1548,4 +1548,4 @@ export {
1548
1548
  HttpClient,
1549
1549
  createHttpClient
1550
1550
  };
1551
- //# sourceMappingURL=chunk-Y3PO2RTO.js.map
1551
+ //# sourceMappingURL=chunk-RZV64BWP.js.map
package/dist/cli.js CHANGED
@@ -34,7 +34,7 @@ import {
34
34
  createHttpClient,
35
35
  describeFetchError,
36
36
  validateAlationAccessToken
37
- } from "./chunk-Y3PO2RTO.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(
@@ -2116,23 +2143,28 @@ var JiraClient = class {
2116
2143
  }
2117
2144
  });
2118
2145
  }
2119
- async search(jql, maxResults, customFields) {
2146
+ async search(jql, maxResults, customFields, startAt, fieldsOverride) {
2120
2147
  const standardFields = ["summary", "status", "priority", "assignee", "issuetype", "project", "created", "updated", "labels", "reporter"];
2121
- const fields = customFields?.length ? [...standardFields, ...customFields.map((f) => f.id)] : standardFields;
2122
- if (maxResults !== void 0) {
2123
- 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`, {
2124
2157
  method: "POST",
2125
- body: { jql, maxResults, fields }
2158
+ body: { jql, startAt: next, maxResults: pageSize, fields }
2126
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;
2127
2166
  }
2128
- const allIssues = await this.http.jiraPaginate(async (startAt, max) => {
2129
- const result = await this.http.jira(`${API2}/search`, {
2130
- method: "POST",
2131
- body: { jql, startAt, maxResults: max, fields }
2132
- });
2133
- return { ...result, values: result.issues };
2134
- });
2135
- return { issues: allIssues, total: allIssues.length, startAt: 0, maxResults: allIssues.length };
2167
+ return { issues, total, startAt: first, maxResults: issues.length };
2136
2168
  }
2137
2169
  async fetchFields() {
2138
2170
  const fields = await this.http.jira(`${API2}/field`);
@@ -2283,6 +2315,10 @@ var JiraClient = class {
2283
2315
  function schemaToPncliType(schema) {
2284
2316
  if (!schema) return void 0;
2285
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";
2286
2322
  if (custom.includes("cascadingselect")) return "cascading-select";
2287
2323
  if (custom.includes("multicheckboxes") || custom.includes("multiselect")) return "multi-select";
2288
2324
  if (custom.includes("select") || custom.includes("radiobuttons")) return "select";
@@ -2527,6 +2563,13 @@ function resolveJqlInput(jql, jqlFile) {
2527
2563
  if (!trimmed) throw new PncliError("JQL query is empty", 1);
2528
2564
  return trimmed;
2529
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
+ }
2530
2573
  function registerJiraCommands(program2) {
2531
2574
  const jira = program2.command("jira").description("Jira Data Cloud operations");
2532
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) => {
@@ -2686,14 +2729,24 @@ function registerJiraCommands(program2) {
2686
2729
  fail(err, "jira", "list-comments", start);
2687
2730
  }
2688
2731
  });
2689
- 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) => {
2690
2733
  const start = Date.now();
2691
2734
  try {
2692
2735
  const { client, fieldMap, customFields } = getClientAndFields(program2);
2693
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
+ }
2694
2746
  const maxResults = opts.maxResults ? parseInt(opts.maxResults, 10) : void 0;
2747
+ const startAt = parseStartAt(opts.startAt);
2695
2748
  const translatedJql = translateJql(jql, fieldMap);
2696
- const data = await client.search(translatedJql, maxResults, customFields);
2749
+ const data = await client.search(translatedJql, maxResults, customFields, startAt, fieldsOverride);
2697
2750
  const translatedIssues = data.issues.map((issue) => ({
2698
2751
  ...issue,
2699
2752
  fields: translateFieldsInOutput(issue.fields, fieldMap)
@@ -2938,11 +2991,13 @@ function registerBitbucketCommands(program2) {
2938
2991
  fail(err, "bitbucket", "create-repo", start);
2939
2992
  }
2940
2993
  });
2941
- 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) => {
2942
2995
  const start = Date.now();
2943
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;
2944
2999
  const { client, project, repo } = getClient2(bb);
2945
- 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 });
2946
3001
  success(data, "bitbucket", "list-prs", start);
2947
3002
  } catch (err) {
2948
3003
  fail(err, "bitbucket", "list-prs", start);
@@ -3021,8 +3076,8 @@ function registerBitbucketCommands(program2) {
3021
3076
  const { client, project, repo } = getClient2(bb);
3022
3077
  const prId = parseInt(opts.id, 10);
3023
3078
  const pr = await client.getPR(project, repo, prId);
3024
- const reviewers = opts.reviewers ? opts.reviewers.split(",").map((s) => s.trim()) : void 0;
3025
- 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 });
3026
3081
  success(data, "bitbucket", "update-pr", start);
3027
3082
  } catch (err) {
3028
3083
  fail(err, "bitbucket", "update-pr", start);
@@ -3237,7 +3292,7 @@ var GitHubClient = class {
3237
3292
  }
3238
3293
  http;
3239
3294
  async listPRs(opts) {
3240
- return this.http.githubPaginate(
3295
+ const prs = await this.http.githubPaginate(
3241
3296
  (page, perPage) => this.http.github(
3242
3297
  `/repos/${opts.owner}/${opts.repo}/pulls`,
3243
3298
  {
@@ -3251,6 +3306,10 @@ var GitHubClient = class {
3251
3306
  }
3252
3307
  )
3253
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
+ );
3254
3313
  }
3255
3314
  async getPR(owner, repo, pullNumber) {
3256
3315
  return this.http.github(`/repos/${owner}/${repo}/pulls/${pullNumber}`);
@@ -3793,16 +3852,21 @@ function registerGitHubCommands(program2) {
3793
3852
  fail(err, "github", "create-issue", start);
3794
3853
  }
3795
3854
  });
3796
- 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) => {
3797
3856
  const start = Date.now();
3798
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;
3799
3860
  const { client, owner, repo } = getClient3(gh);
3800
3861
  const data = await client.listPRs({
3801
3862
  owner,
3802
3863
  repo,
3803
3864
  state: opts.state,
3804
3865
  head: opts.head,
3805
- base: opts.base
3866
+ base: opts.base,
3867
+ author: opts.author,
3868
+ createdAfter,
3869
+ createdBefore
3806
3870
  });
3807
3871
  success(data, "github", "list-prs", start);
3808
3872
  } catch (err) {
@@ -7125,7 +7189,7 @@ var AdoWorkClient = class {
7125
7189
  const result = await this.http.ado(
7126
7190
  `/${encodeURIComponent(collection)}/${encodeURIComponent(project)}/_apis/wit/workItems/${workItemId}/comments?api-version=${API_PREVIEW}`
7127
7191
  );
7128
- return result.value ?? [];
7192
+ return result.comments ?? result.value ?? [];
7129
7193
  }
7130
7194
  async addComment(collection, project, workItemId, text) {
7131
7195
  return this.http.ado(
@@ -7372,7 +7436,7 @@ function registerSauceLabsCommands(program2) {
7372
7436
  function run(action, fn) {
7373
7437
  return async (...args) => {
7374
7438
  const start = Date.now();
7375
- const { success: success2, fail: fail2 } = await import("./output-HDUIIXUI.js");
7439
+ const { success: success2, fail: fail2 } = await import("./output-XE6XDAAR.js");
7376
7440
  try {
7377
7441
  success2(await fn(getHttp(program2), ...args), SERVICE, action, start);
7378
7442
  } catch (err) {
@@ -12433,6 +12497,10 @@ var AdoGitClient = class {
12433
12497
  "searchCriteria.status": opts.status ?? "active",
12434
12498
  ...opts.creatorAlias ? { "searchCriteria.creatorId": opts.creatorAlias } : {},
12435
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() } : {},
12436
12504
  "$top": pageSize,
12437
12505
  "$skip": skip
12438
12506
  };
@@ -13172,14 +13240,18 @@ function registerAdoRepoCommands(ado) {
13172
13240
  fail(err, "ado", "repo-get", start);
13173
13241
  }
13174
13242
  });
13175
- 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) => {
13176
13244
  const start = Date.now();
13177
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;
13178
13248
  const { collection, project, repo: repo2, gitClient } = getAdoContext(ado, true);
13179
13249
  const data = await gitClient.listPRs(collection, project, repo2, {
13180
13250
  status: opts.state,
13181
13251
  creatorAlias: opts.creator,
13182
- reviewerAlias: opts.reviewer
13252
+ reviewerAlias: opts.reviewer,
13253
+ createdAfter,
13254
+ createdBefore
13183
13255
  });
13184
13256
  success(data, "ado", "repo-list-prs", start);
13185
13257
  } catch (err) {
@@ -13419,7 +13491,7 @@ function registerAdoRepoCommands(ado) {
13419
13491
  const config = lc({ configPath: globalOpts.config });
13420
13492
  const { collection, project, repo: repo2, gitClient } = getAdoContext(ado, true);
13421
13493
  const { AdoCoreClient: AdoCoreClient2 } = await import("./core-SWYVXOQ4.js");
13422
- const { createHttpClient: createHttpClient2 } = await import("./http-3FAKF3X4.js");
13494
+ const { createHttpClient: createHttpClient2 } = await import("./http-F24ORY6C.js");
13423
13495
  const http = createHttpClient2(config, Boolean(globalOpts.dryRun));
13424
13496
  const coreClient = new AdoCoreClient2(http);
13425
13497
  const me = await coreClient.getConnectionData(collection);
@@ -15619,7 +15691,7 @@ function registerFigmaCommands(program2) {
15619
15691
  const figma = program2.command("figma").description("Figma design operations (files, comments, versions)");
15620
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) => {
15621
15693
  const start = Date.now();
15622
- const { success: success2, fail: fail2 } = await import("./output-HDUIIXUI.js");
15694
+ const { success: success2, fail: fail2 } = await import("./output-XE6XDAAR.js");
15623
15695
  try {
15624
15696
  const fileKey = parseFileKey(fileKeyOrUrl);
15625
15697
  const nodeId = opts.nodeId ? parseNodeId(opts.nodeId) : isUrl(fileKeyOrUrl) ? findNodeIdInUrl(fileKeyOrUrl) : void 0;
@@ -15678,7 +15750,7 @@ function registerFigmaCommands(program2) {
15678
15750
  });
15679
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) => {
15680
15752
  const start = Date.now();
15681
- const { success: success2, fail: fail2 } = await import("./output-HDUIIXUI.js");
15753
+ const { success: success2, fail: fail2 } = await import("./output-XE6XDAAR.js");
15682
15754
  try {
15683
15755
  const fileKey = parseFileKey(fileKeyOrUrl);
15684
15756
  const params = {};
@@ -15696,7 +15768,7 @@ function registerFigmaCommands(program2) {
15696
15768
  });
15697
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) => {
15698
15770
  const start = Date.now();
15699
- const { success: success2, fail: fail2 } = await import("./output-HDUIIXUI.js");
15771
+ const { success: success2, fail: fail2 } = await import("./output-XE6XDAAR.js");
15700
15772
  try {
15701
15773
  const fileKey = parseFileKey(fileKeyOrUrl);
15702
15774
  const data = await getHttp7(program2).figma(`/v1/files/${encodeURIComponent(fileKey)}/versions`);
@@ -15712,7 +15784,7 @@ function registerFigmaCommands(program2) {
15712
15784
  });
15713
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) => {
15714
15786
  const start = Date.now();
15715
- const { success: success2, fail: fail2 } = await import("./output-HDUIIXUI.js");
15787
+ const { success: success2, fail: fail2 } = await import("./output-XE6XDAAR.js");
15716
15788
  try {
15717
15789
  const data = await getHttp7(program2).figma(`/v1/projects/${encodeURIComponent(projectId)}/files`);
15718
15790
  success2(
@@ -15727,7 +15799,7 @@ function registerFigmaCommands(program2) {
15727
15799
  });
15728
15800
  figma.command("me").description("Get the current Figma user (useful for verifying credentials)").action(async () => {
15729
15801
  const start = Date.now();
15730
- const { success: success2, fail: fail2 } = await import("./output-HDUIIXUI.js");
15802
+ const { success: success2, fail: fail2 } = await import("./output-XE6XDAAR.js");
15731
15803
  try {
15732
15804
  const data = await getHttp7(program2).figma("/v1/me");
15733
15805
  success2(data, "figma", "me", start);