import { hasAllCriteriaPass, isFinalRunCompletionCandidate } from "./goal-status.js";
import { createGoalsAction } from "./plan-missing-recovery.js";
import type { UlwLoopToolkitSurface } from "./surface.js";
import type { UlwLoopItem, UlwLoopPlan } from "./types.js";
/**
* Status is the one call every agent already makes between steps, so it is
* also the cheapest place to answer "what now?" without a second round trip.
*/
export function statusNextActions(plan: UlwLoopPlan, surface: UlwLoopToolkitSurface = "lazycodex"): readonly string[] {
const actions: string[] = [];
const active = plan.goals.find((goal) => goal.id === plan.activeGoalId);
if (plan.goals.length === 0) actions.push(`No goals yet: bootstrap with \`${createGoalsAction(surface)}\`.`);
else if (active !== undefined) actions.push(...activeGoalActions(plan, active, surface));
for (const goal of plan.goals.filter((candidate) => candidate.status === "review_blocked"))
actions.push(
surface === "omo-senpi"
? `${goal.id} is review_blocked: capture the reviewer verdict with \`agentToolkit.recordReviewBlockers({ goalId: "${goal.id}", title: "
", objective: "", evidence: "" })\`.`
: `${goal.id} is review_blocked: capture the reviewer verdict with \`omo-agent-toolkit ulw-loop record-review-blockers --goal-id ${goal.id} --title "" --objective "" --evidence "" --codex-goal-json ''\`.`,
);
if (plan.evidenceLayoutVersion !== 2 || active === undefined)
actions.push("plan is evidence-layout v1; artifacts go under .omo/evidence/");
return actions;
}
function activeGoalActions(plan: UlwLoopPlan, active: UlwLoopItem, surface: UlwLoopToolkitSurface): readonly string[] {
const unresolved = active.successCriteria.filter((criterion) => criterion.status !== "pass");
if (unresolved.length > 0)
return [
surface === "omo-senpi"
? `${active.id} has ${unresolved.length} unresolved criterion(s) (${unresolved.map((criterion) => criterion.id).join(", ")}): record proof with \`agentToolkit.recordEvidence({ goalId: "${active.id}", criterionId: "", status: "pass", evidence: "" })\`.`
: `${active.id} has ${unresolved.length} unresolved criterion(s) (${unresolved.map((criterion) => criterion.id).join(", ")}): record proof with \`omo-agent-toolkit ulw-loop record-evidence --goal-id ${active.id} --criterion-id --status pass --evidence ""\`.`,
];
if (hasAllCriteriaPass(active) && isFinalRunCompletionCandidate(plan, active))
return [
surface === "omo-senpi"
? `${active.id} passes every criterion and is the final story: complete the driver goal, then call \`agentToolkit.checkpoint({ goalId: "${active.id}", printTemplate: true })\` to build the final quality gate. Use status().result.currentAttemptDir for all quality-gate artifacts.`
: `${active.id} passes every criterion and is the final story: update_goal complete, then checkpoint --print-template to build the final quality gate. Use status --json's currentAttemptDir for all quality-gate artifacts.`,
];
return [
surface === "omo-senpi"
? `${active.id} passes every criterion: close it with \`agentToolkit.checkpoint({ goalId: "${active.id}", status: "complete", evidence: "" })\`. Put quality-gate artifacts under status().result.currentAttemptDir.`
: `${active.id} passes every criterion: close it with \`omo-agent-toolkit ulw-loop checkpoint --goal-id ${active.id} --status complete --evidence "" --codex-goal-json ''\`. Put quality-gate artifacts under the currentAttemptDir shown by status --json.`,
];
}