Add security hardening, Ghidra, recreate skill, checkpoints, shells, web search and themes

- Sandbox (bubblewrap) for non-admin shell/git, MCP per-user rights, hard budgets and quotas,
  login rate limiting, audit log and backups
- Ghidra headless decompilation (ARM64 natives built from source), binary_info tool,
  clean room / deep workflow per session
- Recreate skill and commands for analysing and re-building old software
- File checkpoints with rewind/restore, background shells (bash_output, kill_shell)
- web_search tool (DuckDuckGo, SearXNG, Brave, Tavily)
- In-app dialogs and toasts instead of browser dialogs
- 15 base themes (trilium-themes palettes plus Nord, VS Code, GitHub, Catppuccin, One,
  Dracula, Rose Pine, Everforest, Kanagawa) with light/dark/auto switcher and license notes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard ZinkandClaude Opus 5.5 committed 2026-11-08 19:12:30 +01:00
1 parent fab9add5d5
commit 5b569b6835
108 files changed
+6785 -279

No files matched your search

+22 -1
View File
@@ -4,6 +4,7 @@ import { useStore } from "../store";
import type { Part, Todo } from "../types";
import { Spinner } from "./Activity";
import { Diff } from "./Diff";
import { IMAGE_EXT, projectFileUrl } from "./Markdown";
type ToolCall = Extract<Part, { type: "tool_call" }>;
type ToolResult = Extract<Part, { type: "tool_result" }>;
@@ -57,7 +58,7 @@ export function TodoList({ todos }: { todos: Todo[] }) {
);
}
export function ToolCard({ call, result, running }: { call: ToolCall; result?: ToolResult; running: boolean }) {
export function ToolCard({ call, result, running, baseDir }: { call: ToolCall; result?: ToolResult; running: boolean; baseDir?: string }) {
const t = useT();
const progress = useStore((s) => s.progress[call.id]);
const status = result ? (result.is_error ? "err" : "ok") : running ? "run" : "err";
@@ -77,6 +78,26 @@ export function ToolCard({ call, result, running }: { call: ToolCall; result?: T
);
}
// Image files written by the agent are shown as images (SVG too, rendered via <img>).
const writtenImage =
(call.name === "write" || call.name === "edit") && typeof call.input?.path === "string" && IMAGE_EXT.test(call.input.path) && result && !result.is_error
? projectFileUrl(call.input.path, baseDir)
: undefined;
if (writtenImage) {
return (
<div className="tool image-result">
<div className="tool-head">
<span className="tool-name">{call.name}</span>
<span className="tool-title">{call.input.path}</span>
<span className="status ok">✓</span>
</div>
<a href={writtenImage} target="_blank" rel="noreferrer">
<img src={`${writtenImage}&v=${result!.call_id}`} alt={call.input.path} />
</a>
</div>
);
}
// Short diffs are shown right away, like in a terminal agent.
const diffLines = typeof meta?.diff === "string" ? meta.diff.split("\n").length : 0;
const openByDefault =