azdo-cli 0.2.0-003-cli-settings.19 → 0.2.0-005-md-field-commands.25

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 (2) hide show
  1. package/dist/index.js +607 -2
  2. package/package.json +3 -2
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { Command as Command4 } from "commander";
4
+ import { Command as Command9 } from "commander";
5
5
 
6
6
  // src/version.ts
7
7
  import { readFileSync } from "fs";
@@ -90,6 +90,74 @@ async function getWorkItem(context, id, pat, extraFields) {
90
90
  extraFields: extraFields && extraFields.length > 0 ? buildExtraFields(data.fields, extraFields) : null
91
91
  };
92
92
  }
93
+ async function getWorkItemFieldValue(context, id, pat, fieldName) {
94
+ const url = `https://dev.azure.com/${context.org}/${context.project}/_apis/wit/workitems/${id}?api-version=7.1&fields=${fieldName}`;
95
+ const token = Buffer.from(`:${pat}`).toString("base64");
96
+ let response;
97
+ try {
98
+ response = await fetch(url, {
99
+ headers: {
100
+ Authorization: `Basic ${token}`
101
+ }
102
+ });
103
+ } catch {
104
+ throw new Error("NETWORK_ERROR");
105
+ }
106
+ if (response.status === 401) throw new Error("AUTH_FAILED");
107
+ if (response.status === 403) throw new Error("PERMISSION_DENIED");
108
+ if (response.status === 404) throw new Error("NOT_FOUND");
109
+ if (!response.ok) {
110
+ throw new Error(`HTTP_${response.status}`);
111
+ }
112
+ const data = await response.json();
113
+ const value = data.fields[fieldName];
114
+ if (value === void 0 || value === null || value === "") {
115
+ return null;
116
+ }
117
+ return String(value);
118
+ }
119
+ async function updateWorkItem(context, id, pat, fieldName, operations) {
120
+ const url = `https://dev.azure.com/${context.org}/${context.project}/_apis/wit/workitems/${id}?api-version=7.1`;
121
+ const token = Buffer.from(`:${pat}`).toString("base64");
122
+ let response;
123
+ try {
124
+ response = await fetch(url, {
125
+ method: "PATCH",
126
+ headers: {
127
+ Authorization: `Basic ${token}`,
128
+ "Content-Type": "application/json-patch+json"
129
+ },
130
+ body: JSON.stringify(operations)
131
+ });
132
+ } catch {
133
+ throw new Error("NETWORK_ERROR");
134
+ }
135
+ if (response.status === 401) throw new Error("AUTH_FAILED");
136
+ if (response.status === 403) throw new Error("PERMISSION_DENIED");
137
+ if (response.status === 404) throw new Error("NOT_FOUND");
138
+ if (response.status === 400) {
139
+ let serverMessage = "Unknown error";
140
+ try {
141
+ const body = await response.json();
142
+ if (body.message) serverMessage = body.message;
143
+ } catch {
144
+ }
145
+ throw new Error(`UPDATE_REJECTED: ${serverMessage}`);
146
+ }
147
+ if (!response.ok) {
148
+ throw new Error(`HTTP_${response.status}`);
149
+ }
150
+ const data = await response.json();
151
+ const lastOp = operations[operations.length - 1];
152
+ const fieldValue = lastOp.value ?? null;
153
+ return {
154
+ id: data.id,
155
+ rev: data.rev,
156
+ title: data.fields["System.Title"],
157
+ fieldName,
158
+ fieldValue
159
+ };
160
+ }
93
161
 
94
162
  // src/services/auth.ts
95
163
  import { createInterface } from "readline";
@@ -608,12 +676,549 @@ function createConfigCommand() {
608
676
  return config;
609
677
  }
610
678
 
