Skip to content

feat(desktop): Node producer + FixtureBackend + MCP tools + Windows bridge IPC - #12

Merged
rrader26 merged 3 commits into
mainfrom
feat/spec-v0.4-desktop-kind
May 11, 2026
Merged

feat(desktop): Node producer + FixtureBackend + MCP tools + Windows bridge IPC#12
rrader26 merged 3 commits into
mainfrom
feat/spec-v0.4-desktop-kind

Conversation

@rrader26

Copy link
Copy Markdown
Contributor

Summary

Follow-up to PR #11 (which merged the v0.4 spec only). This PR ships
the Node-side producer + fixture backend + MCP tool surface + Windows
bridge IPC substrate
— everything required for the spec-v0.4
desktop kind to work end-to-end with a real AI tool today, plus the
beginning of the Windows bridge that will replace the fixture backend
with live UIA in subsequent PRs.

End-to-end validated locally: Claude Code (configured to use
`agentmark` over MCP) successfully drove a full round-trip against
the FixtureBackend — open session, snapshot the NowCerts preset, type
into the Company Name field, re-snapshot, observe the typed value
reflected in the markdown.

What's in this PR

Node-side desktop module (`src/desktop/`)

  • `types.ts` — `DesktopCaptureBackend` interface contract,
    `DesktopCapture`, `DesktopElement`, normalised `DesktopRole`
    vocabulary, `ExecuteDesktopAction` (click | type | select |
    check | expand | focus | scroll_to | key)
  • `body-builder.ts` — walks the tree → markdown + actions map.
    Headings for windows/panes/dialogs; lists for menus & trees; native
    markdown tables for grids; `[ACTION:]`/`[INPUT:]` tags for
    interactive elements; `[WINDOW:]`/`[ELEMENT:]` structural markers
  • `desktop-converter.ts` — `convertDesktop()` entry point.
    Populates the `ActionBinding` with each action's underlying
    `element_id` so the runtime resolves `execute(actionId)` →
    `backend.execute({ element_id })`
  • `fixture-backend.ts` — in-memory backend with Excel + NowCerts
    presets. Round-trippable for tests

MCP surface (`src/mcp/`)

  • 4 new tools in `ALL_TOOLS`:
    `agentmark_desktop_open` / `_close` / `_snapshot` / `_execute`
  • Dispatcher caches binding + action types per session so `_execute`
    resolves action IDs without the client knowing native element IDs
  • Backend selection at open: `fixture` (default), `windows_uia`,
    `macos_axapi` — the OS ones return "not yet bundled" until the
    bridges ship
  • `agentmark_list_sessions` extended to report active desktop sessions

Windows UIA bridge scaffold (`apps/agent-runner/bridges/windows/`)

  • .NET 8 console project, FlaUI 5.0.0 dependency
  • Stdio JSON-RPC 2.0 server (one message per line, stdout = framed
    JSON, stderr = diagnostics)
  • Two no-UIA methods for cross-language pipeline validation:
    `ping`, `capabilities` — Phase 0e2 (`list_windows`, `capture`)
    and 0e3 (`execute`) land in follow-up PRs
  • PowerShell smoke test driving the bridge via .NET Process API (avoids
    PowerShell pipe EOF bug)
  • README documenting build + protocol
  • Built + tested over SSH from a Mac against a Parallels shared-folder
    checkout — ARM64 native (no x64 emulation), round-trip works, exit 0

`.gitignore` additions

  • bin/, obj/, *.user, .vs/, .idea/

Tests

  • `test/spec-v0.4.test.ts` (7 tests)
  • `test/desktop/desktop-converter.test.ts` (8 tests)
  • `test/mcp/desktop-dispatcher.test.ts` (12 tests)

`npm test` — 295 passed, 10 skipped (pre-existing), 0 failed.

Backwards compat

Pure additive. No existing exports changed; no existing tests touched
beyond bumping three hardcoded `'0.3'` version strings to `'0.4'` to
match the new `AGENTMARK_VERSION` constant.

Next PRs

  1. Phase 0e2: Windows UIA capture (`list_windows`, `capture`)
  2. Phase 0e3: Windows UIA execute
  3. Phase 0e4: live Excel/NowCerts demo with the real bridge
  4. Phase 0f: Node-side `WindowsUiaBackend` that spawns the bridge

🤖 Generated with Claude Code

rrader26-sys and others added 3 commits May 11, 2026 09:58
Implements the spec-v0.4 producer side. Pure-Node and OS-agnostic — OS
work is hidden behind the new DesktopCaptureBackend interface. Real OS
bridges (Windows UIA via FlaUI, macOS AXAPI via Swift) ship in
subsequent PRs as separate sidecar processes that implement this
interface.

