@giamme/forge 0.0.0-stage → 0.9.0
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.
- package/CHANGELOG.md +205 -0
- package/LICENSE +21 -0
- package/README.md +194 -2
- package/SKILL.md +123 -0
- package/VERSION +1 -0
- package/docs/README.md +26 -0
- package/docs/add-ons.md +33 -0
- package/docs/artifacts.md +69 -0
- package/docs/commands.md +315 -0
- package/docs/dataset.md +20 -0
- package/docs/decomposed-runs.md +268 -0
- package/docs/development.md +95 -0
- package/docs/forge-ui.md +92 -0
- package/docs/fractal.md +181 -0
- package/docs/install.md +160 -0
- package/docs/memory.md +156 -0
- package/docs/models.md +118 -0
- package/docs/reviews.md +231 -0
- package/docs/safety.md +55 -0
- package/docs/troubleshooting.md +54 -0
- package/forge +79 -0
- package/package.json +27 -4
- package/references/dataset.md +329 -0
- package/references/decompose.md +667 -0
- package/references/fractal-dashboard.md +21 -0
- package/references/fractal.md +307 -0
- package/references/harnesses.md +365 -0
- package/references/jev.md +865 -0
- package/references/memory.md +228 -0
- package/references/planning.md +42 -0
- package/references/ripwire.md +47 -0
- package/references/runtime.md +64 -0
- package/references/solo.md +113 -0
- package/references/ui.md +112 -0
- package/registry.tsv +81 -0
- package/scripts/forge-artifact.sh +78 -0
- package/scripts/forge-contract.py +430 -0
- package/scripts/forge-dataset.py +6 -0
- package/scripts/forge-dispatch.sh +671 -0
- package/scripts/forge-fail-first.py +195 -0
- package/scripts/forge-fractal-dispatch.sh +4 -0
- package/scripts/forge-fractal-options.sh +54 -0
- package/scripts/forge-fractal.py +6 -0
- package/scripts/forge-guard.py +266 -0
- package/scripts/forge-install-fractal.sh +4 -0
- package/scripts/forge-install-ripwire.sh +52 -0
- package/scripts/forge-install.sh +135 -0
- package/scripts/forge-jev-options.sh +259 -0
- package/scripts/forge-jev.py +6 -0
- package/scripts/forge-lib-plans.sh +785 -0
- package/scripts/forge-lib-review.sh +494 -0
- package/scripts/forge-lib-task.sh +302 -0
- package/scripts/forge-lib-verify.sh +30 -0
- package/scripts/forge-memory.sh +575 -0
- package/scripts/forge-metrics.sh +39 -0
- package/scripts/forge-parallel-options.sh +76 -0
- package/scripts/forge-parallel.sh +1717 -0
- package/scripts/forge-plan-check.py +118 -0
- package/scripts/forge-prompt.py +45 -0
- package/scripts/forge-ripwire.py +136 -0
- package/scripts/forge-route.py +344 -0
- package/scripts/forge-runs.py +121 -0
- package/scripts/forge-runtime.py +586 -0
- package/scripts/forge-schedule.py +312 -0
- package/scripts/forge-shadow.py +305 -0
- package/scripts/forge-solo.sh +347 -0
- package/scripts/forge-ui-options.sh +42 -0
- package/scripts/forge-ui.py +435 -0
- package/scripts/forge-update.sh +71 -0
- package/scripts/forge-verify-coverage.py +956 -0
- package/scripts/forge-version.py +240 -0
- package/scripts/forge_dataset/__init__.py +439 -0
- package/scripts/forge_dataset/capture.py +330 -0
- package/scripts/forge_dataset/checks.py +109 -0
- package/scripts/forge_dataset/cli.py +233 -0
- package/scripts/forge_dataset/export.py +1009 -0
- package/scripts/forge_dataset/harvest.py +716 -0
- package/scripts/forge_dataset/importer.py +412 -0
- package/scripts/forge_dataset/outcomes.py +275 -0
- package/scripts/forge_dataset/routing.py +278 -0
- package/scripts/forge_fractal/__init__.py +84 -0
- package/scripts/forge_fractal/bridge.py +46 -0
- package/scripts/forge_fractal/cli.py +202 -0
- package/scripts/forge_fractal/dashboard.css +138 -0
- package/scripts/forge_fractal/dashboard.html +41 -0
- package/scripts/forge_fractal/dashboard.js +687 -0
- package/scripts/forge_fractal/decomposition.py +262 -0
- package/scripts/forge_fractal/execution.py +659 -0
- package/scripts/forge_fractal/inspection.py +261 -0
- package/scripts/forge_fractal/install.py +158 -0
- package/scripts/forge_fractal/invocation.py +94 -0
- package/scripts/forge_fractal/pipeline.py +124 -0
- package/scripts/forge_fractal/selection.py +179 -0
- package/scripts/forge_jev/__init__.py +376 -0
- package/scripts/forge_jev/backtest.py +322 -0
- package/scripts/forge_jev/cli.py +980 -0
- package/scripts/forge_jev/client.py +418 -0
- package/scripts/forge_jev/corpus.py +156 -0
- package/scripts/forge_jev/coupling.py +244 -0
- package/scripts/forge_jev/features.py +24 -0
- package/scripts/forge_jev/gates.py +100 -0
- package/scripts/forge_jev/memory.py +163 -0
- package/scripts/forge_jev/outcome.py +49 -0
- package/scripts/forge_jev/predict.py +204 -0
- package/scripts/forge_jev/questions.py +661 -0
- package/scripts/forge_jev/review.py +73 -0
- package/scripts/forge_jev/routing.py +271 -0
- package/scripts/forge_jev/subset.py +123 -0
- package/scripts/forge_jev/verify.py +453 -0
- package/scripts/forge_registry.py +140 -0
- package/ui/README.md +347 -0
- package/ui/THIRD_PARTY_NOTICES.md +177 -0
- package/ui/docs/api.md +970 -0
- package/ui/forge_ui/__init__.py +20 -0
- package/ui/forge_ui/__main__.py +135 -0
- package/ui/forge_ui/diffs.py +454 -0
- package/ui/forge_ui/executions.py +436 -0
- package/ui/forge_ui/export.py +214 -0
- package/ui/forge_ui/findings.py +132 -0
- package/ui/forge_ui/fractal.py +582 -0
- package/ui/forge_ui/models.py +216 -0
- package/ui/forge_ui/reader.py +1424 -0
- package/ui/forge_ui/server.py +312 -0
- package/ui/forge_ui/static/D-DINCondensed-Bold.woff2 +0 -0
- package/ui/forge_ui/static/app.js +1079 -0
- package/ui/forge_ui/static/cloud3d.js +647 -0
- package/ui/forge_ui/static/cloudmodel.js +375 -0
- package/ui/forge_ui/static/cloudui.js +397 -0
- package/ui/forge_ui/static/convo.js +295 -0
- package/ui/forge_ui/static/datatable.js +232 -0
- package/ui/forge_ui/static/diffview.js +235 -0
- package/ui/forge_ui/static/favicon.svg +1 -0
- package/ui/forge_ui/static/files.js +776 -0
- package/ui/forge_ui/static/findings3d.js +134 -0
- package/ui/forge_ui/static/gantt.js +97 -0
- package/ui/forge_ui/static/graph.js +266 -0
- package/ui/forge_ui/static/icons.js +94 -0
- package/ui/forge_ui/static/index.html +67 -0
- package/ui/forge_ui/static/iso.js +816 -0
- package/ui/forge_ui/static/leaderboard.js +311 -0
- package/ui/forge_ui/static/map3d.js +45 -0
- package/ui/forge_ui/static/modelstats.js +249 -0
- package/ui/forge_ui/static/notify.js +179 -0
- package/ui/forge_ui/static/panel.js +562 -0
- package/ui/forge_ui/static/runmodel.js +667 -0
- package/ui/forge_ui/static/scene3d.js +1471 -0
- package/ui/forge_ui/static/search.js +120 -0
- package/ui/forge_ui/static/shell.js +137 -0
- package/ui/forge_ui/static/stagectl.js +150 -0
- package/ui/forge_ui/static/style.css +1073 -0
- package/ui/forge_ui/static/theme.js +25 -0
- package/ui/forge_ui/transcripts.py +608 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""forge runs [--repo DIR | --all] [--limit N] [--json]: this repo's recent runs, in the terminal.
|
|
3
|
+
|
|
4
|
+
Every solo run, `plan` and `run` registers its run dir (forge_registry.py); this lists them newest
|
|
5
|
+
first, one line each (run id, kind, age, task states, verification and final review, goal) with the
|
|
6
|
+
run dir under it, so you can see what happened without a browser and get the dir to resume, retry
|
|
7
|
+
or open with `forge ui open`. The repo is the Git top level of the current directory unless
|
|
8
|
+
`--repo` names one; `--all` lists the runs of every repo. It reads the same run summaries as
|
|
9
|
+
forge-ui and never writes anything.
|
|
10
|
+
"""
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import argparse
|
|
14
|
+
import json
|
|
15
|
+
import os
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
import subprocess
|
|
18
|
+
import sys
|
|
19
|
+
import time
|
|
20
|
+
|
|
21
|
+
SKILL = Path(__file__).resolve().parent.parent
|
|
22
|
+
sys.path.insert(0, str(SKILL / 'scripts'))
|
|
23
|
+
sys.path.insert(0, str(SKILL / 'ui'))
|
|
24
|
+
|
|
25
|
+
import forge_registry # noqa: E402
|
|
26
|
+
from forge_ui import reader # noqa: E402
|
|
27
|
+
|
|
28
|
+
FIELDS = ('key', 'run_id', 'kind', 'goal', 'repo', 'path', 'created', 'updated', 'task_count', 'counts',
|
|
29
|
+
'verification_status', 'final_review')
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def repo_of(start: Path) -> Path:
|
|
33
|
+
"""The Git top level of `start`, else `start` itself: the key runs are registered under."""
|
|
34
|
+
try:
|
|
35
|
+
out = subprocess.run(['git', '-C', str(start), 'rev-parse', '--show-toplevel'], capture_output=True,
|
|
36
|
+
text=True, stdin=subprocess.DEVNULL, timeout=10)
|
|
37
|
+
if out.returncode == 0 and out.stdout.strip():
|
|
38
|
+
return Path(out.stdout.strip()).resolve()
|
|
39
|
+
except (OSError, subprocess.SubprocessError):
|
|
40
|
+
pass
|
|
41
|
+
return start.resolve()
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def registered(path: Path) -> list[str]:
|
|
45
|
+
"""The run dirs one registry file lists (absolute paths, comments skipped)."""
|
|
46
|
+
try:
|
|
47
|
+
lines = path.read_text(encoding='utf-8', errors='replace').splitlines()
|
|
48
|
+
except OSError:
|
|
49
|
+
return []
|
|
50
|
+
return [line.strip() for line in lines if line.strip() and not line.startswith('#') and os.path.isabs(line.strip())]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def runs(repo: Path | None) -> list[dict]:
|
|
54
|
+
if repo is None:
|
|
55
|
+
found = reader.discover(registry=True, registry_dir=forge_registry.registry_dir())
|
|
56
|
+
else:
|
|
57
|
+
found = reader.discover(plans=registered(forge_registry.runs_registry(repo)), registry=False)
|
|
58
|
+
result = []
|
|
59
|
+
for path, source in found:
|
|
60
|
+
try:
|
|
61
|
+
summary = reader.summarize(path, source)
|
|
62
|
+
except Exception: # one unreadable run dir must not hide the others
|
|
63
|
+
continue
|
|
64
|
+
result.append({k: summary.get(k) for k in FIELDS})
|
|
65
|
+
return sorted(result, key=lambda r: r['updated'] if r['updated'] is not None else float('-inf'), reverse=True)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def age(epoch, now) -> str:
|
|
69
|
+
if epoch is None:
|
|
70
|
+
return '?'
|
|
71
|
+
s = max(0, now - epoch)
|
|
72
|
+
for unit, size in (('d', 86400), ('h', 3600), ('m', 60)):
|
|
73
|
+
if s >= size:
|
|
74
|
+
return f'{int(s // size)}{unit} ago'
|
|
75
|
+
return 'just now'
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def line(run: dict, now: float, with_repo: bool = False) -> str:
|
|
79
|
+
counts = ' · '.join(f'{status.lower()} {n}' for status, n in (run['counts'] or {}).items()) or 'no tasks'
|
|
80
|
+
checks = ''.join(f' {label} {run[key]}' for label, key in (('verify', 'verification_status'), ('review', 'final_review'))
|
|
81
|
+
if run.get(key))
|
|
82
|
+
goal = str(run['goal'] or 'Untitled run').splitlines()[0]
|
|
83
|
+
if len(goal) > 72:
|
|
84
|
+
goal = goal[:71] + '…'
|
|
85
|
+
repo = f" {Path(run['repo']).name or run['repo']}" if with_repo and run.get('repo') else ''
|
|
86
|
+
return f"{run['run_id'] or run['key']} {run['kind']}{repo} {age(run['updated'], now)} {counts}{checks} {goal}\n {run['path']}"
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def main(argv=None) -> int:
|
|
90
|
+
parser = argparse.ArgumentParser(prog='forge runs', description="This repo's recent forge runs, newest first. Read-only.")
|
|
91
|
+
which = parser.add_mutually_exclusive_group()
|
|
92
|
+
which.add_argument('--repo', type=Path, metavar='DIR', help='the repo whose runs to list (default: the Git top level of the current directory)')
|
|
93
|
+
which.add_argument('--all', action='store_true', help='list the runs of every repo')
|
|
94
|
+
parser.add_argument('--limit', type=int, default=10, metavar='N', help='at most N runs (default 10; 0 lists them all)')
|
|
95
|
+
parser.add_argument('--json', action='store_true', help='print the runs as a JSON array, for scripts and agents')
|
|
96
|
+
args = parser.parse_args(argv)
|
|
97
|
+
if args.limit < 0:
|
|
98
|
+
parser.error('--limit must be 0 or more')
|
|
99
|
+
if args.repo is not None and not args.repo.is_dir():
|
|
100
|
+
parser.error(f'--repo: no such directory: {args.repo}')
|
|
101
|
+
repo = None if args.all else repo_of(args.repo if args.repo is not None else Path.cwd())
|
|
102
|
+
found = runs(repo)
|
|
103
|
+
shown = found[:args.limit] if args.limit else found
|
|
104
|
+
if args.json:
|
|
105
|
+
json.dump(shown, sys.stdout, indent=2)
|
|
106
|
+
sys.stdout.write('\n')
|
|
107
|
+
return 0
|
|
108
|
+
where = 'every repo' if repo is None else str(repo)
|
|
109
|
+
if not found:
|
|
110
|
+
print(f'forge runs: no runs registered for {where}')
|
|
111
|
+
print('Runs register when they start (/forge "<goal>" --dwarf <model>); FORGE_RUN_REGISTRY=off turns that off.')
|
|
112
|
+
return 0
|
|
113
|
+
print(f'forge runs for {where}: {len(shown)} of {len(found)}, newest first')
|
|
114
|
+
now = time.time()
|
|
115
|
+
for run in shown:
|
|
116
|
+
print(line(run, now, with_repo=repo is None))
|
|
117
|
+
return 0
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
if __name__ == '__main__':
|
|
121
|
+
sys.exit(main())
|