pi-pier 0.2.3 → 0.2.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-pier",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "pier: pi extension that fuses pi agent sessions with the herdr pane/tab orchestrator — todo_write loop closure + interactive subagents in isolated panes",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -9,78 +9,69 @@ description: >-
9
9
  license: MIT
10
10
  ---
11
11
 
12
- # pi-herdr 工作台工作流
13
-
14
- 你在一个 herdr 终端工作区(pane)里运行。本 skill 教你把 `todo_write` 与
15
- `subagent` 工具用好;人类在 herdr 的 TUI 里实时观察:每个 pane 的窗格头
16
- 显示 `▶x ○y ■b ✓z · 当前任务`,语义状态(working/blocked/idle)上卷到侧边栏。
17
-
18
- ## 1. todo 纪律(全量替换语义)
19
-
20
- - `todo_write` 每次调用提交**完整列表**(last-wins),没有部分更新。
21
- - 条目 = `content`(非空、唯一、5–10 词的命令式短语,写"做什么"不写"怎么做",**不带编号前缀**)+ `status`(pending | in_progress | completed | blocked | abandoned)。
22
- - `blocked` = 在等外部条件(信息、人、别的系统),必须带 `blocker` 说明等什么;`abandoned` = 显式放弃(不删条目,保留计划痕迹)。
23
- - 多阶段计划用可选 `phase` 分组(≤30 字);单阶段就不写 phase。
24
- - 保持列表精简(≤15 条):一条 = 一个有意义的交付单元,不是微步骤。
25
- - 正在推进的标 `in_progress`(真正并行时才允许多条);**完成立即标 completed**。
26
- - **测试失败/实现不完整/有未解决错误时绝不算 completed**——保持 in_progress,或改成 blocked 并说明 blocker。
27
- - **绝不把 todo_write 当成一轮里的唯一工具调用**——搭着真实工作一起提交。
28
- - 记不清某条任务的原文时,从上一轮 todo_write 结果里找,**不许凭记忆编**(防幻影条目)。
29
- - **不要**把已委派给子代理的工作写进自己的 todo——那是子代理自己的职责;
30
- 你的列表只跟踪你自己的工作。等子代理结果回流后再验收归档。
31
- - 多子代理协作时在 content 里写清**文件所有权**(例如 "重构 auth 模块(只碰 src/auth/)"),
32
- 避免两个 agent 抢同一文件。
33
- - **你是被委派的工作 pane**(`PI_HERDR_SUBAGENT=1`)时,本插件自动执行严格模式:
34
- 你的列表任何时候**至多一条 in_progress**(多写会被归一化),全部完成会自动晋升下一条 pending。
35
- 你是主控 pane 时保持并行语义,纪律由本节承担。
36
-
37
- ## 2. 子代理委派
38
-
39
- 子代理 pane 跑的是**交互式 pi TUI**(独立会话):人类可以随时进入该 pane
40
- 直接与子代理对话;你的委派 prompt 会以消息形式出现在它的对话里。
41
-
42
- ### 选型
43
- - **前台**(默认):调用后等待结果返回。适合"下一步依赖其结果"的委派。
44
- - **后台**(`run_in_background: true`):立即返回 `agentId`;子代理在独立
45
- pane 常驻运行。适合长任务/并行推进。它会**持续存在**(有自己的持久会话),
46
- 结算时你会收到一条 "Background subagent <id> finished..." 通知消息。
47
- - 一条消息里的多个 subagent 调用会并行执行(上限 4 并发)。
48
- - 可选 `role`(如 `advisor`)只是标签:v1 不改工具面、不改生命周期,与普通 task 一样走 TTL;省略 = `task`。复活走 `resume_subagent`,不要假设 pane 会自动补回来。
49
-
50
- ### 任务 tab 分组(`tab` 参数)
51
- - 每个委派默认开一个**以任务命名的新 tab**(名字取自 `description`)。
52
- - 一组相关的子任务用同一个 `tab` 名字收进同一个 tab(例如网络调研 + 现状
53
- 摸索都用 `tab: "调研"`),人类在 herdr 里一个 tab 内看完全部相关 pane。
54
- - 名字要短(≤20 字)、人类一眼能懂;tab 栏就是任务板。
55
- - 不要为了少开 tab 而把无关任务塞进同一个 tab;一个 tab = 一个任务目标。
56
- - **任务 tab 是临时的**:tab 内全部子代理结算后(默认宽限约 10 分钟)tab
57
- 会自动关闭——不要假设它的 pane 长期存在;需要回看/继续时用
58
- `resume_subagent(taskId)` 从历史复活,而不是引用已关的 pane。
59
-
60
- ### prompt 纪律
61
- - prompt 必须**自包含**:子代理看不到你的对话历史,只有这段 prompt。
62
- - 明确输入(哪些文件/事实)、明确产出(交什么)、明确边界(不碰什么)。
63
- - 用文件/工件传递共享上下文,不要把大段内容塞进 prompt。
64
- - 独立任务才委派;互相依赖的工作拆给同一子代理。
65
-
66
- ### 后台子代理的后续管理
67
- - `list_agents`:查看全部后台子代理与状态(running/idle)。
68
- - `send_message(agentId, message)`:给子代理追加任务(FIFO;已结算的子代理
69
- 会被唤醒继续干)。
70
- - `interrupt_agent(agentId)`:打断子代理当前轮次(它仍驻留,可继续 send_message)。
71
- - 子代理结算后不要重新委派同一个 agentId 之外的新任务时,可再 send_message 唤醒。
72
-
73
- ## 3. 人类闸门
74
-
75
- - 需要人类决策(审批、取舍、方向选择)时,用 `ask_user_question`(本插件提供)——
76
- 等待回答期间,你的 pane 在 herdr 里呈 **blocked** 状态,人类会看到并介入;
77
- 答案会作为工具结果回到你的上下文,然后继续工作。
78
- - 子代理 pane 在 herdr 里可被人类直接进入交互;你的委派描述(pane 标签)
79
- 要写得人类一眼能懂。
80
-
81
- ## 4. 多 agent 纪律(工程实践映射)
82
-
83
- - 你是仲裁者:验收每个子代理的输出,再合入你的工作;不要把仲裁权下放。
84
- - 关键结论安排独立复核(换个子代理 reviewer 复核),不盲信单一子代理。
85
- - 同构的并行子代理会犯同样的错:给不同子代理不同的任务边界与产出格式。
86
- - 委派后继续做你自己的事,不要干等(前台调用除外)。
12
+ # pi-herdr workbench workflow
13
+
14
+ You run inside a herdr terminal pane. This skill is how to use `todo_write` and
15
+ `subagent` well. The human watches live in herdr: each pane header shows
16
+ `▶x ○y ■b ✓z · current task`, and semantic state (working / blocked / idle)
17
+ rolls up to the sidebar.
18
+
19
+ ## 1. Todo discipline (full-replace semantics)
20
+
21
+ - Every `todo_write` submits the **entire list** (last-wins). There is no partial update.
22
+ - An item is `content` (non-empty, unique, 5–10 word imperative phrase: *what*, not *how*, **no numeric prefix**) + `status` (`pending` | `in_progress` | `completed` | `blocked` | `abandoned`).
23
+ - `blocked` = waiting on an external condition (info, a person, another system) and **must** include `blocker` saying what is missing; `abandoned` = explicit drop (keep the row; do not delete the plan trail).
24
+ - Multi-phase plans may group with optional `phase` (≤30 chars). Single-phase: omit `phase`.
25
+ - Keep the list small (≤15): one item = one meaningful deliverable, not a micro-step.
26
+ - Mark what you are actually doing `in_progress` (multiple only when truly parallel); **mark `completed` the moment it is done**.
27
+ - **Never mark completed when tests fail, the implementation is incomplete, or errors remain** — stay `in_progress`, or switch to `blocked` with a blocker.
28
+ - **Never make `todo_write` the only tool call in a turn** — batch it with real work.
29
+ - If you forget an item's exact wording, copy it from the previous `todo_write` result. **Do not invent from memory** (phantom items).
30
+ - **Do not** put work you already delegated to a subagent on *your* todo list — that is the subagent's job. Your list tracks *your* work. Accept and archive after the result comes back.
31
+ - When several subagents collaborate, put **file ownership** in `content` (e.g. "refactor auth (only src/auth/)") so two agents do not fight over the same file.
32
+ - When **you** are a delegated worker pane (`PI_HERDR_SUBAGENT=1`), this plugin enforces strict mode: **at most one `in_progress`** at a time (extras are normalized), and finishing the current item auto-promotes the next `pending`. The master pane keeps parallel semantics; this section is the discipline.
33
+
34
+ ## 2. Subagent delegation
35
+
36
+ A subagent pane is an **interactive pi TUI** (independent session). A human can enter that pane and talk to it at any time. Your delegation prompt appears as a message in its conversation.
37
+
38
+ ### Mode
39
+
40
+ - **Foreground** (default): the call waits for a result. Use when the next step depends on it.
41
+ - **Background** (`run_in_background: true`): returns `agentId` immediately; the subagent keeps running in its own pane. Use for long / parallel work. It **persists** (own session). On settle you get a "Background subagent <id> finished..." notice.
42
+ - Multiple `subagent` calls in one message run in parallel (cap 4).
43
+ - Optional `role` (e.g. `advisor`) is a label only: v1 does not change tools or lifecycle; TTL is the same as `task`. Omit = `task`. Revive with `resume_subagent`; do not assume the pane comes back by itself.
44
+
45
+ ### Task-tab grouping (`tab`)
46
+
47
+ - Each delegation defaults to a **new tab named from `description`**.
48
+ - Related subtasks share one `tab` name (e.g. web research + status probe both `tab: "research"`) so the human sees every related pane in one herdr tab.
49
+ - Keep names short (≤20 chars) and obvious; the tab bar *is* the task board.
50
+ - Do not cram unrelated work into one tab to "save tabs". One tab = one goal.
51
+ - **Task tabs are temporary**: after every subagent in the tab has settled (default grace ~10 minutes) the tab closes. Do not assume those panes last. To review or continue, `resume_subagent(taskId)` from history — do not cite a closed pane.
52
+
53
+ ### Prompt discipline
54
+
55
+ - The prompt must be **self-contained**: the subagent cannot see your conversation, only this prompt.
56
+ - State inputs (which files / facts), outputs (what to deliver), and bounds (what not to touch).
57
+ - Share context via files / artifacts. Do not dump large blobs into the prompt.
58
+ - Delegate only independent work; dependent steps go to the same subagent.
59
+
60
+ ### After a background spawn
61
+
62
+ - `list_agents`: all background subagents and status (`running` / `idle`).
63
+ - `send_message(agentId, message)`: append work (FIFO; a settled subagent is woken).
64
+ - `interrupt_agent(agentId)`: abort the current turn (the pane stays; you can `send_message` again).
65
+ - After settle, if you have more work for that same `agentId`, `send_message` to wake it; do not spawn a duplicate.
66
+
67
+ ## 3. Human gate
68
+
69
+ - For a human decision (approval, tradeoff, direction), use `ask_user_question` (this plugin). While waiting, your pane is **blocked** in herdr so the human can see and intervene. The answer comes back as the tool result, then you continue.
70
+ - A human can enter a subagent pane directly. Write the delegation `description` (pane label) so a human understands it at a glance.
71
+
72
+ ## 4. Multi-agent engineering rules
73
+
74
+ - You are the arbiter: accept each subagent's output, then merge it. Do not outsource arbitration.
75
+ - Independent review for critical conclusions (a different subagent as reviewer). Do not trust a single worker blindly.
76
+ - Homogeneous parallel workers make the same mistakes: give them different bounds and output shapes.
77
+ - After delegating, keep doing your own work. Do not idle-wait (except a foreground call).
@@ -122,7 +122,11 @@ export function createSessionIo(h: SessionIoHost): SessionIo {
122
122
  ): Promise<{ text: string | null; pendingTool: boolean; activity: boolean }> {
123
123
  for (const file of await resolveSessionFileCandidates(paneId, cwd)) {
124
124
  const entries = readSessionFile(file);
125
- if (entries.length === 0) continue;
125
+ // readSessionFile returns null when the path is missing or unreadable.
126
+ // herdr often reports a .jsonl path before the worker creates the file;
127
+ // waitAgent(idle) then returns immediately and this path used to throw
128
+ // `Cannot read properties of null (reading 'length')` (session 01a055c5).
129
+ if (!entries?.length) continue;
126
130
  const r = lastAssistantText(entries, { sinceTs });
127
131
  if (r?.text) return { text: r.text, pendingTool: false, activity: true };
128
132
  if (hasPendingToolCall(entries, sinceTs)) return { text: null, pendingTool: true, activity: true };