ultimate-pi 0.18.0 → 0.19.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-debate-plan/SKILL.md +1 -1
- package/.agents/skills/harness-decisions/SKILL.md +2 -3
- package/.agents/skills/harness-governor/SKILL.md +6 -5
- package/.agents/skills/harness-orchestration/SKILL.md +4 -4
- package/.agents/skills/harness-review/SKILL.md +7 -7
- package/.agents/skills/harness-sentrux-setup/SKILL.md +4 -3
- package/.agents/skills/harness-steer/SKILL.md +1 -1
- package/.agents/skills/sentrux/SKILL.md +9 -9
- package/.pi/PACKAGING.md +4 -4
- package/.pi/SYSTEM.md +54 -120
- package/.pi/agents/harness/incident-recorder.md +0 -1
- package/.pi/agents/harness/planning/decompose.md +1 -3
- package/.pi/agents/harness/planning/execution-plan-author.md +0 -2
- package/.pi/agents/harness/planning/hypothesis-validator.md +0 -2
- package/.pi/agents/harness/planning/hypothesis.md +0 -2
- package/.pi/agents/harness/planning/implementation-researcher.md +0 -2
- package/.pi/agents/harness/planning/plan-adversary.md +0 -2
- package/.pi/agents/harness/planning/plan-evaluator.md +1 -3
- package/.pi/agents/harness/planning/planning-context.md +0 -2
- package/.pi/agents/harness/planning/review-integrator.md +0 -2
- package/.pi/agents/harness/planning/sprint-contract-auditor.md +0 -2
- package/.pi/agents/harness/planning/stack-researcher.md +0 -2
- package/.pi/agents/harness/{adversary.md → reviewing/adversary.md} +0 -2
- package/.pi/agents/harness/{evaluator.md → reviewing/evaluator.md} +0 -2
- package/.pi/agents/harness/{tie-breaker.md → reviewing/tie-breaker.md} +0 -2
- package/.pi/agents/harness/{executor.md → running/executor.md} +0 -2
- package/.pi/agents/harness/sentrux-bootstrap.md +0 -1
- package/.pi/agents/harness/sentrux-steward.md +0 -2
- package/.pi/agents/harness/trace-librarian.md +0 -1
- package/.pi/extensions/00-harness-project-control.ts +133 -0
- package/.pi/extensions/00-posthog-network-bootstrap.ts +1 -1
- package/.pi/extensions/agt-kill-switch.ts +57 -0
- package/.pi/extensions/agt-prompt-guard.ts +32 -0
- package/.pi/extensions/budget-guard.ts +2 -0
- package/.pi/extensions/custom-footer.ts +46 -145
- package/.pi/extensions/custom-header.ts +1 -1
- package/.pi/extensions/custom-system-prompt.ts +1 -1
- package/.pi/extensions/debate-orchestrator.ts +7 -5
- package/.pi/extensions/harness-ask-user.ts +8 -8
- package/.pi/extensions/harness-debate-tools.ts +27 -43
- package/.pi/extensions/harness-lens.ts +94 -0
- package/.pi/extensions/harness-live-widget.ts +33 -2
- package/.pi/extensions/harness-plan-approval.ts +12 -12
- package/.pi/extensions/harness-run-context.ts +1214 -852
- package/.pi/extensions/harness-subagent-governance.ts +8 -0
- package/.pi/extensions/harness-subagent-submit.ts +36 -164
- package/.pi/extensions/harness-subagents.ts +4 -4
- package/.pi/extensions/harness-telemetry.ts +3 -1
- package/.pi/extensions/harness-web-tools.ts +3 -3
- package/.pi/extensions/observation-bus.ts +2 -0
- package/.pi/extensions/policy-gate.ts +27 -5
- package/.pi/extensions/review-integrity.ts +91 -10
- package/.pi/extensions/sentrux-rules-sync.ts +3 -1
- package/.pi/extensions/subagent-governance.ts +92 -0
- package/.pi/extensions/test-diff-integrity.ts +1 -0
- package/.pi/extensions/trace-recorder.ts +3 -1
- package/.pi/extensions/{ultimate-pi-vcc.ts → vcc-compaction.ts} +1 -1
- package/.pi/harness/README.md +6 -2
- package/.pi/harness/agents.manifest.json +38 -49
- package/.pi/harness/agents.policy.yaml +275 -0
- package/.pi/harness/corpus/graphify-kb-updater.config.json +55 -0
- package/.pi/harness/docs/adrs/0006-sentrux-dual-layer.md +2 -1
- package/.pi/harness/docs/adrs/0030-inhouse-vcc-compaction.md +1 -1
- package/.pi/harness/docs/adrs/0035-plan-phase-review-gate.md +1 -1
- package/.pi/harness/docs/adrs/0044-harness-steer-loop.md +3 -2
- package/.pi/harness/docs/adrs/0045-harness-lens-minimal-contract.md +49 -0
- package/.pi/harness/docs/adrs/0045-phase-scoped-agent-directories.md +33 -0
- package/.pi/harness/docs/adrs/0046-agt-policy-engine.md +51 -0
- package/.pi/harness/docs/adrs/0047-agt-layered-security.md +39 -0
- package/.pi/harness/docs/adrs/0048-tool-call-hook-order.md +25 -0
- package/.pi/harness/docs/adrs/0049-agents-policy-manifest.md +36 -0
- package/.pi/harness/docs/adrs/README.md +6 -0
- package/.pi/harness/docs/graphify-kb-updater-runbook.md +11 -5
- package/.pi/harness/docs/practice-map.md +2 -2
- package/.pi/harness/evolution/README.md +1 -2
- package/.pi/harness/examples/agents.policy.project.yaml +19 -0
- package/.pi/harness/examples/policies/custom-deny-bash.yaml +9 -0
- package/.pi/harness/policies/bash-denylists.yaml +5 -0
- package/.pi/harness/policies/defaults.yaml +51 -0
- package/.pi/harness/policies/orchestrator.yaml +18 -0
- package/.pi/harness/policies/phases.yaml +10 -0
- package/.pi/harness/policies/roles.yaml +5 -0
- package/.pi/harness/policies/web-guard.yaml +5 -0
- package/.pi/harness/policies/workflow-sequences.yaml +9 -0
- package/.pi/harness/sentrux/architecture.manifest.json +26 -4
- package/.pi/harness/specs/harness-spawn-context.schema.json +1 -1
- package/.pi/harness/specs/observation.schema.json +2 -1
- package/.pi/lib/agents-policy.d.mts +70 -0
- package/.pi/lib/agents-policy.mjs +325 -0
- package/.pi/lib/agents-policy.ts +19 -0
- package/.pi/lib/agt/audit-run-sink.ts +52 -0
- package/.pi/lib/agt/build-evaluation-context.ts +285 -0
- package/.pi/lib/agt/config.ts +28 -0
- package/.pi/lib/agt/delegation.ts +69 -0
- package/.pi/lib/agt/evaluate-policy.ts +56 -0
- package/.pi/lib/agt/identity-registry.ts +41 -0
- package/.pi/lib/agt/index.ts +55 -0
- package/.pi/lib/agt/kill-switch-state.ts +11 -0
- package/.pi/lib/agt/legacy-evaluate.ts +101 -0
- package/.pi/lib/agt/policy-engine.ts +154 -0
- package/.pi/lib/agt/rings.ts +21 -0
- package/.pi/lib/agt/sre-hooks.ts +45 -0
- package/.pi/lib/agt/trust-run-store.ts +26 -0
- package/.pi/lib/agt/workflow-history.ts +29 -0
- package/.pi/lib/agt-governance-active.ts +14 -0
- package/.pi/lib/agt-tool-guard.ts +78 -0
- package/.pi/lib/ask-user/dialog.ts +314 -0
- package/.pi/{extensions/lib → lib}/debate-bus-core.ts +10 -10
- package/.pi/{extensions/lib → lib}/debate-bus-state.ts +1 -1
- package/.pi/{extensions/lib → lib}/extension-load-guard.ts +21 -0
- package/.pi/lib/harness-agt-tool-guard.ts +5 -0
- package/.pi/{extensions/lib → lib}/harness-artifact-gate.ts +6 -16
- package/.pi/lib/harness-debate-core-deps.ts +14 -0
- package/.pi/lib/harness-debate-workflow-deps.ts +43 -0
- package/.pi/lib/harness-lens/.gitattributes +1 -0
- package/.pi/lib/harness-lens/clients/edit-autopatch.ts +88 -0
- package/.pi/lib/harness-lens/clients/file-kinds.ts +380 -0
- package/.pi/lib/harness-lens/clients/file-time.ts +215 -0
- package/.pi/lib/harness-lens/clients/file-utils.ts +484 -0
- package/.pi/lib/harness-lens/clients/format-service.ts +276 -0
- package/.pi/lib/harness-lens/clients/formatters.ts +1000 -0
- package/.pi/lib/harness-lens/clients/git-guard.ts +31 -0
- package/.pi/lib/harness-lens/clients/indent-retarget.ts +90 -0
- package/.pi/lib/harness-lens/clients/installer/index.ts +2368 -0
- package/.pi/lib/harness-lens/clients/latency-logger.ts +80 -0
- package/.pi/lib/harness-lens/clients/lens-config.ts +43 -0
- package/.pi/lib/harness-lens/clients/lens-events.ts +164 -0
- package/.pi/lib/harness-lens/clients/lsp/aggregation.ts +91 -0
- package/.pi/lib/harness-lens/clients/lsp/client.ts +1466 -0
- package/.pi/lib/harness-lens/clients/lsp/config.ts +216 -0
- package/.pi/lib/harness-lens/clients/lsp/edits.ts +297 -0
- package/.pi/lib/harness-lens/clients/lsp/index.ts +1355 -0
- package/.pi/lib/harness-lens/clients/lsp/interactive-install.ts +424 -0
- package/.pi/lib/harness-lens/clients/lsp/language.ts +223 -0
- package/.pi/lib/harness-lens/clients/lsp/launch.ts +939 -0
- package/.pi/lib/harness-lens/clients/lsp/lsp-index.ts +11 -0
- package/.pi/lib/harness-lens/clients/lsp/path-utils.ts +12 -0
- package/.pi/lib/harness-lens/clients/lsp/server-strategies.ts +81 -0
- package/.pi/lib/harness-lens/clients/lsp/server.ts +1971 -0
- package/.pi/lib/harness-lens/clients/path-utils.ts +182 -0
- package/.pi/lib/harness-lens/clients/pipeline.ts +360 -0
- package/.pi/lib/harness-lens/clients/project-profile.ts +117 -0
- package/.pi/lib/harness-lens/clients/runtime-agent-end.ts +112 -0
- package/.pi/lib/harness-lens/clients/runtime-config.ts +33 -0
- package/.pi/lib/harness-lens/clients/runtime-coordinator.ts +186 -0
- package/.pi/lib/harness-lens/clients/runtime-tool-result.ts +171 -0
- package/.pi/lib/harness-lens/clients/safe-spawn.ts +339 -0
- package/.pi/lib/harness-lens/clients/secrets-scanner.ts +214 -0
- package/.pi/lib/harness-lens/clients/tool-policy.ts +2072 -0
- package/.pi/lib/harness-lens/clients/types.ts +59 -0
- package/.pi/lib/harness-lens/clients/widget-state.ts +283 -0
- package/.pi/lib/harness-lens/index.ts +532 -0
- package/.pi/lib/harness-lens/tools/lsp-diagnostics.ts +706 -0
- package/.pi/lib/harness-lens/tools/lsp-navigation.ts +1246 -0
- package/.pi/{extensions/lib → lib}/harness-posthog.ts +3 -0
- package/.pi/lib/harness-project-config.ts +91 -0
- package/.pi/lib/harness-run-context-responses.ts +9 -0
- package/.pi/lib/harness-run-context.ts +1 -3
- package/.pi/{extensions/lib/spawn-policy.ts → lib/harness-spawn-policy.ts} +4 -3
- package/.pi/{extensions/lib → lib}/harness-spawn-topology.ts +5 -28
- package/.pi/lib/harness-subagent-auth.ts +51 -0
- package/.pi/{extensions/lib → lib}/harness-subagent-precheck.ts +13 -10
- package/.pi/{extensions/lib → lib}/harness-subagent-submit-pipeline.ts +3 -3
- package/.pi/lib/harness-subagent-submit-register.ts +163 -0
- package/.pi/{extensions/lib → lib}/harness-subagent-submit-registry.ts +1 -55
- package/.pi/{extensions/lib → lib}/harness-subagents-bridge.ts +53 -14
- package/.pi/{extensions/lib → lib}/harness-subprocess-bootstrap.ts +1 -1
- package/.pi/lib/harness-ui-state.ts +27 -12
- package/.pi/{extensions/lib → lib}/plan-approval/create-plan.ts +2 -2
- package/.pi/{extensions/lib → lib}/plan-approval/format-plan.ts +2 -2
- package/.pi/{extensions/lib → lib}/plan-approval/plan-review.ts +162 -201
- package/.pi/{extensions/lib → lib}/plan-approval/render.ts +1 -1
- package/.pi/{extensions/lib → lib}/plan-approval/resolve-disk.ts +2 -2
- package/.pi/{extensions/lib → lib}/plan-approval/types.ts +1 -1
- package/.pi/{extensions/lib → lib}/plan-approval/validate.ts +3 -3
- package/.pi/{extensions/lib → lib}/plan-approval-readiness.ts +3 -52
- package/.pi/{extensions/lib → lib}/plan-debate-envelope.ts +1 -1
- package/.pi/{extensions/lib → lib}/plan-debate-gate.ts +1 -1
- package/.pi/{extensions/lib → lib}/plan-debate-lane.ts +1 -4
- package/.pi/{extensions/lib → lib}/plan-messenger.ts +1 -1
- package/.pi/prompts/harness-auto.md +2 -2
- package/.pi/prompts/harness-plan.md +4 -6
- package/.pi/prompts/harness-review.md +9 -9
- package/.pi/prompts/harness-run.md +7 -7
- package/.pi/prompts/harness-setup.md +42 -68
- package/.pi/prompts/harness-steer.md +2 -2
- package/.pi/scripts/README.md +3 -5
- package/.pi/scripts/generate-agents-policy-yaml.mjs +148 -0
- package/.pi/scripts/graphify-kb-updater.mjs +48 -8
- package/.pi/scripts/harness-agents-manifest.mjs +61 -4
- package/.pi/scripts/harness-agt-doctor.ts +36 -0
- package/.pi/scripts/harness-cli-verify.sh +9 -2
- package/.pi/scripts/harness-project-toggle.mjs +129 -0
- package/.pi/scripts/harness-sentrux-cli.mjs +142 -0
- package/.pi/scripts/harness-verify.mjs +113 -39
- package/.pi/scripts/harness-web-policy-guard.mjs +2 -2
- package/.pi/scripts/validate-plan-dag.mjs +65 -74
- package/.pi/scripts/vendor-pi-vcc-settings.stub.ts +2 -2
- package/.pi/scripts/vendor-sync-pi-vcc.sh +1 -1
- package/.pi/skills/architecture/broker-domain/SKILL.md +65 -0
- package/.pi/skills/architecture/cqrs/SKILL.md +63 -0
- package/.pi/skills/architecture/event-driven/SKILL.md +60 -0
- package/.pi/skills/architecture/hexagonal-ports-adapters/SKILL.md +66 -0
- package/.pi/skills/architecture/layered/SKILL.md +68 -0
- package/.pi/skills/architecture/microkernel/SKILL.md +62 -0
- package/.pi/skills/architecture/microservices/SKILL.md +64 -0
- package/.pi/skills/architecture/modular-monolith/SKILL.md +65 -0
- package/.pi/skills/architecture/orchestration-driven-soa/SKILL.md +61 -0
- package/.pi/skills/architecture/pipeline/SKILL.md +63 -0
- package/.pi/skills/architecture/service-based/SKILL.md +64 -0
- package/.pi/skills/architecture/service-mesh/SKILL.md +60 -0
- package/.pi/skills/architecture/space-based/SKILL.md +60 -0
- package/.pi/skills/ast-grep/SKILL.md +40 -321
- package/.pi/skills/delivery/debugging-discipline/SKILL.md +36 -0
- package/.pi/skills/delivery/documentation-update/SKILL.md +33 -0
- package/.pi/skills/delivery/requirements-to-implementation/SKILL.md +34 -0
- package/.pi/skills/delivery/risk-based-verification/SKILL.md +43 -0
- package/.pi/skills/delivery/tradeoff-analysis/SKILL.md +34 -0
- package/.pi/skills/engineering/api-contract-design/SKILL.md +38 -0
- package/.pi/skills/engineering/cohesion-coupling/SKILL.md +43 -0
- package/.pi/skills/engineering/complexity-control/SKILL.md +31 -0
- package/.pi/skills/engineering/defensive-programming/SKILL.md +38 -0
- package/.pi/skills/engineering/dependency-management/SKILL.md +29 -0
- package/.pi/skills/engineering/domain-modeling/SKILL.md +32 -0
- package/.pi/skills/engineering/error-handling/SKILL.md +37 -0
- package/.pi/skills/engineering/legacy-code-seams/SKILL.md +35 -0
- package/.pi/skills/engineering/naming-and-intent/SKILL.md +29 -0
- package/.pi/skills/engineering/refactoring-safe-evolution/SKILL.md +35 -0
- package/.pi/skills/engineering/routine-function-design/SKILL.md +34 -0
- package/.pi/skills/engineering/small-change-discipline/SKILL.md +35 -0
- package/.pi/skills/lsp-navigation/SKILL.md +89 -0
- package/.pi/skills/quality/code-review-self-check/SKILL.md +35 -0
- package/.pi/skills/quality/privacy-data-handling/SKILL.md +26 -0
- package/.pi/skills/quality/security-review/SKILL.md +34 -0
- package/.pi/skills/quality/test-strategy/SKILL.md +33 -0
- package/.pi/skills/quality/testability-design/SKILL.md +33 -0
- package/.pi/skills/systems/concurrency-safety/SKILL.md +32 -0
- package/.pi/skills/systems/data-modeling-migrations/SKILL.md +31 -0
- package/.pi/skills/systems/observability-instrumentation/SKILL.md +32 -0
- package/.pi/skills/systems/performance-measurement/SKILL.md +35 -0
- package/.pi/skills/systems/reliability-design/SKILL.md +32 -0
- package/.sentrux/rules.toml +20 -4
- package/AGENTS.md +5 -0
- package/CHANGELOG.md +26 -0
- package/README.md +85 -58
- package/THIRD_PARTY_NOTICES.md +12 -21
- package/package.json +15 -7
- package/vendor/pi-subagents/src/agents.ts +45 -1
- package/vendor/pi-subagents/src/subagents.ts +866 -811
- package/vendor/pi-vcc/src/core/brief.ts +68 -99
- package/vendor/pi-vcc/src/core/settings.ts +2 -2
- package/.agents/skills/caveman/SKILL.md +0 -67
- package/.pi/agents/harness/meta-optimizer.md +0 -36
- package/.pi/agents/harness/planning/scout-graphify.md +0 -39
- package/.pi/agents/harness/planning/scout-semantic.md +0 -41
- package/.pi/agents/harness/planning/scout-structure.md +0 -37
- package/.pi/extensions/lib/ask-user/dialog.ts +0 -260
- package/.pi/extensions/lib/harness-subagent-auth.ts +0 -209
- package/.pi/extensions/lib/harness-subagent-policy.ts +0 -236
- package/.pi/extensions/pi-model-router-harness.ts +0 -42
- package/.pi/harness/evolution/meta-optimizer.mjs +0 -99
- package/.pi/harness/specs/router-tuning-proposal.schema.json +0 -114
- package/.pi/model-router.example.json +0 -36
- package/.pi/prompts/harness-critic.md +0 -10
- package/.pi/prompts/harness-eval.md +0 -10
- package/.pi/prompts/harness-router-tune.md +0 -52
- package/.pi/scripts/harness-generate-model-router.mjs +0 -327
- package/.pi/scripts/harness-model-router-routing.test.mjs +0 -97
- package/.pi/scripts/harness-sync-model-router.mjs +0 -97
- package/.pi/scripts/vendor-sync-pi-model-router.sh +0 -47
- package/vendor/pi-model-router/.prettierignore +0 -4
- package/vendor/pi-model-router/.prettierrc +0 -5
- package/vendor/pi-model-router/AGENTS.md +0 -39
- package/vendor/pi-model-router/LICENSE +0 -21
- package/vendor/pi-model-router/README.md +0 -99
- package/vendor/pi-model-router/UPSTREAM_PIN.md +0 -10
- package/vendor/pi-model-router/docs/ARCHITECTURE.md +0 -54
- package/vendor/pi-model-router/extensions/commands.ts +0 -720
- package/vendor/pi-model-router/extensions/config.ts +0 -348
- package/vendor/pi-model-router/extensions/constants.ts +0 -1
- package/vendor/pi-model-router/extensions/index.ts +0 -478
- package/vendor/pi-model-router/extensions/provider.ts +0 -580
- package/vendor/pi-model-router/extensions/routing.ts +0 -564
- package/vendor/pi-model-router/extensions/state.ts +0 -52
- package/vendor/pi-model-router/extensions/types.ts +0 -95
- package/vendor/pi-model-router/extensions/ui.ts +0 -144
- package/vendor/pi-model-router/model-router.example.json +0 -48
- package/vendor/pi-model-router/package.json +0 -48
- package/vendor/pi-model-router/tsconfig.json +0 -16
- /package/.pi/{prompts → harness/docs}/planning-rubrics.md +0 -0
- /package/.pi/{extensions/lib → lib}/ask-user/fallback.ts +0 -0
- /package/.pi/{extensions/lib → lib}/ask-user/render.ts +0 -0
- /package/.pi/{extensions/lib → lib}/ask-user/schema.ts +0 -0
- /package/.pi/{extensions/lib → lib}/ask-user/types.ts +0 -0
- /package/.pi/{extensions/lib → lib}/ask-user/validate-core.mjs +0 -0
- /package/.pi/{extensions/lib → lib}/ask-user/validate.ts +0 -0
- /package/.pi/{extensions/lib → lib}/harness-cocoindex-refresh.ts +0 -0
- /package/.pi/{extensions/lib → lib}/harness-paths.ts +0 -0
- /package/.pi/{extensions/lib → lib}/harness-spawn-budget.ts +0 -0
- /package/.pi/{extensions/lib → lib}/harness-vcc-settings.ts +0 -0
- /package/.pi/{extensions/lib → lib}/harness-web/run-cli.ts +0 -0
- /package/.pi/{extensions/lib → lib}/plan-approval/dialog.ts +0 -0
- /package/.pi/{extensions/lib → lib}/plan-approval/schema.ts +0 -0
- /package/.pi/{extensions/lib → lib}/plan-debate-eligibility.ts +0 -0
- /package/.pi/{extensions/lib → lib}/plan-debate-focus.ts +0 -0
- /package/.pi/{extensions/lib → lib}/plan-debate-id.ts +0 -0
- /package/.pi/{extensions/lib → lib}/plan-debate-lanes.ts +0 -0
- /package/.pi/{extensions/lib → lib}/plan-debate-round-status.ts +0 -0
- /package/.pi/{extensions/lib → lib}/plan-debate-write-guard.ts +0 -0
- /package/.pi/{extensions/lib → lib}/plan-review-gate.ts +0 -0
- /package/.pi/{extensions/lib → lib}/plan-review-integrator-rules.ts +0 -0
- /package/.pi/{extensions/lib → lib}/plan-scope-guard.ts +0 -0
- /package/.pi/{extensions/lib → lib}/posthog-client.ts +0 -0
- /package/.pi/{extensions/lib → lib}/posthog-node.d.ts +0 -0
|
@@ -1,84 +1,42 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Subprocess-only harness submit tools — validate + write artifacts under run_dir.
|
|
3
|
-
*
|
|
3
|
+
* Prefer harness-subagent-governance.ts bundle (AGT + submit) for harness spawns.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { join } from "node:path";
|
|
7
7
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { getHarnessPackageRoot } from "./lib/harness-paths.js";
|
|
12
|
-
import { evaluateHarnessSubagentToolCall } from "./lib/harness-subagent-policy.js";
|
|
8
|
+
import { claimHarnessGovernanceLoad } from "../lib/extension-load-guard.js";
|
|
9
|
+
import { evaluateAgtHarnessToolCall } from "../lib/harness-agt-tool-guard.js";
|
|
10
|
+
import { getHarnessPackageRoot } from "../lib/harness-paths.js";
|
|
13
11
|
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
isSubprocessHarnessSubmit,
|
|
13
|
+
registerHarnessSubagentSubmitTools,
|
|
14
|
+
resolveHarnessSubmitRunContext,
|
|
15
|
+
} from "../lib/harness-subagent-submit-register.js";
|
|
18
16
|
|
|
19
17
|
// @ts-expect-error pi extensions run as ESM
|
|
20
18
|
const MODULE_URL = import.meta.url;
|
|
21
19
|
|
|
22
|
-
const DocumentSchema = Type.Object(
|
|
23
|
-
{
|
|
24
|
-
document: Type.Optional(
|
|
25
|
-
Type.Record(Type.String(), Type.Unknown(), {
|
|
26
|
-
description:
|
|
27
|
-
"Artifact fields (deprecated when source_path is set; ADR 0043)",
|
|
28
|
-
}),
|
|
29
|
-
),
|
|
30
|
-
source_path: Type.Optional(
|
|
31
|
-
Type.String({
|
|
32
|
-
description:
|
|
33
|
-
"Relative path under run dir, e.g. artifacts/.draft/decomposition.yaml",
|
|
34
|
-
}),
|
|
35
|
-
),
|
|
36
|
-
},
|
|
37
|
-
{ additionalProperties: false },
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
function resolveRunContext(): {
|
|
41
|
-
projectRoot: string;
|
|
42
|
-
specsDir: string;
|
|
43
|
-
runId: string;
|
|
44
|
-
runDirEnv?: string;
|
|
45
|
-
agentId: string;
|
|
46
|
-
} {
|
|
47
|
-
const projectRoot = process.env.HARNESS_PKG_ROOT ?? process.cwd();
|
|
48
|
-
const specsDir = join(projectRoot, ".pi", "harness", "specs");
|
|
49
|
-
const runId = process.env.HARNESS_RUN_ID?.trim() ?? "";
|
|
50
|
-
const runDirEnv = process.env.HARNESS_RUN_DIR?.trim();
|
|
51
|
-
const agentId = process.env.HARNESS_AGENT_ID?.trim() ?? "";
|
|
52
|
-
return { projectRoot, specsDir, runId, runDirEnv, agentId };
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function isSubprocessHarness(): boolean {
|
|
56
|
-
return (
|
|
57
|
-
process.env.PI_HARNESS_SUBPROCESS === "1" &&
|
|
58
|
-
Boolean(process.env.HARNESS_RUN_ID?.trim())
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
20
|
export default function harnessSubagentSubmit(pi: ExtensionAPI) {
|
|
63
|
-
if (!
|
|
64
|
-
|
|
21
|
+
if (!claimHarnessGovernanceLoad("harness-subagent-submit", MODULE_URL))
|
|
22
|
+
return;
|
|
65
23
|
if (process.env.PI_HARNESS_SUBPROCESS !== "1") {
|
|
66
24
|
return;
|
|
67
25
|
}
|
|
68
26
|
|
|
69
|
-
const
|
|
27
|
+
const packageRoot = getHarnessPackageRoot(MODULE_URL);
|
|
28
|
+
registerHarnessSubagentSubmitTools(pi, packageRoot);
|
|
70
29
|
|
|
71
|
-
pi.on("tool_call", async (event) => {
|
|
30
|
+
pi.on("tool_call", async (event, ctx) => {
|
|
72
31
|
if (!event.toolName.startsWith("submit_")) return undefined;
|
|
73
|
-
|
|
74
|
-
if (!subprocessOk) {
|
|
32
|
+
if (!isSubprocessHarnessSubmit()) {
|
|
75
33
|
return {
|
|
76
34
|
block: true,
|
|
77
35
|
reason:
|
|
78
36
|
"harness-subagent-submit: submit_* tools are only available in harness subagent subprocesses.",
|
|
79
37
|
};
|
|
80
38
|
}
|
|
81
|
-
const { agentId } =
|
|
39
|
+
const { agentId } = resolveHarnessSubmitRunContext(packageRoot);
|
|
82
40
|
if (!agentId) {
|
|
83
41
|
return {
|
|
84
42
|
block: true,
|
|
@@ -86,118 +44,32 @@ export default function harnessSubagentSubmit(pi: ExtensionAPI) {
|
|
|
86
44
|
"harness-subagent-submit: HARNESS_AGENT_ID is required for submit tools.",
|
|
87
45
|
};
|
|
88
46
|
}
|
|
89
|
-
const decision = evaluateHarnessSubagentToolCall(
|
|
90
|
-
event.toolName,
|
|
91
|
-
event.input as Record<string, unknown>,
|
|
92
|
-
agentId,
|
|
93
|
-
);
|
|
94
|
-
if (decision.action === "block") {
|
|
95
|
-
return { block: true, reason: decision.reason };
|
|
96
|
-
}
|
|
97
|
-
return undefined;
|
|
98
|
-
});
|
|
99
47
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
isError: true,
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
const { projectRoot, specsDir, runId, runDirEnv, agentId } =
|
|
120
|
-
resolveRunContext();
|
|
121
|
-
if (!spec.agents.includes(agentId)) {
|
|
122
|
-
return {
|
|
123
|
-
content: [
|
|
124
|
-
{
|
|
125
|
-
type: "text",
|
|
126
|
-
text: `${spec.toolName} is not allowed for agent ${agentId}`,
|
|
127
|
-
},
|
|
128
|
-
],
|
|
129
|
-
details: { agentId, tool: spec.toolName },
|
|
130
|
-
isError: true,
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
const runResolved = await resolveGuardedRunDir({
|
|
134
|
-
projectRoot,
|
|
135
|
-
runId,
|
|
136
|
-
runDirEnv,
|
|
137
|
-
});
|
|
138
|
-
if (!runResolved.ok) {
|
|
139
|
-
return {
|
|
140
|
-
content: [{ type: "text", text: runResolved.error }],
|
|
141
|
-
details: {},
|
|
142
|
-
isError: true,
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
const loaded = await loadSubmitDocument({
|
|
146
|
-
projectRoot,
|
|
147
|
-
runDir: runResolved.runDir,
|
|
148
|
-
document: (params as { document?: Record<string, unknown> }).document,
|
|
149
|
-
source_path: (params as { source_path?: string }).source_path,
|
|
150
|
-
});
|
|
151
|
-
if (!loaded.ok) {
|
|
152
|
-
return {
|
|
153
|
-
content: [
|
|
154
|
-
{
|
|
155
|
-
type: "text",
|
|
156
|
-
text: `Validation failed:\n${loaded.validation_errors.join("\n")}`,
|
|
157
|
-
},
|
|
158
|
-
],
|
|
159
|
-
isError: true,
|
|
160
|
-
details: loaded,
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
const result = await executeSubmitPipeline({
|
|
164
|
-
projectRoot,
|
|
165
|
-
specsDir,
|
|
166
|
-
spec,
|
|
167
|
-
agentId,
|
|
168
|
-
document: loaded.document,
|
|
169
|
-
runId,
|
|
170
|
-
runDirEnv,
|
|
171
|
-
});
|
|
172
|
-
if (!result.ok) {
|
|
173
|
-
return {
|
|
174
|
-
content: [
|
|
175
|
-
{
|
|
176
|
-
type: "text",
|
|
177
|
-
text: `Validation failed:\n${(result.validation_errors ?? []).join("\n")}`,
|
|
178
|
-
},
|
|
179
|
-
],
|
|
180
|
-
isError: true,
|
|
181
|
-
details: result,
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
const lines = [`ok: wrote ${result.artifact_path}`];
|
|
185
|
-
if (result.lane_result?.messenger_posted) {
|
|
186
|
-
lines.push("messenger updated");
|
|
187
|
-
}
|
|
188
|
-
if (result.human_required) {
|
|
189
|
-
lines.push("human_required: parent must call ask_user");
|
|
190
|
-
}
|
|
191
|
-
return {
|
|
192
|
-
content: [{ type: "text", text: lines.join("\n") }],
|
|
193
|
-
details: result as unknown,
|
|
194
|
-
};
|
|
48
|
+
return evaluateAgtHarnessToolCall({
|
|
49
|
+
moduleUrl: MODULE_URL,
|
|
50
|
+
toolName: event.toolName,
|
|
51
|
+
toolInput: event.input as Record<string, unknown>,
|
|
52
|
+
policyState: {
|
|
53
|
+
phase:
|
|
54
|
+
(process.env.HARNESS_SUBAGENT_PHASE_HINT as
|
|
55
|
+
| "plan"
|
|
56
|
+
| "execute"
|
|
57
|
+
| "evaluate"
|
|
58
|
+
| "adversary"
|
|
59
|
+
| "merge") ?? "plan",
|
|
60
|
+
approvedPlan: true,
|
|
61
|
+
planId: null,
|
|
62
|
+
aborted: false,
|
|
63
|
+
budgetBypass: false,
|
|
195
64
|
},
|
|
65
|
+
entries: ctx.sessionManager.getEntries(),
|
|
66
|
+
sessionId: ctx.sessionManager.getSessionId(),
|
|
67
|
+
projectRoot: ctx.cwd,
|
|
196
68
|
});
|
|
197
|
-
}
|
|
69
|
+
});
|
|
198
70
|
}
|
|
199
71
|
|
|
200
|
-
/** Absolute path to the subprocess submit extension (
|
|
72
|
+
/** Absolute path to the subprocess submit extension (legacy standalone). */
|
|
201
73
|
export function harnessSubagentSubmitExtensionPath(
|
|
202
74
|
packageRoot: string,
|
|
203
75
|
): string {
|
|
@@ -6,18 +6,18 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
9
|
-
import {
|
|
9
|
+
import { claimHarnessGovernanceLoad } from "../lib/extension-load-guard.js";
|
|
10
10
|
|
|
11
11
|
// @ts-expect-error pi extensions run as ESM
|
|
12
12
|
const MODULE_URL = import.meta.url;
|
|
13
13
|
|
|
14
14
|
async function loadHarnessSubagents(): Promise<(pi: ExtensionAPI) => void> {
|
|
15
|
-
if (!
|
|
15
|
+
if (!claimHarnessGovernanceLoad("harness-subagents", MODULE_URL)) {
|
|
16
16
|
return () => {};
|
|
17
17
|
}
|
|
18
|
-
const { getHarnessPackageRoot } = await import("
|
|
18
|
+
const { getHarnessPackageRoot } = await import("../lib/harness-paths.js");
|
|
19
19
|
const { createHarnessSubagentsExtension } = await import(
|
|
20
|
-
"
|
|
20
|
+
"../lib/harness-subagents-bridge.js"
|
|
21
21
|
);
|
|
22
22
|
return createHarnessSubagentsExtension(getHarnessPackageRoot(MODULE_URL));
|
|
23
23
|
}
|
|
@@ -13,7 +13,8 @@ import {
|
|
|
13
13
|
captureHarnessEvent,
|
|
14
14
|
type HarnessPostHogEventName,
|
|
15
15
|
shutdownHarnessPostHog,
|
|
16
|
-
} from "
|
|
16
|
+
} from "../lib/harness-posthog.js";
|
|
17
|
+
import { isHarnessProjectEnabled } from "../lib/harness-project-config.js";
|
|
17
18
|
|
|
18
19
|
type HarnessPhase = "plan" | "execute" | "evaluate" | "adversary" | "merge";
|
|
19
20
|
|
|
@@ -338,6 +339,7 @@ function mapCustomEntry(
|
|
|
338
339
|
}
|
|
339
340
|
|
|
340
341
|
export default function harnessTelemetry(pi: ExtensionAPI) {
|
|
342
|
+
if (!isHarnessProjectEnabled()) return;
|
|
341
343
|
const flushedHashes = new Set<string>();
|
|
342
344
|
let lastPolicyPhase: HarnessPhase | null = null;
|
|
343
345
|
|
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
6
6
|
import { Type } from "@sinclair/typebox";
|
|
7
|
-
import {
|
|
7
|
+
import { claimHarnessGovernanceLoad } from "../lib/extension-load-guard.js";
|
|
8
8
|
import {
|
|
9
9
|
harnessWebContextLine,
|
|
10
10
|
readTextExcerpt,
|
|
11
11
|
runHarnessWeb,
|
|
12
12
|
summarizeSearchJson,
|
|
13
|
-
} from "
|
|
13
|
+
} from "../lib/harness-web/run-cli.js";
|
|
14
14
|
|
|
15
15
|
// @ts-expect-error pi extensions run as ESM
|
|
16
16
|
const MODULE_URL = import.meta.url;
|
|
@@ -98,7 +98,7 @@ function sessionCwd(ctx: { cwd?: string }): string {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
export default function harnessWebTools(pi: ExtensionAPI) {
|
|
101
|
-
if (!
|
|
101
|
+
if (!claimHarnessGovernanceLoad("harness-web-tools", MODULE_URL)) return;
|
|
102
102
|
pi.on("before_agent_start", async (event) => {
|
|
103
103
|
return {
|
|
104
104
|
systemPrompt: `${event.systemPrompt}\n\n${harnessWebContextLine()}`,
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { randomUUID } from "node:crypto";
|
|
9
9
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
10
|
+
import { isHarnessProjectEnabled } from "../lib/harness-project-config.js";
|
|
10
11
|
import { getRunIdFromSession } from "../lib/harness-run-context.js";
|
|
11
12
|
|
|
12
13
|
type HarnessPhase = "plan" | "execute" | "evaluate" | "adversary" | "merge";
|
|
@@ -87,6 +88,7 @@ function getRunId(ctx: {
|
|
|
87
88
|
}
|
|
88
89
|
|
|
89
90
|
export default function observationBus(pi: ExtensionAPI) {
|
|
91
|
+
if (!isHarnessProjectEnabled()) return;
|
|
90
92
|
const seen = new Set<string>();
|
|
91
93
|
|
|
92
94
|
pi.on("agent_end", async (_event, ctx) => {
|
|
@@ -9,10 +9,9 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
} from "../lib/harness-context-mode-policy.js";
|
|
12
|
+
import { isHarnessAgtPolicyEnabled } from "../lib/agt/config.js";
|
|
13
|
+
import { evaluateAgtHarnessToolCall } from "../lib/harness-agt-tool-guard.js";
|
|
14
|
+
import { isHarnessProjectEnabled } from "../lib/harness-project-config.js";
|
|
16
15
|
import {
|
|
17
16
|
extractWritePathFromToolInput,
|
|
18
17
|
getLatestRunContext,
|
|
@@ -31,7 +30,7 @@ import {
|
|
|
31
30
|
userVisiblePromptSlice,
|
|
32
31
|
validatePlanPacket,
|
|
33
32
|
} from "../lib/harness-run-context.js";
|
|
34
|
-
import { bootstrapHarnessSubprocessFromEnv } from "
|
|
33
|
+
import { bootstrapHarnessSubprocessFromEnv } from "../lib/harness-subprocess-bootstrap.js";
|
|
35
34
|
|
|
36
35
|
type HarnessPhase = "plan" | "execute" | "evaluate" | "adversary" | "merge";
|
|
37
36
|
|
|
@@ -60,6 +59,9 @@ const PHASE_ORDER: HarnessPhase[] = [
|
|
|
60
59
|
"merge",
|
|
61
60
|
];
|
|
62
61
|
|
|
62
|
+
// @ts-expect-error pi extensions run as ESM
|
|
63
|
+
const MODULE_URL = import.meta.url;
|
|
64
|
+
|
|
63
65
|
const MUTATING_TOOLS = new Set(["write", "edit"]);
|
|
64
66
|
|
|
65
67
|
function nowIso(): string {
|
|
@@ -126,6 +128,7 @@ function getLatestPolicyStateFull(ctx: {
|
|
|
126
128
|
}
|
|
127
129
|
|
|
128
130
|
export default function policyGate(pi: ExtensionAPI) {
|
|
131
|
+
if (!isHarnessProjectEnabled()) return;
|
|
129
132
|
let state = defaultState();
|
|
130
133
|
|
|
131
134
|
const appendPolicyState = (next: PolicyState): void => {
|
|
@@ -248,6 +251,19 @@ export default function policyGate(pi: ExtensionAPI) {
|
|
|
248
251
|
const entries = ctx.sessionManager.getEntries();
|
|
249
252
|
const projectRoot = process.cwd();
|
|
250
253
|
const sessionId = ctx.sessionManager.getSessionId();
|
|
254
|
+
|
|
255
|
+
if (isHarnessAgtPolicyEnabled()) {
|
|
256
|
+
return evaluateAgtHarnessToolCall({
|
|
257
|
+
moduleUrl: MODULE_URL,
|
|
258
|
+
toolName: event.toolName,
|
|
259
|
+
toolInput: event.input as Record<string, unknown>,
|
|
260
|
+
policyState: state,
|
|
261
|
+
entries,
|
|
262
|
+
sessionId,
|
|
263
|
+
projectRoot,
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
251
267
|
const runCtx = getLatestRunContext(entries);
|
|
252
268
|
|
|
253
269
|
if (MUTATING_TOOLS.has(event.toolName)) {
|
|
@@ -272,6 +288,9 @@ export default function policyGate(pi: ExtensionAPI) {
|
|
|
272
288
|
|
|
273
289
|
if (event.toolName === "bash") {
|
|
274
290
|
const command = String(event.input.command ?? "");
|
|
291
|
+
const { isMutatingBash } = await import(
|
|
292
|
+
"../lib/harness-context-mode-policy.js"
|
|
293
|
+
);
|
|
275
294
|
if (!isMutatingBash(command)) return undefined;
|
|
276
295
|
if (state.aborted) {
|
|
277
296
|
return {
|
|
@@ -288,6 +307,9 @@ export default function policyGate(pi: ExtensionAPI) {
|
|
|
288
307
|
}
|
|
289
308
|
}
|
|
290
309
|
|
|
310
|
+
const { evaluateContextModeMutation } = await import(
|
|
311
|
+
"../lib/harness-context-mode-policy.js"
|
|
312
|
+
);
|
|
291
313
|
const ctxDecision = evaluateContextModeMutation(
|
|
292
314
|
event.toolName,
|
|
293
315
|
event.input as Record<string, unknown>,
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { appendFile, mkdir } from "node:fs/promises";
|
|
9
9
|
import { join } from "node:path";
|
|
10
10
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
11
|
+
import { isHarnessProjectEnabled } from "../lib/harness-project-config.js";
|
|
11
12
|
|
|
12
13
|
type HarnessPhase = "plan" | "execute" | "evaluate" | "adversary" | "merge";
|
|
13
14
|
|
|
@@ -15,12 +16,13 @@ const INCIDENTS_DIR = join(process.cwd(), ".pi", "harness", "incidents");
|
|
|
15
16
|
const INCIDENT_FILE = join(INCIDENTS_DIR, "review-integrity.jsonl");
|
|
16
17
|
|
|
17
18
|
const REVIEW_SUBAGENT_TYPES = new Set([
|
|
18
|
-
"harness/evaluator",
|
|
19
|
-
"harness/adversary",
|
|
20
|
-
"harness/tie-breaker",
|
|
19
|
+
"harness/reviewing/evaluator",
|
|
20
|
+
"harness/reviewing/adversary",
|
|
21
|
+
"harness/reviewing/tie-breaker",
|
|
21
22
|
]);
|
|
22
23
|
|
|
23
|
-
const EXECUTOR_SUBAGENT_TYPE = "harness/executor";
|
|
24
|
+
const EXECUTOR_SUBAGENT_TYPE = "harness/running/executor";
|
|
25
|
+
const PLANNING_SUBAGENT_PREFIX = "harness/planning/";
|
|
24
26
|
|
|
25
27
|
interface IsolationState {
|
|
26
28
|
executorSessionId: string | null;
|
|
@@ -138,6 +140,70 @@ function agentsFromSubagentInput(
|
|
|
138
140
|
return names;
|
|
139
141
|
}
|
|
140
142
|
|
|
143
|
+
function latestCustomData(
|
|
144
|
+
entries: SessionEntryLike[],
|
|
145
|
+
customType: string,
|
|
146
|
+
): Record<string, unknown> | null {
|
|
147
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
148
|
+
const entry = entries[i];
|
|
149
|
+
if (entry.type !== "custom" || entry.customType !== customType) continue;
|
|
150
|
+
return entry.data && typeof entry.data === "object" ? entry.data : null;
|
|
151
|
+
}
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function collectStrings(value: unknown, depth = 0): string[] {
|
|
156
|
+
if (depth > 5 || value == null) return [];
|
|
157
|
+
if (typeof value === "string") return [value];
|
|
158
|
+
if (Array.isArray(value)) {
|
|
159
|
+
return value.flatMap((item) => collectStrings(item, depth + 1));
|
|
160
|
+
}
|
|
161
|
+
if (typeof value === "object") {
|
|
162
|
+
return Object.values(value).flatMap((item) =>
|
|
163
|
+
collectStrings(item, depth + 1),
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
return [];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function hasPlanReviseRecommendation(entries: unknown[]): boolean {
|
|
170
|
+
const typedEntries = entries as SessionEntryLike[];
|
|
171
|
+
const runContext = latestCustomData(typedEntries, "harness-run-context");
|
|
172
|
+
const text = collectStrings({
|
|
173
|
+
next_recommended_command: runContext?.next_recommended_command,
|
|
174
|
+
last_completed_step: runContext?.last_completed_step,
|
|
175
|
+
last_outcome: runContext?.last_outcome,
|
|
176
|
+
phase: runContext?.phase,
|
|
177
|
+
})
|
|
178
|
+
.join("\n")
|
|
179
|
+
.toLowerCase();
|
|
180
|
+
|
|
181
|
+
return text.includes("/harness-plan") && text.includes("revise");
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export function isPlanRevisePlanningSubagent(input: {
|
|
185
|
+
agents: string[];
|
|
186
|
+
entries: unknown[];
|
|
187
|
+
toolInput?: Record<string, unknown>;
|
|
188
|
+
}): boolean {
|
|
189
|
+
if (input.agents.length === 0) return false;
|
|
190
|
+
if (
|
|
191
|
+
!input.agents.every((agent) => agent.startsWith(PLANNING_SUBAGENT_PREFIX))
|
|
192
|
+
) {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
if (hasPlanReviseRecommendation(input.entries)) return true;
|
|
196
|
+
|
|
197
|
+
const toolText = collectStrings(input.toolInput).join("\n").toLowerCase();
|
|
198
|
+
return (
|
|
199
|
+
toolText.includes("harness-plan") &&
|
|
200
|
+
(toolText.includes("mode: revise") ||
|
|
201
|
+
toolText.includes("mode=revise") ||
|
|
202
|
+
toolText.includes("--mode revise") ||
|
|
203
|
+
toolText.includes("--mode=revise"))
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
|
|
141
207
|
async function appendIncident(payload: Record<string, unknown>): Promise<void> {
|
|
142
208
|
await mkdir(INCIDENTS_DIR, { recursive: true });
|
|
143
209
|
await appendFile(
|
|
@@ -148,6 +214,7 @@ async function appendIncident(payload: Record<string, unknown>): Promise<void> {
|
|
|
148
214
|
}
|
|
149
215
|
|
|
150
216
|
export default function reviewIntegrity(pi: ExtensionAPI) {
|
|
217
|
+
if (!isHarnessProjectEnabled()) return;
|
|
151
218
|
let state: IsolationState = {
|
|
152
219
|
executorSessionId: null,
|
|
153
220
|
violationActive: false,
|
|
@@ -175,7 +242,10 @@ export default function reviewIntegrity(pi: ExtensionAPI) {
|
|
|
175
242
|
const phase = getPhase(ctx);
|
|
176
243
|
const currentSessionId = ctx.sessionManager.getSessionId();
|
|
177
244
|
const inReview = phase === "evaluate" || phase === "adversary";
|
|
178
|
-
if (
|
|
245
|
+
if (
|
|
246
|
+
!inReview ||
|
|
247
|
+
hasPlanReviseRecommendation(ctx.sessionManager.getEntries())
|
|
248
|
+
) {
|
|
179
249
|
state.violationActive = false;
|
|
180
250
|
state.updatedAt = nowIso();
|
|
181
251
|
persist();
|
|
@@ -201,7 +271,7 @@ export default function reviewIntegrity(pi: ExtensionAPI) {
|
|
|
201
271
|
customType: "harness-review-integrity-hint",
|
|
202
272
|
display: true,
|
|
203
273
|
content: [
|
|
204
|
-
"Review phase in executor session: spawn harness/evaluator or harness/adversary via subagent (isolated subprocess).",
|
|
274
|
+
"Review phase in executor session: spawn harness/reviewing/evaluator or harness/reviewing/adversary via subagent (isolated subprocess).",
|
|
205
275
|
"Do not run review checks directly in this session.",
|
|
206
276
|
].join("\n"),
|
|
207
277
|
},
|
|
@@ -210,9 +280,8 @@ export default function reviewIntegrity(pi: ExtensionAPI) {
|
|
|
210
280
|
|
|
211
281
|
pi.on("tool_call", async (event, ctx) => {
|
|
212
282
|
if (event.toolName === "subagent") {
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
);
|
|
283
|
+
const toolInput = event.input as Record<string, unknown> | undefined;
|
|
284
|
+
const agents = agentsFromSubagentInput(toolInput);
|
|
216
285
|
if (agents.includes(EXECUTOR_SUBAGENT_TYPE)) {
|
|
217
286
|
state.executorSessionId = ctx.sessionManager.getSessionId();
|
|
218
287
|
state.violationActive = false;
|
|
@@ -226,6 +295,18 @@ export default function reviewIntegrity(pi: ExtensionAPI) {
|
|
|
226
295
|
persist();
|
|
227
296
|
return undefined;
|
|
228
297
|
}
|
|
298
|
+
if (
|
|
299
|
+
isPlanRevisePlanningSubagent({
|
|
300
|
+
agents,
|
|
301
|
+
entries: ctx.sessionManager.getEntries(),
|
|
302
|
+
toolInput,
|
|
303
|
+
})
|
|
304
|
+
) {
|
|
305
|
+
state.violationActive = false;
|
|
306
|
+
state.updatedAt = nowIso();
|
|
307
|
+
persist();
|
|
308
|
+
return undefined;
|
|
309
|
+
}
|
|
229
310
|
}
|
|
230
311
|
|
|
231
312
|
if (!state.violationActive) return undefined;
|
|
@@ -237,7 +318,7 @@ export default function reviewIntegrity(pi: ExtensionAPI) {
|
|
|
237
318
|
reason:
|
|
238
319
|
"direct tool use in review phase while sharing executor session context",
|
|
239
320
|
mitigation:
|
|
240
|
-
"spawn harness/evaluator or harness/adversary via subagent instead",
|
|
321
|
+
"spawn harness/reviewing/evaluator or harness/reviewing/adversary via subagent instead",
|
|
241
322
|
});
|
|
242
323
|
|
|
243
324
|
return {
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
import { spawn } from "node:child_process";
|
|
6
6
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
7
|
-
import { resolveHarnessScript } from "
|
|
7
|
+
import { resolveHarnessScript } from "../lib/harness-paths.js";
|
|
8
|
+
import { isHarnessProjectEnabled } from "../lib/harness-project-config.js";
|
|
8
9
|
|
|
9
10
|
function resolveSyncScript(): string {
|
|
10
11
|
return resolveHarnessScript(
|
|
@@ -36,6 +37,7 @@ function runSync(args: string[]): Promise<{ code: number; output: string }> {
|
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
export default function sentruxRulesSync(pi: ExtensionAPI) {
|
|
40
|
+
if (!isHarnessProjectEnabled()) return;
|
|
39
41
|
pi.on("session_start", async () => {
|
|
40
42
|
const { code, output } = await runSync(["--check"]);
|
|
41
43
|
if (code !== 0) {
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subprocess governance bundle: AGT policy on all tool_call + harness submit_* tools.
|
|
3
|
+
* Loaded via `pi --no-extensions -e subagent-governance.ts` for every subagent spawn.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
8
|
+
import {
|
|
9
|
+
getAgentKind,
|
|
10
|
+
harnessSubagentPhaseHint,
|
|
11
|
+
} from "../lib/agents-policy.mjs";
|
|
12
|
+
import { evaluateAgtToolCall } from "../lib/agt-tool-guard.js";
|
|
13
|
+
import { claimSubagentGovernanceLoad } from "../lib/extension-load-guard.js";
|
|
14
|
+
import { getHarnessPackageRoot } from "../lib/harness-paths.js";
|
|
15
|
+
import { registerHarnessSubagentSubmitTools } from "../lib/harness-subagent-submit-register.js";
|
|
16
|
+
|
|
17
|
+
// @ts-expect-error pi extensions run as ESM
|
|
18
|
+
const MODULE_URL = import.meta.url;
|
|
19
|
+
|
|
20
|
+
function policyStateFromEnv(packageRoot: string, projectRoot: string) {
|
|
21
|
+
const agentId = process.env.HARNESS_AGENT_ID?.trim() ?? "unknown";
|
|
22
|
+
const phase =
|
|
23
|
+
(process.env.HARNESS_SUBAGENT_PHASE_HINT?.trim() as
|
|
24
|
+
| "plan"
|
|
25
|
+
| "execute"
|
|
26
|
+
| "evaluate"
|
|
27
|
+
| "adversary"
|
|
28
|
+
| "merge") ??
|
|
29
|
+
(harnessSubagentPhaseHint(packageRoot, projectRoot, agentId) as
|
|
30
|
+
| "plan"
|
|
31
|
+
| "execute"
|
|
32
|
+
| "evaluate"
|
|
33
|
+
| "adversary"
|
|
34
|
+
| "merge"
|
|
35
|
+
| null) ??
|
|
36
|
+
"plan";
|
|
37
|
+
return {
|
|
38
|
+
phase,
|
|
39
|
+
approvedPlan: phase === "execute" || phase === "merge",
|
|
40
|
+
planId: process.env.HARNESS_PLAN_ID?.trim() || null,
|
|
41
|
+
aborted: false,
|
|
42
|
+
budgetBypass: false,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function subagentGovernanceExtensionPath(packageRoot: string): string {
|
|
47
|
+
return join(packageRoot, ".pi", "extensions", "subagent-governance.ts");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** @deprecated Use subagentGovernanceExtensionPath */
|
|
51
|
+
export function harnessSubagentGovernanceExtensionPath(
|
|
52
|
+
packageRoot: string,
|
|
53
|
+
): string {
|
|
54
|
+
return subagentGovernanceExtensionPath(packageRoot);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export default function subagentGovernance(pi: ExtensionAPI) {
|
|
58
|
+
if (!claimSubagentGovernanceLoad("subagent-governance", MODULE_URL)) return;
|
|
59
|
+
if (process.env.PI_HARNESS_SUBPROCESS !== "1") {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const packageRoot = getHarnessPackageRoot(MODULE_URL);
|
|
64
|
+
const projectRoot = process.env.HARNESS_PROJECT_ROOT?.trim() || process.cwd();
|
|
65
|
+
const agentId = process.env.HARNESS_AGENT_ID?.trim() ?? "unknown";
|
|
66
|
+
|
|
67
|
+
if (agentId.startsWith("harness/")) {
|
|
68
|
+
registerHarnessSubagentSubmitTools(pi, packageRoot);
|
|
69
|
+
const kind = getAgentKind(packageRoot, projectRoot, agentId);
|
|
70
|
+
process.env.HARNESS_SUBAGENT_PHASE_HINT =
|
|
71
|
+
kind === "executor"
|
|
72
|
+
? "execute"
|
|
73
|
+
: kind === "evaluator"
|
|
74
|
+
? "evaluate"
|
|
75
|
+
: kind === "adversary"
|
|
76
|
+
? "adversary"
|
|
77
|
+
: "plan";
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
pi.on("tool_call", async (event, ctx) => {
|
|
81
|
+
const state = policyStateFromEnv(packageRoot, projectRoot);
|
|
82
|
+
return evaluateAgtToolCall({
|
|
83
|
+
moduleUrl: MODULE_URL,
|
|
84
|
+
toolName: event.toolName,
|
|
85
|
+
toolInput: (event.input ?? {}) as Record<string, unknown>,
|
|
86
|
+
policyState: state,
|
|
87
|
+
entries: ctx.sessionManager.getEntries(),
|
|
88
|
+
sessionId: ctx.sessionManager.getSessionId(),
|
|
89
|
+
projectRoot: ctx.cwd,
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
}
|