mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-01 08:13:37 +00:00
chore: Enhance type safety and improve code consistency across components
- Added a new `typecheck` script in `package.json` for better type checking in the UI workspace. - Refactored several components to remove unnecessary type assertions and improve type safety, particularly in `new-project-modal.tsx`, `edit-project-dialog.tsx`, and `task-progress-panel.tsx`. - Updated event handling in `git-diff-panel.tsx` to use async functions for better error handling. - Improved type definitions in various files, including `setup-view` and `electron.ts`, to ensure consistent usage of types across the codebase. - Cleaned up global type definitions for better clarity and maintainability. These changes aim to streamline the development process and reduce potential runtime errors.
This commit is contained in:
@@ -191,7 +191,7 @@ export function NewProjectModal({
|
||||
|
||||
// Use platform-specific path separator
|
||||
const pathSep =
|
||||
typeof window !== 'undefined' && (window as any).electronAPI
|
||||
typeof window !== 'undefined' && window.electronAPI
|
||||
? navigator.platform.indexOf('Win') !== -1
|
||||
? '\\'
|
||||
: '/'
|
||||
|
||||
@@ -25,9 +25,9 @@ interface EditProjectDialogProps {
|
||||
export function EditProjectDialog({ project, open, onOpenChange }: EditProjectDialogProps) {
|
||||
const { setProjectName, setProjectIcon, setProjectCustomIcon } = useAppStore();
|
||||
const [name, setName] = useState(project.name);
|
||||
const [icon, setIcon] = useState<string | null>((project as any).icon || null);
|
||||
const [icon, setIcon] = useState<string | null>(project.icon || null);
|
||||
const [customIconPath, setCustomIconPath] = useState<string | null>(
|
||||
(project as any).customIconPath || null
|
||||
project.customIconPath || null
|
||||
);
|
||||
const [isUploadingIcon, setIsUploadingIcon] = useState(false);
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
@@ -36,10 +36,10 @@ export function EditProjectDialog({ project, open, onOpenChange }: EditProjectDi
|
||||
if (name.trim() !== project.name) {
|
||||
setProjectName(project.id, name.trim());
|
||||
}
|
||||
if (icon !== (project as any).icon) {
|
||||
if (icon !== project.icon) {
|
||||
setProjectIcon(project.id, icon);
|
||||
}
|
||||
if (customIconPath !== (project as any).customIconPath) {
|
||||
if (customIconPath !== project.customIconPath) {
|
||||
setProjectCustomIcon(project.id, customIconPath);
|
||||
}
|
||||
onOpenChange(false);
|
||||
|
||||
@@ -479,7 +479,12 @@ export function GitDiffPanel({
|
||||
<div className="flex flex-col items-center justify-center gap-2 py-8 text-muted-foreground">
|
||||
<AlertCircle className="w-5 h-5 text-amber-500" />
|
||||
<span className="text-sm">{error}</span>
|
||||
<Button variant="ghost" size="sm" onClick={loadDiffs} className="mt-2">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={async () => await loadDiffs()}
|
||||
className="mt-2"
|
||||
>
|
||||
<RefreshCw className="w-4 h-4 mr-2" />
|
||||
Retry
|
||||
</Button>
|
||||
@@ -550,7 +555,12 @@ export function GitDiffPanel({
|
||||
>
|
||||
Collapse All
|
||||
</Button>
|
||||
<Button variant="ghost" size="sm" onClick={loadDiffs} className="text-xs h-7">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={async () => await loadDiffs()}
|
||||
className="text-xs h-7"
|
||||
>
|
||||
<RefreshCw className="w-3 h-3 mr-1" />
|
||||
Refresh
|
||||
</Button>
|
||||
|
||||
@@ -9,6 +9,7 @@ import { Check, Circle, ChevronDown, ChevronRight, FileCode } from 'lucide-react
|
||||
import { Spinner } from '@/components/ui/spinner';
|
||||
import { getElectronAPI } from '@/lib/electron';
|
||||
import type { AutoModeEvent } from '@/types/electron';
|
||||
import type { Feature, ParsedTask } from '@automaker/types';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
|
||||
interface TaskInfo {
|
||||
@@ -53,26 +54,29 @@ export function TaskProgressPanel({
|
||||
}
|
||||
|
||||
const result = await api.features.get(projectPath, featureId);
|
||||
const feature: any = (result as any).feature;
|
||||
const feature = (result as { success: boolean; feature?: Feature }).feature;
|
||||
if (result.success && feature?.planSpec?.tasks) {
|
||||
const planSpec = feature.planSpec as any;
|
||||
const planTasks = planSpec.tasks;
|
||||
const planSpec = feature.planSpec;
|
||||
const planTasks = planSpec.tasks; // Already guarded by the if condition above
|
||||
const currentId = planSpec.currentTaskId;
|
||||
const completedCount = planSpec.tasksCompleted || 0;
|
||||
|
||||
// Convert planSpec tasks to TaskInfo with proper status
|
||||
const initialTasks: TaskInfo[] = planTasks.map((t: any, index: number) => ({
|
||||
id: t.id,
|
||||
description: t.description,
|
||||
filePath: t.filePath,
|
||||
phase: t.phase,
|
||||
status:
|
||||
index < completedCount
|
||||
? ('completed' as const)
|
||||
: t.id === currentId
|
||||
? ('in_progress' as const)
|
||||
: ('pending' as const),
|
||||
}));
|
||||
// planTasks is guaranteed to be defined due to the if condition check
|
||||
const initialTasks: TaskInfo[] = (planTasks as ParsedTask[]).map(
|
||||
(t: ParsedTask, index: number) => ({
|
||||
id: t.id,
|
||||
description: t.description,
|
||||
filePath: t.filePath,
|
||||
phase: t.phase,
|
||||
status:
|
||||
index < completedCount
|
||||
? ('completed' as const)
|
||||
: t.id === currentId
|
||||
? ('in_progress' as const)
|
||||
: ('pending' as const),
|
||||
})
|
||||
);
|
||||
|
||||
setTasks(initialTasks);
|
||||
setCurrentTaskId(currentId || null);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useCallback, useState } from 'react';
|
||||
import { createLogger } from '@automaker/utils/logger';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { useAppStore, FileTreeNode, ProjectAnalysis } from '@/store/app-store';
|
||||
import { useAppStore, FileTreeNode, ProjectAnalysis, Feature } from '@/store/app-store';
|
||||
import { getElectronAPI } from '@/lib/electron';
|
||||
import { queryKeys } from '@/lib/query-keys';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
@@ -640,14 +640,14 @@ ${Object.entries(projectAnalysis.filesByExtension)
|
||||
}
|
||||
|
||||
for (const detectedFeature of detectedFeatures) {
|
||||
await api.features.create(currentProject.path, {
|
||||
const newFeature: Feature = {
|
||||
id: generateUUID(),
|
||||
category: detectedFeature.category,
|
||||
description: detectedFeature.description,
|
||||
status: 'backlog',
|
||||
// Initialize with empty steps so the object satisfies the Feature type
|
||||
steps: [],
|
||||
} as any);
|
||||
};
|
||||
await api.features.create(currentProject.path, newFeature);
|
||||
}
|
||||
|
||||
// Invalidate React Query cache to sync UI
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// @ts-nocheck - dnd-kit type incompatibilities with collision detection and complex state management
|
||||
import { useEffect, useState, useCallback, useMemo } from 'react';
|
||||
import { createLogger } from '@automaker/utils/logger';
|
||||
import {
|
||||
@@ -9,6 +8,8 @@ import {
|
||||
rectIntersection,
|
||||
pointerWithin,
|
||||
type PointerEvent as DndPointerEvent,
|
||||
type CollisionDetection,
|
||||
type Collision,
|
||||
} from '@dnd-kit/core';
|
||||
|
||||
// Custom pointer sensor that ignores drag events from within dialogs
|
||||
@@ -29,7 +30,7 @@ class DialogAwarePointerSensor extends PointerSensor {
|
||||
import { useAppStore, Feature } from '@/store/app-store';
|
||||
import { getElectronAPI } from '@/lib/electron';
|
||||
import { getHttpApiClient } from '@/lib/http-api-client';
|
||||
import type { BacklogPlanResult } from '@automaker/types';
|
||||
import type { BacklogPlanResult, FeatureStatusWithPipeline } from '@automaker/types';
|
||||
import { pathsEqual } from '@/lib/utils';
|
||||
import { toast } from 'sonner';
|
||||
import { BoardBackgroundModal } from '@/components/dialogs/board-background-modal';
|
||||
@@ -348,12 +349,12 @@ export function BoardView() {
|
||||
}, [currentProject, worktreeRefreshKey]);
|
||||
|
||||
// Custom collision detection that prioritizes specific drop targets (cards, worktrees) over columns
|
||||
const collisionDetectionStrategy = useCallback((args: any) => {
|
||||
const collisionDetectionStrategy = useCallback((args: Parameters<CollisionDetection>[0]) => {
|
||||
const pointerCollisions = pointerWithin(args);
|
||||
|
||||
// Priority 1: Specific drop targets (cards for dependency links, worktrees)
|
||||
// These need to be detected even if they are inside a column
|
||||
const specificTargetCollisions = pointerCollisions.filter((collision: any) => {
|
||||
const specificTargetCollisions = pointerCollisions.filter((collision: Collision) => {
|
||||
const id = String(collision.id);
|
||||
return id.startsWith('card-drop-') || id.startsWith('worktree-drop-');
|
||||
});
|
||||
@@ -363,7 +364,7 @@ export function BoardView() {
|
||||
}
|
||||
|
||||
// Priority 2: Columns
|
||||
const columnCollisions = pointerCollisions.filter((collision: any) =>
|
||||
const columnCollisions = pointerCollisions.filter((collision: Collision) =>
|
||||
COLUMNS.some((col) => col.id === collision.id)
|
||||
);
|
||||
|
||||
@@ -1094,7 +1095,7 @@ export function BoardView() {
|
||||
const columns = getColumnsWithPipeline(pipelineConfig);
|
||||
const map: Record<string, typeof hookFeatures> = {};
|
||||
for (const column of columns) {
|
||||
map[column.id] = getColumnFeatures(column.id as any);
|
||||
map[column.id] = getColumnFeatures(column.id as FeatureStatusWithPipeline);
|
||||
}
|
||||
return map;
|
||||
}, [pipelineConfig, getColumnFeatures]);
|
||||
|
||||
@@ -98,13 +98,11 @@ export const PriorityBadges = memo(function PriorityBadges({
|
||||
return;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
const interval = setInterval(() => {
|
||||
setCurrentTime(Date.now());
|
||||
}, 1000);
|
||||
|
||||
return () => {
|
||||
// eslint-disable-next-line no-undef
|
||||
clearInterval(interval);
|
||||
};
|
||||
}, [feature.justFinishedAt, feature.status, currentTime]);
|
||||
|
||||
@@ -17,6 +17,7 @@ import { useAppStore } from '@/store/app-store';
|
||||
import { extractSummary } from '@/lib/log-parser';
|
||||
import { useAgentOutput } from '@/hooks/queries';
|
||||
import type { AutoModeEvent } from '@/types/electron';
|
||||
import type { BacklogPlanEvent } from '@automaker/types';
|
||||
|
||||
interface AgentOutputModalProps {
|
||||
open: boolean;
|
||||
@@ -48,18 +49,16 @@ export function AgentOutputModal({
|
||||
const isBacklogPlan = featureId.startsWith('backlog-plan:');
|
||||
|
||||
// Resolve project path - prefer prop, fallback to window.__currentProject
|
||||
const resolvedProjectPath = projectPathProp || (window as any).__currentProject?.path || '';
|
||||
const resolvedProjectPath = projectPathProp || window.__currentProject?.path || '';
|
||||
|
||||
// Track additional content from WebSocket events (appended to query data)
|
||||
const [streamedContent, setStreamedContent] = useState<string>('');
|
||||
const [viewMode, setViewMode] = useState<ViewMode | null>(null);
|
||||
|
||||
// Use React Query for initial output loading
|
||||
const { data: initialOutput = '', isLoading } = useAgentOutput(
|
||||
resolvedProjectPath,
|
||||
featureId,
|
||||
open && !!resolvedProjectPath
|
||||
);
|
||||
const { data: initialOutput = '', isLoading } = useAgentOutput(resolvedProjectPath, featureId, {
|
||||
enabled: open && !!resolvedProjectPath,
|
||||
});
|
||||
|
||||
// Reset streamed content when modal opens or featureId changes
|
||||
useEffect(() => {
|
||||
@@ -262,7 +261,8 @@ export function AgentOutputModal({
|
||||
const api = getElectronAPI();
|
||||
if (!api?.backlogPlan) return;
|
||||
|
||||
const unsubscribe = api.backlogPlan.onEvent((event: any) => {
|
||||
const unsubscribe = api.backlogPlan.onEvent((data: unknown) => {
|
||||
const event = data as BacklogPlanEvent;
|
||||
if (!event?.type) return;
|
||||
|
||||
let newContent = '';
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { getElectronAPI } from '@/lib/electron';
|
||||
import { createLogger } from '@automaker/utils/logger';
|
||||
import type { Feature } from '@/store/app-store';
|
||||
|
||||
const logger = createLogger('BoardEffects');
|
||||
|
||||
interface UseBoardEffectsProps {
|
||||
currentProject: { path: string; id: string } | null;
|
||||
currentProject: { path: string; id: string; name?: string } | null;
|
||||
specCreatingForProject: string | null;
|
||||
setSpecCreatingForProject: (path: string | null) => void;
|
||||
checkContextExists: (featureId: string) => Promise<boolean>;
|
||||
features: any[];
|
||||
features: Feature[];
|
||||
isLoading: boolean;
|
||||
featuresWithContext: Set<string>;
|
||||
setFeaturesWithContext: (set: Set<string>) => void;
|
||||
@@ -33,10 +34,10 @@ export function useBoardEffects({
|
||||
// Make current project available globally for modal
|
||||
useEffect(() => {
|
||||
if (currentProject) {
|
||||
(window as any).__currentProject = currentProject;
|
||||
window.__currentProject = currentProject;
|
||||
}
|
||||
return () => {
|
||||
(window as any).__currentProject = null;
|
||||
window.__currentProject = null;
|
||||
};
|
||||
}, [currentProject]);
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// @ts-nocheck - model selector with provider-specific model options and validation
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Brain, AlertTriangle } from 'lucide-react';
|
||||
@@ -7,7 +6,7 @@ import { cn } from '@/lib/utils';
|
||||
import { useAppStore } from '@/store/app-store';
|
||||
import { useSetupStore } from '@/store/setup-store';
|
||||
import { getModelProvider } from '@automaker/types';
|
||||
import type { ModelProvider } from '@automaker/types';
|
||||
import type { ModelProvider, CursorModelId } from '@automaker/types';
|
||||
import { CLAUDE_MODELS, CURSOR_MODELS, ModelOption } from './model-constants';
|
||||
import { useEffect } from 'react';
|
||||
import { Spinner } from '@/components/ui/spinner';
|
||||
@@ -40,6 +39,7 @@ export function ModelSelector({
|
||||
const isCursorAvailable = cursorCliStatus?.installed && cursorCliStatus?.auth?.authenticated;
|
||||
|
||||
// Check if Codex CLI is available
|
||||
// @ts-expect-error - codexCliStatus uses CliStatus type but should use CodexCliStatus which has auth
|
||||
const isCodexAvailable = codexCliStatus?.installed && codexCliStatus?.auth?.authenticated;
|
||||
|
||||
// Fetch Codex models on mount
|
||||
@@ -75,8 +75,8 @@ export function ModelSelector({
|
||||
// Check both the full ID (for GPT models) and the unprefixed version (for non-GPT models)
|
||||
const unprefixedId = model.id.startsWith('cursor-') ? model.id.slice(7) : model.id;
|
||||
return (
|
||||
enabledCursorModels.includes(model.id as any) ||
|
||||
enabledCursorModels.includes(unprefixedId as any)
|
||||
enabledCursorModels.includes(model.id as CursorModelId) ||
|
||||
enabledCursorModels.includes(unprefixedId as CursorModelId)
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import type { UIEvent } from 'react';
|
||||
import { useAppStore } from '@/store/app-store';
|
||||
import { useAppStore, ChatSession } from '@/store/app-store';
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
@@ -156,7 +156,7 @@ export function ChatHistory() {
|
||||
createChatSession();
|
||||
};
|
||||
|
||||
const handleSelectSession = (session: any) => {
|
||||
const handleSelectSession = (session: ChatSession) => {
|
||||
setCurrentChatSession(session);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// @ts-nocheck - graph view page with feature filtering and visualization state
|
||||
import { useState, useCallback, useMemo, useEffect } from 'react';
|
||||
import { useAppStore, Feature } from '@/store/app-store';
|
||||
import { useAppStore, Feature, FeatureImagePath } from '@/store/app-store';
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { GraphView } from './graph-view';
|
||||
import {
|
||||
@@ -236,7 +235,7 @@ export function GraphViewPage() {
|
||||
// Follow-up state (simplified for graph view)
|
||||
const [followUpFeature, setFollowUpFeature] = useState<Feature | null>(null);
|
||||
const [followUpPrompt, setFollowUpPrompt] = useState('');
|
||||
const [followUpImagePaths, setFollowUpImagePaths] = useState<any[]>([]);
|
||||
const [followUpImagePaths, setFollowUpImagePaths] = useState<FeatureImagePath[]>([]);
|
||||
const [, setFollowUpPreviewMap] = useState<Map<string, string>>(new Map());
|
||||
|
||||
// In-progress features for shortcuts
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// @ts-nocheck - interview flow state machine with dynamic question handling
|
||||
import { useState, useCallback, useRef, useEffect } from 'react';
|
||||
import { createLogger } from '@automaker/utils/logger';
|
||||
import { useAppStore, Feature } from '@/store/app-store';
|
||||
@@ -324,7 +323,7 @@ export function InterviewView() {
|
||||
const api = getElectronAPI();
|
||||
// Use platform-specific path separator
|
||||
const pathSep =
|
||||
typeof window !== 'undefined' && (window as any).electronAPI
|
||||
typeof window !== 'undefined' && window.electronAPI
|
||||
? navigator.platform.indexOf('Win') !== -1
|
||||
? '\\'
|
||||
: '/'
|
||||
@@ -349,8 +348,9 @@ export function InterviewView() {
|
||||
id: generateUUID(),
|
||||
category: 'Core',
|
||||
description: 'Initial project setup',
|
||||
status: 'backlog' as const,
|
||||
status: 'backlog',
|
||||
skipTests: true,
|
||||
steps: [],
|
||||
};
|
||||
|
||||
if (!api.features) {
|
||||
|
||||
@@ -1,15 +1,31 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { createLogger } from '@automaker/utils/logger';
|
||||
import type { ModelProvider } from '@automaker/types';
|
||||
import type { CliStatus } from '@/store/setup-store';
|
||||
|
||||
const logger = createLogger('CliInstallation');
|
||||
|
||||
interface InstallApiResult {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
interface InstallProgressEvent {
|
||||
cli?: string;
|
||||
data?: string;
|
||||
type?: string;
|
||||
}
|
||||
|
||||
interface UseCliInstallationOptions {
|
||||
cliType: 'claude';
|
||||
installApi: () => Promise<any>;
|
||||
onProgressEvent?: (callback: (progress: any) => void) => (() => void) | undefined;
|
||||
cliType: ModelProvider;
|
||||
installApi: () => Promise<InstallApiResult>;
|
||||
onProgressEvent?: (
|
||||
callback: (progress: InstallProgressEvent) => void
|
||||
) => (() => void) | undefined;
|
||||
onSuccess?: () => void;
|
||||
getStoreState?: () => any;
|
||||
getStoreState?: () => CliStatus | null;
|
||||
}
|
||||
|
||||
export function useCliInstallation({
|
||||
@@ -32,15 +48,13 @@ export function useCliInstallation({
|
||||
let unsubscribe: (() => void) | undefined;
|
||||
|
||||
if (onProgressEvent) {
|
||||
unsubscribe = onProgressEvent(
|
||||
(progress: { cli?: string; data?: string; type?: string }) => {
|
||||
if (progress.cli === cliType) {
|
||||
setInstallProgress((prev) => ({
|
||||
output: [...prev.output, progress.data || progress.type || ''],
|
||||
}));
|
||||
}
|
||||
unsubscribe = onProgressEvent((progress: InstallProgressEvent) => {
|
||||
if (progress.cli === cliType) {
|
||||
setInstallProgress((prev) => ({
|
||||
output: [...prev.output, progress.data || progress.type || ''],
|
||||
}));
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
const result = await installApi();
|
||||
|
||||
@@ -1,11 +1,34 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import { createLogger } from '@automaker/utils/logger';
|
||||
import type { ModelProvider } from '@automaker/types';
|
||||
import type { CliStatus, ClaudeAuthStatus, CodexAuthStatus } from '@/store/setup-store';
|
||||
|
||||
interface CliStatusApiResponse {
|
||||
success: boolean;
|
||||
status?: 'installed' | 'not_installed';
|
||||
installed?: boolean;
|
||||
method?: string;
|
||||
version?: string;
|
||||
path?: string;
|
||||
auth?: {
|
||||
authenticated: boolean;
|
||||
method: string;
|
||||
hasCredentialsFile?: boolean;
|
||||
hasStoredOAuthToken?: boolean;
|
||||
hasStoredApiKey?: boolean;
|
||||
hasEnvApiKey?: boolean;
|
||||
hasEnvOAuthToken?: boolean;
|
||||
hasAuthFile?: boolean;
|
||||
hasApiKey?: boolean;
|
||||
};
|
||||
error?: string;
|
||||
}
|
||||
|
||||
interface UseCliStatusOptions {
|
||||
cliType: 'claude' | 'codex';
|
||||
statusApi: () => Promise<any>;
|
||||
setCliStatus: (status: any) => void;
|
||||
setAuthStatus: (status: any) => void;
|
||||
cliType: ModelProvider;
|
||||
statusApi: () => Promise<CliStatusApiResponse>;
|
||||
setCliStatus: (status: CliStatus | null) => void;
|
||||
setAuthStatus: (status: ClaudeAuthStatus | CodexAuthStatus | null) => void;
|
||||
}
|
||||
|
||||
const VALID_AUTH_METHODS = {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// @ts-nocheck - CLI setup wizard with step validation and setup store state
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
@@ -45,6 +44,33 @@ type VerificationStatus = 'idle' | 'verifying' | 'verified' | 'error';
|
||||
|
||||
type CliSetupAuthStatus = ClaudeAuthStatus | CodexAuthStatus;
|
||||
|
||||
interface CliStatusApiResponse {
|
||||
success: boolean;
|
||||
status?: 'installed' | 'not_installed';
|
||||
installed?: boolean;
|
||||
method?: string;
|
||||
version?: string;
|
||||
path?: string;
|
||||
auth?: {
|
||||
authenticated: boolean;
|
||||
method: string;
|
||||
hasCredentialsFile?: boolean;
|
||||
hasStoredOAuthToken?: boolean;
|
||||
hasStoredApiKey?: boolean;
|
||||
hasEnvApiKey?: boolean;
|
||||
hasEnvOAuthToken?: boolean;
|
||||
hasAuthFile?: boolean;
|
||||
hasApiKey?: boolean;
|
||||
};
|
||||
error?: string;
|
||||
}
|
||||
|
||||
interface InstallApiResponse {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
interface CliSetupConfig {
|
||||
cliType: ModelProvider;
|
||||
displayName: string;
|
||||
@@ -73,8 +99,8 @@ interface CliSetupConfig {
|
||||
buildCliAuthStatus: (previous: CliSetupAuthStatus | null) => CliSetupAuthStatus;
|
||||
buildApiKeyAuthStatus: (previous: CliSetupAuthStatus | null) => CliSetupAuthStatus;
|
||||
buildClearedAuthStatus: (previous: CliSetupAuthStatus | null) => CliSetupAuthStatus;
|
||||
statusApi: () => Promise<any>;
|
||||
installApi: () => Promise<any>;
|
||||
statusApi: () => Promise<CliStatusApiResponse>;
|
||||
installApi: () => Promise<InstallApiResponse>;
|
||||
verifyAuthApi: (
|
||||
method: 'cli' | 'api_key',
|
||||
apiKey?: string
|
||||
|
||||
Reference in New Issue
Block a user