skopix 2.0.106 → 2.0.107
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/cli/commands/agent.js +44 -46
- package/package.json +1 -1
package/cli/commands/agent.js
CHANGED
|
@@ -390,61 +390,27 @@ export async function agentCommand(options) {
|
|
|
390
390
|
const sendRun = (data) => { try { ws.send(JSON.stringify({ type: 'runUpdate', runId, data })); } catch {} };
|
|
391
391
|
const sendRec = (data) => { try { ws.send(JSON.stringify({ type: 'recordingUpdate', recordingId, data })); } catch {} };
|
|
392
392
|
const steps = [];
|
|
393
|
+
let chromiumBrowser = null;
|
|
394
|
+
let page = null;
|
|
395
|
+
let ctx = null;
|
|
393
396
|
|
|
394
397
|
sendRun({ type: 'stdout', text: '' });
|
|
395
398
|
sendRun({ type: 'stdout', text: ' Replaying ' + replaySteps.length + ' steps to reach debug point...' });
|
|
396
399
|
sendRun({ type: 'stdout', text: '\u2501'.repeat(60) });
|
|
397
400
|
|
|
398
|
-
let chromiumBrowser = null;
|
|
399
|
-
let page = null;
|
|
400
|
-
let ctx = null;
|
|
401
|
-
|
|
402
401
|
try {
|
|
403
402
|
const { chromium } = await import('playwright');
|
|
404
403
|
chromiumBrowser = await chromium.launch({ headless: false, args: ['--no-sandbox', '--disable-blink-features=AutomationControlled', '--allow-insecure-localhost'] });
|
|
405
404
|
ctx = await chromiumBrowser.newContext({ viewport: { width: 1280, height: 800 } });
|
|
406
405
|
page = await ctx.newPage();
|
|
407
406
|
|
|
408
|
-
|
|
409
|
-
await page.goto(startUrl, { waitUntil: 'domcontentloaded', timeout: 30000 });
|
|
410
|
-
await page.waitForTimeout(1000);
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
// Replay steps to debug point
|
|
414
|
-
let stepNum = 0;
|
|
415
|
-
let browserClosed = false;
|
|
416
|
-
for (const step of replaySteps) {
|
|
417
|
-
if (browserClosed) break;
|
|
418
|
-
stepNum++;
|
|
419
|
-
const sel = sanitiseSelector(step.stableSelector || step.selector);
|
|
420
|
-
const desc = step.description || (step.action + ' ' + (sel || ''));
|
|
421
|
-
sendRun({ type: 'stdout', text: ' [' + stepNum + '/' + replaySteps.length + '] ' + step.action.toUpperCase() + ' \u2014 ' + desc });
|
|
422
|
-
try {
|
|
423
|
-
await executeStep(step, sel, page, { url: startUrl || '' });
|
|
424
|
-
sendRun({ type: 'stdout', text: ' \u2713 Done' });
|
|
425
|
-
} catch (err) {
|
|
426
|
-
const msg2 = err.message || '';
|
|
427
|
-
if (msg2.includes('closed') || msg2.includes('destroyed') || msg2.includes('detached')) {
|
|
428
|
-
browserClosed = true;
|
|
429
|
-
sendRun({ type: 'stdout', text: ' \u2716 Browser closed' });
|
|
430
|
-
} else {
|
|
431
|
-
sendRun({ type: 'stdout', text: ' \u26a0 Skipped: ' + msg2.slice(0, 100) });
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
sendRun({ type: 'stdout', text: '' });
|
|
437
|
-
sendRun({ type: 'stdout', text: ' \u2714 Reached debug point \u2014 recording started' });
|
|
438
|
-
sendRun({ type: 'stdout', text: ' Use the browser, then click Stop.' });
|
|
439
|
-
|
|
440
|
-
// Wire up capture — exposeFunction on context persists across navigations
|
|
407
|
+
// Wire up capture FIRST — must be on context before any page loads
|
|
441
408
|
await ctx.exposeFunction('__skopixCapture', async (actionData) => {
|
|
442
409
|
if (actionData.action === 'stop') {
|
|
443
|
-
//
|
|
444
|
-
sendRun({ type: 'done', exitCode: 0, status: 'passed', recordingId });
|
|
445
|
-
// Save steps
|
|
446
|
-
const screenshotDir = path.join(os.homedir(), '.skopix', 'recordings', recordingId);
|
|
410
|
+
// Mirror stopDebugRecording: send done with steps, then stopped
|
|
447
411
|
sendRec({ type: 'done', steps });
|
|
412
|
+
sendRec({ type: 'stopped' });
|
|
413
|
+
try { await ctx.close(); } catch {}
|
|
448
414
|
try { await chromiumBrowser.close(); } catch {}
|
|
449
415
|
ws.send(JSON.stringify({ type: 'jobDone', runId }));
|
|
450
416
|
console.log(chalk.green(' \u2714 Debug recording done \u2014 ' + steps.length + ' new steps'));
|
|
@@ -467,7 +433,6 @@ export async function agentCommand(options) {
|
|
|
467
433
|
sendRec({ type: 'step', step: recStep });
|
|
468
434
|
process.stdout.write(chalk.cyan(' \u23fa ') + (recStep.action || '') + '\n');
|
|
469
435
|
try { await page.evaluate(n => { if (window.__skopixUpdateCount) window.__skopixUpdateCount(n); }, steps.length); } catch {}
|
|
470
|
-
// Screenshot
|
|
471
436
|
setTimeout(async () => {
|
|
472
437
|
try {
|
|
473
438
|
const screenshotDir = path.join(os.homedir(), '.skopix', 'recordings', recordingId);
|
|
@@ -480,9 +445,13 @@ export async function agentCommand(options) {
|
|
|
480
445
|
}, 400);
|
|
481
446
|
});
|
|
482
447
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
448
|
+
if (startUrl) {
|
|
449
|
+
await page.goto(startUrl, { waitUntil: 'domcontentloaded', timeout: 30000 });
|
|
450
|
+
await page.waitForTimeout(500);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// Inject toolbar into page BEFORE replay — visible throughout
|
|
454
|
+
await page.evaluate(() => {
|
|
486
455
|
if (window.__skopixRecording) return;
|
|
487
456
|
window.__skopixRecording = true;
|
|
488
457
|
|
|
@@ -628,7 +597,36 @@ export async function agentCommand(options) {
|
|
|
628
597
|
});
|
|
629
598
|
});
|
|
630
599
|
|
|
631
|
-
|
|
600
|
+
|
|
601
|
+
|
|
602
|
+
// Replay steps to debug point
|
|
603
|
+
let stepNum = 0;
|
|
604
|
+
let browserClosed = false;
|
|
605
|
+
for (const step of replaySteps) {
|
|
606
|
+
if (browserClosed) break;
|
|
607
|
+
stepNum++;
|
|
608
|
+
const sel = sanitiseSelector(step.stableSelector || step.selector);
|
|
609
|
+
const desc = step.description || (step.action + ' ' + (sel || ''));
|
|
610
|
+
sendRun({ type: 'stdout', text: ' [' + stepNum + '/' + replaySteps.length + '] ' + step.action.toUpperCase() + ' \u2014 ' + desc });
|
|
611
|
+
try {
|
|
612
|
+
await executeStep(step, sel, page, { url: startUrl || '' });
|
|
613
|
+
sendRun({ type: 'stdout', text: ' \u2713 Done' });
|
|
614
|
+
} catch (err) {
|
|
615
|
+
const emsg = err.message || '';
|
|
616
|
+
if (emsg.includes('closed') || emsg.includes('destroyed') || emsg.includes('detached')) {
|
|
617
|
+
browserClosed = true;
|
|
618
|
+
sendRun({ type: 'stdout', text: ' \u2716 Browser closed' });
|
|
619
|
+
} else {
|
|
620
|
+
sendRun({ type: 'stdout', text: ' \u26a0 Skipped: ' + emsg.slice(0, 100) });
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
sendRun({ type: 'stdout', text: '' });
|
|
626
|
+
sendRun({ type: 'stdout', text: ' \u2714 Reached debug point \u2014 now recording' });
|
|
627
|
+
sendRun({ type: 'stdout', text: ' Use the browser, then click Stop.' });
|
|
628
|
+
|
|
629
|
+
// Tell dashboard replay is done — frontend switches to recording SSE
|
|
632
630
|
sendRun({ type: 'done', exitCode: 0, status: 'passed', recordingId });
|
|
633
631
|
process.stderr.write('[debug] toolbar injected, waiting for user actions\n');
|
|
634
632
|
|
package/package.json
CHANGED