@freelancercom/phabricator-mcp 2.0.17 → 2.0.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/dist/tools/maniphest.js +75 -24
- package/package.json +1 -1
package/dist/tools/maniphest.js
CHANGED
|
@@ -58,6 +58,59 @@ async function linkRevisionsToTask(client, taskIdentifier, revisionPHIDs, action
|
|
|
58
58
|
}
|
|
59
59
|
return results;
|
|
60
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Phabricator custom fields are only editable when the task's subtype matches
|
|
63
|
+
* the form that exposes them. For example, `custom.postmortem.*` fields require
|
|
64
|
+
* subtype "postmortem", while `custom.incident.*` fields require "incident".
|
|
65
|
+
*
|
|
66
|
+
* This function groups custom field transactions by required subtype, temporarily
|
|
67
|
+
* switches the task's subtype to set each group, then restores the original subtype.
|
|
68
|
+
*/
|
|
69
|
+
const SUBTYPE_FIELD_PREFIXES = {
|
|
70
|
+
'custom.postmortem.': 'postmortem',
|
|
71
|
+
'custom.incident.': 'incident',
|
|
72
|
+
};
|
|
73
|
+
async function applyCustomFields(client, objectIdentifier, customFields, currentSubtype) {
|
|
74
|
+
// Group fields by required subtype
|
|
75
|
+
const groups = new Map();
|
|
76
|
+
for (const [key, value] of Object.entries(customFields)) {
|
|
77
|
+
let requiredSubtype = null;
|
|
78
|
+
for (const [prefix, subtype] of Object.entries(SUBTYPE_FIELD_PREFIXES)) {
|
|
79
|
+
if (key.startsWith(prefix)) {
|
|
80
|
+
requiredSubtype = subtype;
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const group = groups.get(requiredSubtype) ?? [];
|
|
85
|
+
group.push({ type: key, value });
|
|
86
|
+
groups.set(requiredSubtype, group);
|
|
87
|
+
}
|
|
88
|
+
const results = {};
|
|
89
|
+
let lastSubtype = currentSubtype;
|
|
90
|
+
for (const [requiredSubtype, transactions] of groups) {
|
|
91
|
+
// Switch subtype if needed
|
|
92
|
+
if (requiredSubtype !== null && requiredSubtype !== lastSubtype) {
|
|
93
|
+
await client.call('maniphest.edit', {
|
|
94
|
+
objectIdentifier,
|
|
95
|
+
transactions: [{ type: 'subtype', value: requiredSubtype }],
|
|
96
|
+
});
|
|
97
|
+
lastSubtype = requiredSubtype;
|
|
98
|
+
}
|
|
99
|
+
const result = await client.call('maniphest.edit', {
|
|
100
|
+
objectIdentifier,
|
|
101
|
+
transactions,
|
|
102
|
+
});
|
|
103
|
+
results[requiredSubtype ?? 'default'] = result;
|
|
104
|
+
}
|
|
105
|
+
// Restore original subtype if we changed it
|
|
106
|
+
if (lastSubtype !== currentSubtype && currentSubtype !== undefined) {
|
|
107
|
+
await client.call('maniphest.edit', {
|
|
108
|
+
objectIdentifier,
|
|
109
|
+
transactions: [{ type: 'subtype', value: currentSubtype }],
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return results;
|
|
113
|
+
}
|
|
61
114
|
export function registerManiphestTools(server, client) {
|
|
62
115
|
// Search tasks
|
|
63
116
|
server.tool('phabricator_task_search', 'Search Maniphest tasks with optional filters', {
|
|
@@ -161,25 +214,22 @@ export function registerManiphestTools(server, client) {
|
|
|
161
214
|
if (params.comment !== undefined) {
|
|
162
215
|
transactions.push({ type: 'comment', value: params.comment });
|
|
163
216
|
}
|
|
164
|
-
if (params.customFields !== undefined) {
|
|
165
|
-
for (const [key, value] of Object.entries(params.customFields)) {
|
|
166
|
-
transactions.push({ type: key, value });
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
217
|
const result = await client.call('maniphest.edit', { transactions });
|
|
218
|
+
const extras = {};
|
|
219
|
+
// Custom fields are applied in a second call because Phabricator validates
|
|
220
|
+
// transaction types against the default subtype during creation. Subtype-specific
|
|
221
|
+
// custom fields (e.g. postmortem fields) require temporarily switching the subtype.
|
|
222
|
+
if (params.customFields !== undefined && Object.keys(params.customFields).length > 0) {
|
|
223
|
+
extras.customFields = await applyCustomFields(client, result.object.phid, params.customFields, params.subtype);
|
|
224
|
+
}
|
|
170
225
|
// Link revisions to the newly created task via differential.revision.edit
|
|
171
226
|
if (params.revisionIDs !== undefined && params.revisionIDs.length > 0) {
|
|
172
227
|
const revPHIDs = await resolveRevisionPHIDs(client, params.revisionIDs);
|
|
173
228
|
const taskId = `T${result.object.id}`;
|
|
174
|
-
|
|
175
|
-
return {
|
|
176
|
-
content: [{
|
|
177
|
-
type: 'text',
|
|
178
|
-
text: JSON.stringify({ ...result, linkedRevisions: linkResults }, null, 2),
|
|
179
|
-
}],
|
|
180
|
-
};
|
|
229
|
+
extras.linkedRevisions = await linkRevisionsToTask(client, taskId, revPHIDs, 'add');
|
|
181
230
|
}
|
|
182
|
-
|
|
231
|
+
const output = Object.keys(extras).length > 0 ? { ...result, ...extras } : result;
|
|
232
|
+
return { content: [{ type: 'text', text: JSON.stringify(output, null, 2) }] };
|
|
183
233
|
});
|
|
184
234
|
// Edit task
|
|
185
235
|
server.tool('phabricator_task_edit', 'Edit an existing Maniphest task', {
|
|
@@ -269,16 +319,13 @@ export function registerManiphestTools(server, client) {
|
|
|
269
319
|
if (params.comment !== undefined) {
|
|
270
320
|
transactions.push({ type: 'comment', value: params.comment });
|
|
271
321
|
}
|
|
272
|
-
|
|
273
|
-
for (const [key, value] of Object.entries(params.customFields)) {
|
|
274
|
-
transactions.push({ type: key, value });
|
|
275
|
-
}
|
|
276
|
-
}
|
|
322
|
+
const hasCustomFields = params.customFields !== undefined && Object.keys(params.customFields).length > 0;
|
|
277
323
|
const hasRevisionChanges = (params.addRevisionIDs !== undefined && params.addRevisionIDs.length > 0) ||
|
|
278
324
|
(params.removeRevisionIDs !== undefined && params.removeRevisionIDs.length > 0);
|
|
279
|
-
if (transactions.length === 0 && !hasRevisionChanges) {
|
|
325
|
+
if (transactions.length === 0 && !hasCustomFields && !hasRevisionChanges) {
|
|
280
326
|
return { content: [{ type: 'text', text: 'No changes specified' }] };
|
|
281
327
|
}
|
|
328
|
+
const extras = {};
|
|
282
329
|
let result = undefined;
|
|
283
330
|
if (transactions.length > 0) {
|
|
284
331
|
result = await client.call('maniphest.edit', {
|
|
@@ -286,18 +333,22 @@ export function registerManiphestTools(server, client) {
|
|
|
286
333
|
transactions,
|
|
287
334
|
});
|
|
288
335
|
}
|
|
336
|
+
// Custom fields may require subtype switching (e.g. postmortem fields
|
|
337
|
+
// need subtype "postmortem"). applyCustomFields handles this automatically.
|
|
338
|
+
if (hasCustomFields) {
|
|
339
|
+
extras.customFields = await applyCustomFields(client, params.objectIdentifier, params.customFields, params.subtype);
|
|
340
|
+
}
|
|
289
341
|
// Link/unlink revisions via differential.revision.edit
|
|
290
|
-
const revisionResults = {};
|
|
291
342
|
if (params.addRevisionIDs !== undefined && params.addRevisionIDs.length > 0) {
|
|
292
343
|
const revPHIDs = await resolveRevisionPHIDs(client, params.addRevisionIDs);
|
|
293
|
-
|
|
344
|
+
extras.addedRevisions = await linkRevisionsToTask(client, params.objectIdentifier, revPHIDs, 'add');
|
|
294
345
|
}
|
|
295
346
|
if (params.removeRevisionIDs !== undefined && params.removeRevisionIDs.length > 0) {
|
|
296
347
|
const revPHIDs = await resolveRevisionPHIDs(client, params.removeRevisionIDs);
|
|
297
|
-
|
|
348
|
+
extras.removedRevisions = await linkRevisionsToTask(client, params.objectIdentifier, revPHIDs, 'remove');
|
|
298
349
|
}
|
|
299
|
-
const output =
|
|
300
|
-
? { ...(result !== undefined ? { task: result } : {}),
|
|
350
|
+
const output = Object.keys(extras).length > 0
|
|
351
|
+
? { ...(result !== undefined ? { task: result } : {}), ...extras }
|
|
301
352
|
: result;
|
|
302
353
|
return { content: [{ type: 'text', text: JSON.stringify(output, null, 2) }] };
|
|
303
354
|
});
|
package/package.json
CHANGED