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