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
package/README.md ADDED
@@ -0,0 +1,37 @@
1
+ # kantban-cli
2
+
3
+ CLI for KantBan pipeline orchestration — bridges KantBan boards to local Claude Code sessions.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install -g kantban-cli
9
+ ```
10
+
11
+ ## Environment Variables
12
+
13
+ | Variable | Required | Description |
14
+ |----------|----------|-------------|
15
+ | `KANTBAN_API_TOKEN` | Yes | API token from KantBan account settings (starts with `cb_`) |
16
+ | `KANTBAN_API_URL` | Yes | Your KantBan API URL |
17
+ | `KANTBAN_PROJECT_ID` | No | Default project ID (some commands require it) |
18
+
19
+ ## Commands
20
+
21
+ ```bash
22
+ kantban pipeline <board-id> # Run autonomous agent pipeline
23
+ kantban status <board-id> # Monitor pipeline status
24
+ kantban context <board-id> # Print pipeline context as JSON
25
+ kantban work <ticket-id> # Start working on a ticket
26
+ kantban cron <column-id> # Process a single column on a timer
27
+ ```
28
+
29
+ ## Requirements
30
+
31
+ - Node.js >= 22
32
+ - A KantBan account with an API token
33
+
34
+ ## Links
35
+
36
+ - [KantBan](https://kantban.com)
37
+ - [kantban-mcp](https://www.npmjs.com/package/kantban-mcp) — MCP server for Claude Code integration
@@ -0,0 +1,35 @@
1
+ export declare const REQUEST_TIMEOUT_MS = 30000;
2
+ export declare const MAX_RETRIES = 2;
3
+ export declare const RETRY_BASE_MS = 500;
4
+ /** Returns true for statuses that are worth retrying (server errors + rate limit). */
5
+ export declare function isRetryableStatus(status: number): boolean;
6
+ /**
7
+ * Wraps `fetch` with:
8
+ * - Per-request AbortController timeout (REQUEST_TIMEOUT_MS)
9
+ * - Exponential backoff with jitter on retryable failures
10
+ * - Up to MAX_RETRIES retries (so MAX_RETRIES + 1 total attempts)
11
+ *
12
+ * @param _sleep — optional override for the backoff sleep (used in tests to avoid real delays)
13
+ */
14
+ export declare function fetchWithRetry(url: string, init: RequestInit, retries?: number, _sleep?: (ms: number) => Promise<void>): Promise<Response>;
15
+ export declare class KantBanCLIClient {
16
+ private apiUrl;
17
+ private apiToken;
18
+ constructor(apiUrl: string, apiToken: string);
19
+ get baseUrl(): string;
20
+ get token(): string;
21
+ get<T>(path: string, params?: Record<string, string | number | boolean | undefined>): Promise<T>;
22
+ post<T>(path: string, body?: Record<string, unknown>): Promise<T>;
23
+ claimTicket(projectId: string, ticketId: string): Promise<void>;
24
+ getFingerprint(projectId: string, ticketId: string): Promise<{
25
+ column_id: string | null;
26
+ updated_at: string;
27
+ comment_count: number;
28
+ signal_count: number;
29
+ field_value_count: number;
30
+ }>;
31
+ getBoardProject(boardId: string): Promise<{
32
+ project_id: string;
33
+ }>;
34
+ }
35
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,kBAAkB,QAAS,CAAC;AACzC,eAAO,MAAM,WAAW,IAAI,CAAC;AAC7B,eAAO,MAAM,aAAa,MAAM,CAAC;AAEjC,sFAAsF;AACtF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,WAAW,EACjB,OAAO,SAAc,EACrB,MAAM,GAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CACe,GAClD,OAAO,CAAC,QAAQ,CAAC,CAgCnB;AAID,qBAAa,gBAAgB;IAEzB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,QAAQ;gBADR,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM;IAG1B,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED,IAAI,KAAK,IAAI,MAAM,CAElB;IAEK,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAmBhG,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAkBjE,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/D,cAAc,CAClB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QACT,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,UAAU,EAAE,MAAM,CAAC;QACnB,aAAa,EAAE,MAAM,CAAC;QACtB,YAAY,EAAE,MAAM,CAAC;QACrB,iBAAiB,EAAE,MAAM,CAAC;KAC3B,CAAC;IAII,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;CAGxE"}
package/dist/client.js ADDED
@@ -0,0 +1,109 @@
1
+ // ── retry / timeout constants ─────────────────────────────────────────────
2
+ export const REQUEST_TIMEOUT_MS = 30_000;
3
+ export const MAX_RETRIES = 2;
4
+ export const RETRY_BASE_MS = 500;
5
+ /** Returns true for statuses that are worth retrying (server errors + rate limit). */
6
+ export function isRetryableStatus(status) {
7
+ return status >= 500 || status === 429;
8
+ }
9
+ /**
10
+ * Wraps `fetch` with:
11
+ * - Per-request AbortController timeout (REQUEST_TIMEOUT_MS)
12
+ * - Exponential backoff with jitter on retryable failures
13
+ * - Up to MAX_RETRIES retries (so MAX_RETRIES + 1 total attempts)
14
+ *
15
+ * @param _sleep — optional override for the backoff sleep (used in tests to avoid real delays)
16
+ */
17
+ export async function fetchWithRetry(url, init, retries = MAX_RETRIES, _sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))) {
18
+ let lastError;
19
+ for (let attempt = 0; attempt <= retries; attempt++) {
20
+ const controller = new AbortController();
21
+ const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
22
+ try {
23
+ const res = await fetch(url, { ...init, signal: controller.signal });
24
+ clearTimeout(timer);
25
+ // Non-retryable: 2xx (ok) or any non-retryable error status
26
+ if (res.ok || !isRetryableStatus(res.status)) {
27
+ return res;
28
+ }
29
+ // Retryable status — treat as a transient failure
30
+ lastError = new Error(`API error ${res.status}: ${await res.text()}`);
31
+ }
32
+ catch (err) {
33
+ clearTimeout(timer);
34
+ lastError = err;
35
+ // Only retry on network/abort errors, not on logic errors
36
+ }
37
+ if (attempt < retries) {
38
+ // Exponential backoff with up to 50% random jitter
39
+ const delay = RETRY_BASE_MS * 2 ** attempt * (1 + Math.random() * 0.5);
40
+ await _sleep(delay);
41
+ }
42
+ }
43
+ throw lastError;
44
+ }
45
+ // ── client ────────────────────────────────────────────────────────────────
46
+ export class KantBanCLIClient {
47
+ apiUrl;
48
+ apiToken;
49
+ constructor(apiUrl, apiToken) {
50
+ this.apiUrl = apiUrl;
51
+ this.apiToken = apiToken;
52
+ }
53
+ get baseUrl() {
54
+ return this.apiUrl;
55
+ }
56
+ get token() {
57
+ return this.apiToken;
58
+ }
59
+ async get(path, params) {
60
+ const url = new URL(path, this.apiUrl);
61
+ if (params) {
62
+ for (const [k, v] of Object.entries(params)) {
63
+ if (v !== undefined)
64
+ url.searchParams.set(k, String(v));
65
+ }
66
+ }
67
+ const res = await fetchWithRetry(url.toString(), {
68
+ headers: {
69
+ 'Authorization': `Bearer ${this.apiToken}`,
70
+ 'X-KantBan-Via': 'cli',
71
+ },
72
+ });
73
+ if (!res.ok)
74
+ throw new Error(`API error ${res.status}: ${await res.text()}`);
75
+ const json = (await res.json());
76
+ if (!json.success)
77
+ throw new Error(`API responded with success: false`);
78
+ return json.data;
79
+ }
80
+ async post(path, body) {
81
+ const url = new URL(path, this.apiUrl);
82
+ const headers = {
83
+ 'Authorization': `Bearer ${this.apiToken}`,
84
+ 'X-KantBan-Via': 'cli',
85
+ };
86
+ const init = { method: 'POST', headers };
87
+ if (body) {
88
+ headers['Content-Type'] = 'application/json';
89
+ init.body = JSON.stringify(body);
90
+ }
91
+ const res = await fetchWithRetry(url.toString(), init);
92
+ if (!res.ok)
93
+ throw new Error(`API error ${res.status}: ${await res.text()}`);
94
+ const json = (await res.json());
95
+ if (!json.success)
96
+ throw new Error(`API responded with success: false`);
97
+ return json.data;
98
+ }
99
+ async claimTicket(projectId, ticketId) {
100
+ await this.post(`/projects/${projectId}/tickets/${ticketId}/start`, {});
101
+ }
102
+ async getFingerprint(projectId, ticketId) {
103
+ return this.get(`/projects/${projectId}/tickets/${ticketId}/fingerprint`);
104
+ }
105
+ async getBoardProject(boardId) {
106
+ return this.get(`/boards/${boardId}/project`);
107
+ }
108
+ }
109
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { KantBanCLIClient } from '../client.js';
2
+ export declare function runContext(client: KantBanCLIClient, args: string[]): Promise<void>;
3
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/commands/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,wBAAsB,UAAU,CAAC,MAAM,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA6BxF"}
@@ -0,0 +1,27 @@
1
+ export async function runContext(client, args) {
2
+ const [scopeType, scopeId] = args;
3
+ if (!scopeType || !scopeId) {
4
+ console.error('Usage: kantban context <board|column|ticket> <id>');
5
+ process.exit(1);
6
+ }
7
+ const projectId = process.env['KANTBAN_PROJECT_ID'];
8
+ if (!projectId) {
9
+ console.error('Error: KANTBAN_PROJECT_ID environment variable required for context command');
10
+ process.exit(1);
11
+ }
12
+ const params = {};
13
+ if (scopeType === 'board')
14
+ params['boardId'] = scopeId;
15
+ else if (scopeType === 'column')
16
+ params['columnId'] = scopeId;
17
+ else if (scopeType === 'ticket')
18
+ params['ticketId'] = scopeId;
19
+ else {
20
+ console.error(`Unknown scope type: ${scopeType}. Use board, column, or ticket.`);
21
+ process.exit(1);
22
+ }
23
+ const data = await client.get(`/projects/${projectId}/pipeline-context`, params);
24
+ // Output as structured JSON to stdout for piping
25
+ console.log(JSON.stringify(data, null, 2));
26
+ }
27
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/commands/context.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,MAAwB,EAAE,IAAc;IACvE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAClC,IAAI,CAAC,SAAS,IAAI,CAAC,OAAO,EAAE,CAAC;QAC3B,OAAO,CAAC,KAAK,CAAC,mDAAmD,CAAC,CAAC;QACnE,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,6EAA6E,CAAC,CAAC;QAC7F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,IAAI,SAAS,KAAK,OAAO;QAAE,MAAM,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC;SAClD,IAAI,SAAS,KAAK,QAAQ;QAAE,MAAM,CAAC,UAAU,CAAC,GAAG,OAAO,CAAC;SACzD,IAAI,SAAS,KAAK,QAAQ;QAAE,MAAM,CAAC,UAAU,CAAC,GAAG,OAAO,CAAC;SACzD,CAAC;QACJ,OAAO,CAAC,KAAK,CAAC,uBAAuB,SAAS,iCAAiC,CAAC,CAAC;QACjF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,GAAG,CAC3B,aAAa,SAAS,mBAAmB,EACzC,MAAM,CACP,CAAC;IAEF,iDAAiD;IACjD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC7C,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { KantBanCLIClient } from '../client.js';
2
+ export declare function runCron(client: KantBanCLIClient, args: string[]): Promise<void>;
3
+ //# sourceMappingURL=cron.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cron.d.ts","sourceRoot":"","sources":["../../src/commands/cron.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAqBrD,wBAAsB,OAAO,CAAC,MAAM,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAwGrF"}
@@ -0,0 +1,106 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ import { generateMcpConfig, cleanupMcpConfig } from '../lib/mcp-config.js';
4
+ import { RalphLoop } from '../lib/ralph-loop.js';
5
+ const execFileAsync = promisify(execFile);
6
+ function parseDuration(input) {
7
+ const match = input.match(/^(\d+)(s|m|h)$/);
8
+ if (!match)
9
+ throw new Error(`Invalid duration: ${input}. Use format like 5m, 30s, 1h`);
10
+ const value = Number(match[1]);
11
+ const unit = match[2];
12
+ switch (unit) {
13
+ case 's': return value * 1000;
14
+ case 'm': return value * 60 * 1000;
15
+ case 'h': return value * 60 * 60 * 1000;
16
+ default: throw new Error(`Unknown unit: ${unit}`);
17
+ }
18
+ }
19
+ export async function runCron(client, args) {
20
+ const columnId = args[0];
21
+ if (!columnId) {
22
+ console.error('Usage: kantban cron <column-id> [--interval 5m]');
23
+ process.exit(1);
24
+ }
25
+ // Parse interval
26
+ let intervalMs = 5 * 60 * 1000; // default 5m
27
+ const intervalIdx = args.indexOf('--interval');
28
+ const intervalArg = intervalIdx !== -1 ? args[intervalIdx + 1] : undefined;
29
+ if (intervalArg) {
30
+ intervalMs = parseDuration(intervalArg);
31
+ }
32
+ // Resolve project ID
33
+ const projectId = process.env['KANTBAN_PROJECT_ID'];
34
+ if (!projectId) {
35
+ console.error('Error: KANTBAN_PROJECT_ID required');
36
+ process.exit(1);
37
+ }
38
+ // Generate MCP config
39
+ const mcpConfigPath = generateMcpConfig(client.baseUrl, client.token);
40
+ // invokeClaudeP helper (same pattern as pipeline.ts)
41
+ async function invokeClaudeP(prompt, options) {
42
+ const claudeArgs = ['-p', prompt, '--mcp-config', options.mcpConfigPath, '--dangerously-skip-permissions'];
43
+ if (options.model)
44
+ claudeArgs.push('--model', options.model);
45
+ try {
46
+ const { stdout } = await execFileAsync('claude', claudeArgs, { maxBuffer: 10 * 1024 * 1024 });
47
+ return { exitCode: 0, output: stdout };
48
+ }
49
+ catch (err) {
50
+ const execErr = err;
51
+ return { exitCode: execErr.code ?? 1, output: execErr.stdout ?? execErr.message ?? '' };
52
+ }
53
+ }
54
+ let stopped = false;
55
+ // Graceful shutdown
56
+ const shutdown = () => {
57
+ stopped = true;
58
+ cleanupMcpConfig(mcpConfigPath);
59
+ console.log('\nCron stopped.');
60
+ process.exit(0);
61
+ };
62
+ process.on('SIGTERM', shutdown);
63
+ process.on('SIGINT', shutdown);
64
+ console.log(`Cron: column ${columnId}, interval ${String(intervalMs / 1000)}s`);
65
+ console.log('Press Ctrl+C to stop.\n');
66
+ // Main cron tick
67
+ const tick = async () => {
68
+ if (stopped)
69
+ return;
70
+ try {
71
+ // Fetch column scope
72
+ const columnScope = await client.get(`/projects/${projectId}/pipeline-context`, { columnId });
73
+ const tickets = columnScope.tickets ?? [];
74
+ if (tickets.length === 0) {
75
+ console.log(`[${new Date().toLocaleTimeString('en-US', { hour12: false })}] No tickets in column. Sleeping...`);
76
+ return;
77
+ }
78
+ console.log(`[${new Date().toLocaleTimeString('en-US', { hour12: false })}] Processing ${String(tickets.length)} ticket(s)...`);
79
+ // Process each ticket sequentially (one iteration each for cron)
80
+ for (const ticket of tickets) {
81
+ if (stopped)
82
+ break;
83
+ const deps = {
84
+ fetchTicketContext: (tid) => client.get(`/projects/${projectId}/pipeline-context`, { ticketId: tid }),
85
+ fetchColumnContext: (cid) => client.get(`/projects/${projectId}/pipeline-context`, { columnId: cid }),
86
+ fetchFingerprint: (tid) => client.getFingerprint(projectId, tid),
87
+ invokeClaudeP,
88
+ mcpConfigPath,
89
+ projectId,
90
+ };
91
+ const config = { maxIterations: 1, gutterThreshold: 1 };
92
+ const loop = new RalphLoop(ticket.id, columnId, config, deps);
93
+ const result = await loop.run();
94
+ console.log(` ${String(ticket.ticket_number)}: ${result.reason} (${String(result.iterations)} iter)`);
95
+ }
96
+ }
97
+ catch (err) {
98
+ const message = err instanceof Error ? err.message : String(err);
99
+ console.error(`Cron tick error: ${message}`);
100
+ }
101
+ };
102
+ // Run immediately, then on interval
103
+ await tick();
104
+ setInterval(() => void tick(), intervalMs);
105
+ }
106
+ //# sourceMappingURL=cron.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cron.js","sourceRoot":"","sources":["../../src/commands/cron.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { KantBanCLIClient } from '../client.js';
2
+ export declare function runPipeline(client: KantBanCLIClient, args: string[]): Promise<void>;
3
+ export declare function stopPipeline(args: string[]): Promise<void>;
4
+ //# sourceMappingURL=pipeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/commands/pipeline.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AA6QrD,wBAAsB,WAAW,CAAC,MAAM,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA8TzF;AAmBD,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAwChE"}