linuztx commited on
Commit
1ca9ada
·
2 Parent(s): 940225fc807769

merge dev to handle-code-running-session

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. README.md +33 -1
  2. agent.py +0 -12
  3. docker/run/fs/exe/run_A0.sh +2 -3
  4. docs/README.md +1 -0
  5. docs/connectivity.md +585 -0
  6. docs/development.md +5 -0
  7. docs/res/devguide_vid.png +3 -0
  8. initialize.py +1 -29
  9. prompts/memory.memories_query.sys.md +7 -0
  10. prompts/memory.memories_sum.sys.md +10 -2
  11. prompts/memory.recall_delay_msg.md +1 -0
  12. python/api/api_files_get.py +95 -0
  13. python/api/api_log_get.py +64 -0
  14. python/api/api_message.py +140 -0
  15. python/api/api_reset_chat.py +69 -0
  16. python/api/api_terminate_chat.py +68 -0
  17. python/api/poll.py +6 -1
  18. python/api/rfc.py +4 -0
  19. python/extensions/message_loop_end/_90_save_chat.py +6 -2
  20. python/extensions/message_loop_prompts_after/_50_recall_memories.py +25 -14
  21. python/extensions/message_loop_prompts_after/_91_recall_wait.py +23 -10
  22. python/extensions/monologue_start/_10_memory_init.py +13 -0
  23. python/helpers/fasta2a_server.py +23 -4
  24. python/helpers/mcp_server.py +5 -1
  25. python/helpers/persist_chat.py +8 -1
  26. python/helpers/settings.py +136 -38
  27. python/helpers/shell_local.py +26 -49
  28. python/helpers/shell_ssh.py +52 -33
  29. python/helpers/tty_session.py +28 -4
  30. python/tools/call_subordinate.py +1 -1
  31. python/tools/code_execution_tool.py +65 -98
  32. run_ui.py +6 -3
  33. tests/tty_test.py +0 -266
  34. webui/components/chat/speech/speech-store.js +2 -2
  35. webui/components/messages/action-buttons/simple-action-buttons.js +5 -0
  36. webui/components/settings/{external → a2a}/a2a-connection.html +12 -1
  37. webui/components/settings/external/api-examples.html +678 -0
  38. webui/components/settings/mcp/server/example.html +9 -0
  39. webui/index.html +5 -6
  40. webui/js/settings.js +2 -1
  41. webui/public/a2a_server.svg +1 -4
  42. webui/public/code_exec.svg +1 -0
  43. webui/public/external_api.svg +1 -0
  44. webui/vendor/ace-min/ace.js +0 -0
  45. webui/vendor/ace-min/ext-beautify [conflicted].js +8 -0
  46. webui/vendor/ace-min/ext-beautify.js +8 -0
  47. webui/vendor/ace-min/ext-code_lens.js +8 -0
  48. webui/vendor/ace-min/ext-command_bar.js +8 -0
  49. webui/vendor/ace-min/ext-diff.js +8 -0
  50. webui/vendor/ace-min/ext-elastic_tabstops_lite.js +8 -0
README.md CHANGED
@@ -12,6 +12,7 @@
12
  [Installation](./docs/installation.md) •
13
  [Development](./docs/development.md) •
14
  [Extensibility](./docs/extensibility.md) •
 
15
  [How to update](./docs/installation.md#how-to-update-agent-zero) •
16
  [Documentation](./docs/README.md) •
17
  [Usage](./docs/usage.md)
@@ -158,6 +159,9 @@ docker run -p 50001:80 agent0ai/agent-zero
158
  |-------|-------------|
159
  | [Installation](./docs/installation.md) | Installation, setup and configuration |
160
  | [Usage](./docs/usage.md) | Basic and advanced usage |
 
 
 
161
  | [Architecture](./docs/architecture.md) | System design and components |
162
  | [Contributing](./docs/contribution.md) | How to contribute |
163
  | [Troubleshooting](./docs/troubleshooting.md) | Common issues and their solutions |
@@ -165,6 +169,35 @@ docker run -p 50001:80 agent0ai/agent-zero
165
 
166
  ## 🎯 Changelog
167
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
 
169
  ### v0.9.2 - Kokoro TTS, Attachments
170
  [Release video](https://www.youtube.com/watch?v=sPot_CAX62I)
@@ -174,7 +207,6 @@ docker run -p 50001:80 agent0ai/agent-zero
174
  - Minor updates: log truncation, hyperlink targets, component examples, api cleanup
175
 
176
 
177
-
178
  ### v0.9.1 - LiteLLM, UI improvements
179
  [Release video](https://youtu.be/crwr0M4Spcg)
180
  - Langchain replaced with LiteLLM
 
12
  [Installation](./docs/installation.md) •
13
  [Development](./docs/development.md) •
14
  [Extensibility](./docs/extensibility.md) •
15
+ [Connectivity](./docs/connectivity.md) •
16
  [How to update](./docs/installation.md#how-to-update-agent-zero) •
17
  [Documentation](./docs/README.md) •
18
  [Usage](./docs/usage.md)
 
159
  |-------|-------------|
160
  | [Installation](./docs/installation.md) | Installation, setup and configuration |
161
  | [Usage](./docs/usage.md) | Basic and advanced usage |
162
+ | [Development](./docs/development.md) | Development and customization |
163
+ | [Extensibility](./docs/extensibility.md) | Extending Agent Zero |
164
+ | [Connectivity](./docs/connectivity.md) | External API endpoints, MCP server connections, A2A protocol |
165
  | [Architecture](./docs/architecture.md) | System design and components |
166
  | [Contributing](./docs/contribution.md) | How to contribute |
167
  | [Troubleshooting](./docs/troubleshooting.md) | Common issues and their solutions |
 
169
 
170
  ## 🎯 Changelog
171
 
172
+ ### v0.9.4 - Connectivity, UI
173
+ - External API endpoints
174
+ - Streamable HTTP MCP A0 server
175
+ - A2A (Agent to Agent) protocol - server+client
176
+ - New notifications system
177
+ - New local terminal interface for stability
178
+ - Rate limiter integration to models
179
+ - Delayed memory recall
180
+ - Smarter autoscrolling in UI
181
+ - Action buttons in messages
182
+ - Multiple API keys support
183
+ - Download streaming
184
+ - Tunnel URL QR code
185
+ - Internal fixes and optimizations
186
+
187
+ ### v0.9.3 - Subordinates, memory, providers Latest
188
+ [Release video](https://www.youtube.com/watch?v=-LfejFWL34k)
189
+ - Faster startup/restart
190
+ - Subordinate agents can have dedicated prompts, tools and system extensions
191
+ - Streamable HTTP MCP server support
192
+ - Memory loading enhanced by AI filter
193
+ - Memory AI consolidation when saving memories
194
+ - Auto memory system configuration in settings
195
+ - LLM providers available are set by providers.yaml configuration file
196
+ - Venice.ai LLM provider supported
197
+ - Initial agent message for user + as example for LLM
198
+ - Docker build support for local images
199
+ - File browser fix
200
+
201
 
202
  ### v0.9.2 - Kokoro TTS, Attachments
203
  [Release video](https://www.youtube.com/watch?v=sPot_CAX62I)
 
207
  - Minor updates: log truncation, hyperlink targets, component examples, api cleanup
208
 
209
 
 
210
  ### v0.9.1 - LiteLLM, UI improvements
211
  [Release video](https://youtu.be/crwr0M4Spcg)
212
  - Langchain replaced with LiteLLM
agent.py CHANGED
@@ -221,18 +221,6 @@ class AgentConfig:
221
  profile: str = ""
222
  memory_subdir: str = ""
223
  knowledge_subdirs: list[str] = field(default_factory=lambda: ["default", "custom"])
224
- code_exec_docker_enabled: bool = False
225
- code_exec_docker_name: str = "A0-dev"
226
- code_exec_docker_image: str = "agent0ai/agent-zero-run:development"
227
- code_exec_docker_ports: dict[str, int] = field(
228
- default_factory=lambda: {"22/tcp": 55022, "80/tcp": 55080}
229
- )
230
- code_exec_docker_volumes: dict[str, dict[str, str]] = field(
231
- default_factory=lambda: {
232
- files.get_base_dir(): {"bind": "/a0", "mode": "rw"},
233
- files.get_abs_path("work_dir"): {"bind": "/root", "mode": "rw"},
234
- }
235
- )
236
  code_exec_ssh_enabled: bool = True
237
  code_exec_ssh_addr: str = "localhost"
238
  code_exec_ssh_port: int = 55022
 
221
  profile: str = ""
222
  memory_subdir: str = ""
223
  knowledge_subdirs: list[str] = field(default_factory=lambda: ["default", "custom"])
 
 
 
 
 
 
 
 
 
 
 
 
224
  code_exec_ssh_enabled: bool = True
225
  code_exec_ssh_addr: str = "localhost"
226
  code_exec_ssh_port: int = 55022
docker/run/fs/exe/run_A0.sh CHANGED
@@ -10,9 +10,8 @@ echo "Starting A0..."
10
  exec python /a0/run_ui.py \
11
  --dockerized=true \
12
  --port=80 \
13
- --host="0.0.0.0" \
14
- --code_exec_docker_enabled=false \
15
- --code_exec_ssh_enabled=true \
16
  # --code_exec_ssh_addr="localhost" \
17
  # --code_exec_ssh_port=22 \
18
  # --code_exec_ssh_user="root" \
 
10
  exec python /a0/run_ui.py \
11
  --dockerized=true \
12
  --port=80 \
13
+ --host="0.0.0.0"
14
+ # --code_exec_ssh_enabled=true \
 
15
  # --code_exec_ssh_addr="localhost" \
16
  # --code_exec_ssh_port=22 \
17
  # --code_exec_ssh_user="root" \
docs/README.md CHANGED
@@ -6,6 +6,7 @@ To begin with Agent Zero, follow the links below for detailed guides on various
6
  - **[Usage Guide](usage.md):** Explore GUI features and usage scenarios.
7
  - **[Development](development.md):** Set up a development environment for Agent Zero.
8
  - **[Extensibility](extensibility.md):** Learn how to create custom extensions for Agent Zero.
 
9
  - **[Architecture Overview](architecture.md):** Understand the internal workings of the framework.
10
  - **[Contributing](contribution.md):** Learn how to contribute to the Agent Zero project.
11
  - **[Troubleshooting and FAQ](troubleshooting.md):** Find answers to common issues and questions.
 
6
  - **[Usage Guide](usage.md):** Explore GUI features and usage scenarios.
7
  - **[Development](development.md):** Set up a development environment for Agent Zero.
8
  - **[Extensibility](extensibility.md):** Learn how to create custom extensions for Agent Zero.
9
+ - **[Connectivity](connectivity.md):** Learn how to connect to Agent Zero from other applications.
10
  - **[Architecture Overview](architecture.md):** Understand the internal workings of the framework.
11
  - **[Contributing](contribution.md):** Learn how to contribute to the Agent Zero project.
12
  - **[Troubleshooting and FAQ](troubleshooting.md):** Find answers to common issues and questions.
docs/connectivity.md ADDED
@@ -0,0 +1,585 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Agent Zero Connectivity Guide
2
+
3
+ This guide covers the different ways to connect to Agent Zero from external applications, including using the External API, connecting as an MCP client, and enabling agent-to-agent communication.
4
+
5
+ **Note:** You can find your specific URLs and API tokens in your Agent Zero instance under `Settings > External Services`.
6
+
7
+ ### API Token Information
8
+
9
+ The API token is automatically generated from your username and password. This same token is used for External API endpoints, MCP server connections, and A2A communication. The token will change if you update your credentials.
10
+
11
+ ---
12
+
13
+ ## External API Endpoints
14
+
15
+ Agent Zero provides external API endpoints for integration with other applications. These endpoints use API key authentication and support text messages and file attachments.
16
+
17
+ ### `POST /api_message`
18
+
19
+ Send messages to Agent Zero and receive responses. Supports text messages, file attachments, and conversation continuity.
20
+
21
+ ### API Reference
22
+
23
+ **Parameters:**
24
+ * `context_id` (string, optional): Existing chat context ID
25
+ * `message` (string, required): The message to send
26
+ * `attachments` (array, optional): Array of `{filename, base64}` objects
27
+ * `lifetime_hours` (number, optional): Chat lifetime in hours (default: 24)
28
+
29
+ **Headers:**
30
+ * `X-API-KEY` (required)
31
+ * `Content-Type: application/json`
32
+
33
+ ### JavaScript Examples
34
+
35
+ #### Basic Usage Example
36
+
37
+ ```javascript
38
+ // Basic message example
39
+ async function sendMessage() {
40
+ try {
41
+ const response = await fetch('YOUR_AGENT_ZERO_URL/api_message', {
42
+ method: 'POST',
43
+ headers: {
44
+ 'Content-Type': 'application/json',
45
+ 'X-API-KEY': 'YOUR_API_KEY'
46
+ },
47
+ body: JSON.stringify({
48
+ message: "Hello, how can you help me?",
49
+ lifetime_hours: 24
50
+ })
51
+ });
52
+
53
+ const data = await response.json();
54
+
55
+ if (response.ok) {
56
+ console.log('✅ Success!');
57
+ console.log('Response:', data.response);
58
+ console.log('Context ID:', data.context_id);
59
+ return data;
60
+ } else {
61
+ console.error('❌ Error:', data.error);
62
+ return null;
63
+ }
64
+ } catch (error) {
65
+ console.error('❌ Request failed:', error);
66
+ return null;
67
+ }
68
+ }
69
+
70
+ // Call the function
71
+ sendMessage().then(result => {
72
+ if (result) {
73
+ console.log('Message sent successfully!');
74
+ }
75
+ });
76
+ ```
77
+
78
+ #### Conversation Continuation Example
79
+
80
+ ```javascript
81
+ // Continue conversation example
82
+ async function continueConversation(contextId) {
83
+ try {
84
+ const response = await fetch('YOUR_AGENT_ZERO_URL/api_message', {
85
+ method: 'POST',
86
+ headers: {
87
+ 'Content-Type': 'application/json',
88
+ 'X-API-KEY': 'YOUR_API_KEY'
89
+ },
90
+ body: JSON.stringify({
91
+ context_id: contextId,
92
+ message: "Can you tell me more about that?",
93
+ lifetime_hours: 24
94
+ })
95
+ });
96
+
97
+ const data = await response.json();
98
+
99
+ if (response.ok) {
100
+ console.log('✅ Continuation Success!');
101
+ console.log('Response:', data.response);
102
+ return data;
103
+ } else {
104
+ console.error('❌ Error:', data.error);
105
+ return null;
106
+ }
107
+ } catch (error) {
108
+ console.error('❌ Request failed:', error);
109
+ return null;
110
+ }
111
+ }
112
+
113
+ // Example: First send a message, then continue the conversation
114
+ async function fullConversationExample() {
115
+ const firstResult = await sendMessage();
116
+ if (firstResult && firstResult.context_id) {
117
+ await continueConversation(firstResult.context_id);
118
+ }
119
+ }
120
+
121
+ fullConversationExample();
122
+ ```
123
+
124
+ #### File Attachment Example
125
+
126
+ ```javascript
127
+ // File attachment example
128
+ async function sendWithAttachment() {
129
+ try {
130
+ // Example with text content (convert to base64)
131
+ const textContent = "Hello World from attachment!";
132
+ const base64Content = btoa(textContent);
133
+
134
+ const response = await fetch('YOUR_AGENT_ZERO_URL/api_message', {
135
+ method: 'POST',
136
+ headers: {
137
+ 'Content-Type': 'application/json',
138
+ 'X-API-KEY': 'YOUR_API_KEY'
139
+ },
140
+ body: JSON.stringify({
141
+ message: "Please analyze this file:",
142
+ attachments: [
143
+ {
144
+ filename: "document.txt",
145
+ base64: base64Content
146
+ }
147
+ ],
148
+ lifetime_hours: 12
149
+ })
150
+ });
151
+
152
+ const data = await response.json();
153
+
154
+ if (response.ok) {
155
+ console.log('✅ File sent successfully!');
156
+ console.log('Response:', data.response);
157
+ return data;
158
+ } else {
159
+ console.error('❌ Error:', data.error);
160
+ return null;
161
+ }
162
+ } catch (error) {
163
+ console.error('❌ Request failed:', error);
164
+ return null;
165
+ }
166
+ }
167
+
168
+ // Call the function
169
+ sendWithAttachment();
170
+ ```
171
+
172
+ ---
173
+
174
+ ## `GET/POST /api_log_get`
175
+
176
+ Retrieve log data by context ID, limited to a specified number of entries from the newest.
177
+
178
+ ### API Reference
179
+
180
+ **Parameters:**
181
+ * `context_id` (string, required): Context ID to get logs from
182
+ * `length` (integer, optional): Number of log items to return from newest (default: 100)
183
+
184
+ **Headers:**
185
+ * `X-API-KEY` (required)
186
+ * `Content-Type: application/json` (for POST)
187
+
188
+ ### JavaScript Examples
189
+
190
+ #### GET Request Example
191
+
192
+ ```javascript
193
+ // Get logs using GET request
194
+ async function getLogsGET(contextId, length = 50) {
195
+ try {
196
+ const params = new URLSearchParams({
197
+ context_id: contextId,
198
+ length: length.toString()
199
+ });
200
+
201
+ const response = await fetch('YOUR_AGENT_ZERO_URL/api_log_get?' + params, {
202
+ method: 'GET',
203
+ headers: {
204
+ 'X-API-KEY': 'YOUR_API_KEY'
205
+ }
206
+ });
207
+
208
+ const data = await response.json();
209
+
210
+ if (response.ok) {
211
+ console.log('✅ Logs retrieved successfully!');
212
+ console.log('Total items:', data.log.total_items);
213
+ console.log('Returned items:', data.log.returned_items);
214
+ console.log('Log items:', data.log.items);
215
+ return data;
216
+ } else {
217
+ console.error('❌ Error:', data.error);
218
+ return null;
219
+ }
220
+ } catch (error) {
221
+ console.error('❌ Request failed:', error);
222
+ return null;
223
+ }
224
+ }
225
+
226
+ // Example usage
227
+ getLogsGET('ctx_abc123', 20);
228
+ ```
229
+
230
+ #### POST Request Example
231
+
232
+ ```javascript
233
+ // Get logs using POST request
234
+ async function getLogsPOST(contextId, length = 50) {
235
+ try {
236
+ const response = await fetch('YOUR_AGENT_ZERO_URL/api_log_get', {
237
+ method: 'POST',
238
+ headers: {
239
+ 'Content-Type': 'application/json',
240
+ 'X-API-KEY': 'YOUR_API_KEY'
241
+ },
242
+ body: JSON.stringify({
243
+ context_id: contextId,
244
+ length: length
245
+ })
246
+ });
247
+
248
+ const data = await response.json();
249
+
250
+ if (response.ok) {
251
+ console.log('✅ Logs retrieved successfully!');
252
+ console.log('Context ID:', data.context_id);
253
+ console.log('Log GUID:', data.log.guid);
254
+ console.log('Total items:', data.log.total_items);
255
+ console.log('Returned items:', data.log.returned_items);
256
+ console.log('Start position:', data.log.start_position);
257
+ console.log('Progress:', data.log.progress);
258
+ console.log('Log items:', data.log.items);
259
+ return data;
260
+ } else {
261
+ console.error('❌ Error:', data.error);
262
+ return null;
263
+ }
264
+ } catch (error) {
265
+ console.error('❌ Request failed:', error);
266
+ return null;
267
+ }
268
+ }
269
+
270
+ // Example usage - get latest 10 log entries
271
+ getLogsPOST('ctx_abc123', 10);
272
+ ```
273
+
274
+ ---
275
+
276
+ ## `POST /api_terminate_chat`
277
+
278
+ Terminate and remove a chat context to free up resources. Similar to the MCP `finish_chat` function.
279
+
280
+ ### API Reference
281
+
282
+ **Parameters:**
283
+ * `context_id` (string, required): Context ID of the chat to terminate
284
+
285
+ **Headers:**
286
+ * `X-API-KEY` (required)
287
+ * `Content-Type: application/json`
288
+
289
+ ### JavaScript Examples
290
+
291
+ #### Basic Termination Examples
292
+
293
+ ```javascript
294
+ // Basic terminate chat function
295
+ async function terminateChat(contextId) {
296
+ try {
297
+ const response = await fetch('YOUR_AGENT_ZERO_URL/api_terminate_chat', {
298
+ method: 'POST',
299
+ headers: {
300
+ 'Content-Type': 'application/json',
301
+ 'X-API-KEY': 'YOUR_API_KEY'
302
+ },
303
+ body: JSON.stringify({
304
+ context_id: contextId
305
+ })
306
+ });
307
+
308
+ const data = await response.json();
309
+
310
+ if (response.ok) {
311
+ console.log('✅ Chat deleted successfully!');
312
+ console.log('Message:', data.message);
313
+ return data;
314
+ } else {
315
+ console.error('❌ Error:', data.error);
316
+ return null;
317
+ }
318
+ } catch (error) {
319
+ console.error('❌ Request failed:', error);
320
+ return null;
321
+ }
322
+ }
323
+
324
+ // Example 1: Terminate a specific chat
325
+ terminateChat('ctx_abc123');
326
+
327
+ // Example 2: Complete workflow - send message, then terminate
328
+ async function simpleWorkflow() {
329
+ // Send a message
330
+ const result = await sendMessage();
331
+
332
+ if (result && result.context_id) {
333
+ console.log('Chat created:', result.context_id);
334
+
335
+ // Do some work with the chat...
336
+ // await continueConversation(result.context_id);
337
+
338
+ // Clean up when done
339
+ await terminateChat(result.context_id);
340
+ console.log('Chat cleaned up');
341
+ }
342
+ }
343
+
344
+ // Run the workflow
345
+ simpleWorkflow();
346
+ ```
347
+
348
+ ---
349
+
350
+ ## `POST /api_reset_chat`
351
+
352
+ Reset a chat context to clear conversation history while keeping the `context_id` alive for continued use.
353
+
354
+ ### API Reference
355
+
356
+ **Parameters:**
357
+ * `context_id` (string, required): Context ID of the chat to reset
358
+
359
+ **Headers:**
360
+ * `X-API-KEY` (required)
361
+ * `Content-Type: application/json`
362
+
363
+ ### JavaScript Examples
364
+
365
+ #### Basic Reset Examples
366
+
367
+ ```javascript
368
+ // Basic reset chat function
369
+ async function resetChat(contextId) {
370
+ try {
371
+ const response = await fetch('YOUR_AGENT_ZERO_URL/api_reset_chat', {
372
+ method: 'POST',
373
+ headers: {
374
+ 'Content-Type': 'application/json',
375
+ 'X-API-KEY': 'YOUR_API_KEY'
376
+ },
377
+ body: JSON.stringify({
378
+ context_id: contextId
379
+ })
380
+ });
381
+
382
+ const data = await response.json();
383
+
384
+ if (response.ok) {
385
+ console.log('✅ Chat reset successfully!');
386
+ console.log('Message:', data.message);
387
+ console.log('Context ID:', data.context_id);
388
+ return data;
389
+ } else {
390
+ console.error('❌ Error:', data.error);
391
+ return null;
392
+ }
393
+ } catch (error) {
394
+ console.error('❌ Request failed:', error);
395
+ return null;
396
+ }
397
+ }
398
+
399
+ // Example 1: Reset a specific chat
400
+ resetChat('ctx_abc123');
401
+
402
+ // Example 2: Reset and continue conversation
403
+ async function resetAndContinue() {
404
+ const contextId = 'ctx_abc123';
405
+
406
+ // Reset the chat to clear history
407
+ const resetResult = await resetChat(contextId);
408
+
409
+ if (resetResult) {
410
+ console.log('Chat reset, starting fresh conversation...');
411
+
412
+ // Continue with same context_id but fresh history
413
+ const response = await fetch('YOUR_AGENT_ZERO_URL/api_message', {
414
+ method: 'POST',
415
+ headers: {
416
+ 'Content-Type': 'application/json',
417
+ 'X-API-KEY': 'YOUR_API_KEY'
418
+ },
419
+ body: JSON.stringify({
420
+ context_id: contextId, // Same context ID
421
+ message: "Hello, this is a fresh start!",
422
+ lifetime_hours: 24
423
+ })
424
+ });
425
+
426
+ const data = await response.json();
427
+ console.log('New conversation started:', data.response);
428
+ }
429
+ }
430
+
431
+ // Run the example
432
+ resetAndContinue();
433
+ ```
434
+
435
+ ---
436
+
437
+ ## `POST /api_files_get`
438
+
439
+ Retrieve file contents by paths, returning files as base64 encoded data. Useful for retrieving uploaded attachments.
440
+
441
+ ### API Reference
442
+
443
+ **Parameters:**
444
+ * `paths` (array, required): Array of file paths to retrieve (e.g., `["/a0/tmp/uploads/file.txt"]`)
445
+
446
+ **Headers:**
447
+ * `X-API-KEY` (required)
448
+ * `Content-Type: application/json`
449
+
450
+ ### JavaScript Examples
451
+
452
+ #### File Retrieval Examples
453
+
454
+ ```javascript
455
+ // Basic file retrieval
456
+ async function getFiles(filePaths) {
457
+ try {
458
+ const response = await fetch('YOUR_AGENT_ZERO_URL/api_files_get', {
459
+ method: 'POST',
460
+ headers: {
461
+ 'Content-Type': 'application/json',
462
+ 'X-API-KEY': 'YOUR_API_KEY'
463
+ },
464
+ body: JSON.stringify({
465
+ paths: filePaths
466
+ })
467
+ });
468
+
469
+ const data = await response.json();
470
+
471
+ if (response.ok) {
472
+ console.log('✅ Files retrieved successfully!');
473
+ console.log('Retrieved files:', Object.keys(data));
474
+
475
+ // Convert base64 back to text for display
476
+ for (const [filename, base64Content] of Object.entries(data)) {
477
+ try {
478
+ const textContent = atob(base64Content);
479
+ console.log(`${filename}: ${textContent.substring(0, 100)}...`);
480
+ } catch (e) {
481
+ console.log(`${filename}: Binary file (${base64Content.length} chars)`);
482
+ }
483
+ }
484
+
485
+ return data;
486
+ } else {
487
+ console.error('❌ Error:', data.error);
488
+ return null;
489
+ }
490
+ } catch (error) {
491
+ console.error('❌ Request failed:', error);
492
+ return null;
493
+ }
494
+ }
495
+
496
+ // Example 1: Get specific files
497
+ const filePaths = [
498
+ "/a0/tmp/uploads/document.txt",
499
+ "/a0/tmp/uploads/data.json"
500
+ ];
501
+ getFiles(filePaths);
502
+
503
+ // Example 2: Complete attachment workflow
504
+ async function attachmentWorkflow() {
505
+ // Step 1: Send message with attachments
506
+ const messageResponse = await fetch('YOUR_AGENT_ZERO_URL/api_message', {
507
+ method: 'POST',
508
+ headers: {
509
+ 'Content-Type': 'application/json',
510
+ 'X-API-KEY': 'YOUR_API_KEY'
511
+ },
512
+ body: JSON.stringify({
513
+ message: "Please analyze this file",
514
+ attachments: [{
515
+ filename: "test.txt",
516
+ base64: btoa("Hello, this is test content!")
517
+ }],
518
+ lifetime_hours: 1
519
+ })
520
+ });
521
+
522
+ if (messageResponse.ok) {
523
+ console.log('Message sent with attachment');
524
+
525
+ // Step 2: Retrieve the uploaded file
526
+ const retrievedFiles = await getFiles(["/a0/tmp/uploads/test.txt"]);
527
+
528
+ if (retrievedFiles && retrievedFiles["test.txt"]) {
529
+ const originalContent = atob(retrievedFiles["test.txt"]);
530
+ console.log('Retrieved content:', originalContent);
531
+ }
532
+ }
533
+ }
534
+
535
+ // Run the complete workflow
536
+ attachmentWorkflow();
537
+ ```
538
+
539
+ ---
540
+
541
+ ## MCP Server Connectivity
542
+
543
+ Agent Zero includes an MCP Server that allows other MCP-compatible clients to connect to it. The server runs on the same URL and port as the Web UI.
544
+
545
+ It provides two endpoint types:
546
+ - **SSE (`/mcp/sse`):** For clients that support Server-Sent Events.
547
+ - **Streamable HTTP (`/mcp/http/`):** For clients that use streamable HTTP requests.
548
+
549
+ ### Example MCP Server Configuration
550
+
551
+ Below is an example of a `mcp.json` configuration file that a client could use to connect to the Agent Zero MCP server.
552
+
553
+ **Note:** You can find your personalized connection URLs under `Settings > MCP Server > MCP Server`.
554
+
555
+ ```json
556
+ {
557
+ "mcpServers":
558
+ {
559
+ "agent-zero": {
560
+ "type": "sse",
561
+ "url": "YOUR_AGENT_ZERO_URL/mcp/t-YOUR_API_TOKEN/sse"
562
+ },
563
+ "agent-zero-http": {
564
+ "type": "streamable-http",
565
+ "url": "YOUR_AGENT_ZERO_URL/mcp/t-YOUR_API_TOKEN/http/"
566
+ }
567
+ }
568
+ }
569
+ ```
570
+
571
+ ---
572
+
573
+ ## A2A (Agent-to-Agent) Connectivity
574
+
575
+ Agent Zero's A2A Server enables communication with other agents using the FastA2A protocol. Other agents can connect to your instance using the connection URL.
576
+
577
+ ### A2A Connection URL
578
+
579
+ To connect another agent to your Agent Zero instance, use the following URL format.
580
+
581
+ **Note:** You can find your specific A2A connection URL under `Settings > External Services > A2A Connection`.
582
+
583
+ ```
584
+ YOUR_AGENT_ZERO_URL/a2a/t-YOUR_API_TOKEN
585
+ ```
docs/development.md CHANGED
@@ -1,6 +1,11 @@
1
  # Development manual for Agent Zero
2
  This guide will show you how to setup a local development environment for Agent Zero in a VS Code compatible IDE, including proper debugger.
3
 
 
 
 
 
 
4
  > [!WARNING]
5
  > This guide is for developers and contributors. It assumes you have a basic understanding of how to use Git/GitHub, Docker, IDEs and Python.
6
 
 
1
  # Development manual for Agent Zero
2
  This guide will show you how to setup a local development environment for Agent Zero in a VS Code compatible IDE, including proper debugger.
3
 
4
+
5
+ [![Tutorial video](./res/devguide_vid.png)](https://www.youtube.com/watch?v=KE39P4qBjDk)
6
+
7
+
8
+
9
  > [!WARNING]
10
  > This guide is for developers and contributors. It assumes you have a basic understanding of how to use Git/GitHub, Docker, IDEs and Python.
11
 
docs/res/devguide_vid.png ADDED

Git LFS Details

  • SHA256: fc4766f5cba65e486acd1726c7f2d48bd6a493b66388f258d9313f3c53736bdb
  • Pointer size: 132 Bytes
  • Size of remote file: 1.16 MB
initialize.py CHANGED
@@ -79,19 +79,7 @@ def initialize_agent():
79
  memory_subdir=current_settings["agent_memory_subdir"],
80
  knowledge_subdirs=[current_settings["agent_knowledge_subdir"], "default"],
81
  mcp_servers=current_settings["mcp_servers"],
82
- code_exec_docker_enabled=False,
83
- # code_exec_docker_name = "A0-dev",
84
- # code_exec_docker_image = "agent0ai/agent-zero:development",
85
- # code_exec_docker_ports = { "22/tcp": 55022, "80/tcp": 55080 }
86
- # code_exec_docker_volumes = {
87
- # files.get_base_dir(): {"bind": "/a0", "mode": "rw"},
88
- # files.get_abs_path("work_dir"): {"bind": "/root", "mode": "rw"},
89
- # },
90
- # code_exec_ssh_enabled = True,
91
- # code_exec_ssh_addr = "localhost",
92
- # code_exec_ssh_port = 55022,
93
- # code_exec_ssh_user = "root",
94
- # code_exec_ssh_pass = "",
95
  # additional = {},
96
  )
97
 
@@ -176,19 +164,3 @@ def _set_runtime_config(config: AgentConfig, set: settings.Settings):
176
  for key, value in ssh_conf.items():
177
  if hasattr(config, key):
178
  setattr(config, key, value)
179
-
180
- # if config.code_exec_docker_enabled:
181
- # config.code_exec_docker_ports["22/tcp"] = ssh_conf["code_exec_ssh_port"]
182
- # config.code_exec_docker_ports["80/tcp"] = ssh_conf["code_exec_http_port"]
183
- # config.code_exec_docker_name = f"{config.code_exec_docker_name}-{ssh_conf['code_exec_ssh_port']}-{ssh_conf['code_exec_http_port']}"
184
-
185
- # dman = docker.DockerContainerManager(
186
- # logger=log.Log(),
187
- # name=config.code_exec_docker_name,
188
- # image=config.code_exec_docker_image,
189
- # ports=config.code_exec_docker_ports,
190
- # volumes=config.code_exec_docker_volumes,
191
- # )
192
- # dman.start_container()
193
-
194
- # config.code_exec_ssh_pass = asyncio.run(rfc_exchange.get_root_password())
 
79
  memory_subdir=current_settings["agent_memory_subdir"],
80
  knowledge_subdirs=[current_settings["agent_knowledge_subdir"], "default"],
81
  mcp_servers=current_settings["mcp_servers"],
82
+ # code_exec params get initialized in _set_runtime_config
 
 
 
 
 
 
 
 
 
 
 
 
83
  # additional = {},
84
  )
85
 
 
164
  for key, value in ssh_conf.items():
165
  if hasattr(config, key):
166
  setattr(config, key, value)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
prompts/memory.memories_query.sys.md CHANGED
@@ -7,11 +7,18 @@
7
  - The response format is a plain text string containing the query
8
  - No other text, no formatting
9
 
 
 
 
10
  # Rules
11
  - Only focus on facts and events, ignore common conversation patterns, greeting etc.
12
  - Ignore AI thoughts and behavior
13
  - Focus on USER MESSAGE if provided, use HISTORY for context
14
 
 
 
 
 
15
  # Example
16
  ```json
17
  USER: "Write a song about my dog"
 
7
  - The response format is a plain text string containing the query
8
  - No other text, no formatting
9
 
10
+ # No query
11
+ - If the conversation is not relevant for memory search, return a single dash (-)
12
+
13
  # Rules
14
  - Only focus on facts and events, ignore common conversation patterns, greeting etc.
15
  - Ignore AI thoughts and behavior
16
  - Focus on USER MESSAGE if provided, use HISTORY for context
17
 
18
+ # Ignored:
19
+ For the following topics, no query is needed and return a single dash (-):
20
+ - Greeting
21
+
22
  # Example
23
  ```json
24
  USER: "Write a song about my dog"
prompts/memory.memories_sum.sys.md CHANGED
@@ -36,10 +36,18 @@
36
  > AsyncRaceError in primary_modules.py was fixed by adding a thread lock on line 123 (important event with details for context)
37
  > Local SQL database was created, server is running on port 3306 (important event with details for context)
38
 
39
- # Wrong examples with (explanation of error), never output memories like these
40
  > Dog Information (no useful facts)
41
  > User greeted with 'hi' (just conversation, not useful in the future )
42
  > Respond with a warm greeting and invite further conversation (do not memorize AI's instructions or thoughts)
43
  > User's name (details missing, not useful)
44
  > Today is Monday (just date, no value in this information)
45
- > Market inquiry (just a topic without detail)
 
 
 
 
 
 
 
 
 
36
  > AsyncRaceError in primary_modules.py was fixed by adding a thread lock on line 123 (important event with details for context)
37
  > Local SQL database was created, server is running on port 3306 (important event with details for context)
38
 
39
+ # WRONG examples with (explanation of error), never output memories like these
40
  > Dog Information (no useful facts)
41
  > User greeted with 'hi' (just conversation, not useful in the future )
42
  > Respond with a warm greeting and invite further conversation (do not memorize AI's instructions or thoughts)
43
  > User's name (details missing, not useful)
44
  > Today is Monday (just date, no value in this information)
45
+ > Market inquiry (just a topic without detail)
46
+ > RAM Status (just a topic without detail)
47
+ > The user requested current RAM and CPU status. (No exact facts to memorize)
48
+
49
+
50
+ # Further WRONG examples
51
+ - Hello
52
+ - The user requested current RAM and CPU status.
53
+ -
prompts/memory.recall_delay_msg.md ADDED
@@ -0,0 +1 @@
 
 
1
+ Info: auto memory recall set to delayed mode. auto memories will be available after next message. if manual memory check is required use memory tools.
python/api/api_files_get.py ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import base64
2
+ import os
3
+ from python.helpers.api import ApiHandler, Request, Response
4
+ from python.helpers import files
5
+ from python.helpers.print_style import PrintStyle
6
+ import json
7
+
8
+
9
+ class ApiFilesGet(ApiHandler):
10
+ @classmethod
11
+ def requires_auth(cls) -> bool:
12
+ return False
13
+
14
+ @classmethod
15
+ def requires_csrf(cls) -> bool:
16
+ return False
17
+
18
+ @classmethod
19
+ def requires_api_key(cls) -> bool:
20
+ return True
21
+
22
+ @classmethod
23
+ def get_methods(cls) -> list[str]:
24
+ return ["POST"]
25
+
26
+ async def process(self, input: dict, request: Request) -> dict | Response:
27
+ try:
28
+ # Get paths from input
29
+ paths = input.get("paths", [])
30
+
31
+ if not paths:
32
+ return Response(
33
+ '{"error": "paths array is required"}',
34
+ status=400,
35
+ mimetype="application/json"
36
+ )
37
+
38
+ if not isinstance(paths, list):
39
+ return Response(
40
+ '{"error": "paths must be an array"}',
41
+ status=400,
42
+ mimetype="application/json"
43
+ )
44
+
45
+ result = {}
46
+
47
+ for path in paths:
48
+ try:
49
+ # Convert internal paths to external paths
50
+ if path.startswith("/a0/tmp/uploads/"):
51
+ # Internal path - convert to external
52
+ filename = path.replace("/a0/tmp/uploads/", "")
53
+ external_path = files.get_abs_path("tmp/uploads", filename)
54
+ filename = os.path.basename(external_path)
55
+ elif path.startswith("/a0/"):
56
+ # Other internal Agent Zero paths
57
+ relative_path = path.replace("/a0/", "")
58
+ external_path = files.get_abs_path(relative_path)
59
+ filename = os.path.basename(external_path)
60
+ else:
61
+ # Assume it's already an external/absolute path
62
+ external_path = path
63
+ filename = os.path.basename(path)
64
+
65
+ # Check if file exists
66
+ if not os.path.exists(external_path):
67
+ PrintStyle.warning(f"File not found: {path}")
68
+ continue
69
+
70
+ # Read and encode file
71
+ with open(external_path, "rb") as f:
72
+ file_content = f.read()
73
+ base64_content = base64.b64encode(file_content).decode('utf-8')
74
+ result[filename] = base64_content
75
+
76
+ PrintStyle().print(f"Retrieved file: {filename} ({len(file_content)} bytes)")
77
+
78
+ except Exception as e:
79
+ PrintStyle.error(f"Failed to read file {path}: {str(e)}")
80
+ continue
81
+
82
+ # Log the retrieval
83
+ PrintStyle(
84
+ background_color="#2ECC71", font_color="white", bold=True, padding=True
85
+ ).print(f"API Files retrieved: {len(result)} files")
86
+
87
+ return result
88
+
89
+ except Exception as e:
90
+ PrintStyle.error(f"API files get error: {str(e)}")
91
+ return Response(
92
+ json.dumps({"error": f"Internal server error: {str(e)}"}),
93
+ status=500,
94
+ mimetype="application/json"
95
+ )
python/api/api_log_get.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from agent import AgentContext
2
+ from python.helpers.api import ApiHandler, Request, Response
3
+
4
+
5
+ class ApiLogGet(ApiHandler):
6
+ @classmethod
7
+ def get_methods(cls) -> list[str]:
8
+ return ["GET", "POST"]
9
+
10
+ @classmethod
11
+ def requires_auth(cls) -> bool:
12
+ return False # No web auth required
13
+
14
+ @classmethod
15
+ def requires_csrf(cls) -> bool:
16
+ return False # No CSRF required
17
+
18
+ @classmethod
19
+ def requires_api_key(cls) -> bool:
20
+ return True # Require API key
21
+
22
+ async def process(self, input: dict, request: Request) -> dict | Response:
23
+ # Extract parameters (support both query params for GET and body for POST)
24
+ if request.method == "GET":
25
+ context_id = request.args.get("context_id", "")
26
+ length = int(request.args.get("length", 100))
27
+ else:
28
+ context_id = input.get("context_id", "")
29
+ length = input.get("length", 100)
30
+
31
+ if not context_id:
32
+ return Response('{"error": "context_id is required"}', status=400, mimetype="application/json")
33
+
34
+ # Get context
35
+ context = AgentContext.get(context_id)
36
+ if not context:
37
+ return Response('{"error": "Context not found"}', status=404, mimetype="application/json")
38
+
39
+ try:
40
+ # Get total number of log items
41
+ total_items = len(context.log.logs)
42
+
43
+ # Calculate start position (from newest, so we work backwards)
44
+ start_pos = max(0, total_items - length)
45
+
46
+ # Get log items from the calculated start position
47
+ log_items = context.log.output(start=start_pos)
48
+
49
+ # Return log data with metadata
50
+ return {
51
+ "context_id": context_id,
52
+ "log": {
53
+ "guid": context.log.guid,
54
+ "total_items": total_items,
55
+ "returned_items": len(log_items),
56
+ "start_position": start_pos,
57
+ "progress": context.log.progress,
58
+ "progress_active": context.log.progress_active,
59
+ "items": log_items
60
+ }
61
+ }
62
+
63
+ except Exception as e:
64
+ return Response(f'{{"error": "{str(e)}"}}', status=500, mimetype="application/json")
python/api/api_message.py ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import base64
2
+ import os
3
+ from datetime import datetime, timedelta
4
+ from agent import AgentContext, UserMessage, AgentContextType
5
+ from python.helpers.api import ApiHandler, Request, Response
6
+ from python.helpers import files
7
+ from python.helpers.print_style import PrintStyle
8
+ from werkzeug.utils import secure_filename
9
+ from initialize import initialize_agent
10
+ import threading
11
+
12
+
13
+ class ApiMessage(ApiHandler):
14
+ # Track chat lifetimes for cleanup
15
+ _chat_lifetimes = {}
16
+ _cleanup_lock = threading.Lock()
17
+
18
+ @classmethod
19
+ def requires_auth(cls) -> bool:
20
+ return False # No web auth required
21
+
22
+ @classmethod
23
+ def requires_csrf(cls) -> bool:
24
+ return False # No CSRF required
25
+
26
+ @classmethod
27
+ def requires_api_key(cls) -> bool:
28
+ return True # Require API key
29
+
30
+ async def process(self, input: dict, request: Request) -> dict | Response:
31
+ # Extract parameters
32
+ context_id = input.get("context_id", "")
33
+ message = input.get("message", "")
34
+ attachments = input.get("attachments", [])
35
+ lifetime_hours = input.get("lifetime_hours", 24) # Default 24 hours
36
+
37
+ if not message:
38
+ return Response('{"error": "Message is required"}', status=400, mimetype="application/json")
39
+
40
+ # Handle attachments (base64 encoded)
41
+ attachment_paths = []
42
+ if attachments:
43
+ upload_folder_int = "/a0/tmp/uploads"
44
+ upload_folder_ext = files.get_abs_path("tmp/uploads")
45
+ os.makedirs(upload_folder_ext, exist_ok=True)
46
+
47
+ for attachment in attachments:
48
+ if not isinstance(attachment, dict) or "filename" not in attachment or "base64" not in attachment:
49
+ continue
50
+
51
+ try:
52
+ filename = secure_filename(attachment["filename"])
53
+ if not filename:
54
+ continue
55
+
56
+ # Decode base64 content
57
+ file_content = base64.b64decode(attachment["base64"])
58
+
59
+ # Save to temp file
60
+ save_path = os.path.join(upload_folder_ext, filename)
61
+ with open(save_path, "wb") as f:
62
+ f.write(file_content)
63
+
64
+ attachment_paths.append(os.path.join(upload_folder_int, filename))
65
+ except Exception as e:
66
+ PrintStyle.error(f"Failed to process attachment {attachment.get('filename', 'unknown')}: {e}")
67
+ continue
68
+
69
+ # Get or create context
70
+ if context_id:
71
+ context = AgentContext.get(context_id)
72
+ if not context:
73
+ return Response('{"error": "Context not found"}', status=404, mimetype="application/json")
74
+ else:
75
+ config = initialize_agent()
76
+ context = AgentContext(config=config, type=AgentContextType.USER)
77
+ context_id = context.id
78
+
79
+ # Update chat lifetime
80
+ with self._cleanup_lock:
81
+ self._chat_lifetimes[context_id] = datetime.now() + timedelta(hours=lifetime_hours)
82
+
83
+ # Process message
84
+ try:
85
+ # Log the message
86
+ attachment_filenames = [os.path.basename(path) for path in attachment_paths] if attachment_paths else []
87
+
88
+ PrintStyle(
89
+ background_color="#6C3483", font_color="white", bold=True, padding=True
90
+ ).print("External API message:")
91
+ PrintStyle(font_color="white", padding=False).print(f"> {message}")
92
+ if attachment_filenames:
93
+ PrintStyle(font_color="white", padding=False).print("Attachments:")
94
+ for filename in attachment_filenames:
95
+ PrintStyle(font_color="white", padding=False).print(f"- {filename}")
96
+
97
+ # Add user message to chat history so it's visible in the UI
98
+ context.log.log(
99
+ type="user",
100
+ heading="User message",
101
+ content=message,
102
+ kvps={"attachments": attachment_filenames},
103
+ )
104
+
105
+ # Send message to agent
106
+ task = context.communicate(UserMessage(message, attachment_paths))
107
+ result = await task.result()
108
+
109
+ # Clean up expired chats
110
+ self._cleanup_expired_chats()
111
+
112
+ return {
113
+ "context_id": context_id,
114
+ "response": result
115
+ }
116
+
117
+ except Exception as e:
118
+ PrintStyle.error(f"External API error: {e}")
119
+ return Response(f'{{"error": "{str(e)}"}}', status=500, mimetype="application/json")
120
+
121
+ @classmethod
122
+ def _cleanup_expired_chats(cls):
123
+ """Clean up expired chats"""
124
+ with cls._cleanup_lock:
125
+ now = datetime.now()
126
+ expired_contexts = [
127
+ context_id for context_id, expiry in cls._chat_lifetimes.items()
128
+ if now > expiry
129
+ ]
130
+
131
+ for context_id in expired_contexts:
132
+ try:
133
+ context = AgentContext.get(context_id)
134
+ if context:
135
+ context.reset()
136
+ AgentContext.remove(context_id)
137
+ del cls._chat_lifetimes[context_id]
138
+ PrintStyle().print(f"Cleaned up expired chat: {context_id}")
139
+ except Exception as e:
140
+ PrintStyle.error(f"Failed to cleanup chat {context_id}: {e}")
python/api/api_reset_chat.py ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from agent import AgentContext
2
+ from python.helpers.api import ApiHandler, Request, Response
3
+ from python.helpers.print_style import PrintStyle
4
+ from python.helpers import persist_chat
5
+ import json
6
+
7
+
8
+ class ApiResetChat(ApiHandler):
9
+ @classmethod
10
+ def requires_auth(cls) -> bool:
11
+ return False
12
+
13
+ @classmethod
14
+ def requires_csrf(cls) -> bool:
15
+ return False
16
+
17
+ @classmethod
18
+ def requires_api_key(cls) -> bool:
19
+ return True
20
+
21
+ @classmethod
22
+ def get_methods(cls) -> list[str]:
23
+ return ["POST"]
24
+
25
+ async def process(self, input: dict, request: Request) -> dict | Response:
26
+ try:
27
+ # Get context_id from input
28
+ context_id = input.get("context_id")
29
+
30
+ if not context_id:
31
+ return Response(
32
+ '{"error": "context_id is required"}',
33
+ status=400,
34
+ mimetype="application/json"
35
+ )
36
+
37
+ # Check if context exists
38
+ context = AgentContext.get(context_id)
39
+ if not context:
40
+ return Response(
41
+ '{"error": "Chat context not found"}',
42
+ status=404,
43
+ mimetype="application/json"
44
+ )
45
+
46
+ # Reset the chat context (clears history but keeps context alive)
47
+ context.reset()
48
+ # Save the reset context to persist the changes
49
+ persist_chat.save_tmp_chat(context)
50
+
51
+ # Log the reset
52
+ PrintStyle(
53
+ background_color="#3498DB", font_color="white", bold=True, padding=True
54
+ ).print(f"API Chat reset: {context_id}")
55
+
56
+ # Return success response
57
+ return {
58
+ "success": True,
59
+ "message": "Chat reset successfully",
60
+ "context_id": context_id
61
+ }
62
+
63
+ except Exception as e:
64
+ PrintStyle.error(f"API reset chat error: {str(e)}")
65
+ return Response(
66
+ json.dumps({"error": f"Internal server error: {str(e)}"}),
67
+ status=500,
68
+ mimetype="application/json"
69
+ )
python/api/api_terminate_chat.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from agent import AgentContext
2
+ from python.helpers.api import ApiHandler, Request, Response
3
+ from python.helpers.persist_chat import remove_chat
4
+ from python.helpers.print_style import PrintStyle
5
+ import json
6
+
7
+
8
+ class ApiTerminateChat(ApiHandler):
9
+ @classmethod
10
+ def requires_auth(cls) -> bool:
11
+ return False
12
+
13
+ @classmethod
14
+ def requires_csrf(cls) -> bool:
15
+ return False
16
+
17
+ @classmethod
18
+ def requires_api_key(cls) -> bool:
19
+ return True
20
+
21
+ @classmethod
22
+ def get_methods(cls) -> list[str]:
23
+ return ["POST"]
24
+
25
+ async def process(self, input: dict, request: Request) -> dict | Response:
26
+ try:
27
+ # Get context_id from input
28
+ context_id = input.get("context_id")
29
+
30
+ if not context_id:
31
+ return Response(
32
+ '{"error": "context_id is required"}',
33
+ status=400,
34
+ mimetype="application/json"
35
+ )
36
+
37
+ # Check if context exists
38
+ context = AgentContext.get(context_id)
39
+ if not context:
40
+ return Response(
41
+ '{"error": "Chat context not found"}',
42
+ status=404,
43
+ mimetype="application/json"
44
+ )
45
+
46
+ # Delete the chat context
47
+ AgentContext.remove(context.id)
48
+ remove_chat(context.id)
49
+
50
+ # Log the deletion
51
+ PrintStyle(
52
+ background_color="#E74C3C", font_color="white", bold=True, padding=True
53
+ ).print(f"API Chat deleted: {context_id}")
54
+
55
+ # Return success response
56
+ return {
57
+ "success": True,
58
+ "message": "Chat deleted successfully",
59
+ "context_id": context_id
60
+ }
61
+
62
+ except Exception as e:
63
+ PrintStyle.error(f"API terminate chat error: {str(e)}")
64
+ return Response(
65
+ json.dumps({"error": f"Internal server error: {str(e)}"}),
66
+ status=500,
67
+ mimetype="application/json"
68
+ )
python/api/poll.py CHANGED
@@ -1,6 +1,6 @@
1
  from python.helpers.api import ApiHandler, Request, Response
2
 
3
- from agent import AgentContext
4
 
5
  from python.helpers.task_scheduler import TaskScheduler
6
  from python.helpers.localization import Localization
@@ -48,6 +48,11 @@ class Poll(ApiHandler):
48
  if ctx.id in processed_contexts:
49
  continue
50
 
 
 
 
 
 
51
  # Create the base context data that will be returned
52
  context_data = ctx.serialize()
53
 
 
1
  from python.helpers.api import ApiHandler, Request, Response
2
 
3
+ from agent import AgentContext, AgentContextType
4
 
5
  from python.helpers.task_scheduler import TaskScheduler
6
  from python.helpers.localization import Localization
 
48
  if ctx.id in processed_contexts:
49
  continue
50
 
51
+ # Skip BACKGROUND contexts as they should be invisible to users
52
+ if ctx.type == AgentContextType.BACKGROUND:
53
+ processed_contexts.add(ctx.id)
54
+ continue
55
+
56
  # Create the base context data that will be returned
57
  context_data = ctx.serialize()
58
 
python/api/rfc.py CHANGED
@@ -8,6 +8,10 @@ class RFC(ApiHandler):
8
  def requires_csrf(cls) -> bool:
9
  return False
10
 
 
 
 
 
11
  async def process(self, input: dict, request: Request) -> dict | Response:
12
  result = await runtime.handle_rfc(input) # type: ignore
13
  return result
 
8
  def requires_csrf(cls) -> bool:
9
  return False
10
 
11
+ @classmethod
12
+ def requires_auth(cls) -> bool:
13
+ return False
14
+
15
  async def process(self, input: dict, request: Request) -> dict | Response:
16
  result = await runtime.handle_rfc(input) # type: ignore
17
  return result
python/extensions/message_loop_end/_90_save_chat.py CHANGED
@@ -1,8 +1,12 @@
1
  from python.helpers.extension import Extension
2
- from agent import LoopData
3
  from python.helpers import persist_chat
4
 
5
 
6
  class SaveChat(Extension):
7
  async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
8
- persist_chat.save_tmp_chat(self.agent.context)
 
 
 
 
 
1
  from python.helpers.extension import Extension
2
+ from agent import LoopData, AgentContextType
3
  from python.helpers import persist_chat
4
 
5
 
6
  class SaveChat(Extension):
7
  async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
8
+ # Skip saving BACKGROUND contexts as they should be ephemeral
9
+ if self.agent.context.type == AgentContextType.BACKGROUND:
10
+ return
11
+
12
+ persist_chat.save_tmp_chat(self.agent.context)
python/extensions/message_loop_prompts_after/_50_recall_memories.py CHANGED
@@ -3,9 +3,11 @@ from python.helpers.extension import Extension
3
  from python.helpers.memory import Memory
4
  from agent import LoopData
5
  from python.tools.memory_load import DEFAULT_THRESHOLD as DEFAULT_MEMORY_THRESHOLD
6
- from python.helpers import dirty_json, errors, settings
 
7
 
8
  DATA_NAME_TASK = "_recall_memories_task"
 
9
 
10
 
11
  class RecallMemories(Extension):
@@ -22,18 +24,30 @@ class RecallMemories(Extension):
22
 
23
  set = settings.get_settings()
24
 
25
- # every 3 iterations (or the first one) recall memories
 
 
 
 
26
  if loop_data.iteration % set["memory_recall_interval"] == 0:
 
 
 
 
 
 
 
27
  task = asyncio.create_task(
28
- self.search_memories(loop_data=loop_data, **kwargs)
29
  )
30
  else:
31
  task = None
32
 
33
  # set to agent to be able to wait for it
34
  self.agent.set_data(DATA_NAME_TASK, task)
 
35
 
36
- async def search_memories(self, loop_data: LoopData, **kwargs):
37
 
38
  # cleanup
39
  extras = loop_data.extras_persistent
@@ -46,16 +60,6 @@ class RecallMemories(Extension):
46
  set = settings.get_settings()
47
  # try:
48
 
49
- # if recall is disabled, return
50
- if not set["memory_recall_enabled"]:
51
- return
52
-
53
- # show full util message
54
- log_item = self.agent.context.log.log(
55
- type="util",
56
- heading="Searching memories...",
57
- )
58
-
59
  # get system message and chat history for util llm
60
  system = self.agent.read_prompt("memory.memories_query.sys.md")
61
 
@@ -100,6 +104,13 @@ class RecallMemories(Extension):
100
  else:
101
  query = user_instruction + "\n\n" + history
102
 
 
 
 
 
 
 
 
103
  # get memory database
104
  db = await Memory.get(self.agent)
105
 
 
3
  from python.helpers.memory import Memory
4
  from agent import LoopData
5
  from python.tools.memory_load import DEFAULT_THRESHOLD as DEFAULT_MEMORY_THRESHOLD
6
+ from python.helpers import dirty_json, errors, settings, log
7
+
8
 
9
  DATA_NAME_TASK = "_recall_memories_task"
10
+ DATA_NAME_ITER = "_recall_memories_iter"
11
 
12
 
13
  class RecallMemories(Extension):
 
24
 
25
  set = settings.get_settings()
26
 
27
+ # turned off in settings?
28
+ if not set["memory_recall_enabled"]:
29
+ return
30
+
31
+ # every X iterations (or the first one) recall memories
32
  if loop_data.iteration % set["memory_recall_interval"] == 0:
33
+
34
+ # show util message right away
35
+ log_item = self.agent.context.log.log(
36
+ type="util",
37
+ heading="Searching memories...",
38
+ )
39
+
40
  task = asyncio.create_task(
41
+ self.search_memories(loop_data=loop_data, log_item=log_item, **kwargs)
42
  )
43
  else:
44
  task = None
45
 
46
  # set to agent to be able to wait for it
47
  self.agent.set_data(DATA_NAME_TASK, task)
48
+ self.agent.set_data(DATA_NAME_ITER, loop_data.iteration)
49
 
50
+ async def search_memories(self, log_item: log.LogItem, loop_data: LoopData, **kwargs):
51
 
52
  # cleanup
53
  extras = loop_data.extras_persistent
 
60
  set = settings.get_settings()
61
  # try:
62
 
 
 
 
 
 
 
 
 
 
 
63
  # get system message and chat history for util llm
64
  system = self.agent.read_prompt("memory.memories_query.sys.md")
65
 
 
104
  else:
105
  query = user_instruction + "\n\n" + history
106
 
107
+ # if there is no query (or just dash by the LLM), do not continue
108
+ if not query or len(query) <= 3:
109
+ log_item.update(
110
+ query="No relevant memory query generated, skipping search",
111
+ )
112
+ return
113
+
114
  # get memory database
115
  db = await Memory.get(self.agent)
116
 
python/extensions/message_loop_prompts_after/_91_recall_wait.py CHANGED
@@ -1,19 +1,32 @@
1
  from python.helpers.extension import Extension
2
  from agent import LoopData
3
- from python.extensions.message_loop_prompts_after._50_recall_memories import DATA_NAME_TASK as DATA_NAME_TASK_MEMORIES
4
  # from python.extensions.message_loop_prompts_after._51_recall_solutions import DATA_NAME_TASK as DATA_NAME_TASK_SOLUTIONS
5
-
6
 
7
  class RecallWait(Extension):
8
  async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
9
 
10
- task = self.agent.get_data(DATA_NAME_TASK_MEMORIES)
11
- if task and not task.done():
12
- # self.agent.context.log.set_progress("Recalling memories...")
13
- await task
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
- # task = self.agent.get_data(DATA_NAME_TASK_SOLUTIONS)
16
- # if task and not task.done():
17
- # # self.agent.context.log.set_progress("Recalling solutions...")
18
- # await task
19
 
 
1
  from python.helpers.extension import Extension
2
  from agent import LoopData
3
+ from python.extensions.message_loop_prompts_after._50_recall_memories import DATA_NAME_TASK as DATA_NAME_TASK_MEMORIES, DATA_NAME_ITER as DATA_NAME_ITER_MEMORIES
4
  # from python.extensions.message_loop_prompts_after._51_recall_solutions import DATA_NAME_TASK as DATA_NAME_TASK_SOLUTIONS
5
+ from python.helpers import settings
6
 
7
  class RecallWait(Extension):
8
  async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
9
 
10
+ set = settings.get_settings()
11
+
12
+ task = self.agent.get_data(DATA_NAME_TASK_MEMORIES)
13
+ iter = self.agent.get_data(DATA_NAME_ITER_MEMORIES) or 0
14
+
15
+ if task and not task.done():
16
+
17
+ # if memory recall is set to delayed mode, do not await on the iteration it was called
18
+ if set["memory_recall_delayed"]:
19
+ if iter == loop_data.iteration:
20
+ # insert info about delayed memory to extras
21
+ delay_text = self.agent.read_prompt("memory.recall_delay_msg.md")
22
+ loop_data.extras_temporary["memory_recall_delayed"] = delay_text
23
+ return
24
+
25
+ # otherwise await the task
26
+ await task
27
 
28
+ # task = self.agent.get_data(DATA_NAME_TASK_SOLUTIONS)
29
+ # if task and not task.done():
30
+ # # self.agent.context.log.set_progress("Recalling solutions...")
31
+ # await task
32
 
python/extensions/monologue_start/_10_memory_init.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from python.helpers.extension import Extension
2
+ from agent import LoopData
3
+ from python.helpers import memory
4
+ import asyncio
5
+
6
+
7
+ class MemoryInit(Extension):
8
+
9
+ async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
10
+ db = await memory.Memory.get(self.agent)
11
+
12
+
13
+
python/helpers/fasta2a_server.py CHANGED
@@ -351,6 +351,21 @@ class DynamicA2AProxy:
351
  })
352
  return
353
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
354
  # Check if reconfiguration is needed
355
  if self._reconfigure_needed:
356
  try:
@@ -410,11 +425,15 @@ class DynamicA2AProxy:
410
  path = path[4:] # Remove '/a2a' prefix
411
 
412
  # Check if path matches token pattern /t-{token}/
413
- if path.startswith('/t-') and '/' in path[3:]:
414
  # Extract token from path
415
- path_parts = path[3:].split('/', 1) # Remove '/t-' prefix
416
- request_token = path_parts[0]
417
- remaining_path = '/' + path_parts[1] if len(path_parts) > 1 else '/'
 
 
 
 
418
 
419
  # Validate token
420
  cfg = settings.get_settings()
 
351
  })
352
  return
353
 
354
+ from python.helpers import settings
355
+ cfg = settings.get_settings()
356
+ if not cfg["a2a_server_enabled"]:
357
+ response = b'HTTP/1.1 403 Forbidden\r\n\r\nA2A server is disabled'
358
+ await send({
359
+ 'type': 'http.response.start',
360
+ 'status': 403,
361
+ 'headers': [[b'content-type', b'text/plain']],
362
+ })
363
+ await send({
364
+ 'type': 'http.response.body',
365
+ 'body': response,
366
+ })
367
+ return
368
+
369
  # Check if reconfiguration is needed
370
  if self._reconfigure_needed:
371
  try:
 
425
  path = path[4:] # Remove '/a2a' prefix
426
 
427
  # Check if path matches token pattern /t-{token}/
428
+ if path.startswith('/t-'):
429
  # Extract token from path
430
+ if '/' in path[3:]:
431
+ path_parts = path[3:].split('/', 1) # Remove '/t-' prefix
432
+ request_token = path_parts[0]
433
+ remaining_path = '/' + path_parts[1] if len(path_parts) > 1 else '/'
434
+ else:
435
+ request_token = path[3:]
436
+ remaining_path = '/'
437
 
438
  # Validate token
439
  cfg = settings.get_settings()
python/helpers/mcp_server.py CHANGED
@@ -273,6 +273,7 @@ class DynamicMcpProxy:
273
 
274
  def __init__(self):
275
  cfg = settings.get_settings()
 
276
  self.sse_app: ASGIApp | None = None
277
  self.http_app: ASGIApp | None = None
278
  self.http_session_manager = None
@@ -287,6 +288,9 @@ class DynamicMcpProxy:
287
  return DynamicMcpProxy._instance
288
 
289
  def reconfigure(self, token: str):
 
 
 
290
  self.token = token
291
  sse_path = f"/t-{self.token}/sse"
292
  http_path = f"/t-{self.token}/http"
@@ -404,7 +408,7 @@ class DynamicMcpProxy:
404
  # Route based on path
405
  path = scope.get("path", "")
406
 
407
- if f"/t-{self.token}/sse" in path:
408
  # Route to SSE app
409
  await sse_app(scope, receive, send)
410
  elif f"/t-{self.token}/http" in path:
 
273
 
274
  def __init__(self):
275
  cfg = settings.get_settings()
276
+ self.token = ""
277
  self.sse_app: ASGIApp | None = None
278
  self.http_app: ASGIApp | None = None
279
  self.http_session_manager = None
 
288
  return DynamicMcpProxy._instance
289
 
290
  def reconfigure(self, token: str):
291
+ if self.token == token:
292
+ return
293
+
294
  self.token = token
295
  sse_path = f"/t-{self.token}/sse"
296
  http_path = f"/t-{self.token}/http"
 
408
  # Route based on path
409
  path = scope.get("path", "")
410
 
411
+ if f"/t-{self.token}/sse" in path or f"t-{self.token}/messages" in path:
412
  # Route to SSE app
413
  await sse_app(scope, receive, send)
414
  elif f"/t-{self.token}/http" in path:
python/helpers/persist_chat.py CHANGED
@@ -29,6 +29,10 @@ def get_chat_folder_path(ctxid: str):
29
 
30
  def save_tmp_chat(context: AgentContext):
31
  """Save context to the chats folder"""
 
 
 
 
32
  path = _get_chat_file_path(context.id)
33
  files.make_dirs(path)
34
  data = _serialize_context(context)
@@ -39,6 +43,9 @@ def save_tmp_chat(context: AgentContext):
39
  def save_tmp_chats():
40
  """Save all contexts to the chats folder"""
41
  for _, context in AgentContext._contexts.items():
 
 
 
42
  save_tmp_chat(context)
43
 
44
 
@@ -180,7 +187,7 @@ def _deserialize_context(data):
180
  agents = data.get("agents", [])
181
  agent0 = _deserialize_agents(agents, config, context)
182
  streaming_agent = agent0
183
- while streaming_agent.number != data.get("streaming_agent", 0):
184
  streaming_agent = streaming_agent.data.get(Agent.DATA_NAME_SUBORDINATE, None)
185
 
186
  context.agent0 = agent0
 
29
 
30
  def save_tmp_chat(context: AgentContext):
31
  """Save context to the chats folder"""
32
+ # Skip saving BACKGROUND contexts as they should be ephemeral
33
+ if context.type == AgentContextType.BACKGROUND:
34
+ return
35
+
36
  path = _get_chat_file_path(context.id)
37
  files.make_dirs(path)
38
  data = _serialize_context(context)
 
43
  def save_tmp_chats():
44
  """Save all contexts to the chats folder"""
45
  for _, context in AgentContext._contexts.items():
46
+ # Skip BACKGROUND contexts as they should be ephemeral
47
+ if context.type == AgentContextType.BACKGROUND:
48
+ continue
49
  save_tmp_chat(context)
50
 
51
 
 
187
  agents = data.get("agents", [])
188
  agent0 = _deserialize_agents(agents, config, context)
189
  streaming_agent = agent0
190
+ while streaming_agent and streaming_agent.number != data.get("streaming_agent", 0):
191
  streaming_agent = streaming_agent.data.get(Agent.DATA_NAME_SUBORDINATE, None)
192
 
193
  context.agent0 = agent0
python/helpers/settings.py CHANGED
@@ -58,6 +58,7 @@ class Settings(TypedDict):
58
  agent_knowledge_subdir: str
59
 
60
  memory_recall_enabled: bool
 
61
  memory_recall_interval: int
62
  memory_recall_history_len: int
63
  memory_recall_memories_max_search: int
@@ -71,7 +72,6 @@ class Settings(TypedDict):
71
  memory_memorize_consolidation: bool
72
  memory_memorize_replace_threshold: float
73
 
74
-
75
  api_keys: dict[str, str]
76
 
77
  auth_login: str
@@ -98,6 +98,9 @@ class Settings(TypedDict):
98
  mcp_server_enabled: bool
99
  mcp_server_token: str
100
 
 
 
 
101
 
102
  class PartialSettings(Settings, total=False):
103
  pass
@@ -113,7 +116,15 @@ class SettingsField(TypedDict, total=False):
113
  title: str
114
  description: str
115
  type: Literal[
116
- "text", "number", "select", "range", "textarea", "password", "switch", "button", "html"
 
 
 
 
 
 
 
 
117
  ]
118
  value: Any
119
  min: float
@@ -136,12 +147,12 @@ class SettingsOutput(TypedDict):
136
 
137
 
138
  PASSWORD_PLACEHOLDER = "****PSWD****"
 
139
 
140
  SETTINGS_FILE = files.get_abs_path("tmp/settings.json")
141
  _settings: Settings | None = None
142
 
143
 
144
-
145
  def convert_out(settings: Settings) -> SettingsOutput:
146
  default_settings = get_default_settings()
147
 
@@ -478,7 +489,7 @@ def convert_out(settings: Settings) -> SettingsOutput:
478
  "type": "number",
479
  "value": settings["browser_model_rl_output"],
480
  }
481
- )
482
 
483
  browser_model_fields.append(
484
  {
@@ -498,7 +509,6 @@ def convert_out(settings: Settings) -> SettingsOutput:
498
  "tab": "agent",
499
  }
500
 
501
-
502
  # basic auth section
503
  auth_fields: list[SettingsField] = []
504
 
@@ -526,25 +536,6 @@ def convert_out(settings: Settings) -> SettingsOutput:
526
  }
527
  )
528
 
529
- # -------- A2A Section --------
530
- a2a_fields: list[SettingsField] = [
531
- {
532
- "id": "show_a2a_connection",
533
- "title": "Show A2A connection info",
534
- "description": "Display the URL (including token) other agents can use to connect via FastA2A.",
535
- "type": "button",
536
- "value": "Show",
537
- }
538
- ]
539
-
540
- a2a_section: SettingsSection = {
541
- "id": "a2a_server",
542
- "title": "A2A Connection",
543
- "description": "Share this connection string with other agents.",
544
- "fields": a2a_fields,
545
- "tab": "external",
546
- }
547
-
548
  if runtime.is_dockerized():
549
  auth_fields.append(
550
  {
@@ -599,7 +590,8 @@ def convert_out(settings: Settings) -> SettingsOutput:
599
  "value": settings["agent_profile"],
600
  "options": [
601
  {"value": subdir, "label": subdir}
602
- for subdir in files.get_subdirectories("agents") if subdir != "_example"
 
603
  ],
604
  }
605
  )
@@ -626,7 +618,6 @@ def convert_out(settings: Settings) -> SettingsOutput:
626
  "tab": "agent",
627
  }
