v2.7.6 (#600)
Co-authored-by: Clément Sirieix <clement.sirieix@mistral.ai> Co-authored-by: Kim-Adeline Miguel <51720070+kimadeline@users.noreply.github.com> Co-authored-by: Mathias Gesbert <mathias.gesbert@mistral.ai> Co-authored-by: Maxime Dolores <maxime.dolores@ext.mistral.ai> Co-authored-by: Michel Thomazo <51709227+michelTho@users.noreply.github.com> Co-authored-by: Paul Cacheux <paul.cacheux@mistral.ai> Co-authored-by: Quentin <quentin.torroba@mistral.ai> Co-authored-by: Simon <80467011+sorgfresser@users.noreply.github.com> Co-authored-by: angelapopopo <angele.lenglemetz@mistral.ai> Co-authored-by: Mistral Vibe <vibe@mistral.ai>
279
tests/acp/test_commands.py
Normal file
|
|
@ -0,0 +1,279 @@
|
|||
"""Tests for ACP slash command handlers on VibeAcpAgentLoop."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from pathlib import Path
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from acp.schema import AgentMessageChunk, AvailableCommandsUpdate, TextContentBlock
|
||||
import pytest
|
||||
|
||||
from tests.acp.conftest import _create_acp_agent
|
||||
from tests.skills.conftest import create_skill
|
||||
from tests.stubs.fake_backend import FakeBackend
|
||||
from tests.stubs.fake_client import FakeClient
|
||||
from vibe.acp.acp_agent_loop import VibeAcpAgentLoop
|
||||
from vibe.core.agent_loop import AgentLoop
|
||||
from vibe.core.config import SessionLoggingConfig
|
||||
|
||||
|
||||
def _get_client(agent: VibeAcpAgentLoop) -> FakeClient:
|
||||
assert isinstance(agent.client, FakeClient)
|
||||
return agent.client
|
||||
|
||||
|
||||
def _get_message_texts(agent: VibeAcpAgentLoop) -> list[str]:
|
||||
"""Extract text content from all AgentMessageChunk session updates."""
|
||||
return [
|
||||
u.update.content.text
|
||||
for u in _get_client(agent)._session_updates
|
||||
if isinstance(u.update, AgentMessageChunk)
|
||||
]
|
||||
|
||||
|
||||
async def _new_session_and_clear(agent: VibeAcpAgentLoop) -> str:
|
||||
"""Create a new session, drain the startup updates, return session_id."""
|
||||
resp = await agent.new_session(cwd=str(Path.cwd()), mcp_servers=[])
|
||||
await asyncio.sleep(0) # let background tasks (available_commands) complete
|
||||
_get_client(agent)._session_updates.clear()
|
||||
return resp.session_id
|
||||
|
||||
|
||||
async def _prompt(agent: VibeAcpAgentLoop, session_id: str, text: str):
|
||||
return await agent.prompt(
|
||||
prompt=[TextContentBlock(type="text", text=text)], session_id=session_id
|
||||
)
|
||||
|
||||
|
||||
def _make_patched_agent_loop(
|
||||
backend: FakeBackend,
|
||||
*,
|
||||
skill_paths: list[Path] | None = None,
|
||||
session_logging: SessionLoggingConfig | None = None,
|
||||
) -> type[AgentLoop]:
|
||||
"""Create a PatchedAgentLoop class that injects config overrides."""
|
||||
config_updates: dict = {}
|
||||
if skill_paths is not None:
|
||||
config_updates["skill_paths"] = skill_paths
|
||||
if session_logging is not None:
|
||||
config_updates["session_logging"] = session_logging
|
||||
|
||||
class PatchedAgentLoop(AgentLoop):
|
||||
def __init__(self, *args, **kwargs) -> None:
|
||||
if config_updates and "config" in kwargs and kwargs["config"] is not None:
|
||||
kwargs["config"] = kwargs["config"].model_copy(update=config_updates)
|
||||
super().__init__(*args, **{**kwargs, "backend": backend})
|
||||
|
||||
return PatchedAgentLoop
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def acp_agent_loop(backend: FakeBackend) -> VibeAcpAgentLoop:
|
||||
patched = _make_patched_agent_loop(backend)
|
||||
patch("vibe.acp.acp_agent_loop.AgentLoop", side_effect=patched).start()
|
||||
return _create_acp_agent()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def skills_dir(tmp_path: Path) -> Path:
|
||||
d = tmp_path / "skills"
|
||||
d.mkdir()
|
||||
return d
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def acp_agent_loop_with_skills(
|
||||
backend: FakeBackend, skills_dir: Path
|
||||
) -> VibeAcpAgentLoop:
|
||||
# Skills must exist in skills_dir BEFORE new_session() is called.
|
||||
patched = _make_patched_agent_loop(backend, skill_paths=[skills_dir])
|
||||
patch("vibe.acp.acp_agent_loop.AgentLoop", side_effect=patched).start()
|
||||
return _create_acp_agent()
|
||||
|
||||
|
||||
class TestHandleHelp:
|
||||
@pytest.mark.asyncio
|
||||
async def test_lists_all_registered_commands(
|
||||
self, acp_agent_loop: VibeAcpAgentLoop
|
||||
) -> None:
|
||||
session_id = await _new_session_and_clear(acp_agent_loop)
|
||||
response = await _prompt(acp_agent_loop, session_id, "/help")
|
||||
|
||||
assert response.stop_reason == "end_turn"
|
||||
texts = _get_message_texts(acp_agent_loop)
|
||||
assert len(texts) == 1
|
||||
content = texts[0]
|
||||
|
||||
main_commands = ["help", "compact", "reload", "proxy-setup"]
|
||||
for cmd in main_commands:
|
||||
assert f"/{cmd}" in content
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_includes_user_invocable_skills(
|
||||
self, acp_agent_loop_with_skills: VibeAcpAgentLoop, skills_dir: Path
|
||||
) -> None:
|
||||
# Create skills before new_session so SkillManager discovers them
|
||||
create_skill(skills_dir, "my-skill", "Does something useful")
|
||||
create_skill(skills_dir, "hidden-skill", "Secret", user_invocable=False)
|
||||
|
||||
session_id = await _new_session_and_clear(acp_agent_loop_with_skills)
|
||||
await _prompt(acp_agent_loop_with_skills, session_id, "/help")
|
||||
|
||||
content = _get_message_texts(acp_agent_loop_with_skills)[0]
|
||||
assert "/my-skill" in content
|
||||
assert "Does something useful" in content
|
||||
assert "hidden-skill" not in content
|
||||
|
||||
|
||||
class TestHandleCompact:
|
||||
@pytest.mark.asyncio
|
||||
async def test_empty_history_does_not_compact(
|
||||
self, acp_agent_loop: VibeAcpAgentLoop
|
||||
) -> None:
|
||||
session_id = await _new_session_and_clear(acp_agent_loop)
|
||||
session = acp_agent_loop.sessions[session_id]
|
||||
|
||||
with patch.object(
|
||||
session.agent_loop, "compact", new_callable=AsyncMock
|
||||
) as mock_compact:
|
||||
await _prompt(acp_agent_loop, session_id, "/compact")
|
||||
mock_compact.assert_not_called()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_compact_calls_agent_loop_compact(
|
||||
self, acp_agent_loop: VibeAcpAgentLoop
|
||||
) -> None:
|
||||
session_id = await _new_session_and_clear(acp_agent_loop)
|
||||
|
||||
# Have a conversation first to create history
|
||||
await _prompt(acp_agent_loop, session_id, "Hello, tell me something")
|
||||
_get_client(acp_agent_loop)._session_updates.clear()
|
||||
|
||||
session = acp_agent_loop.sessions[session_id]
|
||||
with patch.object(
|
||||
session.agent_loop, "compact", new_callable=AsyncMock
|
||||
) as mock_compact:
|
||||
response = await _prompt(acp_agent_loop, session_id, "/compact")
|
||||
assert response.stop_reason == "end_turn"
|
||||
mock_compact.assert_called_once()
|
||||
|
||||
|
||||
class TestHandleReload:
|
||||
@pytest.mark.asyncio
|
||||
async def test_reload_calls_reload_with_initial_messages(
|
||||
self, acp_agent_loop: VibeAcpAgentLoop
|
||||
) -> None:
|
||||
session_id = await _new_session_and_clear(acp_agent_loop)
|
||||
session = acp_agent_loop.sessions[session_id]
|
||||
|
||||
with patch.object(
|
||||
session.agent_loop, "reload_with_initial_messages", new_callable=AsyncMock
|
||||
) as mock_reload:
|
||||
response = await _prompt(acp_agent_loop, session_id, "/reload")
|
||||
assert response.stop_reason == "end_turn"
|
||||
mock_reload.assert_called_once()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_reload_notifies_commands_changed(
|
||||
self, acp_agent_loop: VibeAcpAgentLoop
|
||||
) -> None:
|
||||
session_id = await _new_session_and_clear(acp_agent_loop)
|
||||
session = acp_agent_loop.sessions[session_id]
|
||||
|
||||
with patch.object(
|
||||
session.command_registry, "notify_changed", new_callable=AsyncMock
|
||||
) as mock_notify:
|
||||
await _prompt(acp_agent_loop, session_id, "/reload")
|
||||
mock_notify.assert_called_once()
|
||||
|
||||
|
||||
class TestCommandFallthrough:
|
||||
@pytest.mark.asyncio
|
||||
async def test_unknown_slash_command_reaches_agent(
|
||||
self, acp_agent_loop: VibeAcpAgentLoop
|
||||
) -> None:
|
||||
session_id = await _new_session_and_clear(acp_agent_loop)
|
||||
response = await _prompt(acp_agent_loop, session_id, "/nonexistent")
|
||||
|
||||
# The agent loop should have processed it (FakeBackend returns "Hi")
|
||||
assert response.stop_reason == "end_turn"
|
||||
texts = _get_message_texts(acp_agent_loop)
|
||||
# Should contain the LLM response, not a command reply
|
||||
assert any("Hi" in t for t in texts)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_regular_message_reaches_agent(
|
||||
self, acp_agent_loop: VibeAcpAgentLoop
|
||||
) -> None:
|
||||
session_id = await _new_session_and_clear(acp_agent_loop)
|
||||
response = await _prompt(acp_agent_loop, session_id, "Hello world")
|
||||
|
||||
assert response.stop_reason == "end_turn"
|
||||
texts = _get_message_texts(acp_agent_loop)
|
||||
assert any("Hi" in t for t in texts)
|
||||
|
||||
|
||||
class TestAvailableCommandsWithSkills:
|
||||
@pytest.mark.asyncio
|
||||
async def test_skills_appear_in_available_commands(
|
||||
self, acp_agent_loop_with_skills: VibeAcpAgentLoop, skills_dir: Path
|
||||
) -> None:
|
||||
create_skill(skills_dir, "my-skill", "A useful skill")
|
||||
|
||||
await acp_agent_loop_with_skills.new_session(
|
||||
cwd=str(Path.cwd()), mcp_servers=[]
|
||||
)
|
||||
await asyncio.sleep(0)
|
||||
|
||||
updates = _get_client(acp_agent_loop_with_skills)._session_updates
|
||||
available = [
|
||||
u for u in updates if isinstance(u.update, AvailableCommandsUpdate)
|
||||
]
|
||||
assert len(available) == 1
|
||||
|
||||
cmd_names = [c.name for c in available[0].update.available_commands]
|
||||
assert "my-skill" in cmd_names
|
||||
# Built-in commands should also be present
|
||||
assert "help" in cmd_names
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_non_invocable_skills_excluded_from_available_commands(
|
||||
self, acp_agent_loop_with_skills: VibeAcpAgentLoop, skills_dir: Path
|
||||
) -> None:
|
||||
create_skill(skills_dir, "visible-skill", "Visible")
|
||||
create_skill(skills_dir, "hidden-skill", "Hidden", user_invocable=False)
|
||||
|
||||
await acp_agent_loop_with_skills.new_session(
|
||||
cwd=str(Path.cwd()), mcp_servers=[]
|
||||
)
|
||||
await asyncio.sleep(0)
|
||||
|
||||
updates = _get_client(acp_agent_loop_with_skills)._session_updates
|
||||
available = [
|
||||
u for u in updates if isinstance(u.update, AvailableCommandsUpdate)
|
||||
]
|
||||
cmd_names = [c.name for c in available[0].update.available_commands]
|
||||
|
||||
assert "visible-skill" in cmd_names
|
||||
assert "hidden-skill" not in cmd_names
|
||||
|
||||
|
||||
class TestCommandCaseInsensitivity:
|
||||
@pytest.mark.asyncio
|
||||
async def test_uppercase_command(self, acp_agent_loop: VibeAcpAgentLoop) -> None:
|
||||
session_id = await _new_session_and_clear(acp_agent_loop)
|
||||
response = await _prompt(acp_agent_loop, session_id, "/HELP")
|
||||
|
||||
assert response.stop_reason == "end_turn"
|
||||
content = _get_message_texts(acp_agent_loop)[0]
|
||||
assert "Available Commands" in content
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mixed_case_command(self, acp_agent_loop: VibeAcpAgentLoop) -> None:
|
||||
session_id = await _new_session_and_clear(acp_agent_loop)
|
||||
response = await _prompt(acp_agent_loop, session_id, "/Help")
|
||||
|
||||
assert response.stop_reason == "end_turn"
|
||||
content = _get_message_texts(acp_agent_loop)[0]
|
||||
assert "Available Commands" in content
|
||||
|
|
@ -28,7 +28,7 @@ class TestACPInitialize:
|
|||
session_capabilities=SessionCapabilities(list=SessionListCapabilities()),
|
||||
)
|
||||
assert response.agent_info == Implementation(
|
||||
name="@mistralai/mistral-vibe", title="Mistral Vibe", version="2.7.5"
|
||||
name="@mistralai/mistral-vibe", title="Mistral Vibe", version="2.7.6"
|
||||
)
|
||||
|
||||
assert response.auth_methods == []
|
||||
|
|
@ -52,7 +52,7 @@ class TestACPInitialize:
|
|||
session_capabilities=SessionCapabilities(list=SessionListCapabilities()),
|
||||
)
|
||||
assert response.agent_info == Implementation(
|
||||
name="@mistralai/mistral-vibe", title="Mistral Vibe", version="2.7.5"
|
||||
name="@mistralai/mistral-vibe", title="Mistral Vibe", version="2.7.6"
|
||||
)
|
||||
|
||||
assert response.auth_methods is not None
|
||||
|
|
|
|||
|
|
@ -142,7 +142,9 @@ class TestMCPAppInit:
|
|||
app = MCPApp(mcp_servers=servers, tool_manager=mgr)
|
||||
app._viewing_server = "srv"
|
||||
render_calls: list[str | None] = []
|
||||
app._refresh_view = lambda server_name: render_calls.append(server_name)
|
||||
app._refresh_view = lambda server_name, *, kind=None: render_calls.append(
|
||||
server_name
|
||||
)
|
||||
app.action_back()
|
||||
assert render_calls == [None]
|
||||
|
||||
|
|
@ -151,6 +153,8 @@ class TestMCPAppInit:
|
|||
app = MCPApp(mcp_servers=[], tool_manager=mgr)
|
||||
app._viewing_server = None
|
||||
render_calls: list[str | None] = []
|
||||
app._refresh_view = lambda server_name: render_calls.append(server_name)
|
||||
app._refresh_view = lambda server_name, *, kind=None: render_calls.append(
|
||||
server_name
|
||||
)
|
||||
app.action_back()
|
||||
assert render_calls == []
|
||||
|
|
|
|||
|
|
@ -278,6 +278,65 @@ class TestQuestionAppActions:
|
|||
assert app._get_other_text(0) == "Text for Q1"
|
||||
assert app._get_other_text(1) == ""
|
||||
|
||||
def test_switch_question_restores_cursor_to_answered_option(
|
||||
self, multi_question_args
|
||||
):
|
||||
from vibe.cli.textual_ui.widgets.question_app import QuestionApp
|
||||
|
||||
app = QuestionApp(multi_question_args)
|
||||
# Answer question 0 with MongoDB (index 1)
|
||||
app.answers[0] = ("MongoDB", False)
|
||||
|
||||
# Switch away then back
|
||||
app._switch_question(1)
|
||||
app._switch_question(0)
|
||||
|
||||
assert app.selected_option == 1
|
||||
|
||||
def test_switch_question_restores_cursor_to_other(self, multi_question_args):
|
||||
from vibe.cli.textual_ui.widgets.question_app import QuestionApp
|
||||
|
||||
app = QuestionApp(multi_question_args)
|
||||
# Answer question 0 with Other
|
||||
app.answers[0] = ("Custom DB", True)
|
||||
|
||||
app._switch_question(1)
|
||||
app._switch_question(0)
|
||||
|
||||
assert app.selected_option == len(app.questions[0].options)
|
||||
assert app._is_other_selected
|
||||
|
||||
def test_switch_question_defaults_to_zero_if_unanswered(self, multi_question_args):
|
||||
from vibe.cli.textual_ui.widgets.question_app import QuestionApp
|
||||
|
||||
app = QuestionApp(multi_question_args)
|
||||
|
||||
app._switch_question(1)
|
||||
assert app.selected_option == 0
|
||||
|
||||
def test_switch_question_restores_cursor_multi_select(self):
|
||||
from vibe.cli.textual_ui.widgets.question_app import QuestionApp
|
||||
|
||||
args = AskUserQuestionArgs(
|
||||
questions=[
|
||||
Question(
|
||||
question="Q1?", options=[Choice(label="A"), Choice(label="B")]
|
||||
),
|
||||
Question(
|
||||
question="Q2?",
|
||||
options=[Choice(label="X"), Choice(label="Y"), Choice(label="Z")],
|
||||
multi_select=True,
|
||||
),
|
||||
]
|
||||
)
|
||||
app = QuestionApp(args)
|
||||
# Select Y (1) and Z (2) for question 1
|
||||
app.multi_selections[1] = {1, 2}
|
||||
|
||||
app._switch_question(1)
|
||||
|
||||
assert app.selected_option == 1 # min of {1, 2}
|
||||
|
||||
|
||||
class TestMultiSelectOtherBehavior:
|
||||
def test_multi_select_other_does_not_advance_on_save(self, multi_select_args):
|
||||
|
|
@ -489,6 +548,152 @@ class TestMultiSelectAutoSelect:
|
|||
assert app._other_option_idx in app.multi_selections[0]
|
||||
|
||||
|
||||
class TestNumberKeyShortcuts:
|
||||
def test_number_key_selects_predefined_option(self, single_question_args):
|
||||
from unittest.mock import patch
|
||||
|
||||
from textual import events
|
||||
|
||||
from vibe.cli.textual_ui.widgets.question_app import QuestionApp
|
||||
|
||||
app = QuestionApp(single_question_args)
|
||||
app.selected_option = 0
|
||||
|
||||
# Press "2" -> should select MongoDB (index 1) and save
|
||||
event = events.Key("2", "2")
|
||||
with patch.object(app, "_advance_or_submit"):
|
||||
app._handle_number_key(event)
|
||||
|
||||
assert app.selected_option == 1
|
||||
assert 0 in app.answers
|
||||
answer_text, is_other = app.answers[0]
|
||||
assert answer_text == "MongoDB"
|
||||
assert is_other is False
|
||||
|
||||
def test_number_key_first_option(self, single_question_args):
|
||||
from unittest.mock import patch
|
||||
|
||||
from textual import events
|
||||
|
||||
from vibe.cli.textual_ui.widgets.question_app import QuestionApp
|
||||
|
||||
app = QuestionApp(single_question_args)
|
||||
|
||||
event = events.Key("1", "1")
|
||||
with patch.object(app, "_advance_or_submit"):
|
||||
app._handle_number_key(event)
|
||||
|
||||
assert app.selected_option == 0
|
||||
assert 0 in app.answers
|
||||
answer_text, _ = app.answers[0]
|
||||
assert answer_text == "PostgreSQL"
|
||||
|
||||
def test_number_key_other_empty_focuses(self, single_question_args):
|
||||
from textual import events
|
||||
|
||||
from vibe.cli.textual_ui.widgets.question_app import QuestionApp
|
||||
|
||||
app = QuestionApp(single_question_args)
|
||||
# Other is option index 2 -> key "3"
|
||||
event = events.Key("3", "3")
|
||||
app._handle_number_key(event)
|
||||
|
||||
# Should navigate to Other but not validate (no text)
|
||||
assert app.selected_option == 2
|
||||
assert app._is_other_selected is True
|
||||
assert 0 not in app.answers
|
||||
|
||||
def test_number_key_other_with_text_focuses_without_validating(
|
||||
self, single_question_args
|
||||
):
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from textual import events
|
||||
|
||||
from vibe.cli.textual_ui.widgets.question_app import QuestionApp
|
||||
|
||||
app = QuestionApp(single_question_args)
|
||||
app.other_texts[0] = "SQLite"
|
||||
app.other_input = MagicMock()
|
||||
app.other_input.has_focus = False
|
||||
|
||||
event = events.Key("3", "3")
|
||||
app._handle_number_key(event)
|
||||
|
||||
# Should navigate to Other but not validate — just focus the input
|
||||
assert app.selected_option == 2
|
||||
assert app._is_other_selected is True
|
||||
assert 0 not in app.answers
|
||||
|
||||
def test_number_key_out_of_range_ignored(self, single_question_args):
|
||||
from textual import events
|
||||
|
||||
from vibe.cli.textual_ui.widgets.question_app import QuestionApp
|
||||
|
||||
app = QuestionApp(single_question_args)
|
||||
# 3 options total (2 + Other), so "4" is out of range
|
||||
event = events.Key("4", "4")
|
||||
app._handle_number_key(event)
|
||||
|
||||
assert app.selected_option == 0
|
||||
assert 0 not in app.answers
|
||||
|
||||
def test_number_key_zero_ignored(self, single_question_args):
|
||||
from textual import events
|
||||
|
||||
from vibe.cli.textual_ui.widgets.question_app import QuestionApp
|
||||
|
||||
app = QuestionApp(single_question_args)
|
||||
event = events.Key("0", "0")
|
||||
app._handle_number_key(event)
|
||||
|
||||
assert app.selected_option == 0
|
||||
assert 0 not in app.answers
|
||||
|
||||
def test_number_key_ignored_when_input_focused(self, single_question_args):
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from textual import events
|
||||
|
||||
from vibe.cli.textual_ui.widgets.question_app import QuestionApp
|
||||
|
||||
app = QuestionApp(single_question_args)
|
||||
app.other_input = MagicMock()
|
||||
app.other_input.has_focus = True
|
||||
|
||||
event = events.Key("1", "1")
|
||||
app._handle_number_key(event)
|
||||
|
||||
assert app.selected_option == 0
|
||||
assert 0 not in app.answers
|
||||
|
||||
def test_number_key_multi_select_toggles(self, multi_select_args):
|
||||
from textual import events
|
||||
|
||||
from vibe.cli.textual_ui.widgets.question_app import QuestionApp
|
||||
|
||||
app = QuestionApp(multi_select_args)
|
||||
|
||||
# Press "1" in multi-select -> should toggle Auth
|
||||
event = events.Key("1", "1")
|
||||
app._handle_number_key(event)
|
||||
|
||||
assert 0 in app.multi_selections.get(0, set())
|
||||
|
||||
def test_number_key_multi_select_submit_ignored(self, multi_select_args):
|
||||
from textual import events
|
||||
|
||||
from vibe.cli.textual_ui.widgets.question_app import QuestionApp
|
||||
|
||||
app = QuestionApp(multi_select_args)
|
||||
# Submit is at index 4 -> key "5"
|
||||
event = events.Key("5", "5")
|
||||
app._handle_number_key(event)
|
||||
|
||||
# Should not navigate to submit
|
||||
assert app.selected_option == 0
|
||||
|
||||
|
||||
class TestMultiSelectSubmit:
|
||||
def test_navigate_to_submit(self, multi_select_args):
|
||||
from vibe.cli.textual_ui.widgets.question_app import QuestionApp
|
||||
|
|
|
|||
163
tests/core/test_merge.py
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
from vibe.core.utils.merge import MergeConflictError, MergeStrategy
|
||||
|
||||
|
||||
class TestMergeStrategyEnum:
|
||||
def test_values_are_lowercase_strings(self) -> None:
|
||||
assert MergeStrategy.REPLACE == "replace"
|
||||
assert MergeStrategy.CONCAT == "concat"
|
||||
assert MergeStrategy.UNION == "union"
|
||||
assert MergeStrategy.MERGE == "merge"
|
||||
assert MergeStrategy.CONFLICT == "conflict"
|
||||
|
||||
def test_all_strategies_exist(self) -> None:
|
||||
assert len(MergeStrategy) == 5
|
||||
|
||||
def test_unknown_strategy_raises_not_implemented(self) -> None:
|
||||
fake = MagicMock(spec=MergeStrategy)
|
||||
with pytest.raises(NotImplementedError, match="not implemented"):
|
||||
MergeStrategy.apply(fake, "a", "b")
|
||||
|
||||
|
||||
class TestReplace:
|
||||
def test_override_wins(self) -> None:
|
||||
assert MergeStrategy.REPLACE.apply(1, 2) == 2
|
||||
|
||||
def test_base_returned_when_override_none(self) -> None:
|
||||
assert MergeStrategy.REPLACE.apply(1, None) == 1
|
||||
|
||||
def test_both_none_returns_none(self) -> None:
|
||||
assert MergeStrategy.REPLACE.apply(None, None) is None
|
||||
|
||||
def test_override_none_preserves_base_type(self) -> None:
|
||||
assert MergeStrategy.REPLACE.apply([1, 2], None) == [1, 2]
|
||||
assert MergeStrategy.REPLACE.apply({"a": 1}, None) == {"a": 1}
|
||||
|
||||
def test_override_can_be_falsy(self) -> None:
|
||||
assert MergeStrategy.REPLACE.apply(1, 0) == 0
|
||||
assert MergeStrategy.REPLACE.apply(1, "") == ""
|
||||
assert MergeStrategy.REPLACE.apply(1, False) is False
|
||||
|
||||
|
||||
class TestConcat:
|
||||
def test_lists_concatenated(self) -> None:
|
||||
assert MergeStrategy.CONCAT.apply([1, 2], [3, 4]) == [1, 2, 3, 4]
|
||||
|
||||
def test_base_none_returns_override(self) -> None:
|
||||
assert MergeStrategy.CONCAT.apply(None, [1]) == [1]
|
||||
|
||||
def test_override_none_returns_base(self) -> None:
|
||||
assert MergeStrategy.CONCAT.apply([1], None) == [1]
|
||||
|
||||
def test_both_none_returns_none(self) -> None:
|
||||
assert MergeStrategy.CONCAT.apply(None, None) is None
|
||||
|
||||
def test_empty_lists(self) -> None:
|
||||
assert MergeStrategy.CONCAT.apply([], []) == []
|
||||
|
||||
def test_raises_type_error_for_non_list(self) -> None:
|
||||
with pytest.raises(TypeError, match="CONCAT requires list operands"):
|
||||
MergeStrategy.CONCAT.apply("a", [1])
|
||||
with pytest.raises(TypeError, match="CONCAT requires list operands"):
|
||||
MergeStrategy.CONCAT.apply([1], "b")
|
||||
|
||||
|
||||
class TestUnion:
|
||||
def test_merge_by_key_override_wins(self) -> None:
|
||||
base = [{"name": "a", "v": 1}, {"name": "b", "v": 2}]
|
||||
override = [{"name": "b", "v": 99}]
|
||||
result = MergeStrategy.UNION.apply(base, override, key_fn=lambda x: x["name"])
|
||||
assert result == [{"name": "a", "v": 1}, {"name": "b", "v": 99}]
|
||||
|
||||
def test_preserves_order_base_first(self) -> None:
|
||||
base = [{"name": "a"}, {"name": "b"}]
|
||||
override = [{"name": "c"}]
|
||||
result = MergeStrategy.UNION.apply(base, override, key_fn=lambda x: x["name"])
|
||||
assert [x["name"] for x in result] == ["a", "b", "c"]
|
||||
|
||||
def test_new_keys_from_override_appended(self) -> None:
|
||||
base = [{"name": "a"}]
|
||||
override = [{"name": "b"}, {"name": "c"}]
|
||||
result = MergeStrategy.UNION.apply(base, override, key_fn=lambda x: x["name"])
|
||||
assert len(result) == 3
|
||||
|
||||
def test_base_none_returns_override(self) -> None:
|
||||
assert MergeStrategy.UNION.apply(None, [1], key_fn=str) == [1]
|
||||
|
||||
def test_override_none_returns_base(self) -> None:
|
||||
assert MergeStrategy.UNION.apply([1], None, key_fn=str) == [1]
|
||||
|
||||
def test_both_none_returns_none(self) -> None:
|
||||
assert MergeStrategy.UNION.apply(None, None) is None
|
||||
|
||||
def test_raises_without_key_fn(self) -> None:
|
||||
with pytest.raises(ValueError, match="UNION strategy requires key_fn"):
|
||||
MergeStrategy.UNION.apply([1], [2])
|
||||
|
||||
def test_raises_type_error_for_non_list(self) -> None:
|
||||
with pytest.raises(TypeError, match="UNION requires list operands"):
|
||||
MergeStrategy.UNION.apply("a", [1], key_fn=str)
|
||||
|
||||
|
||||
class TestMerge:
|
||||
def test_dicts_merged_one_level(self) -> None:
|
||||
result = MergeStrategy.MERGE.apply({"a": 1, "b": 2}, {"b": 3, "c": 4})
|
||||
assert result == {"a": 1, "b": 3, "c": 4}
|
||||
|
||||
def test_nested_dicts_not_recursed(self) -> None:
|
||||
base = {"a": {"x": 1, "y": 2}}
|
||||
override = {"a": {"y": 3, "z": 4}}
|
||||
result = MergeStrategy.MERGE.apply(base, override)
|
||||
assert result == {"a": {"y": 3, "z": 4}}
|
||||
|
||||
def test_base_none_returns_override(self) -> None:
|
||||
assert MergeStrategy.MERGE.apply(None, {"a": 1}) == {"a": 1}
|
||||
|
||||
def test_override_none_returns_base(self) -> None:
|
||||
assert MergeStrategy.MERGE.apply({"a": 1}, None) == {"a": 1}
|
||||
|
||||
def test_both_none_returns_none(self) -> None:
|
||||
assert MergeStrategy.MERGE.apply(None, None) is None
|
||||
|
||||
def test_raises_type_error_for_non_dict(self) -> None:
|
||||
with pytest.raises(TypeError, match="MERGE requires dict operands"):
|
||||
MergeStrategy.MERGE.apply([1], {"a": 1})
|
||||
|
||||
def test_does_not_mutate_inputs(self) -> None:
|
||||
base = {"a": 1}
|
||||
override = {"b": 2}
|
||||
MergeStrategy.MERGE.apply(base, override)
|
||||
assert base == {"a": 1}
|
||||
assert override == {"b": 2}
|
||||
|
||||
|
||||
class TestConflict:
|
||||
def test_raises_when_both_provided(self) -> None:
|
||||
with pytest.raises(MergeConflictError):
|
||||
MergeStrategy.CONFLICT.apply(1, 2)
|
||||
|
||||
def test_base_only_returns_base(self) -> None:
|
||||
assert MergeStrategy.CONFLICT.apply(1, None) == 1
|
||||
|
||||
def test_override_only_returns_override(self) -> None:
|
||||
assert MergeStrategy.CONFLICT.apply(None, 2) == 2
|
||||
|
||||
def test_both_none_returns_none(self) -> None:
|
||||
assert MergeStrategy.CONFLICT.apply(None, None) is None
|
||||
|
||||
|
||||
class TestMergeConflictError:
|
||||
def test_default_message(self) -> None:
|
||||
err = MergeConflictError()
|
||||
assert str(err) == "Merge conflict"
|
||||
assert err.field_name == ""
|
||||
|
||||
def test_message_with_field_name(self) -> None:
|
||||
err = MergeConflictError("active_model")
|
||||
assert str(err) == "Merge conflict on field 'active_model'"
|
||||
assert err.field_name == "active_model"
|
||||
|
|
@ -489,7 +489,7 @@ class TestTelemetryClient:
|
|||
|
||||
assert (
|
||||
client._get_telemetry_url("not-a-valid-url")
|
||||
== "https://codestral.mistral.ai/v1/datalake/events"
|
||||
== "https://api.mistral.ai/v1/datalake/events"
|
||||
)
|
||||
|
||||
def test_is_active_false_when_mistral_provider_exists_but_no_api_key(
|
||||
|
|
|
|||
|
|
@ -518,3 +518,77 @@ class TestSkillUserInvocable:
|
|||
assert skills["visible-skill"].user_invocable is True
|
||||
assert skills["hidden-skill"].user_invocable is False
|
||||
assert skills["default-skill"].user_invocable is True
|
||||
|
||||
|
||||
class TestParseSkillCommand:
|
||||
def test_plain_text_returns_none(self, skill_manager: SkillManager) -> None:
|
||||
assert skill_manager.parse_skill_command("hello world") is None
|
||||
|
||||
def test_unknown_skill_returns_none(self, skill_manager: SkillManager) -> None:
|
||||
assert skill_manager.parse_skill_command("/nonexistent") is None
|
||||
|
||||
def test_slash_only_returns_none(self, skill_manager: SkillManager) -> None:
|
||||
assert skill_manager.parse_skill_command("/") is None
|
||||
|
||||
def test_parses_skill_without_args(
|
||||
self, skills_dir: Path, skill_config: VibeConfig
|
||||
) -> None:
|
||||
create_skill(skills_dir, "my-skill", body="Do the thing.")
|
||||
manager = SkillManager(lambda: skill_config)
|
||||
|
||||
parsed = manager.parse_skill_command("/my-skill")
|
||||
assert parsed is not None
|
||||
assert parsed.name == "my-skill"
|
||||
assert "Do the thing." in parsed.content
|
||||
assert parsed.extra_instructions is None
|
||||
|
||||
def test_parses_skill_with_args(
|
||||
self, skills_dir: Path, skill_config: VibeConfig
|
||||
) -> None:
|
||||
create_skill(skills_dir, "my-skill", body="Do the thing.")
|
||||
manager = SkillManager(lambda: skill_config)
|
||||
|
||||
parsed = manager.parse_skill_command("/my-skill fix the bug")
|
||||
assert parsed is not None
|
||||
assert parsed.name == "my-skill"
|
||||
assert parsed.extra_instructions == "fix the bug"
|
||||
|
||||
def test_case_insensitive(self, skills_dir: Path, skill_config: VibeConfig) -> None:
|
||||
create_skill(skills_dir, "my-skill", body="Do the thing.")
|
||||
manager = SkillManager(lambda: skill_config)
|
||||
|
||||
parsed = manager.parse_skill_command("/MY-SKILL")
|
||||
assert parsed is not None
|
||||
assert parsed.name == "my-skill"
|
||||
|
||||
def test_raises_on_unreadable_skill(
|
||||
self, skills_dir: Path, skill_config: VibeConfig
|
||||
) -> None:
|
||||
create_skill(skills_dir, "bad-skill", body="content")
|
||||
manager = SkillManager(lambda: skill_config)
|
||||
(skills_dir / "bad-skill" / "SKILL.md").unlink()
|
||||
|
||||
with pytest.raises(OSError):
|
||||
manager.parse_skill_command("/bad-skill")
|
||||
|
||||
|
||||
class TestBuildSkillPrompt:
|
||||
def test_without_args(self, skills_dir: Path, skill_config: VibeConfig) -> None:
|
||||
create_skill(skills_dir, "my-skill", body="Do the thing.")
|
||||
manager = SkillManager(lambda: skill_config)
|
||||
|
||||
parsed = manager.parse_skill_command("/my-skill")
|
||||
assert parsed is not None
|
||||
prompt = SkillManager.build_skill_prompt("/my-skill", parsed)
|
||||
assert prompt == parsed.content
|
||||
|
||||
def test_with_args(self, skills_dir: Path, skill_config: VibeConfig) -> None:
|
||||
create_skill(skills_dir, "my-skill", body="Do the thing.")
|
||||
manager = SkillManager(lambda: skill_config)
|
||||
|
||||
text = "/my-skill fix the bug"
|
||||
parsed = manager.parse_skill_command(text)
|
||||
assert parsed is not None
|
||||
prompt = SkillManager.build_skill_prompt(text, parsed)
|
||||
assert prompt.startswith("/my-skill fix the bug")
|
||||
assert "Do the thing." in prompt
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@
|
|||
.terminal-r5 { fill: #9a9b99 }
|
||||
.terminal-r6 { fill: #608ab1;font-weight: bold }
|
||||
.terminal-r7 { fill: #c5c8c6;font-weight: bold }
|
||||
.terminal-r8 { fill: #9cafbd;font-weight: bold }
|
||||
.terminal-r9 { fill: #868887 }
|
||||
</style>
|
||||
|
||||
<defs>
|
||||
|
|
@ -160,7 +162,7 @@
|
|||
</g>
|
||||
|
||||
<g transform="translate(9, 41)" clip-path="url(#terminal-clip-terminal)">
|
||||
<rect fill="#608ab1" x="36.6" y="733.5" width="427" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="463.6" y="733.5" width="963.8" height="24.65" shape-rendering="crispEdges"/>
|
||||
<rect fill="#608ab1" x="36.6" y="733.5" width="146.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="183" y="733.5" width="109.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="292.8" y="733.5" width="97.6" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="390.4" y="733.5" width="1037" height="24.65" shape-rendering="crispEdges"/>
|
||||
<g class="terminal-matrix">
|
||||
<text class="terminal-r1" x="1464" y="20" textLength="12.2" clip-path="url(#terminal-line-0)">
|
||||
</text><text class="terminal-r1" x="1464" y="44.4" textLength="12.2" clip-path="url(#terminal-line-1)">
|
||||
|
|
@ -179,21 +181,21 @@
|
|||
</text><text class="terminal-r1" x="1464" y="361.6" textLength="12.2" clip-path="url(#terminal-line-14)">
|
||||
</text><text class="terminal-r1" x="1464" y="386" textLength="12.2" clip-path="url(#terminal-line-15)">
|
||||
</text><text class="terminal-r1" x="1464" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">
|
||||
</text><text class="terminal-r1" x="1464" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">
|
||||
</text><text class="terminal-r1" x="0" y="459.2" textLength="134.2" clip-path="url(#terminal-line-18)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="459.2" textLength="146.4" clip-path="url(#terminal-line-18)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="459.2" textLength="122" clip-path="url(#terminal-line-18)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="459.2" textLength="183" clip-path="url(#terminal-line-18)">devstral-latest</text><text class="terminal-r1" x="622.2" y="459.2" textLength="256.2" clip-path="url(#terminal-line-18)"> · [Subscription] Pro</text><text class="terminal-r1" x="1464" y="459.2" textLength="12.2" clip-path="url(#terminal-line-18)">
|
||||
</text><text class="terminal-r1" x="0" y="483.6" textLength="134.2" clip-path="url(#terminal-line-19)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="483.6" textLength="414.8" clip-path="url(#terminal-line-19)">1 model · 2 MCP servers · 0 skills</text><text class="terminal-r1" x="1464" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">
|
||||
</text><text class="terminal-r1" x="0" y="508" textLength="134.2" clip-path="url(#terminal-line-20)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="508" textLength="61" clip-path="url(#terminal-line-20)">Type </text><text class="terminal-r3" x="231.8" y="508" textLength="61" clip-path="url(#terminal-line-20)">/help</text><text class="terminal-r1" x="292.8" y="508" textLength="256.2" clip-path="url(#terminal-line-20)"> for more information</text><text class="terminal-r1" x="1464" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r1" x="0" y="434.8" textLength="134.2" clip-path="url(#terminal-line-17)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="434.8" textLength="146.4" clip-path="url(#terminal-line-17)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="434.8" textLength="122" clip-path="url(#terminal-line-17)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="434.8" textLength="183" clip-path="url(#terminal-line-17)">devstral-latest</text><text class="terminal-r1" x="622.2" y="434.8" textLength="256.2" clip-path="url(#terminal-line-17)"> · [Subscription] Pro</text><text class="terminal-r1" x="1464" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">
|
||||
</text><text class="terminal-r1" x="0" y="459.2" textLength="134.2" clip-path="url(#terminal-line-18)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="459.2" textLength="414.8" clip-path="url(#terminal-line-18)">1 model · 2 MCP servers · 0 skills</text><text class="terminal-r1" x="1464" y="459.2" textLength="12.2" clip-path="url(#terminal-line-18)">
|
||||
</text><text class="terminal-r1" x="0" y="483.6" textLength="134.2" clip-path="url(#terminal-line-19)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="483.6" textLength="61" clip-path="url(#terminal-line-19)">Type </text><text class="terminal-r3" x="231.8" y="483.6" textLength="61" clip-path="url(#terminal-line-19)">/help</text><text class="terminal-r1" x="292.8" y="483.6" textLength="256.2" clip-path="url(#terminal-line-19)"> for more information</text><text class="terminal-r1" x="1464" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">
|
||||
</text><text class="terminal-r1" x="1464" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r1" x="1464" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">
|
||||
</text><text class="terminal-r1" x="1464" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">
|
||||
</text><text class="terminal-r4" x="0" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">┃</text><text class="terminal-r2" x="24.4" y="581.2" textLength="183" clip-path="url(#terminal-line-23)">/mcp filesystem</text><text class="terminal-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r5" x="24.4" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">⎣</text><text class="terminal-r1" x="48.8" y="605.6" textLength="256.2" clip-path="url(#terminal-line-24)">MCP servers opened...</text><text class="terminal-r1" x="1464" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">
|
||||
</text><text class="terminal-r4" x="0" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">┃</text><text class="terminal-r2" x="24.4" y="556.8" textLength="183" clip-path="url(#terminal-line-22)">/mcp filesystem</text><text class="terminal-r1" x="1464" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">
|
||||
</text><text class="terminal-r5" x="24.4" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">⎣</text><text class="terminal-r1" x="48.8" y="581.2" textLength="256.2" clip-path="url(#terminal-line-23)">MCP servers opened...</text><text class="terminal-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r1" x="1464" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">
|
||||
</text><text class="terminal-r1" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r1" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</text><text class="terminal-r5" x="0" y="678.8" textLength="1464" clip-path="url(#terminal-line-27)">┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐</text><text class="terminal-r1" x="1464" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">
|
||||
</text><text class="terminal-r5" x="0" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">│</text><text class="terminal-r6" x="24.4" y="703.2" textLength="134.2" clip-path="url(#terminal-line-28)">MCP Servers</text><text class="terminal-r5" x="1451.8" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">│</text><text class="terminal-r1" x="1464" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">
|
||||
</text><text class="terminal-r5" x="0" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">│</text><text class="terminal-r5" x="1451.8" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">│</text><text class="terminal-r1" x="1464" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">
|
||||
</text><text class="terminal-r5" x="0" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">│</text><text class="terminal-r7" x="36.6" y="752" textLength="427" clip-path="url(#terminal-line-30)">filesystem  [stdio]  1 tool enabled</text><text class="terminal-r5" x="1451.8" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">│</text><text class="terminal-r1" x="1464" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">
|
||||
</text><text class="terminal-r5" x="0" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">│</text><text class="terminal-r1" x="36.6" y="776.4" textLength="366" clip-path="url(#terminal-line-31)">search  [http]  1 tool enabled</text><text class="terminal-r5" x="1451.8" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">│</text><text class="terminal-r1" x="1464" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">
|
||||
</text><text class="terminal-r5" x="0" y="654.4" textLength="1464" clip-path="url(#terminal-line-26)">┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐</text><text class="terminal-r1" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</text><text class="terminal-r5" x="0" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">│</text><text class="terminal-r6" x="24.4" y="678.8" textLength="134.2" clip-path="url(#terminal-line-27)">MCP Servers</text><text class="terminal-r5" x="1451.8" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">│</text><text class="terminal-r1" x="1464" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">
|
||||
</text><text class="terminal-r5" x="0" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">│</text><text class="terminal-r5" x="1451.8" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">│</text><text class="terminal-r1" x="1464" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">
|
||||
</text><text class="terminal-r5" x="0" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">│</text><text class="terminal-r7" x="36.6" y="727.6" textLength="207.4" clip-path="url(#terminal-line-29)">Local MCP Servers</text><text class="terminal-r5" x="1451.8" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">│</text><text class="terminal-r1" x="1464" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">
|
||||
</text><text class="terminal-r5" x="0" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">│</text><text class="terminal-r7" x="36.6" y="752" textLength="146.4" clip-path="url(#terminal-line-30)">  filesystem</text><text class="terminal-r8" x="183" y="752" textLength="109.8" clip-path="url(#terminal-line-30)">  [stdio]</text><text class="terminal-r8" x="292.8" y="752" textLength="97.6" clip-path="url(#terminal-line-30)">  1 tool</text><text class="terminal-r5" x="1451.8" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">│</text><text class="terminal-r1" x="1464" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">
|
||||
</text><text class="terminal-r5" x="0" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">│</text><text class="terminal-r1" x="36.6" y="776.4" textLength="146.4" clip-path="url(#terminal-line-31)">  search    </text><text class="terminal-r9" x="183" y="776.4" textLength="109.8" clip-path="url(#terminal-line-31)">  [http] </text><text class="terminal-r9" x="292.8" y="776.4" textLength="97.6" clip-path="url(#terminal-line-31)">  1 tool</text><text class="terminal-r5" x="1451.8" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">│</text><text class="terminal-r1" x="1464" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">
|
||||
</text><text class="terminal-r5" x="0" y="800.8" textLength="12.2" clip-path="url(#terminal-line-32)">│</text><text class="terminal-r5" x="1451.8" y="800.8" textLength="12.2" clip-path="url(#terminal-line-32)">│</text><text class="terminal-r1" x="1464" y="800.8" textLength="12.2" clip-path="url(#terminal-line-32)">
|
||||
</text><text class="terminal-r5" x="0" y="825.2" textLength="12.2" clip-path="url(#terminal-line-33)">│</text><text class="terminal-r5" x="24.4" y="825.2" textLength="488" clip-path="url(#terminal-line-33)">↑↓ Navigate  Enter Show tools  Esc Close</text><text class="terminal-r5" x="1451.8" y="825.2" textLength="12.2" clip-path="url(#terminal-line-33)">│</text><text class="terminal-r1" x="1464" y="825.2" textLength="12.2" clip-path="url(#terminal-line-33)">
|
||||
</text><text class="terminal-r5" x="0" y="849.6" textLength="1464" clip-path="url(#terminal-line-34)">└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘</text><text class="terminal-r1" x="1464" y="849.6" textLength="12.2" clip-path="url(#terminal-line-34)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 16 KiB |
|
|
@ -39,6 +39,8 @@
|
|||
.terminal-r5 { fill: #9a9b99 }
|
||||
.terminal-r6 { fill: #608ab1;font-weight: bold }
|
||||
.terminal-r7 { fill: #c5c8c6;font-weight: bold }
|
||||
.terminal-r8 { fill: #9cafbd;font-weight: bold }
|
||||
.terminal-r9 { fill: #868887 }
|
||||
</style>
|
||||
|
||||
<defs>
|
||||
|
|
@ -160,7 +162,7 @@
|
|||
</g>
|
||||
|
||||
<g transform="translate(9, 41)" clip-path="url(#terminal-clip-terminal)">
|
||||
<rect fill="#608ab1" x="36.6" y="709.1" width="427" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="463.6" y="709.1" width="963.8" height="24.65" shape-rendering="crispEdges"/>
|
||||
<rect fill="#608ab1" x="36.6" y="709.1" width="183" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="219.6" y="709.1" width="109.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="329.4" y="709.1" width="97.6" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="427" y="709.1" width="1000.4" height="24.65" shape-rendering="crispEdges"/>
|
||||
<g class="terminal-matrix">
|
||||
<text class="terminal-r1" x="1464" y="20" textLength="12.2" clip-path="url(#terminal-line-0)">
|
||||
</text><text class="terminal-r1" x="1464" y="44.4" textLength="12.2" clip-path="url(#terminal-line-1)">
|
||||
|
|
@ -178,22 +180,22 @@
|
|||
</text><text class="terminal-r1" x="1464" y="337.2" textLength="12.2" clip-path="url(#terminal-line-13)">
|
||||
</text><text class="terminal-r1" x="1464" y="361.6" textLength="12.2" clip-path="url(#terminal-line-14)">
|
||||
</text><text class="terminal-r1" x="1464" y="386" textLength="12.2" clip-path="url(#terminal-line-15)">
|
||||
</text><text class="terminal-r1" x="1464" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">
|
||||
</text><text class="terminal-r1" x="0" y="434.8" textLength="134.2" clip-path="url(#terminal-line-17)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="434.8" textLength="146.4" clip-path="url(#terminal-line-17)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="434.8" textLength="122" clip-path="url(#terminal-line-17)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="434.8" textLength="183" clip-path="url(#terminal-line-17)">devstral-latest</text><text class="terminal-r1" x="622.2" y="434.8" textLength="256.2" clip-path="url(#terminal-line-17)"> · [Subscription] Pro</text><text class="terminal-r1" x="1464" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">
|
||||
</text><text class="terminal-r1" x="0" y="459.2" textLength="134.2" clip-path="url(#terminal-line-18)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="459.2" textLength="414.8" clip-path="url(#terminal-line-18)">1 model · 2 MCP servers · 0 skills</text><text class="terminal-r1" x="1464" y="459.2" textLength="12.2" clip-path="url(#terminal-line-18)">
|
||||
</text><text class="terminal-r1" x="0" y="483.6" textLength="134.2" clip-path="url(#terminal-line-19)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="483.6" textLength="61" clip-path="url(#terminal-line-19)">Type </text><text class="terminal-r3" x="231.8" y="483.6" textLength="61" clip-path="url(#terminal-line-19)">/help</text><text class="terminal-r1" x="292.8" y="483.6" textLength="256.2" clip-path="url(#terminal-line-19)"> for more information</text><text class="terminal-r1" x="1464" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">
|
||||
</text><text class="terminal-r1" x="0" y="410.4" textLength="134.2" clip-path="url(#terminal-line-16)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="410.4" textLength="146.4" clip-path="url(#terminal-line-16)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="410.4" textLength="122" clip-path="url(#terminal-line-16)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="410.4" textLength="183" clip-path="url(#terminal-line-16)">devstral-latest</text><text class="terminal-r1" x="622.2" y="410.4" textLength="256.2" clip-path="url(#terminal-line-16)"> · [Subscription] Pro</text><text class="terminal-r1" x="1464" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">
|
||||
</text><text class="terminal-r1" x="0" y="434.8" textLength="134.2" clip-path="url(#terminal-line-17)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="434.8" textLength="414.8" clip-path="url(#terminal-line-17)">1 model · 2 MCP servers · 0 skills</text><text class="terminal-r1" x="1464" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">
|
||||
</text><text class="terminal-r1" x="0" y="459.2" textLength="134.2" clip-path="url(#terminal-line-18)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="459.2" textLength="61" clip-path="url(#terminal-line-18)">Type </text><text class="terminal-r3" x="231.8" y="459.2" textLength="61" clip-path="url(#terminal-line-18)">/help</text><text class="terminal-r1" x="292.8" y="459.2" textLength="256.2" clip-path="url(#terminal-line-18)"> for more information</text><text class="terminal-r1" x="1464" y="459.2" textLength="12.2" clip-path="url(#terminal-line-18)">
|
||||
</text><text class="terminal-r1" x="1464" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">
|
||||
</text><text class="terminal-r1" x="1464" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r1" x="1464" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">
|
||||
</text><text class="terminal-r4" x="0" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">┃</text><text class="terminal-r2" x="24.4" y="556.8" textLength="48.8" clip-path="url(#terminal-line-22)">/mcp</text><text class="terminal-r1" x="1464" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">
|
||||
</text><text class="terminal-r5" x="24.4" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">⎣</text><text class="terminal-r1" x="48.8" y="581.2" textLength="256.2" clip-path="url(#terminal-line-23)">MCP servers opened...</text><text class="terminal-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r4" x="0" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">┃</text><text class="terminal-r2" x="24.4" y="532.4" textLength="48.8" clip-path="url(#terminal-line-21)">/mcp</text><text class="terminal-r1" x="1464" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">
|
||||
</text><text class="terminal-r5" x="24.4" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">⎣</text><text class="terminal-r1" x="48.8" y="556.8" textLength="256.2" clip-path="url(#terminal-line-22)">MCP servers opened...</text><text class="terminal-r1" x="1464" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">
|
||||
</text><text class="terminal-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r1" x="1464" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">
|
||||
</text><text class="terminal-r1" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r5" x="0" y="654.4" textLength="1464" clip-path="url(#terminal-line-26)">┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐</text><text class="terminal-r1" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</text><text class="terminal-r5" x="0" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">│</text><text class="terminal-r6" x="24.4" y="678.8" textLength="134.2" clip-path="url(#terminal-line-27)">MCP Servers</text><text class="terminal-r5" x="1451.8" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">│</text><text class="terminal-r1" x="1464" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">
|
||||
</text><text class="terminal-r5" x="0" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">│</text><text class="terminal-r5" x="1451.8" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">│</text><text class="terminal-r1" x="1464" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">
|
||||
</text><text class="terminal-r5" x="0" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">│</text><text class="terminal-r7" x="36.6" y="727.6" textLength="427" clip-path="url(#terminal-line-29)">filesystem  [stdio]  1 tool enabled</text><text class="terminal-r5" x="1451.8" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">│</text><text class="terminal-r1" x="1464" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">
|
||||
</text><text class="terminal-r5" x="0" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">│</text><text class="terminal-r1" x="36.6" y="752" textLength="427" clip-path="url(#terminal-line-30)">broken-server  [stdio]  unavailable</text><text class="terminal-r5" x="1451.8" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">│</text><text class="terminal-r1" x="1464" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">
|
||||
</text><text class="terminal-r5" x="0" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">│</text><text class="terminal-r1" x="36.6" y="776.4" textLength="366" clip-path="url(#terminal-line-31)">search  [http]  1 tool enabled</text><text class="terminal-r5" x="1451.8" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">│</text><text class="terminal-r1" x="1464" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">
|
||||
</text><text class="terminal-r5" x="0" y="630" textLength="1464" clip-path="url(#terminal-line-25)">┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐</text><text class="terminal-r1" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r5" x="0" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">│</text><text class="terminal-r6" x="24.4" y="654.4" textLength="134.2" clip-path="url(#terminal-line-26)">MCP Servers</text><text class="terminal-r5" x="1451.8" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">│</text><text class="terminal-r1" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</text><text class="terminal-r5" x="0" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">│</text><text class="terminal-r5" x="1451.8" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">│</text><text class="terminal-r1" x="1464" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">
|
||||
</text><text class="terminal-r5" x="0" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">│</text><text class="terminal-r7" x="36.6" y="703.2" textLength="207.4" clip-path="url(#terminal-line-28)">Local MCP Servers</text><text class="terminal-r5" x="1451.8" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">│</text><text class="terminal-r1" x="1464" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">
|
||||
</text><text class="terminal-r5" x="0" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">│</text><text class="terminal-r7" x="36.6" y="727.6" textLength="183" clip-path="url(#terminal-line-29)">  filesystem   </text><text class="terminal-r8" x="219.6" y="727.6" textLength="109.8" clip-path="url(#terminal-line-29)">  [stdio]</text><text class="terminal-r8" x="329.4" y="727.6" textLength="97.6" clip-path="url(#terminal-line-29)">  1 tool</text><text class="terminal-r5" x="1451.8" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">│</text><text class="terminal-r1" x="1464" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">
|
||||
</text><text class="terminal-r5" x="0" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">│</text><text class="terminal-r1" x="36.6" y="752" textLength="183" clip-path="url(#terminal-line-30)">  broken-server</text><text class="terminal-r9" x="219.6" y="752" textLength="109.8" clip-path="url(#terminal-line-30)">  [stdio]</text><text class="terminal-r9" x="329.4" y="752" textLength="122" clip-path="url(#terminal-line-30)">  no tools</text><text class="terminal-r5" x="1451.8" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">│</text><text class="terminal-r1" x="1464" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">
|
||||
</text><text class="terminal-r5" x="0" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">│</text><text class="terminal-r1" x="36.6" y="776.4" textLength="183" clip-path="url(#terminal-line-31)">  search       </text><text class="terminal-r9" x="219.6" y="776.4" textLength="109.8" clip-path="url(#terminal-line-31)">  [http] </text><text class="terminal-r9" x="329.4" y="776.4" textLength="97.6" clip-path="url(#terminal-line-31)">  1 tool</text><text class="terminal-r5" x="1451.8" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">│</text><text class="terminal-r1" x="1464" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">
|
||||
</text><text class="terminal-r5" x="0" y="800.8" textLength="12.2" clip-path="url(#terminal-line-32)">│</text><text class="terminal-r5" x="1451.8" y="800.8" textLength="12.2" clip-path="url(#terminal-line-32)">│</text><text class="terminal-r1" x="1464" y="800.8" textLength="12.2" clip-path="url(#terminal-line-32)">
|
||||
</text><text class="terminal-r5" x="0" y="825.2" textLength="12.2" clip-path="url(#terminal-line-33)">│</text><text class="terminal-r5" x="24.4" y="825.2" textLength="488" clip-path="url(#terminal-line-33)">↑↓ Navigate  Enter Show tools  Esc Close</text><text class="terminal-r5" x="1451.8" y="825.2" textLength="12.2" clip-path="url(#terminal-line-33)">│</text><text class="terminal-r1" x="1464" y="825.2" textLength="12.2" clip-path="url(#terminal-line-33)">
|
||||
</text><text class="terminal-r5" x="0" y="849.6" textLength="1464" clip-path="url(#terminal-line-34)">└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘</text><text class="terminal-r1" x="1464" y="849.6" textLength="12.2" clip-path="url(#terminal-line-34)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 16 KiB |
|
|
@ -0,0 +1,206 @@
|
|||
<svg class="rich-terminal" viewBox="0 0 1482 928.4" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Generated with Rich https://www.textualize.io -->
|
||||
<style>
|
||||
|
||||
@font-face {
|
||||
font-family: "Fira Code";
|
||||
src: local("FiraCode-Regular"),
|
||||
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Regular.woff2") format("woff2"),
|
||||
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Regular.woff") format("woff");
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Fira Code";
|
||||
src: local("FiraCode-Bold"),
|
||||
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Bold.woff2") format("woff2"),
|
||||
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Bold.woff") format("woff");
|
||||
font-style: bold;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.terminal-matrix {
|
||||
font-family: Fira Code, monospace;
|
||||
font-size: 20px;
|
||||
line-height: 24.4px;
|
||||
font-variant-east-asian: full-width;
|
||||
}
|
||||
|
||||
.terminal-title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
font-family: arial;
|
||||
}
|
||||
|
||||
.terminal-r1 { fill: #c5c8c6 }
|
||||
.terminal-r2 { fill: #ff8205;font-weight: bold }
|
||||
.terminal-r3 { fill: #68a0b3 }
|
||||
.terminal-r4 { fill: #ff8205 }
|
||||
.terminal-r5 { fill: #9a9b99 }
|
||||
.terminal-r6 { fill: #608ab1;font-weight: bold }
|
||||
.terminal-r7 { fill: #c5c8c6;font-weight: bold }
|
||||
.terminal-r8 { fill: #9cafbd;font-weight: bold }
|
||||
.terminal-r9 { fill: #868887 }
|
||||
.terminal-r10 { fill: #98a84b }
|
||||
</style>
|
||||
|
||||
<defs>
|
||||
<clipPath id="terminal-clip-terminal">
|
||||
<rect x="0" y="0" width="1463.0" height="877.4" />
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-0">
|
||||
<rect x="0" y="1.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-1">
|
||||
<rect x="0" y="25.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-2">
|
||||
<rect x="0" y="50.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-3">
|
||||
<rect x="0" y="74.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-4">
|
||||
<rect x="0" y="99.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-5">
|
||||
<rect x="0" y="123.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-6">
|
||||
<rect x="0" y="147.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-7">
|
||||
<rect x="0" y="172.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-8">
|
||||
<rect x="0" y="196.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-9">
|
||||
<rect x="0" y="221.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-10">
|
||||
<rect x="0" y="245.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-11">
|
||||
<rect x="0" y="269.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-12">
|
||||
<rect x="0" y="294.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-13">
|
||||
<rect x="0" y="318.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-14">
|
||||
<rect x="0" y="343.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-15">
|
||||
<rect x="0" y="367.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-16">
|
||||
<rect x="0" y="391.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-17">
|
||||
<rect x="0" y="416.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-18">
|
||||
<rect x="0" y="440.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-19">
|
||||
<rect x="0" y="465.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-20">
|
||||
<rect x="0" y="489.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-21">
|
||||
<rect x="0" y="513.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-22">
|
||||
<rect x="0" y="538.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-23">
|
||||
<rect x="0" y="562.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-24">
|
||||
<rect x="0" y="587.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-25">
|
||||
<rect x="0" y="611.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-26">
|
||||
<rect x="0" y="635.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-27">
|
||||
<rect x="0" y="660.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-28">
|
||||
<rect x="0" y="684.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-29">
|
||||
<rect x="0" y="709.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-30">
|
||||
<rect x="0" y="733.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-31">
|
||||
<rect x="0" y="757.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-32">
|
||||
<rect x="0" y="782.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-33">
|
||||
<rect x="0" y="806.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-34">
|
||||
<rect x="0" y="831.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
|
||||
<rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" x="1" y="1" width="1480" height="926.4" rx="8"/><text class="terminal-title" fill="#c5c8c6" text-anchor="middle" x="740" y="27">SnapshotTestAppWithConnectors</text>
|
||||
<g transform="translate(26,22)">
|
||||
<circle cx="0" cy="0" r="7" fill="#ff5f57"/>
|
||||
<circle cx="22" cy="0" r="7" fill="#febc2e"/>
|
||||
<circle cx="44" cy="0" r="7" fill="#28c840"/>
|
||||
</g>
|
||||
|
||||
<g transform="translate(9, 41)" clip-path="url(#terminal-clip-terminal)">
|
||||
<rect fill="#608ab1" x="36.6" y="660.3" width="146.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="183" y="660.3" width="109.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="292.8" y="660.3" width="97.6" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="390.4" y="660.3" width="1037" height="24.65" shape-rendering="crispEdges"/>
|
||||
<g class="terminal-matrix">
|
||||
<text class="terminal-r1" x="1464" y="20" textLength="12.2" clip-path="url(#terminal-line-0)">
|
||||
</text><text class="terminal-r1" x="1464" y="44.4" textLength="12.2" clip-path="url(#terminal-line-1)">
|
||||
</text><text class="terminal-r1" x="1464" y="68.8" textLength="12.2" clip-path="url(#terminal-line-2)">
|
||||
</text><text class="terminal-r1" x="1464" y="93.2" textLength="12.2" clip-path="url(#terminal-line-3)">
|
||||
</text><text class="terminal-r1" x="1464" y="117.6" textLength="12.2" clip-path="url(#terminal-line-4)">
|
||||
</text><text class="terminal-r1" x="1464" y="142" textLength="12.2" clip-path="url(#terminal-line-5)">
|
||||
</text><text class="terminal-r1" x="1464" y="166.4" textLength="12.2" clip-path="url(#terminal-line-6)">
|
||||
</text><text class="terminal-r1" x="1464" y="190.8" textLength="12.2" clip-path="url(#terminal-line-7)">
|
||||
</text><text class="terminal-r1" x="1464" y="215.2" textLength="12.2" clip-path="url(#terminal-line-8)">
|
||||
</text><text class="terminal-r1" x="1464" y="239.6" textLength="12.2" clip-path="url(#terminal-line-9)">
|
||||
</text><text class="terminal-r1" x="1464" y="264" textLength="12.2" clip-path="url(#terminal-line-10)">
|
||||
</text><text class="terminal-r1" x="1464" y="288.4" textLength="12.2" clip-path="url(#terminal-line-11)">
|
||||
</text><text class="terminal-r1" x="1464" y="312.8" textLength="12.2" clip-path="url(#terminal-line-12)">
|
||||
</text><text class="terminal-r1" x="1464" y="337.2" textLength="12.2" clip-path="url(#terminal-line-13)">
|
||||
</text><text class="terminal-r1" x="0" y="361.6" textLength="134.2" clip-path="url(#terminal-line-14)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="361.6" textLength="146.4" clip-path="url(#terminal-line-14)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="361.6" textLength="122" clip-path="url(#terminal-line-14)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="361.6" textLength="183" clip-path="url(#terminal-line-14)">devstral-latest</text><text class="terminal-r1" x="622.2" y="361.6" textLength="256.2" clip-path="url(#terminal-line-14)"> · [Subscription] Pro</text><text class="terminal-r1" x="1464" y="361.6" textLength="12.2" clip-path="url(#terminal-line-14)">
|
||||
</text><text class="terminal-r1" x="0" y="386" textLength="134.2" clip-path="url(#terminal-line-15)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="386" textLength="585.6" clip-path="url(#terminal-line-15)">1 model · 2 connectors · 1 MCP server · 0 skills</text><text class="terminal-r1" x="1464" y="386" textLength="12.2" clip-path="url(#terminal-line-15)">
|
||||
</text><text class="terminal-r1" x="0" y="410.4" textLength="134.2" clip-path="url(#terminal-line-16)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="410.4" textLength="61" clip-path="url(#terminal-line-16)">Type </text><text class="terminal-r3" x="231.8" y="410.4" textLength="61" clip-path="url(#terminal-line-16)">/help</text><text class="terminal-r1" x="292.8" y="410.4" textLength="256.2" clip-path="url(#terminal-line-16)"> for more information</text><text class="terminal-r1" x="1464" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">
|
||||
</text><text class="terminal-r1" x="1464" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">
|
||||
</text><text class="terminal-r1" x="1464" y="459.2" textLength="12.2" clip-path="url(#terminal-line-18)">
|
||||
</text><text class="terminal-r4" x="0" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">┃</text><text class="terminal-r2" x="24.4" y="483.6" textLength="48.8" clip-path="url(#terminal-line-19)">/mcp</text><text class="terminal-r1" x="1464" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">
|
||||
</text><text class="terminal-r5" x="24.4" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">⎣</text><text class="terminal-r1" x="48.8" y="508" textLength="256.2" clip-path="url(#terminal-line-20)">MCP servers opened...</text><text class="terminal-r1" x="1464" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r1" x="1464" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">
|
||||
</text><text class="terminal-r1" x="1464" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">
|
||||
</text><text class="terminal-r5" x="0" y="581.2" textLength="1464" clip-path="url(#terminal-line-23)">┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐</text><text class="terminal-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r5" x="0" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">│</text><text class="terminal-r6" x="24.4" y="605.6" textLength="292.8" clip-path="url(#terminal-line-24)">MCP Servers & Connectors</text><text class="terminal-r5" x="1451.8" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">│</text><text class="terminal-r1" x="1464" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">
|
||||
</text><text class="terminal-r5" x="0" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">│</text><text class="terminal-r5" x="1451.8" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">│</text><text class="terminal-r1" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r5" x="0" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">│</text><text class="terminal-r7" x="36.6" y="654.4" textLength="207.4" clip-path="url(#terminal-line-26)">Local MCP Servers</text><text class="terminal-r5" x="1451.8" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">│</text><text class="terminal-r1" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</text><text class="terminal-r5" x="0" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">│</text><text class="terminal-r7" x="36.6" y="678.8" textLength="146.4" clip-path="url(#terminal-line-27)">  filesystem</text><text class="terminal-r8" x="183" y="678.8" textLength="109.8" clip-path="url(#terminal-line-27)">  [stdio]</text><text class="terminal-r8" x="292.8" y="678.8" textLength="97.6" clip-path="url(#terminal-line-27)">  1 tool</text><text class="terminal-r5" x="1451.8" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">│</text><text class="terminal-r1" x="1464" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">
|
||||
</text><text class="terminal-r5" x="0" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">│</text><text class="terminal-r5" x="1451.8" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">│</text><text class="terminal-r1" x="1464" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">
|
||||
</text><text class="terminal-r5" x="0" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">│</text><text class="terminal-r7" x="36.6" y="727.6" textLength="244" clip-path="url(#terminal-line-29)">Workspace Connectors</text><text class="terminal-r5" x="1451.8" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">│</text><text class="terminal-r1" x="1464" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">
|
||||
</text><text class="terminal-r5" x="0" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">│</text><text class="terminal-r1" x="36.6" y="752" textLength="85.4" clip-path="url(#terminal-line-30)">  gmail</text><text class="terminal-r9" x="122" y="752" textLength="158.6" clip-path="url(#terminal-line-30)">  [connector]</text><text class="terminal-r9" x="280.6" y="752" textLength="109.8" clip-path="url(#terminal-line-30)">  3 tools</text><text class="terminal-r10" x="414.8" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">●</text><text class="terminal-r9" x="427" y="752" textLength="122" clip-path="url(#terminal-line-30)"> connected</text><text class="terminal-r5" x="1451.8" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">│</text><text class="terminal-r1" x="1464" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">
|
||||
</text><text class="terminal-r5" x="0" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">│</text><text class="terminal-r1" x="36.6" y="776.4" textLength="85.4" clip-path="url(#terminal-line-31)">  slack</text><text class="terminal-r9" x="122" y="776.4" textLength="158.6" clip-path="url(#terminal-line-31)">  [connector]</text><text class="terminal-r9" x="280.6" y="776.4" textLength="109.8" clip-path="url(#terminal-line-31)">  2 tools</text><text class="terminal-r10" x="414.8" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">●</text><text class="terminal-r9" x="427" y="776.4" textLength="122" clip-path="url(#terminal-line-31)"> connected</text><text class="terminal-r5" x="1451.8" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">│</text><text class="terminal-r1" x="1464" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">
|
||||
</text><text class="terminal-r5" x="0" y="800.8" textLength="12.2" clip-path="url(#terminal-line-32)">│</text><text class="terminal-r5" x="1451.8" y="800.8" textLength="12.2" clip-path="url(#terminal-line-32)">│</text><text class="terminal-r1" x="1464" y="800.8" textLength="12.2" clip-path="url(#terminal-line-32)">
|
||||
</text><text class="terminal-r5" x="0" y="825.2" textLength="12.2" clip-path="url(#terminal-line-33)">│</text><text class="terminal-r5" x="24.4" y="825.2" textLength="488" clip-path="url(#terminal-line-33)">↑↓ Navigate  Enter Show tools  Esc Close</text><text class="terminal-r5" x="1451.8" y="825.2" textLength="12.2" clip-path="url(#terminal-line-33)">│</text><text class="terminal-r1" x="1464" y="825.2" textLength="12.2" clip-path="url(#terminal-line-33)">
|
||||
</text><text class="terminal-r5" x="0" y="849.6" textLength="1464" clip-path="url(#terminal-line-34)">└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘</text><text class="terminal-r1" x="1464" y="849.6" textLength="12.2" clip-path="url(#terminal-line-34)">
|
||||
</text><text class="terminal-r5" x="0" y="874" textLength="158.6" clip-path="url(#terminal-line-35)">/test/workdir</text><text class="terminal-r5" x="1256.6" y="874" textLength="207.4" clip-path="url(#terminal-line-35)">0% of 200k tokens</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 18 KiB |
|
|
@ -0,0 +1,207 @@
|
|||
<svg class="rich-terminal" viewBox="0 0 1482 928.4" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Generated with Rich https://www.textualize.io -->
|
||||
<style>
|
||||
|
||||
@font-face {
|
||||
font-family: "Fira Code";
|
||||
src: local("FiraCode-Regular"),
|
||||
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Regular.woff2") format("woff2"),
|
||||
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Regular.woff") format("woff");
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Fira Code";
|
||||
src: local("FiraCode-Bold"),
|
||||
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Bold.woff2") format("woff2"),
|
||||
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Bold.woff") format("woff");
|
||||
font-style: bold;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.terminal-matrix {
|
||||
font-family: Fira Code, monospace;
|
||||
font-size: 20px;
|
||||
line-height: 24.4px;
|
||||
font-variant-east-asian: full-width;
|
||||
}
|
||||
|
||||
.terminal-title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
font-family: arial;
|
||||
}
|
||||
|
||||
.terminal-r1 { fill: #c5c8c6 }
|
||||
.terminal-r2 { fill: #ff8205;font-weight: bold }
|
||||
.terminal-r3 { fill: #68a0b3 }
|
||||
.terminal-r4 { fill: #ff8205 }
|
||||
.terminal-r5 { fill: #9a9b99 }
|
||||
.terminal-r6 { fill: #608ab1;font-weight: bold }
|
||||
.terminal-r7 { fill: #c5c8c6;font-weight: bold }
|
||||
.terminal-r8 { fill: #9cafbd;font-weight: bold }
|
||||
.terminal-r9 { fill: #98a84b;font-weight: bold }
|
||||
.terminal-r10 { fill: #868887 }
|
||||
.terminal-r11 { fill: #98a84b }
|
||||
</style>
|
||||
|
||||
<defs>
|
||||
<clipPath id="terminal-clip-terminal">
|
||||
<rect x="0" y="0" width="1463.0" height="877.4" />
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-0">
|
||||
<rect x="0" y="1.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-1">
|
||||
<rect x="0" y="25.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-2">
|
||||
<rect x="0" y="50.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-3">
|
||||
<rect x="0" y="74.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-4">
|
||||
<rect x="0" y="99.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-5">
|
||||
<rect x="0" y="123.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-6">
|
||||
<rect x="0" y="147.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-7">
|
||||
<rect x="0" y="172.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-8">
|
||||
<rect x="0" y="196.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-9">
|
||||
<rect x="0" y="221.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-10">
|
||||
<rect x="0" y="245.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-11">
|
||||
<rect x="0" y="269.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-12">
|
||||
<rect x="0" y="294.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-13">
|
||||
<rect x="0" y="318.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-14">
|
||||
<rect x="0" y="343.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-15">
|
||||
<rect x="0" y="367.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-16">
|
||||
<rect x="0" y="391.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-17">
|
||||
<rect x="0" y="416.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-18">
|
||||
<rect x="0" y="440.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-19">
|
||||
<rect x="0" y="465.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-20">
|
||||
<rect x="0" y="489.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-21">
|
||||
<rect x="0" y="513.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-22">
|
||||
<rect x="0" y="538.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-23">
|
||||
<rect x="0" y="562.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-24">
|
||||
<rect x="0" y="587.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-25">
|
||||
<rect x="0" y="611.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-26">
|
||||
<rect x="0" y="635.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-27">
|
||||
<rect x="0" y="660.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-28">
|
||||
<rect x="0" y="684.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-29">
|
||||
<rect x="0" y="709.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-30">
|
||||
<rect x="0" y="733.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-31">
|
||||
<rect x="0" y="757.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-32">
|
||||
<rect x="0" y="782.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-33">
|
||||
<rect x="0" y="806.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-34">
|
||||
<rect x="0" y="831.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
|
||||
<rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" x="1" y="1" width="1480" height="926.4" rx="8"/><text class="terminal-title" fill="#c5c8c6" text-anchor="middle" x="740" y="27">SnapshotTestAppConnectorsOnly</text>
|
||||
<g transform="translate(26,22)">
|
||||
<circle cx="0" cy="0" r="7" fill="#ff5f57"/>
|
||||
<circle cx="22" cy="0" r="7" fill="#febc2e"/>
|
||||
<circle cx="44" cy="0" r="7" fill="#28c840"/>
|
||||
</g>
|
||||
|
||||
<g transform="translate(9, 41)" clip-path="url(#terminal-clip-terminal)">
|
||||
<rect fill="#608ab1" x="36.6" y="733.5" width="85.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="122" y="733.5" width="158.6" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="280.6" y="733.5" width="109.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="390.4" y="733.5" width="24.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="414.8" y="733.5" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="427" y="733.5" width="122" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="549" y="733.5" width="878.4" height="24.65" shape-rendering="crispEdges"/>
|
||||
<g class="terminal-matrix">
|
||||
<text class="terminal-r1" x="1464" y="20" textLength="12.2" clip-path="url(#terminal-line-0)">
|
||||
</text><text class="terminal-r1" x="1464" y="44.4" textLength="12.2" clip-path="url(#terminal-line-1)">
|
||||
</text><text class="terminal-r1" x="1464" y="68.8" textLength="12.2" clip-path="url(#terminal-line-2)">
|
||||
</text><text class="terminal-r1" x="1464" y="93.2" textLength="12.2" clip-path="url(#terminal-line-3)">
|
||||
</text><text class="terminal-r1" x="1464" y="117.6" textLength="12.2" clip-path="url(#terminal-line-4)">
|
||||
</text><text class="terminal-r1" x="1464" y="142" textLength="12.2" clip-path="url(#terminal-line-5)">
|
||||
</text><text class="terminal-r1" x="1464" y="166.4" textLength="12.2" clip-path="url(#terminal-line-6)">
|
||||
</text><text class="terminal-r1" x="1464" y="190.8" textLength="12.2" clip-path="url(#terminal-line-7)">
|
||||
</text><text class="terminal-r1" x="1464" y="215.2" textLength="12.2" clip-path="url(#terminal-line-8)">
|
||||
</text><text class="terminal-r1" x="1464" y="239.6" textLength="12.2" clip-path="url(#terminal-line-9)">
|
||||
</text><text class="terminal-r1" x="1464" y="264" textLength="12.2" clip-path="url(#terminal-line-10)">
|
||||
</text><text class="terminal-r1" x="1464" y="288.4" textLength="12.2" clip-path="url(#terminal-line-11)">
|
||||
</text><text class="terminal-r1" x="1464" y="312.8" textLength="12.2" clip-path="url(#terminal-line-12)">
|
||||
</text><text class="terminal-r1" x="1464" y="337.2" textLength="12.2" clip-path="url(#terminal-line-13)">
|
||||
</text><text class="terminal-r1" x="1464" y="361.6" textLength="12.2" clip-path="url(#terminal-line-14)">
|
||||
</text><text class="terminal-r1" x="1464" y="386" textLength="12.2" clip-path="url(#terminal-line-15)">
|
||||
</text><text class="terminal-r1" x="1464" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">
|
||||
</text><text class="terminal-r1" x="0" y="434.8" textLength="134.2" clip-path="url(#terminal-line-17)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="434.8" textLength="146.4" clip-path="url(#terminal-line-17)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="434.8" textLength="122" clip-path="url(#terminal-line-17)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="434.8" textLength="183" clip-path="url(#terminal-line-17)">devstral-latest</text><text class="terminal-r1" x="622.2" y="434.8" textLength="256.2" clip-path="url(#terminal-line-17)"> · [Subscription] Pro</text><text class="terminal-r1" x="1464" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">
|
||||
</text><text class="terminal-r1" x="0" y="459.2" textLength="134.2" clip-path="url(#terminal-line-18)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="459.2" textLength="597.8" clip-path="url(#terminal-line-18)">1 model · 2 connectors · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1464" y="459.2" textLength="12.2" clip-path="url(#terminal-line-18)">
|
||||
</text><text class="terminal-r1" x="0" y="483.6" textLength="134.2" clip-path="url(#terminal-line-19)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="483.6" textLength="61" clip-path="url(#terminal-line-19)">Type </text><text class="terminal-r3" x="231.8" y="483.6" textLength="61" clip-path="url(#terminal-line-19)">/help</text><text class="terminal-r1" x="292.8" y="483.6" textLength="256.2" clip-path="url(#terminal-line-19)"> for more information</text><text class="terminal-r1" x="1464" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">
|
||||
</text><text class="terminal-r1" x="1464" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r1" x="1464" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">
|
||||
</text><text class="terminal-r4" x="0" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">┃</text><text class="terminal-r2" x="24.4" y="556.8" textLength="48.8" clip-path="url(#terminal-line-22)">/mcp</text><text class="terminal-r1" x="1464" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">
|
||||
</text><text class="terminal-r5" x="24.4" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">⎣</text><text class="terminal-r1" x="48.8" y="581.2" textLength="256.2" clip-path="url(#terminal-line-23)">MCP servers opened...</text><text class="terminal-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r1" x="1464" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">
|
||||
</text><text class="terminal-r1" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r5" x="0" y="654.4" textLength="1464" clip-path="url(#terminal-line-26)">┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐</text><text class="terminal-r1" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</text><text class="terminal-r5" x="0" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">│</text><text class="terminal-r6" x="24.4" y="678.8" textLength="292.8" clip-path="url(#terminal-line-27)">MCP Servers & Connectors</text><text class="terminal-r5" x="1451.8" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">│</text><text class="terminal-r1" x="1464" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">
|
||||
</text><text class="terminal-r5" x="0" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">│</text><text class="terminal-r5" x="1451.8" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">│</text><text class="terminal-r1" x="1464" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">
|
||||
</text><text class="terminal-r5" x="0" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">│</text><text class="terminal-r7" x="36.6" y="727.6" textLength="244" clip-path="url(#terminal-line-29)">Workspace Connectors</text><text class="terminal-r5" x="1451.8" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">│</text><text class="terminal-r1" x="1464" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">
|
||||
</text><text class="terminal-r5" x="0" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">│</text><text class="terminal-r7" x="36.6" y="752" textLength="85.4" clip-path="url(#terminal-line-30)">  gmail</text><text class="terminal-r8" x="122" y="752" textLength="158.6" clip-path="url(#terminal-line-30)">  [connector]</text><text class="terminal-r8" x="280.6" y="752" textLength="109.8" clip-path="url(#terminal-line-30)">  3 tools</text><text class="terminal-r9" x="414.8" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">●</text><text class="terminal-r8" x="427" y="752" textLength="122" clip-path="url(#terminal-line-30)"> connected</text><text class="terminal-r5" x="1451.8" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">│</text><text class="terminal-r1" x="1464" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">
|
||||
</text><text class="terminal-r5" x="0" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">│</text><text class="terminal-r1" x="36.6" y="776.4" textLength="85.4" clip-path="url(#terminal-line-31)">  slack</text><text class="terminal-r10" x="122" y="776.4" textLength="158.6" clip-path="url(#terminal-line-31)">  [connector]</text><text class="terminal-r10" x="280.6" y="776.4" textLength="109.8" clip-path="url(#terminal-line-31)">  2 tools</text><text class="terminal-r11" x="414.8" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">●</text><text class="terminal-r10" x="427" y="776.4" textLength="122" clip-path="url(#terminal-line-31)"> connected</text><text class="terminal-r5" x="1451.8" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">│</text><text class="terminal-r1" x="1464" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">
|
||||
</text><text class="terminal-r5" x="0" y="800.8" textLength="12.2" clip-path="url(#terminal-line-32)">│</text><text class="terminal-r5" x="1451.8" y="800.8" textLength="12.2" clip-path="url(#terminal-line-32)">│</text><text class="terminal-r1" x="1464" y="800.8" textLength="12.2" clip-path="url(#terminal-line-32)">
|
||||
</text><text class="terminal-r5" x="0" y="825.2" textLength="12.2" clip-path="url(#terminal-line-33)">│</text><text class="terminal-r5" x="24.4" y="825.2" textLength="488" clip-path="url(#terminal-line-33)">↑↓ Navigate  Enter Show tools  Esc Close</text><text class="terminal-r5" x="1451.8" y="825.2" textLength="12.2" clip-path="url(#terminal-line-33)">│</text><text class="terminal-r1" x="1464" y="825.2" textLength="12.2" clip-path="url(#terminal-line-33)">
|
||||
</text><text class="terminal-r5" x="0" y="849.6" textLength="1464" clip-path="url(#terminal-line-34)">└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘</text><text class="terminal-r1" x="1464" y="849.6" textLength="12.2" clip-path="url(#terminal-line-34)">
|
||||
</text><text class="terminal-r5" x="0" y="874" textLength="158.6" clip-path="url(#terminal-line-35)">/test/workdir</text><text class="terminal-r5" x="1256.6" y="874" textLength="207.4" clip-path="url(#terminal-line-35)">0% of 200k tokens</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 17 KiB |
|
|
@ -0,0 +1,203 @@
|
|||
<svg class="rich-terminal" viewBox="0 0 1482 928.4" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Generated with Rich https://www.textualize.io -->
|
||||
<style>
|
||||
|
||||
@font-face {
|
||||
font-family: "Fira Code";
|
||||
src: local("FiraCode-Regular"),
|
||||
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Regular.woff2") format("woff2"),
|
||||
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Regular.woff") format("woff");
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Fira Code";
|
||||
src: local("FiraCode-Bold"),
|
||||
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Bold.woff2") format("woff2"),
|
||||
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Bold.woff") format("woff");
|
||||
font-style: bold;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.terminal-matrix {
|
||||
font-family: Fira Code, monospace;
|
||||
font-size: 20px;
|
||||
line-height: 24.4px;
|
||||
font-variant-east-asian: full-width;
|
||||
}
|
||||
|
||||
.terminal-title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
font-family: arial;
|
||||
}
|
||||
|
||||
.terminal-r1 { fill: #c5c8c6 }
|
||||
.terminal-r2 { fill: #ff8205;font-weight: bold }
|
||||
.terminal-r3 { fill: #68a0b3 }
|
||||
.terminal-r4 { fill: #ff8205 }
|
||||
.terminal-r5 { fill: #9a9b99 }
|
||||
.terminal-r6 { fill: #608ab1;font-weight: bold }
|
||||
.terminal-r7 { fill: #c5c8c6;font-weight: bold }
|
||||
</style>
|
||||
|
||||
<defs>
|
||||
<clipPath id="terminal-clip-terminal">
|
||||
<rect x="0" y="0" width="1463.0" height="877.4" />
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-0">
|
||||
<rect x="0" y="1.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-1">
|
||||
<rect x="0" y="25.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-2">
|
||||
<rect x="0" y="50.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-3">
|
||||
<rect x="0" y="74.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-4">
|
||||
<rect x="0" y="99.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-5">
|
||||
<rect x="0" y="123.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-6">
|
||||
<rect x="0" y="147.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-7">
|
||||
<rect x="0" y="172.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-8">
|
||||
<rect x="0" y="196.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-9">
|
||||
<rect x="0" y="221.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-10">
|
||||
<rect x="0" y="245.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-11">
|
||||
<rect x="0" y="269.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-12">
|
||||
<rect x="0" y="294.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-13">
|
||||
<rect x="0" y="318.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-14">
|
||||
<rect x="0" y="343.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-15">
|
||||
<rect x="0" y="367.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-16">
|
||||
<rect x="0" y="391.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-17">
|
||||
<rect x="0" y="416.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-18">
|
||||
<rect x="0" y="440.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-19">
|
||||
<rect x="0" y="465.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-20">
|
||||
<rect x="0" y="489.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-21">
|
||||
<rect x="0" y="513.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-22">
|
||||
<rect x="0" y="538.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-23">
|
||||
<rect x="0" y="562.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-24">
|
||||
<rect x="0" y="587.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-25">
|
||||
<rect x="0" y="611.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-26">
|
||||
<rect x="0" y="635.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-27">
|
||||
<rect x="0" y="660.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-28">
|
||||
<rect x="0" y="684.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-29">
|
||||
<rect x="0" y="709.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-30">
|
||||
<rect x="0" y="733.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-31">
|
||||
<rect x="0" y="757.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-32">
|
||||
<rect x="0" y="782.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-33">
|
||||
<rect x="0" y="806.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-34">
|
||||
<rect x="0" y="831.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
|
||||
<rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" x="1" y="1" width="1480" height="926.4" rx="8"/><text class="terminal-title" fill="#c5c8c6" text-anchor="middle" x="740" y="27">SnapshotTestAppWithConnectors</text>
|
||||
<g transform="translate(26,22)">
|
||||
<circle cx="0" cy="0" r="7" fill="#ff5f57"/>
|
||||
<circle cx="22" cy="0" r="7" fill="#febc2e"/>
|
||||
<circle cx="44" cy="0" r="7" fill="#28c840"/>
|
||||
</g>
|
||||
|
||||
<g transform="translate(9, 41)" clip-path="url(#terminal-clip-terminal)">
|
||||
<rect fill="#608ab1" x="36.6" y="733.5" width="183" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="219.6" y="733.5" width="317.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="536.8" y="733.5" width="890.6" height="24.65" shape-rendering="crispEdges"/>
|
||||
<g class="terminal-matrix">
|
||||
<text class="terminal-r1" x="1464" y="20" textLength="12.2" clip-path="url(#terminal-line-0)">
|
||||
</text><text class="terminal-r1" x="1464" y="44.4" textLength="12.2" clip-path="url(#terminal-line-1)">
|
||||
</text><text class="terminal-r1" x="1464" y="68.8" textLength="12.2" clip-path="url(#terminal-line-2)">
|
||||
</text><text class="terminal-r1" x="1464" y="93.2" textLength="12.2" clip-path="url(#terminal-line-3)">
|
||||
</text><text class="terminal-r1" x="1464" y="117.6" textLength="12.2" clip-path="url(#terminal-line-4)">
|
||||
</text><text class="terminal-r1" x="1464" y="142" textLength="12.2" clip-path="url(#terminal-line-5)">
|
||||
</text><text class="terminal-r1" x="1464" y="166.4" textLength="12.2" clip-path="url(#terminal-line-6)">
|
||||
</text><text class="terminal-r1" x="1464" y="190.8" textLength="12.2" clip-path="url(#terminal-line-7)">
|
||||
</text><text class="terminal-r1" x="1464" y="215.2" textLength="12.2" clip-path="url(#terminal-line-8)">
|
||||
</text><text class="terminal-r1" x="1464" y="239.6" textLength="12.2" clip-path="url(#terminal-line-9)">
|
||||
</text><text class="terminal-r1" x="1464" y="264" textLength="12.2" clip-path="url(#terminal-line-10)">
|
||||
</text><text class="terminal-r1" x="1464" y="288.4" textLength="12.2" clip-path="url(#terminal-line-11)">
|
||||
</text><text class="terminal-r1" x="1464" y="312.8" textLength="12.2" clip-path="url(#terminal-line-12)">
|
||||
</text><text class="terminal-r1" x="1464" y="337.2" textLength="12.2" clip-path="url(#terminal-line-13)">
|
||||
</text><text class="terminal-r1" x="1464" y="361.6" textLength="12.2" clip-path="url(#terminal-line-14)">
|
||||
</text><text class="terminal-r1" x="1464" y="386" textLength="12.2" clip-path="url(#terminal-line-15)">
|
||||
</text><text class="terminal-r1" x="1464" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">
|
||||
</text><text class="terminal-r1" x="1464" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">
|
||||
</text><text class="terminal-r1" x="0" y="459.2" textLength="134.2" clip-path="url(#terminal-line-18)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="459.2" textLength="146.4" clip-path="url(#terminal-line-18)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="459.2" textLength="122" clip-path="url(#terminal-line-18)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="459.2" textLength="183" clip-path="url(#terminal-line-18)">devstral-latest</text><text class="terminal-r1" x="622.2" y="459.2" textLength="256.2" clip-path="url(#terminal-line-18)"> · [Subscription] Pro</text><text class="terminal-r1" x="1464" y="459.2" textLength="12.2" clip-path="url(#terminal-line-18)">
|
||||
</text><text class="terminal-r1" x="0" y="483.6" textLength="134.2" clip-path="url(#terminal-line-19)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="483.6" textLength="585.6" clip-path="url(#terminal-line-19)">1 model · 2 connectors · 1 MCP server · 0 skills</text><text class="terminal-r1" x="1464" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">
|
||||
</text><text class="terminal-r1" x="0" y="508" textLength="134.2" clip-path="url(#terminal-line-20)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="508" textLength="61" clip-path="url(#terminal-line-20)">Type </text><text class="terminal-r3" x="231.8" y="508" textLength="61" clip-path="url(#terminal-line-20)">/help</text><text class="terminal-r1" x="292.8" y="508" textLength="256.2" clip-path="url(#terminal-line-20)"> for more information</text><text class="terminal-r1" x="1464" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r1" x="1464" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">
|
||||
</text><text class="terminal-r1" x="1464" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">
|
||||
</text><text class="terminal-r4" x="0" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">┃</text><text class="terminal-r2" x="24.4" y="581.2" textLength="48.8" clip-path="url(#terminal-line-23)">/mcp</text><text class="terminal-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r5" x="24.4" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">⎣</text><text class="terminal-r1" x="48.8" y="605.6" textLength="256.2" clip-path="url(#terminal-line-24)">MCP servers opened...</text><text class="terminal-r1" x="1464" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">
|
||||
</text><text class="terminal-r1" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r1" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</text><text class="terminal-r5" x="0" y="678.8" textLength="1464" clip-path="url(#terminal-line-27)">┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐</text><text class="terminal-r1" x="1464" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">
|
||||
</text><text class="terminal-r5" x="0" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">│</text><text class="terminal-r6" x="24.4" y="703.2" textLength="195.2" clip-path="url(#terminal-line-28)">Connector: slack</text><text class="terminal-r5" x="1451.8" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">│</text><text class="terminal-r1" x="1464" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">
|
||||
</text><text class="terminal-r5" x="0" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">│</text><text class="terminal-r5" x="1451.8" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">│</text><text class="terminal-r1" x="1464" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">
|
||||
</text><text class="terminal-r5" x="0" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">│</text><text class="terminal-r7" x="36.6" y="752" textLength="183" clip-path="url(#terminal-line-30)">search_messages</text><text class="terminal-r7" x="219.6" y="752" textLength="317.2" clip-path="url(#terminal-line-30)">  -  Search Slack messages</text><text class="terminal-r5" x="1451.8" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">│</text><text class="terminal-r1" x="1464" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">
|
||||
</text><text class="terminal-r5" x="0" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">│</text><text class="terminal-r7" x="36.6" y="776.4" textLength="146.4" clip-path="url(#terminal-line-31)">send_message</text><text class="terminal-r1" x="183" y="776.4" textLength="305" clip-path="url(#terminal-line-31)">  -  Send a Slack message</text><text class="terminal-r5" x="1451.8" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">│</text><text class="terminal-r1" x="1464" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">
|
||||
</text><text class="terminal-r5" x="0" y="800.8" textLength="12.2" clip-path="url(#terminal-line-32)">│</text><text class="terminal-r5" x="1451.8" y="800.8" textLength="12.2" clip-path="url(#terminal-line-32)">│</text><text class="terminal-r1" x="1464" y="800.8" textLength="12.2" clip-path="url(#terminal-line-32)">
|
||||
</text><text class="terminal-r5" x="0" y="825.2" textLength="12.2" clip-path="url(#terminal-line-33)">│</text><text class="terminal-r5" x="24.4" y="825.2" textLength="463.6" clip-path="url(#terminal-line-33)">↑↓ Navigate  Backspace Back  Esc Close</text><text class="terminal-r5" x="1451.8" y="825.2" textLength="12.2" clip-path="url(#terminal-line-33)">│</text><text class="terminal-r1" x="1464" y="825.2" textLength="12.2" clip-path="url(#terminal-line-33)">
|
||||
</text><text class="terminal-r5" x="0" y="849.6" textLength="1464" clip-path="url(#terminal-line-34)">└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘</text><text class="terminal-r1" x="1464" y="849.6" textLength="12.2" clip-path="url(#terminal-line-34)">
|
||||
</text><text class="terminal-r5" x="0" y="874" textLength="158.6" clip-path="url(#terminal-line-35)">/test/workdir</text><text class="terminal-r5" x="1256.6" y="874" textLength="207.4" clip-path="url(#terminal-line-35)">0% of 200k tokens</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 15 KiB |
|
|
@ -39,6 +39,8 @@
|
|||
.terminal-r5 { fill: #9a9b99 }
|
||||
.terminal-r6 { fill: #608ab1;font-weight: bold }
|
||||
.terminal-r7 { fill: #c5c8c6;font-weight: bold }
|
||||
.terminal-r8 { fill: #9cafbd;font-weight: bold }
|
||||
.terminal-r9 { fill: #868887 }
|
||||
</style>
|
||||
|
||||
<defs>
|
||||
|
|
@ -160,7 +162,7 @@
|
|||
</g>
|
||||
|
||||
<g transform="translate(9, 41)" clip-path="url(#terminal-clip-terminal)">
|
||||
<rect fill="#608ab1" x="36.6" y="733.5" width="427" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="463.6" y="733.5" width="963.8" height="24.65" shape-rendering="crispEdges"/>
|
||||
<rect fill="#608ab1" x="36.6" y="733.5" width="146.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="183" y="733.5" width="109.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="292.8" y="733.5" width="97.6" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="390.4" y="733.5" width="1037" height="24.65" shape-rendering="crispEdges"/>
|
||||
<g class="terminal-matrix">
|
||||
<text class="terminal-r1" x="1464" y="20" textLength="12.2" clip-path="url(#terminal-line-0)">
|
||||
</text><text class="terminal-r1" x="1464" y="44.4" textLength="12.2" clip-path="url(#terminal-line-1)">
|
||||
|
|
@ -179,21 +181,21 @@
|
|||
</text><text class="terminal-r1" x="1464" y="361.6" textLength="12.2" clip-path="url(#terminal-line-14)">
|
||||
</text><text class="terminal-r1" x="1464" y="386" textLength="12.2" clip-path="url(#terminal-line-15)">
|
||||
</text><text class="terminal-r1" x="1464" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">
|
||||
</text><text class="terminal-r1" x="1464" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">
|
||||
</text><text class="terminal-r1" x="0" y="459.2" textLength="134.2" clip-path="url(#terminal-line-18)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="459.2" textLength="146.4" clip-path="url(#terminal-line-18)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="459.2" textLength="122" clip-path="url(#terminal-line-18)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="459.2" textLength="183" clip-path="url(#terminal-line-18)">devstral-latest</text><text class="terminal-r1" x="622.2" y="459.2" textLength="256.2" clip-path="url(#terminal-line-18)"> · [Subscription] Pro</text><text class="terminal-r1" x="1464" y="459.2" textLength="12.2" clip-path="url(#terminal-line-18)">
|
||||
</text><text class="terminal-r1" x="0" y="483.6" textLength="134.2" clip-path="url(#terminal-line-19)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="483.6" textLength="414.8" clip-path="url(#terminal-line-19)">1 model · 2 MCP servers · 0 skills</text><text class="terminal-r1" x="1464" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">
|
||||
</text><text class="terminal-r1" x="0" y="508" textLength="134.2" clip-path="url(#terminal-line-20)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="508" textLength="61" clip-path="url(#terminal-line-20)">Type </text><text class="terminal-r3" x="231.8" y="508" textLength="61" clip-path="url(#terminal-line-20)">/help</text><text class="terminal-r1" x="292.8" y="508" textLength="256.2" clip-path="url(#terminal-line-20)"> for more information</text><text class="terminal-r1" x="1464" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r1" x="0" y="434.8" textLength="134.2" clip-path="url(#terminal-line-17)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="434.8" textLength="146.4" clip-path="url(#terminal-line-17)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="434.8" textLength="122" clip-path="url(#terminal-line-17)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="434.8" textLength="183" clip-path="url(#terminal-line-17)">devstral-latest</text><text class="terminal-r1" x="622.2" y="434.8" textLength="256.2" clip-path="url(#terminal-line-17)"> · [Subscription] Pro</text><text class="terminal-r1" x="1464" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">
|
||||
</text><text class="terminal-r1" x="0" y="459.2" textLength="134.2" clip-path="url(#terminal-line-18)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="459.2" textLength="414.8" clip-path="url(#terminal-line-18)">1 model · 2 MCP servers · 0 skills</text><text class="terminal-r1" x="1464" y="459.2" textLength="12.2" clip-path="url(#terminal-line-18)">
|
||||
</text><text class="terminal-r1" x="0" y="483.6" textLength="134.2" clip-path="url(#terminal-line-19)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="483.6" textLength="61" clip-path="url(#terminal-line-19)">Type </text><text class="terminal-r3" x="231.8" y="483.6" textLength="61" clip-path="url(#terminal-line-19)">/help</text><text class="terminal-r1" x="292.8" y="483.6" textLength="256.2" clip-path="url(#terminal-line-19)"> for more information</text><text class="terminal-r1" x="1464" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">
|
||||
</text><text class="terminal-r1" x="1464" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r1" x="1464" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">
|
||||
</text><text class="terminal-r1" x="1464" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">
|
||||
</text><text class="terminal-r4" x="0" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">┃</text><text class="terminal-r2" x="24.4" y="581.2" textLength="48.8" clip-path="url(#terminal-line-23)">/mcp</text><text class="terminal-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r5" x="24.4" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">⎣</text><text class="terminal-r1" x="48.8" y="605.6" textLength="256.2" clip-path="url(#terminal-line-24)">MCP servers opened...</text><text class="terminal-r1" x="1464" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">
|
||||
</text><text class="terminal-r4" x="0" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">┃</text><text class="terminal-r2" x="24.4" y="556.8" textLength="48.8" clip-path="url(#terminal-line-22)">/mcp</text><text class="terminal-r1" x="1464" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">
|
||||
</text><text class="terminal-r5" x="24.4" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">⎣</text><text class="terminal-r1" x="48.8" y="581.2" textLength="256.2" clip-path="url(#terminal-line-23)">MCP servers opened...</text><text class="terminal-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r1" x="1464" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">
|
||||
</text><text class="terminal-r1" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r1" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</text><text class="terminal-r5" x="0" y="678.8" textLength="1464" clip-path="url(#terminal-line-27)">┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐</text><text class="terminal-r1" x="1464" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">
|
||||
</text><text class="terminal-r5" x="0" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">│</text><text class="terminal-r6" x="24.4" y="703.2" textLength="134.2" clip-path="url(#terminal-line-28)">MCP Servers</text><text class="terminal-r5" x="1451.8" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">│</text><text class="terminal-r1" x="1464" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">
|
||||
</text><text class="terminal-r5" x="0" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">│</text><text class="terminal-r5" x="1451.8" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">│</text><text class="terminal-r1" x="1464" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">
|
||||
</text><text class="terminal-r5" x="0" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">│</text><text class="terminal-r7" x="36.6" y="752" textLength="427" clip-path="url(#terminal-line-30)">filesystem  [stdio]  1 tool enabled</text><text class="terminal-r5" x="1451.8" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">│</text><text class="terminal-r1" x="1464" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">
|
||||
</text><text class="terminal-r5" x="0" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">│</text><text class="terminal-r1" x="36.6" y="776.4" textLength="366" clip-path="url(#terminal-line-31)">search  [http]  1 tool enabled</text><text class="terminal-r5" x="1451.8" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">│</text><text class="terminal-r1" x="1464" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">
|
||||
</text><text class="terminal-r5" x="0" y="654.4" textLength="1464" clip-path="url(#terminal-line-26)">┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐</text><text class="terminal-r1" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</text><text class="terminal-r5" x="0" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">│</text><text class="terminal-r6" x="24.4" y="678.8" textLength="134.2" clip-path="url(#terminal-line-27)">MCP Servers</text><text class="terminal-r5" x="1451.8" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">│</text><text class="terminal-r1" x="1464" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">
|
||||
</text><text class="terminal-r5" x="0" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">│</text><text class="terminal-r5" x="1451.8" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">│</text><text class="terminal-r1" x="1464" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">
|
||||
</text><text class="terminal-r5" x="0" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">│</text><text class="terminal-r7" x="36.6" y="727.6" textLength="207.4" clip-path="url(#terminal-line-29)">Local MCP Servers</text><text class="terminal-r5" x="1451.8" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">│</text><text class="terminal-r1" x="1464" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">
|
||||
</text><text class="terminal-r5" x="0" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">│</text><text class="terminal-r7" x="36.6" y="752" textLength="146.4" clip-path="url(#terminal-line-30)">  filesystem</text><text class="terminal-r8" x="183" y="752" textLength="109.8" clip-path="url(#terminal-line-30)">  [stdio]</text><text class="terminal-r8" x="292.8" y="752" textLength="97.6" clip-path="url(#terminal-line-30)">  1 tool</text><text class="terminal-r5" x="1451.8" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">│</text><text class="terminal-r1" x="1464" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">
|
||||
</text><text class="terminal-r5" x="0" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">│</text><text class="terminal-r1" x="36.6" y="776.4" textLength="146.4" clip-path="url(#terminal-line-31)">  search    </text><text class="terminal-r9" x="183" y="776.4" textLength="109.8" clip-path="url(#terminal-line-31)">  [http] </text><text class="terminal-r9" x="292.8" y="776.4" textLength="97.6" clip-path="url(#terminal-line-31)">  1 tool</text><text class="terminal-r5" x="1451.8" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">│</text><text class="terminal-r1" x="1464" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">
|
||||
</text><text class="terminal-r5" x="0" y="800.8" textLength="12.2" clip-path="url(#terminal-line-32)">│</text><text class="terminal-r5" x="1451.8" y="800.8" textLength="12.2" clip-path="url(#terminal-line-32)">│</text><text class="terminal-r1" x="1464" y="800.8" textLength="12.2" clip-path="url(#terminal-line-32)">
|
||||
</text><text class="terminal-r5" x="0" y="825.2" textLength="12.2" clip-path="url(#terminal-line-33)">│</text><text class="terminal-r5" x="24.4" y="825.2" textLength="488" clip-path="url(#terminal-line-33)">↑↓ Navigate  Enter Show tools  Esc Close</text><text class="terminal-r5" x="1451.8" y="825.2" textLength="12.2" clip-path="url(#terminal-line-33)">│</text><text class="terminal-r1" x="1464" y="825.2" textLength="12.2" clip-path="url(#terminal-line-33)">
|
||||
</text><text class="terminal-r5" x="0" y="849.6" textLength="1464" clip-path="url(#terminal-line-34)">└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘</text><text class="terminal-r1" x="1464" y="849.6" textLength="12.2" clip-path="url(#terminal-line-34)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 16 KiB |
|
|
@ -39,6 +39,8 @@
|
|||
.terminal-r5 { fill: #9a9b99 }
|
||||
.terminal-r6 { fill: #608ab1;font-weight: bold }
|
||||
.terminal-r7 { fill: #c5c8c6;font-weight: bold }
|
||||
.terminal-r8 { fill: #868887 }
|
||||
.terminal-r9 { fill: #9cafbd;font-weight: bold }
|
||||
</style>
|
||||
|
||||
<defs>
|
||||
|
|
@ -160,7 +162,7 @@
|
|||
</g>
|
||||
|
||||
<g transform="translate(9, 41)" clip-path="url(#terminal-clip-terminal)">
|
||||
<rect fill="#608ab1" x="36.6" y="757.9" width="366" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="402.6" y="757.9" width="1024.8" height="24.65" shape-rendering="crispEdges"/>
|
||||
<rect fill="#608ab1" x="36.6" y="757.9" width="146.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="183" y="757.9" width="109.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="292.8" y="757.9" width="97.6" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="390.4" y="757.9" width="1037" height="24.65" shape-rendering="crispEdges"/>
|
||||
<g class="terminal-matrix">
|
||||
<text class="terminal-r1" x="1464" y="20" textLength="12.2" clip-path="url(#terminal-line-0)">
|
||||
</text><text class="terminal-r1" x="1464" y="44.4" textLength="12.2" clip-path="url(#terminal-line-1)">
|
||||
|
|
@ -179,21 +181,21 @@
|
|||
</text><text class="terminal-r1" x="1464" y="361.6" textLength="12.2" clip-path="url(#terminal-line-14)">
|
||||
</text><text class="terminal-r1" x="1464" y="386" textLength="12.2" clip-path="url(#terminal-line-15)">
|
||||
</text><text class="terminal-r1" x="1464" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">
|
||||
</text><text class="terminal-r1" x="1464" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">
|
||||
</text><text class="terminal-r1" x="0" y="459.2" textLength="134.2" clip-path="url(#terminal-line-18)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="459.2" textLength="146.4" clip-path="url(#terminal-line-18)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="459.2" textLength="122" clip-path="url(#terminal-line-18)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="459.2" textLength="183" clip-path="url(#terminal-line-18)">devstral-latest</text><text class="terminal-r1" x="622.2" y="459.2" textLength="256.2" clip-path="url(#terminal-line-18)"> · [Subscription] Pro</text><text class="terminal-r1" x="1464" y="459.2" textLength="12.2" clip-path="url(#terminal-line-18)">
|
||||
</text><text class="terminal-r1" x="0" y="483.6" textLength="134.2" clip-path="url(#terminal-line-19)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="483.6" textLength="414.8" clip-path="url(#terminal-line-19)">1 model · 2 MCP servers · 0 skills</text><text class="terminal-r1" x="1464" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">
|
||||
</text><text class="terminal-r1" x="0" y="508" textLength="134.2" clip-path="url(#terminal-line-20)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="508" textLength="61" clip-path="url(#terminal-line-20)">Type </text><text class="terminal-r3" x="231.8" y="508" textLength="61" clip-path="url(#terminal-line-20)">/help</text><text class="terminal-r1" x="292.8" y="508" textLength="256.2" clip-path="url(#terminal-line-20)"> for more information</text><text class="terminal-r1" x="1464" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r1" x="0" y="434.8" textLength="134.2" clip-path="url(#terminal-line-17)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="434.8" textLength="146.4" clip-path="url(#terminal-line-17)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="434.8" textLength="122" clip-path="url(#terminal-line-17)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="434.8" textLength="183" clip-path="url(#terminal-line-17)">devstral-latest</text><text class="terminal-r1" x="622.2" y="434.8" textLength="256.2" clip-path="url(#terminal-line-17)"> · [Subscription] Pro</text><text class="terminal-r1" x="1464" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">
|
||||
</text><text class="terminal-r1" x="0" y="459.2" textLength="134.2" clip-path="url(#terminal-line-18)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="459.2" textLength="414.8" clip-path="url(#terminal-line-18)">1 model · 2 MCP servers · 0 skills</text><text class="terminal-r1" x="1464" y="459.2" textLength="12.2" clip-path="url(#terminal-line-18)">
|
||||
</text><text class="terminal-r1" x="0" y="483.6" textLength="134.2" clip-path="url(#terminal-line-19)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="483.6" textLength="61" clip-path="url(#terminal-line-19)">Type </text><text class="terminal-r3" x="231.8" y="483.6" textLength="61" clip-path="url(#terminal-line-19)">/help</text><text class="terminal-r1" x="292.8" y="483.6" textLength="256.2" clip-path="url(#terminal-line-19)"> for more information</text><text class="terminal-r1" x="1464" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">
|
||||
</text><text class="terminal-r1" x="1464" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r1" x="1464" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">
|
||||
</text><text class="terminal-r1" x="1464" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">
|
||||
</text><text class="terminal-r4" x="0" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">┃</text><text class="terminal-r2" x="24.4" y="581.2" textLength="48.8" clip-path="url(#terminal-line-23)">/mcp</text><text class="terminal-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r5" x="24.4" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">⎣</text><text class="terminal-r1" x="48.8" y="605.6" textLength="256.2" clip-path="url(#terminal-line-24)">MCP servers opened...</text><text class="terminal-r1" x="1464" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">
|
||||
</text><text class="terminal-r4" x="0" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">┃</text><text class="terminal-r2" x="24.4" y="556.8" textLength="48.8" clip-path="url(#terminal-line-22)">/mcp</text><text class="terminal-r1" x="1464" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">
|
||||
</text><text class="terminal-r5" x="24.4" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">⎣</text><text class="terminal-r1" x="48.8" y="581.2" textLength="256.2" clip-path="url(#terminal-line-23)">MCP servers opened...</text><text class="terminal-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r1" x="1464" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">
|
||||
</text><text class="terminal-r1" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r1" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</text><text class="terminal-r5" x="0" y="678.8" textLength="1464" clip-path="url(#terminal-line-27)">┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐</text><text class="terminal-r1" x="1464" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">
|
||||
</text><text class="terminal-r5" x="0" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">│</text><text class="terminal-r6" x="24.4" y="703.2" textLength="134.2" clip-path="url(#terminal-line-28)">MCP Servers</text><text class="terminal-r5" x="1451.8" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">│</text><text class="terminal-r1" x="1464" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">
|
||||
</text><text class="terminal-r5" x="0" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">│</text><text class="terminal-r5" x="1451.8" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">│</text><text class="terminal-r1" x="1464" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">
|
||||
</text><text class="terminal-r5" x="0" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">│</text><text class="terminal-r1" x="36.6" y="752" textLength="427" clip-path="url(#terminal-line-30)">filesystem  [stdio]  1 tool enabled</text><text class="terminal-r5" x="1451.8" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">│</text><text class="terminal-r1" x="1464" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">
|
||||
</text><text class="terminal-r5" x="0" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">│</text><text class="terminal-r7" x="36.6" y="776.4" textLength="366" clip-path="url(#terminal-line-31)">search  [http]  1 tool enabled</text><text class="terminal-r5" x="1451.8" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">│</text><text class="terminal-r1" x="1464" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">
|
||||
</text><text class="terminal-r5" x="0" y="654.4" textLength="1464" clip-path="url(#terminal-line-26)">┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐</text><text class="terminal-r1" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</text><text class="terminal-r5" x="0" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">│</text><text class="terminal-r6" x="24.4" y="678.8" textLength="134.2" clip-path="url(#terminal-line-27)">MCP Servers</text><text class="terminal-r5" x="1451.8" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">│</text><text class="terminal-r1" x="1464" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">
|
||||
</text><text class="terminal-r5" x="0" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">│</text><text class="terminal-r5" x="1451.8" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">│</text><text class="terminal-r1" x="1464" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">
|
||||
</text><text class="terminal-r5" x="0" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">│</text><text class="terminal-r7" x="36.6" y="727.6" textLength="207.4" clip-path="url(#terminal-line-29)">Local MCP Servers</text><text class="terminal-r5" x="1451.8" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">│</text><text class="terminal-r1" x="1464" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">
|
||||
</text><text class="terminal-r5" x="0" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">│</text><text class="terminal-r1" x="36.6" y="752" textLength="146.4" clip-path="url(#terminal-line-30)">  filesystem</text><text class="terminal-r8" x="183" y="752" textLength="109.8" clip-path="url(#terminal-line-30)">  [stdio]</text><text class="terminal-r8" x="292.8" y="752" textLength="97.6" clip-path="url(#terminal-line-30)">  1 tool</text><text class="terminal-r5" x="1451.8" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">│</text><text class="terminal-r1" x="1464" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">
|
||||
</text><text class="terminal-r5" x="0" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">│</text><text class="terminal-r7" x="36.6" y="776.4" textLength="146.4" clip-path="url(#terminal-line-31)">  search    </text><text class="terminal-r9" x="183" y="776.4" textLength="109.8" clip-path="url(#terminal-line-31)">  [http] </text><text class="terminal-r9" x="292.8" y="776.4" textLength="97.6" clip-path="url(#terminal-line-31)">  1 tool</text><text class="terminal-r5" x="1451.8" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">│</text><text class="terminal-r1" x="1464" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">
|
||||
</text><text class="terminal-r5" x="0" y="800.8" textLength="12.2" clip-path="url(#terminal-line-32)">│</text><text class="terminal-r5" x="1451.8" y="800.8" textLength="12.2" clip-path="url(#terminal-line-32)">│</text><text class="terminal-r1" x="1464" y="800.8" textLength="12.2" clip-path="url(#terminal-line-32)">
|
||||
</text><text class="terminal-r5" x="0" y="825.2" textLength="12.2" clip-path="url(#terminal-line-33)">│</text><text class="terminal-r5" x="24.4" y="825.2" textLength="488" clip-path="url(#terminal-line-33)">↑↓ Navigate  Enter Show tools  Esc Close</text><text class="terminal-r5" x="1451.8" y="825.2" textLength="12.2" clip-path="url(#terminal-line-33)">│</text><text class="terminal-r1" x="1464" y="825.2" textLength="12.2" clip-path="url(#terminal-line-33)">
|
||||
</text><text class="terminal-r5" x="0" y="849.6" textLength="1464" clip-path="url(#terminal-line-34)">└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘</text><text class="terminal-r1" x="1464" y="849.6" textLength="12.2" clip-path="url(#terminal-line-34)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 16 KiB |
|
|
@ -0,0 +1,206 @@
|
|||
<svg class="rich-terminal" viewBox="0 0 1482 928.4" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Generated with Rich https://www.textualize.io -->
|
||||
<style>
|
||||
|
||||
@font-face {
|
||||
font-family: "Fira Code";
|
||||
src: local("FiraCode-Regular"),
|
||||
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Regular.woff2") format("woff2"),
|
||||
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Regular.woff") format("woff");
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Fira Code";
|
||||
src: local("FiraCode-Bold"),
|
||||
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Bold.woff2") format("woff2"),
|
||||
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Bold.woff") format("woff");
|
||||
font-style: bold;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.terminal-matrix {
|
||||
font-family: Fira Code, monospace;
|
||||
font-size: 20px;
|
||||
line-height: 24.4px;
|
||||
font-variant-east-asian: full-width;
|
||||
}
|
||||
|
||||
.terminal-title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
font-family: arial;
|
||||
}
|
||||
|
||||
.terminal-r1 { fill: #c5c8c6 }
|
||||
.terminal-r2 { fill: #ff8205;font-weight: bold }
|
||||
.terminal-r3 { fill: #68a0b3 }
|
||||
.terminal-r4 { fill: #ff8205 }
|
||||
.terminal-r5 { fill: #9a9b99 }
|
||||
.terminal-r6 { fill: #608ab1;font-weight: bold }
|
||||
.terminal-r7 { fill: #c5c8c6;font-weight: bold }
|
||||
.terminal-r8 { fill: #9cafbd;font-weight: bold }
|
||||
.terminal-r9 { fill: #868887 }
|
||||
.terminal-r10 { fill: #98a84b }
|
||||
</style>
|
||||
|
||||
<defs>
|
||||
<clipPath id="terminal-clip-terminal">
|
||||
<rect x="0" y="0" width="1463.0" height="877.4" />
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-0">
|
||||
<rect x="0" y="1.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-1">
|
||||
<rect x="0" y="25.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-2">
|
||||
<rect x="0" y="50.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-3">
|
||||
<rect x="0" y="74.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-4">
|
||||
<rect x="0" y="99.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-5">
|
||||
<rect x="0" y="123.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-6">
|
||||
<rect x="0" y="147.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-7">
|
||||
<rect x="0" y="172.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-8">
|
||||
<rect x="0" y="196.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-9">
|
||||
<rect x="0" y="221.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-10">
|
||||
<rect x="0" y="245.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-11">
|
||||
<rect x="0" y="269.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-12">
|
||||
<rect x="0" y="294.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-13">
|
||||
<rect x="0" y="318.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-14">
|
||||
<rect x="0" y="343.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-15">
|
||||
<rect x="0" y="367.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-16">
|
||||
<rect x="0" y="391.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-17">
|
||||
<rect x="0" y="416.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-18">
|
||||
<rect x="0" y="440.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-19">
|
||||
<rect x="0" y="465.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-20">
|
||||
<rect x="0" y="489.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-21">
|
||||
<rect x="0" y="513.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-22">
|
||||
<rect x="0" y="538.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-23">
|
||||
<rect x="0" y="562.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-24">
|
||||
<rect x="0" y="587.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-25">
|
||||
<rect x="0" y="611.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-26">
|
||||
<rect x="0" y="635.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-27">
|
||||
<rect x="0" y="660.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-28">
|
||||
<rect x="0" y="684.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-29">
|
||||
<rect x="0" y="709.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-30">
|
||||
<rect x="0" y="733.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-31">
|
||||
<rect x="0" y="757.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-32">
|
||||
<rect x="0" y="782.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-33">
|
||||
<rect x="0" y="806.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-34">
|
||||
<rect x="0" y="831.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
|
||||
<rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" x="1" y="1" width="1480" height="926.4" rx="8"/><text class="terminal-title" fill="#c5c8c6" text-anchor="middle" x="740" y="27">SnapshotTestAppWithConnectors</text>
|
||||
<g transform="translate(26,22)">
|
||||
<circle cx="0" cy="0" r="7" fill="#ff5f57"/>
|
||||
<circle cx="22" cy="0" r="7" fill="#febc2e"/>
|
||||
<circle cx="44" cy="0" r="7" fill="#28c840"/>
|
||||
</g>
|
||||
|
||||
<g transform="translate(9, 41)" clip-path="url(#terminal-clip-terminal)">
|
||||
<rect fill="#608ab1" x="36.6" y="660.3" width="146.4" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="183" y="660.3" width="109.8" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="292.8" y="660.3" width="97.6" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="390.4" y="660.3" width="1037" height="24.65" shape-rendering="crispEdges"/>
|
||||
<g class="terminal-matrix">
|
||||
<text class="terminal-r1" x="1464" y="20" textLength="12.2" clip-path="url(#terminal-line-0)">
|
||||
</text><text class="terminal-r1" x="1464" y="44.4" textLength="12.2" clip-path="url(#terminal-line-1)">
|
||||
</text><text class="terminal-r1" x="1464" y="68.8" textLength="12.2" clip-path="url(#terminal-line-2)">
|
||||
</text><text class="terminal-r1" x="1464" y="93.2" textLength="12.2" clip-path="url(#terminal-line-3)">
|
||||
</text><text class="terminal-r1" x="1464" y="117.6" textLength="12.2" clip-path="url(#terminal-line-4)">
|
||||
</text><text class="terminal-r1" x="1464" y="142" textLength="12.2" clip-path="url(#terminal-line-5)">
|
||||
</text><text class="terminal-r1" x="1464" y="166.4" textLength="12.2" clip-path="url(#terminal-line-6)">
|
||||
</text><text class="terminal-r1" x="1464" y="190.8" textLength="12.2" clip-path="url(#terminal-line-7)">
|
||||
</text><text class="terminal-r1" x="1464" y="215.2" textLength="12.2" clip-path="url(#terminal-line-8)">
|
||||
</text><text class="terminal-r1" x="1464" y="239.6" textLength="12.2" clip-path="url(#terminal-line-9)">
|
||||
</text><text class="terminal-r1" x="1464" y="264" textLength="12.2" clip-path="url(#terminal-line-10)">
|
||||
</text><text class="terminal-r1" x="1464" y="288.4" textLength="12.2" clip-path="url(#terminal-line-11)">
|
||||
</text><text class="terminal-r1" x="1464" y="312.8" textLength="12.2" clip-path="url(#terminal-line-12)">
|
||||
</text><text class="terminal-r1" x="1464" y="337.2" textLength="12.2" clip-path="url(#terminal-line-13)">
|
||||
</text><text class="terminal-r1" x="0" y="361.6" textLength="134.2" clip-path="url(#terminal-line-14)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="361.6" textLength="146.4" clip-path="url(#terminal-line-14)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="361.6" textLength="122" clip-path="url(#terminal-line-14)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="361.6" textLength="183" clip-path="url(#terminal-line-14)">devstral-latest</text><text class="terminal-r1" x="622.2" y="361.6" textLength="256.2" clip-path="url(#terminal-line-14)"> · [Subscription] Pro</text><text class="terminal-r1" x="1464" y="361.6" textLength="12.2" clip-path="url(#terminal-line-14)">
|
||||
</text><text class="terminal-r1" x="0" y="386" textLength="134.2" clip-path="url(#terminal-line-15)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="386" textLength="585.6" clip-path="url(#terminal-line-15)">1 model · 2 connectors · 1 MCP server · 0 skills</text><text class="terminal-r1" x="1464" y="386" textLength="12.2" clip-path="url(#terminal-line-15)">
|
||||
</text><text class="terminal-r1" x="0" y="410.4" textLength="134.2" clip-path="url(#terminal-line-16)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="410.4" textLength="61" clip-path="url(#terminal-line-16)">Type </text><text class="terminal-r3" x="231.8" y="410.4" textLength="61" clip-path="url(#terminal-line-16)">/help</text><text class="terminal-r1" x="292.8" y="410.4" textLength="256.2" clip-path="url(#terminal-line-16)"> for more information</text><text class="terminal-r1" x="1464" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">
|
||||
</text><text class="terminal-r1" x="1464" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">
|
||||
</text><text class="terminal-r1" x="1464" y="459.2" textLength="12.2" clip-path="url(#terminal-line-18)">
|
||||
</text><text class="terminal-r4" x="0" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">┃</text><text class="terminal-r2" x="24.4" y="483.6" textLength="48.8" clip-path="url(#terminal-line-19)">/mcp</text><text class="terminal-r1" x="1464" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">
|
||||
</text><text class="terminal-r5" x="24.4" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">⎣</text><text class="terminal-r1" x="48.8" y="508" textLength="256.2" clip-path="url(#terminal-line-20)">MCP servers opened...</text><text class="terminal-r1" x="1464" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r1" x="1464" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">
|
||||
</text><text class="terminal-r1" x="1464" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">
|
||||
</text><text class="terminal-r5" x="0" y="581.2" textLength="1464" clip-path="url(#terminal-line-23)">┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐</text><text class="terminal-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r5" x="0" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">│</text><text class="terminal-r6" x="24.4" y="605.6" textLength="292.8" clip-path="url(#terminal-line-24)">MCP Servers & Connectors</text><text class="terminal-r5" x="1451.8" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">│</text><text class="terminal-r1" x="1464" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">
|
||||
</text><text class="terminal-r5" x="0" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">│</text><text class="terminal-r5" x="1451.8" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">│</text><text class="terminal-r1" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r5" x="0" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">│</text><text class="terminal-r7" x="36.6" y="654.4" textLength="207.4" clip-path="url(#terminal-line-26)">Local MCP Servers</text><text class="terminal-r5" x="1451.8" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">│</text><text class="terminal-r1" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</text><text class="terminal-r5" x="0" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">│</text><text class="terminal-r7" x="36.6" y="678.8" textLength="146.4" clip-path="url(#terminal-line-27)">  filesystem</text><text class="terminal-r8" x="183" y="678.8" textLength="109.8" clip-path="url(#terminal-line-27)">  [stdio]</text><text class="terminal-r8" x="292.8" y="678.8" textLength="97.6" clip-path="url(#terminal-line-27)">  1 tool</text><text class="terminal-r5" x="1451.8" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">│</text><text class="terminal-r1" x="1464" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">
|
||||
</text><text class="terminal-r5" x="0" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">│</text><text class="terminal-r5" x="1451.8" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">│</text><text class="terminal-r1" x="1464" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">
|
||||
</text><text class="terminal-r5" x="0" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">│</text><text class="terminal-r7" x="36.6" y="727.6" textLength="244" clip-path="url(#terminal-line-29)">Workspace Connectors</text><text class="terminal-r5" x="1451.8" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">│</text><text class="terminal-r1" x="1464" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">
|
||||
</text><text class="terminal-r5" x="0" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">│</text><text class="terminal-r1" x="36.6" y="752" textLength="85.4" clip-path="url(#terminal-line-30)">  gmail</text><text class="terminal-r9" x="122" y="752" textLength="158.6" clip-path="url(#terminal-line-30)">  [connector]</text><text class="terminal-r9" x="280.6" y="752" textLength="109.8" clip-path="url(#terminal-line-30)">  3 tools</text><text class="terminal-r10" x="414.8" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">●</text><text class="terminal-r9" x="427" y="752" textLength="122" clip-path="url(#terminal-line-30)"> connected</text><text class="terminal-r5" x="1451.8" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">│</text><text class="terminal-r1" x="1464" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">
|
||||
</text><text class="terminal-r5" x="0" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">│</text><text class="terminal-r1" x="36.6" y="776.4" textLength="85.4" clip-path="url(#terminal-line-31)">  slack</text><text class="terminal-r9" x="122" y="776.4" textLength="158.6" clip-path="url(#terminal-line-31)">  [connector]</text><text class="terminal-r9" x="280.6" y="776.4" textLength="109.8" clip-path="url(#terminal-line-31)">  2 tools</text><text class="terminal-r10" x="414.8" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">●</text><text class="terminal-r9" x="427" y="776.4" textLength="122" clip-path="url(#terminal-line-31)"> connected</text><text class="terminal-r5" x="1451.8" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">│</text><text class="terminal-r1" x="1464" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">
|
||||
</text><text class="terminal-r5" x="0" y="800.8" textLength="12.2" clip-path="url(#terminal-line-32)">│</text><text class="terminal-r5" x="1451.8" y="800.8" textLength="12.2" clip-path="url(#terminal-line-32)">│</text><text class="terminal-r1" x="1464" y="800.8" textLength="12.2" clip-path="url(#terminal-line-32)">
|
||||
</text><text class="terminal-r5" x="0" y="825.2" textLength="12.2" clip-path="url(#terminal-line-33)">│</text><text class="terminal-r5" x="24.4" y="825.2" textLength="488" clip-path="url(#terminal-line-33)">↑↓ Navigate  Enter Show tools  Esc Close</text><text class="terminal-r5" x="1451.8" y="825.2" textLength="12.2" clip-path="url(#terminal-line-33)">│</text><text class="terminal-r1" x="1464" y="825.2" textLength="12.2" clip-path="url(#terminal-line-33)">
|
||||
</text><text class="terminal-r5" x="0" y="849.6" textLength="1464" clip-path="url(#terminal-line-34)">└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘</text><text class="terminal-r1" x="1464" y="849.6" textLength="12.2" clip-path="url(#terminal-line-34)">
|
||||
</text><text class="terminal-r5" x="0" y="874" textLength="158.6" clip-path="url(#terminal-line-35)">/test/workdir</text><text class="terminal-r5" x="1256.6" y="874" textLength="207.4" clip-path="url(#terminal-line-35)">0% of 200k tokens</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 18 KiB |
|
|
@ -0,0 +1,203 @@
|
|||
<svg class="rich-terminal" viewBox="0 0 1482 928.4" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Generated with Rich https://www.textualize.io -->
|
||||
<style>
|
||||
|
||||
@font-face {
|
||||
font-family: "Fira Code";
|
||||
src: local("FiraCode-Regular"),
|
||||
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Regular.woff2") format("woff2"),
|
||||
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Regular.woff") format("woff");
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Fira Code";
|
||||
src: local("FiraCode-Bold"),
|
||||
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Bold.woff2") format("woff2"),
|
||||
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Bold.woff") format("woff");
|
||||
font-style: bold;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.terminal-matrix {
|
||||
font-family: Fira Code, monospace;
|
||||
font-size: 20px;
|
||||
line-height: 24.4px;
|
||||
font-variant-east-asian: full-width;
|
||||
}
|
||||
|
||||
.terminal-title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
font-family: arial;
|
||||
}
|
||||
|
||||
.terminal-r1 { fill: #c5c8c6 }
|
||||
.terminal-r2 { fill: #ff8205;font-weight: bold }
|
||||
.terminal-r3 { fill: #68a0b3 }
|
||||
.terminal-r4 { fill: #ff8205 }
|
||||
.terminal-r5 { fill: #9a9b99;font-style: italic; }
|
||||
.terminal-r6 { fill: #d2d2d2 }
|
||||
.terminal-r7 { fill: #9a9b99 }
|
||||
</style>
|
||||
|
||||
<defs>
|
||||
<clipPath id="terminal-clip-terminal">
|
||||
<rect x="0" y="0" width="1463.0" height="877.4" />
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-0">
|
||||
<rect x="0" y="1.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-1">
|
||||
<rect x="0" y="25.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-2">
|
||||
<rect x="0" y="50.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-3">
|
||||
<rect x="0" y="74.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-4">
|
||||
<rect x="0" y="99.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-5">
|
||||
<rect x="0" y="123.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-6">
|
||||
<rect x="0" y="147.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-7">
|
||||
<rect x="0" y="172.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-8">
|
||||
<rect x="0" y="196.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-9">
|
||||
<rect x="0" y="221.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-10">
|
||||
<rect x="0" y="245.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-11">
|
||||
<rect x="0" y="269.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-12">
|
||||
<rect x="0" y="294.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-13">
|
||||
<rect x="0" y="318.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-14">
|
||||
<rect x="0" y="343.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-15">
|
||||
<rect x="0" y="367.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-16">
|
||||
<rect x="0" y="391.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-17">
|
||||
<rect x="0" y="416.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-18">
|
||||
<rect x="0" y="440.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-19">
|
||||
<rect x="0" y="465.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-20">
|
||||
<rect x="0" y="489.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-21">
|
||||
<rect x="0" y="513.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-22">
|
||||
<rect x="0" y="538.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-23">
|
||||
<rect x="0" y="562.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-24">
|
||||
<rect x="0" y="587.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-25">
|
||||
<rect x="0" y="611.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-26">
|
||||
<rect x="0" y="635.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-27">
|
||||
<rect x="0" y="660.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-28">
|
||||
<rect x="0" y="684.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-29">
|
||||
<rect x="0" y="709.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-30">
|
||||
<rect x="0" y="733.5" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-31">
|
||||
<rect x="0" y="757.9" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-32">
|
||||
<rect x="0" y="782.3" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-33">
|
||||
<rect x="0" y="806.7" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
<clipPath id="terminal-line-34">
|
||||
<rect x="0" y="831.1" width="1464" height="24.65"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
|
||||
<rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" x="1" y="1" width="1480" height="926.4" rx="8"/><text class="terminal-title" fill="#c5c8c6" text-anchor="middle" x="740" y="27">StreamingCodeFenceApp</text>
|
||||
<g transform="translate(26,22)">
|
||||
<circle cx="0" cy="0" r="7" fill="#ff5f57"/>
|
||||
<circle cx="22" cy="0" r="7" fill="#febc2e"/>
|
||||
<circle cx="44" cy="0" r="7" fill="#28c840"/>
|
||||
</g>
|
||||
|
||||
<g transform="translate(9, 41)" clip-path="url(#terminal-clip-terminal)">
|
||||
|
||||
<g class="terminal-matrix">
|
||||
<text class="terminal-r1" x="1464" y="20" textLength="12.2" clip-path="url(#terminal-line-0)">
|
||||
</text><text class="terminal-r1" x="1464" y="44.4" textLength="12.2" clip-path="url(#terminal-line-1)">
|
||||
</text><text class="terminal-r1" x="1464" y="68.8" textLength="12.2" clip-path="url(#terminal-line-2)">
|
||||
</text><text class="terminal-r1" x="1464" y="93.2" textLength="12.2" clip-path="url(#terminal-line-3)">
|
||||
</text><text class="terminal-r1" x="0" y="117.6" textLength="134.2" clip-path="url(#terminal-line-4)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="117.6" textLength="146.4" clip-path="url(#terminal-line-4)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="117.6" textLength="122" clip-path="url(#terminal-line-4)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="117.6" textLength="183" clip-path="url(#terminal-line-4)">devstral-latest</text><text class="terminal-r1" x="622.2" y="117.6" textLength="256.2" clip-path="url(#terminal-line-4)"> · [Subscription] Pro</text><text class="terminal-r1" x="1464" y="117.6" textLength="12.2" clip-path="url(#terminal-line-4)">
|
||||
</text><text class="terminal-r1" x="0" y="142" textLength="134.2" clip-path="url(#terminal-line-5)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="142" textLength="414.8" clip-path="url(#terminal-line-5)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1464" y="142" textLength="12.2" clip-path="url(#terminal-line-5)">
|
||||
</text><text class="terminal-r1" x="0" y="166.4" textLength="134.2" clip-path="url(#terminal-line-6)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="166.4" textLength="61" clip-path="url(#terminal-line-6)">Type </text><text class="terminal-r3" x="231.8" y="166.4" textLength="61" clip-path="url(#terminal-line-6)">/help</text><text class="terminal-r1" x="292.8" y="166.4" textLength="256.2" clip-path="url(#terminal-line-6)"> for more information</text><text class="terminal-r1" x="1464" y="166.4" textLength="12.2" clip-path="url(#terminal-line-6)">
|
||||
</text><text class="terminal-r1" x="1464" y="190.8" textLength="12.2" clip-path="url(#terminal-line-7)">
|
||||
</text><text class="terminal-r1" x="1464" y="215.2" textLength="12.2" clip-path="url(#terminal-line-8)">
|
||||
</text><text class="terminal-r4" x="0" y="239.6" textLength="12.2" clip-path="url(#terminal-line-9)">┃</text><text class="terminal-r2" x="24.4" y="239.6" textLength="146.4" clip-path="url(#terminal-line-9)">show diagram</text><text class="terminal-r1" x="1464" y="239.6" textLength="12.2" clip-path="url(#terminal-line-9)">
|
||||
</text><text class="terminal-r1" x="1464" y="264" textLength="12.2" clip-path="url(#terminal-line-10)">
|
||||
</text><text class="terminal-r5" x="0" y="288.4" textLength="97.6" clip-path="url(#terminal-line-11)">  Client</text><text class="terminal-r1" x="1464" y="288.4" textLength="12.2" clip-path="url(#terminal-line-11)">
|
||||
</text><text class="terminal-r5" x="0" y="312.8" textLength="61" clip-path="url(#terminal-line-12)">    |</text><text class="terminal-r1" x="1464" y="312.8" textLength="12.2" clip-path="url(#terminal-line-12)">
|
||||
</text><text class="terminal-r5" x="0" y="337.2" textLength="280.6" clip-path="url(#terminal-line-13)">    |  POST /api/orders</text><text class="terminal-r1" x="1464" y="337.2" textLength="12.2" clip-path="url(#terminal-line-13)">
|
||||
</text><text class="terminal-r5" x="0" y="361.6" textLength="61" clip-path="url(#terminal-line-14)">    v</text><text class="terminal-r1" x="1464" y="361.6" textLength="12.2" clip-path="url(#terminal-line-14)">
|
||||
</text><text class="terminal-r3" x="0" y="386" textLength="134.2" clip-path="url(#terminal-line-15)">+---------+</text><text class="terminal-r1" x="1464" y="386" textLength="12.2" clip-path="url(#terminal-line-15)">
|
||||
</text><text class="terminal-r5" x="0" y="410.4" textLength="134.2" clip-path="url(#terminal-line-16)">| Gateway |</text><text class="terminal-r1" x="1464" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">
|
||||
</text><text class="terminal-r3" x="0" y="434.8" textLength="134.2" clip-path="url(#terminal-line-17)">+---------+</text><text class="terminal-r1" x="1464" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">
|
||||
</text><text class="terminal-r5" x="0" y="459.2" textLength="61" clip-path="url(#terminal-line-18)">    |</text><text class="terminal-r1" x="1464" y="459.2" textLength="12.2" clip-path="url(#terminal-line-18)">
|
||||
</text><text class="terminal-r5" x="0" y="483.6" textLength="61" clip-path="url(#terminal-line-19)">    v</text><text class="terminal-r1" x="1464" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">
|
||||
</text><text class="terminal-r3" x="0" y="508" textLength="134.2" clip-path="url(#terminal-line-20)">+---------+</text><text class="terminal-r1" x="1464" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r5" x="0" y="532.4" textLength="134.2" clip-path="url(#terminal-line-21)">| Service |</text><text class="terminal-r1" x="1464" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">
|
||||
</text><text class="terminal-r3" x="0" y="556.8" textLength="134.2" clip-path="url(#terminal-line-22)">+---------+</text><text class="terminal-r1" x="1464" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">
|
||||
</text><text class="terminal-r5" x="0" y="581.2" textLength="61" clip-path="url(#terminal-line-23)">    |</text><text class="terminal-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r5" x="0" y="605.6" textLength="61" clip-path="url(#terminal-line-24)">    v</text><text class="terminal-r1" x="1464" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">
|
||||
</text><text class="terminal-r3" x="0" y="630" textLength="134.2" clip-path="url(#terminal-line-25)">+----+----+</text><text class="terminal-r1" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r5" x="0" y="654.4" textLength="134.2" clip-path="url(#terminal-line-26)">|   DB    |</text><text class="terminal-r1" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</text><text class="terminal-r3" x="0" y="678.8" textLength="134.2" clip-path="url(#terminal-line-27)">+---------+</text><text class="terminal-r1" x="1464" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">
|
||||
</text><text class="terminal-r1" x="1464" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">
|
||||
</text><text class="terminal-r1" x="1464" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">
|
||||
</text><text class="terminal-r7" x="0" y="752" textLength="1464" clip-path="url(#terminal-line-30)">┌──────────────────────────────────────────────────────────────────────────────────────────────────────────── default ─┐</text><text class="terminal-r1" x="1464" y="752" textLength="12.2" clip-path="url(#terminal-line-30)">
|
||||
</text><text class="terminal-r7" x="0" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">│</text><text class="terminal-r2" x="24.4" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">></text><text class="terminal-r7" x="1451.8" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">│</text><text class="terminal-r1" x="1464" y="776.4" textLength="12.2" clip-path="url(#terminal-line-31)">
|
||||
</text><text class="terminal-r7" x="0" y="800.8" textLength="12.2" clip-path="url(#terminal-line-32)">│</text><text class="terminal-r7" x="1451.8" y="800.8" textLength="12.2" clip-path="url(#terminal-line-32)">│</text><text class="terminal-r1" x="1464" y="800.8" textLength="12.2" clip-path="url(#terminal-line-32)">
|
||||
</text><text class="terminal-r7" x="0" y="825.2" textLength="12.2" clip-path="url(#terminal-line-33)">│</text><text class="terminal-r7" x="1451.8" y="825.2" textLength="12.2" clip-path="url(#terminal-line-33)">│</text><text class="terminal-r1" x="1464" y="825.2" textLength="12.2" clip-path="url(#terminal-line-33)">
|
||||
</text><text class="terminal-r7" x="0" y="849.6" textLength="1464" clip-path="url(#terminal-line-34)">└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘</text><text class="terminal-r1" x="1464" y="849.6" textLength="12.2" clip-path="url(#terminal-line-34)">
|
||||
</text><text class="terminal-r7" x="0" y="874" textLength="158.6" clip-path="url(#terminal-line-35)">/test/workdir</text><text class="terminal-r7" x="1256.6" y="874" textLength="207.4" clip-path="url(#terminal-line-35)">0% of 200k tokens</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 15 KiB |
|
|
@ -6,14 +6,29 @@ from textual.pilot import Pilot
|
|||
|
||||
from tests.snapshots.base_snapshot_test_app import BaseSnapshotTestApp, default_config
|
||||
from tests.snapshots.snap_compare import SnapCompare
|
||||
from tests.stubs.fake_connector_registry import FakeConnectorRegistry
|
||||
from tests.stubs.fake_mcp_registry import (
|
||||
FakeMCPRegistry,
|
||||
FakeMCPRegistryWithBrokenServer,
|
||||
)
|
||||
from vibe.core.config import MCPHttp, MCPStdio
|
||||
from vibe.core.tools.connectors import CONNECTORS_ENV_VAR
|
||||
from vibe.core.tools.mcp.tools import RemoteTool
|
||||
|
||||
_MCP_PATCH = "vibe.core.agent_loop.MCPRegistry"
|
||||
|
||||
_FAKE_CONNECTORS = {
|
||||
"gmail": [
|
||||
RemoteTool(name="gmail_search", description="Search emails in Gmail"),
|
||||
RemoteTool(name="gmail_draft_create", description="Draft an email in Gmail"),
|
||||
RemoteTool(name="gmail_open_message", description="Open a mail on Gmail"),
|
||||
],
|
||||
"slack": [
|
||||
RemoteTool(name="search_messages", description="Search Slack messages"),
|
||||
RemoteTool(name="send_message", description="Send a Slack message"),
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
class SnapshotTestAppNoMcpServers(BaseSnapshotTestApp):
|
||||
def __init__(self) -> None:
|
||||
|
|
@ -157,3 +172,105 @@ def test_snapshot_mcp_escape_closes(snap_compare: SnapCompare) -> None:
|
|||
terminal_size=(120, 36),
|
||||
run_before=run_before,
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Apps with connectors
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class SnapshotTestAppWithConnectors(BaseSnapshotTestApp):
|
||||
def __init__(self) -> None:
|
||||
config = default_config()
|
||||
config.mcp_servers = [
|
||||
MCPStdio(name="filesystem", transport="stdio", command="npx")
|
||||
]
|
||||
super().__init__(config=config)
|
||||
registry = FakeConnectorRegistry(connectors=_FAKE_CONNECTORS)
|
||||
self.agent_loop.connector_registry = registry
|
||||
self.agent_loop.tool_manager._connector_registry = registry
|
||||
self.agent_loop.tool_manager.integrate_connectors()
|
||||
|
||||
|
||||
class SnapshotTestAppConnectorsOnly(BaseSnapshotTestApp):
|
||||
def __init__(self) -> None:
|
||||
config = default_config()
|
||||
config.mcp_servers = []
|
||||
super().__init__(config=config)
|
||||
registry = FakeConnectorRegistry(connectors=_FAKE_CONNECTORS)
|
||||
self.agent_loop.connector_registry = registry
|
||||
self.agent_loop.tool_manager._connector_registry = registry
|
||||
self.agent_loop.tool_manager.integrate_connectors()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Connector snapshot tests
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@patch.dict("os.environ", {CONNECTORS_ENV_VAR: "1"})
|
||||
def test_snapshot_mcp_with_connectors_overview(snap_compare: SnapCompare) -> None:
|
||||
|
||||
async def run_before(pilot: Pilot) -> None:
|
||||
await _run_mcp_command(pilot, "/mcp")
|
||||
|
||||
with patch(_MCP_PATCH, FakeMCPRegistry):
|
||||
assert snap_compare(
|
||||
"test_ui_snapshot_mcp_command.py:SnapshotTestAppWithConnectors",
|
||||
terminal_size=(120, 36),
|
||||
run_before=run_before,
|
||||
)
|
||||
|
||||
|
||||
@patch.dict("os.environ", {CONNECTORS_ENV_VAR: "1"})
|
||||
def test_snapshot_mcp_connectors_only(snap_compare: SnapCompare) -> None:
|
||||
|
||||
async def run_before(pilot: Pilot) -> None:
|
||||
await _run_mcp_command(pilot, "/mcp")
|
||||
|
||||
assert snap_compare(
|
||||
"test_ui_snapshot_mcp_command.py:SnapshotTestAppConnectorsOnly",
|
||||
terminal_size=(120, 36),
|
||||
run_before=run_before,
|
||||
)
|
||||
|
||||
|
||||
@patch.dict("os.environ", {CONNECTORS_ENV_VAR: "1"})
|
||||
def test_snapshot_mcp_drill_into_connector(snap_compare: SnapCompare) -> None:
|
||||
|
||||
async def run_before(pilot: Pilot) -> None:
|
||||
await _run_mcp_command(pilot, "/mcp")
|
||||
# Navigate past the MCP server to the first connector
|
||||
await pilot.press("down") # skip filesystem server
|
||||
await pilot.pause(0.1)
|
||||
await pilot.press("down") # first connector
|
||||
await pilot.pause(0.1)
|
||||
await pilot.press("enter") # drill in
|
||||
await pilot.pause(0.1)
|
||||
|
||||
with patch(_MCP_PATCH, FakeMCPRegistry):
|
||||
assert snap_compare(
|
||||
"test_ui_snapshot_mcp_command.py:SnapshotTestAppWithConnectors",
|
||||
terminal_size=(120, 36),
|
||||
run_before=run_before,
|
||||
)
|
||||
|
||||
|
||||
@patch.dict("os.environ", {CONNECTORS_ENV_VAR: "1"})
|
||||
def test_snapshot_mcp_connector_back_to_overview(snap_compare: SnapCompare) -> None:
|
||||
|
||||
async def run_before(pilot: Pilot) -> None:
|
||||
await _run_mcp_command(pilot, "/mcp")
|
||||
await pilot.press("down", "down")
|
||||
await pilot.pause(0.1)
|
||||
await pilot.press("enter")
|
||||
await pilot.pause(0.1)
|
||||
await pilot.press("backspace")
|
||||
await pilot.pause(0.1)
|
||||
|
||||
with patch(_MCP_PATCH, FakeMCPRegistry):
|
||||
assert snap_compare(
|
||||
"test_ui_snapshot_mcp_command.py:SnapshotTestAppWithConnectors",
|
||||
terminal_size=(120, 36),
|
||||
run_before=run_before,
|
||||
)
|
||||
|
|
|
|||
61
tests/snapshots/test_ui_snapshot_streaming_code_fence.py
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
"""Regression test for streaming code-fenced ASCII art rendering.
|
||||
|
||||
Textual's Markdown.update() sets _last_parsed_line past fence openers,
|
||||
causing append() to re-parse without fence context and collapse content
|
||||
into paragraph text. This test streams a code-fenced diagram in small
|
||||
chunks and verifies the rendered output preserves the fence block.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from textual.pilot import Pilot
|
||||
|
||||
from tests.conftest import build_test_agent_loop
|
||||
from tests.mock.utils import mock_llm_chunk
|
||||
from tests.snapshots.base_snapshot_test_app import BaseSnapshotTestApp, default_config
|
||||
from tests.snapshots.snap_compare import SnapCompare
|
||||
from tests.stubs.fake_backend import FakeBackend
|
||||
|
||||
# Chunks are sized so the first one contains the fence opener (```)
|
||||
# plus content past the first newline — the exact pattern that triggers
|
||||
# the bug.
|
||||
_CHUNKS = [
|
||||
# First chunk: fence opener + content past newline (triggers the bug)
|
||||
"```\n Client\n |\n | POST",
|
||||
" /api/orders\n v\n+---------+\n| Gateway ",
|
||||
"|\n+---------+\n |\n v\n+---------+\n| Service ",
|
||||
"|\n+---------+\n |\n v\n+----+----+\n| DB ",
|
||||
"|\n+---------+\n```",
|
||||
]
|
||||
|
||||
|
||||
class StreamingCodeFenceApp(BaseSnapshotTestApp):
|
||||
def __init__(self) -> None:
|
||||
config = default_config()
|
||||
fake_backend = FakeBackend(
|
||||
chunks=[mock_llm_chunk(content=chunk) for chunk in _CHUNKS]
|
||||
)
|
||||
super().__init__(config=config)
|
||||
self.agent_loop = build_test_agent_loop(
|
||||
config=config,
|
||||
agent_name=self._current_agent_name,
|
||||
enable_streaming=True,
|
||||
backend=fake_backend,
|
||||
)
|
||||
|
||||
|
||||
def test_snapshot_streaming_code_fence_preserved(snap_compare: SnapCompare) -> None:
|
||||
"""Verify that a streamed code-fenced diagram renders as a code block,
|
||||
not as collapsed paragraph text.
|
||||
"""
|
||||
|
||||
async def run_before(pilot: Pilot) -> None:
|
||||
await pilot.press(*"show diagram")
|
||||
await pilot.press("enter")
|
||||
await pilot.pause(0.5)
|
||||
|
||||
assert snap_compare(
|
||||
"test_ui_snapshot_streaming_code_fence.py:StreamingCodeFenceApp",
|
||||
terminal_size=(120, 36),
|
||||
run_before=run_before,
|
||||
)
|
||||
46
tests/stubs/fake_connector_registry.py
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from vibe.core.tools.base import BaseTool
|
||||
from vibe.core.tools.connectors.connector_registry import (
|
||||
ConnectorRegistry,
|
||||
RemoteTool,
|
||||
_normalize_name,
|
||||
create_connector_proxy_tool_class,
|
||||
)
|
||||
|
||||
|
||||
class FakeConnectorRegistry(ConnectorRegistry):
|
||||
"""Test double that returns canned connector tools without hitting the API."""
|
||||
|
||||
def __init__(self, connectors: dict[str, list[RemoteTool]] | None = None) -> None:
|
||||
super().__init__(api_key="fake-key")
|
||||
self._fake_connectors = connectors or {}
|
||||
self._build_cache()
|
||||
|
||||
def _build_cache(self) -> None:
|
||||
self._cache = {}
|
||||
self._connector_names = []
|
||||
self._connector_connected = {}
|
||||
for connector_name, tools in self._fake_connectors.items():
|
||||
alias = _normalize_name(connector_name)
|
||||
connector_id = f"fake-id-{connector_name}"
|
||||
tool_map: dict[str, type[BaseTool]] = {}
|
||||
for remote in tools:
|
||||
proxy_cls = create_connector_proxy_tool_class(
|
||||
connector_name=connector_name,
|
||||
connector_alias=alias,
|
||||
connector_id=connector_id,
|
||||
remote=remote,
|
||||
api_key="fake-key",
|
||||
)
|
||||
tool_map[proxy_cls.get_name()] = proxy_cls
|
||||
self._cache[connector_id] = tool_map
|
||||
self._connector_names.append(alias)
|
||||
self._connector_connected[alias] = bool(tool_map)
|
||||
|
||||
def get_tools(self) -> dict[str, type[BaseTool]]:
|
||||
result: dict[str, type[BaseTool]] = {}
|
||||
if self._cache:
|
||||
for tools in self._cache.values():
|
||||
result.update(tools)
|
||||
return result
|
||||
|
|
@ -18,6 +18,11 @@ _BROKEN_SERVER_NAME = "broken-server"
|
|||
|
||||
|
||||
class FakeMCPRegistry(MCPRegistry):
|
||||
async def get_tools_async(
|
||||
self, servers: list[MCPServer]
|
||||
) -> dict[str, type[BaseTool]]:
|
||||
return self.get_tools(servers)
|
||||
|
||||
def get_tools(self, servers: list[MCPServer]) -> dict[str, type[BaseTool]]:
|
||||
result: dict[str, type[BaseTool]] = {}
|
||||
for srv in servers:
|
||||
|
|
|
|||
|
|
@ -131,6 +131,7 @@ async def test_passes_session_id_to_backend(vibe_config: VibeConfig):
|
|||
assert "message_id" in meta
|
||||
assert meta["is_user_prompt"] == "true"
|
||||
assert meta["call_type"] == "main_call"
|
||||
assert meta["call_source"] == "vibe_code"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -162,6 +163,7 @@ async def test_passes_entrypoint_metadata_to_backend(vibe_config: VibeConfig):
|
|||
assert "message_id" in meta
|
||||
assert meta["is_user_prompt"] == "true"
|
||||
assert meta["call_type"] == "main_call"
|
||||
assert meta["call_source"] == "vibe_code"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class TestCompleteInit:
|
|||
loop = build_test_agent_loop(defer_heavy_init=True)
|
||||
error = RuntimeError("mcp boom")
|
||||
|
||||
with patch.object(loop.tool_manager, "integrate_mcp", side_effect=error):
|
||||
with patch.object(loop.tool_manager, "integrate_all", side_effect=error):
|
||||
loop._complete_init()
|
||||
|
||||
assert loop.is_initialized
|
||||
|
|
@ -44,7 +44,7 @@ class TestCompleteInit:
|
|||
|
||||
with patch.object(
|
||||
loop.tool_manager._mcp_registry,
|
||||
"get_tools",
|
||||
"get_tools_async",
|
||||
side_effect=RuntimeError("mcp discovery boom"),
|
||||
):
|
||||
loop._complete_init()
|
||||
|
|
@ -84,7 +84,7 @@ class TestWaitForInit:
|
|||
loop = build_test_agent_loop(defer_heavy_init=True)
|
||||
error = RuntimeError("init failed")
|
||||
|
||||
with patch.object(loop.tool_manager, "integrate_mcp", side_effect=error):
|
||||
with patch.object(loop.tool_manager, "integrate_all", side_effect=error):
|
||||
loop._complete_init()
|
||||
|
||||
with pytest.raises(RuntimeError, match="init failed"):
|
||||
|
|
@ -95,7 +95,7 @@ class TestWaitForInit:
|
|||
loop = build_test_agent_loop(defer_heavy_init=True)
|
||||
error = RuntimeError("once only")
|
||||
|
||||
with patch.object(loop.tool_manager, "integrate_mcp", side_effect=error):
|
||||
with patch.object(loop.tool_manager, "integrate_all", side_effect=error):
|
||||
loop._complete_init()
|
||||
|
||||
with pytest.raises(RuntimeError):
|
||||
|
|
|
|||
|
|
@ -123,13 +123,13 @@ async def test_ui_alt_left_and_alt_right_move_by_word(vibe_app: VibeApp) -> None
|
|||
await pilot.press(*"hello brave world")
|
||||
assert textarea.cursor_location == (0, len("hello brave world"))
|
||||
|
||||
await pilot.press("alt+left")
|
||||
await pilot.press("ctrl+left")
|
||||
assert textarea.cursor_location == (0, len("hello brave "))
|
||||
|
||||
await pilot.press("alt+left")
|
||||
await pilot.press("ctrl+left")
|
||||
assert textarea.cursor_location == (0, len("hello "))
|
||||
|
||||
await pilot.press("alt+right")
|
||||
await pilot.press("ctrl+right")
|
||||
assert textarea.cursor_location == (0, len("hello brave"))
|
||||
|
||||
assert chat_input.value == "hello brave world"
|
||||
|
|
|
|||
401
tests/tools/test_connectors.py
Normal file
|
|
@ -0,0 +1,401 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from typing import cast
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
import httpx
|
||||
import pytest
|
||||
|
||||
from tests.stubs.fake_connector_registry import FakeConnectorRegistry
|
||||
from tests.stubs.fake_mcp_registry import FakeMCPRegistry
|
||||
from vibe.core.config import VibeConfig
|
||||
from vibe.core.tools.base import BaseToolConfig, ToolError
|
||||
from vibe.core.tools.connectors import CONNECTORS_ENV_VAR
|
||||
from vibe.core.tools.connectors.connector_registry import (
|
||||
RemoteTool,
|
||||
_connector_error_message,
|
||||
_normalize_name,
|
||||
_unwrap_http_status_error,
|
||||
create_connector_proxy_tool_class,
|
||||
)
|
||||
from vibe.core.tools.manager import ToolManager
|
||||
from vibe.core.tools.mcp.tools import MCPTool, MCPToolResult
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Unit tests for helper functions
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestNormalizeName:
|
||||
def test_basic(self) -> None:
|
||||
assert _normalize_name("my_connector") == "my_connector"
|
||||
|
||||
def test_special_chars(self) -> None:
|
||||
assert _normalize_name("my.connector!v2") == "my_connector_v2"
|
||||
|
||||
def test_strip_edges(self) -> None:
|
||||
assert _normalize_name("--hello--") == "hello"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Unit tests for proxy tool class creation
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestCreateConnectorProxyTool:
|
||||
def test_tool_name(self) -> None:
|
||||
remote = RemoteTool(name="search", description="Search docs")
|
||||
cls = create_connector_proxy_tool_class(
|
||||
connector_name="deepwiki",
|
||||
connector_alias="deepwiki",
|
||||
connector_id="abc-123",
|
||||
remote=remote,
|
||||
api_key="key",
|
||||
)
|
||||
assert cls.get_name() == "connector_deepwiki_search"
|
||||
|
||||
def test_is_connector_flag(self) -> None:
|
||||
remote = RemoteTool(name="read", description="Read file")
|
||||
cls = create_connector_proxy_tool_class(
|
||||
connector_name="myconn",
|
||||
connector_alias="myconn",
|
||||
connector_id="id-1",
|
||||
remote=remote,
|
||||
api_key="key",
|
||||
)
|
||||
assert issubclass(cls, MCPTool)
|
||||
assert cls._is_connector is True
|
||||
assert cls.is_connector() is True
|
||||
|
||||
def test_description_includes_alias(self) -> None:
|
||||
remote = RemoteTool(name="fetch", description="Fetch page")
|
||||
cls = create_connector_proxy_tool_class(
|
||||
connector_name="web_tool",
|
||||
connector_alias="web_tool",
|
||||
connector_id="id-2",
|
||||
remote=remote,
|
||||
api_key="key",
|
||||
)
|
||||
assert cls.description.startswith("[web_tool]")
|
||||
assert "Fetch page" in cls.description
|
||||
|
||||
def test_parameters_from_schema(self) -> None:
|
||||
schema = {
|
||||
"type": "object",
|
||||
"properties": {"query": {"type": "string"}},
|
||||
"required": ["query"],
|
||||
}
|
||||
remote = RemoteTool.model_validate({
|
||||
"name": "search",
|
||||
"description": "Search",
|
||||
"inputSchema": schema,
|
||||
})
|
||||
cls = create_connector_proxy_tool_class(
|
||||
connector_name="conn",
|
||||
connector_alias="conn",
|
||||
connector_id="id-3",
|
||||
remote=remote,
|
||||
api_key="key",
|
||||
)
|
||||
params = cls.get_parameters()
|
||||
assert params["properties"]["query"]["type"] == "string"
|
||||
|
||||
def test_server_name_is_connector_alias(self) -> None:
|
||||
remote = RemoteTool(name="tool1", description="A tool")
|
||||
cls = cast(
|
||||
type[MCPTool],
|
||||
create_connector_proxy_tool_class(
|
||||
connector_name="my-connector",
|
||||
connector_alias="my-connector",
|
||||
connector_id="id-4",
|
||||
remote=remote,
|
||||
api_key="key",
|
||||
),
|
||||
)
|
||||
assert cls.get_server_name() == "my-connector"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# FakeConnectorRegistry tests
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestFakeConnectorRegistry:
|
||||
def test_get_tools(self) -> None:
|
||||
registry = FakeConnectorRegistry(
|
||||
connectors={
|
||||
"wiki": [RemoteTool(name="search", description="Search wiki")],
|
||||
"mail": [
|
||||
RemoteTool(name="send", description="Send email"),
|
||||
RemoteTool(name="read", description="Read email"),
|
||||
],
|
||||
}
|
||||
)
|
||||
tools = registry.get_tools()
|
||||
assert "connector_wiki_search" in tools
|
||||
assert "connector_mail_send" in tools
|
||||
assert "connector_mail_read" in tools
|
||||
assert registry.connector_count == 2
|
||||
|
||||
def test_connector_names(self) -> None:
|
||||
registry = FakeConnectorRegistry(connectors={"alpha": [], "beta": []})
|
||||
assert set(registry.get_connector_names()) == {"alpha", "beta"}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Integration: ToolManager + ConnectorRegistry
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestToolManagerConnectorIntegration:
|
||||
@staticmethod
|
||||
def _make_config() -> VibeConfig:
|
||||
"""Minimal VibeConfig-like stub for ToolManager."""
|
||||
return cast(
|
||||
VibeConfig,
|
||||
type(
|
||||
"_Cfg",
|
||||
(),
|
||||
{
|
||||
"mcp_servers": [],
|
||||
"enabled_tools": [],
|
||||
"disabled_tools": [],
|
||||
"tools": {},
|
||||
"tool_paths": [],
|
||||
},
|
||||
)(),
|
||||
)
|
||||
|
||||
def test_connector_tools_registered(self) -> None:
|
||||
registry = FakeConnectorRegistry(
|
||||
connectors={"myconn": [RemoteTool(name="ping", description="Ping")]}
|
||||
)
|
||||
config = self._make_config()
|
||||
tm = ToolManager(
|
||||
config_getter=lambda: config,
|
||||
mcp_registry=FakeMCPRegistry(),
|
||||
connector_registry=registry,
|
||||
)
|
||||
assert "connector_myconn_ping" in tm.registered_tools
|
||||
|
||||
def test_no_connector_registry(self) -> None:
|
||||
config = self._make_config()
|
||||
tm = ToolManager(
|
||||
config_getter=lambda: config,
|
||||
mcp_registry=FakeMCPRegistry(),
|
||||
connector_registry=None,
|
||||
)
|
||||
# No connector tools, but no crash
|
||||
connector_tools = [
|
||||
name
|
||||
for name, cls in tm.registered_tools.items()
|
||||
if issubclass(cls, MCPTool) and cls.is_connector()
|
||||
]
|
||||
assert connector_tools == []
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# ConnectorRegistry env var gating (tested via agent_loop helper logic)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestConnectorRegistryEnvGating:
|
||||
def test_disabled_without_env_var(self) -> None:
|
||||
with patch.dict(os.environ, {}, clear=False):
|
||||
os.environ.pop(CONNECTORS_ENV_VAR, None)
|
||||
assert os.getenv(CONNECTORS_ENV_VAR) != "1"
|
||||
|
||||
def test_enabled_with_env_var(self) -> None:
|
||||
with patch.dict(os.environ, {CONNECTORS_ENV_VAR: "1"}):
|
||||
assert os.getenv(CONNECTORS_ENV_VAR) == "1"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Error message helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def _make_http_status_error(status: int, body: str = "") -> httpx.HTTPStatusError:
|
||||
response = httpx.Response(
|
||||
status, text=body, request=httpx.Request("POST", "http://example.com")
|
||||
)
|
||||
return httpx.HTTPStatusError("error", request=response.request, response=response)
|
||||
|
||||
|
||||
class TestConnectorErrorMessage:
|
||||
def test_timeout(self) -> None:
|
||||
exc = httpx.ReadTimeout("timed out")
|
||||
msg = _connector_error_message(exc, "id-1", "myconn")
|
||||
assert "timed out" in msg.lower()
|
||||
assert "myconn" in msg
|
||||
|
||||
def test_connect_error(self) -> None:
|
||||
exc = httpx.ConnectError("connection refused")
|
||||
msg = _connector_error_message(exc, "id-1", "myconn")
|
||||
assert "network" in msg.lower()
|
||||
assert "myconn" in msg
|
||||
|
||||
def test_exception_group(self) -> None:
|
||||
exc = ExceptionGroup("errors", [ValueError("a"), RuntimeError("b")])
|
||||
msg = _connector_error_message(exc, "id-1", "myconn")
|
||||
assert "multiple errors" in msg.lower()
|
||||
assert "myconn" in msg
|
||||
|
||||
def test_generic_error(self) -> None:
|
||||
exc = RuntimeError("something broke")
|
||||
msg = _connector_error_message(exc, "id-1", "myconn")
|
||||
assert "something broke" in msg
|
||||
assert "myconn" in msg
|
||||
|
||||
def test_http_401_surfaces_auth_message(self) -> None:
|
||||
exc = _make_http_status_error(401, "Unauthorized")
|
||||
msg = _connector_error_message(exc, "id-1", "myconn")
|
||||
assert "authentication failed" in msg.lower()
|
||||
assert "401" in msg
|
||||
assert "Unauthorized" in msg
|
||||
|
||||
def test_http_400_surfaces_response_body(self) -> None:
|
||||
exc = _make_http_status_error(400, '{"error": "missing field X"}')
|
||||
msg = _connector_error_message(exc, "id-1", "myconn")
|
||||
assert "400" in msg
|
||||
assert "missing field X" in msg
|
||||
|
||||
def test_http_404_surfaces_not_found(self) -> None:
|
||||
exc = _make_http_status_error(404)
|
||||
msg = _connector_error_message(exc, "id-1", "myconn")
|
||||
assert "not found" in msg.lower()
|
||||
|
||||
def test_http_error_wrapped_in_exception_group(self) -> None:
|
||||
inner = _make_http_status_error(400, "bad request detail")
|
||||
exc = ExceptionGroup("errors", [inner])
|
||||
msg = _connector_error_message(exc, "id-1", "myconn")
|
||||
assert "400" in msg
|
||||
assert "bad request detail" in msg
|
||||
|
||||
|
||||
class TestUnwrapHttpStatusError:
|
||||
def test_direct(self) -> None:
|
||||
exc = _make_http_status_error(400)
|
||||
assert _unwrap_http_status_error(exc) is exc
|
||||
|
||||
def test_from_exception_group(self) -> None:
|
||||
inner = _make_http_status_error(500)
|
||||
exc = ExceptionGroup("g", [ValueError("x"), inner])
|
||||
assert _unwrap_http_status_error(exc) is inner
|
||||
|
||||
def test_from_cause(self) -> None:
|
||||
inner = _make_http_status_error(403)
|
||||
outer = RuntimeError("wrapper")
|
||||
outer.__cause__ = inner
|
||||
assert _unwrap_http_status_error(outer) is inner
|
||||
|
||||
def test_none_when_absent(self) -> None:
|
||||
assert _unwrap_http_status_error(RuntimeError("no http")) is None
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# ConnectorProxyTool.run() via MCP proxy
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestConnectorProxyToolRun:
|
||||
@staticmethod
|
||||
def _make_tool_class() -> type[MCPTool]:
|
||||
remote = RemoteTool(name="search", description="Search docs")
|
||||
return cast(
|
||||
type[MCPTool],
|
||||
create_connector_proxy_tool_class(
|
||||
connector_name="wiki",
|
||||
connector_alias="wiki",
|
||||
connector_id="conn-123",
|
||||
remote=remote,
|
||||
api_key="test-key",
|
||||
server_url="https://custom.api.example.com",
|
||||
),
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _make_tool(tool_cls: type[MCPTool]) -> MCPTool:
|
||||
return cast(MCPTool, tool_cls.from_config(lambda: BaseToolConfig()))
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_run_calls_mcp_proxy(self) -> None:
|
||||
cls = self._make_tool_class()
|
||||
tool = self._make_tool(cls)
|
||||
expected = MCPToolResult(
|
||||
ok=True, server="test", tool="search", text="result text"
|
||||
)
|
||||
|
||||
with patch(
|
||||
"vibe.core.tools.connectors.connector_registry.call_tool_http",
|
||||
new_callable=AsyncMock,
|
||||
return_value=expected,
|
||||
) as mock_call:
|
||||
results = [r async for r in tool.invoke(query="hello")]
|
||||
|
||||
mock_call.assert_awaited_once()
|
||||
call_args = mock_call.call_args
|
||||
assert "/v1/experimental/connectors/conn-123/mcp" in call_args.args[0]
|
||||
assert call_args.args[1] == "search"
|
||||
assert call_args.kwargs["headers"]["Authorization"] == "Bearer test-key"
|
||||
|
||||
assert len(results) == 1
|
||||
assert results[0] == expected
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_run_uses_default_base_url(self) -> None:
|
||||
remote = RemoteTool(name="ping", description="Ping")
|
||||
cls = cast(
|
||||
type[MCPTool],
|
||||
create_connector_proxy_tool_class(
|
||||
connector_name="svc",
|
||||
connector_alias="svc",
|
||||
connector_id="c-1",
|
||||
remote=remote,
|
||||
api_key="key",
|
||||
server_url=None,
|
||||
),
|
||||
)
|
||||
tool = self._make_tool(cls)
|
||||
expected = MCPToolResult(ok=True, server="s", tool="ping", text="pong")
|
||||
|
||||
with patch(
|
||||
"vibe.core.tools.connectors.connector_registry.call_tool_http",
|
||||
new_callable=AsyncMock,
|
||||
return_value=expected,
|
||||
) as mock_call:
|
||||
[_ async for _ in tool.invoke()]
|
||||
|
||||
url = mock_call.call_args.args[0]
|
||||
assert url.startswith("https://api.mistral.ai/")
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_run_surfaces_timeout_error(self) -> None:
|
||||
cls = self._make_tool_class()
|
||||
tool = self._make_tool(cls)
|
||||
|
||||
with (
|
||||
patch(
|
||||
"vibe.core.tools.connectors.connector_registry.call_tool_http",
|
||||
new_callable=AsyncMock,
|
||||
side_effect=httpx.ReadTimeout("timed out"),
|
||||
),
|
||||
pytest.raises(ToolError, match="timed out"),
|
||||
):
|
||||
[_ async for _ in tool.invoke(query="hello")]
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_run_surfaces_connect_error(self) -> None:
|
||||
cls = self._make_tool_class()
|
||||
tool = self._make_tool(cls)
|
||||
|
||||
with (
|
||||
patch(
|
||||
"vibe.core.tools.connectors.connector_registry.call_tool_http",
|
||||
new_callable=AsyncMock,
|
||||
side_effect=httpx.ConnectError("refused"),
|
||||
),
|
||||
pytest.raises(ToolError, match="network"),
|
||||
):
|
||||
[_ async for _ in tool.invoke(query="hello")]
|
||||