@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
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { LaunchOutcome } from '#scripts/lane/lane-launch-cli'
|
|
2
|
+
import type { DrivePorts, DriveState, PassResult } from './backlog-drive'
|
|
3
|
+
import { backlog_drive_seats } from './backlog-drive-seats'
|
|
4
|
+
|
|
5
|
+
// The launches of one offered pass, out of `backlog-drive.ts` so the loop stays within its size.
|
|
6
|
+
|
|
7
|
+
const NO_FREE_LANES = 0
|
|
8
|
+
const LAUNCHED = 'launched'
|
|
9
|
+
const UNOPENED = 'unopened'
|
|
10
|
+
// The launch port's answer for an issue its measurement declaration closed (`backlog-measure-close.ts`).
|
|
11
|
+
const MEASURED_LAUNCH = 'measured' as const
|
|
12
|
+
|
|
13
|
+
type DriveLaunch = LaunchOutcome['kind'] | typeof MEASURED_LAUNCH
|
|
14
|
+
|
|
15
|
+
interface Settled {
|
|
16
|
+
in_flight: Array<string>
|
|
17
|
+
measured: Array<string>
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function handed_back(issue: string, state: DriveState): PassResult {
|
|
21
|
+
return { kind: 'end', end: { reason: 'launch', token: undefined, issue }, state }
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// A `lane:open` refused with every lane taken is a wait, not a judgement: the
|
|
25
|
+
// next offer after a lane frees retries it. A step failing after the lane opened is always handed back —
|
|
26
|
+
// that lane holds the last seat itself, so the free count would read the failure as a full pool.
|
|
27
|
+
async function refused(
|
|
28
|
+
issue: string,
|
|
29
|
+
outcome: DriveLaunch,
|
|
30
|
+
state: DriveState,
|
|
31
|
+
ports: DrivePorts,
|
|
32
|
+
): Promise<PassResult> {
|
|
33
|
+
if (outcome !== UNOPENED) return handed_back(issue, state)
|
|
34
|
+
if ((await ports.free_lanes()) <= NO_FREE_LANES) return { kind: 'continue', state }
|
|
35
|
+
|
|
36
|
+
return handed_back(issue, state)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// **Only a launch or a measured close is activity**: a pass that started nothing — every lane taken
|
|
40
|
+
// — keeps `active` where it was, or the once-a-minute offer would restart the idle budget for good. A
|
|
41
|
+
// measured issue is closed but may still read OPEN to `backlog:next`, so it is excluded as a merge is.
|
|
42
|
+
function launched(state: DriveState, settled: Settled, ports: DrivePorts): DriveState {
|
|
43
|
+
const { in_flight, measured } = settled
|
|
44
|
+
|
|
45
|
+
if (in_flight.length === state.in_flight.length && measured.length === 0) {
|
|
46
|
+
return { ...state, in_flight }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const exclude = [...state.exclude, ...measured]
|
|
50
|
+
|
|
51
|
+
return { ...state, in_flight, exclude, active: ports.now().toISOString() }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Whether the launch settled the issue — into flight, or closed by its measurement.
|
|
55
|
+
function is_settled(settled: Settled, issue: string, outcome: DriveLaunch): boolean {
|
|
56
|
+
if (outcome === MEASURED_LAUNCH) settled.measured.push(issue)
|
|
57
|
+
if (outcome === LAUNCHED) settled.in_flight.push(issue)
|
|
58
|
+
|
|
59
|
+
return outcome === MEASURED_LAUNCH || outcome === LAUNCHED
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// **No more new lanes than free lanes**. `backlog:offer` lists every ready issue without reading the
|
|
63
|
+
// lanes, so launching all of them overran `JOSH_LANE_LIMIT` until `lane:open` ran out of seats. An issue
|
|
64
|
+
// that already holds a kept lane reuses its port seat but takes a place under the limit, ahead of a
|
|
65
|
+
// fresh launch; the rest launch up to the free count (`backlog-drive-seats.ts`), read before the first.
|
|
66
|
+
async function launch_all(
|
|
67
|
+
issues: ReadonlyArray<string>,
|
|
68
|
+
state: DriveState,
|
|
69
|
+
ports: DrivePorts,
|
|
70
|
+
): Promise<PassResult> {
|
|
71
|
+
const settled: Settled = { in_flight: [...state.in_flight], measured: [] }
|
|
72
|
+
const launching = await backlog_drive_seats.seated(issues, ports)
|
|
73
|
+
|
|
74
|
+
for (const issue of launching) {
|
|
75
|
+
// eslint-disable-next-line no-await-in-loop -- lanes launch in order and the first refusal ends the pass
|
|
76
|
+
const outcome = await ports.launch(issue)
|
|
77
|
+
|
|
78
|
+
if (!is_settled(settled, issue, outcome)) {
|
|
79
|
+
// eslint-disable-next-line no-await-in-loop -- lanes launch in order and the first refusal ends the pass
|
|
80
|
+
return await refused(issue, outcome, launched(state, settled, ports), ports)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return { kind: 'continue', state: launched(state, settled, ports) }
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const backlog_drive_launch_pass = { MEASURED_LAUNCH, launch_all }
|
|
88
|
+
|
|
89
|
+
export type { DriveLaunch }
|
|
90
|
+
export { backlog_drive_launch_pass }
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { git_stash } from '#scripts/git/stash/git-stash'
|
|
2
|
-
import { lane_launch_cli
|
|
2
|
+
import { lane_launch_cli } from '#scripts/lane/lane-launch-cli'
|
|
3
3
|
import { run_event_setup } from '#scripts/run/event/run-event-setup'
|
|
4
|
+
import { backlog_drive_launch_pass, type DriveLaunch } from './backlog-drive-launch-pass'
|
|
4
5
|
import { backlog_drive_owner } from './backlog-drive-owner'
|
|
6
|
+
import { backlog_measure_close } from './backlog-measure-close'
|
|
7
|
+
|
|
8
|
+
const { MEASURED_LAUNCH } = backlog_drive_launch_pass
|
|
5
9
|
|
|
6
10
|
// The driver's lane launch. The parent that ran `josh latest` in the primary
|
|
7
11
|
// checkout leaves its rewritten lock file in a stash under this message — `backlogrun-lanes.md` →
|
|
@@ -27,8 +31,10 @@ async function latest_stash(): Promise<string | undefined> {
|
|
|
27
31
|
return selection.kind === 'match' ? LATEST_STASH_MESSAGE : undefined
|
|
28
32
|
}
|
|
29
33
|
|
|
30
|
-
|
|
34
|
+
// An issue its measurement declaration closed takes no lane (`backlog-measure-close.ts`).
|
|
35
|
+
async function launch(issue: string, owner: string): Promise<DriveLaunch> {
|
|
31
36
|
await backlog_drive_owner.assert_current(owner)
|
|
37
|
+
if (await backlog_measure_close.closed(issue)) return MEASURED_LAUNCH
|
|
32
38
|
await run_event_setup.emit(run_event_setup.opening_lane(issue))
|
|
33
39
|
|
|
34
40
|
const outcome = await lane_launch_cli.launch_lane({ issue, stash: await latest_stash() })
|
|
@@ -1,14 +1,22 @@
|
|
|
1
|
+
import { auto_ok_cli } from '#scripts/auto-ok/auto-ok-cli'
|
|
1
2
|
import { issue_cite } from '#scripts/issue/issue-cite'
|
|
2
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
EPIC_LABEL,
|
|
5
|
+
has_label_name,
|
|
6
|
+
has_parked_label,
|
|
7
|
+
parked_label_of,
|
|
8
|
+
} from '#scripts/issue/issue-labels'
|
|
3
9
|
import type { IssueState } from '#scripts/issue/issue-state'
|
|
4
10
|
import { issue_state_cli } from '#scripts/issue/issue-state-cli'
|
|
11
|
+
import { lane_plan } from '#scripts/lane/lane-plan'
|
|
5
12
|
import type { RunCarry } from '#scripts/run/carry/run-carry'
|
|
6
|
-
import type { MergeResult } from '#scripts/run/merge/run-merge-cli'
|
|
7
13
|
import { backlog_budget } from './backlog-budget'
|
|
8
14
|
import type { DriveState, OfferRead } from './backlog-drive'
|
|
9
15
|
import { backlog_drive_epic } from './backlog-drive-epic'
|
|
10
16
|
import { backlog_drive_named } from './backlog-drive-named'
|
|
11
17
|
import { backlog_drive_unread } from './backlog-drive-unread'
|
|
18
|
+
import type { Declared } from './backlog-overlap'
|
|
19
|
+
import { backlog_plan_comment } from './backlog-plan-comment'
|
|
12
20
|
|
|
13
21
|
interface NamedContext {
|
|
14
22
|
is_only: boolean
|
|
@@ -49,13 +57,11 @@ function budget_offer(
|
|
|
49
57
|
}
|
|
50
58
|
}
|
|
51
59
|
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
// Either is booked done rather than offered
|
|
55
|
-
function
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return has_parked_label(state.labels) ? 'parked' : undefined
|
|
60
|
+
// Whether a named issue has already settled without this run dispatching it: closed is merged, and a
|
|
61
|
+
// park (`PARKED_LABELS`) waits on a person, so re-dispatching it only repeats the stop it parked on.
|
|
62
|
+
// Either is booked done rather than offered.
|
|
63
|
+
function is_settled(state: IssueState): boolean {
|
|
64
|
+
return state.state.toUpperCase() === 'CLOSED' || has_parked_label(state.labels)
|
|
59
65
|
}
|
|
60
66
|
|
|
61
67
|
async function classify(
|
|
@@ -68,14 +74,8 @@ async function classify(
|
|
|
68
74
|
|
|
69
75
|
if (result.kind !== 'state') return backlog_drive_unread.offer(issue, result, state.retries)
|
|
70
76
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
if (outcome !== undefined) {
|
|
74
|
-
await backlog_drive_named.mark_done(
|
|
75
|
-
issue,
|
|
76
|
-
{ outcome, code: 0, token: 'none', is_offer: true },
|
|
77
|
-
owner,
|
|
78
|
-
)
|
|
77
|
+
if (is_settled(result.state)) {
|
|
78
|
+
await backlog_drive_named.mark_settled(issue, owner)
|
|
79
79
|
|
|
80
80
|
return { verdict: 'wait', issues: [], retries: NO_RETRIES }
|
|
81
81
|
}
|
|
@@ -88,23 +88,37 @@ async function classify(
|
|
|
88
88
|
// **A named issue booked done is not thereby merged**: a park and a failure are
|
|
89
89
|
// booked done too, so the run moves past them. One the run's own merges did not record and GitHub does
|
|
90
90
|
// not read as closed ended without a merge — and an unreadable state counts as that, because a false
|
|
91
|
-
// stop reaches a person while a false finish ends the run where nobody sees it.
|
|
92
|
-
|
|
93
|
-
|
|
91
|
+
// stop reaches a person while a false finish ends the run where nobody sees it. The answer is why it
|
|
92
|
+
// did not merge (joshuafolkken/kit#4746): the park it sits on, or that it is open without one.
|
|
93
|
+
async function unmerged_reason(
|
|
94
|
+
issue: number,
|
|
95
|
+
merged: ReadonlyArray<number>,
|
|
96
|
+
): Promise<string | undefined> {
|
|
97
|
+
if (merged.includes(issue)) return undefined
|
|
94
98
|
|
|
95
99
|
const result = await issue_state_cli.read_issue(String(issue))
|
|
96
100
|
|
|
97
|
-
|
|
101
|
+
if (result.kind !== 'state') return 'state unreadable'
|
|
102
|
+
if (result.state.state.toUpperCase() === 'CLOSED') return undefined
|
|
103
|
+
|
|
104
|
+
return parked_label_of(result.state.labels) ?? 'open'
|
|
98
105
|
}
|
|
99
106
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
107
|
+
function cite(issue: number, reason: string | undefined): string | undefined {
|
|
108
|
+
return reason === undefined ? undefined : `${issue_cite.plain(issue)} (${reason})`
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Each named issue that did not merge, with its reason. The issues `run:add` put in count too: one that
|
|
112
|
+
// parked is no more a merge than a declared one.
|
|
113
|
+
async function unmerged_of(carry: RunCarry): Promise<Array<string>> {
|
|
103
114
|
const declared = backlog_drive_named.named_issues(carry)
|
|
104
115
|
const merged = carry.merged_issues ?? []
|
|
105
|
-
const
|
|
116
|
+
const reasons = await Promise.all(
|
|
117
|
+
declared.map(async (issue) => await unmerged_reason(issue, merged)),
|
|
118
|
+
)
|
|
119
|
+
const cited = declared.map((issue, index) => cite(issue, reasons[index]))
|
|
106
120
|
|
|
107
|
-
return
|
|
121
|
+
return cited.filter((line) => line !== undefined)
|
|
108
122
|
}
|
|
109
123
|
|
|
110
124
|
// The `--only` run's end: a finish when every named issue merged, otherwise a stop naming the ones that
|
|
@@ -114,9 +128,11 @@ async function only_end(carry: RunCarry, named: OfferRead): Promise<OfferRead> {
|
|
|
114
128
|
|
|
115
129
|
if (unmerged.length === 0) return named
|
|
116
130
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
131
|
+
return {
|
|
132
|
+
...named,
|
|
133
|
+
reason: `only: ${unmerged.join(', ')} ended without a merge`,
|
|
134
|
+
is_finish: false,
|
|
135
|
+
}
|
|
120
136
|
}
|
|
121
137
|
|
|
122
138
|
async function not_run(
|
|
@@ -126,12 +142,39 @@ async function not_run(
|
|
|
126
142
|
return named?.is_finish === true ? await only_end(carry, named) : named
|
|
127
143
|
}
|
|
128
144
|
|
|
145
|
+
// What the lanes in flight declare — recorded plan, else plan comment, else body, the scope `lane:plan` and
|
|
146
|
+
// `backlog:next` read. A lane the listing does not carry, or an unread listing, declares its plan alone.
|
|
147
|
+
async function in_flight_declared(in_flight: ReadonlyArray<string>): Promise<Declared> {
|
|
148
|
+
const listing = await auto_ok_cli.fetch_opted_in()
|
|
149
|
+
const listed = listing.kind === 'read' ? listing.issues : []
|
|
150
|
+
const pool = in_flight
|
|
151
|
+
.map(Number)
|
|
152
|
+
.map((number) => listed.find((issue) => issue.number === number) ?? { number })
|
|
153
|
+
|
|
154
|
+
return await backlog_plan_comment.declared_of(pool, process.cwd())
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// The issues in flight, with each named one whose yielded plan a running lane still holds: the offer
|
|
158
|
+
// waits on it as on a lane, so the run does not relaunch it into the same yield (joshuafolkken/kit#4926).
|
|
159
|
+
// The listing is read only when a named issue yielded and a lane runs.
|
|
160
|
+
async function holding(carry: RunCarry, in_flight: ReadonlyArray<string>): Promise<Array<string>> {
|
|
161
|
+
const yielded = backlog_drive_named
|
|
162
|
+
.named_issues(carry)
|
|
163
|
+
.filter((issue) => lane_plan.is_yielded(issue, process.cwd()))
|
|
164
|
+
if (yielded.length === 0 || in_flight.length === 0) return [...in_flight]
|
|
165
|
+
const declared = await in_flight_declared(in_flight)
|
|
166
|
+
const held = yielded.filter((issue) => lane_plan.is_yield_held(issue, declared, process.cwd()))
|
|
167
|
+
|
|
168
|
+
return [...new Set([...in_flight, ...held.map(String)])]
|
|
169
|
+
}
|
|
170
|
+
|
|
129
171
|
async function read(
|
|
130
172
|
carry: RunCarry,
|
|
131
173
|
state: DriveState,
|
|
132
174
|
context: NamedContext,
|
|
133
175
|
): Promise<OfferRead | undefined> {
|
|
134
|
-
const
|
|
176
|
+
const waiting = { ...state, in_flight: await holding(carry, state.in_flight) }
|
|
177
|
+
const named = backlog_drive_named.offer(carry, waiting, context.is_only)
|
|
135
178
|
if (named?.verdict !== 'run') return await not_run(carry, named)
|
|
136
179
|
const budget = budget_offer(carry, state, context.forwarded)
|
|
137
180
|
if (budget.verdict !== 'run') return budget
|
|
@@ -53,6 +53,15 @@ function held_after(
|
|
|
53
53
|
return index > declared.indexOf(next) ? declared[index - 1] : undefined
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
// **An `--only` run ends once nothing it named is left and nothing is in flight**
|
|
57
|
+
// (joshuafolkken/kit#4746): the stop's reason is read when it is offered, so one offered while a lane
|
|
58
|
+
// still ran would name that lane's issue unmerged even after it merged.
|
|
59
|
+
function only_end(state: DriveState): OfferRead {
|
|
60
|
+
return state.in_flight.length > 0
|
|
61
|
+
? { verdict: 'wait', issues: [], retries: NO_RETRIES }
|
|
62
|
+
: { verdict: 'stop', issues: [], retries: NO_RETRIES, reason: 'only', is_finish: true }
|
|
63
|
+
}
|
|
64
|
+
|
|
56
65
|
function offer(carry: RunCarry, state: DriveState, is_only: boolean): OfferRead | undefined {
|
|
57
66
|
const next = next_of(carry, state.in_flight)
|
|
58
67
|
|
|
@@ -64,9 +73,7 @@ function offer(carry: RunCarry, state: DriveState, is_only: boolean): OfferRead
|
|
|
64
73
|
: { verdict: 'run', issues: [issue], retries: NO_RETRIES }
|
|
65
74
|
}
|
|
66
75
|
|
|
67
|
-
return is_only
|
|
68
|
-
? { verdict: 'stop', issues: [], retries: NO_RETRIES, reason: 'only', is_finish: true }
|
|
69
|
-
: undefined
|
|
76
|
+
return is_only ? only_end(state) : undefined
|
|
70
77
|
}
|
|
71
78
|
|
|
72
79
|
function is_done(result: MergeResult): boolean {
|
|
@@ -121,15 +128,28 @@ async function should_skip(issue: string, outcome: MergeResult['outcome']): Prom
|
|
|
121
128
|
return await lane_parked.is_parked(issue)
|
|
122
129
|
}
|
|
123
130
|
|
|
131
|
+
async function carry_target(): Promise<string | undefined> {
|
|
132
|
+
const directory = await run_carry.repository_directory()
|
|
133
|
+
|
|
134
|
+
return directory === undefined ? undefined : run_carry.carry_path(directory)
|
|
135
|
+
}
|
|
136
|
+
|
|
124
137
|
async function mark_done(issue: string, result: MergeResult, owner: string): Promise<void> {
|
|
125
138
|
if (!is_done(result)) return
|
|
126
|
-
const
|
|
127
|
-
if (
|
|
128
|
-
const target = run_carry.carry_path(directory)
|
|
129
|
-
if (!mark_one(target, issue, owner)) return
|
|
139
|
+
const target = await carry_target()
|
|
140
|
+
if (target === undefined || !mark_one(target, issue, owner)) return
|
|
130
141
|
if (await should_skip(issue, result.outcome)) skip_after_failure(target, issue, owner)
|
|
131
142
|
}
|
|
132
143
|
|
|
144
|
+
// **A named issue settled before this run dispatched it skips nothing** (joshuafolkken/kit#4746): it
|
|
145
|
+
// did not fail inside the run, so booking the ones declared after it done would end an `--only` run
|
|
146
|
+
// over issues no lane ever started.
|
|
147
|
+
async function mark_settled(issue: string, owner: string): Promise<void> {
|
|
148
|
+
const target = await carry_target()
|
|
149
|
+
|
|
150
|
+
if (target !== undefined) mark_one(target, issue, owner)
|
|
151
|
+
}
|
|
152
|
+
|
|
133
153
|
async function reconcile(
|
|
134
154
|
carry: RunCarry,
|
|
135
155
|
events: ReadonlyArray<RunEvent>,
|
|
@@ -173,6 +193,7 @@ export const backlog_drive_named = {
|
|
|
173
193
|
offer,
|
|
174
194
|
held_after,
|
|
175
195
|
mark_done,
|
|
196
|
+
mark_settled,
|
|
176
197
|
named_issues,
|
|
177
198
|
own_carried,
|
|
178
199
|
reconcile,
|
|
@@ -11,6 +11,7 @@ import { DEFAULT_SILENT_MINUTES } from '#scripts/run/run-liveness'
|
|
|
11
11
|
import type { DrivePorts, OfferRead, PassResult } from './backlog-drive'
|
|
12
12
|
import { backlog_drive_idle } from './backlog-drive-idle'
|
|
13
13
|
import { backlog_overlap } from './backlog-overlap'
|
|
14
|
+
import { backlog_plan_comment } from './backlog-plan-comment'
|
|
14
15
|
|
|
15
16
|
// A run held only by paused lanes (joshuafolkken/kit#4270): nothing of this run in flight, nothing
|
|
16
17
|
// dispatched, and a lane a person paused past the silent window `run:liveness` waits out declares a
|
|
@@ -85,12 +86,12 @@ function waiting_of(
|
|
|
85
86
|
}
|
|
86
87
|
|
|
87
88
|
/** The `paused` records whose declared paths a waiting candidate overlaps. */
|
|
88
|
-
function holding(
|
|
89
|
+
async function holding(
|
|
89
90
|
paused: ReadonlyArray<LaneStateRecord>,
|
|
90
91
|
issues: ReadonlyArray<OpenIssueData>,
|
|
91
92
|
records: ReadonlyArray<LaneStateRecord>,
|
|
92
|
-
): Array<LaneStateRecord
|
|
93
|
-
const declared =
|
|
93
|
+
): Promise<Array<LaneStateRecord>> {
|
|
94
|
+
const declared = await backlog_plan_comment.declared_of(issues, process.cwd())
|
|
94
95
|
const waiting = waiting_of(issues, records)
|
|
95
96
|
|
|
96
97
|
return paused.filter((record) =>
|
|
@@ -106,7 +107,7 @@ async function held_by(ports: PausedPorts): Promise<Array<LaneStateRecord>> {
|
|
|
106
107
|
|
|
107
108
|
const issues = await ports.read_issues()
|
|
108
109
|
|
|
109
|
-
return issues === undefined ? [] : holding(paused, issues, records)
|
|
110
|
+
return issues === undefined ? [] : await holding(paused, issues, records)
|
|
110
111
|
}
|
|
111
112
|
|
|
112
113
|
function describe(records: ReadonlyArray<LaneStateRecord>): string {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { lane_yield } from '#scripts/lane/lane-yield'
|
|
1
2
|
import { run_event_scope } from '#scripts/run/event/run-event-scope'
|
|
2
3
|
import { run_event_stream, type RunEvent } from '#scripts/run/event/run-event-stream'
|
|
3
4
|
import { backlog_offer_exclude } from './backlog-offer-exclude'
|
|
@@ -9,6 +10,7 @@ const SETTLED_KINDS: ReadonlySet<string> = new Set([
|
|
|
9
10
|
run_event_stream.EVENT_KIND.SPLIT,
|
|
10
11
|
run_event_stream.EVENT_KIND.WITHDRAW,
|
|
11
12
|
run_event_stream.EVENT_KIND.OUTAGE,
|
|
13
|
+
run_event_stream.EVENT_KIND.USAGE_LIMIT,
|
|
12
14
|
])
|
|
13
15
|
const DONE_KINDS: ReadonlySet<string> = new Set([
|
|
14
16
|
run_event_stream.EVENT_KIND.MERGE,
|
|
@@ -37,8 +39,11 @@ function active_issues(events: ReadonlyArray<RunEvent>): ReadonlySet<string> {
|
|
|
37
39
|
return active
|
|
38
40
|
}
|
|
39
41
|
|
|
42
|
+
// A yield is not among them: it gave its lane back without settling the issue (`lane-yield.ts`).
|
|
40
43
|
function settled_issues(events: ReadonlyArray<RunEvent>): ReadonlySet<number> {
|
|
41
|
-
const settled = events.filter(
|
|
44
|
+
const settled = events.filter(
|
|
45
|
+
(event) => DONE_KINDS.has(event.kind) && !lane_yield.is_yield(event),
|
|
46
|
+
)
|
|
42
47
|
|
|
43
48
|
return new Set(
|
|
44
49
|
settled
|
|
@@ -56,11 +61,14 @@ function issues_of_kind(events: ReadonlyArray<RunEvent>, kind: string): Readonly
|
|
|
56
61
|
}
|
|
57
62
|
|
|
58
63
|
// The issues a person withdrew from this run and nobody launched again: the withdrawal leaves the issue
|
|
59
|
-
// open for the next run, so this one keeps it out of the offer (joshuafolkken/kit#4365).
|
|
64
|
+
// open for the next run, so this one keeps it out of the offer (joshuafolkken/kit#4365). A lane that
|
|
65
|
+
// yielded stays in the run: its retained plan holds it back until the holder ends (`lane-yield.ts`).
|
|
60
66
|
function withdrawn_issues(events: ReadonlyArray<RunEvent>): ReadonlyArray<string> {
|
|
61
67
|
const named = issues_of_kind(events, run_event_stream.EVENT_KIND.WITHDRAW)
|
|
62
68
|
|
|
63
|
-
return named.filter(
|
|
69
|
+
return named.filter(
|
|
70
|
+
(issue) => run_event_scope.is_withdrawn(events, issue) && !lane_yield.is_yielded(events, issue),
|
|
71
|
+
)
|
|
64
72
|
}
|
|
65
73
|
|
|
66
74
|
// The offer's exclusion as the stream records it: the merged and withdrawn children and the ones still
|
|
@@ -17,16 +17,15 @@
|
|
|
17
17
|
// without a process, a network or a clock.
|
|
18
18
|
|
|
19
19
|
import { issue_cite } from '#scripts/issue/issue-cite'
|
|
20
|
-
import type { LaunchOutcome } from '#scripts/lane/lane-launch-cli'
|
|
21
20
|
import type { MergeResult } from '#scripts/run/merge/run-merge-cli'
|
|
22
21
|
import { run_merge_token } from '#scripts/run/merge/run-merge-token'
|
|
23
22
|
import { backlog_drive_adopt } from './backlog-drive-adopt'
|
|
24
23
|
import { backlog_drive_hold, type HeldWaiting } from './backlog-drive-hold'
|
|
25
24
|
import { backlog_drive_idle } from './backlog-drive-idle'
|
|
26
25
|
import { backlog_drive_judge } from './backlog-drive-judge'
|
|
26
|
+
import { backlog_drive_launch_pass, type DriveLaunch } from './backlog-drive-launch-pass'
|
|
27
27
|
import { backlog_drive_memory } from './backlog-drive-memory'
|
|
28
28
|
import { backlog_drive_paused } from './backlog-drive-paused'
|
|
29
|
-
import { backlog_drive_seats } from './backlog-drive-seats'
|
|
30
29
|
import { backlog_drive_token_handling } from './backlog-drive-token-handling'
|
|
31
30
|
|
|
32
31
|
const { MERGE_TOKEN } = run_merge_token
|
|
@@ -44,11 +43,11 @@ const KNOWN_VERDICTS: ReadonlySet<string> = new Set([
|
|
|
44
43
|
'wait',
|
|
45
44
|
])
|
|
46
45
|
const NO_RETRIES = 0
|
|
47
|
-
const NO_FREE_LANES = 0
|
|
48
46
|
const EXHAUSTED_ANSWER = 'exhausted'
|
|
49
47
|
const JUDGE_REASON = 'judge'
|
|
50
|
-
|
|
51
|
-
const
|
|
48
|
+
// The `hold` reason a pass held by a Claude usage limit records.
|
|
49
|
+
const USAGE_LIMIT_REASON = 'usage-limit'
|
|
50
|
+
const { launch_all } = backlog_drive_launch_pass
|
|
52
51
|
|
|
53
52
|
interface OfferRead extends HeldWaiting {
|
|
54
53
|
verdict: string
|
|
@@ -106,8 +105,9 @@ interface DrivePorts {
|
|
|
106
105
|
adoptable: (in_flight: ReadonlyArray<string>) => Promise<ReadonlyArray<string>>
|
|
107
106
|
// `backlog:offer`'s answer for the state, or `undefined` when it exited non-zero.
|
|
108
107
|
offer: (state: DriveState) => Promise<OfferRead | undefined>
|
|
109
|
-
// Where `lane:launch`'s chain ended — `launched`, `unopened` (no lane taken) or `failed` (one taken)
|
|
110
|
-
|
|
108
|
+
// Where `lane:launch`'s chain ended — `launched`, `unopened` (no lane taken) or `failed` (one taken) —
|
|
109
|
+
// or `measured`, the issue closed by its declaration with no lane taken.
|
|
110
|
+
launch: (issue: string) => Promise<DriveLaunch>
|
|
111
111
|
// The lanes free right now — `backlog_ready.drive_free_lane_count` in production, the limit less the
|
|
112
112
|
// open lanes.
|
|
113
113
|
free_lanes: () => Promise<number>
|
|
@@ -122,6 +122,9 @@ interface DrivePorts {
|
|
|
122
122
|
// Whether the machine has no memory for one more lane — `backlog_drive_memory.gauge()` in production,
|
|
123
123
|
// which carries its hysteresis between calls.
|
|
124
124
|
memory_held: () => Promise<boolean>
|
|
125
|
+
// Whether a Claude usage limit that stopped a child has yet to reset — `run_merge_usage_limit.is_held`
|
|
126
|
+
// in production (joshuafolkken/kit#4745).
|
|
127
|
+
usage_limited: () => Promise<boolean>
|
|
125
128
|
// Why an offered pass started nothing (`backlog-drive-hold.ts`). Production records it in the lane
|
|
126
129
|
// ledger only while a lane is free. `undefined` is the run's stop, which owes no lane a child.
|
|
127
130
|
hold: (reason: string | undefined, waiting?: ReadonlyArray<number>) => Promise<void>
|
|
@@ -250,58 +253,6 @@ async function collect_finished(state: DriveState, ports: DrivePorts): Promise<P
|
|
|
250
253
|
return { kind: 'continue', state: current }
|
|
251
254
|
}
|
|
252
255
|
|
|
253
|
-
// A `lane:open` refused with every lane taken is a wait, not a judgement: the
|
|
254
|
-
// next offer after a lane frees retries it. A step failing after the lane opened is always handed back —
|
|
255
|
-
// that lane holds the last seat itself, so the free count would read the failure as a full pool.
|
|
256
|
-
async function refused(
|
|
257
|
-
issue: string,
|
|
258
|
-
outcome: LaunchOutcome['kind'],
|
|
259
|
-
state: DriveState,
|
|
260
|
-
ports: DrivePorts,
|
|
261
|
-
): Promise<PassResult> {
|
|
262
|
-
if (outcome !== UNOPENED) return ended('launch', state, undefined, issue)
|
|
263
|
-
if ((await ports.free_lanes()) <= NO_FREE_LANES) return { kind: 'continue', state }
|
|
264
|
-
|
|
265
|
-
return ended('launch', state, undefined, issue)
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
// **No more new lanes than free lanes**. `backlog:offer` lists every ready issue without reading the
|
|
269
|
-
// lanes, so launching all of them overran `JOSH_LANE_LIMIT` until `lane:open` ran out of seats. An issue
|
|
270
|
-
// that already holds a kept lane reuses its port seat but takes a place under the limit, ahead of a
|
|
271
|
-
// fresh launch; the rest launch up to the free count (`backlog-drive-seats.ts`), read before the first.
|
|
272
|
-
//
|
|
273
|
-
// **Only a launch is activity**: a pass that started nothing — every lane taken
|
|
274
|
-
// — keeps `active` where it was, or the once-a-minute offer would restart the idle budget for good.
|
|
275
|
-
function launched(state: DriveState, in_flight: Array<string>, ports: DrivePorts): DriveState {
|
|
276
|
-
if (in_flight.length === state.in_flight.length) return { ...state, in_flight }
|
|
277
|
-
|
|
278
|
-
return { ...state, in_flight, active: ports.now().toISOString() }
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
async function launch_all(
|
|
282
|
-
issues: ReadonlyArray<string>,
|
|
283
|
-
state: DriveState,
|
|
284
|
-
ports: DrivePorts,
|
|
285
|
-
): Promise<PassResult> {
|
|
286
|
-
const in_flight = [...state.in_flight]
|
|
287
|
-
|
|
288
|
-
const launching = await backlog_drive_seats.seated(issues, ports)
|
|
289
|
-
|
|
290
|
-
for (const issue of launching) {
|
|
291
|
-
// eslint-disable-next-line no-await-in-loop -- lanes launch in order and the first refusal ends the pass
|
|
292
|
-
const outcome = await ports.launch(issue)
|
|
293
|
-
|
|
294
|
-
if (outcome !== LAUNCHED) {
|
|
295
|
-
// eslint-disable-next-line no-await-in-loop -- lanes launch in order and the first refusal ends the pass
|
|
296
|
-
return await refused(issue, outcome, launched(state, in_flight, ports), ports)
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
in_flight.push(issue)
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
return { kind: 'continue', state: launched(state, in_flight, ports) }
|
|
303
|
-
}
|
|
304
|
-
|
|
305
256
|
// A watch with nothing in flight is the drain: `run:step` owes the retrospective there, so it is the
|
|
306
257
|
// parent's. With children still running the watch is only waiting on them.
|
|
307
258
|
function on_verdict(read: OfferRead, state: DriveState): PassResult {
|
|
@@ -328,12 +279,21 @@ function on_verdict(read: OfferRead, state: DriveState): PassResult {
|
|
|
328
279
|
return { kind: 'continue', state }
|
|
329
280
|
}
|
|
330
281
|
|
|
331
|
-
|
|
282
|
+
async function usage_held(state: DriveState, ports: DrivePorts): Promise<PassResult> {
|
|
283
|
+
await ports.hold(USAGE_LIMIT_REASON)
|
|
284
|
+
|
|
285
|
+
return { kind: 'continue', state }
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// An offer answered `run`: launched while the machine has memory to spare and no usage limit is in
|
|
289
|
+
// force, held until both hold otherwise. A usage-limited pass polls on as a held one does.
|
|
332
290
|
async function run_offered(
|
|
333
291
|
issues: ReadonlyArray<string>,
|
|
334
292
|
state: DriveState,
|
|
335
293
|
ports: DrivePorts,
|
|
336
294
|
): Promise<PassResult> {
|
|
295
|
+
if (await ports.usage_limited()) return await usage_held(state, ports)
|
|
296
|
+
|
|
337
297
|
if (await ports.memory_held()) return await backlog_drive_memory.held(state, ports)
|
|
338
298
|
|
|
339
299
|
return await launch_all(issues, state, ports)
|
|
@@ -464,6 +424,7 @@ async function run_loop(
|
|
|
464
424
|
const backlog_drive = {
|
|
465
425
|
HANDOFF_TOKENS,
|
|
466
426
|
TOKEN_HANDLING,
|
|
427
|
+
USAGE_LIMIT_REASON,
|
|
467
428
|
initial_state,
|
|
468
429
|
merge_stopped,
|
|
469
430
|
run_loop,
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { OptedInRead, TrackingRead } from '#scripts/auto-ok/auto-ok-cli'
|
|
2
|
+
import { epic_graph } from '#scripts/epic/epic-graph'
|
|
3
|
+
import { epic_index } from '#scripts/epic/epic-index'
|
|
4
|
+
import { lane_plan } from '#scripts/lane/lane-plan'
|
|
5
|
+
import { lane_state } from '#scripts/lane/lane-state'
|
|
6
|
+
import { backlog_plan_comment } from './backlog-plan-comment'
|
|
7
|
+
import { backlog_pool } from './backlog-pool'
|
|
8
|
+
import type { GateScope } from './backlog-rank'
|
|
9
|
+
|
|
10
|
+
type OptedIn = Extract<OptedInRead, { kind: 'read' }>
|
|
11
|
+
type Tracking = Extract<TrackingRead, { kind: 'read' }>
|
|
12
|
+
|
|
13
|
+
// Everything the answer is assembled from, read once and passed down rather than re-fetched.
|
|
14
|
+
interface PoolContext {
|
|
15
|
+
opted_in: OptedIn
|
|
16
|
+
tracking: Tracking
|
|
17
|
+
repo: string
|
|
18
|
+
exclude: ReadonlyArray<number>
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// The rows the offer's cap bounds — the standalone half.
|
|
22
|
+
function standalone_keys(context: PoolContext): ReadonlySet<string> {
|
|
23
|
+
return backlog_pool.standalone_keys(context.opted_in.issues, {
|
|
24
|
+
tracked: epic_index.withheld_children(context.tracking.index, context.opted_in.issues),
|
|
25
|
+
exclude: context.exclude,
|
|
26
|
+
repo: context.repo,
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// The issues whose lane yielded on a plan it kept (`lane-yield.ts`) — offered first (`backlog-rank.ts`,
|
|
31
|
+
// joshuafolkken/kit#5107).
|
|
32
|
+
function yielded_keys(context: PoolContext, directory: string): ReadonlySet<string> {
|
|
33
|
+
const yielded = context.opted_in.issues.filter((issue) =>
|
|
34
|
+
lane_plan.is_yielded(issue.number, directory),
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
return new Set(yielded.map(({ number }) => epic_graph.key_of({ number, repo: context.repo })))
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// The running lanes still carry the pickup label, so the opted-in listing holds their bodies too —
|
|
41
|
+
// which is what lets a candidate be held back from a path a running lane already declares.
|
|
42
|
+
// `backlog:plan --waves` reads the same scope, so its first wave is this offer. Their lane state
|
|
43
|
+
// records name a paused holder in the wait it causes (joshuafolkken/kit#4270); they are local files.
|
|
44
|
+
// A lane's recorded plan (joshuafolkken/kit#4864), else a plan comment (joshuafolkken/kit#4923), is
|
|
45
|
+
// read in place of the body (joshuafolkken/kit#4937).
|
|
46
|
+
async function gate_scope(context: PoolContext): Promise<GateScope> {
|
|
47
|
+
const { issues } = context.opted_in
|
|
48
|
+
const directory = process.cwd()
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
standalone: standalone_keys(context),
|
|
52
|
+
declared: await backlog_plan_comment.declared_of(issues, directory),
|
|
53
|
+
lanes: await lane_state.read_states(issues.map((issue) => String(issue.number))),
|
|
54
|
+
yielded: yielded_keys(context, directory),
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const backlog_gate_scope = { gate_scope }
|
|
59
|
+
|
|
60
|
+
export { backlog_gate_scope }
|
|
61
|
+
export type { OptedIn, PoolContext }
|