runops 0.2.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.
- runops/__init__.py +5 -0
- runops/_data/README.md +476 -0
- runops/adapters/__init__.py +29 -0
- runops/adapters/_utils/__init__.py +36 -0
- runops/adapters/_utils/toml_utils.py +81 -0
- runops/adapters/base.py +335 -0
- runops/adapters/contrib/__init__.py +5 -0
- runops/adapters/contrib/beach.py +837 -0
- runops/adapters/contrib/emses.py +1010 -0
- runops/adapters/generic.py +439 -0
- runops/adapters/registry.py +244 -0
- runops/cli/__init__.py +3 -0
- runops/cli/analyze.py +222 -0
- runops/cli/clone.py +104 -0
- runops/cli/config.py +217 -0
- runops/cli/context.py +56 -0
- runops/cli/create.py +263 -0
- runops/cli/dashboard.py +179 -0
- runops/cli/extend.py +204 -0
- runops/cli/history.py +105 -0
- runops/cli/init.py +1432 -0
- runops/cli/jobs.py +145 -0
- runops/cli/knowledge.py +1017 -0
- runops/cli/list.py +102 -0
- runops/cli/log.py +163 -0
- runops/cli/main.py +96 -0
- runops/cli/manage.py +231 -0
- runops/cli/new.py +343 -0
- runops/cli/notes.py +257 -0
- runops/cli/run_lookup.py +148 -0
- runops/cli/setup.py +174 -0
- runops/cli/status.py +187 -0
- runops/cli/submit.py +297 -0
- runops/cli/update.py +113 -0
- runops/cli/update_harness.py +245 -0
- runops/cli/update_refs.py +370 -0
- runops/core/__init__.py +3 -0
- runops/core/actions.py +1186 -0
- runops/core/analysis.py +1090 -0
- runops/core/campaign.py +156 -0
- runops/core/case.py +307 -0
- runops/core/context.py +426 -0
- runops/core/discovery.py +192 -0
- runops/core/environment.py +266 -0
- runops/core/exceptions.py +93 -0
- runops/core/knowledge.py +595 -0
- runops/core/knowledge_source.py +1204 -0
- runops/core/manifest.py +219 -0
- runops/core/project.py +171 -0
- runops/core/provenance.py +147 -0
- runops/core/retry.py +193 -0
- runops/core/run.py +170 -0
- runops/core/run_creation.py +456 -0
- runops/core/site.py +337 -0
- runops/core/state.py +197 -0
- runops/core/survey.py +380 -0
- runops/core/validation.py +40 -0
- runops/harness/__init__.py +27 -0
- runops/harness/builder.py +327 -0
- runops/harness/claude.py +189 -0
- runops/jobgen/__init__.py +3 -0
- runops/jobgen/generator.py +295 -0
- runops/launchers/__init__.py +17 -0
- runops/launchers/base.py +313 -0
- runops/launchers/mpiexec.py +131 -0
- runops/launchers/mpirun.py +132 -0
- runops/launchers/srun.py +126 -0
- runops/sites/__init__.py +0 -0
- runops/sites/camphor.md +98 -0
- runops/sites/camphor.toml +27 -0
- runops/slurm/__init__.py +3 -0
- runops/slurm/query.py +384 -0
- runops/slurm/submit.py +203 -0
- runops/templates/__init__.py +29 -0
- runops/templates/adapters/beach/agent_guide.md +50 -0
- runops/templates/adapters/beach/beach.toml +19 -0
- runops/templates/adapters/beach/case.toml +16 -0
- runops/templates/adapters/beach/summarize.py +272 -0
- runops/templates/adapters/emses/agent_guide.md +39 -0
- runops/templates/adapters/emses/case.toml +18 -0
- runops/templates/adapters/emses/plasma.toml +118 -0
- runops/templates/adapters/emses/summarize.py +413 -0
- runops/templates/adapters/generic/case.toml.j2 +13 -0
- runops/templates/adapters/generic/summarize.py +21 -0
- runops/templates/agent.md +156 -0
- runops/templates/rules/cookbook.md +22 -0
- runops/templates/scaffold/campaign.toml.j2 +10 -0
- runops/templates/scaffold/cases_claude.md +22 -0
- runops/templates/scaffold/facts.toml +2 -0
- runops/templates/scaffold/gitignore.txt +30 -0
- runops/templates/scaffold/notes/README.md +69 -0
- runops/templates/scaffold/rules/plan-before-act.md +17 -0
- runops/templates/scaffold/rules/runops-workflow.md +84 -0
- runops/templates/scaffold/rules/upstream-feedback.md +85 -0
- runops/templates/scaffold/runs_claude.md +24 -0
- runops/templates/scaffold/vscode_settings.json +9 -0
- runops/templates/skills/analyze/SKILL.md +40 -0
- runops/templates/skills/check-status/SKILL.md +29 -0
- runops/templates/skills/cleanup/SKILL.md +43 -0
- runops/templates/skills/create-run/SKILL.md +135 -0
- runops/templates/skills/debug-failed/SKILL.md +38 -0
- runops/templates/skills/learn/SKILL.md +54 -0
- runops/templates/skills/new-case/SKILL.md +108 -0
- runops/templates/skills/note/SKILL.md +107 -0
- runops/templates/skills/run-all/SKILL.md +47 -0
- runops/templates/skills/runops-reference/SKILL.md +203 -0
- runops/templates/skills/setup-campaign/SKILL.md +111 -0
- runops/templates/skills/setup-env/SKILL.md +32 -0
- runops/templates/skills/survey-design/SKILL.md +73 -0
- runops/templates/survey.toml.j2 +22 -0
- runops-0.2.0.dist-info/METADATA +491 -0
- runops-0.2.0.dist-info/RECORD +115 -0
- runops-0.2.0.dist-info/WHEEL +4 -0
- runops-0.2.0.dist-info/entry_points.txt +2 -0
- runops-0.2.0.dist-info/licenses/LICENSE +201 -0
runops/cli/history.py
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""CLI command for viewing job submission history."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import contextlib
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Annotated, Optional
|
|
8
|
+
|
|
9
|
+
import typer
|
|
10
|
+
|
|
11
|
+
from runops.core.discovery import discover_runs
|
|
12
|
+
from runops.core.exceptions import SimctlError
|
|
13
|
+
from runops.core.manifest import read_manifest
|
|
14
|
+
from runops.core.project import find_project_root
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def history(
|
|
18
|
+
path: Annotated[
|
|
19
|
+
Optional[Path],
|
|
20
|
+
typer.Argument(help="Directory to search (defaults to project root)."),
|
|
21
|
+
] = None,
|
|
22
|
+
count: Annotated[
|
|
23
|
+
int,
|
|
24
|
+
typer.Option("-n", "--count", help="Number of entries to show (0 = all)."),
|
|
25
|
+
] = 20,
|
|
26
|
+
) -> None:
|
|
27
|
+
"""Show job submission history across the project.
|
|
28
|
+
|
|
29
|
+
Lists runs sorted by submission time (most recent first).
|
|
30
|
+
|
|
31
|
+
Examples:
|
|
32
|
+
runops runs history # last 20 submissions
|
|
33
|
+
runops runs history -n 0 # all submissions
|
|
34
|
+
"""
|
|
35
|
+
search_dir = (path or Path.cwd()).resolve()
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
root = find_project_root(search_dir)
|
|
39
|
+
runs_dir = root / "runs"
|
|
40
|
+
if runs_dir.is_dir():
|
|
41
|
+
search_dir = runs_dir
|
|
42
|
+
except SimctlError:
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
try:
|
|
46
|
+
run_dirs = discover_runs(search_dir)
|
|
47
|
+
except SimctlError as e:
|
|
48
|
+
typer.echo(f"Error: {e}", err=True)
|
|
49
|
+
raise typer.Exit(code=1) from None
|
|
50
|
+
|
|
51
|
+
if not run_dirs:
|
|
52
|
+
typer.echo("No runs found.")
|
|
53
|
+
return
|
|
54
|
+
|
|
55
|
+
# Collect entries with submission info
|
|
56
|
+
entries: list[tuple[str, str, str, str, str]] = []
|
|
57
|
+
for run_dir in run_dirs:
|
|
58
|
+
try:
|
|
59
|
+
manifest = read_manifest(run_dir)
|
|
60
|
+
except SimctlError:
|
|
61
|
+
continue
|
|
62
|
+
|
|
63
|
+
job_id = manifest.job.get("job_id", "")
|
|
64
|
+
if not job_id:
|
|
65
|
+
continue # Never submitted
|
|
66
|
+
|
|
67
|
+
run_id = manifest.run.get("id", "???")
|
|
68
|
+
status = manifest.run.get("status", "unknown")
|
|
69
|
+
submitted_at = manifest.job.get("submitted_at", "")
|
|
70
|
+
rel_path = str(run_dir)
|
|
71
|
+
with contextlib.suppress(ValueError):
|
|
72
|
+
rel_path = str(run_dir.relative_to(search_dir.parent))
|
|
73
|
+
|
|
74
|
+
entries.append((submitted_at, job_id, run_id, status, rel_path))
|
|
75
|
+
|
|
76
|
+
if not entries:
|
|
77
|
+
typer.echo("No submitted runs found.")
|
|
78
|
+
return
|
|
79
|
+
|
|
80
|
+
# Sort by submission time (newest first)
|
|
81
|
+
entries.sort(key=lambda e: e[0], reverse=True)
|
|
82
|
+
|
|
83
|
+
if count > 0:
|
|
84
|
+
entries = entries[:count]
|
|
85
|
+
|
|
86
|
+
headers = ("SUBMITTED", "JOB_ID", "RUN_ID", "STATUS", "PATH")
|
|
87
|
+
widths = [len(h) for h in headers]
|
|
88
|
+
for row in entries:
|
|
89
|
+
for i, cell in enumerate(row):
|
|
90
|
+
# Shorten timestamp for display
|
|
91
|
+
display = cell
|
|
92
|
+
if i == 0 and "T" in cell:
|
|
93
|
+
display = cell.replace("T", " ")[:19]
|
|
94
|
+
widths[i] = max(widths[i], len(display))
|
|
95
|
+
|
|
96
|
+
fmt = " ".join(f"{{:<{w}}}" for w in widths)
|
|
97
|
+
typer.echo(fmt.format(*headers))
|
|
98
|
+
typer.echo(fmt.format(*("-" * w for w in widths)))
|
|
99
|
+
for row in entries:
|
|
100
|
+
display_row = list(row)
|
|
101
|
+
if "T" in display_row[0]:
|
|
102
|
+
display_row[0] = display_row[0].replace("T", " ")[:19]
|
|
103
|
+
typer.echo(fmt.format(*display_row))
|
|
104
|
+
|
|
105
|
+
typer.echo(f"\n{len(entries)} entries")
|