misoai-web 1.6.0 → 1.6.2

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.
Files changed (71) hide show
  1. package/dist/es/agent.js +108 -50
  2. package/dist/es/agent.js.map +1 -1
  3. package/dist/es/bridge-mode-browser.js +3 -3
  4. package/dist/es/bridge-mode-browser.js.map +1 -1
  5. package/dist/es/bridge-mode.js +110 -52
  6. package/dist/es/bridge-mode.js.map +1 -1
  7. package/dist/es/chrome-extension.js +109 -51
  8. package/dist/es/chrome-extension.js.map +1 -1
  9. package/dist/es/index.js +425 -68
  10. package/dist/es/index.js.map +1 -1
  11. package/dist/es/midscene-playground.js +111 -53
  12. package/dist/es/midscene-playground.js.map +1 -1
  13. package/dist/es/midscene-server.js +4 -4
  14. package/dist/es/midscene-server.js.map +1 -1
  15. package/dist/es/playground.js +108 -50
  16. package/dist/es/playground.js.map +1 -1
  17. package/dist/es/playwright-report.js +1 -1
  18. package/dist/es/playwright-report.js.map +1 -1
  19. package/dist/es/playwright.js +425 -68
  20. package/dist/es/playwright.js.map +1 -1
  21. package/dist/es/puppeteer-agent-launcher.js +424 -67
  22. package/dist/es/puppeteer-agent-launcher.js.map +1 -1
  23. package/dist/es/puppeteer.js +424 -67
  24. package/dist/es/puppeteer.js.map +1 -1
  25. package/dist/es/utils.js +1 -1
  26. package/dist/es/utils.js.map +1 -1
  27. package/dist/es/yaml.js +1 -1
  28. package/dist/es/yaml.js.map +1 -1
  29. package/dist/lib/agent.js +108 -50
  30. package/dist/lib/agent.js.map +1 -1
  31. package/dist/lib/bridge-mode-browser.js +3 -3
  32. package/dist/lib/bridge-mode-browser.js.map +1 -1
  33. package/dist/lib/bridge-mode.js +110 -52
  34. package/dist/lib/bridge-mode.js.map +1 -1
  35. package/dist/lib/chrome-extension.js +109 -51
  36. package/dist/lib/chrome-extension.js.map +1 -1
  37. package/dist/lib/index.js +425 -68
  38. package/dist/lib/index.js.map +1 -1
  39. package/dist/lib/midscene-playground.js +111 -53
  40. package/dist/lib/midscene-playground.js.map +1 -1
  41. package/dist/lib/midscene-server.js +4 -4
  42. package/dist/lib/midscene-server.js.map +1 -1
  43. package/dist/lib/playground.js +108 -50
  44. package/dist/lib/playground.js.map +1 -1
  45. package/dist/lib/playwright-report.js +1 -1
  46. package/dist/lib/playwright-report.js.map +1 -1
  47. package/dist/lib/playwright.js +425 -68
  48. package/dist/lib/playwright.js.map +1 -1
  49. package/dist/lib/puppeteer-agent-launcher.js +424 -67
  50. package/dist/lib/puppeteer-agent-launcher.js.map +1 -1
  51. package/dist/lib/puppeteer.js +424 -67
  52. package/dist/lib/puppeteer.js.map +1 -1
  53. package/dist/lib/utils.js +1 -1
  54. package/dist/lib/utils.js.map +1 -1
  55. package/dist/lib/yaml.js +1 -1
  56. package/dist/lib/yaml.js.map +1 -1
  57. package/dist/types/agent.d.ts +1 -1
  58. package/dist/types/bridge-mode-browser.d.ts +2 -2
  59. package/dist/types/bridge-mode.d.ts +2 -2
  60. package/dist/types/{browser-9b472ffb.d.ts → browser-f205f69d.d.ts} +1 -1
  61. package/dist/types/chrome-extension.d.ts +2 -2
  62. package/dist/types/index.d.ts +2 -2
  63. package/dist/types/midscene-server.d.ts +1 -1
  64. package/dist/types/{page-ed0ecb44.d.ts → page-c5452809.d.ts} +45 -0
  65. package/dist/types/playground.d.ts +2 -2
  66. package/dist/types/playwright.d.ts +2 -2
  67. package/dist/types/puppeteer-agent-launcher.d.ts +1 -1
  68. package/dist/types/puppeteer.d.ts +2 -2
  69. package/dist/types/utils.d.ts +1 -1
  70. package/dist/types/yaml.d.ts +1 -1
  71. package/package.json +18 -54
