kantban-cli 0.1.8 → 0.1.11

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 (155) hide show
  1. package/dist/chunk-ZCUIGFSP.js +4111 -0
  2. package/dist/chunk-ZCUIGFSP.js.map +1 -0
  3. package/dist/context-7YDNTI3P.js +30 -0
  4. package/dist/context-7YDNTI3P.js.map +1 -0
  5. package/dist/cron-OKQP6QDF.js +112 -0
  6. package/dist/cron-OKQP6QDF.js.map +1 -0
  7. package/dist/index.d.ts +0 -2
  8. package/dist/index.js +179 -44
  9. package/dist/index.js.map +1 -1
  10. package/dist/pipeline-7LG74YA2.js +4098 -0
  11. package/dist/pipeline-7LG74YA2.js.map +1 -0
  12. package/dist/pipeline-init-IGZZOOLK.js +103 -0
  13. package/dist/pipeline-init-IGZZOOLK.js.map +1 -0
  14. package/dist/status-4GFXMVIM.js +128 -0
  15. package/dist/status-4GFXMVIM.js.map +1 -0
  16. package/dist/work-2V33NZAT.js +81 -0
  17. package/dist/work-2V33NZAT.js.map +1 -0
  18. package/package.json +5 -4
  19. package/dist/client.d.ts +0 -38
  20. package/dist/client.d.ts.map +0 -1
  21. package/dist/client.js +0 -163
  22. package/dist/client.js.map +0 -1
  23. package/dist/commands/context.d.ts +0 -3
  24. package/dist/commands/context.d.ts.map +0 -1
  25. package/dist/commands/context.js +0 -27
  26. package/dist/commands/context.js.map +0 -1
  27. package/dist/commands/cron.d.ts +0 -3
  28. package/dist/commands/cron.d.ts.map +0 -1
  29. package/dist/commands/cron.js +0 -106
  30. package/dist/commands/cron.js.map +0 -1
  31. package/dist/commands/pipeline-init.d.ts +0 -2
  32. package/dist/commands/pipeline-init.d.ts.map +0 -1
  33. package/dist/commands/pipeline-init.js +0 -100
  34. package/dist/commands/pipeline-init.js.map +0 -1
  35. package/dist/commands/pipeline.d.ts +0 -4
  36. package/dist/commands/pipeline.d.ts.map +0 -1
  37. package/dist/commands/pipeline.js +0 -1222
  38. package/dist/commands/pipeline.js.map +0 -1
  39. package/dist/commands/status.d.ts +0 -3
  40. package/dist/commands/status.d.ts.map +0 -1
  41. package/dist/commands/status.js +0 -135
  42. package/dist/commands/status.js.map +0 -1
  43. package/dist/commands/work.d.ts +0 -3
  44. package/dist/commands/work.d.ts.map +0 -1
  45. package/dist/commands/work.js +0 -76
  46. package/dist/commands/work.js.map +0 -1
  47. package/dist/index.d.ts.map +0 -1
  48. package/dist/lib/advisor.d.ts +0 -108
  49. package/dist/lib/advisor.d.ts.map +0 -1
  50. package/dist/lib/advisor.js +0 -139
  51. package/dist/lib/advisor.js.map +0 -1
  52. package/dist/lib/checkpoint.d.ts +0 -15
  53. package/dist/lib/checkpoint.d.ts.map +0 -1
  54. package/dist/lib/checkpoint.js +0 -49
  55. package/dist/lib/checkpoint.js.map +0 -1
  56. package/dist/lib/constraint-evaluator.d.ts +0 -40
  57. package/dist/lib/constraint-evaluator.d.ts.map +0 -1
  58. package/dist/lib/constraint-evaluator.js +0 -189
  59. package/dist/lib/constraint-evaluator.js.map +0 -1
  60. package/dist/lib/cost-tracker.d.ts +0 -46
  61. package/dist/lib/cost-tracker.d.ts.map +0 -1
  62. package/dist/lib/cost-tracker.js +0 -120
  63. package/dist/lib/cost-tracker.js.map +0 -1
  64. package/dist/lib/evaluator.d.ts +0 -17
  65. package/dist/lib/evaluator.d.ts.map +0 -1
  66. package/dist/lib/evaluator.js +0 -71
  67. package/dist/lib/evaluator.js.map +0 -1
  68. package/dist/lib/event-emitter.d.ts +0 -28
  69. package/dist/lib/event-emitter.d.ts.map +0 -1
  70. package/dist/lib/event-emitter.js +0 -100
  71. package/dist/lib/event-emitter.js.map +0 -1
  72. package/dist/lib/event-queue.d.ts +0 -28
  73. package/dist/lib/event-queue.d.ts.map +0 -1
  74. package/dist/lib/event-queue.js +0 -73
  75. package/dist/lib/event-queue.js.map +0 -1
  76. package/dist/lib/gate-config.d.ts +0 -7
  77. package/dist/lib/gate-config.d.ts.map +0 -1
  78. package/dist/lib/gate-config.js +0 -68
  79. package/dist/lib/gate-config.js.map +0 -1
  80. package/dist/lib/gate-proxy-server.d.ts +0 -16
  81. package/dist/lib/gate-proxy-server.d.ts.map +0 -1
  82. package/dist/lib/gate-proxy-server.js +0 -385
  83. package/dist/lib/gate-proxy-server.js.map +0 -1
  84. package/dist/lib/gate-proxy.d.ts +0 -46
  85. package/dist/lib/gate-proxy.d.ts.map +0 -1
  86. package/dist/lib/gate-proxy.js +0 -104
  87. package/dist/lib/gate-proxy.js.map +0 -1
  88. package/dist/lib/gate-runner.d.ts +0 -13
  89. package/dist/lib/gate-runner.d.ts.map +0 -1
  90. package/dist/lib/gate-runner.js +0 -104
  91. package/dist/lib/gate-runner.js.map +0 -1
  92. package/dist/lib/gate-snapshot.d.ts +0 -12
  93. package/dist/lib/gate-snapshot.d.ts.map +0 -1
  94. package/dist/lib/gate-snapshot.js +0 -49
  95. package/dist/lib/gate-snapshot.js.map +0 -1
  96. package/dist/lib/light-call.d.ts +0 -37
  97. package/dist/lib/light-call.d.ts.map +0 -1
  98. package/dist/lib/light-call.js +0 -62
  99. package/dist/lib/light-call.js.map +0 -1
  100. package/dist/lib/logger.d.ts +0 -22
  101. package/dist/lib/logger.d.ts.map +0 -1
  102. package/dist/lib/logger.js +0 -98
  103. package/dist/lib/logger.js.map +0 -1
  104. package/dist/lib/mcp-config.d.ts +0 -24
  105. package/dist/lib/mcp-config.d.ts.map +0 -1
  106. package/dist/lib/mcp-config.js +0 -115
  107. package/dist/lib/mcp-config.js.map +0 -1
  108. package/dist/lib/orchestrator.d.ts +0 -392
  109. package/dist/lib/orchestrator.d.ts.map +0 -1
  110. package/dist/lib/orchestrator.js +0 -1636
  111. package/dist/lib/orchestrator.js.map +0 -1
  112. package/dist/lib/parse-utils.d.ts +0 -6
  113. package/dist/lib/parse-utils.d.ts.map +0 -1
  114. package/dist/lib/parse-utils.js +0 -64
  115. package/dist/lib/parse-utils.js.map +0 -1
  116. package/dist/lib/prompt-composer.d.ts +0 -131
  117. package/dist/lib/prompt-composer.d.ts.map +0 -1
  118. package/dist/lib/prompt-composer.js +0 -317
  119. package/dist/lib/prompt-composer.js.map +0 -1
  120. package/dist/lib/ralph-loop.d.ts +0 -123
  121. package/dist/lib/ralph-loop.d.ts.map +0 -1
  122. package/dist/lib/ralph-loop.js +0 -383
  123. package/dist/lib/ralph-loop.js.map +0 -1
  124. package/dist/lib/reaper.d.ts +0 -14
  125. package/dist/lib/reaper.d.ts.map +0 -1
  126. package/dist/lib/reaper.js +0 -114
  127. package/dist/lib/reaper.js.map +0 -1
  128. package/dist/lib/replanner.d.ts +0 -49
  129. package/dist/lib/replanner.d.ts.map +0 -1
  130. package/dist/lib/replanner.js +0 -61
  131. package/dist/lib/replanner.js.map +0 -1
  132. package/dist/lib/run-memory.d.ts +0 -37
  133. package/dist/lib/run-memory.d.ts.map +0 -1
  134. package/dist/lib/run-memory.js +0 -115
  135. package/dist/lib/run-memory.js.map +0 -1
  136. package/dist/lib/stream-parser.d.ts +0 -20
  137. package/dist/lib/stream-parser.d.ts.map +0 -1
  138. package/dist/lib/stream-parser.js +0 -65
  139. package/dist/lib/stream-parser.js.map +0 -1
  140. package/dist/lib/stuck-detector.d.ts +0 -47
  141. package/dist/lib/stuck-detector.d.ts.map +0 -1
  142. package/dist/lib/stuck-detector.js +0 -105
  143. package/dist/lib/stuck-detector.js.map +0 -1
  144. package/dist/lib/tool-profiles.d.ts +0 -19
  145. package/dist/lib/tool-profiles.d.ts.map +0 -1
  146. package/dist/lib/tool-profiles.js +0 -22
  147. package/dist/lib/tool-profiles.js.map +0 -1
  148. package/dist/lib/worktree.d.ts +0 -12
  149. package/dist/lib/worktree.d.ts.map +0 -1
  150. package/dist/lib/worktree.js +0 -29
  151. package/dist/lib/worktree.js.map +0 -1
  152. package/dist/lib/ws-client.d.ts +0 -31
  153. package/dist/lib/ws-client.d.ts.map +0 -1
  154. package/dist/lib/ws-client.js +0 -113
  155. package/dist/lib/ws-client.js.map +0 -1
