@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.
Files changed (195) hide show
  1. package/.agents/plugins/marketplace.json +20 -0
  2. package/.claude-plugin/marketplace.json +26 -0
  3. package/.claude-plugin/plugin.json +45 -0
  4. package/.codex-plugin/mcp.json +16 -0
  5. package/.codex-plugin/plugin.json +27 -0
  6. package/.mcp.json +17 -0
  7. package/CHANGELOG.md +510 -0
  8. package/README.es.md +294 -55
  9. package/README.md +293 -55
  10. package/dist/cli/init.d.ts +101 -0
  11. package/dist/cli/init.d.ts.map +1 -0
  12. package/dist/cli/init.js +481 -0
  13. package/dist/cli/init.js.map +1 -0
  14. package/dist/client.d.ts +32 -4
  15. package/dist/client.d.ts.map +1 -1
  16. package/dist/client.js +106 -32
  17. package/dist/client.js.map +1 -1
  18. package/dist/config/policy.d.ts +82 -0
  19. package/dist/config/policy.d.ts.map +1 -0
  20. package/dist/config/policy.js +226 -0
  21. package/dist/config/policy.js.map +1 -0
  22. package/dist/errors.d.ts +5 -1
  23. package/dist/errors.d.ts.map +1 -1
  24. package/dist/errors.js +62 -5
  25. package/dist/errors.js.map +1 -1
  26. package/dist/identity.generated.d.ts +2 -1
  27. package/dist/identity.generated.d.ts.map +1 -1
  28. package/dist/identity.generated.js +2 -1
  29. package/dist/identity.generated.js.map +1 -1
  30. package/dist/index.js +85 -10
  31. package/dist/index.js.map +1 -1
  32. package/dist/instructions.d.ts +21 -0
  33. package/dist/instructions.d.ts.map +1 -0
  34. package/dist/instructions.js +37 -0
  35. package/dist/instructions.js.map +1 -0
  36. package/dist/operations/actions.d.ts +654 -0
  37. package/dist/operations/actions.d.ts.map +1 -0
  38. package/dist/operations/actions.js +154 -0
  39. package/dist/operations/actions.js.map +1 -0
  40. package/dist/operations/archive.d.ts +28 -0
  41. package/dist/operations/archive.d.ts.map +1 -0
  42. package/dist/operations/archive.js +74 -0
  43. package/dist/operations/archive.js.map +1 -0
  44. package/dist/operations/attachments.d.ts +1 -1
  45. package/dist/operations/attachments.d.ts.map +1 -1
  46. package/dist/operations/attachments.js +3 -1
  47. package/dist/operations/attachments.js.map +1 -1
  48. package/dist/operations/board-id.d.ts +1 -1
  49. package/dist/operations/board-id.d.ts.map +1 -1
  50. package/dist/operations/board-id.js +13 -7
  51. package/dist/operations/board-id.js.map +1 -1
  52. package/dist/operations/boards.d.ts +96 -19
  53. package/dist/operations/boards.d.ts.map +1 -1
  54. package/dist/operations/boards.js +377 -93
  55. package/dist/operations/boards.js.map +1 -1
  56. package/dist/operations/card-brief.d.ts +91 -0
  57. package/dist/operations/card-brief.d.ts.map +1 -0
  58. package/dist/operations/card-brief.js +79 -0
  59. package/dist/operations/card-brief.js.map +1 -0
  60. package/dist/operations/cards.d.ts +34 -9
  61. package/dist/operations/cards.d.ts.map +1 -1
  62. package/dist/operations/cards.js +60 -14
  63. package/dist/operations/cards.js.map +1 -1
  64. package/dist/operations/comments.d.ts +61 -4
  65. package/dist/operations/comments.d.ts.map +1 -1
  66. package/dist/operations/comments.js +91 -8
  67. package/dist/operations/comments.js.map +1 -1
  68. package/dist/operations/duplicate.d.ts +16 -0
  69. package/dist/operations/duplicate.d.ts.map +1 -0
  70. package/dist/operations/duplicate.js +43 -0
  71. package/dist/operations/duplicate.js.map +1 -0
  72. package/dist/operations/labels.d.ts +1 -1
  73. package/dist/operations/labels.d.ts.map +1 -1
  74. package/dist/operations/labels.js +7 -4
  75. package/dist/operations/labels.js.map +1 -1
  76. package/dist/operations/lists.d.ts +63 -1
  77. package/dist/operations/lists.d.ts.map +1 -1
  78. package/dist/operations/lists.js +97 -2
  79. package/dist/operations/lists.js.map +1 -1
  80. package/dist/operations/members.d.ts +39 -0
  81. package/dist/operations/members.d.ts.map +1 -0
  82. package/dist/operations/members.js +107 -0
  83. package/dist/operations/members.js.map +1 -0
  84. package/dist/operations/projects.d.ts +16 -0
  85. package/dist/operations/projects.d.ts.map +1 -1
  86. package/dist/operations/projects.js +54 -9
  87. package/dist/operations/projects.js.map +1 -1
  88. package/dist/operations/tasks.d.ts +1 -1
  89. package/dist/operations/tasks.d.ts.map +1 -1
  90. package/dist/operations/tasks.js +5 -3
  91. package/dist/operations/tasks.js.map +1 -1
  92. package/dist/operations/users.d.ts +123 -0
  93. package/dist/operations/users.d.ts.map +1 -0
  94. package/dist/operations/users.js +180 -0
  95. package/dist/operations/users.js.map +1 -0
  96. package/dist/operations/verify.d.ts +84 -0
  97. package/dist/operations/verify.d.ts.map +1 -0
  98. package/dist/operations/verify.js +124 -0
  99. package/dist/operations/verify.js.map +1 -0
  100. package/dist/prompts.d.ts +48 -0
  101. package/dist/prompts.d.ts.map +1 -0
  102. package/dist/prompts.js +155 -0
  103. package/dist/prompts.js.map +1 -0
  104. package/dist/resources.d.ts +38 -0
  105. package/dist/resources.d.ts.map +1 -0
  106. package/dist/resources.js +127 -0
  107. package/dist/resources.js.map +1 -0
  108. package/dist/schemas/entities.d.ts +115 -24
  109. package/dist/schemas/entities.d.ts.map +1 -1
  110. package/dist/schemas/entities.js +48 -0
  111. package/dist/schemas/entities.js.map +1 -1
  112. package/dist/schemas/requests.d.ts +121 -46
  113. package/dist/schemas/requests.d.ts.map +1 -1
  114. package/dist/schemas/requests.js +57 -12
  115. package/dist/schemas/requests.js.map +1 -1
  116. package/dist/schemas/responses.d.ts +541 -186
  117. package/dist/schemas/responses.d.ts.map +1 -1
  118. package/dist/schemas/responses.js +13 -2
  119. package/dist/schemas/responses.js.map +1 -1
  120. package/dist/tools/activity.d.ts +150 -0
  121. package/dist/tools/activity.d.ts.map +1 -0
  122. package/dist/tools/activity.js +198 -0
  123. package/dist/tools/activity.js.map +1 -0
  124. package/dist/tools/annotations.d.ts +52 -0
  125. package/dist/tools/annotations.d.ts.map +1 -0
  126. package/dist/tools/annotations.js +214 -0
  127. package/dist/tools/annotations.js.map +1 -0
  128. package/dist/tools/attachments.d.ts +28 -4
  129. package/dist/tools/attachments.d.ts.map +1 -1
  130. package/dist/tools/attachments.js +53 -34
  131. package/dist/tools/attachments.js.map +1 -1
  132. package/dist/tools/card-ops.d.ts +232 -0
  133. package/dist/tools/card-ops.d.ts.map +1 -0
  134. package/dist/tools/card-ops.js +333 -0
  135. package/dist/tools/card-ops.js.map +1 -0
  136. package/dist/tools/cards.d.ts +90 -8
  137. package/dist/tools/cards.d.ts.map +1 -1
  138. package/dist/tools/cards.js +411 -128
  139. package/dist/tools/cards.js.map +1 -1
  140. package/dist/tools/comments.d.ts +226 -22
  141. package/dist/tools/comments.d.ts.map +1 -1
  142. package/dist/tools/comments.js +163 -134
  143. package/dist/tools/comments.js.map +1 -1
  144. package/dist/tools/dispatch.d.ts +47 -0
  145. package/dist/tools/dispatch.d.ts.map +1 -0
  146. package/dist/tools/dispatch.js +63 -0
  147. package/dist/tools/dispatch.js.map +1 -0
  148. package/dist/tools/guard.d.ts +9 -0
  149. package/dist/tools/guard.d.ts.map +1 -0
  150. package/dist/tools/guard.js +20 -0
  151. package/dist/tools/guard.js.map +1 -0
  152. package/dist/tools/index.d.ts +748 -450
  153. package/dist/tools/index.d.ts.map +1 -1
  154. package/dist/tools/index.js +136 -17
  155. package/dist/tools/index.js.map +1 -1
  156. package/dist/tools/labels.d.ts +213 -18
  157. package/dist/tools/labels.d.ts.map +1 -1
  158. package/dist/tools/labels.js +218 -203
  159. package/dist/tools/labels.js.map +1 -1
  160. package/dist/tools/lists.d.ts +222 -15
  161. package/dist/tools/lists.d.ts.map +1 -1
  162. package/dist/tools/lists.js +175 -156
  163. package/dist/tools/lists.js.map +1 -1
  164. package/dist/tools/members.d.ts +128 -0
  165. package/dist/tools/members.d.ts.map +1 -0
  166. package/dist/tools/members.js +150 -0
  167. package/dist/tools/members.js.map +1 -0
  168. package/dist/tools/navigation.d.ts +22 -2
  169. package/dist/tools/navigation.d.ts.map +1 -1
  170. package/dist/tools/navigation.js +60 -15
  171. package/dist/tools/navigation.js.map +1 -1
  172. package/dist/tools/queries.d.ts +196 -166
  173. package/dist/tools/queries.d.ts.map +1 -1
  174. package/dist/tools/queries.js +125 -155
  175. package/dist/tools/queries.js.map +1 -1
  176. package/dist/tools/tasks.d.ts +26 -6
  177. package/dist/tools/tasks.d.ts.map +1 -1
  178. package/dist/tools/tasks.js +110 -55
  179. package/dist/tools/tasks.js.map +1 -1
  180. package/dist/tools/users.d.ts +130 -0
  181. package/dist/tools/users.d.ts.map +1 -0
  182. package/dist/tools/users.js +165 -0
  183. package/dist/tools/users.js.map +1 -0
  184. package/docs/planka-2x-gotchas.md +121 -5
  185. package/docs/tools.md +771 -187
  186. package/docs/troubleshooting.md +137 -5
  187. package/hooks/hooks.json +15 -0
  188. package/hooks/preflight.mjs +100 -0
  189. package/package.json +6 -1
  190. package/scripts/setup.sh +8 -26
  191. package/scripts/sync-identity.mjs +55 -1
  192. package/server.json +87 -6
  193. package/tests/smoke/planka-smoke.mjs +512 -72
  194. package/workflow/skills/planka-close-card/SKILL.md +18 -5
  195. 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
- When it stops early, or when the last card has no `listChangedAt` and no cursor
92
- can be built, `planka_list_cards` returns `truncated: true` with a note. It says
93
- it did not see everything rather than pretending it did.
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, this fork filters board-level searches locally over that one request.
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