kanbo-cli 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 (86) hide show
  1. package/CHANGELOG.md +173 -0
  2. package/LICENSE +75 -21
  3. package/README.md +19 -48
  4. package/dist/{better-sqlite3-fU3G4xnX.cjs → better-sqlite3-DPdSZ6sH.cjs} +244 -247
  5. package/dist/cli-main.cjs +51208 -0
  6. package/dist/cli.cjs +32 -45216
  7. package/dist/dist-IHRTF-b5.cjs +2552 -0
  8. package/dist/lib/{tool-names-WfH4IURz.d.cts → approval-BsBk2xVr.d.cts} +72 -3
  9. package/dist/lib/{tool-names-3q_GEZej.d.mts → approval-LRZ6ontC.d.mts} +72 -3
  10. package/dist/lib/{board-store-BvWn9xTB.d.mts → board-store-D_Mpfb84.d.mts} +75 -2
  11. package/dist/lib/{board-store-BfszzAJB.d.cts → board-store-Dx-mw2I6.d.cts} +75 -2
  12. package/dist/lib/index.cjs +8 -2
  13. package/dist/lib/index.d.cts +202 -91
  14. package/dist/lib/index.d.mts +202 -91
  15. package/dist/lib/index.mjs +3 -3
  16. package/dist/lib/{manifest-RDyoGrVR.cjs → manifest-QPoQl8tn.cjs} +6881 -1556
  17. package/dist/lib/{manifest-BwpC-4BO.mjs → manifest-v2e9x_C8.mjs} +6795 -1556
  18. package/dist/lib/mcp/index.cjs +156 -21
  19. package/dist/lib/mcp/index.d.cts +140 -5
  20. package/dist/lib/mcp/index.d.mts +140 -5
  21. package/dist/lib/mcp/index.mjs +152 -22
  22. package/dist/lib/{migrate-DnMjTCvu.cjs → migrate-Dca5WdYd.cjs} +144 -14
  23. package/dist/lib/{migrate-BhYi9cXw.mjs → migrate-DtBeW3Fs.mjs} +134 -16
  24. package/dist/lib/{migrations-path-Ciwan537.mjs → migrations-path-ClaYRNwk.mjs} +5 -7
  25. package/dist/lib/{migrations-path-CZxVOgeD.cjs → migrations-path-DBCE17dT.cjs} +5 -7
  26. package/dist/lib/postgres/index.cjs +2 -4
  27. package/dist/lib/postgres/index.d.cts +2 -3
  28. package/dist/lib/postgres/index.d.mts +2 -3
  29. package/dist/lib/postgres/index.mjs +2 -4
  30. package/dist/lib/{roles.sql-CvyCGt38.mjs → roles.sql-BoOZSkBp.mjs} +96 -5
  31. package/dist/lib/{roles.sql-B9rt-x4o.cjs → roles.sql-E58x7mLS.cjs} +95 -4
  32. package/dist/lib/schema-D0MyXcej.d.cts +1 -2
  33. package/dist/lib/schema-D0MyXcej.d.mts +1 -2
  34. package/dist/lib/schema-epoch-ZyumVL_A.d.cts +1 -2
  35. package/dist/lib/schema-epoch-ZyumVL_A.d.mts +1 -2
  36. package/dist/lib/sqlite/index.cjs +2 -2
  37. package/dist/lib/sqlite/index.d.cts +3 -4
  38. package/dist/lib/sqlite/index.d.mts +3 -4
  39. package/dist/lib/sqlite/index.mjs +2 -2
  40. package/dist/lib/sqlite/schema.cjs +0 -2
  41. package/dist/lib/sqlite/schema.mjs +0 -2
  42. package/package.json +14 -11
  43. package/dist/better-sqlite3-fU3G4xnX.cjs.map +0 -1
  44. package/dist/cli.cjs.map +0 -1
  45. package/dist/dist-BsCwQFEl.cjs +0 -989
  46. package/dist/dist-BsCwQFEl.cjs.map +0 -1
  47. package/dist/lib/manifest-BwpC-4BO.mjs.map +0 -1
  48. package/dist/lib/manifest-RDyoGrVR.cjs.map +0 -1
  49. package/dist/lib/mcp/index.cjs.map +0 -1
  50. package/dist/lib/mcp/index.mjs.map +0 -1
  51. package/dist/lib/migrate-BhYi9cXw.mjs.map +0 -1
  52. package/dist/lib/migrate-DnMjTCvu.cjs.map +0 -1
  53. package/dist/lib/migrations-path-CZxVOgeD.cjs.map +0 -1
  54. package/dist/lib/migrations-path-Ciwan537.mjs.map +0 -1
  55. package/dist/lib/postgres/index.cjs.map +0 -1
  56. package/dist/lib/postgres/index.mjs.map +0 -1
  57. package/dist/lib/roles.sql-B9rt-x4o.cjs.map +0 -1
  58. package/dist/lib/roles.sql-CvyCGt38.mjs.map +0 -1
  59. package/dist/lib/sqlite/schema.cjs.map +0 -1
  60. package/dist/lib/sqlite/schema.mjs.map +0 -1
  61. package/drizzle-postgres/0000_board.sql +0 -135
  62. package/drizzle-postgres/0001_history_order.sql +0 -2
  63. package/drizzle-postgres/0002_issue_pull_requests.sql +0 -16
  64. package/drizzle-postgres/0003_milestone_start_date.sql +0 -1
  65. package/drizzle-postgres/0004_status_entry_rules.sql +0 -1
  66. package/drizzle-postgres/0005_run_external_session_ref.sql +0 -1
  67. package/drizzle-postgres/README.md +0 -61
  68. package/drizzle-postgres/meta/0000_snapshot.json +0 -1078
  69. package/drizzle-postgres/meta/0001_snapshot.json +0 -1090
  70. package/drizzle-postgres/meta/0002_snapshot.json +0 -1239
  71. package/drizzle-postgres/meta/0003_snapshot.json +0 -1245
  72. package/drizzle-postgres/meta/0004_snapshot.json +0 -1251
  73. package/drizzle-postgres/meta/0005_snapshot.json +0 -1257
  74. package/drizzle-postgres/meta/_journal.json +0 -48
  75. package/drizzle-sqlite/0000_board.sql +0 -133
  76. package/drizzle-sqlite/0001_issue_pull_requests.sql +0 -15
  77. package/drizzle-sqlite/0002_milestone_start_date.sql +0 -1
  78. package/drizzle-sqlite/0003_status_entry_rules.sql +0 -1
  79. package/drizzle-sqlite/0004_run_external_session_ref.sql +0 -1
  80. package/drizzle-sqlite/README.md +0 -67
  81. package/drizzle-sqlite/meta/0000_snapshot.json +0 -946
  82. package/drizzle-sqlite/meta/0001_snapshot.json +0 -1054
  83. package/drizzle-sqlite/meta/0002_snapshot.json +0 -1061
  84. package/drizzle-sqlite/meta/0003_snapshot.json +0 -1068
  85. package/drizzle-sqlite/meta/0004_snapshot.json +0 -1075
  86. package/drizzle-sqlite/meta/_journal.json +0 -41
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_manifest = require("../manifest-RDyoGrVR.cjs");
3
- const require_migrations_path = require("../migrations-path-CZxVOgeD.cjs");
2
+ const require_manifest = require("../manifest-QPoQl8tn.cjs");
3
+ const require_migrations_path = require("../migrations-path-DBCE17dT.cjs");
4
4
  let zod = require("zod");
