ralph-hero-mcp-server 2.4.89 → 2.4.90

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.
@@ -14,7 +14,7 @@ import { resolveState } from "../lib/state-resolution.js";
14
14
  import { parseDateMath } from "../lib/date-math.js";
15
15
  import { expandProfile } from "../lib/filter-profiles.js";
16
16
  import { toolSuccess, toolError } from "../types.js";
17
- import { ensureFieldCache, resolveIssueNodeId, resolveProjectItemId, updateProjectItemField, getCurrentFieldValue, resolveConfig, resolveFullConfig, resolveFullConfigOptionalRepo, syncStatusField, } from "../lib/helpers.js";
17
+ import { ensureFieldCache, resolveIssueNodeId, resolveProjectItemId, updateProjectItemField, resolveConfig, resolveFullConfig, resolveFullConfigOptionalRepo, } from "../lib/helpers.js";
18
18
  // ---------------------------------------------------------------------------
19
19
  // Register issue tools
20
20
  // ---------------------------------------------------------------------------
@@ -876,198 +876,6 @@ export function registerIssueTools(server, client, fieldCache) {
876
876
  }
877
877
  });
878
878
  // -------------------------------------------------------------------------
879
- // ralph_hero__update_issue
880
- // -------------------------------------------------------------------------
881
- server.tool("ralph_hero__update_issue", "Update a GitHub issue's basic properties (title, body, labels, assignees). Returns: number, title, url. Use update_workflow_state for state changes, update_estimate for estimates, update_priority for priorities.", {
882
- owner: z
883
- .string()
884
- .optional()
885
- .describe("GitHub owner. Defaults to GITHUB_OWNER env var"),
886
- repo: z
887
- .string()
888
- .optional()
889
- .describe("Repository name. Defaults to GITHUB_REPO env var"),
890
- number: z.coerce.number().describe("Issue number"),
891
- title: z.string().optional().describe("New issue title"),
892
- body: z.string().optional().describe("New issue body (Markdown)"),
893
- labels: z
894
- .array(z.string())
895
- .optional()
896
- .describe("Label names (replaces existing labels)"),
897
- assignees: z
898
- .array(z.string())
899
- .optional()
900
- .describe("GitHub usernames to assign (replaces existing)"),
901
- }, async (args) => {
902
- try {
903
- const { owner, repo } = resolveConfig(client, args);
904
- const issueId = await resolveIssueNodeId(client, owner, repo, args.number);
905
- // Resolve label IDs if provided
906
- let labelIds;
907
- if (args.labels) {
908
- const labelResult = await client.query(`query($owner: String!, $repo: String!) {
909
- repository(owner: $owner, name: $repo) {
910
- labels(first: 100) {
911
- nodes { id name }
912
- }
913
- }
914
- }`, { owner, repo }, { cache: true, cacheTtlMs: 5 * 60 * 1000 });
915
- const allLabels = labelResult.repository.labels.nodes;
916
- labelIds = args.labels
917
- .map((name) => allLabels.find((l) => l.name === name)?.id)
918
- .filter((id) => id !== undefined);
919
- }
920
- const result = await client.mutate(`mutation($issueId: ID!, $title: String, $body: String, $labelIds: [ID!], $assigneeIds: [ID!]) {
921
- updateIssue(input: {
922
- id: $issueId,
923
- title: $title,
924
- body: $body,
925
- labelIds: $labelIds,
926
- assigneeIds: $assigneeIds
927
- }) {
928
- issue {
929
- number
930
- title
931
- url
932
- }
933
- }
934
- }`, {
935
- issueId,
936
- title: args.title || null,
937
- body: args.body || null,
938
- labelIds: labelIds || null,
939
- assigneeIds: null, // Would need username -> ID resolution
940
- });
941
- return toolSuccess({
942
- number: result.updateIssue.issue.number,
943
- title: result.updateIssue.issue.title,
944
- url: result.updateIssue.issue.url,
945
- });
946
- }
947
- catch (error) {
948
- const message = error instanceof Error ? error.message : String(error);
949
- return toolError(`Failed to update issue: ${message}`);
950
- }
951
- });
952
- // -------------------------------------------------------------------------
953
- // ralph_hero__update_workflow_state
954
- // -------------------------------------------------------------------------
955
- server.tool("ralph_hero__update_workflow_state", "Change an issue's Workflow State using semantic intents or direct state names. Returns: number, previousState, newState, command. Semantic intents: __LOCK__ (lock for processing), __COMPLETE__ (mark done), __ESCALATE__ (needs human), __CLOSE__, __CANCEL__. Recovery: if state transition fails, verify the issue is in the project and the state name is valid.", {
956
- owner: z
957
- .string()
958
- .optional()
959
- .describe("GitHub owner. Defaults to GITHUB_OWNER env var"),
960
- repo: z
961
- .string()
962
- .optional()
963
- .describe("Repository name. Defaults to GITHUB_REPO env var"),
964
- projectNumber: z.coerce.number().optional()
965
- .describe("Project number override (defaults to configured project)"),
966
- number: z.coerce.number().describe("Issue number"),
967
- state: z
968
- .string()
969
- .describe("Target state: semantic intent (__LOCK__, __COMPLETE__, __ESCALATE__, __CLOSE__, __CANCEL__) " +
970
- "or direct state name (e.g., 'Research Needed', 'In Progress')"),
971
- command: z
972
- .string()
973
- .describe("Ralph command making this transition (e.g., 'ralph_research', 'ralph_plan'). " +
974
- "Required for validation and semantic intent resolution."),
975
- }, async (args) => {
976
- try {
977
- const { owner, repo, projectNumber, projectOwner } = resolveFullConfig(client, args);
978
- // Resolve semantic intent or validate direct state
979
- const { resolvedState, wasIntent, originalState } = resolveState(args.state, args.command);
980
- // Ensure field cache is populated
981
- await ensureFieldCache(client, fieldCache, projectOwner, projectNumber);
982
- // Get current state for the response
983
- const previousState = await getCurrentFieldValue(client, fieldCache, owner, repo, args.number, "Workflow State", projectNumber);
984
- // Resolve project item ID
985
- const projectItemId = await resolveProjectItemId(client, fieldCache, owner, repo, args.number, projectNumber);
986
- // Update the field with the resolved state
987
- await updateProjectItemField(client, fieldCache, projectItemId, "Workflow State", resolvedState, projectNumber);
988
- // Sync default Status field (best-effort, one-way)
989
- await syncStatusField(client, fieldCache, projectItemId, resolvedState, projectNumber);
990
- const result = {
991
- number: args.number,
992
- previousState: previousState || "(unknown)",
993
- newState: resolvedState,
994
- command: args.command,
995
- };
996
- if (wasIntent) {
997
- result.resolvedFrom = originalState;
998
- }
999
- return toolSuccess(result);
1000
- }
1001
- catch (error) {
1002
- const message = error instanceof Error ? error.message : String(error);
1003
- return toolError(`Failed to update workflow state: ${message}`);
1004
- }
1005
- });
1006
- // -------------------------------------------------------------------------
1007
- // ralph_hero__update_estimate
1008
- // -------------------------------------------------------------------------
1009
- server.tool("ralph_hero__update_estimate", "Change an issue's Estimate in the project. Returns: number, estimate. Valid values: XS, S, M, L, XL. Recovery: if the issue is not in the project, add it first via create_issue.", {
1010
- owner: z
1011
- .string()
1012
- .optional()
1013
- .describe("GitHub owner. Defaults to GITHUB_OWNER env var"),
1014
- repo: z
1015
- .string()
1016
- .optional()
1017
- .describe("Repository name. Defaults to GITHUB_REPO env var"),
1018
- projectNumber: z.coerce.number().optional()
1019
- .describe("Project number override (defaults to configured project)"),
1020
- number: z.coerce.number().describe("Issue number"),
1021
- estimate: z.string().describe("Estimate value (XS, S, M, L, XL)"),
1022
- }, async (args) => {
1023
- try {
1024
- const { owner, repo, projectNumber, projectOwner } = resolveFullConfig(client, args);
1025
- await ensureFieldCache(client, fieldCache, projectOwner, projectNumber);
1026
- const projectItemId = await resolveProjectItemId(client, fieldCache, owner, repo, args.number, projectNumber);
1027
- await updateProjectItemField(client, fieldCache, projectItemId, "Estimate", args.estimate, projectNumber);
1028
- return toolSuccess({
1029
- number: args.number,
1030
- estimate: args.estimate,
1031
- });
1032
- }
1033
- catch (error) {
1034
- const message = error instanceof Error ? error.message : String(error);
1035
- return toolError(`Failed to update estimate: ${message}`);
1036
- }
1037
- });
1038
- // -------------------------------------------------------------------------
1039
- // ralph_hero__update_priority
1040
- // -------------------------------------------------------------------------
1041
- server.tool("ralph_hero__update_priority", "Change an issue's Priority in the project. Returns: number, priority. Valid values: P0, P1, P2, P3. Recovery: if the issue is not in the project, add it first via create_issue.", {
1042
- owner: z
1043
- .string()
1044
- .optional()
1045
- .describe("GitHub owner. Defaults to GITHUB_OWNER env var"),
1046
- repo: z
1047
- .string()
1048
- .optional()
1049
- .describe("Repository name. Defaults to GITHUB_REPO env var"),
1050
- projectNumber: z.coerce.number().optional()
1051
- .describe("Project number override (defaults to configured project)"),
1052
- number: z.coerce.number().describe("Issue number"),
1053
- priority: z.string().describe("Priority value (P0, P1, P2, P3)"),
1054
- }, async (args) => {
1055
- try {
1056
- const { owner, repo, projectNumber, projectOwner } = resolveFullConfig(client, args);
1057
- await ensureFieldCache(client, fieldCache, projectOwner, projectNumber);
1058
- const projectItemId = await resolveProjectItemId(client, fieldCache, owner, repo, args.number, projectNumber);
1059
- await updateProjectItemField(client, fieldCache, projectItemId, "Priority", args.priority, projectNumber);
1060
- return toolSuccess({
1061
- number: args.number,
1062
- priority: args.priority,
1063
- });
1064
- }
1065
- catch (error) {
1066
- const message = error instanceof Error ? error.message : String(error);
1067
- return toolError(`Failed to update priority: ${message}`);
1068
- }
1069
- });
1070
- // -------------------------------------------------------------------------
1071
879
  // ralph_hero__create_comment
