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.
- package/README.md +37 -0
- package/dist/client.d.ts +35 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +109 -0
- package/dist/client.js.map +1 -0
- package/dist/commands/context.d.ts +3 -0
- package/dist/commands/context.d.ts.map +1 -0
- package/dist/commands/context.js +27 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/cron.d.ts +3 -0
- package/dist/commands/cron.d.ts.map +1 -0
- package/dist/commands/cron.js +106 -0
- package/dist/commands/cron.js.map +1 -0
- package/dist/commands/pipeline.d.ts +4 -0
- package/dist/commands/pipeline.d.ts.map +1 -0
- package/dist/commands/pipeline.js +543 -0
- package/dist/commands/pipeline.js.map +1 -0
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +135 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/work.d.ts +3 -0
- package/dist/commands/work.d.ts.map +1 -0
- package/dist/commands/work.js +76 -0
- package/dist/commands/work.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +65 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/event-queue.d.ts +28 -0
- package/dist/lib/event-queue.d.ts.map +1 -0
- package/dist/lib/event-queue.js +65 -0
- package/dist/lib/event-queue.js.map +1 -0
- package/dist/lib/logger.d.ts +20 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +52 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/mcp-config.d.ts +3 -0
- package/dist/lib/mcp-config.d.ts.map +1 -0
- package/dist/lib/mcp-config.js +49 -0
- package/dist/lib/mcp-config.js.map +1 -0
- package/dist/lib/orchestrator.d.ts +172 -0
- package/dist/lib/orchestrator.d.ts.map +1 -0
- package/dist/lib/orchestrator.js +315 -0
- package/dist/lib/orchestrator.js.map +1 -0
- package/dist/lib/prompt-composer.d.ts +102 -0
- package/dist/lib/prompt-composer.d.ts.map +1 -0
- package/dist/lib/prompt-composer.js +178 -0
- package/dist/lib/prompt-composer.js.map +1 -0
- package/dist/lib/ralph-loop.d.ts +47 -0
- package/dist/lib/ralph-loop.d.ts.map +1 -0
- package/dist/lib/ralph-loop.js +114 -0
- package/dist/lib/ralph-loop.js.map +1 -0
- package/dist/lib/ws-client.d.ts +28 -0
- package/dist/lib/ws-client.d.ts.map +1 -0
- package/dist/lib/ws-client.js +113 -0
- package/dist/lib/ws-client.js.map +1 -0
- 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
|
package/dist/client.d.ts
ADDED
|
@@ -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":"AAAA,6EAA6E;AAE7E,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AACzC,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC;AAC7B,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,CAAC;AAEjC,sFAAsF;AACtF,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,OAAO,MAAM,IAAI,GAAG,IAAI,MAAM,KAAK,GAAG,CAAC;AACzC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,GAAW,EACX,IAAiB,EACjB,OAAO,GAAG,WAAW,EACrB,SAAwC,CAAC,EAAE,EAAE,EAAE,CAC7C,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAEnD,IAAI,SAAkB,CAAC;IAEvB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC;QACpD,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,kBAAkB,CAAC,CAAC;QAEvE,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;YACrE,YAAY,CAAC,KAAK,CAAC,CAAC;YAEpB,4DAA4D;YAC5D,IAAI,GAAG,CAAC,EAAE,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC7C,OAAO,GAAG,CAAC;YACb,CAAC;YAED,kDAAkD;YAClD,SAAS,GAAG,IAAI,KAAK,CAAC,aAAa,GAAG,CAAC,MAAM,KAAK,MAAM,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACxE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,SAAS,GAAG,GAAG,CAAC;YAChB,0DAA0D;QAC5D,CAAC;QAED,IAAI,OAAO,GAAG,OAAO,EAAE,CAAC;YACtB,mDAAmD;YACnD,MAAM,KAAK,GAAG,aAAa,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC;YACvE,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAED,MAAM,SAAS,CAAC;AAClB,CAAC;AAED,6EAA6E;AAE7E,MAAM,OAAO,gBAAgB;IAEjB;IACA;IAFV,YACU,MAAc,EACd,QAAgB;QADhB,WAAM,GAAN,MAAM,CAAQ;QACd,aAAQ,GAAR,QAAQ,CAAQ;IACvB,CAAC;IAEJ,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,GAAG,CAAI,IAAY,EAAE,MAA8D;QACvF,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,MAAM,EAAE,CAAC;YACX,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC5C,IAAI,CAAC,KAAK,SAAS;oBAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YAC1D,CAAC;QACH,CAAC;QACD,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE;YAC/C,OAAO,EAAE;gBACP,eAAe,EAAE,UAAU,IAAI,CAAC,QAAQ,EAAE;gBAC1C,eAAe,EAAE,KAAK;aACvB;SACF,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,aAAa,GAAG,CAAC,MAAM,KAAK,MAAM,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC7E,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAkC,CAAC;QACjE,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACxE,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,IAAI,CAAI,IAAY,EAAE,IAA8B;QACxD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QACvC,MAAM,OAAO,GAA2B;YACtC,eAAe,EAAE,UAAU,IAAI,CAAC,QAAQ,EAAE;YAC1C,eAAe,EAAE,KAAK;SACvB,CAAC;QACF,MAAM,IAAI,GAAgB,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;QACtD,IAAI,IAAI,EAAE,CAAC;YACT,OAAO,CAAC,cAAc,CAAC,GAAG,kBAAkB,CAAC;YAC7C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACnC,CAAC;QACD,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,IAAI,CAAC,CAAC;QACvD,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,aAAa,GAAG,CAAC,MAAM,KAAK,MAAM,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC7E,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAkC,CAAC;QACjE,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACxE,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,SAAiB,EAAE,QAAgB;QACnD,MAAM,IAAI,CAAC,IAAI,CAAC,aAAa,SAAS,YAAY,QAAQ,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC1E,CAAC;IAED,KAAK,CAAC,cAAc,CAClB,SAAiB,EACjB,QAAgB;QAQhB,OAAO,IAAI,CAAC,GAAG,CAAC,aAAa,SAAS,YAAY,QAAQ,cAAc,CAAC,CAAC;IAC5E,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,OAAe;QACnC,OAAO,IAAI,CAAC,GAAG,CAAC,WAAW,OAAO,UAAU,CAAC,CAAC;IAChD,CAAC;CACF"}
|
|
@@ -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 @@
|
|
|
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 @@
|
|
|
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"}
|