@ddwang/magnitude-core 0.3.1-ddwang.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/actions/desktopActions.d.ts +58 -0
- package/dist/actions/desktopActions.js +154 -0
- package/dist/actions/index.d.ts +26 -0
- package/dist/actions/index.js +11 -0
- package/dist/actions/taskActions.d.ts +8 -0
- package/dist/actions/taskActions.js +27 -0
- package/dist/actions/types.d.ts +31 -0
- package/dist/actions/types.js +5 -0
- package/dist/actions/util.d.ts +20 -0
- package/dist/actions/util.js +297 -0
- package/dist/actions/webActions.d.ts +79 -0
- package/dist/actions/webActions.js +190 -0
- package/dist/agent/browserAgent.d.ts +29 -0
- package/dist/agent/browserAgent.js +122 -0
- package/dist/agent/errors.d.ts +8 -0
- package/dist/agent/errors.js +68 -0
- package/dist/agent/index.d.ts +53 -0
- package/dist/agent/index.js +377 -0
- package/dist/agent/narrator.d.ts +4 -0
- package/dist/agent/narrator.js +63 -0
- package/dist/agent/pause.test.d.ts +1 -0
- package/dist/agent/pause.test.js +194 -0
- package/dist/ai/baml_client/async_client.d.ts +73 -0
- package/dist/ai/baml_client/async_client.js +152 -0
- package/dist/ai/baml_client/async_request.d.ts +35 -0
- package/dist/ai/baml_client/async_request.js +98 -0
- package/dist/ai/baml_client/config.d.ts +11 -0
- package/dist/ai/baml_client/config.js +20 -0
- package/dist/ai/baml_client/globals.d.ts +16 -0
- package/dist/ai/baml_client/globals.js +37 -0
- package/dist/ai/baml_client/index.d.ts +16 -0
- package/dist/ai/baml_client/index.js +41 -0
- package/dist/ai/baml_client/inlinedbaml.d.ts +19 -0
- package/dist/ai/baml_client/inlinedbaml.js +31 -0
- package/dist/ai/baml_client/parser.d.ts +53 -0
- package/dist/ai/baml_client/parser.js +86 -0
- package/dist/ai/baml_client/partial_types.d.ts +61 -0
- package/dist/ai/baml_client/partial_types.js +10 -0
- package/dist/ai/baml_client/sync_client.d.ts +50 -0
- package/dist/ai/baml_client/sync_client.js +100 -0
- package/dist/ai/baml_client/sync_request.d.ts +35 -0
- package/dist/ai/baml_client/sync_request.js +98 -0
- package/dist/ai/baml_client/tracing.d.ts +16 -0
- package/dist/ai/baml_client/tracing.js +18 -0
- package/dist/ai/baml_client/type_builder.d.ts +38 -0
- package/dist/ai/baml_client/type_builder.js +96 -0
- package/dist/ai/baml_client/types.d.ts +69 -0
- package/dist/ai/baml_client/types.js +15 -0
- package/dist/ai/claudeCode.d.ts +1 -0
- package/dist/ai/claudeCode.js +186 -0
- package/dist/ai/modelHarness.d.ts +39 -0
- package/dist/ai/modelHarness.js +189 -0
- package/dist/ai/multiModelHarness.d.ts +27 -0
- package/dist/ai/multiModelHarness.js +52 -0
- package/dist/ai/types.d.ts +90 -0
- package/dist/ai/types.js +5 -0
- package/dist/ai/util.d.ts +13 -0
- package/dist/ai/util.js +165 -0
- package/dist/cli.d.ts +0 -0
- package/dist/cli.js +3 -0
- package/dist/common/actions.d.ts +0 -0
- package/dist/common/actions.js +14 -0
- package/dist/common/events.d.ts +15 -0
- package/dist/common/events.js +3 -0
- package/dist/common/failure.d.ts +68 -0
- package/dist/common/failure.js +1 -0
- package/dist/common/index.d.ts +3 -0
- package/dist/common/index.js +3 -0
- package/dist/common/retry.d.ts +16 -0
- package/dist/common/retry.js +30 -0
- package/dist/common/util.d.ts +23 -0
- package/dist/common/util.js +132 -0
- package/dist/connectors/browserConnector.d.ts +40 -0
- package/dist/connectors/browserConnector.js +127 -0
- package/dist/connectors/desktopConnector.d.ts +58 -0
- package/dist/connectors/desktopConnector.js +68 -0
- package/dist/connectors/index.d.ts +10 -0
- package/dist/connectors/index.js +2 -0
- package/dist/index.cjs +6143 -0
- package/dist/index.d.cts +825 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +26 -0
- package/dist/index.mjs +6097 -0
- package/dist/logger.d.ts +3 -0
- package/dist/logger.js +15 -0
- package/dist/memory/agentMemory.d.ts +37 -0
- package/dist/memory/agentMemory.js +121 -0
- package/dist/memory/image.d.ts +26 -0
- package/dist/memory/image.js +106 -0
- package/dist/memory/index.d.ts +3 -0
- package/dist/memory/index.js +3 -0
- package/dist/memory/masking.d.ts +7 -0
- package/dist/memory/masking.js +141 -0
- package/dist/memory/masking.test.d.ts +1 -0
- package/dist/memory/masking.test.js +117 -0
- package/dist/memory/observation.d.ts +38 -0
- package/dist/memory/observation.js +79 -0
- package/dist/memory/rendering/index.d.ts +10 -0
- package/dist/memory/rendering/index.js +13 -0
- package/dist/memory/rendering/renderJsonParts.d.ts +3 -0
- package/dist/memory/rendering/renderJsonParts.js +115 -0
- package/dist/memory/rendering/renderJsonParts.test.d.ts +1 -0
- package/dist/memory/rendering/renderJsonParts.test.js +217 -0
- package/dist/memory/rendering/renderXmlParts.d.ts +7 -0
- package/dist/memory/rendering/renderXmlParts.js +127 -0
- package/dist/memory/serde.d.ts +20 -0
- package/dist/memory/serde.js +81 -0
- package/dist/memory/util.d.ts +2 -0
- package/dist/memory/util.js +17 -0
- package/dist/telemetry/events.d.ts +9 -0
- package/dist/telemetry/events.js +80 -0
- package/dist/telemetry/index.d.ts +6 -0
- package/dist/telemetry/index.js +91 -0
- package/dist/types.d.ts +30 -0
- package/dist/types.js +1 -0
- package/dist/util.d.ts +1 -0
- package/dist/util.js +12 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +3 -0
- package/dist/web/browserProvider.d.ts +23 -0
- package/dist/web/browserProvider.js +153 -0
- package/dist/web/harness.d.ts +102 -0
- package/dist/web/harness.js +340 -0
- package/dist/web/stability.d.ts +57 -0
- package/dist/web/stability.js +316 -0
- package/dist/web/tabs.d.ts +58 -0
- package/dist/web/tabs.js +293 -0
- package/dist/web/transformer.d.ts +7 -0
- package/dist/web/transformer.js +41 -0
- package/dist/web/types.d.ts +32 -0
- package/dist/web/types.js +2 -0
- package/dist/web/util.d.ts +3 -0
- package/dist/web/util.js +81 -0
- package/dist/web/visualizer/cursor.d.ts +16 -0
- package/dist/web/visualizer/cursor.js +152 -0
- package/dist/web/visualizer/index.d.ts +22 -0
- package/dist/web/visualizer/index.js +47 -0
- package/dist/web/visualizer/mouseEffects.d.ts +18 -0
- package/dist/web/visualizer/mouseEffects.js +287 -0
- package/dist/web/visualizer/typeEffects.d.ts +10 -0
- package/dist/web/visualizer/typeEffects.js +190 -0
- package/package.json +71 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import { retryOnErrorIsSuccess } from "@/common";
|
|
2
|
+
export class MouseEffectVisual {
|
|
3
|
+
baseOpacity;
|
|
4
|
+
showHoverCircle;
|
|
5
|
+
showClickRipple;
|
|
6
|
+
showDragLine;
|
|
7
|
+
page;
|
|
8
|
+
constructor(options = {}) {
|
|
9
|
+
this.baseOpacity = options.baseOpacity ?? 0.5;
|
|
10
|
+
this.showHoverCircle = options.showHoverCircle ?? true;
|
|
11
|
+
this.showClickRipple = options.showClickRipple ?? true;
|
|
12
|
+
this.showDragLine = options.showDragLine ?? true;
|
|
13
|
+
}
|
|
14
|
+
async setActivePage(page) {
|
|
15
|
+
this.page = page;
|
|
16
|
+
page.on('load', async () => {
|
|
17
|
+
// Clear the initialized flag on navigation to ensure re-initialization
|
|
18
|
+
await page.evaluate(() => {
|
|
19
|
+
window.__mouseEffectsInitialized = false;
|
|
20
|
+
}).catch(() => { }); // Ignore errors
|
|
21
|
+
await retryOnErrorIsSuccess(this.setupOnPage.bind(this), { mode: 'retry_all', delayMs: 200, retryLimit: 10 });
|
|
22
|
+
});
|
|
23
|
+
await retryOnErrorIsSuccess(this.setupOnPage.bind(this), { mode: 'retry_all', delayMs: 200, retryLimit: 10 });
|
|
24
|
+
}
|
|
25
|
+
async setupOnPage() {
|
|
26
|
+
await this.page.evaluate((options) => {
|
|
27
|
+
if (window.__mouseEffectsInitialized) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
window.__mouseEffectsInitialized = true;
|
|
31
|
+
// Create custom cursor element only if enabled
|
|
32
|
+
let cursor = null;
|
|
33
|
+
if (options.showHoverCircle) {
|
|
34
|
+
cursor = document.createElement('div');
|
|
35
|
+
cursor.id = 'custom-cursor';
|
|
36
|
+
cursor.style.cssText = `
|
|
37
|
+
position: fixed;
|
|
38
|
+
width: 20px;
|
|
39
|
+
height: 20px;
|
|
40
|
+
border: 2px solid rgba(0, 150, 255, ${options.opacity});
|
|
41
|
+
border-radius: 50%;
|
|
42
|
+
background: rgba(0, 150, 255, ${options.opacity * 0.5});
|
|
43
|
+
pointer-events: none;
|
|
44
|
+
z-index: 1000000050;
|
|
45
|
+
transition: transform 0.1s ease-out;
|
|
46
|
+
`;
|
|
47
|
+
document.body.appendChild(cursor);
|
|
48
|
+
}
|
|
49
|
+
// Create drag line element only if enabled
|
|
50
|
+
let dragLine = null;
|
|
51
|
+
let line = null;
|
|
52
|
+
if (options.showDragLine) {
|
|
53
|
+
dragLine = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
54
|
+
dragLine.id = 'drag-line';
|
|
55
|
+
dragLine.style.cssText = `
|
|
56
|
+
position: fixed;
|
|
57
|
+
top: 0;
|
|
58
|
+
left: 0;
|
|
59
|
+
width: 100vw;
|
|
60
|
+
height: 100vh;
|
|
61
|
+
pointer-events: none;
|
|
62
|
+
z-index: 1000000030;
|
|
63
|
+
overflow: visible;
|
|
64
|
+
`;
|
|
65
|
+
line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
|
|
66
|
+
line.setAttribute('stroke', '#0096ff');
|
|
67
|
+
line.setAttribute('stroke-width', '2');
|
|
68
|
+
line.setAttribute('stroke-dasharray', '5,5');
|
|
69
|
+
line.setAttribute('opacity', '0.8');
|
|
70
|
+
line.style.display = 'none';
|
|
71
|
+
dragLine.appendChild(line);
|
|
72
|
+
document.body.appendChild(dragLine);
|
|
73
|
+
}
|
|
74
|
+
let isMouseDown = false;
|
|
75
|
+
let dragStartX = 0;
|
|
76
|
+
let dragStartY = 0;
|
|
77
|
+
const activeRipples = new Set();
|
|
78
|
+
// Track mouse movement
|
|
79
|
+
document.addEventListener('mousemove', (e) => {
|
|
80
|
+
// Update cursor position - always center on mouse
|
|
81
|
+
if (cursor) {
|
|
82
|
+
cursor.style.left = e.clientX - 10 + 'px';
|
|
83
|
+
cursor.style.top = e.clientY - 10 + 'px';
|
|
84
|
+
}
|
|
85
|
+
// Update drag line if dragging
|
|
86
|
+
if (isMouseDown && line) {
|
|
87
|
+
line.setAttribute('x1', dragStartX.toString());
|
|
88
|
+
line.setAttribute('y1', dragStartY.toString());
|
|
89
|
+
line.setAttribute('x2', e.clientX.toString());
|
|
90
|
+
line.setAttribute('y2', e.clientY.toString());
|
|
91
|
+
line.style.display = 'block';
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
// Mouse down - start drag and shrink cursor
|
|
95
|
+
document.addEventListener('mousedown', (e) => {
|
|
96
|
+
isMouseDown = true;
|
|
97
|
+
dragStartX = e.clientX;
|
|
98
|
+
dragStartY = e.clientY;
|
|
99
|
+
// Use transform scale instead of changing width/height
|
|
100
|
+
if (cursor) {
|
|
101
|
+
cursor.style.transform = 'scale(0.5)';
|
|
102
|
+
cursor.style.background = `rgba(0, 150, 255, ${options.opacity * 1.5})`;
|
|
103
|
+
cursor.style.border = `2px solid rgba(0, 150, 255, ${options.opacity * 2})`;
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
// Mouse up - end drag and restore cursor
|
|
107
|
+
document.addEventListener('mouseup', (e) => {
|
|
108
|
+
isMouseDown = false;
|
|
109
|
+
// Hide drag line
|
|
110
|
+
if (line) {
|
|
111
|
+
line.style.display = 'none';
|
|
112
|
+
}
|
|
113
|
+
// Restore cursor
|
|
114
|
+
if (cursor) {
|
|
115
|
+
cursor.style.transform = 'scale(1)';
|
|
116
|
+
cursor.style.background = `rgba(0, 150, 255, ${options.opacity * 0.5})`;
|
|
117
|
+
cursor.style.border = `2px solid rgba(0, 150, 255, ${options.opacity})`;
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
// Visualize clicks
|
|
121
|
+
document.addEventListener('click', (e) => {
|
|
122
|
+
if (options.showClickRipple) {
|
|
123
|
+
// Add ripple animation styles once
|
|
124
|
+
if (!document.querySelector('style[data-cursor-effects]')) {
|
|
125
|
+
const style = document.createElement('style');
|
|
126
|
+
style.setAttribute('data-cursor-effects', 'true');
|
|
127
|
+
style.textContent = `
|
|
128
|
+
@keyframes ripple {
|
|
129
|
+
0% {
|
|
130
|
+
transform: scale(0);
|
|
131
|
+
opacity: 1;
|
|
132
|
+
}
|
|
133
|
+
100% {
|
|
134
|
+
transform: scale(2);
|
|
135
|
+
opacity: 0;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
.click-ripple {
|
|
139
|
+
position: fixed;
|
|
140
|
+
width: 60px;
|
|
141
|
+
height: 60px;
|
|
142
|
+
border: 3px solid #0096ff;
|
|
143
|
+
border-radius: 50%;
|
|
144
|
+
pointer-events: none;
|
|
145
|
+
z-index: 1000000040;
|
|
146
|
+
transform: scale(0);
|
|
147
|
+
opacity: 0;
|
|
148
|
+
}
|
|
149
|
+
.click-ripple.active {
|
|
150
|
+
animation: ripple 0.6s ease-out forwards;
|
|
151
|
+
}
|
|
152
|
+
`;
|
|
153
|
+
document.head.appendChild(style);
|
|
154
|
+
}
|
|
155
|
+
// Create ripple effect
|
|
156
|
+
const ripple = document.createElement('div');
|
|
157
|
+
ripple.className = 'click-ripple';
|
|
158
|
+
ripple.style.left = `${e.clientX - 30}px`;
|
|
159
|
+
ripple.style.top = `${e.clientY - 30}px`;
|
|
160
|
+
document.body.appendChild(ripple);
|
|
161
|
+
activeRipples.add(ripple);
|
|
162
|
+
// Trigger animation on next frame to ensure proper initialization
|
|
163
|
+
requestAnimationFrame(() => {
|
|
164
|
+
ripple.classList.add('active');
|
|
165
|
+
});
|
|
166
|
+
// Remove ripple after animation
|
|
167
|
+
setTimeout(() => {
|
|
168
|
+
ripple.remove();
|
|
169
|
+
activeRipples.delete(ripple);
|
|
170
|
+
}, 600);
|
|
171
|
+
}
|
|
172
|
+
// Flash the cursor only if not already scaled down
|
|
173
|
+
if (cursor) {
|
|
174
|
+
const currentTransform = cursor.style.transform;
|
|
175
|
+
if (currentTransform !== 'scale(0.5)') {
|
|
176
|
+
cursor.style.background = `rgba(0, 150, 255, ${options.opacity * 1.5})`;
|
|
177
|
+
cursor.style.border = `2px solid rgba(0, 150, 255, 1)`;
|
|
178
|
+
cursor.style.transform = 'scale(1.5)';
|
|
179
|
+
setTimeout(() => {
|
|
180
|
+
cursor.style.background = `rgba(0, 150, 255, ${options.opacity * 0.5})`;
|
|
181
|
+
cursor.style.border = `2px solid rgba(0, 150, 255, ${options.opacity})`;
|
|
182
|
+
cursor.style.transform = 'scale(1)';
|
|
183
|
+
}, 200);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
// Also track right clicks
|
|
188
|
+
document.addEventListener('contextmenu', (e) => {
|
|
189
|
+
// Don't prevent default - let context menu show
|
|
190
|
+
if (options.showClickRipple) {
|
|
191
|
+
// Create ripple for right click (reuse same styles)
|
|
192
|
+
const ripple = document.createElement('div');
|
|
193
|
+
ripple.className = 'click-ripple';
|
|
194
|
+
ripple.style.left = `${e.clientX - 30}px`;
|
|
195
|
+
ripple.style.top = `${e.clientY - 30}px`;
|
|
196
|
+
document.body.appendChild(ripple);
|
|
197
|
+
activeRipples.add(ripple);
|
|
198
|
+
// Trigger animation on next frame
|
|
199
|
+
requestAnimationFrame(() => {
|
|
200
|
+
ripple.classList.add('active');
|
|
201
|
+
});
|
|
202
|
+
setTimeout(() => {
|
|
203
|
+
ripple.remove();
|
|
204
|
+
activeRipples.delete(ripple);
|
|
205
|
+
}, 600);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
// Scroll visualization
|
|
209
|
+
let scrollTimeout;
|
|
210
|
+
let scrollArrow = null;
|
|
211
|
+
// Create the single scroll arrow
|
|
212
|
+
scrollArrow = document.createElement('div');
|
|
213
|
+
scrollArrow.style.cssText = `
|
|
214
|
+
position: fixed;
|
|
215
|
+
width: 40px;
|
|
216
|
+
height: 40px;
|
|
217
|
+
font-size: 24px;
|
|
218
|
+
color: #0096ff;
|
|
219
|
+
text-align: center;
|
|
220
|
+
line-height: 40px;
|
|
221
|
+
pointer-events: none;
|
|
222
|
+
z-index: 1000000045;
|
|
223
|
+
display: none;
|
|
224
|
+
transition: transform 0.1s ease-out, opacity 0.2s ease-out;
|
|
225
|
+
`;
|
|
226
|
+
document.body.appendChild(scrollArrow);
|
|
227
|
+
// Handle both wheel and scroll events
|
|
228
|
+
const handleScroll = (e) => {
|
|
229
|
+
if (!scrollArrow)
|
|
230
|
+
return;
|
|
231
|
+
// Skip if no vertical scroll
|
|
232
|
+
if (Math.abs(e.deltaY) < 0.5)
|
|
233
|
+
return;
|
|
234
|
+
// Clear existing timeout
|
|
235
|
+
if (scrollTimeout) {
|
|
236
|
+
clearTimeout(scrollTimeout);
|
|
237
|
+
}
|
|
238
|
+
// Update arrow
|
|
239
|
+
const scrollDirection = e.deltaY > 0 ? 'down' : 'up';
|
|
240
|
+
scrollArrow.textContent = scrollDirection === 'down' ? '▼' : '▲';
|
|
241
|
+
// Position above/below cursor based on direction
|
|
242
|
+
// Arrow is 40px tall, cursor is ~20px, add 10px spacing
|
|
243
|
+
const offset = scrollDirection === 'down' ? 30 : -30;
|
|
244
|
+
scrollArrow.style.left = `${e.clientX - 20}px`;
|
|
245
|
+
scrollArrow.style.top = `${e.clientY + offset - 20}px`; // -20 to account for arrow center
|
|
246
|
+
// Scale based on deltaY magnitude
|
|
247
|
+
const scale = 0.8 + Math.min(Math.abs(e.deltaY) / 10, 0.4);
|
|
248
|
+
scrollArrow.style.transform = `scale(${scale})`;
|
|
249
|
+
scrollArrow.style.opacity = '0.4';
|
|
250
|
+
scrollArrow.style.display = 'block';
|
|
251
|
+
// Hide after scroll stops
|
|
252
|
+
scrollTimeout = setTimeout(() => {
|
|
253
|
+
if (scrollArrow) {
|
|
254
|
+
scrollArrow.style.opacity = '0';
|
|
255
|
+
setTimeout(() => {
|
|
256
|
+
if (scrollArrow)
|
|
257
|
+
scrollArrow.style.display = 'none';
|
|
258
|
+
}, 200);
|
|
259
|
+
}
|
|
260
|
+
}, 150);
|
|
261
|
+
};
|
|
262
|
+
// Add event listeners for both wheel and scroll events
|
|
263
|
+
document.addEventListener('wheel', handleScroll, { passive: true });
|
|
264
|
+
// Also listen to scroll events on window and document.body for better compatibility
|
|
265
|
+
window.addEventListener('wheel', handleScroll, { passive: true });
|
|
266
|
+
document.body.addEventListener('wheel', handleScroll, { passive: true });
|
|
267
|
+
// Hide cursor when it leaves the viewport
|
|
268
|
+
document.addEventListener('mouseleave', () => {
|
|
269
|
+
if (cursor) {
|
|
270
|
+
cursor.style.display = 'none';
|
|
271
|
+
}
|
|
272
|
+
// Clean up any active ripples
|
|
273
|
+
activeRipples.forEach(ripple => ripple.remove());
|
|
274
|
+
activeRipples.clear();
|
|
275
|
+
// Hide scroll arrow
|
|
276
|
+
if (scrollArrow) {
|
|
277
|
+
scrollArrow.style.display = 'none';
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
document.addEventListener('mouseenter', () => {
|
|
281
|
+
if (cursor) {
|
|
282
|
+
cursor.style.display = 'block';
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
}, { opacity: this.baseOpacity, showHoverCircle: this.showHoverCircle, showClickRipple: this.showClickRipple, showDragLine: this.showDragLine });
|
|
286
|
+
}
|
|
287
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Page } from "playwright";
|
|
2
|
+
export declare class TypeEffectVisual {
|
|
3
|
+
private baseOpacity;
|
|
4
|
+
private displayDuration;
|
|
5
|
+
private maxKeys;
|
|
6
|
+
private page;
|
|
7
|
+
constructor(baseOpacity?: number, displayDuration?: number, maxKeys?: number);
|
|
8
|
+
setActivePage(page: Page): Promise<void>;
|
|
9
|
+
setupOnPage(): Promise<void>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { retryOnErrorIsSuccess } from "@/common";
|
|
2
|
+
export class TypeEffectVisual {
|
|
3
|
+
baseOpacity;
|
|
4
|
+
displayDuration;
|
|
5
|
+
maxKeys;
|
|
6
|
+
page;
|
|
7
|
+
constructor(baseOpacity = 0.6, displayDuration = 2000, maxKeys = 5) {
|
|
8
|
+
this.baseOpacity = baseOpacity;
|
|
9
|
+
this.displayDuration = displayDuration;
|
|
10
|
+
this.maxKeys = maxKeys;
|
|
11
|
+
}
|
|
12
|
+
async setActivePage(page) {
|
|
13
|
+
this.page = page;
|
|
14
|
+
page.on('load', async () => {
|
|
15
|
+
await retryOnErrorIsSuccess(this.setupOnPage.bind(this), { mode: 'retry_all', delayMs: 200, retryLimit: 10 });
|
|
16
|
+
});
|
|
17
|
+
await retryOnErrorIsSuccess(this.setupOnPage.bind(this), { mode: 'retry_all', delayMs: 200, retryLimit: 5 });
|
|
18
|
+
}
|
|
19
|
+
async setupOnPage() {
|
|
20
|
+
await this.page.evaluate((options) => {
|
|
21
|
+
if (window.__typeEffectsInitialized) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
window.__typeEffectsInitialized = true;
|
|
25
|
+
// Create container for key badges
|
|
26
|
+
const container = document.createElement('div');
|
|
27
|
+
container.id = 'type-effects-container';
|
|
28
|
+
container.style.cssText = `
|
|
29
|
+
position: fixed;
|
|
30
|
+
bottom: 40px;
|
|
31
|
+
left: 50%;
|
|
32
|
+
transform: translateX(-50%);
|
|
33
|
+
display: flex;
|
|
34
|
+
gap: 8px;
|
|
35
|
+
align-items: center;
|
|
36
|
+
pointer-events: none;
|
|
37
|
+
z-index: 1000000060;
|
|
38
|
+
`;
|
|
39
|
+
document.body.appendChild(container);
|
|
40
|
+
// Add styles for key badges
|
|
41
|
+
const style = document.createElement('style');
|
|
42
|
+
style.setAttribute('data-type-effects', 'true');
|
|
43
|
+
style.textContent = `
|
|
44
|
+
@keyframes keyIn {
|
|
45
|
+
0% {
|
|
46
|
+
opacity: 0;
|
|
47
|
+
transform: scale(0.5) translateY(20px);
|
|
48
|
+
}
|
|
49
|
+
100% {
|
|
50
|
+
opacity: 1;
|
|
51
|
+
transform: scale(1) translateY(0);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
@keyframes keyOut {
|
|
55
|
+
0% {
|
|
56
|
+
opacity: 1;
|
|
57
|
+
transform: scale(1) translateY(0);
|
|
58
|
+
}
|
|
59
|
+
100% {
|
|
60
|
+
opacity: 0;
|
|
61
|
+
transform: scale(0.8) translateY(10px);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
.key-badge {
|
|
65
|
+
display: inline-flex;
|
|
66
|
+
align-items: center;
|
|
67
|
+
justify-content: center;
|
|
68
|
+
min-width: 40px;
|
|
69
|
+
height: 40px;
|
|
70
|
+
padding: 0 12px;
|
|
71
|
+
background: rgba(0, 100, 200, ${options.opacity * 0.9});
|
|
72
|
+
border: none;
|
|
73
|
+
border-radius: 6px;
|
|
74
|
+
font-family: monospace;
|
|
75
|
+
font-size: 16px;
|
|
76
|
+
font-weight: bold;
|
|
77
|
+
color: white;
|
|
78
|
+
animation: keyIn 0.2s ease-out forwards;
|
|
79
|
+
white-space: nowrap;
|
|
80
|
+
user-select: none;
|
|
81
|
+
-webkit-user-select: none;
|
|
82
|
+
-moz-user-select: none;
|
|
83
|
+
-ms-user-select: none;
|
|
84
|
+
}
|
|
85
|
+
.key-badge.fading {
|
|
86
|
+
animation: keyOut 0.3s ease-out forwards;
|
|
87
|
+
}
|
|
88
|
+
`;
|
|
89
|
+
document.head.appendChild(style);
|
|
90
|
+
// Define special keys to track (excluding modifiers on their own)
|
|
91
|
+
const specialKeys = {
|
|
92
|
+
'Enter': '↵ Enter',
|
|
93
|
+
'Tab': '⇥ Tab',
|
|
94
|
+
'Delete': '⌦ Del',
|
|
95
|
+
'Escape': '⎋ Esc',
|
|
96
|
+
'ArrowUp': '↑',
|
|
97
|
+
'ArrowDown': '↓',
|
|
98
|
+
'ArrowLeft': '←',
|
|
99
|
+
'ArrowRight': '→',
|
|
100
|
+
'Home': '⇱ Home',
|
|
101
|
+
'End': '⇲ End',
|
|
102
|
+
'PageUp': '⇞ PgUp',
|
|
103
|
+
'PageDown': '⇟ PgDn',
|
|
104
|
+
'Insert': 'Ins',
|
|
105
|
+
};
|
|
106
|
+
// Active badges
|
|
107
|
+
const activeBadges = [];
|
|
108
|
+
// Handle keydown events
|
|
109
|
+
document.addEventListener('keydown', (e) => {
|
|
110
|
+
const key = e.key;
|
|
111
|
+
// Check if we have meaningful modifiers (Ctrl or Cmd)
|
|
112
|
+
const hasMeaningfulModifiers = e.ctrlKey || e.metaKey;
|
|
113
|
+
// For modifier combos, we want to show them with ANY key (including letters/numbers)
|
|
114
|
+
if (hasMeaningfulModifiers) {
|
|
115
|
+
// Skip if it's just a modifier key by itself
|
|
116
|
+
if (['Control', 'Alt', 'Shift', 'Meta'].includes(key)) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
// Build the combo display
|
|
120
|
+
let modifiers = [];
|
|
121
|
+
if (e.ctrlKey)
|
|
122
|
+
modifiers.push('Ctrl');
|
|
123
|
+
if (e.metaKey)
|
|
124
|
+
modifiers.push('⌘');
|
|
125
|
+
// Include Shift/Alt only if Ctrl or Cmd is also pressed
|
|
126
|
+
if ((e.ctrlKey || e.metaKey) && e.shiftKey)
|
|
127
|
+
modifiers.push('Shift');
|
|
128
|
+
if ((e.ctrlKey || e.metaKey) && e.altKey)
|
|
129
|
+
modifiers.push('Alt');
|
|
130
|
+
// Get the key display
|
|
131
|
+
let keyDisplay = specialKeys[key] || key.toUpperCase();
|
|
132
|
+
if (key.length === 1) {
|
|
133
|
+
keyDisplay = key.toUpperCase();
|
|
134
|
+
}
|
|
135
|
+
const displayText = modifiers.join('+') + '+' + keyDisplay;
|
|
136
|
+
// Create badge
|
|
137
|
+
createBadge(displayText);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
// No modifiers - only show if it's a special key
|
|
141
|
+
const keyDisplay = specialKeys[key];
|
|
142
|
+
if (keyDisplay) {
|
|
143
|
+
createBadge(keyDisplay);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
function createBadge(displayText) {
|
|
148
|
+
// Create badge element
|
|
149
|
+
const badge = document.createElement('div');
|
|
150
|
+
badge.className = 'key-badge';
|
|
151
|
+
badge.textContent = displayText;
|
|
152
|
+
// Add to container
|
|
153
|
+
container.appendChild(badge);
|
|
154
|
+
// Set up removal timeout
|
|
155
|
+
const timeout = setTimeout(() => {
|
|
156
|
+
badge.classList.add('fading');
|
|
157
|
+
setTimeout(() => {
|
|
158
|
+
badge.remove();
|
|
159
|
+
// Remove from active badges
|
|
160
|
+
const index = activeBadges.findIndex(b => b.element === badge);
|
|
161
|
+
if (index !== -1) {
|
|
162
|
+
activeBadges.splice(index, 1);
|
|
163
|
+
}
|
|
164
|
+
}, 300);
|
|
165
|
+
}, options.displayDuration);
|
|
166
|
+
// Track active badge
|
|
167
|
+
activeBadges.push({ element: badge, timeout });
|
|
168
|
+
// Remove oldest badges if we exceed max
|
|
169
|
+
while (activeBadges.length > options.maxKeys) {
|
|
170
|
+
const oldest = activeBadges.shift();
|
|
171
|
+
if (oldest) {
|
|
172
|
+
clearTimeout(oldest.timeout);
|
|
173
|
+
oldest.element.classList.add('fading');
|
|
174
|
+
setTimeout(() => oldest.element.remove(), 300);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// Clean up on page hide
|
|
179
|
+
document.addEventListener('visibilitychange', () => {
|
|
180
|
+
if (document.hidden) {
|
|
181
|
+
activeBadges.forEach(({ element, timeout }) => {
|
|
182
|
+
clearTimeout(timeout);
|
|
183
|
+
element.remove();
|
|
184
|
+
});
|
|
185
|
+
activeBadges.length = 0;
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
}, { opacity: this.baseOpacity, displayDuration: this.displayDuration, maxKeys: this.maxKeys });
|
|
189
|
+
}
|
|
190
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ddwang/magnitude-core",
|
|
3
|
+
"version": "0.3.1-ddwang.1",
|
|
4
|
+
"description": "Magnitude e2e testing agent",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"main": "./dist/index.cjs",
|
|
9
|
+
"module": "./dist/index.mjs",
|
|
10
|
+
"types": "./dist/index.d.cts",
|
|
11
|
+
"bin": {
|
|
12
|
+
"magnus": "dist/cli.js"
|
|
13
|
+
},
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/magnitudedev/magnitude.git"
|
|
17
|
+
},
|
|
18
|
+
"homepage": "https://github.com/magnitudedev/magnitude#readme",
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/magnitudedev/magnitude/issues"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"keywords": [
|
|
26
|
+
"ai",
|
|
27
|
+
"agent",
|
|
28
|
+
"testing",
|
|
29
|
+
"ui-testing",
|
|
30
|
+
"automation",
|
|
31
|
+
"magnitude",
|
|
32
|
+
"typescript"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "baml-cli generate && tsc && pkgroll",
|
|
36
|
+
"check": "tsc --noEmit",
|
|
37
|
+
"cli": "bun ./src/cli.ts",
|
|
38
|
+
"pubdev": "bun run build && yalc publish --force --push"
|
|
39
|
+
},
|
|
40
|
+
"author": {
|
|
41
|
+
"name": "Magnitude",
|
|
42
|
+
"email": "founders@magnitude.run",
|
|
43
|
+
"url": "https://magnitude.run"
|
|
44
|
+
},
|
|
45
|
+
"contributors": [
|
|
46
|
+
"Anders Lie <anders@magnitude.run>"
|
|
47
|
+
],
|
|
48
|
+
"license": "Apache-2.0",
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@types/node": "^22.13.4",
|
|
51
|
+
"@types/object-hash": "^3.0.6",
|
|
52
|
+
"pkgroll": "^2.10.0",
|
|
53
|
+
"typescript": "~5.7.2"
|
|
54
|
+
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"@boundaryml/baml": "^0.202.0",
|
|
57
|
+
"@paralleldrive/cuid2": "^2.2.2",
|
|
58
|
+
"ansis": "^4.1.0",
|
|
59
|
+
"commander": "^13.1.0",
|
|
60
|
+
"eventemitter3": "^5.0.1",
|
|
61
|
+
"magnitude-extract": "0.0.2",
|
|
62
|
+
"object-hash": "^3.0.0",
|
|
63
|
+
"pino": "^9.6.0",
|
|
64
|
+
"pino-pretty": "^13.0.0",
|
|
65
|
+
"playwright": "npm:patchright@^1.52.0",
|
|
66
|
+
"posthog-node": "^5.1.1",
|
|
67
|
+
"sharp": "^0.33.5",
|
|
68
|
+
"zod": "^3.24.4",
|
|
69
|
+
"zod-to-json-schema": "^3.24.5"
|
|
70
|
+
}
|
|
71
|
+
}
|