///|
pub async fn poll_run(
task_id : String,
run_id : String,
home? : String = default_moonclaw_home(),
cwd? : String = ".",
detect_orphan? : Bool = true,
) -> ProposalPollResponse {
let resolved_cwd = resolve_root_path(cwd)
let resolved_home = resolve_home_path(home, resolved_cwd)
match load_run(run_id, resolved_home) {
Some(run) => {
let workspace_dir = run.workspace_dir.unwrap_or(resolved_cwd)
let result_payload = load_run_result_payload(workspace_dir)
let indexed_status = town_status_for_run_status(run.status)
let orphaned = detect_orphan &&
orphan_detectable_run_status(indexed_status) &&
!moonclaw_run_process_alive(run.id)
let status : @core.TaskExecutionStatus = if orphaned {
Failed
} else {
indexed_status
}
let result_text = moonclaw_result_payload_text(result_payload)
let result_decision = guarded_moonclaw_result_decision(
parse_json_string(result_payload, "result_decision").unwrap_or(
if status == Failed {
"blocked"
} else if status == Completed {
"accepted"
} else {
"pending"
},
),
result_text,
)
let requires_review = parse_json_bool(result_payload, "requires_review").unwrap_or(
false,
) ||
moonclaw_result_text_requires_review(result_text)
{
task_id,
run_id,
status,
summary: if orphaned {
"MoonClaw run \{run.id} is indexed as Running, but no live proposal process was found; treating it as failed for mayor recovery."
} else {
run_summary(run, result_payload)
},
memory_candidates: [],
result_decision,
requires_review,
notify_town: parse_json_bool(result_payload, "notify_town").unwrap_or(
status == Completed,
),
}
}
None =>
{
task_id,
run_id,
status: Running,
summary: "Run \{run_id} has not been indexed in MoonClaw yet.",
memory_candidates: [],
result_decision: "pending",
requires_review: false,
notify_town: false,
}
}
}
///|
fn moonclaw_result_payload_text(payload : Json) -> String {
match parse_json_string(payload, "content") {
Some(content) => content
None =>
match parse_json_string(payload, "summary") {
Some(summary) => summary
None => ""
}
}
}
///|
fn guarded_moonclaw_result_decision(
decision : String,
result_text : String,
) -> String {
if moonclaw_result_text_requires_review(result_text) {
"needs_review"
} else {
decision
}
}
///|
fn moonclaw_result_text_requires_review(result_text : String) -> Bool {
if result_text.is_empty() {
return false
}
for raw in result_text.split("\n") {
let line = raw.trim().to_owned().to_lower()
if line.contains("pass/fail:** fail") ||
line.contains("pass/fail: fail") ||
line.contains("review outcome: rejected") ||
line.contains("result should be rejected") {
return true
}
}
false
}
///|
fn orphan_detectable_run_status(status : @core.TaskExecutionStatus) -> Bool {
status == RunConfirmed || status == Running
}
///|
pub async fn run_workspace_dir(
run_id : String,
home? : String = default_moonclaw_home(),
cwd? : String = ".",
) -> String? {
let resolved_cwd = resolve_root_path(cwd)
let resolved_home = resolve_home_path(home, resolved_cwd)
load_run(run_id, resolved_home).bind(fn(run) { run.workspace_dir })
}
///|
pub async fn run_process_alive(run_id : String) -> Bool {
moonclaw_run_process_alive(run_id)
}
///|
async fn moonclaw_run_process_alive(run_id : String) -> Bool {
let listed = @integration.run_checked("ps", ["-ef"]) catch {
_ => return false
}
for line in listed.stdout.split("\n") {
if moonclaw_process_line_is_proposal_run(line.to_owned(), run_id) {
return true
}
}
false
}
///|
fn moonclaw_process_line_is_proposal_run(
line : String,
run_id : String,
) -> Bool {
let tokens : Array[String] = []
for token in line.split(" ") {
let token = token.trim().to_owned()
if !token.is_blank() {
tokens.push(token)
}
}
if tokens.length() < 4 {
return false
}
for index in 1..<(tokens.length() - 2) {
if tokens[index - 1] == "--" &&
tokens[index] == "proposal" &&
tokens[index + 1] == "run" &&
tokens[index + 2] == run_id {
return true
}
}
false
}