-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbootstrap.py
More file actions
151 lines (122 loc) · 4.89 KB
/
Copy pathbootstrap.py
File metadata and controls
151 lines (122 loc) · 4.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
"""Immutable launcher for the trusted OpenClaus runtime.
Usage:
python bootstrap.py
python bootstrap.py --dry-run
python bootstrap.py --replace PID --token TOKEN --generation N
"""
from __future__ import annotations
import argparse
import os
import shutil
import subprocess
import sys
import time
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parent
READY_MARKER = PROJECT_ROOT / ".evolve_ready"
ACK_MARKER = PROJECT_ROOT / ".evolve_ack"
ACTIVE_MARKER = PROJECT_ROOT / ".evolve_active"
if str(PROJECT_ROOT) not in sys.path:
sys.path.insert(0, str(PROJECT_ROOT))
def load_config() -> dict:
import yaml
config_path = PROJECT_ROOT / "config.yaml"
example_path = PROJECT_ROOT / "config.example.yaml"
if not config_path.exists():
if example_path.exists():
shutil.copy(example_path, config_path)
print("[BOOTSTRAP] Created config.yaml from config.example.yaml")
print("[BOOTSTRAP] Set the Gemini API key and restart.")
raise SystemExit(0)
raise SystemExit("[BOOTSTRAP] config.yaml is missing")
with config_path.open("r", encoding="utf-8") as handle:
config = yaml.safe_load(handle)
if not isinstance(config, dict):
raise SystemExit("[BOOTSTRAP] config.yaml must contain a mapping")
api_key = str(config.get("gemini", {}).get("api_key", ""))
if not api_key or api_key.startswith("YOUR_"):
raise SystemExit("[BOOTSTRAP] Set a valid Gemini API key in config.yaml")
return config
def ensure_git_repo() -> None:
if (PROJECT_ROOT / ".git").exists():
return
print("[BOOTSTRAP] Initializing git repository...")
subprocess.run(["git", "init"], cwd=PROJECT_ROOT, check=True)
subprocess.run(["git", "add", "."], cwd=PROJECT_ROOT, check=True)
subprocess.run(
["git", "commit", "-m", "gen-0: initial code"],
cwd=PROJECT_ROOT,
check=True,
)
def run_verification() -> bool:
from engine.verifier import run_checks
return run_checks(PROJECT_ROOT).ok
def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
parser = argparse.ArgumentParser(description="OpenClaus trusted launcher")
parser.add_argument("--dry-run", action="store_true", help="verify without evolving")
parser.add_argument("--replace", type=int, metavar="PID", help=argparse.SUPPRESS)
parser.add_argument("--token", help=argparse.SUPPRESS)
parser.add_argument("--generation", type=int, help=argparse.SUPPRESS)
return parser.parse_args(argv)
def replacement_start(parent_pid: int, token: str, generation: int) -> None:
from engine.controller import run
from engine.runtime import pid_is_alive, read_ready_marker, write_json_atomic
print(f"[BOOTSTRAP] Validating replacement for generation {generation}")
if not run_verification():
raise SystemExit("[BOOTSTRAP] Replacement verification failed")
write_json_atomic(
READY_MARKER,
{
"token": token,
"generation": generation,
"pid": os.getpid(),
},
)
deadline = time.monotonic() + 30
acknowledged = False
while pid_is_alive(parent_pid) and time.monotonic() < deadline:
ack = read_ready_marker(ACK_MARKER, token, generation)
if ack and ack.get("pid") == parent_pid:
acknowledged = True
break
time.sleep(0.1)
if not acknowledged:
READY_MARKER.unlink(missing_ok=True)
raise SystemExit("[BOOTSTRAP] Parent did not acknowledge the handoff")
write_json_atomic(
ACTIVE_MARKER,
{"token": token, "generation": generation, "pid": os.getpid()},
)
deadline = time.monotonic() + 30
while pid_is_alive(parent_pid) and time.monotonic() < deadline:
time.sleep(0.25)
if pid_is_alive(parent_pid):
READY_MARKER.unlink(missing_ok=True)
raise SystemExit("[BOOTSTRAP] Parent did not exit after handoff")
config = load_config()
run(config)
def main(argv: list[str] | None = None) -> int:
args = parse_args(argv)
if args.replace is not None:
if not args.token or args.generation is None or args.generation < 1:
raise SystemExit("[BOOTSTRAP] Invalid replacement handshake")
if args.dry_run:
raise SystemExit("[BOOTSTRAP] --dry-run cannot be combined with --replace")
replacement_start(args.replace, args.token, args.generation)
return 0
print("[BOOTSTRAP] OpenClaus trusted runtime starting...")
ensure_git_repo()
if args.dry_run:
ok = run_verification()
print(f"[BOOTSTRAP] Verification: {'OK' if ok else 'FAILED'}")
return 0 if ok else 1
from engine.controller import run
from engine.runtime import SafetyError
try:
run(load_config())
except SafetyError as exc:
print(f"[BOOTSTRAP] SAFETY STOP: {exc}")
return 2
return 0
if __name__ == "__main__":
raise SystemExit(main())