(directory, client, sessionID)
| 1136 | job.paused = true |
| 1137 | job.goalCompletedAt = now() |
| 1138 | job.goalSummary = job.goalSummary || "All configured goal checks passed." |
| 1139 | job.goalEvidence = results.map((item) => `${item.command}: exit ${item.code}`).join("\n") |
| 1140 | await appendLoopLog(directory, "goal-auto-complete", { sessionID, job: job.name || job.id }) |
| 1141 | } |
| 1142 | } else { |
| 1143 | job.failureCount = (job.failureCount || 0) + 1 |
| 1144 | job.lastVerifyFailure = results.map((item) => `${item.command}\nexit=${item.code}\n${item.output}`).join("\n\n").slice(0, 4000) |
| 1145 | await toast(client, "Goal checks still failing; goal will continue on next idle turn.", "warning") |
| 1146 | } |
| 1147 | await appendLoopLog(directory, "goal-checks", { sessionID, job: job.name || job.id, results: results.map((item) => ({ command: item.command, code: item.code })) }) |
| 1148 | return job |
| 1149 | } |
| 1150 | |
| 1151 | async function finalizeActiveRun(directory, client, sessionID) { |
| 1152 | const active = activeRuns.get(sessionID) |
| 1153 | if (!active) return |
| 1154 | clearActiveRun(sessionID) |
| 1155 | const state = await readState(directory, sessionID) |
| 1156 | let job = (state.jobs || []).find((candidate) => candidate.id === active.jobId) |
| 1157 | if (!job) return |
| 1158 | job.lastFinishedAt = now() |
| 1159 | |
| 1160 | if (job.verifyCommand) { |
| 1161 | const verify = await runShellCommand(job.verifyCommand, directory, job.timeoutMs || 300_000) |
| 1162 | job.lastVerifyAt = now() |
| 1163 | job.lastVerifyCode = verify.code |
| 1164 | if (verify.code === 0) { |
| 1165 | job.failureCount = 0 |
| 1166 | job.lastVerifyFailure = "" |
| 1167 | await toast(client, "Loop verify passed: " + job.verifyCommand, "success") |
| 1168 | } else { |
| 1169 | job.failureCount = (job.failureCount || 0) + 1 |
| 1170 | job.lastVerifyFailure = (job.verifyCommand + "\nexit=" + verify.code + "\n" + verify.stdout + "\n" + verify.stderr).slice(0, 4000) |
| 1171 | await toast(client, "Loop verify failed: " + job.verifyCommand, "warning") |
| 1172 | if (job.pauseOnVerifyFail || (job.maxFailures > 0 && job.failureCount >= job.maxFailures)) { |
| 1173 | job.paused = true |
| 1174 | await notifyJob(directory, job, "verify_failed") |
| 1175 | } |
| 1176 | } |
| 1177 | await appendLoopLog(directory, "verify", { sessionID, job: job.name || job.id, command: job.verifyCommand, code: verify.code, failures: job.failureCount || 0 }) |
| 1178 | } |
| 1179 | |
| 1180 | if (job.postrunCommand) { |
| 1181 | if (job.safe && dangerousShell(job.postrunCommand)) await appendLoopLog(directory, "postrun-blocked", { sessionID, job: job.name || job.id, command: job.postrunCommand }) |
| 1182 | else { |
| 1183 | const postrun = await runShellCommand(job.postrunCommand, directory, job.timeoutMs || 300_000) |
| 1184 | job.lastPostrunCode = postrun.code |
| 1185 | job.lastPostrunAt = now() |
| 1186 | if (postrun.code !== 0) { |
| 1187 | job.failureCount = (job.failureCount || 0) + 1 |
| 1188 | job.lastPostrunFailure = (job.postrunCommand + "\nexit=" + postrun.code + "\n" + postrun.stdout + "\n" + postrun.stderr).slice(0, 4000) |
| 1189 | if (job.maxFailures > 0 && job.failureCount >= job.maxFailures) { |
| 1190 | job.paused = true |
| 1191 | await notifyJob(directory, job, "postrun_failed") |
| 1192 | } |
| 1193 | } |
| 1194 | await appendLoopLog(directory, "postrun", { sessionID, job: job.name || job.id, command: job.postrunCommand, code: postrun.code }) |
no test coverage detected