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

@unieai/uad-subprocess-ssh

v0.1.21

Published

The subprocess seam placed on a machine reached over SSH

Readme

@unieai/uad-subprocess-ssh

English | 中文

subprocess 接縫,放在一台透過 SSH 連到的機器上。掛載時取代 subprocess-local,於是 harness 執行的每一個指令——Bash 工具的執行器、language server、搜尋——都移到那台機器上,而它們全都不知道這件事。

是改寫,不是重寫

這個 provider 繼承本機的那個,把每一份 spec 轉成同一個指令的 ssh 呼叫。改寫底下的一切都是本機 provider 的,已經寫好也測好:分離的行程樹、帶位移讀取器與溢出檔的 collect 模式、SIGTERM–緩衝–SIGKILL 的升級、釋放、以及行程結束時的收尾。在這裡,那套機制管的是代表遠端指令的那個 ssh 客戶端行程。

有兩件事在本機的意義必須重新指向:

  • 工作目錄是遠端機器上的。客戶端本身跑在 harness 使用者的家目錄,因為 spec 的 cwd 指的路徑通常不會同時存在於兩台機器上。
  • 環境變數屬於遠端指令,所以它們寫在命令列裡送過去,而不是給客戶端。客戶端自己需要的——HOME、PATH、agent 驗證用的 SSH_AUTH_SOCK——來自本機 provider 自己那份已清洗的父環境。

遠端行程的生命週期

遠端指令活得比啟動它的連線久。 對真實伺服器實測:殺掉本機客戶端之後,遠端指令仍在執行——有沒有配置終端機都一樣;而一個忽略 SIGHUP 的指令,兩種情況下都活著。

所以連線不是行程的把手,pid 檔才是。遠端 shell 先記下自己的 pid 再 exec——pid 仍然是指令自己的——而終止一次執行,是開第二條(重用連線,所以很便宜)連線去對那個 pid 的行程群組送訊號。群組正是它成為整棵樹終止的原因:在 sshd 底下,指令 shell 本身就是群組的 leader,所以一個訊號就能打到指令與它啟動的一切。沒有群組可打時,退回單一 pid。

終止會做兩邊,而且兩邊都需要:結束客戶端會釋放呼叫端的串流並讓結果落地,而遠端的訊號才是真正停下工作的那一半。

客戶端結束代表什麼,取決於那是誰的結束。 遠端指令自己產生的狀態碼——255 以外的任何值——代表指令跑完了,它的 pid 檔只是殘留物,該清掉。而 255、或是被訊號終止,是客戶端結束,這對遠端行程什麼也沒說:活得比自己的連線久,正是遠端行程會做的事。這時候刪掉 pid 檔,等於把「仍在執行中的工作」的唯一把手丟掉,所以連線遺失會去終止那次遠端執行,而不是把它忘掉。

控制指令自己的離開狀態也基於同樣理由要檢查。遠端腳本一律以 exit 0 結尾,所以其他任何值都來自客戶端——被別處關掉的重用主連線、被拒絕的連線——把那當成「做完了」,會讓那台機器繼續跑著沒有人在看的工作。每一個終止步驟因此會重試一次。

終端機

終端機是一個跑著 ssh -tt 的本機 PTY,由它承載位元組、視窗大小與整個 session 的生命週期。而終端機也正是 -tt 在這裡站得住腳的原因:那些會弄壞「被收集的指令輸出」的換行轉換與串流合併,恰好是終端機想要的。

所有關於這個 session 的問題則改在那台機器上回答,因為本機 PTY 的前景行程永遠是 ssh:

  • 前景是什麼,來自遠端終端機自己的 tpgid,所以它會跟著每一次 fg、每一條管線、每一層巢狀程式走,harness 一件都不用追蹤。session 的 wrapper 在變成 shell 之前先記下自己的終端機(tty),第二條連線才知道要問誰。
  • 訊號送到遠端的前景群組。 對本機 PTY 送訊號會打到 ssh 客戶端,在使用者只想中斷一個指令的時候把整個 session 結束掉。
  • 結束 session 會對遠端整個 SESSION 的每一個成員送訊號,不只是 shell 的行程群組。job control 正是終端機存在的意義:sleep 90 & 跑在自己的群組裡,只針對群組的終止會留下它繼續執行,而已經沒有人在看它了。
  • shell 是不是在等輸入,讀的是前景群組的核心等待點(wchan)。本機 provider 用的那個更強的證據——被阻擋的 syscall 與它的檔案描述子——在這裡拿不到:/proc/<pid>/syscall 需要 ptrace 等級的權限,而預設 kernel.yama.ptrace_scope=1 的機器會拒絕第二條 SSH session 的讀取。等待點沒有名字或認不得時,這裡回報「不知道」,而不是用猜的。

它拒絕什麼

相對的執行檔路徑,與本機 provider 完全一致:它要解析的基準點並不存在,而跨過一個網路並不會生出一個。

Model Experience

間接的,透過建立在 ctx.subprocess 之上的工具——首先是 Bash 執行器——由它們擁有所有面向模型的契約;此套件自己不註冊任何 tool、prompt 或 schema,只改變它們的工作發生在哪一台機器上。

KV Cache effect

無。這裡不產生任何 prompt 片段、工具定義或 context 條目。

已知限制與未完成項目

  • 「正在等輸入」是證據,不是證明。 這裡認得的核心等待點(n_tty_read、read_chan、wait_woken、ttyin)涵蓋目前的 Linux 與 BSD;拼法不同的核心會回報「不知道」,消費端的就緒判斷就退回以沉默為依據。特別是 wait_woken 是個通用等待點,所以一個因為別的原因阻擋住的前景群組也可能被讀成「在等輸入」。
  • 前景檢視要付一次往返,而就緒輪詢會反覆問。連線重用讓每一次都很便宜,但線路慢的機器回答輪詢就是比本機讀 /proc 慢。
  • 遠端必須是 POSIX 類的登入 shell,這一點記在機器名冊。
  • 一次掛載一台機器。 alias 是設定,所以這個 provider 的每一次掛載,指令都跑在同一台機器上。同時要好幾台,是呼叫端的組裝——execution-router 為每台機器建一個 runtime 再從中挑一個——而那個呼叫端是直接建構這個類別的,這也是機器名冊除了注入之外還能從建構子交進來的原因:用 new 建出來的 provider 坐在一個什麼都沒宣告的 context 上,在那裡讀 ctx.ssh 會被拒絕,而不是被回答。
  • exitCode 255 是有歧義的。 它既是 OpenSSH 自己的失敗碼,也是被終止的執行會回報的值,所以呼叫端無法只憑狀態碼區分「連線失敗」與「遠端指令被殺掉」。