Agent guide¶
Consoleri is an Electron desktop app for managing remote hosts: SSH, local shells, RDP, and VNC. The main UI is a mosaic workspace where sessions open as resizable panes, alongside a host browser, an interactive map view, a reports subsystem, and a HashiCorp Vault integration. This document is written for AI agents and contributors working inside the repo.
Monorepo layout¶
consoleri/
├── apps/desktop/ @consoleri/desktop — Electron + React
├── packages/core/ @consoleri/core — pure functions + Vitest
├── scripts/ dev, pnpm wrapper, postinstall, rebuild-native, release
├── docs/
└── pnpm-workspace.yaml
pnpm is bundled in root devDependencies (pnpm@10.34.5). A global install
is not required — use npm run * or node scripts/pnpm.mjs for everything.
Commands¶
Command |
What it does |
|---|---|
|
|
|
full |
|
production build for |
|
builds Windows distributable |
|
linting and TypeScript checks |
|
Vitest for both |
|
re-run |
|
manual fallback if postinstall was skipped |
|
bump versions + CHANGELOG + commit |
|
bump version, changelog, commit+tag, push (starts Release CI) |
npm run dev always runs a full pre-build first so main/preload/renderer are
in sync before the dev server starts.
Hot-reload only (skip pre-build):
node scripts/pnpm.mjs --filter @consoleri/desktop dev:watch
Architecture overview¶
flowchart TB
subgraph renderer [Renderer]
AppShell --> HostBrowser
AppShell --> MosaicWorkspace
AppShell --> HostMapView
AppShell --> ReportsManager
SessionWindow
LogWindow
ReportWindow
end
subgraph mainProc [Main process]
registerIpc --> SessionManager
registerIpc --> HostRepository
registerIpc --> VaultAuth
SessionManager --> SessionFactory
SessionFactory --> SshSession
SessionFactory --> PtySession
SessionFactory --> VncProxy
SessionFactory --> RdpProxy
database[(SQLite)]
end
renderer -->|"IPC / Zod schemas"| mainProc
mainProc --> core["@consoleri/core"]
renderer --> core
Main process¶
Sessions
Module |
Role |
|---|---|
|
async |
|
creates transport by protocol |
|
takes resolved profile + credentials, no repository dependency |
|
local PTY sessions |
|
VNC and RDP proxies |
|
per-session ring buffer |
|
resolves credentials from vault, local storage, or key files |
|
SSH connection helpers including jump host logic |
IPC
Handlers are split by domain in apps/desktop/src/main/ipc/ and registered by
register.ts:
registerHostIpc— hosts, profiles, workspace, import/exportregisterVaultIpc— vault auth and settingsregisterSessionIpc— session lifecycle, terminal I/OregisterKeysIpc— SSH key managementregisterUxProfilesIpc— UX profile CRUDregisterPreferencesIpc— app preferencesregisterReportIpc— connectivity and inventory reports
IPC contracts are defined as Zod schemas in
apps/desktop/src/shared/ipcSchemas.ts.
Persistence
SQLite via node:sqlite in main/db/database.ts. Repositories:
HostRepository, ProfileRepository, WorkspaceRepository,
ReportRepository, UxProfileRepository.
Windows
The main window plus three detached windows — LogWindow, SessionWindow,
ReportWindow — each with its own preload and renderer HTML entry.
Renderer¶
Layout
AppShell is the root layout: NavRail on the left, ResizableSidebar
(drag-resizable panel), and the main content area. Sidebar width is persisted in
the active UX profile’s chrome.sidebarWidth field — not localStorage.
Hosts
HostBrowser (scrollable via min-h-0 flex-1 overflow-y-auto),
HostListItem with inline Edit/Delete actions (visible on hover and selected),
HostDetailPanel, HostForm, ProfileForm, PickProfileDialog,
HostProfilesSection.
Workspace
MosaicWorkspace renders the session mosaic. Workspace state is loaded exactly
once in App.tsx. Panes are inserted via insertPaneIntoLayout from core.
sessionMosaicOps.ts contains the mosaic-aware session state helpers. Each
pane toolbar has a Log button that opens a LogWindow. Failed sessions are
never added to the mosaic. Pane maximize is a CSS overlay (does not mutate
splitPercentages); restore returns to the prior layout. Configurable hotkeys
live under Settings → Hotkeys (default: Mod+Shift+M to toggle maximize).
Other main views
HostMapView / HostMapCanvas — interactive graph map of hosts.
ReportsManager — connectivity and inventory reports.
VaultSettingsPanel — vault connection and auth. KeyManager — SSH key
management. UxProfileManager — UX profile management.
UI kit
components/ui/ — Button, InlineConfirmButton,
ConfirmDeleteButton, EditDeleteActions, Modal, DialogHeader,
DialogFooter, LabeledSelect, CheckboxPickList.
Multi-window renderers
renderer/log-window/, renderer/session-window/,
renderer/report-window/ — standalone renderer entries for detached windows.
Key files¶
packages/core/src/
apps/desktop/
electron.vite.config.ts
src/main/
sessions/{SessionManager,SessionFactory,SshSession,PtySession,ConnectionLog}.ts
sessions/rdp/RdpProxy.ts
ipc/register.ts
ipc/register{Host,Vault,Session,Keys,UxProfiles,Preferences,Report}Ipc.ts
db/database.ts
services/CredentialResolver.ts
windows/{LogWindow,SessionWindow,ReportWindow}.ts
src/renderer/src/
App.tsx
components/{hosts,workspace,map,reports,vault,layout,ui}/
session/mosaic/sessionMosaicOps.ts
src/shared/ipcSchemas.ts
scripts/{dev,pnpm,postinstall,rebuild-native}.mjs
Gotchas¶
``@consoleri/core`` must be bundled in main, not externalized. In
electron.vite.config.ts:externalizeDepsPlugin({ exclude: ['@consoleri/core'] })on the main buildalias
@consoleri/core→packages/core/srcfor both main and rendererWithout this you get a runtime
ERR_MODULE_NOT_FOUNDfor./types(no.jsextension in ESM imports).
MosaicNode type mismatch — react-mosaic and core use incompatible generic types. Cast input as
CoreMosaicNodewhen calling core helpers; cast the result back toMosaicNodefor the renderer.Terminal connect status — after calling
attachTransport, always callupdateStatus(id, 'connected'). Skipping it leaves the pane UI stuck on “Connecting…”.pnpm not on PATH — always use
npm run *ornode scripts/pnpm.mjsrather than callingpnpmdirectly.Electron binary + native deps —
postinstall.mjsdownloads the Electron binary if absent, then runselectron-rebuild --only node-ptyso PTY matches the Electron ABI. Optionalcpu-features(viassh2) is skipped — it often fails gyp and is not required. If install scripts were skipped with--ignore-scripts, runnpm run install:electronandnpm run rebuild-nativemanually.Native rollup externals —
node-pty,ssh2,cpu-features, andnode:sqliteare declared external in the main build’s rollup config and must not be bundled.Failed sessions —
openSessionreturnsnullon error; only non-null sessions are inserted into the mosaic.
Agent constraints¶
.cursor/plans/— treat as read-only; do not modify plan filesDo not commit unless explicitly asked by the user
Do not revert to npm workspaces or restore
package-lock.json
Known gaps¶
No E2E tests. Desktop has unit tests split across
vitest.config.ts(renderer) andvitest.main.config.ts(main).Connecting to a host without a compatible profile silently picks the first available profile (
connectHost.ts). A clearer in-UI error or profile picker dialog would improve this flow.