jeo-code 0.12.6 → 0.12.7
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/CHANGELOG.md +11 -0
- package/README.ja.md +1 -1
- package/README.ko.md +1 -1
- package/README.md +1 -1
- package/README.zh.md +1 -1
- package/package.json +1 -1
- package/src/agent/engine.ts +6 -2
- package/src/agent/tools.ts +1 -0
- package/src/ai/providers/anthropic.ts +1 -0
- package/src/ai/providers/openai-responses.ts +1 -0
- package/src/commands/computer.ts +46 -15
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,17 @@ The README mirrors the latest 5 entries — regenerate with `bun run changelog:s
|
|
|
9
9
|
|
|
10
10
|
## [Unreleased]
|
|
11
11
|
|
|
12
|
+
## [0.12.7] - 2026-10-18
|
|
13
|
+
_Repair desktop screenshot vision feedback, macOS scrolling, complete drag gestures, and keyboard normalization._
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- **Screenshot vision feedback** — carry PNG attachments through tool execution, batches, and native Anthropic/OpenAI Responses replay instead of spilling base64 as text. Preserve CLI screenshot base64 stdout.
|
|
17
|
+
- **Desktop input** — use Quartz scroll events on macOS (cliclick `w:` waits rather than scrolling), release the mouse after dragging on macOS/Linux, normalize macOS key aliases/modifier combinations, and terminate Linux text options before user text.
|
|
18
|
+
- **Execution reliability** — drain subprocess pipes concurrently with exit, use collision-resistant screenshot paths, reject non-finite numeric inputs and out-of-range waits/scrolls, and explicitly reject unsupported platforms. Existing enablement/supervisor gates remain unchanged.
|
|
19
|
+
|
|
20
|
+
### Documentation
|
|
21
|
+
- Added [desktop setup and troubleshooting](docs/computer-use.md), including platform requirements, OS permissions, coordinate caveats, and supported action semantics.
|
|
22
|
+
|
|
12
23
|
## [0.12.6] - 2026-10-17
|
|
13
24
|
_Preserve OpenAI subscription authentication behind configured proxies, isolate account catalogs, and give provider-specific recovery instructions while retaining Antigravity OAuth calls._
|
|
14
25
|
|
package/README.ja.md
CHANGED
|
@@ -416,10 +416,10 @@ CI は `.github/workflows/npm-publish.yml` で公開します — GitHub リリ
|
|
|
416
416
|
|
|
417
417
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
418
418
|
- **[Unreleased]**
|
|
419
|
+
- **[0.12.7]** (2026-10-18) — Repair desktop screenshot vision feedback, macOS scrolling, complete drag gestures, and keyboard normalization.
|
|
419
420
|
- **[0.12.6]** (2026-10-17) — Preserve OpenAI subscription authentication behind configured proxies, isolate account catalogs, and give provider-specific recovery instructions while retaining Antigravity OAuth calls.
|
|
420
421
|
- **[0.12.5]** (2026-10-17) — Antigravity and Kimi provider support in interactive setup, Kimi live model cache rehydration, immediate discovery caching on provider probing.
|
|
421
422
|
- **[0.12.4]** (2026-10-17) — Refresh Antigravity provider (`antigravity/*`) account catalogs with `antigravity/hub/2.23.1` so entitled Gemini 4 Argon and Gemini 3.8 Flash tiers appear directly in `/model provider antigravity`.
|
|
422
|
-
- **[0.12.3]** (2026-10-17) — Anthropic static model catalog trimmed to claude-5.x with live API discovery, and `/route off` strictly fixes the active model with no failover.
|
|
423
423
|
|
|
424
424
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
425
425
|
<!-- CHANGELOG:END -->
|
package/README.ko.md
CHANGED
|
@@ -417,10 +417,10 @@ CI는 `.github/workflows/npm-publish.yml`로 배포합니다 — GitHub 릴리
|
|
|
417
417
|
|
|
418
418
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
419
419
|
- **[Unreleased]**
|
|
420
|
+
- **[0.12.7]** (2026-10-18) — Repair desktop screenshot vision feedback, macOS scrolling, complete drag gestures, and keyboard normalization.
|
|
420
421
|
- **[0.12.6]** (2026-10-17) — Preserve OpenAI subscription authentication behind configured proxies, isolate account catalogs, and give provider-specific recovery instructions while retaining Antigravity OAuth calls.
|
|
421
422
|
- **[0.12.5]** (2026-10-17) — Antigravity and Kimi provider support in interactive setup, Kimi live model cache rehydration, immediate discovery caching on provider probing.
|
|
422
423
|
- **[0.12.4]** (2026-10-17) — Refresh Antigravity provider (`antigravity/*`) account catalogs with `antigravity/hub/2.23.1` so entitled Gemini 4 Argon and Gemini 3.8 Flash tiers appear directly in `/model provider antigravity`.
|
|
423
|
-
- **[0.12.3]** (2026-10-17) — Anthropic static model catalog trimmed to claude-5.x with live API discovery, and `/route off` strictly fixes the active model with no failover.
|
|
424
424
|
|
|
425
425
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
426
426
|
<!-- CHANGELOG:END -->
|
package/README.md
CHANGED
|
@@ -409,10 +409,10 @@ Huge thanks to [gajae-code](https://github.com/Yeachan-Heo/gajae-code) for the i
|
|
|
409
409
|
|
|
410
410
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
411
411
|
- **[Unreleased]**
|
|
412
|
+
- **[0.12.7]** (2026-10-18) — Repair desktop screenshot vision feedback, macOS scrolling, complete drag gestures, and keyboard normalization.
|
|
412
413
|
- **[0.12.6]** (2026-10-17) — Preserve OpenAI subscription authentication behind configured proxies, isolate account catalogs, and give provider-specific recovery instructions while retaining Antigravity OAuth calls.
|
|
413
414
|
- **[0.12.5]** (2026-10-17) — Antigravity and Kimi provider support in interactive setup, Kimi live model cache rehydration, immediate discovery caching on provider probing.
|
|
414
415
|
- **[0.12.4]** (2026-10-17) — Refresh Antigravity provider (`antigravity/*`) account catalogs with `antigravity/hub/2.23.1` so entitled Gemini 4 Argon and Gemini 3.8 Flash tiers appear directly in `/model provider antigravity`.
|
|
415
|
-
- **[0.12.3]** (2026-10-17) — Anthropic static model catalog trimmed to claude-5.x with live API discovery, and `/route off` strictly fixes the active model with no failover.
|
|
416
416
|
|
|
417
417
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
418
418
|
<!-- CHANGELOG:END -->
|
package/README.zh.md
CHANGED
|
@@ -414,10 +414,10 @@ CI 通过 `.github/workflows/npm-publish.yml` 发布 — GitHub 发布 release
|
|
|
414
414
|
|
|
415
415
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
416
416
|
- **[Unreleased]**
|
|
417
|
+
- **[0.12.7]** (2026-10-18) — Repair desktop screenshot vision feedback, macOS scrolling, complete drag gestures, and keyboard normalization.
|
|
417
418
|
- **[0.12.6]** (2026-10-17) — Preserve OpenAI subscription authentication behind configured proxies, isolate account catalogs, and give provider-specific recovery instructions while retaining Antigravity OAuth calls.
|
|
418
419
|
- **[0.12.5]** (2026-10-17) — Antigravity and Kimi provider support in interactive setup, Kimi live model cache rehydration, immediate discovery caching on provider probing.
|
|
419
420
|
- **[0.12.4]** (2026-10-17) — Refresh Antigravity provider (`antigravity/*`) account catalogs with `antigravity/hub/2.23.1` so entitled Gemini 4 Argon and Gemini 3.8 Flash tiers appear directly in `/model provider antigravity`.
|
|
420
|
-
- **[0.12.3]** (2026-10-17) — Anthropic static model catalog trimmed to claude-5.x with live API discovery, and `/route off` strictly fixes the active model with no failover.
|
|
421
421
|
|
|
422
422
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
423
423
|
<!-- CHANGELOG:END -->
|
package/package.json
CHANGED
package/src/agent/engine.ts
CHANGED
|
@@ -1215,6 +1215,7 @@ export async function runAgentLoop(history: Message[], opts: AgentLoopOptions):
|
|
|
1215
1215
|
const { tool, arguments: args } = call;
|
|
1216
1216
|
let success: boolean;
|
|
1217
1217
|
let output: string;
|
|
1218
|
+
let images: import("../ai/types").ImageAttachment[] | undefined;
|
|
1218
1219
|
|
|
1219
1220
|
if (tool === "done") {
|
|
1220
1221
|
success = false;
|
|
@@ -1242,6 +1243,7 @@ export async function runAgentLoop(history: Message[], opts: AgentLoopOptions):
|
|
|
1242
1243
|
const onProgress = ev.onToolProgress ? (partial: string) => ev.onToolProgress!(tool, partial) : undefined;
|
|
1243
1244
|
const res = await handler(args ?? {}, cwd, onProgress);
|
|
1244
1245
|
success = res.success;
|
|
1246
|
+
images = res.images;
|
|
1245
1247
|
output = res.success ? res.output : (res.error ? (res.output ? `${res.error}\n${res.output}` : res.error) : res.output);
|
|
1246
1248
|
} catch (err: any) {
|
|
1247
1249
|
success = false;
|
|
@@ -1250,7 +1252,7 @@ export async function runAgentLoop(history: Message[], opts: AgentLoopOptions):
|
|
|
1250
1252
|
}
|
|
1251
1253
|
}
|
|
1252
1254
|
}
|
|
1253
|
-
return { success, output };
|
|
1255
|
+
return { success, output, images };
|
|
1254
1256
|
};
|
|
1255
1257
|
|
|
1256
1258
|
const WRITE_TOOLS = new Set(["write", "edit"]);
|
|
@@ -1293,7 +1295,7 @@ export async function runAgentLoop(history: Message[], opts: AgentLoopOptions):
|
|
|
1293
1295
|
}
|
|
1294
1296
|
}
|
|
1295
1297
|
|
|
1296
|
-
const results: { success: boolean; output: string; executed: boolean }[] = Array.from(
|
|
1298
|
+
const results: { success: boolean; output: string; executed: boolean; images?: import("../ai/types").ImageAttachment[] }[] = Array.from(
|
|
1297
1299
|
{ length: toolCalls.length },
|
|
1298
1300
|
() => ({ success: false, output: "", executed: false })
|
|
1299
1301
|
);
|
|
@@ -1385,6 +1387,8 @@ export async function runAgentLoop(history: Message[], opts: AgentLoopOptions):
|
|
|
1385
1387
|
}));
|
|
1386
1388
|
pushAssistantTurn(history, responseText, reasonBuf, artifactBuf, toolUse);
|
|
1387
1389
|
const resultMsg: Message = { role: "user", content: resultBlocks.join("\n\n"), toolResults };
|
|
1390
|
+
const images = indices.flatMap(idx => results[idx].images ?? []);
|
|
1391
|
+
if (images.length) resultMsg.images = images;
|
|
1388
1392
|
if (hookExtra) resultMsg.toolResultExtra = hookExtra;
|
|
1389
1393
|
history.push(resultMsg);
|
|
1390
1394
|
};
|
package/src/agent/tools.ts
CHANGED
|
@@ -240,6 +240,7 @@ export function buildAnthropicMessages(messages: Message[], model: string, think
|
|
|
240
240
|
const blocks: AnthropicContentBlock[] = m.toolResults.map(tr => ({
|
|
241
241
|
type: "tool_result", tool_use_id: tr.id, content: tr.output, is_error: tr.isError,
|
|
242
242
|
}));
|
|
243
|
+
for (const img of m.images ?? []) blocks.push({ type: "image", source: { type: "base64", media_type: img.mediaType, data: img.data } });
|
|
243
244
|
if (m.toolResultExtra) blocks.push({ type: "text", text: m.toolResultExtra });
|
|
244
245
|
return { role: "user", content: blocks };
|
|
245
246
|
}
|
|
@@ -87,6 +87,7 @@ export function buildResponsesInput(messages: Message[], modelKey: string, strip
|
|
|
87
87
|
&& nonSystem[i - 1].role === "assistant" && responsesNativizable(nonSystem[i - 1], modelKey)) {
|
|
88
88
|
for (const tr of m.toolResults) items.push({ type: "function_call_output", call_id: tr.id, output: tr.output });
|
|
89
89
|
if (m.toolResultExtra) items.push({ role: "user", content: [{ type: "input_text", text: m.toolResultExtra }] });
|
|
90
|
+
if (m.images?.length) items.push({ role: "user", content: m.images.map(img => ({ type: "input_image", image_url: `data:${img.mediaType};base64,${img.data}` })) });
|
|
90
91
|
return;
|
|
91
92
|
}
|
|
92
93
|
items.push(plain(m));
|
package/src/commands/computer.ts
CHANGED
|
@@ -2,6 +2,7 @@ import * as fs from "node:fs/promises";
|
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import * as os from "node:os";
|
|
4
4
|
import { computerSupervisor } from "../agent/computer-supervisor";
|
|
5
|
+
import type { ImageAttachment } from "../ai/types";
|
|
5
6
|
import { readGlobalConfig } from "../agent/state";
|
|
6
7
|
|
|
7
8
|
export interface ComputerAction {
|
|
@@ -36,9 +37,11 @@ async function logAudit(action: ComputerAction, success: boolean, error?: string
|
|
|
36
37
|
async function runCommand(cmd: string[]): Promise<{ success: boolean; stdout: string; stderr: string }> {
|
|
37
38
|
try {
|
|
38
39
|
const proc = Bun.spawn(cmd, { stdout: "pipe", stderr: "pipe" });
|
|
39
|
-
await
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
const [stdout, stderr] = await Promise.all([
|
|
41
|
+
new Response(proc.stdout).text(),
|
|
42
|
+
new Response(proc.stderr).text(),
|
|
43
|
+
proc.exited,
|
|
44
|
+
]);
|
|
42
45
|
return {
|
|
43
46
|
success: proc.exitCode === 0,
|
|
44
47
|
stdout,
|
|
@@ -53,7 +56,7 @@ async function runCommand(cmd: string[]): Promise<{ success: boolean; stdout: st
|
|
|
53
56
|
}
|
|
54
57
|
}
|
|
55
58
|
|
|
56
|
-
export async function executeComputerAction(action: ComputerAction, opts?: { enabledOverride?: boolean }): Promise<{ success: boolean; output: string; error?: string }> {
|
|
59
|
+
export async function executeComputerAction(action: ComputerAction, opts?: { enabledOverride?: boolean }): Promise<{ success: boolean; output: string; error?: string; images?: ImageAttachment[] }> {
|
|
57
60
|
let enabled = opts?.enabledOverride;
|
|
58
61
|
if (enabled === undefined) {
|
|
59
62
|
const config = await readGlobalConfig().catch(() => null);
|
|
@@ -68,6 +71,18 @@ export async function executeComputerAction(action: ComputerAction, opts?: { ena
|
|
|
68
71
|
}
|
|
69
72
|
|
|
70
73
|
|
|
74
|
+
if (!action || typeof action !== "object") return { success: false, output: "", error: "Expected a computer action object." };
|
|
75
|
+
for (const field of ["x", "y", "deltaX", "deltaY", "duration"] as const) {
|
|
76
|
+
if (action[field] !== undefined && (typeof action[field] !== "number" || !Number.isFinite(action[field]))) {
|
|
77
|
+
return { success: false, output: "", error: `Invalid finite number for ${field}.` };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (action.duration !== undefined && (action.duration < 0 || action.duration > 60)) {
|
|
81
|
+
return { success: false, output: "", error: "duration must be between 0 and 60 seconds." };
|
|
82
|
+
}
|
|
83
|
+
if (os.platform() !== "darwin" && os.platform() !== "linux") {
|
|
84
|
+
return { success: false, output: "", error: "Computer use supports macOS and Linux/X11 only." };
|
|
85
|
+
}
|
|
71
86
|
// Read-only actions don't need supervisor inputAllowed check
|
|
72
87
|
const isReadOnly = action.action === "screenshot" || action.action === "wait";
|
|
73
88
|
if (!isReadOnly) {
|
|
@@ -83,7 +98,7 @@ export async function executeComputerAction(action: ComputerAction, opts?: { ena
|
|
|
83
98
|
switch (action.action) {
|
|
84
99
|
case "screenshot": {
|
|
85
100
|
const tmpDir = os.tmpdir();
|
|
86
|
-
const screenPath = path.join(tmpDir, `jeo-screen-${
|
|
101
|
+
const screenPath = path.join(tmpDir, `jeo-screen-${crypto.randomUUID()}.png`);
|
|
87
102
|
let cmd: string[];
|
|
88
103
|
if (isMac) {
|
|
89
104
|
cmd = ["screencapture", "-x", screenPath];
|
|
@@ -100,7 +115,7 @@ export async function executeComputerAction(action: ComputerAction, opts?: { ena
|
|
|
100
115
|
const base64 = bytes.toString("base64");
|
|
101
116
|
await fs.unlink(screenPath).catch(() => {});
|
|
102
117
|
await logAudit(action, true);
|
|
103
|
-
return { success: true, output: base64 };
|
|
118
|
+
return { success: true, output: "Screenshot captured.", images: [{ mediaType: "image/png", data: base64 }] };
|
|
104
119
|
} catch (err: any) {
|
|
105
120
|
await logAudit(action, false, err.message);
|
|
106
121
|
return { success: false, output: "", error: `Failed to read screenshot file: ${err.message}` };
|
|
@@ -164,9 +179,9 @@ export async function executeComputerAction(action: ComputerAction, opts?: { ena
|
|
|
164
179
|
}
|
|
165
180
|
let cmd: string[];
|
|
166
181
|
if (isMac) {
|
|
167
|
-
cmd = ["cliclick", `
|
|
182
|
+
cmd = ["cliclick", "dd:.", `dm:${action.x},${action.y}`, `du:${action.x},${action.y}`];
|
|
168
183
|
} else {
|
|
169
|
-
cmd = ["xdotool", "mousemove", String(action.x), String(action.y), "
|
|
184
|
+
cmd = ["xdotool", "mousedown", "1", "mousemove", String(action.x), String(action.y), "mouseup", "1"];
|
|
170
185
|
}
|
|
171
186
|
const res = await runCommand(cmd);
|
|
172
187
|
await logAudit(action, res.success, res.success ? undefined : res.stderr);
|
|
@@ -179,9 +194,14 @@ export async function executeComputerAction(action: ComputerAction, opts?: { ena
|
|
|
179
194
|
let cmd: string[];
|
|
180
195
|
const dx = action.deltaX ?? 0;
|
|
181
196
|
const dy = action.deltaY ?? 0;
|
|
197
|
+
if (!Number.isInteger(dx) || !Number.isInteger(dy) || Math.abs(dx) > 1000 || Math.abs(dy) > 1000) {
|
|
198
|
+
return { success: false, output: "", error: "Scroll deltas must be integers between -1000 and 1000." };
|
|
199
|
+
}
|
|
200
|
+
if (dx === 0 && dy === 0) return { success: true, output: "Scroll skipped (zero deltas)." };
|
|
182
201
|
if (isMac) {
|
|
183
|
-
// cliclick scroll
|
|
184
|
-
cmd = ["
|
|
202
|
+
// cliclick's w: command WAITS; it cannot scroll. Use Quartz line events.
|
|
203
|
+
cmd = ["/usr/bin/osascript", "-l", "JavaScript", "-e",
|
|
204
|
+
`ObjC.import('Cocoa'); var event = $.CGEventCreateScrollWheelEvent(null, 1, 2, ${dy}, ${dx}); $.CGEventPost(0, event);`];
|
|
185
205
|
} else {
|
|
186
206
|
// xdotool click 4 (scroll up), 5 (scroll down), 6 (scroll left), 7 (scroll right)
|
|
187
207
|
const actions: string[] = [];
|
|
@@ -212,7 +232,7 @@ export async function executeComputerAction(action: ComputerAction, opts?: { ena
|
|
|
212
232
|
if (isMac) {
|
|
213
233
|
cmd = ["cliclick", `t:${action.text}`];
|
|
214
234
|
} else {
|
|
215
|
-
cmd = ["xdotool", "type", action.text];
|
|
235
|
+
cmd = ["xdotool", "type", "--clearmodifiers", "--", action.text];
|
|
216
236
|
}
|
|
217
237
|
const res = await runCommand(cmd);
|
|
218
238
|
await logAudit(action, res.success, res.success ? undefined : res.stderr);
|
|
@@ -227,7 +247,16 @@ export async function executeComputerAction(action: ComputerAction, opts?: { ena
|
|
|
227
247
|
}
|
|
228
248
|
let cmd: string[];
|
|
229
249
|
if (isMac) {
|
|
230
|
-
|
|
250
|
+
const aliases: Record<string, string> = { return: "return", enter: "return", escape: "esc", backspace: "delete", arrowup: "arrow-up", arrowdown: "arrow-down", arrowleft: "arrow-left", arrowright: "arrow-right", pageup: "page-up", pagedown: "page-down" };
|
|
251
|
+
const parts = action.key.toLowerCase().split("+");
|
|
252
|
+
const key = parts.pop()!;
|
|
253
|
+
const modifiers = parts.map(p => ({ command: "cmd", meta: "cmd", control: "ctrl", option: "alt" }[p] ?? p));
|
|
254
|
+
if (modifiers.some(p => !["cmd", "ctrl", "alt", "shift", "fn"].includes(p))) {
|
|
255
|
+
return { success: false, output: "", error: "Unknown key modifier." };
|
|
256
|
+
}
|
|
257
|
+
const press = key.length === 1 ? `t:${key}` : `kp:${aliases[key] ?? key}`;
|
|
258
|
+
cmd = ["cliclick", ...(modifiers.length ? [`kd:${modifiers.join(",")}`] : []), press,
|
|
259
|
+
...(modifiers.length ? [`ku:${modifiers.join(",")}`] : [])];
|
|
231
260
|
} else {
|
|
232
261
|
cmd = ["xdotool", "key", action.key];
|
|
233
262
|
}
|
|
@@ -250,6 +279,7 @@ export async function executeComputerAction(action: ComputerAction, opts?: { ena
|
|
|
250
279
|
return { success: false, output: "", error: "Missing actions array for batch action." };
|
|
251
280
|
}
|
|
252
281
|
const results: string[] = [];
|
|
282
|
+
const images: ImageAttachment[] = [];
|
|
253
283
|
for (let i = 0; i < action.actions.length; i++) {
|
|
254
284
|
const subAction = action.actions[i];
|
|
255
285
|
const res = await executeComputerAction(subAction, opts);
|
|
@@ -257,12 +287,13 @@ export async function executeComputerAction(action: ComputerAction, opts?: { ena
|
|
|
257
287
|
if (!res.success) {
|
|
258
288
|
const err = `Batch failed at step ${i}: ${res.error}`;
|
|
259
289
|
await logAudit(action, false, err);
|
|
260
|
-
return { success: false, output: results.join("\n"), error: err };
|
|
290
|
+
return { success: false, output: results.join("\n"), error: err, images };
|
|
261
291
|
}
|
|
262
292
|
results.push(`Step ${i}: ${res.output}`);
|
|
293
|
+
images.push(...(res.images ?? []));
|
|
263
294
|
}
|
|
264
295
|
await logAudit(action, true);
|
|
265
|
-
return { success: true, output: results.join("\n") };
|
|
296
|
+
return { success: true, output: results.join("\n"), images };
|
|
266
297
|
}
|
|
267
298
|
|
|
268
299
|
default:
|
|
@@ -329,7 +360,7 @@ export async function runComputerCommand(args: string[]): Promise<void> {
|
|
|
329
360
|
const res = await executeComputerAction(action);
|
|
330
361
|
if (res.success) {
|
|
331
362
|
if (actionName === "screenshot") {
|
|
332
|
-
console.log(res.output); // base64 output
|
|
363
|
+
console.log(res.images?.[0]?.data ?? res.output); // preserve CLI base64 output
|
|
333
364
|
} else {
|
|
334
365
|
console.log(res.output);
|
|
335
366
|
}
|