状态:实验性实现讨论 / Draft,Unreleased。 本文介绍实验实现的设计、接口和工程取舍。它尚未完成生产验收,不是发布候选或完整安全认证。
本提案把三个容易混为一谈的问题拆开:
- 没有可靠的 Windows Git Bash 围栏时怎么办? 当前实验选择 fail-closed,不再“标注无围栏后继续”。
- 必须精确保留 Windows 原生参数、明确解码原生输出时怎么办? 新增独立 typed argv 入口,复用 Core 托管执行。
- 原生 Node API 如何使用模型得到的 MSYS 路径? 新增完整值运行时转换,不再把源码字符串猜测当作可靠机制。
另补 Agent 路由指引,让上述机制不是仅存在于 README 中的“需要用户手动教模型”的能力。
维护者已在 PR #26 裁决接受 fail-closed 方向,要求默认开启且可实时关闭的行 Config 开关。正式验收门槛仍未完成。
在 Bash 启动原生程序时,MSYS 可能把 /all、/c 当作路径。单命令 EXCL、双斜杠等只适用于确定场景;EXCL 按前缀匹配,排除 /c 也可能影响真正的 /c/... 文件参数。
实验不全局设置 MSYS2_ARG_CONV_EXCL=*,不重写 Bash command,不猜某个字符串究竟是 option、路径还是程序源码。
UTF-8 捕获不等于原生程序输出 UTF-8。locale 变量不保证改变其代码页;同一调用、甚至同一流可以混合编码。没有替换字符也不能证明转码正确。
实验只支持显式已知编码。未知同流混编码不能普遍可靠解码;损坏后的字符串不能普遍还原原始字节。
legacy codePaths 无法识别 /c/users 是路径还是路由数据,也不能可靠处理所有动态表达式。它的默认值和既有兼容机制没有在本提案中移除。
显式 helper 是完整值接口,不是“更聪明的全程序重写器”。处理路径状业务数据时建议关闭 codePaths;普通工具路径参数翻译不因此关闭。
本提案没有修复 OS 围栏。匹配研究纠正了旧泛化:现代 MSYS cygheap 使用 VirtualAlloc,signal pipe 使用显式 SD;实际 Core 已补 TokenDefaultDacl。不能据此声称“再补默认 DACL 就解决”或“所有未来方案都无解”。
IPC/Token/AppContainer/VM 路线仍需隔离环境的真实正负权限验证;这些 OS 隔离机制不属于本提案的实现范围。
| 项目 | 旧行为或既有原则 | 当前实验 |
|---|---|---|
| Windows 受限自有 Bash | 无围栏执行并标注 unconfined | RO/WW/缺失策略在执行前拒绝 |
| 默认 Shell | Git for Windows Bash | 保持;原生入口是显式补充,不是隐式 fallback |
| root PowerShell/provider | route B 不替换 | 保持 |
| 原生参数 | 通过 Bash/MSYS,可能转换 | typed native 入口只转换标明的路径 |
| Node 路径 | 字面量尽力重写 | 可显式转换运行时完整值;legacy 默认未改 |
| 编码 | 原有 UTF-8 捕获边界 | 新入口逐流显式编码,默认 utf8/replace |
| 设置/界面 | 现有 Config/UI | experimentalNative volatile 布尔,默认 true,同卡实时编辑 |
| 同装 dsh-ops 的受限会话 | 本插件 bash fail-closed;ops_bash 只发 full-access | 不是零命令工具:ops_* 在场时补位逻辑不遮蔽 pwsh(inlineNeeds 的 hidePwsh 短路,宿主 pwsh 故事保留),官方执行器带真围栏可直接跑命令;bash 要回来需切 danger-full-access 或关 experimentalNative(后者同时放开 ops_bash) |
运行时开关: 设置 → 插件 → dsh-gitbash-shell →「实验原生执行 / fail-closed」,权威值是 gitbash-shell 行 Config 的 experimentalNative,默认 true(包括旧配置缺键)。开启时受限/未确定 Windows Bash 拒绝,两个 companions 在能力可用且不冲突时注册。关闭时实时注销两个工具(旧 SDK 引用也拒绝),Bash 恢复旧版明确标注 enforcement: 'unconfined' 的受限执行并一次性日志告知;未确定策略保持旧版宿主委派。关闭不提供真实围栏,shell 文件写入限制不执行;官方文件工具策略始终独立。
变更作用于现有会话后续调用,无需重启,不终止已开始的后台 producer。native 在准备入口、异步准备后、执行入口及最终 spawn 重读开关;已关闭则不得开始新进程。重新开启恢复工具注册与拒绝机制。posixPaths、codePaths、subagentDialect 独立,不改变安全开关。拒绝错误说明设置关闭路径及用户在会话访问模式控件选择 danger-full-access 的路径,Agent 不得自行调整。
21 份词典均已补齐开关本地化,保留工具名、UNCONFINED 和 danger-full-access 的事实,维护者可继续审阅译文。
| 意图 | 选择 | 禁止的理解 |
|---|---|---|
| Shell 脚本、管道、重定向、globbing、POSIX utilities | bash |
不能把权限拒绝当作改用另一个执行入口的许可 |
Windows .exe 精确 literal argv,或已知逐流编码 |
可见的 gitbash_native |
不是 shell source,也不是通用脚本包装器 |
| 完整 MSYS 路径交给原生 Node fs/path | 可见的 gitbash_to_native_path |
不转换路由、搜索数据、command/code;不授文件权限 |
| 真正 PowerShell cmdlet/服务/WMI | 可见且开关允许的 pwsh |
不调用隐藏名称、不把 PowerShell 嵌进 Bash 绕行 |
| 权限/访问拒绝 | 停止并说明 | 不自动换模式、解释器、文件工具或 Node I/O |
| 显示/解码失败 | 核对 producer exit 与输出事实 | 不盲目重复有副作用的命令 |
路由生成在提示组装按实际工具面生成,不只看开关意图。自有提示块可替换、幂等;重组后不残留失效建议。方言/子代理方言关闭不关闭安全选路指引。
PTC 中直调 schema 可只有 run_code:该描述解释如何选择已提供 SDK binding,具体 native/path binding 的描述进入 tools:sdk。没有把 SDK 声明误当成可直调工具,也不编造缺失名称。
已验证提示送达,不等于已验证 LLM 必然正确决策。 当前没有真实模型自主选工具评测。
agent-owned tool scope
├─ bash → private GitBashSandboxExecutor → existing Core lifecycle/provider
├─ gitbash_to_native_path → fresh shared translator → native_path(无I/O)
└─ gitbash_native
├─ 每调用解析真实 standing policy / 严格请求校验
├─ prepared capability(WeakMap;不是可伪造的 policy DTO)
├─ bounded preparation / trusted artifact owner
└─ per-operation scope(属于 agent,隔离 shell + subprocess)
└─ actual LocalBashExecutor.executeArgv
└─ private guarded provider facade
└─ actual managed provider + per-stream output adapter
对应:执行器、工具/Jobs/DTO、输出适配。
不改 root 服务条目,不另造 child_process runner/Jobs registry,不覆盖 private spawnSpec。新模块不静态导入宿主 peer;由既有 host resolution 通道注入真实模块。
策略门要求 Windows spec 明确为 danger-full-access;其他/缺失策略拒绝。工具层预检查位于工作目录准备、环境收集和 Jobs admission/promotion之前。
实际 host SandboxUnavailableError 能解析时保留结构化 SANDBOX_UNAVAILABLE;直接/旧调用者缺导出也必须拒绝,不能因此运行。非 Windows 的受限路径仍继承父后端。
不以部署 defaultMode 代替逐调用策略;准备、执行、目录 callback 前后、最终 spawn seam 重验真实 standing policy。Prepared request 只能由同一个 executor 产生,复制或跨 executor 不构成能力授权。
这只是本地 Windows danger-only 入口,不是 native restricted-token adapter;不支持模型传入 env、sandbox_permissions 或自动 escalation。
官方文件工具有独立 policy;helper 转换不扩大权限。minimal 持久 PTY、侧栏交互终端和其他插件执行器不因本门控获得围栏。历史 unconfined 渲染仍兼容旧记录,不授权新调用降级。
输入 { msys_path: string },成功值 { native_path: string }。复用共享 translator 与 fresh mount facts;无 fs I/O、存在性判断或 env seeding。
Windows-native/cwd-relative 值声明后可 passthrough;未知 POSIX mount、缺映射、空值、NUL、URL明确拒绝。msys_path/native_path避开旧参数/结果的自动路径字段翻译,避免转换前被改写或成功值回流。
PTC 程序示例,假设 inputPath 是已经取得的完整路径值:
const resolved = await tools.gitbash_to_native_path({ msys_path: inputPath });
const fs = await import('node:fs/promises');
return await fs.readFile(resolved.native_path, 'utf8');这不是绕过文件拒绝的方式;已发生拒绝必须停止。
| 字段 | 契约 |
|---|---|
| description | 必填、非空、NUL-free |
| executable | 必填 {kind:'path',value},可解析绝对 .exe;无 bare command |
| argv | 必填 typed 数组;literal 原值,path 显式转换/规范化;允许空 literal |
| cwd | 可选绝对 typed path;默认 agent workspace |
| entrypoint | native 默认;已知解释器需显式 interpreter |
| stdoutEncoding/stderrEncoding | utf8 默认,或 gbk/utf16le/raw;不支持 auto |
| errors | replace 默认,strict opt-in |
| timeoutMs | 正有限数,默认120000ms,上限600000ms |
| run_in_background | 仅能力允许时声明;与显式 timeoutMs 同时给出会拒绝 |
Native typed path 不支持相对值、变量/home展开;需要时先通过显式 helper取得可用绝对值。Windows 启动字段/path argv规范化反斜杠;literal /all、/c 等不经过 MSYS。
拒绝未知字段、model env、path-list env、隐式脚本、.cmd/.bat。当前限制4096个argv及保守Windows command-line预算。已知解释器名称检查是防误门,不是二进制鉴定;重命名/custom exe可有自己的语言。
Exact argv 指验证过的 Core/CRT/Node 语义,不承诺任意 cmd/非CRT parser 的 quoting。
只有已知 collect disposition {maxBytes,spill?:{maxBytes}} 转 raw pipe;未知/其他 disposition按原 provider契约委托。每 operation immutable config,stdout/stderr独立 decoder,只在 ingest解码。
- UTF8默认宽容替换,保留BOM;strict显式。
- Decoder能力在spawn前探测;unknown同流mixed选raw。
- 原字节产物与normalized UTF8产物分开;raw无可靠文本承诺。
- Reader为独立、非消费normalized UTF8 byte cursor;不是原编码byte游标,也不是Core Jobs全局游标。
- handle.done保留真实provider outcome/error身份;decode/storage问题只记facts,不伪造命令未执行。
- OutputCollector只使用公开push/snapshot/seal;不访问其私有spill字段。
| 字段 | 解释 |
|---|---|
| sourceComplete | 是否收到自然EOF;不能单独证明程序未被中止 |
| complete | 管线完整性;不承诺tail包含全文 |
| lossy/reliableText | 与尾缓存、解码、存储等损失合读,不是编码自动鉴定 |
| aborted | 取消/主动terminate/owner终止事实 |
| artifact.complete/capReached/error | 对该产物自身完整性、预算、存储错误判断 |
| rawBytes/rawCursor | 原流字节计数/游标 |
| decodedUtf8Bytes/decodedCursor | normalized UTF8计数/游标 |
Foreground DTO使用closed schemas;去undefined投影不放任unknown字段。无facts/投影失败是显式分支,不通过宽schema吞错。后台最终exit/facts进入现有Jobs文本source,不声称扩展Core Jobs结构化API。
准备阶段workspace/scope/plugin mount/artifact callback受同一取消/有界期限控制,剩余预算交Core;后台/onExpiry:none只限制准备,已handoff producer不会被准备timer杀死。
operation-owned AbortController统一caller cancel、explicit kill、ownerdispose;先记录cause再terminate。正常settlement后释放scope不能反向污染已完成facts。
输出end/error/close/abort/provider failure分别收尾;默认250ms有界drain,不无限等后代持有管道。不保证所有输出在短drain窗口内到达,未完整必须如实标注。
默认两流raw+decoded总磁盘8MiB、自有payload16MiB;含保守tail/copy/scratch预留。不是OS/RSS、provider buffer、caller副本或跨调用硬quota。
trusted owner在真实policy/校验后创建自有临时目录,不从model cwd建产物目录。Adapter不创建目录、chmod、删除或授权;文件有限wx创建。完成产物保留供晚reader读取,无自动purge承诺。晚callback结果不续spawn,不武断删除可能仍被引用的目录;归trusted retention owner。
复用registry.start/wait/read/kill/remove、processJob/processSources和owner/controller admission。Scope属于agent,不属于tool registration fiber;后台/promotion后卸载工具不提前销毁运行进程。
没有controller时明确拒绝,不以“admission失败后再运行前台”冒二次副作用风险。没有Jobs时为前台kill deadline;有Jobs时可timeout promotion。该差异需在正式用户体验验收中检查。
Windows own-bash agent scope挂两个companions,各自按 agent 创建注册模块。初始挂载、开关更新和 native Jobs 刷新共用注册入口:先注销自身注册,再检查当前 agent 的工具所有权;已有外部全局或同 agent 同名工具就让位。实际 Core 的 knownNames 包含隐藏工具,旧宿主回退 schemas 检查;检查失败也让位。外部所有者移除后,下次刷新可恢复。注册异常只记录日志,不阻断另一个 companion 的更新。两工具必须确认 apply 已执行;scope 就绪与实际注册成功分别报告,关闭或让位时不会报告注册成功。Bash/native 共用可选目录读取,有服务走官方 ensure(错误不降级),无服务走旧 policy.workspaceRoot ?? session.header.cwd 接缝。缺native executor/OutputCollector公开能力不撤bash/path。新工具不加入minimal持久终端通道,不改变root PowerShell、market patch或preset id。
- 初版ownerdispose/direct kill虽quiet且无LATE,却错报completed/aborted:false/artifact.complete:true。独立固定sentinel反证后,operation cause与adapter terminate共同修正;正常cleanup反向用例确保不污染成功结果。
- trusted artifact callback初版可无限await;abort/deadline时0spawn但不返回。现准备阶段有界race,晚callback不恢复执行,保留资源责任明确。
- 初版facts空宽schema现closed DTO;跨模块termination枚举/三参callback曾不同步,已对齐并真实Core负向校验。
- 集成发现显式证据env未配置、路径夹具硬编码盘符/安装bootstrap;改test-only目录预载、动态盘符、宿主自身bootstrap,真实Node fs复跑通过。没有放宽产品断言掩盖失败。
详情见验证文档。失败观察用例退出0只表示复现成功,不能算修复通过。
- 接受 fail-closed,新增默认 true 的 volatile 开关,关闭恢复旧行为。
- Controller 缺失保持明确拒绝,不静默改前台重复执行。
- Artifact ownership/quota/retention 由插件层自管;跨调用 quota/purge 尚未实现,不宣称已验收。
- 长期跟踪(不阻塞本 PR):Core 将来开放 native typed argv、逐流 encoding、closed DTO 等对应公开 API 时,遵循官方优先纪律整体切换并退役插件私有实现。
- 同步上游:前置 PR #24 已合并;实验已 rebase 到上游 v0.39.4 的 main(v0.39.4 起
fastctxTools默认 OFF、新增 ops_* 互操作面),继承正式 v0.39.4 的兼容与激活验证;单装工具面在fastctxToolsOFF 下 companion 注册检测不受影响(tests/runtime-preview.mjs「companions mount on the single-install face with fastctxTools OFF」锁死设计文档 §10 语义)。 - 拆分评估:建议两步 review:① Bash fail-closed + 行 Config/UI/拒绝引导/回退;② native/path、逐流输出与可见性路由。唯一开关在第一步建立,第二步复用同一字段。当前保留完整 Draft/RFC,尚未另开子 PR。
- 转正式的四项门槛:真实 Agent 自主选路、生产 GUI(非 preview)、维护者 Windows 真机全量验证、非 CRT 解释器矩阵抽测。四项齐后才谈 ready for review → release。
- 真实Agent选工具评测、生产GUI/full apply、会话replay尚未验收。
- 真restricted-token/ACL/IPC/VM正负权限、PTY/SSH、任意非CRT/解释器quoting尚未验收。
- 真实disk exhaustion、吞吐/RSS峰值、跨任务DOS/自动purge尚未验收。
- 若未来Core提供受限native adapter,应如何探测启用而非偷换mode?
当前结论:接口机制与确定性隔离用例可讨论;不能据此宣布普遍乱码解决、Windows沙箱恢复或正式发布就绪。