{"_id":"@buddhilive/dsh-subprocess-local","name":"@buddhilive/dsh-subprocess-local","dist-tags":{"alpha":"0.1.2-alpha.3","latest":"0.1.2-alpha.3"},"versions":{"0.1.2-alpha.3":{"name":"@buddhilive/dsh-subprocess-local","description":"Local-subprocess implementation of the DeepSeek Harness subprocess seam","version":"0.1.2-alpha.3","publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/Buddhilive/buddhi-ai-harness.git","directory":"packages/subprocess/subprocess-local"},"type":"module","main":"lib/index.js","types":"lib/types/index.d.ts","exports":{".":{"types":"./lib/types/index.d.ts","default":"./lib/index.js"},"./invariant":{"types":"./lib/types/invariant.d.ts","default":"./lib/invariant.js"},"./src/*":"./src/*","./package.json":"./package.json"},"license":"MIT","peerDependencies":{"@buddhilive/dsh-subprocess":"^0.1.2-alpha.3","@buddhilive/dsh-timeout":"^0.1.2-alpha.3","@deepseek-ai/cordis":"^4.0.2","@buddhilive/dsh-invariants":"^0.1.2-alpha.3"},"dependencies":{"koffi":"^3.1.0","node-pty":"1.2.0-beta.15"},"devDependencies":{"@buddhilive/dsh-loader-smoke":"^0.1.2-alpha.3","@buddhilive/dsh-invariants":"^0.1.2-alpha.3","@buddhilive/dsh-timeout":"^0.1.2-alpha.3","@buddhilive/dsh-subprocess":"^0.1.2-alpha.3","@deepseek-ai/cordis":"^4.0.2"},"scripts":{"postinstall":"node scripts/ensure-spawn-helper.mjs"},"_id":"@buddhilive/dsh-subprocess-local@0.1.2-alpha.3","bugs":{"url":"https://github.com/Buddhilive/buddhi-ai-harness/issues"},"homepage":"https://github.com/Buddhilive/buddhi-ai-harness#readme","_integrity":"sha512-/Y/dd/isfmG+xGlGKUvsOXkILI92fjRqkr/Wm3nH6J6frHdraeyA6vTOL016MoHmFMswy93fY85Y4ioylxDKcw==","_resolved":"C:\\DevDojo\\Buddhi\\buddhi-ai-harness\\dist\\npm\\buddhilive-dsh-subprocess-local-0.1.2-alpha.3.tgz","_from":"file:C:/DevDojo/Buddhi/buddhi-ai-harness/dist/npm/buddhilive-dsh-subprocess-local-0.1.2-alpha.3.tgz","_nodeVersion":"24.13.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-/Y/dd/isfmG+xGlGKUvsOXkILI92fjRqkr/Wm3nH6J6frHdraeyA6vTOL016MoHmFMswy93fY85Y4ioylxDKcw==","shasum":"a553c9468dc33cd8a84bd9f791c99ca85a422252","tarball":"https://registry.npmjs.org/@buddhilive/dsh-subprocess-local/-/dsh-subprocess-local-0.1.2-alpha.3.tgz","fileCount":14,"unpackedSize":97752,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIFfcHGh3K4THEn2aoumaZ+qz1zm1RRLEKHgvRY8NXmtLAiEAvbpZJVNGRY/mW4MeBu694Pcasw8YfuxBA5BpsCoOoeg="}]},"_npmUser":{"name":"buddhilive","email":"visitbudkavin@gmail.com"},"directories":{},"maintainers":[{"name":"buddhilive","email":"visitbudkavin@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/dsh-subprocess-local_0.1.2-alpha.3_1788165848620_0.9145363176875194"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-31T08:44:08.503Z","0.1.2-alpha.3":"2026-08-31T08:44:08.759Z","modified":"2026-08-31T08:44:08.964Z"},"maintainers":[{"name":"buddhilive","email":"visitbudkavin@gmail.com"}],"description":"Local-subprocess implementation of the DeepSeek Harness subprocess seam","homepage":"https://github.com/Buddhilive/buddhi-ai-harness#readme","repository":{"type":"git","url":"git+https://github.com/Buddhilive/buddhi-ai-harness.git","directory":"packages/subprocess/subprocess-local"},"bugs":{"url":"https://github.com/Buddhilive/buddhi-ai-harness/issues"},"license":"MIT","readme":"---\ndescription: \"面向部署方与维护者的子进程服务本地宿主提供方说明：在宿主机器上运行受管进程树与真实终端会话。\"\nkind: \"package-reference\"\n---\n\n# @buddhilive/dsh-subprocess-local\n\n[English](README.md) | 中文\n\n## 概述\n\n在需要于宿主机上运行子进程的组合中挂载 `dsh-subprocess-local`：它解析本地可执行文件、以显式 stdio 运行 detached 进程树，并通过 `node-pty` 提供真实终端会话。它没有任何配置，因此每项处置方式、限制、终端尺寸与宽限期都随 spawn 请求来自调用方能力 seam。输出收集在内存中保留一段有界尾部，并可选地用 spill 文件恢复完整流；子进程从清理后的环境起步；dispose（资源释放）会终止并等待每棵仍在运行的进程树退出。\n\n## 目录\n\n- [使用本包](#use-this-package)\n- [理解实现](#understand-the-implementation)\n- [进一步探索](#further-exploration)\n- [模型体验](#model-experience)\n- [已知限制与延期工作](#known-limitations-and-deferred-work)\n- [开发备注](#dev-note)\n\n-----\n\n<a id=\"use-this-package\"></a>\n## 使用本包\n\n把提供方与它的消费方挂载在同一组合中，并完全按子进程服务的规定启动进程；本包只决定这些进程在宿主机上如何运行。\n\n### 挂载提供方\n\n在与消费方相同的组合中加载本提供方。它没有任何配置字段：每项选择都随 spawn 请求到达，因此随部署变化的决策留在调用方的配置里。\n\n```yaml\n- name: '@buddhilive/dsh-subprocess-local'\n- name: '@buddhilive/dsh-bash-local'\n```\n\n### 解析可执行文件\n\n绝对可执行文件路径会被验证；裸名称根据清理后的 PATH 并以平台感知的可执行文件扩展名（Windows 上为 `.COM`/`.EXE`/`.BAT`/`.CMD`）解析。含分隔符的相对路径会被拒绝——请提供绝对路径或裸 PATH 名称——相对 PATH 条目从宿主进程 cwd 解析。\n\n### 收集输出\n\n收集模式在内存中保留一条流的最后 `maxBytes`——错误与最终结果通常聚集在末尾——并在配置了 `spill` 上限时把完整流追加到 OS 临时目录下每进程目录中的私有文件（`0700` 目录、`0600` 随机命名文件）。某条流大于 spill 上限时，会丢弃不完整的 spill，只返回带截断标记的尾部。读取基于偏移量且从不消费，因此后台读取与批量读取在退出前后都可以共存。\n\n### 运行终端会话\n\n`spawnTerminal` 分配真实 PTY 并桥接 UTF-8 文本；你可以检查当前前台进程组并向其发送信号，还可以等待一次 `terminate()`，让提供方仍可观察到的每个会话成员完全停稳。在 Linux 上，精确输入等待要求前台线程的 fd 0 标识 shell 的控制终端，且线程当前的 syscall 正在等待该 fd。如果内核拒绝 syscall 探测，提供方不会报告精确等待，而由上层 PTY 后端使用空闲推断；进程睡眠状态不能作为证据。在 Windows 上，SIGINT 以 Ctrl-C 输入写入投递，SIGTSTP 与 SIGHUP 不受支持，拆卸会通过进程表验证 shell 已终止，因为被外部终止的 shell 可能永远不会触发 PTY 退出通知。\n\n### 关闭行为\n\n正常 dispose 会终止每棵仍在运行的进程树与终端并等待其退出。在 JavaScript 可观察的宿主退出期间——直接 `process.exit()`、默认未捕获异常、默认未处理 rejection——同步最终清理会强制终止所有仍归本包所有的对象（对进程组发送 SIGKILL，Windows 上运行 `taskkill /T /F`），且不创建任何 Promise 或定时器。未处理的 `SIGTERM`/`SIGINT`/`SIGHUP`、`SIGKILL`、fatal OOM、native crash 与断电则需要外部 supervisor。\n\n### 可能出错的地方\n\n无法解析的可执行文件会以稳定的错误快速失败；从未启动成功的 spawn 会让 `done` reject。越过保留尾部的读取是 `lossy` 的，并在 spill 文件存在时指向它。脱离进程树或终端会话的 daemon 化后代可能比清理更长寿——见下文限制。\n\n-----\n\n<a id=\"understand-the-implementation\"></a>\n## 理解实现\n\n<details>\n<summary>实现细节——点击展开</summary>\n\n本节解释提供方背后的设计决策，并指出实现它们的代码位置；可观察行为已在[使用本包](#use-this-package)中说明。\n\n### 设计理念\n\n本提供方把进程树视为生命周期单元。POSIX 子进程以 detached 方式 spawn（拥有独立进程组），因此整棵进程树以负进程组 id 发送信号，并以直接子进程作为回退；Windows 通过 `taskkill /T` 按根 pid 终止。信号发送、升级与拆卸都以进程树存活状态为守卫，而非以直接子进程结算为准，因此拦截 TERM 的辅助进程无法在无人察觉的情况下比句柄更长寿。\n\n### 源码地图\n\n| 文件 | 职责 |\n|---|---|\n| [`src/index.ts`](src/index.ts) | 服务接线：存活句柄集合、dispose、宿主退出最终清理、可执行文件查找 |\n| [`src/spawn.ts`](src/spawn.ts) | 进程管道：detached spawn、保尾收集、spill 文件、升级、进程树退出观察器 |\n| [`src/terminal.ts`](src/terminal.ts) | `node-pty` 终端句柄：前台检查、会话清理、Windows 拆卸 |\n| [`src/process-inspector.ts`](src/process-inspector.ts) | POSIX 进程树与会话检查 |\n| [`src/windows-inspector.ts`](src/windows-inspector.ts) | 经 koffi 的 Windows Toolhelp32 进程表检查 |\n| [`src/invariant.ts`](src/invariant.ts) | 不变式伴生插件（无运行时不变式；约定归 seam 所有） |\n\n### 主流程\n\n一次 spawn 会构建清理后的子进程环境、启动 detached 进程、把收集器挂到收集模式的流上，然后返回句柄。`done` 在进程关闭后、经过一段有界管道排空宽限期才结算，因此继承了管道的存活后代无法无限期拖住结果；升级定时器在直接子进程结算后依然存活，使 SIGKILL 仍能到达进程树幸存者。终端清理按精确身份清扫后代、停止 shell、再次清扫，并通过进程表验证其已不存在。\n\n### 安全不变式\n\nspill 文件以 `0600` 权限、`O_EXCL` 与随机名称在 `0700` 每进程目录下创建，可抵御共享临时目录中的符号链接植入；最终关闭失败时不公布 spill 路径。进程身份携带启动时间，因此清理绝不会跟随 PID 复用。宿主退出最终清理不创建 Promise 或定时器，保留宿主退出码与诊断，分别包含每个目标的失败，也不会声称已经完全停稳。\n\n</details>\n\n-----\n\n<a id=\"further-exploration\"></a>\n## 进一步探索\n\n当提供方级约定不够用时阅读以下页面。它们从穷尽式类型参考逐步进入抽象约定，以及宿主机制背后的决策。\n\n- [子进程子系统](../../../docs/subsystems/subprocess.zh.md)——spawn spec、输出读取器、结果与完整的 `DSH_*` 环境。\n- [dsh-subprocess](../subprocess/README.zh.md)——本提供方实现的抽象约定。\n- [dsh-bash-local](../../shell/bash-local/README.zh.md)——最大的消费方及其请求的具体 stdio 形态。\n- [subprocess seam Agent Note](../../../.agents/notes/implemented/architecture/2026-07-26-subprocess-seam.zh.md)——进程部分为何成为独立的 seam。\n- [同步子进程退出清理](../../../.agents/notes/implemented/bug-fix/2026-08-11-synchronous-subprocess-exit-cleanup.zh.md)——宿主退出最终清理决策及其失败模式。\n\n-----\n\n<a id=\"model-experience\"></a>\n## 模型体验\n\n通过消费方 seam（例如 bash 执行器家族）间接影响，它们负责所 spawn 进程的输出与生命周期的全部面向模型渲染。\n\n#### KV Cache 影响\n\n不会直接导致 KV Cache 失效；请求前缀变更由上述消费方负责。\n\n## 已知限制与延期工作\n\n<a id=\"known-limitations-and-deferred-work\"></a>\n\n\n这些限制说明本提供方何时不合适，或何时需要特别的运维注意。它们是当前包约束，不是通用平台对比或任务积压。\n\n- **Windows 进程树支持仅为尽力而为**——终止经由 `taskkill /PID <pid> /T /F` 完成，所有结果都被就地吸收（进程树已不存在、竞态、二进制缺失），存活探测则回退到直接子进程边界。\n- **Windows 终端信号是控制台级的**——SIGINT 以 `\\x03` Ctrl-C 输入写入投递，由 conhost 转为控制台级 CTRL_C 事件；SIGTSTP 与 SIGHUP 因不可用而被拒绝；不带 `/F` 的 `taskkill` 无法终止控制台进程，因此拆卸的 TERM 档是 `/F` 升级前的宽限等待。\n- **守护化的终端后代仍可能逃出可观察边界**——在 macOS 上，子进程如果在任何前台检查快照之前重新设定父进程，将无法再从 PTY 根进程发现；在 Linux 上，调用 `setsid` 的子进程会同时离开进程树与自有终端会话；本提供方不新增持续进程表监视器。\n- **进程内清理要求退出阶段仍能执行 JavaScript**——直接 `process.exit()`、默认未捕获异常和默认未处理 rejection 会发出 Node 同步 `exit` 事件；未处理的 `SIGTERM`、`SIGINT` 或 `SIGHUP`、`SIGKILL`、fatal OOM、`process.abort()`、native crash 与断电，都需要外部 supervisor、容器 init 或等价的 OS 所有者负责。\n- **凭据清除依赖名称启发式规则**——只匹配 `*KEY*`/`*PASSWORD*`/`*SECRET*`/`*TOKEN*`；名称不同的 secret（例如 `*PASSPHRASE*`）会继续传递，对误删变量引入白名单属于已记录的后续工作。\n- **不会删除已完成的 spill 文件**——有界的完整输出恢复文件（以及每进程私有 spill 目录）会在 OS tmpdir 下累积，直到外部机制进行清理。\n\n<a id=\"dev-note\"></a>\n### 开发备注\n\n<details>\n<summary>维护者的工作上下文——点击展开</summary>\n\n无。\n\n</details>\n","readmeFilename":"README.zh.md","_rev":"1-f5c06ab218b4e2f0ab2ff14f4c296a64"}