generated from nhcarrigan/template
feat: Claude CLI 2.1.50–2.1.53 audit (#171)
## Summary This PR covers the full audit of Claude CLI changes from 2.1.50 to 2.1.53, plus a batch of bug fixes, new features, and maintenance work identified during that review. ### New Features - **Workspace trust gate** — detects hooks, MCP servers, and custom commands in a workspace before connecting; persists trust decisions so users aren't prompted repeatedly - **Custom background image** — users can set a background image with configurable opacity; character panel and compact mode go transparent when active - **Draggable tab reordering** — conversation tabs can be reordered via pointer-event drag-and-drop (HTML5 drag is intercepted by Tauri/WebView2, so pointer events are used instead) - **Org UUID in account info** — exposes the org UUID from Claude auth status ### Bug Fixes - **Unread dot false positives** — initialise unread counts on mount to prevent all tabs showing the blue dot after toggling the file editor (Closes #164) - **Watchdog for hung WSL bridge** — detects connections that never receive `system:init` and kills the stale process after 1 minute (Closes #166) - **Suppress terminal window flash on Windows** — applies `CREATE_NO_WINDOW` to all subprocesses via a `HideWindow` trait extension (Closes #165) - **HTML escaping in markdown renderer** — escape `<` and `>` in `codespan` and `html` renderer callbacks to prevent raw HTML injection (Closes #169) ### Maintenance - Verify stream-JSON handles tool results above the 50K threshold correctly (Closes #162) - Reviewed hook security fixes from CLI 2.1.51 — not applicable to our setup (Closes #163) - Expose org UUID from `claude auth status` (Closes #160) - Clean up Svelte and Vite build warnings (`a11y_click_events_have_key_events`, `state_referenced_locally`, `non_reactive_update`, `codeSplitting`, chunk size, CodeMirror dynamic import) - Update all npm dependencies to latest compatible versions with exact pinning (Closes #81, Closes #82, Closes #83, Closes #84, Closes #85, Closes #86, Closes #87, Closes #90, Closes #91, Closes #93, Closes #94, Closes #95, Closes #96, Closes #97, Closes #98, Closes #99, Closes #101, Closes #141, Closes #142, Closes #143, Closes #145, Closes #146, Closes #147) - Run `cargo update` to bring Cargo.lock up to date ### Closes Closes #160 Closes #162 Closes #163 Closes #164 Closes #165 Closes #166 Closes #167 Closes #168 Closes #169 Closes #81 Closes #82 Closes #83 Closes #84 Closes #85 Closes #86 Closes #87 Closes #90 Closes #91 Closes #93 Closes #94 Closes #95 Closes #96 Closes #97 Closes #98 Closes #99 Closes #101 Closes #141 Closes #142 Closes #143 Closes #145 Closes #146 Closes #147 ✨ This PR was created with help from Hikari~ 🌸 Reviewed-on: #171 Co-authored-by: Hikari <hikari@nhcarrigan.com> Co-committed-by: Hikari <hikari@nhcarrigan.com>
This commit was merged in pull request #171.
This commit is contained in:
+58
-3
@@ -12,6 +12,7 @@
|
||||
setSkipNextGreeting,
|
||||
} from "$lib/tauri";
|
||||
import { configStore, applyTheme, applyFontSize, isCompactMode } from "$lib/stores/config";
|
||||
import { readFile } from "@tauri-apps/plugin-fs";
|
||||
import { initNotificationSync, cleanupNotificationSync } from "$lib/stores/notifications";
|
||||
import { conversationsStore } from "$lib/stores/conversations";
|
||||
import { claudeStore, isClaudeProcessing } from "$lib/stores/claude";
|
||||
@@ -37,6 +38,45 @@
|
||||
import { debugConsoleStore } from "$lib/stores/debugConsole";
|
||||
import { initializeTodoListener, cleanupTodoListener } from "$lib/stores/todos";
|
||||
|
||||
let backgroundDataUrl = $state<string | null>(null);
|
||||
let backgroundOpacity = $state(0.3);
|
||||
|
||||
const configValues = configStore.config;
|
||||
$effect(() => {
|
||||
const cfg = $configValues;
|
||||
backgroundOpacity = cfg.background_image_opacity;
|
||||
if (cfg.background_image_path) {
|
||||
void loadBackgroundImage(cfg.background_image_path);
|
||||
} else {
|
||||
backgroundDataUrl = null;
|
||||
}
|
||||
});
|
||||
|
||||
async function loadBackgroundImage(path: string) {
|
||||
try {
|
||||
const data = await readFile(path);
|
||||
const chunks: string[] = [];
|
||||
const chunkSize = 8192;
|
||||
for (let i = 0; i < data.length; i += chunkSize) {
|
||||
chunks.push(String.fromCharCode(...data.slice(i, i + chunkSize)));
|
||||
}
|
||||
const ext = path.split(".").pop()?.toLowerCase() ?? "png";
|
||||
const mimeMap: Record<string, string> = {
|
||||
jpg: "image/jpeg",
|
||||
jpeg: "image/jpeg",
|
||||
png: "image/png",
|
||||
webp: "image/webp",
|
||||
gif: "image/gif",
|
||||
avif: "image/avif",
|
||||
};
|
||||
const mime = mimeMap[ext] ?? "image/png";
|
||||
backgroundDataUrl = `data:${mime};base64,${btoa(chunks.join(""))}`;
|
||||
} catch (error) {
|
||||
console.error("Failed to load background image:", error);
|
||||
backgroundDataUrl = null;
|
||||
}
|
||||
}
|
||||
|
||||
let initialized = false;
|
||||
let updateNotification: UpdateNotification | undefined = $state(undefined);
|
||||
let achievementPanelOpen = $state(false);
|
||||
@@ -473,16 +513,27 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
{#if backgroundDataUrl}
|
||||
<div
|
||||
class="fixed inset-0 bg-cover bg-center pointer-events-none"
|
||||
style="background-image: url('{backgroundDataUrl}'); opacity: {backgroundOpacity}; z-index: 0;"
|
||||
></div>
|
||||
{/if}
|
||||
|
||||
{#if compactModeActive}
|
||||
<!-- Compact mode: minimal widget interface -->
|
||||
<div
|
||||
class="app-container compact-app h-screen w-screen flex flex-col bg-[var(--bg-primary)] overflow-hidden"
|
||||
style={backgroundDataUrl ? "background: transparent;" : ""}
|
||||
>
|
||||
<CompactMode onExpand={exitCompactMode} />
|
||||
</div>
|
||||
{:else}
|
||||
<!-- Full mode: standard interface -->
|
||||
<div class="app-container h-screen w-screen flex flex-col bg-[var(--bg-primary)] overflow-hidden">
|
||||
<div
|
||||
class="app-container h-screen w-screen flex flex-col bg-[var(--bg-primary)] overflow-hidden"
|
||||
style={backgroundDataUrl ? "background: transparent;" : ""}
|
||||
>
|
||||
<StatusBar
|
||||
onToggleAchievements={() => (achievementPanelOpen = !achievementPanelOpen)}
|
||||
onToggleCompact={enterCompactMode}
|
||||
@@ -491,8 +542,12 @@
|
||||
<main class="flex-1 flex overflow-hidden">
|
||||
<!-- Left panel: Character display -->
|
||||
<div
|
||||
class="character-panel {getPanelGlowClass()} flex flex-col items-center justify-center bg-[var(--bg-secondary)]/50"
|
||||
style="width: {panelWidth}px; min-width: {MIN_PANEL_WIDTH}px; max-width: {MAX_PANEL_WIDTH}px;"
|
||||
class="character-panel {getPanelGlowClass()} flex flex-col items-center justify-center {backgroundDataUrl
|
||||
? ''
|
||||
: 'bg-[var(--bg-secondary)]/50'}"
|
||||
style="width: {panelWidth}px; min-width: {MIN_PANEL_WIDTH}px; max-width: {MAX_PANEL_WIDTH}px;{backgroundDataUrl
|
||||
? ' background: transparent !important;'
|
||||
: ''}"
|
||||
>
|
||||
<AnimeGirl />
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user