426e9eeabd
Voice Workbench / headless workbench (mocked backends) (push) Has been cancelled
Voice Workbench / real acoustic lane (nightly, provisioned only) (push) Has been cancelled
ci / test (push) Has been cancelled
ci / lint-and-format (push) Has been cancelled
ci / build (push) Has been cancelled
ci / dev-startup (push) Has been cancelled
gitleaks / gitleaks (push) Has been cancelled
Markdown Links / Relative Markdown Links (push) Has been cancelled
Quality (Extended) / Homepage Build (PR smoke) (push) Has been cancelled
Quality (Extended) / Comment-only diff guard (push) Has been cancelled
Quality (Extended) / Format + Type Safety Ratchet (push) Has been cancelled
Quality (Extended) / Develop Gate (secret scan + UI determinism) (push) Has been cancelled
Quality (Extended) / Develop Gate (lint) (push) Has been cancelled
Chat shell gestures / Chat shell gesture + parity e2e (push) Has been cancelled
Cloud Gateway Discord / Test (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx @biomejs/biome check packages/lifeops-bench/src, benchmark-lint) (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx vitest run --config packages/lifeops-bench/vitest.config.ts --root packages/lifeops-bench --passWithNoTests, benchmark-tests) (push) Has been cancelled
Build Agent Image / build-and-push (push) Has been cancelled
Dev Smoke / bun run dev onboarding chat (push) Has been cancelled
Dev Smoke / Vite HMR dependency-level smoke (push) Has been cancelled
Electrobun Submodule Guard / electrobun gitlink is fetchable (push) Has been cancelled
Publish @elizaos/example-code / check_npm (push) Has been cancelled
Publish @elizaos/example-code / publish_npm (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / verify_version (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / publish_npm (push) Has been cancelled
Sandbox Live Smoke / Sandbox live smoke (push) Has been cancelled
Snap Build & Test / Build Snap (amd64) (push) Has been cancelled
Snap Build & Test / Build Snap (arm64) (push) Has been cancelled
Test Packaging / elizaos CLI global-install smoke (node + bun) (push) Has been cancelled
Cloud Gateway Webhook / Test (push) Has been cancelled
Cloud Tests / lint-and-types (push) Has been cancelled
Cloud Tests / unit-tests (push) Has been cancelled
Cloud Tests / integration-tests (push) Has been cancelled
Cloud Tests / e2e-tests (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Apps Worker (Product 2) / Determine environment (push) Has been cancelled
Deploy Apps Worker (Product 2) / Deploy apps worker to apps-control host (${{ needs.determine-env.outputs.environment }}) (push) Has been cancelled
Deploy Eliza Provisioning Worker / Determine environment (push) Has been cancelled
Deploy Eliza Provisioning Worker / Deploy worker to Hetzner host (${{ needs.determine-env.outputs.environment }} @ ${{ needs.determine-env.outputs.deployment_sha }}) (push) Has been cancelled
Dev Smoke / Classify changed paths (push) Has been cancelled
supply-chain / sbom (push) Has been cancelled
supply-chain / vulnerability-scan (push) Has been cancelled
Build, Push & Deploy to Phala Cloud / build-and-push (push) Has been cancelled
Test Packaging / Validate Packaging Configs (push) Has been cancelled
Test Packaging / Build & Test PyPI Package (push) Has been cancelled
Test Packaging / PyPI on Python ${{ matrix.python }} (push) Has been cancelled
Test Packaging / Pack & Test JS Tarballs (push) Has been cancelled
UI Fixture E2E / ui-fixture-e2e (push) Has been cancelled
UI Fixture E2E / fixture-e2e (push) Has been cancelled
UI Story Gate / story-gate (push) Has been cancelled
vault-ci / test (macos-latest) (push) Has been cancelled
vault-ci / test (ubuntu-latest) (push) Has been cancelled
vault-ci / test (windows-latest) (push) Has been cancelled
vault-ci / app-core wiring tests (push) Has been cancelled
verify-patches / verify patches/CHECKSUMS.sha256 (push) Has been cancelled
Voice Benchmark Smoke / voice-emotion fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voiceagentbench fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench-quality unit smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench TypeScript unit (no audio) (push) Has been cancelled
Voice Benchmark Smoke / voice bench smoke summary (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/app-core test bun run --cwd packages/elizaos test bun run --cwd packages/cloud/shared test], app-and-cli) (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/scenario-runner test bun run --cwd packages/vault test bun run --cwd packages/security test bun run --cwd plugins/plugin-coding-tools test], framework-packages) (push) Has been cancelled
Windows CI / windows ([bun run --cwd plugins/plugin-elizacloud test bun run --cwd plugins/plugin-discord test bun run --cwd plugins/plugin-anthropic test bun run --cwd plugins/plugin-openai test bun run --cwd plugins/plugin-app-control test bun run --cwd plugins/pl… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run build --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/agent --concurrency=4 node packages/scripts/run-bash-linux-only.mjs scripts/verify-riscv64-buildpaths.sh node packages/scripts/run… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run typecheck --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/cloud-shared --concurrency=4 bun run --cwd packages/core test bun run --cwd packages/shared test], core-runtime, 75) (push) Has been cancelled
265 lines
8.4 KiB
TypeScript
265 lines
8.4 KiB
TypeScript
import type http from "node:http";
|
|
import { CLOUD_CONTAINER_SERVICE_TYPE } from "@elizaos/shared";
|
|
import { describe, expect, it } from "vitest";
|
|
import { handleCloudCodingContainerRoute } from "../src/routes/cloud-coding-container-routes";
|
|
import type {
|
|
PromoteVfsToCloudContainerRequest,
|
|
RequestCodingAgentContainerRequest,
|
|
SyncCloudCodingContainerRequest,
|
|
} from "../src/types/cloud";
|
|
|
|
function requestWithBody(body: unknown): http.IncomingMessage {
|
|
return {
|
|
body,
|
|
headers: {},
|
|
method: "POST",
|
|
url: "/",
|
|
} as http.IncomingMessage & { body: unknown };
|
|
}
|
|
|
|
function responseSink(): http.ServerResponse & { jsonBody: () => unknown } {
|
|
let body = "";
|
|
const sink = {
|
|
headersSent: false,
|
|
statusCode: 200,
|
|
setHeader: () => {},
|
|
end: (chunk?: unknown) => {
|
|
body = typeof chunk === "string" ? chunk : String(chunk ?? "");
|
|
sink.headersSent = true;
|
|
return {} as http.ServerResponse;
|
|
},
|
|
jsonBody: () => JSON.parse(body),
|
|
};
|
|
return sink as http.ServerResponse & { jsonBody: () => unknown };
|
|
}
|
|
|
|
describe("cloud coding-container routes", () => {
|
|
it("forwards VFS promotion requests to the cloud container service", async () => {
|
|
let captured: PromoteVfsToCloudContainerRequest | null = null;
|
|
const service = {
|
|
promoteVfsToCloudContainer: async (request: PromoteVfsToCloudContainerRequest) => {
|
|
captured = request;
|
|
return {
|
|
success: true,
|
|
data: {
|
|
promotionId: "promo-1",
|
|
status: "accepted" as const,
|
|
source: request.source,
|
|
workspacePath: "/workspace",
|
|
createdAt: "2026-05-11T00:00:00.000Z",
|
|
},
|
|
};
|
|
},
|
|
requestCodingAgentContainer: async () => {
|
|
throw new Error("unexpected");
|
|
},
|
|
syncCodingContainerChanges: async () => {
|
|
throw new Error("unexpected");
|
|
},
|
|
};
|
|
const requestedServiceTypes: string[] = [];
|
|
const runtime = {
|
|
getService: (serviceType: string) => {
|
|
requestedServiceTypes.push(serviceType);
|
|
return serviceType === CLOUD_CONTAINER_SERVICE_TYPE ? service : null;
|
|
},
|
|
};
|
|
const request: PromoteVfsToCloudContainerRequest = {
|
|
preferredAgent: "codex",
|
|
source: {
|
|
sourceKind: "project",
|
|
projectId: "vfs-project-1",
|
|
revision: "rev-1",
|
|
files: [{ path: "src/index.ts", contents: "export {};", encoding: "utf-8" }],
|
|
},
|
|
};
|
|
const response = responseSink();
|
|
|
|
const handled = await handleCloudCodingContainerRoute(
|
|
requestWithBody(request),
|
|
response,
|
|
"/api/cloud/coding-containers/promotions",
|
|
"POST",
|
|
{ runtime: runtime as never }
|
|
);
|
|
|
|
expect(handled).toBe(true);
|
|
expect(response.statusCode).toBe(200);
|
|
expect(requestedServiceTypes).toEqual([CLOUD_CONTAINER_SERVICE_TYPE]);
|
|
expect(captured).toEqual(request);
|
|
expect(response.jsonBody()).toMatchObject({
|
|
success: true,
|
|
data: { promotionId: "promo-1", workspacePath: "/workspace" },
|
|
});
|
|
});
|
|
|
|
it("forwards coding-agent container requests with Claude/Codex/OpenCode agent ids", async () => {
|
|
let captured: RequestCodingAgentContainerRequest | null = null;
|
|
const service = {
|
|
promoteVfsToCloudContainer: async () => {
|
|
throw new Error("unexpected");
|
|
},
|
|
requestCodingAgentContainer: async (request: RequestCodingAgentContainerRequest) => {
|
|
captured = request;
|
|
return {
|
|
success: true,
|
|
data: {
|
|
containerId: "cc-1",
|
|
status: "requested" as const,
|
|
agent: request.agent,
|
|
promotionId: request.promotionId,
|
|
workspacePath: "/workspace",
|
|
createdAt: "2026-05-11T00:00:00.000Z",
|
|
},
|
|
};
|
|
},
|
|
syncCodingContainerChanges: async () => {
|
|
throw new Error("unexpected");
|
|
},
|
|
};
|
|
const runtime = { getService: () => service };
|
|
const request: RequestCodingAgentContainerRequest = {
|
|
agent: "claude",
|
|
promotionId: "promo-1",
|
|
prompt: "Fix the failing test",
|
|
};
|
|
const response = responseSink();
|
|
|
|
await handleCloudCodingContainerRoute(
|
|
requestWithBody(request),
|
|
response,
|
|
"/api/cloud/coding-containers",
|
|
"POST",
|
|
{ runtime: runtime as never }
|
|
);
|
|
|
|
expect(captured).toEqual(request);
|
|
expect(response.jsonBody()).toMatchObject({
|
|
success: true,
|
|
data: { containerId: "cc-1", agent: "claude", promotionId: "promo-1" },
|
|
});
|
|
});
|
|
|
|
it("forwards sync requests with decoded container ids", async () => {
|
|
let capturedContainerId: string | null = null;
|
|
let capturedRequest: SyncCloudCodingContainerRequest | null = null;
|
|
const service = {
|
|
promoteVfsToCloudContainer: async () => {
|
|
throw new Error("unexpected");
|
|
},
|
|
requestCodingAgentContainer: async () => {
|
|
throw new Error("unexpected");
|
|
},
|
|
syncCodingContainerChanges: async (
|
|
containerId: string,
|
|
request: SyncCloudCodingContainerRequest
|
|
) => {
|
|
capturedContainerId = containerId;
|
|
capturedRequest = request;
|
|
return {
|
|
success: true,
|
|
data: {
|
|
syncId: "sync-1",
|
|
containerId,
|
|
status: "ready" as const,
|
|
direction: request.direction ?? "pull",
|
|
target: request.target,
|
|
changedFiles: request.changedFiles ?? [],
|
|
deletedFiles: request.deletedFiles ?? [],
|
|
patches: request.patches ?? [],
|
|
createdAt: "2026-05-11T00:00:00.000Z",
|
|
},
|
|
};
|
|
},
|
|
};
|
|
const runtime = { getService: () => service };
|
|
const request: SyncCloudCodingContainerRequest = {
|
|
direction: "pull",
|
|
target: { sourceKind: "workspace", workspaceId: "workspace-1", baseRevision: "rev-1" },
|
|
patches: [{ path: "src/index.ts", format: "unified-diff", patch: "@@ test" }],
|
|
};
|
|
const response = responseSink();
|
|
|
|
await handleCloudCodingContainerRoute(
|
|
requestWithBody(request),
|
|
response,
|
|
"/api/cloud/coding-containers/container%2Fone/sync",
|
|
"POST",
|
|
{ runtime: runtime as never }
|
|
);
|
|
|
|
expect(capturedContainerId).toBe("container/one");
|
|
expect(capturedRequest).toEqual(request);
|
|
expect(response.jsonBody()).toMatchObject({
|
|
success: true,
|
|
data: { syncId: "sync-1", containerId: "container/one" },
|
|
});
|
|
});
|
|
|
|
it("rejects malformed request shapes before hitting the service", async () => {
|
|
const response = responseSink();
|
|
const runtime = {
|
|
getService: () => ({
|
|
promoteVfsToCloudContainer: async () => {
|
|
throw new Error("should not be called");
|
|
},
|
|
requestCodingAgentContainer: async () => {
|
|
throw new Error("should not be called");
|
|
},
|
|
syncCodingContainerChanges: async () => {
|
|
throw new Error("should not be called");
|
|
},
|
|
}),
|
|
};
|
|
|
|
await handleCloudCodingContainerRoute(
|
|
requestWithBody({ agent: "gemini", promotionId: "promo-1" }),
|
|
response,
|
|
"/api/cloud/coding-containers",
|
|
"POST",
|
|
{ runtime: runtime as never }
|
|
);
|
|
|
|
expect(response.statusCode).toBe(400);
|
|
expect(response.jsonBody()).toEqual({
|
|
error: 'Invalid option: expected one of "claude"|"codex"|"opencode"|"elizaos"',
|
|
});
|
|
});
|
|
|
|
it("does not discover cloud container services through legacy spelling guesses", async () => {
|
|
const legacyOnlyRuntime = {
|
|
getService: (serviceType: string) =>
|
|
serviceType === "cloud-container"
|
|
? {
|
|
promoteVfsToCloudContainer: async () => {
|
|
throw new Error("should not be called");
|
|
},
|
|
requestCodingAgentContainer: async () => {
|
|
throw new Error("should not be called");
|
|
},
|
|
syncCodingContainerChanges: async () => {
|
|
throw new Error("should not be called");
|
|
},
|
|
}
|
|
: null,
|
|
};
|
|
const response = responseSink();
|
|
|
|
const handled = await handleCloudCodingContainerRoute(
|
|
requestWithBody({
|
|
source: { sourceKind: "project", projectId: "vfs-project-1" },
|
|
}),
|
|
response,
|
|
"/api/cloud/coding-containers/promotions",
|
|
"POST",
|
|
{ runtime: legacyOnlyRuntime as never }
|
|
);
|
|
|
|
expect(handled).toBe(true);
|
|
expect(response.statusCode).toBe(503);
|
|
expect(response.jsonBody()).toEqual({
|
|
error: "Cloud container service is not available",
|
|
});
|
|
});
|
|
});
|