azdo-cli 0.22.0-develop.790 → 0.22.0-develop.798

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.
Files changed (3) hide show
  1. package/README.md +6 -0
  2. package/dist/index.js +297 -73
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -9,6 +9,7 @@ Azure DevOps CLI focused on work item read/write workflows.
9
9
  ## Features
10
10
 
11
11
  - Retrieve work items with readable output (`get-item`)
12
+ - List work items by state, tag, assignee or title (`list-items`)
12
13
  - Update work item state, assignee, or any field (`set-state`, `assign`, `set-field`)
13
14
  - Create or update work items from markdown documents (`upsert`)
14
15
  - Read and post work item comments (`comments`)
@@ -48,6 +49,9 @@ azdo get-item 12345
48
49
  # Download images embedded in a work item's rich-text fields (opt-in)
49
50
  azdo get-item 12345 --download-images # saved to the system temp dir
50
51
  azdo get-item 12345 --resize-images 1024 --images-path ./img # cap width at 1024px, save as PNG
52
+
53
+ # List work items (--state, --tag, --assigned-to [@me], --title-contains, --top, --json)
54
+ azdo list-items --state Active --tag ready --json
51
55
  azdo get-md-field 12345 System.Description --download-images # same flags on get-md-field
52
56
 
53
57
  # Update state
@@ -123,6 +127,8 @@ azdo pr work-items unlink 1234 --pr-number 64
123
127
  azdo pr reviewers add jane@example.com --pr-number 64 # optional by default
124
128
  azdo pr reviewers add jane@example.com --pr-number 64 --required # required (or promotes in place)
125
129
  azdo pr reviewers remove jane@example.com --pr-number 64
130
+ azdo pr reviewers list --pr-number 64 # who must review, and how each voted
131
+ azdo pr reviewers list --pr-number 64 --json # { pullRequestId, reviewers: [{ id, uniqueName, isRequired, vote, voteState, ... }] }
126
132
 
127
133
  # Any pr subcommand can target another repository
128
134
  azdo pr comments --repo other-repo --pr-number 12
package/dist/index.js CHANGED
@@ -42,7 +42,7 @@ import {
42
42
  } from "./chunk-MHJ6OBX3.js";
43
43
 
44
44
  // src/program.ts
45
- import { Command as Command19 } from "commander";
45
+ import { Command as Command20 } from "commander";
46
46
 
47
47
  // src/version.ts
48
48
  import { readFileSync } from "fs";
@@ -249,8 +249,9 @@ function handleCommandError(err, id, context, scope = "write", exit = true) {
249
249
  );
250
250
  writeErrorDetail(msg, "PERMISSION_DENIED");