5
5
  //#region src/mcp/http-transport.ts
6
6
  const IssueSchema = zod.z.object({
@@ -88,6 +88,26 @@ const SprintSchema = zod.z.object({
88
88
  })
89
89
  });
90
90
  const PrimeSchema = zod.z.object({ text: zod.z.string() });
91
+ const ACTOR_KINDS = [
92
+ "user",
93
+ "agent",
94
+ "provider-target",
95
+ "system"
96
+ ];
97
+ /** A comment as the server lists it; who wrote it by the stored kind, `system.*` markers included. */
98
+ const CardCommentSchema = zod.z.object({
99
+ id: zod.z.string(),
100
+ authorKind: zod.z.string(),
101
+ content: zod.z.string(),
102
+ createdAt: zod.z.number()
103
+ });
104
+ const FieldChangeSchema = zod.z.object({
105
+ field: zod.z.string(),
106
+ fromValue: zod.z.string().nullable(),
107
+ toValue: zod.z.string().nullable(),
108
+ actorKind: zod.z.enum(ACTOR_KINDS),
109
+ createdAt: zod.z.number()
110
+ });
91
111
  function createHttpTransport(input) {
92
112
  const { request } = input;
93
113
  async function readColumns() {
@@ -111,36 +131,135 @@ function createHttpTransport(input) {
111
131
  });
112
132
  return column;
113
133
  }
