kanban-lite 1.0.9 → 1.0.13

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 (38) hide show
  1. package/dist/cli.js +1015 -407
  2. package/dist/extension.js +897 -347
  3. package/dist/mcp-server.js +550 -189
  4. package/dist/sdk/index.cjs +1223 -0
  5. package/dist/sdk/index.mjs +1168 -0
  6. package/dist/sdk/sdk/KanbanSDK.d.ts +39 -21
  7. package/dist/sdk/sdk/index.d.ts +4 -3
  8. package/dist/sdk/sdk/migration.d.ts +6 -0
  9. package/dist/sdk/sdk/types.d.ts +3 -5
  10. package/dist/sdk/shared/config.d.ts +23 -10
  11. package/dist/sdk/shared/types.d.ts +18 -4
  12. package/dist/standalone-webview/index.js +27 -27
  13. package/dist/standalone-webview/index.js.map +1 -1
  14. package/dist/standalone-webview/style.css +1 -1
  15. package/dist/standalone.js +831 -328
  16. package/dist/webview/index.js +45 -45
  17. package/dist/webview/index.js.map +1 -1
  18. package/dist/webview/style.css +1 -1
  19. package/package.json +4 -3
  20. package/src/cli/index.ts +217 -95
  21. package/src/extension/KanbanPanel.ts +49 -22
  22. package/src/mcp-server/index.ts +138 -62
  23. package/src/sdk/KanbanSDK.ts +283 -77
  24. package/src/sdk/__tests__/KanbanSDK.test.ts +5 -5
  25. package/src/sdk/__tests__/migration.test.ts +269 -0
  26. package/src/sdk/__tests__/multi-board.test.ts +449 -0
  27. package/src/sdk/index.ts +4 -3
  28. package/src/sdk/migration.ts +52 -0
  29. package/src/sdk/types.ts +3 -6
  30. package/src/shared/config.ts +144 -22
  31. package/src/shared/types.ts +14 -5
  32. package/src/standalone/__tests__/server.integration.test.ts +38 -37
  33. package/src/standalone/server.ts +239 -21
  34. package/src/webview/App.tsx +17 -7
  35. package/src/webview/components/Toolbar.tsx +99 -3
  36. package/src/webview/store/index.ts +11 -3
  37. package/.kanban/backlog/1-test1.md +0 -30
  38. package/.kanban.json +0 -42
@@ -24,15 +24,15 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  ));
25
25
 
26
26
  // src/mcp-server/index.ts
27
- var path6 = __toESM(require("path"));
28
- var fs5 = __toESM(require("fs/promises"));
27
+ var path7 = __toESM(require("path"));
28
+ var fs6 = __toESM(require("fs/promises"));
29
29
  var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
30
30
  var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
31
31
  var import_zod = require("zod");
32
32
 
33
33
  // src/sdk/KanbanSDK.ts
34
- var fs3 = __toESM(require("fs/promises"));
35
- var path4 = __toESM(require("path"));
34
+ var fs4 = __toESM(require("fs/promises"));
35
+ var path5 = __toESM(require("path"));
36
36
 
37
37
  // node_modules/.pnpm/fractional-indexing@3.2.0/node_modules/fractional-indexing/src/index.js
38
38
  var BASE_62_DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
@@ -263,23 +263,34 @@ function extractNumericId(filenameOrId) {
263
263
  const match = filenameOrId.match(/^(\d+)(?:-|$)/);
264
264
  return match ? parseInt(match[1], 10) : null;
265
265
  }
266
+ var DEFAULT_COLUMNS = [
267
+ { id: "backlog", name: "Backlog", color: "#6b7280" },
268
+ { id: "todo", name: "To Do", color: "#3b82f6" },
269
+ { id: "in-progress", name: "In Progress", color: "#f59e0b" },
270
+ { id: "review", name: "Review", color: "#8b5cf6" },
271
+ { id: "done", name: "Done", color: "#22c55e" }
272
+ ];
266
273
 
267
274
  // src/shared/config.ts
268
275
  var fs = __toESM(require("fs"));
269
276
  var path = __toESM(require("path"));
