kanban-lite 1.0.7 → 1.0.8

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 (3) hide show
  1. package/README.md +17 -26
  2. package/docs/sdk.md +659 -0
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -344,51 +344,42 @@ kanban-mcp --dir .kanban
344
344
 
345
345
  ## SDK
346
346
 
347
- Use the kanban SDK programmatically in your own tools:
347
+ Use the kanban SDK programmatically in your own tools. The `KanbanSDK` class is the single source of truth — the CLI, MCP server, VSCode extension, and standalone server all delegate to it.
348
348
 
349
349
  ```typescript
350
350
  import { KanbanSDK } from 'kanban-lite/dist/sdk'
351
351
 
352
352
  const sdk = new KanbanSDK('/path/to/.kanban')
353
353
 
354
- // List all cards
354
+ // Cards
355
355
  const cards = await sdk.listCards()
356
-
357
- // Create a card
358
- const card = await sdk.createCard({
359
- content: '# My Card\n\nDescription here.',
360
- status: 'todo',
361
- priority: 'high',
362
- labels: ['backend']
363
- })
364
-
365
- // Move a card
366
- await sdk.moveCard('card-id', 'in-progress')
367
-
368
- // Update fields
369
- await sdk.updateCard('card-id', { assignee: 'alice' })
370
-
371
- // Delete
372
- await sdk.deleteCard('card-id')
356
+ const card = await sdk.createCard({ content: '# My Task', status: 'todo', priority: 'high' })
357
+ await sdk.moveCard(card.id, 'in-progress')
358
+ await sdk.updateCard(card.id, { assignee: 'alice' })
359
+ await sdk.deleteCard(card.id)
373
360
 
374
361
  // Comments
375
362
  await sdk.addComment('card-id', 'alice', 'Looks good!')
376
- await sdk.updateComment('card-id', 'c1', 'Updated comment')
363
+ await sdk.updateComment('card-id', 'c1', 'Updated')
377
364
  await sdk.deleteComment('card-id', 'c1')
378
- const comments = await sdk.listComments('card-id')
379
365
 
380
366
  // Attachments
381
367
  await sdk.addAttachment('card-id', '/path/to/file.png')
382
368
  await sdk.removeAttachment('card-id', 'file.png')
383
- const attachments = await sdk.listAttachments('card-id')
384
369
 
385
- // Manage columns
386
- const columns = await sdk.listColumns()
387
- await sdk.addColumn({ id: 'testing', name: 'Testing', color: '#ff9900' })
388
- await sdk.updateColumn('testing', { name: 'QA' })
370
+ // Columns
371
+ const columns = sdk.listColumns()
372
+ sdk.addColumn({ id: 'testing', name: 'Testing', color: '#ff9900' })
373
+ sdk.updateColumn('testing', { name: 'QA' })
389
374
  await sdk.removeColumn('testing')
375
+
376
+ // Settings
377
+ const settings = sdk.getSettings()
378
+ sdk.updateSettings({ ...settings, compactMode: true })
390
379
  ```
391
380
 
381
+ See the [full SDK documentation](docs/sdk.md) for detailed API reference, types, error handling, and file layout.
382
+
392
383
  ## Data Storage
393
384
 
394
385
  Cards are stored as markdown files with YAML frontmatter in `.kanban/` within your project:
