mirrorneuron-cli 1.0.0__py3-none-any.whl
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.0.0.dist-info/METADATA +73 -0
- mirrorneuron_cli-1.0.0.dist-info/RECORD +19 -0
- mirrorneuron_cli-1.0.0.dist-info/WHEEL +5 -0
- mirrorneuron_cli-1.0.0.dist-info/entry_points.txt +2 -0
- mirrorneuron_cli-1.0.0.dist-info/licenses/LICENSE +21 -0
- mirrorneuron_cli-1.0.0.dist-info/top_level.txt +1 -0
- mn_cli/__init__.py +0 -0
- mn_cli/config.py +43 -0
- mn_cli/error_handler.py +51 -0
- mn_cli/libs/__init__.py +1 -0
- mn_cli/libs/blueprint_cmds.py +598 -0
- mn_cli/libs/job_cmds.py +160 -0
- mn_cli/libs/run_cmds.py +780 -0
- mn_cli/libs/sys_cmds.py +52 -0
- mn_cli/libs/ui.py +162 -0
- mn_cli/logging_config.py +38 -0
- mn_cli/main.py +35 -0
- mn_cli/server_cmds.py +331 -0
- mn_cli/shared.py +13 -0
mn_cli/libs/job_cmds.py
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from rich.table import Table
|
|
3
|
+
from mn_cli.shared import console, client, logger
|
|
4
|
+
from mn_cli.error_handler import handle_cli_error
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def submit(manifest_path: str):
|
|
9
|
+
"""Submit a new workflow job"""
|
|
10
|
+
try:
|
|
11
|
+
with open(manifest_path, "r") as f:
|
|
12
|
+
manifest = f.read()
|
|
13
|
+
|
|
14
|
+
job_id = client.submit_job(manifest, {})
|
|
15
|
+
logger.info("Submitted job id=%s from manifest=%s", job_id, manifest_path)
|
|
16
|
+
console.print(f"[green]Job submitted successfully. Job ID: {job_id}[/green]")
|
|
17
|
+
except Exception as e:
|
|
18
|
+
handle_cli_error(e, console, 'submit')
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def status(job_id: str):
|
|
22
|
+
"""Get the status of a job"""
|
|
23
|
+
try:
|
|
24
|
+
job_json = client.get_job(job_id)
|
|
25
|
+
job = json.loads(job_json)
|
|
26
|
+
console.print_json(data=job)
|
|
27
|
+
except Exception as e:
|
|
28
|
+
handle_cli_error(e, console, 'status')
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def list_jobs(running_only: bool = typer.Option(False, "--running-only", help="Only show running jobs")):
|
|
32
|
+
"""List all jobs"""
|
|
33
|
+
try:
|
|
34
|
+
jobs_json = client.list_jobs()
|
|
35
|
+
data = json.loads(jobs_json)
|
|
36
|
+
|
|
37
|
+
table = Table("Job ID", "Graph ID", "Status", "Submitted At")
|
|
38
|
+
for job in data.get("data", []):
|
|
39
|
+
status = job.get("status", "N/A")
|
|
40
|
+
if running_only and status not in ["running", "pending", "scheduled", "validated", "paused"]:
|
|
41
|
+
continue
|
|
42
|
+
|
|
43
|
+
table.add_row(
|
|
44
|
+
job.get("job_id", "N/A"),
|
|
45
|
+
job.get("graph_id", "N/A"),
|
|
46
|
+
status,
|
|
47
|
+
job.get("submitted_at", "N/A"),
|
|
48
|
+
)
|
|
49
|
+
console.print(table)
|
|
50
|
+
except Exception as e:
|
|
51
|
+
handle_cli_error(e, console, 'list_jobs')
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def clear():
|
|
55
|
+
"""Remove all job records except running ones"""
|
|
56
|
+
try:
|
|
57
|
+
cleared_count = client.clear_jobs()
|
|
58
|
+
logger.info("Cleared %d non-running jobs", cleared_count)
|
|
59
|
+
console.print(f"[green]Successfully cleared {cleared_count} non-running jobs.[/green]")
|
|
60
|
+
except Exception as e:
|
|
61
|
+
handle_cli_error(e, console, 'clear')
|
|
62
|
+
|
|
63
|
+
def cancel(job_id: str):
|
|
64
|
+
"""Cancel a running job"""
|
|
65
|
+
try:
|
|
66
|
+
status = client.cancel_job(job_id)
|
|
67
|
+
console.print(f"[green]Job cancelled. Status: {status}[/green]")
|
|
68
|
+
except Exception as e:
|
|
69
|
+
handle_cli_error(e, console, 'cancel')
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def pause(job_id: str):
|
|
73
|
+
"""Pause a running job"""
|
|
74
|
+
try:
|
|
75
|
+
status = client.pause_job(job_id)
|
|
76
|
+
console.print(f"[green]Job paused. Status: {status}[/green]")
|
|
77
|
+
except Exception as e:
|
|
78
|
+
handle_cli_error(e, console, 'pause')
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def resume(job_id: str):
|
|
82
|
+
"""Resume a paused job"""
|
|
83
|
+
try:
|
|
84
|
+
status = client.resume_job(job_id)
|
|
85
|
+
console.print(f"[green]Job resumed. Status: {status}[/green]")
|
|
86
|
+
except Exception as e:
|
|
87
|
+
handle_cli_error(e, console, 'resume')
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def nodes():
|
|
91
|
+
"""Get system summary and nodes"""
|
|
92
|
+
try:
|
|
93
|
+
summary_json = client.get_system_summary()
|
|
94
|
+
summary = json.loads(summary_json)
|
|
95
|
+
console.print_json(data=summary)
|
|
96
|
+
except Exception as e:
|
|
97
|
+
handle_cli_error(e, console, 'nodes')
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def metrics():
|
|
101
|
+
"""Show runtime metrics derived from the core system summary"""
|
|
102
|
+
try:
|
|
103
|
+
summary = json.loads(client.get_system_summary())
|
|
104
|
+
if "metrics" in summary:
|
|
105
|
+
console.print_json(data=summary["metrics"])
|
|
106
|
+
return
|
|
107
|
+
|
|
108
|
+
jobs = summary.get("jobs", [])
|
|
109
|
+
status_counts = {}
|
|
110
|
+
queue_depth_total = 0
|
|
111
|
+
queue_depth_max = 0
|
|
112
|
+
pressured_agents = 0
|
|
113
|
+
|
|
114
|
+
for job in jobs:
|
|
115
|
+
status = job.get("status", "unknown")
|
|
116
|
+
status_counts[status] = status_counts.get(status, 0) + 1
|
|
117
|
+
for agent in job.get("agents", []):
|
|
118
|
+
pressure = agent.get("backpressure", {})
|
|
119
|
+
depth = int(pressure.get("queue_depth", agent.get("mailbox_depth", 0)) or 0)
|
|
120
|
+
queue_depth_total += depth
|
|
121
|
+
queue_depth_max = max(queue_depth_max, depth)
|
|
122
|
+
if pressure.get("backpressure") is True:
|
|
123
|
+
pressured_agents += 1
|
|
124
|
+
|
|
125
|
+
console.print_json(
|
|
126
|
+
data={
|
|
127
|
+
"jobs": {"total": len(jobs), "by_status": status_counts},
|
|
128
|
+
"agents": {
|
|
129
|
+
"queue_depth_total": queue_depth_total,
|
|
130
|
+
"queue_depth_max": queue_depth_max,
|
|
131
|
+
"pressured": pressured_agents,
|
|
132
|
+
},
|
|
133
|
+
"nodes": {"total": len(summary.get("nodes", []))},
|
|
134
|
+
"source": "system_summary",
|
|
135
|
+
}
|
|
136
|
+
)
|
|
137
|
+
except Exception as e:
|
|
138
|
+
handle_cli_error(e, console, "metrics")
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def dead_letters(job_id: str):
|
|
142
|
+
"""List dead-letter events for a job"""
|
|
143
|
+
try:
|
|
144
|
+
letters = []
|
|
145
|
+
for index, event_json in enumerate(client.stream_events(job_id)):
|
|
146
|
+
event = json.loads(event_json)
|
|
147
|
+
if event.get("type") == "dead_letter":
|
|
148
|
+
letters.append(
|
|
149
|
+
{
|
|
150
|
+
"index": len(letters),
|
|
151
|
+
"event_index": index,
|
|
152
|
+
"agent_id": event.get("agent_id"),
|
|
153
|
+
"reason": event.get("reason") or event.get("error"),
|
|
154
|
+
"timestamp": event.get("timestamp"),
|
|
155
|
+
"message": event.get("message"),
|
|
156
|
+
}
|
|
157
|
+
)
|
|
158
|
+
console.print_json(data={"job_id": job_id, "data": letters})
|
|
159
|
+
except Exception as e:
|
|
160
|
+
handle_cli_error(e, console, "dead_letters")
|