diff --git a/src/inbox-item-persistence.ts b/src/inbox-item-persistence.ts index 44b2f87..bd65e47 100644 --- a/src/inbox-item-persistence.ts +++ b/src/inbox-item-persistence.ts @@ -21,6 +21,14 @@ const ACTIONS_REQUIRING_SPHERES: readonly string[] = [ "someday-file", ]; +function flattenToSingleLine(text: string): string { + return text + .split(/\r?\n/) + .map((line) => line.trim()) + .filter((line) => line.length > 0) + .join(" "); +} + export class InboxItemPersistenceService { constructor( private readonly writer: FileWriter, @@ -59,7 +67,9 @@ export class InboxItemPersistenceService { finalNextActions = [item.original]; } - return finalNextActions; + // Each next action must occupy a single line in the destination file, so + // collapse any multi-line content (e.g. a captured note used as the action). + return finalNextActions.map(flattenToSingleLine); } private validateFinalNextActions(item: EditableItem, finalNextActions: string[]): void { diff --git a/tests/inbox-item-persistence.test.ts b/tests/inbox-item-persistence.test.ts index bd4fe47..56a37fd 100644 --- a/tests/inbox-item-persistence.test.ts +++ b/tests/inbox-item-persistence.test.ts @@ -115,6 +115,22 @@ describe("InboxItemPersistenceService", () => { expect(writerMocks.addToNextActionsFile).not.toHaveBeenCalled(); }); + it("flattens multi-line note content into a single-line next action", async () => { + const item: EditableItem = { + original: "Call dentist\nabout the crown that fell out", + isAIProcessed: false, + selectedAction: "next-actions-file", + selectedSpheres: ["personal"], + sourceNoteLink: "[[Captured note|source]]", + }; + + await service.persist(item); + + expect(writerMocks.addToNextActionsFile).toHaveBeenCalledTimes(1); + const actionsArg = writerMocks.addToNextActionsFile.mock.calls[0][0]; + expect(actionsArg).toEqual(["Call dentist about the crown that fell out"]); + }); + it("skips persistence work for trash items", async () => { const item: EditableItem = { original: "Duplicate",