kantban-cli 0.1.18 → 0.1.20

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.
@@ -3,8 +3,8 @@ import {
3
3
  RalphLoop,
4
4
  cleanupMcpConfig,
5
5
  generateMcpConfig
6
- } from "./chunk-2EJEOAGB.js";
7
- import "./chunk-MN4H5NSU.js";
6
+ } from "./chunk-D4T7ZUWI.js";
7
+ import "./chunk-ZTQJMXJM.js";
8
8
 
9
9
  // src/commands/cron.ts
10
10
  import { readFileSync } from "fs";
@@ -101,4 +101,4 @@ async function runCron(client, args) {
101
101
  export {
102
102
  runCron
103
103
  };
104
- //# sourceMappingURL=cron-273WBN3N.js.map
104
+ //# sourceMappingURL=cron-722GUOUP.js.map
package/dist/index.js CHANGED
@@ -31,16 +31,16 @@ async function main() {
31
31
  }
32
32
  case "pipeline": {
33
33
  if (args[0] === "stop") {
34
- const { stopPipeline } = await import("./pipeline-KAIEIIIC.js");
34
+ const { stopPipeline } = await import("./pipeline-FMDQGNHO.js");
35
35
  await stopPipeline(args.slice(1));
36
36
  } else {
37
- const { runPipeline } = await import("./pipeline-KAIEIIIC.js");
37
+ const { runPipeline } = await import("./pipeline-FMDQGNHO.js");
38
38
  await runPipeline(client, args);
39
39
  }
40
40
  break;
41
41
  }
42
42
  case "cron": {
43
- const { runCron } = await import("./cron-273WBN3N.js");
43
+ const { runCron } = await import("./cron-722GUOUP.js");
44
44
  await runCron(client, args);
45
45
  break;
46
46
  }
@@ -5,12 +5,12 @@ import {
5
5
  import {
6
6
  formatGateErrors,
7
7
  runGates
8
- } from "../chunk-4IUZAIFL.js";
8
+ } from "../chunk-APZG5K2J.js";
9
9
  import {
10
10
  parseGateConfig,
11
11
  parseTimeout,
12
12
  resolveGatesForColumn
13
- } from "../chunk-MN4H5NSU.js";
13
+ } from "../chunk-ZTQJMXJM.js";
14
14
 
15
15
  // src/lib/gate-proxy-server.ts
16
16
  import { readFileSync } from "fs";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  runGates
3
- } from "./chunk-4IUZAIFL.js";
3
+ } from "./chunk-APZG5K2J.js";
4
4
  import {
5
5
  ClaudeProvider,
6
6
  RalphLoop,
@@ -12,14 +12,14 @@ import {
12
12
  generateMcpConfig,
13
13
  parseJsonFromLlmOutput,
14
14
  parseStuckDetectionResponse
15
- } from "./chunk-2EJEOAGB.js";
15
+ } from "./chunk-D4T7ZUWI.js";
16
16
  import {
17
17
  LoopCheckpointSchema,
18
18
  VerdictSchema,
19
19
  parseGateConfig,
20
20
  parseTimeout,
21
21
  resolveGatesForColumn
22
- } from "./chunk-MN4H5NSU.js";
22
+ } from "./chunk-ZTQJMXJM.js";
23
23
 
24
24
  // src/commands/pipeline.ts
25
25
  import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync3, readFileSync as readFileSync2, unlinkSync as unlinkSync2, existsSync as existsSync2, appendFileSync as appendFileSync2 } from "fs";
