feat(session-inbox-monitor): pi support — global extension section, v0.3.0
Pi (pi-coding-agent) sessions get inbox delivery via global extension (.common/lib/pi-extensions/inbox-monitor.ts → ~/.pi/agent/extensions/). Not cwd-scoped: any .claude-inbox/ message pages the current session with project name in header. Headless = no delivery. SKILL.md v0.2.2→v0.3.0.
This commit is contained in:
File diff suppressed because one or more lines are too long
51
.tasks/session-inbox-monitor-pi-extension.md
Normal file
51
.tasks/session-inbox-monitor-pi-extension.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# session-inbox-monitor-pi-extension — working context
|
||||
|
||||
**Status:** 🟢 done (shipped 2026-08-10) — pi-native inbox delivery shipped for ALL pi sessions, see STATUS.md block.
|
||||
**Owner:** vitya (pi interactive session, .admin)
|
||||
**Notify:** OpeItcLoc03/claude-skills
|
||||
|
||||
Pi (pi-coding-agent) не покрывался скилом: Monitor tool — CC-only, хуки CC-only.
|
||||
Собран pi-native аналог: глобальное расширение, доставляющее сообщения из ЛЮБОГО
|
||||
`.claude-inbox/` в текущую pi-сессию независимо от cwd (требование vitya: «мне
|
||||
похуй, какой агент в какой папке сидит — система сообщений должна работать»).
|
||||
|
||||
## Решения
|
||||
|
||||
1. **Глобально, не cwd-scoped.** Скан всех инбоксов: прямые дети `~/projects`
|
||||
(все 20 инбоксов живут на глубине 1, проверено find). Оверрайд —
|
||||
`PI_INBOX_ROOTS` (pathsep, `;` на Windows).
|
||||
2. **Два пути доставки** (контракт как у CC-хуков):
|
||||
- PUSH: один глобальный poll-интервал 15s (интерактив только).
|
||||
- PULL: `agent_settled` sweep — pi-эквивалент Stop-хука.
|
||||
- Dedup per-process по `inbox|filename`; move в `.read/` — кросс-процессный
|
||||
guard: кто первый swept — тот и забрал (CC hook или pi), второй пропускает.
|
||||
3. **Headless (`pi -p`, `ctx.hasUI === false`) — НИКАКОЙ доставки.** Ни watcher,
|
||||
ни sweep. Сообщения ждут интерактивную сессию. Зеркалит CC-headless (там
|
||||
внешний Notify/ntfy, не инжект в ран) + не угоняет one-shot прогоны и не
|
||||
съедает сообщения без обработки.
|
||||
4. **Доставка:** `pi.sendUserMessage(body, { deliverAs: "followUp", triggerTurn:
|
||||
true })` — заголовок `[inbox] <project>/<name>` + тело инлайн, потом move в
|
||||
`.read/`. Пустые файлы (частичная запись) пропускаются и ретраятся.
|
||||
5. **Source of truth:** `.common/lib/pi-extensions/inbox-monitor.ts` (Node
|
||||
built-ins only, без npm deps — авто-дискавери без package.json). Деплой:
|
||||
копия в `~/.pi/agent/extensions/inbox-monitor.ts` (global → все pi, все
|
||||
директории). Hot-reload `/reload`. Тест: `inbox-monitor.test.mjs`
|
||||
(`node --experimental-strip-types`, Node ≥22.6).
|
||||
|
||||
## Verified
|
||||
|
||||
- Функциональный тест 3 блоков (интерактив-глобал, headless-no-delivery,
|
||||
partial-write-retry) — ALL TESTS PASSED.
|
||||
- Нет зависания процесса: headless не стартует интервал; интерактив чистит
|
||||
интервал в `session_shutdown` (timeout-прогон EXITED CLEANLY).
|
||||
- Деплой: diff source↔`~/.pi/agent/extensions/` = 0 (byte-identical).
|
||||
|
||||
## Open questions / failure modes
|
||||
|
||||
- **Кросс-харнессный двойной пикап:** CC и pi оба свипят — `.read/` move делает
|
||||
first-wins, не double-processing. Два pi-процесса на одной машине гонятся как
|
||||
две CC-сессии (known limitation, см. SKILL.md).
|
||||
- **Проверка живого pi-лоада** (что авто-дискавери подхватил расширение в
|
||||
реальном TUI) — за `/reload` при следующей интерактивной pi-сессии.
|
||||
- **Headless-доставка не реализована** (сознательно): при необходимости —
|
||||
внешний Notify/ntfy, отдельная задача.
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: session-inbox-monitor
|
||||
version: 0.2.2
|
||||
version: 0.3.0
|
||||
description: >
|
||||
Raises a persistent Monitor (Monitor tool, NOT background Bash) on the
|
||||
project's `.claude-inbox/` at the start of an interactive session, so
|
||||
@@ -11,7 +11,9 @@ description: >
|
||||
CLAUDE.md line `inbox monitor: raise on start`, or «подними монитор почты»,
|
||||
«настрой авто-монитор инбокса», «raise inbox monitor», «auto-arm inbox
|
||||
watcher». Headless (`claude -p`): does NOT raise — Monitor doesn't work
|
||||
there; rely on the Stop-hook inbox pickup + Notify/ntfy. NOT for how to
|
||||
there; rely on the Stop-hook inbox pickup + Notify/ntfy. Pi (pi-coding-agent)
|
||||
sessions: a global extension delivers any `.claude-inbox/` message to the
|
||||
current session regardless of cwd (see the Pi section). NOT for how to
|
||||
handle a received message (→ inter-session-peer-discipline) nor the
|
||||
multi-machine inbox backend (→ cross-machine-inbox design).
|
||||
---
|
||||
@@ -127,6 +129,39 @@ for free on session end. Headless sessions skip it and rely on the pull-model
|
||||
- **No repo writes.** The hook and its `~/.claude/settings.json` registration are
|
||||
machine-local; only this skill (docs) and `.claude-inbox/` activity are in play.
|
||||
|
||||
## Pi (pi-coding-agent) support — global extension
|
||||
|
||||
Same contract, pi-native, and **not cwd-scoped**: which folder the pi session
|
||||
sits in is irrelevant — every `.claude-inbox/` under the configured roots is
|
||||
watched and swept; a message pages the *current* pi session with the project
|
||||
name in the header (`[inbox] <project>/<name>` + body inline, then moved to
|
||||
`.read/`).
|
||||
|
||||
- **Source of truth:** `.common/lib/pi-extensions/inbox-monitor.ts` (Node
|
||||
built-ins only, no npm deps). Deploy: copy to
|
||||
`~/.pi/agent/extensions/inbox-monitor.ts` (global → every pi, every
|
||||
directory), hot-reload with `/reload`. Test:
|
||||
`node --experimental-strip-types .common/lib/pi-extensions/inbox-monitor.test.mjs`.
|
||||
- **Roots:** direct children of `~/projects` by default (all inboxes live there,
|
||||
depth 1); override with `PI_INBOX_ROOTS` (pathsep-separated, `;` on Windows).
|
||||
- **PUSH:** one 15s global poll while a session is live (interactive only).
|
||||
**PULL:** `agent_settled` sweep — the pi equivalent of the CC Stop-hook
|
||||
pickup. Both share one dedup set per process; the `.read/` move is the
|
||||
cross-process guard — first sweeper (CC hook or pi) claims the message, the
|
||||
other skips it.
|
||||
- **Headless (`pi -p`, `ctx.hasUI === false`):** NO delivery — no watcher, no
|
||||
sweep. Messages sit in the inbox until an interactive session picks them up.
|
||||
Mirrors CC headless (external Notify there, nothing in-run) and avoids
|
||||
hijacking one-shot scripted runs or consuming messages nobody processes.
|
||||
- **Delivery:** `pi.sendUserMessage(body, { deliverAs: "followUp", triggerTurn:
|
||||
true })` — paged into the transcript as a user message; the agent handles it
|
||||
per `inter-session-peer-discipline`. Partial writes (empty file) are skipped
|
||||
and retried next poll.
|
||||
- **Failure mode — cross-harness double-pickup:** CC and pi both sweep; the
|
||||
`.read/` move makes it first-wins, not double-processing. Two live pi sessions
|
||||
in one process tree share the dedup set; two pi *processes* on one machine
|
||||
race like two CC sessions (known limitation, see Failure modes above).
|
||||
|
||||
## What NOT to do
|
||||
|
||||
- **Don't watch the inbox with a background Bash** (`run_in_background`) — it
|
||||
|
||||
Reference in New Issue
Block a user