pi-subagent-permission-compat0.1.0
Parent-session compatibility and cwd permission checks for almost any Pi subagent extension with @gotgenes/pi-permission-system
Untested on omp
This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.
Reports 0
No reports yet.
Readme
pi-subagent-permission-compat
English | 简体中文
一个面向第三方子智能体(subagent)扩展的 Pi Coding Agent 兼容性补丁包,提供两项彼此独立的能力:
- 父会话环境兼容 —— 为根会话进程写入
PI_SUBAGENT_PARENT_SESSION,使继承该环境的子智能体子进程能够将权限询问回传到父会话。 - 子智能体 cwd 防护 —— 检查子智能体工具调用输入中的
cwd值,当某个值与当前工作目录不一致时,请求一次性批准。
权限扩展兼容性
- 本扩展用于兼容
@gotgenes/pi-permission-system:它会写入上述PI_SUBAGENT_PARENT_SESSION变量。详见其子智能体集成文档。 - 简言之,对于未自行遵守该约定的子智能体扩展,本扩展提供兼容性补丁。
- 本包不安装、不导入、也不查询该权限扩展,cwd 防护也不以其为前提。
- 只有该权限扩展自身已安装并启用时,这种配合才会实际生效。
两项能力始终开启且无需配置:本包不新增任何命令、工具、配置文件或持久化规则。
功能
1. 父会话环境兼容
在 session_start 时,如果当前进程是根会话,扩展会写入:
PI_SUBAGENT_PARENT_SESSION=<当前会话 ID>
继承该环境的子进程据此可以定位父会话。
出现以下任一情况时跳过写入:
- 环境中已存在第三方子智能体标记,说明当前进程本身就是子智能体子进程。
- 环境中已声明父会话。
该值会在 session_shutdown(例如 /new、/resume、fork 或 /reload)时移除,避免会话切换后残留旧会话 ID。只有本扩展写入的值才会被移除;由其它组件设置或改写过的值保持不变。
确切的常量清单见可识别的环境变量。
2. 子智能体 cwd 防护
工具名中包含 subagent、delegate、spawn 或 agent(不区分大小写)的工具调用会被检查,输入树中任意位置发现的每个 cwd 字段都会被判定:
cwd 值 |
结果 |
|---|---|
缺失、null 或 "" |
直接放行 |
| 与当前目录完全相同的非空字符串 | 直接放行 |
| 与当前目录不同的非空字符串 | 弹出批准提示(Deny / Allow once) |
| 其它类型(数字、布尔值、对象、数组等) | 弹出批准提示(Deny / Allow once) |
| 无法安全扫描的输入 | 硬性拦截,用户无法批准 |
行为说明:
- 比较方式为原始字符串严格相等:工具输入与当前目录均不做 trim、归一化或改写。详见注意事项与限制。
- 一次提示覆盖整个工具调用,并列出所有发现的
cwd,包括嵌套位置,例如$["tasks"][0]["cwd"]。 - 批准仅对当次调用有效。不写入任何规则、不持久化,因此下次相同调用仍会再次询问。
- 只有精确选择
Allow once才算批准。选择Deny、取消提示、提示被关闭、返回未知响应或提示本身出错,都会拦截该调用。 - 没有交互 UI 时(print/JSON 模式,或无 UI 的子智能体),任何 ask 都会直接拦截而不弹窗。
- 批量或链式子智能体参数会作为一个调用整体判定:只要有一个
cwd未获批准,整个调用即被拦截。
安装
作为 Pi 包安装:
# 从 npm 安装
pi install npm:pi-subagent-permission-compat
# 从本 GitHub 仓库安装
pi install git:github.com/gszj2018/pi-subagent-permission-compat
使用
安装后两项功能即自动生效,无需按会话启用,也无需任何配置。
- 父会话环境兼容 —— 无需配置。若同时使用权限扩展,参见上文说明。
- 子智能体 cwd 防护 —— 无需配置。在交互式会话中,若子智能体工具调用使用的工作目录不同,会逐次询问,由你选择
Allow once或Deny。
可识别的环境变量
确切的变量列表由 extensions/parent-session-env.ts 中导出的常量定义:
THIRD_PARTY_SUBAGENT_ENV_HINTS—— 第三方子智能体扩展在子进程内写入的标记,任一项存在即视为子智能体子进程并跳过写入。SUBAGENT_PARENT_SESSION_ENV_CANDIDATES—— 已携带父会话声明的变量,任一项存在时本扩展不改动环境。PARENT_SESSION_ENV_VAR—— 本扩展唯一写入的变量。
"存在"指变量已被定义:空字符串、空白、"0"、"false" 都视为已设置,因此既有声明始终优先,本扩展不会改写它们。
如果宿主提供的会话 ID 为空白等不可用值,扩展会给出警告通知且不写入变量,cwd 防护继续正常工作。
注意事项与限制
- cwd 防护不是沙箱。它只检查当次工具调用输入中可见的
cwd字段,无法限制子智能体后续的行为。 - 工具名采用宽松匹配。名称中仅含
agent的无关工具也可能被检查,而名称不含这些关键字的子智能体启动工具则不会被检查。 - 智能体配置中的默认工作目录、工具内部创建的 worktree、后续目录变更以及包装器内部的调用均不在覆盖范围内。
- 比较是原始字符串严格相等,而不是"相同真实目录"。大小写差异、尾部分隔符或重复分隔符、
./..段、反斜杠与斜杠差异、首尾空白、相对与绝对写法都会触发提示而不会被自动放行;link/..这类路径也不会被静默接受。若两侧字节完全相同,即使是非规范字符串也会放行。 cwd缺失、为null或""时按设计放行。这是便利性处理,不能证明调用方确实使用了当前目录。- 无法安全扫描的输入——嵌套超过 10 层容器、不是普通 JSON 对象或数组的容器、异常的数组键或不可读成员——一律硬性拦截,用户无法批准。
- 没有交互 UI 时(print/JSON 模式或无 UI 的子智能体)不会弹出询问,而是直接拦截;本扩展没有其它批准途径。
- 批准是一次性的,且仅存在于本扩展内:不在会话内缓存、不向其它扩展共享。其它扩展仍可能拒绝同一个调用。
- 环境写入只覆盖继承环境的子进程(例如直接
spawn/fork)。替换过环境的进程、常驻守护进程、远程启动,以及共享同一process.env的进程内子智能体均不在覆盖范围内。
开发
# 安装依赖
npm install
# 运行测试
npm test
# 类型检查
npm run typecheck
如需在本地开发时直接加载扩展(无需打包),请在仓库根目录运行:
pi -e ./extensions/index.ts
项目使用 TypeScript 编写,测试采用 Node.js 内置测试运行器。
项目结构
pi-subagent-permission-compat/
├── extensions/
│ ├── index.ts # 扩展入口(仅做组合装配)
│ ├── extension-meta.ts # 公共扩展标识
│ ├── feature-parent-session.ts # 父会话生命周期注册
│ ├── feature-cwd-guard.ts # 工具调用注册与批准流程
│ ├── parent-session-env.ts # 环境检测与 owned-value 清理
│ ├── cwd-ident.ts # 工具名匹配
│ ├── cwd-inspection.ts # cwd 收集
│ ├── cwd-guard.ts # 逐值判定与拦截决策
│ ├── cwd-prompt.ts # 提示格式化与 select 批准
│ └── diagnostics.ts # 安全的值/错误展示辅助
└── tests/ # 单元测试与集成测试