@@ -0,0 +1,30 @@
1
+ // src/commands/context.ts
2
+ async function runContext(client, args) {
3
+ const [scopeType, scopeId] = args;
4
+ if (!scopeType || !scopeId) {
5
+ console.error("Usage: kantban context <board|column|ticket> <id>");
6
+ process.exit(1);
7
+ }
8
+ const projectId = process.env["KANTBAN_PROJECT_ID"];
9
+ if (!projectId) {
10
+ console.error("Error: KANTBAN_PROJECT_ID environment variable required for context command");
11
+ process.exit(1);
12
+ }
13
+ const params = {};
14
+ if (scopeType === "board") params["boardId"] = scopeId;
15
+ else if (scopeType === "column") params["columnId"] = scopeId;
16
+ else if (scopeType === "ticket") params["ticketId"] = scopeId;
17
+ else {
18
+ console.error(`Unknown scope type: ${scopeType}. Use board, column, or ticket.`);
19
+ process.exit(1);
20
+ }
21
+ const data = await client.get(
22
+ `/projects/${projectId}/pipeline-context`,
23
+ params
24
+ );
25
+ console.log(JSON.stringify(data, null, 2));
26
+ }
27
+ export {
28
+ runContext
29
+ };
30
+ //# sourceMappingURL=context-7YDNTI3P.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/context.ts"],"sourcesContent":["import type { KantBanCLIClient } from '../client.js';\n\nexport async function runContext(client: KantBanCLIClient, args: string[]): Promise<void> {\n const [scopeType, scopeId] = args;\n if (!scopeType || !scopeId) {\n console.error('Usage: kantban context <board|column|ticket> <id>');\n process.exit(1);\n }\n\n const projectId = process.env['KANTBAN_PROJECT_ID'];\n if (!projectId) {\n console.error('Error: KANTBAN_PROJECT_ID environment variable required for context command');\n process.exit(1);\n }\n\n const params: Record<string, string> = {};\n if (scopeType === 'board') params['boardId'] = scopeId;\n else if (scopeType === 'column') params['columnId'] = scopeId;\n else if (scopeType === 'ticket') params['ticketId'] = scopeId;\n else {\n console.error(`Unknown scope type: ${scopeType}. Use board, column, or ticket.`);\n process.exit(1);\n }\n\n const data = await client.get<Record<string, unknown>>(\n `/projects/${projectId}/pipeline-context`,\n params,\n );\n\n // Output as structured JSON to stdout for piping\n console.log(JSON.stringify(data, null, 2));\n}\n"],"mappings":";AAEA,eAAsB,WAAW,QAA0B,MAA+B;AACxF,QAAM,CAAC,WAAW,OAAO,IAAI;AAC7B,MAAI,CAAC,aAAa,CAAC,SAAS;AAC1B,YAAQ,MAAM,mDAAmD;AACjE,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,YAAY,QAAQ,IAAI,oBAAoB;AAClD,MAAI,CAAC,WAAW;AACd,YAAQ,MAAM,6EAA6E;AAC3F,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,SAAiC,CAAC;AACxC,MAAI,cAAc,QAAS,QAAO,SAAS,IAAI;AAAA,WACtC,cAAc,SAAU,QAAO,UAAU,IAAI;AAAA,WAC7C,cAAc,SAAU,QAAO,UAAU,IAAI;AAAA,OACjD;AACH,YAAQ,MAAM,uBAAuB,SAAS,iCAAiC;AAC/E,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,OAAO,MAAM,OAAO;AAAA,IACxB,aAAa,SAAS;AAAA,IACtB;AAAA,EACF;AAGA,UAAQ,IAAI,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAC3C;","names":[]}
@@ -0,0 +1,112 @@
1
+ import {
2
+ RalphLoop,
3
+ cleanupMcpConfig,
4
+ generateMcpConfig
5
+ } from "./chunk-ZCUIGFSP.js";
6
+
7
+ // src/commands/cron.ts
8
+ import { execFile } from "child_process";
9
+ import { promisify } from "util";
10
+ var execFileAsync = promisify(execFile);
11
+ function parseDuration(input) {
12
+ const match = input.match(/^(\d+)(s|m|h)$/);
13
+ if (!match) throw new Error(`Invalid duration: ${input}. Use format like 5m, 30s, 1h`);
14
+ const value = Number(match[1]);
15
+ const unit = match[2];
16
+ switch (unit) {
17
+ case "s":
18
+ return value * 1e3;
19
+ case "m":
20
+ return value * 60 * 1e3;
21
+ case "h":
22
+ return value * 60 * 60 * 1e3;
23
+ default:
24
+ throw new Error(`Unknown unit: ${unit}`);
25
+ }
26
+ }
27
+ async function runCron(client, args) {
28
+ const columnId = args[0];
29
+ if (!columnId) {
30
+ console.error("Usage: kantban cron <column-id> [--interval 5m]");
31
+ process.exit(1);
32
+ }
33
+ let intervalMs = 5 * 60 * 1e3;
34
+ const intervalIdx = args.indexOf("--interval");
35
+ const intervalArg = intervalIdx !== -1 ? args[intervalIdx + 1] : void 0;
36
+ if (intervalArg) {
37
+ intervalMs = parseDuration(intervalArg);
38
+ }
39
+ const projectId = process.env["KANTBAN_PROJECT_ID"];
40
+ if (!projectId) {
41
+ console.error("Error: KANTBAN_PROJECT_ID required");
42
+ process.exit(1);
43
+ }
44
+ const mcpConfigPath = generateMcpConfig(client.baseUrl, client.token, `cron-${columnId}`);
45
+ async function invokeClaudeP(prompt, options) {
46
+ const claudeArgs = ["-p", prompt, "--mcp-config", options.mcpConfigPath, "--dangerously-skip-permissions"];
47
+ if (options.model) claudeArgs.push("--model", options.model);
48
+ try {
49
+ const { stdout } = await execFileAsync("claude", claudeArgs, { maxBuffer: 10 * 1024 * 1024 });
50
+ return { exitCode: 0, output: stdout, toolCallCount: 0, tokensIn: 0, tokensOut: 0 };
51
+ } catch (err) {
52
+ const execErr = err;
53
+ return { exitCode: execErr.code ?? 1, output: execErr.stdout ?? execErr.message ?? "", toolCallCount: 0, tokensIn: 0, tokensOut: 0 };
54
+ }
55
+ }
56
+ let stopped = false;
57
+ const shutdown = () => {
58
+ stopped = true;
59
+ cleanupMcpConfig(mcpConfigPath);
60
+ console.log("\nCron stopped.");
61
+ process.exit(0);
62
+ };
63
+ process.on("SIGTERM", shutdown);
64
+ process.on("SIGINT", shutdown);
65
+ console.log(`Cron: column ${columnId}, interval ${String(intervalMs / 1e3)}s`);
66
+ console.log("Press Ctrl+C to stop.\n");
67
+ const tick = async () => {
68
+ if (stopped) return;
69
+ try {
70
+ const columnScope = await client.get(
71
+ `/projects/${projectId}/pipeline-context`,
72
+ { columnId }
73
+ );
74
+ const tickets = columnScope.tickets ?? [];
75
+ if (tickets.length === 0) {
76
+ console.log(`[${(/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false })}] No tickets in column. Sleeping...`);
77
+ return;
78
+ }
79
+ console.log(`[${(/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false })}] Processing ${String(tickets.length)} ticket(s)...`);
80
+ for (const ticket of tickets) {
81
+ if (stopped) break;
82
+ const deps = {
83
+ fetchTicketContext: (tid) => client.get(
84
+ `/projects/${projectId}/pipeline-context`,
85
+ { ticketId: tid }
86
+ ),
87
+ fetchColumnContext: (cid) => client.get(
88
+ `/projects/${projectId}/pipeline-context`,
89
+ { columnId: cid }
90
+ ),
91
+ fetchFingerprint: (tid) => client.getFingerprint(projectId, tid),
92
+ invokeClaudeP,
93
+ mcpConfigPath,
94
+ projectId
95
+ };
96
+ const config = { maxIterations: 1, gutterThreshold: 1 };
97
+ const loop = new RalphLoop(ticket.id, columnId, config, deps);
98
+ const result = await loop.run();
99
+ console.log(` ${String(ticket.ticket_number)}: ${result.reason} (${String(result.iterations)} iter)`);
100
+ }
101
+ } catch (err) {
102
+ const message = err instanceof Error ? err.message : String(err);
103
+ console.error(`Cron tick error: ${message}`);
104
+ }
105
+ };
106
+ await tick();
107
+ setInterval(() => void tick(), intervalMs);
108
+ }
109
+ export {
110
+ runCron
111
+ };
112
+ //# sourceMappingURL=cron-OKQP6QDF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/cron.ts"],"sourcesContent":["import { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport type { KantBanCLIClient } from '../client.js';\nimport { generateMcpConfig, cleanupMcpConfig } from '../lib/mcp-config.js';\nimport { RalphLoop, type RalphLoopDeps, type LoopConfig, type ClaudeInvokeOptions } from '../lib/ralph-loop.js';\nimport type { ColumnContext, TicketContext } from '../lib/prompt-composer.js';\nimport type { TicketFingerprint } from '@kantban/types';\n\nconst execFileAsync = promisify(execFile);\n\nfunction parseDuration(input: string): number {\n const match = input.match(/^(\\d+)(s|m|h)$/);\n if (!match) throw new Error(`Invalid duration: ${input}. Use format like 5m, 30s, 1h`);\n const value = Number(match[1]);\n const unit = match[2];\n switch (unit) {\n case 's': return value * 1000;\n case 'm': return value * 60 * 1000;\n case 'h': return value * 60 * 60 * 1000;\n default: throw new Error(`Unknown unit: ${unit}`);\n }\n}\n\nexport async function runCron(client: KantBanCLIClient, args: string[]): Promise<void> {\n const columnId = args[0];\n if (!columnId) {\n console.error('Usage: kantban cron <column-id> [--interval 5m]');\n process.exit(1);\n }\n\n // Parse interval\n let intervalMs = 5 * 60 * 1000; // default 5m\n const intervalIdx = args.indexOf('--interval');\n const intervalArg = intervalIdx !== -1 ? args[intervalIdx + 1] : undefined;\n if (intervalArg) {\n intervalMs = parseDuration(intervalArg);\n }\n\n // Resolve project ID\n const projectId = process.env['KANTBAN_PROJECT_ID'];\n if (!projectId) {\n console.error('Error: KANTBAN_PROJECT_ID required');\n process.exit(1);\n }\n\n // Generate MCP config (stable path keyed by column)\n const mcpConfigPath = generateMcpConfig(client.baseUrl, client.token, `cron-${columnId}`);\n\n // invokeClaudeP helper (same pattern as pipeline.ts)\n async function invokeClaudeP(prompt: string, options: ClaudeInvokeOptions): Promise<{ exitCode: number; output: string; toolCallCount: number; tokensIn: number; tokensOut: number }> {\n const claudeArgs = ['-p', prompt, '--mcp-config', options.mcpConfigPath, '--dangerously-skip-permissions'];\n if (options.model) claudeArgs.push('--model', options.model);\n try {\n const { stdout } = await execFileAsync('claude', claudeArgs, { maxBuffer: 10 * 1024 * 1024 });\n return { exitCode: 0, output: stdout, toolCallCount: 0, tokensIn: 0, tokensOut: 0 };\n } catch (err: unknown) {\n const execErr = err as { code?: number; stdout?: string; message?: string };\n return { exitCode: execErr.code ?? 1, output: execErr.stdout ?? execErr.message ?? '', toolCallCount: 0, tokensIn: 0, tokensOut: 0 };\n }\n }\n\n let stopped = false;\n\n // Graceful shutdown\n const shutdown = () => {\n stopped = true;\n cleanupMcpConfig(mcpConfigPath);\n console.log('\\nCron stopped.');\n process.exit(0);\n };\n process.on('SIGTERM', shutdown);\n process.on('SIGINT', shutdown);\n\n console.log(`Cron: column ${columnId}, interval ${String(intervalMs / 1000)}s`);\n console.log('Press Ctrl+C to stop.\\n');\n\n // Main cron tick\n const tick = async () => {\n if (stopped) return;\n\n try {\n // Fetch column scope\n const columnScope = await client.get<ColumnContext>(\n `/projects/${projectId}/pipeline-context`,\n { columnId },\n );\n\n const tickets = columnScope.tickets ?? [];\n if (tickets.length === 0) {\n console.log(`[${new Date().toLocaleTimeString('en-US', { hour12: false })}] No tickets in column. Sleeping...`);\n return;\n }\n\n console.log(`[${new Date().toLocaleTimeString('en-US', { hour12: false })}] Processing ${String(tickets.length)} ticket(s)...`);\n\n // Process each ticket sequentially (one iteration each for cron)\n for (const ticket of tickets) {\n if (stopped) break;\n\n const deps: RalphLoopDeps = {\n fetchTicketContext: (tid) => client.get<TicketContext>(\n `/projects/${projectId}/pipeline-context`, { ticketId: tid },\n ),\n fetchColumnContext: (cid) => client.get<ColumnContext>(\n `/projects/${projectId}/pipeline-context`, { columnId: cid },\n ),\n fetchFingerprint: (tid) => client.getFingerprint(projectId, tid) as Promise<TicketFingerprint>,\n invokeClaudeP,\n mcpConfigPath,\n projectId,\n };\n\n const config: LoopConfig = { maxIterations: 1, gutterThreshold: 1 };\n\n const loop = new RalphLoop(ticket.id, columnId, config, deps);\n const result = await loop.run();\n console.log(` ${String(ticket.ticket_number)}: ${result.reason} (${String(result.iterations)} iter)`);\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`Cron tick error: ${message}`);\n }\n };\n\n // Run immediately, then on interval\n await tick();\n setInterval(() => void tick(), intervalMs);\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.ts CHANGED
@@ -1,3 +1 @@
1
1
  #!/usr/bin/env node
