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 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