Fresh history cut from cynarAI/evoo antigravity-handoff/project-timeline (Voice First + project timeline). Brand docs/titles as evOo; keep @rakazo/* packages as tech debt. Excludes node_modules, caches, secrets, voice blobs.
43 lines
1.5 KiB
TypeScript
43 lines
1.5 KiB
TypeScript
import { createHash } from "node:crypto";
|
|
import type { CloudAgentProvider } from "@rakazo/adapter-kit";
|
|
import { EmulatorCloudAgentProvider } from "./cloud-agent-emulator.js";
|
|
import { resolveCloudAgentProvider } from "./cloud-agent-provider-env.js";
|
|
import { CursorCloudAgentProvider } from "./cursor-cloud-agent.js";
|
|
|
|
/** The composition root binds a credential to exactly one authorized Space. */
|
|
export interface CloudAgentConnection {
|
|
provider: CloudAgentProvider;
|
|
/** Opaque credential binding. Rotation fails closed for existing agents. */
|
|
key: string;
|
|
/** Only the offline emulator may be available in every Space. */
|
|
spaceId?: string;
|
|
}
|
|
|
|
export function cloudAgentsEnabled(
|
|
connection: CloudAgentConnection | null | undefined,
|
|
spaceId: string,
|
|
) {
|
|
return Boolean(
|
|
connection &&
|
|
(connection.spaceId === spaceId ||
|
|
(!connection.spaceId && connection.provider.describe().capabilities.offline)),
|
|
);
|
|
}
|
|
|
|
export function createCloudAgentConnection(
|
|
source: NodeJS.ProcessEnv = process.env,
|
|
): CloudAgentConnection | null {
|
|
const kind = resolveCloudAgentProvider(source);
|
|
if (kind === "emulator") {
|
|
return { provider: new EmulatorCloudAgentProvider(), key: "emulator" };
|
|
}
|
|
if (kind !== "cursor") return null;
|
|
const apiKey = source.CURSOR_API_KEY!.trim();
|
|
const spaceId = source.CLOUD_AGENT_SPACE_ID!.trim();
|
|
return {
|
|
provider: new CursorCloudAgentProvider({ apiKey }),
|
|
key: `cursor:${createHash("sha256").update(apiKey).digest("hex")}`,
|
|
spaceId,
|
|
};
|
|
}
|