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.
Files changed (115) hide show
  1. runops/__init__.py +5 -0
  2. runops/_data/README.md +476 -0
  3. runops/adapters/__init__.py +29 -0
  4. runops/adapters/_utils/__init__.py +36 -0
  5. runops/adapters/_utils/toml_utils.py +81 -0
  6. runops/adapters/base.py +335 -0
  7. runops/adapters/contrib/__init__.py +5 -0
  8. runops/adapters/contrib/beach.py +837 -0
  9. runops/adapters/contrib/emses.py +1010 -0
  10. runops/adapters/generic.py +439 -0
  11. runops/adapters/registry.py +244 -0
  12. runops/cli/__init__.py +3 -0
  13. runops/cli/analyze.py +222 -0
  14. runops/cli/clone.py +104 -0
  15. runops/cli/config.py +217 -0
  16. runops/cli/context.py +56 -0
  17. runops/cli/create.py +263 -0
  18. runops/cli/dashboard.py +179 -0
  19. runops/cli/extend.py +204 -0
  20. runops/cli/history.py +105 -0
  21. runops/cli/init.py +1432 -0
  22. runops/cli/jobs.py +145 -0
  23. runops/cli/knowledge.py +1017 -0
  24. runops/cli/list.py +102 -0
  25. runops/cli/log.py +163 -0
  26. runops/cli/main.py +96 -0
  27. runops/cli/manage.py +231 -0
  28. runops/cli/new.py +343 -0
  29. runops/cli/notes.py +257 -0
  30. runops/cli/run_lookup.py +148 -0
  31. runops/cli/setup.py +174 -0
  32. runops/cli/status.py +187 -0
  33. runops/cli/submit.py +297 -0
  34. runops/cli/update.py +113 -0
  35. runops/cli/update_harness.py +245 -0
  36. runops/cli/update_refs.py +370 -0
  37. runops/core/__init__.py +3 -0
  38. runops/core/actions.py +1186 -0
  39. runops/core/analysis.py +1090 -0
  40. runops/core/campaign.py +156 -0
  41. runops/core/case.py +307 -0
  42. runops/core/context.py +426 -0
  43. runops/core/discovery.py +192 -0
  44. runops/core/environment.py +266 -0
  45. runops/core/exceptions.py +93 -0
  46. runops/core/knowledge.py +595 -0
  47. runops/core/knowledge_source.py +1204 -0
  48. runops/core/manifest.py +219 -0
  49. runops/core/project.py +171 -0
  50. runops/core/provenance.py +147 -0
  51. runops/core/retry.py +193 -0
  52. runops/core/run.py +170 -0
  53. runops/core/run_creation.py +456 -0
  54. runops/core/site.py +337 -0
  55. runops/core/state.py +197 -0
  56. runops/core/survey.py +380 -0
  57. runops/core/validation.py +40 -0
  58. runops/harness/__init__.py +27 -0
  59. runops/harness/builder.py +327 -0
  60. runops/harness/claude.py +189 -0
  61. runops/jobgen/__init__.py +3 -0
  62. runops/jobgen/generator.py +295 -0
  63. runops/launchers/__init__.py +17 -0
  64. runops/launchers/base.py +313 -0
  65. runops/launchers/mpiexec.py +131 -0
  66. runops/launchers/mpirun.py +132 -0
  67. runops/launchers/srun.py +126 -0
  68. runops/sites/__init__.py +0 -0
  69. runops/sites/camphor.md +98 -0
  70. runops/sites/camphor.toml +27 -0
  71. runops/slurm/__init__.py +3 -0
  72. runops/slurm/query.py +384 -0
  73. runops/slurm/submit.py +203 -0
  74. runops/templates/__init__.py +29 -0
  75. runops/templates/adapters/beach/agent_guide.md +50 -0
  76. runops/templates/adapters/beach/beach.toml +19 -0
  77. runops/templates/adapters/beach/case.toml +16 -0
  78. runops/templates/adapters/beach/summarize.py +272 -0
  79. runops/templates/adapters/emses/agent_guide.md +39 -0
  80. runops/templates/adapters/emses/case.toml +18 -0
  81. runops/templates/adapters/emses/plasma.toml +118 -0
  82. runops/templates/adapters/emses/summarize.py +413 -0
  83. runops/templates/adapters/generic/case.toml.j2 +13 -0
  84. runops/templates/adapters/generic/summarize.py +21 -0
  85. runops/templates/agent.md +156 -0
  86. runops/templates/rules/cookbook.md +22 -0
  87. runops/templates/scaffold/campaign.toml.j2 +10 -0
  88. runops/templates/scaffold/cases_claude.md +22 -0
  89. runops/templates/scaffold/facts.toml +2 -0
  90. runops/templates/scaffold/gitignore.txt +30 -0
  91. runops/templates/scaffold/notes/README.md +69 -0
  92. runops/templates/scaffold/rules/plan-before-act.md +17 -0
  93. runops/templates/scaffold/rules/runops-workflow.md +84 -0
  94. runops/templates/scaffold/rules/upstream-feedback.md +85 -0
  95. runops/templates/scaffold/runs_claude.md +24 -0
  96. runops/templates/scaffold/vscode_settings.json +9 -0
  97. runops/templates/skills/analyze/SKILL.md +40 -0
  98. runops/templates/skills/check-status/SKILL.md +29 -0
  99. runops/templates/skills/cleanup/SKILL.md +43 -0
  100. runops/templates/skills/create-run/SKILL.md +135 -0
  101. runops/templates/skills/debug-failed/SKILL.md +38 -0
  102. runops/templates/skills/learn/SKILL.md +54 -0
  103. runops/templates/skills/new-case/SKILL.md +108 -0
  104. runops/templates/skills/note/SKILL.md +107 -0
  105. runops/templates/skills/run-all/SKILL.md +47 -0
  106. runops/templates/skills/runops-reference/SKILL.md +203 -0
  107. runops/templates/skills/setup-campaign/SKILL.md +111 -0
  108. runops/templates/skills/setup-env/SKILL.md +32 -0
  109. runops/templates/skills/survey-design/SKILL.md +73 -0
  110. runops/templates/survey.toml.j2 +22 -0
  111. runops-0.2.0.dist-info/METADATA +491 -0
  112. runops-0.2.0.dist-info/RECORD +115 -0
  113. runops-0.2.0.dist-info/WHEEL +4 -0
  114. runops-0.2.0.dist-info/entry_points.txt +2 -0
  115. 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")