Co-Authored-By: Quentin Torroba <quentin.torroba@mistral.ai> Co-Authored-By: Vincent Guilloux <vincent.guilloux@mistral.ai> Co-Authored-By: Luis Cardoso <luis.cardoso@mistral.ai>
144 lines
4.2 KiB
Python
144 lines
4.2 KiB
Python
from __future__ import annotations
|
|
|
|
import argparse
|
|
from pathlib import Path
|
|
import sys
|
|
|
|
from rich import print as rprint
|
|
|
|
from vibe import __version__
|
|
from vibe.core.paths.config_paths import unlock_config_paths
|
|
from vibe.core.trusted_folders import has_trustable_content, trusted_folders_manager
|
|
from vibe.setup.trusted_folders.trust_folder_dialog import (
|
|
TrustDialogQuitException,
|
|
ask_trust_folder,
|
|
)
|
|
|
|
|
|
def parse_arguments() -> argparse.Namespace:
|
|
parser = argparse.ArgumentParser(description="Run the Mistral Vibe interactive CLI")
|
|
parser.add_argument(
|
|
"-v", "--version", action="version", version=f"%(prog)s {__version__}"
|
|
)
|
|
parser.add_argument(
|
|
"initial_prompt",
|
|
nargs="?",
|
|
metavar="PROMPT",
|
|
help="Initial prompt to start the interactive session with.",
|
|
)
|
|
parser.add_argument(
|
|
"-p",
|
|
"--prompt",
|
|
nargs="?",
|
|
const="",
|
|
metavar="TEXT",
|
|
help="Run in programmatic mode: send prompt, auto-approve all tools, "
|
|
"output response, and exit.",
|
|
)
|
|
parser.add_argument(
|
|
"--auto-approve",
|
|
action="store_true",
|
|
default=False,
|
|
help="Start in auto-approve mode: never ask for approval before running tools.",
|
|
)
|
|
parser.add_argument(
|
|
"--plan",
|
|
action="store_true",
|
|
default=False,
|
|
help="Start in plan mode: read-only tools for exploration and planning.",
|
|
)
|
|
parser.add_argument(
|
|
"--max-turns",
|
|
type=int,
|
|
metavar="N",
|
|
help="Maximum number of assistant turns "
|
|
"(only applies in programmatic mode with -p).",
|
|
)
|
|
parser.add_argument(
|
|
"--max-price",
|
|
type=float,
|
|
metavar="DOLLARS",
|
|
help="Maximum cost in dollars (only applies in programmatic mode with -p). "
|
|
"Session will be interrupted if cost exceeds this limit.",
|
|
)
|
|
parser.add_argument(
|
|
"--enabled-tools",
|
|
action="append",
|
|
metavar="TOOL",
|
|
help="Enable specific tools. In programmatic mode (-p), this disables "
|
|
"all other tools. "
|
|
"Can use exact names, glob patterns (e.g., 'bash*'), or "
|
|
"regex with 're:' prefix. Can be specified multiple times.",
|
|
)
|
|
parser.add_argument(
|
|
"--output",
|
|
type=str,
|
|
choices=["text", "json", "streaming"],
|
|
default="text",
|
|
help="Output format for programmatic mode (-p): 'text' "
|
|
"for human-readable (default), 'json' for all messages at end, "
|
|
"'streaming' for newline-delimited JSON per message.",
|
|
)
|
|
parser.add_argument(
|
|
"--agent",
|
|
metavar="NAME",
|
|
default=None,
|
|
help="Load agent configuration from ~/.vibe/agents/NAME.toml",
|
|
)
|
|
parser.add_argument("--setup", action="store_true", help="Setup API key and exit")
|
|
|
|
continuation_group = parser.add_mutually_exclusive_group()
|
|
continuation_group.add_argument(
|
|
"-c",
|
|
"--continue",
|
|
action="store_true",
|
|
dest="continue_session",
|
|
help="Continue from the most recent saved session",
|
|
)
|
|
continuation_group.add_argument(
|
|
"--resume",
|
|
metavar="SESSION_ID",
|
|
help="Resume a specific session by its ID (supports partial matching)",
|
|
)
|
|
return parser.parse_args()
|
|
|
|
|
|
def check_and_resolve_trusted_folder() -> None:
|
|
cwd = Path.cwd()
|
|
if not has_trustable_content(cwd) or cwd.resolve() == Path.home().resolve():
|
|
return
|
|
|
|
is_folder_trusted = trusted_folders_manager.is_trusted(cwd)
|
|
|
|
if is_folder_trusted is not None:
|
|
return
|
|
|
|
try:
|
|
is_folder_trusted = ask_trust_folder(cwd)
|
|
except (KeyboardInterrupt, EOFError, TrustDialogQuitException):
|
|
sys.exit(0)
|
|
except Exception as e:
|
|
rprint(f"[yellow]Error showing trust dialog: {e}[/]")
|
|
return
|
|
|
|
if is_folder_trusted is True:
|
|
trusted_folders_manager.add_trusted(cwd)
|
|
elif is_folder_trusted is False:
|
|
trusted_folders_manager.add_untrusted(cwd)
|
|
|
|
|
|
def main() -> None:
|
|
args = parse_arguments()
|
|
|
|
is_interactive = args.prompt is None
|
|
if is_interactive:
|
|
check_and_resolve_trusted_folder()
|
|
unlock_config_paths()
|
|
|
|
from vibe.cli.cli import run_cli
|
|
|
|
run_cli(args)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|