679
+ // src/commands/set-state.ts
680
+ import { Command as Command4 } from "commander";
681
+ function resolveContext(options) {
682
+ if (options.org && options.project) {
683
+ return { org: options.org, project: options.project };
684
+ }
685
+ const config = loadConfig();
686
+ if (config.org && config.project) {
687
+ return { org: config.org, project: config.project };
688
+ }
689
+ let gitContext = null;
690
+ try {
691
+ gitContext = detectAzdoContext();
692
+ } catch {
693
+ }
694
+ const org = config.org || gitContext?.org;
695
+ const project = config.project || gitContext?.project;
696
+ if (org && project) {
697
+ return { org, project };
698
+ }
699
+ throw new Error(
700
+ 'Could not determine org/project. Use --org and --project flags, work from an Azure DevOps git repo, or run "azdo config set org/project".'
701
+ );
702
+ }
703
+ function createSetStateCommand() {
704
+ const command = new Command4("set-state");
705
+ 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(
706
+ async (idStr, state, options) => {
707
+ const id = parseInt(idStr, 10);
708
+ if (!Number.isInteger(id) || id <= 0) {
709
+ process.stderr.write(
710
+ `Error: Work item ID must be a positive integer. Got: "${idStr}"
711
+ `
712
+ );
713
+ process.exit(1);
714
+ }
715
+ const hasOrg = options.org !== void 0;
716
+ const hasProject = options.project !== void 0;
717
+ if (hasOrg !== hasProject) {
718
+ process.stderr.write(
719
+ "Error: --org and --project must both be provided, or both omitted.\n"
720
+ );
721
+ process.exit(1);
722
+ }
723
+ let context;
724
+ try {
725
+ context = resolveContext(options);
726
+ const credential = await resolvePat();
727
+ const operations = [
728
+ { op: "add", path: "/fields/System.State", value: state }
729
+ ];
730
+ const result = await updateWorkItem(context, id, credential.pat, "System.State", operations);
731
+ if (options.json) {
732
+ process.stdout.write(
733
+ JSON.stringify({
734
+ id: result.id,
735
+ rev: result.rev,
736
+ title: result.title,
737
+ field: result.fieldName,
738
+ value: result.fieldValue
739
+ }) + "\n"
740
+ );
741
+ } else {
742
+ process.stdout.write(`Updated work item ${result.id}: State -> ${state}
743
+ `);
744
+ }
745
+ } catch (err) {
746
+ const error = err instanceof Error ? err : new Error(String(err));
747
+ const msg = error.message;
748
+ if (msg === "AUTH_FAILED") {
749
+ process.stderr.write(
750
+ 'Error: Authentication failed. Check that your PAT is valid and has the "Work Items (Read & Write)" scope.\n'
751
+ );
752
+ } else if (msg === "PERMISSION_DENIED") {
753
+ process.stderr.write(
754
+ `Error: Access denied. Your PAT may lack write permissions for project "${context.project}".
755
+ `
756
+ );
757
+ } else if (msg === "NOT_FOUND") {
758
+ process.stderr.write(
759
+ `Error: Work item ${id} not found in ${context.org}/${context.project}.
760
+ `
761
+ );
762
+ } else if (msg.startsWith("UPDATE_REJECTED:")) {
763
+ const serverMsg = msg.replace("UPDATE_REJECTED: ", "");
764
+ process.stderr.write(`Error: Update rejected: ${serverMsg}
765
+ `);
766
+ } else if (msg === "NETWORK_ERROR") {
767
+ process.stderr.write(
768
+ "Error: Could not connect to Azure DevOps. Check your network connection.\n"
769
+ );
770
+ } else {
771
+ process.stderr.write(`Error: ${msg}
772
+ `);
773
+ }
774
+ process.exit(1);
775
+ }
776
+ }
777
+ );
778
+ return command;
779
+ }
780
+
781
+ // src/commands/assign.ts
782
+ import { Command as Command5 } from "commander";
783
+ function resolveContext2(options) {
784
+ if (options.org && options.project) {
785
+ return { org: options.org, project: options.project };
786
+ }
787
+ const config = loadConfig();
788
+ if (config.org && config.project) {
789
+ return { org: config.org, project: config.project };
790
+ }
791
+ let gitContext = null;
792
+ try {
793
+ gitContext = detectAzdoContext();
794
+ } catch {
795
+ }
796
+ const org = config.org || gitContext?.org;
797
+ const project = config.project || gitContext?.project;
798
+ if (org && project) {
799
+ return { org, project };
800
+ }
801
+ throw new Error(
802
+ 'Could not determine org/project. Use --org and --project flags, work from an Azure DevOps git repo, or run "azdo config set org/project".'
803
+ );
804
+ }
805
+ function createAssignCommand() {
806
+ const command = new Command5("assign");
807
+ 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(
808
+ async (idStr, name, options) => {
809
+ const id = parseInt(idStr, 10);
810
+ if (!Number.isInteger(id) || id <= 0) {
811
+ process.stderr.write(
812
+ `Error: Work item ID must be a positive integer. Got: "${idStr}"
813
+ `
814
+ );
815
+ process.exit(1);
816
+ }
817
+ if (!name && !options.unassign) {
818
+ process.stderr.write(
819
+ "Error: Either provide a user name or use --unassign.\n"
820
+ );
821
+ process.exit(1);
822
+ }
823
+ if (name && options.unassign) {
824
+ process.stderr.write(
825
+ "Error: Cannot provide both a user name and --unassign.\n"
826
+ );
827
+ process.exit(1);
828
+ }
829
+ const hasOrg = options.org !== void 0;
830
+ const hasProject = options.project !== void 0;
831
+ if (hasOrg !== hasProject) {
832
+ process.stderr.write(
833
+ "Error: --org and --project must both be provided, or both omitted.\n"
834
+ );
835
+ process.exit(1);
836
+ }
837
+ let context;
838
+ try {
839
+ context = resolveContext2(options);
840
+ const credential = await resolvePat();
841
+ const value = options.unassign ? "" : name;
842
+ const operations = [
843
+ { op: "add", path: "/fields/System.AssignedTo", value }
844
+ ];
845
+ const result = await updateWorkItem(context, id, credential.pat, "System.AssignedTo", operations);
846
+ if (options.json) {
847
+ process.stdout.write(
848
+ JSON.stringify({
849
+ id: result.id,
850
+ rev: result.rev,
851
+ title: result.title,
852
+ field: result.fieldName,
853
+ value: result.fieldValue
854
+ }) + "\n"
855
+ );
856
+ } else {
857
+ const displayValue = options.unassign ? "(unassigned)" : name;
858
+ process.stdout.write(`Updated work item ${result.id}: Assigned To -> ${displayValue}
859
+ `);
860
+ }
861
+ } catch (err) {
862
+ const error = err instanceof Error ? err : new Error(String(err));
863
+ const msg = error.message;
864
+ if (msg === "AUTH_FAILED") {
865
+ process.stderr.write(
866
+ 'Error: Authentication failed. Check that your PAT is valid and has the "Work Items (Read & Write)" scope.\n'
867
+ );
868
+ } else if (msg === "PERMISSION_DENIED") {
869
+ process.stderr.write(
870
+ `Error: Access denied. Your PAT may lack write permissions for project "${context.project}".
871
+ `
872
+ );
873
+ } else if (msg === "NOT_FOUND") {
874
+ process.stderr.write(
875
+ `Error: Work item ${id} not found in ${context.org}/${context.project}.
876
+ `
877
+ );
878
+ } else if (msg.startsWith("UPDATE_REJECTED:")) {
879
+ const serverMsg = msg.replace("UPDATE_REJECTED: ", "");
880
+ process.stderr.write(`Error: Update rejected: ${serverMsg}
881
+ `);
882
+ } else if (msg === "NETWORK_ERROR") {
883
+ process.stderr.write(
884
+ "Error: Could not connect to Azure DevOps. Check your network connection.\n"
885
+ );
886
+ } else {
887
+ process.stderr.write(`Error: ${msg}
888
+ `);
889
+ }
890
+ process.exit(1);
891
+ }
892
+ }
893
+ );
894
+ return command;
895
+ }
896
+
897
+ // src/commands/set-field.ts
898
+ import { Command as Command6 } from "commander";
899
+
900
+ // src/services/context.ts
901
+ function resolveContext3(options) {
902
+ if (options.org && options.project) {
903
+ return { org: options.org, project: options.project };
904
+ }
905
+ const config = loadConfig();
906
+ if (config.org && config.project) {
907
+ return { org: config.org, project: config.project };
908
+ }
909
+ let gitContext = null;
910
+ try {
911
+ gitContext = detectAzdoContext();
912
+ } catch {
913
+ }
914
+ const org = config.org || gitContext?.org;
915
+ const project = config.project || gitContext?.project;
916
+ if (org && project) {
917
+ return { org, project };
918
+ }
919
+ throw new Error(
920
+ 'Could not determine org/project. Use --org and --project flags, work from an Azure DevOps git repo, or run "azdo config set org/project".'
921
+ );
922
+ }
923
+
924
+ // src/commands/set-field.ts
925
+ function createSetFieldCommand() {
926
+ const command = new Command6("set-field");
927
+ 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(
928
+ async (idStr, field, value, options) => {
929
+ const id = parseInt(idStr, 10);
930
+ if (!Number.isInteger(id) || id <= 0) {
931
+ process.stderr.write(
932
+ `Error: Work item ID must be a positive integer. Got: "${idStr}"
933
+ `
934
+ );
935
+ process.exit(1);
936
+ }
937
+ const hasOrg = options.org !== void 0;
938
+ const hasProject = options.project !== void 0;
939
+ if (hasOrg !== hasProject) {
940
+ process.stderr.write(
941
+ "Error: --org and --project must both be provided, or both omitted.\n"
942
+ );
943
+ process.exit(1);
944
+ }
945
+ let context;
946
+ try {
947
+ context = resolveContext3(options);
948
+ const credential = await resolvePat();
949
+ const operations = [
950
+ { op: "add", path: `/fields/${field}`, value }
951
+ ];
952
+ const result = await updateWorkItem(context, id, credential.pat, field, operations);
953
+ if (options.json) {
954
+ process.stdout.write(
955
+ JSON.stringify({
956
+ id: result.id,
957
+ rev: result.rev,
958
+ title: result.title,
959
+ field: result.fieldName,
960
+ value: result.fieldValue
961
+ }) + "\n"
962
+ );
963
+ } else {
964
+ process.stdout.write(`Updated work item ${result.id}: ${field} -> ${value}
965
+ `);
966
+ }
967
+ } catch (err) {
968
+ const error = err instanceof Error ? err : new Error(String(err));
969
+ const msg = error.message;
970
+ if (msg === "AUTH_FAILED") {
971
+ process.stderr.write(
972
+ 'Error: Authentication failed. Check that your PAT is valid and has the "Work Items (Read & Write)" scope.\n'
973
+ );
974
+ } else if (msg === "PERMISSION_DENIED") {
975
+ process.stderr.write(
976
+ `Error: Access denied. Your PAT may lack write permissions for project "${context.project}".
977
+ `
978
+ );
979
+ } else if (msg === "NOT_FOUND") {
980
+ process.stderr.write(
981
+ `Error: Work item ${id} not found in ${context.org}/${context.project}.
982
+ `
983
+ );
984
+ } else if (msg.startsWith("UPDATE_REJECTED:")) {
985
+ const serverMsg = msg.replace("UPDATE_REJECTED: ", "");
986
+ process.stderr.write(`Error: Update rejected: ${serverMsg}
987
+ `);
988
+ } else if (msg === "NETWORK_ERROR") {
989
+ process.stderr.write(
990
+ "Error: Could not connect to Azure DevOps. Check your network connection.\n"
991
+ );
992
+ } else {
993
+ process.stderr.write(`Error: ${msg}
994
+ `);
995
+ }
996
+ process.exit(1);
997
+ }
998
+ }
999
+ );
1000
+ return command;
1001
+ }
1002
+
1003
+ // src/commands/get-md-field.ts
1004
+ import { Command as Command7 } from "commander";
1005
+
1006
+ // src/services/md-convert.ts
1007
+ import { NodeHtmlMarkdown } from "node-html-markdown";
1008
+
1009
+ // src/services/html-detect.ts
1010
+ var HTML_TAG_REGEX = /<\/?(p|br|div|span|strong|em|b|i|u|a|ul|ol|li|h[1-6]|table|tr|td|th|img|pre|code)\b/i;
1011
+ function isHtml(content) {
1012
+ return HTML_TAG_REGEX.test(content);
1013
+ }
1014
+
1015
+ // src/services/md-convert.ts
1016
+ function htmlToMarkdown(html) {
1017
+ return NodeHtmlMarkdown.translate(html);
1018
+ }
1019
+ function toMarkdown(content) {
1020
+ if (isHtml(content)) {
1021
+ return htmlToMarkdown(content);
1022
+ }
1023
+ return content;
1024
+ }
1025
+
1026
+ // src/commands/get-md-field.ts
1027
+ function createGetMdFieldCommand() {
1028
+ const command = new Command7("get-md-field");
1029
+ 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").action(
1030
+ async (idStr, field, options) => {
1031
+ const id = parseInt(idStr, 10);
1032
+ if (!Number.isInteger(id) || id <= 0) {
1033
+ process.stderr.write(
1034
+ `Error: Work item ID must be a positive integer. Got: "${idStr}"
1035
+ `
1036
+ );
1037
+ process.exit(1);
1038
+ }
1039
+ const hasOrg = options.org !== void 0;
1040
+ const hasProject = options.project !== void 0;
1041
+ if (hasOrg !== hasProject) {
1042
+ process.stderr.write(
1043
+ "Error: --org and --project must both be provided, or both omitted.\n"
1044
+ );
1045
+ process.exit(1);
1046
+ }
1047
+ let context;
1048
+ try {
1049
+ context = resolveContext3(options);
1050
+ const credential = await resolvePat();
1051
+ const value = await getWorkItemFieldValue(context, id, credential.pat, field);
1052
+ if (value === null) {
1053
+ process.stdout.write("\n");
1054
+ } else {
1055
+ process.stdout.write(toMarkdown(value) + "\n");
1056
+ }
1057
+ } catch (err) {
1058
+ const error = err instanceof Error ? err : new Error(String(err));
1059
+ const msg = error.message;
1060
+ if (msg === "AUTH_FAILED") {
1061
+ process.stderr.write(
1062
+ 'Error: Authentication failed. Check that your PAT is valid and has the "Work Items (Read)" scope.\n'
1063
+ );
1064
+ } else if (msg === "PERMISSION_DENIED") {
1065
+ process.stderr.write(
1066
+ `Error: Access denied. Your PAT may lack read permissions for project "${context.project}".
1067
+ `
1068
+ );
1069
+ } else if (msg === "NOT_FOUND") {
1070
+ process.stderr.write(
1071
+ `Error: Work item ${id} not found in ${context.org}/${context.project}.
1072
+ `
1073
+ );
1074
+ } else if (msg === "NETWORK_ERROR") {
1075
+ process.stderr.write(
1076
+ "Error: Could not connect to Azure DevOps. Check your network connection.\n"
1077
+ );
1078
+ } else {
1079
+ process.stderr.write(`Error: ${msg}
1080
+ `);
1081
+ }
1082
+ process.exit(1);
1083
+ }
1084
+ }
1085
+ );
1086
+ return command;
1087
+ }
1088
+
1089
+ // src/commands/set-md-field.ts
1090
+ import { existsSync, readFileSync as readFileSync2 } from "fs";
1091
+ import { Command as Command8 } from "commander";
1092
+ function createSetMdFieldCommand() {
1093
+ const command = new Command8("set-md-field");
1094
+ 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(
1095
+ async (idStr, field, inlineContent, options) => {
1096
+ const id = parseInt(idStr, 10);
1097
+ if (!Number.isInteger(id) || id <= 0) {
1098
+ process.stderr.write(
1099
+ `Error: Work item ID must be a positive integer. Got: "${idStr}"
1100
+ `
1101
+ );
1102
+ process.exit(1);
1103
+ }
1104
+ if (inlineContent && options.file) {
1105
+ process.stderr.write(
1106
+ "Error: Cannot specify both inline content and --file.\n"
1107
+ );
1108
+ process.exit(1);
1109
+ }
1110
+ let content;
1111
+ if (options.file) {
1112
+ if (!existsSync(options.file)) {
1113
+ process.stderr.write(`Error: File not found: ${options.file}
1114
+ `);
1115
+ process.exit(1);
1116
+ }
1117
+ try {
1118
+ content = readFileSync2(options.file, "utf-8");
1119
+ } catch {
1120
+ process.stderr.write(`Error: Cannot read file: ${options.file}
1121
+ `);
1122
+ process.exit(1);
1123
+ }
1124
+ } else if (inlineContent) {
1125
+ content = inlineContent;
1126
+ } else if (!process.stdin.isTTY) {
1127
+ const chunks = [];
1128
+ for await (const chunk of process.stdin) {
1129
+ chunks.push(chunk);
1130
+ }
1131
+ const stdinContent = Buffer.concat(chunks).toString("utf-8").trimEnd();
1132
+ if (!stdinContent) {
1133
+ process.stderr.write(
1134
+ "Error: No content provided via stdin. Pipe markdown content or use inline content or --file.\n"
1135
+ );
1136
+ process.exit(1);
1137
+ }
1138
+ content = stdinContent;
1139
+ } else {
1140
+ process.stderr.write(
1141
+ "Error: No content provided. Pass markdown content as the third argument, use --file, or pipe via stdin.\n"
1142
+ );
1143
+ process.exit(1);
1144
+ }
1145
+ const hasOrg = options.org !== void 0;
1146
+ const hasProject = options.project !== void 0;
1147
+ if (hasOrg !== hasProject) {
1148
+ process.stderr.write(
1149
+ "Error: --org and --project must both be provided, or both omitted.\n"
1150
+ );
1151
+ process.exit(1);
1152
+ }
1153
+ let context;
1154
+ try {
1155
+ context = resolveContext3(options);
1156
+ const credential = await resolvePat();
1157
+ const operations = [
1158
+ { op: "add", path: `/fields/${field}`, value: content },
1159
+ { op: "add", path: `/multilineFieldsFormat/${field}`, value: "Markdown" }
1160
+ ];
1161
+ const result = await updateWorkItem(context, id, credential.pat, field, operations);
1162
+ if (options.json) {
1163
+ process.stdout.write(
1164
+ JSON.stringify({
1165
+ id: result.id,
1166
+ rev: result.rev,
1167
+ field: result.fieldName,
1168
+ value: result.fieldValue
1169
+ }) + "\n"
1170
+ );
1171
+ } else {
1172
+ process.stdout.write(`Updated work item ${result.id}: ${field} set with markdown content
1173
+ `);
1174
+ }
1175
+ } catch (err) {
1176
+ const error = err instanceof Error ? err : new Error(String(err));
1177
+ const msg = error.message;
1178
+ if (msg === "AUTH_FAILED") {
1179
+ process.stderr.write(
1180
+ 'Error: Authentication failed. Check that your PAT is valid and has the "Work Items (Read & Write)" scope.\n'
1181
+ );
1182
+ } else if (msg === "PERMISSION_DENIED") {
1183
+ process.stderr.write(
1184
+ `Error: Access denied. Your PAT may lack write permissions for project "${context.project}".
1185
+ `
1186
+ );
1187
+ } else if (msg === "NOT_FOUND") {
1188
+ process.stderr.write(
1189
+ `Error: Work item ${id} not found in ${context.org}/${context.project}.
1190
+ `
1191
+ );
1192
+ } else if (msg.startsWith("UPDATE_REJECTED:")) {
1193
+ const serverMsg = msg.replace("UPDATE_REJECTED: ", "");
1194
+ process.stderr.write(`Error: Update rejected: ${serverMsg}
1195
+ `);
1196
+ } else if (msg === "NETWORK_ERROR") {
1197
+ process.stderr.write(
1198
+ "Error: Could not connect to Azure DevOps. Check your network connection.\n"
1199
+ );
1200
+ } else {
1201
+ process.stderr.write(`Error: ${msg}
1202
+ `);
1203
+ }
1204
+ process.exit(1);
1205
+ }
1206
+ }
1207
+ );
1208
+ return command;
1209
+ }
1210
+
611
1211
  // src/index.ts
