@stubbedev/atlassian-mcp 0.1.1 → 0.1.4
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/dist/bitbucket.js +13 -2
- package/dist/index.js +6 -6
- package/dist/jira.js +12 -1
- package/package.json +1 -1
package/dist/bitbucket.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { execSync } from 'child_process';
|
|
2
|
+
const EMOJI_RE = /\p{Extended_Pictographic}/u;
|
|
2
3
|
function safeExec(cmd) {
|
|
3
4
|
try {
|
|
4
5
|
return execSync(cmd, { encoding: 'utf-8' }).trim();
|
|
@@ -136,6 +137,16 @@ function formatBitbucketError(status, method, path, details) {
|
|
|
136
137
|
return `${prefix}. Conflict (often stale version/state). Refresh and retry. ${details}`.trim();
|
|
137
138
|
return details ? `${prefix}. ${details}` : prefix;
|
|
138
139
|
}
|
|
140
|
+
function validateCommentText(textValue) {
|
|
141
|
+
const trimmed = textValue.trim();
|
|
142
|
+
if (!trimmed) {
|
|
143
|
+
throw new Error('Bitbucket comment text must not be empty.');
|
|
144
|
+
}
|
|
145
|
+
if (EMOJI_RE.test(trimmed)) {
|
|
146
|
+
throw new Error('Bitbucket comments must not include emoji. Use concise plain text only.');
|
|
147
|
+
}
|
|
148
|
+
return trimmed;
|
|
149
|
+
}
|
|
139
150
|
export class BitbucketClient {
|
|
140
151
|
baseUrl;
|
|
141
152
|
headers;
|
|
@@ -510,7 +521,7 @@ export class BitbucketClient {
|
|
|
510
521
|
}
|
|
511
522
|
async addPrComment(args) {
|
|
512
523
|
const { projectKey, repoSlug } = this.resolveProjectAndRepo(args.projectKey, args.repoSlug);
|
|
513
|
-
const body = { text: args.text };
|
|
524
|
+
const body = { text: validateCommentText(args.text) };
|
|
514
525
|
if (args.parentCommentId)
|
|
515
526
|
body.parent = { id: args.parentCommentId };
|
|
516
527
|
const created = await this.request('POST', `/projects/${projectKey}/repos/${repoSlug}/pull-requests/${args.prId}/comments`, body);
|
|
@@ -531,7 +542,7 @@ export class BitbucketClient {
|
|
|
531
542
|
throw new Error(`Comment #${args.commentId} not found.`);
|
|
532
543
|
const body = {
|
|
533
544
|
version: current.version,
|
|
534
|
-
text: args.text
|
|
545
|
+
text: args.text !== undefined ? validateCommentText(args.text) : current.text,
|
|
535
546
|
};
|
|
536
547
|
if (args.state)
|
|
537
548
|
body.state = args.state;
|
package/dist/index.js
CHANGED
|
@@ -162,12 +162,12 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
162
162
|
},
|
|
163
163
|
{
|
|
164
164
|
name: 'jira_add_comment',
|
|
165
|
-
description: 'Use when you want to leave a comment on a Jira ticket.',
|
|
165
|
+
description: 'Use when you want to leave a comment on a Jira ticket. Keep comments concise, plain text, and free of filler. Never include emojis.',
|
|
166
166
|
inputSchema: {
|
|
167
167
|
type: 'object',
|
|
168
168
|
properties: {
|
|
169
169
|
issueKey: { type: 'string', description: 'Jira issue key' },
|
|
170
|
-
body: { type: 'string', description: '
|
|
170
|
+
body: { type: 'string', description: 'Concise comment text only. No filler. Do not include emojis.' },
|
|
171
171
|
},
|
|
172
172
|
required: ['issueKey', 'body'],
|
|
173
173
|
},
|
|
@@ -406,7 +406,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
406
406
|
},
|
|
407
407
|
{
|
|
408
408
|
name: 'bitbucket_add_pr_comment',
|
|
409
|
-
description: 'Use when you want to add a PR review comment or reply to an existing thread. You can pass projectKey/repoSlug or project/repo.',
|
|
409
|
+
description: 'Use when you want to add a PR review comment or reply to an existing thread. Keep comments concise, plain text, and free of filler. Never include emojis. You can pass projectKey/repoSlug or project/repo.',
|
|
410
410
|
inputSchema: {
|
|
411
411
|
type: 'object',
|
|
412
412
|
properties: {
|
|
@@ -416,14 +416,14 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
416
416
|
repo: { type: 'string', description: 'Alias for repoSlug' },
|
|
417
417
|
prId: { type: 'number', description: 'Pull request number (PR ID)' },
|
|
418
418
|
parentCommentId: { type: 'number', description: 'Parent comment ID for reply mode (optional)' },
|
|
419
|
-
text: { type: 'string', description: '
|
|
419
|
+
text: { type: 'string', description: 'Concise comment text only. No filler. Do not include emojis.' },
|
|
420
420
|
},
|
|
421
421
|
required: ['prId', 'text'],
|
|
422
422
|
},
|
|
423
423
|
},
|
|
424
424
|
{
|
|
425
425
|
name: 'bitbucket_update_pr_comment',
|
|
426
|
-
description: 'Use when you want to edit PR comments, resolve/reopen them, or mark comments as task-style BLOCKER items. You can pass projectKey/repoSlug or project/repo.',
|
|
426
|
+
description: 'Use when you want to edit PR comments, resolve/reopen them, or mark comments as task-style BLOCKER items. Keep comments concise, plain text, and free of filler. Never include emojis. You can pass projectKey/repoSlug or project/repo.',
|
|
427
427
|
inputSchema: {
|
|
428
428
|
type: 'object',
|
|
429
429
|
properties: {
|
|
@@ -433,7 +433,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
433
433
|
repo: { type: 'string', description: 'Alias for repoSlug' },
|
|
434
434
|
prId: { type: 'number', description: 'Pull request number (PR ID)' },
|
|
435
435
|
commentId: { type: 'number', description: 'Comment ID to update' },
|
|
436
|
-
text: { type: 'string', description: 'New comment text (optional)' },
|
|
436
|
+
text: { type: 'string', description: 'New concise comment text only. No filler. Do not include emojis. (optional)' },
|
|
437
437
|
state: { type: 'string', enum: ['OPEN', 'RESOLVED'], description: 'Comment state (optional)' },
|
|
438
438
|
severity: { type: 'string', enum: ['NORMAL', 'BLOCKER'], description: 'Comment severity (optional). BLOCKER marks it as a task/checklist item.' },
|
|
439
439
|
},
|
package/dist/jira.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { execSync } from 'child_process';
|
|
2
2
|
const JIRA_KEY_IN_BRANCH_RE = /\b([A-Z][A-Z0-9]+)-\d+\b/;
|
|
3
|
+
const EMOJI_RE = /\p{Extended_Pictographic}/u;
|
|
3
4
|
function text(t) {
|
|
4
5
|
return { content: [{ type: 'text', text: t }] };
|
|
5
6
|
}
|
|
@@ -76,6 +77,16 @@ function formatJiraError(status, method, path, details) {
|
|
|
76
77
|
return `${prefix}. Conflict. Refresh and retry. ${details}`.trim();
|
|
77
78
|
return details ? `${prefix}. ${details}` : prefix;
|
|
78
79
|
}
|
|
80
|
+
function validateCommentBody(body) {
|
|
81
|
+
const trimmed = body.trim();
|
|
82
|
+
if (!trimmed) {
|
|
83
|
+
throw new Error('Jira comment body must not be empty.');
|
|
84
|
+
}
|
|
85
|
+
if (EMOJI_RE.test(trimmed)) {
|
|
86
|
+
throw new Error('Jira comments must not include emoji. Use concise plain text only.');
|
|
87
|
+
}
|
|
88
|
+
return trimmed;
|
|
89
|
+
}
|
|
79
90
|
export class JiraClient {
|
|
80
91
|
baseUrl;
|
|
81
92
|
headers;
|
|
@@ -246,7 +257,7 @@ export class JiraClient {
|
|
|
246
257
|
return text(`${data.total} comment(s) on ${issueKey}${page}:\n\n${blocks.join('\n\n')}`);
|
|
247
258
|
}
|
|
248
259
|
async addComment(args) {
|
|
249
|
-
await this.request('POST', `/issue/${args.issueKey}/comment`, { body: args.body });
|
|
260
|
+
await this.request('POST', `/issue/${args.issueKey}/comment`, { body: validateCommentBody(args.body) });
|
|
250
261
|
return text(`Comment added to ${args.issueKey}.`);
|
|
251
262
|
}
|
|
252
263
|
async transitionIssue(args) {
|