feat(scum): add file config workbench

This commit is contained in:
npc0-hue
2026-07-28 14:43:24 +08:00
parent e739dd9c79
commit e4ef4024a8
22 changed files with 397 additions and 109 deletions
+12 -6
View File
@@ -1,14 +1,14 @@
import { describe, expect, it } from "vitest";
import type { GamePluginResponse } from "../api/types";
import { resolveScumOperationsPageContract } from "./scumOperations";
import { normalizeScumRouteKey, resolveScumOperationsPageContract } from "./scumOperations";
const plugin = {
id: "game.scum",
pages: [{
key: "operations",
title: "SCUM 运维",
path: "/operations",
key: "files-config",
title: "文件与配置",
path: "/files-config",
permissions: ["server.game-client.read", "server.game-client.command", "server.remote.access", "unknown.permission"],
bridgeActions: ["server.instances.read", "logs.query", "remote.access.request", "unknown.action"]
}],
@@ -26,7 +26,7 @@ const plugin = {
],
commandRetentionSeconds: 86400,
maxCommands: 1000,
pages: [{ pageKey: "operations", commandTypes: ["announcement.send"], snapshotTypes: ["companion.health"], queryTemplateKeys: ["scum.player.search"] }]
pages: [{ pageKey: "files-config", commandTypes: ["announcement.send"], snapshotTypes: ["companion.health"], queryTemplateKeys: ["scum.player.search"] }]
},
runtimeProfiles: {
logSources: [{ key: "scum-chat-events", kind: "file.tail", streamKey: "scum.chat", retentionDays: 30 }],
@@ -42,7 +42,7 @@ describe("SCUM operations page contract", () => {
available: true,
contract: {
pluginId: "game.scum",
routeKey: "operations",
routeKey: "files-config",
serverInstanceId: "server-1",
permissions: ["server.game-client.read", "server.game-client.command", "server.remote.access"],
bridgeActions: ["server.instances.read", "logs.query", "remote.access.request"],
@@ -61,4 +61,10 @@ describe("SCUM operations page contract", () => {
expect(resolveScumOperationsPageContract(plugin, "")).toMatchObject({ available: false, reason: "缺少服务器实例上下文。" });
expect(resolveScumOperationsPageContract({ ...plugin, gameClientBridge: undefined }, "server-1")).toMatchObject({ available: false });
});
it("migrates only legacy SCUM page keys to the files-and-config workbench", () => {
expect(normalizeScumRouteKey("game.scum", "overview")).toBe("files-config");
expect(normalizeScumRouteKey("game.scum", "logs")).toBe("files-config");
expect(normalizeScumRouteKey("game.other", "logs")).toBe("logs");
});
});
+4 -2
View File
@@ -15,7 +15,7 @@ import {
} from "./pluginBridge";
export const scumOperationsPluginId = "game.scum";
export const scumOperationsRouteKey = "operations";
export const scumOperationsRouteKey = "files-config";
export interface ScumOperationsPageContract {
pluginId: typeof scumOperationsPluginId;
@@ -102,7 +102,9 @@ export type ScumOperationsPageResolution =
| { available: true; contract: ScumOperationsPageContract }
| { available: false; reason: string };
type ScumPluginProjection = Pick<GamePluginResponse, "id" | "pages" | "gameClientBridge" | "runtimeProfiles" | "productionLifecycle">;
type ScumPluginProjection = Pick<GamePluginResponse, "id" | "pages" | "gameClientBridge" | "runtimeProfiles" | "productionLifecycle" | "fileWorkspace">;
export function normalizeScumRouteKey(pluginId: string, routeKey: string): string { return pluginId === scumOperationsPluginId && ["overview", "operations", "config", "logs"].includes(routeKey) ? scumOperationsRouteKey : routeKey; }
export function resolveScumOperationsPageContract(plugin: ScumPluginProjection, serverInstanceId: string): ScumOperationsPageResolution {
if (plugin.id !== scumOperationsPluginId) {