feat(client): enrich digital skill catalog

This commit is contained in:
baiyanyun
2026-06-07 20:04:38 +08:00
parent 0f0bffe695
commit ee51fcdbeb
12 changed files with 643 additions and 263 deletions

View File

@@ -70,6 +70,24 @@ export interface SkillSummary {
category: string;
capabilityLevel: 'core' | 'standard' | 'specialized' | 'experimental';
source: 'skill-api';
serverId?: string | null;
transport?: string | null;
running?: boolean | null;
toolCount?: number | null;
tools?: string[];
allowTools?: string[];
denyTools?: string[];
governancePolicy?: 'allow' | 'deny' | 'open' | 'disabled' | null;
recentCalls?: Array<{
eventId: string;
message: string;
status?: string | null;
occurredAt: string;
toolName?: string | null;
projectId?: string | null;
}>;
callCount?: number;
lastCalledAt?: string | null;
}
export interface DataSourceStatus {
@@ -87,6 +105,10 @@ function arr(v: unknown): Obj[] {
return Array.isArray(v) ? (v as Obj[]) : [];
}
function obj(v: unknown): Obj | null {
return v && typeof v === 'object' && !Array.isArray(v) ? v as Obj : null;
}
function str(v: unknown, fallback = ''): string {
if (typeof v === 'string') return v;
if (typeof v === 'number') return String(v);
@@ -456,6 +478,7 @@ export function adaptSkillSummaries(skillsData: Obj[] | null): SkillSummary[] {
if (!skillsData) return [];
return skillsData.map((s: Obj) => {
const sid = str(s.skill_id, str(s.id));
const governance = obj(s.governance);
return {
id: sid,
name: zhName(sid, str(s.name, sid)),
@@ -465,10 +488,51 @@ export function adaptSkillSummaries(skillsData: Obj[] | null): SkillSummary[] {
category: s.category ? str(s.category, categoryFor(sid)) : categoryFor(sid),
capabilityLevel: capabilityLevelFor(s.capability_level ?? s.capabilityLevel),
source: 'skill-api' as const,
serverId: s.server_id ? str(s.server_id) : null,
transport: s.transport ? str(s.transport) : null,
running: typeof s.running === 'boolean' ? s.running : null,
toolCount: num(s.tool_count),
tools: stringList(s.tools),
allowTools: stringList(s.allow_tools ?? governance?.server_allow_tools ?? governance?.global_allow_tools),
denyTools: stringList(s.deny_tools ?? governance?.server_deny_tools ?? governance?.global_deny_tools),
governancePolicy: governancePolicy(s.governance_policy ?? governance?.effective_policy),
recentCalls: arr(s.recent_calls).map((call) => {
const c = obj(call) ?? {};
return {
eventId: str(c.event_id, str(c.id)),
message: str(c.message),
status: c.status ? str(c.status) : null,
occurredAt: str(c.occurred_at, str(c.occurredAt)),
toolName: c.tool_name ? str(c.tool_name) : null,
projectId: c.project_id ? str(c.project_id) : null,
};
}).filter((call) => call.eventId || call.message),
callCount: num(s.call_count) ?? 0,
lastCalledAt: s.last_called_at ? str(s.last_called_at) : null,
};
});
}
function stringList(value: unknown): string[] {
if (!Array.isArray(value)) return [];
return value.filter((item): item is string => typeof item === 'string' && item.trim().length > 0).map((item) => item.trim());
}
function num(value: unknown): number | null {
if (typeof value === 'number' && Number.isFinite(value)) return value;
if (typeof value === 'string' && value.trim()) {
const parsed = Number(value);
return Number.isFinite(parsed) ? parsed : null;
}
return null;
}
function governancePolicy(value: unknown): SkillSummary['governancePolicy'] {
return value === 'allow' || value === 'deny' || value === 'open' || value === 'disabled'
? value
: null;
}
export function adaptJournalEntries(storeData: Obj | null): JournalEntry[] {
if (!storeData) return [];
const tables = (storeData.tables ?? {}) as Obj;