ralph-hero-mcp-server 2.4.16 → 2.4.17

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.
@@ -57,6 +57,47 @@ const UPDATE_FIELD_MUTATION = `mutation($projectId: ID!, $itemId: ID!, $fieldId:
57
57
  projectV2Item { id }
58
58
  }
59
59
  }`;
60
+ const ADD_SYNC_AUDIT_COMMENT = `mutation($subjectId: ID!, $body: String!) {
61
+ addComment(input: { subjectId: $subjectId, body: $body }) {
62
+ commentEdge { node { id } }
63
+ }
64
+ }`;
65
+ const SYNC_AUDIT_MARKER = "<!-- cross-project-sync-audit -->";
66
+ const ISSUE_COMMENTS_QUERY = `query($issueId: ID!) {
67
+ node(id: $issueId) {
68
+ ... on Issue {
69
+ comments(last: 20) { nodes { body } }
70
+ }
71
+ }
72
+ }`;
73
+ // ---------------------------------------------------------------------------
74
+ // Audit trail helpers (#199)
75
+ // ---------------------------------------------------------------------------
76
+ /**
77
+ * Build the audit comment body for a cross-project sync operation.
78
+ * Pure function, no I/O.
79
+ */
80
+ export function buildSyncAuditBody(workflowState, syncedResults) {
81
+ const lines = syncedResults.map((r) => `- Project #${r.projectNumber} (${r.currentState ?? "none"} -> ${workflowState})`);
82
+ return (`${SYNC_AUDIT_MARKER}\n` +
83
+ `**Cross-project sync** \u2014 Workflow State synced to **${workflowState}** across ${syncedResults.length} project(s):\n` +
84
+ lines.join("\n"));
85
+ }
86
+ /**
87
+ * Detect if any comment bodies contain the sync audit marker.
88
+ * Pure function for testability.
89
+ */
90
+ export function detectSyncAuditMarker(comments) {
91
+ return comments.some((c) => c.body.startsWith(SYNC_AUDIT_MARKER));
92
+ }
93
+ /**
94
+ * Check if an issue already has a sync audit comment.
95
+ */
96
+ async function hasExistingSyncAuditComment(client, issueNodeId) {
97
+ const result = await client.query(ISSUE_COMMENTS_QUERY, { issueId: issueNodeId });
98
+ const comments = result.node?.comments?.nodes ?? [];
99
+ return detectSyncAuditMarker(comments);
100
+ }
60
101
  // ---------------------------------------------------------------------------
61
102
  // Helpers
62
103
  // ---------------------------------------------------------------------------
@@ -88,6 +129,11 @@ export function registerSyncTools(server, client, _fieldCache) {
88
129
  .optional()
89
130
  .default(false)
90
131
  .describe("If true, return affected projects without mutating (default: false)"),
132
+ auditComment: z
133
+ .boolean()
134
+ .optional()
135
+ .default(true)
136
+ .describe("Add audit comment to the issue after sync (default: true)"),
91
137
  }, async (args) => {
92
138
  try {
93
139
  const { owner, repo } = resolveConfig(client, args);
@@ -164,6 +210,19 @@ export function registerSyncTools(server, client, _fieldCache) {
164
210
  targetState: args.workflowState,
165
211
  });
166
212
  }
213
+ // Audit trail: add comment documenting the sync (#199)
214
+ let auditCommentAdded = false;
215
+ if (args.auditComment && !args.dryRun && synced.length > 0) {
216
+ const alreadyAudited = await hasExistingSyncAuditComment(client, issueNodeId);
217
+ if (!alreadyAudited) {
218
+ const body = buildSyncAuditBody(args.workflowState, synced);
219
+ await client.mutate(ADD_SYNC_AUDIT_COMMENT, {
220
+ subjectId: issueNodeId,
221
+ body,
222
+ });
223
+ auditCommentAdded = true;
224
+ }
225
+ }
167
226
  return toolSuccess({
168
227
  number: args.number,
169
228
  workflowState: args.workflowState,
@@ -172,6 +231,7 @@ export function registerSyncTools(server, client, _fieldCache) {
172
231
  skippedCount: skipped.length,
173
232
  synced,
174
233
  skipped,
234
+ auditCommentAdded,
175
235
  });
176
236
  }
177
237
  catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ralph-hero-mcp-server",
3
- "version": "2.4.16",
3
+ "version": "2.4.17",
4
4
  "description": "MCP server for GitHub Projects V2 - Ralph workflow automation",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",