Files
Claude-Code-Workflow/ccw/frontend/src/hooks/useDeepWiki.ts
catlog22 fb4f6e718e feat: Implement DeepWiki documentation generation tools
- Added `__init__.py` in `codexlens/tools` for documentation generation.
- Created `deepwiki_generator.py` to handle symbol extraction and markdown generation.
- Introduced `MockMarkdownGenerator` for testing purposes.
- Implemented `DeepWikiGenerator` class for managing documentation generation and file processing.
- Added unit tests for `DeepWikiStore` to ensure proper functionality and error handling.
- Created tests for DeepWiki TypeScript types matching.
2026-03-05 18:30:56 +08:00

273 lines
6.5 KiB
TypeScript

// ========================================
// useDeepWiki Hook
// ========================================
// TanStack Query hooks for DeepWiki documentation system
import { useQuery } from '@tanstack/react-query';
import { useWorkflowStore, selectProjectPath } from '@/stores/workflowStore';
// Types
export interface DeepWikiFile {
id?: number;
path: string;
contentHash: string;
lastIndexed: string;
symbolsCount: number;
docsGenerated: boolean;
}
export interface DeepWikiSymbol {
id?: number;
name: string;
type: string;
sourceFile: string;
docFile: string;
anchor: string;
lineRange: [number, number];
createdAt?: string;
updatedAt?: string;
}
export interface DeepWikiDoc {
id?: number;
path: string;
contentHash: string;
symbols: string[];
generatedAt: string;
llmTool?: string;
}
export interface DeepWikiStats {
available: boolean;
files: number;
symbols: number;
docs: number;
filesNeedingDocs?: number;
dbPath?: string;
}
export interface DocumentResponse {
doc: DeepWikiDoc | null;
content: string;
symbols: DeepWikiSymbol[];
}
// Query key factory
export const deepWikiKeys = {
all: ['deepWiki'] as const,
files: () => [...deepWikiKeys.all, 'files'] as const,
doc: (path: string) => [...deepWikiKeys.all, 'doc', path] as const,
stats: () => [...deepWikiKeys.all, 'stats'] as const,
search: (query: string) => [...deepWikiKeys.all, 'search', query] as const,
};
// Default stale time: 2 minutes
const STALE_TIME = 2 * 60 * 1000;
/**
* Fetch list of documented files
*/
async function fetchDeepWikiFiles(): Promise<DeepWikiFile[]> {
const response = await fetch('/api/deepwiki/files');
if (!response.ok) {
throw new Error(`Failed to fetch files: ${response.statusText}`);
}
return response.json();
}
/**
* Fetch document by source file path
*/
async function fetchDeepWikiDoc(filePath: string): Promise<DocumentResponse> {
const response = await fetch(`/api/deepwiki/doc?path=${encodeURIComponent(filePath)}`);
if (!response.ok) {
if (response.status === 404) {
return { doc: null, content: '', symbols: [] };
}
throw new Error(`Failed to fetch document: ${response.statusText}`);
}
return response.json();
}
/**
* Fetch DeepWiki statistics
*/
async function fetchDeepWikiStats(): Promise<DeepWikiStats> {
const response = await fetch('/api/deepwiki/stats');
if (!response.ok) {
throw new Error(`Failed to fetch stats: ${response.statusText}`);
}
return response.json();
}
/**
* Search symbols by query
*/
async function searchDeepWikiSymbols(query: string, limit = 50): Promise<DeepWikiSymbol[]> {
const response = await fetch(`/api/deepwiki/search?q=${encodeURIComponent(query)}&limit=${limit}`);
if (!response.ok) {
throw new Error(`Failed to search symbols: ${response.statusText}`);
}
return response.json();
}
// ========== Hooks ==========
export interface UseDeepWikiFilesOptions {
staleTime?: number;
enabled?: boolean;
}
export interface UseDeepWikiFilesReturn {
files: DeepWikiFile[];
isLoading: boolean;
isFetching: boolean;
error: Error | null;
refetch: () => Promise<void>;
}
/**
* Hook for fetching list of documented files
*/
export function useDeepWikiFiles(options: UseDeepWikiFilesOptions = {}): UseDeepWikiFilesReturn {
const { staleTime = STALE_TIME, enabled = true } = options;
const projectPath = useWorkflowStore(selectProjectPath);
const query = useQuery({
queryKey: deepWikiKeys.files(),
queryFn: fetchDeepWikiFiles,
staleTime,
enabled: enabled && !!projectPath,
retry: 2,
});
return {
files: query.data ?? [],
isLoading: query.isLoading,
isFetching: query.isFetching,
error: query.error,
refetch: async () => {
await query.refetch();
},
};
}
export interface UseDeepWikiDocOptions {
staleTime?: number;
enabled?: boolean;
}
export interface UseDeepWikiDocReturn {
doc: DeepWikiDoc | null;
content: string;
symbols: DeepWikiSymbol[];
isLoading: boolean;
isFetching: boolean;
error: Error | null;
refetch: () => Promise<void>;
}
/**
* Hook for fetching a document by source file path
*/
export function useDeepWikiDoc(filePath: string | null, options: UseDeepWikiDocOptions = {}): UseDeepWikiDocReturn {
const { staleTime = STALE_TIME, enabled = true } = options;
const query = useQuery({
queryKey: deepWikiKeys.doc(filePath ?? ''),
queryFn: () => fetchDeepWikiDoc(filePath!),
staleTime,
enabled: enabled && !!filePath,
retry: 2,
});
return {
doc: query.data?.doc ?? null,
content: query.data?.content ?? '',
symbols: query.data?.symbols ?? [],
isLoading: query.isLoading,
isFetching: query.isFetching,
error: query.error,
refetch: async () => {
await query.refetch();
},
};
}
export interface UseDeepWikiStatsOptions {
staleTime?: number;
enabled?: boolean;
}
export interface UseDeepWikiStatsReturn {
stats: DeepWikiStats | null;
isLoading: boolean;
isFetching: boolean;
error: Error | null;
refetch: () => Promise<void>;
}
/**
* Hook for fetching DeepWiki statistics
*/
export function useDeepWikiStats(options: UseDeepWikiStatsOptions = {}): UseDeepWikiStatsReturn {
const { staleTime = STALE_TIME, enabled = true } = options;
const query = useQuery({
queryKey: deepWikiKeys.stats(),
queryFn: fetchDeepWikiStats,
staleTime,
enabled,
retry: 2,
});
return {
stats: query.data ?? null,
isLoading: query.isLoading,
isFetching: query.isFetching,
error: query.error,
refetch: async () => {
await query.refetch();
},
};
}
export interface UseDeepWikiSearchOptions {
limit?: number;
staleTime?: number;
enabled?: boolean;
}
export interface UseDeepWikiSearchReturn {
symbols: DeepWikiSymbol[];
isLoading: boolean;
isFetching: boolean;
error: Error | null;
refetch: () => Promise<void>;
}
/**
* Hook for searching symbols
*/
export function useDeepWikiSearch(query: string, options: UseDeepWikiSearchOptions = {}): UseDeepWikiSearchReturn {
const { limit = 50, staleTime = STALE_TIME, enabled = true } = options;
const queryResult = useQuery({
queryKey: deepWikiKeys.search(query),
queryFn: () => searchDeepWikiSymbols(query, limit),
staleTime,
enabled: enabled && query.length > 0,
retry: 2,
});
return {
symbols: queryResult.data ?? [],
isLoading: queryResult.isLoading,
isFetching: queryResult.isFetching,
error: queryResult.error,
refetch: async () => {
await queryResult.refetch();
},
};
}