Add hooks, @file mentions, session search/fork/export, follow-scroll

- Hooks ([[hooks]]): pre_tool, post_tool, user_prompt, stop; sandboxed, exit 2 blocks
- @file mentions with autocomplete; mentioned files/folders are attached to the prompt
- Session full-text search in the sidebar, fork into a copy, export as Markdown/JSON
- Chat follows the newest message until the user scrolls up; jump-to-latest button
- SVG activity spark and thinking icon instead of Unicode/emoji glyphs
- File search ranks name matches first and returns relative paths

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard ZinkandClaude Opus 5.5 committed 2026-11-08 20:17:12 +01:00
1 parent ec1b9b4925
commit 013695722a
17 files changed
+911 -41

No files matched your search

+30 -9
View File
@@ -19,16 +19,37 @@ export function Spinner({ small }: { small?: boolean }) {
return <span className={`spinner ${small ? "small" : ""}`} aria-hidden="true" />;
}
const STARS = ["·", "✢", "✳", "✶", "✻", "✽", "✻", "✶", "✳", "✢"];
/** Animated spark (SVG, looks the same on every system): rays light up in turn while it turns. */
export function Star() {
const rays = Array.from({ length: 8 }, (_, i) => i);
return (
<svg className="star" viewBox="-12 -12 24 24" aria-hidden="true">
<g className="star-spin">
{rays.map((i) => (
<line
key={i}
x1="0"
y1="-4"
x2="0"
y2={i % 2 ? "-8.5" : "-10.5"}
transform={`rotate(${i * 45})`}
style={{ animationDelay: `${(i * 0.9) / 8 - 0.9}s` }}
/>
))}
</g>
</svg>
);
}
/** Rotating star like a terminal agent's spinner. */
function Star() {
const [i, setI] = useState(0);
useEffect(() => {
const h = setInterval(() => setI((x) => (x + 1) % STARS.length), 120);
return () => clearInterval(h);
}, []);
return <span className="star" aria-hidden="true">{STARS[i]}</span>;
/** Thought bubble icon for model reasoning (SVG instead of an emoji). */
export function ThinkIcon() {
return (
<svg className="think-icon" viewBox="0 0 24 24" aria-hidden="true">
<path d="M7 15.5a4.5 4.5 0 0 1-.6-8.96A5.5 5.5 0 0 1 16.6 5.2 4.25 4.25 0 0 1 18 13.5a4 4 0 0 1-4 2Z" />
<circle cx="7.5" cy="19" r="1.6" />
<circle cx="4" cy="21.6" r="1" />
</svg>
);
}
function useNow(active: boolean) {