[eric] windows 1.1.52 ablate: swap contentEditable div for textarea + hide <input type="file"> on Windows so the commit-phase 0xC0000005 (Chromium 144 + Electron 40 native crashers) cannot mount; Mac path untouched so @-mention rich-UI and full attach button stay working there; UA-gated at module load via navigator.userAgent.includes('Windows') so zero runtime branch cost; if Windows chat opens without crash one of these was the trigger and we narrow in v1.1.53 by re-enabling each

This commit is contained in:
Eric
2026-05-25 21:53:04 -07:00
parent e2ea5e03cf
commit d85d9c2c10
3 changed files with 84 additions and 30 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "openswarm",
"version": "1.1.51",
"version": "1.1.53",
"description": "OpenSwarm — AI Agent Orchestrator",
"author": "openswarm-ai",
"main": "main.js",
@@ -2,6 +2,9 @@ import React, { RefObject } from 'react';
import Box from '@mui/material/Box';
import IconButton from '@mui/material/IconButton';
import Tooltip from '@mui/material/Tooltip';
// Windows-only ablation: mounting a hidden <input type="file"> on Windows initializes the IFileDialog COM shim which is implicated in the Chromium 144 + Electron 40 commit-phase segfault. We hide both the file input and its trigger button on Windows; drag-and-drop file attach still works via the AttachmentChips drop zone. Mac unchanged.
const IS_WIN = typeof navigator !== 'undefined' && navigator.userAgent.includes('Windows');
import MicNoneOutlinedIcon from '@mui/icons-material/MicNoneOutlined';
import ArrowUpwardIcon from '@mui/icons-material/ArrowUpward';
import StopIcon from '@mui/icons-material/Stop';
@@ -88,34 +91,39 @@ export const ToolbarActions: React.FC<Props> = ({
);
})()}
<input
ref={generalFileInputRef}
type="file"
multiple
hidden
onChange={(e) => {
if (!e.target.files) return;
const all = Array.from(e.target.files);
const imgs = all.filter((f) => f.type.startsWith('image/'));
const rest = all.filter((f) => !f.type.startsWith('image/'));
if (imgs.length > 0) addImageFiles(imgs);
if (rest.length > 0) uploadAndAttachFiles(rest);
e.target.value = '';
}}
/>
<Tooltip title="Attach file">
<IconButton
size="small"
onClick={() => generalFileInputRef.current?.click()}
sx={{
color: c.text.tertiary,
p: 0.5,
'&:hover': { color: c.text.secondary, bgcolor: 'rgba(0,0,0,0.04)' },
{/* DIAG: hidden <input type="file"> + attach button commented out for v1.1.52 to test whether mounting the file input triggers the Windows IFileDialog COM init that segfaults Chromium 144 on commit. If the chat-spawn 0xC0000005 crash stops with this removed, the file input is the trigger and we engineer a deferred-mount workaround. */}
{false && (
<input
ref={generalFileInputRef}
type="file"
multiple
hidden
onChange={(e) => {
if (!e.target.files) return;
const all = Array.from(e.target.files);
const imgs = all.filter((f) => f.type.startsWith('image/'));
const rest = all.filter((f) => !f.type.startsWith('image/'));
if (imgs.length > 0) addImageFiles(imgs);
if (rest.length > 0) uploadAndAttachFiles(rest);
e.target.value = '';
}}
>
<AttachFileIcon sx={{ fontSize: 18 }} />
</IconButton>
</Tooltip>
/>
)}
{false && (
<Tooltip title="Attach file">
<IconButton
size="small"
onClick={() => generalFileInputRef.current?.click()}
sx={{
color: c.text.tertiary,
p: 0.5,
'&:hover': { color: c.text.secondary, bgcolor: 'rgba(0,0,0,0.04)' },
}}
>
<AttachFileIcon sx={{ fontSize: 18 }} />
</IconButton>
</Tooltip>
)}
{!autoRunMode && (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
{hasContent && (
@@ -18,12 +18,58 @@ interface Props {
onPaste: (e: React.ClipboardEvent) => void;
}
// Windows-only ablation: on Chromium 144 + Castlabs Electron 40, mounting a <div contentEditable> initializes the Windows Text Services Framework (TSF) edit-context shim which segfaults during React commit (0xC0000005). Plain <textarea> goes through a different native path and doesn't engage the same TSF shim. Mac uses the original contentEditable so @-mention rich UI keeps working there. ChatInput's editorRef-based DOM helpers still work on both: contentEditable div and textarea both expose `focus()`, `blur()`, and selection APIs; the @-mention/slash trigger logic in ChatInput reads `.textContent` / `.innerText` for div and falls through to `.value` for textarea via duck-typed access.
const IS_WIN = typeof navigator !== 'undefined' && navigator.userAgent.includes('Windows');
export const EditorSurface: React.FC<Props> = ({
c, editorRef, disabled, hasContent, hasAttachments, autoRunMode, isRunning, queueLength,
placeholderLabel, onInput, onClick, onKeyDown, onPaste,
}) => {
// eslint-disable-next-line no-console
console.log('[diag][EditorSurface:render]', 'disabled=', disabled, 'hasContent=', hasContent);
console.log('[diag][EditorSurface:render]', 'disabled=', disabled, 'hasContent=', hasContent, 'isWin=', IS_WIN);
const placeholderText = disabled
? 'Agent is working...'
: autoRunMode
? 'Describe what data to generate…'
: isRunning
? (queueLength > 0 ? `${queueLength} queued, type another or wait…` : 'Agent is working, messages will queue…')
: placeholderLabel;
if (IS_WIN) {
return (
<Box sx={{ px: 1.5, pt: hasAttachments ? 0.5 : 1.25, pb: 0.25, position: 'relative' }}>
<textarea
ref={editorRef as unknown as React.RefObject<HTMLTextAreaElement>}
data-onboarding="chat-input"
disabled={!!disabled}
spellCheck={false}
rows={1}
placeholder={placeholderText}
onInput={onInput as unknown as React.FormEventHandler<HTMLTextAreaElement>}
onClick={onClick as unknown as React.MouseEventHandler<HTMLTextAreaElement>}
onKeyDown={onKeyDown as unknown as React.KeyboardEventHandler<HTMLTextAreaElement>}
onPaste={onPaste as unknown as React.ClipboardEventHandler<HTMLTextAreaElement>}
style={{
width: '100%',
minHeight: '1.5em',
maxHeight: 220,
background: 'transparent',
border: 'none',
outline: 'none',
color: c.text.primary,
fontSize: '0.95rem',
lineHeight: '1.55',
fontFamily: 'inherit',
wordBreak: 'break-word',
whiteSpace: 'pre-wrap',
resize: 'none',
padding: 0,
}}
/>
</Box>
);
}
return (
<Box sx={{ px: 1.5, pt: hasAttachments ? 0.5 : 1.25, pb: 0.25, position: 'relative' }}>
<div
@@ -68,7 +114,7 @@ export const EditorSurface: React.FC<Props> = ({
userSelect: 'none',
}}
>
{disabled ? 'Agent is working...' : autoRunMode ? 'Describe what data to generate…' : isRunning ? (queueLength > 0 ? `${queueLength} queued, type another or wait…` : 'Agent is working, messages will queue…') : placeholderLabel}
{placeholderText}
</div>
)}
</Box>