kanban-lite 1.0.41 → 1.0.44

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 (46) hide show
  1. package/.vscodeignore +21 -0
  2. package/dist/cli.js +78 -39
  3. package/dist/extension.js +70 -32
  4. package/dist/mcp-server.js +55 -16
  5. package/dist/sdk/index.cjs +51 -12
  6. package/dist/sdk/index.mjs +49 -10
  7. package/dist/sdk/sdk/KanbanSDK.d.ts +14 -3
  8. package/dist/sdk/sdk/fileUtils.d.ts +18 -0
  9. package/dist/standalone-webview/{icons-r7GgGAg-.js → icons-BQC9f0h7.js} +76 -46
  10. package/dist/standalone-webview/icons-BQC9f0h7.js.map +1 -0
  11. package/dist/standalone-webview/index.js +49 -49
  12. package/dist/standalone-webview/index.js.map +1 -1
  13. package/dist/{webview/react-vendor-DAFGO9PR.js → standalone-webview/react-vendor-CXl8NHLV.js} +2 -2
  14. package/dist/{webview/react-vendor-DAFGO9PR.js.map → standalone-webview/react-vendor-CXl8NHLV.js.map} +1 -1
  15. package/dist/standalone-webview/style.css +1 -1
  16. package/dist/standalone.js +1498 -1189
  17. package/dist/webview/{icons-r7GgGAg-.js → icons-BQC9f0h7.js} +76 -46
  18. package/dist/webview/icons-BQC9f0h7.js.map +1 -0
  19. package/dist/webview/index.js +60 -60
  20. package/dist/webview/index.js.map +1 -1
  21. package/dist/{standalone-webview/react-vendor-DAFGO9PR.js → webview/react-vendor-CXl8NHLV.js} +2 -2
  22. package/dist/{standalone-webview/react-vendor-DAFGO9PR.js.map → webview/react-vendor-CXl8NHLV.js.map} +1 -1
  23. package/dist/webview/style.css +1 -1
  24. package/package.json +5 -5
  25. package/src/extension/KanbanPanel.ts +8 -10
  26. package/src/sdk/KanbanSDK.ts +18 -3
  27. package/src/sdk/fileUtils.ts +49 -0
  28. package/src/shared/config.ts +2 -2
  29. package/src/standalone/server.ts +4 -2
  30. package/src/webview/App.tsx +58 -27
  31. package/src/webview/components/BoardSwitcher.tsx +145 -0
  32. package/src/webview/components/CardEditor.tsx +55 -28
  33. package/src/webview/components/CardItem.tsx +5 -5
  34. package/src/webview/components/CreateCardDialog.tsx +14 -14
  35. package/src/webview/components/KanbanBoard.tsx +14 -2
  36. package/src/webview/components/KanbanColumn.tsx +26 -5
  37. package/src/webview/components/SettingsPanel.tsx +43 -26
  38. package/src/webview/components/ShortcutHelp.tsx +127 -0
  39. package/src/webview/components/Toolbar.tsx +367 -96
  40. package/src/webview/router.tsx +3 -3
  41. package/src/webview/standalone-shim.ts +5 -0
  42. package/src/webview/store/index.ts +45 -0
  43. package/src/webview/vsCodeApi.ts +17 -0
  44. package/vite.standalone.config.ts +2 -2
  45. package/dist/standalone-webview/icons-r7GgGAg-.js.map +0 -1
  46. package/dist/webview/icons-r7GgGAg-.js.map +0 -1
