immune-brain 4.6.0 → 5.1.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/README.md +374 -46
- package/README.zh-CN.md +384 -47
- package/package.json +2 -1
- package/plugins/immune-brain/.claude-plugin/plugin.json +1 -1
- package/plugins/immune-brain/.pi-extension/imm-canary-enroll.ts +42 -44
- package/plugins/immune-brain/.pi-extension/imm-canary-work.ts +143 -474
- package/plugins/immune-brain/.pi-extension/imm-unattended-batch.ts +78 -87
- package/plugins/immune-brain/.pi-extension/pi-canary-assurance-progression.ts +7 -2
- package/plugins/immune-brain/.pi-extension/tsconfig.json +2 -2
- package/plugins/immune-brain/agents/immune-brain-advisory-reviewer.md +23 -0
- package/plugins/immune-brain/agents/immune-brain-qa.md +42 -0
- package/plugins/immune-brain/agents/immune-brain-reviewer.md +90 -1
- package/plugins/immune-brain/agents/immune-brain-ui-review.md +21 -0
- package/plugins/immune-brain/dist/BASELINE.md +4 -4
- package/plugins/immune-brain/dist/claude/mcp-server.mjs +8601 -6975
- package/plugins/immune-brain/dist/docs/reference/immune-brain-config.md +27 -0
- package/plugins/immune-brain/dist/docs/reference/planning-quality-gate.md +3 -3
- package/plugins/immune-brain/dist/docs/reference/subagent-dispatch-protocol.md +30 -1
- package/plugins/immune-brain/dist/imm-brainstorm.md +1 -1
- package/plugins/immune-brain/dist/imm-doc-prune.md +2 -2
- package/plugins/immune-brain/dist/{imm-agent-doc-maintain.md → imm-doc-slim.md} +9 -9
- package/plugins/immune-brain/dist/imm-planner.md +23 -8
- package/plugins/immune-brain/dist/imm-pr-fix.md +1 -1
- package/plugins/immune-brain/dist/{imm-review-retro.md → imm-retro.md} +26 -13
- package/plugins/immune-brain/dist/{imm-loop.md → imm-run.md} +231 -10
- package/plugins/immune-brain/dist/registry.yaml +9 -9
- package/plugins/immune-brain/dist/role-prompts/code-review.md +7 -0
- package/plugins/immune-brain/dist/role-prompts/executor.md +35 -2
- package/plugins/immune-brain/dist/role-prompts/lane-steward.md +44 -0
- package/plugins/immune-brain/runtime/assurance/coordinator.ts +83 -67
- package/plugins/immune-brain/runtime/assurance/host_port.ts +20 -0
- package/plugins/immune-brain/runtime/assurance/qa.ts +2 -2
- package/plugins/immune-brain/runtime/assurance/verdict_authority.ts +347 -0
- package/plugins/immune-brain/runtime/claude/interaction.ts +6 -0
- package/plugins/immune-brain/runtime/claude/kernel_ports.ts +78 -373
- package/plugins/immune-brain/runtime/claude/mcp_server.ts +26 -2
- package/plugins/immune-brain/runtime/claude/review_host.ts +48 -16
- package/plugins/immune-brain/runtime/claude/role_agents.ts +84 -0
- package/plugins/immune-brain/runtime/commands/kernel.ts +3 -6
- package/plugins/immune-brain/runtime/kernel/application.ts +6 -3
- package/plugins/immune-brain/runtime/kernel/assurance_projection.ts +15 -8
- package/plugins/immune-brain/runtime/kernel/canary_application.ts +5 -3
- package/plugins/immune-brain/runtime/kernel/enrollment.ts +149 -5
- package/plugins/immune-brain/runtime/kernel/index.ts +3 -1
- package/plugins/immune-brain/runtime/kernel/storage.ts +170 -11
- package/plugins/immune-brain/runtime/kernel/storage_paths.ts +13 -0
- package/plugins/immune-brain/runtime/local_initiative.ts +94 -0
- package/plugins/immune-brain/runtime/loop_contract.ts +77 -24
- package/plugins/immune-brain/runtime/plugin_version.ts +1 -1
- package/plugins/immune-brain/runtime/prompts/code-review.md +7 -0
- package/plugins/immune-brain/runtime/prompts/executor.md +35 -2
- package/plugins/immune-brain/runtime/prompts/lane-steward.md +44 -0
- package/plugins/immune-brain/runtime/role_prompt_bridge.ts +42 -2
- package/plugins/immune-brain/runtime/unattended/batch_git.ts +57 -27
- package/plugins/immune-brain/runtime/unattended/batch_integration.ts +387 -0
- package/plugins/immune-brain/runtime/unattended/batch_kernel_port.ts +106 -0
- package/plugins/immune-brain/runtime/unattended/batch_lanes.ts +909 -0
- package/plugins/immune-brain/runtime/unattended/batch_plan.ts +36 -11
- package/plugins/immune-brain/runtime/unattended/batch_preflight.ts +53 -36
- package/plugins/immune-brain/runtime/unattended/batch_reconfirmation.ts +34 -29
- package/plugins/immune-brain/runtime/unattended/batch_runner.ts +46 -91
- package/plugins/immune-brain/runtime/unattended/batch_schedule.ts +162 -0
- package/plugins/immune-brain/runtime/unattended/batch_state.ts +356 -8
- package/plugins/immune-brain/runtime/unattended/types.ts +21 -2
- package/plugins/immune-brain/runtime/workspace_scope.ts +34 -0
- package/plugins/immune-brain/skills/BASELINE.md +4 -4
- package/plugins/immune-brain/skills/imm-doc-prune/SKILL.md +1 -1
- package/plugins/immune-brain/skills/{imm-agent-doc-maintain → imm-doc-slim}/SKILL.md +9 -9
- package/plugins/immune-brain/skills/imm-planner/SKILL.md +4 -2
- package/plugins/immune-brain/skills/imm-pr-fix/SKILL.md +1 -1
- package/plugins/immune-brain/skills/{imm-review-retro → imm-retro}/SKILL.md +7 -7
- package/plugins/immune-brain/skills/{imm-review-retro → imm-retro}/scripts/review_retro.ts +46 -21
- package/plugins/immune-brain/skills/{imm-loop → imm-run}/SKILL.md +11 -7
- package/plugins/immune-brain/skills/registry.yaml +9 -9
- package/plugins/immune-brain/.pi-extension/runtime-stub.ts +0 -581
|
@@ -5,11 +5,13 @@
|
|
|
5
5
|
* Usage: bun review_retro.ts <days> [--root <sessions-dir>] [--project <substr>] [--top N]
|
|
6
6
|
*
|
|
7
7
|
* Counting rules (the 口径 that keeps the numbers honest):
|
|
8
|
-
* review executed = Agent(subagent_type="Review") tool call
|
|
9
|
-
* avgSc
|
|
8
|
+
* review executed = Agent(subagent_type="Review", any case) tool call
|
|
9
|
+
* avgSc = average score (0-10) from [SCORE: ...] tags in Review toolResult (the contract has no score)
|
|
10
|
+
* pass% = PASS rate over judged reviews: assurance_verdict `decision`, else the [VERDICT: ...] tag
|
|
10
11
|
* kernel:submit_review = the *registration* of that same review, reported separately (never added)
|
|
11
|
-
* attribution = the model behind the most recent edit/write before the review (the code's author)
|
|
12
|
-
* findings =
|
|
12
|
+
* attribution = the model behind the most recent edit/write/apply_patch before the review (the code's author)
|
|
13
|
+
* findings = submit_review verdict.findings plus legacy record_finding, deduped per session,
|
|
14
|
+
* harness bookkeeping split out
|
|
13
15
|
*/
|
|
14
16
|
import { createReadStream, existsSync, readdirSync } from "node:fs";
|
|
15
17
|
import { homedir } from "node:os";
|
|
@@ -18,12 +20,14 @@ import { createInterface } from "node:readline";
|
|
|
18
20
|
import { pathToFileURL } from "node:url";
|
|
19
21
|
|
|
20
22
|
const BOOKKEEPING = /recorded cleanly|receipt recorded|round recorded|no findings?\b/i;
|
|
21
|
-
const EDIT_TOOLS = new Set(["edit", "write", "multiedit"]);
|
|
23
|
+
const EDIT_TOOLS = new Set(["edit", "write", "multiedit", "apply_patch"]);
|
|
22
24
|
const SCORE_RE = /\[SCORE:\s*([\d.]+)\s*(?:\/\s*10)?\]/i;
|
|
23
25
|
const VERDICT_RE = /\[VERDICT:\s*(\w+)\]/i;
|
|
24
26
|
const RISK_RE = /\[RISK:\s*(\w+)\]/i;
|
|
25
27
|
const BLOCK_RE = /\[BLOCKING:\s*(\d+)\]/i;
|
|
26
28
|
const ADVIS_RE = /\[ADVISORY:\s*(\d+)\]/i;
|
|
29
|
+
const VERDICT_CONTRACT = "assurance_kernel/assurance_verdict";
|
|
30
|
+
const DECISION_RE = /"decision"\s*:\s*"(\w+)"/;
|
|
27
31
|
|
|
28
32
|
type ReviewTag = {
|
|
29
33
|
score: number;
|
|
@@ -48,6 +52,11 @@ function parseReviewTag(text: string): ReviewTag | null {
|
|
|
48
52
|
};
|
|
49
53
|
}
|
|
50
54
|
|
|
55
|
+
function parseDecision(text: string): string | null {
|
|
56
|
+
if (!text.includes(VERDICT_CONTRACT)) return null;
|
|
57
|
+
return DECISION_RE.exec(text)?.[1]?.toLowerCase() ?? null;
|
|
58
|
+
}
|
|
59
|
+
|
|
51
60
|
function extractText(content: unknown): string {
|
|
52
61
|
if (typeof content === "string") return content;
|
|
53
62
|
if (Array.isArray(content)) {
|
|
@@ -136,6 +145,8 @@ export async function run(argv: string[]): Promise<string> {
|
|
|
136
145
|
const findingsRaw = new Map<string, number>();
|
|
137
146
|
const scores = new Map<string, number[]>();
|
|
138
147
|
const verdicts = new Map<string, number>();
|
|
148
|
+
const judged = new Map<string, number>();
|
|
149
|
+
const passed = new Map<string, number>();
|
|
139
150
|
const risks = new Map<string, number>();
|
|
140
151
|
let files = 0;
|
|
141
152
|
|
|
@@ -144,6 +155,16 @@ export async function run(argv: string[]): Promise<string> {
|
|
|
144
155
|
let cwd = "";
|
|
145
156
|
let used = false;
|
|
146
157
|
const pending = new Map<string, string>();
|
|
158
|
+
const addFinding = (owner: string, finding: unknown) => {
|
|
159
|
+
const f = norm(finding);
|
|
160
|
+
const summ = String(f.summary ?? "");
|
|
161
|
+
const kind = BOOKKEEPING.test(summ) ? "bookkeeping" : String(f.kind ?? "");
|
|
162
|
+
const rawKey = `${owner}\0${kind}`;
|
|
163
|
+
bump(findingsRaw, rawKey);
|
|
164
|
+
const uniq = findUniq.get(rawKey) ?? new Set();
|
|
165
|
+
uniq.add(`${path}\0${summ.slice(0, 160)}`);
|
|
166
|
+
findUniq.set(rawKey, uniq);
|
|
167
|
+
};
|
|
147
168
|
const rl = createInterface({ input: createReadStream(path, { encoding: "utf8" }) });
|
|
148
169
|
for await (const raw of rl) {
|
|
149
170
|
const line = raw.trim();
|
|
@@ -179,7 +200,7 @@ export async function run(argv: string[]): Promise<string> {
|
|
|
179
200
|
if (EDIT_TOOLS.has(name)) {
|
|
180
201
|
bump(dev, mo);
|
|
181
202
|
editor = mo;
|
|
182
|
-
} else if (name === "Agent" && a.subagent_type === "
|
|
203
|
+
} else if (name === "Agent" && String(a.subagent_type ?? "").toLowerCase() === "review") {
|
|
183
204
|
const owner = editor ?? "no-edit (review-only)";
|
|
184
205
|
bump(rev, owner);
|
|
185
206
|
const ep = episode.get(owner) ?? new Set();
|
|
@@ -197,15 +218,10 @@ export async function run(argv: string[]): Promise<string> {
|
|
|
197
218
|
const t = tasks.get(owner) ?? new Set();
|
|
198
219
|
t.add(`${cwd}\0${String(a.task_id ?? "")}`);
|
|
199
220
|
tasks.set(owner, t);
|
|
221
|
+
const found = norm(act.verdict).findings;
|
|
222
|
+
if (Array.isArray(found)) for (const f of found) addFinding(owner, f);
|
|
200
223
|
} else if (op === "record_finding") {
|
|
201
|
-
|
|
202
|
-
const summ = String(f.summary ?? "");
|
|
203
|
-
const kind = BOOKKEEPING.test(summ) ? "bookkeeping" : String(f.kind ?? "");
|
|
204
|
-
const rawKey = `${owner}\0${kind}`;
|
|
205
|
-
bump(findingsRaw, rawKey);
|
|
206
|
-
const uniq = findUniq.get(rawKey) ?? new Set();
|
|
207
|
-
uniq.add(`${path}\0${summ.slice(0, 160)}`);
|
|
208
|
-
findUniq.set(rawKey, uniq);
|
|
224
|
+
addFinding(owner, act.finding);
|
|
209
225
|
}
|
|
210
226
|
}
|
|
211
227
|
}
|
|
@@ -214,7 +230,13 @@ export async function run(argv: string[]): Promise<string> {
|
|
|
214
230
|
const owner = pending.get(tcid);
|
|
215
231
|
if (!owner) continue;
|
|
216
232
|
pending.delete(tcid);
|
|
217
|
-
const
|
|
233
|
+
const text = extractText(m.content);
|
|
234
|
+
const tag = parseReviewTag(text);
|
|
235
|
+
const decision = parseDecision(text);
|
|
236
|
+
if (decision || tag) {
|
|
237
|
+
bump(judged, owner);
|
|
238
|
+
if (decision ? decision === "pass" : tag?.verdict === "PASS") bump(passed, owner);
|
|
239
|
+
}
|
|
218
240
|
if (!tag) continue;
|
|
219
241
|
const sl = scores.get(owner) ?? [];
|
|
220
242
|
sl.push(tag.score);
|
|
@@ -230,7 +252,9 @@ export async function run(argv: string[]): Promise<string> {
|
|
|
230
252
|
const emit = (s = "") => lines.push(s);
|
|
231
253
|
emit(`window: last ${args.days}d (UTC >= ${cut}Z) | sessions with activity: ${files} | root: ${args.root}`);
|
|
232
254
|
emit("review = Agent(Review) executed; attributed to the model that last edited the code under review");
|
|
233
|
-
emit("avgSc
|
|
255
|
+
emit("avgSc = parsed from Review [SCORE: .../10] tags (shows '-' if untagged)");
|
|
256
|
+
emit("pass% = assurance_verdict decision, else the [VERDICT: ...] tag, over judged reviews (shows '-' if none)");
|
|
257
|
+
emit("block/advis = submit_review verdict.findings plus legacy record_finding, deduped per session");
|
|
234
258
|
emit("");
|
|
235
259
|
const hdr =
|
|
236
260
|
`${"model".padEnd(42)}${"devEdits".padStart(9)}${"turns".padStart(6)}${"reviews".padStart(8)}${"uniq".padStart(5)}${"rev/100ed".padStart(10)}${"avgSc".padStart(6)}${"pass%".padStart(6)}${"registr".padStart(8)}${"block".padStart(6)}${"advis".padStart(6)}${"noisy".padStart(6)}`;
|
|
@@ -250,8 +274,8 @@ export async function run(argv: string[]): Promise<string> {
|
|
|
250
274
|
const rate = d ? ((100 * r) / d).toFixed(1) : "-";
|
|
251
275
|
const sl = scores.get(mo) ?? [];
|
|
252
276
|
const avgSc = sl.length ? (sl.reduce((x, y) => x + y, 0) / sl.length).toFixed(1) : "-";
|
|
253
|
-
const
|
|
254
|
-
const passPct =
|
|
277
|
+
const judgedCnt = judged.get(mo) ?? 0;
|
|
278
|
+
const passPct = judgedCnt ? `${Math.round((100 * (passed.get(mo) ?? 0)) / judgedCnt)}%` : "-";
|
|
255
279
|
const block = findUniq.get(`${mo}\0blocking`)?.size ?? 0;
|
|
256
280
|
const advis = findUniq.get(`${mo}\0advisory`)?.size ?? 0;
|
|
257
281
|
const noisy = findUniq.get(`${mo}\0bookkeeping`)?.size ?? 0;
|
|
@@ -264,8 +288,9 @@ export async function run(argv: string[]): Promise<string> {
|
|
|
264
288
|
const totAvg = totalScores.length
|
|
265
289
|
? (totalScores.reduce((x, y) => x + y, 0) / totalScores.length).toFixed(1)
|
|
266
290
|
: "-";
|
|
267
|
-
const totPass = shown.reduce((n, mo) => n + (
|
|
268
|
-
const
|
|
291
|
+
const totPass = shown.reduce((n, mo) => n + (passed.get(mo) ?? 0), 0);
|
|
292
|
+
const totJudged = shown.reduce((n, mo) => n + (judged.get(mo) ?? 0), 0);
|
|
293
|
+
const totPassPct = totJudged ? `${Math.round((100 * totPass) / totJudged)}%` : "-";
|
|
269
294
|
const totBlock = [...findUniq.entries()].reduce((n, [k, v]) => n + (k.endsWith("\0blocking") ? v.size : 0), 0);
|
|
270
295
|
const totAdvis = [...findUniq.entries()].reduce((n, [k, v]) => n + (k.endsWith("\0advisory") ? v.size : 0), 0);
|
|
271
296
|
const totNoisy = [...findUniq.entries()].reduce((n, [k, v]) => n + (k.endsWith("\0bookkeeping") ? v.size : 0), 0);
|
|
@@ -286,7 +311,7 @@ export async function run(argv: string[]): Promise<string> {
|
|
|
286
311
|
else for (const [name, n] of toolRows) emit(`${String(n).padStart(5)} ${name}`);
|
|
287
312
|
|
|
288
313
|
emit("");
|
|
289
|
-
emit("=== review quality & scores (
|
|
314
|
+
emit("=== review quality & scores (tagged reviews only) ===");
|
|
290
315
|
const scoredModels = [...scores.keys()]
|
|
291
316
|
.filter((m) => (scores.get(m) ?? []).length > 0)
|
|
292
317
|
.sort((a, b) => (scores.get(b)?.length ?? 0) - (scores.get(a)?.length ?? 0));
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: imm-
|
|
2
|
+
name: imm-run
|
|
3
3
|
description: Use when the user explicitly requests execution or resumption of an Immune-Brain task.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Immune-Brain: Loop
|
|
7
7
|
|
|
8
|
-
Use [`../../dist/imm-
|
|
8
|
+
Use [`../../dist/imm-run.md`](../../dist/imm-run.md) as the canonical contract
|
|
9
9
|
index, not a whole-document read, in the current host conversation. Explicit entry only:
|
|
10
10
|
ordinary host input never resumes a Managed owner implicitly.
|
|
11
11
|
|
|
@@ -23,8 +23,12 @@ Read each linked heading body up to the next heading; nested sections and
|
|
|
23
23
|
references load only under their own condition. Never read the whole contract
|
|
24
24
|
or all references as an entry prerequisite.
|
|
25
25
|
|
|
26
|
-
- common: [Shared Guards](../../dist/BASELINE.md#shared-guards), [Workflow Activation](../../dist/BASELINE.md#workflow-activation), [Host Confirmation Boundary](../../dist/BASELINE.md#host-confirmation-boundary), [Kernel Canary Routing and Authority](../../dist/imm-
|
|
27
|
-
- unattended batch run, or any question about whether `imm-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
26
|
+
- common: [Shared Guards](../../dist/BASELINE.md#shared-guards), [Workflow Activation](../../dist/BASELINE.md#workflow-activation), [Host Confirmation Boundary](../../dist/BASELINE.md#host-confirmation-boundary), [Kernel Canary Routing and Authority](../../dist/imm-run.md#kernel-canary-routing-and-authority)
|
|
27
|
+
- unattended batch run, or any question about whether `imm-run` starts one: [Unattended Batch Opt-In](../../dist/imm-run.md#unattended-batch-opt-in)
|
|
28
|
+
- parallel batch (`max_parallel`, `lane_offers`, Lane admission or integration): [Parallel Batch Opt-In](../../dist/imm-run.md#parallel-batch-opt-in)
|
|
29
|
+
- a lane-mode report carries an `executor` handoff, or a Lane's Executor Host session has ended: [Lane Executor Supervision](../../dist/imm-run.md#lane-executor-supervision)
|
|
30
|
+
- that Parent runs inside Herdr (`HERDR_ENV=1`): [Herdr Lane Tabs](../../dist/imm-run.md#herdr-lane-tabs)
|
|
31
|
+
- a lane-mode batch is about to start, to resolve the repository's parallelism, Executor Host, model and effort: [Lane Preferences](../../dist/imm-run.md#lane-preferences)
|
|
32
|
+
- steady execution: [Verification and Local Recovery](../../dist/BASELINE.md#verification-and-local-recovery), [Execution Loop](../../dist/imm-run.md#execution-loop), [Observable Output](../../dist/imm-run.md#observable-output)
|
|
33
|
+
- rework, scope expansion, breaking revision, user decision, stop, interruption or unknown state before any action: [Decisions and Recovery](../../dist/imm-run.md#decisions-and-recovery), [Failure Output](../../dist/imm-run.md#failure-output); re-read `status`, then the pending obligation. Rework submits the verdict before editing, and an uncertain interruption resumes from exact task/run authority facts rather than a summary.
|
|
34
|
+
- review or post-settlement learning: [Review and Learning](../../dist/imm-run.md#review-and-learning)
|
|
@@ -18,10 +18,10 @@ skills:
|
|
|
18
18
|
role_class: authority
|
|
19
19
|
canonical: true
|
|
20
20
|
output_artifacts: [validated_plan]
|
|
21
|
-
next_actions: [imm-
|
|
21
|
+
next_actions: [imm-run]
|
|
22
22
|
boundary: Owns plan creation and revision; no executor edits.
|
|
23
|
-
- name: imm-
|
|
24
|
-
path: skills/imm-
|
|
23
|
+
- name: imm-run
|
|
24
|
+
path: skills/imm-run/SKILL.md
|
|
25
25
|
role: coordinate
|
|
26
26
|
title: Run
|
|
27
27
|
role_class: coordinator
|
|
@@ -47,19 +47,19 @@ skills:
|
|
|
47
47
|
output_artifacts: [prune_report]
|
|
48
48
|
next_actions: []
|
|
49
49
|
boundary: Prune stale current documentation after explicit manifest approval; no Managed authority mutation or authority-artifact deletion.
|
|
50
|
-
- name: imm-
|
|
51
|
-
path: skills/imm-
|
|
50
|
+
- name: imm-doc-slim
|
|
51
|
+
path: skills/imm-doc-slim/SKILL.md
|
|
52
52
|
role: execute
|
|
53
|
-
title:
|
|
53
|
+
title: Doc Slim
|
|
54
54
|
role_class: repair
|
|
55
55
|
canonical: true
|
|
56
56
|
output_artifacts: [maintain_report]
|
|
57
57
|
next_actions: []
|
|
58
58
|
boundary: Minimize tracked agent-instruction context after explicit manifest approval; no Managed authority mutation, contract installation, or reference-document creation.
|
|
59
|
-
- name: imm-
|
|
60
|
-
path: skills/imm-
|
|
59
|
+
- name: imm-retro
|
|
60
|
+
path: skills/imm-retro/SKILL.md
|
|
61
61
|
role: execute
|
|
62
|
-
title:
|
|
62
|
+
title: Retro
|
|
63
63
|
role_class: discovery
|
|
64
64
|
canonical: true
|
|
65
65
|
output_artifacts: [retro_report]
|