mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-15 02:42:45 +08:00
feat: Add global relationships management to GlobalSymbolIndex
- Introduced a new schema version (v2) with a global_relationships table. - Implemented CRUD operations for file relationships, including update and delete functionalities. - Added query capabilities for relationships by target and symbols. - Created migration logic from v1 to v2 schema. - Enhanced tests for global relationships, covering various scenarios including insertion, querying, and deletion. docs: Add update-single command for generating module documentation - Created a new command to generate manual-style documentation (CLAUDE.md) for a single module. - Detailed execution process and implementation phases for the command. - Included usage examples and error handling guidelines. feat: Implement team command for CLI interface - Added a new team command for logging and retrieving messages in a team message bus. - Supported subcommands for logging, reading, listing, and checking status of messages. - Included error handling and JSON output options. test: Add comprehensive tests for global relationships - Developed extensive tests for the global_relationships table in GlobalSymbolIndex. - Covered schema creation, migration, CRUD operations, and performance benchmarks. - Ensured project isolation and validated query functionalities for relationships.
This commit is contained in:
@@ -142,12 +142,12 @@ export function ObservabilityPanel() {
|
||||
<label className="block text-xs font-medium text-muted-foreground mb-1">
|
||||
{formatMessage({ id: 'issues.observability.filters.type' })}
|
||||
</label>
|
||||
<Select value={type} onValueChange={(v) => setType(v)}>
|
||||
<Select value={type || '__all__'} onValueChange={(v) => setType(v === '__all__' ? '' : v)}>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={formatMessage({ id: 'issues.observability.filters.typeAll' })} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="">{formatMessage({ id: 'issues.observability.filters.typeAll' })}</SelectItem>
|
||||
<SelectItem value="__all__">{formatMessage({ id: 'issues.observability.filters.typeAll' })}</SelectItem>
|
||||
{EVENT_TYPES.map((t) => (
|
||||
<SelectItem key={t} value={t}>
|
||||
{t}
|
||||
|
||||
@@ -209,7 +209,7 @@ export function QueuePanel() {
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{(historyIndex.queues || []).length === 0 ? (
|
||||
<SelectItem value="" disabled>
|
||||
<SelectItem value="__none__" disabled>
|
||||
{formatMessage({ id: 'issues.queue.history.empty' })}
|
||||
</SelectItem>
|
||||
) : (
|
||||
|
||||
@@ -215,7 +215,7 @@ export function QueueExecuteInSession({ item, className }: { item: QueueItem; cl
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{sessions.length === 0 ? (
|
||||
<SelectItem value="" disabled>
|
||||
<SelectItem value="__none__" disabled>
|
||||
{formatMessage({ id: 'issues.terminal.session.none' })}
|
||||
</SelectItem>
|
||||
) : (
|
||||
|
||||
@@ -267,7 +267,7 @@ export function QueueSendToOrchestrator({ item, className }: { item: QueueItem;
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{sessions.length === 0 ? (
|
||||
<SelectItem value="" disabled>
|
||||
<SelectItem value="__none__" disabled>
|
||||
{formatMessage({ id: 'issues.terminal.session.none' })}
|
||||
</SelectItem>
|
||||
) : (
|
||||
|
||||
@@ -248,7 +248,7 @@ function ContextContent({
|
||||
<div className="space-y-0.5 pl-2 max-h-32 overflow-y-auto">
|
||||
{ctx.relevant_files.map((f, i) => {
|
||||
const filePath = typeof f === 'string' ? f : f.path;
|
||||
const reason = typeof f === 'string' ? undefined : (f.rationale || f.reason);
|
||||
const reason = typeof f === 'string' ? undefined : f.reason;
|
||||
return (
|
||||
<div key={i} className="group flex items-start gap-1 text-muted-foreground hover:bg-muted/30 rounded px-1 py-0.5">
|
||||
<span className="text-primary/50 shrink-0">{i + 1}.</span>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import {
|
||||
Server,
|
||||
Plus,
|
||||
@@ -226,6 +226,7 @@ export function McpManagerPage() {
|
||||
const [saveTemplateDialogOpen, setSaveTemplateDialogOpen] = useState(false);
|
||||
const [serverToSaveAsTemplate, setServerToSaveAsTemplate] = useState<McpServer | undefined>(undefined);
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
const notifications = useNotifications();
|
||||
|
||||
const {
|
||||
@@ -352,15 +353,47 @@ export function McpManagerPage() {
|
||||
};
|
||||
|
||||
const handleToggleCcwTool = async (tool: string, enabled: boolean) => {
|
||||
// Read latest from cache to avoid stale closures
|
||||
const currentConfig = queryClient.getQueryData<CcwMcpConfig>(['ccwMcpConfig']) ?? ccwConfig;
|
||||
const currentTools = currentConfig.enabledTools;
|
||||
const previousConfig = queryClient.getQueryData<CcwMcpConfig>(['ccwMcpConfig']);
|
||||
|
||||
const updatedTools = enabled
|
||||
? [...ccwConfig.enabledTools, tool]
|
||||
: ccwConfig.enabledTools.filter((t) => t !== tool);
|
||||
await updateCcwConfig({ enabledTools: updatedTools });
|
||||
? (currentTools.includes(tool) ? currentTools : [...currentTools, tool])
|
||||
: currentTools.filter((t) => t !== tool);
|
||||
|
||||
// Optimistic cache update for immediate UI response
|
||||
queryClient.setQueryData(['ccwMcpConfig'], (old: CcwMcpConfig | undefined) => {
|
||||
if (!old) return old;
|
||||
return { ...old, enabledTools: updatedTools };
|
||||
});
|
||||
|
||||
try {
|
||||
await updateCcwConfig({ ...currentConfig, enabledTools: updatedTools });
|
||||
} catch (error) {
|
||||
console.error('Failed to toggle CCW tool:', error);
|
||||
queryClient.setQueryData(['ccwMcpConfig'], previousConfig);
|
||||
}
|
||||
ccwMcpQuery.refetch();
|
||||
};
|
||||
|
||||
const handleUpdateCcwConfig = async (config: Partial<CcwMcpConfig>) => {
|
||||
await updateCcwConfig(config);
|
||||
// Read BEFORE optimistic update to capture actual server state
|
||||
const currentConfig = queryClient.getQueryData<CcwMcpConfig>(['ccwMcpConfig']) ?? ccwConfig;
|
||||
const previousConfig = queryClient.getQueryData<CcwMcpConfig>(['ccwMcpConfig']);
|
||||
|
||||
// Optimistic cache update for immediate UI response
|
||||
queryClient.setQueryData(['ccwMcpConfig'], (old: CcwMcpConfig | undefined) => {
|
||||
if (!old) return old;
|
||||
return { ...old, ...config };
|
||||
});
|
||||
|
||||
try {
|
||||
await updateCcwConfig({ ...currentConfig, ...config });
|
||||
} catch (error) {
|
||||
console.error('Failed to update CCW config:', error);
|
||||
queryClient.setQueryData(['ccwMcpConfig'], previousConfig);
|
||||
}
|
||||
ccwMcpQuery.refetch();
|
||||
};
|
||||
|
||||
@@ -378,15 +411,48 @@ export function McpManagerPage() {
|
||||
};
|
||||
|
||||
const handleToggleCcwToolCodex = async (tool: string, enabled: boolean) => {
|
||||
const currentConfig = queryClient.getQueryData<CcwMcpConfig>(['ccwMcpConfigCodex']) ?? ccwCodexConfig;
|
||||
const currentTools = currentConfig.enabledTools;
|
||||
|
||||
const updatedTools = enabled
|
||||
? [...ccwCodexConfig.enabledTools, tool]
|
||||
: ccwCodexConfig.enabledTools.filter((t) => t !== tool);
|
||||
await updateCcwConfigForCodex({ enabledTools: updatedTools });
|
||||
? [...currentTools, tool]
|
||||
: currentTools.filter((t) => t !== tool);
|
||||
|
||||
queryClient.setQueryData(['ccwMcpConfigCodex'], (old: CcwMcpConfig | undefined) => {
|
||||
if (!old) return old;
|
||||
return { ...old, enabledTools: updatedTools };
|
||||
});
|
||||
|
||||
try {
|
||||
await updateCcwConfigForCodex({
|
||||
enabledTools: updatedTools,
|
||||
projectRoot: currentConfig.projectRoot,
|
||||
allowedDirs: currentConfig.allowedDirs,
|
||||
disableSandbox: currentConfig.disableSandbox,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to toggle CCW tool (Codex):', error);
|
||||
}
|
||||
ccwMcpCodexQuery.refetch();
|
||||
};
|
||||
|
||||
const handleUpdateCcwConfigCodex = async (config: Partial<CcwMcpConfig>) => {
|
||||
await updateCcwConfigForCodex(config);
|
||||
queryClient.setQueryData(['ccwMcpConfigCodex'], (old: CcwMcpConfig | undefined) => {
|
||||
if (!old) return old;
|
||||
return { ...old, ...config };
|
||||
});
|
||||
|
||||
try {
|
||||
const currentConfig = queryClient.getQueryData<CcwMcpConfig>(['ccwMcpConfigCodex']) ?? ccwCodexConfig;
|
||||
await updateCcwConfigForCodex({
|
||||
enabledTools: config.enabledTools ?? currentConfig.enabledTools,
|
||||
projectRoot: config.projectRoot ?? currentConfig.projectRoot,
|
||||
allowedDirs: config.allowedDirs ?? currentConfig.allowedDirs,
|
||||
disableSandbox: config.disableSandbox ?? currentConfig.disableSandbox,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to update CCW config (Codex):', error);
|
||||
}
|
||||
ccwMcpCodexQuery.refetch();
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user