628
 
629
-
630
  memory_fields: list[SettingsField] = []
631
 
632
  memory_fields.append(
@@ -653,6 +644,16 @@ def convert_out(settings: Settings) -> SettingsOutput:
653
  }
654
  )
655
 
 
 
 
 
 
 
 
 
 
 
656
  memory_fields.append(
657
  {
658
  "id": "memory_recall_query_prep",
@@ -856,6 +857,46 @@ def convert_out(settings: Settings) -> SettingsOutput:
856
  "tab": "developer",
857
  }
858
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
859
  # Speech to text section
860
  stt_fields: list[SettingsField] = []
861
 
@@ -1009,7 +1050,7 @@ def convert_out(settings: Settings) -> SettingsOutput:
1009
  {
1010
  "id": "mcp_server_enabled",
1011
  "title": "Enable A0 MCP Server",
1012
- "description": "Expose Agent Zero as an SSE MCP server. This will make this A0 instance available to MCP clients.",
1013
  "type": "switch",
1014
  "value": settings["mcp_server_enabled"],
1015
  }
@@ -1034,6 +1075,50 @@ def convert_out(settings: Settings) -> SettingsOutput:
1034
  "tab": "mcp",
1035
  }
1036
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1037
  # Backup & Restore section
1038
  backup_fields: list[SettingsField] = []
1039
 
@@ -1080,11 +1165,13 @@ def convert_out(settings: Settings) -> SettingsOutput:
1080
  speech_section,
1081
  api_keys_section,
1082
  auth_section,
1083
- a2a_section,
1084
  mcp_client_section,
1085
  mcp_server_section,
 
 
1086
  backup_section,
1087
  dev_section,
 
1088
  ]
1089
  }
1090
  return result
@@ -1092,11 +1179,12 @@ def convert_out(settings: Settings) -> SettingsOutput:
1092
 
1093
  def _get_api_key_field(settings: Settings, provider: str, title: str) -> SettingsField:
1094
  key = settings["api_keys"].get(provider, models.get_api_key(provider))
 
1095
  return {
1096
  "id": f"api_key_{provider}",
1097
  "title": title,
1098
- "type": "password",
1099
- "value": (PASSWORD_PLACEHOLDER if key and key != "None" else ""),
1100
  }
1101
 
1102
 
@@ -1105,7 +1193,13 @@ def convert_in(settings: dict) -> Settings:
1105
  for section in settings["sections"]:
1106
  if "fields" in section:
1107
  for field in section["fields"]:
1108
- if field["value"] != PASSWORD_PLACEHOLDER:
 
 
 
 
 
 
1109
  if field["id"].endswith("_kwargs"):
1110
  current[field["id"]] = _env_to_dict(field["value"])
1111
  elif field["id"].startswith("api_key_"):
@@ -1147,7 +1241,7 @@ def normalize_settings(settings: Settings) -> Settings:
1147
  # adjust settings values to match current version if needed
1148
  if "version" not in copy or copy["version"] != default["version"]:
1149
  _adjust_to_version(copy, default)
1150
- copy["version"] = default["version"] # sync version
1151
 
1152
  # remove keys that are not in default
1153
  keys_to_remove = [key for key in copy if key not in default]
@@ -1162,7 +1256,7 @@ def normalize_settings(settings: Settings) -> Settings:
1162
  try:
1163
  copy[key] = type(value)(copy[key]) # type: ignore
1164
  if isinstance(copy[key], str):
1165
- copy[key] = copy[key].strip() # strip strings
1166
  except (ValueError, TypeError):
1167
  copy[key] = value # make default instead
1168
 
@@ -1179,6 +1273,7 @@ def _adjust_to_version(settings: Settings, default: Settings):
1179
  if "agent_profile" not in settings or settings["agent_profile"] == "default":
1180
  settings["agent_profile"] = "agent0"
1181
 
 
1182
  def _read_settings_file() -> Settings | None:
1183
  if os.path.exists(SETTINGS_FILE):
1184
  content = files.read_file(SETTINGS_FILE)
@@ -1187,6 +1282,7 @@ def _read_settings_file() -> Settings | None:
1187
 
1188
 
1189
  def _write_settings_file(settings: Settings):
 
1190
  _write_sensitive_settings(settings)
1191
  _remove_sensitive_settings(settings)
1192
 
@@ -1224,7 +1320,7 @@ def get_default_settings() -> Settings:
1224
  return Settings(
1225
  version=_get_version(),
1226
  chat_model_provider="openrouter",
1227
- chat_model_name="openai/gpt-4.1",
1228
  chat_model_api_base="",
1229
  chat_model_kwargs={"temperature": "0"},
1230
  chat_model_ctx_length=100000,
@@ -1234,7 +1330,7 @@ def get_default_settings() -> Settings:
1234
  chat_model_rl_input=0,
1235
  chat_model_rl_output=0,
1236
  util_model_provider="openrouter",
1237
- util_model_name="openai/gpt-4.1-mini",
1238
  util_model_api_base="",
1239
  util_model_ctx_length=100000,
1240
  util_model_ctx_input=0.7,
@@ -1249,7 +1345,7 @@ def get_default_settings() -> Settings:
1249
  embed_model_rl_requests=0,
1250
  embed_model_rl_input=0,
1251
  browser_model_provider="openrouter",
1252
- browser_model_name="openai/gpt-4.1",
1253
  browser_model_api_base="",
1254
  browser_model_vision=True,
1255
  browser_model_rl_requests=0,
@@ -1257,6 +1353,7 @@ def get_default_settings() -> Settings:
1257
  browser_model_rl_output=0,
1258
  browser_model_kwargs={"temperature": "0"},
1259
  memory_recall_enabled=True,
 
1260
  memory_recall_interval=3,
1261
  memory_recall_history_len=10000,
1262
  memory_recall_memories_max_search=12,
@@ -1292,6 +1389,7 @@ def get_default_settings() -> Settings:
1292
  mcp_client_tool_timeout=120,
1293
  mcp_server_enabled=False,
1294
  mcp_server_token=create_auth_token(),
 
1295
  )
1296
 
1297
 
@@ -1441,9 +1539,9 @@ def set_root_password(password: str):
1441
  def get_runtime_config(set: Settings):
1442
  if runtime.is_dockerized():
1443
  return {
 
1444
  "code_exec_ssh_addr": "localhost",
1445
  "code_exec_ssh_port": 22,
1446
- "code_exec_http_port": 80,
1447
  "code_exec_ssh_user": "root",
1448
  }
1449
  else:
@@ -1455,9 +1553,9 @@ def get_runtime_config(set: Settings):
1455
  if host.endswith("/"):
1456
  host = host[:-1]
1457
  return {
 
1458
  "code_exec_ssh_addr": host,
1459
  "code_exec_ssh_port": set["rfc_port_ssh"],
1460
- "code_exec_http_port": set["rfc_port_http"],
1461
  "code_exec_ssh_user": "root",
1462
  }
1463
 
 
58
  agent_knowledge_subdir: str
59
 
60
  memory_recall_enabled: bool
61
+ memory_recall_delayed: bool
62
  memory_recall_interval: int
63
  memory_recall_history_len: int
64
  memory_recall_memories_max_search: int
 
72
  memory_memorize_consolidation: bool
73
  memory_memorize_replace_threshold: float
74
 
 
75
  api_keys: dict[str, str]
76
 
77
  auth_login: str
 
98
  mcp_server_enabled: bool
99
  mcp_server_token: str
100
 
101
+ a2a_server_enabled: bool
102
+
103
+
104
 
105
  class PartialSettings(Settings, total=False):
106
  pass
 
116
  title: str
117
  description: str
118
  type: Literal[
119
+ "text",
120
+ "number",
121
+ "select",
122
+ "range",
123
+ "textarea",
124
+ "password",
125
+ "switch",
126
+ "button",
127
+ "html",
128
  ]
129
  value: Any
130
  min: float
 
147
 
148
 
149
  PASSWORD_PLACEHOLDER = "****PSWD****"
150
+ API_KEY_PLACEHOLDER = "************"
151
 
152
  SETTINGS_FILE = files.get_abs_path("tmp/settings.json")
153
  _settings: Settings | None = None
154
 
155
 
 
156
  def convert_out(settings: Settings) -> SettingsOutput:
157
  default_settings = get_default_settings()
158
 
 
489
  "type": "number",
490
  "value": settings["browser_model_rl_output"],
491
  }
492
+ )
493
 
