codekanban 0.26.0 → 0.28.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/package.json +6 -6
- package/packages/node-sdk/README.md +137 -2
- package/packages/node-sdk/package.json +1 -1
- package/packages/node-sdk/src/cli.js +331 -10
- package/packages/node-sdk/src/client.js +607 -15
- package/packages/node-sdk/src/index.js +3 -0
- package/packages/node-sdk/src/web-session-command-channel.js +378 -0
- package/packages/node-sdk/src/web-session-event-stream.js +216 -0
- package/packages/node-sdk/src/web-session-shared.js +629 -0
- package/skills/codekanban-project-session/agents/openai.yaml +2 -2
package/package.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codekanban",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.28.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.
|
|
10
|
-
"@codekanban/darwin-x64": "0.
|
|
11
|
-
"@codekanban/darwin-arm64": "0.
|
|
12
|
-
"@codekanban/linux-x64": "0.
|
|
13
|
-
"@codekanban/linux-arm64": "0.
|
|
9
|
+
"@codekanban/win32-x64": "0.28.0",
|
|
10
|
+
"@codekanban/darwin-x64": "0.28.0",
|
|
11
|
+
"@codekanban/darwin-arm64": "0.28.0",
|
|
12
|
+
"@codekanban/linux-x64": "0.28.0",
|
|
13
|
+
"@codekanban/linux-arm64": "0.28.0"
|
|
14
14
|
},
|
|
15
15
|
"keywords": [
|
|
16
16
|
"ai",
|
|
@@ -1,16 +1,24 @@
|
|
|
1
1
|
# `@codekanban/sdk`
|
|
2
2
|
|
|
3
|
-
Node SDK and CLI for CodeKanban
|
|
3
|
+
Node SDK and CLI for CodeKanban coding workflows, terminal sessions, and web sessions.
|
|
4
|
+
|
|
5
|
+
Use it as a programming-assistant toolkit for launching, observing, and steering CodeKanban work in a registered project or local path, with `web session` as the default structured path and `terminal session` for PTY-style flows.
|
|
4
6
|
|
|
5
7
|
## Features
|
|
6
8
|
|
|
7
9
|
- Resolve CodeKanban projects by `projectId` or local `path`
|
|
8
10
|
- Auto-create projects for new paths
|
|
9
11
|
- Select the main worktree automatically
|
|
10
|
-
- Launch
|
|
12
|
+
- Launch coding workflows for `codex` or `claude`
|
|
11
13
|
- Support `standard`, `plan`, and `yolo` Codex profiles
|
|
12
14
|
- Read terminal session lists and AI session summaries
|
|
13
15
|
- Read AI conversations and continue existing terminal sessions
|
|
16
|
+
- Control CodeKanban `web session` runs over HTTP and WebSocket
|
|
17
|
+
- Read `web session` snapshots, history, runtime config, command groups, and archived sessions
|
|
18
|
+
- Send `web session` messages, approvals, user-input answers, model/workflow/permission updates, and move operations
|
|
19
|
+
- Receive normalized `web session` events through `on/off`, `waitFor`, or `for await`
|
|
20
|
+
- Poll a `web session` for a derived actionable state instead of reconstructing history logic yourself
|
|
21
|
+
- Execute the latest plan or answer the active structured prompt with one SDK call
|
|
14
22
|
|
|
15
23
|
## CLI
|
|
16
24
|
|
|
@@ -21,6 +29,19 @@ node packages/node-sdk/bin/codekanban-sdk.js session conversation --base-url htt
|
|
|
21
29
|
node packages/node-sdk/bin/codekanban-sdk.js terminal continue --base-url http://127.0.0.1:3000 --session-id <terminal-session-id> --prompt "Continue from the previous plan"
|
|
22
30
|
```
|
|
23
31
|
|
|
32
|
+
### Web Session CLI
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
node packages/node-sdk/bin/codekanban-sdk.js web-session create --base-url http://127.0.0.1:3000 --path D:\repo --agent codex --workflow-mode plan --permission-level elevated --title "Planning session"
|
|
36
|
+
node packages/node-sdk/bin/codekanban-sdk.js web-session snapshot --base-url http://127.0.0.1:3000 --project-id <project-id> --session-id <session-id> --limit 80
|
|
37
|
+
node packages/node-sdk/bin/codekanban-sdk.js web-session send --base-url http://127.0.0.1:3000 --session-id <session-id> --text "Continue from the last plan"
|
|
38
|
+
node packages/node-sdk/bin/codekanban-sdk.js web-session approve --base-url http://127.0.0.1:3000 --session-id <session-id>
|
|
39
|
+
node packages/node-sdk/bin/codekanban-sdk.js web-session user-input --base-url http://127.0.0.1:3000 --session-id <session-id> --item-id <item-id> --answers-json '{"scope":["full repo"]}'
|
|
40
|
+
node packages/node-sdk/bin/codekanban-sdk.js web-session watch --base-url http://127.0.0.1:3000 --session-id <session-id> --max-events 20
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
`web-session watch` writes NDJSON. Add `--raw` to print raw short-key protocol frames.
|
|
44
|
+
|
|
24
45
|
## Library
|
|
25
46
|
|
|
26
47
|
```js
|
|
@@ -37,3 +58,117 @@ const result = await client.startWorkflow({
|
|
|
37
58
|
},
|
|
38
59
|
});
|
|
39
60
|
```
|
|
61
|
+
|
|
62
|
+
### Web Session HTTP
|
|
63
|
+
|
|
64
|
+
```js
|
|
65
|
+
const client = new CodeKanbanClient({ baseURL: 'http://127.0.0.1:3000' });
|
|
66
|
+
|
|
67
|
+
const session = await client.createWebSession({
|
|
68
|
+
path: 'D:/repo',
|
|
69
|
+
agent: 'codex',
|
|
70
|
+
workflowMode: 'plan',
|
|
71
|
+
permissionLevel: 'elevated',
|
|
72
|
+
title: 'Planning session',
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const snapshot = await client.getWebSessionSnapshot({
|
|
76
|
+
projectId: session.projectId,
|
|
77
|
+
sessionId: session.id,
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Polling-Friendly Web Session State
|
|
82
|
+
|
|
83
|
+
```js
|
|
84
|
+
const state = await client.getWebSessionState({
|
|
85
|
+
projectId: session.projectId,
|
|
86
|
+
sessionId: session.id,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
if (state.phase === 'running') {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (state.nextAction?.type === 'answer_user_input') {
|
|
94
|
+
await client.answerPendingUserInput({
|
|
95
|
+
projectId: session.projectId,
|
|
96
|
+
sessionId: session.id,
|
|
97
|
+
answers: {
|
|
98
|
+
scope: ['full repo'],
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (state.nextAction?.type === 'execute_plan') {
|
|
104
|
+
await client.executeLatestPlan({
|
|
105
|
+
projectId: session.projectId,
|
|
106
|
+
sessionId: session.id,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`getWebSessionState()` derives:
|
|
112
|
+
|
|
113
|
+
- `phase`
|
|
114
|
+
- `canSend`
|
|
115
|
+
- `needsAction`
|
|
116
|
+
- `nextAction`
|
|
117
|
+
- `pendingApproval`
|
|
118
|
+
- `pendingUserInput`
|
|
119
|
+
- `latestPlan`
|
|
120
|
+
- `lastAssistantMessage`
|
|
121
|
+
- `snapshot`
|
|
122
|
+
|
|
123
|
+
### Waiting With Polling
|
|
124
|
+
|
|
125
|
+
```js
|
|
126
|
+
const doneState = await client.waitForWebSessionState({
|
|
127
|
+
projectId: session.projectId,
|
|
128
|
+
sessionId: session.id,
|
|
129
|
+
until: 'done',
|
|
130
|
+
intervalMs: 5000,
|
|
131
|
+
timeoutMs: 120000,
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
console.log(doneState.lastAssistantMessage?.text);
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Web Session Command Channel
|
|
138
|
+
|
|
139
|
+
```js
|
|
140
|
+
const channel = client.openWebSessionCommandChannel();
|
|
141
|
+
await channel.waitForOpen();
|
|
142
|
+
|
|
143
|
+
await channel.sendMessage(session.id, {
|
|
144
|
+
text: 'Continue from the latest review.',
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
await channel.updateWorkflowMode(session.id, {
|
|
148
|
+
workflowMode: 'plan',
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
channel.close();
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Web Session Event Stream
|
|
155
|
+
|
|
156
|
+
```js
|
|
157
|
+
const events = client.openWebSessionEventStream({ sessionId: session.id });
|
|
158
|
+
await events.waitForOpen();
|
|
159
|
+
|
|
160
|
+
events.on('snapshot', event => {
|
|
161
|
+
console.log('snapshot', event.snapshot.session.title);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
const nextApproval = events.waitFor(event => event.type === 'historyItem' && event.item.detail?.type === 'approval_request');
|
|
165
|
+
|
|
166
|
+
for await (const event of events) {
|
|
167
|
+
if (event.type === 'historyItem') {
|
|
168
|
+
console.log(event.item.itemType, event.item.text);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
await nextApproval;
|
|
173
|
+
events.close();
|
|
174
|
+
```
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codekanban/sdk",
|
|
3
3
|
"version": "0.1.0",
|
|
4
|
-
"description": "Node SDK and CLI for launching CodeKanban
|
|
4
|
+
"description": "Node SDK and CLI for launching CodeKanban coding workflows, terminal sessions, and web sessions.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
7
7
|
"exports": {
|
|
@@ -10,14 +10,39 @@ function readFlagValue(argv, index, flag) {
|
|
|
10
10
|
return value;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
function parseIntegerFlag(value, fieldName) {
|
|
14
|
+
if (value == null || value === '') {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
const parsed = Number(value);
|
|
18
|
+
if (!Number.isFinite(parsed)) {
|
|
19
|
+
throw new Error(`${fieldName} must be a number`);
|
|
20
|
+
}
|
|
21
|
+
return Math.trunc(parsed);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function parseJsonFlag(value, fieldName) {
|
|
25
|
+
if (!value) {
|
|
26
|
+
throw new Error(`${fieldName} is required`);
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
return JSON.parse(value);
|
|
30
|
+
} catch (error) {
|
|
31
|
+
throw new Error(`${fieldName} must be valid JSON`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
13
35
|
function parseCliArgs(argv) {
|
|
14
36
|
const positionals = [];
|
|
15
37
|
const flags = {
|
|
16
38
|
addDirs: [],
|
|
39
|
+
attachmentIds: [],
|
|
17
40
|
extraArgs: [],
|
|
18
41
|
includeTerminal: true,
|
|
19
42
|
includeAI: true,
|
|
20
43
|
refresh: false,
|
|
44
|
+
clearExisting: false,
|
|
45
|
+
raw: false,
|
|
21
46
|
};
|
|
22
47
|
|
|
23
48
|
for (let index = 0; index < argv.length; index += 1) {
|
|
@@ -44,10 +69,18 @@ function parseCliArgs(argv) {
|
|
|
44
69
|
flags.prompt = readFlagValue(argv, index, token);
|
|
45
70
|
index += 1;
|
|
46
71
|
break;
|
|
72
|
+
case '--text':
|
|
73
|
+
flags.text = readFlagValue(argv, index, token);
|
|
74
|
+
index += 1;
|
|
75
|
+
break;
|
|
47
76
|
case '--agent':
|
|
48
77
|
flags.agent = readFlagValue(argv, index, token);
|
|
49
78
|
index += 1;
|
|
50
79
|
break;
|
|
80
|
+
case '--model':
|
|
81
|
+
flags.model = readFlagValue(argv, index, token);
|
|
82
|
+
index += 1;
|
|
83
|
+
break;
|
|
51
84
|
case '--profile':
|
|
52
85
|
flags.profile = readFlagValue(argv, index, token);
|
|
53
86
|
index += 1;
|
|
@@ -64,6 +97,10 @@ function parseCliArgs(argv) {
|
|
|
64
97
|
flags.addDirs.push(readFlagValue(argv, index, token));
|
|
65
98
|
index += 1;
|
|
66
99
|
break;
|
|
100
|
+
case '--attachment-id':
|
|
101
|
+
flags.attachmentIds.push(readFlagValue(argv, index, token));
|
|
102
|
+
index += 1;
|
|
103
|
+
break;
|
|
67
104
|
case '--extra-arg':
|
|
68
105
|
flags.extraArgs.push(readFlagValue(argv, index, token));
|
|
69
106
|
index += 1;
|
|
@@ -76,10 +113,6 @@ function parseCliArgs(argv) {
|
|
|
76
113
|
flags.workingDir = readFlagValue(argv, index, token);
|
|
77
114
|
index += 1;
|
|
78
115
|
break;
|
|
79
|
-
case '--task-id':
|
|
80
|
-
flags.taskId = readFlagValue(argv, index, token);
|
|
81
|
-
index += 1;
|
|
82
|
-
break;
|
|
83
116
|
case '--worktree-id':
|
|
84
117
|
flags.worktreeId = readFlagValue(argv, index, token);
|
|
85
118
|
index += 1;
|
|
@@ -96,9 +129,75 @@ function parseCliArgs(argv) {
|
|
|
96
129
|
flags.toolUseId = readFlagValue(argv, index, token);
|
|
97
130
|
index += 1;
|
|
98
131
|
break;
|
|
132
|
+
case '--reasoning-effort':
|
|
133
|
+
flags.reasoningEffort = readFlagValue(argv, index, token);
|
|
134
|
+
index += 1;
|
|
135
|
+
break;
|
|
136
|
+
case '--workflow-mode':
|
|
137
|
+
flags.workflowMode = readFlagValue(argv, index, token);
|
|
138
|
+
index += 1;
|
|
139
|
+
break;
|
|
140
|
+
case '--permission-level':
|
|
141
|
+
flags.permissionLevel = readFlagValue(argv, index, token);
|
|
142
|
+
index += 1;
|
|
143
|
+
break;
|
|
144
|
+
case '--permission-mode':
|
|
145
|
+
flags.permissionMode = readFlagValue(argv, index, token);
|
|
146
|
+
index += 1;
|
|
147
|
+
break;
|
|
148
|
+
case '--limit':
|
|
149
|
+
flags.limit = readFlagValue(argv, index, token);
|
|
150
|
+
index += 1;
|
|
151
|
+
break;
|
|
152
|
+
case '--before-cursor':
|
|
153
|
+
flags.beforeCursor = readFlagValue(argv, index, token);
|
|
154
|
+
index += 1;
|
|
155
|
+
break;
|
|
156
|
+
case '--mode':
|
|
157
|
+
flags.mode = readFlagValue(argv, index, token);
|
|
158
|
+
index += 1;
|
|
159
|
+
break;
|
|
160
|
+
case '--group-id':
|
|
161
|
+
flags.groupId = readFlagValue(argv, index, token);
|
|
162
|
+
index += 1;
|
|
163
|
+
break;
|
|
164
|
+
case '--file':
|
|
165
|
+
flags.file = readFlagValue(argv, index, token);
|
|
166
|
+
index += 1;
|
|
167
|
+
break;
|
|
168
|
+
case '--item-id':
|
|
169
|
+
flags.itemId = readFlagValue(argv, index, token);
|
|
170
|
+
index += 1;
|
|
171
|
+
break;
|
|
172
|
+
case '--answers-json':
|
|
173
|
+
flags.answersJson = readFlagValue(argv, index, token);
|
|
174
|
+
index += 1;
|
|
175
|
+
break;
|
|
176
|
+
case '--prev-session-id':
|
|
177
|
+
flags.prevSessionId = readFlagValue(argv, index, token);
|
|
178
|
+
index += 1;
|
|
179
|
+
break;
|
|
180
|
+
case '--next-session-id':
|
|
181
|
+
flags.nextSessionId = readFlagValue(argv, index, token);
|
|
182
|
+
index += 1;
|
|
183
|
+
break;
|
|
184
|
+
case '--idle-timeout-ms':
|
|
185
|
+
flags.idleTimeoutMs = readFlagValue(argv, index, token);
|
|
186
|
+
index += 1;
|
|
187
|
+
break;
|
|
188
|
+
case '--max-events':
|
|
189
|
+
flags.maxEvents = readFlagValue(argv, index, token);
|
|
190
|
+
index += 1;
|
|
191
|
+
break;
|
|
99
192
|
case '--refresh':
|
|
100
193
|
flags.refresh = true;
|
|
101
194
|
break;
|
|
195
|
+
case '--clear-existing':
|
|
196
|
+
flags.clearExisting = true;
|
|
197
|
+
break;
|
|
198
|
+
case '--raw':
|
|
199
|
+
flags.raw = true;
|
|
200
|
+
break;
|
|
102
201
|
case '--no-terminal':
|
|
103
202
|
flags.includeTerminal = false;
|
|
104
203
|
break;
|
|
@@ -136,6 +235,9 @@ function sanitizeConnection(value) {
|
|
|
136
235
|
}
|
|
137
236
|
const next = { ...value };
|
|
138
237
|
delete next.connection;
|
|
238
|
+
delete next.commandChannel;
|
|
239
|
+
delete next.eventStream;
|
|
240
|
+
delete next.socket;
|
|
139
241
|
return next;
|
|
140
242
|
}
|
|
141
243
|
|
|
@@ -143,12 +245,88 @@ function printJson(stream, payload) {
|
|
|
143
245
|
stream.write(createJsonOutput(payload));
|
|
144
246
|
}
|
|
145
247
|
|
|
146
|
-
|
|
248
|
+
function writeJsonLine(stream, payload) {
|
|
249
|
+
stream.write(`${JSON.stringify(payload)}\n`);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
async function withWebSessionCommandChannel(client, handler) {
|
|
253
|
+
const channel = client.openWebSessionCommandChannel();
|
|
254
|
+
try {
|
|
255
|
+
await channel.waitForOpen();
|
|
256
|
+
return await handler(channel);
|
|
257
|
+
} finally {
|
|
258
|
+
channel.close();
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
async function watchWebSession(client, flags, stdout) {
|
|
263
|
+
const eventStream = client.openWebSessionEventStream({
|
|
264
|
+
sessionId: flags.sessionId,
|
|
265
|
+
});
|
|
266
|
+
const maxEvents = parseIntegerFlag(flags.maxEvents, 'maxEvents');
|
|
267
|
+
const idleTimeoutMs = parseIntegerFlag(flags.idleTimeoutMs, 'idleTimeoutMs');
|
|
268
|
+
let eventCount = 0;
|
|
269
|
+
let idleTimer = null;
|
|
270
|
+
let closedByPolicy = false;
|
|
271
|
+
|
|
272
|
+
const armIdleTimer = () => {
|
|
273
|
+
if (idleTimer) {
|
|
274
|
+
clearTimeout(idleTimer);
|
|
275
|
+
idleTimer = null;
|
|
276
|
+
}
|
|
277
|
+
if (!Number.isFinite(idleTimeoutMs) || idleTimeoutMs == null || idleTimeoutMs <= 0) {
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
idleTimer = setTimeout(() => {
|
|
281
|
+
closedByPolicy = true;
|
|
282
|
+
eventStream.close();
|
|
283
|
+
}, idleTimeoutMs);
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
try {
|
|
287
|
+
await eventStream.waitForOpen();
|
|
288
|
+
armIdleTimer();
|
|
289
|
+
|
|
290
|
+
for await (const event of eventStream) {
|
|
291
|
+
if (event.type === 'open' || event.type === 'close') {
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (event.type === 'error' && event.errorType !== 'frame') {
|
|
296
|
+
throw event.error instanceof Error ? event.error : new Error(event.message || 'event stream failed');
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const payload = flags.raw && event.raw ? event.raw : event;
|
|
300
|
+
writeJsonLine(stdout, payload);
|
|
301
|
+
eventCount += 1;
|
|
302
|
+
armIdleTimer();
|
|
303
|
+
|
|
304
|
+
if (maxEvents != null && maxEvents > 0 && eventCount >= maxEvents) {
|
|
305
|
+
closedByPolicy = true;
|
|
306
|
+
eventStream.close();
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return 0;
|
|
311
|
+
} finally {
|
|
312
|
+
if (idleTimer) {
|
|
313
|
+
clearTimeout(idleTimer);
|
|
314
|
+
}
|
|
315
|
+
if (!closedByPolicy) {
|
|
316
|
+
eventStream.close();
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
export async function runCli(argv, options = {}) {
|
|
322
|
+
const stdout = options.stdout || process.stdout;
|
|
323
|
+
const stderr = options.stderr || process.stderr;
|
|
324
|
+
|
|
147
325
|
try {
|
|
148
326
|
const { positionals, flags } = parseCliArgs(argv);
|
|
149
327
|
const [scope, action] = positionals;
|
|
150
328
|
if (!scope || !action) {
|
|
151
|
-
throw new Error('usage: <workflow|session|terminal> <action> --base-url <url> [...]');
|
|
329
|
+
throw new Error('usage: <workflow|session|terminal|web-session> <action> --base-url <url> [...]');
|
|
152
330
|
}
|
|
153
331
|
|
|
154
332
|
if (scope === 'workflow' && action === 'command') {
|
|
@@ -159,7 +337,7 @@ export async function runCli(argv) {
|
|
|
159
337
|
extraArgs: flags.extraArgs,
|
|
160
338
|
prompt: flags.prompt || 'Inspect the project and respond.',
|
|
161
339
|
});
|
|
162
|
-
printJson(
|
|
340
|
+
printJson(stdout, sanitizeConnection(result));
|
|
163
341
|
return 0;
|
|
164
342
|
}
|
|
165
343
|
|
|
@@ -182,7 +360,6 @@ export async function runCli(argv) {
|
|
|
182
360
|
extraArgs: flags.extraArgs,
|
|
183
361
|
title: flags.title,
|
|
184
362
|
workingDir: flags.workingDir,
|
|
185
|
-
taskId: flags.taskId,
|
|
186
363
|
});
|
|
187
364
|
} else if (scope === 'session' && action === 'list') {
|
|
188
365
|
result = await client.listSessions({
|
|
@@ -210,11 +387,155 @@ export async function runCli(argv) {
|
|
|
210
387
|
sessionId: flags.sessionId,
|
|
211
388
|
prompt: flags.prompt,
|
|
212
389
|
});
|
|
390
|
+
} else if (scope === 'web-session' && action === 'list') {
|
|
391
|
+
result = await client.listWebSessions({
|
|
392
|
+
projectId: flags.projectId,
|
|
393
|
+
path: flags.path,
|
|
394
|
+
});
|
|
395
|
+
} else if (scope === 'web-session' && action === 'create') {
|
|
396
|
+
result = await client.createWebSession({
|
|
397
|
+
projectId: flags.projectId,
|
|
398
|
+
path: flags.path,
|
|
399
|
+
worktreeId: flags.worktreeId,
|
|
400
|
+
agent: flags.agent,
|
|
401
|
+
model: flags.model,
|
|
402
|
+
reasoningEffort: flags.reasoningEffort,
|
|
403
|
+
workflowMode: flags.workflowMode,
|
|
404
|
+
permissionLevel: flags.permissionLevel,
|
|
405
|
+
permissionMode: flags.permissionMode,
|
|
406
|
+
title: flags.title,
|
|
407
|
+
});
|
|
408
|
+
} else if (scope === 'web-session' && action === 'connect') {
|
|
409
|
+
result = await withWebSessionCommandChannel(client, channel => channel.connect(flags.sessionId));
|
|
410
|
+
} else if (scope === 'web-session' && action === 'snapshot') {
|
|
411
|
+
result = await client.getWebSessionSnapshot({
|
|
412
|
+
projectId: flags.projectId,
|
|
413
|
+
path: flags.path,
|
|
414
|
+
sessionId: flags.sessionId,
|
|
415
|
+
limit: parseIntegerFlag(flags.limit, 'limit'),
|
|
416
|
+
});
|
|
417
|
+
} else if (scope === 'web-session' && action === 'history') {
|
|
418
|
+
result = await client.getWebSessionHistory({
|
|
419
|
+
projectId: flags.projectId,
|
|
420
|
+
path: flags.path,
|
|
421
|
+
sessionId: flags.sessionId,
|
|
422
|
+
beforeCursor: flags.beforeCursor,
|
|
423
|
+
limit: parseIntegerFlag(flags.limit, 'limit'),
|
|
424
|
+
});
|
|
425
|
+
} else if (scope === 'web-session' && action === 'sync') {
|
|
426
|
+
result = await client.syncWebSession({
|
|
427
|
+
projectId: flags.projectId,
|
|
428
|
+
path: flags.path,
|
|
429
|
+
sessionId: flags.sessionId,
|
|
430
|
+
mode: flags.mode,
|
|
431
|
+
clearExisting: flags.clearExisting,
|
|
432
|
+
});
|
|
433
|
+
} else if (scope === 'web-session' && action === 'archive') {
|
|
434
|
+
result = await client.archiveWebSession({
|
|
435
|
+
projectId: flags.projectId,
|
|
436
|
+
path: flags.path,
|
|
437
|
+
sessionId: flags.sessionId,
|
|
438
|
+
});
|
|
439
|
+
} else if (scope === 'web-session' && action === 'unarchive') {
|
|
440
|
+
result = await client.unarchiveWebSession({
|
|
441
|
+
projectId: flags.projectId,
|
|
442
|
+
path: flags.path,
|
|
443
|
+
sessionId: flags.sessionId,
|
|
444
|
+
});
|
|
445
|
+
} else if (scope === 'web-session' && action === 'rename') {
|
|
446
|
+
result = await client.renameWebSession({
|
|
447
|
+
projectId: flags.projectId,
|
|
448
|
+
path: flags.path,
|
|
449
|
+
sessionId: flags.sessionId,
|
|
450
|
+
title: flags.title,
|
|
451
|
+
});
|
|
452
|
+
} else if (scope === 'web-session' && action === 'close') {
|
|
453
|
+
result = await client.closeWebSession({
|
|
454
|
+
projectId: flags.projectId,
|
|
455
|
+
path: flags.path,
|
|
456
|
+
sessionId: flags.sessionId,
|
|
457
|
+
});
|
|
458
|
+
} else if (scope === 'web-session' && action === 'delete') {
|
|
459
|
+
result = await client.deleteWebSession({
|
|
460
|
+
projectId: flags.projectId,
|
|
461
|
+
path: flags.path,
|
|
462
|
+
sessionId: flags.sessionId,
|
|
463
|
+
});
|
|
464
|
+
} else if (scope === 'web-session' && action === 'runtime-config') {
|
|
465
|
+
result = await client.getWebSessionRuntimeConfig();
|
|
466
|
+
} else if (scope === 'web-session' && action === 'command-group') {
|
|
467
|
+
result = await client.getWebSessionCommandGroup({
|
|
468
|
+
projectId: flags.projectId,
|
|
469
|
+
path: flags.path,
|
|
470
|
+
sessionId: flags.sessionId,
|
|
471
|
+
groupId: flags.groupId,
|
|
472
|
+
});
|
|
473
|
+
} else if (scope === 'web-session' && action === 'attach') {
|
|
474
|
+
result = await client.uploadWebSessionAttachment({
|
|
475
|
+
projectId: flags.projectId,
|
|
476
|
+
path: flags.path,
|
|
477
|
+
filePath: flags.file,
|
|
478
|
+
});
|
|
479
|
+
} else if (scope === 'web-session' && action === 'send') {
|
|
480
|
+
result = await withWebSessionCommandChannel(client, channel =>
|
|
481
|
+
channel.sendMessage(flags.sessionId, {
|
|
482
|
+
text: flags.text || flags.prompt,
|
|
483
|
+
attachmentIds: flags.attachmentIds,
|
|
484
|
+
}),
|
|
485
|
+
);
|
|
486
|
+
} else if (scope === 'web-session' && action === 'approve') {
|
|
487
|
+
result = await withWebSessionCommandChannel(client, channel => channel.approve(flags.sessionId));
|
|
488
|
+
} else if (scope === 'web-session' && action === 'reject') {
|
|
489
|
+
result = await withWebSessionCommandChannel(client, channel => channel.reject(flags.sessionId));
|
|
490
|
+
} else if (scope === 'web-session' && action === 'user-input') {
|
|
491
|
+
result = await withWebSessionCommandChannel(client, channel =>
|
|
492
|
+
channel.answerUserInput(flags.sessionId, {
|
|
493
|
+
itemId: flags.itemId,
|
|
494
|
+
answers: parseJsonFlag(flags.answersJson, 'answersJson'),
|
|
495
|
+
}),
|
|
496
|
+
);
|
|
497
|
+
} else if (scope === 'web-session' && action === 'set-model') {
|
|
498
|
+
result = await withWebSessionCommandChannel(client, channel =>
|
|
499
|
+
channel.updateModel(flags.sessionId, { model: flags.model }),
|
|
500
|
+
);
|
|
501
|
+
} else if (scope === 'web-session' && action === 'set-reasoning') {
|
|
502
|
+
result = await withWebSessionCommandChannel(client, channel =>
|
|
503
|
+
channel.updateReasoningEffort(flags.sessionId, {
|
|
504
|
+
reasoningEffort: flags.reasoningEffort,
|
|
505
|
+
}),
|
|
506
|
+
);
|
|
507
|
+
} else if (scope === 'web-session' && action === 'set-workflow') {
|
|
508
|
+
result = await withWebSessionCommandChannel(client, channel =>
|
|
509
|
+
channel.updateWorkflowMode(flags.sessionId, {
|
|
510
|
+
workflowMode: flags.workflowMode,
|
|
511
|
+
}),
|
|
512
|
+
);
|
|
513
|
+
} else if (scope === 'web-session' && action === 'set-permission') {
|
|
514
|
+
result = await withWebSessionCommandChannel(client, channel =>
|
|
515
|
+
channel.updatePermissionLevel(flags.sessionId, {
|
|
516
|
+
permissionLevel: flags.permissionLevel,
|
|
517
|
+
}),
|
|
518
|
+
);
|
|
519
|
+
} else if (scope === 'web-session' && action === 'set-agent') {
|
|
520
|
+
result = await withWebSessionCommandChannel(client, channel =>
|
|
521
|
+
channel.updateAgent(flags.sessionId, {
|
|
522
|
+
agent: flags.agent,
|
|
523
|
+
}),
|
|
524
|
+
);
|
|
525
|
+
} else if (scope === 'web-session' && action === 'move') {
|
|
526
|
+
result = await withWebSessionCommandChannel(client, channel =>
|
|
527
|
+
channel.move(flags.sessionId, {
|
|
528
|
+
prevSessionId: flags.prevSessionId,
|
|
529
|
+
nextSessionId: flags.nextSessionId,
|
|
530
|
+
}),
|
|
531
|
+
);
|
|
532
|
+
} else if (scope === 'web-session' && action === 'watch') {
|
|
533
|
+
return await watchWebSession(client, flags, stdout);
|
|
213
534
|
} else {
|
|
214
535
|
throw new Error(`unsupported command: ${scope} ${action}`);
|
|
215
536
|
}
|
|
216
537
|
|
|
217
|
-
printJson(
|
|
538
|
+
printJson(stdout, sanitizeConnection(result));
|
|
218
539
|
return 0;
|
|
219
540
|
} catch (error) {
|
|
220
541
|
const payload = {
|
|
@@ -223,7 +544,7 @@ export async function runCli(argv) {
|
|
|
223
544
|
message: error instanceof Error ? error.message : String(error),
|
|
224
545
|
},
|
|
225
546
|
};
|
|
226
|
-
printJson(
|
|
547
|
+
printJson(stderr, payload);
|
|
227
548
|
return 1;
|
|
228
549
|
}
|
|
229
550
|
}
|