ultimate-pi 0.16.0 → 0.18.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/.agents/skills/harness-context/SKILL.md +13 -6
- package/.agents/skills/harness-debate-plan/SKILL.md +37 -20
- package/.agents/skills/harness-eval/SKILL.md +6 -21
- package/.agents/skills/harness-governor/SKILL.md +4 -3
- package/.agents/skills/harness-orchestration/SKILL.md +39 -51
- package/.agents/skills/harness-plan/SKILL.md +23 -12
- package/.agents/skills/harness-review/SKILL.md +52 -0
- package/.agents/skills/harness-sentrux-setup/SKILL.md +13 -1
- package/.agents/skills/harness-steer/SKILL.md +14 -0
- package/.pi/agents/harness/adversary.md +3 -10
- package/.pi/agents/harness/evaluator.md +3 -12
- package/.pi/agents/harness/executor.md +12 -14
- package/.pi/agents/harness/planning/decompose.md +7 -4
- package/.pi/agents/harness/planning/hypothesis-validator.md +2 -0
- package/.pi/agents/harness/planning/hypothesis.md +4 -2
- package/.pi/agents/harness/planning/implementation-researcher.md +1 -1
- package/.pi/agents/harness/planning/plan-adversary.md +2 -0
- package/.pi/agents/harness/planning/plan-evaluator.md +2 -0
- package/.pi/agents/harness/planning/plan-synthesizer.md +25 -0
- package/.pi/agents/harness/planning/planning-context.md +48 -0
- package/.pi/agents/harness/planning/review-integrator.md +2 -0
- package/.pi/agents/harness/planning/scout-graphify.md +3 -1
- package/.pi/agents/harness/planning/scout-semantic.md +3 -1
- package/.pi/agents/harness/planning/scout-structure.md +3 -1
- package/.pi/agents/harness/planning/sprint-contract-auditor.md +2 -0
- package/.pi/agents/harness/sentrux-steward.md +51 -0
- package/.pi/extensions/00-posthog-network-bootstrap.ts +11 -0
- package/.pi/extensions/harness-debate-tools.ts +12 -3
- package/.pi/extensions/harness-live-widget.ts +27 -1
- package/.pi/extensions/harness-plan-approval.ts +62 -56
- package/.pi/extensions/harness-run-context.ts +553 -84
- package/.pi/extensions/harness-subagent-submit.ts +43 -33
- package/.pi/extensions/harness-telemetry.ts +29 -4
- package/.pi/extensions/lib/debate-bus-core.ts +15 -9
- package/.pi/extensions/lib/harness-artifact-gate.ts +182 -0
- package/.pi/extensions/lib/harness-posthog.ts +9 -5
- package/.pi/extensions/lib/harness-spawn-topology.ts +188 -0
- package/.pi/extensions/lib/harness-subagent-auth.ts +105 -19
- package/.pi/extensions/lib/harness-subagent-policy.ts +37 -19
- package/.pi/extensions/lib/harness-subagent-precheck.ts +35 -9
- package/.pi/extensions/lib/harness-subagent-submit-pipeline.ts +66 -2
- package/.pi/extensions/lib/harness-subagent-submit-registry.ts +21 -3
- package/.pi/extensions/lib/harness-subagents-bridge.ts +91 -28
- package/.pi/extensions/lib/harness-subprocess-bootstrap.ts +73 -0
- package/.pi/extensions/lib/plan-approval/create-plan.ts +2 -3
- package/.pi/extensions/lib/plan-approval/resolve-disk.ts +102 -0
- package/.pi/extensions/lib/plan-approval/schema.ts +22 -8
- package/.pi/extensions/lib/plan-approval/types.ts +1 -1
- package/.pi/extensions/lib/plan-approval/validate.ts +2 -2
- package/.pi/extensions/lib/plan-approval-readiness.ts +241 -0
- package/.pi/extensions/lib/plan-debate-eligibility.ts +67 -7
- package/.pi/extensions/lib/plan-debate-focus.ts +21 -9
- package/.pi/extensions/lib/plan-debate-gate.ts +101 -17
- package/.pi/extensions/lib/plan-debate-lanes.ts +57 -3
- package/.pi/extensions/lib/plan-debate-round-status.ts +18 -7
- package/.pi/extensions/lib/plan-messenger.ts +4 -0
- package/.pi/extensions/lib/plan-review-gate.ts +59 -0
- package/.pi/extensions/lib/posthog-client.ts +76 -0
- package/.pi/extensions/policy-gate.ts +24 -19
- package/.pi/extensions/trace-recorder.ts +1 -0
- package/.pi/harness/agents.manifest.json +24 -16
- package/.pi/harness/corpus/cron.example +8 -0
- package/.pi/harness/corpus/graphify-kb-updater.config.json +159 -0
- package/.pi/harness/corpus/systemd/graphify-kb-updater.env.template +4 -0
- package/.pi/harness/corpus/systemd/graphify-kb-updater.service +17 -0
- package/.pi/harness/corpus/systemd/graphify-kb-updater.timer +11 -0
- package/.pi/harness/docs/adrs/0001-harness-constitution.md +2 -1
- package/.pi/harness/docs/adrs/0006-sentrux-dual-layer.md +7 -6
- package/.pi/harness/docs/adrs/0009-sentrux-rules-lifecycle.md +6 -1
- package/.pi/harness/docs/adrs/0031-harness-run-context.md +1 -1
- package/.pi/harness/docs/adrs/0032-harness-command-orchestration.md +7 -0
- package/.pi/harness/docs/adrs/0034-darwin-plan-research-pipeline.md +3 -3
- package/.pi/harness/docs/adrs/0036-implementation-research-and-selective-debate.md +8 -5
- package/.pi/harness/docs/adrs/0039-harness-post-run-review-gate.md +47 -0
- package/.pi/harness/docs/adrs/0040-practice-grounded-orchestration.md +40 -0
- package/.pi/harness/docs/adrs/0041-intelligent-planning-reconnaissance.md +39 -0
- package/.pi/harness/docs/adrs/0042-agent-native-orchestration.md +35 -0
- package/.pi/harness/docs/adrs/0043-path-first-harness-tools.md +38 -0
- package/.pi/harness/docs/adrs/0044-harness-steer-loop.md +36 -0
- package/.pi/harness/docs/adrs/README.md +10 -0
- package/.pi/harness/docs/graphify-kb-updater-runbook.md +157 -0
- package/.pi/harness/docs/practice-map.md +110 -0
- package/.pi/harness/env.harness.template +5 -3
- package/.pi/harness/evals/smoke/fixtures/plan-phase/minimal-med-fast/artifacts/implementation-research.yaml +28 -0
- package/.pi/harness/evals/smoke/fixtures/plan-phase/minimal-med-fast/artifacts/review-round-consolidated.yaml +25 -0
- package/.pi/harness/evals/smoke/fixtures/plan-phase/minimal-med-fast/plan-packet.yaml +196 -0
- package/.pi/harness/evals/smoke/fixtures/plan-phase/minimal-med-fast/plan-review.md +14 -0
- package/.pi/harness/evals/smoke/fixtures/plan-phase/minimal-med-fast/research-brief.yaml +62 -0
- package/.pi/harness/evals/smoke/sentrux-stub.json +1 -1
- package/.pi/harness/evals/smoke/smoke-harness-plan.mjs +43 -17
- package/.pi/harness/specs/README.md +1 -1
- package/.pi/harness/specs/harness-run-context.schema.json +11 -0
- package/.pi/harness/specs/harness-spawn-context.schema.json +14 -0
- package/.pi/harness/specs/plan-execution-plan.schema.json +39 -1
- package/.pi/harness/specs/plan-packet.schema.json +4 -0
- package/.pi/harness/specs/plan-phase-status.schema.json +17 -0
- package/.pi/harness/specs/plan-phase-waiver.schema.json +25 -0
- package/.pi/harness/specs/plan-planning-context.schema.json +50 -0
- package/.pi/harness/specs/plan-review-round-draft.schema.json +1 -1
- package/.pi/harness/specs/repair-brief.schema.json +45 -0
- package/.pi/harness/specs/review-outcome.schema.json +46 -0
- package/.pi/harness/specs/sentrux-manifest-proposal.schema.json +80 -0
- package/.pi/harness/specs/sentrux-signal.schema.json +43 -0
- package/.pi/harness/specs/steer-state.schema.json +20 -0
- package/.pi/lib/harness-context-mode-policy.ts +256 -0
- package/.pi/lib/harness-repair-brief.ts +145 -0
- package/.pi/lib/harness-run-context.ts +591 -32
- package/.pi/lib/harness-ui-state.ts +87 -9
- package/.pi/model-router.example.json +13 -4
- package/.pi/prompts/harness-auto.md +9 -9
- package/.pi/prompts/harness-critic.md +3 -30
- package/.pi/prompts/harness-eval.md +4 -37
- package/.pi/prompts/harness-plan.md +139 -57
- package/.pi/prompts/harness-review.md +150 -15
- package/.pi/prompts/harness-run.md +62 -10
- package/.pi/prompts/harness-sentrux-steward.md +55 -0
- package/.pi/prompts/harness-setup.md +4 -4
- package/.pi/prompts/harness-steer.md +30 -0
- package/.pi/scripts/graphify-kb-updater.mjs +358 -0
- package/.pi/scripts/harness-generate-model-router.mjs +118 -36
- package/.pi/scripts/harness-model-router-routing.test.mjs +97 -0
- package/.pi/scripts/harness-sync-model-router.mjs +15 -2
- package/.pi/scripts/harness-verify.mjs +51 -6
- package/.pi/scripts/harness-web-policy-guard.mjs +68 -0
- package/.pi/scripts/validate-plan-dag.mjs +3 -3
- package/AGENTS.md +1 -0
- package/CHANGELOG.md +22 -0
- package/package.json +5 -4
- package/vendor/pi-model-router/UPSTREAM_PIN.md +3 -1
- package/vendor/pi-model-router/extensions/commands.ts +4 -4
- package/vendor/pi-model-router/extensions/index.ts +21 -0
- package/vendor/pi-model-router/extensions/provider.ts +130 -79
- package/vendor/pi-model-router/extensions/routing.ts +148 -0
- package/vendor/pi-model-router/extensions/state.ts +3 -0
- package/vendor/pi-model-router/extensions/types.ts +9 -0
- package/vendor/pi-model-router/extensions/ui.ts +16 -2
- package/.pi/prompts/git-sync.md +0 -124
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: harness/planning/plan-synthesizer
|
|
3
|
+
description: Lake-first plan synthesis for low/med risk — problem framing, hypothesis, and execution_plan draft in one pass.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Plan synthesizer
|
|
7
|
+
|
|
8
|
+
You produce **lake-sized** outcomes (ADR 0042), not ticket-granularity WBS. Read `artifacts/planning-context.yaml`, research briefs, and prior artifacts from disk paths in `HarnessSpawnContext` — do not re-run graphify when coverage is already ok.
|
|
9
|
+
|
|
10
|
+
## Outputs (all required on disk)
|
|
11
|
+
|
|
12
|
+
1. **`submit_decomposition_brief`** → `artifacts/decomposition.yaml` — `core_tension`, `lakes[]` (outcome, scope boundary, verification intent), not a deep task tree.
|
|
13
|
+
2. **`submit_hypothesis_brief`** → `artifacts/hypothesis.yaml` — falsifiable claim grounded in decomposition.
|
|
14
|
+
3. **`submit_execution_plan_brief`** → `artifacts/execution-plan-draft.yaml` — lake-first `execution_plan` with `work_items` (each with `lake_id`, rich `description`, optional `context_bundle_path`), `executor_strategy` (`single_pass` for low, `per_lake` for med unless user dictates otherwise).
|
|
15
|
+
|
|
16
|
+
## Rules
|
|
17
|
+
|
|
18
|
+
- Use **`submit_*({ source_path })`** when drafts exist on disk (ADR 0043); otherwise `document`.
|
|
19
|
+
- Do not spawn subprocesses; you are the subprocess.
|
|
20
|
+
- Match schemas under `.pi/harness/specs/`.
|
|
21
|
+
- Parent runs `validate-plan-dag.mjs` after merge into `plan-packet.yaml`.
|
|
22
|
+
|
|
23
|
+
## High risk
|
|
24
|
+
|
|
25
|
+
If `--risk high` or material fork, stop and tell parent to use sequential `decompose` → `hypothesis` → `execution-plan-author` instead.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Plan-phase optional reconnaissance subagent — graphify, sg, ccc (read-only). Prefer parent tool use.
|
|
3
|
+
tools: read, bash, ls, submit_planning_context
|
|
4
|
+
disallowed_tools: write, edit, ask_user, approve_plan, create_plan, subagent, grep, find
|
|
5
|
+
extensions: false
|
|
6
|
+
thinking: low
|
|
7
|
+
max_turns: 12
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
You are the **Harness planning-context gatherer** (optional Phase 1 subprocess).
|
|
11
|
+
|
|
12
|
+
## When to use
|
|
13
|
+
|
|
14
|
+
The **parent orchestrator** normally compiles `artifacts/planning-context.yaml` using tools directly. Spawn this agent only when reconnaissance is large enough to need a clean subprocess or context isolation.
|
|
15
|
+
|
|
16
|
+
## Mission
|
|
17
|
+
|
|
18
|
+
Compile merged reconnaissance for the task in `HarnessSpawnContext`. You do **not** build the PlanPacket, approve plans, or mutate anything.
|
|
19
|
+
|
|
20
|
+
Use the repo tool hierarchy intelligently — pick tools that answer the task, not every tool by rote:
|
|
21
|
+
|
|
22
|
+
1. **Architecture / relationships:** `graphify-out/GRAPH_REPORT.md`, then `graphify query`, `graphify explain`, `graphify path` (read-only).
|
|
23
|
+
2. **Structure / symbols:** `sg -p '…'` — do not use `find` or `grep` for code search.
|
|
24
|
+
3. **Semantic implementation:** `ccc search` (2–3 focused queries). The harness runs incremental `ccc index` before spawns — do **not** run `ccc index` or `ccc search --refresh`.
|
|
25
|
+
|
|
26
|
+
Skip lanes that add no value for this task. Record skipped lanes in `coverage.<lane>.status: skipped`.
|
|
27
|
+
|
|
28
|
+
## Spawn context
|
|
29
|
+
|
|
30
|
+
Read `HarnessSpawnContext` (`task_summary`, `mode`, `plan_packet_path`, `risk_level`, `quick`). For `mode: revise`, read the existing plan first and focus on delta/risk areas.
|
|
31
|
+
|
|
32
|
+
When `quick: true`, you may set `coverage.semantic.status: skipped`.
|
|
33
|
+
|
|
34
|
+
## Bash guardrails
|
|
35
|
+
|
|
36
|
+
Read-only only: no `graphify update`, installs, redirects (`>`, `>>`), or file creation.
|
|
37
|
+
|
|
38
|
+
## Output
|
|
39
|
+
|
|
40
|
+
Before ending, call `submit_planning_context` exactly once with a full `PlanPlanningContext` document:
|
|
41
|
+
|
|
42
|
+
- `schema_version: "1.0.0"`
|
|
43
|
+
- `status`: `ok` | `partial` | `failed`
|
|
44
|
+
- `summary`: one paragraph
|
|
45
|
+
- `coverage`: `architecture`, `structure`, and `semantic` (each with `status`, `tools_used`, `summary`, `key_paths` as applicable)
|
|
46
|
+
- `findings`, `evidence_refs`, `open_questions`
|
|
47
|
+
|
|
48
|
+
Do not paste the artifact as prose — the tool write is the deliverable.
|
|
@@ -7,6 +7,8 @@ thinking: medium
|
|
|
7
7
|
max_turns: 12
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
**Inspection role:** Recorder / integration PM (round synthesis). Parent is chair. See `.pi/harness/docs/practice-map.md`.
|
|
11
|
+
|
|
10
12
|
## Your task
|
|
11
13
|
|
|
12
14
|
Synthesize evaluator, adversary, sprint audit, and (R1) hypothesis-validator lanes into one Review Gate round draft. Decide `review_gate_ready` from evidence, not optimism.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: "[DEPRECATED — ADR 0041] Legacy graphify-only scout. Prefer parent tools + planning-context.yaml."
|
|
3
3
|
tools: read, bash, ls, submit_scout_findings
|
|
4
4
|
disallowed_tools: write, edit, ask_user, approve_plan, create_plan, subagent, grep, find
|
|
5
5
|
extensions: false
|
|
@@ -7,6 +7,8 @@ thinking: low
|
|
|
7
7
|
max_turns: 8
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
> **Deprecated (ADR 0041):** The parent orchestrator should compile `artifacts/planning-context.yaml` using tools directly, or spawn `harness/planning/planning-context` once. This agent remains for backward compatibility only.
|
|
11
|
+
|
|
10
12
|
You are the **Harness planning scout (graphify lane)**.
|
|
11
13
|
|
|
12
14
|
## Mission
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: "[DEPRECATED — ADR 0041] Legacy semantic-only scout. Prefer parent tools + planning-context.yaml."
|
|
3
3
|
tools: read, bash, ls, submit_scout_findings
|
|
4
4
|
disallowed_tools: write, edit, ask_user, approve_plan, create_plan, subagent, grep, find
|
|
5
5
|
extensions: false
|
|
@@ -7,6 +7,8 @@ thinking: low
|
|
|
7
7
|
max_turns: 6
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
> **Deprecated (ADR 0041):** Prefer parent tool use or `harness/planning/planning-context`.
|
|
11
|
+
|
|
10
12
|
You are the **Harness planning scout (semantic lane)**.
|
|
11
13
|
|
|
12
14
|
## Mission
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: "[DEPRECATED — ADR 0041] Legacy structure-only scout. Prefer parent tools + planning-context.yaml."
|
|
3
3
|
tools: read, bash, ls, submit_scout_findings
|
|
4
4
|
disallowed_tools: write, edit, ask_user, approve_plan, create_plan, subagent, grep, find
|
|
5
5
|
extensions: false
|
|
@@ -7,6 +7,8 @@ thinking: low
|
|
|
7
7
|
max_turns: 6
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
> **Deprecated (ADR 0041):** Prefer parent tool use or `harness/planning/planning-context`.
|
|
11
|
+
|
|
10
12
|
You are the **Harness planning scout (structure lane)**.
|
|
11
13
|
|
|
12
14
|
## Mission
|
|
@@ -7,6 +7,8 @@ thinking: medium
|
|
|
7
7
|
max_turns: 12
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
**Inspection role:** Definition of Done auditor (sprint contract). See `.pi/harness/docs/practice-map.md`.
|
|
11
|
+
|
|
10
12
|
## Your task
|
|
11
13
|
|
|
12
14
|
Audit `execution_plan.sprint_contract` and work_item `done_criteria` against ADR-020 (Sprint Contract, Done Criteria Types, Keep Quality Left).
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Propose architecture.manifest.json changes from graphify evidence (read-only governance steward).
|
|
3
|
+
tools: read, grep, find, ls, bash, submit_sentrux_manifest_proposal
|
|
4
|
+
disallowed_tools: write, edit, ask_user, approve_plan, create_plan, subagent
|
|
5
|
+
extensions: false
|
|
6
|
+
thinking: high
|
|
7
|
+
max_turns: 16
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
You are the **Harness Sentrux Steward** — architectural **intent** governance, not setup or execution.
|
|
11
|
+
|
|
12
|
+
**Practice:** Architecture governance + fitness functions (Ford/Richards); integrated change control (PMBOK). See `.pi/harness/docs/practice-map.md` phase 4e.
|
|
13
|
+
|
|
14
|
+
## Mission
|
|
15
|
+
|
|
16
|
+
Propose updates to `.pi/harness/sentrux/architecture.manifest.json` when the codebase or plan introduces a **new bounded context**, **new forbidden dependency class**, or **evidence-backed constraint tuning**. You never write the manifest, `rules.toml`, or merge patches yourself.
|
|
17
|
+
|
|
18
|
+
## Spawn context
|
|
19
|
+
|
|
20
|
+
Read `HarnessSpawnContext` (`run_id`, `run_dir`, `plan_packet_path`, `task_summary`, scope hints). Read `artifacts/planning-context.yaml` and `artifacts/execution-plan-draft.yaml` when paths are provided.
|
|
21
|
+
|
|
22
|
+
## Protocol (graphify-first)
|
|
23
|
+
|
|
24
|
+
1. Read `graphify-out/GRAPH_REPORT.md` — god nodes, communities, surprising edges for paths in scope.
|
|
25
|
+
2. Run **targeted** read-only graphify (no `graphify update`):
|
|
26
|
+
- `graphify query "<module> coupling boundaries layers"`
|
|
27
|
+
- `graphify path "<concept A>" "<concept B>"` when proposing a new boundary
|
|
28
|
+
- `graphify explain "Modularity"` or `"Architecture governance"` for corpus-backed rationale
|
|
29
|
+
3. Compare manifest layers/boundaries to plan scope and repo structure (`sg -p` for import edges when proposing boundaries).
|
|
30
|
+
4. Optional: `sentrux check .` — cite violation messages only; do not fix code.
|
|
31
|
+
5. Classify proposal:
|
|
32
|
+
- `none` — existing layer globs cover changes; no new coupling class
|
|
33
|
+
- `tune_constraint` — e.g. `max_cc` with sentrux/graphify evidence
|
|
34
|
+
- `add_boundary` — new forbidden import direction
|
|
35
|
+
- `add_layer` / `split_layer` — new bounded context or split overloaded layer
|
|
36
|
+
|
|
37
|
+
## Output
|
|
38
|
+
|
|
39
|
+
Call **`submit_sentrux_manifest_proposal`** before exit with document matching `sentrux-manifest-proposal.schema.json` → `artifacts/sentrux-manifest-proposal.yaml`.
|
|
40
|
+
|
|
41
|
+
- `manifest_patch`: JSON Merge Patch against current manifest (minimal diff).
|
|
42
|
+
- `evidence[]`: at least one entry per non-`none` change; prefer `source: graphify`.
|
|
43
|
+
- `adr_required: true` and `adr_draft` when material (new layer or boundary affecting multiple agents).
|
|
44
|
+
- `human_required: true` when `change_class` is not `none` and not a single numeric `tune_constraint` with clear sentrux evidence.
|
|
45
|
+
|
|
46
|
+
## Guardrails
|
|
47
|
+
|
|
48
|
+
- Read-only — no file mutations, no `harness-sentrux-bootstrap`, no `/harness-sentrux-sync`.
|
|
49
|
+
- Do not duplicate full WBS decomposition — read planning artifacts instead.
|
|
50
|
+
- Do not auto-sync rules from directory trees.
|
|
51
|
+
- Never set `inherit_context: true`.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Load before other extensions: IPv4-first fetch for *.posthog.com (@posthog/pi uses global fetch).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { installPostHogFetchPatch } from "./lib/posthog-client.js";
|
|
6
|
+
|
|
7
|
+
installPostHogFetchPatch();
|
|
8
|
+
|
|
9
|
+
export default function posthogNetworkBootstrap() {
|
|
10
|
+
// Side effects run at module load; no hooks required.
|
|
11
|
+
}
|
|
@@ -192,7 +192,7 @@ export default function harnessDebateTools(pi: ExtensionAPI) {
|
|
|
192
192
|
name: "harness_plan_debate_eligibility",
|
|
193
193
|
label: "Plan Debate Eligibility",
|
|
194
194
|
description:
|
|
195
|
-
"Pre-debate profile selection (full|standard|light). Call after DAG pass, before harness_debate_open. Uses risk, fork, implementation/stack briefs — not R1 hypothesis output.",
|
|
195
|
+
"Pre-debate profile selection (full|standard|light|fast). Call after DAG pass, before harness_debate_open. Uses risk, fork, implementation/stack briefs — not R1 hypothesis output.",
|
|
196
196
|
parameters: Type.Object({
|
|
197
197
|
risk_level: Type.Optional(
|
|
198
198
|
Type.String({ description: "low | med | high" }),
|
|
@@ -250,6 +250,7 @@ export default function harnessDebateTools(pi: ExtensionAPI) {
|
|
|
250
250
|
const result = harnessPlanDebateEligibility(input);
|
|
251
251
|
const lines = [
|
|
252
252
|
`profile: ${result.profile}`,
|
|
253
|
+
`review_gate_mode: ${result.review_gate_strategy.mode}`,
|
|
253
254
|
`required_focuses: ${result.required_focuses.join(", ")}`,
|
|
254
255
|
`min_focus_rounds: ${result.min_focus_rounds}`,
|
|
255
256
|
`debate_global_cap: ${result.debate_global_cap}`,
|
|
@@ -273,7 +274,7 @@ export default function harnessDebateTools(pi: ExtensionAPI) {
|
|
|
273
274
|
Type.String({ description: "Optional; normalized to plan-<run_id>" }),
|
|
274
275
|
),
|
|
275
276
|
debate_profile: Type.Optional(
|
|
276
|
-
Type.String({ description: "full | standard | light" }),
|
|
277
|
+
Type.String({ description: "full | standard | light | fast" }),
|
|
277
278
|
),
|
|
278
279
|
required_focuses: Type.Optional(
|
|
279
280
|
Type.Array(
|
|
@@ -297,7 +298,8 @@ export default function harnessDebateTools(pi: ExtensionAPI) {
|
|
|
297
298
|
const profile =
|
|
298
299
|
p.debate_profile === "full" ||
|
|
299
300
|
p.debate_profile === "standard" ||
|
|
300
|
-
p.debate_profile === "light"
|
|
301
|
+
p.debate_profile === "light" ||
|
|
302
|
+
p.debate_profile === "fast"
|
|
301
303
|
? p.debate_profile
|
|
302
304
|
: "standard";
|
|
303
305
|
const required_focuses = (p.required_focuses ?? []).filter((f) =>
|
|
@@ -308,11 +310,14 @@ export default function harnessDebateTools(pi: ExtensionAPI) {
|
|
|
308
310
|
required_focuses:
|
|
309
311
|
required_focuses.length > 0 ? required_focuses : undefined,
|
|
310
312
|
});
|
|
313
|
+
const review_gate_mode =
|
|
314
|
+
profile === "fast" ? ("consolidated" as const) : ("threaded" as const);
|
|
311
315
|
await initPlanMessenger(runDir(projectRoot, runId), {
|
|
312
316
|
runId,
|
|
313
317
|
debateId,
|
|
314
318
|
debate_profile: profile,
|
|
315
319
|
required_focuses: opened.required_focuses,
|
|
320
|
+
review_gate_mode,
|
|
316
321
|
});
|
|
317
322
|
const sessionId = ctx.sessionManager.getSessionId();
|
|
318
323
|
captureHarnessEvent(sessionId, "harness_debate_round", {
|
|
@@ -325,11 +330,15 @@ export default function harnessDebateTools(pi: ExtensionAPI) {
|
|
|
325
330
|
const lines = [
|
|
326
331
|
`Plan debate opened: ${debateId}`,
|
|
327
332
|
`Profile: ${profile}`,
|
|
333
|
+
`Review gate mode: ${review_gate_mode}`,
|
|
328
334
|
required_focuses.length
|
|
329
335
|
? `Required focuses: ${required_focuses.join(", ")}`
|
|
330
336
|
: opened.required_focuses?.length
|
|
331
337
|
? `Required focuses: ${opened.required_focuses.join(", ")}`
|
|
332
338
|
: "Required focuses: (default all four)",
|
|
339
|
+
review_gate_mode === "consolidated"
|
|
340
|
+
? "Consolidated path: one review round (artifacts/review-round-consolidated.yaml); escalate to threaded rounds only on blockers."
|
|
341
|
+
: "Threaded path: one review round per focus (spec → wbs → schedule → quality).",
|
|
333
342
|
`Messenger: debate-messenger/ (inbox + threads/round-N/transcript.jsonl)`,
|
|
334
343
|
];
|
|
335
344
|
if (warning) lines.push(`Note: ${warning}`);
|
|
@@ -2,6 +2,7 @@ import type {
|
|
|
2
2
|
ExtensionAPI,
|
|
3
3
|
ExtensionContext,
|
|
4
4
|
} from "@earendil-works/pi-coding-agent";
|
|
5
|
+
import { evaluateCrossSessionResume } from "../lib/harness-run-context.js";
|
|
5
6
|
import {
|
|
6
7
|
deriveHarnessStatusHint,
|
|
7
8
|
formatHarnessPhaseLabel,
|
|
@@ -283,6 +284,22 @@ export default function harnessLiveWidget(pi: ExtensionAPI) {
|
|
|
283
284
|
if (mountCtx) remountHarnessLiveWidget(mountCtx);
|
|
284
285
|
});
|
|
285
286
|
|
|
287
|
+
pi.events.on("harness-run-context:updated", () => {
|
|
288
|
+
stateStore.setCrossSessionResumeCommand(null);
|
|
289
|
+
if (mountCtx) scheduleRefresh(mountCtx);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
pi.events.on("harness-cross-session-resume", (payload: unknown) => {
|
|
293
|
+
const data =
|
|
294
|
+
payload && typeof payload === "object"
|
|
295
|
+
? (payload as { resume_command?: string })
|
|
296
|
+
: null;
|
|
297
|
+
const cmd =
|
|
298
|
+
typeof data?.resume_command === "string" ? data.resume_command : null;
|
|
299
|
+
stateStore.setCrossSessionResumeCommand(cmd);
|
|
300
|
+
if (mountCtx) scheduleRefresh(mountCtx);
|
|
301
|
+
});
|
|
302
|
+
|
|
286
303
|
function updateStatusFallback(
|
|
287
304
|
ctx: ExtensionContext,
|
|
288
305
|
state: HarnessUiState,
|
|
@@ -304,6 +321,7 @@ export default function harnessLiveWidget(pi: ExtensionAPI) {
|
|
|
304
321
|
policyDecision: state.policyDecision,
|
|
305
322
|
flowSubstate: state.flowSubstate,
|
|
306
323
|
nextRecommendedCommand: state.nextRecommendedCommand,
|
|
324
|
+
crossSessionResumeCommand: state.crossSessionResumeCommand,
|
|
307
325
|
});
|
|
308
326
|
}
|
|
309
327
|
|
|
@@ -322,9 +340,17 @@ export default function harnessLiveWidget(pi: ExtensionAPI) {
|
|
|
322
340
|
});
|
|
323
341
|
}
|
|
324
342
|
|
|
325
|
-
pi.on("session_start", (_event, ctx) => {
|
|
343
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
326
344
|
mountCtx = ctx;
|
|
327
345
|
mountHarnessWidget(ctx);
|
|
346
|
+
const info = await evaluateCrossSessionResume(
|
|
347
|
+
process.cwd(),
|
|
348
|
+
ctx.sessionManager.getEntries(),
|
|
349
|
+
);
|
|
350
|
+
if (info) {
|
|
351
|
+
stateStore.setCrossSessionResumeCommand(info.resumeCommand);
|
|
352
|
+
scheduleRefresh(ctx);
|
|
353
|
+
}
|
|
328
354
|
});
|
|
329
355
|
|
|
330
356
|
pi.on("context", (_event, ctx) => {
|
|
@@ -2,12 +2,8 @@
|
|
|
2
2
|
* harness-plan-approval — PlanPacket approval UI and transcript renderer for parent sessions.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { constants } from "node:fs";
|
|
6
|
-
import { access } from "node:fs/promises";
|
|
7
|
-
import { join } from "node:path";
|
|
8
5
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
9
6
|
import { Text } from "@earendil-works/pi-tui";
|
|
10
|
-
import { Type } from "@sinclair/typebox";
|
|
11
7
|
import type { PlanPacketLike } from "../lib/harness-run-context.js";
|
|
12
8
|
import {
|
|
13
9
|
appendPlanApprovalIfNew,
|
|
@@ -33,8 +29,10 @@ import {
|
|
|
33
29
|
renderApprovePlanResult,
|
|
34
30
|
renderHarnessPlanDraft,
|
|
35
31
|
} from "./lib/plan-approval/render.js";
|
|
32
|
+
import { resolveApprovePlanParamsFromDisk } from "./lib/plan-approval/resolve-disk.js";
|
|
36
33
|
import {
|
|
37
34
|
ApprovePlanParamsSchema,
|
|
35
|
+
CreatePlanParamsSchema,
|
|
38
36
|
PROMPT_GUIDELINES,
|
|
39
37
|
PROMPT_SNIPPET,
|
|
40
38
|
} from "./lib/plan-approval/schema.js";
|
|
@@ -47,21 +45,12 @@ import {
|
|
|
47
45
|
toApprovePlanToolDetails,
|
|
48
46
|
validateApprovePlanParams,
|
|
49
47
|
} from "./lib/plan-approval/validate.js";
|
|
48
|
+
import { validatePlanApprovalReadiness } from "./lib/plan-approval-readiness.js";
|
|
50
49
|
import { validatePlanDebateGate } from "./lib/plan-debate-gate.js";
|
|
51
50
|
|
|
52
51
|
// @ts-expect-error pi extensions run as ESM
|
|
53
52
|
const MODULE_URL = import.meta.url;
|
|
54
53
|
|
|
55
|
-
const CreatePlanParamsSchema = Type.Object({
|
|
56
|
-
plan_packet: Type.Object(
|
|
57
|
-
{},
|
|
58
|
-
{
|
|
59
|
-
description:
|
|
60
|
-
"Approved PlanPacket to persist (same object as approve_plan).",
|
|
61
|
-
},
|
|
62
|
-
),
|
|
63
|
-
});
|
|
64
|
-
|
|
65
54
|
export default function harnessPlanApproval(pi: ExtensionAPI) {
|
|
66
55
|
if (!claimExtensionLoad("harness-plan-approval", MODULE_URL)) return;
|
|
67
56
|
pi.registerMessageRenderer(
|
|
@@ -103,12 +92,37 @@ export default function harnessPlanApproval(pi: ExtensionAPI) {
|
|
|
103
92
|
parameters: ApprovePlanParamsSchema,
|
|
104
93
|
|
|
105
94
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
106
|
-
const
|
|
95
|
+
const entries = ctx.sessionManager.getEntries();
|
|
96
|
+
const projectRoot = process.cwd();
|
|
97
|
+
const resolved = await resolveApprovePlanParamsFromDisk(
|
|
98
|
+
params as ApprovePlanParams,
|
|
99
|
+
entries,
|
|
100
|
+
projectRoot,
|
|
101
|
+
);
|
|
102
|
+
if (!resolved.ok) {
|
|
103
|
+
return {
|
|
104
|
+
content: [{ type: "text", text: resolved.error }],
|
|
105
|
+
details: {
|
|
106
|
+
plan_packet: (params as ApprovePlanParams).plan_packet ?? {},
|
|
107
|
+
options: [],
|
|
108
|
+
response: null,
|
|
109
|
+
cancelled: true,
|
|
110
|
+
},
|
|
111
|
+
isError: true,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
const validated = validateApprovePlanParams({
|
|
115
|
+
...(params as ApprovePlanParams),
|
|
116
|
+
plan_packet: resolved.plan_packet,
|
|
117
|
+
research_brief:
|
|
118
|
+
resolved.research_brief ??
|
|
119
|
+
(params as ApprovePlanParams).research_brief,
|
|
120
|
+
});
|
|
107
121
|
if (typeof validated === "string") {
|
|
108
122
|
return {
|
|
109
123
|
content: [{ type: "text", text: validated }],
|
|
110
124
|
details: {
|
|
111
|
-
plan_packet:
|
|
125
|
+
plan_packet: resolved.plan_packet,
|
|
112
126
|
options: [],
|
|
113
127
|
response: null,
|
|
114
128
|
cancelled: true,
|
|
@@ -116,7 +130,6 @@ export default function harnessPlanApproval(pi: ExtensionAPI) {
|
|
|
116
130
|
};
|
|
117
131
|
}
|
|
118
132
|
|
|
119
|
-
const entries = ctx.sessionManager.getEntries();
|
|
120
133
|
if (
|
|
121
134
|
hasPlanUserApproval(entries, {
|
|
122
135
|
sincePlanCommand: true,
|
|
@@ -148,43 +161,33 @@ export default function harnessPlanApproval(pi: ExtensionAPI) {
|
|
|
148
161
|
validated.human_summary?.trim() ||
|
|
149
162
|
`Plan ${planId} — pending your approval`;
|
|
150
163
|
const runCtx = getLatestRunContext(entries);
|
|
151
|
-
const projectRoot = process.cwd();
|
|
152
164
|
const implWarnings: string[] = [];
|
|
165
|
+
const risk = String(
|
|
166
|
+
validated.plan_packet.risk_level ?? "med",
|
|
167
|
+
).toLowerCase();
|
|
153
168
|
if (runCtx?.run_id) {
|
|
154
|
-
const
|
|
169
|
+
const readiness = await validatePlanApprovalReadiness(
|
|
155
170
|
projectRoot,
|
|
156
|
-
".pi",
|
|
157
|
-
"harness",
|
|
158
|
-
"runs",
|
|
159
171
|
runCtx.run_id,
|
|
160
|
-
|
|
161
|
-
"implementation-research.yaml",
|
|
172
|
+
{ risk_level: risk },
|
|
162
173
|
);
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
}
|
|
170
|
-
const risk = String(
|
|
171
|
-
validated.plan_packet.risk_level ?? "med",
|
|
172
|
-
).toLowerCase();
|
|
173
|
-
if (!implExists) {
|
|
174
|
-
const msg =
|
|
175
|
-
"approve_plan: missing artifacts/implementation-research.yaml (Phase 3.5 required)";
|
|
176
|
-
if (risk === "high") {
|
|
177
|
-
return {
|
|
178
|
-
content: [{ type: "text", text: msg }],
|
|
179
|
-
details: {
|
|
180
|
-
plan_packet: validated.plan_packet,
|
|
181
|
-
cancelled: true,
|
|
174
|
+
if (!readiness.ok) {
|
|
175
|
+
return {
|
|
176
|
+
content: [
|
|
177
|
+
{
|
|
178
|
+
type: "text",
|
|
179
|
+
text: `approve_plan blocked — plan phase not ready:\n- ${readiness.errors.join("\n- ")}`,
|
|
182
180
|
},
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
181
|
+
],
|
|
182
|
+
details: {
|
|
183
|
+
plan_packet: validated.plan_packet,
|
|
184
|
+
readiness,
|
|
185
|
+
cancelled: true,
|
|
186
|
+
},
|
|
187
|
+
isError: true,
|
|
188
|
+
};
|
|
187
189
|
}
|
|
190
|
+
implWarnings.push(...readiness.warnings);
|
|
188
191
|
}
|
|
189
192
|
if (runCtx?.run_id) {
|
|
190
193
|
const gate = await validatePlanDebateGate(projectRoot, runCtx.run_id);
|
|
@@ -308,19 +311,22 @@ export default function harnessPlanApproval(pi: ExtensionAPI) {
|
|
|
308
311
|
parameters: CreatePlanParamsSchema,
|
|
309
312
|
|
|
310
313
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
311
|
-
const
|
|
312
|
-
|
|
314
|
+
const entries = ctx.sessionManager.getEntries();
|
|
315
|
+
const runCtx = getLatestRunContext(entries);
|
|
316
|
+
const projectRoot = process.cwd();
|
|
317
|
+
const resolved = await resolveApprovePlanParamsFromDisk(
|
|
318
|
+
params as ApprovePlanParams,
|
|
319
|
+
entries,
|
|
320
|
+
projectRoot,
|
|
321
|
+
);
|
|
322
|
+
if (!resolved.ok) {
|
|
313
323
|
return {
|
|
314
|
-
content: [{ type: "text", text:
|
|
315
|
-
details: { error:
|
|
324
|
+
content: [{ type: "text", text: resolved.error }],
|
|
325
|
+
details: { error: resolved.error },
|
|
316
326
|
isError: true,
|
|
317
327
|
};
|
|
318
328
|
}
|
|
319
|
-
|
|
320
|
-
const entries = ctx.sessionManager.getEntries();
|
|
321
|
-
const runCtx = getLatestRunContext(entries);
|
|
322
|
-
const projectRoot = process.cwd();
|
|
323
|
-
const result = await executeCreatePlan(validated.plan_packet, {
|
|
329
|
+
const result = await executeCreatePlan(resolved.plan_packet, {
|
|
324
330
|
projectRoot,
|
|
325
331
|
getParentEntries: () => entries,
|
|
326
332
|
getSubagentEntries: () => entries,
|