finch-ego-lite 0.1.0 → 0.1.1
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/dist/index.js +426 -451
- package/package.json +20 -7
package/dist/index.js
CHANGED
|
@@ -1,71 +1,67 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { promisify } from "node:util";
|
|
7
|
+
var execFileAsync = promisify(execFile);
|
|
8
|
+
var WEBSITE = "https://lite.ego.app/";
|
|
9
|
+
var STATUS_MARKER = "__EGO_STATUS__";
|
|
10
|
+
var commandQueue = Promise.resolve();
|
|
10
11
|
function egoBinary() {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
return 'ego-browser';
|
|
12
|
+
const local = join(homedir(), ".local", "bin", "ego-browser");
|
|
13
|
+
if (existsSync(local)) return local;
|
|
14
|
+
return "ego-browser";
|
|
15
15
|
}
|
|
16
16
|
async function processRunning() {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
return false;
|
|
25
|
-
}
|
|
17
|
+
if (process.platform !== "darwin") return false;
|
|
18
|
+
try {
|
|
19
|
+
await execFileAsync("pgrep", ["-f", "/ego lite.app/Contents/MacOS/ego lite"], { timeout: 2e3 });
|
|
20
|
+
return true;
|
|
21
|
+
} catch {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
26
24
|
}
|
|
27
|
-
async function runCommand(file, args, timeout =
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
});
|
|
41
|
-
// ego-browser waits for stdin EOF even when a script is supplied with -e.
|
|
42
|
-
child.stdin?.end();
|
|
25
|
+
async function runCommand(file, args, timeout = 2e4) {
|
|
26
|
+
const execute = () => new Promise((resolve, reject) => {
|
|
27
|
+
const child = execFile(file, args, {
|
|
28
|
+
timeout,
|
|
29
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
30
|
+
env: { ...process.env, PATH: `${join(homedir(), ".local", "bin")}:${process.env.PATH ?? ""}` }
|
|
31
|
+
}, (error, stdout, stderr) => {
|
|
32
|
+
const output = [stdout, stderr].filter(Boolean).join("\n").trim();
|
|
33
|
+
if (error) {
|
|
34
|
+
reject(new Error(output || error.message));
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
resolve(output);
|
|
43
38
|
});
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
39
|
+
child.stdin?.end();
|
|
40
|
+
});
|
|
41
|
+
const result = commandQueue.then(execute, execute);
|
|
42
|
+
commandQueue = result.then(() => void 0, () => void 0);
|
|
43
|
+
return result;
|
|
47
44
|
}
|
|
48
45
|
async function installedVersion(binary) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
46
|
+
try {
|
|
47
|
+
const output = await runCommand(binary, ["--version"], 3e3);
|
|
48
|
+
return output.split("\n").find((line) => line.startsWith("ego-browser "))?.replace("ego-browser ", "").trim();
|
|
49
|
+
} catch {
|
|
50
|
+
return void 0;
|
|
51
|
+
}
|
|
56
52
|
}
|
|
57
53
|
function statusScript(detailed) {
|
|
58
|
-
|
|
54
|
+
return `
|
|
59
55
|
const spaces = await listTaskSpaces();
|
|
60
56
|
let initialTab = null;
|
|
61
|
-
if (${detailed ?
|
|
57
|
+
if (${detailed ? "true" : "false"} && spaces.some(space => space.ownership === 'agent')) {
|
|
62
58
|
initialTab = await currentTab().catch(() => null);
|
|
63
59
|
}
|
|
64
60
|
let initialSpaceId = null;
|
|
65
61
|
const result = [];
|
|
66
62
|
for (const space of spaces) {
|
|
67
63
|
const item = Object.assign({}, space);
|
|
68
|
-
if (${detailed ?
|
|
64
|
+
if (${detailed ? "true" : "false"} && space.ownership === 'agent') {
|
|
69
65
|
try {
|
|
70
66
|
await switchTaskSpace(space.id);
|
|
71
67
|
item.tabs = await listTabs();
|
|
@@ -86,425 +82,404 @@ cliLog('${STATUS_MARKER}' + JSON.stringify(result));
|
|
|
86
82
|
`;
|
|
87
83
|
}
|
|
88
84
|
function parseSpaces(output) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
return JSON.parse(json);
|
|
85
|
+
const markerIndex = output.lastIndexOf(STATUS_MARKER);
|
|
86
|
+
if (markerIndex < 0) throw new Error(output || "Ego Browser did not return status data");
|
|
87
|
+
const json = output.slice(markerIndex + STATUS_MARKER.length).split("\n")[0];
|
|
88
|
+
return JSON.parse(json);
|
|
94
89
|
}
|
|
95
90
|
async function getStatus(detailed = false) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
spaces: [],
|
|
125
|
-
pageCount: 0,
|
|
126
|
-
error: error instanceof Error ? error.message : String(error),
|
|
127
|
-
};
|
|
128
|
-
}
|
|
91
|
+
if (process.platform !== "darwin") {
|
|
92
|
+
return { supported: false, installed: false, running: false, spaces: [], pageCount: 0 };
|
|
93
|
+
}
|
|
94
|
+
const binary = egoBinary();
|
|
95
|
+
if (!binary) return { supported: true, installed: false, running: false, spaces: [], pageCount: 0 };
|
|
96
|
+
const version = await installedVersion(binary);
|
|
97
|
+
if (!version) return { supported: true, installed: false, running: false, spaces: [], pageCount: 0 };
|
|
98
|
+
const running = await processRunning();
|
|
99
|
+
if (!running) return { supported: true, installed: true, running: false, version, spaces: [], pageCount: 0 };
|
|
100
|
+
try {
|
|
101
|
+
const output = await runCommand(binary, ["nodejs", "-e", statusScript(detailed)], 1e4);
|
|
102
|
+
const spaces = parseSpaces(output);
|
|
103
|
+
const pageCount = spaces.reduce((sum, space) => {
|
|
104
|
+
if (space.tabs) return sum + space.tabs.length;
|
|
105
|
+
return sum + (space.recentTabTitles?.length ?? 0);
|
|
106
|
+
}, 0);
|
|
107
|
+
return { supported: true, installed: true, running: true, version, spaces, pageCount };
|
|
108
|
+
} catch (error) {
|
|
109
|
+
return {
|
|
110
|
+
supported: true,
|
|
111
|
+
installed: true,
|
|
112
|
+
running: true,
|
|
113
|
+
version,
|
|
114
|
+
spaces: [],
|
|
115
|
+
pageCount: 0,
|
|
116
|
+
error: error instanceof Error ? error.message : String(error)
|
|
117
|
+
};
|
|
118
|
+
}
|
|
129
119
|
}
|
|
130
120
|
async function launchEgo() {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
await execFileAsync('open', ['-a', 'ego lite'], { timeout: 5000 });
|
|
121
|
+
if (process.platform !== "darwin") throw new Error("Ego Lite currently supports macOS only.");
|
|
122
|
+
await execFileAsync("open", ["-a", "ego lite"], { timeout: 5e3 });
|
|
134
123
|
}
|
|
135
124
|
async function openWebsite() {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
125
|
+
const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
|
|
126
|
+
const args = process.platform === "win32" ? ["/c", "start", "", WEBSITE] : [WEBSITE];
|
|
127
|
+
await execFileAsync(command, args, { timeout: 5e3 });
|
|
139
128
|
}
|
|
140
129
|
function key(value) {
|
|
141
|
-
|
|
130
|
+
return Buffer.from(JSON.stringify(value)).toString("base64url");
|
|
142
131
|
}
|
|
143
132
|
function unkey(value) {
|
|
144
|
-
|
|
133
|
+
return JSON.parse(Buffer.from(value, "base64url").toString("utf8"));
|
|
145
134
|
}
|
|
146
135
|
function compactTitle(title, fallback, maxLength = 32) {
|
|
147
|
-
|
|
148
|
-
|
|
136
|
+
const chars = Array.from(title.trim() || fallback);
|
|
137
|
+
return chars.length > maxLength ? `${chars.slice(0, maxLength).join("")}\u2026` : chars.join("");
|
|
149
138
|
}
|
|
150
139
|
function domainOf(url, fallback) {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}
|
|
140
|
+
try {
|
|
141
|
+
const parsed = new URL(url);
|
|
142
|
+
return `${parsed.protocol}//${parsed.hostname.replace(/^www\./, "")}`;
|
|
143
|
+
} catch {
|
|
144
|
+
return fallback;
|
|
145
|
+
}
|
|
158
146
|
}
|
|
159
147
|
function ownershipText(ownership, t) {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
return t('ownership.delegated');
|
|
164
|
-
return t('ownership.user');
|
|
148
|
+
if (ownership === "agent") return t("ownership.agent");
|
|
149
|
+
if (ownership === "agentDelegatedToUser") return t("ownership.delegated");
|
|
150
|
+
return t("ownership.user");
|
|
165
151
|
}
|
|
166
152
|
function statusText(status, t) {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
pages: space.tabs?.length ?? space.recentTabTitles?.length ?? 0,
|
|
180
|
-
tabs: space.tabs?.map(({ targetId, title, url, active }) => ({ targetId, title, url, active })),
|
|
181
|
-
}));
|
|
182
|
-
return JSON.stringify({ ready: true, version: status.version, pageCount: status.pageCount, spaces }, null, 2);
|
|
153
|
+
if (!status.supported) return t("status.unsupported", { platform: process.platform });
|
|
154
|
+
if (!status.installed) return t("status.notInstalled", { website: WEBSITE });
|
|
155
|
+
if (!status.running) return t("status.notRunning", { version: status.version ?? "unknown" });
|
|
156
|
+
if (status.error) return t("status.error", { error: status.error });
|
|
157
|
+
const spaces = status.spaces.map((space) => ({
|
|
158
|
+
id: space.id,
|
|
159
|
+
name: space.name,
|
|
160
|
+
ownership: space.ownership,
|
|
161
|
+
pages: space.tabs?.length ?? space.recentTabTitles?.length ?? 0,
|
|
162
|
+
tabs: space.tabs?.map(({ targetId, title, url, active }) => ({ targetId, title, url, active }))
|
|
163
|
+
}));
|
|
164
|
+
return JSON.stringify({ ready: true, version: status.version, pageCount: status.pageCount, spaces }, null, 2);
|
|
183
165
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
iconName: space.ownership === 'agent' ? 'bot' : 'users',
|
|
320
|
-
disabled: true,
|
|
321
|
-
});
|
|
322
|
-
}
|
|
323
|
-
children.push({ id: `close-divider:${space.id}`, label: '', separator: true });
|
|
324
|
-
children.push({
|
|
325
|
-
id: `close:${key(space.id)}`,
|
|
326
|
-
label: t('menu.close.label'),
|
|
327
|
-
description: t('menu.close.description'),
|
|
328
|
-
iconName: 'ext:ego-browser-icons/x',
|
|
329
|
-
});
|
|
330
|
-
items.push({
|
|
331
|
-
id: `space-menu:${space.id}`,
|
|
332
|
-
label: space.name || t('menu.space.fallback', { id: space.id }),
|
|
333
|
-
description: ownershipText(space.ownership, t),
|
|
334
|
-
iconName: space.ownership === 'agent'
|
|
335
|
-
? 'ext:ego-browser-icons/bot'
|
|
336
|
-
: 'ext:ego-browser-icons/compass',
|
|
337
|
-
children,
|
|
338
|
-
});
|
|
339
|
-
}
|
|
340
|
-
if (status.spaces.length === 0) {
|
|
341
|
-
items.push({
|
|
342
|
-
id: '__empty__',
|
|
343
|
-
label: t('menu.empty.label'),
|
|
344
|
-
description: t('menu.empty.description'),
|
|
345
|
-
hoverText: t('menu.empty.hover'),
|
|
346
|
-
iconName: 'ext:ego-browser-icons/bot-off',
|
|
347
|
-
});
|
|
348
|
-
}
|
|
349
|
-
return items;
|
|
350
|
-
},
|
|
351
|
-
async execute(_actionContext, itemId, actions) {
|
|
352
|
-
try {
|
|
353
|
-
if (itemId === '__install__') {
|
|
354
|
-
await openWebsite();
|
|
355
|
-
return;
|
|
356
|
-
}
|
|
357
|
-
if (itemId === '__empty__') {
|
|
358
|
-
await actions.composer.fill(t('composer.startPrompt'));
|
|
359
|
-
return;
|
|
360
|
-
}
|
|
361
|
-
if (itemId === '__launch__') {
|
|
362
|
-
await launchEgo();
|
|
363
|
-
await ctx.ui.showToast({ title: t('toast.launched'), variant: 'success', position: 'TC' });
|
|
364
|
-
cachedStatus = undefined;
|
|
365
|
-
action.notifyUpdate();
|
|
366
|
-
refreshStatus(true);
|
|
367
|
-
return;
|
|
368
|
-
}
|
|
369
|
-
if (itemId.startsWith('resume:')) {
|
|
370
|
-
const spaceId = unkey(itemId.slice('resume:'.length));
|
|
371
|
-
await actions.composer.fill(t('composer.resumePrompt', { id: spaceId }));
|
|
372
|
-
return;
|
|
373
|
-
}
|
|
374
|
-
if (itemId.startsWith('close:')) {
|
|
375
|
-
const spaceId = unkey(itemId.slice('close:'.length));
|
|
376
|
-
const space = cachedStatus?.spaces.find((item) => item.id === spaceId);
|
|
377
|
-
const result = await ctx.ui.showConfirmDialog({
|
|
378
|
-
title: t('dialog.close.title'),
|
|
379
|
-
description: space?.name || t('menu.space.fallback', { id: spaceId }),
|
|
380
|
-
message: t('dialog.close.message', { count: space?.tabs?.length ?? space?.recentTabTitles?.length ?? 0 }),
|
|
381
|
-
confirmLabel: t('dialog.close.confirm'),
|
|
382
|
-
cancelLabel: t('dialog.close.cancel'),
|
|
383
|
-
variant: 'danger',
|
|
384
|
-
});
|
|
385
|
-
if (!result.confirmed)
|
|
386
|
-
return;
|
|
387
|
-
const binary = egoBinary();
|
|
388
|
-
if (!binary || !(await installedVersion(binary)))
|
|
389
|
-
throw new Error(t('error.notInstalled'));
|
|
390
|
-
const script = `const result = await completeTaskSpace(${JSON.stringify(spaceId)}, { keep: false }); cliLog(JSON.stringify(result));`;
|
|
391
|
-
await runCommand(binary, ['nodejs', '-e', script], 15_000);
|
|
392
|
-
cachedStatus = undefined;
|
|
393
|
-
action.notifyUpdate();
|
|
394
|
-
refreshStatus(true);
|
|
395
|
-
await ctx.ui.showToast({ title: t('toast.closed'), variant: 'success', position: 'TC' });
|
|
396
|
-
return;
|
|
397
|
-
}
|
|
398
|
-
if (itemId.startsWith('tab:')) {
|
|
399
|
-
const [spaceId, targetId] = unkey(itemId.slice('tab:'.length));
|
|
400
|
-
await launchEgo();
|
|
401
|
-
const binary = egoBinary();
|
|
402
|
-
const script = `await switchTaskSpace(${JSON.stringify(spaceId)}); await switchTab(${JSON.stringify(targetId)}); cliLog('ok');`;
|
|
403
|
-
await runCommand(binary, ['nodejs', '-e', script], 10_000);
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
catch (error) {
|
|
407
|
-
ctx.logger.error('Ego Composer action failed', error);
|
|
408
|
-
await ctx.ui.showToast({
|
|
409
|
-
title: t('toast.actionFailed'),
|
|
410
|
-
description: error instanceof Error ? error.message : String(error),
|
|
411
|
-
variant: 'error',
|
|
412
|
-
position: 'TC',
|
|
413
|
-
});
|
|
414
|
-
}
|
|
415
|
-
},
|
|
416
|
-
});
|
|
417
|
-
ctx.subscriptions.push(action);
|
|
418
|
-
ctx.subscriptions.push(ctx.i18n.onDidChangeLocale(() => action.notifyUpdate()));
|
|
419
|
-
ctx.subscriptions.push(ctx.tools.register({
|
|
420
|
-
name: 'ego_browser',
|
|
421
|
-
title: 'Ego Browser',
|
|
422
|
-
description: `Operate Ego Browser through its preloaded JavaScript helpers.
|
|
423
|
-
action:
|
|
424
|
-
status — check installation, runtime, task-space ownership, and open pages
|
|
425
|
-
run — execute one coherent Ego Browser JavaScript program (requires script)
|
|
426
|
-
Use cliLog(...) for output. Reuse task spaces, respect user control, verify actions, and complete finished spaces.`,
|
|
427
|
-
inputSchema: {
|
|
428
|
-
type: 'object',
|
|
429
|
-
properties: {
|
|
430
|
-
action: { type: 'string', enum: ['status', 'run'] },
|
|
431
|
-
script: { type: 'string', description: 'JavaScript program for action=run. Ego Browser helpers are preloaded.' },
|
|
432
|
-
timeout_seconds: { type: 'number', description: 'Execution timeout for action=run, from 1 to 300 seconds. Default 60.' },
|
|
433
|
-
},
|
|
434
|
-
required: ['action'],
|
|
435
|
-
},
|
|
436
|
-
risk: 'high',
|
|
437
|
-
defaultEnabled: true,
|
|
438
|
-
async execute(input, exec) {
|
|
439
|
-
const request = input;
|
|
440
|
-
if (request.action === 'status') {
|
|
441
|
-
const status = await getStatus(true);
|
|
442
|
-
cachedStatus = status;
|
|
443
|
-
action.notifyUpdate();
|
|
444
|
-
return { content: [{ type: 'text', text: statusText(status, t) }], isError: !status.supported || Boolean(status.error) };
|
|
445
|
-
}
|
|
446
|
-
if (request.action !== 'run' || typeof request.script !== 'string' || !request.script.trim()) {
|
|
447
|
-
return { content: [{ type: 'text', text: 'action=run requires a non-empty script.' }], isError: true };
|
|
448
|
-
}
|
|
449
|
-
if (request.script.length > 100_000 || request.script.includes('\0')) {
|
|
450
|
-
return { content: [{ type: 'text', text: 'The Ego Browser script is invalid or too large.' }], isError: true };
|
|
451
|
-
}
|
|
452
|
-
if (process.platform !== 'darwin') {
|
|
453
|
-
return { content: [{ type: 'text', text: t('status.unsupported', { platform: process.platform }) }], isError: true };
|
|
454
|
-
}
|
|
455
|
-
const binary = egoBinary();
|
|
456
|
-
const version = binary ? await installedVersion(binary) : undefined;
|
|
457
|
-
if (!binary || !version) {
|
|
458
|
-
return {
|
|
459
|
-
content: [{ type: 'text', text: `Ego Lite is not installed. Install it from ${WEBSITE}, finish onboarding, then retry.` }],
|
|
460
|
-
isError: true,
|
|
461
|
-
};
|
|
462
|
-
}
|
|
463
|
-
if (!(await processRunning())) {
|
|
464
|
-
exec.progress.report({ stage: 'launching', message: t('progress.launching') });
|
|
465
|
-
await launchEgo();
|
|
466
|
-
await new Promise((resolve) => setTimeout(resolve, 1800));
|
|
467
|
-
}
|
|
468
|
-
const timeout = Math.min(300, Math.max(1, request.timeout_seconds ?? 60)) * 1000;
|
|
469
|
-
exec.progress.report({ stage: 'browsing', message: t('progress.browsing') });
|
|
470
|
-
try {
|
|
471
|
-
const output = await runCommand(binary, ['nodejs', '-e', request.script], timeout);
|
|
472
|
-
cachedStatus = undefined;
|
|
473
|
-
action.notifyUpdate();
|
|
474
|
-
refreshStatus(false);
|
|
475
|
-
return { content: [{ type: 'text', text: output || 'Ego Browser script completed.' }] };
|
|
476
|
-
}
|
|
477
|
-
catch (error) {
|
|
478
|
-
cachedStatus = undefined;
|
|
479
|
-
action.notifyUpdate();
|
|
480
|
-
refreshStatus(false);
|
|
481
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
482
|
-
return { content: [{ type: 'text', text: message }], isError: true };
|
|
483
|
-
}
|
|
484
|
-
},
|
|
485
|
-
}));
|
|
486
|
-
refreshStatus = (detailed = false) => {
|
|
487
|
-
if (refreshInFlight) {
|
|
488
|
-
pendingDetailedRefresh ||= detailed;
|
|
489
|
-
return;
|
|
166
|
+
function activate(ctx) {
|
|
167
|
+
const t = (key2, values) => ctx.i18n.t(key2, values);
|
|
168
|
+
ctx.subscriptions.push(ctx.icons.register("ego-browser-icons", {
|
|
169
|
+
ego: {
|
|
170
|
+
svg: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor"><path stroke-width=".77" d="M4.78 3.634c1.066 0 2.042.38 2.803 1.012-.421.91-.668 2.099-.668 3.384s.248 2.474.669 3.384a4.396 4.396 0 1 1-2.804-7.78Zm4.938 0c.446 0 .95.367 1.367 1.19.405.8.667 1.934.667 3.206s-.262 2.406-.667 3.206c-.416.823-.92 1.19-1.367 1.19-.38 0-.803-.266-1.179-.858A5.15 5.15 0 0 0 9.944 8.03c0-1.37-.535-2.616-1.405-3.54.376-.59.799-.856 1.179-.856Zm5.05.007c.024.015.076.06.152.184.12.196.24.505.348.921.212.826.348 1.987.348 3.284s-.136 2.459-.348 3.285c-.107.415-.229.724-.348.92a.6.6 0 0 1-.151.183.6.6 0 0 1-.15-.184c-.12-.195-.242-.504-.348-.92-.213-.825-.348-1.987-.348-3.284s.135-2.458.348-3.284c.106-.416.228-.725.347-.92a.6.6 0 0 1 .15-.185Z"/></svg>'
|
|
171
|
+
},
|
|
172
|
+
"bot-off": {
|
|
173
|
+
svg: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M13.67 8H18a2 2 0 0 1 2 2v4.33"/><path d="M2 14h2"/><path d="M20 14h2"/><path d="M22 22 2 2"/><path d="M8 8H6a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h12a2 2 0 0 0 1.414-.586"/><path d="M9 13v2"/><path d="M9.67 4H12v2.33"/></svg>'
|
|
174
|
+
},
|
|
175
|
+
compass: {
|
|
176
|
+
svg: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m16.24 7.76-1.804 5.411a2 2 0 0 1-1.265 1.265L7.76 16.24l1.804-5.411a2 2 0 0 1 1.265-1.265z"/></svg>'
|
|
177
|
+
},
|
|
178
|
+
bot: {
|
|
179
|
+
svg: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 8V4H8"/><rect width="16" height="12" x="4" y="8" rx="2"/><path d="M2 14h2"/><path d="M20 14h2"/><path d="M15 13v2"/><path d="M9 13v2"/></svg>'
|
|
180
|
+
},
|
|
181
|
+
x: {
|
|
182
|
+
svg: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>'
|
|
183
|
+
},
|
|
184
|
+
play: {
|
|
185
|
+
svg: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z"/></svg>'
|
|
186
|
+
}
|
|
187
|
+
}));
|
|
188
|
+
let cachedStatus;
|
|
189
|
+
let refreshInFlight;
|
|
190
|
+
let pendingDetailedRefresh = false;
|
|
191
|
+
let refreshStatus = () => {
|
|
192
|
+
};
|
|
193
|
+
const action = ctx.composerActions.register("ego-browser", {
|
|
194
|
+
async getBadge() {
|
|
195
|
+
const online = cachedStatus?.installed === true && cachedStatus.running === true && !cachedStatus.error;
|
|
196
|
+
if (cachedStatus?.supported === false) return { text: t("badge.unsupported"), active: false };
|
|
197
|
+
return online ? { text: t("badge.online"), active: true } : { text: t("badge.offline"), active: false };
|
|
198
|
+
},
|
|
199
|
+
async getMenu() {
|
|
200
|
+
refreshStatus(true);
|
|
201
|
+
if (!cachedStatus) {
|
|
202
|
+
return [{
|
|
203
|
+
id: "__checking__",
|
|
204
|
+
label: t("menu.checking.label"),
|
|
205
|
+
description: t("menu.checking.description"),
|
|
206
|
+
iconName: "timer",
|
|
207
|
+
disabled: true
|
|
208
|
+
}, {
|
|
209
|
+
id: "__install__",
|
|
210
|
+
label: t("menu.help.label"),
|
|
211
|
+
description: "lite.ego.app",
|
|
212
|
+
iconName: "lightbulb"
|
|
213
|
+
}];
|
|
214
|
+
}
|
|
215
|
+
const status = cachedStatus;
|
|
216
|
+
if (!status.supported) {
|
|
217
|
+
return [{
|
|
218
|
+
id: "__unsupported__",
|
|
219
|
+
label: t("menu.unsupported.label"),
|
|
220
|
+
description: t("menu.unsupported.description"),
|
|
221
|
+
hoverText: t("menu.unsupported.hover", { platform: process.platform }),
|
|
222
|
+
iconName: "ext:ego-browser-icons/bot-off",
|
|
223
|
+
disabled: true
|
|
224
|
+
}, {
|
|
225
|
+
id: "__unsupported_divider__",
|
|
226
|
+
label: "",
|
|
227
|
+
separator: true
|
|
228
|
+
}, {
|
|
229
|
+
id: "__install__",
|
|
230
|
+
label: t("menu.learn.label"),
|
|
231
|
+
description: "lite.ego.app",
|
|
232
|
+
iconName: "lightbulb"
|
|
233
|
+
}];
|
|
234
|
+
}
|
|
235
|
+
if (!status.installed) {
|
|
236
|
+
return [{
|
|
237
|
+
id: "__install__",
|
|
238
|
+
label: t("menu.install.label"),
|
|
239
|
+
description: t("menu.install.description"),
|
|
240
|
+
hoverText: t("menu.install.hover"),
|
|
241
|
+
iconName: "rocket"
|
|
242
|
+
}];
|
|
243
|
+
}
|
|
244
|
+
if (!status.running) {
|
|
245
|
+
return [{
|
|
246
|
+
id: "__install__",
|
|
247
|
+
label: t("menu.help.label"),
|
|
248
|
+
description: "lite.ego.app",
|
|
249
|
+
iconName: "lightbulb"
|
|
250
|
+
}, {
|
|
251
|
+
id: "__launch_divider__",
|
|
252
|
+
label: "",
|
|
253
|
+
separator: true
|
|
254
|
+
}, {
|
|
255
|
+
id: "__launch__",
|
|
256
|
+
label: t("menu.launch.label"),
|
|
257
|
+
description: status.version,
|
|
258
|
+
iconName: "ext:ego-browser-icons/play"
|
|
259
|
+
}];
|
|
260
|
+
}
|
|
261
|
+
const items = [{
|
|
262
|
+
id: "__summary__",
|
|
263
|
+
label: t("menu.summary.spaces", { count: status.spaces.length }),
|
|
264
|
+
description: t("menu.summary.pages", { count: status.pageCount }),
|
|
265
|
+
iconName: "ext:ego-browser-icons/compass",
|
|
266
|
+
disabled: true
|
|
267
|
+
}, {
|
|
268
|
+
id: "__spaces_divider__",
|
|
269
|
+
label: "",
|
|
270
|
+
separator: true
|
|
271
|
+
}];
|
|
272
|
+
for (const space of status.spaces) {
|
|
273
|
+
const tabs = space.tabs ?? [];
|
|
274
|
+
const children = tabs.map((tab, index) => ({
|
|
275
|
+
id: `tab:${key([space.id, tab.targetId])}`,
|
|
276
|
+
label: compactTitle(tab.title, t("page.untitled")),
|
|
277
|
+
hoverText: `${tab.title || t("page.untitled")}
|
|
278
|
+
${domainOf(tab.url, t("site.unknown"))}`,
|
|
279
|
+
current: tab.active,
|
|
280
|
+
iconName: "globe",
|
|
281
|
+
group: `space-${space.id}`,
|
|
282
|
+
groupLabel: index === 0 ? ownershipText(space.ownership, t) : void 0,
|
|
283
|
+
groupMaxVisible: index === 0 ? 6 : void 0
|
|
284
|
+
}));
|
|
285
|
+
if (space.ownership === "agentDelegatedToUser") {
|
|
286
|
+
children.push({
|
|
287
|
+
id: `resume:${key(space.id)}`,
|
|
288
|
+
label: t("menu.resume.label"),
|
|
289
|
+
description: t("menu.resume.description"),
|
|
290
|
+
iconName: "message-circle"
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
if (children.length === 0) {
|
|
294
|
+
children.push({
|
|
295
|
+
id: `space:${key(space.id)}`,
|
|
296
|
+
label: ownershipText(space.ownership, t),
|
|
297
|
+
description: t("menu.summary.pages", { count: space.recentTabTitles?.length ?? 0 }),
|
|
298
|
+
iconName: space.ownership === "agent" ? "bot" : "users",
|
|
299
|
+
disabled: true
|
|
300
|
+
});
|
|
490
301
|
}
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
.finally(() => {
|
|
498
|
-
refreshInFlight = undefined;
|
|
499
|
-
if (pendingDetailedRefresh) {
|
|
500
|
-
pendingDetailedRefresh = false;
|
|
501
|
-
refreshStatus(true);
|
|
502
|
-
}
|
|
302
|
+
children.push({ id: `close-divider:${space.id}`, label: "", separator: true });
|
|
303
|
+
children.push({
|
|
304
|
+
id: `close:${key(space.id)}`,
|
|
305
|
+
label: t("menu.close.label"),
|
|
306
|
+
description: t("menu.close.description"),
|
|
307
|
+
iconName: "ext:ego-browser-icons/x"
|
|
503
308
|
});
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
309
|
+
items.push({
|
|
310
|
+
id: `space-menu:${space.id}`,
|
|
311
|
+
label: space.name || t("menu.space.fallback", { id: space.id }),
|
|
312
|
+
description: ownershipText(space.ownership, t),
|
|
313
|
+
iconName: space.ownership === "agent" ? "ext:ego-browser-icons/bot" : "ext:ego-browser-icons/compass",
|
|
314
|
+
children
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
if (status.spaces.length === 0) {
|
|
318
|
+
items.push({
|
|
319
|
+
id: "__empty__",
|
|
320
|
+
label: t("menu.empty.label"),
|
|
321
|
+
description: t("menu.empty.description"),
|
|
322
|
+
hoverText: t("menu.empty.hover"),
|
|
323
|
+
iconName: "ext:ego-browser-icons/bot-off"
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
return items;
|
|
327
|
+
},
|
|
328
|
+
async execute(_actionContext, itemId, actions) {
|
|
329
|
+
try {
|
|
330
|
+
if (itemId === "__install__") {
|
|
331
|
+
await openWebsite();
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
if (itemId === "__empty__") {
|
|
335
|
+
await actions.composer.fill(t("composer.startPrompt"));
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
if (itemId === "__launch__") {
|
|
339
|
+
await launchEgo();
|
|
340
|
+
await ctx.ui.showToast({ title: t("toast.launched"), variant: "success", position: "TC" });
|
|
341
|
+
cachedStatus = void 0;
|
|
342
|
+
action.notifyUpdate();
|
|
343
|
+
refreshStatus(true);
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
if (itemId.startsWith("resume:")) {
|
|
347
|
+
const spaceId = unkey(itemId.slice("resume:".length));
|
|
348
|
+
await actions.composer.fill(t("composer.resumePrompt", { id: spaceId }));
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
if (itemId.startsWith("close:")) {
|
|
352
|
+
const spaceId = unkey(itemId.slice("close:".length));
|
|
353
|
+
const space = cachedStatus?.spaces.find((item) => item.id === spaceId);
|
|
354
|
+
const result = await ctx.ui.showConfirmDialog({
|
|
355
|
+
title: t("dialog.close.title"),
|
|
356
|
+
description: space?.name || t("menu.space.fallback", { id: spaceId }),
|
|
357
|
+
message: t("dialog.close.message", { count: space?.tabs?.length ?? space?.recentTabTitles?.length ?? 0 }),
|
|
358
|
+
confirmLabel: t("dialog.close.confirm"),
|
|
359
|
+
cancelLabel: t("dialog.close.cancel"),
|
|
360
|
+
variant: "danger"
|
|
361
|
+
});
|
|
362
|
+
if (!result.confirmed) return;
|
|
363
|
+
const binary = egoBinary();
|
|
364
|
+
if (!binary || !await installedVersion(binary)) throw new Error(t("error.notInstalled"));
|
|
365
|
+
const script = `const result = await completeTaskSpace(${JSON.stringify(spaceId)}, { keep: false }); cliLog(JSON.stringify(result));`;
|
|
366
|
+
await runCommand(binary, ["nodejs", "-e", script], 15e3);
|
|
367
|
+
cachedStatus = void 0;
|
|
368
|
+
action.notifyUpdate();
|
|
369
|
+
refreshStatus(true);
|
|
370
|
+
await ctx.ui.showToast({ title: t("toast.closed"), variant: "success", position: "TC" });
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
if (itemId.startsWith("tab:")) {
|
|
374
|
+
const [spaceId, targetId] = unkey(itemId.slice("tab:".length));
|
|
375
|
+
await launchEgo();
|
|
376
|
+
const binary = egoBinary();
|
|
377
|
+
const script = `await switchTaskSpace(${JSON.stringify(spaceId)}); await switchTab(${JSON.stringify(targetId)}); cliLog('ok');`;
|
|
378
|
+
await runCommand(binary, ["nodejs", "-e", script], 1e4);
|
|
379
|
+
}
|
|
380
|
+
} catch (error) {
|
|
381
|
+
ctx.logger.error("Ego Composer action failed", error);
|
|
382
|
+
await ctx.ui.showToast({
|
|
383
|
+
title: t("toast.actionFailed"),
|
|
384
|
+
description: error instanceof Error ? error.message : String(error),
|
|
385
|
+
variant: "error",
|
|
386
|
+
position: "TC"
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
ctx.subscriptions.push(action);
|
|
392
|
+
ctx.subscriptions.push(ctx.i18n.onDidChangeLocale(() => action.notifyUpdate()));
|
|
393
|
+
ctx.subscriptions.push(ctx.tools.register({
|
|
394
|
+
name: "ego_browser",
|
|
395
|
+
title: "Ego Browser",
|
|
396
|
+
description: `Operate Ego Browser through its preloaded JavaScript helpers.
|
|
397
|
+
action:
|
|
398
|
+
status \u2014 check installation, runtime, task-space ownership, and open pages
|
|
399
|
+
run \u2014 execute one coherent Ego Browser JavaScript program (requires script)
|
|
400
|
+
Use cliLog(...) for output. Reuse task spaces, respect user control, verify actions, and complete finished spaces.`,
|
|
401
|
+
inputSchema: {
|
|
402
|
+
type: "object",
|
|
403
|
+
properties: {
|
|
404
|
+
action: { type: "string", enum: ["status", "run"] },
|
|
405
|
+
script: { type: "string", description: "JavaScript program for action=run. Ego Browser helpers are preloaded." },
|
|
406
|
+
timeout_seconds: { type: "number", description: "Execution timeout for action=run, from 1 to 300 seconds. Default 60." }
|
|
407
|
+
},
|
|
408
|
+
required: ["action"]
|
|
409
|
+
},
|
|
410
|
+
risk: "high",
|
|
411
|
+
defaultEnabled: true,
|
|
412
|
+
async execute(input, exec) {
|
|
413
|
+
const request = input;
|
|
414
|
+
if (request.action === "status") {
|
|
415
|
+
const status = await getStatus(true);
|
|
416
|
+
cachedStatus = status;
|
|
417
|
+
action.notifyUpdate();
|
|
418
|
+
return { content: [{ type: "text", text: statusText(status, t) }], isError: !status.supported || Boolean(status.error) };
|
|
419
|
+
}
|
|
420
|
+
if (request.action !== "run" || typeof request.script !== "string" || !request.script.trim()) {
|
|
421
|
+
return { content: [{ type: "text", text: "action=run requires a non-empty script." }], isError: true };
|
|
422
|
+
}
|
|
423
|
+
if (request.script.length > 1e5 || request.script.includes("\0")) {
|
|
424
|
+
return { content: [{ type: "text", text: "The Ego Browser script is invalid or too large." }], isError: true };
|
|
425
|
+
}
|
|
426
|
+
if (process.platform !== "darwin") {
|
|
427
|
+
return { content: [{ type: "text", text: t("status.unsupported", { platform: process.platform }) }], isError: true };
|
|
428
|
+
}
|
|
429
|
+
const binary = egoBinary();
|
|
430
|
+
const version = binary ? await installedVersion(binary) : void 0;
|
|
431
|
+
if (!binary || !version) {
|
|
432
|
+
return {
|
|
433
|
+
content: [{ type: "text", text: `Ego Lite is not installed. Install it from ${WEBSITE}, finish onboarding, then retry.` }],
|
|
434
|
+
isError: true
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
if (!await processRunning()) {
|
|
438
|
+
exec.progress.report({ stage: "launching", message: t("progress.launching") });
|
|
439
|
+
await launchEgo();
|
|
440
|
+
await new Promise((resolve) => setTimeout(resolve, 1800));
|
|
441
|
+
}
|
|
442
|
+
const timeout = Math.min(300, Math.max(1, request.timeout_seconds ?? 60)) * 1e3;
|
|
443
|
+
exec.progress.report({ stage: "browsing", message: t("progress.browsing") });
|
|
444
|
+
try {
|
|
445
|
+
const output = await runCommand(binary, ["nodejs", "-e", request.script], timeout);
|
|
446
|
+
cachedStatus = void 0;
|
|
447
|
+
action.notifyUpdate();
|
|
448
|
+
refreshStatus(false);
|
|
449
|
+
return { content: [{ type: "text", text: output || "Ego Browser script completed." }] };
|
|
450
|
+
} catch (error) {
|
|
451
|
+
cachedStatus = void 0;
|
|
452
|
+
action.notifyUpdate();
|
|
453
|
+
refreshStatus(false);
|
|
454
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
455
|
+
return { content: [{ type: "text", text: message }], isError: true };
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}));
|
|
459
|
+
refreshStatus = (detailed = false) => {
|
|
460
|
+
if (refreshInFlight) {
|
|
461
|
+
pendingDetailedRefresh ||= detailed;
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
refreshInFlight = getStatus(detailed).then((status) => {
|
|
465
|
+
cachedStatus = status;
|
|
466
|
+
action.notifyUpdate();
|
|
467
|
+
}).catch((error) => ctx.logger.warn("Ego background status refresh failed", error)).finally(() => {
|
|
468
|
+
refreshInFlight = void 0;
|
|
469
|
+
if (pendingDetailedRefresh) {
|
|
470
|
+
pendingDetailedRefresh = false;
|
|
471
|
+
refreshStatus(true);
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
};
|
|
475
|
+
refreshStatus(true);
|
|
476
|
+
const timer = setInterval(() => refreshStatus(true), 1e4);
|
|
477
|
+
ctx.subscriptions.push({ dispose: () => clearInterval(timer) });
|
|
478
|
+
ctx.logger.info("ego-browser mini tool activated", { cached: Boolean(cachedStatus) });
|
|
479
|
+
}
|
|
480
|
+
function deactivate() {
|
|
509
481
|
}
|
|
510
|
-
export
|
|
482
|
+
export {
|
|
483
|
+
activate,
|
|
484
|
+
deactivate
|
|
485
|
+
};
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "finch-ego-lite",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Let Finch browse the web in isolated Ego Lite task spaces while you follow every page it opens.",
|
|
5
5
|
"author": {
|
|
6
|
-
"name": "
|
|
6
|
+
"name": "PuterJam",
|
|
7
7
|
"url": "https://github.com/puterjam"
|
|
8
8
|
},
|
|
9
9
|
"repository": {
|
|
@@ -19,8 +19,9 @@
|
|
|
19
19
|
"type": "module",
|
|
20
20
|
"main": "dist/index.js",
|
|
21
21
|
"scripts": {
|
|
22
|
-
"build": "
|
|
23
|
-
"
|
|
22
|
+
"build": "esbuild src/index.ts --bundle --platform=node --format=esm --target=node18 --outfile=dist/index.js",
|
|
23
|
+
"typecheck": "tsc --noEmit",
|
|
24
|
+
"prepublishOnly": "npm run typecheck && npm run build && npx @finchtoys/minitools doctor ."
|
|
24
25
|
},
|
|
25
26
|
"finch": {
|
|
26
27
|
"manifestVersion": 1,
|
|
@@ -29,9 +30,14 @@
|
|
|
29
30
|
"description": "Control Ego Browser and see the pages your Agent is working on.",
|
|
30
31
|
"systemPrompt": "Use ego_browser for browser automation. Call action=status to inspect Ego availability and task spaces. Call action=run with one coherent ego-browser JavaScript program for browser work. Reuse task spaces, respect user ownership, verify meaningful actions, and complete spaces when done.",
|
|
31
32
|
"main": "dist/index.js",
|
|
32
|
-
"activationEvents": [
|
|
33
|
+
"activationEvents": [
|
|
34
|
+
"onStartup"
|
|
35
|
+
],
|
|
33
36
|
"miniToolType": "local",
|
|
34
|
-
"categories": [
|
|
37
|
+
"categories": [
|
|
38
|
+
"productivity",
|
|
39
|
+
"developer"
|
|
40
|
+
],
|
|
35
41
|
"contributes": {
|
|
36
42
|
"tools": true,
|
|
37
43
|
"composerActions": [
|
|
@@ -58,7 +64,14 @@
|
|
|
58
64
|
"devDependencies": {
|
|
59
65
|
"@finchtoys/minitool-api": "^0.2.9",
|
|
60
66
|
"@types/node": "^26.1.0",
|
|
67
|
+
"esbuild": "^0.28.1",
|
|
61
68
|
"typescript": "^6.0.3"
|
|
62
69
|
},
|
|
63
|
-
"files": [
|
|
70
|
+
"files": [
|
|
71
|
+
"dist/",
|
|
72
|
+
"i18n/",
|
|
73
|
+
"skills/",
|
|
74
|
+
"icon.png",
|
|
75
|
+
"README.md"
|
|
76
|
+
]
|
|
64
77
|
}
|