1072
880
  // -------------------------------------------------------------------------
1073
881
  server.tool("ralph_hero__create_comment", "Add a comment to a GitHub issue. Returns: commentId, issueNumber. Recovery: if issue not found, verify the issue number exists in the repository.", {
@@ -242,51 +242,6 @@ export function registerProjectManagementTools(server, client, fieldCache) {
242
242
  }
243
243
  });
244
244
  // -------------------------------------------------------------------------
245
- // ralph_hero__clear_field
246
- // -------------------------------------------------------------------------
247
- server.tool("ralph_hero__clear_field", "Clear a field value on a project item. Works for any single-select field (Workflow State, Estimate, Priority, Status, etc.). Returns: number, field, cleared.", {
248
- owner: z.string().optional().describe("GitHub owner. Defaults to env var"),
249
- repo: z.string().optional().describe("Repository name. Defaults to env var"),
250
- projectNumber: z.coerce.number().optional()
251
- .describe("Project number override (defaults to configured project)"),
252
- number: z.coerce.number().describe("Issue number"),
253
- field: z.string().describe("Field name to clear (e.g., 'Estimate', 'Priority', 'Workflow State')"),
254
- }, async (args) => {
255
- try {
256
- const { owner, repo, projectNumber, projectOwner } = resolveFullConfig(client, args);
257
- await ensureFieldCache(client, fieldCache, projectOwner, projectNumber);
258
- const projectId = fieldCache.getProjectId(projectNumber);
259
- if (!projectId) {
260
- return toolError("Could not resolve project ID");
261
- }
262
- const fieldId = fieldCache.getFieldId(args.field, projectNumber);
263
- if (!fieldId) {
264
- const validFields = fieldCache.getFieldNames(projectNumber);
265
- return toolError(`Field "${args.field}" not found in project. ` +
266
- `Valid fields: ${validFields.join(", ")}`);
267
- }
268
- const projectItemId = await resolveProjectItemId(client, fieldCache, owner, repo, args.number, projectNumber);
269
- await client.projectMutate(`mutation($projectId: ID!, $itemId: ID!, $fieldId: ID!) {
270
- clearProjectV2ItemFieldValue(input: {
271
- projectId: $projectId,
272
- itemId: $itemId,
273
- fieldId: $fieldId
274
- }) {
275
- projectV2Item { id }
276
- }
277
- }`, { projectId, itemId: projectItemId, fieldId });
278
- return toolSuccess({
279
- number: args.number,
280
- field: args.field,
281
- cleared: true,
282
- });
283
- }
284
- catch (error) {
285
- const message = error instanceof Error ? error.message : String(error);
286
- return toolError(`Failed to clear field: ${message}`);
287
- }
288
- });
289
- // -------------------------------------------------------------------------
290
245
  // ralph_hero__create_draft_issue
291
246
  // -------------------------------------------------------------------------
292
247
  server.tool("ralph_hero__create_draft_issue", "Create a draft issue in the project (no repo required). Optionally set workflow state, priority, and estimate after creation. Returns: projectItemId, title, fieldsSet.", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ralph-hero-mcp-server",
3
- "version": "2.4.89",
3
+ "version": "2.4.90",
4
4
  "description": "MCP server for GitHub Projects V2 - Ralph workflow automation",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",