chore: checkpoint admin restore state

This commit is contained in:
john
2026-06-30 20:26:33 +08:00
parent f2172322fd
commit f9a7584ad4
63 changed files with 7555 additions and 1030 deletions
+306
View File
@@ -1,18 +1,31 @@
import type {
AdminDashboardSummary,
AdminServiceRestartAction,
AdminServiceRestartResult,
AdminSubscription,
AdminUserRow,
AuthStatus,
BlockedWord,
CapabilityDefinition,
CapabilityMap,
InsufficientBalanceDetails,
LedgerEntry,
LlmConnectionTestResult,
LlmExecutorBinding,
LlmExecutorId,
LlmExecutorLaunchPlan,
LlmExecutorLaunchState,
LlmExecutorRuntime,
LlmGlobalSettings,
LlmVisionSettings,
LlmProviderDefinition,
LlmProviderKeyRow,
PlanDefinition,
PlanSyncResult,
PolicyDefinition,
PolicyMap,
PortalUser,
MindSpaceAdminConfig,
SkillDefinition,
SkillMap,
UsageRecord,
@@ -21,6 +34,7 @@ import type {
WechatDeliveryLog,
WechatDigestSubscription,
WechatMessage,
WechatWebNotification,
} from '../types';
export class ApiError extends Error {
@@ -179,6 +193,14 @@ export async function getAdminDashboardSummary(): Promise<AdminDashboardSummary>
return result.summary;
}
export async function restartAdminService(
action: AdminServiceRestartAction,
): Promise<AdminServiceRestartResult> {
return portalFetch<AdminServiceRestartResult>(`/admin-api/service-restart/${action}`, {
method: 'POST',
});
}
export async function listAdminUsage(params?: {
userId?: string;
page?: number;
@@ -241,6 +263,21 @@ export async function getWechatAdminSummary(): Promise<WechatAdminSummary> {
};
}
export async function getMindSpaceAdminConfig(): Promise<MindSpaceAdminConfig> {
const result = await portalFetch<{ config: MindSpaceAdminConfig }>('/admin-api/mindspace/config');
return result.config;
}
export async function updateMindSpaceAdminConfig(
payload: Partial<MindSpaceAdminConfig>,
): Promise<MindSpaceAdminConfig> {
const result = await portalFetch<{ config: MindSpaceAdminConfig }>('/admin-api/mindspace/config', {
method: 'PATCH',
body: JSON.stringify(payload),
});
return result.config;
}
export async function listWechatBindings(params?: {
search?: string;
limit?: number;
@@ -293,6 +330,42 @@ export async function listWechatDeliveries(params?: {
return result.deliveries ?? [];
}
export async function listWechatWebNotifications(params?: {
status?: string;
limit?: number;
}): Promise<WechatWebNotification[]> {
const q = new URLSearchParams();
if (params?.status) q.set('status', params.status);
if (params?.limit) q.set('limit', String(params.limit));
const result = await portalFetch<{ notifications: WechatWebNotification[] }>(
`/admin-api/wechat/web-notifications${q.toString() ? `?${q}` : ''}`,
);
return result.notifications ?? [];
}
export async function createWechatWebNotification(payload: {
userId?: string;
userIds?: string[];
audience?: 'all';
allUsers?: boolean;
title: string;
body: string;
notificationType?: string;
channel?: 'web' | 'wechat';
channels?: Array<'web' | 'wechat'>;
}): Promise<{
ok: boolean;
created: number;
wechatSent: number;
wechatFailures: Array<{ userId: string; message: string }>;
targets: number;
}> {
return portalFetch('/admin-api/wechat/web-notifications', {
method: 'POST',
body: JSON.stringify(payload),
});
}
export async function clearWechatRoute(userId: string): Promise<{ ok: boolean; deleted: number }> {
return portalFetch(`/admin-api/wechat/users/${userId}/route/clear`, { method: 'POST' });
}
@@ -328,6 +401,11 @@ export async function listAdminUsers(params?: {
return { items: result.users ?? [], total, page: result.page ?? 1, pageSize, totalPages: Math.ceil(total / pageSize) };
}
export async function getAdminUser(userId: string): Promise<PortalUser> {
const result = await portalFetch<{ user: PortalUser }>(`/admin-api/users/${userId}`);
return result.user;
}
export async function createAdminUser(payload: {
username: string;
password: string;
@@ -351,6 +429,7 @@ export async function updateAdminUser(
status: 'active' | 'suspended' | 'disabled';
workspaceRoot: string;
balanceCents: number;
spaceQuotaBytes: number;
role: 'user' | 'admin';
}>,
): Promise<PortalUser> {
@@ -593,6 +672,109 @@ export async function getLlmGlobalSettings(): Promise<LlmGlobalSettings> {
return result.global;
}
export async function getLlmVisionSettings(): Promise<LlmVisionSettings> {
const result = await portalFetch<{ vision: LlmVisionSettings }>('/admin-api/llm-providers/vision');
return result.vision;
}
export async function setLlmVisionKey(keyId: string, model: string): Promise<LlmVisionSettings> {
const result = await portalFetch<{ vision: LlmVisionSettings }>('/admin-api/llm-providers/vision', {
method: 'PUT',
body: JSON.stringify({ keyId, model }),
});
return result.vision;
}
export async function clearLlmVisionKey(): Promise<void> {
await portalFetch('/admin-api/llm-providers/vision', { method: 'DELETE' });
}
export async function listLlmExecutorBindings(): Promise<LlmExecutorBinding[]> {
const result = await portalFetch<{ bindings: LlmExecutorBinding[] }>(
'/admin-api/llm-providers/executor-bindings',
);
return result.bindings ?? [];
}
export async function setLlmExecutorBinding(
executor: LlmExecutorId,
payload: { keyId: string | null; model: string; enabled: boolean; purpose?: string },
): Promise<LlmExecutorBinding> {
const result = await portalFetch<{ binding: LlmExecutorBinding }>(
`/admin-api/llm-providers/executor-bindings/${executor}`,
{ method: 'PUT', body: JSON.stringify(payload) },
);
return result.binding;
}
export async function listLlmExecutorRuntime(): Promise<LlmExecutorRuntime[]> {
const result = await portalFetch<{ runtimes: LlmExecutorRuntime[] }>(
'/admin-api/llm-providers/executor-runtime',
);
return result.runtimes ?? [];
}
export async function listLlmExecutorLaunchPlans(params: {
mode?: 'headless' | 'serve';
cwd?: string;
instruction?: string;
purpose?: string;
} = {}): Promise<LlmExecutorLaunchPlan[]> {
const q = new URLSearchParams();
if (params.mode) q.set('mode', params.mode);
if (params.cwd) q.set('cwd', params.cwd);
if (params.instruction) q.set('instruction', params.instruction);
if (params.purpose) q.set('purpose', params.purpose);
const result = await portalFetch<{ plans: LlmExecutorLaunchPlan[] }>(
`/admin-api/llm-providers/executor-launch-plan${q.toString() ? `?${q}` : ''}`,
);
return result.plans ?? [];
}
export async function listLlmExecutorLaunchStatus(params: {
purpose?: string;
} = {}): Promise<Array<LlmExecutorLaunchState | null>> {
const q = new URLSearchParams();
if (params.purpose) q.set('purpose', params.purpose);
const result = await portalFetch<{ launches: Array<LlmExecutorLaunchState | null> }>(
`/admin-api/llm-providers/executor-launch-status${q.toString() ? `?${q}` : ''}`,
);
return result.launches ?? [];
}
export async function launchLlmExecutor(
executor: LlmExecutorId,
payload: { mode?: 'headless' | 'serve'; cwd?: string; instruction?: string; purpose?: string } = {},
): Promise<LlmExecutorLaunchState> {
const result = await portalFetch<{ launch: LlmExecutorLaunchState }>(
`/admin-api/llm-providers/executor-launch/${executor}`,
{ method: 'POST', body: JSON.stringify(payload) },
);
return result.launch;
}
export async function stopLlmExecutor(
executor: LlmExecutorId,
payload: { purpose?: string; force?: boolean } = {},
): Promise<LlmExecutorLaunchState | null> {
const result = await portalFetch<{ launch: LlmExecutorLaunchState | null }>(
`/admin-api/llm-providers/executor-stop/${executor}`,
{ method: 'POST', body: JSON.stringify(payload) },
);
return result.launch;
}
export async function restartLlmExecutor(
executor: LlmExecutorId,
payload: { mode?: 'headless' | 'serve'; cwd?: string; instruction?: string; purpose?: string } = {},
): Promise<LlmExecutorLaunchState> {
const result = await portalFetch<{ launch: LlmExecutorLaunchState }>(
`/admin-api/llm-providers/executor-restart/${executor}`,
{ method: 'POST', body: JSON.stringify(payload) },
);
return result.launch;
}
export async function setLlmGlobalModel(model: string): Promise<{ global: LlmGlobalSettings }> {
return portalFetch('/admin-api/llm-providers/global', {
method: 'PUT',
@@ -627,3 +809,127 @@ export async function testLlmProviderKey(
body: JSON.stringify(model ? { model } : {}),
});
}
// ── Blocked words ─────────────────────────────────────
export async function listBlockedWords(): Promise<BlockedWord[]> {
const result = await portalFetch<{ words: BlockedWord[] }>('/admin-api/blocked-words');
return result.words ?? [];
}
export async function createBlockedWord(payload: {
word: string;
replacement?: string;
note?: string;
}): Promise<BlockedWord> {
const result = await portalFetch<{ blockedWord: BlockedWord }>('/admin-api/blocked-words', {
method: 'POST',
body: JSON.stringify(payload),
});
return result.blockedWord;
}
export async function updateBlockedWord(
id: string,
payload: Partial<{ word: string; replacement: string; note: string; status: 'active' | 'disabled' }>,
): Promise<BlockedWord> {
const result = await portalFetch<{ blockedWord: BlockedWord }>(`/admin-api/blocked-words/${id}`, {
method: 'PATCH',
body: JSON.stringify(payload),
});
return result.blockedWord;
}
export async function deleteBlockedWord(id: string): Promise<void> {
await portalFetch(`/admin-api/blocked-words/${id}`, { method: 'DELETE' });
}
// ── Subscriptions ──────────────────────────────────────
export async function listSubscriptionPlans(): Promise<PlanDefinition[]> {
const result = await portalFetch<{ plans: PlanDefinition[] }>('/admin-api/subscriptions/plans');
return result.plans;
}
export async function createSubscriptionPlan(
planType: string,
data: Partial<PlanDefinition>,
): Promise<{ plan: PlanDefinition; sync?: PlanSyncResult }> {
const result = await portalFetch<{ plan: PlanDefinition; sync?: PlanSyncResult }>('/admin-api/subscriptions/plans', {
method: 'POST',
body: JSON.stringify({ planType, ...data }),
});
return result;
}
export async function updateSubscriptionPlan(
planType: string,
data: Partial<PlanDefinition>,
): Promise<{ plan: PlanDefinition; sync?: PlanSyncResult }> {
const result = await portalFetch<{ plan: PlanDefinition; sync?: PlanSyncResult }>(`/admin-api/subscriptions/plans/${planType}`, {
method: 'PUT',
body: JSON.stringify(data),
});
return result;
}
export async function deleteSubscriptionPlan(planType: string): Promise<{ ok: boolean; sync?: PlanSyncResult }> {
return portalFetch(`/admin-api/subscriptions/plans/${planType}`, { method: 'DELETE' });
}
export async function syncSubscriptionPlansToProduction(): Promise<PlanSyncResult> {
const result = await portalFetch<{ sync: PlanSyncResult }>('/admin-api/subscriptions/plans/sync-production', {
method: 'POST',
});
return result.sync;
}
export async function listAdminSubscriptions(opts?: {
userId?: string;
status?: string;
page?: number;
pageSize?: number;
}): Promise<{ items: AdminSubscription[]; total: number; page: number; totalPages: number; pageSize: number }> {
const q = new URLSearchParams();
if (opts?.userId) q.set('userId', opts.userId);
if (opts?.status) q.set('status', opts.status);
if (opts?.page) q.set('page', String(opts.page));
if (opts?.pageSize) q.set('pageSize', String(opts.pageSize));
const result = await portalFetch<{
items: AdminSubscription[];
total: number;
page: number;
pageSize: number;
}>(`/admin-api/subscriptions${q.toString() ? `?${q}` : ''}`);
return {
items: result.items,
total: result.total,
page: result.page,
totalPages: Math.ceil(result.total / result.pageSize) || 1,
pageSize: result.pageSize,
};
}
export async function grantUserSubscription(
userId: string,
planType: string,
durationDays?: number,
note?: string,
): Promise<AdminSubscription> {
const result = await portalFetch<{ subscription: AdminSubscription }>(`/admin-api/users/${userId}/subscription`, {
method: 'POST',
body: JSON.stringify({ planType, durationDays, note }),
});
return result.subscription;
}
export async function cancelUserSubscription(userId: string): Promise<void> {
await portalFetch(`/admin-api/users/${userId}/subscription`, { method: 'DELETE' });
}
export async function getUserSubscription(userId: string): Promise<AdminSubscription | null> {
const result = await portalFetch<{ subscription: AdminSubscription | null }>(
`/admin-api/users/${userId}/subscription`,
);
return result.subscription;
}