dsh-console-sentinel: Dismiss finished console windows from the taskbar

Preface

When running long automated tasks in DSH, the taskbar is often cluttered with a row of PowerShell / Python black windows: Fluent unattended tasks, batch scripts, and detached processes launched by WMI each occupy one. The problem here is not “lack of output,” but the inability to distinguish which are still running and which are finished. Consequently, no one dares to close them casually—the cost of accidentally closing a window currently calculating is much higher than simply looking at a few extra windows.

dsh-console-sentinel handles this: it tracks these console windows, distinguishes between “busy” and “finished,” and hides the finished ones. It does not kill processes, does not touch logs, does not lose output, and the windows can be recalled later.

What is this

dsh-console-sentinel is a plugin for DeepSeek Harness (DSH) developed and maintained by loyalchiiina. It is categorized as admin-security in the community directory and is licensed under MIT.

One-sentence positioning: A Windows console window sentinel—automatically hiding (or closing) idle AI/script console windows. It only operates on windows and does not interfere with processes, making it suitable for “unattended” scenarios where the task is still running but the interface does not need to be kept open. It is restricted to the Windows platform.

How it works

The plugin polls console windows at a fixed interval. Each round performs four actions:

  1. Enumerate windows. It uses an embedded zero-dependency Windows PowerShell probe (user32 + ntdll P/Invoke) to find three types of consoles by window class: CASCADIA_HOSTING_WINDOW_CLASS (Windows Terminal), ConsoleWindowClass (traditional conhost), and PseudoConsoleWindow (ConPTY pseudo-console).
  2. Classify source. It prioritizes checking the parent process: if the parent is WmiPrvSE.exe → wmi-detached (WMI-launched detached tasks, usually how unattended Fluent calculations start); if the parent is DSH Desktop.exe → dsh-host; if the parent has exited → orphaned. If the parent chain doesn’t explain it, it checks the console title: console titles launched by scripts default to the path of the launched program (...\python.exe), while interactive consoles opened manually have a prompt-style title (Windows PowerShell), classified as script-console.
  3. Determine idle. In each round, it samples the cumulative CPU time of the process. If it is below cpuThresholdPct (default 1%) and sustained for idleThresholdSec (default 60 seconds), it is judged as “finished.” A single background CPU spike will not reset the idle timer; this is controlled by spikeTolerance (default 2).
  4. Execute action. For windows in the managed scope that are “finished,” it executes autoAction (default hide, i.e., SW_HIDE, process continues running); close sends WM_CLOSE. Foreground windows are never processed automatically (guardForeground).

The probe obtains the parent process PID using NtQueryInformationProcess rather than CIM (Get-CimInstance Win32_Process)—actual machine testing shows 39 seconds vs 24 milliseconds (13 processes), with a single full probe taking about 350 milliseconds. This explains why the plugin insists on embedding its own probe.

Installation and Activation

The installation command comes from the project README:

dsh plugin --profile <name> add dsh-console-sentinel

This is a Bundle plugin (dsh.bundle.patch): after installation, it enters the profile bundle stack and takes effect after restarting DSH. The patch line is marked as disabled on other platforms, and apply() also enforces platform limits at runtime.

Running requirements: Node ^22.19.0 || >=24.0.0; peer dependencies @deepseek-ai/cordis >=4.0.2, @deepseek-ai/dsh-tools >=0.1.5-rc.2, @deepseek-ai/schemastery >=3.18.0; current version 0.3.0.

Tools Visible to the Model

The plugin provides 5 tools that models can call directly:

  • console_windows_list — Lists all tracked console windows, their idle status, and source classification. Use this first to see the current state.
  • console_window_action — Performs hide/show/minimize/restore/close on a single window, located by hwnd or pid. hide is lossless; close may lose unsaved output. force must be passed when operating on foreground windows.
  • console_windows_sweep — Performs an action on all idle and in-scope windows at once. Very useful for clearing the taskbar after running a batch of Fluent tasks.
  • desktop_windows_cleanup — One-click close of other windows: closes all application windows on the desktop except foreground, self, system shell, and protected processes. dryRun outputs the plan first; protected / keepTitle / keepPid can temporarily reinforce protection.
  • sentinel_whitelist — Manages a persistent exemption whitelist, with list / add / remove / reset, kind=process (by image name, e.g., code.exe) or kind=title (by title substring). The whitelist applies to both automatic hiding/closing and one-click window cleanup, persisting to ~/.dsh/console-sentinel/whitelist.json.

Settings Panel

Starting from 0.3.0, the plugin registers a “Console Sentinel” section in the DSH “Settings” page (client bundle lib/client.js), allowing operations without knowing the tool names:

  • Overview: Counts of total windows / empty shells PowerShell / visible shells / hidden, plus “Hide visible shells.”
  • Taskbar Window Cleanup: Preview / One-click close other windows (foreground, system processes, whitelist auto-skips).
  • Console Windows: Displays process name / title / hwnd / pid / CPU / idle seconds / child process count row by row; rows can directly hide/show/close.
  • Whitelist: Tag-style add/remove/clear for process names and title keywords, saving immediately.

