@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,6 +1,3 @@
|
|
|
1
|
-
import { read_pull } from '#scripts/gh/git-gh-pr-read'
|
|
2
|
-
import { git_closes_keyword } from '#scripts/git/git-closes-keyword'
|
|
3
|
-
import { lane_ledger } from '#scripts/lane/lane-ledger'
|
|
4
1
|
import { issue_cite } from './issue-cite'
|
|
5
2
|
import { markdown_section } from './markdown-section'
|
|
6
3
|
|
|
@@ -14,23 +11,40 @@ import { markdown_section } from './markdown-section'
|
|
|
14
11
|
// the wait needs — when the pull request merged — is read ahead by `prime`, once per pull request per
|
|
15
12
|
// process, wherever bodies first arrive. A body nobody primed reads as waiting: offering it early is
|
|
16
13
|
// the defect this guards, and the next primed read releases it.
|
|
14
|
+
//
|
|
15
|
+
// joshuafolkken/kit#5220: the reads `prime` makes — the pull request and the lane ledger — live in
|
|
16
|
+
// `issue-sample-prime.ts`, which hands this module the ledger's merges. The readers that only judge a
|
|
17
|
+
// body import this module alone, so a change to the ledger's reading never reaches their suites.
|
|
18
|
+
//
|
|
19
|
+
// joshuafolkken/kit#5051: a lane files its measurement follow-up before its own pull request exists —
|
|
20
|
+
// `josh ship` wants the deferral row first. So the condition may cite the issue instead (`CLOSING_FORMAT`),
|
|
21
|
+
// and `prime` resolves the merged pull request that closes it; until one exists the body waits as
|
|
22
|
+
// unmerged.
|
|
17
23
|
|
|
18
24
|
const BACKGROUND_HEADING = '## 背景'
|
|
19
25
|
const PREFIX = '- 実施可能条件:'
|
|
20
|
-
const CONDITION_PATTERN =
|
|
26
|
+
const CONDITION_PATTERN =
|
|
27
|
+
/^#(?<cited>[1-9]\d*) (?<closing>を閉じる PR )?のマージ後 (?<count>[1-9]\d*) マージ$/u
|
|
21
28
|
const VALUE_FORMAT = '#<PR> のマージ後 <K> マージ'
|
|
29
|
+
const CLOSING_FORMAT = '#<issue> を閉じる PR のマージ後 <K> マージ'
|
|
22
30
|
const DECLARATION = `${PREFIX} ${VALUE_FORMAT}`
|
|
23
|
-
|
|
31
|
+
// The refusal ends in a line ready to paste (joshuafolkken/kit#5225).
|
|
32
|
+
const EXAMPLE = `${PREFIX} #5198 のマージ後 30 マージ`
|
|
33
|
+
const MALFORMED = `\`${PREFIX}\` must read \`${VALUE_FORMAT}\` or \`${CLOSING_FORMAT}\` with K at least 1\n${EXAMPLE}`
|
|
34
|
+
|
|
35
|
+
// `pull` cites the pull request itself, `issue` the issue whose closing pull request it waits on.
|
|
36
|
+
type Via = 'pull' | 'issue'
|
|
24
37
|
|
|
25
38
|
interface Condition {
|
|
26
|
-
|
|
39
|
+
cited: number
|
|
40
|
+
via: Via
|
|
27
41
|
count: number
|
|
28
42
|
}
|
|
29
43
|
|
|
30
44
|
type SampleWait =
|
|
31
|
-
| { kind: 'unread';
|
|
32
|
-
| { kind: 'unmerged';
|
|
33
|
-
| { kind: 'short';
|
|
45
|
+
| { kind: 'unread'; cited: number; via: Via }
|
|
46
|
+
| { kind: 'unmerged'; cited: number; via: Via }
|
|
47
|
+
| { kind: 'short'; cited: number; via: Via; counted: number; needed: number }
|
|
34
48
|
|
|
35
49
|
// One pull request as read: `merged_at` absent is one found unmerged, read again as it may merge since.
|
|
36
50
|
// `closes` is the issue its body closes, whose ledger merge is the pull request's own.
|
|
@@ -39,19 +53,26 @@ interface PullRead {
|
|
|
39
53
|
closes: number | undefined
|
|
40
54
|
}
|
|
41
55
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
56
|
+
// One merge the lane ledger recorded, keyed by the issue its pull request closed.
|
|
57
|
+
interface MergeSample {
|
|
58
|
+
at: string
|
|
59
|
+
issue: number
|
|
45
60
|
}
|
|
46
61
|
|
|
62
|
+
// The ledger's merges as they read now; none until a prime has handed them over.
|
|
47
63
|
interface LedgerState {
|
|
48
|
-
|
|
64
|
+
merges: () => ReadonlyArray<MergeSample>
|
|
49
65
|
}
|
|
50
66
|
|
|
51
|
-
// A
|
|
67
|
+
// A cited number with no entry was never read. Keyed by `key_of`, as one number may be cited both ways.
|
|
68
|
+
|
|
69
|
+
const pull_by_key = new Map<string, PullRead>()
|
|
70
|
+
|
|
71
|
+
function no_merges(): ReadonlyArray<MergeSample> {
|
|
72
|
+
return []
|
|
73
|
+
}
|
|
52
74
|
|
|
53
|
-
const
|
|
54
|
-
const ledger: LedgerState = { path: undefined }
|
|
75
|
+
const ledger: LedgerState = { merges: no_merges }
|
|
55
76
|
|
|
56
77
|
function declared_value(body: string): string | undefined {
|
|
57
78
|
const background = markdown_section.section_lines(body, BACKGROUND_HEADING).join('\n')
|
|
@@ -63,6 +84,10 @@ function declared_value(body: string): string | undefined {
|
|
|
63
84
|
return line?.slice(PREFIX.length).trim()
|
|
64
85
|
}
|
|
65
86
|
|
|
87
|
+
function via_of(groups: Partial<Record<string, string>>): Via {
|
|
88
|
+
return groups['closing'] === undefined ? 'pull' : 'issue'
|
|
89
|
+
}
|
|
90
|
+
|
|
66
91
|
// The declared condition, or `undefined` when there is none or it does not parse — a malformed one is
|
|
67
92
|
// refused by `issue:lint`, and holding a hand-edited one forever would lose the issue silently.
|
|
68
93
|
function condition_of(body = ''): Condition | undefined {
|
|
@@ -70,12 +95,23 @@ function condition_of(body = ''): Condition | undefined {
|
|
|
70
95
|
|
|
71
96
|
if (groups === undefined) return undefined
|
|
72
97
|
|
|
73
|
-
return {
|
|
98
|
+
return { cited: Number(groups['cited']), via: via_of(groups), count: Number(groups['count']) }
|
|
74
99
|
}
|
|
75
100
|
|
|
76
101
|
// The number the declared condition cites, or `undefined` when there is none or it does not parse.
|
|
77
102
|
function cited_number(body: string): number | undefined {
|
|
78
|
-
return condition_of(body)?.
|
|
103
|
+
return condition_of(body)?.cited
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// The number cited by the given form only — the issue form cites an issue by design.
|
|
107
|
+
function cited_via(body: string, via: Via): number | undefined {
|
|
108
|
+
const condition = condition_of(body)
|
|
109
|
+
|
|
110
|
+
return condition?.via === via ? condition.cited : undefined
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function key_of({ cited, via }: Pick<Condition, 'cited' | 'via'>): string {
|
|
114
|
+
return `${via}:${String(cited)}`
|
|
79
115
|
}
|
|
80
116
|
|
|
81
117
|
function problems(body: string): ReadonlyArray<string> {
|
|
@@ -84,63 +120,38 @@ function problems(body: string): ReadonlyArray<string> {
|
|
|
84
120
|
return value === undefined || CONDITION_PATTERN.test(value) ? [] : [MALFORMED]
|
|
85
121
|
}
|
|
86
122
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const
|
|
123
|
+
// Keeps what a prime read for the condition; `undefined` — a failed read — leaves it unread.
|
|
124
|
+
function record(condition: Condition, pull: PullRead | undefined): void {
|
|
125
|
+
const key = key_of(condition)
|
|
90
126
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
closes: closes === undefined ? undefined : Number(closes),
|
|
94
|
-
}
|
|
127
|
+
if (pull === undefined) pull_by_key.delete(key)
|
|
128
|
+
else pull_by_key.set(key, pull)
|
|
95
129
|
}
|
|
96
130
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
// A failed read stays unread, so the next prime asks again.
|
|
100
|
-
async function remember(pr: number, ports: PrimePorts): Promise<void> {
|
|
101
|
-
try {
|
|
102
|
-
pull_by_number.set(pr, await ports.pull(pr))
|
|
103
|
-
} catch {
|
|
104
|
-
pull_by_number.delete(pr)
|
|
105
|
-
}
|
|
131
|
+
function use_merges(merges: () => ReadonlyArray<MergeSample>): void {
|
|
132
|
+
ledger.merges = merges
|
|
106
133
|
}
|
|
107
134
|
|
|
108
|
-
function is_merge_known(
|
|
109
|
-
return
|
|
135
|
+
function is_merge_known(condition: Condition): boolean {
|
|
136
|
+
return pull_by_key.get(key_of(condition))?.merged_at !== undefined
|
|
110
137
|
}
|
|
111
138
|
|
|
112
|
-
//
|
|
113
|
-
|
|
114
|
-
bodies: ReadonlyArray<string | undefined>,
|
|
115
|
-
ports: PrimePorts = DEFAULT_PORTS,
|
|
116
|
-
): Promise<void> {
|
|
139
|
+
// The conditions the bodies declare whose pull request has not been read merged, one per key.
|
|
140
|
+
function unread_of(bodies: ReadonlyArray<string | undefined>): Array<Condition> {
|
|
117
141
|
const unread = bodies
|
|
118
|
-
.map((body) => condition_of(body)
|
|
119
|
-
.filter(
|
|
120
|
-
|
|
121
|
-
|
|
142
|
+
.map((body) => condition_of(body))
|
|
143
|
+
.filter(
|
|
144
|
+
(condition): condition is Condition => condition !== undefined && !is_merge_known(condition),
|
|
145
|
+
)
|
|
122
146
|
|
|
123
|
-
|
|
124
|
-
await Promise.all(
|
|
125
|
-
[...new Set(unread)].map(async (pr) => {
|
|
126
|
-
await remember(pr, ports)
|
|
127
|
-
}),
|
|
128
|
-
)
|
|
147
|
+
return [...new Map(unread.map((condition) => [key_of(condition), condition])).values()]
|
|
129
148
|
}
|
|
130
149
|
|
|
131
150
|
function merges_after({ merged_at, closes }: PullRead & { merged_at: string }): number {
|
|
132
|
-
if (ledger.path === undefined) return 0
|
|
133
|
-
|
|
134
151
|
const since = Date.parse(merged_at)
|
|
135
152
|
|
|
136
|
-
return
|
|
137
|
-
.
|
|
138
|
-
.filter(
|
|
139
|
-
(entry) =>
|
|
140
|
-
entry.kind === lane_ledger.KIND.MERGE &&
|
|
141
|
-
entry.issue !== closes &&
|
|
142
|
-
Date.parse(entry.at) > since,
|
|
143
|
-
).length
|
|
153
|
+
return ledger.merges().filter((merge) => merge.issue !== closes && Date.parse(merge.at) > since)
|
|
154
|
+
.length
|
|
144
155
|
}
|
|
145
156
|
|
|
146
157
|
// What the body still waits on, or `undefined` when it declares nothing or has its samples.
|
|
@@ -149,44 +160,54 @@ function wait_of(body?: string): SampleWait | undefined {
|
|
|
149
160
|
|
|
150
161
|
if (condition === undefined) return undefined
|
|
151
162
|
|
|
152
|
-
const {
|
|
153
|
-
const pull =
|
|
163
|
+
const { cited, via, count } = condition
|
|
164
|
+
const pull = pull_by_key.get(key_of(condition))
|
|
154
165
|
|
|
155
|
-
if (pull === undefined) return { kind: 'unread',
|
|
166
|
+
if (pull === undefined) return { kind: 'unread', cited, via }
|
|
156
167
|
|
|
157
168
|
const { merged_at, closes } = pull
|
|
158
169
|
|
|
159
|
-
if (merged_at === undefined) return { kind: 'unmerged',
|
|
170
|
+
if (merged_at === undefined) return { kind: 'unmerged', cited, via }
|
|
160
171
|
|
|
161
172
|
const counted = merges_after({ merged_at, closes })
|
|
162
173
|
|
|
163
|
-
return counted >= count ? undefined : { kind: 'short',
|
|
174
|
+
return counted >= count ? undefined : { kind: 'short', cited, via, counted, needed: count }
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function subject_of({ cited, via }: SampleWait): string {
|
|
178
|
+
const plain = issue_cite.plain(cited)
|
|
179
|
+
|
|
180
|
+
return via === 'pull' ? plain : `the pull request closing ${plain}`
|
|
164
181
|
}
|
|
165
182
|
|
|
166
183
|
// Why the body waits, for a reader that cites the issue itself.
|
|
167
184
|
function reason_of(wait: SampleWait): string {
|
|
168
|
-
const
|
|
185
|
+
const subject = subject_of(wait)
|
|
169
186
|
|
|
170
|
-
if (wait.kind === 'unread') return `until the merge of ${
|
|
171
|
-
if (wait.kind === 'unmerged') return `until ${
|
|
187
|
+
if (wait.kind === 'unread') return `until the merge of ${subject} is read`
|
|
188
|
+
if (wait.kind === 'unmerged') return `until ${subject} merges`
|
|
172
189
|
|
|
173
|
-
return `${String(wait.counted)}/${String(wait.needed)} merges after ${
|
|
190
|
+
return `${String(wait.counted)}/${String(wait.needed)} merges after ${subject}`
|
|
174
191
|
}
|
|
175
192
|
|
|
176
193
|
function reset(): void {
|
|
177
|
-
|
|
178
|
-
ledger.
|
|
194
|
+
pull_by_key.clear()
|
|
195
|
+
ledger.merges = no_merges
|
|
179
196
|
}
|
|
180
197
|
|
|
181
198
|
const issue_sample_gate = {
|
|
182
199
|
DECLARATION,
|
|
200
|
+
CLOSING_FORMAT,
|
|
183
201
|
cited_number,
|
|
184
|
-
|
|
202
|
+
cited_via,
|
|
185
203
|
problems,
|
|
186
204
|
reason_of,
|
|
205
|
+
record,
|
|
187
206
|
reset,
|
|
207
|
+
unread_of,
|
|
208
|
+
use_merges,
|
|
188
209
|
wait_of,
|
|
189
210
|
}
|
|
190
211
|
|
|
191
|
-
export type {
|
|
212
|
+
export type { Condition, MergeSample, PullRead, SampleWait }
|
|
192
213
|
export { issue_sample_gate }
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { git_gh_api_path } from '#scripts/gh/git-gh-api-path'
|
|
2
|
+
import { git_gh_exec } from '#scripts/gh/git-gh-exec'
|
|
3
|
+
import { git_gh_issue_rest } from '#scripts/gh/git-gh-issue-rest'
|
|
4
|
+
import { read_pull } from '#scripts/gh/git-gh-pr-read'
|
|
5
|
+
import { git_gh_pr_too_large } from '#scripts/gh/git-gh-pr-too-large'
|
|
6
|
+
import { git_closes_keyword } from '#scripts/git/git-closes-keyword'
|
|
7
|
+
import { lane_ledger, type MergeEntry } from '#scripts/lane/lane-ledger'
|
|
8
|
+
import { issue_closing_pr } from './issue-closing-pr'
|
|
9
|
+
import {
|
|
10
|
+
issue_sample_gate,
|
|
11
|
+
type Condition,
|
|
12
|
+
type MergeSample,
|
|
13
|
+
type PullRead,
|
|
14
|
+
} from './issue-sample-gate'
|
|
15
|
+
|
|
16
|
+
// The reads `issue_sample_gate` waits on, made ahead where bodies first arrive (joshuafolkken/kit#4414):
|
|
17
|
+
// when the cited pull request merged, and the merges the lane ledger recorded. Kept apart from the
|
|
18
|
+
// gate so that only the primers reach the ledger's reader (joshuafolkken/kit#5220).
|
|
19
|
+
|
|
20
|
+
// The two fields `read_source` takes from a pull request, whichever endpoint served them.
|
|
21
|
+
interface PullFields {
|
|
22
|
+
body?: string | null | undefined
|
|
23
|
+
merged_at?: string | null | undefined
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// `closing` reads the pull request that closes an issue; one not merged yet reads as unmerged.
|
|
27
|
+
interface PrimePorts {
|
|
28
|
+
pull: (pr: number) => Promise<PullRead>
|
|
29
|
+
closing: (issue: number) => Promise<PullRead>
|
|
30
|
+
ledger_path: () => Promise<string | undefined>
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// joshuafolkken/kit#5241: GitHub refuses the single pull request read of a large one with 422 `too many
|
|
34
|
+
// files changed`, and a closing number carries no branch to read the listing row by. The issue
|
|
35
|
+
// endpoint serves the same pull request's body and merge time.
|
|
36
|
+
async function read_as_issue(pr: number): Promise<PullFields> {
|
|
37
|
+
const json = await git_gh_exec.exec_gh_api({ path: git_gh_api_path.issue_api_path(String(pr)) })
|
|
38
|
+
const issue = git_gh_issue_rest.parse_rest_issue(json)
|
|
39
|
+
|
|
40
|
+
return { body: issue.body, merged_at: issue.pull_request?.merged_at }
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function read_fields(pr: number): Promise<PullFields> {
|
|
44
|
+
try {
|
|
45
|
+
return await read_pull(pr)
|
|
46
|
+
} catch (error) {
|
|
47
|
+
if (!git_gh_pr_too_large.is_too_many_files(error)) throw error
|
|
48
|
+
|
|
49
|
+
return await read_as_issue(pr)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function read_source(pr: number): Promise<PullRead> {
|
|
54
|
+
const pull = await read_fields(pr)
|
|
55
|
+
const closes = git_closes_keyword.parse_closes_issue_number(pull.body ?? undefined)
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
merged_at: pull.merged_at ?? undefined,
|
|
59
|
+
closes: closes === undefined ? undefined : Number(closes),
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// The merged pull request closing the issue; `closes` is the issue itself, whichever pull request it is.
|
|
64
|
+
async function read_closing_source(issue: number): Promise<PullRead> {
|
|
65
|
+
const pr = await issue_closing_pr.read_closing_number(issue)
|
|
66
|
+
|
|
67
|
+
if (pr === undefined) return { merged_at: undefined, closes: issue }
|
|
68
|
+
|
|
69
|
+
const { merged_at } = await read_source(pr)
|
|
70
|
+
|
|
71
|
+
return { merged_at, closes: issue }
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const DEFAULT_PORTS: PrimePorts = {
|
|
75
|
+
pull: read_source,
|
|
76
|
+
closing: read_closing_source,
|
|
77
|
+
ledger_path: lane_ledger.target,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// The ledger's merges, read on each judgement so a merge recorded since the prime counts; an absent
|
|
81
|
+
// ledger records none.
|
|
82
|
+
function merges_of(path: string | undefined): () => ReadonlyArray<MergeSample> {
|
|
83
|
+
return function merges(): ReadonlyArray<MergeSample> {
|
|
84
|
+
if (path === undefined) return []
|
|
85
|
+
|
|
86
|
+
return lane_ledger
|
|
87
|
+
.read_entries(path)
|
|
88
|
+
.filter((entry): entry is MergeEntry => entry.kind === lane_ledger.KIND.MERGE)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// A failed read stays unread, so the next prime asks again.
|
|
93
|
+
async function remember(condition: Condition, ports: PrimePorts): Promise<void> {
|
|
94
|
+
const read = condition.via === 'pull' ? ports.pull : ports.closing
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
issue_sample_gate.record(condition, await read(condition.cited))
|
|
98
|
+
} catch {
|
|
99
|
+
issue_sample_gate.record(condition, undefined)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Reads ahead what the bodies' conditions need. Nothing is read for bodies that declare none.
|
|
104
|
+
async function prime(
|
|
105
|
+
bodies: ReadonlyArray<string | undefined>,
|
|
106
|
+
ports: PrimePorts = DEFAULT_PORTS,
|
|
107
|
+
): Promise<void> {
|
|
108
|
+
const unread = issue_sample_gate.unread_of(bodies)
|
|
109
|
+
|
|
110
|
+
if (unread.length === 0) return
|
|
111
|
+
|
|
112
|
+
issue_sample_gate.use_merges(merges_of(await ports.ledger_path()))
|
|
113
|
+
await Promise.all(
|
|
114
|
+
unread.map(async (condition) => {
|
|
115
|
+
await remember(condition, ports)
|
|
116
|
+
}),
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const issue_sample_prime = {
|
|
121
|
+
prime,
|
|
122
|
+
read_closing: read_closing_source,
|
|
123
|
+
read_source,
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export type { PrimePorts }
|
|
127
|
+
export { issue_sample_prime }
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { acceptance_map } from '#scripts/review/acceptance-map'
|
|
2
|
+
import { issue_sample_gate } from './issue-sample-gate'
|
|
3
|
+
import { measure_declaration } from './measure-declaration'
|
|
4
|
+
import { size_estimate } from './size-estimate'
|
|
5
|
+
|
|
6
|
+
// joshuafolkken/kit#4901: a follow-up that measures a pull request's effect reads records that only
|
|
7
|
+
// the merges after it write. Filed without its start condition, the backlog offers it at once and the
|
|
8
|
+
// lane finds no sample (#4897). It is refused until it declares the condition (`measurement.md`).
|
|
9
|
+
//
|
|
10
|
+
// A measurement follow-up is a body carrying a measure declaration, or one changing no file whose criterion
|
|
11
|
+
// reads the period after a cited change: its wording says "after #N" whichever record it reads
|
|
12
|
+
// (#5103), or it names a reader of the post-merge records. A record read that cites nothing (a CI
|
|
13
|
+
// investigation) waits on no merge, so it files as before. A bare "after" character ends many words
|
|
14
|
+
// that are no period ("last", "around", "from now on"), so it counts only right after the citation,
|
|
15
|
+
// a possessive particle or "merge"; one opening a word ("see below", "cleanup", "successor") is no
|
|
16
|
+
// period either.
|
|
17
|
+
|
|
18
|
+
const AFTER_CITED_CHANGE: ReadonlyArray<RegExp> = [
|
|
19
|
+
/#[1-9]\d*(?:\s*|[^#\n]{0,16}?(?:の|マージ(?:した|直)?))後(?![述始片続])/u,
|
|
20
|
+
/#[1-9]\d*[^#\n]{0,16}?(?:以降|以後)/u,
|
|
21
|
+
]
|
|
22
|
+
const RECORD_READERS: ReadonlyArray<string> = ['lane:stats', 'actions/runs', 'ship --log']
|
|
23
|
+
const CITATION_PATTERN = /#[1-9]\d*/u
|
|
24
|
+
const MISSING = `measurement follow-up without its start condition: declare \`${issue_sample_gate.DECLARATION}\`, or \`${issue_sample_gate.CLOSING_FORMAT}\` before that pull request exists, under ## 背景 — prompts/collaboration-workflow/measurement.md → "効果を測る後続 Issue"`
|
|
25
|
+
// joshuafolkken/kit#5144: one waiting K merges reads one value against a bound, which `backlog:drive`
|
|
26
|
+
// does without a lane once it is declared; the declaration is the default, a stated reason the exception.
|
|
27
|
+
const UNDECLARED = `measurement follow-up without a measure declaration: declare \`${measure_declaration.DECLARATION}\` (any \`lane:stats\` cell: \`pnpm josh lane:value cell\`), or \`${measure_declaration.ABSENT}\` when no one command prints the value, under ## 背景 — prompts/collaboration-workflow/measurement.md → "効果を測る後続 Issue"\n${measure_declaration.EXAMPLE}`
|
|
28
|
+
|
|
29
|
+
function measures_a_change(criterion: string): boolean {
|
|
30
|
+
if (AFTER_CITED_CHANGE.some((pattern) => pattern.test(criterion))) return true
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
CITATION_PATTERN.test(criterion) && RECORD_READERS.some((reader) => criterion.includes(reader))
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function is_measurement(body: string): boolean {
|
|
38
|
+
if (measure_declaration.parse(body) !== undefined) return true
|
|
39
|
+
if (size_estimate.declared_files(body) !== 0) return false
|
|
40
|
+
|
|
41
|
+
return acceptance_map.criteria_of(body).some((criterion) => measures_a_change(criterion.text))
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// The refusal for a measurement follow-up whose start condition does not parse — missing, or
|
|
45
|
+
// malformed beside `issue_sample_gate.problems`' format refusal — or whose condition parses with no
|
|
46
|
+
// measure declaration nor a reason for none; `undefined` for any other filing.
|
|
47
|
+
function problem(body: string): string | undefined {
|
|
48
|
+
if (issue_sample_gate.cited_number(body) !== undefined) {
|
|
49
|
+
return measure_declaration.is_stated(body) ? undefined : UNDECLARED
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return is_measurement(body) ? MISSING : undefined
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const issue_sample_required = { problem }
|
|
56
|
+
|
|
57
|
+
export { issue_sample_required }
|
|
@@ -15,7 +15,7 @@ import { session_cite } from './session-cite'
|
|
|
15
15
|
|
|
16
16
|
interface SourcePorts {
|
|
17
17
|
is_pull: (number: number, repo: string | undefined) => Promise<boolean | undefined>
|
|
18
|
-
closing_pr: (issue: number) => Promise<
|
|
18
|
+
closing_pr: (issue: number) => Promise<number | undefined>
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
async function read_is_pull(
|
|
@@ -33,15 +33,14 @@ async function read_is_pull(
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const url = await issue_closing_pr.read_closing_pr(String(issue))
|
|
39
|
-
|
|
40
|
-
return url?.slice(url.lastIndexOf('/') + 1)
|
|
36
|
+
async function read_closing_number(issue: number): Promise<number | undefined> {
|
|
37
|
+
return await issue_closing_pr.read_closing_number(issue)
|
|
41
38
|
}
|
|
42
39
|
|
|
43
|
-
const DEFAULT_PORTS: SourcePorts = { is_pull: read_is_pull, closing_pr:
|
|
40
|
+
const DEFAULT_PORTS: SourcePorts = { is_pull: read_is_pull, closing_pr: read_closing_number }
|
|
44
41
|
|
|
42
|
+
// No merged closing pull request yet — the lane filing ahead of its own (joshuafolkken/kit#5051) —
|
|
43
|
+
// points at the form that waits on the pull request to come.
|
|
45
44
|
async function hint_of(
|
|
46
45
|
issue: number,
|
|
47
46
|
repo: string | undefined,
|
|
@@ -49,19 +48,21 @@ async function hint_of(
|
|
|
49
48
|
): Promise<string> {
|
|
50
49
|
const closing = repo === undefined ? await ports.closing_pr(issue) : undefined
|
|
51
50
|
|
|
52
|
-
if (closing === undefined)
|
|
51
|
+
if (closing === undefined) {
|
|
52
|
+
return `cite the pull request whose merge it waits on, or write \`${issue_sample_gate.CLOSING_FORMAT}\` to wait on the one that closes it`
|
|
53
|
+
}
|
|
53
54
|
|
|
54
55
|
return `cite the pull request that closed it: ${session_cite.issue(closing)}`
|
|
55
56
|
}
|
|
56
57
|
|
|
57
|
-
// The refusal for a condition citing an issue, or `undefined` when it cites a pull
|
|
58
|
-
// nothing, or cannot be read.
|
|
58
|
+
// The refusal for a pull request condition citing an issue, or `undefined` when it cites a pull
|
|
59
|
+
// request, cites nothing, uses the issue form, or cannot be read.
|
|
59
60
|
async function problem(
|
|
60
61
|
body: string,
|
|
61
62
|
repo?: string,
|
|
62
63
|
ports: SourcePorts = DEFAULT_PORTS,
|
|
63
64
|
): Promise<string | undefined> {
|
|
64
|
-
const number = issue_sample_gate.
|
|
65
|
+
const number = issue_sample_gate.cited_via(body, 'pull')
|
|
65
66
|
|
|
66
67
|
if (number === undefined || (await ports.is_pull(number, repo)) !== false) return undefined
|
|
67
68
|
const cited = session_cite.issue(number, undefined, repo)
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { git_gh_exec } from '#scripts/gh/git-gh-exec'
|
|
2
|
+
import { issue_label_schema } from '#scripts/git/git-schemas'
|
|
3
|
+
import { parse_json } from '#scripts/git/parse-json-array'
|
|
4
|
+
import { bounded_pool } from '#scripts/lib/bounded-pool'
|
|
5
|
+
import { z } from 'zod'
|
|
6
|
+
|
|
7
|
+
// Every issue one `search/issues` query matches, read page by page. `defect:rate`'s windows and
|
|
8
|
+
// `effect:audit`'s listing ask it.
|
|
9
|
+
|
|
10
|
+
const PER_PAGE = '100'
|
|
11
|
+
const FIRST_PAGE = 1
|
|
12
|
+
const SECOND_PAGE = 2
|
|
13
|
+
// The search API serves at most this many results, so a window past it holds no further page.
|
|
14
|
+
const SEARCH_RESULT_CEILING = 1000
|
|
15
|
+
// The search API allows 30 requests a minute, so this bounds only how many are in flight at once.
|
|
16
|
+
const PAGE_CONCURRENCY = 4
|
|
17
|
+
|
|
18
|
+
const search_item_schema = z.object({
|
|
19
|
+
number: z.number().optional(),
|
|
20
|
+
title: z.string().optional(),
|
|
21
|
+
state: z.string().optional(),
|
|
22
|
+
body: z.string().nullish(),
|
|
23
|
+
labels: z.array(issue_label_schema),
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
// One page of `search/issues`.
|
|
27
|
+
const search_page_schema = z.object({
|
|
28
|
+
total_count: z.number(),
|
|
29
|
+
incomplete_results: z.boolean(),
|
|
30
|
+
items: z.array(search_item_schema),
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
type SearchPage = z.infer<typeof search_page_schema>
|
|
34
|
+
|
|
35
|
+
interface SearchIssue {
|
|
36
|
+
number: number
|
|
37
|
+
title: string
|
|
38
|
+
state: string
|
|
39
|
+
body: string
|
|
40
|
+
labels: ReadonlyArray<string>
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
interface SearchResult {
|
|
44
|
+
issues: ReadonlyArray<SearchIssue>
|
|
45
|
+
is_capped: boolean
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function search_path(query: string, page: number = FIRST_PAGE): string {
|
|
49
|
+
const parameters = new URLSearchParams({ q: query, per_page: PER_PAGE })
|
|
50
|
+
|
|
51
|
+
if (page !== FIRST_PAGE) parameters.set('page', String(page))
|
|
52
|
+
|
|
53
|
+
return `search/issues?${parameters.toString()}`
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// How many pages the search holds, read off the first page's own count. Bounded by the API's
|
|
57
|
+
// ceiling, past which GitHub serves no page at all — so this asks for exactly the pages `gh api
|
|
58
|
+
// --paginate` would walk to.
|
|
59
|
+
function page_count(first: SearchPage): number {
|
|
60
|
+
return Math.ceil(Math.min(first.total_count, SEARCH_RESULT_CEILING) / Number(PER_PAGE))
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function read_page(query: string, page: number): Promise<SearchPage | undefined> {
|
|
64
|
+
const raw = await git_gh_exec.exec_gh_api({ path: search_path(query, page) })
|
|
65
|
+
|
|
66
|
+
return parse_json.parse_json_object_or_undefined(raw, search_page_schema)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Every page of one search. Not `gh api --paginate`: it follows each page's `next` link one page
|
|
70
|
+
// after another, at about 1.5 s a page. The first page names the total, so the rest are fetched
|
|
71
|
+
// together; any page that does not read fails the whole search.
|
|
72
|
+
async function read_pages(query: string): Promise<ReadonlyArray<SearchPage> | undefined> {
|
|
73
|
+
const first = await read_page(query, FIRST_PAGE)
|
|
74
|
+
|
|
75
|
+
if (first === undefined) return undefined
|
|
76
|
+
|
|
77
|
+
const rest_numbers = Array.from(
|
|
78
|
+
{ length: Math.max(page_count(first) - FIRST_PAGE, 0) },
|
|
79
|
+
(_value, index) => index + SECOND_PAGE,
|
|
80
|
+
)
|
|
81
|
+
const rest = await bounded_pool.bounded_map(
|
|
82
|
+
rest_numbers,
|
|
83
|
+
PAGE_CONCURRENCY,
|
|
84
|
+
async (page) => await read_page(query, page),
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
return rest.every((page) => page !== undefined) ? [first, ...rest] : undefined
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function to_issue(item: z.infer<typeof search_item_schema>): SearchIssue {
|
|
91
|
+
return {
|
|
92
|
+
number: item.number ?? 0,
|
|
93
|
+
title: item.title ?? '',
|
|
94
|
+
state: item.state ?? '',
|
|
95
|
+
body: item.body ?? '',
|
|
96
|
+
labels: item.labels.map((label) => label.name),
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function to_result(pages: ReadonlyArray<SearchPage>): SearchResult {
|
|
101
|
+
const issues = pages.flatMap((page) => page.items.map((item) => to_issue(item)))
|
|
102
|
+
// The search API serves at most 1000 results, and says so only by a total larger than what it
|
|
103
|
+
// handed back — a window past that ceiling is measured on part of itself.
|
|
104
|
+
const total = pages[0]?.total_count ?? 0
|
|
105
|
+
const is_incomplete = pages.some((page) => page.incomplete_results)
|
|
106
|
+
|
|
107
|
+
return { issues, is_capped: is_incomplete || total > issues.length }
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// The search's issues, or `undefined` when any page could not be read.
|
|
111
|
+
async function search(query: string): Promise<SearchResult | undefined> {
|
|
112
|
+
try {
|
|
113
|
+
const pages = await read_pages(query)
|
|
114
|
+
|
|
115
|
+
return pages === undefined ? undefined : to_result(pages)
|
|
116
|
+
} catch {
|
|
117
|
+
return undefined
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const issue_search = { search, search_path }
|
|
122
|
+
|
|
123
|
+
export type { SearchIssue, SearchResult }
|
|
124
|
+
export { issue_search }
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { parse_json_object_or_undefined } from '#scripts/git/parse-json-array'
|
|
2
2
|
import { z } from 'zod'
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
has_any_label,
|
|
5
|
+
has_label_name,
|
|
6
|
+
NEEDS_HUMAN_REVIEW_LABEL,
|
|
7
|
+
PLANNED_LABEL,
|
|
8
|
+
} from './issue-labels'
|
|
9
|
+
import type { StateRead } from './issue-state-cli'
|
|
4
10
|
|
|
5
11
|
// The answer `josh issue:state` prints, kept apart from the reading and the printing so the shape of
|
|
6
12
|
// the report is decided by one pure function.
|
|
@@ -93,7 +99,13 @@ function format_attributed_issue_state(issue_number: string, state: IssueState):
|
|
|
93
99
|
return `${ISSUE_LABEL}${issue_number}\n${format_issue_state(state)}`
|
|
94
100
|
}
|
|
95
101
|
|
|
102
|
+
// Whether a read issue carries `run:planned` — asked by `run:stage` and by `run:entry`'s trust gate.
|
|
103
|
+
function is_planned(read: StateRead): boolean {
|
|
104
|
+
return read.kind === 'state' && has_label_name(read.state.labels, PLANNED_LABEL)
|
|
105
|
+
}
|
|
106
|
+
|
|
96
107
|
const issue_state = {
|
|
108
|
+
is_planned,
|
|
97
109
|
NO_LABELS,
|
|
98
110
|
parse_issue_state,
|
|
99
111
|
format_issue_state,
|