Skip to content

feat(workitems): extend manage_work_item with date, time tracking, and tier-specific widgets #135

@polaz

Description

@polaz

Summary

Extend manage_work_item with additional widget parameters and linked items management that GitLab API supports but our tool currently doesn't expose.

Current State

manage_work_item supports: title, description, state, assigneeIds, labelIds, milestoneId

browse_work_items already fetches linkedItems { nodes { linkType, workItem } } in GraphQL queries — but there's no way to create or remove links.

Target State — New Parameters

Free Tier (CE)

Parameter Widget Input Type Description
startDate startAndDueDateWidget Date (YYYY-MM-DD) Start date
dueDate startAndDueDateWidget Date (YYYY-MM-DD) Due date
parentId hierarchyWidget ID Set/remove parent work item (use null to unlink)
childrenIds hierarchyWidget ID[] Add children work items
timeEstimate timeTrackingWidget String ("1h 30m") Time estimate in human-readable format
timeSpent timeTrackingWidget.timelog String ("2h") Log time spent (adds timelog entry)
timeSpentAt timeTrackingWidget.timelog DateTime (ISO 8601) When time was spent (optional, defaults to now)
timeSpentSummary timeTrackingWidget.timelog String Summary of work done (optional)

Premium Tier (EE)

Parameter Widget Input Type Description
isFixed startAndDueDateWidget Boolean Fixed dates (not inherited from children)
weight weightWidget Integer Story points / weight
iterationId iterationWidget ID Assign to iteration/sprint
progressCurrentValue progressWidget Integer Current progress value (OKR)

Ultimate Tier (EE)

Parameter Widget Input Type Description
healthStatus healthStatusWidget Enum (onTrack, needsAttention, atRisk) Health status
color colorWidget String (hex) Custom color (epics)

Target State — Linked Items (New Actions)

Problem

GitLab Work Items support relationship links (blocks/blocked_by/relates_to) via separate mutations workItemAddLinkedItems and workItemRemoveLinkedItems. Our tool has read support (browse_work_items returns linkedItems) but no write support.

New Actions in manage_work_item

Action Description
add_link Add a relationship link between two work items
remove_link Remove a relationship link between two work items

Link Types

linkType GraphQL Enum Description
BLOCKS BLOCKS This item blocks the target
IS_BLOCKED_BY IS_BLOCKED_BY This item is blocked by the target
RELATES_TO RELATED General relationship

Parameters for add_link

Parameter Type Required Description
id string Yes Source work item ID (numeric)
targetId string Yes Target work item ID to link to (numeric)
linkType enum Yes Relationship type: BLOCKS, IS_BLOCKED_BY, RELATES_TO

Parameters for remove_link

Parameter Type Required Description
id string Yes Source work item ID (numeric)
targetId string Yes Target work item ID to unlink (numeric)
linkType enum Yes Relationship type to remove: BLOCKS, IS_BLOCKED_BY, RELATES_TO

GraphQL Mutations

# Add link
mutation workItemAddLinkedItems($input: WorkItemAddLinkedItemsInput!) {
  workItemAddLinkedItems(input: $input) {
    workItem { id iid title }
    errors
    message
  }
}

# Input:
# { id: "gid://gitlab/WorkItem/123", workItemsIds: ["gid://gitlab/WorkItem/456"], linkType: BLOCKS }

# Remove link
mutation workItemRemoveLinkedItems($input: WorkItemRemoveLinkedItemsInput!) {
  workItemRemoveLinkedItems(input: $input) {
    workItem { id iid title }
    errors
    message
  }
}

# Input:
# { id: "gid://gitlab/WorkItem/123", workItemsIds: ["gid://gitlab/WorkItem/456"], linkType: BLOCKS }

Tier Requirement

Linked items are Free tier — available on all GitLab instances (CE and EE).

Hierarchy Widget Details

The hierarchyWidget also supports reordering:

  • adjacentWorkItemId — ID of sibling to position relative to
  • relativePositionBEFORE or AFTER

This enables setting parent (linking Issue->Epic), adding children, and reordering within a parent.

Documentation Updates Required

1. docs/TOOLS.md (auto-generated)

After implementation, regenerate with yarn list-tools --export --toc > docs/TOOLS.md. The following changes will appear:

manage_work_item section — new actions and parameters:

  • Add add_link and remove_link to actions table
  • Add all new widget parameters to create and update action tables
  • Add tier badges for Premium/Ultimate parameters

browse_work_items section — verify linkedItems appear in response docs (already fetched by GraphQL).

2. docs/tools/index.md

Update the work items tool summary table:

| `manage_work_item` | Command | Create, update, delete, link/unlink work items |

3. Schema .describe() annotations (CRITICAL for auto-docs)

Every new parameter MUST have proper .describe() in Zod schema for doc generation:

startDate: z.string().optional().describe("Start date in YYYY-MM-DD format"),
linkType: z.enum(["BLOCKS", "IS_BLOCKED_BY", "RELATES_TO"]).describe("Relationship type between work items"),

4. docs/advanced/ (if exists) or README

Add a "Work Item Relationships" section explaining:

  • How to use add_link / remove_link actions
  • linkType semantics (BLOCKS means "this item blocks target")
  • How linked items appear in browse_work_items response

Integration Tests

Data Lifecycle Pattern

Follow the project's data lifecycle approach — create test infrastructure once, share across tests:

1. SETUP (beforeAll):
   - Create test Epic (group level)
   - Create test Issue (project level)
   - Create 2 additional test Issues (for linking tests)
   - Create test Task (project level)
   - Create test Iteration (if Premium)
   - Store IDs for dependent tests