494
  browser_model_fields.append(
495
  {
 
509
  "tab": "agent",
510
  }
511
 
 
512
  # basic auth section
513
  auth_fields: list[SettingsField] = []
514
 
 
536
  }
537
  )
538
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
539
  if runtime.is_dockerized():
540
  auth_fields.append(
541
  {
 
590
  "value": settings["agent_profile"],
591
  "options": [
592
  {"value": subdir, "label": subdir}
593
+ for subdir in files.get_subdirectories("agents")
594
+ if subdir != "_example"
595
  ],
596
  }
597
  )
 
618
  "tab": "agent",
619
  }
620
 
 
621
  memory_fields: list[SettingsField] = []
622
 
623
  memory_fields.append(
 
644
  }
645
  )
646
 
647
+ memory_fields.append(
648
+ {
649
+ "id": "memory_recall_delayed",
650
+ "title": "Memory auto-recall delayed",
651
+ "description": "The agent will not wait for auto memory recall. Memories will be delivered one message later. This speeds up agent's response time but may result in less relevant first step.",
652
+ "type": "switch",
653
+ "value": settings["memory_recall_delayed"],
654
+ }
655
+ )
656
+
657
  memory_fields.append(
658
  {
659
  "id": "memory_recall_query_prep",
 
857
  "tab": "developer",
858
  }
859
 
860
+ # code_exec_fields: list[SettingsField] = []
861
+
862
+ # code_exec_fields.append(
863
+ # {
864
+ # "id": "code_exec_ssh_enabled",
865
+ # "title": "Use SSH for code execution",
866
+ # "description": "Code execution will use SSH to connect to the terminal. When disabled, a local python terminal interface is used instead. SSH should only be used in development environment or when encountering issues with the local python terminal interface.",
867
+ # "type": "switch",
868
+ # "value": settings["code_exec_ssh_enabled"],
869
+ # }
870
+ # )
871
+
872
+ # code_exec_fields.append(
873
+ # {
874
+ # "id": "code_exec_ssh_addr",
875
+ # "title": "Code execution SSH address",
876
+ # "description": "Address of the SSH server for code execution. Only applies when SSH is enabled.",
877
+ # "type": "text",
878
+ # "value": settings["code_exec_ssh_addr"],
879
+ # }
880
+ # )
881
+
882
+ # code_exec_fields.append(
883
+ # {
884
+ # "id": "code_exec_ssh_port",
885
+ # "title": "Code execution SSH port",
886
+ # "description": "Port of the SSH server for code execution. Only applies when SSH is enabled.",
887
+ # "type": "text",
888
+ # "value": settings["code_exec_ssh_port"],
889
+ # }
890
+ # )
891
+
892
+ # code_exec_section: SettingsSection = {
893
+ # "id": "code_exec",
894
+ # "title": "Code execution",
895
+ # "description": "Configuration of code execution by the agent.",
896
+ # "fields": code_exec_fields,
897
+ # "tab": "developer",
898
+ # }
899
+
900
  # Speech to text section
901
  stt_fields: list[SettingsField] = []
902
 
 
1050
  {
1051
  "id": "mcp_server_enabled",
1052
  "title": "Enable A0 MCP Server",
1053
+ "description": "Expose Agent Zero as an SSE/HTTP MCP server. This will make this A0 instance available to MCP clients.",
1054
  "type": "switch",
1055
  "value": settings["mcp_server_enabled"],
1056
  }
 
1075
  "tab": "mcp",
1076
  }
1077
 
1078
+ # -------- A2A Section --------
1079
+ a2a_fields: list[SettingsField] = []
1080
+
1081
+ a2a_fields.append(
1082
+ {
1083
+ "id": "a2a_server_enabled",
1084
+ "title": "Enable A2A server",
1085
+ "description": "Expose Agent Zero as A2A server. This allows other agents to connect to A0 via A2A protocol.",
1086
+ "type": "switch",
1087
+ "value": settings["a2a_server_enabled"],
1088
+ }
1089
+ )
1090
+
1091
+ a2a_section: SettingsSection = {
1092
+ "id": "a2a_server",
1093
+ "title": "A0 A2A Server",
1094
+ "description": "Agent Zero can be exposed as an A2A server. See <a href=\"javascript:openModal('settings/a2a/a2a-connection.html')\">connection example</a>.",
1095
+ "fields": a2a_fields,
1096
+ "tab": "mcp",
1097
+ }
1098
+
1099
+
1100
+ # External API section
1101
+ external_api_fields: list[SettingsField] = []
1102
+
1103
+ external_api_fields.append(
1104
+ {
1105
+ "id": "external_api_examples",
1106
+ "title": "API Examples",
1107
+ "description": "View examples for using Agent Zero's external API endpoints with API key authentication.",
1108
+ "type": "button",
1109
+ "value": "Show API Examples",
1110
+ }
1111
+ )
1112
+
1113
+ external_api_section: SettingsSection = {
1114
+ "id": "external_api",
1115
+ "title": "External API",
1116
+ "description": "Agent Zero provides external API endpoints for integration with other applications. "
1117
+ "These endpoints use API key authentication and support text messages and file attachments.",
1118
+ "fields": external_api_fields,
1119
+ "tab": "external",
1120
+ }
1121
+
1122
  # Backup & Restore section
1123
  backup_fields: list[SettingsField] = []
1124
 
 
1165
  speech_section,
1166
  api_keys_section,
1167
  auth_section,
 
1168
  mcp_client_section,
1169
  mcp_server_section,
1170
+ a2a_section,
1171
+ external_api_section,
1172
  backup_section,
1173
  dev_section,
1174
+ # code_exec_section,
1175
  ]
1176
  }
1177
  return result
 
1179
 
1180
  def _get_api_key_field(settings: Settings, provider: str, title: str) -> SettingsField:
1181
  key = settings["api_keys"].get(provider, models.get_api_key(provider))
1182
+ # For API keys, use simple asterisk placeholder for existing keys
1183
  return {
1184
  "id": f"api_key_{provider}",
1185
  "title": title,
1186
+ "type": "text",
1187
+ "value": (API_KEY_PLACEHOLDER if key and key != "None" else ""),
1188
  }
1189
 
1190
 
 
1193
  for section in settings["sections"]:
1194
  if "fields" in section:
1195
  for field in section["fields"]:
1196
+ # Skip saving if value is a placeholder
1197
+ should_skip = (
1198
+ field["value"] == PASSWORD_PLACEHOLDER or
1199
+ field["value"] == API_KEY_PLACEHOLDER
1200
+ )
1201
+
1202
+ if not should_skip:
1203
  if field["id"].endswith("_kwargs"):
1204
  current[field["id"]] = _env_to_dict(field["value"])
1205
  elif field["id"].startswith("api_key_"):
 
1241
  # adjust settings values to match current version if needed
1242
  if "version" not in copy or copy["version"] != default["version"]:
1243
  _adjust_to_version(copy, default)
1244
+ copy["version"] = default["version"] # sync version
1245
 
1246
  # remove keys that are not in default
1247
  keys_to_remove = [key for key in copy if key not in default]
 
1256
  try:
1257
  copy[key] = type(value)(copy[key]) # type: ignore
1258
  if isinstance(copy[key], str):
1259
+ copy[key] = copy[key].strip() # strip strings
1260
  except (ValueError, TypeError):
1261
  copy[key] = value # make default instead
1262
 
 
1273
  if "agent_profile" not in settings or settings["agent_profile"] == "default":
1274
  settings["agent_profile"] = "agent0"
1275
 
1276
+
1277
  def _read_settings_file() -> Settings | None:
1278
  if os.path.exists(SETTINGS_FILE):
1279
  content = files.read_file(SETTINGS_FILE)
 
1282
 
1283
 
1284
  def _write_settings_file(settings: Settings):
1285
+ settings = settings.copy()
1286
  _write_sensitive_settings(settings)
1287
  _remove_sensitive_settings(settings)
1288
 
 
1320
  return Settings(
1321
  version=_get_version(),
1322
  chat_model_provider="openrouter",
1323
+ chat_model_name="openai/gpt-5-chat",
1324
  chat_model_api_base="",
1325
  chat_model_kwargs={"temperature": "0"},
1326
  chat_model_ctx_length=100000,
 
1330
  chat_model_rl_input=0,
1331
  chat_model_rl_output=0,
1332
  util_model_provider="openrouter",
1333
+ util_model_name="google/gemini-2.5-flash-lite",
1334
  util_model_api_base="",
1335
  util_model_ctx_length=100000,
1336
  util_model_ctx_input=0.7,
 
1345
  embed_model_rl_requests=0,
1346
  embed_model_rl_input=0,
1347
  browser_model_provider="openrouter",
1348
+ browser_model_name="openai/gpt-5-chat",
1349
  browser_model_api_base="",
1350
  browser_model_vision=True,
1351
  browser_model_rl_requests=0,
 
1353
  browser_model_rl_output=0,
1354
  browser_model_kwargs={"temperature": "0"},
1355
  memory_recall_enabled=True,
1356
+ memory_recall_delayed=False,
1357
  memory_recall_interval=3,
1358
  memory_recall_history_len=10000,
1359
  memory_recall_memories_max_search=12,
 
1389
  mcp_client_tool_timeout=120,
1390
  mcp_server_enabled=False,
1391
  mcp_server_token=create_auth_token(),
1392
+ a2a_server_enabled=False,
1393
  )
1394
 
1395
 
 
1539
  def get_runtime_config(set: Settings):
1540
  if runtime.is_dockerized():
1541
  return {
1542
+ "code_exec_ssh_enabled": False,
1543
  "code_exec_ssh_addr": "localhost",
1544
  "code_exec_ssh_port": 22,
 
1545
  "code_exec_ssh_user": "root",
1546
  }
1547
  else:
 
1553
  if host.endswith("/"):
1554
  host = host[:-1]
1555
  return {
1556
+ "code_exec_ssh_enabled": True,
1557
  "code_exec_ssh_addr": host,
1558
  "code_exec_ssh_port": set["rfc_port_ssh"],
 
1559
  "code_exec_ssh_user": "root",
1560
  }
1561
 
python/helpers/shell_local.py CHANGED
@@ -3,70 +3,47 @@ import subprocess
3
  import time
4
  import sys
5
  from typing import Optional, Tuple
 
 
6
 
7
  class LocalInteractiveSession:
8
  def __init__(self):
9
- self.process = None
10
  self.full_output = ''
 
11
 
12
  async def connect(self):
13
- # Start a new subprocess with the appropriate shell for the OS
14
- if sys.platform.startswith('win'):
15
- # Windows
16
- self.process = subprocess.Popen(
17
- ['cmd.exe'],
18
- stdin=subprocess.PIPE,
19
- stdout=subprocess.PIPE,
20
- stderr=subprocess.PIPE,
21
- text=True,
22
- bufsize=1
23
- )
24
- else:
25
- # macOS and Linux
26
- self.process = subprocess.Popen(
27
- ['/bin/bash'],
28
- stdin=subprocess.PIPE,
29
- stdout=subprocess.PIPE,
30
- stderr=subprocess.PIPE,
31
- text=True,
32
- bufsize=1
33
- )
34
 
35
- def close(self):
36
- if self.process:
37
- self.process.terminate()
38
- self.process.wait()
39
 
40
- def send_command(self, command: str):
41
- if not self.process:
42
  raise Exception("Shell not connected")
43
  self.full_output = ""
44
- self.process.stdin.write(command + '\n') # type: ignore
45
- self.process.stdin.flush() # type: ignore
46
 
47
  async def read_output(self, timeout: float = 0, reset_full_output: bool = False) -> Tuple[str, Optional[str]]:
48
- if not self.process:
49
  raise Exception("Shell not connected")
50
 
51
  if reset_full_output:
52
  self.full_output = ""
53
- partial_output = ''
54
- start_time = time.time()
55
-
56
- while (timeout <= 0 or time.time() - start_time < timeout):
57
- rlist, _, _ = select.select([self.process.stdout], [], [], 0.1)
58
- if rlist:
59
- line = self.process.stdout.readline() # type: ignore
60
- if line:
61
- partial_output += line
62
- self.full_output += line
63
- time.sleep(0.1)
64
- else:
65
- break # No more output
66
- else:
67
- break # No data available
68
 
69
  if not partial_output:
70
- return self.full_output, None
71
-
72
- return self.full_output, partial_output
 
3
  import time
4
  import sys
5
  from typing import Optional, Tuple
6
+ from python.helpers import tty_session
7
+ from python.helpers.shell_ssh import clean_string
8
 
9
  class LocalInteractiveSession:
10
  def __init__(self):
11
+ self.session: tty_session.TTYSession|None = None
12
  self.full_output = ''
13
+ self.is_running = False
14
 
15
  async def connect(self):
16
+ self.session = tty_session.TTYSession("/bin/bash")
17
+ await self.session.start()
18
+ await self.session.read_full_until_idle(idle_timeout=1, total_timeout=1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
+ async def close(self):
21
+ if self.session:
22
+ self.session.kill()
23
+ # self.session.wait()
24
 
25
+ async def send_command(self, command: str):
26
+ if not self.session:
27
  raise Exception("Shell not connected")
28
  self.full_output = ""
29
+ await self.session.sendline(command)
30
+ self.is_running = True
31
 
32
  async def read_output(self, timeout: float = 0, reset_full_output: bool = False) -> Tuple[str, Optional[str]]:
33
+ if not self.session:
34
  raise Exception("Shell not connected")
35
 
36
  if reset_full_output:
37
  self.full_output = ""
38
+
39
+ # get output from terminal
40
+ partial_output = await self.session.read_full_until_idle(idle_timeout=0.01, total_timeout=timeout)
41
+ self.full_output += partial_output
42
+
43
+ # clean output
44
+ partial_output = clean_string(partial_output)
45
+ clean_full_output = clean_string(self.full_output)
 
 
 
 
 
 
 
46
 
47
  if not partial_output:
48
+ return clean_full_output, None
49
+ return clean_full_output, partial_output
 
python/helpers/shell_ssh.py CHANGED
@@ -29,11 +29,20 @@ class SSHInteractiveSession:
29
  self.trimmed_command_length = 0 # Initialize trimmed_command_length
30
  self.is_running = False
31
 
32
- async def connect(self):
33
- # try 3 times with wait and then except
 
 
 
 
 
 
 
 
34
  errors = 0
35
  while True:
36
  try:
 
37
  self.client.connect(
38
  self.hostname,
39
  self.port,
@@ -42,16 +51,25 @@ class SSHInteractiveSession:
42
  allow_agent=False,
43
  look_for_keys=False,
44
  )
 
 
 
 
 
 
 
 
 
45
  self.shell = self.client.invoke_shell(width=100, height=50)
46
- # self.shell.send(f'PS1="{SSHInteractiveSession.ps1_label}"'.encode())
47
- # return
48
- self.shell.send("stty -echo\n".encode()) # disable shell echo
49
 
50
- while True: # wait for end of initial output
 
51
  full, part = await self.read_output()
52
  if full and not part:
53
  return
54
  time.sleep(0.1)
 
55
  except Exception as e:
56
  errors += 1
57
  if errors < 3:
@@ -61,18 +79,17 @@ class SSHInteractiveSession:
61
  content=f"SSH Connection attempt {errors}...",
62
  temp=True,
63
  )
64
-
65
  time.sleep(5)
66
  else:
67
  raise e
68
 
69
- def close(self):
70
  if self.shell:
71
  self.shell.close()
72
  if self.client:
73
  self.client.close()
74
 
75
- def send_command(self, command: str):
76
  if not self.shell:
77
  raise Exception("Shell not connected")
78
  self.full_output = b""
@@ -140,8 +157,8 @@ class SSHInteractiveSession:
140
  decoded_partial_output = partial_output.decode("utf-8", errors="replace")
141
  decoded_full_output = self.full_output.decode("utf-8", errors="replace")
142
 
143
- decoded_partial_output = self.clean_string(decoded_partial_output)
144
- decoded_full_output = self.clean_string(decoded_full_output)
145
 
146
  return decoded_full_output, decoded_partial_output
147
 
@@ -193,32 +210,34 @@ class SSHInteractiveSession:
193
 
194
  return data
195
 
196
- def clean_string(self, input_string):
197
- # Remove ANSI escape codes
198
- ansi_escape = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])")
199
- cleaned = ansi_escape.sub("", input_string)
200
 
201
- # remove null bytes
202
- cleaned = cleaned.replace("\x00", "")
203
 
204
- # remove ipython \r\r\n> sequences from the start
205
- cleaned = re.sub(r'^[ \r]*(?:\r*\n>[ \r]*)*', '', cleaned)
 
 
206
 
207
- # Replace '\r\n' with '\n'
208
- cleaned = cleaned.replace("\r\n", "\n")
209
 
210
- # remove leading \r and spaces
211
- cleaned = cleaned.lstrip("\r ")
212
 
213
- # Split the string by newline characters to process each segment separately
214
- lines = cleaned.split("\n")
215
 
216
- for i in range(len(lines)):
217
- # Handle carriage returns '\r' by splitting and taking the last part
218
- parts = [part for part in lines[i].split("\r") if part.strip()]
219
- if parts:
220
- lines[i] = parts[
221
- -1
222
- ].rstrip() # Overwrite with the last part after the last '\r'
223
 
224
- return "\n".join(lines)
 
29
  self.trimmed_command_length = 0 # Initialize trimmed_command_length
30
  self.is_running = False
31
 
32
+ async def connect(self, keepalive_interval: int = 5):
33
+ """
34
+ Establish the SSH connection and start an interactive shell.
35
+
36
+ Parameters
37
+ ----------
38
+ keepalive_interval : int
39
+ Interval in **seconds** between keep-alive packets sent by Paramiko.
40
+ A value ≤ 0 disables Paramiko’s keep-alive feature.
41
+ """
42
  errors = 0
43
  while True:
44
  try:
45
+ # --- establish TCP/SSH session ---------------------------------
46
  self.client.connect(
47
  self.hostname,
48
  self.port,
 
51
  allow_agent=False,
52
  look_for_keys=False,
53
  )
54
+
55
+ # --------- NEW: enable transport-level keep-alives -------------
56
+ transport = self.client.get_transport()
57
+ if transport and keepalive_interval > 0:
58
+ # sends an SSH_MSG_IGNORE every <keepalive_interval> seconds
59
+ transport.set_keepalive(keepalive_interval)
60
+ # ----------------------------------------------------------------
61
+
62
+ # invoke interactive shell
63
  self.shell = self.client.invoke_shell(width=100, height=50)
64
+ self.shell.send("stty -echo\n".encode()) # disable local echo
 
 
65
 
66
+ # wait for initial prompt/output to settle
67
+ while True:
68
  full, part = await self.read_output()
69
  if full and not part:
70
  return
71
  time.sleep(0.1)
72
+
73
  except Exception as e:
74
  errors += 1
75
  if errors < 3:
 
79
  content=f"SSH Connection attempt {errors}...",
80
  temp=True,
81
  )
 
82
  time.sleep(5)
83
  else:
84
  raise e
85
 
86
+ async def close(self):
87
  if self.shell:
88
  self.shell.close()
89
  if self.client:
90
  self.client.close()
91
 
92
+ async def send_command(self, command: str):
93
  if not self.shell:
94
  raise Exception("Shell not connected")
95
  self.full_output = b""
 
157
  decoded_partial_output = partial_output.decode("utf-8", errors="replace")
158
  decoded_full_output = self.full_output.decode("utf-8", errors="replace")
159
 
160
+ decoded_partial_output = clean_string(decoded_partial_output)
161
+ decoded_full_output = clean_string(decoded_full_output)
162
 
163
  return decoded_full_output, decoded_partial_output
164
 
 
210
 
211
  return data
212
 
213
+ def clean_string(input_string):
214
+ # Remove ANSI escape codes
215
+ ansi_escape = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])")
216
+ cleaned = ansi_escape.sub("", input_string)
217
 
218
+ # remove null bytes
219
+ cleaned = cleaned.replace("\x00", "")
220
 
221
+ # remove ipython \r\r\n> sequences from the start
222
+ cleaned = re.sub(r'^[ \r]*(?:\r*\n>[ \r]*)*', '', cleaned)
223
+ # also remove any amount of '> ' sequences from the start
224
+ cleaned = re.sub(r'^(>\s*)+', '', cleaned)
225
 
226
+ # Replace '\r\n' with '\n'
227
+ cleaned = cleaned.replace("\r\n", "\n")
228
 
229
+ # remove leading \r and spaces
230
+ cleaned = cleaned.lstrip("\r ")
231
 
232
+ # Split the string by newline characters to process each segment separately
233
+ lines = cleaned.split("\n")
234
 
235
+ for i in range(len(lines)):
236
+ # Handle carriage returns '\r' by splitting and taking the last part
237
+ parts = [part for part in lines[i].split("\r") if part.strip()]
238
+ if parts:
239
+ lines[i] = parts[
240
+ -1
241
+ ].rstrip() # Overwrite with the last part after the last '\r'
242
 
243
+ return "\n".join(lines)
python/helpers/tty_session.py CHANGED
@@ -15,9 +15,7 @@ sys.stdout.reconfigure(errors="replace") # type: ignore
15
 
16
 
17
  class TTYSession:
18
- def __init__(
19
- self, cmd, *, cwd=None, env=None, encoding="utf-8", echo=False
20
- ): # ← NEW kw-arg `echo`
21
  self.cmd = cmd if isinstance(cmd, str) else " ".join(cmd)
22
  self.cwd = cwd
23
  self.env = env or os.environ.copy()
@@ -26,6 +24,17 @@ class TTYSession:
26
  self._proc = None
27
  self._buf = asyncio.Queue()
28
 
 
 
 
 
 
 
 
 
 
 
 
29
  # ── user-facing coroutines ────────────────────────────────────────
30
  async def start(self):
31
  if _IS_WIN:
@@ -36,7 +45,22 @@ class TTYSession:
36
  self._proc = await _spawn_posix_pty(
37
  self.cmd, self.cwd, self.env, self.echo
38
  ) # ← pass echo
39
- asyncio.create_task(self._pump_stdout())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
  async def send(self, data: str | bytes):
42
  if self._proc is None:
 
15
 
16
 
17
  class TTYSession:
18
+ def __init__(self, cmd, *, cwd=None, env=None, encoding="utf-8", echo=False):
 
 
19
  self.cmd = cmd if isinstance(cmd, str) else " ".join(cmd)
20
  self.cwd = cwd
21
  self.env = env or os.environ.copy()
 
24
  self._proc = None
25
  self._buf = asyncio.Queue()
26
 
27
+ def __del__(self):
28
+ # Simple cleanup on object destruction
29
+ import nest_asyncio
30
+
31
+ nest_asyncio.apply()
32
+ if hasattr(self, "close"):
33
+ try:
34
+ asyncio.run(self.close())
35
+ except Exception:
36
+ pass
37
+
38
  # ── user-facing coroutines ────────────────────────────────────────
39
  async def start(self):
40
  if _IS_WIN:
 
45
  self._proc = await _spawn_posix_pty(
46
  self.cmd, self.cwd, self.env, self.echo
47
  ) # ← pass echo
48
+ self._pump_task = asyncio.create_task(self._pump_stdout())
49
+
50
+ async def close(self):
51
+ # Cancel the pump task if it exists
52
+ if hasattr(self, "_pump_task") and self._pump_task:
53
+ self._pump_task.cancel()
54
+ try:
55
+ await self._pump_task
56
+ except asyncio.CancelledError:
57
+ pass
58
+ # Terminate the process if it exists
59
+ if self._proc:
60
+ self._proc.terminate()
61
+ await self._proc.wait()
62
+ self._proc = None
63
+ self._pump_task = None
64
 
65
  async def send(self, data: str | bytes):
66
  if self._proc is None:
python/tools/call_subordinate.py CHANGED
@@ -23,7 +23,7 @@ class Delegation(Tool):
23
  subordinate.hist_add_user_message(UserMessage(message=message, attachments=[]))
24
 
25
  # set subordinate prompt profile if provided, if not, keep original
26
- agent_profile = kwargs.get("agent_profile")
27
  if agent_profile:
28
  subordinate.config.profile = agent_profile
29
 
 
23
  subordinate.hist_add_user_message(UserMessage(message=message, attachments=[]))
24
 
25
  # set subordinate prompt profile if provided, if not, keep original
26
+ agent_profile = kwargs.get("profile")
27
  if agent_profile:
28
  subordinate.config.profile = agent_profile
29
 
python/tools/code_execution_tool.py CHANGED
@@ -16,7 +16,6 @@ import re
16
  @dataclass
17
  class State:
18
  shells: dict[int, LocalInteractiveSession | SSHInteractiveSession]
19
- docker: DockerContainerManager | None
20
 
21
 
22
  class CodeExecution(Tool):
@@ -35,14 +34,10 @@ class CodeExecution(Tool):
35
  re.compile(r"\?\s*$"), # line ending with question mark
36
  ]
37
 
38
- async def execute(self, **kwargs):
39
 
40
  await self.agent.handle_intervention() # wait for intervention and handle it, if paused
41
 
42
- await self.prepare_state()
43
-
44
- # os.chdir(files.get_abs_path("./work_dir")) #change CWD to work_dir
45
-
46
  runtime = self.args.get("runtime", "").lower().strip()
47
  session = int(self.args.get("session", 0))
48
  self.allow_running = bool(self.args.get("allow_running", False))
@@ -95,59 +90,48 @@ class CodeExecution(Tool):
95
  async def after_execution(self, response, **kwargs):
96
  self.agent.hist_add_tool_result(self.name, response.message)
97
 
98
- async def prepare_state(self, reset=False, session=None):
99
- self.state = self.agent.get_data("_cet_state")
100
- if not self.state or reset:
101
-
102
- # initialize docker container if execution in docker is configured
103
- if not self.state and self.agent.config.code_exec_docker_enabled:
104
- docker = DockerContainerManager(
105
- logger=self.agent.context.log,
106
- name=self.agent.config.code_exec_docker_name,
107
- image=self.agent.config.code_exec_docker_image,
108
- ports=self.agent.config.code_exec_docker_ports,
109
- volumes=self.agent.config.code_exec_docker_volumes,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
  )
111
- docker.start_container()
112
  else:
113
- docker = self.state.docker if self.state else None
114
-
115
- # initialize shells dictionary if not exists
116
- shells = {} if not self.state else self.state.shells.copy()
117
-
118
- # Only reset the specified session if provided
119
- if session is not None and session in shells:
120
- shells[session].close()
121
- del shells[session]
122
- elif reset and not session:
123
- # Close all sessions if full reset requested
124
- for s in list(shells.keys()):
125
- shells[s].close()
126
- shells = {}
127
-
128
- # initialize local or remote interactive shell interface for session 0 if needed
129
- if 0 not in shells:
130
- if self.agent.config.code_exec_ssh_enabled:
131
- pswd = (
132
- self.agent.config.code_exec_ssh_pass
133
- if self.agent.config.code_exec_ssh_pass
134
- else await rfc_exchange.get_root_password()
135
- )
136
- shell = SSHInteractiveSession(
137
- self.agent.context.log,
138
- self.agent.config.code_exec_ssh_addr,
139
- self.agent.config.code_exec_ssh_port,
140
- self.agent.config.code_exec_ssh_user,
141
- pswd,
142
- )
143
- else:
144
- shell = LocalInteractiveSession()
145
 
146
- shells[0] = shell
147
- await shell.connect()
148
 
149
- self.state = State(shells=shells, docker=docker)
150
  self.agent.set_data("_cet_state", self.state)
 
151
 
152
  async def execute_python_code(self, session: int, code: str, reset: bool = False):
153
  escaped_code = shlex.quote(code)
@@ -171,6 +155,8 @@ class CodeExecution(Tool):
171
  self, session: int, command: str, reset: bool = False, prefix: str = ""
172
  ):
173
 
 
 
174
  await self.agent.handle_intervention() # wait for intervention and handle it, if paused
175
 
176
  # Check if session is running and handle it
@@ -182,40 +168,28 @@ class CodeExecution(Tool):
182
  for i in range(2):
183
  try:
184
 
185
- if reset:
186
- await self.reset_terminal()
187
-
188
- if session not in self.state.shells:
189
- if self.agent.config.code_exec_ssh_enabled:
190
- pswd = (
191
- self.agent.config.code_exec_ssh_pass
192
- if self.agent.config.code_exec_ssh_pass
193
- else await rfc_exchange.get_root_password()
194
- )
195
- shell = SSHInteractiveSession(
196
- self.agent.context.log,
197
- self.agent.config.code_exec_ssh_addr,
198
- self.agent.config.code_exec_ssh_port,
199
- self.agent.config.code_exec_ssh_user,
200
- pswd,
201
- )
202
- else:
203
- shell = LocalInteractiveSession()
204
- self.state.shells[session] = shell
205
- await shell.connect()
206
-
207
- self.state.shells[session].send_command(command)
208
 
209
  PrintStyle(
210
  background_color="white", font_color="#1B4F72", bold=True
211
- ).print(f"{self.agent.agent_name} code execution output")
212
  return await self.get_terminal_output(session=session, prefix=prefix)
213
 
214
  except Exception as e:
215
  if i == 1:
216
  # try again on lost connection
217
  PrintStyle.error(str(e))
218
- await self.prepare_state(reset=True)
219
  continue
220
  else:
221
  raise e
@@ -246,20 +220,7 @@ class CodeExecution(Tool):
246
  # if not self.state:
247
  self.state = await self.prepare_state(session=session)
248
 
249
- # Common shell prompt regex patterns (add more as needed)
250
- prompt_patterns = [
251
- re.compile(r"\\(venv\\).+[$#] ?$"), # (venv) ...$ or (venv) ...#
252
- re.compile(r"root@[^:]+:[^#]+# ?$"), # root@container:~#
253
- re.compile(r"[a-zA-Z0-9_.-]+@[^:]+:[^$#]+[$#] ?$"), # user@host:~$
254
- ]
255
-
256
- # potential dialog detection
257
- dialog_patterns = [
258
- re.compile(r"Y/N", re.IGNORECASE), # Y/N anywhere in line
259
- re.compile(r"yes/no", re.IGNORECASE), # yes/no anywhere in line
260
- re.compile(r":\s*$"), # line ending with colon
261
- re.compile(r"\?\s*$"), # line ending with question mark
262
- ]
263
 
264
  start_time = time.time()
265
  last_output_time = start_time
@@ -382,13 +343,16 @@ class CodeExecution(Tool):
382
  reset_full_output=False,
383
  prefix=""
384
  ):
 
 
 
385
  if not (
386
- session in self.state.shells
387
- and getattr(self.state.shells[session], "is_running", False)
388
  ):
389
  return None
390
 
391
- full_output, _ = await self.state.shells[session].read_output(
392
  timeout=1, reset_full_output=reset_full_output
393
  )
394
  truncated_output = self.fix_full_output(full_output)
@@ -430,8 +394,11 @@ class CodeExecution(Tool):
430
 
431
  def mark_session_idle(self, session: int = 0):
432
  # Mark session as idle - command finished
433
- if session in self.state.shells:
434
- self.state.shells[session].is_running = False
 
 
 
435
 
436
  async def reset_terminal(self, session=0, reason: str | None = None):
437
  # Print the reason for the reset to the console if provided
 
16
  @dataclass
17
  class State:
18
  shells: dict[int, LocalInteractiveSession | SSHInteractiveSession]
 
19
 
20
 
21
  class CodeExecution(Tool):
 
34
  re.compile(r"\?\s*$"), # line ending with question mark
35
  ]
36
 
37
+ async def execute(self, **kwargs) -> Response:
38
 
39
  await self.agent.handle_intervention() # wait for intervention and handle it, if paused
40
 
 
 
 
 
41
  runtime = self.args.get("runtime", "").lower().strip()
42
  session = int(self.args.get("session", 0))
43
  self.allow_running = bool(self.args.get("allow_running", False))
 
90
  async def after_execution(self, response, **kwargs):
91
  self.agent.hist_add_tool_result(self.name, response.message)
92
 
93
+ async def prepare_state(self, reset=False, session: int | None = None):
94
+ self.state: State | None = self.agent.get_data("_cet_state")
95
+ if not self.state:
96
+ # initialize shells dictionary if not exists
97
+ shells: dict[int, LocalInteractiveSession | SSHInteractiveSession] = {}
98
+ else:
99
+ shells = self.state.shells.copy()
100
+
101
+ # Only reset the specified session if provided
102
+ if reset and session is not None and session in shells:
103
+ await shells[session].close()
104
+ del shells[session]
105
+ elif reset and not session:
106
+ # Close all sessions if full reset requested
107
+ for s in list(shells.keys()):
108
+ await shells[s].close()
109
+ shells = {}
110
+
111
+ # initialize local or remote interactive shell interface for session 0 if needed
112
+ if session is not None and session not in shells:
113
+ if self.agent.config.code_exec_ssh_enabled:
114
+ pswd = (
115
+ self.agent.config.code_exec_ssh_pass
116
+ if self.agent.config.code_exec_ssh_pass
117
+ else await rfc_exchange.get_root_password()
118
+ )
119
+ shell = SSHInteractiveSession(
120
+ self.agent.context.log,
121
+ self.agent.config.code_exec_ssh_addr,
122
+ self.agent.config.code_exec_ssh_port,
123
+ self.agent.config.code_exec_ssh_user,
124
+ pswd,
125
  )
 
126
  else:
127
+ shell = LocalInteractiveSession()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
 
129
+ shells[session] = shell
130
+ await shell.connect()
131
 
132
+ self.state = State(shells=shells)
133
  self.agent.set_data("_cet_state", self.state)
134
+ return self.state
135
 
136
  async def execute_python_code(self, session: int, code: str, reset: bool = False):
137
  escaped_code = shlex.quote(code)
 
155
  self, session: int, command: str, reset: bool = False, prefix: str = ""
156
  ):
157
 
158
+ self.state = await self.prepare_state(reset=reset, session=session)
159
+
160
  await self.agent.handle_intervention() # wait for intervention and handle it, if paused
161
 
162
  # Check if session is running and handle it
 
168
  for i in range(2):
169
  try:
170
 
171
+ await self.state.shells[session].send_command(command)
172
+
173
+ locl = (
174
+ " (local)"
175
+ if isinstance(self.state.shells[session], LocalInteractiveSession)
176
+ else (
177
+ " (remote)"
178
+ if isinstance(self.state.shells[session], SSHInteractiveSession)
179
+ else " (unknown)"
180
+ )
181
+ )
 
 
 
 
 
 
 
 
 
 
 
 
182
 
183
  PrintStyle(
184
  background_color="white", font_color="#1B4F72", bold=True
185
+ ).print(f"{self.agent.agent_name} code execution output{locl}")
186
  return await self.get_terminal_output(session=session, prefix=prefix)
187
 
188
  except Exception as e:
189
  if i == 1:
190
  # try again on lost connection
191
  PrintStyle.error(str(e))
192
+ await self.prepare_state(reset=True, session=session)
193
  continue
194
  else:
195
  raise e
 
220
  # if not self.state:
221
  self.state = await self.prepare_state(session=session)
222
 
223
+
 
 
 
 
 
 
 
 
 
 
 
 
 
224
 
225
  start_time = time.time()
226
  last_output_time = start_time
 
343
  reset_full_output=False,
344
  prefix=""
345
  ):
346
+ state = getattr(self, "state", None)
347
+ if not state:
348
+ return None
349
  if not (
350
+ session in state.shells
351
+ and getattr(state.shells[session], "is_running", False)
352
  ):
353
  return None
354
 
355
+ full_output, _ = await state.shells[session].read_output(
356
  timeout=1, reset_full_output=reset_full_output
357
  )
358
  truncated_output = self.fix_full_output(full_output)
 
394
 
395
  def mark_session_idle(self, session: int = 0):
396
  # Mark session as idle - command finished
397
+ state = getattr(self, "state", None)
398
+ if state and session in state.shells:
399
+ shell = state.shells[session]
400
+ if hasattr(shell, "is_running"):
401
+ shell.is_running = False
402
 
403
  async def reset_terminal(self, session=0, reason: str | None = None):
404
  # Print the reason for the reset to the console if provided
run_ui.py CHANGED
@@ -79,14 +79,17 @@ def is_loopback_address(address):
79
  def requires_api_key(f):
80
  @wraps(f)
81
  async def decorated(*args, **kwargs):
82
- valid_api_key = dotenv.get_dotenv_value("API_KEY")
 
 
 
83
  if api_key := request.headers.get("X-API-KEY"):
84
  if api_key != valid_api_key:
85
- return Response("API key required", 401)
86
  elif request.json and request.json.get("api_key"):
87
  api_key = request.json.get("api_key")
88
  if api_key != valid_api_key:
89
- return Response("API key required", 401)
90
  else:
91
  return Response("API key required", 401)
92
  return await f(*args, **kwargs)
 
79
  def requires_api_key(f):
80
  @wraps(f)
81
  async def decorated(*args, **kwargs):
82
+ # Use the auth token from settings (same as MCP server)
83
+ from python.helpers.settings import get_settings
84
+ valid_api_key = get_settings()["mcp_server_token"]
85
+
86
  if api_key := request.headers.get("X-API-KEY"):
87
  if api_key != valid_api_key:
88
+ return Response("Invalid API key", 401)
89
  elif request.json and request.json.get("api_key"):
90
  api_key = request.json.get("api_key")
91
  if api_key != valid_api_key:
92
+ return Response("Invalid API key", 401)
93
  else:
94
  return Response("API key required", 401)
95
  return await f(*args, **kwargs)
