authorgravatar for 132888838+arhxam@users.noreply.github.comArham Amin <132888838+arhxam@users.noreply.github.com> 2026-08-04 18:49:12+05:30
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-08-04 09:19:12-04:00
log82b76e2138db7fcf8f8c1613184dc94777b2196e
tree0a1f0de10efb0acb0fb79a9fa538ba5537382f47
parent8a16cadbafb2ec98f79e7cb1300a3ad09ca394e5
signature Signed by PGP key B5690EEEBB952194

fix(server): use a Cursor todo's title when its content is blank (#5073)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

2 files changed, 23 insertions(+), 1 deletions(-)

apps/server/src/provider/acp/CursorAcpExtension.test.ts+19
...@@ -107,6 +107,25 @@ describe("CursorAcpExtension", () => {...@@ -107,6 +107,25 @@ describe("CursorAcpExtension", () => {
107 });107 });
108 });108 });
109109
110 it("falls back to the title when content is present but blank", () => {
111 expect(
112 extractTodosAsPlan({
113 toolCallId: "todos-2",
114 todos: [
115 { id: "1", content: "", title: "Titled step", status: "pending" },
116 { id: "2", content: " ", title: "Whitespace content", status: "in_progress" },
117 { id: "3", content: "", title: "", status: "pending" },
118 ],
119 merge: true,
120 }),
121 ).toEqual({
122 plan: [
123 { step: "Titled step", status: "pending" },
124 { step: "Whitespace content", status: "inProgress" },
125 ],
126 });
127 });
128
110 it("decodes Cursor list_available_models responses with per-model config options", () => {129 it("decodes Cursor list_available_models responses with per-model config options", () => {
111 const decoded = CursorListAvailableModelsResponse.make({130 const decoded = CursorListAvailableModelsResponse.make({
112 models: [131 models: [
apps/server/src/provider/acp/CursorAcpExtension.ts+4-1
...@@ -94,7 +94,10 @@ export function extractTodosAsPlan(params: typeof CursorUpdateTodosRequest.Type)...@@ -94,7 +94,10 @@ export function extractTodosAsPlan(params: typeof CursorUpdateTodosRequest.Type)
94 }>;94 }>;
95} {95} {
96 const plan = params.todos.flatMap((todo) => {96 const plan = params.todos.flatMap((todo) => {
97 const step = todo.content?.trim() ?? todo.title?.trim() ?? "";97 // Fall back to the title when content is missing OR blank. `??` only
98 // covers a missing content, so a present-but-empty content ("" or
99 // whitespace) would shadow a real title and drop the step below.
100 const step = todo.content?.trim() || todo.title?.trim() || "";
98 if (step === "") {101 if (step === "") {
99 return [];102 return [];
100 }103 }