PowerShell Memory Watchdog
A Windows Desktop VS Code extension that measures private committed memory and resident memory of the pwsh instances launched by each VS Code window: integrated terminals, their nested PowerShell processes, and processes launched by that window's extension host. Runs in the local Node extension host; one independent, profile-free PowerShell 7 collector measures the whole window inventory. No runtime npm dependencies.
Install
Install dist/powershell-watchdog-0.3.0.vsix using Extensions: Install from VSIX… in VS Code Stable or Insiders. Requires VS Code 1.114 or later, Windows and an independent PowerShell 7 Core collector. Ordinary pwsh monitoring works without the Microsoft PowerShell extension or an open .ps1 file. Reload the window after upgrading an already active watchdog.
Automatic Editor Services restart additionally requires ms-vscode.powershell 2026.1.2 and its verified window association. Unknown extension versions and ambiguous Editor Services do not disable ordinary process measurements or alerts. Remote windows, the browser, Linux and macOS remain unsupported. Actual editor qualification is documented in QUALIFICATION.md.
Use
The status bar shows the number of measured pwsh instances and their total private memory, for example pwsh 3 · 0.42 GiB total · Monitoring. No pwsh in this window means a completed collection found none; Discovering pwsh means discovery is still incomplete. Collection errors say Measurement unavailable. An incomplete total is prefixed with ≥. Hover for per-process private/resident memory, PID, creation time, current action policy and last collection age. Click for actions or open PowerShell Watchdog: Show Diagnostics for the full process list.
Defaults: 15-second collection interval, 4 GiB warning, 8 GiB restart threshold, three consecutive high samples, 3-second collection deadline, 45-second restart deadline, 120-second stabilization and at most three automatic requests in a rolling hour. One GiB is 1,073,741,824 bytes. Private and resident memory are never added together.
Thresholds apply to each process independently. Adding several small processes together does not qualify one process for restart. The default mode is automatic for verified Editor Services; ordinary terminals and child pwsh processes always use alerts only. Their threshold crossings never invoke PowerShell.RestartSession or close a terminal. The manual restart command is explicitly named Restart Editor Services Session…. An editor restart discards editor-session variables, modules and state and may interrupt an interactive editor command. PowerShell debugging defers automatic requests; absence of a debugger does not establish an idle console. Use notifyOnly for alerts on every instance.
Configure frenchexdev.powershellWatchdog.* in user settings. All settings are machine scoped; workspace and folder overrides are ignored explicitly. The settings and their defaults match BESOIN.md. Invalid policies disable automatic decisions and show an explanation. Disable survives a window reload. Quota, suspension, cooldown and unsuccessful/pending attempts are retained in workspace state; Resume is required after an automatic failure or quota suspension. Resume retains the rolling quota and does not authorize a second request while a timed-out command remains pending.
Per-window ownership and editor recovery
Ownership roots come from this window's Terminal.processId values and its extension-host PID. The collector walks the Windows process graph to include their live pwsh.exe descendants. Parent creation times must precede child creation times; traversal stops at the first Code executable boundary. This prevents walking through another editor process into a different window's tree. Ordinary PowerShell started outside these ownership roots is excluded. Detached/orphaned processes with no surviving verifiable ownership chain cannot be associated. The collector excludes itself.
Editor restart permission is stricter than read-only measurement. The adapter, derived from the shipped Microsoft extension, reads its public getLogUri()/getStorageUri() and matches exactly one current-window terminal's module and session-launch artifacts. The collector independently checks these artifacts before declaring it an automatic restart target. Debug-only and other terminals remain alert-only. Full command lines are neither returned nor logged. A changed creation time invalidates the old process's counters, including PID reuse.
A restart is requested only through the current window's registered PowerShell.RestartSession. A normal command return is insufficient: a different PID/creation-time identity must be associated and measured before the overall deadline. Failed, expired or interrupted requests suspend automatic actions. Persistently high memory after stabilization also suspends them. There is no automatic forced termination, global process selection, elevation, profile change or telemetry.
Diagnostics and budgets
Diagnostics opens a JSON document containing the current policy, all measured processes with kind and restart capability, completeness/errors, the previous inventory, Editor Services identity, decisions and environment versions. Collection errors never become zero memory. Inventory is bounded to 256 pwsh instances and 255 terminal roots plus the extension host; overflow is explicit. History retains 200 collections, each with the 20 largest measured processes and an omitted count. The journal uses VS Code's per-window extension log directory: watchdog.0.jsonl through watchdog.2.jsonl, each at most 5 MiB. Storage failures are visible in diagnostics. The shared extension host must itself remain responsive.
Visual diagnostic report
Run PowerShell Watchdog: Open Visual Diagnostics (HTML) from the command palette or Visual diagnostics (HTML) from the status-bar menu. It saves a uniquely dated HTML file under diagnostic-reports in the extension's workspace storage, or global extension storage when no workspace is open, then requests external opening. The system association for .html normally opens the browser. If opening fails, a notification gives the saved path and Reveal report action. Each export is retained; generating another report does not overwrite an earlier one.
The self-contained file works offline and includes current state and process inventory, private/resident memory curves with a process selector and hover values, historical per-process thresholds, observed peak rankings, paginated recorded events and environment versions. Uncheck Show per-process thresholds to inspect smaller memory changes. It is a point-in-time report; rerun the command to update it. The JSON diagnostic remains available separately.
Exports read only the three journal files in this window's current log directory, at most 15 MiB, and merge them with the 200-entry in-memory history. They do not search previous VS Code log sessions or other windows. Missing/unreadable files, malformed records and capped files are reported. Retained historical inventories contain the 20 largest processes, with an additional Editor Services sample when available: absent samples are gaps, incomplete current totals are lower bounds, and recorded peaks are not exhaustive lifetime maxima. Older journal entries lack the sampling cadence; their long-gap detection uses the median retained interval. Plot reduction preserves peaks and interruptions while the complete normalized retained data remains embedded in the HTML. No collection, restart or policy change is requested by exporting.
node test/run-report-browser.js exercises an existing Edge/Chromium browser with a separate headless profile and near-15-MiB prepared journals, without downloads. Set WATCHDOG_TEST_BROWSER for another installed Chromium executable. It verifies offline rendering, PID reuse, gaps, escaping, controls and narrow layout; JSON results are written to verification/report-browser.json, with sample HTML and screenshots under .sandbox/report-*.
Develop and qualify
For automated Marketplace publication from a version tag, see RELEASING.md.
Node 22+ is required for the development tooling. Install locked tools with npm ci --ignore-scripts, run node --test test/*.test.js, and package with node node_modules/@vscode/vsce/vsce package --no-dependencies --out dist/. Follow the repository's QuietCli instructions when running commands as an agent.
test/run-integration.js installs the current-version VSIX into a new .sandbox/run-* extension directory, copies the explicitly selected Microsoft extension, and runs two independent editor instances with separate user data and workspaces. Set WATCHDOG_TEST_EXTENSION to the installed Microsoft extension directory and WATCHDOG_TEST_PWSH to pwsh.exe, then run node test/run-integration.js. Select an existing Desktop executable with WATCHDOG_TEST_VSCODE, or download a separate test copy using WATCHDOG_TEST_CHANNEL=insiders (default) or stable. It never uses your normal VS Code profile. It first measures an ordinary terminal and its nested pwsh before explicitly starting Editor Services, checks child exit/removal, then tests isolation, debugger deferral, editor restart and independent ordinary-process warnings. Allocation is bounded to 192 MiB per Editor Services session and 192 MiB per ordinary console, with scaled thresholds. Both editors are reopened to verify persistent disable and quota. Reports go to verification/integration-insiders.json or verification/integration-stable.json, with installed runtime hashes. Sandbox files are retained for inspection. These tests do not establish the proposed stabilized <50 MiB overhead objective.
Sources: Microsoft extension API, session launch implementation, VS Code terminal API, extension host placement, Windows private memory, resident memory. Compatibility is gated to the locally inspected release rather than inferred from the moving main branch.