package/.vscodeignore CHANGED
@@ -1,13 +1,34 @@
1
1
  .vscode/**
2
2
  .git/**
3
+ .github/**
4
+ .agents/**
5
+ .claude/**
6
+ .devtool/**
7
+ .kanban/**
3
8
  node_modules/**
4
9
  lib/**
5
10
  bin/**
6
11
  src/**
12
+ tmp/**
13
+ releases/**
14
+ docs/**
15
+ scripts/**
7
16
  *.map
8
17
  .gitignore
9
18
  pnpm-lock.yaml
10
19
  tsconfig.json
11
20
  vite.config.ts
12
21
  eslint.config.mjs
22
+ vite.standalone.config.ts
23
+ vitest.config.ts
24
+ postcss.config.js
25
+ AGENTS.md
26
+ SKILL.md
27
+ CONTRIBUTING.md
28
+ skills-lock.json
13
29
  README.md
30
+ dist/standalone.js
31
+ dist/webview/**
32
+ dist/cli.js
33
+ dist/mcp-server.js
34
+ dist/sdk/**
package/dist/cli.js CHANGED
@@ -118,7 +118,7 @@ function migrateConfigV1ToV2(raw) {
118
118
  showDeletedColumn: false,
119
119
  boardZoom: 100,
120
120
  cardZoom: 100,
121
- port: 3e3
121
+ port: 2954
122
122
  };
123
123
  }
124
124
  function readConfig(workspaceRoot) {
@@ -249,7 +249,7 @@ var init_config = __esm({
249
249
  showDeletedColumn: false,
250
250
  boardZoom: 100,
251
251
  cardZoom: 100,
252
- port: 3e3,
252
+ port: 2954,
253
253
  labels: {}
254
254
  };
255
255
  CONFIG_FILENAME = ".kanban.json";
@@ -261,11 +261,39 @@ var fileUtils_exports = {};
261
261
  __export(fileUtils_exports, {
262
262
  ensureDirectories: () => ensureDirectories,
263
263
  ensureStatusSubfolders: () => ensureStatusSubfolders,
264
+ findWorkspaceRootSync: () => findWorkspaceRootSync,
264
265
  getCardFilePath: () => getCardFilePath,
265
266
  getStatusFromPath: () => getStatusFromPath,
266
267
  moveCardFile: () => moveCardFile,
267
- renameCardFile: () => renameCardFile
268
+ renameCardFile: () => renameCardFile,
269
+ resolveKanbanDir: () => resolveKanbanDir
268
270
  });
271
+ function findWorkspaceRootSync(startDir) {
272
+ let dir = startDir;
273
+ while (true) {
274
+ if (fsSync.existsSync(path2.join(dir, ".git")) || fsSync.existsSync(path2.join(dir, "package.json")) || fsSync.existsSync(path2.join(dir, ".kanban.json"))) {
275
+ return dir;
276
+ }
277
+ const parent = path2.dirname(dir);
278
+ if (parent === dir)
279
+ return startDir;
280
+ dir = parent;
281
+ }
282
+ }
283
+ function resolveKanbanDir(startDir) {
284
+ const root = findWorkspaceRootSync(startDir ?? process.cwd());
285
+ const configFile = path2.join(root, ".kanban.json");
286
+ if (fsSync.existsSync(configFile)) {
287
+ try {
288
+ const raw = JSON.parse(fsSync.readFileSync(configFile, "utf-8"));
289
+ if (typeof raw.kanbanDirectory === "string") {
290
+ return path2.resolve(root, raw.kanbanDirectory);
291
+ }
292
+ } catch {
293
+ }
294
+ }
295
+ return path2.join(root, ".kanban");
296
+ }
269
297
  function getCardFilePath(kanbanDir, status, filename) {
270
298
  return path2.join(kanbanDir, status, `${filename}.md`);
271
299
  }
@@ -333,12 +361,13 @@ async function fileExists(filePath) {
333
361
  return false;
334
362
  }
335
363
  }
336
- var path2, fs2;
364
+ var path2, fs2, fsSync;
337
365
  var init_fileUtils = __esm({
338
366
  "src/sdk/fileUtils.ts"() {
339
367
  "use strict";
340
368
  path2 = __toESM(require("path"));
341
369
  fs2 = __toESM(require("fs/promises"));
370
+ fsSync = __toESM(require("fs"));
342
371
  }
343
372
  });
344
373
 
@@ -3753,13 +3782,13 @@ var require_backup = __commonJS({
3753
3782
  var runBackup = (backup, handler) => {
3754
3783
  let rate = 0;
3755
3784
  let useDefault = true;
3756
- return new Promise((resolve9, reject) => {
3785
+ return new Promise((resolve10, reject) => {
3757
3786
  setImmediate(function step() {
3758
3787
  try {
3759
3788
  const progress = backup.transfer(rate);
3760
3789
  if (!progress.remainingPages) {
3761
3790
  backup.close();
3762
- resolve9(progress);
3791
+ resolve10(progress);
3763
3792
  return;
3764
3793
  }
3765
3794
  if (useDefault) {
@@ -4171,12 +4200,12 @@ var sqlite_exports = {};
4171
4200
  __export(sqlite_exports, {
4172
4201
  SqliteStorageEngine: () => SqliteStorageEngine
4173
4202
  });
4174
- var fs5, fsSync, path6, import_better_sqlite3, SCHEMA_VERSION, CREATE_SCHEMA_SQL, SqliteStorageEngine;
4203
+ var fs5, fsSync2, path6, import_better_sqlite3, SCHEMA_VERSION, CREATE_SCHEMA_SQL, SqliteStorageEngine;
4175
4204
  var init_sqlite = __esm({
4176
4205
  "src/sdk/storage/sqlite.ts"() {
4177
4206
  "use strict";
4178
4207
  fs5 = __toESM(require("fs/promises"));
4179
- fsSync = __toESM(require("fs"));
4208
+ fsSync2 = __toESM(require("fs"));
4180
4209
  path6 = __toESM(require("path"));
4181
4210
  import_better_sqlite3 = __toESM(require_lib());
4182
4211
  init_types();
@@ -4266,7 +4295,7 @@ CREATE INDEX IF NOT EXISTS idx_comments_card ON comments (card_id, board_i
4266
4295
  /** Lazily opens (or returns the already-open) database connection. */
