Converts gadget-tasks from a duplicated codebase with direct MongoDB access
to a headless IDE client that uses gadget-code's REST API and Socket.IO
protocol to submit and process task prompts through the existing pipeline.
Deleted (no longer needed):
- gadget-tasks/src/models/ (5 Mongoose models — duplicated from gadget-code)
- gadget-tasks/data/prompts/ (11 prompt templates — duplicated from gadget-code)
- gadget-tasks/src/services/executor.ts (629-line AWL loop — duplicated from gadget-drone)
- gadget-tasks/src/services/ai.ts (direct AI API calls — drones do this now)
- gadget-tasks/src/services/workspace.ts (workspace management — drones do this now)
Added:
- gadget-tasks/src/services/platform.ts — REST API + Socket.IO headless IDE client
with session lock, workspace mode, prompt submission, work order tracking
Rewritten:
- gadget-tasks/src/gadget-tasks.ts — new startup: user login → auth → drone
selection → Socket.IO connect → schedule tasks (no MongoDB)
- gadget-tasks/src/services/scheduler.ts — delegates to PlatformService.executeTask()
- gadget-tasks/src/config/env.ts — platform.baseUrl config, no mongodb/google
gadget-code changes:
- Added PATCH /api/v1/projects/:projectId/tasks/:taskId/lastRun route
- Added ProjectService.updateTaskLastRun() for atomic task field update
Config changes:
- GadgetTasksConfig: replaced mongodb with platform.baseUrl, removed google.cse
- Dependencies: removed mongoose, @gadget/ai, @gadget/ai-toolbox, dayjs,
simple-git, nanoid; added socket.io-client, @inquirer/prompts
- IChatSession/IChatTurn interfaces: add optional numCtx field
- Mongoose schemas: add numCtx field to ChatSession and ChatTurn
- API controller: validate numCtx (>=16384, multiple of 8192)
- ChatSessionService: persist numCtx on session, pass through to turn
- SessionPanel: add range slider for Context Window (hidden for OpenAI)
- Drone buildDroneModelConfig: prefer turn.numCtx over model defaults
Complete Phase 1 of subprocess management in gadget-drone:
- SubProcessService with graceful shutdown (SIGINT→SIGKILL), halt, getLog
- SubprocessTool with create/list/kill/killAll/halt/log commands
- Registered in agent toolbox for build/test/ship/develop modes
- Fixed missing {{process_management_block}} replacement in chat-session.ts
- 34 unit tests across service and tool
- Comprehensive documentation in docs/subprocess.md
Documents:
- Complete session history and what was accomplished
- ACE → CodeMirror migration rationale and steps
- Flex layout height constraint fix pattern
- Key technical learnings (CJS/ESM interop, flex layouts)
- Remaining steps organized by priority (high/medium/low)
- Continuation prompt template for next session
- MVP success criteria (all ✅ complete)
This serves as the handoff document for the next developer
or AI agent continuing work on User Mode.
Documents the complete ACE → CodeMirror migration, including:
- Root cause analysis of react-ace CJS/ESM incompatibility with Vite
- Migration steps and rationale for @uiw/react-codemirror
- Flex layout height constraint fix and the underlying pattern
- Key technical learnings about CJS/ESM interop and flex layouts
- Remaining steps and continuation prompt for next session
This serves as the authoritative reference for why we use CodeMirror
and how to properly constrain third-party components in flex layouts.
The editor was overflowing its container because @uiw/react-codemirror
renders a wrapper div that doesn't inherit flex constraints by default.
Fixed by adding CSS rules that:
1. Set overflow:hidden on .cm-editor-container
2. Target the wrapper div (> div) with flex:1, min-height:0, overflow:hidden
3. Set .cm-editor and .cm-scroller to overflow appropriately
This ensures the flex height constraint propagates through every level
of the CodeMirror DOM tree, and only .cm-scroller scrolls.
Layout chain:
.cm-editor-container (flex-1, min-h-0)
└─ wrapper div (flex:1, min-h-0, overflow:hidden)
└─ .cm-editor (flex:1, min-h-0, overflow:hidden)
└─ .cm-scroller (min-h-0, overflow:auto) ← only this scrolls
react-ace v14 is CommonJS-only with no ESM entry point, making it
fundamentally incompatible with Vite's ESM-first dev server. Every
CJS interop workaround failed. Switched to @uiw/react-codemirror v4.25
which ships proper dual ESM+CJS and works with Vite out of the box.
Changes:
- Remove ace-builds and react-ace dependencies
- Add @uiw/react-codemirror + 16 @codemirror/lang-* packages
- Add @uiw/codemirror-theme-tomorrow-night-blue (closest to ACE's 'tomorrow')
- Add @replit/codemirror-lang-csharp for C# support
- Rewrite EditorPanel.tsx: delete 108 lines of ACE boilerplate
(?url imports, setModuleUrl, CJS interop hack), replace with
~30 lines of clean CodeMirror language extension setup
- Delete vite.d.ts (only needed for ACE ?url import types)
- Remove optimizeDeps.include from vite.config.ts (not needed for CM)
- Add CodeMirror flex layout CSS to index.css
Supported languages: JavaScript/JSX, TypeScript/TSX, Python, JSON,
HTML, CSS, Less, YAML, Markdown, SQL, Java, Go, Rust, C/C++, C#,
PHP, XML. Unsupported types fall back to plain text.
Verified: tsc clean, vite build passes, heartbeat worker intact.
react-ace v14 ships CommonJS only ('main': 'lib/index.js'). Vite's dev
server pre-bundling wraps CJS modules as namespace objects where the
default export is nested under .default. This caused 'Element type is
invalid: got object' because import Ace from 'react-ace' resolved to
the module namespace instead of the React component.
Fix: import * as ReactAceModule and extract default with fallback:
const Ace = ReactAceModule.default || ReactAceModule
Same treatment for ace-builds import. Production build (Rolldown) was
unaffected due to different CJS interop handling.
- Added react-ace and ace-builds to optimizeDeps.include
- This forces Vite to properly bundle the CommonJS react-ace module
- Resolves 'Element type is invalid' error when opening files
The react-ace package uses CommonJS exports, and Vite needs to
pre-bundle it to properly handle the default export in ESM context.
- Fixed Ace import (default import, not named)
- Moved EditorPanel from FilesPanel to ChatSessionView
- Editor now replaces chat view when file is selected (per UI design guide)
- FILES panel now contains only the file tree
- Added editorFilePath state to track open file
- File selection in tree opens editor in content area
- Close button returns to chat view
This matches the UI design guide specification where the File Editor
replaces the Chat View in the content area when a file is selected.
Root Cause: CSS flex items default to min-height: auto, which prevents
flex-1 elements from shrinking below their content size. This caused
the FilesPanel to grow beyond its allocated space when the file tree
had many entries, pushing content off-screen.
Changes:
- FilesPanel.tsx: Added min-h-0 to root div to override min-height: auto
This allows flex-1 to actually constrain height and enable scrolling
- FileTree.tsx: Removed redundant overflow-auto and h-full from root div
The parent (FilesPanel flex-1 overflow-auto) already handles scrolling.
Nested scroll containers create height resolution issues.
The sidebar layout is now a clean single-scroll-container hierarchy:
Sidebar (flex flex-col, no overflow)
↳ SESSION (shrink-0, natural height)
↳ PROJECT (shrink-0, natural height)
↳ FilesPanel (flex-1 min-h-0) — constrained to available space
↳ Header (natural height)
↳ Scroll area (flex-1 overflow-auto) — THE scroll container
↳ FileTree (p-2 only) — no overflow, no h-full
↳ Footer (natural height)
- SESSION and PROJECT panels now have shrink-0 to prevent them from
growing unbounded and pushing FILES panel off-screen
- FILES panel with flex-1 now properly fills remaining vertical space
- File tree scrolls in-place while SESSION/PROJECT stay fixed
- FileTree had flex-1 inside an overflow container which didn't work
- Changed to h-full to properly fill the parent container height
- Scrolling now works correctly in the file tree area
- The sidebar container had overflow-y-auto which caused the entire sidebar
to scroll when FILES panel content grew
- FILES panel already has proper flex-1 and internal overflow-auto handling
- Now only the file tree scrolls in place while SESSION and PROJECT panels
remain fixed as expected
- Fixes UX issue where entire sidebar would scroll vertically
- Add flex-1 to FilesPanel root div
- Sidebar is flex flex-col, FILES panel now grows to fill space
- SESSION and PROJECT panels remain natural height
- FILES panel expands into all remaining vertical space
This eliminates the gap below the FILES panel footer by making
the panel itself grow rather than just making the tree bigger.
- Remove max-h-80 constraint from FileTree
- FileTree uses flex-1 to expand and fill available space
- Panel now properly fills sidebar from top to bottom
- File tree scrolls internally when content overflows
The FILES panel header, file tree, and footer now form a proper
flex column that fills all remaining vertical space in the sidebar.
- Change FilesPanel overflow-hidden to overflow-auto for scrolling
- Add max-h-80 to FileTree to limit height while allowing scroll
- Add select-none to FileTreeNode to prevent text selection
- Cursor-pointer already present for clickable indication
Now the file tree scrolls independently within the FILES panel,
and text cannot be selected during rapid clicking.
CRITICAL FIX: Remove recursion from listDirectoryForTree function.
The backend was recursively fetching ALL subdirectories and returning
them as a flat list, which completely broke the lazy-loading model.
Changes:
- Remove recursive call in listDirectoryForTree
- Backend now returns ONLY immediate children
- Frontend handles lazy loading by requesting children on expand
- This matches the intended architecture where frontend controls tree
This fixes the issue where directory contents were duplicated and
the tree structure was corrupted when expanding/collapsing.