agen-vektor 0.3.28 → 0.3.29

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/tools/e2b.js CHANGED
@@ -335,6 +335,90 @@ ${lines.join('\n')}`,
335
335
  };
336
336
  },
337
337
  },
338
+ {
339
+ definition: {
340
+ name: 'e2b_screenshot',
341
+ description: 'Take a screenshot of a URL with headless Chromium INSIDE a persistent e2b cloud session (from e2b_cloud create) and get it back as a downloadable gateway link (render_ui button opens it). Requires Playwright+Chromium installed in the session (npx playwright install --with-deps chromium). The target URL is fetched FROM INSIDE the sandbox — use http://localhost:<port> for dev servers running in this session. The sandbox needs internet unless the target is localhost.',
342
+ parameters: {
343
+ type: 'object',
344
+ properties: {
345
+ id: { type: 'string', description: 'Session id from e2b_cloud create' },
346
+ url: { type: 'string', description: 'URL to capture, e.g. http://localhost:3000 (default)' },
347
+ wait_ms: { type: 'number', description: 'Milliseconds to wait for page load before capturing (default 1500)' },
348
+ full_page: { type: 'boolean', description: 'Capture full scrollable page (default false)' },
349
+ },
350
+ required: ['id'],
351
+ },
352
+ },
353
+ async execute(args, ctx) {
354
+ const id = String(args.id || '');
355
+ const target = String(args.url || 'http://localhost:3000').trim();
356
+ if (!/^[A-Za-z0-9-]{8,80}$/.test(id))
357
+ return { output: 'ERROR: invalid session id' };
358
+ if (!/^https?:\/\//.test(target) || target.includes("'"))
359
+ return { output: 'ERROR: url harus http(s) tanpa quote' };
360
+ const waitMs = Math.min(15_000, Math.max(0, Number(args.wait_ms) || 1500));
361
+ const fullPage = args.full_page === true;
362
+ // Dua langkah: (1) exec script Playwright → simpan PNG di /home/user/, (2) beri
363
+ // link download via route /v1/e2b/file (gateway stream PNG → tombol render_ui
364
+ // di TUI membukanya di browser). Script memakai flag jitless WAJIB (gotcha V8
365
+ // OOM di sandbox kecil) dan hanya setelah marker __VECTOR_DONE_ hasil poll.
366
+ // PENTING: script DITULIS ke /home/user (bukan /tmp) — ESM resolve
367
+ // `import 'playwright'` relatif thd lokasi file, dan package terinstall
368
+ // di /home/user/node_modules (npm i tanpa -g).
369
+ const script = [
370
+ 'mkdir -p /home/user',
371
+ `cat > /home/user/vector-shot.mjs <<\'EOF\'`,
372
+ `import { chromium } from 'playwright';`,
373
+ `const b = await chromium.launch({ args: ['--no-sandbox','--disable-dev-shm-usage','--disable-gpu','--js-flags=--jitless'] });`,
374
+ `const p = await b.newPage();`,
375
+ `try {`,
376
+ ` await p.goto(${JSON.stringify(target)}, { waitUntil: 'load', timeout: 20000 });`,
377
+ ` await p.waitForTimeout(${waitMs});`,
378
+ ` await p.screenshot({ path: '/home/user/vector-preview.png', fullPage: ${fullPage ? 'true' : 'false'} });`,
379
+ ` console.log('SHOT_OK');`,
380
+ `} catch (e) { console.log('SHOT_ERR ' + e.message); await b.close(); process.exit(3); }`,
381
+ `await b.close();`,
382
+ `EOF`,
383
+ `cd /home/user && node /home/user/vector-shot.mjs`,
384
+ ].join('\n');
385
+ ctx.onActivity?.('e2b', `screenshot ${target}`);
386
+ // Poll exec manual di sini (bukan e2bExec blocking): kita butuh exit code.
387
+ const started = await fetch(GW_BASE + '/v1/e2b/exec?id=' + encodeURIComponent(id), {
388
+ method: 'POST',
389
+ headers: { 'Content-Type': 'application/json', 'User-Agent': 'VectorHead-AI-Agent/0.1' },
390
+ body: JSON.stringify({ command: script }),
391
+ signal: AbortSignal.timeout(30_000),
392
+ });
393
+ const sdata = (await started.json().catch(() => null));
394
+ if (!started.ok || !sdata?.jobId) {
395
+ return { output: `ERROR: e2b exec gagal — ${(0, credentials_1.redact)(sdata?.error || 'HTTP ' + started.status)}`, summary: 'screenshot exec error' };
396
+ }
397
+ const t0 = Date.now();
398
+ while (Date.now() - t0 < 90_000) {
399
+ await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
400
+ const jr = await fetch(GW_BASE + '/v1/e2b/job?id=' + encodeURIComponent(id) + '&job=' + sdata.jobId, {
401
+ signal: AbortSignal.timeout(15_000),
402
+ });
403
+ const j = (await jr.json().catch(() => null));
404
+ if (j?.status === 'done') {
405
+ if (j.exitCode !== 0 || !(j.stdout || '').includes('SHOT_OK')) {
406
+ const why = (j.stderr || j.stdout || '').trim().slice(0, 300);
407
+ return { output: `ERROR: screenshot gagal (exit ${j.exitCode})\n${(0, credentials_1.redact)(why)}` + (why.includes('Cannot find package') ? '\n→ Playwright belum terpasang di sesi ini: e2b_exec {command: "npm i playwright && npx playwright install --with-deps chromium"}' : ''), summary: 'screenshot error' };
408
+ }
409
+ const link = `${GW_BASE}/v1/e2b/file?id=${encodeURIComponent(id)}&path=%2Fhome%2Fuser%2Fvector-preview.png`;
410
+ return {
411
+ output: `screenshot tersimpan: /home/user/vector-preview.png (${target})\nlink: ${link}`,
412
+ summary: `e2b screenshot ${target}`,
413
+ data: { widget: { type: 'button', text: '🖼 Lihat screenshot', link }, screenshot: link },
414
+ };
415
+ }
416
+ if (j?.status === 'error')
417
+ break;
418
+ }
419
+ return { output: 'ERROR: screenshot timeout (job tidak selesai dalam 90s)', summary: 'screenshot timeout' };
420
+ },
421
+ },
338
422
  {
339
423
  definition: {
340
424
  name: 'e2b_download',
package/dist/tui/app.js CHANGED
@@ -1763,7 +1763,13 @@ class App {
1763
1763
  this.runFollowupMsgs.push(followupMsg);
1764
1764
  }
1765
1765
  }
1766
- if (tool === 'render_ui' && data && data.widget) {
1766
+ // Tombol UI: tool render_ui — dan kini juga tool e2b (screenshot/
1767
+ // preview) — bisa mengembalikan data.widget {type:'button',text,link}.
1768
+ // Whitelist supaya tool pihak ketiga (MCP) tidak bisa memicu tombol
1769
+ // (surface prompt-injection: deskripsi/hasil tool = untrusted data).
1770
+ if ((tool === 'render_ui' || tool.startsWith('e2b_')) &&
1771
+ data &&
1772
+ data.widget) {
1767
1773
  const w = data.widget;
1768
1774
  this.activeUiButton = w;
1769
1775
  this.messages.push({ kind: 'ui', content: w.text, ui: w, ts: Date.now() });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agen-vektor",
3
- "version": "0.3.28",
3
+ "version": "0.3.29",
4
4
  "description": "VectorHead (agen-vektor) — AI Coding Agent CLI/TUI for Linux & Termux. Multi-provider, tool calling, session, permission system.",
5
5
  "type": "commonjs",
6
6
  "bin": {