@quickchatai/pi-quickreview 0.0.0-stage → 1.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/LICENSE +23 -0
- package/README.md +75 -2
- package/assets/agents/pass-abstraction.md +64 -0
- package/assets/agents/pass-ask-human.md +134 -0
- package/assets/agents/pass-backcompat.md +67 -0
- package/assets/agents/pass-baseline.md +61 -0
- package/assets/agents/pass-behaviour-delta.md +64 -0
- package/assets/agents/pass-bounds.md +36 -0
- package/assets/agents/pass-claims.md +31 -0
- package/assets/agents/pass-concurrency.md +168 -0
- package/assets/agents/pass-consistency.md +57 -0
- package/assets/agents/pass-contracts.md +30 -0
- package/assets/agents/pass-data-safety.md +54 -0
- package/assets/agents/pass-deferred.md +35 -0
- package/assets/agents/pass-delivery.md +37 -0
- package/assets/agents/pass-duplication.md +60 -0
- package/assets/agents/pass-intent.md +63 -0
- package/assets/agents/pass-lint-conformance.md +46 -0
- package/assets/agents/pass-maintainability.md +67 -0
- package/assets/agents/pass-placement.md +68 -0
- package/assets/agents/pass-prod-risk.md +24 -0
- package/assets/agents/pass-rollout.md +32 -0
- package/assets/agents/pass-roundtrip.md +46 -0
- package/assets/agents/pass-security.md +31 -0
- package/assets/agents/pass-simplicity.md +68 -0
- package/assets/agents/pass-statelessness.md +27 -0
- package/assets/agents/pass-style.md +37 -0
- package/assets/agents/pass-sweep.md +57 -0
- package/assets/agents/pass-tests.md +58 -0
- package/assets/agents/pass-ui.md +23 -0
- package/assets/agents/pass-validate.md +50 -0
- package/assets/agents/pass-widened.md +46 -0
- package/assets/agents/scan/pass-scan.md +86 -0
- package/assets/config.example.toml +1067 -0
- package/assets/deploy/reviewer/AGENTS.override.md +12 -0
- package/assets/profiles/default/README.md +21 -0
- package/assets/profiles/default/addenda/.gitkeep +0 -0
- package/assets/profiles/default/profile.toml +17 -0
- package/assets/profiles/example-django/README.md +21 -0
- package/assets/profiles/example-django/addenda/10-migration-discipline.md +13 -0
- package/assets/profiles/example-django/addenda/20-new-column-nullability.md +12 -0
- package/assets/profiles/example-django/addenda/30-test-doctrine.md +12 -0
- package/assets/profiles/example-django/addenda/40-orm-usage.md +19 -0
- package/assets/profiles/example-django/addenda/50-declared-shape.md +10 -0
- package/assets/profiles/example-django/addenda/60-config-placement.md +14 -0
- package/assets/profiles/example-django/heuristics.toml +24 -0
- package/assets/profiles/example-django/profile.toml +9 -0
- package/assets/profiles/fast/README.md +24 -0
- package/assets/profiles/fast/profile.toml +59 -0
- package/assets/profiles/minimal/README.md +17 -0
- package/assets/profiles/minimal/addenda/.gitkeep +0 -0
- package/assets/profiles/minimal/profile.toml +8 -0
- package/assets/profiles/snappy/README.md +24 -0
- package/assets/profiles/snappy/addenda/10-race-as-question.md +6 -0
- package/assets/profiles/snappy/profile.toml +46 -0
- package/assets/prompts/companion-day-open.md +46 -0
- package/assets/prompts/companion-first-run.md +104 -0
- package/assets/prompts/companion.md +821 -0
- package/assets/prompts/conversation-system.md +117 -0
- package/assets/prompts/eod-sweep.md +120 -0
- package/assets/prompts/onboarding.md +74 -0
- package/assets/prompts/pass-common.md +52 -0
- package/assets/prompts/pass-quality-common.md +22 -0
- package/assets/prompts/round-first.md +874 -0
- package/assets/prompts/round-follow-up.md +991 -0
- package/assets/prompts/round-re-review.md +889 -0
- package/assets/prompts/round-recheck.md +196 -0
- package/assets/prompts/round-staleness.md +856 -0
- package/assets/schemas/review-result.v1.json +391 -0
- package/assets/schemas/scan-result.v1.json +421 -0
- package/assets/schemas/version.v1.json +57 -0
- package/assets/seed-manifest.json +19 -0
- package/assets/seeds/agents/pass-baseline.md +61 -0
- package/assets/seeds/agents/pass-contracts.md +30 -0
- package/assets/seeds/agents/pass-data-safety.md +54 -0
- package/assets/seeds/agents/pass-delivery.md +37 -0
- package/assets/seeds/agents/pass-prod-risk.md +24 -0
- package/assets/seeds/agents/pass-security.md +31 -0
- package/assets/seeds/agents/pass-statelessness.md +27 -0
- package/assets/seeds/agents/pass-ui.md +23 -0
- package/assets/seeds/agents/pass-validate.md +50 -0
- package/assets/seeds/prompts/conversation-system.md +117 -0
- package/assets/seeds/prompts/eod-sweep.md +120 -0
- package/assets/seeds/prompts/pass-common.md +52 -0
- package/dist/extensions/bash-guard.d.ts +467 -0
- package/dist/extensions/bash-guard.d.ts.map +1 -0
- package/dist/extensions/bash-guard.js +3058 -0
- package/dist/extensions/bash-guard.js.map +1 -0
- package/dist/extensions/finding-clusters.d.ts +33 -0
- package/dist/extensions/finding-clusters.d.ts.map +1 -0
- package/dist/extensions/finding-clusters.js +218 -0
- package/dist/extensions/finding-clusters.js.map +1 -0
- package/dist/extensions/ledger-pin.d.ts +76 -0
- package/dist/extensions/ledger-pin.d.ts.map +1 -0
- package/dist/extensions/ledger-pin.js +331 -0
- package/dist/extensions/ledger-pin.js.map +1 -0
- package/dist/extensions/lens.d.ts +43 -0
- package/dist/extensions/lens.d.ts.map +1 -0
- package/dist/extensions/lens.js +150 -0
- package/dist/extensions/lens.js.map +1 -0
- package/dist/extensions/pi-tool.d.ts +22 -0
- package/dist/extensions/pi-tool.d.ts.map +1 -0
- package/dist/extensions/pi-tool.js +20 -0
- package/dist/extensions/pi-tool.js.map +1 -0
- package/dist/extensions/quickreview.d.ts +21 -0
- package/dist/extensions/quickreview.d.ts.map +1 -0
- package/dist/extensions/quickreview.js +132 -0
- package/dist/extensions/quickreview.js.map +1 -0
- package/dist/src/anchors.d.ts +54 -0
- package/dist/src/anchors.d.ts.map +1 -0
- package/dist/src/anchors.js +127 -0
- package/dist/src/anchors.js.map +1 -0
- package/dist/src/assetroot.d.ts +16 -0
- package/dist/src/assetroot.d.ts.map +1 -0
- package/dist/src/assetroot.js +77 -0
- package/dist/src/assetroot.js.map +1 -0
- package/dist/src/authwatch.d.ts +61 -0
- package/dist/src/authwatch.d.ts.map +1 -0
- package/dist/src/authwatch.js +210 -0
- package/dist/src/authwatch.js.map +1 -0
- package/dist/src/budget.d.ts +15 -0
- package/dist/src/budget.d.ts.map +1 -0
- package/dist/src/budget.js +32 -0
- package/dist/src/budget.js.map +1 -0
- package/dist/src/casebudget.d.ts +3 -0
- package/dist/src/casebudget.d.ts.map +1 -0
- package/dist/src/casebudget.js +3 -0
- package/dist/src/casebudget.js.map +1 -0
- package/dist/src/cigate.d.ts +116 -0
- package/dist/src/cigate.d.ts.map +1 -0
- package/dist/src/cigate.js +176 -0
- package/dist/src/cigate.js.map +1 -0
- package/dist/src/codespan.d.ts +46 -0
- package/dist/src/codespan.d.ts.map +1 -0
- package/dist/src/codespan.js +75 -0
- package/dist/src/codespan.js.map +1 -0
- package/dist/src/contextpack.d.ts +56 -0
- package/dist/src/contextpack.d.ts.map +1 -0
- package/dist/src/contextpack.js +195 -0
- package/dist/src/contextpack.js.map +1 -0
- package/dist/src/contract.d.ts +8 -0
- package/dist/src/contract.d.ts.map +1 -0
- package/dist/src/contract.js +21 -0
- package/dist/src/contract.js.map +1 -0
- package/dist/src/coverage.d.ts +32 -0
- package/dist/src/coverage.d.ts.map +1 -0
- package/dist/src/coverage.js +85 -0
- package/dist/src/coverage.js.map +1 -0
- package/dist/src/datafence.d.ts +19 -0
- package/dist/src/datafence.d.ts.map +1 -0
- package/dist/src/datafence.js +60 -0
- package/dist/src/datafence.js.map +1 -0
- package/dist/src/dedup.d.ts +65 -0
- package/dist/src/dedup.d.ts.map +1 -0
- package/dist/src/dedup.js +459 -0
- package/dist/src/dedup.js.map +1 -0
- package/dist/src/depsources.d.ts +304 -0
- package/dist/src/depsources.d.ts.map +1 -0
- package/dist/src/depsources.js +3367 -0
- package/dist/src/depsources.js.map +1 -0
- package/dist/src/diffinput.d.ts +10 -0
- package/dist/src/diffinput.d.ts.map +1 -0
- package/dist/src/diffinput.js +172 -0
- package/dist/src/diffinput.js.map +1 -0
- package/dist/src/doubtwords.d.ts +10 -0
- package/dist/src/doubtwords.d.ts.map +1 -0
- package/dist/src/doubtwords.js +13 -0
- package/dist/src/doubtwords.js.map +1 -0
- package/dist/src/ecosystem.d.ts +148 -0
- package/dist/src/ecosystem.d.ts.map +1 -0
- package/dist/src/ecosystem.js +338 -0
- package/dist/src/ecosystem.js.map +1 -0
- package/dist/src/engine/agentdir.d.ts +5 -0
- package/dist/src/engine/agentdir.d.ts.map +1 -0
- package/dist/src/engine/agentdir.js +21 -0
- package/dist/src/engine/agentdir.js.map +1 -0
- package/dist/src/engine/auth.d.ts +214 -0
- package/dist/src/engine/auth.d.ts.map +1 -0
- package/dist/src/engine/auth.js +374 -0
- package/dist/src/engine/auth.js.map +1 -0
- package/dist/src/engine/budget.d.ts +60 -0
- package/dist/src/engine/budget.d.ts.map +1 -0
- package/dist/src/engine/budget.js +113 -0
- package/dist/src/engine/budget.js.map +1 -0
- package/dist/src/engine/capfd.d.ts +6 -0
- package/dist/src/engine/capfd.d.ts.map +1 -0
- package/dist/src/engine/capfd.js +21 -0
- package/dist/src/engine/capfd.js.map +1 -0
- package/dist/src/engine/caseout.d.ts +66 -0
- package/dist/src/engine/caseout.d.ts.map +1 -0
- package/dist/src/engine/caseout.js +107 -0
- package/dist/src/engine/caseout.js.map +1 -0
- package/dist/src/engine/context.d.ts +57 -0
- package/dist/src/engine/context.d.ts.map +1 -0
- package/dist/src/engine/context.js +212 -0
- package/dist/src/engine/context.js.map +1 -0
- package/dist/src/engine/envmap.d.ts +13 -0
- package/dist/src/engine/envmap.d.ts.map +1 -0
- package/dist/src/engine/envmap.js +372 -0
- package/dist/src/engine/envmap.js.map +1 -0
- package/dist/src/engine/extfiles.d.ts +7 -0
- package/dist/src/engine/extfiles.d.ts.map +1 -0
- package/dist/src/engine/extfiles.js +23 -0
- package/dist/src/engine/extfiles.js.map +1 -0
- package/dist/src/engine/keyroute.d.ts +21 -0
- package/dist/src/engine/keyroute.d.ts.map +1 -0
- package/dist/src/engine/keyroute.js +58 -0
- package/dist/src/engine/keyroute.js.map +1 -0
- package/dist/src/engine/lens/cache-group.d.ts +20 -0
- package/dist/src/engine/lens/cache-group.d.ts.map +1 -0
- package/dist/src/engine/lens/cache-group.js +31 -0
- package/dist/src/engine/lens/cache-group.js.map +1 -0
- package/dist/src/engine/lens/cache-run.d.ts +65 -0
- package/dist/src/engine/lens/cache-run.d.ts.map +1 -0
- package/dist/src/engine/lens/cache-run.js +159 -0
- package/dist/src/engine/lens/cache-run.js.map +1 -0
- package/dist/src/engine/lens/deadline.d.ts +54 -0
- package/dist/src/engine/lens/deadline.d.ts.map +1 -0
- package/dist/src/engine/lens/deadline.js +111 -0
- package/dist/src/engine/lens/deadline.js.map +1 -0
- package/dist/src/engine/lens/engine-tools.d.ts +13 -0
- package/dist/src/engine/lens/engine-tools.d.ts.map +1 -0
- package/dist/src/engine/lens/engine-tools.js +37 -0
- package/dist/src/engine/lens/engine-tools.js.map +1 -0
- package/dist/src/engine/lens/env.d.ts +23 -0
- package/dist/src/engine/lens/env.d.ts.map +1 -0
- package/dist/src/engine/lens/env.js +42 -0
- package/dist/src/engine/lens/env.js.map +1 -0
- package/dist/src/engine/lens/launch-plan.d.ts +63 -0
- package/dist/src/engine/lens/launch-plan.d.ts.map +1 -0
- package/dist/src/engine/lens/launch-plan.js +203 -0
- package/dist/src/engine/lens/launch-plan.js.map +1 -0
- package/dist/src/engine/lens/leaf-cache.d.ts +22 -0
- package/dist/src/engine/lens/leaf-cache.d.ts.map +1 -0
- package/dist/src/engine/lens/leaf-cache.js +115 -0
- package/dist/src/engine/lens/leaf-cache.js.map +1 -0
- package/dist/src/engine/lens/permits.d.ts +14 -0
- package/dist/src/engine/lens/permits.d.ts.map +1 -0
- package/dist/src/engine/lens/permits.js +18 -0
- package/dist/src/engine/lens/permits.js.map +1 -0
- package/dist/src/engine/lens/registry.d.ts +55 -0
- package/dist/src/engine/lens/registry.d.ts.map +1 -0
- package/dist/src/engine/lens/registry.js +140 -0
- package/dist/src/engine/lens/registry.js.map +1 -0
- package/dist/src/engine/lens/round-lens.d.ts +16 -0
- package/dist/src/engine/lens/round-lens.d.ts.map +1 -0
- package/dist/src/engine/lens/round-lens.js +46 -0
- package/dist/src/engine/lens/round-lens.js.map +1 -0
- package/dist/src/engine/lens/runlens.d.ts +103 -0
- package/dist/src/engine/lens/runlens.d.ts.map +1 -0
- package/dist/src/engine/lens/runlens.js +538 -0
- package/dist/src/engine/lens/runlens.js.map +1 -0
- package/dist/src/engine/lens/section.d.ts +19 -0
- package/dist/src/engine/lens/section.d.ts.map +1 -0
- package/dist/src/engine/lens/section.js +40 -0
- package/dist/src/engine/lens/section.js.map +1 -0
- package/dist/src/engine/lens/semaphore.d.ts +13 -0
- package/dist/src/engine/lens/semaphore.d.ts.map +1 -0
- package/dist/src/engine/lens/semaphore.js +44 -0
- package/dist/src/engine/lens/semaphore.js.map +1 -0
- package/dist/src/engine/lens/tool.d.ts +34 -0
- package/dist/src/engine/lens/tool.d.ts.map +1 -0
- package/dist/src/engine/lens/tool.js +345 -0
- package/dist/src/engine/lens/tool.js.map +1 -0
- package/dist/src/engine/lens/wave.d.ts +63 -0
- package/dist/src/engine/lens/wave.d.ts.map +1 -0
- package/dist/src/engine/lens/wave.js +95 -0
- package/dist/src/engine/lens/wave.js.map +1 -0
- package/dist/src/engine/livesessions.d.ts +21 -0
- package/dist/src/engine/livesessions.d.ts.map +1 -0
- package/dist/src/engine/livesessions.js +57 -0
- package/dist/src/engine/livesessions.js.map +1 -0
- package/dist/src/engine/livewire.d.ts +18 -0
- package/dist/src/engine/livewire.d.ts.map +1 -0
- package/dist/src/engine/livewire.js +31 -0
- package/dist/src/engine/livewire.js.map +1 -0
- package/dist/src/engine/openable.d.ts +37 -0
- package/dist/src/engine/openable.d.ts.map +1 -0
- package/dist/src/engine/openable.js +120 -0
- package/dist/src/engine/openable.js.map +1 -0
- package/dist/src/engine/pisdk.d.ts +226 -0
- package/dist/src/engine/pisdk.d.ts.map +1 -0
- package/dist/src/engine/pisdk.js +552 -0
- package/dist/src/engine/pisdk.js.map +1 -0
- package/dist/src/engine/port.d.ts +144 -0
- package/dist/src/engine/port.d.ts.map +1 -0
- package/dist/src/engine/port.js +16 -0
- package/dist/src/engine/port.js.map +1 -0
- package/dist/src/engine/prompts.d.ts +159 -0
- package/dist/src/engine/prompts.d.ts.map +1 -0
- package/dist/src/engine/prompts.js +339 -0
- package/dist/src/engine/prompts.js.map +1 -0
- package/dist/src/engine/render.d.ts +10 -0
- package/dist/src/engine/render.d.ts.map +1 -0
- package/dist/src/engine/render.js +23 -0
- package/dist/src/engine/render.js.map +1 -0
- package/dist/src/engine/reviewruntime.d.ts +13 -0
- package/dist/src/engine/reviewruntime.d.ts.map +1 -0
- package/dist/src/engine/reviewruntime.js +35 -0
- package/dist/src/engine/reviewruntime.js.map +1 -0
- package/dist/src/engine/reviewsdk.d.ts +75 -0
- package/dist/src/engine/reviewsdk.d.ts.map +1 -0
- package/dist/src/engine/reviewsdk.js +180 -0
- package/dist/src/engine/reviewsdk.js.map +1 -0
- package/dist/src/engine/round.d.ts +166 -0
- package/dist/src/engine/round.d.ts.map +1 -0
- package/dist/src/engine/round.js +543 -0
- package/dist/src/engine/round.js.map +1 -0
- package/dist/src/engine/roundagents.d.ts +17 -0
- package/dist/src/engine/roundagents.d.ts.map +1 -0
- package/dist/src/engine/roundagents.js +49 -0
- package/dist/src/engine/roundagents.js.map +1 -0
- package/dist/src/engine/roundevents.d.ts +110 -0
- package/dist/src/engine/roundevents.d.ts.map +1 -0
- package/dist/src/engine/roundevents.js +276 -0
- package/dist/src/engine/roundevents.js.map +1 -0
- package/dist/src/engine/roundsdk.d.ts +33 -0
- package/dist/src/engine/roundsdk.d.ts.map +1 -0
- package/dist/src/engine/roundsdk.js +76 -0
- package/dist/src/engine/roundsdk.js.map +1 -0
- package/dist/src/engine/sdkruntime.d.ts +23 -0
- package/dist/src/engine/sdkruntime.d.ts.map +1 -0
- package/dist/src/engine/sdkruntime.js +340 -0
- package/dist/src/engine/sdkruntime.js.map +1 -0
- package/dist/src/engine/select.d.ts +16 -0
- package/dist/src/engine/select.d.ts.map +1 -0
- package/dist/src/engine/select.js +32 -0
- package/dist/src/engine/select.js.map +1 -0
- package/dist/src/engine/sessionwrap.d.ts +4 -0
- package/dist/src/engine/sessionwrap.d.ts.map +1 -0
- package/dist/src/engine/sessionwrap.js +31 -0
- package/dist/src/engine/sessionwrap.js.map +1 -0
- package/dist/src/engine/toolfence.d.ts +90 -0
- package/dist/src/engine/toolfence.d.ts.map +1 -0
- package/dist/src/engine/toolfence.js +378 -0
- package/dist/src/engine/toolfence.js.map +1 -0
- package/dist/src/engine/tooluid.d.ts +128 -0
- package/dist/src/engine/tooluid.d.ts.map +1 -0
- package/dist/src/engine/tooluid.js +401 -0
- package/dist/src/engine/tooluid.js.map +1 -0
- package/dist/src/envstrip.d.ts +10 -0
- package/dist/src/envstrip.d.ts.map +1 -0
- package/dist/src/envstrip.js +15 -0
- package/dist/src/envstrip.js.map +1 -0
- package/dist/src/escalationprompt.d.ts +22 -0
- package/dist/src/escalationprompt.d.ts.map +1 -0
- package/dist/src/escalationprompt.js +54 -0
- package/dist/src/escalationprompt.js.map +1 -0
- package/dist/src/execfn.d.ts +29 -0
- package/dist/src/execfn.d.ts.map +1 -0
- package/dist/src/execfn.js +55 -0
- package/dist/src/execfn.js.map +1 -0
- package/dist/src/finding-chain.d.ts +40 -0
- package/dist/src/finding-chain.d.ts.map +1 -0
- package/dist/src/finding-chain.js +76 -0
- package/dist/src/finding-chain.js.map +1 -0
- package/dist/src/finding-row.d.ts +24 -0
- package/dist/src/finding-row.d.ts.map +1 -0
- package/dist/src/finding-row.js +26 -0
- package/dist/src/finding-row.js.map +1 -0
- package/dist/src/findingkey.d.ts +99 -0
- package/dist/src/findingkey.d.ts.map +1 -0
- package/dist/src/findingkey.js +210 -0
- package/dist/src/findingkey.js.map +1 -0
- package/dist/src/findingsrecord.d.ts +175 -0
- package/dist/src/findingsrecord.d.ts.map +1 -0
- package/dist/src/findingsrecord.js +410 -0
- package/dist/src/findingsrecord.js.map +1 -0
- package/dist/src/followup-mode.d.ts +4 -0
- package/dist/src/followup-mode.d.ts.map +1 -0
- package/dist/src/followup-mode.js +6 -0
- package/dist/src/followup-mode.js.map +1 -0
- package/dist/src/gate.d.ts +199 -0
- package/dist/src/gate.d.ts.map +1 -0
- package/dist/src/gate.js +315 -0
- package/dist/src/gate.js.map +1 -0
- package/dist/src/ghcred.d.ts +58 -0
- package/dist/src/ghcred.d.ts.map +1 -0
- package/dist/src/ghcred.js +139 -0
- package/dist/src/ghcred.js.map +1 -0
- package/dist/src/githubAuth.d.ts +32 -0
- package/dist/src/githubAuth.d.ts.map +1 -0
- package/dist/src/githubAuth.js +116 -0
- package/dist/src/githubAuth.js.map +1 -0
- package/dist/src/githubcore.d.ts +20 -0
- package/dist/src/githubcore.d.ts.map +1 -0
- package/dist/src/githubcore.js +20 -0
- package/dist/src/githubcore.js.map +1 -0
- package/dist/src/glob.d.ts +11 -0
- package/dist/src/glob.d.ts.map +1 -0
- package/dist/src/glob.js +69 -0
- package/dist/src/glob.js.map +1 -0
- package/dist/src/guards.d.ts +93 -0
- package/dist/src/guards.d.ts.map +1 -0
- package/dist/src/guards.js +306 -0
- package/dist/src/guards.js.map +1 -0
- package/dist/src/heartbeat.d.ts +29 -0
- package/dist/src/heartbeat.d.ts.map +1 -0
- package/dist/src/heartbeat.js +87 -0
- package/dist/src/heartbeat.js.map +1 -0
- package/dist/src/heuristics.d.ts +247 -0
- package/dist/src/heuristics.d.ts.map +1 -0
- package/dist/src/heuristics.js +927 -0
- package/dist/src/heuristics.js.map +1 -0
- package/dist/src/homes.d.ts +181 -0
- package/dist/src/homes.d.ts.map +1 -0
- package/dist/src/homes.js +242 -0
- package/dist/src/homes.js.map +1 -0
- package/dist/src/hunkheader.d.ts +11 -0
- package/dist/src/hunkheader.d.ts.map +1 -0
- package/dist/src/hunkheader.js +18 -0
- package/dist/src/hunkheader.js.map +1 -0
- package/dist/src/include.d.ts +435 -0
- package/dist/src/include.d.ts.map +1 -0
- package/dist/src/include.js +1692 -0
- package/dist/src/include.js.map +1 -0
- package/dist/src/launchvocab.d.ts +36 -0
- package/dist/src/launchvocab.d.ts.map +1 -0
- package/dist/src/launchvocab.js +59 -0
- package/dist/src/launchvocab.js.map +1 -0
- package/dist/src/ledgercarry.d.ts +24 -0
- package/dist/src/ledgercarry.d.ts.map +1 -0
- package/dist/src/ledgercarry.js +109 -0
- package/dist/src/ledgercarry.js.map +1 -0
- package/dist/src/lensids.d.ts +7 -0
- package/dist/src/lensids.d.ts.map +1 -0
- package/dist/src/lensids.js +53 -0
- package/dist/src/lensids.js.map +1 -0
- package/dist/src/lensplanning.d.ts +8 -0
- package/dist/src/lensplanning.d.ts.map +1 -0
- package/dist/src/lensplanning.js +126 -0
- package/dist/src/lensplanning.js.map +1 -0
- package/dist/src/lensresult.d.ts +94 -0
- package/dist/src/lensresult.d.ts.map +1 -0
- package/dist/src/lensresult.js +162 -0
- package/dist/src/lensresult.js.map +1 -0
- package/dist/src/lenstuning.d.ts +97 -0
- package/dist/src/lenstuning.d.ts.map +1 -0
- package/dist/src/lenstuning.js +326 -0
- package/dist/src/lenstuning.js.map +1 -0
- package/dist/src/lintconfig.d.ts +31 -0
- package/dist/src/lintconfig.d.ts.map +1 -0
- package/dist/src/lintconfig.js +543 -0
- package/dist/src/lintconfig.js.map +1 -0
- package/dist/src/live/events.d.ts +188 -0
- package/dist/src/live/events.d.ts.map +1 -0
- package/dist/src/live/events.js +136 -0
- package/dist/src/live/events.js.map +1 -0
- package/dist/src/live/writer.d.ts +54 -0
- package/dist/src/live/writer.d.ts.map +1 -0
- package/dist/src/live/writer.js +516 -0
- package/dist/src/live/writer.js.map +1 -0
- package/dist/src/localreview.d.ts +128 -0
- package/dist/src/localreview.d.ts.map +1 -0
- package/dist/src/localreview.js +426 -0
- package/dist/src/localreview.js.map +1 -0
- package/dist/src/loosenedtests.d.ts +13 -0
- package/dist/src/loosenedtests.d.ts.map +1 -0
- package/dist/src/loosenedtests.js +188 -0
- package/dist/src/loosenedtests.js.map +1 -0
- package/dist/src/memoryport.d.ts +264 -0
- package/dist/src/memoryport.d.ts.map +1 -0
- package/dist/src/memoryport.js +445 -0
- package/dist/src/memoryport.js.map +1 -0
- package/dist/src/migrations.d.ts +106 -0
- package/dist/src/migrations.d.ts.map +1 -0
- package/dist/src/migrations.js +373 -0
- package/dist/src/migrations.js.map +1 -0
- package/dist/src/oneshot.d.ts +12 -0
- package/dist/src/oneshot.d.ts.map +1 -0
- package/dist/src/oneshot.js +8 -0
- package/dist/src/oneshot.js.map +1 -0
- package/dist/src/packing.d.ts +11 -0
- package/dist/src/packing.d.ts.map +1 -0
- package/dist/src/packing.js +31 -0
- package/dist/src/packing.js.map +1 -0
- package/dist/src/passes.d.ts +16 -0
- package/dist/src/passes.d.ts.map +1 -0
- package/dist/src/passes.js +104 -0
- package/dist/src/passes.js.map +1 -0
- package/dist/src/passtasks.d.ts +68 -0
- package/dist/src/passtasks.d.ts.map +1 -0
- package/dist/src/passtasks.js +360 -0
- package/dist/src/passtasks.js.map +1 -0
- package/dist/src/pathinside.d.ts +5 -0
- package/dist/src/pathinside.d.ts.map +1 -0
- package/dist/src/pathinside.js +9 -0
- package/dist/src/pathinside.js.map +1 -0
- package/dist/src/pibuiltins.d.ts +36 -0
- package/dist/src/pibuiltins.d.ts.map +1 -0
- package/dist/src/pibuiltins.js +83 -0
- package/dist/src/pibuiltins.js.map +1 -0
- package/dist/src/plankey.d.ts +4 -0
- package/dist/src/plankey.d.ts.map +1 -0
- package/dist/src/plankey.js +10 -0
- package/dist/src/plankey.js.map +1 -0
- package/dist/src/planner.d.ts +375 -0
- package/dist/src/planner.d.ts.map +1 -0
- package/dist/src/planner.js +722 -0
- package/dist/src/planner.js.map +1 -0
- package/dist/src/plugin/args.d.ts +19 -0
- package/dist/src/plugin/args.d.ts.map +1 -0
- package/dist/src/plugin/args.js +107 -0
- package/dist/src/plugin/args.js.map +1 -0
- package/dist/src/plugin/index.d.ts +3 -0
- package/dist/src/plugin/index.d.ts.map +1 -0
- package/dist/src/plugin/index.js +14 -0
- package/dist/src/plugin/index.js.map +1 -0
- package/dist/src/plugin/login.d.ts +39 -0
- package/dist/src/plugin/login.d.ts.map +1 -0
- package/dist/src/plugin/login.js +73 -0
- package/dist/src/plugin/login.js.map +1 -0
- package/dist/src/plugin/review.d.ts +27 -0
- package/dist/src/plugin/review.d.ts.map +1 -0
- package/dist/src/plugin/review.js +298 -0
- package/dist/src/plugin/review.js.map +1 -0
- package/dist/src/plugin/runner.d.ts +6 -0
- package/dist/src/plugin/runner.d.ts.map +1 -0
- package/dist/src/plugin/runner.js +65 -0
- package/dist/src/plugin/runner.js.map +1 -0
- package/dist/src/plugin/scan.d.ts +79 -0
- package/dist/src/plugin/scan.d.ts.map +1 -0
- package/dist/src/plugin/scan.js +348 -0
- package/dist/src/plugin/scan.js.map +1 -0
- package/dist/src/plugin/session.d.ts +56 -0
- package/dist/src/plugin/session.d.ts.map +1 -0
- package/dist/src/plugin/session.js +2 -0
- package/dist/src/plugin/session.js.map +1 -0
- package/dist/src/plugin/setup.d.ts +19 -0
- package/dist/src/plugin/setup.d.ts.map +1 -0
- package/dist/src/plugin/setup.js +142 -0
- package/dist/src/plugin/setup.js.map +1 -0
- package/dist/src/plugin/versiongate.d.ts +26 -0
- package/dist/src/plugin/versiongate.d.ts.map +1 -0
- package/dist/src/plugin/versiongate.js +83 -0
- package/dist/src/plugin/versiongate.js.map +1 -0
- package/dist/src/postingkey.d.ts +8 -0
- package/dist/src/postingkey.d.ts.map +1 -0
- package/dist/src/postingkey.js +25 -0
- package/dist/src/postingkey.js.map +1 -0
- package/dist/src/postingpolicy.d.ts +108 -0
- package/dist/src/postingpolicy.d.ts.map +1 -0
- package/dist/src/postingpolicy.js +341 -0
- package/dist/src/postingpolicy.js.map +1 -0
- package/dist/src/pr-identity.d.ts +3 -0
- package/dist/src/pr-identity.d.ts.map +1 -0
- package/dist/src/pr-identity.js +9 -0
- package/dist/src/pr-identity.js.map +1 -0
- package/dist/src/prdelta.d.ts +181 -0
- package/dist/src/prdelta.d.ts.map +1 -0
- package/dist/src/prdelta.js +501 -0
- package/dist/src/prdelta.js.map +1 -0
- package/dist/src/pricing.d.ts +94 -0
- package/dist/src/pricing.d.ts.map +1 -0
- package/dist/src/pricing.js +209 -0
- package/dist/src/pricing.js.map +1 -0
- package/dist/src/priorfindings.d.ts +167 -0
- package/dist/src/priorfindings.d.ts.map +1 -0
- package/dist/src/priorfindings.js +445 -0
- package/dist/src/priorfindings.js.map +1 -0
- package/dist/src/priortasks.d.ts +31 -0
- package/dist/src/priortasks.d.ts.map +1 -0
- package/dist/src/priortasks.js +119 -0
- package/dist/src/priortasks.js.map +1 -0
- package/dist/src/profilelookup.d.ts +59 -0
- package/dist/src/profilelookup.d.ts.map +1 -0
- package/dist/src/profilelookup.js +98 -0
- package/dist/src/profilelookup.js.map +1 -0
- package/dist/src/profileoverrides.d.ts +91 -0
- package/dist/src/profileoverrides.d.ts.map +1 -0
- package/dist/src/profileoverrides.js +313 -0
- package/dist/src/profileoverrides.js.map +1 -0
- package/dist/src/profiles.d.ts +144 -0
- package/dist/src/profiles.d.ts.map +1 -0
- package/dist/src/profiles.js +604 -0
- package/dist/src/profiles.js.map +1 -0
- package/dist/src/promptdoc.d.ts +3 -0
- package/dist/src/promptdoc.d.ts.map +1 -0
- package/dist/src/promptdoc.js +18 -0
- package/dist/src/promptdoc.js.map +1 -0
- package/dist/src/prtarget.d.ts +70 -0
- package/dist/src/prtarget.d.ts.map +1 -0
- package/dist/src/prtarget.js +181 -0
- package/dist/src/prtarget.js.map +1 -0
- package/dist/src/recheckorder.d.ts +32 -0
- package/dist/src/recheckorder.d.ts.map +1 -0
- package/dist/src/recheckorder.js +5 -0
- package/dist/src/recheckorder.js.map +1 -0
- package/dist/src/reviewapi.d.ts +207 -0
- package/dist/src/reviewapi.d.ts.map +1 -0
- package/dist/src/reviewapi.js +939 -0
- package/dist/src/reviewapi.js.map +1 -0
- package/dist/src/reviewbotfindings.d.ts +33 -0
- package/dist/src/reviewbotfindings.d.ts.map +1 -0
- package/dist/src/reviewbotfindings.js +80 -0
- package/dist/src/reviewbotfindings.js.map +1 -0
- package/dist/src/reviewconfig.d.ts +741 -0
- package/dist/src/reviewconfig.d.ts.map +1 -0
- package/dist/src/reviewconfig.js +797 -0
- package/dist/src/reviewconfig.js.map +1 -0
- package/dist/src/reviewdelta.d.ts +51 -0
- package/dist/src/reviewdelta.d.ts.map +1 -0
- package/dist/src/reviewdelta.js +119 -0
- package/dist/src/reviewdelta.js.map +1 -0
- package/dist/src/reviewdest.d.ts +86 -0
- package/dist/src/reviewdest.d.ts.map +1 -0
- package/dist/src/reviewdest.js +142 -0
- package/dist/src/reviewdest.js.map +1 -0
- package/dist/src/reviewerstub.d.ts +12 -0
- package/dist/src/reviewerstub.d.ts.map +1 -0
- package/dist/src/reviewerstub.js +28 -0
- package/dist/src/reviewerstub.js.map +1 -0
- package/dist/src/reviewhost.d.ts +58 -0
- package/dist/src/reviewhost.d.ts.map +1 -0
- package/dist/src/reviewhost.js +135 -0
- package/dist/src/reviewhost.js.map +1 -0
- package/dist/src/reviewpost.d.ts +79 -0
- package/dist/src/reviewpost.d.ts.map +1 -0
- package/dist/src/reviewpost.js +233 -0
- package/dist/src/reviewpost.js.map +1 -0
- package/dist/src/reviewrender.d.ts +154 -0
- package/dist/src/reviewrender.d.ts.map +1 -0
- package/dist/src/reviewrender.js +480 -0
- package/dist/src/reviewrender.js.map +1 -0
- package/dist/src/reviewstate.d.ts +62 -0
- package/dist/src/reviewstate.d.ts.map +1 -0
- package/dist/src/reviewstate.js +167 -0
- package/dist/src/reviewstate.js.map +1 -0
- package/dist/src/reviewstore.d.ts +17 -0
- package/dist/src/reviewstore.d.ts.map +1 -0
- package/dist/src/reviewstore.js +105 -0
- package/dist/src/reviewstore.js.map +1 -0
- package/dist/src/round-progress.d.ts +120 -0
- package/dist/src/round-progress.d.ts.map +1 -0
- package/dist/src/round-progress.js +172 -0
- package/dist/src/round-progress.js.map +1 -0
- package/dist/src/round-stage-deadlines.d.ts +12 -0
- package/dist/src/round-stage-deadlines.d.ts.map +1 -0
- package/dist/src/round-stage-deadlines.js +10 -0
- package/dist/src/round-stage-deadlines.js.map +1 -0
- package/dist/src/session-command.d.ts +19 -0
- package/dist/src/session-command.d.ts.map +1 -0
- package/dist/src/session-command.js +20 -0
- package/dist/src/session-command.js.map +1 -0
- package/dist/src/settledread.d.ts +61 -0
- package/dist/src/settledread.d.ts.map +1 -0
- package/dist/src/settledread.js +135 -0
- package/dist/src/settledread.js.map +1 -0
- package/dist/src/severity.d.ts +167 -0
- package/dist/src/severity.d.ts.map +1 -0
- package/dist/src/severity.js +364 -0
- package/dist/src/severity.js.map +1 -0
- package/dist/src/severityrank.d.ts +8 -0
- package/dist/src/severityrank.d.ts.map +1 -0
- package/dist/src/severityrank.js +16 -0
- package/dist/src/severityrank.js.map +1 -0
- package/dist/src/standing-review.d.ts +45 -0
- package/dist/src/standing-review.d.ts.map +1 -0
- package/dist/src/standing-review.js +43 -0
- package/dist/src/standing-review.js.map +1 -0
- package/dist/src/storerows.d.ts +225 -0
- package/dist/src/storerows.d.ts.map +1 -0
- package/dist/src/storerows.js +7 -0
- package/dist/src/storerows.js.map +1 -0
- package/dist/src/styleguide.d.ts +25 -0
- package/dist/src/styleguide.d.ts.map +1 -0
- package/dist/src/styleguide.js +272 -0
- package/dist/src/styleguide.js.map +1 -0
- package/dist/src/sweepstatus.d.ts +42 -0
- package/dist/src/sweepstatus.d.ts.map +1 -0
- package/dist/src/sweepstatus.js +97 -0
- package/dist/src/sweepstatus.js.map +1 -0
- package/dist/src/templates.d.ts +243 -0
- package/dist/src/templates.d.ts.map +1 -0
- package/dist/src/templates.js +847 -0
- package/dist/src/templates.js.map +1 -0
- package/dist/src/types.d.ts +639 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +90 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/unifieddiff.d.ts +22 -0
- package/dist/src/unifieddiff.d.ts.map +1 -0
- package/dist/src/unifieddiff.js +176 -0
- package/dist/src/unifieddiff.js.map +1 -0
- package/dist/src/yieldloop.d.ts +2 -0
- package/dist/src/yieldloop.d.ts.map +1 -0
- package/dist/src/yieldloop.js +14 -0
- package/dist/src/yieldloop.js.map +1 -0
- package/package.json +60 -4
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
// Posting-time guards, all applied at the one moment that matters:
|
|
2
|
+
// immediately before a review reaches GitHub.
|
|
3
|
+
//
|
|
4
|
+
// 1. Never re-block a head a human already approved. A non-author human
|
|
5
|
+
// approval at the head under review downgrades a REQUEST_CHANGES to a
|
|
6
|
+
// COMMENT: the bot still reports everything it found, it just stops
|
|
7
|
+
// holding the gate against a person who has already looked.
|
|
8
|
+
// 2. No-op when there is no new evidence. The mark lives in
|
|
9
|
+
// `reviewed_heads` (state.ts): same head AND no author reply since ⇒ post
|
|
10
|
+
// nothing. The same mark is what the post-approval delta recheck reads.
|
|
11
|
+
// 3. Re-check merged/closed state immediately before posting, so no review
|
|
12
|
+
// lands at or after a merge.
|
|
13
|
+
// 5. The live head must be the head the round actually reviewed, so a push
|
|
14
|
+
// landing between a round's validation and its posting step never gets
|
|
15
|
+
// the stale review posted against it. On the gate route the intent's
|
|
16
|
+
// commit_id is the reviewed head, so a mismatch with the guard-3 live
|
|
17
|
+
// read refuses; a session's post carries QCR_EXPECTED_HEAD
|
|
18
|
+
// (cited by its round prompt) as the intent's commit_id, and a post that
|
|
19
|
+
// names none carries no expectation, so a session whose prompt does not
|
|
20
|
+
// set it is never wedged.
|
|
21
|
+
// 4. No green CI at this head ⇒ APPROVE is unavailable. The review still
|
|
22
|
+
// posts — as a COMMENT with the approval withheld and a plain note saying
|
|
23
|
+
// so — and the PR is re-queued when CI goes green. The classifier lives
|
|
24
|
+
// in cigate.ts.
|
|
25
|
+
//
|
|
26
|
+
// All of them are installed on the one MutationGate (gate.ts `MutationGuard`),
|
|
27
|
+
// not on a call site, so no posting route in the daemon can reach GitHub
|
|
28
|
+
// around them. The sessions post through scripts/post-review.sh,
|
|
29
|
+
// approve-pr.sh and reply-thread.sh, Node-only clients of the daemon's post
|
|
30
|
+
// endpoint (src/ipc/postshim.ts); the daemon builds the intent and hands it to
|
|
31
|
+
// the same gate, so these guards bind them too. The gate's after-step makes
|
|
32
|
+
// the reviewed-head stamp. tests/guards.test.ts drives the real gate over the
|
|
33
|
+
// cases.
|
|
34
|
+
// Guard 2 never gates an APPROVE. Guard 4 softens rather than refuses: an
|
|
35
|
+
// approval over red CI posts as a COMMENT with the approval withheld.
|
|
36
|
+
//
|
|
37
|
+
// Nothing here dismisses, retracts or edits an existing review. A guard's only
|
|
38
|
+
// powers are to refuse a mutation and to soften its event to COMMENT — a
|
|
39
|
+
// REQUEST_CHANGES a human's approval outranks (guard 1), an APPROVE red CI
|
|
40
|
+
// withholds (guard 4).
|
|
41
|
+
import { ciBlocksApproval, classifyCi, withholdApproval, } from "./cigate.js";
|
|
42
|
+
import { standingReview } from "./standing-review.js";
|
|
43
|
+
/** A bot's login: the App's own, or any `[bot]` account. Bot-authored PRs
|
|
44
|
+
* never enter the state machine (spec §3, src/statemachine.ts re-exports
|
|
45
|
+
* this), and a bot's approval is no human's. */
|
|
46
|
+
export function isBotAuthor(author, botLogin) {
|
|
47
|
+
return author === botLogin || author.endsWith("[bot]");
|
|
48
|
+
}
|
|
49
|
+
/** Mutation kinds that put words on a PR — the ones the guards inspect. */
|
|
50
|
+
export const POSTING_KINDS = new Set([
|
|
51
|
+
"create_review",
|
|
52
|
+
"create_review_comment_reply",
|
|
53
|
+
"create_issue_comment",
|
|
54
|
+
]);
|
|
55
|
+
// ---- guard 1: a human already approved this head --------------------------
|
|
56
|
+
/**
|
|
57
|
+
* The login of a non-author human whose APPROVED review stands at `head_sha`,
|
|
58
|
+
* or null. "Stands" means it is that person's LATEST verdict-bearing review:
|
|
59
|
+
* a later CHANGES_REQUESTED or DISMISSED by the same person retires it.
|
|
60
|
+
* COMMENTED/PENDING reviews carry no verdict and are ignored.
|
|
61
|
+
*
|
|
62
|
+
* Reviews are read in submission order, which is the order the REST endpoint
|
|
63
|
+
* returns them in.
|
|
64
|
+
*/
|
|
65
|
+
export function humanApprovalAtHead(reviews, opts) {
|
|
66
|
+
if (!opts.head_sha)
|
|
67
|
+
return null;
|
|
68
|
+
const latest = new Map();
|
|
69
|
+
for (const r of reviews) {
|
|
70
|
+
const state = (r.state ?? "").toUpperCase();
|
|
71
|
+
if (state !== "APPROVED" && state !== "CHANGES_REQUESTED" && state !== "DISMISSED")
|
|
72
|
+
continue;
|
|
73
|
+
if (!r.user)
|
|
74
|
+
continue;
|
|
75
|
+
latest.set(r.user, { state, commit_id: r.commit_id });
|
|
76
|
+
}
|
|
77
|
+
for (const [user, r] of latest) {
|
|
78
|
+
if (r.state !== "APPROVED")
|
|
79
|
+
continue;
|
|
80
|
+
if (r.commit_id !== opts.head_sha)
|
|
81
|
+
continue;
|
|
82
|
+
if (user === opts.author)
|
|
83
|
+
continue; // GitHub forbids it, but never trust that
|
|
84
|
+
if (isBotAuthor(user, opts.botLogin))
|
|
85
|
+
continue;
|
|
86
|
+
return user;
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
/** The note the downgraded review carries, so the softer event is never a
|
|
91
|
+
* silent change of mind. */
|
|
92
|
+
export function downgradeNote(approver, headSha) {
|
|
93
|
+
return (`_Not blocking: **@${approver}** has already approved this head (\`${headSha.slice(0, 7)}\`). ` +
|
|
94
|
+
"The findings above are reported for information only — this review does not request changes._");
|
|
95
|
+
}
|
|
96
|
+
/** REQUEST_CHANGES → COMMENT, findings untouched, with the note appended. */
|
|
97
|
+
export function downgradeForHumanApproval(body, approver, headSha) {
|
|
98
|
+
return {
|
|
99
|
+
...body,
|
|
100
|
+
event: "COMMENT",
|
|
101
|
+
body: `${body.body ?? ""}\n\n${downgradeNote(approver, headSha)}`,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
// ---- guard 2: no new evidence ---------------------------------------------
|
|
105
|
+
/**
|
|
106
|
+
* Is there anything new to review at `head_sha`? True unless the mark sits on
|
|
107
|
+
* exactly this head and no author reply has landed since it was stamped.
|
|
108
|
+
* An unknown head (empty string) is always "new": guessing would suppress a
|
|
109
|
+
* real review.
|
|
110
|
+
*/
|
|
111
|
+
export function hasNewEvidence(mark, headSha) {
|
|
112
|
+
if (!mark || !headSha)
|
|
113
|
+
return true;
|
|
114
|
+
// A NEEDS_HUMAN/ESCALATE mark (legacy vocabulary) is an undecided review:
|
|
115
|
+
// it must never suppress a re-run or a posting — a re-triggered PR with only
|
|
116
|
+
// an undecided mark deserves a full round. Read through the one
|
|
117
|
+
// standing-review interpretation, so this guard and dispatch's skip can
|
|
118
|
+
// never disagree about what the mark says.
|
|
119
|
+
if (standingReview(mark).kind === "undecided")
|
|
120
|
+
return true;
|
|
121
|
+
if (mark.head_sha !== headSha)
|
|
122
|
+
return true;
|
|
123
|
+
// `>=`, not `>`: a reply stamped in the same millisecond as the review is
|
|
124
|
+
// ambiguous, and the safe reading of an ambiguous reply is "new evidence".
|
|
125
|
+
// Re-stamping the mark clears the reply, so this cannot loop.
|
|
126
|
+
if (mark.last_author_reply_at && mark.last_author_reply_at >= mark.reviewed_at)
|
|
127
|
+
return true;
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Read the checks at a head for guard 4. Null means "cannot see CI" — no
|
|
132
|
+
* adapter method, no head, or a failed read — and a guard never blocks on what
|
|
133
|
+
* it cannot see: failing closed here would withhold every approval during a
|
|
134
|
+
* GitHub outage, turning an outage into a pile of parked PRs. What it CAN see
|
|
135
|
+
* it enforces without exception, infra failures included.
|
|
136
|
+
*/
|
|
137
|
+
async function readCi(deps, pr, head, log) {
|
|
138
|
+
if (!deps.adapter.listChecks || !head)
|
|
139
|
+
return null;
|
|
140
|
+
try {
|
|
141
|
+
return classifyCi(await deps.adapter.listChecks(head));
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
log(`guard: checks read failed on #${pr}`, err);
|
|
145
|
+
deps.store.logEvent("approval_ci_unreadable", pr, { head_sha: head, error: String(err) });
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
export function makePostingGuard(deps) {
|
|
150
|
+
const log = deps.log ?? (() => { });
|
|
151
|
+
const refuse = (intent, pr, reason, extra = {}) => {
|
|
152
|
+
log(`guard: refused ${intent.kind} on #${pr} — ${reason}`);
|
|
153
|
+
deps.store.logEvent("posting_guard_blocked", pr, { kind: intent.kind, reason, ...extra });
|
|
154
|
+
return { block: reason };
|
|
155
|
+
};
|
|
156
|
+
return {
|
|
157
|
+
async before(intent) {
|
|
158
|
+
if (!POSTING_KINDS.has(intent.kind))
|
|
159
|
+
return {};
|
|
160
|
+
const pr = intent.pr;
|
|
161
|
+
if (!pr)
|
|
162
|
+
return {}; // no PR to check against — nothing this guard can say
|
|
163
|
+
const body = (intent.body ?? {});
|
|
164
|
+
// --- guard 3: is the PR still open, right now? ---
|
|
165
|
+
let ref;
|
|
166
|
+
if (deps.guards.recheck_pr_state_before_post) {
|
|
167
|
+
try {
|
|
168
|
+
ref = await deps.adapter.getPr(pr);
|
|
169
|
+
}
|
|
170
|
+
catch (err) {
|
|
171
|
+
// Fail closed: an unverifiable PR state is exactly when a post-merge
|
|
172
|
+
// review could land. The session retries; reconcile re-derives the
|
|
173
|
+
// truth.
|
|
174
|
+
return refuse(intent, pr, "pr-unreadable", { error: String(err) });
|
|
175
|
+
}
|
|
176
|
+
if (ref.merged)
|
|
177
|
+
return refuse(intent, pr, "pr-merged");
|
|
178
|
+
if (ref.state === "closed")
|
|
179
|
+
return refuse(intent, pr, "pr-closed");
|
|
180
|
+
}
|
|
181
|
+
if (intent.kind !== "create_review")
|
|
182
|
+
return {};
|
|
183
|
+
// The head the review is ABOUT: the payload's commit_id when it has one,
|
|
184
|
+
// otherwise whatever the PR points at now.
|
|
185
|
+
const head = body.commit_id || ref?.head_sha || "";
|
|
186
|
+
// --- guard 5: the head the review is about must still BE the head ---
|
|
187
|
+
// A push landing between a round's validation and its posting step
|
|
188
|
+
// would otherwise land the stale review against the new head. Fires
|
|
189
|
+
// only where the data exists —
|
|
190
|
+
// an intent without a commit_id carries no expectation, and without the
|
|
191
|
+
// guard-3 read there is no live head to compare against. Shas compare
|
|
192
|
+
// case-insensitively: git shas are hex, and an LLM-written
|
|
193
|
+
// commit_id with drifted case must never fake a "moved" head.
|
|
194
|
+
// A deferred session review the daemon delivers
|
|
195
|
+
// (`intent.postingRetry`) posts at its ORIGINAL commit_id even when the
|
|
196
|
+
// PR has moved on; admission pins the key to
|
|
197
|
+
// that commit_id and marker.
|
|
198
|
+
if (deps.guards.refuse_on_head_drift &&
|
|
199
|
+
intent.postingRetry === undefined &&
|
|
200
|
+
body.commit_id &&
|
|
201
|
+
ref &&
|
|
202
|
+
ref.head_sha.toLowerCase() !== body.commit_id.toLowerCase()) {
|
|
203
|
+
return refuse(intent, pr, "head-drift", {
|
|
204
|
+
expected_head: body.commit_id,
|
|
205
|
+
live_head: ref.head_sha,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
// --- guard 2: has anything happened since the last review? ---
|
|
209
|
+
//
|
|
210
|
+
// The escalation note is exempt, and only it. Guard 2 exists to stop the
|
|
211
|
+
// bot re-reviewing a head it already reviewed. An escalation note is not
|
|
212
|
+
// a review of the head: it carries no verdict, claims no head (see
|
|
213
|
+
// `after` below), and by design lands right after the round's own review
|
|
214
|
+
// — i.e. always at a head the mark has just been stamped on, so guard 2
|
|
215
|
+
// would suppress every one of them. Its duplicate-suppression is strictly
|
|
216
|
+
// narrower than guard 2's: the `escalations` ledger refuses the same
|
|
217
|
+
// person + the same thing on the same PR forever, and `[escalation]
|
|
218
|
+
// max_per_pr` caps the rest. Every other guard still binds it —
|
|
219
|
+
// merged/closed (3) and head drift (5) both ran above, unconditionally.
|
|
220
|
+
//
|
|
221
|
+
// An APPROVE is exempt too, as a matter of design. Every approval reaching the gate is a
|
|
222
|
+
// session's approve-pr.sh POST the daemon delivers, and the one that
|
|
223
|
+
// meets an already-stamped head is the CI-green retry of a withheld
|
|
224
|
+
// approval: its COMMENT stamped the head, and refusing the APPROVE here
|
|
225
|
+
// would strand the approval that withholding promised.
|
|
226
|
+
const mechanical = intent.reviewPurpose === "escalation";
|
|
227
|
+
const approval = (body.event ?? "").toUpperCase() === "APPROVE";
|
|
228
|
+
if (deps.guards.skip_unchanged_head &&
|
|
229
|
+
!mechanical &&
|
|
230
|
+
!approval &&
|
|
231
|
+
!hasNewEvidence(deps.store.reviewedHead(pr), head)) {
|
|
232
|
+
return refuse(intent, pr, "no-new-evidence", { head_sha: head });
|
|
233
|
+
}
|
|
234
|
+
// --- guard 1: a human approved this head; do not hold the gate ---
|
|
235
|
+
if (deps.guards.downgrade_on_human_approval &&
|
|
236
|
+
(body.event ?? "").toUpperCase() === "REQUEST_CHANGES") {
|
|
237
|
+
let approver = null;
|
|
238
|
+
try {
|
|
239
|
+
approver = humanApprovalAtHead(await deps.adapter.listReviews(pr), {
|
|
240
|
+
head_sha: head,
|
|
241
|
+
author: ref?.author ?? "",
|
|
242
|
+
botLogin: deps.botLogin,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
catch (err) {
|
|
246
|
+
// A failed read must not block a review — the worst case here is an
|
|
247
|
+
// unsoftened review, not a post-merge or duplicate one.
|
|
248
|
+
log(`guard: review listing failed on #${pr}`, err);
|
|
249
|
+
}
|
|
250
|
+
if (approver) {
|
|
251
|
+
log(`guard: #${pr} REQUEST_CHANGES → COMMENT (@${approver} approved ${head.slice(0, 7)})`);
|
|
252
|
+
deps.store.logEvent("posting_guard_downgraded", pr, { approver, head_sha: head });
|
|
253
|
+
return {
|
|
254
|
+
intent: {
|
|
255
|
+
...intent,
|
|
256
|
+
body: downgradeForHumanApproval(body, approver, head),
|
|
257
|
+
note: `post COMMENT review on #${pr} (downgraded: @${approver} approved this head)`,
|
|
258
|
+
},
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
// --- guard 4: no green CI at this head ⇒ no approval ---
|
|
263
|
+
if (deps.guards.block_approve_on_red_ci && (body.event ?? "").toUpperCase() === "APPROVE") {
|
|
264
|
+
const ci = await readCi(deps, pr, head, log);
|
|
265
|
+
if (ci && ciBlocksApproval(ci, { noChecksIsRed: deps.guards.no_checks_is_red })) {
|
|
266
|
+
log(`guard: #${pr} APPROVE → COMMENT (CI ${ci} at ${head.slice(0, 7)})`);
|
|
267
|
+
deps.store.logEvent("approval_withheld_red_ci", pr, { head_sha: head, ci_state: ci });
|
|
268
|
+
// The promise this note makes to the author — "waiting on CI alone" —
|
|
269
|
+
// is kept by the mark: the `ci_completed` trigger reads it and
|
|
270
|
+
// re-queues the PR the moment CI goes green (cigate.ts).
|
|
271
|
+
deps.store.recordApprovalWithheld(pr, { head_sha: head, ci_state: ci, reason: "red-ci" });
|
|
272
|
+
return {
|
|
273
|
+
intent: {
|
|
274
|
+
...intent,
|
|
275
|
+
body: withholdApproval(body, ci, head),
|
|
276
|
+
note: `post COMMENT review on #${pr} (approval withheld: CI ${ci} at this head)`,
|
|
277
|
+
},
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
// Green (or invisible) CI: no approval is being withheld here any more.
|
|
281
|
+
if (ci === "green")
|
|
282
|
+
deps.store.clearApprovalWithheld(pr);
|
|
283
|
+
}
|
|
284
|
+
return {};
|
|
285
|
+
},
|
|
286
|
+
after(intent, result) {
|
|
287
|
+
// The mark is stamped only for a substantive review that really reached
|
|
288
|
+
// GitHub. A mechanically-authored COMMENT — the migration pre-check,
|
|
289
|
+
// the escalation note — is deterministic mechanics,
|
|
290
|
+
// not the round's verdict; letting one claim the head makes guard 2
|
|
291
|
+
// suppress the substantive review that follows. Keyed on the PRESENCE of
|
|
292
|
+
// a `reviewPurpose` rather than on each spelling, so a future purpose
|
|
293
|
+
// cannot claim a head by being forgotten here.
|
|
294
|
+
if (intent.kind !== "create_review" || intent.reviewPurpose || !result.executed || !intent.pr)
|
|
295
|
+
return;
|
|
296
|
+
const body = (intent.body ?? {});
|
|
297
|
+
if (!body.commit_id)
|
|
298
|
+
return;
|
|
299
|
+
deps.store.recordReviewedHead(intent.pr, {
|
|
300
|
+
head_sha: body.commit_id,
|
|
301
|
+
posted_event: (body.event ?? "").toUpperCase() || null,
|
|
302
|
+
});
|
|
303
|
+
},
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
//# sourceMappingURL=guards.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guards.js","sourceRoot":"","sources":["../../src/guards.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export declare const HEARTBEAT_FILE = "heartbeat.json";
|
|
2
|
+
export interface Beat {
|
|
3
|
+
/** Counts up with every write. */
|
|
4
|
+
seq: number;
|
|
5
|
+
/** When it was written (ms since the epoch). */
|
|
6
|
+
at: number;
|
|
7
|
+
pid: number;
|
|
8
|
+
/** The latest deadline of a turn in flight; null while none runs. */
|
|
9
|
+
deadline_at: number | null;
|
|
10
|
+
/** Process groups the driver had running when it wrote this. */
|
|
11
|
+
pgids: number[];
|
|
12
|
+
}
|
|
13
|
+
/** A turn in flight ends at `at`: the beat carries it until the returned
|
|
14
|
+
* release is called. Cheap and inert when no heartbeat is running. The beat is
|
|
15
|
+
* rewritten at once: a driver that freezes in the turn's first moments (a
|
|
16
|
+
* synchronous loop on the SDK runtime stops the timer too) would otherwise leave
|
|
17
|
+
* a last beat without the deadline, and the watchdog would never act. */
|
|
18
|
+
export declare function trackDeadline(at: number): () => void;
|
|
19
|
+
/** Read a beat; null when the file is missing or is not one. */
|
|
20
|
+
export declare function readBeat(path: string): Beat | null;
|
|
21
|
+
/** Write a beat now and every `intervalMs` after; returns the stop. The timer
|
|
22
|
+
* never holds the process open. A write that fails is skipped: a heartbeat that
|
|
23
|
+
* cannot be written reads as a stopped one, which is what it is. */
|
|
24
|
+
export declare function startHeartbeat(path: string, o?: {
|
|
25
|
+
intervalMs?: number;
|
|
26
|
+
now?: () => number;
|
|
27
|
+
pgids?: () => readonly number[];
|
|
28
|
+
}): () => void;
|
|
29
|
+
//# sourceMappingURL=heartbeat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"heartbeat.d.ts","sourceRoot":"","sources":["../../src/heartbeat.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,cAAc,mBAAmB,CAAC;AAE/C,MAAM,WAAW,IAAI;IACnB,kCAAkC;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,gDAAgD;IAChD,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,qEAAqE;IACrE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,gEAAgE;IAChE,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAMD;;;;yEAIyE;AACzE,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,IAAI,CAQpD;AAQD,gEAAgE;AAChE,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAclD;AAED;;oEAEoE;AACpE,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,CAAC,GAAE;IACD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,SAAS,MAAM,EAAE,CAAC;CAC5B,GACL,MAAM,IAAI,CA2BZ"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// The heartbeat of a detached review run: a small file its driver rewrites on
|
|
2
|
+
// a timer, which an OUTSIDE process (the watchdog in reviewdetach.ts) reads.
|
|
3
|
+
//
|
|
4
|
+
// An in-process deadline cannot cover a frozen event loop: a synchronous loop
|
|
5
|
+
// stops every timer, the budget's included, and the signal handlers with them.
|
|
6
|
+
// What the driver cannot say for itself, a file that stops advancing says for
|
|
7
|
+
// it. The beat also names the latest deadline of the turns in flight and the
|
|
8
|
+
// process groups of the pi children, so the watchdog can reach the children
|
|
9
|
+
// the driver's own group does not hold.
|
|
10
|
+
import { renameSync, readFileSync, writeFileSync } from "node:fs";
|
|
11
|
+
export const HEARTBEAT_FILE = "heartbeat.json";
|
|
12
|
+
const deadlines = new Set();
|
|
13
|
+
/** Writes a beat now: set while a heartbeat runs. */
|
|
14
|
+
let beatNow = null;
|
|
15
|
+
/** A turn in flight ends at `at`: the beat carries it until the returned
|
|
16
|
+
* release is called. Cheap and inert when no heartbeat is running. The beat is
|
|
17
|
+
* rewritten at once: a driver that freezes in the turn's first moments (a
|
|
18
|
+
* synchronous loop on the SDK runtime stops the timer too) would otherwise leave
|
|
19
|
+
* a last beat without the deadline, and the watchdog would never act. */
|
|
20
|
+
export function trackDeadline(at) {
|
|
21
|
+
const entry = { at };
|
|
22
|
+
deadlines.add(entry);
|
|
23
|
+
beatNow?.();
|
|
24
|
+
return () => {
|
|
25
|
+
deadlines.delete(entry);
|
|
26
|
+
beatNow?.();
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function latestDeadline() {
|
|
30
|
+
let max = null;
|
|
31
|
+
for (const d of deadlines)
|
|
32
|
+
if (max === null || d.at > max)
|
|
33
|
+
max = d.at;
|
|
34
|
+
return max;
|
|
35
|
+
}
|
|
36
|
+
/** Read a beat; null when the file is missing or is not one. */
|
|
37
|
+
export function readBeat(path) {
|
|
38
|
+
try {
|
|
39
|
+
const b = JSON.parse(readFileSync(path, "utf8"));
|
|
40
|
+
if (typeof b.at !== "number" || typeof b.seq !== "number")
|
|
41
|
+
return null;
|
|
42
|
+
return {
|
|
43
|
+
seq: b.seq,
|
|
44
|
+
at: b.at,
|
|
45
|
+
pid: typeof b.pid === "number" ? b.pid : 0,
|
|
46
|
+
deadline_at: typeof b.deadline_at === "number" ? b.deadline_at : null,
|
|
47
|
+
pgids: Array.isArray(b.pgids) ? b.pgids.filter((p) => Number.isInteger(p)) : [],
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/** Write a beat now and every `intervalMs` after; returns the stop. The timer
|
|
55
|
+
* never holds the process open. A write that fails is skipped: a heartbeat that
|
|
56
|
+
* cannot be written reads as a stopped one, which is what it is. */
|
|
57
|
+
export function startHeartbeat(path, o = {}) {
|
|
58
|
+
const now = o.now ?? Date.now;
|
|
59
|
+
let seq = 0;
|
|
60
|
+
const beat = () => {
|
|
61
|
+
const b = {
|
|
62
|
+
seq: ++seq,
|
|
63
|
+
at: now(),
|
|
64
|
+
pid: process.pid,
|
|
65
|
+
deadline_at: latestDeadline(),
|
|
66
|
+
pgids: [...(o.pgids?.() ?? [])],
|
|
67
|
+
};
|
|
68
|
+
try {
|
|
69
|
+
// renamed into place: the watchdog never reads half a beat
|
|
70
|
+
writeFileSync(`${path}.tmp`, JSON.stringify(b));
|
|
71
|
+
renameSync(`${path}.tmp`, path);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
// see above
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
beat();
|
|
78
|
+
beatNow = beat;
|
|
79
|
+
const timer = setInterval(beat, o.intervalMs ?? 2_000);
|
|
80
|
+
timer.unref();
|
|
81
|
+
return () => {
|
|
82
|
+
clearInterval(timer);
|
|
83
|
+
if (beatNow === beat)
|
|
84
|
+
beatNow = null;
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=heartbeat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"heartbeat.js","sourceRoot":"","sources":["../../src/heartbeat.ts"],"names":[],"mappings":"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"}
|