@omnicoreos/planka-mcp 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/plugins/marketplace.json +20 -0
- package/.claude-plugin/marketplace.json +26 -0
- package/.claude-plugin/plugin.json +45 -0
- package/.codex-plugin/mcp.json +16 -0
- package/.codex-plugin/plugin.json +27 -0
- package/.mcp.json +17 -0
- package/CHANGELOG.md +510 -0
- package/README.es.md +294 -55
- package/README.md +293 -55
- package/dist/cli/init.d.ts +101 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +481 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/client.d.ts +32 -4
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +106 -32
- package/dist/client.js.map +1 -1
- package/dist/config/policy.d.ts +82 -0
- package/dist/config/policy.d.ts.map +1 -0
- package/dist/config/policy.js +226 -0
- package/dist/config/policy.js.map +1 -0
- package/dist/errors.d.ts +5 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +62 -5
- package/dist/errors.js.map +1 -1
- package/dist/identity.generated.d.ts +2 -1
- package/dist/identity.generated.d.ts.map +1 -1
- package/dist/identity.generated.js +2 -1
- package/dist/identity.generated.js.map +1 -1
- package/dist/index.js +85 -10
- package/dist/index.js.map +1 -1
- package/dist/instructions.d.ts +21 -0
- package/dist/instructions.d.ts.map +1 -0
- package/dist/instructions.js +37 -0
- package/dist/instructions.js.map +1 -0
- package/dist/operations/actions.d.ts +654 -0
- package/dist/operations/actions.d.ts.map +1 -0
- package/dist/operations/actions.js +154 -0
- package/dist/operations/actions.js.map +1 -0
- package/dist/operations/archive.d.ts +28 -0
- package/dist/operations/archive.d.ts.map +1 -0
- package/dist/operations/archive.js +74 -0
- package/dist/operations/archive.js.map +1 -0
- package/dist/operations/attachments.d.ts +1 -1
- package/dist/operations/attachments.d.ts.map +1 -1
- package/dist/operations/attachments.js +3 -1
- package/dist/operations/attachments.js.map +1 -1
- package/dist/operations/board-id.d.ts +1 -1
- package/dist/operations/board-id.d.ts.map +1 -1
- package/dist/operations/board-id.js +13 -7
- package/dist/operations/board-id.js.map +1 -1
- package/dist/operations/boards.d.ts +96 -19
- package/dist/operations/boards.d.ts.map +1 -1
- package/dist/operations/boards.js +377 -93
- package/dist/operations/boards.js.map +1 -1
- package/dist/operations/card-brief.d.ts +91 -0
- package/dist/operations/card-brief.d.ts.map +1 -0
- package/dist/operations/card-brief.js +79 -0
- package/dist/operations/card-brief.js.map +1 -0
- package/dist/operations/cards.d.ts +34 -9
- package/dist/operations/cards.d.ts.map +1 -1
- package/dist/operations/cards.js +60 -14
- package/dist/operations/cards.js.map +1 -1
- package/dist/operations/comments.d.ts +61 -4
- package/dist/operations/comments.d.ts.map +1 -1
- package/dist/operations/comments.js +91 -8
- package/dist/operations/comments.js.map +1 -1
- package/dist/operations/duplicate.d.ts +16 -0
- package/dist/operations/duplicate.d.ts.map +1 -0
- package/dist/operations/duplicate.js +43 -0
- package/dist/operations/duplicate.js.map +1 -0
- package/dist/operations/labels.d.ts +1 -1
- package/dist/operations/labels.d.ts.map +1 -1
- package/dist/operations/labels.js +7 -4
- package/dist/operations/labels.js.map +1 -1
- package/dist/operations/lists.d.ts +63 -1
- package/dist/operations/lists.d.ts.map +1 -1
- package/dist/operations/lists.js +97 -2
- package/dist/operations/lists.js.map +1 -1
- package/dist/operations/members.d.ts +39 -0
- package/dist/operations/members.d.ts.map +1 -0
- package/dist/operations/members.js +107 -0
- package/dist/operations/members.js.map +1 -0
- package/dist/operations/projects.d.ts +16 -0
- package/dist/operations/projects.d.ts.map +1 -1
- package/dist/operations/projects.js +54 -9
- package/dist/operations/projects.js.map +1 -1
- package/dist/operations/tasks.d.ts +1 -1
- package/dist/operations/tasks.d.ts.map +1 -1
- package/dist/operations/tasks.js +5 -3
- package/dist/operations/tasks.js.map +1 -1
- package/dist/operations/users.d.ts +123 -0
- package/dist/operations/users.d.ts.map +1 -0
- package/dist/operations/users.js +180 -0
- package/dist/operations/users.js.map +1 -0
- package/dist/operations/verify.d.ts +84 -0
- package/dist/operations/verify.d.ts.map +1 -0
- package/dist/operations/verify.js +124 -0
- package/dist/operations/verify.js.map +1 -0
- package/dist/prompts.d.ts +48 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +155 -0
- package/dist/prompts.js.map +1 -0
- package/dist/resources.d.ts +38 -0
- package/dist/resources.d.ts.map +1 -0
- package/dist/resources.js +127 -0
- package/dist/resources.js.map +1 -0
- package/dist/schemas/entities.d.ts +115 -24
- package/dist/schemas/entities.d.ts.map +1 -1
- package/dist/schemas/entities.js +48 -0
- package/dist/schemas/entities.js.map +1 -1
- package/dist/schemas/requests.d.ts +121 -46
- package/dist/schemas/requests.d.ts.map +1 -1
- package/dist/schemas/requests.js +57 -12
- package/dist/schemas/requests.js.map +1 -1
- package/dist/schemas/responses.d.ts +541 -186
- package/dist/schemas/responses.d.ts.map +1 -1
- package/dist/schemas/responses.js +13 -2
- package/dist/schemas/responses.js.map +1 -1
- package/dist/tools/activity.d.ts +150 -0
- package/dist/tools/activity.d.ts.map +1 -0
- package/dist/tools/activity.js +198 -0
- package/dist/tools/activity.js.map +1 -0
- package/dist/tools/annotations.d.ts +52 -0
- package/dist/tools/annotations.d.ts.map +1 -0
- package/dist/tools/annotations.js +214 -0
- package/dist/tools/annotations.js.map +1 -0
- package/dist/tools/attachments.d.ts +28 -4
- package/dist/tools/attachments.d.ts.map +1 -1
- package/dist/tools/attachments.js +53 -34
- package/dist/tools/attachments.js.map +1 -1
- package/dist/tools/card-ops.d.ts +232 -0
- package/dist/tools/card-ops.d.ts.map +1 -0
- package/dist/tools/card-ops.js +333 -0
- package/dist/tools/card-ops.js.map +1 -0
- package/dist/tools/cards.d.ts +90 -8
- package/dist/tools/cards.d.ts.map +1 -1
- package/dist/tools/cards.js +411 -128
- package/dist/tools/cards.js.map +1 -1
- package/dist/tools/comments.d.ts +226 -22
- package/dist/tools/comments.d.ts.map +1 -1
- package/dist/tools/comments.js +163 -134
- package/dist/tools/comments.js.map +1 -1
- package/dist/tools/dispatch.d.ts +47 -0
- package/dist/tools/dispatch.d.ts.map +1 -0
- package/dist/tools/dispatch.js +63 -0
- package/dist/tools/dispatch.js.map +1 -0
- package/dist/tools/guard.d.ts +9 -0
- package/dist/tools/guard.d.ts.map +1 -0
- package/dist/tools/guard.js +20 -0
- package/dist/tools/guard.js.map +1 -0
- package/dist/tools/index.d.ts +748 -450
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +136 -17
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/labels.d.ts +213 -18
- package/dist/tools/labels.d.ts.map +1 -1
- package/dist/tools/labels.js +218 -203
- package/dist/tools/labels.js.map +1 -1
- package/dist/tools/lists.d.ts +222 -15
- package/dist/tools/lists.d.ts.map +1 -1
- package/dist/tools/lists.js +175 -156
- package/dist/tools/lists.js.map +1 -1
- package/dist/tools/members.d.ts +128 -0
- package/dist/tools/members.d.ts.map +1 -0
- package/dist/tools/members.js +150 -0
- package/dist/tools/members.js.map +1 -0
- package/dist/tools/navigation.d.ts +22 -2
- package/dist/tools/navigation.d.ts.map +1 -1
- package/dist/tools/navigation.js +60 -15
- package/dist/tools/navigation.js.map +1 -1
- package/dist/tools/queries.d.ts +196 -166
- package/dist/tools/queries.d.ts.map +1 -1
- package/dist/tools/queries.js +125 -155
- package/dist/tools/queries.js.map +1 -1
- package/dist/tools/tasks.d.ts +26 -6
- package/dist/tools/tasks.d.ts.map +1 -1
- package/dist/tools/tasks.js +110 -55
- package/dist/tools/tasks.js.map +1 -1
- package/dist/tools/users.d.ts +130 -0
- package/dist/tools/users.d.ts.map +1 -0
- package/dist/tools/users.js +165 -0
- package/dist/tools/users.js.map +1 -0
- package/docs/planka-2x-gotchas.md +121 -5
- package/docs/tools.md +771 -187
- package/docs/troubleshooting.md +137 -5
- package/hooks/hooks.json +15 -0
- package/hooks/preflight.mjs +100 -0
- package/package.json +6 -1
- package/scripts/setup.sh +8 -26
- package/scripts/sync-identity.mjs +55 -1
- package/server.json +87 -6
- package/tests/smoke/planka-smoke.mjs +512 -72
- package/workflow/skills/planka-close-card/SKILL.md +18 -5
- package/workflow/skills/planka-orchestrator/SKILL.md +36 -7
|
@@ -87,13 +87,112 @@ card of the previous page:
|
|
|
87
87
|
GET /api/lists/<LIST_ID>/cards?before[id]=<LAST_CARD_ID>&before[listChangedAt]=<LAST_CARD_listChangedAt>
|
|
88
88
|
```
|
|
89
89
|
|
|
90
|
-
This fork follows that cursor until a page comes back short, capped at 20 pages
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
This fork follows that cursor until a page comes back short, capped at 20 pages,
|
|
91
|
+
and the page size is **derived from the first response, never assumed**: an
|
|
92
|
+
instance answering 20 per page would otherwise stop on page one and report a
|
|
93
|
+
third of the column as the whole of it. When pagination stops early, or when the
|
|
94
|
+
last card has no `listChangedAt` and no cursor can be built, the result carries
|
|
95
|
+
`truncated: true` with a note. It says it did not see everything rather than
|
|
96
|
+
pretending it did.
|
|
97
|
+
|
|
98
|
+
`planka_find_cards` with a `listId` avoids the cursor entirely: `GET
|
|
99
|
+
/api/lists/:id` returns **every card of the column in one response**, so the
|
|
100
|
+
answer is `truncated: false` by construction and `total` is the real size of the
|
|
101
|
+
column. Verified on Planka 2.2.1 against a column of 159 cards — one request
|
|
102
|
+
where the cursor needed four.
|
|
94
103
|
|
|
95
104
|
Why it matters: an incomplete list looks exactly like a complete one.
|
|
96
105
|
|
|
106
|
+
## 6. The `item` a write returns is not the state of the entity
|
|
107
|
+
|
|
108
|
+
**Planka 2.x behavior:** a write answers `200` with the item it *thinks* it
|
|
109
|
+
wrote, and that echo can disagree with the database.
|
|
110
|
+
|
|
111
|
+
Measured against Planka 2.2.1:
|
|
112
|
+
|
|
113
|
+
| Write | What it answers | What is true afterwards |
|
|
114
|
+
|---|---|---|
|
|
115
|
+
| `PATCH /api/cards/:id {isSubscribed:true}` | `200`, `item.isSubscribed: **null**` | re-reading the card says `true` |
|
|
116
|
+
| `POST /api/lists/:id/cards` | `200` with `{item}` and **no `included`** | the card exists, but its tasks/labels are not in the answer |
|
|
117
|
+
| `DELETE /api/cards/:id` | `200` with `{item}` of the deleted card | a later `GET` answers `404` JSON — that 404 is the proof |
|
|
118
|
+
| `PATCH` with an empty body | `200` with the untouched item | nothing changed |
|
|
119
|
+
|
|
120
|
+
So a `success: true` built out of the write's own response proves only that the
|
|
121
|
+
request was accepted. The empty PATCH is the sharpest case: the tool reported a
|
|
122
|
+
change that never happened.
|
|
123
|
+
|
|
124
|
+
This fork writes and then **re-reads**, and reports `verified: true|false`
|
|
125
|
+
(`src/operations/verify.ts`). The DELETE body is kept rather than discarded,
|
|
126
|
+
because the deleted item carries the parent id (`cardId`, `boardId`) the
|
|
127
|
+
confirmation read needs. Deletes are confirmed either by a 404 on the entity or
|
|
128
|
+
by its absence from the parent.
|
|
129
|
+
|
|
130
|
+
Corollary for tasks: there is no `GET /api/tasks/:id` in 2.x, so a task can only
|
|
131
|
+
be verified through its card — which is why `planka_update_task` and
|
|
132
|
+
`planka_delete_task` take an optional `cardId` and say
|
|
133
|
+
`verificationUnavailable` when it is missing, instead of claiming success.
|
|
134
|
+
|
|
135
|
+
## 7. Deleting a list deletes its cards
|
|
136
|
+
|
|
137
|
+
**Planka 2.x behavior:** `DELETE /api/lists/:id` removes the column **and every
|
|
138
|
+
card in it**, with no warning and no undo.
|
|
139
|
+
|
|
140
|
+
The tool description and the docs now say so out loud, and `planka_delete_list`
|
|
141
|
+
confirms the deletion by re-reading the board. There is no server-side guard:
|
|
142
|
+
move the cards out first.
|
|
143
|
+
|
|
144
|
+
## 8. Comments come 50 at a time, and only `beforeId` walks them
|
|
145
|
+
|
|
146
|
+
Measured against Planka 2.2.1 on 2026-09-03:
|
|
147
|
+
|
|
148
|
+
```text
|
|
149
|
+
GET /api/cards/:cardId/comments -> 50 items, newest first (id DESC)
|
|
150
|
+
GET /api/cards/:cardId/comments?beforeId=X -> the 50 older than X
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`?limit=` and `?page=` are **ignored** — the page size is fixed at 50 in the
|
|
154
|
+
server. A card with 120 comments therefore answers 50 and looks complete. Any
|
|
155
|
+
"comment count" derived from one response is the size of that page, never the
|
|
156
|
+
card's total.
|
|
157
|
+
|
|
158
|
+
What planka-mcp does:
|
|
159
|
+
|
|
160
|
+
- `planka_get_comments` returns `limit` comments (default 20) plus `hasMore` and
|
|
161
|
+
`nextBeforeId`, and `all: true` walks the pages up to a ceiling of 10, after
|
|
162
|
+
which it says `truncated: true`. Its `commentCount` is documented as what the
|
|
163
|
+
response carries.
|
|
164
|
+
- the card's **real** total is `commentsTotal` on the card row itself, which is
|
|
165
|
+
what `planka_get_card` reports.
|
|
166
|
+
|
|
167
|
+
The same `?beforeId=` cursor and the same 50-item page apply to
|
|
168
|
+
`GET /api/cards/:id/actions` and `GET /api/boards/:id/actions`.
|
|
169
|
+
|
|
170
|
+
## 9. `GET /api/cards/:id` names nothing
|
|
171
|
+
|
|
172
|
+
The card response's `included` carries `cardMemberships`, `cardLabels`,
|
|
173
|
+
`taskLists`, `tasks`, `customFieldGroups`, `customFields`, `customFieldValues`,
|
|
174
|
+
`users` and `attachments`. It does **not** carry `comments`, and it does **not**
|
|
175
|
+
carry `labels` or `lists`.
|
|
176
|
+
|
|
177
|
+
So a card read on its own gives `listId` and a set of `labelId`s and no way to
|
|
178
|
+
say which column it is in or what its labels are called. The names live only in
|
|
179
|
+
the board payload (`GET /api/boards/:boardId`). `planka_get_card` resolves them
|
|
180
|
+
with one board read cached for a minute, and treats a failure there as "no
|
|
181
|
+
names", never as a failed read.
|
|
182
|
+
|
|
183
|
+
## 10. Planka answers 404 where it means 403
|
|
184
|
+
|
|
185
|
+
A 404 from Planka means one of three things, and the body does not distinguish
|
|
186
|
+
them:
|
|
187
|
+
|
|
188
|
+
1. the entity really does not exist;
|
|
189
|
+
2. the ID is of the wrong kind (all IDs are strings of digits: a `labelId`
|
|
190
|
+
passed as a `listId` produces exactly this);
|
|
191
|
+
3. **the agent user has no permission on it** — a 403 wearing a 404's clothes.
|
|
192
|
+
|
|
193
|
+
Every 404 this server raises now names the kind of ID the path expected, keeps
|
|
194
|
+
Planka's own message, and states the permission possibility.
|
|
195
|
+
|
|
97
196
|
## Related Planka 2.x traps
|
|
98
197
|
|
|
99
198
|
### Board-level card and label endpoints do not exist
|
|
@@ -124,11 +223,28 @@ accepts:
|
|
|
124
223
|
Both are per list, not per board. Since enumerating a board's columns, or
|
|
125
224
|
resolving a label name to its ID, needs a `GET /api/boards/:boardId` anyway, and
|
|
126
225
|
that single call already carries every card with its description and label
|
|
127
|
-
links,
|
|
226
|
+
links, planka-mcp filters board-level searches locally over that one request.
|
|
128
227
|
Issuing one search per list would be N extra round-trips for data already in
|
|
129
228
|
hand. What stays small in `planka_find_cards` and `planka_board_summary` is the
|
|
130
229
|
**output**, which is what a model pays for.
|
|
131
230
|
|
|
231
|
+
### The board read has no archive and no trash
|
|
232
|
+
|
|
233
|
+
`GET /api/boards/:id` carries every card of the FINITE lists — the ones typed
|
|
234
|
+
`active` or `closed`. The `archive` and `trash` lists come back with
|
|
235
|
+
`name: null`, `position: null` and **without a single card**. There is no
|
|
236
|
+
parameter to include them, and no `GET /api/boards/:id/cards` to ask again.
|
|
237
|
+
|
|
238
|
+
So every read built on the board show — `planka_board_summary`,
|
|
239
|
+
`planka_find_cards` without a `listId`, `planka_get_board`, `planka_list_lists` —
|
|
240
|
+
describes the **visible** board, not everything Planka stores. A card someone
|
|
241
|
+
archived is not "gone": it is outside what these tools can see. They all say so
|
|
242
|
+
with `excludesArchived: true` rather than letting a zero pass for a fact.
|
|
243
|
+
|
|
244
|
+
Verified on Planka 2.2.1: a board whose show reports 185 cards across 8 named
|
|
245
|
+
columns also carries two nameless lists (`archive`, `trash`) with no cards
|
|
246
|
+
attached to them anywhere in the payload.
|
|
247
|
+
|
|
132
248
|
### A projectId where a boardId goes returns a bare 404
|
|
133
249
|
|
|
134
250
|
Project IDs and board IDs are both strings of digits. Nothing in either one says
|