2
- export {};
3
- //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,48 +1,183 @@
1
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'];
2
+
3
+ // src/client.ts
4
+ var REQUEST_TIMEOUT_MS = 3e4;
5
+ var MAX_RETRIES = 2;
6
+ var RETRY_BASE_MS = 500;
7
+ function isRetryableStatus(status) {
8
+ return status >= 500 || status === 429;
9
+ }
10
+ async function fetchWithRetry(url, init, retries = MAX_RETRIES, _sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))) {
11
+ let lastError;
12
+ for (let attempt = 0; attempt <= retries; attempt++) {
13
+ const controller = new AbortController();
14
+ const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
15
+ try {
16
+ const res = await fetch(url, { ...init, signal: controller.signal });
17
+ clearTimeout(timer);
18
+ if (res.ok || !isRetryableStatus(res.status)) {
19
+ return res;
20
+ }
21
+ lastError = new Error(`API error ${res.status}: ${await res.text()}`);
22
+ } catch (err) {
23
+ clearTimeout(timer);
24
+ lastError = err;
25
+ }
26
+ if (attempt < retries) {
27
+ const delay = RETRY_BASE_MS * 2 ** attempt * (1 + Math.random() * 0.5);
28
+ await _sleep(delay);
29
+ }
30
+ }
31
+ throw lastError;
32
+ }
33
+ var KantBanCLIClient = class {
34
+ constructor(apiUrl2, apiToken2) {
35
+ this.apiUrl = apiUrl2;
36
+ this.apiToken = apiToken2;
37
+ }
38
+ get baseUrl() {
39
+ return this.apiUrl;
40
+ }
41
+ get token() {
42
+ return this.apiToken;
43
+ }
44
+ async get(path, params) {
45
+ const url = new URL(path, this.apiUrl);
46
+ if (params) {
47
+ for (const [k, v] of Object.entries(params)) {
48
+ if (v !== void 0) url.searchParams.set(k, String(v));
49
+ }
50
+ }
51
+ const res = await fetchWithRetry(url.toString(), {
52
+ headers: {
53
+ "Authorization": `Bearer ${this.apiToken}`,
54
+ "X-KantBan-Via": "cli"
55
+ }
56
+ });
57
+ if (!res.ok) throw new Error(`API error ${res.status}: ${await res.text()}`);
58
+ const json = await res.json();
59
+ if (!json.success) throw new Error(`API responded with success: false`);
60
+ return json.data;
61
+ }
62
+ async post(path, body) {
63
+ const url = new URL(path, this.apiUrl);
64
+ const headers = {
65
+ "Authorization": `Bearer ${this.apiToken}`,
66
+ "X-KantBan-Via": "cli"
67
+ };
68
+ const init = { method: "POST", headers };
69
+ if (body) {
70
+ headers["Content-Type"] = "application/json";
71
+ init.body = JSON.stringify(body);
72
+ }
73
+ const res = await fetchWithRetry(url.toString(), init);
74
+ if (!res.ok) throw new Error(`API error ${res.status}: ${await res.text()}`);
75
+ const json = await res.json();
76
+ if (!json.success) throw new Error(`API responded with success: false`);
77
+ return json.data;
78
+ }
79
+ async claimTicket(projectId, ticketId) {
80
+ await this.post(`/projects/${projectId}/tickets/${ticketId}/start`, {});
81
+ }
82
+ async getFingerprint(projectId, ticketId) {
83
+ return this.get(`/projects/${projectId}/tickets/${ticketId}/fingerprint`);
84
+ }
85
+ async put(path, body) {
86
+ const url = new URL(path, this.apiUrl);
87
+ const headers = {
88
+ "Authorization": `Bearer ${this.apiToken}`,
89
+ "X-KantBan-Via": "cli"
90
+ };
91
+ const init = { method: "PUT", headers };
92
+ if (body) {
93
+ headers["Content-Type"] = "application/json";
94
+ init.body = JSON.stringify(body);
95
+ }
96
+ const res = await fetchWithRetry(url.toString(), init);
97
+ if (!res.ok) throw new Error(`API error ${res.status}: ${await res.text()}`);
98
+ const json = await res.json();
99
+ if (!json.success) throw new Error(`API responded with success: false`);
100
+ return json.data;
101
+ }
102
+ async patch(path, body) {
103
+ const url = new URL(path, this.apiUrl);
104
+ const headers = {
105
+ "Authorization": `Bearer ${this.apiToken}`,
106
+ "X-KantBan-Via": "cli"
107
+ };
108
+ const init = { method: "PATCH", headers };
109
+ if (body) {
110
+ headers["Content-Type"] = "application/json";
111
+ init.body = JSON.stringify(body);
112
+ }
113
+ const res = await fetchWithRetry(url.toString(), init);
114
+ if (!res.ok) throw new Error(`API error ${res.status}: ${await res.text()}`);
115
+ const json = await res.json();
116
+ if (!json.success) throw new Error(`API responded with success: false`);
117
+ return json.data;
118
+ }
119
+ async delete(path) {
120
+ const url = new URL(path, this.apiUrl);
121
+ const res = await fetchWithRetry(url.toString(), {
122
+ method: "DELETE",
123
+ headers: {
124
+ "Authorization": `Bearer ${this.apiToken}`,
125
+ "X-KantBan-Via": "cli"
126
+ }
127
+ });
128
+ if (!res.ok) throw new Error(`API error ${res.status}: ${await res.text()}`);
129
+ const json = await res.json();
130
+ if (!json.success) throw new Error(`API responded with success: false`);
131
+ return json.data;
132
+ }
133
+ async getBoardProject(boardId) {
134
+ return this.get(`/boards/${boardId}/project`);
135
+ }
136
+ };
137
+
138
+ // src/index.ts
139
+ var apiToken = process.env["KANTBAN_API_TOKEN"];
140
+ var apiUrl = process.env["KANTBAN_API_URL"];
5
141
  if (!apiToken || !apiUrl) {
6
- console.error('Error: KANTBAN_API_TOKEN and KANTBAN_API_URL environment variables are required');
7
- process.exit(1);
142
+ console.error("Error: KANTBAN_API_TOKEN and KANTBAN_API_URL environment variables are required");
143
+ process.exit(1);
8
144
  }
