mirror of
https://github.com/anomalyco/opencode.git
synced 2026-02-09 10:24:11 +00:00
Compare commits
1 Commits
sqlite2
...
fix-markdo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8aa7e65dc8 |
@@ -14,7 +14,9 @@ export namespace ConfigMarkdown {
|
||||
return Array.from(template.matchAll(SHELL_REGEX))
|
||||
}
|
||||
|
||||
export function preprocessFrontmatter(content: string): string {
|
||||
// other coding agents like claude code allow invalid yaml in their
|
||||
// frontmatter, we need to fallback to a more permissive parser for those cases
|
||||
export function fallbackSanitization(content: string): string {
|
||||
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/)
|
||||
if (!match) return content
|
||||
|
||||
@@ -53,7 +55,7 @@ export namespace ConfigMarkdown {
|
||||
|
||||
// if value contains a colon, convert to block scalar
|
||||
if (value.includes(":")) {
|
||||
result.push(`${key}: |`)
|
||||
result.push(`${key}: |-`)
|
||||
result.push(` ${value}`)
|
||||
continue
|
||||
}
|
||||
@@ -66,20 +68,23 @@ export namespace ConfigMarkdown {
|
||||
}
|
||||
|
||||
export async function parse(filePath: string) {
|
||||
const raw = await Bun.file(filePath).text()
|
||||
const template = preprocessFrontmatter(raw)
|
||||
const template = await Bun.file(filePath).text()
|
||||
|
||||
try {
|
||||
const md = matter(template)
|
||||
return md
|
||||
} catch (err) {
|
||||
throw new FrontmatterError(
|
||||
{
|
||||
path: filePath,
|
||||
message: `${filePath}: Failed to parse YAML frontmatter: ${err instanceof Error ? err.message : String(err)}`,
|
||||
},
|
||||
{ cause: err },
|
||||
)
|
||||
} catch {
|
||||
try {
|
||||
return matter(fallbackSanitization(template))
|
||||
} catch (err) {
|
||||
throw new FrontmatterError(
|
||||
{
|
||||
path: filePath,
|
||||
message: `${filePath}: Failed to parse YAML frontmatter: ${err instanceof Error ? err.message : String(err)}`,
|
||||
},
|
||||
{ cause: err },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
11
packages/opencode/test/config/fixtures/markdown-header.md
Normal file
11
packages/opencode/test/config/fixtures/markdown-header.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# Response Formatting Requirements
|
||||
|
||||
Always structure your responses using clear markdown formatting:
|
||||
|
||||
- By default don't put information into tables for questions (but do put information into tables when creating or updating files)
|
||||
- Use headings (##, ###) to organise sections, always
|
||||
- Use bullet points or numbered lists for multiple items
|
||||
- Use code blocks with language tags for any code
|
||||
- Use **bold** for key terms and emphasis
|
||||
- Use tables when comparing options or listing structured data
|
||||
- Break long responses into logical sections with headings
|
||||
13
packages/opencode/test/config/fixtures/weird-model-id.md
Normal file
13
packages/opencode/test/config/fixtures/weird-model-id.md
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
description: General coding and planning agent
|
||||
mode: subagent
|
||||
model: synthetic/hf:zai-org/GLM-4.7
|
||||
tools:
|
||||
write: true
|
||||
read: true
|
||||
edit: true
|
||||
stuff: >
|
||||
This is some stuff
|
||||
---
|
||||
|
||||
Strictly follow da rules
|
||||
@@ -104,7 +104,7 @@ describe("ConfigMarkdown: frontmatter parsing", async () => {
|
||||
})
|
||||
|
||||
test("should extract occupation field with colon in value", () => {
|
||||
expect(parsed.data.occupation).toBe("This man has the following occupation: Software Engineer\n")
|
||||
expect(parsed.data.occupation).toBe("This man has the following occupation: Software Engineer")
|
||||
})
|
||||
|
||||
test("should extract title field with single quotes", () => {
|
||||
@@ -128,15 +128,15 @@ describe("ConfigMarkdown: frontmatter parsing", async () => {
|
||||
})
|
||||
|
||||
test("should extract URL with port", () => {
|
||||
expect(parsed.data.url).toBe("https://example.com:8080/path?query=value\n")
|
||||
expect(parsed.data.url).toBe("https://example.com:8080/path?query=value")
|
||||
})
|
||||
|
||||
test("should extract time with colons", () => {
|
||||
expect(parsed.data.time).toBe("The time is 12:30:00 PM\n")
|
||||
expect(parsed.data.time).toBe("The time is 12:30:00 PM")
|
||||
})
|
||||
|
||||
test("should extract value with multiple colons", () => {
|
||||
expect(parsed.data.nested).toBe("First: Second: Third: Fourth\n")
|
||||
expect(parsed.data.nested).toBe("First: Second: Third: Fourth")
|
||||
})
|
||||
|
||||
test("should preserve already double-quoted values with colons", () => {
|
||||
@@ -148,7 +148,7 @@ describe("ConfigMarkdown: frontmatter parsing", async () => {
|
||||
})
|
||||
|
||||
test("should extract value with quotes and colons mixed", () => {
|
||||
expect(parsed.data.mixed).toBe('He said "hello: world" and then left\n')
|
||||
expect(parsed.data.mixed).toBe('He said "hello: world" and then left')
|
||||
})
|
||||
|
||||
test("should handle empty values", () => {
|
||||
@@ -190,3 +190,39 @@ describe("ConfigMarkdown: frontmatter parsing w/ no frontmatter", async () => {
|
||||
expect(result.content.trim()).toBe("Content")
|
||||
})
|
||||
})
|
||||
|
||||
describe("ConfigMarkdown: frontmatter parsing w/ Markdown header", async () => {
|
||||
const result = await ConfigMarkdown.parse(import.meta.dir + "/fixtures/markdown-header.md")
|
||||
|
||||
test("should parse and match", () => {
|
||||
expect(result).toBeDefined()
|
||||
expect(result.data).toEqual({})
|
||||
expect(result.content.trim()).toBe(`# Response Formatting Requirements
|
||||
|
||||
Always structure your responses using clear markdown formatting:
|
||||
|
||||
- By default don't put information into tables for questions (but do put information into tables when creating or updating files)
|
||||
- Use headings (##, ###) to organise sections, always
|
||||
- Use bullet points or numbered lists for multiple items
|
||||
- Use code blocks with language tags for any code
|
||||
- Use **bold** for key terms and emphasis
|
||||
- Use tables when comparing options or listing structured data
|
||||
- Break long responses into logical sections with headings`)
|
||||
})
|
||||
})
|
||||
|
||||
describe("ConfigMarkdown: frontmatter has weird model id", async () => {
|
||||
const result = await ConfigMarkdown.parse(import.meta.dir + "/fixtures/weird-model-id.md")
|
||||
|
||||
test("should parse and match", () => {
|
||||
expect(result).toBeDefined()
|
||||
expect(result.data["description"]).toEqual("General coding and planning agent")
|
||||
expect(result.data["mode"]).toEqual("subagent")
|
||||
expect(result.data["model"]).toEqual("synthetic/hf:zai-org/GLM-4.7")
|
||||
expect(result.data["tools"]["write"]).toBeTrue()
|
||||
expect(result.data["tools"]["read"]).toBeTrue()
|
||||
expect(result.data["stuff"]).toBe("This is some stuff\n")
|
||||
|
||||
expect(result.content.trim()).toBe("Strictly follow da rules")
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user