ralph-hero-mcp-server 2.5.126 → 2.5.129

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.
@@ -0,0 +1,41 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Boolean schema that tolerates the harness wire-format for booleans.
4
+ *
5
+ * Background (GH-1130): When a ralph-hero MCP tool is invoked before its
6
+ * schema has been hydrated by Claude Code's `ToolSearch`, the harness
7
+ * passes boolean argument values through as the literal strings `"true"`
8
+ * or `"false"` instead of the native boolean primitives. A plain
9
+ * `z.boolean()` schema rejects those strings with `"Expected boolean,
10
+ * received string"`, producing MCP error -32602 and forcing the caller
11
+ * to round-trip through `ToolSearch` before the call can succeed.
12
+ *
13
+ * `z.coerce.boolean()` is NOT a safe replacement: it uses the JavaScript
14
+ * `Boolean()` constructor, and `Boolean("false") === true` because any
15
+ * non-empty string is truthy. That would silently flip every `"false"`
16
+ * arrival into `true`.
17
+ *
18
+ * `zBoolish` uses `z.preprocess` to map only the two exact literal
19
+ * strings the harness emits (`"true"` → `true`, `"false"` → `false`)
20
+ * before handing off to a real `z.boolean()` validator. Anything else
21
+ * (numbers, objects, `"yes"`, `"1"`, etc.) is passed through unchanged
22
+ * and rejected with the standard boolean error message. Native booleans
23
+ * pass through unchanged.
24
+ *
25
+ * @example
26
+ * const Schema = z.object({ flag: zBoolish().optional().default(false) });
27
+ * Schema.parse({ flag: true }) // { flag: true }
28
+ * Schema.parse({ flag: "true" }) // { flag: true }
29
+ * Schema.parse({ flag: "false" }) // { flag: false }
30
+ * Schema.parse({ flag: "yes" }) // throws ZodError
31
+ */
32
+ export function zBoolish() {
33
+ return z.preprocess((value) => {
34
+ if (value === "true")
35
+ return true;
36
+ if (value === "false")
37
+ return false;
38
+ return value;
39
+ }, z.boolean());
40
+ }
41
+ //# sourceMappingURL=zod-helpers.js.map
@@ -3,6 +3,7 @@ import * as path from "node:path";
3
3
  import * as os from "node:os";
4
4
  import { readActivity } from "../lib/activity.js";
5
5
  import { toolSuccess, toolError } from "../types.js";
6
+ import { zBoolish } from "../lib/zod-helpers.js";
6
7
  function defaultActivityRoot() {
7
8
  return process.env.RALPH_ACTIVITY_DIR ?? path.join(os.homedir(), ".ralph-hero", "activity");
8
9
  }
