kanbango 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +606 -0
- package/API.md +177 -0
- package/CHANGELOG.md +122 -0
- package/LICENSE +21 -0
- package/LLM_AGENTS.md +484 -0
- package/README.md +360 -0
- package/bin/kanban-cmd.js +40 -0
- package/bin/kanban.js +462 -0
- package/index.html +1095 -0
- package/index.js +15 -0
- package/kanban.js +625 -0
- package/kanbango.md +48 -0
- package/mcp-server.js +489 -0
- package/package.json +41 -0
- package/planv2.md +307 -0
- package/tests/run.js +19 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,606 @@
|
|
|
1
|
+
# AGENTS.md - Guide for AI Coding Agents
|
|
2
|
+
|
|
3
|
+
This document provides build commands, testing procedures, and code style guidelines for working with the kanbango codebase.
|
|
4
|
+
|
|
5
|
+
## Build & Development Commands
|
|
6
|
+
|
|
7
|
+
### Available Scripts
|
|
8
|
+
```bash
|
|
9
|
+
# Start web GUI (opens http://localhost:5500)
|
|
10
|
+
npm start
|
|
11
|
+
# or
|
|
12
|
+
node bin/kanban.js serve
|
|
13
|
+
|
|
14
|
+
# Start web GUI on custom port
|
|
15
|
+
node bin/kanban.js serve 8080
|
|
16
|
+
|
|
17
|
+
# Run MCP server
|
|
18
|
+
npm run mcp
|
|
19
|
+
# or
|
|
20
|
+
node mcp-server.js
|
|
21
|
+
|
|
22
|
+
# Run tests (lists tasks in JSON format)
|
|
23
|
+
npm test
|
|
24
|
+
# or
|
|
25
|
+
node bin/kanban.js list --json
|
|
26
|
+
|
|
27
|
+
# Initialize backlog structure
|
|
28
|
+
node bin/kanban.js init
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Testing
|
|
32
|
+
The project uses a simple test command that verifies the CLI works:
|
|
33
|
+
```bash
|
|
34
|
+
npm test
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Single test verification:**
|
|
38
|
+
```bash
|
|
39
|
+
# Test MCP server tools list
|
|
40
|
+
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | node mcp-server.js
|
|
41
|
+
|
|
42
|
+
# Test kanban_read tool
|
|
43
|
+
echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"kanban_read","arguments":{"operation":"list"}}}' | node mcp-server.js
|
|
44
|
+
|
|
45
|
+
# Test CLI list
|
|
46
|
+
node bin/kanban.js list --json
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Installation & Setup
|
|
50
|
+
```bash
|
|
51
|
+
# Install dependencies
|
|
52
|
+
npm install
|
|
53
|
+
|
|
54
|
+
# Install globally for CLI access
|
|
55
|
+
npm install -g .
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Code Style Guidelines
|
|
59
|
+
|
|
60
|
+
### File Structure
|
|
61
|
+
```
|
|
62
|
+
kanbango/
|
|
63
|
+
├── bin/ # CLI executables
|
|
64
|
+
│ ├── kanban.js # Main CLI with web server
|
|
65
|
+
│ └── kanban-cmd.js # Alternative CLI (symlink to kanban.js)
|
|
66
|
+
├── kanban.js # Core business logic module
|
|
67
|
+
├── mcp-server.js # MCP server implementation
|
|
68
|
+
├── index.js # Main entry point (module exports)
|
|
69
|
+
├── index.html # Web GUI
|
|
70
|
+
├── backlog/ # Task storage (gitignored)
|
|
71
|
+
└── examples/ # Usage examples
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Imports
|
|
75
|
+
|
|
76
|
+
**Use CommonJS require statements:**
|
|
77
|
+
```javascript
|
|
78
|
+
const fs = require('fs').promises;
|
|
79
|
+
const path = require('path');
|
|
80
|
+
const kanban = require('./kanban.js');
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Standard library imports:**
|
|
84
|
+
```javascript
|
|
85
|
+
const fs = require('fs');
|
|
86
|
+
const path = require('path');
|
|
87
|
+
const os = require('os');
|
|
88
|
+
const http = require('http');
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**External package imports:**
|
|
92
|
+
```javascript
|
|
93
|
+
const { Server } = require("@modelcontextprotocol/sdk/server/index.js");
|
|
94
|
+
const { StdioServerTransport } = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Destructure imports from external packages:**
|
|
98
|
+
```javascript
|
|
99
|
+
const { Server, StdioServerTransport } = require("@modelcontextprotocol/sdk");
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Formatting
|
|
103
|
+
|
|
104
|
+
**Indentation:** 2 spaces (no tabs)
|
|
105
|
+
|
|
106
|
+
**Line length:** Aim for under 100 characters when practical
|
|
107
|
+
|
|
108
|
+
**Semicolons:** Required at end of statements
|
|
109
|
+
|
|
110
|
+
**Quotes:** Single quotes for strings and keys, double quotes for JSON
|
|
111
|
+
```javascript
|
|
112
|
+
const title = 'Task title';
|
|
113
|
+
const filePath = path.join(__dirname, 'file.js');
|
|
114
|
+
console.log(JSON.stringify(data, null, 2)); // Double quotes in JSON
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Trailing commas:** Omit in objects/arrays unless needed for formatting
|
|
118
|
+
```javascript
|
|
119
|
+
const config = {
|
|
120
|
+
name: "kanbango",
|
|
121
|
+
version: "1.0.0"
|
|
122
|
+
};
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Types
|
|
126
|
+
|
|
127
|
+
**No TypeScript** - This is a pure JavaScript project
|
|
128
|
+
|
|
129
|
+
**Common type patterns:**
|
|
130
|
+
```javascript
|
|
131
|
+
// Arrays
|
|
132
|
+
const epics = [];
|
|
133
|
+
const COLS = ["active", "planned", "icebox", "done"];
|
|
134
|
+
|
|
135
|
+
// Objects
|
|
136
|
+
const task = { done: false, text: "Description" };
|
|
137
|
+
const STATUS_MAP = { active: "in_progress", planned: "planned" };
|
|
138
|
+
|
|
139
|
+
// Functions (implicitly typed)
|
|
140
|
+
async function parseEpic(filePath, column) {
|
|
141
|
+
// ...
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Callbacks
|
|
145
|
+
function shortId(epicId) {
|
|
146
|
+
const match = epicId.match(/^(PI-\d+[\w.]*|BUG-\d+|CHORE-\d+)/);
|
|
147
|
+
return match ? match[1] : epicId;
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Naming Conventions
|
|
152
|
+
|
|
153
|
+
**Constants:** UPPER_SNAKE_CASE
|
|
154
|
+
```javascript
|
|
155
|
+
const BACKLOG = path.join(__dirname, 'backlog');
|
|
156
|
+
const COLS = ["active", "planned", "icebox", "done"];
|
|
157
|
+
const STATUS_MAP = { active: "in_progress" };
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**Functions:** camelCase
|
|
161
|
+
```javascript
|
|
162
|
+
function parseEpic(filePath, column) { }
|
|
163
|
+
async function ensureBacklogDir() { }
|
|
164
|
+
function displayTitle(epic) { }
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**Variables:** camelCase
|
|
168
|
+
```javascript
|
|
169
|
+
const filePath = await findFile(taskId);
|
|
170
|
+
const col = COLS.find(c => c === 'active');
|
|
171
|
+
let filtered = epics;
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**Classes/Modules:** PascalCase (not used in this project, but for reference)
|
|
175
|
+
```javascript
|
|
176
|
+
class KanbanServer { }
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**Private/internal functions:** prefix with underscore if needed (not commonly used)
|
|
180
|
+
```javascript
|
|
181
|
+
function _normalizePath(p) { }
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Error Handling
|
|
185
|
+
|
|
186
|
+
**Use try/catch for async operations that might fail:**
|
|
187
|
+
```javascript
|
|
188
|
+
async function allEpics() {
|
|
189
|
+
const epics = [];
|
|
190
|
+
|
|
191
|
+
for (const col of COLS) {
|
|
192
|
+
const colDir = path.join(BACKLOG, col);
|
|
193
|
+
try {
|
|
194
|
+
const files = await fs.readdir(colDir);
|
|
195
|
+
// Process files...
|
|
196
|
+
} catch (e) {
|
|
197
|
+
if (e.code !== 'ENOENT') throw e; // Re-throw if not ENOENT
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return epics;
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**Handle expected error codes:**
|
|
206
|
+
- `ENOENT` - File/directory not found (ignore)
|
|
207
|
+
- Other errors - log and continue, or re-throw
|
|
208
|
+
|
|
209
|
+
**In CLI context:**
|
|
210
|
+
```javascript
|
|
211
|
+
async function cliShow(taskId) {
|
|
212
|
+
const filePath = await kanban.findFile(taskId);
|
|
213
|
+
if (!filePath) {
|
|
214
|
+
console.error(`✗ Nie znaleziono: ${taskId}`);
|
|
215
|
+
process.exit(1);
|
|
216
|
+
}
|
|
217
|
+
// ...
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
**In MCP server context:**
|
|
222
|
+
```javascript
|
|
223
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
224
|
+
try {
|
|
225
|
+
// Process request
|
|
226
|
+
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
|
227
|
+
} catch (error) {
|
|
228
|
+
return {
|
|
229
|
+
content: [{ type: "text", text: JSON.stringify({ error: error.message }) }],
|
|
230
|
+
isError: true
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
**Never crash silently - always provide feedback:**
|
|
237
|
+
- Use `console.error()` for errors
|
|
238
|
+
- Use `console.log()` for normal output
|
|
239
|
+
- Use `process.exit(1)` for fatal CLI errors
|
|
240
|
+
|
|
241
|
+
### Async/Await Patterns
|
|
242
|
+
|
|
243
|
+
**Prefer async/await over callbacks:**
|
|
244
|
+
```javascript
|
|
245
|
+
async function ensureBacklogDir() {
|
|
246
|
+
for (const col of COLS) {
|
|
247
|
+
const colDir = path.join(BACKLOG, col);
|
|
248
|
+
await fs.mkdir(colDir, { recursive: true });
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
**Handle async in loops:**
|
|
254
|
+
```javascript
|
|
255
|
+
for (const col of COLS) {
|
|
256
|
+
const colDir = path.join(BACKLOG, col);
|
|
257
|
+
const files = await fs.readdir(colDir); // await inside loop
|
|
258
|
+
// Process each file
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### File Operations
|
|
263
|
+
|
|
264
|
+
**Use fs.promises for async operations:**
|
|
265
|
+
```javascript
|
|
266
|
+
const fs = require('fs').promises;
|
|
267
|
+
|
|
268
|
+
await fs.mkdir(dir, { recursive: true });
|
|
269
|
+
await fs.readFile(filePath, 'utf-8');
|
|
270
|
+
await fs.writeFile(filePath, content, 'utf-8');
|
|
271
|
+
await fs.readdir(dir);
|
|
272
|
+
await fs.rename(oldPath, newPath);
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
**Use fs.existsSync for synchronous checks:**
|
|
276
|
+
```javascript
|
|
277
|
+
if (!fs.existsSync(readme)) {
|
|
278
|
+
await fs.promises.writeFile(readme, content, 'utf-8');
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
**Always use path.join() for cross-platform paths:**
|
|
283
|
+
```javascript
|
|
284
|
+
const BACKLOG = path.join(__dirname, 'backlog');
|
|
285
|
+
const filePath = path.join(BACKLOG, col, fileName);
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
**Use path.basename() and path.dirname() for path manipulation:**
|
|
289
|
+
```javascript
|
|
290
|
+
const fileName = path.basename(filePath, '.md'); // Remove extension
|
|
291
|
+
const dirName = path.dirname(filePath);
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### Console Output
|
|
295
|
+
|
|
296
|
+
**CLI output:**
|
|
297
|
+
- Normal messages: `console.log()`
|
|
298
|
+
- Errors: `console.error()`
|
|
299
|
+
- Exit on error: `process.exit(1)`
|
|
300
|
+
|
|
301
|
+
**MCP server:**
|
|
302
|
+
- Use `console.error()` for server logs (visible only in stderr)
|
|
303
|
+
- Return errors in response, don't log them
|
|
304
|
+
|
|
305
|
+
**Examples:**
|
|
306
|
+
```javascript
|
|
307
|
+
// CLI
|
|
308
|
+
console.log('✓ Task created');
|
|
309
|
+
console.error('✗ Task not found');
|
|
310
|
+
process.exit(1);
|
|
311
|
+
|
|
312
|
+
// MCP server
|
|
313
|
+
console.error("kanbango MCP server running");
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### Comments
|
|
317
|
+
|
|
318
|
+
**Minimal comments preferred** - code should be self-documenting
|
|
319
|
+
|
|
320
|
+
**Use JSDoc for module exports when helpful:**
|
|
321
|
+
```javascript
|
|
322
|
+
/**
|
|
323
|
+
* kanbango - JSON-first Kanban board
|
|
324
|
+
|
|
325
|
+
* This package provides a local Kanban board with web GUI, CLI, and MCP server.
|
|
326
|
+
* Tasks are stored as JSON files in a `backlog/` directory.
|
|
327
|
+
*
|
|
328
|
+
* @module kanbango
|
|
329
|
+
*/
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
**Section separators for large files:**
|
|
333
|
+
```javascript
|
|
334
|
+
// ── Section name ──────────────────────────────────────────────────────────────
|
|
335
|
+
|
|
336
|
+
function someFunction() {
|
|
337
|
+
// ...
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### Regular Expressions
|
|
342
|
+
|
|
343
|
+
**Use regex flags appropriately:**
|
|
344
|
+
- `m` - multiline: match across multiple lines
|
|
345
|
+
- `g` - global: find all matches
|
|
346
|
+
- `i` - case insensitive (not commonly needed)
|
|
347
|
+
|
|
348
|
+
**Examples:**
|
|
349
|
+
```javascript
|
|
350
|
+
const titleMatch = text.match(/^# (.+)$/m); // Match first header line
|
|
351
|
+
const taskRegex = /^- \[([ x])\] (.+)$/gm; // Find all task items
|
|
352
|
+
|
|
353
|
+
let match;
|
|
354
|
+
while ((match = taskRegex.exec(text)) !== null) {
|
|
355
|
+
tasks.push({
|
|
356
|
+
done: match[1] === 'x',
|
|
357
|
+
text: match[2]
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
### Module Exports
|
|
363
|
+
|
|
364
|
+
**Use module.exports for CommonJS:**
|
|
365
|
+
```javascript
|
|
366
|
+
const kanban = require('./kanban.js');
|
|
367
|
+
|
|
368
|
+
module.exports = {
|
|
369
|
+
kanban,
|
|
370
|
+
// OR export individual functions
|
|
371
|
+
ensureBacklogDir,
|
|
372
|
+
parseEpic,
|
|
373
|
+
allEpics
|
|
374
|
+
};
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
**Default exports (not used here but for reference):**
|
|
378
|
+
```javascript
|
|
379
|
+
module.exports = function() { };
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
### CLI Argument Parsing
|
|
383
|
+
|
|
384
|
+
**Process.argv provides arguments:**
|
|
385
|
+
```javascript
|
|
386
|
+
const args = process.argv.slice(2); // Skip node and script path
|
|
387
|
+
const cmd = args[0];
|
|
388
|
+
const param1 = args[1];
|
|
389
|
+
|
|
390
|
+
// Example: node bin/kanban.js move PI-001 done
|
|
391
|
+
// args[0] = "move"
|
|
392
|
+
// args[1] = "PI-001"
|
|
393
|
+
// args[2] = "done"
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
**Parse optional flags:**
|
|
397
|
+
```javascript
|
|
398
|
+
let colFilter = null;
|
|
399
|
+
let asJson = false;
|
|
400
|
+
|
|
401
|
+
for (let i = 1; i < args.length; i++) {
|
|
402
|
+
if (args[i] === '--col' && args[i + 1]) {
|
|
403
|
+
colFilter = args[++i];
|
|
404
|
+
} else if (args[i] === '--json') {
|
|
405
|
+
asJson = true;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### MCP Server Patterns
|
|
411
|
+
|
|
412
|
+
**Tool definitions:**
|
|
413
|
+
```javascript
|
|
414
|
+
{
|
|
415
|
+
name: "tool_name",
|
|
416
|
+
description: "Clear description of what this tool does",
|
|
417
|
+
inputSchema: {
|
|
418
|
+
type: "object",
|
|
419
|
+
properties: {
|
|
420
|
+
param_name: {
|
|
421
|
+
type: "string",
|
|
422
|
+
description: "Description of parameter"
|
|
423
|
+
}
|
|
424
|
+
},
|
|
425
|
+
required: ["param_name"]
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
**Tool handlers:**
|
|
431
|
+
```javascript
|
|
432
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
433
|
+
const { name, arguments: args } = request.params;
|
|
434
|
+
|
|
435
|
+
switch (name) {
|
|
436
|
+
case "tool_name":
|
|
437
|
+
// Process tool
|
|
438
|
+
break;
|
|
439
|
+
default:
|
|
440
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
return {
|
|
444
|
+
content: [{ type: "text", text: JSON.stringify(result) }]
|
|
445
|
+
};
|
|
446
|
+
});
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
## Best Practices
|
|
450
|
+
|
|
451
|
+
1. **Always validate inputs** - especially from CLI arguments
|
|
452
|
+
2. **Handle async errors** - never let async operations fail silently
|
|
453
|
+
3. **Use const by default** - use let only when reassignment is needed
|
|
454
|
+
4. **Prefer fs.promises** - over callback-based fs operations
|
|
455
|
+
5. **Use path.join()** - never concatenate paths with + or /
|
|
456
|
+
6. **Keep functions small** - aim for 20-30 lines max
|
|
457
|
+
7. **Return early on errors** - reduce nesting
|
|
458
|
+
8. **Use descriptive variable names** - avoid single letters except in loop counters
|
|
459
|
+
9. **Test MCP tools** - use JSON RPC messages to verify functionality
|
|
460
|
+
10. **Check for existing files** - before writing to avoid overwrites when unintended
|
|
461
|
+
|
|
462
|
+
## Version Management
|
|
463
|
+
|
|
464
|
+
Update `package.json` version on changes:
|
|
465
|
+
```bash
|
|
466
|
+
# Major: incompatible API changes
|
|
467
|
+
npm version major
|
|
468
|
+
|
|
469
|
+
# Minor: new features, backwards compatible
|
|
470
|
+
npm version minor
|
|
471
|
+
|
|
472
|
+
# Patch: bug fixes, backwards compatible
|
|
473
|
+
npm version patch
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
**Manual version update** (if npm version doesn't work):
|
|
477
|
+
```bash
|
|
478
|
+
# Edit package.json and update "version" field
|
|
479
|
+
# Example: "version": "1.2.0" → "version": "1.3.0"
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
Always update CHANGELOG.md with version changes:
|
|
483
|
+
```bash
|
|
484
|
+
# Add new section with date
|
|
485
|
+
## [1.3.0] - 2026-03-XX
|
|
486
|
+
|
|
487
|
+
### Added
|
|
488
|
+
- New feature description
|
|
489
|
+
|
|
490
|
+
### Changed
|
|
491
|
+
- Modified existing functionality
|
|
492
|
+
|
|
493
|
+
### Fixed
|
|
494
|
+
- Bug fix description
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
## Git Workflow
|
|
498
|
+
|
|
499
|
+
**Commit changes with proper messages:**
|
|
500
|
+
```bash
|
|
501
|
+
# Check status
|
|
502
|
+
git status
|
|
503
|
+
|
|
504
|
+
# Add changes
|
|
505
|
+
git add -A
|
|
506
|
+
|
|
507
|
+
# Commit with descriptive message (follows these patterns):
|
|
508
|
+
git commit -m "Add feature: description"
|
|
509
|
+
git commit -m "Fix bug: description"
|
|
510
|
+
git commit -m "Update docs: description"
|
|
511
|
+
git commit -m "Refactor: description"
|
|
512
|
+
git commit -m "Release v1.2.0 - brief description"
|
|
513
|
+
|
|
514
|
+
# Push to origin
|
|
515
|
+
git push origin master
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
**Commit message patterns:**
|
|
519
|
+
- `Add feature:` - new functionality
|
|
520
|
+
- `Fix bug:` - bug fix
|
|
521
|
+
- `Update docs:` - documentation changes
|
|
522
|
+
- `Refactor:` - code restructuring
|
|
523
|
+
- `Release vX.Y.Z:` - version releases
|
|
524
|
+
|
|
525
|
+
**Complete workflow for releases:**
|
|
526
|
+
```bash
|
|
527
|
+
# 1. Update version in package.json
|
|
528
|
+
npm version patch # or minor/major
|
|
529
|
+
|
|
530
|
+
# 2. Update CHANGELOG.md with version details
|
|
531
|
+
# (manually edit CHANGELOG.md)
|
|
532
|
+
|
|
533
|
+
# 3. Commit changes
|
|
534
|
+
git add package.json CHANGELOG.md
|
|
535
|
+
git commit -m "Release v1.3.0 - Add new feature"
|
|
536
|
+
|
|
537
|
+
# 4. Push to remote
|
|
538
|
+
git push origin master
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
**Multiple files commit pattern:**
|
|
542
|
+
```bash
|
|
543
|
+
# Add all changes
|
|
544
|
+
git add -A
|
|
545
|
+
|
|
546
|
+
# Commit all changes together
|
|
547
|
+
git commit -m "Add MCP tools and update documentation
|
|
548
|
+
|
|
549
|
+
- Added 3 unified MCP tools (read, create, update)
|
|
550
|
+
- Updated README.md with new tool names
|
|
551
|
+
- Updated CHANGELOG.md with v1.2.0 details
|
|
552
|
+
- Enhanced documentation for LLM agents"
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
Branch: `master` (not `main`)
|
|
556
|
+
|
|
557
|
+
## Testing Your Changes
|
|
558
|
+
|
|
559
|
+
After making changes, verify:
|
|
560
|
+
1. CLI works: `node bin/kanban.js list --json`
|
|
561
|
+
2. Web GUI starts: `node bin/kanban.js serve` (Ctrl+C to stop)
|
|
562
|
+
3. MCP server tools: `echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | node mcp-server.js`
|
|
563
|
+
4. All three tools work: kanban_read, kanban_create, kanban_update
|
|
564
|
+
|
|
565
|
+
## Common Patterns to Avoid
|
|
566
|
+
|
|
567
|
+
❌ Don't use synchronous file operations in async contexts
|
|
568
|
+
```javascript
|
|
569
|
+
// Bad
|
|
570
|
+
const content = fs.readFileSync(path); // Blocking
|
|
571
|
+
// Good
|
|
572
|
+
const content = await fs.readFile(path);
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
❌ Don't concatenate paths manually
|
|
576
|
+
```javascript
|
|
577
|
+
// Bad
|
|
578
|
+
const path = __dirname + '/backlog';
|
|
579
|
+
// Good
|
|
580
|
+
const path = path.join(__dirname, 'backlog');
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
❌ Don't ignore error codes
|
|
584
|
+
```javascript
|
|
585
|
+
// Bad
|
|
586
|
+
try { await fs.mkdir(dir); } catch (e) { }
|
|
587
|
+
// Good
|
|
588
|
+
try { await fs.mkdir(dir); } catch (e) {
|
|
589
|
+
if (e.code !== 'ENOENT') throw e;
|
|
590
|
+
}
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
❌ Don't use console.log for errors in MCP server
|
|
594
|
+
```javascript
|
|
595
|
+
// Bad
|
|
596
|
+
console.log('Error:', error);
|
|
597
|
+
// Good
|
|
598
|
+
return { content: [{ text: JSON.stringify({ error: error.message }) }], isError: true };
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
## Getting Help
|
|
602
|
+
|
|
603
|
+
- README.md: https://github.com/k0r81/kanbango#readme
|
|
604
|
+
- LLM Agents Guide: LLM_AGENTS.md
|
|
605
|
+
- MCP Server Guide: LLM_AGENTS.md
|
|
606
|
+
- Issues: https://github.com/k0r81/kanbango/issues
|