Conversation
… list
`task search` and `export tasks` walked workspace → spaces → folders → lists and
called GetTasks per list. That cost one request per list under a 100 req/min
limit, and since only page 0 was ever fetched, any list past 100 tasks was
silently cut off. export also discarded GetFolders/GetLists errors, so it could
omit whole subtrees and still report success.
Both now issue one server-side query per workspace against
GET /team/{id}/task, paged to exhaustion. Against a small real workspace this
takes search from 3.7s to 1.1s; the gap widens with list count.
Pagination is bounded by DefaultMaxTaskPages and reports Truncated when it stops
early, so a capped result is never presented as a complete one — the failure
mode this issue is about. The paging loop is extracted as `paginate` so
termination and truncation are testable without a network round trip.
Search and export defaults deliberately mirror the old crawl (open tasks, no
subtasks) to keep this a performance fix; the endpoint makes the fuller set
reachable via new --include-closed and --subtasks flags. Verified that default
results match v0.2.1 exactly on a real workspace.
Adds Client.FindTasksByCustomField and `cu field find`, the reverse lookup from
a value stored in a custom field back to the task holding it, which the crawl
could not do at any acceptable cost.
Fixes #25
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014aqbmccWm1tqttmBUCR5rv
ClickUp: 86dxbeqyt
These four files were swept into the previous commit by a broad `git add` while another change was in progress in the same working tree. They are unrelated to the search/export work this branch is about, and that commit's message does not mention them — so a change to what `cu config get` prints, and a new write guard on .cu.yml, were riding along undisclosed on a PR titled as a performance fix. They now live on their own in #50, against a clean main, where the security surface gets reviewed on its own terms. Nothing here depended on them: no code on this branch references GlobalConfigPath, stripCredentials, RedactedValue or IsCredentialKey, and the suite passes without them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015ZEGsLHBQ2GzP6v48i4hXz
Note: four files removed from this branchHeads up if you are working on this branch — I pushed a commit removing four files that did not belong to it.
They now live on their own in #50, against a clean Nothing on this branch depended on them: no code here references The search/export work itself is untouched — I have not reviewed it yet, and will do that separately. |
Brings in #50 and #51. One conflict, in the export flag block, where this branch's --include-closed/--subtasks met #51 moving the destination file off -o/--output onto --file/-F. Both sides kept: the new filters stay, and -o is left to the global format flag as #51 intends. Resolved as a merge rather than a rebase because another session owns this branch; force-pushing rewritten history over it is the one operation that could destroy work in progress. Docs regenerated for the combined flag set — the auto-merged page still advertised -o as the output file, which is no longer true. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015ZEGsLHBQ2GzP6v48i4hXz
Updated against
|
Summary
Fixes #25.
task searchandexport taskswalked workspace → spaces → folders → lists and calledGetTasksper list. Three problems, all of which this replaces with one server-side query per workspace againstGET /team/{team_id}/task:export.godiscardedGetFolders/GetListserrors (folders, _ := …), so whole subtrees could vanish and the export still reported success.Measured on a small real workspace,
task search: 3.74s → 1.14s. The gap widens with list count, since the old cost was linear in lists and the new one is linear in pages of results.Truncation is now reported, not hidden
Pagination is bounded by
DefaultMaxTaskPagesand returnsTruncatedwhen it stops early, so a capped result is never presented as complete — that being the actual bug in this issue. Both commands print a warning when it happens.The paging loop is extracted as
paginateso termination and truncation are testable without a network round trip.Behaviour is deliberately unchanged by default
The team endpoint can return closed tasks and subtasks, which the per-list crawl never did. Turning that on by default would have quietly changed what
searchreturns — on this workspace,search cuwent from 2 results to 4, the extra two being subtasks. That is a better answer, but it is not what this issue asked for, so:--include-closedand--subtasksflags on both commands.--spacegiven as a name still works: tasks carry only a space id, so the name is resolved to an id first rather than dropping the capability.New: reverse lookup
Client.FindTasksByCustomFieldandcu field find— from a value stored in a custom field back to the task holding it. The crawl could not do this at any acceptable cost; the endpoint filters custom fields server-side.A field id works anywhere; a field name is resolved against
--listor the default list, since fields are only enumerable per list. No match exits 0 with an empty result rather than erroring.Tests
TestPaginatecovers stopping on a short page, a single short page, an empty first page, the exactly-full-last-page case (which costs one extra request to discover), hitting the cap and reporting truncation, and errors aborting rather than returning a partial set.TestTeamTaskQueryToSDKcovers filter pass-through and omission of empty filters.Checklist
./scripts/ci.shpasses locally — excepterrcheck, which reports the same pre-existing findings onmain, none in files this PR touchescu docs markdown --dir docs/site/commands) andcu field findadded to the mkdocs nav