feat(runtime): make the headless agent runtime DOM-free - #69
Conversation
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.
Walkthrough
ChangesHeadless Agent Runtime DOM-Free Path
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
Estimated Review Effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
@coderabbitai review |
✅ Action performedReview finished.
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## beta #69 +/- ##
=======================================
Coverage ? 89.96%
=======================================
Files ? 32
Lines ? 1514
Branches ? 433
=======================================
Hits ? 1362
Misses ? 142
Partials ? 10
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
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
📒 Files selected for processing (3)
.changeset/headless-agent-runtime-dom-free.mdpackages/ignite-element/src/IgniteElementFactory.tspackages/ignite-element/src/tests/agent-runtime-headless-node.test.ts
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, sogetSchema()/execute()threwdocument is not definedin Node.What changed
createRuntimeHostfalls back to a bareEventTargetwhen there's nodocument, and keepsdocument.createElementunder a real/jsdom DOM (browser + existing tests unchanged). The headless host is only ever used as an EventTarget —on()registersaddEventListener/removeEventListenerand effect emits go throughdispatchEvent. Node 22 shipsEventTarget+CustomEventglobally.@vitest-environment node, zero jsdom) coversgetSchema/execute/on/watchView— including effect events flowing through theEventTargethost.Verification
verify.sh --fullALL PASSED; TDD red receipt captured against base.Review notes (CodeRabbit CLI gate)
as unknown as HTMLElementcast increateRuntimeHostis documented + accepted with justification: the runtime host shares the render path'sHostgeneric (typedHTMLElementfor the JSX renderer'sappendChild), and the runtime never touches the host with element-only APIs (verified). The proper fix — splitting the runtime-host type (EventTarget) from the render-hostHostgeneric — is filed as a follow-up.runtime.executenot bound, scalarvalueenvelope not strict, and acanExecutedoc-wording overpromise — are filed as a separate follow-up.Changeset
Lockstep minor.
Summary by CodeRabbit
New Features
Bug Fixes
document is not definederrors when using the runtime outside the browser.Tests