package/docs/sdk.md ADDED
@@ -0,0 +1,659 @@
1
+ # Kanban Lite SDK
2
+
3
+ The `KanbanSDK` class is the core engine behind Kanban Lite. It provides a complete, async API for managing cards, comments, attachments, columns, and board settings. The CLI, MCP server, VSCode extension, and standalone web server all delegate to this single SDK — so behavior is consistent everywhere.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install kanban-lite
9
+ ```
10
+
11
+ ## Import
12
+
13
+ ```typescript
14
+ import { KanbanSDK } from 'kanban-lite/dist/sdk'
15
+ ```
16
+
17
+ You can also import types and utilities:
18
+
19
+ ```typescript
20
+ import type { Feature, FeatureStatus, Priority, KanbanColumn, CardDisplaySettings, CreateCardInput } from 'kanban-lite/dist/sdk'
21
+ import { parseFeatureFile, serializeFeature, getTitleFromContent, DEFAULT_COLUMNS } from 'kanban-lite/dist/sdk'
22
+ import { readConfig, writeConfig, configToSettings, settingsToConfig } from 'kanban-lite/dist/sdk'
23
+ ```
24
+
25
+ ## Quick Start
26
+
27
+ ```typescript
28
+ import { KanbanSDK } from 'kanban-lite/dist/sdk'
29
+
30
+ const sdk = new KanbanSDK('/path/to/project/.kanban')
31
+
32
+ // Create a card
33
+ const card = await sdk.createCard({
34
+ content: '# Implement auth\n\nAdd OAuth2 login flow.',
35
+ status: 'todo',
36
+ priority: 'high',
37
+ labels: ['backend', 'security']
38
+ })
39
+
40
+ // List all cards (sorted by order)
41
+ const cards = await sdk.listCards()
42
+
43
+ // Move card to a different column
44
+ await sdk.moveCard(card.id, 'in-progress')
45
+
46
+ // Add a comment
47
+ await sdk.addComment(card.id, 'alice', 'Started working on this')
48
+
49
+ // Clean up
50
+ await sdk.deleteCard(card.id)
51
+ ```
52
+
53
+ ## Constructor
54
+
55
+ ```typescript
56
+ new KanbanSDK(featuresDir: string)
57
+ ```
58
+
59
+ | Parameter | Type | Description |
60
+ |-----------|------|-------------|
61
+ | `featuresDir` | `string` | Absolute path to the features directory (typically `/path/to/project/.kanban`) |
62
+
63
+ The SDK derives the **workspace root** as the parent directory of `featuresDir`. This is where it looks for `.kanban.json` (board configuration).
64
+
65
+ ### Properties
66
+
67
+ | Property | Type | Description |
68
+ |----------|------|-------------|
69
+ | `featuresDir` | `string` | The features directory passed to the constructor |
70
+ | `workspaceRoot` | `string` | Parent directory of `featuresDir` (read-only getter) |
71
+
72
+ ---
73
+
74
+ ## Card Operations
75
+
76
+ ### `listCards(columns?)`
77
+
78
+ Lists all cards, sorted by their fractional order. Automatically handles migration of legacy data formats.
79
+
80
+ ```typescript
81
+ const cards: Feature[] = await sdk.listCards()
82
+
83
+ // Optionally pass column IDs to ensure their subdirectories exist
84
+ const cards = await sdk.listCards(['backlog', 'todo', 'in-progress', 'review', 'done'])
85
+ ```
86
+
87
+ **Parameters:**
88
+
89
+ | Parameter | Type | Default | Description |
90
+ |-----------|------|---------|-------------|
91
+ | `columns` | `string[]` | `undefined` | Column IDs whose subdirectories should be created if missing |
92
+
93
+ **Returns:** `Promise<Feature[]>` — All cards sorted by `order` (ascending).
94
+
95
+ **Automatic migrations performed on each call:**
96
+ 1. Flat `.md` files in the root features directory are moved into their status subfolder
97
+ 2. Cards whose frontmatter status doesn't match their folder location are moved to the correct folder
98
+ 3. Legacy integer `order` values are converted to fractional indices (base-62)
99
+
100
+ ---
101
+
102
+ ### `getCard(cardId)`
103
+
104
+ Retrieves a single card by its ID.
105
+
106
+ ```typescript
107
+ const card: Feature | null = await sdk.getCard('42')
108
+ ```
109
+
110
+ **Returns:** `Promise<Feature | null>` — The card, or `null` if not found.
111
+
112
+ ---
113
+
114
+ ### `createCard(data)`
115
+
116
+ Creates a new card with auto-generated ID, timestamps, and fractional order.
117
+
118
+ ```typescript
119
+ const card = await sdk.createCard({
120
+ content: '# My Task\n\nDescription here.',
121
+ status: 'todo',
122
+ priority: 'high',
123
+ assignee: 'alice',
124
+ dueDate: '2026-03-01',
125
+ labels: ['frontend', 'urgent'],
126
+ attachments: []
127
+ })
128
+ ```
129
+
130
+ **Parameters — `CreateCardInput`:**
131
+
132
+ | Field | Type | Default | Description |
133
+ |-------|------|---------|-------------|
134
+ | `content` | `string` | *required* | Markdown content (title extracted from first `# heading`) |
135
+ | `status` | `FeatureStatus` | `'backlog'` | Initial column |
136
+ | `priority` | `Priority` | `'medium'` | Priority level |
137
+ | `assignee` | `string \| null` | `null` | Assigned team member |
138
+ | `dueDate` | `string \| null` | `null` | Due date (ISO 8601 string) |
139
+ | `labels` | `string[]` | `[]` | Labels/tags |
140
+ | `attachments` | `string[]` | `[]` | Attachment filenames |
141
+
142
+ **Returns:** `Promise<Feature>` — The created card with all generated fields.
143
+
144
+ **Auto-generated fields:**
145
+ - `id` — Incremental numeric ID (e.g. `"42"`)
146
+ - `created` / `modified` — Current ISO timestamp
147
+ - `completedAt` — Set to current timestamp if status is `'done'`, otherwise `null`
148
+ - `order` — Fractional index placing the card at the end of its column
149
+ - `filePath` — Full path to the created `.md` file
150
+
151
+ ---
152
+
153
+ ### `updateCard(cardId, updates)`
154
+
155
+ Updates one or more fields of an existing card.
156
+
157
+ ```typescript
158
+ const updated = await sdk.updateCard('42', {
159
+ priority: 'critical',
160
+ assignee: 'bob',
161
+ labels: ['backend'],
162
+ content: '# Updated Title\n\nNew description.'
163
+ })
164
+ ```
165
+
166
+ **Parameters:**
167
+
168
+ | Parameter | Type | Description |
169
+ |-----------|------|-------------|
170
+ | `cardId` | `string` | Card ID |
171
+ | `updates` | `Partial<Feature>` | Fields to update (`id` and `filePath` are ignored) |
172
+
173
+ **Returns:** `Promise<Feature>` — The updated card.
174
+
175
+ **Automatic behaviors:**
176
+ - `modified` timestamp is updated
177
+ - If `status` changes to `'done'`, `completedAt` is set; if it changes away from `'done'`, `completedAt` is cleared
178
+ - If `status` changes, the file is moved to the corresponding subfolder
179
+ - If the title (first `# heading` in content) changes, the file is renamed to match
180
+
181
+ **Throws:** `Error` if card not found.
182
+
183
+ ---
184
+
185
+ ### `moveCard(cardId, newStatus, position?)`
186
+
187
+ Moves a card to a different column and/or reorders it within a column.
188
+
189
+ ```typescript
190
+ // Move to the end of "in-progress"
191
+ await sdk.moveCard('42', 'in-progress')
192
+
193
+ // Move to position 0 (top) of "review"
194
+ await sdk.moveCard('42', 'review', 0)
195
+
196
+ // Move to position 2 within the same column
197
+ await sdk.moveCard('42', 'todo', 2)
198
+ ```
199
+
200
+ **Parameters:**
201
+
202
+ | Parameter | Type | Default | Description |
203
+ |-----------|------|---------|-------------|
204
+ | `cardId` | `string` | *required* | Card ID |
205
+ | `newStatus` | `FeatureStatus` | *required* | Target column |
206
+ | `position` | `number` | End of column | Zero-based position within the target column |
207
+
208
+ **Returns:** `Promise<Feature>` — The moved card.
209
+
210
+ **Throws:** `Error` if card not found.
211
+
212
+ ---
213
+
214
+ ### `deleteCard(cardId)`
215
+
216
+ Permanently deletes a card's markdown file.
217
+
218
+ ```typescript
219
+ await sdk.deleteCard('42')
220
+ ```
221
+
222
+ **Throws:** `Error` if card not found.
223
+
224
+ ---
225
+
226
+ ### `getCardsByStatus(status)`
227
+
228
+ Convenience method to list cards filtered by status.
229
+
230
+ ```typescript
231
+ const todoCards = await sdk.getCardsByStatus('todo')
232
+ ```
233
+
234
+ **Returns:** `Promise<Feature[]>`
235
+
236
+ ---
237
+
238
+ ### `getUniqueAssignees()`
239
+
240
+ Returns a sorted list of all unique assignee names across all cards.
241
+
242
+ ```typescript
243
+ const assignees: string[] = await sdk.getUniqueAssignees()
244
+ // ['alice', 'bob']
245
+ ```
246
+
247
+ ---
248
+
249
+ ### `getUniqueLabels()`
250
+
251
+ Returns a sorted list of all unique labels across all cards.
252
+
253
+ ```typescript
254
+ const labels: string[] = await sdk.getUniqueLabels()
255
+ // ['backend', 'frontend', 'urgent']
256
+ ```
257
+
258
+ ---
259
+
260
+ ## Comment Operations
261
+
262
+ Comments are stored inside the card's markdown file as additional YAML document blocks.
263
+
264
+ ### `listComments(cardId)`
265
+
266
+ ```typescript
267
+ const comments: Comment[] = await sdk.listComments('42')
268
+ ```
269
+
270
+ **Returns:** `Promise<Comment[]>`
271
+
272
+ Each `Comment` has:
273
+
274
+ | Field | Type | Description |
275
+ |-------|------|-------------|
276
+ | `id` | `string` | Comment ID (e.g. `"c1"`, `"c2"`) |
277
+ | `author` | `string` | Author name |
278
+ | `created` | `string` | ISO 8601 timestamp |
279
+ | `content` | `string` | Comment body (plain text or markdown) |
280
+
281
+ ---
282
+
283
+ ### `addComment(cardId, author, content)`
284
+
285
+ ```typescript
286
+ const card = await sdk.addComment('42', 'alice', 'Looks good, needs tests')
287
+ // card.comments now includes the new comment with auto-generated ID
288
+ ```
289
+
290
+ **Returns:** `Promise<Feature>` — The updated card.
291
+
292
+ ---
293
+
294
+ ### `updateComment(cardId, commentId, content)`
295
+
296
+ ```typescript
297
+ await sdk.updateComment('42', 'c1', 'Updated: LGTM after adding tests')
298
+ ```
299
+
300
+ **Throws:** `Error` if card or comment not found.
301
+
302
+ ---
303
+
304
+ ### `deleteComment(cardId, commentId)`
305
+
306
+ ```typescript
307
+ await sdk.deleteComment('42', 'c1')
308
+ ```
309
+
310
+ **Throws:** `Error` if card not found.
311
+
312
+ ---
313
+
314
+ ## Attachment Operations
315
+
316
+ Attachments are files stored alongside the card's `.md` file in the same directory.
317
+
318
+ ### `listAttachments(cardId)`
319
+
320
+ ```typescript
321
+ const attachments: string[] = await sdk.listAttachments('42')
322
+ // ['screenshot.png', 'design.pdf']
323
+ ```
324
+
325
+ ---
326
+
327
+ ### `addAttachment(cardId, sourcePath)`
328
+
329
+ Copies a file to the card's directory and records it in the card's frontmatter.
330
+
331
+ ```typescript
332
+ const card = await sdk.addAttachment('42', '/tmp/screenshot.png')
333
+ ```
334
+
335
+ If the file is already in the card's directory, it won't be copied again.
336
+
337
+ **Returns:** `Promise<Feature>` — The updated card.
338
+
339
+ ---
340
+
341
+ ### `removeAttachment(cardId, attachment)`
342
+
343
+ Removes an attachment reference from the card's frontmatter. Does **not** delete the file from disk.
344
+
345
+ ```typescript
346
+ await sdk.removeAttachment('42', 'screenshot.png')
347
+ ```
348
+
349
+ **Returns:** `Promise<Feature>` — The updated card.
350
+
351
+ ---
352
+
353
+ ## Column Operations
354
+
355
+ Columns define the board's workflow stages. They are stored in `.kanban.json` at the workspace root.
356
+
357
+ > Column methods are **synchronous** (they read/write `.kanban.json` using `fs.readFileSync`/`writeFileSync`), except `removeColumn` which is async because it checks for cards in the column.
358
+
359
+ ### `listColumns()`
360
+
361
+ ```typescript
362
+ const columns: KanbanColumn[] = sdk.listColumns()
363
+ ```
364
+
365
+ Each `KanbanColumn` has:
366
+
367
+ | Field | Type | Description |
368
+ |-------|------|-------------|
369
+ | `id` | `string` | Unique column identifier (used as folder name and status value) |
370
+ | `name` | `string` | Display name |
371
+ | `color` | `string` | Hex color code |
372
+
373
+ Default columns: `backlog`, `todo`, `in-progress`, `review`, `done`.
374
+
375
+ ---
376
+
377
+ ### `addColumn(column)`
378
+
379
+ ```typescript
380
+ const columns = sdk.addColumn({ id: 'testing', name: 'Testing', color: '#ff9900' })
381
+ ```
382
+
383
+ **Throws:** `Error` if a column with the same `id` already exists.
384
+
385
+ **Returns:** `KanbanColumn[]` — The updated list of all columns.
386
+
387
+ ---
388
+
389
+ ### `updateColumn(columnId, updates)`
390
+
391
+ ```typescript
392
+ const columns = sdk.updateColumn('testing', { name: 'QA', color: '#00cc99' })
393
+ ```
394
+
395
+ Both `name` and `color` are optional — only provided fields are updated.
396
+
397
+ **Throws:** `Error` if column not found.
398
+
399
+ **Returns:** `KanbanColumn[]` — The updated list of all columns.
400
+
401
+ ---
402
+
403
+ ### `removeColumn(columnId)`
404
+
405
+ Removes a column. Fails if any cards are still in that column.
406
+
407
+ ```typescript
408
+ const columns = await sdk.removeColumn('testing')
409
+ ```
410
+
411
+ **Throws:** `Error` if column not found or column still contains cards.
412
+
413
+ **Returns:** `Promise<KanbanColumn[]>` — The updated list of all columns.
414
+
415
+ ---
416
+
417
+ ### `reorderColumns(columnIds)`
418
+
419
+ Reorders columns by specifying all column IDs in the desired order.
420
+
421
+ ```typescript
422
+ const columns = sdk.reorderColumns(['todo', 'in-progress', 'review', 'done', 'backlog'])
423
+ ```
424
+
425
+ **Throws:** `Error` if any ID is missing or if the list doesn't include all columns.
426
+
427
+ **Returns:** `KanbanColumn[]` — The reordered column list.
428
+
429
+ ---
430
+
431
+ ## Settings Operations
432
+
433
+ Board display settings control how cards are rendered in the UI.
434
+
435
+ ### `getSettings()`
436
+
437
+ ```typescript
438
+ const settings: CardDisplaySettings = sdk.getSettings()
439
+ ```
440
+
441
+ **`CardDisplaySettings` fields:**
442
+
443
+ | Field | Type | Default | Description |
444
+ |-------|------|---------|-------------|
445
+ | `showPriorityBadges` | `boolean` | `true` | Show priority badges on cards |
446
+ | `showAssignee` | `boolean` | `true` | Show assignee on cards |
447
+ | `showDueDate` | `boolean` | `true` | Show due dates on cards |
448
+ | `showLabels` | `boolean` | `true` | Show labels on cards |
449
+ | `showBuildWithAI` | `boolean` | `true` | Show "Build with AI" button |
450
+ | `showFileName` | `boolean` | `false` | Show file name on cards |
451
+ | `compactMode` | `boolean` | `false` | Use compact card layout |
452
+ | `markdownEditorMode` | `boolean` | `false` | Use raw markdown editor |
453
+ | `defaultPriority` | `Priority` | `'medium'` | Default priority for new cards |
454
+ | `defaultStatus` | `FeatureStatus` | `'backlog'` | Default status for new cards |
455
+
456
+ ---
457
+
458
+ ### `updateSettings(settings)`
459
+
460
+ ```typescript
461
+ sdk.updateSettings({
462
+ ...sdk.getSettings(),
463
+ compactMode: true,
464
+ showFileName: true
465
+ })
466
+ ```
467
+
468
+ **Note:** Pass a full `CardDisplaySettings` object (use spread with `getSettings()` to change only specific fields).
469
+
470
+ ---
471
+
472
+ ## Initialization
473
+
474
+ ### `init()`
475
+
476
+ Ensures the features directory exists. Called automatically by most operations, but can be invoked explicitly.
477
+
478
+ ```typescript
479
+ await sdk.init()
480
+ ```
481
+
482
+ ---
483
+
484
+ ## Types
485
+
486
+ ### `Feature`
487
+
488
+ ```typescript
489
+ interface Feature {
490
+ id: string // Auto-generated card ID (e.g. "42")
491
+ status: FeatureStatus // Column: 'backlog' | 'todo' | 'in-progress' | 'review' | 'done'
492
+ priority: Priority // 'critical' | 'high' | 'medium' | 'low'
493
+ assignee: string | null // Assigned team member
494
+ dueDate: string | null // ISO 8601 date string
495
+ created: string // ISO 8601 timestamp
496
+ modified: string // ISO 8601 timestamp (auto-updated)
497
+ completedAt: string | null // Set when status becomes 'done'
498
+ labels: string[] // Tags
499
+ attachments: string[] // Attachment filenames
500
+ comments: Comment[] // Discussion threads
501
+ order: string // Fractional index for ordering (base-62)
502
+ content: string // Markdown body (title is the first # heading)
503
+ filePath: string // Absolute path to the .md file
504
+ }
505
+ ```
506
+
507
+ ### `FeatureStatus`
508
+
509
+ ```typescript
510
+ type FeatureStatus = 'backlog' | 'todo' | 'in-progress' | 'review' | 'done'
511
+ ```
512
+
513
+ ### `Priority`
514
+
515
+ ```typescript
516
+ type Priority = 'critical' | 'high' | 'medium' | 'low'
517
+ ```
518
+
519
+ ### `KanbanColumn`
520
+
521
+ ```typescript
522
+ interface KanbanColumn {
523
+ id: string // Used as folder name and status value
524
+ name: string // Display name
525
+ color: string // Hex color
526
+ }
527
+ ```
528
+
529
+ ### `Comment`
530
+
531
+ ```typescript
532
+ interface Comment {
533
+ id: string // e.g. "c1", "c2"
534
+ author: string
535
+ created: string // ISO 8601 timestamp
536
+ content: string
537
+ }
538
+ ```
539
+
540
+ ### `CreateCardInput`
541
+
542
+ ```typescript
543
+ interface CreateCardInput {
544
+ content: string
545
+ status?: FeatureStatus
546
+ priority?: Priority
547
+ assignee?: string | null
548
+ dueDate?: string | null
549
+ labels?: string[]
550
+ attachments?: string[]
551
+ }
552
+ ```
553
+
554
+ ### `CardDisplaySettings`
555
+
556
+ ```typescript
557
+ interface CardDisplaySettings {
558
+ showPriorityBadges: boolean
559
+ showAssignee: boolean
560
+ showDueDate: boolean
561
+ showLabels: boolean
562
+ showBuildWithAI: boolean
563
+ showFileName: boolean
564
+ compactMode: boolean
565
+ markdownEditorMode: boolean
566
+ defaultPriority: Priority
567
+ defaultStatus: FeatureStatus
568
+ }
569
+ ```
570
+
571
+ ---
572
+
573
+ ## Utility Exports
574
+
575
+ The SDK package also exports lower-level utilities:
576
+
577
+ | Export | Description |
578
+ |--------|-------------|
579
+ | `parseFeatureFile(content, filePath)` | Parse a markdown string into a `Feature` object |
580
+ | `serializeFeature(feature)` | Serialize a `Feature` object back to markdown with YAML frontmatter |
581
+ | `getTitleFromContent(content)` | Extract the title from the first `# heading` in markdown |
582
+ | `generateFeatureFilename(id, title)` | Generate a filename slug from a numeric ID and title |
583
+ | `DEFAULT_COLUMNS` | The default 5-column board layout |
584
+ | `readConfig(workspaceRoot)` | Read `.kanban.json` configuration |
585
+ | `writeConfig(workspaceRoot, config)` | Write `.kanban.json` configuration |
586
+ | `configToSettings(config)` | Extract `CardDisplaySettings` from a `KanbanConfig` |
587
+ | `settingsToConfig(config, settings)` | Merge `CardDisplaySettings` back into a `KanbanConfig` |
588
+
589
+ ---
590
+
591
+ ## File Layout
592
+
593
+ The SDK manages this file structure:
594
+
595
+ ```
596
+ project/
597
+ .kanban.json # Board config (columns, display settings)
598
+ .kanban/ # Features directory
599
+ backlog/
600
+ 1-my-task.md # Card markdown file
601
+ todo/
602
+ 2-another-task.md
603
+ screenshot.png # Attachment (same directory as card)
604
+ in-progress/
605
+ review/
606
+ done/
607
+ ```
608
+
609
+ Each card file uses YAML frontmatter followed by markdown content:
610
+
611
+ ```markdown
612
+ ---
613
+ id: "1"
614
+ status: "backlog"
615
+ priority: "high"
616
+ assignee: "alice"
617
+ dueDate: "2026-03-01"
618
+ created: "2026-02-21T10:00:00.000Z"
619
+ modified: "2026-02-21T14:00:00.000Z"
620
+ completedAt: null
621
+ labels: ["backend", "security"]
622
+ attachments: []
623
+ order: "a0"
624
+ ---
625
+
626
+ # Implement authentication
627
+
628
+ Add OAuth2 login flow with Google and GitHub providers.
629
+
630
+ ---
631
+ comment: true
632
+ id: "c1"
633
+ author: "bob"
634
+ created: "2026-02-21T15:00:00.000Z"
635
+ ---
636
+ Should we support SAML too?
637
+ ```
638
+
639
+ ---
640
+
641
+ ## Error Handling
642
+
643
+ SDK methods throw standard `Error` objects with descriptive messages:
644
+
645
+ ```typescript
646
+ try {
647
+ await sdk.deleteCard('nonexistent')
648
+ } catch (err) {
649
+ console.error(err.message) // "Card not found: nonexistent"
650
+ }
651
+ ```
652
+
653
+ Common error messages:
654
+ - `"Card not found: <id>"`
655
+ - `"Comment not found: <commentId>"`
656
+ - `"Column not found: <columnId>"`
657
+ - `"Column already exists: <columnId>"`
658
+ - `"Cannot remove column "<id>": N card(s) still in this column"`
659
+ - `"Must include all column IDs when reordering"`
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "kanban-lite",
3
3
  "displayName": "Kanban Lite",
4
4
  "description": "A kanban board for your codebase. Features stored as markdown.",
5
- "version": "1.0.7",
5
+ "version": "1.0.8",
6
6
  "publisher": "borgius",
7
7
  "license": "MIT",
8
8
  "repository": {