@crypto512/jicon-mcp 2.2.1 → 2.3.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PROMPT.md +10 -28
- package/README.md +39 -6
- package/TOOL_LIST.md +542 -407
- package/dist/config/constants.d.ts +28 -0
- package/dist/config/constants.d.ts.map +1 -1
- package/dist/config/constants.js +34 -0
- package/dist/config/constants.js.map +1 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +12 -2
- package/dist/config/loader.js.map +1 -1
- package/dist/config/types.d.ts +49 -6
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js +18 -0
- package/dist/config/types.js.map +1 -1
- package/dist/confluence/client.d.ts.map +1 -1
- package/dist/confluence/client.js +7 -2
- package/dist/confluence/client.js.map +1 -1
- package/dist/confluence/formatters.d.ts +20 -0
- package/dist/confluence/formatters.d.ts.map +1 -1
- package/dist/confluence/formatters.js +74 -8
- package/dist/confluence/formatters.js.map +1 -1
- package/dist/confluence/tools.d.ts +16 -20
- package/dist/confluence/tools.d.ts.map +1 -1
- package/dist/confluence/tools.js +71 -68
- package/dist/confluence/tools.js.map +1 -1
- package/dist/credentials/extractor.d.ts +15 -5
- package/dist/credentials/extractor.d.ts.map +1 -1
- package/dist/credentials/extractor.js +99 -12
- package/dist/credentials/extractor.js.map +1 -1
- package/dist/credentials/index.d.ts +4 -3
- package/dist/credentials/index.d.ts.map +1 -1
- package/dist/credentials/index.js +3 -2
- package/dist/credentials/index.js.map +1 -1
- package/dist/credentials/types.d.ts +22 -0
- package/dist/credentials/types.d.ts.map +1 -1
- package/dist/credentials/types.js.map +1 -1
- package/dist/index.js +211 -176
- package/dist/index.js.map +1 -1
- package/dist/jira/activity-tools.d.ts +8 -15
- package/dist/jira/activity-tools.d.ts.map +1 -1
- package/dist/jira/activity-tools.js +131 -90
- package/dist/jira/activity-tools.js.map +1 -1
- package/dist/jira/client.d.ts +24 -0
- package/dist/jira/client.d.ts.map +1 -1
- package/dist/jira/client.js +65 -6
- package/dist/jira/client.js.map +1 -1
- package/dist/jira/formatters.d.ts +61 -0
- package/dist/jira/formatters.d.ts.map +1 -1
- package/dist/jira/formatters.js +83 -11
- package/dist/jira/formatters.js.map +1 -1
- package/dist/jira/tools.d.ts +78 -26
- package/dist/jira/tools.d.ts.map +1 -1
- package/dist/jira/tools.js +293 -130
- package/dist/jira/tools.js.map +1 -1
- package/dist/permissions/filter.d.ts.map +1 -1
- package/dist/permissions/filter.js +8 -4
- package/dist/permissions/filter.js.map +1 -1
- package/dist/permissions/tool-registry.d.ts +15 -13
- package/dist/permissions/tool-registry.d.ts.map +1 -1
- package/dist/permissions/tool-registry.js +19 -10
- package/dist/permissions/tool-registry.js.map +1 -1
- package/dist/session/context.d.ts +81 -0
- package/dist/session/context.d.ts.map +1 -0
- package/dist/session/context.js +107 -0
- package/dist/session/context.js.map +1 -0
- package/dist/session/index.d.ts +12 -0
- package/dist/session/index.d.ts.map +1 -0
- package/dist/session/index.js +22 -0
- package/dist/session/index.js.map +1 -0
- package/dist/session/manager.d.ts +186 -0
- package/dist/session/manager.d.ts.map +1 -0
- package/dist/session/manager.js +383 -0
- package/dist/session/manager.js.map +1 -0
- package/dist/tempo/client.d.ts +14 -0
- package/dist/tempo/client.d.ts.map +1 -1
- package/dist/tempo/client.js +57 -0
- package/dist/tempo/client.js.map +1 -1
- package/dist/tempo/formatters.d.ts +13 -0
- package/dist/tempo/formatters.d.ts.map +1 -1
- package/dist/tempo/formatters.js +106 -20
- package/dist/tempo/formatters.js.map +1 -1
- package/dist/tempo/tools.d.ts +14 -13
- package/dist/tempo/tools.d.ts.map +1 -1
- package/dist/tempo/tools.js +203 -33
- package/dist/tempo/tools.js.map +1 -1
- package/dist/tempo/types.d.ts +20 -6
- package/dist/tempo/types.d.ts.map +1 -1
- package/dist/transport/http.d.ts +21 -5
- package/dist/transport/http.d.ts.map +1 -1
- package/dist/transport/http.js +193 -22
- package/dist/transport/http.js.map +1 -1
- package/dist/transport/index.d.ts +7 -2
- package/dist/transport/index.d.ts.map +1 -1
- package/dist/transport/index.js +10 -4
- package/dist/transport/index.js.map +1 -1
- package/dist/utils/buffer-tools.d.ts +48 -724
- package/dist/utils/buffer-tools.d.ts.map +1 -1
- package/dist/utils/buffer-tools.js +337 -170
- package/dist/utils/buffer-tools.js.map +1 -1
- package/dist/utils/content-buffer.d.ts +10 -31
- package/dist/utils/content-buffer.d.ts.map +1 -1
- package/dist/utils/content-buffer.js +12 -86
- package/dist/utils/content-buffer.js.map +1 -1
- package/dist/utils/http-client.d.ts.map +1 -1
- package/dist/utils/http-client.js +99 -2
- package/dist/utils/http-client.js.map +1 -1
- package/dist/utils/jicon-help.d.ts +3 -3
- package/dist/utils/jicon-help.d.ts.map +1 -1
- package/dist/utils/jicon-help.js +164 -312
- package/dist/utils/jicon-help.js.map +1 -1
- package/dist/utils/logger.d.ts +43 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +102 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/plantuml/tools.d.ts.map +1 -1
- package/dist/utils/plantuml/tools.js +10 -9
- package/dist/utils/plantuml/tools.js.map +1 -1
- package/dist/utils/response-formatter.d.ts +20 -2
- package/dist/utils/response-formatter.d.ts.map +1 -1
- package/dist/utils/response-formatter.js +147 -17
- package/dist/utils/response-formatter.js.map +1 -1
- package/dist/utils/sandbox/formatters.d.ts +25 -0
- package/dist/utils/sandbox/formatters.d.ts.map +1 -0
- package/dist/utils/sandbox/formatters.js +690 -0
- package/dist/utils/sandbox/formatters.js.map +1 -0
- package/dist/utils/sandbox/helpers.d.ts +16 -0
- package/dist/utils/sandbox/helpers.d.ts.map +1 -0
- package/dist/utils/sandbox/helpers.js +252 -0
- package/dist/utils/sandbox/helpers.js.map +1 -0
- package/dist/utils/sandbox/index.d.ts +19 -0
- package/dist/utils/sandbox/index.d.ts.map +1 -0
- package/dist/utils/sandbox/index.js +269 -0
- package/dist/utils/sandbox/index.js.map +1 -0
- package/dist/utils/sandbox/schema.d.ts +55 -0
- package/dist/utils/sandbox/schema.d.ts.map +1 -0
- package/dist/utils/sandbox/schema.js +39 -0
- package/dist/utils/sandbox/schema.js.map +1 -0
- package/dist/utils/sandbox/types.d.ts +179 -0
- package/dist/utils/sandbox/types.d.ts.map +1 -0
- package/dist/utils/sandbox/types.js +8 -0
- package/dist/utils/sandbox/types.js.map +1 -0
- package/dist/utils/schemas/confluence.d.ts +41 -0
- package/dist/utils/schemas/confluence.d.ts.map +1 -0
- package/dist/utils/schemas/confluence.js +105 -0
- package/dist/utils/schemas/confluence.js.map +1 -0
- package/dist/utils/schemas/index.d.ts +77 -0
- package/dist/utils/schemas/index.d.ts.map +1 -0
- package/dist/utils/schemas/index.js +107 -0
- package/dist/utils/schemas/index.js.map +1 -0
- package/dist/utils/schemas/jira.d.ts +49 -0
- package/dist/utils/schemas/jira.d.ts.map +1 -0
- package/dist/utils/schemas/jira.js +153 -0
- package/dist/utils/schemas/jira.js.map +1 -0
- package/dist/utils/schemas/tempo.d.ts +29 -0
- package/dist/utils/schemas/tempo.d.ts.map +1 -0
- package/dist/utils/schemas/tempo.js +72 -0
- package/dist/utils/schemas/tempo.js.map +1 -0
- package/dist/utils/whoami-tools.d.ts +17 -0
- package/dist/utils/whoami-tools.d.ts.map +1 -0
- package/dist/utils/whoami-tools.js +90 -0
- package/dist/utils/whoami-tools.js.map +1 -0
- package/dist/utils/xhtml/error-locator.js +5 -5
- package/dist/utils/xhtml/error-locator.js.map +1 -1
- package/package.json +10 -9
- package/dist/credentials/client-factory.d.ts +0 -64
- package/dist/credentials/client-factory.d.ts.map +0 -1
- package/dist/credentials/client-factory.js +0 -110
- package/dist/credentials/client-factory.js.map +0 -1
- package/dist/credentials/context.d.ts +0 -25
- package/dist/credentials/context.d.ts.map +0 -1
- package/dist/credentials/context.js +0 -35
- package/dist/credentials/context.js.map +0 -1
- package/dist/utils/buffer-pipeline/index.d.ts +0 -30
- package/dist/utils/buffer-pipeline/index.d.ts.map +0 -1
- package/dist/utils/buffer-pipeline/index.js +0 -317
- package/dist/utils/buffer-pipeline/index.js.map +0 -1
- package/dist/utils/buffer-pipeline/output/csv.d.ts +0 -20
- package/dist/utils/buffer-pipeline/output/csv.d.ts.map +0 -1
- package/dist/utils/buffer-pipeline/output/csv.js +0 -117
- package/dist/utils/buffer-pipeline/output/csv.js.map +0 -1
- package/dist/utils/buffer-pipeline/output/json.d.ts +0 -16
- package/dist/utils/buffer-pipeline/output/json.d.ts.map +0 -1
- package/dist/utils/buffer-pipeline/output/json.js +0 -48
- package/dist/utils/buffer-pipeline/output/json.js.map +0 -1
- package/dist/utils/buffer-pipeline/output/markdown.d.ts +0 -15
- package/dist/utils/buffer-pipeline/output/markdown.d.ts.map +0 -1
- package/dist/utils/buffer-pipeline/output/markdown.js +0 -105
- package/dist/utils/buffer-pipeline/output/markdown.js.map +0 -1
- package/dist/utils/buffer-pipeline/output/xhtml-list.d.ts +0 -16
- package/dist/utils/buffer-pipeline/output/xhtml-list.d.ts.map +0 -1
- package/dist/utils/buffer-pipeline/output/xhtml-list.js +0 -81
- package/dist/utils/buffer-pipeline/output/xhtml-list.js.map +0 -1
- package/dist/utils/buffer-pipeline/output/xhtml-table.d.ts +0 -15
- package/dist/utils/buffer-pipeline/output/xhtml-table.d.ts.map +0 -1
- package/dist/utils/buffer-pipeline/output/xhtml-table.js +0 -176
- package/dist/utils/buffer-pipeline/output/xhtml-table.js.map +0 -1
- package/dist/utils/buffer-pipeline/schema.d.ts +0 -1878
- package/dist/utils/buffer-pipeline/schema.d.ts.map +0 -1
- package/dist/utils/buffer-pipeline/schema.js +0 -168
- package/dist/utils/buffer-pipeline/schema.js.map +0 -1
- package/dist/utils/buffer-pipeline/stages/filter.d.ts +0 -32
- package/dist/utils/buffer-pipeline/stages/filter.d.ts.map +0 -1
- package/dist/utils/buffer-pipeline/stages/filter.js +0 -208
- package/dist/utils/buffer-pipeline/stages/filter.js.map +0 -1
- package/dist/utils/buffer-pipeline/stages/format.d.ts +0 -45
- package/dist/utils/buffer-pipeline/stages/format.d.ts.map +0 -1
- package/dist/utils/buffer-pipeline/stages/format.js +0 -160
- package/dist/utils/buffer-pipeline/stages/format.js.map +0 -1
- package/dist/utils/buffer-pipeline/stages/group-by.d.ts +0 -25
- package/dist/utils/buffer-pipeline/stages/group-by.d.ts.map +0 -1
- package/dist/utils/buffer-pipeline/stages/group-by.js +0 -190
- package/dist/utils/buffer-pipeline/stages/group-by.js.map +0 -1
- package/dist/utils/buffer-pipeline/stages/select.d.ts +0 -54
- package/dist/utils/buffer-pipeline/stages/select.d.ts.map +0 -1
- package/dist/utils/buffer-pipeline/stages/select.js +0 -228
- package/dist/utils/buffer-pipeline/stages/select.js.map +0 -1
- package/dist/utils/buffer-pipeline/stages/sort.d.ts +0 -20
- package/dist/utils/buffer-pipeline/stages/sort.d.ts.map +0 -1
- package/dist/utils/buffer-pipeline/stages/sort.js +0 -96
- package/dist/utils/buffer-pipeline/stages/sort.js.map +0 -1
- package/dist/utils/buffer-pipeline/types.d.ts +0 -277
- package/dist/utils/buffer-pipeline/types.d.ts.map +0 -1
- package/dist/utils/buffer-pipeline/types.js +0 -8
- package/dist/utils/buffer-pipeline/types.js.map +0 -1
- package/dist/utils/plantuml/docker-manager.d.ts +0 -37
- package/dist/utils/plantuml/docker-manager.d.ts.map +0 -1
- package/dist/utils/plantuml/docker-manager.js +0 -284
- package/dist/utils/plantuml/docker-manager.js.map +0 -1
|
@@ -7,11 +7,16 @@
|
|
|
7
7
|
* - "Any blockers in recent discussions?"
|
|
8
8
|
* - "Summarize team activity this month"
|
|
9
9
|
* - "Analyze Epic PROJ-123 for progress and velocity"
|
|
10
|
+
*
|
|
11
|
+
* All tool handlers use session-scoped clients via getSessionJiraClient()
|
|
12
|
+
* which provides per-session caching and credential isolation.
|
|
10
13
|
*/
|
|
11
14
|
import { z } from "zod";
|
|
12
|
-
import {
|
|
15
|
+
import { getSessionJiraClient } from "../session/context.js";
|
|
16
|
+
import { formatSuccessDirect, formatSuccessJson, formatError, isApiError, getMaxOutputSize, getMaxApiResults, getDefaultPeriod } from "../utils/response-formatter.js";
|
|
13
17
|
import { parseSince } from "../utils/date-tools.js";
|
|
14
18
|
import { formatTimeSpent } from "../utils/time-formatter.js";
|
|
19
|
+
import { formatCommentMetadata } from "./formatters.js";
|
|
15
20
|
/**
|
|
16
21
|
* Build JQL from flexible scoping parameters
|
|
17
22
|
*/
|
|
@@ -25,7 +30,7 @@ function buildScopingJql(params) {
|
|
|
25
30
|
if (params.projectKey) {
|
|
26
31
|
return `project = ${params.projectKey}`;
|
|
27
32
|
}
|
|
28
|
-
throw new Error(
|
|
33
|
+
throw new Error('At least one scoping parameter required: projectKey, jql, or issueKeys. Call help(topic="analysis") for scoping guide.');
|
|
29
34
|
}
|
|
30
35
|
/**
|
|
31
36
|
* Format a date string for display (e.g., "Jan 28 14:30")
|
|
@@ -82,11 +87,73 @@ function truncateText(text, maxLength) {
|
|
|
82
87
|
return text.substring(0, maxLength - 3) + "...";
|
|
83
88
|
}
|
|
84
89
|
/**
|
|
85
|
-
*
|
|
90
|
+
* Sanitize text for use in markdown tables.
|
|
91
|
+
* Removes/replaces characters that break table formatting.
|
|
86
92
|
*/
|
|
87
|
-
|
|
93
|
+
function sanitizeForTable(text) {
|
|
94
|
+
if (!text)
|
|
95
|
+
return "";
|
|
96
|
+
return text
|
|
97
|
+
.replace(/<br\s*\/?>/gi, " ") // Replace <br> tags with space
|
|
98
|
+
.replace(/<[^>]+>/g, "") // Remove other HTML tags
|
|
99
|
+
.replace(/\|/g, "\\|") // Escape pipe characters
|
|
100
|
+
.replace(/\n/g, " ") // Replace newlines with space
|
|
101
|
+
.replace(/\s+/g, " ") // Collapse multiple spaces
|
|
102
|
+
.trim();
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Convert HTML content to Markdown for free-text display (comments, descriptions).
|
|
106
|
+
* Preserves line breaks and basic formatting.
|
|
107
|
+
*/
|
|
108
|
+
function htmlToMarkdown(text) {
|
|
109
|
+
if (!text)
|
|
110
|
+
return "";
|
|
111
|
+
return text
|
|
112
|
+
// Convert block elements to double newlines
|
|
113
|
+
.replace(/<\/p>\s*<p[^>]*>/gi, "\n\n")
|
|
114
|
+
.replace(/<p[^>]*>/gi, "")
|
|
115
|
+
.replace(/<\/p>/gi, "\n\n")
|
|
116
|
+
.replace(/<\/div>\s*<div[^>]*>/gi, "\n\n")
|
|
117
|
+
.replace(/<div[^>]*>/gi, "")
|
|
118
|
+
.replace(/<\/div>/gi, "\n")
|
|
119
|
+
// Convert line breaks
|
|
120
|
+
.replace(/<br\s*\/?>/gi, "\n")
|
|
121
|
+
// Convert lists
|
|
122
|
+
.replace(/<li[^>]*>/gi, "• ")
|
|
123
|
+
.replace(/<\/li>/gi, "\n")
|
|
124
|
+
.replace(/<\/?[uo]l[^>]*>/gi, "\n")
|
|
125
|
+
// Convert basic formatting
|
|
126
|
+
.replace(/<strong[^>]*>|<b[^>]*>/gi, "**")
|
|
127
|
+
.replace(/<\/strong>|<\/b>/gi, "**")
|
|
128
|
+
.replace(/<em[^>]*>|<i[^>]*>/gi, "_")
|
|
129
|
+
.replace(/<\/em>|<\/i>/gi, "_")
|
|
130
|
+
.replace(/<code[^>]*>/gi, "`")
|
|
131
|
+
.replace(/<\/code>/gi, "`")
|
|
132
|
+
// Convert links: <a href="url">text</a> → [text](url)
|
|
133
|
+
.replace(/<a[^>]*href="([^"]*)"[^>]*>([^<]*)<\/a>/gi, "[$2]($1)")
|
|
134
|
+
// Remove remaining HTML tags
|
|
135
|
+
.replace(/<[^>]+>/g, "")
|
|
136
|
+
// Decode common HTML entities
|
|
137
|
+
.replace(/&/g, "&")
|
|
138
|
+
.replace(/</g, "<")
|
|
139
|
+
.replace(/>/g, ">")
|
|
140
|
+
.replace(/"/g, '"')
|
|
141
|
+
.replace(/'/g, "'")
|
|
142
|
+
.replace(/ /g, " ")
|
|
143
|
+
// Clean up excessive whitespace while preserving intentional line breaks
|
|
144
|
+
.replace(/[ \t]+/g, " ") // Collapse horizontal whitespace
|
|
145
|
+
.replace(/\n{3,}/g, "\n\n") // Max 2 consecutive newlines
|
|
146
|
+
.trim();
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Create activity tools using session-scoped clients
|
|
150
|
+
*
|
|
151
|
+
* Tools automatically use the JiraClient from the current session context,
|
|
152
|
+
* which provides per-session caching and credential isolation.
|
|
153
|
+
*/
|
|
154
|
+
export function createActivityTools() {
|
|
88
155
|
const requireClient = () => {
|
|
89
|
-
const client =
|
|
156
|
+
const client = getSessionJiraClient();
|
|
90
157
|
if (!client) {
|
|
91
158
|
throw new Error("Jira is not configured. Provide JIRA_URL and JIRA_API_TOKEN environment variables, or pass credentials via X-Jira-Url and X-Jira-Token headers.");
|
|
92
159
|
}
|
|
@@ -104,14 +171,14 @@ Fetches comments, status changes, priority changes, and assignee changes. Ideal
|
|
|
104
171
|
REQUIRES: At least one scoping parameter (projectKey, jql, or issueKeys)
|
|
105
172
|
RETURNS: Markdown-formatted activity digest with pre-computed summary
|
|
106
173
|
|
|
107
|
-
Example: jira_get_activity_digest(projectKey="ACME", since="
|
|
174
|
+
Example: jira_get_activity_digest(projectKey="ACME", since="30d")`,
|
|
108
175
|
inputSchema: z.object({
|
|
109
176
|
// Flexible scoping - at least one required
|
|
110
177
|
projectKey: z.string().optional().describe("Filter by project key"),
|
|
111
178
|
jql: z.string().optional().describe("Full JQL query for flexible scoping"),
|
|
112
179
|
issueKeys: z.array(z.string()).optional().describe("Specific issue keys to include"),
|
|
113
180
|
// Time range
|
|
114
|
-
since: z.string().optional().describe('Time range: "
|
|
181
|
+
since: z.string().optional().describe('Time range: "7d", "30d", "365d", or ISO date (default: "30d"). Provide explicitly for accurate results.'),
|
|
115
182
|
// Activity types
|
|
116
183
|
includeComments: z.boolean().optional().describe("Include comments (default: true)"),
|
|
117
184
|
includeStatusChanges: z.boolean().optional().describe("Include status changes (default: true)"),
|
|
@@ -119,14 +186,12 @@ Example: jira_get_activity_digest(projectKey="ACME", since="7d")`,
|
|
|
119
186
|
includeAssigneeChanges: z.boolean().optional().describe("Include assignee changes (default: true)"),
|
|
120
187
|
// Output control
|
|
121
188
|
maxActivities: z.number().optional().describe("Maximum activities to return (default: 50)"),
|
|
122
|
-
commentMaxLength: z.number().optional().describe("Max length for comment text (default: 500)"),
|
|
123
189
|
}),
|
|
124
190
|
handler: async (args) => {
|
|
125
191
|
try {
|
|
126
|
-
const since = args.since ||
|
|
192
|
+
const since = args.since || getDefaultPeriod();
|
|
127
193
|
const { dateFrom, dateTo } = parseSince(since);
|
|
128
194
|
const maxActivities = args.maxActivities ?? 50;
|
|
129
|
-
const commentMaxLength = args.commentMaxLength ?? 500;
|
|
130
195
|
// Build scoping JQL
|
|
131
196
|
const scopeJql = buildScopingJql({
|
|
132
197
|
projectKey: args.projectKey,
|
|
@@ -207,7 +272,7 @@ Example: jira_get_activity_digest(projectKey="ACME", since="7d")`,
|
|
|
207
272
|
timestamp: comment.created,
|
|
208
273
|
author: comment.author.displayName,
|
|
209
274
|
details: {
|
|
210
|
-
body:
|
|
275
|
+
body: htmlToMarkdown(comment.body),
|
|
211
276
|
},
|
|
212
277
|
});
|
|
213
278
|
}
|
|
@@ -343,36 +408,36 @@ Example: jira_get_activity_digest(projectKey="ACME", since="7d")`,
|
|
|
343
408
|
},
|
|
344
409
|
},
|
|
345
410
|
jira_get_recent_comments: {
|
|
346
|
-
description: `Get comments across multiple issues for
|
|
411
|
+
description: `Get comments across multiple issues for analysis. Returns buffered data.
|
|
347
412
|
|
|
348
413
|
Ideal for:
|
|
414
|
+
- "Who commented the most on project X?"
|
|
349
415
|
- "Show me recent discussions about authentication"
|
|
350
|
-
- "What are people saying about the new feature?"
|
|
351
416
|
- "Find comments mentioning blockers"
|
|
352
417
|
|
|
353
418
|
REQUIRES: At least one scoping parameter (projectKey, jql, or issueKeys)
|
|
354
|
-
|
|
419
|
+
IMPORTANT: Always provide since — default is 30d. Use "365d" or ISO date for longer history.
|
|
420
|
+
RETURNS: bufferId with comments array (issueKey, author, body, created)
|
|
421
|
+
NEXT: buffer_transform for stats/tables, buffer_grep to search
|
|
355
422
|
|
|
356
|
-
Example: jira_get_recent_comments(projectKey="ACME", since="
|
|
423
|
+
Example: jira_get_recent_comments(projectKey="ACME", since="365d", maxComments=5000)`,
|
|
357
424
|
inputSchema: z.object({
|
|
358
425
|
// Flexible scoping
|
|
359
426
|
projectKey: z.string().optional().describe("Filter by project key"),
|
|
360
427
|
jql: z.string().optional().describe("Full JQL query for flexible scoping"),
|
|
361
428
|
issueKeys: z.array(z.string()).optional().describe("Specific issue keys to include"),
|
|
362
429
|
// Time
|
|
363
|
-
since: z.string().optional().describe('Time range: "
|
|
430
|
+
since: z.string().optional().describe('Time range: "7d", "30d", "365d", or ISO date (default: "30d"). Provide explicitly for accurate results.'),
|
|
364
431
|
// Filtering
|
|
365
432
|
authorKey: z.string().optional().describe("Filter by comment author username"),
|
|
366
433
|
// Output
|
|
367
|
-
maxComments: z.number().optional().describe("Maximum comments to return (default:
|
|
368
|
-
includeContext: z.boolean().optional().describe("Include issue summary/status (default: true)"),
|
|
434
|
+
maxComments: z.number().optional().describe("Maximum comments to return (default: all)"),
|
|
369
435
|
}),
|
|
370
436
|
handler: async (args) => {
|
|
371
437
|
try {
|
|
372
|
-
const since = args.since ||
|
|
438
|
+
const since = args.since || getDefaultPeriod();
|
|
373
439
|
const { dateFrom, dateTo } = parseSince(since);
|
|
374
|
-
const maxComments = args.maxComments ??
|
|
375
|
-
const includeContext = args.includeContext !== false;
|
|
440
|
+
const maxComments = args.maxComments ?? getMaxApiResults();
|
|
376
441
|
// Build scoping JQL
|
|
377
442
|
const scopeJql = buildScopingJql({
|
|
378
443
|
projectKey: args.projectKey,
|
|
@@ -382,11 +447,13 @@ Example: jira_get_recent_comments(projectKey="ACME", since="7d")`,
|
|
|
382
447
|
// Add date filter for updated issues (comments update the issue)
|
|
383
448
|
const fullJql = `${scopeJql} AND updated >= "${dateFrom}" ORDER BY updated DESC`;
|
|
384
449
|
// Search for issues
|
|
385
|
-
const searchResult = await requireClient().searchIssuesAll(fullJql, ["summary", "status"],
|
|
450
|
+
const searchResult = await requireClient().searchIssuesAll(fullJql, ["summary", "status"], getMaxApiResults());
|
|
386
451
|
if (searchResult.issues.length === 0) {
|
|
387
|
-
return
|
|
388
|
-
|
|
389
|
-
|
|
452
|
+
return formatSuccessJson([], {
|
|
453
|
+
resourceType: "jira_comments",
|
|
454
|
+
schemaType: "jira_comment",
|
|
455
|
+
title: "Recent comments: no issues with recent activity found",
|
|
456
|
+
totalComments: 0,
|
|
390
457
|
});
|
|
391
458
|
}
|
|
392
459
|
// Get comments for all issues
|
|
@@ -413,54 +480,28 @@ Example: jira_get_recent_comments(projectKey="ACME", since="7d")`,
|
|
|
413
480
|
// Sort by date (most recent first)
|
|
414
481
|
allComments.sort((a, b) => new Date(b.comment.created).getTime() - new Date(a.comment.created).getTime());
|
|
415
482
|
const limitedComments = allComments.slice(0, maxComments);
|
|
416
|
-
//
|
|
417
|
-
const
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
}
|
|
422
|
-
byIssue.get(issueKey).comments.push(comment);
|
|
423
|
-
}
|
|
424
|
-
// Build markdown output
|
|
483
|
+
// Flatten comments to jira_comment schema with issue context
|
|
484
|
+
const comments = limitedComments.map(({ issueKey, issue, comment }) => formatCommentMetadata(comment, {
|
|
485
|
+
issueKey,
|
|
486
|
+
issueSummary: issue.fields.summary || undefined,
|
|
487
|
+
}));
|
|
425
488
|
const scopeDesc = args.projectKey
|
|
426
489
|
? `Project ${args.projectKey}`
|
|
427
490
|
: args.jql
|
|
428
491
|
? `JQL: ${args.jql.substring(0, 50)}...`
|
|
429
492
|
: `${args.issueKeys?.length || 0} issues`;
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
authors.add(comment.author.displayName);
|
|
443
|
-
const dateTime = formatDisplayDateTime(comment.created);
|
|
444
|
-
// Truncate long comments
|
|
445
|
-
const body = truncateText(comment.body, 500);
|
|
446
|
-
const formattedBody = body.includes("\n")
|
|
447
|
-
? body.split("\n").map((l, i) => (i === 0 ? l : " " + l)).join("\n")
|
|
448
|
-
: body;
|
|
449
|
-
lines.push(`- @${comment.author.displayName} (${dateTime}): "${formattedBody}"`);
|
|
450
|
-
}
|
|
451
|
-
lines.push("");
|
|
452
|
-
}
|
|
453
|
-
// Add summary
|
|
454
|
-
lines.push("---");
|
|
455
|
-
lines.push(`**Total**: ${limitedComments.length} comments across ${byIssue.size} issues`);
|
|
456
|
-
lines.push(`**Unique authors**: ${authors.size}`);
|
|
457
|
-
if (allComments.length > maxComments) {
|
|
458
|
-
lines.push(`**Note**: Showing ${maxComments} of ${allComments.length} comments`);
|
|
459
|
-
}
|
|
460
|
-
const output = lines.join("\n");
|
|
461
|
-
return formatSuccessDirect({
|
|
462
|
-
_directContent: true,
|
|
463
|
-
content: output,
|
|
493
|
+
return formatSuccessJson(comments, {
|
|
494
|
+
resourceType: "jira_comments",
|
|
495
|
+
schemaType: "jira_comment",
|
|
496
|
+
title: `Recent comments: ${scopeDesc} (${dateFrom} to ${dateTo})`,
|
|
497
|
+
totalComments: allComments.length,
|
|
498
|
+
info: {
|
|
499
|
+
period: `${dateFrom} to ${dateTo}`,
|
|
500
|
+
since,
|
|
501
|
+
issuesSearched: searchResult.issues.length,
|
|
502
|
+
totalComments: allComments.length,
|
|
503
|
+
...(allComments.length > maxComments && { limited: `Showing ${maxComments} of ${allComments.length} (increase maxComments)` }),
|
|
504
|
+
},
|
|
464
505
|
});
|
|
465
506
|
}
|
|
466
507
|
catch (error) {
|
|
@@ -479,14 +520,14 @@ Ideal for:
|
|
|
479
520
|
REQUIRES: At least one scoping parameter (projectKey, jql, or issueKeys)
|
|
480
521
|
RETURNS: Markdown-formatted changelog with pre-computed summary
|
|
481
522
|
|
|
482
|
-
Example: jira_get_changelog(projectKey="ACME", since="
|
|
523
|
+
Example: jira_get_changelog(projectKey="ACME", since="30d", fields=["status", "priority"])`,
|
|
483
524
|
inputSchema: z.object({
|
|
484
525
|
// Flexible scoping
|
|
485
526
|
projectKey: z.string().optional().describe("Filter by project key"),
|
|
486
527
|
jql: z.string().optional().describe("Full JQL query for flexible scoping"),
|
|
487
528
|
issueKeys: z.array(z.string()).optional().describe("Specific issue keys to include"),
|
|
488
529
|
// Time
|
|
489
|
-
since: z.string().optional().describe('Time range: "
|
|
530
|
+
since: z.string().optional().describe('Time range: "7d", "30d", "365d", or ISO date (default: "30d"). Provide explicitly for accurate results.'),
|
|
490
531
|
// Filtering
|
|
491
532
|
fields: z.array(z.string()).optional().describe('Fields to track (default: ["status", "priority", "assignee", "resolution"])'),
|
|
492
533
|
// Output
|
|
@@ -494,7 +535,7 @@ Example: jira_get_changelog(projectKey="ACME", since="7d", fields=["status", "pr
|
|
|
494
535
|
}),
|
|
495
536
|
handler: async (args) => {
|
|
496
537
|
try {
|
|
497
|
-
const since = args.since ||
|
|
538
|
+
const since = args.since || getDefaultPeriod();
|
|
498
539
|
const { dateFrom, dateTo } = parseSince(since);
|
|
499
540
|
const userFields = args.fields || ["status", "priority", "assignee", "resolution"];
|
|
500
541
|
const maxChanges = args.maxChanges ?? 50;
|
|
@@ -867,7 +908,7 @@ Example: jira_analyze_epic(issueKey="PROJ-100")`,
|
|
|
867
908
|
issueKey,
|
|
868
909
|
author: comment.author.displayName,
|
|
869
910
|
date: comment.created,
|
|
870
|
-
body:
|
|
911
|
+
body: htmlToMarkdown(comment.body),
|
|
871
912
|
});
|
|
872
913
|
}
|
|
873
914
|
}
|
|
@@ -905,7 +946,7 @@ Example: jira_analyze_epic(issueKey="PROJ-100")`,
|
|
|
905
946
|
const description = rootIssue.fields.description;
|
|
906
947
|
if (description) {
|
|
907
948
|
lines.push("## Description");
|
|
908
|
-
lines.push(
|
|
949
|
+
lines.push(htmlToMarkdown(description));
|
|
909
950
|
lines.push("");
|
|
910
951
|
}
|
|
911
952
|
// Hierarchy breakdown
|
|
@@ -917,7 +958,7 @@ Example: jira_analyze_epic(issueKey="PROJ-100")`,
|
|
|
917
958
|
const completion = metrics.total > 0
|
|
918
959
|
? Math.round((metrics.done / metrics.total) * 100)
|
|
919
960
|
: 0;
|
|
920
|
-
lines.push(`| ${type} | ${metrics.total} | ${metrics.done} | ${metrics.inProgress} | ${metrics.todo} | ${completion}% |`);
|
|
961
|
+
lines.push(`| ${sanitizeForTable(type)} | ${metrics.total} | ${metrics.done} | ${metrics.inProgress} | ${metrics.todo} | ${completion}% |`);
|
|
921
962
|
}
|
|
922
963
|
const totalCompletion = totals.total > 0
|
|
923
964
|
? Math.round((totals.done / totals.total) * 100)
|
|
@@ -985,7 +1026,7 @@ Example: jira_analyze_epic(issueKey="PROJ-100")`,
|
|
|
985
1026
|
lines.push("| Source | Relationship | Target | Project | Status |");
|
|
986
1027
|
lines.push("|--------|--------------|--------|---------|--------|");
|
|
987
1028
|
for (const dep of crossProjectDeps.slice(0, 20)) {
|
|
988
|
-
lines.push(`| ${dep.source} | ${dep.relationship} | ${dep.target} | ${dep.project} | ${dep.status} |`);
|
|
1029
|
+
lines.push(`| ${dep.source} | ${sanitizeForTable(dep.relationship)} | ${dep.target} | ${dep.project} | ${sanitizeForTable(dep.status)} |`);
|
|
989
1030
|
}
|
|
990
1031
|
if (crossProjectDeps.length > 20) {
|
|
991
1032
|
lines.push("");
|
|
@@ -1001,9 +1042,9 @@ Example: jira_analyze_epic(issueKey="PROJ-100")`,
|
|
|
1001
1042
|
const shownComments = recentComments.slice(0, 15);
|
|
1002
1043
|
for (const comment of shownComments) {
|
|
1003
1044
|
const dateStr = formatDisplayDateTime(comment.date);
|
|
1004
|
-
|
|
1045
|
+
// Body already converted via htmlToMarkdown during collection
|
|
1005
1046
|
lines.push(`- **${comment.issueKey}** @${comment.author} (${dateStr}):`);
|
|
1006
|
-
lines.push(` "${body}"`);
|
|
1047
|
+
lines.push(` "${comment.body}"`);
|
|
1007
1048
|
}
|
|
1008
1049
|
if (recentComments.length > 15) {
|
|
1009
1050
|
lines.push(`- *...and ${recentComments.length - 15} more comments*`);
|
|
@@ -1228,10 +1269,10 @@ Example: jira_epic_summary(issueKey="PROJ-100")`,
|
|
|
1228
1269
|
lines.push("| Key | Type | Summary | Status | Assignee |");
|
|
1229
1270
|
lines.push("|-----|------|---------|--------|----------|");
|
|
1230
1271
|
for (const issue of allIssues.slice(0, 50)) {
|
|
1231
|
-
const type = issue.fields.issuetype?.name || "?";
|
|
1232
|
-
const summary = truncateText(issue.fields.summary || "", 50);
|
|
1233
|
-
const status = issue.fields.status?.name || "?";
|
|
1234
|
-
const assignee = issue.fields.assignee?.displayName || "Unassigned";
|
|
1272
|
+
const type = sanitizeForTable(issue.fields.issuetype?.name) || "?";
|
|
1273
|
+
const summary = sanitizeForTable(truncateText(issue.fields.summary || "", 50));
|
|
1274
|
+
const status = sanitizeForTable(issue.fields.status?.name) || "?";
|
|
1275
|
+
const assignee = sanitizeForTable(issue.fields.assignee?.displayName) || "Unassigned";
|
|
1235
1276
|
lines.push(`| ${issue.key} | ${type} | ${summary} | ${status} | ${assignee} |`);
|
|
1236
1277
|
}
|
|
1237
1278
|
if (allIssues.length > 50) {
|
|
@@ -1246,7 +1287,7 @@ Example: jira_epic_summary(issueKey="PROJ-100")`,
|
|
|
1246
1287
|
lines.push("|------|-------|------|-------------|-------|------------|");
|
|
1247
1288
|
for (const [type, metrics] of byType) {
|
|
1248
1289
|
const completion = metrics.total > 0 ? Math.round((metrics.done / metrics.total) * 100) : 0;
|
|
1249
|
-
lines.push(`| ${type} | ${metrics.total} | ${metrics.done} | ${metrics.inProgress} | ${metrics.todo} | ${completion}% |`);
|
|
1290
|
+
lines.push(`| ${sanitizeForTable(type)} | ${metrics.total} | ${metrics.done} | ${metrics.inProgress} | ${metrics.todo} | ${completion}% |`);
|
|
1250
1291
|
}
|
|
1251
1292
|
lines.push(`| **TOTAL** | **${totalIssues}** | **${totalDone}** | **${totalInProgress}** | **${totalTodo}** | **${totalCompletion}%** |`);
|
|
1252
1293
|
lines.push("");
|
|
@@ -1257,7 +1298,7 @@ Example: jira_epic_summary(issueKey="PROJ-100")`,
|
|
|
1257
1298
|
lines.push("| Source | Relationship | Target | Project | Status |");
|
|
1258
1299
|
lines.push("|--------|--------------|--------|---------|--------|");
|
|
1259
1300
|
for (const dep of crossProjectDeps.slice(0, 20)) {
|
|
1260
|
-
lines.push(`| ${dep.source} | ${dep.relationship} | ${dep.target} | ${dep.project} | ${dep.status} |`);
|
|
1301
|
+
lines.push(`| ${dep.source} | ${sanitizeForTable(dep.relationship)} | ${dep.target} | ${dep.project} | ${sanitizeForTable(dep.status)} |`);
|
|
1261
1302
|
}
|
|
1262
1303
|
if (crossProjectDeps.length > 20) {
|
|
1263
1304
|
lines.push("");
|
|
@@ -1483,7 +1524,7 @@ Example: jira_analyze_sprint(sprintId=123)`,
|
|
|
1483
1524
|
issueKey,
|
|
1484
1525
|
author: comment.author.displayName,
|
|
1485
1526
|
date: comment.created,
|
|
1486
|
-
body:
|
|
1527
|
+
body: htmlToMarkdown(comment.body),
|
|
1487
1528
|
});
|
|
1488
1529
|
}
|
|
1489
1530
|
}
|
|
@@ -1522,7 +1563,7 @@ Example: jira_analyze_sprint(sprintId=123)`,
|
|
|
1522
1563
|
lines.push("| Type | Total | Done | In Progress | To Do |");
|
|
1523
1564
|
lines.push("|------|-------|------|-------------|-------|");
|
|
1524
1565
|
for (const [type, metrics] of byType) {
|
|
1525
|
-
lines.push(`| ${type} | ${metrics.total} | ${metrics.done} | ${metrics.inProgress} | ${metrics.todo} |`);
|
|
1566
|
+
lines.push(`| ${sanitizeForTable(type)} | ${metrics.total} | ${metrics.done} | ${metrics.inProgress} | ${metrics.todo} |`);
|
|
1526
1567
|
}
|
|
1527
1568
|
lines.push("");
|
|
1528
1569
|
// Time metrics
|
|
@@ -1549,7 +1590,7 @@ Example: jira_analyze_sprint(sprintId=123)`,
|
|
|
1549
1590
|
// Sort by total issues descending
|
|
1550
1591
|
const sortedAssignees = Array.from(byAssignee.entries()).sort((a, b) => b[1].total - a[1].total);
|
|
1551
1592
|
for (const [assignee, metrics] of sortedAssignees.slice(0, 15)) {
|
|
1552
|
-
lines.push(`| ${assignee} | ${metrics.total} | ${metrics.done} | ${metrics.inProgress} |`);
|
|
1593
|
+
lines.push(`| ${sanitizeForTable(assignee)} | ${metrics.total} | ${metrics.done} | ${metrics.inProgress} |`);
|
|
1553
1594
|
}
|
|
1554
1595
|
if (sortedAssignees.length > 15) {
|
|
1555
1596
|
lines.push(`| *...and ${sortedAssignees.length - 15} more* | | | |`);
|
|
@@ -1561,7 +1602,7 @@ Example: jira_analyze_sprint(sprintId=123)`,
|
|
|
1561
1602
|
lines.push("");
|
|
1562
1603
|
lines.push(`⚠️ **${risks.length} issue${risks.length > 1 ? "s" : ""} at risk:**`);
|
|
1563
1604
|
for (const risk of risks.slice(0, 10)) {
|
|
1564
|
-
lines.push(`- **${risk.issueKey}**: ${risk.detail}`);
|
|
1605
|
+
lines.push(`- **${risk.issueKey}**: ${sanitizeForTable(risk.detail)}`);
|
|
1565
1606
|
}
|
|
1566
1607
|
if (risks.length > 10) {
|
|
1567
1608
|
lines.push(`- *...and ${risks.length - 10} more risks*`);
|
|
@@ -1580,8 +1621,8 @@ Example: jira_analyze_sprint(sprintId=123)`,
|
|
|
1580
1621
|
lines.push("");
|
|
1581
1622
|
for (const comment of recentComments.slice(0, 10)) {
|
|
1582
1623
|
const dateStr = formatDisplayDate(comment.date);
|
|
1583
|
-
|
|
1584
|
-
lines.push(`- **${comment.issueKey}** @${comment.author} (${dateStr}): "${body}"`);
|
|
1624
|
+
// Body already converted via htmlToMarkdown during collection
|
|
1625
|
+
lines.push(`- **${comment.issueKey}** @${comment.author} (${dateStr}): "${comment.body}"`);
|
|
1585
1626
|
}
|
|
1586
1627
|
if (recentComments.length > 10) {
|
|
1587
1628
|
lines.push(`- *...and ${recentComments.length - 10} more comments*`);
|
|
@@ -1592,7 +1633,7 @@ Example: jira_analyze_sprint(sprintId=123)`,
|
|
|
1592
1633
|
lines.push("---");
|
|
1593
1634
|
lines.push("## Summary");
|
|
1594
1635
|
lines.push("");
|
|
1595
|
-
lines.push(`Sprint "${sprint.name}" is **${completionPercent}% complete** with ${statusCounts.inProgress} issues in progress and ${statusCounts.todo} issues remaining.`);
|
|
1636
|
+
lines.push(`Sprint "${sanitizeForTable(sprint.name)}" is **${completionPercent}% complete** with ${statusCounts.inProgress} issues in progress and ${statusCounts.todo} issues remaining.`);
|
|
1596
1637
|
if (daysRemaining > 0) {
|
|
1597
1638
|
lines.push(`**${daysRemaining} days remaining** in the sprint.`);
|
|
1598
1639
|
}
|