Add unit tests for skill capabilities, skill planner, and UV setup
- Implement tests for random ID generation, ensuring preference for crypto.randomUUID. - Create tests for runtime context capabilities, validating the injection of enabled skill capabilities. - Add tests for skill capability parsing, including classification and command example extraction. - Introduce tests for the skill planner, verifying tool call planning based on user requests and attachment requirements. - Establish tests for UV setup, ensuring proper handling of Python installation scenarios and environment checks.
This commit is contained in:
@@ -1,4 +1,10 @@
|
||||
import { BrowserWindow } from 'electron';
|
||||
import { ClawHubService } from '@electron/gateway/clawhub';
|
||||
import {
|
||||
hydrateSkillCapabilityRegistry,
|
||||
refreshSkillCapabilityRegistry,
|
||||
} from '@electron/gateway/skill-capability-registry';
|
||||
import { windowManager } from '@electron/service/window-service';
|
||||
import {
|
||||
SkillInstallService,
|
||||
SkillInstallServiceError,
|
||||
@@ -9,17 +15,34 @@ import type { GatewayEvent, GatewayRpcParams, GatewayRpcReturns } from '../types
|
||||
|
||||
type GatewayBroadcast = (event: GatewayEvent) => void;
|
||||
|
||||
function broadcastGatewayEvent(event: GatewayEvent): void {
|
||||
const mainWindow = BrowserWindow.getAllWindows().find(
|
||||
(win) => windowManager.getName(win) === 'main',
|
||||
) ?? BrowserWindow.getAllWindows().find((win) => !win.isDestroyed());
|
||||
if (mainWindow && !mainWindow.isDestroyed()) {
|
||||
mainWindow.webContents.send('gateway:event', event);
|
||||
}
|
||||
}
|
||||
|
||||
function broadcastSkillsRuntimeChanged(broadcast?: GatewayBroadcast, reason = 'skills:changed'): void {
|
||||
broadcast?.({
|
||||
const event: GatewayEvent = {
|
||||
type: 'runtime:changed',
|
||||
topics: ['skills'],
|
||||
reason,
|
||||
syncedAt: new Date().toISOString(),
|
||||
});
|
||||
};
|
||||
|
||||
if (broadcast) {
|
||||
broadcast(event);
|
||||
return;
|
||||
}
|
||||
|
||||
broadcastGatewayEvent(event);
|
||||
}
|
||||
|
||||
export async function handleSkillsStatus(): Promise<GatewayRpcReturns['skills.status']> {
|
||||
const configs = await getAllSkillConfigs();
|
||||
hydrateSkillCapabilityRegistry(configs);
|
||||
|
||||
return {
|
||||
skills: Object.entries(configs).map(([skillKey, config]) => ({
|
||||
@@ -47,6 +70,7 @@ export async function handleSkillsStatus(): Promise<GatewayRpcReturns['skills.st
|
||||
|
||||
export async function handleSkillsUpdate(
|
||||
params: { skillKey: string; enabled?: boolean },
|
||||
broadcast?: GatewayBroadcast,
|
||||
): Promise<GatewayRpcReturns['skills.update']> {
|
||||
const { skillKey, enabled } = params;
|
||||
if (!skillKey || !String(skillKey).trim()) {
|
||||
@@ -58,6 +82,17 @@ export async function handleSkillsUpdate(
|
||||
throw new Error(result.error || 'Failed to update skill');
|
||||
}
|
||||
|
||||
try {
|
||||
const configs = await getAllSkillConfigs();
|
||||
hydrateSkillCapabilityRegistry(configs);
|
||||
} catch (error) {
|
||||
console.warn('Failed to refresh skill capability registry after skills.update:', error);
|
||||
}
|
||||
|
||||
const normalizedSkillKey = String(skillKey).trim();
|
||||
const action = enabled === false ? 'disabled' : enabled === true ? 'enabled' : 'updated';
|
||||
broadcastSkillsRuntimeChanged(broadcast, `skills:update:${normalizedSkillKey}:${action}`);
|
||||
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
@@ -72,6 +107,11 @@ export async function handleSkillsInstall(
|
||||
|
||||
try {
|
||||
const result = await installService.install(request);
|
||||
try {
|
||||
await refreshSkillCapabilityRegistry();
|
||||
} catch (error) {
|
||||
console.warn('Failed to refresh skill capability registry after skills.install:', error);
|
||||
}
|
||||
broadcastSkillsRuntimeChanged(
|
||||
broadcast,
|
||||
`skills:install:${result.source}:${result.slug}`,
|
||||
|
||||
Reference in New Issue
Block a user