@joshuafolkken/kit 1.1784.0 → 1.2116.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/.claude/agents/reviewer-verification.md +19 -0
- package/.claude/agents/reviewer.md +19 -0
- package/.claude/settings.json +5 -6
- package/.claude/skills/dependency-update/SKILL.md +9 -10
- package/.claude/skills/workflow-commands/SKILL.md +6 -6
- package/.claude/skills/workflow-commands/background-commands.md +8 -5
- package/.claude/skills/workflow-commands/backlogrun-child.md +3 -1
- package/.claude/skills/workflow-commands/backlogrun-lanes.md +1 -1
- package/.claude/skills/workflow-commands/backlogrun-park.md +5 -2
- package/.claude/skills/workflow-commands/backlogrun-progress.md +2 -3
- package/.claude/skills/workflow-commands/backlogrun-recovery.md +1 -1
- package/.claude/skills/workflow-commands/backlogrun-steps.md +3 -2
- package/.claude/skills/workflow-commands/backlogrun.md +1 -1
- package/.claude/skills/workflow-commands/chain-rule.md +41 -32
- package/.claude/skills/workflow-commands/delegation.md +6 -6
- package/.claude/skills/workflow-commands/entry-sequence.md +2 -2
- package/.claude/skills/workflow-commands/followup.md +7 -5
- package/.claude/skills/workflow-commands/fullrun-steps.md +6 -6
- package/.claude/skills/workflow-commands/fullrun.md +1 -1
- package/.claude/skills/workflow-commands/issue-comments.md +9 -4
- package/.claude/skills/workflow-commands/issue-fold-existing.md +2 -1
- package/.claude/skills/workflow-commands/kickoff.md +2 -2
- package/.claude/skills/workflow-commands/observation-filing.md +1 -1
- package/.claude/skills/workflow-commands/observation-ledger.md +6 -4
- package/.claude/skills/workflow-commands/pre-gate-cut.md +9 -7
- package/.claude/skills/workflow-commands/prerequisite.md +3 -2
- package/.claude/skills/workflow-commands/retrospective.md +2 -2
- package/.claude/skills/workflow-commands/split-assessment.md +7 -5
- package/.codex/hooks.json +5 -5
- package/.github/actions/setup-pnpm/action.yml +9 -16
- package/.github/dependabot.yml +16 -0
- package/.github/workflows/auto-tag.yml +45 -0
- package/.github/workflows/ci.yml +155 -15
- package/.github/workflows/dependabot-auto-merge.yml +63 -4
- package/.github/workflows/production.yml +8 -0
- package/.github/workflows/publish.yml +60 -45
- package/.vscode/settings.json +19 -0
- package/CLAUDE.md +5 -12
- package/SECURITY.md +2 -2
- package/dist/CLAUDE.md +5 -12
- package/dist/commands/document-read-cli.js +2 -1
- package/dist/commands/document-section-main.js +2 -1
- package/dist/commands/read-set-cli.js +194 -134
- package/dist/commands/run-prep-main.js +9694 -10173
- package/dist/commands/run-step-cli.js +22138 -18285
- package/dist/hooks/audit-provision.js +23 -5
- package/dist/hooks/chunk-3GKE653K.js +6204 -0
- package/dist/hooks/chunk-45CJJOO7.js +1243 -0
- package/dist/hooks/{chunk-CWMBGKYW.js → chunk-5PM2JRGV.js} +2153 -856
- package/dist/hooks/{chunk-WR2KQAYZ.js → chunk-7SIUNQXK.js} +1207 -1470
- package/dist/hooks/{chunk-O2YBIDSI.js → chunk-CQD4LJE6.js} +1682 -1130
- package/dist/hooks/{chunk-VWWCFGWK.js → chunk-OPSRGWFU.js} +1 -1
- package/dist/hooks/{chunk-XGBNSWEI.js → chunk-UJ3FPMMM.js} +132 -49
- package/dist/hooks/chunk-VVNYJWEI.js +30 -0
- package/dist/hooks/chunk-Z6DQJKH3.js +2806 -0
- package/dist/hooks/codex-hook-adapter.js +8 -8
- package/dist/hooks/format-edited.js +4 -5
- package/dist/hooks/inputs.json +386 -360
- package/dist/hooks/pretool-guard.js +7 -6
- package/dist/hooks/session-lang.js +101 -258
- package/dist/hooks/stop-guard.js +1744 -2576
- package/dist/josh.js +7133 -6368
- package/dist/version/index.js +161 -1
- package/eslint/rules/comment-why-only.js +108 -0
- package/package.json +16 -9
- package/prompts/coding-standards.md +1 -1
- package/prompts/collaboration-workflow/file-edits.md +14 -11
- package/prompts/collaboration-workflow/issue-citation.md +0 -4
- package/prompts/collaboration-workflow/issue-template.md +40 -21
- package/prompts/collaboration-workflow/lane-instructions.md +3 -1
- package/prompts/collaboration-workflow/measurement.md +8 -1
- package/prompts/collaboration-workflow/operating-rules.md +11 -2
- package/prompts/collaboration-workflow/output-bounds.md +6 -2
- package/prompts/collaboration-workflow/plan-comment.md +1 -1
- package/prompts/collaboration-workflow/principles.md +9 -0
- package/prompts/collaboration-workflow/residency.md +3 -2
- package/prompts/collaboration-workflow/rule-delivery.md +13 -1
- package/prompts/collaboration-workflow/upstream-interrupt.md +2 -2
- package/prompts/collaboration-workflow/wip-cap.md +3 -1
- package/prompts/review-rubric.md +8 -0
- package/prompts/review.md +31 -22
- package/prompts/testing-guide.md +1 -0
- package/scripts/agent/agent-argv.ts +14 -16
- package/scripts/agent/agent-provider.ts +138 -0
- package/scripts/agent/agent-role-profile.ts +108 -156
- package/scripts/agent/agent-safe-text.ts +20 -5
- package/scripts/agent/api-usage-limit.ts +65 -0
- package/scripts/agent/claude-agent-argv.ts +19 -9
- package/scripts/agent/codex-agent-argv.ts +118 -22
- package/scripts/agent/usage-limit-reset.ts +179 -0
- package/scripts/auth/claude-token-output.ts +2 -2
- package/scripts/auto-ok/auto-ok-author.ts +53 -0
- package/scripts/auto-ok/auto-ok-cli.ts +20 -9
- package/scripts/backlog/backlog-defect-priority.ts +1 -1
- package/scripts/backlog/backlog-drive-cli.ts +6 -1
- package/scripts/backlog/backlog-drive-hold.ts +3 -3
- package/scripts/backlog/backlog-drive-idle.ts +10 -0
- package/scripts/backlog/backlog-drive-launch-pass.ts +90 -0
- package/scripts/backlog/backlog-drive-launch.ts +8 -2
- package/scripts/backlog/backlog-drive-named-offer.ts +73 -30
- package/scripts/backlog/backlog-drive-named.ts +28 -7
- package/scripts/backlog/backlog-drive-paused.ts +5 -4
- package/scripts/backlog/backlog-drive-restore.ts +11 -3
- package/scripts/backlog/backlog-drive.ts +21 -60
- package/scripts/backlog/backlog-gate-scope.ts +61 -0
- package/scripts/backlog/backlog-measure-close.ts +112 -0
- package/scripts/backlog/backlog-next.ts +39 -49
- package/scripts/backlog/backlog-occupied.ts +2 -2
- package/scripts/backlog/backlog-overlap.ts +42 -8
- package/scripts/backlog/backlog-plan-cli.ts +4 -1
- package/scripts/backlog/backlog-plan-comment.ts +81 -0
- package/scripts/backlog/backlog-plan-read.ts +19 -6
- package/scripts/backlog/backlog-pool.ts +50 -12
- package/scripts/backlog/backlog-rank.ts +60 -13
- package/scripts/backlog/backlog-stalled-detect.ts +2 -1
- package/scripts/backlog/backlog-waves.ts +17 -2
- package/scripts/backlog/backlogrun-launch.ts +7 -4
- package/scripts/cost-runtime/context-cut-payback.ts +27 -25
- package/scripts/cost-runtime/cost-cli.ts +37 -16
- package/scripts/cost-runtime/cost-pricing.ts +9 -0
- package/scripts/cost-runtime/cost-verdict.ts +4 -1
- package/scripts/delegation/delegation-policy.ts +2 -2
- package/scripts/delegation/duplicate-read-guard.ts +1 -0
- package/scripts/delegation/investigation-guard.ts +14 -2
- package/scripts/delegation/investigation-reads.ts +45 -23
- package/scripts/dependabot/dependabot-cooldown.ts +3 -2
- package/scripts/discovery/repo-party.ts +80 -20
- package/scripts/discovery/session-owner-pin.ts +51 -0
- package/scripts/document/capped-print.ts +1 -1
- package/scripts/document/command-reference-line-budget.ts +42 -0
- package/scripts/document/document-byte-budget.ts +17 -7
- package/scripts/document/document-checks.ts +20 -0
- package/scripts/document/document-ratchet-check.ts +101 -0
- package/scripts/document/document-section.ts +1 -0
- package/scripts/document/entry-read-budget.ts +7 -3
- package/scripts/document/issue-citation-budget.ts +94 -0
- package/scripts/epic/epic-cli-argv.ts +2 -2
- package/scripts/epic/epic-fetch.ts +4 -2
- package/scripts/epic/epic-graph.ts +7 -2
- package/scripts/epic/epic-issue.ts +3 -1
- package/scripts/epic/epic-rank.ts +5 -0
- package/scripts/exports/unused-members-check.ts +62 -0
- package/scripts/exports/unused-members-cli.ts +6 -51
- package/scripts/followup/followup-ci-path.ts +67 -0
- package/scripts/followup/followup-coderabbit-retrigger.ts +261 -0
- package/scripts/followup/followup-coderabbit-wait.ts +13 -10
- package/scripts/followup/followup-failed-tests.ts +160 -0
- package/scripts/followup/followup-job-needs.ts +100 -0
- package/scripts/followup/followup-job-rerun.ts +303 -0
- package/scripts/followup/followup-main-move.ts +113 -0
- package/scripts/followup/git-followup-finish.ts +43 -11
- package/scripts/followup/git-followup-pending.ts +3 -3
- package/scripts/followup/git-followup-stages.ts +41 -11
- package/scripts/followup/git-pr-followup-checks.ts +55 -16
- package/scripts/followup/git-pr-followup-wrapup.ts +24 -5
- package/scripts/followup/git-pr-followup.ts +62 -27
- package/scripts/fresh-machine/fresh-machine-script.ts +5 -9
- package/scripts/fresh-machine/specs/kit-test-backlogrun-python.json +2 -2
- package/scripts/fresh-machine/specs/kit-test-backlogrun.json +2 -2
- package/scripts/gate/busy-average.ts +34 -2
- package/scripts/gate/check-related-pinned.ts +43 -0
- package/scripts/gate/check-related-reuse.ts +64 -0
- package/scripts/gate/check-related-section.ts +57 -0
- package/scripts/gate/check-related-unplanned.ts +34 -0
- package/scripts/gate/check-related.ts +265 -0
- package/scripts/gate/command-memory.ts +1 -1
- package/scripts/gate/core-admission.ts +24 -6
- package/scripts/gate/core-budget-timing.ts +20 -6
- package/scripts/gate/core-budget.ts +40 -11
- package/scripts/gate/core-wait-record.ts +3 -2
- package/scripts/gate/core-wait.ts +25 -2
- package/scripts/gate/core-weights.ts +15 -7
- package/scripts/gate/gate-labels.ts +46 -0
- package/scripts/gate/gate-ledger.ts +14 -6
- package/scripts/gate/gate-plan.ts +103 -58
- package/scripts/gate/gate-report.ts +9 -7
- package/scripts/gate/gate-run-steps.ts +26 -3
- package/scripts/gate/gate-skip.ts +45 -6
- package/scripts/gate/gate-static-group.ts +60 -0
- package/scripts/gate/gate-steps.ts +2 -1
- package/scripts/gate/gate-tree.ts +4 -2
- package/scripts/gate/hook-gate-reuse.ts +19 -2
- package/scripts/gate/metrics-totals.ts +59 -0
- package/scripts/gate/scoped-green.ts +68 -15
- package/scripts/gate/since-green.ts +14 -6
- package/scripts/gate/structural-checks.ts +96 -0
- package/scripts/gate/verification-gate.ts +51 -16
- package/scripts/gate/verification-inputs.ts +21 -6
- package/scripts/gate/verification-tail.ts +52 -0
- package/scripts/gh/gh-author-association.ts +23 -2
- package/scripts/gh/git-ai-review-scan.ts +1 -1
- package/scripts/gh/git-gh-api-path.ts +12 -3
- package/scripts/gh/git-gh-comments-unreadable.ts +36 -0
- package/scripts/gh/git-gh-exec.ts +32 -2
- package/scripts/gh/git-gh-issue-read.ts +4 -2
- package/scripts/gh/git-gh-issue-rest.ts +1 -0
- package/scripts/gh/git-gh-issue-write.ts +8 -2
- package/scripts/gh/git-gh-issue.ts +12 -5
- package/scripts/gh/git-gh-pr-auto-merge.ts +13 -6
- package/scripts/gh/git-gh-pr-graphql-state.ts +56 -0
- package/scripts/gh/git-gh-pr-read.ts +74 -13
- package/scripts/gh/git-gh-pr-rest.ts +3 -1
- package/scripts/gh/git-gh-pr-snapshot.ts +22 -7
- package/scripts/gh/git-gh-pr-too-large.ts +20 -0
- package/scripts/gh/git-gh-pr.ts +21 -7
- package/scripts/gh/git-gh-retry.ts +141 -0
- package/scripts/gh/git-pr-ai-review.ts +15 -6
- package/scripts/gh/git-pr-checks-eval.ts +3 -0
- package/scripts/gh/git-pr-checks.ts +5 -5
- package/scripts/git/base-tree.ts +30 -0
- package/scripts/git/change-base.ts +4 -10
- package/scripts/git/changed-paths-sync.ts +63 -0
- package/scripts/git/changed-paths.ts +16 -1
- package/scripts/git/git-common-directory.ts +11 -1
- package/scripts/git/git-diff-reads.ts +66 -20
- package/scripts/git/git-error.ts +9 -2
- package/scripts/git/git-schemas.ts +13 -0
- package/scripts/git/git-worktree.ts +13 -0
- package/scripts/git/gone-branch.ts +4 -1
- package/scripts/git/main-merge-budget-conflict.ts +89 -0
- package/scripts/git/main-merge-guard.ts +55 -18
- package/scripts/git/main-merge-regenerate.ts +59 -25
- package/scripts/git/main-merge.ts +53 -5
- package/scripts/git/no-base-checkout.ts +127 -0
- package/scripts/git/stash/git-stash.ts +11 -2
- package/scripts/git/stash/stash-push-cli.ts +10 -0
- package/scripts/hooks/batch-guard.ts +40 -21
- package/scripts/hooks/edited-cspell.ts +37 -11
- package/scripts/hooks/format-edited-file.ts +22 -2
- package/scripts/hooks/lane-plan-guard.ts +50 -0
- package/scripts/hooks/pre-commit-lint-switch.ts +9 -0
- package/scripts/hooks/pre-commit-lint.ts +14 -1
- package/scripts/hooks/pre-push-related-switch.ts +10 -0
- package/scripts/hooks/pre-push-unit.ts +76 -10
- package/scripts/hooks/pretool-guard.ts +2 -0
- package/scripts/hooks/reserved-run.ts +14 -1
- package/scripts/hooks/run-hook.sh +23 -8
- package/scripts/hooks/step-zero-notice.ts +6 -1
- package/scripts/hooks/stop-actions.ts +3 -15
- package/scripts/hooks/stop-guard.ts +7 -6
- package/scripts/init/distributed-paths.ts +1 -0
- package/scripts/init/hook-command-rewrite.ts +5 -1
- package/scripts/init/hook-launch.ts +4 -2
- package/scripts/issue/aggregation-split.ts +52 -0
- package/scripts/issue/defect-origin-line.ts +19 -1
- package/scripts/issue/defect-rate-cli.ts +5 -102
- package/scripts/issue/defect-report.ts +4 -4
- package/scripts/issue/effect-audit-cli.ts +178 -0
- package/scripts/issue/effect-audit.ts +185 -0
- package/scripts/issue/expected-effect-lint.ts +64 -9
- package/scripts/issue/git-next-issues.ts +5 -0
- package/scripts/issue/issue-body-or-comment.ts +38 -4
- package/scripts/issue/issue-cite-cli.ts +1 -3
- package/scripts/issue/issue-classification.ts +1 -0
- package/scripts/issue/issue-closing-pr.ts +8 -1
- package/scripts/issue/issue-evidence-exit.ts +4 -2
- package/scripts/issue/issue-file-cap.ts +58 -0
- package/scripts/issue/issue-file-cli.ts +111 -38
- package/scripts/issue/issue-file-deferral.ts +52 -0
- package/scripts/issue/issue-file-fold.ts +29 -10
- package/scripts/issue/issue-file-interrupt.ts +85 -0
- package/scripts/issue/issue-file-lane-hint.ts +30 -0
- package/scripts/issue/issue-file.ts +43 -6
- package/scripts/issue/issue-labels.ts +19 -2
- package/scripts/issue/issue-lint-cli.ts +27 -2
- package/scripts/issue/issue-measured-cli.ts +13 -35
- package/scripts/issue/issue-measured-close.ts +58 -0
- package/scripts/issue/issue-not-before-label.ts +2 -2
- package/scripts/issue/issue-not-before.ts +4 -1
- package/scripts/issue/issue-priority-cli.ts +60 -0
- package/scripts/issue/issue-priority-raise.ts +55 -0
- package/scripts/issue/issue-priority.ts +174 -43
- package/scripts/issue/issue-rank.ts +21 -4
- package/scripts/issue/issue-read-cli.ts +32 -6
- package/scripts/issue/issue-read.ts +37 -12
- package/scripts/issue/issue-sample-gate.ts +95 -74
- package/scripts/issue/issue-sample-prime.ts +127 -0
- package/scripts/issue/issue-sample-required.ts +57 -0
- package/scripts/issue/issue-sample-source.ts +12 -11
- package/scripts/issue/issue-search.ts +124 -0
- package/scripts/issue/issue-state.ts +13 -1
- package/scripts/issue/issue-template-section.ts +43 -0
- package/scripts/issue/issue-watch-diff.ts +31 -1
- package/scripts/issue/issue-watch-hook.ts +11 -2
- package/scripts/issue/issue-watch.ts +55 -12
- package/scripts/issue/markdown-section.ts +1 -0
- package/scripts/issue/measure-declaration.ts +121 -0
- package/scripts/issue/measure-rerun-cli.ts +7 -70
- package/scripts/issue/plan-consumers-section.ts +22 -1
- package/scripts/issue/reproduction-measure.ts +3 -1
- package/scripts/issue/size-estimate.ts +90 -0
- package/scripts/issue/trusted-measure.ts +84 -0
- package/scripts/josh/command-usage.ts +3 -2
- package/scripts/josh/durable-state-migrate.ts +105 -0
- package/scripts/josh/durable-state.ts +112 -0
- package/scripts/josh/josh-aliases.ts +95 -0
- package/scripts/josh/josh-command-map.ts +1 -82
- package/scripts/josh/josh-commands-agent-hooks.ts +6 -6
- package/scripts/josh/josh-commands-ai.ts +5 -5
- package/scripts/josh/josh-commands-development.ts +59 -58
- package/scripts/josh/josh-commands-issue-write.ts +23 -4
- package/scripts/josh/josh-commands-issue.ts +32 -0
- package/scripts/josh/josh-commands-lane.ts +87 -4
- package/scripts/josh/josh-commands-lint.ts +16 -3
- package/scripts/josh/josh-commands-maintenance.ts +15 -0
- package/scripts/josh/josh-commands-review.ts +41 -6
- package/scripts/josh/josh-commands-ship.ts +56 -8
- package/scripts/josh/josh-commands-test-check.ts +80 -0
- package/scripts/josh/josh-commands-workflow.ts +1 -1
- package/scripts/josh/josh-environment-file.ts +43 -3
- package/scripts/josh/josh-in-process.ts +2 -2
- package/scripts/josh/josh-logic.ts +5 -3
- package/scripts/josh/josh-run.ts +19 -1
- package/scripts/josh/run-record-path.ts +15 -0
- package/scripts/josh/stamp-file.ts +11 -2
- package/scripts/lane/lane-adopt-cli.ts +98 -0
- package/scripts/lane/lane-adopt.ts +208 -0
- package/scripts/lane/lane-await.ts +5 -8
- package/scripts/lane/lane-baseline.ts +123 -0
- package/scripts/lane/lane-breakdown-cli.ts +64 -0
- package/scripts/lane/lane-breakdown-implement.ts +170 -0
- package/scripts/lane/lane-breakdown-laps.ts +107 -0
- package/scripts/lane/lane-breakdown-pinned.ts +76 -0
- package/scripts/lane/lane-breakdown-text.ts +145 -0
- package/scripts/lane/lane-breakdown.ts +239 -0
- package/scripts/lane/lane-check-stats.ts +29 -8
- package/scripts/lane/lane-child-invocation.ts +9 -2
- package/scripts/lane/lane-child-mark-keys.ts +12 -0
- package/scripts/lane/lane-child-marker.ts +20 -1
- package/scripts/lane/lane-ci-path-stats.ts +73 -0
- package/scripts/lane/lane-claim-stats.ts +84 -0
- package/scripts/lane/lane-close.ts +8 -3
- package/scripts/lane/lane-dispatch-log.ts +3 -3
- package/scripts/lane/lane-dispatch.ts +2 -2
- package/scripts/lane/lane-gap-stats.ts +7 -6
- package/scripts/lane/lane-guard-policy.ts +7 -1
- package/scripts/lane/lane-implement-stats.ts +207 -0
- package/scripts/lane/lane-implement-subagents.ts +90 -0
- package/scripts/lane/lane-investigation-switch.ts +16 -0
- package/scripts/lane/lane-ledger-kind.ts +31 -0
- package/scripts/lane/lane-ledger-schema-ship.ts +49 -0
- package/scripts/lane/lane-ledger-schema.ts +119 -36
- package/scripts/lane/lane-ledger-write.ts +257 -0
- package/scripts/lane/lane-ledger.ts +31 -177
- package/scripts/lane/lane-load.ts +1 -1
- package/scripts/lane/lane-measure-cli.ts +176 -59
- package/scripts/lane/lane-net-read.ts +44 -0
- package/scripts/lane/lane-net-time.ts +212 -0
- package/scripts/lane/lane-open.ts +16 -7
- package/scripts/lane/lane-output.ts +2 -4
- package/scripts/lane/lane-overrun-prompt.ts +147 -0
- package/scripts/lane/lane-overrun.ts +274 -0
- package/scripts/lane/lane-paths.ts +24 -1
- package/scripts/lane/lane-pause-cli.ts +4 -1
- package/scripts/lane/lane-paused-spans.ts +97 -0
- package/scripts/lane/lane-plan-check.ts +207 -0
- package/scripts/lane/lane-plan-cli.ts +41 -0
- package/scripts/lane/lane-plan.ts +144 -0
- package/scripts/lane/lane-registry.ts +14 -1
- package/scripts/lane/lane-relaunch.ts +1 -1
- package/scripts/lane/lane-round-one-stats.ts +51 -0
- package/scripts/lane/lane-sampler.ts +23 -4
- package/scripts/lane/lane-session-action.ts +93 -18
- package/scripts/lane/lane-session-broker.ts +49 -21
- package/scripts/lane/lane-session-reread-main.ts +14 -0
- package/scripts/lane/lane-session-reread.ts +51 -0
- package/scripts/lane/lane-ship-lap-stats.ts +74 -0
- package/scripts/lane/lane-sleep.ts +58 -0
- package/scripts/lane/lane-spent.ts +1 -1
- package/scripts/lane/lane-split-stats.ts +28 -0
- package/scripts/lane/lane-stage-stats.ts +13 -1
- package/scripts/lane/lane-state.ts +41 -9
- package/scripts/lane/lane-stats-tables.ts +58 -0
- package/scripts/lane/lane-stats.ts +21 -5
- package/scripts/lane/lane-stop-stats.ts +51 -19
- package/scripts/lane/lane-tail-stats.ts +32 -0
- package/scripts/lane/lane-transcript-calls.ts +67 -10
- package/scripts/lane/lane-transcript-stats.ts +44 -12
- package/scripts/lane/lane-value-cell.ts +72 -0
- package/scripts/lane/lane-value.ts +118 -0
- package/scripts/lane/lane-withdraw-closed.ts +124 -0
- package/scripts/lane/lane-withdraw.ts +108 -31
- package/scripts/lane/lane-yield.ts +85 -0
- package/scripts/lane/openai-lane-ship.ts +12 -11
- package/scripts/lane/openai-lane-supervisor-decision.ts +6 -8
- package/scripts/lane/openai-lane-supervisor-owner.ts +5 -8
- package/scripts/lane/openai-lane-supervisor.ts +5 -4
- package/scripts/lib/poll.ts +38 -9
- package/scripts/lib/settled-together.ts +10 -0
- package/scripts/lib/shell-quote.ts +21 -0
- package/scripts/lib/token-shape.ts +111 -0
- package/scripts/lint/eslint-daemon-sources.ts +79 -0
- package/scripts/lint/eslint-daemon.ts +45 -6
- package/scripts/lint/eslint-warm-cli.ts +7 -0
- package/scripts/lint/eslint-warm.ts +66 -0
- package/scripts/lint/import-graph.ts +141 -11
- package/scripts/lint/lint-gate-scope.ts +2 -2
- package/scripts/lint/lint-parallel.ts +54 -6
- package/scripts/lint/lint-related.ts +154 -33
- package/scripts/lint/rename-cli.ts +179 -0
- package/scripts/lint/rename-identifier.ts +192 -0
- package/scripts/lint/type-only-imports.ts +58 -0
- package/scripts/notify/telegram-notify.ts +12 -3
- package/scripts/observations/observation-record.ts +42 -16
- package/scripts/observations/observations-flush.ts +32 -9
- package/scripts/overrides/overrides-check.ts +9 -1
- package/scripts/release/release-approval-prune.ts +7 -1
- package/scripts/repo/required-checks-logic.ts +4 -1
- package/scripts/repo/ruleset-check.ts +4 -3
- package/scripts/report/markdown-shape.ts +28 -0
- package/scripts/report/report-format-reference.ts +15 -1
- package/scripts/report/report-labels.ts +12 -1
- package/scripts/report/report-lint-child-summary.ts +94 -0
- package/scripts/report/report-lint-cli.ts +26 -7
- package/scripts/report/report-lint.ts +2 -20
- package/scripts/review/prose-stale-cli.ts +88 -0
- package/scripts/review/prose-stale-scan.ts +152 -0
- package/scripts/review/review-attest.ts +73 -23
- package/scripts/review/review-brief-cli.ts +68 -19
- package/scripts/review/review-brief-paths.ts +22 -0
- package/scripts/review/review-brief.ts +14 -7
- package/scripts/review/review-comment-carry.ts +47 -0
- package/scripts/review/review-comment-round.ts +85 -22
- package/scripts/review/review-finding-ledger.ts +109 -7
- package/scripts/review/review-finding-text.ts +43 -0
- package/scripts/review/review-interaction.ts +11 -0
- package/scripts/review/review-lane-handover.ts +68 -0
- package/scripts/review/review-lint-cli.ts +57 -0
- package/scripts/review/review-lint-findings.ts +92 -0
- package/scripts/review/review-lint-sections.ts +80 -0
- package/scripts/review/review-lint.ts +221 -0
- package/scripts/review/review-prior-findings.ts +102 -0
- package/scripts/review/review-readers-scan.ts +4 -2
- package/scripts/review/review-record-cli.ts +177 -54
- package/scripts/review/review-record-code-round.ts +55 -0
- package/scripts/review/review-record-comment.ts +60 -0
- package/scripts/review/review-record-interaction.ts +35 -0
- package/scripts/review/review-record-pinned.ts +108 -0
- package/scripts/review/review-record.ts +25 -1
- package/scripts/review/review-reviewed-tree.ts +307 -0
- package/scripts/review/review-round-one-closure.ts +62 -0
- package/scripts/review/review-round-reuse.ts +106 -0
- package/scripts/review/review-round2-cli.ts +91 -29
- package/scripts/review/review-round2-skip-comment.ts +55 -0
- package/scripts/review/review-round2.ts +24 -8
- package/scripts/review/review-stamps.ts +7 -3
- package/scripts/review/review-stop-log.ts +20 -6
- package/scripts/review/review-stops-cli.ts +2 -1
- package/scripts/review/review-submit-cli.ts +101 -0
- package/scripts/rules/agent-model.ts +1 -1
- package/scripts/rules/bash-triggers.ts +3 -3
- package/scripts/rules/concise-reply.ts +88 -0
- package/scripts/rules/credential-body.ts +77 -0
- package/scripts/rules/decision-oracle.ts +1 -1
- package/scripts/rules/delivered-rules.ts +36 -17
- package/scripts/rules/destructive-command.ts +3 -11
- package/scripts/rules/direct-issue-comment.ts +34 -12
- package/scripts/rules/direct-issue-read.ts +191 -0
- package/scripts/rules/direct-pr-create.ts +4 -24
- package/scripts/rules/early-heartbeat.ts +2 -0
- package/scripts/rules/edit-tool.ts +27 -0
- package/scripts/rules/file-edit-rows.ts +17 -0
- package/scripts/rules/file-rewrite.ts +146 -0
- package/scripts/rules/firing-point.ts +3 -2
- package/scripts/rules/gh-api.ts +128 -7
- package/scripts/rules/gh-repo-selector.ts +84 -0
- package/scripts/rules/git-force.ts +2 -2
- package/scripts/rules/guard-remedy.ts +14 -5
- package/scripts/rules/implementation-cut.ts +61 -28
- package/scripts/rules/investigator-foreground.ts +231 -0
- package/scripts/rules/issue-citation.ts +15 -60
- package/scripts/rules/issue-comments.ts +9 -4
- package/scripts/rules/josh-git-bare.ts +1 -1
- package/scripts/rules/lane-background.ts +41 -13
- package/scripts/rules/lane-direct-tool.ts +107 -9
- package/scripts/rules/lane-interactive-ask.ts +4 -1
- package/scripts/rules/lane-park.ts +4 -2
- package/scripts/rules/lane-spilled-read.ts +90 -0
- package/scripts/rules/lane-split-park.ts +1 -1
- package/scripts/rules/lane-switch-main.ts +4 -4
- package/scripts/rules/last-prompt.ts +20 -47
- package/scripts/rules/oracle-consulted.ts +1 -1
- package/scripts/rules/permission-guards.ts +5 -1
- package/scripts/rules/piped-verification-shapes.ts +110 -0
- package/scripts/rules/piped-verification.ts +67 -17
- package/scripts/rules/poll-loop.ts +72 -9
- package/scripts/rules/pr-merge.ts +5 -5
- package/scripts/rules/pre-gate-cut.ts +3 -3
- package/scripts/rules/protected-files.ts +88 -24
- package/scripts/rules/reply-language.ts +3 -17
- package/scripts/rules/reply-prose.ts +34 -0
- package/scripts/rules/repo-admin.ts +132 -0
- package/scripts/rules/reviewer-foreground.ts +88 -0
- package/scripts/rules/round-one-check-related.ts +120 -0
- package/scripts/rules/rule-body-guard.ts +5 -15
- package/scripts/rules/rule-value-cache.ts +53 -5
- package/scripts/rules/rule-value-candidates.ts +84 -0
- package/scripts/rules/rule-value-cli.ts +59 -11
- package/scripts/rules/rule-value.ts +17 -4
- package/scripts/rules/run-tail-rule.ts +1 -1
- package/scripts/rules/sed-in-place.ts +196 -0
- package/scripts/rules/shell-segments.ts +10 -2
- package/scripts/rules/stop-rule-rows.ts +1 -13
- package/scripts/rules/stop-rules.ts +33 -58
- package/scripts/rules/test-declared-commit.ts +1 -1
- package/scripts/rules/third-party-write.ts +110 -23
- package/scripts/rules/timed-rerun.ts +1 -1
- package/scripts/rules/turn-filings.ts +90 -0
- package/scripts/rules/worktree-guard.ts +22 -7
- package/scripts/run/board/run-board-ending-reason.ts +6 -2
- package/scripts/run/board/run-board-fit.ts +24 -1
- package/scripts/run/board/run-board-found.ts +134 -0
- package/scripts/run/board/run-board-header.ts +8 -0
- package/scripts/run/board/run-board-labels.ts +11 -1
- package/scripts/run/board/run-board-lane-time.ts +1 -0
- package/scripts/run/board/run-board-link.ts +15 -2
- package/scripts/run/board/run-board-notes.ts +7 -1
- package/scripts/run/board/run-board-operation.ts +4 -2
- package/scripts/run/board/run-board-phase.ts +2 -5
- package/scripts/run/board/run-board-plan.ts +1 -1
- package/scripts/run/board/run-board-read.ts +46 -1
- package/scripts/run/board/run-board-reason.ts +20 -8
- package/scripts/run/board/run-board-render-checks.ts +3 -2
- package/scripts/run/board/run-board-render-drawn.ts +11 -0
- package/scripts/run/board/run-board-render-found.ts +157 -0
- package/scripts/run/board/run-board-render-lead.ts +9 -0
- package/scripts/run/board/run-board-render-legend.ts +19 -0
- package/scripts/run/board/run-board-render-tail.ts +1 -1
- package/scripts/run/board/run-board-render.ts +82 -18
- package/scripts/run/board/run-board-spin.ts +1 -3
- package/scripts/run/board/run-board-status.ts +2 -0
- package/scripts/run/board/run-board-tick.ts +39 -10
- package/scripts/run/carry/run-carry-ended.ts +3 -2
- package/scripts/run/carry/run-carry.ts +3 -2
- package/scripts/run/cut/run-cut-cli.ts +33 -133
- package/scripts/run/cut/run-cut-digest.ts +152 -0
- package/scripts/run/cut/run-cut-handoff.ts +52 -8
- package/scripts/run/cut/run-cut-report.ts +24 -3
- package/scripts/run/cut/run-cut-resume.ts +129 -0
- package/scripts/run/cut/run-cut-review.ts +105 -0
- package/scripts/run/cut/run-cut.ts +18 -7
- package/scripts/run/detached-launch.ts +1 -1
- package/scripts/run/entry/run-entry-cli.ts +88 -19
- package/scripts/run/entry/run-entry-spill.ts +83 -0
- package/scripts/run/entry/run-entry-stop.ts +5 -1
- package/scripts/run/entry/run-entry-trust.ts +91 -0
- package/scripts/run/event/run-event-baseline.ts +56 -0
- package/scripts/run/event/run-event-filed.ts +9 -3
- package/scripts/run/event/run-event-overrun.ts +197 -0
- package/scripts/run/event/run-event-render.ts +4 -0
- package/scripts/run/event/run-event-stream.ts +25 -3
- package/scripts/run/hold/run-stop-notify.ts +3 -8
- package/scripts/run/merge/run-merge-cap.ts +57 -0
- package/scripts/run/merge/run-merge-cli.ts +66 -23
- package/scripts/run/merge/run-merge-outcome.ts +2 -0
- package/scripts/run/merge/run-merge-ship.ts +13 -3
- package/scripts/run/merge/run-merge-signals.ts +40 -23
- package/scripts/run/merge/run-merge-steps.ts +56 -36
- package/scripts/run/merge/run-merge-usage-limit.ts +53 -0
- package/scripts/run/merge/run-merge-withdrawn.ts +53 -0
- package/scripts/run/merge/run-merge.ts +41 -14
- package/scripts/run/review/run-review-cli.ts +306 -20
- package/scripts/run/review/run-review-early-push.ts +121 -0
- package/scripts/run/review/run-review-join-read.ts +94 -0
- package/scripts/run/review/run-review-pinned-accepted.ts +126 -0
- package/scripts/run/review/run-review-pinned-join.ts +216 -0
- package/scripts/run/review/run-review-pinned-steps.ts +383 -0
- package/scripts/run/review/run-review-pinned-tree.ts +37 -0
- package/scripts/run/review/run-review-pinned.ts +53 -0
- package/scripts/run/review/run-review-steps.ts +70 -34
- package/scripts/run/review/run-review.ts +26 -6
- package/scripts/run/run-parent-cut-hook.ts +3 -4
- package/scripts/run/run-prep.ts +1 -0
- package/scripts/run/run-stage-read.ts +2 -6
- package/scripts/run/run-step-cli.ts +17 -5
- package/scripts/run/run-step-lane-plan.ts +27 -0
- package/scripts/run/run-step-section.ts +26 -7
- package/scripts/run/run-step.ts +5 -2
- package/scripts/run/ship/run-ship-args.ts +19 -0
- package/scripts/run/ship/run-ship-brokered-review.ts +106 -0
- package/scripts/run/ship/run-ship-cli.ts +131 -39
- package/scripts/run/ship/run-ship-conflict-probe.ts +59 -0
- package/scripts/run/ship/run-ship-detach.ts +10 -4
- package/scripts/run/ship/run-ship-handover.ts +106 -0
- package/scripts/run/ship/run-ship-infra-retry.ts +16 -1
- package/scripts/run/ship/run-ship-lap.ts +63 -0
- package/scripts/run/ship/run-ship-next.ts +27 -26
- package/scripts/run/ship/run-ship-overlap.ts +8 -3
- package/scripts/run/ship/run-ship-place.ts +9 -2
- package/scripts/run/ship/run-ship-planned.ts +92 -0
- package/scripts/run/ship/run-ship-pre-detach-pinned.ts +197 -0
- package/scripts/run/ship/run-ship-pre-detach-timed.ts +7 -8
- package/scripts/run/ship/run-ship-pre-detach.ts +77 -23
- package/scripts/run/ship/run-ship-preflight.ts +16 -4
- package/scripts/run/ship/run-ship-probe.ts +23 -9
- package/scripts/run/ship/run-ship-relaunch-cap.ts +43 -7
- package/scripts/run/ship/run-ship-relaunch.ts +51 -0
- package/scripts/run/ship/run-ship-return.ts +103 -29
- package/scripts/run/ship/run-ship-review-reason.ts +24 -0
- package/scripts/run/ship/run-ship-review-steps.ts +230 -59
- package/scripts/run/ship/run-ship-review.ts +171 -51
- package/scripts/run/ship/run-ship-reviewer.ts +138 -42
- package/scripts/run/ship/run-ship-scoped.ts +39 -10
- package/scripts/run/ship/run-ship-stage.ts +49 -13
- package/scripts/run/ship/run-ship-steps.ts +24 -4
- package/scripts/run/ship/run-ship-stop-cause.ts +43 -2
- package/scripts/run/ship/run-ship-stop-context.ts +50 -13
- package/scripts/run/ship/run-ship-sync.ts +171 -30
- package/scripts/run/ship/run-ship-synced-scope.ts +178 -0
- package/scripts/run/ship/run-ship-wait-cli.ts +145 -0
- package/scripts/run/ship/run-ship-waiter.ts +114 -0
- package/scripts/run/ship/run-ship.ts +16 -2
- package/scripts/run/wake/run-wake-caffeinate.ts +48 -0
- package/scripts/run/wake/run-wake-cli.ts +6 -113
- package/scripts/run/wake/run-wake-code.ts +53 -11
- package/scripts/run/wake/run-wake-driver.ts +5 -3
- package/scripts/run/wake/run-wake-finish.ts +137 -0
- package/scripts/run/wake/run-wake-loop.ts +5 -3
- package/scripts/run/wake/run-wake-ports.ts +11 -3
- package/scripts/run/wake/run-wake-session.ts +2 -0
- package/scripts/run/wake/run-wake.ts +3 -2
- package/scripts/safe-chain/ci-installer-pin.ts +49 -8
- package/scripts/safe-chain/project-config.ts +3 -2
- package/scripts/security/secretlint-scan.ts +42 -9
- package/scripts/security/security-audit-provision-main.ts +9 -1
- package/scripts/security/security-audit-provision.ts +1 -1
- package/scripts/security/security-audit.ts +21 -1
- package/scripts/security/sonar-file.ts +10 -5
- package/scripts/split/split-assess.ts +12 -3
- package/scripts/split/split-early-notice.ts +116 -0
- package/scripts/split/split-measure.ts +20 -2
- package/scripts/split/split-resolution.ts +107 -0
- package/scripts/test/direct-importers.ts +185 -0
- package/scripts/test/pure-files-entries.ts +83 -0
- package/scripts/test/related-heavy-tests.ts +81 -0
- package/scripts/test/test-no-base.ts +88 -0
- package/scripts/test/test-pinned-cache-logic.ts +363 -0
- package/scripts/test/test-pinned-cache.ts +337 -0
- package/scripts/test/test-pinned-emit.ts +49 -0
- package/scripts/test/test-pinned-functions.ts +116 -0
- package/scripts/test/test-pinned-ledger.ts +80 -0
- package/scripts/test/test-pinned-logic.ts +208 -20
- package/scripts/test/test-pinned-main.ts +84 -18
- package/scripts/test/test-pinned-pool.ts +73 -0
- package/scripts/test/test-pinned-probe.ts +254 -0
- package/scripts/test/test-pinned-prune-logic.ts +118 -0
- package/scripts/test/test-pinned-reach.ts +194 -0
- package/scripts/test/test-pinned-record.ts +196 -0
- package/scripts/test/test-pinned-rewire.ts +148 -0
- package/scripts/test/test-pinned-spawn.ts +81 -0
- package/scripts/test/test-pinned-stage.ts +70 -0
- package/scripts/test/test-pinned.ts +258 -47
- package/scripts/test/test-reach-cli.ts +61 -0
- package/scripts/test/test-read-map.ts +35 -11
- package/scripts/test/test-read-recording.ts +17 -5
- package/scripts/test/test-read-trace.ts +26 -8
- package/scripts/test/test-red-logic.ts +46 -7
- package/scripts/test/test-red.ts +34 -14
- package/scripts/test/test-related-claim.ts +37 -0
- package/scripts/test/test-related-main.ts +4 -1
- package/scripts/test/test-related-moved.ts +91 -0
- package/scripts/test/test-related-record.ts +43 -23
- package/scripts/test/test-related-scope.ts +99 -34
- package/scripts/test/test-related-synced.ts +135 -0
- package/scripts/test/test-related-touched.ts +84 -0
- package/scripts/test/test-related.ts +167 -83
- package/scripts/test/test-unit-guard.ts +28 -5
- package/scripts/test/unit-durations.ts +41 -0
- package/scripts/test/unit-worker-share.ts +5 -4
- package/scripts/test/vitest-cache-directory.ts +19 -0
- package/scripts/test/vitest-cli-excludes.ts +14 -0
- package/scripts/test/vitest-failure-summary.ts +111 -0
- package/scripts/test/whole-suite-files.ts +12 -1
- package/scripts/time-runtime/time-batch-guard.ts +42 -4
- package/scripts/time-runtime/time-bundle-call.ts +1 -1
- package/scripts/time-runtime/time-bundles.ts +36 -5
- package/scripts/time-runtime/time-markers.ts +2 -2
- package/scripts/time-runtime/time-search-call.ts +38 -0
- package/scripts/time-runtime/time-shell.ts +1 -1
- package/scripts/time-runtime/time-transcript-line.ts +17 -5
- package/scripts/version/development-engines-verdict.ts +124 -0
- package/scripts/version/latest-corepack.ts +2 -0
- package/templates/gitignore +2 -0
- package/templates/workflows/ci.yml +41 -0
- package/dist/hooks/chunk-AZX4FGQ3.js +0 -207
- package/dist/hooks/chunk-PT5R6UJD.js +0 -7131
- package/dist/hooks/chunk-TUIFS5E7.js +0 -72
- package/dist/hooks/chunk-YCDOIR3I.js +0 -3456
- package/scripts/cost-runtime/context-cut-threshold.ts +0 -11
- package/scripts/rules/filing-cap.ts +0 -139
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { error_text } from '#scripts/lib/error-message'
|
|
1
2
|
import { FULL_PAGE_QUERY, git_gh_api_path } from './git-gh-api-path'
|
|
3
|
+
import { note_unreadable_comments } from './git-gh-comments-unreadable'
|
|
2
4
|
import { git_gh_exec } from './git-gh-exec'
|
|
3
5
|
import { git_gh_helpers } from './git-gh-helpers'
|
|
4
6
|
import { git_gh_pr_rest, type RestPull } from './git-gh-pr-rest'
|
|
7
|
+
import { git_gh_pr_too_large } from './git-gh-pr-too-large'
|
|
5
8
|
import { to_gh_state } from './git-gh-rest-state'
|
|
6
9
|
|
|
7
10
|
// Reading pull requests through REST, in the answers `gh pr view` gives.
|
|
@@ -61,10 +64,16 @@ function lookup_path(branch_name: string): string {
|
|
|
61
64
|
return `${git_gh_api_path.pulls_api_path()}?head=${head}&${LOOKUP_QUERY}`
|
|
62
65
|
}
|
|
63
66
|
|
|
64
|
-
async function
|
|
67
|
+
async function fetch_branch_pull(branch_name: string): Promise<RestPull | undefined> {
|
|
65
68
|
const json = await git_gh_exec.exec_gh_api({ path: lookup_path(branch_name) })
|
|
66
69
|
|
|
67
|
-
return git_gh_pr_rest.select_pull(git_gh_pr_rest.parse_rest_pulls(json))
|
|
70
|
+
return git_gh_pr_rest.select_pull(git_gh_pr_rest.parse_rest_pulls(json))
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async function fetch_pr_number(branch_name: string): Promise<number | undefined> {
|
|
74
|
+
const pull = await fetch_branch_pull(branch_name)
|
|
75
|
+
|
|
76
|
+
return pull?.number
|
|
68
77
|
}
|
|
69
78
|
|
|
70
79
|
// Why the resolution produced no number. `missing` is the lookup answering: the listing came back and
|
|
@@ -80,7 +89,7 @@ interface PullMergeState {
|
|
|
80
89
|
is_merged: boolean
|
|
81
90
|
merged_at: string | undefined
|
|
82
91
|
head_sha: string | undefined
|
|
83
|
-
//
|
|
92
|
+
// GitHub's merge state (`DIRTY` on a conflict).
|
|
84
93
|
merge_state_status: string | undefined
|
|
85
94
|
}
|
|
86
95
|
|
|
@@ -100,8 +109,8 @@ const pending_pr_number_by_branch = new Map<string, Promise<PullNumberRead>>()
|
|
|
100
109
|
// same `GET /pulls/{N}` each time. The promise is stored, so readers in one tick share the request as
|
|
101
110
|
// well as its answer; a read that fails is dropped and re-tried, the rule the number memo holds.
|
|
102
111
|
// **Every write to a pull request clears it** through `forget_pr_numbers`, and the two state readers
|
|
103
|
-
// never read it: `pr_get_merge_state` answers where the pull request stands *now*, which `josh
|
|
104
|
-
// asks again after every merge
|
|
112
|
+
// never read it: `pr_get_merge_state` answers where the pull request stands *now*, which `josh followup`
|
|
113
|
+
// asks again after every merge `josh ship` pushes, and `pr_view` decides whether `josh git -y` writes onto the
|
|
105
114
|
// pull request — after a commit and a push its preflight read would otherwise outlast.
|
|
106
115
|
const pull_by_number = new Map<number, Promise<RestPull>>()
|
|
107
116
|
|
|
@@ -168,9 +177,12 @@ async function resolve_pr_number(branch_name: string): Promise<number | undefine
|
|
|
168
177
|
}
|
|
169
178
|
|
|
170
179
|
// One definition, because both callers that refuse to fold an unreadable lookup raise it —
|
|
171
|
-
// `require_pr_number` and `pr_exists`.
|
|
180
|
+
// `require_pr_number` and `pr_exists`. The cause's first line rides in the message: a reader that
|
|
181
|
+
// prints only the message — the `josh git -y` preflight, a `josh ship` log — still says why.
|
|
172
182
|
function to_unreadable_error(branch_name: string, cause: unknown): Error {
|
|
173
|
-
|
|
183
|
+
const [gist = ''] = error_text.message_of(cause).split('\n', 1)
|
|
184
|
+
|
|
185
|
+
return new Error(`${UNREADABLE_PULL_REQUEST_MESSAGE}: ${branch_name} (${gist})`, { cause })
|
|
174
186
|
}
|
|
175
187
|
|
|
176
188
|
// The number for a caller that has nothing to fold an absence into. The reads above answer their own
|
|
@@ -213,6 +225,36 @@ async function read_remembered_pull(pr_number: number): Promise<RestPull> {
|
|
|
213
225
|
}
|
|
214
226
|
}
|
|
215
227
|
|
|
228
|
+
// The listing row for a detail read GitHub refused as too large (`git-gh-pr-too-large.ts`). The row
|
|
229
|
+
// carries neither `mergeable` nor `mergeable_state`, which every reader of them already takes as
|
|
230
|
+
// "not known yet". Any other failure — and a listing that no longer names the number — stays the
|
|
231
|
+
// detail read's own `unreadable`.
|
|
232
|
+
async function read_listed_pull(
|
|
233
|
+
detail_error: unknown,
|
|
234
|
+
branch_name: string,
|
|
235
|
+
pr_number: number,
|
|
236
|
+
): Promise<RestPull | undefined> {
|
|
237
|
+
if (!git_gh_pr_too_large.is_too_many_files(detail_error)) return undefined
|
|
238
|
+
const pull = await fetch_branch_pull(branch_name)
|
|
239
|
+
|
|
240
|
+
return pull?.number === pr_number ? pull : undefined
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
async function read_pull_or_listed(
|
|
244
|
+
branch_name: string,
|
|
245
|
+
pr_number: number,
|
|
246
|
+
read: (pr_number: number) => Promise<RestPull>,
|
|
247
|
+
): Promise<RestPull> {
|
|
248
|
+
try {
|
|
249
|
+
return await read(pr_number)
|
|
250
|
+
} catch (error) {
|
|
251
|
+
const listed = await read_listed_pull(error, branch_name, pr_number)
|
|
252
|
+
if (listed === undefined) throw error
|
|
253
|
+
|
|
254
|
+
return listed
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
216
258
|
// One pull request named by its branch: the resolution, then the detail read that carries
|
|
217
259
|
// `mergeable` and `mergeable_state`, which the lookup listing does not.
|
|
218
260
|
async function read_pull_of_branch(
|
|
@@ -223,7 +265,10 @@ async function read_pull_of_branch(
|
|
|
223
265
|
if (number_read.kind !== 'read') return number_read
|
|
224
266
|
|
|
225
267
|
try {
|
|
226
|
-
return {
|
|
268
|
+
return {
|
|
269
|
+
kind: 'read',
|
|
270
|
+
pull: await read_pull_or_listed(branch_name, number_read.pr_number, read),
|
|
271
|
+
}
|
|
227
272
|
} catch (error) {
|
|
228
273
|
return { kind: 'unreadable', cause: error }
|
|
229
274
|
}
|
|
@@ -301,25 +346,39 @@ async function pr_view(branch_name: string): Promise<string> {
|
|
|
301
346
|
return JSON.stringify(git_gh_pr_rest.to_pr_info(read.pull))
|
|
302
347
|
}
|
|
303
348
|
|
|
349
|
+
// gh's own reason for a lookup that never answered, or that the branch has no pull request at all.
|
|
350
|
+
function unresolved_reason(read: Exclude<PullNumberRead, { kind: 'read' }>): string {
|
|
351
|
+
return read.kind === 'unreadable' ? error_text.message_of(read.cause) : NO_PULL_REQUEST_MESSAGE
|
|
352
|
+
}
|
|
353
|
+
|
|
304
354
|
// `undefined` when the listing could not be read — a failed request, or a PR whose number could not
|
|
305
355
|
// be resolved. Not `'[]'`.
|
|
306
356
|
//
|
|
307
357
|
// The two are the same string to a caller, and the callers are the merge gate: a rate limit would
|
|
308
358
|
// arrive as "no reviewer left a finding" and the PR merge with the gate never actually read.
|
|
309
359
|
// The direction is what makes it worse than the epic auto-close's version of
|
|
310
|
-
// the same misread — that one only failed to close something.
|
|
360
|
+
// the same misread — that one only failed to close something. Either failure warns its reason
|
|
361
|
+
// (`git-gh-comments-unreadable.ts`).
|
|
311
362
|
async function read_comments(
|
|
312
363
|
branch_name: string,
|
|
313
364
|
to_path: (pr_number: string) => string,
|
|
314
365
|
to_json: (raw: string) => string,
|
|
315
366
|
): Promise<string | undefined> {
|
|
316
|
-
const
|
|
317
|
-
|
|
318
|
-
|
|
367
|
+
const read = await read_pr_number(branch_name)
|
|
368
|
+
|
|
369
|
+
if (read.kind !== 'read') {
|
|
370
|
+
note_unreadable_comments(branch_name, unresolved_reason(read))
|
|
371
|
+
|
|
372
|
+
return undefined
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
const path = `${to_path(String(read.pr_number))}${COMMENTS_QUERY}`
|
|
319
376
|
|
|
320
377
|
try {
|
|
321
378
|
return to_json(await git_gh_exec.exec_gh_api({ path, should_paginate: true }))
|
|
322
|
-
} catch {
|
|
379
|
+
} catch (error) {
|
|
380
|
+
note_unreadable_comments(branch_name, error_text.message_of(error))
|
|
381
|
+
|
|
323
382
|
return undefined
|
|
324
383
|
}
|
|
325
384
|
}
|
|
@@ -362,7 +421,9 @@ export type { PullMergeState }
|
|
|
362
421
|
export {
|
|
363
422
|
git_gh_pr_read,
|
|
364
423
|
forget_pr_numbers,
|
|
424
|
+
read_listed_pull,
|
|
365
425
|
read_pull,
|
|
426
|
+
read_pull_or_listed,
|
|
366
427
|
require_pr_number,
|
|
367
428
|
resolve_pr_number,
|
|
368
429
|
NO_PULL_REQUEST_MESSAGE,
|
|
@@ -145,7 +145,8 @@ function to_pr_info(pull: RestPull): Record<string, unknown> {
|
|
|
145
145
|
|
|
146
146
|
// The conversation comments in the shape `gh pr view --json comments` answered with. A listing that
|
|
147
147
|
// will not parse throws rather than answering an empty one — `git-pr-ai-review.ts` reads an empty
|
|
148
|
-
// listing as "no reviewer left a finding" and merges.
|
|
148
|
+
// listing as "no reviewer left a finding" and merges. `updatedAt` is when CodeRabbit last rewrote its
|
|
149
|
+
// rate-limit notice, the moment its stated window counts from (joshuafolkken/kit#5289).
|
|
149
150
|
function to_pr_comments(rest_json: string): Array<Record<string, unknown>> {
|
|
150
151
|
const parsed = parse_json_array_or_undefined(rest_json, rest_comment_schema)
|
|
151
152
|
if (parsed === undefined) throw new Error(NOT_A_COMMENT_LISTING_MESSAGE)
|
|
@@ -154,6 +155,7 @@ function to_pr_comments(rest_json: string): Array<Record<string, unknown>> {
|
|
|
154
155
|
body: comment.body ?? EMPTY_BODY,
|
|
155
156
|
url: comment.html_url,
|
|
156
157
|
author: { login: comment.user?.login },
|
|
158
|
+
updatedAt: comment.updated_at,
|
|
157
159
|
}))
|
|
158
160
|
}
|
|
159
161
|
|
|
@@ -2,13 +2,15 @@ import { FULL_PAGE_QUERY, git_gh_api_path } from './git-gh-api-path'
|
|
|
2
2
|
import { git_gh_branch_rules } from './git-gh-branch-rules'
|
|
3
3
|
import { git_gh_exec } from './git-gh-exec'
|
|
4
4
|
import { git_gh_poll_read } from './git-gh-poll-read'
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { git_gh_pr_graphql_state } from './git-gh-pr-graphql-state'
|
|
6
|
+
import { read_listed_pull, read_pull, require_pr_number } from './git-gh-pr-read'
|
|
7
|
+
import type { RestPull } from './git-gh-pr-rest'
|
|
7
8
|
import { git_gh_pr_review } from './git-gh-pr-review'
|
|
8
9
|
import { git_gh_pr_rollup } from './git-gh-pr-rollup'
|
|
9
10
|
import { to_gh_state } from './git-gh-rest-state'
|
|
10
11
|
|
|
11
|
-
// The merge gate's pull request state snapshot, rebuilt from REST
|
|
12
|
+
// The merge gate's pull request state snapshot, rebuilt from REST — GraphQL only for the merge state
|
|
13
|
+
// of a pull request whose REST detail GitHub refuses as too large (`resolve_pull`).
|
|
12
14
|
//
|
|
13
15
|
// `gh pr view --json mergeStateStatus,reviewDecision,statusCheckRollup` is answered 403 in a cloud
|
|
14
16
|
// session, and all three fields are GraphQL-only: one has no REST
|
|
@@ -93,13 +95,26 @@ interface ResolvedPull {
|
|
|
93
95
|
// **The detail is read without an ETag.** GitHub computes `mergeable_state` lazily and can change it
|
|
94
96
|
// under an unchanged ETag, so a 304 answered from the poll cache kept the gate reading a stale
|
|
95
97
|
// `blocked` on a pull request that had turned `clean` (joshuafolkken/kit#4589).
|
|
98
|
+
//
|
|
99
|
+
// **A detail GitHub refuses as too many files changed** is stood in for by the listing row, whose
|
|
100
|
+
// missing `mergeable_state` is read from GraphQL (`git-gh-pr-graphql-state.ts`) — or the snapshot
|
|
101
|
+
// throws with the reason, since an unknown state would hold the gate pending until its budget ran out.
|
|
102
|
+
async function read_detail_or_listed(branch_name: string, pr_number: number): Promise<RestPull> {
|
|
103
|
+
try {
|
|
104
|
+
return await read_pull(pr_number)
|
|
105
|
+
} catch (error) {
|
|
106
|
+
const listed = await read_listed_pull(error, branch_name, pr_number)
|
|
107
|
+
if (listed === undefined) throw error
|
|
108
|
+
const state = await git_gh_pr_graphql_state.read_merge_state_status(listed, error)
|
|
109
|
+
|
|
110
|
+
return { ...listed, mergeable_state: state }
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
96
114
|
async function resolve_pull(branch_name: string): Promise<ResolvedPull> {
|
|
97
115
|
const pr_number = await require_pr_number(branch_name)
|
|
98
|
-
const json = await git_gh_exec.exec_gh_api({
|
|
99
|
-
path: git_gh_api_path.pull_api_path(String(pr_number)),
|
|
100
|
-
})
|
|
101
116
|
|
|
102
|
-
return { pr_number, pull:
|
|
117
|
+
return { pr_number, pull: await read_detail_or_listed(branch_name, pr_number) }
|
|
103
118
|
}
|
|
104
119
|
|
|
105
120
|
// Everything the snapshot carries except the review decision: three requests rather than four.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { error_text } from '#scripts/lib/error-message'
|
|
2
|
+
import { gh_failure } from './git-gh-failure'
|
|
3
|
+
|
|
4
|
+
// GitHub refuses the single-pull JSON (`GET /pulls/{N}`) of some pull requests with
|
|
5
|
+
// `HTTP 422: … too many files changed`, every time, however few files the pull request changes — while
|
|
6
|
+
// the listing, the files, the diff and GraphQL all answer for the same one (joshuafolkken/kit#5226).
|
|
7
|
+
// The refusal is about that one response, so the branch-keyed reads fall back to the listing row
|
|
8
|
+
// rather than reporting the pull request unreadable.
|
|
9
|
+
const UNPROCESSABLE_STATUS = 422
|
|
10
|
+
const TOO_MANY_FILES_TEXT = 'too many files changed'
|
|
11
|
+
|
|
12
|
+
function is_too_many_files(error: unknown): boolean {
|
|
13
|
+
if (gh_failure.failure_of(error)?.status !== UNPROCESSABLE_STATUS) return false
|
|
14
|
+
|
|
15
|
+
return error_text.message_of(error).includes(TOO_MANY_FILES_TEXT)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const git_gh_pr_too_large = { is_too_many_files }
|
|
19
|
+
|
|
20
|
+
export { git_gh_pr_too_large }
|
package/scripts/gh/git-gh-pr.ts
CHANGED
|
@@ -6,7 +6,13 @@ import { git_gh_exec } from './git-gh-exec'
|
|
|
6
6
|
import { gh_failure } from './git-gh-failure'
|
|
7
7
|
import { git_gh_helpers } from './git-gh-helpers'
|
|
8
8
|
import { git_gh_issue_write } from './git-gh-issue-write'
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
forget_pr_numbers,
|
|
11
|
+
git_gh_pr_read,
|
|
12
|
+
read_pull,
|
|
13
|
+
read_pull_or_listed,
|
|
14
|
+
require_pr_number,
|
|
15
|
+
} from './git-gh-pr-read'
|
|
10
16
|
import { git_gh_pr_rest } from './git-gh-pr-rest'
|
|
11
17
|
import { git_gh_pr_snapshot } from './git-gh-pr-snapshot'
|
|
12
18
|
|
|
@@ -188,10 +194,14 @@ function is_head_moved(error: unknown): boolean {
|
|
|
188
194
|
}
|
|
189
195
|
|
|
190
196
|
// `undefined` is "nobody read it", kept apart from the `false` that means "the pull request is not
|
|
191
|
-
// merged". Folding the two would report an unread state as a settled answer.
|
|
192
|
-
|
|
197
|
+
// merged". Folding the two would report an unread state as a settled answer. The listing row, which
|
|
198
|
+
// carries `merged_at` too, stands in for a detail GitHub refuses as too many files changed.
|
|
199
|
+
async function read_merge_state(
|
|
200
|
+
branch_name: string,
|
|
201
|
+
pr_number: number,
|
|
202
|
+
): Promise<boolean | undefined> {
|
|
193
203
|
try {
|
|
194
|
-
return git_gh_pr_rest.is_merged(await
|
|
204
|
+
return git_gh_pr_rest.is_merged(await read_pull_or_listed(branch_name, pr_number, read_pull))
|
|
195
205
|
} catch (error) {
|
|
196
206
|
// The reason goes in the line, for the same reason the poll loop's warning carries one: the
|
|
197
207
|
// failure this throws below names the *merge* request as its cause, so without this an operator
|
|
@@ -220,10 +230,14 @@ async function sleep_between_read_backs(attempt: number): Promise<void> {
|
|
|
220
230
|
// **A read that failed is still not an answer.** Out of attempts it throws rather than reporting
|
|
221
231
|
// `false`, carrying the merge failure as its `cause`, so no run ever concludes "the merge did not
|
|
222
232
|
// happen" from a read nobody got.
|
|
223
|
-
async function has_merge_landed(
|
|
233
|
+
async function has_merge_landed(
|
|
234
|
+
branch_name: string,
|
|
235
|
+
pr_number: number,
|
|
236
|
+
merge_error: unknown,
|
|
237
|
+
): Promise<boolean> {
|
|
224
238
|
for (let attempt = 0; attempt < MERGE_READ_BACK_ATTEMPTS; attempt += 1) {
|
|
225
239
|
// eslint-disable-next-line no-await-in-loop -- a retry runs only after the previous attempt has answered
|
|
226
|
-
const is_merged = await read_merge_state(pr_number)
|
|
240
|
+
const is_merged = await read_merge_state(branch_name, pr_number)
|
|
227
241
|
if (is_merged !== undefined) return is_merged
|
|
228
242
|
|
|
229
243
|
// eslint-disable-next-line no-await-in-loop -- a retry runs only after the previous attempt has answered
|
|
@@ -257,7 +271,7 @@ async function pr_merge(branch_name: string, head_sha: string): Promise<void> {
|
|
|
257
271
|
try {
|
|
258
272
|
await put_merge(pr_number, head_sha)
|
|
259
273
|
} catch (error) {
|
|
260
|
-
if (!(await has_merge_landed(pr_number, error))) throw error
|
|
274
|
+
if (!(await has_merge_landed(branch_name, pr_number, error))) throw error
|
|
261
275
|
}
|
|
262
276
|
}
|
|
263
277
|
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { setTimeout as delay } from 'node:timers/promises'
|
|
2
|
+
import { get_exit_code, has_timed_out } from '#scripts/git/git-execa-error'
|
|
3
|
+
import { error_text } from '#scripts/lib/error-message'
|
|
4
|
+
import { gh_failure } from './git-gh-failure'
|
|
5
|
+
|
|
6
|
+
// One REST request asked again, a bounded number of times, when GitHub failed it transiently
|
|
7
|
+
// (joshuafolkken/kit#4717). A single 502 on `review:record --comment` used to stop a whole ship stage
|
|
8
|
+
// and cost a relaunched session that changed nothing; the same request seconds later succeeds.
|
|
9
|
+
//
|
|
10
|
+
// **Transient is a 5xx or a request that got no answer at all** — a dropped connection writes no
|
|
11
|
+
// error document, so its status is `undefined`. A 4xx is the request's own fault and answers the same
|
|
12
|
+
// the next time. Three failures without a status are still not retried: a timeout (it has already
|
|
13
|
+
// spent a minute, and a write it killed may have landed — `GH_REQUEST_TIMEOUT_MS`'s note), an error
|
|
14
|
+
// `to_gh_error` never built (gh missing, a refused body), which no wait can change, and one that wrote
|
|
15
|
+
// a body anyway — a GraphQL `errors` document is served with a 200, so it names no status and is
|
|
16
|
+
// still GitHub's answer.
|
|
17
|
+
//
|
|
18
|
+
// **A retried write can land twice** when the first attempt reached GitHub before it failed. The
|
|
19
|
+
// writes on this path tolerate it: a duplicate pull request is refused with the 422 the creator reads
|
|
20
|
+
// (`handle_pr_create_error`), a repeated merge is read back by `has_merge_landed`, and at worst a
|
|
21
|
+
// review-round comment is posted twice — cheaper than the stopped stage it replaces. Issue creation
|
|
22
|
+
// has no such guard — a second issue opens and nothing reads the first back — so
|
|
23
|
+
// `issue_create_request` opts out with `should_retry: false`.
|
|
24
|
+
|
|
25
|
+
const FIRST_RETRY_DELAY_MS = 2000
|
|
26
|
+
const SECOND_RETRY_DELAY_MS = 5000
|
|
27
|
+
const RETRY_DELAYS_MS = [FIRST_RETRY_DELAY_MS, SECOND_RETRY_DELAY_MS]
|
|
28
|
+
const MAX_ATTEMPTS = RETRY_DELAYS_MS.length + 1
|
|
29
|
+
const SERVER_ERROR_FLOOR = 500
|
|
30
|
+
// gh's own exit code for "authentication required" (`gh auth login`, no `GH_TOKEN`). It writes no
|
|
31
|
+
// error document either, so without this it would read as a request that got no answer — and no
|
|
32
|
+
// wait logs anyone in.
|
|
33
|
+
const GH_AUTH_REQUIRED_EXIT_CODE = 4
|
|
34
|
+
|
|
35
|
+
const SPENT_NOTE = 'gh: request failed transiently on every attempt'
|
|
36
|
+
|
|
37
|
+
// gh's own summary line for a failed request, e.g. `gh: Server Error (HTTP 502)`. It is the only
|
|
38
|
+
// place the status is written when the body is an HTML error page rather than GitHub's JSON document.
|
|
39
|
+
const SUMMARY_STATUS_PATTERN = /\(HTTP (?<status>\d{3})\)/u
|
|
40
|
+
|
|
41
|
+
interface RetryHooks {
|
|
42
|
+
wait: (milliseconds: number) => Promise<void>
|
|
43
|
+
note: (text: string) => void
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const DEFAULT_HOOKS: RetryHooks = {
|
|
47
|
+
wait: async (milliseconds) => {
|
|
48
|
+
await delay(milliseconds)
|
|
49
|
+
},
|
|
50
|
+
note: (text) => {
|
|
51
|
+
process.stderr.write(`${text}\n`)
|
|
52
|
+
},
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function summary_status(error: Error): number | undefined {
|
|
56
|
+
const { status } = SUMMARY_STATUS_PATTERN.exec(error.message)?.groups ?? {}
|
|
57
|
+
|
|
58
|
+
return status === undefined ? undefined : Number(status)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Whether the failed spawn wrote a response body: a request that got no answer at all wrote none.
|
|
62
|
+
function has_answer(spawn_error: unknown): boolean {
|
|
63
|
+
if (!(spawn_error instanceof Error) || !('stdout' in spawn_error)) return false
|
|
64
|
+
|
|
65
|
+
return typeof spawn_error.stdout === 'string' && spawn_error.stdout.trim().length > 0
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function is_transient_status(status: number | undefined, spawn_error: unknown): boolean {
|
|
69
|
+
if (status === undefined) return !has_answer(spawn_error)
|
|
70
|
+
|
|
71
|
+
return status >= SERVER_ERROR_FLOOR
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// A spawn no wait can change: one it killed on its budget, or one gh refused before asking.
|
|
75
|
+
function is_final_spawn(spawn_error: unknown): boolean {
|
|
76
|
+
return has_timed_out(spawn_error) || get_exit_code(spawn_error) === GH_AUTH_REQUIRED_EXIT_CODE
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function is_transient(error: unknown): boolean {
|
|
80
|
+
const failure = gh_failure.failure_of(error)
|
|
81
|
+
|
|
82
|
+
if (failure === undefined || !(error instanceof Error)) return false
|
|
83
|
+
|
|
84
|
+
const status = failure.status ?? summary_status(error)
|
|
85
|
+
|
|
86
|
+
return !is_final_spawn(error.cause) && is_transient_status(status, error.cause)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function first_line(error: unknown): string {
|
|
90
|
+
return error_text.message_of(error).split('\n', 1)[0] ?? ''
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function retry_note(error: unknown, attempt: number, wait_ms: number): string {
|
|
94
|
+
const ordinal = `${String(attempt)}/${String(MAX_ATTEMPTS)}`
|
|
95
|
+
|
|
96
|
+
return `gh: request failed transiently (attempt ${ordinal}: ${first_line(error)}) — retrying in ${String(wait_ms)} ms`
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// The wait before asking again, or `undefined` when this failure is final — not transient, or the
|
|
100
|
+
// last attempt spent.
|
|
101
|
+
function retry_delay(error: unknown, attempt: number): number | undefined {
|
|
102
|
+
return is_transient(error) ? RETRY_DELAYS_MS[attempt - 1] : undefined
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// The line a request transient to its last attempt leaves on stderr, naming the failure by the first
|
|
106
|
+
// line of its message: a stopped `josh ship` stage that ended on that failure reads it as the
|
|
107
|
+
// infrastructure (joshuafolkken/kit#5052). A recovered retry writes none.
|
|
108
|
+
function spent_note(message: string): string {
|
|
109
|
+
return `${SPENT_NOTE} (${message})`
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function note_spent(error: unknown, attempt: number, hooks: RetryHooks): void {
|
|
113
|
+
if (attempt === MAX_ATTEMPTS && is_transient(error)) hooks.note(spent_note(first_line(error)))
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async function with_retry<T>(
|
|
117
|
+
request: () => Promise<T>,
|
|
118
|
+
hooks: RetryHooks = DEFAULT_HOOKS,
|
|
119
|
+
attempt = 1,
|
|
120
|
+
): Promise<T> {
|
|
121
|
+
try {
|
|
122
|
+
return await request()
|
|
123
|
+
} catch (error) {
|
|
124
|
+
const wait_ms = retry_delay(error, attempt)
|
|
125
|
+
|
|
126
|
+
if (wait_ms === undefined) {
|
|
127
|
+
note_spent(error, attempt, hooks)
|
|
128
|
+
throw error
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
hooks.note(retry_note(error, attempt, wait_ms))
|
|
132
|
+
await hooks.wait(wait_ms)
|
|
133
|
+
|
|
134
|
+
return await with_retry(request, hooks, attempt + 1)
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const gh_retry = { MAX_ATTEMPTS, RETRY_DELAYS_MS, is_transient, spent_note, with_retry }
|
|
139
|
+
|
|
140
|
+
export type { RetryHooks }
|
|
141
|
+
export { gh_retry }
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
type ReviewComment,
|
|
8
8
|
} from './git-ai-review-scan'
|
|
9
9
|
import { git_gh_command } from './git-gh-command'
|
|
10
|
+
import { is_retry_pending, note_unreadable_stop } from './git-gh-comments-unreadable'
|
|
10
11
|
import { git_pr_confirmation, has_ignore_reason, type TelegramContext } from './git-pr-confirmation'
|
|
11
12
|
|
|
12
13
|
interface AiReviewPullComment {
|
|
@@ -132,6 +133,19 @@ const UNREADABLE_COMMENTS_BODY =
|
|
|
132
133
|
// never read the gate reports exactly like one that read it and found nothing.
|
|
133
134
|
const UNREADABLE_COMMENTS_NOTE = 'AI reviewer comments could not be read; the scan was bypassed.'
|
|
134
135
|
|
|
136
|
+
// An attempt the ship will run again sends no confirmation; the final one does (is_retry_pending).
|
|
137
|
+
async function confirm_unreadable_stop(context: TelegramContext): Promise<void> {
|
|
138
|
+
note_unreadable_stop()
|
|
139
|
+
if (is_retry_pending()) return
|
|
140
|
+
|
|
141
|
+
await git_pr_confirmation.notify_confirmation({
|
|
142
|
+
context,
|
|
143
|
+
body: UNREADABLE_COMMENTS_BODY,
|
|
144
|
+
recommended: 'Re-run `pnpm josh followup` once the comments can be read',
|
|
145
|
+
alternatives: [IGNORE_ALTERNATIVE],
|
|
146
|
+
})
|
|
147
|
+
}
|
|
148
|
+
|
|
135
149
|
async function handle_unreadable_comments(input: {
|
|
136
150
|
branch_name: string
|
|
137
151
|
ignore_reason: string | undefined
|
|
@@ -146,12 +160,7 @@ async function handle_unreadable_comments(input: {
|
|
|
146
160
|
return [UNREADABLE_COMMENTS_NOTE]
|
|
147
161
|
}
|
|
148
162
|
|
|
149
|
-
await
|
|
150
|
-
context: input.context,
|
|
151
|
-
body: UNREADABLE_COMMENTS_BODY,
|
|
152
|
-
recommended: 'Re-run `pnpm josh followup` once the comments can be read',
|
|
153
|
-
alternatives: [IGNORE_ALTERNATIVE],
|
|
154
|
-
})
|
|
163
|
+
await confirm_unreadable_stop(input.context)
|
|
155
164
|
|
|
156
165
|
throw new Error(UNREADABLE_COMMENTS_BODY)
|
|
157
166
|
}
|
|
@@ -48,10 +48,10 @@ function get_configured_max_attempts(): number {
|
|
|
48
48
|
const CHECK_MAX_ATTEMPTS = get_configured_max_attempts()
|
|
49
49
|
const DEFAULT_STABLE_READS = 2
|
|
50
50
|
|
|
51
|
-
// One authoritative gate poll is enough once `pr_checks_watch` has
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
//
|
|
51
|
+
// One authoritative gate poll is enough once `pr_checks_watch` has returned — every check finished, or
|
|
52
|
+
// its budget ran out on a pending read. The two reads exist for the pending→settled window a bare poll
|
|
53
|
+
// opens on, and a returned watch has either spanned that window or seen its pending side, which the
|
|
54
|
+
// poll's first settled read then closes — so a second interval merely re-proves it (#5080).
|
|
55
55
|
const WATCH_CONFIRMED_STABLE_READS = 1
|
|
56
56
|
|
|
57
57
|
// **A read that failed is not a verdict.** The loop reads every ten seconds, so a dropped connection,
|
|
@@ -314,7 +314,7 @@ async function default_fetch_pr_state(
|
|
|
314
314
|
}
|
|
315
315
|
|
|
316
316
|
// **`required_stable_reads` is a parameter, not a constant, so the caller can lower it** — `run_checks`
|
|
317
|
-
// passes `WATCH_CONFIRMED_STABLE_READS` when the watch
|
|
317
|
+
// passes `WATCH_CONFIRMED_STABLE_READS` when the watch returned. It defaults to
|
|
318
318
|
// `DEFAULT_STABLE_READS`, so every caller that names only the branch is exactly where it was.
|
|
319
319
|
// What a caller is shown of each poll it waits on — `followup` reports the checks to the run's event
|
|
320
320
|
// stream from it (joshuafolkken/kit#3770). It decides nothing: the wait reads the same snapshot.
|
package/scripts/git/base-tree.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { rmSync } from 'node:fs'
|
|
1
2
|
import { copyFile, mkdir, mkdtemp, rm, symlink } from 'node:fs/promises'
|
|
2
3
|
import { tmpdir } from 'node:os'
|
|
3
4
|
import path from 'node:path'
|
|
@@ -13,6 +14,12 @@ import { git_worktree } from './git-worktree'
|
|
|
13
14
|
|
|
14
15
|
const TREE_NAME = 'tree'
|
|
15
16
|
const NODE_MODULES = 'node_modules'
|
|
17
|
+
const TERMINATE_SIGNAL = 'SIGTERM'
|
|
18
|
+
// 128 + SIGTERM's 15: the code the process would have exited with had no listener caught the signal.
|
|
19
|
+
const TERMINATED_EXIT_CODE = 143
|
|
20
|
+
|
|
21
|
+
// The temp directories of the trees this process holds now.
|
|
22
|
+
const live_parents = new Set<string>()
|
|
16
23
|
|
|
17
24
|
interface BaseTree {
|
|
18
25
|
// The temp directory holding the tree — a file written here sits beside the tree, never in it.
|
|
@@ -43,6 +50,26 @@ async function remove(base_tree: BaseTree): Promise<void> {
|
|
|
43
50
|
}
|
|
44
51
|
}
|
|
45
52
|
|
|
53
|
+
// **A terminated run removes its trees before it exits** (joshuafolkken/kit#4794): `josh run:review
|
|
54
|
+
// --join` stops a `test:pinned` that fell behind, and a `finally` never runs past a signal, so each
|
|
55
|
+
// tree would stay in the temp directory and in `git worktree list`. The removal is synchronous because
|
|
56
|
+
// the process exits right after it; the next `with_tree`'s prune drops the registrations.
|
|
57
|
+
function remove_live_trees(): void {
|
|
58
|
+
for (const parent of live_parents) rmSync(parent, { force: true, recursive: true })
|
|
59
|
+
|
|
60
|
+
process.exit(TERMINATED_EXIT_CODE)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function track(parent: string): void {
|
|
64
|
+
if (live_parents.size === 0) process.on(TERMINATE_SIGNAL, remove_live_trees)
|
|
65
|
+
live_parents.add(parent)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function untrack(parent: string): void {
|
|
69
|
+
live_parents.delete(parent)
|
|
70
|
+
if (live_parents.size === 0) process.off(TERMINATE_SIGNAL, remove_live_trees)
|
|
71
|
+
}
|
|
72
|
+
|
|
46
73
|
async function with_tree<T>(
|
|
47
74
|
prefix: string,
|
|
48
75
|
commit: string,
|
|
@@ -51,12 +78,15 @@ async function with_tree<T>(
|
|
|
51
78
|
const parent = await mkdtemp(path.join(tmpdir(), prefix))
|
|
52
79
|
const base_tree = { parent, tree: path.join(parent, TREE_NAME) }
|
|
53
80
|
|
|
81
|
+
track(parent)
|
|
82
|
+
|
|
54
83
|
try {
|
|
55
84
|
await prepare(base_tree.tree, commit)
|
|
56
85
|
|
|
57
86
|
return await use(base_tree)
|
|
58
87
|
} finally {
|
|
59
88
|
await remove(base_tree)
|
|
89
|
+
untrack(parent)
|
|
60
90
|
}
|
|
61
91
|
}
|
|
62
92
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { git_command } from './git-command'
|
|
2
|
+
import { git_diff_reads } from './git-diff-reads'
|
|
2
3
|
import { git_spawn } from './git-spawn'
|
|
3
4
|
|
|
4
5
|
// **The change base as a commit, or nothing — never a ref name**.
|
|
@@ -22,29 +23,22 @@ async function resolved(): Promise<string | undefined> {
|
|
|
22
23
|
}
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
const MERGE_BASE_COMMAND = 'merge-base'
|
|
26
|
-
const MERGE_HEAD = 'MERGE_HEAD'
|
|
27
|
-
const LINE_BREAK = '\n'
|
|
28
|
-
|
|
29
26
|
// Where the side a merge in progress brings in left the default branch — `undefined` where no merge
|
|
30
27
|
// is in progress, which is every ordinary run.
|
|
31
28
|
async function incoming_base(): Promise<string | undefined> {
|
|
32
29
|
try {
|
|
33
30
|
const reference = await git_command.default_branch_reference()
|
|
34
31
|
|
|
35
|
-
return await git_spawn.read([
|
|
32
|
+
return await git_spawn.read([...git_diff_reads.incoming_base_arguments(reference)])
|
|
36
33
|
} catch {
|
|
37
34
|
return undefined
|
|
38
35
|
}
|
|
39
36
|
}
|
|
40
37
|
|
|
41
|
-
// `--independent` drops every commit another one listed reaches, so of two commits on the default
|
|
42
|
-
// branch's history it keeps the later.
|
|
43
38
|
async function later_of(base: string, incoming: string): Promise<string> {
|
|
44
|
-
const kept = await git_spawn.read([
|
|
45
|
-
const [later = base] = kept.split(LINE_BREAK)
|
|
39
|
+
const kept = await git_spawn.read([...git_diff_reads.later_base_arguments(base, incoming)])
|
|
46
40
|
|
|
47
|
-
return
|
|
41
|
+
return git_diff_reads.later_base_of(kept, base)
|
|
48
42
|
}
|
|
49
43
|
|
|
50
44
|
// **The base of the tree, not of `HEAD`, while a merge is in progress.** A merge of the default
|