134
+ async function listCards(filters) {
135
+ const query = new URLSearchParams({
136
+ workspaceId: input.workspaceId(),
137
+ ...filters
138
+ });
139
+ return zod.z.array(IssueSchema).parse(await request("GET", `/issues/?${query.toString()}`));
140
+ }
141
+ /**
142
+ * The cards a query picks. A server of the `/issues` routes filters on one
143
+ * column and on a parent, and no more; the rest of the query is applied here,
144
+ * to the cards it answered with, so the answer is the one the board file gives.
145
+ *
146
+ * The server filters on a parent's id only, and an agent may name the parent
147
+ * the way it names any card — `WOR-001`, `WOR-1`, `1`. The id is asked first;
148
+ * when no card answers it, the board is read whole to learn which card the
149
+ * reference names, and a reference that names none is refused as `issue_not_found`.
150
+ */
151
+ async function cardPage(cardQuery) {
152
+ const columns = await readColumns();
153
+ const statusIds = cardQuery.columns === void 0 ? null : new Set(cardQuery.columns.map((column) => requireColumn(columns, column).id));
154
+ const filters = statusIds?.size === 1 ? { statusId: [...statusIds][0] } : {};
155
+ let parent = cardQuery.parent;
156
+ let rows = await listCards(parent === void 0 ? filters : {
157
+ ...filters,
158
+ parentIssueId: parent
159
+ });
160
+ if (parent !== void 0 && rows.length === 0) {
161
+ const board = await listCards({});
162
+ const named = findCardRow(board, parent);
163
+ if (!named) throw new require_migrations_path.BoardError("issue_not_found", { issueId: parent });
164
+ parent = named.id;
165
+ rows = board;
166
+ }
167
+ const matched = rows.filter((row) => require_manifest.matchesKanboCardQuery(row, {
168
+ ...cardQuery,
169
+ parent,
170
+ returned: void 0
171
+ }, statusIds));
172
+ const picked = cardQuery.returned === void 0 ? matched : (await withAttention(matched)).filter((row) => require_manifest.matchesKanboCardQuery(row, cardQuery, null));
173
+ const offset = cardQuery.offset ?? 0;
174
+ return {
175
+ cards: (await withAttention(picked.slice(offset, cardQuery.limit === void 0 ? void 0 : offset + cardQuery.limit))).map((row) => require_manifest.projectKanboCard(row, columns)),
176
+ total: picked.length,
177
+ offset
178
+ };
179
+ }
180
+ /**
181
+ * The cards with what a list says beside the ones a person has to look at or
182
+ * sent back — their comments read one card at a time, since the route lists
183
+ * none, and only for cards that are waiting, or neither waiting nor running.
184
+ */
185
+ async function withAttention(rows) {
186
+ return await Promise.all(rows.map(async (row) => {
187
+ if (row.attention || row.waitingFor !== "human" && row.activeRun !== null) return row;
188
+ const comments = zod.z.array(CardCommentSchema).parse(await request("GET", `/issues/${encodeURIComponent(row.id)}/comments`));
189
+ const decision = comments.filter((comment) => comment.authorKind === "system.approved" || comment.authorKind === "system.returned").at(-1);
190
+ const returned = row.waitingFor !== "human" && decision?.authorKind === "system.returned";
191
+ const latest = comments.filter((comment) => comment.authorKind !== "system.run").at(-1);
192
+ const lastComment = (row.waitingFor === "human" || returned) && latest ? require_manifest.previewComment({
193
+ ...latest,
194
+ authorKind: latest.authorKind
195
+ }) : null;
196
+ return {
197
+ ...row,
198
+ attention: {
199
+ returned,
200
+ lastComment
201
+ }
202
+ };
203
+ }));
204
+ }
205
+ /** The ready cards, a page of them; the server answers the whole queue. */
206
+ async function readyPage({ returnedLimit, ...page }) {
207
+ const query = new URLSearchParams({ workspaceId: input.workspaceId() });
208
+ const cards = zod.z.array(IssueSchema).parse(await request("GET", `/issues/ready?${query.toString()}`));
209
+ const columns = await readColumns();
210
+ const offset = page.offset ?? 0;
211
+ const ready = {
212
+ cards: cards.slice(offset, page.limit === void 0 ? void 0 : offset + page.limit).map((row) => require_manifest.projectKanboCard(row, columns)),
213
+ total: cards.length,
214
+ offset
215
+ };
216
+ return returnedLimit === void 0 ? ready : {
217
+ ...ready,
218
+ returned: await cardPage({
219
+ returned: true,
220
+ limit: returnedLimit
221
+ })
222
+ };
223
+ }
114
224
  return {
115
225
  prime: async () => PrimeSchema.parse(await request("GET", `/issues/prime?workspaceId=${encodeURIComponent(input.workspaceId())}`)),
116
- ready: async ({ limit }) => {
117
- const query = new URLSearchParams({ workspaceId: input.workspaceId() });
118
- if (limit !== void 0) query.set("limit", String(limit));
119
- const cards = zod.z.array(IssueSchema).parse(await request("GET", `/issues/ready?${query.toString()}`));
120
- const columns = await readColumns();
121
- return cards.map((row) => require_manifest.projectKanboCard(row, columns));
122
- },
226
+ ready: async ({ limit }) => (await readyPage({ limit })).cards,
227
+ readyPage,
123
228
  columns: readColumns,
124
229
  sprints: async () => zod.z.array(SprintSchema).parse(await request("GET", `/issues/sprints?workspaceId=${encodeURIComponent(input.workspaceId())}`)).map(require_manifest.projectKanboSprint),
125
- cardGet: async ({ card }) => {
230
+ cardGet: async ({ card, include = require_manifest.DEFAULT_KANBO_CARD_INCLUDES, commentLimit = 10 }) => {
126
231
  const found = IssueSchema.parse(await request("GET", `/issues/${encodeURIComponent(card)}`));
127
- const columns = await readColumns();
232
+ const wants = new Set(include);
233
+ const path = `/issues/${encodeURIComponent(found.id)}`;
128
234
  const query = new URLSearchParams({
129
235
  workspaceId: input.workspaceId(),
130
236
  parentIssueId: found.id
131
237
  });
132
- const subCards = zod.z.array(IssueSchema).parse(await request("GET", `/issues/?${query.toString()}`));
238
+ const [columns, subCards, comments, runs, history, pullRequests] = await Promise.all([
239
+ readColumns(),
240
+ wants.has("subCards") ? request("GET", `/issues/?${query.toString()}`).then((rows) => zod.z.array(IssueSchema).parse(rows)) : null,
241
+ wants.has("comments") ? request("GET", `${path}/comments`).then((rows) => zod.z.array(CardCommentSchema).parse(rows)) : null,
242
+ wants.has("runs") ? request("GET", `${path}/runs`).then((rows) => zod.z.array(RunSchema).parse(rows)) : null,
243
+ wants.has("history") ? request("GET", `${path}/field-changes`).then((rows) => zod.z.array(FieldChangeSchema).parse(rows)) : null,
244
+ wants.has("prs") ? request("GET", `${path}/pull-requests`).then((rows) => zod.z.array(PullRequestSchema).parse(rows)) : null
245
+ ]);
133
246
  return {
134
247
  ...require_manifest.projectKanboCard(found, columns),
135
- subCards: subCards.map((row) => require_manifest.projectKanboSubCard(row, columns))
248
+ ...subCards ? { subCards: subCards.map((row) => require_manifest.projectKanboSubCard(row, columns)) } : {},
249
+ ...comments ? {
250
+ comments: comments.slice(-commentLimit).map(require_manifest.projectKanboCardComment),
251
+ commentCount: comments.length
252
+ } : {},
253
+ ...runs ? { runs: runs.map(require_manifest.projectKanboRun) } : {},
254
+ ...history ? { history: history.map(require_manifest.projectKanboFieldChange) } : {},
255
+ ...pullRequests ? { pullRequests: pullRequests.map(require_manifest.projectKanboPullRequest) } : {}
136
256
  };
137
257
  },
138
- cardList: async ({ column, limit }) => {
139
- const columns = await readColumns();
140
- const query = new URLSearchParams({ workspaceId: input.workspaceId() });
141
- if (column) query.set("statusId", requireColumn(columns, column).id);
142
- return zod.z.array(IssueSchema).parse(await request("GET", `/issues/?${query.toString()}`)).slice(0, limit ?? Number.POSITIVE_INFINITY).map((row) => require_manifest.projectKanboCard(row, columns));
143
- },
258
+ cardList: async ({ column, limit }) => (await cardPage({
259
+ columns: column ? [column] : void 0,
260
+ limit
261
+ })).cards,
262
+ cardPage,
144
263
  cardCreate: async ({ title, description, column, parent, executionMode }) => await projectOne(await request("POST", "/issues/", {
145
264
  workspaceId: input.workspaceId(),
146
265
  ...title !== void 0 ? { title } : {},
@@ -168,9 +287,25 @@ function createHttpTransport(input) {
168
287
  })))
169
288
  };
170
289
  }
