@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
@@ -30,24 +30,107 @@ export async function updateComment(input) {
30
30
  */
31
31
  export async function deleteComment(input) {
32
32
  const { commentId } = parseInput(CommentIdSchema, input);
33
- await plankaClient.delete(`/api/comments/${commentId}`);
33
+ const body = await plankaClient.delete(`/api/comments/${commentId}`);
34
+ const parsed = CommentResponse.safeParse(body);
35
+ return parsed.success ? parsed.data.item : null;
34
36
  }
35
37
  /**
36
- * Get all comments for a card, newest first.
37
- * PLANKA 2.x serves comments only from the dedicated endpoint — the card
38
- * response's `included` never carries them.
38
+ * Planka 2.x serves comments 50 at a time and IGNORES ?limit / ?page. The only
39
+ * cursor is `?beforeId=<id>`, and the order is id DESC (newest first).
40
+ * Measured against the live instance — see docs/planka-2x-gotchas.md.
39
41
  */
40
- export async function getCommentsForCard(input) {
41
- const { cardId } = parseInput(CardIdSchema, input);
42
- const response = await plankaClient.get(`/api/cards/${cardId}/comments`);
42
+ export const COMMENTS_PAGE_SIZE = 50;
43
+ /** Ceiling for `all: true`: 10 pages = 500 comments, then `truncated`. */
44
+ export const COMMENTS_MAX_PAGES = 10;
45
+ /**
46
+ * One page of a card's comments (max 50), newest first.
47
+ * `beforeId` walks backwards in time: it returns comments OLDER than that id.
48
+ */
49
+ export async function getCommentsPage(input) {
50
+ const { cardId } = parseInput(CardIdSchema, { cardId: input.cardId });
51
+ const query = input.beforeId
52
+ ? `?beforeId=${encodeURIComponent(input.beforeId)}`
53
+ : "";
54
+ const response = await plankaClient.get(`/api/cards/${cardId}/comments${query}`);
43
55
  const parsed = CommentsResponse.parse(response);
44
56
  const included = CommentsIncludedSchema.parse(response.included || {});
45
57
  const users = included.users || [];
46
- return parsed.items
58
+ const comments = parsed.items
47
59
  .map((c) => ({
48
60
  ...c,
49
61
  authorName: users.find((u) => u.id === c.userId)?.name,
50
62
  }))
51
63
  .sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
64
+ return {
65
+ comments,
66
+ full: parsed.items.length >= COMMENTS_PAGE_SIZE,
67
+ nextBeforeId: comments[comments.length - 1]?.id,
68
+ };
69
+ }
70
+ /**
71
+ * The FIRST page of a card's comments, newest first (max 50).
72
+ *
73
+ * Kept as the cheap read used by write verification: a comment that was just
74
+ * created or edited is on page 1 by definition. Anything that has to be
75
+ * complete — or honest about not being — goes through `getComments`.
76
+ */
77
+ export async function getCommentsForCard(input) {
78
+ const { cardId } = parseInput(CardIdSchema, input);
79
+ const page = await getCommentsPage({ cardId });
80
+ return page.comments;
81
+ }
82
+ /**
83
+ * Read a card's comments with honest paging.
84
+ *
85
+ * - `limit` how many to return (1..50 per server page; default up to the caller)
86
+ * - `beforeId` cursor from a previous call — returns comments OLDER than it
87
+ * - `all` walk every page up to COMMENTS_MAX_PAGES, then say `truncated`
88
+ * - `order` "asc" (oldest first, the reading order) or "desc" (newest first)
89
+ *
90
+ * `hasMore` is never guessed: it is true only when Planka handed back a full
91
+ * page, or when a page carried more comments than the caller asked for.
92
+ */
93
+ export async function getComments(input) {
94
+ const order = input.order ?? "asc";
95
+ if (input.all) {
96
+ const maxPages = Math.max(1, input.maxPages ?? COMMENTS_MAX_PAGES);
97
+ const collected = [];
98
+ let beforeId = input.beforeId;
99
+ let pagesFetched = 0;
100
+ let full = false;
101
+ while (pagesFetched < maxPages) {
102
+ const page = await getCommentsPage({ cardId: input.cardId, beforeId });
103
+ pagesFetched += 1;
104
+ collected.push(...page.comments);
105
+ full = page.full;
106
+ beforeId = page.nextBeforeId;
107
+ if (!page.full || !beforeId)
108
+ break;
109
+ }
110
+ // Ran out of pages while Planka still had more to give.
111
+ const truncated = full && pagesFetched >= maxPages;
112
+ return {
113
+ comments: order === "asc" ? [...collected].reverse() : collected,
114
+ hasMore: truncated,
115
+ ...(truncated && beforeId ? { nextBeforeId: beforeId } : {}),
116
+ truncated,
117
+ pagesFetched,
118
+ };
119
+ }
120
+ const page = await getCommentsPage({
121
+ cardId: input.cardId,
122
+ beforeId: input.beforeId,
123
+ });
124
+ const limit = Math.max(1, Math.min(input.limit ?? COMMENTS_PAGE_SIZE, COMMENTS_PAGE_SIZE));
125
+ const slice = page.comments.slice(0, limit);
126
+ const hasMore = page.comments.length > slice.length || page.full;
127
+ const nextBeforeId = slice[slice.length - 1]?.id;
128
+ return {
129
+ comments: order === "asc" ? [...slice].reverse() : slice,
130
+ hasMore,
131
+ ...(hasMore && nextBeforeId ? { nextBeforeId } : {}),
132
+ truncated: false,
133
+ pagesFetched: 1,
134
+ };
52
135
  }
53
136
  //# sourceMappingURL=comments.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"comments.js","sourceRoot":"","sources":["../../src/operations/comments.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,OAAO,EACL,YAAY,EAEZ,eAAe,EAEf,mBAAmB,EAEnB,yBAAyB,GAE1B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAUpG;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAAyB;IAC3D,MAAM,SAAS,GAAG,UAAU,CAAC,mBAAmB,EAAE,KAAK,CAAC,CAAC;IAEzD,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,IAAI,CACtC,cAAc,SAAS,CAAC,MAAM,WAAW,EACzC;QACE,IAAI,EAAE,SAAS,CAAC,IAAI;KACrB,CACF,CAAC;IAEF,MAAM,MAAM,GAAG,eAAe,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC/C,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,KAA+B;IAE/B,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,EAAE,GAAG,UAAU,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;IAE/E,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,KAAK,CACvC,iBAAiB,SAAS,EAAE,EAC5B,OAAO,CACR,CAAC;IAEF,MAAM,MAAM,GAAG,eAAe,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC/C,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAAqB;IACvD,MAAM,EAAE,SAAS,EAAE,GAAG,UAAU,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC;IACzD,MAAM,YAAY,CAAC,MAAM,CAAC,iBAAiB,SAAS,EAAE,CAAC,CAAC;AAC1D,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,KAAkB;IAElB,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;IACnD,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,GAAG,CACrC,cAAc,MAAM,WAAW,CAChC,CAAC;IACF,MAAM,MAAM,GAAG,gBAAgB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,sBAAsB,CAAC,KAAK,CAC1C,QAAoC,CAAC,QAAQ,IAAI,EAAE,CACrD,CAAC;IACF,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC;IAEnC,OAAO,MAAM,CAAC,KAAK;SAChB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACX,GAAG,CAAC;QACJ,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI;KACvD,CAAC,CAAC;SACF,IAAI,CACH,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAC5E,CAAC;AACN,CAAC"}
1
+ {"version":3,"file":"comments.js","sourceRoot":"","sources":["../../src/operations/comments.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Duplicate a card. `position` defaults to Planka's usual end-of-column value.
3
+ */
4
+ export declare function duplicateCard(input: {
5
+ cardId: string;
6
+ listId?: string;
7
+ boardId?: string;
8
+ name?: string;
9
+ position?: number;
10
+ }): Promise<{
11
+ id: string;
12
+ name: string;
13
+ listId: string;
14
+ boardId: string;
15
+ }>;
16
+ //# sourceMappingURL=duplicate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duplicate.d.ts","sourceRoot":"","sources":["../../src/operations/duplicate.ts"],"names":[],"mappings":"AAqBA;;GAEG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAqBzE"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Card duplication.
3
+ *
4
+ * `POST /api/cards/:id/duplicate` is a real Planka 2.x endpoint and it copies
5
+ * more than the card row: verified live on 2.2.1, the response's `included`
6
+ * came back with the card's memberships, labels, task lists, tasks and custom
7
+ * field values. Attachments are NOT re-uploaded. The copy lands in the SAME
8
+ * list unless `listId` (and optionally `boardId`) say otherwise, and Planka
9
+ * appends its own suffix to the name unless `name` is given.
10
+ *
11
+ * The counts reported to the caller come from re-reading the new card, not
12
+ * from this response: the point of the tool is to say what the copy actually
13
+ * carries.
14
+ */
15
+ import { z } from "zod";
16
+ import { plankaClient } from "../client.js";
17
+ import { assertBoardAllowed, assertListWritable } from "../config/policy.js";
18
+ import { CardBriefSchema } from "./card-brief.js";
19
+ const DuplicateResponse = z.object({ item: CardBriefSchema });
20
+ /**
21
+ * Duplicate a card. `position` defaults to Planka's usual end-of-column value.
22
+ */
23
+ export async function duplicateCard(input) {
24
+ assertListWritable(input.listId, undefined, "duplicate cards into");
25
+ if (input.boardId)
26
+ assertBoardAllowed(input.boardId);
27
+ const body = { position: input.position ?? 65536 };
28
+ if (input.listId)
29
+ body.listId = input.listId;
30
+ if (input.boardId)
31
+ body.boardId = input.boardId;
32
+ if (input.name !== undefined)
33
+ body.name = input.name;
34
+ const response = await plankaClient.post(`/api/cards/${input.cardId}/duplicate`, body);
35
+ const item = DuplicateResponse.parse(response).item;
36
+ return {
37
+ id: item.id,
38
+ name: item.name,
39
+ listId: item.listId,
40
+ boardId: item.boardId,
41
+ };
42
+ }
43
+ //# sourceMappingURL=duplicate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duplicate.js","sourceRoot":"","sources":["../../src/operations/duplicate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElD,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,CAAC;AAE9D;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAMnC;IACC,kBAAkB,CAAC,KAAK,CAAC,MAAM,EAAE,SAAS,EAAE,sBAAsB,CAAC,CAAC;IACpE,IAAI,KAAK,CAAC,OAAO;QAAE,kBAAkB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAErD,MAAM,IAAI,GAA4B,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,KAAK,EAAE,CAAC;IAC5E,IAAI,KAAK,CAAC,MAAM;QAAE,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IAC7C,IAAI,KAAK,CAAC,OAAO;QAAE,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAChD,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS;QAAE,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;IAErD,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,IAAI,CACtC,cAAc,KAAK,CAAC,MAAM,YAAY,EACtC,IAAI,CACL,CAAC;IACF,MAAM,IAAI,GAAG,iBAAiB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC;IAEpD,OAAO;QACL,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,OAAO,EAAE,IAAI,CAAC,OAAO;KACtB,CAAC;AACJ,CAAC"}
@@ -11,7 +11,7 @@ export declare function updateLabel(input: UpdateLabelParamsInput): Promise<Labe
11
11
  /**
12
12
  * Delete a label.
13
13
  */
14
- export declare function deleteLabel(input: LabelIdInput): Promise<void>;
14
+ export declare function deleteLabel(input: LabelIdInput): Promise<Label | null>;
15
15
  /**
16
16
  * Add a label to a card.
17
17
  * Uses PLANKA 2.0 /card-labels endpoint.
@@ -1 +1 @@
1
- {"version":3,"file":"labels.d.ts","sourceRoot":"","sources":["../../src/operations/labels.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAEL,mBAAmB,EAEnB,gBAAgB,EAEhB,YAAY,EAEZ,wBAAwB,EAExB,kBAAkB,EAElB,sBAAsB,EACvB,MAAM,wBAAwB,CAAC;AAIhC;;GAEG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,KAAK,CAAC,CAgBzE;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,sBAAsB,GAC5B,OAAO,CAAC,KAAK,CAAC,CAUhB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAGpE;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,SAAS,CAAC,CAYnF;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,wBAAwB,GAC9B,OAAO,CAAC,IAAI,CAAC,CAKf;AAED;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,wCAAwC;IACxC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,gDAAgD;IAChD,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,0CAA0C;IAC1C,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,4DAA4D;IAC5D,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,4EAA4E;IAC5E,MAAM,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD,2DAA2D;IAC3D,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC,mBAAmB,CAAC,CAwF9B"}
1
+ {"version":3,"file":"labels.d.ts","sourceRoot":"","sources":["../../src/operations/labels.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAEL,mBAAmB,EAEnB,gBAAgB,EAEhB,YAAY,EAEZ,wBAAwB,EAExB,kBAAkB,EAElB,sBAAsB,EACvB,MAAM,wBAAwB,CAAC;AAIhC;;GAEG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,KAAK,CAAC,CAgBzE;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,sBAAsB,GAC5B,OAAO,CAAC,KAAK,CAAC,CAUhB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CAK5E;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,SAAS,CAAC,CAYnF;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,wBAAwB,GAC9B,OAAO,CAAC,IAAI,CAAC,CAKf;AAED;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,wCAAwC;IACxC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,gDAAgD;IAChD,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,0CAA0C;IAC1C,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,4DAA4D;IAC5D,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,4EAA4E;IAC5E,MAAM,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD,2DAA2D;IAC3D,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC,mBAAmB,CAAC,CAyF9B"}
@@ -6,7 +6,7 @@ import { withBoardId } from "./board-id.js";
6
6
  import { parseInput } from "../errors.js";
7
7
  import { AddLabelToCardSchema, CreateLabelSchema, LabelIdSchema, RemoveLabelFromCardSchema, SetCardLabelsSchema, UpdateLabelParamsSchema, } from "../schemas/requests.js";
8
8
  import { LabelResponse, CardLabelResponse } from "../schemas/responses.js";
9
- import { getCard } from "./cards.js";
9
+ import { getCardLight } from "./cards.js";
10
10
  /**
11
11
  * Create a new label on a board.
12
12
  */
@@ -36,7 +36,9 @@ export async function updateLabel(input) {
36
36
  */
37
37
  export async function deleteLabel(input) {
38
38
  const { labelId } = parseInput(LabelIdSchema, input);
39
- await plankaClient.delete(`/api/labels/${labelId}`);
39
+ const body = await plankaClient.delete(`/api/labels/${labelId}`);
40
+ const parsed = LabelResponse.safeParse(body);
41
+ return parsed.success ? parsed.data.item : null;
40
42
  }
41
43
  /**
42
44
  * Add a label to a card.
@@ -72,7 +74,8 @@ export async function setCardLabels(input) {
72
74
  const { cardId, addLabelIds, removeLabelIds } = parseInput(SetCardLabelsSchema, input);
73
75
  const toAdd = addLabelIds ?? [];
74
76
  const toRemove = removeLabelIds ?? [];
75
- const before = await getCard({ cardId });
77
+ // Light read: comparing label ids never needed the card's comments.
78
+ const before = await getCardLight({ cardId });
76
79
  const presentBefore = new Set(before.cardLabels.map((cl) => cl.labelId));
77
80
  const result = {
78
81
  added: [],
@@ -117,7 +120,7 @@ export async function setCardLabels(input) {
117
120
  }
118
121
  }
119
122
  // Verify against the card itself: this is what makes the report trustworthy.
120
- const after = await getCard({ cardId });
123
+ const after = await getCardLight({ cardId });
121
124
  const presentAfter = new Set(after.cardLabels.map((cl) => cl.labelId));
122
125
  result.finalLabelIds = [...presentAfter];
123
126
  result.added = toAdd.filter((id) => presentAfter.has(id) && !presentBefore.has(id));
@@ -1 +1 @@
1
- {"version":3,"file":"labels.js","sourceRoot":"","sources":["../../src/operations/labels.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"labels.js","sourceRoot":"","sources":["../../src/operations/labels.ts"],"names":[],"mappings":"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"}
@@ -11,5 +11,67 @@ export declare function updateList(input: UpdateListParamsInput): Promise<List>;
11
11
  /**
12
12
  * Delete a list.
13
13
  */
14
- export declare function deleteList(input: ListIdInput): Promise<void>;
14
+ export declare function deleteList(input: ListIdInput): Promise<List | null>;
15
+ /** What a column holds right now, and what kind of column it is. */
16
+ export interface ListState {
17
+ id: string;
18
+ /** "active" | "closed" | "archive" | "trash", when Planka will say. */
19
+ type: string | null;
20
+ boardId: string | null;
21
+ cardIds: string[];
22
+ /** Card id -> its position, so a per-card move can preserve the order. */
23
+ positions: Map<string, number | null>;
24
+ count: number;
25
+ }
26
+ /**
27
+ * Reads a column: its type, its board and every card in it.
28
+ *
29
+ * `GET /api/lists/:id` returns the WHOLE column in `included.cards` — no 50-item
30
+ * page, unlike `GET /api/lists/:id/cards` — which is what makes it usable both
31
+ * as a counter and as the source of a per-card move.
32
+ *
33
+ * Returns `null` for a column Planka refuses to show: the hidden `archive` and
34
+ * `trash` lists answer 404 here. That is not an error, it is information.
35
+ */
36
+ export declare function readListState(listId: string): Promise<ListState | null>;
37
+ /** How many cards a column holds. `null` when the column cannot be read. */
38
+ export declare function countListCards(listId: string): Promise<number | null>;
39
+ /**
40
+ * Planka's own bulk move — and the ONLY thing it can do.
41
+ *
42
+ * `POST /api/lists/:id/move-cards` reads like a general "move every card from
43
+ * A to B", and it is not: `server/api/controllers/lists/move-cards.js` in 2.2.1
44
+ * refuses anything but archiving a whole closed column —
45
+ *
46
+ * if (list.type !== List.Types.CLOSED) throw NOT_ENOUGH_RIGHTS; // 403
47
+ * if (nextList.type !== List.Types.ARCHIVE) throw LIST_NOT_FOUND; // 404
48
+ *
49
+ * so an active -> active call comes back 403 "Not enough rights", which reads
50
+ * like a permission problem and is not one. Callers that need the general move
51
+ * fall back to `moveCardsOneByOne`.
52
+ */
53
+ export declare function bulkMoveClosedListToArchive(input: {
54
+ fromListId: string;
55
+ toListId: string;
56
+ }): Promise<void>;
57
+ /**
58
+ * The general move: one PATCH per card.
59
+ *
60
+ * Each card keeps the position it had, so the relative order survives. A card
61
+ * whose position is null (it came out of the archive) gets one, because Planka
62
+ * rejects a move without it.
63
+ *
64
+ * Returns the cards that could not be moved, with the reason — a partial move
65
+ * has to be visible, not silently reported as a smaller success.
66
+ */
67
+ export declare function moveCardsOneByOne(input: {
68
+ cards: Array<{
69
+ id: string;
70
+ position: number | null;
71
+ }>;
72
+ toListId: string;
73
+ }): Promise<Array<{
74
+ cardId: string;
75
+ reason: string;
76
+ }>>;
15
77
  //# sourceMappingURL=lists.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"lists.d.ts","sourceRoot":"","sources":["../../src/operations/lists.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAE9C,OAAO,EAEL,eAAe,EAEf,WAAW,EAEX,qBAAqB,EACtB,MAAM,wBAAwB,CAAC;AAEhC;;GAEG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBtE;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE,qBAAqB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAUf;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAGlE"}
1
+ {"version":3,"file":"lists.d.ts","sourceRoot":"","sources":["../../src/operations/lists.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAE9C,OAAO,EAEL,eAAe,EAEf,WAAW,EAEX,qBAAqB,EACtB,MAAM,wBAAwB,CAAC;AAEhC;;GAEG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBtE;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE,qBAAqB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAWf;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAMzE;AAED,oEAAoE;AACpE,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,uEAAuE;IACvE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,0EAA0E;IAC1E,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;IACtC,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CA2B7E;AAED,4EAA4E;AAC5E,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAG3E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,2BAA2B,CAAC,KAAK,EAAE;IACvD,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC,IAAI,CAAC,CAOhB;AAED;;;;;;;;;GASG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE;IAC7C,KAAK,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;IACtD,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC,KAAK,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CAkBrD"}
@@ -3,7 +3,8 @@
3
3
  */
4
4
  import { plankaClient } from "../client.js";
5
5
  import { withBoardId } from "./board-id.js";
6
- import { parseInput } from "../errors.js";
6
+ import { PlankaError, parseInput } from "../errors.js";
7
+ import { assertListWritable } from "../config/policy.js";
7
8
  import { ListResponse } from "../schemas/responses.js";
8
9
  import { CreateListSchema, ListIdSchema, UpdateListParamsSchema, } from "../schemas/requests.js";
9
10
  /**
@@ -26,6 +27,7 @@ export async function createList(input) {
26
27
  */
27
28
  export async function updateList(input) {
28
29
  const { listId, ...updates } = parseInput(UpdateListParamsSchema, input);
30
+ assertListWritable(listId, undefined, "edit");
29
31
  const response = await plankaClient.patch(`/api/lists/${listId}`, updates);
30
32
  const parsed = ListResponse.parse(response);
31
33
  return parsed.item;
@@ -35,6 +37,99 @@ export async function updateList(input) {
35
37
  */
36
38
  export async function deleteList(input) {
37
39
  const { listId } = parseInput(ListIdSchema, input);
38
- await plankaClient.delete(`/api/lists/${listId}`);
40
+ assertListWritable(listId, undefined, "delete");
41
+ const body = await plankaClient.delete(`/api/lists/${listId}`);
42
+ const parsed = ListResponse.safeParse(body);
43
+ return parsed.success ? parsed.data.item : null;
44
+ }
45
+ /**
46
+ * Reads a column: its type, its board and every card in it.
47
+ *
48
+ * `GET /api/lists/:id` returns the WHOLE column in `included.cards` — no 50-item
49
+ * page, unlike `GET /api/lists/:id/cards` — which is what makes it usable both
50
+ * as a counter and as the source of a per-card move.
51
+ *
52
+ * Returns `null` for a column Planka refuses to show: the hidden `archive` and
53
+ * `trash` lists answer 404 here. That is not an error, it is information.
54
+ */
55
+ export async function readListState(listId) {
56
+ let response;
57
+ try {
58
+ response = await plankaClient.get(`/api/lists/${listId}`);
59
+ }
60
+ catch (error) {
61
+ if (error instanceof PlankaError && error.status === 404)
62
+ return null;
63
+ throw error;
64
+ }
65
+ const cards = response?.included?.cards ?? [];
66
+ const positions = new Map();
67
+ for (const card of cards) {
68
+ if (card?.id)
69
+ positions.set(card.id, card.position ?? null);
70
+ }
71
+ return {
72
+ id: listId,
73
+ type: response?.item?.type ?? null,
74
+ boardId: response?.item?.boardId ?? null,
75
+ cardIds: [...positions.keys()],
76
+ positions,
77
+ count: positions.size,
78
+ };
79
+ }
80
+ /** How many cards a column holds. `null` when the column cannot be read. */
81
+ export async function countListCards(listId) {
82
+ const state = await readListState(listId);
83
+ return state ? state.count : null;
84
+ }
85
+ /**
86
+ * Planka's own bulk move — and the ONLY thing it can do.
87
+ *
88
+ * `POST /api/lists/:id/move-cards` reads like a general "move every card from
89
+ * A to B", and it is not: `server/api/controllers/lists/move-cards.js` in 2.2.1
90
+ * refuses anything but archiving a whole closed column —
91
+ *
92
+ * if (list.type !== List.Types.CLOSED) throw NOT_ENOUGH_RIGHTS; // 403
93
+ * if (nextList.type !== List.Types.ARCHIVE) throw LIST_NOT_FOUND; // 404
94
+ *
95
+ * so an active -> active call comes back 403 "Not enough rights", which reads
96
+ * like a permission problem and is not one. Callers that need the general move
97
+ * fall back to `moveCardsOneByOne`.
98
+ */
99
+ export async function bulkMoveClosedListToArchive(input) {
100
+ assertListWritable(input.toListId, undefined, "move cards into");
101
+ assertListWritable(input.fromListId, undefined, "move cards out of");
102
+ await plankaClient.post(`/api/lists/${input.fromListId}/move-cards`, {
103
+ listId: input.toListId,
104
+ });
105
+ }
106
+ /**
107
+ * The general move: one PATCH per card.
108
+ *
109
+ * Each card keeps the position it had, so the relative order survives. A card
110
+ * whose position is null (it came out of the archive) gets one, because Planka
111
+ * rejects a move without it.
112
+ *
113
+ * Returns the cards that could not be moved, with the reason — a partial move
114
+ * has to be visible, not silently reported as a smaller success.
115
+ */
116
+ export async function moveCardsOneByOne(input) {
117
+ assertListWritable(input.toListId, undefined, "move cards into");
118
+ const failed = [];
119
+ for (const card of input.cards) {
120
+ try {
121
+ await plankaClient.patch(`/api/cards/${card.id}`, {
122
+ listId: input.toListId,
123
+ position: card.position ?? 65536,
124
+ });
125
+ }
126
+ catch (error) {
127
+ failed.push({
128
+ cardId: card.id,
129
+ reason: error instanceof Error ? error.message : String(error),
130
+ });
131
+ }
132
+ }
133
+ return failed;
39
134
  }
40
135
  //# sourceMappingURL=lists.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"lists.js","sourceRoot":"","sources":["../../src/operations/lists.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EACL,gBAAgB,EAEhB,YAAY,EAEZ,sBAAsB,GAEvB,MAAM,wBAAwB,CAAC;AAEhC;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,KAAsB;IACrD,MAAM,SAAS,GAAG,UAAU,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;IAEtD,OAAO,WAAW,CAAC,SAAS,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QACtD,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,IAAI,CACtC,eAAe,OAAO,QAAQ,EAC9B;YACE,IAAI,EAAE,SAAS,CAAC,IAAI;YACpB,QAAQ,EAAE,SAAS,CAAC,QAAQ;YAC5B,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,+CAA+C;SACtE,CACF,CAAC;QAEF,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC5C,OAAO,MAAM,CAAC,IAAI,CAAC;IACrB,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,KAA4B;IAE5B,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,EAAE,GAAG,UAAU,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAC;IAEzE,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,KAAK,CACvC,cAAc,MAAM,EAAE,EACtB,OAAO,CACR,CAAC;IAEF,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC5C,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,KAAkB;IACjD,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;IACnD,MAAM,YAAY,CAAC,MAAM,CAAC,cAAc,MAAM,EAAE,CAAC,CAAC;AACpD,CAAC"}
1
+ {"version":3,"file":"lists.js","sourceRoot":"","sources":["../../src/operations/lists.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /** Put a user on a card. */
2
+ export declare function addCardMember(input: {
3
+ cardId: string;
4
+ userId: string;
5
+ }): Promise<{
6
+ id: string;
7
+ userId: string;
8
+ }>;
9
+ /** Take a user off a card. */
10
+ export declare function removeCardMember(input: {
11
+ cardId: string;
12
+ userId: string;
13
+ }): Promise<void>;
14
+ export interface SetCardMembersResult {
15
+ /** Users this call put on the card. */
16
+ added: string[];
17
+ /** Users asked for that were already there. */
18
+ alreadyPresent: string[];
19
+ /** Users this call took off the card. */
20
+ removed: string[];
21
+ /** Users asked to be removed that were not on the card. */
22
+ notPresent: string[];
23
+ /** Requests that did NOT reach the desired state. */
24
+ failed: Array<{
25
+ userId: string;
26
+ reason: string;
27
+ }>;
28
+ /** Every member of the card once the operation finished. */
29
+ finalMemberIds: string[];
30
+ }
31
+ /**
32
+ * Add and/or remove card members, then re-read to report what really landed.
33
+ */
34
+ export declare function setCardMembers(input: {
35
+ cardId: string;
36
+ add?: string[];
37
+ remove?: string[];
38
+ }): Promise<SetCardMembersResult>;
39
+ //# sourceMappingURL=members.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"members.d.ts","sourceRoot":"","sources":["../../src/operations/members.ts"],"names":[],"mappings":"AAuBA,4BAA4B;AAC5B,wBAAsB,aAAa,CAAC,KAAK,EAAE;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAM1C;AAED,8BAA8B;AAC9B,wBAAsB,gBAAgB,CAAC,KAAK,EAAE;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,IAAI,CAAC,CAIhB;AAED,MAAM,WAAW,oBAAoB;IACnC,uCAAuC;IACvC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,+CAA+C;IAC/C,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,yCAAyC;IACzC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,2DAA2D;IAC3D,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,qDAAqD;IACrD,MAAM,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClD,4DAA4D;IAC5D,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA+EhC"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Card members (assignees).
3
+ *
4
+ * The mirror image of `setCardLabels`, and for the same reason: a 200 on
5
+ * `POST /card-memberships` proves the request was accepted, not that the
6
+ * person is on the card. A userId that is not a member of the board answers
7
+ * 404 (Planka's "not found" for "not allowed"), and reporting the REQUESTED
8
+ * assignment would leave an agent believing a card is assigned to nobody.
9
+ *
10
+ * So this writes, re-reads `included.cardMemberships`, and reports the final
11
+ * membership set.
12
+ *
13
+ * The DELETE path is Planka's criteria syntax, `userId:<id>` — a literal colon
14
+ * in the URL, not the membership record's own id.
15
+ */
16
+ import { z } from "zod";
17
+ import { plankaClient } from "../client.js";
18
+ import { getCardBrief } from "./card-brief.js";
19
+ const MembershipResponse = z.object({
20
+ item: z.object({ id: z.string(), cardId: z.string(), userId: z.string() }).passthrough(),
21
+ });
22
+ /** Put a user on a card. */
23
+ export async function addCardMember(input) {
24
+ const response = await plankaClient.post(`/api/cards/${input.cardId}/card-memberships`, { userId: input.userId });
25
+ return MembershipResponse.parse(response).item;
26
+ }
27
+ /** Take a user off a card. */
28
+ export async function removeCardMember(input) {
29
+ await plankaClient.delete(`/api/cards/${input.cardId}/card-memberships/userId:${input.userId}`);
30
+ }
31
+ /**
32
+ * Add and/or remove card members, then re-read to report what really landed.
33
+ */
34
+ export async function setCardMembers(input) {
35
+ const toAdd = [...new Set(input.add ?? [])];
36
+ const toRemove = [...new Set(input.remove ?? [])];
37
+ const before = await getCardBrief({ cardId: input.cardId });
38
+ const presentBefore = new Set(before.memberIds);
39
+ const result = {
40
+ added: [],
41
+ alreadyPresent: [],
42
+ removed: [],
43
+ notPresent: [],
44
+ failed: [],
45
+ finalMemberIds: [],
46
+ };
47
+ // Remove first, so one call can hand a card over from one person to another.
48
+ for (const userId of toRemove) {
49
+ if (!presentBefore.has(userId)) {
50
+ result.notPresent.push(userId);
51
+ continue;
52
+ }
53
+ try {
54
+ await removeCardMember({ cardId: input.cardId, userId });
55
+ }
56
+ catch (error) {
57
+ result.failed.push({
58
+ userId,
59
+ reason: error instanceof Error ? error.message : String(error),
60
+ });
61
+ }
62
+ }
63
+ for (const userId of toAdd) {
64
+ if (presentBefore.has(userId)) {
65
+ result.alreadyPresent.push(userId);
66
+ continue;
67
+ }
68
+ try {
69
+ await addCardMember({ cardId: input.cardId, userId });
70
+ }
71
+ catch (error) {
72
+ const message = error instanceof Error ? error.message : String(error);
73
+ // Already assigned is the desired state, not a failure.
74
+ if (message.toLowerCase().includes("already")) {
75
+ result.alreadyPresent.push(userId);
76
+ continue;
77
+ }
78
+ result.failed.push({
79
+ userId,
80
+ reason: message +
81
+ (message.includes("404")
82
+ ? " (a 404 here usually means the user is not a member of this board)"
83
+ : ""),
84
+ });
85
+ }
86
+ }
87
+ const after = await getCardBrief({ cardId: input.cardId });
88
+ const presentAfter = new Set(after.memberIds);
89
+ result.finalMemberIds = [...presentAfter];
90
+ result.added = toAdd.filter((id) => presentAfter.has(id) && !presentBefore.has(id));
91
+ result.removed = toRemove.filter((id) => !presentAfter.has(id) && presentBefore.has(id));
92
+ // Anything asked for that the re-read contradicts is a failure, even if the
93
+ // HTTP call came back 200.
94
+ const reported = new Set(result.failed.map((f) => f.userId));
95
+ for (const userId of toAdd) {
96
+ if (!presentAfter.has(userId) && !reported.has(userId)) {
97
+ result.failed.push({ userId, reason: "still not a member of the card after the write" });
98
+ }
99
+ }
100
+ for (const userId of toRemove) {
101
+ if (presentAfter.has(userId) && !reported.has(userId)) {
102
+ result.failed.push({ userId, reason: "still a member of the card after the write" });
103
+ }
104
+ }
105
+ return result;
106
+ }
107
+ //# sourceMappingURL=members.js.map