Skip to content

plugin-cdp

Placement runtime (out-of-process over gRPC)
Source github.com/opencharly/charly/candy/plugin-cdp
Version 2026.178.0900
Candy plugin-cdp

This plugin is not listed in charly/charly.yml’s compiled_plugins:. It is not part of the shipped binary: charly builds and loads it out-of-process over gRPC when a plan references one of its words (the coexist path).

The reserved words this plugin serves:

  • cdp — verb class

OUT-OF-TREE charly plugin serving the cdp Chrome-DevTools-Protocol check verb — a standalone Go module (go.mod + main.go) that speaks CDP over the DevTools HTTP (/json) + per-tab WebSocket surface via golang.org/x/net/websocket, served OUT-OF-PROCESS over go-plugin gRPC via the charly plugin SDK (github.com/opencharly/sdk). charly’s loader fetches this candy’s repo, go-builds the provider binary on the HOST, and serves it via LocalTransport — so the CDP WebSocket client lives HERE, out of charly’s core check surface (the latest external dep-shed after candy/plugin-appium, -adb, -kube, -spice, -mcp, -record; charly’s core no longer keeps a CDP client of its own — the former in-core copy was deleted when wl externalized). Since the schema-compaction cutover an authored cdp: step desugars to the internal plugin/plugin_input envelope, and every cdp-exclusive modifier (method/tab/url/expression/selector/x/y/…) lives in the plugin’s OWN #CdpInput (schema/cdp.cue); the verb dispatches through the provider registry exactly like a built-in (ResolveVerb → grpcProvider → invokeVerbProvider hands it the full #Op). The plugin resolves the deployment’s CDP port 9222 to a host-reachable DevTools base URL via the generic cc.ResolveEndpoint reverse-leg (the host owns the podman / venue / port-mapping machinery) — so this plugin needs no container inspection at all. Provides the full query/action surface (status/list/url/text/html/eval/axtree/coords/raw/wait/ screenshot/open/close/click/type) plus the SPA remote-desktop input group (spa-status/click/mouse/type/key/key-combo). The R10 consumer is a Chrome-bearing pod bed whose check composes this plugin (e.g. sway-browser-vnc).

The CUE schema below is the authoritative grammar for this plugin’s input. It is the same single source that generates the plugin’s Go parameter types and answers the runtime Describe RPC, so this page cannot disagree with either.

// The `cdp` plugin's OWN CUE schema — the typed plugin_input for the `cdp`
// Chrome-DevTools check verb. It is the SINGLE SOURCE for this plugin's params,
// used two ways (the same contract core `spec` and the http plugin use):
//
// 1. GENERATE the Go param struct — `cue exp gengotypes` (driven by the cue:gen
// pipeline, which wraps this with `package params` + `@go(params)`) emits
// ../params/cue_types_gen.go, so the provider decodes plugin_input into a
// TYPED struct, never a hand-parsed map.
// 2. VALIDATE authored input AT RUNTIME — the plugin serves this source over the
// Describe channel; the host splices it onto the base (base ++ plugin) and
// validates every authored `cdp:` step's plugin_input against #CdpInput.
//
// Since the schema-compaction cutover the per-verb fields LEFT core #Op: an
// authored `cdp: <method>` step (scalar sugar) or `cdp: {method: …, tab: …}`
// (map form) desugars to the INTERNAL plugin/plugin_input envelope, and every
// cdp-exclusive modifier lives HERE — the former core #CdpMethod enum is this
// def's `method` field, and the former shared #Op `method` HTTP-method modifier
// (which `raw` used for the CDP protocol method name) is RENAMED `http_method`
// (the input's `method` key is the VERB method). The shared assertion matchers
// (exit_status/stdout/stderr) and the general `timeout` stay on core #Op, read
// off the step Op by the provider.
//
// SELF-CONTAINED: it references NO base def, so it compiles standalone
// (gengotypes + the load-gate compile) AND splices onto the base (base ++ plugin
// is a def-name collision check, not a base-reference resolver).
#CdpInput: {
// method — the cdp method to dispatch (the former core #CdpMethod enum; also
// the scalar-sugar primary: `cdp: <method>`).
method: "status" | "list" | "url" | "text" | "html" | "eval" | "axtree" | "coords" | "raw" | "wait" | "screenshot" | "open" | "close" | "click" | "type" | "spa-status" | "spa-click" | "spa-type" | "spa-key" | "spa-key-combo" | "spa-mouse"
// tab — the target tab: a 1-based page index or a DevTools UUID.
tab?: string
// expression — the JavaScript expression `eval` evaluates.
expression?: string
// url — the page URL `open` navigates to.
url?: string @go(URL)
// selector — the CSS selector (coords/wait/click/type; pierces shadow DOM).
selector?: string
// text — the text `type`/`spa-type` types.
text?: string
// x / y — desktop-absolute coordinates (spa-click/spa-mouse).
x?: int @go(,type=int)
y?: int @go(,type=int)
// button — the mouse button for spa-click (default left).
button?: string
// key — the named key `spa-key` presses.
key?: string @go(KeyName)
// combo — the key combo `spa-key-combo` sends (e.g. "ctrl+t").
combo?: string
// query — the optional filter `axtree` matches accessibility nodes against.
query?: string
// http_method — the raw CDP protocol method `raw` calls (e.g.
// "Page.captureScreenshot"; RENAMED from the former shared #Op `method`
// modifier — `method` here is the VERB method).
http_method?: string @go(HttpMethod)
// params — the JSON params blob `raw` passes to the protocol method.
params?: string
// artifact — the host path `screenshot` writes the PNG to.
artifact?: string
// artifact_min_bytes / artifact_min_dimensions / artifact_not_uniform — the
// post-run artifact-reality assertions (sdk.RunArtifactValidators).
artifact_min_bytes?: int & >=0 @go(ArtifactMinBytes,type=int)
artifact_min_dimensions?: string & =~"^[0-9]+x[0-9]+$" @go(ArtifactMinDimensions)
artifact_not_uniform?: bool @go(ArtifactNotUniform)
}

See also the candy reference for this candy’s install surface.