9
- const client = new KantBanCLIClient(apiUrl, apiToken);
10
- const [command, ...args] = process.argv.slice(2);
145
+ var client = new KantBanCLIClient(apiUrl, apiToken);
146
+ var [command, ...args] = process.argv.slice(2);
11
147
  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
148
+ switch (command) {
149
+ case "context": {
150
+ const { runContext } = await import("./context-7YDNTI3P.js");
151
+ await runContext(client, args);
152
+ break;
153
+ }
154
+ case "status": {
155
+ const { runStatus } = await import("./status-4GFXMVIM.js");
156
+ await runStatus(client, args);
157
+ break;
158
+ }
159
+ case "work": {
160
+ const { runWork } = await import("./work-2V33NZAT.js");
161
+ await runWork(client, args);
162
+ break;
163
+ }
164
+ case "pipeline": {
165
+ if (args[0] === "stop") {
166
+ const { stopPipeline } = await import("./pipeline-7LG74YA2.js");
167
+ await stopPipeline(args.slice(1));
168
+ } else {
169
+ const { runPipeline } = await import("./pipeline-7LG74YA2.js");
170
+ await runPipeline(client, args);
171
+ }
172
+ break;
173
+ }
174
+ case "cron": {
175
+ const { runCron } = await import("./cron-OKQP6QDF.js");
176
+ await runCron(client, args);
177
+ break;
178
+ }
179
+ default:
180
+ console.log(`kantban CLI \u2014 Pipeline orchestration for KantBan
46
181
 
47
182
  Usage:
48
183
  kantban context <scope-type> <scope-id> Output scoped pipeline context to stdout
@@ -56,10 +191,10 @@ Environment:
56
191
  KANTBAN_API_TOKEN API token (required)
57
192
  KANTBAN_API_URL API URL (required)
58
193
  KANTBAN_PROJECT_ID Default project ID (optional)`);
59
- }
194
+ }
60
195
  }
