camel-ai 0.2.67__py3-none-any.whl → 0.2.80a2__py3-none-any.whl
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.
- camel/__init__.py +1 -1
- camel/agents/_types.py +6 -2
- camel/agents/_utils.py +38 -0
- camel/agents/chat_agent.py +4014 -410
- camel/agents/mcp_agent.py +30 -27
- camel/agents/repo_agent.py +2 -1
- camel/benchmarks/browsecomp.py +6 -6
- camel/configs/__init__.py +15 -0
- camel/configs/aihubmix_config.py +88 -0
- camel/configs/amd_config.py +70 -0
- camel/configs/cometapi_config.py +104 -0
- camel/configs/minimax_config.py +93 -0
- camel/configs/nebius_config.py +103 -0
- camel/configs/vllm_config.py +2 -0
- camel/data_collectors/alpaca_collector.py +15 -6
- camel/datagen/self_improving_cot.py +1 -1
- camel/datasets/base_generator.py +39 -10
- camel/environments/__init__.py +12 -0
- camel/environments/rlcards_env.py +860 -0
- camel/environments/single_step.py +28 -3
- camel/environments/tic_tac_toe.py +1 -1
- camel/interpreters/__init__.py +2 -0
- camel/interpreters/docker/Dockerfile +4 -16
- camel/interpreters/docker_interpreter.py +3 -2
- camel/interpreters/e2b_interpreter.py +34 -1
- camel/interpreters/internal_python_interpreter.py +51 -2
- camel/interpreters/microsandbox_interpreter.py +395 -0
- camel/loaders/__init__.py +11 -2
- camel/loaders/base_loader.py +85 -0
- camel/loaders/chunkr_reader.py +9 -0
- camel/loaders/firecrawl_reader.py +4 -4
- camel/logger.py +1 -1
- camel/memories/agent_memories.py +84 -1
- camel/memories/base.py +34 -0
- camel/memories/blocks/chat_history_block.py +122 -4
- camel/memories/blocks/vectordb_block.py +8 -1
- camel/memories/context_creators/score_based.py +29 -237
- camel/memories/records.py +88 -8
- camel/messages/base.py +166 -40
- camel/messages/func_message.py +32 -5
- camel/models/__init__.py +10 -0
- camel/models/aihubmix_model.py +83 -0
- camel/models/aiml_model.py +1 -16
- camel/models/amd_model.py +101 -0
- camel/models/anthropic_model.py +117 -18
- camel/models/aws_bedrock_model.py +2 -33
- camel/models/azure_openai_model.py +205 -91
- camel/models/base_audio_model.py +3 -1
- camel/models/base_model.py +189 -24
- camel/models/cohere_model.py +5 -17
- camel/models/cometapi_model.py +83 -0
- camel/models/crynux_model.py +1 -16
- camel/models/deepseek_model.py +6 -16
- camel/models/fish_audio_model.py +6 -0
- camel/models/gemini_model.py +71 -20
- camel/models/groq_model.py +1 -17
- camel/models/internlm_model.py +1 -16
- camel/models/litellm_model.py +49 -32
- camel/models/lmstudio_model.py +1 -17
- camel/models/minimax_model.py +83 -0
- camel/models/mistral_model.py +1 -16
- camel/models/model_factory.py +27 -1
- camel/models/model_manager.py +24 -6
- camel/models/modelscope_model.py +1 -16
- camel/models/moonshot_model.py +185 -19
- camel/models/nebius_model.py +83 -0
- camel/models/nemotron_model.py +0 -5
- camel/models/netmind_model.py +1 -16
- camel/models/novita_model.py +1 -16
- camel/models/nvidia_model.py +1 -16
- camel/models/ollama_model.py +4 -19
- camel/models/openai_compatible_model.py +171 -46
- camel/models/openai_model.py +205 -77
- camel/models/openrouter_model.py +1 -17
- camel/models/ppio_model.py +1 -16
- camel/models/qianfan_model.py +1 -16
- camel/models/qwen_model.py +1 -16
- camel/models/reka_model.py +1 -16
- camel/models/samba_model.py +34 -47
- camel/models/sglang_model.py +64 -31
- camel/models/siliconflow_model.py +1 -16
- camel/models/stub_model.py +0 -4
- camel/models/togetherai_model.py +1 -16
- camel/models/vllm_model.py +1 -16
- camel/models/volcano_model.py +0 -17
- camel/models/watsonx_model.py +1 -16
- camel/models/yi_model.py +1 -16
- camel/models/zhipuai_model.py +60 -16
- camel/parsers/__init__.py +18 -0
- camel/parsers/mcp_tool_call_parser.py +176 -0
- camel/retrievers/auto_retriever.py +1 -0
- camel/runtimes/configs.py +11 -11
- camel/runtimes/daytona_runtime.py +15 -16
- camel/runtimes/docker_runtime.py +6 -6
- camel/runtimes/remote_http_runtime.py +5 -5
- camel/services/agent_openapi_server.py +380 -0
- camel/societies/__init__.py +2 -0
- camel/societies/role_playing.py +26 -28
- camel/societies/workforce/__init__.py +2 -0
- camel/societies/workforce/events.py +122 -0
- camel/societies/workforce/prompts.py +249 -38
- camel/societies/workforce/role_playing_worker.py +82 -20
- camel/societies/workforce/single_agent_worker.py +634 -34
- camel/societies/workforce/structured_output_handler.py +512 -0
- camel/societies/workforce/task_channel.py +169 -23
- camel/societies/workforce/utils.py +176 -9
- camel/societies/workforce/worker.py +77 -23
- camel/societies/workforce/workflow_memory_manager.py +772 -0
- camel/societies/workforce/workforce.py +3168 -478
- camel/societies/workforce/workforce_callback.py +74 -0
- camel/societies/workforce/workforce_logger.py +203 -175
- camel/societies/workforce/workforce_metrics.py +33 -0
- camel/storages/__init__.py +4 -0
- camel/storages/key_value_storages/json.py +15 -2
- camel/storages/key_value_storages/mem0_cloud.py +48 -47
- camel/storages/object_storages/google_cloud.py +1 -1
- camel/storages/vectordb_storages/__init__.py +6 -0
- camel/storages/vectordb_storages/chroma.py +731 -0
- camel/storages/vectordb_storages/oceanbase.py +13 -13
- camel/storages/vectordb_storages/pgvector.py +349 -0
- camel/storages/vectordb_storages/qdrant.py +3 -3
- camel/storages/vectordb_storages/surreal.py +365 -0
- camel/storages/vectordb_storages/tidb.py +8 -6
- camel/tasks/task.py +244 -27
- camel/toolkits/__init__.py +46 -8
- camel/toolkits/aci_toolkit.py +64 -19
- camel/toolkits/arxiv_toolkit.py +6 -6
- camel/toolkits/base.py +63 -5
- camel/toolkits/code_execution.py +28 -1
- camel/toolkits/context_summarizer_toolkit.py +684 -0
- camel/toolkits/craw4ai_toolkit.py +93 -0
- camel/toolkits/dappier_toolkit.py +10 -6
- camel/toolkits/dingtalk.py +1135 -0
- camel/toolkits/edgeone_pages_mcp_toolkit.py +49 -0
- camel/toolkits/excel_toolkit.py +901 -67
- camel/toolkits/file_toolkit.py +1402 -0
- camel/toolkits/function_tool.py +30 -6
- camel/toolkits/github_toolkit.py +107 -20
- camel/toolkits/gmail_toolkit.py +1839 -0
- camel/toolkits/google_calendar_toolkit.py +38 -4
- camel/toolkits/google_drive_mcp_toolkit.py +54 -0
- camel/toolkits/human_toolkit.py +34 -10
- camel/toolkits/hybrid_browser_toolkit/__init__.py +18 -0
- camel/toolkits/hybrid_browser_toolkit/config_loader.py +185 -0
- camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit.py +246 -0
- camel/toolkits/hybrid_browser_toolkit/hybrid_browser_toolkit_ts.py +1973 -0
- camel/toolkits/hybrid_browser_toolkit/installer.py +203 -0
- camel/toolkits/hybrid_browser_toolkit/ts/package-lock.json +3749 -0
- camel/toolkits/hybrid_browser_toolkit/ts/package.json +32 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/browser-scripts.js +125 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/browser-session.ts +1815 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/config-loader.ts +233 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/hybrid-browser-toolkit.ts +590 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/index.ts +7 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/parent-child-filter.ts +226 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/snapshot-parser.ts +219 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/som-screenshot-injected.ts +543 -0
- camel/toolkits/hybrid_browser_toolkit/ts/src/types.ts +130 -0
- camel/toolkits/hybrid_browser_toolkit/ts/tsconfig.json +26 -0
- camel/toolkits/hybrid_browser_toolkit/ts/websocket-server.js +319 -0
- camel/toolkits/hybrid_browser_toolkit/ws_wrapper.py +1032 -0
- camel/toolkits/hybrid_browser_toolkit_py/__init__.py +17 -0
- camel/toolkits/hybrid_browser_toolkit_py/actions.py +575 -0
- camel/toolkits/hybrid_browser_toolkit_py/agent.py +311 -0
- camel/toolkits/hybrid_browser_toolkit_py/browser_session.py +787 -0
- camel/toolkits/hybrid_browser_toolkit_py/config_loader.py +490 -0
- camel/toolkits/hybrid_browser_toolkit_py/hybrid_browser_toolkit.py +2390 -0
- camel/toolkits/hybrid_browser_toolkit_py/snapshot.py +233 -0
- camel/toolkits/hybrid_browser_toolkit_py/stealth_script.js +0 -0
- camel/toolkits/hybrid_browser_toolkit_py/unified_analyzer.js +1043 -0
- camel/toolkits/image_generation_toolkit.py +390 -0
- camel/toolkits/jina_reranker_toolkit.py +3 -4
- camel/toolkits/klavis_toolkit.py +5 -1
- camel/toolkits/markitdown_toolkit.py +104 -0
- camel/toolkits/math_toolkit.py +64 -10
- camel/toolkits/mcp_toolkit.py +370 -45
- camel/toolkits/memory_toolkit.py +5 -1
- camel/toolkits/message_agent_toolkit.py +608 -0
- camel/toolkits/message_integration.py +724 -0
- camel/toolkits/minimax_mcp_toolkit.py +195 -0
- camel/toolkits/note_taking_toolkit.py +277 -0
- camel/toolkits/notion_mcp_toolkit.py +224 -0
- camel/toolkits/openbb_toolkit.py +5 -1
- camel/toolkits/origene_mcp_toolkit.py +56 -0
- camel/toolkits/playwright_mcp_toolkit.py +12 -31
- camel/toolkits/pptx_toolkit.py +25 -12
- camel/toolkits/resend_toolkit.py +168 -0
- camel/toolkits/screenshot_toolkit.py +213 -0
- camel/toolkits/search_toolkit.py +437 -142
- camel/toolkits/slack_toolkit.py +104 -50
- camel/toolkits/sympy_toolkit.py +1 -1
- camel/toolkits/task_planning_toolkit.py +3 -3
- camel/toolkits/terminal_toolkit/__init__.py +18 -0
- camel/toolkits/terminal_toolkit/terminal_toolkit.py +957 -0
- camel/toolkits/terminal_toolkit/utils.py +532 -0
- camel/toolkits/thinking_toolkit.py +1 -1
- camel/toolkits/vertex_ai_veo_toolkit.py +590 -0
- camel/toolkits/video_analysis_toolkit.py +106 -26
- camel/toolkits/video_download_toolkit.py +17 -14
- camel/toolkits/web_deploy_toolkit.py +1219 -0
- camel/toolkits/wechat_official_toolkit.py +483 -0
- camel/toolkits/zapier_toolkit.py +5 -1
- camel/types/__init__.py +2 -2
- camel/types/agents/tool_calling_record.py +4 -1
- camel/types/enums.py +316 -40
- camel/types/openai_types.py +2 -2
- camel/types/unified_model_type.py +31 -4
- camel/utils/commons.py +36 -5
- camel/utils/constants.py +3 -0
- camel/utils/context_utils.py +1003 -0
- camel/utils/mcp.py +138 -4
- camel/utils/mcp_client.py +45 -1
- camel/utils/message_summarizer.py +148 -0
- camel/utils/token_counting.py +43 -20
- camel/utils/tool_result.py +44 -0
- {camel_ai-0.2.67.dist-info → camel_ai-0.2.80a2.dist-info}/METADATA +296 -85
- {camel_ai-0.2.67.dist-info → camel_ai-0.2.80a2.dist-info}/RECORD +219 -146
- camel/loaders/pandas_reader.py +0 -368
- camel/toolkits/dalle_toolkit.py +0 -175
- camel/toolkits/file_write_toolkit.py +0 -444
- camel/toolkits/openai_agent_toolkit.py +0 -135
- camel/toolkits/terminal_toolkit.py +0 -1037
- {camel_ai-0.2.67.dist-info → camel_ai-0.2.80a2.dist-info}/WHEEL +0 -0
- {camel_ai-0.2.67.dist-info → camel_ai-0.2.80a2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,543 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Alternative implementation of SOM-screenshot using JS injection
|
|
3
|
+
* This avoids CDP resolution issues by rendering labels directly in the page
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Page } from 'playwright';
|
|
7
|
+
import { SnapshotResult, VisualMarkResult } from './types';
|
|
8
|
+
import { writeFile } from 'fs/promises';
|
|
9
|
+
|
|
10
|
+
export class SomScreenshotInjected {
|
|
11
|
+
/**
|
|
12
|
+
* Take a screenshot with SOM-labels injected into the page
|
|
13
|
+
* This approach uses a single script injection for better performance
|
|
14
|
+
*/
|
|
15
|
+
static async captureOptimized(
|
|
16
|
+
page: Page,
|
|
17
|
+
snapshotResult: SnapshotResult,
|
|
18
|
+
clickableElements: Set<string>,
|
|
19
|
+
exportPath?: string
|
|
20
|
+
): Promise<VisualMarkResult & { timing: any }> {
|
|
21
|
+
const startTime = Date.now();
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
// Use the already filtered clickableElements directly
|
|
25
|
+
const filterStartTime = Date.now();
|
|
26
|
+
const filterTime = Date.now() - filterStartTime;
|
|
27
|
+
console.log(`Using pre-filtered clickable elements: ${clickableElements.size} elements`);
|
|
28
|
+
|
|
29
|
+
// Prepare element geometry data for export
|
|
30
|
+
const elementGeometry: any[] = [];
|
|
31
|
+
// Inject and capture in one go
|
|
32
|
+
// Collect visibility debug info
|
|
33
|
+
const visibilityDebugInfo: any[] = [];
|
|
34
|
+
|
|
35
|
+
const result = await page.evaluate(async (data) => {
|
|
36
|
+
const { elements, clickable, filterDebugInfo } = data;
|
|
37
|
+
const markedElements: any[] = [];
|
|
38
|
+
|
|
39
|
+
// Debug info collector - include filter debug info
|
|
40
|
+
const debugInfo: any[] = [...filterDebugInfo];
|
|
41
|
+
|
|
42
|
+
// Helper function to check element visibility based on coordinates
|
|
43
|
+
function checkElementVisibilityByCoords(
|
|
44
|
+
coords: { x: number, y: number, width: number, height: number },
|
|
45
|
+
ref: string,
|
|
46
|
+
elementInfo: any
|
|
47
|
+
): 'visible' | 'partial' | 'hidden' {
|
|
48
|
+
// Skip if element is outside viewport
|
|
49
|
+
if (coords.y + coords.height < 0 || coords.y > window.innerHeight ||
|
|
50
|
+
coords.x + coords.width < 0 || coords.x > window.innerWidth) {
|
|
51
|
+
return 'hidden';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Simple approach: just check the center point
|
|
55
|
+
// If center is visible and shows our element (or its child), consider it visible
|
|
56
|
+
const centerX = coords.x + coords.width * 0.5;
|
|
57
|
+
const centerY = coords.y + coords.height * 0.5;
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
const elementsAtCenter = document.elementsFromPoint(centerX, centerY);
|
|
61
|
+
if (!elementsAtCenter || elementsAtCenter.length === 0) {
|
|
62
|
+
return 'hidden';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Find our target element in the stack
|
|
66
|
+
let targetFound = false;
|
|
67
|
+
let targetIsTopmost = false;
|
|
68
|
+
|
|
69
|
+
for (let i = 0; i < elementsAtCenter.length; i++) {
|
|
70
|
+
const elem = elementsAtCenter[i];
|
|
71
|
+
const rect = elem.getBoundingClientRect();
|
|
72
|
+
|
|
73
|
+
// Check if this element matches our expected bounds (within tolerance)
|
|
74
|
+
if (Math.abs(rect.left - coords.x) < 5 &&
|
|
75
|
+
Math.abs(rect.top - coords.y) < 5 &&
|
|
76
|
+
Math.abs(rect.width - coords.width) < 10 &&
|
|
77
|
+
Math.abs(rect.height - coords.height) < 10) {
|
|
78
|
+
targetFound = true;
|
|
79
|
+
targetIsTopmost = (i === 0);
|
|
80
|
+
|
|
81
|
+
// If target is topmost, it's definitely visible
|
|
82
|
+
if (targetIsTopmost) {
|
|
83
|
+
return 'visible';
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// If not topmost, check if the topmost element is a child of our target
|
|
87
|
+
const topmostElem = elementsAtCenter[0];
|
|
88
|
+
if (elem.contains(topmostElem)) {
|
|
89
|
+
// Topmost is our child - element is visible
|
|
90
|
+
return 'visible';
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Otherwise, we're obscured
|
|
94
|
+
return 'hidden';
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// If we didn't find our target element at all
|
|
99
|
+
if (!targetFound) {
|
|
100
|
+
// Special handling for composite widgets
|
|
101
|
+
const topElement = elementsAtCenter[0];
|
|
102
|
+
const tagName = topElement.tagName.toUpperCase();
|
|
103
|
+
|
|
104
|
+
// Get element role/type for better decision making
|
|
105
|
+
const elementRole = elementInfo?.role || '';
|
|
106
|
+
const elementTagName = elementInfo?.tagName || '';
|
|
107
|
+
|
|
108
|
+
// Only apply special handling for form controls that are part of composite widgets
|
|
109
|
+
if (['SELECT', 'INPUT', 'TEXTAREA', 'BUTTON'].includes(tagName)) {
|
|
110
|
+
const isFormRelatedElement = ['combobox', 'select', 'textbox', 'searchbox', 'spinbutton'].includes(elementRole) ||
|
|
111
|
+
['SELECT', 'INPUT', 'TEXTAREA', 'BUTTON', 'OPTION'].includes(elementTagName.toUpperCase());
|
|
112
|
+
|
|
113
|
+
// Check if the form control approximately matches our area
|
|
114
|
+
const rect = topElement.getBoundingClientRect();
|
|
115
|
+
const overlap = Math.min(rect.right, coords.x + coords.width) - Math.max(rect.left, coords.x) > 0 &&
|
|
116
|
+
Math.min(rect.bottom, coords.y + coords.height) - Math.max(rect.top, coords.y) > 0;
|
|
117
|
+
|
|
118
|
+
if (overlap && isFormRelatedElement) {
|
|
119
|
+
// Check for specific composite widget patterns
|
|
120
|
+
// For combobox with search input (like Amazon search)
|
|
121
|
+
if (elementRole === 'combobox' && tagName === 'INPUT') {
|
|
122
|
+
// This is likely a search box with category selector - mark as visible
|
|
123
|
+
return 'visible';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// For button/generic elements covered by INPUT with exact same bounds
|
|
127
|
+
// This usually indicates the INPUT is the actual interactive element for the button
|
|
128
|
+
if ((elementRole === 'button' || elementRole === 'generic') && tagName === 'INPUT') {
|
|
129
|
+
const rectMatch = Math.abs(rect.left - coords.x) < 2 &&
|
|
130
|
+
Math.abs(rect.top - coords.y) < 2 &&
|
|
131
|
+
Math.abs(rect.width - coords.width) < 2 &&
|
|
132
|
+
Math.abs(rect.height - coords.height) < 2;
|
|
133
|
+
if (rectMatch) {
|
|
134
|
+
// The INPUT is the actual interactive element for this button
|
|
135
|
+
return 'visible';
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// For other form-related elements, only mark as visible if they share similar positioning
|
|
140
|
+
// (i.e., they're likely part of the same widget)
|
|
141
|
+
const sizeDiff = Math.abs(rect.width - coords.width) + Math.abs(rect.height - coords.height);
|
|
142
|
+
if (sizeDiff < 50) { // Tolerance for size difference
|
|
143
|
+
return 'visible';
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return 'hidden';
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return 'partial';
|
|
152
|
+
|
|
153
|
+
} catch (e) {
|
|
154
|
+
// Fallback: use simple elementFromPoint check
|
|
155
|
+
const elem = document.elementFromPoint(centerX, centerY);
|
|
156
|
+
if (!elem) return 'hidden';
|
|
157
|
+
|
|
158
|
+
const rect = elem.getBoundingClientRect();
|
|
159
|
+
// Check if the element at center matches our bounds
|
|
160
|
+
if (Math.abs(rect.left - coords.x) < 5 &&
|
|
161
|
+
Math.abs(rect.top - coords.y) < 5) {
|
|
162
|
+
return 'visible';
|
|
163
|
+
}
|
|
164
|
+
return 'partial';
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
// Create overlay
|
|
170
|
+
const overlay = document.createElement('div');
|
|
171
|
+
overlay.id = 'camel-som-overlay-temp'; // Set ID immediately for cleanup
|
|
172
|
+
overlay.style.cssText = `
|
|
173
|
+
position: fixed;
|
|
174
|
+
top: 0;
|
|
175
|
+
left: 0;
|
|
176
|
+
width: 100%;
|
|
177
|
+
height: 100%;
|
|
178
|
+
pointer-events: none;
|
|
179
|
+
z-index: 2147483647;
|
|
180
|
+
`;
|
|
181
|
+
|
|
182
|
+
// Check visibility for each element using coordinates
|
|
183
|
+
const elementStates = new Map<string, 'visible' | 'partial' | 'hidden'>();
|
|
184
|
+
|
|
185
|
+
Object.entries(elements).forEach(([ref, element]: [string, any]) => {
|
|
186
|
+
if (element.coordinates && clickable.includes(ref)) {
|
|
187
|
+
const visibility = checkElementVisibilityByCoords(element.coordinates, ref, element);
|
|
188
|
+
elementStates.set(ref, visibility);
|
|
189
|
+
|
|
190
|
+
// Add debug info
|
|
191
|
+
const centerX = element.coordinates.x + element.coordinates.width * 0.5;
|
|
192
|
+
const centerY = element.coordinates.y + element.coordinates.height * 0.5;
|
|
193
|
+
|
|
194
|
+
try {
|
|
195
|
+
const elementsAtCenter = document.elementsFromPoint(centerX, centerY);
|
|
196
|
+
const topmostElement = elementsAtCenter[0];
|
|
197
|
+
|
|
198
|
+
debugInfo.push({
|
|
199
|
+
ref,
|
|
200
|
+
coords: element.coordinates,
|
|
201
|
+
centerPoint: { x: centerX, y: centerY },
|
|
202
|
+
visibilityResult: visibility,
|
|
203
|
+
elementRole: element.role || 'unknown',
|
|
204
|
+
elementTagName: element.tagName || '',
|
|
205
|
+
topmostElement: topmostElement ? {
|
|
206
|
+
tagName: topmostElement.tagName,
|
|
207
|
+
className: topmostElement.className,
|
|
208
|
+
id: topmostElement.id
|
|
209
|
+
} : null,
|
|
210
|
+
elementsAtCenterCount: elementsAtCenter.length
|
|
211
|
+
});
|
|
212
|
+
} catch (e) {
|
|
213
|
+
debugInfo.push({
|
|
214
|
+
ref,
|
|
215
|
+
coords: element.coordinates,
|
|
216
|
+
visibilityResult: visibility,
|
|
217
|
+
elementRole: element.role || 'unknown',
|
|
218
|
+
elementTagName: element.tagName || '',
|
|
219
|
+
error: 'Failed to get elements at center'
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
// Track label positions to avoid overlap
|
|
226
|
+
const labelPositions: Array<{x: number, y: number, width: number, height: number, ref: string}> = [];
|
|
227
|
+
|
|
228
|
+
// Helper to check if two rectangles overlap
|
|
229
|
+
function rectsOverlap(r1: any, r2: any): boolean {
|
|
230
|
+
return !(r1.x + r1.width < r2.x ||
|
|
231
|
+
r2.x + r2.width < r1.x ||
|
|
232
|
+
r1.y + r1.height < r2.y ||
|
|
233
|
+
r2.y + r2.height < r1.y);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Helper to find non-overlapping position for label
|
|
237
|
+
function findLabelPosition(element: any, labelWidth: number, labelHeight: number): {x: number, y: number} {
|
|
238
|
+
const { x, y, width, height } = element.coordinates;
|
|
239
|
+
const isSmallElement = height < 70;
|
|
240
|
+
const margin = 2; // Space between label and element
|
|
241
|
+
|
|
242
|
+
// Try different positions in order of preference
|
|
243
|
+
const positions = [];
|
|
244
|
+
|
|
245
|
+
if (isSmallElement) {
|
|
246
|
+
// For small elements, try outside positions
|
|
247
|
+
// 1. Above element
|
|
248
|
+
positions.push({ x: x - 2, y: y - labelHeight - margin });
|
|
249
|
+
// 2. Below element
|
|
250
|
+
positions.push({ x: x - 2, y: y + height + margin });
|
|
251
|
+
// 3. Left of element
|
|
252
|
+
positions.push({ x: x - labelWidth - margin, y: y });
|
|
253
|
+
// 4. Right of element
|
|
254
|
+
positions.push({ x: x + width + margin, y: y });
|
|
255
|
+
} else {
|
|
256
|
+
// For large elements, inside top-left
|
|
257
|
+
positions.push({ x: x + 4, y: y + 4 });
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Check each position
|
|
261
|
+
for (const pos of positions) {
|
|
262
|
+
// Adjust for viewport boundaries
|
|
263
|
+
const adjustedPos = { ...pos };
|
|
264
|
+
|
|
265
|
+
// Keep within viewport
|
|
266
|
+
adjustedPos.x = Math.max(0, Math.min(adjustedPos.x, window.innerWidth - labelWidth));
|
|
267
|
+
adjustedPos.y = Math.max(0, Math.min(adjustedPos.y, window.innerHeight - labelHeight));
|
|
268
|
+
|
|
269
|
+
// Check for overlaps with existing labels
|
|
270
|
+
const testRect = { x: adjustedPos.x, y: adjustedPos.y, width: labelWidth, height: labelHeight };
|
|
271
|
+
let hasOverlap = false;
|
|
272
|
+
|
|
273
|
+
for (const existing of labelPositions) {
|
|
274
|
+
if (rectsOverlap(testRect, existing)) {
|
|
275
|
+
hasOverlap = true;
|
|
276
|
+
break;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (!hasOverlap) {
|
|
281
|
+
return adjustedPos;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// If all positions overlap, try to find space by offsetting
|
|
286
|
+
// Try positions around the element in a spiral pattern
|
|
287
|
+
const offsets = [
|
|
288
|
+
{ dx: 0, dy: -labelHeight - margin - 20 }, // Further above
|
|
289
|
+
{ dx: 0, dy: height + margin + 20 }, // Further below
|
|
290
|
+
{ dx: -labelWidth - margin - 20, dy: 0 }, // Further left
|
|
291
|
+
{ dx: width + margin + 20, dy: 0 }, // Further right
|
|
292
|
+
{ dx: -labelWidth - margin, dy: -labelHeight - margin }, // Top-left
|
|
293
|
+
{ dx: width + margin, dy: -labelHeight - margin }, // Top-right
|
|
294
|
+
{ dx: -labelWidth - margin, dy: height + margin }, // Bottom-left
|
|
295
|
+
{ dx: width + margin, dy: height + margin }, // Bottom-right
|
|
296
|
+
];
|
|
297
|
+
|
|
298
|
+
for (const offset of offsets) {
|
|
299
|
+
const pos = {
|
|
300
|
+
x: Math.max(0, Math.min(x + offset.dx, window.innerWidth - labelWidth)),
|
|
301
|
+
y: Math.max(0, Math.min(y + offset.dy, window.innerHeight - labelHeight))
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
const testRect = { x: pos.x, y: pos.y, width: labelWidth, height: labelHeight };
|
|
305
|
+
let hasOverlap = false;
|
|
306
|
+
|
|
307
|
+
for (const existing of labelPositions) {
|
|
308
|
+
if (rectsOverlap(testRect, existing)) {
|
|
309
|
+
hasOverlap = true;
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (!hasOverlap) {
|
|
315
|
+
return pos;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Fallback: use original logic but ensure within viewport
|
|
320
|
+
if (isSmallElement) {
|
|
321
|
+
const fallbackY = y >= 25 ? y - 25 : y + height + 2;
|
|
322
|
+
return {
|
|
323
|
+
x: Math.max(0, Math.min(x - 2, window.innerWidth - labelWidth)),
|
|
324
|
+
y: Math.max(0, Math.min(fallbackY, window.innerHeight - labelHeight))
|
|
325
|
+
};
|
|
326
|
+
} else {
|
|
327
|
+
return { x: x + 4, y: y + 4 };
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Add labels and collect geometry data (only for filtered elements)
|
|
332
|
+
Object.entries(elements).forEach(([ref, element]: [string, any]) => {
|
|
333
|
+
if (element.coordinates && clickable.includes(ref)) {
|
|
334
|
+
const state = elementStates.get(ref);
|
|
335
|
+
|
|
336
|
+
// Skip completely hidden elements
|
|
337
|
+
if (state === 'hidden') return;
|
|
338
|
+
const label = document.createElement('div');
|
|
339
|
+
const { x, y, width, height } = element.coordinates;
|
|
340
|
+
|
|
341
|
+
label.style.cssText = `
|
|
342
|
+
position: absolute;
|
|
343
|
+
left: ${x}px;
|
|
344
|
+
top: ${y}px;
|
|
345
|
+
width: ${width}px;
|
|
346
|
+
height: ${height}px;
|
|
347
|
+
border: 2px ${state === 'partial' ? 'dashed' : 'solid'} #FF0066;
|
|
348
|
+
border-radius: 4px;
|
|
349
|
+
box-shadow: 0 2px 8px rgba(0,0,0,0.3);
|
|
350
|
+
`;
|
|
351
|
+
|
|
352
|
+
// Add ref number with smart positioning
|
|
353
|
+
const refLabel = document.createElement('div');
|
|
354
|
+
refLabel.textContent = ref;
|
|
355
|
+
|
|
356
|
+
// Create temporary label to measure its size
|
|
357
|
+
refLabel.style.cssText = `
|
|
358
|
+
position: absolute;
|
|
359
|
+
visibility: hidden;
|
|
360
|
+
background: #FF0066;
|
|
361
|
+
color: white;
|
|
362
|
+
font: bold 12px Arial, sans-serif;
|
|
363
|
+
padding: 2px 6px;
|
|
364
|
+
border-radius: 2px;
|
|
365
|
+
min-width: 20px;
|
|
366
|
+
text-align: center;
|
|
367
|
+
white-space: nowrap;
|
|
368
|
+
`;
|
|
369
|
+
document.body.appendChild(refLabel);
|
|
370
|
+
const labelWidth = refLabel.offsetWidth;
|
|
371
|
+
const labelHeight = refLabel.offsetHeight;
|
|
372
|
+
document.body.removeChild(refLabel);
|
|
373
|
+
|
|
374
|
+
// Find non-overlapping position
|
|
375
|
+
const labelPos = findLabelPosition(element, labelWidth, labelHeight);
|
|
376
|
+
|
|
377
|
+
// Apply final position
|
|
378
|
+
refLabel.style.cssText = `
|
|
379
|
+
position: absolute;
|
|
380
|
+
left: ${labelPos.x - x}px;
|
|
381
|
+
top: ${labelPos.y - y}px;
|
|
382
|
+
background: #FF0066;
|
|
383
|
+
color: white;
|
|
384
|
+
font: bold 12px Arial, sans-serif;
|
|
385
|
+
padding: 2px 6px;
|
|
386
|
+
border-radius: 2px;
|
|
387
|
+
min-width: 20px;
|
|
388
|
+
text-align: center;
|
|
389
|
+
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
|
|
390
|
+
opacity: ${state === 'partial' ? '0.8' : '1'};
|
|
391
|
+
z-index: 1;
|
|
392
|
+
white-space: nowrap;
|
|
393
|
+
`;
|
|
394
|
+
|
|
395
|
+
// Track this label position
|
|
396
|
+
labelPositions.push({
|
|
397
|
+
x: labelPos.x,
|
|
398
|
+
y: labelPos.y,
|
|
399
|
+
width: labelWidth,
|
|
400
|
+
height: labelHeight,
|
|
401
|
+
ref: ref
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
label.appendChild(refLabel);
|
|
405
|
+
overlay.appendChild(label);
|
|
406
|
+
|
|
407
|
+
// Collect geometry data
|
|
408
|
+
markedElements.push({
|
|
409
|
+
ref,
|
|
410
|
+
x,
|
|
411
|
+
y,
|
|
412
|
+
width,
|
|
413
|
+
height,
|
|
414
|
+
center: {
|
|
415
|
+
x: x + width / 2,
|
|
416
|
+
y: y + height / 2
|
|
417
|
+
},
|
|
418
|
+
area: width * height,
|
|
419
|
+
type: element.role || 'unknown',
|
|
420
|
+
text: element.text || '',
|
|
421
|
+
attributes: element.attributes || {},
|
|
422
|
+
tagName: element.tagName || '',
|
|
423
|
+
isFiltered: false
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
document.body.appendChild(overlay);
|
|
429
|
+
|
|
430
|
+
// Force repaint
|
|
431
|
+
await new Promise(resolve => requestAnimationFrame(resolve));
|
|
432
|
+
|
|
433
|
+
return {
|
|
434
|
+
overlayId: overlay.id, // Use the ID that was set earlier
|
|
435
|
+
elementCount: overlay.children.length,
|
|
436
|
+
markedElements,
|
|
437
|
+
debugInfo
|
|
438
|
+
};
|
|
439
|
+
}, {
|
|
440
|
+
elements: snapshotResult.elements,
|
|
441
|
+
clickable: Array.from(clickableElements),
|
|
442
|
+
filterDebugInfo: []
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
// Take screenshot
|
|
446
|
+
const screenshotBuffer = await page.screenshot({
|
|
447
|
+
fullPage: false,
|
|
448
|
+
type: 'png'
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
// Keep the overlay visible for 1 second before cleanup
|
|
452
|
+
await page.waitForTimeout(1000);
|
|
453
|
+
|
|
454
|
+
// Clean up
|
|
455
|
+
await page.evaluate((overlayId) => {
|
|
456
|
+
const overlay = document.getElementById(overlayId);
|
|
457
|
+
if (overlay) overlay.remove();
|
|
458
|
+
}, result.overlayId);
|
|
459
|
+
|
|
460
|
+
// Export element geometry if path is provided
|
|
461
|
+
if (exportPath && result.markedElements) {
|
|
462
|
+
try {
|
|
463
|
+
const pageUrl = page.url();
|
|
464
|
+
const timestamp = new Date().toISOString();
|
|
465
|
+
const exportData = {
|
|
466
|
+
timestamp,
|
|
467
|
+
url: pageUrl,
|
|
468
|
+
viewport: await page.viewportSize(),
|
|
469
|
+
elements: result.markedElements,
|
|
470
|
+
summary: {
|
|
471
|
+
totalElements: result.markedElements.length,
|
|
472
|
+
byType: result.markedElements.reduce((acc: any, el: any) => {
|
|
473
|
+
acc[el.type] = (acc[el.type] || 0) + 1;
|
|
474
|
+
return acc;
|
|
475
|
+
}, {}),
|
|
476
|
+
averageSize: {
|
|
477
|
+
width: result.markedElements.reduce((sum: number, el: any) => sum + el.width, 0) / result.markedElements.length,
|
|
478
|
+
height: result.markedElements.reduce((sum: number, el: any) => sum + el.height, 0) / result.markedElements.length
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
if (typeof writeFile !== 'undefined') {
|
|
484
|
+
await writeFile(exportPath, JSON.stringify(exportData, null, 2));
|
|
485
|
+
console.log(`Element geometry exported to: ${exportPath}`);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// Also save visibility debug info
|
|
489
|
+
if (result.debugInfo) {
|
|
490
|
+
const debugPath = exportPath.replace('.json', '-visibility-debug.json');
|
|
491
|
+
|
|
492
|
+
const debugData = {
|
|
493
|
+
timestamp,
|
|
494
|
+
url: pageUrl,
|
|
495
|
+
totalElements: result.debugInfo.length,
|
|
496
|
+
summary: {
|
|
497
|
+
visible: result.debugInfo.filter((d: any) => d.visibilityResult === 'visible').length,
|
|
498
|
+
partial: result.debugInfo.filter((d: any) => d.visibilityResult === 'partial').length,
|
|
499
|
+
hidden: result.debugInfo.filter((d: any) => d.visibilityResult === 'hidden').length
|
|
500
|
+
},
|
|
501
|
+
elements: result.debugInfo.sort((a: any, b: any) => {
|
|
502
|
+
// Sort by visibility status: hidden first, then partial, then visible
|
|
503
|
+
const order: any = { hidden: 0, partial: 1, visible: 2 };
|
|
504
|
+
return order[a.visibilityResult] - order[b.visibilityResult];
|
|
505
|
+
})
|
|
506
|
+
};
|
|
507
|
+
|
|
508
|
+
if (typeof writeFile !== 'undefined') {
|
|
509
|
+
await writeFile(debugPath, JSON.stringify(debugData, null, 2));
|
|
510
|
+
console.log(`Visibility debug info exported to: ${debugPath}`);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
} catch (error) {
|
|
514
|
+
console.error('Failed to export element geometry:', error);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
const base64Image = screenshotBuffer.toString('base64');
|
|
519
|
+
const dataUrl = `data:image/png;base64,${base64Image}`;
|
|
520
|
+
|
|
521
|
+
return {
|
|
522
|
+
text: `Visual webpage screenshot captured with ${result.elementCount} interactive elements marked`,
|
|
523
|
+
images: [dataUrl],
|
|
524
|
+
timing: {
|
|
525
|
+
total_time_ms: Date.now() - startTime,
|
|
526
|
+
screenshot_time_ms: Date.now() - startTime - 1100, // Approximate screenshot time (excluding 1s wait)
|
|
527
|
+
snapshot_time_ms: 0, // Will be filled by caller
|
|
528
|
+
coordinate_enrichment_time_ms: 0, // Will be filled by caller
|
|
529
|
+
visual_marking_time_ms: 1100, // Injection, rendering and 1s display time
|
|
530
|
+
injection_method: 'optimized',
|
|
531
|
+
elements_count: result.elementCount,
|
|
532
|
+
display_duration_ms: 1000, // Time the overlay is kept visible
|
|
533
|
+
parent_child_filter_time_ms: filterTime,
|
|
534
|
+
filtered_count: 0 // Filtering is done before this method is called
|
|
535
|
+
}
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
} catch (error) {
|
|
539
|
+
console.error('SOM screenshot injection error:', error);
|
|
540
|
+
throw error;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
export interface SnapshotElement {
|
|
2
|
+
ref: string;
|
|
3
|
+
role: string;
|
|
4
|
+
name: string;
|
|
5
|
+
coordinates?: {
|
|
6
|
+
x: number;
|
|
7
|
+
y: number;
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
};
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
checked?: boolean;
|
|
13
|
+
expanded?: boolean;
|
|
14
|
+
tagName?: string;
|
|
15
|
+
[key: string]: any;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
export interface SnapshotResult {
|
|
20
|
+
snapshot: string;
|
|
21
|
+
elements: Record<string, SnapshotElement>;
|
|
22
|
+
metadata: {
|
|
23
|
+
elementCount: number;
|
|
24
|
+
url: string;
|
|
25
|
+
timestamp: string;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface DetailedTiming {
|
|
30
|
+
total_time_ms: number;
|
|
31
|
+
navigation_time_ms?: number;
|
|
32
|
+
page_load_time_ms?: number;
|
|
33
|
+
stability_wait_time_ms?: number;
|
|
34
|
+
dom_content_loaded_time_ms?: number;
|
|
35
|
+
network_idle_time_ms?: number;
|
|
36
|
+
snapshot_time_ms?: number;
|
|
37
|
+
element_search_time_ms?: number;
|
|
38
|
+
action_execution_time_ms?: number;
|
|
39
|
+
screenshot_time_ms?: number;
|
|
40
|
+
coordinate_enrichment_time_ms?: number;
|
|
41
|
+
visual_marking_time_ms?: number;
|
|
42
|
+
aria_mapping_time_ms?: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface ActionResult {
|
|
46
|
+
success: boolean;
|
|
47
|
+
message: string;
|
|
48
|
+
snapshot?: string;
|
|
49
|
+
details?: Record<string, any>;
|
|
50
|
+
timing?: DetailedTiming;
|
|
51
|
+
newTabId?: string; // ID of newly opened tab if click opened a new tab
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface TabInfo {
|
|
55
|
+
tab_id: string;
|
|
56
|
+
title: string;
|
|
57
|
+
url: string;
|
|
58
|
+
is_current: boolean;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
import { StealthConfig } from './config-loader';
|
|
62
|
+
|
|
63
|
+
export interface BrowserToolkitConfig {
|
|
64
|
+
headless?: boolean;
|
|
65
|
+
userDataDir?: string;
|
|
66
|
+
stealth?: boolean | StealthConfig; // Support both legacy boolean and new object format
|
|
67
|
+
defaultStartUrl?: string;
|
|
68
|
+
navigationTimeout?: number;
|
|
69
|
+
networkIdleTimeout?: number;
|
|
70
|
+
screenshotTimeout?: number;
|
|
71
|
+
pageStabilityTimeout?: number;
|
|
72
|
+
useNativePlaywrightMapping?: boolean; // New option to control mapping implementation
|
|
73
|
+
connectOverCdp?: boolean; // Whether to connect to existing browser via CDP
|
|
74
|
+
cdpUrl?: string; // WebSocket endpoint URL for CDP connection
|
|
75
|
+
cdpKeepCurrentPage?: boolean; // When true, CDP mode will keep the current page instead of creating new one
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface ClickAction {
|
|
79
|
+
type: 'click';
|
|
80
|
+
ref: string;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface TypeAction {
|
|
84
|
+
type: 'type';
|
|
85
|
+
ref?: string; // Optional for backward compatibility
|
|
86
|
+
text?: string; // Optional for backward compatibility
|
|
87
|
+
inputs?: Array<{ ref: string; text: string }>; // New field for multiple inputs
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface SelectAction {
|
|
91
|
+
type: 'select';
|
|
92
|
+
ref: string;
|
|
93
|
+
value: string;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface ScrollAction {
|
|
97
|
+
type: 'scroll';
|
|
98
|
+
direction: 'up' | 'down';
|
|
99
|
+
amount: number;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface EnterAction {
|
|
103
|
+
type: 'enter';
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface MouseAction {
|
|
107
|
+
type: 'mouse_control';
|
|
108
|
+
control: 'click' | 'right_click' | 'dblclick';
|
|
109
|
+
x: number;
|
|
110
|
+
y: number;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface MouseDragAction {
|
|
114
|
+
type: 'mouse_drag';
|
|
115
|
+
from_ref: string;
|
|
116
|
+
to_ref: string;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export interface PressKeyAction {
|
|
120
|
+
type: 'press_key';
|
|
121
|
+
keys: string[];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export type BrowserAction = ClickAction | TypeAction | SelectAction | ScrollAction | EnterAction | MouseAction | MouseDragAction | PressKeyAction;
|
|
125
|
+
|
|
126
|
+
export interface VisualMarkResult {
|
|
127
|
+
text: string;
|
|
128
|
+
images: string[];
|
|
129
|
+
}
|
|
130
|
+
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"lib": ["ES2020", "DOM"],
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"rootDir": "./src",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"declaration": true,
|
|
13
|
+
"declarationMap": true,
|
|
14
|
+
"sourceMap": true,
|
|
15
|
+
"moduleResolution": "node",
|
|
16
|
+
"resolveJsonModule": true
|
|
17
|
+
},
|
|
18
|
+
"include": [
|
|
19
|
+
"src/**/*"
|
|
20
|
+
],
|
|
21
|
+
"exclude": [
|
|
22
|
+
"node_modules",
|
|
23
|
+
"dist",
|
|
24
|
+
"**/*.test.ts"
|
|
25
|
+
]
|
|
26
|
+
}
|