immune-brain 3.2.0 → 3.2.1
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 +5 -5
- package/README.zh-CN.md +5 -5
- package/package.json +3 -3
- package/plugins/immune-brain/.claude-plugin/plugin.json +1 -1
- package/plugins/immune-brain/.pi-extension/imm-canary-enroll.ts +1 -3
- package/plugins/immune-brain/.pi-extension/imm-canary-work.ts +3 -3
- package/plugins/immune-brain/.pi-extension/pi-canary-interaction.ts +39 -9
- package/plugins/immune-brain/dist/docs/reference/HANDOFF-template.md +2 -2
- package/plugins/immune-brain/dist/docs/reference/planning-artifact-retention.md +2 -2
package/README.md
CHANGED
|
@@ -46,7 +46,7 @@ This repo is a Pi package — Pi discovers Skills and extensions from `package.j
|
|
|
46
46
|
}
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
No extra server config is needed. Installing the package via Pi makes all
|
|
49
|
+
No extra server config is needed. Installing the package via Pi makes all 6 Skills available automatically. Verify with:
|
|
50
50
|
|
|
51
51
|
```bash
|
|
52
52
|
bun test # run all tests
|
|
@@ -165,7 +165,7 @@ See [`docs/reference/immune-brain-config.md`](docs/reference/immune-brain-config
|
|
|
165
165
|
package.json # Pi package manifest (skills + extensions)
|
|
166
166
|
plugins/immune-brain/
|
|
167
167
|
├── .pi-extension/ # Pi TUI + Kernel authority extension
|
|
168
|
-
├── skills/ #
|
|
168
|
+
├── skills/ # 6 public Skills (trigger shims)
|
|
169
169
|
├── dist/ # Built skill contracts & references
|
|
170
170
|
├── runtime/ # Bun + TypeScript runtime & Kernel
|
|
171
171
|
└── bin/ # CLI wrappers (→ runtime/v4_runtime.ts)
|
|
@@ -183,7 +183,7 @@ docs/specs/ # Living specs (updated in place)
|
|
|
183
183
|
|
|
184
184
|
## FAQ
|
|
185
185
|
|
|
186
|
-
**Do I need to learn all
|
|
186
|
+
**Do I need to learn all 6 skills?** No. Just describe what you want — Pi routes to the right skill. Learn `imm-planner` and `imm-loop` first; the other four are occasional.
|
|
187
187
|
|
|
188
188
|
**What if I interrupt or close Pi mid-task?** State is on disk (`.imm/` + TaskIntent). Re-enter `imm-loop` to resume — the Kernel projection is authoritative.
|
|
189
189
|
|
|
@@ -202,8 +202,8 @@ This repo uses [Changesets](https://github.com/changesets/changesets) for versio
|
|
|
202
202
|
| Task | Command |
|
|
203
203
|
|------|---------|
|
|
204
204
|
| Add a changeset | `bunx changeset` — pick bump (patch/minor/major) and write summary |
|
|
205
|
-
| Bump version | `bun run changeset:version` — updates `package.json` + `CHANGELOG.md
|
|
206
|
-
| Publish (local) | `bun run changeset:publish` — publishes to npm (needs `NPM_TOKEN` or `npm login`) |
|
|
205
|
+
| Bump version | `bun run changeset:version` — updates `package.json` + `CHANGELOG.md`, then syncs and validates the Claude plugin manifest |
|
|
206
|
+
| Publish (local) | `bun run changeset:publish` — validates manifest versions, then publishes to npm (needs `NPM_TOKEN` or `npm login`) |
|
|
207
207
|
|
|
208
208
|
**Automated flow (recommended):**
|
|
209
209
|
1. Push changesets to `main` → workflow opens a “Version Packages” PR.
|
package/README.zh-CN.md
CHANGED
|
@@ -46,7 +46,7 @@ Pi 与 Claude Code 是支持的宿主。未声明的适配器仍不受支持。C
|
|
|
46
46
|
}
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
无需额外 server 配置,通过 Pi 安装本 package 后
|
|
49
|
+
无需额外 server 配置,通过 Pi 安装本 package 后 6 个 Skill 即自动可用。验证:
|
|
50
50
|
|
|
51
51
|
```bash
|
|
52
52
|
bun test # 全量测试
|
|
@@ -165,7 +165,7 @@ Immune-Brain **没有独立配置文件**,偏好设置写在 `AGENTS.md`(仓
|
|
|
165
165
|
package.json # Pi package manifest(skills + extensions)
|
|
166
166
|
plugins/immune-brain/
|
|
167
167
|
├── .pi-extension/ # Pi TUI + Kernel 扩展
|
|
168
|
-
├── skills/ #
|
|
168
|
+
├── skills/ # 6 个公开 Skills(触发 shim)
|
|
169
169
|
├── dist/ # 构建后的 skill 契约与参考文档
|
|
170
170
|
├── runtime/ # Bun + TypeScript 运行时与 Kernel
|
|
171
171
|
└── bin/ # CLI wrappers(→ runtime/v4_runtime.ts)
|
|
@@ -183,7 +183,7 @@ docs/specs/ # Living specs(原地更新)
|
|
|
183
183
|
|
|
184
184
|
## 常见问题
|
|
185
185
|
|
|
186
|
-
**需要记住所有 Skill 吗?** 不需要,直接描述需求即可,Pi 会自动路由。先掌握 `imm-planner` 和 `imm-loop
|
|
186
|
+
**需要记住所有 Skill 吗?** 不需要,直接描述需求即可,Pi 会自动路由。先掌握 `imm-planner` 和 `imm-loop`,另外四个按需使用。
|
|
187
187
|
|
|
188
188
|
**中途关闭 Pi 会怎样?** 状态已落盘(`.imm/` + TaskIntent),重新进入 `imm-loop` 即可恢复,以 Kernel projection 为准。
|
|
189
189
|
|
|
@@ -202,8 +202,8 @@ docs/specs/ # Living specs(原地更新)
|
|
|
202
202
|
| 任务 | 命令 |
|
|
203
203
|
|------|------|
|
|
204
204
|
| 创建 changeset | `bunx changeset` — 选择 bump 类型(patch/minor/major)并填写说明 |
|
|
205
|
-
| 升级版本 | `bun run changeset:version` — 更新 `package.json` + `CHANGELOG.md
|
|
206
|
-
| 本地发布 | `bun run changeset:publish` —
|
|
205
|
+
| 升级版本 | `bun run changeset:version` — 更新 `package.json` + `CHANGELOG.md`,然后同步并校验 Claude plugin manifest |
|
|
206
|
+
| 本地发布 | `bun run changeset:publish` — 校验 manifest 版本后发布到 npm(需 `NPM_TOKEN` 或 `npm login`) |
|
|
207
207
|
|
|
208
208
|
**自动化流程(推荐):**
|
|
209
209
|
1. 推送 changeset 到 `main` → workflow 自动创建 “Version Packages” PR。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "immune-brain",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.1",
|
|
4
4
|
"description": "Immune-Brain agent skill system",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
},
|
|
30
30
|
"scripts": {
|
|
31
31
|
"changeset": "changeset",
|
|
32
|
-
"changeset:version": "changeset version && bun scripts/plugin_versioning.ts stamp",
|
|
33
|
-
"changeset:publish": "changeset publish",
|
|
32
|
+
"changeset:version": "changeset version && bun scripts/plugin_versioning.ts stamp && bun scripts/plugin_versioning.ts validate",
|
|
33
|
+
"changeset:publish": "bun scripts/plugin_versioning.ts validate && changeset publish",
|
|
34
34
|
"release": "bun run changeset:publish"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
@@ -458,9 +458,7 @@ async function executeForegroundEnrollment(
|
|
|
458
458
|
`Goal: ${taskIntent.intent.goal}`,
|
|
459
459
|
`Risk: ${taskIntent.intent.risk}`,
|
|
460
460
|
`Scope: ${taskIntent.intent.scope_hint.length > 0 ? taskIntent.intent.scope_hint.join(", ") : "(none)"}`,
|
|
461
|
-
`Acceptance: ${taskIntent.intent.acceptance.length} descriptor(s)
|
|
462
|
-
`Intent digest: ${preparation.intent.content_hash}`,
|
|
463
|
-
`Preparation digest: ${preparation.digest}`,
|
|
461
|
+
`Acceptance: ${taskIntent.intent.acceptance.length} descriptor(s)`,
|
|
464
462
|
].join("\n");
|
|
465
463
|
const confirmationDetails = [
|
|
466
464
|
`Acceptance descriptors:`,
|
|
@@ -477,7 +477,7 @@ export default function (
|
|
|
477
477
|
presentTaskRail(ctx, {
|
|
478
478
|
task_id: taskId,
|
|
479
479
|
state: "Approval required",
|
|
480
|
-
result: "
|
|
480
|
+
result: "Authority repair needs your approval",
|
|
481
481
|
next: "Decide whether to repair the stale claim",
|
|
482
482
|
});
|
|
483
483
|
const repairSelection = await requestAuthorityDialog(pi, ctx, {
|
|
@@ -854,7 +854,7 @@ export default function (
|
|
|
854
854
|
presentTaskRail(ctx, {
|
|
855
855
|
task_id: taskId,
|
|
856
856
|
state: "Approval required",
|
|
857
|
-
result: `${operation} requires
|
|
857
|
+
result: `${operation} requires your confirmation`,
|
|
858
858
|
next: `Decide ${operation}`,
|
|
859
859
|
});
|
|
860
860
|
const attention = {
|
|
@@ -870,7 +870,7 @@ export default function (
|
|
|
870
870
|
details: dialogDetails,
|
|
871
871
|
signal: ctx.signal,
|
|
872
872
|
actions: [
|
|
873
|
-
{ value: "authorize", label: "Authorize", description: `Apply ${operation} after
|
|
873
|
+
{ value: "authorize", label: "Authorize", description: `Apply ${operation} after re-checking state` },
|
|
874
874
|
{ value: "cancel", label: "Cancel", description: "Leave managed authority unchanged" },
|
|
875
875
|
],
|
|
876
876
|
});
|
|
@@ -161,7 +161,14 @@ export async function requestAuthorityDialog<T extends string, R = T | undefined
|
|
|
161
161
|
|
|
162
162
|
export function presentTaskRail(ctx: UiContext, view: TaskRailView): void {
|
|
163
163
|
try {
|
|
164
|
-
ctx.ui.setWidget(TASK_RAIL_KEY,
|
|
164
|
+
ctx.ui.setWidget(TASK_RAIL_KEY, (_tui, theme) => {
|
|
165
|
+
return {
|
|
166
|
+
render(width: number): string[] {
|
|
167
|
+
return renderTaskRail(view, width, theme);
|
|
168
|
+
},
|
|
169
|
+
invalidate(): void {},
|
|
170
|
+
};
|
|
171
|
+
}, { placement: "aboveEditor" });
|
|
165
172
|
if (view.state === "Completed" || view.state === "Stopped") terminalRailUis.add(ctx.ui);
|
|
166
173
|
else terminalRailUis.delete(ctx.ui);
|
|
167
174
|
} catch {
|
|
@@ -180,7 +187,7 @@ export function presentTaskRailResult(
|
|
|
180
187
|
const operation = string(details.operation);
|
|
181
188
|
const rawState = string(details.state);
|
|
182
189
|
const result = string(details.result) ?? string(details.reason) ?? operation ?? rawState ?? "Task state updated";
|
|
183
|
-
const next = string(details.next_action) ?? "
|
|
190
|
+
const next = string(details.next_action) ?? "Follow the projected Obligation";
|
|
184
191
|
presentTaskRail(ctx, {
|
|
185
192
|
task_id: taskId,
|
|
186
193
|
state: railState({ lifecycle, obligation: string(taskState?.next_obligation), operation, state: rawState }),
|
|
@@ -286,11 +293,34 @@ function emitAttention(pi: EventPublisher, event: UserAttentionEventV1): void {
|
|
|
286
293
|
}
|
|
287
294
|
}
|
|
288
295
|
|
|
289
|
-
function
|
|
296
|
+
function formatTaskRailState(state: TaskRailState, theme?: Theme): string {
|
|
297
|
+
const symbolAndColor: Record<TaskRailState, { symbol: string; color: string }> = {
|
|
298
|
+
Planning: { symbol: "●", color: "muted" },
|
|
299
|
+
"Approval required": { symbol: "▲", color: "accent" },
|
|
300
|
+
Working: { symbol: "●", color: "accent" },
|
|
301
|
+
Verifying: { symbol: "●", color: "accent" },
|
|
302
|
+
Reviewing: { symbol: "●", color: "accent" },
|
|
303
|
+
Blocked: { symbol: "⚠", color: "warning" },
|
|
304
|
+
Completed: { symbol: "✓", color: "success" },
|
|
305
|
+
Stopped: { symbol: "■", color: "muted" },
|
|
306
|
+
};
|
|
307
|
+
const cfg = symbolAndColor[state] ?? { symbol: "●", color: "dim" };
|
|
308
|
+
if (!theme) return `${cfg.symbol} ${state}`;
|
|
309
|
+
return `${theme.fg(cfg.color, cfg.symbol)} ${theme.fg(cfg.color, state)}`;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function renderTaskRail(view: TaskRailView, width = 120, theme?: Theme): string[] {
|
|
313
|
+
const prefixWidth = 8; // "Result: " or "Next: "
|
|
314
|
+
const availableContentWidth = Math.max(20, width - prefixWidth);
|
|
315
|
+
const taskIdWidth = Math.max(16, Math.min(52, width - 26));
|
|
316
|
+
const stateFormatted = formatTaskRailState(view.state, theme);
|
|
317
|
+
const label = (text: string) => (theme ? theme.fg("muted", text) : text);
|
|
318
|
+
const body = (text: string) => (theme ? theme.fg("dim", text) : text);
|
|
319
|
+
|
|
290
320
|
return [
|
|
291
|
-
`Task ${boundedMiddle(view.task_id,
|
|
292
|
-
|
|
293
|
-
|
|
321
|
+
`Task ${boundedMiddle(view.task_id, taskIdWidth)} · ${stateFormatted}`,
|
|
322
|
+
`${label("Result:")} ${body(bounded(view.result, availableContentWidth))}`,
|
|
323
|
+
`${label("Next:")} ${body(bounded(view.next, availableContentWidth))}`,
|
|
294
324
|
];
|
|
295
325
|
}
|
|
296
326
|
|
|
@@ -338,12 +368,12 @@ function strings(value: unknown): string[] {
|
|
|
338
368
|
}
|
|
339
369
|
|
|
340
370
|
function bounded(value: string, max: number): string {
|
|
341
|
-
return value.length <= max ? value : `${value.slice(0, max -
|
|
371
|
+
return value.length <= max ? value : `${value.slice(0, max - 1)}…`;
|
|
342
372
|
}
|
|
343
373
|
|
|
344
374
|
function boundedMiddle(value: string, max: number): string {
|
|
345
375
|
if (value.length <= max) return value;
|
|
346
|
-
const visible = max -
|
|
376
|
+
const visible = max - 1;
|
|
347
377
|
const start = Math.ceil(visible / 2);
|
|
348
|
-
return `${value.slice(0, start)}
|
|
378
|
+
return `${value.slice(0, start)}…${value.slice(-(visible - start))}`;
|
|
349
379
|
}
|
|
@@ -117,6 +117,6 @@ kept for historical reference only.
|
|
|
117
117
|
|
|
118
118
|
## Notes
|
|
119
119
|
|
|
120
|
-
- `imm-work`
|
|
121
|
-
- `.imm/memory/`
|
|
120
|
+
- Historical: `imm-work` previously owned HANDOFF.md writes (v3 boundary exception); that writer was removed with the v3 State Ledger retirement and no current runtime code rewrites the generated block.
|
|
121
|
+
- Historical: `.imm/memory/` was the v3 source of truth; it is retired. The current durable source of truth is the TaskRecord v4 under `.imm/state/tasks/`, with HANDOFF.md as a convenience artifact only.
|
|
122
122
|
- Priority files list is advisory (max 5) and exists only to make Pi session continuation faster
|
|
@@ -65,8 +65,8 @@ listed here while its program was in flight; when that program closed the
|
|
|
65
65
|
justification expired, and the spec was archived rather than left protected by
|
|
66
66
|
text that no longer described it.
|
|
67
67
|
|
|
68
|
-
- `docs/specs/automatic-subagent-activation.spec.md` —
|
|
69
|
-
- `docs/specs/opencode-native-plugin.spec.md` — dual-path
|
|
68
|
+
- `docs/specs/automatic-subagent-activation.spec.md` — EXPIRED: this exemption lapsed when its program closed and the spec was archived to `docs/specs/archive/automatic-subagent-activation.spec.md` (the packaged copy pin in `tests/code-review-activation-contract.test.ts` remains in force).
|
|
69
|
+
- `docs/specs/opencode-native-plugin.spec.md` — EXPIRED: this exemption lapsed when its program closed and the spec was archived to `docs/specs/archive/opencode-native-plugin.spec.md` (the dual-path resolution in `tests/python-reference-boundary.test.ts` remains in force).
|
|
70
70
|
- `docs/plans/archive/2026-06-29-001-feat-bun-typescript-runtime-migration-plan.md` — frozen plan: its `docs/specs/opencode-native-plugin.spec.md` reference is exempt from archive-path rewriting because it is part of `REFERENCE_SIGNATURE = "e89bf7809875d215c2ca0275c8f6e86e024dd451934fdc04d8e4a422bbd03a6c"` in `tests/plan-validation.test.ts`; rewriting it changes the cross-runtime signature.
|
|
71
71
|
|
|
72
72
|
Non-terminal artifacts remain durable at their existing paths by default.
|