Integrate SCUM real ops workflows
This commit is contained in:
@@ -244,61 +244,18 @@ describe("PlatformApiClient AI providers", () => {
|
||||
count: 1
|
||||
});
|
||||
}
|
||||
if (url.endsWith("/api/v1/server-instances/server-1/config")) {
|
||||
return jsonResponse({
|
||||
serverInstanceId: server.id,
|
||||
configVersion: 1,
|
||||
format: "properties",
|
||||
key: "server.properties",
|
||||
content: "server.name=Example Survival #1\n",
|
||||
source: "platform-derived",
|
||||
updatedAt: "2026-07-03T00:00:00Z"
|
||||
});
|
||||
}
|
||||
if (url.endsWith("/api/v1/server-instances/server-1/config/diff") && init?.method === "POST") {
|
||||
expect(JSON.parse(String(init.body))).toEqual({
|
||||
expectedConfigVersion: 1,
|
||||
key: "server.properties",
|
||||
proposedContent: "server.name=Example Survival #2\n"
|
||||
});
|
||||
return jsonResponse({
|
||||
serverInstanceId: server.id,
|
||||
configVersion: 1,
|
||||
key: "server.properties",
|
||||
currentContent: "server.name=Example Survival #1\n",
|
||||
proposedContent: "server.name=Example Survival #2\n",
|
||||
diff: [
|
||||
{ kind: "removed", oldNumber: 1, content: "server.name=Example Survival #1" },
|
||||
{ kind: "added", newNumber: 1, content: "server.name=Example Survival #2" }
|
||||
],
|
||||
hasChanges: true,
|
||||
source: "platform-review",
|
||||
reviewedAt: "2026-07-03T00:00:00Z"
|
||||
});
|
||||
}
|
||||
if (url.endsWith("/api/v1/server-instances/server-1/config/approve") && init?.method === "POST") {
|
||||
expect(JSON.parse(String(init.body))).toEqual({
|
||||
expectedConfigVersion: 1,
|
||||
key: "server.properties",
|
||||
proposedContent: "server.name=Example Survival #2\n",
|
||||
idempotencyKey: "idem-config"
|
||||
});
|
||||
return jsonResponse({
|
||||
status: "queued",
|
||||
preview: {
|
||||
serverInstanceId: server.id,
|
||||
configVersion: 1,
|
||||
key: "server.properties",
|
||||
currentContent: "server.name=Example Survival #1\n",
|
||||
proposedContent: "server.name=Example Survival #2\n",
|
||||
diff: [{ kind: "added", newNumber: 1, content: "server.name=Example Survival #2" }],
|
||||
hasChanges: true,
|
||||
source: "platform-review",
|
||||
reviewedAt: "2026-07-03T00:00:00Z"
|
||||
},
|
||||
job: { ...job, id: "job-config-write", capability: "config.write", targetKey: "server.properties", inputRef: "input://server-config/server-1/server.properties/v1" }
|
||||
});
|
||||
}
|
||||
if (url.endsWith("/api/v1/server-instances/server-1/scum/players")) return jsonResponse({ items: [{ id: "scum-player-1", gamePlayerId: "steam-1", displayName: "Prisoner One", online: true }], count: 1 });
|
||||
if (url.endsWith("/api/v1/server-instances/server-1/scum/squads")) return jsonResponse({ items: [{ id: "squad-1", squadId: "squad-1", name: "Alpha" }], count: 1 });
|
||||
if (url.endsWith("/api/v1/server-instances/server-1/scum/squad-members")) return jsonResponse({ items: [{ id: "member-1", squadId: "squad-1", gamePlayerId: "steam-1" }], count: 1 });
|
||||
if (url.endsWith("/api/v1/server-instances/server-1/scum/vehicles")) return jsonResponse({ items: [{ id: "vehicle-1", vehicleId: "vehicle-1", label: "SUV" }], count: 1 });
|
||||
if (url.endsWith("/api/v1/server-instances/server-1/scum/flags")) return jsonResponse({ items: [{ id: "flag-1", flagId: "flag-1", ownerSquadId: "squad-1" }], count: 1 });
|
||||
if (url.endsWith("/api/v1/server-instances/server-1/scum/positions")) return jsonResponse({ items: [{ id: "position-1", subjectType: "player", subjectId: "steam-1", x: 1, y: 2, z: 3 }], count: 1 });
|
||||
if (url.endsWith("/api/v1/server-instances/server-1/scum/operations") && (!init?.method || init.method === "GET")) return jsonResponse({ items: [], count: 0 });
|
||||
if (url.endsWith("/api/v1/server-instances/server-1/scum/operations") && init?.method === "POST") return jsonResponse({ id: "op-1", serverInstanceId: server.id, pluginId: plugin.id, templateKey: "player.fame.set", status: "waiting", approvalLevel: "operator", createdAt: "2026-07-03T00:00:00Z", updatedAt: "2026-07-03T00:00:00Z" });
|
||||
if (url.endsWith("/api/v1/server-instances/server-1/scum/operations/op-1/approve") && init?.method === "POST") return jsonResponse({ id: "op-1", serverInstanceId: server.id, pluginId: plugin.id, templateKey: "player.fame.set", status: "queued", approvalLevel: "operator", createdAt: "2026-07-03T00:00:00Z", updatedAt: "2026-07-03T00:00:00Z" });
|
||||
if (url.endsWith("/api/v1/server-instances/server-1/scum/workflows") && (!init?.method || init.method === "GET")) return jsonResponse({ items: [], count: 0 });
|
||||
if (url.endsWith("/api/v1/server-instances/server-1/scum/workflows") && init?.method === "POST") return jsonResponse({ id: "workflow-1", serverInstanceId: server.id, pluginId: plugin.id, templateKey: "scum.world-refresh", status: "queued", createdAt: "2026-07-03T00:00:00Z", updatedAt: "2026-07-03T00:00:00Z" });
|
||||
if (url.endsWith("/api/v1/server-instances/server-1/scum/workflow-steps?workflowId=workflow-1")) return jsonResponse({ items: [{ id: "step-1", workflowId: "workflow-1", serverInstanceId: server.id, stepKey: "read-positions", status: "queued", createdAt: "2026-07-03T00:00:00Z", updatedAt: "2026-07-03T00:00:00Z" }], count: 1 });
|
||||
if (url.endsWith("/api/v1/file-operations/dispatch") && init?.method === "POST") {
|
||||
expect(JSON.parse(String(init.body))).toEqual({
|
||||
serverInstanceId: server.id,
|
||||
@@ -536,13 +493,6 @@ describe("PlatformApiClient AI providers", () => {
|
||||
expect(JSON.parse(String(init.body))).toEqual({ probeKey: "java-21", installPlanKey: "install-java-linux", planDigest: runtimeDigest, idempotencyKey: "idem-dep-install" });
|
||||
return jsonResponse({ ...job, id: "job-dep-install", capability: "dependencies.install", targetKey: "dependencies/install/install-java-linux" });
|
||||
}
|
||||
if (url.endsWith("/api/v1/server-instances/server-1/logs/live")) {
|
||||
return jsonResponse({ items: [], count: 0 });
|
||||
}
|
||||
if (url.endsWith("/api/v1/server-instances/server-1/logs/backfill") && init?.method === "POST") {
|
||||
expect(JSON.parse(String(init.body))).toEqual({ sourceKey: "latest-log", checkpointRef: "artifact://logs/checkpoint/1", limit: 200, idempotencyKey: "idem-log-backfill" });
|
||||
return jsonResponse({ ...job, id: "job-log-backfill", capability: "logs.backfill", targetKey: "logs/latest-log", inputRef: "artifact://logs/checkpoint/1" });
|
||||
}
|
||||
if (url.endsWith("/api/v1/plugin-bridge/authorize") && init?.method === "POST") {
|
||||
return jsonResponse({
|
||||
pluginId: plugin.id,
|
||||
@@ -604,13 +554,18 @@ describe("PlatformApiClient AI providers", () => {
|
||||
await expect(client.deleteServerInstance(server.id, { password: "secret-password", force: true, confirmation: "FORCE DELETE" })).resolves.toBeUndefined();
|
||||
await expect(client.getPlatformResourceUsage()).resolves.toMatchObject({ source: "platform-derived", cpuPercent: 28 });
|
||||
await expect(client.listServerMetrics()).resolves.toMatchObject({ count: 1, items: [{ serverInstanceId: server.id, online: true }] });
|
||||
await expect(client.getServerConfig(server.id)).resolves.toMatchObject({ content: "server.name=Example Survival #1\n" });
|
||||
await expect(
|
||||
client.previewServerConfigDiff(server.id, { expectedConfigVersion: 1, key: "server.properties", proposedContent: "server.name=Example Survival #2\n" })
|
||||
).resolves.toMatchObject({ hasChanges: true, source: "platform-review" });
|
||||
await expect(
|
||||
client.approveServerConfigWrite(server.id, { expectedConfigVersion: 1, key: "server.properties", proposedContent: "server.name=Example Survival #2\n", idempotencyKey: "idem-config" })
|
||||
).resolves.toMatchObject({ status: "queued", job: { capability: "config.write", targetKey: "server.properties" } });
|
||||
await expect(client.listSCUMPlayers(server.id)).resolves.toMatchObject({ count: 1, items: [{ gamePlayerId: "steam-1" }] });
|
||||
await expect(client.listSCUMSquads(server.id)).resolves.toMatchObject({ count: 1 });
|
||||
await expect(client.listSCUMSquadMembers(server.id)).resolves.toMatchObject({ count: 1 });
|
||||
await expect(client.listSCUMVehicles(server.id)).resolves.toMatchObject({ count: 1 });
|
||||
await expect(client.listSCUMFlags(server.id)).resolves.toMatchObject({ count: 1 });
|
||||
await expect(client.listSCUMPositions(server.id)).resolves.toMatchObject({ count: 1 });
|
||||
await expect(client.listSCUMOperations(server.id)).resolves.toMatchObject({ count: 0 });
|
||||
await expect(client.createSCUMOperation(server.id, { templateKey: "player.fame.set", playerId: "steam-1", payload: { fame: 100 }, reason: "typed correction", idempotencyKey: "idem-scum-op" })).resolves.toMatchObject({ id: "op-1", status: "waiting" });
|
||||
await expect(client.approveSCUMOperation(server.id, "op-1")).resolves.toMatchObject({ id: "op-1", status: "queued" });
|
||||
await expect(client.listSCUMWorkflows(server.id)).resolves.toMatchObject({ count: 0 });
|
||||
await expect(client.createSCUMWorkflow(server.id, { templateKey: "scum.world-refresh", idempotencyKey: "idem-scum-workflow" })).resolves.toMatchObject({ id: "workflow-1", status: "queued" });
|
||||
await expect(client.listSCUMWorkflowSteps(server.id, "workflow-1")).resolves.toMatchObject({ count: 1, items: [{ stepKey: "read-positions" }] });
|
||||
await expect(client.dispatchFileOperation({ serverInstanceId: server.id, operation: "read", key: "logs/latest.log", idempotencyKey: "idem-file" })).resolves.toMatchObject({
|
||||
status: "queued",
|
||||
job: { capability: "files.read", targetKey: "logs/latest.log" }
|
||||
@@ -665,21 +620,11 @@ describe("PlatformApiClient AI providers", () => {
|
||||
await expect(client.installDependencies(server.id, { probeKey: "java-21", installPlanKey: "install-java-linux", planDigest: runtimeDigest, idempotencyKey: "idem-dep-install" })).resolves.toMatchObject({
|
||||
capability: "dependencies.install"
|
||||
});
|
||||
await expect(client.listServerLiveLogs(server.id)).resolves.toMatchObject({ count: 0 });
|
||||
await expect(client.requestLogBackfill(server.id, { sourceKey: "latest-log", checkpointRef: "artifact://logs/checkpoint/1", limit: 200, idempotencyKey: "idem-log-backfill" })).resolves.toMatchObject({
|
||||
capability: "logs.backfill"
|
||||
});
|
||||
await expect(client.authorizePluginBridge({ pluginId: plugin.id, routeKey: "logs", action: "logs.query" })).resolves.toMatchObject({
|
||||
allowed: true
|
||||
});
|
||||
await expect(
|
||||
client.executePluginBridge({ requestId: "req-bridge", pluginId: plugin.id, routeKey: "logs", serverInstanceId: server.id, action: "logs.query", payload: { logStreamId: "log-1" } })
|
||||
).resolves.toMatchObject({ status: "ok", result: { entryCount: "0" } });
|
||||
await expect(
|
||||
client.invokeAI({ requestId: "ai-1", serverInstanceId: server.id, purpose: "config.suggest", prompt: "Tune PVP safely", currentConfig: "server.name=Example Survival #1\n" })
|
||||
).resolves.toMatchObject({ status: "ok", usage: { mocked: true }, configRecommendation: { diffSummary: "review required" } });
|
||||
|
||||
expect(fetchMock).toHaveBeenCalledTimes(43);
|
||||
expect(fetchMock).toHaveBeenCalledTimes(48);
|
||||
});
|
||||
|
||||
it("calls plugin marketplace endpoints with filter and state contracts", async () => {
|
||||
@@ -708,11 +653,11 @@ describe("PlatformApiClient AI providers", () => {
|
||||
expect(fetchMock).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
|
||||
it("surfaces config diff preview failures from the platform", async () => {
|
||||
it("surfaces SCUM typed operation failures from the platform", async () => {
|
||||
const fetchMock = vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => {
|
||||
const url = String(input);
|
||||
if (url.endsWith("/api/v1/server-instances/server-1/config/diff") && init?.method === "POST") {
|
||||
return new Response(JSON.stringify({ code: "validation", message: "expectedConfigVersion must match server instance" }), {
|
||||
if (url.endsWith("/api/v1/server-instances/server-1/scum/operations") && init?.method === "POST") {
|
||||
return new Response(JSON.stringify({ code: "validation", message: "SCUM operation template is not declared" }), {
|
||||
status: 400,
|
||||
headers: { "Content-Type": "application/json" }
|
||||
});
|
||||
@@ -723,9 +668,7 @@ describe("PlatformApiClient AI providers", () => {
|
||||
|
||||
const client = new PlatformApiClient();
|
||||
|
||||
await expect(client.previewServerConfigDiff(server.id, { expectedConfigVersion: 0, key: "server.properties", proposedContent: "changed=true\n" })).rejects.toThrow(
|
||||
"expectedConfigVersion must match server instance"
|
||||
);
|
||||
await expect(client.createSCUMOperation(server.id, { templateKey: "raw.sql", reason: "unsafe", idempotencyKey: "bad-scum-op" })).rejects.toThrow("SCUM operation template is not declared");
|
||||
});
|
||||
|
||||
it("keeps raw key and base URL fields out of provider responses", () => {
|
||||
|
||||
Reference in New Issue
Block a user