New module: src/desktop/

  - types.ts            — DesktopCaptureBackend interface contract,
                          DesktopCapture (the tree shape backends
                          return), DesktopElement (one node), DesktopRole
                          (normalised UIA/AXAPI role vocabulary),
                          ExecuteDesktopAction (click | type | select |
                          check | expand | focus | scroll_to | key)
  - body-builder.ts     — walks the captured tree → emits markdown +
                          Records<actionId, ActionDefinition>. Headings
                          for windows/panes/dialogs, lists for menus and
                          tree controls, native tables for grids,
                          [ACTION:]/[INPUT:] tags for interactive
                          elements, [WINDOW:]/[ELEMENT:] for structural
                          markers
  - desktop-converter.ts — convertDesktop() entry point. Backend agnostic.
                          Populates ActionBinding with the original
                          element_id so the runtime can resolve
                          execute(actionId) → backend.execute({ element_id })
  - fixture-backend.ts  — in-memory DesktopCaptureBackend returning
                          pre-baked Excel + NowCerts trees. Lets the
                          MCP server work end-to-end on machines without
                          the real OS bridge (e.g. testing on a Mac
                          before the AXAPI bridge exists; CI runners
                          with no GUI). Round-trippable — execute() type
                          mutates a value map that the next capture()
                          reflects.
  - index.ts            — module exports

Wired into the package root src/index.ts under the existing v0.* section
headers, matching how PDF/audio/video are exported.

Tests: test/desktop/desktop-converter.test.ts — 8 tests covering:
  - Valid v0.4 desktop snapshot from Excel fixture (validates clean
    against schema + cross-field invariants)
  - NowCerts fixture with editable inputs rendered as [INPUT:] tags
  - Round-trip: type → re-capture → observe the typed text
  - Synthesised desktop:// URL when none provided
  - Explicit URL override respected
  - Backend name reported in desktop_meta.a11y_backend
  - Check_box aria.checked state preserved
  - Static-only snapshot drops the `actions` field

Full suite: 283 passed, 10 skipped, 0 failed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wires the v0.4 desktop kind through the existing MCP server so any
MCP-compatible AI tool (Claude Code, Cursor, Codex, Windsurf, Continue,
Cody, Agent Zero, etc.) can drive native applications via AgentMark by
adding one stanza to its mcp config:

    {
      "mcpServers": {
        "agentmark": {
          "command": "npx",
          "args": ["-y", "@thinkfleet/agentmark", "mcp"]
        }
      }
    }

Once connected the AI gets:
  - agentmark_desktop_open  — attach to a capture backend (default: fixture)
  - agentmark_desktop_snapshot — capture the focused window (or specified
    target) as v0.4 markdown
  - agentmark_desktop_execute — drive an action by ID against the most
    recent snapshot. Server resolves action_id → backend element_id via
    the ActionBinding cached at snapshot time
  - agentmark_desktop_close — release the backend

Backend selection at open-time: `fixture` ships today (in-memory Excel +
NowCerts trees, works on any OS). `windows_uia` and `macos_axapi` return
a friendly "not yet bundled" error until the real bridges ship in
follow-up PRs.

Action-type → ExecuteDesktopAction mapping happens server-side so the
client only needs to know the action_id from the snapshot, not the
underlying UIA/AXAPI pattern.

Files touched:
  - src/mcp/types.ts        — DesktopSession type + 'dt' prefix
  - src/mcp/tool-defs.ts    — 4 new tools added to ALL_TOOLS
  - src/mcp/dispatcher.ts   — handlers, switch cases, listSessions,
                              disposeAll all extended
  - test/mcp/desktop-dispatcher.test.ts — 12 new tests covering open,
    snapshot, execute round-trip, unknown action handling, close,
    list_sessions integration

Full suite: 295 passed, 10 skipped, 0 failed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the Windows UIA bridge as a .NET 8 console project at
apps/agent-runner/bridges/windows/. Stdio JSON-RPC 2.0 server; one
message per line; stdout strictly framed JSON, stderr for diagnostics.

This first commit ships the protocol substrate and two no-UIA methods
so we can validate the cross-language pipeline before adding the heavy
COM-STA capture/execute logic in Phase 0e2/0e3:

  - ping         -> { pong, version, arch, processId }
  - capabilities -> supported methods + UIA provider info

Built + smoke-tested over SSH from the Mac against a Parallels-shared
checkout. ARM64 native build (no x64 emulation overhead). Round-trip
verified: pipe two requests -> close stdin -> get two responses ->
bridge exits 0.

Implementation notes:
- Sync stdin reads (Console.In.ReadLine). Async ReadLineAsync has a
  known issue on Windows pipes where it does not return null on EOF,
  hanging the process even after the parent closes the pipe. Sync
  reads handle EOF correctly. UIA is COM-STA anyway, so async would
  not buy us anything for capture/execute.
- UTF8Encoding(false) on both pipes to avoid BOM corruption of the
  JSON-RPC framing.
- All diagnostic output to stderr, never stdout.
- Smoke test uses .NET Process API rather than PowerShell pipes —
  PowerShell's pipe-to-native-exe does not propagate EOF, which would
  hang the bridge on smoke-test runs.

.gitignore extended for bin/, obj/, *.user, .vs/, .idea/.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rrader26
rrader26 merged commit 5d9a397 into main May 11, 2026
4 checks passed
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.

2 participants