tests/tty_test.py DELETED
@@ -1,266 +0,0 @@
1
- """
2
- tty_spawn.py – drive any console program through a real TTY
3
- cross-platform (Windows via pywinpty, POSIX via pty).
4
-
5
- API (async):
6
- term = TTYSpawn(cmd, *, cwd=None, env=None, encoding="utf-8")
7
- await term.start() # launch child
8
- chunk = await term.read(timeout=1.0) # None on timeout
9
- await term.send("data") # raw bytes
10
- await term.sendline("text") # adds '\n'
11
- await term.wait() # exit code
12
- term.kill() # abort
13
- """
14
- # ────────────────── NO ORIGINAL LINES REMOVED – ONLY APPENDED CODE ──────────────────
15
-
16
- import asyncio, os, sys, platform, errno
17
-
18
- _IS_WIN = platform.system() == "Windows"
19
- if _IS_WIN:
20
- import winpty # pip install pywinpty
21
- import msvcrt
22
-
23
-
24
- # Make stdin / stdout tolerant to broken UTF-8 so input() never aborts
25
- try:
26
- # Python 3.7+ has reconfigure()
27
- sys.stdin .reconfigure(errors="replace")
28
- sys.stdout.reconfigure(errors="replace")
29
- except AttributeError:
30
- # Older Pythons: wrap them manually
31
- import io
32
- sys.stdin = io.TextIOWrapper(sys.stdin.buffer,
33
- encoding=sys.stdin.encoding or "utf-8",
34
- errors="replace",
35
- line_buffering=True)
36
- sys.stdout = io.TextIOWrapper(sys.stdout.buffer,
37
- encoding=sys.stdout.encoding or "utf-8",
38
- errors="replace",
39
- line_buffering=True)
40
- # ─────────────────────────────────────────────────────────────────────
41
-
42
-
43
- # ──────────────────────────── PUBLIC CLASS ────────────────────────────
44
-
45
- class TTYSpawn:
46
- def __init__(self, cmd, *, cwd=None, env=None,
47
- encoding="utf-8", echo=True): # ← NEW kw-arg `echo`
48
- self.cmd = cmd if isinstance(cmd, str) else " ".join(cmd)
49
- self.cwd = cwd
50
- self.env = env or os.environ.copy()
51
- self.encoding = encoding
52
- self.echo = echo # ← store preference
53
- self._proc = None
54
- self._buf = asyncio.Queue()
55
-
56
- # ── user-facing coroutines ────────────────────────────────────────
57
- async def start(self):
58
- if _IS_WIN:
59
- self._proc = await _spawn_winpty(
60
- self.cmd, self.cwd, self.env, self.echo) # ← pass echo
61
- else:
62
- self._proc = await _spawn_posix_pty(
63
- self.cmd, self.cwd, self.env, self.echo) # ← pass echo
64
- asyncio.create_task(self._pump_stdout())
65
-
66
- async def read(self, timeout=None):
67
- # Return any decoded text the child produced, or None on timeout
68
- try:
69
- return await asyncio.wait_for(self._buf.get(), timeout)
70
- except asyncio.TimeoutError:
71
- return None
72
-
73
- # backward-compat alias:
74
- readline = read
75
-
76
- async def send(self, data: str | bytes):
77
- if isinstance(data, str):
78
- data = data.encode(self.encoding)
79
- self._proc.stdin.write(data)
80
- await self._proc.stdin.drain()
81
-
82
- async def sendline(self, line: str):
83
- await self.send(line + "\n")
84
-
85
- async def wait(self):
86
- return await self._proc.wait()
87
-
88
- def kill(self):
89
- self._proc.kill()
90
-
91
- async def read_until_idle(self, idle_timeout, total_timeout):
92
- # Collect child output using iter_until_idle to avoid duplicate logic
93
- return "".join([chunk async for chunk in self.iter_until_idle(idle_timeout, total_timeout)])
94
-
95
- async def iter_until_idle(self, idle_timeout, total_timeout):
96
- # Yield each chunk as soon as it arrives until idle or total timeout
97
- import time
98
- start = time.monotonic()
99
- while True:
100
- if time.monotonic() - start > total_timeout:
101
- break
102
- chunk = await self.read(timeout=idle_timeout)
103
- if chunk is None:
104
- break
105
- yield chunk
106
-
107
- # ── internal: stream raw output into the queue ────────────────────
108
- async def _pump_stdout(self):
109
- reader = self._proc.stdout
110
- while True:
111
- chunk = await reader.read(4096) # grab whatever is ready
112
- if not chunk:
113
- break
114
- self._buf.put_nowait(chunk.decode(self.encoding, "replace"))
115
-
116
- # ──────────────────────────── POSIX IMPLEMENTATION ────────────────────
117
-
118
- async def _spawn_posix_pty(cmd, cwd, env, echo):
119
- import pty, asyncio, os, termios
120
- master, slave = pty.openpty()
121
-
122
- # ── Disable ECHO on the slave side if requested ──
123
- if not echo:
124
- attrs = termios.tcgetattr(slave)
125
- attrs[3] &= ~termios.ECHO # lflag
126
- termios.tcsetattr(slave, termios.TCSANOW, attrs)
127
-
128
- proc = await asyncio.create_subprocess_shell(
129
- cmd,
130
- stdin=slave,
131
- stdout=slave,
132
- stderr=slave,
133
- cwd=cwd,
134
- env=env,
135
- close_fds=True,
136
- )
137
- os.close(slave)
138
-
139
- loop = asyncio.get_running_loop()
140
- reader = asyncio.StreamReader()
141
-
142
- def _on_data():
143
- try:
144
- data = os.read(master, 1 << 16)
145
- except OSError as e:
146
- if e.errno != errno.EIO: # EIO == EOF on some systems
147
- raise
148
- data = b""
149
- if data:
150
- reader.feed_data(data)
151
- else:
152
- reader.feed_eof()
153
- loop.remove_reader(master)
154
-
155
- loop.add_reader(master, _on_data)
156
-
157
- class _Stdin:
158
- def write(self, d): os.write(master, d)
159
- async def drain(self): await asyncio.sleep(0)
160
-
161
- proc.stdin = _Stdin()
162
- proc.stdout = reader
163
- return proc
164
-
165
- # ──────────────────────────── WINDOWS IMPLEMENTATION ──────────────────
166
-
167
- async def _spawn_winpty(cmd, cwd, env, echo):
168
- # A quick way to silence command echo in cmd.exe is /Q (quiet)
169
- if not echo and cmd.strip().lower().startswith("cmd") and "/q" not in cmd.lower():
170
- cmd = cmd.replace("cmd.exe", "cmd.exe /Q")
171
-
172
- cols, rows = 80, 25
173
- pty = winpty.PTY(cols, rows)
174
- child = pty.spawn(cmd, cwd=cwd or os.getcwd(), env=env)
175
-
176
- master_r_fd = msvcrt.open_osfhandle(child.conout_pipe, os.O_RDONLY)
177
- master_w_fd = msvcrt.open_osfhandle(child.conin_pipe, 0)
178
-
179
- loop = asyncio.get_running_loop()
180
- reader = asyncio.StreamReader()
181
-
182
- def _on_data():
183
- try:
184
- data = os.read(master_r_fd, 1 << 16)
185
- except OSError:
186
- data = b""
187
- if data:
188
- reader.feed_data(data)
189
- else:
190
- reader.feed_eof()
191
- loop.remove_reader(master_r_fd)
192
-
193
- loop.add_reader(master_r_fd, _on_data)
194
-
195
- class _Stdin:
196
- def write(self, d): os.write(master_w_fd, d)
197
- async def drain(self): await asyncio.sleep(0)
198
-
199
- class _Proc(asyncio.subprocess.Process):
200
- def __init__(self):
201
- self.stdin = _Stdin()
202
- self.stdout = reader
203
- self.pid = child.pid
204
- async def wait(self):
205
- while child.isalive():
206
- await asyncio.sleep(0.2)
207
- return 0
208
- def kill(self):
209
- child.kill()
210
-
211
- return _Proc()
212
-
213
- # ───────────────────────── INTERACTIVE DRIVER ─────────────────────────
214
-
215
- async def interactive_shell():
216
- shell_cmd, prompt_hint = (
217
- ("cmd.exe", "$") if _IS_WIN else ("/bin/bash", "$")
218
- )
219
-
220
- # echo=False → suppress the shell’s own echo of commands
221
- term = TTYSpawn(shell_cmd, echo=False)
222
- await term.start()
223
-
224
- timeout = 1.0
225
-
226
- print(f"Connected to {shell_cmd}.")
227
- print("Type commands for the shell.")
228
- print("• t=<seconds> → change idle timeout")
229
- print("• exit → quit helper\n")
230
-
231
- await term.sendline(" ")
232
- print(await term.read_until_idle(timeout, timeout), end="", flush=True)
233
-
234
- while True:
235
- try:
236
- user = input(f"(timeout={timeout}) {prompt_hint} ")
237
- except (EOFError, KeyboardInterrupt):
238
- print("\nLeaving…")
239
- break
240
-
241
- if user.lower() == "/exit":
242
- break
243
- if user.startswith("/t="):
244
- try:
245
- timeout = float(user.split("=", 1)[1])
246
- print(f"[helper] idle timeout set to {timeout}s")
247
- except ValueError:
248
- print("[helper] invalid number")
249
- continue
250
-
251
- idle_timeout = timeout
252
- total_timeout = 10 * idle_timeout
253
- if user == "":
254
- # Just read output, do not send empty line
255
- async for chunk in term.iter_until_idle(idle_timeout, total_timeout):
256
- print(chunk, end="", flush=True)
257
- else:
258
- await term.sendline(user)
259
- async for chunk in term.iter_until_idle(idle_timeout, total_timeout):
260
- print(chunk, end="", flush=True)
261
-
262
- await term.sendline("exit")
263
- await term.wait()
264
-
265
- if __name__ == "__main__":
266
- asyncio.run(interactive_shell())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
webui/components/chat/speech/speech-store.js CHANGED
@@ -303,8 +303,8 @@ const model = {
303
  for (const line of lines) {
304
  if (!line.trim()) continue;
305
  // Process each line into sentence tokens and add to chunks
306
- const sentenceStr = sentenceTokens(line.trim()).join(" ");
307
- initialChunks.push(sentenceStr);
308
  }
309
 
310
  // Step 2: Merge short chunks until they meet minimum length criteria
 
303
  for (const line of lines) {
304
  if (!line.trim()) continue;
305
  // Process each line into sentence tokens and add to chunks
306
+ const sentences = sentenceTokens(line.trim());
307
+ initialChunks.push(...sentences);
308
  }
309
 
310
  // Step 2: Merge short chunks until they meet minimum length criteria
webui/components/messages/action-buttons/simple-action-buttons.js CHANGED
@@ -9,6 +9,11 @@ function getTextContent(element) {
9
  for (const child of element.children) {
10
  // Skip action buttons
11
  if (child.classList.contains("action-buttons")) continue;
 
 
 
 
 
12
  // Get text content from the child
13
  const text = child.innerText || "";
14
  if (text.trim()) {
 
9
  for (const child of element.children) {
10
  // Skip action buttons
11
  if (child.classList.contains("action-buttons")) continue;
12
+ // If the child is an image, copy its src URL
13
+ if (child.tagName && child.tagName.toLowerCase() === "img") {
14
+ if (child.src) textParts.push(child.src);
15
+ continue;
16
+ }
17
  // Get text content from the child
18
  const text = child.innerText || "";
19
  if (text.trim()) {
webui/components/settings/{external → a2a}/a2a-connection.html RENAMED
@@ -9,6 +9,17 @@
9
  <p>Agent Zero A2A Server enables FastA2A protocol communication with other agents.</p>
10
  <p>Other agents can connect using the URL below (replace host if needed):</p>
11
 
 
 
 
 
 
 
 
 
 
 
 
12
  <h3>A2A Connection URL</h3>
13
  <div id="a2a-connection-example"></div>
14
 
@@ -44,4 +55,4 @@
44
 
45
  </body>
46
 
47
- </html>
 
9
  <p>Agent Zero A2A Server enables FastA2A protocol communication with other agents.</p>
10
  <p>Other agents can connect using the URL below (replace host if needed):</p>
11
 
12
+ <!-- API Token Information -->
13
+ <div
14
+ style="background-color: var(--color-bg-secondary); border: 1px solid var(--color-border); border-radius: 6px; padding: 12px; margin: 16px 0;">
15
+ <h4 style="margin: 0 0 8px 0; color: var(--color-text-primary);">API Token Information</h4>
16
+ <p style="margin: 0; color: var(--color-text-secondary); font-size: 14px;">
17
+ The token used in the URL is automatically generated from your username and password.
18
+ This same token is also used for external API endpoints. The token changes when you update your
19
+ credentials.
20
+ </p>
21
+ </div>
22
+
23
  <h3>A2A Connection URL</h3>
24
  <div id="a2a-connection-example"></div>
25
 
 
55
 
56
  </body>
57
 
58
+ </html>
webui/components/settings/external/api-examples.html ADDED
@@ -0,0 +1,678 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <html>
2
+
3
+ <head>
4
+ <title>Agent Zero External API Examples</title>
5
+ </head>
6
+
7
+ <body>
8
+ <div x-data>
9
+ <p>Agent Zero provides external API endpoints for integration with other applications.</p>
10
+ <p>These endpoints use API key authentication and support text messages and file attachments.</p>
11
+
12
+ <!-- API Token Information -->
13
+ <div style="background-color: var(--color-bg-secondary); border: 1px solid var(--color-border); border-radius: 6px; padding: 12px; margin: 16px 0;">
14
+ <h4 style="margin: 0 0 8px 0; color: var(--color-text-primary);">API Token Information</h4>
15
+ <p style="margin: 0; color: var(--color-text-secondary); font-size: 14px;">
16
+ The API token is automatically generated from your username and password.
17
+ This same token is used for both MCP server connections and external API endpoints.
18
+ The token changes when you update your credentials.
19
+ </p>
20
+ </div>
21
+
22
+ <!-- Section 1: api_message Endpoint -->
23
+ <div class="api-section">
24
+ <h2>POST /api_message</h2>
25
+ <p style="margin: 0 0 16px 0; color: var(--color-text-secondary); font-size: 14px;">
26
+ Send messages to Agent Zero and receive responses. Supports text messages, file attachments, and conversation continuity.
27
+ </p>
28
+
29
+ <!-- API Reference -->
30
+ <h3 style="margin: 20px 0 12px 0; color: var(--color-text-primary);">API Reference</h3>
31
+ <div style="background-color: var(--color-bg-secondary); border: 1px solid var(--color-border); border-radius: 6px; padding: 12px; margin: 0 0 20px 0;">
32
+ <p style="margin: 0 0 8px 0; color: var(--color-text-secondary); font-size: 14px;">
33
+ <strong>Parameters:</strong><br>
34
+ • <code>context_id</code> (string, optional): Existing chat context ID<br>
35
+ • <code>message</code> (string, required): The message to send<br>
36
+ • <code>attachments</code> (array, optional): Array of {filename, base64} objects<br>
37
+ • <code>lifetime_hours</code> (number, optional): Chat lifetime in hours (default: 24)
38
+ </p>
39
+ <p style="margin: 0; color: var(--color-text-secondary); font-size: 14px;">
40
+ <strong>Headers:</strong> <code>X-API-KEY</code> (required), <code>Content-Type: application/json</code>
41
+ </p>
42
+ </div>
43
+
44
+ <!-- JavaScript Examples -->
45
+ <h3 style="margin: 20px 0 12px 0; color: var(--color-text-primary);">JavaScript Examples</h3>
46
+
47
+ <h4>Basic Usage Example</h4>
48
+ <div id="api-basic-example"></div>
49
+
50
+ <h4>Conversation Continuation Example</h4>
51
+ <div id="api-continuation-example"></div>
52
+
53
+ <h4>File Attachment Example</h4>
54
+ <div id="api-attachment-example"></div>
55
+ </div>
56
+
57
+ <!-- Section 2: api_log_get Endpoint -->
58
+ <div class="api-section">
59
+ <h2>GET/POST /api_log_get</h2>
60
+ <p style="margin: 0 0 16px 0; color: var(--color-text-secondary); font-size: 14px;">
61
+ Retrieve log data by context ID, limited to a specified number of entries from the newest.
62
+ </p>
63
+
64
+ <!-- API Reference -->
65
+ <h3 style="margin: 20px 0 12px 0; color: var(--color-text-primary);">API Reference</h3>
66
+ <div style="background-color: var(--color-bg-secondary); border: 1px solid var(--color-border); border-radius: 6px; padding: 12px; margin: 0 0 20px 0;">
67
+ <p style="margin: 0 0 8px 0; color: var(--color-text-secondary); font-size: 14px;">
68
+ <strong>Parameters:</strong><br>
69
+ • <code>context_id</code> (string, required): Context ID to get logs from<br>
70
+ • <code>length</code> (integer, optional): Number of log items to return from newest (default: 100)
71
+ </p>
72
+ <p style="margin: 0; color: var(--color-text-secondary); font-size: 14px;">
73
+ <strong>Headers:</strong> <code>X-API-KEY</code> (required), <code>Content-Type: application/json</code> (for POST)
74
+ </p>
75
+ </div>
76
+
77
+ <!-- JavaScript Examples -->
78
+ <h3 style="margin: 20px 0 12px 0; color: var(--color-text-primary);">JavaScript Examples</h3>
79
+
80
+ <h4>GET Request Example</h4>
81
+ <div id="api-log-get-example"></div>
82
+
83
+ <h4>POST Request Example</h4>
84
+ <div id="api-log-post-example"></div>
85
+ </div>
86
+
87
+ <!-- Section 3: api_terminate_chat Endpoint -->
88
+ <div class="api-section">
89
+ <h2>POST /api_terminate_chat</h2>
90
+ <p style="margin: 0 0 16px 0; color: var(--color-text-secondary); font-size: 14px;">
91
+ Terminate and remove a chat context to free up resources. Similar to the MCP finish_chat function.
92
+ </p>
93
+
94
+ <!-- API Reference -->
95
+ <h3 style="margin: 20px 0 12px 0; color: var(--color-text-primary);">API Reference</h3>
96
+ <div style="background-color: var(--color-bg-secondary); border: 1px solid var(--color-border); border-radius: 6px; padding: 12px; margin: 0 0 20px 0;">
97
+ <p style="margin: 0 0 8px 0; color: var(--color-text-secondary); font-size: 14px;">
98
+ <strong>Parameters:</strong><br>
99
+ • <code>context_id</code> (string, required): Context ID of the chat to terminate
100
+ </p>
101
+ <p style="margin: 0; color: var(--color-text-secondary); font-size: 14px;">
102
+ <strong>Headers:</strong> <code>X-API-KEY</code> (required), <code>Content-Type: application/json</code>
103
+ </p>
104
+ </div>
105
+
106
+ <!-- JavaScript Examples -->
107
+ <h3 style="margin: 20px 0 12px 0; color: var(--color-text-primary);">JavaScript Examples</h3>
108
+ <h4>Basic Termination Examples</h4>
109
+ <div id="api-terminate-example"></div>
110
+ </div>
111
+
112
+ <!-- Section 4: api_reset_chat Endpoint -->
113
+ <div class="api-section">
114
+ <h2>POST /api_reset_chat</h2>
115
+ <p style="margin: 0 0 16px 0; color: var(--color-text-secondary); font-size: 14px;">
116
+ Reset a chat context to clear conversation history while keeping the context_id alive for continued use.
117
+ </p>
118
+
119
+ <!-- API Reference -->
120
+ <h3 style="margin: 20px 0 12px 0; color: var(--color-text-primary);">API Reference</h3>
121
+ <div style="background-color: var(--color-bg-secondary); border: 1px solid var(--color-border); border-radius: 6px; padding: 12px; margin: 0 0 20px 0;">
122
+ <p style="margin: 0 0 8px 0; color: var(--color-text-secondary); font-size: 14px;">
123
+ <strong>Parameters:</strong><br>
124
+ • <code>context_id</code> (string, required): Context ID of the chat to reset
125
+ </p>
126
+ <p style="margin: 0; color: var(--color-text-secondary); font-size: 14px;">
127
+ <strong>Headers:</strong> <code>X-API-KEY</code> (required), <code>Content-Type: application/json</code>
128
+ </p>
129
+ </div>
130
+
131
+ <!-- JavaScript Examples -->
132
+ <h3 style="margin: 20px 0 12px 0; color: var(--color-text-primary);">JavaScript Examples</h3>
133
+ <h4>Basic Reset Examples</h4>
134
+ <div id="api-reset-example"></div>
135
+ </div>
136
+
137
+ <!-- Section 5: api_files_get Endpoint -->
138
+ <div class="api-section">
139
+ <h2>POST /api_files_get</h2>
140
+ <p style="margin: 0 0 16px 0; color: var(--color-text-secondary); font-size: 14px;">
141
+ Retrieve file contents by paths, returning files as base64 encoded data. Useful for retrieving uploaded attachments.
142
+ </p>
143
+
144
+ <!-- API Reference -->
145
+ <h3 style="margin: 20px 0 12px 0; color: var(--color-text-primary);">API Reference</h3>
146
+ <div style="background-color: var(--color-bg-secondary); border: 1px solid var(--color-border); border-radius: 6px; padding: 12px; margin: 0 0 20px 0;">
147
+ <p style="margin: 0 0 8px 0; color: var(--color-text-secondary); font-size: 14px;">
148
+ <strong>Parameters:</strong><br>
149
+ • <code>paths</code> (array, required): Array of file paths to retrieve (e.g., ["/a0/tmp/uploads/file.txt"])
150
+ </p>
151
+ <p style="margin: 0; color: var(--color-text-secondary); font-size: 14px;">
152
+ <strong>Headers:</strong> <code>X-API-KEY</code> (required), <code>Content-Type: application/json</code>
153
+ </p>
154
+ </div>
155
+
156
+ <!-- JavaScript Examples -->
157
+ <h3 style="margin: 20px 0 12px 0; color: var(--color-text-primary);">JavaScript Examples</h3>
158
+ <h4>File Retrieval Examples</h4>
159
+ <div id="api-files-get-example"></div>
160
+ </div>
161
+
162
+ <!-- Section 6: Additional Endpoints -->
163
+ <!--
164
+ Example template for new endpoint sections:
165
+
166
+ <div class="api-section">
167
+ <h2>POST /endpoint_name</h2>
168
+ <p style="margin: 0 0 16px 0; color: var(--color-text-secondary); font-size: 14px;">
169
+ Description of what this endpoint does...
170
+ </p>
171
+
172
+ <h3 style="margin: 20px 0 12px 0; color: var(--color-text-primary);">API Reference</h3>
173
+ <div style="background-color: var(--color-bg-secondary); border: 1px solid var(--color-border); border-radius: 6px; padding: 12px; margin: 0 0 20px 0;">
174
+ <p style="margin: 0 0 8px 0; color: var(--color-text-secondary); font-size: 14px;">
175
+ <strong>Parameters:</strong><br>
176
+ • <code>param_name</code> (type, required/optional): Description
177
+ </p>
178
+ <p style="margin: 0; color: var(--color-text-secondary); font-size: 14px;">
179
+ <strong>Headers:</strong> <code>X-API-KEY</code> (required), <code>Content-Type: application/json</code>
180
+ </p>
181
+ </div>
182
+
183
+ <h3 style="margin: 20px 0 12px 0; color: var(--color-text-primary);">JavaScript Examples</h3>
184
+ <h4>Example Title</h4>
185
+ <div id="example-id"></div>
186
+ </div>
187
+ -->
188
+
189
+ <script>
190
+ setTimeout(() => {
191
+ const url = window.location.origin;
192
+ const token = settingsModalProxy.settings.sections.filter(x => x.id == "mcp_server")[0].fields.filter(x => x.id == "mcp_server_token")[0].value;
193
+
194
+ // Basic usage example
195
+ const basicExample = `// Basic message example
196
+ async function sendMessage() {
197
+ try {
198
+ const response = await fetch('${url}/api_message', {
199
+ method: 'POST',
200
+ headers: {
201
+ 'Content-Type': 'application/json',
202
+ 'X-API-KEY': '${token}'
203
+ },
204
+ body: JSON.stringify({
205
+ message: "Hello, how can you help me?",
206
+ lifetime_hours: 24
207
+ })
208
+ });
209
+
210
+ const data = await response.json();
211
+
212
+ if (response.ok) {
213
+ console.log('✅ Success!');
214
+ console.log('Response:', data.response);
215
+ console.log('Context ID:', data.context_id);
216
+ return data;
217
+ } else {
218
+ console.error('❌ Error:', data.error);
219
+ return null;
220
+ }
221
+ } catch (error) {
222
+ console.error('❌ Request failed:', error);
223
+ return null;
224
+ }
225
+ }
226
+
227
+ // Call the function
228
+ sendMessage().then(result => {
229
+ if (result) {
230
+ console.log('Message sent successfully!');
231
+ }
232
+ });`;
233
+
234
+ // Continuation example
235
+ const continuationExample = `// Continue conversation example
236
+ async function continueConversation(contextId) {
237
+ try {
238
+ const response = await fetch('${url}/api_message', {
239
+ method: 'POST',
240
+ headers: {
241
+ 'Content-Type': 'application/json',
242
+ 'X-API-KEY': '${token}'
243
+ },
244
+ body: JSON.stringify({
245
+ context_id: contextId,
246
+ message: "Can you tell me more about that?",
247
+ lifetime_hours: 24
248
+ })
249
+ });
250
+
251
+ const data = await response.json();
252
+
253
+ if (response.ok) {
254
+ console.log('✅ Continuation Success!');
255
+ console.log('Response:', data.response);
256
+ return data;
257
+ } else {
258
+ console.error('❌ Error:', data.error);
259
+ return null;
260
+ }
261
+ } catch (error) {
262
+ console.error('❌ Request failed:', error);
263
+ return null;
264
+ }
265
+ }
266
+
267
+ // Example: First send a message, then continue the conversation
268
+ async function fullConversationExample() {
269
+ const firstResult = await sendMessage();
270
+ if (firstResult && firstResult.context_id) {
271
+ await continueConversation(firstResult.context_id);
272
+ }
273
+ }
274
+
275
+ fullConversationExample();`;
276
+
277
+ // Attachment example
278
+ const attachmentExample = `// File attachment example
279
+ async function sendWithAttachment() {
280
+ try {
281
+ // Example with text content (convert to base64)
282
+ const textContent = "Hello World from attachment!";
283
+ const base64Content = btoa(textContent);
284
+
285
+ const response = await fetch('${url}/api_message', {
286
+ method: 'POST',
287
+ headers: {
288
+ 'Content-Type': 'application/json',
289
+ 'X-API-KEY': '${token}'
290
+ },
291
+ body: JSON.stringify({
292
+ message: "Please analyze this file:",
293
+ attachments: [
294
+ {
295
+ filename: "document.txt",
296
+ base64: base64Content
297
+ }
298
+ ],
299
+ lifetime_hours: 12
300
+ })
301
+ });
302
+
303
+ const data = await response.json();
304
+
305
+ if (response.ok) {
306
+ console.log('✅ File sent successfully!');
307
+ console.log('Response:', data.response);
308
+ return data;
309
+ } else {
310
+ console.error('❌ Error:', data.error);
311
+ return null;
312
+ }
313
+ } catch (error) {
314
+ console.error('❌ Request failed:', error);
315
+ return null;
316
+ }
317
+ }
318
+
319
+ // Call the function
320
+ sendWithAttachment();`;
321
+
322
+ // Log GET example
323
+ const logGetExample = `// Get logs using GET request
324
+ async function getLogsGET(contextId, length = 50) {
325
+ try {
326
+ const params = new URLSearchParams({
327
+ context_id: contextId,
328
+ length: length.toString()
329
+ });
330
+
331
+ const response = await fetch('${url}/api_log_get?' + params, {
332
+ method: 'GET',
333
+ headers: {
334
+ 'X-API-KEY': '${token}'
335
+ }
336
+ });
337
+
338
+ const data = await response.json();
339
+
340
+ if (response.ok) {
341
+ console.log('✅ Logs retrieved successfully!');
342
+ console.log('Total items:', data.log.total_items);
343
+ console.log('Returned items:', data.log.returned_items);
344
+ console.log('Log items:', data.log.items);
345
+ return data;
346
+ } else {
347
+ console.error('❌ Error:', data.error);
348
+ return null;
349
+ }
350
+ } catch (error) {
351
+ console.error('❌ Request failed:', error);
352
+ return null;
353
+ }
354
+ }
355
+
356
+ // Example usage
357
+ getLogsGET('ctx_abc123', 20);`;
358
+
359
+ // Log POST example
360
+ const logPostExample = `// Get logs using POST request
361
+ async function getLogsPOST(contextId, length = 50) {
362
+ try {
363
+ const response = await fetch('${url}/api_log_get', {
364
+ method: 'POST',
365
+ headers: {
366
+ 'Content-Type': 'application/json',
367
+ 'X-API-KEY': '${token}'
368
+ },
369
+ body: JSON.stringify({
370
+ context_id: contextId,
371
+ length: length
372
+ })
373
+ });
374
+
375
+ const data = await response.json();
376
+
377
+ if (response.ok) {
378
+ console.log('✅ Logs retrieved successfully!');
379
+ console.log('Context ID:', data.context_id);
380
+ console.log('Log GUID:', data.log.guid);
381
+ console.log('Total items:', data.log.total_items);
382
+ console.log('Returned items:', data.log.returned_items);
383
+ console.log('Start position:', data.log.start_position);
384
+ console.log('Progress:', data.log.progress);
385
+ console.log('Log items:', data.log.items);
386
+ return data;
387
+ } else {
388
+ console.error('❌ Error:', data.error);
389
+ return null;
390
+ }
391
+ } catch (error) {
392
+ console.error('❌ Request failed:', error);
393
+ return null;
394
+ }
395
+ }
396
+
397
+ // Example usage - get latest 10 log entries
398
+ getLogsPOST('ctx_abc123', 10);`;
399
+
400
+ // Terminate chat example
401
+ const terminateExample = `// Basic terminate chat function
402
+ async function terminateChat(contextId) {
403
+ try {
404
+ const response = await fetch('${url}/api_terminate_chat', {
405
+ method: 'POST',
406
+ headers: {
407
+ 'Content-Type': 'application/json',
408
+ 'X-API-KEY': '${token}'
409
+ },
410
+ body: JSON.stringify({
411
+ context_id: contextId
412
+ })
413
+ });
414
+
415
+ const data = await response.json();
416
+
417
+ if (response.ok) {
418
+ console.log('✅ Chat deleted successfully!');
419
+ console.log('Message:', data.message);
420
+ return data;
421
+ } else {
422
+ console.error('❌ Error:', data.error);
423
+ return null;
424
+ }
425
+ } catch (error) {
426
+ console.error('❌ Request failed:', error);
427
+ return null;
428
+ }
429
+ }
430
+
431
+ // Example 1: Terminate a specific chat
432
+ terminateChat('ctx_abc123');
433
+
434
+ // Example 2: Complete workflow - send message, then terminate
435
+ async function simpleWorkflow() {
436
+ // Send a message
437
+ const result = await sendMessage();
438
+
439
+ if (result && result.context_id) {
440
+ console.log('Chat created:', result.context_id);
441
+
442
+ // Do some work with the chat...
443
+ // await continueConversation(result.context_id);
444
+
445
+ // Clean up when done
446
+ await terminateChat(result.context_id);
447
+ console.log('Chat cleaned up');
448
+ }
449
+ }
450
+
451
+ // Run the workflow
452
+ simpleWorkflow();`;
453
+
454
+ // Reset chat example
455
+ const resetExample = `// Basic reset chat function
456
+ async function resetChat(contextId) {
457
+ try {
458
+ const response = await fetch('${url}/api_reset_chat', {
459
+ method: 'POST',
460
+ headers: {
461
+ 'Content-Type': 'application/json',
462
+ 'X-API-KEY': '${token}'
463
+ },
464
+ body: JSON.stringify({
465
+ context_id: contextId
466
+ })
467
+ });
468
+
469
+ const data = await response.json();
470
+
471
+ if (response.ok) {
472
+ console.log('✅ Chat reset successfully!');
473
+ console.log('Message:', data.message);
474
+ console.log('Context ID:', data.context_id);
475
+ return data;
476
+ } else {
477
+ console.error('❌ Error:', data.error);
478
+ return null;
479
+ }
480
+ } catch (error) {
481
+ console.error('❌ Request failed:', error);
482
+ return null;
483
+ }
484
+ }
485
+
486
+ // Example 1: Reset a specific chat
487
+ resetChat('ctx_abc123');
488
+
489
+ // Example 2: Reset and continue conversation
490
+ async function resetAndContinue() {
491
+ const contextId = 'ctx_abc123';
492
+
493
+ // Reset the chat to clear history
494
+ const resetResult = await resetChat(contextId);
495
+
496
+ if (resetResult) {
497
+ console.log('Chat reset, starting fresh conversation...');
498
+
499
+ // Continue with same context_id but fresh history
500
+ const response = await fetch('${url}/api_message', {
501
+ method: 'POST',
502
+ headers: {
503
+ 'Content-Type': 'application/json',
504
+ 'X-API-KEY': '${token}'
505
+ },
506
+ body: JSON.stringify({
507
+ context_id: contextId, // Same context ID
508
+ message: "Hello, this is a fresh start!",
509
+ lifetime_hours: 24
510
+ })
511
+ });
512
+
513
+ const data = await response.json();
514
+ console.log('New conversation started:', data.response);
515
+ }
516
+ }
517
+
518
+ // Run the example
519
+ resetAndContinue();`;
520
+
521
+ // Files get example
522
+ const filesGetExample = `// Basic file retrieval
523
+ async function getFiles(filePaths) {
524
+ try {
525
+ const response = await fetch('${url}/api_files_get', {
526
+ method: 'POST',
527
+ headers: {
528
+ 'Content-Type': 'application/json',
529
+ 'X-API-KEY': '${token}'
530
+ },
531
+ body: JSON.stringify({
532
+ paths: filePaths
533
+ })
534
+ });
535
+
536
+ const data = await response.json();
537
+
538
+ if (response.ok) {
539
+ console.log('✅ Files retrieved successfully!');
540
+ console.log('Retrieved files:', Object.keys(data));
541
+
542
+ // Convert base64 back to text for display
543
+ for (const [filename, base64Content] of Object.entries(data)) {
544
+ try {
545
+ const textContent = atob(base64Content);
546
+ console.log(\`\${filename}: \${textContent.substring(0, 100)}...\`);
547
+ } catch (e) {
548
+ console.log(\`\${filename}: Binary file (\${base64Content.length} chars)\`);
549
+ }
550
+ }
551
+
552
+ return data;
553
+ } else {
554
+ console.error('❌ Error:', data.error);
555
+ return null;
556
+ }
557
+ } catch (error) {
558
+ console.error('❌ Request failed:', error);
559
+ return null;
560
+ }
561
+ }
562
+
563
+ // Example 1: Get specific files
564
+ const filePaths = [
565
+ "/a0/tmp/uploads/document.txt",
566
+ "/a0/tmp/uploads/data.json"
567
+ ];
568
+ getFiles(filePaths);
569
+
570
+ // Example 2: Complete attachment workflow
571
+ async function attachmentWorkflow() {
572
+ // Step 1: Send message with attachments
573
+ const messageResponse = await fetch('${url}/api_message', {
574
+ method: 'POST',
575
+ headers: {
576
+ 'Content-Type': 'application/json',
577
+ 'X-API-KEY': '${token}'
578
+ },
579
+ body: JSON.stringify({
580
+ message: "Please analyze this file",
581
+ attachments: [{
582
+ filename: "test.txt",
583
+ base64: btoa("Hello, this is test content!")
584
+ }],
585
+ lifetime_hours: 1
586
+ })
587
+ });
588
+
589
+ if (messageResponse.ok) {
590
+ console.log('Message sent with attachment');
591
+
592
+ // Step 2: Retrieve the uploaded file
593
+ const retrievedFiles = await getFiles(["/a0/tmp/uploads/test.txt"]);
594
+
595
+ if (retrievedFiles && retrievedFiles["test.txt"]) {
596
+ const originalContent = atob(retrievedFiles["test.txt"]);
597
+ console.log('Retrieved content:', originalContent);
598
+ }
599
+ }
600
+ }
601
+
602
+ // Run the complete workflow
603
+ attachmentWorkflow();`;
604
+
605
+ // Initialize ACE editors
606
+ const editors = [
607
+ { id: "api-basic-example", content: basicExample },
608
+ { id: "api-continuation-example", content: continuationExample },
609
+ { id: "api-attachment-example", content: attachmentExample },
610
+ { id: "api-log-get-example", content: logGetExample },
611
+ { id: "api-log-post-example", content: logPostExample },
612
+ { id: "api-terminate-example", content: terminateExample },
613
+ { id: "api-reset-example", content: resetExample },
614
+ { id: "api-files-get-example", content: filesGetExample }
615
+ ];
616
+
617
+ editors.forEach(({ id, content }) => {
618
+ const editor = ace.edit(id);
619
+ const dark = localStorage.getItem("darkMode");
620
+ if (dark != "false") {
621
+ editor.setTheme("ace/theme/github_dark");
622
+ } else {
623
+ editor.setTheme("ace/theme/tomorrow");
624
+ }
625
+ editor.session.setMode("ace/mode/javascript");
626
+ editor.setValue(content);
627
+ editor.clearSelection();
628
+ editor.setReadOnly(true);
629
+ });
630
+ }, 0);
631
+ </script>
632
+ </div>
633
+
634
+ <style>
635
+ #api-basic-example,
636
+ #api-continuation-example,
637
+ #api-attachment-example,
638
+ #api-log-get-example,
639
+ #api-log-post-example,
640
+ #api-terminate-example,
641
+ #api-reset-example,
642
+ #api-files-get-example {
643
+ width: 100%;
644
+ height: 20em;
645
+ margin: 8px 0 16px 0;
646
+ border-radius: 4px;
647
+ }
648
+
649
+ /* Section styling */
650
+ .api-section {
651
+ border: 1px solid var(--color-border);
652
+ border-radius: 8px;
653
+ margin: 20px 0;
654
+ padding: 16px;
655
+ }
656
+
657
+ .api-section h2 {
658
+ margin: 0 0 16px 0;
659
+ color: var(--color-text-primary);
660
+ border-bottom: 1px solid var(--color-border);
661
+ padding-bottom: 8px;
662
+ }
663
+
664
+ .api-section h3 {
665
+ margin: 20px 0 12px 0;
666
+ color: var(--color-text-primary);
667
+ font-size: 1.2em;
668
+ }
669
+
670
+ .api-section h4 {
671
+ margin: 16px 0 8px 0;
672
+ color: var(--color-text-primary);
673
+ }
674
+ </style>
675
+
676
+ </body>
677
+
678
+ </html>
webui/components/settings/mcp/server/example.html CHANGED
@@ -10,6 +10,15 @@
10
  <p>Agent Zero MCP Server is an SSE MCP running on the same URL and port as the Web UI + /mcp/sse path.</p>
11
  <p>The same applies if you run A0 on a public URL using a tunnel.</p>
12
 
 
 
 
 
 
 
 
 
 
13
  <h3>Example MCP Server Configuration JSON</h3>
14
  <div id="mcp-server-example"></div>
15
 
 
10
  <p>Agent Zero MCP Server is an SSE MCP running on the same URL and port as the Web UI + /mcp/sse path.</p>
11
  <p>The same applies if you run A0 on a public URL using a tunnel.</p>
12
 
13
+ <!-- API Token Information -->
14
+ <div style="background-color: var(--color-bg-secondary); border: 1px solid var(--color-border); border-radius: 6px; padding: 12px; margin: 16px 0;">
15
+ <h4 style="margin: 0 0 8px 0; color: var(--color-text-primary);">API Token Information</h4>
16
+ <p style="margin: 0; color: var(--color-text-secondary); font-size: 14px;">
17
+ The token used in the URL is automatically generated from your username and password.
18
+ This same token is also used for external API endpoints. The token changes when you update your credentials.
19
+ </p>
20
+ </div>
21
+
22
  <h3>Example MCP Server Configuration JSON</h3>
23
  <div id="mcp-server-example"></div>
24
 
webui/index.html CHANGED
@@ -20,9 +20,6 @@
20
  <link rel="stylesheet" href="css/tunnel.css">
21
  <link rel="stylesheet" href="css/notification.css">
22
 
23
- <!-- Font Awesome for icons -->
24
- <link rel="stylesheet" href="vendor/font-awesome/all.min.css">
25
-
26
  <!-- Flatpickr for datetime picker -->
27
  <link rel="stylesheet" href="vendor/flatpickr/flatpickr.min.css">
28
  <script src="vendor/flatpickr/flatpickr.min.js"></script>
@@ -111,8 +108,8 @@
111
  <!-- <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.14.3/dist/cdn.min.js"></script> -->
112
  <script type="module" src="js/initFw.js"></script>
113
 
114
- <script src="vendor/ace/ace.js"></script>
115
- <link href="vendor/ace/ace.min.css" rel="stylesheet">
116
  <!-- KaTeX CSS -->
117
  <link rel="stylesheet" href="vendor/katex/katex.min.css" crossorigin="anonymous">
118
 
@@ -554,7 +551,7 @@
554
  <div class="settings-tab"
555
  :class="{'active': activeTab === 'mcp'}"
556
  @click="switchTab('mcp')"
557
- title="MCP">MCP</div>
558
  <div class="settings-tab"
559
  :class="{'active': activeTab === 'developer'}"
560
  @click="switchTab('developer')"
@@ -626,6 +623,8 @@
626
  <template x-if="field.type === 'password'">
627
  <input type="password" :class="field.classes" :value="field.value"
628
  :readonly="field.readonly === true"
 
 
629
  @input="field.value = $event.target.value">
630
  </template>
631
 
 
20
  <link rel="stylesheet" href="css/tunnel.css">
21
  <link rel="stylesheet" href="css/notification.css">
22
 
 
 
 
23
  <!-- Flatpickr for datetime picker -->
24
  <link rel="stylesheet" href="vendor/flatpickr/flatpickr.min.css">
25
  <script src="vendor/flatpickr/flatpickr.min.js"></script>
 
108
  <!-- <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.14.3/dist/cdn.min.js"></script> -->
109
  <script type="module" src="js/initFw.js"></script>
110
 
111
+ <script src="vendor/ace-min/ace.js"></script>
112
+ <link href="vendor/ace-min/ace.min.css" rel="stylesheet">
113
  <!-- KaTeX CSS -->
114
  <link rel="stylesheet" href="vendor/katex/katex.min.css" crossorigin="anonymous">
115
 
 
551
  <div class="settings-tab"
552
  :class="{'active': activeTab === 'mcp'}"
553
  @click="switchTab('mcp')"
554
+ title="MCP">MCP/A2A</div>
555
  <div class="settings-tab"
556
  :class="{'active': activeTab === 'developer'}"
557
  @click="switchTab('developer')"
 
623
  <template x-if="field.type === 'password'">
624
  <input type="password" :class="field.classes" :value="field.value"
625
  :readonly="field.readonly === true"
626
+ :id="field.id"
627
+ autocomplete="off"
628
  @input="field.value = $event.target.value">
629
  </template>
630
 
webui/js/settings.js CHANGED
@@ -291,8 +291,9 @@ const settingsModalProxy = {
291
  } else if (field.id === "backup_restore") {
292
  openModal("settings/backup/restore.html");
293
  } else if (field.id === "show_a2a_connection") {
294
- console.log('Opening A2A connection modal...');
295
  openModal("settings/external/a2a-connection.html");
 
 
296
  }
297
  }
298
  };
 
291
  } else if (field.id === "backup_restore") {
292
  openModal("settings/backup/restore.html");
293
  } else if (field.id === "show_a2a_connection") {
 
294
  openModal("settings/external/a2a-connection.html");
295
+ } else if (field.id === "external_api_examples") {
296
+ openModal("settings/external/api-examples.html");
297
  }
298
  }
299
  };
