codekanban 0.37.0 → 0.38.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.
package/Dockerfile CHANGED
@@ -4,7 +4,7 @@ FROM node:22.12-alpine AS frontend-builder
4
4
  WORKDIR /app/ui
5
5
 
6
6
  # Install pnpm using npm
7
- RUN npm install -g pnpm@latest
7
+ RUN npm install -g pnpm@9.15.9
8
8
 
9
9
  # Copy frontend package files
10
10
  COPY ui/package.json ui/pnpm-lock.yaml ./
package/README.md CHANGED
@@ -78,7 +78,7 @@ After installing the CLI and skills, restart Codex so the new skill is discovere
78
78
  ### Requirements
79
79
  - **Node.js**: v20.19.0+ or v22.12.0+
80
80
  - **Go**: 1.24.6+
81
- - **Package Manager**: pnpm (recommended)
81
+ - **Package Manager**: pnpm 9.15.9
82
82
 
83
83
  ### Install Dependencies
84
84
 
package/README.zh-CN.md CHANGED
@@ -55,7 +55,7 @@ npm install -g codekanban@latest
55
55
  ### 环境要求
56
56
  - **Node.js**: v20.19.0+ 或 v22.12.0+
57
57
  - **Go**: 1.24.6+
58
- - **包管理器**: pnpm(推荐)
58
+ - **包管理器**: pnpm 9.15.9
59
59
 
60
60
  ### 安装依赖
61
61
 
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "codekanban",
3
- "version": "0.37.0",
3
+ "version": "0.38.0",
4
4
  "description": "An auxiliary programming tool for the AI era, helping you speed up 10x.",
5
5
  "bin": {
6
6
  "codekanban": "npm-bin/codekanban.js"
7
7
  },
8
8
  "optionalDependencies": {
9
- "@codekanban/win32-x64": "0.37.0",
10
- "@codekanban/darwin-x64": "0.37.0",
11
- "@codekanban/darwin-arm64": "0.37.0",
12
- "@codekanban/linux-x64": "0.37.0",
13
- "@codekanban/linux-arm64": "0.37.0"
9
+ "@codekanban/win32-x64": "0.38.0",
10
+ "@codekanban/darwin-x64": "0.38.0",
11
+ "@codekanban/darwin-arm64": "0.38.0",
12
+ "@codekanban/linux-x64": "0.38.0",
13
+ "@codekanban/linux-arm64": "0.38.0"
14
14
  },
