Add file badges, menu icons, LSP diagnostics, robust compaction
- Files in chat: preview with type/size badges and file name; attachment chips - Menu and settings tabs with icons - Heatmap: distinct colour for empty hours, hourly labels - Context chip shows used/total tokens (e.g. 221k/240k) plus percent - LSP client: diagnostics appended to edit/write results and a diagnostics tool (typescript-language-server, pyright, rust-analyzer, gopls, clangd; sandboxed) - Compaction summarizes a plain transcript and retries once on empty output - files/stat endpoint Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5b569b6835
commit
ec1b9b4925
22 files changed
+1036
-48
No files matched your search
@@ -2,6 +2,7 @@ import { memo, useState, type ReactNode } from "react";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import rehypeHighlight from "rehype-highlight";
|
||||
import { FileChip, FileFigure } from "./FileFigure";
|
||||
|
||||
export const IMAGE_EXT = /\.(png|jpe?g|gif|webp|bmp|svg)$/i;
|
||||
|
||||
@@ -31,7 +32,9 @@ export function SvgBlock({ code, children }: { code: string; children?: ReactNod
|
||||
const url = `data:image/svg+xml;base64,${btoa(unescape(encodeURIComponent(code)))}`;
|
||||
return (
|
||||
<div className="svg-block">
|
||||
<img src={url} alt="SVG" />
|
||||
<FileFigure name="inline.svg" size={new Blob([code]).size} mime="image/svg+xml">
|
||||
<img src={url} alt="SVG" />
|
||||
</FileFigure>
|
||||
<button className="small ghost" onClick={() => setShowCode(!showCode)}>
|
||||
{showCode ? "▾ SVG" : "▸ SVG"}
|
||||
</button>
|
||||
@@ -53,13 +56,14 @@ export const Markdown = memo(function Markdown({ text, baseDir }: { text: string
|
||||
if (!url) return <span>{alt}</span>;
|
||||
// Non-image files (3D models, documents) become links.
|
||||
if (typeof src === "string" && !/^(data:|https?:)/i.test(src) && !IMAGE_EXT.test(src)) {
|
||||
return (
|
||||
<a href={url} target="_blank" rel="noreferrer">
|
||||
📎 {alt || src}
|
||||
</a>
|
||||
);
|
||||
return <FileChip url={url} name={src} />;
|
||||
}
|
||||
return <img className="inline-image" src={url} alt={alt ?? ""} loading="lazy" />;
|
||||
const name = typeof src === "string" && !src.startsWith("data:") ? decodeURIComponent(src.split("?")[0]) : alt || undefined;
|
||||
return (
|
||||
<FileFigure url={url} name={name} mime={typeof src === "string" ? src.match(/^data:([^;,]+)/)?.[1] : undefined}>
|
||||
<img className="inline-image" src={url} alt={alt ?? ""} loading="lazy" />
|
||||
</FileFigure>
|
||||
);
|
||||
},
|
||||
pre: ({ children }) => {
|
||||
const code = textOf(children);
|
||||
@@ -105,9 +109,9 @@ export function ImageRefs({ text, baseDir }: { text: string; baseDir?: string })
|
||||
{paths.map((p) => {
|
||||
const url = projectFileUrl(p, baseDir)!;
|
||||
return (
|
||||
<a key={p} href={url} target="_blank" rel="noreferrer" title={p}>
|
||||
<img src={url} alt={p} loading="lazy" onError={(e) => ((e.currentTarget.parentElement as HTMLElement).style.display = "none")} />
|
||||
</a>
|
||||
<FileFigure key={p} url={url} name={p} className="thumb">
|
||||
<img src={url} alt={p} loading="lazy" onError={(e) => ((e.currentTarget.closest("figure") as HTMLElement).style.display = "none")} />
|
||||
</FileFigure>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user