ultimate-pi 0.17.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 +3 -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-live-widget.ts +27 -1
- package/.pi/extensions/harness-plan-approval.ts +62 -56
- package/.pi/extensions/harness-run-context.ts +541 -84
- package/.pi/extensions/harness-subagent-submit.ts +43 -10
- 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 +1 -0
- package/.pi/extensions/lib/harness-subagent-policy.ts +23 -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 +7 -29
- 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 +12 -5
- package/.pi/extensions/lib/plan-debate-gate.ts +22 -1
- package/.pi/extensions/lib/plan-debate-lanes.ts +32 -2
- package/.pi/extensions/lib/plan-review-gate.ts +8 -0
- package/.pi/extensions/lib/posthog-client.ts +76 -0
- package/.pi/extensions/policy-gate.ts +24 -19
- 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/sentrux-stub.json +1 -1
- package/.pi/harness/evals/smoke/smoke-harness-plan.mjs +5 -2
- 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/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/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 +118 -54
- 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-steer.md +30 -0
- package/.pi/scripts/graphify-kb-updater.mjs +358 -0
- package/.pi/scripts/harness-verify.mjs +22 -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 +11 -0
- package/package.json +5 -4
- 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
|
+
}
|
|
@@ -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,
|