251
251
  } else if (msg.startsWith("NOT_FOUND")) {
252
+ const subject = id === void 0 ? "Project or resource" : `Work item ${id}`;
252
253
  process.stderr.write(
253
- `Error: Work item ${id} not found in ${context?.org}/${context?.project}.
254
+ `Error: ${subject} not found in ${context?.org}/${context?.project}.
254
255
  `
255
256
  );
256
257
  } else if (msg === "NETWORK_ERROR") {
@@ -988,6 +989,107 @@ async function createAttachment(context, fileName, content, cred) {
988
989
  }
989
990
  return await response.json();
990
991
  }
992
+ var LIST_SYSTEM_FIELDS = [
993
+ "System.Title",
994
+ "System.State",
995
+ "System.WorkItemType",
996
+ "System.AssignedTo",
997
+ "System.Description",
998
+ "System.Tags",
999
+ "System.TeamProject"
1000
+ ];
1001
+ var LIST_PROCESS_FIELDS = [
1002
+ "Microsoft.VSTS.Common.AcceptanceCriteria",
1003
+ "Microsoft.VSTS.TCM.ReproSteps"
1004
+ ];
1005
+ var WORKITEMS_BATCH_LIMIT = 200;
1006
+ function wiqlLiteral(value) {
1007
+ return `'${value.replaceAll("'", "''")}'`;
1008
+ }
1009
+ function buildListWiql(filter) {
1010
+ const clauses = ["[System.TeamProject] = @project"];
1011
+ if (filter.state) clauses.push(`[System.State] = ${wiqlLiteral(filter.state)}`);
1012
+ if (filter.tag) clauses.push(`[System.Tags] CONTAINS ${wiqlLiteral(filter.tag)}`);
1013
+ if (filter.assignedTo) {
1014
+ clauses.push(
1015
+ filter.assignedTo.toLowerCase() === "@me" ? "[System.AssignedTo] = @Me" : `[System.AssignedTo] = ${wiqlLiteral(filter.assignedTo)}`
1016
+ );
1017
+ }
1018
+ if (filter.titleContains) clauses.push(`[System.Title] CONTAINS ${wiqlLiteral(filter.titleContains)}`);
1019
+ return `SELECT [System.Id] FROM WorkItems WHERE ${clauses.join(" AND ")} ORDER BY [System.ChangedDate] DESC`;
1020
+ }
1021
+ function parseTags(raw) {
1022
+ if (typeof raw !== "string") return [];
1023
+ return raw.split(";").map((t) => t.trim()).filter((t) => t.length > 0);
1024
+ }
1025
+ async function runWiql(context, cred, wiql, top) {
1026
+ const url = new URL(
1027
+ `https://dev.azure.com/${encodeURIComponent(context.org)}/${encodeURIComponent(context.project)}/_apis/wit/wiql`
1028
+ );
1029
+ url.searchParams.set("api-version", "7.1");
1030
+ url.searchParams.set("$top", String(top));
1031
+ const response = await fetchWithErrors(url.toString(), {
1032
+ method: "POST",
1033
+ headers: { ...authHeaders(cred), "Content-Type": "application/json" },
1034
+ body: JSON.stringify({ query: wiql })
1035
+ });
1036
+ if (response.status === 400) {
1037
+ const serverMessage = await readResponseMessage(response);
1038
+ if (serverMessage) throw new Error(`BAD_REQUEST: ${serverMessage}`);
1039
+ }
1040
+ if (!response.ok) throw httpError(response);
1041
+ const data = await response.json();
1042
+ return (data.workItems ?? []).map((w) => w.id);
1043
+ }
1044
+ async function postWorkItemsBatch(context, cred, ids, fields) {
1045
+ const url = new URL(
1046
+ `https://dev.azure.com/${encodeURIComponent(context.org)}/${encodeURIComponent(context.project)}/_apis/wit/workitemsbatch`
1047
+ );
1048
+ url.searchParams.set("api-version", "7.1");
1049
+ return fetchWithErrors(url.toString(), {
1050
+ method: "POST",
1051
+ headers: { ...authHeaders(cred), "Content-Type": "application/json" },
1052
+ body: JSON.stringify({ ids, fields })
1053
+ });
1054
+ }
1055
+ async function readWorkItemsBatch(context, cred, ids) {
1056
+ let response = await postWorkItemsBatch(context, cred, ids, [...LIST_SYSTEM_FIELDS, ...LIST_PROCESS_FIELDS]);
1057
+ if (response.status === 400) {
1058
+ const serverMessage = await readResponseMessage(response);
1059
+ if (!serverMessage?.includes("TF51535")) {
1060
+ throw serverMessage ? new Error(`BAD_REQUEST: ${serverMessage}`) : httpError(response);
1061
+ }
1062
+ response = await postWorkItemsBatch(context, cred, ids, LIST_SYSTEM_FIELDS);
1063
+ }
1064
+ if (!response.ok) throw httpError(response);
1065
+ return (await response.json()).value ?? [];
1066
+ }
1067
+ async function queryWorkItems(context, cred, filter) {
1068
+ const ids = await runWiql(context, cred, buildListWiql(filter), filter.top);
1069
+ const byId = /* @__PURE__ */ new Map();
1070
+ const chunks = [];
1071
+ for (let i = 0; i < ids.length; i += WORKITEMS_BATCH_LIMIT) {
1072
+ chunks.push(ids.slice(i, i + WORKITEMS_BATCH_LIMIT));
1073
+ }
1074
+ const batches = await Promise.all(chunks.map((chunk) => readWorkItemsBatch(context, cred, chunk)));
1075
+ for (const batch of batches) {
1076
+ for (const item of batch) {
1077
+ const teamProject = item.fields["System.TeamProject"];
1078
+ const project = typeof teamProject === "string" ? teamProject : context.project;
1079
+ byId.set(item.id, {
1080
+ id: item.id,
1081
+ title: item.fields["System.Title"],
1082
+ description: buildCombinedDescription(item.fields),
1083
+ url: `https://dev.azure.com/${encodeURIComponent(context.org)}/${encodeURIComponent(project)}/_workitems/edit/${item.id}`,
1084
+ state: item.fields["System.State"],
1085
+ type: item.fields["System.WorkItemType"],
1086
+ tags: parseTags(item.fields["System.Tags"]),
1087
+ assignedTo: item.fields["System.AssignedTo"]?.displayName ?? null
1088
+ });
1089
+ }
1090
+ }
1091
+ return ids.flatMap((id) => byId.get(id) ?? []);
1092
+ }
991
1093
 
992
1094
  // src/services/auth.ts
993
1095
  import { createInterface } from "readline";
@@ -1957,10 +2059,69 @@ function createGetItemCommand() {
1957
2059
  return command;
1958
2060
  }
1959
2061
 
1960
- // src/commands/clear-pat.ts
2062
+ // src/commands/list-items.ts
1961
2063
  import { Command as Command2 } from "commander";
2064
+ var DEFAULT_TOP = 50;
2065
+ var MAX_TOP = 1e3;
2066
+ function parseTop(raw) {
2067
+ if (raw === void 0) return DEFAULT_TOP;
2068
+ const top = Number(raw);
2069
+ if (!/^\d+$/.test(raw) || top < 1 || top > MAX_TOP) {
2070
+ process.stderr.write(`Error: --top must be an integer between 1 and ${MAX_TOP}. Got: "${raw}"
2071
+ `);
2072
+ process.exit(1);
2073
+ }
2074
+ return top;
2075
+ }
2076
+ function toJsonRow(item) {
2077
+ return {
2078
+ id: item.id,
2079
+ title: item.title,
2080
+ description: item.description ? toMarkdown(item.description) : "",
2081
+ url: item.url,
2082
+ state: item.state,
2083
+ tags: item.tags,
2084
+ assignedTo: item.assignedTo
2085
+ };
2086
+ }
2087
+ function formatItemLine(item) {
2088
+ const tags = item.tags.length > 0 ? ` [${item.tags.join(", ")}]` : "";
2089
+ return `${item.id} ${item.state} ${item.assignedTo ?? "Unassigned"} ${item.title}${tags}`;
2090
+ }
2091
+ function createListItemsCommand() {
2092
+ const command = new Command2("list-items");
2093
+ command.description("List work items filtered by state, tag, assignee and title (one WIQL query, then batched reads of 200 items)").option("--state <state>", 'only items in this state (e.g. "Active")').option("--tag <tag>", "only items carrying this tag").option("--assigned-to <user>", "only items assigned to this user (display name, email, or @me)").option("--title-contains <text>", "only items whose title contains this text").option("--top <n>", `maximum number of items, newest change first (default ${DEFAULT_TOP}, max ${MAX_TOP})`).option("--org <org>", "Azure DevOps organization").option("--project <project>", "Azure DevOps project").option("--json", "output an array of { id, title, description (markdown), url, state, tags, assignedTo }").action(async (options) => {
2094
+ validateOrgProjectPair(options);
2095
+ const top = parseTop(options.top);
2096
+ let context;
2097
+ try {
2098
+ context = resolveContext(options);
2099
+ const credential = await requireAuthCredential(context.org);
2100
+ const items = await queryWorkItems(context, credential, {
2101
+ state: options.state,
2102
+ tag: options.tag,
2103
+ assignedTo: options.assignedTo,
2104
+ titleContains: options.titleContains,
2105
+ top
2106
+ });
2107
+ if (options.json) {
2108
+ process.stdout.write(JSON.stringify(items.map(toJsonRow)) + "\n");
2109
+ } else if (items.length === 0) {
2110
+ process.stdout.write("No work items found.\n");
2111
+ } else {
2112
+ process.stdout.write(items.map(formatItemLine).join("\n") + "\n");
2113
+ }
2114
+ } catch (err) {
2115
+ handleCommandError(err, void 0, context, "read");
2116
+ }
2117
+ });
2118
+ return command;
2119
+ }
2120
+
2121
+ // src/commands/clear-pat.ts
2122
+ import { Command as Command3 } from "commander";
1962
2123
  function createClearPatCommand() {
1963
- const command = new Command2("clear-pat");
2124
+ const command = new Command3("clear-pat");
1964
2125
  command.description("Remove a stored Azure DevOps PAT (deprecated: use `azdo auth logout`)").option("--org <name>", "Azure DevOps organization (overrides auto-detect / config)").action(async (options) => {
1965
2126
  process.stderr.write("`azdo clear-pat` is deprecated; use `azdo auth logout [--org <name>]` instead.\n");
1966
2127
  const resolved = resolveOrg({ org: options.org });
@@ -1983,7 +2144,7 @@ function createClearPatCommand() {
1983
2144
  }
1984
2145
 
1985
2146
  // src/commands/auth.ts
1986
- import { Command as Command3 } from "commander";
2147
+ import { Command as Command4 } from "commander";
1987
2148
 
1988
2149
  // src/services/auth-diagnostics.ts
1989
2150
  async function runConnectivityTest(org, cred) {
@@ -2481,7 +2642,7 @@ async function handleToken(orgFromGlobal) {
2481
2642
  `);
2482
2643
  }
2483
2644
  function createAuthCommand() {
2484
- const command = new Command3("auth");
2645
+ const command = new Command4("auth");
2485
2646
  command.description(
2486
2647
  "Manage Azure DevOps authentication. Use `azdo auth login` for OAuth (default); the bare `azdo auth` form preserves the legacy PAT-prompt path for back-compat."
2487
2648
  );
@@ -2619,7 +2780,7 @@ not be resolved, 4 OS credential store unavailable. stdout stays empty on all.
2619
2780
  }
2620
2781
 
2621
2782
  // src/commands/config.ts
2622
- import { Command as Command4 } from "commander";
2783
+ import { Command as Command5 } from "commander";
2623
2784
  import { createInterface as createInterface2 } from "readline";
2624
2785
 
2625
2786
  // src/services/dpapi-copy.ts
@@ -2810,7 +2971,7 @@ function renderSettingsHelp(settings = SETTINGS) {
2810
2971
  var KEY_ARGUMENT_HELP = `setting key (${SETTINGS.map((s) => s.key).join(", ")})`;
2811
2972
  var KEY_HELP_POINTER = "\nRun `azdo config --help` for each setting's meaning, accepted values and scope.\n";
2812
2973
  function createConfigCommand() {
2813
- const config = new Command4("config");
2974
+ const config = new Command5("config");
2814
2975
  config.description("Manage CLI settings");
2815
2976
  config.addHelpText("after", `
2816
2977
  ${renderSettingsHelp()}`);
@@ -2830,7 +2991,7 @@ ${renderSettingsHelp()}`);
2830
2991
  "Run `azdo auth diagnose` to see which credential is in use."
2831
2992
  ].join("\n")
2832
2993
  );
2833
- const set = new Command4("set");
2994
+ const set = new Command5("set");
2834
2995
  set.description("Set a configuration value").argument("<key>", KEY_ARGUMENT_HELP).argument("<value>", "setting value").option("--org <org>", "set value in an org-scoped configuration").option("--json", "output in JSON format").option("--copy-credentials", "with credentialStore dpapi: copy Credential Manager credentials without asking").option("--no-copy-credentials", "with credentialStore dpapi: do not offer to copy Credential Manager credentials").addHelpText("after", KEY_HELP_POINTER).action((key, value, options) => {
2835
2996
  try {
2836
2997
  if (options.org) {
@@ -2864,7 +3025,7 @@ ${renderSettingsHelp()}`);
2864
3025
  }
2865
3026
  writeJson();
2866
3027
  });
2867
- const get = new Command4("get");
3028
+ const get = new Command5("get");
2868
3029
  get.description("Get a configuration value").argument("<key>", KEY_ARGUMENT_HELP).option("--org <org>", "read from an org-scoped configuration").option("--json", "output in JSON format").addHelpText("after", KEY_HELP_POINTER).action((key, options) => {
2869
3030
  try {
2870
3031
  const value = options.org ? getOrgScopedValue(options.org, key) : getConfigValue(key);
@@ -2887,7 +3048,7 @@ ${renderSettingsHelp()}`);
2887
3048
  process.exit(1);
2888
3049
  }
2889
3050
  });
2890
- const list = new Command4("list");
3051
+ const list = new Command5("list");
2891
3052
  list.description("List all configuration values").option("--json", "output in JSON format").action((options) => {
2892
3053
  const cfg = loadConfig();
2893
3054
  if (options.json) {
@@ -2897,7 +3058,7 @@ ${renderSettingsHelp()}`);
2897
3058
  }
2898
3059
  writeConfigList(cfg);
2899
3060
  });
2900
- const unset = new Command4("unset");
3061
+ const unset = new Command5("unset");
2901
3062
  unset.description("Remove a configuration value").argument("<key>", KEY_ARGUMENT_HELP).option("--org <org>", "remove from an org-scoped configuration").option("--json", "output in JSON format").addHelpText("after", KEY_HELP_POINTER).action((key, options) => {
2902
3063
  try {
2903
3064
  if (options.org) {
@@ -2919,7 +3080,7 @@ ${renderSettingsHelp()}`);
2919
3080
  process.exit(1);
2920
3081
  }
2921
3082
  });
2922
- const wizard = new Command4("wizard");
3083
+ const wizard = new Command5("wizard");
2923
3084
  wizard.description("Interactive wizard to configure all settings").action(async () => {
2924
3085
  if (!process.stdin.isTTY) {
2925
3086
  process.stderr.write(
@@ -2942,7 +3103,7 @@ ${renderSettingsHelp()}`);
2942
3103
  rl.close();
2943
3104
  process.stderr.write("Configuration complete!\n");
2944
3105
  });
2945
- const orgCopy = new Command4("org-copy");
3106
+ const orgCopy = new Command5("org-copy");
2946
3107
  orgCopy.description('Copy settings from one scope to another (use "default" as source to copy top-level settings)').argument("<from>", 'source scope name or "default"').argument("<to>", "destination org name").option("--force", "overwrite existing values on collision").action((from, to, options) => {
2947
3108
  try {
2948
3109
  copyOrgScope(from, to, options.force ?? false);
@@ -2955,7 +3116,7 @@ ${renderSettingsHelp()}`);
2955
3116
  process.exit(1);
2956
3117
  }
2957
3118
  });
2958
- const orgMove = new Command4("org-move");
3119
+ const orgMove = new Command5("org-move");
2959
3120
  orgMove.description("Move settings from one org scope to another").argument("<from>", "source org name").argument("<to>", "destination org name").option("--force", "overwrite existing values on collision").action((from, to, options) => {
2960
3121
  try {
2961
3122
  moveOrgScope(from, to, options.force ?? false);
@@ -2968,7 +3129,7 @@ ${renderSettingsHelp()}`);
2968
3129
  process.exit(1);
2969
3130
  }
2970
3131
  });
2971
- const orgDelete = new Command4("org-delete");
3132
+ const orgDelete = new Command5("org-delete");
2972
3133
  orgDelete.description("Delete an org-scoped configuration").argument("<name>", "org name").action((name) => {
2973
3134
  try {
2974
3135
  deleteOrgScope(name);
@@ -2993,9 +3154,9 @@ ${renderSettingsHelp()}`);
2993
3154
  }
2994
3155
 
2995
3156
  // src/commands/set-state.ts
2996
- import { Command as Command5 } from "commander";
3157
+ import { Command as Command6 } from "commander";
2997
3158
  function createSetStateCommand() {
2998
- const command = new Command5("set-state");
3159
+ const command = new Command6("set-state");
2999
3160
  command.description("Change the state of a work item").argument("<id>", "work item ID").argument("<state>", 'target state (e.g., "Active", "Closed")').option("--org <org>", "Azure DevOps organization").option("--project <project>", "Azure DevOps project").option("--json", "output result as JSON").action(
3000
3161
  async (idStr, state, options) => {
3001
3162
  const id = parseWorkItemId(idStr);
@@ -3031,9 +3192,9 @@ function createSetStateCommand() {
3031
3192
  }
3032
3193
 
3033
3194
  // src/commands/assign.ts
3034
- import { Command as Command6 } from "commander";
3195
+ import { Command as Command7 } from "commander";
3035
3196
  function createAssignCommand() {
3036
- const command = new Command6("assign");
3197
+ const command = new Command7("assign");
3037
3198
  command.description("Assign a work item to a user, or unassign it").argument("<id>", "work item ID").argument("[name]", "user display name or email").option("--unassign", "clear the Assigned To field").option("--org <org>", "Azure DevOps organization").option("--project <project>", "Azure DevOps project").option("--json", "output result as JSON").action(
3038
3199
  async (idStr, name, options) => {
3039
3200
  const id = parseWorkItemId(idStr);
@@ -3083,9 +3244,9 @@ function createAssignCommand() {
3083
3244
  }
3084
3245
 
3085
3246
  // src/commands/set-field.ts
3086
- import { Command as Command7 } from "commander";
3247
+ import { Command as Command8 } from "commander";
3087
3248
  function createSetFieldCommand() {
3088
- const command = new Command7("set-field");
3249
+ const command = new Command8("set-field");
3089
3250
  command.description("Set any work item field by its reference name").argument("<id>", "work item ID").argument("<field>", "field reference name (e.g., System.Title)").argument("<value>", "new value for the field").option("--org <org>", "Azure DevOps organization").option("--project <project>", "Azure DevOps project").option("--json", "output result as JSON").action(
3090
3251
  async (idStr, field, value, options) => {
3091
3252
  const id = parseWorkItemId(idStr);
@@ -3121,9 +3282,9 @@ function createSetFieldCommand() {
3121
3282
  }
3122
3283
 
3123
3284
  // src/commands/get-md-field.ts
3124
- import { Command as Command8 } from "commander";
3285
+ import { Command as Command9 } from "commander";
3125
3286
  function createGetMdFieldCommand() {
3126
- const command = new Command8("get-md-field");
3287
+ const command = new Command9("get-md-field");
3127
3288
  command.description("Get a work item field value, converting HTML to markdown").argument("<id>", "work item ID").argument("<field>", "field reference name (e.g., System.Description)").option("--org <org>", "Azure DevOps organization").option("--project <project>", "Azure DevOps project");
3128
3289
  addImageDownloadOptions(command);
3129
3290
  command.action(
@@ -3158,7 +3319,7 @@ function createGetMdFieldCommand() {
3158
3319
 
3159
3320
  // src/commands/set-md-field.ts
3160
3321
  import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
3161
- import { Command as Command9 } from "commander";
3322
+ import { Command as Command10 } from "commander";
3162
3323
  function fail(message) {
3163
3324
  process.stderr.write(`Error: ${message}
3164
3325
  `);
@@ -3220,7 +3381,7 @@ function formatOutput(result, options, field) {
3220
3381
  }
3221
3382
  }
3222
3383
  function createSetMdFieldCommand() {
3223
- const command = new Command9("set-md-field");
3384
+ const command = new Command10("set-md-field");
3224
3385
  command.description("Set a work item field with markdown content").argument("<id>", "work item ID").argument("<field>", "field reference name (e.g., System.Description)").argument("[content]", "markdown content to set").option("--org <org>", "Azure DevOps organization").option("--project <project>", "Azure DevOps project").option("--json", "output result as JSON").option("--file <path>", "read markdown content from file").action(
3225
3386
  async (idStr, field, inlineContent, options) => {
3226
3387
  const id = parseWorkItemId(idStr);
@@ -3247,7 +3408,7 @@ function createSetMdFieldCommand() {
3247
3408
 
3248
3409
  // src/commands/upsert.ts
3249
3410
  import { existsSync as existsSync4, readFileSync as readFileSync4, unlinkSync } from "fs";
3250
- import { Command as Command10 } from "commander";
3411
+ import { Command as Command11 } from "commander";
3251
3412
 
3252
3413
  // src/services/task-document.ts
3253
3414
  var FIELD_ALIASES = /* @__PURE__ */ new Map([
@@ -3532,7 +3693,7 @@ function handleUpsertError(err, id, context) {
3532
3693
  process.exit(1);
3533
3694
  }
3534
3695
  function createUpsertCommand() {
3535
- const command = new Command10("upsert");
3696
+ const command = new Command11("upsert");
3536
3697
  command.description("Create or update a work item from a markdown document").argument("[id]", "work item ID to update; omit to create a new work item").option("--content <markdown>", "task document content").option("--file <path>", "read task document from file").option("--type <workItemType>", "create mode work item type (defaults to Task)").option("--json", "output result as JSON").option("--org <org>", "Azure DevOps organization").option("--project <project>", "Azure DevOps project").action(async (idStr, options) => {
3537
3698
  validateOrgProjectPair(options);
3538
3699
  const id = idStr === void 0 ? void 0 : parseWorkItemId(idStr);
@@ -3573,7 +3734,7 @@ function createUpsertCommand() {
3573
3734
  }
3574
3735
 
3575
3736
  // src/commands/list-fields.ts
3576
- import { Command as Command11 } from "commander";
3737
+ import { Command as Command12 } from "commander";
3577
3738
  function stringifyValue(value) {
3578
3739
  if (value === null || value === void 0) return "";
3579
3740
  if (typeof value === "string") return value;
@@ -3607,7 +3768,7 @@ function formatFieldList(fields) {
3607
3768
  }).join("\n");
3608
3769
  }
3609
3770
  function createListFieldsCommand() {
3610
- const command = new Command11("list-fields");
3771
+ const command = new Command12("list-fields");
3611
3772
  command.description("List all fields of an Azure DevOps work item").argument("<id>", "work item ID").option("--org <org>", "Azure DevOps organization").option("--project <project>", "Azure DevOps project").option("--json", "output result as JSON").action(
3612
3773
  async (idStr, options) => {
3613
3774
  const id = parseWorkItemId(idStr);
@@ -3635,7 +3796,7 @@ function createListFieldsCommand() {
3635
3796
 
3636
3797
  // src/commands/pr.ts
3637
3798
  import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
3638
- import { Command as Command12 } from "commander";
3799
+ import { Command as Command13 } from "commander";
3639
3800
 
3640
3801
  // src/services/pr-client.ts
3641
3802
  function buildPullRequestsUrl(context, repo, sourceBranch, opts) {
@@ -4261,13 +4422,34 @@ function buildPullRequestReviewerUrl(context, repo, prId, reviewerId) {
4261
4422
  url.searchParams.set("api-version", "7.1");
4262
4423
  return url;
4263
4424
  }
4425
+ function reviewerVoteState(vote) {
4426
+ switch (vote) {
4427
+ case 10:
4428
+ return "approved";
4429
+ case 5:
4430
+ return "approved-with-suggestions";
4431
+ case 0:
4432
+ return "no-vote";
4433
+ case -5:
4434
+ return "waiting-for-author";
4435
+ case -10:
4436
+ return "rejected";
4437
+ case 15:
4438
+ return "bypassed";
4439
+ default:
4440
+ return "unknown";
4441
+ }
4442
+ }
4264
4443
  function mapReviewer(data) {
4444
+ const vote = data.vote ?? 0;
4265
4445
  return {
4266
4446
  id: data.id,
4267
4447
  displayName: data.displayName ?? null,
4268
4448
  uniqueName: data.uniqueName ?? null,
4269
4449
  isRequired: data.isRequired ?? false,
4270
- vote: data.vote ?? 0
4450
+ vote,
4451
+ voteState: reviewerVoteState(vote),
4452
+ hasDeclined: data.hasDeclined ?? false
4271
4453
  };
4272
4454
  }
4273
4455
  async function getPullRequestReviewers(context, repo, cred, prId) {
@@ -4742,7 +4924,7 @@ async function findStatusPullRequests(resolved, target) {
4742
4924
  return { branch, pullRequests };
4743
4925
  }
4744
4926
  function createPrStatusCommand() {
4745
- const command = new Command12("status");
4927
+ const command = new Command13("status");
4746
4928
  withCommonPrOptions(configureUnwrappedHelp(command)).description("Check pull requests for the current branch, another branch, or a specific pull request").option("--pr-number <id>", STATUS_PR_NUMBER_HELP).option("--branch <name>", STATUS_BRANCH_HELP).option("--json", "output JSON").action(async (options) => {
4747
4929
  validateOrgProjectPair(options);
4748
4930
  const target = parseStatusTarget(options);
@@ -4829,7 +5011,7 @@ function resolveOpenDescription(inline, file) {
4829
5011
  return trimmedInline;
4830
5012
  }
4831
5013
  function createPrOpenCommand() {
4832
- const command = new Command12("open");
5014
+ const command = new Command13("open");
4833
5015
  withCommonPrOptions(command).description("Open a pull request from the current branch to develop").option("--title <title>", "pull request title").option(
4834
5016
  "--description <description>",
4835
5017
  "pull request description; when omitted, a repository-defined pull request template is used if one exists (prepended by this text when both are present)"
@@ -4997,7 +5179,7 @@ ${updated.url ?? "\u2014"}
4997
5179
  }
4998
5180
  }
4999
5181
  function createPrUpdateCommand() {
5000
- const command = new Command12("update");
5182
+ const command = new Command13("update");
5001
5183
  withCommonPrOptions(configureUnwrappedHelp(command)).alias("edit").description("Update a pull request's title and/or description").option("--pr-number <N>", PR_NUMBER_HELP).option("--title <title>", "new pull request title").option("--title-file <path>", 'read the new title from a UTF-8 file; "-" reads standard input').option(
5002
5184
  "--description <description>",
5003
5185
  'new pull request description; REPLACES the existing description literally \u2014 no repository pull request template is looked up or prepended, unlike "azdo pr open"'
@@ -5085,7 +5267,7 @@ ${updated.url ?? "\u2014"}
5085
5267
  }
5086
5268
  }
5087
5269
  function createPrAbandonCommand() {
5088
- const command = new Command12("abandon");
5270
+ const command = new Command13("abandon");
5089
5271
  withCommonPrOptions(configureUnwrappedHelp(command)).alias("close").description(
5090
5272
  'Abandon a pull request (status: abandoned) \u2014 reversible with "azdo pr reactivate". This does NOT complete or merge the pull request; nothing is deleted and no confirmation is asked.'
5091
5273
  ).option("--pr-number <N>", PR_NUMBER_HELP).option("--json", "output JSON").action(async (_options, command2) => {
@@ -5094,7 +5276,7 @@ function createPrAbandonCommand() {
5094
5276
  return command;
5095
5277
  }
5096
5278
  function createPrReactivateCommand() {
5097
- const command = new Command12("reactivate");
5279
+ const command = new Command13("reactivate");
5098
5280
  withCommonPrOptions(configureUnwrappedHelp(command)).description(
5099
5281
  "Reactivate an abandoned pull request (status: active). When --pr-number is omitted the current branch's single ABANDONED pull request is used, not the active one."
5100
5282
  ).option("--pr-number <N>", PR_NUMBER_HELP_ABANDONED).option("--json", "output JSON").action(async (_options, command2) => {
@@ -5200,7 +5382,7 @@ function describeEmptyThreads(pullRequestId, allThreadCount, active) {
5200
5382
  `;
5201
5383
  }
5202
5384
  function createPrCommentsCommand() {
5203
- const command = new Command12("comments");
5385
+ const command = new Command13("comments");
5204
5386
  withCommonPrOptions(configureUnwrappedHelp(command)).description("List pull request comment threads for the current branch").option("--pr-number <N>", PR_NUMBER_HELP).option("--hide-resolved", "hide threads whose status is resolved / won't fix / closed / by design").option("--exclude-resolved", "alias of --hide-resolved: exclude resolved / won't fix / closed / by design threads").option("--code-related-only", "show only threads anchored to a file/line; omit general discussion threads").option("--exclude-system", "omit Azure DevOps system comments (branch updates, reviewer votes, build events)").option("--max-chars <N>", "truncate each comment body to N characters (0 = no limit, the default)").option("--thread <id>", "show only the thread with this numeric id; fails when the pull request has no such thread").option("--contains <text>", "show only threads holding a comment that contains this literal, case-sensitive substring (matched before --max-chars truncates)").option("--json", "output JSON").action(async (options) => {
5205
5387
  validateOrgProjectPair(options);
5206
5388
  const parsed = parseCommentsOptions(options);
@@ -5396,14 +5578,14 @@ async function runThreadStateChange(threadIdRaw, options, direction) {
5396
5578
  }
5397
5579
  }
5398
5580
  function createPrCommentResolveCommand() {
5399
- const command = new Command12("comment-resolve");
5581
+ const command = new Command13("comment-resolve");
5400
5582
  withCommonPrOptions(configureUnwrappedHelp(command)).description("Mark a pull request comment thread as resolved").argument("<threadId>", "numeric id of the thread to resolve").option("--pr-number <N>", PR_NUMBER_HELP).option("--json", "output JSON").action(async (threadIdRaw, options) => {
5401
5583
  await runThreadStateChange(threadIdRaw, options, "resolve");
5402
5584
  });
5403
5585
  return command;
5404
5586
  }
5405
5587
  function createPrCommentReopenCommand() {
5406
- const command = new Command12("comment-reopen");
5588
+ const command = new Command13("comment-reopen");
5407
5589
  withCommonPrOptions(configureUnwrappedHelp(command)).description("Reopen (set to active) a previously resolved pull request comment thread").argument("<threadId>", "numeric id of the thread to reopen").option("--pr-number <N>", PR_NUMBER_HELP).option("--json", "output JSON").action(async (threadIdRaw, options) => {
5408
5590
  await runThreadStateChange(threadIdRaw, options, "reopen");
5409
5591
  });
@@ -5455,7 +5637,7 @@ async function runCommentReply(threadIdRaw, text, options) {
5455
5637
  }
5456
5638
  }
5457
5639
  function buildCommentReplyCommand(name, description) {
5458
- const command = new Command12(name);
5640
+ const command = new Command13(name);
5459
5641
  withCommonPrOptions(configureUnwrappedHelp(command)).description(description).argument("<threadId>", "numeric id of the thread to reply to").argument("[text]", "text of the reply; omit when using --file").option("--file <path>", "read the reply body from a UTF-8 file instead of the inline argument").option("--pr-number <N>", PR_NUMBER_HELP).option("--json", "output JSON").action(async (threadIdRaw, text, _options, command2) => {
5460
5642
  await runCommentReply(threadIdRaw, text, mergedPrOptions(command2));
5461
5643
  });
@@ -5557,7 +5739,7 @@ ${body}
5557
5739
  }
5558
5740
  }
5559
5741
  function buildCommentAddCommand(name, description) {
5560
- const command = new Command12(name);
5742
+ const command = new Command13(name);
5561
5743
  withCommonPrOptions(configureUnwrappedHelp(command)).description(description).argument("[text]", "body of the new comment; omit when using --file").option("--file <path>", "read the comment body from a UTF-8 file instead of the inline argument").option(
5562
5744
  "--status <status>",
5563
5745
  `thread status (${CREATABLE_THREAD_STATUSES.join(" | ")}); omit for a plain, non-resolvable comment`
@@ -5707,7 +5889,7 @@ async function runCommentEdit(threadIdRaw, text, options) {
5707
5889
  }
5708
5890
  }
5709
5891
  function buildCommentEditCommand(name, description) {
5710
- const command = new Command12(name);
5892
+ const command = new Command13(name);
5711
5893
  withCommonPrOptions(configureUnwrappedHelp(command)).description(description).argument("<threadId>", "numeric id of the thread holding the comment").argument("[text]", "new comment body; omit when using --file").option("--comment-id <N>", "numeric id of the comment to edit; defaults to the thread's first comment").option("--file <path>", "read the new body from a UTF-8 file instead of the inline argument").option("--dry-run", "print the replacement body plus the current/new lengths, without writing anything (--json also returns previousContent)").option("--pr-number <N>", PR_NUMBER_HELP).option("--json", "output JSON").action(async (threadIdRaw, text, _options, command2) => {
5712
5894
  await runCommentEdit(threadIdRaw, text, mergedPrOptions(command2));
5713
5895
  });
@@ -5808,7 +5990,7 @@ async function runCommentDelete(threadIdRaw, options) {
5808
5990
  }
5809
5991
  }
5810
5992
  function buildCommentDeleteCommand(name, description) {
5811
- const command = new Command12(name);
5993
+ const command = new Command13(name);
5812
5994
  withCommonPrOptions(configureUnwrappedHelp(command)).description(description).argument("<threadId>", "numeric id of the thread holding the comment").option("--comment-id <N>", "numeric id of the comment to delete; may be omitted only when the thread holds a single comment").option("--dry-run", "resolve the target comment and print what would be deleted, without deleting anything").option("--pr-number <N>", PR_NUMBER_HELP).option("--json", "output JSON").action(async (threadIdRaw, _options, command2) => {
5813
5995
  await runCommentDelete(threadIdRaw, mergedPrOptions(command2));
5814
5996
  });
@@ -5874,7 +6056,7 @@ async function attachWorkItemIds(context, repo, cred, pullRequests) {
5874
6056
  return result;
5875
6057
  }
5876
6058
  function createPrListCommand() {
5877
- const command = new Command12("list");
6059
+ const command = new Command13("list");
5878
6060
  withCommonPrOptions(configureUnwrappedHelp(command)).description("List pull requests in the repository, optionally filtered by source branch").option("--branch <name>", "only pull requests whose source branch is this one (with or without the refs/heads/ prefix)").option("--status <status>", `pull request status filter (${LIST_STATUS_VALUES.join(" | ")})`, "active").option("--top <N>", `maximum number of pull requests to return (default ${DEFAULT_LIST_TOP})`).option("--work-items", "also return the ids of each pull request's linked work items (one extra API call per pull request)").option("--json", "output JSON").action(async (options) => {
5879
6061
  validateOrgProjectPair(options);
5880
6062
  const parsed = parseListOptions(options);
@@ -5972,14 +6154,14 @@ async function runWorkItemLinkChange(workItemIdRaw, options, direction) {
5972
6154
  }
5973
6155
  }
5974
6156
  function buildWorkItemLinkCommand(name, description, direction) {
5975
- const command = new Command12(name);
6157
+ const command = new Command13(name);
5976
6158
  withCommonPrOptions(configureUnwrappedHelp(command)).description(description).argument("<workItemId>", "numeric id of the work item").option("--pr-number <N>", PR_NUMBER_HELP).option("--json", "output JSON").action(async (workItemIdRaw, _options, command2) => {
5977
6159
  await runWorkItemLinkChange(workItemIdRaw, mergedPrOptions(command2), direction);
5978
6160
  });
5979
6161
  return command;
5980
6162
  }
5981
6163
  function createPrWorkItemsCommand() {
5982
- const command = new Command12("work-items");
6164
+ const command = new Command13("work-items");
5983
6165
  command.description("Manage work items linked to a pull request");
5984
6166
  command.addCommand(buildWorkItemLinkCommand("link", "Link a work item to the pull request", "link"));
5985
6167
  command.addCommand(buildWorkItemLinkCommand("unlink", "Unlink a work item from the pull request", "unlink"));
@@ -6087,15 +6269,56 @@ async function runReviewerRemove(reviewer, options) {
6087
6269
  handlePrCommandError(err, context, "write");
6088
6270
  }
6089
6271
  }
6272
+ function formatReviewerLine(reviewer) {
6273
+ const name = reviewer.displayName ?? reviewer.uniqueName ?? reviewer.id;
6274
+ const unique = reviewer.uniqueName && reviewer.uniqueName !== name ? ` <${reviewer.uniqueName}>` : "";
6275
+ const kind = reviewer.isRequired ? "required" : "optional";
6276
+ const declined = reviewer.hasDeclined ? ", declined" : "";
6277
+ return `${name}${unique} \u2014 ${reviewer.voteState} (${kind}${declined})`;
6278
+ }
6279
+ async function runReviewerList(options) {
6280
+ let context;
6281
+ try {
6282
+ const target = await resolvePullRequestTarget(options, {
6283
+ onContextResolved: (resolved) => {
6284
+ context = resolved;
6285
+ }
6286
+ });
6287
+ if (target === null) {
6288
+ return;
6289
+ }
6290
+ const reviewers = await getPullRequestReviewers(target.context, target.repo, target.pat, target.pullRequest.id);
6291
+ const result = { pullRequestId: target.pullRequest.id, reviewers };
6292
+ if (options.json) {
6293
+ process.stdout.write(`${JSON.stringify(result, null, 2)}
6294
+ `);
6295
+ return;
6296
+ }
6297
+ if (reviewers.length === 0) {
6298
+ process.stdout.write(`No reviewers on pull request #${target.pullRequest.id}.
6299
+ `);
6300
+ return;
6301
+ }
6302
+ process.stdout.write(`${reviewers.map(formatReviewerLine).join("\n")}
6303
+ `);
6304
+ } catch (err) {
6305
+ handlePrCommandError(err, context, "read");
6306
+ }
6307
+ }
6090
6308
  function createPrReviewersCommand() {
6091
- const command = new Command12("reviewers");
6309
+ const command = new Command13("reviewers");
6092
6310
  command.description("Manage pull request reviewers");
6093
- const add = new Command12("add");
6311
+ const list = new Command13("list");
6312
+ withCommonPrOptions(configureUnwrappedHelp(list)).description("List the pull request reviewers with their votes (approved, waiting-for-author, \u2026) and required flag").option("--pr-number <N>", PR_NUMBER_HELP).option("--json", "output JSON").action(async (_options, command2) => {
6313
+ await runReviewerList(mergedPrOptions(command2));
6314
+ });
6315
+ command.addCommand(list);
6316
+ const add = new Command13("add");
6094
6317
  withCommonPrOptions(configureUnwrappedHelp(add)).description("Add a reviewer to the pull request (optional by default)").argument("<reviewer>", "reviewer email or unique name").option("--required", "mark the reviewer as required instead of optional").option("--pr-number <N>", PR_NUMBER_HELP).option("--json", "output JSON").action(async (reviewer, _options, command2) => {
6095
6318
  await runReviewerAdd(reviewer, mergedPrOptions(command2));
6096
6319
  });
6097
6320
  command.addCommand(add);
6098
- const remove = new Command12("remove");
6321
+ const remove = new Command13("remove");
6099
6322
  withCommonPrOptions(configureUnwrappedHelp(remove)).description("Remove a reviewer from the pull request").argument("<reviewer>", "reviewer email or unique name").option("--pr-number <N>", PR_NUMBER_HELP).option("--json", "output JSON").action(async (reviewer, _options, command2) => {
6100
6323
  await runReviewerRemove(reviewer, mergedPrOptions(command2));
6101
6324
  });
@@ -6103,7 +6326,7 @@ function createPrReviewersCommand() {
6103
6326
  return command;
6104
6327
  }
6105
6328
  function createPrCommand() {
6106
- const command = new Command12("pr");
6329
+ const command = new Command13("pr");
6107
6330
  command.description("Manage Azure DevOps pull requests");
6108
6331
  command.addCommand(createPrListCommand());
6109
6332
  command.addCommand(createPrStatusCommand());
@@ -6124,7 +6347,7 @@ function createPrCommand() {
6124
6347
  }
6125
6348
 
6126
6349
  // src/commands/pipeline.ts
6127
- import { Command as Command13 } from "commander";
6350
+ import { Command as Command14 } from "commander";
6128
6351
 
6129
6352
  // src/services/pipeline-client.ts
6130
6353
  var API_VERSION = "7.1";
@@ -6499,7 +6722,7 @@ function formatTable(rows, rightAlign = /* @__PURE__ */ new Set()) {
6499
6722
  ).join("\n");
6500
6723
  }
6501
6724
  function createPipelineListCommand() {
6502
- const command = new Command13("list");
6725
+ const command = new Command14("list");
6503
6726
  command.description("List Azure DevOps pipeline definitions").option("--org <org>", "Azure DevOps organization").option("--project <project>", "Azure DevOps project").option("--filter <name>", "filter definitions by name (case-insensitive substring)").option("--json", "output JSON").action(async (options) => {
6504
6727
  validateOrgProjectPair(options);
6505
6728
  let context;
@@ -6571,7 +6794,7 @@ function parseGetRunsInputs(defIdRaw, options) {
6571
6794
  return { defId, limit: limit ?? 10, prNumber };
6572
6795
  }
6573
6796
  function createPipelineGetRunsCommand() {
6574
- const command = new Command13("get-runs");
6797
+ const command = new Command14("get-runs");
6575
6798
  command.description("List recent runs for a pipeline definition (newest first)").argument("[def_id]", "pipeline definition id (optional with --commit or --pr)").option("--org <org>", "Azure DevOps organization").option("--project <project>", "Azure DevOps project").option("--limit <n>", "maximum number of runs to show (default 10)").option("--branch <branch>", "only show runs for this source branch").option("--commit <sha>", "only show runs that built this commit (full or abbreviated SHA)").option("--pr <number>", "only show runs for this pull request").option("--json", "output JSON").action(async (defIdRaw, options) => {
6576
6799
  validateOrgProjectPair(options);
6577
6800
  const inputs = parseGetRunsInputs(defIdRaw, options);
@@ -6626,7 +6849,7 @@ function applyWaitExitCode(result) {
6626
6849
  }
6627
6850
  }
6628
6851
  function createPipelineWaitCommand() {
6629
- const command = new Command13("wait");
6852
+ const command = new Command14("wait");
6630
6853
  command.description("Wait for a pipeline run to finish; exit code reflects the result (0 success, non-zero otherwise)").argument("<run_id>", "pipeline run id").option("--org <org>", "Azure DevOps organization").option("--project <project>", "Azure DevOps project").option("--timeout <seconds>", "maximum seconds to wait (default 1800)").option("--poll-interval <seconds>", "seconds between status checks (default 5)").option("--json", "output JSON").action(async (runIdRaw, options) => {
6631
6854
  validateOrgProjectPair(options);
6632
6855
  const runId = parsePositiveId(runIdRaw);
@@ -6754,7 +6977,7 @@ function formatRunDetail(detail) {
6754
6977
  ].join("\n");
6755
6978
  }
6756
6979
  function createPipelineGetRunDetailCommand() {
6757
- const command = new Command13("get-run-detail");
6980
+ const command = new Command14("get-run-detail");
6758
6981
  command.description("Show a detailed summary of a single pipeline run (errors, failing tests, stages)").argument("<run_id>", "pipeline run id").option("--org <org>", "Azure DevOps organization").option("--project <project>", "Azure DevOps project").option("--json", "output JSON").action(async (runIdRaw, options) => {
6759
6982
  validateOrgProjectPair(options);
6760
6983
  const runId = parsePositiveId(runIdRaw);
@@ -6887,7 +7110,7 @@ function printSingleLog(content, filters) {
6887
7110
  `);
6888
7111
  }
6889
7112
  function createPipelineLogsCommand() {
6890
- const command = new Command13("logs");
7113
+ const command = new Command14("logs");
6891
7114
  command.description("List a pipeline run's logs, or print a specific log with --log-id").argument("<run_id>", "pipeline run id").option("--org <org>", "Azure DevOps organization").option("--project <project>", "Azure DevOps project").option("--log-id <id>", "print the content of this log id").option("--step <name>", "print the log of the step/job matching this name (case-insensitive substring)").option("--tail <n>", "with --log-id/--step, print only the last N lines").option("--grep <pattern>", "with --log-id/--step, print only lines matching this regular expression").option("--context <n>", "with --grep, also print N lines around each match (grep -C)").option("--json", "output JSON").action(async (runIdRaw, options) => {
6892
7115
  validateOrgProjectPair(options);
6893
7116
  const runId = parsePositiveId(runIdRaw);
@@ -6938,7 +7161,7 @@ function createPipelineLogsCommand() {
6938
7161
  return command;
6939
7162
  }
6940
7163
  function createPipelineTestsCommand() {
6941
- const command = new Command13("tests");
7164
+ const command = new Command14("tests");
6942
7165
  command.description("Show a run's test results: summary plus failing tests by name (no log grepping needed)").argument("<run_id>", "pipeline run id").option("--org <org>", "Azure DevOps organization").option("--project <project>", "Azure DevOps project").option("--failed", "list only the failing tests").option("--json", "output JSON").action(async (runIdRaw, options) => {
6943
7166
  validateOrgProjectPair(options);
6944
7167
  const runId = parsePositiveId(runIdRaw);
@@ -6995,7 +7218,7 @@ function collectParameter(value, previous) {
6995
7218
  return previous.concat([value]);
6996
7219
  }
6997
7220
  function createPipelineStartCommand() {
6998
- const command = new Command13("start");
7221
+ const command = new Command14("start");
6999
7222
  command.description("Queue a new run of a pipeline definition").argument("<def_id>", "pipeline definition id").option("--org <org>", "Azure DevOps organization").option("--project <project>", "Azure DevOps project").option("--branch <branch>", "branch to run against (default: pipeline default branch)").option("--parameter <key=value>", "template parameter (repeatable)", collectParameter, []).option("--json", "output JSON").action(async (defIdRaw, options) => {
7000
7223
  validateOrgProjectPair(options);
7001
7224
  const defId = parsePositiveId(defIdRaw);
@@ -7031,7 +7254,7 @@ ${result.webUrl ?? "\u2014"}
7031
7254
  return command;
7032
7255
  }
7033
7256
  function createPipelineCommand() {
7034
- const command = new Command13("pipeline");
7257
+ const command = new Command14("pipeline");
7035
7258
  command.description("Manage Azure DevOps pipelines");
7036
7259
  command.addCommand(createPipelineListCommand());
7037
7260
  command.addCommand(createPipelineGetRunsCommand());
@@ -7044,7 +7267,7 @@ function createPipelineCommand() {
7044
7267
  }
7045
7268
 
7046
7269
  // src/commands/comments.ts
7047
- import { Command as Command14 } from "commander";
7270
+ import { Command as Command15 } from "commander";
7048
7271
  function writeError3(message) {
7049
7272
  process.stderr.write(`Error: ${message}
7050
7273
  `);
@@ -7064,7 +7287,7 @@ function formatComments(result, convertMarkdown) {
7064
7287
  return lines.join("\n");
7065
7288
  }
7066
7289
  function createCommentsListCommand() {
7067
- const command = new Command14("list");
7290
+ const command = new Command15("list");
7068
7291
  command.description("List visible comments for a work item").argument("<id>", "work item ID").option("--org <org>", "Azure DevOps organization").option("--project <project>", "Azure DevOps project").option("--json", "output JSON").option("--markdown", "convert HTML comment bodies to markdown").action(async (idStr, options) => {
7069
7292
  validateOrgProjectPair(options);
7070
7293
  const id = parseWorkItemId(idStr);
@@ -7092,7 +7315,7 @@ function createCommentsListCommand() {
7092
7315
  return command;
7093
7316
  }
7094
7317
  function createCommentsAddCommand() {
7095
- const command = new Command14("add");
7318
+ const command = new Command15("add");
7096
7319
  command.description("Add a comment to a work item").argument("<id>", "work item ID").argument("<text>", "comment text").option("--org <org>", "Azure DevOps organization").option("--project <project>", "Azure DevOps project").option("--json", "output JSON").option("--markdown", "post comment as markdown").action(async (idStr, text, options) => {
7097
7320
  validateOrgProjectPair(options);
7098
7321
  const id = parseWorkItemId(idStr);
@@ -7119,7 +7342,7 @@ function createCommentsAddCommand() {
7119
7342
  return command;
7120
7343
  }
7121
7344
  function createCommentsCommand() {
7122
- const command = new Command14("comments");
7345
+ const command = new Command15("comments");
7123
7346
  command.description("Manage Azure DevOps work item comments");
7124
7347
  command.addCommand(createCommentsListCommand());
7125
7348
  command.addCommand(createCommentsAddCommand());
@@ -7127,12 +7350,12 @@ function createCommentsCommand() {
7127
7350
  }
7128
7351
 
7129
7352
  // src/commands/download-attachment.ts
7130
- import { Command as Command15 } from "commander";
7353
+ import { Command as Command16 } from "commander";
7131
7354
  import { writeFile as writeFile2 } from "fs/promises";
7132
7355
  import { existsSync as existsSync6 } from "fs";
7133
7356
  import { join as join3 } from "path";
7134
7357
  function createDownloadAttachmentCommand() {
7135
- const command = new Command15("download-attachment");
7358
+ const command = new Command16("download-attachment");
7136
7359
  command.description("Download an attachment from an Azure DevOps work item").argument("<id>", "work item ID").argument("<filename>", "name of the attachment to download").option("--org <org>", "Azure DevOps organization").option("--project <project>", "Azure DevOps project").option("--output <dir>", "target directory for the downloaded file").action(
7137
7360
  async (idStr, filename, options) => {
7138
7361
  const id = parseWorkItemId(idStr);
@@ -7174,12 +7397,12 @@ function createDownloadAttachmentCommand() {
7174
7397
  }
7175
7398
 
7176
7399
  // src/commands/add-attachment.ts
7177
- import { Command as Command16 } from "commander";
7400
+ import { Command as Command17 } from "commander";
7178
7401
  import { existsSync as existsSync7, statSync } from "fs";
7179
7402
  import { readFile } from "fs/promises";
7180
7403
  import { basename } from "path";
7181
7404
  function createAddAttachmentCommand() {
7182
- const command = new Command16("add-attachment");
7405
+ const command = new Command17("add-attachment");
7183
7406
  command.description("Attach a local file to an Azure DevOps work item").argument("<id>", "work item ID").argument("<file>", "path to the local file to upload").option("--comment <text>", "optional comment to store with the attachment").option("--org <org>", "Azure DevOps organization").option("--project <project>", "Azure DevOps project").action(
7184
7407
  async (idStr, file, options) => {
7185
7408
  const id = parseWorkItemId(idStr);
@@ -7226,12 +7449,12 @@ function createAddAttachmentCommand() {
7226
7449
  }
7227
7450
 
7228
7451
  // src/commands/delete-attachment.ts
7229
- import { Command as Command17 } from "commander";
7452
+ import { Command as Command18 } from "commander";
7230
7453
  function formatUploadDate(iso) {
7231
7454
  return iso ? iso.slice(0, 10) : "unknown date";
7232
7455
  }
7233
7456
  function createDeleteAttachmentCommand() {
7234
- const command = new Command17("delete-attachment");
7457
+ const command = new Command18("delete-attachment");
7235
7458
  command.description("Remove an attachment from an Azure DevOps work item").argument("<id>", "work item ID").argument("<filename>", "name of the attachment to remove").option("--id <attachmentId>", "attachment GUID, to disambiguate when the filename is shared by more than one attachment").option("-y, --yes", "skip the interactive confirmation prompt").option("--org <org>", "Azure DevOps organization").option("--project <project>", "Azure DevOps project").action(
7236
7459
  async (idStr, filename, options) => {
7237
7460
  const id = parseWorkItemId(idStr);
@@ -7308,7 +7531,7 @@ function createDeleteAttachmentCommand() {
7308
7531
  }
7309
7532
 
7310
7533
  // src/commands/relations.ts
7311
- import { Command as Command18 } from "commander";
7534
+ import { Command as Command19 } from "commander";
7312
7535
 
7313
7536
  // src/services/relations-client.ts
7314
7537
  var API_VERSION2 = "7.1";
@@ -7525,7 +7748,7 @@ function parsePositiveInt(value, label) {
7525
7748
  return n;
7526
7749
  }
7527
7750
  function createRelationsCommand() {
7528
- const relations = new Command18("relations").description("Manage work item relations");
7751
+ const relations = new Command19("relations").description("Manage work item relations");
7529
7752
  addCommonOptions(
7530
7753
  relations.command("types").description("List all available work item relation types")
7531
7754
  ).action(async (opts) => {
@@ -7720,11 +7943,12 @@ async function getUpdateNotice(opts) {
7720
7943
 
7721
7944
  // src/program.ts
7722
7945
  function createProgram() {
7723
- const program2 = new Command19();
7946
+ const program2 = new Command20();
7724
7947
  program2.name("azdo").description("Azure DevOps CLI tool").version(version, "-v, --version");
7725
7948
  program2.option("--no-update-check", "Skip the check for a newer published version");
7726
7949
  program2.option("--trace <filepath>", "Append redacted HTTP request/response trace to a file (owner-read-only permissions)");
7727
7950
  program2.addCommand(createGetItemCommand());
7951
+ program2.addCommand(createListItemsCommand());
7728
7952
  program2.addCommand(createAuthCommand());
7729
7953
  program2.addCommand(createClearPatCommand());
7730
7954
  program2.addCommand(createConfigCommand());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "azdo-cli",
3
- "version": "0.22.0-develop.790",
3
+ "version": "0.22.0-develop.798",
4
4
  "description": "Azure DevOps CLI tool",
5
5
  "type": "module",
6
6
  "bin": {