15
15
  "keywords": [
16
16
  "ai",
@@ -20,6 +20,7 @@ const VALUE_FLAGS = new Set([
20
20
  '--prompt',
21
21
  '--text',
22
22
  '--agent',
23
+ '--claude-runtime',
23
24
  '--model',
24
25
  '--profile',
25
26
  '--sandbox',
@@ -12,6 +12,14 @@ function readFlagValue(argv, index, flag) {
12
12
  return value;
13
13
  }
14
14
 
15
+ function readRawFlagValue(argv, index, flag) {
16
+ const value = argv[index + 1];
17
+ if (value == null) {
18
+ throw new Error(`${flag} requires a value`);
19
+ }
20
+ return value;
21
+ }
22
+
15
23
  function parseIntegerFlag(value, fieldName) {
16
24
  if (value == null || value === '') {
17
25
  return undefined;
@@ -83,6 +91,10 @@ function parseCliArgs(argv) {
83
91
  flags.agent = readFlagValue(argv, index, token);
84
92
  index += 1;
85
93
  break;
94
+ case '--claude-runtime':
95
+ flags.claudeRuntime = readFlagValue(argv, index, token);
96
+ index += 1;
97
+ break;
86
98
  case '--model':
87
99
  flags.model = readFlagValue(argv, index, token);
88
100
  index += 1;
@@ -108,7 +120,7 @@ function parseCliArgs(argv) {
108
120
  index += 1;
109
121
  break;
110
122
  case '--extra-arg':
111
- flags.extraArgs.push(readFlagValue(argv, index, token));
123
+ flags.extraArgs.push(readRawFlagValue(argv, index, token));
112
124
  index += 1;
113
125
  break;
114
126
  case '--title':
@@ -282,6 +294,7 @@ Common options:
282
294
  --project-id <id> Project identifier
283
295
  --path <path> Local project path
284
296
  --session-id <id> Session identifier
297
+ --claude-runtime <rt> Claude launcher for workflow terminal mode: claude or ccr
285
298
  --help Show this help text
286
299
 
287
300
  Examples:
@@ -620,6 +633,7 @@ export async function runCli(argv, options = {}) {
620
633
  if (scope === 'workflow' && action === 'command') {
621
634
  const result = buildAgentLaunchSpec({
622
635
  agent: flags.agent,
636
+ claudeRuntime: flags.claudeRuntime,
623
637
  profile: flags.profile,
624
638
  permissions: buildPermissions(flags),
625
639
  extraArgs: flags.extraArgs,
@@ -652,6 +666,7 @@ export async function runCli(argv, options = {}) {
652
666
  worktreeId: flags.worktreeId,
653
667
  prompt: flags.prompt,
654
668
  agent: flags.agent,
669
+ claudeRuntime: flags.claudeRuntime,
655
670
  profile: flags.profile,
656
671
  permissions: buildPermissions(flags),
657
672
  extraArgs: flags.extraArgs,
@@ -1003,6 +1003,7 @@ export class CodeKanbanClient {
1003
1003
  body: {
1004
1004
  worktreeId: ensureString(worktree?.id, "worktreeId"),
1005
1005
  agent,
1006
+ claudeRuntime: ensureOptionalString(input.claudeRuntime) || "claude",
1006
1007
  model:
1007
1008
  ensureOptionalString(input.model) || defaultWebSessionModel(agent),
1008
1009
  reasoningEffort:
@@ -1367,6 +1368,48 @@ export class CodeKanbanClient {
1367
1368
  );
1368
1369
  }
1369
1370
 
1371
+ async getWebSessionGoal({ sessionId }) {
1372
+ return await this.withWebSessionCommandChannel((channel) =>
1373
+ channel.getGoal(sessionId),
1374
+ );
1375
+ }
1376
+
1377
+ async setWebSessionGoal({ sessionId, objective, status }) {
1378
+ return await this.withWebSessionCommandChannel((channel) =>
1379
+ channel.setGoal(sessionId, {
1380
+ objective,
1381
+ status: ensureOptionalString(status),
1382
+ }),
1383
+ );
1384
+ }
1385
+
1386
+ async bootstrapWebSessionGoal({ sessionId, objective, status }) {
1387
+ return await this.withWebSessionCommandChannel((channel) =>
1388
+ channel.bootstrapGoal(sessionId, {
1389
+ objective,
1390
+ status: ensureOptionalString(status),
1391
+ }),
1392
+ );
1393
+ }
1394
+
1395
+ async pauseWebSessionGoal({ sessionId }) {
1396
+ return await this.withWebSessionCommandChannel((channel) =>
1397
+ channel.pauseGoal(sessionId),
1398
+ );
1399
+ }
1400
+
1401
+ async resumeWebSessionGoal({ sessionId }) {
1402
+ return await this.withWebSessionCommandChannel((channel) =>
1403
+ channel.resumeGoal(sessionId),
1404
+ );
1405
+ }
1406
+
1407
+ async clearWebSessionGoal({ sessionId }) {
1408
+ return await this.withWebSessionCommandChannel((channel) =>
1409
+ channel.clearGoal(sessionId),
1410
+ );
1411
+ }
1412
+
1370
1413
  async answerPendingUserInput({
1371
1414
  projectId,
1372
1415
  projectName,
@@ -1878,6 +1921,7 @@ export class CodeKanbanClient {
1878
1921
  worktree,
1879
1922
  terminalSession: terminal,
1880
1923
  agent: launch.agent,
1924
+ claudeRuntime: launch.claudeRuntime,
1881
1925
  profile: launch.profile,
1882
1926
  command: launch.command,
1883
1927
  prompt: launch.prompt,
@@ -5,6 +5,7 @@ export const SANDBOX_MODES = ['read-only', 'workspace-write', 'danger-full-acces
5
5
  export const APPROVAL_POLICIES = ['untrusted', 'on-request', 'never'];
6
6
  export const WORKFLOW_PROFILES = ['plan', 'standard', 'yolo'];
7
7
  export const AGENTS = ['codex', 'claude'];
8
+ export const CLAUDE_RUNTIMES = ['claude', 'ccr'];
8
9
 
9
10
  const KNOWN_STRUCTURED_FLAGS = new Set([
10
11
  '-s',
@@ -60,15 +61,18 @@ export function buildAgentLaunchSpec(options = {}) {
60
61
  const extraArgs = ensureArrayOfStrings(options.extraArgs, 'extraArgs');
61
62
 
62
63
  if (agent === 'claude') {
64
+ const claudeRuntime =
65
+ validateEnum(options.claudeRuntime || 'claude', CLAUDE_RUNTIMES, 'claudeRuntime') || 'claude';
63
66
  if (profile !== 'standard') {
64
67
  throw new CodeKanbanValidationError('claude only supports the standard profile in v1');
65
68
  }
66
69
  if (options.permissions) {
67
70
  throw new CodeKanbanValidationError('structured permissions are only supported for codex in v1');
68
71
  }
69
- const argv = ['claude', ...extraArgs];
72
+ const argv = claudeRuntime === 'ccr' ? ['ccr', 'code', ...extraArgs] : ['claude', ...extraArgs];
70
73
  return {
71
74
  agent,
75
+ claudeRuntime,
72
76
  profile,
73
77
  argv,
74
78
  command: toCommandString(argv),
@@ -119,6 +119,7 @@ export class WebSessionCommandChannel {
119
119
  pid: ensureString(input.projectId, "projectId"),
120
120
  wid: ensureOptionalString(input.worktreeId),
121
121
  ag: ensureString(input.agent, "agent"),
122
+ cr: ensureOptionalString(input.claudeRuntime),
122
123
  md: ensureOptionalString(input.model),
123
124
  re: ensureOptionalString(input.reasoningEffort),
124
125
  wm: ensureOptionalString(input.workflowMode),
@@ -230,6 +231,16 @@ export class WebSessionCommandChannel {
230
231
  });
231
232
  }
232
233
 
234
+ async updateClaudeRuntime(sessionId, input = {}) {
235
+ return await this._executeCommand({
236
+ operation: "set_cr",
237
+ sessionId,
238
+ payload: {
239
+ cr: ensureString(input.claudeRuntime, "claudeRuntime"),
240
+ },
241
+ });
242
+ }
243
+
233
244
  async updateReasoningEffort(sessionId, input = {}) {
234
245
  return await this._executeCommand({
235
246
  operation: "set_re",
@@ -250,6 +261,56 @@ export class WebSessionCommandChannel {
250
261
  });
251
262
  }
252
263
 
264
+ async getGoal(sessionId) {
265
+ return await this._executeCommand({
266
+ operation: "goal_get",
267
+ sessionId,
268
+ });
269
+ }
270
+
271
+ async setGoal(sessionId, input = {}) {
272
+ return await this._executeCommand({
273
+ operation: "goal_set",
274
+ sessionId,
275
+ payload: {
276
+ obj: ensureString(input.objective, "objective"),
277
+ st: ensureOptionalString(input.status),
278
+ },
279
+ });
280
+ }
281
+
282
+ async bootstrapGoal(sessionId, input = {}) {
283
+ return await this._executeCommand({
284
+ operation: "goal_bootstrap",
285
+ sessionId,
286
+ payload: {
287
+ obj: ensureString(input.objective, "objective"),
288
+ st: ensureOptionalString(input.status),
289
+ },
290
+ });
291
+ }
292
+
293
+ async pauseGoal(sessionId) {
294
+ return await this._executeCommand({
295
+ operation: "goal_pause",
296
+ sessionId,
297
+ });
298
+ }
299
+
300
+ async resumeGoal(sessionId) {
301
+ return await this._executeCommand({
302
+ operation: "goal_resume",
303
+ sessionId,
304
+ });
305
+ }
306
+
307
+ async clearGoal(sessionId) {
308
+ return await this._executeCommand({
309
+ operation: "goal_clear",
310
+ sessionId,
311
+ });
312
+ }
313
+
253
314
  async updatePermissionLevel(sessionId, input = {}) {
254
315
  return await this._executeCommand({
255
316
  operation: "set_pl",
@@ -89,6 +89,30 @@ function normalizeContextEstimate(value, usageFallback) {
89
89
  };
90
90
  }
91
91
 
92
+ function normalizeGoal(value) {
93
+ if (!value || typeof value !== "object") {
94
+ return null;
95
+ }
96
+ const objective = trimmedString(value?.obj ?? value?.objective);
97
+ const threadId = trimmedString(value?.tid ?? value?.threadId);
98
+ const status = trimmedString(value?.st ?? value?.status);
99
+ if (!objective || !threadId || !status) {
100
+ return null;
101
+ }
102
+ return {
103
+ threadId,
104
+ objective,
105
+ status,
106
+ tokenBudget: nullableNumberValue(value?.tb ?? value?.tokenBudget),
107
+ tokensUsed: numberValue(value?.tu ?? value?.tokensUsed, 0),
108
+ timeUsedSeconds: numberValue(value?.tsu ?? value?.timeUsedSeconds, 0),
109
+ createdAt:
110
+ isoFromUnixMilli(value?.ca ?? value?.createdAt) || new Date().toISOString(),
111
+ updatedAt:
112
+ isoFromUnixMilli(value?.ua ?? value?.updatedAt) || new Date().toISOString(),
113
+ };
114
+ }
115
+
92
116
  function normalizeHistoryAttachment(value) {
93
117
  return {
94
118
  id: trimmedString(value?.id),
@@ -264,6 +288,7 @@ export function normalizeWebSessionSummaryFromWire(value) {
264
288
  worktreeId: trimmedString(value?.wid) || null,
265
289
  orderIndex: numberValue(value?.oi, 0),
266
290
  agent: trimmedString(value?.ag) || "codex",
291
+ claudeRuntime: trimmedString(value?.cr) === "ccr" ? "ccr" : "claude",
267
292
  title: trimmedString(value?.ttl),
268
293
  model: trimmedString(value?.md),
269
294
  reasoningEffort: trimmedString(value?.re) || "default",
@@ -303,6 +328,7 @@ export function normalizeWebSessionSummaryFromWire(value) {
303
328
  lastContextCompactionAt: isoFromUnixMilli(value?.lcca),
304
329
  contextWindowTokens: nullableNumberValue(value?.cwt),
305
330
  contextWindowSource: trimmedString(value?.cws) || "unavailable",
331
+ goal: normalizeGoal(value?.goal),
306
332
  };
307
333
  }
308
334