@@ -306,8 +306,8 @@ var ScriptPlayer = class {
306
306
  import yaml from "js-yaml";
307
307
 
308
308
  // src/yaml/utils.ts
309
- import { assert as assert2 } from "misoai-shared/utils";
310
309
  import yaml2 from "js-yaml";
310
+ import { assert as assert2 } from "misoai-shared/utils";
311
311
  function interpolateEnvVars(content) {
312
312
  return content.replace(/\$\{([^}]+)\}/g, (_, envVar) => {
313
313
  const value = process.env[envVar.trim()];
@@ -468,6 +468,7 @@ function paramStr(task) {
468
468
  }
469
469
 
470
470
  // src/common/utils.ts
471
+ import dayjs from "dayjs";
471
472
  import { elementByPositionWithElementInfo } from "misoai-core/ai-model";
472
473
  import { uploadTestInfoToServer } from "misoai-core/utils";
473
474
  import { MIDSCENE_REPORT_TAG_NAME, getAIConfig } from "misoai-shared/env";
@@ -479,7 +480,6 @@ import {
479
480
  } from "misoai-shared/extractor";
480
481
  import { resizeImgBase64 } from "misoai-shared/img";
481
482
  import { assert as assert3, logMsg, uuid } from "misoai-shared/utils";
482
- import dayjs from "dayjs";
483
483
 
484
484
  // src/web-element.ts
485
485
  var WebElementInfo = class {
@@ -648,8 +648,12 @@ var WorkflowMemory = class {
648
648
  const workflow = this.workflows.get(workflowId) || this.createEmptyWorkflowData(workflowId);
649
649
  workflow.memory = [...memory];
650
650
  workflow.metadata.totalSteps = workflow.steps.length;
651
- workflow.metadata.completedSteps = workflow.steps.filter((s) => s.status === "completed").length;
652
- workflow.metadata.failedSteps = workflow.steps.filter((s) => s.status === "failed").length;
651
+ workflow.metadata.completedSteps = workflow.steps.filter(
652
+ (s) => s.status === "completed"
653
+ ).length;
654
+ workflow.metadata.failedSteps = workflow.steps.filter(
655
+ (s) => s.status === "failed"
656
+ ).length;
653
657
  this.workflows.set(workflowId, workflow);
654
658
  this.enforceRetentionPolicy();
655
659
  }
@@ -660,7 +664,9 @@ var WorkflowMemory = class {
660
664
  const workflow = this.workflows.get(workflowId) || this.createEmptyWorkflowData(workflowId);
661
665
  workflow.context = { ...workflow.context, ...context };
662
666
  if (context.currentStep) {
663
- const existingStep = workflow.steps.find((s) => s.stepName === context.currentStep);
667
+ const existingStep = workflow.steps.find(
668
+ (s) => s.stepName === context.currentStep
669
+ );
664
670
  if (!existingStep) {
665
671
  workflow.steps.push({
666
672
  stepId: `step_${workflow.steps.length + 1}`,
@@ -705,7 +711,9 @@ var WorkflowMemory = class {
705
711
  enforceRetentionPolicy() {
706
712
  const maxWorkflows = 10;
707
713
  if (this.workflows.size > maxWorkflows) {
708
- const sortedWorkflows = Array.from(this.workflows.entries()).sort(([, a], [, b]) => (b.metadata.endTime || b.metadata.startTime) - (a.metadata.endTime || a.metadata.startTime));
714
+ const sortedWorkflows = Array.from(this.workflows.entries()).sort(
715
+ ([, a], [, b]) => (b.metadata.endTime || b.metadata.startTime) - (a.metadata.endTime || a.metadata.startTime)
716
+ );
709
717
  const toDelete = sortedWorkflows.slice(maxWorkflows);
710
718
  toDelete.forEach(([workflowId]) => this.workflows.delete(workflowId));
711
719
  }
@@ -1272,6 +1280,7 @@ var PageTaskExecutor = class {
1272
1280
  actions: [],
1273
1281
  more_actions_needed_by_instruction: false,
1274
1282
  log: "",
1283
+ summary: "Loaded YAML workflow configuration",
1275
1284
  yamlString
1276
1285
  },
1277
1286
  cache: {
@@ -1373,6 +1382,7 @@ var PageTaskExecutor = class {
1373
1382
  actions: finalActions,
1374
1383
  more_actions_needed_by_instruction,
1375
1384
  log: log2,
1385
+ summary: planResult.summary || "Generated action plan from user instruction",
1376
1386
  yamlFlow: planResult.yamlFlow
1377
1387
  },
1378
1388
  cache: {
@@ -1428,6 +1438,7 @@ var PageTaskExecutor = class {
1428
1438
  actionType: actions[0].type,
1429
1439
  more_actions_needed_by_instruction: true,
1430
1440
  log: "",
1441
+ summary: action_summary || "Generated VLM action plan",
1431
1442
  yamlFlow: planResult.yamlFlow
1432
1443
  },
1433
1444
  cache: {
@@ -1444,7 +1455,9 @@ var PageTaskExecutor = class {
1444
1455
  */
1445
1456
  getPersistentExecutor() {
1446
1457
  if (!this.persistentExecutor || this.persistentExecutor.status === "error") {
1447
- const previousMemory = this.workflowMemory.getWorkflowMemory(this.sessionContext.workflowId);
1458
+ const previousMemory = this.workflowMemory.getWorkflowMemory(
1459
+ this.sessionContext.workflowId
1460
+ );
1448
1461
  this.persistentExecutor = new Executor("Persistent Task Executor", {
1449
1462
  onTaskStart: this.onTaskStartCallback,
1450
1463
  initialMemory: previousMemory
@@ -1473,7 +1486,9 @@ var PageTaskExecutor = class {
1473
1486
  if (this.persistentExecutor) {
1474
1487
  this.persistentExecutor.clearMemory();
1475
1488
  }
1476
- this.workflowMemory.clearWorkflow(this.sessionContext.workflowId || "default");
1489
+ this.workflowMemory.clearWorkflow(
1490
+ this.sessionContext.workflowId || "default"
1491
+ );
1477
1492
  }
1478
1493
  /**
1479
1494
  * Mevcut hafızayı döndürür
@@ -1485,7 +1500,9 @@ var PageTaskExecutor = class {
1485
1500
  * İş akışı hafızasını döndürür
1486
1501
  */
1487
1502
  getWorkflowMemory() {
1488
- return this.workflowMemory.getWorkflowData(this.sessionContext.workflowId || "default");
1503
+ return this.workflowMemory.getWorkflowData(
1504
+ this.sessionContext.workflowId || "default"
1505
+ );
1489
1506
  }
1490
1507
  /**
1491
1508
  * Hafıza istatistiklerini döndürür
@@ -1493,7 +1510,13 @@ var PageTaskExecutor = class {
1493
1510
  getMemoryStats() {
1494
1511
  return this.persistentExecutor?.getMemoryStats() || {
1495
1512
  totalItems: 0,
1496
- analytics: { totalTasks: 0, memoryHits: 0, memoryMisses: 0, averageMemorySize: 0, memoryEffectiveness: 0 },
1513
+ analytics: {
1514
+ totalTasks: 0,
1515
+ memoryHits: 0,
1516
+ memoryMisses: 0,
1517
+ averageMemorySize: 0,
1518
+ memoryEffectiveness: 0
1519
+ },
1497
1520
  config: this.memoryConfig
1498
1521
  };
1499
1522
  }
@@ -1529,11 +1552,14 @@ var PageTaskExecutor = class {
1529
1552
  let taskExecutor;
1530
1553
  if (useMemory) {
1531
1554
  taskExecutor = this.getPersistentExecutor();
1532
- this.workflowMemory.updateWorkflowContext({
1533
- currentStep: title,
1534
- pageInfo: this.sessionContext.pageInfo,
1535
- timestamp: Date.now()
1536
- }, this.sessionContext.workflowId || "default");
1555
+ this.workflowMemory.updateWorkflowContext(
1556
+ {
1557
+ currentStep: title,
1558
+ pageInfo: this.sessionContext.pageInfo,
1559
+ timestamp: Date.now()
1560
+ },
1561
+ this.sessionContext.workflowId || "default"
1562
+ );
1537
1563
  } else {
1538
1564
  taskExecutor = new Executor(title, {
1539
1565
  onTaskStart: this.onTaskStartCallback
@@ -1899,14 +1925,19 @@ var PageTaskExecutor = class {
1899
1925
  */
1900
1926
  addToMemory(memoryItem) {
1901
1927
  if (!this.persistentExecutor || this.persistentExecutor.status === "error") {
1902
- const previousMemory = this.workflowMemory.getWorkflowMemory(this.sessionContext.workflowId);
1928
+ const previousMemory = this.workflowMemory.getWorkflowMemory(
1929
+ this.sessionContext.workflowId
1930
+ );
1903
1931
  this.persistentExecutor = new Executor("Persistent Task Executor", {
1904
1932
  onTaskStart: this.onTaskStartCallback,
1905
1933
  initialMemory: previousMemory
1906
1934
  });
1907
1935
  }
1908
1936
  this.persistentExecutor.memoryStore?.add(memoryItem);
1909
- this.persistentExecutor.memoryAnalytics?.recordMemoryOperation("add", memoryItem);
1937
+ this.persistentExecutor.memoryAnalytics?.recordMemoryOperation(
1938
+ "add",
1939
+ memoryItem
1940
+ );
1910
1941
  }
1911
1942
  };
1912
1943
 
@@ -1995,14 +2026,14 @@ function buildPlans(type, locateParam, param) {
1995
2026
  import assert6 from "assert";
1996
2027
  import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync, writeFileSync as writeFileSync2 } from "fs";
1997
2028
  import { dirname as dirname2, join as join2 } from "path";
2029
+ import yaml3 from "js-yaml";
1998
2030
  import { getMidsceneRunSubDir as getMidsceneRunSubDir2 } from "misoai-shared/common";
1999
2031
  import { getDebug as getDebug3 } from "misoai-shared/logger";
2000
2032
  import { ifInBrowser as ifInBrowser2 } from "misoai-shared/utils";
2001
- import yaml3 from "js-yaml";
2002
2033
  import semver from "semver";
2003
2034
 
2004
2035
  // package.json
2005
- var version = "1.6.0";
2036
+ var version = "1.6.2";
2006
2037
 
2007
2038
  // src/common/task-cache.ts
2008
2039
  var debug3 = getDebug3("cache");
@@ -2297,22 +2328,28 @@ var PageAgent = class {
2297
2328
  const allThoughts = executor.tasks.filter((task) => task.thought).map((task) => task.thought);
2298
2329
  const allLocates = executor.tasks.filter((task) => task.locate).map((task) => task.locate);
2299
2330
  const allPlans = executor.tasks.filter((task) => task.param?.plans).map((task) => task.param?.plans);
2300
- const planningTasks = executor.tasks.filter((task) => task.type === "Planning");
2301
- const insightTasks = executor.tasks.filter((task) => task.type === "Insight");
2331
+ const planningTasks = executor.tasks.filter(
2332
+ (task) => task.type === "Planning"
2333
+ );
2334
+ const insightTasks = executor.tasks.filter(
2335
+ (task) => task.type === "Insight"
2336
+ );
2302
2337
  const actionTasks = executor.tasks.filter((task) => task.type === "Action");
2303
2338
  const planning = planningTasks.length > 0 ? {
2304
2339
  type: "Planning",
2305
- description: `Planning for task execution`,
2340
+ description: "Planning for task execution",
2306
2341
  steps: planningTasks.map((task) => task.thought || "Planning step")
2307
2342
  } : void 0;
2308
2343
  const insight = insightTasks.length > 0 ? {
2309
2344
  type: "Insight",
2310
- description: `Insight for task execution`,
2311
- elements: insightTasks.map((task) => task.thought || "Insight element")
2345
+ description: "Insight for task execution",
2346
+ elements: insightTasks.map(
2347
+ (task) => task.thought || "Insight element"
2348
+ )
2312
2349
  } : void 0;
2313
2350
  const action = actionTasks.length > 0 ? {
2314
2351
  type: "Action",
2315
- description: `Action for task execution`,
2352
+ description: "Action for task execution",
2316
2353
  result: lastTask?.output
2317
2354
  } : void 0;
2318
2355
  const actionDetails = executor.tasks.map((task) => ({
@@ -2646,7 +2683,10 @@ ${memoryContext}` : void 0;
2646
2683
  }
2647
2684
  const memoryContext = this.getMemoryAsContext();
2648
2685
  const assertionWithContext = currentUrl ? `For the page at URL "${currentUrl}", ${assertion}` : assertion;
2649
- const { output, executor } = await this.taskExecutor.assert(assertionWithContext, memoryContext);
2686
+ const { output, executor } = await this.taskExecutor.assert(
2687
+ assertionWithContext,
2688
+ memoryContext
2689
+ );
2650
2690
  const metadata = this.afterTaskRunning(executor, true);
2651
2691
  if (output && opt?.keepRawResponse) {
2652
2692
  return {
@@ -2685,7 +2725,10 @@ A complex CAPTCHA typically has one or more of these characteristics:
2685
2725
  Return only "complex" or "simple" based on your analysis.
2686
2726
  `;
2687
2727
  const complexityMsgs = [
2688
- { role: "system", content: "You are an AI assistant that analyzes screenshots to determine CAPTCHA complexity." },
2728
+ {
2729
+ role: "system",
2730
+ content: "You are an AI assistant that analyzes screenshots to determine CAPTCHA complexity."
2731
+ },
2689
2732
  {
2690
2733
  role: "user",
2691
2734
  content: [
@@ -2709,7 +2752,12 @@ Return only "complex" or "simple" based on your analysis.
2709
2752
  );
2710
2753
  const responseText = typeof complexityResult.content === "string" ? complexityResult.content.toLowerCase() : JSON.stringify(complexityResult.content).toLowerCase();
2711
2754
  shouldUseDeepThink = responseText.includes("complex");
2712
- debug4("CAPTCHA complexity analysis:", responseText, "Using deep think:", shouldUseDeepThink);
2755
+ debug4(
2756
+ "CAPTCHA complexity analysis:",
2757
+ responseText,
2758
+ "Using deep think:",
2759
+ shouldUseDeepThink
2760
+ );
2713
2761
  } catch (error) {
2714
2762
  debug4("Failed to analyze CAPTCHA complexity:", error);
2715
2763
  }
@@ -2726,7 +2774,9 @@ Return only "complex" or "simple" based on your analysis.
2726
2774
  await this.aiTap(action.target, { deepThink: shouldUseDeepThink });
2727
2775
  } else if (action.type === "input" && action.value) {
2728
2776
  if (action.target) {
2729
- await this.aiInput(action.value, action.target, { deepThink: shouldUseDeepThink });
2777
+ await this.aiInput(action.value, action.target, {
2778
+ deepThink: shouldUseDeepThink
2779
+ });
2730
2780
  }
2731
2781
  } else if (action.type === "verify" && action.target) {
2732
2782
  await this.aiTap(action.target, { deepThink: shouldUseDeepThink });
@@ -2738,7 +2788,9 @@ Return only "complex" or "simple" based on your analysis.
2738
2788
  if (action.coordinates) {
2739
2789
  const x = action.coordinates[0];
2740
2790
  const y = action.coordinates[1];
2741
- await this.aiTap(`element at coordinates (${x}, ${y})`, { deepThink: shouldUseDeepThink });
2791
+ await this.aiTap(`element at coordinates (${x}, ${y})`, {
2792
+ deepThink: shouldUseDeepThink
2793
+ });
2742
2794
  } else if (action.target) {
2743
2795
  await this.aiTap(action.target, { deepThink: shouldUseDeepThink });
2744
2796
  }
@@ -2890,25 +2942,27 @@ ${errors}`);
2890
2942
  const executionDump = {
2891
2943
  name: screenshotTitle,
2892
2944
  description: content,
2893
- tasks: [{
2894
- type: "Screenshot",
2895
- subType: "log",
2896
- status: "finished",
2897
- executor: null,
2898
- param: {
2899
- title: screenshotTitle,
2900
- content
2901
- },
2902
- output: {
2903
- screenshot
2904
- },
2905
- thought: `Logged screenshot: ${screenshotTitle}`,
2906
- timing: {
2907
- start: Date.now(),
2908
- end: Date.now(),
2909
- cost: 0
2945
+ tasks: [
2946
+ {
2947
+ type: "Screenshot",
2948
+ subType: "log",
2949
+ status: "finished",
2950
+ executor: null,
2951
+ param: {
2952
+ title: screenshotTitle,
2953
+ content
2954
+ },
2955
+ output: {
2956
+ screenshot
2957
+ },
2958
+ thought: `Logged screenshot: ${screenshotTitle}`,
2959
+ timing: {
2960
+ start: Date.now(),
2961
+ end: Date.now(),
2962
+ cost: 0
2963
+ }
2910
2964
  }
2911
- }],
2965
+ ],
2912
2966
  sdkVersion: "1.0.0",
2913
2967
  logTime: Date.now(),
2914
2968
  model_name: "screenshot"
@@ -2960,7 +3014,9 @@ ${errors}`);
2960
3014
  totalTasks: stats.analytics.totalTasks,
2961
3015
  memoryHits: stats.analytics.memoryHits,
2962
3016
  memoryMisses: stats.analytics.memoryMisses,
2963
- memoryEffectiveness: Math.round(stats.analytics.memoryEffectiveness * 100),
3017
+ memoryEffectiveness: Math.round(
3018
+ stats.analytics.memoryEffectiveness * 100
3019
+ ),
2964
3020
  averageMemorySize: Math.round(stats.analytics.averageMemorySize * 100) / 100
2965
3021
  },
2966
3022
  config: stats.config,
@@ -3024,7 +3080,9 @@ ${errors}`);
3024
3080
  calculateSuccessRate(memory) {
3025
3081
  if (memory.length === 0)
3026
3082
  return 0;
3027
- const successCount = memory.filter((item) => item.metadata?.success !== false).length;
3083
+ const successCount = memory.filter(
3084
+ (item) => item.metadata?.success !== false
3085
+ ).length;
3028
3086
  return Math.round(successCount / memory.length * 100);
3029
3087
  }
3030
3088
  calculateAverageExecutionTime(memory) {
@@ -3063,13 +3121,236 @@ import {
3063
3121
  } from "misoai-shared/fs";
3064
3122
  import { getDebug as getDebug5 } from "misoai-shared/logger";
3065
3123
  import { assert as assert8 } from "misoai-shared/utils";
3124
+
3125
+ // src/common/mouse-utils.ts
3126
+ function generateHumanMousePath(from, to, options = {}) {
3127
+ const {
3128
+ steps = 20,
3129
+ easing = "easeInOut"
3130
+ } = options;
3131
+ if (steps <= 1) {
3132
+ return [to];
3133
+ }
3134
+ const path = [];
3135
+ const controlPoint1 = {
3136
+ x: from.x + (to.x - from.x) * 0.25 + (Math.random() - 0.5) * 50,
3137
+ y: from.y + (to.y - from.y) * 0.25 + (Math.random() - 0.5) * 50
3138
+ };
3139
+ const controlPoint2 = {
3140
+ x: from.x + (to.x - from.x) * 0.75 + (Math.random() - 0.5) * 50,
3141
+ y: from.y + (to.y - from.y) * 0.75 + (Math.random() - 0.5) * 50
3142
+ };
3143
+ for (let i = 0; i <= steps; i++) {
3144
+ const t = i / steps;
3145
+ const easedT = applyEasing(t, easing);
3146
+ const point = calculateBezierPoint(from, controlPoint1, controlPoint2, to, easedT);
3147
+ path.push(point);
3148
+ }
3149
+ return path;
3150
+ }
3151
+ function calculateBezierPoint(p0, p1, p2, p3, t) {
3152
+ const oneMinusT = 1 - t;
3153
+ const oneMinusTSquared = oneMinusT * oneMinusT;
3154
+ const oneMinusTCubed = oneMinusTSquared * oneMinusT;
3155
+ const tSquared = t * t;
3156
+ const tCubed = tSquared * t;
3157
+ return {
3158
+ x: oneMinusTCubed * p0.x + 3 * oneMinusTSquared * t * p1.x + 3 * oneMinusT * tSquared * p2.x + tCubed * p3.x,
3159
+ y: oneMinusTCubed * p0.y + 3 * oneMinusTSquared * t * p1.y + 3 * oneMinusT * tSquared * p2.y + tCubed * p3.y
3160
+ };
3161
+ }
3162
+ function applyEasing(t, easing) {
3163
+ switch (easing) {
3164
+ case "linear":
3165
+ return t;
3166
+ case "easeIn":
3167
+ return t * t;
3168
+ case "easeOut":
3169
+ return 1 - (1 - t) * (1 - t);
3170
+ case "easeInOut":
3171
+ return t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2;
3172
+ default:
3173
+ return t;
3174
+ }
3175
+ }
3176
+ function calculateStepDelay(totalDuration, currentStep, totalSteps) {
3177
+ const baseDelay = totalDuration / totalSteps;
3178
+ const variation = 0.3;
3179
+ const randomFactor = 1 + (Math.random() - 0.5) * variation;
3180
+ return Math.max(1, baseDelay * randomFactor);
3181
+ }
3182
+
3183
+ // src/common/visual-feedback.ts
3184
+ function getMousePointerScript(x, y, options = {}) {
3185
+ const {
3186
+ pointerSize = 20,
3187
+ pointerColor = "#ff4444",
3188
+ trailLength = 5,
3189
+ showTrail = true,
3190
+ animationDuration = 200
3191
+ } = options;
3192
+ return `
3193
+ (() => {
3194
+ // Create or update mouse pointer
3195
+ if (!window.misoaiMousePointer) {
3196
+ const pointer = document.createElement('div');
3197
+ pointer.id = 'misoai-mouse-pointer';
3198
+ pointer.style.cssText = \`
3199
+ position: fixed;
3200
+ width: ${pointerSize}px;
3201
+ height: ${pointerSize}px;
3202
+ background: ${pointerColor};
3203
+ border: 2px solid white;
3204
+ border-radius: 50%;
3205
+ pointer-events: none;
3206
+ z-index: 999999;
3207
+ box-shadow: 0 0 10px rgba(0,0,0,0.3);
3208
+ transition: all ${animationDuration}ms ease-out;
3209
+ transform: translate(-50%, -50%);
3210
+ \`;
3211
+ document.body.appendChild(pointer);
3212
+ window.misoaiMousePointer = pointer;
3213
+
3214
+ // Initialize trail array
3215
+ window.misoaiMouseTrail = [];
3216
+ }
3217
+
3218
+ const pointer = window.misoaiMousePointer;
3219
+ pointer.style.left = ${x}px;
3220
+ pointer.style.top = ${y}px;
3221
+
3222
+ ${showTrail ? getTrailScript(x, y, trailLength, pointerColor) : ""}
3223
+
3224
+ // Auto-hide after 3 seconds of inactivity
3225
+ clearTimeout(window.misoaiMouseTimeout);
3226
+ pointer.style.opacity = '1';
3227
+ window.misoaiMouseTimeout = setTimeout(() => {
3228
+ if (pointer) pointer.style.opacity = '0.3';
3229
+ }, 3000);
3230
+ })();
3231
+ `;
3232
+ }
3233
+ function getTrailScript(x, y, trailLength, color) {
3234
+ return `
3235
+ // Add current position to trail
3236
+ window.misoaiMouseTrail.push({ x: ${x}, y: ${y}, timestamp: Date.now() });
3237
+
3238
+ // Keep only recent trail points
3239
+ if (window.misoaiMouseTrail.length > ${trailLength}) {
3240
+ window.misoaiMouseTrail.shift();
3241
+ }
3242
+
3243
+ // Remove old trail elements
3244
+ document.querySelectorAll('.misoai-mouse-trail').forEach(el => el.remove());
3245
+
3246
+ // Create new trail elements
3247
+ window.misoaiMouseTrail.forEach((point, index) => {
3248
+ if (index === window.misoaiMouseTrail.length - 1) return; // Skip current position
3249
+
3250
+ const trailElement = document.createElement('div');
3251
+ trailElement.className = 'misoai-mouse-trail';
3252
+ const opacity = (index + 1) / window.misoaiMouseTrail.length * 0.6;
3253
+ const size = 8 + (index + 1) / window.misoaiMouseTrail.length * 8;
3254
+
3255
+ trailElement.style.cssText = \`
3256
+ position: fixed;
3257
+ width: \${size}px;
3258
+ height: \${size}px;
3259
+ background: ${color};
3260
+ border-radius: 50%;
3261
+ pointer-events: none;
3262
+ z-index: 999998;
3263
+ opacity: \${opacity};
3264
+ transform: translate(-50%, -50%);
3265
+ left: \${point.x}px;
3266
+ top: \${point.y}px;
3267
+ \`;
3268
+
3269
+ document.body.appendChild(trailElement);
3270
+
3271
+ // Auto-remove trail element after animation
3272
+ setTimeout(() => {
3273
+ if (trailElement.parentNode) {
3274
+ trailElement.parentNode.removeChild(trailElement);
3275
+ }
3276
+ }, 1000);
3277
+ });
3278
+ `;
3279
+ }
3280
+ function getClickAnimationScript(x, y) {
3281
+ return `
3282
+ (() => {
3283
+ const clickRipple = document.createElement('div');
3284
+ clickRipple.style.cssText = \`
3285
+ position: fixed;
3286
+ left: ${x}px;
3287
+ top: ${y}px;
3288
+ width: 0;
3289
+ height: 0;
3290
+ border: 2px solid #ff4444;
3291
+ border-radius: 50%;
3292
+ pointer-events: none;
3293
+ z-index: 999999;
3294
+ transform: translate(-50%, -50%);
3295
+ animation: misoai-click-ripple 0.6s ease-out forwards;
3296
+ \`;
3297
+
3298
+ // Add CSS animation if not exists
3299
+ if (!document.getElementById('misoai-click-styles')) {
3300
+ const style = document.createElement('style');
3301
+ style.id = 'misoai-click-styles';
3302
+ style.textContent = \`
3303
+ @keyframes misoai-click-ripple {
3304
+ 0% {
3305
+ width: 0;
3306
+ height: 0;
3307
+ opacity: 1;
3308
+ }
3309
+ 100% {
3310
+ width: 40px;
3311
+ height: 40px;
3312
+ opacity: 0;
3313
+ }
3314
+ }
3315
+ \`;
3316
+ document.head.appendChild(style);
3317
+ }
3318
+
3319
+ document.body.appendChild(clickRipple);
3320
+
3321
+ // Remove after animation
3322
+ setTimeout(() => {
3323
+ if (clickRipple.parentNode) {
3324
+ clickRipple.parentNode.removeChild(clickRipple);
3325
+ }
3326
+ }, 600);
3327
+ })();
3328
+ `;
3329
+ }
3330
+
3331
+ // src/puppeteer/base-page.ts
3066
3332
  var debugPage = getDebug5("web:page");
3067
3333
  var Page = class {
3068
3334
  constructor(underlyingPage, pageType, opts) {
3335
+ this.currentMousePosition = { x: 0, y: 0 };
3336
+ this.mouseMovementOptions = {
3337
+ steps: 15,
3338
+ duration: 300,
3339
+ easing: "easeInOut",
3340
+ showVisualFeedback: true
3341
+ };
3342
+ this.visualFeedbackOptions = {
3343
+ pointerSize: 16,
3344
+ pointerColor: "#ff4444",
3345
+ trailLength: 4,
3346
+ showTrail: true,
3347
+ animationDuration: 150
3348
+ };
3069
3349
  this.everMoved = false;
3070
3350
  this.underlyingPage = underlyingPage;
3071
3351
  this.pageType = pageType;
3072
3352
  this.waitForNavigationTimeout = opts?.waitForNavigationTimeout ?? DEFAULT_WAIT_FOR_NAVIGATION_TIMEOUT2;
3353
+ this.initializeMousePosition();
3073
3354
  }
3074
3355
  async evaluate(pageFunction, arg) {
3075
3356
  let result;
@@ -3088,9 +3369,76 @@ var Page = class {
3088
3369
  debugPage("evaluate function end");
3089
3370
  return result;
3090
3371
  }
3372
+ /**
3373
+ * Initialize mouse position to center of viewport
3374
+ */
3375
+ async initializeMousePosition() {
3376
+ try {
3377
+ const size = await this.size();
3378
+ this.currentMousePosition = {
3379
+ x: Math.floor(size.width / 2),
3380
+ y: Math.floor(size.height / 2)
3381
+ };
3382
+ } catch (error) {
3383
+ this.currentMousePosition = { x: 400, y: 300 };
3384
+ }
3385
+ }
3091
3386
  async evaluateJavaScript(script) {
3092
3387
  return this.evaluate(script);
3093
3388
  }
3389
+ /**
3390
+ * Show visual feedback for mouse pointer
3391
+ */
3392
+ async showMousePointer(x, y) {
3393
+ if (!this.mouseMovementOptions.showVisualFeedback)
3394
+ return;
3395
+ const script = getMousePointerScript(x, y, this.visualFeedbackOptions);
3396
+ try {
3397
+ await this.evaluate(script);
3398
+ } catch (error) {
3399
+ debugPage("Visual feedback error:", error);
3400
+ }
3401
+ }
3402
+ /**
3403
+ * Show click animation
3404
+ */
3405
+ async showClickAnimation(x, y) {
3406
+ if (!this.mouseMovementOptions.showVisualFeedback)
3407
+ return;
3408
+ const script = getClickAnimationScript(x, y);
3409
+ try {
3410
+ await this.evaluate(script);
3411
+ } catch (error) {
3412
+ debugPage("Click animation error:", error);
3413
+ }
3414
+ }
3415
+ /**
3416
+ * Move mouse with human-like movement and visual feedback
3417
+ */
3418
+ async moveMouseHumanLike(toX, toY, options) {
3419
+ const moveOptions = { ...this.mouseMovementOptions, ...options };
3420
+ const path = generateHumanMousePath(
3421
+ this.currentMousePosition,
3422
+ { x: toX, y: toY },
3423
+ moveOptions
3424
+ );
3425
+ for (let i = 0; i < path.length; i++) {
3426
+ const point = path[i];
3427
+ if (moveOptions.showVisualFeedback) {
3428
+ await this.showMousePointer(point.x, point.y);
3429
+ }
3430
+ await this.underlyingPage.mouse.move(point.x, point.y);
3431
+ this.currentMousePosition = point;
3432
+ if (i < path.length - 1) {
3433
+ const delay = calculateStepDelay(
3434
+ moveOptions.duration || 300,
3435
+ i,
3436
+ path.length
3437
+ );
3438
+ await sleep2(delay);
3439
+ }
3440
+ }
3441
+ }
3094
3442
  async waitForNavigation() {
3095
3443
  if (this.pageType === "puppeteer" || this.pageType === "playwright") {
3096
3444
  debugPage("waitForNavigation begin");
@@ -3180,7 +3528,8 @@ var Page = class {
3180
3528
  return {
3181
3529
  click: async (x, y, options) => {
3182
3530
  await this.mouse.move(x, y);
3183
- this.underlyingPage.mouse.click(x, y, {
3531
+ await this.showClickAnimation(x, y);
3532
+ await this.underlyingPage.mouse.click(x, y, {
3184
3533
  button: options?.button || "left",
3185
3534
  count: options?.count || 1
3186
3535
  });
@@ -3200,27 +3549,23 @@ var Page = class {
3200
3549
  },
3201
3550
  move: async (x, y) => {
3202
3551
  this.everMoved = true;
3203
- return this.underlyingPage.mouse.move(x, y);
3552
+ await this.moveMouseHumanLike(x, y);
3553
+ return Promise.resolve();
3204
3554
  },
3205
3555
  drag: async (from, to) => {
3206
3556
  if (this.pageType === "puppeteer") {
3207
- await this.underlyingPage.mouse.drag(
3208
- {
3209
- x: from.x,
3210
- y: from.y
3211
- },
3212
- {
3213
- x: to.x,
3214
- y: to.y
3215
- }
3216
- );
3557
+ await this.mouse.move(from.x, from.y);
3558
+ await this.underlyingPage.mouse.down();
3559
+ await this.moveMouseHumanLike(to.x, to.y, {
3560
+ duration: 500,
3561
+ // Slower for drag operations
3562
+ steps: 25
3563
+ });
3564
+ await this.underlyingPage.mouse.up();
3217
3565
  } else if (this.pageType === "playwright") {
3218
- await this.underlyingPage.mouse.move(
3219
- from.x,
3220
- from.y
3221
- );
3566
+ await this.mouse.move(from.x, from.y);
3222
3567
  await this.underlyingPage.mouse.down();
3223
- await this.underlyingPage.mouse.move(to.x, to.y);
3568
+ await this.mouse.move(to.x, to.y);
3224
3569
  await this.underlyingPage.mouse.up();
3225
3570
  }
3226
3571
  }
@@ -3283,6 +3628,18 @@ var Page = class {
3283
3628
  await this.mouse.move(targetX, targetY);
3284
3629
  }
3285
3630
  }
3631
+ /**
3632
+ * Configure mouse movement behavior
3633
+ */
3634
+ configureMouseMovement(options) {
3635
+ this.mouseMovementOptions = { ...this.mouseMovementOptions, ...options };
3636
+ }
3637
+ /**
3638
+ * Configure visual feedback
3639
+ */
3640
+ configureVisualFeedback(options) {
3641
+ this.visualFeedbackOptions = { ...this.visualFeedbackOptions, ...options };
3642
+ }
3286
3643
  async scrollUntilTop(startingPoint) {
3287
3644
  await this.moveToPointBeforeScroll(startingPoint);
3288
3645
  return this.mouse.wheel(0, -9999999);
@@ -3345,8 +3702,8 @@ var WebPage = class extends Page {
3345
3702
 
3346
3703
  // src/playwright/ai-fixture.ts
3347
3704
  import { randomUUID } from "crypto";
3348
- import { getDebug as getDebug6 } from "misoai-shared/logger";
3349
3705
  import { test } from "@playwright/test";
3706
+ import { getDebug as getDebug6 } from "misoai-shared/logger";
3350
3707
  var debugPage2 = getDebug6("web:playwright:ai-fixture");
3351
3708
  var groupAndCaseForTest = (testInfo) => {
3352
3709
  let taskFile;