@rui.branco/jira-mcp 1.7.2 → 1.7.3

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/index.js +68 -2
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -459,7 +459,73 @@ async function parseInlineFormatting(text, instance = defaultInstance) {
459
459
  nodes.push({ type: "text", text: text.substring(lastIndex) });
460
460
  }
461
461
 
462
- return nodes.length > 0 ? nodes : [{ type: "text", text: text }];
462
+ const finalNodes = nodes.length > 0 ? nodes : [{ type: "text", text }];
463
+ return autoLinkTextNodes(finalNodes, instance);
464
+ }
465
+
466
+ // Post-process plain text nodes: convert bare URLs and bare Jira ticket keys
467
+ // (e.g. PROJ-123) into ADF link nodes. Jira does NOT auto-link plain text in
468
+ // ADF — links must be explicit `link` marks.
469
+ function autoLinkTextNodes(nodes, instance = defaultInstance) {
470
+ const baseUrl = instance && instance.baseUrl;
471
+ const result = [];
472
+ // Bare URL OR Jira wiki-style [text|url] OR bare ticket key (PROJ-123)
473
+ const re = /(\[([^\]|\n]+)\|(https?:\/\/[^\]\s]+)\])|(https?:\/\/[^\s<>()\[\]]+)|(\b[A-Z][A-Z0-9]+-\d+\b)/g;
474
+ for (const node of nodes) {
475
+ if (node.type !== "text" || (node.marks && node.marks.length > 0)) {
476
+ result.push(node);
477
+ continue;
478
+ }
479
+ const text = node.text;
480
+ let last = 0;
481
+ let m;
482
+ re.lastIndex = 0;
483
+ while ((m = re.exec(text)) !== null) {
484
+ if (m.index > last) {
485
+ result.push({ type: "text", text: text.substring(last, m.index) });
486
+ }
487
+ if (m[1]) {
488
+ // [label|url] wiki markup
489
+ result.push({
490
+ type: "text",
491
+ text: m[2],
492
+ marks: [{ type: "link", attrs: { href: m[3] } }],
493
+ });
494
+ } else if (m[4]) {
495
+ // Bare URL — strip trailing punctuation that's unlikely to be part of the URL
496
+ let url = m[4];
497
+ const trailingMatch = url.match(/[.,;:!?]+$/);
498
+ let consumed = m[0].length;
499
+ if (trailingMatch) {
500
+ url = url.substring(0, url.length - trailingMatch[0].length);
501
+ consumed -= trailingMatch[0].length;
502
+ }
503
+ result.push({
504
+ type: "text",
505
+ text: url,
506
+ marks: [{ type: "link", attrs: { href: url } }],
507
+ });
508
+ last = m.index + consumed;
509
+ re.lastIndex = last;
510
+ continue;
511
+ } else if (m[5] && baseUrl) {
512
+ // Bare ticket key
513
+ const key = m[5];
514
+ result.push({
515
+ type: "text",
516
+ text: key,
517
+ marks: [{ type: "link", attrs: { href: `${baseUrl}/browse/${key}` } }],
518
+ });
519
+ } else if (m[5]) {
520
+ result.push({ type: "text", text: m[5] });
521
+ }
522
+ last = m.index + m[0].length;
523
+ }
524
+ if (last < text.length) {
525
+ result.push({ type: "text", text: text.substring(last) });
526
+ }
527
+ }
528
+ return result;
463
529
  }
464
530
 
465
531
  // Parse text with markdown formatting and @mentions, build ADF content
@@ -3831,5 +3897,5 @@ if (require.main === module) {
3831
3897
 
3832
3898
  // Export for testing
3833
3899
  if (typeof module !== "undefined") {
3834
- module.exports = { buildCommentADF, parseInlineFormatting, findJiraTicketKeys, resolveTeamId, fetchJiraTeams, listTeams, searchTeamsViaJql };
3900
+ module.exports = { buildCommentADF, parseInlineFormatting, autoLinkTextNodes, findJiraTicketKeys, resolveTeamId, fetchJiraTeams, listTeams, searchTeamsViaJql };
3835
3901
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rui.branco/jira-mcp",
3
- "version": "1.7.2",
3
+ "version": "1.7.3",
4
4
  "description": "Jira MCP server for Claude Code - fetch tickets, search with JQL, update tickets, manage comments, change status, and get Figma designs",
5
5
  "main": "index.js",
6
6
  "bin": {