@@ -14,7 +15,7 @@ export function registerActivityTools(server) {
14
15
  category: z.enum(["work", "meta", "all"]).default("work").describe("Filter by category; default 'work' excludes meta noise"),
15
16
  project: z.string().nullable().default(null).describe("Filter by project name"),
16
17
  limit: z.number().int().min(1).default(50).describe("Max events to return (default 50; was 100 before 2.5.x)"),
17
- compact: z.boolean().default(false).describe("When true, project each event to {ts, kind, tool, project}; drops actor/session_id/category/wrapper-target. Use for narrative synthesis."),
18
+ compact: zBoolish().default(false).describe("When true, project each event to {ts, kind, tool, project}; drops actor/session_id/category/wrapper-target. Use for narrative synthesis."),
18
19
  }, async (params) => {
19
20
  try {
20
21
  const result = readActivity({
@@ -8,6 +8,7 @@
8
8
  import { z } from "zod";
9
9
  import { isEarlierState, WORKFLOW_STATE_TO_STATUS } from "../lib/workflow-states.js";
10
10
  import { toolSuccess, toolError } from "../types.js";
11
+ import { zBoolish } from "../lib/zod-helpers.js";
11
12
  import { ensureFieldCache, resolveFullConfig, } from "../lib/helpers.js";
12
13
  // ---------------------------------------------------------------------------
13
14
  // Aliased GraphQL builders
@@ -171,8 +172,7 @@ export function registerBatchTools(server, client, fieldCache) {
171
172
  .min(1)
172
173
  .max(MAX_OPERATIONS)
173
174
  .describe("Field updates to apply to all issues (1-3)"),
174
- skipIfAtOrPast: z
175
- .boolean()
175
+ skipIfAtOrPast: zBoolish()
176
176
  .optional()
177
177
  .default(false)
178
178
  .describe("For workflow_state operations, skip issues already at or past the target state (default: false)"),
@@ -12,6 +12,7 @@ import { toolSuccess, toolError, resolveProjectOwner, resolveProjectNumbers } fr
12
12
  import { detectWorkStreams } from "../lib/work-stream-detection.js";
13
13
  import { detectStreamPipelinePositions } from "../lib/pipeline-detection.js";
14
14
  import { calculateMetrics, DEFAULT_METRICS_CONFIG, } from "../lib/metrics.js";
15
+ import { zBoolish } from "../lib/zod-helpers.js";
15
16
  // Re-export for backwards compatibility — tests + downstream tools used to
16
17
  // pull these symbols straight out of dashboard-tools.ts before they were
17
18
  // hoisted into lib/dashboard-fetch.ts.
@@ -34,8 +35,7 @@ export function registerDashboardTools(server, client, fieldCache) {
34
35
  .optional()
35
36
  .default("json")
36
37
  .describe("Output format (default: json)"),
37
- includeHealth: z
38
- .boolean()
38
+ includeHealth: zBoolish()
39
39
  .optional()
40
40
  .default(true)
41
41
  .describe("Include health indicators (default: true)"),
@@ -58,8 +58,7 @@ export function registerDashboardTools(server, client, fieldCache) {
58
58
  .optional()
59
59
  .default(10)
60
60
  .describe("Max issues to list per phase (default: 10)"),
61
- includeMetrics: z
62
- .boolean()
61
+ includeMetrics: zBoolish()
63
62
  .optional()
64
63
  .default(false)
65
64
  .describe("Include velocity metrics, risk score, and auto-status (default: false)"),
@@ -12,6 +12,7 @@ import { homedir } from "node:os";
12
12
  import { createHash } from "node:crypto";
13
13
  import { z } from "zod";
14
14
  import { toolSuccess, toolError } from "../types.js";
15
+ import { zBoolish } from "../lib/zod-helpers.js";
15
16
  // ---------------------------------------------------------------------------
16
17
  // JSONL Parsing
17
18
  // ---------------------------------------------------------------------------
@@ -186,8 +187,7 @@ export function registerDebugTools(server, client) {
186
187
  .string()
187
188
  .optional()
188
189
  .describe("ISO date string. Only process events after this time (default: 24h ago)"),
189
- dryRun: z
190
- .boolean()
190
+ dryRun: zBoolish()
191
191
  .optional()
192
192
  .default(false)
193
193
  .describe("If true, report what would be created/updated without making changes"),
@@ -12,6 +12,7 @@ import { z } from "zod";
12
12
  import { toolSuccess, toolError } from "../types.js";
13
13
  import { ensureFieldCache, resolveFullConfigOptionalRepo, } from "../lib/helpers.js";
14
14
  import { lookupRepo, lookupPattern, mergeDefaults, } from "../lib/repo-registry.js";
15
+ import { zBoolish } from "../lib/zod-helpers.js";
15
16
  // ---------------------------------------------------------------------------
16
17
  // Pure function: buildDecomposition
17
18
  // ---------------------------------------------------------------------------
@@ -109,8 +110,7 @@ export function registerDecomposeTools(server, client, fieldCache) {
109
110
  .optional()
110
111
  .describe("Decomposition pattern name from .ralph-repos.yml. " +
111
112
  "Omit to list available patterns and repos."),
112
- dryRun: z
113
- .boolean()
113
+ dryRun: zBoolish()
114
114
  .optional()
115
115
  .default(true)
116
116
  .describe("When true (default), return the proposal without creating issues. " +
@@ -14,6 +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 { zBoolish } from "../lib/zod-helpers.js";
17
18
  import { ensureFieldCache, resolveIssueNodeId, resolveProjectItemId, updateProjectItemField, getCurrentFieldValue, resolveConfig, resolveFullConfig, resolveFullConfigOptionalRepo, syncStatusField, autoAdvanceParent, resolveIterationId, } from "../lib/helpers.js";
18
19
  import { lookupRepo, mergeDefaults } from "../lib/repo-registry.js";
19
20
  import { isLockConflict } from "../lib/lock-guard.js";
@@ -378,13 +379,11 @@ export function registerIssueTools(server, client, fieldCache) {
378
379
  projectNumber: z.coerce.number().optional()
379
380
  .describe("Project number override (defaults to configured project)"),
380
381
  number: z.coerce.number().describe("Issue number"),
381
- includeGroup: z
382
- .boolean()
382
+ includeGroup: zBoolish()
383
383
  .optional()
384
384
  .default(true)
385
385
  .describe("Include group detection results (default: true). Set to false to skip group detection and save API calls when group context is not needed."),
386
- includePipeline: z
387
- .boolean()
386
+ includePipeline: zBoolish()
388
387
  .optional()
389
388
  .default(false)
390
389
  .describe("Include pipeline position: phase, convergence, member states, remaining phases. Auto-enables includeGroup."),
@@ -833,7 +832,7 @@ export function registerIssueTools(server, client, fieldCache) {
833
832
  .describe("Iteration/sprint title (e.g., 'Sprint 1'), @current, @next, or null to clear."),
834
833
  command: z.string().optional()
835
834
  .describe("Ralph command for semantic intent resolution (e.g., 'ralph_impl'). Required when workflowState is a semantic intent."),
836
- force: z.boolean().optional()
835
+ force: zBoolish().optional()
837
836
  .describe("Bypass lock guard. Use only for recovery when an agent crash left an issue stuck in a lock state."),
838
837
  }, async (args) => {
839
838
  try {
@@ -10,6 +10,7 @@ import { readFile } from "fs/promises";
10
10
  import { parsePlanGraph } from "../lib/plan-graph.js";
11
11
  import { toolSuccess, toolError } from "../types.js";
12
12
  import { resolveIssueNodeId, resolveConfig } from "../lib/helpers.js";
13
+ import { zBoolish } from "../lib/zod-helpers.js";
13
14
  // ---------------------------------------------------------------------------
14
15
  // Pure function: diffDependencyEdges
15
16
  // ---------------------------------------------------------------------------
@@ -52,8 +53,7 @@ export function registerPlanGraphTools(server, client) {
52
53
  planPath: z
53
54
  .string()
54
55
  .describe("Absolute path to the plan markdown document"),
55
- dryRun: z
56
- .boolean()
56
+ dryRun: zBoolish()
57
57
  .optional()
58
58
  .default(false)
59
59
  .describe("When true, report what would change without mutating GitHub. Default: false."),
@@ -9,6 +9,7 @@
9
9
  import { z } from "zod";
10
10
  import { toolSuccess, toolError } from "../types.js";
11
11
  import { buildBatchArchiveMutation } from "./batch-tools.js";
12
+ import { zBoolish } from "../lib/zod-helpers.js";
12
13
  import { ensureFieldCache, resolveProjectItemId, resolveFullConfig, updateProjectItemField, } from "../lib/helpers.js";
13
14
  // ---------------------------------------------------------------------------
14
15
  // Constants
@@ -406,7 +407,7 @@ export function registerProjectManagementTools(server, client, fieldCache) {
406
407
  .describe("Archive a single issue by number. Mutually exclusive with workflowStates filter."),
407
408
  projectItemId: z.string().optional()
408
409
  .describe("Archive by project item ID (for draft issues). Mutually exclusive with number and workflowStates."),
409
- unarchive: z.boolean().optional().default(false)
410
+ unarchive: zBoolish().optional().default(false)
410
411
  .describe("Unarchive instead of archive. Only works with number or projectItemId (single-item mode)."),
411
412
  workflowStates: z
412
413
  .array(z.string())
@@ -417,8 +418,7 @@ export function registerProjectManagementTools(server, client, fieldCache) {
417
418
  .optional()
418
419
  .default(50)
419
420
  .describe("Max items to archive per invocation (default 50, cap 200). Bulk mode only."),
420
- dryRun: z
421
- .boolean()
421
+ dryRun: zBoolish()
422
422
  .optional()
423
423
  .default(false)
424
424
  .describe("If true, return matching items without archiving them (default: false). Bulk mode only."),
@@ -7,6 +7,7 @@
7
7
  import { z } from "zod";
8
8
  import { toolSuccess, toolError } from "../types.js";
9
9
  import { resolveProjectOwner } from "../types.js";
10
+ import { zBoolish } from "../lib/zod-helpers.js";
10
11
  const WORKFLOW_STATE_OPTIONS = [
11
12
  { name: "Backlog", color: "GRAY", description: "Awaiting triage" },
12
13
  {
@@ -107,8 +108,7 @@ export function registerProjectTools(server, client, fieldCache) {
107
108
  .optional()
108
109
  .describe("Template project number to copy from. Overrides RALPH_GH_TEMPLATE_PROJECT env var. " +
109
110
  "When set, copies the template project (views, fields, automations) instead of creating blank."),
110
- createIterationField: z
111
- .boolean()
111
+ createIterationField: zBoolish()
112
112
  .optional()
113
113
  .default(false)
114
114
  .describe('When true, creates a "Sprint" iteration field with 2-week duration starting next Monday. ' +
@@ -12,6 +12,7 @@ import { isValidState, isEarlierState, VALID_STATES, PARENT_GATE_STATES, isParen
12
12
  import { toolSuccess, toolError } from "../types.js";
13
13
  import { ensureFieldCache, resolveIssueNodeId, resolveProjectItemId, updateProjectItemField, getCurrentFieldValue, resolveConfig, resolveFullConfig, resolveFullConfigOptionalRepo, syncStatusField, } from "../lib/helpers.js";
14
14
  import { paginateConnection } from "../lib/pagination.js";
15
+ import { zBoolish } from "../lib/zod-helpers.js";
15
16
  // ---------------------------------------------------------------------------
16
17
  // Sub-issue tree helpers (exported for testing)
17
18
  // ---------------------------------------------------------------------------
@@ -84,8 +85,7 @@ export function registerRelationshipTools(server, client, fieldCache) {
84
85
  childNumber: z
85
86
  .coerce.number()
86
87
  .describe("Child issue number (will become sub-issue of parent)"),
87
- replaceParent: z
88
- .boolean()
88
+ replaceParent: zBoolish()
89
89
  .optional()
90
90
  .default(false)
91
91
  .describe("If true, move child even if it already has a parent"),
@@ -692,8 +692,7 @@ export function registerRelationshipTools(server, client, fieldCache) {
692
692
  .optional()
693
693
  .default("OPEN")
694
694
  .describe("Filter parent issues by state (default: OPEN)"),
695
- showChildren: z
696
- .boolean()
695
+ showChildren: zBoolish()
697
696
  .optional()
698
697
  .default(false)
699
698
  .describe("Expand each group to include child issues with number/title/state/workflowState"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ralph-hero-mcp-server",
3
- "version": "2.5.126",
3
+ "version": "2.5.129",
4
4
  "description": "MCP server for GitHub Projects V2 - Ralph workflow automation",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",