azdo-cli 0.2.0-develop.65 → 0.2.0-develop.71

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 +18 -1
  2. package/dist/index.js +92 -71
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -53,7 +53,7 @@ azdo set-state 12345 "Active"
53
53
 
54
54
  | Command | Purpose | Common Flags |
55
55
  | --- | --- | --- |
56
- | `azdo get-item <id>` | Read a work item | `--short`, `--fields`, `--org`, `--project` |
56
+ | `azdo get-item <id>` | Read a work item | `--short`, `--fields`, `--markdown`, `--org`, `--project` |
57
57
  | `azdo set-state <id> <state>` | Change work item state | `--json`, `--org`, `--project` |
58
58
  | `azdo assign <id> [name]` | Assign or unassign owner | `--unassign`, `--json`, `--org`, `--project` |
59
59
  | `azdo set-field <id> <field> <value>` | Update any field | `--json`, `--org`, `--project` |
@@ -75,6 +75,12 @@ azdo get-item 12345 --short
75
75
 
76
76
  # Include extra fields for this call
77
77
  azdo get-item 12345 --fields "System.Tags,Microsoft.VSTS.Common.Priority"
78
+
79
+ # Convert rich text fields to markdown
80
+ azdo get-item 12345 --markdown
81
+
82
+ # Disable markdown even if config is on
83
+ azdo get-item 12345 --no-markdown
78
84
  ```
79
85
 
80
86
  ```bash
@@ -89,6 +95,14 @@ azdo assign 12345 --unassign
89
95
  azdo set-field 12345 System.Title "Updated title"
90
96
  ```
91
97
 
98
+ ### Markdown Display
99
+
100
+ The `get-item` command can convert HTML rich-text fields to readable markdown. Resolution order:
101
+
102
+ 1. `--markdown` / `--no-markdown` flag (highest priority)
103
+ 2. Config setting: `azdo config set markdown true`
104
+ 3. Default: off (HTML stripped to plain text)
105
+
92
106
  ### Markdown Field Commands
93
107
 
94
108
  ```bash
@@ -114,6 +128,9 @@ azdo config list
114
128
  # Interactive setup
115
129
  azdo config wizard
116
130
 
131
+ # Enable markdown display for all get-item calls
132
+ azdo config set markdown true
133
+
117
134
  # Set/get/unset values
118
135
  azdo config set fields "System.Tags,Custom.Priority"
119
136
  azdo config get fields
package/dist/index.js CHANGED
@@ -336,6 +336,13 @@ var SETTINGS = [
336
336
  type: "string[]",
337
337
  example: "System.Tags,Custom.Priority",
338
338
  required: false
339
+ },
340
+ {
341
+ key: "markdown",
342
+ description: "Convert rich text fields to markdown on display",
343
+ type: "boolean",
344
+ example: "true",
345
+ required: false
339
346
  }
340
347
  ];
341
348
  var VALID_KEYS = SETTINGS.map((s) => s.key);
@@ -369,7 +376,7 @@ function saveConfig(config) {
369
376
  }
370
377
  function validateKey(key) {
371
378
  if (!VALID_KEYS.includes(key)) {
372
- throw new Error(`Unknown setting key "${key}". Valid keys: org, project, fields`);
379
+ throw new Error(`Unknown setting key "${key}". Valid keys: ${VALID_KEYS.join(", ")}`);
373
380
  }
374
381
  }
375
382
  function getConfigValue(key) {
@@ -382,6 +389,11 @@ function setConfigValue(key, value) {
382
389
  const config = loadConfig();
383
390
  if (value === "") {
384
391
  delete config[key];
392
+ } else if (key === "markdown") {
393
+ if (value !== "true" && value !== "false") {
394
+ throw new Error(`Invalid value "${value}" for markdown. Must be "true" or "false".`);
395
+ }
396
+ config.markdown = value === "true";
385
397
  } else if (key === "fields") {
386
398
  config.fields = value.split(",").map((s) => s.trim());
387
399
  } else {
@@ -420,6 +432,61 @@ function resolveContext(options) {
420
432
  );
421
433
  }
422
434
 
435
+ // src/services/md-convert.ts
436
+ import { NodeHtmlMarkdown } from "node-html-markdown";
437
+
438
+ // src/services/html-detect.ts
439
+ var HTML_TAG_REGEX = /<\/?([a-z][a-z0-9]*)\b/gi;
440
+ var HTML_TAGS = /* @__PURE__ */ new Set([
441
+ "p",
442
+ "br",
443
+ "div",
444
+ "span",
445
+ "strong",
446
+ "em",
447
+ "b",
448
+ "i",
449
+ "u",
450
+ "a",
451
+ "ul",
452
+ "ol",
453
+ "li",
454
+ "h1",
455
+ "h2",
456
+ "h3",
457
+ "h4",
458
+ "h5",
459
+ "h6",
460
+ "table",
461
+ "tr",
462
+ "td",
463
+ "th",
464
+ "img",
465
+ "pre",
466
+ "code"
467
+ ]);
468
+ function isHtml(content) {
469
+ let match;
470
+ HTML_TAG_REGEX.lastIndex = 0;
471
+ while ((match = HTML_TAG_REGEX.exec(content)) !== null) {
472
+ if (HTML_TAGS.has(match[1].toLowerCase())) {
473
+ return true;
474
+ }
475
+ }
476
+ return false;
477
+ }
478
+
479
+ // src/services/md-convert.ts
480
+ function htmlToMarkdown(html) {
481
+ return NodeHtmlMarkdown.translate(html);
482
+ }
483
+ function toMarkdown(content) {
484
+ if (isHtml(content)) {
485
+ return htmlToMarkdown(content);
486
+ }
487
+ return content;
488
+ }
489
+
423
490
  // src/services/command-helpers.ts
424
491
  function parseWorkItemId(idStr) {
425
492
  const id = Number.parseInt(idStr, 10);
@@ -508,7 +575,24 @@ function stripHtml(html) {
508
575
  text = text.replace(/\n{3,}/g, "\n\n");
509
576
  return text.trim();
510
577
  }
511
- function formatWorkItem(workItem, short) {
578
+ function convertRichText(html, markdown) {
579
+ if (!html) return "";
580
+ return markdown ? toMarkdown(html) : stripHtml(html);
581
+ }
582
+ function formatExtraFields(extraFields, markdown) {
583
+ return Object.entries(extraFields).map(([refName, value]) => {
584
+ const fieldLabel = refName.includes(".") ? refName.split(".").pop() : refName;
585
+ const displayValue = markdown ? toMarkdown(value) : value;
586
+ return `${fieldLabel.padEnd(13)}${displayValue}`;
587
+ });
588
+ }
589
+ function summarizeDescription(text, label) {
590
+ const descLines = text.split("\n").filter((l) => l.trim() !== "");
591
+ const firstThree = descLines.slice(0, 3);
592
+ const suffix = descLines.length > 3 ? "\n..." : "";
593
+ return [`${label("Description:")}${firstThree.join("\n")}${suffix}`];
594
+ }
595
+ function formatWorkItem(workItem, short, markdown = false) {
512
596
  const lines = [];
513
597
  const label = (name) => name.padEnd(13);
514
598
  lines.push(`${label("ID:")}${workItem.id}`);
@@ -522,19 +606,12 @@ function formatWorkItem(workItem, short) {
522
606
  }
523
607
  lines.push(`${label("URL:")}${workItem.url}`);
524
608
  if (workItem.extraFields) {
525
- for (const [refName, value] of Object.entries(workItem.extraFields)) {
526
- const fieldLabel = refName.includes(".") ? refName.split(".").pop() : refName;
527
- lines.push(`${fieldLabel.padEnd(13)}${value}`);
528
- }
609
+ lines.push(...formatExtraFields(workItem.extraFields, markdown));
529
610
  }
530
611
  lines.push("");
531
- const descriptionText = workItem.description ? stripHtml(workItem.description) : "";
612
+ const descriptionText = convertRichText(workItem.description, markdown);
532
613
  if (short) {
533
- const descLines = descriptionText.split("\n").filter((l) => l.trim() !== "");
534
- const firstThree = descLines.slice(0, 3);
535
- const truncated = descLines.length > 3;
536
- const descSummary = firstThree.join("\n") + (truncated ? "\n..." : "");
537
- lines.push(`${label("Description:")}${descSummary}`);
614
+ lines.push(...summarizeDescription(descriptionText, label));
538
615
  } else {
539
616
  lines.push("Description:");
540
617
  lines.push(descriptionText);
@@ -543,7 +620,7 @@ function formatWorkItem(workItem, short) {
543
620
  }
544
621
  function createGetItemCommand() {
545
622
  const command = new Command("get-item");
546
- command.description("Retrieve an Azure DevOps work item by ID").argument("<id>", "work item ID").option("--org <org>", "Azure DevOps organization").option("--project <project>", "Azure DevOps project").option("--short", "show abbreviated output").option("--fields <fields>", "comma-separated additional field reference names").action(
623
+ command.description("Retrieve an Azure DevOps work item by ID").argument("<id>", "work item ID").option("--org <org>", "Azure DevOps organization").option("--project <project>", "Azure DevOps project").option("--short", "show abbreviated output").option("--fields <fields>", "comma-separated additional field reference names").option("--markdown", "convert rich text fields to markdown").action(
547
624
  async (idStr, options) => {
548
625
  const id = parseWorkItemId(idStr);
549
626
  validateOrgProjectPair(options);
@@ -553,7 +630,8 @@ function createGetItemCommand() {
553
630
  const credential = await resolvePat();
554
631
  const fieldsList = options.fields !== void 0 ? parseRequestedFields(options.fields) : parseRequestedFields(loadConfig().fields);
555
632
  const workItem = await getWorkItem(context, id, credential.pat, fieldsList);
556
- const output = formatWorkItem(workItem, options.short ?? false);
633
+ const markdownEnabled = options.markdown ?? loadConfig().markdown ?? false;
634
+ const output = formatWorkItem(workItem, options.short ?? false, markdownEnabled);
557
635
  process.stdout.write(output + "\n");
558
636
  } catch (err) {
559
637
  handleCommandError(err, id, context, "read", false);
@@ -857,63 +935,6 @@ function createSetFieldCommand() {
857
935
 
858
936
  // src/commands/get-md-field.ts
859
937
  import { Command as Command7 } from "commander";
860
-
861
- // src/services/md-convert.ts
862
- import { NodeHtmlMarkdown } from "node-html-markdown";
863
-
864
- // src/services/html-detect.ts
865
- var HTML_TAG_REGEX = /<\/?([a-z][a-z0-9]*)\b/gi;
866
- var HTML_TAGS = /* @__PURE__ */ new Set([
867
- "p",
868
- "br",
869
- "div",
870
- "span",
871
- "strong",
872
- "em",
873
- "b",
874
- "i",
875
- "u",
876
- "a",
877
- "ul",
878
- "ol",
879
- "li",
880
- "h1",
881
- "h2",
882
- "h3",
883
- "h4",
884
- "h5",
885
- "h6",
886
- "table",
887
- "tr",
888
- "td",
889
- "th",
890
- "img",
891
- "pre",
892
- "code"
893
- ]);
894
- function isHtml(content) {
895
- let match;
896
- HTML_TAG_REGEX.lastIndex = 0;
897
- while ((match = HTML_TAG_REGEX.exec(content)) !== null) {
898
- if (HTML_TAGS.has(match[1].toLowerCase())) {
899
- return true;
900
- }
901
- }
902
- return false;
903
- }
904
-
905
- // src/services/md-convert.ts
906
- function htmlToMarkdown(html) {
907
- return NodeHtmlMarkdown.translate(html);
908
- }
909
- function toMarkdown(content) {
910
- if (isHtml(content)) {
911
- return htmlToMarkdown(content);
912
- }
913
- return content;
914
- }
915
-
916
- // src/commands/get-md-field.ts
917
938
  function createGetMdFieldCommand() {
918
939
  const command = new Command7("get-md-field");
919
940
  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(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "azdo-cli",
3
- "version": "0.2.0-develop.65",
3
+ "version": "0.2.0-develop.71",
4
4
  "description": "Azure DevOps CLI tool",
5
5
  "type": "module",
6
6
  "bin": {