-
Notifications
You must be signed in to change notification settings - Fork 0
Shared Domain Types and File URL Helpers
src/shared is the cross-process contract layer for Termsprawl. It holds the data shapes and IPC channel names that Electron main, preload, renderer, core, and the Server Edition all agree on. The directory rule is explicit: it must stay Electron-free because it is imported by both core and renderer, and channel strings must never be hardcoded outside ipc.ts.
| File | Responsibility |
|---|---|
src/shared/ipc.ts |
Single source of truth for IPC channel strings: workspace, pty, files, agent hooks, context links, managed accounts. |
src/shared/types.ts |
Shared domain types: node kinds, workspace shapes, context link pairs, agent accounts, app settings, cloud/chat/browser/file contracts. |
src/shared/file-url.ts |
termsprawl-file://local/... preview URL helpers. |
src/shared/agent-status.ts |
Agent status and notification types shared with the hook server. |
src/shared/agents/config.ts |
Agent registry/preset config for Claude, Codex, Gemini and Grok. |
src/shared/remote-project.ts |
Remote project-related shared types/helpers. |
src/shared/node-links.ts |
Shared link data shapes used by the link engine and UI. |
src/shared/agent-tools.ts |
Shared agent-tool protocol types. |
src/shared/update-status.ts |
Shared update-status types. |
src/shared/*.test.ts |
Contract tests for file URLs, settings contracts, and update status. |
The directory also contains the shared contract tests file-url.test.ts, settings-contracts.test.ts, and update-status.test.ts; file-url.test.ts explicitly guards the protocol round-trip and rejection behavior.
flowchart LR
EM[Electron main] --> SH[src/shared]
PR[Preload bridge] --> SH
RN[Renderer] --> SH
SRV[Server Edition] --> SH
CORE[core services] --> SH
SH --> IPC[ipc.ts<br/>channel strings]
SH --> T[types.ts<br/>domain contracts]
SH --> FU[file-url.ts<br/>preview URL protocol]
SH --> AS[agent-status.ts]
SH --> AC[agents/config.ts]
The key architectural point is that src/shared is not a service layer. It is the vocabulary boundary. Main/Server Edition perform the actual work; the renderer and core consume the same shapes; ipc.ts keeps channel names enumerable; types.ts keeps request/result/state contracts structural. Because this layer cannot import Electron, it also cannot depend on runtime host capabilities.
file-url.ts defines the custom protocol used to preview local images without exposing a file:// hole to the renderer:
- Protocol constant:
FILE_PROTOCOL = 'termsprawl-file'. - Shape:
termsprawl-file://local/<absolute/path>. - The dummy host
localis required so Chromium treats it as a standard URL. -
toFilePreviewUrl(absPath)splits the path on/, encodes each segment withencodeURIComponent, joins them, and prefixes${FILE_PROTOCOL}://local. -
fromFilePreviewUrl(url)parses the URL, requires thetermsprawl-file:protocol and hostnamelocal, decodes the pathname, and requires the result to start with/. - It returns
nullfor foreign schemes, non-localhosts, relative/empty payloads, invalid URLs, or any parse error.
flowchart LR
A[absolute filesystem path] --> B[toFilePreviewUrl]
B --> C[termsprawl-file://local/<encoded path>]
C --> D[fromFilePreviewUrl]
D --> E{protocol = termsprawl-file:?<br/>host = local?<br/>path starts with /?}
E -- yes --> F[absolute path]
E -- no --> G[null]
file-url.test.ts verifies the round trip, encoding of spaces and unicode, rejection of foreign schemes such as https:// and file:///, and rejection of relative or empty payloads. The helper assumes callers pass an absolute path; the decode side is the validating side.
PtyCreateRequest is the shared terminal-spawn contract:
-
idis stable per-node and also the tmux session key. -
projectIdlets main clean up live sessions before persistence settles. -
shell,cwd,command,cols,rows,env,terminalProfile, andhttpProxydescribe the local or remote process. -
commandruns asshell -lc <command>so the user’s login PATH applies. -
remoteswitches the terminal from localnode-ptytossh -ttplus remote tmux.
ProjectRemote carries user?, host, port?, and path. GitTarget models where git/file operations run: a local project sends cwd, while a remote project sends remote and cwd is null. The renderer is expected to set exactly one side; main validates both against the known project list.
Terminal lifecycle result types include PtyCreateResult with pid and fresh (false means warm tmux reattach, true means cold start), PtyExitInfo with exitCode and optional signal, and DurableCleanupResult for destructive metadata operations where committed sessions still need retry cleanup.
SerializedNode is the persisted node shape and intentionally mirrors core’s SerializedNode so the renderer never imports core. It carries:
-
id,type,position -
parentIdfor group/frame membership, kept out of live React Flow state but persisted -
width,height, andstyleso resized nodes restore their saved size instead of reverting to content-measured size -
datafor node-specific state
ProjectMeta stores id, name, cwd, optional remote, closed, optional archived, and optional per-project settings. ProjectSettings currently includes accent, used for node accent dots.
WorkspaceSnapshot is the persisted workspace envelope:
index.version: 1index.projects: ProjectMeta[]- optional
pendingTerminalCleanupandpendingTerminalNodeCleanup - optional
terminalTombstones projects: Record<string, SerializedNode[]>
Those cleanup and tombstone fields are the shared representation of terminal deletion/cleanup state across persistence boundaries.
AppSettings is the central user-configuration shape. It covers update downloads, managed agent accounts, announcement dismissal, cloud API origin, A2A peers, API provider endpoints, theme, enter behavior, browser agent control, A2A server enablement, wheel zoom inversion, onboarding timestamp, browser home URL, terminal font/profile/proxy settings, Telegram, chat, and relay configuration.
Several settings are intentionally local-machine-only or secret-adjacent:
-
TelegramSettingsstores the user’s bot token and allowed chat ids. -
ProviderKeystores provider API keys in settings.json only; env overrides are documented asTERMSPRAWL_PROVIDER_KEY_<ID>. -
A2APeer.tokenmay hold a bearer token, with env overrideTERMSPRAWL_A2A_PEER_TOKEN_<ID>. -
relay.trustedFingerprintpersists a confirmed peer identity after fingerprint confirmation.
Agent capability types describe CLI-side extensions:
-
SettingsSkill:enabledis real state; disabled skills live inskills-disabled/, and toggling moves directories. -
SettingsHook: distinguishesmanagedhooks installed by Termsprawl fromlegacyhooks owned by another tool. -
SettingsCommand:built-in,project, oragent. -
SettingsMcpServer: read-only discovery ofstdioorhttpservers; the CLI launches them. -
SettingsPlugin: CLI cached plugin withenabled,skills, andagentscounts. -
SettingsSubagent: reusable CLI-loaded subagent definition. -
SettingsCapabilities: aggregate wrapper withsupported, optionalreason, and arrays for each capability family. -
UsageStats: usage totals, sessions, daily breakdown, and model breakdowns.
AgentAccount includes id, label, agentId: 'claude', a configDir under userData/accounts/<id>, and a per-account permission mode. The type comment explicitly says never store tokens there.
BrowserCdpInfo describes the localhost-only CDP facade: port, per-boot bearer token, wsUrl, and host (127.0.0.1). The token is required on every CDP call. BrowserNavigateResult is a small discriminated result with ok: true or ok: false plus UNKNOWN_NODE | DENIED.
File and diff node contracts include:
DiffBase = 'staged' | 'HEAD'-
DiffInfoResultwithoriginal,modified, and optional error codeNO_REPO | MISSING | IO FileErrorCode = 'MISSING' | 'IO' | 'UNSUPPORTED' | 'OUTSIDE'-
FileReadResultvariants for text, markdown, image, and error -
FileWriteResultfor success or error
ChatNodeData persists a chat node’s provider/model/system/messages, including tool calls, usage, cost, and a cache-only streaming flag. ChatSettings stores default provider/model, provider keys, and optional price overrides for the cost chip.
Cloud contracts mirror the web API and include plans (free, pro, canvas), backup status, sync state, user, backup/detail, sync status, device-flow start/poll, online spaces, space access, space pull/push results, and GitHub repo/import results. CloudSpacePullResult carries imported SerializedNode[] so the renderer can hydrate them through its own deserialize path. CloudGithubRepo.cloneUrl is present on the wire but stripped before anything crosses IPC. Workspace bundle export/import contracts report saved/imported project counts and the first project id to switch to.
Announcements are pure shared data: Announcement has version, title, and body.
-
Terminal creation: renderer builds
PtyCreateRequest→ IPC channel fromipc.ts→ main resolves local vs remote project → returnsPtyCreateResult→ later emitsPtyExitInfo. -
Project deletion/cleanup: destructive metadata operations return
DurableCleanupResult, whosecleanupPendingIdsfeed pending terminal cleanup state across persistence. -
Workspace reopen/switch: persisted
SerializedNode[]insideWorkspaceSnapshotare deserialized by the renderer, restoring position, size, style, parent frame, and node data. -
Cloud space pull: main pulls a space, imports it as a new local project, returns
CloudSpacePullResultcontainingSerializedNode[], and the renderer hydrates through its normal path. -
File preview: renderer calls
toFilePreviewUrl(absPath)→ emitstermsprawl-file://local/...→ main maps it back withfromFilePreviewUrl(url). -
Settings/capability UI: shared shapes from
types.tsare populated by settings/capability readers and consumed by the settings panel and capability pages.
-
src/sharedmust remain Electron-free. This is whySerializedNodemirrors core’s type andChatNodeDatastays structurally in sync instead of importing core. - IPC channel names are centralized. Adding a capability should start in
ipc.ts, not in a handler or component. - Node kinds are a shared union. The documented rule is: when adding a node kind, extend the union in
src/sharedand insrc/renderer/src/state/workspace.ts. -
fromFilePreviewUrlis the guard for preview URLs: foreign schemes, non-localhosts, relative paths, empty payloads, and parse failures all returnnull. - Secrets are typed into settings only, not into project files or IPC payloads. Provider keys, Telegram tokens, relay fingerprints, A2A peer tokens, and agent account directories are explicitly local-only or never-token-bearing.
- Remote/local targeting is mutually exclusive for git/file ops:
GitTargetexpects one side set, and main validates against known projects. - Some contracts carry incomplete/partial provider data, e.g.
UsageStatsmodel breakdowns andAgentAccount.permissionMode; consumers should treat optional fields as optional rather than inventing defaults in shared code.
- Add or rename an IPC channel in
src/shared/ipc.ts. - Add a node kind to the shared union and the renderer workspace state.
- Add request/result/state shapes in
src/shared/types.ts, keeping them structural and Electron-free. - Add file preview protocol behavior only alongside
file-url.test.tsround-trip and rejection coverage. - Add settings or capability fields in the shared types first, then thread them through the settings store, IPC surface, and UI.
- Keep contract tests such as
settings-contracts.test.tsandupdate-status.test.tsin sync with shared changes.
Sources: src/shared/AGENTS.md, src/shared/file-url.ts, src/shared/file-url.test.ts, src/shared/types.ts
Generated from termsprawl at 0d4393be54c6200beedd91bb636e5296c30472c5.
App Shell & Platform Foundations
- Electron Main Process & Window Lifecycle
- Preload Bridge & IPC Contract
- Shared Domain Types and File/URL Helpers
- Renderer Bootstrap & App Composition
- Build Targets & TypeScript Configuration
Canvas, Nodes & Renderer State
- Infinite Canvas Surface & Viewport Interaction
- Workspace, Project & Tab State
- Node Links, Edges & Link Inspector
- Sticky, Group, Editor & Diff Nodes
- Keyboard Canvas Navigation & Cross-Panel Requests
- Theme, Accent & Visual Language
- Boot Overlay, Onboarding & Shared UI Kit
Terminals & Session Continuity
- PTY Lifecycle & Terminal Sessions
- tmux Session Naming & Reattach
- Scrollback Snapshots & Cold Replay
- Terminal Node Rendering (xterm.js)
- SSH Remote Projects, Terminals & Files
Persistence, Projects & Files
- Workspace Store & Project File Layout
- Project Scope, Deletion & Worktree Registry
- Workspace Bundle Export/Import
- File Service & File Tree UI
Agent Runtime & Tooling
- Agent Status Model & Hook Normalization
- Hook Server & CLI Hook Installers
- Agent Launch, CLI Probing & Managed Accounts
- Agent Tool Protocol & In-Process Server
- Agent Tool Client, CLI & MCP Entry
- Transcripts, Context Discovery & Context CLI
- Agent Canvas State & Status Badges
Chat Nodes & Model Providers
- Chat Runtime, Conversation & Cost
- Model Provider Adapters & Streaming
- Chat Tool Calling & Project Tools
- Chat Node UI
Git & Source Control
Embedded Browser Nodes
- Browser Manager & Guest Runtime
- CDP Facade & Browser Agent Server
- Browser Navigation Policy & Node UI
Server Edition
- Server Bootstrap & HTTP/WebSocket Entry
- RPC Dispatch, Handlers & Service Bridges
- Renderer Shim & Server Boundary
- Server Auth & Security Boundary
Relay & Remote Access
- Relay Hub & WebSocket Frame Routing
- Relay End-to-End Cryptography
- Relay Auth, Invites, Store & Admin API
- Relay Client, Pairing & Terminal Tunneling
- Relay Trust UI
Integrations & Secondary Surfaces
- Telegram Bot, Commands & Pairing
- A2A Peers: Protocol, Client & Server
- Node Link Engine, Registry & Scheduler
- Cloud Spaces, Snapshots & Sync
Settings, Updates & Maintenance