Repository navigation
Add the three task commands: get, cancel and delete - #29
Conversation
`meili get tasks` covers `GET /tasks`, `meili cancel tasks` covers `POST /tasks/cancel` and `meili delete tasks` covers `DELETE /tasks`. The three routes take the same twelve selectors, so they are declared once in `src/lib/task-filters.ts` and spread into each command. `GET /tasks` pages with `from` and `next` rather than `offset` and `total`, which `commands.md` already names: `BaseCommand` gains the `fromPaginationFlags` group the contract's List routes group describes for a cursor route, `pagination.ts` gains `nextFromQuery`, and `outputList` takes the walk its route uses. `mergePages` now drops the fields that describe one page, whichever pair a route carries, and `output.md` says so. `cancel tasks` without a filter is passed through: the API answers `missing_task_filters` and the command exits 1. `delete tasks` without one is refused by the CLI, `cli_usage` and exit 2 before any network call, as `output.md` requires of a `delete`. On the way, `src/lib/tasks.ts` stops hinting `meili task get <uid>` on a `--wait` timeout, a command that never existed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Walkthrough
Merge Risk:
|
There was a problem hiding this comment.
🔇 Additional comments: 24
docs/contract/output.md: 1
113-113: LGTM!oclif.manifest.json: 1
1159-1167: LGTM!Also applies to: 1188-1351, 2485-2493, 2539-2879, 3484-3493, 3540-3651, 3660-3664, 3677-3688
src/commands/get/documents.ts: 1
7-7: LGTM!Also applies to: 83-83
src/commands/get/indexes.ts: 1
3-3: LGTM!Also applies to: 41-41
src/lib/base-command.ts: 1
39-43: LGTM!Also applies to: 123-139, 248-252, 262-268
test/contract/env.test.ts: 1
43-43: LGTM!test/lib/pagination.test.ts: 1
28-41: LGTM!Also applies to: 62-80, 84-97
src/lib/tasks.ts: 1
19-19: LGTM!Also applies to: 78-78
src/lib/task-filters.ts: 1
1-90: LGTM!src/commands/get/tasks.ts: 1
1-47: LGTM!test/helpers/meilisearch-handlers.ts: 1
120-152: LGTM!test/commands/get/tasks.test.ts: 1
1-120: LGTM!test/integration/meilisearch/get-tasks.test.ts: 1
1-70: LGTM!src/commands/cancel/tasks.ts: 1
1-31: LGTM!src/commands/delete/tasks.ts: 1
1-41: LGTM!docs/contract/commands.md: 1
52-52: LGTM!package.json: 1
57-59: LGTM!.changeset/first-version.md: 1
10-10: LGTM!test/commands/cancel/tasks.test.ts: 1
1-88: LGTM!test/commands/delete/tasks.test.ts: 1
1-82: LGTM!test/integration/meilisearch/cancel-tasks.test.ts: 1
1-59: LGTM!test/integration/meilisearch/delete-tasks.test.ts: 1
1-54: LGTM!test/lib/tasks.test.ts: 1
85-87: LGTM!src/lib/pagination.ts: 1
42-42:Trivial · Stability & Availability · Quick win
⚠️ Unverified finding
Verification ran but could not confirm this finding. It is shown for review, not as a verified issue.Reject a
nextcursor that equals the cursor just requested.
nextFromQueryreturns{ ...query, from: next }for every numericnext.iteratePagesthen callsfetchPageagain. If the server answers anextequal to the currentfrom, the same page is requested forever.--allthen never ends. Inndjsonmode it prints the same page without end. Injsonmode it buffers pages without end until memory runs out. A buggy or hostile server can cause this.Throw an error when the cursor does not move. Import
MeiliCliErrorfrom./errors.js. The contract has no code for a bad server answer, socli_internalis the closest existing one. Adding a new code is a contract change.🛡️ Proposed fix
export function nextFromQuery(query: FromQuery, page: ListPage): FromQuery | undefined { const next = page.next; - return typeof next === "number" ? { ...query, from: next } : undefined; + if (typeof next !== "number") return undefined; + if (next === query.from) { + throw new MeiliCliError( + "cli_internal", + `The API answered the cursor \`next\` ${next} that the request already used.`, + ); + } + return { ...query, from: next }; }Based on learnings: "detect and reject responses where the server indicates more pages ... but the returned end cursor is unchanged from the previous request."
Source: Learnings

