Download apps/vscode/webview-ui/src/hooks/useAppInit.ts from SaylorTwift/kimi-code: direct link, hf CLI and curl.
- Browser
- Download file 4.93 kB
-
https://huggingface.co/SaylorTwift/kimi-code/resolve/main/apps/vscode/webview-ui/src/hooks/useAppInit.ts
- Command line
-
hf download hf://SaylorTwift/kimi-code/apps/vscode/webview-ui/src/hooks/useAppInit.ts
-
curl -L -o useAppInit.ts https://huggingface.co/SaylorTwift/kimi-code/resolve/main/apps/vscode/webview-ui/src/hooks/useAppInit.ts
4.93 kB
| import { useState, useEffect, useCallback } from "react"; | |
| import { bridge, Events } from "@/services"; | |
| import { requiresManagedProviderLogin, useSettingsStore } from "@/stores"; | |
| import type { ExtensionConfig } from "shared/types"; | |
| export type AppStatus = "loading" | "no-workspace" | "runtime-error" | "not-logged-in" | "no-models" | "ready"; | |
| export type ConfigErrorStatus = "loading" | "no-workspace" | "runtime-error" | "no-models"; | |
| export type AppViewResolution = | |
| | { readonly view: "login" } | |
| | { | |
| readonly view: "status"; | |
| readonly status: ConfigErrorStatus; | |
| /** True when the status screen must offer a path to the sign-in screen. */ | |
| readonly canGoToLogin: boolean; | |
| } | |
| | { readonly view: "main" }; | |
| /** | |
| * Pure view router for App. The `no-models` status (a managed OAuth token | |
| * exists but config.toml has no models — e.g. a first login whose model | |
| * provisioning failed after the device flow already persisted the token) | |
| * must always keep a path back to the sign-in screen: Reload alone cannot | |
| * change the on-disk state, so without it the user is stranded and the | |
| * login UI becomes unreachable. | |
| */ | |
| export function resolveAppView(input: { | |
| readonly status: AppStatus; | |
| readonly modelsCount: number; | |
| readonly skippedLogin: boolean; | |
| readonly showLogin: boolean; | |
| }): AppViewResolution { | |
| const { status, modelsCount, skippedLogin, showLogin } = input; | |
| if (showLogin || (status === "not-logged-in" && !skippedLogin)) { | |
| return { view: "login" }; | |
| } | |
| if (skippedLogin && modelsCount === 0) { | |
| return { view: "status", status: "no-models", canGoToLogin: true }; | |
| } | |
| if (status !== "ready" && status !== "not-logged-in") { | |
| return { view: "status", status, canGoToLogin: status === "no-models" }; | |
| } | |
| return { view: "main" }; | |
| } | |
| export interface AppInitState { | |
| status: AppStatus; | |
| errorMessage: string | null; | |
| modelsCount: number; | |
| refresh: () => void; | |
| } | |
| export function useAppInit(): AppInitState { | |
| const [state, setState] = useState<Omit<AppInitState, "refresh">>({ | |
| status: "loading", | |
| errorMessage: null, | |
| modelsCount: 0, | |
| }); | |
| const [initKey, setInitKey] = useState(0); | |
| const { initModels, setExtensionConfig, setWireSlashCommands, setIsLoggedIn, setWorkspaceRoot } = useSettingsStore(); | |
| const refresh = useCallback(() => { | |
| setState({ status: "loading", errorMessage: null, modelsCount: 0 }); | |
| setInitKey((k) => k + 1); | |
| }, []); | |
| useEffect(() => { | |
| return bridge.on<{ config: ExtensionConfig; changedKeys: string[] }>(Events.ExtensionConfigChanged, ({ config }) => { | |
| setExtensionConfig(config); | |
| }); | |
| }, [setExtensionConfig, refresh]); | |
| useEffect(() => { | |
| let cancelled = false; | |
| async function init() { | |
| try { | |
| const workspace = await bridge.checkWorkspace(); | |
| if (cancelled) { | |
| return; | |
| } | |
| if (!workspace.hasWorkspace) { | |
| setState({ status: "no-workspace", errorMessage: null, modelsCount: 0 }); | |
| return; | |
| } | |
| setWorkspaceRoot(workspace.workspaceRoot ?? workspace.path ?? null); | |
| const [extensionConfig, slashCommands] = await Promise.all([ | |
| bridge.getExtensionConfig(), | |
| bridge.getSlashCommands(), | |
| ]); | |
| if (cancelled) { | |
| return; | |
| } | |
| setExtensionConfig(extensionConfig); | |
| setWireSlashCommands(slashCommands); | |
| const [loginStatus, kimiConfig] = await Promise.all([bridge.checkLoginStatus(), bridge.getModels()]); | |
| if (cancelled) { | |
| return; | |
| } | |
| console.log("[AppInit] Login status:", loginStatus, "kimiConfig:", kimiConfig); | |
| setIsLoggedIn(loginStatus.loggedIn); | |
| initModels(kimiConfig.models, kimiConfig.defaultModel, kimiConfig.defaultThinking, kimiConfig.defaultThinkingEffort); | |
| const modelsCount = kimiConfig.models?.length ?? 0; | |
| if (modelsCount === 0 && !loginStatus.loggedIn) { | |
| setState({ status: "not-logged-in", errorMessage: null, modelsCount }); | |
| return; | |
| } | |
| if (modelsCount === 0) { | |
| setState({ status: "no-models", errorMessage: null, modelsCount: 0 }); | |
| return; | |
| } | |
| if (requiresManagedProviderLogin(kimiConfig.models, kimiConfig.defaultModel, loginStatus.loggedIn)) { | |
| setState({ status: "not-logged-in", errorMessage: null, modelsCount }); | |
| return; | |
| } | |
| setState({ status: "ready", errorMessage: null, modelsCount }); | |
| } catch (err) { | |
| if (!cancelled) { | |
| setState({ | |
| status: "runtime-error", | |
| errorMessage: err instanceof Error ? err.message : "Failed to initialize", | |
| modelsCount: 0, | |
| }); | |
| } | |
| } | |
| } | |
| void init(); | |
| return () => { | |
| cancelled = true; | |
| }; | |
| }, [initKey, initModels, setExtensionConfig, setWireSlashCommands, setIsLoggedIn]); | |
| return { ...state, refresh }; | |
| } | |