feat: add --assignee flag to task search#10
feat: add --assignee flag to task search#10nick-preda wants to merge 1 commit intotriptechtravel:mainfrom
Conversation
Resolves assignee by name, username, or numeric ID (case-insensitive substring match). Fetches up to 10 pages of tasks assigned to that person via the team-task API. If a query is also provided, results are filtered client-side by name/description. Examples: clickup task search --assignee Michela clickup task search "bug" --assignee 42547184 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
PR Review: --assignee flag for task search
Note (v0.21.0): Main has been significantly refactored since this PR was opened. You will need to rebase against main. Key changes:
search.go:dedupScoredrefactored (index-based),searchTaskCommentsuses bounded concurrency (5-worker pool), all hardcoded URLs replaced withclient.URL()/client.BaseURL()- Test infrastructure available at
internal/testutil/— new features should include tests
Core approach is solid — using fetchTeamTasks with assignees[] param is the right call. A few things to address before merging:
Must Fix
Rebase against main. search.go has significant refactors (dedup algorithm, concurrent comment search, URL replacement). This PR will have merge conflicts.
No tests for new code. resolveAssigneeID has three distinct match paths (numeric, exact username, substring) — this is very testable. Update: internal/testutil/ is now available on main with TestFactory, httptest.Server, and RunCommand helpers. Use these for integration tests. Extract the matching logic into a standalone function that takes []resolvedMember + input string, and cover:
- exact numeric ID match
- numeric ID not in member list (see below)
- exact username match (case-insensitive)
- substring username match
- ambiguous substring (multiple matches)
- no match
--assignee silently ignores --space/--folder. Because the assignee check runs before the space/folder check, combining them silently drops the scope filter. Either return an error when both are provided, or wire the assignees[]=ID param into searchViaSpaces.
Use client.URL()/client.BaseURL() for all raw HTTP calls. Hardcoded https://api.clickup.com/api/v2/... URLs have been removed from main. This PR needs to follow the same pattern.
Should Fix
Reuse searchLevel instead of reimplementing the pagination loop. searchByAssignee with a query duplicates the page-fetch + filterTasks + comment-search pattern that searchLevel already handles. When opts.query != "", you could just call:
return searchLevel(ctx, client, teamID, strings.ToLower(opts.query),
assigneeParam, 10, opts.comments, ios)Numeric ID fallback trusts unvalidated input. If a numeric ID isn't found in the member list, resolveAssigneeID silently returns it as-is. This should error — if the user gave an ID not in the workspace, it's likely a mistake.
Ambiguous substring matches are silent. If "mi" matches both "michela" and "mike", first wins with no indication. Collect all substring matches and error with "ambiguous match, did you mean: michela, mike?" if >1.
Nice to Have
cmd.Usestill sayssearch <query>but the arg is now optional — update tosearch [query]resolveAssigneeIDre-reads config viaf.Config()to get workspace ID, butteamIDis already resolved indoSearch— pass it through to avoid the redundant call- No-query path tags all results as
matchSubstringwhich is semantically misleading — consider amatchAssigneekind
Problem
There is no way to search tasks by assignee across the workspace. To find all tasks assigned to a team member, users must either know specific list IDs or manually filter JSON output — neither is practical from the CLI.
Solution
Add an
--assigneeflag totask searchthat accepts a name, username, or numeric ID.Assignee resolution
The flag resolves the input against workspace members in this order:
Invalid names produce a clear error:
Combined with query
When both
--assigneeand a query are provided, tasks are fetched by assignee first, then filtered client-side by name/description:Standalone usage
When only
--assigneeis provided (no query), all tasks for that person are returned:The command now accepts 0 or 1 positional args (was exactly 1). Validation ensures at least a query or
--assigneeis provided.Implementation details
resolveAssigneeIDfetches workspace members viaGetTeamsand resolves input to aresolvedMember{Username, ID}searchByAssigneeuses the existingfetchTeamTaskswithassignees[]={id}param (up to 10 pages)--assigneetakes priority over--space/--folderto avoid silent flag conflictsstrconv.Atoi(notfmt.Sscanf) for strict numeric detectionTest plan
--assignee Michela— resolves by partial name, lists tasks--assignee 42547184— resolves by numeric ID, shows display name--assignee "mich"— substring match works--assignee INVENTATO— clear error message--assignee Michela --json— valid JSON output"persi" --assignee Michela— query + assignee combined filteringgo test -race ./...— no data races🤖 Generated with Claude Code