@joshuafolkken/kit 1.1784.0 → 1.2114.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 +59 -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 +415 -389
- 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 +15 -8
- 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
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// The issue-number citation ceiling of every agent-read document — an exact ratchet.
|
|
2
|
+
//
|
|
3
|
+
// Issue-number citations and the "why / measured / rejected" prose around them are what swell the
|
|
4
|
+
// documents an agent reads at run time; a reduction epic cuts them only for the next PRs to add them
|
|
5
|
+
// back, because nothing held the reduced count. This list is that hold:
|
|
6
|
+
// `issue-citation-budget.test.ts` fails `pnpm josh gate` when an agent-read document cites more issue
|
|
7
|
+
// numbers than its entry records, and when it cites fewer — a reduction must lower its entry in the
|
|
8
|
+
// same PR, so the ceiling follows the count down and never sits loose above it. A document absent from
|
|
9
|
+
// the list has a ceiling of zero. History belongs in `docs/maintainers/<topic>-rationale.md`, which
|
|
10
|
+
// this budget does not hold (`docs/maintainers/residency-rationale.md` → "The issue-citation ratchet").
|
|
11
|
+
//
|
|
12
|
+
// The ratchet is exact rather than block-quantized like `document-byte-budget.ts`: a single added
|
|
13
|
+
// citation is the growth this exists to refuse, so there is no headroom to quantize.
|
|
14
|
+
|
|
15
|
+
interface CitationBudget {
|
|
16
|
+
path: string
|
|
17
|
+
citations: number
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// An issue number as a document cites it — `#1234` or `joshuafolkken/kit#1234`. Three digits or more,
|
|
21
|
+
// so a placeholder (`#N`, `#<N>`) and a list ordinal are not counted.
|
|
22
|
+
const CITATION_PATTERN = /#\d{3,}\b/gu
|
|
23
|
+
|
|
24
|
+
const ISSUE_CITATION_BUDGET: ReadonlyArray<CitationBudget> = [
|
|
25
|
+
{ path: 'docs/josh-commands-backlog.md', citations: 13 },
|
|
26
|
+
{ path: 'docs/josh-commands-run.md', citations: 4 },
|
|
27
|
+
{ path: 'docs/josh-commands.md', citations: 2 },
|
|
28
|
+
{ path: 'prompts/collaboration-workflow/file-edits.md', citations: 1 },
|
|
29
|
+
{ path: 'prompts/collaboration-workflow/glossary.md', citations: 1 },
|
|
30
|
+
{ path: 'prompts/collaboration-workflow/issue-citation.md', citations: 1 },
|
|
31
|
+
{ path: 'prompts/collaboration-workflow/issue-template.md', citations: 5 },
|
|
32
|
+
{ path: 'prompts/collaboration-workflow/operating-rules.md', citations: 3 },
|
|
33
|
+
{ path: 'prompts/collaboration-workflow/output-bounds.md', citations: 3 },
|
|
34
|
+
{ path: 'prompts/collaboration-workflow/overview.md', citations: 1 },
|
|
35
|
+
{ path: 'prompts/collaboration-workflow/plan-comment.md', citations: 1 },
|
|
36
|
+
{ path: 'prompts/collaboration-workflow/principles.md', citations: 1 },
|
|
37
|
+
{ path: 'prompts/collaboration-workflow/report-format.md', citations: 7 },
|
|
38
|
+
{ path: 'prompts/collaboration-workflow/residency.md', citations: 3 },
|
|
39
|
+
{ path: 'prompts/collaboration-workflow/rule-delivery.md', citations: 5 },
|
|
40
|
+
{ path: 'prompts/collaboration-workflow/shell-body.md', citations: 2 },
|
|
41
|
+
{ path: 'prompts/collaboration-workflow/turn-batching.md', citations: 2 },
|
|
42
|
+
{ path: 'prompts/collaboration-workflow/upstream-interrupt.md', citations: 1 },
|
|
43
|
+
{ path: 'prompts/collaboration-workflow/wip-cap.md', citations: 2 },
|
|
44
|
+
{ path: 'prompts/refactoring.md', citations: 1 },
|
|
45
|
+
{ path: 'prompts/review-rubric.md', citations: 1 },
|
|
46
|
+
{ path: 'prompts/sonar-hotspot-handling.md', citations: 2 },
|
|
47
|
+
{ path: 'prompts/testing-guide.md', citations: 3 },
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
const BUDGET_FILE = 'scripts/document/issue-citation-budget.ts'
|
|
51
|
+
|
|
52
|
+
function count_citations(text: string): number {
|
|
53
|
+
return text.match(CITATION_PATTERN)?.length ?? 0
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// The recorded ceiling for one path — zero when the list carries no entry for it.
|
|
57
|
+
function recorded_citations_for(relative_path: string): number {
|
|
58
|
+
return ISSUE_CITATION_BUDGET.find((entry) => entry.path === relative_path)?.citations ?? 0
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function over_budget_message(relative_path: string, current: number, recorded: number): string {
|
|
62
|
+
const hint = `move the history to docs/maintainers/<topic>-rationale.md, or record ${current.toString()} in ${BUDGET_FILE} so the reason shows in the PR diff`
|
|
63
|
+
|
|
64
|
+
return `${relative_path} cites ${current.toString()} issue numbers, over its ceiling of ${recorded.toString()}. Cut the citations — ${hint}.`
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function stale_budget_message(relative_path: string, current: number, recorded: number): string {
|
|
68
|
+
const hint = `lower its entry to ${current.toString()} in ${BUDGET_FILE} (remove the entry at 0) so the ratchet holds the reduction`
|
|
69
|
+
|
|
70
|
+
return `${relative_path} cites ${current.toString()} issue numbers but records ${recorded.toString()}. ${hint}.`
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// The failure for one document, or undefined when its count equals its record. Growth and a
|
|
74
|
+
// reduction left unrecorded both fail, which is what makes the ceiling a ratchet rather than a cap.
|
|
75
|
+
function citation_violation(
|
|
76
|
+
relative_path: string,
|
|
77
|
+
current: number,
|
|
78
|
+
recorded: number,
|
|
79
|
+
): string | undefined {
|
|
80
|
+
if (current > recorded) return over_budget_message(relative_path, current, recorded)
|
|
81
|
+
if (current < recorded) return stale_budget_message(relative_path, current, recorded)
|
|
82
|
+
|
|
83
|
+
return undefined
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const issue_citation_budget = {
|
|
87
|
+
ISSUE_CITATION_BUDGET,
|
|
88
|
+
citation_violation,
|
|
89
|
+
count_citations,
|
|
90
|
+
recorded_citations_for,
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export type { CitationBudget }
|
|
94
|
+
export { issue_citation_budget }
|
|
@@ -33,9 +33,9 @@ interface FormFlags {
|
|
|
33
33
|
value_flags?: ReadonlyArray<string>
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
type OptionEntry = [string, ParseArgsOptionsConfig[string]]
|
|
37
|
-
|
|
38
36
|
function options_of(form: FormFlags): ParseArgsOptionsConfig {
|
|
37
|
+
type OptionEntry = [string, ParseArgsOptionsConfig[string]]
|
|
38
|
+
|
|
39
39
|
const entries: Array<OptionEntry> = [
|
|
40
40
|
...form.switches.map((flag): OptionEntry => [cli_flags.option_name(flag), SWITCH_OPTION]),
|
|
41
41
|
...(form.value_flags ?? []).map((flag): OptionEntry => [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { git_gh_command } from '#scripts/gh/git-gh-command'
|
|
2
2
|
import type { IssueReadFailure } from '#scripts/gh/git-gh-issue-read'
|
|
3
|
-
import {
|
|
3
|
+
import { issue_sample_prime } from '#scripts/issue/issue-sample-prime'
|
|
4
4
|
import { epic_cross_repo } from './epic-cross-repo'
|
|
5
5
|
import type { EpicChild, IssueReference } from './epic-graph'
|
|
6
6
|
import { epic_issue, type EpicIssue } from './epic-issue'
|
|
@@ -23,6 +23,8 @@ function to_child(parsed: EpicIssue, repo: string): EpicChild {
|
|
|
23
23
|
labels: epic_issue.label_names(parsed),
|
|
24
24
|
blocked_by: epic_issue.blocker_references_of(parsed, repo),
|
|
25
25
|
body: parsed.body,
|
|
26
|
+
author_association: parsed.author_association,
|
|
27
|
+
user: parsed.user,
|
|
26
28
|
}
|
|
27
29
|
}
|
|
28
30
|
|
|
@@ -134,7 +136,7 @@ async function fetch_child_read(
|
|
|
134
136
|
|
|
135
137
|
const parsed = epic_issue.parse_epic_issue(read.json)
|
|
136
138
|
|
|
137
|
-
await
|
|
139
|
+
await issue_sample_prime.prime([parsed?.body])
|
|
138
140
|
|
|
139
141
|
return { child: parsed === undefined ? undefined : to_child(parsed, repo), is_unreachable: false }
|
|
140
142
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AuthorFields } from '#scripts/gh/gh-author-association'
|
|
1
2
|
import type { DependencyLink } from './epic-parse'
|
|
2
3
|
import {
|
|
3
4
|
format_dependency_link,
|
|
@@ -23,13 +24,17 @@ import {
|
|
|
23
24
|
// exist, `blocker_categories` dropped it, and the child ran as though nothing blocked it. It also
|
|
24
25
|
// made `epic_cross_repo.resolve_cross_repo`'s cross-repository branch unreachable: every blocker
|
|
25
26
|
// arrived carrying the blocked child's repository, so `blocker.repo === blocked.repo` always held.
|
|
26
|
-
|
|
27
|
+
//
|
|
28
|
+
// The author fields (`AuthorFields`) are read only by `backlog:next`, which offers a child only when
|
|
29
|
+
// its author has write access (joshuafolkken/kit#4633); absent on rows built without a read.
|
|
30
|
+
interface EpicChild extends AuthorFields {
|
|
27
31
|
number: number
|
|
28
32
|
repo: string
|
|
29
33
|
state: 'OPEN' | 'CLOSED'
|
|
30
34
|
labels: ReadonlyArray<string>
|
|
31
35
|
blocked_by: ReadonlyArray<IssueReference>
|
|
32
|
-
// Read
|
|
36
|
+
// Read to hold a child until its declared start time and to rank it by its causing-lane minutes;
|
|
37
|
+
// absent on rows built without a read.
|
|
33
38
|
body?: string | undefined
|
|
34
39
|
}
|
|
35
40
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { git_gh_issue_rest } from '#scripts/gh/git-gh-issue-rest'
|
|
2
|
-
import { blocked_by_schema } from '#scripts/git/git-schemas'
|
|
2
|
+
import { author_fields_schema, blocked_by_schema } from '#scripts/git/git-schemas'
|
|
3
3
|
import { parse_json_object_or_undefined } from '#scripts/git/parse-json-array'
|
|
4
4
|
import { z } from 'zod'
|
|
5
5
|
import { REPOSITORY_SEGMENT_SOURCE } from './epic-parse'
|
|
@@ -36,6 +36,8 @@ const epic_issue_schema = z.object({
|
|
|
36
36
|
url: z.string().default(''),
|
|
37
37
|
labels: z.array(label_schema).default([]),
|
|
38
38
|
blockedBy: blocked_by_schema,
|
|
39
|
+
// Who filed the issue, for `backlog:next`'s author-trust check (joshuafolkken/kit#4633).
|
|
40
|
+
...author_fields_schema,
|
|
39
41
|
})
|
|
40
42
|
|
|
41
43
|
type EpicIssue = z.infer<typeof epic_issue_schema>
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { expected_effect_lint } from '#scripts/issue/expected-effect-lint'
|
|
2
|
+
import { issue_priority } from '#scripts/issue/issue-priority'
|
|
1
3
|
import { issue_rank } from '#scripts/issue/issue-rank'
|
|
2
4
|
import { epic_graph, type EpicChild } from './epic-graph'
|
|
3
5
|
|
|
@@ -27,7 +29,10 @@ function rank(
|
|
|
27
29
|
const dependents = dependents_of(pool)
|
|
28
30
|
|
|
29
31
|
return issue_rank.rank(children, (child) => ({
|
|
32
|
+
is_last: issue_priority.is_last(child.body),
|
|
30
33
|
labels: child.labels,
|
|
34
|
+
lost_minutes: issue_priority.lost_minutes(child.body),
|
|
35
|
+
gain_minutes: expected_effect_lint.weekly_minutes(child.body),
|
|
31
36
|
dependents: dependents.get(epic_graph.key_of(child)) ?? 0,
|
|
32
37
|
}))
|
|
33
38
|
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
import { doctor_consumer } from '#scripts/doctor/doctor-consumer'
|
|
3
|
+
import { NOTHING_TO_CHECK_MARKER } from '#scripts/test/skip-marker'
|
|
4
|
+
import type { NamespaceMember } from '#tools/exports/namespace-members'
|
|
5
|
+
|
|
6
|
+
const CHECK = 'exports'
|
|
7
|
+
const FAIL_EXIT_CODE = 1
|
|
8
|
+
// A consumer's namespaces are read from `.svelte` files and routes a TypeScript program over its
|
|
9
|
+
// `tsconfig.json` does not see, so every member they use would read as unused. The check is kit's own.
|
|
10
|
+
//
|
|
11
|
+
// **Not a skip notice**. `SKIP_MARKER` means "a check passed without running",
|
|
12
|
+
// and the gate withholds its green record on it — so a consumer, where this notice prints on every
|
|
13
|
+
// run, never got a green record. Out of scope by design is not unverified, so the marker stays out.
|
|
14
|
+
const CONSUMER_NOTICE = `josh ${CHECK}: checks only the kit repository itself — ${NOTHING_TO_CHECK_MARKER} in a consumer project.`
|
|
15
|
+
|
|
16
|
+
function format_member(root: string, member: NamespaceMember): string {
|
|
17
|
+
return `${path.relative(root, member.file)}:${String(member.line)} ${member.namespace}.${member.member}`
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function report(root: string, members: ReadonlyArray<NamespaceMember>): string {
|
|
21
|
+
if (members.length === 0) return `josh ${CHECK}: no unused namespace member`
|
|
22
|
+
|
|
23
|
+
return [
|
|
24
|
+
`josh ${CHECK}: ${String(members.length)} namespace member(s) nothing reads — remove each from its namespace object (and the declaration, if nothing in its file uses it either):`,
|
|
25
|
+
...members.map((member) => ` ${format_member(root, member)}`),
|
|
26
|
+
].join('\n')
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Loaded only past the consumer skip: the scanner pulls in `typescript`, an optional peer a
|
|
30
|
+
// basic-profile consumer may not have, and this check runs in every consumer's gate. For the same
|
|
31
|
+
// reason the scanner is left out of the published package (`package.json` `files`); only this check
|
|
32
|
+
// ships. `files` narrows the scan to the namespaces they declare or import directly; undefined scans
|
|
33
|
+
// the whole program.
|
|
34
|
+
async function find_members(
|
|
35
|
+
root: string,
|
|
36
|
+
files: ReadonlyArray<string> | undefined,
|
|
37
|
+
): Promise<ReadonlyArray<NamespaceMember>> {
|
|
38
|
+
const { unused_members } = await import('#tools/exports/unused-members')
|
|
39
|
+
if (files === undefined) return unused_members.find_unused_members(root)
|
|
40
|
+
|
|
41
|
+
return await unused_members.find_unused_members_in(root, files)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function run_unused_members(root: string, files?: ReadonlyArray<string>): Promise<number> {
|
|
45
|
+
if (doctor_consumer.is_kit_consumer(root)) {
|
|
46
|
+
console.info(CONSUMER_NOTICE)
|
|
47
|
+
|
|
48
|
+
return 0
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const members = await find_members(root, files)
|
|
52
|
+
const output = report(root, members)
|
|
53
|
+
|
|
54
|
+
if (members.length === 0) console.info(output)
|
|
55
|
+
else console.error(output)
|
|
56
|
+
|
|
57
|
+
return members.length === 0 ? 0 : FAIL_EXIT_CODE
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const unused_members_check = { run_unused_members, CONSUMER_NOTICE }
|
|
61
|
+
|
|
62
|
+
export { unused_members_check }
|
|
@@ -1,58 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env tsx
|
|
2
|
-
import path from 'node:path'
|
|
3
2
|
import { fileURLToPath } from 'node:url'
|
|
4
|
-
import { doctor_consumer } from '#scripts/doctor/doctor-consumer'
|
|
5
3
|
import { project_checks } from '#scripts/gate/project-checks'
|
|
6
|
-
import {
|
|
7
|
-
import type { NamespaceMember } from '#tools/exports/namespace-members'
|
|
4
|
+
import { unused_members_check } from './unused-members-check'
|
|
8
5
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
// A consumer's namespaces are read from `.svelte` files and routes a TypeScript program over its
|
|
12
|
-
// `tsconfig.json` does not see, so every member they use would read as unused. The check is kit's own.
|
|
13
|
-
//
|
|
14
|
-
// **Not a skip notice**. `SKIP_MARKER` means "a check passed without running",
|
|
15
|
-
// and the gate withholds its green record on it — so a consumer, where this notice prints on every
|
|
16
|
-
// run, never got a green record. Out of scope by design is not unverified, so the marker stays out.
|
|
17
|
-
const CONSUMER_NOTICE = `josh ${CHECK}: checks only the kit repository itself — ${NOTHING_TO_CHECK_MARKER} in a consumer project.`
|
|
18
|
-
|
|
19
|
-
function format_member(root: string, member: NamespaceMember): string {
|
|
20
|
-
return `${path.relative(root, member.file)}:${String(member.line)} ${member.namespace}.${member.member}`
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function report(root: string, members: ReadonlyArray<NamespaceMember>): string {
|
|
24
|
-
if (members.length === 0) return `josh ${CHECK}: no unused namespace member`
|
|
25
|
-
|
|
26
|
-
return [
|
|
27
|
-
`josh ${CHECK}: ${String(members.length)} namespace member(s) nothing reads — remove each from its namespace object (and the declaration, if nothing in its file uses it either):`,
|
|
28
|
-
...members.map((member) => ` ${format_member(root, member)}`),
|
|
29
|
-
].join('\n')
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
async function run_unused_members(root: string): Promise<number> {
|
|
33
|
-
if (doctor_consumer.is_kit_consumer(root)) {
|
|
34
|
-
console.info(CONSUMER_NOTICE)
|
|
35
|
-
|
|
36
|
-
return 0
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Loaded only past the skip: the scanner pulls in `typescript`, an optional peer a basic-profile
|
|
40
|
-
// consumer may not have, and this check runs in every consumer's gate. For the same reason the
|
|
41
|
-
// scanner is left out of the published package (`package.json` `files`); only this entry ships.
|
|
42
|
-
const { unused_members } = await import('#tools/exports/unused-members')
|
|
43
|
-
const members = unused_members.find_unused_members(root)
|
|
44
|
-
const output = report(root, members)
|
|
45
|
-
|
|
46
|
-
if (members.length === 0) console.info(output)
|
|
47
|
-
else console.error(output)
|
|
48
|
-
|
|
49
|
-
return members.length === 0 ? 0 : FAIL_EXIT_CODE
|
|
50
|
-
}
|
|
6
|
+
// The `josh exports:unused` entry point: the whole-program scan the gate runs. `josh lint:related`
|
|
7
|
+
// imports the check itself, narrowed to the changed files.
|
|
51
8
|
|
|
52
9
|
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
|
53
|
-
process.exitCode = await run_unused_members(
|
|
10
|
+
process.exitCode = await unused_members_check.run_unused_members(
|
|
11
|
+
project_checks.project_root(process.cwd()),
|
|
12
|
+
)
|
|
54
13
|
}
|
|
55
|
-
|
|
56
|
-
const unused_members_cli = { run_unused_members, CONSUMER_NOTICE }
|
|
57
|
-
|
|
58
|
-
export { unused_members_cli }
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { SnapshotObserver } from '#scripts/gh/git-pr-checks'
|
|
2
|
+
import { is_coderabbit_check } from '#scripts/gh/git-pr-checks-eval'
|
|
3
|
+
import { CHECK_STATUS_PENDING, type PrStateSnapshot } from '#scripts/gh/git-pr-checks-parse'
|
|
4
|
+
|
|
5
|
+
// Which check `followup`'s CI wait waited on last (joshuafolkken/kit#5295). The `ci-wait` row alone
|
|
6
|
+
// says how long the wait was, not which job held it, so the next job to shorten could not be chosen.
|
|
7
|
+
//
|
|
8
|
+
// **A check is timed when it is seen pending and then settled**: its time is the interval from the
|
|
9
|
+
// wait's first poll to the first poll that saw it settled. A check already settled at the first poll
|
|
10
|
+
// held nothing up and is not recorded. CodeRabbit is left out — its wait is `coderabbit-wait`'s
|
|
11
|
+
// (`followup-coderabbit-wait.ts`), so it is never counted twice. The clock is `performance.now()`'s
|
|
12
|
+
// for the reason `git-followup-stages.ts` states.
|
|
13
|
+
|
|
14
|
+
// Mutable for the reason `StageLog` is: the observer adds to it as the wait polls.
|
|
15
|
+
interface CiPath {
|
|
16
|
+
start_ms?: number
|
|
17
|
+
pending: Set<string>
|
|
18
|
+
check_ms: Record<string, number>
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// The `ci-wait` row's critical-path fields, both absent where no check was seen to settle.
|
|
22
|
+
interface CiPathRecord {
|
|
23
|
+
last_check?: string
|
|
24
|
+
check_ms?: Record<string, number>
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function new_path(): CiPath {
|
|
28
|
+
return { pending: new Set(), check_ms: {} }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function settle(path: CiPath, name: string, elapsed_ms: number): void {
|
|
32
|
+
if (path.pending.delete(name)) path.check_ms[name] = elapsed_ms
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function observe(path: CiPath, snapshot: PrStateSnapshot, now_ms: number): void {
|
|
36
|
+
path.start_ms ??= now_ms
|
|
37
|
+
const elapsed_ms = now_ms - path.start_ms
|
|
38
|
+
const checks = snapshot.rollup.filter((check) => !is_coderabbit_check(check.name))
|
|
39
|
+
|
|
40
|
+
for (const check of checks) {
|
|
41
|
+
if (check.status === CHECK_STATUS_PENDING) path.pending.add(check.name)
|
|
42
|
+
else settle(path, check.name, elapsed_ms)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// **Only the first check wait is timed**: the `ci-wait` row is that wait's lap, and the wait the merge
|
|
47
|
+
// goes back to when the head moved (#4036) times checks the row does not cover.
|
|
48
|
+
function observer_of(path: CiPath): SnapshotObserver {
|
|
49
|
+
const is_first_wait = path.start_ms === undefined
|
|
50
|
+
|
|
51
|
+
return async function time_checks(snapshot: PrStateSnapshot): Promise<void> {
|
|
52
|
+
if (is_first_wait) observe(path, snapshot, performance.now())
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function record_of(path: CiPath): CiPathRecord {
|
|
57
|
+
const [last] = Object.entries(path.check_ms).toSorted((left, right) => right[1] - left[1])
|
|
58
|
+
|
|
59
|
+
if (last === undefined) return {}
|
|
60
|
+
|
|
61
|
+
return { last_check: last[0], check_ms: { ...path.check_ms } }
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const followup_ci_path = { new_path, observe, observer_of, record_of }
|
|
65
|
+
|
|
66
|
+
export type { CiPath, CiPathRecord }
|
|
67
|
+
export { followup_ci_path }
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
// cspell:words coderabbit coderabbitai
|
|
2
|
+
import { is_coderabbit_author, is_coderabbit_rate_limit } from '#scripts/gh/git-ai-review-scan'
|
|
3
|
+
import { git_gh_command } from '#scripts/gh/git-gh-command'
|
|
4
|
+
import type { SnapshotObserver } from '#scripts/gh/git-pr-checks'
|
|
5
|
+
import { parse_pr_state_snapshot } from '#scripts/gh/git-pr-checks-parse'
|
|
6
|
+
import { ai_review_pull_comment_schema } from '#scripts/git/git-schemas'
|
|
7
|
+
import { parse_json_array_or_undefined } from '#scripts/git/parse-json-array'
|
|
8
|
+
import { lane_ledger_write } from '#scripts/lane/lane-ledger-write'
|
|
9
|
+
import { poll } from '#scripts/lib/poll'
|
|
10
|
+
import type { CodeRabbitState } from '#scripts/run/event/run-event-checks'
|
|
11
|
+
import { followup_checks_event } from './followup-checks-event'
|
|
12
|
+
import { followup_coderabbit_wait, type CodeRabbitWait } from './followup-coderabbit-wait'
|
|
13
|
+
|
|
14
|
+
// A rate-limited CodeRabbit, retriggered once by `followup` itself (joshuafolkken/kit#5289): read the
|
|
15
|
+
// window off CodeRabbit's own notice, wait it out, post `@coderabbitai review`, and wait for the check
|
|
16
|
+
// again. **Once per pull request** — a retrigger comment older than the latest notice means the one
|
|
17
|
+
// attempt was spent, and a second rate limit is the person's call (bypassing it is Tier C); one newer
|
|
18
|
+
// than it, whoever posted it, is a review still to come and is waited for, not posted again. The pull
|
|
19
|
+
// request, not the ledger, answers "already retriggered", so a re-run `followup` reads the same answer.
|
|
20
|
+
|
|
21
|
+
const RETRIGGER_BODY = '@coderabbitai review'
|
|
22
|
+
// `Please wait **12 minutes and 34 seconds** before requesting another review.` — the clause between
|
|
23
|
+
// `wait` and `before`, read as `<number> <unit>` token pairs.
|
|
24
|
+
const WAIT_OPENER = /please wait/iu
|
|
25
|
+
const WAIT_CLOSER = /before/iu
|
|
26
|
+
const TOKEN = /\d+|[a-z]+/giu
|
|
27
|
+
const DIGITS = /^\d+$/u
|
|
28
|
+
const SECOND_MS = 1000
|
|
29
|
+
const SECONDS_PER_MINUTE = 60
|
|
30
|
+
const MINUTES_PER_HOUR = 60
|
|
31
|
+
const MINUTE_MS = SECONDS_PER_MINUTE * SECOND_MS
|
|
32
|
+
const UNIT_MS: Readonly<Record<string, number>> = {
|
|
33
|
+
h: MINUTES_PER_HOUR * MINUTE_MS,
|
|
34
|
+
m: MINUTE_MS,
|
|
35
|
+
s: SECOND_MS,
|
|
36
|
+
}
|
|
37
|
+
// Past the window's end, so the retrigger does not land on its last second.
|
|
38
|
+
const MARGIN_SECONDS = 15
|
|
39
|
+
const MARGIN_MS = MARGIN_SECONDS * SECOND_MS
|
|
40
|
+
// The longest window `followup` waits out; a longer one is left to the person (`followup.md`).
|
|
41
|
+
const WINDOW_CAP_MINUTES = 30
|
|
42
|
+
const WINDOW_CAP_MS = WINDOW_CAP_MINUTES * MINUTE_MS
|
|
43
|
+
// The wait for the retriggered review: twenty minutes, polled every thirty seconds.
|
|
44
|
+
const REVIEW_WAIT_ATTEMPTS = 40
|
|
45
|
+
const REVIEW_WAIT_INTERVAL_SECONDS = 30
|
|
46
|
+
const REVIEW_WAIT_INTERVAL_MS = REVIEW_WAIT_INTERVAL_SECONDS * SECOND_MS
|
|
47
|
+
const NO_TIME = 0
|
|
48
|
+
const FIRST = 0
|
|
49
|
+
const NEXT = 1
|
|
50
|
+
const RATE_LIMITED: CodeRabbitState = 'rate-limited'
|
|
51
|
+
const TIER_C = 'bypassing it is Tier C — explicit user instruction only'
|
|
52
|
+
const BY_HAND = `wait it out, post \`${RETRIGGER_BODY}\` and rerun followup; ${TIER_C}`
|
|
53
|
+
const AGAIN_NOTE = `CodeRabbit rate-limited again after the one \`${RETRIGGER_BODY}\` (kit#5289): ${TIER_C}`
|
|
54
|
+
const UNREADABLE_NOTE = `CodeRabbit rate-limited with no window readable from its comments (kit#5289): no retrigger posted — ${BY_HAND}`
|
|
55
|
+
const UNFINISHED_NOTE = `CodeRabbit still reviewing after \`${RETRIGGER_BODY}\` (kit#5289): the merge goes ahead without it`
|
|
56
|
+
|
|
57
|
+
interface PullComment {
|
|
58
|
+
body?: string | undefined
|
|
59
|
+
author?: { login?: string | undefined } | undefined
|
|
60
|
+
updatedAt?: string | undefined
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
type Decision =
|
|
64
|
+
{ kind: 'retrigger'; wait_ms: number } | { kind: 'await' } | { kind: 'stop'; note: string }
|
|
65
|
+
|
|
66
|
+
interface Retrigger {
|
|
67
|
+
is_retriggered: boolean
|
|
68
|
+
notes: Array<string>
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
interface Settled<T> {
|
|
72
|
+
snapshot: T
|
|
73
|
+
is_retriggered: boolean
|
|
74
|
+
notes: Array<string>
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function wait_clause_of(body: string): string {
|
|
78
|
+
const after_opener = body.split(WAIT_OPENER)[NEXT] ?? ''
|
|
79
|
+
|
|
80
|
+
return after_opener.split(WAIT_CLOSER)[FIRST] ?? ''
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// The time one token stands for: a number times the unit the next token starts with.
|
|
84
|
+
function token_ms(tokens: ReadonlyArray<string>, index: number): number {
|
|
85
|
+
const token = tokens[index] ?? ''
|
|
86
|
+
if (!DIGITS.test(token)) return NO_TIME
|
|
87
|
+
const unit = (tokens[index + NEXT] ?? '').charAt(FIRST).toLowerCase()
|
|
88
|
+
|
|
89
|
+
return Number(token) * (UNIT_MS[unit] ?? NO_TIME)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// The wait CodeRabbit's notice states, or `undefined` for a comment that states none.
|
|
93
|
+
function parse_wait_ms(body: string): number | undefined {
|
|
94
|
+
if (!is_coderabbit_rate_limit(body)) return undefined
|
|
95
|
+
const tokens = wait_clause_of(body).match(TOKEN) ?? []
|
|
96
|
+
const wait_ms = tokens.reduce((sum, _token, index) => sum + token_ms(tokens, index), NO_TIME)
|
|
97
|
+
|
|
98
|
+
return wait_ms === NO_TIME ? undefined : wait_ms
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function is_notice(comment: PullComment): boolean {
|
|
102
|
+
return (
|
|
103
|
+
is_coderabbit_author(comment.author?.login ?? '') &&
|
|
104
|
+
is_coderabbit_rate_limit(comment.body ?? '')
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function is_retrigger(comment: PullComment): boolean {
|
|
109
|
+
return comment.body?.trim() === RETRIGGER_BODY
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function written_ms(comment: PullComment): number {
|
|
113
|
+
return Date.parse(comment.updatedAt ?? '')
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// The latest time among the comments `is_match` picks; one with no readable time counts as none.
|
|
117
|
+
function latest_ms(
|
|
118
|
+
comments: ReadonlyArray<PullComment>,
|
|
119
|
+
is_match: (comment: PullComment) => boolean,
|
|
120
|
+
): number | undefined {
|
|
121
|
+
const times = comments
|
|
122
|
+
.filter((comment) => is_match(comment))
|
|
123
|
+
.map((comment) => written_ms(comment))
|
|
124
|
+
.filter((ms) => !Number.isNaN(ms))
|
|
125
|
+
|
|
126
|
+
return times.length === 0 ? undefined : Math.max(...times)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// The latest end any CodeRabbit notice states — the window counts from when the notice was written.
|
|
130
|
+
function window_end_ms(comments: ReadonlyArray<PullComment>): number | undefined {
|
|
131
|
+
const ends = comments
|
|
132
|
+
.filter((comment) => is_notice(comment))
|
|
133
|
+
.map((comment) => written_ms(comment) + (parse_wait_ms(comment.body ?? '') ?? NaN))
|
|
134
|
+
.filter((ms) => !Number.isNaN(ms))
|
|
135
|
+
|
|
136
|
+
return ends.length === 0 ? undefined : Math.max(...ends)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// A retrigger written after the latest notice is still to be answered; one before it was answered
|
|
140
|
+
// with another rate limit. Either time unreadable reads as the second.
|
|
141
|
+
function decide_after_retrigger(comments: ReadonlyArray<PullComment>): Decision {
|
|
142
|
+
const retrigger_ms = latest_ms(comments, is_retrigger) ?? NO_TIME
|
|
143
|
+
const notice_ms = latest_ms(comments, is_notice) ?? retrigger_ms
|
|
144
|
+
|
|
145
|
+
return retrigger_ms > notice_ms ? { kind: 'await' } : { kind: 'stop', note: AGAIN_NOTE }
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function too_long_note(wait_ms: number): string {
|
|
149
|
+
const minutes = String(Math.ceil(wait_ms / MINUTE_MS))
|
|
150
|
+
|
|
151
|
+
return `CodeRabbit rate-limited for ${minutes} more minutes, over followup's ${String(WINDOW_CAP_MINUTES)} minute wait (kit#5289): no retrigger posted — ${BY_HAND}`
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function decide(comments: ReadonlyArray<PullComment>, now_ms: number): Decision {
|
|
155
|
+
if (comments.some((comment) => is_retrigger(comment))) return decide_after_retrigger(comments)
|
|
156
|
+
const end_ms = window_end_ms(comments)
|
|
157
|
+
if (end_ms === undefined) return { kind: 'stop', note: UNREADABLE_NOTE }
|
|
158
|
+
const wait_ms = Math.max(NO_TIME, end_ms - now_ms) + MARGIN_MS
|
|
159
|
+
|
|
160
|
+
return wait_ms > WINDOW_CAP_MS
|
|
161
|
+
? { kind: 'stop', note: too_long_note(wait_ms) }
|
|
162
|
+
: { kind: 'retrigger', wait_ms }
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async function read_comments(branch_name: string): Promise<Array<PullComment>> {
|
|
166
|
+
const raw = await git_gh_command.pr_get_comments(branch_name)
|
|
167
|
+
|
|
168
|
+
return parse_json_array_or_undefined(raw ?? '', ai_review_pull_comment_schema) ?? []
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async function read_state(
|
|
172
|
+
branch_name: string,
|
|
173
|
+
observe: SnapshotObserver,
|
|
174
|
+
): Promise<CodeRabbitState> {
|
|
175
|
+
const checks = await git_gh_command.pr_get_checks_snapshot(branch_name)
|
|
176
|
+
const snapshot = parse_pr_state_snapshot(checks.snapshot_json)
|
|
177
|
+
|
|
178
|
+
await observe(snapshot)
|
|
179
|
+
|
|
180
|
+
return followup_checks_event.coderabbit_of(snapshot)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// **A rate limit read before the review started is the old one**, so only one read after another
|
|
184
|
+
// state is the second rate limit; a check that never moves off it is read as one at the budget's end.
|
|
185
|
+
// One observer for the whole wait, so its polls are timed against one another.
|
|
186
|
+
async function wait_for_review(branch_name: string, wait: CodeRabbitWait): Promise<Array<string>> {
|
|
187
|
+
const observe = followup_coderabbit_wait.observer_of(wait)
|
|
188
|
+
let is_started = false
|
|
189
|
+
let state: CodeRabbitState = RATE_LIMITED
|
|
190
|
+
const is_settled = await poll.poll_until(
|
|
191
|
+
async () => {
|
|
192
|
+
state = await read_state(branch_name, observe)
|
|
193
|
+
is_started ||= state !== RATE_LIMITED
|
|
194
|
+
|
|
195
|
+
return is_started && state !== 'running'
|
|
196
|
+
},
|
|
197
|
+
{ attempts: REVIEW_WAIT_ATTEMPTS, interval_ms: REVIEW_WAIT_INTERVAL_MS, sleeper: poll.sleep },
|
|
198
|
+
)
|
|
199
|
+
if (state === RATE_LIMITED) return [AGAIN_NOTE]
|
|
200
|
+
|
|
201
|
+
return is_settled ? [] : [UNFINISHED_NOTE]
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async function retrigger(
|
|
205
|
+
branch_name: string,
|
|
206
|
+
wait: CodeRabbitWait,
|
|
207
|
+
wait_ms: number,
|
|
208
|
+
): Promise<Retrigger> {
|
|
209
|
+
const seconds = String(Math.ceil(wait_ms / SECOND_MS))
|
|
210
|
+
|
|
211
|
+
console.info(`⏳ CodeRabbit rate-limited — waiting ${seconds}s, then \`${RETRIGGER_BODY}\``)
|
|
212
|
+
await poll.sleep(wait_ms)
|
|
213
|
+
await git_gh_command.pr_comment(branch_name, RETRIGGER_BODY)
|
|
214
|
+
await lane_ledger_write.record_stage({
|
|
215
|
+
stage: lane_ledger_write.CODERABBIT_RETRIGGER_STAGE,
|
|
216
|
+
elapsed_ms: wait_ms,
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
return { is_retriggered: true, notes: await wait_for_review(branch_name, wait) }
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Runs only when the check wait last saw CodeRabbit rate-limited; anything else is untouched.
|
|
223
|
+
async function run(branch_name: string, wait: CodeRabbitWait): Promise<Retrigger> {
|
|
224
|
+
if (wait.last?.state !== RATE_LIMITED) return { is_retriggered: false, notes: [] }
|
|
225
|
+
const decision = decide(await read_comments(branch_name), Date.now())
|
|
226
|
+
if (decision.kind === 'stop') return { is_retriggered: false, notes: [decision.note] }
|
|
227
|
+
|
|
228
|
+
if (decision.kind === 'await') {
|
|
229
|
+
return { is_retriggered: true, notes: await wait_for_review(branch_name, wait) }
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return await retrigger(branch_name, wait, decision.wait_ms)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// The checks after a retriggered review are read again, so the merge and the skip notes read the
|
|
236
|
+
// snapshot that review left, not the rate-limited one.
|
|
237
|
+
async function settle<T>(
|
|
238
|
+
snapshot: T,
|
|
239
|
+
wait_for_green: () => Promise<T>,
|
|
240
|
+
branch_name: string,
|
|
241
|
+
wait: CodeRabbitWait,
|
|
242
|
+
): Promise<Settled<T>> {
|
|
243
|
+
const { is_retriggered, notes } = await run(branch_name, wait)
|
|
244
|
+
if (!is_retriggered) return { snapshot, is_retriggered, notes }
|
|
245
|
+
|
|
246
|
+
return { snapshot: await wait_for_green(), is_retriggered, notes }
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const followup_coderabbit_retrigger = {
|
|
250
|
+
AGAIN_NOTE,
|
|
251
|
+
RETRIGGER_BODY,
|
|
252
|
+
UNFINISHED_NOTE,
|
|
253
|
+
UNREADABLE_NOTE,
|
|
254
|
+
decide,
|
|
255
|
+
parse_wait_ms,
|
|
256
|
+
run,
|
|
257
|
+
settle,
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export type { PullComment, Retrigger, Settled }
|
|
261
|
+
export { followup_coderabbit_retrigger }
|