fix(desktop): parse codex ACP plan entries[] into checklist (#1824)

Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Co-authored-by: npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@sprout-oss.stage.blox.sqprod.co>
This commit is contained in:
Will Pfleger
2026-07-13 16:59:20 -04:00
committed by GitHub
parent 020ac7f405
commit 34dcd13d55
3 changed files with 108 additions and 1 deletions

View File

@@ -295,6 +295,36 @@ export function extractBlockText(value: unknown): string {
return directText || nestedText || rawOutputText || "";
}
/**
* Build markdown checklist text for a `plan` session update.
*
* The standard ACP shape (`@agentclientprotocol/codex-acp`) sends
* `entries[]` — `{ status, content, priority }` — with no top-level
* `content` field. Older/non-standard adapters instead send
* `content: { type: "text", text }` directly on the update. `entries`
* (even empty) is treated as authoritative when present; `content` is
* only consulted when `entries` is absent, and the raw update is
* stringified only when neither yields usable text.
*/
export function extractPlanText(update: Record<string, unknown>): string {
if (Array.isArray(update.entries)) {
return update.entries
.map((entry) => formatPlanEntry(asRecord(entry)))
.filter(Boolean)
.join("\n");
}
const contentText = extractContentText(update.content);
return contentText || JSON.stringify(update, null, 2);
}
function formatPlanEntry(entry: Record<string, unknown>): string {
const content = asString(entry.content);
if (!content) return "";
const checkbox = entry.status === "completed" ? "[x]" : "[ ]";
const suffix = entry.status === "in_progress" ? " (in progress)" : "";
return `- ${checkbox} ${content}${suffix}`;
}
export function extractToolArgs(
update: Record<string, unknown>,
): Record<string, unknown> {