mirrorneuron-cli 1.1.4__tar.gz → 1.2.5__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.
- {mirrorneuron_cli-1.1.4 → mirrorneuron_cli-1.2.5}/.github/workflows/ci.yml +2 -3
- {mirrorneuron_cli-1.1.4 → mirrorneuron_cli-1.2.5}/.github/workflows/release.yml +2 -13
- {mirrorneuron_cli-1.1.4 → mirrorneuron_cli-1.2.5}/.gitignore +17 -1
- mirrorneuron_cli-1.2.5/.python-version +1 -0
- mirrorneuron_cli-1.2.5/AGENTS.md +10 -0
- mirrorneuron_cli-1.2.5/PKG-INFO +53 -0
- mirrorneuron_cli-1.2.5/README.md +38 -0
- mirrorneuron_cli-1.2.5/mirrorneuron_cli.egg-info/PKG-INFO +53 -0
- {mirrorneuron_cli-1.1.4 → mirrorneuron_cli-1.2.5}/mirrorneuron_cli.egg-info/SOURCES.txt +41 -1
- {mirrorneuron_cli-1.1.4 → mirrorneuron_cli-1.2.5}/mirrorneuron_cli.egg-info/requires.txt +1 -0
- mirrorneuron_cli-1.2.5/mn_cli/banner.py +13 -0
- mirrorneuron_cli-1.2.5/mn_cli/config.py +38 -0
- {mirrorneuron_cli-1.1.4 → mirrorneuron_cli-1.2.5}/mn_cli/error_handler.py +19 -0
- mirrorneuron_cli-1.2.5/mn_cli/libs/artifacts.py +139 -0
- mirrorneuron_cli-1.2.5/mn_cli/libs/backup_cmds.py +574 -0
- mirrorneuron_cli-1.2.5/mn_cli/libs/blueprint_cmds.py +1859 -0
- mirrorneuron_cli-1.2.5/mn_cli/libs/blueprint_models.py +118 -0
- {mirrorneuron_cli-1.1.4 → mirrorneuron_cli-1.2.5}/mn_cli/libs/blueprint_observability.py +44 -14
- {mirrorneuron_cli-1.1.4 → mirrorneuron_cli-1.2.5}/mn_cli/libs/blueprint_repository.py +25 -16
- mirrorneuron_cli-1.2.5/mn_cli/libs/blueprint_resources.py +902 -0
- mirrorneuron_cli-1.2.5/mn_cli/libs/bundles.py +40 -0
- mirrorneuron_cli-1.2.5/mn_cli/libs/deployment_cmds.py +183 -0
- mirrorneuron_cli-1.2.5/mn_cli/libs/event_relay.py +41 -0
- mirrorneuron_cli-1.2.5/mn_cli/libs/job_cmds.py +624 -0
- mirrorneuron_cli-1.2.5/mn_cli/libs/model_cmds.py +542 -0
- mirrorneuron_cli-1.2.5/mn_cli/libs/resource_cmds.py +194 -0
- mirrorneuron_cli-1.2.5/mn_cli/libs/run_cmds.py +3230 -0
- {mirrorneuron_cli-1.1.4 → mirrorneuron_cli-1.2.5}/mn_cli/libs/run_logs.py +38 -5
- mirrorneuron_cli-1.2.5/mn_cli/libs/run_manifest.py +1131 -0
- mirrorneuron_cli-1.2.5/mn_cli/libs/runtime_health.py +322 -0
- mirrorneuron_cli-1.2.5/mn_cli/libs/schedule_cmds.py +290 -0
- mirrorneuron_cli-1.2.5/mn_cli/libs/service_cmds.py +121 -0
- mirrorneuron_cli-1.2.5/mn_cli/libs/skill_runtime.py +668 -0
- mirrorneuron_cli-1.2.5/mn_cli/libs/sys_cmds.py +354 -0
- mirrorneuron_cli-1.2.5/mn_cli/libs/ui.py +637 -0
- mirrorneuron_cli-1.2.5/mn_cli/libs/workflow_progress.py +318 -0
- mirrorneuron_cli-1.2.5/mn_cli/libs/workflow_validation.py +677 -0
- mirrorneuron_cli-1.2.5/mn_cli/main.py +169 -0
- mirrorneuron_cli-1.2.5/mn_cli/runtime_mode.py +66 -0
- mirrorneuron_cli-1.2.5/mn_cli/runtime_state.py +135 -0
- mirrorneuron_cli-1.2.5/mn_cli/schemas/workflow_manifest.schema.json +261 -0
- mirrorneuron_cli-1.2.5/mn_cli/sdk_path.py +12 -0
- mirrorneuron_cli-1.2.5/mn_cli/server_cmds.py +3539 -0
- mirrorneuron_cli-1.2.5/mn_cli/shared.py +56 -0
- mirrorneuron_cli-1.2.5/mn_cli/terminal.py +25 -0
- {mirrorneuron_cli-1.1.4 → mirrorneuron_cli-1.2.5}/mn_cli/update_cmds.py +138 -69
- {mirrorneuron_cli-1.1.4 → mirrorneuron_cli-1.2.5}/pyproject.toml +4 -0
- mirrorneuron_cli-1.2.5/tests/test_backup_cmds.py +208 -0
- mirrorneuron_cli-1.2.5/tests/test_blueprint_cmds.py +1268 -0
- {mirrorneuron_cli-1.1.4 → mirrorneuron_cli-1.2.5}/tests/test_blueprint_repository.py +6 -3
- mirrorneuron_cli-1.2.5/tests/test_blueprint_resources.py +251 -0
- mirrorneuron_cli-1.2.5/tests/test_deployment_cmds.py +79 -0
- mirrorneuron_cli-1.2.5/tests/test_docker_network_integration.py +101 -0
- mirrorneuron_cli-1.2.5/tests/test_job_cmds.py +57 -0
- mirrorneuron_cli-1.2.5/tests/test_main.py +178 -0
- mirrorneuron_cli-1.2.5/tests/test_model_cmds.py +356 -0
- mirrorneuron_cli-1.2.5/tests/test_resource_cmds.py +52 -0
- mirrorneuron_cli-1.2.5/tests/test_run_cmds.py +2283 -0
- mirrorneuron_cli-1.2.5/tests/test_run_helpers.py +1092 -0
- mirrorneuron_cli-1.2.5/tests/test_runtime_health.py +329 -0
- mirrorneuron_cli-1.2.5/tests/test_runtime_mode.py +57 -0
- mirrorneuron_cli-1.2.5/tests/test_runtime_state.py +84 -0
- mirrorneuron_cli-1.2.5/tests/test_schedule_cmds.py +100 -0
- mirrorneuron_cli-1.2.5/tests/test_server_cmds.py +2646 -0
- mirrorneuron_cli-1.2.5/tests/test_service_cmds.py +89 -0
- mirrorneuron_cli-1.2.5/tests/test_shared.py +242 -0
- mirrorneuron_cli-1.2.5/tests/test_sys_cmds.py +161 -0
- mirrorneuron_cli-1.2.5/tests/test_terminal.py +32 -0
- mirrorneuron_cli-1.2.5/tests/test_ui.py +49 -0
- mirrorneuron_cli-1.2.5/tests/test_update_cmds.py +273 -0
- mirrorneuron_cli-1.2.5/tests/test_workflow_validation.py +95 -0
- mirrorneuron_cli-1.2.5/uv.lock +393 -0
- mirrorneuron_cli-1.1.4/PKG-INFO +0 -202
- mirrorneuron_cli-1.1.4/README.md +0 -188
- mirrorneuron_cli-1.1.4/mirrorneuron_cli.egg-info/PKG-INFO +0 -202
- mirrorneuron_cli-1.1.4/mn_cli/config.py +0 -43
- mirrorneuron_cli-1.1.4/mn_cli/libs/blueprint_cmds.py +0 -569
- mirrorneuron_cli-1.1.4/mn_cli/libs/job_cmds.py +0 -225
- mirrorneuron_cli-1.1.4/mn_cli/libs/run_cmds.py +0 -541
- mirrorneuron_cli-1.1.4/mn_cli/libs/run_manifest.py +0 -253
- mirrorneuron_cli-1.1.4/mn_cli/libs/sys_cmds.py +0 -51
- mirrorneuron_cli-1.1.4/mn_cli/libs/ui.py +0 -162
- mirrorneuron_cli-1.1.4/mn_cli/main.py +0 -43
- mirrorneuron_cli-1.1.4/mn_cli/server_cmds.py +0 -344
- mirrorneuron_cli-1.1.4/mn_cli/shared.py +0 -13
- mirrorneuron_cli-1.1.4/tests/test_blueprint_cmds.py +0 -637
- mirrorneuron_cli-1.1.4/tests/test_job_cmds.py +0 -225
- mirrorneuron_cli-1.1.4/tests/test_run_cmds.py +0 -446
- mirrorneuron_cli-1.1.4/tests/test_run_helpers.py +0 -155
- mirrorneuron_cli-1.1.4/tests/test_server_cmds.py +0 -291
- mirrorneuron_cli-1.1.4/tests/test_sys_cmds.py +0 -89
- mirrorneuron_cli-1.1.4/tests/test_update_cmds.py +0 -113
- {mirrorneuron_cli-1.1.4 → mirrorneuron_cli-1.2.5}/LICENSE +0 -0
- {mirrorneuron_cli-1.1.4 → mirrorneuron_cli-1.2.5}/RELEASE.md +0 -0
- {mirrorneuron_cli-1.1.4 → mirrorneuron_cli-1.2.5}/mirrorneuron_cli.egg-info/dependency_links.txt +0 -0
- {mirrorneuron_cli-1.1.4 → mirrorneuron_cli-1.2.5}/mirrorneuron_cli.egg-info/entry_points.txt +0 -0
- {mirrorneuron_cli-1.1.4 → mirrorneuron_cli-1.2.5}/mirrorneuron_cli.egg-info/top_level.txt +0 -0
- {mirrorneuron_cli-1.1.4 → mirrorneuron_cli-1.2.5}/mn_cli/__init__.py +0 -0
- {mirrorneuron_cli-1.1.4 → mirrorneuron_cli-1.2.5}/mn_cli/libs/__init__.py +0 -0
- {mirrorneuron_cli-1.1.4 → mirrorneuron_cli-1.2.5}/mn_cli/logging_config.py +0 -0
- {mirrorneuron_cli-1.1.4 → mirrorneuron_cli-1.2.5}/scripts/check-release-artifacts.sh +0 -0
- {mirrorneuron_cli-1.1.4 → mirrorneuron_cli-1.2.5}/scripts/make-release-zip.sh +0 -0
- {mirrorneuron_cli-1.1.4 → mirrorneuron_cli-1.2.5}/scripts/validate-version-tag.sh +0 -0
- {mirrorneuron_cli-1.1.4 → mirrorneuron_cli-1.2.5}/setup.cfg +0 -0
- {mirrorneuron_cli-1.1.4 → mirrorneuron_cli-1.2.5}/tests/conftest.py +0 -0
|
@@ -3,13 +3,7 @@ name: Release
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
5
5
|
tags:
|
|
6
|
-
- "v
|
|
7
|
-
workflow_dispatch:
|
|
8
|
-
inputs:
|
|
9
|
-
tag:
|
|
10
|
-
description: "Existing release tag to publish, such as v1.0.1 or v1.0.1-rc.1"
|
|
11
|
-
required: true
|
|
12
|
-
type: string
|
|
6
|
+
- "v[0-9]*.[0-9]*.[0-9]*"
|
|
13
7
|
|
|
14
8
|
permissions:
|
|
15
9
|
contents: read
|
|
@@ -31,19 +25,14 @@ jobs:
|
|
|
31
25
|
uses: actions/checkout@v4
|
|
32
26
|
with:
|
|
33
27
|
fetch-depth: 0
|
|
34
|
-
ref: ${{ github.
|
|
28
|
+
ref: ${{ github.ref }}
|
|
35
29
|
|
|
36
30
|
- name: Validate release tag
|
|
37
31
|
id: version
|
|
38
32
|
shell: bash
|
|
39
|
-
env:
|
|
40
|
-
INPUT_TAG: ${{ inputs.tag }}
|
|
41
33
|
run: |
|
|
42
34
|
set -euo pipefail
|
|
43
35
|
tag="$GITHUB_REF_NAME"
|
|
44
|
-
if [[ "$GITHUB_EVENT_NAME" == "workflow_dispatch" ]]; then
|
|
45
|
-
tag="$INPUT_TAG"
|
|
46
|
-
fi
|
|
47
36
|
scripts/validate-version-tag.sh "$tag"
|
|
48
37
|
|
|
49
38
|
- name: Detect project type
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
# Environments
|
|
2
2
|
.env
|
|
3
|
+
.env.*
|
|
4
|
+
!.env.example
|
|
3
5
|
.venv
|
|
6
|
+
.venv/
|
|
4
7
|
env/
|
|
5
8
|
venv/
|
|
6
9
|
ENV/
|
|
@@ -30,5 +33,18 @@ __pycache__/
|
|
|
30
33
|
*.py[cod]
|
|
31
34
|
*$py.class
|
|
32
35
|
.pytest_cache/
|
|
36
|
+
.ruff_cache/
|
|
37
|
+
.mypy_cache/
|
|
38
|
+
.pyre/
|
|
39
|
+
.hypothesis/
|
|
40
|
+
.tox/
|
|
41
|
+
.nox/
|
|
33
42
|
.coverage
|
|
34
|
-
|
|
43
|
+
.coverage.*
|
|
44
|
+
coverage.xml
|
|
45
|
+
htmlcov/
|
|
46
|
+
|
|
47
|
+
# Local editor and OS files
|
|
48
|
+
.DS_Store
|
|
49
|
+
.idea/
|
|
50
|
+
.vscode/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.11.15
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
Guidance for future coding agents working in this repository.
|
|
4
|
+
|
|
5
|
+
## Issue Fixing Policy
|
|
6
|
+
|
|
7
|
+
- Unless the user explicitly asks for a temporary workaround, fix the root cause in the intended layer or contract.
|
|
8
|
+
- Avoid adding fallback paths, compatibility shims, feature flags, or temp solutions that mask a broken primary path.
|
|
9
|
+
- If fallback behavior is already product-specified, keep it narrow, documented, and tested; do not use it to avoid fixing the primary path.
|
|
10
|
+
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mirrorneuron-cli
|
|
3
|
+
Version: 1.2.5
|
|
4
|
+
Summary: MirrorNeuron CLI
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Classifier: Programming Language :: Python :: 3
|
|
7
|
+
Requires-Python: >=3.11
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: mirrorneuron-python-sdk
|
|
11
|
+
Requires-Dist: jsonschema>=4.25
|
|
12
|
+
Requires-Dist: typer>=0.9.0
|
|
13
|
+
Requires-Dist: rich>=13.0.0
|
|
14
|
+
Dynamic: license-file
|
|
15
|
+
|
|
16
|
+
# MirrorNeuron CLI
|
|
17
|
+
|
|
18
|
+
`mn-cli` provides the `mn` command for validating and running blueprints,
|
|
19
|
+
inspecting runtime state, managing jobs, exporting artifacts, and starting local
|
|
20
|
+
services installed by `mn-deploy`.
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
Install locally and run tests:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
python3.11 -m venv .venv
|
|
28
|
+
. .venv/bin/activate
|
|
29
|
+
.venv/bin/python -m pip install -e .
|
|
30
|
+
.venv/bin/python -m pytest -q
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Try the CLI:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
mn --version
|
|
37
|
+
mn node list
|
|
38
|
+
mn blueprint run message_routing_trace
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Details
|
|
42
|
+
|
|
43
|
+
- [MirrorNeuron Component Guide](../mn-docs/component-guide.md#cli)
|
|
44
|
+
- [CLI Reference](../mn-docs/cli.md)
|
|
45
|
+
- [Environment Variables](../mn-docs/env_variables.md)
|
|
46
|
+
- [Monitor Guide](../mn-docs/monitor.md)
|
|
47
|
+
|
|
48
|
+
## Notes
|
|
49
|
+
|
|
50
|
+
- A running MirrorNeuron core is required for live runtime commands.
|
|
51
|
+
- The default gRPC target comes from `MN_GRPC_TARGET`, then local deployment
|
|
52
|
+
settings, then `localhost:55051`.
|
|
53
|
+
- Use `mn blueprint validate` before `mn blueprint run --folder` when checking a local bundle.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# MirrorNeuron CLI
|
|
2
|
+
|
|
3
|
+
`mn-cli` provides the `mn` command for validating and running blueprints,
|
|
4
|
+
inspecting runtime state, managing jobs, exporting artifacts, and starting local
|
|
5
|
+
services installed by `mn-deploy`.
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
Install locally and run tests:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
python3.11 -m venv .venv
|
|
13
|
+
. .venv/bin/activate
|
|
14
|
+
.venv/bin/python -m pip install -e .
|
|
15
|
+
.venv/bin/python -m pytest -q
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Try the CLI:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
mn --version
|
|
22
|
+
mn node list
|
|
23
|
+
mn blueprint run message_routing_trace
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Details
|
|
27
|
+
|
|
28
|
+
- [MirrorNeuron Component Guide](../mn-docs/component-guide.md#cli)
|
|
29
|
+
- [CLI Reference](../mn-docs/cli.md)
|
|
30
|
+
- [Environment Variables](../mn-docs/env_variables.md)
|
|
31
|
+
- [Monitor Guide](../mn-docs/monitor.md)
|
|
32
|
+
|
|
33
|
+
## Notes
|
|
34
|
+
|
|
35
|
+
- A running MirrorNeuron core is required for live runtime commands.
|
|
36
|
+
- The default gRPC target comes from `MN_GRPC_TARGET`, then local deployment
|
|
37
|
+
settings, then `localhost:55051`.
|
|
38
|
+
- Use `mn blueprint validate` before `mn blueprint run --folder` when checking a local bundle.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mirrorneuron-cli
|
|
3
|
+
Version: 1.2.5
|
|
4
|
+
Summary: MirrorNeuron CLI
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Classifier: Programming Language :: Python :: 3
|
|
7
|
+
Requires-Python: >=3.11
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: mirrorneuron-python-sdk
|
|
11
|
+
Requires-Dist: jsonschema>=4.25
|
|
12
|
+
Requires-Dist: typer>=0.9.0
|
|
13
|
+
Requires-Dist: rich>=13.0.0
|
|
14
|
+
Dynamic: license-file
|
|
15
|
+
|
|
16
|
+
# MirrorNeuron CLI
|
|
17
|
+
|
|
18
|
+
`mn-cli` provides the `mn` command for validating and running blueprints,
|
|
19
|
+
inspecting runtime state, managing jobs, exporting artifacts, and starting local
|
|
20
|
+
services installed by `mn-deploy`.
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
Install locally and run tests:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
python3.11 -m venv .venv
|
|
28
|
+
. .venv/bin/activate
|
|
29
|
+
.venv/bin/python -m pip install -e .
|
|
30
|
+
.venv/bin/python -m pytest -q
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Try the CLI:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
mn --version
|
|
37
|
+
mn node list
|
|
38
|
+
mn blueprint run message_routing_trace
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Details
|
|
42
|
+
|
|
43
|
+
- [MirrorNeuron Component Guide](../mn-docs/component-guide.md#cli)
|
|
44
|
+
- [CLI Reference](../mn-docs/cli.md)
|
|
45
|
+
- [Environment Variables](../mn-docs/env_variables.md)
|
|
46
|
+
- [Monitor Guide](../mn-docs/monitor.md)
|
|
47
|
+
|
|
48
|
+
## Notes
|
|
49
|
+
|
|
50
|
+
- A running MirrorNeuron core is required for live runtime commands.
|
|
51
|
+
- The default gRPC target comes from `MN_GRPC_TARGET`, then local deployment
|
|
52
|
+
settings, then `localhost:55051`.
|
|
53
|
+
- Use `mn blueprint validate` before `mn blueprint run --folder` when checking a local bundle.
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
.gitignore
|
|
2
|
+
.python-version
|
|
3
|
+
AGENTS.md
|
|
2
4
|
LICENSE
|
|
3
5
|
README.md
|
|
4
6
|
RELEASE.md
|
|
5
7
|
pyproject.toml
|
|
8
|
+
uv.lock
|
|
6
9
|
.github/workflows/ci.yml
|
|
7
10
|
.github/workflows/release.yml
|
|
8
11
|
mirrorneuron_cli.egg-info/PKG-INFO
|
|
@@ -12,32 +15,69 @@ mirrorneuron_cli.egg-info/entry_points.txt
|
|
|
12
15
|
mirrorneuron_cli.egg-info/requires.txt
|
|
13
16
|
mirrorneuron_cli.egg-info/top_level.txt
|
|
14
17
|
mn_cli/__init__.py
|
|
18
|
+
mn_cli/banner.py
|
|
15
19
|
mn_cli/config.py
|
|
16
20
|
mn_cli/error_handler.py
|
|
17
21
|
mn_cli/logging_config.py
|
|
18
22
|
mn_cli/main.py
|
|
23
|
+
mn_cli/runtime_mode.py
|
|
24
|
+
mn_cli/runtime_state.py
|
|
25
|
+
mn_cli/sdk_path.py
|
|
19
26
|
mn_cli/server_cmds.py
|
|
20
27
|
mn_cli/shared.py
|
|
28
|
+
mn_cli/terminal.py
|
|
21
29
|
mn_cli/update_cmds.py
|
|
22
30
|
mn_cli/libs/__init__.py
|
|
31
|
+
mn_cli/libs/artifacts.py
|
|
32
|
+
mn_cli/libs/backup_cmds.py
|
|
23
33
|
mn_cli/libs/blueprint_cmds.py
|
|
34
|
+
mn_cli/libs/blueprint_models.py
|
|
24
35
|
mn_cli/libs/blueprint_observability.py
|
|
25
36
|
mn_cli/libs/blueprint_repository.py
|
|
37
|
+
mn_cli/libs/blueprint_resources.py
|
|
38
|
+
mn_cli/libs/bundles.py
|
|
39
|
+
mn_cli/libs/deployment_cmds.py
|
|
40
|
+
mn_cli/libs/event_relay.py
|
|
26
41
|
mn_cli/libs/job_cmds.py
|
|
42
|
+
mn_cli/libs/model_cmds.py
|
|
43
|
+
mn_cli/libs/resource_cmds.py
|
|
27
44
|
mn_cli/libs/run_cmds.py
|
|
28
45
|
mn_cli/libs/run_logs.py
|
|
29
46
|
mn_cli/libs/run_manifest.py
|
|
47
|
+
mn_cli/libs/runtime_health.py
|
|
48
|
+
mn_cli/libs/schedule_cmds.py
|
|
49
|
+
mn_cli/libs/service_cmds.py
|
|
50
|
+
mn_cli/libs/skill_runtime.py
|
|
30
51
|
mn_cli/libs/sys_cmds.py
|
|
31
52
|
mn_cli/libs/ui.py
|
|
53
|
+
mn_cli/libs/workflow_progress.py
|
|
54
|
+
mn_cli/libs/workflow_validation.py
|
|
55
|
+
mn_cli/schemas/workflow_manifest.schema.json
|
|
32
56
|
scripts/check-release-artifacts.sh
|
|
33
57
|
scripts/make-release-zip.sh
|
|
34
58
|
scripts/validate-version-tag.sh
|
|
35
59
|
tests/conftest.py
|
|
60
|
+
tests/test_backup_cmds.py
|
|
36
61
|
tests/test_blueprint_cmds.py
|
|
37
62
|
tests/test_blueprint_repository.py
|
|
63
|
+
tests/test_blueprint_resources.py
|
|
64
|
+
tests/test_deployment_cmds.py
|
|
65
|
+
tests/test_docker_network_integration.py
|
|
38
66
|
tests/test_job_cmds.py
|
|
67
|
+
tests/test_main.py
|
|
68
|
+
tests/test_model_cmds.py
|
|
69
|
+
tests/test_resource_cmds.py
|
|
39
70
|
tests/test_run_cmds.py
|
|
40
71
|
tests/test_run_helpers.py
|
|
72
|
+
tests/test_runtime_health.py
|
|
73
|
+
tests/test_runtime_mode.py
|
|
74
|
+
tests/test_runtime_state.py
|
|
75
|
+
tests/test_schedule_cmds.py
|
|
41
76
|
tests/test_server_cmds.py
|
|
77
|
+
tests/test_service_cmds.py
|
|
78
|
+
tests/test_shared.py
|
|
42
79
|
tests/test_sys_cmds.py
|
|
43
|
-
tests/
|
|
80
|
+
tests/test_terminal.py
|
|
81
|
+
tests/test_ui.py
|
|
82
|
+
tests/test_update_cmds.py
|
|
83
|
+
tests/test_workflow_validation.py
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
MN_ASCII_ART = r"""
|
|
2
|
+
__ __ _ _ _
|
|
3
|
+
| \/ (_)_ __ _ __ ___ _ __| \ | | ___ _ _ _ __ ___ _ __
|
|
4
|
+
| |\/| | | '__| '__/ _ \| '__| \| |/ _ \ | | | '__/ _ \| '_ \
|
|
5
|
+
| | | | | | | | | (_) | | | |\ | __/ |_| | | | (_) | | | |
|
|
6
|
+
|_| |_|_|_| |_| \___/|_| |_| \_|\___|\__,_|_| \___/|_| |_|
|
|
7
|
+
""".strip("\n")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def format_banner(title: str | None = None) -> str:
|
|
11
|
+
if not title:
|
|
12
|
+
return MN_ASCII_ART
|
|
13
|
+
return f"{MN_ASCII_ART}\n\n => {title}"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from mn_cli.sdk_path import add_local_sdk_path
|
|
8
|
+
|
|
9
|
+
add_local_sdk_path("runtime_config.py")
|
|
10
|
+
|
|
11
|
+
from mn_sdk.runtime_config import RuntimeConfig, default_logs_root
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(frozen=True)
|
|
15
|
+
class CliConfig:
|
|
16
|
+
grpc_target: str = "localhost:55051"
|
|
17
|
+
grpc_timeout_seconds: float | None = 10.0
|
|
18
|
+
grpc_auth_token: str = ""
|
|
19
|
+
grpc_admin_token: str = ""
|
|
20
|
+
log_path: Path = default_logs_root() / "cli.log"
|
|
21
|
+
output_mode: str = "rich"
|
|
22
|
+
|
|
23
|
+
@classmethod
|
|
24
|
+
def from_env(cls) -> "CliConfig":
|
|
25
|
+
runtime_config = RuntimeConfig.from_env()
|
|
26
|
+
return cls(
|
|
27
|
+
grpc_target=runtime_config.grpc_target,
|
|
28
|
+
grpc_timeout_seconds=runtime_config.grpc_timeout_seconds,
|
|
29
|
+
grpc_auth_token=runtime_config.grpc_auth_token,
|
|
30
|
+
grpc_admin_token=runtime_config.grpc_admin_token,
|
|
31
|
+
log_path=Path(
|
|
32
|
+
os.getenv(
|
|
33
|
+
"MN_CLI_LOG_PATH",
|
|
34
|
+
str(default_logs_root() / "cli.log"),
|
|
35
|
+
)
|
|
36
|
+
).expanduser(),
|
|
37
|
+
output_mode=os.getenv("MN_CLI_OUTPUT", "rich"),
|
|
38
|
+
)
|
|
@@ -14,8 +14,27 @@ CONTEXT_MESSAGES = {
|
|
|
14
14
|
"cancel": "Error cancelling job",
|
|
15
15
|
"pause": "Error pausing job",
|
|
16
16
|
"resume": "Error resuming job",
|
|
17
|
+
"backup": "Error backing up job",
|
|
18
|
+
"restore": "Error restoring job",
|
|
17
19
|
"nodes": "Error fetching nodes",
|
|
20
|
+
"reconcile-node": "Error reconciling node",
|
|
21
|
+
"drain-node": "Error draining node",
|
|
22
|
+
"undrain-node": "Error cancelling node drain",
|
|
23
|
+
"maintenance-node": "Error changing node maintenance",
|
|
18
24
|
"metrics": "Error fetching metrics",
|
|
25
|
+
"resource list": "Error fetching resources",
|
|
26
|
+
"resource set": "Error setting resource limits",
|
|
27
|
+
"service list": "Error listing services",
|
|
28
|
+
"service resolve": "Error resolving service",
|
|
29
|
+
"service check": "Service validation failed",
|
|
30
|
+
"deploy": "Error deploying bundle",
|
|
31
|
+
"deployment list": "Error listing deployments",
|
|
32
|
+
"deployment status": "Error fetching deployment",
|
|
33
|
+
"deployment promote": "Error promoting deployment",
|
|
34
|
+
"deployment rollback": "Error rolling back deployment",
|
|
35
|
+
"deployment pause": "Error pausing deployment",
|
|
36
|
+
"deployment resume": "Error resuming deployment",
|
|
37
|
+
"deployment fail": "Error failing deployment",
|
|
19
38
|
"dead_letters": "Error listing dead letters",
|
|
20
39
|
"run bundle": "Error running bundle",
|
|
21
40
|
"monitor stream": "Error fetching job",
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import hashlib
|
|
4
|
+
import mimetypes
|
|
5
|
+
import os
|
|
6
|
+
import socket
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from mn_sdk.runtime_config import resolve_mn_home
|
|
11
|
+
|
|
12
|
+
from mn_cli.runtime_state import read_env_file
|
|
13
|
+
|
|
14
|
+
DEFAULT_INLINE_PAYLOAD_MAX_BYTES = 1_048_576
|
|
15
|
+
DEFAULT_ARTIFACT_PORT = "55660"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def promote_large_payloads_to_blob_refs(
|
|
19
|
+
manifest: dict[str, Any],
|
|
20
|
+
payloads: dict[str, bytes],
|
|
21
|
+
*,
|
|
22
|
+
runtime_env: dict[str, str] | None = None,
|
|
23
|
+
) -> list[dict[str, Any]]:
|
|
24
|
+
threshold = _inline_payload_max_bytes()
|
|
25
|
+
if threshold < 0:
|
|
26
|
+
return []
|
|
27
|
+
|
|
28
|
+
env = _runtime_env_file_values()
|
|
29
|
+
env.update(os.environ)
|
|
30
|
+
env.update(runtime_env or {})
|
|
31
|
+
root = _host_blob_store_root(env)
|
|
32
|
+
promoted: list[dict[str, Any]] = []
|
|
33
|
+
|
|
34
|
+
for rel_path, contents in list(payloads.items()):
|
|
35
|
+
if len(contents) <= threshold:
|
|
36
|
+
continue
|
|
37
|
+
|
|
38
|
+
blob_ref = _store_payload_blob(root, rel_path, contents, env)
|
|
39
|
+
promoted.append(blob_ref)
|
|
40
|
+
del payloads[rel_path]
|
|
41
|
+
|
|
42
|
+
if promoted:
|
|
43
|
+
metadata = manifest.setdefault("metadata", {})
|
|
44
|
+
artifacts = metadata.setdefault("mn_artifacts", {})
|
|
45
|
+
artifacts.setdefault("blob_refs", []).extend(promoted)
|
|
46
|
+
|
|
47
|
+
return promoted
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _store_payload_blob(
|
|
51
|
+
root: Path,
|
|
52
|
+
rel_path: str,
|
|
53
|
+
contents: bytes,
|
|
54
|
+
env: dict[str, str],
|
|
55
|
+
) -> dict[str, Any]:
|
|
56
|
+
sha256 = hashlib.sha256(contents).hexdigest()
|
|
57
|
+
target = root / sha256[:2] / sha256
|
|
58
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
59
|
+
|
|
60
|
+
if not target.exists():
|
|
61
|
+
tmp = target.with_name(f"{target.name}.tmp-{os.getpid()}")
|
|
62
|
+
tmp.write_bytes(contents)
|
|
63
|
+
os.replace(tmp, target)
|
|
64
|
+
|
|
65
|
+
media_type, _encoding = mimetypes.guess_type(rel_path)
|
|
66
|
+
location = _blob_location(sha256, env)
|
|
67
|
+
|
|
68
|
+
blob_ref: dict[str, Any] = {
|
|
69
|
+
"type": "blob_ref",
|
|
70
|
+
"sha256": sha256,
|
|
71
|
+
"size_bytes": len(contents),
|
|
72
|
+
"media_type": media_type or "application/octet-stream",
|
|
73
|
+
"logical_name": Path(rel_path).name,
|
|
74
|
+
"scope": "job",
|
|
75
|
+
"payload_path": rel_path.replace("\\", "/"),
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if location:
|
|
79
|
+
blob_ref["locations"] = [location]
|
|
80
|
+
|
|
81
|
+
return blob_ref
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _blob_location(sha256: str, env: dict[str, str]) -> dict[str, str] | None:
|
|
85
|
+
base_url = str(env.get("MN_ARTIFACT_ADVERTISE_URL") or os.getenv("MN_ARTIFACT_ADVERTISE_URL") or "").strip()
|
|
86
|
+
if not base_url:
|
|
87
|
+
host = (
|
|
88
|
+
str(env.get("MN_NETWORK_ADVERTISE_HOST") or os.getenv("MN_NETWORK_ADVERTISE_HOST") or "").strip()
|
|
89
|
+
or _detect_lan_ip()
|
|
90
|
+
)
|
|
91
|
+
port = str(env.get("MN_ARTIFACT_PORT") or os.getenv("MN_ARTIFACT_PORT") or DEFAULT_ARTIFACT_PORT).strip()
|
|
92
|
+
if not host or not port:
|
|
93
|
+
return None
|
|
94
|
+
base_url = f"http://{host}:{port}"
|
|
95
|
+
|
|
96
|
+
location = {
|
|
97
|
+
"url": f"{base_url.rstrip('/')}/blobs/{sha256}",
|
|
98
|
+
"status": "available",
|
|
99
|
+
}
|
|
100
|
+
node = str(env.get("MN_NODE_NAME") or os.getenv("MN_NODE_NAME") or "").strip()
|
|
101
|
+
if node:
|
|
102
|
+
location["node"] = node
|
|
103
|
+
return location
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _host_blob_store_root(env: dict[str, str]) -> Path:
|
|
107
|
+
configured = (
|
|
108
|
+
env.get("MN_HOST_BLOB_STORE_DIR")
|
|
109
|
+
or os.getenv("MN_HOST_BLOB_STORE_DIR")
|
|
110
|
+
or env.get("MN_BLOB_STORE_ROOT")
|
|
111
|
+
or os.getenv("MN_BLOB_STORE_ROOT")
|
|
112
|
+
)
|
|
113
|
+
if configured:
|
|
114
|
+
return Path(configured).expanduser()
|
|
115
|
+
return resolve_mn_home() / "blobs"
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _runtime_env_file_values() -> dict[str, str]:
|
|
119
|
+
env_file = resolve_mn_home() / "docker-compose.env"
|
|
120
|
+
return {key.strip(): value.strip() for key, value in read_env_file(env_file).items()}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _inline_payload_max_bytes() -> int:
|
|
124
|
+
value = os.getenv("MN_INLINE_PAYLOAD_MAX_BYTES", str(DEFAULT_INLINE_PAYLOAD_MAX_BYTES))
|
|
125
|
+
try:
|
|
126
|
+
return int(value)
|
|
127
|
+
except (TypeError, ValueError):
|
|
128
|
+
return DEFAULT_INLINE_PAYLOAD_MAX_BYTES
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _detect_lan_ip() -> str:
|
|
132
|
+
probe = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
133
|
+
try:
|
|
134
|
+
probe.connect(("8.8.8.8", 80))
|
|
135
|
+
return probe.getsockname()[0]
|
|
136
|
+
except OSError:
|
|
137
|
+
return "127.0.0.1"
|
|
138
|
+
finally:
|
|
139
|
+
probe.close()
|