@@ -2214,12 +2214,28 @@ var EventQueue = class {
2214
2214
 
2215
2215
  // src/lib/ws-client.ts
2216
2216
  import WebSocket from "ws";
2217
- var PipelineWsClient = class {
2217
+ var PipelineWsClient = class _PipelineWsClient {
2218
2218
  ws = null;
2219
2219
  client;
2220
2220
  options;
2221
2221
  pingTimer = null;
2222
+ reconnectTimer = null;
2223
+ reconnectAttempt = 0;
2224
+ lastPong = 0;
2222
2225
  stopped = false;
2226
+ sendBuffer = [];
2227
+ static CRITICAL_TYPES = /* @__PURE__ */ new Set([
2228
+ "pipeline:session-start",
2229
+ "pipeline:session-end",
2230
+ "pipeline:stopped",
2231
+ "board:subscribe"
2232
+ ]);
2233
+ static BUFFER_MAX = 100;
2234
+ static BUFFER_TTL_MS = 3e4;
2235
+ // 30 seconds
2236
+ static PING_INTERVAL_MS = 3e4;
2237
+ static PONG_TIMEOUT_MS = 45e3;
2238
+ // dead if no pong in 45s
2223
2239
  constructor(client, options) {
2224
2240
  this.client = client;
2225
2241
  this.options = options;
@@ -2237,22 +2253,35 @@ var PipelineWsClient = class {
2237
2253
  }
2238
2254
  this.ws = null;
2239
2255
  }
2240
- this.cleanupPing();
2256
+ this.cleanupTimers();
2241
2257
  const { ticket } = await this.client.post("/ws-ticket");
2242
- const wsUrl = this.client.baseUrl.replace(/^http/, "ws") + `/ws?ticket=${ticket}`;
2258
+ const wsUrl = this.client.baseUrl.replace(/^http/, "ws") + `/ws?ticket=${ticket}&clientType=cli`;
2243
2259
  return new Promise((resolve, reject) => {
2244
2260
  let resolved = false;
2245
2261
  this.ws = new WebSocket(wsUrl);
2246
2262
  let subscribed = false;
2247
2263
  this.ws.on("open", () => {
2248
- this.pingTimer = setInterval(() => this.send({ type: "ping", payload: {} }), 3e4);
2264
+ this.lastPong = Date.now();
2265
+ this.reconnectAttempt = 0;
2266
+ this.pingTimer = setInterval(() => {
2267
+ if (Date.now() - this.lastPong > _PipelineWsClient.PONG_TIMEOUT_MS) {
2268
+ console.warn("[WS] No pong in 45s \u2014 connection dead, forcing reconnect");
2269
+ this.ws?.close();
2270
+ return;
2271
+ }
2272
+ this.send({ type: "ping", payload: {} });
2273
+ }, _PipelineWsClient.PING_INTERVAL_MS);
2249
2274
  });
2250
2275
  this.ws.on("message", (data) => {
2251
2276
  try {
2252
2277
  const event = JSON.parse(data.toString());
2278
+ if (event.type === "pong") {
2279
+ this.lastPong = Date.now();
2280
+ }
2253
2281
  if (!subscribed) {
2254
2282
  subscribed = true;
2255
2283
  this.send({ type: "board:subscribe", payload: { boardId: this.options.boardId, projectId: this.options.projectId } });
2284
+ this.flushBuffer();
2256
2285
  this.options.onConnect();
2257
2286
  if (!resolved) {
2258
2287
  resolved = true;
@@ -2265,11 +2294,13 @@ var PipelineWsClient = class {
2265
2294
  }
2266
2295
  });
2267
2296
  this.ws.on("close", (code) => {
2268
- this.cleanupPing();
2297
+ this.cleanupTimers();
2269
2298
  this.options.onDisconnect();
2270
2299
  if (!resolved) {
2271
2300
  resolved = true;
2272
2301
  reject(new Error(`WebSocket closed before handshake (code ${code})`));
2302
+ } else {
2303
+ this.scheduleReconnect();
2273
2304
  }
2274
2305
  });
2275
2306
  this.ws.on("error", (err) => {
@@ -2294,8 +2325,9 @@ var PipelineWsClient = class {
2294
2325
  }
2295
2326
  }
2296
2327
  stop() {
2328
+ this.sendBuffer = [];
2297
2329
  this.stopped = true;
2298
- this.cleanupPing();
2330
+ this.cleanupTimers();
2299
2331
  if (this.ws) {
2300
2332
  try {
2301
2333
  this.ws.removeAllListeners();
@@ -2308,13 +2340,57 @@ var PipelineWsClient = class {
2308
2340
  send(data) {
2309
2341
  if (this.ws?.readyState === WebSocket.OPEN) {
2310
2342
  this.ws.send(JSON.stringify(data));
2343
+ return;
2344
+ }
2345
+ const event = data;
2346
+ const isCritical = _PipelineWsClient.CRITICAL_TYPES.has(event.type ?? "");
2347
+ if (isCritical) {
2348
+ if (this.sendBuffer.length < _PipelineWsClient.BUFFER_MAX) {
2349
+ this.sendBuffer.push({ data, critical: true, timestamp: Date.now() });
2350
+ }
2351
+ console.warn(`[WS] Buffered critical event (WS not open): ${event.type}`);
2352
+ } else if (event.type !== "ping") {
2353
+ console.debug?.(`[WS] Dropped non-critical event (WS not open): ${event.type}`);
2311
2354
  }
2312
2355
  }
2313
- cleanupPing() {
2356
+ flushBuffer() {
2357
+ const now = Date.now();
2358
+ const valid = this.sendBuffer.filter((e) => now - e.timestamp < _PipelineWsClient.BUFFER_TTL_MS);
2359
+ this.sendBuffer = [];
2360
+ for (const entry of valid) {
2361
+ if (this.ws?.readyState === WebSocket.OPEN) {
2362
+ this.ws.send(JSON.stringify(entry.data));
2363
+ const event = entry.data;
2364
+ console.log(`[WS] Replayed buffered event: ${event.type}`);
2365
+ }
2366
+ }
2367
+ }
2368
+ scheduleReconnect() {
2369
+ if (this.stopped || this.reconnectTimer) return;
2370
+ const delay = Math.min(1e3 * Math.pow(2, this.reconnectAttempt), 3e4);
2371
+ this.reconnectAttempt++;
2372
+ console.log(`[WS] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempt})`);
2373
+ this.reconnectTimer = setTimeout(() => {
2374
+ this.reconnectTimer = null;
2375
+ if (this.stopped) return;
2376
+ this.connect().then(() => {
2377
+ console.log("[WS] Reconnected successfully");
2378
+ }).catch((err) => {
2379
+ const msg = err instanceof Error ? err.message : String(err);
2380
+ console.warn(`[WS] Reconnect failed: ${msg}`);
2381
+ this.scheduleReconnect();
2382
+ });
2383
+ }, delay);
2384
+ }
2385
+ cleanupTimers() {
2314
2386
  if (this.pingTimer) {
2315
2387
  clearInterval(this.pingTimer);
2316
2388
  this.pingTimer = null;
2317
2389
  }
2390
+ if (this.reconnectTimer) {
2391
+ clearTimeout(this.reconnectTimer);
2392
+ this.reconnectTimer = null;
2393
+ }
2318
2394
  }
2319
2395
  };
2320
2396
 
@@ -4253,4 +4329,4 @@ export {
4253
4329
  runPipeline,
4254
4330
  stopPipeline
4255
4331
  };
4256
- //# sourceMappingURL=pipeline-KAIEIIIC.js.map
4332
+ //# sourceMappingURL=pipeline-FMDQGNHO.js.map