@freelancercom/phabricator-mcp 2.0.18 → 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 +68 -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', {
|
|
@@ -165,19 +218,9 @@ export function registerManiphestTools(server, client) {
|
|
|
165
218
|
const extras = {};
|
|
166
219
|
// Custom fields are applied in a second call because Phabricator validates
|
|
167
220
|
// transaction types against the default subtype during creation. Subtype-specific
|
|
168
|
-
// custom fields (e.g.
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const customTransactions = [];
|
|
172
|
-
for (const [key, value] of Object.entries(params.customFields)) {
|
|
173
|
-
customTransactions.push({ type: key, value });
|
|
174
|
-
}
|
|
175
|
-
if (customTransactions.length > 0) {
|
|
176
|
-
extras.customFields = await client.call('maniphest.edit', {
|
|
177
|
-
objectIdentifier: result.object.phid,
|
|
178
|
-
transactions: customTransactions,
|
|
179
|
-
});
|
|
180
|
-
}
|
|
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);
|
|
181
224
|
}
|
|
182
225
|
// Link revisions to the newly created task via differential.revision.edit
|
|
183
226
|
if (params.revisionIDs !== undefined && params.revisionIDs.length > 0) {
|
|
@@ -276,16 +319,13 @@ export function registerManiphestTools(server, client) {
|
|
|
276
319
|
if (params.comment !== undefined) {
|
|
277
320
|
transactions.push({ type: 'comment', value: params.comment });
|
|
278
321
|
}
|
|
279
|
-
|
|
280
|
-
for (const [key, value] of Object.entries(params.customFields)) {
|
|
281
|
-
transactions.push({ type: key, value });
|
|
282
|
-
}
|
|
283
|
-
}
|
|
322
|
+
const hasCustomFields = params.customFields !== undefined && Object.keys(params.customFields).length > 0;
|
|
284
323
|
const hasRevisionChanges = (params.addRevisionIDs !== undefined && params.addRevisionIDs.length > 0) ||
|
|
285
324
|
(params.removeRevisionIDs !== undefined && params.removeRevisionIDs.length > 0);
|
|
286
|
-
if (transactions.length === 0 && !hasRevisionChanges) {
|
|
325
|
+
if (transactions.length === 0 && !hasCustomFields && !hasRevisionChanges) {
|
|
287
326
|
return { content: [{ type: 'text', text: 'No changes specified' }] };
|
|
288
327
|
}
|
|
328
|
+
const extras = {};
|
|
289
329
|
let result = undefined;
|
|
290
330
|
if (transactions.length > 0) {
|
|
291
331
|
result = await client.call('maniphest.edit', {
|
|
@@ -293,18 +333,22 @@ export function registerManiphestTools(server, client) {
|
|
|
293
333
|
transactions,
|
|
294
334
|
});
|
|
295
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
|
+
}
|
|
296
341
|
// Link/unlink revisions via differential.revision.edit
|
|
297
|
-
const revisionResults = {};
|
|
298
342
|
if (params.addRevisionIDs !== undefined && params.addRevisionIDs.length > 0) {
|
|
299
343
|
const revPHIDs = await resolveRevisionPHIDs(client, params.addRevisionIDs);
|
|
300
|
-
|
|
344
|
+
extras.addedRevisions = await linkRevisionsToTask(client, params.objectIdentifier, revPHIDs, 'add');
|
|
301
345
|
}
|
|
302
346
|
if (params.removeRevisionIDs !== undefined && params.removeRevisionIDs.length > 0) {
|
|
303
347
|
const revPHIDs = await resolveRevisionPHIDs(client, params.removeRevisionIDs);
|
|
304
|
-
|
|
348
|
+
extras.removedRevisions = await linkRevisionsToTask(client, params.objectIdentifier, revPHIDs, 'remove');
|
|
305
349
|
}
|
|
306
|
-
const output =
|
|
307
|
-
? { ...(result !== undefined ? { task: result } : {}),
|
|
350
|
+
const output = Object.keys(extras).length > 0
|
|
351
|
+
? { ...(result !== undefined ? { task: result } : {}), ...extras }
|
|
308
352
|
: result;
|
|
309
353
|
return { content: [{ type: 'text', text: JSON.stringify(output, null, 2) }] };
|
|
310
354
|
});
|
package/package.json
CHANGED