45 lines
2.2 KiB
TypeScript
45 lines
2.2 KiB
TypeScript
import type { GoalState } from "./state.ts";
|
|
|
|
export type GoalDisplay = {
|
|
label: "Active" | "Waiting" | "Paused" | "Blocked" | "Complete" | "None";
|
|
color: "accent" | "warning" | "error" | "success" | "muted";
|
|
};
|
|
|
|
export function goalDisplay(state: GoalState): GoalDisplay {
|
|
if (state.status === "none") return state.lastOutcome
|
|
? { label: "Complete", color: "success" }
|
|
: { label: "None", color: "muted" };
|
|
if (state.status === "blocked" ||
|
|
(state.status === "paused" && state.pausedReason?.startsWith("blocked:"))) {
|
|
return { label: "Blocked", color: "error" };
|
|
}
|
|
if (state.status === "paused") return { label: "Paused", color: "warning" };
|
|
if (state.activeWait && !state.activeWait.wakeSent) return { label: "Waiting", color: "warning" };
|
|
return { label: "Active", color: "accent" };
|
|
}
|
|
|
|
/** Full recall is deliberately separate from short transient notifications. */
|
|
export function goalDetails(state: GoalState): string {
|
|
const display = goalDisplay(state);
|
|
if (display.label === "None") return "Goal: None\nUse /goal <text> to set a goal.";
|
|
const completed = state.status === "none" ? state.lastOutcome : undefined;
|
|
const lines = [`Goal: ${display.label}`, "", completed?.text ?? state.text, ""];
|
|
if (completed) {
|
|
lines.push(`Completed: ${completed.at}`, `Evidence: ${completed.evidence}`);
|
|
} else {
|
|
if (state.pausedReason) lines.push(`Reason: ${state.pausedReason}`);
|
|
if (state.status === "active" && state.activeWait) {
|
|
lines.push(`Wait owner: ${state.activeWait.owner}`);
|
|
if (state.activeWait.nextCheck) lines.push(`Next check: ${state.activeWait.nextCheck}`);
|
|
if (state.activeWait.watchId) lines.push(`Watch: ${state.activeWait.watchId}`);
|
|
if (state.activeWait.deadlineAt !== undefined) {
|
|
const deadline = new Date(state.activeWait.deadlineAt);
|
|
lines.push(`Deadline: ${Number.isFinite(deadline.getTime()) ? deadline.toISOString() : "invalid"}`);
|
|
}
|
|
}
|
|
lines.push(`Checks: ${state.checks}/${state.maxChecks}`, `No-progress reports: ${state.noProgressReports}/${state.maxNoProgressReports}`);
|
|
}
|
|
lines.push("", "/goal stop | /goal resume | /goal clear");
|
|
return lines.join("\n");
|
|
}
|