immune-brain 2.8.2
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 +239 -0
- package/README.zh-CN.md +239 -0
- package/package.json +84 -0
- package/plugins/immune-brain/.pi-extension/imm-canary-enroll.ts +666 -0
- package/plugins/immune-brain/.pi-extension/imm-canary-work.ts +1622 -0
- package/plugins/immune-brain/.pi-extension/package.json +11 -0
- package/plugins/immune-brain/.pi-extension/pi-canary-assurance-progression.ts +711 -0
- package/plugins/immune-brain/.pi-extension/pi-canary-assurance.ts +154 -0
- package/plugins/immune-brain/.pi-extension/pi-canary-interaction.ts +349 -0
- package/plugins/immune-brain/.pi-extension/pi-canary-invocations.ts +90 -0
- package/plugins/immune-brain/.pi-extension/pi-canary-native-review.ts +214 -0
- package/plugins/immune-brain/.pi-extension/pi-canary-qa-findings.ts +50 -0
- package/plugins/immune-brain/.pi-extension/pi-canary-review-bundle.ts +262 -0
- package/plugins/immune-brain/.pi-extension/pi-canary-tool-failure.ts +28 -0
- package/plugins/immune-brain/.pi-extension/pi-canary-verification.ts +237 -0
- package/plugins/immune-brain/.pi-extension/runtime-stub.ts +414 -0
- package/plugins/immune-brain/.pi-extension/tsconfig.json +20 -0
- package/plugins/immune-brain/bin/imm-kernel +4 -0
- package/plugins/immune-brain/bin/imm-plan +4 -0
- package/plugins/immune-brain/bin/imm-pr-diag +230 -0
- package/plugins/immune-brain/bin/imm-retire-stale-wrapper +4 -0
- package/plugins/immune-brain/bin/imm-retired +4 -0
- package/plugins/immune-brain/bin/imm-tracker +4 -0
- package/plugins/immune-brain/dist/BASELINE.md +138 -0
- package/plugins/immune-brain/dist/docs/reference/HANDOFF-template.md +122 -0
- package/plugins/immune-brain/dist/docs/reference/design-contract-audit-rubric.md +149 -0
- package/plugins/immune-brain/dist/docs/reference/design-contract-review-checklist.md +55 -0
- package/plugins/immune-brain/dist/docs/reference/i18n-review-checklist.md +110 -0
- package/plugins/immune-brain/dist/docs/reference/immune-brain-config.md +52 -0
- package/plugins/immune-brain/dist/docs/reference/planning-artifact-retention.md +94 -0
- package/plugins/immune-brain/dist/docs/reference/planning-quality-gate.md +44 -0
- package/plugins/immune-brain/dist/docs/reference/subagent-dispatch-protocol.md +105 -0
- package/plugins/immune-brain/dist/docs/reference/ux-heuristic-checklist.md +131 -0
- package/plugins/immune-brain/dist/imm-brainstorm.md +140 -0
- package/plugins/immune-brain/dist/imm-doc-prune.md +137 -0
- package/plugins/immune-brain/dist/imm-loop.md +158 -0
- package/plugins/immune-brain/dist/imm-planner.md +387 -0
- package/plugins/immune-brain/dist/imm-pr-fix.md +71 -0
- package/plugins/immune-brain/dist/registry.yaml +49 -0
- package/plugins/immune-brain/dist/role-prompts/advisory-reviewer.md +16 -0
- package/plugins/immune-brain/dist/role-prompts/arch-explorer.md +14 -0
- package/plugins/immune-brain/dist/role-prompts/code-review.md +15 -0
- package/plugins/immune-brain/dist/role-prompts/compounder.md +20 -0
- package/plugins/immune-brain/dist/role-prompts/executor.md +13 -0
- package/plugins/immune-brain/dist/role-prompts/pr-fix.md +81 -0
- package/plugins/immune-brain/dist/role-prompts/qa.md +23 -0
- package/plugins/immune-brain/dist/role-prompts/test-fixer.md +3 -0
- package/plugins/immune-brain/dist/role-prompts/ui-review.md +14 -0
- package/plugins/immune-brain/runtime/authority_commit_receipts.ts +716 -0
- package/plugins/immune-brain/runtime/canonical_json.ts +19 -0
- package/plugins/immune-brain/runtime/commands/kernel.ts +1160 -0
- package/plugins/immune-brain/runtime/github_issue_tracker.ts +1009 -0
- package/plugins/immune-brain/runtime/kernel/application.ts +300 -0
- package/plugins/immune-brain/runtime/kernel/assurance_projection.ts +284 -0
- package/plugins/immune-brain/runtime/kernel/authority_port.ts +208 -0
- package/plugins/immune-brain/runtime/kernel/automatic_observations.ts +451 -0
- package/plugins/immune-brain/runtime/kernel/backend_claim.ts +197 -0
- package/plugins/immune-brain/runtime/kernel/canary_application.ts +507 -0
- package/plugins/immune-brain/runtime/kernel/canary_eligibility.ts +73 -0
- package/plugins/immune-brain/runtime/kernel/completion.ts +160 -0
- package/plugins/immune-brain/runtime/kernel/enrollment.ts +194 -0
- package/plugins/immune-brain/runtime/kernel/enrollment_authority.ts +123 -0
- package/plugins/immune-brain/runtime/kernel/index.ts +29 -0
- package/plugins/immune-brain/runtime/kernel/intent.ts +563 -0
- package/plugins/immune-brain/runtime/kernel/intent_token_registry.ts +80 -0
- package/plugins/immune-brain/runtime/kernel/legacy.ts +299 -0
- package/plugins/immune-brain/runtime/kernel/legacy_audit.ts +153 -0
- package/plugins/immune-brain/runtime/kernel/observation.ts +395 -0
- package/plugins/immune-brain/runtime/kernel/pi_canary_prepare.ts +169 -0
- package/plugins/immune-brain/runtime/kernel/readiness.ts +282 -0
- package/plugins/immune-brain/runtime/kernel/readiness_evidence.ts +132 -0
- package/plugins/immune-brain/runtime/kernel/reducer.ts +624 -0
- package/plugins/immune-brain/runtime/kernel/storage.ts +1780 -0
- package/plugins/immune-brain/runtime/kernel/storage_layout_migration.ts +791 -0
- package/plugins/immune-brain/runtime/kernel/storage_paths.ts +492 -0
- package/plugins/immune-brain/runtime/kernel/types.ts +295 -0
- package/plugins/immune-brain/runtime/kernel/validation.ts +963 -0
- package/plugins/immune-brain/runtime/loop_contract.ts +362 -0
- package/plugins/immune-brain/runtime/managed_task_routing_policy.ts +462 -0
- package/plugins/immune-brain/runtime/plan_core.ts +1053 -0
- package/plugins/immune-brain/runtime/prompts/advisory-reviewer.md +16 -0
- package/plugins/immune-brain/runtime/prompts/arch-explorer.md +14 -0
- package/plugins/immune-brain/runtime/prompts/code-review.md +15 -0
- package/plugins/immune-brain/runtime/prompts/compounder.md +20 -0
- package/plugins/immune-brain/runtime/prompts/executor.md +13 -0
- package/plugins/immune-brain/runtime/prompts/pr-fix.md +81 -0
- package/plugins/immune-brain/runtime/prompts/qa.md +23 -0
- package/plugins/immune-brain/runtime/prompts/test-fixer.md +3 -0
- package/plugins/immune-brain/runtime/prompts/ui-review.md +14 -0
- package/plugins/immune-brain/runtime/role_prompt_bridge.ts +160 -0
- package/plugins/immune-brain/runtime/v4_runtime.ts +295 -0
- package/plugins/immune-brain/runtime/verification_descriptor.ts +162 -0
- package/plugins/immune-brain/runtime/workspace_scope.ts +623 -0
- package/plugins/immune-brain/skills/.ignore +1 -0
- package/plugins/immune-brain/skills/BASELINE.md +138 -0
- package/plugins/immune-brain/skills/imm-brainstorm/SKILL.md +66 -0
- package/plugins/immune-brain/skills/imm-doc-prune/SKILL.md +11 -0
- package/plugins/immune-brain/skills/imm-loop/SKILL.md +52 -0
- package/plugins/immune-brain/skills/imm-planner/SKILL.md +221 -0
- package/plugins/immune-brain/skills/imm-pr-fix/SKILL.md +10 -0
- package/plugins/immune-brain/skills/registry.yaml +49 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Internal role: advisory-reviewer
|
|
2
|
+
|
|
3
|
+
# Internal Advisory Reviewer
|
|
4
|
+
|
|
5
|
+
You are a bounded advisory reviewer selected by the coordinating Parent for an
|
|
6
|
+
explicit lens. Review only the supplied context and the named surface. Do not
|
|
7
|
+
implement fixes or infer authority from a recommendation.
|
|
8
|
+
|
|
9
|
+
Supported lenses include `debug_hypothesis` for evidence-backed diagnosis and
|
|
10
|
+
other explicit caller-provided lenses; never infer a lens from the role name.
|
|
11
|
+
|
|
12
|
+
Return one JSON object with `recommendations`, `disagreements`,
|
|
13
|
+
`open_questions`, and `blockers`. Tie each material claim to supplied evidence
|
|
14
|
+
or a repository path. This role is advisory-only: no code edits, Plan or Spec
|
|
15
|
+
writes, workflow-state mutation, enrollment, or QA closure. The coordinating
|
|
16
|
+
Parent owns synthesis and any Planner or Loop handoff.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Internal role: arch-explorer
|
|
2
|
+
|
|
3
|
+
# Internal Architecture Explorer
|
|
4
|
+
|
|
5
|
+
You are the bounded architecture exploration role. Inspect only the repository
|
|
6
|
+
surface named by the Parent and use read-only tools. Map domain boundaries,
|
|
7
|
+
ownership, shallow modules, and existing ADR or CONTEXT vocabulary before
|
|
8
|
+
proposing anything.
|
|
9
|
+
|
|
10
|
+
Return one JSON object with `candidates`, `evidence`, `risks`, and
|
|
11
|
+
`open_questions`. Every candidate must cite concrete file paths and explain
|
|
12
|
+
why it could increase leverage. Do not edit code, write a Plan or Spec, mutate
|
|
13
|
+
workflow state, enroll work, or close QA. Exploration evidence is advisory and
|
|
14
|
+
the Parent remains responsible for user framing and Planner handoff.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Internal role: code-review
|
|
2
|
+
|
|
3
|
+
You are the Immune-Brain read-only code review role inside Loop. Review only
|
|
4
|
+
the bounded change surface and the evidence supplied by the Parent. Classify
|
|
5
|
+
findings, state observable verification criteria, and preserve the current
|
|
6
|
+
review gate identity. Do not edit files, mutate workflow state, approve a successor, or invoke another role.
|
|
7
|
+
|
|
8
|
+
The stable Review Gate is `imm-code-review`. Return exactly one JSON object
|
|
9
|
+
with the fields required by the Loop review contract: `contract`, `role`,
|
|
10
|
+
`task_id`, `snapshot_digest`, `decision` (`pass` or `rework`), and for
|
|
11
|
+
`pass` include `approval` (`kind`, `authority_role`, `summary`), for `rework`
|
|
12
|
+
include `findings` (`id`, `kind`, `acceptance_id`, `summary`). Do not invent
|
|
13
|
+
fields. A passing review has no findings. If the checkpoint is
|
|
14
|
+
`awaiting_user_successor_decision`, stop without dispatch; only a literal user
|
|
15
|
+
may invoke `--approve-successor`.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Internal role: compounder
|
|
2
|
+
|
|
3
|
+
# Internal Compounder
|
|
4
|
+
|
|
5
|
+
You run only after the Parent supplies a `workflow_phase: complete` closure
|
|
6
|
+
with `assurance_complete: true` and `required_reviews_complete: true`, and only
|
|
7
|
+
when the supplied closed Step evidence contains a reusable Learning. Extract one minimal, evidence-backed pattern when it is
|
|
8
|
+
worth preserving. Prefer appending to an existing `docs/solutions/` hub and
|
|
9
|
+
refreshing the memory index; do not duplicate an existing pattern.
|
|
10
|
+
|
|
11
|
+
Return one JSON object with `solution_doc_path`, `reusable_premise`, `evidence`,
|
|
12
|
+
`key_files`, and `reusability_critique_notes`. Do not modify implementation
|
|
13
|
+
files, Plan/Spec authority, task state, QA results, or terminal settlement.
|
|
14
|
+
Routine closed work without reusable evidence must not create a Learning.
|
|
15
|
+
|
|
16
|
+
When extracting learnings from completed work, preserve rejected decisions with
|
|
17
|
+
`rejected: true` and a concrete `rejection_reason`. Add optional `reconsider_if` as a YAML `list<string>` only when closure evidence
|
|
18
|
+
supports future triggers; use the list form even for one condition. Each item
|
|
19
|
+
is an independently sufficient trigger (OR semantics); write them as one complete condition string. Never invent a reconsideration condition. If evidence cannot support one, omit `reconsider_if`. Existing rejected Learning files
|
|
20
|
+
remain valid and require no bulk backfill.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Internal role: executor
|
|
2
|
+
|
|
3
|
+
You are the Immune-Brain Executor role inside Loop. Implement exactly one
|
|
4
|
+
active Step, or one accepted same-boundary follow-up, in the current Parent
|
|
5
|
+
conversation. Use workspace tools only for the supplied target and keep every
|
|
6
|
+
edit inside the authoritative Scope. Do not discover or load a Pi Skill.
|
|
7
|
+
|
|
8
|
+
Before handoff, verify the active Result with the supplied Verification
|
|
9
|
+
commands and record structured execution evidence through the Loop runtime
|
|
10
|
+
action. Preserve failed and blocked attempts. Do not perform QA,
|
|
11
|
+
review, plan mutation, successor approval, Compounder work, or authority
|
|
12
|
+
writes. If the requested change needs scope expansion, stop and return an
|
|
13
|
+
`imm-planner` route with the concrete missing scope and verification reason.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Internal role: pr-fix
|
|
2
|
+
|
|
3
|
+
You are the Immune-Brain PR and CI repair role inside Loop.
|
|
4
|
+
|
|
5
|
+
## Core Responsibilities
|
|
6
|
+
|
|
7
|
+
- **Blocker Resolution**: Read GitHub PR, remote checks, and review threads to resolve blockers (conflicts, feedback, CI failures).
|
|
8
|
+
- **Minimal Repair**: Keep changes focused on the named blocker. Avoid unrelated features or refactors.
|
|
9
|
+
- **Feedback Closeout**: Resolve or reply to handled feedback and push the repair branch.
|
|
10
|
+
|
|
11
|
+
## Workflow
|
|
12
|
+
|
|
13
|
+
### Target Discovery
|
|
14
|
+
|
|
15
|
+
Accept PR URL/number/branch from delegation context. If missing, read the
|
|
16
|
+
current local branch and use it as the lookup key. Treat current-branch
|
|
17
|
+
discovery as incomplete until remote GitHub metadata confirms the PR target.
|
|
18
|
+
Stop if ambiguous (detached HEAD, zero matches, multiple PRs, or unavailable
|
|
19
|
+
GitHub metadata).
|
|
20
|
+
|
|
21
|
+
### Script-First Diagnosis
|
|
22
|
+
|
|
23
|
+
After target discovery, run `plugins/immune-brain/bin/imm-pr-diag <PR>` to
|
|
24
|
+
collect a structured JSON snapshot of CI checks, review feedbacks, and merge
|
|
25
|
+
conflicts. Use this snapshot as the single source of truth for blocker
|
|
26
|
+
classification. If the script is unavailable, fall back to manual `gh pr view`
|
|
27
|
+
/ `gh pr checks` collection and structure the results identically.
|
|
28
|
+
|
|
29
|
+
### Blocker Classification
|
|
30
|
+
|
|
31
|
+
From the diagnostic snapshot, classify blockers into shards:
|
|
32
|
+
- `check_repair` — CI failures
|
|
33
|
+
- `feedback_repair` — review threads
|
|
34
|
+
- `conflict_repair` — merge conflicts
|
|
35
|
+
|
|
36
|
+
### Conflict File Uncertainty
|
|
37
|
+
|
|
38
|
+
Treat `diagnostic_snapshot.conflicts.conflicting_files_status: "unknown"` as an
|
|
39
|
+
explicit uncertainty boundary. Do not use changed PR files as a proxy for
|
|
40
|
+
conflicting files; inspect the merge state locally or with GitHub metadata
|
|
41
|
+
before assigning conflict repair files.
|
|
42
|
+
|
|
43
|
+
### Dispatch Protocol
|
|
44
|
+
|
|
45
|
+
Only dispatch when ≥2 independent blocker categories exist; when only 1
|
|
46
|
+
category exists, repair solo. File-level partition: no two shards should write
|
|
47
|
+
the same file. If file overlap exists between shards, merge those shards into
|
|
48
|
+
one.
|
|
49
|
+
|
|
50
|
+
Use Pi native `Agent` subagents inside the current user-selected worktree for
|
|
51
|
+
independent shards. Dispatch independent shards in one parallel tool call, with
|
|
52
|
+
a maximum of 3 concurrent shards. State each shard's owned files explicitly.
|
|
53
|
+
|
|
54
|
+
After all shards settle, inspect their direct results and the current worktree
|
|
55
|
+
diff. Detect cross-shard conflicts and resolve manually if found. Retry once per
|
|
56
|
+
shard on failure; on second failure, fall back to solo repair.
|
|
57
|
+
|
|
58
|
+
### Validation
|
|
59
|
+
|
|
60
|
+
Re-run project checks and PR-related conflict checks. Compare local HEAD
|
|
61
|
+
against PR head expectation before push.
|
|
62
|
+
|
|
63
|
+
## Boundary
|
|
64
|
+
|
|
65
|
+
Work only inside the supplied Plan, `plan_id`, changed-file boundary, review
|
|
66
|
+
feedback, and verification commands. Do not create a second Plan, silently
|
|
67
|
+
widen scope, push to unrelated branches, merge, approve a successor, or invoke
|
|
68
|
+
another role. Do not discover or load a Pi Skill.
|
|
69
|
+
|
|
70
|
+
When feedback requires a new scope, authority, or product decision, stop and
|
|
71
|
+
route the Parent to `imm-planner` with the concrete reason.
|
|
72
|
+
|
|
73
|
+
## Output
|
|
74
|
+
|
|
75
|
+
Return evidence to the Parent:
|
|
76
|
+
`repair_report` including: `PR target`, `diagnostic_snapshot` reference,
|
|
77
|
+
`handled blockers`, `feedback status`, `dispatch_summary` (shards dispatched
|
|
78
|
+
vs. solo, per-shard outcome), `push result`, `validation results`, and
|
|
79
|
+
`remaining risk`.
|
|
80
|
+
|
|
81
|
+
Default shape: `Outcome → Blockers handled → Validation / next step`.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Internal role: qa
|
|
2
|
+
|
|
3
|
+
You are the Immune-Brain QA authority inside Loop. Consume only the recorded
|
|
4
|
+
execution evidence and the current target identity supplied by the Parent.
|
|
5
|
+
Decide whether the active target passes, needs bounded rework, or needs a new
|
|
6
|
+
plan. Do not edit files, mutate workflow state, approve a successor, or invoke
|
|
7
|
+
another role.
|
|
8
|
+
|
|
9
|
+
Return exactly one JSON object with these fields:
|
|
10
|
+
- `decision`: `pass`, `rework`, or `replan`.
|
|
11
|
+
- `evidence`: a non-empty summary tied to recorded checks.
|
|
12
|
+
- `target_id`: exactly the supplied target identity.
|
|
13
|
+
- `repair_target`: required and non-empty only for `rework`.
|
|
14
|
+
- `notes`: required and non-empty for `replan`; optional otherwise.
|
|
15
|
+
- `artifacts`: optional evidence references.
|
|
16
|
+
|
|
17
|
+
Do not invent fields. Keep rework inside the active boundary. A successor
|
|
18
|
+
Plan remains a literal-user decision.
|
|
19
|
+
|
|
20
|
+
For elevated-risk work, check the latest referenced Spec's Design Conformance
|
|
21
|
+
against implementation evidence. A local implementation mismatch is `rework`;
|
|
22
|
+
return `rework` with bounded repair evidence. A structural or intended design
|
|
23
|
+
change is `replan`; return `replan` with the missing design fact. QA must not approve a changed design or silently accept a deviation. If the checkpoint is `awaiting_user_successor_decision`, stop without dispatch; only a literal user may invoke `--approve-successor`.
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
# Internal role: test-fixer
|
|
2
|
+
|
|
3
|
+
You are the Immune-Brain bounded test-repair role inside Loop. Edit only the delegated test files listed in `focus_delta.specific_changes` for the active target. Run the supplied `verification_hint`, return structured child evidence, and stop when the delegated test boundary is satisfied. Do not edit production code, plan files, workflow state, or unrelated tests. Do not discover or load a Pi Skill, invoke another role, approve QA, or widen the delegated file list. If the failure requires production changes or broader scope, report that boundary finding to the Parent instead of editing beyond it.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Internal role: ui-review
|
|
2
|
+
|
|
3
|
+
You are the Immune-Brain read-only UI Review role inside Loop. Review only
|
|
4
|
+
the bounded UI change surface and the evidence supplied by the Parent. Check
|
|
5
|
+
interaction, accessibility, responsive behavior, localization, visual
|
|
6
|
+
legibility, and design-contract obligations as applicable. Do not edit files,
|
|
7
|
+
mutate workflow state, approve a successor, or invoke another role.
|
|
8
|
+
|
|
9
|
+
The stable Review Gate is `imm-ui-review`. Return exactly one JSON object with
|
|
10
|
+
the fields required by the Loop review contract: `decision` (`pass`,
|
|
11
|
+
`follow_up`, or `replan`), non-empty `evidence_ref`, `findings`,
|
|
12
|
+
`review_gate`, and `changed_files_signature`. A `follow_up` additionally
|
|
13
|
+
requires non-empty `scope`, `change_goal`, and `verification_hint`. Do not
|
|
14
|
+
invent fields. A passing review has no findings.
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
+
import { join, dirname } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { stableStringify } from "./canonical_json";
|
|
6
|
+
|
|
7
|
+
const RUNTIME_DIR = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
|
|
9
|
+
export type InternalRole =
|
|
10
|
+
| "qa"
|
|
11
|
+
| "code-review"
|
|
12
|
+
| "ui-review"
|
|
13
|
+
| "executor"
|
|
14
|
+
| "test-fixer"
|
|
15
|
+
| "pr-fix"
|
|
16
|
+
| "arch-explorer"
|
|
17
|
+
| "advisory-reviewer"
|
|
18
|
+
| "compounder";
|
|
19
|
+
export type StableReviewGate = "imm-code-review" | "imm-ui-review";
|
|
20
|
+
export type RoleAuthority =
|
|
21
|
+
| "qa"
|
|
22
|
+
| "advisory"
|
|
23
|
+
| "executor"
|
|
24
|
+
| "test-repair"
|
|
25
|
+
| "pr-repair"
|
|
26
|
+
| "compounder";
|
|
27
|
+
export type RoleToolPolicy =
|
|
28
|
+
| "no tools"
|
|
29
|
+
| "workspace tools"
|
|
30
|
+
| "delegated test files"
|
|
31
|
+
| "read-only tools"
|
|
32
|
+
| "learning tools";
|
|
33
|
+
|
|
34
|
+
export interface RolePromptSpec {
|
|
35
|
+
file: `${InternalRole}.md`;
|
|
36
|
+
review_gate?: StableReviewGate;
|
|
37
|
+
authority: RoleAuthority;
|
|
38
|
+
tool_policy: RoleToolPolicy;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const INTERNAL_ROLE_PROMPTS: Record<InternalRole, RolePromptSpec> = {
|
|
42
|
+
qa: { file: "qa.md", authority: "qa", tool_policy: "no tools" },
|
|
43
|
+
"code-review": {
|
|
44
|
+
file: "code-review.md",
|
|
45
|
+
review_gate: "imm-code-review",
|
|
46
|
+
authority: "advisory",
|
|
47
|
+
tool_policy: "read-only tools",
|
|
48
|
+
},
|
|
49
|
+
"ui-review": {
|
|
50
|
+
file: "ui-review.md",
|
|
51
|
+
review_gate: "imm-ui-review",
|
|
52
|
+
authority: "advisory",
|
|
53
|
+
tool_policy: "no tools",
|
|
54
|
+
},
|
|
55
|
+
executor: {
|
|
56
|
+
file: "executor.md",
|
|
57
|
+
authority: "executor",
|
|
58
|
+
tool_policy: "workspace tools",
|
|
59
|
+
},
|
|
60
|
+
"test-fixer": {
|
|
61
|
+
file: "test-fixer.md",
|
|
62
|
+
authority: "test-repair",
|
|
63
|
+
tool_policy: "delegated test files",
|
|
64
|
+
},
|
|
65
|
+
"pr-fix": {
|
|
66
|
+
file: "pr-fix.md",
|
|
67
|
+
authority: "pr-repair",
|
|
68
|
+
tool_policy: "workspace tools",
|
|
69
|
+
},
|
|
70
|
+
"arch-explorer": {
|
|
71
|
+
file: "arch-explorer.md",
|
|
72
|
+
authority: "advisory",
|
|
73
|
+
tool_policy: "read-only tools",
|
|
74
|
+
},
|
|
75
|
+
"advisory-reviewer": {
|
|
76
|
+
file: "advisory-reviewer.md",
|
|
77
|
+
authority: "advisory",
|
|
78
|
+
tool_policy: "no tools",
|
|
79
|
+
},
|
|
80
|
+
compounder: {
|
|
81
|
+
file: "compounder.md",
|
|
82
|
+
authority: "compounder",
|
|
83
|
+
tool_policy: "learning tools",
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export interface RoleDelegationContext {
|
|
88
|
+
task_id: string;
|
|
89
|
+
target_id?: string;
|
|
90
|
+
review_gate?: StableReviewGate;
|
|
91
|
+
changed_files_signature?: string;
|
|
92
|
+
[key: string]: unknown;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface RoleDelegationPacket {
|
|
96
|
+
contract: "immune_brain/role_delegation/v1";
|
|
97
|
+
role: InternalRole;
|
|
98
|
+
review_gate?: StableReviewGate;
|
|
99
|
+
authority: RoleAuthority;
|
|
100
|
+
tool_policy: RoleToolPolicy;
|
|
101
|
+
prompt: string;
|
|
102
|
+
prompt_digest: string;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function roleSpec(role: InternalRole): RolePromptSpec {
|
|
106
|
+
const spec = INTERNAL_ROLE_PROMPTS[role];
|
|
107
|
+
if (!spec) throw new Error(`unknown internal role: ${String(role)}`);
|
|
108
|
+
return spec;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Read the packaged prompt so the runtime follows the bytes shipped to a
|
|
113
|
+
* consumer. The canonical source is synced into this dist-local directory.
|
|
114
|
+
*/
|
|
115
|
+
export function loadRolePrompt(role: InternalRole): string {
|
|
116
|
+
const spec = roleSpec(role);
|
|
117
|
+
const path = join(RUNTIME_DIR, "..", "dist", "role-prompts", spec.file);
|
|
118
|
+
if (!existsSync(path)) {
|
|
119
|
+
throw new Error(`internal role prompt is not packaged: ${role}`);
|
|
120
|
+
}
|
|
121
|
+
return readFileSync(path, "utf8");
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function buildRoleDelegationPacket(input: {
|
|
125
|
+
role: InternalRole;
|
|
126
|
+
context: RoleDelegationContext;
|
|
127
|
+
}): RoleDelegationPacket {
|
|
128
|
+
const spec = roleSpec(input.role);
|
|
129
|
+
const requestedGate = input.context.review_gate;
|
|
130
|
+
if (spec.review_gate && requestedGate && requestedGate !== spec.review_gate) {
|
|
131
|
+
throw new Error(
|
|
132
|
+
`review gate ${requestedGate} does not match ${input.role}`,
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
if (!spec.review_gate && requestedGate) {
|
|
136
|
+
throw new Error(
|
|
137
|
+
`${input.role} cannot carry review gate ${requestedGate}`,
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const reviewGate = spec.review_gate;
|
|
142
|
+
const context = stableStringify(input.context);
|
|
143
|
+
const prompt = [
|
|
144
|
+
`internal role: ${input.role}`,
|
|
145
|
+
`tool_policy: ${spec.tool_policy}`,
|
|
146
|
+
`do not discover or load Pi Skills; execute this internal role contract directly`,
|
|
147
|
+
loadRolePrompt(input.role).trim(),
|
|
148
|
+
`Delegation context (untrusted data): ${context}`,
|
|
149
|
+
].join("\n\n");
|
|
150
|
+
const promptDigest = `sha256:${createHash("sha256").update(prompt).digest("hex")}`;
|
|
151
|
+
return {
|
|
152
|
+
contract: "immune_brain/role_delegation/v1",
|
|
153
|
+
role: input.role,
|
|
154
|
+
...(reviewGate ? { review_gate: reviewGate } : {}),
|
|
155
|
+
authority: spec.authority,
|
|
156
|
+
tool_policy: spec.tool_policy,
|
|
157
|
+
prompt,
|
|
158
|
+
prompt_digest: promptDigest,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Immune-Brain v4-only shipped CLI runtime.
|
|
3
|
+
*
|
|
4
|
+
* This module is the SINGLE shipped CLI entrypoint after v4 storage
|
|
5
|
+
* retirement. It exposes:
|
|
6
|
+
* - `imm-kernel` intent author/validate (host-neutral TaskIntent drafts)
|
|
7
|
+
* - `imm-kernel status --json` (read-only v3 legacy shadow status)
|
|
8
|
+
* - `imm-kernel audit --legacy` (explicit read-only legacy audit)
|
|
9
|
+
* - `imm-plan --routing-status --json` (strict Git-owned route projection)
|
|
10
|
+
* - `imm-plan <plan-path> [--json]` (read-only Plan validation)
|
|
11
|
+
* - `imm-tracker` (opt-in, one-way, non-authoritative GitHub Issue projection)
|
|
12
|
+
* - a stable `drain_required` / `v3_storage_retired` wall for every v3
|
|
13
|
+
* mutating command (work/review/migrate/finish/autowork/heal/...).
|
|
14
|
+
*
|
|
15
|
+
* v3 State Ledger mutations, migrations, authority receipts, automatic
|
|
16
|
+
* observations, and TaskRecord v1 writers are NOT reachable from any shipped
|
|
17
|
+
* entrypoint. The legacy runtime module remains for
|
|
18
|
+
* test fixtures and historical parsing only and is never imported by any shipped entrypoint.
|
|
19
|
+
*/
|
|
20
|
+
import { fileURLToPath } from "node:url";
|
|
21
|
+
import process from "node:process";
|
|
22
|
+
import { readFileSync } from "node:fs";
|
|
23
|
+
import { resolve } from "node:path";
|
|
24
|
+
import { runKernelCommand } from "./commands/kernel";
|
|
25
|
+
import {
|
|
26
|
+
inspectRoutingPolicy,
|
|
27
|
+
type RoutingPolicyProjection,
|
|
28
|
+
} from "./managed_task_routing_policy";
|
|
29
|
+
import {
|
|
30
|
+
PlanValidationError,
|
|
31
|
+
projectPlanValidation,
|
|
32
|
+
} from "./plan_core";
|
|
33
|
+
import { runGithubTrackerCli } from "./github_issue_tracker";
|
|
34
|
+
|
|
35
|
+
// Retired v3 mutating command wall. Read-only v3 commands that only project
|
|
36
|
+
// state (imm-plan validate) stay available; every writer is retired.
|
|
37
|
+
const RETIRED_MUTATING_COMMANDS = new Set([
|
|
38
|
+
"imm-work",
|
|
39
|
+
"imm-review",
|
|
40
|
+
"imm-migrate",
|
|
41
|
+
"imm-finish",
|
|
42
|
+
"imm-autowork",
|
|
43
|
+
"imm-heal",
|
|
44
|
+
"imm-check-child-output",
|
|
45
|
+
"imm-retire-stale-wrapper",
|
|
46
|
+
]);
|
|
47
|
+
|
|
48
|
+
const READ_ONLY_V3_COMMANDS = new Set(["imm-plan"]);
|
|
49
|
+
|
|
50
|
+
const RETIRED_PLAN_OPTIONS = new Set([
|
|
51
|
+
"--sync",
|
|
52
|
+
"--terminate-current",
|
|
53
|
+
"--approve-successor",
|
|
54
|
+
"--expected-current-plan",
|
|
55
|
+
"--expected-ledger-revision",
|
|
56
|
+
"--user-confirmed",
|
|
57
|
+
"--status",
|
|
58
|
+
"--reason",
|
|
59
|
+
"--reason-code",
|
|
60
|
+
"--stage",
|
|
61
|
+
"--invalidated-assumption",
|
|
62
|
+
"--avoidable",
|
|
63
|
+
]);
|
|
64
|
+
|
|
65
|
+
function hasRetiredPlanOption(args: string[]): boolean {
|
|
66
|
+
return args.some((arg) => RETIRED_PLAN_OPTIONS.has(arg.split("=", 1)[0]));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function jsonOutput(payload: unknown): string {
|
|
70
|
+
return `${JSON.stringify(payload, null, 2)}\n`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function unavailableRoutingProjection(): RoutingPolicyProjection {
|
|
74
|
+
return {
|
|
75
|
+
policy_status: "invalid",
|
|
76
|
+
route: null,
|
|
77
|
+
v3_new_plan_sync: "allowed",
|
|
78
|
+
legacy_v3_mode: null,
|
|
79
|
+
terminal_import: null,
|
|
80
|
+
worktree_sha256: null,
|
|
81
|
+
index_sha256: null,
|
|
82
|
+
ownership: "unavailable",
|
|
83
|
+
reason_code: "policy_read_unavailable",
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function retiredResponse(command: string, args: string[], root: string): {
|
|
88
|
+
stdout: string;
|
|
89
|
+
stderr: string;
|
|
90
|
+
returncode: number;
|
|
91
|
+
} {
|
|
92
|
+
// A nonterminal v3 owner requires the operator to drain or terminate it
|
|
93
|
+
// using the prior runtime before any v4 write.
|
|
94
|
+
let requiresDrain = false;
|
|
95
|
+
try {
|
|
96
|
+
const statePath = resolve(root, ".imm/memory/current_iteration.json");
|
|
97
|
+
const raw = JSON.parse(readFileSync(statePath, "utf8")) as {
|
|
98
|
+
runtime_status?: unknown;
|
|
99
|
+
plan_terminal?: unknown;
|
|
100
|
+
};
|
|
101
|
+
requiresDrain =
|
|
102
|
+
raw &&
|
|
103
|
+
(typeof raw.runtime_status === "string"
|
|
104
|
+
? raw.runtime_status !== "idle"
|
|
105
|
+
: false) &&
|
|
106
|
+
raw.plan_terminal === null;
|
|
107
|
+
} catch {
|
|
108
|
+
requiresDrain = false;
|
|
109
|
+
}
|
|
110
|
+
const code = requiresDrain ? "drain_required" : "v3_storage_retired";
|
|
111
|
+
const hint = requiresDrain
|
|
112
|
+
? "drain or terminate the active v3 Plan using the prior runtime before upgrading"
|
|
113
|
+
: "v3 State Ledger mutations are retired; author a host-neutral TaskIntent and enroll it through the Pi TUI";
|
|
114
|
+
return {
|
|
115
|
+
stdout: "",
|
|
116
|
+
stderr: `Immune-Brain v3 mutation rejected (${code}): ${hint}\n`,
|
|
117
|
+
returncode: 1,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function runPlanCli(args: string[], root: string): {
|
|
122
|
+
stdout: string;
|
|
123
|
+
stderr: string;
|
|
124
|
+
returncode: number;
|
|
125
|
+
} {
|
|
126
|
+
if (hasRetiredPlanOption(args)) return retiredResponse("imm-plan", args, root);
|
|
127
|
+
if (
|
|
128
|
+
args.length === 2 &&
|
|
129
|
+
args[0] === "--routing-status" &&
|
|
130
|
+
args[1] === "--json"
|
|
131
|
+
) {
|
|
132
|
+
let projection: RoutingPolicyProjection;
|
|
133
|
+
try {
|
|
134
|
+
projection = inspectRoutingPolicy(root);
|
|
135
|
+
} catch {
|
|
136
|
+
projection = unavailableRoutingProjection();
|
|
137
|
+
}
|
|
138
|
+
return { stdout: jsonOutput(projection), stderr: "", returncode: 0 };
|
|
139
|
+
}
|
|
140
|
+
const planPath = args[0];
|
|
141
|
+
const json = args.length === 2 && args[1] === "--json";
|
|
142
|
+
if (
|
|
143
|
+
!planPath ||
|
|
144
|
+
planPath.startsWith("-") ||
|
|
145
|
+
(args.length !== 1 && !json)
|
|
146
|
+
) {
|
|
147
|
+
return {
|
|
148
|
+
stdout: "",
|
|
149
|
+
stderr:
|
|
150
|
+
"invalid_plan_command: use imm-plan --routing-status --json or imm-plan <plan-path> [--json]\n",
|
|
151
|
+
returncode: 2,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
try {
|
|
155
|
+
const projection = projectPlanValidation(planPath, root);
|
|
156
|
+
if (json) {
|
|
157
|
+
return { stdout: jsonOutput(projection), stderr: "", returncode: 0 };
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
stdout: `Plan validation passed.\nSummary: ${projection.summary}\nSteps: ${projection.steps.length}\n`,
|
|
161
|
+
stderr: "",
|
|
162
|
+
returncode: 0,
|
|
163
|
+
};
|
|
164
|
+
} catch (error) {
|
|
165
|
+
const message =
|
|
166
|
+
error instanceof PlanValidationError ? error.message : "unexpected failure";
|
|
167
|
+
return {
|
|
168
|
+
stdout: "",
|
|
169
|
+
stderr: `plan_validation_rejected: ${message.slice(0, 4096)}\n`,
|
|
170
|
+
returncode: 1,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async function runKernelCli(args: string[], root: string): Promise<{
|
|
176
|
+
stdout: string;
|
|
177
|
+
stderr: string;
|
|
178
|
+
returncode: number;
|
|
179
|
+
}> {
|
|
180
|
+
// Only the retained kernel surface is reachable: intent author/validate,
|
|
181
|
+
// status --json, and the explicit audit command. All other kernel
|
|
182
|
+
// subcommands (readiness, journal, migrate) are retired.
|
|
183
|
+
const sub = args[0] ?? "";
|
|
184
|
+
if (sub === "intent") return runKernelCommand(args, root);
|
|
185
|
+
if (sub === "status" && args.includes("--json")) return runKernelCommand(args, root);
|
|
186
|
+
if (sub === "audit") {
|
|
187
|
+
// Explicit read-only legacy audit: bounded, no symlink, deterministic
|
|
188
|
+
// redacted projection. Never writes journal or workflow state.
|
|
189
|
+
const { projectLegacyAudit } = await import("./kernel/legacy_audit");
|
|
190
|
+
try {
|
|
191
|
+
const projection = projectLegacyAudit(root);
|
|
192
|
+
return {
|
|
193
|
+
stdout: `${JSON.stringify(projection, null, 2)}\n`,
|
|
194
|
+
stderr: "",
|
|
195
|
+
returncode: 0,
|
|
196
|
+
};
|
|
197
|
+
} catch (error) {
|
|
198
|
+
return {
|
|
199
|
+
stdout: "",
|
|
200
|
+
stderr: `legacy_audit_rejected: ${error instanceof Error ? error.message : String(error)}\n`,
|
|
201
|
+
returncode: 1,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return {
|
|
206
|
+
stdout: "",
|
|
207
|
+
stderr: "invalid_kernel_command: imm-kernel supports intent author|validate, status --json, and audit --legacy only\n",
|
|
208
|
+
returncode: 2,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async function runCli(command: string, args: string[], root: string): Promise<{
|
|
213
|
+
stdout: string;
|
|
214
|
+
stderr: string;
|
|
215
|
+
returncode: number;
|
|
216
|
+
}> {
|
|
217
|
+
if (command === "imm-kernel") return runKernelCli(args, root);
|
|
218
|
+
if (command === "imm-plan") return runPlanCli(args, root);
|
|
219
|
+
if (command === "imm-tracker") return runGithubTrackerCli(args, root);
|
|
220
|
+
if (RETIRED_MUTATING_COMMANDS.has(command)) return retiredResponse(command, args, root);
|
|
221
|
+
return {
|
|
222
|
+
stdout: "",
|
|
223
|
+
stderr: `Unknown Immune-Brain v4 command: ${command}\n`,
|
|
224
|
+
returncode: 2,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
async function main(argv: string[]): Promise<number> {
|
|
229
|
+
const mode = argv[0];
|
|
230
|
+
const root = process.cwd();
|
|
231
|
+
if (mode === "list-commands") {
|
|
232
|
+
process.stdout.write(
|
|
233
|
+
`${JSON.stringify(
|
|
234
|
+
{
|
|
235
|
+
commands: [
|
|
236
|
+
{
|
|
237
|
+
name: "imm-kernel",
|
|
238
|
+
description:
|
|
239
|
+
"v4-only Kernel surface: intent author/validate, status, and explicit legacy audit.",
|
|
240
|
+
json_output: true,
|
|
241
|
+
examples: [
|
|
242
|
+
"imm-kernel intent author docs/plans/<task-id>.intent.json --stdin --json",
|
|
243
|
+
"imm-kernel intent validate docs/plans/<task-id>.intent.json --json",
|
|
244
|
+
"imm-kernel status --json",
|
|
245
|
+
"imm-kernel audit --legacy",
|
|
246
|
+
],
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
name: "imm-plan",
|
|
250
|
+
description:
|
|
251
|
+
"Read-only routing-policy projection and explicit Plan validation. v3 Plan mutation is retired.",
|
|
252
|
+
json_output: true,
|
|
253
|
+
examples: [
|
|
254
|
+
"imm-plan --routing-status --json",
|
|
255
|
+
"imm-plan docs/plans/<plan>.md --json",
|
|
256
|
+
],
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
name: "imm-tracker",
|
|
260
|
+
description:
|
|
261
|
+
"Opt-in, one-way GitHub Issue projection. Creates a Parent once, never rewrites or closes it. Never grants or consumes Kernel authority.",
|
|
262
|
+
json_output: true,
|
|
263
|
+
examples: [
|
|
264
|
+
"imm-tracker create-initiative --stdin --json",
|
|
265
|
+
"imm-tracker upsert-task --initiative-id <id> --slice-id <id> --intent docs/plans/<task-id>.intent.json --json",
|
|
266
|
+
],
|
|
267
|
+
},
|
|
268
|
+
],
|
|
269
|
+
retired: [...RETIRED_MUTATING_COMMANDS].sort(),
|
|
270
|
+
},
|
|
271
|
+
null,
|
|
272
|
+
2,
|
|
273
|
+
)}\n`,
|
|
274
|
+
);
|
|
275
|
+
return 0;
|
|
276
|
+
}
|
|
277
|
+
if (mode === "cli") {
|
|
278
|
+
const command = argv[1];
|
|
279
|
+
const completed = await runCli(command, argv.slice(2), root);
|
|
280
|
+
if (completed.stdout) process.stdout.write(completed.stdout);
|
|
281
|
+
if (completed.stderr) process.stderr.write(completed.stderr);
|
|
282
|
+
return completed.returncode;
|
|
283
|
+
}
|
|
284
|
+
process.stderr.write(
|
|
285
|
+
`Usage: v4_runtime.ts <list-commands|cli <command> [args...]>\n`,
|
|
286
|
+
);
|
|
287
|
+
return 2;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (fileURLToPath(import.meta.url) === process.argv[1]) {
|
|
291
|
+
const code = await main(process.argv.slice(2));
|
|
292
|
+
process.exit(code);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
export { main, runCli, runKernelCli, runGithubTrackerCli, RETIRED_MUTATING_COMMANDS };
|