Revert SCUM real data management change

This commit is contained in:
npc0-hue
2026-08-13 15:33:34 +08:00
parent d831e4ade9
commit b07a792784
163 changed files with 5443 additions and 9174 deletions
+1 -1
View File
@@ -334,7 +334,7 @@ describe("first-party console pages", () => {
expect(html).not.toContain("操作历史");
});
it("routes SCUM management through plugin pages and the AI assistant", () => {
it("routes SCUM operations through typed plugin workflow surfaces", () => {
expect(serverDetailPageSource).toContain("PluginPageHostPage");
expect(serverDetailPageSource).toContain("plugin:${page.key}");
expect(serverDetailPageSource).toContain("section === \"llm\"");
@@ -96,18 +96,18 @@ describe("PluginPageHostPage", () => {
expect(hostSource).not.toMatch(/ScumFileConfigWorkbench|GamePlayerIntelligencePanel|GameGiftCatalogPanel|ScumMapTrajectoryPanel|game\.scum/);
});
it("removes SCUM legacy workspace callbacks from the parent host", () => {
it("keeps typed SCUM workspace callbacks stable across parent operational refreshes", () => {
expect(hostSource).toContain("readyPluginRef.current = readyPlugin");
expect(hostSource).toContain("hostContextRef.current = hostContext");
expect(hostSource).not.toContain("listSCUMPlayers");
expect(hostSource).not.toContain("listSCUMPositions");
expect(hostSource).not.toContain("createSCUMWorkflow");
expect(hostSource).not.toContain("createSCUMOperation");
expect(hostSource).not.toContain("listSCUMWorkflowSteps");
expect(hostSource).toContain("listSCUMPlayers: () => platformApiClient.listSCUMPlayers(serverId)");
expect(hostSource).toContain("createSCUMWorkflow: (request) => platformApiClient.createSCUMWorkflow(serverId, request as never)");
expect(hostSource).toContain("createSCUMOperation: (request) => platformApiClient.createSCUMOperation(serverId, request as never)");
expect(hostSource).toContain("listSCUMWorkflowSteps: (workflowId) => platformApiClient.listSCUMWorkflowSteps(serverId, workflowId)");
expect(hostSource).not.toContain("refreshWorkspace");
expect(hostSource).not.toContain("requestFile");
expect(hostSource).not.toContain("writeFile");
expect(hostSource).not.toContain("getDeclaredFileReadSnapshot");
expect(hostSource).toContain("const workspaceActions = undefined");
expect(hostSource).toContain("}, [pluginId, serverId]);");
expect(hostSource).not.toContain("}, [hostContext, readyPlugin, serverId]);");
});
});
+20 -4
View File
@@ -29,7 +29,7 @@ export function PluginPageHostPage({ params, onNavigate, initialPlugin, embedded
const [state, setState] = useState<PluginPageState>(() => initialPlugin ? { status: "ready", plugin: initialPlugin } : { status: "loading" });
const [bundle, setBundle] = useState<ComponentType<{ context: ReturnType<typeof createPluginBridgeHostContext>; workspaceActions?: PluginPageWorkspaceActions; availability: PluginPageAvailability }> | null>(null);
const [bundleError, setBundleError] = useState("");
const [availability, setAvailability] = useState<PluginPageAvailability>({ available: false, reason: "正在验证本地数据通道。" });
const [availability, setAvailability] = useState<PluginPageAvailability>({ available: false, reason: "正在验证 Companion 可用性。" });
const readyPluginRef = useRef<GamePluginResponse | undefined>(undefined);
const hostContextRef = useRef<ReturnType<typeof createPluginBridgeHostContext> | undefined>(undefined);
@@ -66,7 +66,23 @@ export function PluginPageHostPage({ params, onNavigate, initialPlugin, embedded
}) : undefined, [manifestContract, routeKey, serverId]);
readyPluginRef.current = readyPlugin;
hostContextRef.current = hostContext;
const workspaceActions = undefined as PluginPageWorkspaceActions | undefined;
const workspaceActions = useMemo<PluginPageWorkspaceActions | undefined>(() => {
if (!pluginId) return undefined;
return {
listSCUMPlayers: () => platformApiClient.listSCUMPlayers(serverId),
listSCUMSquads: () => platformApiClient.listSCUMSquads(serverId),
listSCUMSquadMembers: () => platformApiClient.listSCUMSquadMembers(serverId),
listSCUMVehicles: () => platformApiClient.listSCUMVehicles(serverId),
listSCUMFlags: () => platformApiClient.listSCUMFlags(serverId),
listSCUMPositions: () => platformApiClient.listSCUMPositions(serverId),
listSCUMOperations: () => platformApiClient.listSCUMOperations(serverId),
createSCUMOperation: (request) => platformApiClient.createSCUMOperation(serverId, request as never),
approveSCUMOperation: (operationId) => platformApiClient.approveSCUMOperation(serverId, operationId),
listSCUMWorkflows: () => platformApiClient.listSCUMWorkflows(serverId),
createSCUMWorkflow: (request) => platformApiClient.createSCUMWorkflow(serverId, request as never),
listSCUMWorkflowSteps: (workflowId) => platformApiClient.listSCUMWorkflowSteps(serverId, workflowId)
};
}, [pluginId, serverId]);
const bundleLoadKey = declaredBundlePage ? [declaredBundlePage.bundleKey, declaredBundlePage.bundleVersion, declaredBundlePage.bundleIntegritySha256, declaredBundlePage.path].join(":") : "";
const loadableBundlePage = useMemo(() => declaredBundlePage, [bundleLoadKey]);
useEffect(() => {
@@ -78,7 +94,7 @@ export function PluginPageHostPage({ params, onNavigate, initialPlugin, embedded
if (!serverId) { setAvailability({ available: false, reason: "插件页面没有绑定服务器。" }); return () => { active = false; }; }
void platformApiClient.getGameClientBridgeStatus(serverId).then((status) => {
if (active) setAvailability({ available: status.available, reason: status.reason, features: status.features });
}).catch((error) => { if (active) setAvailability({ available: false, reason: error instanceof Error ? error.message : "无法验证本地数据通道。" }); });
}).catch((error) => { if (active) setAvailability({ available: false, reason: error instanceof Error ? error.message : "无法验证 Companion 可用性。" }); });
return () => { active = false; };
}, [bundleLoadKey, loadableBundlePage, serverId]);
@@ -127,7 +143,7 @@ export function PluginPageHostPage({ params, onNavigate, initialPlugin, embedded
</button>
</div>
<div className="action-list" aria-label="plugin page declarations"><span><strong>Bundle</strong> {page.bundleKey ? `${page.bundleKey}@${page.bundleVersion}` : "未声明"}</span><span><strong></strong> {page.bundleIntegritySha256 ? `${page.bundleIntegritySha256.slice(0, 18)}` : "未声明"}</span><span><strong></strong> {availability.available ? "可用" : "不可用"}</span></div>
<div className="action-list" aria-label="plugin page declarations"><span><strong>Bundle</strong> {page.bundleKey ? `${page.bundleKey}@${page.bundleVersion}` : "未声明"}</span><span><strong></strong> {page.bundleIntegritySha256 ? `${page.bundleIntegritySha256.slice(0, 18)}` : "未声明"}</span><span><strong>Companion</strong> {availability.available ? "可用" : "不可用"}</span></div>
</section>
{bundleError && <ErrorState title="插件页面不可用" reason={bundleError} />}
{!bundle && !bundleError && <LoadingState label="正在校验并加载插件页面 bundle…" />}
@@ -135,11 +135,6 @@ describe("ServerDetailPage config write approval", () => {
expect(serverDetailPageSource).not.toContain("ScumFileManagementSection");
});
it("keeps SCUM detail tabs to plugin management pages plus AI assistant", () => {
expect(serverDetailPageSource).toContain('plugin?.id === "game.scum"');
expect(serverDetailPageSource).toContain('return [...pluginPages, { id: "llm", label: "AI 助手" }]');
});
it("keeps plugin lifecycle output out of raw bridge-visible detail surfaces", () => {
expect(serverDetailPageSource).not.toContain("platformApiClient.openArtifactDownload(artifact.id)");
expect(serverDetailPageSource).not.toContain("downloadArtifactReference(reference");
-1
View File
@@ -310,7 +310,6 @@ export function ServerDetailPage(props: PageComponentProps) {
function serverDetailSectionEntries(plugin?: GamePluginResponse): Array<{ id: ServerDetailSection; label: string }> {
const pluginPages = (plugin?.pages ?? []).map((page) => ({ id: `plugin:${page.key}` as ServerDetailSection, label: page.title }));
if (plugin?.id === "game.scum") return [...pluginPages, { id: "llm", label: "AI 助手" }];
return [...pluginPages, ...serverDetailSections];
}