Skip to content
| Marketplace
Sign in
Visual Studio Code>Other>Live Share - IntranetNew to Visual Studio Code? Get it now.
Live Share - Intranet

Live Share - Intranet

alexanderzjs

|
6 installs
| (0) | Free
Decentralized real-time collaborative editing for VSCode — no external servers required, pure intranet P2P
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

Live Share - Intranet — VSCode Extension

Project Overview

Decentralized real-time collaborative editing VSCode extension. No external servers required — the Host acts as both the WebSocket server and the session coordinator. All data stays on the intranet.

Architecture

Host (WebSocket Server + Editor) ←→ Guest (WebSocket Client + Editor)
                 ↕
         WebSocket on IP:PORT
  • Host: Starts a ws.Server, broadcasts messages, relays between guests
  • Guest: Connects via ws://HOST:PORT, sends/receives messages
  • Protocol: Unified JSON message envelope (Message type in src/protocol)

Build & Run

npm install          # Install dependencies
npm run compile      # Build for production
npm run watch        # Dev mode with watch

Project Structure

src/
├── extension.ts       # Entry point: commands, status bar, session lifecycle, collab + FS + terminal + debug wiring
├── websocket/
│   ├── wsserver.ts       # Host-side WebSocket server (HostServer class)
│   └── wsclient.ts       # Guest-side WebSocket client (GuestClient class)
├── protocol/
│   └── index.ts          # Message types, payload definitions, helpers, base64 utils
├── collab/
│   ├── doc-manager.ts    # Yjs document lifecycle per file, on-demand disk init, binding creation
│   ├── editor-binding.ts # Two-way sync: VSCode TextEditor ↔ Yjs Y.Text (supports rebind)
│   └── awareness.ts      # Cursor/selection sync, remote cursor decorations, trackEditor()
├── filesystem/
│   ├── provider.ts       # lsintranet:// FileSystemProvider (Guest side), reads from Yjs docs
│   └── sync.ts           # File change watcher + tree builder (Host side), updates Yjs on disk change
├── terminal/
│   ├── host.ts           # Host terminal manager (node-pty), spawns shells, bridges I/O
│   └── guest.ts          # Guest Pseudoterminal, renders remote terminal output
├── debug/
│   ├── proxy.ts          # DAP message proxy (Guest-side DebugAdapter implementation)
│   └── path-mapper.ts    # Bidirectional path mapping (lsintranet:// ↔ host FS)
├── follow/
│   └── tracker.ts        # Follow mode: editor focus + cursor sync, auto-stop on local edit
├── chat/
│   └── handler.ts        # Chat panel (Webview), message send/receive via WebSocket
└── agent/
    └── handler.ts        # Shared agent prompt/response panel (Webview)

Development Phases

  • [x] Step 1: Project scaffold & configuration
  • [x] Step 2: Communication layer (WebSocket Host/Guest + protocol)
  • [x] Step 3: Real-time collaborative editing (Yjs + cursor sync)
  • [x] Step 4: File tree sync (FileSystemProvider)
  • [x] Step 5: Terminal sharing (node-pty + Pseudoterminal)
  • [x] Step 6: Debug session sharing (DAP proxy)
  • [x] Step 7: Follow mode
  • [x] Step 8: Chat
  • [x] Step 9: UI polish & packaging
  • [x] Step 10: Unify file content sync through Yjs channel (Phase 2)

Key APIs Used

  • vscode.StatusBarItem — Session status display
  • vscode.commands.registerCommand — Command palette integration
  • vscode.workspace.onDidChangeTextDocument — Detect local edits → push to Yjs
  • vscode.workspace.applyEdit — Apply remote Yjs edits to local document
  • vscode.window.createTextEditorDecorationType — Remote cursor rendering
  • ws.Server / ws.WebSocket — WebSocket communication
  • Yjs (yjs) — CRDT engine for conflict-free collaborative editing
  • vscode.FileSystemProvider — Virtual file system for lsintranet:// scheme
  • vscode.workspace.registerFileSystemProvider — Register custom scheme
  • vscode.FileSystemWatcher — Watch Host workspace for file changes
  • node-pty — Spawn pseudo-terminal processes on Host
  • vscode.Pseudoterminal — Render remote terminal output on Guest
  • vscode.debug.registerDebugAdapterDescriptorFactory — Register custom DAP proxy
  • vscode.DebugAdapter — Guest-side DAP proxy implementation
  • vscode.window.onDidChangeActiveTextEditor — Follow mode: detect editor focus change
  • vscode.window.onDidChangeTextEditorSelection — Follow mode: detect cursor/selection change
  • vscode.window.createWebviewPanel — Chat panel UI

Collab Data Flow

Local edit → onDidChangeTextDocument → Yjs Y.Text → doc.on('update')
  → WebSocket (yjs-update) → Remote side → Y.applyUpdate → Ytext.observe
  → workspace.applyEdit → VSCode document updated

Remote cursor → yjs-awareness message → AwarenessManager.updateRemote()
  → editor.setDecorations() → Colored cursor + name label rendered