290
+ /**
291
+ * The card a reference names among cards already read, the way the board file
292
+ * resolves one: its id, its number, or its key without the padding (`WOR-1`).
293
+ */
294
+ function findCardRow(rows, reference) {
295
+ const trimmed = reference.trim();
296
+ const byId = rows.find((row) => row.id === trimmed);
297
+ if (byId) return byId;
298
+ const key = /^(?:(.+)-)?(\d+)$/.exec(trimmed);
299
+ if (!key) return;
300
+ const [, prefix, digits] = key;
301
+ return rows.find((row) => row.number === Number(digits) && (prefix === void 0 || row.id.slice(0, row.id.lastIndexOf("-")).toUpperCase() === prefix.toUpperCase()));
302
+ }
171
303
  //#endregion
304
+ exports.DEFAULT_KANBO_CARD_INCLUDES = require_manifest.DEFAULT_KANBO_CARD_INCLUDES;
305
+ exports.DEFAULT_KANBO_COMMENT_LIMIT = require_manifest.DEFAULT_KANBO_COMMENT_LIMIT;
172
306
  exports.KANBO_CAPABILITIES_MARKDOWN_RESOURCE_URI = require_manifest.KANBO_CAPABILITIES_MARKDOWN_RESOURCE_URI;
173
307
  exports.KANBO_CAPABILITIES_RESOURCE_URI = require_manifest.KANBO_CAPABILITIES_RESOURCE_URI;
308
+ exports.KANBO_CARD_INCLUDES = require_manifest.KANBO_CARD_INCLUDES;
174
309
  exports.KANBO_MCP_INSTRUCTIONS = require_manifest.KANBO_MCP_INSTRUCTIONS;
175
310
  exports.KANBO_MCP_SERVER_NAME = require_manifest.KANBO_MCP_SERVER_NAME;
176
311
  exports.KANBO_TOOLS = require_manifest.KANBO_TOOLS;
@@ -179,7 +314,7 @@ exports.KANBO_TOOL_NAMES = require_manifest.KANBO_TOOL_NAMES;
179
314
  exports.buildKanboTools = require_manifest.buildKanboTools;
180
315
  exports.createHttpTransport = createHttpTransport;
181
316
  exports.createKanboMcpServer = require_manifest.createKanboMcpServer;
317
+ exports.matchesKanboCardQuery = require_manifest.matchesKanboCardQuery;
318
+ exports.pageOf = require_manifest.pageOf;
182
319
  exports.registerKanboCapabilitiesResources = require_manifest.registerKanboCapabilitiesResources;
183
320
  exports.registerKanboTools = require_manifest.registerKanboTools;
184
-
185
- //# sourceMappingURL=index.cjs.map
@@ -1,5 +1,5 @@
1
1
  import { s as IssueRun, t as Issue } from "../schema-D0MyXcej.cjs";
2
- import { i as KanboToolName, n as KANBO_TOOL_NAMES, r as KanboToolCliEquivalent, s as EntryRule, t as KANBO_TOOL_CLI_EQUIVALENTS } from "../tool-names-WfH4IURz.cjs";
2
+ import { _ as EntryRule, d as KANBO_TOOL_CLI_EQUIVALENTS, f as KANBO_TOOL_NAMES, i as IssueActorKind, m as KanboToolName, p as KanboToolCliEquivalent, r as CardLastComment } from "../approval-BsBk2xVr.cjs";
3
3
  import { z } from "zod";
4
4
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
5
  import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
@@ -40,13 +40,86 @@ interface KanboCardResult {
40
40
  /** The run going on right now, `null` when nobody is working on the card. */
41
41
  activeRun: KanboActiveRunResult | null;
42
42
  updatedAt: number;
43
+ /** Present on a list's card a person sent back that nobody has picked up again. */
44
+ returned?: true;
45
+ /** On a list's card waiting for a person or returned: its latest comment, cut short. */
46
+ lastComment?: CardLastComment;
43
47
  }