612
- var program = new Command4();
1212
+ var program = new Command9();
613
1213
  program.name("azdo").description("Azure DevOps CLI tool").version(version, "-v, --version");
614
1214
  program.addCommand(createGetItemCommand());
615
1215
  program.addCommand(createClearPatCommand());
616
1216
  program.addCommand(createConfigCommand());
1217
+ program.addCommand(createSetStateCommand());
1218
+ program.addCommand(createAssignCommand());
1219
+ program.addCommand(createSetFieldCommand());
1220
+ program.addCommand(createGetMdFieldCommand());
1221
+ program.addCommand(createSetMdFieldCommand());
617
1222
  program.showHelpAfterError();
618
1223
  program.parse();
619
1224
  if (process.argv.length <= 2) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "azdo-cli",
3
- "version": "0.2.0-003-cli-settings.19",
3
+ "version": "0.2.0-005-md-field-commands.25",
4
4
  "description": "Azure DevOps CLI tool",
5
5
  "type": "module",
6
6
  "bin": {
@@ -23,7 +23,8 @@
23
23
  "license": "MIT",
24
24
  "dependencies": {
25
25
  "@napi-rs/keyring": "^1.2.0",
26
- "commander": "^14.0.3"
26
+ "commander": "^14.0.3",
27
+ "node-html-markdown": "^2.0.0"
27
28
  },
28
29
  "devDependencies": {
29
30
  "@eslint/js": "^10.0.1",