mistralai-workflows-cli 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,201 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ develop-eggs/
12
+ dist/
13
+ downloads/
14
+ eggs/
15
+ .eggs/
16
+ parts/
17
+ sdist/
18
+ var/
19
+ wheels/
20
+ share/python-wheels/
21
+ *.egg-info/
22
+ .installed.cfg
23
+ *.egg
24
+ MANIFEST
25
+
26
+ # PyInstaller
27
+ # Usually these files are written by a python script from a template
28
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
29
+ *.manifest
30
+ *.spec
31
+
32
+ # Installer logs
33
+ pip-log.txt
34
+ pip-delete-this-directory.txt
35
+
36
+ # Unit test / coverage reports
37
+ htmlcov/
38
+ .tox/
39
+ .nox/
40
+ .coverage
41
+ .coverage.*
42
+ .cache
43
+ nosetests.xml
44
+ coverage.xml
45
+ *.cover
46
+ *.py,cover
47
+ .hypothesis/
48
+ .pytest_cache/
49
+ cover/
50
+
51
+ # Translations
52
+ *.pot
53
+
54
+ # Django stuff:
55
+ *.log
56
+ local_settings.py
57
+ db.sqlite3
58
+ db.sqlite3-journal
59
+
60
+ # Flask stuff:
61
+ instance/
62
+ .webassets-cache
63
+
64
+ # Scrapy stuff:
65
+ .scrapy
66
+
67
+ # Sphinx documentation
68
+ docs/_build/
69
+
70
+ # PyBuilder
71
+ .pybuilder/
72
+ target/
73
+
74
+ # Ruff
75
+ .ruff_cache/
76
+
77
+ # Jupyter Notebook
78
+ .ipynb_checkpoints
79
+
80
+ # IPython
81
+ profile_default/
82
+ ipython_config.py
83
+
84
+ # pyenv
85
+ # For a library or package, you might want to ignore these files since the code is
86
+ # intended to run in multiple environments; otherwise, check them in:
87
+ # .python-version
88
+
89
+ # pipenv
90
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
91
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
92
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
93
+ # install all needed dependencies.
94
+ #Pipfile.lock
95
+
96
+ # poetry
97
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
98
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
99
+ # commonly ignored for libraries.
100
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
101
+ #poetry.lock
102
+
103
+ # pdm
104
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
105
+ #pdm.lock
106
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
107
+ # in version control.
108
+ # https://pdm.fming.dev/#use-with-ide
109
+ .pdm.toml
110
+
111
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
112
+ __pypackages__/
113
+
114
+ # Celery stuff
115
+ celerybeat-schedule
116
+ celerybeat.pid
117
+
118
+ # SageMath parsed files
119
+ *.sage.py
120
+
121
+ # Environments
122
+ .env
123
+ .envrc
124
+ .venv
125
+ env/
126
+ venv/
127
+ ENV/
128
+ env.bak/
129
+ venv.bak/
130
+
131
+ # Spyder project settings
132
+ .spyderproject
133
+ .spyproject
134
+
135
+ # Rope project settings
136
+ .ropeproject
137
+
138
+ # mkdocs documentation
139
+ /site
140
+
141
+ # mypy
142
+ .mypy_cache/
143
+ .dmypy.json
144
+ dmypy.json
145
+
146
+ # Pyre type checker
147
+ .pyre/
148
+
149
+ # pytype static type analyzer
150
+ .pytype/
151
+
152
+ # Cython debug symbols
153
+ cython_debug/
154
+
155
+ # VSCode
156
+ .vscode/
157
+ !.vscode/extensions.json
158
+ !.vscode/settings.json
159
+
160
+ # PyCharm
161
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
162
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
163
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
164
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
165
+ .idea/
166
+
167
+ .DS_Store
168
+ pyrightconfig.json
169
+ coverage
170
+ i18n.cache
171
+
172
+ ## Local scripts
173
+
174
+ integrations/scripts/local/
175
+ scripts/run-dashboard/apps.local.yaml
176
+ # Convenient to disable your local config without deleting it
177
+ scripts/run-dashboard/_apps.local.yaml
178
+ scripts/run-dashboard/plugins
179
+
180
+ ## Local data for notebooks
181
+ .data/
182
+
183
+ # Watchman - used by mobile (metro and jest)
184
+ # Those files are written in a 60s interval, not ignoring them causes turbo to restart tasks
185
+ .watchman-cookie-*
186
+
187
+ # TS
188
+ node_modules
189
+ .turbo
190
+ .yarn
191
+
192
+ # Files generated by the jobs tests. TODO: see whether we can use a temp directory for this.
193
+ jobs/run/checkpoints/test/consolidated/lora.safetensors
194
+ jobs/run/checkpoints/test/consolidated/params.json
195
+
196
+ # By default `claude --worktree` creates the worktree in this directory
197
+ .claude/worktrees
198
+
199
+ # Cursor plans folder
200
+ .cursor/plans/
201
+ tsconfig.tsbuildinfo
@@ -0,0 +1,21 @@
1
+ .PHONY: lint format typecheck test installdeps clean
2
+
3
+ lint:
4
+ uv run ruff check .
5
+ uv run ruff format --check .
6
+
7
+ format:
8
+ uv run ruff format .
9
+ uv run ruff check --fix .
10
+
11
+ typecheck:
12
+ uv run mypy src/
13
+
14
+ test:
15
+ uv run pytest
16
+
17
+ installdeps:
18
+ uv sync
19
+
20
+ clean:
21
+ rm -rf dist/ build/ *.egg-info
@@ -0,0 +1,8 @@
1
+ Metadata-Version: 2.4
2
+ Name: mistralai-workflows-cli
3
+ Version: 0.1.0
4
+ Summary: CLI to bootstrap Mistral Workflows projects
5
+ Requires-Python: >=3.10
6
+ Requires-Dist: click>=8.0
7
+ Requires-Dist: copier>=9.0
8
+ Requires-Dist: rich>=13.0
@@ -0,0 +1,39 @@
1
+ # mistralai-workflows-cli
2
+
3
+ CLI to bootstrap Mistral Workflows projects.
4
+
5
+ ## Usage
6
+
7
+ ```bash
8
+ uvx mistralai-workflows-cli setup
9
+ ```
10
+
11
+ Or with options:
12
+
13
+ ```bash
14
+ uvx mistralai-workflows-cli setup --api-key sk-... --project-name my-project
15
+ ```
16
+
17
+ The `setup` command will:
18
+
19
+ 1. Ask for a project name (or use `--project-name`)
20
+ 2. Ask for a Mistral API key (or use `--api-key` / `MISTRAL_API_KEY` env var)
21
+ 3. Scaffold a new project from the [workflows-starter-app](https://github.com/mistralai/workflows-starter-app) template
22
+ 4. Suggest running `vibe` to start coding
23
+
24
+ ## Development
25
+
26
+ ```bash
27
+ cd tools/mistral-workflows
28
+ uv sync
29
+ uv run mistral-workflows --help
30
+ ```
31
+
32
+ ## Publishing
33
+
34
+ Tag with `mistral-workflows-cli/v<version>` to trigger the PyPI publish workflow.
35
+
36
+ ```bash
37
+ git tag mistral-workflows-cli/v0.1.0
38
+ git push origin mistral-workflows-cli/v0.1.0
39
+ ```
@@ -0,0 +1,34 @@
1
+ [project]
2
+ name = "mistralai-workflows-cli"
3
+ version = "0.1.0"
4
+ description = "CLI to bootstrap Mistral Workflows projects"
5
+ requires-python = ">=3.10"
6
+ dependencies = [
7
+ "click>=8.0",
8
+ "copier>=9.0",
9
+ "rich>=13.0",
10
+ ]
11
+
12
+ [project.scripts]
13
+ mistral-workflows = "mistral_workflows_cli.main:cli"
14
+ mistralai-workflows-cli = "mistral_workflows_cli.main:cli"
15
+
16
+ [build-system]
17
+ requires = ["hatchling"]
18
+ build-backend = "hatchling.build"
19
+
20
+ [tool.hatch.build.targets.wheel]
21
+ packages = ["src/mistral_workflows_cli"]
22
+
23
+ [tool.ruff]
24
+ line-length = 120
25
+
26
+ [tool.ruff.lint]
27
+ select = ["E", "F", "I", "UP"]
28
+
29
+ [dependency-groups]
30
+ dev = [
31
+ "ruff>=0.11",
32
+ "mypy>=1.15",
33
+ "pytest>=8.0",
34
+ ]
@@ -0,0 +1,18 @@
1
+ import click
2
+
3
+
4
+ @click.group()
5
+ @click.version_option()
6
+ def cli() -> None:
7
+ """Mistral Workflows CLI — bootstrap and manage workflow projects."""
8
+
9
+
10
+ @cli.command()
11
+ @click.option("--api-key", default=None, help="Mistral API key.")
12
+ @click.option("--output-dir", "-o", default=".", help="Parent directory for the new project.")
13
+ @click.option("--project-name", "-n", default=None, help="Project name (also used as directory name).")
14
+ def setup(api_key: str | None, output_dir: str, project_name: str | None) -> None:
15
+ """Bootstrap a new Mistral Workflows project."""
16
+ from mistral_workflows_cli.setup import run_setup
17
+
18
+ run_setup(api_key=api_key, output_dir=output_dir, project_name=project_name)
@@ -0,0 +1,61 @@
1
+ from __future__ import annotations
2
+
3
+ import socket
4
+ from pathlib import Path
5
+
6
+ from rich.console import Console
7
+ from rich.prompt import Prompt
8
+
9
+ TEMPLATE_URL = "gh:mistralai/workflows-starter-app"
10
+ API_KEYS_URL = "https://console.mistral.ai/api-keys"
11
+
12
+
13
+ def run_setup(
14
+ api_key: str | None,
15
+ output_dir: str,
16
+ project_name: str | None,
17
+ ) -> None:
18
+ console = Console()
19
+
20
+ console.print("\n[bold]Mistral Workflows — Project Setup[/bold]\n")
21
+
22
+ # 1. Project name
23
+ if not project_name:
24
+ project_name = Prompt.ask("Project name", default="my-workflow")
25
+
26
+ # 2. API key
27
+ if not api_key:
28
+ console.print(f"Create an API key at: [link={API_KEYS_URL}]{API_KEYS_URL}[/link]\n")
29
+ api_key = Prompt.ask("Paste your Mistral API key")
30
+
31
+ if not api_key:
32
+ console.print("[bold red]No API key provided. Aborting.[/bold red]")
33
+ raise SystemExit(1)
34
+
35
+ # 3. Clone template via copier
36
+ dest = Path(output_dir) / project_name
37
+
38
+ if dest.exists():
39
+ console.print(f"[bold red]Directory already exists: {dest}[/bold red]")
40
+ raise SystemExit(1)
41
+
42
+ console.print(f"\nScaffolding project into [bold]{dest}[/bold] ...\n")
43
+
44
+ try:
45
+ import copier
46
+ except ImportError:
47
+ console.print("[bold red]copier is not installed. Run: pip install copier[/bold red]")
48
+ raise SystemExit(1)
49
+
50
+ copier.run_copy(
51
+ TEMPLATE_URL,
52
+ str(dest),
53
+ data={"project_name": project_name, "mistral_api_key": api_key, "temporal_task_queue": socket.gethostname()},
54
+ unsafe=True,
55
+ )
56
+
57
+ # 4. Success
58
+ console.print(f"\n[bold green]Project created at {dest}[/bold green]\n")
59
+ console.print("Get started:\n")
60
+ console.print(f" cd {project_name}")
61
+ console.print(" vibe\n")
File without changes
@@ -0,0 +1,36 @@
1
+ from __future__ import annotations
2
+
3
+ from unittest.mock import patch
4
+
5
+ import pytest
6
+ from click.testing import CliRunner
7
+
8
+ from mistral_workflows_cli.main import cli
9
+ from mistral_workflows_cli.setup import run_setup
10
+
11
+
12
+ @pytest.fixture
13
+ def runner() -> CliRunner:
14
+ return CliRunner()
15
+
16
+
17
+ def test_cli_has_setup_command(runner: CliRunner) -> None:
18
+ result = runner.invoke(cli, ["--help"])
19
+ assert result.exit_code == 0
20
+ assert "setup" in result.output
21
+
22
+
23
+ def test_setup_fails_without_api_key(tmp_path: object) -> None:
24
+ with patch("mistral_workflows_cli.setup.Prompt.ask", return_value=""):
25
+ with pytest.raises(SystemExit) as exc_info:
26
+ run_setup(api_key=None, output_dir=str(tmp_path), project_name="test-proj")
27
+ assert exc_info.value.code == 1
28
+
29
+
30
+ def test_setup_fails_if_dir_exists(tmp_path: object) -> None:
31
+ import pathlib
32
+
33
+ (pathlib.Path(str(tmp_path)) / "existing").mkdir()
34
+ with pytest.raises(SystemExit) as exc_info:
35
+ run_setup(api_key="sk-test", output_dir=str(tmp_path), project_name="existing")
36
+ assert exc_info.value.code == 1