Commit Graph

66 Commits

Author SHA1 Message Date
Rob Colbert
dc54ea3dec fix: handle CJS default export interop for react-ace v14 in Vite dev server
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.
2026-05-12 21:49:55 -04:00
Rob Colbert
37907ef098 fix 2026-05-12 21:40:43 -04:00
Rob Colbert
c14c3a235a fix: ACE editor integration crash — React 19 compat, Vite ?url pattern, Error Boundary
Root causes:
- react-ace v12 doesn't support React 19 (project uses ^19.2.5)
- Dynamic import(`ace-builds/src-noconflict/mode-${language}`) broken with Vite
  (template-literal dynamic imports can't be statically analyzed)
- No React Error Boundaries — ACE render crash whitescreens entire app
- ace-builds/react-ace duplicated in backend package.json

Fixes:
1. Upgrade react-ace ^12.0.0 → ^14.0.1 (React 19 support)
2. Upgrade ace-builds ^1.36.0 → ^1.43.6
3. Remove ACE deps from backend package.json (not used by Express)
4. Replace broken dynamic imports with Vite ?url + ace.config.setModuleUrl()
   pattern (canonical Vite solution per ace#4597)
5. Add ErrorBoundary component wrapping EditorPanel
6. Add vite.d.ts type declarations for ?url/?raw/?worker imports
7. Fix worker-typescript import (doesn't exist — TS uses worker-javascript)
8. Register 24 language modes, 4 workers, 1 theme, 2 extensions

Verified: TypeScript clean, production build passes, heartbeat worker intact.
2026-05-12 21:36:22 -04:00
Rob Colbert
fb8f15aeec Fix react-ace import: add optimizeDeps to Vite config
- 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.
2026-05-12 20:02:13 -04:00
Rob Colbert
fb8b73e290 Fix editor integration: move EditorPanel to ChatSessionView
- 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.
2026-05-12 19:45:50 -04:00
Rob Colbert
1e13f95808 Phase 2: ACE Editor integration and file operations
- Added react-ace and ace-builds dependencies
- Created EditorPanel component with ACE editor integration
- Implemented file read/write socket protocol
- Added backend handlers for fileReadRequest and fileWriteRequest
- Implemented file loading from tree click
- Implemented file saving with Ctrl+S shortcut
- Added dirty state tracking and unsaved changes indicator
- Enforced workspace mode (read-only in Agent mode)
- Added security: path traversal prevention, binary file detection, file size limits
- Updated FilesPanel with split view (tree + editor)

Enables Users to edit files for the first time in Gadget Code.
2026-05-12 19:32:58 -04:00
Rob Colbert
ec7b83d610 Fix: Proper flexbox scrolling for FILES panel sidebar
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)
2026-05-12 17:40:11 -04:00
Rob Colbert
6dba16a8c5 Fix: Add shrink-0 to SESSION and PROJECT panels for proper flex layout
- 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
2026-05-12 17:26:20 -04:00
Rob Colbert
b0b94c2b7d Fix: FileTree scrolling - use h-full instead of flex-1
- 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
2026-05-12 17:22:29 -04:00
Rob Colbert
869dd919c8 Fix: Remove overflow-y-auto from sidebar to prevent entire sidebar from scrolling
- 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
2026-05-12 17:19:15 -04:00
Rob Colbert
a2a74c6da3 fix: FILES panel should expand to fill sidebar height
- 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.
2026-05-12 16:58:35 -04:00
Rob Colbert
91d02e1468 fix: FILES panel should fill entire sidebar height
- 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.
2026-05-12 16:45:26 -04:00
Rob Colbert
a7c20d6105 fix: FileTree scrolling and text selection issues
- 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.
2026-05-12 16:38:27 -04:00
Rob Colbert
71f213d8d1 fix: FileTree duplication and corruption on expand
- Replace recursive buildTree with buildVisibleNodes approach
- Build flat list of visible nodes based on expanded state
- Use processNode helper to traverse tree structure correctly
- Each node appears exactly once in the rendered output
- Eliminates duplication when expanding directories
2026-05-12 16:11:20 -04:00
Rob Colbert
3062420e99 fix: FileTree expand/collapse not rendering children
- Change buildTree from .map() to for-loop to properly render children
- Append expanded directory children to nodes array immediately
- Fix TypeScript error by using ReactElement instead of JSX.Element
- Children now render correctly when directories are expanded
2026-05-12 16:03:18 -04:00
Rob Colbert
0a510de487 docs: Add plan for Project-Specific Agent Instructions feature
- Create comprehensive plan document for agent instructions text area
- Define requirements, acceptance criteria, and technical implementation
- Include UI/UX mockups and testing strategy
- Plan discovered during FILES panel implementation
- Addresses need for project-specific acceptance criteria
2026-05-12 15:39:38 -04:00
Rob Colbert
c05c7f5a61 feat: Implement FILES panel foundation with lazy-loading file tree
- Add fileTreeRequest/fileTreeResponse socket messages
- Implement gadget-drone handler with security validation
- Add web backend message forwarding
- Create FileTree and FileTreeNode React components
- Update FilesPanel to contain file tree browser
- Add requestFileTree method to frontend socket client
- Exclude node_modules, .git, and hidden files by default
- Implement lazy loading with directory caching
- Add loading and error states per node
- Support keyboard navigation (Enter, Space)

Phase 1 of FILES panel implementation complete.
2026-05-12 15:12:18 -04:00
Rob Colbert
4780b79148 feat: abort controller for work order processing
Add end-to-end abort support: AbortSignal in @gadget/ai providers,
abortWorkOrder socket message, drone AbortController handling,
Cancel button and double-Esc in frontend, and aborted turn status display.
2026-05-12 12:25:17 -04:00
Rob Colbert
c635209201 sidebar: navigate to project in Project Manager using slug
The Home icon in the PROJECT panel now navigates to /projects/{slug}
instead of /projects/{id}. This opens Project Manager with the
project already selected and displayed.
2026-05-12 11:14:53 -04:00
Rob Colbert
24975b58c4 Define missing socket event types and enforce typed events in frontend build
Adds type definitions + forwarding for status, reconnect_attempt, reconnect_failed, reconnect events.
Frontend build now runs tsc --noEmit before vite build so undefined socket events cause failures.
Fixes pre-existing type errors exposed by strict mode in the frontend.
2026-05-12 10:42:31 -04:00
Rob Colbert
896aff1b02 Fix User Settings persona display issue
- Switch frontend sign-in to /api/v1/auth/sign-in endpoint (includes persona)
- Add updateUser() to App context for proper state management
- Fix Settings.tsx save flow to use updateUser() instead of broken localStorage merge
- Remove unused web AuthController (gadget-code/src/controllers/auth.ts)
- Fix UserApiControllerV1 to return flat user object instead of double-wrapped
- Remove SessionType enum and references (dead code)
- Add proper server sign-out call before clearing local state

Resolves issue where User Settings view didn't display persona text even though it existed in the database.
2026-05-12 01:15:00 -04:00
Rob Colbert
b3c9579890 style and display fixes 2026-05-12 01:02:09 -04:00
Rob Colbert
dd47212471 fix: crush whitespace in subagent markdown output using .subagent-compact.gadget-markdown overrides 2026-05-11 21:28:02 -04:00
Rob Colbert
d118497d83 CSS and style fixes for subagent display 2026-05-11 21:09:17 -04:00
Rob Colbert
26e568612a ChatSession reconnect logic 2026-05-11 20:27:24 -04:00
Rob Colbert
01c84ba5a0 crash fix 2026-05-11 19:15:02 -04:00
Rob Colbert
c5add0fc7d subagent processing updates and fixes 2026-05-11 19:07:48 -04:00
Rob Colbert
9418d95e35 fix: resolve build errors in session-stability branch
1. Vite config: make HTTPS conditional on SSL cert/key files existing
   (pre-existing issue, broke builds when certs not present)
2. Drone reconnect handler: use socket.io Manager-level 'reconnect'
   event (this.socket.io.on) instead of Socket-level event, and add
   explicit type annotation for attemptNumber parameter
2026-05-11 17:46:09 -04:00
Rob Colbert
009863cf2b fix: resolve drone heartbeat timeouts and JWT expiration bugs
This commit addresses two interrelated issues causing drones to
de-register and users to be forcibly signed out:

## Heartbeat Timeout Fixes

1. Move heartbeat interval to a Web Worker (not subject to browser
   tab throttling). Chrome throttles setInterval in background tabs
   to ~1/min, which causes the 19s heartbeat to miss the drone's
   timeout timer. The Web Worker fires reliably regardless of tab
   visibility.

2. Add visibilitychange handler: when the tab becomes visible again,
   send an immediate heartbeat to reset the drone's timer after any
   throttling that may have occurred.

3. Fix onReleaseSessionLock to clear the heartbeat timer. Previously,
   releasing the lock left the 60s timer running, causing a spurious
   timeout and status emit after the lock was already released.

4. Increase drone heartbeat timeout from 60s to 120s. With the Web
   Worker fix, heartbeats should be reliable, but doubling the timeout
   provides a generous safety margin.

5. Add socket disconnect/reconnect handlers on the drone side. On
   disconnect, clear the heartbeat timer. On reconnect, re-emit drone
   status so the platform knows the drone is alive.

6. Configure Socket.IO pingInterval/pingTimeout explicitly (25s/60s)
   instead of relying on defaults.

## JWT Expiration Fixes

1. Increase WebToken DB record expiration from 1 hour to 7 days. The
   1-hour expiration was the real session lifetime gate (the JWT crypto
   exp was already 24h), and it was far too aggressive for a dev tool.

2. Fix web /auth/renew-token endpoint to use req.user from the session
   cookie instead of verifyJsonWebToken(req.body.token). This eliminates
   the catch-22 where an expired token cannot be used to request its
   own renewal.

3. Fix token refresh response parsing. The API v1 renew-token endpoint
   returns { success: true, token } at the top level, but the frontend
   was looking for json.data?.token, causing every refresh to fail.

4. Add proactive token refresh: check the JWT exp claim before each
   request and refresh if expiring within 5 minutes. This avoids
   unnecessary 401 errors and the resulting socket disconnections.

5. Update socket JWT on token renewal via a callback registered in
   App.tsx. This ensures that future socket reconnections use the new
   token instead of the expired one.

## Files Modified

- gadget-code/frontend/src/workers/heartbeat.worker.ts (NEW)
- gadget-code/frontend/src/lib/socket.ts
- gadget-code/frontend/src/lib/api.ts
- gadget-code/frontend/src/App.tsx
- gadget-code/src/services/session.ts
- gadget-code/src/controllers/auth.ts
- gadget-code/src/services/socket.ts
- gadget-drone/src/gadget-drone.ts
2026-05-11 17:46:09 -04:00
Rob Colbert
d7f694fa8c a pile of small fixes 2026-05-11 07:08:18 -04:00
Rob Colbert
0df6661fc5 chat interface fixes and cleanup
The Chat View area of the view was growing in width (unbounded), and has
been fixed. From the agent:

> The root cause was a flexbox sizing rule: in ChatSessionView.tsx:768
the parent row flex-1 flex bg-bg-primary overflow-hidden relative has
two children — the content area and the sidebar. The content area (line
777) was flex-1 flex flex-col relative, which as a flex child defaults
to min-width: auto. This means its intrinsic content width (driven by
the wide <pre>) is used as a minimum, forcing the flex item to expand
the whole row beyond the viewport.
>
> Adding min-w-0 overrides min-width: auto to min-width: 0, letting the
flex item shrink below its content's natural width. Now the
overflow-x-auto on the markdown wrapper actually has somewhere to scroll
into.
2026-05-10 10:49:16 -04:00
Rob Colbert
73c5345879 Re-build Agentic Workflow Loop
The ridiculousness of trying to maintain the previous agent's work got
out of hand, so we had this one re-build it - and got a better result.
2026-05-09 21:04:18 -04:00
Rob Colbert
931359b674 stream response handling and correctness 2026-05-09 11:51:09 -04:00
Rob Colbert
d26624ab93 chat session auto-naming with IDE update 2026-05-09 09:58:47 -04:00
Rob Colbert
d7924a9d6f GadgetLogTransportSocket and the drone-to-IDE log 2026-05-09 07:16:50 -04:00
Rob Colbert
1019c675e8 add navigation to return to Project Manager 2026-05-08 16:54:41 -04:00
Rob Colbert
af200c8c3a chat session heartbeat and session unlock 2026-05-08 14:27:37 -04:00
Rob Colbert
8eff66dcec user settings 2026-05-08 14:08:49 -04:00
Rob Colbert
9e9bc5267a rework provider/model selection with save/cancel pattern; add editable session name with cog icon
Replace the broken provider/model <select> elements (which sent empty model
on provider change, rejected by backend) with a cog-icon-driven edit flow:
- Default view shows current provider/model as text labels with a cog icon
- Clicking cog enters edit mode with <select> elements + checkmark/cancel
- Save atomically sends both provider and model; Save disabled until both set
- Cancel restores original values; whole view grays out during edit

Apply the same cog metaphor to the session Name field — inline text edit
with save/cancel, Enter to confirm, Escape to cancel. No global gray-out.
2026-05-08 14:08:05 -04:00
Rob Colbert
2613acf00d password_hash => password (display string); formatting 2026-05-08 11:51:52 -04:00
Rob Colbert
49ef6de30c new sign-in form and presentation 2026-05-08 11:44:27 -04:00
Rob Colbert
11bdd5e3b0 make reasoning effort configurable; remove sign up concept
- Implemented reasoning effort setting in SESSION panel of Chat Sessio
View
- Removed all ability to "sign up" for an account
2026-05-08 11:40:30 -04:00
Rob Colbert
e0df415237 streaming response fixes (Ollama) 2026-05-08 02:02:17 -04:00
Rob Colbert
61ba0e4412 streaming responses (see ./docs/streaming-responses.md) 2026-05-07 21:36:01 -04:00
Rob Colbert
819654e20a provider, model, and mode selections
User can now update the AI Provider, selected model on that provider,
and chat session mode.
2026-05-05 20:49:13 -04:00
Rob Colbert
cb73d276a3 more progress along ChatTurn processing
The agent has been failing and failing and failing, so I:
1. Swapped models
2. Did some by-hand enhancements
3. Set this checkpoint for continuing
2026-05-05 14:34:52 -04:00
Rob Colbert
09ebacc711 agent's progress on ChatTurn 2026-05-05 13:18:15 -04:00
Rob Colbert
3a8f2e4f44 agent's progress on ChatTurn component 2026-05-05 13:18:06 -04:00
Rob Colbert
dca21cf762 status message display fix (agent) 2026-05-03 04:34:36 -04:00
Rob Colbert
bab0b1810f many fixes
- JWT refresh logic to prevent dead sessions
- drone status messages now arrive in IDE for display
- WorkspaceService.deployProject method added to clone into a repo or
create the directory (new project not yet in git)
2026-05-03 04:15:48 -04:00