pi-claude-supervisor 0.5.1 → 0.5.2
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 +19 -0
- package/README.cn.md +15 -6
- package/README.md +20 -12
- package/docs/architecture.md +41 -11
- package/docs/automation-hardening-plan.md +211 -0
- package/docs/engineering-plan.md +24 -2
- package/docs/testing.md +59 -19
- package/package.json +1 -1
- package/src/decision-worker.ts +56 -9
- package/src/index.ts +29 -7
- package/src/redaction.ts +2 -1
- package/src/reviewer.ts +69 -16
- package/src/supervisor.ts +238 -37
- package/src/types.ts +6 -2
- package/src/verifier.ts +175 -20
- package/src/worker/process-adapter.ts +245 -47
- package/src/worker/tmux-adapter.ts +42 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented here.
|
|
4
4
|
|
|
5
|
+
## [0.5.2](https://github.com/btnalit/pi-claude-supervisor/compare/v0.5.1...v0.5.2) (2026-09-14)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* harden automatic review lifecycle ([fefa5c5](https://github.com/btnalit/pi-claude-supervisor/commit/fefa5c5b39fd2411b5e82df384074983252263ca))
|
|
11
|
+
|
|
5
12
|
## [0.5.1](https://github.com/btnalit/pi-claude-supervisor/compare/v0.5.0...v0.5.1) (2026-09-14)
|
|
6
13
|
|
|
7
14
|
|
|
@@ -18,6 +25,18 @@ All notable changes to this project will be documented here.
|
|
|
18
25
|
|
|
19
26
|
## [Unreleased]
|
|
20
27
|
|
|
28
|
+
### Hardening implemented in working tree (not yet released)
|
|
29
|
+
|
|
30
|
+
- Split JSONL in-process `repairableSession` from cross-restart `persistentSession` and eliminate duplicate terminal transitions.
|
|
31
|
+
- Make `verifying` stop/shutdown cleanup authoritative, with abortable acceptance and Reviewer operations.
|
|
32
|
+
- Pause and rebase the no-output watchdog clock across pause/resume while retaining the cumulative deadline.
|
|
33
|
+
- Include staged, unstaged and bounded untracked evidence in independent Review, with symlink/path safety and fail-closed completeness.
|
|
34
|
+
- Harden assistant-message output framing, startup/runtime preflight, permission gates, bounded acceptance buffers and lifecycle progress reporting.
|
|
35
|
+
|
|
36
|
+
### Remaining hardening gate
|
|
37
|
+
|
|
38
|
+
- Complete the exact-head independent read-only Review; the real editable Claude `2.1.270` repair/reacceptance drill and cleanup/lease evidence are recorded in `docs/automation-hardening-plan.md`.
|
|
39
|
+
|
|
21
40
|
### Added
|
|
22
41
|
|
|
23
42
|
- Structured task specifications with Goal, scope, constraints, forbidden actions and multiple argv-based acceptance checks.
|
package/README.cn.md
CHANGED
|
@@ -8,7 +8,12 @@
|
|
|
8
8
|
|
|
9
9
|
用于 Pi 的 Claude Code Worker 监督扩展。MVP 中 Pi 负责生命周期、状态机、策略门和独立验收;Worker 只是被显式启动的子进程。
|
|
10
10
|
|
|
11
|
-
>
|
|
11
|
+
> `v0.5.1` 已发布为单 Worker recovery 基线。默认手动 transport 是无额外依赖的
|
|
12
|
+
> process pipe,不是 PTY;自动模式只使用 Claude JSONL 或 tmux。当前工作树已实现
|
|
13
|
+
> repairable/persistent 能力拆分、可取消验收/Reviewer、证据完整性门禁、启动前
|
|
14
|
+
> preflight 和阶段进度通知;真实 Claude Code `2.1.270` 允许编辑的
|
|
15
|
+
> repair/reacceptance 演练已在隔离临时 worktree 通过,剩余发布门禁是 exact-head
|
|
16
|
+
> 独立只读 Review。低权限用户、OS sandbox 与网络隔离继续延期。
|
|
12
17
|
|
|
13
18
|
## 关键安全边界
|
|
14
19
|
|
|
@@ -16,12 +21,13 @@
|
|
|
16
21
|
- 不经过 shell 启动子进程。
|
|
17
22
|
- Worker 只继承最小环境;凭据必须由调用方显式传入。
|
|
18
23
|
- 破坏性命令和绕过权限的 Worker 参数默认拒绝;需要复核的启动命令会请求用户批准,不会一律拒绝。
|
|
19
|
-
- Linux 上优先使用可写的 cgroup v2 清理后代进程,包括 `setsid()` 后代;不可用时回退到进程组清理。需要强制失败闭环时,embedding 集成可使用 `cgroupMode: "required"
|
|
24
|
+
- Linux 上优先使用可写的 cgroup v2 清理后代进程,包括 `setsid()` 后代;不可用时回退到进程组清理。需要强制失败闭环时,embedding 集成可使用 `cgroupMode: "required"`,并会在 Claude 启动前执行 preflight。
|
|
20
25
|
- 普通联网查询不因联网本身被拒绝;下载后直接交给 shell 等高风险模式仍需人工复核。
|
|
21
26
|
- Worker 声称完成只会进入 `verifying`,不能作为成功证据。
|
|
22
27
|
- 默认独立验收命令为 `git diff --check`。
|
|
23
28
|
- 扩展运行时不执行 merge、deploy、release 或 publish;仓库 Release 只会在维护者合并 Release Please PR 且 CI 门禁全部通过后自动发布。
|
|
24
|
-
- 默认 4 小时总时限、20 分钟无输出 watchdog 超时即停止 Worker
|
|
29
|
+
- 默认 4 小时总时限、20 分钟无输出 watchdog 超时即停止 Worker;paused 期间不消耗无输出预算,resume 会重建基准但不会重置总时限。嵌入调用方可将对应选项设为 `0` 关闭。
|
|
30
|
+
- 验收命令、仓库证据收集和独立 Reviewer 共用 abort signal,人工 stop/shutdown 不必等待完整超时。
|
|
25
31
|
|
|
26
32
|
## 安装和使用
|
|
27
33
|
|
|
@@ -105,9 +111,12 @@ Worker 应使用 `adopt-tmux`,而不是 takeover。
|
|
|
105
111
|
`v0.5.0` 已完成并发布“多命令验收—独立只读 Reviewer—结构化修复轮次—再次验收”闭环。
|
|
106
112
|
任务可通过 API 或 JSON spec 提供 `goal`、`scope`、`constraints`、`forbidden` 和多个
|
|
107
113
|
`acceptance` 命令;旧的纯文本任务继续使用默认 `git diff --check`。Reviewer 只能使用
|
|
108
|
-
`read`、`grep`、`find`、`ls
|
|
109
|
-
|
|
110
|
-
|
|
114
|
+
`read`、`grep`、`find`、`ls`,不会修改工作树或批准权限。当前加固要求 HEAD-relative
|
|
115
|
+
tracked diff 和受限 untracked evidence 完整,P0/P1 或重复 finding 必须人工处理;自动模式
|
|
116
|
+
拒绝显式 process-pipe,并在模型执行前检查目录、可执行文件、依赖和 cgroup。剩余门禁是
|
|
117
|
+
固定 Claude Code `2.1.270` 隔离 worktree 的真实 repair/reacceptance 已通过,当前只剩
|
|
118
|
+
exact-head 独立只读 Review;协同多 Worker 属于后续独立开发阶段,暂不把 sandbox、低权限
|
|
119
|
+
和网络隔离作为本阶段门禁。
|
|
111
120
|
|
|
112
121
|
### tmux/PTY 交互模式
|
|
113
122
|
|
package/README.md
CHANGED
|
@@ -10,11 +10,15 @@ A policy-gated [Pi](https://pi.dev) extension for supervising a Claude Code work
|
|
|
10
10
|
The MVP keeps Pi in control of lifecycle, state, policy and verification while the
|
|
11
11
|
worker remains an explicitly started child process.
|
|
12
12
|
|
|
13
|
-
> **
|
|
14
|
-
>
|
|
15
|
-
>
|
|
16
|
-
>
|
|
17
|
-
>
|
|
13
|
+
> **Release status:** `v0.5.1` is the released single-Worker recovery baseline. The
|
|
14
|
+
> default manual transport is dependency-free process pipes, not PTY. Automatic
|
|
15
|
+
> supervision uses Claude JSONL or tmux, and the current working-tree hardening
|
|
16
|
+
> adds repairable-vs-persistent capabilities, cancellable verification, evidence
|
|
17
|
+
> completeness gates, startup preflight and phase progress reporting. A real
|
|
18
|
+
> edit-capable Claude Code `2.1.270` repair/reacceptance drill has passed in an
|
|
19
|
+
> isolated temporary worktree; the exact-head independent review is the remaining
|
|
20
|
+
> release gate. OS sandbox, low-privilege execution and network isolation remain
|
|
21
|
+
> deferred.
|
|
18
22
|
|
|
19
23
|
## Safety boundary
|
|
20
24
|
|
|
@@ -27,7 +31,8 @@ worker remains an explicitly started child process.
|
|
|
27
31
|
- Verification is an independent host command (default: `git diff --check`).
|
|
28
32
|
- 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
33
|
- 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
|
|
34
|
+
- 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 `cgroupMode: "required"` for a fail-closed integration; required mode is preflighted before Claude starts.
|
|
35
|
+
- Acceptance commands, repository evidence collection and independent Review share an abort signal, so operator stop/shutdown does not wait for a full command or model timeout.
|
|
31
36
|
- Events are append-only JSONL records in `~/.pi/agent/claude-supervisor/events.jsonl`.
|
|
32
37
|
|
|
33
38
|
## Install
|
|
@@ -114,12 +119,15 @@ The `v0.5.0` automation milestone adds a structured acceptance pipeline:
|
|
|
114
119
|
multiple argv-based checks, an independent read-only Reviewer, bounded structured
|
|
115
120
|
findings and repair rounds. Legacy text tasks keep the default `git diff --check`.
|
|
116
121
|
The Reviewer only has `read`, `grep`, `find` and `ls`; it cannot edit files or grant
|
|
117
|
-
permissions. The
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
122
|
+
permissions. The current hardening also requires complete HEAD-relative tracked and
|
|
123
|
+
bounded untracked evidence, rejects P0/P1 or repeated findings, and only repairs a
|
|
124
|
+
live `repairableSession` Worker. Automatic mode rejects explicit `process-pipe` and
|
|
125
|
+
preflights runtime prerequisites. The real pinned Claude Code `2.1.270` disposable repair/reacceptance run has passed;
|
|
126
|
+
the remaining gate is the exact-head independent review.
|
|
127
|
+
Coordinated multi-worker scheduling is a later milestone; CI uses deterministic fake
|
|
128
|
+
Workers/replay fixtures, and real multi-worker Claude tests remain authenticated
|
|
129
|
+
manual Spikes. CLI multi-version compatibility, sandboxing, low-privilege execution
|
|
130
|
+
and network isolation are not part of this milestone.
|
|
123
131
|
|
|
124
132
|
Automatic mode persists the Pi Decision Worker session under the configured state
|
|
125
133
|
directory. After an unclean Pi restart, `/supervise sessions` lists recoverable
|
package/docs/architecture.md
CHANGED
|
@@ -59,6 +59,13 @@ recovery, not by relaxing the current cwd lease rule.
|
|
|
59
59
|
- idempotency keys for messages;
|
|
60
60
|
- no session-resume claim.
|
|
61
61
|
|
|
62
|
+
Worker capabilities distinguish two different properties. `persistentSession` means that a
|
|
63
|
+
Worker can remain usable across a Pi disconnect/restart and can be explicitly re-adopted;
|
|
64
|
+
`repairableSession` means that the current Supervisor can send another bounded turn after a
|
|
65
|
+
verification/review result. Claude JSONL is repairable while attached but does not claim
|
|
66
|
+
cross-restart resume. Tmux is both repairable and persistent. The Supervisor must never infer
|
|
67
|
+
one capability from the other.
|
|
68
|
+
|
|
62
69
|
This is a control-boundary fixture and headless transport. It does not emulate a
|
|
63
70
|
terminal. Manual compatibility mode remains `process-pipe`; automatic mode
|
|
64
71
|
(`PI_CLAUDE_SUPERVISOR_MODE=auto`) defaults to Claude JSONL and uses the CLI
|
|
@@ -68,7 +75,8 @@ screen-based.
|
|
|
68
75
|
A worker exit automatically triggers cleanup, and terminal status waits for
|
|
69
76
|
that cleanup to be confirmed (or reports a cleanup error). On Linux the adapter
|
|
70
77
|
uses cgroup v2 automatically when the current user cgroup is writable; the
|
|
71
|
-
`required` mode
|
|
78
|
+
`required` mode performs a preflight and fails before Claude starts if cgroup
|
|
79
|
+
attachment or cleanup is unavailable. Cgroup
|
|
72
80
|
cleanup kills descendants even when they call `setsid()` or create another
|
|
73
81
|
process group. Attachment occurs immediately after spawn, so a worker that
|
|
74
82
|
forks before attachment remains a documented startup-window limitation.
|
|
@@ -78,9 +86,11 @@ process-group cleanup. That fallback is not recursive: `setsid()` descendants
|
|
|
78
86
|
can escape, and PID reuse between leader exit and cleanup is a host-level
|
|
79
87
|
limitation. Production deployments that require an atomic boundary should use a
|
|
80
88
|
service-manager scope, Job Object, pidfd-aware reaper, or equivalent supervisor.
|
|
81
|
-
|
|
82
|
-
`
|
|
83
|
-
|
|
89
|
+
Pi owns graceful `SIGTERM`/`SIGINT` handling and invokes the extension's
|
|
90
|
+
`session_shutdown` hook. The extension does not install a second `process.exit()`
|
|
91
|
+
handler, avoiding races with Pi terminal restoration and other extensions. `SIGSTOP`
|
|
92
|
+
and `SIGKILL` cannot be handled; no orphan guarantee is claimed for those
|
|
93
|
+
host-fatal signals.
|
|
84
94
|
|
|
85
95
|
## tmux/PTY transport
|
|
86
96
|
|
|
@@ -130,10 +140,12 @@ idle -> starting -> running -> waiting -> running -> verifying -> completed
|
|
|
130
140
|
| | | |
|
|
131
141
|
v v v v
|
|
132
142
|
paused failed stopped idle
|
|
143
|
+
verifying -> stopped
|
|
133
144
|
```
|
|
134
145
|
|
|
135
|
-
`stop` is available from `starting`, `running`, `waiting` and `
|
|
136
|
-
|
|
146
|
+
`stop` is available from `starting`, `running`, `waiting`, `paused` and `verifying`.
|
|
147
|
+
A stop request from `verifying` is cleanup-authoritative and takes precedence over a
|
|
148
|
+
verification result that has not yet been finalized. Invalid transitions fail closed. Supervisor lifecycle operations and their state/event
|
|
137
149
|
updates run through one serial queue, so concurrent `poll`, `send`, `stop`,
|
|
138
150
|
watchdog and shutdown work cannot produce duplicate terminal transitions. If a
|
|
139
151
|
lifecycle event append fails after the state transition, it remains pending and
|
|
@@ -166,6 +178,14 @@ is alive; the extension periodically rechecks released sessions and removes the
|
|
|
166
178
|
lease only after the pane is confirmed gone. If that check fails, the lease is
|
|
167
179
|
retained rather than allowing a cwd overlap.
|
|
168
180
|
|
|
181
|
+
Before model or Worker execution, automatic starts preflight the validated cwd,
|
|
182
|
+
worker executable, transport dependencies, runtime state/lease directories and,
|
|
183
|
+
when requested, the real writable cgroup-v2 boundary. A failed preflight is
|
|
184
|
+
fail-closed and does not start Claude. Long acceptance commands and Reviewer
|
|
185
|
+
sessions share an abort signal with the Supervisor, so operator stop/shutdown
|
|
186
|
+
wins without waiting for a full check timeout. Progress hooks expose starting,
|
|
187
|
+
Worker heartbeat, acceptance, review, repair and human-gate phases in the Pi UI.
|
|
188
|
+
|
|
169
189
|
Startup owns an `AbortController` and passes its signal to the adapter. A stop
|
|
170
190
|
or shutdown request aborts the controller and calls the adapter's out-of-band
|
|
171
191
|
startup cleanup without waiting behind the serialized start operation. Each
|
|
@@ -186,7 +206,9 @@ must be treated as sensitive because worker output may contain repository data.
|
|
|
186
206
|
For Claude JSONL, the adapter tracks `activeRequests`, `lastInputAt` and
|
|
187
207
|
`lastOutputAt`. A `result` record closes an active request; malformed output does
|
|
188
208
|
not. JSONL sends are rejected while a request is active, and a valid terminal
|
|
189
|
-
result moves the session to `waiting`; only then may the next turn be sent.
|
|
209
|
+
result moves the session to `waiting`; only then may the next turn be sent. A paused
|
|
210
|
+
Worker does not consume its no-output budget; resume establishes a fresh no-output
|
|
211
|
+
baseline while the cumulative wall-clock deadline remains active.
|
|
190
212
|
Input writes are serialized with stop and are acknowledged through the stream
|
|
191
213
|
write callback before their idempotency key is consumed. Writes have a bounded
|
|
192
214
|
timeout, and `stop()` preempts a queued lifecycle operation by initiating adapter
|
|
@@ -224,11 +246,19 @@ conversation or control channel. It can inspect only `read`, `grep`, `find` and
|
|
|
224
246
|
output or a Reviewer API failure is a human-required condition.
|
|
225
247
|
|
|
226
248
|
A `revise` result produces an audited repair round and sends a bounded corrective
|
|
227
|
-
instruction to a still-live
|
|
249
|
+
instruction to a still-live `repairableSession` Worker. Checks and review then run again.
|
|
228
250
|
The repair budget defaults to three rounds; repeated findings and P0/P1 findings
|
|
229
|
-
stop automation and escalate. A
|
|
230
|
-
|
|
231
|
-
|
|
251
|
+
stop automation and escalate. A Worker that has already exited cannot be silently recreated
|
|
252
|
+
for repair; it remains failed/recoverable rather than replaying the original task. If a repair
|
|
253
|
+
or human-review branch cannot continue, a single idempotent terminalizer records
|
|
254
|
+
`verification_failed`, closes the Decision Worker and reports cleanup evidence; it never performs
|
|
255
|
+
a second `failed -> failed` transition.
|
|
256
|
+
|
|
257
|
+
Repository evidence is HEAD-relative: tracked staged and unstaged changes are collected together,
|
|
258
|
+
and untracked regular files are included through bounded, component-safe, no-symlink reads. Incomplete or
|
|
259
|
+
truncated evidence is not sufficient for an independent `pass` verdict. Acceptance
|
|
260
|
+
process output uses a bounded execution buffer before the smaller persisted evidence
|
|
261
|
+
limit, so a normal large test report is not misclassified as a failed command.
|
|
232
262
|
|
|
233
263
|
## Deliberate non-goals
|
|
234
264
|
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# 自动化稳定性与生命周期加固计划
|
|
2
|
+
|
|
3
|
+
> 计划状态:Phase A–D 已在当前工作树实现;真实可编辑 repair/reacceptance 已通过,待 exact-head 独立只读 Review 作为发布前最后门禁
|
|
4
|
+
> 基线:`v0.5.1` / `26443f0`
|
|
5
|
+
> 真实验证:Claude Code `2.1.270`
|
|
6
|
+
> 记录日期:2026-09-14
|
|
7
|
+
|
|
8
|
+
## 1. 实际演练结论
|
|
9
|
+
|
|
10
|
+
本轮真实演练完成了以下链路:
|
|
11
|
+
|
|
12
|
+
```text
|
|
13
|
+
真实 Claude Code Worker
|
|
14
|
+
-> Decision Worker 判断完成
|
|
15
|
+
-> argv/execFile 验收
|
|
16
|
+
-> 独立只读 Reviewer
|
|
17
|
+
-> P1/P2 阻塞发现
|
|
18
|
+
-> fail-closed / human intervention
|
|
19
|
+
-> Worker、Pi、lease 清理
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
六项验收全部通过:
|
|
23
|
+
|
|
24
|
+
- `git diff --check`
|
|
25
|
+
- `npm run check`
|
|
26
|
+
- `npm run check:workflows`
|
|
27
|
+
- `npm run test:pi`
|
|
28
|
+
- `npm run test:install`
|
|
29
|
+
- `npm run build`
|
|
30
|
+
|
|
31
|
+
本次任务明确使用只读 Claude 权限并设置 `maxRepairRounds=0`,因此没有进入真实的
|
|
32
|
+
repair/reacceptance。现有 replay 测试覆盖了模拟 repair,但没有覆盖真实
|
|
33
|
+
`ProcessWorkerAdapter` 能力矩阵。
|
|
34
|
+
|
|
35
|
+
完整事件证据位于本机临时目录:
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
/tmp/pi-claude-supervisor-real-state-3/events.jsonl
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 1.1 Phase D:真实可编辑 repair/reacceptance
|
|
42
|
+
|
|
43
|
+
在不触碰主仓库的临时 Git 工作树中,使用真实 Claude Code `2.1.270` 和
|
|
44
|
+
`ProcessWorkerAdapter(mode=claude-jsonl, cgroup=off)` 完成了一个 bounded repair:
|
|
45
|
+
|
|
46
|
+
- task:`cd39ed51-6003-4aad-8518-ebd6ab5de7e7`;`maxRepairRounds=1`。
|
|
47
|
+
- Worker 首轮只创建 `add.mjs`;第一次 `node check.mjs` 按 drill 设计失败并给出
|
|
48
|
+
`repair required`。
|
|
49
|
+
- Supervisor 发送 repair round 1;真实 Worker 创建 `add.test.mjs`。
|
|
50
|
+
- 第二轮验收通过,独立只读 Reviewer 返回 `pass`,没有 human intervention。
|
|
51
|
+
- 最终状态为 `completed`;Worker 状态为 `running=false`、`exitReason=stopped`、
|
|
52
|
+
`processGroupCleaned=true`;Decision Worker closure 为 `cleanupConfirmed=true`。
|
|
53
|
+
- UI progress 覆盖 `starting -> worker -> acceptance(failed) -> repair -> worker ->
|
|
54
|
+
acceptance(passed) -> review -> completed`,并包含 Worker heartbeat。
|
|
55
|
+
- Cwd lease 在 Worker 启动后记录了 PID/start time;结束后 `leaseAfterRelease=[]`,
|
|
56
|
+
未留下 lease。
|
|
57
|
+
|
|
58
|
+
事件序列为:
|
|
59
|
+
|
|
60
|
+
```text
|
|
61
|
+
task_started -> worker_started -> worker_output -> worker_waiting -> decision_made
|
|
62
|
+
-> acceptance_started -> acceptance_check_finished -> acceptance_result
|
|
63
|
+
-> repair_requested -> worker_message_sent -> worker_output -> worker_waiting
|
|
64
|
+
-> decision_made -> acceptance_started -> acceptance_check_finished -> acceptance_result
|
|
65
|
+
-> review_started -> review_result -> review_finished -> verification_passed
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
证据归档位置(均在主仓库之外):
|
|
69
|
+
|
|
70
|
+
```text
|
|
71
|
+
/tmp/pi-cs-repair4-runtime-X6MLob/events.jsonl
|
|
72
|
+
/tmp/pi-cs-repair4-runtime-X6MLob/decision/
|
|
73
|
+
/tmp/pi-cs-repair4-runtime-X6MLob/leases/ # 结束时为空
|
|
74
|
+
/tmp/pi-cs-repair4.log
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## 2. 正式发现与复现结果
|
|
78
|
+
|
|
79
|
+
### P1-1:非持久 JSONL repair 会触发非法状态转换
|
|
80
|
+
|
|
81
|
+
`ProcessWorkerAdapter` 的 JSONL Worker 没有 `persistentSession`,Supervisor 在验收前停止
|
|
82
|
+
Worker;验收失败或 Reviewer `revise` 后,`requestRepair()` 先执行
|
|
83
|
+
`verifying -> failed`,调用方又执行 `failed -> failed`。
|
|
84
|
+
|
|
85
|
+
已用非持久 JSONL fake adapter 复现:
|
|
86
|
+
|
|
87
|
+
```text
|
|
88
|
+
InvalidTransitionError: Invalid supervisor transition: failed -> failed
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
根本修复不是把 JSONL 伪装成可跨重启恢复,而是把 Worker 能力拆成:
|
|
92
|
+
|
|
93
|
+
- `persistentSession`:能否在 Pi 重启/断开后继续存在;
|
|
94
|
+
- `repairableSession`:当前 Supervisor 生命周期内能否继续发送 repair turn。
|
|
95
|
+
|
|
96
|
+
JSONL 可以是 `repairableSession=true`、`persistentSession=false`;tmux 两者都可以为
|
|
97
|
+
`true`。终结和人工介入必须通过单一幂等路径完成,不能由 `requestRepair()` 和
|
|
98
|
+
`finalizeVerification()` 重复转换终态。
|
|
99
|
+
|
|
100
|
+
### P1-2:`verifying` 状态下 stop 无效
|
|
101
|
+
|
|
102
|
+
当前 `stop()` 和 `#stopInternal()` 没有处理 `verifying`。已复现:
|
|
103
|
+
|
|
104
|
+
```text
|
|
105
|
+
before stop: verifying
|
|
106
|
+
adapter.stop calls: 0
|
|
107
|
+
after stop: verifying
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
结果可能是 Decision Worker 未关闭、Pi shutdown 不释放 cwd lease、后续任务被错误地
|
|
111
|
+
判定为 cwd 冲突。
|
|
112
|
+
|
|
113
|
+
修复要求:`verifying` 支持 stop、cleanup、`worker_stopped` 事件、Decision Worker
|
|
114
|
+
关闭、closure callback 和 lease 回收;并确保人工 stop 优先于正在完成的 verification。
|
|
115
|
+
|
|
116
|
+
### P2-1:paused Worker 仍触发 no-output watchdog
|
|
117
|
+
|
|
118
|
+
`SIGSTOP` 后 Worker 本来就不会产生输出,但 watchdog 仍把 `paused` 纳入 no-output
|
|
119
|
+
计算。使用 50ms timeout 暂停 1.25s 已复现 Worker 被停止。
|
|
120
|
+
|
|
121
|
+
修复要求:暂停期间暂停 no-output 时钟;resume 时重建基准;wall-clock deadline 仍然
|
|
122
|
+
保持累计,不允许通过 pause 绕过总时限。
|
|
123
|
+
|
|
124
|
+
### P2-2:Reviewer diff evidence 遗漏 staged 和 untracked 内容
|
|
125
|
+
|
|
126
|
+
当前使用 unstaged-only 的 `git diff`。已复现:
|
|
127
|
+
|
|
128
|
+
```text
|
|
129
|
+
status: M tracked.txt / ?? new.txt
|
|
130
|
+
diff: (none)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
修复要求:tracked 文件使用 `git diff HEAD`,额外安全读取 untracked regular files,
|
|
134
|
+
拒绝 symlink,限制单文件和总证据大小;证据不完整或被截断时 Reviewer 不得返回
|
|
135
|
+
`pass`。
|
|
136
|
+
|
|
137
|
+
## 3.1 当前实现状态
|
|
138
|
+
|
|
139
|
+
已完成并有确定性回归覆盖:
|
|
140
|
+
|
|
141
|
+
- `repairableSession` 与 `persistentSession` 已分离;JSONL 仅支持当前进程内 repair,tmux 才声明持久恢复。
|
|
142
|
+
- `verifying` 的 stop/shutdown 使用统一 cleanup/finalize 路径,人工 stop 优先于验收结果,cleanup 不确定时保留恢复记录。
|
|
143
|
+
- paused Worker 不消耗 no-output watchdog;resume 重建 no-output 基准,但不重置累计 deadline。
|
|
144
|
+
- Reviewer evidence 使用 `git diff HEAD`、受限 untracked regular-file 内容、路径组件/symlink 门禁,并对 incomplete/truncated fail-closed。
|
|
145
|
+
- Acceptance 子进程、证据收集和 Reviewer 共享 abort signal;Pi UI 可看到 startup、Worker heartbeat、acceptance、review、repair 和 human phases。
|
|
146
|
+
- 自动模式启动前检查运行目录、cwd、Worker/tmux 可执行文件、transport 依赖和 required cgroup;显式 `process-pipe` 不再进入自动模式。
|
|
147
|
+
- Reviewer/Decision Worker 只解析 assistant message 边界的最终文本;permission pending 会在自动和人工响应后清除,独立 human gate 不会被错误解除;扩大的 exec buffer 避免普通大测试报告被误判为命令失败。
|
|
148
|
+
|
|
149
|
+
仍待完成:
|
|
150
|
+
|
|
151
|
+
- 对当前 exact head 执行最后一次独立只读 Review;该 Review 必须不编辑、不运行命令、不发送 Worker 输入、不提交或发布。
|
|
152
|
+
- Review 通过且完整质量门禁再次通过后,才允许人工决定是否提交、合并或发布;本轮仍不自动 release/publish。
|
|
153
|
+
|
|
154
|
+
## 4. 实施顺序
|
|
155
|
+
|
|
156
|
+
### Phase A:生命周期和能力模型(最高优先级)
|
|
157
|
+
|
|
158
|
+
1. 增加 `repairableSession` capability。
|
|
159
|
+
2. JSONL 在当前 Supervisor 生命周期内支持 repair,仍不声明跨重启恢复。
|
|
160
|
+
3. 重构 repair/finalize/human 分支,保证终态转换和 Decision Worker closure 幂等。
|
|
161
|
+
4. `verifying` 支持 stop/shutdown,保留 cleanup 不确定时的 lease。
|
|
162
|
+
5. 增加真实非持久 adapter 和 stop-from-verifying 测试。
|
|
163
|
+
|
|
164
|
+
### Phase B:watchdog 与证据完整性
|
|
165
|
+
|
|
166
|
+
1. paused no-output 时钟暂停,resume 重建基准。
|
|
167
|
+
2. HEAD-relative diff 覆盖 staged/unstaged tracked 修改。
|
|
168
|
+
3. 安全收集 untracked regular-file evidence,防 symlink 和路径逃逸。
|
|
169
|
+
4. evidence truncation/incomplete 强制 human。
|
|
170
|
+
|
|
171
|
+
### Phase C:自动化协议和运行前保护
|
|
172
|
+
|
|
173
|
+
1. Reviewer/Decision Worker 按 assistant message 边界解析最终响应,不拼接所有工具回合文字。
|
|
174
|
+
2. 自动模式启动前执行 transport、Claude、cgroup、state/lease 目录 preflight。
|
|
175
|
+
3. 区分 Worker heartbeat、验收、Reviewer、repair 阶段,并提高实时可观测性。
|
|
176
|
+
4. 修复自动 permission 响应后的 stale pending request 和错误清除 human gate。
|
|
177
|
+
5. 清理 Pi extension 自己安装的 signal handler,避免与 Pi `session_shutdown` 竞争。
|
|
178
|
+
|
|
179
|
+
### Phase D:回归、真实演练和发布门禁
|
|
180
|
+
|
|
181
|
+
1. 扩展 acceptance/replay/capability 矩阵。
|
|
182
|
+
2. 在临时 worktree 中使用真实 Claude 做一次受控 repair/reacceptance;禁止触碰主仓库。
|
|
183
|
+
3. 运行 `npm run check`、Pi/npm smoke、build 和真实只读 review。
|
|
184
|
+
4. 只有独立 Reviewer `pass`、所有检查通过、cleanup/lease 证据完整后,才允许人工
|
|
185
|
+
决定是否提交、合并或发布。
|
|
186
|
+
|
|
187
|
+
## 5. 验收矩阵
|
|
188
|
+
|
|
189
|
+
| 场景 | 预期 |
|
|
190
|
+
|---|---|
|
|
191
|
+
| JSONL Worker alive + P2 revise | 发送一次 bounded repair,重新验收 |
|
|
192
|
+
| JSONL Worker 已退出 + 验收失败 | 不抛非法 transition,记录 `verification_failed`,升级人工 |
|
|
193
|
+
| Reviewer `human` + Worker alive | 保持 Worker 可人工接管,不自动继续 |
|
|
194
|
+
| Reviewer `human` + Worker 已退出 | 完成 cleanup、关闭 Decision Worker、保留 recoverable record |
|
|
195
|
+
| `stop()` from `verifying` | `stopped`、cleanup confirmed 后释放 lease |
|
|
196
|
+
| shutdown from `verifying` | 不泄漏 Worker、Decision Worker 或 cwd lease |
|
|
197
|
+
| pause 超过 no-output timeout | 仍保持 paused |
|
|
198
|
+
| resume 后无输出 | 从 resume 时刻重新计算 timeout |
|
|
199
|
+
| staged + untracked 修改 | Reviewer evidence 包含两者 |
|
|
200
|
+
| evidence 截断/不可验证 | Reviewer 只能返回 human |
|
|
201
|
+
| malformed/multi-message model output | 不误判为 pass/action |
|
|
202
|
+
| preflight 失败 | Claude 尚未启动前 fail-closed |
|
|
203
|
+
|
|
204
|
+
## 6. 明确不改变的安全边界
|
|
205
|
+
|
|
206
|
+
- Reviewer 继续只允许 `read`、`grep`、`find`、`ls`。
|
|
207
|
+
- 验收命令继续使用 argv 和 `execFile`,不经过 shell 拼接。
|
|
208
|
+
- 不伪造 Claude `--resume`;`resumeSession` 仍然是明确能力声明。
|
|
209
|
+
- 不自动 merge、deploy、release 或 publish。
|
|
210
|
+
- 不允许多 Worker 共享同一可写 worktree。
|
|
211
|
+
- P0/P1、重复 finding、超时、API 错误、无效输出和不完整证据继续 fail-closed。
|
package/docs/engineering-plan.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Pi Claude Supervisor 完整方案
|
|
2
2
|
|
|
3
|
-
> 文档状态:`v0.5.
|
|
3
|
+
> 文档状态:`v0.5.1` 已发布;Phase A–D 加固和真实 repair/reacceptance 已在当前工作树实现;待 exact-head 独立只读 Review 门禁
|
|
4
4
|
> 目标项目目录:`pi-claude-supervisor`
|
|
5
5
|
> 适用对象:W、项目负责人、实现人员、评审人员
|
|
6
6
|
|
|
@@ -36,7 +36,7 @@ Claude Code Worker
|
|
|
36
36
|
4. Supervisor 因误判导致无限循环、危险操作或不可审计的修改。
|
|
37
37
|
5. 人工无法随时接管或恢复任务。
|
|
38
38
|
|
|
39
|
-
**当前状态:`v0.5.
|
|
39
|
+
**当前状态:`v0.5.1` 已正式发布,已完成固定 Claude Code `2.1.270` 稳定性统计、单 Worker recovery、真实只读 Review drill 和隔离临时 worktree 的允许编辑 repair/reacceptance drill。当前工作树已落实 repairable/persistent 能力拆分、verifying stop、paused watchdog、完整 repository evidence、可取消验收/Reviewer、启动 preflight、权限门禁修复和阶段进度通知;下一项也是发布前最后硬门禁的是当前 exact head 的独立只读 Review。协同多 Worker 仍延期;低权限用户、OS sandbox 与网络隔离仍是后续安全加固。**
|
|
40
40
|
|
|
41
41
|
---
|
|
42
42
|
|
|
@@ -1030,3 +1030,25 @@ Reviewer 必须使用独立 Pi session,只允许 `read`、`grep`、`find`、`l
|
|
|
1030
1030
|
- CLI 多版本兼容矩阵;
|
|
1031
1031
|
- OS sandbox、低权限执行、网络隔离/allowlist;
|
|
1032
1032
|
- 更深的供应链、SBOM、密钥隔离和生产监控。
|
|
1033
|
+
|
|
1034
|
+
## 22. v0.5.1 真实演练后的自动化加固计划
|
|
1035
|
+
|
|
1036
|
+
`v0.5.1` 发布后的真实 Claude Code `2.1.270` 演练完成了
|
|
1037
|
+
Worker → 验收 → 独立 Reviewer → fail-closed 人工介入链路。验收六项全部通过,
|
|
1038
|
+
但发现两个 P1 和两个 P2 生命周期/证据问题。正式记录、复现结果、实施阶段和门禁
|
|
1039
|
+
见 [`docs/automation-hardening-plan.md`](automation-hardening-plan.md)。
|
|
1040
|
+
|
|
1041
|
+
本轮实现顺序固定为:
|
|
1042
|
+
|
|
1043
|
+
1. **生命周期与能力模型**:拆分 `persistentSession` 与 `repairableSession`,修复非持久
|
|
1044
|
+
JSONL repair 的非法终态转换,并支持 `verifying` 状态的 stop/shutdown;
|
|
1045
|
+
2. **watchdog 与证据完整性**:暂停 no-output 时钟,补齐 HEAD-relative staged/unstaged
|
|
1046
|
+
diff 和安全的 untracked evidence;
|
|
1047
|
+
3. **自动化协议**:按 assistant message 边界解析 Reviewer/Decision Worker 输出,增加
|
|
1048
|
+
启动 preflight、可观测 heartbeat、permission gate 一致性和 signal 生命周期;
|
|
1049
|
+
4. **验证门禁**:已补齐真实 capability 矩阵并完成隔离 worktree 的真实
|
|
1050
|
+
repair/reacceptance 演练;当前 exact-head 独立 Reviewer 通过前不进行任何合并或发布。
|
|
1051
|
+
|
|
1052
|
+
本轮不放宽以下边界:Reviewer 仍只读,验收仍使用 argv/`execFile`,不伪造 Claude
|
|
1053
|
+
`--resume`,不自动 merge/deploy/release,P0/P1、重复 finding、超时、API 错误和不完整
|
|
1054
|
+
证据继续 fail-closed。多 Worker 协作继续后置。
|
package/docs/testing.md
CHANGED
|
@@ -65,7 +65,10 @@ cause a later run to fail closed as human-required after the bounded Decision
|
|
|
65
65
|
Worker or Reviewer timeout; this is evidence for the manual spike only, not a CI
|
|
66
66
|
guarantee.
|
|
67
67
|
The extension persists each automatic Decision Worker session as Pi JSONL plus a
|
|
68
|
-
0600 task mapping.
|
|
68
|
+
0600 task mapping. Automatic startup preflights the state/lease directories, cwd,
|
|
69
|
+
worker executable, transport dependency and required cgroup boundary before model
|
|
70
|
+
execution. Progress callbacks expose the current phase and periodic Worker
|
|
71
|
+
heartbeat. Recovery is explicit and safe: after an unclean Pi restart,
|
|
69
72
|
`/supervise sessions` shows the task as `recoverable`, and `/supervise recover
|
|
70
73
|
[--takeover] <task-id>` restores the Decision Worker history before starting a new
|
|
71
74
|
Claude Worker. `--takeover` is accepted only when the old Pi owner is dead, the
|
|
@@ -120,7 +123,9 @@ escalation is outbound-only through `PI_CLAUDE_SUPERVISOR_HUMAN_WEBHOOK_URL`;
|
|
|
120
123
|
approval callbacks are deliberately not accepted without a separately
|
|
121
124
|
authenticated endpoint.
|
|
122
125
|
|
|
123
|
-
The tmux transport is selected with `PI_CLAUDE_SUPERVISOR_TRANSPORT=tmux`.
|
|
126
|
+
The tmux transport is selected with `PI_CLAUDE_SUPERVISOR_TRANSPORT=tmux`.
|
|
127
|
+
Automatic mode rejects an explicit `process-pipe` transport; use JSONL or tmux for
|
|
128
|
+
bounded decisions and repair. Before
|
|
124
129
|
release, verify: private-socket attach, multi-line paste, prompt stability while
|
|
125
130
|
Claude is busy, trust/permission dialog takeover, duplicate send prevention, pane
|
|
126
131
|
replacement refusal, pause/resume, owned-session stop, adopted-session
|
|
@@ -137,29 +142,38 @@ response.
|
|
|
137
142
|
|
|
138
143
|
The automated adapter matrix covers external `SIGTERM`, `SIGINT`, `SIGKILL`,
|
|
139
144
|
`SIGSTOP`/`SIGCONT`, SIGTERM refusal/escalation, leader-early-exit descendant
|
|
140
|
-
cleanup, required cgroup
|
|
141
|
-
|
|
142
|
-
JSONL results. The Supervisor
|
|
143
|
-
retrying failed lifecycle events, preserving startup event
|
|
144
|
-
persistent timeout-event failure, and restoring output
|
|
145
|
-
|
|
145
|
+
cleanup, required cgroup bootstrap containment of a pre-attachment detached
|
|
146
|
+
and `setsid()` descendant, repeated stop, spawn failure, output truncation,
|
|
147
|
+
blocked stdin write timeouts, and immediate JSONL results. The Supervisor
|
|
148
|
+
matrix also covers retrying failed lifecycle events, preserving startup event
|
|
149
|
+
order, stopping under persistent timeout-event failure, and restoring output
|
|
150
|
+
after event-log failure. The Supervisor matrix covers startup rejection,
|
|
151
|
+
externally terminated workers, lifecycle serialization and stop races.
|
|
146
152
|
|
|
147
153
|
Before release, manually test at least: immediate crash, hung process, malformed
|
|
148
154
|
output, duplicate send, send/exit race, Pi `SIGTERM`/`SIGINT` shutdown,
|
|
149
155
|
verification failure, blocked stdin writes/stop preemption, corrupt event-log
|
|
150
156
|
tails, and descendants that call `setsid()` when cgroup mode is unavailable (expected
|
|
151
|
-
fallback limitation).
|
|
152
|
-
|
|
153
|
-
|
|
157
|
+
fallback limitation). In cgroup mode, a small bootstrap joins the cgroup before
|
|
158
|
+
launching Worker code, and cleanup also validates and reaps the detached process
|
|
159
|
+
group; this closes the post-spawn attachment window. `SIGSTOP` and `SIGKILL` of
|
|
160
|
+
the Pi host cannot be handled; verify and document the resulting orphan behavior.
|
|
154
161
|
Default behavior must be fail-closed and leave no orphaned worker process within
|
|
155
162
|
the managed process group.
|
|
156
163
|
|
|
157
164
|
## Near-term automation acceptance gate
|
|
158
165
|
|
|
159
166
|
The `v0.5.0` implementation of the acceptance—independent Review—repair—reacceptance
|
|
160
|
-
loop is shipped. The
|
|
161
|
-
|
|
162
|
-
|
|
167
|
+
loop is shipped. The `v0.5.1` real read-only drill reached acceptance and independent
|
|
168
|
+
Review, then correctly stopped at human intervention after two P1 and two P2 findings.
|
|
169
|
+
A separate real edit-capable Claude Code `2.1.270` drill then exercised one bounded
|
|
170
|
+
acceptance failure, repair turn, reacceptance and independent Reviewer `pass` in an
|
|
171
|
+
isolated temporary worktree. The current hardening plan and evidence paths are recorded
|
|
172
|
+
in [`docs/automation-hardening-plan.md`](automation-hardening-plan.md). Deterministic
|
|
173
|
+
coverage now includes repairable-vs-persistent capability assertions, cancellation
|
|
174
|
+
of acceptance commands, stop-from-verifying precedence, paused watchdog baselining,
|
|
175
|
+
staged/untracked evidence and untracked symlink rejection. The remaining release gate
|
|
176
|
+
is the exact-head independent read-only review.
|
|
163
177
|
|
|
164
178
|
### Acceptance and Reviewer fixtures
|
|
165
179
|
|
|
@@ -170,6 +184,9 @@ Deterministic tests must cover:
|
|
|
170
184
|
- independent read-only Reviewer pass/revise/human results;
|
|
171
185
|
- invalid Reviewer JSON and Reviewer API failure escalating to human;
|
|
172
186
|
- repair rounds, repeated finding detection, P0/P1 escalation and repair-budget exhaustion;
|
|
187
|
+
- non-persistent JSONL verification failure without duplicate terminal transitions;
|
|
188
|
+
- repairable-but-not-persistent JSONL multi-turn repair;
|
|
189
|
+
- stop and Pi shutdown from `verifying`, including Decision Worker closure and cwd lease release;
|
|
173
190
|
- completion being impossible without passing all required checks and review.
|
|
174
191
|
|
|
175
192
|
Reviewer sessions use only `read`, `grep`, `find` and `ls`; they must not modify
|
|
@@ -187,14 +204,17 @@ The adapter/replay matrix must cover:
|
|
|
187
204
|
- duplicate Supervisor idempotency keys without duplicate input;
|
|
188
205
|
- stop, SIGTERM, SIGINT and Pi shutdown while a JSONL request is active;
|
|
189
206
|
- ordinary completion, low-risk permission allow, AskUserQuestion deny-to-text,
|
|
190
|
-
multi-turn, verifier failure/repair, takeover and explicit recovery
|
|
207
|
+
multi-turn, verifier failure/repair, takeover and explicit recovery;
|
|
208
|
+
- staged and untracked repository evidence, symlink rejection and truncation fail-closed;
|
|
209
|
+
- paused watchdog behavior and resume-time no-output rebasing;
|
|
210
|
+
- assistant-message-bounded Reviewer and Decision Worker output parsing.
|
|
191
211
|
|
|
192
212
|
Real Claude tests remain authenticated manual Spikes and are pinned to
|
|
193
213
|
`2.1.270`; they are not part of normal CI. Normal CI runs deterministic fake
|
|
194
|
-
Worker and replay fixtures. The
|
|
195
|
-
|
|
196
|
-
for permission and question handling, with
|
|
197
|
-
or unreaped Worker.
|
|
214
|
+
Worker and replay fixtures. The pinned stability matrix is the compatibility evidence
|
|
215
|
+
for this release line; any future CLI change must rerun ten consecutive ordinary
|
|
216
|
+
automatic runs and at least five runs each for permission and question handling, with
|
|
217
|
+
no duplicate action, false completion or unreaped Worker.
|
|
198
218
|
|
|
199
219
|
## Future multi-worker test plan
|
|
200
220
|
|
|
@@ -218,3 +238,23 @@ Required deterministic and integration coverage:
|
|
|
218
238
|
The multi-worker gate should be added only after the pinned single-worker stability
|
|
219
239
|
and recovery gates pass. CI should use fake Workers and replay fixtures; authenticated
|
|
220
240
|
Claude multi-worker Spikes remain manual and version-pinned.
|
|
241
|
+
|
|
242
|
+
## Live drill and hardening gate
|
|
243
|
+
|
|
244
|
+
A live review must record the exact Claude executable/version, transport, cgroup mode,
|
|
245
|
+
permission flags, task id, acceptance result, Reviewer result, cleanup status and cwd lease
|
|
246
|
+
status. A human-required result is a valid safety outcome and must not be converted into a
|
|
247
|
+
pass by retrying the same task automatically.
|
|
248
|
+
|
|
249
|
+
For the hardening release, the completed gate record is:
|
|
250
|
+
|
|
251
|
+
1. `npm run check`, `npm run test:pi`, `npm run test:install`, `npm run build`;
|
|
252
|
+
2. deterministic lifecycle/evidence/capability tests;
|
|
253
|
+
3. a disposable temporary-worktree real Claude repair/reacceptance spike with an edit-capable
|
|
254
|
+
Worker;
|
|
255
|
+
4. cleanup verification: no Worker, no Decision Worker, no unreconciled lease and clean Git
|
|
256
|
+
worktree.
|
|
257
|
+
|
|
258
|
+
The remaining gate is a read-only review of the exact resulting commit. The drill evidence is
|
|
259
|
+
recorded in `docs/automation-hardening-plan.md`; it did not run against this release worktree,
|
|
260
|
+
did not use Claude `--resume`, and did not merge, publish or release automatically.
|