ralph-hero-mcp-server 2.4.73 → 2.4.74

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.
@@ -446,6 +446,158 @@ export function registerProjectManagementTools(server, client, fieldCache) {
446
446
  }
447
447
  });
448
448
  // -------------------------------------------------------------------------
449
+ // ralph_hero__get_draft_issue
450
+ // -------------------------------------------------------------------------
451
+ server.tool("ralph_hero__get_draft_issue", "Get the full content of one or more draft issues. Accepts DI_ (content node) or PVTI_ (project item) IDs — auto-detected by prefix. PVTI_ IDs also return project field values. Returns: array of { draftIssueId, projectItemId, title, body, creator, createdAt, updatedAt, workflowState?, estimate?, priority? }.", {
452
+ owner: z.string().optional().describe("GitHub owner. Defaults to env var"),
453
+ repo: z.string().optional().describe("Repository name. Defaults to env var"),
454
+ projectNumber: z.coerce.number().optional()
455
+ .describe("Project number override (defaults to configured project)"),
456
+ ids: z.union([
457
+ z.string().describe("Single draft issue ID (DI_... or PVTI_...)"),
458
+ z.array(z.string()).describe("Array of draft issue IDs"),
459
+ ]).describe("One or more draft issue IDs. DI_ prefix fetches content only. PVTI_ prefix also fetches project field values."),
460
+ }, async (args) => {
461
+ try {
462
+ const idList = Array.isArray(args.ids) ? args.ids : [args.ids];
463
+ if (idList.length === 0) {
464
+ return toolError("At least one ID must be provided");
465
+ }
466
+ // Validate all IDs have valid prefixes
467
+ const invalidIds = idList.filter((id) => !id.startsWith("DI_") && !id.startsWith("PVTI_"));
468
+ if (invalidIds.length > 0) {
469
+ return toolError(`Invalid ID prefix(es): ${invalidIds.join(", ")}. IDs must start with DI_ or PVTI_.`);
470
+ }
471
+ // Partition into DI_ and PVTI_ groups
472
+ const diIds = [];
473
+ const pvtiIds = [];
474
+ for (let i = 0; i < idList.length; i++) {
475
+ if (idList[i].startsWith("DI_")) {
476
+ diIds.push({ id: idList[i], index: i });
477
+ }
478
+ else {
479
+ pvtiIds.push({ id: idList[i], index: i });
480
+ }
481
+ }
482
+ // Build aliased GraphQL query
483
+ const queryParts = [];
484
+ const variables = {};
485
+ const variableDecls = [];
486
+ for (let i = 0; i < diIds.length; i++) {
487
+ const varName = `diId${i}`;
488
+ variableDecls.push(`$${varName}: ID!`);
489
+ variables[varName] = diIds[i].id;
490
+ queryParts.push(`
491
+ draft${i}: node(id: $${varName}) {
492
+ ... on DraftIssue {
493
+ id
494
+ title
495
+ body
496
+ creator { login }
497
+ createdAt
498
+ updatedAt
499
+ }
500
+ }
501
+ `);
502
+ }
503
+ for (let i = 0; i < pvtiIds.length; i++) {
504
+ const varName = `pvtiId${i}`;
505
+ variableDecls.push(`$${varName}: ID!`);
506
+ variables[varName] = pvtiIds[i].id;
507
+ queryParts.push(`
508
+ item${i}: node(id: $${varName}) {
509
+ ... on ProjectV2Item {
510
+ id
511
+ content {
512
+ ... on DraftIssue {
513
+ id
514
+ title
515
+ body
516
+ creator { login }
517
+ createdAt
518
+ updatedAt
519
+ }
520
+ }
521
+ fieldValues(first: 20) {
522
+ nodes {
523
+ ... on ProjectV2ItemFieldSingleSelectValue {
524
+ name
525
+ field { ... on ProjectV2FieldCommon { name } }
526
+ }
527
+ }
528
+ }
529
+ }
530
+ }
531
+ `);
532
+ }
533
+ const fullQuery = `query(${variableDecls.join(", ")}) {\n${queryParts.join("\n")}\n}`;
534
+ const result = await client.projectQuery(fullQuery, variables);
535
+ const drafts = [];
536
+ // Process DI_ results
537
+ for (let i = 0; i < diIds.length; i++) {
538
+ const node = result[`draft${i}`];
539
+ if (!node || !node.id) {
540
+ drafts.push({ id: diIds[i].id, error: "Not found" });
541
+ }
542
+ else {
543
+ drafts.push({
544
+ draftIssueId: node.id,
545
+ projectItemId: null,
546
+ title: node.title ?? "",
547
+ body: node.body ?? null,
548
+ creator: node.creator?.login ?? null,
549
+ createdAt: node.createdAt ?? null,
550
+ updatedAt: node.updatedAt ?? null,
551
+ });
552
+ }
553
+ }
554
+ // Process PVTI_ results
555
+ for (let i = 0; i < pvtiIds.length; i++) {
556
+ const node = result[`item${i}`];
557
+ if (!node || !node.id) {
558
+ drafts.push({ id: pvtiIds[i].id, error: "Not found" });
559
+ }
560
+ else if (!node.content || !node.content.id) {
561
+ drafts.push({ id: pvtiIds[i].id, error: "Not a draft issue" });
562
+ }
563
+ else {
564
+ // Extract field values
565
+ let workflowState;
566
+ let estimate;
567
+ let priority;
568
+ if (node.fieldValues?.nodes) {
569
+ for (const fv of node.fieldValues.nodes) {
570
+ const fieldName = fv.field?.name;
571
+ if (fieldName === "Workflow State")
572
+ workflowState = fv.name;
573
+ else if (fieldName === "Estimate")
574
+ estimate = fv.name;
575
+ else if (fieldName === "Priority")
576
+ priority = fv.name;
577
+ }
578
+ }
579
+ drafts.push({
580
+ draftIssueId: node.content.id,
581
+ projectItemId: pvtiIds[i].id,
582
+ title: node.content.title ?? "",
583
+ body: node.content.body ?? null,
584
+ creator: node.content.creator?.login ?? null,
585
+ createdAt: node.content.createdAt ?? null,
586
+ updatedAt: node.content.updatedAt ?? null,
587
+ ...(workflowState !== undefined && { workflowState }),
588
+ ...(estimate !== undefined && { estimate }),
589
+ ...(priority !== undefined && { priority }),
590
+ });
591
+ }
592
+ }
593
+ return toolSuccess({ drafts });
594
+ }
595
+ catch (error) {
596
+ const message = error instanceof Error ? error.message : String(error);
597
+ return toolError(`Failed to get draft issue(s): ${message}`);
598
+ }
599
+ });
600
+ // -------------------------------------------------------------------------
449
601
  // ralph_hero__reorder_item
450
602
  // -------------------------------------------------------------------------
451
603
  server.tool("ralph_hero__reorder_item", "Set item position within project views. Moves an issue before or after another item. Omit afterNumber to move to the top. Returns: number, position.", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ralph-hero-mcp-server",
3
- "version": "2.4.73",
3
+ "version": "2.4.74",
4
4
  "description": "MCP server for GitHub Projects V2 - Ralph workflow automation",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",