@oldflag2333333/pi-subagent 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +171 -2
- package/README.zh-CN.md +172 -0
- package/docs/releasing.md +61 -0
- package/herdr-plugin/README.md +34 -0
- package/herdr-plugin/action.ts +19 -0
- package/herdr-plugin/herdr-plugin.toml +27 -0
- package/herdr-plugin/index.mjs +108 -0
- package/package.json +65 -4
- package/src/adapters/herdr.ts +155 -0
- package/src/adapters/index.ts +31 -0
- package/src/channel-monitor.ts +127 -0
- package/src/channel.ts +286 -0
- package/src/commands/clean-sub.ts +82 -0
- package/src/commands/sub.ts +39 -0
- package/src/inbox-state.ts +108 -0
- package/src/index.ts +45 -0
- package/src/main-context.ts +91 -0
- package/src/manual-context.ts +9 -0
- package/src/profiles/context.ts +27 -0
- package/src/profiles/launch-args.ts +21 -0
- package/src/profiles/loader.ts +325 -0
- package/src/profiles/mcp.ts +16 -0
- package/src/profiles/runtime.ts +102 -0
- package/src/profiles/system-prompt.ts +33 -0
- package/src/profiles/tool-selection.ts +21 -0
- package/src/profiles/tool-sources.ts +49 -0
- package/src/profiles/types.ts +37 -0
- package/src/run-manager.ts +442 -0
- package/src/sessions.ts +50 -0
- package/src/talk-delivery.ts +73 -0
- package/src/talk-message.ts +32 -0
- package/src/talk-render.ts +18 -0
- package/src/tools/main.ts +299 -0
- package/src/tools/sub.ts +215 -0
- package/src/types.ts +111 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Facets contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,172 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Pi Subagent
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
English | [简体中文](README.zh-CN.md)
|
|
4
|
+
|
|
5
|
+
Give Pi reusable specialists for code review, research, and other focused tasks. Each specialist runs in its own Herdr tab and reports back to your main conversation, without inheriting its chat history.
|
|
6
|
+
|
|
7
|
+
A **profile** defines a specialist's instructions, tools, and optional skills or model. You can invoke it yourself or let your main Pi delegate work to it.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
You need **Node.js 22.19+**, **[Pi](https://pi.dev) 1.0.4+**, and **Herdr**. To launch specialists, run Pi inside a Herdr workspace with the `herdr` command available.
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pi install npm:@oldflag2333333/pi-subagent
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Restart Pi or run `/reload`. Pi Subagent uses your existing Pi provider credentials; make sure Pi can already run a normal conversation.
|
|
18
|
+
|
|
19
|
+
To update later:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pi update npm:@oldflag2333333/pi-subagent
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Restart Pi or run `/reload` after updating.
|
|
26
|
+
|
|
27
|
+
## Try it: a code reviewer
|
|
28
|
+
|
|
29
|
+
Pi Subagent ships without built-in profiles. Create your first one:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
mkdir -p ~/.pi/agent/subagent/profiles/reviewer
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Save this as `~/.pi/agent/subagent/profiles/reviewer/config.json`:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"version": 1,
|
|
40
|
+
"name": "reviewer",
|
|
41
|
+
"description": "Review code for bugs and missing tests without modifying files.",
|
|
42
|
+
"tools": ["read", "grep", "find", "ls"]
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Save this beside it as `instructions.md`:
|
|
47
|
+
|
|
48
|
+
```markdown
|
|
49
|
+
Review the requested code for bugs, regressions, and missing tests.
|
|
50
|
+
Do not modify files. Report actionable findings with file paths and
|
|
51
|
+
line numbers. If nothing stands out, say so and note any testing gaps.
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
In Pi, run `/reload`, then:
|
|
55
|
+
|
|
56
|
+
```text
|
|
57
|
+
/sub:reviewer Review the authentication code in src/auth.
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Replace `src/auth` with a path in your project. The reviewer opens in a separate Herdr tab and sends its findings back to your main conversation. You can keep working while it runs.
|
|
61
|
+
|
|
62
|
+
Or ask your main Pi to delegate:
|
|
63
|
+
|
|
64
|
+
```text
|
|
65
|
+
Ask the reviewer profile to review src/auth for bugs and missing tests.
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Everyday use
|
|
69
|
+
|
|
70
|
+
| What you want | How to do it |
|
|
71
|
+
| --- | --- |
|
|
72
|
+
| See available profiles or configuration errors | `/profiles` |
|
|
73
|
+
| Start a specialist or send it another task | `/sub:reviewer <task>` |
|
|
74
|
+
| Let Pi choose a specialist | Ask Pi to delegate the task to an appropriate profile |
|
|
75
|
+
| Check progress | Ask Pi to list its Subs, or open the specialist's Herdr tab |
|
|
76
|
+
| Stop its current task without closing it | Ask Pi to interrupt the Sub |
|
|
77
|
+
| Finish with a specialist | Ask Pi to close the Sub, or close its Herdr tab |
|
|
78
|
+
| Remove communication files left by deleted Main sessions | `/clean-sub` |
|
|
79
|
+
|
|
80
|
+
Within the same Main session, repeated `/sub:reviewer` commands reuse that profile's open Sub. If it is busy, your next task is queued. Finishing a task does not automatically close the tab.
|
|
81
|
+
|
|
82
|
+
The **Sub-agents** list shows only assistants created by the current Main: all **Open** Subs (including idle or unknown status) and **Resumable** persistent sessions confirmed closed with saved files still available. Other Main sessions and forks do not inherit them or gain access to resume them. Reloading or resuming the same Main preserves ownership.
|
|
83
|
+
|
|
84
|
+
To use a profile in your current Pi instead of opening a Sub, start Pi with:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
pi --profile reviewer
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Starting Pi without `--profile` leaves your existing tools, model, and skills unchanged.
|
|
91
|
+
|
|
92
|
+
## Customize a profile
|
|
93
|
+
|
|
94
|
+
### Where profiles live
|
|
95
|
+
|
|
96
|
+
- **Personal:** `~/.pi/agent/subagent/profiles/<name>/`
|
|
97
|
+
- **Project:** `.pi/subagent/profiles/<name>/` in your project or an ancestor directory; loaded only when the project is trusted.
|
|
98
|
+
|
|
99
|
+
Each directory needs a `config.json`, with a `name` matching the directory name. A nearer project profile replaces a same-named ancestor or personal profile; settings are not merged. Legacy `<name>.json` profiles are also supported.
|
|
100
|
+
|
|
101
|
+
### Instructions
|
|
102
|
+
|
|
103
|
+
Write the role in `instructions.md` beside `config.json`. It takes precedence over an inline `"instructions": "..."` field; if the file is absent, the inline field is used instead. Instructions add to Pi's normal project context, rather than replacing it.
|
|
104
|
+
|
|
105
|
+
Instruction files must be non-empty and no longer than 65,536 characters. An invalid or unreadable file is reported as an error, not silently ignored.
|
|
106
|
+
|
|
107
|
+
Run `/reload` after editing profiles. Already-open Subs keep their launch configuration; close and reopen them to use changes.
|
|
108
|
+
|
|
109
|
+
### Optional settings
|
|
110
|
+
|
|
111
|
+
Add these fields to `config.json` as needed:
|
|
112
|
+
|
|
113
|
+
| Field | Use it to… |
|
|
114
|
+
| --- | --- |
|
|
115
|
+
| `"invocation": "manual"` | Allow only user commands such as `/sub:reviewer` to start this specialist. Default: `"both"`, allowing Pi delegation too. |
|
|
116
|
+
| `"sessionPersistence": "persistent"` | Save the Sub's conversation so it can be resumed after closing. Default: `"ephemeral"`, which keeps it only in memory. |
|
|
117
|
+
| `"model": "provider/model-id"` | Choose a model available in your Pi configuration. |
|
|
118
|
+
| `"thinkingLevel": "high"` | Request a thinking level supported by the selected model. |
|
|
119
|
+
| `"skills": ["skill-name", "./path/to/SKILL.md"]` | Include installed skills or paths relative to the profile. |
|
|
120
|
+
|
|
121
|
+
For a persistent specialist started with `/sub:reviewer`, invoking the command again from the same saved Main session resumes it after closure. A different Main session gets its own specialist. Manual-only profiles are not available for Pi to delegate on its own.
|
|
122
|
+
|
|
123
|
+
### Profile-specific skills
|
|
124
|
+
|
|
125
|
+
Put skills inside the profile directory to load them only when that profile is selected. No `skills` field is needed:
|
|
126
|
+
|
|
127
|
+
```text
|
|
128
|
+
reviewer/
|
|
129
|
+
├── config.json
|
|
130
|
+
├── instructions.md
|
|
131
|
+
└── skills/
|
|
132
|
+
└── code-review/
|
|
133
|
+
└── SKILL.md
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Delegation rules for your main Pi
|
|
137
|
+
|
|
138
|
+
Use `~/.pi/agent/subagent/MAIN.md` or a trusted project's `.pi/subagent/MAIN.md` for rules such as:
|
|
139
|
+
|
|
140
|
+
```markdown
|
|
141
|
+
Ask the reviewer profile to review code changes before declaring a task complete.
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
These instructions apply only to your main Pi, not to its Subs. Keep shared project rules in `AGENTS.md`.
|
|
145
|
+
|
|
146
|
+
## Clean up deleted sessions
|
|
147
|
+
|
|
148
|
+
Run `/clean-sub` to immediately delete runtime communication directories whose Main ID is no longer found among saved Pi sessions. It checks the default session store and the current session directory, always preserves the current Main, and creates no index. If session files cannot be read or their headers are invalid, cleanup stops rather than treating them as deleted.
|
|
149
|
+
|
|
150
|
+
Persistent Sub `.jsonl` files are **not deleted**; remove them manually through Pi's session picker. Profiles and global settings are untouched. The command does not close Herdr tabs. If you moved Main files or use other custom session directories, make them available in the scanned locations before cleaning.
|
|
151
|
+
|
|
152
|
+
## Things to know
|
|
153
|
+
|
|
154
|
+
- **Herdr is required for Subs.** There is no headless fallback. Up to four Subs can be open at once, and Subs cannot delegate further.
|
|
155
|
+
- **Profiles are not a sandbox.** Subs run as your OS user. A read-only role is not a filesystem permission boundary.
|
|
156
|
+
- **MCP follows Pi's normal configuration.** Profiles select non-MCP tools; they do not isolate or filter MCP servers. Custom non-MCP tools must come from extensions already loaded in Main.
|
|
157
|
+
- **Subs have separate conversations.** They receive their task, profile, and normal project context—not Main's chat history. Include the details they need in the task.
|
|
158
|
+
- **Reloading Main does not close Subs.** Close tabs you no longer need. Hard crashes may require manual cleanup.
|
|
159
|
+
|
|
160
|
+
If a profile is missing or fails to start, run `/profiles` first. Check its directory/name match, project trust, and any referenced tools or skills. If Herdr is unavailable, confirm Pi is running inside a Herdr workspace.
|
|
161
|
+
|
|
162
|
+
To hide or show Pi Subagent Subs in Herdr's Agents panel, see the optional [Herdr companion plugin](herdr-plugin/README.md).
|
|
163
|
+
|
|
164
|
+
## Development
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
npm install
|
|
168
|
+
npm run check
|
|
169
|
+
pi -e ./src/index.ts
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Maintainers: see [the release guide](docs/releasing.md) for CI and automatic npm publishing.
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# Pi Subagent
|
|
2
|
+
|
|
3
|
+
[English](README.md) | 简体中文
|
|
4
|
+
|
|
5
|
+
给 Pi 配置可复用的专用助手,用于代码审查、资料调研等任务。每个助手都在独立的 Herdr 标签页中工作,将结果发回主对话,不继承主对话的聊天记录。
|
|
6
|
+
|
|
7
|
+
一份 **profile(角色配置)** 定义助手的指令、工具,以及可选的技能和模型。你可以手动调用,也可以让主 Pi 自行委派任务。
|
|
8
|
+
|
|
9
|
+
## 安装
|
|
10
|
+
|
|
11
|
+
需要 **Node.js 22.19+**、**[Pi](https://pi.dev) 1.0.4+** 和 **Herdr**。启动助手时,Pi 必须运行在 Herdr 工作区中,并且能调用 `herdr` 命令。
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pi install npm:@oldflag2333333/pi-subagent
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
安装后重启 Pi,或执行 `/reload`。Pi Subagent 使用 Pi 已有的模型服务凭据,请先确认 Pi 能正常对话。
|
|
18
|
+
|
|
19
|
+
后续更新:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pi update npm:@oldflag2333333/pi-subagent
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
更新后同样需要重启 Pi 或执行 `/reload`。
|
|
26
|
+
|
|
27
|
+
## 快速上手:代码审查助手
|
|
28
|
+
|
|
29
|
+
Pi Subagent 不附带内置角色。先创建一个:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
mkdir -p ~/.pi/agent/subagent/profiles/reviewer
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
将以下内容保存为 `~/.pi/agent/subagent/profiles/reviewer/config.json`:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"version": 1,
|
|
40
|
+
"name": "reviewer",
|
|
41
|
+
"description": "检查代码中的缺陷和测试遗漏,不修改文件。",
|
|
42
|
+
"tools": ["read", "grep", "find", "ls"]
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
在同一目录下创建 `instructions.md`:
|
|
47
|
+
|
|
48
|
+
```markdown
|
|
49
|
+
检查指定代码中的缺陷、回归风险和测试遗漏。
|
|
50
|
+
不要修改文件。报告具体、可操作的问题,并附上文件路径和行号。
|
|
51
|
+
如果没有发现明显问题,请明确说明,并指出尚未验证的部分。
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
在 Pi 中执行 `/reload`,然后输入:
|
|
55
|
+
|
|
56
|
+
```text
|
|
57
|
+
/sub:reviewer 检查 src/auth 中的认证代码。
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
将 `src/auth` 替换为你项目中的路径。审查助手会在独立的 Herdr 标签页中启动,并将结果发回主对话。等待期间,你可以继续处理其他工作。
|
|
61
|
+
|
|
62
|
+
也可以直接让主 Pi 委派:
|
|
63
|
+
|
|
64
|
+
```text
|
|
65
|
+
让 reviewer 检查 src/auth 中的缺陷和测试遗漏。
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## 日常使用
|
|
69
|
+
|
|
70
|
+
| 你想做什么 | 操作方式 |
|
|
71
|
+
| --- | --- |
|
|
72
|
+
| 查看可用角色或配置错误 | `/profiles` |
|
|
73
|
+
| 启动助手,或给它追加任务 | `/sub:reviewer <任务>` |
|
|
74
|
+
| 让 Pi 选择助手 | 告诉 Pi 将任务委派给合适的角色 |
|
|
75
|
+
| 查看进度 | 让 Pi 列出子助手,或打开助手的 Herdr 标签页 |
|
|
76
|
+
| 停止当前任务,但保留助手会话 | 让 Pi 中断该子助手 |
|
|
77
|
+
| 结束使用 | 让 Pi 关闭子助手,或手动关闭其 Herdr 标签页 |
|
|
78
|
+
| 清理已删除 Main 遗留的通信文件 | `/clean-sub` |
|
|
79
|
+
|
|
80
|
+
在同一个主会话(Main)中,多次调用 `/sub:reviewer` 会复用该角色已打开的子助手(Sub)。如果它正在工作,新任务会排队。任务完成后,标签页不会自动关闭。
|
|
81
|
+
|
|
82
|
+
**Sub-agents(子助手)** 列表只显示当前 Main 创建的助手:**Open** 包含所有已打开的子助手,包括空闲或状态未知的;**Resumable** 包含已确认关闭、且保存文件仍存在的持久化会话。其他 Main 或分叉会话不会继承这些助手,也不能恢复它们。重载或恢复同一个 Main 则会保留关联。
|
|
83
|
+
|
|
84
|
+
如果想将角色应用到当前 Pi,而不是打开子助手,可以这样启动:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
pi --profile reviewer
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
不传入 `--profile` 时,Pi 原有的工具、模型和技能配置保持不变。
|
|
91
|
+
|
|
92
|
+
## 自定义角色
|
|
93
|
+
|
|
94
|
+
### 配置放在哪里
|
|
95
|
+
|
|
96
|
+
- **个人配置:** `~/.pi/agent/subagent/profiles/<name>/`
|
|
97
|
+
- **项目配置:** 项目或其上级目录中的 `.pi/subagent/profiles/<name>/`,仅在项目信任后加载。
|
|
98
|
+
|
|
99
|
+
每个目录都需要一份 `config.json`,其中的 `name` 必须与目录名一致。距离当前工作目录更近的项目配置会替换上级目录或个人目录中的同名角色,不会合并字段。旧式的 `<name>.json` 单文件配置仍然受支持。
|
|
100
|
+
|
|
101
|
+
### 角色指令
|
|
102
|
+
|
|
103
|
+
将角色说明写在 `config.json` 旁边的 `instructions.md` 中。它优先于 JSON 内的 `"instructions": "..."` 字段;文件不存在时才使用 JSON 字段。角色指令会补充 Pi 原有的项目上下文,而不是替换它。
|
|
104
|
+
|
|
105
|
+
指令文件不能为空,且不能超过 65,536 个字符。文件无效或无法读取时会报错,不会静默忽略。
|
|
106
|
+
|
|
107
|
+
修改角色后执行 `/reload`。已经打开的子助手保留启动时的配置,需要关闭并重新打开才能使用新配置。
|
|
108
|
+
|
|
109
|
+
### 可选设置
|
|
110
|
+
|
|
111
|
+
按需在 `config.json` 中添加:
|
|
112
|
+
|
|
113
|
+
| 字段 | 作用 |
|
|
114
|
+
| --- | --- |
|
|
115
|
+
| `"invocation": "manual"` | 只允许用户通过 `/sub:reviewer` 等命令启动。默认值为 `"both"`,也允许 Pi 自行委派。 |
|
|
116
|
+
| `"sessionPersistence": "persistent"` | 保存子助手对话,关闭后可以恢复。默认值为 `"ephemeral"`,仅保存在内存中。 |
|
|
117
|
+
| `"model": "provider/model-id"` | 指定 Pi 配置中可用的模型。 |
|
|
118
|
+
| `"thinkingLevel": "high"` | 请求所选模型支持的思考级别。 |
|
|
119
|
+
| `"skills": ["skill-name", "./path/to/SKILL.md"]` | 加载已安装的技能,或使用相对于角色配置的路径。 |
|
|
120
|
+
|
|
121
|
+
通过 `/sub:reviewer` 启动的持久化助手,在关闭后,可以从同一个已保存的主会话中再次执行该命令来恢复。不同的主会话各自拥有独立的助手。设置为手动调用的角色不能由 Pi 自行委派。
|
|
122
|
+
|
|
123
|
+
### 角色专属技能
|
|
124
|
+
|
|
125
|
+
将技能放在角色目录中,就只会在选中该角色时加载,无需填写 `skills` 字段:
|
|
126
|
+
|
|
127
|
+
```text
|
|
128
|
+
reviewer/
|
|
129
|
+
├── config.json
|
|
130
|
+
├── instructions.md
|
|
131
|
+
└── skills/
|
|
132
|
+
└── code-review/
|
|
133
|
+
└── SKILL.md
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### 主 Pi 的委派规则
|
|
137
|
+
|
|
138
|
+
在 `~/.pi/agent/subagent/MAIN.md` 或受信任项目的 `.pi/subagent/MAIN.md` 中写入规则,例如:
|
|
139
|
+
|
|
140
|
+
```markdown
|
|
141
|
+
宣布任务完成之前,让 reviewer 审查本次代码变更。
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
这些指令只适用于主 Pi,不会加载到子助手中。主 Pi 和子助手都需要遵守的项目规则应放在 `AGENTS.md` 中。
|
|
145
|
+
|
|
146
|
+
## 清理已删除会话的遗留文件
|
|
147
|
+
|
|
148
|
+
执行 `/clean-sub`,立即删除找不到对应 Main ID 的运行时通信目录。它检查 Pi 默认会话目录和当前会话目录,始终保留当前 Main,不新增索引文件。会话文件无法读取或文件头无效时会停止清理,不会将它们当作已删除。
|
|
149
|
+
|
|
150
|
+
持久化 Sub 的 `.jsonl` **不会自动删除**,请通过 Pi 的会话列表手动删除。角色配置和全局设置不受影响,命令也不会关闭 Herdr 标签页。如果移动过 Main 文件或使用其他自定义会话目录,请先确保这些会话位于扫描范围内,再执行清理。
|
|
151
|
+
|
|
152
|
+
## 使用须知
|
|
153
|
+
|
|
154
|
+
- **子助手依赖 Herdr。** 不支持无界面后台运行;最多同时打开四个子助手,子助手不能继续委派。
|
|
155
|
+
- **角色配置不是沙箱。** 子助手以你的系统用户身份运行,配置“只读角色”不等于限制文件系统权限。
|
|
156
|
+
- **MCP 沿用 Pi 的常规配置。** 角色只选择非 MCP 工具,不隔离或筛选 MCP 服务。自定义的非 MCP 工具必须来自主 Pi 已加载的扩展。
|
|
157
|
+
- **子助手拥有独立对话。** 它会收到任务、角色配置和常规项目上下文,但不会收到主对话的聊天记录。请在任务中提供必要信息。
|
|
158
|
+
- **重载主 Pi 不会关闭子助手。** 不再需要时请关闭标签页;异常崩溃后可能需要手动清理。
|
|
159
|
+
|
|
160
|
+
如果找不到角色或启动失败,先运行 `/profiles`,检查目录名与 `name` 是否一致、项目是否受信任,以及引用的工具和技能是否可用。如果提示 Herdr 不可用,请确认 Pi 正在 Herdr 工作区内运行。
|
|
161
|
+
|
|
162
|
+
如需在 Herdr 的 Agents 面板中隐藏或显示 Pi Subagent 子助手,可安装可选的 [Herdr 配套插件](herdr-plugin/README.md)(英文说明)。
|
|
163
|
+
|
|
164
|
+
## 开发
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
npm install
|
|
168
|
+
npm run check
|
|
169
|
+
pi -e ./src/index.ts
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
维护者可参考[发布指南](docs/releasing.md)(英文),了解 CI 和 npm 自动发布流程。
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Releasing Pi Subagent
|
|
2
|
+
|
|
3
|
+
Maintainer guide. For installation and usage, see the [README](../README.md).
|
|
4
|
+
|
|
5
|
+
## CI and automatic npm releases
|
|
6
|
+
|
|
7
|
+
GitHub Actions runs type checks, tests, package metadata validation, and a packaging dry run for pull requests and pushes to `main` and `dev`, on Node.js 22.19 and 24.
|
|
8
|
+
|
|
9
|
+
A **version increase in `package.json` pushed to `main`** releases automatically after both check jobs pass:
|
|
10
|
+
|
|
11
|
+
1. Validate the matching version in `package-lock.json`.
|
|
12
|
+
2. Reserve `v<version>` at the exact checked commit.
|
|
13
|
+
3. Publish the npm tarball through OIDC trusted publishing, with provenance.
|
|
14
|
+
4. Create the GitHub Release with automatically generated release notes.
|
|
15
|
+
|
|
16
|
+
Ordinary code/dependency changes with no version increase do not publish. Neither PRs, `dev` pushes, tag pushes, nor installing the workflow alone publish a package. Stable versions use npm's `latest` tag; prereleases such as `0.2.0-rc.1` use `next` and GitHub's prerelease flag.
|
|
17
|
+
|
|
18
|
+
### One-time npm setup
|
|
19
|
+
|
|
20
|
+
For a new package, publish the initial version once after committing and checking the source:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm ci
|
|
24
|
+
npm run check
|
|
25
|
+
npm login
|
|
26
|
+
npm publish --access public --ignore-scripts
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
This bootstrap publish creates the package so its trusted publisher can be configured. Subsequent releases use the workflow below, not local `npm publish`.
|
|
30
|
+
|
|
31
|
+
In the npm settings for **@oldflag2333333/pi-subagent**, add a **GitHub Actions Trusted Publisher**:
|
|
32
|
+
|
|
33
|
+
| Setting | Value |
|
|
34
|
+
| --- | --- |
|
|
35
|
+
| Organization or user | `oldflag2333333` |
|
|
36
|
+
| Repository | `pi-subagent` |
|
|
37
|
+
| Workflow filename | `release.yml` (filename only, not a path) |
|
|
38
|
+
| Environment | Leave blank; this workflow does not use a GitHub Environment |
|
|
39
|
+
| Allowed actions | Allow direct `npm publish` |
|
|
40
|
+
|
|
41
|
+
No `NPM_TOKEN` secret is needed. GitHub supplies its built-in `GITHUB_TOKEN` for tags/releases; only the release job has `contents: write` and `id-token: write`. Publishing runs on a GitHub-hosted runner with Node 24 and a pinned npm 11 CLI. See [npm trusted publishing](https://docs.npmjs.com/trusted-publishers/) for package-side setup.
|
|
42
|
+
|
|
43
|
+
Commit the workflow to GitHub and enable Actions before the first version bump. Keep `package.json`'s `repository.url` aligned with this repository; npm provenance and the release script verify that identity.
|
|
44
|
+
|
|
45
|
+
### Releasing
|
|
46
|
+
|
|
47
|
+
On your feature/release branch:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npm version minor --no-git-tag-version
|
|
51
|
+
# Or: npm version patch --no-git-tag-version
|
|
52
|
+
git add package.json package-lock.json
|
|
53
|
+
git commit -m "chore: release v0.2.0"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Merge that change into `main` (or push it directly if your branch policy allows). The workflow handles the tag, npm publication, and GitHub Release; do not run `npm publish` yourself.
|
|
57
|
+
|
|
58
|
+
If publishing fails, correct the external setup and **re-run the original failed workflow** on its original commit. An identical already-published artifact is not republished, so a failed GitHub Release step can be completed safely. An existing tag pointing elsewhere, an npm version with different contents, or a version that would move a dist-tag backwards causes an error instead of an overwrite. A failed npm publish may leave its reserved Git tag, but no GitHub Release is announced until publication succeeds. Publish one version at a time.
|
|
59
|
+
|
|
60
|
+
GitHub Releases created by `GITHUB_TOKEN` do not trigger a second release workflow, so npm publication and Release creation deliberately run in the same job.
|
|
61
|
+
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Pi Subagent Agent Visibility for Herdr
|
|
2
|
+
|
|
3
|
+
This companion Herdr plugin hides Pi Subagent-managed subs from the built-in Agents panel by default and provides actions to show, hide, or toggle them.
|
|
4
|
+
|
|
5
|
+
Pi Subagent marks each Herdr Sub pane with the metadata token `subagent_role=sub`. This plugin applies a transient `agent.view` filter; it does not affect `agent list`, notifications, lifecycle detection, or global attention counts.
|
|
6
|
+
|
|
7
|
+
## Link for development
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
herdr plugin link /absolute/path/to/pi-subagent/herdr-plugin
|
|
11
|
+
herdr plugin action invoke subagent.agent-visibility.hide-subs
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Actions
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
herdr plugin action invoke subagent.agent-visibility.toggle-subs
|
|
18
|
+
herdr plugin action invoke subagent.agent-visibility.hide-subs
|
|
19
|
+
herdr plugin action invoke subagent.agent-visibility.show-subs
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The selected visibility is stored in `HERDR_PLUGIN_STATE_DIR` and restored when the Herdr server starts. The initial default is hidden.
|
|
23
|
+
|
|
24
|
+
Optional keybinding:
|
|
25
|
+
|
|
26
|
+
```toml
|
|
27
|
+
[[keys.command]]
|
|
28
|
+
key = "prefix+shift+a"
|
|
29
|
+
type = "plugin_action"
|
|
30
|
+
command = "subagent.agent-visibility.toggle-subs"
|
|
31
|
+
description = "toggle Pi Subagent subs"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
After editing Herdr config, run `herdr server reload-config`.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
import { run } from "./index.mjs";
|
|
4
|
+
|
|
5
|
+
// WORKAROUND: herdr-plugin.toml uses Pi with --list-models to load this action
|
|
6
|
+
// without entering an interactive session. We run the visibility script during
|
|
7
|
+
// extension initialization and exit before model listing, relying on Pi's startup
|
|
8
|
+
// order. Prefer invoking index.mjs directly once Node availability is guaranteed
|
|
9
|
+
// in the Herdr plugin environment.
|
|
10
|
+
export default async function action(pi: ExtensionAPI): Promise<void> {
|
|
11
|
+
pi.registerFlag("subagent-visibility-action", {
|
|
12
|
+
description: "Internal Pi Subagent Herdr visibility action",
|
|
13
|
+
type: "string",
|
|
14
|
+
});
|
|
15
|
+
const flagIndex = process.argv.indexOf("--subagent-visibility-action");
|
|
16
|
+
const requested = flagIndex >= 0 ? process.argv[flagIndex + 1] : undefined;
|
|
17
|
+
await run(typeof requested === "string" && requested.length > 0 ? requested : "startup");
|
|
18
|
+
process.exit(0);
|
|
19
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
id = "subagent.agent-visibility"
|
|
2
|
+
name = "Pi Subagent Agent Visibility"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
min_herdr_version = "0.8.2"
|
|
5
|
+
description = "Hide or show Pi Subagent subs in Herdr's Agents panel"
|
|
6
|
+
platforms = ["linux", "macos"]
|
|
7
|
+
|
|
8
|
+
[[startup]]
|
|
9
|
+
command = ["pi", "--offline", "--no-extensions", "-e", "action.ts", "--subagent-visibility-action", "startup", "--list-models"]
|
|
10
|
+
|
|
11
|
+
[[actions]]
|
|
12
|
+
id = "toggle-subs"
|
|
13
|
+
title = "Toggle Pi Subagent subs"
|
|
14
|
+
contexts = ["global"]
|
|
15
|
+
command = ["pi", "--offline", "--no-extensions", "-e", "action.ts", "--subagent-visibility-action", "toggle", "--list-models"]
|
|
16
|
+
|
|
17
|
+
[[actions]]
|
|
18
|
+
id = "hide-subs"
|
|
19
|
+
title = "Hide Pi Subagent subs"
|
|
20
|
+
contexts = ["global"]
|
|
21
|
+
command = ["pi", "--offline", "--no-extensions", "-e", "action.ts", "--subagent-visibility-action", "hide", "--list-models"]
|
|
22
|
+
|
|
23
|
+
[[actions]]
|
|
24
|
+
id = "show-subs"
|
|
25
|
+
title = "Show Pi Subagent subs"
|
|
26
|
+
contexts = ["global"]
|
|
27
|
+
command = ["pi", "--offline", "--no-extensions", "-e", "action.ts", "--subagent-visibility-action", "show", "--list-models"]
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as net from "node:net";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
|
|
6
|
+
const pluginId = process.env.HERDR_PLUGIN_ID ?? "subagent.agent-visibility";
|
|
7
|
+
const source = `plugin:${pluginId}`;
|
|
8
|
+
const socketPath = process.env.HERDR_SOCKET_PATH;
|
|
9
|
+
const stateDir = process.env.HERDR_PLUGIN_STATE_DIR;
|
|
10
|
+
|
|
11
|
+
function statePath() {
|
|
12
|
+
if (!stateDir) throw new Error("HERDR_PLUGIN_STATE_DIR is missing.");
|
|
13
|
+
return path.join(stateDir, "visibility.json");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function readState() {
|
|
17
|
+
try {
|
|
18
|
+
const value = JSON.parse(fs.readFileSync(statePath(), "utf8"));
|
|
19
|
+
return { showSubs: value?.showSubs === true };
|
|
20
|
+
} catch (error) {
|
|
21
|
+
if (error?.code === "ENOENT") return { showSubs: false };
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function writeState(state) {
|
|
27
|
+
const file = statePath();
|
|
28
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
29
|
+
const temporary = `${file}.${process.pid}.tmp`;
|
|
30
|
+
fs.writeFileSync(temporary, `${JSON.stringify(state, null, 2)}\n`, { mode: 0o600 });
|
|
31
|
+
fs.renameSync(temporary, file);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function send(method, params) {
|
|
35
|
+
if (!socketPath) return Promise.reject(new Error("HERDR_SOCKET_PATH is missing."));
|
|
36
|
+
const endpoint = process.platform === "win32" ? `\\\\.\\pipe\\${socketPath}` : socketPath;
|
|
37
|
+
const request = { id: `subagent:${Date.now()}:${process.pid}`, method, params };
|
|
38
|
+
return new Promise((resolve, reject) => {
|
|
39
|
+
let buffer = "";
|
|
40
|
+
const socket = net.createConnection(endpoint);
|
|
41
|
+
const timeout = setTimeout(() => {
|
|
42
|
+
socket.destroy();
|
|
43
|
+
reject(new Error("Timed out waiting for Herdr."));
|
|
44
|
+
}, 5000);
|
|
45
|
+
const finish = (callback) => {
|
|
46
|
+
clearTimeout(timeout);
|
|
47
|
+
socket.destroy();
|
|
48
|
+
callback();
|
|
49
|
+
};
|
|
50
|
+
socket.on("error", (error) => finish(() => reject(error)));
|
|
51
|
+
socket.on("connect", () => socket.write(`${JSON.stringify(request)}\n`));
|
|
52
|
+
socket.on("data", (chunk) => {
|
|
53
|
+
buffer += chunk.toString("utf8");
|
|
54
|
+
const newline = buffer.indexOf("\n");
|
|
55
|
+
if (newline < 0) return;
|
|
56
|
+
try {
|
|
57
|
+
const response = JSON.parse(buffer.slice(0, newline));
|
|
58
|
+
if (response.error) throw new Error(response.error.message ?? JSON.stringify(response.error));
|
|
59
|
+
finish(() => resolve(response.result));
|
|
60
|
+
} catch (error) {
|
|
61
|
+
finish(() => reject(error));
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function apply(showSubs) {
|
|
68
|
+
if (showSubs) {
|
|
69
|
+
await send("agent.view.clear", { source });
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
await send("agent.view.set", {
|
|
73
|
+
source,
|
|
74
|
+
label: "subs hidden",
|
|
75
|
+
filter: {
|
|
76
|
+
op: "not",
|
|
77
|
+
filter: {
|
|
78
|
+
op: "eq",
|
|
79
|
+
field: { token: "subagent_role" },
|
|
80
|
+
value: "sub",
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
sort: [],
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export async function run(action = "startup") {
|
|
88
|
+
const current = readState();
|
|
89
|
+
const next = action === "toggle"
|
|
90
|
+
? { showSubs: !current.showSubs }
|
|
91
|
+
: action === "show"
|
|
92
|
+
? { showSubs: true }
|
|
93
|
+
: action === "hide" || action === "startup"
|
|
94
|
+
? current
|
|
95
|
+
: undefined;
|
|
96
|
+
if (!next) throw new Error(`Unknown action '${action}'.`);
|
|
97
|
+
if (action === "hide") next.showSubs = false;
|
|
98
|
+
writeState(next);
|
|
99
|
+
await apply(next.showSubs);
|
|
100
|
+
console.log(next.showSubs ? "Pi Subagent subs are visible." : "Pi Subagent subs are hidden.");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
104
|
+
run(process.argv[2] ?? "startup").catch((error) => {
|
|
105
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
106
|
+
process.exitCode = 1;
|
|
107
|
+
});
|
|
108
|
+
}
|