The panel fetches data via the host route /dsh-console-sentinel/*. The client fetches relative to the root path. On the desktop, it automatically includes the capability header and does not use an iframe. After modifying lib/client.js, do a Ctrl+Shift+R hard refresh; modifying the host side (lib/index.js / package.json) requires fully exiting DSH and restarting.

Configuration

Configuration is written in cordis.yml. Common keys are as follows:

Key Default Meaning
enabled true Master switch
scanIntervalSec 10 Scan + CPU sampling interval
idleThresholdSec 60 How many seconds of sustained low CPU count as “finished”
cpuThresholdPct 1 CPU below this value counts as idle
autoAction hide none | hide | close
probeTimeoutMs 20000 Probe hard timeout
spikeTolerance 2 How many consecutive “busy” samples must occur before resetting the idle timer
guardForeground true Never automatically process foreground windows
scope.wmiDetached true Manage WMI-launched detached consoles
scope.dshHost true Manage host-derived consoles
scope.orphaned false Manage consoles whose parent process has exited
scope.scriptConsole true Manage consoles whose title is a script executable file path (script sessions hosted by Windows Terminal)
scope.excludeTitles [] Title substring blacklist
scope.emptyConsole true Interpreters (PowerShell/Python/cmd left with only conhost) with no working child processes are judged as empty shells and managed regardless of the parent chain. This is the switch for safely cleaning up residual empty PowerShell windows; you don’t need to enable the entire orphaned scope (the latter would accidentally harm mpiexec/fl2610/calculations running).
emptyConsoleAction hide Action for empty shell consoles: none | hide | close; independent of autoAction, automatic actions can still take effect individually
whitelist.processes [] Exempt process image names (e.g., code.exe), never automatically processed / one-click closed
whitelist.titles [] Exempt title substrings, never automatically processed / one-click closed

For example, to relax the idle judgment to 90 seconds and exempt windows containing keep-alive in the title:

- id: dsh-console-sentinel
  config:
    idleThresholdSec: 90
    scope:
      excludeTitles:
        - keep-alive

Typical Usage

  1. First, use console_windows_list to see what windows currently exist, whether each is busy or idle, and what their source classification is.
  2. For a single finished window, use console_window_action hide (locating by hwnd or pid); when you need it back in the foreground, use show.
  3. After running a batch of Fluent tasks, use console_windows_sweep to pick up all idle windows at once.
  4. Normally, if you want a specific process (e.g., code.exe) or a specific title keyword to never be moved, call sentinel_whitelist add; when using the one-click cleanup from the desktop bottom-right corner, processes outside the area are also covered by an extra layer of protected / keepTitle / keepPid from desktop_windows_cleanup.

The actual window state cannot be replayed. The README only provides the above operation sequence, without screenshots or end-to-end logs; for actual results, it is recommended to run console_windows_list once on your own machine to confirm if the classification meets expectations.

Security and Applicable Scenarios

The actions themselves are restrained:

  • hide only calls ShowWindow(SW_HIDE); processes, logs, and output remain untouched. show in console_window_action can be restored at any time (using SW_SHOWNORMAL—actual testing shows SW_SHOW cannot restore a hidden Windows Terminal window).
  • close sends WM_CLOSE (graceful close, same as clicking X), but may lose unsaved state, so it is never the default action.
  • Automatic actions never touch: foreground windows, manually opened consoles (manual source), windows whose titles hit the blacklist or whitelist, and system/computing processes in HARD_PROTECTED_PROCESSES (explorer, taskmgr, dsh desktop, fl2610/cx2610/mpiexec/smpd/fluent, etc.).
  • Every action sends a console-sentinel/action event and writes to the log.

Applicable scenarios: Long-term unattended script execution, automated workflows that need to keep background calculations running but don’t want to keep windows visible, and the “clean taskbar” cleanup action. It is not suitable for interactive debugging where windows need to stay visible—in that case, you should directly set autoAction to none or use the whitelist to pin the window.

It should be noted that the plugin runs with the permissions of the current dsh process and can only enumerate and operate on windows visible within that permission scope; before installation, it is recommended to check the source code and license (MIT) to ensure that the scope.* switches and the HARD_PROTECTED_PROCESSES list match your environment.

Project Structure and Testing

lib/index.js   Cordis plugin: config, scan scheduling, tools
lib/logic.js   Pure ledger / idle state machine (unit tests covered)
lib/probe.js   Embedded PowerShell probe + window actions
tests/         Node-only regression tests, no real Windows needed

node tests/logic.test.mjs — 24 assertions, covering source classification, idle accumulation, busy pulse reset, scope guard, ledger GC, sorting. This means the core judgment logic can be regression-tested on non-Windows machines.

Conclusion

The value of dsh-console-sentinel does not lie in “having another window management tool,” but in how it solidifies the question “is this window still busy?” into a three-way judgment of CPU + parent chain + title, and uses hide instead of kill for cleanup, providing an unattended workflow with a cleanup method that does not risk data loss.

  • Directory page: https://www.skillhub.cn/plugins/loyalchiiina/dsh-console-sentinel
  • GitHub: https://github.com/loyalchiiina/dsh-console-sentinel
羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

Xiaoye