codekanban 0.31.0 → 0.32.0

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.
@@ -6,7 +6,7 @@ function decodeJsonMessage(raw) {
6
6
  }
7
7
 
8
8
  export class TerminalConnection {
9
- constructor({ sessionId, url, WebSocketImpl }) {
9
+ constructor({ sessionId, url, WebSocketImpl, webSocketOptions } = {}) {
10
10
  if (!sessionId) {
11
11
  throw new CodeKanbanValidationError('sessionId is required');
12
12
  }
@@ -25,7 +25,7 @@ export class TerminalConnection {
25
25
  this.readyMessage = undefined;
26
26
  this._listeners = new Map();
27
27
 
28
- this.socket = new Socket(url);
28
+ this.socket = webSocketOptions ? new Socket(url, webSocketOptions) : new Socket(url);
29
29
  this._readyResolve = null;
30
30
  this._readyReject = null;
31
31
  this._readyPromise = new Promise((resolve, reject) => {
@@ -1,7 +1,15 @@
1
- import path from 'node:path';
1
+ import path from 'node:path';
2
2
 
3
3
  import { CodeKanbanConfigError, CodeKanbanValidationError } from './errors.js';
4
4
 
5
+ function isWindowsAbsolutePath(value) {
6
+ return /^[a-zA-Z]:[\\/]/.test(value) || value.startsWith('\\\\');
7
+ }
8
+
9
+ function isPosixAbsolutePath(value) {
10
+ return value.startsWith('/');
11
+ }
12
+
5
13
  export function normalizeBaseUrl(baseURL) {
6
14
  const value = String(baseURL || '').trim();
7
15
  if (!value) {
@@ -46,14 +54,27 @@ export function ensureArrayOfStrings(value, fieldName) {
46
54
 
47
55
  export function normalizeFsPath(inputPath) {
48
56
  const value = ensureString(inputPath, 'path');
57
+ if (isWindowsAbsolutePath(value)) {
58
+ return path.win32.normalize(value).toLowerCase();
59
+ }
60
+ if (isPosixAbsolutePath(value)) {
61
+ return path.posix.normalize(value);
62
+ }
49
63
  const resolved = path.resolve(value);
50
64
  const normalized = path.normalize(resolved);
51
65
  return process.platform === 'win32' ? normalized.toLowerCase() : normalized;
52
66
  }
53
67
 
54
68
  export function pathBasename(inputPath) {
55
- const resolved = path.resolve(String(inputPath || ''));
56
- const base = path.basename(resolved);
69
+ const value = String(inputPath || '').trim();
70
+ if (!value) {
71
+ return 'project';
72
+ }
73
+ const base = isWindowsAbsolutePath(value)
74
+ ? path.win32.basename(path.win32.normalize(value))
75
+ : isPosixAbsolutePath(value)
76
+ ? path.posix.basename(path.posix.normalize(value))
77
+ : path.basename(path.resolve(value));
57
78
  return base || 'project';
58
79
  }
59
80
 
@@ -97,3 +118,4 @@ export function toCommandString(argv) {
97
118
  export function createJsonOutput(value) {
98
119
  return `${JSON.stringify(value, null, 2)}\n`;
99
120
  }
121
+
@@ -34,7 +34,7 @@ function normalizeHistoryLimit(value) {
34
34
  }
35
35
 
36
36
  export class WebSessionCommandChannel {
37
- constructor({ url, WebSocketImpl } = {}) {
37
+ constructor({ url, WebSocketImpl, webSocketOptions } = {}) {
38
38
  const resolvedUrl = ensureString(url, "url");
39
39
  const Socket = WebSocketImpl || globalThis.WebSocket;
40
40
  if (!Socket) {
@@ -44,7 +44,7 @@ export class WebSessionCommandChannel {
44
44
  }
45
45
 
46
46
  this.url = resolvedUrl;
47
- this.socket = new Socket(resolvedUrl);
47
+ this.socket = webSocketOptions ? new Socket(resolvedUrl, webSocketOptions) : new Socket(resolvedUrl);
48
48
  this.protocolVersion = WEB_SESSION_PROTOCOL_VERSION;
49
49
  this._pendingRequests = new Map();
50
50
  this._pendingFollowUp = null;
@@ -22,7 +22,7 @@ function nowEventBase() {
22
22
  }
23
23
 
24
24
  export class WebSessionEventStream {
25
- constructor({ url, sessionId, WebSocketImpl } = {}) {
25
+ constructor({ url, sessionId, WebSocketImpl, webSocketOptions } = {}) {
26
26
  const resolvedUrl = ensureString(url, 'url');
27
27
  const Socket = WebSocketImpl || globalThis.WebSocket;
28
28
  if (!Socket) {
@@ -73,6 +73,22 @@ function normalizeUsage(value) {
73
73
  };
74
74
  }
75
75
 
76
+ function normalizeContextEstimate(value, usageFallback) {
77
+ return {
78
+ inputTokens: numberValue(value?.in, numberValue(usageFallback?.in, 0)),
79
+ cachedInputTokens: numberValue(value?.cin, numberValue(usageFallback?.cin, 0)),
80
+ outputTokens: numberValue(value?.out, numberValue(usageFallback?.out, 0)),
81
+ usedTokens: numberValue(
82
+ value?.usd,
83
+ Math.max(
84
+ 0,
85
+ numberValue(value?.in, numberValue(usageFallback?.in, 0)) +
86
+ numberValue(value?.out, numberValue(usageFallback?.out, 0)),
87
+ ),
88
+ ),
89
+ };
90
+ }
91
+
76
92
  function normalizeHistoryAttachment(value) {
77
93
  return {
78
94
  id: trimmedString(value?.id),
@@ -185,6 +201,25 @@ function normalizePendingInput(value) {
185
201
  };
186
202
  }
187
203
 
204
+ function normalizePendingUserInputState(value) {
205
+ const itemId = trimmedString(value?.iid ?? value?.itemId);
206
+ if (!itemId) {
207
+ return null;
208
+ }
209
+ return {
210
+ itemId,
211
+ prompt: trimmedString(value?.txt ?? value?.prompt) || "",
212
+ questions: Array.isArray(value?.qs ?? value?.questions)
213
+ ? (value.qs ?? value.questions).map(normalizeUserInputQuestion)
214
+ : [],
215
+ requestedAt:
216
+ isoFromUnixMilli(value?.ra) ||
217
+ (typeof value?.requestedAt === "string"
218
+ ? trimmedString(value.requestedAt) || null
219
+ : null),
220
+ };
221
+ }
222
+
188
223
  export function normalizeWebSessionHistoryItem(value) {
189
224
  const updatedTimestamp =
190
225
  isoFromUnixMilli(value?.ts2) || isoFromUnixMilli(value?.obs);
@@ -262,6 +297,10 @@ export function normalizeWebSessionSummaryFromWire(value) {
262
297
  ...normalizeUsage(value?.usa),
263
298
  cost: numberValue(value?.cost, 0),
264
299
  },
300
+ latestTurnUsage: value?.ltu ? normalizeContextEstimate(value.ltu, null) : null,
301
+ contextEstimate: normalizeContextEstimate(value?.cea, value?.usa),
302
+ contextEstimateMode: trimmedString(value?.cem) || "cumulative_total",
303
+ lastContextCompactionAt: isoFromUnixMilli(value?.lcca),
265
304
  contextWindowTokens: nullableNumberValue(value?.cwt),
266
305
  contextWindowSource: trimmedString(value?.cws) || "unavailable",
267
306
  };
@@ -274,6 +313,7 @@ export function normalizeWebSessionSnapshotFromWire(frame) {
274
313
  pendingInputs: Array.isArray(frame?.pi)
275
314
  ? frame.pi.map(normalizePendingInput).filter(Boolean)
276
315
  : [],
316
+ pendingUserInput: normalizePendingUserInputState(frame?.ui),
277
317
  };
278
318
  }
279
319
 
@@ -468,7 +508,9 @@ export function analyzeWebSession(snapshot) {
468
508
  : [];
469
509
  const items = Array.isArray(history.items) ? history.items : [];
470
510
  const pendingApproval = findPendingApproval(items);
471
- const pendingUserInput = findPendingUserInput(items);
511
+ const pendingUserInput =
512
+ normalizePendingUserInputState(snapshot?.pendingUserInput) ||
513
+ findPendingUserInput(items);
472
514
  const latestPlan = findLatestPlan(items);
473
515
  const lastAssistantMessage = findLastAssistantMessage(items);
474
516
 
@@ -543,6 +585,7 @@ export function analyzeWebSession(snapshot) {
543
585
  session,
544
586
  history,
545
587
  pendingInputs,
588
+ pendingUserInput,
546
589
  },
547
590
  };
548
591
  }
@@ -1,4 +0,0 @@
1
- interface:
2
- display_name: "CodeKanban Project Session"
3
- short_description: "Prefer web sessions for CodeKanban AI work"
4
- default_prompt: "Use the CodeKanban project session workflow with web session as the default interactive path. Prefer web-session create/control/watch for structured AI work in a project path, and use workflow start or terminal continue only when the user explicitly wants PTY-style terminal behavior or startup profiles such as plan or yolo."
@@ -1,7 +0,0 @@
1
- #!/usr/bin/env node
2
- import { runCli } from '../../../packages/node-sdk/src/cli.js';
3
-
4
- const exitCode = await runCli(process.argv.slice(2));
5
- if (typeof exitCode === 'number') {
6
- process.exitCode = exitCode;
7
- }