Review info
-
Run configuration-
- Source mode: Auto
- Repository: Unavailable
- Branch: Unavailable
- File: No configuration file from this repository applied
- Commit: Unavailable
- Layers: Organization UI
- Review profile: CHILL
- Plan: Essentials
- Run ID:
4c8a361d-bc12-4682-87ea-a756781860e3
Files ignored due to path filters: 5-
test/commands/cancel/__snapshots__/tasks.test.ts.snapis excluded by!**/*.snaptest/commands/delete/__snapshots__/tasks.test.ts.snapis excluded by!**/*.snaptest/commands/get/__snapshots__/tasks.test.ts.snapis excluded by!**/*.snaptest/contract/__snapshots__/commands.test.ts.snapis excluded by!**/*.snaptest/contract/__snapshots__/help.test.ts.snapis excluded by!**/*.snap
Files selected for processing: 24-
.changeset/first-version.mddocs/contract/commands.mddocs/contract/output.mdoclif.manifest.jsonpackage.jsonsrc/commands/cancel/tasks.tssrc/commands/delete/tasks.tssrc/commands/get/documents.tssrc/commands/get/indexes.tssrc/commands/get/tasks.tssrc/lib/base-command.tssrc/lib/pagination.tssrc/lib/task-filters.tssrc/lib/tasks.tstest/commands/cancel/tasks.test.tstest/commands/delete/tasks.test.tstest/commands/get/tasks.test.tstest/contract/env.test.tstest/helpers/meilisearch-handlers.tstest/integration/meilisearch/cancel-tasks.test.tstest/integration/meilisearch/delete-tasks.test.tstest/integration/meilisearch/get-tasks.test.tstest/lib/pagination.test.tstest/lib/tasks.test.ts
Included review availability: This review used your included allowance. 4 included reviews remain after this review. Your included PR review attempts over the past 7 days set your current allowance at 5 reviews per hour.
-
What
Add
meili get tasks,meili cancel tasksandmeili delete tasks, the three stable routes of/tasks.Contract
docs/contract/commands.md, and each route is reachable by a distinct set of flags, or the exception is recorded with its reason (or this pull request changes the contract and nothing else)src/lib/output.ts, errors throughsrc/lib/errors.ts$EDITOR; adeletecommand spreadsBaseCommand.confirmFlagsand its examples carry--yesfetchoutsidesrc/lib/clients/Tests
--helpsnapshot added or updated on purposepnpm lint,pnpm typecheck,pnpm testpass locallySimplicity
src/lib/, is used by this command, and is named belowDocs
docs/contract/updated for every name, flag, variable or code this change adds or renames, or nothing to updateHousekeeping
oclif.manifest.jsonregeneratedNotes for the reviewer
meili get tasksGET /taskstasks.getmeili cancel tasksPOST /tasks/canceltasks.cancelmeili delete tasks --yesDELETE /taskstasks.deleteThree commands of one resource in one change, as rule 10 allows.
POST /tasks/compactis left out: it is an experimental route, already recorded as an exception.GET /tasks/streamandGET /tasks/{task_id}/documentsstay recorded without command.Shared pieces added to
src/lib/, used by the three commandssrc/lib/task-filters.ts: the twelve selectors the three routes share (--ids,--batch-ids,--index-ids,--canceled-by,--types,--statusesand the six date filters), plus the query they build. Spread into each command's ownflags, someili schema --commandshows them (ADR 0010).GET /batchestakes the same filters, so this file is where that command will find them.src/lib/pagination.ts:GET /taskspages withfrom/next, notoffset/total— the shapecommands.mdalready names in its List routes group.nextFromQueryfollows the cursor, andoutputListtakes the walk its route uses as a fourth argument, soget indexesandget documentsnow namenextOffsetQuery.mergePagesdrops the fields that describe one page itself; a route carries one pair or the other, so dropping all three is dropping its.src/lib/base-command.ts:fromPaginationFlags,--limit/--from/--all.--limitand--allare the same flag objects aspaginationFlags, so the wording lives once. Added to the group list oftest/contract/env.test.ts, which rule 14 walks.Interface decisions
cancel taskswith no filter is passed through to the API, which answersmissing_task_filtersand exits 1.delete taskswith no filter is refused by the CLI,cli_usageand exit 2 before any network call, becauseoutput.mdrequires it of adelete. The two differ on purpose: the destructive rule covers the verbdeleteand nothing else.--statusesand--typesdeclare no closed list of values. The API accepts*next to its enum, and the values are comma-separated, which an oclifoptionslist would validate as one string. The text travels as written and the API names what it refuses, asoutput.mdsays.--allonget tasksfollows thenextcursor and merges into one envelope withlimitandfromdropped.output.mdsaidlimitandoffset; the sentence now covers both shapes.One simplification considered and not taken
outputList's fourth argument could go away by havingpagination.tsread the envelope shape ("next" in page), which would also keepget indexesandget documentsout of this diff. TheAllTasksschema of the OpenAPI document lists onlyresults,totalandlimitasrequired:fromandnextare optional. Anextthe API omitted would fall through to the offset walk and re-fetch from the start, so the route's walk is named at the call site instead.Unrelated line fixed on the way
src/lib/tasks.tshintedmeili task get <uid>on a--waittimeout, a command that never existed. It now namesmeili get tasks --ids <uid>.No new dependency.
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
get taskswith filters for task IDs, indexes, status, type, batches, and date ranges, plus cursor pagination and--alloutput.cancel tasksanddelete taskswith matching filters. Deletion requires--yes; both commands can wait for a final task status.get indexessupport for listing and retrieving indexes.Documentation