immune-brain 3.6.7 → 3.6.8
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/README.md +89 -51
- package/README.zh-CN.md +130 -46
- package/package.json +1 -1
- package/plugins/immune-brain/.claude-plugin/plugin.json +1 -1
- package/plugins/immune-brain/.pi-extension/package.json +3 -2
- package/plugins/immune-brain/.pi-extension/pi-canary-interaction.ts +149 -4
- package/plugins/immune-brain/dist/claude/mcp-server.mjs +1 -1
- package/plugins/immune-brain/dist/imm-loop.md +3 -0
- package/plugins/immune-brain/runtime/plugin_version.ts +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Immune-Brain
|
|
2
2
|
|
|
3
|
-
> Deterministic workflow & quality engine for [Pi](https://github.com/badlogic/pi) — turn vague ideas into shipped code with planning, execution, QA, and review.
|
|
3
|
+
> Deterministic workflow & quality engine for [Pi](https://github.com/badlogic/pi) and [Claude Code](https://claude.ai/code) — turn vague ideas into shipped code with planning, execution, QA, and review.
|
|
4
4
|
|
|
5
5
|
**Language:** **English** | [中文](./README.zh-CN.md)
|
|
6
6
|
|
|
@@ -8,12 +8,13 @@
|
|
|
8
8
|
|
|
9
9
|
## What Is This?
|
|
10
10
|
|
|
11
|
-
Immune-Brain
|
|
11
|
+
Immune-Brain brings a structured engineering workflow to AI coding assistants (**Pi** and **Claude Code**):
|
|
12
12
|
|
|
13
|
-
- **
|
|
14
|
-
- **
|
|
15
|
-
- **
|
|
16
|
-
- **
|
|
13
|
+
- **Zero overhead for normal chat & coding** — Ordinary questions, quick edits, and exploratory chat stay 100% host-native. Immune-Brain never interrupts normal conversation.
|
|
14
|
+
- **Explicit trigger when rigor matters** — When you want engineering discipline, invoke `imm-brainstorm`, `imm-planner`, or `imm-loop`.
|
|
15
|
+
- **Plans become trackable tasks** (`TaskIntent` + `TaskRecord`) — Progress lives on disk (Git + `.imm/`), surviving restarts and context wipes.
|
|
16
|
+
- **Quality is enforced by code, not promises** — Automated QA and isolated review subagents must pass before a task can complete.
|
|
17
|
+
- **Ready Initiatives can run as a batch** — One confirmed batch authorization lets `imm-loop` work through a published Initiative's children serially, while every child is still enrolled, QA'd, reviewed, and settled on its own.
|
|
17
18
|
|
|
18
19
|
Pi and Claude Code are the supported hosts. Undeclared adapters remain unsupported. Minimum Claude Code is `2.1.236`, the lowest version verified with interactive server-initiated MCP elicitation. Current real-Host evidence is recorded in [Claude native elicitation conformance](docs/verification/claude-native-elicitation-authority-conformance.md); historical reports remain under [docs/verification/archive/](docs/verification/archive/). Either host can use the model provider you configure — Immune-Brain works on top of Kernel authority, not a vendor chat.
|
|
19
20
|
|
|
@@ -36,9 +37,11 @@ Pi and Claude Code are the supported hosts. Undeclared adapters remain unsupport
|
|
|
36
37
|
|
|
37
38
|
## Installation
|
|
38
39
|
|
|
39
|
-
**Prerequisites:** [Pi](https://github.com/badlogic/pi)
|
|
40
|
+
**Prerequisites:** [Pi](https://github.com/badlogic/pi) or [Claude Code](https://claude.ai/code) (>= 2.1.236), Node.js 20+, `bun` for tests.
|
|
40
41
|
|
|
41
|
-
|
|
42
|
+
### In Pi
|
|
43
|
+
|
|
44
|
+
Pi discovers Skills and extensions from `package.json` (or your global Pi configuration):
|
|
42
45
|
|
|
43
46
|
```json
|
|
44
47
|
// package.json → pi.skills / pi.extensions
|
|
@@ -48,7 +51,24 @@ This repo is a Pi package — Pi discovers Skills and extensions from `package.j
|
|
|
48
51
|
}
|
|
49
52
|
```
|
|
50
53
|
|
|
51
|
-
No extra server config is needed. Installing the package via Pi makes all 6 Skills available automatically.
|
|
54
|
+
No extra server config is needed. Installing the package via Pi makes all 6 Skills available automatically.
|
|
55
|
+
|
|
56
|
+
### In Claude Code
|
|
57
|
+
|
|
58
|
+
Add the plugin from the marketplace:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
claude plugin marketplace add dereknex/immune-brain
|
|
62
|
+
claude plugin install immune-brain
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Or load the local directory directly:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
claude --plugin-dir ./plugins/immune-brain
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Verification
|
|
52
72
|
|
|
53
73
|
```bash
|
|
54
74
|
bun test # run all tests
|
|
@@ -60,39 +80,49 @@ mise run check-dist-sync # verify generated docs are in sync
|
|
|
60
80
|
|
|
61
81
|
## Quick Start
|
|
62
82
|
|
|
63
|
-
**
|
|
83
|
+
Immune-Brain follows a **Skill-explicit** model: ordinary conversation is just standard, lightweight AI coding. The managed workflow activates **only when you explicitly invoke a skill**.
|
|
64
84
|
|
|
65
|
-
|
|
85
|
+
**1. Call a skill when you need structured engineering**:
|
|
86
|
+
- Fuzzy idea that needs scoping? Run `/imm-brainstorm` (or ask the agent to use `imm-brainstorm`).
|
|
87
|
+
- Ready to design and build? Run `/imm-planner` (or ask the agent to use `imm-planner`).
|
|
66
88
|
|
|
67
|
-
|
|
89
|
+
*(Ordinary questions like "What does this function do?" or "Fix this typo" stay host-native — zero workflow ceremony.)*
|
|
68
90
|
|
|
69
|
-
**2. Confirm the plan
|
|
91
|
+
**2. Confirm the plan**:
|
|
92
|
+
Planner authors a `TaskIntent` and living Spec (scoped files, risk tier, acceptance checks). A native confirmation dialog opens directly:
|
|
93
|
+
- In **Pi**: native TUI modal dialog.
|
|
94
|
+
- In **Claude Code**: native MCP elicitation confirmation.
|
|
70
95
|
|
|
71
|
-
|
|
96
|
+
Review the scope and confirm enrollment. No code or authority writes happen before your explicit confirmation.
|
|
72
97
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
98
|
+
**3. Run and verify with `imm-loop`**:
|
|
99
|
+
Run `/imm-loop` (or say "Start imm-loop"). The engine will:
|
|
100
|
+
- Dispatch an Executor to write code strictly within the frozen scope.
|
|
101
|
+
- Run deterministic QA acceptance checks.
|
|
102
|
+
- Dispatch an isolated Review subagent for material/critical changes.
|
|
103
|
+
- Settle the completed proof into `.imm/audit/<task-id>/`.
|
|
78
104
|
|
|
79
105
|
---
|
|
80
106
|
|
|
81
107
|
## How to Use
|
|
82
108
|
|
|
83
|
-
|
|
109
|
+
Immune-Brain provides two clean modes: **Host-native** for daily coding, and **Managed Path** for structured, high-assurance tasks:
|
|
84
110
|
|
|
85
111
|
| Your situation | What to say / do | What happens |
|
|
86
112
|
|---|---|---|
|
|
87
|
-
|
|
|
88
|
-
|
|
|
89
|
-
|
|
|
90
|
-
|
|
|
91
|
-
|
|
|
92
|
-
|
|
|
93
|
-
|
|
|
94
|
-
|
|
95
|
-
|
|
113
|
+
| Daily coding, quick fix, general Q&A | Normal conversation ("Fix typo in README", "Explain this function") | **Host-native**: Standard Pi / Claude Code behavior. Zero workflow overhead. |
|
|
114
|
+
| Fuzzy idea, needs scoping & risk analysis | `/imm-brainstorm` "Help me think through webhook support" | → `imm-brainstorm` frames requirements, constraints, and risks (read-only, no code edits) |
|
|
115
|
+
| Clear goal, want formal plan & specs | `/imm-planner` "Plan the webhook feature" | → `imm-planner` writes `TaskIntent` + Specs with testable acceptance checks |
|
|
116
|
+
| Plan confirmed, ready to build & verify | `/imm-loop` | → Executor builds within scope → deterministic QA verifies → isolated Review checks → task settles |
|
|
117
|
+
| Session interrupted or resuming a task | `/imm-loop` | → Resumes existing task seamlessly from on-disk state (`.imm/`) |
|
|
118
|
+
| Ready Initiative to run unattended | "Run initiative `<slug>` unattended" | → Host's `start_unattended_batch`: one native confirmation covers ordered plan digest, children run serially |
|
|
119
|
+
| PR has review comments or failing CI | `/imm-pr-fix` on that PR | → Standalone repair: minimal scoped fix in place, no managed task created |
|
|
120
|
+
| Project docs out of date | `/imm-doc-prune` | → Read-only audit; deletes only user-approved stale docs from manifest |
|
|
121
|
+
| Agent instructions bloated | `/imm-agent-doc-maintain` | → Minimizes tracked `AGENTS.md` / `CLAUDE.md` to essential non-discoverable rules |
|
|
122
|
+
|
|
123
|
+
> **Core Principle: Skill-Explicit Entry**
|
|
124
|
+
> - **Ordinary input stays host-native**: Natural language queries never automatically start planning or task enrollment. You choose when to turn on engineering rigor.
|
|
125
|
+
> - **Managed work starts with explicit skills**: Use `imm-brainstorm` to clarify, `imm-planner` to plan, and `imm-loop` to execute and resume.
|
|
96
126
|
|
|
97
127
|
---
|
|
98
128
|
|
|
@@ -109,7 +139,7 @@ You rarely need to remember skill names — **just describe your intent**:
|
|
|
109
139
|
|
|
110
140
|
Internal roles (Executor, QA, Review, Compounder) are dispatched by `imm-loop` — you never invoke them directly.
|
|
111
141
|
|
|
112
|
-
|
|
142
|
+
All 6 skills are invoked explicitly. For new features, start with `imm-brainstorm` (if requirements are uncertain) or `imm-planner` (if requirements are clear), then proceed to `imm-loop` once enrolled.
|
|
113
143
|
|
|
114
144
|
### Managed Path entries (brainstorm → planner → loop)
|
|
115
145
|
|
|
@@ -117,21 +147,21 @@ The three Managed skills form one continuous pipeline with a single authority mo
|
|
|
117
147
|
|
|
118
148
|
#### `imm-brainstorm` — requirement clarification
|
|
119
149
|
|
|
120
|
-
- **Trigger:** explicit
|
|
150
|
+
- **Trigger:** explicit `/imm-brainstorm` or request for requirement clarification.
|
|
121
151
|
- **What it does:** frames the problem — goal, constraints, unknowns, risks — and produces a `brainstorm_framing` result with a recommended next step (usually → `imm-planner`).
|
|
122
152
|
- **What it never does:** read-only by design. No code, test, or runtime edits; no Spec, Plan, or workflow-state writes.
|
|
123
153
|
- **Exit:** a framed, answerable problem statement you can hand to the Planner.
|
|
124
154
|
|
|
125
155
|
#### `imm-planner` — Spec & TaskIntent planning
|
|
126
156
|
|
|
127
|
-
- **Trigger:** explicit
|
|
157
|
+
- **Trigger:** explicit `/imm-planner` or request for Spec & TaskIntent planning.
|
|
128
158
|
- **What it does:** authors or revises `TaskIntent` files (`docs/plans/`) and living Specs (`docs/specs/`) — scope (`scope_hint`), risk tier, acceptance descriptors. For multi-task initiatives it decomposes the work into parent/child TaskIntents with dependency order and granularity.
|
|
129
159
|
- **What it never does:** implements code, overwrites an enrolled TaskIntent without a revision flow, or grants execution authority — only the native Enrollment gate can.
|
|
130
160
|
- **Exit:** Git-tracked `TaskIntent` awaiting enrollment confirmation.
|
|
131
161
|
|
|
132
162
|
#### `imm-loop` — managed execution & assurance
|
|
133
163
|
|
|
134
|
-
- **Trigger:** explicit
|
|
164
|
+
- **Trigger:** explicit `/imm-loop` (start, resume, or check a managed task).
|
|
135
165
|
- **What it does:** drives one task end to end through foreground tools — Executor edits inside the frozen scope, deterministic QA executes every acceptance descriptor, an isolated Review subagent audits material/critical tasks, and the Kernel settles terminal evidence. Interrupted workflows resume from on-disk state; the Kernel projection is authoritative.
|
|
136
166
|
- **What it never does:** skips or weakens a failing check, runs without your Enrollment/revision/authorization gates, or continues after lineage or authority drift — it fails closed.
|
|
137
167
|
- **Finding evidence:** every Review finding carries machine-checkable provenance (`trigger`, `caller_chain`, `violated`). A claim that fresh passing QA evidence already contradicts is recorded as `refuted` and only blocks again if that evidence goes stale.
|
|
@@ -162,19 +192,27 @@ The three repair/maintenance skills are host-native: they never create a managed
|
|
|
162
192
|
## Lifecycle
|
|
163
193
|
|
|
164
194
|
```
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
195
|
+
Ordinary request: normal coding / Q&A (Host-native, zero overhead)
|
|
196
|
+
│
|
|
197
|
+
Explicit skill call (/imm-brainstorm or /imm-planner)
|
|
198
|
+
│
|
|
199
|
+
┌──────────────┴──────────────┐
|
|
200
|
+
▼ ▼
|
|
201
|
+
imm-brainstorm imm-planner
|
|
202
|
+
(clarify requirements, (author Spec + TaskIntent,
|
|
203
|
+
read-only framing) define acceptance checks)
|
|
204
|
+
│ │
|
|
205
|
+
└──────────────┬──────────────┘
|
|
206
|
+
▼
|
|
207
|
+
Native Host Confirmation
|
|
208
|
+
(Pi TUI dialog / Claude MCP elicitation)
|
|
209
|
+
│
|
|
210
|
+
▼
|
|
211
|
+
imm-loop
|
|
212
|
+
├── Executor (edits strictly inside scope)
|
|
213
|
+
├── Deterministic QA (runs all acceptance checks)
|
|
214
|
+
├── Isolated Review (independent subagent audit)
|
|
215
|
+
└── Settled (.imm/audit/<task-id>/)
|
|
178
216
|
```
|
|
179
217
|
|
|
180
218
|
Key invariants:
|
|
@@ -245,11 +283,11 @@ docs/specs/ # Living specs (updated in place)
|
|
|
245
283
|
|
|
246
284
|
## FAQ
|
|
247
285
|
|
|
248
|
-
**Do I need to learn all 6 skills?** No.
|
|
286
|
+
**Do I need to learn all 6 skills?** No. Most of the time you only need `/imm-planner` (to plan and enroll a task) and `/imm-loop` (to build and verify it). Use `imm-brainstorm` when requirements need clarifying first, and the maintenance skills (`imm-pr-fix`, etc.) only when specific repair needs arise. Ordinary chat and simple edits don't need any skills at all.
|
|
249
287
|
|
|
250
|
-
**What if I interrupt or close
|
|
288
|
+
**What if I interrupt or close the session mid-task?** State is safely stored on disk (`.imm/` + TaskIntent). In Pi or Claude Code, simply re-enter `/imm-loop` to resume — the Kernel projection is authoritative.
|
|
251
289
|
|
|
252
|
-
**Why does enrollment show a
|
|
290
|
+
**Why does enrollment show a confirmation dialog?** All risk levels (`routine`/`material`/`critical`) require explicit human confirmation before execution authority is granted. In Pi, this is a native TUI modal dialog; in Claude Code, it is a native MCP elicitation gate. It binds the staged digest so you see exactly what will be tracked.
|
|
253
291
|
|
|
254
292
|
**QA failed — what now?** QA returns `rework` or `replan_required`. `imm-loop` routes back to the executor or to `imm-planner` for scope changes. No manual reset needed.
|
|
255
293
|
|
|
@@ -257,7 +295,7 @@ docs/specs/ # Living specs (updated in place)
|
|
|
257
295
|
|
|
258
296
|
**Can it run a whole Initiative without me?** Only as far as you authorize. Confirm `start_unattended_batch` with the Initiative slug and the runner works through the published, non-`critical` children serially on one batch branch — parking as soon as a child needs a human decision or the run hits a budget, deadline, authorization, or commit failure. It never pushes, opens PRs, or settles user decisions for you.
|
|
259
297
|
|
|
260
|
-
**
|
|
298
|
+
**Which AI coding assistants are supported?** Pi and Claude Code are the supported hosts (Claude Code version >= `2.1.236`). Both hosts run on the exact same Kernel authority, assurance guarantees, and multi-skill pipeline.
|
|
261
299
|
|
|
262
300
|
---
|
|
263
301
|
|
|
@@ -283,7 +321,7 @@ npm publish --access public # requires npm login / NPM_TOKEN
|
|
|
283
321
|
# or
|
|
284
322
|
bun run changeset:publish
|
|
285
323
|
```
|
|
286
|
-
The package publishes to npm as `immune-brain` (current release `3.6.
|
|
324
|
+
The package publishes to npm as `immune-brain` (current release `3.6.7`) with `publishConfig.access=public` already set. After the initial publish, all future releases go through changesets.
|
|
287
325
|
|
|
288
326
|
See `CHANGELOG.md` and `.changeset/config.json` (changelog: `@changesets/changelog-github`, repo: `dereknex/immune-brain`).
|
|
289
327
|
|
package/README.zh-CN.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Immune-Brain
|
|
2
2
|
|
|
3
|
-
> 面向 [Pi](https://github.com/badlogic/pi) 的确定性工程工作流与质量保障引擎 — 把模糊想法变成可交付代码,覆盖规划、执行、QA 与审查。
|
|
3
|
+
> 面向 [Pi](https://github.com/badlogic/pi) 与 [Claude Code](https://claude.ai/code) 的确定性工程工作流与质量保障引擎 — 把模糊想法变成可交付代码,覆盖规划、执行、QA 与审查。
|
|
4
4
|
|
|
5
5
|
**语言:** [English](./README.md) | **中文**
|
|
6
6
|
|
|
@@ -8,11 +8,12 @@
|
|
|
8
8
|
|
|
9
9
|
## 这是什么?
|
|
10
10
|
|
|
11
|
-
Immune-Brain
|
|
11
|
+
Immune-Brain 为 AI 编程工具(**Pi** 与 **Claude Code**)提供结构化的工程工作流保障:
|
|
12
12
|
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
13
|
+
- **日常对话零负担** — 普通问答、单点代码修改与探索性对话完全保持 Host 原生体验,不拦截、不强加流程。
|
|
14
|
+
- **需要严谨时显式启用** — 遇到复杂功能开发或高保证任务时,显式调用 `imm-brainstorm`、`imm-planner` 或 `imm-loop`。
|
|
15
|
+
- **计划变为可追踪的任务**(`TaskIntent` + `TaskRecord`) — 进度落盘持久化(Git + `.imm/`),会话重启或上下文清理后仍可无缝恢复。
|
|
16
|
+
- **质量由代码强制保障** — 自动化 QA 验收与隔离式 Reviewer 审查必须通过,任务才会结算完成。
|
|
16
17
|
- **已就绪的 Initiative 可以整批运行** — 一次确认的 Batch Authorization 让 `imm-loop` 串行推进已发布 Initiative 的各个 child,而每个 child 仍然独立 Enrollment、独立 QA/Review、独立结算。
|
|
17
18
|
|
|
18
19
|
Pi 与 Claude Code 是支持的宿主。未声明的适配器仍不受支持。Claude Code 最低版本为 `2.1.236`,这是已通过交互式 server-initiated MCP elicitation 验证的最低版本。当前真实 Host 证据见 `docs/verification/claude-native-elicitation-authority-conformance.md`;历史报告归档于 `docs/verification/archive/`。
|
|
@@ -36,9 +37,11 @@ Pi 与 Claude Code 是支持的宿主。未声明的适配器仍不受支持。C
|
|
|
36
37
|
|
|
37
38
|
## 安装
|
|
38
39
|
|
|
39
|
-
**前置要求:** 已安装 [Pi](https://github.com/badlogic/pi)
|
|
40
|
+
**前置要求:** 已安装 [Pi](https://github.com/badlogic/pi) 或 [Claude Code](https://claude.ai/code)(>= 2.1.236)、Node.js 20+、`bun`(用于测试)。
|
|
40
41
|
|
|
41
|
-
|
|
42
|
+
### 在 Pi 中使用
|
|
43
|
+
|
|
44
|
+
Pi 通过 `package.json`(或全局 Pi 配置)自动发现 Skills 与扩展:
|
|
42
45
|
|
|
43
46
|
```json
|
|
44
47
|
// package.json → pi.skills / pi.extensions
|
|
@@ -48,7 +51,24 @@ Pi 与 Claude Code 是支持的宿主。未声明的适配器仍不受支持。C
|
|
|
48
51
|
}
|
|
49
52
|
```
|
|
50
53
|
|
|
51
|
-
无需额外 server 配置,通过 Pi 安装本 package 后 6 个 Skill
|
|
54
|
+
无需额外 server 配置,通过 Pi 安装本 package 后 6 个 Skill 即自动可用。
|
|
55
|
+
|
|
56
|
+
### 在 Claude Code 中使用
|
|
57
|
+
|
|
58
|
+
从 Marketplace 安装插件:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
claude plugin marketplace add dereknex/immune-brain
|
|
62
|
+
claude plugin install immune-brain
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
或在本地开发时直接加载插件目录:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
claude --plugin-dir ./plugins/immune-brain
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 验证安装
|
|
52
72
|
|
|
53
73
|
```bash
|
|
54
74
|
bun test # 全量测试
|
|
@@ -60,39 +80,49 @@ mise run check-dist-sync # 校验生成文档同步
|
|
|
60
80
|
|
|
61
81
|
## 快速开始
|
|
62
82
|
|
|
63
|
-
|
|
83
|
+
Immune-Brain 遵循 **显式 Skill 触发(Skill-explicit)** 模型:日常对话就是轻量自然的 AI 编程,只有显式调用对应 Skill 时才会开启严格工程管理。
|
|
64
84
|
|
|
65
|
-
|
|
85
|
+
**1. 当你需要严谨工程流程时,显式调用 Skill:**
|
|
86
|
+
- 需求模糊想先梳理?输入 `/imm-brainstorm`(或对 Agent 说 "用 imm-brainstorm 梳理需求")。
|
|
87
|
+
- 目标明确准备制定方案?输入 `/imm-planner`(或对 Agent 说 "用 imm-planner 规划深色模式功能")。
|
|
66
88
|
|
|
67
|
-
|
|
89
|
+
*(日常提问如 "这个函数什么意思"、"改个 typo" 保持完全原生,没有任何流程弹窗和开销。)*
|
|
68
90
|
|
|
69
|
-
**2.
|
|
91
|
+
**2. 确认计划:**
|
|
92
|
+
Planner 会在 `docs/plans/` 生成 `TaskIntent` 与 living Spec(锁定文件范围、风险等级与自动化验收条件)。随后弹出当前 Host 的原生确认界面:
|
|
93
|
+
- 在 **Pi** 中:原生 TUI 对话框;
|
|
94
|
+
- 在 **Claude Code** 中:原生 MCP elicitation 确认弹窗。
|
|
70
95
|
|
|
71
|
-
|
|
96
|
+
检查无误并确认后,才会正式锁定范围并开放执行权限。
|
|
72
97
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
98
|
+
**3. 用 `imm-loop` 自动执行与验收:**
|
|
99
|
+
输入 `/imm-loop`(或 "开始 imm-loop"),工作流引擎会自动:
|
|
100
|
+
- 调度 Executor 仅在锁定的 scope 范围内编写代码。
|
|
101
|
+
- 自动运行确定性 QA 验收命令。
|
|
102
|
+
- 对 material/critical 任务分发隔离的 Reviewer 子代理审查代码。
|
|
103
|
+
- 全部通过后落盘结算凭证至 `.imm/audit/<task-id>/`,任务完成。
|
|
78
104
|
|
|
79
105
|
---
|
|
80
106
|
|
|
81
107
|
## 如何使用
|
|
82
108
|
|
|
83
|
-
|
|
109
|
+
Immune-Brain 提供两种清晰的工作模式:日常轻量编码走 **Host-native**,复杂高保证任务走 **Managed Path**:
|
|
84
110
|
|
|
85
|
-
| 你的情况 |
|
|
111
|
+
| 你的情况 | 你做什么 / 说什么 | 会发生什么 |
|
|
86
112
|
|---|---|---|
|
|
87
|
-
|
|
|
88
|
-
|
|
|
89
|
-
|
|
|
113
|
+
| 日常编码、快速改动、普通问答 | 正常自然语言对话("帮我改下文案"、"解释这段代码") | **Host-native**:标准 Pi / Claude Code 行为,零流程开销 |
|
|
114
|
+
| 想法模糊,需要梳理边界与风险 | `/imm-brainstorm` "帮我梳理一下通知系统的方案" | → `imm-brainstorm` 提问澄清、分析约束与风险(只读,不改代码) |
|
|
115
|
+
| 目标明确,需要正规计划与规格 | `/imm-planner` "规划一下深色模式功能" | → `imm-planner` 产出 `TaskIntent` + Spec,包含可执行验收条件 |
|
|
116
|
+
| 计划已确认,准备执行与验证 | `/imm-loop` | → Executor 在范围内实现 → 确定性 QA 验收 → 隔离 Review 审查 → 任务结算 |
|
|
117
|
+
| 会话中断或需恢复未完成任务 | `/imm-loop` | → 从磁盘状态(`.imm/`)无缝恢复,以 Kernel projection 为准 |
|
|
90
118
|
| 已发布的 Initiative 可以整批跑了 | "把 initiative `<slug>` 无人值守跑完" | → Host 的 `start_unattended_batch`:一次原生确认绑定有序 plan digest,child 串行执行 |
|
|
91
|
-
| PR 被评论 / CI 挂了 | 对该 PR 使用
|
|
92
|
-
| 文档过时需要清理 |
|
|
93
|
-
| Agent
|
|
119
|
+
| PR 被评论 / CI 挂了 | 对该 PR 使用 `/imm-pr-fix` | → 独立修复:在当前 PR 内针对性修复,不创建新 managed 任务 |
|
|
120
|
+
| 文档过时需要清理 | `/imm-doc-prune` | → 只读审计过时文档,仅删除经哈希审批的条目 |
|
|
121
|
+
| Agent 指令文件膨胀 | `/imm-agent-doc-maintain` | → 将 tracked `AGENTS.md` / `CLAUDE.md` 压到最小必要上下文 |
|
|
94
122
|
|
|
95
|
-
>
|
|
123
|
+
> **核心原则:Skill 显式调用**
|
|
124
|
+
> - **普通输入保持 Host-native**:自然语言提问绝不自动绑架流程或发起 Enrollment。你完全自主决定何时开启严格工程保障。
|
|
125
|
+
> - **Managed 工作流显式启动**:需要澄清用 `imm-brainstorm`,制定计划用 `imm-planner`,执行与恢复用 `imm-loop`。
|
|
96
126
|
|
|
97
127
|
---
|
|
98
128
|
|
|
@@ -109,26 +139,80 @@ QA 与 Review 以 foreground Tool 形式运行并回传结果,返回 `phase=do
|
|
|
109
139
|
|
|
110
140
|
Executor、QA、Review、Compounder 等为 `imm-loop` 内部调度的角色,无需手动调用。
|
|
111
141
|
|
|
112
|
-
|
|
142
|
+
所有 6 个 Skill 均显式调用。新需求开发时:若需求含糊先调 `imm-brainstorm`,目标清晰直接调 `imm-planner`,完成确认后调 `imm-loop` 推进闭环。
|
|
143
|
+
|
|
144
|
+
### Managed Path 入口(brainstorm → planner → loop)
|
|
145
|
+
|
|
146
|
+
这三个 Managed Skill 组成连续的工作流管道,拥有统一的 authority 模型:在你于原生确认窗口授权前绝不执行任何写入,每一次状态转换均由 Kernel 权威结算。
|
|
147
|
+
|
|
148
|
+
#### `imm-brainstorm` — 需求与问题澄清
|
|
149
|
+
|
|
150
|
+
- **触发方式:** 显式调用 `/imm-brainstorm` 或明确提出需求澄清。
|
|
151
|
+
- **职责:** 梳理问题框架 — 目标、约束、未知项与风险 — 产出 `brainstorm_framing` 结论及下一步建议(通常指向 `imm-planner`)。
|
|
152
|
+
- **边界:** 纯只读设计。不修改代码、不修改测试、不写入运行态、不创建 Spec 或 TaskIntent。
|
|
153
|
+
- **产出:** 结构清晰、可解答的问题框架,作为 Planner 的输入。
|
|
154
|
+
|
|
155
|
+
#### `imm-planner` — Spec 与 TaskIntent 规划
|
|
156
|
+
|
|
157
|
+
- **触发方式:** 显式调用 `/imm-planner` 或明确提出规划请求。
|
|
158
|
+
- **职责:** 编写或修订 `TaskIntent` 文件(`docs/plans/`)与 living Spec(`docs/specs/`) — 划定文件范围(`scope_hint`)、风险等级与验收条件。对于多任务 Initiative,负责按依赖顺序和粒度拆解为 parent/child TaskIntent。
|
|
159
|
+
- **边界:** 不编写业务实现代码、不经 revision 流程不覆盖已 Enrolled 的 TaskIntent,不擅自赋予执行权限 — 仅当前 Host 原生确认窗口具备授权能力。
|
|
160
|
+
- **产出:** 纳入 Git 版本控制、等待 Enrollment 确认的 `TaskIntent`。
|
|
161
|
+
|
|
162
|
+
#### `imm-loop` — Managed 执行与质量保障
|
|
163
|
+
|
|
164
|
+
- **触发方式:** 显式调用 `/imm-loop`(启动、恢复或检查 managed 任务)。
|
|
165
|
+
- **职责:** 通过前台 Tool 驱动任务端到端闭环 — Executor 仅在冻结的 scope 内修改代码,确定性 QA 逐项运行验收条件,隔离的 Reviewer 子代理审计 material/critical 任务,最后由 Kernel 结算落盘凭证。会话中断后从磁盘状态自动恢复,以 Kernel projection 为真源。
|
|
166
|
+
- **边界:** 绝不跳过或弱化失败检查、无用户原生授权绝不执行、遇到版本或权限偏移立即 fail-closed。
|
|
167
|
+
- **Finding 证据:** 每一项 Review finding 均携带可机器核验的 provenance(`trigger`、`caller_chain`、`violated`)。若新鲜且通过的 QA 证据已证明某项 finding 声称的 acceptance 通过,则标记为 `refuted`,仅在证据过期时才会重新阻塞。
|
|
168
|
+
- **产出:** 带有完整 QA + Review 签批、保存在 `.imm/audit/<task-id>/` 的 `done` 状态 TaskRecord。
|
|
169
|
+
|
|
170
|
+
### 独立维护入口
|
|
171
|
+
|
|
172
|
+
三个维护类 Skill 保持 Host-native:不创建 managed 任务、不推进 Managed 工作流、尊重已有的 Managed owner。
|
|
173
|
+
|
|
174
|
+
#### `imm-pr-fix` — PR 修复
|
|
175
|
+
|
|
176
|
+
- **触发方式:** 显式要求修复 GitHub PR 的 review 意见、合并冲突或 CI 失败。
|
|
177
|
+
- **职责:** 原地修复单个 PR — 诊断 review/冲突/CI 证据,实施最小范围修复,并重跑相关检查。
|
|
178
|
+
- **边界:** 严格限定在 PR 原有范围内;将远端文本视为不可信数据;修复不授予合入或批准权限。
|
|
179
|
+
|
|
180
|
+
#### `imm-doc-prune` — 过时文档清理
|
|
181
|
+
|
|
182
|
+
- **触发方式:** 显式要求清理当前过时的文档。
|
|
183
|
+
- **职责:** 只读审计文档时效性,根据用户明确审批的哈希绑定 manifest 进行精准删除,每次修改后立即重验。
|
|
184
|
+
|
|
185
|
+
#### `imm-agent-doc-maintain` — Agent 指令文件瘦身
|
|
186
|
+
|
|
187
|
+
- **触发方式:** 显式要求精简版本控制下的 `AGENTS.md` / `CLAUDE.md` / `GEMINI.md`。
|
|
188
|
+
- **职责:** 遵循与 `imm-doc-prune` 相同的「只读审计 + 哈希清单审批」模式,仅保留无法直接推导的必要规则。
|
|
113
189
|
|
|
114
190
|
---
|
|
115
191
|
|
|
116
192
|
## 生命周期
|
|
117
193
|
|
|
118
194
|
```
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
195
|
+
普通请求:日常编程 / 问答(Host-native,零流程开销)
|
|
196
|
+
│
|
|
197
|
+
显式调用 Skill(/imm-brainstorm 或 /imm-planner)
|
|
198
|
+
│
|
|
199
|
+
┌──────────────┴──────────────┐
|
|
200
|
+
▼ ▼
|
|
201
|
+
imm-brainstorm imm-planner
|
|
202
|
+
(澄清需求、约束与风险, (编写 Spec + TaskIntent,
|
|
203
|
+
只读输出 framing) 定义可自动化验证的验收条件)
|
|
204
|
+
│ │
|
|
205
|
+
└──────────────┬──────────────┘
|
|
206
|
+
▼
|
|
207
|
+
当前 Host 原生确认
|
|
208
|
+
(Pi TUI 弹窗 / Claude MCP elicitation)
|
|
209
|
+
│
|
|
210
|
+
▼
|
|
211
|
+
imm-loop
|
|
212
|
+
├── Executor(严格在 scope 内修改代码)
|
|
213
|
+
├── 确定性 QA(前台逐项执行验收命令)
|
|
214
|
+
├── 隔离式 Review(独立 subagent 审查代码)
|
|
215
|
+
└── 落盘结算(.imm/audit/<task-id>/)
|
|
132
216
|
```
|
|
133
217
|
|
|
134
218
|
核心不变量:
|
|
@@ -199,11 +283,11 @@ docs/specs/ # Living specs(原地更新)
|
|
|
199
283
|
|
|
200
284
|
## 常见问题
|
|
201
285
|
|
|
202
|
-
**需要记住所有 Skill 吗?**
|
|
286
|
+
**需要记住所有 Skill 吗?** 不需要。日常开发核心只需两个:`/imm-planner`(规划与确认任务)和 `/imm-loop`(执行与验证)。需求模糊时用 `/imm-brainstorm`,维护类任务(如 `/imm-pr-fix`)按需使用。普通问答与即时小修改无需任何 Skill。
|
|
203
287
|
|
|
204
|
-
|
|
288
|
+
**中途关闭会话会怎样?** 状态已落盘保存(`.imm/` + TaskIntent)。在 Pi 或 Claude Code 中重新输入 `/imm-loop` 即可恢复,以 Kernel projection 状态为准。
|
|
205
289
|
|
|
206
|
-
**为什么 enrollment 要弹窗确认?** 所有风险等级(`routine`/`material`/`critical
|
|
290
|
+
**为什么 enrollment 要弹窗确认?** 所有风险等级(`routine`/`material`/`critical`)在获得执行授权前都必须经由人工显式确认。在 Pi 中是原生 TUI 对话框,在 Claude Code 中是原生 MCP elicitation 弹窗。确认界面绑定 staged digest,让你清楚看到被锁定的文件范围和验收要求。
|
|
207
291
|
|
|
208
292
|
**QA 失败怎么办?** QA 返回 `rework` 或 `replan_required`,`imm-loop` 会自动路由回 Executor 或 `imm-planner` 调整范围,无需手动重置。
|
|
209
293
|
|
|
@@ -211,7 +295,7 @@ docs/specs/ # Living specs(原地更新)
|
|
|
211
295
|
|
|
212
296
|
**能不能整个 Initiative 不用我盯着?** 只能在你授权范围内。用 Initiative slug 确认 `start_unattended_batch` 后,runner 会在一个 batch 分支上串行推进已发布且非 `critical` 的 child — 一旦某个 child 需要人决策,或遇到预算/截止时间/授权/提交失败就暂停。它不会替你 push、开 PR 或结算用户决策。
|
|
213
297
|
|
|
214
|
-
|
|
298
|
+
**支持哪些 AI 编程工具?** Pi 与 Claude Code 是支持的宿主(Claude Code 最低版本为 `2.1.236`)。两者共享同一套确定性 Kernel 核心、质量保障机制与工具链。
|
|
215
299
|
|
|
216
300
|
---
|
|
217
301
|
|
|
@@ -237,7 +321,7 @@ npm publish --access public # 需 npm login / NPM_TOKEN
|
|
|
237
321
|
# 或
|
|
238
322
|
bun run changeset:publish
|
|
239
323
|
```
|
|
240
|
-
包名为 `immune-brain`(当前版本 `3.6.
|
|
324
|
+
包名为 `immune-brain`(当前版本 `3.6.7`),已配置 `publishConfig.access=public`。首次发布后,后续所有版本均通过 changesets 管理。
|
|
241
325
|
|
|
242
326
|
详见 `CHANGELOG.md` 与 `.changeset/config.json`(changelog: `@changesets/changelog-github`,repo: `dereknex/immune-brain`)。
|
|
243
327
|
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "immune-brain-pi-extension",
|
|
3
3
|
"private": true,
|
|
4
|
-
"description": "Explicit extension entry manifest for the Immune-Brain Pi lifecycle Tools. Helper modules in this directory are library code, not extension factories; listing only the
|
|
4
|
+
"description": "Explicit extension entry manifest for the Immune-Brain Pi lifecycle Tools. Helper modules in this directory are library code, not extension factories; listing only the three factory files here prevents Pi's directory discovery from loading them as extensions.",
|
|
5
5
|
"pi": {
|
|
6
6
|
"extensions": [
|
|
7
7
|
"./imm-canary-enroll.ts",
|
|
8
|
-
"./imm-canary-work.ts"
|
|
8
|
+
"./imm-canary-work.ts",
|
|
9
|
+
"./imm-unattended-batch.ts"
|
|
9
10
|
]
|
|
10
11
|
}
|
|
11
12
|
}
|
|
@@ -55,6 +55,8 @@ export interface TaskRailView {
|
|
|
55
55
|
recovery?: string;
|
|
56
56
|
/** Latest per-descriptor QA fact; rendered only while present. */
|
|
57
57
|
acceptance_progress?: TaskRailAcceptanceProgress;
|
|
58
|
+
/** Optional pipeline milestone progress indicator. */
|
|
59
|
+
pipeline?: boolean;
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
export interface TaskOverviewEntry {
|
|
@@ -144,7 +146,7 @@ export async function requestAuthorityDialog<T extends string, R = T | undefined
|
|
|
144
146
|
finish = done;
|
|
145
147
|
if (settled || options.signal?.aborted) done(undefined);
|
|
146
148
|
let expanded = false;
|
|
147
|
-
const detailText = new Text(theme.fg("muted", "Details collapsed; press d to expand."), 1, 0);
|
|
149
|
+
const detailText = new Text(theme.fg("muted", "▸ Details collapsed; press d to expand."), 1, 0);
|
|
148
150
|
const selectList = new SelectList(
|
|
149
151
|
options.actions.map((action): SelectItem => ({ ...action })),
|
|
150
152
|
options.actions.length,
|
|
@@ -158,13 +160,27 @@ export async function requestAuthorityDialog<T extends string, R = T | undefined
|
|
|
158
160
|
);
|
|
159
161
|
selectList.onSelect = (item) => complete(item.value as T);
|
|
160
162
|
selectList.onCancel = () => complete(undefined);
|
|
163
|
+
|
|
164
|
+
const affirmativeAction = options.actions.find((a) =>
|
|
165
|
+
["confirm", "authorize", "yes", "accept"].includes(a.value.toLowerCase()),
|
|
166
|
+
);
|
|
167
|
+
const negativeAction = options.actions.find((a) =>
|
|
168
|
+
["cancel", "decline", "no", "reject"].includes(a.value.toLowerCase()),
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
const affKey = affirmativeAction ? "y/enter" : "enter";
|
|
172
|
+
const negKey = negativeAction ? "n/esc" : "esc";
|
|
173
|
+
const affLabel = affirmativeAction ? affirmativeAction.value : "choose";
|
|
174
|
+
const negLabel = negativeAction ? negativeAction.value : "cancel";
|
|
175
|
+
const hintLine = `d: details | ${affKey}: ${affLabel} | ${negKey}: ${negLabel}`;
|
|
176
|
+
|
|
161
177
|
const container = new Container();
|
|
162
178
|
container.addChild(new DynamicBorder((text: string) => theme.fg("accent", text)));
|
|
163
179
|
container.addChild(new Text(theme.fg("accent", theme.bold(options.title)), 1, 0));
|
|
164
|
-
container.addChild(new Text(options.summary, 1, 0));
|
|
180
|
+
container.addChild(new Text(formatDialogSummary(options.summary, theme), 1, 0));
|
|
165
181
|
container.addChild(detailText);
|
|
166
182
|
container.addChild(selectList);
|
|
167
|
-
container.addChild(new Text(theme.fg("dim",
|
|
183
|
+
container.addChild(new Text(theme.fg("dim", hintLine), 1, 0));
|
|
168
184
|
container.addChild(new DynamicBorder((text: string) => theme.fg("accent", text)));
|
|
169
185
|
return {
|
|
170
186
|
render: (width) => container.render(width),
|
|
@@ -172,10 +188,20 @@ export async function requestAuthorityDialog<T extends string, R = T | undefined
|
|
|
172
188
|
handleInput: (data) => {
|
|
173
189
|
if (data === "d" || data === "D") {
|
|
174
190
|
expanded = !expanded;
|
|
175
|
-
detailText.setText(expanded
|
|
191
|
+
detailText.setText(expanded
|
|
192
|
+
? `${theme.fg("muted", "▾ Details:")}\n${options.details}`
|
|
193
|
+
: theme.fg("muted", "▸ Details collapsed; press d to expand."));
|
|
176
194
|
tui.requestRender();
|
|
177
195
|
return;
|
|
178
196
|
}
|
|
197
|
+
if ((data === "y" || data === "Y") && affirmativeAction) {
|
|
198
|
+
complete(affirmativeAction.value as T);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
if ((data === "n" || data === "N") && negativeAction) {
|
|
202
|
+
complete(negativeAction.value as T);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
179
205
|
selectList.handleInput(data);
|
|
180
206
|
tui.requestRender();
|
|
181
207
|
},
|
|
@@ -372,6 +398,13 @@ export function renderStructuredResult(
|
|
|
372
398
|
];
|
|
373
399
|
const recovery = recoveryHint(details);
|
|
374
400
|
if (recovery) lines.push(`${theme.fg("muted", "Recovery:")} ${theme.fg("dim", recovery)}`);
|
|
401
|
+
const facts = record(details.facts) ?? record(details.execution_facts);
|
|
402
|
+
if (facts) {
|
|
403
|
+
const factParts = Object.entries(facts)
|
|
404
|
+
.map(([k, v]) => `${k}=${String(v)}`)
|
|
405
|
+
.join(" · ");
|
|
406
|
+
if (factParts) lines.push(`${theme.fg("muted", "Facts:")} ${theme.fg("dim", factParts)}`);
|
|
407
|
+
}
|
|
375
408
|
if (terminal && taskState) lines.push(...renderFinalLines(taskState, theme));
|
|
376
409
|
return new Text(lines.join("\n"), 0, 0);
|
|
377
410
|
}
|
|
@@ -423,6 +456,9 @@ function renderTaskRail(view: TaskRailView, width = 120, theme?: Theme): string[
|
|
|
423
456
|
const lines = [
|
|
424
457
|
`Task ${boundedMiddle(view.task_id, taskIdWidth)} · ${stateFormatted}`,
|
|
425
458
|
];
|
|
459
|
+
if (view.pipeline) {
|
|
460
|
+
lines.push(`${label("Pipeline:")} ${renderPipelineMilestones(view.state, theme)}`);
|
|
461
|
+
}
|
|
426
462
|
if (view.phase) {
|
|
427
463
|
lines.push(`${label("Phase:")} ${body(bounded(view.phase, availableContentWidth))}`);
|
|
428
464
|
}
|
|
@@ -446,6 +482,69 @@ function renderTaskRail(view: TaskRailView, width = 120, theme?: Theme): string[
|
|
|
446
482
|
return lines;
|
|
447
483
|
}
|
|
448
484
|
|
|
485
|
+
export function renderPipelineMilestones(state: TaskRailState, theme?: Theme): string {
|
|
486
|
+
const milestones = [
|
|
487
|
+
{ name: "Plan", key: "plan" },
|
|
488
|
+
{ name: "Exec", key: "exec" },
|
|
489
|
+
{ name: "QA", key: "qa" },
|
|
490
|
+
{ name: "Review", key: "review" },
|
|
491
|
+
] as const;
|
|
492
|
+
|
|
493
|
+
type StepStatus = "done" | "active" | "pending" | "blocked" | "stopped";
|
|
494
|
+
|
|
495
|
+
let statuses: [StepStatus, StepStatus, StepStatus, StepStatus];
|
|
496
|
+
switch (state) {
|
|
497
|
+
case "Planning":
|
|
498
|
+
statuses = ["active", "pending", "pending", "pending"];
|
|
499
|
+
break;
|
|
500
|
+
case "Approval required":
|
|
501
|
+
case "Working":
|
|
502
|
+
statuses = ["done", "active", "pending", "pending"];
|
|
503
|
+
break;
|
|
504
|
+
case "Verifying":
|
|
505
|
+
statuses = ["done", "done", "active", "pending"];
|
|
506
|
+
break;
|
|
507
|
+
case "Reviewing":
|
|
508
|
+
statuses = ["done", "done", "done", "active"];
|
|
509
|
+
break;
|
|
510
|
+
case "Completed":
|
|
511
|
+
statuses = ["done", "done", "done", "done"];
|
|
512
|
+
break;
|
|
513
|
+
case "Blocked":
|
|
514
|
+
statuses = ["done", "blocked", "pending", "pending"];
|
|
515
|
+
break;
|
|
516
|
+
case "Stopped":
|
|
517
|
+
statuses = ["done", "stopped", "pending", "pending"];
|
|
518
|
+
break;
|
|
519
|
+
default:
|
|
520
|
+
statuses = ["pending", "pending", "pending", "pending"];
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
const renderStep = (name: string, status: StepStatus, index: number): string => {
|
|
524
|
+
const stepNum = index + 1;
|
|
525
|
+
if (!theme) {
|
|
526
|
+
const sym = status === "done" ? "✔" : status === "active" ? "●" : status === "blocked" ? "⚠" : status === "stopped" ? "■" : "○";
|
|
527
|
+
return `[${stepNum}.${name} ${sym}]`;
|
|
528
|
+
}
|
|
529
|
+
switch (status) {
|
|
530
|
+
case "done":
|
|
531
|
+
return `[${stepNum}.${name} ${theme.fg("success", "✔")}]`;
|
|
532
|
+
case "active":
|
|
533
|
+
return `[${stepNum}.${name} ${theme.fg("accent", "●")}]`;
|
|
534
|
+
case "blocked":
|
|
535
|
+
return `[${stepNum}.${name} ${theme.fg("warning", "⚠")}]`;
|
|
536
|
+
case "stopped":
|
|
537
|
+
return `[${stepNum}.${name} ${theme.fg("muted", "■")}]`;
|
|
538
|
+
case "pending":
|
|
539
|
+
default:
|
|
540
|
+
return `[${stepNum}.${name} ${theme.fg("dim", "○")}]`;
|
|
541
|
+
}
|
|
542
|
+
};
|
|
543
|
+
|
|
544
|
+
const sep = theme ? ` ${theme.fg("dim", "─")} ` : " ─ ";
|
|
545
|
+
return milestones.map((m, i) => renderStep(m.name, statuses[i], i)).join(sep);
|
|
546
|
+
}
|
|
547
|
+
|
|
449
548
|
export function renderTaskOverview(view: TaskOverviewView, width = 120, theme?: Theme): string[] {
|
|
450
549
|
const label = (text: string) => (theme ? theme.fg("muted", text) : text);
|
|
451
550
|
const head = (text: string) => (theme ? theme.fg("accent", theme.bold(text)) : text);
|
|
@@ -456,6 +555,7 @@ export function renderTaskOverview(view: TaskOverviewView, width = 120, theme?:
|
|
|
456
555
|
}
|
|
457
556
|
if (view.active) {
|
|
458
557
|
lines.push(`${label("Active:")} ${formatTaskRailState(view.active.state, theme)} ${bounded(view.active.task_id, 60)}`);
|
|
558
|
+
lines.push(`${label(" Pipeline:")} ${renderPipelineMilestones(view.active.state, theme)}`);
|
|
459
559
|
lines.push(`${label(" Result:")} ${bounded(view.active.result, 100)}`);
|
|
460
560
|
lines.push(`${label(" Next:")} ${bounded(view.active.next, 100)}`);
|
|
461
561
|
} else {
|
|
@@ -501,15 +601,60 @@ function renderFinalLines(taskState: Record<string, unknown>, theme: Theme): str
|
|
|
501
601
|
+ strings(taskState.unresolved_user_decision_ids).length
|
|
502
602
|
+ strings(taskState.replan_required_ids).length;
|
|
503
603
|
const diffHash = string(taskState.diff_hash);
|
|
604
|
+
const divider = theme.fg("dim", "────────────────────────────────────────");
|
|
504
605
|
return [
|
|
606
|
+
divider,
|
|
607
|
+
theme.fg("accent", theme.bold("Final Settlement Summary")),
|
|
505
608
|
`${theme.fg("muted", "Acceptance:")} ${theme.fg(missing === 0 ? "success" : "warning", `${fresh}/${fresh + missing} fresh`)}`,
|
|
506
609
|
`${theme.fg("muted", "QA / Review:")} ${theme.fg("dim", approvals.length > 0 ? approvals.join(", ") : "not recorded")}`,
|
|
507
610
|
`${theme.fg("muted", "Residual blockers:")} ${theme.fg(blockers === 0 ? "dim" : "warning", String(blockers))}`,
|
|
508
611
|
`${theme.fg("muted", "Repository health:")} ${theme.fg("dim", "not assessed")}`,
|
|
509
612
|
`${theme.fg("muted", "Git:")} ${theme.fg("dim", diffHash ? `task diff ${diffHash.slice(0, 15)}` : "not reported")}`,
|
|
613
|
+
divider,
|
|
510
614
|
];
|
|
511
615
|
}
|
|
512
616
|
|
|
617
|
+
function formatDialogSummary(summary: string, theme: Theme): string {
|
|
618
|
+
const lines = summary.split("\n");
|
|
619
|
+
return lines.map((line) => {
|
|
620
|
+
const colonIdx = line.indexOf(":");
|
|
621
|
+
if (colonIdx === -1) return theme.fg("dim", line);
|
|
622
|
+
const key = line.slice(0, colonIdx).trim();
|
|
623
|
+
const value = line.slice(colonIdx + 1).trim();
|
|
624
|
+
let formattedValue = theme.fg("dim", value);
|
|
625
|
+
const lowerKey = key.toLowerCase();
|
|
626
|
+
if (lowerKey === "risk") {
|
|
627
|
+
const isHigh = /high|material|critical/i.test(value);
|
|
628
|
+
formattedValue = isHigh ? theme.fg("warning", theme.bold(value)) : theme.fg("accent", value);
|
|
629
|
+
} else if (lowerKey === "goal") {
|
|
630
|
+
formattedValue = theme.fg("accent", value);
|
|
631
|
+
} else if (lowerKey === "acceptance") {
|
|
632
|
+
formattedValue = theme.fg("success", value);
|
|
633
|
+
}
|
|
634
|
+
return `${theme.fg("muted", `${key}:`)} ${formattedValue}`;
|
|
635
|
+
}).join("\n");
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
export function boundedPath(path: string, max: number): string {
|
|
639
|
+
const width = visibleWidth(path);
|
|
640
|
+
if (width <= max) return path;
|
|
641
|
+
if (!path.includes("/")) return bounded(path, max);
|
|
642
|
+
const parts = path.split("/");
|
|
643
|
+
const fileName = parts.pop() ?? "";
|
|
644
|
+
const fileWidth = visibleWidth(fileName);
|
|
645
|
+
if (fileWidth + 2 >= max) {
|
|
646
|
+
return bounded(fileName, max);
|
|
647
|
+
}
|
|
648
|
+
const remaining = max - fileWidth - 3; // "…/"
|
|
649
|
+
let prefix = "";
|
|
650
|
+
for (const part of parts) {
|
|
651
|
+
const next = prefix ? `${prefix}/${part}` : part;
|
|
652
|
+
if (visibleWidth(next) > remaining) break;
|
|
653
|
+
prefix = next;
|
|
654
|
+
}
|
|
655
|
+
return prefix ? `${prefix}/…/${fileName}` : `…/${fileName}`;
|
|
656
|
+
}
|
|
657
|
+
|
|
513
658
|
function record(value: unknown): Record<string, unknown> | undefined {
|
|
514
659
|
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
515
660
|
? value as Record<string, unknown>
|
|
@@ -42,7 +42,7 @@ function probeHost(env = process.env, platform = process.platform, hostVersion)
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
// plugins/immune-brain/runtime/plugin_version.ts
|
|
45
|
-
var PLUGIN_VERSION = "3.6.
|
|
45
|
+
var PLUGIN_VERSION = "3.6.8";
|
|
46
46
|
|
|
47
47
|
// plugins/immune-brain/runtime/claude/interaction.ts
|
|
48
48
|
import { createHash, randomUUID } from "node:crypto";
|
|
@@ -90,6 +90,9 @@ with its `initiative_slug` parameter. That parameter is the opt-in: absent the c
|
|
|
90
90
|
`imm-loop` behavior is byte-identical to per-task Enrollment, and no batch state,
|
|
91
91
|
branch, or Batch Authorization exists. The Standalone Hosts expose the same tool
|
|
92
92
|
name and the same single parameter; it is never a batch of tasks the Host chose.
|
|
93
|
+
When an Initiative is referenced by its tracker Issue (e.g. `github #<number>`),
|
|
94
|
+
extract `initiative_slug` from the Issue body `<!-- immune-brain:initiative-id=<slug> -->`
|
|
95
|
+
marker or title prefix before invoking the tool.
|
|
93
96
|
|
|
94
97
|
Invoking it authorizes only a user-confirmed batch of already-planned child
|
|
95
98
|
TaskIntents. The Host projects the batch plan from the Initiative's published
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated by scripts/plugin_versioning.ts from the root package.json.
|
|
2
|
-
export const PLUGIN_VERSION = "3.6.
|
|
2
|
+
export const PLUGIN_VERSION = "3.6.8" as const;
|