Initial sync (Guest joins):
  Host → onGuestJoin → buildFullWorkspaceInit() → yjs-init (ALL files, not just open ones)
  Guest → initFromRemote() → Y.applyUpdate for each file → content available via getDocContent()

File System Data Flow (Phase 2: Unified Yjs Channel)

Host side:
  FileSyncManager watches workspace with FileSystemWatcher
  → onDidCreate/Change/Delete (file) → docManager.updateDocFromDisk() → Yjs Doc updated
    → Yjs automatically syncs delta to all Guests via yjs-update
  → onDidCreate/Delete (directory) → broadcast file-tree-change (structural only)
  → Guest joins → buildFullWorkspaceInit() → yjs-init (all files) + file-tree

  Guest requests a file not yet synced:
    Guest → yjs-req (filePath) → Host
    Host → docManager.createDocFromDisk() → yjs-init (single file) → Guest

Guest side:
  Live Share - Intranet FS Provider registered as lsintranet:// scheme
  → file-tree message → buildTree() → populate virtual FS cache
  → file-tree-change message → applyTreeChange() (structural: create/delete/rename)
  → readFile(uri) → getDocContent(filePath) from CollabDocManager → returns Yjs doc text
    → if doc not found, send yjs-req → Host creates doc → yjs-init arrives → content available
  → URI mapping: lsintranet:///path/to/file.py ↔ /path/to/file.py

Key change from Phase 1:
  REMOVED: file-content-req, file-content-res, file-change (base64 broadcast)
  ADDED: yjs-req, file-tree-change
  ALL file content now flows through Yjs — same channel as collaborative edits
  Disk changes on Host update Yjs Doc → Yjs handles incremental sync automatically

Terminal Data Flow

Host side:
  HostTerminalManager creates PTY process via node-pty
  → pty.onData(data) → base64-encode → broadcast terminal-data to all Guests
  → receive terminal-data from Guest → pty.write(base64-decoded)
  → pty resize → broadcast terminal-resize
  → Host also opens a local mirror terminal for the same PTY so Host and Guests share one live session
  → Guest joins → send terminal-create for each active terminal

Guest side:
  Receive terminal-create → vscode.window.createTerminal({ pty: Live Share - Intranet Pseudoterminal })
  → PseudoTerminal.onDidWrite → writeEmitter.fire(decoded data)
  → User input → send terminal-data to Host → pty.write()
  → Resize → send terminal-resize to Host → pty.resize()

Terminal ID mapping:
  Each terminal has a unique string ID (uuid)
  Host maintains Map<terminalId, IPty>
  Guest maintains Map<terminalId, Live Share - Intranet Pseudoterminal>

Debug Data Flow

Host is the debug authority:
  Host starts a normal VS Code debug session
  → onDidStartDebugSession captures the active session and broadcasts dap-event
  → Host DebugAdapterTracker captures real adapter events (output/stopped/continued/terminated)
  → Guests proxy DAP requests to Host via dap-request
  → Host forwards to the active Debug Adapter via customRequest()
  → Host relays dap-response / dap-event back to Guests
  → Guest auto-starts an Live Share - Intranet mirror debug session to render Host events in the Guest Debug UI
  → Guest forwards threads/stackTrace/scopes/variables to Host so stopped frames, line highlight, variables, and call stack match the Host
  → Guest buffers early output/stopped events until the mirror adapter initializes, then opens the Debug Console for mirrored output

Path mapping (automatic):
  Guest sets breakpoint at lsintranet:///home/user/project/main.py:10
  → PathMapper.guestToHost() → /home/user/project/main.py
  → Host Debug Adapter receives correct local path
  → Variable panel shows lsintranet:// paths → PathMapper.hostToGuest() for display

Debug lifecycle:
  Host: onDidStartDebugSession → capture session → notify Guests (debug-start)
  Host: onDidTerminateDebugSession → notify Guests (debug-stop)
  Guest: "Remote Debug (Guest)" can request the Host to auto-start a session
  Breakpoints sync separately through breakpoints-sync and mirror both ways

Configuration

  • lsIntranet.port — WebSocket server port (default: 9999)
  • lsIntranet.userName — Display name (defaults to hostname)

Notes

  • bufferutil, utf-8-validate, and node-pty are native modules, marked as webpack externals
  • Host auto-detects local IPs and shows them in the status bar
  • Guest has auto-reconnect with exponential backoff (max 10 attempts)
  • Terminal data is base64-encoded for safe JSON transport over WebSocket
  • Debug DAP proxy is a transparent message forwarder — does not parse DAP content, only maps paths
  • File content sync is unified through Yjs (方案2): no separate content request channel, disk changes update Yjs Docs directly
  • CollabDocManager.createDocFromDisk() creates Yjs docs for files not currently open in the editor
  • EditorBinding supports rebind() for re-attaching to a different editor instance
  • AwarenessManager.trackEditor() sets up selection/focus listeners for a specific editor
  • Breakpoints now sync through breakpoints-sync; debug launch is still Host-authoritative and guests proxy through the Host session
  • Host debug adapter events are mirrored to Guests through dap-event; output events appear in the Guest mirror debug session and the Guest forwards stack/variable requests to the Host to render stopped locations
  • Shared terminal output now mirrors into a local Host terminal window as well as Guest pseudoterminals

