kantban-cli 0.1.1

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 (58) hide show
  1. package/README.md +37 -0
  2. package/dist/client.d.ts +35 -0
  3. package/dist/client.d.ts.map +1 -0
  4. package/dist/client.js +109 -0
  5. package/dist/client.js.map +1 -0
  6. package/dist/commands/context.d.ts +3 -0
  7. package/dist/commands/context.d.ts.map +1 -0
  8. package/dist/commands/context.js +27 -0
  9. package/dist/commands/context.js.map +1 -0
  10. package/dist/commands/cron.d.ts +3 -0
  11. package/dist/commands/cron.d.ts.map +1 -0
  12. package/dist/commands/cron.js +106 -0
  13. package/dist/commands/cron.js.map +1 -0
  14. package/dist/commands/pipeline.d.ts +4 -0
  15. package/dist/commands/pipeline.d.ts.map +1 -0
  16. package/dist/commands/pipeline.js +543 -0
  17. package/dist/commands/pipeline.js.map +1 -0
  18. package/dist/commands/status.d.ts +3 -0
  19. package/dist/commands/status.d.ts.map +1 -0
  20. package/dist/commands/status.js +135 -0
  21. package/dist/commands/status.js.map +1 -0
  22. package/dist/commands/work.d.ts +3 -0
  23. package/dist/commands/work.d.ts.map +1 -0
  24. package/dist/commands/work.js +76 -0
  25. package/dist/commands/work.js.map +1 -0
  26. package/dist/index.d.ts +3 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +65 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/lib/event-queue.d.ts +28 -0
  31. package/dist/lib/event-queue.d.ts.map +1 -0
  32. package/dist/lib/event-queue.js +65 -0
  33. package/dist/lib/event-queue.js.map +1 -0
  34. package/dist/lib/logger.d.ts +20 -0
  35. package/dist/lib/logger.d.ts.map +1 -0
  36. package/dist/lib/logger.js +52 -0
  37. package/dist/lib/logger.js.map +1 -0
  38. package/dist/lib/mcp-config.d.ts +3 -0
  39. package/dist/lib/mcp-config.d.ts.map +1 -0
  40. package/dist/lib/mcp-config.js +49 -0
  41. package/dist/lib/mcp-config.js.map +1 -0
  42. package/dist/lib/orchestrator.d.ts +172 -0
  43. package/dist/lib/orchestrator.d.ts.map +1 -0
  44. package/dist/lib/orchestrator.js +315 -0
  45. package/dist/lib/orchestrator.js.map +1 -0
  46. package/dist/lib/prompt-composer.d.ts +102 -0
  47. package/dist/lib/prompt-composer.d.ts.map +1 -0
  48. package/dist/lib/prompt-composer.js +178 -0
  49. package/dist/lib/prompt-composer.js.map +1 -0
  50. package/dist/lib/ralph-loop.d.ts +47 -0
  51. package/dist/lib/ralph-loop.d.ts.map +1 -0
  52. package/dist/lib/ralph-loop.js +114 -0
  53. package/dist/lib/ralph-loop.js.map +1 -0
  54. package/dist/lib/ws-client.d.ts +28 -0
  55. package/dist/lib/ws-client.d.ts.map +1 -0
  56. package/dist/lib/ws-client.js +113 -0
  57. package/dist/lib/ws-client.js.map +1 -0
  58. package/package.json +49 -0
