@vsuryav/agent-sim 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/README.md +25 -0
  2. package/bin/agent-sim.js +25 -0
  3. package/package.json +72 -0
  4. package/src/app-paths.ts +29 -0
  5. package/src/app-sync.test.ts +75 -0
  6. package/src/app-sync.ts +110 -0
  7. package/src/cli.ts +129 -0
  8. package/src/collector/claude-code.test.ts +102 -0
  9. package/src/collector/claude-code.ts +133 -0
  10. package/src/collector/codex-cli.test.ts +116 -0
  11. package/src/collector/codex-cli.ts +149 -0
  12. package/src/collector/db.test.ts +59 -0
  13. package/src/collector/db.ts +125 -0
  14. package/src/collector/names.test.ts +21 -0
  15. package/src/collector/names.ts +28 -0
  16. package/src/collector/personality.test.ts +40 -0
  17. package/src/collector/personality.ts +46 -0
  18. package/src/collector/remote-sync.test.ts +31 -0
  19. package/src/collector/remote-sync.ts +171 -0
  20. package/src/collector/sync.test.ts +67 -0
  21. package/src/collector/sync.ts +148 -0
  22. package/src/collector/types.ts +1 -0
  23. package/src/engine/bootstrap/state.ts +3 -0
  24. package/src/engine/buddy/CompanionSprite.tsx +371 -0
  25. package/src/engine/buddy/companion.ts +133 -0
  26. package/src/engine/buddy/prompt.ts +36 -0
  27. package/src/engine/buddy/sprites.ts +514 -0
  28. package/src/engine/buddy/types.ts +148 -0
  29. package/src/engine/buddy/useBuddyNotification.tsx +98 -0
  30. package/src/engine/ink/Ansi.tsx +292 -0
  31. package/src/engine/ink/bidi.ts +139 -0
  32. package/src/engine/ink/clearTerminal.ts +74 -0
  33. package/src/engine/ink/colorize.ts +231 -0
  34. package/src/engine/ink/components/AlternateScreen.tsx +80 -0
  35. package/src/engine/ink/components/App.tsx +658 -0
  36. package/src/engine/ink/components/AppContext.ts +21 -0
  37. package/src/engine/ink/components/Box.tsx +214 -0
  38. package/src/engine/ink/components/Button.tsx +192 -0
  39. package/src/engine/ink/components/ClockContext.tsx +112 -0
  40. package/src/engine/ink/components/CursorDeclarationContext.ts +32 -0
  41. package/src/engine/ink/components/ErrorOverview.tsx +109 -0
  42. package/src/engine/ink/components/Link.tsx +42 -0
  43. package/src/engine/ink/components/Newline.tsx +39 -0
  44. package/src/engine/ink/components/NoSelect.tsx +68 -0
  45. package/src/engine/ink/components/RawAnsi.tsx +57 -0
  46. package/src/engine/ink/components/ScrollBox.tsx +237 -0
  47. package/src/engine/ink/components/Spacer.tsx +20 -0
  48. package/src/engine/ink/components/StdinContext.ts +49 -0
  49. package/src/engine/ink/components/TerminalFocusContext.tsx +52 -0
  50. package/src/engine/ink/components/TerminalSizeContext.tsx +7 -0
  51. package/src/engine/ink/components/Text.tsx +254 -0
  52. package/src/engine/ink/constants.ts +2 -0
  53. package/src/engine/ink/dom.ts +484 -0
  54. package/src/engine/ink/events/click-event.ts +38 -0
  55. package/src/engine/ink/events/dispatcher.ts +233 -0
  56. package/src/engine/ink/events/emitter.ts +39 -0
  57. package/src/engine/ink/events/event-handlers.ts +73 -0
  58. package/src/engine/ink/events/event.ts +11 -0
  59. package/src/engine/ink/events/focus-event.ts +21 -0
  60. package/src/engine/ink/events/input-event.ts +205 -0
  61. package/src/engine/ink/events/keyboard-event.ts +51 -0
  62. package/src/engine/ink/events/terminal-event.ts +107 -0
  63. package/src/engine/ink/events/terminal-focus-event.ts +19 -0
  64. package/src/engine/ink/focus.ts +181 -0
  65. package/src/engine/ink/frame.ts +124 -0
  66. package/src/engine/ink/get-max-width.ts +27 -0
  67. package/src/engine/ink/global.d.ts +18 -0
  68. package/src/engine/ink/hit-test.ts +130 -0
  69. package/src/engine/ink/hooks/use-animation-frame.ts +57 -0
  70. package/src/engine/ink/hooks/use-app.ts +8 -0
  71. package/src/engine/ink/hooks/use-declared-cursor.ts +73 -0
  72. package/src/engine/ink/hooks/use-input.ts +92 -0
  73. package/src/engine/ink/hooks/use-interval.ts +67 -0
  74. package/src/engine/ink/hooks/use-search-highlight.ts +53 -0
  75. package/src/engine/ink/hooks/use-selection.ts +104 -0
  76. package/src/engine/ink/hooks/use-stdin.ts +8 -0
  77. package/src/engine/ink/hooks/use-tab-status.ts +72 -0
  78. package/src/engine/ink/hooks/use-terminal-focus.ts +16 -0
  79. package/src/engine/ink/hooks/use-terminal-title.ts +31 -0
  80. package/src/engine/ink/hooks/use-terminal-viewport.ts +96 -0
  81. package/src/engine/ink/ink.tsx +1723 -0
  82. package/src/engine/ink/instances.ts +10 -0
  83. package/src/engine/ink/layout/engine.ts +6 -0
  84. package/src/engine/ink/layout/geometry.ts +97 -0
  85. package/src/engine/ink/layout/node.ts +152 -0
  86. package/src/engine/ink/layout/yoga.ts +308 -0
  87. package/src/engine/ink/line-width-cache.ts +24 -0
  88. package/src/engine/ink/log-update.ts +773 -0
  89. package/src/engine/ink/measure-element.ts +23 -0
  90. package/src/engine/ink/measure-text.ts +47 -0
  91. package/src/engine/ink/node-cache.ts +54 -0
  92. package/src/engine/ink/optimizer.ts +93 -0
  93. package/src/engine/ink/output.ts +797 -0
  94. package/src/engine/ink/parse-keypress.ts +801 -0
  95. package/src/engine/ink/reconciler.ts +512 -0
  96. package/src/engine/ink/render-border.ts +231 -0
  97. package/src/engine/ink/render-node-to-output.ts +1462 -0
  98. package/src/engine/ink/render-to-screen.ts +231 -0
  99. package/src/engine/ink/renderer.ts +178 -0
  100. package/src/engine/ink/root.ts +184 -0
  101. package/src/engine/ink/screen.ts +1486 -0
  102. package/src/engine/ink/searchHighlight.ts +93 -0
  103. package/src/engine/ink/selection.ts +917 -0
  104. package/src/engine/ink/squash-text-nodes.ts +92 -0
  105. package/src/engine/ink/stringWidth.ts +222 -0
  106. package/src/engine/ink/styles.ts +771 -0
  107. package/src/engine/ink/supports-hyperlinks.ts +57 -0
  108. package/src/engine/ink/tabstops.ts +46 -0
  109. package/src/engine/ink/terminal-focus-state.ts +47 -0
  110. package/src/engine/ink/terminal-querier.ts +212 -0
  111. package/src/engine/ink/terminal.ts +248 -0
  112. package/src/engine/ink/termio/ansi.ts +75 -0
  113. package/src/engine/ink/termio/csi.ts +319 -0
  114. package/src/engine/ink/termio/dec.ts +60 -0
  115. package/src/engine/ink/termio/esc.ts +67 -0
  116. package/src/engine/ink/termio/osc.ts +493 -0
  117. package/src/engine/ink/termio/parser.ts +394 -0
  118. package/src/engine/ink/termio/sgr.ts +308 -0
  119. package/src/engine/ink/termio/tokenize.ts +319 -0
  120. package/src/engine/ink/termio/types.ts +236 -0
  121. package/src/engine/ink/useTerminalNotification.ts +126 -0
  122. package/src/engine/ink/warn.ts +9 -0
  123. package/src/engine/ink/widest-line.ts +19 -0
  124. package/src/engine/ink/wrap-text.ts +74 -0
  125. package/src/engine/ink/wrapAnsi.ts +20 -0
  126. package/src/engine/native-ts/yoga-layout/enums.ts +134 -0
  127. package/src/engine/native-ts/yoga-layout/index.ts +2578 -0
  128. package/src/engine/stubs/bootstrap-state.ts +4 -0
  129. package/src/engine/stubs/debug.ts +6 -0
  130. package/src/engine/stubs/log.ts +4 -0
  131. package/src/engine/utils/debug.ts +5 -0
  132. package/src/engine/utils/earlyInput.ts +4 -0
  133. package/src/engine/utils/env.ts +15 -0
  134. package/src/engine/utils/envUtils.ts +4 -0
  135. package/src/engine/utils/execFileNoThrow.ts +24 -0
  136. package/src/engine/utils/fullscreen.ts +4 -0
  137. package/src/engine/utils/intl.ts +9 -0
  138. package/src/engine/utils/log.ts +3 -0
  139. package/src/engine/utils/semver.ts +13 -0
  140. package/src/engine/utils/sliceAnsi.ts +10 -0
  141. package/src/engine/utils/theme.ts +17 -0
  142. package/src/game/App.tsx +141 -0
  143. package/src/game/agents/behavior.ts +249 -0
  144. package/src/game/agents/speech.ts +57 -0
  145. package/src/game/canvas.ts +98 -0
  146. package/src/game/launch.ts +36 -0
  147. package/src/game/ship/ShipView.tsx +145 -0
  148. package/src/game/ship/ship-map.ts +172 -0
  149. package/src/game/ui/AgentBio.tsx +72 -0
  150. package/src/game/ui/HUD.tsx +63 -0
  151. package/src/game/ui/StatusBar.tsx +49 -0
  152. package/src/game/useKeyboard.ts +62 -0
  153. package/src/main.tsx +22 -0
  154. package/src/run-interactive.ts +74 -0
