@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,21 +1,27 @@
|
|
|
1
1
|
#!/usr/bin/env tsx
|
|
2
2
|
import { fileURLToPath } from 'node:url'
|
|
3
3
|
import { lane_child_marker } from '#scripts/lane/lane-child-marker'
|
|
4
|
-
import {
|
|
4
|
+
import { lane_ledger_write } from '#scripts/lane/lane-ledger-write'
|
|
5
5
|
import { review_stop_log } from '#scripts/review/review-stop-log'
|
|
6
6
|
import { run_event_stream } from '#scripts/run/event/run-event-stream'
|
|
7
7
|
import { run_event_stream_emit } from '#scripts/run/event/run-event-stream-emit'
|
|
8
8
|
import { run_ship, type ShipSection } from './run-ship'
|
|
9
9
|
import { run_ship_args } from './run-ship-args'
|
|
10
10
|
import { run_ship_body_draft } from './run-ship-body-draft'
|
|
11
|
+
import { run_ship_conflict_probe } from './run-ship-conflict-probe'
|
|
11
12
|
import { run_ship_detach } from './run-ship-detach'
|
|
13
|
+
import { run_ship_handover, type CodeCheck } from './run-ship-handover'
|
|
12
14
|
import { run_ship_infra_retry } from './run-ship-infra-retry'
|
|
15
|
+
import { run_ship_lap } from './run-ship-lap'
|
|
16
|
+
import type { PreDetachResult } from './run-ship-pre-detach'
|
|
17
|
+
import { run_ship_pre_detach_pinned } from './run-ship-pre-detach-pinned'
|
|
13
18
|
import { run_ship_pre_detach_timed } from './run-ship-pre-detach-timed'
|
|
14
19
|
import { run_ship_probe } from './run-ship-probe'
|
|
15
20
|
import { run_ship_return } from './run-ship-return'
|
|
16
21
|
import { run_ship_stage, type Phase, type ShipState, type Stage } from './run-ship-stage'
|
|
17
22
|
import { run_ship_steps, type ShipArguments, type Step } from './run-ship-steps'
|
|
18
23
|
import { run_ship_stop_cause } from './run-ship-stop-cause'
|
|
24
|
+
import type { StepResult } from './run-ship-sync'
|
|
19
25
|
|
|
20
26
|
// `josh ship "<title> #<N>"` — one call for the fixed commit-to-report region a run ships a change on.
|
|
21
27
|
// It runs `gate`, `git -y`, `followup` and `run:tail` internally, so no round trip re-bills a lane's
|
|
@@ -47,7 +53,7 @@ const ARGV_OFFSET = 2
|
|
|
47
53
|
const SUCCESS_EXIT_CODE = 0
|
|
48
54
|
const FAILURE_EXIT_CODE = 1
|
|
49
55
|
const USAGE =
|
|
50
|
-
'Usage: josh ship "<title> #<N>" [<follow-up-N> ...] [--cite <N> ...] [--review] [--detach] [--body-file <path>] [--notify-message <text> | --notify-message-file <path>] | josh ship --log <N>'
|
|
56
|
+
'Usage: josh ship "<title> #<N>" [<follow-up-N> ...] [--cite <N> ...] [--review [--unpinned-ok "<reason>"]] [--detach] [--body-file <path>] [--notify-message <text> | --notify-message-file <path>] | josh ship --log <N>'
|
|
51
57
|
const NO_LOG_NOTE = 'no detached ship supervisor log for this issue'
|
|
52
58
|
const LANE_CHILD_DETACH_NOTE =
|
|
53
59
|
'lane child: shipping through the detached supervisor (--detach implied), so the end of this turn cannot kill it'
|
|
@@ -61,9 +67,17 @@ interface ShipContext {
|
|
|
61
67
|
done: ReadonlySet<string>
|
|
62
68
|
state: ShipState
|
|
63
69
|
started: Array<string>
|
|
70
|
+
// Whether the code this process loaded has changed since it started (`run-ship-handover.ts`).
|
|
71
|
+
is_stale: CodeCheck
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
interface ShipOutcome {
|
|
75
|
+
sections: ReadonlyArray<ShipSection>
|
|
76
|
+
is_handed_over: boolean
|
|
64
77
|
}
|
|
65
78
|
|
|
66
79
|
const { PHASE, STAGE } = run_ship_stage
|
|
80
|
+
const REREAD_AFTER: ReadonlySet<Stage> = new Set([STAGE.SYNC, STAGE.REVIEW])
|
|
67
81
|
|
|
68
82
|
// Every stage that ran is timed into the lane ledger, failed ones included — a stage that stopped the
|
|
69
83
|
// ship cost the lane its time as well. The append is local and best-effort, so it adds no wait.
|
|
@@ -72,12 +86,16 @@ const { PHASE, STAGE } = run_ship_stage
|
|
|
72
86
|
// recorded, or a gate that reused its tree's green record would otherwise read as a run that took a
|
|
73
87
|
// second and pull the stage's median to zero.
|
|
74
88
|
async function record_timed(step: Step, issue: string, elapsed_ms: number): Promise<void> {
|
|
75
|
-
await
|
|
89
|
+
await lane_ledger_write.record_stage({ stage: step.stage, elapsed_ms, issue: Number(issue) })
|
|
76
90
|
}
|
|
77
91
|
|
|
78
92
|
async function run_once(step: Step, args: ShipArguments, state: ShipState): Promise<ShipSection> {
|
|
79
93
|
const started_ms = performance.now()
|
|
80
|
-
const result = await
|
|
94
|
+
const result = await run_ship_lap.within(
|
|
95
|
+
args.number,
|
|
96
|
+
step.stage,
|
|
97
|
+
async () => await step.run(args, state),
|
|
98
|
+
)
|
|
81
99
|
const elapsed_ms = performance.now() - started_ms
|
|
82
100
|
|
|
83
101
|
if (result.is_skipped !== true) await record_timed(step, args.number, elapsed_ms)
|
|
@@ -97,15 +115,31 @@ async function run_step(step: Step, args: ShipArguments, state: ShipState): Prom
|
|
|
97
115
|
})
|
|
98
116
|
}
|
|
99
117
|
|
|
118
|
+
// One stage's line on the event stream, with why it ran or was skipped where the stage said.
|
|
119
|
+
interface StageMark {
|
|
120
|
+
stage: Stage
|
|
121
|
+
phase: Phase
|
|
122
|
+
reason?: string | undefined
|
|
123
|
+
}
|
|
124
|
+
|
|
100
125
|
async function emit_phase(
|
|
101
126
|
args: ShipArguments,
|
|
102
127
|
context: ShipContext,
|
|
103
|
-
|
|
104
|
-
phase: Phase,
|
|
128
|
+
mark: StageMark,
|
|
105
129
|
): Promise<void> {
|
|
106
|
-
const text = run_ship_stage.event_text(args.number, stage, phase, context.started)
|
|
130
|
+
const text = run_ship_stage.event_text(args.number, mark.stage, mark.phase, context.started)
|
|
107
131
|
|
|
108
|
-
await run_event_stream_emit.emit(
|
|
132
|
+
await run_event_stream_emit.emit(
|
|
133
|
+
run_event_stream.EVENT_KIND.SHIP_STAGE,
|
|
134
|
+
run_ship_stage.with_reason(text, mark.reason),
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// A green stage that found nothing to do ends `skipped` rather than `done` (joshuafolkken/kit#5296).
|
|
139
|
+
function settled_phase(section: ShipSection): Phase {
|
|
140
|
+
if (section.code !== SUCCESS_EXIT_CODE) return PHASE.FAILED
|
|
141
|
+
|
|
142
|
+
return section.is_skipped === true ? PHASE.SKIPPED : PHASE.DONE
|
|
109
143
|
}
|
|
110
144
|
|
|
111
145
|
// The record is written best-effort, as the event stream is: a record that could not be written costs
|
|
@@ -124,13 +158,13 @@ async function settle(
|
|
|
124
158
|
step: Step,
|
|
125
159
|
args: ShipArguments,
|
|
126
160
|
context: ShipContext,
|
|
127
|
-
|
|
161
|
+
section: ShipSection,
|
|
128
162
|
): Promise<void> {
|
|
129
|
-
const
|
|
163
|
+
const phase = settled_phase(section)
|
|
130
164
|
|
|
131
|
-
await emit_phase(args, context, step.stage,
|
|
165
|
+
await emit_phase(args, context, { stage: step.stage, phase, reason: section.reason })
|
|
132
166
|
|
|
133
|
-
if (
|
|
167
|
+
if (phase === PHASE.FAILED) return
|
|
134
168
|
|
|
135
169
|
record(context.target, (path) => {
|
|
136
170
|
run_ship_stage.mark_done(path, step.stage)
|
|
@@ -150,7 +184,7 @@ async function run_stage(
|
|
|
150
184
|
context: ShipContext,
|
|
151
185
|
): Promise<ShipSection> {
|
|
152
186
|
if (run_ship_stage.is_done(step.stage, context.done, context.state, args.body.length > 0)) {
|
|
153
|
-
await emit_phase(args, context, step.stage, PHASE.SKIPPED)
|
|
187
|
+
await emit_phase(args, context, { stage: step.stage, phase: PHASE.SKIPPED })
|
|
154
188
|
|
|
155
189
|
return { header: step.header, body: run_ship.SKIPPED_BODY, code: SUCCESS_EXIT_CODE }
|
|
156
190
|
}
|
|
@@ -159,20 +193,22 @@ async function run_stage(
|
|
|
159
193
|
record(context.target, (path) => {
|
|
160
194
|
run_ship_stage.mark_started(path, step.stage)
|
|
161
195
|
})
|
|
162
|
-
await emit_phase(args, context, step.stage, PHASE.START)
|
|
196
|
+
await emit_phase(args, context, { stage: step.stage, phase: PHASE.START })
|
|
163
197
|
const section = await run_step(step, args, context.state)
|
|
164
198
|
|
|
165
|
-
await settle(step, args, context, section
|
|
166
|
-
//
|
|
167
|
-
|
|
199
|
+
await settle(step, args, context, section)
|
|
200
|
+
// The sync commits locally and a review may fix the tree, so the stages after either read the state
|
|
201
|
+
// anew — the commit stage then pushes the sync's commit rather than making it again.
|
|
202
|
+
if (REREAD_AFTER.has(step.stage)) set_state(context, await run_ship_probe.read_state())
|
|
168
203
|
|
|
169
204
|
return section
|
|
170
205
|
}
|
|
171
206
|
|
|
172
207
|
async function open_context(args: ShipArguments): Promise<ShipContext> {
|
|
173
|
-
const [target, state] = await Promise.all([
|
|
208
|
+
const [target, state, is_stale] = await Promise.all([
|
|
174
209
|
run_ship_probe.record_target(args.number),
|
|
175
210
|
run_ship_probe.read_state(),
|
|
211
|
+
run_ship_handover.watch(),
|
|
176
212
|
])
|
|
177
213
|
|
|
178
214
|
const done = target === undefined ? new Set<string>() : run_ship_stage.read_done(target)
|
|
@@ -183,7 +219,7 @@ async function open_context(args: ShipArguments): Promise<ShipContext> {
|
|
|
183
219
|
run_ship_stage.clear_waits(path)
|
|
184
220
|
})
|
|
185
221
|
|
|
186
|
-
return { target, done, state, started }
|
|
222
|
+
return { target, done, state, started, is_stale }
|
|
187
223
|
}
|
|
188
224
|
|
|
189
225
|
// Every stop goes to the lane ledger — supervised, in an agent's own turn, or a lane child's preflight
|
|
@@ -192,7 +228,7 @@ async function open_context(args: ShipArguments): Promise<ShipContext> {
|
|
|
192
228
|
async function record_stop(args: ShipArguments, stage: Stage, failed?: ShipSection): Promise<void> {
|
|
193
229
|
const issue = Number(args.number)
|
|
194
230
|
|
|
195
|
-
await
|
|
231
|
+
await lane_ledger_write.record_stop(run_ship_stop_cause.record_of(issue, stage, failed))
|
|
196
232
|
review_stop_log.record({ issue, stage, findings: run_ship_stop_cause.details_of(stage, failed) })
|
|
197
233
|
}
|
|
198
234
|
|
|
@@ -217,28 +253,50 @@ async function stopped(
|
|
|
217
253
|
return sections
|
|
218
254
|
}
|
|
219
255
|
|
|
256
|
+
// One stage, and the outcome where the ship ends at it: a failure, or a sync after which a successor on
|
|
257
|
+
// the code it merged took the rest over (`run-ship-handover.ts`).
|
|
258
|
+
async function ship_stage(
|
|
259
|
+
step: Step,
|
|
260
|
+
args: ShipArguments,
|
|
261
|
+
context: ShipContext,
|
|
262
|
+
sections: Array<ShipSection>,
|
|
263
|
+
): Promise<ShipOutcome | undefined> {
|
|
264
|
+
const section = await run_stage(step, args, context)
|
|
265
|
+
|
|
266
|
+
sections.push(section)
|
|
267
|
+
|
|
268
|
+
if (section.code !== SUCCESS_EXIT_CODE) {
|
|
269
|
+
return { sections: await stopped(sections, args, step, context), is_handed_over: false }
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (step.stage !== STAGE.SYNC) return undefined
|
|
273
|
+
const handover = await run_ship_handover.hand_over(args, context.is_stale)
|
|
274
|
+
|
|
275
|
+
return handover === undefined
|
|
276
|
+
? undefined
|
|
277
|
+
: { sections: [...sections, handover], is_handed_over: true }
|
|
278
|
+
}
|
|
279
|
+
|
|
220
280
|
// Run the stages in order, stopping at the first that failed: a red gate never reaches the commit, so
|
|
221
281
|
// the returned sections end at the failure the report names. A ship that reached the end clears its
|
|
222
|
-
// record, so the next ship of the same issue starts from the preflight
|
|
223
|
-
|
|
282
|
+
// record, so the next ship of the same issue starts from the preflight; one handed over leaves it to
|
|
283
|
+
// the successor, which passes over what this one finished.
|
|
284
|
+
async function ship(args: ShipArguments): Promise<ShipOutcome> {
|
|
224
285
|
const context = await open_context(args)
|
|
225
286
|
const sections: Array<ShipSection> = []
|
|
226
287
|
|
|
227
288
|
for (const step of run_ship_steps.steps(args)) {
|
|
228
289
|
// eslint-disable-next-line no-await-in-loop -- stages run in order and the first failure stops the ship
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
sections.push(section)
|
|
290
|
+
const outcome = await ship_stage(step, args, context, sections)
|
|
232
291
|
|
|
233
|
-
|
|
234
|
-
if (section.code !== SUCCESS_EXIT_CODE) return await stopped(sections, args, step, context)
|
|
292
|
+
if (outcome !== undefined) return outcome
|
|
235
293
|
}
|
|
236
294
|
|
|
237
295
|
record(context.target, (path) => {
|
|
238
296
|
run_ship_stage.clear(path)
|
|
239
297
|
})
|
|
240
298
|
|
|
241
|
-
return sections
|
|
299
|
+
return { sections, is_handed_over: false }
|
|
242
300
|
}
|
|
243
301
|
|
|
244
302
|
async function print_log(number: string): Promise<number> {
|
|
@@ -283,11 +341,29 @@ function should_detach(args: ShipArguments): boolean {
|
|
|
283
341
|
return !run_ship_detach.is_supervised() && lane_child_marker.is_child_of(process.cwd())
|
|
284
342
|
}
|
|
285
343
|
|
|
286
|
-
// The preflight stop's unmet kinds, with
|
|
287
|
-
|
|
344
|
+
// The preflight stop's unmet kinds, with the red pre-detach checks' own kinds added beside them
|
|
345
|
+
// (`run-ship-pre-detach.ts`).
|
|
346
|
+
function with_checks(stop: ShipSection, checks: PreDetachResult): ShipSection {
|
|
288
347
|
if (checks.code === SUCCESS_EXIT_CODE) return stop
|
|
289
348
|
|
|
290
|
-
return {
|
|
349
|
+
return {
|
|
350
|
+
...stop,
|
|
351
|
+
preconditions: [...(stop.preconditions ?? []), ...(checks.preconditions ?? [])],
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// The stop is the sync stage's, so it is recorded and resumed as that stage's `conflict` is; the
|
|
356
|
+
// preflight's refusal, if any, still prints last.
|
|
357
|
+
async function conflict_sections(
|
|
358
|
+
args: ShipArguments,
|
|
359
|
+
conflict: StepResult,
|
|
360
|
+
preflight: ShipSection,
|
|
361
|
+
): Promise<ReadonlyArray<ShipSection>> {
|
|
362
|
+
const section = run_ship.section_of(run_ship.SYNC_HEADER, conflict)
|
|
363
|
+
|
|
364
|
+
await record_stop(args, STAGE.SYNC, section)
|
|
365
|
+
|
|
366
|
+
return [section, preflight]
|
|
291
367
|
}
|
|
292
368
|
|
|
293
369
|
// The preflight is deterministic and fast, so it runs here, in the agent's own turn, before the
|
|
@@ -296,19 +372,32 @@ function with_checks(stop: ShipSection, checks: ShipSection): ShipSection {
|
|
|
296
372
|
// checks (`run-ship-pre-detach.ts`) follow it here for the same reason; they are not a stage, so the
|
|
297
373
|
// supervisor's gate runs them again rather than passing over them. They run even when the preflight
|
|
298
374
|
// refused, so one ship reports every failure there is to fix (joshuafolkken/kit#4305); the preflight's
|
|
299
|
-
// refusal still comes before its own scoped pair, the one heavy check here
|
|
375
|
+
// refusal still comes before its own scoped pair, the one heavy check here beside a `--review` ship's
|
|
376
|
+
// `test:pinned`.
|
|
300
377
|
//
|
|
301
378
|
// **The refusal is printed last**: a lane child reading the report through `tail` saw only the red
|
|
302
379
|
// metrics or type check after it, fixed those, and shipped into the same refusal again — every repeated
|
|
303
380
|
// preflight stop of joshuafolkken/kit#4478. The stop records the pre-detach checks' red beside the
|
|
304
|
-
// unmet kinds, so the ledger shows which refusals came with one.
|
|
381
|
+
// unmet kinds, so the ledger shows which refusals came with one. **Red checks behind a passed preflight
|
|
382
|
+
// are a stop too** (joshuafolkken/kit#5228): recorded under the preflight with their kinds, an
|
|
383
|
+
// `unpinned` place among them.
|
|
384
|
+
//
|
|
385
|
+
// **A conflict with origin/main stops before the checks** (joshuafolkken/kit#5018): the supervisor's
|
|
386
|
+
// sync would stop on it after them, so they would only be run again once it is resolved.
|
|
305
387
|
async function pre_detach_sections(args: ShipArguments): Promise<ReadonlyArray<ShipSection>> {
|
|
306
388
|
const preflight = await run_stage(run_ship_steps.PREFLIGHT_STEP, args, await open_context(args))
|
|
307
|
-
const
|
|
389
|
+
const conflict = await run_ship_conflict_probe.probe()
|
|
390
|
+
|
|
391
|
+
if (conflict !== undefined) return await conflict_sections(args, conflict, preflight)
|
|
392
|
+
|
|
393
|
+
const result = await run_ship_pre_detach_timed.checks(
|
|
394
|
+
args.number,
|
|
395
|
+
run_ship_pre_detach_pinned.checks_for(args),
|
|
396
|
+
)
|
|
308
397
|
const checks = { header: run_ship.PRE_DETACH_HEADER, body: result.out, code: result.code }
|
|
309
398
|
|
|
310
|
-
if (
|
|
311
|
-
await record_stop(args, run_ship_steps.PREFLIGHT_STEP.stage, with_checks(preflight,
|
|
399
|
+
if (run_ship.exit_code([checks, preflight]) !== SUCCESS_EXIT_CODE) {
|
|
400
|
+
await record_stop(args, run_ship_steps.PREFLIGHT_STEP.stage, with_checks(preflight, result))
|
|
312
401
|
}
|
|
313
402
|
|
|
314
403
|
return [checks, preflight]
|
|
@@ -343,7 +432,9 @@ async function record_supervised_result(
|
|
|
343
432
|
await run_ship_detach.mark_result(repository, args.number, run_ship.exit_code(sections))
|
|
344
433
|
}
|
|
345
434
|
|
|
346
|
-
async function run_ship_command(
|
|
435
|
+
async function run_ship_command(given: ShipArguments): Promise<number> {
|
|
436
|
+
const args = await run_ship_pre_detach_pinned.with_recorded_reason(given)
|
|
437
|
+
|
|
347
438
|
if (should_detach(args)) {
|
|
348
439
|
if (!args.is_detach) console.error(LANE_CHILD_DETACH_NOTE)
|
|
349
440
|
|
|
@@ -351,9 +442,10 @@ async function run_ship_command(args: ShipArguments): Promise<number> {
|
|
|
351
442
|
}
|
|
352
443
|
|
|
353
444
|
await claim_supervised_identity(args)
|
|
354
|
-
const sections = await ship(args)
|
|
445
|
+
const { sections, is_handed_over } = await ship(args)
|
|
355
446
|
|
|
356
|
-
|
|
447
|
+
// The successor carries the same launch record, so its result is the one written there.
|
|
448
|
+
if (!is_handed_over) await record_supervised_result(args, sections)
|
|
357
449
|
console.info(run_ship.format_report(sections))
|
|
358
450
|
|
|
359
451
|
return run_ship.exit_code(sections)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { changed_paths } from '#scripts/git/changed-paths'
|
|
2
|
+
import { git_command } from '#scripts/git/git-command'
|
|
3
|
+
import { git_merge_conflicts } from '#scripts/git/git-merge-conflicts'
|
|
4
|
+
import { main_merge_guard } from '#scripts/git/main-merge-guard'
|
|
5
|
+
import { main_merge_regenerate } from '#scripts/git/main-merge-regenerate'
|
|
6
|
+
import type { StepResult } from './run-ship-sync'
|
|
7
|
+
|
|
8
|
+
// Before `josh ship --detach` runs its pre-detach checks, whether merging origin/main would stop on a
|
|
9
|
+
// conflict (joshuafolkken/kit#5018). The supervisor's sync stage is the first to merge, so a branch
|
|
10
|
+
// main had moved under ran the whole pre-detach first and then stopped there, its checks thrown away.
|
|
11
|
+
// The reading touches neither the working tree nor the index (`git-merge-conflicts.ts`); only the
|
|
12
|
+
// remote-tracking ref of the default branch moves with the fetch. A probe that cannot answer — a fetch
|
|
13
|
+
// that failed, a merge base it cannot read — leaves the question to the sync stage, as the sync itself
|
|
14
|
+
// leaves a failed fetch to the followup; the ship then runs exactly as it did before the probe.
|
|
15
|
+
|
|
16
|
+
const FAILURE_EXIT_CODE = 1
|
|
17
|
+
const CONFLICT_NOTE = 'merging origin/main would stop on a conflict in:'
|
|
18
|
+
|
|
19
|
+
// The sync's own order: `main:merge` refuses uncommitted work origin/main also changed, so the commit
|
|
20
|
+
// comes first (`main-merge-guard.ts`).
|
|
21
|
+
function fix_note(): string {
|
|
22
|
+
return `The pre-detach checks did not run. Commit the work with ${main_merge_guard.commit_command()}, run \`pnpm josh main:merge\`, resolve the conflict in those files, then run the ship again.`
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function conflicting_paths(): Promise<ReadonlyArray<string>> {
|
|
26
|
+
const default_branch = await git_command.get_default_branch()
|
|
27
|
+
|
|
28
|
+
await git_command.fetch_branch(default_branch)
|
|
29
|
+
|
|
30
|
+
const paths = await changed_paths.read_changed_paths(false)
|
|
31
|
+
const root = await git_command.repository_root()
|
|
32
|
+
|
|
33
|
+
return git_merge_conflicts.working_tree_conflicts(`origin/${default_branch}`, paths, root) ?? []
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function answered_paths(): Promise<ReadonlyArray<string>> {
|
|
37
|
+
try {
|
|
38
|
+
return await conflicting_paths()
|
|
39
|
+
} catch {
|
|
40
|
+
return []
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// The stop, carrying the paths as the sync stage's conflict does, so the stop is recorded as
|
|
45
|
+
// `conflict`; `undefined` when the merge would go through, the sync's merge would resolve every
|
|
46
|
+
// conflict itself (`main-merge-regenerate.ts`), or the probe could not tell.
|
|
47
|
+
async function probe(): Promise<StepResult | undefined> {
|
|
48
|
+
const conflicts = await answered_paths()
|
|
49
|
+
|
|
50
|
+
if (conflicts.length === 0 || main_merge_regenerate.is_resolvable(conflicts)) return undefined
|
|
51
|
+
|
|
52
|
+
const out = [CONFLICT_NOTE, ...conflicts, fix_note()].join('\n')
|
|
53
|
+
|
|
54
|
+
return { code: FAILURE_EXIT_CODE, out, conflicts }
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const run_ship_conflict_probe = { CONFLICT_NOTE, probe }
|
|
58
|
+
|
|
59
|
+
export { run_ship_conflict_probe }
|
|
@@ -3,6 +3,7 @@ import { setTimeout as sleep } from 'node:timers/promises'
|
|
|
3
3
|
import { agent_role_profile } from '#scripts/agent/agent-role-profile'
|
|
4
4
|
import { issue_cite } from '#scripts/issue/issue-cite'
|
|
5
5
|
import { session_cite } from '#scripts/issue/session-cite'
|
|
6
|
+
import { durable_state } from '#scripts/josh/durable-state'
|
|
6
7
|
import { process_identity } from '#scripts/josh/process-identity'
|
|
7
8
|
import { stamp_file } from '#scripts/josh/stamp-file'
|
|
8
9
|
import { json_value } from '#scripts/lib/json-value'
|
|
@@ -33,7 +34,7 @@ import { z } from 'zod'
|
|
|
33
34
|
// probe cannot momentarily read is the opposite case: the pid is alive and was verified once, so it is
|
|
34
35
|
// kept running rather than read as a crash that would license a second supervisor.
|
|
35
36
|
|
|
36
|
-
const LOG_PREFIX =
|
|
37
|
+
const LOG_PREFIX = durable_state.PREFIX.SHIP_LOG
|
|
37
38
|
const PID_PREFIX = 'josh-ship-pid-'
|
|
38
39
|
const BODY_PREFIX = 'josh-ship-notify-'
|
|
39
40
|
const KEY_SEPARATOR = '-'
|
|
@@ -51,7 +52,7 @@ const SUPERVISED_VALUE = '1'
|
|
|
51
52
|
const LAUNCHED = 'launched'
|
|
52
53
|
const BUSY = 'busy'
|
|
53
54
|
const FAILED = 'failed'
|
|
54
|
-
const RESULT_PREFIX =
|
|
55
|
+
const RESULT_PREFIX = durable_state.PREFIX.SHIP_RESULT
|
|
55
56
|
const RECORD_POLL_MS = 25
|
|
56
57
|
const RECORD_WAIT_ATTEMPTS = 200
|
|
57
58
|
// How long a bare launched pid is believed before the supervisor must have claimed the record: far above
|
|
@@ -92,6 +93,7 @@ interface DetachRequest {
|
|
|
92
93
|
body: ReadonlyArray<string>
|
|
93
94
|
cites: ReadonlyArray<string>
|
|
94
95
|
is_review: boolean
|
|
96
|
+
unpinned_ok: ReadonlyArray<string>
|
|
95
97
|
repository: string
|
|
96
98
|
cwd: string
|
|
97
99
|
}
|
|
@@ -106,11 +108,11 @@ function key(prefix: string, request: Pick<DetachRequest, 'number' | 'repository
|
|
|
106
108
|
}
|
|
107
109
|
|
|
108
110
|
function log_path(repository: string, number: string): string {
|
|
109
|
-
return
|
|
111
|
+
return durable_state.path(`${LOG_PREFIX}${number}${KEY_SEPARATOR}`, repository, LOG_SUFFIX)
|
|
110
112
|
}
|
|
111
113
|
|
|
112
114
|
function result_path(repository: string, number: string): string {
|
|
113
|
-
return
|
|
115
|
+
return durable_state.path(`${RESULT_PREFIX}${number}${KEY_SEPARATOR}`, repository)
|
|
114
116
|
}
|
|
115
117
|
|
|
116
118
|
function read_record(repository: string, number: string): ShipRecord | undefined {
|
|
@@ -277,6 +279,7 @@ function supervisor_argv(request: DetachRequest): LaunchArgv {
|
|
|
277
279
|
'josh',
|
|
278
280
|
'ship',
|
|
279
281
|
...review,
|
|
282
|
+
...request.unpinned_ok,
|
|
280
283
|
...notify_arguments(request),
|
|
281
284
|
...request.body,
|
|
282
285
|
...cites,
|
|
@@ -381,8 +384,11 @@ const run_ship_detach = {
|
|
|
381
384
|
last_launch,
|
|
382
385
|
log_path,
|
|
383
386
|
read_log,
|
|
387
|
+
read_record,
|
|
388
|
+
result_path,
|
|
384
389
|
running_since,
|
|
385
390
|
supervisor_argv,
|
|
391
|
+
supervisor_environment,
|
|
386
392
|
}
|
|
387
393
|
|
|
388
394
|
export type { DetachRequest, DetachResult }
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { fileURLToPath } from 'node:url'
|
|
2
|
+
import { issue_cite } from '#scripts/issue/issue-cite'
|
|
3
|
+
import { process_identity } from '#scripts/josh/process-identity'
|
|
4
|
+
import { run_event_stream } from '#scripts/run/event/run-event-stream'
|
|
5
|
+
import { run_event_stream_emit } from '#scripts/run/event/run-event-stream-emit'
|
|
6
|
+
import { run_wake_code } from '#scripts/run/wake/run-wake-code'
|
|
7
|
+
import { run_wake_stop } from '#scripts/run/wake/run-wake-stop'
|
|
8
|
+
import { run_wake_takeover, type TakeoverPorts } from '#scripts/run/wake/run-wake-takeover'
|
|
9
|
+
import type { ShipSection } from './run-ship'
|
|
10
|
+
import { run_ship_detach } from './run-ship-detach'
|
|
11
|
+
import { run_ship_probe } from './run-ship-probe'
|
|
12
|
+
import { run_ship_relaunch } from './run-ship-relaunch'
|
|
13
|
+
import type { ShipArguments } from './run-ship-steps'
|
|
14
|
+
|
|
15
|
+
// A supervisor whose sync merged a change to its own code hands the ship to a successor on that code
|
|
16
|
+
// (joshuafolkken/kit#4849). The stages run in one process, so a review stage after a sync that pulled
|
|
17
|
+
// a fix to `scripts/review/` still judged on the code the supervisor started with.
|
|
18
|
+
//
|
|
19
|
+
// **The wake supervisor's mechanism, shared**: the loaded code is the import closure of the ship entry
|
|
20
|
+
// (`run-wake-code.ts`), and the successor's own claim on the ship record is the take-over's proof
|
|
21
|
+
// (`run-wake-takeover.ts`). A successor that dies or never claims leaves the record naming this
|
|
22
|
+
// supervisor, which runs the rest on the code it started with.
|
|
23
|
+
|
|
24
|
+
const ENTRY = fileURLToPath(new URL('run-ship-cli.ts', import.meta.url))
|
|
25
|
+
const ROOT = fileURLToPath(new URL('../../..', import.meta.url))
|
|
26
|
+
const HANDOVER_HEADER = '=== handover ==='
|
|
27
|
+
const SUCCESS_EXIT_CODE = 0
|
|
28
|
+
|
|
29
|
+
type CodeCheck = () => Promise<boolean>
|
|
30
|
+
|
|
31
|
+
async function never_stale(): Promise<boolean> {
|
|
32
|
+
return false
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Only a supervisor hands over: a ship in an agent's own turn ends with that turn, which reads the
|
|
36
|
+
// next command on the merged code anyway.
|
|
37
|
+
async function watch(): Promise<CodeCheck> {
|
|
38
|
+
if (!run_ship_detach.is_supervised()) return never_stale
|
|
39
|
+
|
|
40
|
+
return await run_wake_code.watch(run_wake_code.source_of(ROOT, ENTRY))
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function ports_of(repository: string, number: string): TakeoverPorts {
|
|
44
|
+
return {
|
|
45
|
+
holder_pid: () => run_ship_relaunch.holder_pid(repository, number),
|
|
46
|
+
is_alive: process_identity.is_live_pid,
|
|
47
|
+
stop: run_wake_stop.signal,
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Several lanes' supervisors hand over at once, so each note leads with its issue for `run:board`.
|
|
52
|
+
async function note(number: string, text: string): Promise<void> {
|
|
53
|
+
await run_event_stream_emit.emit(
|
|
54
|
+
run_event_stream.EVENT_KIND.NOTE,
|
|
55
|
+
`${issue_cite.plain(number)} ${text}`,
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function take_over(args: ShipArguments, repository: string): Promise<number | undefined> {
|
|
60
|
+
const pid = run_ship_relaunch.relaunch({ repository, number: args.number, cwd: process.cwd() })
|
|
61
|
+
if (pid === undefined) return undefined
|
|
62
|
+
const result = await run_wake_takeover.await_takeover(pid, ports_of(repository, args.number))
|
|
63
|
+
|
|
64
|
+
return result === 'taken' ? pid : undefined
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function handed_over(pid: number): ShipSection {
|
|
68
|
+
return {
|
|
69
|
+
header: HANDOVER_HEADER,
|
|
70
|
+
body: `code changed on main — process ${String(pid)} ships the rest on the new code`,
|
|
71
|
+
code: SUCCESS_EXIT_CODE,
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// The handover section where a successor took the ship over; `undefined` where the code is unchanged
|
|
76
|
+
// or no successor took it, and this supervisor runs the rest of the stages itself.
|
|
77
|
+
async function hand_over(
|
|
78
|
+
args: ShipArguments,
|
|
79
|
+
is_stale: CodeCheck,
|
|
80
|
+
): Promise<ShipSection | undefined> {
|
|
81
|
+
if (!(await is_stale())) return undefined
|
|
82
|
+
const repository = await run_ship_probe.repository_directory()
|
|
83
|
+
if (repository === undefined) return undefined
|
|
84
|
+
const pid = await take_over(args, repository)
|
|
85
|
+
|
|
86
|
+
if (pid === undefined) {
|
|
87
|
+
await note(
|
|
88
|
+
args.number,
|
|
89
|
+
`The ship supervisor's code changed on main, but no successor took the ship over, so process ${String(process.pid)} runs the rest on the code it started with.`,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
return undefined
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
await note(
|
|
96
|
+
args.number,
|
|
97
|
+
`The ship supervisor's code changed on main, so process ${String(process.pid)} handed the ship to process ${String(pid)} on the new code.`,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
return handed_over(pid)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const run_ship_handover = { hand_over, watch }
|
|
104
|
+
|
|
105
|
+
export type { CodeCheck }
|
|
106
|
+
export { run_ship_handover }
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { setTimeout as delay } from 'node:timers/promises'
|
|
2
|
+
import { RETRY_PENDING_KEY, RETRY_PENDING_VALUE } from '#scripts/gh/git-gh-comments-unreadable'
|
|
2
3
|
import type { ShipSection } from './run-ship'
|
|
3
4
|
import type { Stage } from './run-ship-stage'
|
|
4
5
|
import { run_ship_stop_cause } from './run-ship-stop-cause'
|
|
@@ -35,13 +36,27 @@ function is_retryable(stage: Stage, section: ShipSection): boolean {
|
|
|
35
36
|
return run_ship_stop_cause.cause_of(stage, section) === run_ship_stop_cause.CAUSE.INFRA
|
|
36
37
|
}
|
|
37
38
|
|
|
39
|
+
// An attempt with a retry still left runs with `RETRY_PENDING_KEY` set, so its stop sends no
|
|
40
|
+
// confirmation; the final attempt runs without it and sends the one confirmation.
|
|
41
|
+
async function run_attempt(attempt: Attempt, retries_left: number): Promise<ShipSection> {
|
|
42
|
+
if (retries_left === 0) return await attempt()
|
|
43
|
+
|
|
44
|
+
process.env[RETRY_PENDING_KEY] = RETRY_PENDING_VALUE
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
return await attempt()
|
|
48
|
+
} finally {
|
|
49
|
+
Reflect.deleteProperty(process.env, RETRY_PENDING_KEY)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
38
53
|
async function retried(
|
|
39
54
|
stage: Stage,
|
|
40
55
|
attempt: Attempt,
|
|
41
56
|
hooks: RetryHooks = DEFAULT_HOOKS,
|
|
42
57
|
retries_left = MAX_INFRA_RETRIES,
|
|
43
58
|
): Promise<ShipSection> {
|
|
44
|
-
const section = await attempt
|
|
59
|
+
const section = await run_attempt(attempt, retries_left)
|
|
45
60
|
|
|
46
61
|
if (retries_left === 0 || !is_retryable(stage, section)) return section
|
|
47
62
|
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks'
|
|
2
|
+
import type { ShipLapRecord } from '#scripts/lane/lane-ledger-schema'
|
|
3
|
+
import { lane_ledger_write } from '#scripts/lane/lane-ledger-write'
|
|
4
|
+
|
|
5
|
+
// The inner steps of a `josh ship` stage, each timed into the lane ledger as a lap, so `lane:breakdown`
|
|
6
|
+
// names what a stage spent its minutes on (joshuafolkken/kit#5294). The stage and the issue are held
|
|
7
|
+
// for the stage's whole run (`within`), so a step deep inside it — the scoped pair the preflight, the
|
|
8
|
+
// review rounds and the gate share — is timed without either being passed down to it. A step run
|
|
9
|
+
// outside a ship stage (the followup's own gate) has no stage to belong to and is not timed.
|
|
10
|
+
|
|
11
|
+
interface LapScope {
|
|
12
|
+
issue: number
|
|
13
|
+
stage: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
type LapSink = (lap: ShipLapRecord) => Promise<void>
|
|
17
|
+
|
|
18
|
+
// The names a lap is written under, read back by `lane:breakdown` and `lane:stats` as they are.
|
|
19
|
+
const STEP = {
|
|
20
|
+
PRECONDITIONS: 'preconditions',
|
|
21
|
+
SCOPED_PAIR: 'scoped pair',
|
|
22
|
+
GATE: 'josh gate',
|
|
23
|
+
OVERLAP_WAIT: 'overlap wait',
|
|
24
|
+
LOCAL_COMMIT: 'local commit',
|
|
25
|
+
MERGE: 'merge',
|
|
26
|
+
PUSH: 'push',
|
|
27
|
+
COMMIT: 'josh git',
|
|
28
|
+
} as const
|
|
29
|
+
|
|
30
|
+
const scope = new AsyncLocalStorage<LapScope>()
|
|
31
|
+
|
|
32
|
+
async function to_ledger(lap: ShipLapRecord): Promise<void> {
|
|
33
|
+
await lane_ledger_write.record_ship_lap(lap)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function within<T>(issue: string, stage: string, run: () => Promise<T>): Promise<T> {
|
|
37
|
+
return await scope.run({ issue: Number(issue), stage }, run)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// A step that threw still cost the stage its time, so it is timed either way; the append is
|
|
41
|
+
// best-effort (`lane-ledger-write.ts`), so it never replaces the step's own error.
|
|
42
|
+
async function timed<T>(
|
|
43
|
+
step: string,
|
|
44
|
+
run: () => Promise<T>,
|
|
45
|
+
sink: LapSink = to_ledger,
|
|
46
|
+
): Promise<T> {
|
|
47
|
+
const current = scope.getStore()
|
|
48
|
+
|
|
49
|
+
if (current === undefined) return await run()
|
|
50
|
+
|
|
51
|
+
const started_ms = performance.now()
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
return await run()
|
|
55
|
+
} finally {
|
|
56
|
+
await sink({ ...current, step, elapsed_ms: performance.now() - started_ms })
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const run_ship_lap = { STEP, timed, within }
|
|
61
|
+
|
|
62
|
+
export type { LapSink }
|
|
63
|
+
export { run_ship_lap }
|