277
+ var DEFAULT_BOARD_CONFIG = {
278
+ name: "Default",
279
+ columns: [...DEFAULT_COLUMNS],
280
+ nextCardId: 1,
281
+ defaultStatus: "backlog",
282
+ defaultPriority: "medium"
283
+ };
270
284
  var DEFAULT_CONFIG = {
285
+ version: 2,
286
+ boards: {
287
+ default: { ...DEFAULT_BOARD_CONFIG, columns: [...DEFAULT_COLUMNS] }
288
+ },
289
+ defaultBoard: "default",
271
290
  featuresDirectory: ".kanban",
291
+ aiAgent: "claude",
272
292
  defaultPriority: "medium",
273
293
  defaultStatus: "backlog",
274
- columns: [
275
- { id: "backlog", name: "Backlog", color: "#6b7280" },
276
- { id: "todo", name: "To Do", color: "#3b82f6" },
277
- { id: "in-progress", name: "In Progress", color: "#f59e0b" },
278
- { id: "review", name: "Review", color: "#8b5cf6" },
279
- { id: "done", name: "Done", color: "#22c55e" }
280
- ],
281
- aiAgent: "claude",
282
- nextCardId: 1,
283
294
  showPriorityBadges: true,
284
295
  showAssignee: true,
285
296
  showDueDate: true,
@@ -293,12 +304,65 @@ var CONFIG_FILENAME = ".kanban.json";
293
304
  function configPath(workspaceRoot) {
294
305
  return path.join(workspaceRoot, CONFIG_FILENAME);
295
306
  }
307
+ function migrateConfigV1ToV2(raw) {
308
+ const v1Defaults = {
309
+ featuresDirectory: ".kanban",
310
+ defaultPriority: "medium",
311
+ defaultStatus: "backlog",
312
+ columns: [...DEFAULT_COLUMNS],
313
+ aiAgent: "claude",
314
+ nextCardId: 1,
315
+ showPriorityBadges: true,
316
+ showAssignee: true,
317
+ showDueDate: true,
318
+ showLabels: true,
319
+ showBuildWithAI: true,
320
+ showFileName: false,
321
+ compactMode: false,
322
+ markdownEditorMode: false
323
+ };
324
+ const v1 = { ...v1Defaults, ...raw };
325
+ return {
326
+ version: 2,
327
+ boards: {
328
+ default: {
329
+ name: "Default",
330
+ columns: v1.columns,
331
+ nextCardId: v1.nextCardId,
332
+ defaultStatus: v1.defaultStatus,
333
+ defaultPriority: v1.defaultPriority
334
+ }
335
+ },
336
+ defaultBoard: "default",
337
+ featuresDirectory: v1.featuresDirectory,
338
+ aiAgent: v1.aiAgent,
339
+ defaultPriority: v1.defaultPriority,
340
+ defaultStatus: v1.defaultStatus,
341
+ showPriorityBadges: v1.showPriorityBadges,
342
+ showAssignee: v1.showAssignee,
343
+ showDueDate: v1.showDueDate,
344
+ showLabels: v1.showLabels,
345
+ showBuildWithAI: v1.showBuildWithAI,
346
+ showFileName: v1.showFileName,
347
+ compactMode: v1.compactMode,
348
+ markdownEditorMode: v1.markdownEditorMode
349
+ };
350
+ }
296
351
  function readConfig(workspaceRoot) {
297
352
  const filePath = configPath(workspaceRoot);
298
- const defaults = { ...DEFAULT_CONFIG, columns: [...DEFAULT_CONFIG.columns] };
353
+ const defaults = { ...DEFAULT_CONFIG, boards: { default: { ...DEFAULT_BOARD_CONFIG, columns: [...DEFAULT_COLUMNS] } } };
299
354
  try {
300
355
  const raw = JSON.parse(fs.readFileSync(filePath, "utf-8"));
301
- return { ...defaults, ...raw };
356
+ if (!raw.version || raw.version === 1) {
357
+ const v2 = migrateConfigV1ToV2(raw);
358
+ writeConfig(workspaceRoot, v2);
359
+ return v2;
360
+ }
361
+ const config = { ...defaults, ...raw };
362
+ if (!config.boards || Object.keys(config.boards).length === 0) {
363
+ config.boards = defaults.boards;
364
+ }
365
+ return config;
302
366
  } catch {
303
367
  return defaults;
304
368
  }
@@ -307,19 +371,39 @@ function writeConfig(workspaceRoot, config) {
307
371
  const filePath = configPath(workspaceRoot);
308
372
  fs.writeFileSync(filePath, JSON.stringify(config, null, 2) + "\n", "utf-8");
309
373
  }
310
- function allocateCardId(workspaceRoot) {
374
+ function getBoardConfig(workspaceRoot, boardId) {
375
+ const config = readConfig(workspaceRoot);
376
+ const resolvedId = boardId || config.defaultBoard;
377
+ const board = config.boards[resolvedId];
378
+ if (!board) {
379
+ throw new Error(`Board '${resolvedId}' not found`);
380
+ }
381
+ return board;
382
+ }
383
+ function allocateCardId(workspaceRoot, boardId) {
311
384
  const config = readConfig(workspaceRoot);
312
- const id = config.nextCardId;
313
- writeConfig(workspaceRoot, { ...config, nextCardId: id + 1 });
385
+ const resolvedId = boardId || config.defaultBoard;
386
+ const board = config.boards[resolvedId];
387
+ if (!board) {
388
+ throw new Error(`Board '${resolvedId}' not found`);
389
+ }
390
+ const id = board.nextCardId;
391
+ board.nextCardId = id + 1;
392
+ writeConfig(workspaceRoot, config);
314
393
  return id;
315
394
  }
316
- function syncCardIdCounter(workspaceRoot, existingIds) {
395
+ function syncCardIdCounter(workspaceRoot, boardId, existingIds) {
317
396
  if (existingIds.length === 0)
318
397
  return;
319
398
  const maxId = Math.max(...existingIds);
320
399
  const config = readConfig(workspaceRoot);
321
- if (config.nextCardId <= maxId) {
322
- writeConfig(workspaceRoot, { ...config, nextCardId: maxId + 1 });
400
+ const resolvedId = boardId || config.defaultBoard;
401
+ const board = config.boards[resolvedId];
402
+ if (!board)
403
+ return;
404
+ if (board.nextCardId <= maxId) {
405
+ board.nextCardId = maxId + 1;
406
+ writeConfig(workspaceRoot, config);
323
407
  }
324
408
  }
325
409
  function configToSettings(config) {
@@ -537,30 +621,203 @@ async function fileExists(filePath) {
537
621
  }
538
622
  }
539
623
 
624
+ // src/sdk/migration.ts
625
+ var fs3 = __toESM(require("fs/promises"));
626
+ var path4 = __toESM(require("path"));
627
+ async function migrateFileSystemToMultiBoard(featuresDir) {
628
+ const boardsDir = path4.join(featuresDir, "boards");
629
+ const defaultBoardDir = path4.join(boardsDir, "default");
630
+ try {
631
+ await fs3.access(boardsDir);
632
+ return;
633
+ } catch {
634
+ }
635
+ await fs3.mkdir(defaultBoardDir, { recursive: true });
636
+ let entries;
637
+ try {
638
+ entries = await fs3.readdir(featuresDir, { withFileTypes: true });
639
+ } catch {
640
+ return;
641
+ }
642
+ for (const entry of entries) {
643
+ if (!entry.isDirectory())
644
+ continue;
645
+ if (entry.name === "boards" || entry.name.startsWith("."))
646
+ continue;
647
+ const src = path4.join(featuresDir, entry.name);
648
+ const dest = path4.join(defaultBoardDir, entry.name);
649
+ await fs3.rename(src, dest);
650
+ }
651
+ const rootMdFiles = entries.filter((e) => e.isFile() && e.name.endsWith(".md"));
652
+ if (rootMdFiles.length > 0) {
653
+ const backlogDir = path4.join(defaultBoardDir, "backlog");
654
+ await fs3.mkdir(backlogDir, { recursive: true });
655
+ for (const file of rootMdFiles) {
656
+ await fs3.rename(
657
+ path4.join(featuresDir, file.name),
658
+ path4.join(backlogDir, file.name)
659
+ );
660
+ }
661
+ }
662
+ }
663
+
540
664
  // src/sdk/KanbanSDK.ts
541
665
  var KanbanSDK = class {
542
666
  constructor(featuresDir) {
543
667
  this.featuresDir = featuresDir;
668
+ this._migrated = false;
544
669
  }
545
670
  get workspaceRoot() {
546
- return path4.dirname(this.featuresDir);
671
+ return path5.dirname(this.featuresDir);
672
+ }
673
+ // --- Board resolution helpers ---
674
+ _resolveBoardId(boardId) {
675
+ const config = readConfig(this.workspaceRoot);
676
+ return boardId || config.defaultBoard;
677
+ }
678
+ _boardDir(boardId) {
679
+ const resolvedId = this._resolveBoardId(boardId);
680
+ return path5.join(this.featuresDir, "boards", resolvedId);
681
+ }
682
+ _isCompletedStatus(status, boardId) {
683
+ const config = readConfig(this.workspaceRoot);
684
+ const resolvedId = boardId || config.defaultBoard;
685
+ const board = config.boards[resolvedId];
686
+ if (!board || board.columns.length === 0)
687
+ return status === "done";
688
+ return board.columns[board.columns.length - 1].id === status;
689
+ }
690
+ async _ensureMigrated() {
691
+ if (this._migrated)
692
+ return;
693
+ await migrateFileSystemToMultiBoard(this.featuresDir);
694
+ this._migrated = true;
547
695
  }
548
696
  async init() {
549
- await ensureDirectories(this.featuresDir);
697
+ await this._ensureMigrated();
698
+ const boardDir = this._boardDir();
699
+ await ensureDirectories(boardDir);
700
+ }
701
+ // --- Board management ---
702
+ listBoards() {
703
+ const config = readConfig(this.workspaceRoot);
704
+ return Object.entries(config.boards).map(([id, board]) => ({
705
+ id,
706
+ name: board.name,
707
+ description: board.description
708
+ }));
709
+ }
710
+ createBoard(id, name, options) {
711
+ const config = readConfig(this.workspaceRoot);
712
+ if (config.boards[id]) {
713
+ throw new Error(`Board already exists: ${id}`);
714
+ }
715
+ const columns = options?.columns || [...config.boards[config.defaultBoard]?.columns || [
716
+ { id: "backlog", name: "Backlog", color: "#6b7280" },
717
+ { id: "todo", name: "To Do", color: "#3b82f6" },
718
+ { id: "in-progress", name: "In Progress", color: "#f59e0b" },
719
+ { id: "review", name: "Review", color: "#8b5cf6" },
720
+ { id: "done", name: "Done", color: "#22c55e" }
721
+ ]];
722
+ config.boards[id] = {
723
+ name,
724
+ description: options?.description,
725
+ columns,
726
+ nextCardId: 1,
727
+ defaultStatus: options?.defaultStatus || columns[0]?.id || "backlog",
728
+ defaultPriority: options?.defaultPriority || config.defaultPriority
729
+ };
730
+ writeConfig(this.workspaceRoot, config);
731
+ return { id, name, description: options?.description };
732
+ }
733
+ async deleteBoard(boardId) {
734
+ const config = readConfig(this.workspaceRoot);
735
+ if (!config.boards[boardId]) {
736
+ throw new Error(`Board not found: ${boardId}`);
737
+ }
738
+ if (config.defaultBoard === boardId) {
739
+ throw new Error(`Cannot delete the default board: ${boardId}`);
740
+ }
741
+ const cards = await this.listCards(void 0, boardId);
742
+ if (cards.length > 0) {
743
+ throw new Error(`Cannot delete board "${boardId}": ${cards.length} card(s) still exist`);
744
+ }
745
+ const boardDir = this._boardDir(boardId);
746
+ try {
747
+ await fs4.rm(boardDir, { recursive: true });
748
+ } catch {
749
+ }
750
+ delete config.boards[boardId];
751
+ writeConfig(this.workspaceRoot, config);
752
+ }
753
+ getBoard(boardId) {
754
+ return getBoardConfig(this.workspaceRoot, boardId);
755
+ }
756
+ updateBoard(boardId, updates) {
757
+ const config = readConfig(this.workspaceRoot);
758
+ const board = config.boards[boardId];
759
+ if (!board) {
760
+ throw new Error(`Board not found: ${boardId}`);
761
+ }
762
+ if (updates.name !== void 0)
763
+ board.name = updates.name;
764
+ if (updates.description !== void 0)
765
+ board.description = updates.description;
766
+ if (updates.columns !== void 0)
767
+ board.columns = updates.columns;
768
+ if (updates.defaultStatus !== void 0)
769
+ board.defaultStatus = updates.defaultStatus;
770
+ if (updates.defaultPriority !== void 0)
771
+ board.defaultPriority = updates.defaultPriority;
772
+ writeConfig(this.workspaceRoot, config);
773
+ return board;
774
+ }
775
+ async transferCard(cardId, fromBoardId, toBoardId, targetStatus) {
776
+ const toBoardDir = this._boardDir(toBoardId);
777
+ const config = readConfig(this.workspaceRoot);
778
+ if (!config.boards[fromBoardId])
779
+ throw new Error(`Board not found: ${fromBoardId}`);
780
+ if (!config.boards[toBoardId])
781
+ throw new Error(`Board not found: ${toBoardId}`);
782
+ const card = await this.getCard(cardId, fromBoardId);
783
+ if (!card)
784
+ throw new Error(`Card not found: ${cardId} in board ${fromBoardId}`);
785
+ const toBoard = config.boards[toBoardId];
786
+ const newStatus = targetStatus || toBoard.defaultStatus || toBoard.columns[0]?.id || "backlog";
787
+ const targetDir = path5.join(toBoardDir, newStatus);
788
+ await fs4.mkdir(targetDir, { recursive: true });
789
+ const oldPath = card.filePath;
790
+ const filename = path5.basename(oldPath);
791
+ const newPath = path5.join(targetDir, filename);
792
+ await fs4.rename(oldPath, newPath);
793
+ card.status = newStatus;
794
+ card.boardId = toBoardId;
795
+ card.filePath = newPath;
796
+ card.modified = (/* @__PURE__ */ new Date()).toISOString();
797
+ card.completedAt = this._isCompletedStatus(newStatus, toBoardId) ? (/* @__PURE__ */ new Date()).toISOString() : null;
798
+ const targetCards = await this.listCards(void 0, toBoardId);
799
+ const cardsInStatus = targetCards.filter((c) => c.status === newStatus && c.id !== cardId).sort((a, b) => a.order < b.order ? -1 : a.order > b.order ? 1 : 0);
800
+ const lastOrder = cardsInStatus.length > 0 ? cardsInStatus[cardsInStatus.length - 1].order : null;
801
+ card.order = generateKeyBetween(lastOrder, null);
802
+ await fs4.writeFile(card.filePath, serializeFeature(card), "utf-8");
803
+ return card;
550
804
  }
551
805
  // --- Card CRUD ---
552
- async listCards(columns) {
553
- await ensureDirectories(this.featuresDir);
806
+ async listCards(columns, boardId) {
807
+ await this._ensureMigrated();
808
+ const boardDir = this._boardDir(boardId);
809
+ const resolvedBoardId = this._resolveBoardId(boardId);
810
+ await ensureDirectories(boardDir);
554
811
  if (columns) {
555
- await ensureStatusSubfolders(this.featuresDir, columns);
812
+ await ensureStatusSubfolders(boardDir, columns);
556
813
  }
557
814
  try {
558
- const rootFiles = await this._readMdFiles(this.featuresDir);
815
+ const rootFiles = await this._readMdFiles(boardDir);
559
816
  for (const filePath of rootFiles) {
560
817
  try {
561
818
  const card = await this._loadCard(filePath);
562
819
  if (card) {
563
- await moveFeatureFile(filePath, this.featuresDir, card.status, card.attachments);
820
+ await moveFeatureFile(filePath, boardDir, card.status, card.attachments);
564
821
  }
565
822
  } catch {
566
823
  }
@@ -568,26 +825,33 @@ var KanbanSDK = class {
568
825
  } catch {
569
826
  }
570
827
  const cards = [];
571
- const entries = await fs3.readdir(this.featuresDir, { withFileTypes: true });
828
+ let entries;
829
+ try {
830
+ entries = await fs4.readdir(boardDir, { withFileTypes: true });
831
+ } catch {
832
+ return [];
833
+ }
572
834
  for (const entry of entries) {
573
835
  if (!entry.isDirectory() || entry.name.startsWith("."))
574
836
  continue;
575
- const subdir = path4.join(this.featuresDir, entry.name);
837
+ const subdir = path5.join(boardDir, entry.name);
576
838
  try {
577
839
  const mdFiles = await this._readMdFiles(subdir);
578
840
  for (const filePath of mdFiles) {
579
841
  const card = await this._loadCard(filePath);
580
- if (card)
842
+ if (card) {
843
+ card.boardId = resolvedBoardId;
581
844
  cards.push(card);
845
+ }
582
846
  }
583
847
  } catch {
584
848
  }
585
849
  }
586
850
  for (const card of cards) {
587
- const pathStatus = getStatusFromPath(card.filePath, this.featuresDir);
851
+ const pathStatus = getStatusFromPath(card.filePath, boardDir);
588
852
  if (pathStatus !== null && pathStatus !== card.status) {
589
853
  try {
590
- card.filePath = await moveFeatureFile(card.filePath, this.featuresDir, card.status, card.attachments);
854
+ card.filePath = await moveFeatureFile(card.filePath, boardDir, card.status, card.attachments);
591
855
  } catch {
592
856
  }
593
857
  }
@@ -605,65 +869,72 @@ var KanbanSDK = class {
605
869
  const keys = generateNKeysBetween(null, null, columnCards.length);
606
870
  for (let i = 0; i < columnCards.length; i++) {
607
871
  columnCards[i].order = keys[i];
608
- await fs3.writeFile(columnCards[i].filePath, serializeFeature(columnCards[i]), "utf-8");
872
+ await fs4.writeFile(columnCards[i].filePath, serializeFeature(columnCards[i]), "utf-8");
609
873
  }
610
874
  }
611
875
  }
612
876
  const numericIds = cards.map((c) => parseInt(c.id, 10)).filter((n) => !Number.isNaN(n));
613
877
  if (numericIds.length > 0) {
614
- syncCardIdCounter(path4.dirname(this.featuresDir), numericIds);
878
+ syncCardIdCounter(this.workspaceRoot, resolvedBoardId, numericIds);
615
879
  }
616
880
  return cards.sort((a, b) => a.order < b.order ? -1 : a.order > b.order ? 1 : 0);
617
881
  }
618
- async getCard(cardId) {
619
- const cards = await this.listCards();
882
+ async getCard(cardId, boardId) {
883
+ const cards = await this.listCards(void 0, boardId);
620
884
  return cards.find((c) => c.id === cardId) || null;
621
885
  }
622
886
  async createCard(data) {
623
- await ensureDirectories(this.featuresDir);
624
- const status = data.status || "backlog";
625
- const priority = data.priority || "medium";
887
+ await this._ensureMigrated();
888
+ const resolvedBoardId = this._resolveBoardId(data.boardId);
889
+ const boardDir = this._boardDir(resolvedBoardId);
890
+ await ensureDirectories(boardDir);
891
+ const config = readConfig(this.workspaceRoot);
892
+ const board = config.boards[resolvedBoardId];
893
+ const status = data.status || board?.defaultStatus || config.defaultStatus || "backlog";
894
+ const priority = data.priority || board?.defaultPriority || config.defaultPriority || "medium";
626
895
  const title = getTitleFromContent(data.content);
627
- const workspaceRoot = path4.dirname(this.featuresDir);
628
- const numericId = allocateCardId(workspaceRoot);
896
+ const numericId = allocateCardId(this.workspaceRoot, resolvedBoardId);
629
897
  const filename = generateFeatureFilename(numericId, title);
630
898
  const now = (/* @__PURE__ */ new Date()).toISOString();
631
- const cards = await this.listCards();
899
+ const cards = await this.listCards(void 0, resolvedBoardId);
632
900
  const cardsInStatus = cards.filter((c) => c.status === status).sort((a, b) => a.order < b.order ? -1 : a.order > b.order ? 1 : 0);
633
901
  const lastOrder = cardsInStatus.length > 0 ? cardsInStatus[cardsInStatus.length - 1].order : null;
634
902
  const card = {
635
903
  id: String(numericId),
904
+ boardId: resolvedBoardId,
636
905
  status,
637
906
  priority,
638
907
  assignee: data.assignee ?? null,
639
908
  dueDate: data.dueDate ?? null,
640
909
  created: now,
641
910
  modified: now,
642
- completedAt: status === "done" ? now : null,
911
+ completedAt: this._isCompletedStatus(status, resolvedBoardId) ? now : null,
643
912
  labels: data.labels || [],
644
913
  attachments: data.attachments || [],
645
914
  comments: [],
646
915
  order: generateKeyBetween(lastOrder, null),
647
916
  content: data.content,
648
- filePath: getFeatureFilePath(this.featuresDir, status, filename)
917
+ filePath: getFeatureFilePath(boardDir, status, filename)
649
918
  };
650
- await fs3.mkdir(path4.dirname(card.filePath), { recursive: true });
651
- await fs3.writeFile(card.filePath, serializeFeature(card), "utf-8");
919
+ await fs4.mkdir(path5.dirname(card.filePath), { recursive: true });
920
+ await fs4.writeFile(card.filePath, serializeFeature(card), "utf-8");
652
921
  return card;
653
922
  }
654
- async updateCard(cardId, updates) {
655
- const card = await this.getCard(cardId);
923
+ async updateCard(cardId, updates, boardId) {
924
+ const card = await this.getCard(cardId, boardId);
656
925
  if (!card)
657
926
  throw new Error(`Card not found: ${cardId}`);
927
+ const resolvedBoardId = card.boardId || this._resolveBoardId(boardId);
928
+ const boardDir = this._boardDir(resolvedBoardId);
658
929
  const oldStatus = card.status;
659
930
  const oldTitle = getTitleFromContent(card.content);
660
- const { filePath: _fp, id: _id, ...safeUpdates } = updates;
931
+ const { filePath: _fp, id: _id, boardId: _bid, ...safeUpdates } = updates;
661
932
  Object.assign(card, safeUpdates);
662
933
  card.modified = (/* @__PURE__ */ new Date()).toISOString();
663
934
  if (oldStatus !== card.status) {
664
- card.completedAt = card.status === "done" ? (/* @__PURE__ */ new Date()).toISOString() : null;
935
+ card.completedAt = this._isCompletedStatus(card.status, resolvedBoardId) ? (/* @__PURE__ */ new Date()).toISOString() : null;
665
936
  }
666
- await fs3.writeFile(card.filePath, serializeFeature(card), "utf-8");
937
+ await fs4.writeFile(card.filePath, serializeFeature(card), "utf-8");
667
938
  const newTitle = getTitleFromContent(card.content);
668
939
  const numericId = extractNumericId(card.id);
669
940
  if (numericId !== null && newTitle !== oldTitle) {
@@ -671,46 +942,48 @@ var KanbanSDK = class {
671
942
  card.filePath = await renameFeatureFile(card.filePath, newFilename);
672
943
  }
673
944
  if (oldStatus !== card.status) {
674
- const newPath = await moveFeatureFile(card.filePath, this.featuresDir, card.status, card.attachments);
945
+ const newPath = await moveFeatureFile(card.filePath, boardDir, card.status, card.attachments);
675
946
  card.filePath = newPath;
676
947
  }
677
948
  return card;
678
949
  }
679
- async moveCard(cardId, newStatus, position) {
680
- const cards = await this.listCards();
950
+ async moveCard(cardId, newStatus, position, boardId) {
951
+ const cards = await this.listCards(void 0, boardId);
681
952
  const card = cards.find((c) => c.id === cardId);
682
953
  if (!card)
683
954
  throw new Error(`Card not found: ${cardId}`);
955
+ const resolvedBoardId = card.boardId || this._resolveBoardId(boardId);
956
+ const boardDir = this._boardDir(resolvedBoardId);
684
957
  const oldStatus = card.status;
685
958
  card.status = newStatus;
686
959
  card.modified = (/* @__PURE__ */ new Date()).toISOString();
687
960
  if (oldStatus !== newStatus) {
688
- card.completedAt = newStatus === "done" ? (/* @__PURE__ */ new Date()).toISOString() : null;
961
+ card.completedAt = this._isCompletedStatus(newStatus, resolvedBoardId) ? (/* @__PURE__ */ new Date()).toISOString() : null;
689
962
  }
690
963
  const targetColumnCards = cards.filter((c) => c.status === newStatus && c.id !== cardId).sort((a, b) => a.order < b.order ? -1 : a.order > b.order ? 1 : 0);
691
964
  const pos = position !== void 0 ? Math.max(0, Math.min(position, targetColumnCards.length)) : targetColumnCards.length;
692
965
  const before = pos > 0 ? targetColumnCards[pos - 1].order : null;
693
966
  const after = pos < targetColumnCards.length ? targetColumnCards[pos].order : null;
694
967
  card.order = generateKeyBetween(before, after);
695
- await fs3.writeFile(card.filePath, serializeFeature(card), "utf-8");
968
+ await fs4.writeFile(card.filePath, serializeFeature(card), "utf-8");
696
969
  if (oldStatus !== newStatus) {
697
- const newPath = await moveFeatureFile(card.filePath, this.featuresDir, newStatus, card.attachments);
970
+ const newPath = await moveFeatureFile(card.filePath, boardDir, newStatus, card.attachments);
698
971
  card.filePath = newPath;
699
972
  }
700
973
  return card;
701
974
  }
702
- async deleteCard(cardId) {
703
- const card = await this.getCard(cardId);
975
+ async deleteCard(cardId, boardId) {
976
+ const card = await this.getCard(cardId, boardId);
704
977
  if (!card)
705
978
  throw new Error(`Card not found: ${cardId}`);
706
- await fs3.unlink(card.filePath);
979
+ await fs4.unlink(card.filePath);
707
980
  }
708
- async getCardsByStatus(status) {
709
- const cards = await this.listCards();
981
+ async getCardsByStatus(status, boardId) {
982
+ const cards = await this.listCards(void 0, boardId);
710
983
  return cards.filter((c) => c.status === status);
711
984
  }
712
- async getUniqueAssignees() {
713
- const cards = await this.listCards();
985
+ async getUniqueAssignees(boardId) {
986
+ const cards = await this.listCards(void 0, boardId);
714
987
  const assignees = /* @__PURE__ */ new Set();
715
988
  for (const c of cards) {
716
989
  if (c.assignee)
@@ -718,8 +991,8 @@ var KanbanSDK = class {
718
991
  }
719
992
  return [...assignees].sort();
720
993
  }
721
- async getUniqueLabels() {
722
- const cards = await this.listCards();
994
+ async getUniqueLabels(boardId) {
995
+ const cards = await this.listCards(void 0, boardId);
723
996
  const labels = /* @__PURE__ */ new Set();
724
997
  for (const c of cards) {
725
998
  for (const l of c.labels)
@@ -728,48 +1001,48 @@ var KanbanSDK = class {
728
1001
  return [...labels].sort();
729
1002
  }
730
1003
  // --- Attachment management ---
731
- async addAttachment(cardId, sourcePath) {
732
- const card = await this.getCard(cardId);
1004
+ async addAttachment(cardId, sourcePath, boardId) {
1005
+ const card = await this.getCard(cardId, boardId);
733
1006
  if (!card)
734
1007
  throw new Error(`Card not found: ${cardId}`);
735
- const fileName = path4.basename(sourcePath);
736
- const cardDir = path4.dirname(card.filePath);
737
- const destPath = path4.join(cardDir, fileName);
738
- const sourceDir = path4.dirname(path4.resolve(sourcePath));
1008
+ const fileName = path5.basename(sourcePath);
1009
+ const cardDir = path5.dirname(card.filePath);
1010
+ const destPath = path5.join(cardDir, fileName);
1011
+ const sourceDir = path5.dirname(path5.resolve(sourcePath));
739
1012
  if (sourceDir !== cardDir) {
740
- await fs3.copyFile(path4.resolve(sourcePath), destPath);
1013
+ await fs4.copyFile(path5.resolve(sourcePath), destPath);
741
1014
  }
742
1015
  if (!card.attachments.includes(fileName)) {
743
1016
  card.attachments.push(fileName);
744
1017
  }
745
1018
  card.modified = (/* @__PURE__ */ new Date()).toISOString();
746
- await fs3.writeFile(card.filePath, serializeFeature(card), "utf-8");
1019
+ await fs4.writeFile(card.filePath, serializeFeature(card), "utf-8");
747
1020
  return card;
748
1021
  }
749
- async removeAttachment(cardId, attachment) {
750
- const card = await this.getCard(cardId);
1022
+ async removeAttachment(cardId, attachment, boardId) {
1023
+ const card = await this.getCard(cardId, boardId);
751
1024
  if (!card)
752
1025
  throw new Error(`Card not found: ${cardId}`);
753
1026
  card.attachments = card.attachments.filter((a) => a !== attachment);
754
1027
  card.modified = (/* @__PURE__ */ new Date()).toISOString();
755
- await fs3.writeFile(card.filePath, serializeFeature(card), "utf-8");
1028
+ await fs4.writeFile(card.filePath, serializeFeature(card), "utf-8");
756
1029
  return card;
757
1030
  }
758
- async listAttachments(cardId) {
759
- const card = await this.getCard(cardId);
1031
+ async listAttachments(cardId, boardId) {
1032
+ const card = await this.getCard(cardId, boardId);
760
1033
  if (!card)
761
1034
  throw new Error(`Card not found: ${cardId}`);
762
1035
  return card.attachments;
763
1036
  }
764
1037
  // --- Comment management ---
765
- async listComments(cardId) {
766
- const card = await this.getCard(cardId);
1038
+ async listComments(cardId, boardId) {
1039
+ const card = await this.getCard(cardId, boardId);
767
1040
  if (!card)
768
1041
  throw new Error(`Card not found: ${cardId}`);
769
1042
  return card.comments || [];
770
1043
  }
771
- async addComment(cardId, author, content) {
772
- const card = await this.getCard(cardId);
1044
+ async addComment(cardId, author, content, boardId) {
1045
+ const card = await this.getCard(cardId, boardId);
773
1046
  if (!card)
774
1047
  throw new Error(`Card not found: ${cardId}`);
775
1048
  if (!card.comments)
@@ -786,11 +1059,11 @@ var KanbanSDK = class {
786
1059
  };
787
1060
  card.comments.push(comment);
788
1061
  card.modified = (/* @__PURE__ */ new Date()).toISOString();
789
- await fs3.writeFile(card.filePath, serializeFeature(card), "utf-8");
1062
+ await fs4.writeFile(card.filePath, serializeFeature(card), "utf-8");
790
1063
  return card;
791
1064
  }
792
- async updateComment(cardId, commentId, content) {
793
- const card = await this.getCard(cardId);
1065
+ async updateComment(cardId, commentId, content, boardId) {
1066
+ const card = await this.getCard(cardId, boardId);
794
1067
  if (!card)
795
1068
  throw new Error(`Card not found: ${cardId}`);
796
1069
  const comment = (card.comments || []).find((c) => c.id === commentId);
@@ -798,34 +1071,45 @@ var KanbanSDK = class {
798
1071
  throw new Error(`Comment not found: ${commentId}`);
799
1072
  comment.content = content;
800
1073
  card.modified = (/* @__PURE__ */ new Date()).toISOString();
801
- await fs3.writeFile(card.filePath, serializeFeature(card), "utf-8");
1074
+ await fs4.writeFile(card.filePath, serializeFeature(card), "utf-8");
802
1075
  return card;
803
1076
  }
804
- async deleteComment(cardId, commentId) {
805
- const card = await this.getCard(cardId);
1077
+ async deleteComment(cardId, commentId, boardId) {
1078
+ const card = await this.getCard(cardId, boardId);
806
1079
  if (!card)
807
1080
  throw new Error(`Card not found: ${cardId}`);
808
1081
  card.comments = (card.comments || []).filter((c) => c.id !== commentId);
809
1082
  card.modified = (/* @__PURE__ */ new Date()).toISOString();
810
- await fs3.writeFile(card.filePath, serializeFeature(card), "utf-8");
1083
+ await fs4.writeFile(card.filePath, serializeFeature(card), "utf-8");
811
1084
  return card;
812
1085
  }
813
- // --- Column management ---
814
- listColumns() {
815
- return readConfig(this.workspaceRoot).columns;
1086
+ // --- Column management (board-scoped) ---
1087
+ listColumns(boardId) {
1088
+ const config = readConfig(this.workspaceRoot);
1089
+ const resolvedId = boardId || config.defaultBoard;
1090
+ const board = config.boards[resolvedId];
1091
+ return board?.columns || [];
816
1092
  }
817
- addColumn(column) {
1093
+ addColumn(column, boardId) {
818
1094
  const config = readConfig(this.workspaceRoot);
819
- if (config.columns.some((c) => c.id === column.id)) {
1095
+ const resolvedId = boardId || config.defaultBoard;
1096
+ const board = config.boards[resolvedId];
1097
+ if (!board)
1098
+ throw new Error(`Board not found: ${resolvedId}`);
1099
+ if (board.columns.some((c) => c.id === column.id)) {
820
1100
  throw new Error(`Column already exists: ${column.id}`);
821
1101
  }
822
- config.columns.push(column);
1102
+ board.columns.push(column);
823
1103
  writeConfig(this.workspaceRoot, config);
824
- return config.columns;
1104
+ return board.columns;
825
1105
  }
826
- updateColumn(columnId, updates) {
1106
+ updateColumn(columnId, updates, boardId) {
827
1107
  const config = readConfig(this.workspaceRoot);
828
- const col = config.columns.find((c) => c.id === columnId);
1108
+ const resolvedId = boardId || config.defaultBoard;
1109
+ const board = config.boards[resolvedId];
1110
+ if (!board)
1111
+ throw new Error(`Board not found: ${resolvedId}`);
1112
+ const col = board.columns.find((c) => c.id === columnId);
829
1113
  if (!col)
830
1114
  throw new Error(`Column not found: ${columnId}`);
831
1115
  if (updates.name !== void 0)
@@ -833,37 +1117,45 @@ var KanbanSDK = class {
833
1117
  if (updates.color !== void 0)
834
1118
  col.color = updates.color;
835
1119
  writeConfig(this.workspaceRoot, config);
836
- return config.columns;
1120
+ return board.columns;
837
1121
  }
838
- async removeColumn(columnId) {
1122
+ async removeColumn(columnId, boardId) {
839
1123
  const config = readConfig(this.workspaceRoot);
840
- const idx = config.columns.findIndex((c) => c.id === columnId);
1124
+ const resolvedId = boardId || config.defaultBoard;
1125
+ const board = config.boards[resolvedId];
1126
+ if (!board)
1127
+ throw new Error(`Board not found: ${resolvedId}`);
1128
+ const idx = board.columns.findIndex((c) => c.id === columnId);
841
1129
  if (idx === -1)
842
1130
  throw new Error(`Column not found: ${columnId}`);
843
- const cards = await this.listCards();
1131
+ const cards = await this.listCards(void 0, resolvedId);
844
1132
  const cardsInColumn = cards.filter((c) => c.status === columnId);
845
1133
  if (cardsInColumn.length > 0) {
846
1134
  throw new Error(`Cannot remove column "${columnId}": ${cardsInColumn.length} card(s) still in this column`);
847
1135
  }
848
- config.columns.splice(idx, 1);
1136
+ board.columns.splice(idx, 1);
849
1137
  writeConfig(this.workspaceRoot, config);
850
- return config.columns;
1138
+ return board.columns;
851
1139
  }
852
- reorderColumns(columnIds) {
1140
+ reorderColumns(columnIds, boardId) {
853
1141
  const config = readConfig(this.workspaceRoot);
854
- const colMap = new Map(config.columns.map((c) => [c.id, c]));
1142
+ const resolvedId = boardId || config.defaultBoard;
1143
+ const board = config.boards[resolvedId];
1144
+ if (!board)
1145
+ throw new Error(`Board not found: ${resolvedId}`);
1146
+ const colMap = new Map(board.columns.map((c) => [c.id, c]));
855
1147
  for (const id of columnIds) {
856
1148
  if (!colMap.has(id))
857
1149
  throw new Error(`Column not found: ${id}`);
858
1150
  }
859
- if (columnIds.length !== config.columns.length) {
1151
+ if (columnIds.length !== board.columns.length) {
860
1152
  throw new Error("Must include all column IDs when reordering");
861
1153
  }
862
- config.columns = columnIds.map((id) => colMap.get(id));
1154
+ board.columns = columnIds.map((id) => colMap.get(id));
863
1155
  writeConfig(this.workspaceRoot, config);
864
- return config.columns;
1156
+ return board.columns;
865
1157
  }
866
- // --- Settings management ---
1158
+ // --- Settings management (global) ---
867
1159
  getSettings() {
868
1160
  return configToSettings(readConfig(this.workspaceRoot));
869
1161
  }
@@ -873,26 +1165,26 @@ var KanbanSDK = class {
873
1165
  }
874
1166
  // --- Private helpers ---
875
1167
  async _readMdFiles(dir) {
876
- const entries = await fs3.readdir(dir, { withFileTypes: true });
877
- return entries.filter((e) => e.isFile() && e.name.endsWith(".md")).map((e) => path4.join(dir, e.name));
1168
+ const entries = await fs4.readdir(dir, { withFileTypes: true });
1169
+ return entries.filter((e) => e.isFile() && e.name.endsWith(".md")).map((e) => path5.join(dir, e.name));
878
1170
  }
879
1171
  async _loadCard(filePath) {
880
- const content = await fs3.readFile(filePath, "utf-8");
1172
+ const content = await fs4.readFile(filePath, "utf-8");
881
1173
  return parseFeatureFile(content, filePath);
882
1174
  }
883
1175
  };
884
1176
 
885
1177
  // src/standalone/webhooks.ts
886
- var fs4 = __toESM(require("fs"));
887
- var path5 = __toESM(require("path"));
1178
+ var fs5 = __toESM(require("fs"));
1179
+ var path6 = __toESM(require("path"));
888
1180
  var crypto = __toESM(require("crypto"));
889
1181
  var WEBHOOKS_FILENAME = ".kanban-webhooks.json";
890
1182
  function webhooksPath(workspaceRoot) {
891
- return path5.join(workspaceRoot, WEBHOOKS_FILENAME);
1183
+ return path6.join(workspaceRoot, WEBHOOKS_FILENAME);
892
1184
  }
893
1185
  function loadWebhooks(workspaceRoot) {
894
1186
  try {
895
- const raw = fs4.readFileSync(webhooksPath(workspaceRoot), "utf-8");
1187
+ const raw = fs5.readFileSync(webhooksPath(workspaceRoot), "utf-8");
896
1188
  const data = JSON.parse(raw);
897
1189
  return Array.isArray(data) ? data : [];
898
1190
  } catch {
@@ -900,7 +1192,7 @@ function loadWebhooks(workspaceRoot) {
900
1192
  }
901
1193
  }
902
1194
  function saveWebhooks(workspaceRoot, webhooks) {
903
- fs4.writeFileSync(webhooksPath(workspaceRoot), JSON.stringify(webhooks, null, 2) + "\n", "utf-8");
1195
+ fs5.writeFileSync(webhooksPath(workspaceRoot), JSON.stringify(webhooks, null, 2) + "\n", "utf-8");
904
1196
  }
905
1197
  function createWebhook(workspaceRoot, config) {
906
1198
  const webhooks = loadWebhooks(workspaceRoot);
@@ -929,16 +1221,16 @@ async function findWorkspaceRoot(startDir) {
929
1221
  let dir = startDir;
930
1222
  while (true) {
931
1223
  try {
932
- await fs5.access(path6.join(dir, ".git"));
1224
+ await fs6.access(path7.join(dir, ".git"));
933
1225
  return dir;
934
1226
  } catch {
935
1227
  }
936
1228
  try {
937
- await fs5.access(path6.join(dir, "package.json"));
1229
+ await fs6.access(path7.join(dir, "package.json"));
938
1230
  return dir;
939
1231
  } catch {
940
1232
  }
941
- const parent = path6.dirname(dir);
1233
+ const parent = path7.dirname(dir);
942
1234
  if (parent === dir)
943
1235
  return startDir;
944
1236
  dir = parent;
@@ -947,13 +1239,13 @@ async function findWorkspaceRoot(startDir) {
947
1239
  async function resolveFeaturesDir() {
948
1240
  const dirIndex = process.argv.indexOf("--dir");
949
1241
  if (dirIndex !== -1 && process.argv[dirIndex + 1]) {
950
- return path6.resolve(process.argv[dirIndex + 1]);
1242
+ return path7.resolve(process.argv[dirIndex + 1]);
951
1243
  }
952
1244
  if (process.env.KANBAN_FEATURES_DIR) {
953
- return path6.resolve(process.env.KANBAN_FEATURES_DIR);
1245
+ return path7.resolve(process.env.KANBAN_FEATURES_DIR);
954
1246
  }
955
1247
  const root = await findWorkspaceRoot(process.cwd());
956
- return path6.join(root, ".devtool", "features");
1248
+ return path7.join(root, ".devtool", "features");
957
1249
  }
958
1250
  function getTitleFromContent2(content) {
959
1251
  const match = content.match(/^#\s+(.+)$/m);
@@ -969,17 +1261,68 @@ async function main() {
969
1261
  name: "kanban-lite",
970
1262
  version: "1.0.0"
971
1263
  });
1264
+ server.tool("list_boards", "List all kanban boards.", {}, async () => {
1265
+ const boards = sdk.listBoards();
1266
+ return { content: [{ type: "text", text: JSON.stringify(boards, null, 2) }] };
1267
+ });
1268
+ server.tool("create_board", "Create a new kanban board.", {
1269
+ id: import_zod.z.string().describe("Board ID (used in directory name)"),
1270
+ name: import_zod.z.string().describe("Display name"),
1271
+ description: import_zod.z.string().optional().describe("Board description"),
1272
+ columns: import_zod.z.array(import_zod.z.object({ id: import_zod.z.string(), name: import_zod.z.string(), color: import_zod.z.string() })).optional().describe("Board columns (defaults to standard columns)")
1273
+ }, async ({ id, name, description, columns }) => {
1274
+ try {
1275
+ const board = sdk.createBoard(id, name, { description, columns });
1276
+ return { content: [{ type: "text", text: JSON.stringify(board, null, 2) }] };
1277
+ } catch (err) {
1278
+ return { content: [{ type: "text", text: String(err) }], isError: true };
1279
+ }
1280
+ });
1281
+ server.tool("get_board", "Get details of a specific board.", {
1282
+ boardId: import_zod.z.string().describe("Board ID")
1283
+ }, async ({ boardId }) => {
1284
+ try {
1285
+ const board = sdk.getBoard(boardId);
1286
+ return { content: [{ type: "text", text: JSON.stringify({ id: boardId, ...board }, null, 2) }] };
1287
+ } catch (err) {
1288
+ return { content: [{ type: "text", text: String(err) }], isError: true };
1289
+ }
1290
+ });
1291
+ server.tool("delete_board", "Delete an empty kanban board.", {
1292
+ boardId: import_zod.z.string().describe("Board ID to delete")
1293
+ }, async ({ boardId }) => {
1294
+ try {
1295
+ await sdk.deleteBoard(boardId);
1296
+ return { content: [{ type: "text", text: `Deleted board: ${boardId}` }] };
1297
+ } catch (err) {
1298
+ return { content: [{ type: "text", text: String(err) }], isError: true };
1299
+ }
1300
+ });
1301
+ server.tool("transfer_card", "Transfer a card from one board to another.", {
1302
+ cardId: import_zod.z.string().describe("Card ID"),
1303
+ fromBoard: import_zod.z.string().describe("Source board ID"),
1304
+ toBoard: import_zod.z.string().describe("Target board ID"),
1305
+ targetStatus: import_zod.z.string().optional().describe("Status in the target board (defaults to board default)")
1306
+ }, async ({ cardId, fromBoard, toBoard, targetStatus }) => {
1307
+ try {
1308
+ const card = await sdk.transferCard(cardId, fromBoard, toBoard, targetStatus);
1309
+ return { content: [{ type: "text", text: JSON.stringify(card, null, 2) }] };
1310
+ } catch (err) {
1311
+ return { content: [{ type: "text", text: String(err) }], isError: true };
1312
+ }
1313
+ });
972
1314
  server.tool(
973
1315
  "list_cards",
974
1316
  "List all kanban cards. Optionally filter by status, priority, assignee, or label.",
975
1317
  {
976
- status: import_zod.z.enum(["backlog", "todo", "in-progress", "review", "done"]).optional().describe("Filter by status"),
1318
+ boardId: import_zod.z.string().optional().describe("Board ID (uses default board if omitted)"),
1319
+ status: import_zod.z.string().optional().describe("Filter by status"),
977
1320
  priority: import_zod.z.enum(["critical", "high", "medium", "low"]).optional().describe("Filter by priority"),
978
1321
  assignee: import_zod.z.string().optional().describe("Filter by assignee name"),
979
1322
  label: import_zod.z.string().optional().describe("Filter by label")
980
1323
  },
981
- async ({ status, priority, assignee, label }) => {
982
- let cards = await sdk.listCards();
1324
+ async ({ boardId, status, priority, assignee, label }) => {
1325
+ let cards = await sdk.listCards(void 0, boardId);
983
1326
  if (status)
984
1327
  cards = cards.filter((c) => c.status === status);
985
1328
  if (priority)
@@ -1009,12 +1352,13 @@ async function main() {
1009
1352
  "get_card",
1010
1353
  "Get full details of a specific kanban card by ID. Supports partial ID matching.",
1011
1354
  {
1355
+ boardId: import_zod.z.string().optional().describe("Board ID (uses default board if omitted)"),
1012
1356
  cardId: import_zod.z.string().describe("Card ID (or partial ID)")
1013
1357
  },
1014
- async ({ cardId }) => {
1015
- let card = await sdk.getCard(cardId);
1358
+ async ({ boardId, cardId }) => {
1359
+ let card = await sdk.getCard(cardId, boardId);
1016
1360
  if (!card) {
1017
- const all = await sdk.listCards();
1361
+ const all = await sdk.listCards(void 0, boardId);
1018
1362
  const matches = all.filter((c) => c.id.includes(cardId));
1019
1363
  if (matches.length === 1) {
1020
1364
  card = matches[0];
@@ -1042,23 +1386,25 @@ async function main() {
1042
1386
  "create_card",
1043
1387
  "Create a new kanban card. Returns the created card.",
1044
1388
  {
1389
+ boardId: import_zod.z.string().optional().describe("Board ID (uses default board if omitted)"),
1045
1390
  title: import_zod.z.string().describe("Card title"),
1046
1391
  body: import_zod.z.string().optional().describe("Card body/description (markdown)"),
1047
- status: import_zod.z.enum(["backlog", "todo", "in-progress", "review", "done"]).optional().describe("Initial status (default: backlog)"),
1392
+ status: import_zod.z.string().optional().describe("Initial status (default: backlog)"),
1048
1393
  priority: import_zod.z.enum(["critical", "high", "medium", "low"]).optional().describe("Priority level (default: medium)"),
1049
1394
  assignee: import_zod.z.string().optional().describe("Assignee name"),
1050
1395
  dueDate: import_zod.z.string().optional().describe("Due date (ISO format or YYYY-MM-DD)"),
1051
1396
  labels: import_zod.z.array(import_zod.z.string()).optional().describe("Labels/tags")
1052
1397
  },
1053
- async ({ title, body, status, priority, assignee, dueDate, labels }) => {
1398
+ async ({ boardId, title, body, status, priority, assignee, dueDate, labels }) => {
1054
1399
  const content = `# ${title}${body ? "\n\n" + body : ""}`;
1055
1400
  const card = await sdk.createCard({
1056
1401
  content,
1057
- status,
1402
+ status: status || void 0,
1058
1403
  priority,
1059
1404
  assignee: assignee || null,
1060
1405
  dueDate: dueDate || null,
1061
- labels: labels || []
1406
+ labels: labels || [],
1407
+ boardId
1062
1408
  });
1063
1409
  return {
1064
1410
  content: [{
@@ -1072,19 +1418,20 @@ async function main() {
1072
1418
  "update_card",
1073
1419
  "Update fields of an existing kanban card. Only specified fields are changed.",
1074
1420
  {
1421
+ boardId: import_zod.z.string().optional().describe("Board ID (uses default board if omitted)"),
1075
1422
  cardId: import_zod.z.string().describe("Card ID (or partial ID)"),
1076
- status: import_zod.z.enum(["backlog", "todo", "in-progress", "review", "done"]).optional().describe("New status"),
1423
+ status: import_zod.z.string().optional().describe("New status"),
1077
1424
  priority: import_zod.z.enum(["critical", "high", "medium", "low"]).optional().describe("New priority"),
1078
1425
  assignee: import_zod.z.string().optional().describe("New assignee"),
1079
1426
  dueDate: import_zod.z.string().optional().describe("New due date"),
1080
1427
  labels: import_zod.z.array(import_zod.z.string()).optional().describe("New labels (replaces existing)"),
1081
1428
  content: import_zod.z.string().optional().describe("New markdown content (replaces existing body)")
1082
1429
  },
1083
- async ({ cardId, status, priority, assignee, dueDate, labels, content }) => {
1430
+ async ({ boardId, cardId, status, priority, assignee, dueDate, labels, content }) => {
1084
1431
  let resolvedId = cardId;
1085
- const card = await sdk.getCard(cardId);
1432
+ const card = await sdk.getCard(cardId, boardId);
1086
1433
  if (!card) {
1087
- const all = await sdk.listCards();
1434
+ const all = await sdk.listCards(void 0, boardId);
1088
1435
  const matches = all.filter((c) => c.id.includes(cardId));
1089
1436
  if (matches.length === 1) {
1090
1437
  resolvedId = matches[0].id;
@@ -1113,7 +1460,7 @@ async function main() {
1113
1460
  updates.labels = labels;
1114
1461
  if (content !== void 0)
1115
1462
  updates.content = content;
1116
- const updated = await sdk.updateCard(resolvedId, updates);
1463
+ const updated = await sdk.updateCard(resolvedId, updates, boardId);
1117
1464
  return {
1118
1465
  content: [{
1119
1466
  type: "text",
@@ -1126,14 +1473,15 @@ async function main() {
1126
1473
  "move_card",
1127
1474
  "Move a kanban card to a different status column.",
1128
1475
  {
1476
+ boardId: import_zod.z.string().optional().describe("Board ID (uses default board if omitted)"),
1129
1477
  cardId: import_zod.z.string().describe("Card ID (or partial ID)"),
1130
- status: import_zod.z.enum(["backlog", "todo", "in-progress", "review", "done"]).describe("Target status column")
1478
+ status: import_zod.z.string().describe("Target status column")
1131
1479
  },
1132
- async ({ cardId, status }) => {
1480
+ async ({ boardId, cardId, status }) => {
1133
1481
  let resolvedId = cardId;
1134
- const card = await sdk.getCard(cardId);
1482
+ const card = await sdk.getCard(cardId, boardId);
1135
1483
  if (!card) {
1136
- const all = await sdk.listCards();
1484
+ const all = await sdk.listCards(void 0, boardId);
1137
1485
  const matches = all.filter((c) => c.id.includes(cardId));
1138
1486
  if (matches.length === 1) {
1139
1487
  resolvedId = matches[0].id;
@@ -1149,7 +1497,7 @@ async function main() {
1149
1497
  };
1150
1498
  }
1151
1499
  }
1152
- const updated = await sdk.moveCard(resolvedId, status);
1500
+ const updated = await sdk.moveCard(resolvedId, status, void 0, boardId);
1153
1501
  return {
1154
1502
  content: [{
1155
1503
  type: "text",
@@ -1162,13 +1510,14 @@ async function main() {
1162
1510
  "delete_card",
1163
1511
  "Permanently delete a kanban card.",
1164
1512
  {
1513
+ boardId: import_zod.z.string().optional().describe("Board ID (uses default board if omitted)"),
1165
1514
  cardId: import_zod.z.string().describe("Card ID (or partial ID)")
1166
1515
  },
1167
- async ({ cardId }) => {
1516
+ async ({ boardId, cardId }) => {
1168
1517
  let resolvedId = cardId;
1169
- const card = await sdk.getCard(cardId);
1518
+ const card = await sdk.getCard(cardId, boardId);
1170
1519
  if (!card) {
1171
- const all = await sdk.listCards();
1520
+ const all = await sdk.listCards(void 0, boardId);
1172
1521
  const matches = all.filter((c) => c.id.includes(cardId));
1173
1522
  if (matches.length === 1) {
1174
1523
  resolvedId = matches[0].id;
@@ -1184,7 +1533,7 @@ async function main() {
1184
1533
  };
1185
1534
  }
1186
1535
  }
1187
- await sdk.deleteCard(resolvedId);
1536
+ await sdk.deleteCard(resolvedId, boardId);
1188
1537
  return {
1189
1538
  content: [{
1190
1539
  type: "text",
@@ -1197,13 +1546,14 @@ async function main() {
1197
1546
  "list_attachments",
1198
1547
  "List all attachments on a kanban card.",
1199
1548
  {
1549
+ boardId: import_zod.z.string().optional().describe("Board ID (uses default board if omitted)"),
1200
1550
  cardId: import_zod.z.string().describe("Card ID (or partial ID)")
1201
1551
  },
1202
- async ({ cardId }) => {
1552
+ async ({ boardId, cardId }) => {
1203
1553
  let resolvedId = cardId;
1204
- const card = await sdk.getCard(cardId);
1554
+ const card = await sdk.getCard(cardId, boardId);
1205
1555
  if (!card) {
1206
- const all = await sdk.listCards();
1556
+ const all = await sdk.listCards(void 0, boardId);
1207
1557
  const matches = all.filter((c) => c.id.includes(cardId));
1208
1558
  if (matches.length === 1) {
1209
1559
  resolvedId = matches[0].id;
@@ -1219,7 +1569,7 @@ async function main() {
1219
1569
  };
1220
1570
  }
1221
1571
  }
1222
- const attachments = await sdk.listAttachments(resolvedId);
1572
+ const attachments = await sdk.listAttachments(resolvedId, boardId);
1223
1573
  return {
1224
1574
  content: [{
1225
1575
  type: "text",
@@ -1232,14 +1582,15 @@ async function main() {
1232
1582
  "add_attachment",
1233
1583
  "Add a file attachment to a kanban card. Copies the file to the card directory.",
1234
1584
  {
1585
+ boardId: import_zod.z.string().optional().describe("Board ID (uses default board if omitted)"),
1235
1586
  cardId: import_zod.z.string().describe("Card ID (or partial ID)"),
1236
1587
  filePath: import_zod.z.string().describe("Absolute path to the file to attach")
1237
1588
  },
1238
- async ({ cardId, filePath }) => {
1589
+ async ({ boardId, cardId, filePath }) => {
1239
1590
  let resolvedId = cardId;
1240
- const card = await sdk.getCard(cardId);
1591
+ const card = await sdk.getCard(cardId, boardId);
1241
1592
  if (!card) {
1242
- const all = await sdk.listCards();
1593
+ const all = await sdk.listCards(void 0, boardId);
1243
1594
  const matches = all.filter((c) => c.id.includes(cardId));
1244
1595
  if (matches.length === 1) {
1245
1596
  resolvedId = matches[0].id;
@@ -1255,7 +1606,7 @@ async function main() {
1255
1606
  };
1256
1607
  }
1257
1608
  }
1258
- const updated = await sdk.addAttachment(resolvedId, filePath);
1609
+ const updated = await sdk.addAttachment(resolvedId, filePath, boardId);
1259
1610
  return {
1260
1611
  content: [{
1261
1612
  type: "text",
@@ -1268,14 +1619,15 @@ async function main() {
1268
1619
  "remove_attachment",
1269
1620
  "Remove an attachment from a kanban card. Only removes the reference, not the file.",
1270
1621
  {
1622
+ boardId: import_zod.z.string().optional().describe("Board ID (uses default board if omitted)"),
1271
1623
  cardId: import_zod.z.string().describe("Card ID (or partial ID)"),
1272
1624
  attachment: import_zod.z.string().describe("Attachment filename to remove")
1273
1625
  },
1274
- async ({ cardId, attachment }) => {
1626
+ async ({ boardId, cardId, attachment }) => {
1275
1627
  let resolvedId = cardId;
1276
- const card = await sdk.getCard(cardId);
1628
+ const card = await sdk.getCard(cardId, boardId);
1277
1629
  if (!card) {
1278
- const all = await sdk.listCards();
1630
+ const all = await sdk.listCards(void 0, boardId);
1279
1631
  const matches = all.filter((c) => c.id.includes(cardId));
1280
1632
  if (matches.length === 1) {
1281
1633
  resolvedId = matches[0].id;
@@ -1291,7 +1643,7 @@ async function main() {
1291
1643
  };
1292
1644
  }
1293
1645
  }
1294
- const updated = await sdk.removeAttachment(resolvedId, attachment);
1646
+ const updated = await sdk.removeAttachment(resolvedId, attachment, boardId);
1295
1647
  return {
1296
1648
  content: [{
1297
1649
  type: "text",
@@ -1304,13 +1656,14 @@ async function main() {
1304
1656
  "list_comments",
1305
1657
  "List all comments on a kanban card.",
1306
1658
  {
1659
+ boardId: import_zod.z.string().optional().describe("Board ID (uses default board if omitted)"),
1307
1660
  cardId: import_zod.z.string().describe("Card ID (or partial ID)")
1308
1661
  },
1309
- async ({ cardId }) => {
1662
+ async ({ boardId, cardId }) => {
1310
1663
  let resolvedId = cardId;
1311
- const card = await sdk.getCard(cardId);
1664
+ const card = await sdk.getCard(cardId, boardId);
1312
1665
  if (!card) {
1313
- const all = await sdk.listCards();
1666
+ const all = await sdk.listCards(void 0, boardId);
1314
1667
  const matches = all.filter((c) => c.id.includes(cardId));
1315
1668
  if (matches.length === 1) {
1316
1669
  resolvedId = matches[0].id;
@@ -1326,7 +1679,7 @@ async function main() {
1326
1679
  };
1327
1680
  }
1328
1681
  }
1329
- const comments = await sdk.listComments(resolvedId);
1682
+ const comments = await sdk.listComments(resolvedId, boardId);
1330
1683
  return {
1331
1684
  content: [{
1332
1685
  type: "text",
@@ -1339,15 +1692,16 @@ async function main() {
1339
1692
  "add_comment",
1340
1693
  "Add a comment to a kanban card.",
1341
1694
  {
1695
+ boardId: import_zod.z.string().optional().describe("Board ID (uses default board if omitted)"),
1342
1696
  cardId: import_zod.z.string().describe("Card ID (or partial ID)"),
1343
1697
  author: import_zod.z.string().describe("Comment author name"),
1344
1698
  content: import_zod.z.string().describe("Comment text (supports markdown)")
1345
1699
  },
1346
- async ({ cardId, author, content }) => {
1700
+ async ({ boardId, cardId, author, content }) => {
1347
1701
  let resolvedId = cardId;
1348
- const card = await sdk.getCard(cardId);
1702
+ const card = await sdk.getCard(cardId, boardId);
1349
1703
  if (!card) {
1350
- const all = await sdk.listCards();
1704
+ const all = await sdk.listCards(void 0, boardId);
1351
1705
  const matches = all.filter((c) => c.id.includes(cardId));
1352
1706
  if (matches.length === 1) {
1353
1707
  resolvedId = matches[0].id;
@@ -1363,7 +1717,7 @@ async function main() {
1363
1717
  };
1364
1718
  }
1365
1719
  }
1366
- const updated = await sdk.addComment(resolvedId, author, content);
1720
+ const updated = await sdk.addComment(resolvedId, author, content, boardId);
1367
1721
  const added = updated.comments[updated.comments.length - 1];
1368
1722
  return {
1369
1723
  content: [{
@@ -1377,15 +1731,16 @@ async function main() {
1377
1731
  "update_comment",
1378
1732
  "Update the content of a comment on a kanban card.",
1379
1733
  {
1734
+ boardId: import_zod.z.string().optional().describe("Board ID (uses default board if omitted)"),
1380
1735
  cardId: import_zod.z.string().describe("Card ID (or partial ID)"),
1381
1736
  commentId: import_zod.z.string().describe('Comment ID (e.g. "c1")'),
1382
1737
  content: import_zod.z.string().describe("New comment text")
1383
1738
  },
1384
- async ({ cardId, commentId, content }) => {
1739
+ async ({ boardId, cardId, commentId, content }) => {
1385
1740
  let resolvedId = cardId;
1386
- const card = await sdk.getCard(cardId);
1741
+ const card = await sdk.getCard(cardId, boardId);
1387
1742
  if (!card) {
1388
- const all = await sdk.listCards();
1743
+ const all = await sdk.listCards(void 0, boardId);
1389
1744
  const matches = all.filter((c) => c.id.includes(cardId));
1390
1745
  if (matches.length === 1) {
1391
1746
  resolvedId = matches[0].id;
@@ -1402,7 +1757,7 @@ async function main() {
1402
1757
  }
1403
1758
  }
1404
1759
  try {
1405
- const updated = await sdk.updateComment(resolvedId, commentId, content);
1760
+ const updated = await sdk.updateComment(resolvedId, commentId, content, boardId);
1406
1761
  const comment = updated.comments.find((c) => c.id === commentId);
1407
1762
  return {
1408
1763
  content: [{
@@ -1422,14 +1777,15 @@ async function main() {
1422
1777
  "delete_comment",
1423
1778
  "Delete a comment from a kanban card.",
1424
1779
  {
1780
+ boardId: import_zod.z.string().optional().describe("Board ID (uses default board if omitted)"),
1425
1781
  cardId: import_zod.z.string().describe("Card ID (or partial ID)"),
1426
1782
  commentId: import_zod.z.string().describe('Comment ID (e.g. "c1")')
1427
1783
  },
1428
- async ({ cardId, commentId }) => {
1784
+ async ({ boardId, cardId, commentId }) => {
1429
1785
  let resolvedId = cardId;
1430
- const card = await sdk.getCard(cardId);
1786
+ const card = await sdk.getCard(cardId, boardId);
1431
1787
  if (!card) {
1432
- const all = await sdk.listCards();
1788
+ const all = await sdk.listCards(void 0, boardId);
1433
1789
  const matches = all.filter((c) => c.id.includes(cardId));
1434
1790
  if (matches.length === 1) {
1435
1791
  resolvedId = matches[0].id;
@@ -1446,7 +1802,7 @@ async function main() {
1446
1802
  }
1447
1803
  }
1448
1804
  try {
1449
- await sdk.deleteComment(resolvedId, commentId);
1805
+ await sdk.deleteComment(resolvedId, commentId, boardId);
1450
1806
  return {
1451
1807
  content: [{
1452
1808
  type: "text",
@@ -1464,9 +1820,11 @@ async function main() {
1464
1820
  server.tool(
1465
1821
  "list_columns",
1466
1822
  "List all kanban board columns.",
1467
- {},
1468
- async () => {
1469
- const columns = await sdk.listColumns();
1823
+ {
1824
+ boardId: import_zod.z.string().optional().describe("Board ID (uses default board if omitted)")
1825
+ },
1826
+ async ({ boardId }) => {
1827
+ const columns = await sdk.listColumns(boardId);
1470
1828
  return {
1471
1829
  content: [{
1472
1830
  type: "text",
@@ -1479,12 +1837,13 @@ async function main() {
1479
1837
  "add_column",
1480
1838
  "Add a new column to the kanban board.",
1481
1839
  {
1840
+ boardId: import_zod.z.string().optional().describe("Board ID (uses default board if omitted)"),
1482
1841
  id: import_zod.z.string().describe("Unique column ID (used in card status field)"),
1483
1842
  name: import_zod.z.string().describe("Display name for the column"),
1484
1843
  color: import_zod.z.string().describe('Column color (hex format, e.g. "#3b82f6")')
1485
1844
  },
1486
- async ({ id, name, color }) => {
1487
- const columns = await sdk.addColumn({ id, name, color });
1845
+ async ({ boardId, id, name, color }) => {
1846
+ const columns = await sdk.addColumn({ id, name, color }, boardId);
1488
1847
  return {
1489
1848
  content: [{
1490
1849
  type: "text",
@@ -1497,17 +1856,18 @@ async function main() {
1497
1856
  "update_column",
1498
1857
  "Update an existing kanban board column.",
1499
1858
  {
1859
+ boardId: import_zod.z.string().optional().describe("Board ID (uses default board if omitted)"),
1500
1860
  columnId: import_zod.z.string().describe("Column ID to update"),
1501
1861
  name: import_zod.z.string().optional().describe("New display name"),
1502
1862
  color: import_zod.z.string().optional().describe("New color (hex format)")
1503
1863
  },
1504
- async ({ columnId, name, color }) => {
1864
+ async ({ boardId, columnId, name, color }) => {
1505
1865
  const updates = {};
1506
1866
  if (name)
1507
1867
  updates.name = name;
1508
1868
  if (color)
1509
1869
  updates.color = color;
1510
- const columns = await sdk.updateColumn(columnId, updates);
1870
+ const columns = await sdk.updateColumn(columnId, updates, boardId);
1511
1871
  return {
1512
1872
  content: [{
1513
1873
  type: "text",
@@ -1520,10 +1880,11 @@ async function main() {
1520
1880
  "remove_column",
1521
1881
  "Remove a column from the kanban board. Fails if any cards are in the column.",
1522
1882
  {
1883
+ boardId: import_zod.z.string().optional().describe("Board ID (uses default board if omitted)"),
1523
1884
  columnId: import_zod.z.string().describe("Column ID to remove")
1524
1885
  },
1525
- async ({ columnId }) => {
1526
- const columns = await sdk.removeColumn(columnId);
1886
+ async ({ boardId, columnId }) => {
1887
+ const columns = await sdk.removeColumn(columnId, boardId);
1527
1888
  return {
1528
1889
  content: [{
1529
1890
  type: "text",
@@ -1532,7 +1893,7 @@ async function main() {
1532
1893
  };
1533
1894
  }
1534
1895
  );
1535
- const workspaceRoot = path6.dirname(featuresDir);
1896
+ const workspaceRoot = path7.dirname(featuresDir);
1536
1897
  server.tool(
1537
1898
  "get_settings",
1538
1899
  "Get the current kanban board display settings.",
@@ -1559,7 +1920,7 @@ async function main() {
1559
1920
  showFileName: import_zod.z.boolean().optional().describe("Show file name on cards"),
1560
1921
  compactMode: import_zod.z.boolean().optional().describe("Enable compact card display"),
1561
1922
  defaultPriority: import_zod.z.enum(["critical", "high", "medium", "low"]).optional().describe("Default priority for new cards"),
1562
- defaultStatus: import_zod.z.enum(["backlog", "todo", "in-progress", "review", "done"]).optional().describe("Default status for new cards")
1923
+ defaultStatus: import_zod.z.string().optional().describe("Default status for new cards")
1563
1924
  },
1564
1925
  async (updates) => {
1565
1926
  const config = readConfig(workspaceRoot);