mirror of
https://github.com/schpet/linear-cli.git
synced 2026-09-14 14:26:50 +08:00
10553fe632
project update could only replace a project's teams and labels, and could not change initiatives at all: project create accepts --initiative, but after creation the only route was a hand-written mutation. Every collection field an update command can change should offer the same three operations, following the pattern issue update already has for labels: --team/--label/--initiative replace the whole set, --add-* appends, --remove-* detaches, all repeatable, and a replace flag cannot be combined with its add/remove flags. Linear's ProjectUpdateInput only takes a full teamIds/labelIds list, so add and remove read the project's current connection, following every page, compute the new set, and send it. Removing something the project does not have is an error that lists what it does have, rather than a silent no-op, and removing the last team errors up front because Linear rejects an empty teamIds. Initiatives have no input field: membership is an InitiativeToProject join row, so all three initiative flags diff the desired set against the current rows and run initiativeToProjectDelete then initiativeToProjectCreate. Deletes go first because a project may appear only once in an initiative hierarchy, so moving it to a parent or child initiative is rejected while the old link still exists; that is also why a UUID-shaped initiative is confirmed to exist before any link is touched, since the shared resolver passes UUIDs through unchecked. Those mutations are not transactional, so a failure part-way reports what was applied, including the already-committed project fields, and what is still pending, with the remaining flags given by initiative ID because names are not unique, instead of implying a rollback. The survey of issue update and initiative update found no other replace-only collection flag: IssueUpdateInput's releaseIds and subscriberIds and InitiativeUpdateInput's labelIds are not exposed by either command. Claude-Session: https://claude.ai/code/session_01A9qEGri4p2HZMQSuYsBmub