immune-brain 3.6.5 → 3.6.7

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.
Files changed (49) hide show
  1. package/README.md +69 -3
  2. package/README.zh-CN.md +23 -3
  3. package/package.json +2 -1
  4. package/plugins/immune-brain/.claude-plugin/plugin.json +1 -1
  5. package/plugins/immune-brain/.pi-extension/imm-canary-work.ts +60 -21
  6. package/plugins/immune-brain/.pi-extension/imm-unattended-batch.ts +932 -0
  7. package/plugins/immune-brain/.pi-extension/pi-canary-interaction.ts +38 -10
  8. package/plugins/immune-brain/.pi-extension/runtime-stub.ts +200 -2
  9. package/plugins/immune-brain/dist/BASELINE.md +48 -15
  10. package/plugins/immune-brain/dist/claude/mcp-server.mjs +3415 -228
  11. package/plugins/immune-brain/dist/docs/reference/planning-quality-gate.md +1 -1
  12. package/plugins/immune-brain/dist/docs/reference/subagent-dispatch-protocol.md +1 -1
  13. package/plugins/immune-brain/dist/imm-agent-doc-maintain.md +9 -1
  14. package/plugins/immune-brain/dist/imm-brainstorm.md +49 -35
  15. package/plugins/immune-brain/dist/imm-doc-prune.md +7 -1
  16. package/plugins/immune-brain/dist/imm-loop.md +45 -11
  17. package/plugins/immune-brain/dist/imm-planner.md +65 -28
  18. package/plugins/immune-brain/dist/imm-pr-fix.md +6 -2
  19. package/plugins/immune-brain/dist/role-prompts/code-review.md +9 -1
  20. package/plugins/immune-brain/dist/role-prompts/executor.md +18 -10
  21. package/plugins/immune-brain/dist/role-prompts/pr-fix.md +5 -2
  22. package/plugins/immune-brain/runtime/assurance/coordinator.ts +101 -3
  23. package/plugins/immune-brain/runtime/assurance/verification.ts +13 -2
  24. package/plugins/immune-brain/runtime/claude/interaction.ts +16 -3
  25. package/plugins/immune-brain/runtime/claude/kernel_ports.ts +840 -17
  26. package/plugins/immune-brain/runtime/claude/mcp_server.ts +72 -10
  27. package/plugins/immune-brain/runtime/github_issue_tracker.ts +1018 -17
  28. package/plugins/immune-brain/runtime/kernel/canary_application.ts +16 -1
  29. package/plugins/immune-brain/runtime/kernel/completion.ts +19 -1
  30. package/plugins/immune-brain/runtime/kernel/reducer.ts +165 -12
  31. package/plugins/immune-brain/runtime/kernel/refutation.ts +82 -0
  32. package/plugins/immune-brain/runtime/kernel/types.ts +34 -1
  33. package/plugins/immune-brain/runtime/kernel/validation.ts +202 -9
  34. package/plugins/immune-brain/runtime/plugin_version.ts +1 -1
  35. package/plugins/immune-brain/runtime/prompts/code-review.md +9 -1
  36. package/plugins/immune-brain/runtime/prompts/executor.md +18 -10
  37. package/plugins/immune-brain/runtime/prompts/pr-fix.md +5 -2
  38. package/plugins/immune-brain/runtime/unattended/batch_git.ts +775 -0
  39. package/plugins/immune-brain/runtime/unattended/batch_plan.ts +203 -0
  40. package/plugins/immune-brain/runtime/unattended/batch_runner.ts +1224 -0
  41. package/plugins/immune-brain/runtime/unattended/batch_state.ts +360 -0
  42. package/plugins/immune-brain/runtime/unattended/types.ts +60 -0
  43. package/plugins/immune-brain/skills/BASELINE.md +48 -15
  44. package/plugins/immune-brain/skills/imm-agent-doc-maintain/SKILL.md +20 -4
  45. package/plugins/immune-brain/skills/imm-brainstorm/SKILL.md +24 -64
  46. package/plugins/immune-brain/skills/imm-doc-prune/SKILL.md +18 -3
  47. package/plugins/immune-brain/skills/imm-loop/SKILL.md +21 -6
  48. package/plugins/immune-brain/skills/imm-planner/SKILL.md +35 -8
  49. package/plugins/immune-brain/skills/imm-pr-fix/SKILL.md +17 -3
