mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-01 20:23:36 +00:00
refactor: enhance skills and subagents settings management
- Updated useSkillsSettings and useSubagents hooks to improve state management and error handling. - Added new settings API methods for skills configuration and agent discovery. - Refactored app-store to include enableSkills and skillsSources state management. - Enhanced settings migration to sync skills configuration with the server. These changes streamline the management of skills and subagents, ensuring better integration and user experience.
This commit is contained in:
@@ -11,17 +11,20 @@ import { toast } from 'sonner';
|
||||
import { getElectronAPI } from '@/lib/electron';
|
||||
|
||||
export function useSkillsSettings() {
|
||||
const { settings } = useAppStore();
|
||||
const enabled = useAppStore((state) => state.enableSkills);
|
||||
const sources = useAppStore((state) => state.skillsSources);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const enabled = settings?.enableSkills ?? true;
|
||||
const sources = settings?.skillsSources ?? ['user', 'project'];
|
||||
|
||||
const updateEnabled = async (newEnabled: boolean) => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const api = getElectronAPI();
|
||||
if (!api.settings) {
|
||||
throw new Error('Settings API not available');
|
||||
}
|
||||
await api.settings.updateGlobal({ enableSkills: newEnabled });
|
||||
// Update local store after successful server update
|
||||
useAppStore.setState({ enableSkills: newEnabled });
|
||||
toast.success(newEnabled ? 'Skills enabled' : 'Skills disabled');
|
||||
} catch (error) {
|
||||
toast.error('Failed to update skills settings');
|
||||
@@ -35,7 +38,12 @@ export function useSkillsSettings() {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const api = getElectronAPI();
|
||||
if (!api.settings) {
|
||||
throw new Error('Settings API not available');
|
||||
}
|
||||
await api.settings.updateGlobal({ skillsSources: newSources });
|
||||
// Update local store after successful server update
|
||||
useAppStore.setState({ skillsSources: newSources });
|
||||
toast.success('Skills sources updated');
|
||||
} catch (error) {
|
||||
toast.error('Failed to update skills sources');
|
||||
|
||||
@@ -3,27 +3,28 @@
|
||||
*
|
||||
* Provides read-only view of custom subagent configurations
|
||||
* used for specialized task delegation. Supports:
|
||||
* - Programmatic agents (stored in settings JSON) - global and project-level
|
||||
* - Filesystem agents (AGENT.md files in .claude/agents/) - user and project-level (read-only)
|
||||
*
|
||||
* Filesystem agents are discovered via the server API and displayed in the UI.
|
||||
* Agent definitions in settings JSON are used server-side only.
|
||||
*/
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { useAppStore } from '@/store/app-store';
|
||||
import type { AgentDefinition } from '@automaker/types';
|
||||
import { getElectronAPI } from '@/lib/electron';
|
||||
|
||||
export type SubagentScope = 'global' | 'project';
|
||||
export type SubagentType = 'programmatic' | 'filesystem';
|
||||
export type SubagentType = 'filesystem';
|
||||
export type FilesystemSource = 'user' | 'project';
|
||||
|
||||
export interface SubagentWithScope {
|
||||
name: string;
|
||||
definition: AgentDefinition;
|
||||
scope: SubagentScope; // For programmatic agents
|
||||
scope: SubagentScope;
|
||||
type: SubagentType;
|
||||
// For filesystem agents:
|
||||
source?: FilesystemSource;
|
||||
filePath?: string;
|
||||
source: FilesystemSource;
|
||||
filePath: string;
|
||||
}
|
||||
|
||||
interface FilesystemAgent {
|
||||
@@ -34,71 +35,46 @@ interface FilesystemAgent {
|
||||
}
|
||||
|
||||
export function useSubagents() {
|
||||
const { settings, currentProject, projectSettings } = useAppStore();
|
||||
const currentProject = useAppStore((state) => state.currentProject);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [subagentsWithScope, setSubagentsWithScope] = useState<SubagentWithScope[]>([]);
|
||||
const [filesystemAgents, setFilesystemAgents] = useState<FilesystemAgent[]>([]);
|
||||
|
||||
// Fetch filesystem agents
|
||||
const fetchFilesystemAgents = async () => {
|
||||
const fetchFilesystemAgents = useCallback(async () => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const api = getElectronAPI();
|
||||
if (!api.settings) {
|
||||
console.warn('Settings API not available');
|
||||
return;
|
||||
}
|
||||
const data = await api.settings.discoverAgents(currentProject?.path, ['user', 'project']);
|
||||
|
||||
if (data.success) {
|
||||
setFilesystemAgents(data.agents || []);
|
||||
if (data.success && data.agents) {
|
||||
// Transform filesystem agents to SubagentWithScope format
|
||||
const agents: SubagentWithScope[] = data.agents.map(
|
||||
({ name, definition, source, filePath }: FilesystemAgent) => ({
|
||||
name,
|
||||
definition,
|
||||
scope: source === 'user' ? 'global' : 'project',
|
||||
type: 'filesystem' as const,
|
||||
source,
|
||||
filePath,
|
||||
})
|
||||
);
|
||||
setSubagentsWithScope(agents);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch filesystem agents:', error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
}, [currentProject?.path]);
|
||||
|
||||
// Fetch filesystem agents on mount and when project changes
|
||||
useEffect(() => {
|
||||
fetchFilesystemAgents();
|
||||
}, [currentProject?.path]);
|
||||
|
||||
// Merge programmatic and filesystem agents
|
||||
useEffect(() => {
|
||||
const globalSubagents = settings?.customSubagents || {};
|
||||
const projectSubagents = projectSettings?.customSubagents || {};
|
||||
|
||||
const merged: SubagentWithScope[] = [];
|
||||
|
||||
// Add programmatic global agents
|
||||
Object.entries(globalSubagents).forEach(([name, definition]) => {
|
||||
merged.push({ name, definition, scope: 'global', type: 'programmatic' });
|
||||
});
|
||||
|
||||
// Add programmatic project agents (override globals with same name)
|
||||
Object.entries(projectSubagents).forEach(([name, definition]) => {
|
||||
const globalIndex = merged.findIndex((s) => s.name === name && s.scope === 'global');
|
||||
if (globalIndex !== -1) {
|
||||
merged.splice(globalIndex, 1);
|
||||
}
|
||||
merged.push({ name, definition, scope: 'project', type: 'programmatic' });
|
||||
});
|
||||
|
||||
// Add filesystem agents
|
||||
filesystemAgents.forEach(({ name, definition, source, filePath }) => {
|
||||
// Remove any programmatic agents with the same name (filesystem takes precedence)
|
||||
const programmaticIndex = merged.findIndex((s) => s.name === name);
|
||||
if (programmaticIndex !== -1) {
|
||||
merged.splice(programmaticIndex, 1);
|
||||
}
|
||||
|
||||
merged.push({
|
||||
name,
|
||||
definition,
|
||||
scope: source === 'user' ? 'global' : 'project',
|
||||
type: 'filesystem',
|
||||
source,
|
||||
filePath,
|
||||
});
|
||||
});
|
||||
|
||||
setSubagentsWithScope(merged);
|
||||
}, [settings?.customSubagents, projectSettings?.customSubagents, filesystemAgents]);
|
||||
}, [fetchFilesystemAgents]);
|
||||
|
||||
return {
|
||||
subagentsWithScope,
|
||||
|
||||
Reference in New Issue
Block a user