Skip to content

refactor(daemon): inject the command surface as a port - #3402

Draft
thymikee wants to merge 2 commits into
refactor/command-runtime-contractsfrom
refactor/daemon-command-surface-injection
Draft

thymikee wants to merge 2 commits into
refactor/command-runtime-contractsfrom
refactor/daemon-command-surface-injection

Conversation

@thymikee

@thymikee thymikee commented Oct 10, 2026 •

Copy link
Copy Markdown
Member

Summary

Stacked on #3394. The daemon stops importing createCommandSurfaceAgentDevice: the composition root (src/daemon.ts) now supplies it as the required createCommandSurface port, typed by CreateDaemonCommandSurface in @agent-device/contracts/daemon-command-surface. Threading path: RequestRouterDeps -> request-handler-chain params -> session/snapshot/find/interaction handlers -> generic dispatch -> execution runtimes (interaction, screenshot, selector, snapshot, sparse-fallback, generic-settle, session-open). Behavior unchanged; the field stays required, so 143 test param-bag literals gained one line via a shared fixture (src/daemon/__tests__/command-surface-fixture.ts). No assertions changed except three exact-forward-shape tests that now include the port.

Diff budget: the production change is ~450 lines (24 files); the rest is the mechanical AST-codemod insertion of the required createCommandSurface fixture line into 143 test param bags, and splitting it out would leave an intermediate commit that does not type-check.

Validation

Commit f21198abd. pnpm build, pnpm check:quick, pnpm check:layering, pnpm check:di-seams, test-file size ratchet, and pnpm check:affected --run all pass. Depgraph query: zero edges from daemon/** production nodes to command-runtime/** or commands/** nodes (jq on .tmp/depgraph/graph.json over production src/daemon/** sources); the only edge into command-runtime/runtime-command-surface.ts originates from the daemon.ts executable.

…ed port

The daemon no longer imports createCommandSurfaceAgentDevice; the composition
root (src/daemon.ts) supplies it through the required createCommandSurface
field threaded from RequestRouterDeps down to every execution runtime. The
port shape lives in @agent-device/contracts/daemon-command-surface so naming
it costs daemon files no type edge into the command families.
@thymikee
thymikee force-pushed the refactor/daemon-command-surface-injection branch from 06b89da to f21198a Compare October 10, 2026 21:55
@github-actions

Copy link
Copy Markdown

Size Report

Metric Base Current Diff
Installed (including dependencies) 5.15 MB 5.15 MB +2.7 kB
Package (unpacked) 5.15 MB 5.15 MB +2.7 kB
Package (download) 1.55 MB 1.55 MB +857 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 26.4 ms 26.2 ms -0.3 ms
CLI --help 81.4 ms 80.6 ms -0.8 ms

@thymikee

Copy link
Copy Markdown
Member Author

I found nothing that needs a fix in f21198a, but this review is not a full check. I did not run tsc, depgraph or check:di-seams, so the zero-edge depgraph claim rests on my read of the PR head, not on the graph. The injected value is the same createCommandSurfaceAgentDevice function the old imports supplied, called with the same config, so I did not ask for a live device run. I did not read all 143 test bag edits one by one. I filtered the diff for non-fixture lines and found only a reformat.

The 14 checks are green and none fail. I know of no conflicts. The base is the stacked branch refactor/command-runtime-contracts (#3394), which is still open, and this review assumes #3394 lands as reviewed. This PR can merge after #3394 merges and it is rebased onto main.

Not blocking: the port in daemon-command-surface.ts re-declares option shapes that src/commands already owns, such as DaemonWaitTarget, DaemonSelectorSnapshotOptions and the gesture and press/fill/longPress options. Each shape now has two declarations, and only the assignability check in daemon.ts ties them together. The rule would be one declaration per command option or result shape, in contracts, with src/commands importing it. Also, the members of DaemonCommandSurfaceCapture, DaemonCommandSurfaceSelectors and DaemonCommandSurfaceInteractions use method shorthand, which TypeScript checks bivariantly (see line 300). A required field added to the implementation's options would still compile, which weakens the header claim at lines 1-4. Function-typed properties would make strictFunctionTypes check them. Take or leave both.

Is the 357-line contracts mirror the part to cut? The threading itself matches how RequestRouterDeps already carries androidObservation and platformResourceCleanup. I found no single per-request bag that reaches all four construction sites, so I accept it at 433 net production lines. If the command option and result types the daemon calls (wait, find/get/is, press/fill/longPress/hover, gesture, screenshot, snapshot) moved into @agent-device/contracts, the port could be about 30 lines of interface over shared types. That would be a follow-up type move like #3394, not part of this PR.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant