mirror of
https://github.com/backnotprop/plannotator.git
synced 2026-09-14 14:17:26 +08:00
2a5528693f
* Add Ask AI to plan and annotate reviews - mount shared AI runtime on plan, annotate, review, and Pi servers - add shared document chat UI and comment-popover Ask AI entry point - default providers from detected agent origin and document first-run announcement - reuse shared code-review AI hook and document setup/docs * Address Ask AI review followups Stabilize AI chat session resets and callbacks, preserve per-origin provider defaults, share AI chat formatting utilities, and avoid blocking startup on model discovery. * Fix AI permission details and Pi CLI lookup Show formatted tool input in document AI permission cards and make Pi AI provider CLI detection work on Windows. * Fix Pi model discovery in AI capabilities Keep AI runtime startup non-blocking while making the capabilities endpoint await pending Pi/OpenCode model discovery before returning provider metadata.
34 lines
1.1 KiB
TypeScript
34 lines
1.1 KiB
TypeScript
import { createElement, type ReactNode } from 'react';
|
|
import { marked } from 'marked';
|
|
import DOMPurify from 'dompurify';
|
|
|
|
export function renderChatMarkdown(text: string): ReactNode {
|
|
const html = marked.parse(text, { async: false, breaks: true }) as string;
|
|
const clean = DOMPurify.sanitize(html, {
|
|
ALLOWED_TAGS: [
|
|
'p', 'br', 'strong', 'em', 'code', 'pre', 'ul', 'ol', 'li',
|
|
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'a', 'blockquote',
|
|
],
|
|
ALLOWED_ATTR: ['href', 'rel', 'class'],
|
|
});
|
|
|
|
return createElement('div', {
|
|
className: 'ai-markdown',
|
|
dangerouslySetInnerHTML: { __html: clean },
|
|
});
|
|
}
|
|
|
|
export function formatRelativeTime(ts: number): string {
|
|
const seconds = Math.max(0, Math.floor((Date.now() - ts) / 1000));
|
|
const minutes = Math.floor(seconds / 60);
|
|
const hours = Math.floor(minutes / 60);
|
|
const days = Math.floor(hours / 24);
|
|
|
|
if (seconds < 60) return 'now';
|
|
if (minutes < 60) return `${minutes}m`;
|
|
if (hours < 24) return `${hours}h`;
|
|
if (days < 7) return `${days}d`;
|
|
|
|
return new Date(ts).toLocaleDateString(undefined, { month: 'short', day: 'numeric' });
|
|
}
|