devrites 3.0.7 → 3.1.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/CHANGELOG.md +12 -0
- package/README.md +67 -47
- package/SECURITY.md +31 -29
- package/docs/adr/0001-go-engine-as-control-plane.md +1 -1
- package/docs/adr/0002-dual-host-harness.md +1 -1
- package/docs/adr/0004-state-schema-phases-sections.md +1 -2
- package/docs/adr/0006-clock-seam-and-engine-ci-gates.md +3 -4
- package/docs/adr/0009-prebuild-decision-coverage-and-readiness.md +67 -0
- package/docs/adr/0010-agent-first-fresh-context-orchestration.md +71 -0
- package/docs/adr/0011-define-plan-transition-rights.md +28 -0
- package/docs/adr/README.md +3 -0
- package/docs/agents/triage-labels.md +7 -7
- package/docs/architecture.md +157 -140
- package/docs/cli.md +41 -12
- package/docs/command-map.md +49 -35
- package/docs/engine/agent-contract.md +92 -15
- package/docs/engine/commands.md +242 -72
- package/docs/engine/state-schema.md +52 -23
- package/docs/engine/workspace-schema.md +94 -15
- package/docs/extensions.md +1 -1
- package/docs/flow.md +80 -50
- package/docs/harness-compliance.md +29 -5
- package/docs/orchestration.md +107 -79
- package/docs/quick-reference.md +7 -3
- package/docs/release.md +4 -3
- package/docs/skills.md +64 -38
- package/docs/usage.md +57 -38
- package/engine/cmd/releasepack/main.go +219 -0
- package/engine/cmd/releasepack/main_test.go +170 -0
- package/engine/commands.go +170 -23
- package/engine/git_guard.go +187 -0
- package/engine/git_guard_test.go +283 -0
- package/engine/hookpolicy.go +53 -55
- package/engine/hookpolicy_test.go +91 -1
- package/engine/hooks.go +296 -75
- package/engine/hooks_events_test.go +276 -6
- package/engine/hooks_workspace.go +640 -159
- package/engine/internal/devritespaths/paths.go +65 -10
- package/engine/internal/devritespaths/paths_test.go +110 -0
- package/engine/internal/doctor/doctor.go +153 -23
- package/engine/internal/doctor/doctor_test.go +74 -0
- package/engine/internal/forge/forge.go +940 -0
- package/engine/internal/forge/forge_test.go +576 -0
- package/engine/internal/forge/git.go +245 -0
- package/engine/internal/forge/liveness_unix.go +48 -0
- package/engine/internal/forge/liveness_windows.go +67 -0
- package/engine/internal/forge/manifest.go +402 -0
- package/engine/internal/gate/gate.go +90 -71
- package/engine/internal/gate/gate_test.go +71 -2
- package/engine/internal/harness/compliance.go +18 -24
- package/engine/internal/harness/harness.go +37 -44
- package/engine/internal/harness/harness_test.go +21 -5
- package/engine/internal/install/install.go +486 -38
- package/engine/internal/install/install_test.go +383 -10
- package/engine/internal/iohooks/iohooks.go +350 -59
- package/engine/internal/iohooks/iohooks_test.go +421 -1
- package/engine/internal/lib/buildreadiness.go +35 -18
- package/engine/internal/lib/clarifyreturn.go +91 -0
- package/engine/internal/lib/clarifyreturn_test.go +123 -0
- package/engine/internal/lib/context.go +54 -15
- package/engine/internal/lib/cursor_compat_test.go +8 -0
- package/engine/internal/lib/extensions.go +2 -3
- package/engine/internal/lib/gitauthority.go +601 -0
- package/engine/internal/lib/gitauthority_test.go +346 -0
- package/engine/internal/lib/jsonout.go +25 -11
- package/engine/internal/lib/jsonout_test.go +16 -0
- package/engine/internal/lib/lanes.go +14 -8
- package/engine/internal/lib/observability_test.go +358 -0
- package/engine/internal/lib/packageexistence.go +151 -35
- package/engine/internal/lib/packageexistence_test.go +163 -0
- package/engine/internal/lib/progress.go +11 -9
- package/engine/internal/lib/provenance.go +462 -0
- package/engine/internal/lib/provenance_test.go +154 -0
- package/engine/internal/lib/readiness_contract.json +111 -0
- package/engine/internal/lib/readinessartifact.go +510 -0
- package/engine/internal/lib/readinessartifact_test.go +321 -0
- package/engine/internal/lib/reconcile.go +712 -88
- package/engine/internal/lib/reconcile_test.go +335 -16
- package/engine/internal/lib/recoveryattempts.go +298 -0
- package/engine/internal/lib/recoveryattempts_test.go +215 -0
- package/engine/internal/lib/resolve.go +23 -19
- package/engine/internal/lib/runbook_context_test.go +20 -0
- package/engine/internal/lib/session.go +701 -9
- package/engine/internal/lib/session_test.go +80 -13
- package/engine/internal/lib/testintegrity.go +33 -37
- package/engine/internal/lib/testintegrity_test.go +63 -1
- package/engine/internal/migrate/migrate.go +81 -1
- package/engine/internal/migrate/migrate_test.go +22 -1
- package/engine/internal/reason/reason.go +180 -0
- package/engine/internal/reason/reason_test.go +35 -0
- package/engine/internal/rootfacts/facts.go +466 -0
- package/engine/internal/rootfacts/facts_test.go +306 -0
- package/engine/internal/safepath/safepath.go +55 -0
- package/engine/internal/safepath/safepath_test.go +69 -0
- package/engine/internal/safepath/safepath_windows_test.go +26 -0
- package/engine/internal/state/clarify_transition.go +165 -0
- package/engine/internal/state/clarify_transition_test.go +130 -0
- package/engine/internal/state/cmd/workflowmanifest/main.go +12 -8
- package/engine/internal/state/cursor.go +58 -0
- package/engine/internal/state/cursor_test.go +42 -1
- package/engine/internal/state/feature.go +35 -48
- package/engine/internal/state/schema.go +90 -37
- package/engine/internal/state/snapshot.go +18 -2
- package/engine/internal/state/state_test.go +187 -7
- package/engine/internal/state/status.go +48 -11
- package/engine/internal/state/workflow_manifest.json +231 -50
- package/engine/internal/toolpolicy/classifier.go +533 -0
- package/engine/internal/toolpolicy/classifier_test.go +424 -0
- package/engine/internal/toolpolicy/git.go +616 -0
- package/engine/internal/toolpolicy/scanner.go +382 -0
- package/engine/main.go +160 -77
- package/engine/observability_cli_test.go +52 -0
- package/engine/root_routing_test.go +277 -0
- package/engine/testdata/golden/TestParityBuildReadiness/arg=approved.golden +1 -1
- package/engine/testdata/golden/TestParityBuildReadiness/arg=emptystatus.golden +1 -1
- package/engine/testdata/golden/TestParityBuildReadiness/arg=noclarify.golden +1 -0
- package/engine/testdata/golden/TestParityBuildReadiness/arg=novet.golden +1 -0
- package/engine/testdata/golden/TestParityBuildReadiness/arg=stalevet.golden +1 -0
- package/engine/testdata/golden/TestParityBuildReadiness/arg=trailhash.golden +1 -1
- package/engine/testdata/golden/TestParityBuildReadiness/arg=trailpipe.golden +1 -1
- package/engine/testdata/golden/TestParityBuildReadiness/arg=vetnotready.golden +1 -0
- package/engine/testdata/golden/TestParityProgress/arg=allbuilt.golden +1 -1
- package/engine/testdata/golden/TestParityProgress/arg=done.golden +1 -1
- package/engine/testdata/golden/TestParityProgress/arg=mid.golden +1 -1
- package/engine/testdata/golden/TestParityProgress/arg=nophase.golden +1 -1
- package/engine/testdata/golden/TestParityProgress/arg=noslice.golden +1 -1
- package/engine/testdata/golden/TestParityProgress/arg=plan.golden +1 -1
- package/engine/testdata/golden/TestParityProgress/arg=seal.golden +1 -1
- package/engine/testdata/golden/TestParityReconcile/check-clean.golden +1 -1
- package/engine/testdata/golden/TestParityReconcile/inline-fallback.golden +1 -0
- package/engine/testdata/golden/TestParityReconcile/snapshot-no-allowlist.golden +1 -0
- package/engine/testdata/golden/TestParityWrightScope/devrites-edit-denied.golden +2 -0
- package/engine/testdata/golden/TestParityWrightScope/out-of-scope-enforce-denies.golden +1 -1
- package/engine/tests/adr_0011_define_plan_test.go +30 -0
- package/engine/tests/budget_test.go +19 -8
- package/engine/tests/concurrency_cli_test.go +7 -1
- package/engine/tests/doctor_cli_test.go +148 -2
- package/engine/tests/forge_cli_test.go +463 -0
- package/engine/tests/gate_test.go +63 -8
- package/engine/tests/hook_test.go +260 -8
- package/engine/tests/hooks_io_test.go +94 -3
- package/engine/tests/json_contract_test.go +127 -2
- package/engine/tests/migrate_cli_test.go +2 -2
- package/engine/tests/parity_buildreadiness_test.go +141 -10
- package/engine/tests/parity_learnings_test.go +16 -17
- package/engine/tests/parity_reconcile_test.go +20 -17
- package/engine/tests/parity_resolve_test.go +12 -11
- package/engine/tests/parity_test.go +21 -17
- package/pack/.claude/agents/devrites-code-reviewer.md +62 -48
- package/pack/.claude/agents/devrites-devex-reviewer.md +69 -53
- package/pack/.claude/agents/devrites-doubt-reviewer.md +29 -22
- package/pack/.claude/agents/devrites-evidence-scout.md +69 -0
- package/pack/.claude/agents/devrites-forge-judge.md +74 -61
- package/pack/.claude/agents/devrites-frontend-reviewer.md +48 -39
- package/pack/.claude/agents/devrites-performance-reviewer.md +49 -40
- package/pack/.claude/agents/devrites-plan-drafter.md +71 -0
- package/pack/.claude/agents/devrites-plan-reviewer.md +80 -47
- package/pack/.claude/agents/devrites-proof-runner.md +74 -0
- package/pack/.claude/agents/devrites-retrospector.md +48 -45
- package/pack/.claude/agents/devrites-security-auditor.md +46 -36
- package/pack/.claude/agents/devrites-simplifier-reviewer.md +50 -46
- package/pack/.claude/agents/devrites-slice-wright.md +153 -165
- package/pack/.claude/agents/devrites-spec-reviewer.md +34 -32
- package/pack/.claude/agents/devrites-strategy-reviewer.md +63 -34
- package/pack/.claude/agents/devrites-test-analyst.md +40 -30
- package/pack/.claude/settings.json +2 -1
- package/pack/.claude/skills/devrites-audit/SKILL.md +40 -61
- package/pack/.claude/skills/devrites-debug-recovery/SKILL.md +24 -13
- package/pack/.claude/skills/devrites-debug-recovery/reference/build-the-loop.md +24 -21
- package/pack/.claude/skills/devrites-debug-recovery/reference/cleanup-and-classify.md +34 -6
- package/pack/.claude/skills/devrites-debug-recovery/reference/instrumentation.md +2 -2
- package/pack/.claude/skills/devrites-doubt/SKILL.md +25 -17
- package/pack/.claude/skills/devrites-interview/SKILL.md +53 -52
- package/pack/.claude/skills/devrites-lib/SKILL.md +11 -9
- package/pack/.claude/skills/devrites-lib/reference/intent-map.md +3 -2
- package/pack/.claude/skills/devrites-lib/reference/parallel-dispatch.md +82 -137
- package/pack/.claude/skills/devrites-lib/reference/reply-contract.md +8 -1
- package/pack/.claude/skills/devrites-lib/reference/standards/README.md +38 -55
- package/pack/.claude/skills/devrites-lib/reference/standards/afk-hitl.md +53 -27
- package/pack/.claude/skills/devrites-lib/reference/standards/agents.md +198 -190
- package/pack/.claude/skills/devrites-lib/reference/standards/anti-patterns.md +5 -15
- package/pack/.claude/skills/devrites-lib/reference/standards/ci-cd.md +27 -58
- package/pack/.claude/skills/devrites-lib/reference/standards/code-review.md +16 -52
- package/pack/.claude/skills/devrites-lib/reference/standards/coding-style.md +2 -10
- package/pack/.claude/skills/devrites-lib/reference/standards/context-hygiene.md +18 -61
- package/pack/.claude/skills/devrites-lib/reference/standards/core.md +23 -18
- package/pack/.claude/skills/devrites-lib/reference/standards/deprecation.md +17 -57
- package/pack/.claude/skills/devrites-lib/reference/standards/development-workflow.md +4 -33
- package/pack/.claude/skills/devrites-lib/reference/standards/git-workflow.md +4 -20
- package/pack/.claude/skills/devrites-lib/reference/standards/hooks.md +3 -14
- package/pack/.claude/skills/devrites-lib/reference/standards/patterns.md +9 -25
- package/pack/.claude/skills/devrites-lib/reference/standards/performance.md +0 -9
- package/pack/.claude/skills/devrites-lib/reference/standards/principles.md +1 -3
- package/pack/.claude/skills/devrites-lib/reference/standards/security.md +17 -7
- package/pack/.claude/skills/devrites-lib/reference/standards/testing.md +1 -27
- package/pack/.claude/skills/devrites-lib/reference/standards/tooling.md +46 -50
- package/pack/.claude/skills/devrites-lib/reference/workspace-artifact-schema.md +23 -10
- package/pack/.claude/skills/devrites-source-driven/SKILL.md +23 -22
- package/pack/.claude/skills/rite/SKILL.md +8 -6
- package/pack/.claude/skills/rite/reference/menu.md +8 -6
- package/pack/.claude/skills/rite-adopt/SKILL.md +33 -37
- package/pack/.claude/skills/rite-autocomplete/SKILL.md +33 -28
- package/pack/.claude/skills/rite-autocomplete/reference/loop.md +21 -21
- package/pack/.claude/skills/rite-autocomplete/reference/stop-conditions.md +15 -6
- package/pack/.claude/skills/rite-build/SKILL.md +35 -30
- package/pack/.claude/skills/rite-build/reference/afk-discipline.md +38 -38
- package/pack/.claude/skills/rite-build/reference/evidence-standard.md +10 -0
- package/pack/.claude/skills/rite-build/reference/forge.md +186 -156
- package/pack/.claude/skills/rite-build/reference/one-slice-cycle.md +4 -3
- package/pack/.claude/skills/rite-build/reference/phase-contract.md +96 -175
- package/pack/.claude/skills/rite-build/reference/wright-dispatch.md +129 -134
- package/pack/.claude/skills/rite-clarify/SKILL.md +89 -0
- package/pack/.claude/skills/rite-clarify/reference/decision-coverage.md +59 -0
- package/pack/.claude/skills/rite-converge/SKILL.md +35 -25
- package/pack/.claude/skills/rite-define/SKILL.md +57 -32
- package/pack/.claude/skills/rite-define/reference/gates.md +16 -15
- package/pack/.claude/skills/rite-define/reference/plan-template.md +16 -8
- package/pack/.claude/skills/rite-frame/reference/failure-modes.md +22 -24
- package/pack/.claude/skills/rite-plan/SKILL.md +44 -16
- package/pack/.claude/skills/rite-plan/reference/task-breakdown.md +4 -0
- package/pack/.claude/skills/rite-polish/SKILL.md +27 -23
- package/pack/.claude/skills/rite-prototype/SKILL.md +25 -26
- package/pack/.claude/skills/rite-prove/SKILL.md +27 -17
- package/pack/.claude/skills/rite-resolve/SKILL.md +12 -11
- package/pack/.claude/skills/rite-resolve/reference/answer-protocol.md +3 -0
- package/pack/.claude/skills/rite-review/SKILL.md +37 -28
- package/pack/.claude/skills/rite-seal/reference/phase-contract.md +27 -92
- package/pack/.claude/skills/rite-seal/reference/risk-and-rollback.md +13 -0
- package/pack/.claude/skills/rite-ship/reference/design-memory.md +31 -36
- package/pack/.claude/skills/rite-spec/SKILL.md +84 -135
- package/pack/.claude/skills/rite-spec/reference/investigation.md +37 -33
- package/pack/.claude/skills/rite-spec/reference/question-protocol.md +6 -2
- package/pack/.claude/skills/rite-spec/reference/spec-checklists.md +25 -24
- package/pack/.claude/skills/rite-spec/reference/spec-template.md +9 -2
- package/pack/.claude/skills/rite-spec/reference/state-workspace.md +13 -3
- package/pack/.claude/skills/rite-temper/SKILL.md +62 -47
- package/pack/.claude/skills/rite-temper/reference/review-dimensions.md +24 -22
- package/pack/.claude/skills/rite-vet/SKILL.md +110 -113
- package/pack/.claude/skills/rite-vet/reference/artifacts.md +42 -9
- package/pack/.claude/skills/rite-vet/reference/review-axes.md +39 -37
- package/pack/generated/claude/agents/devrites-code-reviewer.md +62 -48
- package/pack/generated/claude/agents/devrites-devex-reviewer.md +69 -53
- package/pack/generated/claude/agents/devrites-doubt-reviewer.md +29 -22
- package/pack/generated/claude/agents/devrites-evidence-scout.md +69 -0
- package/pack/generated/claude/agents/devrites-forge-judge.md +74 -61
- package/pack/generated/claude/agents/devrites-frontend-reviewer.md +48 -39
- package/pack/generated/claude/agents/devrites-performance-reviewer.md +49 -40
- package/pack/generated/claude/agents/devrites-plan-drafter.md +71 -0
- package/pack/generated/claude/agents/devrites-plan-reviewer.md +80 -47
- package/pack/generated/claude/agents/devrites-proof-runner.md +74 -0
- package/pack/generated/claude/agents/devrites-retrospector.md +48 -45
- package/pack/generated/claude/agents/devrites-security-auditor.md +46 -36
- package/pack/generated/claude/agents/devrites-simplifier-reviewer.md +50 -46
- package/pack/generated/claude/agents/devrites-slice-wright.md +153 -165
- package/pack/generated/claude/agents/devrites-spec-reviewer.md +34 -32
- package/pack/generated/claude/agents/devrites-strategy-reviewer.md +63 -34
- package/pack/generated/claude/agents/devrites-test-analyst.md +40 -30
- package/pack/generated/claude/settings.json +2 -1
- package/pack/generated/claude/skills/devrites-audit/SKILL.md +40 -61
- package/pack/generated/claude/skills/devrites-debug-recovery/SKILL.md +24 -13
- package/pack/generated/claude/skills/devrites-debug-recovery/reference/build-the-loop.md +24 -21
- package/pack/generated/claude/skills/devrites-debug-recovery/reference/cleanup-and-classify.md +34 -6
- package/pack/generated/claude/skills/devrites-debug-recovery/reference/instrumentation.md +2 -2
- package/pack/generated/claude/skills/devrites-doubt/SKILL.md +25 -17
- package/pack/generated/claude/skills/devrites-interview/SKILL.md +53 -52
- package/pack/generated/claude/skills/devrites-lib/SKILL.md +11 -9
- package/pack/generated/claude/skills/devrites-lib/reference/intent-map.md +3 -2
- package/pack/generated/claude/skills/devrites-lib/reference/parallel-dispatch.md +82 -137
- package/pack/generated/claude/skills/devrites-lib/reference/reply-contract.md +8 -1
- package/pack/generated/claude/skills/devrites-lib/reference/standards/README.md +38 -55
- package/pack/generated/claude/skills/devrites-lib/reference/standards/afk-hitl.md +53 -27
- package/pack/generated/claude/skills/devrites-lib/reference/standards/agents.md +198 -190
- package/pack/generated/claude/skills/devrites-lib/reference/standards/anti-patterns.md +5 -15
- package/pack/generated/claude/skills/devrites-lib/reference/standards/ci-cd.md +27 -58
- package/pack/generated/claude/skills/devrites-lib/reference/standards/code-review.md +16 -52
- package/pack/generated/claude/skills/devrites-lib/reference/standards/coding-style.md +2 -10
- package/pack/generated/claude/skills/devrites-lib/reference/standards/context-hygiene.md +18 -61
- package/pack/generated/claude/skills/devrites-lib/reference/standards/core.md +23 -18
- package/pack/generated/claude/skills/devrites-lib/reference/standards/deprecation.md +17 -57
- package/pack/generated/claude/skills/devrites-lib/reference/standards/development-workflow.md +4 -33
- package/pack/generated/claude/skills/devrites-lib/reference/standards/git-workflow.md +4 -20
- package/pack/generated/claude/skills/devrites-lib/reference/standards/hooks.md +3 -14
- package/pack/generated/claude/skills/devrites-lib/reference/standards/patterns.md +9 -25
- package/pack/generated/claude/skills/devrites-lib/reference/standards/performance.md +0 -9
- package/pack/generated/claude/skills/devrites-lib/reference/standards/principles.md +1 -3
- package/pack/generated/claude/skills/devrites-lib/reference/standards/security.md +17 -7
- package/pack/generated/claude/skills/devrites-lib/reference/standards/testing.md +1 -27
- package/pack/generated/claude/skills/devrites-lib/reference/standards/tooling.md +46 -50
- package/pack/generated/claude/skills/devrites-lib/reference/workspace-artifact-schema.md +23 -10
- package/pack/generated/claude/skills/devrites-source-driven/SKILL.md +23 -22
- package/pack/generated/claude/skills/rite/SKILL.md +8 -6
- package/pack/generated/claude/skills/rite/reference/menu.md +8 -6
- package/pack/generated/claude/skills/rite-adopt/SKILL.md +33 -37
- package/pack/generated/claude/skills/rite-autocomplete/SKILL.md +33 -28
- package/pack/generated/claude/skills/rite-autocomplete/reference/loop.md +21 -21
- package/pack/generated/claude/skills/rite-autocomplete/reference/stop-conditions.md +15 -6
- package/pack/generated/claude/skills/rite-build/SKILL.md +35 -30
- package/pack/generated/claude/skills/rite-build/reference/afk-discipline.md +38 -38
- package/pack/generated/claude/skills/rite-build/reference/evidence-standard.md +10 -0
- package/pack/generated/claude/skills/rite-build/reference/forge.md +186 -156
- package/pack/generated/claude/skills/rite-build/reference/one-slice-cycle.md +4 -3
- package/pack/generated/claude/skills/rite-build/reference/phase-contract.md +96 -175
- package/pack/generated/claude/skills/rite-build/reference/wright-dispatch.md +129 -134
- package/pack/generated/claude/skills/rite-clarify/SKILL.md +89 -0
- package/pack/generated/claude/skills/rite-clarify/reference/decision-coverage.md +59 -0
- package/pack/generated/claude/skills/rite-converge/SKILL.md +35 -25
- package/pack/generated/claude/skills/rite-define/SKILL.md +57 -32
- package/pack/generated/claude/skills/rite-define/reference/gates.md +16 -15
- package/pack/generated/claude/skills/rite-define/reference/plan-template.md +16 -8
- package/pack/generated/claude/skills/rite-frame/reference/failure-modes.md +22 -24
- package/pack/generated/claude/skills/rite-plan/SKILL.md +44 -16
- package/pack/generated/claude/skills/rite-plan/reference/task-breakdown.md +4 -0
- package/pack/generated/claude/skills/rite-polish/SKILL.md +27 -23
- package/pack/generated/claude/skills/rite-prototype/SKILL.md +25 -26
- package/pack/generated/claude/skills/rite-prove/SKILL.md +27 -17
- package/pack/generated/claude/skills/rite-resolve/SKILL.md +12 -11
- package/pack/generated/claude/skills/rite-resolve/reference/answer-protocol.md +3 -0
- package/pack/generated/claude/skills/rite-review/SKILL.md +37 -28
- package/pack/generated/claude/skills/rite-seal/reference/phase-contract.md +27 -92
- package/pack/generated/claude/skills/rite-seal/reference/risk-and-rollback.md +13 -0
- package/pack/generated/claude/skills/rite-ship/reference/design-memory.md +31 -36
- package/pack/generated/claude/skills/rite-spec/SKILL.md +84 -135
- package/pack/generated/claude/skills/rite-spec/reference/investigation.md +37 -33
- package/pack/generated/claude/skills/rite-spec/reference/question-protocol.md +6 -2
- package/pack/generated/claude/skills/rite-spec/reference/spec-checklists.md +25 -24
- package/pack/generated/claude/skills/rite-spec/reference/spec-template.md +9 -2
- package/pack/generated/claude/skills/rite-spec/reference/state-workspace.md +13 -3
- package/pack/generated/claude/skills/rite-temper/SKILL.md +62 -47
- package/pack/generated/claude/skills/rite-temper/reference/review-dimensions.md +24 -22
- package/pack/generated/claude/skills/rite-vet/SKILL.md +110 -113
- package/pack/generated/claude/skills/rite-vet/reference/artifacts.md +42 -9
- package/pack/generated/claude/skills/rite-vet/reference/review-axes.md +39 -37
- package/pack/generated/codex/AGENTS.md +5 -2
- package/pack/generated/codex/agents/devrites-code-reviewer.toml +69 -47
- package/pack/generated/codex/agents/devrites-devex-reviewer.toml +75 -51
- package/pack/generated/codex/agents/devrites-doubt-reviewer.toml +35 -20
- package/pack/generated/codex/agents/devrites-evidence-scout.toml +75 -0
- package/pack/generated/codex/agents/devrites-forge-judge.toml +80 -59
- package/pack/generated/codex/agents/devrites-frontend-reviewer.toml +54 -37
- package/pack/generated/codex/agents/devrites-performance-reviewer.toml +55 -38
- package/pack/generated/codex/agents/devrites-plan-drafter.toml +77 -0
- package/pack/generated/codex/agents/devrites-plan-reviewer.toml +82 -47
- package/pack/generated/codex/agents/devrites-proof-runner.toml +80 -0
- package/pack/generated/codex/agents/devrites-retrospector.toml +54 -43
- package/pack/generated/codex/agents/devrites-security-auditor.toml +53 -35
- package/pack/generated/codex/agents/devrites-simplifier-reviewer.toml +56 -44
- package/pack/generated/codex/agents/devrites-slice-wright.toml +159 -163
- package/pack/generated/codex/agents/devrites-spec-reviewer.toml +40 -30
- package/pack/generated/codex/agents/devrites-strategy-reviewer.toml +65 -34
- package/pack/generated/codex/agents/devrites-test-analyst.toml +46 -28
- package/pack/generated/codex/hooks.json +4 -14
- package/pack/generated/codex/skills/devrites-api-interface/SKILL.md +7 -3
- package/pack/generated/codex/skills/devrites-audit/SKILL.md +47 -64
- package/pack/generated/codex/skills/devrites-browser-proof/SKILL.md +7 -3
- package/pack/generated/codex/skills/devrites-debug-recovery/SKILL.md +31 -16
- package/pack/generated/codex/skills/devrites-debug-recovery/reference/build-the-loop.md +24 -21
- package/pack/generated/codex/skills/devrites-debug-recovery/reference/cleanup-and-classify.md +34 -6
- package/pack/generated/codex/skills/devrites-debug-recovery/reference/instrumentation.md +2 -2
- package/pack/generated/codex/skills/devrites-doubt/SKILL.md +32 -20
- package/pack/generated/codex/skills/devrites-frontend-craft/SKILL.md +7 -3
- package/pack/generated/codex/skills/devrites-interview/SKILL.md +60 -55
- package/pack/generated/codex/skills/devrites-lib/SKILL.md +18 -12
- package/pack/generated/codex/skills/devrites-lib/reference/intent-map.md +3 -2
- package/pack/generated/codex/skills/devrites-lib/reference/parallel-dispatch.md +82 -137
- package/pack/generated/codex/skills/devrites-lib/reference/reply-contract.md +8 -1
- package/pack/generated/codex/skills/devrites-lib/reference/standards/README.md +38 -55
- package/pack/generated/codex/skills/devrites-lib/reference/standards/afk-hitl.md +53 -27
- package/pack/generated/codex/skills/devrites-lib/reference/standards/agents.md +198 -190
- package/pack/generated/codex/skills/devrites-lib/reference/standards/anti-patterns.md +5 -15
- package/pack/generated/codex/skills/devrites-lib/reference/standards/ci-cd.md +27 -58
- package/pack/generated/codex/skills/devrites-lib/reference/standards/code-review.md +16 -52
- package/pack/generated/codex/skills/devrites-lib/reference/standards/coding-style.md +2 -10
- package/pack/generated/codex/skills/devrites-lib/reference/standards/context-hygiene.md +18 -61
- package/pack/generated/codex/skills/devrites-lib/reference/standards/core.md +23 -18
- package/pack/generated/codex/skills/devrites-lib/reference/standards/deprecation.md +17 -57
- package/pack/generated/codex/skills/devrites-lib/reference/standards/development-workflow.md +4 -33
- package/pack/generated/codex/skills/devrites-lib/reference/standards/git-workflow.md +4 -20
- package/pack/generated/codex/skills/devrites-lib/reference/standards/hooks.md +3 -14
- package/pack/generated/codex/skills/devrites-lib/reference/standards/patterns.md +9 -25
- package/pack/generated/codex/skills/devrites-lib/reference/standards/performance.md +0 -9
- package/pack/generated/codex/skills/devrites-lib/reference/standards/principles.md +1 -3
- package/pack/generated/codex/skills/devrites-lib/reference/standards/security.md +17 -7
- package/pack/generated/codex/skills/devrites-lib/reference/standards/testing.md +1 -27
- package/pack/generated/codex/skills/devrites-lib/reference/standards/tooling.md +46 -50
- package/pack/generated/codex/skills/devrites-lib/reference/workspace-artifact-schema.md +23 -10
- package/pack/generated/codex/skills/devrites-prose-craft/SKILL.md +7 -3
- package/pack/generated/codex/skills/devrites-refresh-indexes/SKILL.md +7 -3
- package/pack/generated/codex/skills/devrites-source-driven/SKILL.md +29 -24
- package/pack/generated/codex/skills/devrites-ux-shape/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite/SKILL.md +19 -13
- package/pack/generated/codex/skills/rite/reference/menu.md +8 -6
- package/pack/generated/codex/skills/rite-adopt/SKILL.md +40 -40
- package/pack/generated/codex/skills/rite-autocomplete/SKILL.md +40 -31
- package/pack/generated/codex/skills/rite-autocomplete/reference/loop.md +21 -21
- package/pack/generated/codex/skills/rite-autocomplete/reference/stop-conditions.md +15 -6
- package/pack/generated/codex/skills/rite-build/SKILL.md +42 -33
- package/pack/generated/codex/skills/rite-build/reference/afk-discipline.md +38 -38
- package/pack/generated/codex/skills/rite-build/reference/evidence-standard.md +10 -0
- package/pack/generated/codex/skills/rite-build/reference/forge.md +186 -156
- package/pack/generated/codex/skills/rite-build/reference/one-slice-cycle.md +4 -3
- package/pack/generated/codex/skills/rite-build/reference/phase-contract.md +96 -175
- package/pack/generated/codex/skills/rite-build/reference/wright-dispatch.md +129 -134
- package/pack/generated/codex/skills/rite-clarify/SKILL.md +105 -0
- package/pack/generated/codex/skills/rite-clarify/reference/decision-coverage.md +59 -0
- package/pack/generated/codex/skills/rite-converge/SKILL.md +42 -28
- package/pack/generated/codex/skills/rite-customize/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite-define/SKILL.md +64 -35
- package/pack/generated/codex/skills/rite-define/reference/gates.md +16 -15
- package/pack/generated/codex/skills/rite-define/reference/plan-template.md +16 -8
- package/pack/generated/codex/skills/rite-doctor/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite-dogfood/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite-explain/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite-frame/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite-frame/reference/failure-modes.md +22 -24
- package/pack/generated/codex/skills/rite-handoff/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite-learn/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite-plan/SKILL.md +51 -19
- package/pack/generated/codex/skills/rite-plan/reference/task-breakdown.md +5 -1
- package/pack/generated/codex/skills/rite-polish/SKILL.md +34 -26
- package/pack/generated/codex/skills/rite-pov/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite-pr-feedback/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite-pressure-test/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite-prototype/SKILL.md +32 -29
- package/pack/generated/codex/skills/rite-prove/SKILL.md +34 -20
- package/pack/generated/codex/skills/rite-quick/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite-resolve/SKILL.md +19 -14
- package/pack/generated/codex/skills/rite-resolve/reference/answer-protocol.md +3 -0
- package/pack/generated/codex/skills/rite-review/SKILL.md +44 -31
- package/pack/generated/codex/skills/rite-seal/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite-seal/reference/phase-contract.md +27 -92
- package/pack/generated/codex/skills/rite-seal/reference/risk-and-rollback.md +13 -0
- package/pack/generated/codex/skills/rite-ship/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite-ship/reference/design-memory.md +31 -36
- package/pack/generated/codex/skills/rite-spec/SKILL.md +91 -138
- package/pack/generated/codex/skills/rite-spec/reference/investigation.md +37 -33
- package/pack/generated/codex/skills/rite-spec/reference/question-protocol.md +6 -2
- package/pack/generated/codex/skills/rite-spec/reference/spec-checklists.md +25 -24
- package/pack/generated/codex/skills/rite-spec/reference/spec-template.md +9 -2
- package/pack/generated/codex/skills/rite-spec/reference/state-workspace.md +13 -3
- package/pack/generated/codex/skills/rite-status/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite-temper/SKILL.md +69 -50
- package/pack/generated/codex/skills/rite-temper/reference/review-dimensions.md +24 -22
- package/pack/generated/codex/skills/rite-vet/SKILL.md +117 -116
- package/pack/generated/codex/skills/rite-vet/reference/artifacts.md +42 -9
- package/pack/generated/codex/skills/rite-vet/reference/review-axes.md +40 -38
- package/pack/generated/codex/skills/rite-zoom-out/SKILL.md +7 -3
- package/package.json +1 -1
- package/scripts/build-release-tarball.sh +32 -15
- package/scripts/check-authority-drift.py +125 -0
- package/scripts/check-instruction-size-baseline.mjs +19 -11
- package/scripts/check-invocation-integrity.py +2 -0
- package/scripts/codex-generate.sh +69 -33
- package/scripts/grade-feature.sh +121 -40
- package/scripts/live-hosts/agent-result.schema.json +230 -0
- package/scripts/live-hosts/claude.sh +87 -0
- package/scripts/live-hosts/codex.sh +81 -0
- package/scripts/live-hosts/common.sh +113 -0
- package/scripts/live-hosts/fake-host.py +264 -0
- package/scripts/live-hosts/host-transport.py +287 -0
- package/scripts/release-check.sh +5 -1
- package/scripts/run-agent-contract-evals.py +1380 -0
- package/scripts/run-behavioral-evals.sh +24 -30
- package/scripts/run-evals.sh +1 -5
- package/scripts/run-live-behavioral-evals.py +1274 -144
- package/scripts/run-outcome-evals.sh +414 -88
- package/scripts/run-tests.mjs +30 -2
- package/scripts/skills-inventory.mjs +1 -1
- package/scripts/validate-workflow-security.py +39 -20
- package/scripts/validate-workspace-schema.py +362 -10
- package/scripts/validate.sh +21 -15
- package/engine/testdata/golden/TestParityWrightScope/devrites-edit-allowed.golden +0 -1
- /package/engine/testdata/golden/{TestParityReconcile/check-no-claimed.golden → TestParityBuildReadiness/arg=clarifyopen.golden} +0 -0
package/engine/hooks.go
CHANGED
|
@@ -12,23 +12,24 @@ import (
|
|
|
12
12
|
|
|
13
13
|
"github.com/devrites/devrites/internal/gate"
|
|
14
14
|
"github.com/devrites/devrites/internal/harness"
|
|
15
|
+
"github.com/devrites/devrites/internal/lib"
|
|
15
16
|
"github.com/devrites/devrites/internal/orient"
|
|
17
|
+
drvreason "github.com/devrites/devrites/internal/reason"
|
|
16
18
|
"github.com/devrites/devrites/internal/state"
|
|
17
19
|
)
|
|
18
20
|
|
|
19
|
-
// hookOrient emits
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
// present binary run outside a workspace.
|
|
21
|
+
// hookOrient emits SessionStart context for the active feature. It is read only
|
|
22
|
+
// and returns silently when the workspace is missing, unreadable, or has nothing
|
|
23
|
+
// to report. An inline shell guard handles a missing binary; this function
|
|
24
|
+
// handles a present binary outside a workspace.
|
|
24
25
|
func hookOrient(h harness.Harness, stdin io.Reader, stdout, stderr io.Writer) int {
|
|
25
|
-
//
|
|
26
|
-
//
|
|
26
|
+
// Orientation depends only on workspace files, so read and discard the
|
|
27
|
+
// SessionStart payload.
|
|
27
28
|
_, _ = io.Copy(io.Discard, stdin)
|
|
28
29
|
|
|
29
30
|
root, err := orient.ResolveRoot(os.Getenv("DEVRITES_ROOT"))
|
|
30
31
|
if err != nil {
|
|
31
|
-
return exitOK //
|
|
32
|
+
return exitOK // Stay silent outside a DevRites workspace.
|
|
32
33
|
}
|
|
33
34
|
text, has, err := orient.Digest(root)
|
|
34
35
|
if err != nil {
|
|
@@ -36,8 +37,8 @@ func hookOrient(h harness.Harness, stdin io.Reader, stdout, stderr io.Writer) in
|
|
|
36
37
|
return exitOK
|
|
37
38
|
}
|
|
38
39
|
if !has {
|
|
39
|
-
//
|
|
40
|
-
//
|
|
40
|
+
// On the first session without an active feature, print a starting hint
|
|
41
|
+
// based on the repository.
|
|
41
42
|
if text, has = orient.FirstRunDigest(root); !has {
|
|
42
43
|
return exitOK
|
|
43
44
|
}
|
|
@@ -51,40 +52,59 @@ func hookOrient(h harness.Harness, stdin io.Reader, stdout, stderr io.Writer) in
|
|
|
51
52
|
return exitOK
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
// hookStopGate
|
|
55
|
-
//
|
|
56
|
-
// DEVRITES_STOP_GATE=enforce
|
|
57
|
-
//
|
|
55
|
+
// hookStopGate catches inconsistent state when a turn ends. It mirrors
|
|
56
|
+
// devrites-stop-gate.sh, observes by default, and blocks only when
|
|
57
|
+
// DEVRITES_STOP_GATE=enforce. stop_hook_active prevents a blocking loop, and
|
|
58
|
+
// parsing or workspace errors do not block.
|
|
58
59
|
func hookStopGate(h harness.Harness, stdin io.Reader, stdout, stderr io.Writer) int {
|
|
59
60
|
in := h.ParseStopInput(stdin)
|
|
61
|
+
if !in.StopHookActivePresent {
|
|
62
|
+
recordHookGuard(h, "stop-gate", drvreason.HookStopInputInvalid, lib.GuardUnavailable, lib.OutcomeUnavailable)
|
|
63
|
+
return exitOK // Invalid input does not block.
|
|
64
|
+
}
|
|
60
65
|
if in.StopHookActive {
|
|
61
|
-
|
|
66
|
+
recordHookGuard(h, "stop-gate", drvreason.HookStopReentry, lib.GuardBypassed, lib.OutcomeBypassed)
|
|
67
|
+
return exitOK // A reentered Stop must finish.
|
|
62
68
|
}
|
|
63
69
|
root, err := orient.ResolveRoot(os.Getenv("DEVRITES_ROOT"))
|
|
64
70
|
if err != nil {
|
|
65
71
|
return exitOK
|
|
66
72
|
}
|
|
67
73
|
res, err := gate.StopGate(root)
|
|
68
|
-
if err != nil
|
|
74
|
+
if err != nil {
|
|
75
|
+
recordHookGuard(h, "stop-gate", drvreason.HookStopWorkspaceUnavailable, lib.GuardUnavailable, lib.OutcomeUnavailable)
|
|
76
|
+
return exitOK
|
|
77
|
+
}
|
|
78
|
+
if res.ReasonID == "" {
|
|
79
|
+
recordHookGuard(h, "stop-gate", drvreason.HookStopWorkspaceUnavailable, lib.GuardUnavailable, lib.OutcomeUnavailable)
|
|
80
|
+
return exitOK
|
|
81
|
+
}
|
|
82
|
+
if !res.Blocked {
|
|
83
|
+
strength := lib.GuardObserved
|
|
84
|
+
if hookEnforce("DEVRITES_STOP_GATE") {
|
|
85
|
+
strength = lib.GuardEnforced
|
|
86
|
+
}
|
|
87
|
+
recordHookGuard(h, "stop-gate", res.ReasonID, strength, lib.OutcomePassed)
|
|
69
88
|
return exitOK
|
|
70
89
|
}
|
|
71
90
|
if !hookEnforce("DEVRITES_STOP_GATE") {
|
|
72
|
-
// Observe mode
|
|
73
|
-
//
|
|
74
|
-
// visible without gating; the append is O_APPEND-atomic across the
|
|
75
|
-
// concurrent processes DevRites spawns.
|
|
91
|
+
// Observe mode records the finding without blocking. O_APPEND keeps each
|
|
92
|
+
// log entry intact when DevRites runs concurrent processes.
|
|
76
93
|
logPath := filepath.Join(resolveWorkspaceDir(root, res.Slug), ".stop-gate.log")
|
|
77
94
|
if err := state.AppendLog(logPath, "WOULD-BLOCK\t"+res.Reason); err != nil {
|
|
78
95
|
debugf(stderr, "stop-gate log: %v", err)
|
|
79
96
|
}
|
|
97
|
+
recordHookGuard(h, "stop-gate", res.ReasonID, lib.GuardObserved, lib.OutcomeObserved, res.EvidenceFiles...)
|
|
80
98
|
return exitOK
|
|
81
99
|
}
|
|
82
100
|
out, err := h.StopBlock(res.Reason)
|
|
83
101
|
if err != nil {
|
|
84
102
|
debugf(stderr, "stop-gate: %v", err)
|
|
103
|
+
recordHookGuard(h, "stop-gate", res.ReasonID, lib.GuardUnavailable, lib.OutcomeUnavailable, res.EvidenceFiles...)
|
|
85
104
|
return exitOK
|
|
86
105
|
}
|
|
87
106
|
fmt.Fprintln(stdout, out)
|
|
107
|
+
recordHookGuard(h, "stop-gate", res.ReasonID, lib.GuardEnforced, lib.OutcomeBlocked, res.EvidenceFiles...)
|
|
88
108
|
return exitOK
|
|
89
109
|
}
|
|
90
110
|
|
|
@@ -107,16 +127,14 @@ var allowReadonlySubcommands = map[string]map[string]bool{
|
|
|
107
127
|
"reviewer-stats": {"report": true},
|
|
108
128
|
}
|
|
109
129
|
|
|
110
|
-
// hookAllow
|
|
111
|
-
//
|
|
112
|
-
// ever EMITS an allow for a structurally exact command shape; on any doubt it
|
|
113
|
-
// stays silent, leaving the normal permission flow untouched.
|
|
130
|
+
// hookAllow approves exact read-only DevRites orientation and gate commands.
|
|
131
|
+
// Any other command stays in the harness's normal permission flow.
|
|
114
132
|
func hookAllow(h harness.Harness, stdin io.Reader, stdout, stderr io.Writer) int {
|
|
115
133
|
data, err := io.ReadAll(stdin)
|
|
116
134
|
if err != nil {
|
|
117
135
|
return exitOK
|
|
118
136
|
}
|
|
119
|
-
//
|
|
137
|
+
// Ignore commands that do not mention DevRites.
|
|
120
138
|
if !bytes.Contains(data, []byte("devrites")) {
|
|
121
139
|
return exitOK
|
|
122
140
|
}
|
|
@@ -133,6 +151,7 @@ func hookAllow(h harness.Harness, stdin io.Reader, stdout, stderr io.Writer) int
|
|
|
133
151
|
return exitOK
|
|
134
152
|
}
|
|
135
153
|
fmt.Fprintln(stdout, out)
|
|
154
|
+
recordHookGuard(h, "allow", drvreason.HookAllowApproved, lib.GuardEnforced, lib.OutcomeAllowed)
|
|
136
155
|
return exitOK
|
|
137
156
|
}
|
|
138
157
|
|
|
@@ -215,77 +234,283 @@ func safeAllowArg(arg string) bool {
|
|
|
215
234
|
// parity oracle green.
|
|
216
235
|
const reviewerReadonlyDenyReason = "DevRites: reviewers are read-only. This Bash command can mutate or exfiltrate; inspect with Read/Grep/Glob and return findings: do not modify the tree or reach the network. (devrites-reviewer-readonly)"
|
|
217
236
|
|
|
218
|
-
// reviewerMutateRe
|
|
219
|
-
//
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
//
|
|
235
|
-
//
|
|
236
|
-
|
|
237
|
-
|
|
237
|
+
// reviewerMutateRe is the legacy observe-mode deny-list. Active DevRites leaves
|
|
238
|
+
// use the fail-closed safe-command check below instead.
|
|
239
|
+
var reviewerMutateRe = regexp.MustCompile(`(?im)>>|[^0-9 ]>[^>&]|[[:space:]]-i([[:space:]]|$)|sed[[:space:]]+-i|\b(rm|mv|cp|touch|mkdir|rmdir|tee|truncate|dd|chmod|chown|ln|unlink|install|patch)\b|git[[:space:]]+(add|commit|push|reset|checkout|restore|clean|rm|mv|stash|tag|apply|merge|rebase)|npm[[:space:]]+(install|i|ci|publish)|pnpm[[:space:]]+(install|add|publish)|yarn[[:space:]]+(add|install|publish)|pip[[:space:]]+install|go[[:space:]]+(get|install|generate)|cargo[[:space:]]+(add|install|publish)|\b(curl|wget|scp|ssh|nc|socat|telnet)\b`)
|
|
240
|
+
|
|
241
|
+
var shellSegmentRe = regexp.MustCompile(`\|\||&&|[;|\n]`)
|
|
242
|
+
|
|
243
|
+
type devritesAgentKind uint8
|
|
244
|
+
|
|
245
|
+
const (
|
|
246
|
+
devritesAgentNone devritesAgentKind = iota
|
|
247
|
+
devritesAgentReadonly
|
|
248
|
+
devritesAgentWright
|
|
249
|
+
devritesAgentInvalid
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
// devritesAgent identifies the one write-capable leaf without copying the agent
|
|
253
|
+
// roster. DEVRITES_AGENT_RUN supplies identity when a hook payload cannot carry
|
|
254
|
+
// agent_type.
|
|
255
|
+
func devritesAgent(payloadAgent string) devritesAgentKind {
|
|
256
|
+
payloadAgent = strings.TrimSpace(payloadAgent)
|
|
257
|
+
envAgent := strings.TrimSpace(os.Getenv("DEVRITES_ACTIVE_AGENT"))
|
|
258
|
+
declared := os.Getenv("DEVRITES_AGENT_RUN") == "1" || strings.HasPrefix(payloadAgent, "devrites-")
|
|
259
|
+
if !declared {
|
|
260
|
+
return devritesAgentNone
|
|
261
|
+
}
|
|
262
|
+
if payloadAgent != "" && envAgent != "" && payloadAgent != envAgent {
|
|
263
|
+
return devritesAgentInvalid
|
|
264
|
+
}
|
|
265
|
+
agent := payloadAgent
|
|
266
|
+
if agent == "" {
|
|
267
|
+
agent = envAgent
|
|
268
|
+
}
|
|
269
|
+
switch {
|
|
270
|
+
case agent == "devrites-slice-wright":
|
|
271
|
+
return devritesAgentWright
|
|
272
|
+
case strings.HasPrefix(agent, "devrites-") && len(agent) > len("devrites-"):
|
|
273
|
+
return devritesAgentReadonly
|
|
274
|
+
default:
|
|
275
|
+
return devritesAgentInvalid
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
func toolBaseName(tool string) string {
|
|
280
|
+
tool = strings.ToLower(strings.TrimSpace(tool))
|
|
281
|
+
for _, sep := range []string{"::", "__", "/", "."} {
|
|
282
|
+
if i := strings.LastIndex(tool, sep); i >= 0 {
|
|
283
|
+
tool = tool[i+len(sep):]
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return strings.ReplaceAll(tool, "-", "_")
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
func isShellTool(tool string) bool {
|
|
290
|
+
switch toolBaseName(tool) {
|
|
291
|
+
case "bash", "shell", "sh", "exec_command", "run_command":
|
|
292
|
+
return true
|
|
293
|
+
}
|
|
294
|
+
return false
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
func isOpaqueExecutionTool(tool string) bool {
|
|
298
|
+
switch toolBaseName(tool) {
|
|
299
|
+
case "exec", "js", "python", "computer", "computer_use", "write_stdin", "run_code":
|
|
300
|
+
return true
|
|
301
|
+
}
|
|
302
|
+
return false
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
func isAgentDispatchTool(tool string) bool {
|
|
306
|
+
switch toolBaseName(tool) {
|
|
307
|
+
case "agent", "task", "spawn_agent", "delegate", "dispatch_agent", "create_agent":
|
|
308
|
+
return true
|
|
309
|
+
}
|
|
310
|
+
return false
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// safeReadonlyShellCommand accepts common inspection and proof commands. A
|
|
314
|
+
// read-only leaf can use Read or Grep, or ask the orchestrator to run anything
|
|
315
|
+
// outside this conservative set.
|
|
316
|
+
func safeReadonlyShellCommand(command string) bool {
|
|
317
|
+
command, writeTargets, opaqueRedirect := shellOutputRedirections(command)
|
|
318
|
+
if opaqueRedirect || len(writeTargets) != 0 ||
|
|
319
|
+
strings.Contains(command, "$(") || strings.ContainsRune(command, '`') ||
|
|
320
|
+
reviewerMutateRe.MatchString(command) {
|
|
321
|
+
return false
|
|
322
|
+
}
|
|
323
|
+
segments := shellSegmentRe.Split(command, -1)
|
|
324
|
+
if len(segments) == 0 {
|
|
325
|
+
return false
|
|
326
|
+
}
|
|
327
|
+
for _, segment := range segments {
|
|
328
|
+
if !safeReadonlyShellSegment(segment) {
|
|
329
|
+
return false
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return true
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
func safeReadonlyShellSegment(segment string) bool {
|
|
336
|
+
fields := strings.Fields(strings.TrimSpace(segment))
|
|
337
|
+
for len(fields) > 0 && strings.Contains(fields[0], "=") && !strings.HasPrefix(fields[0], "=") {
|
|
338
|
+
fields = fields[1:]
|
|
339
|
+
}
|
|
340
|
+
for len(fields) > 0 {
|
|
341
|
+
switch filepath.Base(fields[0]) {
|
|
342
|
+
case "rtk", "timeout", "nice":
|
|
343
|
+
fields = fields[1:]
|
|
344
|
+
continue
|
|
345
|
+
case "command":
|
|
346
|
+
if len(fields) == 2 && fields[1] == "-v" {
|
|
347
|
+
return true
|
|
348
|
+
}
|
|
349
|
+
fields = fields[1:]
|
|
350
|
+
continue
|
|
351
|
+
case "env":
|
|
352
|
+
fields = fields[1:]
|
|
353
|
+
for len(fields) > 0 && (strings.HasPrefix(fields[0], "-") || strings.Contains(fields[0], "=")) {
|
|
354
|
+
fields = fields[1:]
|
|
355
|
+
}
|
|
356
|
+
continue
|
|
357
|
+
}
|
|
358
|
+
break
|
|
359
|
+
}
|
|
360
|
+
if len(fields) == 0 {
|
|
361
|
+
return false
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
base := strings.ToLower(filepath.Base(strings.Trim(fields[0], `"'`)))
|
|
365
|
+
args := fields[1:]
|
|
366
|
+
switch base {
|
|
367
|
+
case "true", "false", "pwd", "ls", "cat", "head", "tail", "less", "more",
|
|
368
|
+
"grep", "rg", "wc", "sort", "uniq", "cut", "tr", "stat", "file",
|
|
369
|
+
"readlink", "realpath", "basename", "dirname", "cmp", "diff", "jq", "yq",
|
|
370
|
+
"tree", "du", "df", "printenv", "which", "date", "uname", "id", "whoami",
|
|
371
|
+
"ps", "echo", "printf", "test", "[", "cd":
|
|
372
|
+
return true
|
|
373
|
+
case "find":
|
|
374
|
+
return !hasAnyArg(args, "-delete", "-exec", "-execdir", "-ok", "-okdir", "-fprint", "-fprintf")
|
|
375
|
+
case "sed":
|
|
376
|
+
return !hasArgPrefix(args, "-i")
|
|
377
|
+
case "git":
|
|
378
|
+
return len(args) > 0 && hasAnyArg(args[:1], "diff", "status", "show", "log", "rev-parse", "ls-files", "grep", "blame")
|
|
379
|
+
case "go":
|
|
380
|
+
if len(args) == 0 || !hasAnyArg(args[:1], "test", "vet", "list", "version", "env") {
|
|
381
|
+
return false
|
|
382
|
+
}
|
|
383
|
+
return args[0] != "env" || !hasAnyArg(args[1:], "-w", "-u")
|
|
384
|
+
case "npm", "pnpm", "yarn":
|
|
385
|
+
return safePackageProof(args)
|
|
386
|
+
case "pytest", "rspec":
|
|
387
|
+
return true
|
|
388
|
+
case "python", "python3":
|
|
389
|
+
return len(args) >= 2 && args[0] == "-m" && hasAnyArg(args[1:2], "pytest", "unittest", "compileall")
|
|
390
|
+
case "cargo":
|
|
391
|
+
if len(args) == 0 {
|
|
392
|
+
return false
|
|
393
|
+
}
|
|
394
|
+
if hasAnyArg(args[:1], "test", "check", "clippy") {
|
|
395
|
+
return true
|
|
396
|
+
}
|
|
397
|
+
return args[0] == "fmt" && hasAnyArg(args[1:], "--check")
|
|
398
|
+
case "ruff":
|
|
399
|
+
return len(args) > 0 && args[0] == "check" && !hasAnyArg(args[1:], "--fix")
|
|
400
|
+
case "prettier":
|
|
401
|
+
return hasAnyArg(args, "--check", "--list-different")
|
|
402
|
+
case "eslint":
|
|
403
|
+
return !hasAnyArg(args, "--fix", "--fix-dry-run")
|
|
404
|
+
case "tsc":
|
|
405
|
+
return hasAnyArg(args, "--noEmit")
|
|
406
|
+
case "node":
|
|
407
|
+
return hasAnyArg(args, "--check", "--test", "--version", "-v")
|
|
408
|
+
case "bash", "sh", "zsh":
|
|
409
|
+
return len(args) > 0 && args[0] == "-n"
|
|
410
|
+
case "make":
|
|
411
|
+
return len(args) > 0 && hasAnyArg(args[:1], "test", "check", "lint", "vet")
|
|
412
|
+
case "devrites-engine":
|
|
413
|
+
return len(args) > 0 && safeAllowShape(args[0], args[1:])
|
|
414
|
+
}
|
|
415
|
+
return false
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
func safePackageProof(args []string) bool {
|
|
419
|
+
if len(args) == 0 {
|
|
420
|
+
return false
|
|
421
|
+
}
|
|
422
|
+
if args[0] == "test" {
|
|
423
|
+
return true
|
|
424
|
+
}
|
|
425
|
+
return len(args) > 1 && args[0] == "run" &&
|
|
426
|
+
hasAnyArg(args[1:2], "test", "lint", "check", "typecheck", "type-check")
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
func hasAnyArg(args []string, wants ...string) bool {
|
|
430
|
+
for _, arg := range args {
|
|
431
|
+
for _, want := range wants {
|
|
432
|
+
if arg == want {
|
|
433
|
+
return true
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
return false
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
func hasArgPrefix(args []string, prefix string) bool {
|
|
441
|
+
for _, arg := range args {
|
|
442
|
+
if strings.HasPrefix(arg, prefix) {
|
|
443
|
+
return true
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
return false
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// hookReviewerReadonly keeps every DevRites leaf except slice-wright read only.
|
|
450
|
+
// It always enforces declared DevRites runs. Undeclared runs keep the legacy
|
|
451
|
+
// observe mode.
|
|
238
452
|
func hookReviewerReadonly(h harness.Harness, stdin io.Reader, stdout, stderr io.Writer) int {
|
|
239
453
|
data, err := io.ReadAll(stdin)
|
|
240
454
|
if err != nil {
|
|
241
455
|
return exitOK
|
|
242
456
|
}
|
|
243
|
-
// Fast path: a payload with no tool call is not ours: mirrors the script's
|
|
244
|
-
// `case "$input" in *'"tool_name"'*`.
|
|
245
457
|
if !bytes.Contains(data, []byte(`"tool_name"`)) {
|
|
246
458
|
return exitOK
|
|
247
459
|
}
|
|
248
|
-
in := h.
|
|
460
|
+
in := h.ParseGuardInput(bytes.NewReader(data))
|
|
461
|
+
kind := devritesAgent(in.AgentType)
|
|
249
462
|
|
|
250
|
-
//
|
|
251
|
-
//
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
463
|
+
// Do not let a global hook interfere with the main thread or another
|
|
464
|
+
// product's agent when no DevRites run is declared.
|
|
465
|
+
if kind == devritesAgentNone && (in.AgentType != "" || os.Getenv("DEVRITES_REVIEWER_AGENT_REQUIRED") == "1") {
|
|
466
|
+
return exitOK
|
|
467
|
+
}
|
|
468
|
+
if kind == devritesAgentWright {
|
|
469
|
+
if !isAgentDispatchTool(in.ToolName) {
|
|
256
470
|
return exitOK
|
|
257
|
-
|
|
471
|
+
}
|
|
472
|
+
} else {
|
|
473
|
+
active := kind != devritesAgentNone
|
|
474
|
+
unsafe := isEditTool(in.ToolName) || isOpaqueExecutionTool(in.ToolName) || isAgentDispatchTool(in.ToolName)
|
|
475
|
+
if isShellTool(in.ToolName) {
|
|
476
|
+
if in.Command == "" {
|
|
477
|
+
unsafe = active
|
|
478
|
+
} else if active {
|
|
479
|
+
unsafe = !safeReadonlyShellCommand(in.Command)
|
|
480
|
+
} else {
|
|
481
|
+
unsafe = reviewerMutateRe.MatchString(in.Command)
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
if !unsafe {
|
|
258
485
|
return exitOK
|
|
259
486
|
}
|
|
260
487
|
}
|
|
261
|
-
if in.ToolName != "Bash" || in.Command == "" {
|
|
262
|
-
return exitOK
|
|
263
|
-
}
|
|
264
|
-
if !reviewerMutateRe.MatchString(in.Command) {
|
|
265
|
-
return exitOK
|
|
266
|
-
}
|
|
267
488
|
|
|
268
|
-
|
|
489
|
+
active := kind != devritesAgentNone
|
|
490
|
+
if active || hookEnforce("DEVRITES_REVIEWER_RO") {
|
|
269
491
|
out, err := h.PreToolDeny(reviewerReadonlyDenyReason)
|
|
270
492
|
if err != nil {
|
|
271
493
|
debugf(stderr, "reviewer-readonly: %v", err)
|
|
272
494
|
return exitOK
|
|
273
495
|
}
|
|
274
496
|
fmt.Fprintln(stdout, out)
|
|
497
|
+
recordHookGuard(h, "reviewer-readonly", drvreason.HookReviewerReadonlyDenied, lib.GuardEnforced, lib.OutcomeDenied)
|
|
275
498
|
return exitOK
|
|
276
499
|
}
|
|
277
500
|
|
|
278
|
-
// Observe mode: record the would-block to the active feature's append-only log,
|
|
279
|
-
// mirroring the stop-gate's log convention, then allow. The append is
|
|
280
|
-
// O_APPEND-atomic across the concurrent processes DevRites spawns.
|
|
281
501
|
if root, err := orient.ResolveRoot(os.Getenv("DEVRITES_ROOT")); err == nil {
|
|
282
502
|
if slug, _ := orient.ActiveSlug(root); slug != "" {
|
|
283
503
|
logPath := filepath.Join(resolveWorkspaceDir(root, slug), ".reviewer-ro.log")
|
|
284
|
-
|
|
504
|
+
action := in.Command
|
|
505
|
+
if action == "" {
|
|
506
|
+
action = in.ToolName + "\t" + in.FilePath
|
|
507
|
+
}
|
|
508
|
+
if err := state.AppendLog(logPath, "WOULD-BLOCK\t"+head80(action)); err != nil {
|
|
285
509
|
debugf(stderr, "reviewer-readonly log: %v", err)
|
|
286
510
|
}
|
|
287
511
|
}
|
|
288
512
|
}
|
|
513
|
+
recordHookGuard(h, "reviewer-readonly", drvreason.HookReviewerReadonlyObserved, lib.GuardObserved, lib.OutcomeObserved)
|
|
289
514
|
return exitOK
|
|
290
515
|
}
|
|
291
516
|
|
|
@@ -297,15 +522,13 @@ func hookReviewerReadonly(h harness.Harness, stdin io.Reader, stdout, stderr io.
|
|
|
297
522
|
//go:embed subagent_orient_context.txt
|
|
298
523
|
var subagentOrientContext string
|
|
299
524
|
|
|
300
|
-
// hookSubagentOrient
|
|
301
|
-
//
|
|
302
|
-
//
|
|
303
|
-
// devrites-subagent-orient.sh: fire only for devrites-* agents, emit a fixed
|
|
304
|
-
// context envelope, stay silent + fail-open otherwise.
|
|
525
|
+
// hookSubagentOrient adds DevRites instructions when a devrites-* agent starts.
|
|
526
|
+
// Spawned agents have fresh context and do not load the rite-* framework the
|
|
527
|
+
// same way as the main thread. The output matches devrites-subagent-orient.sh.
|
|
305
528
|
func hookSubagentOrient(h harness.Harness, stdin io.Reader, stdout, stderr io.Writer) int {
|
|
306
529
|
agentType := h.SubagentAgentType(stdin)
|
|
307
530
|
if !strings.HasPrefix(agentType, "devrites-") {
|
|
308
|
-
return exitOK //
|
|
531
|
+
return exitOK // Stay silent without a DevRites agent identity.
|
|
309
532
|
}
|
|
310
533
|
out, err := h.SubagentStartContext(strings.ReplaceAll(subagentOrientContext, "\r\n", "\n"))
|
|
311
534
|
if err != nil {
|
|
@@ -326,9 +549,7 @@ func head80(s string) string {
|
|
|
326
549
|
return s
|
|
327
550
|
}
|
|
328
551
|
|
|
329
|
-
// debugf writes
|
|
330
|
-
// fail-open hook can surface WHY it stayed silent without ever polluting normal
|
|
331
|
-
// hook stdout/stderr.
|
|
552
|
+
// debugf writes diagnostics only when DEVRITES_DEBUG is set.
|
|
332
553
|
func debugf(stderr io.Writer, format string, args ...any) {
|
|
333
554
|
if os.Getenv("DEVRITES_DEBUG") != "" {
|
|
334
555
|
fmt.Fprintf(stderr, "devrites: "+format+"\n", args...)
|