Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions apps/web/lib/plugin-document.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { describe, expect, it } from "bun:test"
import { parsePluginDocument } from "./plugin-document"

type PluginDocumentInput = Parameters<typeof parsePluginDocument>[0]

function makeCodexSessionDocument(content: string): PluginDocumentInput {
return {
id: "doc_1",
title: "Codex session",
content,
metadata: { sm_source: "codex" },
memoryEntries: [],
} as unknown as PluginDocumentInput
Comment on lines +7 to +13

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The object literal returned from makeCodexSessionDocument uses a type assertion (as unknown as PluginDocumentInput) instead of a type annotation. According to the 'Use type annotations instead of assertions for object literals' rule, you should annotate the return type of the function or the variable directly rather than casting. For example, annotate the function's return type: function makeCodexSessionDocument(content: string): PluginDocumentInput { return { ... }; } and remove the as unknown as PluginDocumentInput assertion.

Spotted by Graphite (based on custom rule: TypeScript style guide (Google))

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

}

describe("parsePluginDocument — session transcripts", () => {
it("keeps multi-line message bodies intact", () => {
const parsed = parsePluginDocument(
makeCodexSessionDocument(
[
"[Session abc-123]",
"1. [user] Hello there",
"Here is more context on line two",
"2. [assistant] Sure!",
"Second line of the reply",
].join("\n"),
),
)

expect(parsed).not.toBeNull()
expect(parsed?.kind).toBe("codex-session")
expect(parsed?.messages).toHaveLength(2)
expect(parsed?.messages[0]?.text).toBe(
"Hello there\nHere is more context on line two",
)
expect(parsed?.messages[1]?.text).toBe("Sure!\nSecond line of the reply")
})

it("surfaces memory id artifacts from continuation lines", () => {
const parsed = parsePluginDocument(
makeCodexSessionDocument(
[
"[Session abc-123]",
"1. [user] Remember my editor is Neovim",
"memory id: mem_456",
"2. [assistant] Saved it.",
].join("\n"),
),
)

expect(parsed?.messages[0]?.text).toBe("Remember my editor is Neovim")
expect(parsed?.artifacts).toContainEqual({
label: "Memory ID",
value: "mem_456",
})
})

it("normalizes literal \\n escapes before splitting messages", () => {
const parsed = parsePluginDocument(
makeCodexSessionDocument(
"[Session abc-123]\\n1. [user] First line\\nSecond line\\n2. [assistant] Reply",
),
)

expect(parsed?.messages).toHaveLength(2)
expect(parsed?.messages[0]?.text).toBe("First line\nSecond line")
expect(parsed?.messages[1]?.text).toBe("Reply")
})

it("parses single-line messages as before", () => {
const parsed = parsePluginDocument(
makeCodexSessionDocument(
["[Session abc-123]", "1. [user] Hi", "2. [assistant] Hello!"].join(
"\n",
),
),
)

expect(parsed?.messages).toHaveLength(2)
expect(parsed?.messages[0]?.text).toBe("Hi")
expect(parsed?.messages[1]?.text).toBe("Hello!")
expect(parsed?.summary).toBe(
"1 user message and 1 assistant message captured from Codex.",
)
})
})
5 changes: 4 additions & 1 deletion apps/web/lib/plugin-document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,11 @@ function parseTranscriptMessages(content: string): {
} {
const messages: PluginDocumentMessage[] = []
const artifacts: PluginArtifact[] = []
// The lookahead must end the last message at the true end of input:
// with the m flag, a bare $ matches every line end and would cut each
// message body off at its first newline.
const regex = new RegExp(
`^\\s*(\\d+)\\.\\s+\\[(${TRANSCRIPT_ROLE_PATTERN})\\]\\s*([\\s\\S]*?)(?=^\\s*\\d+\\.\\s+\\[(?:${TRANSCRIPT_ROLE_PATTERN})\\]\\s*|$)`,
`^\\s*(\\d+)\\.\\s+\\[(${TRANSCRIPT_ROLE_PATTERN})\\]\\s*([\\s\\S]*?)(?=^\\s*\\d+\\.\\s+\\[(?:${TRANSCRIPT_ROLE_PATTERN})\\]\\s*|(?![\\s\\S]))`,
"gm",
)

Expand Down