v2.15.0 (#773)
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: Nelson PROIA <144663685+Nelson-PROIA@users.noreply.github.com> Co-authored-by: Paul VEZIA <166131032+le-codeur-rapide@users.noreply.github.com> Co-authored-by: Pierre Rossinès <pierre.rossines@mistral.ai> Co-authored-by: Quentin <quentin.torroba@mistral.ai> Co-authored-by: Val <102326092+vdeva@users.noreply.github.com> Co-authored-by: Vincent G <10739306+VinceOPS@users.noreply.github.com> Co-authored-by: Mistral Vibe <vibe@mistral.ai>
|
|
@ -127,7 +127,7 @@ class TestAcpHooksLoading:
|
|||
assert result.hooks[0].name == "lint"
|
||||
assert result.hooks[0].type == HookType.POST_AGENT_TURN
|
||||
assert result.hooks[0].command == "eslint ."
|
||||
assert result.hooks[0].timeout == 30.0
|
||||
assert result.hooks[0].timeout == 60.0
|
||||
assert result.issues == []
|
||||
|
||||
async def test_new_session_hooks_enabled_invalid_toml(
|
||||
|
|
@ -167,5 +167,5 @@ class TestAcpHooksLoading:
|
|||
assert result.hooks[0].name == "lint"
|
||||
assert result.hooks[0].type == HookType.POST_AGENT_TURN
|
||||
assert result.hooks[0].command == "eslint ."
|
||||
assert result.hooks[0].timeout == 30.0
|
||||
assert result.hooks[0].timeout == 60.0
|
||||
assert result.issues == []
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ class TestACPInitialize:
|
|||
),
|
||||
)
|
||||
assert response.agent_info == Implementation(
|
||||
name="@mistralai/mistral-vibe", title="Mistral Vibe", version="2.14.1"
|
||||
name="@mistralai/mistral-vibe", title="Mistral Vibe", version="2.15.0"
|
||||
)
|
||||
|
||||
assert response.auth_methods is not None
|
||||
|
|
@ -101,7 +101,7 @@ class TestACPInitialize:
|
|||
),
|
||||
)
|
||||
assert response.agent_info == Implementation(
|
||||
name="@mistralai/mistral-vibe", title="Mistral Vibe", version="2.14.1"
|
||||
name="@mistralai/mistral-vibe", title="Mistral Vibe", version="2.15.0"
|
||||
)
|
||||
|
||||
assert response.auth_methods is not None
|
||||
|
|
|
|||
|
|
@ -151,6 +151,7 @@ class TestWebSearchFieldMeta:
|
|||
|
||||
def test_result_locations_are_source_urls_with_titles(self) -> None:
|
||||
result = WebSearchResult(
|
||||
query="python",
|
||||
answer="found it",
|
||||
sources=[
|
||||
WebSearchSource(title="Docs", url="https://docs.python.org"),
|
||||
|
|
|
|||
|
|
@ -498,6 +498,83 @@ class TestAdapterParseResponse:
|
|||
assert chunk.message.content == "Hello!"
|
||||
assert chunk.usage.prompt_tokens == 10
|
||||
|
||||
def test_non_streaming_captures_refusal_stop_reason(self, adapter, provider):
|
||||
data = {
|
||||
"content": [],
|
||||
"usage": {"input_tokens": 10, "output_tokens": 2},
|
||||
"stop_reason": "refusal",
|
||||
}
|
||||
chunk = adapter.parse_response(data, provider)
|
||||
assert chunk.stop is not None
|
||||
assert chunk.stop.reason == "refusal"
|
||||
|
||||
def test_streaming_message_delta_captures_refusal_stop_reason(
|
||||
self, adapter, provider
|
||||
):
|
||||
data = {
|
||||
"type": "message_delta",
|
||||
"delta": {"stop_reason": "refusal", "stop_sequence": None},
|
||||
"usage": {"output_tokens": 7},
|
||||
}
|
||||
chunk = adapter.parse_response(data, provider)
|
||||
assert chunk.stop is not None
|
||||
assert chunk.stop.reason == "refusal"
|
||||
assert chunk.usage.completion_tokens == 7
|
||||
|
||||
def test_streaming_message_delta_end_turn_stop_reason(self, adapter, provider):
|
||||
data = {
|
||||
"type": "message_delta",
|
||||
"delta": {"stop_reason": "end_turn", "stop_sequence": None},
|
||||
"usage": {"output_tokens": 3},
|
||||
}
|
||||
chunk = adapter.parse_response(data, provider)
|
||||
assert chunk.stop is not None
|
||||
assert chunk.stop.reason == "end_turn"
|
||||
|
||||
def test_non_streaming_captures_refusal_stop_details(self, adapter, provider):
|
||||
data = {
|
||||
"content": [],
|
||||
"usage": {"input_tokens": 10, "output_tokens": 2},
|
||||
"stop_reason": "refusal",
|
||||
"stop_details": {
|
||||
"type": "refusal",
|
||||
"category": "cyber",
|
||||
"explanation": "This request was declined.",
|
||||
},
|
||||
}
|
||||
chunk = adapter.parse_response(data, provider)
|
||||
assert chunk.stop is not None
|
||||
assert chunk.stop.category == "cyber"
|
||||
assert chunk.stop.explanation == "This request was declined."
|
||||
|
||||
def test_non_streaming_without_stop_details_is_none(self, adapter, provider):
|
||||
data = {
|
||||
"content": [],
|
||||
"usage": {"input_tokens": 10, "output_tokens": 2},
|
||||
"stop_reason": "end_turn",
|
||||
}
|
||||
chunk = adapter.parse_response(data, provider)
|
||||
assert chunk.stop is not None
|
||||
assert chunk.stop.category is None
|
||||
assert chunk.stop.explanation is None
|
||||
|
||||
def test_streaming_message_delta_captures_refusal_stop_details(
|
||||
self, adapter, provider
|
||||
):
|
||||
data = {
|
||||
"type": "message_delta",
|
||||
"delta": {
|
||||
"stop_reason": "refusal",
|
||||
"stop_sequence": None,
|
||||
"stop_details": {"type": "refusal", "category": "bio"},
|
||||
},
|
||||
"usage": {"output_tokens": 7},
|
||||
}
|
||||
chunk = adapter.parse_response(data, provider)
|
||||
assert chunk.stop is not None
|
||||
assert chunk.stop.category == "bio"
|
||||
assert chunk.stop.explanation is None
|
||||
|
||||
def test_streaming_text_delta(self, adapter, provider):
|
||||
data = {
|
||||
"type": "content_block_delta",
|
||||
|
|
|
|||
|
|
@ -228,3 +228,67 @@ class TestBannerConnectorsCount:
|
|||
|
||||
assert banner._initial_state.connectors_connected == 3
|
||||
assert banner._initial_state.connectors_total == 5
|
||||
|
||||
|
||||
class TestBannerHooksCount:
|
||||
def test_hooks_count_passed_through(self) -> None:
|
||||
skill_manager = Mock(spec=SkillManager)
|
||||
skill_manager.custom_skills_count = 0
|
||||
|
||||
banner = Banner(
|
||||
config=_make_mock_config(), skill_manager=skill_manager, hooks_count=4
|
||||
)
|
||||
|
||||
assert banner._initial_state.hooks_count == 4
|
||||
|
||||
def test_hooks_count_defaults_to_zero(self) -> None:
|
||||
skill_manager = Mock(spec=SkillManager)
|
||||
skill_manager.custom_skills_count = 0
|
||||
|
||||
banner = Banner(config=_make_mock_config(), skill_manager=skill_manager)
|
||||
|
||||
assert banner._initial_state.hooks_count == 0
|
||||
|
||||
def test_format_meta_counts_shows_hooks_when_present(self) -> None:
|
||||
skill_manager = Mock(spec=SkillManager)
|
||||
skill_manager.custom_skills_count = 0
|
||||
|
||||
banner = Banner(config=_make_mock_config(), skill_manager=skill_manager)
|
||||
banner.state = BannerState(models_count=1, skills_count=0, hooks_count=3)
|
||||
|
||||
result = banner._format_meta_counts()
|
||||
assert "3 hooks" in result
|
||||
|
||||
def test_format_meta_counts_singular_hook(self) -> None:
|
||||
skill_manager = Mock(spec=SkillManager)
|
||||
skill_manager.custom_skills_count = 0
|
||||
|
||||
banner = Banner(config=_make_mock_config(), skill_manager=skill_manager)
|
||||
banner.state = BannerState(models_count=1, skills_count=0, hooks_count=1)
|
||||
|
||||
result = banner._format_meta_counts()
|
||||
assert "1 hook" in result
|
||||
assert "1 hooks" not in result
|
||||
|
||||
def test_format_meta_counts_hides_hooks_when_zero(self) -> None:
|
||||
skill_manager = Mock(spec=SkillManager)
|
||||
skill_manager.custom_skills_count = 0
|
||||
|
||||
banner = Banner(config=_make_mock_config(), skill_manager=skill_manager)
|
||||
banner.state = BannerState(models_count=1, skills_count=0, hooks_count=0)
|
||||
|
||||
result = banner._format_meta_counts()
|
||||
assert "hook" not in result
|
||||
|
||||
def test_set_state_updates_hooks_count(self) -> None:
|
||||
skill_manager = Mock(spec=SkillManager)
|
||||
skill_manager.custom_skills_count = 0
|
||||
|
||||
banner = Banner(
|
||||
config=_make_mock_config(), skill_manager=skill_manager, hooks_count=0
|
||||
)
|
||||
banner.set_state(
|
||||
config=_make_mock_config(), skill_manager=skill_manager, hooks_count=7
|
||||
)
|
||||
|
||||
assert banner.state.hooks_count == 7
|
||||
|
|
|
|||
|
|
@ -268,8 +268,16 @@ def test_installed_bundle_launches(binary_dir: Path, binary_name: str) -> None:
|
|||
env = _isolated_env(vibe_home)
|
||||
env["PATH"] = f"{install_dir}{os.pathsep}{env.get('PATH', '')}"
|
||||
|
||||
command = binary_name
|
||||
if platform.system() == "Windows":
|
||||
# subprocess on Windows does not resolve executables through a PATH
|
||||
# value supplied only via env, so resolve it against that PATH first.
|
||||
if (resolved := shutil.which(binary_name, path=env["PATH"])) is None:
|
||||
_fail(f"installed binary not found on PATH: {binary_name}")
|
||||
command = resolved
|
||||
|
||||
result = subprocess.run(
|
||||
[binary_name, "--version"],
|
||||
[command, "--version"],
|
||||
capture_output=True,
|
||||
cwd=workdir,
|
||||
env=env,
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ class TestCommandRegistry:
|
|||
assert result is not None
|
||||
_, cmd, _ = result
|
||||
assert cmd.handler == "_show_session_picker"
|
||||
assert cmd.description == "Browse, resume, or delete saved sessions"
|
||||
|
||||
def test_rename_command_registration(self) -> None:
|
||||
registry = CommandRegistry()
|
||||
|
|
@ -143,3 +144,47 @@ class TestCommandRegistry:
|
|||
assert cmd_name == "loop"
|
||||
assert cmd.handler == "_loop_command"
|
||||
assert cmd_args == "30s ping"
|
||||
|
||||
def test_exit_command_accepts_bare_synonyms(self) -> None:
|
||||
registry = CommandRegistry()
|
||||
for alias in ["/exit", "exit", "quit", ":q", ":quit"]:
|
||||
assert registry.get_command_name(alias) == "exit", alias
|
||||
result = registry.parse_command(alias)
|
||||
assert result is not None, alias
|
||||
cmd_name, cmd, _ = result
|
||||
assert cmd_name == "exit"
|
||||
assert cmd.handler == "_exit_app"
|
||||
assert cmd.exits is True
|
||||
|
||||
def test_bare_exit_synonym_with_trailing_text_is_not_a_command(self) -> None:
|
||||
registry = CommandRegistry()
|
||||
assert registry.parse_command("exit the function early") is None
|
||||
assert registry.parse_command("quit your job") is None
|
||||
|
||||
def test_bare_exit_synonym_in_multiline_message_is_not_a_command(self) -> None:
|
||||
registry = CommandRegistry()
|
||||
assert registry.parse_command("exit\nplease refactor this module") is None
|
||||
|
||||
def test_slash_exit_still_parses_with_trailing_text(self) -> None:
|
||||
registry = CommandRegistry()
|
||||
result = registry.parse_command("/exit now")
|
||||
assert result is not None
|
||||
cmd_name, _, cmd_args = result
|
||||
assert cmd_name == "exit"
|
||||
assert cmd_args == "now"
|
||||
|
||||
def test_exit_command_synonyms_are_case_insensitive(self) -> None:
|
||||
registry = CommandRegistry()
|
||||
for alias in ["EXIT", "Quit", " exit ", ":Q"]:
|
||||
assert registry.get_command_name(alias) == "exit", alias
|
||||
|
||||
def test_exit_synonyms_excluded_when_command_disabled(self) -> None:
|
||||
registry = CommandRegistry(excluded_commands=["exit"])
|
||||
for alias in ["/exit", "exit", "quit", ":q", ":quit"]:
|
||||
assert registry.get_command_name(alias) is None, alias
|
||||
|
||||
def test_help_text_lists_exit_synonyms(self) -> None:
|
||||
registry = CommandRegistry()
|
||||
help_text = registry.get_help_text()
|
||||
for alias in ["`/exit`", "`exit`", "`quit`", "`:q`", "`:quit`"]:
|
||||
assert alias in help_text, alias
|
||||
|
|
|
|||
31
tests/cli/test_help.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from vibe.cli.entrypoint import parse_arguments
|
||||
|
||||
|
||||
def test_help_shows_auto_approve_flag(
|
||||
monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
|
||||
) -> None:
|
||||
monkeypatch.setattr("sys.argv", ["vibe", "--help"])
|
||||
|
||||
with pytest.raises(SystemExit) as exc_info:
|
||||
parse_arguments()
|
||||
|
||||
assert exc_info.value.code == 0
|
||||
output = capsys.readouterr().out
|
||||
assert "--auto-approve" in output
|
||||
assert "Shortcut for --agent auto-approve" in output
|
||||
|
||||
|
||||
def test_auto_approve_conflicts_with_agent(
|
||||
monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
|
||||
) -> None:
|
||||
monkeypatch.setattr("sys.argv", ["vibe", "--agent", "plan", "--auto-approve"])
|
||||
|
||||
with pytest.raises(SystemExit) as exc_info:
|
||||
parse_arguments()
|
||||
|
||||
assert exc_info.value.code == 2
|
||||
assert "not allowed with argument --agent" in capsys.readouterr().err
|
||||
|
|
@ -7,8 +7,10 @@ from vibe.core.agents.models import BuiltinAgentName
|
|||
from vibe.core.config import VibeConfig
|
||||
|
||||
|
||||
def _make_args(*, agent: str | None, prompt: str | None) -> argparse.Namespace:
|
||||
return argparse.Namespace(agent=agent, prompt=prompt)
|
||||
def _make_args(
|
||||
*, agent: str | None, prompt: str | None, auto_approve: bool = False
|
||||
) -> argparse.Namespace:
|
||||
return argparse.Namespace(agent=agent, prompt=prompt, auto_approve=auto_approve)
|
||||
|
||||
|
||||
def test_uses_args_agent_when_provided() -> None:
|
||||
|
|
@ -51,3 +53,10 @@ def test_programmatic_mode_keeps_explicit_agent_arg() -> None:
|
|||
args = _make_args(agent="accept-edits", prompt="hello")
|
||||
|
||||
assert get_initial_agent_name(args, config) == "accept-edits"
|
||||
|
||||
|
||||
def test_auto_approve_flag_selects_auto_approve_agent() -> None:
|
||||
config = VibeConfig.model_construct(default_agent=BuiltinAgentName.PLAN)
|
||||
args = _make_args(agent=None, prompt="hello", auto_approve=True)
|
||||
|
||||
assert get_initial_agent_name(args, config) == BuiltinAgentName.AUTO_APPROVE
|
||||
|
|
|
|||
230
tests/cli/test_session_delete.py
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from tests.conftest import build_test_vibe_app, build_test_vibe_config
|
||||
from vibe.cli.textual_ui.widgets.messages import ErrorMessage, UserCommandMessage
|
||||
from vibe.cli.textual_ui.widgets.session_picker import SessionPickerApp
|
||||
from vibe.core.config import SessionLoggingConfig
|
||||
from vibe.core.session.resume_sessions import short_session_id
|
||||
|
||||
|
||||
def _enabled_session_config(save_dir: Path) -> SessionLoggingConfig:
|
||||
return SessionLoggingConfig(enabled=True, save_dir=str(save_dir))
|
||||
|
||||
|
||||
class FakeSessionPicker:
|
||||
def __init__(self, *, has_sessions_after_remove: bool = True) -> None:
|
||||
self.has_sessions = True
|
||||
self.removed_option_ids: list[str] = []
|
||||
self.cleared_pending_option_ids: list[str] = []
|
||||
self._has_sessions_after_remove = has_sessions_after_remove
|
||||
|
||||
def remove_session(self, option_id: str) -> bool:
|
||||
self.removed_option_ids.append(option_id)
|
||||
self.has_sessions = self._has_sessions_after_remove
|
||||
return True
|
||||
|
||||
def clear_pending_delete(self, option_id: str) -> bool:
|
||||
self.cleared_pending_option_ids.append(option_id)
|
||||
return True
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_session_delete_request_deletes_local_session(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
config = build_test_vibe_config(
|
||||
session_logging=_enabled_session_config(tmp_path), enable_connectors=False
|
||||
)
|
||||
app = build_test_vibe_app(config=config)
|
||||
picker = FakeSessionPicker()
|
||||
mounted_widgets: list[object] = []
|
||||
deleted_sessions: list[tuple[str, SessionLoggingConfig]] = []
|
||||
|
||||
async def delete_session(
|
||||
session_id: str, session_config: SessionLoggingConfig
|
||||
) -> None:
|
||||
deleted_sessions.append((session_id, session_config))
|
||||
|
||||
async def mount_and_scroll(widget: object, after: object | None = None) -> None:
|
||||
mounted_widgets.append(widget)
|
||||
|
||||
monkeypatch.setattr("vibe.cli.textual_ui.app.delete_saved_session", delete_session)
|
||||
monkeypatch.setattr(app, "query_one", lambda _selector: picker)
|
||||
monkeypatch.setattr(app, "_mount_and_scroll", mount_and_scroll)
|
||||
|
||||
await app.on_session_picker_app_session_delete_requested(
|
||||
SessionPickerApp.SessionDeleteRequested(
|
||||
"local:deleted-session", "local", "deleted-session"
|
||||
)
|
||||
)
|
||||
|
||||
assert deleted_sessions == [("deleted-session", config.session_logging)]
|
||||
assert picker.removed_option_ids == ["local:deleted-session"]
|
||||
assert any(
|
||||
isinstance(widget, UserCommandMessage)
|
||||
and widget._content
|
||||
== f"Deleted session `{short_session_id('deleted-session')}`."
|
||||
for widget in mounted_widgets
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_session_delete_request_keeps_picker_on_delete_error(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
config = build_test_vibe_config(
|
||||
session_logging=_enabled_session_config(tmp_path), enable_connectors=False
|
||||
)
|
||||
app = build_test_vibe_app(config=config)
|
||||
picker = FakeSessionPicker()
|
||||
mounted_widgets: list[object] = []
|
||||
|
||||
async def delete_session(
|
||||
session_id: str, session_config: SessionLoggingConfig
|
||||
) -> None:
|
||||
raise RuntimeError("disk said no")
|
||||
|
||||
async def mount_and_scroll(widget: object, after: object | None = None) -> None:
|
||||
mounted_widgets.append(widget)
|
||||
|
||||
monkeypatch.setattr("vibe.cli.textual_ui.app.delete_saved_session", delete_session)
|
||||
monkeypatch.setattr(app, "query_one", lambda _selector: picker)
|
||||
monkeypatch.setattr(app, "_mount_and_scroll", mount_and_scroll)
|
||||
|
||||
await app.on_session_picker_app_session_delete_requested(
|
||||
SessionPickerApp.SessionDeleteRequested(
|
||||
"local:deleted-session", "local", "deleted-session"
|
||||
)
|
||||
)
|
||||
|
||||
assert picker.removed_option_ids == []
|
||||
assert picker.cleared_pending_option_ids == ["local:deleted-session"]
|
||||
assert any(
|
||||
isinstance(widget, ErrorMessage)
|
||||
and widget._error == "Failed to delete session: disk said no"
|
||||
for widget in mounted_widgets
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_session_delete_request_returns_to_input_when_picker_becomes_empty(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
config = build_test_vibe_config(
|
||||
session_logging=_enabled_session_config(tmp_path), enable_connectors=False
|
||||
)
|
||||
app = build_test_vibe_app(config=config)
|
||||
picker = FakeSessionPicker(has_sessions_after_remove=False)
|
||||
mounted_widgets: list[object] = []
|
||||
switched_to_input = False
|
||||
|
||||
async def delete_session(
|
||||
session_id: str, session_config: SessionLoggingConfig
|
||||
) -> None:
|
||||
pass
|
||||
|
||||
async def mount_and_scroll(widget: object, after: object | None = None) -> None:
|
||||
mounted_widgets.append(widget)
|
||||
|
||||
async def switch_to_input() -> None:
|
||||
nonlocal switched_to_input
|
||||
switched_to_input = True
|
||||
|
||||
monkeypatch.setattr("vibe.cli.textual_ui.app.delete_saved_session", delete_session)
|
||||
monkeypatch.setattr(app, "query_one", lambda _selector: picker)
|
||||
monkeypatch.setattr(app, "_mount_and_scroll", mount_and_scroll)
|
||||
monkeypatch.setattr(app, "_switch_to_input_app", switch_to_input)
|
||||
|
||||
await app.on_session_picker_app_session_delete_requested(
|
||||
SessionPickerApp.SessionDeleteRequested(
|
||||
"local:deleted-session", "local", "deleted-session"
|
||||
)
|
||||
)
|
||||
|
||||
assert switched_to_input is True
|
||||
assert picker.removed_option_ids == ["local:deleted-session"]
|
||||
assert [
|
||||
widget._content
|
||||
for widget in mounted_widgets
|
||||
if isinstance(widget, UserCommandMessage)
|
||||
] == [
|
||||
f"Deleted session `{short_session_id('deleted-session')}`.",
|
||||
"No saved sessions left for this directory.",
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_session_delete_request_rejects_remote_sessions(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
config = build_test_vibe_config(
|
||||
session_logging=_enabled_session_config(tmp_path), enable_connectors=False
|
||||
)
|
||||
app = build_test_vibe_app(config=config)
|
||||
mounted_widgets: list[object] = []
|
||||
|
||||
async def delete_session(
|
||||
session_id: str, session_config: SessionLoggingConfig
|
||||
) -> None:
|
||||
pytest.fail("remote sessions should not be deleted")
|
||||
|
||||
async def mount_and_scroll(widget: object, after: object | None = None) -> None:
|
||||
mounted_widgets.append(widget)
|
||||
|
||||
monkeypatch.setattr("vibe.cli.textual_ui.app.delete_saved_session", delete_session)
|
||||
monkeypatch.setattr(app, "_mount_and_scroll", mount_and_scroll)
|
||||
|
||||
await app.on_session_picker_app_session_delete_requested(
|
||||
SessionPickerApp.SessionDeleteRequested(
|
||||
"remote:remote-session", "remote", "remote-session"
|
||||
)
|
||||
)
|
||||
|
||||
assert any(
|
||||
isinstance(widget, ErrorMessage)
|
||||
and widget._error == "Deleting remote sessions is not supported."
|
||||
for widget in mounted_widgets
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_session_delete_request_rejects_current_session(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
config = build_test_vibe_config(
|
||||
session_logging=_enabled_session_config(tmp_path), enable_connectors=False
|
||||
)
|
||||
app = build_test_vibe_app(config=config)
|
||||
picker = FakeSessionPicker()
|
||||
mounted_widgets: list[object] = []
|
||||
deleted_sessions: list[str] = []
|
||||
|
||||
async def delete_session(
|
||||
session_id: str, session_config: SessionLoggingConfig
|
||||
) -> None:
|
||||
deleted_sessions.append(session_id)
|
||||
|
||||
async def mount_and_scroll(widget: object, after: object | None = None) -> None:
|
||||
mounted_widgets.append(widget)
|
||||
|
||||
monkeypatch.setattr("vibe.cli.textual_ui.app.delete_saved_session", delete_session)
|
||||
monkeypatch.setattr(app, "query_one", lambda _selector: picker)
|
||||
monkeypatch.setattr(app, "_mount_and_scroll", mount_and_scroll)
|
||||
|
||||
await app.on_session_picker_app_session_delete_requested(
|
||||
SessionPickerApp.SessionDeleteRequested(
|
||||
f"local:{app.agent_loop.session_id}", "local", app.agent_loop.session_id
|
||||
)
|
||||
)
|
||||
|
||||
assert deleted_sessions == []
|
||||
assert picker.cleared_pending_option_ids == [f"local:{app.agent_loop.session_id}"]
|
||||
assert any(
|
||||
isinstance(widget, ErrorMessage)
|
||||
and widget._error == "Deleting the current session is not supported."
|
||||
for widget in mounted_widgets
|
||||
)
|
||||
|
|
@ -145,6 +145,35 @@ async def test_ui_displays_multiple_user_assistant_turns(
|
|||
assert assistant_messages[1]._content == "Second answer"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_ui_displays_messages_when_resuming_in_dangerous_directory(
|
||||
monkeypatch: pytest.MonkeyPatch, vibe_config: VibeConfig
|
||||
) -> None:
|
||||
monkeypatch.setattr(
|
||||
"vibe.cli.textual_ui.app.is_dangerous_directory",
|
||||
lambda: (True, "You are in the home directory"),
|
||||
)
|
||||
|
||||
agent_loop = build_test_agent_loop(config=vibe_config)
|
||||
agent_loop.messages.extend([
|
||||
LLMMessage(role=Role.user, content="Hello from a previous run"),
|
||||
LLMMessage(role=Role.assistant, content="Welcome back!"),
|
||||
])
|
||||
|
||||
app = build_test_vibe_app(agent_loop=agent_loop)
|
||||
|
||||
async with app.run_test() as pilot:
|
||||
await pilot.pause(0.5)
|
||||
|
||||
user_messages = app.query(UserMessage)
|
||||
assistant_messages = app.query(AssistantMessage)
|
||||
|
||||
assert len(user_messages) == 1
|
||||
assert user_messages[0]._content == "Hello from a previous run"
|
||||
assert len(assistant_messages) == 1
|
||||
assert assistant_messages[0]._content == "Welcome back!"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_ui_rebuilds_history_when_whats_new_is_shown(
|
||||
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
|
||||
|
|
|
|||
|
|
@ -129,3 +129,30 @@ async def test_skill_without_args_does_not_prepend_invocation_line(
|
|||
vibe_app_with_skills, pilot, "Do the thing."
|
||||
)
|
||||
assert "/my-skill" not in message._content
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_popped_queued_skill_does_not_fire_telemetry(
|
||||
vibe_app_with_skills: VibeApp, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
async with vibe_app_with_skills.run_test() as pilot:
|
||||
events: list[tuple[str, str]] = []
|
||||
monkeypatch.setattr(
|
||||
vibe_app_with_skills.agent_loop.telemetry_client,
|
||||
"send_slash_command_used",
|
||||
lambda name, kind: events.append((name, kind)),
|
||||
)
|
||||
|
||||
chat_input = vibe_app_with_skills.query_one(ChatInputContainer)
|
||||
vibe_app_with_skills._agent_running = True
|
||||
try:
|
||||
chat_input.post_message(ChatInputContainer.Submitted("/my-skill"))
|
||||
await pilot.pause(0.1)
|
||||
assert len(vibe_app_with_skills._input_queue) == 1
|
||||
|
||||
await pilot.press("ctrl+c")
|
||||
await pilot.pause(0.1)
|
||||
assert len(vibe_app_with_skills._input_queue) == 0
|
||||
assert events == []
|
||||
finally:
|
||||
vibe_app_with_skills._agent_running = False
|
||||
|
|
|
|||
|
|
@ -4,38 +4,55 @@ from unittest.mock import AsyncMock
|
|||
|
||||
import pytest
|
||||
|
||||
from tests.stubs.fake_tool import FakeTool, FakeToolArgs
|
||||
import vibe.cli.textual_ui.handlers.event_handler as event_handler_module
|
||||
from vibe.cli.textual_ui.handlers.event_handler import EventHandler
|
||||
from vibe.cli.textual_ui.widgets.messages import HookSystemMessageLine
|
||||
from vibe.core.hooks.models import (
|
||||
HookEndEvent,
|
||||
HookMessageSeverity,
|
||||
HookRunEndEvent,
|
||||
HookRunStartEvent,
|
||||
HookStartEvent,
|
||||
HookType,
|
||||
)
|
||||
from vibe.core.types import ToolCallEvent, ToolResultEvent
|
||||
|
||||
|
||||
class FakeHookRunContainer:
|
||||
def __init__(self) -> None:
|
||||
self.display = False
|
||||
self.remove = AsyncMock()
|
||||
self.messages: list[HookSystemMessageLine] = []
|
||||
self.classes: set[str] = set()
|
||||
|
||||
async def add_message(self, _widget: object) -> None:
|
||||
def add_class(self, cls: str) -> None:
|
||||
self.classes.add(cls)
|
||||
|
||||
async def add_message(self, widget: HookSystemMessageLine) -> None:
|
||||
self.display = True
|
||||
self.messages.append(widget)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def hook_container_factory(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> list[FakeHookRunContainer]:
|
||||
created: list[FakeHookRunContainer] = []
|
||||
|
||||
def make_container() -> FakeHookRunContainer:
|
||||
container = FakeHookRunContainer()
|
||||
created.append(container)
|
||||
return container
|
||||
|
||||
monkeypatch.setattr(event_handler_module, "HookRunContainer", make_container)
|
||||
return created
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_hook_run_end_removes_empty_container(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
hook_container_factory: list[FakeHookRunContainer],
|
||||
) -> None:
|
||||
created_containers: list[FakeHookRunContainer] = []
|
||||
|
||||
def make_container() -> FakeHookRunContainer:
|
||||
container = FakeHookRunContainer()
|
||||
created_containers.append(container)
|
||||
return container
|
||||
|
||||
monkeypatch.setattr(event_handler_module, "HookRunContainer", make_container)
|
||||
|
||||
mount_callback = AsyncMock()
|
||||
handler = EventHandler(
|
||||
mount_callback=mount_callback, get_tools_collapsed=lambda: False
|
||||
|
|
@ -44,30 +61,22 @@ async def test_hook_run_end_removes_empty_container(
|
|||
await handler.handle_event(HookRunStartEvent())
|
||||
await handler.handle_event(HookRunEndEvent())
|
||||
|
||||
assert len(created_containers) == 1
|
||||
created_containers[0].remove.assert_awaited_once()
|
||||
assert handler._hook_run_container is None
|
||||
assert len(hook_container_factory) == 1
|
||||
hook_container_factory[0].remove.assert_awaited_once()
|
||||
assert "agent_turn" not in handler._hook_containers
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_hook_run_end_keeps_container_with_messages(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
hook_container_factory: list[FakeHookRunContainer],
|
||||
) -> None:
|
||||
created_containers: list[FakeHookRunContainer] = []
|
||||
|
||||
def make_container() -> FakeHookRunContainer:
|
||||
container = FakeHookRunContainer()
|
||||
created_containers.append(container)
|
||||
return container
|
||||
|
||||
monkeypatch.setattr(event_handler_module, "HookRunContainer", make_container)
|
||||
|
||||
mount_callback = AsyncMock()
|
||||
handler = EventHandler(
|
||||
mount_callback=mount_callback, get_tools_collapsed=lambda: False
|
||||
)
|
||||
|
||||
await handler.handle_event(HookRunStartEvent())
|
||||
await handler.handle_event(HookStartEvent(hook_name="post-turn"))
|
||||
await handler.handle_event(
|
||||
HookEndEvent(
|
||||
hook_name="post-turn", status=HookMessageSeverity.OK, content="Hook output"
|
||||
|
|
@ -75,7 +84,279 @@ async def test_hook_run_end_keeps_container_with_messages(
|
|||
)
|
||||
await handler.handle_event(HookRunEndEvent())
|
||||
|
||||
assert len(created_containers) == 1
|
||||
created_containers[0].remove.assert_not_awaited()
|
||||
assert created_containers[0].display is True
|
||||
assert handler._hook_run_container is None
|
||||
assert len(hook_container_factory) == 1
|
||||
hook_container_factory[0].remove.assert_not_awaited()
|
||||
assert hook_container_factory[0].display is True
|
||||
assert "agent_turn" not in handler._hook_containers
|
||||
|
||||
|
||||
def _tool_call_event(call_id: str) -> ToolCallEvent:
|
||||
return ToolCallEvent(
|
||||
tool_name="stub_tool",
|
||||
tool_class=FakeTool,
|
||||
args=FakeToolArgs(),
|
||||
tool_call_id=call_id,
|
||||
)
|
||||
|
||||
|
||||
def _tool_result_event(call_id: str) -> ToolResultEvent:
|
||||
return ToolResultEvent(
|
||||
tool_name="stub_tool",
|
||||
tool_class=FakeTool,
|
||||
result=None,
|
||||
cancelled=False,
|
||||
tool_call_id=call_id,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_before_tool_container_scoped_to_tool_call_id(
|
||||
hook_container_factory: list[FakeHookRunContainer],
|
||||
) -> None:
|
||||
"""Two concurrent tool calls each get their own before_tool container."""
|
||||
mount_callback = AsyncMock()
|
||||
handler = EventHandler(
|
||||
mount_callback=mount_callback, get_tools_collapsed=lambda: False
|
||||
)
|
||||
|
||||
# Two tool calls arrive
|
||||
await handler.handle_event(_tool_call_event("call_A"))
|
||||
await handler.handle_event(_tool_call_event("call_B"))
|
||||
|
||||
# before_tool starts for both, interleaved
|
||||
await handler.handle_event(
|
||||
HookRunStartEvent(
|
||||
scope=HookType.BEFORE_TOOL, tool_name="stub_tool", tool_call_id="call_A"
|
||||
)
|
||||
)
|
||||
await handler.handle_event(
|
||||
HookRunStartEvent(
|
||||
scope=HookType.BEFORE_TOOL, tool_name="stub_tool", tool_call_id="call_B"
|
||||
)
|
||||
)
|
||||
|
||||
# Two distinct containers were created.
|
||||
assert len(hook_container_factory) == 2
|
||||
assert "before_tool:call_A" in handler._hook_containers
|
||||
assert "before_tool:call_B" in handler._hook_containers
|
||||
assert (
|
||||
handler._hook_containers["before_tool:call_A"]
|
||||
is not handler._hook_containers["before_tool:call_B"]
|
||||
)
|
||||
|
||||
# End them — both are empty, both should be removed.
|
||||
await handler.handle_event(
|
||||
HookRunEndEvent(scope=HookType.BEFORE_TOOL, tool_call_id="call_A")
|
||||
)
|
||||
await handler.handle_event(
|
||||
HookRunEndEvent(scope=HookType.BEFORE_TOOL, tool_call_id="call_B")
|
||||
)
|
||||
assert "before_tool:call_A" not in handler._hook_containers
|
||||
assert "before_tool:call_B" not in handler._hook_containers
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_after_tool_container_anchors_after_tool_result(
|
||||
hook_container_factory: list[FakeHookRunContainer],
|
||||
) -> None:
|
||||
mount_callback = AsyncMock()
|
||||
handler = EventHandler(
|
||||
mount_callback=mount_callback, get_tools_collapsed=lambda: False
|
||||
)
|
||||
|
||||
await handler.handle_event(_tool_call_event("call_X"))
|
||||
await handler.handle_event(_tool_result_event("call_X"))
|
||||
# After-tool start mounts after the tool result, which is the current
|
||||
# anchor for this tool_call_id.
|
||||
await handler.handle_event(
|
||||
HookRunStartEvent(
|
||||
scope=HookType.AFTER_TOOL, tool_name="stub_tool", tool_call_id="call_X"
|
||||
)
|
||||
)
|
||||
assert "after_tool:call_X" in handler._hook_containers
|
||||
|
||||
# mount_callback was called with after=<tool_result_widget> for the after_tool
|
||||
# container. Inspect the last call's kwargs.
|
||||
last_call = mount_callback.call_args_list[-1]
|
||||
assert last_call.kwargs.get("after") is not None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_before_tool_container_for_unknown_tool_call_id(
|
||||
hook_container_factory: list[FakeHookRunContainer],
|
||||
) -> None:
|
||||
mount_callback = AsyncMock()
|
||||
handler = EventHandler(
|
||||
mount_callback=mount_callback, get_tools_collapsed=lambda: False
|
||||
)
|
||||
|
||||
await handler.handle_event(
|
||||
HookRunStartEvent(
|
||||
scope=HookType.BEFORE_TOOL, tool_name="bash", tool_call_id="unknown"
|
||||
)
|
||||
)
|
||||
last_call = mount_callback.call_args_list[-1]
|
||||
assert last_call.kwargs.get("after") is None
|
||||
assert last_call.kwargs.get("before") is None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_before_tool_container_mounts_before_tool_call_widget(
|
||||
hook_container_factory: list[FakeHookRunContainer],
|
||||
) -> None:
|
||||
mount_callback = AsyncMock()
|
||||
handler = EventHandler(
|
||||
mount_callback=mount_callback, get_tools_collapsed=lambda: False
|
||||
)
|
||||
|
||||
await handler.handle_event(_tool_call_event("call_Y"))
|
||||
tool_call_widget = handler._tool_call_anchors["call_Y"]
|
||||
|
||||
await handler.handle_event(
|
||||
HookRunStartEvent(
|
||||
scope=HookType.BEFORE_TOOL, tool_name="stub_tool", tool_call_id="call_Y"
|
||||
)
|
||||
)
|
||||
|
||||
last_call = mount_callback.call_args_list[-1]
|
||||
assert last_call.kwargs.get("before") is tool_call_widget
|
||||
assert last_call.kwargs.get("after") is None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_before_tool_run_end_keeps_tool_call_widget_as_anchor(
|
||||
hook_container_factory: list[FakeHookRunContainer],
|
||||
) -> None:
|
||||
mount_callback = AsyncMock()
|
||||
handler = EventHandler(
|
||||
mount_callback=mount_callback, get_tools_collapsed=lambda: False
|
||||
)
|
||||
|
||||
await handler.handle_event(_tool_call_event("call_Z"))
|
||||
tool_call_widget = handler._tool_call_anchors["call_Z"]
|
||||
|
||||
await handler.handle_event(
|
||||
HookRunStartEvent(
|
||||
scope=HookType.BEFORE_TOOL, tool_name="stub_tool", tool_call_id="call_Z"
|
||||
)
|
||||
)
|
||||
await handler.handle_event(HookStartEvent(hook_name="before"))
|
||||
await handler.handle_event(
|
||||
HookEndEvent(hook_name="before", status=HookMessageSeverity.OK, content="ok")
|
||||
)
|
||||
await handler.handle_event(
|
||||
HookRunEndEvent(scope=HookType.BEFORE_TOOL, tool_call_id="call_Z")
|
||||
)
|
||||
|
||||
# Even though the before_tool container has content and stays in the DOM,
|
||||
# the anchor for the next widget (the tool result) must remain the call
|
||||
# widget — the container lives *above* the call, not below it.
|
||||
assert handler._tool_call_anchors["call_Z"] is tool_call_widget
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_hook_end_routes_to_matching_container_when_chains_interleave(
|
||||
hook_container_factory: list[FakeHookRunContainer],
|
||||
) -> None:
|
||||
mount_callback = AsyncMock()
|
||||
handler = EventHandler(
|
||||
mount_callback=mount_callback, get_tools_collapsed=lambda: False
|
||||
)
|
||||
|
||||
await handler.handle_event(_tool_call_event("call_A"))
|
||||
await handler.handle_event(_tool_call_event("call_B"))
|
||||
|
||||
await handler.handle_event(
|
||||
HookRunStartEvent(
|
||||
scope=HookType.BEFORE_TOOL, tool_name="stub_tool", tool_call_id="call_A"
|
||||
)
|
||||
)
|
||||
assert len(hook_container_factory) == 1
|
||||
container_a = hook_container_factory[-1]
|
||||
|
||||
await handler.handle_event(HookStartEvent(hook_name="hook_a"))
|
||||
await handler.handle_event(
|
||||
HookRunStartEvent(
|
||||
scope=HookType.BEFORE_TOOL, tool_name="stub_tool", tool_call_id="call_B"
|
||||
)
|
||||
)
|
||||
assert len(hook_container_factory) == 2
|
||||
container_b = hook_container_factory[-1]
|
||||
assert container_a is not container_b
|
||||
|
||||
await handler.handle_event(
|
||||
HookEndEvent(
|
||||
hook_name="hook_a",
|
||||
status=HookMessageSeverity.OK,
|
||||
content="from A",
|
||||
scope=HookType.BEFORE_TOOL,
|
||||
tool_call_id="call_A",
|
||||
)
|
||||
)
|
||||
await handler.handle_event(HookStartEvent(hook_name="hook_b"))
|
||||
await handler.handle_event(
|
||||
HookEndEvent(
|
||||
hook_name="hook_b",
|
||||
status=HookMessageSeverity.OK,
|
||||
content="from B",
|
||||
scope=HookType.BEFORE_TOOL,
|
||||
tool_call_id="call_B",
|
||||
)
|
||||
)
|
||||
|
||||
assert len(container_a.messages) == 1
|
||||
assert len(container_b.messages) == 1
|
||||
assert container_a.messages[0]._content == "from A"
|
||||
assert container_b.messages[0]._content == "from B"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_hook_end_after_other_chain_ended_still_routes_correctly(
|
||||
hook_container_factory: list[FakeHookRunContainer],
|
||||
) -> None:
|
||||
mount_callback = AsyncMock()
|
||||
handler = EventHandler(
|
||||
mount_callback=mount_callback, get_tools_collapsed=lambda: False
|
||||
)
|
||||
|
||||
await handler.handle_event(_tool_call_event("call_A"))
|
||||
await handler.handle_event(_tool_call_event("call_B"))
|
||||
await handler.handle_event(
|
||||
HookRunStartEvent(
|
||||
scope=HookType.BEFORE_TOOL, tool_name="stub_tool", tool_call_id="call_A"
|
||||
)
|
||||
)
|
||||
container_a = hook_container_factory[-1]
|
||||
await handler.handle_event(HookStartEvent(hook_name="hook_a"))
|
||||
|
||||
await handler.handle_event(
|
||||
HookRunStartEvent(
|
||||
scope=HookType.BEFORE_TOOL, tool_name="stub_tool", tool_call_id="call_B"
|
||||
)
|
||||
)
|
||||
await handler.handle_event(HookStartEvent(hook_name="hook_b"))
|
||||
await handler.handle_event(
|
||||
HookEndEvent(
|
||||
hook_name="hook_b",
|
||||
status=HookMessageSeverity.OK,
|
||||
content="from B",
|
||||
scope=HookType.BEFORE_TOOL,
|
||||
tool_call_id="call_B",
|
||||
)
|
||||
)
|
||||
await handler.handle_event(
|
||||
HookRunEndEvent(scope=HookType.BEFORE_TOOL, tool_call_id="call_B")
|
||||
)
|
||||
|
||||
await handler.handle_event(
|
||||
HookEndEvent(
|
||||
hook_name="hook_a",
|
||||
status=HookMessageSeverity.OK,
|
||||
content="from A",
|
||||
scope=HookType.BEFORE_TOOL,
|
||||
tool_call_id="call_A",
|
||||
)
|
||||
)
|
||||
|
||||
assert len(container_a.messages) == 1
|
||||
assert container_a.messages[0]._content == "from A"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ from __future__ import annotations
|
|||
|
||||
import pytest
|
||||
|
||||
from vibe.cli.textual_ui.message_queue import MessageQueue, QueuedItemKind
|
||||
from vibe.cli.textual_ui.message_queue import MessageQueue, QueuedItem, QueuedItemKind
|
||||
|
||||
|
||||
def test_empty_queue_is_falsy() -> None:
|
||||
|
|
@ -38,6 +38,17 @@ def test_pop_last_returns_newest() -> None:
|
|||
assert [item.content for item in queue.items] == ["a", "b"]
|
||||
|
||||
|
||||
def test_pop_last_resumes_when_queue_becomes_empty() -> None:
|
||||
queue = MessageQueue()
|
||||
queue.append_prompt("a")
|
||||
queue.pause()
|
||||
|
||||
queue.pop_last()
|
||||
|
||||
assert not queue
|
||||
assert not queue.paused
|
||||
|
||||
|
||||
def test_pop_first_returns_oldest() -> None:
|
||||
queue = MessageQueue()
|
||||
queue.append_prompt("a")
|
||||
|
|
@ -74,11 +85,9 @@ def test_pause_and_resume() -> None:
|
|||
|
||||
def test_pause_is_idempotent() -> None:
|
||||
queue = MessageQueue()
|
||||
calls = []
|
||||
queue.set_change_listener(lambda: calls.append(None))
|
||||
queue.pause()
|
||||
queue.pause()
|
||||
assert len(calls) == 1
|
||||
assert queue.paused
|
||||
|
||||
|
||||
def test_clear_resets_state() -> None:
|
||||
|
|
@ -90,34 +99,30 @@ def test_clear_resets_state() -> None:
|
|||
assert not queue.paused
|
||||
|
||||
|
||||
def test_change_listener_fires_on_mutations() -> None:
|
||||
def test_prepend_prompts_inserts_at_head_preserving_order() -> None:
|
||||
queue = MessageQueue()
|
||||
calls: list[None] = []
|
||||
queue.set_change_listener(lambda: calls.append(None))
|
||||
|
||||
queue.append_prompt("a")
|
||||
assert len(calls) == 1
|
||||
|
||||
queue.append_bash("ls")
|
||||
assert len(calls) == 2
|
||||
|
||||
queue.pop_last()
|
||||
assert len(calls) == 3
|
||||
|
||||
queue.pause()
|
||||
assert len(calls) == 4
|
||||
|
||||
queue.resume()
|
||||
assert len(calls) == 5
|
||||
queue.append_prompt("x")
|
||||
queue.append_prompt("y")
|
||||
queue.prepend_prompts([
|
||||
QueuedItem(QueuedItemKind.PROMPT, "a"),
|
||||
QueuedItem(QueuedItemKind.PROMPT, "b"),
|
||||
])
|
||||
assert [item.content for item in queue.items] == ["a", "b", "x", "y"]
|
||||
|
||||
|
||||
def test_change_listener_can_be_cleared() -> None:
|
||||
def test_prepend_prompts_empty_is_noop() -> None:
|
||||
queue = MessageQueue()
|
||||
calls: list[None] = []
|
||||
queue.set_change_listener(lambda: calls.append(None))
|
||||
queue.set_change_listener(None)
|
||||
queue.append_prompt("a")
|
||||
assert calls == []
|
||||
queue.append_prompt("x")
|
||||
queue.prepend_prompts([])
|
||||
assert [item.content for item in queue.items] == ["x"]
|
||||
|
||||
|
||||
def test_append_prompt_with_skill_name() -> None:
|
||||
queue = MessageQueue()
|
||||
queue.append_prompt("expanded prompt", skill_name="my-skill")
|
||||
item = queue.items[0]
|
||||
assert item.skill_name == "my-skill"
|
||||
assert item.content == "expanded prompt"
|
||||
|
||||
|
||||
def test_items_returns_copy() -> None:
|
||||
|
|
|
|||
200
tests/cli/textual_ui/test_message_queue_ui.py
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
|
||||
import pytest
|
||||
|
||||
from tests.conftest import build_test_vibe_app
|
||||
from vibe.cli.textual_ui.app import VibeApp
|
||||
from vibe.cli.textual_ui.widgets.chat_input.container import ChatInputContainer
|
||||
from vibe.cli.textual_ui.widgets.messages import (
|
||||
BashOutputMessage,
|
||||
QueueHeaderMessage,
|
||||
WarningMessage,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def vibe_app() -> VibeApp:
|
||||
return build_test_vibe_app()
|
||||
|
||||
|
||||
async def _wait_until(pilot, predicate, timeout: float = 2.0) -> bool:
|
||||
deadline = time.monotonic() + timeout
|
||||
while time.monotonic() < deadline:
|
||||
if predicate():
|
||||
return True
|
||||
await pilot.pause(0.05)
|
||||
return False
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_no_queue_header_when_empty(vibe_app: VibeApp) -> None:
|
||||
async with vibe_app.run_test():
|
||||
headers = list(vibe_app.query(QueueHeaderMessage))
|
||||
assert headers == []
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_bash_submitted_during_running_bash_is_queued(vibe_app: VibeApp) -> None:
|
||||
async with vibe_app.run_test() as pilot:
|
||||
chat_input = vibe_app.query_one(ChatInputContainer)
|
||||
chat_input.value = "!sleep 0.3"
|
||||
await pilot.press("enter")
|
||||
|
||||
await _wait_until(pilot, lambda: vibe_app._bash_task is not None, timeout=1.0)
|
||||
|
||||
chat_input.value = "!echo queued"
|
||||
await pilot.press("enter")
|
||||
|
||||
assert len(vibe_app._input_queue) == 1
|
||||
assert vibe_app._input_queue.items[0].content == "echo queued"
|
||||
|
||||
headers = list(vibe_app.query(QueueHeaderMessage))
|
||||
assert len(headers) == 1
|
||||
|
||||
queued_bashes = [w for w in vibe_app.query(BashOutputMessage) if w._queued]
|
||||
assert len(queued_bashes) == 1
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_slash_command_rejected_with_warning_when_busy(vibe_app: VibeApp) -> None:
|
||||
async with vibe_app.run_test() as pilot:
|
||||
chat_input = vibe_app.query_one(ChatInputContainer)
|
||||
chat_input.value = "!sleep 0.3"
|
||||
await pilot.press("enter")
|
||||
|
||||
await _wait_until(pilot, lambda: vibe_app._bash_task is not None, timeout=1.0)
|
||||
|
||||
chat_input.value = "/help"
|
||||
await pilot.press("enter")
|
||||
|
||||
assert not list(vibe_app.query(WarningMessage))
|
||||
assert any(
|
||||
"Slash commands cannot be queued" in notification.message
|
||||
for notification in vibe_app._notifications
|
||||
)
|
||||
assert len(vibe_app._input_queue) == 0
|
||||
assert chat_input.value.startswith("/help")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_ctrl_c_pops_last_queued_item_lifo(vibe_app: VibeApp) -> None:
|
||||
async with vibe_app.run_test() as pilot:
|
||||
chat_input = vibe_app.query_one(ChatInputContainer)
|
||||
chat_input.value = "!sleep 2"
|
||||
await pilot.press("enter")
|
||||
|
||||
await _wait_until(pilot, lambda: vibe_app._bash_task is not None, timeout=2.0)
|
||||
|
||||
chat_input.value = "!echo first"
|
||||
await pilot.press("enter")
|
||||
chat_input.value = "!echo second"
|
||||
await pilot.press("enter")
|
||||
|
||||
assert len(vibe_app._input_queue) == 2
|
||||
|
||||
await pilot.press("ctrl+c")
|
||||
assert len(vibe_app._input_queue) == 1
|
||||
assert vibe_app._input_queue.items[0].content == "echo first"
|
||||
|
||||
await pilot.press("escape")
|
||||
await _wait_until(pilot, lambda: vibe_app._bash_task is None, timeout=5.0)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_escape_pauses_queue_when_job_running(vibe_app: VibeApp) -> None:
|
||||
async with vibe_app.run_test() as pilot:
|
||||
chat_input = vibe_app.query_one(ChatInputContainer)
|
||||
chat_input.value = "!sleep 2"
|
||||
await pilot.press("enter")
|
||||
|
||||
await _wait_until(pilot, lambda: vibe_app._bash_task is not None, timeout=2.0)
|
||||
|
||||
chat_input.value = "!echo queued"
|
||||
await pilot.press("enter")
|
||||
assert len(vibe_app._input_queue) == 1
|
||||
|
||||
await pilot.press("escape")
|
||||
assert vibe_app._input_queue.paused
|
||||
assert len(vibe_app._input_queue) == 1
|
||||
|
||||
await _wait_until(pilot, lambda: vibe_app._bash_task is None, timeout=5.0)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_drain_runs_queued_bashes_in_fifo_order(vibe_app: VibeApp) -> None:
|
||||
async with vibe_app.run_test() as pilot:
|
||||
chat_input = vibe_app.query_one(ChatInputContainer)
|
||||
chat_input.value = "!sleep 0.2"
|
||||
await pilot.press("enter")
|
||||
|
||||
await _wait_until(pilot, lambda: vibe_app._bash_task is not None, timeout=1.0)
|
||||
|
||||
chat_input.value = "!echo first"
|
||||
await pilot.press("enter")
|
||||
chat_input.value = "!echo second"
|
||||
await pilot.press("enter")
|
||||
|
||||
await _wait_until(
|
||||
pilot,
|
||||
lambda: (
|
||||
len(list(vibe_app.query(BashOutputMessage))) == 3
|
||||
and all(not m._pending for m in vibe_app.query(BashOutputMessage))
|
||||
),
|
||||
timeout=5.0,
|
||||
)
|
||||
|
||||
msgs = list(vibe_app.query(BashOutputMessage))
|
||||
assert len(msgs) == 3
|
||||
assert vibe_app._input_queue.paused is False
|
||||
assert len(vibe_app._input_queue) == 0
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_enter_on_empty_input_flushes_paused_queue(vibe_app: VibeApp) -> None:
|
||||
async with vibe_app.run_test() as pilot:
|
||||
chat_input = vibe_app.query_one(ChatInputContainer)
|
||||
chat_input.value = "!sleep 2"
|
||||
await pilot.press("enter")
|
||||
|
||||
await _wait_until(pilot, lambda: vibe_app._bash_task is not None, timeout=2.0)
|
||||
|
||||
chat_input.value = "!echo queued"
|
||||
await pilot.press("enter")
|
||||
assert len(vibe_app._input_queue) == 1
|
||||
|
||||
await pilot.press("escape")
|
||||
assert vibe_app._input_queue.paused
|
||||
|
||||
await _wait_until(pilot, lambda: vibe_app._bash_task is None, timeout=10.0)
|
||||
|
||||
chat_input.value = ""
|
||||
await pilot.press("enter")
|
||||
|
||||
await _wait_until(
|
||||
pilot,
|
||||
lambda: (
|
||||
not vibe_app._input_queue.paused and len(vibe_app._input_queue) == 0
|
||||
),
|
||||
timeout=10.0,
|
||||
)
|
||||
|
||||
assert not vibe_app._input_queue.paused
|
||||
assert len(vibe_app._input_queue) == 0
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_quit_warning_shows_queue_count(vibe_app: VibeApp) -> None:
|
||||
async with vibe_app.run_test():
|
||||
vibe_app._input_queue.append_prompt("a")
|
||||
vibe_app._input_queue.append_prompt("b")
|
||||
warning = vibe_app._queue.quit_warning_extra()
|
||||
assert warning == "2 queued messages will be discarded"
|
||||
|
||||
vibe_app._input_queue.pop_last()
|
||||
warning = vibe_app._queue.quit_warning_extra()
|
||||
assert warning == "1 queued message will be discarded"
|
||||
|
||||
vibe_app._input_queue.pop_last()
|
||||
assert vibe_app._queue.quit_warning_extra() == ""
|
||||
|
|
@ -92,11 +92,12 @@ class TestActionInterruptOrQuit:
|
|||
mock_container.value = ""
|
||||
with (
|
||||
patch.object(app, "_get_chat_input", return_value=mock_container),
|
||||
patch.object(app, "_try_interrupt", return_value=False),
|
||||
patch.object(app, "_try_interrupt_no_job_steps", return_value=False),
|
||||
patch.object(app, "_try_interrupt_running_job", return_value=False),
|
||||
patch.object(app._quit_manager, "request_confirmation") as mock_confirm,
|
||||
):
|
||||
app.action_interrupt_or_quit()
|
||||
mock_confirm.assert_called_once_with("Ctrl+C")
|
||||
mock_confirm.assert_called_once_with("Ctrl+C", "")
|
||||
|
||||
def test_quits_on_confirmed(self, app: VibeApp) -> None:
|
||||
app._quit_manager._confirm_time = time.monotonic()
|
||||
|
|
@ -111,7 +112,9 @@ class TestActionInterruptOrQuit:
|
|||
def test_interrupts_before_requesting_confirmation(self, app: VibeApp) -> None:
|
||||
with (
|
||||
patch.object(app, "_get_chat_input", return_value=None),
|
||||
patch.object(app, "_try_interrupt", return_value=True) as mock_interrupt,
|
||||
patch.object(
|
||||
app, "_try_interrupt_no_job_steps", return_value=True
|
||||
) as mock_interrupt,
|
||||
patch.object(app._quit_manager, "request_confirmation") as mock_confirm,
|
||||
):
|
||||
app.action_interrupt_or_quit()
|
||||
|
|
@ -123,11 +126,12 @@ class TestActionInterruptOrQuit:
|
|||
) -> None:
|
||||
with (
|
||||
patch.object(app, "_get_chat_input", return_value=None),
|
||||
patch.object(app, "_try_interrupt", return_value=False),
|
||||
patch.object(app, "_try_interrupt_no_job_steps", return_value=False),
|
||||
patch.object(app, "_try_interrupt_running_job", return_value=False),
|
||||
patch.object(app._quit_manager, "request_confirmation") as mock_confirm,
|
||||
):
|
||||
app.action_interrupt_or_quit()
|
||||
mock_confirm.assert_called_once_with("Ctrl+C")
|
||||
mock_confirm.assert_called_once_with("Ctrl+C", "")
|
||||
|
||||
|
||||
class TestActionDeleteRightOrQuit:
|
||||
|
|
@ -148,7 +152,7 @@ class TestActionDeleteRightOrQuit:
|
|||
patch.object(app._quit_manager, "request_confirmation") as mock_confirm,
|
||||
):
|
||||
app.action_delete_right_or_quit()
|
||||
mock_confirm.assert_called_once_with("Ctrl+D")
|
||||
mock_confirm.assert_called_once_with("Ctrl+D", "")
|
||||
|
||||
def test_quits_on_confirmed(self, app: VibeApp) -> None:
|
||||
app._quit_manager._confirm_time = time.monotonic()
|
||||
|
|
@ -166,4 +170,15 @@ class TestActionDeleteRightOrQuit:
|
|||
patch.object(app._quit_manager, "request_confirmation") as mock_confirm,
|
||||
):
|
||||
app.action_delete_right_or_quit()
|
||||
mock_confirm.assert_called_once_with("Ctrl+D")
|
||||
mock_confirm.assert_called_once_with("Ctrl+D", "")
|
||||
|
||||
def test_shows_queue_warning_when_queue_non_empty(self, app: VibeApp) -> None:
|
||||
app._input_queue.append_prompt("queued")
|
||||
with (
|
||||
patch.object(app, "_get_chat_input", return_value=None),
|
||||
patch.object(app._quit_manager, "request_confirmation") as mock_confirm,
|
||||
):
|
||||
app.action_delete_right_or_quit()
|
||||
mock_confirm.assert_called_once_with(
|
||||
"Ctrl+D", "1 queued message will be discarded"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,14 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from vibe.cli.textual_ui.widgets.tool_widgets import _strip_line_numbers
|
||||
from pydantic import BaseModel
|
||||
|
||||
from vibe.cli.textual_ui.widgets.collapsible import CollapsibleSection
|
||||
from vibe.cli.textual_ui.widgets.tool_widgets import (
|
||||
ToolResultWidget,
|
||||
_fenced_code_block,
|
||||
_strip_line_numbers,
|
||||
get_result_widget,
|
||||
)
|
||||
|
||||
|
||||
def test_strips_numbered_prefixes() -> None:
|
||||
|
|
@ -16,3 +24,57 @@ def test_leaves_warning_lines_untouched() -> None:
|
|||
def test_preserves_arrows_inside_content() -> None:
|
||||
content = " 1→a → b → c"
|
||||
assert _strip_line_numbers(content) == "a → b → c"
|
||||
|
||||
|
||||
def test_fence_uses_three_backticks_for_plain_content() -> None:
|
||||
block = _fenced_code_block("hello\nworld", "py")
|
||||
assert block == "```py\nhello\nworld\n```"
|
||||
|
||||
|
||||
def test_fence_outgrows_embedded_triple_backticks() -> None:
|
||||
content = "before\n```\n[click me](http://evil)\n```\nafter"
|
||||
block = _fenced_code_block(content, "md")
|
||||
fence = "````"
|
||||
assert block == f"{fence}md\n{content}\n{fence}"
|
||||
assert block.startswith(fence)
|
||||
assert block.endswith(fence)
|
||||
|
||||
|
||||
def test_fence_outgrows_longest_backtick_run() -> None:
|
||||
content = "a ```` b ``` c"
|
||||
block = _fenced_code_block(content, "")
|
||||
assert block.startswith("`````")
|
||||
assert block.endswith("`````")
|
||||
|
||||
|
||||
def test_fence_strips_newlines_from_ext() -> None:
|
||||
block = _fenced_code_block("safe", "x\n[click](http://evil)")
|
||||
assert block == "```xclickhttpevil\nsafe\n```"
|
||||
assert "\n[click]" not in block
|
||||
|
||||
|
||||
def test_fence_strips_backticks_from_ext() -> None:
|
||||
block = _fenced_code_block("safe", "py`\n```md")
|
||||
first_line = block.split("\n", 1)[0]
|
||||
assert first_line == "```pymd"
|
||||
|
||||
|
||||
def test_fence_caps_ext_length() -> None:
|
||||
block = _fenced_code_block("safe", "a" * 500)
|
||||
first_line = block.split("\n", 1)[0]
|
||||
assert first_line == "```" + "a" * 32
|
||||
|
||||
|
||||
def test_unknown_tool_uses_default_widget() -> None:
|
||||
widget = get_result_widget("unknown_tool", None, True, "done")
|
||||
assert type(widget) is ToolResultWidget
|
||||
|
||||
|
||||
def test_default_widget_renders_fields_collapsibly() -> None:
|
||||
class _Result(BaseModel):
|
||||
server: str
|
||||
text: str
|
||||
|
||||
widget = ToolResultWidget(_Result(server="s", text="hello"), True, "ok")
|
||||
children = list(widget.compose())
|
||||
assert any(isinstance(child, CollapsibleSection) for child in children)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from datetime import UTC, datetime, timedelta
|
||||
from typing import cast
|
||||
|
||||
import pytest
|
||||
from rich.text import Text
|
||||
from textual.widgets import OptionList
|
||||
|
||||
from vibe.cli.textual_ui.widgets.session_picker import (
|
||||
SessionPickerApp,
|
||||
|
|
@ -48,6 +51,12 @@ def sample_latest_messages() -> dict[str, str]:
|
|||
}
|
||||
|
||||
|
||||
def assert_delete_state(picker: SessionPickerApp, *, kind: str, option_id: str) -> None:
|
||||
assert picker._delete_state is not None
|
||||
assert picker._delete_state.kind == kind
|
||||
assert picker._delete_state.option_id == option_id
|
||||
|
||||
|
||||
class TestFormatRelativeTime:
|
||||
def test_just_now(self) -> None:
|
||||
now = datetime.now(UTC).isoformat()
|
||||
|
|
@ -99,6 +108,7 @@ class TestSessionPickerAppInit:
|
|||
)
|
||||
assert picker._sessions == sample_sessions
|
||||
assert picker._latest_messages == sample_latest_messages
|
||||
assert picker._current_session_id is None
|
||||
|
||||
def test_id_is_sessionpicker_app(self) -> None:
|
||||
picker = SessionPickerApp(sessions=[], latest_messages={})
|
||||
|
|
@ -107,6 +117,29 @@ class TestSessionPickerAppInit:
|
|||
def test_can_focus_children_is_true(self) -> None:
|
||||
assert SessionPickerApp.can_focus_children is True
|
||||
|
||||
def test_delete_confirmation_state_starts_empty(
|
||||
self,
|
||||
sample_sessions: list[ResumeSessionInfo],
|
||||
sample_latest_messages: dict[str, str],
|
||||
) -> None:
|
||||
picker = SessionPickerApp(
|
||||
sessions=sample_sessions, latest_messages=sample_latest_messages
|
||||
)
|
||||
assert picker._delete_state is None
|
||||
|
||||
def test_has_sessions_tracks_session_list(
|
||||
self,
|
||||
sample_sessions: list[ResumeSessionInfo],
|
||||
sample_latest_messages: dict[str, str],
|
||||
) -> None:
|
||||
picker = SessionPickerApp(
|
||||
sessions=sample_sessions, latest_messages=sample_latest_messages
|
||||
)
|
||||
assert picker.has_sessions is True
|
||||
|
||||
empty_picker = SessionPickerApp(sessions=[], latest_messages={})
|
||||
assert empty_picker.has_sessions is False
|
||||
|
||||
|
||||
class TestSessionPickerMessages:
|
||||
def test_session_selected_stores_option_id(self) -> None:
|
||||
|
|
@ -129,16 +162,377 @@ class TestSessionPickerMessages:
|
|||
msg = SessionPickerApp.Cancelled()
|
||||
assert isinstance(msg, SessionPickerApp.Cancelled)
|
||||
|
||||
def test_session_delete_requested_stores_session_info(self) -> None:
|
||||
msg = SessionPickerApp.SessionDeleteRequested(
|
||||
"local:test-session-id", "local", "test-session-id"
|
||||
)
|
||||
assert msg.option_id == "local:test-session-id"
|
||||
assert msg.source == "local"
|
||||
assert msg.session_id == "test-session-id"
|
||||
|
||||
|
||||
class TestSessionPickerAppBindings:
|
||||
def _get_binding_keys(self) -> list[str]:
|
||||
keys = []
|
||||
for binding in SessionPickerApp.BINDINGS:
|
||||
if isinstance(binding, tuple) and len(binding) >= 1:
|
||||
keys.append(binding[0])
|
||||
keys.extend(binding[0].split(","))
|
||||
else:
|
||||
keys.append(binding.key)
|
||||
keys.extend(binding.key.split(","))
|
||||
return keys
|
||||
|
||||
def test_has_escape_binding(self) -> None:
|
||||
assert "escape" in self._get_binding_keys()
|
||||
|
||||
def test_has_delete_binding(self) -> None:
|
||||
assert "d" in self._get_binding_keys()
|
||||
assert "D" in self._get_binding_keys()
|
||||
|
||||
|
||||
class TestSessionPickerSessionRemoval:
|
||||
def test_first_delete_request_enters_confirmation(
|
||||
self,
|
||||
sample_sessions: list[ResumeSessionInfo],
|
||||
sample_latest_messages: dict[str, str],
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
picker = SessionPickerApp(
|
||||
sessions=sample_sessions, latest_messages=sample_latest_messages
|
||||
)
|
||||
option_list = FakeOptionList(highlighted_option_id="local:session-a")
|
||||
posted_messages: list[object] = []
|
||||
monkeypatch.setattr(picker, "query_one", lambda _selector: option_list)
|
||||
monkeypatch.setattr(picker, "post_message", posted_messages.append)
|
||||
|
||||
picker.action_request_delete()
|
||||
|
||||
assert_delete_state(picker, kind="confirmation", option_id="local:session-a")
|
||||
assert option_list.replaced_prompts[-1].option_id == "local:session-a"
|
||||
assert (
|
||||
"Press D again to delete" in option_list.replaced_prompts[-1].prompt.plain
|
||||
)
|
||||
assert posted_messages == []
|
||||
|
||||
def test_second_delete_request_posts_delete_message(
|
||||
self,
|
||||
sample_sessions: list[ResumeSessionInfo],
|
||||
sample_latest_messages: dict[str, str],
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
picker = SessionPickerApp(
|
||||
sessions=sample_sessions, latest_messages=sample_latest_messages
|
||||
)
|
||||
option_list = FakeOptionList(highlighted_option_id="local:session-a")
|
||||
posted_messages: list[object] = []
|
||||
monkeypatch.setattr(picker, "query_one", lambda _selector: option_list)
|
||||
monkeypatch.setattr(picker, "post_message", posted_messages.append)
|
||||
|
||||
picker.action_request_delete()
|
||||
picker.action_request_delete()
|
||||
|
||||
assert_delete_state(picker, kind="pending", option_id="local:session-a")
|
||||
assert option_list.replaced_prompts[-1].option_id == "local:session-a"
|
||||
assert "Deleting..." in option_list.replaced_prompts[-1].prompt.plain
|
||||
assert len(posted_messages) == 1
|
||||
message = posted_messages[0]
|
||||
assert isinstance(message, SessionPickerApp.SessionDeleteRequested)
|
||||
assert message.option_id == "local:session-a"
|
||||
assert message.source == "local"
|
||||
assert message.session_id == "session-a"
|
||||
|
||||
def test_delete_confirmation_is_consumed_after_request(
|
||||
self,
|
||||
sample_sessions: list[ResumeSessionInfo],
|
||||
sample_latest_messages: dict[str, str],
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
picker = SessionPickerApp(
|
||||
sessions=sample_sessions, latest_messages=sample_latest_messages
|
||||
)
|
||||
option_list = FakeOptionList(highlighted_option_id="local:session-a")
|
||||
posted_messages: list[object] = []
|
||||
monkeypatch.setattr(picker, "query_one", lambda _selector: option_list)
|
||||
monkeypatch.setattr(picker, "post_message", posted_messages.append)
|
||||
|
||||
picker.action_request_delete()
|
||||
picker.action_request_delete()
|
||||
picker.action_request_delete()
|
||||
|
||||
assert len(posted_messages) == 1
|
||||
assert_delete_state(picker, kind="pending", option_id="local:session-a")
|
||||
assert option_list.replaced_prompts[-1].option_id == "local:session-a"
|
||||
assert "Deleting..." in option_list.replaced_prompts[-1].prompt.plain
|
||||
|
||||
def test_delete_request_shows_feedback_for_remote_sessions(
|
||||
self,
|
||||
sample_sessions: list[ResumeSessionInfo],
|
||||
sample_latest_messages: dict[str, str],
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
picker = SessionPickerApp(
|
||||
sessions=sample_sessions, latest_messages=sample_latest_messages
|
||||
)
|
||||
option_list = FakeOptionList(highlighted_option_id="remote:session-c")
|
||||
posted_messages: list[object] = []
|
||||
monkeypatch.setattr(picker, "query_one", lambda _selector: option_list)
|
||||
monkeypatch.setattr(picker, "post_message", posted_messages.append)
|
||||
|
||||
picker.action_request_delete()
|
||||
|
||||
assert_delete_state(picker, kind="feedback", option_id="remote:session-c")
|
||||
assert option_list.replaced_prompts[-1].option_id == "remote:session-c"
|
||||
assert (
|
||||
"Can't delete remote session"
|
||||
in option_list.replaced_prompts[-1].prompt.plain
|
||||
)
|
||||
assert posted_messages == []
|
||||
|
||||
def test_delete_request_shows_feedback_for_current_session(
|
||||
self,
|
||||
sample_sessions: list[ResumeSessionInfo],
|
||||
sample_latest_messages: dict[str, str],
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
picker = SessionPickerApp(
|
||||
sessions=sample_sessions,
|
||||
latest_messages=sample_latest_messages,
|
||||
current_session_id="session-a",
|
||||
)
|
||||
option_list = FakeOptionList(highlighted_option_id="local:session-a")
|
||||
posted_messages: list[object] = []
|
||||
monkeypatch.setattr(picker, "query_one", lambda _selector: option_list)
|
||||
monkeypatch.setattr(picker, "post_message", posted_messages.append)
|
||||
|
||||
picker.action_request_delete()
|
||||
|
||||
assert_delete_state(picker, kind="feedback", option_id="local:session-a")
|
||||
assert option_list.replaced_prompts[-1].option_id == "local:session-a"
|
||||
assert (
|
||||
"Can't delete current session"
|
||||
in option_list.replaced_prompts[-1].prompt.plain
|
||||
)
|
||||
assert posted_messages == []
|
||||
|
||||
picker.action_request_delete()
|
||||
|
||||
assert_delete_state(picker, kind="feedback", option_id="local:session-a")
|
||||
assert posted_messages == []
|
||||
|
||||
def test_pending_delete_blocks_resume_selection(
|
||||
self,
|
||||
sample_sessions: list[ResumeSessionInfo],
|
||||
sample_latest_messages: dict[str, str],
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
picker = SessionPickerApp(
|
||||
sessions=sample_sessions, latest_messages=sample_latest_messages
|
||||
)
|
||||
option_list = FakeOptionList(highlighted_option_id="local:session-a")
|
||||
posted_messages: list[object] = []
|
||||
monkeypatch.setattr(picker, "query_one", lambda _selector: option_list)
|
||||
monkeypatch.setattr(picker, "post_message", posted_messages.append)
|
||||
|
||||
picker.action_request_delete()
|
||||
picker.action_request_delete()
|
||||
picker.on_option_list_option_selected(
|
||||
cast(OptionList.OptionSelected, FakeOptionEvent("local:session-a"))
|
||||
)
|
||||
picker.on_option_list_option_selected(
|
||||
cast(OptionList.OptionSelected, FakeOptionEvent("local:session-b"))
|
||||
)
|
||||
|
||||
assert len(posted_messages) == 1
|
||||
assert isinstance(posted_messages[0], SessionPickerApp.SessionDeleteRequested)
|
||||
assert_delete_state(picker, kind="pending", option_id="local:session-a")
|
||||
|
||||
def test_clear_pending_delete_restores_session_option(
|
||||
self,
|
||||
sample_sessions: list[ResumeSessionInfo],
|
||||
sample_latest_messages: dict[str, str],
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
picker = SessionPickerApp(
|
||||
sessions=sample_sessions, latest_messages=sample_latest_messages
|
||||
)
|
||||
option_list = FakeOptionList(highlighted_option_id="local:session-a")
|
||||
posted_messages: list[object] = []
|
||||
monkeypatch.setattr(picker, "query_one", lambda _selector: option_list)
|
||||
monkeypatch.setattr(picker, "post_message", posted_messages.append)
|
||||
|
||||
picker.action_request_delete()
|
||||
picker.action_request_delete()
|
||||
|
||||
assert picker.clear_pending_delete("local:session-a") is True
|
||||
assert picker._delete_state is None
|
||||
assert option_list.replaced_prompts[-1].option_id == "local:session-a"
|
||||
assert "Help me fix this bug" in option_list.replaced_prompts[-1].prompt.plain
|
||||
|
||||
def test_highlighting_another_session_clears_confirmation(
|
||||
self,
|
||||
sample_sessions: list[ResumeSessionInfo],
|
||||
sample_latest_messages: dict[str, str],
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
picker = SessionPickerApp(
|
||||
sessions=sample_sessions, latest_messages=sample_latest_messages
|
||||
)
|
||||
option_list = FakeOptionList(highlighted_option_id="local:session-a")
|
||||
monkeypatch.setattr(picker, "query_one", lambda _selector: option_list)
|
||||
picker.action_request_delete()
|
||||
|
||||
picker.on_option_list_option_highlighted(
|
||||
cast(OptionList.OptionHighlighted, FakeOptionEvent("local:session-b"))
|
||||
)
|
||||
|
||||
assert picker._delete_state is None
|
||||
assert option_list.replaced_prompts[-1].option_id == "local:session-a"
|
||||
assert "Help me fix this bug" in option_list.replaced_prompts[-1].prompt.plain
|
||||
|
||||
def test_highlighting_another_session_clears_delete_feedback(
|
||||
self,
|
||||
sample_sessions: list[ResumeSessionInfo],
|
||||
sample_latest_messages: dict[str, str],
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
picker = SessionPickerApp(
|
||||
sessions=sample_sessions, latest_messages=sample_latest_messages
|
||||
)
|
||||
option_list = FakeOptionList(highlighted_option_id="remote:session-c")
|
||||
monkeypatch.setattr(picker, "query_one", lambda _selector: option_list)
|
||||
picker.action_request_delete()
|
||||
|
||||
picker.on_option_list_option_highlighted(
|
||||
cast(OptionList.OptionHighlighted, FakeOptionEvent("local:session-b"))
|
||||
)
|
||||
|
||||
assert picker._delete_state is None
|
||||
assert option_list.replaced_prompts[-1].option_id == "remote:session-c"
|
||||
assert (
|
||||
"Add unit tests for the API"
|
||||
in option_list.replaced_prompts[-1].prompt.plain
|
||||
)
|
||||
|
||||
def test_escape_clears_confirmation_before_cancelling(
|
||||
self,
|
||||
sample_sessions: list[ResumeSessionInfo],
|
||||
sample_latest_messages: dict[str, str],
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
picker = SessionPickerApp(
|
||||
sessions=sample_sessions, latest_messages=sample_latest_messages
|
||||
)
|
||||
option_list = FakeOptionList(highlighted_option_id="local:session-a")
|
||||
posted_messages: list[object] = []
|
||||
monkeypatch.setattr(picker, "query_one", lambda _selector: option_list)
|
||||
monkeypatch.setattr(picker, "post_message", posted_messages.append)
|
||||
picker.action_request_delete()
|
||||
|
||||
picker.action_cancel()
|
||||
|
||||
assert picker._delete_state is None
|
||||
assert posted_messages == []
|
||||
|
||||
picker.action_cancel()
|
||||
|
||||
assert len(posted_messages) == 1
|
||||
assert isinstance(posted_messages[0], SessionPickerApp.Cancelled)
|
||||
|
||||
def test_escape_clears_delete_feedback_before_cancelling(
|
||||
self,
|
||||
sample_sessions: list[ResumeSessionInfo],
|
||||
sample_latest_messages: dict[str, str],
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
picker = SessionPickerApp(
|
||||
sessions=sample_sessions, latest_messages=sample_latest_messages
|
||||
)
|
||||
option_list = FakeOptionList(highlighted_option_id="remote:session-c")
|
||||
posted_messages: list[object] = []
|
||||
monkeypatch.setattr(picker, "query_one", lambda _selector: option_list)
|
||||
monkeypatch.setattr(picker, "post_message", posted_messages.append)
|
||||
picker.action_request_delete()
|
||||
|
||||
picker.action_cancel()
|
||||
|
||||
assert picker._delete_state is None
|
||||
assert posted_messages == []
|
||||
|
||||
picker.action_cancel()
|
||||
|
||||
assert len(posted_messages) == 1
|
||||
assert isinstance(posted_messages[0], SessionPickerApp.Cancelled)
|
||||
|
||||
def test_remove_session_updates_picker_state(
|
||||
self,
|
||||
sample_sessions: list[ResumeSessionInfo],
|
||||
sample_latest_messages: dict[str, str],
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
picker = SessionPickerApp(
|
||||
sessions=sample_sessions, latest_messages=sample_latest_messages
|
||||
)
|
||||
option_list = FakeOptionList(highlighted_option_id="local:session-a")
|
||||
monkeypatch.setattr(picker, "query_one", lambda _selector: option_list)
|
||||
picker.action_request_delete()
|
||||
assert_delete_state(picker, kind="confirmation", option_id="local:session-a")
|
||||
|
||||
assert picker.remove_session("local:session-a") is True
|
||||
|
||||
assert [session.option_id for session in picker._sessions] == [
|
||||
"local:session-b",
|
||||
"remote:session-c",
|
||||
]
|
||||
assert "local:session-a" not in picker._latest_messages
|
||||
assert picker._delete_state is None
|
||||
assert option_list.removed_option_ids == ["local:session-a"]
|
||||
|
||||
def test_remove_missing_session_returns_false(
|
||||
self,
|
||||
sample_sessions: list[ResumeSessionInfo],
|
||||
sample_latest_messages: dict[str, str],
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
picker = SessionPickerApp(
|
||||
sessions=sample_sessions, latest_messages=sample_latest_messages
|
||||
)
|
||||
option_list = FakeOptionList()
|
||||
monkeypatch.setattr(picker, "query_one", lambda _selector: option_list)
|
||||
|
||||
assert picker.remove_session("local:missing") is False
|
||||
|
||||
assert picker._sessions == sample_sessions
|
||||
assert picker._latest_messages == sample_latest_messages
|
||||
assert option_list.removed_option_ids == []
|
||||
|
||||
|
||||
class FakeOption:
|
||||
def __init__(self, option_id: str) -> None:
|
||||
self.id = option_id
|
||||
|
||||
|
||||
class FakeOptionEvent:
|
||||
def __init__(self, option_id: str) -> None:
|
||||
self.option = FakeOption(option_id)
|
||||
|
||||
|
||||
class ReplacedPrompt:
|
||||
def __init__(self, option_id: str, prompt: Text) -> None:
|
||||
self.option_id = option_id
|
||||
self.prompt = prompt
|
||||
|
||||
|
||||
class FakeOptionList:
|
||||
def __init__(self, highlighted_option_id: str | None = None) -> None:
|
||||
self.highlighted_option = (
|
||||
FakeOption(highlighted_option_id)
|
||||
if highlighted_option_id is not None
|
||||
else None
|
||||
)
|
||||
self.removed_option_ids: list[str] = []
|
||||
self.replaced_prompts: list[ReplacedPrompt] = []
|
||||
|
||||
def remove_option(self, option_id: str) -> None:
|
||||
self.removed_option_ids.append(option_id)
|
||||
|
||||
def replace_option_prompt(self, option_id: str, prompt: Text) -> None:
|
||||
self.replaced_prompts.append(ReplacedPrompt(option_id, prompt))
|
||||
|
|
|
|||
75
tests/cli/textual_ui/test_terminal_input_filter.py
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
from textual import events
|
||||
|
||||
from vibe.cli.textual_ui.terminal_input_filter import (
|
||||
FilteringXTermParser,
|
||||
patch_driver_parser,
|
||||
strip_malformed_mouse,
|
||||
)
|
||||
|
||||
NOISE = [
|
||||
"\x1b[<32;NaN;NaNM", # malformed SGR mouse (extended button on focus change)
|
||||
"\x1b[<35;NaN;NaNm",
|
||||
]
|
||||
|
||||
PRESERVED = [
|
||||
"\x1b[A", # arrow up
|
||||
"\x1b[15~", # F5
|
||||
"\x1b[97u", # plain kitty key 'a'
|
||||
"\x1b[<0;5;5M", # valid mouse down
|
||||
"\x1b[<0;5;5m", # valid mouse up
|
||||
"\x1b[<128;10;10M", # valid extended-button mouse
|
||||
"\x1b[<0;-1;-1M", # negative SGR-Pixels coords (Textual handles these)
|
||||
"\x1b[24;80R", # cursor position report
|
||||
"\x1b[I", # focus in
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("seq", NOISE)
|
||||
def test_strip_removes_malformed_mouse(seq: str) -> None:
|
||||
assert strip_malformed_mouse(seq) == ""
|
||||
|
||||
|
||||
@pytest.mark.parametrize("seq", PRESERVED)
|
||||
def test_strip_preserves_real_input(seq: str) -> None:
|
||||
assert strip_malformed_mouse(seq) == seq
|
||||
|
||||
|
||||
def test_strip_keeps_real_key_after_noise() -> None:
|
||||
assert strip_malformed_mouse("\x1b[<32;NaN;NaNM\x1b[A") == "\x1b[A"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("seq", NOISE)
|
||||
def test_parser_emits_no_keys_for_noise(seq: str) -> None:
|
||||
tokens = list(FilteringXTermParser().feed(seq))
|
||||
assert [t for t in tokens if isinstance(t, events.Key) and t.character] == []
|
||||
|
||||
|
||||
def test_parser_still_emits_key_for_arrow() -> None:
|
||||
tokens = list(FilteringXTermParser().feed("\x1b[A"))
|
||||
assert any(isinstance(t, events.Key) and t.key == "up" for t in tokens)
|
||||
|
||||
|
||||
def test_all_noise_chunk_does_not_trip_eof() -> None:
|
||||
parser = FilteringXTermParser()
|
||||
assert list(parser.feed("\x1b[<32;NaN;NaNM")) == []
|
||||
# The parser must still be alive for the next real chunk.
|
||||
assert any(
|
||||
isinstance(t, events.Key) and t.key == "up" for t in parser.feed("\x1b[A")
|
||||
)
|
||||
|
||||
|
||||
def test_patch_driver_parser_rebinds_module_global() -> None:
|
||||
import sys
|
||||
|
||||
from textual.drivers.linux_driver import LinuxDriver
|
||||
|
||||
namespace = sys.modules[LinuxDriver.__module__].__dict__
|
||||
original = namespace["XTermParser"]
|
||||
try:
|
||||
patch_driver_parser(LinuxDriver)
|
||||
assert namespace["XTermParser"] is FilteringXTermParser
|
||||
finally:
|
||||
namespace["XTermParser"] = original
|
||||
|
|
@ -52,7 +52,6 @@ def test_resumed_user_message_with_images_renders_footer(tmp_path: Path) -> None
|
|||
[msg],
|
||||
tool_call_map={},
|
||||
start_index=0,
|
||||
tools_collapsed=False,
|
||||
history_widget_indices=WeakKeyDictionary(),
|
||||
)
|
||||
|
||||
|
|
@ -70,7 +69,6 @@ def test_resumed_user_message_with_images_only_still_mounts(tmp_path: Path) -> N
|
|||
[msg],
|
||||
tool_call_map={},
|
||||
start_index=0,
|
||||
tools_collapsed=False,
|
||||
history_widget_indices=WeakKeyDictionary(),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -111,8 +111,25 @@ class TestAgentManager:
|
|||
include_prompt_detail=False,
|
||||
disabled_agents=["plan"],
|
||||
)
|
||||
with pytest.raises(ValueError, match="not available"):
|
||||
with pytest.raises(ValueError, match="disabled_agents") as exc_info:
|
||||
AgentManager(lambda: config, initial_agent="plan")
|
||||
message = str(exc_info.value)
|
||||
assert "default_agent" not in message
|
||||
assert message.startswith("Agent 'plan'")
|
||||
|
||||
def test_explicit_agent_excluded_by_enabled_agents_does_not_blame_default(
|
||||
self,
|
||||
) -> None:
|
||||
config = build_test_vibe_config(
|
||||
include_project_context=False,
|
||||
include_prompt_detail=False,
|
||||
enabled_agents=["default"],
|
||||
)
|
||||
with pytest.raises(ValueError, match="enabled_agents") as exc_info:
|
||||
AgentManager(lambda: config, initial_agent="plan")
|
||||
message = str(exc_info.value)
|
||||
assert "default_agent" not in message
|
||||
assert message.startswith("Agent 'plan'")
|
||||
|
||||
def test_initial_agent_raises_when_agent_does_not_exist(self) -> None:
|
||||
config = build_test_vibe_config(
|
||||
|
|
@ -120,3 +137,55 @@ class TestAgentManager:
|
|||
)
|
||||
with pytest.raises(ValueError, match="not found"):
|
||||
AgentManager(lambda: config, initial_agent="nonexistent-agent")
|
||||
|
||||
def test_default_agent_excluded_by_enabled_agents_raises_config_contradiction(
|
||||
self,
|
||||
) -> None:
|
||||
config = build_test_vibe_config(
|
||||
include_project_context=False,
|
||||
include_prompt_detail=False,
|
||||
enabled_agents=["plan"],
|
||||
)
|
||||
with pytest.raises(ValueError, match="enabled_agents") as exc_info:
|
||||
AgentManager(lambda: config)
|
||||
message = str(exc_info.value)
|
||||
assert "default" in message
|
||||
assert "default_agent" in message
|
||||
|
||||
def test_default_agent_excluded_by_disabled_agents_raises_config_contradiction(
|
||||
self,
|
||||
) -> None:
|
||||
config = build_test_vibe_config(
|
||||
include_project_context=False,
|
||||
include_prompt_detail=False,
|
||||
disabled_agents=["default"],
|
||||
)
|
||||
with pytest.raises(ValueError, match="disabled_agents") as exc_info:
|
||||
AgentManager(lambda: config)
|
||||
assert "default_agent" in str(exc_info.value)
|
||||
|
||||
def test_disabled_agents_ignored_entirely_when_enabled_agents_set(
|
||||
self, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
config = build_test_vibe_config(
|
||||
include_project_context=False,
|
||||
include_prompt_detail=False,
|
||||
enabled_agents=["plan"],
|
||||
disabled_agents=["plan"],
|
||||
)
|
||||
with caplog.at_level("WARNING"):
|
||||
manager = AgentManager(lambda: config, initial_agent="plan")
|
||||
assert manager.active_profile.name == "plan"
|
||||
assert caplog.text == ""
|
||||
|
||||
def test_install_required_agent_reports_install_not_disabled_agents(self) -> None:
|
||||
# 'lean' is install_required and enabled but not installed: the message
|
||||
# must point to installation, not blame disabled_agents.
|
||||
config = build_test_vibe_config(
|
||||
include_project_context=False,
|
||||
include_prompt_detail=False,
|
||||
enabled_agents=["lean"],
|
||||
)
|
||||
with pytest.raises(ValueError, match="requires installation") as exc_info:
|
||||
AgentManager(lambda: config, initial_agent="lean")
|
||||
assert "disabled_agents" not in str(exc_info.value)
|
||||
|
|
|
|||
|
|
@ -1,46 +0,0 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from dataclasses import asdict
|
||||
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||
|
||||
from vibe.core.auth import EncryptedPayload, decrypt, encrypt
|
||||
|
||||
|
||||
def _generate_test_key_pair() -> tuple[bytes, bytes]:
|
||||
private_key = rsa.generate_private_key(public_exponent=65537, key_size=4096)
|
||||
private_pem = private_key.private_bytes(
|
||||
encoding=serialization.Encoding.PEM,
|
||||
format=serialization.PrivateFormat.PKCS8,
|
||||
encryption_algorithm=serialization.NoEncryption(),
|
||||
)
|
||||
public_pem = private_key.public_key().public_bytes(
|
||||
encoding=serialization.Encoding.PEM,
|
||||
format=serialization.PublicFormat.SubjectPublicKeyInfo,
|
||||
)
|
||||
return private_pem, public_pem
|
||||
|
||||
|
||||
class TestEncryptDecrypt:
|
||||
def test_encrypt_decrypt_roundtrip(self) -> None:
|
||||
private_pem, public_pem = _generate_test_key_pair()
|
||||
|
||||
plaintext = "ghp_test_token_12345"
|
||||
encrypted = encrypt(plaintext, public_pem)
|
||||
|
||||
assert encrypted.encrypted_key != plaintext
|
||||
assert encrypted.ciphertext != plaintext
|
||||
|
||||
decrypted = decrypt(encrypted, private_pem)
|
||||
assert decrypted == plaintext
|
||||
|
||||
def test_encrypted_payload_serialization(self) -> None:
|
||||
payload = EncryptedPayload(
|
||||
encrypted_key="enc_key", nonce="nonce123", ciphertext="cipher"
|
||||
)
|
||||
|
||||
data = asdict(payload)
|
||||
restored = EncryptedPayload(**data)
|
||||
|
||||
assert restored == payload
|
||||
|
|
@ -1,286 +0,0 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
import httpx
|
||||
import pytest
|
||||
|
||||
from vibe.core.auth.github import (
|
||||
DeviceFlowHandle,
|
||||
DeviceFlowInfo,
|
||||
GitHubAuthError,
|
||||
GitHubAuthProvider,
|
||||
)
|
||||
|
||||
|
||||
class TestDeviceFlowModels:
|
||||
def test_device_flow_info(self) -> None:
|
||||
info = DeviceFlowInfo(
|
||||
user_code="ABC-123", verification_uri="https://example.com"
|
||||
)
|
||||
assert info.user_code == "ABC-123"
|
||||
assert info.verification_uri == "https://example.com"
|
||||
|
||||
def test_device_flow_handle(self) -> None:
|
||||
info = DeviceFlowInfo(
|
||||
user_code="ABC-123", verification_uri="https://example.com"
|
||||
)
|
||||
handle = DeviceFlowHandle(device_code="dc_123", expires_in=900, info=info)
|
||||
assert handle.device_code == "dc_123"
|
||||
assert handle.expires_in == 900
|
||||
assert handle.info.user_code == "ABC-123"
|
||||
|
||||
|
||||
class TestGitHubAuthProviderContextManager:
|
||||
@pytest.mark.asyncio
|
||||
async def test_creates_client_on_enter(self) -> None:
|
||||
provider = GitHubAuthProvider()
|
||||
assert provider._client is None
|
||||
async with provider:
|
||||
assert provider._client is not None
|
||||
assert provider._client is None
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_uses_provided_client(self) -> None:
|
||||
external_client = httpx.AsyncClient()
|
||||
provider = GitHubAuthProvider(client=external_client)
|
||||
async with provider:
|
||||
assert provider._client is external_client
|
||||
assert provider._client is external_client
|
||||
await external_client.aclose()
|
||||
|
||||
|
||||
class TestGitHubAuthProviderGetToken:
|
||||
def test_returns_token_from_keyring(self) -> None:
|
||||
with patch("vibe.core.auth.github.keyring") as mock_keyring:
|
||||
mock_keyring.get_password.return_value = "ghp_test_token"
|
||||
provider = GitHubAuthProvider()
|
||||
token = provider.get_token()
|
||||
assert token == "ghp_test_token"
|
||||
|
||||
def test_returns_none_on_keyring_error(self) -> None:
|
||||
with patch("vibe.core.auth.github.keyring") as mock_keyring:
|
||||
import keyring.errors
|
||||
|
||||
mock_keyring.errors = keyring.errors
|
||||
mock_keyring.get_password.side_effect = keyring.errors.KeyringError("error")
|
||||
provider = GitHubAuthProvider()
|
||||
token = provider.get_token()
|
||||
assert token is None
|
||||
|
||||
def test_returns_none_when_no_token(self) -> None:
|
||||
with patch("vibe.core.auth.github.keyring") as mock_keyring:
|
||||
mock_keyring.get_password.return_value = None
|
||||
provider = GitHubAuthProvider()
|
||||
token = provider.get_token()
|
||||
assert token is None
|
||||
|
||||
|
||||
class TestGitHubAuthProviderHasToken:
|
||||
def test_returns_true_when_token_exists(self) -> None:
|
||||
with patch("vibe.core.auth.github.keyring") as mock_keyring:
|
||||
mock_keyring.get_password.return_value = "ghp_token"
|
||||
provider = GitHubAuthProvider()
|
||||
assert provider.has_token() is True
|
||||
|
||||
def test_returns_false_when_no_token(self) -> None:
|
||||
with patch("vibe.core.auth.github.keyring") as mock_keyring:
|
||||
mock_keyring.get_password.return_value = None
|
||||
provider = GitHubAuthProvider()
|
||||
assert provider.has_token() is False
|
||||
|
||||
|
||||
class TestGitHubAuthProviderStartDeviceFlow:
|
||||
@pytest.fixture
|
||||
def mock_client(self) -> MagicMock:
|
||||
return MagicMock(spec=httpx.AsyncClient)
|
||||
|
||||
@pytest.fixture
|
||||
def provider(self, mock_client: MagicMock) -> GitHubAuthProvider:
|
||||
return GitHubAuthProvider(client=mock_client)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_start_device_flow_success(
|
||||
self, provider: GitHubAuthProvider, mock_client: MagicMock
|
||||
) -> None:
|
||||
mock_response = MagicMock()
|
||||
mock_response.is_success = True
|
||||
mock_response.json.return_value = {
|
||||
"device_code": "dc_123",
|
||||
"user_code": "ABC-123",
|
||||
"verification_uri": "https://github.com/login/device",
|
||||
"expires_in": 900,
|
||||
}
|
||||
mock_client.post = AsyncMock(return_value=mock_response)
|
||||
|
||||
with patch("vibe.core.auth.github.webbrowser") as mock_browser:
|
||||
handle = await provider.start_device_flow(open_browser=True)
|
||||
mock_browser.open.assert_called_once_with("https://github.com/login/device")
|
||||
|
||||
assert handle.device_code == "dc_123"
|
||||
assert handle.info.user_code == "ABC-123"
|
||||
assert handle.expires_in == 900
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_start_device_flow_without_browser(
|
||||
self, provider: GitHubAuthProvider, mock_client: MagicMock
|
||||
) -> None:
|
||||
mock_response = MagicMock()
|
||||
mock_response.is_success = True
|
||||
mock_response.json.return_value = {
|
||||
"device_code": "dc_123",
|
||||
"user_code": "ABC-123",
|
||||
"verification_uri": "https://github.com/login/device",
|
||||
"expires_in": 900,
|
||||
}
|
||||
mock_client.post = AsyncMock(return_value=mock_response)
|
||||
|
||||
with patch("vibe.core.auth.github.webbrowser") as mock_browser:
|
||||
await provider.start_device_flow(open_browser=False)
|
||||
mock_browser.open.assert_not_called()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_start_device_flow_failure(
|
||||
self, provider: GitHubAuthProvider, mock_client: MagicMock
|
||||
) -> None:
|
||||
mock_response = MagicMock()
|
||||
mock_response.is_success = False
|
||||
mock_response.text = "Bad request"
|
||||
mock_client.post = AsyncMock(return_value=mock_response)
|
||||
|
||||
with pytest.raises(GitHubAuthError, match="Failed to initiate device flow"):
|
||||
await provider.start_device_flow()
|
||||
|
||||
|
||||
class TestGitHubAuthProviderPollForToken:
|
||||
@pytest.fixture
|
||||
def mock_client(self) -> MagicMock:
|
||||
return MagicMock(spec=httpx.AsyncClient)
|
||||
|
||||
@pytest.fixture
|
||||
def provider(self, mock_client: MagicMock) -> GitHubAuthProvider:
|
||||
return GitHubAuthProvider(client=mock_client)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_poll_returns_token_on_success(
|
||||
self, provider: GitHubAuthProvider, mock_client: MagicMock
|
||||
) -> None:
|
||||
mock_response = MagicMock()
|
||||
mock_response.json.return_value = {"access_token": "ghp_new_token"}
|
||||
mock_client.post = AsyncMock(return_value=mock_response)
|
||||
|
||||
with patch("vibe.core.auth.github.asyncio.sleep", new_callable=AsyncMock):
|
||||
token = await provider._poll_for_token(
|
||||
mock_client, "dc_123", expires_in=10, interval=1
|
||||
)
|
||||
assert token == "ghp_new_token"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_poll_handles_slow_down(
|
||||
self, provider: GitHubAuthProvider, mock_client: MagicMock
|
||||
) -> None:
|
||||
responses = [
|
||||
MagicMock(
|
||||
json=MagicMock(return_value={"error": "slow_down", "interval": 5})
|
||||
),
|
||||
MagicMock(json=MagicMock(return_value={"access_token": "ghp_token"})),
|
||||
]
|
||||
mock_client.post = AsyncMock(side_effect=responses)
|
||||
|
||||
with patch("vibe.core.auth.github.asyncio.sleep", new_callable=AsyncMock):
|
||||
token = await provider._poll_for_token(
|
||||
mock_client, "dc_123", expires_in=30, interval=1
|
||||
)
|
||||
assert token == "ghp_token"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_poll_raises_on_expired_token(
|
||||
self, provider: GitHubAuthProvider, mock_client: MagicMock
|
||||
) -> None:
|
||||
mock_response = MagicMock()
|
||||
mock_response.json.return_value = {"error": "expired_token"}
|
||||
mock_client.post = AsyncMock(return_value=mock_response)
|
||||
|
||||
with patch("vibe.core.auth.github.asyncio.sleep", new_callable=AsyncMock):
|
||||
with pytest.raises(GitHubAuthError, match="expired_token"):
|
||||
await provider._poll_for_token(
|
||||
mock_client, "dc_123", expires_in=10, interval=1
|
||||
)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_poll_raises_on_access_denied(
|
||||
self, provider: GitHubAuthProvider, mock_client: MagicMock
|
||||
) -> None:
|
||||
mock_response = MagicMock()
|
||||
mock_response.json.return_value = {"error": "access_denied"}
|
||||
mock_client.post = AsyncMock(return_value=mock_response)
|
||||
|
||||
with patch("vibe.core.auth.github.asyncio.sleep", new_callable=AsyncMock):
|
||||
with pytest.raises(GitHubAuthError, match="access_denied"):
|
||||
await provider._poll_for_token(
|
||||
mock_client, "dc_123", expires_in=10, interval=1
|
||||
)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_poll_raises_on_timeout(
|
||||
self, provider: GitHubAuthProvider, mock_client: MagicMock
|
||||
) -> None:
|
||||
mock_response = MagicMock()
|
||||
mock_response.json.return_value = {"error": "authorization_pending"}
|
||||
mock_client.post = AsyncMock(return_value=mock_response)
|
||||
|
||||
with patch("vibe.core.auth.github.asyncio.sleep", new_callable=AsyncMock):
|
||||
with pytest.raises(GitHubAuthError, match="timed out"):
|
||||
await provider._poll_for_token(
|
||||
mock_client, "dc_123", expires_in=2, interval=1
|
||||
)
|
||||
|
||||
|
||||
class TestGitHubAuthProviderSaveToken:
|
||||
def test_save_token_success(self) -> None:
|
||||
with patch("vibe.core.auth.github.keyring") as mock_keyring:
|
||||
provider = GitHubAuthProvider()
|
||||
provider._save_token("ghp_token")
|
||||
mock_keyring.set_password.assert_called_once_with(
|
||||
"vibe", "github_token", "ghp_token"
|
||||
)
|
||||
|
||||
def test_save_token_raises_on_keyring_error(self) -> None:
|
||||
with patch("vibe.core.auth.github.keyring") as mock_keyring:
|
||||
import keyring.errors
|
||||
|
||||
mock_keyring.errors = keyring.errors
|
||||
mock_keyring.set_password.side_effect = keyring.errors.KeyringError("error")
|
||||
provider = GitHubAuthProvider()
|
||||
with pytest.raises(GitHubAuthError, match="Failed to save token"):
|
||||
provider._save_token("ghp_token")
|
||||
|
||||
|
||||
class TestGitHubAuthProviderWaitForToken:
|
||||
@pytest.fixture
|
||||
def mock_client(self) -> MagicMock:
|
||||
return MagicMock(spec=httpx.AsyncClient)
|
||||
|
||||
@pytest.fixture
|
||||
def provider(self, mock_client: MagicMock) -> GitHubAuthProvider:
|
||||
return GitHubAuthProvider(client=mock_client)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_wait_for_token_polls_and_saves(
|
||||
self, provider: GitHubAuthProvider, mock_client: MagicMock
|
||||
) -> None:
|
||||
mock_response = MagicMock()
|
||||
mock_response.json.return_value = {"access_token": "ghp_token"}
|
||||
mock_client.post = AsyncMock(return_value=mock_response)
|
||||
|
||||
info = DeviceFlowInfo(user_code="ABC", verification_uri="https://example.com")
|
||||
handle = DeviceFlowHandle(device_code="dc_123", expires_in=10, info=info)
|
||||
|
||||
with (
|
||||
patch("vibe.core.auth.github.asyncio.sleep", new_callable=AsyncMock),
|
||||
patch("vibe.core.auth.github.keyring") as mock_keyring,
|
||||
):
|
||||
token = await provider.wait_for_token(handle)
|
||||
|
||||
assert token == "ghp_token"
|
||||
mock_keyring.set_password.assert_called_once()
|
||||
|
|
@ -1,6 +1,10 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from vibe.core.compaction import collect_prior_user_messages
|
||||
from vibe.core.compaction import (
|
||||
collect_prior_user_messages,
|
||||
parse_previous_user_messages,
|
||||
render_compaction_context,
|
||||
)
|
||||
from vibe.core.types import LLMMessage, Role
|
||||
|
||||
_PREFIX = "Another language model started to solve this problem"
|
||||
|
|
@ -51,17 +55,52 @@ def test_empty_content_filtered_out() -> None:
|
|||
|
||||
|
||||
def test_prior_summary_filtered_out() -> None:
|
||||
# A user message starting with the summary prefix represents a previous
|
||||
# compaction summary and must not be re-injected (would stack).
|
||||
# The injected summary marker represents a previous compaction summary and
|
||||
# must not be re-injected (would stack).
|
||||
messages = [
|
||||
_user("original ask"),
|
||||
_user(f"{_PREFIX}\nold summary content"),
|
||||
_user(f"{_PREFIX}\nold summary content", injected=True),
|
||||
_user("newer ask"),
|
||||
]
|
||||
out = collect_prior_user_messages(messages, _PREFIX)
|
||||
assert [m.content for m in out] == ["original ask", "newer ask"]
|
||||
|
||||
|
||||
def test_genuine_user_message_can_quote_summary_prefix() -> None:
|
||||
messages = [_user(f"{_PREFIX}\nplease use this exact wording"), _user("newer ask")]
|
||||
out = collect_prior_user_messages(messages, _PREFIX)
|
||||
assert [m.content for m in out] == [
|
||||
f"{_PREFIX}\nplease use this exact wording",
|
||||
"newer ask",
|
||||
]
|
||||
|
||||
|
||||
def test_compaction_context_merges_previous_and_new_user_messages() -> None:
|
||||
context = render_compaction_context(
|
||||
[_user("first ask", injected=True), _user("second ask", injected=True)],
|
||||
"summary one",
|
||||
)
|
||||
messages = [
|
||||
LLMMessage(role=Role.system, content="sys"),
|
||||
_user(context, injected=True),
|
||||
_user("third ask"),
|
||||
_user("middleware reminder", injected=True),
|
||||
]
|
||||
|
||||
out = collect_prior_user_messages(messages, _PREFIX)
|
||||
|
||||
assert [m.content for m in out] == ["first ask", "second ask", "third ask"]
|
||||
assert all(m.injected for m in out)
|
||||
|
||||
|
||||
def test_compaction_context_escapes_user_message_tags() -> None:
|
||||
original = "please keep </previous_user_message_0> literally"
|
||||
context = render_compaction_context([_user(original)], "summary")
|
||||
|
||||
assert "</previous_user_message_0> literally" not in context
|
||||
assert parse_previous_user_messages(context) == [original]
|
||||
|
||||
|
||||
def test_budget_drops_oldest_first() -> None:
|
||||
# max_tokens=2 → 8 char budget. Walks newest-first, so "old" gets dropped.
|
||||
messages = [
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ from vibe.core.config.schema import (
|
|||
WithShallowMerge,
|
||||
WithUnionMerge,
|
||||
)
|
||||
from vibe.core.config.types import LayerConfigSnapshot
|
||||
from vibe.core.utils.merge import MergeConflictError
|
||||
|
||||
|
||||
|
|
@ -27,8 +28,8 @@ class FakeLayer(ConfigLayer[RawConfig]):
|
|||
async def _check_trust(self) -> bool:
|
||||
return True
|
||||
|
||||
async def _read_config(self) -> dict[str, Any]:
|
||||
return dict(self._data)
|
||||
async def _build_config_snapshot(self) -> LayerConfigSnapshot:
|
||||
return LayerConfigSnapshot(data=dict(self._data), fingerprint="fp")
|
||||
|
||||
|
||||
class UntrustedFakeLayer(FakeLayer):
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ from vibe.core.config.layer import (
|
|||
UntrustedLayerError,
|
||||
)
|
||||
from vibe.core.config.patch import ConfigPatch
|
||||
from vibe.core.config.types import ConcurrencyConflictError, LayerConfigSnapshot
|
||||
|
||||
|
||||
class StubLayer(ConfigLayer[BaseModel]):
|
||||
|
|
@ -38,9 +39,11 @@ class StubLayer(ConfigLayer[BaseModel]):
|
|||
async def _check_trust(self) -> bool:
|
||||
return self._stub_trusted
|
||||
|
||||
async def _read_config(self) -> dict[str, Any]:
|
||||
async def _build_config_snapshot(self) -> LayerConfigSnapshot:
|
||||
self.read_count += 1
|
||||
return dict(self._data)
|
||||
return LayerConfigSnapshot(
|
||||
data=dict(self._data), fingerprint=f"fp-{self.read_count}"
|
||||
)
|
||||
|
||||
|
||||
class ObservableStubLayer(StubLayer):
|
||||
|
|
@ -59,7 +62,7 @@ class SampleSchema(BaseModel):
|
|||
count: int = 0
|
||||
|
||||
|
||||
def test_abstract_read_config_enforced() -> None:
|
||||
def test_abstract_build_config_snapshot_enforced() -> None:
|
||||
class IncompleteLayer(ConfigLayer[BaseModel]):
|
||||
pass
|
||||
|
||||
|
|
@ -72,11 +75,21 @@ def test_repr() -> None:
|
|||
assert repr(layer) == "StubLayer(name='my-layer')"
|
||||
|
||||
|
||||
def test_layer_config_snapshot_strips_fingerprint() -> None:
|
||||
snapshot = LayerConfigSnapshot(data={}, fingerprint=" fp ")
|
||||
assert snapshot.fingerprint == "fp"
|
||||
|
||||
|
||||
def test_layer_config_snapshot_rejects_empty_fingerprint() -> None:
|
||||
with pytest.raises(ValidationError):
|
||||
LayerConfigSnapshot(data={}, fingerprint=" ")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_default_check_trust_returns_false() -> None:
|
||||
class DefaultTrustLayer(ConfigLayer[BaseModel]):
|
||||
async def _read_config(self) -> dict[str, Any]:
|
||||
return {}
|
||||
async def _build_config_snapshot(self) -> LayerConfigSnapshot:
|
||||
return LayerConfigSnapshot(data={}, fingerprint="fp")
|
||||
|
||||
layer = DefaultTrustLayer(name="default")
|
||||
result = await layer.resolve_trust()
|
||||
|
|
@ -224,6 +237,7 @@ async def test_load_returns_data() -> None:
|
|||
result = await layer.load()
|
||||
assert isinstance(result, RawConfig)
|
||||
assert result.model_extra == {"key": "value"}
|
||||
assert layer.fingerprint == "fp-1"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -233,6 +247,10 @@ async def test_load_auto_resolves_trust() -> None:
|
|||
result = await layer.load()
|
||||
assert layer.is_trusted is True
|
||||
assert result.model_extra == {"a": 1}
|
||||
assert layer.fingerprint == "fp-1"
|
||||
|
||||
await layer.resolve_trust()
|
||||
assert layer.fingerprint == "fp-1"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -251,6 +269,7 @@ async def test_load_force_bypasses_cache() -> None:
|
|||
assert layer.read_count == 1
|
||||
await layer.load(force=True)
|
||||
assert layer.read_count == 2
|
||||
assert layer.fingerprint == "fp-2"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -312,6 +331,7 @@ async def test_resolve_trust_clears_data_on_revocation() -> None:
|
|||
layer._stub_trusted = False
|
||||
await layer.resolve_trust()
|
||||
assert layer.is_trusted is False
|
||||
assert layer.fingerprint is None
|
||||
|
||||
# Re-trust and update backing data while revoked
|
||||
layer._stub_trusted = True
|
||||
|
|
@ -335,17 +355,30 @@ async def test_load_returns_deep_copy() -> None:
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_read_config_failure_wrapped() -> None:
|
||||
async def test_build_config_snapshot_failure_wrapped() -> None:
|
||||
class BrokenReadLayer(StubLayer):
|
||||
async def _read_config(self) -> dict[str, Any]:
|
||||
async def _build_config_snapshot(self) -> LayerConfigSnapshot:
|
||||
raise OSError("config file missing")
|
||||
|
||||
layer = BrokenReadLayer()
|
||||
with pytest.raises(LayerImplementationError, match="_read_config") as exc_info:
|
||||
with pytest.raises(
|
||||
LayerImplementationError, match="_build_config_snapshot"
|
||||
) as exc_info:
|
||||
await layer.load()
|
||||
assert isinstance(exc_info.value.__cause__, IOError)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_build_config_snapshot_concurrency_conflict_propagates() -> None:
|
||||
class ConflictingReadLayer(StubLayer):
|
||||
async def _build_config_snapshot(self) -> LayerConfigSnapshot:
|
||||
raise ConcurrencyConflictError(expected_fp="before", actual_fp="after")
|
||||
|
||||
layer = ConflictingReadLayer()
|
||||
with pytest.raises(ConcurrencyConflictError):
|
||||
await layer.load()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_default_schema_preserves_extras() -> None:
|
||||
layer = StubLayer(data={"anything": "goes"})
|
||||
|
|
@ -364,10 +397,13 @@ async def test_custom_schema_validates() -> None:
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_invalid_data_raises_validation_error() -> None:
|
||||
async def test_invalid_data_raises_layer_implementation_error() -> None:
|
||||
layer = StubLayer(output_schema=SampleSchema, data={"count": "bad"})
|
||||
with pytest.raises(ValidationError):
|
||||
with pytest.raises(
|
||||
LayerImplementationError, match="_build_config_snapshot"
|
||||
) as exc_info:
|
||||
await layer.load()
|
||||
assert isinstance(exc_info.value.__cause__, ValidationError)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -380,10 +416,12 @@ async def test_concurrent_loads_serialize() -> None:
|
|||
async def _check_trust(self) -> bool:
|
||||
return True
|
||||
|
||||
async def _read_config(self) -> dict[str, Any]:
|
||||
async def _build_config_snapshot(self) -> LayerConfigSnapshot:
|
||||
self.read_count += 1
|
||||
await asyncio.sleep(0.05)
|
||||
return {"v": self.read_count}
|
||||
return LayerConfigSnapshot(
|
||||
data={"v": self.read_count}, fingerprint=f"fp-{self.read_count}"
|
||||
)
|
||||
|
||||
layer = SlowLayer()
|
||||
results = await asyncio.gather(layer.load(), layer.load(), layer.load())
|
||||
|
|
@ -392,10 +430,9 @@ async def test_concurrent_loads_serialize() -> None:
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_fingerprint_not_implemented() -> None:
|
||||
async def test_fingerprint_returns_none_before_load() -> None:
|
||||
layer = StubLayer()
|
||||
with pytest.raises(NotImplementedError):
|
||||
await layer.get_fingerprint()
|
||||
assert layer.fingerprint is None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -459,8 +496,8 @@ class FakeLocalUserLayer(ConfigLayer[UserConfigSchema]):
|
|||
async def _check_trust(self) -> bool:
|
||||
return True
|
||||
|
||||
async def _read_config(self) -> dict[str, Any]:
|
||||
return dict(self._data)
|
||||
async def _build_config_snapshot(self) -> LayerConfigSnapshot:
|
||||
return LayerConfigSnapshot(data=dict(self._data), fingerprint="user-fp")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -504,8 +541,8 @@ class FakeLocalProjectLayer(ConfigLayer[BaseModel]):
|
|||
else:
|
||||
self._trust_store.pop(self._project_path, None)
|
||||
|
||||
async def _read_config(self) -> dict[str, Any]:
|
||||
return dict(self._data)
|
||||
async def _build_config_snapshot(self) -> LayerConfigSnapshot:
|
||||
return LayerConfigSnapshot(data=dict(self._data), fingerprint="project-fp")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
|
|||
213
tests/core/test_config_mcp_auth.py
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from pydantic import ValidationError
|
||||
import pytest
|
||||
|
||||
from vibe.core.config import MCPHttp, MCPOAuth, MCPStaticAuth, MCPStreamableHttp
|
||||
from vibe.core.tools.mcp.registry import MCPRegistry
|
||||
|
||||
HTTP_TRANSPORTS = [
|
||||
pytest.param(MCPHttp, "http", id="http"),
|
||||
pytest.param(MCPStreamableHttp, "streamable-http", id="streamable-http"),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("cls", "transport"), HTTP_TRANSPORTS)
|
||||
def test_legacy_top_level_keys_promote_to_static_auth(
|
||||
cls: type[MCPHttp | MCPStreamableHttp],
|
||||
transport: str,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
monkeypatch.setenv("MCP_TOKEN", "secret-token")
|
||||
|
||||
srv = cls.model_validate({
|
||||
"name": "remote",
|
||||
"transport": transport,
|
||||
"url": "https://mcp.example.com",
|
||||
"api_key_env": "MCP_TOKEN",
|
||||
})
|
||||
|
||||
assert isinstance(srv.auth, MCPStaticAuth)
|
||||
assert srv.auth.api_key_env == "MCP_TOKEN"
|
||||
assert srv.http_headers() == {"Authorization": "Bearer secret-token"}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("cls", "transport"), HTTP_TRANSPORTS)
|
||||
def test_legacy_custom_header_and_format(
|
||||
cls: type[MCPHttp | MCPStreamableHttp],
|
||||
transport: str,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
monkeypatch.setenv("MCP_TOKEN", "k")
|
||||
|
||||
srv = cls.model_validate({
|
||||
"name": "remote",
|
||||
"transport": transport,
|
||||
"url": "https://mcp.example.com",
|
||||
"api_key_env": "MCP_TOKEN",
|
||||
"api_key_header": "X-API-Key",
|
||||
"api_key_format": "{token}",
|
||||
})
|
||||
|
||||
assert srv.http_headers() == {"X-API-Key": "k"}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("cls", "transport"), HTTP_TRANSPORTS)
|
||||
def test_explicit_static_auth_round_trips(
|
||||
cls: type[MCPHttp | MCPStreamableHttp], transport: str
|
||||
) -> None:
|
||||
srv = cls.model_validate({
|
||||
"name": "remote",
|
||||
"transport": transport,
|
||||
"url": "https://mcp.example.com",
|
||||
"auth": {"type": "static", "api_key_env": "X", "api_key_header": "X-API-Key"},
|
||||
})
|
||||
|
||||
dumped = srv.model_dump()
|
||||
rebuilt = cls.model_validate(dumped)
|
||||
|
||||
assert isinstance(rebuilt.auth, MCPStaticAuth)
|
||||
assert rebuilt.auth.api_key_env == "X"
|
||||
assert rebuilt.auth.api_key_header == "X-API-Key"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("cls", "transport"), HTTP_TRANSPORTS)
|
||||
def test_oauth_auth_parses(
|
||||
cls: type[MCPHttp | MCPStreamableHttp], transport: str
|
||||
) -> None:
|
||||
srv = cls.model_validate({
|
||||
"name": "linear",
|
||||
"transport": transport,
|
||||
"url": "https://mcp.linear.app/mcp",
|
||||
"auth": {"type": "oauth", "scopes": ["read", "write"]},
|
||||
})
|
||||
|
||||
assert isinstance(srv.auth, MCPOAuth)
|
||||
assert srv.auth.scopes == ["read", "write"]
|
||||
assert srv.auth.redirect_port == 47823
|
||||
assert srv.http_headers() == {}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("cls", "transport"), HTTP_TRANSPORTS)
|
||||
def test_mixing_legacy_keys_with_auth_block_is_rejected(
|
||||
cls: type[MCPHttp | MCPStreamableHttp], transport: str
|
||||
) -> None:
|
||||
with pytest.raises(ValidationError, match="cannot mix top-level"):
|
||||
cls.model_validate({
|
||||
"name": "remote",
|
||||
"transport": transport,
|
||||
"url": "https://mcp.example.com",
|
||||
"api_key_env": "LEGACY",
|
||||
"auth": {"type": "static", "api_key_env": "NEW"},
|
||||
})
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("cls", "transport"), HTTP_TRANSPORTS)
|
||||
def test_default_auth_is_static(
|
||||
cls: type[MCPHttp | MCPStreamableHttp], transport: str
|
||||
) -> None:
|
||||
srv = cls.model_validate({
|
||||
"name": "remote",
|
||||
"transport": transport,
|
||||
"url": "https://mcp.example.com",
|
||||
})
|
||||
|
||||
assert isinstance(srv.auth, MCPStaticAuth)
|
||||
assert srv.http_headers() == {}
|
||||
|
||||
|
||||
def test_oauth_client_id_and_metadata_url_mutually_exclusive() -> None:
|
||||
with pytest.raises(ValidationError, match="mutually exclusive"):
|
||||
MCPOAuth.model_validate({
|
||||
"type": "oauth",
|
||||
"scopes": ["read"],
|
||||
"client_id": "abc",
|
||||
"client_metadata_url": "https://example.com/cm.json",
|
||||
})
|
||||
|
||||
|
||||
def test_oauth_client_metadata_url_must_be_http_url() -> None:
|
||||
with pytest.raises(ValidationError):
|
||||
MCPOAuth.model_validate({
|
||||
"type": "oauth",
|
||||
"scopes": ["read"],
|
||||
"client_metadata_url": "not-a-url",
|
||||
})
|
||||
|
||||
|
||||
def test_oauth_client_id_rejects_empty_string() -> None:
|
||||
with pytest.raises(ValidationError):
|
||||
MCPOAuth.model_validate({"type": "oauth", "scopes": ["read"], "client_id": ""})
|
||||
|
||||
|
||||
@pytest.mark.parametrize("port", [80, 1023, 0, 65536, 70000])
|
||||
def test_oauth_redirect_port_out_of_range(port: int) -> None:
|
||||
with pytest.raises(ValidationError):
|
||||
MCPOAuth.model_validate({
|
||||
"type": "oauth",
|
||||
"scopes": ["read"],
|
||||
"redirect_port": port,
|
||||
})
|
||||
|
||||
|
||||
def test_oauth_redirect_port_inside_range() -> None:
|
||||
auth = MCPOAuth.model_validate({
|
||||
"type": "oauth",
|
||||
"scopes": ["read"],
|
||||
"redirect_port": 1024,
|
||||
})
|
||||
assert auth.redirect_port == 1024
|
||||
|
||||
|
||||
def test_static_auth_forbids_extra_keys() -> None:
|
||||
with pytest.raises(ValidationError):
|
||||
MCPStaticAuth.model_validate({"type": "static", "headerz": {}})
|
||||
|
||||
|
||||
def test_oauth_forbids_extra_keys() -> None:
|
||||
with pytest.raises(ValidationError):
|
||||
MCPOAuth.model_validate({"type": "oauth", "scopes": ["read"], "scope": "x"})
|
||||
|
||||
|
||||
def test_oauth_scopes_required() -> None:
|
||||
with pytest.raises(ValidationError):
|
||||
MCPOAuth.model_validate({"type": "oauth"})
|
||||
|
||||
|
||||
def test_oauth_scopes_empty_list_allowed() -> None:
|
||||
auth = MCPOAuth.model_validate({"type": "oauth", "scopes": []})
|
||||
assert auth.scopes == []
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize(("cls", "transport"), HTTP_TRANSPORTS)
|
||||
async def test_registry_skips_oauth_servers_with_gated_warning(
|
||||
cls: type[MCPHttp | MCPStreamableHttp],
|
||||
transport: str,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
srv = cls.model_validate({
|
||||
"name": "linear",
|
||||
"transport": transport,
|
||||
"url": "https://mcp.linear.app/mcp",
|
||||
"auth": {"type": "oauth", "scopes": ["read"]},
|
||||
})
|
||||
registry = MCPRegistry()
|
||||
|
||||
with caplog.at_level(logging.WARNING, logger="vibe"):
|
||||
first = await registry.get_tools_async([srv])
|
||||
|
||||
assert first == {}
|
||||
assert (
|
||||
"OAuth support for MCP servers is not yet enabled; coming in a future release"
|
||||
in caplog.text
|
||||
)
|
||||
|
||||
caplog.clear()
|
||||
with caplog.at_level(logging.WARNING, logger="vibe"):
|
||||
second = await registry.get_tools_async([srv])
|
||||
|
||||
assert second == {}
|
||||
assert "OAuth support" not in caplog.text
|
||||
|
|
@ -9,6 +9,7 @@ from vibe.core.config.layer import ConfigLayer, RawConfig
|
|||
from vibe.core.config.orchestrator import ConfigOrchestrator
|
||||
from vibe.core.config.patch import ConfigPatch
|
||||
from vibe.core.config.schema import ConfigSchema, WithReplaceMerge
|
||||
from vibe.core.config.types import LayerConfigSnapshot
|
||||
|
||||
|
||||
class FakeLayer(ConfigLayer[RawConfig]):
|
||||
|
|
@ -19,8 +20,8 @@ class FakeLayer(ConfigLayer[RawConfig]):
|
|||
async def _check_trust(self) -> bool:
|
||||
return True
|
||||
|
||||
async def _read_config(self) -> dict[str, Any]:
|
||||
return dict(self._data)
|
||||
async def _build_config_snapshot(self) -> LayerConfigSnapshot:
|
||||
return LayerConfigSnapshot(data=dict(self._data), fingerprint="fp")
|
||||
|
||||
|
||||
class SimpleSchema(ConfigSchema):
|
||||
|
|
|
|||
|
|
@ -342,7 +342,10 @@ class TestMigrateLeavesFindInBashAllowlist:
|
|||
) -> None:
|
||||
monkeypatch.setenv("VIBE_HOME", str(tmp_path))
|
||||
config_file = tmp_path / "config.toml"
|
||||
data = {"tools": {"bash": {"allowlist": ["echo", "ls"]}}}
|
||||
data = {
|
||||
"applied_migrations": [VibeConfig._BASH_READ_ONLY_MIGRATION],
|
||||
"tools": {"bash": {"allowlist": ["echo", "ls"]}},
|
||||
}
|
||||
with config_file.open("wb") as f:
|
||||
tomli_w.dump(data, f)
|
||||
|
||||
|
|
@ -359,7 +362,10 @@ class TestMigrateLeavesFindInBashAllowlist:
|
|||
) -> None:
|
||||
monkeypatch.setenv("VIBE_HOME", str(tmp_path))
|
||||
config_file = tmp_path / "config.toml"
|
||||
data = {"tools": {"bash": {"allowlist": ["echo", "find", "ls"]}}}
|
||||
data = {
|
||||
"applied_migrations": [VibeConfig._BASH_READ_ONLY_MIGRATION],
|
||||
"tools": {"bash": {"allowlist": ["echo", "find", "ls"]}},
|
||||
}
|
||||
with config_file.open("wb") as f:
|
||||
tomli_w.dump(data, f)
|
||||
|
||||
|
|
@ -396,7 +402,8 @@ class TestMigrateStripsBashAllowlistWildcardSuffix:
|
|||
monkeypatch.setenv("VIBE_HOME", str(tmp_path))
|
||||
config_file = tmp_path / "config.toml"
|
||||
data = {
|
||||
"tools": {"bash": {"allowlist": ["git commit *", "npm install *", "echo"]}}
|
||||
"applied_migrations": [VibeConfig._BASH_READ_ONLY_MIGRATION],
|
||||
"tools": {"bash": {"allowlist": ["git commit *", "npm install *", "echo"]}},
|
||||
}
|
||||
with config_file.open("wb") as f:
|
||||
tomli_w.dump(data, f)
|
||||
|
|
@ -420,7 +427,8 @@ class TestMigrateStripsBashAllowlistWildcardSuffix:
|
|||
monkeypatch.setenv("VIBE_HOME", str(tmp_path))
|
||||
config_file = tmp_path / "config.toml"
|
||||
data = {
|
||||
"tools": {"bash": {"allowlist": ["git commit *", "git commit", "find"]}}
|
||||
"applied_migrations": [VibeConfig._BASH_READ_ONLY_MIGRATION],
|
||||
"tools": {"bash": {"allowlist": ["git commit *", "git commit", "find"]}},
|
||||
}
|
||||
with config_file.open("wb") as f:
|
||||
tomli_w.dump(data, f)
|
||||
|
|
@ -438,7 +446,10 @@ class TestMigrateStripsBashAllowlistWildcardSuffix:
|
|||
) -> None:
|
||||
monkeypatch.setenv("VIBE_HOME", str(tmp_path))
|
||||
config_file = tmp_path / "config.toml"
|
||||
data = {"tools": {"bash": {"allowlist": ["echo", "find", "ls"]}}}
|
||||
data = {
|
||||
"applied_migrations": [VibeConfig._BASH_READ_ONLY_MIGRATION],
|
||||
"tools": {"bash": {"allowlist": ["echo", "find", "ls"]}},
|
||||
}
|
||||
with config_file.open("wb") as f:
|
||||
tomli_w.dump(data, f)
|
||||
|
||||
|
|
@ -451,6 +462,68 @@ class TestMigrateStripsBashAllowlistWildcardSuffix:
|
|||
assert result["tools"]["bash"]["allowlist"] == ["echo", "find", "ls"]
|
||||
|
||||
|
||||
class TestMigrateBashReadOnlyDefaults:
|
||||
def test_merges_read_only_commands_into_existing_allowlist(
|
||||
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
from vibe.core.tools.builtins.bash import default_read_only_commands
|
||||
|
||||
monkeypatch.setenv("VIBE_HOME", str(tmp_path))
|
||||
config_file = tmp_path / "config.toml"
|
||||
data = {"tools": {"bash": {"allowlist": ["echo", "git commit"]}}}
|
||||
with config_file.open("wb") as f:
|
||||
tomli_w.dump(data, f)
|
||||
|
||||
reset_harness_files_manager()
|
||||
init_harness_files_manager("user")
|
||||
VibeConfig._migrate()
|
||||
|
||||
with config_file.open("rb") as f:
|
||||
result = tomllib.load(f)
|
||||
allowlist = result["tools"]["bash"]["allowlist"]
|
||||
assert "git commit" in allowlist
|
||||
for cmd in default_read_only_commands():
|
||||
assert cmd in allowlist
|
||||
assert VibeConfig._BASH_READ_ONLY_MIGRATION in result["applied_migrations"]
|
||||
|
||||
def test_does_not_readd_removed_command_after_migration(
|
||||
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
monkeypatch.setenv("VIBE_HOME", str(tmp_path))
|
||||
config_file = tmp_path / "config.toml"
|
||||
data = {
|
||||
"applied_migrations": [VibeConfig._BASH_READ_ONLY_MIGRATION],
|
||||
"tools": {"bash": {"allowlist": ["echo", "find"]}},
|
||||
}
|
||||
with config_file.open("wb") as f:
|
||||
tomli_w.dump(data, f)
|
||||
|
||||
reset_harness_files_manager()
|
||||
init_harness_files_manager("user")
|
||||
VibeConfig._migrate()
|
||||
|
||||
with config_file.open("rb") as f:
|
||||
result = tomllib.load(f)
|
||||
assert result["tools"]["bash"]["allowlist"] == ["echo", "find"]
|
||||
|
||||
def test_noop_when_no_bash_allowlist(
|
||||
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
monkeypatch.setenv("VIBE_HOME", str(tmp_path))
|
||||
config_file = tmp_path / "config.toml"
|
||||
data = {"active_model": "test"}
|
||||
with config_file.open("wb") as f:
|
||||
tomli_w.dump(data, f)
|
||||
|
||||
reset_harness_files_manager()
|
||||
init_harness_files_manager("user")
|
||||
VibeConfig._migrate()
|
||||
|
||||
with config_file.open("rb") as f:
|
||||
result = tomllib.load(f)
|
||||
assert result == {"active_model": "test"}
|
||||
|
||||
|
||||
class TestMigrateMistralVibeCliLatestDefaults:
|
||||
def test_updates_alias_temperature_and_thinking_for_default_model(
|
||||
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
|
|
|
|||
|
|
@ -43,6 +43,26 @@ async def test_no_vars_set_returns_empty() -> None:
|
|||
assert data.model_dump() == {}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_fingerprint_changes_when_env_changes() -> None:
|
||||
with patch.dict(os.environ, {"VIBE_ACTIVE_MODEL": "first-model"}, clear=True):
|
||||
layer = EnvironmentLayer(schema=VibeConfigSchema)
|
||||
data1 = await layer.load()
|
||||
fp1 = layer.fingerprint
|
||||
|
||||
os.environ["VIBE_ACTIVE_MODEL"] = "second-model"
|
||||
data2 = await layer.load(force=True)
|
||||
fp2 = layer.fingerprint
|
||||
|
||||
assert data1.model_dump() == {"active_model": "first-model"}
|
||||
assert data2.model_dump() == {"active_model": "second-model"}
|
||||
assert isinstance(fp1, str)
|
||||
assert fp1
|
||||
assert isinstance(fp2, str)
|
||||
assert fp2
|
||||
assert fp1 != fp2
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_always_trusted() -> None:
|
||||
assert await EnvironmentLayer(schema=VibeConfigSchema).resolve_trust() is True
|
||||
|
|
|
|||
118
tests/core/test_fingerprint.py
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from vibe.core.config.fingerprint import capture_stable_file, create_dict_fingerprint
|
||||
from vibe.core.config.types import ConcurrencyConflictError
|
||||
|
||||
|
||||
class TestCaptureStableFile:
|
||||
def test_captures_unchanged_file(self, tmp_working_directory: Path) -> None:
|
||||
path = tmp_working_directory / "config.toml"
|
||||
path.write_text("key = 1")
|
||||
|
||||
with capture_stable_file(path) as (file, first_fingerprint):
|
||||
assert file.read() == b"key = 1"
|
||||
|
||||
with capture_stable_file(path) as (file, second_fingerprint):
|
||||
assert file.read() == b"key = 1"
|
||||
|
||||
assert isinstance(first_fingerprint, str)
|
||||
assert first_fingerprint
|
||||
assert first_fingerprint == second_fingerprint
|
||||
|
||||
def test_raises_when_file_changes(self, tmp_working_directory: Path) -> None:
|
||||
path = tmp_working_directory / "config.toml"
|
||||
path.write_text("key = 1")
|
||||
|
||||
with pytest.raises(ConcurrencyConflictError) as exc_info:
|
||||
with capture_stable_file(path):
|
||||
path.write_text("key = 123")
|
||||
|
||||
assert exc_info.value.actual_fp != exc_info.value.expected_fp
|
||||
|
||||
def test_raises_when_path_is_replaced_after_open(
|
||||
self, tmp_working_directory: Path
|
||||
) -> None:
|
||||
path = tmp_working_directory / "config.toml"
|
||||
replacement = tmp_working_directory / "replacement.toml"
|
||||
path.write_text("key = 1")
|
||||
replacement.write_text("key = 2")
|
||||
|
||||
with pytest.raises(ConcurrencyConflictError) as exc_info:
|
||||
with capture_stable_file(path) as (file, _):
|
||||
replacement.replace(path)
|
||||
assert file.read() == b"key = 1"
|
||||
|
||||
assert exc_info.value.actual_fp != exc_info.value.expected_fp
|
||||
|
||||
def test_raises_when_file_disappears_after_read(
|
||||
self, tmp_working_directory: Path
|
||||
) -> None:
|
||||
path = tmp_working_directory / "config.toml"
|
||||
path.write_text("key = 1")
|
||||
|
||||
with pytest.raises(FileNotFoundError):
|
||||
with capture_stable_file(path) as (file, _):
|
||||
assert file.read() == b"key = 1"
|
||||
path.unlink()
|
||||
|
||||
def test_raises_when_file_is_missing(self, tmp_working_directory: Path) -> None:
|
||||
path = tmp_working_directory / "missing.toml"
|
||||
|
||||
with pytest.raises(FileNotFoundError):
|
||||
with capture_stable_file(path):
|
||||
pass
|
||||
|
||||
|
||||
class TestCreateDictFingerprint:
|
||||
def test_empty_dict_returns_stable_non_empty_token(self) -> None:
|
||||
first_fingerprint = create_dict_fingerprint({})
|
||||
second_fingerprint = create_dict_fingerprint({})
|
||||
|
||||
assert isinstance(first_fingerprint, str)
|
||||
assert first_fingerprint
|
||||
assert first_fingerprint == second_fingerprint
|
||||
|
||||
def test_stable_for_same_dict(self) -> None:
|
||||
data = {
|
||||
"VIBE_MODEL": "mistral-large",
|
||||
"VIBE_THEME": "dark",
|
||||
"VIBE_TOOLS": ["read", "write"],
|
||||
}
|
||||
fp1 = create_dict_fingerprint(data)
|
||||
fp2 = create_dict_fingerprint(data)
|
||||
assert fp1 == fp2
|
||||
|
||||
def test_order_independent(self) -> None:
|
||||
fp1 = create_dict_fingerprint({"a": "1", "b": "2"})
|
||||
fp2 = create_dict_fingerprint({"b": "2", "a": "1"})
|
||||
assert fp1 == fp2
|
||||
|
||||
def test_serializes_path_values(self) -> None:
|
||||
fp1 = create_dict_fingerprint({
|
||||
"tool_paths": [Path("/tmp/custom-tools")],
|
||||
"agent_paths": [Path("agents")],
|
||||
})
|
||||
fp2 = create_dict_fingerprint({
|
||||
"tool_paths": ["/tmp/custom-tools"],
|
||||
"agent_paths": ["agents"],
|
||||
})
|
||||
assert fp1 == fp2
|
||||
|
||||
def test_changes_when_list_order_changes(self) -> None:
|
||||
fp1 = create_dict_fingerprint({"tools": ["read", "write"]})
|
||||
fp2 = create_dict_fingerprint({"tools": ["write", "read"]})
|
||||
assert fp1 != fp2
|
||||
|
||||
def test_changes_when_value_changes(self) -> None:
|
||||
fp1 = create_dict_fingerprint({"VIBE_MODEL": "mistral-large"})
|
||||
fp2 = create_dict_fingerprint({"VIBE_MODEL": "devstral-2"})
|
||||
assert fp1 != fp2
|
||||
|
||||
def test_changes_when_key_added(self) -> None:
|
||||
fp1 = create_dict_fingerprint({"a": "1"})
|
||||
fp2 = create_dict_fingerprint({"a": "1", "b": "2"})
|
||||
assert fp1 != fp2
|
||||
|
|
@ -2,6 +2,8 @@ from __future__ import annotations
|
|||
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from vibe.core.paths._local_config_files import LocalConfigDirs, find_local_config_dirs
|
||||
|
||||
|
||||
|
|
@ -87,6 +89,21 @@ class TestConfigDirs:
|
|||
assert resolved / ".vibe" in result.config_dirs
|
||||
assert resolved / ".agents" in result.config_dirs
|
||||
|
||||
def test_unreadable_config_dirs_do_not_crash(
|
||||
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
def fake_is_dir(self: Path) -> bool:
|
||||
raise PermissionError(13, "Permission denied")
|
||||
|
||||
def fake_is_file(self: Path) -> bool:
|
||||
raise PermissionError(13, "Permission denied")
|
||||
|
||||
monkeypatch.setattr(Path, "is_dir", fake_is_dir)
|
||||
monkeypatch.setattr(Path, "is_file", fake_is_file)
|
||||
|
||||
result = find_local_config_dirs(tmp_path)
|
||||
assert result == LocalConfigDirs()
|
||||
|
||||
|
||||
class TestLocalConfigDirsOr:
|
||||
def test_or_concatenates_each_field(self) -> None:
|
||||
|
|
|
|||
496
tests/core/test_mcp_oauth.py
Normal file
|
|
@ -0,0 +1,496 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from collections.abc import Callable, Iterator
|
||||
from contextlib import suppress
|
||||
import socket
|
||||
import urllib.parse
|
||||
|
||||
import httpx
|
||||
import keyring
|
||||
from keyring.backend import KeyringBackend
|
||||
import keyring.backends.fail
|
||||
import keyring.errors
|
||||
from mcp.shared.auth import OAuthClientInformationFull, OAuthToken
|
||||
import pytest
|
||||
import respx
|
||||
|
||||
from vibe.core.auth.mcp_oauth import (
|
||||
Fingerprint,
|
||||
KeyringTokenStorage,
|
||||
LoopbackCallbackHandler,
|
||||
MCPOAuthError,
|
||||
MCPOAuthHeadlessError,
|
||||
MCPOAuthPortInUse,
|
||||
build_oauth_provider,
|
||||
perform_oauth_login,
|
||||
)
|
||||
from vibe.core.config import MCPOAuth, MCPStreamableHttp
|
||||
|
||||
|
||||
class _MemoryKeyring(KeyringBackend):
|
||||
priority = 100 # type: ignore[assignment]
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.store: dict[tuple[str, str], str] = {}
|
||||
|
||||
def get_password(self, service: str, username: str) -> str | None:
|
||||
return self.store.get((service, username))
|
||||
|
||||
def set_password(self, service: str, username: str, password: str) -> None:
|
||||
self.store[(service, username)] = password
|
||||
|
||||
def delete_password(self, service: str, username: str) -> None:
|
||||
if (service, username) not in self.store:
|
||||
raise keyring.errors.PasswordDeleteError(username)
|
||||
del self.store[(service, username)]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def memory_keyring() -> Iterator[_MemoryKeyring]:
|
||||
original = keyring.get_keyring()
|
||||
fake = _MemoryKeyring()
|
||||
keyring.set_keyring(fake)
|
||||
try:
|
||||
yield fake
|
||||
finally:
|
||||
keyring.set_keyring(original)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def headless_keyring() -> Iterator[None]:
|
||||
original = keyring.get_keyring()
|
||||
keyring.set_keyring(keyring.backends.fail.Keyring())
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
keyring.set_keyring(original)
|
||||
|
||||
|
||||
def _oauth_server(
|
||||
*,
|
||||
name: str = "demo",
|
||||
url: str = "https://mcp.example.com/mcp",
|
||||
scopes: list[str] | None = None,
|
||||
client_id: str | None = None,
|
||||
client_metadata_url: str | None = None,
|
||||
redirect_port: int = 47823,
|
||||
) -> MCPStreamableHttp:
|
||||
auth = MCPOAuth(
|
||||
type="oauth",
|
||||
scopes=scopes if scopes is not None else ["read", "write"],
|
||||
client_id=client_id,
|
||||
client_metadata_url=client_metadata_url, # type: ignore[arg-type]
|
||||
redirect_port=redirect_port,
|
||||
)
|
||||
return MCPStreamableHttp(transport="streamable-http", name=name, url=url, auth=auth)
|
||||
|
||||
|
||||
def _free_port() -> int:
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||||
s.bind(("127.0.0.1", 0))
|
||||
return int(s.getsockname()[1])
|
||||
|
||||
|
||||
async def _send_callback(port: int, query: str, *, timeout: float = 5.0) -> bytes:
|
||||
deadline = asyncio.get_event_loop().time() + timeout
|
||||
last_err: BaseException | None = None
|
||||
while asyncio.get_event_loop().time() < deadline:
|
||||
try:
|
||||
reader, writer = await asyncio.open_connection("127.0.0.1", port)
|
||||
except (ConnectionRefusedError, OSError) as exc:
|
||||
last_err = exc
|
||||
await asyncio.sleep(0.02)
|
||||
continue
|
||||
try:
|
||||
request = (
|
||||
f"GET /callback?{query} HTTP/1.0\r\n"
|
||||
"Host: 127.0.0.1\r\n"
|
||||
"Connection: close\r\n"
|
||||
"\r\n"
|
||||
)
|
||||
writer.write(request.encode("ascii"))
|
||||
await writer.drain()
|
||||
return await reader.read()
|
||||
finally:
|
||||
writer.close()
|
||||
with suppress(Exception):
|
||||
await writer.wait_closed()
|
||||
raise RuntimeError(f"loopback never bound on port {port}: {last_err}")
|
||||
|
||||
|
||||
class TestKeyringTokenStorage:
|
||||
@pytest.mark.asyncio
|
||||
async def test_round_trip_tokens(self, memory_keyring: _MemoryKeyring) -> None:
|
||||
storage = KeyringTokenStorage(alias="linear")
|
||||
assert await storage.get_tokens() is None
|
||||
|
||||
tokens = OAuthToken(
|
||||
access_token="at",
|
||||
token_type="Bearer",
|
||||
expires_in=3600,
|
||||
refresh_token="rt",
|
||||
scope="read write",
|
||||
)
|
||||
await storage.set_tokens(tokens)
|
||||
|
||||
loaded = await storage.get_tokens()
|
||||
assert loaded is not None
|
||||
assert loaded.access_token == "at"
|
||||
assert loaded.refresh_token == "rt"
|
||||
assert loaded.scope == "read write"
|
||||
assert ("vibe", "mcp-oauth:linear:tokens") in memory_keyring.store
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_round_trip_client_info(self, memory_keyring: _MemoryKeyring) -> None:
|
||||
storage = KeyringTokenStorage(alias="linear")
|
||||
assert await storage.get_client_info() is None
|
||||
|
||||
info = OAuthClientInformationFull(
|
||||
client_id="abc123",
|
||||
redirect_uris=["http://127.0.0.1:47823/callback"], # type: ignore[list-item]
|
||||
token_endpoint_auth_method="none",
|
||||
)
|
||||
await storage.set_client_info(info)
|
||||
|
||||
loaded = await storage.get_client_info()
|
||||
assert loaded is not None
|
||||
assert loaded.client_id == "abc123"
|
||||
assert ("vibe", "mcp-oauth:linear:client_info") in memory_keyring.store
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_per_alias_isolation(self, memory_keyring: _MemoryKeyring) -> None:
|
||||
a = KeyringTokenStorage(alias="linear")
|
||||
b = KeyringTokenStorage(alias="notion")
|
||||
await a.set_tokens(
|
||||
OAuthToken(access_token="A", token_type="Bearer", expires_in=60)
|
||||
)
|
||||
await b.set_tokens(
|
||||
OAuthToken(access_token="B", token_type="Bearer", expires_in=60)
|
||||
)
|
||||
loaded_a = await a.get_tokens()
|
||||
loaded_b = await b.get_tokens()
|
||||
assert loaded_a is not None and loaded_a.access_token == "A"
|
||||
assert loaded_b is not None and loaded_b.access_token == "B"
|
||||
|
||||
def test_headless_init_raises(self, headless_keyring: None) -> None:
|
||||
with pytest.raises(MCPOAuthHeadlessError) as exc_info:
|
||||
KeyringTokenStorage(alias="linear")
|
||||
msg = str(exc_info.value)
|
||||
assert "linear" in msg
|
||||
assert "api_key_env" in msg
|
||||
assert exc_info.value.server_alias == "linear"
|
||||
|
||||
|
||||
class TestFingerprint:
|
||||
def test_compute_stable_across_scope_order(
|
||||
self, memory_keyring: _MemoryKeyring
|
||||
) -> None:
|
||||
a = _oauth_server(scopes=["read", "write", "admin"])
|
||||
b = _oauth_server(scopes=["admin", "write", "read"])
|
||||
assert Fingerprint.compute(a) == Fingerprint.compute(b)
|
||||
|
||||
def test_compute_strips_whitespace_and_dedupes(
|
||||
self, memory_keyring: _MemoryKeyring
|
||||
) -> None:
|
||||
a = _oauth_server(scopes=["read", "write"])
|
||||
b = _oauth_server(scopes=[" read ", "write", "write", ""])
|
||||
assert Fingerprint.compute(a) == Fingerprint.compute(b)
|
||||
|
||||
def test_compute_marker_for_client_id(self, memory_keyring: _MemoryKeyring) -> None:
|
||||
srv = _oauth_server(client_id="pre-registered-id")
|
||||
assert Fingerprint.compute(srv).client_marker == "pre-registered-id"
|
||||
|
||||
def test_compute_marker_for_client_metadata_url(
|
||||
self, memory_keyring: _MemoryKeyring
|
||||
) -> None:
|
||||
srv = _oauth_server(client_metadata_url="https://vibe.example/cm.json")
|
||||
fp = Fingerprint.compute(srv)
|
||||
assert fp.client_marker.startswith("https://vibe.example/cm.json")
|
||||
|
||||
def test_compute_marker_for_dcr(self, memory_keyring: _MemoryKeyring) -> None:
|
||||
assert Fingerprint.compute(_oauth_server()).client_marker == "<dcr>"
|
||||
|
||||
def test_compute_rejects_static_auth(self, memory_keyring: _MemoryKeyring) -> None:
|
||||
from vibe.core.config import MCPStaticAuth
|
||||
|
||||
srv = MCPStreamableHttp(
|
||||
transport="streamable-http",
|
||||
name="x",
|
||||
url="https://x/mcp",
|
||||
auth=MCPStaticAuth(),
|
||||
)
|
||||
with pytest.raises(TypeError, match="OAuth"):
|
||||
Fingerprint.compute(srv)
|
||||
|
||||
def test_matches_detects_url_change(self, memory_keyring: _MemoryKeyring) -> None:
|
||||
a = Fingerprint.compute(_oauth_server(url="https://a/mcp"))
|
||||
b = Fingerprint.compute(_oauth_server(url="https://b/mcp"))
|
||||
assert a != b
|
||||
|
||||
def test_matches_detects_scope_change(self, memory_keyring: _MemoryKeyring) -> None:
|
||||
a = Fingerprint.compute(_oauth_server(scopes=["read"]))
|
||||
b = Fingerprint.compute(_oauth_server(scopes=["read", "write"]))
|
||||
assert a != b
|
||||
|
||||
def test_matches_detects_marker_change(
|
||||
self, memory_keyring: _MemoryKeyring
|
||||
) -> None:
|
||||
a = Fingerprint.compute(_oauth_server(client_id="x"))
|
||||
b = Fingerprint.compute(_oauth_server(client_id="y"))
|
||||
assert a != b
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_load_returns_none_when_missing(
|
||||
self, memory_keyring: _MemoryKeyring
|
||||
) -> None:
|
||||
assert await Fingerprint.load("nope") is None
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_save_and_load_round_trip(
|
||||
self, memory_keyring: _MemoryKeyring
|
||||
) -> None:
|
||||
fp = Fingerprint.compute(_oauth_server(name="linear"))
|
||||
await fp.save("linear")
|
||||
loaded = await Fingerprint.load("linear")
|
||||
assert loaded == fp
|
||||
|
||||
|
||||
class TestLoopbackCallbackHandler:
|
||||
@pytest.mark.asyncio
|
||||
async def test_happy_path(self) -> None:
|
||||
port = _free_port()
|
||||
handler = LoopbackCallbackHandler(port=port, server_alias="demo")
|
||||
|
||||
async def driver() -> bytes:
|
||||
return await _send_callback(port, "code=AUTH_CODE_123&state=STATE_XYZ")
|
||||
|
||||
serve_task = asyncio.create_task(handler.serve_once())
|
||||
driver_task = asyncio.create_task(driver())
|
||||
code, state = await serve_task
|
||||
response = await driver_task
|
||||
|
||||
assert code == "AUTH_CODE_123"
|
||||
assert state == "STATE_XYZ"
|
||||
assert b"200 OK" in response
|
||||
assert b"Login complete" in response
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_port_in_use_raises(self) -> None:
|
||||
port = _free_port()
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 0)
|
||||
sock.bind(("127.0.0.1", port))
|
||||
sock.listen(1)
|
||||
try:
|
||||
handler = LoopbackCallbackHandler(port=port, server_alias="demo")
|
||||
with pytest.raises(MCPOAuthPortInUse) as exc_info:
|
||||
await handler.serve_once()
|
||||
assert exc_info.value.port == port
|
||||
assert exc_info.value.server_alias == "demo"
|
||||
assert "redirect_port" in str(exc_info.value)
|
||||
finally:
|
||||
sock.close()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_missing_code_raises(self) -> None:
|
||||
port = _free_port()
|
||||
handler = LoopbackCallbackHandler(port=port, server_alias="demo")
|
||||
|
||||
async def driver() -> bytes:
|
||||
return await _send_callback(port, "error=access_denied&state=S")
|
||||
|
||||
serve_task = asyncio.create_task(handler.serve_once())
|
||||
driver_task = asyncio.create_task(driver())
|
||||
with pytest.raises(MCPOAuthError, match="missing 'code'"):
|
||||
await serve_task
|
||||
response = await driver_task
|
||||
assert b"400 Bad Request" in response
|
||||
|
||||
|
||||
class TestBuildOAuthProvider:
|
||||
@pytest.mark.asyncio
|
||||
async def test_metadata_matches_config(
|
||||
self, memory_keyring: _MemoryKeyring
|
||||
) -> None:
|
||||
srv = _oauth_server(scopes=["read", "write"], redirect_port=51234)
|
||||
|
||||
async def on_url(_url: str) -> None:
|
||||
return None
|
||||
|
||||
async def cb() -> tuple[str, str | None]:
|
||||
return "code", None
|
||||
|
||||
provider = build_oauth_provider(
|
||||
srv, redirect_handler=on_url, callback_handler=cb
|
||||
)
|
||||
md = provider.context.client_metadata
|
||||
assert md.scope == "read write"
|
||||
assert md.client_name == "Mistral Vibe"
|
||||
assert md.token_endpoint_auth_method == "none"
|
||||
assert md.grant_types == ["authorization_code", "refresh_token"]
|
||||
assert md.redirect_uris is not None
|
||||
assert str(md.redirect_uris[0]) == "http://127.0.0.1:51234/callback"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_empty_scopes_becomes_none(
|
||||
self, memory_keyring: _MemoryKeyring
|
||||
) -> None:
|
||||
srv = _oauth_server(scopes=[])
|
||||
|
||||
async def on_url(_url: str) -> None:
|
||||
return None
|
||||
|
||||
async def cb() -> tuple[str, str | None]:
|
||||
return "code", None
|
||||
|
||||
provider = build_oauth_provider(
|
||||
srv, redirect_handler=on_url, callback_handler=cb
|
||||
)
|
||||
assert provider.context.client_metadata.scope is None
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_client_metadata_url_forwarded(
|
||||
self, memory_keyring: _MemoryKeyring
|
||||
) -> None:
|
||||
srv = _oauth_server(client_metadata_url="https://vibe.example/cm.json")
|
||||
|
||||
async def on_url(_url: str) -> None:
|
||||
return None
|
||||
|
||||
async def cb() -> tuple[str, str | None]:
|
||||
return "code", None
|
||||
|
||||
provider = build_oauth_provider(
|
||||
srv, redirect_handler=on_url, callback_handler=cb
|
||||
)
|
||||
assert provider.context.client_metadata_url == "https://vibe.example/cm.json"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_rejects_static_auth(self, memory_keyring: _MemoryKeyring) -> None:
|
||||
from vibe.core.config import MCPStaticAuth
|
||||
|
||||
srv = MCPStreamableHttp(
|
||||
transport="streamable-http",
|
||||
name="x",
|
||||
url="https://x/mcp",
|
||||
auth=MCPStaticAuth(),
|
||||
)
|
||||
|
||||
async def on_url(_url: str) -> None:
|
||||
return None
|
||||
|
||||
async def cb() -> tuple[str, str | None]:
|
||||
return "code", None
|
||||
|
||||
with pytest.raises(TypeError, match="OAuth"):
|
||||
build_oauth_provider(srv, redirect_handler=on_url, callback_handler=cb)
|
||||
|
||||
|
||||
class TestPerformOAuthLogin:
|
||||
@pytest.mark.asyncio
|
||||
async def test_full_flow_persists_tokens_and_fingerprint(
|
||||
self, memory_keyring: _MemoryKeyring
|
||||
) -> None:
|
||||
port = _free_port()
|
||||
server_url = "https://mcp.example.com/mcp"
|
||||
as_url = "https://as.example.com"
|
||||
srv = _oauth_server(
|
||||
name="demo", url=server_url, scopes=["read"], redirect_port=port
|
||||
)
|
||||
|
||||
async def on_url(url: str) -> None:
|
||||
qs = urllib.parse.urlparse(url).query
|
||||
state = urllib.parse.parse_qs(qs)["state"][0]
|
||||
|
||||
async def fire() -> None:
|
||||
await _send_callback(port, f"code=THE_CODE&state={state}")
|
||||
|
||||
asyncio.get_event_loop().create_task(fire())
|
||||
|
||||
async with respx.mock(assert_all_called=False) as router:
|
||||
router.get(server_url).mock(side_effect=_mcp_responses())
|
||||
router.get(
|
||||
"https://mcp.example.com/.well-known/oauth-protected-resource"
|
||||
).mock(
|
||||
return_value=httpx.Response(
|
||||
200,
|
||||
json={"resource": server_url, "authorization_servers": [as_url]},
|
||||
)
|
||||
)
|
||||
router.get(
|
||||
"https://as.example.com/.well-known/oauth-authorization-server"
|
||||
).mock(
|
||||
return_value=httpx.Response(
|
||||
200,
|
||||
json={
|
||||
"issuer": as_url,
|
||||
"authorization_endpoint": f"{as_url}/authorize",
|
||||
"token_endpoint": f"{as_url}/token",
|
||||
"registration_endpoint": f"{as_url}/register",
|
||||
"response_types_supported": ["code"],
|
||||
"code_challenge_methods_supported": ["S256"],
|
||||
"grant_types_supported": [
|
||||
"authorization_code",
|
||||
"refresh_token",
|
||||
],
|
||||
},
|
||||
)
|
||||
)
|
||||
router.post(f"{as_url}/register").mock(
|
||||
return_value=httpx.Response(
|
||||
201,
|
||||
json={
|
||||
"client_id": "dcr-client-id",
|
||||
"redirect_uris": [f"http://127.0.0.1:{port}/callback"],
|
||||
"token_endpoint_auth_method": "none",
|
||||
"grant_types": ["authorization_code", "refresh_token"],
|
||||
"response_types": ["code"],
|
||||
},
|
||||
)
|
||||
)
|
||||
router.post(f"{as_url}/token").mock(
|
||||
return_value=httpx.Response(
|
||||
200,
|
||||
json={
|
||||
"access_token": "ACCESS_TOKEN",
|
||||
"token_type": "Bearer",
|
||||
"expires_in": 3600,
|
||||
"refresh_token": "REFRESH_TOKEN",
|
||||
"scope": "read",
|
||||
},
|
||||
)
|
||||
)
|
||||
router.route(host="127.0.0.1").pass_through()
|
||||
|
||||
await perform_oauth_login(srv, on_url=on_url)
|
||||
|
||||
storage = KeyringTokenStorage(alias="demo")
|
||||
tokens = await storage.get_tokens()
|
||||
assert tokens is not None
|
||||
assert tokens.access_token == "ACCESS_TOKEN"
|
||||
assert tokens.refresh_token == "REFRESH_TOKEN"
|
||||
|
||||
fp = await Fingerprint.load("demo")
|
||||
assert fp is not None
|
||||
assert fp == Fingerprint.compute(srv)
|
||||
|
||||
|
||||
def _mcp_responses() -> Callable[[httpx.Request], httpx.Response]:
|
||||
state = {"calls": 0}
|
||||
|
||||
def _factory(_request: httpx.Request) -> httpx.Response:
|
||||
state["calls"] += 1
|
||||
if state["calls"] == 1:
|
||||
return httpx.Response(
|
||||
401,
|
||||
headers={
|
||||
"WWW-Authenticate": (
|
||||
"Bearer resource_metadata="
|
||||
'"https://mcp.example.com/.well-known/oauth-protected-resource"'
|
||||
)
|
||||
},
|
||||
)
|
||||
return httpx.Response(200, json={"ok": True})
|
||||
|
||||
return _factory
|
||||
|
|
@ -80,6 +80,10 @@ async def test_live_reference_picks_up_caller_mutation() -> None:
|
|||
data: dict[str, object] = {"key": "original"}
|
||||
layer = OverridesLayer(data=data)
|
||||
await layer.load()
|
||||
fp1 = layer.fingerprint
|
||||
data["key"] = "updated"
|
||||
result = await layer.load(force=True)
|
||||
fp2 = layer.fingerprint
|
||||
|
||||
assert result.model_extra == {"key": "updated"}
|
||||
assert fp1 != fp2
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import pytest
|
|||
from vibe.core.config.layer import UntrustedLayerError
|
||||
from vibe.core.config.layers.project import ProjectConfigLayer
|
||||
from vibe.core.config.patch import ConfigPatch
|
||||
from vibe.core.config.types import MISSING_CONFIG_FILE_FINGERPRINT
|
||||
from vibe.core.paths._vibe_home import GlobalPath
|
||||
from vibe.core.trusted_folders import trusted_folders_manager
|
||||
|
||||
|
|
@ -21,6 +22,14 @@ async def test_reads_toml_when_trusted(tmp_working_directory: Path) -> None:
|
|||
layer = ProjectConfigLayer(path=tmp_working_directory)
|
||||
data = await layer.load()
|
||||
assert data.model_extra == {"active_model": "project-model"}
|
||||
fp1 = layer.fingerprint
|
||||
assert isinstance(fp1, str)
|
||||
assert fp1
|
||||
|
||||
config_path.unlink()
|
||||
data = await layer.load(force=True)
|
||||
assert data.model_extra == {}
|
||||
assert layer.fingerprint == MISSING_CONFIG_FILE_FINGERPRINT
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -55,6 +64,7 @@ async def test_missing_file_returns_empty(tmp_working_directory: Path) -> None:
|
|||
layer = ProjectConfigLayer(path=tmp_working_directory)
|
||||
data = await layer.load()
|
||||
assert data.model_extra == {}
|
||||
assert layer.fingerprint == MISSING_CONFIG_FILE_FINGERPRINT
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
|
||||
from pydantic import BaseModel
|
||||
import pytest
|
||||
|
||||
from tests.conftest import build_test_vibe_config
|
||||
|
|
@ -14,7 +16,7 @@ from vibe.core.telemetry.build_metadata import (
|
|||
build_base_metadata,
|
||||
build_request_metadata,
|
||||
)
|
||||
from vibe.core.telemetry.send import TelemetryClient
|
||||
from vibe.core.telemetry.send import TelemetryClient, _extract_file_extension
|
||||
from vibe.core.telemetry.types import (
|
||||
AttachmentKind,
|
||||
EntrypointMetadata,
|
||||
|
|
@ -25,18 +27,35 @@ from vibe.core.types import Backend
|
|||
from vibe.core.utils import get_user_agent
|
||||
|
||||
_original_send_telemetry_event = TelemetryClient.send_telemetry_event
|
||||
from vibe.core.tools.builtins.edit import Edit, EditArgs
|
||||
from vibe.core.tools.builtins.read import Read, ReadArgs
|
||||
from vibe.core.tools.builtins.write_file import WriteFile, WriteFileArgs
|
||||
|
||||
|
||||
def _make_resolved_tool_call(
|
||||
tool_name: str, args_dict: dict[str, Any]
|
||||
) -> ResolvedToolCall:
|
||||
if tool_name == "write_file":
|
||||
validated = WriteFileArgs(path="foo.txt", content="x")
|
||||
cls: type[BaseTool] = WriteFile
|
||||
else:
|
||||
validated = FakeToolArgs()
|
||||
cls = FakeTool
|
||||
validated: BaseModel
|
||||
cls: type[BaseTool]
|
||||
match tool_name:
|
||||
case "write_file":
|
||||
validated = WriteFileArgs(
|
||||
path=args_dict.get("path", "foo.txt"), content="x"
|
||||
)
|
||||
cls = WriteFile
|
||||
case "edit":
|
||||
validated = EditArgs(
|
||||
file_path=args_dict.get("file_path", "foo.txt"),
|
||||
old_string="a",
|
||||
new_string="b",
|
||||
)
|
||||
cls = Edit
|
||||
case "read":
|
||||
validated = ReadArgs(file_path=args_dict.get("file_path", "foo.txt"))
|
||||
cls = Read
|
||||
case _:
|
||||
validated = FakeToolArgs()
|
||||
cls = FakeTool
|
||||
return ResolvedToolCall(
|
||||
tool_name=tool_name, tool_class=cls, validated_args=validated, call_id="call_1"
|
||||
)
|
||||
|
|
@ -50,6 +69,37 @@ def _run_telemetry_tasks() -> None:
|
|||
loop.close()
|
||||
|
||||
|
||||
class TestExtractFileExtension:
|
||||
@pytest.mark.parametrize(
|
||||
("path", "expected"),
|
||||
[
|
||||
("/tmp/foo.py", ".py"),
|
||||
("foo.TSX", ".tsx"),
|
||||
("/tmp/Makefile", None),
|
||||
("/tmp/.bashrc", None),
|
||||
("archive.tar.gz", ".gz"),
|
||||
("", None),
|
||||
],
|
||||
)
|
||||
def test_string_inputs(self, path: str, expected: str | None) -> None:
|
||||
assert _extract_file_extension(path) == expected
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("path", "expected"),
|
||||
[
|
||||
(Path("/tmp/foo.py"), ".py"),
|
||||
(Path("foo.TSX"), ".tsx"),
|
||||
(Path("/tmp/Makefile"), None),
|
||||
],
|
||||
)
|
||||
def test_path_inputs(self, path: Path, expected: str | None) -> None:
|
||||
assert _extract_file_extension(path) == expected
|
||||
|
||||
@pytest.mark.parametrize("path", [None, 42, ["foo.py"], {"path": "foo.py"}])
|
||||
def test_non_path_like_inputs_return_none(self, path: object) -> None:
|
||||
assert _extract_file_extension(path) is None
|
||||
|
||||
|
||||
class TestTelemetryClient:
|
||||
def test_send_telemetry_event_swallows_config_getter_value_error(self) -> None:
|
||||
def _raise_config_error() -> Any:
|
||||
|
|
@ -151,6 +201,7 @@ class TestTelemetryClient:
|
|||
assert properties["model"] == "mistral-large"
|
||||
assert properties["nb_files_created"] == 0
|
||||
assert properties["nb_files_modified"] == 0
|
||||
assert properties["file_extension"] is None
|
||||
assert properties["message_id"] is None
|
||||
|
||||
def test_send_tool_call_finished_with_message_id(
|
||||
|
|
@ -176,7 +227,7 @@ class TestTelemetryClient:
|
|||
) -> None:
|
||||
config = build_test_vibe_config(enable_telemetry=True)
|
||||
client = TelemetryClient(config_getter=lambda: config)
|
||||
tool_call = _make_resolved_tool_call("write_file", {})
|
||||
tool_call = _make_resolved_tool_call("write_file", {"path": "/tmp/foo.PY"})
|
||||
|
||||
client.send_tool_call_finished(
|
||||
tool_call=tool_call,
|
||||
|
|
@ -189,6 +240,86 @@ class TestTelemetryClient:
|
|||
|
||||
assert telemetry_events[0]["properties"]["nb_files_created"] == 1
|
||||
assert telemetry_events[0]["properties"]["nb_files_modified"] == 0
|
||||
assert telemetry_events[0]["properties"]["file_extension"] == ".py"
|
||||
|
||||
def test_send_tool_call_finished_file_extension_edit(
|
||||
self, telemetry_events: list[dict[str, Any]]
|
||||
) -> None:
|
||||
config = build_test_vibe_config(enable_telemetry=True)
|
||||
client = TelemetryClient(config_getter=lambda: config)
|
||||
tool_call = _make_resolved_tool_call(
|
||||
"edit", {"file_path": "/tmp/component.tsx"}
|
||||
)
|
||||
|
||||
client.send_tool_call_finished(
|
||||
tool_call=tool_call,
|
||||
status="success",
|
||||
decision=None,
|
||||
agent_profile_name="default",
|
||||
model="mistral-large",
|
||||
result={},
|
||||
)
|
||||
|
||||
assert telemetry_events[0]["properties"]["nb_files_modified"] == 1
|
||||
assert telemetry_events[0]["properties"]["nb_files_created"] == 0
|
||||
assert telemetry_events[0]["properties"]["file_extension"] == ".tsx"
|
||||
|
||||
def test_send_tool_call_finished_file_extension_read(
|
||||
self, telemetry_events: list[dict[str, Any]]
|
||||
) -> None:
|
||||
config = build_test_vibe_config(enable_telemetry=True)
|
||||
client = TelemetryClient(config_getter=lambda: config)
|
||||
tool_call = _make_resolved_tool_call("read", {"file_path": "/tmp/lib.rs"})
|
||||
|
||||
client.send_tool_call_finished(
|
||||
tool_call=tool_call,
|
||||
status="success",
|
||||
decision=None,
|
||||
agent_profile_name="default",
|
||||
model="mistral-large",
|
||||
result={},
|
||||
)
|
||||
|
||||
assert telemetry_events[0]["properties"]["nb_files_created"] == 0
|
||||
assert telemetry_events[0]["properties"]["nb_files_modified"] == 0
|
||||
assert telemetry_events[0]["properties"]["file_extension"] == ".rs"
|
||||
|
||||
def test_send_tool_call_finished_file_extension_none_when_no_suffix(
|
||||
self, telemetry_events: list[dict[str, Any]]
|
||||
) -> None:
|
||||
config = build_test_vibe_config(enable_telemetry=True)
|
||||
client = TelemetryClient(config_getter=lambda: config)
|
||||
tool_call = _make_resolved_tool_call("write_file", {"path": "/tmp/Makefile"})
|
||||
|
||||
client.send_tool_call_finished(
|
||||
tool_call=tool_call,
|
||||
status="success",
|
||||
decision=None,
|
||||
agent_profile_name="default",
|
||||
model="mistral-large",
|
||||
result={},
|
||||
)
|
||||
|
||||
assert telemetry_events[0]["properties"]["file_extension"] is None
|
||||
|
||||
def test_send_tool_call_finished_file_extension_none_on_failure(
|
||||
self, telemetry_events: list[dict[str, Any]]
|
||||
) -> None:
|
||||
config = build_test_vibe_config(enable_telemetry=True)
|
||||
client = TelemetryClient(config_getter=lambda: config)
|
||||
tool_call = _make_resolved_tool_call("write_file", {"path": "/tmp/foo.py"})
|
||||
|
||||
client.send_tool_call_finished(
|
||||
tool_call=tool_call,
|
||||
status="failure",
|
||||
decision=None,
|
||||
agent_profile_name="default",
|
||||
model="mistral-large",
|
||||
result={},
|
||||
)
|
||||
|
||||
assert telemetry_events[0]["properties"]["nb_files_created"] == 0
|
||||
assert telemetry_events[0]["properties"]["file_extension"] is None
|
||||
|
||||
def test_send_tool_call_finished_decision_none(
|
||||
self, telemetry_events: list[dict[str, Any]]
|
||||
|
|
@ -378,6 +509,40 @@ class TestTelemetryClient:
|
|||
"nb_session_messages": 4,
|
||||
}
|
||||
|
||||
def test_send_remote_resume_requested_payload(
|
||||
self, telemetry_events: list[dict[str, Any]]
|
||||
) -> None:
|
||||
config = build_test_vibe_config(enable_telemetry=True)
|
||||
client = TelemetryClient(config_getter=lambda: config)
|
||||
client.send_remote_resume_requested(session_id="remote-123")
|
||||
assert len(telemetry_events) == 1
|
||||
assert telemetry_events[0]["event_name"] == "vibe.remote_resume_requested"
|
||||
assert telemetry_events[0]["properties"] == {"session_id": "remote-123"}
|
||||
|
||||
def test_send_teleport_failed_payload_includes_error_details(
|
||||
self, telemetry_events: list[dict[str, Any]]
|
||||
) -> None:
|
||||
config = build_test_vibe_config(enable_telemetry=True)
|
||||
client = TelemetryClient(config_getter=lambda: config)
|
||||
|
||||
client.send_teleport_failed(
|
||||
stage="workflow_start",
|
||||
error_class="ServiceTeleportError",
|
||||
push_required=False,
|
||||
nb_session_messages=4,
|
||||
error_details={"failure_kind": "http_error", "http_status_code": 502},
|
||||
)
|
||||
|
||||
assert telemetry_events[0]["event_name"] == "vibe.teleport_failed"
|
||||
assert telemetry_events[0]["properties"] == {
|
||||
"stage": "workflow_start",
|
||||
"error_class": "ServiceTeleportError",
|
||||
"push_required": False,
|
||||
"nb_session_messages": 4,
|
||||
"failure_kind": "http_error",
|
||||
"http_status_code": 502,
|
||||
}
|
||||
|
||||
def test_send_new_session_payload(
|
||||
self, telemetry_events: list[dict[str, Any]]
|
||||
) -> None:
|
||||
|
|
|
|||
|
|
@ -174,9 +174,14 @@ async def test_start_raises_for_unsuccessful_response() -> None:
|
|||
|
||||
async with httpx.AsyncClient(transport=httpx.MockTransport(handler)) as client:
|
||||
nuage = NuageClient("https://chat.example.com", "api-key", client=client)
|
||||
with pytest.raises(ServiceTeleportError, match="Nuage start"):
|
||||
with pytest.raises(ServiceTeleportError, match="status 401") as exc_info:
|
||||
await nuage.start(_request())
|
||||
|
||||
assert exc_info.value.telemetry_details == {
|
||||
"failure_kind": "http_error",
|
||||
"http_status_code": 401,
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_start_raises_for_invalid_response() -> None:
|
||||
|
|
@ -185,5 +190,30 @@ async def test_start_raises_for_invalid_response() -> None:
|
|||
|
||||
async with httpx.AsyncClient(transport=httpx.MockTransport(handler)) as client:
|
||||
nuage = NuageClient("https://chat.example.com", "api-key", client=client)
|
||||
with pytest.raises(ServiceTeleportError, match="response was invalid"):
|
||||
with pytest.raises(
|
||||
ServiceTeleportError, match="response was invalid"
|
||||
) as exc_info:
|
||||
await nuage.start(_request())
|
||||
|
||||
assert exc_info.value.telemetry_details == {
|
||||
"failure_kind": "invalid_schema",
|
||||
"http_status_code": 200,
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_start_raises_for_invalid_json_response() -> None:
|
||||
async def handler(request: httpx.Request) -> httpx.Response:
|
||||
return httpx.Response(
|
||||
200, text="not-json", headers={"content-type": "text/plain"}
|
||||
)
|
||||
|
||||
async with httpx.AsyncClient(transport=httpx.MockTransport(handler)) as client:
|
||||
nuage = NuageClient("https://chat.example.com", "api-key", client=client)
|
||||
with pytest.raises(ServiceTeleportError, match="not valid JSON") as exc_info:
|
||||
await nuage.start(_request())
|
||||
|
||||
assert exc_info.value.telemetry_details == {
|
||||
"failure_kind": "invalid_json",
|
||||
"http_status_code": 200,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,7 +87,10 @@ class TestTeleportAgentLoopTelemetry:
|
|||
) -> AsyncGenerator[object, object]:
|
||||
yield TeleportCheckingGitEvent()
|
||||
yield TeleportStartingWorkflowEvent()
|
||||
raise ServiceTeleportError("Workflow api-key-123 could not be started.")
|
||||
raise ServiceTeleportError(
|
||||
"Workflow api-key-123 could not be started.",
|
||||
telemetry_details={"http_status_code": 502},
|
||||
)
|
||||
|
||||
agent_loop.messages.append(LLMMessage(role=Role.user, content="hello"))
|
||||
_set_teleport_service(agent_loop, FakeTeleportService())
|
||||
|
|
@ -103,6 +106,7 @@ class TestTeleportAgentLoopTelemetry:
|
|||
"error_class": "ServiceTeleportError",
|
||||
"push_required": False,
|
||||
"nb_session_messages": 1,
|
||||
"http_status_code": 502,
|
||||
"session_id": agent_loop.session_id,
|
||||
}
|
||||
assert "api-key-123" not in str(telemetry_events[-1]["properties"])
|
||||
|
|
|
|||
|
|
@ -351,6 +351,19 @@ class TestHasAgentsMdFile:
|
|||
def test_agents_md_filename_constant(self) -> None:
|
||||
assert AGENTS_MD_FILENAME == "AGENTS.md"
|
||||
|
||||
def test_unreadable_agents_md_does_not_crash(
|
||||
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
denied = (tmp_path / "AGENTS.md").resolve()
|
||||
|
||||
def fake_is_file(self: Path) -> bool:
|
||||
if self.resolve() == denied:
|
||||
raise PermissionError(13, "Permission denied")
|
||||
return False
|
||||
|
||||
monkeypatch.setattr(Path, "is_file", fake_is_file)
|
||||
assert has_agents_md_file(tmp_path) is False
|
||||
|
||||
|
||||
class TestFindTrustableFiles:
|
||||
def test_returns_empty_for_clean_directory(self, tmp_path: Path) -> None:
|
||||
|
|
@ -513,3 +526,24 @@ class TestFindGitRepoAncestor:
|
|||
) -> None:
|
||||
monkeypatch.setattr(Path, "home", classmethod(lambda _cls: tmp_path / "nope"))
|
||||
assert find_git_repo_ancestor(tmp_path) is None
|
||||
|
||||
def test_unreadable_ancestor_git_head_does_not_crash(
|
||||
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
ancestor = tmp_path / "mnt" / "vast"
|
||||
(ancestor / ".git").mkdir(parents=True)
|
||||
cwd = ancestor / "project"
|
||||
cwd.mkdir()
|
||||
|
||||
real_is_file = Path.is_file
|
||||
denied = (ancestor / ".git" / "HEAD").resolve()
|
||||
|
||||
def fake_is_file(self: Path) -> bool:
|
||||
if self.resolve() == denied:
|
||||
raise PermissionError(13, "Permission denied")
|
||||
return real_is_file(self)
|
||||
|
||||
monkeypatch.setattr(Path, "is_file", fake_is_file)
|
||||
monkeypatch.setattr(Path, "home", classmethod(lambda _cls: tmp_path / "home"))
|
||||
|
||||
assert find_git_repo_ancestor(cwd) is None
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import pytest
|
|||
from vibe.core.config.layer import LayerImplementationError
|
||||
from vibe.core.config.layers.user import UserConfigLayer
|
||||
from vibe.core.config.patch import ConfigPatch
|
||||
from vibe.core.config.types import MISSING_CONFIG_FILE_FINGERPRINT
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -17,6 +18,9 @@ async def test_reads_toml_file(tmp_working_directory: Path) -> None:
|
|||
layer = UserConfigLayer(path=path, name="user-toml")
|
||||
data = await layer.load()
|
||||
assert data.model_extra == {"active_model": "mistral-large", "count": 42}
|
||||
fingerprint = layer.fingerprint
|
||||
assert isinstance(fingerprint, str)
|
||||
assert fingerprint
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -37,6 +41,7 @@ async def test_missing_file_returns_empty(tmp_working_directory: Path) -> None:
|
|||
layer = UserConfigLayer(path=path, name="user-toml")
|
||||
data = await layer.load()
|
||||
assert data.model_extra == {}
|
||||
assert layer.fingerprint == MISSING_CONFIG_FILE_FINGERPRINT
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -70,7 +75,7 @@ async def test_invalid_toml_raises(tmp_working_directory: Path) -> None:
|
|||
path = tmp_working_directory / "bad.toml"
|
||||
path.write_text("this is not valid = = = toml [[[")
|
||||
layer = UserConfigLayer(path=path, name="user-toml")
|
||||
with pytest.raises(LayerImplementationError, match="_read_config"):
|
||||
with pytest.raises(LayerImplementationError, match="_build_config_snapshot"):
|
||||
await layer.load()
|
||||
|
||||
|
||||
|
|
@ -81,11 +86,23 @@ async def test_force_reload_reads_fresh_data(tmp_working_directory: Path) -> Non
|
|||
layer = UserConfigLayer(path=path, name="user-toml")
|
||||
|
||||
data1 = await layer.load()
|
||||
fp1 = layer.fingerprint
|
||||
assert data1.model_extra == {"value": "first"}
|
||||
assert isinstance(fp1, str)
|
||||
assert fp1
|
||||
|
||||
path.write_text('value = "second"\n')
|
||||
data2 = await layer.load(force=True)
|
||||
fp2 = layer.fingerprint
|
||||
assert data2.model_extra == {"value": "second"}
|
||||
assert isinstance(fp2, str)
|
||||
assert fp2
|
||||
assert fp1 != fp2
|
||||
|
||||
path.unlink()
|
||||
data3 = await layer.load(force=True)
|
||||
assert data3.model_extra == {}
|
||||
assert layer.fingerprint == MISSING_CONFIG_FILE_FINGERPRINT
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
|
|||
|
|
@ -106,6 +106,28 @@ class TestReadSafe:
|
|||
with pytest.raises(FileNotFoundError):
|
||||
read_safe(tmp_path / "nope.txt")
|
||||
|
||||
def test_from_subprocess_prefers_oem_over_locale_ansi(
|
||||
self, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
# \x82 is invalid UTF-8 and decodes differently across single-byte
|
||||
# encodings: cp1252 (Windows ANSI) -> "‚" (low-9 quote);
|
||||
# cp850 (Windows OEM) -> "é". Subprocess output prefers OEM over the
|
||||
# ANSI locale; file reads (from_subprocess=False) must not.
|
||||
raw = "café\n".encode("cp850")
|
||||
monkeypatch.setattr(
|
||||
io_utils.locale, "getpreferredencoding", lambda _do_setlocale: "cp1252"
|
||||
)
|
||||
monkeypatch.setattr(io_utils, "_encoding_from_best_match", lambda _raw: None)
|
||||
monkeypatch.setattr(io_utils, "_windows_oem_encoding", lambda: "cp850")
|
||||
|
||||
from_file = decode_safe(raw)
|
||||
assert from_file.encoding == "cp1252"
|
||||
assert from_file.text == raw.decode("cp1252")
|
||||
|
||||
from_subprocess = decode_safe(raw, from_subprocess=True)
|
||||
assert from_subprocess.encoding == "cp850"
|
||||
assert from_subprocess.text == "café\n"
|
||||
|
||||
|
||||
class TestReadSafeNewlines:
|
||||
def test_lf(self, tmp_path: Path) -> None:
|
||||
|
|
|
|||
|
|
@ -244,7 +244,6 @@ def test_get_result_display() -> None:
|
|||
|
||||
assert isinstance(display, ToolResultDisplay)
|
||||
assert display.success is True
|
||||
assert "10 lines" in display.message
|
||||
assert "foo.py" in display.message
|
||||
|
||||
|
||||
|
|
@ -261,7 +260,7 @@ def test_get_result_display_truncated() -> None:
|
|||
)
|
||||
display = Read.get_result_display(event)
|
||||
|
||||
assert "truncated" in display.message
|
||||
assert "truncated" in display.suffix
|
||||
|
||||
|
||||
def test_get_result_display_truncated_via_flag() -> None:
|
||||
|
|
@ -278,7 +277,7 @@ def test_get_result_display_truncated_via_flag() -> None:
|
|||
)
|
||||
display = Read.get_result_display(event)
|
||||
|
||||
assert "truncated" in display.message
|
||||
assert "truncated" in display.suffix
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
|
|
|
|||
|
|
@ -85,3 +85,7 @@ def test_spawn_cli_runs_configured_hook_after_turn(
|
|||
assert invocation["hook_event_name"] == "post_agent_turn"
|
||||
assert isinstance(invocation["cwd"], str) and invocation["cwd"]
|
||||
assert isinstance(invocation["session_id"], str) and invocation["session_id"]
|
||||
# New in the discriminated-union payload: top-level sessions have no
|
||||
# parent. Tool hook invocations in this test never fire (no tool calls
|
||||
# in the mock response), so we only assert the post_agent_turn shape.
|
||||
assert invocation.get("parent_session_id") is None
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ from __future__ import annotations
|
|||
|
||||
from collections.abc import Callable
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
import time
|
||||
|
|
@ -12,12 +14,14 @@ import pytest
|
|||
from tests.e2e.common import (
|
||||
SpawnedVibeProcessFixture,
|
||||
ansi_tolerant_pattern,
|
||||
poll_until,
|
||||
send_ctrl_c_until_quit_confirmation,
|
||||
strip_ansi,
|
||||
wait_for_main_screen,
|
||||
wait_for_request_count,
|
||||
)
|
||||
from tests.e2e.mock_server import StreamingMockServer
|
||||
from vibe.core.utils.io import read_safe
|
||||
|
||||
|
||||
def _usage_by_run_factory(
|
||||
|
|
@ -42,6 +46,47 @@ def _usage_by_run_factory(
|
|||
]
|
||||
|
||||
|
||||
def _saved_session_has_usage(
|
||||
vibe_home: Path, expected_prompt_tokens: int, expected_completion_tokens: int
|
||||
) -> bool:
|
||||
session_log_dir = vibe_home / "logs" / "session"
|
||||
if not session_log_dir.exists():
|
||||
return False
|
||||
|
||||
for metadata_path in session_log_dir.glob("session_*/meta.json"):
|
||||
try:
|
||||
metadata = json.loads(read_safe(metadata_path).text)
|
||||
except (OSError, json.JSONDecodeError):
|
||||
continue
|
||||
|
||||
stats = metadata.get("stats", {})
|
||||
if not isinstance(stats, dict):
|
||||
continue
|
||||
if (
|
||||
stats.get("session_prompt_tokens") == expected_prompt_tokens
|
||||
and stats.get("session_completion_tokens") == expected_completion_tokens
|
||||
):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def _wait_for_saved_session_usage(
|
||||
expected_prompt_tokens: int, expected_completion_tokens: int
|
||||
) -> None:
|
||||
vibe_home = Path(os.environ["VIBE_HOME"])
|
||||
poll_until(
|
||||
lambda: _saved_session_has_usage(
|
||||
vibe_home, expected_prompt_tokens, expected_completion_tokens
|
||||
),
|
||||
timeout=10,
|
||||
message=(
|
||||
"Timed out waiting for saved session usage "
|
||||
f"input={expected_prompt_tokens} output={expected_completion_tokens}."
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def _finish_turn(
|
||||
child: pexpect.spawn,
|
||||
captured: io.StringIO,
|
||||
|
|
@ -103,6 +148,9 @@ def test_resumed_session_prints_only_fresh_token_usage_on_exit(
|
|||
expected_request_count=1,
|
||||
request_count_getter=lambda: len(streaming_mock_server.requests),
|
||||
)
|
||||
_wait_for_saved_session_usage(
|
||||
expected_prompt_tokens=11, expected_completion_tokens=7
|
||||
)
|
||||
|
||||
send_ctrl_c_until_quit_confirmation(child, captured, timeout=5)
|
||||
child.expect(pexpect.EOF, timeout=10)
|
||||
|
|
@ -130,6 +178,9 @@ def test_resumed_session_prints_only_fresh_token_usage_on_exit(
|
|||
expected_request_count=2,
|
||||
request_count_getter=lambda: len(streaming_mock_server.requests),
|
||||
)
|
||||
_wait_for_saved_session_usage(
|
||||
expected_prompt_tokens=2, expected_completion_tokens=1
|
||||
)
|
||||
|
||||
send_ctrl_c_until_quit_confirmation(resumed_child, resumed_captured, timeout=5)
|
||||
resumed_child.expect(pexpect.EOF, timeout=10)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ from unittest.mock import AsyncMock, MagicMock, patch
|
|||
import pytest
|
||||
|
||||
from vibe.core.session.resume_sessions import (
|
||||
ResumeSessionInfo,
|
||||
can_delete_resume_session_source,
|
||||
list_remote_resume_sessions,
|
||||
short_session_id,
|
||||
)
|
||||
|
|
@ -45,6 +47,25 @@ class TestShortSessionId:
|
|||
assert short_session_id("") == ""
|
||||
|
||||
|
||||
class TestCanDeleteResumeSession:
|
||||
def test_local_source_can_delete(self) -> None:
|
||||
assert can_delete_resume_session_source("local") is True
|
||||
|
||||
def test_remote_source_cannot_delete(self) -> None:
|
||||
assert can_delete_resume_session_source("remote") is False
|
||||
|
||||
def test_session_info_can_delete_matches_source(self) -> None:
|
||||
session = ResumeSessionInfo(
|
||||
session_id="session-a",
|
||||
source="local",
|
||||
cwd="/test",
|
||||
title=None,
|
||||
end_time=None,
|
||||
)
|
||||
|
||||
assert session.can_delete is True
|
||||
|
||||
|
||||
class TestListRemoteResumeSessions:
|
||||
@pytest.mark.asyncio
|
||||
async def test_returns_empty_when_vibe_code_disabled(self) -> None:
|
||||
|
|
|
|||
|
|
@ -20,6 +20,22 @@ class TestBuiltinSkills:
|
|||
def test_vibe_skill_has_inline_prompt(self) -> None:
|
||||
assert BUILTIN_SKILLS["vibe"].prompt
|
||||
|
||||
def test_vibe_skill_pins_readme_url_to_running_version(self) -> None:
|
||||
from vibe import __version__
|
||||
|
||||
prompt = BUILTIN_SKILLS["vibe"].prompt
|
||||
assert "__VIBE_VERSION__" not in prompt
|
||||
assert (
|
||||
f"https://github.com/mistralai/mistral-vibe/blob/v{__version__}/README.md"
|
||||
in prompt
|
||||
)
|
||||
|
||||
def test_vibe_skill_references_user_docs_url(self) -> None:
|
||||
assert (
|
||||
"https://docs.mistral.ai/vibe/code/overview"
|
||||
in BUILTIN_SKILLS["vibe"].prompt
|
||||
)
|
||||
|
||||
def test_discovers_builtin_skills(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
monkeypatch.setattr("vibe.core.skills.manager.BUILTIN_SKILLS", BUILTIN_SKILLS)
|
||||
config = build_test_vibe_config(
|
||||
|
|
|
|||
|
|
@ -114,15 +114,15 @@
|
|||
<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="0" y="93.2" textLength="134.2" clip-path="url(#terminal-line-3)">  ⡠⣒⠄  ⡔⢄⠔⡄</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-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="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="0" y="215.2" textLength="134.2" clip-path="url(#terminal-line-8)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="215.2" textLength="146.4" clip-path="url(#terminal-line-8)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="215.2" textLength="122" clip-path="url(#terminal-line-8)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="215.2" textLength="244" clip-path="url(#terminal-line-8)">devstral-latest[off]</text><text class="terminal-r1" x="683.2" y="215.2" textLength="256.2" clip-path="url(#terminal-line-8)"> · [Subscription] Pro</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="0" y="239.6" textLength="134.2" clip-path="url(#terminal-line-9)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="239.6" textLength="414.8" clip-path="url(#terminal-line-9)">1 model · 0 MCP servers · 0 skills</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="0" y="264" textLength="134.2" clip-path="url(#terminal-line-10)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="264" textLength="61" clip-path="url(#terminal-line-10)">Type </text><text class="terminal-r3" x="231.8" y="264" textLength="61" clip-path="url(#terminal-line-10)">/help</text><text class="terminal-r1" x="292.8" y="264" textLength="256.2" clip-path="url(#terminal-line-10)"> for more information</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-r2" x="0" y="190.8" textLength="146.4" clip-path="url(#terminal-line-7)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="190.8" textLength="122" clip-path="url(#terminal-line-7)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="190.8" textLength="244" clip-path="url(#terminal-line-7)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" y="190.8" textLength="256.2" clip-path="url(#terminal-line-7)"> · [Subscription] Pro</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="0" y="215.2" textLength="414.8" clip-path="url(#terminal-line-8)">1 model · 0 MCP servers · 0 skills</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="0" y="239.6" textLength="61" clip-path="url(#terminal-line-9)">Type </text><text class="terminal-r3" x="61" y="239.6" textLength="61" clip-path="url(#terminal-line-9)">/help</text><text class="terminal-r1" x="122" y="239.6" textLength="256.2" clip-path="url(#terminal-line-9)"> for more information</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-r4" x="24.4" y="288.4" textLength="12.2" clip-path="url(#terminal-line-11)">⎣</text><text class="terminal-r4" x="48.8" y="288.4" textLength="12.2" clip-path="url(#terminal-line-11)">▶</text><text class="terminal-r4" x="73.2" y="288.4" textLength="85.4" clip-path="url(#terminal-line-11)">6 lines</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="1464" clip-path="url(#terminal-line-14)">────────────────────────────────────────────────────────────────────────────────────────────────────────────── default ─</text><text class="terminal-r1" x="1464" y="361.6" textLength="12.2" clip-path="url(#terminal-line-14)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 9.1 KiB |
|
|
@ -148,21 +148,21 @@
|
|||
</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="0" y="190.8" textLength="134.2" clip-path="url(#terminal-line-7)">  ⡠⣒⠄  ⡔⢄⠔⡄</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="0" y="215.2" textLength="134.2" clip-path="url(#terminal-line-8)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</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="0" y="239.6" textLength="134.2" clip-path="url(#terminal-line-9)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</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="0" y="312.8" textLength="134.2" clip-path="url(#terminal-line-12)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="312.8" textLength="146.4" clip-path="url(#terminal-line-12)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="312.8" textLength="122" clip-path="url(#terminal-line-12)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="312.8" textLength="244" clip-path="url(#terminal-line-12)">devstral-latest[off]</text><text class="terminal-r1" x="683.2" y="312.8" textLength="256.2" clip-path="url(#terminal-line-12)"> · [Subscription] Pro</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="0" y="337.2" textLength="134.2" clip-path="url(#terminal-line-13)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="337.2" textLength="414.8" clip-path="url(#terminal-line-13)">1 model · 0 MCP servers · 0 skills</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-r1" x="170.8" y="361.6" textLength="61" clip-path="url(#terminal-line-14)">Type </text><text class="terminal-r3" x="231.8" y="361.6" textLength="61" clip-path="url(#terminal-line-14)">/help</text><text class="terminal-r1" x="292.8" y="361.6" textLength="256.2" clip-path="url(#terminal-line-14)"> for more information</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-r4" x="24.4" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">⎢</text><text class="terminal-r4" x="48.8" y="410.4" textLength="695.4" clip-path="url(#terminal-line-16)">What programming language are you currently working with?</text><text class="terminal-r1" x="1464" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">
|
||||
</text><text class="terminal-r4" x="24.4" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">⎢</text><text class="terminal-r1" x="48.8" y="434.8" textLength="48.8" clip-path="url(#terminal-line-17)">Rust</text><text class="terminal-r1" x="1464" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">
|
||||
</text><text class="terminal-r4" x="24.4" y="459.2" textLength="12.2" clip-path="url(#terminal-line-18)">⎢</text><text class="terminal-r4" x="48.8" y="459.2" textLength="463.6" clip-path="url(#terminal-line-18)">What type of project are you building?</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="24.4" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">⎢</text><text class="terminal-r1" x="48.8" y="483.6" textLength="183" clip-path="url(#terminal-line-19)">Web Application</text><text class="terminal-r1" x="1464" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">
|
||||
</text><text class="terminal-r4" x="24.4" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">⎢</text><text class="terminal-r4" x="48.8" y="508" textLength="402.6" clip-path="url(#terminal-line-20)">What editor or IDE do you prefer?</text><text class="terminal-r1" x="1464" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r4" x="24.4" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">⎣</text><text class="terminal-r1" x="48.8" y="532.4" textLength="183" clip-path="url(#terminal-line-21)">(Other) VS Code</text><text class="terminal-r1" x="1464" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">
|
||||
</text><text class="terminal-r2" x="0" y="288.4" textLength="146.4" clip-path="url(#terminal-line-11)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="288.4" textLength="122" clip-path="url(#terminal-line-11)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="288.4" textLength="244" clip-path="url(#terminal-line-11)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" y="288.4" textLength="256.2" clip-path="url(#terminal-line-11)"> · [Subscription] Pro</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="0" y="312.8" textLength="414.8" clip-path="url(#terminal-line-12)">1 model · 0 MCP servers · 0 skills</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="0" y="337.2" textLength="61" clip-path="url(#terminal-line-13)">Type </text><text class="terminal-r3" x="61" y="337.2" textLength="61" clip-path="url(#terminal-line-13)">/help</text><text class="terminal-r1" x="122" y="337.2" textLength="256.2" clip-path="url(#terminal-line-13)"> for more information</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-r4" x="24.4" y="386" textLength="12.2" clip-path="url(#terminal-line-15)">⎢</text><text class="terminal-r4" x="48.8" y="386" textLength="695.4" clip-path="url(#terminal-line-15)">What programming language are you currently working with?</text><text class="terminal-r1" x="1464" y="386" textLength="12.2" clip-path="url(#terminal-line-15)">
|
||||
</text><text class="terminal-r4" x="24.4" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">⎢</text><text class="terminal-r1" x="48.8" y="410.4" textLength="48.8" clip-path="url(#terminal-line-16)">Rust</text><text class="terminal-r1" x="1464" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">
|
||||
</text><text class="terminal-r4" x="24.4" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">⎢</text><text class="terminal-r4" x="48.8" y="434.8" textLength="463.6" clip-path="url(#terminal-line-17)">What type of project are you building?</text><text class="terminal-r1" x="1464" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">
|
||||
</text><text class="terminal-r4" x="24.4" y="459.2" textLength="12.2" clip-path="url(#terminal-line-18)">⎢</text><text class="terminal-r1" x="48.8" y="459.2" textLength="183" clip-path="url(#terminal-line-18)">Web Application</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="24.4" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">⎢</text><text class="terminal-r4" x="48.8" y="483.6" textLength="402.6" clip-path="url(#terminal-line-19)">What editor or IDE do you prefer?</text><text class="terminal-r1" x="1464" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">
|
||||
</text><text class="terminal-r4" 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="183" clip-path="url(#terminal-line-20)">(Other) VS Code</text><text class="terminal-r1" x="1464" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r4" x="24.4" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">⎣</text><text class="terminal-r4" x="48.8" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">▼</text><text class="terminal-r4" x="73.2" y="532.4" textLength="109.8" clip-path="url(#terminal-line-21)">show less</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-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r1" x="0" y="605.6" textLength="1464" clip-path="url(#terminal-line-24)">────────────────────────────────────────────────────────────────────────────────────────────────────────────── default ─</text><text class="terminal-r1" x="1464" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 13 KiB |
|
|
@ -174,13 +174,13 @@
|
|||
</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="361.6" textLength="134.2" clip-path="url(#terminal-line-14)">  ⡠⣒⠄  ⡔⢄⠔⡄</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="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="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="244" clip-path="url(#terminal-line-18)">devstral-latest[off]</text><text class="terminal-r1" x="683.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 · 0 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-r2" x="0" y="459.2" textLength="146.4" clip-path="url(#terminal-line-18)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="459.2" textLength="122" clip-path="url(#terminal-line-18)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="459.2" textLength="244" clip-path="url(#terminal-line-18)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" 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="414.8" clip-path="url(#terminal-line-19)">1 model · 0 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="61" clip-path="url(#terminal-line-20)">Type </text><text class="terminal-r3" x="61" y="508" textLength="61" clip-path="url(#terminal-line-20)">/help</text><text class="terminal-r1" x="122" 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-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
|
@ -178,13 +178,13 @@
|
|||
</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="0" y="312.8" textLength="134.2" 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-r1" x="0" y="337.2" textLength="134.2" clip-path="url(#terminal-line-13)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</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-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="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="244" clip-path="url(#terminal-line-16)">devstral-latest[off]</text><text class="terminal-r1" x="683.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 · 0 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-r2" x="0" y="410.4" textLength="146.4" clip-path="url(#terminal-line-16)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="410.4" textLength="122" clip-path="url(#terminal-line-16)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="410.4" textLength="244" clip-path="url(#terminal-line-16)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" 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="414.8" clip-path="url(#terminal-line-17)">1 model · 0 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="61" clip-path="url(#terminal-line-18)">Type </text><text class="terminal-r3" x="61" y="459.2" textLength="61" clip-path="url(#terminal-line-18)">/help</text><text class="terminal-r1" x="122" 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="24.4" y="532.4" textLength="451.4" clip-path="url(#terminal-line-21)">Here's a very long print instruction:</text><text class="terminal-r1" x="1464" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
|
@ -177,13 +177,13 @@
|
|||
</text><text class="terminal-r1" x="1220" y="386" textLength="12.2" clip-path="url(#terminal-line-15)">
|
||||
</text><text class="terminal-r1" x="1220" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">
|
||||
</text><text class="terminal-r1" x="1220" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">
|
||||
</text><text class="terminal-r1" x="1220" y="459.2" textLength="12.2" clip-path="url(#terminal-line-18)">
|
||||
</text><text class="terminal-r1" x="1220" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">
|
||||
</text><text class="terminal-r1" x="1220" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</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="1220" 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="1220" 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="1220" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r1" x="1220" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">
|
||||
</text><text class="terminal-r1" x="0" y="556.8" textLength="134.2" clip-path="url(#terminal-line-22)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="556.8" textLength="146.4" clip-path="url(#terminal-line-22)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="556.8" textLength="122" clip-path="url(#terminal-line-22)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="556.8" textLength="244" clip-path="url(#terminal-line-22)">devstral-latest[off]</text><text class="terminal-r1" x="683.2" y="556.8" textLength="256.2" clip-path="url(#terminal-line-22)"> · [Subscription] Pro</text><text class="terminal-r1" x="1220" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">
|
||||
</text><text class="terminal-r1" x="0" y="581.2" textLength="134.2" clip-path="url(#terminal-line-23)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="581.2" textLength="414.8" clip-path="url(#terminal-line-23)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1220" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r1" x="0" y="605.6" textLength="134.2" clip-path="url(#terminal-line-24)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="605.6" textLength="61" clip-path="url(#terminal-line-24)">Type </text><text class="terminal-r3" x="231.8" y="605.6" textLength="61" clip-path="url(#terminal-line-24)">/help</text><text class="terminal-r1" x="292.8" y="605.6" textLength="256.2" clip-path="url(#terminal-line-24)"> for more information</text><text class="terminal-r1" x="1220" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">
|
||||
</text><text class="terminal-r2" x="0" y="556.8" textLength="146.4" clip-path="url(#terminal-line-22)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="556.8" textLength="122" clip-path="url(#terminal-line-22)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="556.8" textLength="244" clip-path="url(#terminal-line-22)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" y="556.8" textLength="256.2" clip-path="url(#terminal-line-22)"> · [Subscription] Pro</text><text class="terminal-r1" x="1220" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">
|
||||
</text><text class="terminal-r1" x="0" y="581.2" textLength="414.8" clip-path="url(#terminal-line-23)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1220" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r1" x="0" y="605.6" textLength="61" clip-path="url(#terminal-line-24)">Type </text><text class="terminal-r3" x="61" y="605.6" textLength="61" clip-path="url(#terminal-line-24)">/help</text><text class="terminal-r1" x="122" y="605.6" textLength="256.2" clip-path="url(#terminal-line-24)"> for more information</text><text class="terminal-r1" x="1220" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">
|
||||
</text><text class="terminal-r1" x="1220" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r1" x="24.4" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">⎣</text><text class="terminal-r1" x="48.8" y="654.4" textLength="280.6" clip-path="url(#terminal-line-26)">Configuration opened...</text><text class="terminal-r1" x="1220" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</text><text class="terminal-r1" x="24.4" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">⎣</text><text class="terminal-r1" x="48.8" y="678.8" textLength="488" clip-path="url(#terminal-line-27)">Configuration closed (no changes saved).</text><text class="terminal-r1" x="1220" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
|
@ -177,13 +177,13 @@
|
|||
</text><text class="terminal-r1" x="1220" y="288.4" textLength="12.2" clip-path="url(#terminal-line-11)">
|
||||
</text><text class="terminal-r1" x="1220" y="312.8" textLength="12.2" clip-path="url(#terminal-line-12)">
|
||||
</text><text class="terminal-r1" x="1220" y="337.2" textLength="12.2" clip-path="url(#terminal-line-13)">
|
||||
</text><text class="terminal-r1" x="1220" y="361.6" textLength="12.2" clip-path="url(#terminal-line-14)">
|
||||
</text><text class="terminal-r1" x="1220" y="386" textLength="12.2" clip-path="url(#terminal-line-15)">
|
||||
</text><text class="terminal-r1" x="1220" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">
|
||||
</text><text class="terminal-r1" x="0" y="361.6" textLength="134.2" clip-path="url(#terminal-line-14)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r1" x="1220" 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="1220" 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="1220" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">
|
||||
</text><text class="terminal-r1" x="1220" 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="244" clip-path="url(#terminal-line-18)">devstral-latest[off]</text><text class="terminal-r1" x="683.2" y="459.2" textLength="256.2" clip-path="url(#terminal-line-18)"> · [Subscription] Pro</text><text class="terminal-r1" x="1220" 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 · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1220" 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="1220" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r2" x="0" y="459.2" textLength="146.4" clip-path="url(#terminal-line-18)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="459.2" textLength="122" clip-path="url(#terminal-line-18)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="459.2" textLength="244" clip-path="url(#terminal-line-18)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" y="459.2" textLength="256.2" clip-path="url(#terminal-line-18)"> · [Subscription] Pro</text><text class="terminal-r1" x="1220" y="459.2" textLength="12.2" clip-path="url(#terminal-line-18)">
|
||||
</text><text class="terminal-r1" x="0" y="483.6" textLength="414.8" clip-path="url(#terminal-line-19)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1220" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">
|
||||
</text><text class="terminal-r1" x="0" y="508" textLength="61" clip-path="url(#terminal-line-20)">Type </text><text class="terminal-r3" x="61" y="508" textLength="61" clip-path="url(#terminal-line-20)">/help</text><text class="terminal-r1" x="122" y="508" textLength="256.2" clip-path="url(#terminal-line-20)"> for more information</text><text class="terminal-r1" x="1220" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r1" x="1220" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">
|
||||
</text><text class="terminal-r1" 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="280.6" clip-path="url(#terminal-line-22)">Configuration opened...</text><text class="terminal-r1" x="1220" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">
|
||||
</text><text class="terminal-r1" x="1220" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
|
@ -177,13 +177,13 @@
|
|||
</text><text class="terminal-r1" x="1220" y="288.4" textLength="12.2" clip-path="url(#terminal-line-11)">
|
||||
</text><text class="terminal-r1" x="1220" y="312.8" textLength="12.2" clip-path="url(#terminal-line-12)">
|
||||
</text><text class="terminal-r1" x="1220" y="337.2" textLength="12.2" clip-path="url(#terminal-line-13)">
|
||||
</text><text class="terminal-r1" x="1220" y="361.6" textLength="12.2" clip-path="url(#terminal-line-14)">
|
||||
</text><text class="terminal-r1" x="1220" y="386" textLength="12.2" clip-path="url(#terminal-line-15)">
|
||||
</text><text class="terminal-r1" x="1220" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">
|
||||
</text><text class="terminal-r1" x="0" y="361.6" textLength="134.2" clip-path="url(#terminal-line-14)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r1" x="1220" 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="1220" 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="1220" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">
|
||||
</text><text class="terminal-r1" x="1220" 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="244" clip-path="url(#terminal-line-18)">devstral-latest[off]</text><text class="terminal-r1" x="683.2" y="459.2" textLength="256.2" clip-path="url(#terminal-line-18)"> · [Subscription] Pro</text><text class="terminal-r1" x="1220" 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 · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1220" 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="1220" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r2" x="0" y="459.2" textLength="146.4" clip-path="url(#terminal-line-18)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="459.2" textLength="122" clip-path="url(#terminal-line-18)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="459.2" textLength="244" clip-path="url(#terminal-line-18)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" y="459.2" textLength="256.2" clip-path="url(#terminal-line-18)"> · [Subscription] Pro</text><text class="terminal-r1" x="1220" y="459.2" textLength="12.2" clip-path="url(#terminal-line-18)">
|
||||
</text><text class="terminal-r1" x="0" y="483.6" textLength="414.8" clip-path="url(#terminal-line-19)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1220" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">
|
||||
</text><text class="terminal-r1" x="0" y="508" textLength="61" clip-path="url(#terminal-line-20)">Type </text><text class="terminal-r3" x="61" y="508" textLength="61" clip-path="url(#terminal-line-20)">/help</text><text class="terminal-r1" x="122" y="508" textLength="256.2" clip-path="url(#terminal-line-20)"> for more information</text><text class="terminal-r1" x="1220" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r1" x="1220" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">
|
||||
</text><text class="terminal-r1" 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="280.6" clip-path="url(#terminal-line-22)">Configuration opened...</text><text class="terminal-r1" x="1220" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">
|
||||
</text><text class="terminal-r1" x="1220" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
|
@ -177,13 +177,13 @@
|
|||
</text><text class="terminal-r1" x="1220" y="288.4" textLength="12.2" clip-path="url(#terminal-line-11)">
|
||||
</text><text class="terminal-r1" x="1220" y="312.8" textLength="12.2" clip-path="url(#terminal-line-12)">
|
||||
</text><text class="terminal-r1" x="1220" y="337.2" textLength="12.2" clip-path="url(#terminal-line-13)">
|
||||
</text><text class="terminal-r1" x="1220" y="361.6" textLength="12.2" clip-path="url(#terminal-line-14)">
|
||||
</text><text class="terminal-r1" x="1220" y="386" textLength="12.2" clip-path="url(#terminal-line-15)">
|
||||
</text><text class="terminal-r1" x="1220" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">
|
||||
</text><text class="terminal-r1" x="0" y="361.6" textLength="134.2" clip-path="url(#terminal-line-14)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r1" x="1220" 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="1220" 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="1220" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">
|
||||
</text><text class="terminal-r1" x="1220" 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="244" clip-path="url(#terminal-line-18)">devstral-latest[off]</text><text class="terminal-r1" x="683.2" y="459.2" textLength="256.2" clip-path="url(#terminal-line-18)"> · [Subscription] Pro</text><text class="terminal-r1" x="1220" 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 · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1220" 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="1220" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r2" x="0" y="459.2" textLength="146.4" clip-path="url(#terminal-line-18)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="459.2" textLength="122" clip-path="url(#terminal-line-18)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="459.2" textLength="244" clip-path="url(#terminal-line-18)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" y="459.2" textLength="256.2" clip-path="url(#terminal-line-18)"> · [Subscription] Pro</text><text class="terminal-r1" x="1220" y="459.2" textLength="12.2" clip-path="url(#terminal-line-18)">
|
||||
</text><text class="terminal-r1" x="0" y="483.6" textLength="414.8" clip-path="url(#terminal-line-19)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1220" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">
|
||||
</text><text class="terminal-r1" x="0" y="508" textLength="61" clip-path="url(#terminal-line-20)">Type </text><text class="terminal-r3" x="61" y="508" textLength="61" clip-path="url(#terminal-line-20)">/help</text><text class="terminal-r1" x="122" y="508" textLength="256.2" clip-path="url(#terminal-line-20)"> for more information</text><text class="terminal-r1" x="1220" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r1" x="1220" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">
|
||||
</text><text class="terminal-r1" 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="280.6" clip-path="url(#terminal-line-22)">Configuration opened...</text><text class="terminal-r1" x="1220" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">
|
||||
</text><text class="terminal-r1" x="1220" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
|
@ -180,13 +180,13 @@
|
|||
</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-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-r1" 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-r1" x="0" y="532.4" textLength="134.2" clip-path="url(#terminal-line-21)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</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="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-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r1" x="0" y="605.6" textLength="134.2" clip-path="url(#terminal-line-24)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="605.6" textLength="146.4" clip-path="url(#terminal-line-24)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="605.6" textLength="122" clip-path="url(#terminal-line-24)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="605.6" textLength="244" clip-path="url(#terminal-line-24)">devstral-latest[off]</text><text class="terminal-r1" x="683.2" y="605.6" textLength="256.2" clip-path="url(#terminal-line-24)"> · [Subscription] Pro</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="0" y="630" textLength="134.2" clip-path="url(#terminal-line-25)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="630" textLength="414.8" clip-path="url(#terminal-line-25)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r1" x="0" y="654.4" textLength="134.2" clip-path="url(#terminal-line-26)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">Type </text><text class="terminal-r3" x="231.8" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">/help</text><text class="terminal-r1" x="292.8" y="654.4" textLength="256.2" clip-path="url(#terminal-line-26)"> for more information</text><text class="terminal-r4" x="719.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-r2" x="0" y="605.6" textLength="146.4" clip-path="url(#terminal-line-24)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="605.6" textLength="122" clip-path="url(#terminal-line-24)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="605.6" textLength="244" clip-path="url(#terminal-line-24)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" y="605.6" textLength="256.2" clip-path="url(#terminal-line-24)"> · [Subscription] Pro</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="0" y="630" textLength="414.8" clip-path="url(#terminal-line-25)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r1" x="0" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">Type </text><text class="terminal-r3" x="61" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">/help</text><text class="terminal-r1" x="122" y="654.4" textLength="256.2" clip-path="url(#terminal-line-26)"> for more information</text><text class="terminal-r4" x="719.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-r4" x="719.8" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">▌</text><text class="terminal-r1" x="744.2" y="678.8" textLength="414.8" clip-path="url(#terminal-line-27)">/test/skills/broken-skill/SKILL.md</text><text class="terminal-r1" x="1464" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">
|
||||
</text><text class="terminal-r4" x="719.8" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">▌</text><text class="terminal-r1" x="744.2" y="703.2" textLength="634.4" clip-path="url(#terminal-line-28)">Failed to load: missing required field 'description'</text><text class="terminal-r1" x="1464" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">
|
||||
</text><text class="terminal-r4" x="719.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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
|
@ -180,13 +180,13 @@
|
|||
</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-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-r1" 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-r1" x="0" y="532.4" textLength="134.2" clip-path="url(#terminal-line-21)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</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="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-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r1" x="0" y="605.6" textLength="134.2" clip-path="url(#terminal-line-24)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="605.6" textLength="146.4" clip-path="url(#terminal-line-24)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="605.6" textLength="122" clip-path="url(#terminal-line-24)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="605.6" textLength="244" clip-path="url(#terminal-line-24)">devstral-latest[off]</text><text class="terminal-r1" x="683.2" y="605.6" textLength="256.2" clip-path="url(#terminal-line-24)"> · [Subscription] Pro</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="0" y="630" textLength="134.2" clip-path="url(#terminal-line-25)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="630" textLength="414.8" clip-path="url(#terminal-line-25)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r1" x="0" y="654.4" textLength="134.2" clip-path="url(#terminal-line-26)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">Type </text><text class="terminal-r3" x="231.8" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">/help</text><text class="terminal-r1" x="292.8" y="654.4" textLength="256.2" clip-path="url(#terminal-line-26)"> for more information</text><text class="terminal-r4" x="719.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-r2" x="0" y="605.6" textLength="146.4" clip-path="url(#terminal-line-24)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="605.6" textLength="122" clip-path="url(#terminal-line-24)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="605.6" textLength="244" clip-path="url(#terminal-line-24)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" y="605.6" textLength="256.2" clip-path="url(#terminal-line-24)"> · [Subscription] Pro</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="0" y="630" textLength="414.8" clip-path="url(#terminal-line-25)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r1" x="0" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">Type </text><text class="terminal-r3" x="61" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">/help</text><text class="terminal-r1" x="122" y="654.4" textLength="256.2" clip-path="url(#terminal-line-26)"> for more information</text><text class="terminal-r4" x="719.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-r4" x="719.8" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">▌</text><text class="terminal-r1" x="744.2" y="678.8" textLength="341.6" clip-path="url(#terminal-line-27)">/test/hooks/broken-hook.toml</text><text class="terminal-r1" x="1464" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">
|
||||
</text><text class="terminal-r4" x="719.8" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">▌</text><text class="terminal-r1" x="744.2" y="703.2" textLength="439.2" clip-path="url(#terminal-line-28)">Failed to parse: invalid TOML syntax</text><text class="terminal-r1" x="1464" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">
|
||||
</text><text class="terminal-r4" x="719.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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
|
@ -175,13 +175,13 @@
|
|||
</text><text class="terminal-r1" x="1220" y="288.4" textLength="12.2" clip-path="url(#terminal-line-11)">
|
||||
</text><text class="terminal-r1" x="1220" y="312.8" textLength="12.2" clip-path="url(#terminal-line-12)">
|
||||
</text><text class="terminal-r1" x="1220" y="337.2" textLength="12.2" clip-path="url(#terminal-line-13)">
|
||||
</text><text class="terminal-r1" x="1220" y="361.6" textLength="12.2" clip-path="url(#terminal-line-14)">
|
||||
</text><text class="terminal-r1" x="1220" y="386" textLength="12.2" clip-path="url(#terminal-line-15)">
|
||||
</text><text class="terminal-r1" x="1220" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">
|
||||
</text><text class="terminal-r1" x="0" y="361.6" textLength="134.2" clip-path="url(#terminal-line-14)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r1" x="1220" 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="1220" 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="1220" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">
|
||||
</text><text class="terminal-r1" x="1220" 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="244" clip-path="url(#terminal-line-18)">devstral-latest[off]</text><text class="terminal-r1" x="683.2" y="459.2" textLength="256.2" clip-path="url(#terminal-line-18)"> · [Subscription] Pro</text><text class="terminal-r1" x="1220" 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 · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1220" 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="1220" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r2" x="0" y="459.2" textLength="146.4" clip-path="url(#terminal-line-18)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="459.2" textLength="122" clip-path="url(#terminal-line-18)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="459.2" textLength="244" clip-path="url(#terminal-line-18)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" y="459.2" textLength="256.2" clip-path="url(#terminal-line-18)"> · [Subscription] Pro</text><text class="terminal-r1" x="1220" y="459.2" textLength="12.2" clip-path="url(#terminal-line-18)">
|
||||
</text><text class="terminal-r1" x="0" y="483.6" textLength="414.8" clip-path="url(#terminal-line-19)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1220" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">
|
||||
</text><text class="terminal-r1" x="0" y="508" textLength="61" clip-path="url(#terminal-line-20)">Type </text><text class="terminal-r3" x="61" y="508" textLength="61" clip-path="url(#terminal-line-20)">/help</text><text class="terminal-r1" x="122" y="508" textLength="256.2" clip-path="url(#terminal-line-20)"> for more information</text><text class="terminal-r1" x="1220" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r1" x="1220" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">
|
||||
</text><text class="terminal-r1" x="24.4" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">⎢</text><text class="terminal-r4" x="48.8" y="556.8" textLength="414.8" clip-path="url(#terminal-line-22)">Your Data Helps Improve Mistral AI</text><text class="terminal-r1" x="1220" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">
|
||||
</text><text class="terminal-r1" 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="1159" clip-path="url(#terminal-line-23)">At Mistral AI, we're committed to delivering the best possible experience. When you use Mistral</text><text class="terminal-r1" x="1220" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
|
@ -179,13 +179,13 @@
|
|||
</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-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-r1" 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-r1" x="0" y="532.4" textLength="134.2" clip-path="url(#terminal-line-21)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</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="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-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r1" x="0" y="605.6" textLength="134.2" clip-path="url(#terminal-line-24)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="605.6" textLength="146.4" clip-path="url(#terminal-line-24)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="605.6" textLength="122" clip-path="url(#terminal-line-24)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="605.6" textLength="244" clip-path="url(#terminal-line-24)">devstral-latest[off]</text><text class="terminal-r1" x="683.2" y="605.6" textLength="256.2" clip-path="url(#terminal-line-24)"> · [Subscription] Pro</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="0" y="630" textLength="134.2" clip-path="url(#terminal-line-25)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="630" textLength="414.8" clip-path="url(#terminal-line-25)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r1" x="0" y="654.4" textLength="134.2" clip-path="url(#terminal-line-26)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">Type </text><text class="terminal-r3" x="231.8" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">/help</text><text class="terminal-r1" x="292.8" y="654.4" textLength="256.2" clip-path="url(#terminal-line-26)"> for more information</text><text class="terminal-r1" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</text><text class="terminal-r2" x="0" y="605.6" textLength="146.4" clip-path="url(#terminal-line-24)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="605.6" textLength="122" clip-path="url(#terminal-line-24)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="605.6" textLength="244" clip-path="url(#terminal-line-24)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" y="605.6" textLength="256.2" clip-path="url(#terminal-line-24)"> · [Subscription] Pro</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="0" y="630" textLength="414.8" clip-path="url(#terminal-line-25)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r1" x="0" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">Type </text><text class="terminal-r3" x="61" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">/help</text><text class="terminal-r1" x="122" y="654.4" textLength="256.2" clip-path="url(#terminal-line-26)"> for more information</text><text class="terminal-r1" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
|
@ -182,13 +182,13 @@
|
|||
</text><text class="terminal-r1" x="878.4" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">│</text><text class="terminal-r1" x="902.8" y="434.8" textLength="268.4" clip-path="url(#terminal-line-17)">connection attempt 1/3</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="878.4" y="459.2" textLength="12.2" clip-path="url(#terminal-line-18)">│</text><text class="terminal-r2" x="902.8" y="459.2" textLength="231.8" clip-path="url(#terminal-line-18)">2026-02-21 10:28:51</text><text class="terminal-r4" x="1146.8" y="459.2" textLength="97.6" clip-path="url(#terminal-line-18)">WARNING </text><text class="terminal-r1" x="1244.4" y="459.2" textLength="207.4" clip-path="url(#terminal-line-18)"> Rate limit      </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="878.4" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">│</text><text class="terminal-r1" x="902.8" y="483.6" textLength="414.8" clip-path="url(#terminal-line-19)">approaching for client api-key-abc</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="878.4" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">│</text><text class="terminal-r2" x="902.8" y="508" textLength="231.8" clip-path="url(#terminal-line-20)">2026-02-21 10:28:52</text><text class="terminal-r3" x="1146.8" y="508" textLength="97.6" clip-path="url(#terminal-line-20)">INFO    </text><text class="terminal-r1" x="1244.4" y="508" textLength="207.4" clip-path="url(#terminal-line-20)"> Health check    </text><text class="terminal-r1" x="1464" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r1" x="878.4" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">│</text><text class="terminal-r1" x="902.8" y="532.4" textLength="73.2" clip-path="url(#terminal-line-21)">passed</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="878.4" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">│</text><text class="terminal-r2" x="902.8" y="556.8" textLength="231.8" clip-path="url(#terminal-line-22)">2026-02-21 10:28:53</text><text class="terminal-r6" x="1146.8" y="556.8" textLength="97.6" clip-path="url(#terminal-line-22)">CRITICAL</text><text class="terminal-r1" x="1244.4" y="556.8" textLength="207.4" clip-path="url(#terminal-line-22)"> Out of memory   </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="878.4" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">│</text><text class="terminal-r1" x="902.8" y="581.2" textLength="170.8" clip-path="url(#terminal-line-23)">error detected</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="0" y="605.6" textLength="134.2" clip-path="url(#terminal-line-24)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r7" x="170.8" y="605.6" textLength="146.4" clip-path="url(#terminal-line-24)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="605.6" textLength="122" clip-path="url(#terminal-line-24)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="605.6" textLength="244" clip-path="url(#terminal-line-24)">devstral-latest[off]</text><text class="terminal-r1" x="683.2" y="605.6" textLength="195.2" clip-path="url(#terminal-line-24)"> · [Subscription</text><text class="terminal-r1" x="878.4" 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-r1" x="0" y="630" textLength="134.2" clip-path="url(#terminal-line-25)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="630" textLength="414.8" clip-path="url(#terminal-line-25)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="878.4" 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-r1" x="0" y="654.4" textLength="134.2" clip-path="url(#terminal-line-26)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">Type </text><text class="terminal-r3" x="231.8" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">/help</text><text class="terminal-r1" x="292.8" y="654.4" textLength="256.2" clip-path="url(#terminal-line-26)"> for more information</text><text class="terminal-r1" x="878.4" 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-r1" x="0" y="508" textLength="134.2" clip-path="url(#terminal-line-20)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r1" x="780.8" y="508" textLength="109.8" clip-path="url(#terminal-line-20)">        │</text><text class="terminal-r2" x="902.8" y="508" textLength="231.8" clip-path="url(#terminal-line-20)">2026-02-21 10:28:52</text><text class="terminal-r3" x="1146.8" y="508" textLength="97.6" clip-path="url(#terminal-line-20)">INFO    </text><text class="terminal-r1" x="1244.4" y="508" textLength="207.4" clip-path="url(#terminal-line-20)"> Health check    </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="532.4" textLength="134.2" clip-path="url(#terminal-line-21)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="780.8" y="532.4" textLength="109.8" clip-path="url(#terminal-line-21)">        │</text><text class="terminal-r1" x="902.8" y="532.4" textLength="73.2" clip-path="url(#terminal-line-21)">passed</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="0" y="556.8" textLength="134.2" clip-path="url(#terminal-line-22)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="780.8" y="556.8" textLength="109.8" clip-path="url(#terminal-line-22)">        │</text><text class="terminal-r2" x="902.8" y="556.8" textLength="231.8" clip-path="url(#terminal-line-22)">2026-02-21 10:28:53</text><text class="terminal-r6" x="1146.8" y="556.8" textLength="97.6" clip-path="url(#terminal-line-22)">CRITICAL</text><text class="terminal-r1" x="1244.4" y="556.8" textLength="207.4" clip-path="url(#terminal-line-22)"> Out of memory   </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="780.8" y="581.2" textLength="109.8" clip-path="url(#terminal-line-23)">        │</text><text class="terminal-r1" x="902.8" y="581.2" textLength="170.8" clip-path="url(#terminal-line-23)">error detected</text><text class="terminal-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r7" x="0" y="605.6" textLength="146.4" clip-path="url(#terminal-line-24)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="605.6" textLength="122" clip-path="url(#terminal-line-24)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="605.6" textLength="244" clip-path="url(#terminal-line-24)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" y="605.6" textLength="256.2" clip-path="url(#terminal-line-24)"> · [Subscription] Pro</text><text class="terminal-r1" x="780.8" y="605.6" textLength="109.8" 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-r1" x="0" y="630" textLength="414.8" clip-path="url(#terminal-line-25)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="780.8" y="630" textLength="109.8" 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-r1" x="0" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">Type </text><text class="terminal-r3" x="61" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">/help</text><text class="terminal-r1" x="122" y="654.4" textLength="256.2" clip-path="url(#terminal-line-26)"> for more information</text><text class="terminal-r1" x="780.8" y="654.4" textLength="109.8" 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-r1" x="878.4" 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-r1" x="878.4" 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-r1" x="878.4" 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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
|
@ -181,13 +181,13 @@
|
|||
</text><text class="terminal-r1" x="878.4" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">│</text><text class="terminal-r1" x="902.8" y="434.8" textLength="268.4" clip-path="url(#terminal-line-17)">connection attempt 1/3</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="878.4" y="459.2" textLength="12.2" clip-path="url(#terminal-line-18)">│</text><text class="terminal-r2" x="902.8" y="459.2" textLength="231.8" clip-path="url(#terminal-line-18)">2026-02-21 10:28:51</text><text class="terminal-r4" x="1146.8" y="459.2" textLength="97.6" clip-path="url(#terminal-line-18)">WARNING </text><text class="terminal-r1" x="1244.4" y="459.2" textLength="207.4" clip-path="url(#terminal-line-18)"> Rate limit      </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="878.4" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">│</text><text class="terminal-r1" x="902.8" y="483.6" textLength="414.8" clip-path="url(#terminal-line-19)">approaching for client api-key-abc</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="878.4" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">│</text><text class="terminal-r2" x="902.8" y="508" textLength="231.8" clip-path="url(#terminal-line-20)">2026-02-21 10:28:52</text><text class="terminal-r3" x="1146.8" y="508" textLength="97.6" clip-path="url(#terminal-line-20)">INFO    </text><text class="terminal-r1" x="1244.4" y="508" textLength="207.4" clip-path="url(#terminal-line-20)"> Health check    </text><text class="terminal-r1" x="1464" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r1" x="878.4" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">│</text><text class="terminal-r1" x="902.8" y="532.4" textLength="73.2" clip-path="url(#terminal-line-21)">passed</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="878.4" y="556.8" textLength="12.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-r1" x="878.4" y="581.2" textLength="12.2" 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-r1" x="0" y="605.6" textLength="134.2" clip-path="url(#terminal-line-24)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r6" x="170.8" y="605.6" textLength="146.4" clip-path="url(#terminal-line-24)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="605.6" textLength="122" clip-path="url(#terminal-line-24)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="605.6" textLength="244" clip-path="url(#terminal-line-24)">devstral-latest[off]</text><text class="terminal-r1" x="683.2" y="605.6" textLength="195.2" clip-path="url(#terminal-line-24)"> · [Subscription</text><text class="terminal-r1" x="878.4" 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-r1" x="0" y="630" textLength="134.2" clip-path="url(#terminal-line-25)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="630" textLength="414.8" clip-path="url(#terminal-line-25)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="878.4" 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-r1" x="0" y="654.4" textLength="134.2" clip-path="url(#terminal-line-26)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">Type </text><text class="terminal-r3" x="231.8" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">/help</text><text class="terminal-r1" x="292.8" y="654.4" textLength="256.2" clip-path="url(#terminal-line-26)"> for more information</text><text class="terminal-r1" x="878.4" 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-r1" x="0" y="508" textLength="134.2" clip-path="url(#terminal-line-20)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r1" x="780.8" y="508" textLength="109.8" clip-path="url(#terminal-line-20)">        │</text><text class="terminal-r2" x="902.8" y="508" textLength="231.8" clip-path="url(#terminal-line-20)">2026-02-21 10:28:52</text><text class="terminal-r3" x="1146.8" y="508" textLength="97.6" clip-path="url(#terminal-line-20)">INFO    </text><text class="terminal-r1" x="1244.4" y="508" textLength="207.4" clip-path="url(#terminal-line-20)"> Health check    </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="532.4" textLength="134.2" clip-path="url(#terminal-line-21)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="780.8" y="532.4" textLength="109.8" clip-path="url(#terminal-line-21)">        │</text><text class="terminal-r1" x="902.8" y="532.4" textLength="73.2" clip-path="url(#terminal-line-21)">passed</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="0" y="556.8" textLength="134.2" clip-path="url(#terminal-line-22)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="780.8" y="556.8" textLength="109.8" 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-r1" x="780.8" y="581.2" textLength="109.8" 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-r6" x="0" y="605.6" textLength="146.4" clip-path="url(#terminal-line-24)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="605.6" textLength="122" clip-path="url(#terminal-line-24)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="605.6" textLength="244" clip-path="url(#terminal-line-24)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" y="605.6" textLength="256.2" clip-path="url(#terminal-line-24)"> · [Subscription] Pro</text><text class="terminal-r1" x="780.8" y="605.6" textLength="109.8" 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-r1" x="0" y="630" textLength="414.8" clip-path="url(#terminal-line-25)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="780.8" y="630" textLength="109.8" 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-r1" x="0" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">Type </text><text class="terminal-r3" x="61" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">/help</text><text class="terminal-r1" x="122" y="654.4" textLength="256.2" clip-path="url(#terminal-line-26)"> for more information</text><text class="terminal-r1" x="780.8" y="654.4" textLength="109.8" 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-r1" x="878.4" 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-r1" x="878.4" 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-r1" x="878.4" 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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 23 KiB |
|
|
@ -178,13 +178,13 @@
|
|||
<rect fill="#4b4e55" x="1427.4" y="318.7" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#4b4e55" x="1427.4" y="343.1" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#4b4e55" x="1427.4" y="367.5" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#4b4e55" x="1427.4" y="391.9" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#4b4e55" x="1427.4" y="416.3" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#4b4e55" x="1427.4" y="440.7" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#4b4e55" x="1427.4" y="465.1" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#4b4e55" x="1427.4" y="489.5" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#4b4e55" x="1427.4" y="513.9" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#4b4e55" x="1427.4" y="538.3" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#4b4e55" x="1427.4" y="562.7" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#4b4e55" x="1427.4" y="587.1" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#4b4e55" x="1427.4" y="611.5" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="1427.4" y="635.9" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="1427.4" y="660.3" width="12.2" 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="0" y="44.4" textLength="134.2" clip-path="url(#terminal-line-1)">  ⡠⣒⠄  ⡔⢄⠔⡄</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="0" y="68.8" textLength="134.2" clip-path="url(#terminal-line-2)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</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="0" y="93.2" textLength="134.2" clip-path="url(#terminal-line-3)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</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="0" y="142" textLength="134.2" clip-path="url(#terminal-line-5)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="142" textLength="146.4" clip-path="url(#terminal-line-5)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="142" textLength="122" clip-path="url(#terminal-line-5)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="142" textLength="244" clip-path="url(#terminal-line-5)">devstral-latest[off]</text><text class="terminal-r1" x="683.2" y="142" textLength="256.2" clip-path="url(#terminal-line-5)"> · [Subscription] Pro</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="414.8" clip-path="url(#terminal-line-6)">1 model · 0 MCP servers · 0 skills</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="0" y="190.8" textLength="134.2" clip-path="url(#terminal-line-7)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="190.8" textLength="61" clip-path="url(#terminal-line-7)">Type </text><text class="terminal-r3" x="231.8" y="190.8" textLength="61" clip-path="url(#terminal-line-7)">/help</text><text class="terminal-r1" x="292.8" y="190.8" textLength="256.2" clip-path="url(#terminal-line-7)"> for more information</text><text class="terminal-r1" x="1464" y="190.8" textLength="12.2" clip-path="url(#terminal-line-7)">
|
||||
</text><text class="terminal-r2" x="0" y="142" textLength="146.4" clip-path="url(#terminal-line-5)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="142" textLength="122" clip-path="url(#terminal-line-5)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="142" textLength="244" clip-path="url(#terminal-line-5)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" y="142" textLength="256.2" clip-path="url(#terminal-line-5)"> · [Subscription] Pro</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="414.8" clip-path="url(#terminal-line-6)">1 model · 0 MCP servers · 0 skills</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="0" y="190.8" textLength="61" clip-path="url(#terminal-line-7)">Type </text><text class="terminal-r3" x="61" y="190.8" textLength="61" clip-path="url(#terminal-line-7)">/help</text><text class="terminal-r1" x="122" y="190.8" textLength="256.2" clip-path="url(#terminal-line-7)"> for more information</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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
|
@ -35,9 +35,9 @@
|
|||
.terminal-r1 { fill: #c5c8c6 }
|
||||
.terminal-r2 { fill: #ff8205;font-weight: bold }
|
||||
.terminal-r3 { fill: #68a0b3 }
|
||||
.terminal-r4 { fill: #d0b344;font-weight: bold }
|
||||
.terminal-r5 { fill: #d0b344 }
|
||||
.terminal-r6 { fill: #292929 }
|
||||
.terminal-r4 { fill: #292929 }
|
||||
.terminal-r5 { fill: #d0b344;font-weight: bold }
|
||||
.terminal-r6 { fill: #d0b344 }
|
||||
.terminal-r7 { fill: #98a84b;font-weight: bold }
|
||||
.terminal-r8 { fill: #cc555a }
|
||||
.terminal-r9 { fill: #868887 }
|
||||
|
|
@ -144,26 +144,26 @@
|
|||
</g>
|
||||
|
||||
<g transform="translate(9, 41)" clip-path="url(#terminal-clip-terminal)">
|
||||
<rect fill="#4b4e55" x="1183.4" y="245.5" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#4b4e55" x="1183.4" y="269.9" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#4b4e55" x="1183.4" y="294.3" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#4b4e55" x="1183.4" y="318.7" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#4b4e55" x="1183.4" y="343.1" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#4b4e55" x="1183.4" y="367.5" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#4b4e55" x="1183.4" y="391.9" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="1183.4" y="416.3" width="12.2" height="24.65" shape-rendering="crispEdges"/>
|
||||
<rect fill="#4b4e55" x="1207.8" y="1.5" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#4b4e55" x="1207.8" y="25.9" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="1207.8" y="50.3" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="1207.8" y="74.7" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="1207.8" y="99.1" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="1207.8" y="123.5" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#4b4e55" x="1183.4" y="245.5" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#4b4e55" x="1183.4" y="269.9" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#4b4e55" x="1183.4" y="294.3" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#4b4e55" x="1183.4" y="318.7" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#4b4e55" x="1183.4" y="343.1" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#4b4e55" x="1183.4" y="367.5" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#4b4e55" x="1183.4" y="391.9" width="12.2" height="24.65" shape-rendering="crispEdges"/><rect fill="#608ab1" x="1183.4" y="416.3" width="12.2" height="24.65" shape-rendering="crispEdges"/>
|
||||
<g class="terminal-matrix">
|
||||
<text class="terminal-r1" x="1220" y="20" textLength="12.2" clip-path="url(#terminal-line-0)">
|
||||
<text class="terminal-r1" x="0" y="20" textLength="134.2" clip-path="url(#terminal-line-0)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="1220" y="20" textLength="12.2" clip-path="url(#terminal-line-0)">
|
||||
</text><text class="terminal-r1" x="1220" y="44.4" textLength="12.2" clip-path="url(#terminal-line-1)">
|
||||
</text><text class="terminal-r1" x="0" y="68.8" textLength="134.2" clip-path="url(#terminal-line-2)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="68.8" textLength="146.4" clip-path="url(#terminal-line-2)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="68.8" textLength="122" clip-path="url(#terminal-line-2)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="68.8" textLength="244" clip-path="url(#terminal-line-2)">devstral-latest[off]</text><text class="terminal-r1" x="683.2" y="68.8" textLength="256.2" clip-path="url(#terminal-line-2)"> · [Subscription] Pro</text><text class="terminal-r1" x="1220" y="68.8" textLength="12.2" clip-path="url(#terminal-line-2)">
|
||||
</text><text class="terminal-r1" x="0" y="93.2" textLength="134.2" clip-path="url(#terminal-line-3)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="93.2" textLength="414.8" clip-path="url(#terminal-line-3)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1220" 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-r1" x="170.8" y="117.6" textLength="61" clip-path="url(#terminal-line-4)">Type </text><text class="terminal-r3" x="231.8" y="117.6" textLength="61" clip-path="url(#terminal-line-4)">/help</text><text class="terminal-r1" x="292.8" y="117.6" textLength="256.2" clip-path="url(#terminal-line-4)"> for more information</text><text class="terminal-r1" x="1220" y="117.6" textLength="12.2" clip-path="url(#terminal-line-4)">
|
||||
</text><text class="terminal-r2" x="0" y="68.8" textLength="146.4" clip-path="url(#terminal-line-2)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="68.8" textLength="122" clip-path="url(#terminal-line-2)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="68.8" textLength="244" clip-path="url(#terminal-line-2)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" y="68.8" textLength="256.2" clip-path="url(#terminal-line-2)"> · [Subscription] Pro</text><text class="terminal-r1" x="1220" y="68.8" textLength="12.2" clip-path="url(#terminal-line-2)">
|
||||
</text><text class="terminal-r1" x="0" y="93.2" textLength="414.8" clip-path="url(#terminal-line-3)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1220" y="93.2" textLength="12.2" clip-path="url(#terminal-line-3)">
|
||||
</text><text class="terminal-r1" x="0" y="117.6" textLength="61" clip-path="url(#terminal-line-4)">Type </text><text class="terminal-r3" x="61" y="117.6" textLength="61" clip-path="url(#terminal-line-4)">/help</text><text class="terminal-r1" x="122" y="117.6" textLength="256.2" clip-path="url(#terminal-line-4)"> for more information</text><text class="terminal-r1" x="1220" y="117.6" textLength="12.2" clip-path="url(#terminal-line-4)">
|
||||
</text><text class="terminal-r1" x="1220" y="142" textLength="12.2" clip-path="url(#terminal-line-5)">
|
||||
</text><text class="terminal-r1" x="1220" y="166.4" textLength="12.2" clip-path="url(#terminal-line-6)">
|
||||
</text><text class="terminal-r1" x="1220" y="190.8" textLength="12.2" clip-path="url(#terminal-line-7)">
|
||||
</text><text class="terminal-r1" x="0" y="215.2" textLength="1220" clip-path="url(#terminal-line-8)">┌──────────────────────────────────────────────────────────────────────────────────────────────────┐</text><text class="terminal-r1" x="1220" y="215.2" textLength="12.2" clip-path="url(#terminal-line-8)">
|
||||
</text><text class="terminal-r1" x="0" y="239.6" textLength="12.2" clip-path="url(#terminal-line-9)">│</text><text class="terminal-r4" x="24.4" y="239.6" textLength="414.8" clip-path="url(#terminal-line-9)">Permission for the write_file tool</text><text class="terminal-r1" x="1207.8" y="239.6" textLength="12.2" clip-path="url(#terminal-line-9)">│</text><text class="terminal-r1" x="1220" y="239.6" textLength="12.2" clip-path="url(#terminal-line-9)">
|
||||
</text><text class="terminal-r1" x="0" y="264" textLength="12.2" clip-path="url(#terminal-line-10)">│</text><text class="terminal-r1" x="24.4" y="264" textLength="97.6" clip-path="url(#terminal-line-10)">line_093</text><text class="terminal-r1" x="134.2" y="264" textLength="12.2" clip-path="url(#terminal-line-10)">=</text><text class="terminal-r5" x="158.6" y="264" textLength="36.6" clip-path="url(#terminal-line-10)">651</text><text class="terminal-r1" x="1207.8" y="264" textLength="12.2" clip-path="url(#terminal-line-10)">│</text><text class="terminal-r1" x="1220" y="264" textLength="12.2" clip-path="url(#terminal-line-10)">
|
||||
</text><text class="terminal-r1" x="0" y="288.4" textLength="12.2" clip-path="url(#terminal-line-11)">│</text><text class="terminal-r1" x="24.4" y="288.4" textLength="97.6" clip-path="url(#terminal-line-11)">line_094</text><text class="terminal-r1" x="134.2" y="288.4" textLength="12.2" clip-path="url(#terminal-line-11)">=</text><text class="terminal-r5" x="158.6" y="288.4" textLength="36.6" clip-path="url(#terminal-line-11)">658</text><text class="terminal-r1" x="1207.8" y="288.4" textLength="12.2" clip-path="url(#terminal-line-11)">│</text><text class="terminal-r1" x="1220" y="288.4" textLength="12.2" clip-path="url(#terminal-line-11)">
|
||||
</text><text class="terminal-r1" x="0" y="312.8" textLength="12.2" clip-path="url(#terminal-line-12)">│</text><text class="terminal-r1" x="24.4" y="312.8" textLength="97.6" clip-path="url(#terminal-line-12)">line_095</text><text class="terminal-r1" x="134.2" y="312.8" textLength="12.2" clip-path="url(#terminal-line-12)">=</text><text class="terminal-r5" x="158.6" y="312.8" textLength="36.6" clip-path="url(#terminal-line-12)">665</text><text class="terminal-r1" x="1207.8" y="312.8" textLength="12.2" clip-path="url(#terminal-line-12)">│</text><text class="terminal-r1" x="1220" y="312.8" textLength="12.2" clip-path="url(#terminal-line-12)">
|
||||
</text><text class="terminal-r1" x="0" y="337.2" textLength="12.2" clip-path="url(#terminal-line-13)">│</text><text class="terminal-r1" x="24.4" y="337.2" textLength="97.6" clip-path="url(#terminal-line-13)">line_096</text><text class="terminal-r1" x="134.2" y="337.2" textLength="12.2" clip-path="url(#terminal-line-13)">=</text><text class="terminal-r5" x="158.6" y="337.2" textLength="36.6" clip-path="url(#terminal-line-13)">672</text><text class="terminal-r1" x="1207.8" y="337.2" textLength="12.2" clip-path="url(#terminal-line-13)">│</text><text class="terminal-r1" x="1220" y="337.2" textLength="12.2" clip-path="url(#terminal-line-13)">
|
||||
</text><text class="terminal-r1" x="0" y="361.6" textLength="12.2" clip-path="url(#terminal-line-14)">│</text><text class="terminal-r1" x="24.4" y="361.6" textLength="97.6" clip-path="url(#terminal-line-14)">line_097</text><text class="terminal-r1" x="134.2" y="361.6" textLength="12.2" clip-path="url(#terminal-line-14)">=</text><text class="terminal-r5" x="158.6" y="361.6" textLength="36.6" clip-path="url(#terminal-line-14)">679</text><text class="terminal-r1" x="1207.8" y="361.6" textLength="12.2" clip-path="url(#terminal-line-14)">│</text><text class="terminal-r1" x="1220" y="361.6" textLength="12.2" clip-path="url(#terminal-line-14)">
|
||||
</text><text class="terminal-r1" x="0" y="386" textLength="12.2" clip-path="url(#terminal-line-15)">│</text><text class="terminal-r1" x="24.4" y="386" textLength="97.6" clip-path="url(#terminal-line-15)">line_098</text><text class="terminal-r1" x="134.2" y="386" textLength="12.2" clip-path="url(#terminal-line-15)">=</text><text class="terminal-r5" x="158.6" y="386" textLength="36.6" clip-path="url(#terminal-line-15)">686</text><text class="terminal-r1" x="1207.8" y="386" textLength="12.2" clip-path="url(#terminal-line-15)">│</text><text class="terminal-r1" x="1220" y="386" textLength="12.2" clip-path="url(#terminal-line-15)">
|
||||
</text><text class="terminal-r1" x="0" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">│</text><text class="terminal-r1" x="24.4" y="410.4" textLength="97.6" clip-path="url(#terminal-line-16)">line_099</text><text class="terminal-r1" x="134.2" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">=</text><text class="terminal-r5" x="158.6" y="410.4" textLength="36.6" clip-path="url(#terminal-line-16)">693</text><text class="terminal-r1" x="1207.8" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">│</text><text class="terminal-r1" x="1220" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">
|
||||
</text><text class="terminal-r1" x="0" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">│</text><text class="terminal-r1" x="24.4" y="434.8" textLength="97.6" clip-path="url(#terminal-line-17)">line_100</text><text class="terminal-r1" x="134.2" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">=</text><text class="terminal-r5" x="158.6" y="434.8" textLength="36.6" clip-path="url(#terminal-line-17)">700</text><text class="terminal-r1" x="1207.8" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">│</text><text class="terminal-r1" x="1220" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">
|
||||
</text><text class="terminal-r1" x="0" y="239.6" textLength="12.2" clip-path="url(#terminal-line-9)">│</text><text class="terminal-r5" x="24.4" y="239.6" textLength="414.8" clip-path="url(#terminal-line-9)">Permission for the write_file tool</text><text class="terminal-r1" x="1207.8" y="239.6" textLength="12.2" clip-path="url(#terminal-line-9)">│</text><text class="terminal-r1" x="1220" y="239.6" textLength="12.2" clip-path="url(#terminal-line-9)">
|
||||
</text><text class="terminal-r1" x="0" y="264" textLength="12.2" clip-path="url(#terminal-line-10)">│</text><text class="terminal-r1" x="24.4" y="264" textLength="97.6" clip-path="url(#terminal-line-10)">line_093</text><text class="terminal-r1" x="134.2" y="264" textLength="12.2" clip-path="url(#terminal-line-10)">=</text><text class="terminal-r6" x="158.6" y="264" textLength="36.6" clip-path="url(#terminal-line-10)">651</text><text class="terminal-r1" x="1207.8" y="264" textLength="12.2" clip-path="url(#terminal-line-10)">│</text><text class="terminal-r1" x="1220" y="264" textLength="12.2" clip-path="url(#terminal-line-10)">
|
||||
</text><text class="terminal-r1" x="0" y="288.4" textLength="12.2" clip-path="url(#terminal-line-11)">│</text><text class="terminal-r1" x="24.4" y="288.4" textLength="97.6" clip-path="url(#terminal-line-11)">line_094</text><text class="terminal-r1" x="134.2" y="288.4" textLength="12.2" clip-path="url(#terminal-line-11)">=</text><text class="terminal-r6" x="158.6" y="288.4" textLength="36.6" clip-path="url(#terminal-line-11)">658</text><text class="terminal-r1" x="1207.8" y="288.4" textLength="12.2" clip-path="url(#terminal-line-11)">│</text><text class="terminal-r1" x="1220" y="288.4" textLength="12.2" clip-path="url(#terminal-line-11)">
|
||||
</text><text class="terminal-r1" x="0" y="312.8" textLength="12.2" clip-path="url(#terminal-line-12)">│</text><text class="terminal-r1" x="24.4" y="312.8" textLength="97.6" clip-path="url(#terminal-line-12)">line_095</text><text class="terminal-r1" x="134.2" y="312.8" textLength="12.2" clip-path="url(#terminal-line-12)">=</text><text class="terminal-r6" x="158.6" y="312.8" textLength="36.6" clip-path="url(#terminal-line-12)">665</text><text class="terminal-r1" x="1207.8" y="312.8" textLength="12.2" clip-path="url(#terminal-line-12)">│</text><text class="terminal-r1" x="1220" y="312.8" textLength="12.2" clip-path="url(#terminal-line-12)">
|
||||
</text><text class="terminal-r1" x="0" y="337.2" textLength="12.2" clip-path="url(#terminal-line-13)">│</text><text class="terminal-r1" x="24.4" y="337.2" textLength="97.6" clip-path="url(#terminal-line-13)">line_096</text><text class="terminal-r1" x="134.2" y="337.2" textLength="12.2" clip-path="url(#terminal-line-13)">=</text><text class="terminal-r6" x="158.6" y="337.2" textLength="36.6" clip-path="url(#terminal-line-13)">672</text><text class="terminal-r1" x="1207.8" y="337.2" textLength="12.2" clip-path="url(#terminal-line-13)">│</text><text class="terminal-r1" x="1220" y="337.2" textLength="12.2" clip-path="url(#terminal-line-13)">
|
||||
</text><text class="terminal-r1" x="0" y="361.6" textLength="12.2" clip-path="url(#terminal-line-14)">│</text><text class="terminal-r1" x="24.4" y="361.6" textLength="97.6" clip-path="url(#terminal-line-14)">line_097</text><text class="terminal-r1" x="134.2" y="361.6" textLength="12.2" clip-path="url(#terminal-line-14)">=</text><text class="terminal-r6" x="158.6" y="361.6" textLength="36.6" clip-path="url(#terminal-line-14)">679</text><text class="terminal-r1" x="1207.8" y="361.6" textLength="12.2" clip-path="url(#terminal-line-14)">│</text><text class="terminal-r1" x="1220" y="361.6" textLength="12.2" clip-path="url(#terminal-line-14)">
|
||||
</text><text class="terminal-r1" x="0" y="386" textLength="12.2" clip-path="url(#terminal-line-15)">│</text><text class="terminal-r1" x="24.4" y="386" textLength="97.6" clip-path="url(#terminal-line-15)">line_098</text><text class="terminal-r1" x="134.2" y="386" textLength="12.2" clip-path="url(#terminal-line-15)">=</text><text class="terminal-r6" x="158.6" y="386" textLength="36.6" clip-path="url(#terminal-line-15)">686</text><text class="terminal-r1" x="1207.8" y="386" textLength="12.2" clip-path="url(#terminal-line-15)">│</text><text class="terminal-r1" x="1220" y="386" textLength="12.2" clip-path="url(#terminal-line-15)">
|
||||
</text><text class="terminal-r1" x="0" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">│</text><text class="terminal-r1" x="24.4" y="410.4" textLength="97.6" clip-path="url(#terminal-line-16)">line_099</text><text class="terminal-r1" x="134.2" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">=</text><text class="terminal-r6" x="158.6" y="410.4" textLength="36.6" clip-path="url(#terminal-line-16)">693</text><text class="terminal-r1" x="1207.8" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">│</text><text class="terminal-r1" x="1220" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">
|
||||
</text><text class="terminal-r1" x="0" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">│</text><text class="terminal-r1" x="24.4" y="434.8" textLength="97.6" clip-path="url(#terminal-line-17)">line_100</text><text class="terminal-r1" x="134.2" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">=</text><text class="terminal-r6" x="158.6" y="434.8" textLength="36.6" clip-path="url(#terminal-line-17)">700</text><text class="terminal-r1" x="1207.8" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">│</text><text class="terminal-r1" x="1220" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">
|
||||
</text><text class="terminal-r1" x="0" y="459.2" textLength="12.2" clip-path="url(#terminal-line-18)">│</text><text class="terminal-r1" x="1207.8" y="459.2" textLength="12.2" clip-path="url(#terminal-line-18)">│</text><text class="terminal-r1" x="1220" y="459.2" textLength="12.2" clip-path="url(#terminal-line-18)">
|
||||
</text><text class="terminal-r1" x="0" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">│</text><text class="terminal-r7" x="24.4" y="483.6" textLength="183" clip-path="url(#terminal-line-19)">› 1. Allow once</text><text class="terminal-r1" x="1207.8" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">│</text><text class="terminal-r1" x="1220" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">
|
||||
</text><text class="terminal-r1" x="0" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">│</text><text class="terminal-r1" x="1207.8" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">│</text><text class="terminal-r1" x="1220" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
|
@ -148,13 +148,13 @@
|
|||
<text class="terminal-r1" x="1220" y="20" textLength="12.2" clip-path="url(#terminal-line-0)">
|
||||
</text><text class="terminal-r1" x="1220" y="44.4" textLength="12.2" clip-path="url(#terminal-line-1)">
|
||||
</text><text class="terminal-r1" x="1220" y="68.8" textLength="12.2" clip-path="url(#terminal-line-2)">
|
||||
</text><text class="terminal-r1" x="1220" y="93.2" textLength="12.2" clip-path="url(#terminal-line-3)">
|
||||
</text><text class="terminal-r1" x="1220" y="117.6" textLength="12.2" clip-path="url(#terminal-line-4)">
|
||||
</text><text class="terminal-r1" x="1220" y="142" textLength="12.2" clip-path="url(#terminal-line-5)">
|
||||
</text><text class="terminal-r1" x="0" y="93.2" textLength="134.2" clip-path="url(#terminal-line-3)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r1" x="1220" 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-r1" x="1220" 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="1220" y="142" textLength="12.2" clip-path="url(#terminal-line-5)">
|
||||
</text><text class="terminal-r1" x="1220" y="166.4" textLength="12.2" clip-path="url(#terminal-line-6)">
|
||||
</text><text class="terminal-r1" x="0" y="190.8" textLength="134.2" clip-path="url(#terminal-line-7)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="190.8" textLength="146.4" clip-path="url(#terminal-line-7)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="190.8" textLength="122" clip-path="url(#terminal-line-7)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="190.8" textLength="244" clip-path="url(#terminal-line-7)">devstral-latest[off]</text><text class="terminal-r1" x="683.2" y="190.8" textLength="256.2" clip-path="url(#terminal-line-7)"> · [Subscription] Pro</text><text class="terminal-r1" x="1220" y="190.8" textLength="12.2" clip-path="url(#terminal-line-7)">
|
||||
</text><text class="terminal-r1" x="0" y="215.2" textLength="134.2" clip-path="url(#terminal-line-8)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="215.2" textLength="414.8" clip-path="url(#terminal-line-8)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1220" y="215.2" textLength="12.2" clip-path="url(#terminal-line-8)">
|
||||
</text><text class="terminal-r1" x="0" y="239.6" textLength="134.2" clip-path="url(#terminal-line-9)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="239.6" textLength="61" clip-path="url(#terminal-line-9)">Type </text><text class="terminal-r3" x="231.8" y="239.6" textLength="61" clip-path="url(#terminal-line-9)">/help</text><text class="terminal-r1" x="292.8" y="239.6" textLength="256.2" clip-path="url(#terminal-line-9)"> for more information</text><text class="terminal-r1" x="1220" y="239.6" textLength="12.2" clip-path="url(#terminal-line-9)">
|
||||
</text><text class="terminal-r2" x="0" y="190.8" textLength="146.4" clip-path="url(#terminal-line-7)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="190.8" textLength="122" clip-path="url(#terminal-line-7)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="190.8" textLength="244" clip-path="url(#terminal-line-7)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" y="190.8" textLength="256.2" clip-path="url(#terminal-line-7)"> · [Subscription] Pro</text><text class="terminal-r1" x="1220" y="190.8" textLength="12.2" clip-path="url(#terminal-line-7)">
|
||||
</text><text class="terminal-r1" x="0" y="215.2" textLength="414.8" clip-path="url(#terminal-line-8)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1220" y="215.2" textLength="12.2" clip-path="url(#terminal-line-8)">
|
||||
</text><text class="terminal-r1" x="0" y="239.6" textLength="61" clip-path="url(#terminal-line-9)">Type </text><text class="terminal-r3" x="61" y="239.6" textLength="61" clip-path="url(#terminal-line-9)">/help</text><text class="terminal-r1" x="122" y="239.6" textLength="256.2" clip-path="url(#terminal-line-9)"> for more information</text><text class="terminal-r1" x="1220" y="239.6" textLength="12.2" clip-path="url(#terminal-line-9)">
|
||||
</text><text class="terminal-r1" x="1220" y="264" textLength="12.2" clip-path="url(#terminal-line-10)">
|
||||
</text><text class="terminal-r1" x="1220" y="288.4" textLength="12.2" clip-path="url(#terminal-line-11)">
|
||||
</text><text class="terminal-r1" x="1220" y="312.8" textLength="12.2" clip-path="url(#terminal-line-12)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
|
@ -37,7 +37,7 @@
|
|||
.terminal-r3 { fill: #68a0b3 }
|
||||
.terminal-r4 { fill: #c5c8c6;font-weight: bold }
|
||||
.terminal-r5 { fill: #868887 }
|
||||
.terminal-r6 { fill: #6b753d }
|
||||
.terminal-r6 { fill: #98a84b }
|
||||
</style>
|
||||
|
||||
<defs>
|
||||
|
|
@ -173,20 +173,20 @@
|
|||
</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="0" y="312.8" textLength="134.2" 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-r1" x="0" y="337.2" textLength="134.2" clip-path="url(#terminal-line-13)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</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-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="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="244" clip-path="url(#terminal-line-16)">devstral-latest[off]</text><text class="terminal-r1" x="683.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 · 0 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-r2" x="0" y="410.4" textLength="146.4" clip-path="url(#terminal-line-16)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="410.4" textLength="122" clip-path="url(#terminal-line-16)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="410.4" textLength="244" clip-path="url(#terminal-line-16)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" 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="414.8" clip-path="url(#terminal-line-17)">1 model · 0 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="61" clip-path="url(#terminal-line-18)">Type </text><text class="terminal-r3" x="61" y="459.2" textLength="61" clip-path="url(#terminal-line-18)">/help</text><text class="terminal-r1" x="122" 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-r2" x="0" y="556.8" textLength="24.4" clip-path="url(#terminal-line-22)">> </text><text class="terminal-r4" x="24.4" y="556.8" textLength="231.8" clip-path="url(#terminal-line-22)">What is the answer?</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-r1" x="1464" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">
|
||||
</text><text class="terminal-r6" x="0" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">✓</text><text class="terminal-r5" x="24.4" y="630" textLength="85.4" clip-path="url(#terminal-line-25)">Thought</text><text class="terminal-r5" x="122" 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-r6" x="0" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">■</text><text class="terminal-r5" x="24.4" y="630" textLength="85.4" clip-path="url(#terminal-line-25)">Thought</text><text class="terminal-r5" x="122" 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-r1" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</text><text class="terminal-r1" x="24.4" y="678.8" textLength="207.4" clip-path="url(#terminal-line-27)">The answer is 42.</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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
|
@ -175,13 +175,13 @@
|
|||
</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="361.6" textLength="134.2" clip-path="url(#terminal-line-14)">  ⡠⣒⠄  ⡔⢄⠔⡄</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="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="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="244" clip-path="url(#terminal-line-18)">devstral-latest[off]</text><text class="terminal-r1" x="683.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 · 0 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-r2" x="0" y="459.2" textLength="146.4" clip-path="url(#terminal-line-18)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="459.2" textLength="122" clip-path="url(#terminal-line-18)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="459.2" textLength="244" clip-path="url(#terminal-line-18)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" 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="414.8" clip-path="url(#terminal-line-19)">1 model · 0 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="61" clip-path="url(#terminal-line-20)">Type </text><text class="terminal-r3" x="61" y="508" textLength="61" clip-path="url(#terminal-line-20)">/help</text><text class="terminal-r1" x="122" 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-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
|
@ -179,13 +179,13 @@
|
|||
</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-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-r1" 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-r1" x="0" y="532.4" textLength="134.2" clip-path="url(#terminal-line-21)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</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="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-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r1" x="0" y="605.6" textLength="134.2" clip-path="url(#terminal-line-24)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="605.6" textLength="146.4" clip-path="url(#terminal-line-24)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="605.6" textLength="122" clip-path="url(#terminal-line-24)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="605.6" textLength="244" clip-path="url(#terminal-line-24)">devstral-latest[off]</text><text class="terminal-r1" x="683.2" y="605.6" textLength="256.2" clip-path="url(#terminal-line-24)"> · [Subscription] Pro</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="0" y="630" textLength="134.2" clip-path="url(#terminal-line-25)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="630" textLength="414.8" clip-path="url(#terminal-line-25)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r1" x="0" y="654.4" textLength="134.2" clip-path="url(#terminal-line-26)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">Type </text><text class="terminal-r3" x="231.8" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">/help</text><text class="terminal-r1" x="292.8" y="654.4" textLength="256.2" clip-path="url(#terminal-line-26)"> for more information</text><text class="terminal-r1" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</text><text class="terminal-r2" x="0" y="605.6" textLength="146.4" clip-path="url(#terminal-line-24)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="605.6" textLength="122" clip-path="url(#terminal-line-24)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="605.6" textLength="244" clip-path="url(#terminal-line-24)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" y="605.6" textLength="256.2" clip-path="url(#terminal-line-24)"> · [Subscription] Pro</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="0" y="630" textLength="414.8" clip-path="url(#terminal-line-25)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r1" x="0" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">Type </text><text class="terminal-r3" x="61" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">/help</text><text class="terminal-r1" x="122" y="654.4" textLength="256.2" clip-path="url(#terminal-line-26)"> for more information</text><text class="terminal-r1" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
|
@ -173,13 +173,13 @@
|
|||
</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="0" y="337.2" textLength="134.2" clip-path="url(#terminal-line-13)">  ⡠⣒⠄  ⡔⢄⠔⡄</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-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="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="244" clip-path="url(#terminal-line-17)">devstral-latest[off]</text><text class="terminal-r1" x="683.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 · 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-r2" x="0" y="434.8" textLength="146.4" clip-path="url(#terminal-line-17)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="434.8" textLength="122" clip-path="url(#terminal-line-17)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="434.8" textLength="244" clip-path="url(#terminal-line-17)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" 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="414.8" clip-path="url(#terminal-line-18)">1 model · 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="61" clip-path="url(#terminal-line-19)">Type </text><text class="terminal-r3" x="61" y="483.6" textLength="61" clip-path="url(#terminal-line-19)">/help</text><text class="terminal-r1" x="122" 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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
|
@ -173,13 +173,13 @@
|
|||
</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="0" y="337.2" textLength="134.2" clip-path="url(#terminal-line-13)">  ⡠⣒⠄  ⡔⢄⠔⡄</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-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="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="244" clip-path="url(#terminal-line-17)">devstral-latest[off]</text><text class="terminal-r1" x="683.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 · 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-r2" x="0" y="434.8" textLength="146.4" clip-path="url(#terminal-line-17)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="434.8" textLength="122" clip-path="url(#terminal-line-17)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="434.8" textLength="244" clip-path="url(#terminal-line-17)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" 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="414.8" clip-path="url(#terminal-line-18)">1 model · 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="61" clip-path="url(#terminal-line-19)">Type </text><text class="terminal-r3" x="61" y="483.6" textLength="61" clip-path="url(#terminal-line-19)">/help</text><text class="terminal-r1" x="122" 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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
|
@ -175,13 +175,13 @@
|
|||
</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="288.4" textLength="134.2" clip-path="url(#terminal-line-11)">  ⡠⣒⠄  ⡔⢄⠔⡄</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="0" y="312.8" textLength="134.2" 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-r1" x="0" y="337.2" textLength="134.2" clip-path="url(#terminal-line-13)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</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="0" y="386" textLength="134.2" clip-path="url(#terminal-line-15)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="386" textLength="146.4" clip-path="url(#terminal-line-15)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="386" textLength="122" clip-path="url(#terminal-line-15)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="386" textLength="244" clip-path="url(#terminal-line-15)">devstral-latest[off]</text><text class="terminal-r1" x="683.2" y="386" textLength="256.2" clip-path="url(#terminal-line-15)"> · [Subscription] Pro</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="622.2" clip-path="url(#terminal-line-16)">1 model · 1/3 connectors · 0 MCP servers · 0 skills</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="61" clip-path="url(#terminal-line-17)">Type </text><text class="terminal-r3" x="231.8" y="434.8" textLength="61" clip-path="url(#terminal-line-17)">/help</text><text class="terminal-r1" x="292.8" y="434.8" textLength="256.2" clip-path="url(#terminal-line-17)"> for more information</text><text class="terminal-r1" x="1464" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">
|
||||
</text><text class="terminal-r2" x="0" y="386" textLength="146.4" clip-path="url(#terminal-line-15)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="386" textLength="122" clip-path="url(#terminal-line-15)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="386" textLength="244" clip-path="url(#terminal-line-15)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" y="386" textLength="256.2" clip-path="url(#terminal-line-15)"> · [Subscription] Pro</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="622.2" clip-path="url(#terminal-line-16)">1 model · 1/3 connectors · 0 MCP servers · 0 skills</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="61" clip-path="url(#terminal-line-17)">Type </text><text class="terminal-r3" x="61" y="434.8" textLength="61" clip-path="url(#terminal-line-17)">/help</text><text class="terminal-r1" x="122" y="434.8" textLength="256.2" clip-path="url(#terminal-line-17)"> for more information</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-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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
|
@ -169,13 +169,13 @@
|
|||
</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="0" y="215.2" textLength="134.2" clip-path="url(#terminal-line-8)">  ⡠⣒⠄  ⡔⢄⠔⡄</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="0" y="239.6" textLength="134.2" clip-path="url(#terminal-line-9)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</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="0" y="264" textLength="134.2" clip-path="url(#terminal-line-10)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</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="0" y="312.8" textLength="134.2" clip-path="url(#terminal-line-12)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="312.8" textLength="146.4" clip-path="url(#terminal-line-12)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="312.8" textLength="122" clip-path="url(#terminal-line-12)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="312.8" textLength="244" clip-path="url(#terminal-line-12)">devstral-latest[off]</text><text class="terminal-r1" x="683.2" y="312.8" textLength="256.2" clip-path="url(#terminal-line-12)"> · [Subscription] Pro</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="0" y="337.2" textLength="134.2" clip-path="url(#terminal-line-13)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="337.2" textLength="622.2" clip-path="url(#terminal-line-13)">1 model · 1/3 connectors · 0 MCP servers · 0 skills</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-r1" x="170.8" y="361.6" textLength="61" clip-path="url(#terminal-line-14)">Type </text><text class="terminal-r3" x="231.8" y="361.6" textLength="61" clip-path="url(#terminal-line-14)">/help</text><text class="terminal-r1" x="292.8" y="361.6" textLength="256.2" clip-path="url(#terminal-line-14)"> for more information</text><text class="terminal-r1" x="1464" y="361.6" textLength="12.2" clip-path="url(#terminal-line-14)">
|
||||
</text><text class="terminal-r2" x="0" y="312.8" textLength="146.4" clip-path="url(#terminal-line-12)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="312.8" textLength="122" clip-path="url(#terminal-line-12)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="312.8" textLength="244" clip-path="url(#terminal-line-12)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" y="312.8" textLength="256.2" clip-path="url(#terminal-line-12)"> · [Subscription] Pro</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="0" y="337.2" textLength="622.2" clip-path="url(#terminal-line-13)">1 model · 1/3 connectors · 0 MCP servers · 0 skills</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="61" clip-path="url(#terminal-line-14)">Type </text><text class="terminal-r3" x="61" y="361.6" textLength="61" clip-path="url(#terminal-line-14)">/help</text><text class="terminal-r1" x="122" y="361.6" textLength="256.2" clip-path="url(#terminal-line-14)"> for more information</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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
|
@ -167,13 +167,13 @@
|
|||
</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="0" y="166.4" textLength="134.2" clip-path="url(#terminal-line-6)">  ⡠⣒⠄  ⡔⢄⠔⡄</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="0" y="190.8" textLength="134.2" clip-path="url(#terminal-line-7)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</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="0" y="215.2" textLength="134.2" clip-path="url(#terminal-line-8)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</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="0" y="264" textLength="134.2" clip-path="url(#terminal-line-10)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="264" textLength="146.4" clip-path="url(#terminal-line-10)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="264" textLength="122" clip-path="url(#terminal-line-10)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="264" textLength="244" clip-path="url(#terminal-line-10)">devstral-latest[off]</text><text class="terminal-r1" x="683.2" y="264" textLength="256.2" clip-path="url(#terminal-line-10)"> · [Subscription] Pro</text><text class="terminal-r1" x="1464" y="264" textLength="12.2" clip-path="url(#terminal-line-10)">
|
||||
</text><text class="terminal-r1" x="0" y="288.4" textLength="134.2" clip-path="url(#terminal-line-11)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="288.4" textLength="622.2" clip-path="url(#terminal-line-11)">1 model · 1/3 connectors · 0 MCP servers · 0 skills</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="0" y="312.8" textLength="134.2" clip-path="url(#terminal-line-12)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="312.8" textLength="61" clip-path="url(#terminal-line-12)">Type </text><text class="terminal-r3" x="231.8" y="312.8" textLength="61" clip-path="url(#terminal-line-12)">/help</text><text class="terminal-r1" x="292.8" y="312.8" textLength="256.2" clip-path="url(#terminal-line-12)"> for more information</text><text class="terminal-r1" x="1464" y="312.8" textLength="12.2" clip-path="url(#terminal-line-12)">
|
||||
</text><text class="terminal-r2" x="0" y="264" textLength="146.4" clip-path="url(#terminal-line-10)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="264" textLength="122" clip-path="url(#terminal-line-10)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="264" textLength="244" clip-path="url(#terminal-line-10)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" y="264" textLength="256.2" clip-path="url(#terminal-line-10)"> · [Subscription] Pro</text><text class="terminal-r1" x="1464" y="264" textLength="12.2" clip-path="url(#terminal-line-10)">
|
||||
</text><text class="terminal-r1" x="0" y="288.4" textLength="622.2" clip-path="url(#terminal-line-11)">1 model · 1/3 connectors · 0 MCP servers · 0 skills</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="0" y="312.8" textLength="61" clip-path="url(#terminal-line-12)">Type </text><text class="terminal-r3" x="61" y="312.8" textLength="61" clip-path="url(#terminal-line-12)">/help</text><text class="terminal-r1" x="122" y="312.8" textLength="256.2" clip-path="url(#terminal-line-12)"> for more information</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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
|
@ -176,13 +176,13 @@
|
|||
</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="0" y="337.2" textLength="134.2" clip-path="url(#terminal-line-13)">  ⡠⣒⠄  ⡔⢄⠔⡄</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-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="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="244" clip-path="url(#terminal-line-17)">devstral-latest[off]</text><text class="terminal-r1" x="683.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-r2" x="0" y="434.8" textLength="146.4" clip-path="url(#terminal-line-17)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="434.8" textLength="122" clip-path="url(#terminal-line-17)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="434.8" textLength="244" clip-path="url(#terminal-line-17)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" 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="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="61" clip-path="url(#terminal-line-19)">Type </text><text class="terminal-r3" x="61" y="483.6" textLength="61" clip-path="url(#terminal-line-19)">/help</text><text class="terminal-r1" x="122" 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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
|
@ -175,13 +175,13 @@
|
|||
</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="0" y="312.8" textLength="134.2" 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-r1" x="0" y="337.2" textLength="134.2" clip-path="url(#terminal-line-13)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</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-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="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="244" clip-path="url(#terminal-line-16)">devstral-latest[off]</text><text class="terminal-r1" x="683.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 · 3 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-r2" x="0" y="410.4" textLength="146.4" clip-path="url(#terminal-line-16)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="410.4" textLength="122" clip-path="url(#terminal-line-16)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="410.4" textLength="244" clip-path="url(#terminal-line-16)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" 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="414.8" clip-path="url(#terminal-line-17)">1 model · 3 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="61" clip-path="url(#terminal-line-18)">Type </text><text class="terminal-r3" x="61" y="459.2" textLength="61" clip-path="url(#terminal-line-18)">/help</text><text class="terminal-r1" x="122" 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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
|
@ -174,13 +174,13 @@
|
|||
</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="0" y="264" textLength="134.2" clip-path="url(#terminal-line-10)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r1" x="1464" y="264" textLength="12.2" clip-path="url(#terminal-line-10)">
|
||||
</text><text class="terminal-r1" x="0" y="288.4" textLength="134.2" clip-path="url(#terminal-line-11)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</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="0" y="312.8" textLength="134.2" 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-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="244" clip-path="url(#terminal-line-14)">devstral-latest[off]</text><text class="terminal-r1" x="683.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-r2" x="0" y="361.6" textLength="146.4" clip-path="url(#terminal-line-14)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="361.6" textLength="122" clip-path="url(#terminal-line-14)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="361.6" textLength="244" clip-path="url(#terminal-line-14)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" 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="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="61" clip-path="url(#terminal-line-16)">Type </text><text class="terminal-r3" x="61" y="410.4" textLength="61" clip-path="url(#terminal-line-16)">/help</text><text class="terminal-r1" x="122" 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-r1" x="1464" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
|
@ -178,13 +178,13 @@
|
|||
</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="0" y="337.2" textLength="134.2" clip-path="url(#terminal-line-13)">  ⡠⣒⠄  ⡔⢄⠔⡄</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-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="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="244" clip-path="url(#terminal-line-17)">devstral-latest[off]</text><text class="terminal-r1" x="683.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-r2" x="0" y="434.8" textLength="146.4" clip-path="url(#terminal-line-17)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="434.8" textLength="122" clip-path="url(#terminal-line-17)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="434.8" textLength="244" clip-path="url(#terminal-line-17)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" 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="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="61" clip-path="url(#terminal-line-19)">Type </text><text class="terminal-r3" x="61" y="483.6" textLength="61" clip-path="url(#terminal-line-19)">/help</text><text class="terminal-r1" x="122" 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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
|
@ -176,13 +176,13 @@
|
|||
</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="0" y="312.8" textLength="134.2" 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-r1" x="0" y="337.2" textLength="134.2" clip-path="url(#terminal-line-13)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</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-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="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="244" clip-path="url(#terminal-line-16)">devstral-latest[off]</text><text class="terminal-r1" x="683.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="622.2" clip-path="url(#terminal-line-17)">1 model · 1/3 connectors · 0 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-r2" x="0" y="410.4" textLength="146.4" clip-path="url(#terminal-line-16)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="410.4" textLength="122" clip-path="url(#terminal-line-16)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="410.4" textLength="244" clip-path="url(#terminal-line-16)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" 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="622.2" clip-path="url(#terminal-line-17)">1 model · 1/3 connectors · 0 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="61" clip-path="url(#terminal-line-18)">Type </text><text class="terminal-r3" x="61" y="459.2" textLength="61" clip-path="url(#terminal-line-18)">/help</text><text class="terminal-r1" x="122" 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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
|
@ -176,13 +176,13 @@
|
|||
</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="361.6" textLength="134.2" clip-path="url(#terminal-line-14)">  ⡠⣒⠄  ⡔⢄⠔⡄</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="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="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="244" clip-path="url(#terminal-line-18)">devstral-latest[off]</text><text class="terminal-r1" x="683.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-r2" x="0" y="459.2" textLength="146.4" clip-path="url(#terminal-line-18)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="459.2" textLength="122" clip-path="url(#terminal-line-18)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="459.2" textLength="244" clip-path="url(#terminal-line-18)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" 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="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="61" clip-path="url(#terminal-line-20)">Type </text><text class="terminal-r3" x="61" y="508" textLength="61" clip-path="url(#terminal-line-20)">/help</text><text class="terminal-r1" x="122" 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-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
|
@ -176,13 +176,13 @@
|
|||
</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="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-r1" x="0" y="410.4" textLength="134.2" clip-path="url(#terminal-line-16)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</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="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-r1" x="0" y="483.6" textLength="134.2" clip-path="url(#terminal-line-19)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="483.6" textLength="146.4" clip-path="url(#terminal-line-19)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="483.6" textLength="122" clip-path="url(#terminal-line-19)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="483.6" textLength="244" clip-path="url(#terminal-line-19)">devstral-latest[off]</text><text class="terminal-r1" x="683.2" y="483.6" textLength="256.2" clip-path="url(#terminal-line-19)"> · [Subscription] Pro</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="414.8" clip-path="url(#terminal-line-20)">1 model · 2 MCP servers · 0 skills</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="532.4" textLength="134.2" clip-path="url(#terminal-line-21)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="532.4" textLength="61" clip-path="url(#terminal-line-21)">Type </text><text class="terminal-r3" x="231.8" y="532.4" textLength="61" clip-path="url(#terminal-line-21)">/help</text><text class="terminal-r1" x="292.8" y="532.4" textLength="256.2" clip-path="url(#terminal-line-21)"> for more information</text><text class="terminal-r1" x="1464" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">
|
||||
</text><text class="terminal-r2" x="0" y="483.6" textLength="146.4" clip-path="url(#terminal-line-19)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="483.6" textLength="122" clip-path="url(#terminal-line-19)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="483.6" textLength="244" clip-path="url(#terminal-line-19)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" y="483.6" textLength="256.2" clip-path="url(#terminal-line-19)"> · [Subscription] Pro</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="414.8" clip-path="url(#terminal-line-20)">1 model · 2 MCP servers · 0 skills</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="532.4" textLength="61" clip-path="url(#terminal-line-21)">Type </text><text class="terminal-r3" x="61" y="532.4" textLength="61" clip-path="url(#terminal-line-21)">/help</text><text class="terminal-r1" x="122" y="532.4" textLength="256.2" clip-path="url(#terminal-line-21)"> for more information</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-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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
|
@ -174,13 +174,13 @@
|
|||
</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="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-r1" x="0" y="410.4" textLength="134.2" clip-path="url(#terminal-line-16)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</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="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-r1" x="0" y="483.6" textLength="134.2" clip-path="url(#terminal-line-19)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="483.6" textLength="146.4" clip-path="url(#terminal-line-19)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="483.6" textLength="122" clip-path="url(#terminal-line-19)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="483.6" textLength="244" clip-path="url(#terminal-line-19)">devstral-latest[off]</text><text class="terminal-r1" x="683.2" y="483.6" textLength="256.2" clip-path="url(#terminal-line-19)"> · [Subscription] Pro</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="414.8" clip-path="url(#terminal-line-20)">1 model · 2 MCP servers · 0 skills</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="532.4" textLength="134.2" clip-path="url(#terminal-line-21)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="532.4" textLength="61" clip-path="url(#terminal-line-21)">Type </text><text class="terminal-r3" x="231.8" y="532.4" textLength="61" clip-path="url(#terminal-line-21)">/help</text><text class="terminal-r1" x="292.8" y="532.4" textLength="256.2" clip-path="url(#terminal-line-21)"> for more information</text><text class="terminal-r1" x="1464" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">
|
||||
</text><text class="terminal-r2" x="0" y="483.6" textLength="146.4" clip-path="url(#terminal-line-19)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="483.6" textLength="122" clip-path="url(#terminal-line-19)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="483.6" textLength="244" clip-path="url(#terminal-line-19)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" y="483.6" textLength="256.2" clip-path="url(#terminal-line-19)"> · [Subscription] Pro</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="414.8" clip-path="url(#terminal-line-20)">1 model · 2 MCP servers · 0 skills</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="532.4" textLength="61" clip-path="url(#terminal-line-21)">Type </text><text class="terminal-r3" x="61" y="532.4" textLength="61" clip-path="url(#terminal-line-21)">/help</text><text class="terminal-r1" x="122" y="532.4" textLength="256.2" clip-path="url(#terminal-line-21)"> for more information</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-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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
|
@ -176,13 +176,13 @@
|
|||
</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="0" y="312.8" textLength="134.2" 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-r1" x="0" y="337.2" textLength="134.2" clip-path="url(#terminal-line-13)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</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-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="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="244" clip-path="url(#terminal-line-16)">devstral-latest[off]</text><text class="terminal-r1" x="683.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="622.2" clip-path="url(#terminal-line-17)">1 model · 1/3 connectors · 0 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-r2" x="0" y="410.4" textLength="146.4" clip-path="url(#terminal-line-16)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="410.4" textLength="122" clip-path="url(#terminal-line-16)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="410.4" textLength="244" clip-path="url(#terminal-line-16)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" 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="622.2" clip-path="url(#terminal-line-17)">1 model · 1/3 connectors · 0 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="61" clip-path="url(#terminal-line-18)">Type </text><text class="terminal-r3" x="61" y="459.2" textLength="61" clip-path="url(#terminal-line-18)">/help</text><text class="terminal-r1" x="122" 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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
|
@ -175,13 +175,13 @@
|
|||
</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="1464" y="459.2" textLength="12.2" clip-path="url(#terminal-line-18)">
|
||||
</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="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="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="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="0" y="508" textLength="134.2" clip-path="url(#terminal-line-20)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="508" textLength="146.4" clip-path="url(#terminal-line-20)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="508" textLength="122" clip-path="url(#terminal-line-20)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="508" textLength="244" clip-path="url(#terminal-line-20)">devstral-latest[off]</text><text class="terminal-r1" x="683.2" y="508" textLength="256.2" clip-path="url(#terminal-line-20)"> · [Subscription] Pro</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="532.4" textLength="134.2" clip-path="url(#terminal-line-21)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="532.4" textLength="414.8" clip-path="url(#terminal-line-21)">1 model · 0 MCP servers · 0 skills</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="0" y="556.8" textLength="134.2" clip-path="url(#terminal-line-22)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="556.8" textLength="61" clip-path="url(#terminal-line-22)">Type </text><text class="terminal-r3" x="231.8" y="556.8" textLength="61" clip-path="url(#terminal-line-22)">/help</text><text class="terminal-r1" x="292.8" y="556.8" textLength="256.2" clip-path="url(#terminal-line-22)"> for more information</text><text class="terminal-r1" x="1464" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">
|
||||
</text><text class="terminal-r2" x="0" y="508" textLength="146.4" clip-path="url(#terminal-line-20)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="508" textLength="122" clip-path="url(#terminal-line-20)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="508" textLength="244" clip-path="url(#terminal-line-20)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" y="508" textLength="256.2" clip-path="url(#terminal-line-20)"> · [Subscription] Pro</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="532.4" textLength="414.8" clip-path="url(#terminal-line-21)">1 model · 0 MCP servers · 0 skills</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="0" y="556.8" textLength="61" clip-path="url(#terminal-line-22)">Type </text><text class="terminal-r3" x="61" y="556.8" textLength="61" clip-path="url(#terminal-line-22)">/help</text><text class="terminal-r1" x="122" y="556.8" textLength="256.2" clip-path="url(#terminal-line-22)"> for more information</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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
|
@ -176,13 +176,13 @@
|
|||
</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="0" y="337.2" textLength="134.2" clip-path="url(#terminal-line-13)">  ⡠⣒⠄  ⡔⢄⠔⡄</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-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="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="244" clip-path="url(#terminal-line-17)">devstral-latest[off]</text><text class="terminal-r1" x="683.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-r2" x="0" y="434.8" textLength="146.4" clip-path="url(#terminal-line-17)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="434.8" textLength="122" clip-path="url(#terminal-line-17)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="434.8" textLength="244" clip-path="url(#terminal-line-17)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" 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="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="61" clip-path="url(#terminal-line-19)">Type </text><text class="terminal-r3" x="61" y="483.6" textLength="61" clip-path="url(#terminal-line-19)">/help</text><text class="terminal-r1" x="122" 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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
|
@ -176,13 +176,13 @@
|
|||
</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="0" y="337.2" textLength="134.2" clip-path="url(#terminal-line-13)">  ⡠⣒⠄  ⡔⢄⠔⡄</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-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="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="244" clip-path="url(#terminal-line-17)">devstral-latest[off]</text><text class="terminal-r1" x="683.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-r2" x="0" y="434.8" textLength="146.4" clip-path="url(#terminal-line-17)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="434.8" textLength="122" clip-path="url(#terminal-line-17)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="434.8" textLength="244" clip-path="url(#terminal-line-17)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" 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="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="61" clip-path="url(#terminal-line-19)">Type </text><text class="terminal-r3" x="61" y="483.6" textLength="61" clip-path="url(#terminal-line-19)">/help</text><text class="terminal-r1" x="122" 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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
|
@ -176,13 +176,13 @@
|
|||
</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="0" y="337.2" textLength="134.2" clip-path="url(#terminal-line-13)">  ⡠⣒⠄  ⡔⢄⠔⡄</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-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="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="244" clip-path="url(#terminal-line-17)">devstral-latest[off]</text><text class="terminal-r1" x="683.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-r2" x="0" y="434.8" textLength="146.4" clip-path="url(#terminal-line-17)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="434.8" textLength="122" clip-path="url(#terminal-line-17)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="434.8" textLength="244" clip-path="url(#terminal-line-17)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" 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="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="61" clip-path="url(#terminal-line-19)">Type </text><text class="terminal-r3" x="61" y="483.6" textLength="61" clip-path="url(#terminal-line-19)">/help</text><text class="terminal-r1" x="122" 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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
|
@ -176,13 +176,13 @@
|
|||
</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="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-r1" x="0" y="410.4" textLength="134.2" clip-path="url(#terminal-line-16)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</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="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-r1" x="0" y="483.6" textLength="134.2" clip-path="url(#terminal-line-19)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="483.6" textLength="146.4" clip-path="url(#terminal-line-19)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="483.6" textLength="122" clip-path="url(#terminal-line-19)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="483.6" textLength="244" clip-path="url(#terminal-line-19)">devstral-latest[off]</text><text class="terminal-r1" x="683.2" y="483.6" textLength="256.2" clip-path="url(#terminal-line-19)"> · [Subscription] Pro</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="414.8" clip-path="url(#terminal-line-20)">1 model · 2 MCP servers · 0 skills</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="532.4" textLength="134.2" clip-path="url(#terminal-line-21)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="532.4" textLength="61" clip-path="url(#terminal-line-21)">Type </text><text class="terminal-r3" x="231.8" y="532.4" textLength="61" clip-path="url(#terminal-line-21)">/help</text><text class="terminal-r1" x="292.8" y="532.4" textLength="256.2" clip-path="url(#terminal-line-21)"> for more information</text><text class="terminal-r1" x="1464" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">
|
||||
</text><text class="terminal-r2" x="0" y="483.6" textLength="146.4" clip-path="url(#terminal-line-19)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="483.6" textLength="122" clip-path="url(#terminal-line-19)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="483.6" textLength="244" clip-path="url(#terminal-line-19)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" y="483.6" textLength="256.2" clip-path="url(#terminal-line-19)"> · [Subscription] Pro</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="414.8" clip-path="url(#terminal-line-20)">1 model · 2 MCP servers · 0 skills</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="532.4" textLength="61" clip-path="url(#terminal-line-21)">Type </text><text class="terminal-r3" x="61" y="532.4" textLength="61" clip-path="url(#terminal-line-21)">/help</text><text class="terminal-r1" x="122" y="532.4" textLength="256.2" clip-path="url(#terminal-line-21)"> for more information</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-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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
|
@ -174,13 +174,13 @@
|
|||
</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="0" y="264" textLength="134.2" clip-path="url(#terminal-line-10)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r1" x="1464" y="264" textLength="12.2" clip-path="url(#terminal-line-10)">
|
||||
</text><text class="terminal-r1" x="0" y="288.4" textLength="134.2" clip-path="url(#terminal-line-11)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</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="0" y="312.8" textLength="134.2" 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-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="244" clip-path="url(#terminal-line-14)">devstral-latest[off]</text><text class="terminal-r1" x="683.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-r2" x="0" y="361.6" textLength="146.4" clip-path="url(#terminal-line-14)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="361.6" textLength="122" clip-path="url(#terminal-line-14)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="361.6" textLength="244" clip-path="url(#terminal-line-14)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" 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="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="61" clip-path="url(#terminal-line-16)">Type </text><text class="terminal-r3" x="61" y="410.4" textLength="61" clip-path="url(#terminal-line-16)">/help</text><text class="terminal-r1" x="122" 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-r1" x="1464" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
|
@ -179,13 +179,13 @@
|
|||
</text><text class="terminal-r1" x="1220" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">
|
||||
</text><text class="terminal-r1" x="1220" y="459.2" textLength="12.2" clip-path="url(#terminal-line-18)">
|
||||
</text><text class="terminal-r1" x="1220" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">
|
||||
</text><text class="terminal-r1" x="1220" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r1" x="1220" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">
|
||||
</text><text class="terminal-r1" x="1220" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">
|
||||
</text><text class="terminal-r1" x="0" y="508" textLength="134.2" clip-path="url(#terminal-line-20)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r1" x="1220" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r1" x="0" y="532.4" textLength="134.2" clip-path="url(#terminal-line-21)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="1220" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">
|
||||
</text><text class="terminal-r1" x="0" y="556.8" textLength="134.2" clip-path="url(#terminal-line-22)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="1220" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">
|
||||
</text><text class="terminal-r1" x="1220" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r1" x="0" y="605.6" textLength="134.2" clip-path="url(#terminal-line-24)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="605.6" textLength="146.4" clip-path="url(#terminal-line-24)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="605.6" textLength="122" clip-path="url(#terminal-line-24)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="605.6" textLength="158.6" clip-path="url(#terminal-line-24)">devstral[off]</text><text class="terminal-r1" x="597.8" y="605.6" textLength="256.2" clip-path="url(#terminal-line-24)"> · [Subscription] Pro</text><text class="terminal-r1" x="1220" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">
|
||||
</text><text class="terminal-r1" x="0" y="630" textLength="134.2" clip-path="url(#terminal-line-25)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="630" textLength="427" clip-path="url(#terminal-line-25)">5 models · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1220" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r1" x="0" y="654.4" textLength="134.2" clip-path="url(#terminal-line-26)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">Type </text><text class="terminal-r3" x="231.8" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">/help</text><text class="terminal-r1" x="292.8" y="654.4" textLength="256.2" clip-path="url(#terminal-line-26)"> for more information</text><text class="terminal-r1" x="1220" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</text><text class="terminal-r2" x="0" y="605.6" textLength="146.4" clip-path="url(#terminal-line-24)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="605.6" textLength="122" clip-path="url(#terminal-line-24)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="605.6" textLength="158.6" clip-path="url(#terminal-line-24)">devstral[off]</text><text class="terminal-r1" x="427" y="605.6" textLength="256.2" clip-path="url(#terminal-line-24)"> · [Subscription] Pro</text><text class="terminal-r1" x="1220" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">
|
||||
</text><text class="terminal-r1" x="0" y="630" textLength="427" clip-path="url(#terminal-line-25)">5 models · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1220" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r1" x="0" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">Type </text><text class="terminal-r3" x="61" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">/help</text><text class="terminal-r1" x="122" y="654.4" textLength="256.2" clip-path="url(#terminal-line-26)"> for more information</text><text class="terminal-r1" x="1220" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</text><text class="terminal-r1" x="1220" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">
|
||||
</text><text class="terminal-r1" x="1220" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">
|
||||
</text><text class="terminal-r1" x="1220" y="727.6" textLength="12.2" clip-path="url(#terminal-line-29)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
|
@ -177,13 +177,13 @@
|
|||
</text><text class="terminal-r1" x="1220" y="312.8" textLength="12.2" clip-path="url(#terminal-line-12)">
|
||||
</text><text class="terminal-r1" x="1220" y="337.2" textLength="12.2" clip-path="url(#terminal-line-13)">
|
||||
</text><text class="terminal-r1" x="1220" y="361.6" textLength="12.2" clip-path="url(#terminal-line-14)">
|
||||
</text><text class="terminal-r1" x="1220" y="386" textLength="12.2" clip-path="url(#terminal-line-15)">
|
||||
</text><text class="terminal-r1" x="1220" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">
|
||||
</text><text class="terminal-r1" x="1220" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">
|
||||
</text><text class="terminal-r1" x="0" y="386" textLength="134.2" clip-path="url(#terminal-line-15)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r1" x="1220" 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="1220" 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="1220" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">
|
||||
</text><text class="terminal-r1" x="1220" 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-r2" x="170.8" y="483.6" textLength="146.4" clip-path="url(#terminal-line-19)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="483.6" textLength="122" clip-path="url(#terminal-line-19)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="483.6" textLength="158.6" clip-path="url(#terminal-line-19)">devstral[off]</text><text class="terminal-r1" x="597.8" y="483.6" textLength="256.2" clip-path="url(#terminal-line-19)"> · [Subscription] Pro</text><text class="terminal-r1" x="1220" 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="427" clip-path="url(#terminal-line-20)">5 models · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1220" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r1" x="0" y="532.4" textLength="134.2" clip-path="url(#terminal-line-21)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="532.4" textLength="61" clip-path="url(#terminal-line-21)">Type </text><text class="terminal-r3" x="231.8" y="532.4" textLength="61" clip-path="url(#terminal-line-21)">/help</text><text class="terminal-r1" x="292.8" y="532.4" textLength="256.2" clip-path="url(#terminal-line-21)"> for more information</text><text class="terminal-r1" x="1220" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">
|
||||
</text><text class="terminal-r2" x="0" y="483.6" textLength="146.4" clip-path="url(#terminal-line-19)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="483.6" textLength="122" clip-path="url(#terminal-line-19)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="483.6" textLength="158.6" clip-path="url(#terminal-line-19)">devstral[off]</text><text class="terminal-r1" x="427" y="483.6" textLength="256.2" clip-path="url(#terminal-line-19)"> · [Subscription] Pro</text><text class="terminal-r1" x="1220" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">
|
||||
</text><text class="terminal-r1" x="0" y="508" textLength="427" clip-path="url(#terminal-line-20)">5 models · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1220" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r1" x="0" y="532.4" textLength="61" clip-path="url(#terminal-line-21)">Type </text><text class="terminal-r3" x="61" y="532.4" textLength="61" clip-path="url(#terminal-line-21)">/help</text><text class="terminal-r1" x="122" y="532.4" textLength="256.2" clip-path="url(#terminal-line-21)"> for more information</text><text class="terminal-r1" x="1220" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">
|
||||
</text><text class="terminal-r1" x="1220" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">
|
||||
</text><text class="terminal-r1" x="1220" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r1" x="1220" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
|
@ -178,13 +178,13 @@
|
|||
</text><text class="terminal-r1" x="1220" y="312.8" textLength="12.2" clip-path="url(#terminal-line-12)">
|
||||
</text><text class="terminal-r1" x="1220" y="337.2" textLength="12.2" clip-path="url(#terminal-line-13)">
|
||||
</text><text class="terminal-r1" x="1220" y="361.6" textLength="12.2" clip-path="url(#terminal-line-14)">
|
||||
</text><text class="terminal-r1" x="1220" y="386" textLength="12.2" clip-path="url(#terminal-line-15)">
|
||||
</text><text class="terminal-r1" x="1220" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">
|
||||
</text><text class="terminal-r1" x="1220" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">
|
||||
</text><text class="terminal-r1" x="0" y="386" textLength="134.2" clip-path="url(#terminal-line-15)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r1" x="1220" 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="1220" 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="1220" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">
|
||||
</text><text class="terminal-r1" x="1220" 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-r2" x="170.8" y="483.6" textLength="146.4" clip-path="url(#terminal-line-19)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="483.6" textLength="122" clip-path="url(#terminal-line-19)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="483.6" textLength="158.6" clip-path="url(#terminal-line-19)">devstral[off]</text><text class="terminal-r1" x="597.8" y="483.6" textLength="256.2" clip-path="url(#terminal-line-19)"> · [Subscription] Pro</text><text class="terminal-r1" x="1220" 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="427" clip-path="url(#terminal-line-20)">5 models · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1220" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r1" x="0" y="532.4" textLength="134.2" clip-path="url(#terminal-line-21)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="532.4" textLength="61" clip-path="url(#terminal-line-21)">Type </text><text class="terminal-r3" x="231.8" y="532.4" textLength="61" clip-path="url(#terminal-line-21)">/help</text><text class="terminal-r1" x="292.8" y="532.4" textLength="256.2" clip-path="url(#terminal-line-21)"> for more information</text><text class="terminal-r1" x="1220" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">
|
||||
</text><text class="terminal-r2" x="0" y="483.6" textLength="146.4" clip-path="url(#terminal-line-19)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="483.6" textLength="122" clip-path="url(#terminal-line-19)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="483.6" textLength="158.6" clip-path="url(#terminal-line-19)">devstral[off]</text><text class="terminal-r1" x="427" y="483.6" textLength="256.2" clip-path="url(#terminal-line-19)"> · [Subscription] Pro</text><text class="terminal-r1" x="1220" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">
|
||||
</text><text class="terminal-r1" x="0" y="508" textLength="427" clip-path="url(#terminal-line-20)">5 models · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1220" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r1" x="0" y="532.4" textLength="61" clip-path="url(#terminal-line-21)">Type </text><text class="terminal-r3" x="61" y="532.4" textLength="61" clip-path="url(#terminal-line-21)">/help</text><text class="terminal-r1" x="122" y="532.4" textLength="256.2" clip-path="url(#terminal-line-21)"> for more information</text><text class="terminal-r1" x="1220" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">
|
||||
</text><text class="terminal-r1" x="1220" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">
|
||||
</text><text class="terminal-r1" x="1220" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r1" x="1220" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
|
@ -178,13 +178,13 @@
|
|||
</text><text class="terminal-r1" x="1220" y="410.4" textLength="12.2" clip-path="url(#terminal-line-16)">
|
||||
</text><text class="terminal-r1" x="1220" y="434.8" textLength="12.2" clip-path="url(#terminal-line-17)">
|
||||
</text><text class="terminal-r1" x="1220" y="459.2" textLength="12.2" clip-path="url(#terminal-line-18)">
|
||||
</text><text class="terminal-r1" x="1220" y="483.6" textLength="12.2" clip-path="url(#terminal-line-19)">
|
||||
</text><text class="terminal-r1" x="1220" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r1" x="1220" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">
|
||||
</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="1220" 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="1220" y="508" textLength="12.2" clip-path="url(#terminal-line-20)">
|
||||
</text><text class="terminal-r1" x="0" y="532.4" textLength="134.2" clip-path="url(#terminal-line-21)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="1220" y="532.4" textLength="12.2" clip-path="url(#terminal-line-21)">
|
||||
</text><text class="terminal-r1" x="1220" y="556.8" textLength="12.2" clip-path="url(#terminal-line-22)">
|
||||
</text><text class="terminal-r1" x="0" y="581.2" textLength="134.2" clip-path="url(#terminal-line-23)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="581.2" textLength="146.4" clip-path="url(#terminal-line-23)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="581.2" textLength="122" clip-path="url(#terminal-line-23)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="581.2" textLength="244" clip-path="url(#terminal-line-23)">devstral-latest[off]</text><text class="terminal-r1" x="683.2" y="581.2" textLength="256.2" clip-path="url(#terminal-line-23)"> · [Subscription] Pro</text><text class="terminal-r1" x="1220" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r1" x="0" y="605.6" textLength="134.2" clip-path="url(#terminal-line-24)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="605.6" textLength="414.8" clip-path="url(#terminal-line-24)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1220" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">
|
||||
</text><text class="terminal-r1" x="0" y="630" textLength="134.2" clip-path="url(#terminal-line-25)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="630" textLength="61" clip-path="url(#terminal-line-25)">Type </text><text class="terminal-r3" x="231.8" y="630" textLength="61" clip-path="url(#terminal-line-25)">/help</text><text class="terminal-r1" x="292.8" y="630" textLength="256.2" clip-path="url(#terminal-line-25)"> for more information</text><text class="terminal-r1" x="1220" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r2" x="0" y="581.2" textLength="146.4" clip-path="url(#terminal-line-23)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="581.2" textLength="122" clip-path="url(#terminal-line-23)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="581.2" textLength="244" clip-path="url(#terminal-line-23)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" y="581.2" textLength="256.2" clip-path="url(#terminal-line-23)"> · [Subscription] Pro</text><text class="terminal-r1" x="1220" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r1" x="0" y="605.6" textLength="414.8" clip-path="url(#terminal-line-24)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1220" y="605.6" textLength="12.2" clip-path="url(#terminal-line-24)">
|
||||
</text><text class="terminal-r1" x="0" y="630" textLength="61" clip-path="url(#terminal-line-25)">Type </text><text class="terminal-r3" x="61" y="630" textLength="61" clip-path="url(#terminal-line-25)">/help</text><text class="terminal-r1" x="122" y="630" textLength="256.2" clip-path="url(#terminal-line-25)"> for more information</text><text class="terminal-r1" x="1220" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r1" x="1220" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</text><text class="terminal-r1" x="24.4" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">⎣</text><text class="terminal-r1" x="48.8" y="678.8" textLength="780.8" clip-path="url(#terminal-line-27)">Configuration reloaded (includes agent instructions and skills).</text><text class="terminal-r1" x="1220" y="678.8" textLength="12.2" clip-path="url(#terminal-line-27)">
|
||||
</text><text class="terminal-r1" x="1220" y="703.2" textLength="12.2" clip-path="url(#terminal-line-28)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
|
@ -180,13 +180,13 @@
|
|||
</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-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-r1" 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-r1" x="0" y="532.4" textLength="134.2" clip-path="url(#terminal-line-21)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</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="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-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r1" x="0" y="605.6" textLength="134.2" clip-path="url(#terminal-line-24)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="605.6" textLength="146.4" clip-path="url(#terminal-line-24)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="605.6" textLength="122" clip-path="url(#terminal-line-24)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="605.6" textLength="244" clip-path="url(#terminal-line-24)">devstral-latest[off]</text><text class="terminal-r1" x="683.2" y="605.6" textLength="256.2" clip-path="url(#terminal-line-24)"> · [Subscription] Pro</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="0" y="630" textLength="134.2" clip-path="url(#terminal-line-25)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="630" textLength="414.8" clip-path="url(#terminal-line-25)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r1" x="0" y="654.4" textLength="134.2" clip-path="url(#terminal-line-26)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">Type </text><text class="terminal-r3" x="231.8" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">/help</text><text class="terminal-r1" x="292.8" y="654.4" textLength="256.2" clip-path="url(#terminal-line-26)"> for more information</text><text class="terminal-r1" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</text><text class="terminal-r2" x="0" y="605.6" textLength="146.4" clip-path="url(#terminal-line-24)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="605.6" textLength="122" clip-path="url(#terminal-line-24)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="605.6" textLength="244" clip-path="url(#terminal-line-24)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" y="605.6" textLength="256.2" clip-path="url(#terminal-line-24)"> · [Subscription] Pro</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="0" y="630" textLength="414.8" clip-path="url(#terminal-line-25)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r1" x="0" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">Type </text><text class="terminal-r3" x="61" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">/help</text><text class="terminal-r1" x="122" y="654.4" textLength="256.2" clip-path="url(#terminal-line-26)"> for more information</text><text class="terminal-r1" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
|
@ -180,13 +180,13 @@
|
|||
</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-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-r1" 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-r1" x="0" y="532.4" textLength="134.2" clip-path="url(#terminal-line-21)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</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="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-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r1" x="0" y="605.6" textLength="134.2" clip-path="url(#terminal-line-24)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="605.6" textLength="146.4" clip-path="url(#terminal-line-24)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="605.6" textLength="122" clip-path="url(#terminal-line-24)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="605.6" textLength="244" clip-path="url(#terminal-line-24)">devstral-latest[off]</text><text class="terminal-r1" x="683.2" y="605.6" textLength="256.2" clip-path="url(#terminal-line-24)"> · [Subscription] Pro</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="0" y="630" textLength="134.2" clip-path="url(#terminal-line-25)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="630" textLength="414.8" clip-path="url(#terminal-line-25)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r1" x="0" y="654.4" textLength="134.2" clip-path="url(#terminal-line-26)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">Type </text><text class="terminal-r3" x="231.8" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">/help</text><text class="terminal-r1" x="292.8" y="654.4" textLength="256.2" clip-path="url(#terminal-line-26)"> for more information</text><text class="terminal-r1" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</text><text class="terminal-r2" x="0" y="605.6" textLength="146.4" clip-path="url(#terminal-line-24)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="605.6" textLength="122" clip-path="url(#terminal-line-24)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="605.6" textLength="244" clip-path="url(#terminal-line-24)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" y="605.6" textLength="256.2" clip-path="url(#terminal-line-24)"> · [Subscription] Pro</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="0" y="630" textLength="414.8" clip-path="url(#terminal-line-25)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r1" x="0" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">Type </text><text class="terminal-r3" x="61" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">/help</text><text class="terminal-r1" x="122" y="654.4" textLength="256.2" clip-path="url(#terminal-line-26)"> for more information</text><text class="terminal-r1" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
|
@ -180,13 +180,13 @@
|
|||
</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-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-r1" 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-r1" x="0" y="532.4" textLength="134.2" clip-path="url(#terminal-line-21)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</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="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-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r1" x="0" y="605.6" textLength="134.2" clip-path="url(#terminal-line-24)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="605.6" textLength="146.4" clip-path="url(#terminal-line-24)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="605.6" textLength="122" clip-path="url(#terminal-line-24)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="605.6" textLength="244" clip-path="url(#terminal-line-24)">devstral-latest[off]</text><text class="terminal-r1" x="683.2" y="605.6" textLength="256.2" clip-path="url(#terminal-line-24)"> · [Subscription] Pro</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="0" y="630" textLength="134.2" clip-path="url(#terminal-line-25)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="630" textLength="414.8" clip-path="url(#terminal-line-25)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r1" x="0" y="654.4" textLength="134.2" clip-path="url(#terminal-line-26)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">Type </text><text class="terminal-r3" x="231.8" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">/help</text><text class="terminal-r1" x="292.8" y="654.4" textLength="256.2" clip-path="url(#terminal-line-26)"> for more information</text><text class="terminal-r1" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</text><text class="terminal-r2" x="0" y="605.6" textLength="146.4" clip-path="url(#terminal-line-24)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="605.6" textLength="122" clip-path="url(#terminal-line-24)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="605.6" textLength="244" clip-path="url(#terminal-line-24)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" y="605.6" textLength="256.2" clip-path="url(#terminal-line-24)"> · [Subscription] Pro</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="0" y="630" textLength="414.8" clip-path="url(#terminal-line-25)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r1" x="0" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">Type </text><text class="terminal-r3" x="61" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">/help</text><text class="terminal-r1" x="122" y="654.4" textLength="256.2" clip-path="url(#terminal-line-26)"> for more information</text><text class="terminal-r1" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
|
@ -179,13 +179,13 @@
|
|||
</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-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-r1" 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-r1" x="0" y="532.4" textLength="134.2" clip-path="url(#terminal-line-21)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</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="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-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r1" x="0" y="605.6" textLength="134.2" clip-path="url(#terminal-line-24)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="605.6" textLength="146.4" clip-path="url(#terminal-line-24)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="605.6" textLength="122" clip-path="url(#terminal-line-24)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="605.6" textLength="244" clip-path="url(#terminal-line-24)">devstral-latest[off]</text><text class="terminal-r1" x="683.2" y="605.6" textLength="256.2" clip-path="url(#terminal-line-24)"> · [Subscription] Pro</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="0" y="630" textLength="134.2" clip-path="url(#terminal-line-25)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="630" textLength="414.8" clip-path="url(#terminal-line-25)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r1" x="0" y="654.4" textLength="134.2" clip-path="url(#terminal-line-26)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">Type </text><text class="terminal-r3" x="231.8" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">/help</text><text class="terminal-r1" x="292.8" y="654.4" textLength="256.2" clip-path="url(#terminal-line-26)"> for more information</text><text class="terminal-r1" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</text><text class="terminal-r2" x="0" y="605.6" textLength="146.4" clip-path="url(#terminal-line-24)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="605.6" textLength="122" clip-path="url(#terminal-line-24)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="605.6" textLength="244" clip-path="url(#terminal-line-24)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" y="605.6" textLength="256.2" clip-path="url(#terminal-line-24)"> · [Subscription] Pro</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="0" y="630" textLength="414.8" clip-path="url(#terminal-line-25)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r1" x="0" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">Type </text><text class="terminal-r3" x="61" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">/help</text><text class="terminal-r1" x="122" y="654.4" textLength="256.2" clip-path="url(#terminal-line-26)"> for more information</text><text class="terminal-r1" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
|
@ -179,13 +179,13 @@
|
|||
</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-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-r1" 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-r1" x="0" y="532.4" textLength="134.2" clip-path="url(#terminal-line-21)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</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="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-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
</text><text class="terminal-r1" x="0" y="605.6" textLength="134.2" clip-path="url(#terminal-line-24)">  ⡠⣒⠄  ⡔⢄⠔⡄</text><text class="terminal-r2" x="170.8" y="605.6" textLength="146.4" clip-path="url(#terminal-line-24)">Mistral Vibe</text><text class="terminal-r1" x="317.2" y="605.6" textLength="122" clip-path="url(#terminal-line-24)"> v0.0.0 · </text><text class="terminal-r3" x="439.2" y="605.6" textLength="244" clip-path="url(#terminal-line-24)">devstral-latest[off]</text><text class="terminal-r1" x="683.2" y="605.6" textLength="256.2" clip-path="url(#terminal-line-24)"> · [Subscription] Pro</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="0" y="630" textLength="134.2" clip-path="url(#terminal-line-25)"> ⢸⠸⣀⡔⢉⠱⣃⡢⣂⡣</text><text class="terminal-r1" x="170.8" y="630" textLength="414.8" clip-path="url(#terminal-line-25)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r1" x="0" y="654.4" textLength="134.2" clip-path="url(#terminal-line-26)">  ⠉⠒⠣⠤⠵⠤⠬⠮⠆</text><text class="terminal-r1" x="170.8" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">Type </text><text class="terminal-r3" x="231.8" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">/help</text><text class="terminal-r1" x="292.8" y="654.4" textLength="256.2" clip-path="url(#terminal-line-26)"> for more information</text><text class="terminal-r1" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</text><text class="terminal-r2" x="0" y="605.6" textLength="146.4" clip-path="url(#terminal-line-24)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="605.6" textLength="122" clip-path="url(#terminal-line-24)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="605.6" textLength="244" clip-path="url(#terminal-line-24)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" y="605.6" textLength="256.2" clip-path="url(#terminal-line-24)"> · [Subscription] Pro</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="0" y="630" textLength="414.8" clip-path="url(#terminal-line-25)">1 model · 0 MCP servers · 0 skills</text><text class="terminal-r1" x="1464" y="630" textLength="12.2" clip-path="url(#terminal-line-25)">
|
||||
</text><text class="terminal-r1" x="0" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">Type </text><text class="terminal-r3" x="61" y="654.4" textLength="61" clip-path="url(#terminal-line-26)">/help</text><text class="terminal-r1" x="122" y="654.4" textLength="256.2" clip-path="url(#terminal-line-26)"> for more information</text><text class="terminal-r1" x="1464" y="654.4" textLength="12.2" clip-path="url(#terminal-line-26)">
|
||||
</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)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
|
@ -174,13 +174,13 @@
|
|||
</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="361.6" textLength="134.2" clip-path="url(#terminal-line-14)">  ⡠⣒⠄  ⡔⢄⠔⡄</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="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="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="244" clip-path="url(#terminal-line-18)">devstral-latest[off]</text><text class="terminal-r1" x="683.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 · 0 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-r2" x="0" y="459.2" textLength="146.4" clip-path="url(#terminal-line-18)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="459.2" textLength="122" clip-path="url(#terminal-line-18)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="459.2" textLength="244" clip-path="url(#terminal-line-18)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" 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="414.8" clip-path="url(#terminal-line-19)">1 model · 0 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="61" clip-path="url(#terminal-line-20)">Type </text><text class="terminal-r3" x="61" y="508" textLength="61" clip-path="url(#terminal-line-20)">/help</text><text class="terminal-r1" x="122" 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-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
|
@ -175,13 +175,13 @@
|
|||
</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="361.6" textLength="134.2" clip-path="url(#terminal-line-14)">  ⡠⣒⠄  ⡔⢄⠔⡄</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="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="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="244" clip-path="url(#terminal-line-18)">devstral-latest[off]</text><text class="terminal-r1" x="683.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 · 0 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-r2" x="0" y="459.2" textLength="146.4" clip-path="url(#terminal-line-18)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="459.2" textLength="122" clip-path="url(#terminal-line-18)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="459.2" textLength="244" clip-path="url(#terminal-line-18)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" 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="414.8" clip-path="url(#terminal-line-19)">1 model · 0 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="61" clip-path="url(#terminal-line-20)">Type </text><text class="terminal-r3" x="61" y="508" textLength="61" clip-path="url(#terminal-line-20)">/help</text><text class="terminal-r1" x="122" 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-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
|
@ -175,13 +175,13 @@
|
|||
</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="361.6" textLength="134.2" clip-path="url(#terminal-line-14)">  ⡠⣒⠄  ⡔⢄⠔⡄</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="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="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="244" clip-path="url(#terminal-line-18)">devstral-latest[off]</text><text class="terminal-r1" x="683.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 · 0 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-r2" x="0" y="459.2" textLength="146.4" clip-path="url(#terminal-line-18)">Mistral Vibe</text><text class="terminal-r1" x="146.4" y="459.2" textLength="122" clip-path="url(#terminal-line-18)"> v0.0.0 · </text><text class="terminal-r3" x="268.4" y="459.2" textLength="244" clip-path="url(#terminal-line-18)">devstral-latest[off]</text><text class="terminal-r1" x="512.4" 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="414.8" clip-path="url(#terminal-line-19)">1 model · 0 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="61" clip-path="url(#terminal-line-20)">Type </text><text class="terminal-r3" x="61" y="508" textLength="61" clip-path="url(#terminal-line-20)">/help</text><text class="terminal-r1" x="122" 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-r1" x="1464" y="581.2" textLength="12.2" clip-path="url(#terminal-line-23)">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 12 KiB |