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.
- package/README.md +17 -26
- package/docs/sdk.md +659 -0
- 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
|
-
//
|
|
354
|
+
// Cards
|
|
355
355
|
const cards = await sdk.listCards()
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
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
|
|
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
|
-
//
|
|
386
|
-
const columns =
|
|
387
|
-
|
|
388
|
-
|
|
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