From 71ce80ac05620a3aab7613ba4b2a08d08fa45a1d Mon Sep 17 00:00:00 2001 From: Peter Schilling Date: Fri, 4 Sep 2026 13:42:47 -0700 Subject: [PATCH] Add explicit clearing flags to issue update and project update issue update could set a due date, estimate, parent, project, or milestone but never remove one, and project update had the same gap for lead, start date, and target date. Only --unassign and --clear-cycle existed. cliffy rejects an empty string as a missing option value, so --due-date "" is not a workaround, and an agent driving the CLI had to fall back to a hand-written projectUpdate/issueUpdate mutation through linear api. Add one boolean clear flag per field, each placed after its set flag and modelled on --clear-cycle: it conflicts with its set flag (a ValidationError before any request, with a null check so --estimate 0 counts as a value), skips the lookup the set flag would run, and puts an explicit null in the mutation input. --clear-project also rejects --milestone, because a milestone belongs to the project being removed; --project with --clear-milestone is allowed so a move can detach a stale milestone in one update. The project update guard treats each clear flag as an update and its suggestion lists them. Linear honours null for every field, including startDate, verified on a scratch project and issue. Claude-Session: https://claude.ai/code/session_01A9qEGri4p2HZMQSuYsBmub --- CHANGELOG.md | 1 + README.md | 2 + docs/usage.md | 18 ++ skills/linear-cli/references/issue.md | 18 +- skills/linear-cli/references/project.md | 9 +- src/commands/issue/issue-update.ts | 125 +++++++++++- src/commands/project/project-update.ts | 83 +++++++- .../__snapshots__/issue-update.test.ts.snap | 40 +++- test/commands/issue/issue-update.test.ts | 187 ++++++++++++++++++ .../__snapshots__/project-update.test.ts.snap | 9 +- test/commands/project/project-update.test.ts | 96 +++++++++ 11 files changed, 554 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2d4bd74..2c2142bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - every command that takes a team now accepts its key, name, or UUID, resolved through one shared lookup: `team states`, `team members`, `team delete`, `label list/create/delete --team`, `cycle list/view --team`, `project list/create/update --team`, `document list/create/update --team`, and `issue query/mine/create/update --team`. Keys stay canonical and win over a same-spelled name; an unknown team errors with the list of valid keys instead of an empty result or a raw API error. Previously only keys worked, which is why [#276](https://github.com/schpet/linear-cli/issues/276) asked for `team list --json` as a name-to-key lookup - `issue query --state` and `issue mine --state` accept a workflow state name or ID as well as the six state types, looked up within the queried team scope (all teams under `--all-teams`, where a name matches every team's same-named state). An unknown name errors and lists the scope's states, and types and names can be mixed - `project update --content ` and `--content-file ` replace a project's long-form overview body, matching the flags `project create` already had. Previously the only way to change the body after creation was a hand-written `projectUpdate` mutation through `linear api` +- `issue update --clear-due-date`, `--clear-estimate`, `--clear-parent`, `--clear-project`, and `--clear-milestone`, plus `project update --clear-lead`, `--clear-start-date`, and `--clear-target-date`, to remove a value the way `--unassign` and `--clear-cycle` already do. Each sends an explicit `null` to Linear and errors when combined with its set flag; `--clear-project` also rejects `--milestone`, since a milestone belongs to the project being removed. Previously these fields could only be changed, never cleared: cliffy treats `--due-date ""` as a missing value - `--json` (`-j`) on `team list`, `cycle list`, `cycle view`, `milestone list`, `milestone view`, and `project view`, the last read commands without machine-readable output. List commands emit the same `{ nodes, pageInfo }` connection shape as the other list commands, after the same filtering and ordering as the table; view commands emit the GraphQL object as fetched, including every issue rather than the ten-item preview, and `milestone view --all --json` includes every page. (A 2.0.0 entry claimed `cycle list --json`; that change never actually landed.) ([#276](https://github.com/schpet/linear-cli/issues/276); thanks @lakardion) ### Fixed diff --git a/README.md b/README.md index f92884cb..6e62c1f0 100644 --- a/README.md +++ b/README.md @@ -145,6 +145,7 @@ linear issue create -t "title" -d "description" # create with flags linear issue create --project "My Project" --milestone "Phase 1" # create with milestone linear issue update # update an issue (interactive prompts) linear issue update ENG-123 --milestone "Phase 2" # set milestone on existing issue +linear issue update ENG-123 --clear-due-date --clear-parent # remove values (also --clear-estimate, --clear-project, --clear-milestone, --clear-cycle, --unassign) linear issue delete # delete an issue linear issue comment list # list comments on current issue linear issue comment add # add a comment to current issue @@ -202,6 +203,7 @@ linear project view --json # project details as JSON linear project create --name "API v2" --team ENG --content-file overview.md linear project create --name "Mobile launch" --team APP --priority high --label Launch --member jane@example.com linear project update --content-file overview.md # replace the project's overview body +linear project update --clear-lead --clear-target-date # remove values (also --clear-start-date) linear project comment list # list the project's discussion thread (UUID, slug, or name) linear project comment add --body "Kickoff Monday" # comment on a project linear project comment add --body "+1" --reply-to # reply in a thread diff --git a/docs/usage.md b/docs/usage.md index 7fbf3c64..2982021b 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -180,6 +180,21 @@ linear issue update TEAM-123 --remove-label sprint-42 --add-label sprint-43 linear issue update TEAM-123 --label bug --label frontend ``` +clear optional fields (each `--clear-*` flag conflicts with its set flag): + +```bash +# Remove the due date, estimate, parent, project, or milestone +linear issue update TEAM-123 --clear-due-date +linear issue update TEAM-123 --clear-estimate --clear-parent +linear issue update TEAM-123 --clear-project --clear-milestone + +# Move to another project and detach the milestone in one update +linear issue update TEAM-123 --project "Mobile App" --clear-milestone + +# Assignee and cycle have their own clearing flags +linear issue update TEAM-123 --unassign --clear-cycle +``` + #### other issue commands get issue id from current git branch: @@ -299,6 +314,9 @@ linear project update PROJECT-ID --description "Short summary" --content "## Ove # Replace the overview body from a markdown file linear project update PROJECT-ID --content-file overview.md + +# Remove the lead, start date, or target date (each conflicts with its set flag) +linear project update PROJECT-ID --clear-lead --clear-start-date --clear-target-date ``` #### list projects diff --git a/skills/linear-cli/references/issue.md b/skills/linear-cli/references/issue.md index 0defd226..d3453c92 100644 --- a/skills/linear-cli/references/issue.md +++ b/skills/linear-cli/references/issue.md @@ -598,10 +598,13 @@ Options: --workspace - Target workspace (uses credentials) -a, --assignee - Assign the issue to 'self' or someone (by username or name) --unassign - Clear the issue's assignee (cannot be combined with --assignee) - --due-date - Due date of the issue - --parent - Parent issue (if any) as a team_number code + --due-date - Due date of the issue. Use --clear-due-date to remove it + --clear-due-date - Remove the issue's due date (cannot be combined with --due-date) + --parent - Parent issue (if any) as a team_number code. Use --clear-parent to remove it + --clear-parent - Remove the issue's parent (cannot be combined with --parent) -p, --priority - Priority of the issue (1-4, descending priority) - --estimate - Points estimate of the issue + --estimate - Points estimate of the issue. Use --clear-estimate to remove it + --clear-estimate - Remove the issue's estimate (cannot be combined with --estimate) -d, --description - Description of the issue --description-file - Read description from a file (preferred for markdown content) -l, --label