generated from nhcarrigan/template
4134e11c88
## Summary This PR implements all tickets filed from the CLI v2.1.74 → v2.1.80 changelog audit (issues #223–#232). ### Changes by Issue - **#223** — `feat: handle Elicitation and ElicitationResult hook events` New `ElicitationModal.svelte` component, Rust parsing for `[Elicitation Hook]` and `[ElicitationResult Hook]`, new store methods, and TypeScript event types. - **#224** — `feat: handle StopFailure hook event for API error turns` Rust parsing for `[StopFailure Hook]`; frontend shows error toast + error character state. - **#225** — `feat: handle PostCompact hook event` Rust parsing for `[PostCompact Hook]`; frontend shows info toast + success character state. - **#226** — `feat: expose --name CLI flag as session name at startup` Added `session_name` field to `ClaudeStartOptions`; `StatusBar.doConnect()` passes the conversation name. - **#227** — `fix: tighten startup watchdog and correct misleading comment` Startup watchdog tightened from 60 s → 30 s; corrected a comment that said "5 minutes" whilst the code used 60 seconds. - **#228** — `fix: document cost estimation review and update default model fallback` Default model fallback updated from `claude-sonnet-4-5-20250929` → `claude-sonnet-4-6`; added doc comment explaining why char-based estimation is unaffected by v2.1.75 token overcounting fix. - **#229** — `chore: update supported CLI version constant to 2.1.80` `SUPPORTED_CLI_VERSION` bumped in `CliVersion.svelte`. - **#230** — `feat: surface memory file last-modified timestamps in MemoryBrowserPanel` Backend populates `last_modified` Unix timestamp; frontend formats and displays it per file. - **#231** — `feat: update max_output_tokens upper bound and helper text for 128k` Input max raised to 128 000; placeholder and helper text updated to reflect model-dependent defaults and 128 k ceiling for Opus/Sonnet 4.6. - **#232** — `fix: document non-streaming fallback compatibility with mid-session watchdog` Added doc comment above `STUCK_TIMEOUT` explaining the 5-minute watchdog is intentionally larger than the CLI's 2-minute non-streaming API fallback. --- ✨ This PR was created with help from Hikari~ 🌸 Reviewed-on: #233 Co-authored-by: Hikari <hikari@nhcarrigan.com> Co-committed-by: Hikari <hikari@nhcarrigan.com>
96 lines
2.6 KiB
TypeScript
96 lines
2.6 KiB
TypeScript
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 addError(message: string) {
|
||
const id = crypto.randomUUID();
|
||
const toast: InfoToast = { id, kind: "info", message, icon: "⚠️" };
|
||
update((toasts) => [...toasts, toast]);
|
||
setTimeout(() => remove(id), 6000);
|
||
}
|
||
|
||
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, addError, addAchievement, addUpdate, remove };
|
||
}
|
||
|
||
export const toastStore = createToastStore();
|