4267
4296
  get db() {
4268
4297
  if (!this._db) {
4269
- fsSync.mkdirSync(path6.dirname(this.dbPath), { recursive: true });
4298
+ fsSync2.mkdirSync(path6.dirname(this.dbPath), { recursive: true });
4270
4299
  this._db = new import_better_sqlite3.default(this.dbPath);
4271
4300
  this._db.pragma("journal_mode = WAL");
4272
4301
  this._db.pragma("foreign_keys = ON");
@@ -4707,7 +4736,7 @@ async function deliverWebhook(webhook, event, payload) {
4707
4736
  const signature = crypto.createHmac("sha256", webhook.secret).update(payload).digest("hex");
4708
4737
  headers["X-Webhook-Signature"] = `sha256=${signature}`;
4709
4738
  }
4710
- return new Promise((resolve9, reject) => {
4739
+ return new Promise((resolve10, reject) => {
4711
4740
  const req = transport.request(
4712
4741
  {
4713
4742
  hostname: url3.hostname,
@@ -4720,7 +4749,7 @@ async function deliverWebhook(webhook, event, payload) {
4720
4749
  (res) => {
4721
4750
  res.resume();
4722
4751
  if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
4723
- resolve9();
4752
+ resolve10();
4724
4753
  } else {
4725
4754
  reject(new Error(`HTTP ${res.statusCode}`));
4726
4755
  }
@@ -5992,6 +6021,7 @@ var init_KanbanSDK = __esm({
5992
6021
  init_config();
5993
6022
  init_storage();
5994
6023
  init_webhooks();
6024
+ init_fileUtils();
5995
6025
  init_boards();
5996
6026
  init_cards();
5997
6027
  init_labels();
@@ -6006,12 +6036,19 @@ var init_KanbanSDK = __esm({
6006
6036
  * Creates a new KanbanSDK instance.
6007
6037
  *
6008
6038
  * @param kanbanDir - Absolute path to the `.kanban` kanban directory.
6009
- * The parent of this directory is treated as the workspace root.
6039
+ * When omitted, the directory is auto-detected by walking up from
6040
+ * `process.cwd()` to find the workspace root (via `.git`, `package.json`,
6041
+ * or `.kanban.json`), then reading `kanbanDirectory` from `.kanban.json`
6042
+ * (defaults to `'.kanban'`).
6010
6043
  * @param options - Optional configuration including an event handler callback
6011
6044
  * and storage engine selection.
6012
6045
  *
6013
6046
  * @example
6014
6047
  * ```ts
6048
+ * // Auto-detect from process.cwd()
6049
+ * const sdk = new KanbanSDK()
6050
+ *
6051
+ * // Explicit path
6015
6052
  * const sdk = new KanbanSDK('/home/user/my-project/.kanban')
6016
6053
  *
6017
6054
  * // With event handler for webhooks
@@ -6026,10 +6063,10 @@ var init_KanbanSDK = __esm({
6026
6063
  * ```
6027
6064
  */
6028
6065
  constructor(kanbanDir, options) {
6029
- this.kanbanDir = kanbanDir;
6030
6066
  this._migrated = false;
6067
+ this.kanbanDir = kanbanDir ?? resolveKanbanDir();
6031
6068
  this._onEvent = options?.onEvent;
6032
- this._storage = options?.storage ?? createStorageEngine(kanbanDir, {
6069
+ this._storage = options?.storage ?? createStorageEngine(this.kanbanDir, {
6033
6070
  storageEngine: options?.storageEngine,
6034
6071
  sqlitePath: options?.sqlitePath
6035
6072
  });
@@ -22657,7 +22694,7 @@ var init_protocol = __esm({
22657
22694
  return;
22658
22695
  }
22659
22696
  const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
22660
- await new Promise((resolve9) => setTimeout(resolve9, pollInterval));
22697
+ await new Promise((resolve10) => setTimeout(resolve10, pollInterval));
22661
22698
  options?.signal?.throwIfAborted();
22662
22699
  }
22663
22700
  } catch (error49) {
@@ -22674,7 +22711,7 @@ var init_protocol = __esm({
22674
22711
  */
22675
22712
  request(request, resultSchema, options) {
22676
22713
  const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
22677
- return new Promise((resolve9, reject) => {
22714
+ return new Promise((resolve10, reject) => {
22678
22715
  const earlyReject = (error49) => {
22679
22716
  reject(error49);
22680
22717
  };
@@ -22752,7 +22789,7 @@ var init_protocol = __esm({
22752
22789
  if (!parseResult.success) {
22753
22790
  reject(parseResult.error);
22754
22791
  } else {
22755
- resolve9(parseResult.data);
22792
+ resolve10(parseResult.data);
22756
22793
  }
22757
22794
  } catch (error49) {
22758
22795
  reject(error49);
@@ -23013,12 +23050,12 @@ var init_protocol = __esm({
23013
23050
  }
23014
23051
  } catch {
23015
23052
  }
23016
- return new Promise((resolve9, reject) => {
23053
+ return new Promise((resolve10, reject) => {
23017
23054
  if (signal.aborted) {
23018
23055
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
23019
23056
  return;
23020
23057
  }
23021
- const timeoutId = setTimeout(resolve9, interval);
23058
+ const timeoutId = setTimeout(resolve10, interval);
23022
23059
  signal.addEventListener("abort", () => {
23023
23060
  clearTimeout(timeoutId);
23024
23061
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
@@ -26055,7 +26092,7 @@ var require_compile = __commonJS({
26055
26092
  const schOrFunc = root.refs[ref];
26056
26093
  if (schOrFunc)
26057
26094
  return schOrFunc;
26058
- let _sch = resolve9.call(this, root, ref);
26095
+ let _sch = resolve10.call(this, root, ref);
26059
26096
  if (_sch === void 0) {
26060
26097
  const schema2 = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
26061
26098
  const { schemaId } = this.opts;
@@ -26082,7 +26119,7 @@ var require_compile = __commonJS({
26082
26119
  function sameSchemaEnv(s1, s2) {
26083
26120
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
26084
26121
  }
26085
- function resolve9(root, ref) {
26122
+ function resolve10(root, ref) {
26086
26123
  let sch;
26087
26124
  while (typeof (sch = this.refs[ref]) == "string")
26088
26125
  ref = sch;
@@ -26658,7 +26695,7 @@ var require_fast_uri = __commonJS({
26658
26695
  }
26659
26696
  return uri;
26660
26697
  }
26661
- function resolve9(baseURI, relativeURI, options) {
26698
+ function resolve10(baseURI, relativeURI, options) {
26662
26699
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
26663
26700
  const resolved = resolveComponent(parse5(baseURI, schemelessOptions), parse5(relativeURI, schemelessOptions), schemelessOptions, true);
26664
26701
  schemelessOptions.skipEscape = true;
@@ -26886,7 +26923,7 @@ var require_fast_uri = __commonJS({
26886
26923
  var fastUri = {
26887
26924
  SCHEMES,
26888
26925
  normalize: normalize2,
26889
- resolve: resolve9,
26926
+ resolve: resolve10,
26890
26927
  resolveComponent,
26891
26928
  equal,
26892
26929
  serialize,
@@ -30868,7 +30905,7 @@ var init_mcp = __esm({
30868
30905
  let task = createTaskResult.task;
30869
30906
  const pollInterval = task.pollInterval ?? 5e3;
30870
30907
  while (task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled") {
30871
- await new Promise((resolve9) => setTimeout(resolve9, pollInterval));
30908
+ await new Promise((resolve10) => setTimeout(resolve10, pollInterval));
30872
30909
  const updatedTask = await extra.taskStore.getTask(taskId);
30873
30910
  if (!updatedTask) {
30874
30911
  throw new McpError(ErrorCode.InternalError, `Task ${taskId} not found during polling`);
@@ -31459,12 +31496,12 @@ var init_stdio2 = __esm({
31459
31496
  this.onclose?.();
31460
31497
  }
31461
31498
  send(message) {
31462
- return new Promise((resolve9) => {
31499
+ return new Promise((resolve10) => {
31463
31500
  const json4 = serializeMessage(message);
31464
31501
  if (this._stdout.write(json4)) {
31465
- resolve9();
31502
+ resolve10();
31466
31503
  } else {
31467
- this._stdout.once("drain", resolve9);
31504
+ this._stdout.once("drain", resolve10);
31468
31505
  }
31469
31506
  });
31470
31507
  }
@@ -45807,7 +45844,7 @@ async function findWorkspaceRoot(startDir) {
45807
45844
  dir = parent;
45808
45845
  }
45809
45846
  }
45810
- async function resolveKanbanDir() {
45847
+ async function resolveKanbanDir2() {
45811
45848
  const dirIndex = process.argv.indexOf("--dir");
45812
45849
  if (dirIndex !== -1 && process.argv[dirIndex + 1]) {
45813
45850
  return path13.resolve(process.argv[dirIndex + 1]);
@@ -45820,7 +45857,7 @@ async function resolveKanbanDir() {
45820
45857
  return path13.join(root, ".kanban");
45821
45858
  }
45822
45859
  async function main() {
45823
- const kanbanDir = await resolveKanbanDir();
45860
+ const kanbanDir = await resolveKanbanDir2();
45824
45861
  const workspaceRoot = path13.dirname(kanbanDir);
45825
45862
  const sdk = new KanbanSDK(kanbanDir, {
45826
45863
  onEvent: (event, data) => fireWebhooks(workspaceRoot, event, data)
@@ -51638,7 +51675,7 @@ var init_handler = __esm({
51638
51675
  this._addToNodeFs(path17, initialAdd, wh, depth + 1);
51639
51676
  }
51640
51677
  }).on(EV.ERROR, this._boundHandleError);
51641
- return new Promise((resolve9, reject) => {
51678
+ return new Promise((resolve10, reject) => {
51642
51679
  if (!stream)
51643
51680
  return reject();
51644
51681
  stream.once(STR_END, () => {
@@ -51647,7 +51684,7 @@ var init_handler = __esm({
51647
51684
  return;
51648
51685
  }
51649
51686
  const wasThrottled = throttler ? throttler.clear() : false;
51650
- resolve9(void 0);
51687
+ resolve10(void 0);
51651
51688
  previous.getChildren().filter((item) => {
51652
51689
  return item !== directory && !current.has(item);
51653
51690
  }).forEach((item) => {
@@ -52554,13 +52591,13 @@ function startServer(kanbanDir, port, webviewDir) {
52554
52591
  });
52555
52592
  }
52556
52593
  function readBody(req) {
52557
- return new Promise((resolve9, reject) => {
52594
+ return new Promise((resolve10, reject) => {
52558
52595
  const chunks = [];
52559
52596
  req.on("data", (chunk) => chunks.push(chunk));
52560
52597
  req.on("end", () => {
52561
52598
  try {
52562
52599
  const text = Buffer.concat(chunks).toString("utf-8");
52563
- resolve9(text ? JSON.parse(text) : {});
52600
+ resolve10(text ? JSON.parse(text) : {});
52564
52601
  } catch (err) {
52565
52602
  reject(err);
52566
52603
  }
@@ -53803,6 +53840,7 @@ function startServer(kanbanDir, port, webviewDir) {
53803
53840
  }
53804
53841
  const ext2 = path14.extname(attachName);
53805
53842
  const contentType2 = MIME_TYPES[ext2] || "application/octet-stream";
53843
+ const disposition = url3.searchParams.get("download") === "1" ? "attachment" : "inline";
53806
53844
  fs9.readFile(attachmentPath, (err, data) => {
53807
53845
  if (err) {
53808
53846
  res.writeHead(404);
@@ -53811,7 +53849,7 @@ function startServer(kanbanDir, port, webviewDir) {
53811
53849
  }
53812
53850
  res.writeHead(200, {
53813
53851
  "Content-Type": contentType2,
53814
- "Content-Disposition": `inline; filename="${attachName}"`,
53852
+ "Content-Disposition": `${disposition}; filename="${attachName}"`,
53815
53853
  "Access-Control-Allow-Origin": "*"
53816
53854
  });
53817
53855
  res.end(data);
@@ -54194,13 +54232,14 @@ function startServer(kanbanDir, port, webviewDir) {
54194
54232
  }
54195
54233
  const ext2 = path14.extname(filename);
54196
54234
  const contentType2 = MIME_TYPES[ext2] || "application/octet-stream";
54235
+ const disposition = url3.searchParams.get("download") === "1" ? "attachment" : "inline";
54197
54236
  fs9.readFile(attachmentPath, (err, data) => {
54198
54237
  if (err) {
54199
54238
  res.writeHead(404, { "Content-Type": "text/plain" });
54200
54239
  res.end("File not found");
54201
54240
  return;
54202
54241
  }
54203
- res.writeHead(200, { "Content-Type": contentType2, "Content-Disposition": `inline; filename="${filename}"` });
54242
+ res.writeHead(200, { "Content-Type": contentType2, "Content-Disposition": `${disposition}; filename="${filename}"` });
54204
54243
  res.end(data);
54205
54244
  });
54206
54245
  return;
@@ -54859,14 +54898,14 @@ var init_open = __esm({
54859
54898
  }
54860
54899
  const subprocess = import_node_child_process5.default.spawn(command, cliArguments, childProcessOptions);
54861
54900
  if (options.wait) {
54862
- return new Promise((resolve9, reject) => {
54901
+ return new Promise((resolve10, reject) => {
54863
54902
  subprocess.once("error", reject);
54864
54903
  subprocess.once("close", (exitCode) => {
54865
54904
  if (!options.allowNonzeroExitCode && exitCode > 0) {
54866
54905
  reject(new Error(`Exited with code ${exitCode}`));
54867
54906
  return;
54868
54907
  }
54869
- resolve9(subprocess);
54908
+ resolve10(subprocess);
54870
54909
  });
54871
54910
  });
54872
54911
  }
@@ -55002,7 +55041,7 @@ async function findWorkspaceRoot2(startDir) {
55002
55041
  dir = parent;
55003
55042
  }
55004
55043
  }
55005
- async function resolveKanbanDir2(flags) {
55044
+ async function resolveKanbanDir3(flags) {
55006
55045
  if (typeof flags.dir === "string") {
55007
55046
  return path16.resolve(flags.dir);
55008
55047
  }
@@ -56420,7 +56459,7 @@ async function main2() {
56420
56459
  await cmdMcp(flags);
56421
56460
  return;
56422
56461
  }
56423
- const kanbanDir = await resolveKanbanDir2(flags);
56462
+ const kanbanDir = await resolveKanbanDir3(flags);
56424
56463
  const workspaceRoot = path16.dirname(kanbanDir);
56425
56464
  const sdk = new KanbanSDK(kanbanDir);
56426
56465
  switch (command) {