webui/public/a2a_server.svg CHANGED
webui/public/code_exec.svg ADDED
webui/public/external_api.svg ADDED
webui/vendor/ace-min/ace.js ADDED
The diff for this file is too large to render. See raw diff
 
webui/vendor/ace-min/ext-beautify [conflicted].js ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ define("ace/ext/beautify",["require","exports","module","ace/token_iterator"],function(e,t,n){"use strict";function i(e,t){return e.type.lastIndexOf(t+".xml")>-1}var r=e("../token_iterator").TokenIterator;t.singletonTags=["area","base","br","col","command","embed","hr","html","img","input","keygen","link","meta","param","source","track","wbr"],t.blockTags=["article","aside","blockquote","body","div","dl","fieldset","footer","form","head","header","html","nav","ol","p","script","section","style","table","tbody","tfoot","thead","ul"],t.formatOptions={lineBreaksAfterCommasInCurlyBlock:!0},t.beautify=function(e){var n=new r(e,0,0),s=n.getCurrentToken(),o=e.getTabString(),u=t.singletonTags,a=t.blockTags,f=t.formatOptions||{},l,c=!1,h=!1,p=!1,d="",v="",m="",g=0,y=0,b=0,w=0,E=0,S=0,x=0,T,N=0,C=0,k=[],L=!1,A,O=!1,M=!1,_=!1,D=!1,P={0:0},H=[],B=!1,j=function(){l&&l.value&&l.type!=="string.regexp"&&(l.value=l.value.replace(/^\s*/,""))},F=function(){var e=d.length-1;for(;;){if(e==0)break;if(d[e]!==" ")break;e-=1}d=d.slice(0,e+1)},I=function(){d=d.trimRight(),c=!1};while(s!==null){N=n.getCurrentTokenRow(),k=n.$rowTokens,l=n.stepForward();if(typeof s!="undefined"){v=s.value,E=0,_=m==="style"||e.$modeId==="ace/mode/css",i(s,"tag-open")?(M=!0,l&&(D=a.indexOf(l.value)!==-1),v==="</"&&(D&&!c&&C<1&&C++,_&&(C=1),E=1,D=!1)):i(s,"tag-close")?M=!1:i(s,"comment.start")?D=!0:i(s,"comment.end")&&(D=!1),!M&&!C&&s.type==="paren.rparen"&&s.value.substr(0,1)==="}"&&C++,N!==T&&(C=N,T&&(C-=T));if(C){I();for(;C>0;C--)d+="\n";c=!0,!i(s,"comment")&&!s.type.match(/^(comment|string)$/)&&(v=v.trimLeft())}if(v){s.type==="keyword"&&v.match(/^(if|else|elseif|for|foreach|while|switch)$/)?(H[g]=v,j(),p=!0,v.match(/^(else|elseif)$/)&&d.match(/\}[\s]*$/)&&(I(),h=!0)):s.type==="paren.lparen"?(j(),v.substr(-1)==="{"&&(p=!0,O=!1,M||(C=1)),v.substr(0,1)==="{"&&(h=!0,d.substr(-1)!=="["&&d.trimRight().substr(-1)==="["?(I(),h=!1):d.trimRight().substr(-1)===")"?I():F())):s.type==="paren.rparen"?(E=1,v.substr(0,1)==="}"&&(H[g-1]==="case"&&E++,d.trimRight().substr(-1)==="{"?I():(h=!0,_&&(C+=2))),v.substr(0,1)==="]"&&d.substr(-1)!=="}"&&d.trimRight().substr(-1)==="}"&&(h=!1,w++,I()),v.substr(0,1)===")"&&d.substr(-1)!=="("&&d.trimRight().substr(-1)==="("&&(h=!1,w++,I()),F()):s.type!=="keyword.operator"&&s.type!=="keyword"||!v.match(/^(=|==|===|!=|!==|&&|\|\||and|or|xor|\+=|.=|>|>=|<|<=|=>)$/)?s.type==="punctuation.operator"&&v===";"?(I(),j(),p=!0,_&&C++):s.type==="punctuation.operator"&&v.match(/^(:|,)$/)?(I(),j(),v.match(/^(,)$/)&&x>0&&S===0&&f.lineBreaksAfterCommasInCurlyBlock?C++:(p=!0,c=!1)):s.type==="support.php_tag"&&v==="?>"&&!c?(I(),h=!0):i(s,"attribute-name")&&d.substr(-1).match(/^\s$/)?h=!0:i(s,"attribute-equals")?(F(),j()):i(s,"tag-close")?(F(),v==="/>"&&(h=!0)):s.type==="keyword"&&v.match(/^(case|default)$/)&&B&&(E=1):(I(),j(),h=!0,p=!0);if(c&&(!s.type.match(/^(comment)$/)||!!v.substr(0,1).match(/^[/#]$/))&&(!s.type.match(/^(string)$/)||!!v.substr(0,1).match(/^['"@]$/))){w=b;if(g>y){w++;for(A=g;A>y;A--)P[A]=w}else g<y&&(w=P[g]);y=g,b=w,E&&(w-=E),O&&!S&&(w++,O=!1);for(A=0;A<w;A++)d+=o}s.type==="keyword"&&v.match(/^(case|default)$/)?B===!1&&(H[g]=v,g++,B=!0):s.type==="keyword"&&v.match(/^(break)$/)&&H[g-1]&&H[g-1].match(/^(case|default)$/)&&(g--,B=!1),s.type==="paren.lparen"&&(S+=(v.match(/\(/g)||[]).length,x+=(v.match(/\{/g)||[]).length,g+=v.length),s.type==="keyword"&&v.match(/^(if|else|elseif|for|while)$/)?(O=!0,S=0):!S&&v.trim()&&s.type!=="comment"&&(O=!1);if(s.type==="paren.rparen"){S-=(v.match(/\)/g)||[]).length,x-=(v.match(/\}/g)||[]).length;for(A=0;A<v.length;A++)g--,v.substr(A,1)==="}"&&H[g]==="case"&&g--}s.type=="text"&&(v=v.replace(/\s+$/," ")),h&&!c&&(F(),d.substr(-1)!=="\n"&&(d+=" ")),d+=v,p&&(d+=" "),c=!1,h=!1,p=!1;if(i(s,"tag-close")&&(D||a.indexOf(m)!==-1)||i(s,"doctype")&&v===">")D&&l&&l.value==="</"?C=-1:C=1;l&&u.indexOf(l.value)===-1&&(i(s,"tag-open")&&v==="</"?g--:i(s,"tag-open")&&v==="<"?g++:i(s,"tag-close")&&v==="/>"&&g--),i(s,"tag-name")&&(m=v),T=N}}s=l}d=d.trim(),e.doc.setValue(d)},t.commands=[{name:"beautify",description:"Format selection (Beautify)",exec:function(e){t.beautify(e.session)},bindKey:"Ctrl-Shift-B"}]}); (function() {
2
+ window.require(["ace/ext/beautify"], function(m) {
3
+ if (typeof module == "object" && typeof exports == "object" && module) {
4
+ module.exports = m;
5
+ }
6
+ });
7
+ })();
8
+
webui/vendor/ace-min/ext-beautify.js ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ define("ace/ext/beautify",["require","exports","module","ace/token_iterator"],function(e,t,n){"use strict";function i(e,t){return e.type.lastIndexOf(t+".xml")>-1}var r=e("../token_iterator").TokenIterator;t.singletonTags=["area","base","br","col","command","embed","hr","html","img","input","keygen","link","meta","param","source","track","wbr"],t.blockTags=["article","aside","blockquote","body","div","dl","fieldset","footer","form","head","header","html","nav","ol","p","script","section","style","table","tbody","tfoot","thead","ul"],t.formatOptions={lineBreaksAfterCommasInCurlyBlock:!0},t.beautify=function(e){var n=new r(e,0,0),s=n.getCurrentToken(),o=e.getTabString(),u=t.singletonTags,a=t.blockTags,f=t.formatOptions||{},l,c=!1,h=!1,p=!1,d="",v="",m="",g=0,y=0,b=0,w=0,E=0,S=0,x=0,T,N=0,C=0,k=[],L=!1,A,O=!1,M=!1,_=!1,D=!1,P={0:0},H=[],B=!1,j=function(){l&&l.value&&l.type!=="string.regexp"&&(l.value=l.value.replace(/^\s*/,""))},F=function(){var e=d.length-1;for(;;){if(e==0)break;if(d[e]!==" ")break;e-=1}d=d.slice(0,e+1)},I=function(){d=d.trimRight(),c=!1};while(s!==null){N=n.getCurrentTokenRow(),k=n.$rowTokens,l=n.stepForward();if(typeof s!="undefined"){v=s.value,E=0,_=m==="style"||e.$modeId==="ace/mode/css",i(s,"tag-open")?(M=!0,l&&(D=a.indexOf(l.value)!==-1),v==="</"&&(D&&!c&&C<1&&C++,_&&(C=1),E=1,D=!1)):i(s,"tag-close")?M=!1:i(s,"comment.start")?D=!0:i(s,"comment.end")&&(D=!1),!M&&!C&&s.type==="paren.rparen"&&s.value.substr(0,1)==="}"&&C++,N!==T&&(C=N,T&&(C-=T));if(C){I();for(;C>0;C--)d+="\n";c=!0,!i(s,"comment")&&!s.type.match(/^(comment|string)$/)&&(v=v.trimLeft())}if(v){s.type==="keyword"&&v.match(/^(if|else|elseif|for|foreach|while|switch)$/)?(H[g]=v,j(),p=!0,v.match(/^(else|elseif)$/)&&d.match(/\}[\s]*$/)&&(I(),h=!0)):s.type==="paren.lparen"?(j(),v.substr(-1)==="{"&&(p=!0,O=!1,M||(C=1)),v.substr(0,1)==="{"&&(h=!0,d.substr(-1)!=="["&&d.trimRight().substr(-1)==="["?(I(),h=!1):d.trimRight().substr(-1)===")"?I():F())):s.type==="paren.rparen"?(E=1,v.substr(0,1)==="}"&&(H[g-1]==="case"&&E++,d.trimRight().substr(-1)==="{"?I():(h=!0,_&&(C+=2))),v.substr(0,1)==="]"&&d.substr(-1)!=="}"&&d.trimRight().substr(-1)==="}"&&(h=!1,w++,I()),v.substr(0,1)===")"&&d.substr(-1)!=="("&&d.trimRight().substr(-1)==="("&&(h=!1,w++,I()),F()):s.type!=="keyword.operator"&&s.type!=="keyword"||!v.match(/^(=|==|===|!=|!==|&&|\|\||and|or|xor|\+=|.=|>|>=|<|<=|=>)$/)?s.type==="punctuation.operator"&&v===";"?(I(),j(),p=!0,_&&C++):s.type==="punctuation.operator"&&v.match(/^(:|,)$/)?(I(),j(),v.match(/^(,)$/)&&x>0&&S===0&&f.lineBreaksAfterCommasInCurlyBlock?C++:(p=!0,c=!1)):s.type==="support.php_tag"&&v==="?>"&&!c?(I(),h=!0):i(s,"attribute-name")&&d.substr(-1).match(/^\s$/)?h=!0:i(s,"attribute-equals")?(F(),j()):i(s,"tag-close")?(F(),v==="/>"&&(h=!0)):s.type==="keyword"&&v.match(/^(case|default)$/)&&B&&(E=1):(I(),j(),h=!0,p=!0);if(c&&(!s.type.match(/^(comment)$/)||!!v.substr(0,1).match(/^[/#]$/))&&(!s.type.match(/^(string)$/)||!!v.substr(0,1).match(/^['"@]$/))){w=b;if(g>y){w++;for(A=g;A>y;A--)P[A]=w}else g<y&&(w=P[g]);y=g,b=w,E&&(w-=E),O&&!S&&(w++,O=!1);for(A=0;A<w;A++)d+=o}s.type==="keyword"&&v.match(/^(case|default)$/)?B===!1&&(H[g]=v,g++,B=!0):s.type==="keyword"&&v.match(/^(break)$/)&&H[g-1]&&H[g-1].match(/^(case|default)$/)&&(g--,B=!1),s.type==="paren.lparen"&&(S+=(v.match(/\(/g)||[]).length,x+=(v.match(/\{/g)||[]).length,g+=v.length),s.type==="keyword"&&v.match(/^(if|else|elseif|for|while)$/)?(O=!0,S=0):!S&&v.trim()&&s.type!=="comment"&&(O=!1);if(s.type==="paren.rparen"){S-=(v.match(/\)/g)||[]).length,x-=(v.match(/\}/g)||[]).length;for(A=0;A<v.length;A++)g--,v.substr(A,1)==="}"&&H[g]==="case"&&g--}s.type=="text"&&(v=v.replace(/\s+$/," ")),h&&!c&&(F(),d.substr(-1)!=="\n"&&(d+=" ")),d+=v,p&&(d+=" "),c=!1,h=!1,p=!1;if(i(s,"tag-close")&&(D||a.indexOf(m)!==-1)||i(s,"doctype")&&v===">")D&&l&&l.value==="</"?C=-1:C=1;l&&u.indexOf(l.value)===-1&&(i(s,"tag-open")&&v==="</"?g--:i(s,"tag-open")&&v==="<"?g++:i(s,"tag-close")&&v==="/>"&&g--),i(s,"tag-name")&&(m=v),T=N}}s=l}d=d.trim(),e.doc.setValue(d)},t.commands=[{name:"beautify",description:"Format selection (Beautify)",exec:function(e){t.beautify(e.session)},bindKey:"Ctrl-Shift-B"}]}); (function() {
2
+ window.require(["ace/ext/beautify"], function(m) {
3
+ if (typeof module == "object" && typeof exports == "object" && module) {
4
+ module.exports = m;
5
+ }
6
+ });
7
+ })();
8
+
webui/vendor/ace-min/ext-code_lens.js ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ define("ace/ext/code_lens",["require","exports","module","ace/lib/event","ace/lib/lang","ace/lib/dom","ace/editor","ace/config"],function(e,t,n){"use strict";function o(e){var t=e.$textLayer,n=t.$lenses;n&&n.forEach(function(e){e.remove()}),t.$lenses=null}function u(e,t){var n=e&t.CHANGE_LINES||e&t.CHANGE_FULL||e&t.CHANGE_SCROLL||e&t.CHANGE_TEXT;if(!n)return;var r=t.session,i=t.session.lineWidgets,u=t.$textLayer,a=u.$lenses;if(!i){a&&o(t);return}var f=t.$textLayer.$lines.cells,l=t.layerConfig,c=t.$padding;a||(a=u.$lenses=[]);var h=0;for(var p=0;p<f.length;p++){var d=f[p].row,v=i[d],m=v&&v.lenses;if(!m||!m.length)continue;var g=a[h];g||(g=a[h]=s.buildDom(["div",{"class":"ace_codeLens"}],t.container)),g.style.height=l.lineHeight+"px",h++;for(var y=0;y<m.length;y++){var b=g.childNodes[2*y];b||(y!=0&&g.appendChild(s.createTextNode("\u00a0|\u00a0")),b=s.buildDom(["a"],g)),b.textContent=m[y].title,b.lensCommand=m[y]}while(g.childNodes.length>2*y-1)g.lastChild.remove();var w=t.$cursorLayer.getPixelPosition({row:d,column:0},!0).top-l.lineHeight*v.rowsAbove-l.offset;g.style.top=w+"px";var E=t.gutterWidth,S=r.getLine(d).search(/\S|$/);S==-1&&(S=0),E+=S*l.characterWidth,g.style.paddingLeft=c+E+"px"}while(h<a.length)a.pop().remove()}function a(e){if(!e.lineWidgets)return;var t=e.widgetManager;e.lineWidgets.forEach(function(e){e&&e.lenses&&t.removeLineWidget(e)})}function f(e){e.codeLensProviders=[],e.renderer.on("afterRender",u),e.$codeLensClickHandler||(e.$codeLensClickHandler=function(t){var n=t.target.lensCommand;if(!n)return;e.execCommand(n.id,n.arguments),e._emit("codeLensClick",t)},r.addListener(e.container,"click",e.$codeLensClickHandler,e)),e.$updateLenses=function(){function s(){var r=n.selection.cursor,s=n.documentToScreenRow(r),o=n.getScrollTop(),u=t.setLenses(n,i),a=n.$undoManager&&n.$undoManager.$lastDelta;if(a&&a.action=="remove"&&a.lines.length>1)return;var f=n.documentToScreenRow(r),l=e.renderer.layerConfig.lineHeight,c=n.getScrollTop()+(f-s)*l;u==0&&o<l/4&&o>-l/4&&(c=-l),n.setScrollTop(c)}var n=e.session;if(!n)return;var r=e.codeLensProviders.length,i=[];e.codeLensProviders.forEach(function(e){e.provideCodeLenses(n,function(e,t){if(e)return;t.forEach(function(e){i.push(e)}),r--,r==0&&s()})})};var n=i.delayedCall(e.$updateLenses);e.$updateLensesOnInput=function(){n.delay(250)},e.on("input",e.$updateLensesOnInput)}function l(e){e.off("input",e.$updateLensesOnInput),e.renderer.off("afterRender",u),e.$codeLensClickHandler&&e.container.removeEventListener("click",e.$codeLensClickHandler)}var r=e("../lib/event"),i=e("../lib/lang"),s=e("../lib/dom");t.setLenses=function(e,t){var n=Number.MAX_VALUE;return a(e),t&&t.forEach(function(t){var r=t.start.row,i=t.start.column,s=e.lineWidgets&&e.lineWidgets[r];if(!s||!s.lenses)s=e.widgetManager.$registerLineWidget({rowCount:1,rowsAbove:1,row:r,column:i,lenses:[]});s.lenses.push(t.command),r<n&&(n=r)}),e._emit("changeFold",{data:{start:{row:n}}}),n},t.registerCodeLensProvider=function(e,t){e.setOption("enableCodeLens",!0),e.codeLensProviders.push(t),e.$updateLensesOnInput()},t.clear=function(e){t.setLenses(e,null)};var c=e("../editor").Editor;e("../config").defineOptions(c.prototype,"editor",{enableCodeLens:{set:function(e){e?f(this):l(this)}}}),s.importCssString("\n.ace_codeLens {\n position: absolute;\n color: #aaa;\n font-size: 88%;\n background: inherit;\n width: 100%;\n display: flex;\n align-items: flex-end;\n pointer-events: none;\n}\n.ace_codeLens > a {\n cursor: pointer;\n pointer-events: auto;\n}\n.ace_codeLens > a:hover {\n color: #0000ff;\n text-decoration: underline;\n}\n.ace_dark > .ace_codeLens > a:hover {\n color: #4e94ce;\n}\n","codelense.css",!1)}); (function() {
2
+ window.require(["ace/ext/code_lens"], function(m) {
3
+ if (typeof module == "object" && typeof exports == "object" && module) {
4
+ module.exports = m;
5
+ }
6
+ });
7
+ })();
8
+
webui/vendor/ace-min/ext-command_bar.js ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ define("ace/ext/command_bar",["require","exports","module","ace/tooltip","ace/lib/event_emitter","ace/lib/lang","ace/lib/dom","ace/lib/oop","ace/lib/useragent"],function(e,t,n){var r=this&&this.__values||function(e){var t=typeof Symbol=="function"&&Symbol.iterator,n=t&&e[t],r=0;if(n)return n.call(e);if(e&&typeof e.length=="number")return{next:function(){return e&&r>=e.length&&(e=void 0),{value:e&&e[r++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")},i=e("../tooltip").Tooltip,s=e("../lib/event_emitter").EventEmitter,o=e("../lib/lang"),u=e("../lib/dom"),a=e("../lib/oop"),f=e("../lib/useragent"),l="command_bar_tooltip_button",c="command_bar_button_value",h="command_bar_button_caption",p="command_bar_keybinding",d="command_bar_tooltip",v="MoreOptionsButton",m=100,g=4,y=function(e,t){return t.row>e.row?e:t.row===e.row&&t.column>e.column?e:t},b={Ctrl:{mac:"^"},Option:{mac:"\u2325"},Command:{mac:"\u2318"},Cmd:{mac:"\u2318"},Shift:"\u21e7",Left:"\u2190",Right:"\u2192",Up:"\u2191",Down:"\u2193"},w=function(){function e(e,t){var n,s;t=t||{},this.parentNode=e,this.tooltip=new i(this.parentNode),this.moreOptions=new i(this.parentNode),this.maxElementsOnTooltip=t.maxElementsOnTooltip||g,this.$alwaysShow=t.alwaysShow||!1,this.eventListeners={},this.elements={},this.commands={},this.tooltipEl=u.buildDom(["div",{"class":d}],this.tooltip.getElement()),this.moreOptionsEl=u.buildDom(["div",{"class":d+" tooltip_more_options"}],this.moreOptions.getElement()),this.$showTooltipTimer=o.delayedCall(this.$showTooltip.bind(this),t.showDelay||m),this.$hideTooltipTimer=o.delayedCall(this.$hideTooltip.bind(this),t.hideDelay||m),this.$tooltipEnter=this.$tooltipEnter.bind(this),this.$onMouseMove=this.$onMouseMove.bind(this),this.$onChangeScroll=this.$onChangeScroll.bind(this),this.$onEditorChangeSession=this.$onEditorChangeSession.bind(this),this.$scheduleTooltipForHide=this.$scheduleTooltipForHide.bind(this),this.$preventMouseEvent=this.$preventMouseEvent.bind(this);try{for(var a=r(["mousedown","mouseup","click"]),f=a.next();!f.done;f=a.next()){var l=f.value;this.tooltip.getElement().addEventListener(l,this.$preventMouseEvent),this.moreOptions.getElement().addEventListener(l,this.$preventMouseEvent)}}catch(c){n={error:c}}finally{try{f&&!f.done&&(s=a.return)&&s.call(a)}finally{if(n)throw n.error}}}return e.prototype.registerCommand=function(e,t){var n=Object.keys(this.commands).length<this.maxElementsOnTooltip;!n&&!this.elements[v]&&this.$createCommand(v,{name:"\u00b7\u00b7\u00b7",exec:function(){this.$shouldHideMoreOptions=!1,this.$setMoreOptionsVisibility(!this.isMoreOptionsShown())}.bind(this),type:"checkbox",getValue:function(){return this.isMoreOptionsShown()}.bind(this),enabled:!0},!0),this.$createCommand(e,t,n),this.isShown()&&this.updatePosition()},e.prototype.isShown=function(){return!!this.tooltip&&this.tooltip.isOpen},e.prototype.isMoreOptionsShown=function(){return!!this.moreOptions&&this.moreOptions.isOpen},e.prototype.getAlwaysShow=function(){return this.$alwaysShow},e.prototype.setAlwaysShow=function(e){this.$alwaysShow=e,this.$updateOnHoverHandlers(!this.$alwaysShow),this._signal("alwaysShow",this.$alwaysShow)},e.prototype.attach=function(e){if(!e||this.isShown()&&this.editor===e)return;this.detach(),this.editor=e,this.editor.on("changeSession",this.$onEditorChangeSession),this.editor.session&&(this.editor.session.on("changeScrollLeft",this.$onChangeScroll),this.editor.session.on("changeScrollTop",this.$onChangeScroll)),this.getAlwaysShow()?this.$showTooltip():this.$updateOnHoverHandlers(!0)},e.prototype.updatePosition=function(){if(!this.editor)return;var e=this.editor.renderer,t;this.editor.selection.getAllRanges?t=this.editor.selection.getAllRanges():t=[this.editor.getSelectionRange()];if(!t.length)return;var n=y(t[0].start,t[0].end);for(var r=0,i;i=t[r];r++)n=y(n,y(i.start,i.end));var s=e.$cursorLayer.getPixelPosition(n,!0),o=this.tooltip.getElement(),u=window.innerWidth,a=window.innerHeight,f=this.editor.container.getBoundingClientRect();s.top+=f.top-e.layerConfig.offset,s.left+=f.left+e.gutterWidth-e.scrollLeft;var l=s.top>=f.top&&s.top<=f.bottom&&s.left>=f.left+e.gutterWidth&&s.left<=f.right;if(!l&&this.isShown()){this.$hideTooltip();return}if(l&&!this.isShown()&&this.getAlwaysShow()){this.$showTooltip();return}var c=s.top-o.offsetHeight,h=Math.min(u-o.offsetWidth,s.left),p=c>=0&&c+o.offsetHeight<=a&&h>=0&&h+o.offsetWidth<=u;if(!p){this.$hideTooltip();return}this.tooltip.setPosition(h,c);if(this.isMoreOptionsShown()){c+=o.offsetHeight,h=this.elements[v].getBoundingClientRect().left;var d=this.moreOptions.getElement(),a=window.innerHeight;c+d.offsetHeight>a&&(c-=o.offsetHeight+d.offsetHeight),h+d.offsetWidth>u&&(h=u-d.offsetWidth),this.moreOptions.setPosition(h,c)}},e.prototype.update=function(){Object.keys(this.elements).forEach(this.$updateElement.bind(this))},e.prototype.detach=function(){this.tooltip.hide(),this.moreOptions.hide(),this.$updateOnHoverHandlers(!1),this.editor&&(this.editor.off("changeSession",this.$onEditorChangeSession),this.editor.session&&(this.editor.session.off("changeScrollLeft",this.$onChangeScroll),this.editor.session.off("changeScrollTop",this.$onChangeScroll))),this.$mouseInTooltip=!1,this.editor=null},e.prototype.destroy=function(){this.tooltip&&this.moreOptions&&(this.detach(),this.tooltip.destroy(),this.moreOptions.destroy()),this.eventListeners={},this.commands={},this.elements={},this.tooltip=this.moreOptions=this.parentNode=null},e.prototype.$createCommand=function(e,t,n){var r=n?this.tooltipEl:this.moreOptionsEl,i=[],s=t.bindKey;s&&(typeof s=="object"&&(s=f.isMac?s.mac:s.win),s=s.split("|")[0],i=s.split("-"),i=i.map(function(e){if(b[e]){if(typeof b[e]=="string")return b[e];if(f.isMac&&b[e].mac)return b[e].mac}return e}));var o;n&&t.iconCssClass?o=["div",{"class":["ace_icon_svg",t.iconCssClass].join(" "),"aria-label":t.name+" ("+t.bindKey+")"}]:(o=[["div",{"class":c}],["div",{"class":h},t.name]],i.length&&o.push(["div",{"class":p},i.map(function(e){return["div",e]})])),u.buildDom(["div",{"class":[l,t.cssClass||""].join(" "),ref:e},o],r,this.elements),this.commands[e]=t;var a=function(n){this.editor&&this.editor.focus(),this.$shouldHideMoreOptions=this.isMoreOptionsShown(),!this.elements[e].disabled&&t.exec&&t.exec(this.editor),this.$shouldHideMoreOptions&&this.$setMoreOptionsVisibility(!1),this.update(),n.preventDefault()}.bind(this);this.eventListeners[e]=a,this.elements[e].addEventListener("click",a.bind(this)),this.$updateElement(e)},e.prototype.$setMoreOptionsVisibility=function(e){e?(this.moreOptions.setTheme(this.editor.renderer.theme),this.moreOptions.setClassName(d+"_wrapper"),this.moreOptions.show(),this.update(),this.updatePosition()):this.moreOptions.hide()},e.prototype.$onEditorChangeSession=function(e){e.oldSession&&(e.oldSession.off("changeScrollTop",this.$onChangeScroll),e.oldSession.off("changeScrollLeft",this.$onChangeScroll)),this.detach()},e.prototype.$onChangeScroll=function(){this.editor.renderer&&(this.isShown()||this.getAlwaysShow())&&this.editor.renderer.once("afterRender",this.updatePosition.bind(this))},e.prototype.$onMouseMove=function(e){if(this.$mouseInTooltip)return;var t=this.editor.getCursorPosition(),n=this.editor.renderer.textToScreenCoordinates(t.row,t.column),r=this.editor.renderer.lineHeight,i=e.clientY>=n.pageY&&e.clientY<n.pageY+r;i?(!this.isShown()&&!this.$showTooltipTimer.isPending()&&this.$showTooltipTimer.delay(),this.$hideTooltipTimer.isPending()&&this.$hideTooltipTimer.cancel()):(this.isShown()&&!this.$hideTooltipTimer.isPending()&&this.$hideTooltipTimer.delay(),this.$showTooltipTimer.isPending()&&this.$showTooltipTimer.cancel())},e.prototype.$preventMouseEvent=function(e){this.editor&&this.editor.focus(),e.preventDefault()},e.prototype.$scheduleTooltipForHide=function(){this.$mouseInTooltip=!1,this.$showTooltipTimer.cancel(),this.$hideTooltipTimer.delay()},e.prototype.$tooltipEnter=function(){this.$mouseInTooltip=!0,this.$showTooltipTimer.isPending()&&this.$showTooltipTimer.cancel(),this.$hideTooltipTimer.isPending()&&this.$hideTooltipTimer.cancel()},e.prototype.$updateOnHoverHandlers=function(e){var t=this.tooltip.getElement(),n=this.moreOptions.getElement();e?(this.editor&&(this.editor.on("mousemove",this.$onMouseMove),this.editor.renderer.getMouseEventTarget().addEventListener("mouseout",this.$scheduleTooltipForHide,!0)),t.addEventListener("mouseenter",this.$tooltipEnter),t.addEventListener("mouseleave",this.$scheduleTooltipForHide),n.addEventListener("mouseenter",this.$tooltipEnter),n.addEventListener("mouseleave",this.$scheduleTooltipForHide)):(this.editor&&(this.editor.off("mousemove",this.$onMouseMove),this.editor.renderer.getMouseEventTarget().removeEventListener("mouseout",this.$scheduleTooltipForHide,!0)),t.removeEventListener("mouseenter",this.$tooltipEnter),t.removeEventListener("mouseleave",this.$scheduleTooltipForHide),n.removeEventListener("mouseenter",this.$tooltipEnter),n.removeEventListener("mouseleave",this.$scheduleTooltipForHide))},e.prototype.$showTooltip=function(){if(this.isShown())return;this.tooltip.setTheme(this.editor.renderer.theme),this.tooltip.setClassName(d+"_wrapper"),this.tooltip.show(),this.update(),this.updatePosition(),this._signal("show")},e.prototype.$hideTooltip=function(){this.$mouseInTooltip=!1;if(!this.isShown())return;this.moreOptions.hide(),this.tooltip.hide(),this._signal("hide")},e.prototype.$updateElement=function(e){var t=this.commands[e];if(!t)return;var n=this.elements[e],r=t.enabled;typeof r=="function"&&(r=r(this.editor));if(typeof t.getValue=="function"){var i=t.getValue(this.editor);if(t.type==="text")n.textContent=i;else if(t.type==="checkbox"){var s=i?u.addCssClass:u.removeCssClass,o=n.parentElement===this.tooltipEl;n.ariaChecked=i,o?s(n,"ace_selected"):(n=n.querySelector("."+c),s(n,"ace_checkmark"))}}r&&n.disabled?(u.removeCssClass(n,"ace_disabled"),n.ariaDisabled=n.disabled=!1,n.removeAttribute("disabled")):!r&&!n.disabled&&(u.addCssClass(n,"ace_disabled"),n.ariaDisabled=n.disabled=!0,n.setAttribute("disabled",""))},e}();a.implement(w.prototype,s),u.importCssString("\n.ace_tooltip.".concat(d,"_wrapper {\n padding: 0;\n}\n\n.ace_tooltip .").concat(d," {\n padding: 1px 5px;\n display: flex;\n pointer-events: auto;\n}\n\n.ace_tooltip .").concat(d,".tooltip_more_options {\n padding: 1px;\n flex-direction: column;\n}\n\ndiv.").concat(l," {\n display: inline-flex;\n cursor: pointer;\n margin: 1px;\n border-radius: 2px;\n padding: 2px 5px;\n align-items: center;\n}\n\ndiv.").concat(l,".ace_selected,\ndiv.").concat(l,":hover:not(.ace_disabled) {\n background-color: rgba(0, 0, 0, 0.1);\n}\n\ndiv.").concat(l,".ace_disabled {\n color: #777;\n pointer-events: none;\n}\n\ndiv.").concat(l," .ace_icon_svg {\n height: 12px;\n background-color: #000;\n}\n\ndiv.").concat(l,".ace_disabled .ace_icon_svg {\n background-color: #777;\n}\n\n.").concat(d,".tooltip_more_options .").concat(l," {\n display: flex;\n}\n\n.").concat(d,".").concat(c," {\n display: none;\n}\n\n.").concat(d,".tooltip_more_options .").concat(c," {\n display: inline-block;\n width: 12px;\n}\n\n.").concat(h," {\n display: inline-block;\n}\n\n.").concat(p," {\n margin: 0 2px;\n display: inline-block;\n font-size: 8px;\n}\n\n.").concat(d,".tooltip_more_options .").concat(p," {\n margin-left: auto;\n}\n\n.").concat(p," div {\n display: inline-block;\n min-width: 8px;\n padding: 2px;\n margin: 0 1px;\n border-radius: 2px;\n background-color: #ccc;\n text-align: center;\n}\n\n.ace_dark.ace_tooltip .").concat(d," {\n background-color: #373737;\n color: #eee;\n}\n\n.ace_dark div.").concat(l,".ace_disabled {\n color: #979797;\n}\n\n.ace_dark div.").concat(l,".ace_selected,\n.ace_dark div.").concat(l,":hover:not(.ace_disabled) {\n background-color: rgba(255, 255, 255, 0.1);\n}\n\n.ace_dark div.").concat(l," .ace_icon_svg {\n background-color: #eee;\n}\n\n.ace_dark div.").concat(l,".ace_disabled .ace_icon_svg {\n background-color: #979797;\n}\n\n.ace_dark .").concat(l,".ace_disabled {\n color: #979797;\n}\n\n.ace_dark .").concat(p," div {\n background-color: #575757;\n}\n\n.ace_checkmark::before {\n content: '\u2713';\n}\n"),"commandbar.css",!1),t.CommandBarTooltip=w,t.TOOLTIP_CLASS_NAME=d,t.BUTTON_CLASS_NAME=l}); (function() {
2
+ window.require(["ace/ext/command_bar"], function(m) {
3
+ if (typeof module == "object" && typeof exports == "object" && module) {
4
+ module.exports = m;
5
+ }
6
+ });
7
+ })();
8
+
webui/vendor/ace-min/ext-diff.js ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ define("ace/ext/diff/scroll_diff_decorator",["require","exports","module","ace/layer/decorators"],function(e,t,n){var r=this&&this.__extends||function(){var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},e(t,n)};return function(t,n){function r(){this.constructor=t}if(typeof n!="function"&&n!==null)throw new TypeError("Class extends value "+String(n)+" is not a constructor or null");e(t,n),t.prototype=n===null?Object.create(n):(r.prototype=n.prototype,new r)}}(),i=this&&this.__values||function(e){var t=typeof Symbol=="function"&&Symbol.iterator,n=t&&e[t],r=0;if(n)return n.call(e);if(e&&typeof e.length=="number")return{next:function(){return e&&r>=e.length&&(e=void 0),{value:e&&e[r++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")},s=e("../../layer/decorators").Decorator,o=function(e){function t(t,n,r){var i=e.call(this,t,n)||this;return i.colors.dark["delete"]="rgba(255, 18, 18, 1)",i.colors.dark.insert="rgba(18, 136, 18, 1)",i.colors.light["delete"]="rgb(255,51,51)",i.colors.light.insert="rgb(32,133,72)",i.$zones=[],i.$forInlineDiff=r,i}return r(t,e),t.prototype.addZone=function(e,t,n){this.$zones.push({startRow:e,endRow:t,type:n})},t.prototype.setSessions=function(e,t){this.sessionA=e,this.sessionB=t},t.prototype.$updateDecorators=function(t){if(typeof this.canvas.getContext!="function")return;e.prototype.$updateDecorators.call(this,t);if(this.$zones.length>0){var n=this.renderer.theme.isDark===!0?this.colors.dark:this.colors.light,r=this.canvas.getContext("2d");this.$setDiffDecorators(r,n)}},t.prototype.$transformPosition=function(e,t){return t=="delete"?this.sessionA.documentToScreenRow(e,0):this.sessionB.documentToScreenRow(e,0)},t.prototype.$setDiffDecorators=function(e,t){function o(e,t){return e.from===t.from?e.to-t.to:e.from-t.from}var n,r,s=this,u=this.$zones;if(u){var a=[],f=u.filter(function(e){return e.type==="delete"}),l=u.filter(function(e){return e.type==="insert"});[f,l].forEach(function(e){e.forEach(function(e,n){var r=s.$transformPosition(e.startRow,e.type)*s.lineHeight,i=s.$transformPosition(e.endRow,e.type)*s.lineHeight+s.lineHeight,o=Math.round(s.heightRatio*r),u=Math.round(s.heightRatio*i),f=1,l=Math.round((o+u)/2),c=u-l;c<s.halfMinDecorationHeight&&(c=s.halfMinDecorationHeight);var h=a[a.length-1];n>0&&h&&h.type===e.type&&l-c<h.to+f&&(l=a[a.length-1].to+f+c),l-c<0&&(l=c),l+c>s.canvasHeight&&(l=s.canvasHeight-c),a.push({type:e.type,from:l-c,to:l+c,color:t[e.type]||null})})}),a=a.sort(o);try{for(var c=i(a),h=c.next();!h.done;h=c.next()){var p=h.value;e.fillStyle=p.color||null;var d=p.from,v=p.to,m=v-d;this.$forInlineDiff?e.fillRect(this.oneZoneWidth,d,2*this.oneZoneWidth,m):p.type=="delete"?e.fillRect(this.oneZoneWidth,d,this.oneZoneWidth,m):e.fillRect(2*this.oneZoneWidth,d,this.oneZoneWidth,m)}}catch(g){n={error:g}}finally{try{h&&!h.done&&(r=c.return)&&r.call(c)}finally{if(n)throw n.error}}}},t.prototype.setZoneWidth=function(){this.oneZoneWidth=Math.round(this.canvasWidth/3)},t}(s);t.ScrollDiffDecorator=o}),define("ace/ext/diff/styles-css.js",["require","exports","module"],function(e,t,n){t.cssText='\n/*\n * Line Markers\n */\n.ace_diff {\n position: absolute;\n z-index: 0;\n}\n.ace_diff.inline {\n z-index: 20;\n}\n/*\n * Light Colors \n */\n.ace_diff.insert {\n background-color: #EFFFF1;\n}\n.ace_diff.delete {\n background-color: #FFF1F1;\n}\n.ace_diff.aligned_diff {\n background: rgba(206, 194, 191, 0.26);\n background: repeating-linear-gradient(\n 45deg,\n rgba(122, 111, 108, 0.26),\n rgba(122, 111, 108, 0.26) 5px,\n rgba(0, 0, 0, 0) 5px,\n rgba(0, 0, 0, 0) 10px \n );\n}\n\n.ace_diff.insert.inline {\n background-color: rgb(74 251 74 / 18%); \n}\n.ace_diff.delete.inline {\n background-color: rgb(251 74 74 / 15%);\n}\n\n.ace_diff.delete.inline.empty {\n background-color: rgba(255, 128, 79, 0.7);\n width: 2px !important;\n}\n\n.ace_diff.insert.inline.empty {\n background-color: rgba(49, 230, 96, 0.7);\n width: 2px !important;\n}\n\n.ace_diff-active-line {\n border-bottom: 1px solid;\n border-top: 1px solid;\n background: transparent;\n position: absolute;\n box-sizing: border-box;\n border-color: #9191ac;\n}\n\n.ace_dark .ace_diff-active-line {\n background: transparent;\n border-color: #75777a;\n}\n \n\n/* gutter changes */\n.ace_mini-diff_gutter-enabled > .ace_gutter-cell,\n.ace_mini-diff_gutter-enabled > .ace_gutter-cell_svg-icons {\n padding-right: 13px;\n}\n\n.ace_mini-diff_gutter_other > .ace_gutter-cell,\n.ace_mini-diff_gutter_other > .ace_gutter-cell_svg-icons {\n display: none;\n}\n\n.ace_mini-diff_gutter_other {\n pointer-events: none;\n}\n\n\n.ace_mini-diff_gutter-enabled > .mini-diff-added {\n background-color: #EFFFF1;\n border-left: 3px solid #2BB534;\n padding-left: 16px;\n display: block;\n}\n\n.ace_mini-diff_gutter-enabled > .mini-diff-deleted {\n background-color: #FFF1F1;\n border-left: 3px solid #EA7158;\n padding-left: 16px;\n display: block;\n}\n\n\n.ace_mini-diff_gutter-enabled > .mini-diff-added:after {\n position: absolute;\n right: 2px;\n content: "+";\n color: darkgray;\n background-color: inherit;\n}\n\n.ace_mini-diff_gutter-enabled > .mini-diff-deleted:after {\n position: absolute;\n right: 2px;\n content: "-";\n color: darkgray;\n background-color: inherit;\n}\n.ace_fade-fold-widgets:hover > .ace_folding-enabled > .mini-diff-added:after,\n.ace_fade-fold-widgets:hover > .ace_folding-enabled > .mini-diff-deleted:after {\n display: none;\n}\n\n.ace_diff_other .ace_selection {\n filter: drop-shadow(1px 2px 3px darkgray);\n}\n\n.ace_hidden_marker-layer .ace_bracket {\n display: none;\n}\n\n\n\n/*\n * Dark Colors \n */\n\n.ace_dark .ace_diff.insert {\n background-color: #212E25;\n}\n.ace_dark .ace_diff.delete {\n background-color: #3F2222;\n}\n\n.ace_dark .ace_mini-diff_gutter-enabled > .mini-diff-added {\n background-color: #212E25;\n border-left-color:#00802F;\n}\n\n.ace_dark .ace_mini-diff_gutter-enabled > .mini-diff-deleted {\n background-color: #3F2222;\n border-left-color: #9C3838;\n}\n\n'}),define("ace/ext/diff/gutter_decorator",["require","exports","module","ace/lib/dom"],function(e,t,n){var r=e("../../lib/dom"),i=function(){function e(e,t){this.gutterClass="ace_mini-diff_gutter-enabled",this.gutterCellsClasses={add:"mini-diff-added","delete":"mini-diff-deleted"},this.editor=e,this.type=t,this.chunks=[],this.attachToEditor()}return e.prototype.attachToEditor=function(){this.renderGutters=this.renderGutters.bind(this),r.addCssClass(this.editor.renderer.$gutterLayer.element,this.gutterClass),this.editor.renderer.$gutterLayer.on("afterRender",this.renderGutters)},e.prototype.renderGutters=function(e,t){var n=this,r=this.editor.renderer.$gutterLayer.$lines.cells;r.forEach(function(e){e.element.classList.remove(Object.values(n.gutterCellsClasses))});var i=this.type===-1?"old":"new",s=this.type===-1?this.gutterCellsClasses.delete:this.gutterCellsClasses.add;this.chunks.forEach(function(e){var t=e[i].start.row,n=e[i].end.row-1;r.forEach(function(e){e.row>=t&&e.row<=n&&e.element.classList.add(s)})})},e.prototype.setDecorations=function(e){this.chunks=e,this.renderGutters()},e.prototype.dispose=function(){r.removeCssClass(this.editor.renderer.$gutterLayer.element,this.gutterClass),this.editor.renderer.$gutterLayer.off("afterRender",this.renderGutters)},e}();t.MinimalGutterDiffDecorator=i}),define("ace/ext/diff/base_diff_view",["require","exports","module","ace/lib/oop","ace/range","ace/lib/dom","ace/config","ace/line_widgets","ace/ext/diff/scroll_diff_decorator","ace/ext/diff/styles-css.js","ace/editor","ace/virtual_renderer","ace/undomanager","ace/layer/decorators","ace/theme/textmate","ace/multi_select","ace/edit_session","ace/ext/diff/gutter_decorator"],function(e,t,n){"use strict";var r=this&&this.__read||function(e,t){var n=typeof Symbol=="function"&&e[Symbol.iterator];if(!n)return e;var r=n.call(e),i,s=[],o;try{while((t===void 0||t-->0)&&!(i=r.next()).done)s.push(i.value)}catch(u){o={error:u}}finally{try{i&&!i.done&&(n=r["return"])&&n.call(r)}finally{if(o)throw o.error}}return s},i=e("../../lib/oop"),s=e("../../range").Range,o=e("../../lib/dom"),u=e("../../config"),a=e("../../line_widgets").LineWidgets,f=e("./scroll_diff_decorator").ScrollDiffDecorator,l=e("./styles-css.js").cssText,c=e("../../editor").Editor,h=e("../../virtual_renderer").VirtualRenderer,p=e("../../undomanager").UndoManager,d=e("../../layer/decorators").Decorator;e("../../theme/textmate"),e("../../multi_select");var v=e("../../edit_session").EditSession,m=e("./gutter_decorator").MinimalGutterDiffDecorator,g={compute:function(e,t,n){return[]}};o.importCssString(l,"diffview.css");var y=function(){function e(e,t){this.onChangeTheme=this.onChangeTheme.bind(this),this.onInput=this.onInput.bind(this),this.onChangeFold=this.onChangeFold.bind(this),this.realign=this.realign.bind(this),this.onSelect=this.onSelect.bind(this),this.onChangeWrapLimit=this.onChangeWrapLimit.bind(this),this.realignPending=!1,this.diffSession,this.chunks,this.inlineDiffEditor=e||!1,this.currentDiffIndex=0,this.diffProvider=g,t&&(this.container=t),this.$ignoreTrimWhitespace=!1,this.$maxDiffs=5e3,this.$maxComputationTimeMs=150,this.$syncSelections=!1,this.$foldUnchangedOnInput=!1,this.markerB=new E(this,1),this.markerA=new E(this,-1)}return e.prototype.$setupModels=function(e){e.diffProvider&&this.setProvider(e.diffProvider),this.showSideA=e.inline==undefined?!0:e.inline==="a";var t={scrollPastEnd:.5,highlightActiveLine:!1,highlightGutterLine:!1,animatedScroll:!0,customScrollbar:!0,vScrollBarAlwaysVisible:!0,fadeFoldWidgets:!0,showFoldWidgets:!0,selectionStyle:"text"};this.savedOptionsA=e.editorA&&e.editorA.getOptions(t),this.savedOptionsB=e.editorB&&e.editorB.getOptions(t);if(!this.inlineDiffEditor||e.inline==="a")this.editorA=e.editorA||this.$setupModel(e.sessionA,e.valueA),this.container&&this.container.appendChild(this.editorA.container),this.editorA.setOptions(t);if(!this.inlineDiffEditor||e.inline==="b")this.editorB=e.editorB||this.$setupModel(e.sessionB,e.valueB),this.container&&this.container.appendChild(this.editorB.container),this.editorB.setOptions(t);if(this.inlineDiffEditor){this.activeEditor=this.showSideA?this.editorA:this.editorB,this.otherSession=this.showSideA?this.sessionB:this.sessionA;var n=this.activeEditor.getOptions();n.readOnly=!0,delete n.mode,this.otherEditor=new c(new h(null),undefined,n),this.showSideA?this.editorB=this.otherEditor:this.editorA=this.otherEditor}this.setDiffSession({sessionA:e.sessionA||(e.editorA?e.editorA.session:new v(e.valueA||"")),sessionB:e.sessionB||(e.editorB?e.editorB.session:new v(e.valueB||"")),chunks:[]}),this.setupScrollbars()},e.prototype.addGutterDecorators=function(){this.gutterDecoratorA||(this.gutterDecoratorA=new m(this.editorA,-1)),this.gutterDecoratorB||(this.gutterDecoratorB=new m(this.editorB,1))},e.prototype.$setupModel=function(e,t){var n=new c(new h,e);return n.session.setUndoManager(new p),t!=undefined&&n.setValue(t,-1),n},e.prototype.foldUnchanged=function(){var e=this.chunks,t="-".repeat(120),n={old:new s(0,0,0,0),"new":new s(0,0,0,0)},r=!1;for(var i=0;i<e.length+1;i++){var o=e[i]||{old:new s(this.sessionA.getLength(),0,this.sessionA.getLength(),0),"new":new s(this.sessionB.getLength(),0,this.sessionB.getLength(),0)},u=o.new.start.row-n.new.end.row-5;if(u>2){var a=n.old.end.row+2,f=this.sessionA.addFold(t,new s(a,0,a+u,Number.MAX_VALUE));a=n.new.end.row+2;var l=this.sessionB.addFold(t,new s(a,0,a+u,Number.MAX_VALUE));if(f||l)r=!0;l&&f&&(f.other=l,l.other=f)}n=o}return r},e.prototype.unfoldUnchanged=function(){var e=this.sessionA.getAllFolds();for(var t=e.length-1;t>=0;t--){var n=e[t];n.placeholder.length==120&&this.sessionA.removeFold(n)}},e.prototype.toggleFoldUnchanged=function(){this.foldUnchanged()||this.unfoldUnchanged()},e.prototype.setDiffSession=function(e){this.diffSession&&(this.$detachSessionsEventHandlers(),this.clearSelectionMarkers()),this.diffSession=e,this.sessionA=this.sessionB=null,this.diffSession&&(this.chunks=this.diffSession.chunks||[],this.editorA&&this.editorA.setSession(e.sessionA),this.editorB&&this.editorB.setSession(e.sessionB),this.sessionA=this.diffSession.sessionA,this.sessionB=this.diffSession.sessionB,this.$attachSessionsEventHandlers(),this.initSelectionMarkers()),this.otherSession=this.showSideA?this.sessionB:this.sessionA},e.prototype.$attachSessionsEventHandlers=function(){},e.prototype.$detachSessionsEventHandlers=function(){},e.prototype.getDiffSession=function(){return this.diffSession},e.prototype.setTheme=function(e){this.editorA&&this.editorA.setTheme(e),this.editorB&&this.editorB.setTheme(e)},e.prototype.getTheme=function(){return(this.editorA||this.editorB).getTheme()},e.prototype.onChangeTheme=function(e){var t=e&&e.theme||this.getTheme();this.editorA&&this.editorA.getTheme()!==t&&this.editorA.setTheme(t),this.editorB&&this.editorB.getTheme()!==t&&this.editorB.setTheme(t)},e.prototype.resize=function(e){this.editorA&&this.editorA.resize(e),this.editorB&&this.editorB.resize(e)},e.prototype.scheduleOnInput=function(){var e=this;if(this.$onInputTimer)return;this.$onInputTimer=setTimeout(function(){e.$onInputTimer=null,e.onInput()})},e.prototype.onInput=function(){var e=this;this.$onInputTimer&&clearTimeout(this.$onInputTimer);var t=this.sessionA.doc.getAllLines(),n=this.sessionB.doc.getAllLines();this.selectionRangeA=null,this.selectionRangeB=null;var r=this.$diffLines(t,n);this.diffSession.chunks=this.chunks=r,this.gutterDecoratorA&&this.gutterDecoratorA.setDecorations(r),this.gutterDecoratorB&&this.gutterDecoratorB.setDecorations(r);if(this.chunks&&this.chunks.length>this.$maxDiffs)return;this.align(),this.editorA&&this.editorA.renderer.updateBackMarkers(),this.editorB&&this.editorB.renderer.updateBackMarkers(),setTimeout(function(){e.updateScrollBarDecorators()},0),this.$foldUnchangedOnInput&&this.foldUnchanged()},e.prototype.setupScrollbars=function(){var e=this,t=function(t){setTimeout(function(){e.$setScrollBarDecorators(t),e.updateScrollBarDecorators()},0)};this.inlineDiffEditor?t(this.activeEditor.renderer):(t(this.editorA.renderer),t(this.editorB.renderer))},e.prototype.$setScrollBarDecorators=function(e){e.$scrollDecorator&&e.$scrollDecorator.destroy(),e.$scrollDecorator=new f(e.scrollBarV,e,this.inlineDiffEditor),e.$scrollDecorator.setSessions(this.sessionA,this.sessionB),e.scrollBarV.setVisible(!0),e.scrollBarV.element.style.bottom=e.scrollBarH.getHeight()+"px"},e.prototype.$resetDecorators=function(e){e.$scrollDecorator&&e.$scrollDecorator.destroy(),e.$scrollDecorator=new d(e.scrollBarV,e)},e.prototype.updateScrollBarDecorators=function(){var e=this;if(this.inlineDiffEditor){if(!this.activeEditor)return;this.activeEditor.renderer.$scrollDecorator.$zones=[]}else{if(!this.editorA||!this.editorB)return;this.editorA.renderer.$scrollDecorator.$zones=[],this.editorB.renderer.$scrollDecorator.$zones=[]}var t=function(e,t){if(!e)return;if(typeof e.renderer.$scrollDecorator.addZone!="function")return;t.old.start.row!=t.old.end.row&&e.renderer.$scrollDecorator.addZone(t.old.start.row,t.old.end.row-1,"delete"),t.new.start.row!=t.new.end.row&&e.renderer.$scrollDecorator.addZone(t.new.start.row,t.new.end.row-1,"insert")};this.inlineDiffEditor?(this.chunks&&this.chunks.forEach(function(n){t(e.activeEditor,n)}),this.activeEditor.renderer.$scrollDecorator.$updateDecorators(this.activeEditor.renderer.layerConfig)):(this.chunks&&this.chunks.forEach(function(n){t(e.editorA,n),t(e.editorB,n)}),this.editorA.renderer.$scrollDecorator.$updateDecorators(this.editorA.renderer.layerConfig),this.editorB.renderer.$scrollDecorator.$updateDecorators(this.editorB.renderer.layerConfig))},e.prototype.$diffLines=function(e,t){return this.diffProvider.compute(e,t,{ignoreTrimWhitespace:this.$ignoreTrimWhitespace,maxComputationTimeMs:this.$maxComputationTimeMs})},e.prototype.setProvider=function(e){this.diffProvider=e},e.prototype.$addWidget=function(e,t){var n=e.lineWidgets[t.row];n&&(t.rowsAbove+=n.rowsAbove>t.rowsAbove?n.rowsAbove:t.rowsAbove,t.rowCount+=n.rowCount),e.lineWidgets[t.row]=t,e.widgetManager.lineWidgets[t.row]=t,e.$resetRowCache(t.row);var r=e.getFoldAt(t.row,0);r&&e.widgetManager.updateOnFold({data:r,action:"add"},e)},e.prototype.$initWidgets=function(e){var t=e.session;t.widgetManager||(t.widgetManager=new a(t),t.widgetManager.attach(e)),e.session.lineWidgets=[],e.session.widgetManager.lineWidgets=[],e.session.$resetRowCache(0)},e.prototype.$screenRow=function(e,t){var n=t.documentToScreenPosition(e).row,r=e.row-t.getLength()+1;return r>0&&(n+=r),n},e.prototype.align=function(){},e.prototype.onChangeWrapLimit=function(e,t){},e.prototype.onSelect=function(e,t){this.searchHighlight(t),this.syncSelect(t)},e.prototype.syncSelect=function(e){if(this.$updatingSelection)return;var t=e.session===this.sessionA,n=e.getRange(),r=t?this.selectionRangeA:this.selectionRangeB;if(r&&n.isEqual(r))return;t?this.selectionRangeA=n:this.selectionRangeB=n,this.$updatingSelection=!0;var i=this.transformRange(n,t);this.$syncSelections&&(t?this.editorB:this.editorA).session.selection.setSelectionRange(i),this.$updatingSelection=!1,t?(this.selectionRangeA=n,this.selectionRangeB=i):(this.selectionRangeA=i,this.selectionRangeB=n),this.updateSelectionMarker(this.syncSelectionMarkerA,this.sessionA,this.selectionRangeA),this.updateSelectionMarker(this.syncSelectionMarkerB,this.sessionB,this.selectionRangeB)},e.prototype.updateSelectionMarker=function(e,t,n){e.setRange(n),t._signal("changeFrontMarker")},e.prototype.onChangeFold=function(e,t){var n=e.data;if(this.$syncingFold||!n||!e.action)return;this.scheduleRealign();var r=t===this.sessionA,i=r?this.sessionB:this.sessionA;e.action==="remove"&&(n.other?(n.other.other=null,i.removeFold(n.other)):n.lineWidget&&(i.widgetManager.addLineWidget(n.lineWidget),n.lineWidget=null,i.$editor&&i.$editor.renderer.updateBackMarkers()));if(e.action==="add"){var s=this.transformRange(n.range,r);if(s.isEmpty()){var o=s.start.row+1;i.lineWidgets[o]&&(n.lineWidget=i.lineWidgets[o],i.widgetManager.removeLineWidget(n.lineWidget),i.$editor&&i.$editor.renderer.updateBackMarkers())}else this.$syncingFold=!0,n.other=i.addFold(n.placeholder,s),n.other&&(n.other.other=n),this.$syncingFold=!1}},e.prototype.scheduleRealign=function(){this.realignPending||(this.realignPending=!0,this.editorA.renderer.on("beforeRender",this.realign),this.editorB.renderer.on("beforeRender",this.realign))},e.prototype.realign=function(){this.realignPending=!0,this.editorA.renderer.off("beforeRender",this.realign),this.editorB.renderer.off("beforeRender",this.realign),this.align(),this.realignPending=!1},e.prototype.detach=function(){if(!this.editorA||!this.editorB)return;this.savedOptionsA&&this.editorA.setOptions(this.savedOptionsA),this.savedOptionsB&&this.editorB.setOptions(this.savedOptionsB),this.editorA.renderer.off("beforeRender",this.realign),this.editorB.renderer.off("beforeRender",this.realign),this.$detachEventHandlers(),this.$removeLineWidgets(this.sessionA),this.$removeLineWidgets(this.sessionB),this.gutterDecoratorA&&this.gutterDecoratorA.dispose(),this.gutterDecoratorB&&this.gutterDecoratorB.dispose(),this.sessionA.selection.clearSelection(),this.sessionB.selection.clearSelection(),this.savedOptionsA&&this.savedOptionsA.customScrollbar&&this.$resetDecorators(this.editorA.renderer),this.savedOptionsB&&this.savedOptionsB.customScrollbar&&this.$resetDecorators(this.editorB.renderer)},e.prototype.$removeLineWidgets=function(e){e.lineWidgets=[],e.widgetManager.lineWidgets=[],e._signal("changeFold",{data:{start:{row:0}}})},e.prototype.$detachEventHandlers=function(){},e.prototype.destroy=function(){this.detach(),this.editorA&&this.editorA.destroy(),this.editorB&&this.editorB.destroy(),this.editorA=this.editorB=null},e.prototype.gotoNext=function(e){var t=this.activeEditor||this.editorA;this.inlineDiffEditor&&(t=this.editorA);var n=t==this.editorA,r=t.selection.lead.row,i=this.findChunkIndex(this.chunks,r,n),o=this.chunks[i+e]||this.chunks[i],u=t.session.getScrollTop();if(o){var a=o[n?"old":"new"],f=Math.max(a.start.row,a.end.row-1);t.selection.setRange(new s(f,0,f,0))}t.renderer.scrollSelectionIntoView(t.selection.lead,t.selection.anchor,.5),t.renderer.animateScrolling(u)},e.prototype.firstDiffSelected=function(){return this.currentDiffIndex<=1},e.prototype.lastDiffSelected=function(){return this.currentDiffIndex>this.chunks.length-1},e.prototype.transformRange=function(e,t){return s.fromPoints(this.transformPosition(e.start,t),this.transformPosition(e.end,t))},e.prototype.transformPosition=function(e,t){var n=this.findChunkIndex(this.chunks,e.row,t),i=this.chunks[n],s=this.sessionB.doc.clonePos,o=s(e),u=r(t?["old","new"]:["new","old"],2),a=u[0],f=u[1],l=0,c=!1;if(i)if(i[a].end.row<=e.row)o.row-=i[a].end.row-i[f].end.row;else if(i.charChanges)for(var h=0;h<i.charChanges.length;h++){var p=i.charChanges[h],d=p[a],v=p[f];if(d.end.row<e.row)continue;if(d.start.row>e.row)break;if(d.isMultiLine()&&d.contains(e.row,e.column)){o.row=v.start.row+e.row-d.start.row;var m=v.end.row;v.end.column===0&&m--,o.row>m&&(o.row=m,o.column=(t?this.sessionB:this.sessionA).getLine(m).length,c=!0),o.row=Math.min(o.row,m)}else{o.row=v.start.row;if(d.start.column>e.column)break;c=!0,!d.isEmpty()&&d.contains(e.row,e.column)?(o.column=v.start.column,l=e.column-d.start.column,l=Math.min(l,v.end.column-v.start.column)):(o=s(v.end),l=e.column-d.end.column)}}else i[a].start.row<=e.row&&(o.row+=i[f].start.row-i[a].start.row,o.row>=i[f].end.row&&(o.row=i[f].end.row-1,o.column=(t?this.sessionB:this.sessionA).getLine(o.row).length));if(!c){var g=r(t?[this.sessionA,this.sessionB]:[this.sessionB,this.sessionA],2),y=g[0],b=g[1];l-=this.$getDeltaIndent(y,b,e.row,o.row)}return o.column+=l,o},e.prototype.$getDeltaIndent=function(e,t,n,r){var i=this.$getIndent(e,n),s=this.$getIndent(t,r);return i-s},e.prototype.$getIndent=function(e,t){return e.getLine(t).match(/^\s*/)[0].length},e.prototype.printDiffs=function(){this.chunks.forEach(function(e){console.log(e.toString())})},e.prototype.findChunkIndex=function(e,t,n){for(var r=0;r<e.length;r++){var i=e[r],s=n?i.old:i.new;if(s.end.row<t)continue;if(s.start.row>t)break}return this.currentDiffIndex=r,r-1},e.prototype.searchHighlight=function(e){if(this.$syncSelections||this.inlineDiffEditor)return;var t=e.session,n=t===this.sessionA?this.sessionB:this.sessionA;n.highlight(t.$searchHighlight.regExp),n._signal("changeBackMarker")},e.prototype.initSelectionMarkers=function(){this.syncSelectionMarkerA=new S,this.syncSelectionMarkerB=new S,this.sessionA.addDynamicMarker(this.syncSelectionMarkerA,!0),this.sessionB.addDynamicMarker(this.syncSelectionMarkerB,!0)},e.prototype.clearSelectionMarkers=function(){this.sessionA.removeMarker(this.syncSelectionMarkerA.id),this.sessionB.removeMarker(this.syncSelectionMarkerB.id)},e}();u.defineOptions(y.prototype,"DiffView",{showOtherLineNumbers:{set:function(e){this.gutterLayer&&(this.gutterLayer.$renderer=e?null:b,this.editorA.renderer.updateFull())},initialValue:!0},folding:{set:function(e){this.editorA.setOption("showFoldWidgets",e),this.editorB.setOption("showFoldWidgets",e);if(!e){var t=[],n=[];this.chunks&&this.chunks.forEach(function(e){t.push(e.old.start,e.old.end),n.push(e.new.start,e.new.end)}),this.sessionA.unfold(t),this.sessionB.unfold(n)}}},syncSelections:{set:function(e){}},ignoreTrimWhitespace:{set:function(e){this.scheduleOnInput()}},wrap:{set:function(e){this.sessionA.setOption("wrap",e),this.sessionB.setOption("wrap",e)}},maxDiffs:{value:5e3},theme:{set:function(e){this.setTheme(e)},get:function(){return this.editorA.getTheme()}}});var b={getText:function(t){return""},getWidth:function(){return 0}};t.BaseDiffView=y;var w=function(){function e(t,n,r){this.old=t,this.new=n,this.charChanges=r&&r.map(function(t){return new e(new s(t.originalStartLineNumber,t.originalStartColumn,t.originalEndLineNumber,t.originalEndColumn),new s(t.modifiedStartLineNumber,t.modifiedStartColumn,t.modifiedEndLineNumber,t.modifiedEndColumn))})}return e}(),E=function(){function e(e,t){this.id,this.diffView=e,this.type=t}return e.prototype.update=function(e,t,n,r){var i,o,u,a=this.diffView;this.type===-1?(i="old",o="delete",u="insert"):(i="new",o="insert",u="delete");var f=a.$ignoreTrimWhitespace,l=a.chunks;if(n.lineWidgets&&!a.inlineDiffEditor)for(var c=r.firstRow;c<=r.lastRow;c++){var h=n.lineWidgets[c];if(!h||h.hidden)continue;var p=n.documentToScreenRow(c,0);if(h.rowsAbove>0){var d=new s(p-h.rowsAbove,0,p-1,Number.MAX_VALUE);t.drawFullLineMarker(e,d,"ace_diff aligned_diff",r)}var v=p+h.rowCount-(h.rowsAbove||0),d=new s(p+1,0,v,Number.MAX_VALUE);t.drawFullLineMarker(e,d,"ace_diff aligned_diff",r)}l.forEach(function(a){var l=a[i].start.row,c=a[i].end.row;if(c<r.firstRow||l>r.lastRow)return;var h=new s(l,0,c-1,1<<30);l!==c&&(h=h.toScreenRange(n),t.drawFullLineMarker(e,h,"ace_diff "+o,r));if(a.charChanges)for(var p=0;p<a.charChanges.length;p++){var d=a.charChanges[p][i];d.end.column==0&&d.end.row>d.start.row&&d.end.row==a[i].end.row&&(d.end.row--,d.end.column=Number.MAX_VALUE);if(f)for(var v=d.start.row;v<=d.end.row;v++){var m=void 0,g=void 0,y=n.getLine(v).match(/^\s*/)[0].length,b=n.getLine(v).length;v===d.start.row?m=d.start.column:m=y,v===d.end.row?g=d.end.column:g=b;var w=new s(v,m,v,g),E=w.toScreenRange(n);if(y===m&&b===g)continue;var S="inline "+o;w.isEmpty()&&m!==0&&(S="inline "+u+" empty"),t.drawSingleLineMarker(e,E,"ace_diff "+S,r)}else{var x=new s(d.start.row,d.start.column,d.end.row,d.end.column),E=x.toScreenRange(n),S="inline "+o;x.isEmpty()&&d.start.column!==0&&(S="inline empty "+u),E.isMultiLine()?t.drawTextMarker(e,E,"ace_diff "+S,r):t.drawSingleLineMarker(e,E,"ace_diff "+S,r)}}})},e}(),S=function(){function e(){this.id,this.type="fullLine",this.clazz="ace_diff-active-line"}return e.prototype.update=function(e,t,n,r){},e.prototype.setRange=function(e){var t=e.clone();t.end.column++,this.range=t},e}();t.DiffChunk=w,t.DiffHighlight=E}),define("ace/ext/diff/inline_diff_view",["require","exports","module","ace/ext/diff/base_diff_view","ace/virtual_renderer","ace/config"],function(e,t,n){"use strict";var r=this&&this.__extends||function(){var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},e(t,n)};return function(t,n){function r(){this.constructor=t}if(typeof n!="function"&&n!==null)throw new TypeError("Class extends value "+String(n)+" is not a constructor or null");e(t,n),t.prototype=n===null?Object.create(n):(r.prototype=n.prototype,new r)}}(),i=e("./base_diff_view").BaseDiffView,s=e("../../virtual_renderer").VirtualRenderer,o=e("../../config"),u=function(e){function t(t,n){var r=this;return t=t||{},t.inline=t.inline||"a",r=e.call(this,!0,n)||this,r.init(t),r}return r(t,e),t.prototype.init=function(e){this.onSelect=this.onSelect.bind(this),this.onAfterRender=this.onAfterRender.bind(this),this.$setupModels(e),this.onChangeTheme(),o.resetOptions(this),o._signal("diffView",this);var t=this.activeEditor.renderer.$padding;this.addGutterDecorators(),this.otherEditor.renderer.setPadding(t),this.textLayer=this.otherEditor.renderer.$textLayer,this.markerLayer=this.otherEditor.renderer.$markerBack,this.gutterLayer=this.otherEditor.renderer.$gutterLayer,this.cursorLayer=this.otherEditor.renderer.$cursorLayer,this.otherEditor.renderer.$updateCachedSize=function(){};var n=this.activeEditor.renderer.$textLayer.element;n.parentNode.insertBefore(this.textLayer.element,n);var r=this.activeEditor.renderer.$markerBack.element;r.parentNode.insertBefore(this.markerLayer.element,r.nextSibling);var i=this.activeEditor.renderer.$gutterLayer.element;i.parentNode.insertBefore(this.gutterLayer.element,i.nextSibling),i.style.position="absolute",this.gutterLayer.element.style.position="absolute",this.gutterLayer.element.style.width="100%",this.gutterLayer.element.classList.add("ace_mini-diff_gutter_other"),this.gutterLayer.$updateGutterWidth=function(){},this.initMouse(),this.initTextInput(),this.initTextLayer(),this.initRenderer(),this.$attachEventHandlers(),this.selectEditor(this.activeEditor)},t.prototype.initRenderer=function(e){var t=this;e?delete this.activeEditor.renderer.$getLongestLine:this.editorA.renderer.$getLongestLine=this.editorB.renderer.$getLongestLine=function(){var e=s.prototype.$getLongestLine;return Math.max(e.call(t.editorA.renderer),e.call(t.editorB.renderer))}},t.prototype.initTextLayer=function(){function r(e,t){var r=0,i=e.length-1,s=-1;while(r<i){var o=Math.floor((r+i)/2),u=e[o][n].start.row;if(u<t)s=o,r=o+1;else{if(!(u>t)){s=o;break}i=o-1}}e[s+1]&&e[s+1][n].start.row<=t&&s++;var a=e[s]&&e[s][n];return a&&a.end.row>t?!0:!1}var e=this.textLayer.$renderLine,t=this;this.otherEditor.renderer.$textLayer.$renderLine=function(n,i,s){r(t.chunks,i)&&e.call(this,n,i,s)};var n=this.showSideA?"new":"old"},t.prototype.initTextInput=function(e){e?(this.otherEditor.textInput=this.othertextInput,this.otherEditor.container=this.otherEditorContainer):(this.othertextInput=this.otherEditor.textInput,this.otherEditor.textInput=this.activeEditor.textInput,this.otherEditorContainer=this.otherEditor.container,this.otherEditor.container=this.activeEditor.container)},t.prototype.selectEditor=function(e){e==this.activeEditor?(this.otherEditor.selection.clearSelection(),this.activeEditor.textInput.setHost(this.activeEditor),this.activeEditor.setStyle("ace_diff_other",!1),this.cursorLayer.element.remove(),this.activeEditor.renderer.$cursorLayer.element.style.display="block",this.showSideA&&(this.sessionA.removeMarker(this.syncSelectionMarkerA.id),this.sessionA.addDynamicMarker(this.syncSelectionMarkerA,!0)),this.markerLayer.element.classList.add("ace_hidden_marker-layer"),this.activeEditor.renderer.$markerBack.element.classList.remove("ace_hidden_marker-layer"),this.removeBracketHighlight(this.otherEditor)):(this.activeEditor.selection.clearSelection(),this.activeEditor.textInput.setHost(this.otherEditor),this.activeEditor.setStyle("ace_diff_other"),this.activeEditor.renderer.$cursorLayer.element.parentNode.appendChild(this.cursorLayer.element),this.activeEditor.renderer.$cursorLayer.element.style.display="none",this.activeEditor.$isFocused&&this.otherEditor.onFocus(),this.showSideA&&this.sessionA.removeMarker(this.syncSelectionMarkerA.id),this.markerLayer.element.classList.remove("ace_hidden_marker-layer"),this.activeEditor.renderer.$markerBack.element.classList.add("ace_hidden_marker-layer"),this.removeBracketHighlight(this.activeEditor))},t.prototype.removeBracketHighlight=function(e){var t=e.session;t.$bracketHighlight&&(t.$bracketHighlight.markerIds.forEach(function(e){t.removeMarker(e)}),t.$bracketHighlight=null)},t.prototype.initMouse=function(){var e=this;this.otherEditor.renderer.$loop=this.activeEditor.renderer.$loop,this.otherEditor.renderer.scroller={getBoundingClientRect:function(){return e.activeEditor.renderer.scroller.getBoundingClientRect()},style:this.activeEditor.renderer.scroller.style};var t=function(t){if(!t.domEvent)return;var n=t.editor.renderer.pixelToScreenCoordinates(t.clientX,t.clientY),r=e.activeEditor.session,i=e.otherEditor.session,s=r.screenToDocumentPosition(n.row,n.column,n.offsetX),o=i.screenToDocumentPosition(n.row,n.column,n.offsetX),u=r.documentToScreenPosition(s),a=i.documentToScreenPosition(o);t.editor==e.activeEditor&&(a.row==n.row&&u.row!=n.row?(t.type=="mousedown"&&e.selectEditor(e.otherEditor),t.propagationStopped=!0,t.defaultPrevented=!0,e.otherEditor.$mouseHandler.onMouseEvent(t.type,t.domEvent)):t.type=="mousedown"&&e.selectEditor(e.activeEditor))},n=["mousedown","click","mouseup","dblclick","tripleclick","quadclick"];n.forEach(function(n){e.activeEditor.on(n,t,!0),e.activeEditor.on("gutter"+n,t,!0)});var r=function(t){e.activeEditor.onFocus(t)},i=function(t){e.activeEditor.onBlur(t)};this.otherEditor.on("focus",r),this.otherEditor.on("blur",i),this.onMouseDetach=function(){n.forEach(function(n){e.activeEditor.off(n,t,!0),e.activeEditor.off("gutter"+n,t,!0)}),e.otherEditor.off("focus",r),e.otherEditor.off("blur",i)}},t.prototype.align=function(){var e=this;this.$initWidgets(e.editorA),this.$initWidgets(e.editorB),e.chunks.forEach(function(t){var n=e.$screenRow(t.old.end,e.sessionA)-e.$screenRow(t.old.start,e.sessionA),r=e.$screenRow(t.new.end,e.sessionB)-e.$screenRow(t.new.start,e.sessionB);e.$addWidget(e.sessionA,{rowCount:r,rowsAbove:t.old.end.row===0?r:0,row:t.old.end.row===0?0:t.old.end.row-1}),e.$addWidget(e.sessionB,{rowCount:n,rowsAbove:n,row:t.new.start.row})}),e.sessionA._emit("changeFold",{data:{start:{row:0}}}),e.sessionB._emit("changeFold",{data:{start:{row:0}}})},t.prototype.onChangeWrapLimit=function(){this.sessionB.adjustWrapLimit(this.sessionA.$wrapLimit),this.scheduleRealign()},t.prototype.$attachSessionsEventHandlers=function(){this.$attachSessionEventHandlers(this.editorA,this.markerA),this.$attachSessionEventHandlers(this.editorB,this.markerB),this.sessionA.on("changeWrapLimit",this.onChangeWrapLimit),this.sessionA.on("changeWrapMode",this.onChangeWrapLimit)},t.prototype.$attachSessionEventHandlers=function(e,t){e.session.on("changeFold",this.onChangeFold),e.session.addDynamicMarker(t),e.selection.on("changeCursor",this.onSelect),e.selection.on("changeSelection",this.onSelect)},t.prototype.$detachSessionsEventHandlers=function(){this.$detachSessionHandlers(this.editorA,this.markerA),this.$detachSessionHandlers(this.editorB,this.markerB),this.otherSession.bgTokenizer.lines.fill(undefined),this.sessionA.off("changeWrapLimit",this.onChangeWrapLimit),this.sessionA.off("changeWrapMode",this.onChangeWrapLimit)},t.prototype.$detachSessionHandlers=function(e,t){e.session.removeMarker(t.id),e.selection.off("changeCursor",this.onSelect),e.selection.off("changeSelection",this.onSelect),e.session.off("changeFold",this.onChangeFold)},t.prototype.$attachEventHandlers=function(){this.activeEditor.on("input",this.onInput),this.activeEditor.renderer.on("afterRender",this.onAfterRender),this.otherSession.on("change",this.onInput)},t.prototype.$detachEventHandlers=function(){this.$detachSessionsEventHandlers(),this.activeEditor.off("input",this.onInput),this.activeEditor.renderer.off("afterRender",this.onAfterRender),this.otherSession.off("change",this.onInput),this.textLayer.element.textContent="",this.textLayer.element.remove(),this.gutterLayer.element.textContent="",this.gutterLayer.element.remove(),this.markerLayer.element.textContent="",this.markerLayer.element.remove(),this.onMouseDetach(),this.selectEditor(this.activeEditor),this.clearSelectionMarkers(),this.otherEditor.setSession(null),this.otherEditor.renderer.$loop=null,this.initTextInput(!0),this.initRenderer(!0),this.otherEditor.destroy()},t.prototype.onAfterRender=function(e,t){var n=t.layerConfig,r=this.otherSession,i=this.otherEditor.renderer;r.$scrollTop=t.scrollTop,r.$scrollLeft=t.scrollLeft,["characterWidth","lineHeight","scrollTop","scrollLeft","scrollMargin","$padding","$size","layerConfig","$horizScroll","$vScroll"].forEach(function(e){i[e]=t[e]}),i.$computeLayerConfig();var s=i.layerConfig;this.gutterLayer.update(s),s.firstRowScreen=n.firstRowScreen,i.$cursorLayer.config=s,i.$cursorLayer.update(s),(e&i.CHANGE_LINES||e&i.CHANGE_FULL||e&i.CHANGE_SCROLL||e&i.CHANGE_TEXT)&&this.textLayer.update(s),this.markerLayer.setMarkers(this.otherSession.getMarkers()),this.markerLayer.update(s)},t.prototype.detach=function(){e.prototype.detach.call(this),this.otherEditor&&this.otherEditor.destroy()},t}(i);t.InlineDiffView=u}),define("ace/ext/diff/split_diff_view",["require","exports","module","ace/ext/diff/base_diff_view","ace/config"],function(e,t,n){"use strict";var r=this&&this.__extends||function(){var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},e(t,n)};return function(t,n){function r(){this.constructor=t}if(typeof n!="function"&&n!==null)throw new TypeError("Class extends value "+String(n)+" is not a constructor or null");e(t,n),t.prototype=n===null?Object.create(n):(r.prototype=n.prototype,new r)}}(),i=e("./base_diff_view").BaseDiffView,s=e("../../config"),o=function(e){function t(t){var n=this;return t=t||{},n=e.call(this)||this,n.init(t),n}return r(t,e),t.prototype.init=function(e){this.onChangeTheme=this.onChangeTheme.bind(this),this.onMouseWheel=this.onMouseWheel.bind(this),this.onScroll=this.onScroll.bind(this),this.$setupModels(e),this.addGutterDecorators(),this.onChangeTheme(),s.resetOptions(this),s._signal("diffView",this),this.$attachEventHandlers()},t.prototype.onChangeWrapLimit=function(){this.scheduleRealign()},t.prototype.align=function(){var e=this;this.$initWidgets(e.editorA),this.$initWidgets(e.editorB),e.chunks.forEach(function(t){var n=e.$screenRow(t.old.start,e.sessionA),r=e.$screenRow(t.new.start,e.sessionB);n<r?e.$addWidget(e.sessionA,{rowCount:r-n,rowsAbove:t.old.start.row===0?r-n:0,row:t.old.start.row===0?0:t.old.start.row-1}):n>r&&e.$addWidget(e.sessionB,{rowCount:n-r,rowsAbove:t.new.start.row===0?n-r:0,row:t.new.start.row===0?0:t.new.start.row-1});var n=e.$screenRow(t.old.end,e.sessionA),r=e.$screenRow(t.new.end,e.sessionB);n<r?e.$addWidget(e.sessionA,{rowCount:r-n,rowsAbove:t.old.end.row===0?r-n:0,row:t.old.end.row===0?0:t.old.end.row-1}):n>r&&e.$addWidget(e.sessionB,{rowCount:n-r,rowsAbove:t.new.end.row===0?n-r:0,row:t.new.end.row===0?0:t.new.end.row-1})}),e.sessionA._emit("changeFold",{data:{start:{row:0}}}),e.sessionB._emit("changeFold",{data:{start:{row:0}}})},t.prototype.onScroll=function(e,t){this.syncScroll(this.sessionA===t?this.editorA.renderer:this.editorB.renderer)},t.prototype.syncScroll=function(e){if(this.$syncScroll==0)return;var t=this.editorA.renderer,n=this.editorB.renderer,r=e==t;if(t.$scrollAnimation&&n.$scrollAnimation)return;var i=Date.now();if(this.scrollSetBy!=e&&i-this.scrollSetAt<500)return;var s=r?t:n;if(this.scrollSetBy!=e){if(r&&this.scrollA==s.session.getScrollTop())return;if(!r&&this.scrollB==s.session.getScrollTop())return}var o=r?n:t,u=s.session.getScrollTop();this.$syncScroll=!1,r?(this.scrollA=s.session.getScrollTop(),this.scrollB=u):(this.scrollA=u,this.scrollB=s.session.getScrollTop()),this.scrollSetBy=e,o.session.setScrollTop(u),this.$syncScroll=!0,this.scrollSetAt=i},t.prototype.onMouseWheel=function(e){if(e.getAccelKey())return;e.getShiftKey()&&e.wheelY&&!e.wheelX&&(e.wheelX=e.wheelY,e.wheelY=0);var t=e.editor,n=t.renderer.isScrollableBy(e.wheelX*e.speed,e.wheelY*e.speed);if(!n){var r=t==this.editorA?this.editorB:this.editorA;return r.renderer.isScrollableBy(e.wheelX*e.speed,e.wheelY*e.speed)&&r.renderer.scrollBy(e.wheelX*e.speed,e.wheelY*e.speed),e.stop()}},t.prototype.$attachSessionsEventHandlers=function(){this.$attachSessionEventHandlers(this.editorA,this.markerA),this.$attachSessionEventHandlers(this.editorB,this.markerB)},t.prototype.$attachSessionEventHandlers=function(e,t){e.session.on("changeScrollTop",this.onScroll),e.session.on("changeFold",this.onChangeFold),e.session.addDynamicMarker(t),e.selection.on("changeCursor",this.onSelect),e.selection.on("changeSelection",this.onSelect),e.session.on("changeWrapLimit",this.onChangeWrapLimit),e.session.on("changeWrapMode",this.onChangeWrapLimit)},t.prototype.$detachSessionsEventHandlers=function(){this.$detachSessionHandlers(this.editorA,this.markerA),this.$detachSessionHandlers(this.editorB,this.markerB)},t.prototype.$detachSessionHandlers=function(e,t){e.session.off("changeScrollTop",this.onScroll),e.session.off("changeFold",this.onChangeFold),e.session.removeMarker(t.id),e.selection.off("changeCursor",this.onSelect),e.selection.off("changeSelection",this.onSelect),e.session.off("changeWrapLimit",this.onChangeWrapLimit),e.session.off("changeWrapMode",this.onChangeWrapLimit)},t.prototype.$attachEventHandlers=function(){this.editorA.renderer.on("themeChange",this.onChangeTheme),this.editorB.renderer.on("themeChange",this.onChangeTheme),this.editorA.on("mousewheel",this.onMouseWheel),this.editorB.on("mousewheel",this.onMouseWheel),this.editorA.on("input",this.onInput),this.editorB.on("input",this.onInput)},t.prototype.$detachEventHandlers=function(){this.$detachSessionsEventHandlers(),this.clearSelectionMarkers(),this.editorA.renderer.off("themeChange",this.onChangeTheme),this.editorB.renderer.off("themeChange",this.onChangeTheme),this.$detachEditorEventHandlers(this.editorA),this.$detachEditorEventHandlers(this.editorB)},t.prototype.$detachEditorEventHandlers=function(e){e.off("mousewheel",this.onMouseWheel),e.off("input",this.onInput)},t}(i);t.SplitDiffView=o}),define("ace/ext/diff/providers/default",["require","exports","module","ace/range","ace/ext/diff/base_diff_view"],function(e,t,n){"use strict";function h(e,t,n){n===void 0&&(n=function(e,t){return e===t});if(e===t)return!0;if(!e||!t)return!1;if(e.length!==t.length)return!1;for(var r=0,i=e.length;r<i;r++)if(!n(e[r],t[r]))return!1;return!0}function p(e,t){var n,r,o,u,a,f,l,c;return i(this,function(i){switch(i.label){case 0:i.trys.push([0,8,9,10]),o=s(e),u=o.next(),i.label=1;case 1:if(!!u.done)return[3,7];a=u.value;if(r===undefined||!t(r,a))return[3,2];return n.push(a),[3,5];case 2:if(!n)return[3,4];return[4,n];case 3:i.sent(),i.label=4;case 4:n=[a],i.label=5;case 5:r=a,i.label=6;case 6:return u=o.next(),[3,1];case 7:return[3,10];case 8:return f=i.sent(),l={error:f},[3,10];case 9:try{u&&!u.done&&(c=o.return)&&c.call(o)}finally{if(l)throw l.error}return[7];case 10:if(!n)return[3,12];return[4,n];case 11:i.sent(),i.label=12;case 12:return[2]}})}function d(e,t){for(var n=0;n<=e.length;n++)t(n===0?undefined:e[n-1],n===e.length?undefined:e[n])}function v(e,t){for(var n=0;n<e.length;n++)t(n===0?undefined:e[n-1],e[n],n+1===e.length?undefined:e[n+1])}function m(e,t){var n,r;try{for(var i=s(t),o=i.next();!o.done;o=i.next()){var u=o.value;e.push(u)}}catch(a){n={error:a}}finally{try{o&&!o.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}}function g(e,t){return function(n,r){return t(e(n),e(r))}}function b(e){return function(t,n){return-e(t,n)}}function E(e,t){t===void 0&&(t="unexpected state");if(!e)throw new w("Assertion Failed: ".concat(t))}function S(e){e()}function x(e,t){var n=0;while(n<e.length-1){var r=e[n],i=e[n+1];if(!t(r,i))return!1;n++}return!0}function k(e,t){var n=L(e,t);return n===-1?undefined:e[n]}function L(e,t,n,r){n===void 0&&(n=0),r===void 0&&(r=e.length);var i=n,s=r;while(i<s){var o=Math.floor((i+s)/2);t(e[o])?i=o+1:s=o}return i-1}function A(e,t){var n=O(e,t);return n===e.length?undefined:e[n]}function O(e,t,n,r){n===void 0&&(n=0),r===void 0&&(r=e.length);var i=n,s=r;while(i<s){var o=Math.floor((i+s)/2);t(e[o])?s=o:i=o+1}return i}function q(e,t){if(e.lineNumber<1)return new N(1,1);if(e.lineNumber>t.length)return new N(t.length,t[t.length-1].length+1);var n=t[e.lineNumber-1];return e.column>n.length+1?new N(e.lineNumber,n.length+1):e}function R(e,t){return e>=1&&e<=t.length}function W(e,t,n,r){var i,o;r===void 0&&(r=!1);var u=[];try{for(var a=s(p(e.map(function(e){return X(e,t,n)}),function(e,t){return e.original.overlapOrTouch(t.original)||e.modified.overlapOrTouch(t.modified)})),f=a.next();!f.done;f=a.next()){var l=f.value,c=l[0],h=l[l.length-1];u.push(new U(c.original.join(h.original),c.modified.join(h.modified),l.map(function(e){return e.innerChanges[0]})))}}catch(d){i={error:d}}finally{try{f&&!f.done&&(o=a.return)&&o.call(a)}finally{if(i)throw i.error}}return S(function(){if(!r&&u.length>0){if(u[0].modified.startLineNumber!==u[0].original.startLineNumber)return!1;if(n.length.lineCount-u[u.length-1].modified.endLineNumberExclusive!==t.length.lineCount-u[u.length-1].original.endLineNumberExclusive)return!1}return x(u,function(e,t){return t.original.startLineNumber-e.original.endLineNumberExclusive===t.modified.startLineNumber-e.modified.endLineNumberExclusive&&e.original.endLineNumberExclusive<t.original.startLineNumber&&e.modified.endLineNumberExclusive<t.modified.startLineNumber})}),u}function X(e,t,n){var r=0,i=0;e.modifiedRange.endColumn===1&&e.originalRange.endColumn===1&&e.originalRange.startLineNumber+r<=e.originalRange.endLineNumber&&e.modifiedRange.startLineNumber+r<=e.modifiedRange.endLineNumber&&(i=-1),e.modifiedRange.startColumn-1>=n.getLineLength(e.modifiedRange.startLineNumber)&&e.originalRange.startColumn-1>=t.getLineLength(e.originalRange.startLineNumber)&&e.originalRange.startLineNumber<=e.originalRange.endLineNumber+i&&e.modifiedRange.startLineNumber<=e.modifiedRange.endLineNumber+i&&(r=1);var s=new _(e.originalRange.startLineNumber+r,e.originalRange.endLineNumber+1+i),o=new _(e.modifiedRange.startLineNumber+r,e.modifiedRange.endLineNumber+1+i);return new U(s,o,[e])}function Y(e){return e===32||e===9}function ut(e){return e>=97&&e<=122||e>=65&&e<=90||e>=48&&e<=57}function at(e){return e>=65&&e<=90}function lt(e){return ft[e]}function ct(e){return e===10?8:e===13?7:Y(e)?6:e>=97&&e<=122?0:e>=65&&e<=90?1:e>=48&&e<=57?2:e===-1?3:e===44||e===59?5:4}function ht(e,t,n,r,i,s){var o=dt(e,t,n,s),u=o.moves,a=o.excludedChanges;if(!s.isValid())return[];var f=e.filter(function(e){return!a.has(e)}),l=vt(f,r,i,t,n,s);return m(u,l),u=gt(u),u=u.filter(function(e){var n=e.original.toOffsetRange().slice(t).map(function(e){return e.trim()}),r=n.join("\n");return r.length>=15&&pt(n,function(e){return e.length>=2})>=2}),u=yt(e,u),u}function pt(e,t){var n,r,i=0;try{for(var o=s(e),u=o.next();!u.done;u=o.next()){var a=u.value;t(a)&&i++}}catch(f){n={error:f}}finally{try{u&&!u.done&&(r=o.return)&&r.call(o)}finally{if(n)throw n.error}}return i}function dt(e,t,n,r){var i,o,u,a,f=[],l=e.filter(function(e){return e.modified.isEmpty&&e.original.length>=3}).map(function(e){return new Z(e.original,t,e)}),c=new Set(e.filter(function(e){return e.original.isEmpty&&e.modified.length>=3}).map(function(e){return new Z(e.modified,n,e)})),h=new Set;try{for(var p=s(l),d=p.next();!d.done;d=p.next()){var v=d.value,m=-1,g=void 0;try{for(var y=(u=void 0,s(c)),b=y.next();!b.done;b=y.next()){var w=b.value,E=v.computeSimilarity(w);E>m&&(m=E,g=w)}}catch(S){u={error:S}}finally{try{b&&!b.done&&(a=y.return)&&a.call(y)}finally{if(u)throw u.error}}m>.9&&g&&(c.delete(g),f.push(new I(v.range,g.range)),h.add(v.source),h.add(g.source));if(!r.isValid())return{moves:f,excludedChanges:h}}}catch(x){i={error:x}}finally{try{d&&!d.done&&(o=p.return)&&o.call(p)}finally{if(i)throw i.error}}return{moves:f,excludedChanges:h}}function vt(e,t,n,r,i,o){var u,a,f,l,c,h,p,d,v=[],m=new st;try{for(var w=s(e),E=w.next();!E.done;E=w.next()){var S=E.value;for(var x=S.original.startLineNumber;x<S.original.endLineNumberExclusive-2;x++){var T="".concat(t[x-1],":").concat(t[x+1-1],":").concat(t[x+2-1]);m.add(T,{range:new _(x,x+3)})}}}catch(N){u={error:N}}finally{try{E&&!E.done&&(a=w.return)&&a.call(w)}finally{if(u)throw u.error}}var C=[];e.sort(g(function(e){return e.modified.startLineNumber},y));var L=function(e){var t=[],r=function(e){var r="".concat(n[e-1],":").concat(n[e+1-1],":").concat(n[e+2-1]),i=new _(e,e+3),o=[];m.forEach(r,function(e){var n,r,u=e.range;try{for(var a=(n=void 0,s(t)),f=a.next();!f.done;f=a.next()){var l=f.value;if(l.originalLineRange.endLineNumberExclusive+1===u.endLineNumberExclusive&&l.modifiedLineRange.endLineNumberExclusive+1===i.endLineNumberExclusive){l.originalLineRange=new _(l.originalLineRange.startLineNumber,u.endLineNumberExclusive),l.modifiedLineRange=new _(l.modifiedLineRange.startLineNumber,i.endLineNumberExclusive),o.push(l);return}}}catch(c){n={error:c}}finally{try{f&&!f.done&&(r=a.return)&&r.call(a)}finally{if(n)throw n.error}}var h={modifiedLineRange:i,originalLineRange:u};C.push(h),o.push(h)}),t=o};for(var i=e.modified.startLineNumber;i<e.modified.endLineNumberExclusive-2;i++)r(i);if(!o.isValid())return{value:[]}};try{for(var A=s(e),O=A.next();!O.done;O=A.next()){var S=O.value,P=L(S);if(typeof P=="object")return P.value}}catch(H){f={error:H}}finally{try{O&&!O.done&&(l=A.return)&&l.call(A)}finally{if(f)throw f.error}}C.sort(b(g(function(e){return e.modifiedLineRange.length},y)));var B=new D,j=new D;try{for(var F=s(C),q=F.next();!q.done;q=F.next()){var R=q.value,U=R.modifiedLineRange.startLineNumber-R.originalLineRange.startLineNumber,z=B.subtractFrom(R.modifiedLineRange),W=j.subtractFrom(R.originalLineRange).getWithDelta(U),X=z.getIntersection(W);try{for(var V=(p=void 0,s(X.ranges)),$=V.next();!$.done;$=V.next()){var J=$.value;if(J.length<3)continue;var K=J,Q=J.delta(-U);v.push(new I(Q,K)),B.addRange(K),j.addRange(Q)}}catch(G){p={error:G}}finally{try{$&&!$.done&&(d=V.return)&&d.call(V)}finally{if(p)throw p.error}}}}catch(Y){c={error:Y}}finally{try{q&&!q.done&&(h=F.return)&&h.call(F)}finally{if(c)throw c.error}}v.sort(g(function(e){return e.original.startLineNumber},y));var Z=new M(e),et=function(t){var n=v[t],s=Z.findLastMonotonous(function(e){return e.original.startLineNumber<=n.original.startLineNumber}),u=k(e,function(e){return e.modified.startLineNumber<=n.modified.startLineNumber}),a=Math.max(n.original.startLineNumber-s.original.startLineNumber,n.modified.startLineNumber-u.modified.startLineNumber),f=Z.findLastMonotonous(function(e){return e.original.startLineNumber<n.original.endLineNumberExclusive}),l=k(e,function(e){return e.modified.startLineNumber<n.modified.endLineNumberExclusive}),c=Math.max(f.original.endLineNumberExclusive-n.original.endLineNumberExclusive,l.modified.endLineNumberExclusive-n.modified.endLineNumberExclusive),h=void 0;for(h=0;h<a;h++){var p=n.original.startLineNumber-h-1,d=n.modified.startLineNumber-h-1;if(p>r.length||d>i.length)break;if(B.contains(d)||j.contains(p))break;if(!mt(r[p-1],i[d-1],o))break}h>0&&(j.addRange(new _(n.original.startLineNumber-h,n.original.startLineNumber)),B.addRange(new _(n.modified.startLineNumber-h,n.modified.startLineNumber)));var m=void 0;for(m=0;m<c;m++){var p=n.original.endLineNumberExclusive+m,d=n.modified.endLineNumberExclusive+m;if(p>r.length||d>i.length)break;if(B.contains(d)||j.contains(p))break;if(!mt(r[p-1],i[d-1],o))break}m>0&&(j.addRange(new _(n.original.endLineNumberExclusive,n.original.endLineNumberExclusive+m)),B.addRange(new _(n.modified.endLineNumberExclusive,n.modified.endLineNumberExclusive+m)));if(h>0||m>0)v[t]=new I(new _(n.original.startLineNumber-h,n.original.endLineNumberExclusive+m),new _(n.modified.startLineNumber-h,n.modified.endLineNumberExclusive+m))};for(var x=0;x<v.length;x++)et(x);return v}function mt(e,t,n){function d(t){var n=0;for(var r=0;r<e.length;r++)Y(t.charCodeAt(r))||n++;return n}var r,i;if(e.trim()===t.trim())return!0;if(e.length>300&&t.length>300)return!1;var o=new tt,u=o.compute(new ot([e],new C(1,1,1,e.length),!1),new ot([t],new C(1,1,1,t.length),!1),n),a=0,f=$.invert(u.diffs,e.length);try{for(var l=s(f),c=l.next();!c.done;c=l.next()){var h=c.value;h.seq1Range.forEach(function(t){Y(e.charCodeAt(t))||a++})}}catch(p){r={error:p}}finally{try{c&&!c.done&&(i=l.return)&&i.call(l)}finally{if(r)throw r.error}}var v=d(e.length>t.length?e:t),m=a/v>.6&&v>10;return m}function gt(e){if(e.length===0)return e;e.sort(g(function(e){return e.original.startLineNumber},y));var t=[e[0]];for(var n=1;n<e.length;n++){var r=t[t.length-1],i=e[n],s=i.original.startLineNumber-r.original.endLineNumberExclusive,o=i.modified.startLineNumber-r.modified.endLineNumberExclusive,u=s>=0&&o>=0;if(u&&s+o<=2){t[t.length-1]=r.join(i);continue}t.push(i)}return t}function yt(e,t){var n=new M(e);return t=t.filter(function(t){var r=n.findLastMonotonous(function(e){return e.original.startLineNumber<t.original.endLineNumberExclusive})||new I(new _(1,1),new _(1,1)),i=k(e,function(e){return e.modified.startLineNumber<t.modified.endLineNumberExclusive}),s=r!==i;return s}),t}function bt(e,t,n){var r=n;return r=wt(e,t,r),r=wt(e,t,r),r=Et(e,t,r),r}function wt(e,t,n){if(n.length===0)return n;var r=[];r.push(n[0]);for(var i=1;i<n.length;i++){var s=r[r.length-1],o=n[i];if(o.seq1Range.isEmpty||o.seq2Range.isEmpty){var u=o.seq1Range.start-s.seq1Range.endExclusive,a=void 0;for(a=1;a<=u;a++)if(e.getElement(o.seq1Range.start-a)!==e.getElement(o.seq1Range.endExclusive-a)||t.getElement(o.seq2Range.start-a)!==t.getElement(o.seq2Range.endExclusive-a))break;a--;if(a===u){r[r.length-1]=new $(new T(s.seq1Range.start,o.seq1Range.endExclusive-u),new T(s.seq2Range.start,o.seq2Range.endExclusive-u));continue}o=o.delta(-a)}r.push(o)}var f=[];for(var i=0;i<r.length-1;i++){var l=r[i+1],o=r[i];if(o.seq1Range.isEmpty||o.seq2Range.isEmpty){var u=l.seq1Range.start-o.seq1Range.endExclusive,a=void 0;for(a=0;a<u;a++)if(!e.isStronglyEqual(o.seq1Range.start+a,o.seq1Range.endExclusive+a)||!t.isStronglyEqual(o.seq2Range.start+a,o.seq2Range.endExclusive+a))break;if(a===u){r[i+1]=new $(new T(o.seq1Range.start+u,l.seq1Range.endExclusive),new T(o.seq2Range.start+u,l.seq2Range.endExclusive));continue}a>0&&(o=o.delta(a))}f.push(o)}return r.length>0&&f.push(r[r.length-1]),f}function Et(e,t,n){if(!e.getBoundaryScore||!t.getBoundaryScore)return n;for(var r=0;r<n.length;r++){var i=r>0?n[r-1]:undefined,s=n[r],o=r+1<n.length?n[r+1]:undefined,u=new T(i?i.seq1Range.endExclusive+1:0,o?o.seq1Range.start-1:e.length),a=new T(i?i.seq2Range.endExclusive+1:0,o?o.seq2Range.start-1:t.length);s.seq1Range.isEmpty?n[r]=St(s,e,t,u,a):s.seq2Range.isEmpty&&(n[r]=St(s.swap(),t,e,a,u).swap())}return n}function St(e,t,n,r,i){var s=100,o=1;while(e.seq1Range.start-o>=r.start&&e.seq2Range.start-o>=i.start&&n.isStronglyEqual(e.seq2Range.start-o,e.seq2Range.endExclusive-o)&&o<s)o++;o--;var u=0;while(e.seq1Range.start+u<r.endExclusive&&e.seq2Range.endExclusive+u<i.endExclusive&&n.isStronglyEqual(e.seq2Range.start+u,e.seq2Range.endExclusive+u)&&u<s)u++;if(o===0&&u===0)return e;var a=0,f=-1;for(var l=-o;l<=u;l++){var c=e.seq2Range.start+l,h=e.seq2Range.endExclusive+l,p=e.seq1Range.start+l,d=t.getBoundaryScore(p)+n.getBoundaryScore(c)+n.getBoundaryScore(h);d>f&&(f=d,a=l)}return e.delta(a)}function xt(e,t,n){var r,i,o=[];try{for(var u=s(n),a=u.next();!a.done;a=u.next()){var f=a.value,l=o[o.length-1];if(!l){o.push(f);continue}f.seq1Range.start-l.seq1Range.endExclusive<=2||f.seq2Range.start-l.seq2Range.endExclusive<=2?o[o.length-1]=new $(l.seq1Range.join(f.seq1Range),l.seq2Range.join(f.seq2Range)):o.push(f)}}catch(c){r={error:c}}finally{try{a&&!a.done&&(i=u.return)&&i.call(u)}finally{if(r)throw r.error}}return o}function Tt(e,t,n,r,i){function a(n,a){if(n.offset1<u.offset1||n.offset2<u.offset2)return;var f=r(e,n.offset1),l=r(t,n.offset2);if(!f||!l)return;var c=new $(f,l),h=c.intersect(a),p=h.seq1Range.length,d=h.seq2Range.length;while(s.length>0){var v=s[0],m=v.seq1Range.intersects(c.seq1Range)||v.seq2Range.intersects(c.seq2Range);if(!m)break;var g=r(e,v.seq1Range.start),y=r(t,v.seq2Range.start),b=new $(g,y),w=b.intersect(v);p+=w.seq1Range.length,d+=w.seq2Range.length,c=c.join(b);if(!(c.seq1Range.endExclusive>=v.seq1Range.endExclusive))break;s.shift()}(i&&p+d<c.seq1Range.length+c.seq2Range.length||p+d<(c.seq1Range.length+c.seq2Range.length)*2/3)&&o.push(c),u=c.getEndExclusives()}i===void 0&&(i=!1);var s=$.invert(n,e.length),o=[],u=new J(0,0);while(s.length>0){var f=s.shift();if(f.seq1Range.isEmpty)continue;a(f.getStarts(),f),a(f.getEndExclusives().delta(-1),f)}var l=Nt(n,o);return l}function Nt(e,t){var n=[];while(e.length>0||t.length>0){var r=e[0],i=t[0],s=void 0;r&&(!i||r.seq1Range.start<i.seq1Range.start)?s=e.shift():s=t.shift(),n.length>0&&n[n.length-1].seq1Range.endExclusive>=s.seq1Range.start?n[n.length-1]=n[n.length-1].join(s):n.push(s)}return n}function Ct(e,t,n){var r=n;if(r.length===0)return r;var i=0,s;do{s=!1;var o=[r[0]],u=function(t){var n=function(t,n){var r=new T(u.seq1Range.endExclusive,i.seq1Range.start),s=e.getText(r),o=s.replace(/\s/g,"");return o.length<=4&&(t.seq1Range.length+t.seq2Range.length>5||n.seq1Range.length+n.seq2Range.length>5)?!0:!1},i=r[t],u=o[o.length-1],a=n(u,i);a?(s=!0,o[o.length-1]=o[o.length-1].join(i)):o.push(i)};for(var a=1;a<r.length;a++)u(a);r=o}while(i++<10&&s);return r}function kt(e,t,n){var r=n;if(r.length===0)return r;var i=0,s;do{s=!1;var o=[r[0]],u=function(n){var i=function(n,r){function y(e){return Math.min(e,g)}var i=new T(a.seq1Range.endExclusive,u.seq1Range.start),s=e.countLinesIn(i);if(s>5||i.length>500)return!1;var o=e.getText(i).trim();if(o.length>20||o.split(/\r\n|\r|\n/).length>1)return!1;var f=e.countLinesIn(n.seq1Range),l=n.seq1Range.length,c=t.countLinesIn(n.seq2Range),h=n.seq2Range.length,p=e.countLinesIn(r.seq1Range),d=r.seq1Range.length,v=t.countLinesIn(r.seq2Range),m=r.seq2Range.length,g=130;return Math.pow(Math.pow(y(f*40+l),1.5)+Math.pow(y(c*40+h),1.5),1.5)+Math.pow(Math.pow(y(p*40+d),1.5)+Math.pow(y(v*40+m),1.5),1.5)>Math.pow(Math.pow(g,1.5),1.5)*1.3?!0:!1},u=r[n],a=o[o.length-1],f=i(a,u);f?(s=!0,o[o.length-1]=o[o.length-1].join(u)):o.push(u)};for(var a=1;a<r.length;a++)u(a);r=o}while(i++<10&&s);var f=[];return v(r,function(t,n,r){function s(e){return e.length>0&&e.trim().length<=3&&n.seq1Range.length+n.seq2Range.length>100}var i=n,o=e.extendToFullLines(n.seq1Range),u=e.getText(new T(o.start,n.seq1Range.start));s(u)&&(i=i.deltaStart(-u.length));var a=e.getText(new T(n.seq1Range.endExclusive,o.endExclusive));s(a)&&(i=i.deltaEnd(a.length));var l=$.fromOffsetPairs(t?t.getEndExclusives():J.zero,r?r.getStarts():J.max),c=i.intersect(l);f.length>0&&c.getStarts().equals(f[f.length-1].getEndExclusives())?f[f.length-1]=f[f.length-1].join(c):f.push(c)}),f}function At(e){var t=0;while(t<e.length&&(e.charCodeAt(t)===32||e.charCodeAt(t)===9))t++;return t}function Mt(e){return new I(new _(e.seq1Range.start+1,e.seq1Range.endExclusive+1),new _(e.seq2Range.start+1,e.seq2Range.endExclusive+1))}function _t(e,t,n){var r=new Ot,i=r.computeDiff(e,t,n);return i===null||i===void 0?void 0:i.changes.map(function(e){var t,n,r,i,s=e.innerChanges;return t=e.original.startLineNumber-1,n=e.original.endLineNumberExclusive-1,r=e.modified.startLineNumber-1,i=e.modified.endLineNumberExclusive-1,{origStart:t,origEnd:n,editStart:r,editEnd:i,charChanges:s===null||s===void 0?void 0:s.map(function(e){return{originalStartLineNumber:e.originalRange.startLineNumber-1,originalStartColumn:e.originalRange.startColumn-1,originalEndLineNumber:e.originalRange.endLineNumber-1,originalEndColumn:e.originalRange.endColumn-1,modifiedStartLineNumber:e.modifiedRange.startLineNumber-1,modifiedStartColumn:e.modifiedRange.startColumn-1,modifiedEndLineNumber:e.modifiedRange.endLineNumber-1,modifiedEndColumn:e.modifiedRange.endColumn-1}})}})}var r=this&&this.__extends||function(){var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},e(t,n)};return function(t,n){function r(){this.constructor=t}if(typeof n!="function"&&n!==null)throw new TypeError("Class extends value "+String(n)+" is not a constructor or null");e(t,n),t.prototype=n===null?Object.create(n):(r.prototype=n.prototype,new r)}}(),i=this&&this.__generator||function(e,t){function u(e){return function(t){return a([e,t])}}function a(u){if(r)throw new TypeError("Generator is already executing.");while(o&&(o=0,u[0]&&(n=0)),n)try{if(r=1,i&&(s=u[0]&2?i["return"]:u[0]?i["throw"]||((s=i["return"])&&s.call(i),0):i.next)&&!(s=s.call(i,u[1])).done)return s;if(i=0,s)u=[u[0]&2,s.value];switch(u[0]){case 0:case 1:s=u;break;case 4:return n.label++,{value:u[1],done:!1};case 5:n.label++,i=u[1],u=[0];continue;case 7:u=n.ops.pop(),n.trys.pop();continue;default:if(!(s=n.trys,s=s.length>0&&s[s.length-1])&&(u[0]===6||u[0]===2)){n=0;continue}if(u[0]===3&&(!s||u[1]>s[0]&&u[1]<s[3])){n.label=u[1];break}if(u[0]===6&&n.label<s[1]){n.label=s[1],s=u;break}if(s&&n.label<s[2]){n.label=s[2],n.ops.push(u);break}s[2]&&n.ops.pop(),n.trys.pop();continue}u=t.call(e,n)}catch(a){u=[6,a],i=0}finally{r=s=0}if(u[0]&5)throw u[1];return{value:u[0]?u[1]:void 0,done:!0}}var n={label:0,sent:function(){if(s[0]&1)throw s[1];return s[1]},trys:[],ops:[]},r,i,s,o=Object.create((typeof Iterator=="function"?Iterator:Object).prototype);return o.next=u(0),o["throw"]=u(1),o["return"]=u(2),typeof Symbol=="function"&&(o[Symbol.iterator]=function(){return this}),o},s=this&&this.__values||function(e){var t=typeof Symbol=="function"&&Symbol.iterator,n=t&&e[t],r=0;if(n)return n.call(e);if(e&&typeof e.length=="number")return{next:function(){return e&&r>=e.length&&(e=void 0),{value:e&&e[r++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")},o,u,a,f,l,c,y=function(e,t){return e-t},w=function(e){function t(n){var r=e.call(this,n||"An unexpected bug occurred.")||this;return Object.setPrototypeOf(r,t.prototype),r}return r(t,e),t}(Error),T=function(){function e(e,t){this.start=e,this.endExclusive=t;if(e>t)throw new w("Invalid range: ".concat(this.toString()))}return e.fromTo=function(t,n){return new e(t,n)},e.addRange=function(t,n){var r=0;while(r<n.length&&n[r].endExclusive<t.start)r++;var i=r;while(i<n.length&&n[i].start<=t.endExclusive)i++;if(r===i)n.splice(r,0,t);else{var s=Math.min(t.start,n[r].start),o=Math.max(t.endExclusive,n[i-1].endExclusive);n.splice(r,i-r,new e(s,o))}},e.tryCreate=function(t,n){return t>n?undefined:new e(t,n)},e.ofLength=function(t){return new e(0,t)},e.ofStartAndLength=function(t,n){return new e(t,t+n)},e.emptyAt=function(t){return new e(t,t)},Object.defineProperty(e.prototype,"isEmpty",{get:function(){return this.start===this.endExclusive},enumerable:!1,configurable:!0}),e.prototype.delta=function(t){return new e(this.start+t,this.endExclusive+t)},e.prototype.deltaStart=function(t){return new e(this.start+t,this.endExclusive)},e.prototype.deltaEnd=function(t){return new e(this.start,this.endExclusive+t)},Object.defineProperty(e.prototype,"length",{get:function(){return this.endExclusive-this.start},enumerable:!1,configurable:!0}),e.prototype.toString=function(){return"[".concat(this.start,", ").concat(this.endExclusive,")")},e.prototype.equals=function(e){return this.start===e.start&&this.endExclusive===e.endExclusive},e.prototype.containsRange=function(e){return this.start<=e.start&&e.endExclusive<=this.endExclusive},e.prototype.contains=function(e){return this.start<=e&&e<this.endExclusive},e.prototype.join=function(t){return new e(Math.min(this.start,t.start),Math.max(this.endExclusive,t.endExclusive))},e.prototype.intersect=function(t){var n=Math.max(this.start,t.start),r=Math.min(this.endExclusive,t.endExclusive);return n<=r?new e(n,r):undefined},e.prototype.intersectionLength=function(e){var t=Math.max(this.start,e.start),n=Math.min(this.endExclusive,e.endExclusive);return Math.max(0,n-t)},e.prototype.intersects=function(e){var t=Math.max(this.start,e.start),n=Math.min(this.endExclusive,e.endExclusive);return t<n},e.prototype.intersectsOrTouches=function(e){var t=Math.max(this.start,e.start),n=Math.min(this.endExclusive,e.endExclusive);return t<=n},e.prototype.isBefore=function(e){return this.endExclusive<=e.start},e.prototype.isAfter=function(e){return this.start>=e.endExclusive},e.prototype.slice=function(e){return e.slice(this.start,this.endExclusive)},e.prototype.substring=function(e){return e.substring(this.start,this.endExclusive)},e.prototype.clip=function(e){if(this.isEmpty)throw new w("Invalid clipping range: ".concat(this.toString()));return Math.max(this.start,Math.min(this.endExclusive-1,e))},e.prototype.clipCyclic=function(e){if(this.isEmpty)throw new w("Invalid clipping range: ".concat(this.toString()));return e<this.start?this.endExclusive-(this.start-e)%this.length:e>=this.endExclusive?this.start+(e-this.start)%this.length:e},e.prototype.map=function(e){var t=[];for(var n=this.start;n<this.endExclusive;n++)t.push(e(n));return t},e.prototype.forEach=function(e){for(var t=this.start;t<this.endExclusive;t++)e(t)},e}(),N=function(){function e(e,t){this.lineNumber=e,this.column=t}return e.prototype.equals=function(t){return e.equals(this,t)},e.equals=function(e,t){return!e&&!t?!0:!!e&&!!t&&e.lineNumber===t.lineNumber&&e.column===t.column},e.prototype.isBefore=function(t){return e.isBefore(this,t)},e.isBefore=function(e,t){return e.lineNumber<t.lineNumber?!0:t.lineNumber<e.lineNumber?!1:e.column<t.column},e.prototype.isBeforeOrEqual=function(t){return e.isBeforeOrEqual(this,t)},e.isBeforeOrEqual=function(e,t){return e.lineNumber<t.lineNumber?!0:t.lineNumber<e.lineNumber?!1:e.column<=t.column},e}(),C=function(){function e(e,t,n,r){e>n||e===n&&t>r?(this.startLineNumber=n,this.startColumn=r,this.endLineNumber=e,this.endColumn=t):(this.startLineNumber=e,this.startColumn=t,this.endLineNumber=n,this.endColumn=r)}return e.prototype.isEmpty=function(){return e.isEmpty(this)},e.isEmpty=function(e){return e.startLineNumber===e.endLineNumber&&e.startColumn===e.endColumn},e.prototype.containsPosition=function(t){return e.containsPosition(this,t)},e.containsPosition=function(e,t){return t.lineNumber<e.startLineNumber||t.lineNumber>e.endLineNumber?!1:t.lineNumber===e.startLineNumber&&t.column<e.startColumn?!1:t.lineNumber===e.endLineNumber&&t.column>e.endColumn?!1:!0},e.prototype.containsRange=function(t){return e.containsRange(this,t)},e.containsRange=function(e,t){return t.startLineNumber<e.startLineNumber||t.endLineNumber<e.startLineNumber?!1:t.startLineNumber>e.endLineNumber||t.endLineNumber>e.endLineNumber?!1:t.startLineNumber===e.startLineNumber&&t.startColumn<e.startColumn?!1:t.endLineNumber===e.endLineNumber&&t.endColumn>e.endColumn?!1:!0},e.prototype.strictContainsRange=function(t){return e.strictContainsRange(this,t)},e.strictContainsRange=function(e,t){return t.startLineNumber<e.startLineNumber||t.endLineNumber<e.startLineNumber?!1:t.startLineNumber>e.endLineNumber||t.endLineNumber>e.endLineNumber?!1:t.startLineNumber===e.startLineNumber&&t.startColumn<=e.startColumn?!1:t.endLineNumber===e.endLineNumber&&t.endColumn>=e.endColumn?!1:!0},e.prototype.plusRange=function(t){return e.plusRange(this,t)},e.plusRange=function(t,n){var r,i,s,o;return n.startLineNumber<t.startLineNumber?(r=n.startLineNumber,i=n.startColumn):n.startLineNumber===t.startLineNumber?(r=n.startLineNumber,i=Math.min(n.startColumn,t.startColumn)):(r=t.startLineNumber,i=t.startColumn),n.endLineNumber>t.endLineNumber?(s=n.endLineNumber,o=n.endColumn):n.endLineNumber===t.endLineNumber?(s=n.endLineNumber,o=Math.max(n.endColumn,t.endColumn)):(s=t.endLineNumber,o=t.endColumn),new e(r,i,s,o)},e.prototype.intersectRanges=function(t){return e.intersectRanges(this,t)},e.intersectRanges=function(t,n){var r=t.startLineNumber,i=t.startColumn,s=t.endLineNumber,o=t.endColumn,u=n.startLineNumber,a=n.startColumn,f=n.endLineNumber,l=n.endColumn;return r<u?(r=u,i=a):r===u&&(i=Math.max(i,a)),s>f?(s=f,o=l):s===f&&(o=Math.min(o,l)),r>s?null:r===s&&i>o?null:new e(r,i,s,o)},e.prototype.equalsRange=function(t){return e.equalsRange(this,t)},e.equalsRange=function(e,t){return!e&&!t?!0:!!e&&!!t&&e.startLineNumber===t.startLineNumber&&e.startColumn===t.startColumn&&e.endLineNumber===t.endLineNumber&&e.endColumn===t.endColumn},e.prototype.getEndPosition=function(){return e.getEndPosition(this)},e.getEndPosition=function(e){return new N(e.endLineNumber,e.endColumn)},e.prototype.getStartPosition=function(){return e.getStartPosition(this)},e.getStartPosition=function(e){return new N(e.startLineNumber,e.startColumn)},e.prototype.collapseToStart=function(){return e.collapseToStart(this)},e.collapseToStart=function(t){return new e(t.startLineNumber,t.startColumn,t.startLineNumber,t.startColumn)},e.prototype.collapseToEnd=function(){return e.collapseToEnd(this)},e.collapseToEnd=function(t){return new e(t.endLineNumber,t.endColumn,t.endLineNumber,t.endColumn)},e.fromPositions=function(t,n){return n===void 0&&(n=t),new e(t.lineNumber,t.column,n.lineNumber,n.column)},e}(),M=function(){function e(e){this._array=e,this._findLastMonotonousLastIdx=0}return e.prototype.findLastMonotonous=function(e){var t,n;if(u.assertInvariants){if(this._prevFindLastPredicate)try{for(var r=s(this._array),i=r.next();!i.done;i=r.next()){var o=i.value;if(this._prevFindLastPredicate(o)&&!e(o))throw new Error("MonotonousArray: current predicate must be weaker than (or equal to) the previous predicate.")}}catch(a){t={error:a}}finally{try{i&&!i.done&&(n=r.return)&&n.call(r)}finally{if(t)throw t.error}}this._prevFindLastPredicate=e}var f=L(this._array,e,this._findLastMonotonousLastIdx);return this._findLastMonotonousLastIdx=f+1,f===-1?undefined:this._array[f]},e}();u=M,function(){u.assertInvariants=!1}();var _=function(){function e(e,t){if(e>t)throw new w("startLineNumber ".concat(e," cannot be after endLineNumberExclusive ").concat(t));this.startLineNumber=e,this.endLineNumberExclusive=t}return e.fromRangeInclusive=function(t){return new e(t.startLineNumber,t.endLineNumber+1)},e.join=function(t){if(t.length===0)throw new w("lineRanges cannot be empty");var n=t[0].startLineNumber,r=t[0].endLineNumberExclusive;for(var i=1;i<t.length;i++)n=Math.min(n,t[i].startLineNumber),r=Math.max(r,t[i].endLineNumberExclusive);return new e(n,r)},e.ofLength=function(t,n){return new e(t,t+n)},Object.defineProperty(e.prototype,"isEmpty",{get:function(){return this.startLineNumber===this.endLineNumberExclusive},enumerable:!1,configurable:!0}),e.prototype.delta=function(t){return new e(this.startLineNumber+t,this.endLineNumberExclusive+t)},Object.defineProperty(e.prototype,"length",{get:function(){return this.endLineNumberExclusive-this.startLineNumber},enumerable:!1,configurable:!0}),e.prototype.join=function(t){return new e(Math.min(this.startLineNumber,t.startLineNumber),Math.max(this.endLineNumberExclusive,t.endLineNumberExclusive))},e.prototype.intersect=function(t){var n=Math.max(this.startLineNumber,t.startLineNumber),r=Math.min(this.endLineNumberExclusive,t.endLineNumberExclusive);return n<=r?new e(n,r):undefined},e.prototype.overlapOrTouch=function(e){return this.startLineNumber<=e.endLineNumberExclusive&&e.startLineNumber<=this.endLineNumberExclusive},e.prototype.toInclusiveRange=function(){return this.isEmpty?null:new C(this.startLineNumber,1,this.endLineNumberExclusive-1,Number.MAX_SAFE_INTEGER)},e.prototype.toOffsetRange=function(){return new T(this.startLineNumber-1,this.endLineNumberExclusive-1)},e}(),D=function(){function e(e){e===void 0&&(e=[]),this._normalizedRanges=e}return Object.defineProperty(e.prototype,"ranges",{get:function(){return this._normalizedRanges},enumerable:!1,configurable:!0}),e.prototype.addRange=function(e){if(e.length===0)return;var t=O(this._normalizedRanges,function(t){return t.endLineNumberExclusive>=e.startLineNumber}),n=L(this._normalizedRanges,function(t){return t.startLineNumber<=e.endLineNumberExclusive})+1;if(t===n)this._normalizedRanges.splice(t,0,e);else if(t===n-1){var r=this._normalizedRanges[t];this._normalizedRanges[t]=r.join(e)}else{var r=this._normalizedRanges[t].join(this._normalizedRanges[n-1]).join(e);this._normalizedRanges.splice(t,n-t,r)}},e.prototype.contains=function(e){var t=k(this._normalizedRanges,function(t){return t.startLineNumber<=e});return!!t&&t.endLineNumberExclusive>e},e.prototype.subtractFrom=function(t){var n=O(this._normalizedRanges,function(e){return e.endLineNumberExclusive>=t.startLineNumber}),r=L(this._normalizedRanges,function(e){return e.startLineNumber<=t.endLineNumberExclusive})+1;if(n===r)return new e([t]);var i=[],s=t.startLineNumber;for(var o=n;o<r;o++){var u=this._normalizedRanges[o];u.startLineNumber>s&&i.push(new _(s,u.startLineNumber)),s=u.endLineNumberExclusive}return s<t.endLineNumberExclusive&&i.push(new _(s,t.endLineNumberExclusive)),new e(i)},e.prototype.getIntersection=function(t){var n=[],r=0,i=0;while(r<this._normalizedRanges.length&&i<t._normalizedRanges.length){var s=this._normalizedRanges[r],o=t._normalizedRanges[i],u=s.intersect(o);u&&!u.isEmpty&&n.push(u),s.endLineNumberExclusive<o.endLineNumberExclusive?r++:i++}return new e(n)},e.prototype.getWithDelta=function(t){return new e(this._normalizedRanges.map(function(e){return e.delta(t)}))},e}(),P=function(){function e(e,t){this.lineCount=e,this.columnCount=t}return e.prototype.toLineRange=function(){return _.ofLength(1,this.lineCount)},e.prototype.addToPosition=function(e){return this.lineCount===0?new N(e.lineNumber,e.column+this.columnCount):new N(e.lineNumber+this.lineCount,this.columnCount+1)},e}();a=P,function(){a.zero=new a(0,0)}();var H=function(){function e(e,t){E(t>=1),this._getLineContent=e,this._lineCount=t}return e.prototype.getValueOfRange=function(e){if(e.startLineNumber===e.endLineNumber)return this._getLineContent(e.startLineNumber).substring(e.startColumn-1,e.endColumn-1);var t=this._getLineContent(e.startLineNumber).substring(e.startColumn-1);for(var n=e.startLineNumber+1;n<e.endLineNumber;n++)t+="\n"+this._getLineContent(n);return t+="\n"+this._getLineContent(e.endLineNumber).substring(0,e.endColumn-1),t},e.prototype.getLineLength=function(e){return this._getLineContent(e).length},Object.defineProperty(e.prototype,"length",{get:function(){var e=this._getLineContent(this._lineCount);return new P(this._lineCount-1,e.length)},enumerable:!1,configurable:!0}),e}(),B=function(e){function t(t){return e.call(this,function(e){return t[e-1]},t.length)||this}return r(t,e),t}(H),j=function(){function e(e,t,n){this.changes=e,this.moves=t,this.hitTimeout=n}return e}(),F=function(){function e(e,t){this.lineRangeMapping=e,this.changes=t}return e}(),I=function(){function e(e,t){this.original=e,this.modified=t}return e.prototype.join=function(t){return new e(this.original.join(t.original),this.modified.join(t.modified))},Object.defineProperty(e.prototype,"changedLineCount",{get:function(){return Math.max(this.original.length,this.modified.length)},enumerable:!1,configurable:!0}),e.prototype.toRangeMapping=function(){var e=this.original.toInclusiveRange(),t=this.modified.toInclusiveRange();if(e&&t)return new z(e,t);if(this.original.startLineNumber===1||this.modified.startLineNumber===1){if(this.modified.startLineNumber!==1||this.original.startLineNumber!==1)throw new w("not a valid diff");return new z(new C(this.original.startLineNumber,1,this.original.endLineNumberExclusive,1),new C(this.modified.startLineNumber,1,this.modified.endLineNumberExclusive,1))}return new z(new C(this.original.startLineNumber-1,Number.MAX_SAFE_INTEGER,this.original.endLineNumberExclusive-1,Number.MAX_SAFE_INTEGER),new C(this.modified.startLineNumber-1,Number.MAX_SAFE_INTEGER,this.modified.endLineNumberExclusive-1,Number.MAX_SAFE_INTEGER))},e.prototype.toRangeMapping2=function(e,t){if(R(this.original.endLineNumberExclusive,e)&&R(this.modified.endLineNumberExclusive,t))return new z(new C(this.original.startLineNumber,1,this.original.endLineNumberExclusive,1),new C(this.modified.startLineNumber,1,this.modified.endLineNumberExclusive,1));if(!this.original.isEmpty&&!this.modified.isEmpty)return new z(C.fromPositions(new N(this.original.startLineNumber,1),q(new N(this.original.endLineNumberExclusive-1,Number.MAX_SAFE_INTEGER),e)),C.fromPositions(new N(this.modified.startLineNumber,1),q(new N(this.modified.endLineNumberExclusive-1,Number.MAX_SAFE_INTEGER),t)));if(this.original.startLineNumber>1&&this.modified.startLineNumber>1)return new z(C.fromPositions(q(new N(this.original.startLineNumber-1,Number.MAX_SAFE_INTEGER),e),q(new N(this.original.endLineNumberExclusive-1,Number.MAX_SAFE_INTEGER),e)),C.fromPositions(q(new N(this.modified.startLineNumber-1,Number.MAX_SAFE_INTEGER),t),q(new N(this.modified.endLineNumberExclusive-1,Number.MAX_SAFE_INTEGER),t)));throw new w},e}(),U=function(e){function t(t,n,r){var i=e.call(this,t,n)||this;return i.innerChanges=r,i}return r(t,e),t.fromRangeMappings=function(e){var n=_.join(e.map(function(e){return _.fromRangeInclusive(e.originalRange)})),r=_.join(e.map(function(e){return _.fromRangeInclusive(e.modifiedRange)}));return new t(n,r,e)},t.prototype.flip=function(){var e;return new t(this.modified,this.original,(e=this.innerChanges)===null||e===void 0?void 0:e.map(function(e){return e.flip()}))},t.prototype.withInnerChangesFromLineRanges=function(){return new t(this.original,this.modified,[this.toRangeMapping()])},t}(I),z=function(){function e(e,t){this.originalRange=e,this.modifiedRange=t}return e.join=function(e){if(e.length===0)throw new w("Cannot join an empty list of range mappings");var t=e[0];for(var n=1;n<e.length;n++)t=t.join(e[n]);return t},e.assertSorted=function(e){for(var t=1;t<e.length;t++){var n=e[t-1],r=e[t];if(!n.originalRange.getEndPosition().isBeforeOrEqual(r.originalRange.getStartPosition())||!n.modifiedRange.getEndPosition().isBeforeOrEqual(r.modifiedRange.getStartPosition()))throw new w("Range mappings must be sorted")}},e.prototype.flip=function(){return new e(this.modifiedRange,this.originalRange)},e.prototype.join=function(t){return new e(this.originalRange.plusRange(t.originalRange),this.modifiedRange.plusRange(t.modifiedRange))},e}(),V=function(){function e(e,t){this.diffs=e,this.hitTimeout=t}return e.trivial=function(t,n){return new e([new $(T.ofLength(t.length),T.ofLength(n.length))],!1)},e.trivialTimedOut=function(t,n){return new e([new $(T.ofLength(t.length),T.ofLength(n.length))],!0)},e}(),$=function(){function e(e,t){this.seq1Range=e,this.seq2Range=t}return e.invert=function(t,n){var r=[];return d(t,function(t,i){r.push(e.fromOffsetPairs(t?t.getEndExclusives():J.zero,i?i.getStarts():new J(n,(t?t.seq2Range.endExclusive-t.seq1Range.endExclusive:0)+n)))}),r},e.fromOffsetPairs=function(t,n){return new e(new T(t.offset1,n.offset1),new T(t.offset2,n.offset2))},e.assertSorted=function(e){var t,n,r=undefined;try{for(var i=s(e),o=i.next();!o.done;o=i.next()){var u=o.value;if(!(!r||r.seq1Range.endExclusive<=u.seq1Range.start&&r.seq2Range.endExclusive<=u.seq2Range.start))throw new w("Sequence diffs must be sorted");r=u}}catch(a){t={error:a}}finally{try{o&&!o.done&&(n=i.return)&&n.call(i)}finally{if(t)throw t.error}}},e.prototype.swap=function(){return new e(this.seq2Range,this.seq1Range)},e.prototype.join=function(t){return new e(this.seq1Range.join(t.seq1Range),this.seq2Range.join(t.seq2Range))},e.prototype.delta=function(t){return t===0?this:new e(this.seq1Range.delta(t),this.seq2Range.delta(t))},e.prototype.deltaStart=function(t){return t===0?this:new e(this.seq1Range.deltaStart(t),this.seq2Range.deltaStart(t))},e.prototype.deltaEnd=function(t){return t===0?this:new e(this.seq1Range.deltaEnd(t),this.seq2Range.deltaEnd(t))},e.prototype.intersect=function(t){var n=this.seq1Range.intersect(t.seq1Range),r=this.seq2Range.intersect(t.seq2Range);return!n||!r?undefined:new e(n,r)},e.prototype.getStarts=function(){return new J(this.seq1Range.start,this.seq2Range.start)},e.prototype.getEndExclusives=function(){return new J(this.seq1Range.endExclusive,this.seq2Range.endExclusive)},e}(),J=function(){function e(e,t){this.offset1=e,this.offset2=t}return e.prototype.delta=function(e){return e===0?this:new f(this.offset1+e,this.offset2+e)},e.prototype.equals=function(e){return this.offset1===e.offset1&&this.offset2===e.offset2},e}();f=J,function(){f.zero=new f(0,0)}(),function(){f.max=new f(Number.MAX_SAFE_INTEGER,Number.MAX_SAFE_INTEGER)}();var K=function(){function e(){}return e.prototype.isValid=function(){return!0},e}();l=K,function(){l.instance=new l}();var Q=function(){function e(e){this.timeout=e,this.startTime=Date.now(),this.valid=!0;if(e<=0)throw new w("timeout must be positive")}return e.prototype.isValid=function(){var e=Date.now()-this.startTime<this.timeout;return!e&&this.valid&&(this.valid=!1),this.valid},e.prototype.disable=function(){this.timeout=Number.MAX_SAFE_INTEGER,this.isValid=function(){return!0},this.valid=!0},e}(),G=function(){function e(e,t){this.width=e,this.height=t,this.array=[],this.array=new Array(e*t)}return e.prototype.get=function(e,t){return this.array[e+t*this.width]},e.prototype.set=function(e,t,n){this.array[e+t*this.width]=n},e}(),Z=function(){function e(e,t,n){this.range=e,this.lines=t,this.source=n,this.histogram=[];var r=0;for(var i=e.startLineNumber-1;i<e.endLineNumberExclusive-1;i++){var s=t[i];for(var o=0;o<s.length;o++){r++;var u=s[o],a=c.getKey(u);this.histogram[a]=(this.histogram[a]||0)+1}r++;var f=c.getKey("\n");this.histogram[f]=(this.histogram[f]||0)+1}this.totalCount=r}return e.getKey=function(e){var t=this.chrKeys.get(e);return t===undefined&&(t=this.chrKeys.size,this.chrKeys.set(e,t)),t},e.prototype.computeSimilarity=function(e){var t,n,r=0,i=Math.max(this.histogram.length,e.histogram.length);for(var s=0;s<i;s++)r+=Math.abs(((t=this.histogram[s])!==null&&t!==void 0?t:0)-((n=e.histogram[s])!==null&&n!==void 0?n:0));return 1-r/(this.totalCount+e.totalCount)},e}();c=Z,function(){c.chrKeys=new Map}();var et=function(){function e(){}return e.prototype.compute=function(e,t,n,r){function g(e,t){(e+1!==v||t+1!==m)&&d.push(new $(new T(e+1,v),new T(t+1,m))),v=e,m=t}n===void 0&&(n=K.instance);if(e.length===0||t.length===0)return V.trivial(e,t);var i=new G(e.length,t.length),s=new G(e.length,t.length),o=new G(e.length,t.length);for(var u=0;u<e.length;u++)for(var a=0;a<t.length;a++){if(!n.isValid())return V.trivialTimedOut(e,t);var f=u===0?0:i.get(u-1,a),l=a===0?0:i.get(u,a-1),c=void 0;e.getElement(u)===t.getElement(a)?(u===0||a===0?c=0:c=i.get(u-1,a-1),u>0&&a>0&&s.get(u-1,a-1)===3&&(c+=o.get(u-1,a-1)),c+=r?r(u,a):1):c=-1;var h=Math.max(f,l,c);if(h===c){var p=u>0&&a>0?o.get(u-1,a-1):0;o.set(u,a,p+1),s.set(u,a,3)}else h===f?(o.set(u,a,0),s.set(u,a,1)):h===l&&(o.set(u,a,0),s.set(u,a,2));i.set(u,a,h)}var d=[],v=e.length,m=t.length,y=e.length-1,b=t.length-1;while(y>=0&&b>=0)s.get(y,b)===3?(g(y,b),y--,b--):s.get(y,b)===1?y--:b--;return g(-1,-1),d.reverse(),new V(d,!1)},e}(),tt=function(){function e(){}return e.prototype.compute=function(e,t,n){function s(e,t){while(e<r.length&&t<i.length&&r.getElement(e)===i.getElement(t))e++,t++;return e}n===void 0&&(n=K.instance);if(e.length===0||t.length===0)return V.trivial(e,t);var r=e,i=t,o=0,u=new rt;u.set(0,s(0,0));var a=new it;a.set(0,u.get(0)===0?null:new nt(null,0,0,u.get(0)));var f=0;e:for(;;){o++;if(!n.isValid())return V.trivialTimedOut(r,i);var l=-Math.min(o,i.length+o%2),c=Math.min(o,r.length+o%2);for(f=l;f<=c;f+=2){var h=f===c?-1:u.get(f+1),p=f===l?-1:u.get(f-1)+1,d=Math.min(Math.max(h,p),r.length),v=d-f;if(d>r.length||v>i.length)continue;var m=s(d,v);u.set(f,m);var g=d===h?a.get(f+1):a.get(f-1);a.set(f,m!==d?new nt(g,d,v,m-d):g);if(u.get(f)===r.length&&u.get(f)-f===i.length)break e}}var y=a.get(f),b=[],w=r.length,E=i.length;for(;;){var S=y?y.x+y.length:0,x=y?y.y+y.length:0;(S!==w||x!==E)&&b.push(new $(new T(S,w),new T(x,E)));if(!y)break;w=y.x,E=y.y,y=y.prev}return b.reverse(),new V(b,!1)},e}(),nt=function(){function e(e,t,n,r){this.prev=e,this.x=t,this.y=n,this.length=r}return e}(),rt=function(){function e(){this.positiveArr=new Int32Array(10),this.negativeArr=new Int32Array(10)}return e.prototype.get=function(e){return e<0?(e=-e-1,this.negativeArr[e]):this.positiveArr[e]},e.prototype.set=function(e,t){if(e<0){e=-e-1;if(e>=this.negativeArr.length){var n=this.negativeArr;this.negativeArr=new Int32Array(n.length*2),this.negativeArr.set(n)}this.negativeArr[e]=t}else{if(e>=this.positiveArr.length){var n=this.positiveArr;this.positiveArr=new Int32Array(n.length*2),this.positiveArr.set(n)}this.positiveArr[e]=t}},e}(),it=function(){function e(){this.positiveArr=[],this.negativeArr=[]}return e.prototype.get=function(e){return e<0?(e=-e-1,this.negativeArr[e]):this.positiveArr[e]},e.prototype.set=function(e,t){e<0?(e=-e-1,this.negativeArr[e]=t):this.positiveArr[e]=t},e}(),st=function(){function e(){this.map=new Map}return e.prototype.add=function(e,t){var n=this.map.get(e);n||(n=new Set,this.map.set(e,n)),n.add(t)},e.prototype.forEach=function(e,t){var n=this.map.get(e);if(!n)return;n.forEach(t)},e.prototype.get=function(e){var t=this.map.get(e);return t?t:new Set},e}(),ot=function(){function e(e,t,n){this.lines=e,this.range=t,this.considerWhitespaceChanges=n,this.elements=[],this.firstElementOffsetByLineIdx=[],this.lineStartOffsets=[],this.trimmedWsLengthsByLineIdx=[],this.firstElementOffsetByLineIdx.push(0);for(var r=this.range.startLineNumber;r<=this.range.endLineNumber;r++){var i=e[r-1],s=0;r===this.range.startLineNumber&&this.range.startColumn>1&&(s=this.range.startColumn-1,i=i.substring(s)),this.lineStartOffsets.push(s);var o=0;if(!n){var u=i.trimStart();o=i.length-u.length,i=u.trimEnd()}this.trimmedWsLengthsByLineIdx.push(o);var a=r===this.range.endLineNumber?Math.min(this.range.endColumn-1-s-o,i.length):i.length;for(var f=0;f<a;f++)this.elements.push(i.charCodeAt(f));r<this.range.endLineNumber&&(this.elements.push("\n".charCodeAt(0)),this.firstElementOffsetByLineIdx.push(this.elements.length))}}return e.prototype.toString=function(){return'Slice: "'.concat(this.text,'"')},Object.defineProperty(e.prototype,"text",{get:function(){return this.getText(new T(0,this.length))},enumerable:!1,configurable:!0}),e.prototype.getText=function(e){return this.elements.slice(e.start,e.endExclusive).map(function(e){return String.fromCharCode(e)}).join("")},e.prototype.getElement=function(e){return this.elements[e]},Object.defineProperty(e.prototype,"length",{get:function(){return this.elements.length},enumerable:!1,configurable:!0}),e.prototype.getBoundaryScore=function(e){var t=ct(e>0?this.elements[e-1]:-1),n=ct(e<this.elements.length?this.elements[e]:-1);if(t===7&&n===8)return 0;if(t===8)return 150;var r=0;return t!==n&&(r+=10,t===0&&n===1&&(r+=1)),r+=lt(t),r+=lt(n),r},e.prototype.translateOffset=function(e,t){t===void 0&&(t="right");var n=L(this.firstElementOffsetByLineIdx,function(t){return t<=e}),r=e-this.firstElementOffsetByLineIdx[n];return new N(this.range.startLineNumber+n,1+this.lineStartOffsets[n]+r+(r===0&&t==="left"?0:this.trimmedWsLengthsByLineIdx[n]))},e.prototype.translateRange=function(e){var t=this.translateOffset(e.start,"right"),n=this.translateOffset(e.endExclusive,"left");return n.isBefore(t)?C.fromPositions(n,n):C.fromPositions(t,n)},e.prototype.findWordContaining=function(e){if(e<0||e>=this.elements.length)return undefined;if(!ut(this.elements[e]))return undefined;var t=e;while(t>0&&ut(this.elements[t-1]))t--;var n=e;while(n<this.elements.length&&ut(this.elements[n]))n++;return new T(t,n)},e.prototype.findSubWordContaining=function(e){if(e<0||e>=this.elements.length)return undefined;if(!ut(this.elements[e]))return undefined;var t=e;while(t>0&&ut(this.elements[t-1])&&!at(this.elements[t]))t--;var n=e;while(n<this.elements.length&&ut(this.elements[n])&&!at(this.elements[n]))n++;return new T(t,n)},e.prototype.countLinesIn=function(e){return this.translateOffset(e.endExclusive).lineNumber-this.translateOffset(e.start).lineNumber},e.prototype.isStronglyEqual=function(e,t){return this.elements[e]===this.elements[t]},e.prototype.extendToFullLines=function(e){var t,n,r=(t=k(this.firstElementOffsetByLineIdx,function(t){return t<=e.start}))!==null&&t!==void 0?t:0,i=(n=A(this.firstElementOffsetByLineIdx,function(t){return e.endExclusive<=t}))!==null&&n!==void 0?n:this.elements.length;return new T(r,i)},e}(),ft=(o={},o[0]=0,o[1]=0,o[2]=0,o[3]=10,o[4]=2,o[5]=30,o[6]=3,o[7]=10,o[8]=10,o),Lt=function(){function e(e,t){this.trimmedHash=e,this.lines=t}return e.prototype.getElement=function(e){return this.trimmedHash[e]},Object.defineProperty(e.prototype,"length",{get:function(){return this.trimmedHash.length},enumerable:!1,configurable:!0}),e.prototype.getBoundaryScore=function(e){var t=e===0?0:At(this.lines[e-1]),n=e===this.lines.length?0:At(this.lines[e]);return 1e3-(t+n)},e.prototype.getText=function(e){return this.lines.slice(e.start,e.endExclusive).join("\n")},e.prototype.isStronglyEqual=function(e,t){return this.lines[e]===this.lines[t]},e}(),Ot=function(){function e(){this.dynamicProgrammingDiffing=new et,this.myersDiffingAlgorithm=new tt}return e.prototype.computeDiff=function(e,t,n){function l(e){var t=f.get(e);return t===undefined&&(t=f.size,f.set(e,t)),t}var r,i,o=this;if(e.length<=1&&h(e,t,function(e,t){return e===t}))return new j([],[],!1);if(e.length===1&&e[0].length===0||t.length===1&&t[0].length===0)return new j([new U(new _(1,e.length+1),new _(1,t.length+1),[new z(new C(1,1,e.length,e[e.length-1].length+1),new C(1,1,t.length,t[t.length-1].length+1))])],[],!1);var u=n.maxComputationTimeMs===0?K.instance:new Q(n.maxComputationTimeMs),a=!n.ignoreTrimWhitespace,f=new Map,c=e.map(function(e){return l(e.trim())}),p=t.map(function(e){return l(e.trim())}),d=new Lt(c,e),v=new Lt(p,t),m=function(){return d.length+v.length<1700?o.dynamicProgrammingDiffing.compute(d,v,u,function(n,r){return e[n]===t[r]?t[r].length===0?.1:1+Math.log(1+t[r].length):.99}):o.myersDiffingAlgorithm.compute(d,v,u)}(),g=m.diffs,y=m.hitTimeout;g=bt(d,v,g),g=Ct(d,v,g);var b=[],w=function(r){var i,f;if(!a)return;for(var l=0;l<r;l++){var c=E+l,h=x+l;if(e[c]!==t[h]){var p=o.refineDiff(e,t,new $(new T(c,c+1),new T(h,h+1)),u,a,n);try{for(var d=(i=void 0,s(p.mappings)),v=d.next();!v.done;v=d.next()){var m=v.value;b.push(m)}}catch(g){i={error:g}}finally{try{v&&!v.done&&(f=d.return)&&f.call(d)}finally{if(i)throw i.error}}p.hitTimeout&&(y=!0)}}},E=0,x=0,N=function(r){var i,o;S(function(){return r.seq1Range.start-E===r.seq2Range.start-x});var f=r.seq1Range.start-E;w(f),E=r.seq1Range.endExclusive,x=r.seq2Range.endExclusive;var l=k.refineDiff(e,t,r,u,a,n);l.hitTimeout&&(y=!0);try{for(var c=(i=void 0,s(l.mappings)),h=c.next();!h.done;h=c.next()){var p=h.value;b.push(p)}}catch(d){i={error:d}}finally{try{h&&!h.done&&(o=c.return)&&o.call(c)}finally{if(i)throw i.error}}},k=this;try{for(var L=s(g),A=L.next();!A.done;A=L.next()){var O=A.value;N(O)}}catch(M){r={error:M}}finally{try{A&&!A.done&&(i=L.return)&&i.call(L)}finally{if(r)throw r.error}}w(e.length-E);var D=W(b,new B(e),new B(t)),P=[];return n.computeMoves&&(P=this.computeMoves(D,e,t,c,p,u,a,n)),S(function(){function u(e,t){if(e.lineNumber<1||e.lineNumber>t.length)return!1;var n=t[e.lineNumber-1];return e.column<1||e.column>n.length+1?!1:!0}function a(e,t){return e.startLineNumber<1||e.startLineNumber>t.length+1?!1:e.endLineNumberExclusive<1||e.endLineNumberExclusive>t.length+1?!1:!0}var n,r,i,o;try{for(var f=s(D),l=f.next();!l.done;l=f.next()){var c=l.value;if(!c.innerChanges)return!1;try{for(var h=(i=void 0,s(c.innerChanges)),p=h.next();!p.done;p=h.next()){var d=p.value,v=u(d.modifiedRange.getStartPosition(),t)&&u(d.modifiedRange.getEndPosition(),t)&&u(d.originalRange.getStartPosition(),e)&&u(d.originalRange.getEndPosition(),e);if(!v)return!1}}catch(m){i={error:m}}finally{try{p&&!p.done&&(o=h.return)&&o.call(h)}finally{if(i)throw i.error}}if(!a(c.modified,t)||!a(c.original,e))return!1}}catch(g){n={error:g}}finally{try{l&&!l.done&&(r=f.return)&&r.call(f)}finally{if(n)throw n.error}}return!0}),new j(D,P,y)},e.prototype.computeMoves=function(e,t,n,r,i,s,o,u){var a=this,f=ht(e,t,n,r,i,s),l=f.map(function(e){var r=a.refineDiff(t,n,new $(e.original.toOffsetRange(),e.modified.toOffsetRange()),s,o,u),i=W(r.mappings,new B(t),new B(n),!0);return new F(e,i)});return l},e.prototype.refineDiff=function(e,t,n,r,i,s){var o=Mt(n),u=o.toRangeMapping2(e,t),a=new ot(e,u.originalRange,i),f=new ot(t,u.modifiedRange,i),l=a.length+f.length<500?this.dynamicProgrammingDiffing.compute(a,f,r):this.myersDiffingAlgorithm.compute(a,f,r),c=l.diffs;c=bt(a,f,c),c=Tt(a,f,c,function(e,t){return e.findWordContaining(t)}),s.extendToSubwords&&(c=Tt(a,f,c,function(e,t){return e.findSubWordContaining(t)},!0)),c=xt(a,f,c),c=kt(a,f,c);var h=c.map(function(e){return new z(a.translateRange(e.seq1Range),f.translateRange(e.seq2Range))});return{mappings:h,hitTimeout:l.hitTimeout}},e}();t.computeDiff=_t;var Dt=e("../../../range").Range,Pt=e("../base_diff_view").DiffChunk,Ht=function(){function e(){}return e.prototype.compute=function(e,t,n){n||(n={}),n.maxComputationTimeMs||(n.maxComputationTimeMs=500);var r=_t(e,t,n)||[];return r.map(function(e){return new Pt(new Dt(e.origStart,0,e.origEnd,0),new Dt(e.editStart,0,e.editEnd,0),e.charChanges)})},e}();t.DiffProvider=Ht}),define("ace/ext/diff",["require","exports","module","ace/ext/diff/inline_diff_view","ace/ext/diff/split_diff_view","ace/ext/diff/providers/default"],function(e,t,n){function o(e,t){e=e||{},e.diffProvider=e.diffProvider||new s;var n;return e.inline?n=new r(e):n=new i(e),t&&n.setOptions(t),n}var r=e("./diff/inline_diff_view").InlineDiffView,i=e("./diff/split_diff_view").SplitDiffView,s=e("./diff/providers/default").DiffProvider;t.InlineDiffView=r,t.SplitDiffView=i,t.DiffProvider=s,t.createDiffView=o}); (function() {
2
+ window.require(["ace/ext/diff"], function(m) {
3
+ if (typeof module == "object" && typeof exports == "object" && module) {
4
+ module.exports = m;
5
+ }
6
+ });
7
+ })();
8
+
webui/vendor/ace-min/ext-elastic_tabstops_lite.js ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ define("ace/ext/elastic_tabstops_lite",["require","exports","module","ace/editor","ace/config"],function(e,t,n){"use strict";var r=function(){function e(e){this.$editor=e;var t=this,n=[],r=!1;this.onAfterExec=function(){r=!1,t.processRows(n),n=[]},this.onExec=function(){r=!0},this.onChange=function(e){r&&(n.indexOf(e.start.row)==-1&&n.push(e.start.row),e.end.row!=e.start.row&&n.push(e.end.row))}}return e.prototype.processRows=function(e){this.$inChange=!0;var t=[];for(var n=0,r=e.length;n<r;n++){var i=e[n];if(t.indexOf(i)>-1)continue;var s=this.$findCellWidthsForBlock(i),o=this.$setBlockCellWidthsToMax(s.cellWidths),u=s.firstRow;for(var a=0,f=o.length;a<f;a++){var l=o[a];t.push(u),this.$adjustRow(u,l),u++}}this.$inChange=!1},e.prototype.$findCellWidthsForBlock=function(e){var t=[],n,r=e;while(r>=0){n=this.$cellWidthsForRow(r);if(n.length==0)break;t.unshift(n),r--}var i=r+1;r=e;var s=this.$editor.session.getLength();while(r<s-1){r++,n=this.$cellWidthsForRow(r);if(n.length==0)break;t.push(n)}return{cellWidths:t,firstRow:i}},e.prototype.$cellWidthsForRow=function(e){var t=this.$selectionColumnsForRow(e),n=[-1].concat(this.$tabsForRow(e)),r=n.map(function(e){return 0}).slice(1),i=this.$editor.session.getLine(e);for(var s=0,o=n.length-1;s<o;s++){var u=n[s]+1,a=n[s+1],f=this.$rightmostSelectionInCell(t,a),l=i.substring(u,a);r[s]=Math.max(l.replace(/\s+$/g,"").length,f-u)}return r},e.prototype.$selectionColumnsForRow=function(e){var t=[],n=this.$editor.getCursorPosition();return this.$editor.session.getSelection().isEmpty()&&e==n.row&&t.push(n.column),t},e.prototype.$setBlockCellWidthsToMax=function(e){var t=!0,n,r,i,s=this.$izip_longest(e);for(var o=0,u=s.length;o<u;o++){var a=s[o];if(!a.push){console.error(a);continue}a.push(NaN);for(var f=0,l=a.length;f<l;f++){var c=a[f];t&&(n=f,i=0,t=!1);if(isNaN(c)){r=f;for(var h=n;h<r;h++)e[h][o]=i;t=!0}i=Math.max(i,c)}}return e},e.prototype.$rightmostSelectionInCell=function(e,t){var n=0;if(e.length){var r=[];for(var i=0,s=e.length;i<s;i++)e[i]<=t?r.push(i):r.push(0);n=Math.max.apply(Math,r)}return n},e.prototype.$tabsForRow=function(e){var t=[],n=this.$editor.session.getLine(e),r=/\t/g,i;while((i=r.exec(n))!=null)t.push(i.index);return t},e.prototype.$adjustRow=function(e,t){var n=this.$tabsForRow(e);if(n.length==0)return;var r=0,i=-1,s=this.$izip(t,n);for(var o=0,u=s.length;o<u;o++){var a=s[o][0],f=s[o][1];i+=1+a,f+=r;var l=i-f;if(l==0)continue;var c=this.$editor.session.getLine(e).substr(0,f),h=c.replace(/\s*$/g,""),p=c.length-h.length;l>0&&(this.$editor.session.getDocument().insertInLine({row:e,column:f+1},Array(l+1).join(" ")+" "),this.$editor.session.getDocument().removeInLine(e,f,f+1),r+=l),l<0&&p>=-l&&(this.$editor.session.getDocument().removeInLine(e,f+l,f),r+=l)}},e.prototype.$izip_longest=function(e){if(!e[0])return[];var t=e[0].length,n=e.length;for(var r=1;r<n;r++){var i=e[r].length;i>t&&(t=i)}var s=[];for(var o=0;o<t;o++){var u=[];for(var r=0;r<n;r++)e[r][o]===""?u.push(NaN):u.push(e[r][o]);s.push(u)}return s},e.prototype.$izip=function(e,t){var n=e.length>=t.length?t.length:e.length,r=[];for(var i=0;i<n;i++){var s=[e[i],t[i]];r.push(s)}return r},e}();t.ElasticTabstopsLite=r;var i=e("../editor").Editor;e("../config").defineOptions(i.prototype,"editor",{useElasticTabstops:{set:function(e){e?(this.elasticTabstops||(this.elasticTabstops=new r(this)),this.commands.on("afterExec",this.elasticTabstops.onAfterExec),this.commands.on("exec",this.elasticTabstops.onExec),this.on("change",this.elasticTabstops.onChange)):this.elasticTabstops&&(this.commands.removeListener("afterExec",this.elasticTabstops.onAfterExec),this.commands.removeListener("exec",this.elasticTabstops.onExec),this.removeListener("change",this.elasticTabstops.onChange))}}})}); (function() {
2
+ window.require(["ace/ext/elastic_tabstops_lite"], function(m) {
3
+ if (typeof module == "object" && typeof exports == "object" && module) {
4
+ module.exports = m;
5
+ }
6
+ });
7
+ })();
8
+