48
+ /** What `kanbo_card_get` may bring along with the card. */
49
+ export declare const KANBO_CARD_INCLUDES: readonly ['comments', 'subCards', 'runs', 'history', 'prs'];
50
+ type KanboCardInclude = typeof KANBO_CARD_INCLUDES[number];
51
+ /** What a card read brings along when the caller does not say: its latest comments and its sub-cards. */
52
+ export declare const DEFAULT_KANBO_CARD_INCLUDES: readonly KanboCardInclude[];
53
+ /** How many of its latest comments a card read brings along when the caller does not say. */
54
+ export declare const DEFAULT_KANBO_COMMENT_LIMIT = 10;
44
55
  /**
45
56
  * A card read on its own, as `kanbo_card_get` hands it to an agent: the card,
46
- * and the sub-cards under it in board order. Its parent is `parentIssueId`.
57
+ * and whatever the read was asked to bring along — the sub-cards under it in
58
+ * board order, its latest comments, its runs, its field history, the pull
59
+ * requests it names. Its parent is `parentIssueId`.
47
60
  */
48
61
  interface KanboCardDetailResult extends KanboCardResult {
49
- subCards: Pick<KanboCardResult, 'id' | 'title' | 'columnSlug'>[];
62
+ subCards?: Pick<KanboCardResult, 'id' | 'title' | 'columnSlug'>[];
63
+ /** The latest comments, oldest of them first; `commentCount` says how many the card has in all. */
64
+ comments?: KanboCardCommentResult[];
65
+ commentCount?: number;
66
+ /** Every run, first attempt first. */
67
+ runs?: KanboRunResult[];
68
+ /** Every tracked field change, oldest first. */
69
+ history?: KanboFieldChangeResult[];
70
+ pullRequests?: KanboPullRequestResult[];
71
+ }
72
+ /** A comment as a card read lists it: who wrote it — a person, an agent or the board — and what it says. */
73
+ interface KanboCardCommentResult {
74
+ id: string;
75
+ author: IssueActorKind;
76
+ content: string;
77
+ createdAt: number;
78
+ }
79
+ /** One change to a tracked field of a card, and who made it. */
80
+ interface KanboFieldChangeResult {
81
+ field: string;
82
+ from: string | null;
83
+ to: string | null;
84
+ actor: IssueActorKind;
85
+ createdAt: number;
86
+ }
87
+ /**
88
+ * Which cards `kanbo_card_list` picks, and which page of them. Every filter is
89
+ * optional and they all apply together.
90
+ */
91
+ interface KanboCardQuery {
92
+ /** Cards in any of these columns, by slug or name. */
93
+ columns?: string[];
94
+ /** `true`: only cards waiting for a person; `false`: only cards waiting for no one. */
95
+ waitingForPerson?: boolean;
96
+ /** Only the sub-cards of this card, by its id. */
97
+ parent?: string;
98
+ /** `true`: only cards an agent is working on now; `false`: only cards nobody is. */
99
+ hasActiveRun?: boolean;
100
+ /** `true`: only cards a person sent back that nobody has picked up again; `false`: every other card. */
101
+ returned?: boolean;
102
+ /** Cards whose id, title or description contains this text, ignoring case. */
103
+ text?: string;
104
+ /** Cards changed at or after this moment, in unix seconds. */
105
+ updatedSince?: number;
106
+ /** Cards carrying every one of these labels. */
107
+ labels?: string[];
108
+ /** Cards of any of these priorities. */
109
+ priority?: Issue['priority'][];
110
+ offset?: number;
111
+ /** How many cards to return; every one picked when absent. */
112
+ limit?: number;
113
+ }
114
+ /** One page of cards, and how many the question picks in all. */
115
+ interface KanboCardPage {
116
+ cards: KanboCardResult[];
117
+ total: number;
118
+ offset: number;
119
+ }
120
+ /** The ready cards, with the returned ones when they were asked for. */
121
+ interface KanboReadyPage extends KanboCardPage {
122
+ returned?: KanboCardPage;
50
123
  }
51
124
  /** The run of a card that is going on right now. */
