diff --git a/.pi/commands/review.md b/.pi/commands/review.md deleted file mode 100644 index 3e1db779..00000000 --- a/.pi/commands/review.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -description: Review a file for issues ---- -Please review the following file for potential issues, bugs, or improvements: - -$1 - -Focus on: -- Logic errors -- Edge cases -- Code style -- Performance concerns diff --git a/.pi/hooks/test-command.ts b/.pi/hooks/test-command.ts deleted file mode 100644 index 7f737498..00000000 --- a/.pi/hooks/test-command.ts +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Test hook demonstrating custom commands, message rendering, and before_agent_start. - */ -import type { BeforeAgentStartEvent, HookAPI } from "@mariozechner/pi-coding-agent"; -import { Box, Spacer, Text } from "@mariozechner/pi-tui"; - -export default function (pi: HookAPI) { - // Track whether injection is enabled - let injectEnabled = false; - - // Register a custom message renderer for our "test-info" type - pi.registerMessageRenderer("test-info", (message, options, theme) => { - const box = new Box(1, 1, (t) => theme.bg("customMessageBg", t)); - - const label = theme.fg("success", "[TEST INFO]"); - box.addChild(new Text(label, 0, 0)); - box.addChild(new Spacer(1)); - - const content = - typeof message.content === "string" - ? message.content - : message.content.map((c) => (c.type === "text" ? c.text : "[image]")).join(""); - - box.addChild(new Text(theme.fg("text", content), 0, 0)); - - if (options.expanded && message.details) { - box.addChild(new Spacer(1)); - box.addChild(new Text(theme.fg("dim", `Details: ${JSON.stringify(message.details)}`), 0, 0)); - } - - return box; - }); - - // Register /test-msg command - pi.registerCommand("test-msg", { - description: "Send a test custom message", - handler: async () => { - pi.sendMessage( - { - customType: "test-info", - content: "This is a test message with custom rendering!", - display: true, - details: { timestamp: Date.now(), source: "test-command hook" }, - }, - true, // triggerTurn: start agent run - ); - }, - }); - - // Register /test-hidden command - pi.registerCommand("test-hidden", { - description: "Send a hidden message (display: false)", - handler: async (ctx) => { - pi.sendMessage({ - customType: "test-info", - content: "This message is in context but not displayed", - display: false, - }); - ctx.ui.notify("Sent hidden message (check session file)"); - }, - }); - - // Register /test-inject command to toggle before_agent_start injection - pi.registerCommand("test-inject", { - description: "Toggle context injection before agent starts", - handler: async (ctx) => { - injectEnabled = !injectEnabled; - ctx.ui.notify(`Context injection ${injectEnabled ? "enabled" : "disabled"}`); - }, - }); - - // Demonstrate before_agent_start: inject context when enabled - pi.on("before_agent_start", async (event: BeforeAgentStartEvent) => { - if (!injectEnabled) return; - - // Return a message to inject before the user's prompt - return { - message: { - customType: "test-info", - content: `[Injected context for prompt: "${event.prompt.slice(0, 50)}..."]`, - display: true, - details: { injectedAt: Date.now() }, - }, - }; - }); -} diff --git a/packages/coding-agent/src/core/export-html/template.js b/packages/coding-agent/src/core/export-html/template.js index 33c5edb5..b6137a9b 100644 --- a/packages/coding-agent/src/core/export-html/template.js +++ b/packages/coding-agent/src/core/export-html/template.js @@ -1050,19 +1050,17 @@ // INITIALIZATION // ============================================================ - // Wrapper for marked that escapes HTML before parsing - // Escapes all < that look like tag starts (followed by letter or /) - // Code blocks are safe because marked processes them before our escaping affects display - function safeMarkedParse(text) { - const escaped = text.replace(/<(?=[a-zA-Z\/])/g, '<'); - return marked.parse(escaped); + // Escape HTML tags in text (but not code blocks) + function escapeHtmlTags(text) { + return text.replace(/<(?=[a-zA-Z\/])/g, '<'); } - // Configure marked with syntax highlighting + // Configure marked with syntax highlighting and HTML escaping for text marked.use({ breaks: true, gfm: true, renderer: { + // Code blocks: syntax highlight, no HTML escaping code(token) { const code = token.text; const lang = token.lang; @@ -1082,10 +1080,23 @@ } } return `
${highlighted}
`; + }, + // Text content: escape HTML tags + text(token) { + return escapeHtmlTags(escapeHtml(token.text)); + }, + // Inline code: escape HTML + codespan(token) { + return `${escapeHtml(token.text)}`; } } }); + // Simple marked parse (escaping handled in renderers) + function safeMarkedParse(text) { + return marked.parse(text); + } + // Search input const searchInput = document.getElementById('tree-search'); searchInput.addEventListener('input', (e) => {