feat(nonlinear-static-newton-raphson): step 0 - cli-output-lease-and-derived-names

This commit is contained in:
KOKO\Mimi
2026-08-24 10:42:14 +09:00
parent 41816c8aef
commit fc16ef6221
61 changed files with 10890 additions and 115 deletions
+53 -2
View File
@@ -66,8 +66,12 @@ class StepExecutor:
"""Phase 디렉토리 안의 step들을 순차 실행하는 하네스."""
MAX_RETRIES = 3
CODEX_TIMEOUT_SECONDS = 1800
CODEX_SANDBOX_ENV = "FESA_HARNESS_CODEX_SANDBOX"
CODEX_SANDBOX_MODES = frozenset({"workspace-write", "danger-full-access"})
IMPLEMENTATION_AGENT_PROFILE = Path(
".codex/agents/implementation-agent.toml"
)
FEAT_MSG = "feat({phase}): step {num} - {name}"
CHORE_MSG = "chore({phase}): step {num} output"
TZ = timezone(timedelta(hours=9))
@@ -253,6 +257,35 @@ class StepExecutor:
)
return mode
def _implementation_agent_settings(self) -> tuple[str, str]:
profile_path = Path(self._root) / self.IMPLEMENTATION_AGENT_PROFILE
try:
profile_lines = profile_path.read_text(encoding="utf-8").splitlines()
except OSError as exc:
raise CodexEnvironmentError(
f"Implementation Agent profile을 읽을 수 없습니다: {profile_path}"
) from exc
settings = {}
for line in profile_lines:
key, separator, value = line.partition("=")
key = key.strip()
if separator and key in {"model", "model_reasoning_effort"}:
try:
settings[key] = json.loads(value.strip())
except json.JSONDecodeError as exc:
raise CodexEnvironmentError(
f"Implementation Agent profile의 {key} 값이 올바른 문자열이 아닙니다."
) from exc
model = settings.get("model")
reasoning_effort = settings.get("model_reasoning_effort")
if not isinstance(model, str) or not isinstance(reasoning_effort, str):
raise CodexEnvironmentError(
"Implementation Agent profile에 model과 model_reasoning_effort 문자열이 필요합니다."
)
return model, reasoning_effort
def _invoke_codex(self, step: dict, preamble: str) -> dict:
step_num, step_name = step["step"], step["name"]
step_file = self._phase_dir / f"step{step_num}.md"
@@ -262,12 +295,20 @@ class StepExecutor:
sys.exit(1)
prompt = preamble + step_file.read_text(encoding="utf-8")
sandbox_mode = self._codex_sandbox_mode()
model, reasoning_effort = self._implementation_agent_settings()
command = [
"codex",
"exec",
"--disable",
"unified_exec",
"--json",
"--model",
model,
"--config",
f"model_reasoning_effort={json.dumps(reasoning_effort)}",
"--sandbox",
self._codex_sandbox_mode(),
sandbox_mode,
"--dangerously-bypass-hook-trust",
"--cd",
self._root,
@@ -281,12 +322,22 @@ class StepExecutor:
capture_output=True,
text=True,
encoding="utf-8",
timeout=1800,
timeout=self.CODEX_TIMEOUT_SECONDS,
)
except FileNotFoundError as exc:
raise CodexEnvironmentError(
"Codex CLI를 찾을 수 없습니다. codex를 설치하고 PATH를 확인하세요."
) from exc
except subprocess.TimeoutExpired as exc:
timeout_message = f"Codex timed out after {exc.timeout} seconds."
stderr = exc.stderr or ""
if stderr:
stderr = f"{timeout_message}\n{stderr}"
else:
stderr = timeout_message
result = subprocess.CompletedProcess(
command, 124, stdout=exc.stdout or "", stderr=stderr
)
if result.returncode != 0:
print(f"\n WARN: Codex가 비정상 종료됨 (code {result.returncode})")