Skip to content

feat(runtime): make the headless agent runtime DOM-free - #69

Merged
0xjcf merged 1 commit into
betafrom
fas/headless-runtime-dom-free
Jun 27, 2026
Merged

feat(runtime): make the headless agent runtime DOM-free#69
0xjcf merged 1 commit into
betafrom
fas/headless-runtime-dom-free

Conversation

@0xjcf

@0xjcf 0xjcf commented Jun 26, 2026

Copy link
Copy Markdown
Owner

Summary

Phase A of the igniteTools agent showcase: the headless agent runtime (getSchema() / execute() / on() / watchView()) now runs in pure Node / edge with no jsdom. Unblocks running an igniteTools agent loop headless on a server, CLI, or edge device with zero DOM shim (the Phase B/C terminal↔browser showcase needs this).

Found while dogfooding igniteTools: the runtime is meant to be headless, but allocated its host via document.createElement, so getSchema()/execute() threw document is not defined in Node.

What changed

  • createRuntimeHost falls back to a bare EventTarget when there's no document, and keeps document.createElement under a real/jsdom DOM (browser + existing tests unchanged). The headless host is only ever used as an EventTargeton() registers addEventListener/removeEventListener and effect emits go through dispatchEvent. Node 22 ships EventTarget + CustomEvent globally.
  • The DOM render path (custom element / DOM bridge) is unchanged and still requires a real DOM.
  • New pure-Node test (@vitest-environment node, zero jsdom) covers getSchema/execute/on/watchView — including effect events flowing through the EventTarget host.

Verification

  • New headless test 5/5; full package suite 453/453 (jsdom path unchanged); verify.sh --full ALL PASSED; TDD red receipt captured against base.

Review notes (CodeRabbit CLI gate)

  • The as unknown as HTMLElement cast in createRuntimeHost is documented + accepted with justification: the runtime host shares the render path's Host generic (typed HTMLElement for the JSX renderer's appendChild), and the runtime never touches the host with element-only APIs (verified). The proper fix — splitting the runtime-host type (EventTarget) from the render-host Host generic — is filed as a follow-up.
  • Three findings on pre-existing PR2 code (out of this PR's scope) — runtime.execute not bound, scalar value envelope not strict, and a canExecute doc-wording overpromise — are filed as a separate follow-up.

Changeset

Lockstep minor.

Summary by CodeRabbit

  • New Features

    • Headless runtime operations now work in non-DOM environments, including Node and edge runtimes.
    • Core actions like schema fetching, execution, event handling, and view watching now run without requiring a browser DOM.
  • Bug Fixes

    • Prevented document is not defined errors when using the runtime outside the browser.
  • Tests

    • Added coverage for headless runtime behavior in a pure Node environment.

getSchema()/execute()/on()/watchView() are meant to be headless but allocated
the runtime host via document.createElement, so they threw 'document is not
defined' in pure Node/edge. The headless host is only ever used as an
EventTarget (on() add/removeEventListener; effect emits via host.dispatchEvent),
so a real element was never needed: createRuntimeHost now falls back to a bare
EventTarget when there is no document, and keeps document.createElement when a
real/jsdom DOM is present (browser + existing tests unchanged). The DOM render
path still requires a real DOM. Adds a pure-Node (no jsdom) headless test
covering getSchema/execute/on/watchView. Unblocks running an igniteTools agent
loop headless on a server, CLI, or edge device with zero DOM shim.
@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

createRuntimeHost now falls back to EventTarget when document is unavailable. A new Node test file covers getSchema(), execute(), on(), and watchView() without DOM APIs, and the changeset records the release bumps.

Changes

Headless Agent Runtime DOM-Free Path

Layer / File(s) Summary
Runtime host fallback and release note
.changeset/headless-agent-runtime-dom-free.md, packages/ignite-element/src/IgniteElementFactory.ts
createRuntimeHost uses an EventTarget when document is unavailable, and the changeset records the DOM-free runtime note plus minor package bumps.
Node runtime coverage
packages/ignite-element/src/tests/agent-runtime-headless-node.test.ts
A Node-environment test builds a counter machine and verifies getSchema(), execute(), on(), and watchView() without DOM APIs.

Sequence Diagram(s)

sequenceDiagram
  participant NodeRuntime as Node runtime
  participant igniteCore
  participant createRuntimeHost
  participant EventTarget
  NodeRuntime->>igniteCore: call getSchema()
  NodeRuntime->>igniteCore: call execute()
  igniteCore->>createRuntimeHost: create runtime host
  createRuntimeHost-->>igniteCore: EventTarget when document is undefined
  NodeRuntime->>igniteCore: call on() and watchView()
  igniteCore->>EventTarget: addEventListener() / dispatchEvent()
  EventTarget-->>igniteCore: counted event and view updates
Loading

Estimated Review Effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐇 I hopped through Node with nary a pane,
EventTarget jingled like bells in the rain.
execute() boinged, the counter grew tall,
watchView() said “hurray!” with no DOM at all.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: making the headless agent runtime DOM-free.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fas/headless-runtime-dom-free

Comment @coderabbitai help to get the list of available commands.

@0xjcf

0xjcf commented Jun 26, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@codecov

codecov Bot commented Jun 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (beta@fe3fc74). Learn more about missing BASE report.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             beta      #69   +/-   ##
=======================================
  Coverage        ?   89.96%           
=======================================
  Files           ?       32           
  Lines           ?     1514           
  Branches        ?      433           
=======================================
  Hits            ?     1362           
  Misses          ?      142           
  Partials        ?       10           
Flag Coverage Δ
unittests 89.96% <100.00%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...ackages/ignite-element/src/IgniteElementFactory.ts 97.20% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/ignite-element/src/IgniteElementFactory.ts`:
- Around line 338-346: The `createRuntimeHost` fallback is leaking a
non-HTMLElement through the public `createAdditionalArgs(adapter, runtimeHost)`
callback path, even though `createAdditionalArgs` is typed to receive an
`HTMLElement`. Update `IgniteElementFactory` so the DOM-free branch does not
pass the synthetic runtime host into user-facing `createAdditionalArgs` calls,
or split the runtime-host type from the render host before those calls in the
`createAdditionalArgs` flow and related call sites.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3cf8e94d-7de9-477f-845d-b9ab1c629b4e

📥 Commits

Reviewing files that changed from the base of the PR and between fe3fc74 and f06f973.

📒 Files selected for processing (3)
  • .changeset/headless-agent-runtime-dom-free.md
  • packages/ignite-element/src/IgniteElementFactory.ts
  • packages/ignite-element/src/tests/agent-runtime-headless-node.test.ts

Comment thread packages/ignite-element/src/IgniteElementFactory.ts
@0xjcf
0xjcf merged commit 787b6c8 into beta Jun 27, 2026
6 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.

1 participant