@@ -25,8 +25,10 @@ export const TOOLS = [
25
25
  { name: "request_authorization", description: "Apply exact literal-user authorization.", privileged: true },
26
26
  { name: "approve_breaking_intent_revision", description: "Approve a breaking TaskIntent revision.", privileged: true },
27
27
  { name: "stop", description: "Stop the active task with literal-user authority.", privileged: true },
28
+ { name: "start_unattended_batch", description: "Start an unattended serial batch run for an Initiative after native confirmation.", privileged: true },
28
29
  { name: "repair_authority_state", description: "Repair a proven recoverable stale backend claim.", privileged: false },
29
30
  { name: "resolve_finding", description: "Resolve one open blocking or advisory finding whose cause is fixed and verified.", privileged: false },
31
+ { name: "refute_finding", description: "Refute one open finding by binding the fresh passing QA attestation that contradicts it.", privileged: false },
30
32
  ] as const;
31
33
 
32
34
  export function listMcpTools() {
@@ -36,17 +38,26 @@ export function listMcpTools() {
36
38
  inputSchema: {
37
39
  type: "object",
38
40
  properties: {
39
- task_id: { type: "string" },
40
- ...(tool.name === "approve_breaking_intent_revision" ? { next_intent: { type: "object" } } : {}),
41
- ...(tool.name === "stop" ? { reason: { type: "string" } } : {}),
42
- ...(tool.name === "submit_review" ? { verdict: { type: "object" } } : {}),
43
- ...(tool.name === "resolve_finding" ? { finding_id: { type: "string" } } : {}),
41
+ ...(tool.name === "start_unattended_batch"
42
+ ? { initiative_slug: { type: "string" } }
43
+ : {
44
+ task_id: { type: "string" },
45
+ ...(tool.name === "approve_breaking_intent_revision" ? { next_intent: { type: "object" } } : {}),
46
+ ...(tool.name === "stop" ? { reason: { type: "string" } } : {}),
47
+ ...(tool.name === "submit_review" ? { verdict: { type: "object" } } : {}),
48
+ ...(tool.name === "resolve_finding" ? { finding_id: { type: "string" } } : {}),
49
+ ...(tool.name === "refute_finding" ? { finding_id: { type: "string" }, attestation_id: { type: "string" } } : {}),
50
+ }),
44
51
  },
45
- required: tool.name === "submit_review"
46
- ? ["task_id", "verdict"]
47
- : tool.name === "resolve_finding"
48
- ? ["task_id", "finding_id"]
49
- : ["task_id"],
52
+ required: tool.name === "start_unattended_batch"
53
+ ? ["initiative_slug"]
54
+ : tool.name === "submit_review"
55
+ ? ["task_id", "verdict"]
56
+ : tool.name === "resolve_finding"
57
+ ? ["task_id", "finding_id"]
58
+ : tool.name === "refute_finding"
59
+ ? ["task_id", "finding_id", "attestation_id"]
60
+ : ["task_id"],
50
61
  },
51
62
  annotations: tool.privileged ? privilegedAnnotations() : { readOnlyHint: tool.name === "status" },
52
63
  }));
@@ -63,6 +74,9 @@ export interface McpRuntimeOptions {
63
74
  host?: ClaudeReviewHost;
64
75
  interactive?: boolean;
65
76
  requestConfirmation?: NativeConfirmationPort;
77
+ batchKernel?: Partial<import("../unattended/batch_runner").BatchRunnerKernelPort>;
78
+ batchGit?: import("../unattended/batch_git").BatchRunnerGitPort;
79
+ readInitiative?: import("../unattended/types").InitiativeObservationReader;
66
80
  }
67
81
 
68
82
  export function createMcpRuntime(options: McpRuntimeOptions = {}) {
@@ -74,6 +88,9 @@ export function createMcpRuntime(options: McpRuntimeOptions = {}) {
74
88
  ports: options.ports,
75
89
  interactive: options.interactive,
76
90
  requestConfirmation: options.requestConfirmation,
91
+ batchKernel: options.batchKernel,
92
+ batchGit: options.batchGit,
93
+ readInitiative: options.readInitiative,
77
94
  });
78
95
  // Trusted Host evidence negotiated on this JSON-RPC connection. Absent
79
96
  // handshake evidence means unversioned and non-interactive: fail closed.
@@ -95,6 +112,26 @@ export function createMcpRuntime(options: McpRuntimeOptions = {}) {
95
112
  },
96
113
  sessionInteractive: () => negotiatedInteractive,
