mindroot 10.5.0__py3-none-any.whl → 10.14.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mindroot/coreplugins/admin/static/js/agent-form.js +26 -1
- mindroot/coreplugins/admin/static/js/persona-editor.js +14 -1
- mindroot/coreplugins/agent/agent.py +46 -21
- mindroot/coreplugins/agent/buagentz1.py +540 -0
- mindroot/coreplugins/agent/speech_to_speech.py +77 -0
- mindroot/coreplugins/agent/speech_to_speech.py.backup +46 -0
- mindroot/coreplugins/chat/buservices.py +625 -0
- mindroot/coreplugins/chat/commands.py +4 -0
- mindroot/coreplugins/chat/services.py +116 -10
- mindroot/coreplugins/chat/static/css/dark.css +90 -1
- mindroot/coreplugins/chat/static/css/default.css +90 -1
- mindroot/coreplugins/chat/static/css/light.css +724 -0
- mindroot/coreplugins/chat/static/js/chat.js +114 -86
- mindroot/coreplugins/chat/static/js/throttle.js +4 -2
- mindroot/coreplugins/chat/templates/chat.jinja2 +8 -0
- mindroot/lib/chatcontext.py +1 -0
- mindroot/lib/chatlog.py +40 -0
- mindroot/lib/logging/logfiles.py +1 -0
- {mindroot-10.5.0.dist-info → mindroot-10.14.0.dist-info}/METADATA +1 -1
- {mindroot-10.5.0.dist-info → mindroot-10.14.0.dist-info}/RECORD +24 -19
- {mindroot-10.5.0.dist-info → mindroot-10.14.0.dist-info}/WHEEL +0 -0
- {mindroot-10.5.0.dist-info → mindroot-10.14.0.dist-info}/entry_points.txt +0 -0
- {mindroot-10.5.0.dist-info → mindroot-10.14.0.dist-info}/licenses/LICENSE +0 -0
- {mindroot-10.5.0.dist-info → mindroot-10.14.0.dist-info}/top_level.txt +0 -0
|
@@ -8,6 +8,7 @@ from typing import List
|
|
|
8
8
|
from lib.utils.dataurl import dataurl_to_pil
|
|
9
9
|
from .models import MessageParts
|
|
10
10
|
from coreplugins.agent import agent
|
|
11
|
+
from coreplugins.agent.speech_to_speech import SpeechToSpeechAgent
|
|
11
12
|
from lib.utils.debug import debug_box
|
|
12
13
|
import os
|
|
13
14
|
import sys
|
|
@@ -24,6 +25,9 @@ import nanoid
|
|
|
24
25
|
sse_clients = {}
|
|
25
26
|
from lib.chatcontext import get_context
|
|
26
27
|
|
|
28
|
+
# Track active processing tasks per session
|
|
29
|
+
active_tasks = {}
|
|
30
|
+
|
|
27
31
|
@service()
|
|
28
32
|
async def prompt(model: str, instructions: str, temperature=0, max_tokens=400, json=False, context=None):
|
|
29
33
|
messages = [
|
|
@@ -68,7 +72,7 @@ def results_output(results):
|
|
|
68
72
|
text = ""
|
|
69
73
|
for result in results:
|
|
70
74
|
if 'output' in result['args']:
|
|
71
|
-
return result['args']['output']
|
|
75
|
+
return str(result['args']['output'])
|
|
72
76
|
|
|
73
77
|
def results_text_output(results):
|
|
74
78
|
text = ""
|
|
@@ -135,6 +139,9 @@ async def run_task(instructions: str, agent_name:str = None, user:str = None, lo
|
|
|
135
139
|
|
|
136
140
|
while retried < retries:
|
|
137
141
|
[results, full_results] = await send_message_to_agent(context.log_id, instructions, context=context)
|
|
142
|
+
print('#####################################################33')
|
|
143
|
+
print("Full results: ", full_results)
|
|
144
|
+
print("Results: ", results)
|
|
138
145
|
text = results_output(full_results)
|
|
139
146
|
if text == "":
|
|
140
147
|
retried += 1
|
|
@@ -165,6 +172,11 @@ async def init_chat_session(user:str, agent_name: str, log_id: str, context=None
|
|
|
165
172
|
print("context.agent_name: ", context.agent_name)
|
|
166
173
|
await context.save_context()
|
|
167
174
|
print("initiated_chat_session: ", log_id, agent_name, context.agent_name, context.agent)
|
|
175
|
+
|
|
176
|
+
if 'live' in context.agent['stream_chat'] or 'realtime' in context.agent['stream_chat']:
|
|
177
|
+
agent = SpeechToSpeechAgent(agent_name, context=context)
|
|
178
|
+
await agent.connect()
|
|
179
|
+
|
|
168
180
|
return log_id
|
|
169
181
|
|
|
170
182
|
@service()
|
|
@@ -217,13 +229,61 @@ def process_result(result, formatted_results):
|
|
|
217
229
|
|
|
218
230
|
return formatted_results
|
|
219
231
|
|
|
232
|
+
# Deprecated - use active_tasks instead
|
|
233
|
+
in_progress = {}
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
@service()
|
|
237
|
+
async def cancel_and_wait(session_id: str, user:str, context=None):
|
|
238
|
+
global in_progress, active_tasks
|
|
239
|
+
existing_task = active_tasks.get(session_id)
|
|
240
|
+
|
|
241
|
+
if not in_progress.get(session_id, False):
|
|
242
|
+
print(f"SEND_MESSAGE No active processing for session {session_id} to cancel.")
|
|
243
|
+
return
|
|
244
|
+
try:
|
|
245
|
+
print(f"SEND_MESSAGE Cancelling active task for session {session_id}...")
|
|
246
|
+
existing_context = await get_context(session_id, user)
|
|
247
|
+
existing_context.data['cancel_current_turn'] = True
|
|
248
|
+
existing_context.data['finished_conversation'] = True
|
|
249
|
+
existing_context.save_context()
|
|
250
|
+
# Cancel any active command task
|
|
251
|
+
if 'active_command_task' in existing_context.data:
|
|
252
|
+
cmd_task = existing_context.data['active_command_task']
|
|
253
|
+
if cmd_task and not cmd_task.done():
|
|
254
|
+
cmd_task.cancel()
|
|
255
|
+
|
|
256
|
+
await existing_context.save_context()
|
|
257
|
+
except Exception as e:
|
|
258
|
+
print(f"SEND_MESSAGE Error setting cancellation flags: {e}")
|
|
259
|
+
|
|
260
|
+
# Cancel the main task
|
|
261
|
+
existing_task.cancel()
|
|
262
|
+
|
|
263
|
+
# Wait for it to actually finish (with timeout)
|
|
264
|
+
try:
|
|
265
|
+
await asyncio.wait_for(existing_task, timeout=2.0)
|
|
266
|
+
except (asyncio.CancelledError, asyncio.TimeoutError):
|
|
267
|
+
pass # Expected
|
|
268
|
+
|
|
269
|
+
start_wait = time.time()
|
|
270
|
+
while in_progress.get(session_id, False) and (time.time() - start_wait) < 5.0:
|
|
271
|
+
print(f"SEND_MESSAGE Waiting for cancellation of session {session_id} to complete...")
|
|
272
|
+
await asyncio.sleep(0.025)
|
|
273
|
+
|
|
274
|
+
print(f"SEND_MESSAGE Cancellation complete for session {session_id}")
|
|
275
|
+
|
|
220
276
|
@service()
|
|
221
277
|
async def send_message_to_agent(session_id: str, message: str | List[MessageParts], max_iterations=35, context=None, user=None):
|
|
222
|
-
|
|
223
|
-
|
|
278
|
+
global in_progress, active_tasks
|
|
279
|
+
|
|
280
|
+
# Check if there's an active task for this session
|
|
281
|
+
existing_task = active_tasks.get(session_id)
|
|
282
|
+
|
|
224
283
|
if not user:
|
|
225
284
|
# check context
|
|
226
285
|
if not context.username:
|
|
286
|
+
print("SEND_MESSAGE No user provided and context has no username")
|
|
227
287
|
raise Exception("User required")
|
|
228
288
|
else:
|
|
229
289
|
user = {"user": context.username }
|
|
@@ -231,20 +291,46 @@ async def send_message_to_agent(session_id: str, message: str | List[MessagePart
|
|
|
231
291
|
if hasattr(user, "dict"):
|
|
232
292
|
user = user.dict()
|
|
233
293
|
|
|
294
|
+
context.data['cancel_current_turn'] = False
|
|
295
|
+
context.data['finished_conversation'] = False
|
|
296
|
+
await context.save_context()
|
|
297
|
+
|
|
298
|
+
in_progress[session_id] = True
|
|
299
|
+
await asyncio.sleep(0.05)
|
|
300
|
+
|
|
301
|
+
print('b')
|
|
302
|
+
if os.environ.get("MR_MAX_ITERATIONS") is not None:
|
|
303
|
+
max_iterations = int(os.environ.get("MR_MAX_ITERATIONS"))
|
|
234
304
|
try:
|
|
235
305
|
if type(message) is list:
|
|
236
306
|
message = [m.dict() for m in message]
|
|
237
307
|
|
|
238
308
|
if session_id is None or session_id == "" or message is None or message == "":
|
|
239
|
-
print("Invalid session_id or message")
|
|
309
|
+
print("SEND_MESSAGE Invalid session_id or message")
|
|
240
310
|
return []
|
|
241
311
|
|
|
312
|
+
# Create the main processing task and store it
|
|
313
|
+
processing_task = asyncio.current_task()
|
|
314
|
+
active_tasks[session_id] = processing_task
|
|
315
|
+
|
|
316
|
+
print("SEND_MESSAGE proceeding with message processing")
|
|
242
317
|
print("send_message_to_agent: ", session_id, message, max_iterations)
|
|
243
318
|
if context is None:
|
|
244
319
|
context = ChatContext(command_manager, service_manager, user)
|
|
245
320
|
await context.load_context(session_id)
|
|
246
321
|
|
|
247
|
-
|
|
322
|
+
if 'live' in context.agent['stream_chat'] or 'realtime' in context.agent['stream_chat']:
|
|
323
|
+
agent_ = SpeechToSpeechAgent(context.agent_name, context=context)
|
|
324
|
+
print('Using SpeechToSpeechAgent for live/realtime chat')
|
|
325
|
+
print()
|
|
326
|
+
print()
|
|
327
|
+
print()
|
|
328
|
+
print('message: ', message)
|
|
329
|
+
results = await agent_.send_message(message)
|
|
330
|
+
return results, []
|
|
331
|
+
else:
|
|
332
|
+
agent_ = agent.Agent(agent=context.agent)
|
|
333
|
+
|
|
248
334
|
if user is not None and hasattr(user, "keys"):
|
|
249
335
|
for key in user.keys():
|
|
250
336
|
context.data[key] = user[key]
|
|
@@ -373,9 +459,12 @@ async def send_message_to_agent(session_id: str, message: str | List[MessagePart
|
|
|
373
459
|
context.chat_log.add_message({"role": "user", "content": formatted_results})
|
|
374
460
|
results.append(out_results)
|
|
375
461
|
else:
|
|
376
|
-
print("Processing iteration: ", iterations, "no message added")
|
|
462
|
+
print("SEND_MESSAGE Processing iteration: ", iterations, "no message added")
|
|
377
463
|
if context.data.get('finished_conversation') is True:
|
|
378
464
|
termcolor.cprint("Finished conversation, exiting send_message_to_agent", "red")
|
|
465
|
+
if context.data.get('task_result') is not None:
|
|
466
|
+
task_result = context.data.get('task_result')
|
|
467
|
+
full_results.append({ "cmd": "task_result", "args": { "result": task_result } })
|
|
379
468
|
continue_processing = False
|
|
380
469
|
except Exception as e:
|
|
381
470
|
continue_processing = False
|
|
@@ -399,10 +488,23 @@ async def send_message_to_agent(session_id: str, message: str | List[MessagePart
|
|
|
399
488
|
print("Exiting send_message_to_agent: ", session_id, message, max_iterations)
|
|
400
489
|
|
|
401
490
|
await context.finished_chat()
|
|
491
|
+
in_progress.pop(session_id, None)
|
|
492
|
+
active_tasks.pop(session_id, None)
|
|
493
|
+
if len(results) == 0:
|
|
494
|
+
if context.data.get('task_result') is not None:
|
|
495
|
+
task_result = context.data.get('task_result')
|
|
496
|
+
results.append(task_result)
|
|
497
|
+
print("SEND_MESSAGE Done")
|
|
402
498
|
return [results, full_results]
|
|
499
|
+
except asyncio.CancelledError:
|
|
500
|
+
print(f"Task cancelled for session {session_id}")
|
|
501
|
+
in_progress.pop(session_id, None)
|
|
502
|
+
active_tasks.pop(session_id, None)
|
|
503
|
+
raise # Re-raise to properly handle cancellation
|
|
403
504
|
except Exception as e:
|
|
404
505
|
print("Error in send_message_to_agent: ", e)
|
|
405
506
|
print(traceback.format_exc())
|
|
507
|
+
in_progress.pop(session_id, None)
|
|
406
508
|
return []
|
|
407
509
|
|
|
408
510
|
@pipe(name='process_results', priority=5)
|
|
@@ -489,8 +591,7 @@ async def command_result(command: str, result, context=None):
|
|
|
489
591
|
@service()
|
|
490
592
|
async def backend_user_message(message: str, context=None):
|
|
491
593
|
"""
|
|
492
|
-
|
|
493
|
-
This allows backend processes to inject messages into the chat without user interaction.
|
|
594
|
+
Signal the frontend to display a user message.
|
|
494
595
|
"""
|
|
495
596
|
agent_ = context.agent
|
|
496
597
|
persona = 'user'
|
|
@@ -542,10 +643,15 @@ async def cancel_active_response(log_id: str, context=None):
|
|
|
542
643
|
# DEBUG TRACE
|
|
543
644
|
print("\033[91;107m[DEBUG TRACE 6/6] Active command task found and cancelled.\033[0m")
|
|
544
645
|
print(f"Cancelled active command task for session {log_id}")
|
|
646
|
+
print(f"Removing last assistant message from chat log for session {log_id}")
|
|
647
|
+
await context.chat_log.drop_last('assistant')
|
|
648
|
+
|
|
545
649
|
except Exception as e:
|
|
546
650
|
print(f"Error cancelling active command task: {e}")
|
|
547
|
-
|
|
651
|
+
|
|
652
|
+
|
|
548
653
|
await context.save_context()
|
|
549
654
|
|
|
550
655
|
print(f"Cancelled active response for session {log_id}")
|
|
551
|
-
return {"status": "cancelled", "log_id": log_id}
|
|
656
|
+
return {"status": "cancelled", "log_id": log_id}
|
|
657
|
+
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/* Import JetBrains Mono from Google Fonts */
|
|
2
|
+
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&display=swap');
|
|
3
|
+
|
|
4
|
+
/* Base styles */
|
|
5
|
+
|
|
1
6
|
html, body {
|
|
2
7
|
background-color: #101020;
|
|
3
8
|
color: #f0f0f0;
|
|
@@ -16,7 +21,7 @@ input, * {
|
|
|
16
21
|
background-color: transparent;
|
|
17
22
|
color: #f0f0f0;
|
|
18
23
|
margin: 2px 2px;
|
|
19
|
-
font-family: ui-sans-serif, -apple-system, system-ui, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, Helvetica, "Apple Color Emoji", Arial, "Segoe UI Emoji", "Segoe UI Symbol"
|
|
24
|
+
/*font-family: ui-sans-serif, -apple-system, system-ui, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, Helvetica, "Apple Color Emoji", Arial, "Segoe UI Emoji", "Segoe UI Symbol";*/
|
|
20
25
|
}
|
|
21
26
|
|
|
22
27
|
p {
|
|
@@ -1020,3 +1025,87 @@ tbody tr {
|
|
|
1020
1025
|
.left-side {
|
|
1021
1026
|
overflow-y: auto;
|
|
1022
1027
|
}
|
|
1028
|
+
|
|
1029
|
+
/* Enhanced Shell/Terminal output styling */
|
|
1030
|
+
pre.shellout {
|
|
1031
|
+
background: linear-gradient(to bottom, #2d2d2d 0%, #1e1e1e 30px, #1a1a1a 100%);
|
|
1032
|
+
border: 1px solid #404040;
|
|
1033
|
+
border-radius: 12px;
|
|
1034
|
+
padding: 0;
|
|
1035
|
+
margin: 15px 0;
|
|
1036
|
+
overflow-x: auto;
|
|
1037
|
+
max-height: 50vh;
|
|
1038
|
+
overflow-y: auto;
|
|
1039
|
+
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.4),
|
|
1040
|
+
0 0 0 1px rgba(255, 255, 255, 0.05) inset;
|
|
1041
|
+
position: relative;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
/* Mock terminal title bar */
|
|
1045
|
+
pre.shellout::before {
|
|
1046
|
+
content: '';
|
|
1047
|
+
display: block;
|
|
1048
|
+
height: 30px;
|
|
1049
|
+
background: linear-gradient(to bottom, #3a3a3a, #2d2d2d);
|
|
1050
|
+
border-bottom: 1px solid #1a1a1a;
|
|
1051
|
+
border-radius: 12px 12px 0 0;
|
|
1052
|
+
position: sticky;
|
|
1053
|
+
top: 0;
|
|
1054
|
+
z-index: 1;
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
/* Terminal window controls (dots) */
|
|
1058
|
+
pre.shellout::after {
|
|
1059
|
+
content: '';
|
|
1060
|
+
position: absolute;
|
|
1061
|
+
top: 11px;
|
|
1062
|
+
left: 12px;
|
|
1063
|
+
width: 12px;
|
|
1064
|
+
height: 12px;
|
|
1065
|
+
background: #ff5f56;
|
|
1066
|
+
border-radius: 50%;
|
|
1067
|
+
box-shadow:
|
|
1068
|
+
20px 0 0 #ffbd2e,
|
|
1069
|
+
40px 0 0 #27c93f,
|
|
1070
|
+
0 0 0 1px rgba(0, 0, 0, 0.2);
|
|
1071
|
+
z-index: 2;
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
/* Code element inside shellout pre */
|
|
1075
|
+
pre.shellout code {
|
|
1076
|
+
background-color: transparent;
|
|
1077
|
+
color: #e8e8e8;
|
|
1078
|
+
font-family: 'JetBrains Mono', 'Fira Code', 'Consolas', 'Monaco', monospace;
|
|
1079
|
+
font-size: 14px;
|
|
1080
|
+
line-height: 1.6;
|
|
1081
|
+
padding: 15px 20px;
|
|
1082
|
+
padding-top: 10px;
|
|
1083
|
+
margin: 0;
|
|
1084
|
+
border: none;
|
|
1085
|
+
white-space: pre-wrap;
|
|
1086
|
+
display: block;
|
|
1087
|
+
font-weight: 400;
|
|
1088
|
+
letter-spacing: 0.02em;
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
/* Custom scrollbar for terminal */
|
|
1092
|
+
pre.shellout::-webkit-scrollbar {
|
|
1093
|
+
width: 10px;
|
|
1094
|
+
height: 10px;
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
pre.shellout::-webkit-scrollbar-track {
|
|
1098
|
+
background: #1a1a1a;
|
|
1099
|
+
border-radius: 0 0 12px 0;
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
pre.shellout::-webkit-scrollbar-thumb {
|
|
1103
|
+
background: #404040;
|
|
1104
|
+
border-radius: 5px;
|
|
1105
|
+
border: 2px solid #1a1a1a;
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
pre.shellout::-webkit-scrollbar-thumb:hover {
|
|
1109
|
+
background: #4a4a4a;
|
|
1110
|
+
}
|
|
1111
|
+
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/* Import JetBrains Mono from Google Fonts */
|
|
2
|
+
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&display=swap');
|
|
3
|
+
|
|
4
|
+
/* Base styles */
|
|
5
|
+
|
|
1
6
|
html, body {
|
|
2
7
|
background-color: #101020;
|
|
3
8
|
color: #f0f0f0;
|
|
@@ -16,7 +21,7 @@ input, * {
|
|
|
16
21
|
background-color: transparent;
|
|
17
22
|
color: #f0f0f0;
|
|
18
23
|
margin: 2px 2px;
|
|
19
|
-
font-family: ui-sans-serif, -apple-system, system-ui, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, Helvetica, "Apple Color Emoji", Arial, "Segoe UI Emoji", "Segoe UI Symbol"
|
|
24
|
+
/*font-family: ui-sans-serif, -apple-system, system-ui, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, Helvetica, "Apple Color Emoji", Arial, "Segoe UI Emoji", "Segoe UI Symbol";*/
|
|
20
25
|
}
|
|
21
26
|
|
|
22
27
|
p {
|
|
@@ -1020,3 +1025,87 @@ tbody tr {
|
|
|
1020
1025
|
.left-side {
|
|
1021
1026
|
overflow-y: auto;
|
|
1022
1027
|
}
|
|
1028
|
+
|
|
1029
|
+
/* Enhanced Shell/Terminal output styling */
|
|
1030
|
+
pre.shellout {
|
|
1031
|
+
background: linear-gradient(to bottom, #2d2d2d 0%, #1e1e1e 30px, #1a1a1a 100%);
|
|
1032
|
+
border: 1px solid #404040;
|
|
1033
|
+
border-radius: 12px;
|
|
1034
|
+
padding: 0;
|
|
1035
|
+
margin: 15px 0;
|
|
1036
|
+
overflow-x: auto;
|
|
1037
|
+
max-height: 50vh;
|
|
1038
|
+
overflow-y: auto;
|
|
1039
|
+
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.4),
|
|
1040
|
+
0 0 0 1px rgba(255, 255, 255, 0.05) inset;
|
|
1041
|
+
position: relative;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
/* Mock terminal title bar */
|
|
1045
|
+
pre.shellout::before {
|
|
1046
|
+
content: '';
|
|
1047
|
+
display: block;
|
|
1048
|
+
height: 30px;
|
|
1049
|
+
background: linear-gradient(to bottom, #3a3a3a, #2d2d2d);
|
|
1050
|
+
border-bottom: 1px solid #1a1a1a;
|
|
1051
|
+
border-radius: 12px 12px 0 0;
|
|
1052
|
+
position: sticky;
|
|
1053
|
+
top: 0;
|
|
1054
|
+
z-index: 1;
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
/* Terminal window controls (dots) */
|
|
1058
|
+
pre.shellout::after {
|
|
1059
|
+
content: '';
|
|
1060
|
+
position: absolute;
|
|
1061
|
+
top: 11px;
|
|
1062
|
+
left: 12px;
|
|
1063
|
+
width: 12px;
|
|
1064
|
+
height: 12px;
|
|
1065
|
+
background: #ff5f56;
|
|
1066
|
+
border-radius: 50%;
|
|
1067
|
+
box-shadow:
|
|
1068
|
+
20px 0 0 #ffbd2e,
|
|
1069
|
+
40px 0 0 #27c93f,
|
|
1070
|
+
0 0 0 1px rgba(0, 0, 0, 0.2);
|
|
1071
|
+
z-index: 2;
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
/* Code element inside shellout pre */
|
|
1075
|
+
pre.shellout code {
|
|
1076
|
+
background-color: transparent;
|
|
1077
|
+
color: #e8e8e8;
|
|
1078
|
+
font-family: 'JetBrains Mono', 'Fira Code', 'Consolas', 'Monaco', monospace;
|
|
1079
|
+
font-size: 14px;
|
|
1080
|
+
line-height: 1.6;
|
|
1081
|
+
padding: 15px 20px;
|
|
1082
|
+
padding-top: 10px;
|
|
1083
|
+
margin: 0;
|
|
1084
|
+
border: none;
|
|
1085
|
+
white-space: pre-wrap;
|
|
1086
|
+
display: block;
|
|
1087
|
+
font-weight: 400;
|
|
1088
|
+
letter-spacing: 0.02em;
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
/* Custom scrollbar for terminal */
|
|
1092
|
+
pre.shellout::-webkit-scrollbar {
|
|
1093
|
+
width: 10px;
|
|
1094
|
+
height: 10px;
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
pre.shellout::-webkit-scrollbar-track {
|
|
1098
|
+
background: #1a1a1a;
|
|
1099
|
+
border-radius: 0 0 12px 0;
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
pre.shellout::-webkit-scrollbar-thumb {
|
|
1103
|
+
background: #404040;
|
|
1104
|
+
border-radius: 5px;
|
|
1105
|
+
border: 2px solid #1a1a1a;
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
pre.shellout::-webkit-scrollbar-thumb:hover {
|
|
1109
|
+
background: #4a4a4a;
|
|
1110
|
+
}
|
|
1111
|
+
|