@@ -0,0 +1,512 @@
1
+ /* eslint-disable custom-rules/no-top-level-side-effects */
2
+
3
+ import { appendFileSync } from 'fs'
4
+ import createReconciler from 'react-reconciler'
5
+ import { getYogaCounters } from '../native-ts/yoga-layout/index.js'
6
+ import { isEnvTruthy } from '../utils/envUtils.js'
7
+ import {
8
+ appendChildNode,
9
+ clearYogaNodeReferences,
10
+ createNode,
11
+ createTextNode,
12
+ type DOMElement,
13
+ type DOMNodeAttribute,
14
+ type ElementNames,
15
+ insertBeforeNode,
16
+ markDirty,
17
+ removeChildNode,
18
+ setAttribute,
19
+ setStyle,
20
+ setTextNodeValue,
21
+ setTextStyles,
22
+ type TextNode,
23
+ } from './dom.js'
24
+ import { Dispatcher } from './events/dispatcher.js'
25
+ import { EVENT_HANDLER_PROPS } from './events/event-handlers.js'
26
+ import { getFocusManager, getRootNode } from './focus.js'
27
+ import { LayoutDisplay } from './layout/node.js'
28
+ import applyStyles, { type Styles, type TextStyles } from './styles.js'
29
+
30
+ // We need to conditionally perform devtools connection to avoid
31
+ // accidentally breaking other third-party code.
32
+ // See https://github.com/vadimdemedes/ink/issues/384
33
+ if (process.env.NODE_ENV === 'development') {
34
+ try {
35
+ // eslint-disable-next-line custom-rules/no-top-level-dynamic-import -- dev-only; NODE_ENV check is DCE'd in production
36
+ void import('./devtools.js')
37
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
38
+ } catch (error: any) {
39
+ if (error.code === 'ERR_MODULE_NOT_FOUND') {
40
+ // biome-ignore lint/suspicious/noConsole: intentional warning
41
+ console.warn(
42
+ `
43
+ The environment variable DEV is set to true, so Ink tried to import \`react-devtools-core\`,
44
+ but this failed as it was not installed. Debugging with React Devtools requires it.
45
+
46
+ To install use this command:
47
+
48
+ $ npm install --save-dev react-devtools-core
49
+ `.trim() + '\n',
50
+ )
51
+ } else {
52
+ // eslint-disable-next-line @typescript-eslint/only-throw-error
53
+ throw error
54
+ }
55
+ }
56
+ }
57
+
58
+ // --
59
+
60
+ type AnyObject = Record<string, unknown>
61
+
62
+ const diff = (before: AnyObject, after: AnyObject): AnyObject | undefined => {
63
+ if (before === after) {
64
+ return
65
+ }
66
+
67
+ if (!before) {
68
+ return after
69
+ }
70
+
71
+ const changed: AnyObject = {}
72
+ let isChanged = false
73
+
74
+ for (const key of Object.keys(before)) {
75
+ const isDeleted = after ? !Object.hasOwn(after, key) : true
76
+
77
+ if (isDeleted) {
78
+ changed[key] = undefined
79
+ isChanged = true
80
+ }
81
+ }
82
+
83
+ if (after) {
84
+ for (const key of Object.keys(after)) {
85
+ if (after[key] !== before[key]) {
86
+ changed[key] = after[key]
87
+ isChanged = true
88
+ }
89
+ }
90
+ }
91
+
92
+ return isChanged ? changed : undefined
93
+ }
94
+
95
+ const cleanupYogaNode = (node: DOMElement | TextNode): void => {
96
+ const yogaNode = node.yogaNode
97
+ if (yogaNode) {
98
+ yogaNode.unsetMeasureFunc()
99
+ // Clear all references BEFORE freeing to prevent other code from
100
+ // accessing freed WASM memory during concurrent operations
101
+ clearYogaNodeReferences(node)
102
+ yogaNode.freeRecursive()
103
+ }
104
+ }
105
+
106
+ // --
107
+
108
+ type Props = Record<string, unknown>
109
+
110
+ type HostContext = {
111
+ isInsideText: boolean
112
+ }
113
+
114
+ function setEventHandler(node: DOMElement, key: string, value: unknown): void {
115
+ if (!node._eventHandlers) {
116
+ node._eventHandlers = {}
117
+ }
118
+ node._eventHandlers[key] = value
119
+ }
120
+
121
+ function applyProp(node: DOMElement, key: string, value: unknown): void {
122
+ if (key === 'children') return
123
+
124
+ if (key === 'style') {
125
+ setStyle(node, value as Styles)
126
+ if (node.yogaNode) {
127
+ applyStyles(node.yogaNode, value as Styles)
128
+ }
129
+ return
130
+ }
131
+
132
+ if (key === 'textStyles') {
133
+ node.textStyles = value as TextStyles
134
+ return
135
+ }
136
+
137
+ if (EVENT_HANDLER_PROPS.has(key)) {
138
+ setEventHandler(node, key, value)
139
+ return
140
+ }
141
+
142
+ setAttribute(node, key, value as DOMNodeAttribute)
143
+ }
144
+
145
+ // --
146
+
147
+ // react-reconciler's Fiber shape — only the fields we walk. The 5th arg to
148
+ // createInstance is the Fiber (`workInProgress` in react-reconciler.dev.js).
149
+ // _debugOwner is the component that rendered this element (dev builds only);
150
+ // return is the parent fiber (always present). We prefer _debugOwner since it
151
+ // skips past Box/Text wrappers to the actual named component.
152
+ type FiberLike = {
153
+ elementType?: { displayName?: string; name?: string } | string | null
154
+ _debugOwner?: FiberLike | null
155
+ return?: FiberLike | null
156
+ }
157
+
158
+ export function getOwnerChain(fiber: unknown): string[] {
159
+ const chain: string[] = []
160
+ const seen = new Set<unknown>()
161
+ let cur = fiber as FiberLike | null | undefined
162
+ for (let i = 0; cur && i < 50; i++) {
163
+ if (seen.has(cur)) break
164
+ seen.add(cur)
165
+ const t = cur.elementType
166
+ const name =
167
+ typeof t === 'function'
168
+ ? (t as { displayName?: string; name?: string }).displayName ||
169
+ (t as { displayName?: string; name?: string }).name
170
+ : typeof t === 'string'
171
+ ? undefined // host element (ink-box etc) — skip
172
+ : t?.displayName || t?.name
173
+ if (name && name !== chain[chain.length - 1]) chain.push(name)
174
+ cur = cur._debugOwner ?? cur.return
175
+ }
176
+ return chain
177
+ }
178
+
179
+ let debugRepaints: boolean | undefined
180
+ export function isDebugRepaintsEnabled(): boolean {
181
+ if (debugRepaints === undefined) {
182
+ debugRepaints = isEnvTruthy(process.env.CLAUDE_CODE_DEBUG_REPAINTS)
183
+ }
184
+ return debugRepaints
185
+ }
186
+
187
+ export const dispatcher = new Dispatcher()
188
+
189
+ // --- COMMIT INSTRUMENTATION (temp debugging) ---
190
+ // eslint-disable-next-line custom-rules/no-process-env-top-level -- debug instrumentation, read-once is fine
191
+ const COMMIT_LOG = process.env.CLAUDE_CODE_COMMIT_LOG
192
+ let _commits = 0
193
+ let _lastLog = 0
194
+ let _lastCommitAt = 0
195
+ let _maxGapMs = 0
196
+ let _createCount = 0
197
+ let _prepareAt = 0
198
+ // --- END ---
199
+
200
+ // --- SCROLL PROFILING (bench/scroll-e2e.sh reads via getLastYogaMs) ---
201
+ // Set by onComputeLayout wrapper in ink.tsx; read by onRender for phases.
202
+ let _lastYogaMs = 0
203
+ let _lastCommitMs = 0
204
+ let _commitStart = 0
205
+ export function recordYogaMs(ms: number): void {
206
+ _lastYogaMs = ms
207
+ }
208
+ export function getLastYogaMs(): number {
209
+ return _lastYogaMs
210
+ }
211
+ export function markCommitStart(): void {
212
+ _commitStart = performance.now()
213
+ }
214
+ export function getLastCommitMs(): number {
215
+ return _lastCommitMs
216
+ }
217
+ export function resetProfileCounters(): void {
218
+ _lastYogaMs = 0
219
+ _lastCommitMs = 0
220
+ _commitStart = 0
221
+ }
222
+ // --- END ---
223
+
224
+ const reconciler = createReconciler<
225
+ ElementNames,
226
+ Props,
227
+ DOMElement,
228
+ DOMElement,
229
+ TextNode,
230
+ DOMElement,
231
+ unknown,
232
+ unknown,
233
+ DOMElement,
234
+ HostContext,
235
+ null, // UpdatePayload - not used in React 19
236
+ NodeJS.Timeout,
237
+ -1,
238
+ null
239
+ >({
240
+ getRootHostContext: () => ({ isInsideText: false }),
241
+ prepareForCommit: () => {
242
+ if (COMMIT_LOG) _prepareAt = performance.now()
243
+ return null
244
+ },
245
+ preparePortalMount: () => null,
246
+ clearContainer: () => false,
247
+ resetAfterCommit(rootNode) {
248
+ _lastCommitMs = _commitStart > 0 ? performance.now() - _commitStart : 0
249
+ _commitStart = 0
250
+ if (COMMIT_LOG) {
251
+ const now = performance.now()
252
+ _commits++
253
+ const gap = _lastCommitAt > 0 ? now - _lastCommitAt : 0
254
+ if (gap > _maxGapMs) _maxGapMs = gap
255
+ _lastCommitAt = now
256
+ const reconcileMs = _prepareAt > 0 ? now - _prepareAt : 0
257
+ if (gap > 30 || reconcileMs > 20 || _createCount > 50) {
258
+ // eslint-disable-next-line custom-rules/no-sync-fs -- debug instrumentation
259
+ appendFileSync(
260
+ COMMIT_LOG,
261
+ `${now.toFixed(1)} gap=${gap.toFixed(1)}ms reconcile=${reconcileMs.toFixed(1)}ms creates=${_createCount}\n`,
262
+ )
263
+ }
264
+ _createCount = 0
265
+ if (now - _lastLog > 1000) {
266
+ // eslint-disable-next-line custom-rules/no-sync-fs -- debug instrumentation
267
+ appendFileSync(
268
+ COMMIT_LOG,
269
+ `${now.toFixed(1)} commits=${_commits}/s maxGap=${_maxGapMs.toFixed(1)}ms\n`,
270
+ )
271
+ _commits = 0
272
+ _maxGapMs = 0
273
+ _lastLog = now
274
+ }
275
+ }
276
+ const _t0 = COMMIT_LOG ? performance.now() : 0
277
+ if (typeof rootNode.onComputeLayout === 'function') {
278
+ rootNode.onComputeLayout()
279
+ }
280
+ if (COMMIT_LOG) {
281
+ const layoutMs = performance.now() - _t0
282
+ if (layoutMs > 20) {
283
+ const c = getYogaCounters()
284
+ // eslint-disable-next-line custom-rules/no-sync-fs -- debug instrumentation
285
+ appendFileSync(
286
+ COMMIT_LOG,
287
+ `${_t0.toFixed(1)} SLOW_YOGA ${layoutMs.toFixed(1)}ms visited=${c.visited} measured=${c.measured} hits=${c.cacheHits} live=${c.live}\n`,
288
+ )
289
+ }
290
+ }
291
+
292
+ if (process.env.NODE_ENV === 'test') {
293
+ if (rootNode.childNodes.length === 0 && rootNode.hasRenderedContent) {
294
+ return
295
+ }
296
+ if (rootNode.childNodes.length > 0) {
297
+ rootNode.hasRenderedContent = true
298
+ }
299
+ rootNode.onImmediateRender?.()
300
+ return
301
+ }
302
+
303
+ const _tr = COMMIT_LOG ? performance.now() : 0
304
+ rootNode.onRender?.()
305
+ if (COMMIT_LOG) {
306
+ const renderMs = performance.now() - _tr
307
+ if (renderMs > 10) {
308
+ // eslint-disable-next-line custom-rules/no-sync-fs -- debug instrumentation
309
+ appendFileSync(
310
+ COMMIT_LOG,
311
+ `${_tr.toFixed(1)} SLOW_PAINT ${renderMs.toFixed(1)}ms\n`,
312
+ )
313
+ }
314
+ }
315
+ },
316
+ getChildHostContext(
317
+ parentHostContext: HostContext,
318
+ type: ElementNames,
319
+ ): HostContext {
320
+ const previousIsInsideText = parentHostContext.isInsideText
321
+ const isInsideText =
322
+ type === 'ink-text' || type === 'ink-virtual-text' || type === 'ink-link'
323
+
324
+ if (previousIsInsideText === isInsideText) {
325
+ return parentHostContext
326
+ }
327
+
328
+ return { isInsideText }
329
+ },
330
+ shouldSetTextContent: () => false,
331
+ createInstance(
332
+ originalType: ElementNames,
333
+ newProps: Props,
334
+ _root: DOMElement,
335
+ hostContext: HostContext,
336
+ internalHandle?: unknown,
337
+ ): DOMElement {
338
+ if (hostContext.isInsideText && originalType === 'ink-box') {
339
+ throw new Error(`<Box> can't be nested inside <Text> component`)
340
+ }
341
+
342
+ const type =
343
+ originalType === 'ink-text' && hostContext.isInsideText
344
+ ? 'ink-virtual-text'
345
+ : originalType
346
+
347
+ const node = createNode(type)
348
+ if (COMMIT_LOG) _createCount++
349
+
350
+ for (const [key, value] of Object.entries(newProps)) {
351
+ applyProp(node, key, value)
352
+ }
353
+
354
+ if (isDebugRepaintsEnabled()) {
355
+ node.debugOwnerChain = getOwnerChain(internalHandle)
356
+ }
357
+
358
+ return node
359
+ },
360
+ createTextInstance(
361
+ text: string,
362
+ _root: DOMElement,
363
+ hostContext: HostContext,
364
+ ): TextNode {
365
+ if (!hostContext.isInsideText) {
366
+ throw new Error(
367
+ `Text string "${text}" must be rendered inside <Text> component`,
368
+ )
369
+ }
370
+
371
+ return createTextNode(text)
372
+ },
373
+ resetTextContent() {},
374
+ hideTextInstance(node) {
375
+ setTextNodeValue(node, '')
376
+ },
377
+ unhideTextInstance(node, text) {
378
+ setTextNodeValue(node, text)
379
+ },
380
+ getPublicInstance: (instance): DOMElement => instance as DOMElement,
381
+ hideInstance(node) {
382
+ node.isHidden = true
383
+ node.yogaNode?.setDisplay(LayoutDisplay.None)
384
+ markDirty(node)
385
+ },
386
+ unhideInstance(node) {
387
+ node.isHidden = false
388
+ node.yogaNode?.setDisplay(LayoutDisplay.Flex)
389
+ markDirty(node)
390
+ },
391
+ appendInitialChild: appendChildNode,
392
+ appendChild: appendChildNode,
393
+ insertBefore: insertBeforeNode,
394
+ finalizeInitialChildren(
395
+ _node: DOMElement,
396
+ _type: ElementNames,
397
+ props: Props,
398
+ ): boolean {
399
+ return props['autoFocus'] === true
400
+ },
401
+ commitMount(node: DOMElement): void {
402
+ getFocusManager(node).handleAutoFocus(node)
403
+ },
404
+ isPrimaryRenderer: true,
405
+ supportsMutation: true,
406
+ supportsPersistence: false,
407
+ supportsHydration: false,
408
+ scheduleTimeout: setTimeout,
409
+ cancelTimeout: clearTimeout,
410
+ noTimeout: -1,
411
+ getCurrentUpdatePriority: () => dispatcher.currentUpdatePriority,
412
+ beforeActiveInstanceBlur() {},
413
+ afterActiveInstanceBlur() {},
414
+ detachDeletedInstance() {},
415
+ getInstanceFromNode: () => null,
416
+ prepareScopeUpdate() {},
417
+ getInstanceFromScope: () => null,
418
+ appendChildToContainer: appendChildNode,
419
+ insertInContainerBefore: insertBeforeNode,
420
+ removeChildFromContainer(node: DOMElement, removeNode: DOMElement): void {
421
+ removeChildNode(node, removeNode)
422
+ cleanupYogaNode(removeNode)
423
+ getFocusManager(node).handleNodeRemoved(removeNode, node)
424
+ },
425
+ // React 19 commitUpdate receives old and new props directly instead of an updatePayload
426
+ commitUpdate(
427
+ node: DOMElement,
428
+ _type: ElementNames,
429
+ oldProps: Props,
430
+ newProps: Props,
431
+ ): void {
432
+ const props = diff(oldProps, newProps)
433
+ const style = diff(oldProps['style'] as Styles, newProps['style'] as Styles)
434
+
435
+ if (props) {
436
+ for (const [key, value] of Object.entries(props)) {
437
+ if (key === 'style') {
438
+ setStyle(node, value as Styles)
439
+ continue
440
+ }
441
+
442
+ if (key === 'textStyles') {
443
+ setTextStyles(node, value as TextStyles)
444
+ continue
445
+ }
446
+
447
+ if (EVENT_HANDLER_PROPS.has(key)) {
448
+ setEventHandler(node, key, value)
449
+ continue
450
+ }
451
+
452
+ setAttribute(node, key, value as DOMNodeAttribute)
453
+ }
454
+ }
455
+
456
+ if (style && node.yogaNode) {
457
+ applyStyles(node.yogaNode, style, newProps['style'] as Styles)
458
+ }
459
+ },
460
+ commitTextUpdate(node: TextNode, _oldText: string, newText: string): void {
461
+ setTextNodeValue(node, newText)
462
+ },
463
+ removeChild(node, removeNode) {
464
+ removeChildNode(node, removeNode)
465
+ cleanupYogaNode(removeNode)
466
+ if (removeNode.nodeName !== '#text') {
467
+ const root = getRootNode(node)
468
+ root.focusManager!.handleNodeRemoved(removeNode, root)
469
+ }
470
+ },
471
+ // React 19 required methods
472
+ maySuspendCommit(): boolean {
473
+ return false
474
+ },
475
+ preloadInstance(): boolean {
476
+ return true
477
+ },
478
+ startSuspendingCommit(): void {},
479
+ suspendInstance(): void {},
480
+ waitForCommitToBeReady(): null {
481
+ return null
482
+ },
483
+ NotPendingTransition: null,
484
+ HostTransitionContext: {
485
+ $$typeof: Symbol.for('react.context'),
486
+ _currentValue: null,
487
+ } as never,
488
+ setCurrentUpdatePriority(newPriority: number): void {
489
+ dispatcher.currentUpdatePriority = newPriority
490
+ },
491
+ resolveUpdatePriority(): number {
492
+ return dispatcher.resolveEventPriority()
493
+ },
494
+ resetFormInstance(): void {},
495
+ requestPostPaintCallback(): void {},
496
+ shouldAttemptEagerTransition(): boolean {
497
+ return false
498
+ },
499
+ trackSchedulerEvent(): void {},
500
+ resolveEventType(): string | null {
501
+ return dispatcher.currentEvent?.type ?? null
502
+ },
503
+ resolveEventTimeStamp(): number {
504
+ return dispatcher.currentEvent?.timeStamp ?? -1.1
505
+ },
506
+ })
507
+
508
+ // Wire the reconciler's discreteUpdates into the dispatcher.
509
+ // This breaks the import cycle: dispatcher.ts doesn't import reconciler.ts.
510
+ dispatcher.discreteUpdates = reconciler.discreteUpdates.bind(reconciler)
511
+
512
+ export default reconciler