Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | 16x 16x 16x 28x 16x 3x 16x 1x 16x 16x 16x 16x 16x 16x 16x 35x 18x 18x 18x 7x | import { z } from "zod";
// ============================================================================
// Base schemas for work items
// ============================================================================
export const WorkItemIdSchema = z
.string()
.min(1)
.describe(
"Work item ID - use numeric ID from list results (e.g., '5953'). " +
"GID format also accepted and auto-normalized (e.g., 'gid://gitlab/WorkItem/5953')."
);
export const WorkItemTypeEnumSchema = z
.string()
.transform(val => val.toUpperCase().replace(/\s+/g, "_"))
.pipe(
z.enum([
"EPIC",
"ISSUE",
"TASK",
"INCIDENT",
"TEST_CASE",
"REQUIREMENT",
"OBJECTIVE",
"KEY_RESULT",
])
)
.describe("Type of work item");
export const WorkItemStateSchema = z
.string()
.transform(val => val.toUpperCase())
.pipe(z.enum(["OPEN", "CLOSED"]))
.describe("State of work item");
export const WorkItemStateEventSchema = z
.string()
.transform(val => val.toUpperCase())
.pipe(z.enum(["CLOSE", "REOPEN"]))
.describe("State event for updating work item");
// ============================================================================
// browse_work_items - CQRS Query Tool (discriminated union schema)
// Actions: list, get
// Uses z.discriminatedUnion() for type-safe action handling.
// Schema pipeline flattens to flat JSON Schema for AI clients that don't support oneOf.
// ============================================================================
// --- Shared fields ---
const workItemIdField = WorkItemIdSchema.describe(
"Work item ID to retrieve - use numeric ID from list results (e.g., '5953')"
);
const workItemIidField = z
.string()
.min(1)
.describe("Internal ID from URL (e.g., '95' from /issues/95). Use with namespace parameter.");
const namespaceField = z
.string()
.describe("Namespace path containing the work item (e.g., 'group/project')");
// --- Action: list ---
const ListWorkItemsSchema = z.object({
action: z.literal("list").describe("List work items with filtering"),
namespace: z
.string()
.describe(
"Namespace path (group or project). Groups return epics, projects return issues/tasks."
),
types: z.array(WorkItemTypeEnumSchema).optional().describe("Filter by work item types"),
state: z
.array(WorkItemStateSchema)
.optional()
.default(["OPEN"])
.describe(
'Filter by work item state. Defaults to OPEN items only. Use ["OPEN", "CLOSED"] for all items.'
),
first: z.number().optional().default(20).describe("Number of items to return"),
after: z
.string()
.optional()
.describe("Cursor for pagination (use endCursor from previous response)"),
simple: z
.boolean()
.optional()
.default(true)
.describe(
"Return simplified structure with essential fields only. RECOMMENDED: Use default true for most cases."
),
});
// --- Action: get ---
// Supports two lookup methods:
// 1. By namespace + iid (preferred for URL-based lookups)
// 2. By global id (for items from list results)
const GetWorkItemSchema = z.object({
action: z.literal("get").describe("Get single work item details"),
// Lookup by namespace + IID (preferred for URL-based requests)
namespace: namespaceField.optional(),
iid: workItemIidField.optional(),
// Lookup by global ID (backward compatible)
id: workItemIdField.optional(),
});
// --- Discriminated union combining all actions ---
// Base union for type narrowing
const BrowseWorkItemsBaseSchema = z.discriminatedUnion("action", [
ListWorkItemsSchema,
GetWorkItemSchema,
]);
// Add validation for "get" action: must have either (namespace + iid) or (id)
export const BrowseWorkItemsSchema = BrowseWorkItemsBaseSchema.superRefine((data, ctx) => {
if (data.action === "get") {
const hasNamespaceIid = data.namespace !== undefined && data.iid !== undefined;
const hasId = data.id !== undefined;
if (!hasNamespaceIid && !hasId) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message:
"Either 'id' (global ID) or both 'namespace' and 'iid' (from URL) must be provided",
path: ["id"],
});
}
}
});
// ============================================================================
// Type exports
// ============================================================================
export type BrowseWorkItemsInput = z.infer<typeof BrowseWorkItemsSchema>;
export type WorkItemTypeEnum = z.infer<typeof WorkItemTypeEnumSchema>;
export type WorkItemState = z.infer<typeof WorkItemStateSchema>;
|