@@ -9,8 +9,8 @@ A control channel lets a script drive a running SpringBoard the way a user
99drives it — open an editor, set its fields, run a command, place the camera,
1010capture the result — without synthesising X11 input.
1111
12- Status: ** implemented for editor fields, registered commands, camera state, and
13- ordered capture; domain handles are the next layer .**
12+ Status: ** implemented for editor fields, domain dialogs, registered commands,
13+ camera state, and ordered capture .**
1414
1515## Why
1616
@@ -47,7 +47,7 @@ The Python client detects that replacement, waits for the new `instance_id`,
4747refreshes the schema, and reconnects subsequent calls; a caller does not need
4848to rebuild its editor or camera handles.
4949
50- ## Three surfaces, all first -class
50+ ## First -class surfaces
5151
5252** Editors** — ` ui.open(tab, editor) ` , ` ui.set(editor, field, value) ` ,
5353` ui.get(editor, field) ` . This is the user path: ` Editor::set_field_value `
@@ -78,6 +78,22 @@ controller distance/height), `camera.trace_screen_ray(x, y)`,
7878reload deliberately preserves engine world/project state; it is not a project
7979reset.
8080
81+ ** Dialogs** — ` dialog.open/get/set/select/accept/cancel ` controls typed
82+ project/file dialogs through their existing action and modal paths. A domain
83+ workflow can create a project, choose a VFS project, or save/export by name
84+ without synthesising a click, text entry, or Enter key:
85+
86+ ``` python
87+ project = sb.dialog(" new_project" ).open()
88+ project.set(" name" , " Example" )
89+ project.set(" size_x" , 32 )
90+ project.accept()
91+
92+ load = sb.dialog(" load_project" ).open()
93+ load.select(" springboard/projects/Example.sdd" )
94+ load.accept()
95+ ```
96+
8197## The Python client
8298
8399` tools/control/ ` , a ` control ` package alongside ` e2e ` /` smoke ` /` lint ` , depending
@@ -124,7 +140,7 @@ a step at a time while the rest of it still clicks.
124140` native/src/sbc/control/ ` separates the two halves so neither drifts into the
125141other:
126142
127- - ` api/ ` — the surface, one file per method group (` editors ` , ` commands ` ,
143+ - ` api/ ` — the surface, one file per method group (` editors ` , ` dialogs ` , ` commands ` ,
128144 ` camera ` , ` capture ` , ` schema ` ). Each goes through the seam its user action
129145 goes through, and knows nothing about sockets.
130146- ` channel/ ` — the plumbing: ` server ` (socket and connections), ` discovery `
@@ -136,8 +152,9 @@ other:
136152## When a call is done
137153
138154A reply is sent once its effect has landed, not once the request was accepted:
139- ` ui.open ` answers when the editor is on screen, ` capture ` when the image is on
140- disk, and ` runtime.barrier ` after two input-idle native updates. Requests on a
155+ ` ui.open ` answers when the editor is on screen, ` dialog.open ` /` dialog.accept `
156+ answer when the modal opens/closes, ` capture ` when the image is on disk, and
157+ ` runtime.barrier ` after two input-idle native updates. Requests on a
141158connection apply and answer in order, and ` capture ` is queued at
142159` draw_screen_post ` , so an image already contains every call before it. No
143160scenario needs a sleep to make a screenshot honest.
@@ -148,7 +165,7 @@ Nothing in this channel may fail by doing nothing.
148165
149166## Scope
150167
151- ** Built** : ` describe ` , ` ui.open/set/get ` , ` command.execute ` ,
168+ ** Built** : ` describe ` , ` ui.open/set/get ` , ` dialog.open/get/set/select/accept/cancel ` , ` command.execute ` ,
152169` camera.set/get/trace_screen_ray/zoom ` ,
153170` capture ` , ` runtime.barrier ` , ` runtime.reload_native_modules ` . ` SBC_CONTROL_FILE ` names the discovery file and turns the channel on;
154171the E2E harness sets it per run and exposes the connection as
0 commit comments