feat: CLI v2.1.68–v2.1.74 compatibility updates (#221)
Security Scan and Upload / Security & DefectDojo Upload (push) Successful in 1m21s
CI / Lint & Test (push) Has started running
CI / Build Linux (push) Has been cancelled
CI / Build Windows (cross-compile) (push) Has been cancelled

## Summary

This PR brings Hikari Desktop up to full compatibility with Claude Code CLI versions v2.1.68 through v2.1.74, implementing all changelog items audited in issues #200–#218.

## Changes

### Bug Fixes
- Remove deprecated Claude Opus 4.0 and 4.1 models from the model selector
- Auto-migrate users pinned to deprecated models to Opus 4.6

### New Features
- Add cron tool support (`CronCreate`, `CronDelete`, `CronList`) with character state mapping and `CLAUDE_CODE_DISABLE_CRON` settings toggle
- Handle `EnterWorktree` and `ExitWorktree` tools in character state mapping and tool display
- Add CLI update check with npm registry indicator in the version bar
- Add `agent_type` field and support the Agent tool rename from CLI v2.1.69
- Consume `worktree` field from status line hook events
- Display per-agent model override in the agent monitor tree
- Expose Claude Code CLI built-in slash commands (`/simplify`, `/loop`, `/batch`, `/memory`, `/context`) in the command menu with CLI badges
- Add `includeGitInstructions` toggle in settings
- Add `ENABLE_CLAUDEAI_MCP_SERVERS` opt-out setting
- Linkify MCP binary file paths (PDFs, audio, Office docs) in markdown output
- Add auto-memory panel, `/memory` slash command shortcut, and unified toast notification system
- Toast notifications for `WorktreeCreate` and `WorktreeRemove` hook events
- Sort session resume list by most recent activity, with most recent user message as preview
- Convert WSL Linux paths to Windows UNC paths when opening binary files via `open_binary_file` command
- Expose `autoMemoryDirectory` setting in ConfigSidebar (Agent Settings section)
- Add `/context` as a CLI built-in in the slash command menu
- Expose `modelOverrides` setting as a JSON textarea in ConfigSidebar (for AWS Bedrock, Google Vertex, etc.)

> **Note:** The CLI update check commit does not have a corresponding issue — it was a bonus addition during the audit sprint.

## Closes

Closes #200
Closes #201
Closes #202
Closes #205
Closes #206
Closes #207
Closes #208
Closes #209
Closes #210
Closes #211
Closes #212
Closes #213
Closes #214
Closes #215
Closes #216
Closes #217
Closes #218

Reviewed-on: #221
Co-authored-by: Hikari <hikari@nhcarrigan.com>
Co-committed-by: Hikari <hikari@nhcarrigan.com>
This commit was merged in pull request #221.
This commit is contained in:
2026-03-13 01:34:44 -07:00
committed by Naomi Carrigan
parent a690a4969b
commit 452fe185df
45 changed files with 2905 additions and 585 deletions
+88
View File
@@ -0,0 +1,88 @@
import { writable } from "svelte/store";
import type { AchievementUnlockedEvent } from "$lib/types/achievements";
export interface InfoToast {
id: string;
kind: "info";
message: string;
icon: string;
}
export interface AchievementToast {
id: string;
kind: "achievement";
achievement: AchievementUnlockedEvent["achievement"];
}
export interface UpdateToast {
id: string;
kind: "update";
latestVersion: string;
currentVersion: string;
releaseUrl: string;
}
export type Toast = InfoToast | AchievementToast | UpdateToast;
export function getAchievementRarity(id: string): string {
if (id === "TokenMaster") return "legendary";
if (["CodeMachine", "Unstoppable"].includes(id)) return "epic";
if (
[
"BlossomingCoder",
"CodeWizard",
"MasterBuilder",
"EnduranceChamp",
"DeepDive",
"CreativeCoder",
].includes(id)
)
return "rare";
return "common";
}
export function getRarityColour(rarity: string): string {
switch (rarity) {
case "legendary":
return "from-yellow-400 to-orange-500";
case "epic":
return "from-purple-400 to-pink-500";
case "rare":
return "from-blue-400 to-indigo-500";
default:
return "from-green-400 to-emerald-500";
}
}
function createToastStore() {
const { subscribe, update } = writable<Toast[]>([]);
function remove(id: string) {
update((toasts) => toasts.filter((t) => t.id !== id));
}
function addInfo(message: string, icon = "️") {
const id = crypto.randomUUID();
const toast: InfoToast = { id, kind: "info", message, icon };
update((toasts) => [...toasts, toast]);
setTimeout(() => remove(id), 4000);
}
function addAchievement(achievement: AchievementUnlockedEvent["achievement"]) {
const id = crypto.randomUUID();
const toast: AchievementToast = { id, kind: "achievement", achievement };
update((toasts) => [...toasts, toast]);
setTimeout(() => remove(id), 5000);
}
function addUpdate(latestVersion: string, currentVersion: string, releaseUrl: string) {
const id = crypto.randomUUID();
const toast: UpdateToast = { id, kind: "update", latestVersion, currentVersion, releaseUrl };
update((toasts) => [...toasts, toast]);
// Update toasts are persistent — no auto-dismiss
}
return { subscribe, addInfo, addAchievement, addUpdate, remove };
}
export const toastStore = createToastStore();