97
114
  async callTool(name: string, args: Record<string, unknown>, meta: Partial<ToolMeta> = {}) {
115
+ if (name === "start_unattended_batch") {
116
+ const initiativeSlug = String(args.initiative_slug ?? "");
117
+ if (!initiativeSlug) throw new Error("initiative_slug is required");
118
+ if ("native_decision" in args) throw new Error("native_decision cannot be supplied in tool arguments");
119
+ if (!negotiatedVersion) throw new NativeAuthorityError("unsupported_host", "Claude Code version is unavailable");
120
+ if (!negotiatedInteractive) {
121
+ throw new NativeAuthorityError("unsupported_host", "interactive MCP elicitation is unavailable");
122
+ }
123
+ const probe = probeHost(options.env ?? process.env, process.platform, negotiatedVersion);
124
+ if (!probe.ok) throw new NativeAuthorityError("unsupported_host", probe.reason);
125
+ const toolMeta: ToolMeta = {
126
+ sessionId: meta.sessionId ?? connectionId,
127
+ toolCallId: meta.toolCallId ?? `call-${name}`,
128
+ taskId: initiativeSlug,
129
+ initiativeSlug,
130
+ interactive: meta.interactive ?? options.interactive ?? negotiatedInteractive,
131
+ signal: meta.signal,
132
+ };
133
+ return runtime.startUnattendedBatch(initiativeSlug, toolMeta);
134
+ }
98
135
  const taskId = String(args.task_id ?? "");
99
136
  if (!taskId) throw new Error("task_id is required");
100
137
  if ("native_decision" in args) throw new Error("native_decision cannot be supplied in tool arguments");
@@ -132,6 +169,13 @@ export function createMcpRuntime(options: McpRuntimeOptions = {}) {
132
169
  if (typeof args.finding_id !== "string" || !args.finding_id) throw new Error("finding_id is required");
133
170
  return runtime.resolveFinding(taskId, args.finding_id);
134
171
  }
172
+ if (name === "refute_finding") {
173
+ // Structural only, exactly like resolve_finding: the reducer owns
174
+ // which findings may be refuted and with which evidence.
175
+ if (typeof args.finding_id !== "string" || !args.finding_id) throw new Error("finding_id is required");
176
+ if (typeof args.attestation_id !== "string" || !args.attestation_id) throw new Error("attestation_id is required");
177
+ return runtime.refuteFinding(taskId, args.finding_id, args.attestation_id);
178
+ }
135
179
  if (name === "request_authorization" || name === "approve_breaking_intent_revision" || name === "stop" || name === "repair_authority_state") {
136
180
  return runtime.authorize(taskId, name, toolMeta, args);
137
181
  }
@@ -309,6 +353,24 @@ async function writeReply(output: Writable, reply: JsonRpc): Promise<void> {
309
353
  }
310
354
 
311
355
  export function elicitationParams(input: NativeConfirmationInput) {
356
+ if (input.operation === "start_unattended_batch") {
357
+ const b = input.batchDetails;
358
+ const details = [
359
+ `Operation: start_unattended_batch`,
360
+ `Initiative: ${input.initiativeSlug ?? b?.initiative_slug}`,
361
+ b?.batch_branch ? `Batch branch: ${b.batch_branch}` : null,
362
+ input.planDigest ? `Plan digest: ${input.planDigest}` : null,
363
+ b?.children ? `Ordered children (${b.children.length}):\n${b.children.map((c) => ` - ${c.task_id} (${c.slice_id}) [risk: ${c.risk ?? "unknown"}]`).join("\n")}` : null,
364
+ b?.excluded && b.excluded.length > 0 ? `Excluded children (${b.excluded.length}):\n${b.excluded.map((e) => ` - ${e.task_id} (${e.slice_id}): ${e.reason}`).join("\n")}` : null,
365
+ b?.budget ? `Budget: max_children=${b.budget.max_children}, deadline_at=${b.budget.deadline_at}, qa_failure_limit=${b.budget.qa_failure_limit}` : null,
366
+ b?.expires_at ? `Expires at: ${b.expires_at}` : null,
367
+ ].filter(Boolean);
368
+ return {
369
+ mode: "form",
370
+ message: `Authorize this unattended batch run for ${input.initiativeSlug}?\n\n${details.join("\n")}`,
371
+ requestedSchema: { type: "object", properties: {} },
372
+ };
373
+ }
312
374
  const details = [
313
375
  `Operation: ${input.operation}`,
314
376
  `Task: ${input.taskId}`,