ralph-hero-mcp-server 2.4.34 → 2.4.35
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/relationship-tools.js +48 -28
- package/package.json +1 -1
|
@@ -325,7 +325,7 @@ export function registerRelationshipTools(server, client, fieldCache) {
|
|
|
325
325
|
// -------------------------------------------------------------------------
|
|
326
326
|
// ralph_hero__advance_children
|
|
327
327
|
// -------------------------------------------------------------------------
|
|
328
|
-
server.tool("ralph_hero__advance_children", "Advance
|
|
328
|
+
server.tool("ralph_hero__advance_children", "Advance issues to a target workflow state. Provide either 'number' (parent issue, advances sub-issues) or 'issues' (explicit list of issue numbers). Only advances issues in earlier workflow states. Returns what changed, what was skipped, and any errors.", {
|
|
329
329
|
owner: z
|
|
330
330
|
.string()
|
|
331
331
|
.optional()
|
|
@@ -334,12 +334,24 @@ export function registerRelationshipTools(server, client, fieldCache) {
|
|
|
334
334
|
.string()
|
|
335
335
|
.optional()
|
|
336
336
|
.describe("Repository name. Defaults to GITHUB_REPO env var"),
|
|
337
|
-
number: z
|
|
337
|
+
number: z
|
|
338
|
+
.coerce.number()
|
|
339
|
+
.optional()
|
|
340
|
+
.describe("Parent issue number (resolves sub-issues automatically)"),
|
|
341
|
+
issues: z
|
|
342
|
+
.array(z.coerce.number())
|
|
343
|
+
.optional()
|
|
344
|
+
.describe("Explicit list of issue numbers to advance (alternative to parent number)"),
|
|
338
345
|
targetState: z
|
|
339
346
|
.string()
|
|
340
|
-
.describe("State to advance
|
|
347
|
+
.describe("State to advance issues to (e.g., 'Research Needed', 'Ready for Plan')"),
|
|
341
348
|
}, async (args) => {
|
|
342
349
|
try {
|
|
350
|
+
// Validate: at least one of number or issues must be provided
|
|
351
|
+
if (args.number === undefined && (!args.issues || args.issues.length === 0)) {
|
|
352
|
+
return toolError("Either 'number' (parent issue) or 'issues' (explicit list) is required. " +
|
|
353
|
+
"Recovery: provide one of these parameters.");
|
|
354
|
+
}
|
|
343
355
|
// Validate target state
|
|
344
356
|
if (!isValidState(args.targetState)) {
|
|
345
357
|
return toolError(`Unknown target state '${args.targetState}'. ` +
|
|
@@ -358,24 +370,32 @@ export function registerRelationshipTools(server, client, fieldCache) {
|
|
|
358
370
|
}
|
|
359
371
|
// Ensure field cache is populated
|
|
360
372
|
await ensureFieldCache(client, fieldCache, projectOwner, projectNumber);
|
|
361
|
-
//
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
373
|
+
// Build issue list: from explicit `issues` param or from parent's sub-issues
|
|
374
|
+
let issueNumbers;
|
|
375
|
+
if (args.issues && args.issues.length > 0) {
|
|
376
|
+
// Explicit issue list takes precedence
|
|
377
|
+
issueNumbers = args.issues;
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
// Fetch sub-issues from parent
|
|
381
|
+
const result = await client.query(`query($owner: String!, $repo: String!, $number: Int!) {
|
|
382
|
+
repository(owner: $owner, name: $repo) {
|
|
383
|
+
issue(number: $number) {
|
|
384
|
+
number
|
|
385
|
+
title
|
|
386
|
+
subIssues(first: 50) {
|
|
387
|
+
nodes { id number title state }
|
|
388
|
+
}
|
|
369
389
|
}
|
|
370
390
|
}
|
|
391
|
+
}`, { owner, repo, number: args.number });
|
|
392
|
+
const parentIssue = result.repository?.issue;
|
|
393
|
+
if (!parentIssue) {
|
|
394
|
+
return toolError(`Issue #${args.number} not found in ${owner}/${repo}`);
|
|
395
|
+
}
|
|
396
|
+
issueNumbers = parentIssue.subIssues.nodes.map((si) => si.number);
|
|
371
397
|
}
|
|
372
|
-
|
|
373
|
-
const parentIssue = result.repository?.issue;
|
|
374
|
-
if (!parentIssue) {
|
|
375
|
-
return toolError(`Issue #${args.number} not found in ${owner}/${repo}`);
|
|
376
|
-
}
|
|
377
|
-
const subIssues = parentIssue.subIssues.nodes;
|
|
378
|
-
if (subIssues.length === 0) {
|
|
398
|
+
if (issueNumbers.length === 0) {
|
|
379
399
|
return toolSuccess({
|
|
380
400
|
advanced: [],
|
|
381
401
|
skipped: [],
|
|
@@ -385,22 +405,22 @@ export function registerRelationshipTools(server, client, fieldCache) {
|
|
|
385
405
|
const advanced = [];
|
|
386
406
|
const skipped = [];
|
|
387
407
|
const errors = [];
|
|
388
|
-
for (const
|
|
408
|
+
for (const issueNum of issueNumbers) {
|
|
389
409
|
try {
|
|
390
410
|
// Get current workflow state
|
|
391
|
-
const currentState = await getCurrentFieldValue(client, fieldCache, owner, repo,
|
|
411
|
+
const currentState = await getCurrentFieldValue(client, fieldCache, owner, repo, issueNum, "Workflow State");
|
|
392
412
|
if (!currentState) {
|
|
393
413
|
skipped.push({
|
|
394
|
-
number:
|
|
414
|
+
number: issueNum,
|
|
395
415
|
currentState: "unknown",
|
|
396
416
|
reason: "No workflow state set on issue",
|
|
397
417
|
});
|
|
398
418
|
continue;
|
|
399
419
|
}
|
|
400
|
-
// Only advance if
|
|
420
|
+
// Only advance if issue is in an earlier state
|
|
401
421
|
if (!isEarlierState(currentState, args.targetState)) {
|
|
402
422
|
skipped.push({
|
|
403
|
-
number:
|
|
423
|
+
number: issueNum,
|
|
404
424
|
currentState,
|
|
405
425
|
reason: currentState === args.targetState
|
|
406
426
|
? "Already at target state"
|
|
@@ -408,13 +428,13 @@ export function registerRelationshipTools(server, client, fieldCache) {
|
|
|
408
428
|
});
|
|
409
429
|
continue;
|
|
410
430
|
}
|
|
411
|
-
// Advance the
|
|
412
|
-
const projectItemId = await resolveProjectItemId(client, fieldCache, owner, repo,
|
|
431
|
+
// Advance the issue
|
|
432
|
+
const projectItemId = await resolveProjectItemId(client, fieldCache, owner, repo, issueNum);
|
|
413
433
|
await updateProjectItemField(client, fieldCache, projectItemId, "Workflow State", args.targetState);
|
|
414
434
|
// Sync default Status field (best-effort, one-way)
|
|
415
435
|
await syncStatusField(client, fieldCache, projectItemId, args.targetState);
|
|
416
436
|
advanced.push({
|
|
417
|
-
number:
|
|
437
|
+
number: issueNum,
|
|
418
438
|
fromState: currentState,
|
|
419
439
|
toState: args.targetState,
|
|
420
440
|
});
|
|
@@ -422,8 +442,8 @@ export function registerRelationshipTools(server, client, fieldCache) {
|
|
|
422
442
|
catch (error) {
|
|
423
443
|
const message = error instanceof Error ? error.message : String(error);
|
|
424
444
|
errors.push({
|
|
425
|
-
number:
|
|
426
|
-
error: `Failed to update: ${message}. Recovery: retry advance_children or update this
|
|
445
|
+
number: issueNum,
|
|
446
|
+
error: `Failed to update: ${message}. Recovery: retry advance_children or update this issue manually.`,
|
|
427
447
|
});
|
|
428
448
|
}
|
|
429
449
|
}
|