/** * Synap pod connection and management utilities. */ export interface LocalPodConfig { podUrl: string; podId?: string; workspaceId: string; agentUserId: string; hubApiKey: string; label?: string; savedAt: string; } /** SSOT for every connect/surface agent identity. The type is derived from this * array so the two can't drift. */ export declare const SURFACE_NAMES: readonly ["raycast", "claude-code", "claude-desktop", "cursor", "codex", "opencode", "aider", "windsurf", "goose", "zed", "vscode", "discord"]; export type SurfaceName = (typeof SURFACE_NAMES)[number]; /** * agentTypes already owned by OTHER doors — `POST /setup/agent` treats agentType * as a POD-WIDE SINGLETON, so `agents create` deriving a slug that collides with * one of these would silently hijack that door's agent + key. Superset of the * surfaces above plus the non-surface provisioning types (generic/openwebui MCP * mappings; openclaw/cli/memory). Single source of truth for the collision guard. */ export declare const RESERVED_AGENT_TYPES: ReadonlySet; export interface SurfaceAgentKey { hubApiKey: string; agentUserId: string; /** * Pod the key was provisioned against. Consumers (e.g. the Raycast extension) * must only use the key when this matches the pod they're talking to — * a surface pointed at another pod falls back to that pod's own profile key. */ podUrl?: string; } /** Agent workspace routing — persisted by `synap connect` wizard. */ export interface AgentWorkspaceRouting { /** Private workspace for agent-only captures (gotchas, lessons, patterns). Auto-approved. */ memoryWorkspaceId?: string; /** Shared workspaces the agent writes team-visible data to. */ productWorkspaceIds?: string[]; } /** The active project pinned together with the pod profile it lives on. */ export interface ActiveProjectBinding { projectId: string; podName: string; } /** * The active workspace pinned together with the pod profile it belongs to. * * A workspace exists on exactly ONE pod, but `activeWorkspaceId` is a single * pod-agnostic global. Recording the pod it was set against lets resolution * refuse to send a workspace to a pod it doesn't belong to (the cross-pod 403). * Peer of {@link ActiveProjectBinding}. */ export interface ActiveWorkspaceBinding { workspaceId: string; podName: string; } export interface MultiPodConfig { activePod: string; /** Per-surface pod overrides. When set, takes priority over activePod for that surface. */ surfaces?: Partial>; pods: Record; /** Active workspace override — set by `synap use `. Takes priority over the pod's default workspaceId. */ activeWorkspaceId?: string; /** Pod-aware binding of the active workspace — records which pod `activeWorkspaceId` was set against, so cross-pod resolution can ignore it for other pods. */ activeWorkspace?: ActiveWorkspaceBinding; /** Active project override — set by `synap project use `. Peer of activeWorkspaceId; independent (composable). */ activeProjectId?: string; /** Pod-aware binding of the active project — set by cross-pod `synap project use ` so later drift (active pod changed under the pin) can warn. */ activeProject?: ActiveProjectBinding; /** Per-surface dedicated agent keys (provisioned with named agentType). Separate from pod profile keys. */ agentKeys?: Partial>; /** Workspace routing set by `synap connect` wizard — drives capture/recall defaults. */ agentWorkspaceRouting?: AgentWorkspaceRouting; } /** * The ONE "pod profile not found" message. * * Names the profile that missed, the pods that DO exist, and the command that * adds one. Every site that fails to resolve a profile name renders through * this — a bare `not found` leaves the user with no next move, and the known-pods * list is usually the whole answer (a typo). */ export declare function podNotFoundMessage(name: string): string; /** Throwing form of {@link podNotFoundMessage}. */ export declare function podNotFoundError(name: string): Error; /** Get the pod config for a specific surface, falling back to the global activePod. */ export declare function getSurfacePod(surface: SurfaceName): LocalPodConfig | null; /** Get the name of the pod assigned to a surface (or the global active pod name). */ export declare function getSurfacePodName(surface: SurfaceName): string | null; /** Assign a pod to a specific surface without changing the global activePod. */ export declare function setSurfacePod(surface: SurfaceName, podName: string): LocalPodConfig; export declare function getActivePodConfig(surface?: SurfaceName): LocalPodConfig | null; /** @deprecated Use getActivePodConfig() */ export declare function getLocalPodConfig(): LocalPodConfig | null; export declare function listPodProfiles(): Array<{ name: string; config: LocalPodConfig; active: boolean; }>; export declare function getPodOverride(): LocalPodConfig | null; /** Resolve a saved pod profile by name and set it as this invocation's override. */ export declare function setPodOverrideByName(name: string): LocalPodConfig; /** * Consume a position-independent `--pod ` (or `--pod=`) from argv and * register it as the per-invocation override. Mutates `argv` in place so commander * never sees the flag (it isn't registered per-command). No-op when the argv * targets a command that owns `--pod` itself (agents, bridge-setup). Throws with a * helpful message when the named profile is unknown. */ export declare function bootstrapPodOverride(argv: string[]): void; export declare function addPodProfile(name: string, podConfig: LocalPodConfig): void; export declare function setActivePod(name: string): LocalPodConfig; /** The active pod's profile NAME (not its config), or undefined if none is set. */ export declare function getActivePodName(): string | undefined; /** Find a saved pod profile NAME by its URL (trailing slashes ignored). */ export declare function findPodNameByUrl(url: string): string | undefined; /** * Resolve the workspace to use for a specific pod — PURE (no disk, no network), * so the cross-pod rule is unit-testable. * * A workspace lives on exactly one pod, but `activeWorkspaceId` is a single * pod-agnostic global. Sending it to the wrong pod is the "Access denied to * workspace" 403. The rule: only honor the global override for the pod it * actually belongs to; otherwise fall back to THAT pod's own default workspace. * * 1. No override set → the target pod's own default. * 2. Override has a pod binding → honor it only for its bound pod; for any * other pod, use that pod's default. * 3. Legacy override (no binding) that equals ANOTHER saved pod's default → * it clearly belongs to that pod → use the target's default. * 4. Otherwise no evidence it's foreign → assume it's the target pod's (the * legacy `synap use ` case) → honor it. */ export declare function resolveWorkspaceForPod(config: MultiPodConfig, podName: string | undefined): string | undefined; /** * Get the active workspace ID for a pod (by profile NAME). Applies the cross-pod * rule in {@link resolveWorkspaceForPod}. Omit `podName` for the active pod. */ export declare function getActiveWorkspaceIdForPod(podName?: string): string | undefined; /** * Get the active workspace ID for the ACTIVE pod: explicit override first (only * if it belongs to this pod), then the pod default. Cross-pod-safe: a global * override left over from another pod is ignored rather than sent (avoids the * "Access denied to workspace" 403). */ export declare function getActiveWorkspaceId(): string | undefined; /** * Persist a workspace as the active context for all subsequent commands. * Records the pod the workspace belongs to (defaults to the active pod) so * later cross-pod resolution can tell whether the override applies. */ export declare function setActiveWorkspaceId(workspaceId: string, podName?: string): void; /** Get the active project ID: durable override set by `synap project use`. */ export declare function getActiveProjectId(): string | undefined; /** Persist a project as the active context for all subsequent commands. */ export declare function setActiveProjectId(projectId: string): void; /** * Pin project AND the pod it lives on together — the cross-pod `project use` * door. Stores the binding so later drift (active pod switched away from the * pinned project's pod) can warn. */ export declare function setActiveProjectBinding(binding: ActiveProjectBinding): void; /** The pod-aware active-project binding, when set by cross-pod `project use`. */ export declare function getActiveProjectBinding(): ActiveProjectBinding | undefined; /** Remove the active project override — subsequent commands see all projects. */ export declare function clearActiveProjectId(): void; /** Store a dedicated agent key for a specific surface (e.g. "raycast", "claude-code"). */ export declare function setSurfaceAgentKey(surface: SurfaceName, key: SurfaceAgentKey): void; /** Read back the stored agent key for a surface. Returns null if not provisioned. */ export declare function getSurfaceAgentKey(surface: SurfaceName): SurfaceAgentKey | null; export declare function setAgentWorkspaceRouting(routing: AgentWorkspaceRouting): void; export declare function getAgentWorkspaceRouting(): AgentWorkspaceRouting | undefined; /** Remove the active workspace override — subsequent commands see all workspaces. */ export declare function clearActiveWorkspaceId(): void; export declare function removePodProfile(name: string): void; /** @deprecated Use addPodProfile("default", config) */ export declare function saveLocalPodConfig(podConfig: LocalPodConfig): void; export interface PodStatus { url: string; healthy: boolean; version?: string; entityCount?: number; workspaceId?: string; } /** * Check if a Synap pod is healthy. */ export declare function checkPodHealth(podUrl: string): Promise; /** * Install Docker and start a self-hosted Synap pod. */ export declare function startSelfHostedPod(): void; /** * Install the synap skill into OpenClaw. */ /** * Open a Pod session for the CP-authenticated user. * Calls the issuer for a short-lived generic assertion, then exchanges that * assertion directly with the Pod. The issuer never receives a Pod session. * * Returns the Kratos session token the Pod mints after its own membership check. * That token authenticates subsequent pod tRPC calls (e.g. * `apiKeys.connectIntegration`) as the pod user, via the X-Session-Token header. * `sessionToken` is null only if the pod handshake returned no token (e.g. 409). */ export declare function provisionUserOnPod(podUrl: string, cpToken: string): Promise<{ sessionToken: string | null; }>; /** * Issue a scoped Hub Protocol API key on the pod for an authenticated user. * * Canonical path: the pod's `apiKeys.connectIntegration` tRPC procedure — the * same one the pod-admin `/connect` page and the browser's LocalCliRow use. * Auth is the Kratos session token minted by {@link provisionUserOnPod}, * forwarded as the `X-Session-Token` header. (Replaces the removed CP relay * `POST /pods/setup-agent`, which now returns 410.) * * Backend tRPC uses the superjson transformer, so the input rides in a * `{ json: ... }` envelope and the output is unwrapped from `result.data.json`. */ export declare function setupAgentViaPod(podUrl: string, sessionToken: string, integration?: "cli" | "openclaw" | "raycast" | "custom"): Promise<{ hubApiKey: string; agentUserId: string; workspaceId: string; }>; /** * Enable OpenClaw as a free addon on a SELF-HOSTED pod. * Uses the PROVISIONING_TOKEN directly against the pod. * * Routes through the shared `provisionAgentKey()` wrapper (dynamic import to * avoid a circular pod.ts <-> targets.ts static import). `workspaceId` is no * longer part of the response — agents are pod-wide singletons now; scope is * granted separately via `enrollAgentIfNeeded()`, not returned from setup. */ export declare function enableOpenClawAddon(podUrl: string, provisioningToken: string): Promise<{ hubApiKey: string; agentUserId: string; workspaceId: string; }>; /** * Enable OpenClaw as an addon on a MANAGED pod via the Control Plane. * Calls POST /openclaw/provision on the CP (requires CP session token). * Returns the podId so the caller can poll status if needed. */ export declare function enableOpenClawAddonManaged(cpToken: string, podUrl: string): Promise<{ podId: string; }>; /** * Check server resources (RAM, disk). */ export declare function checkServerResources(): { ramTotal: number; ramFree: number; diskFree: string; }; /** * Start OpenClaw as a Docker addon on the local server. * Writes env vars to the pod's .env file and runs docker compose --profile openclaw. * Only works when the CLI is running ON the pod server. */ /** * Find the Synap deploy directory — where the .env and docker-compose files live. * * Strategy (most reliable first): * 1. Docker label — inspect any running synap container for * com.docker.compose.project.working_dir (always accurate, zero guessing) * 2. Walk up from cwd — works when running from inside the repo * 3. Common install paths as a last resort */ export declare function findSynapDeployDir(): string | null; /** * Write OpenClaw env vars into the deploy dir .env and start the container. * Does NOT wait for health — OpenClaw can take several minutes to initialize * (first run pulls ~1GB image + runs setup). Caller should tell user to run * `synap finish` once it's up. * * Returns the deploy dir used. */ export declare function startOpenClawOnServer(hubApiKey: string, agentUserId: string, workspaceId: string, podUrl: string, projectId?: string): string; /** * Install the synap skill into OpenClaw. * Automatically chooses the right execution path: * - Local install: runs `openclaw skills install synap` directly * - Docker container: runs `docker exec openclaw skills install synap` */ export declare function installSynapSkill(containerName?: string): void; /** * Check whether the synap skill is installed inside a Docker container. */ export declare function isSynapSkillInstalledInDocker(containerName: string): boolean;