61
196
  main().catch((err) => {
62
- console.error('Error:', err.message);
63
- process.exit(1);
197
+ console.error("Error:", err.message);
198
+ process.exit(1);
64
199
  });
65
200
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +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"}
1
+ {"version":3,"sources":["../src/client.ts","../src/index.ts"],"sourcesContent":["// ── retry / timeout constants ─────────────────────────────────────────────\n\nexport const REQUEST_TIMEOUT_MS = 30_000;\nexport const MAX_RETRIES = 2;\nexport const RETRY_BASE_MS = 500;\n\n/** Returns true for statuses that are worth retrying (server errors + rate limit). */\nexport function isRetryableStatus(status: number): boolean {\n return status >= 500 || status === 429;\n}\n\n/**\n * Wraps `fetch` with:\n * - Per-request AbortController timeout (REQUEST_TIMEOUT_MS)\n * - Exponential backoff with jitter on retryable failures\n * - Up to MAX_RETRIES retries (so MAX_RETRIES + 1 total attempts)\n *\n * @param _sleep — optional override for the backoff sleep (used in tests to avoid real delays)\n */\nexport async function fetchWithRetry(\n url: string,\n init: RequestInit,\n retries = MAX_RETRIES,\n _sleep: (ms: number) => Promise<void> = (ms) =>\n new Promise((resolve) => setTimeout(resolve, ms)),\n): Promise<Response> {\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= retries; attempt++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);\n\n try {\n const res = await fetch(url, { ...init, signal: controller.signal });\n clearTimeout(timer);\n\n // Non-retryable: 2xx (ok) or any non-retryable error status\n if (res.ok || !isRetryableStatus(res.status)) {\n return res;\n }\n\n // Retryable status — treat as a transient failure\n lastError = new Error(`API error ${res.status}: ${await res.text()}`);\n } catch (err) {\n clearTimeout(timer);\n lastError = err;\n // Only retry on network/abort errors, not on logic errors\n }\n\n if (attempt < retries) {\n // Exponential backoff with up to 50% random jitter\n const delay = RETRY_BASE_MS * 2 ** attempt * (1 + Math.random() * 0.5);\n await _sleep(delay);\n }\n }\n\n throw lastError;\n}\n\n// ── client ────────────────────────────────────────────────────────────────\n\nexport class KantBanCLIClient {\n constructor(\n private apiUrl: string,\n private apiToken: string,\n ) {}\n\n get baseUrl(): string {\n return this.apiUrl;\n }\n\n get token(): string {\n return this.apiToken;\n }\n\n async get<T>(path: string, params?: Record<string, string | number | boolean | undefined>): Promise<T> {\n const url = new URL(path, this.apiUrl);\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined) url.searchParams.set(k, String(v));\n }\n }\n const res = await fetchWithRetry(url.toString(), {\n headers: {\n 'Authorization': `Bearer ${this.apiToken}`,\n 'X-KantBan-Via': 'cli',\n },\n });\n if (!res.ok) throw new Error(`API error ${res.status}: ${await res.text()}`);\n const json = (await res.json()) as { success: boolean; data: T };\n if (!json.success) throw new Error(`API responded with success: false`);\n return json.data;\n }\n\n async post<T>(path: string, body?: Record<string, unknown>): Promise<T> {\n const url = new URL(path, this.apiUrl);\n const headers: Record<string, string> = {\n 'Authorization': `Bearer ${this.apiToken}`,\n 'X-KantBan-Via': 'cli',\n };\n const init: RequestInit = { method: 'POST', headers };\n if (body) {\n headers['Content-Type'] = 'application/json';\n init.body = JSON.stringify(body);\n }\n const res = await fetchWithRetry(url.toString(), init);\n if (!res.ok) throw new Error(`API error ${res.status}: ${await res.text()}`);\n const json = (await res.json()) as { success: boolean; data: T };\n if (!json.success) throw new Error(`API responded with success: false`);\n return json.data;\n }\n\n async claimTicket(projectId: string, ticketId: string): Promise<void> {\n await this.post(`/projects/${projectId}/tickets/${ticketId}/start`, {});\n }\n\n async getFingerprint(\n projectId: string,\n ticketId: string,\n ): Promise<{\n column_id: string | null;\n updated_at: string;\n comment_count: number;\n signal_count: number;\n field_value_count: number;\n }> {\n return this.get(`/projects/${projectId}/tickets/${ticketId}/fingerprint`);\n }\n\n async put<T>(path: string, body?: Record<string, unknown>): Promise<T> {\n const url = new URL(path, this.apiUrl);\n const headers: Record<string, string> = {\n 'Authorization': `Bearer ${this.apiToken}`,\n 'X-KantBan-Via': 'cli',\n };\n const init: RequestInit = { method: 'PUT', headers };\n if (body) {\n headers['Content-Type'] = 'application/json';\n init.body = JSON.stringify(body);\n }\n const res = await fetchWithRetry(url.toString(), init);\n if (!res.ok) throw new Error(`API error ${res.status}: ${await res.text()}`);\n const json = (await res.json()) as { success: boolean; data: T };\n if (!json.success) throw new Error(`API responded with success: false`);\n return json.data;\n }\n\n async patch<T>(path: string, body?: Record<string, unknown>): Promise<T> {\n const url = new URL(path, this.apiUrl);\n const headers: Record<string, string> = {\n 'Authorization': `Bearer ${this.apiToken}`,\n 'X-KantBan-Via': 'cli',\n };\n const init: RequestInit = { method: 'PATCH', headers };\n if (body) {\n headers['Content-Type'] = 'application/json';\n init.body = JSON.stringify(body);\n }\n const res = await fetchWithRetry(url.toString(), init);\n if (!res.ok) throw new Error(`API error ${res.status}: ${await res.text()}`);\n const json = (await res.json()) as { success: boolean; data: T };\n if (!json.success) throw new Error(`API responded with success: false`);\n return json.data;\n }\n\n async delete<T = unknown>(path: string): Promise<T> {\n const url = new URL(path, this.apiUrl);\n const res = await fetchWithRetry(url.toString(), {\n method: 'DELETE',\n headers: {\n 'Authorization': `Bearer ${this.apiToken}`,\n 'X-KantBan-Via': 'cli',\n },\n });\n if (!res.ok) throw new Error(`API error ${res.status}: ${await res.text()}`);\n const json = (await res.json()) as { success: boolean; data: T };\n if (!json.success) throw new Error(`API responded with success: false`);\n return json.data;\n }\n\n async getBoardProject(boardId: string): Promise<{ project_id: string }> {\n return this.get(`/boards/${boardId}/project`);\n }\n}\n","#!/usr/bin/env node\nimport { KantBanCLIClient } from './client.js';\n\nconst apiToken = process.env['KANTBAN_API_TOKEN'];\nconst apiUrl = process.env['KANTBAN_API_URL'];\n\nif (!apiToken || !apiUrl) {\n console.error('Error: KANTBAN_API_TOKEN and KANTBAN_API_URL environment variables are required');\n process.exit(1);\n}\n\nconst client = new KantBanCLIClient(apiUrl, apiToken);\nconst [command, ...args] = process.argv.slice(2);\n\nasync function main() {\n switch (command) {\n case 'context': {\n const { runContext } = await import('./commands/context.js');\n await runContext(client, args);\n break;\n }\n case 'status': {\n const { runStatus } = await import('./commands/status.js');\n await runStatus(client, args);\n break;\n }\n case 'work': {\n const { runWork } = await import('./commands/work.js');\n await runWork(client, args);\n break;\n }\n case 'pipeline': {\n if (args[0] === 'stop') {\n const { stopPipeline } = await import('./commands/pipeline.js');\n await stopPipeline(args.slice(1));\n } else {\n const { runPipeline } = await import('./commands/pipeline.js');\n await runPipeline(client, args);\n }\n break;\n }\n case 'cron': {\n const { runCron } = await import('./commands/cron.js');\n await runCron(client, args);\n break;\n }\n default:\n console.log(`kantban CLI — Pipeline orchestration for KantBan\n\nUsage:\n kantban context <scope-type> <scope-id> Output scoped pipeline context to stdout\n kantban status <board-id> Pipeline health at a glance\n kantban work <ticket-id> Start a Claude session for a ticket\n kantban pipeline <board-id> Persistent pipeline orchestrator\n kantban pipeline stop <board-id> Stop running pipeline\n kantban cron <column-id> [--interval 5m] Run single column on a timer\n\nEnvironment:\n KANTBAN_API_TOKEN API token (required)\n KANTBAN_API_URL API URL (required)\n KANTBAN_PROJECT_ID Default project ID (optional)`);\n }\n}\n\nmain().catch((err: Error) => {\n console.error('Error:', err.message);\n process.exit(1);\n});\n"],"mappings":"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","names":["apiUrl","apiToken"]}