Follow Mode Data Flow

Broadcaster (any user):
  onDidChangeActiveTextEditor → broadcast { type: 'follow', filePath, line, character }
  onDidChangeTextEditorSelection → broadcast { type: 'follow', filePath, line, character }

Follower:
  Receive follow message → open file at path → move cursor to line:character
  → editor.revealRange(InCenterIfOutsideViewport)

Auto-stop:
  Follower makes local edit → stopFollow() → no longer processes follow messages
  stopFollow command → clears following user ID

Chat Data Flow

Send message:
  User types in Webview → postMessage to extension
  → WebSocket chat message → broadcast to all users
  → addLocalMessage() for immediate display (optimistic update)

Receive message:
  WebSocket chat message → ChatHandler.handleIncomingMessage()
  → filters by localUserId to avoid showing own messages twice
  → Webview panel postMessage → render in chat UI

Chat panel:
  Created on first openChat command
  Persists across message sends/receives
  Shows sender name + timestamp + message content

Feasibility Analysis and Updated Design

Feasibility summary (intranet-only, IP:port peer discovery):

  • Architecture: Host-as-server (ws.Server) with Guests connecting via ws://IP:PORT. This is simple, reliable on corporate LANs and requires no external servers.
  • Real-time editing: Yjs per-file CRDTs is appropriate. Use a Y.Doc per file, lazy initialization and on-demand sync to avoid sending whole workspace.
  • Discovery: Manual connect by IP:port is acceptable. Optional local discovery (mDNS/UDP) can be added later.
  • Security: No external auth required. Recommend optional TLS (wss) for encryption using internal CA or configurable self-signed certs. Keep ability to disable TLS for closed networks.
  • Debug & Terminal: Host-side DAP proxy and node-pty are feasible; path mapping required to translate lsintranet:// URIs.
  • Scale: Designed for small-to-medium teams (~2-20 active collaborators). For larger scale, add selective sync, sharding, or an optional relay server inside the intranet.

Recommended implementation plan (phased):

  1. Phase 0 — Prototype (validate core components)

    • Prototype ws host/guest and Yjs per-file sync (small files)
    • Prototype DAP relay and path mapping
    • Prototype node-pty terminal relay
  2. Phase 1 — Core features

    • Implement HostServer and GuestClient with stable protocol (versioned)
    • CollabDocManager (create/apply Yjs updates, persistence)
    • EditorBinding and AwarenessManager (cursor/selection)
  3. Phase 2 — FS and lazy sync

    • File tree sync and lsintranet:// FileSystemProvider
    • yjs-req / yjs-init for on-demand file docs
    • Conflict handling policy for disk ↔ Yjs
  4. Phase 3 — Terminal, Debug, Chat

    • HostTerminalManager (node-pty) and Guest Pseudoterminal
    • DAP proxy with robust path mapping and session multiplexing
    • Chat Webview and message UI
  5. Phase 4 — Hardening & UX

    • TLS support and configuration UI
    • Logging, diagnostics, tests (CRDT convergence + DAP passthrough)
    • Packaging and extension marketplace/private deployment docs

Concrete todos (suggested task ids):

  • host-server: Implement HostServer (ws) and CLI/config for port, TLS
  • yjs-doc-manager: Implement per-file Yjs docs, persistence, lazy load
  • editor-binding: Implement two-way binding + awareness
  • fs-provider: lsintranet:// provider and file-tree sync
  • dap-proxy: DAP relay with path mapping tests
  • terminal-proxy: node-pty host relay and guest pseudoterminal
  • tls-config: support wss with cert configuration and docs

Notes:

  • Keep protocol JSON simple and versioned; allow feature negotiation.
  • Minimize data sent on join: send file-tree + doc summaries; request docs on demand.
  • Write unit tests for path mapping and CRDT convergence; end-to-end for DAP relay.
  • Document limitations (single host, recommended team size, TLS options).

Terminal proxy:

  • Host: src/terminal/host.ts uses node-pty to spawn PTYs, broadcasts terminal-create, terminal-data, terminal-close, and accepts terminal-data and terminal-resize from Guests.
  • Guest: src/terminal/guest.ts implements a vscode.Pseudoterminal per shared terminal, relays keyboard input (terminal-data) and resize (terminal-resize) back to Host.
  • Wired in src/extension.ts: HostTerminalManager and GuestTerminalManager are created and connected to the transport. The shareTerminal command spawns a Host terminal; Guests receive terminal-create and render it.

Testing:

  • Start Host, run Live Share - Intranet: Share Terminal (Host) — Guests will see a new terminal appear.
  • On Guest, type into the pseudoterminal; input is relayed to Host PTY.
  • Live Share - Intranet: Stop Session closes shared terminals.
  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
© 2026 Microsoft