@kolatts/pncli 6.1.0 → 6.2.1
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/{chunk-BOFSNQQ2.js → chunk-MBJ4ZYL7.js} +2 -1
- package/dist/chunk-MBJ4ZYL7.js.map +1 -0
- package/dist/{chunk-Y3PO2RTO.js → chunk-RZV64BWP.js} +2 -2
- package/dist/cli.js +108 -36
- package/dist/cli.js.map +1 -1
- package/dist/{http-3FAKF3X4.js → http-F24ORY6C.js} +3 -3
- package/dist/{output-HDUIIXUI.js → output-XE6XDAAR.js} +2 -2
- package/package.json +1 -1
- package/skills/pncli/jwt.md +2 -2
- package/skills/pncli/openshift.md +5 -5
- package/dist/chunk-BOFSNQQ2.js.map +0 -1
- /package/dist/{chunk-Y3PO2RTO.js.map → chunk-RZV64BWP.js.map} +0 -0
- /package/dist/{http-3FAKF3X4.js.map → http-F24ORY6C.js.map} +0 -0
- /package/dist/{output-HDUIIXUI.js.map → output-XE6XDAAR.js.map} +0 -0
|
@@ -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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
-
|
|
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
|
-
...
|
|
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
|
-
|
|
2123
|
-
|
|
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
|
-
|
|
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()) :
|
|
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
|
-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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);
|