npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@iiwate/pi-silent-gui

v0.2.0

Published

Pi extension: private-desktop GUI smoke with Windows Job Object lifecycle and strict audio failure handling

Readme

pi-silent-gui

Windows-only Pi 扩展:在隔离的 Win32 私有桌面中启动和操作 GUI 程序,并输出无损窗口截图。整个过程不切换用户桌面、不使用剪贴板,也不调用 SendInput

安装

要求:

  • Windows 10 或更高版本;
  • Node.js >= 20;
  • Python >= 3.10,且 python 在 PATH;
  • 提权 Pi 的默认非提权路径需要当前用户的 Explorer shell。
pip install pycaw
pi install npm:@iiwate/pi-silent-gui

安装后执行 /reload。可用 PI_SILENT_GUI_PYTHON 指定 Python 解释器。

工具

| Tool | 作用 | |---|---| | silent_spawn | 在私有 Desktop 和 Job Object 中启动进程;默认非提权,音频 guard 就绪后才恢复目标线程 | | silent_message | 按完整窗口 PNG 坐标投递 click/key,自动分流客户区 child 与非客户区,支持批量 steps | | silent_capture | 捕获完整窗口,返回绝对 PNG 路径、原始尺寸、客户区/DPI 元数据和 all_black | | silent_kill | 终止 Job、停止 broker,并清理受约束的 session 临时目录 |

启动

{
  "exe": "app.exe",
  "cwd": "C:/path/to/app",
  "args": ["--example"]
}

目标默认非提权。只有 Pi 已经提权时,才可显式允许管理员目标:

{
  "exe": "admin-tool.exe",
  "allow_elevated": true
}

扩展不会调用 runas,也不会触发 UAC。

消息

单次 click/key 或批量步骤都在同一个私有桌面和初始顶层 hwnd 上执行。单步 repeat 为 1..100,delay_ms 为 0..10000,总动作数不超过 1000。

click 的 x/ysilent_capture 完整 PNG 共用同一窗口坐标系,(0,0) 是 PNG 左上角,不需要也不允许调用方估算标题栏高度。运行时使用 Window/Client Rect、坐标转换和 WM_NCHITTESTHTCLIENT 会下降到最深可见、非透明 child 并投递客户区鼠标消息;其他命中向顶层窗口异步投递对应非客户区消息,避免标题栏或菜单模态循环阻塞 down/up。

{
  "session_id": "...",
  "steps": [
    { "action": "click", "x": 50, "y": 50 },
    { "action": "key", "key": "return", "repeat": 2, "delay_ms": 50 }
  ]
}

响应包含 coordinate_space: "window"window.client {x,y,width,height}window.dpi。click 还返回 hit_test、实际 target_hwnddispatch,以及 point.window/screen/targetHTCLOSE 会附带 system_command: "close"。成功只表示消息已完成有界投递,界面效果应由后续截图验证。批量响应在 clicks 中按执行顺序返回每次 click 的投递元数据。

截图

{
  "session_id": "...",
  "window_class": "ExampleWindow",
  "out_path": "C:/evidence/window.png"
}

out_path 可省略;默认文件写入当前 session 临时目录。截图始终保留完整 Window Rect,不裁剪客户区。返回值包含 coordinate_space: "window"、相对完整 PNG 的 window.client {x,y,width,height}window.dpi,不内联图像。

清理

{
  "session_id": "..."
}

Pi session_shutdown 会对仍登记的 session 执行两次 best-effort kill。

隔离与生命周期

每个 session 使用一个持久 Python broker:

  1. 生成调用方不可指定的唯一私有 Desktop;
  2. 创建带 KILL_ON_JOB_CLOSE 的 Windows Job Object;
  3. 使用 STARTUPINFOEX + PROC_THREAD_ATTRIBUTE_JOB_LIST,在进程创建时原子加入 Job;
  4. 目标保持 suspended,直到 WASAPI 音频通知和首轮静音枚举完成;
  5. broker 持续跟踪 Job 内进程、维持静音并处理 stop;
  6. broker 异常退出时,Job handle 关闭并终止整棵进程树。

默认路径不会因 Pi 已提权而让目标继承管理员 token;拿不到可信的非提权 Explorer token 时会直接拒绝启动。

安全边界

  • 永不调用 SwitchDesktopSendInput 或剪贴板 API;
  • Desktop、Job 和 session 状态均绑定 12 位 session ID namespace;
  • kill 只操作登记的 Job 和 PID+创建时间身份,不按 exe 名或 PPID 全局扫描;
  • PID 身份核验、终止和等待在同一个进程 handle 上完成;
  • 客户区和 hit-test 使用 SendMessageTimeoutW 限时;非客户区 down/up 使用 PostMessageW 异步有界入队;
  • 几何、message、capture 只临时切换对应 helper 操作线程的 per-monitor DPI awareness,并恢复原 context;
  • 临时目录只允许位于 %LOCALAPPDATA%\Temp\pi-silent-gui\<session_id>
  • 删除前逐级持有目录 handle,拒绝 junction、符号链接和其他 reparse point;
  • 异常 spawn 仅在 Job 和 broker 身份完整时登记恢复 session;
  • Python stdout/stderr 持续排空,各自只保留最后 1 MiB,不因输出超限强杀 launcher。

清理失败会保留 session 登记和结构化错误,供后续重试。

截图保真

  • 捕获完整 Window Rect,保持原始宽高,不缩放、不裁剪;
  • 上限为 32 * 1024 * 1024 像素,超限明确失败,不降质输出;
  • 使用 24-bit RGB 无损 PNG;
  • GetDIBits 未返回全部扫描行时立即失败;
  • 只重试等待 Job/窗口出现,找到窗口后 PrintWindow 只执行一次;
  • 全黑画面仍作为有效证据写入,并以 all_black: boolean 明示;
  • TS 返回前验证绝对路径、文件身份、PNG/IHDR 和窗口尺寸。

静音边界

broker 在恢复目标线程前注册 WASAPI session-created 通知,并辅以启动期 50ms、稳定期 200ms 轮询。SetMute 失败或连续音频 sweep 失败会终止整个 Job。

Windows 用户态 per-process mute 无法形式化证明“绝不产生任何采样”。本扩展保证的是:音频 guard 未建立时不恢复目标,guard 失效时 fail closed。

临时文件

%LOCALAPPDATA%\Temp\pi-silent-gui\<session_id>\
  session.json
  cap_*.png

silent_kill 全成功后永久删除该 session 目录;显式指定到其他位置的证据截图不会随 session 删除。

测试

npm run test:unit
npm run test:integration
npm run test:smoke
npm test
  • unit:capture/window/process 单元测试和 TS 伪造响应 fail-closed;
  • integration:后端 CLI、故障注入、扩展 schema、PNG、有界输出、恢复登记和 abort 清理;
  • smoke:真实 broker/Job 生命周期,以及 WinVer 的 GetDlgItem(IDOK) child 点击和 HTCLOSE 非客户区关闭。

发布通过 prepublishOnly 强制运行全量测试;内部测试源码不进入 npm 包。

已知限制

  • 部分 DirectX、OpenGL、Vulkan、Chromium GPU 或受保护窗口不支持 PrintWindow
  • DirectInput / GetAsyncKeyState 程序可能不响应窗口消息;
  • 目标显式使用 Job breakaway 或系统级服务代理时可能超出当前 Job;
  • 高完整性或反作弊程序可能拒绝窗口消息;
  • 本扩展不是通用 computer-use,也不提供 OCR 或 UIA。

License

MIT