@@ -0,0 +1,135 @@
1
+ import { readFileSync, existsSync, statSync, readdirSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ // ---------------------------------------------------------------------------
5
+ // Pipeline runtime info helper
6
+ // ---------------------------------------------------------------------------
7
+ function formatUptime(ms) {
8
+ const totalMinutes = Math.floor(ms / 60_000);
9
+ const hours = Math.floor(totalMinutes / 60);
10
+ const minutes = totalMinutes % 60;
11
+ if (hours > 0)
12
+ return `${String(hours)}h ${String(minutes)}m`;
13
+ return `${String(minutes)}m`;
14
+ }
15
+ function isProcessRunning(pid) {
16
+ try {
17
+ process.kill(pid, 0);
18
+ return true;
19
+ }
20
+ catch {
21
+ return false;
22
+ }
23
+ }
24
+ function showPipelineInfo(boardId) {
25
+ const pipelineDir = join(homedir(), '.kantban', 'pipelines', boardId);
26
+ const pidFile = join(pipelineDir, 'orchestrator.pid');
27
+ if (!existsSync(pidFile)) {
28
+ console.log('\nPipeline: not running');
29
+ return;
30
+ }
31
+ const pidContent = readFileSync(pidFile, 'utf8').trim();
32
+ const pid = Number(pidContent);
33
+ if (isNaN(pid) || pid <= 0) {
34
+ console.log('\nOrchestrator: not running (invalid PID file)');
35
+ return;
36
+ }
37
+ if (!isProcessRunning(pid)) {
38
+ console.log('\nOrchestrator: not running (stale PID file)');
39
+ return;
40
+ }
41
+ // Process is running — calculate uptime from PID file mtime
42
+ const pidStat = statSync(pidFile);
43
+ const uptimeMs = Date.now() - pidStat.mtimeMs;
44
+ console.log(`\nOrchestrator: running (PID: ${String(pid)}, uptime: ${formatUptime(uptimeMs)})`);
45
+ // Scan for recent iteration logs to show active/recent loop info
46
+ if (!existsSync(pipelineDir))
47
+ return;
48
+ const entries = readdirSync(pipelineDir, { withFileTypes: true });
49
+ const ticketDirs = entries.filter((e) => e.isDirectory());
50
+ if (ticketDirs.length === 0)
51
+ return;
52
+ const recentLoops = [];
53
+ for (const dir of ticketDirs) {
54
+ const ticketDir = join(pipelineDir, dir.name);
55
+ const files = readdirSync(ticketDir).filter((f) => f.startsWith('iteration-') && f.endsWith('.log'));
56
+ if (files.length === 0)
57
+ continue;
58
+ // Get the latest iteration log
59
+ files.sort();
60
+ const latestFile = files[files.length - 1];
61
+ const logPath = join(ticketDir, latestFile);
62
+ try {
63
+ const logContent = readFileSync(logPath, 'utf8');
64
+ const logData = JSON.parse(logContent);
65
+ recentLoops.push({
66
+ ticket: dir.name,
67
+ lastIteration: Number(logData['iteration'] ?? 0),
68
+ outcome: String(logData['outcome'] ?? 'unknown'),
69
+ timestamp: String(logData['timestamp'] ?? ''),
70
+ });
71
+ }
72
+ catch {
73
+ // Skip malformed log files
74
+ }
75
+ }
76
+ if (recentLoops.length > 0) {
77
+ // Sort by timestamp descending to show most recent first
78
+ recentLoops.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
79
+ console.log(` Active/recent loops (${String(recentLoops.length)}):`);
80
+ for (const loop of recentLoops.slice(0, 10)) {
81
+ console.log(` ${loop.ticket} iter:${String(loop.lastIteration)} ${loop.outcome}`);
82
+ }
83
+ if (recentLoops.length > 10) {
84
+ console.log(` ... and ${String(recentLoops.length - 10)} more`);
85
+ }
86
+ }
87
+ }
88
+ export async function runStatus(client, args) {
89
+ const [boardId] = args;
90
+ if (!boardId) {
91
+ console.error('Usage: kantban status <board-id>');
92
+ process.exit(1);
93
+ }
94
+ const projectId = process.env['KANTBAN_PROJECT_ID'];
95
+ if (!projectId) {
96
+ console.error('Error: KANTBAN_PROJECT_ID required');
97
+ process.exit(1);
98
+ }
99
+ const data = await client.get(`/projects/${projectId}/pipeline-context`, { boardId });
100
+ const columns = data['columns'];
101
+ const cb = data['circuit_breaker'];
102
+ const board = data['board'];
103
+ console.log(`Pipeline Status: ${board?.['name'] ?? 'Unknown Board'}`);
104
+ console.log('\u2500'.repeat(60));
105
+ if (columns) {
106
+ for (const col of columns) {
107
+ const prompt = col['has_prompt'] ? '\u{1F4C4}' : ' ';
108
+ const name = String(col['name'] ?? '(unnamed)');
109
+ const count = Number(col['ticket_count'] ?? 0);
110
+ const goal = col['goal'] ? ` \u2014 ${String(col['goal'])}` : '';
111
+ console.log(`${prompt} ${name} (${count} tickets)${goal}`);
112
+ }
113
+ }
114
+ if (cb?.['threshold']) {
115
+ console.log(`\nCircuit Breaker: threshold=${String(cb['threshold'])}`);
116
+ }
117
+ // Fetch bottleneck info
118
+ const bottlenecks = await client.get(`/projects/${projectId}/boards/${boardId}/bottlenecks`);
119
+ const stuckCount = bottlenecks['stuck_tickets']?.length ?? 0;
120
+ const wipCount = bottlenecks['wip_violations']?.length ?? 0;
121
+ if (stuckCount > 0 || wipCount > 0) {
122
+ console.log(`\nWarnings: ${stuckCount} stuck, ${wipCount} WIP violations`);
123
+ }
124
+ else {
125
+ console.log('\nAll clear.');
126
+ }
127
+ // Show pipeline orchestrator runtime info (non-fatal on error)
128
+ try {
129
+ showPipelineInfo(boardId);
130
+ }
131
+ catch {
132
+ // Pipeline info is supplementary — don't break the status command
133
+ }
134
+ }
135
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,8EAA8E;AAC9E,+BAA+B;AAC/B,8EAA8E;AAE9E,SAAS,YAAY,CAAC,EAAU;IAC9B,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,EAAE,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG,YAAY,GAAG,EAAE,CAAC;IAClC,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC;IAC9D,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC;AAC/B,CAAC;AAED,SAAS,gBAAgB,CAAC,GAAW;IACnC,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,OAAe;IACvC,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;IACtE,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,kBAAkB,CAAC,CAAC;IAEtD,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;QACvC,OAAO;IACT,CAAC;IAED,MAAM,UAAU,GAAG,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IACxD,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;IAC/B,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;QAC9D,OAAO;IACT,CAAC;IAED,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;QAC5D,OAAO;IACT,CAAC;IAED,4DAA4D;IAC5D,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAC9C,OAAO,CAAC,GAAG,CAAC,iCAAiC,MAAM,CAAC,GAAG,CAAC,aAAa,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IAEhG,iEAAiE;IACjE,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO;IAErC,MAAM,OAAO,GAAG,WAAW,CAAC,WAAW,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAClE,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;IAE1D,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAEpC,MAAM,WAAW,GAAyF,EAAE,CAAC;IAE7G,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC7B,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QAC9C,MAAM,KAAK,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QACrG,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QAEjC,+BAA+B;QAC/B,KAAK,CAAC,IAAI,EAAE,CAAC;QACb,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC;QAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;QAE5C,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YACjD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAA4B,CAAC;YAClE,WAAW,CAAC,IAAI,CAAC;gBACf,MAAM,EAAE,GAAG,CAAC,IAAI;gBAChB,aAAa,EAAE,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;gBAChD,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC;gBAChD,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;aAC9C,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,2BAA2B;QAC7B,CAAC;IACH,CAAC;IAED,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3B,yDAAyD;QACzD,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;QACnE,OAAO,CAAC,GAAG,CAAC,0BAA0B,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACtE,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;YAC5C,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,CAAC,MAAM,UAAU,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QACzF,CAAC;QACD,IAAI,WAAW,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;YAC5B,OAAO,CAAC,GAAG,CAAC,eAAe,MAAM,CAAC,WAAW,CAAC,MAAM,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,MAAwB,EAAE,IAAc;IACtE,MAAM,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;IACvB,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;QAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IACpD,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;QACpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,GAAG,CAC3B,aAAa,SAAS,mBAAmB,EACzC,EAAE,OAAO,EAAE,CACZ,CAAC;IAEF,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAA+C,CAAC;IAC9E,MAAM,EAAE,GAAG,IAAI,CAAC,iBAAiB,CAAwC,CAAC;IAC1E,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAwC,CAAC;IAEnE,OAAO,CAAC,GAAG,CAAC,oBAAoB,KAAK,EAAE,CAAC,MAAM,CAAC,IAAI,eAAe,EAAE,CAAC,CAAC;IACtE,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAEjC,IAAI,OAAO,EAAE,CAAC;QACZ,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;YAC1B,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;YACtD,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,WAAW,CAAC,CAAC;YAChD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;YAC/C,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjE,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,IAAI,IAAI,KAAK,KAAK,YAAY,IAAI,EAAE,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;IAED,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,gCAAgC,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC;IACzE,CAAC;IAED,wBAAwB;IACxB,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,GAAG,CAClC,aAAa,SAAS,WAAW,OAAO,cAAc,CACvD,CAAC;IACF,MAAM,UAAU,GAAI,WAAW,CAAC,eAAe,CAA2B,EAAE,MAAM,IAAI,CAAC,CAAC;IACxF,MAAM,QAAQ,GAAI,WAAW,CAAC,gBAAgB,CAA2B,EAAE,MAAM,IAAI,CAAC,CAAC;IAEvF,IAAI,UAAU,GAAG,CAAC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QACnC,OAAO,CAAC,GAAG,CAAC,eAAe,UAAU,WAAW,QAAQ,iBAAiB,CAAC,CAAC;IAC7E,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAC9B,CAAC;IAED,+DAA+D;IAC/D,IAAI,CAAC;QACH,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,kEAAkE;IACpE,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { KantBanCLIClient } from '../client.js';
2
+ export declare function runWork(client: KantBanCLIClient, args: string[]): Promise<void>;
3
+ //# sourceMappingURL=work.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"work.d.ts","sourceRoot":"","sources":["../../src/commands/work.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAYrD,wBAAsB,OAAO,CAAC,MAAM,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsFrF"}
@@ -0,0 +1,76 @@
1
+ import { spawn } from 'node:child_process';
2
+ function asRecord(val) {
3
+ return typeof val === 'object' && val !== null && !Array.isArray(val)
4
+ ? val
5
+ : undefined;
6
+ }
7
+ function asStringArray(val) {
8
+ return Array.isArray(val) ? val.map((v) => String(v)) : [];
9
+ }
10
+ export async function runWork(client, args) {
11
+ const [ticketId] = args;
12
+ if (!ticketId) {
13
+ console.error('Usage: kantban work <ticket-id> [--dry-run]');
14
+ process.exit(1);
15
+ }
16
+ const projectId = process.env['KANTBAN_PROJECT_ID'];
17
+ if (!projectId) {
18
+ console.error('Error: KANTBAN_PROJECT_ID required');
19
+ process.exit(1);
20
+ }
21
+ // Fetch ticket-scope context
22
+ const context = await client.get(`/projects/${projectId}/pipeline-context`, { ticketId });
23
+ const ticket = asRecord(context['ticket']);
24
+ const signals = asStringArray(context['signals']);
25
+ const rules = context['transition_rules'] ? String(context['transition_rules']) : undefined;
26
+ const title = String(ticket?.['title'] ?? 'Untitled');
27
+ const description = ticket?.['description'] ? String(ticket['description']) : '';
28
+ const ticketIdStr = String(ticket?.['id'] ?? ticketId);
29
+ // Build prompt for Claude
30
+ const promptLines = [
31
+ `# Task: ${title}`,
32
+ '',
33
+ ];
34
+ if (description) {
35
+ promptLines.push(description, '');
36
+ }
37
+ if (signals.length > 0) {
38
+ promptLines.push('## Signals');
39
+ for (const s of signals) {
40
+ promptLines.push(`- ${s}`);
41
+ }
42
+ promptLines.push('');
43
+ }
44
+ if (rules) {
45
+ promptLines.push('## Transition Rules', rules, '');
46
+ }
47
+ const toolPrefix = context['tool_prefix'] ? String(context['tool_prefix']) : 'kantban_';
48
+ promptLines.push(`## Tool Prefix: ${toolPrefix}`, `## Ticket ID: ${ticketIdStr}`, `## Project ID: ${projectId}`);
49
+ const prompt = promptLines.join('\n');
50
+ console.log(`Starting Claude session for: ${title}`);
51
+ console.log(`Ticket: ${ticketIdStr}`);
52
+ // Check for dry run
53
+ const dryRun = args.includes('--dry-run');
54
+ if (dryRun) {
55
+ console.log('\n--- Prompt (dry run) ---');
56
+ console.log(prompt);
57
+ return;
58
+ }
59
+ // Spawn Claude with the prompt
60
+ const child = spawn('claude', ['-p', prompt], {
61
+ stdio: 'inherit',
62
+ env: { ...process.env },
63
+ });
64
+ await new Promise((resolve) => {
65
+ child.on('error', (err) => {
66
+ console.error(`Failed to start claude: ${err.message}`);
67
+ process.exitCode = 1;
68
+ resolve();
69
+ });
70
+ child.on('exit', (code) => {
71
+ process.exitCode = code ?? 0;
72
+ resolve();
73
+ });
74
+ });
75
+ }
76
+ //# sourceMappingURL=work.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"work.js","sourceRoot":"","sources":["../../src/commands/work.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env node
2
+ import { KantBanCLIClient } from './client.js';
3
+ const apiToken = process.env['KANTBAN_API_TOKEN'];
4
+ const apiUrl = process.env['KANTBAN_API_URL'];
5
+ if (!apiToken || !apiUrl) {
6
+ console.error('Error: KANTBAN_API_TOKEN and KANTBAN_API_URL environment variables are required');
7
+ process.exit(1);
8
+ }
9
+ const client = new KantBanCLIClient(apiUrl, apiToken);
10
+ const [command, ...args] = process.argv.slice(2);
11
+ async function main() {
12
+ switch (command) {
13
+ case 'context': {
14
+ const { runContext } = await import('./commands/context.js');
15
+ await runContext(client, args);
16
+ break;
17
+ }
18
+ case 'status': {
19
+ const { runStatus } = await import('./commands/status.js');
20
+ await runStatus(client, args);
21
+ break;
22
+ }
23
+ case 'work': {
24
+ const { runWork } = await import('./commands/work.js');
25
+ await runWork(client, args);
26
+ break;
27
+ }
28
+ case 'pipeline': {
29
+ if (args[0] === 'stop') {
30
+ const { stopPipeline } = await import('./commands/pipeline.js');
31
+ await stopPipeline(args.slice(1));
32
+ }
33
+ else {
34
+ const { runPipeline } = await import('./commands/pipeline.js');
35
+ await runPipeline(client, args);
36
+ }
37
+ break;
38
+ }
39
+ case 'cron': {
40
+ const { runCron } = await import('./commands/cron.js');
41
+ await runCron(client, args);
42
+ break;
43
+ }
44
+ default:
45
+ console.log(`kantban CLI — Pipeline orchestration for KantBan
46
+
47
+ Usage:
48
+ kantban context <scope-type> <scope-id> Output scoped pipeline context to stdout
49
+ kantban status <board-id> Pipeline health at a glance
50
+ kantban work <ticket-id> Start a Claude session for a ticket
51
+ kantban pipeline <board-id> Persistent pipeline orchestrator
52
+ kantban pipeline stop <board-id> Stop running pipeline
53
+ kantban cron <column-id> [--interval 5m] Run single column on a timer
54
+
55
+ Environment:
56
+ KANTBAN_API_TOKEN API token (required)
57
+ KANTBAN_API_URL API URL (required)
58
+ KANTBAN_PROJECT_ID Default project ID (optional)`);
59
+ }
60
+ }
61
+ main().catch((err) => {
62
+ console.error('Error:', err.message);
63
+ process.exit(1);
64
+ });
65
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;AAClD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;AAE9C,IAAI,CAAC,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;IACzB,OAAO,CAAC,KAAK,CAAC,iFAAiF,CAAC,CAAC;IACjG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AACtD,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEjD,KAAK,UAAU,IAAI;IACjB,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAC;YAC7D,MAAM,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YAC/B,MAAM;QACR,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,sBAAsB,CAAC,CAAC;YAC3D,MAAM,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YAC9B,MAAM;QACR,CAAC;QACD,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;YACvD,MAAM,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YAC5B,MAAM;QACR,CAAC;QACD,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC;gBACvB,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,wBAAwB,CAAC,CAAC;gBAChE,MAAM,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YACpC,CAAC;iBAAM,CAAC;gBACN,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,wBAAwB,CAAC,CAAC;gBAC/D,MAAM,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YAClC,CAAC;YACD,MAAM;QACR,CAAC;QACD,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;YACvD,MAAM,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YAC5B,MAAM;QACR,CAAC;QACD;YACE,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;qDAamC,CAAC,CAAC;IACrD,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAU,EAAE,EAAE;IAC1B,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,28 @@
1
+ export interface PipelineEvent {
2
+ type: 'ticket:created' | 'ticket:moved' | 'ticket:archived' | 'ticket:deleted';
3
+ ticketId: string;
4
+ columnId: string | null;
5
+ }
6
+ export type EventHandler = (event: PipelineEvent) => void | Promise<void>;
7
+ export type ErrorHandler = (event: PipelineEvent, error: unknown) => void;
8
+ interface EventQueueOptions {
9
+ drainRateMs?: number;
10
+ onError?: ErrorHandler;
11
+ }
12
+ export declare class EventQueue {
13
+ private queue;
14
+ private handler;
15
+ private onError;
16
+ private timer;
17
+ private drainRateMs;
18
+ private running;
19
+ private draining;
20
+ constructor(handler: EventHandler, options?: EventQueueOptions);
21
+ start(): void;
22
+ stop(): void;
23
+ push(event: PipelineEvent): void;
24
+ pushPriority(event: PipelineEvent): void;
25
+ private drain;
26
+ }
27
+ export {};
28
+ //# sourceMappingURL=event-queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-queue.d.ts","sourceRoot":"","sources":["../../src/lib/event-queue.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,gBAAgB,GAAG,cAAc,GAAG,iBAAiB,GAAG,gBAAgB,CAAC;IAC/E,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,MAAM,YAAY,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAC1E,MAAM,MAAM,YAAY,GAAG,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;AAE1E,UAAU,iBAAiB;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,KAAK,CAAyC;IACtD,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,KAAK,CAA+C;IAC5D,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAS;gBAEb,OAAO,EAAE,YAAY,EAAE,OAAO,GAAE,iBAAsB;IAMlE,KAAK,IAAI,IAAI;IAKb,IAAI,IAAI,IAAI;IASZ,IAAI,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;IAMhC,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;YAW1B,KAAK;CAiBpB"}
@@ -0,0 +1,65 @@
1
+ export class EventQueue {
2
+ queue = new Map(); // keyed by ticketId for coalescing
3
+ handler;
4
+ onError;
5
+ timer = null;
6
+ drainRateMs;
7
+ running = false;
8
+ draining = false;
9
+ constructor(handler, options = {}) {
10
+ this.handler = handler;
11
+ this.drainRateMs = options.drainRateMs ?? 100;
12
+ this.onError = options.onError ?? ((event, error) => console.error('EventQueue handler error for event', event, error));
13
+ }
14
+ start() {
15
+ this.running = true;
16
+ this.timer = setInterval(() => void this.drain(), this.drainRateMs);
17
+ }
18
+ stop() {
19
+ this.running = false;
20
+ if (this.timer) {
21
+ clearInterval(this.timer);
22
+ this.timer = null;
23
+ }
24
+ this.queue.clear();
25
+ }
26
+ push(event) {
27
+ if (!this.running)
28
+ return;
29
+ // Coalesce: latest event for same ticket wins
30
+ this.queue.set(event.ticketId, event);
31
+ }
32
+ pushPriority(event) {
33
+ if (!this.running)
34
+ return;
35
+ // Priority events bypass the queue — execute immediately
36
+ // Also remove from queue to prevent double-processing
37
+ this.queue.delete(event.ticketId);
38
+ const result = this.handler(event);
39
+ if (result instanceof Promise) {
40
+ result.catch((error) => this.onError(event, error));
41
+ }
42
+ }
43
+ async drain() {
44
+ if (this.draining)
45
+ return;
46
+ if (this.queue.size === 0)
47
+ return;
48
+ this.draining = true;
49
+ try {
50
+ // Take the first event (FIFO from Map insertion order)
51
+ const [ticketId, event] = this.queue.entries().next().value;
52
+ this.queue.delete(ticketId);
53
+ try {
54
+ await this.handler(event);
55
+ }
56
+ catch (error) {
57
+ this.onError(event, error);
58
+ }
59
+ }
60
+ finally {
61
+ this.draining = false;
62
+ }
63
+ }
64
+ }
65
+ //# sourceMappingURL=event-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-queue.js","sourceRoot":"","sources":["../../src/lib/event-queue.ts"],"names":[],"mappings":"AAcA,MAAM,OAAO,UAAU;IACb,KAAK,GAA+B,IAAI,GAAG,EAAE,CAAC,CAAC,mCAAmC;IAClF,OAAO,CAAe;IACtB,OAAO,CAAe;IACtB,KAAK,GAA0C,IAAI,CAAC;IACpD,WAAW,CAAS;IACpB,OAAO,GAAG,KAAK,CAAC;IAChB,QAAQ,GAAG,KAAK,CAAC;IAEzB,YAAY,OAAqB,EAAE,UAA6B,EAAE;QAChE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,GAAG,CAAC;QAC9C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IAC1H,CAAC;IAED,KAAK;QACH,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,KAAK,IAAI,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IACtE,CAAC;IAED,IAAI;QACF,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACpB,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED,IAAI,CAAC,KAAoB;QACvB,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO;QAC1B,8CAA8C;QAC9C,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IACxC,CAAC;IAED,YAAY,CAAC,KAAoB;QAC/B,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO;QAC1B,yDAAyD;QACzD,sDAAsD;QACtD,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAClC,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,MAAM,YAAY,OAAO,EAAE,CAAC;YAC9B,MAAM,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,KAAK;QACjB,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC1B,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO;QAClC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC;YACH,uDAAuD;YACvD,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAAgC,CAAC;YACvF,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC5B,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAC5B,CAAC;YAAC,OAAO,KAAc,EAAE,CAAC;gBACxB,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACxB,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,20 @@
1
+ export interface IterationLogData {
2
+ promptSize: number;
3
+ exitCode: number;
4
+ duration: number;
5
+ tokenUsage?: {
6
+ input: number;
7
+ output: number;
8
+ cost?: number;
9
+ };
10
+ outcome: string;
11
+ }
12
+ export declare class PipelineLogger {
13
+ private boardDir;
14
+ constructor(baseDir: string, boardId: string);
15
+ orchestrator(message: string): void;
16
+ iteration(ticketNumber: string, iterationNum: number, data: IterationLogData): void;
17
+ formatConsole(ticketNumber: string, columnName: string, iteration: number, status: string): string;
18
+ pruneOldLogs(retentionDays: number): void;
19
+ }
20
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/lib/logger.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9D,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAS;gBAEb,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAK5C,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAMnC,SAAS,CAAC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,IAAI;IAanF,aAAa,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM;IAOlG,YAAY,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI;CAgB1C"}
@@ -0,0 +1,52 @@
1
+ import { mkdirSync, writeFileSync, appendFileSync, readdirSync, rmSync, statSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ export class PipelineLogger {
4
+ boardDir;
5
+ constructor(baseDir, boardId) {
6
+ this.boardDir = join(baseDir, boardId);
7
+ mkdirSync(this.boardDir, { recursive: true });
8
+ }
9
+ orchestrator(message) {
10
+ const logPath = join(this.boardDir, 'orchestrator.log');
11
+ const entry = `[${new Date().toISOString()}] ${message}\n`;
12
+ appendFileSync(logPath, entry);
13
+ }
14
+ iteration(ticketNumber, iterationNum, data) {
15
+ const ticketDir = join(this.boardDir, ticketNumber);
16
+ mkdirSync(ticketDir, { recursive: true });
17
+ const padded = String(iterationNum).padStart(3, '0');
18
+ const logPath = join(ticketDir, `iteration-${padded}.log`);
19
+ const entry = {
20
+ timestamp: new Date().toISOString(),
21
+ iteration: iterationNum,
22
+ ...data,
23
+ };
24
+ writeFileSync(logPath, JSON.stringify(entry, null, 2));
25
+ }
26
+ formatConsole(ticketNumber, columnName, iteration, status) {
27
+ const time = new Date().toLocaleTimeString('en-US', { hour12: false });
28
+ const ticket = ticketNumber.padEnd(10);
29
+ const col = columnName.padEnd(12);
30
+ return `[${time}] ${ticket} ${col} iter:${iteration} ${status}`;
31
+ }
32
+ pruneOldLogs(retentionDays) {
33
+ const cutoff = Date.now() - (retentionDays * 24 * 60 * 60 * 1000);
34
+ try {
35
+ const entries = readdirSync(this.boardDir, { withFileTypes: true });
36
+ for (const entry of entries) {
37
+ if (!entry.isDirectory() || entry.name === '.')
38
+ continue;
39
+ const dirPath = join(this.boardDir, entry.name);
40
+ try {
41
+ const stat = statSync(dirPath);
42
+ if (stat.mtimeMs < cutoff) {
43
+ rmSync(dirPath, { recursive: true, force: true });
44
+ }
45
+ }
46
+ catch { /* skip if stat fails */ }
47
+ }
48
+ }
49
+ catch { /* skip if dir doesn't exist */ }
50
+ }
51
+ }
52
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/lib/logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function generateMcpConfig(apiUrl: string, apiToken: string): string;
2
+ export declare function cleanupMcpConfig(filePath: string): void;
3
+ //# sourceMappingURL=mcp-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-config.d.ts","sourceRoot":"","sources":["../../src/lib/mcp-config.ts"],"names":[],"mappings":"AASA,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAmC1E;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAMvD"}
@@ -0,0 +1,49 @@
1
+ import { writeFileSync, unlinkSync, mkdirSync, existsSync } from 'node:fs';
2
+ import { join, dirname } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { tmpdir } from 'node:os';
5
+ import { randomUUID } from 'node:crypto';
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = dirname(__filename);
8
+ export function generateMcpConfig(apiUrl, apiToken) {
9
+ // Use local MCP server if running from the monorepo (dev mode),
10
+ // otherwise fall back to the published npm package.
11
+ const localMcpPath = join(__dirname, '..', '..', '..', 'mcp', 'dist', 'index.js');
12
+ const useLocal = existsSync(localMcpPath);
13
+ const kantbanServer = useLocal
14
+ ? {
15
+ command: 'node',
16
+ args: [localMcpPath],
17
+ env: {
18
+ KANTBAN_API_TOKEN: apiToken,
19
+ KANTBAN_API_URL: apiUrl,
20
+ },
21
+ }
22
+ : {
23
+ command: 'npx',
24
+ args: ['-y', 'kantban-mcp@latest'],
25
+ env: {
26
+ KANTBAN_API_TOKEN: apiToken,
27
+ KANTBAN_API_URL: apiUrl,
28
+ },
29
+ };
30
+ const config = {
31
+ mcpServers: {
32
+ kantban: kantbanServer,
33
+ },
34
+ };
35
+ const dir = join(tmpdir(), 'kantban-pipeline');
36
+ mkdirSync(dir, { recursive: true });
37
+ const filePath = join(dir, `mcp-${randomUUID()}.json`);
38
+ writeFileSync(filePath, JSON.stringify(config, null, 2));
39
+ return filePath;
40
+ }
41
+ export function cleanupMcpConfig(filePath) {
42
+ try {
43
+ unlinkSync(filePath);
44
+ }
45
+ catch {
46
+ /* already deleted */
47
+ }
48
+ }
49
+ //# sourceMappingURL=mcp-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-config.js","sourceRoot":"","sources":["../../src/lib/mcp-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC3E,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,MAAM,UAAU,iBAAiB,CAAC,MAAc,EAAE,QAAgB;IAChE,gEAAgE;IAChE,oDAAoD;IACpD,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;IAClF,MAAM,QAAQ,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC;IAE1C,MAAM,aAAa,GAAG,QAAQ;QAC5B,CAAC,CAAC;YACE,OAAO,EAAE,MAAM;YACf,IAAI,EAAE,CAAC,YAAY,CAAC;YACpB,GAAG,EAAE;gBACH,iBAAiB,EAAE,QAAQ;gBAC3B,eAAe,EAAE,MAAM;aACxB;SACF;QACH,CAAC,CAAC;YACE,OAAO,EAAE,KAAK;YACd,IAAI,EAAE,CAAC,IAAI,EAAE,oBAAoB,CAAC;YAClC,GAAG,EAAE;gBACH,iBAAiB,EAAE,QAAQ;gBAC3B,eAAe,EAAE,MAAM;aACxB;SACF,CAAC;IAEN,MAAM,MAAM,GAAG;QACb,UAAU,EAAE;YACV,OAAO,EAAE,aAAa;SACvB;KACF,CAAC;IAEF,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,kBAAkB,CAAC,CAAC;IAC/C,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,OAAO,UAAU,EAAE,OAAO,CAAC,CAAC;IACvD,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACzD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,IAAI,CAAC;QACH,UAAU,CAAC,QAAQ,CAAC,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,qBAAqB;IACvB,CAAC;AACH,CAAC"}