Files
hikari-desktop/src/lib/components/CliVersion.svelte
T
hikari b745100bd5
Security Scan and Upload / Security & DefectDojo Upload (push) Successful in 1m28s
CI / Lint & Test (push) Has started running
CI / Build Linux (push) Has been cancelled
CI / Build Windows (cross-compile) (push) Has been cancelled
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>
2026-02-25 22:55:47 -08:00

161 lines
3.9 KiB
Svelte

<script lang="ts">
import { invoke } from "@tauri-apps/api/core";
import { onMount } from "svelte";
const SUPPORTED_CLI_VERSION = "2.1.53";
let installedVersion = $state("Loading...");
function compareVersions(a: string, b: string): number {
const aParts = a.split(".").map(Number);
const bParts = b.split(".").map(Number);
for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {
const aVal = aParts[i] ?? 0;
const bVal = bParts[i] ?? 0;
if (aVal > bVal) return 1;
if (aVal < bVal) return -1;
}
return 0;
}
let displayVersion = $derived(installedVersion.split(" (")[0]);
let supportedBadgeState = $derived.by(() => {
if (installedVersion === "Loading..." || installedVersion === "Unknown") {
return "neutral";
}
const semverMatch = /(\d+\.\d+\.\d+)/.exec(installedVersion);
if (!semverMatch) return "neutral";
const cmp = compareVersions(semverMatch[1], SUPPORTED_CLI_VERSION);
if (cmp > 0) return "ahead";
if (cmp < 0) return "behind";
return "current";
});
async function fetchVersion() {
try {
const result = await invoke<string>("get_claude_version");
installedVersion = result;
} catch (error) {
console.error("Failed to get Claude CLI version:", error);
installedVersion = "Unknown";
}
}
onMount(() => {
fetchVersion();
});
</script>
<div class="cli-versions">
<div class="cli-version">
<svg
class="terminal-icon"
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polyline points="4 17 10 11 4 5" />
<line x1="12" y1="19" x2="20" y2="19" />
</svg>
<span class="version-text">CLI {displayVersion}</span>
</div>
<div class="cli-version supported {supportedBadgeState}" title="Highest audited CLI version">
<svg
class="terminal-icon"
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
</svg>
<span class="version-text">Supported {SUPPORTED_CLI_VERSION}</span>
</div>
{#if supportedBadgeState === "ahead"}
<span class="version-warning ahead"
>Your version is newer, some features may not be supported</span
>
{:else if supportedBadgeState === "behind"}
<span class="version-warning behind"
>Your version is out of date, please update to ensure compatibility</span
>
{/if}
</div>
<style>
.cli-versions {
display: flex;
gap: 6px;
align-items: center;
}
.cli-version {
display: flex;
align-items: center;
gap: 6px;
padding: 4px 12px;
background: var(--bg-secondary);
border: 1px solid var(--border-color);
border-radius: 6px;
color: var(--text-secondary);
font-size: 0.85rem;
font-family: var(--font-mono, monospace);
transition: all 0.2s;
}
.cli-version:hover {
border-color: var(--accent-primary);
color: var(--accent-primary);
}
.cli-version.supported.current {
border-color: var(--success-color, #4caf50);
color: var(--success-color, #4caf50);
}
.cli-version.supported.ahead {
border-color: var(--warning-color, #ff9800);
color: var(--warning-color, #ff9800);
}
.cli-version.supported.behind {
border-color: var(--error-color, #f44336);
color: var(--error-color, #f44336);
}
.terminal-icon {
flex-shrink: 0;
opacity: 0.7;
}
.version-text {
white-space: nowrap;
}
.version-warning {
font-size: 0.75rem;
font-style: italic;
white-space: nowrap;
}
.version-warning.ahead {
color: var(--warning-color, #ff9800);
}
.version-warning.behind {
color: var(--error-color, #f44336);
}
</style>