pi-claude-supervisor 0.2.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/CHANGELOG.md ADDED
@@ -0,0 +1,36 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented here.
4
+
5
+ ## [0.2.0](https://github.com/btnalit/pi-claude-supervisor/compare/v0.1.0...v0.2.0) (2026-09-12)
6
+
7
+
8
+ ### Features
9
+
10
+ * persist decision worker sessions across restarts ([a926c0e](https://github.com/btnalit/pi-claude-supervisor/commit/a926c0e4f3455cbc5dfbbcff1441d1d1497939ed))
11
+ * persist Decision Worker sessions and add release gates ([de73d29](https://github.com/btnalit/pi-claude-supervisor/commit/de73d29549605026985db301112ae3745d164bd7))
12
+
13
+ ## [0.1.0] - Unreleased
14
+
15
+ ### Added
16
+
17
+ - Standard Pi/npm package metadata and TypeScript extension entry point.
18
+ - Dependency-free process-pipe WorkerAdapter with process-group control.
19
+ - Explicit Supervisor state machine, append-only event log and turn budget.
20
+ - Deterministic Policy Gate and independent verification phase.
21
+ - Minimal worker environment, argv-aware permission policy, watchdog timeouts and startup cleanup.
22
+ - Opt-in Claude JSONL framing with duplicate-message suppression and transport Spike evidence for prompt, multi-turn and session resume.
23
+ - Event-log sequence recovery and credential-shaped redaction.
24
+ - Bounded output capture, stdin-write timeout, process-group cleanup retry and stop preemption.
25
+ - Linux cgroup-v2 descendant cleanup, including a `setsid()` regression fixture, with required/auto modes.
26
+ - Lifecycle event retry/order preservation, output restoration after log failure and shutdown cleanup retries.
27
+ - Claude CLI 2.1.268 permission allow/deny and SIGTERM/SIGINT transport spike evidence.
28
+ - Event-driven JSONL `control_request`/`result`/exit events, permission responses, persistent Pi Decision Worker automation, bounded duplicate/turn handling, and outbound human-intervention webhooks.
29
+ - Long-task defaults are now 100 automatic turns, 4 hours wall time and 20 minutes without output; Decision Worker API failures alert human operators directly instead of attempting an LLM fallback.
30
+ - Automatic Decision Worker sessions now persist as Pi JSONL with a 0600 task registry. Unclean Pi restarts expose explicit `/supervise recover <task-id>` recovery; Claude work is not silently duplicated.
31
+ - Local tests and package-content checks.
32
+
33
+ ### Limitations
34
+
35
+ - PTY transport and cross-version Claude CLI permission/session semantics are out of scope for this pinned release; Claude JSONL support remains opt-in outside automatic mode. The installed 2.1.268 CLI is covered by local permission and signal spikes, while the cgroup startup-attachment window remains.
36
+ - No automatic merge, deployment, release or publication is implemented.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 yancao
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.cn.md ADDED
@@ -0,0 +1,98 @@
1
+ # pi-claude-supervisor
2
+
3
+ [![CI](https://github.com/btnalit/pi-claude-supervisor/actions/workflows/ci.yml/badge.svg)](https://github.com/btnalit/pi-claude-supervisor/actions/workflows/ci.yml)
4
+ [![npm](https://img.shields.io/npm/v/pi-claude-supervisor)](https://www.npmjs.com/package/pi-claude-supervisor)
5
+ [![MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
6
+
7
+ [English](README.md)
8
+
9
+ 用于 Pi 的 Claude Code Worker 监督扩展。MVP 中 Pi 负责生命周期、状态机、策略门和独立验收;Worker 只是被显式启动的子进程。
10
+
11
+ > 当前默认 transport 是无额外依赖的 process pipe,不是 PTY。已新增可选 Claude JSONL framing,并通过基础 prompt、多轮和 resume Spike。当前优先保证生命周期、进程组清理、恢复和独立验收;低权限用户、OS sandbox 与网络隔离不作为当前主线,按明确授权和宿主机策略运行,后续再做安全加固。
12
+
13
+ ## 关键安全边界
14
+
15
+ - 不会在扩展加载时自动启动 Worker。
16
+ - 不经过 shell 启动子进程。
17
+ - Worker 只继承最小环境;凭据必须由调用方显式传入。
18
+ - 破坏性命令和绕过权限的 Worker 参数默认拒绝;需要复核的启动命令会请求用户批准,不会一律拒绝。
19
+ - Linux 上优先使用可写的 cgroup v2 清理后代进程,包括 `setsid()` 后代;不可用时回退到进程组清理。需要强制失败闭环时,embedding 集成可使用 `cgroupMode: "required"`。
20
+ - 普通联网查询不因联网本身被拒绝;下载后直接交给 shell 等高风险模式仍需人工复核。
21
+ - Worker 声称完成只会进入 `verifying`,不能作为成功证据。
22
+ - 默认独立验收命令为 `git diff --check`。
23
+ - 扩展运行时不执行 merge、deploy、release 或 publish;仓库 Release 只会在维护者合并 Release Please PR 且 CI 门禁全部通过后自动发布。
24
+ - 默认 4 小时总时限、20 分钟无输出 watchdog 超时即停止 Worker,适合长程开发任务;嵌入调用方可将对应选项设为 `0` 关闭。
25
+
26
+ ## 安装和使用
27
+
28
+ 需要 Pi 0.85+ 和 Node.js 22.19+:
29
+
30
+ ```text
31
+ pi install npm:pi-claude-supervisor
32
+ ```
33
+
34
+ 在 Pi 中使用。手动/兼容模式默认使用 process-pipe。要启用事件驱动的 Pi Decision Worker,使用 Claude JSONL 自动模式:
35
+
36
+ ```bash
37
+ export PI_CLAUDE_SUPERVISOR_MODE=auto
38
+ export PI_CLAUDE_SUPERVISOR_WORKER='claude --safe-mode --tools Bash'
39
+ # 可选:人工升级通知;generic 或 wecom
40
+ export PI_CLAUDE_SUPERVISOR_HUMAN_WEBHOOK_URL='https://example.invalid/webhook'
41
+ export PI_CLAUDE_SUPERVISOR_HUMAN_WEBHOOK_FORMAT=generic
42
+ # export PI_CLAUDE_SUPERVISOR_HUMAN_WEBHOOK_SECRET='shared-secret'
43
+ ```
44
+
45
+ 自动模式会强制使用 `claude-jsonl`,通过 `result`、`control_request` 和进程
46
+ `exit` 事件唤醒 Decision Worker;不会依赖 `/supervise poll` 轮询。本版本固定按已验证设备的
47
+ Claude CLI `2.1.268` 运行,跨版本兼容性不在本轮范围内。
48
+
49
+ 然后在 Pi 中使用:
50
+
51
+ ```text
52
+ /supervise capabilities
53
+ /supervise start inspect the current repository
54
+ /supervise poll
55
+ /supervise sessions
56
+ /supervise recover <task-id>
57
+ /supervise stop human requested stop
58
+ /supervise verify
59
+ /supervise approve <task-id> allow|deny [request-id]
60
+ /supervise takeover <task-id>
61
+ /supervise resume-auto <task-id>
62
+ ```
63
+
64
+ 人工升级通知的 generic JSON 格式为:
65
+
66
+ ```json
67
+ {
68
+ "schema": "pi-claude-supervisor/human-intervention/v1",
69
+ "event": "human_intervention_required",
70
+ "task": { "id": "...", "goal": "...", "cwd": "..." },
71
+ "worker": { "id": "..." },
72
+ "reason": "...",
73
+ "question": "...",
74
+ "permission": { "requestId": "...", "toolUseId": "...", "toolName": "Bash", "input": {} },
75
+ "actions": ["approve_or_deny_permission", "send_instruction", "stop_worker", "takeover"]
76
+ }
77
+ ```
78
+
79
+ 当前 webhook 是出站通知,不直接接受批准命令;批准或接管仍通过 Pi。
80
+ 自动模式会将 Decision Worker 会话持久化到状态目录。Pi 非正常重启后,`/supervise sessions`
81
+ 会显示 `recoverable` 任务;显式执行 `/supervise recover <task-id>` 会恢复 Decision Worker 上下文并
82
+ 重新启动 Claude Worker,不会静默恢复或重复执行任务。
83
+ 自动模式下,Decision Worker 可以安全拒绝 `AskUserQuestion`,让 Claude 将问题转成普通文本,
84
+ 再根据任务和仓库证据自动回答;无法确定时才升级人工。如需微信内闭环,需要另建带签名验证、
85
+ 一次性 action token 和重放保护的入站 callback 服务。
86
+
87
+ 可以从不同工作目录启动多个任务会话;活动会话不能共享同一 cwd,建议每个任务使用独立 worktree:
88
+
89
+ ```text
90
+ /supervise sessions
91
+ /supervise poll all
92
+ /supervise poll <task-id>
93
+ /supervise send <task-id> continue after checking the test failure
94
+ ```
95
+
96
+ Pull Request 必须通过聚合的 `CI / Quality gate`。Release Please 根据 Conventional Commits 创建版本 PR;维护者合并后,Release workflow 会针对精确 tag commit 重新验证,并通过受保护的 `npm` environment 使用 npm provenance 发布。
97
+
98
+ 详细内容见 [engineering-plan.md](docs/engineering-plan.md)、[independent-review.md](docs/independent-review.md)、[architecture.md](docs/architecture.md)、[testing.md](docs/testing.md) 和 [releasing.md](docs/releasing.md)。
package/README.md ADDED
@@ -0,0 +1,122 @@
1
+ # pi-claude-supervisor
2
+
3
+ [![CI](https://github.com/btnalit/pi-claude-supervisor/actions/workflows/ci.yml/badge.svg)](https://github.com/btnalit/pi-claude-supervisor/actions/workflows/ci.yml)
4
+ [![npm](https://img.shields.io/npm/v/pi-claude-supervisor)](https://www.npmjs.com/package/pi-claude-supervisor)
5
+ [![MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
6
+
7
+ English · [简体中文](README.cn.md)
8
+
9
+ A policy-gated [Pi](https://pi.dev) extension for supervising a Claude Code worker.
10
+ The MVP keeps Pi in control of lifecycle, state, policy and verification while the
11
+ worker remains an explicitly started child process.
12
+
13
+ > **MVP status:** the default transport is dependency-free process pipes, not PTY.
14
+ > An opt-in Claude JSONL framing mode has passed basic prompt, multi-turn and
15
+ > resume fixtures. The current priority is signal, shutdown, process-group and
16
+ > recovery validation; OS sandbox, low-privilege execution and network isolation
17
+ > are deferred hardening items and are not required by the current MVP plan.
18
+
19
+ ## Safety boundary
20
+
21
+ - The extension never starts a worker automatically.
22
+ - Worker commands are launched without a shell.
23
+ - Workers receive a minimal environment; credentials must be explicitly supplied by the caller.
24
+ - Destructive command patterns and permission-bypass worker flags are denied; review-level patterns request explicit user approval instead of being blanket-denied.
25
+ - Ordinary network use is not denied merely because it is network use; download-to-shell patterns still require review.
26
+ - A worker completion is only a transition to `verifying`; it is not evidence of success.
27
+ - Verification is an independent host command (default: `git diff --check`).
28
+ - The extension never performs merge, deploy, release, or publish at runtime. Repository releases are automated only after a maintainer merges a Release Please PR and the full CI gate passes.
29
+ - A 4-hour wall-clock and 20-minute no-output watchdog stop a worker by default for long development tasks; embedding callers can set either to `0` to disable.
30
+ - On Linux, the adapter automatically uses a writable cgroup v2 for descendant cleanup, including `setsid()` descendants; it falls back to process-group cleanup when unavailable. Use the adapter's `cgroupMode: "required"` for a fail-closed integration.
31
+ - Events are append-only JSONL records in `~/.pi/agent/claude-supervisor/events.jsonl`.
32
+
33
+ ## Install
34
+
35
+ Requires Pi 0.85+ and Node.js 22.19+.
36
+
37
+ ```text
38
+ pi install npm:pi-claude-supervisor
39
+ ```
40
+
41
+ For local development:
42
+
43
+ ```bash
44
+ npm ci --ignore-scripts
45
+ npm run check
46
+ npm run build
47
+ ```
48
+
49
+ ## Use
50
+
51
+ Set the worker executable if needed, then use explicit commands in Pi:
52
+
53
+ ```bash
54
+ export PI_CLAUDE_SUPERVISOR_WORKER=claude
55
+ ```
56
+
57
+ ```text
58
+ /supervise capabilities
59
+ /supervise start inspect the current repository and report what should be changed
60
+ /supervise sessions
61
+ /supervise recover <task-id>
62
+ /supervise poll
63
+ /supervise poll all
64
+ /supervise send continue with read-only inspection
65
+ /supervise pause
66
+ /supervise resume
67
+ /supervise stop human requested stop
68
+ /supervise verify
69
+ ```
70
+
71
+ The default MVP writes the task to the worker's stdin as plain process-pipe
72
+ text. After running the transport spike for the target CLI, JSONL framing can
73
+ be selected explicitly:
74
+
75
+ ```bash
76
+ export PI_CLAUDE_SUPERVISOR_TRANSPORT=jsonl
77
+ export PI_CLAUDE_SUPERVISOR_WORKER='claude --safe-mode --tools ""'
78
+ ```
79
+
80
+ This adds Claude Code stream-json flags and frames supervisor messages as JSONL.
81
+ The supervisor allows only one active JSONL request per session: poll until its
82
+ `result` and `waiting` state before sending the next turn. Session resume is not
83
+ yet exposed by the adapter. Multiple independent task sessions can run
84
+ concurrently when they use different canonical working directories or
85
+ worktrees; same-directory starts are rejected even when concurrent, and
86
+ `/supervise sessions` lists the sessions. Unattended use still requires the
87
+ remaining lifecycle, signal and recovery checks. Host permissions and network
88
+ access follow explicit caller authorization and host policy; there is no
89
+ automatic merge, deploy, release or publish.
90
+
91
+ Automatic mode persists the Pi Decision Worker session under the configured state
92
+ directory. After an unclean Pi restart, `/supervise sessions` lists recoverable
93
+ tasks; `/supervise recover <task-id>` explicitly restores the Decision Worker
94
+ context and starts a new Claude Worker. It never silently resumes or duplicates
95
+ work. The adapter intentionally does not inherit arbitrary host environment variables.
96
+ Pass credentials through an explicit `WorkerStartInput.env` in an embedding
97
+ integration. For the built-in command, opt in to named variables, for example
98
+ `PI_CLAUDE_SUPERVISOR_WORKER_ENV=ANTHROPIC_API_KEY`.
99
+
100
+ ## Development
101
+
102
+ ```bash
103
+ npm run typecheck
104
+ npm test
105
+ npm run check:package
106
+ npm run check:docs
107
+ npm run check:automation
108
+ npm run check:workflows
109
+ npm run build
110
+ ```
111
+
112
+ See [the engineering plan](docs/engineering-plan.md), [the independent review](docs/independent-review.md),
113
+ [architecture](docs/architecture.md), [testing](docs/testing.md), and [releasing](docs/releasing.md).
114
+
115
+ Pull requests are gated by the aggregated `CI / Quality gate`. Release Please
116
+ creates version PRs from Conventional Commits; after a maintainer merges one,
117
+ `Release` verifies the exact tag commit and publishes the package with npm
118
+ provenance through the protected `npm` environment.
119
+
120
+ ## License
121
+
122
+ MIT. See [LICENSE](LICENSE).
@@ -0,0 +1,122 @@
1
+ # Architecture
2
+
3
+ ## Control boundary
4
+
5
+ Pi owns the `Supervisor`. The supervisor owns the task state machine, event log,
6
+ turn budget, policy decision and independent verifier. `WorkerAdapter` owns only
7
+ process lifecycle and transport details.
8
+
9
+ ```text
10
+ Pi extension
11
+ |
12
+ v
13
+ Supervisor -> Policy Gate -> WorkerAdapter -> child process
14
+ |
15
+ +------> EventLog (JSONL)
16
+ +------> Independent Verifier
17
+ ```
18
+
19
+ The Worker cannot advance a task directly to `completed`. A clean worker exit
20
+ moves the supervisor to `verifying`; only a successful verifier moves it to
21
+ `completed`.
22
+
23
+ The extension keeps a registry of independent task sessions. Each session has
24
+ its own Supervisor, watchdog, state machine and Worker handle, while the event
25
+ log is shared and protected by an inter-process lock. Concurrent active sessions must use non-overlapping canonical working
26
+ directories/worktrees; same-cwd and parent/child cwd starts are rejected before
27
+ spawn, including concurrent starts, to prevent uncoordinated edits. Pending starts
28
+ are also awaited during Pi shutdown.
29
+
30
+ ## MVP transport
31
+
32
+ `ProcessWorkerAdapter` uses `node:child_process.spawn` with:
33
+
34
+ - `shell: false` (the default and intentionally not overridden);
35
+ - a detached process group for pause/resume/kill control;
36
+ - separate stdout/stderr capture;
37
+ - idempotency keys for messages;
38
+ - no session-resume claim.
39
+
40
+ This is a control-boundary fixture and headless transport. It does not emulate a
41
+ terminal. Manual compatibility mode remains `process-pipe`; automatic mode
42
+ (`PI_CLAUDE_SUPERVISOR_MODE=auto`) forces Claude JSONL and uses the CLI contract
43
+ validated by the fixed-version spike.
44
+
45
+ A worker exit automatically triggers cleanup, and terminal status waits for
46
+ that cleanup to be confirmed (or reports a cleanup error). On Linux the adapter
47
+ uses cgroup v2 automatically when the current user cgroup is writable; the
48
+ `required` mode fails startup if cgroup attachment is unavailable. Cgroup
49
+ cleanup kills descendants even when they call `setsid()` or create another
50
+ process group. Attachment occurs immediately after spawn, so a worker that
51
+ forks before attachment remains a documented startup-window limitation.
52
+
53
+ When cgroup v2 is unavailable, the adapter falls back to detached
54
+ process-group cleanup. That fallback is not recursive: `setsid()` descendants
55
+ can escape, and PID reuse between leader exit and cleanup is a host-level
56
+ limitation. Production deployments that require an atomic boundary should use a
57
+ service-manager scope, Job Object, pidfd-aware reaper, or equivalent supervisor.
58
+ The Pi host installs graceful `SIGTERM`/`SIGINT` handlers, but `SIGSTOP` and
59
+ `SIGKILL` cannot be handled; no orphan guarantee is claimed for those host-fatal
60
+ signals.
61
+
62
+ ## State machine
63
+
64
+ ```text
65
+ idle -> starting -> running -> waiting -> running -> verifying -> completed
66
+ | | | |
67
+ v v v v
68
+ paused failed stopped idle
69
+ ```
70
+
71
+ `stop` is available from `starting`, `running`, `waiting` and `paused`. Invalid
72
+ transitions fail closed. Supervisor lifecycle operations and their state/event
73
+ updates run through one serial queue, so concurrent `poll`, `send`, `stop`,
74
+ watchdog and shutdown work cannot produce duplicate terminal transitions. If a
75
+ lifecycle event append fails after the state transition, it remains pending and
76
+ is retried before the next lifecycle operation; output events restore their
77
+ chunks for a lossless retry.
78
+
79
+ ## Event log
80
+
81
+ Events are JSONL with a monotonic sequence number, timestamp, task ID and worker
82
+ ID. Appends use a per-log atomic lock directory with owner PID, bounded waiting
83
+ and stale-owner detection. Each append refreshes the sequence from disk while
84
+ holding the lock, so independent Pi processes cannot reuse sequence numbers.
85
+ The log is diagnostic evidence, not an authorization mechanism. Log contents
86
+ must be treated as sensitive because worker output may contain repository data.
87
+
88
+ For Claude JSONL, the adapter tracks `activeRequests`, `lastInputAt` and
89
+ `lastOutputAt`. A `result` record closes an active request; malformed output does
90
+ not. JSONL sends are rejected while a request is active, and a valid terminal
91
+ result moves the session to `waiting`; only then may the next turn be sent.
92
+ Input writes are serialized with stop and are acknowledged through the stream
93
+ write callback before their idempotency key is consumed. Writes have a bounded
94
+ timeout, and `stop()` preempts a queued lifecycle operation by initiating adapter
95
+ termination immediately. This status is observable by `poll` and prevents blind
96
+ duplicate turns. The adapter also exposes event subscriptions for `result`,
97
+ `control_request`, permission requests and process exit. Automatic mode routes
98
+ those events to a persistent, read-only Pi Decision Worker; its Pi session JSONL
99
+ and task mapping are persisted under the supervisor state directory. After an
100
+ unclean Pi restart, recovery is explicit: `/supervise recover <task-id>` restores
101
+ the Decision Worker context and starts a new Claude Worker. It does not silently
102
+ resume or duplicate a task. It does not poll to detect turn completion. A watchdog timer remains only as a deadlock safety
103
+ fallback. Permission actions pass through `evaluatePermission` and can be
104
+ approved or denied manually with `/supervise approve`; human escalation is sent
105
+ to an outbound webhook when configured. If the Decision Worker API/model call
106
+ fails, the system records `decision_worker_failed` and directly alerts the
107
+ human operator; it does not attempt a second LLM fallback. Alert delivery is
108
+ kept independent from event-log persistence so an audit write failure cannot
109
+ suppress the alert.
110
+
111
+ ## Deliberate non-goals
112
+
113
+ - automatic merge/deploy/release;
114
+ - unauthenticated inbound webhook commands; outbound notifications do not grant
115
+ permission and do not replace Pi human takeover;
116
+ - treating an unknown Claude interactive question as safe to answer automatically;
117
+ - bypassing Claude Code permissions;
118
+ - accepting model text as verification;
119
+ - shell command interpolation;
120
+ - automatic network denial or a fake domain allowlist. Network access follows
121
+ Claude's own permission model and the command policy; suspicious download-to-
122
+ shell patterns require human review rather than blanket network rejection.