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 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 5 Skills available automatically. Verify with:
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/ # 5 public Skills (trigger shims)
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 5 skills?** No. Just describe what you want — Pi routes to the right skill. Learn `imm-planner` and `imm-loop` first; the other two are occasional.
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 后 5 个 Skill 即自动可用。验证:
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/ # 5 个公开 Skills(触发 shim)
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` — 发布到 npm(需 `NPM_TOKEN` 或 `npm login`) |
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.0",
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": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "immune-brain",
3
- "version": "3.2.0",
3
+ "version": "3.2.1",
4
4
  "description": "Immune-Brain Claude Code Host: native Enrollment, QA, Review, and Kernel settlement.",
5
5
  "author": {
6
6
  "name": "Immune-Brain Team"
@@ -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); press d to expand`,
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: "Kernel authority repair requires literal-user approval",
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 literal-user approval`,
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 freshness revalidation` },
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, renderTaskRail(view), { placement: "aboveEditor" });
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) ?? "Continue through the projected authority";
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 renderTaskRail(view: TaskRailView): string[] {
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, 52)} · ${view.state}`,
292
- `Result: ${bounded(view.result, 112)}`,
293
- `Next: ${bounded(view.next, 112)}`,
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 - 3)}...`;
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 - 3;
376
+ const visible = max - 1;
347
377
  const start = Math.ceil(visible / 2);
348
- return `${value.slice(0, start)}...${value.slice(-(visible - 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` owns HANDOFF.md writes (boundary exception documented in skill)
121
- - `.imm/memory/` is the source of truth; HANDOFF.md is a convenience artifact
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` — pinned by live planning artifacts: `scripts/dist-sync-manifest.ts`, `tests/code-review-activation-contract.test.ts`, and packaged copy `plugins/immune-brain/dist/docs/specs/automatic-subagent-activation.spec.md`.
69
- - `docs/specs/opencode-native-plugin.spec.md` — dual-path pinned; `tests/python-reference-boundary.test.ts` resolves it at either `docs/specs/` or `docs/specs/archive/`.
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.