功能修改

This commit is contained in:
npc0-hue
2026-07-20 16:42:33 +08:00
parent 48b8ad8d6c
commit a0e69417db
224 changed files with 22015 additions and 884 deletions
+238 -8
View File
@@ -11,6 +11,9 @@ export type PluginPermission =
| "server.run.distribution"
| "server.dependencies.manage"
| "server.client-manager.manage"
| "server.game-client.read"
| "server.game-client.command"
| "server.game-client.maintenance"
| "ai.invoke";
export type RunCapability =
@@ -58,6 +61,7 @@ export type PluginBridgeAction =
| "dependencies.request"
| "logs.backfill.request"
| "client-manager.request"
| "plugin-lifecycle.request"
| "ai.invoke";
export type PluginBridgeRequestPayload = Record<string, unknown>;
@@ -115,7 +119,7 @@ export interface PluginAIInvocationResponse {
purpose: AIPurpose;
status: "ok" | "denied" | "error" | string;
recommendation?: string;
suggestedConfig?: string;
configRecommendation?: { diffId: string; key: string; suggestedConfig: string; diffSummary: string; expiresAt: string };
usage?: { model?: string; mocked?: boolean; inputTokens?: number; outputTokens?: number };
error?: PluginBridgeError;
}
@@ -131,6 +135,15 @@ export type PluginLifecycleDispatchPayload = Record<string, string> & {
idempotencyKey: string;
};
export type ProductionPluginLifecycleOperation = "install" | "enable" | "disable" | "upgrade" | "rollback" | "retire" | "dependency-check";
export type PluginProductionLifecyclePayload = Record<string, string> & {
operation: ProductionPluginLifecycleOperation;
targetVersion: string;
idempotencyKey: string;
confirmed: "true" | "false";
};
export type PluginRemoteAccessPayload = Record<string, string> & {
capability: Extract<RunCapability, `remote.${string}`>;
targetKey?: string;
@@ -196,6 +209,165 @@ export interface GamePluginRemoteAccess {
logTransfer?: boolean;
}
export type GameClientBridgeApprovalLevel = "none" | "operator" | "platform-admin";
export type GameClientBridgeApprovalState = "not_required" | "pending" | "approved" | "rejected";
export type GameClientBridgeCommandState = "pending" | "claimed" | "succeeded" | "failed" | "cancelled" | "expired";
export interface GameClientBridgeCommandDeclaration {
type: string;
title: string;
permission: PluginPermission;
approvalLevel: GameClientBridgeApprovalLevel;
payloadSchemaRef: string;
resultSchemaRef?: string;
timeoutSeconds: number;
maxPayloadBytes: number;
}
export interface GameClientBridgeSnapshotDeclaration {
type: string;
schemaVersion: string;
schemaRef: string;
keepForSeconds: number;
maxRecords: number;
}
export interface GameClientBridgeQueryTemplateDeclaration {
key: string;
title: string;
permission: PluginPermission;
engine: "sqlite";
transportKey: string;
targetKey: string;
parameterSchemaRef: string;
resultSchemaRef: string;
maxRows: number;
timeoutSeconds: number;
}
export interface GameClientBridgePageContract {
pageKey: string;
commandTypes?: string[];
snapshotTypes?: string[];
queryTemplateKeys?: string[];
}
export interface GameClientBridgeCompanionDeclaration {
profileKey: string;
configTemplateKey: string;
configSchemaRef: string;
configFormat: "yaml";
platformBaseUrlSource: "run-control";
registrationProof: "hmac-sha256";
proofMaterialSource: "component-package";
proofMaterialEnv: string;
sessionMode: "component-session";
tlsPolicy: "verify-system-roots";
heartbeatIntervalSeconds: number;
commandPollIntervalSeconds: number;
requestTimeoutSeconds: number;
}
export interface GameClientBridgeManifest {
commands: GameClientBridgeCommandDeclaration[];
snapshots: GameClientBridgeSnapshotDeclaration[];
queryTemplates?: GameClientBridgeQueryTemplateDeclaration[];
commandRetentionSeconds: number;
maxCommands: number;
pages?: GameClientBridgePageContract[];
companion?: GameClientBridgeCompanionDeclaration;
}
export interface GameClientBridgeProfileStatus {
pluginId: string;
profileKey: string;
available: boolean;
reason?: string;
commandTypes: string[];
snapshotTypes: string[];
queryTemplateKeys: string[];
}
export interface GameClientBridgeStatus {
serverInstanceId: string;
pluginId: string;
available: boolean;
reason?: string;
profiles: GameClientBridgeProfileStatus[];
}
export interface GameClientBridgeCommandResult {
status: "succeeded" | "failed" | "cancelled";
summary?: string;
payload?: Record<string, unknown>;
completedAt: string;
}
export interface GameClientBridgeCommand {
id: string;
serverInstanceId: string;
pluginId: string;
profileKey: string;
commandType: string;
priority: number;
state: GameClientBridgeCommandState;
approvalState: GameClientBridgeApprovalState;
result?: GameClientBridgeCommandResult;
auditReferences?: string[];
expiresAt: string;
createdAt: string;
updatedAt: string;
completedAt?: string;
}
export interface GameClientBridgeSnapshot<TPayload extends Record<string, unknown> = Record<string, unknown>> {
id: string;
serverInstanceId: string;
pluginId: string;
profileKey: string;
type: string;
schemaVersion: string;
streamKey: string;
sequence: number;
observedAt: string;
payload: TPayload;
auditReferences?: string[];
createdAt: string;
expiresAt: string;
}
export interface GameClientBridgeQueueRequest<TPayload extends Record<string, unknown> = Record<string, unknown>> {
profileKey: string;
commandType: string;
payload: TPayload;
idempotencyKey: string;
priority?: number;
expiresAt: string;
}
export interface GameClientBridgeSnapshotQuery {
profileKey?: string;
type?: string;
streamKey?: string;
observedAfter?: string;
limit?: number;
}
export interface GameClientBridgePageClient {
getStatus(serverInstanceId: string): Promise<GameClientBridgeStatus>;
listCommands(serverInstanceId: string): Promise<GameClientBridgeCommand[]>;
queueCommand<TPayload extends Record<string, unknown>>(serverInstanceId: string, request: GameClientBridgeQueueRequest<TPayload>): Promise<GameClientBridgeCommand>;
cancelCommand(serverInstanceId: string, commandId: string, reason?: string): Promise<GameClientBridgeCommand>;
querySnapshots<TPayload extends Record<string, unknown> = Record<string, unknown>>(serverInstanceId: string, query?: GameClientBridgeSnapshotQuery): Promise<Array<GameClientBridgeSnapshot<TPayload>>>;
}
export function createGameClientBridgeQueueRequest<TPayload extends Record<string, unknown>>(input: GameClientBridgeQueueRequest<TPayload>): GameClientBridgeQueueRequest<TPayload> {
if (!input.profileKey || !input.commandType || !input.idempotencyKey || !input.expiresAt) {
throw new Error("profileKey, commandType, idempotencyKey, and expiresAt are required");
}
return { profileKey: input.profileKey, commandType: input.commandType, payload: { ...input.payload }, idempotencyKey: input.idempotencyKey, priority: input.priority, expiresAt: input.expiresAt };
}
export type RuntimePlatform = "windows" | "linux" | "darwin";
export type RuntimeArch = "amd64" | "arm64";
export type RuntimeTarget = { os: RuntimePlatform; arch: RuntimeArch };
@@ -254,6 +426,19 @@ export interface RuntimeLogSource {
retentionDays?: number;
}
export type RuntimeLogEventSeverity = "info" | "notice" | "warning" | "critical";
export interface RuntimeLogEventDeclaration {
key: string;
title: string;
sourceKey: string;
eventType: string;
permission: PluginPermission;
schemaRef: string;
retentionDays: number;
severity: RuntimeLogEventSeverity;
}
export interface RuntimeTransportProfile {
key: string;
kind: "file" | "ftp" | "rsync" | "mysql" | "sqlite" | "rcon";
@@ -318,6 +503,7 @@ export interface GamePluginRuntimeProfiles {
dependencyProbes?: RuntimeDependencyProbe[];
installPlans?: RuntimeInstallPlan[];
logSources?: RuntimeLogSource[];
logEvents?: RuntimeLogEventDeclaration[];
transportProfiles?: RuntimeTransportProfile[];
clientManagers?: RuntimeClientManagerProfile[];
}
@@ -380,6 +566,7 @@ export const pluginBridgeActionPolicies: Record<PluginBridgeAction, PluginBridge
"dependencies.request": { permissions: ["server.dependencies.manage"] },
"logs.backfill.request": { permissions: ["server.logs.read"] },
"client-manager.request": { permissions: ["server.client-manager.manage"] },
"plugin-lifecycle.request": { permissions: ["server.lifecycle"] },
"ai.invoke": { permissions: ["ai.invoke"], aiPurposeRequired: true }
};
@@ -432,10 +619,18 @@ export interface GamePluginManifest {
permissions: PluginPermission[];
remoteAccess?: GamePluginRemoteAccess;
runtimeProfiles?: GamePluginRuntimeProfiles;
gameClientBridge?: GameClientBridgeManifest;
actions?: GamePluginActions;
productionLifecycle: {
operations: ProductionPluginLifecycleOperation[];
dependencyPolicy: "required" | "optional";
approvalRequired: Array<"disable" | "rollback" | "retire">;
};
pages?: GamePluginPage[];
ai?: {
purposes?: AIPurpose[];
mediation: "platform";
configWritePolicy: "review-required";
};
}
@@ -533,24 +728,59 @@ export function createLifecycleDispatchRequest(input: {
});
}
export function createProductionPluginLifecycleRequest(input: {
requestId: string;
context: PluginBridgeContext;
operation: ProductionPluginLifecycleOperation;
targetVersion?: string;
idempotencyKey: string;
confirmed?: boolean;
}): PluginBridgeExecutionRequest<PluginProductionLifecyclePayload> {
if (!input.context.serverInstanceId) {
throw new Error("serverInstanceId is required for plugin lifecycle requests");
}
if (["disable", "rollback", "retire"].includes(input.operation) && !input.confirmed) {
throw new Error("disruptive plugin lifecycle requests require confirmation");
}
return createBridgeExecutionRequest({
requestId: input.requestId,
context: input.context,
action: "plugin-lifecycle.request",
payload: {
operation: input.operation,
targetVersion: input.targetVersion ?? "",
idempotencyKey: input.idempotencyKey,
confirmed: input.confirmed ? "true" : "false"
}
});
}
export function createRemoteAccessRequest(input: {
requestId: string;
context: PluginBridgeContext;
capability: PluginRemoteAccessPayload["capability"];
targetKey?: string;
inputRef?: string;
inputs?: Record<string, string>;
idempotencyKey: string;
}): PluginBridgeExecutionRequest<PluginRemoteAccessPayload> {
const payload: PluginRemoteAccessPayload = {
capability: input.capability,
targetKey: input.targetKey ?? "",
inputRef: input.inputRef ?? "",
idempotencyKey: input.idempotencyKey
};
for (const [key, value] of Object.entries(input.inputs ?? {})) {
if (!/^[A-Za-z0-9][A-Za-z0-9._:-]{0,159}$/.test(key) || /(sql|query|shell|script|password|secret|token|credential|dsn|path)/i.test(key)) {
throw new Error(`remote adapter input key is unsafe: ${key}`);
}
payload[`input.${key}`] = value;
}
return createBridgeExecutionRequest({
requestId: input.requestId,
context: input.context,
action: "remote.access.request",
payload: {
capability: input.capability,
targetKey: input.targetKey ?? "",
inputRef: input.inputRef ?? "",
idempotencyKey: input.idempotencyKey
}
payload
});
}
@@ -781,7 +1011,7 @@ export function parseAIInvocationResponse(response: PluginAIInvocationResponse):
purpose: response.purpose,
status: response.status,
recommendation: response.recommendation,
suggestedConfig: response.suggestedConfig,
configRecommendation: response.configRecommendation ? { ...response.configRecommendation } : undefined,
usage: response.usage ? { ...response.usage } : undefined,
error: response.error ? bridgeError(response.error.code, response.error.message, response.error.details ?? []) : undefined
};