吸收数字员工安全服务重启入口

This commit is contained in:
baiyanyun
2026-06-09 23:10:01 +08:00
parent 0d2008b35c
commit 91540dec0c
13 changed files with 717 additions and 155 deletions

View File

@@ -26,6 +26,7 @@ import type {
IngressRouteResponse,
GovernanceCommandRequest,
GovernanceCommandResponse,
DigitalEmployeeManagedService,
DigitalEmployeeWorkdayProjection,
DigitalEmployeeWorkdayActionRequest,
PlanDispatchResponse,
@@ -613,6 +614,26 @@ export function postDigitalEmployeeWorkdayAction(
});
}
export function restartManagedService(
serviceId: string,
body: { reason?: string; actor?: string } = {},
): Promise<{
ok: boolean;
service_id: string;
action: 'restart';
status: 'success' | 'failed' | 'rejected';
message?: string;
error?: string;
managed_service?: DigitalEmployeeManagedService | null;
event_id?: string | null;
}> {
return apiFetch(`/api/digital-employee/managed-services/${encodeURIComponent(serviceId)}/restart`, {
method: 'POST',
body: JSON.stringify(body),
timeoutMs: DIGITAL_EMPLOYEE_WORKDAY_TIMEOUT_MS,
});
}
export function dispatchPlanNow(planId: string): Promise<PlanDispatchResponse> {
return apiFetch<PlanDispatchResponse>(`/api/debug/plan/${encodeURIComponent(planId)}/dispatch`, {
method: 'POST',

View File

@@ -63,6 +63,7 @@ declare global {
recordRouteDecision?: (input: QimingclawRouteDecisionInput) => Promise<RouteDecisionRecord>;
recordGovernanceCommand?: (command: QimingclawGovernanceCommandRecord) => Promise<unknown>;
recordDailyReport?: (input: QimingclawDailyReportRecordInput) => Promise<QimingclawDailyReportRecordResult | null>;
restartManagedService?: (serviceId: string, options?: { reason?: string | null; actor?: string | null }) => Promise<QimingclawManagedServiceActionResponse>;
respondPermission?: (sessionId: string, permissionId: string, response: 'once' | 'always' | 'reject') => Promise<{ success?: boolean; error?: string }>;
};
};
@@ -236,6 +237,17 @@ interface QimingclawDailyReportRecordResult {
eventId: string;
}
interface QimingclawManagedServiceActionResponse {
ok: boolean;
service_id: string;
action: 'restart';
status: 'success' | 'failed' | 'rejected';
message?: string;
error?: string;
managed_service?: DigitalEmployeeManagedService | null;
event_id?: string | null;
}
interface QimingclawRouteDecisionInput {
id?: string | null;
idempotencyKey?: string | null;
@@ -625,6 +637,13 @@ export async function handleQimingclawDigitalApi<T>(
if (method === 'POST' && pathname === '/api/digital-employee/workday/actions') {
return await handleWorkdayAction(parseJsonBody<DigitalEmployeeWorkdayActionRequest>(options.body), await readQimingclawSnapshot()) as T;
}
const managedServiceRestartMatch = pathname.match(/^\/api\/(?:digital-employee\/)?managed-services\/([^/]+)\/restart$/);
if (method === 'POST' && managedServiceRestartMatch) {
return await handleManagedServiceRestart(
decodeURIComponent(managedServiceRestartMatch[1] || ''),
parseOptionalJsonBody(options.body),
) as T;
}
const dailyReportDetailMatch = pathname.match(/^\/api\/digital-employee\/daily-reports\/([^/]+)$/);
if (method === 'GET' && dailyReportDetailMatch) {
const reportId = decodeURIComponent(dailyReportDetailMatch[1] || '');
@@ -1289,6 +1308,45 @@ function managedServiceSummary(services: DigitalEmployeeManagedService[]): strin
return `ManagedService${runningCount}/${services.length} 运行,${issueCount} 项需处理`;
}
async function handleManagedServiceRestart(
serviceId: string,
body: Record<string, unknown>,
): Promise<QimingclawManagedServiceActionResponse> {
const bridge = window.QimingClawBridge?.digital;
if (!bridge?.restartManagedService) {
const snapshot = await readQimingclawSnapshot();
return {
ok: false,
service_id: serviceId,
action: 'restart',
status: 'failed',
error: 'bridge_unavailable',
managed_service: buildManagedServices(snapshot).find((service) => service.service_id === serviceId) ?? null,
};
}
try {
const result = await bridge.restartManagedService(serviceId, {
reason: stringValue(body.reason) || 'digital_employee_managed_service_restart',
actor: stringValue(body.actor) || 'digital_employee_ui',
});
const snapshot = await readQimingclawSnapshot();
return {
...result,
managed_service: result.managed_service ?? buildManagedServices(snapshot).find((service) => service.service_id === serviceId) ?? null,
};
} catch (error) {
const snapshot = await readQimingclawSnapshot();
return {
ok: false,
service_id: serviceId,
action: 'restart',
status: 'failed',
error: error instanceof Error ? error.message : String(error),
managed_service: buildManagedServices(snapshot).find((service) => service.service_id === serviceId) ?? null,
};
}
}
function syncLine(snapshot: QimingclawSnapshot | null): string {
const sync = snapshot?.sync;
if (!sync) return '管理端同步:未连接';