52
125
  interface KanboActiveRunResult {
@@ -167,15 +240,30 @@ interface KanboToolTransport {
167
240
  ready: (input: {
168
241
  limit?: number;
169
242
  }) => Promise<KanboCardResult[]>;
243
+ /**
244
+ * One page of the ready cards, and how many are ready in all — and, when
245
+ * `returnedLimit` is given, up to that many cards a person sent back
246
+ * (`KanboCardQuery.returned`), which an agent continues before anything new.
247
+ */
248
+ readyPage: (input: {
249
+ limit?: number;
250
+ offset?: number;
251
+ returnedLimit?: number;
252
+ }) => Promise<KanboReadyPage>;
170
253
  columns: () => Promise<KanboColumnResult[]>;
171
254
  sprints: () => Promise<KanboSprintResult[]>;
255
+ /** The card, with what `include` names — `DEFAULT_KANBO_CARD_INCLUDES` when absent. */
172
256
  cardGet: (input: {
173
257
  card: string;
258
+ include?: readonly KanboCardInclude[];
259
+ commentLimit?: number;
174
260
  }) => Promise<KanboCardDetailResult>;
175
261
  cardList: (input: {
176
262
  column?: string;
177
263
  limit?: number;
178
264
  }) => Promise<KanboCardResult[]>;
265
+ /** One page of the cards a query picks, and how many it picks in all. */
266
+ cardPage: (input: KanboCardQuery) => Promise<KanboCardPage>;
179
267
  cardCreate: (input: KanboCardCreateInput) => Promise<KanboCardResult>;
180
268
  cardUpdate: (input: KanboCardUpdateInput) => Promise<KanboCardResult>;
181
269
  cardMove: (input: {
@@ -204,6 +292,44 @@ interface KanboToolTransport {
204
292
  runStart: (input: KanboRunStartInput) => Promise<KanboRunResult>;
205
293
  runFinish: (input: KanboRunFinishInput) => Promise<KanboRunResult>;
206
294
  }
295
+ /**
296
+ * A card as either transport already has it: the row's own fields with the
297
+ * labels decoded, plus what the run registry says about it.
298
+ */
299
+ interface KanboCardFacts {
300
+ id: string;
301
+ number: number;
302
+ title: string;
303
+ description: string | null;
304
+ statusId: string | null;
305
+ statusLine: string | null;
306
+ waitingFor: 'human' | null;
307
+ priority: Issue['priority'];
308
+ labels: string[];
309
+ executionMode: Issue['executionMode'];
310
+ parentIssueId: string | null;
311
+ updatedAt: number;
312
+ attemptCount: number;
313
+ activeRun: KanboActiveRunResult | null;
314
+ /** What a list says beside a card a person has to look at, or sent back; absent where nobody asked. */
315
+ attention?: {
316
+ returned: boolean;
317
+ lastComment: CardLastComment | null;
318
+ };
319
+ }
320
+ /**
321
+ * Does the card answer the query? The filters of `KanboCardQuery`, applied to
322
+ * a card already read — for a transport whose server filters on less than the
323
+ * query names. `statusIds` are the query's columns, already resolved.
324
+ */
325
+ export declare function matchesKanboCardQuery(card: KanboCardFacts & {
326
+ description: string | null;
327
+ }, query: KanboCardQuery, statusIds: ReadonlySet<string> | null): boolean;
328
+ /** A page cut out of cards already picked, in the order they were picked. */
329
+ export declare function pageOf(cards: KanboCardResult[], input: {
330
+ offset?: number;
331
+ limit?: number;
332
+ }): KanboCardPage;
207
333
  //#endregion
208
334
  //#region src/mcp/http-transport.d.ts
209
335
  /**
@@ -299,7 +425,17 @@ interface KanboTool {
299
425
  name: KanboToolName;
300
426
  title: string;
301
427
  description: string;
428
+ /** The arguments under their canonical names — what the tool publishes and the manifest lists. */
302
429
  inputSchema: KanboToolShape;
430
+ /**
431
+ * What the MCP server registers: the same JSON Schema as `inputSchema`, but
432
+ * accepting anything, so a call with a wrong or aliased argument reaches
433
+ * `run` — which answers it in a sentence — instead of the server's own
434
+ * validation dump.
435
+ */
436
+ registrationSchema: z.ZodType;
437
+ /** Other names each argument is accepted under, canonical name first. */
438
+ aliases: Readonly<Record<string, readonly string[]>>;
303
439
  run: (transport: KanboToolTransport, input: unknown) => Promise<KanboToolResult>;
304
440
  }
305
441
  //#endregion
@@ -359,5 +495,4 @@ export declare function registerKanboTools(server: McpServer, transport: KanboTo
359
495
  */
360
496
  export declare function createKanboMcpServer(transport: KanboToolTransport, options: KanboToolOptions): McpServer;
361
497
  //#endregion
362
- export { KANBO_TOOL_CLI_EQUIVALENTS, KANBO_TOOL_NAMES, type KanboActiveRunResult, type KanboCardResult, type KanboColumnResult, type KanboCommentResult, type KanboHttpRequest, type KanboHttpTransportInput, type KanboPullRequestResult, type KanboRunResult, type KanboTool, type KanboToolCliEquivalent, type KanboToolName, type KanboToolOptions, type KanboToolRegistration, type KanboToolResult, type KanboToolTransport };
363
- //# sourceMappingURL=index.d.cts.map
498
+ export { KANBO_TOOL_CLI_EQUIVALENTS, KANBO_TOOL_NAMES, type KanboActiveRunResult, type KanboCardCommentResult, type KanboCardCreateInput, type KanboCardDetailResult, type KanboCardFacts, type KanboCardInclude, type KanboCardPage, type KanboCardQuery, type KanboCardResult, type KanboCardUpdateInput, type KanboColumnResult, type KanboCommentResult, type KanboFieldChangeResult, type KanboHttpRequest, type KanboHttpTransportInput, type KanboPullRequestResult, type KanboReadyPage, type KanboRunFinishInput, type KanboRunResult, type KanboRunStartInput, type KanboSprintResult, type KanboTool, type KanboToolCliEquivalent, type KanboToolName, type KanboToolOptions, type KanboToolRegistration, type KanboToolResult, type KanboToolTransport };
@@ -1,5 +1,5 @@
1
1
  import { s as IssueRun, t as Issue } from "../schema-D0MyXcej.mjs";
2
- import { i as KanboToolName, n as KANBO_TOOL_NAMES, r as KanboToolCliEquivalent, s as EntryRule, t as KANBO_TOOL_CLI_EQUIVALENTS } from "../tool-names-3q_GEZej.mjs";
2
+ import { _ as EntryRule, d as KANBO_TOOL_CLI_EQUIVALENTS, f as KANBO_TOOL_NAMES, i as IssueActorKind, m as KanboToolName, p as KanboToolCliEquivalent, r as CardLastComment } from "../approval-LRZ6ontC.mjs";
3
3
  import { z } from "zod";
4
4
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
5
  import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
@@ -40,13 +40,86 @@ interface KanboCardResult {
40
40
  /** The run going on right now, `null` when nobody is working on the card. */
41
41
  activeRun: KanboActiveRunResult | null;
42
42
  updatedAt: number;
43
+ /** Present on a list's card a person sent back that nobody has picked up again. */
44
+ returned?: true;
45
+ /** On a list's card waiting for a person or returned: its latest comment, cut short. */
46
+ lastComment?: CardLastComment;
43
47
  }
48
+ /** What `kanbo_card_get` may bring along with the card. */
49
+ export declare const KANBO_CARD_INCLUDES: readonly ['comments', 'subCards', 'runs', 'history', 'prs'];
50
+ type KanboCardInclude = typeof KANBO_CARD_INCLUDES[number];
51
+ /** What a card read brings along when the caller does not say: its latest comments and its sub-cards. */
52
+ export declare const DEFAULT_KANBO_CARD_INCLUDES: readonly KanboCardInclude[];
53
+ /** How many of its latest comments a card read brings along when the caller does not say. */
54
+ export declare const DEFAULT_KANBO_COMMENT_LIMIT = 10;
44
55
  /**
45
56
  * A card read on its own, as `kanbo_card_get` hands it to an agent: the card,
46
- * and the sub-cards under it in board order. Its parent is `parentIssueId`.
57
+ * and whatever the read was asked to bring along — the sub-cards under it in
58
+ * board order, its latest comments, its runs, its field history, the pull
59
+ * requests it names. Its parent is `parentIssueId`.
47
60
  */
48
61
  interface KanboCardDetailResult extends KanboCardResult {
49
- subCards: Pick<KanboCardResult, 'id' | 'title' | 'columnSlug'>[];
62
+ subCards?: Pick<KanboCardResult, 'id' | 'title' | 'columnSlug'>[];
63
+ /** The latest comments, oldest of them first; `commentCount` says how many the card has in all. */
64
+ comments?: KanboCardCommentResult[];
65
+ commentCount?: number;
66
+ /** Every run, first attempt first. */
67
+ runs?: KanboRunResult[];
68
+ /** Every tracked field change, oldest first. */
69
+ history?: KanboFieldChangeResult[];
70
+ pullRequests?: KanboPullRequestResult[];
71
+ }
72
+ /** A comment as a card read lists it: who wrote it — a person, an agent or the board — and what it says. */
73
+ interface KanboCardCommentResult {
74
+ id: string;
75
+ author: IssueActorKind;
76
+ content: string;
77
+ createdAt: number;
78
+ }
79
+ /** One change to a tracked field of a card, and who made it. */
80
+ interface KanboFieldChangeResult {
81
+ field: string;
82
+ from: string | null;
83
+ to: string | null;
84
+ actor: IssueActorKind;
85
+ createdAt: number;
86
+ }
87
+ /**
88
+ * Which cards `kanbo_card_list` picks, and which page of them. Every filter is
89
+ * optional and they all apply together.
90
+ */
91
+ interface KanboCardQuery {
92
+ /** Cards in any of these columns, by slug or name. */
93
+ columns?: string[];
94
+ /** `true`: only cards waiting for a person; `false`: only cards waiting for no one. */
95
+ waitingForPerson?: boolean;
96
+ /** Only the sub-cards of this card, by its id. */
97
+ parent?: string;
98
+ /** `true`: only cards an agent is working on now; `false`: only cards nobody is. */
99
+ hasActiveRun?: boolean;
100
+ /** `true`: only cards a person sent back that nobody has picked up again; `false`: every other card. */
101
+ returned?: boolean;
102
+ /** Cards whose id, title or description contains this text, ignoring case. */
103
+ text?: string;
104
+ /** Cards changed at or after this moment, in unix seconds. */
105
+ updatedSince?: number;
106
+ /** Cards carrying every one of these labels. */
107
+ labels?: string[];
108
+ /** Cards of any of these priorities. */
109
+ priority?: Issue['priority'][];
110
+ offset?: number;
111
+ /** How many cards to return; every one picked when absent. */
112
+ limit?: number;
113
+ }
114
+ /** One page of cards, and how many the question picks in all. */
115
+ interface KanboCardPage {
116
+ cards: KanboCardResult[];
117
+ total: number;
118
+ offset: number;
119
+ }
120
+ /** The ready cards, with the returned ones when they were asked for. */
121
+ interface KanboReadyPage extends KanboCardPage {
122
+ returned?: KanboCardPage;
50
123
  }
51
124
  /** The run of a card that is going on right now. */
52
125
  interface KanboActiveRunResult {
@@ -167,15 +240,30 @@ interface KanboToolTransport {
167
240
  ready: (input: {
168
241
  limit?: number;
169
242
  }) => Promise<KanboCardResult[]>;
243
+ /**
244
+ * One page of the ready cards, and how many are ready in all — and, when
245
+ * `returnedLimit` is given, up to that many cards a person sent back
246
+ * (`KanboCardQuery.returned`), which an agent continues before anything new.
247
+ */
248
+ readyPage: (input: {
249
+ limit?: number;
250
+ offset?: number;
251
+ returnedLimit?: number;
252
+ }) => Promise<KanboReadyPage>;
170
253
  columns: () => Promise<KanboColumnResult[]>;
171
254
  sprints: () => Promise<KanboSprintResult[]>;
255
+ /** The card, with what `include` names — `DEFAULT_KANBO_CARD_INCLUDES` when absent. */
172
256
  cardGet: (input: {
173
257
  card: string;
258
+ include?: readonly KanboCardInclude[];
259
+ commentLimit?: number;
174
260
  }) => Promise<KanboCardDetailResult>;
175
261
  cardList: (input: {
176
262
  column?: string;
177
263
  limit?: number;
178
264
  }) => Promise<KanboCardResult[]>;
265
+ /** One page of the cards a query picks, and how many it picks in all. */
266
+ cardPage: (input: KanboCardQuery) => Promise<KanboCardPage>;
179
267
  cardCreate: (input: KanboCardCreateInput) => Promise<KanboCardResult>;
180
268
  cardUpdate: (input: KanboCardUpdateInput) => Promise<KanboCardResult>;
181
269
  cardMove: (input: {
@@ -204,6 +292,44 @@ interface KanboToolTransport {
204
292
  runStart: (input: KanboRunStartInput) => Promise<KanboRunResult>;
205
293
  runFinish: (input: KanboRunFinishInput) => Promise<KanboRunResult>;
206
294
  }
295
+ /**
296
+ * A card as either transport already has it: the row's own fields with the
297
+ * labels decoded, plus what the run registry says about it.
298
+ */
299
+ interface KanboCardFacts {
300
+ id: string;
301
+ number: number;
302
+ title: string;
303
+ description: string | null;
304
+ statusId: string | null;
305
+ statusLine: string | null;
306
+ waitingFor: 'human' | null;
307
+ priority: Issue['priority'];
308
+ labels: string[];
309
+ executionMode: Issue['executionMode'];
310
+ parentIssueId: string | null;
311
+ updatedAt: number;
312
+ attemptCount: number;
313
+ activeRun: KanboActiveRunResult | null;
314
+ /** What a list says beside a card a person has to look at, or sent back; absent where nobody asked. */
315
+ attention?: {
316
+ returned: boolean;
317
+ lastComment: CardLastComment | null;
318
+ };
319
+ }
320
+ /**
321
+ * Does the card answer the query? The filters of `KanboCardQuery`, applied to
322
+ * a card already read — for a transport whose server filters on less than the
323
+ * query names. `statusIds` are the query's columns, already resolved.
324
+ */
325
+ export declare function matchesKanboCardQuery(card: KanboCardFacts & {
326
+ description: string | null;
327
+ }, query: KanboCardQuery, statusIds: ReadonlySet<string> | null): boolean;
328
+ /** A page cut out of cards already picked, in the order they were picked. */
329
+ export declare function pageOf(cards: KanboCardResult[], input: {
330
+ offset?: number;
331
+ limit?: number;
332
+ }): KanboCardPage;
207
333
  //#endregion
208
334
  //#region src/mcp/http-transport.d.ts
209
335
  /**
@@ -299,7 +425,17 @@ interface KanboTool {
299
425
  name: KanboToolName;
300
426
  title: string;
301
427
  description: string;
428
+ /** The arguments under their canonical names — what the tool publishes and the manifest lists. */
302
429
  inputSchema: KanboToolShape;
430
+ /**
431
+ * What the MCP server registers: the same JSON Schema as `inputSchema`, but
432
+ * accepting anything, so a call with a wrong or aliased argument reaches
433
+ * `run` — which answers it in a sentence — instead of the server's own
434
+ * validation dump.
435
+ */
436
+ registrationSchema: z.ZodType;
437
+ /** Other names each argument is accepted under, canonical name first. */
438
+ aliases: Readonly<Record<string, readonly string[]>>;
303
439
  run: (transport: KanboToolTransport, input: unknown) => Promise<KanboToolResult>;
304
440
  }
305
441
  //#endregion
@@ -359,5 +495,4 @@ export declare function registerKanboTools(server: McpServer, transport: KanboTo
359
495
  */
360
496
  export declare function createKanboMcpServer(transport: KanboToolTransport, options: KanboToolOptions): McpServer;
361
497
  //#endregion
362
- export { KANBO_TOOL_CLI_EQUIVALENTS, KANBO_TOOL_NAMES, type KanboActiveRunResult, type KanboCardResult, type KanboColumnResult, type KanboCommentResult, type KanboHttpRequest, type KanboHttpTransportInput, type KanboPullRequestResult, type KanboRunResult, type KanboTool, type KanboToolCliEquivalent, type KanboToolName, type KanboToolOptions, type KanboToolRegistration, type KanboToolResult, type KanboToolTransport };
363
- //# sourceMappingURL=index.d.mts.map
498
+ export { KANBO_TOOL_CLI_EQUIVALENTS, KANBO_TOOL_NAMES, type KanboActiveRunResult, type KanboCardCommentResult, type KanboCardCreateInput, type KanboCardDetailResult, type KanboCardFacts, type KanboCardInclude, type KanboCardPage, type KanboCardQuery, type KanboCardResult, type KanboCardUpdateInput, type KanboColumnResult, type KanboCommentResult, type KanboFieldChangeResult, type KanboHttpRequest, type KanboHttpTransportInput, type KanboPullRequestResult, type KanboReadyPage, type KanboRunFinishInput, type KanboRunResult, type KanboRunStartInput, type KanboSprintResult, type KanboTool, type KanboToolCliEquivalent, type KanboToolName, type KanboToolOptions, type KanboToolRegistration, type KanboToolResult, type KanboToolTransport };