2. TEST CASES (sequential, --runInBand):
   
   // === Dates ===
   - Create issue with startDate + dueDate -> verify in response
   - Update issue: change dueDate -> verify updated
   - Update issue: clear startDate (null) -> verify removed
   - Create epic with isFixed=true (Premium) -> verify
   
   // === Hierarchy ===
   - Update task: set parentId to issue -> verify parent in response
   - Update issue: set parentId to epic -> verify hierarchy
   - Update issue: add childrenIds [task] -> verify children
   - Update task: set parentId to null -> verify unlinked
   - Reorder: adjacentWorkItemId + relativePosition
   
   // === Linked Items (NEW) ===
   - add_link: issue1 BLOCKS issue2 -> verify in browse_work_items response
   - add_link: issue1 RELATES_TO issue3 -> verify both links exist
   - browse issue2 -> verify IS_BLOCKED_BY appears (reverse link)
   - remove_link: issue1 BLOCKS issue2 -> verify removed
   - add_link: issue2 IS_BLOCKED_BY issue3 -> verify
   - remove_link: issue2 IS_BLOCKED_BY issue3 -> verify removed
   - Verify all links cleaned up (no orphan links)
   
   // === Time Tracking ===
   - Update issue: set timeEstimate "4h" -> verify humanTimeEstimate
   - Update issue: add timeSpent "1h 30m" with summary -> verify totalTimeSpent
   - Update issue: add timeSpent "2h" with spentAt -> verify accumulated
   - Update issue: reset timeEstimate "0h" -> verify cleared
   
   // === Weight (Premium) ===
   - Update issue: set weight=5 -> verify
   - Update issue: clear weight (null) -> verify removed
   
   // === Iteration (Premium) ===
   - Update issue: set iterationId -> verify
   - Update issue: clear iterationId -> verify removed
   
   // === Health Status (Ultimate) ===
   - Update issue: set healthStatus="needsAttention" -> verify
   - Update issue: set healthStatus="onTrack" -> verify changed
   
   // === Color (Epics, Ultimate) ===
   - Update epic: set color="#FF5733" -> verify
   - Update epic: change color="#00AA00" -> verify
   
   // === Progress (OKR, Premium) ===
   - Create Objective + Key Result
   - Update Key Result: set progressCurrentValue=50 -> verify
   - Update Key Result: set progressCurrentValue=100 -> verify
   
3. TEARDOWN (afterAll):
   - Remove all links first (remove_link)
   - Delete test work items in reverse order (children first)

Edge Cases (Unit Tests)

// Validation errors
- Invalid date format "2024-13-45" -> expect validation error
- parentId pointing to wrong level (issue as parent of epic) -> expect hierarchy error
- timeEstimate invalid format ("abc") -> expect parsing error
- weight negative number -> expect validation error
- Widget parameters on Free tier when Premium required -> expect tier error (after #136)

// Linked items edge cases
- add_link with same source and target ID -> expect error
- add_link duplicate (same link already exists) -> expect graceful handling (idempotent or error)
- remove_link that doesn't exist -> expect graceful handling
- add_link with invalid linkType -> expect Zod validation error
- add_link with non-existent target ID -> expect API error with clear message

Schema Validation

  • All new widget fields in GraphQL response must be typed
  • Verify response includes widget data after create/update
  • Validate against real API responses (dynamic assertions, no hardcoded IDs)
  • Linked items response: verify linkType and workItem structure

Implementation Notes

Widget Parameters (update/create)

  • Parameters should be added to both create and update action schemas
  • GraphQL mutations already return these widgets in browse queries (types + queries exist in src/graphql/workItems.ts)
  • Widget interface types already defined: WorkItemStartAndDueDateWidget, WorkItemTimeTrackingWidget, WorkItemWeightWidget, WorkItemHealthStatusWidget, WorkItemProgressWidget, WorkItemColorWidget, WorkItemHierarchyWidget
  • UPDATE_WORK_ITEM GraphQL mutation needs to be extended with new widget fragments in response
  • hierarchyWidget input uses parent_id (nullable) + children_ids (array)

Linked Items (add_link/remove_link)

  • Uses SEPARATE GraphQL mutations (workItemAddLinkedItems / workItemRemoveLinkedItems), NOT widget input on update
  • Must normalize numeric IDs to GIDs before mutation (same pattern as other tools)
  • WorkItemLinkedItemsWidget interface needs update: nodes should include linkType: string field
  • GraphQL already fetches linkType in queries (line 775) but interface (line 248-253) doesn't type it
  • Response should return updated work item with all current links

Files to Modify

File Changes
src/entities/work-items/schema.ts Add new params to create/update schemas, add add_link/remove_link action schemas
src/entities/work-items/handler.ts Handle new widget params in mutation builder, add link handlers
src/graphql/workItems.ts Add WORK_ITEM_ADD_LINKED_ITEMS and WORK_ITEM_REMOVE_LINKED_ITEMS mutations, fix WorkItemLinkedItemsWidget interface
src/entities/work-items/registry.ts Update tool description to mention linking
src/__tests__/integration/work-items-widgets.test.ts New integration test file
src/__tests__/unit/work-items/ Unit tests for new schema/handler logic
docs/TOOLS.md Auto-regenerated after implementation
docs/tools/index.md Update summary table

GitLab API Source

Widget Inputs (update mutation)

Linked Items (separate mutations)

Depends On

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions