@joshuafolkken/kit 1.1784.0 → 1.2114.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/reviewer-verification.md +19 -0
- package/.claude/agents/reviewer.md +19 -0
- package/.claude/settings.json +5 -6
- package/.claude/skills/dependency-update/SKILL.md +9 -10
- package/.claude/skills/workflow-commands/SKILL.md +6 -6
- package/.claude/skills/workflow-commands/background-commands.md +8 -5
- package/.claude/skills/workflow-commands/backlogrun-child.md +3 -1
- package/.claude/skills/workflow-commands/backlogrun-lanes.md +1 -1
- package/.claude/skills/workflow-commands/backlogrun-park.md +5 -2
- package/.claude/skills/workflow-commands/backlogrun-progress.md +2 -3
- package/.claude/skills/workflow-commands/backlogrun-recovery.md +1 -1
- package/.claude/skills/workflow-commands/backlogrun-steps.md +3 -2
- package/.claude/skills/workflow-commands/backlogrun.md +1 -1
- package/.claude/skills/workflow-commands/chain-rule.md +41 -32
- package/.claude/skills/workflow-commands/delegation.md +6 -6
- package/.claude/skills/workflow-commands/entry-sequence.md +2 -2
- package/.claude/skills/workflow-commands/followup.md +7 -5
- package/.claude/skills/workflow-commands/fullrun-steps.md +6 -6
- package/.claude/skills/workflow-commands/fullrun.md +1 -1
- package/.claude/skills/workflow-commands/issue-comments.md +9 -4
- package/.claude/skills/workflow-commands/issue-fold-existing.md +2 -1
- package/.claude/skills/workflow-commands/kickoff.md +2 -2
- package/.claude/skills/workflow-commands/observation-filing.md +1 -1
- package/.claude/skills/workflow-commands/observation-ledger.md +6 -4
- package/.claude/skills/workflow-commands/pre-gate-cut.md +9 -7
- package/.claude/skills/workflow-commands/prerequisite.md +3 -2
- package/.claude/skills/workflow-commands/retrospective.md +2 -2
- package/.claude/skills/workflow-commands/split-assessment.md +7 -5
- package/.codex/hooks.json +5 -5
- package/.github/actions/setup-pnpm/action.yml +9 -16
- package/.github/dependabot.yml +16 -0
- package/.github/workflows/auto-tag.yml +45 -0
- package/.github/workflows/ci.yml +155 -15
- package/.github/workflows/dependabot-auto-merge.yml +63 -4
- package/.github/workflows/production.yml +8 -0
- package/.github/workflows/publish.yml +59 -45
- package/.vscode/settings.json +19 -0
- package/CLAUDE.md +5 -12
- package/SECURITY.md +2 -2
- package/dist/CLAUDE.md +5 -12
- package/dist/commands/document-read-cli.js +2 -1
- package/dist/commands/document-section-main.js +2 -1
- package/dist/commands/read-set-cli.js +194 -134
- package/dist/commands/run-prep-main.js +9694 -10173
- package/dist/commands/run-step-cli.js +22138 -18285
- package/dist/hooks/audit-provision.js +23 -5
- package/dist/hooks/chunk-3GKE653K.js +6204 -0
- package/dist/hooks/chunk-45CJJOO7.js +1243 -0
- package/dist/hooks/{chunk-CWMBGKYW.js → chunk-5PM2JRGV.js} +2153 -856
- package/dist/hooks/{chunk-WR2KQAYZ.js → chunk-7SIUNQXK.js} +1207 -1470
- package/dist/hooks/{chunk-O2YBIDSI.js → chunk-CQD4LJE6.js} +1682 -1130
- package/dist/hooks/{chunk-VWWCFGWK.js → chunk-OPSRGWFU.js} +1 -1
- package/dist/hooks/{chunk-XGBNSWEI.js → chunk-UJ3FPMMM.js} +132 -49
- package/dist/hooks/chunk-VVNYJWEI.js +30 -0
- package/dist/hooks/chunk-Z6DQJKH3.js +2806 -0
- package/dist/hooks/codex-hook-adapter.js +8 -8
- package/dist/hooks/format-edited.js +4 -5
- package/dist/hooks/inputs.json +415 -389
- package/dist/hooks/pretool-guard.js +7 -6
- package/dist/hooks/session-lang.js +101 -258
- package/dist/hooks/stop-guard.js +1744 -2576
- package/dist/josh.js +7133 -6368
- package/dist/version/index.js +161 -1
- package/eslint/rules/comment-why-only.js +108 -0
- package/package.json +15 -8
- package/prompts/coding-standards.md +1 -1
- package/prompts/collaboration-workflow/file-edits.md +14 -11
- package/prompts/collaboration-workflow/issue-citation.md +0 -4
- package/prompts/collaboration-workflow/issue-template.md +40 -21
- package/prompts/collaboration-workflow/lane-instructions.md +3 -1
- package/prompts/collaboration-workflow/measurement.md +8 -1
- package/prompts/collaboration-workflow/operating-rules.md +11 -2
- package/prompts/collaboration-workflow/output-bounds.md +6 -2
- package/prompts/collaboration-workflow/plan-comment.md +1 -1
- package/prompts/collaboration-workflow/principles.md +9 -0
- package/prompts/collaboration-workflow/residency.md +3 -2
- package/prompts/collaboration-workflow/rule-delivery.md +13 -1
- package/prompts/collaboration-workflow/upstream-interrupt.md +2 -2
- package/prompts/collaboration-workflow/wip-cap.md +3 -1
- package/prompts/review-rubric.md +8 -0
- package/prompts/review.md +31 -22
- package/prompts/testing-guide.md +1 -0
- package/scripts/agent/agent-argv.ts +14 -16
- package/scripts/agent/agent-provider.ts +138 -0
- package/scripts/agent/agent-role-profile.ts +108 -156
- package/scripts/agent/agent-safe-text.ts +20 -5
- package/scripts/agent/api-usage-limit.ts +65 -0
- package/scripts/agent/claude-agent-argv.ts +19 -9
- package/scripts/agent/codex-agent-argv.ts +118 -22
- package/scripts/agent/usage-limit-reset.ts +179 -0
- package/scripts/auth/claude-token-output.ts +2 -2
- package/scripts/auto-ok/auto-ok-author.ts +53 -0
- package/scripts/auto-ok/auto-ok-cli.ts +20 -9
- package/scripts/backlog/backlog-defect-priority.ts +1 -1
- package/scripts/backlog/backlog-drive-cli.ts +6 -1
- package/scripts/backlog/backlog-drive-hold.ts +3 -3
- package/scripts/backlog/backlog-drive-idle.ts +10 -0
- package/scripts/backlog/backlog-drive-launch-pass.ts +90 -0
- package/scripts/backlog/backlog-drive-launch.ts +8 -2
- package/scripts/backlog/backlog-drive-named-offer.ts +73 -30
- package/scripts/backlog/backlog-drive-named.ts +28 -7
- package/scripts/backlog/backlog-drive-paused.ts +5 -4
- package/scripts/backlog/backlog-drive-restore.ts +11 -3
- package/scripts/backlog/backlog-drive.ts +21 -60
- package/scripts/backlog/backlog-gate-scope.ts +61 -0
- package/scripts/backlog/backlog-measure-close.ts +112 -0
- package/scripts/backlog/backlog-next.ts +39 -49
- package/scripts/backlog/backlog-occupied.ts +2 -2
- package/scripts/backlog/backlog-overlap.ts +42 -8
- package/scripts/backlog/backlog-plan-cli.ts +4 -1
- package/scripts/backlog/backlog-plan-comment.ts +81 -0
- package/scripts/backlog/backlog-plan-read.ts +19 -6
- package/scripts/backlog/backlog-pool.ts +50 -12
- package/scripts/backlog/backlog-rank.ts +60 -13
- package/scripts/backlog/backlog-stalled-detect.ts +2 -1
- package/scripts/backlog/backlog-waves.ts +17 -2
- package/scripts/backlog/backlogrun-launch.ts +7 -4
- package/scripts/cost-runtime/context-cut-payback.ts +27 -25
- package/scripts/cost-runtime/cost-cli.ts +37 -16
- package/scripts/cost-runtime/cost-pricing.ts +9 -0
- package/scripts/cost-runtime/cost-verdict.ts +4 -1
- package/scripts/delegation/delegation-policy.ts +2 -2
- package/scripts/delegation/duplicate-read-guard.ts +1 -0
- package/scripts/delegation/investigation-guard.ts +14 -2
- package/scripts/delegation/investigation-reads.ts +45 -23
- package/scripts/dependabot/dependabot-cooldown.ts +3 -2
- package/scripts/discovery/repo-party.ts +80 -20
- package/scripts/discovery/session-owner-pin.ts +51 -0
- package/scripts/document/capped-print.ts +1 -1
- package/scripts/document/command-reference-line-budget.ts +42 -0
- package/scripts/document/document-byte-budget.ts +17 -7
- package/scripts/document/document-checks.ts +20 -0
- package/scripts/document/document-ratchet-check.ts +101 -0
- package/scripts/document/document-section.ts +1 -0
- package/scripts/document/entry-read-budget.ts +7 -3
- package/scripts/document/issue-citation-budget.ts +94 -0
- package/scripts/epic/epic-cli-argv.ts +2 -2
- package/scripts/epic/epic-fetch.ts +4 -2
- package/scripts/epic/epic-graph.ts +7 -2
- package/scripts/epic/epic-issue.ts +3 -1
- package/scripts/epic/epic-rank.ts +5 -0
- package/scripts/exports/unused-members-check.ts +62 -0
- package/scripts/exports/unused-members-cli.ts +6 -51
- package/scripts/followup/followup-ci-path.ts +67 -0
- package/scripts/followup/followup-coderabbit-retrigger.ts +261 -0
- package/scripts/followup/followup-coderabbit-wait.ts +13 -10
- package/scripts/followup/followup-failed-tests.ts +160 -0
- package/scripts/followup/followup-job-needs.ts +100 -0
- package/scripts/followup/followup-job-rerun.ts +303 -0
- package/scripts/followup/followup-main-move.ts +113 -0
- package/scripts/followup/git-followup-finish.ts +43 -11
- package/scripts/followup/git-followup-pending.ts +3 -3
- package/scripts/followup/git-followup-stages.ts +41 -11
- package/scripts/followup/git-pr-followup-checks.ts +55 -16
- package/scripts/followup/git-pr-followup-wrapup.ts +24 -5
- package/scripts/followup/git-pr-followup.ts +62 -27
- package/scripts/fresh-machine/fresh-machine-script.ts +5 -9
- package/scripts/fresh-machine/specs/kit-test-backlogrun-python.json +2 -2
- package/scripts/fresh-machine/specs/kit-test-backlogrun.json +2 -2
- package/scripts/gate/busy-average.ts +34 -2
- package/scripts/gate/check-related-pinned.ts +43 -0
- package/scripts/gate/check-related-reuse.ts +64 -0
- package/scripts/gate/check-related-section.ts +57 -0
- package/scripts/gate/check-related-unplanned.ts +34 -0
- package/scripts/gate/check-related.ts +265 -0
- package/scripts/gate/command-memory.ts +1 -1
- package/scripts/gate/core-admission.ts +24 -6
- package/scripts/gate/core-budget-timing.ts +20 -6
- package/scripts/gate/core-budget.ts +40 -11
- package/scripts/gate/core-wait-record.ts +3 -2
- package/scripts/gate/core-wait.ts +25 -2
- package/scripts/gate/core-weights.ts +15 -7
- package/scripts/gate/gate-labels.ts +46 -0
- package/scripts/gate/gate-ledger.ts +14 -6
- package/scripts/gate/gate-plan.ts +103 -58
- package/scripts/gate/gate-report.ts +9 -7
- package/scripts/gate/gate-run-steps.ts +26 -3
- package/scripts/gate/gate-skip.ts +45 -6
- package/scripts/gate/gate-static-group.ts +60 -0
- package/scripts/gate/gate-steps.ts +2 -1
- package/scripts/gate/gate-tree.ts +4 -2
- package/scripts/gate/hook-gate-reuse.ts +19 -2
- package/scripts/gate/metrics-totals.ts +59 -0
- package/scripts/gate/scoped-green.ts +68 -15
- package/scripts/gate/since-green.ts +14 -6
- package/scripts/gate/structural-checks.ts +96 -0
- package/scripts/gate/verification-gate.ts +51 -16
- package/scripts/gate/verification-inputs.ts +21 -6
- package/scripts/gate/verification-tail.ts +52 -0
- package/scripts/gh/gh-author-association.ts +23 -2
- package/scripts/gh/git-ai-review-scan.ts +1 -1
- package/scripts/gh/git-gh-api-path.ts +12 -3
- package/scripts/gh/git-gh-comments-unreadable.ts +36 -0
- package/scripts/gh/git-gh-exec.ts +32 -2
- package/scripts/gh/git-gh-issue-read.ts +4 -2
- package/scripts/gh/git-gh-issue-rest.ts +1 -0
- package/scripts/gh/git-gh-issue-write.ts +8 -2
- package/scripts/gh/git-gh-issue.ts +12 -5
- package/scripts/gh/git-gh-pr-auto-merge.ts +13 -6
- package/scripts/gh/git-gh-pr-graphql-state.ts +56 -0
- package/scripts/gh/git-gh-pr-read.ts +74 -13
- package/scripts/gh/git-gh-pr-rest.ts +3 -1
- package/scripts/gh/git-gh-pr-snapshot.ts +22 -7
- package/scripts/gh/git-gh-pr-too-large.ts +20 -0
- package/scripts/gh/git-gh-pr.ts +21 -7
- package/scripts/gh/git-gh-retry.ts +141 -0
- package/scripts/gh/git-pr-ai-review.ts +15 -6
- package/scripts/gh/git-pr-checks-eval.ts +3 -0
- package/scripts/gh/git-pr-checks.ts +5 -5
- package/scripts/git/base-tree.ts +30 -0
- package/scripts/git/change-base.ts +4 -10
- package/scripts/git/changed-paths-sync.ts +63 -0
- package/scripts/git/changed-paths.ts +16 -1
- package/scripts/git/git-common-directory.ts +11 -1
- package/scripts/git/git-diff-reads.ts +66 -20
- package/scripts/git/git-error.ts +9 -2
- package/scripts/git/git-schemas.ts +13 -0
- package/scripts/git/git-worktree.ts +13 -0
- package/scripts/git/gone-branch.ts +4 -1
- package/scripts/git/main-merge-budget-conflict.ts +89 -0
- package/scripts/git/main-merge-guard.ts +55 -18
- package/scripts/git/main-merge-regenerate.ts +59 -25
- package/scripts/git/main-merge.ts +53 -5
- package/scripts/git/no-base-checkout.ts +127 -0
- package/scripts/git/stash/git-stash.ts +11 -2
- package/scripts/git/stash/stash-push-cli.ts +10 -0
- package/scripts/hooks/batch-guard.ts +40 -21
- package/scripts/hooks/edited-cspell.ts +37 -11
- package/scripts/hooks/format-edited-file.ts +22 -2
- package/scripts/hooks/lane-plan-guard.ts +50 -0
- package/scripts/hooks/pre-commit-lint-switch.ts +9 -0
- package/scripts/hooks/pre-commit-lint.ts +14 -1
- package/scripts/hooks/pre-push-related-switch.ts +10 -0
- package/scripts/hooks/pre-push-unit.ts +76 -10
- package/scripts/hooks/pretool-guard.ts +2 -0
- package/scripts/hooks/reserved-run.ts +14 -1
- package/scripts/hooks/run-hook.sh +23 -8
- package/scripts/hooks/step-zero-notice.ts +6 -1
- package/scripts/hooks/stop-actions.ts +3 -15
- package/scripts/hooks/stop-guard.ts +7 -6
- package/scripts/init/distributed-paths.ts +1 -0
- package/scripts/init/hook-command-rewrite.ts +5 -1
- package/scripts/init/hook-launch.ts +4 -2
- package/scripts/issue/aggregation-split.ts +52 -0
- package/scripts/issue/defect-origin-line.ts +19 -1
- package/scripts/issue/defect-rate-cli.ts +5 -102
- package/scripts/issue/defect-report.ts +4 -4
- package/scripts/issue/effect-audit-cli.ts +178 -0
- package/scripts/issue/effect-audit.ts +185 -0
- package/scripts/issue/expected-effect-lint.ts +64 -9
- package/scripts/issue/git-next-issues.ts +5 -0
- package/scripts/issue/issue-body-or-comment.ts +38 -4
- package/scripts/issue/issue-cite-cli.ts +1 -3
- package/scripts/issue/issue-classification.ts +1 -0
- package/scripts/issue/issue-closing-pr.ts +8 -1
- package/scripts/issue/issue-evidence-exit.ts +4 -2
- package/scripts/issue/issue-file-cap.ts +58 -0
- package/scripts/issue/issue-file-cli.ts +111 -38
- package/scripts/issue/issue-file-deferral.ts +52 -0
- package/scripts/issue/issue-file-fold.ts +29 -10
- package/scripts/issue/issue-file-interrupt.ts +85 -0
- package/scripts/issue/issue-file-lane-hint.ts +30 -0
- package/scripts/issue/issue-file.ts +43 -6
- package/scripts/issue/issue-labels.ts +19 -2
- package/scripts/issue/issue-lint-cli.ts +27 -2
- package/scripts/issue/issue-measured-cli.ts +13 -35
- package/scripts/issue/issue-measured-close.ts +58 -0
- package/scripts/issue/issue-not-before-label.ts +2 -2
- package/scripts/issue/issue-not-before.ts +4 -1
- package/scripts/issue/issue-priority-cli.ts +60 -0
- package/scripts/issue/issue-priority-raise.ts +55 -0
- package/scripts/issue/issue-priority.ts +174 -43
- package/scripts/issue/issue-rank.ts +21 -4
- package/scripts/issue/issue-read-cli.ts +32 -6
- package/scripts/issue/issue-read.ts +37 -12
- package/scripts/issue/issue-sample-gate.ts +95 -74
- package/scripts/issue/issue-sample-prime.ts +127 -0
- package/scripts/issue/issue-sample-required.ts +57 -0
- package/scripts/issue/issue-sample-source.ts +12 -11
- package/scripts/issue/issue-search.ts +124 -0
- package/scripts/issue/issue-state.ts +13 -1
- package/scripts/issue/issue-template-section.ts +43 -0
- package/scripts/issue/issue-watch-diff.ts +31 -1
- package/scripts/issue/issue-watch-hook.ts +11 -2
- package/scripts/issue/issue-watch.ts +55 -12
- package/scripts/issue/markdown-section.ts +1 -0
- package/scripts/issue/measure-declaration.ts +121 -0
- package/scripts/issue/measure-rerun-cli.ts +7 -70
- package/scripts/issue/plan-consumers-section.ts +22 -1
- package/scripts/issue/reproduction-measure.ts +3 -1
- package/scripts/issue/size-estimate.ts +90 -0
- package/scripts/issue/trusted-measure.ts +84 -0
- package/scripts/josh/command-usage.ts +3 -2
- package/scripts/josh/durable-state-migrate.ts +105 -0
- package/scripts/josh/durable-state.ts +112 -0
- package/scripts/josh/josh-aliases.ts +95 -0
- package/scripts/josh/josh-command-map.ts +1 -82
- package/scripts/josh/josh-commands-agent-hooks.ts +6 -6
- package/scripts/josh/josh-commands-ai.ts +5 -5
- package/scripts/josh/josh-commands-development.ts +59 -58
- package/scripts/josh/josh-commands-issue-write.ts +23 -4
- package/scripts/josh/josh-commands-issue.ts +32 -0
- package/scripts/josh/josh-commands-lane.ts +87 -4
- package/scripts/josh/josh-commands-lint.ts +16 -3
- package/scripts/josh/josh-commands-maintenance.ts +15 -0
- package/scripts/josh/josh-commands-review.ts +41 -6
- package/scripts/josh/josh-commands-ship.ts +56 -8
- package/scripts/josh/josh-commands-test-check.ts +80 -0
- package/scripts/josh/josh-commands-workflow.ts +1 -1
- package/scripts/josh/josh-environment-file.ts +43 -3
- package/scripts/josh/josh-in-process.ts +2 -2
- package/scripts/josh/josh-logic.ts +5 -3
- package/scripts/josh/josh-run.ts +19 -1
- package/scripts/josh/run-record-path.ts +15 -0
- package/scripts/josh/stamp-file.ts +11 -2
- package/scripts/lane/lane-adopt-cli.ts +98 -0
- package/scripts/lane/lane-adopt.ts +208 -0
- package/scripts/lane/lane-await.ts +5 -8
- package/scripts/lane/lane-baseline.ts +123 -0
- package/scripts/lane/lane-breakdown-cli.ts +64 -0
- package/scripts/lane/lane-breakdown-implement.ts +170 -0
- package/scripts/lane/lane-breakdown-laps.ts +107 -0
- package/scripts/lane/lane-breakdown-pinned.ts +76 -0
- package/scripts/lane/lane-breakdown-text.ts +145 -0
- package/scripts/lane/lane-breakdown.ts +239 -0
- package/scripts/lane/lane-check-stats.ts +29 -8
- package/scripts/lane/lane-child-invocation.ts +9 -2
- package/scripts/lane/lane-child-mark-keys.ts +12 -0
- package/scripts/lane/lane-child-marker.ts +20 -1
- package/scripts/lane/lane-ci-path-stats.ts +73 -0
- package/scripts/lane/lane-claim-stats.ts +84 -0
- package/scripts/lane/lane-close.ts +8 -3
- package/scripts/lane/lane-dispatch-log.ts +3 -3
- package/scripts/lane/lane-dispatch.ts +2 -2
- package/scripts/lane/lane-gap-stats.ts +7 -6
- package/scripts/lane/lane-guard-policy.ts +7 -1
- package/scripts/lane/lane-implement-stats.ts +207 -0
- package/scripts/lane/lane-implement-subagents.ts +90 -0
- package/scripts/lane/lane-investigation-switch.ts +16 -0
- package/scripts/lane/lane-ledger-kind.ts +31 -0
- package/scripts/lane/lane-ledger-schema-ship.ts +49 -0
- package/scripts/lane/lane-ledger-schema.ts +119 -36
- package/scripts/lane/lane-ledger-write.ts +257 -0
- package/scripts/lane/lane-ledger.ts +31 -177
- package/scripts/lane/lane-load.ts +1 -1
- package/scripts/lane/lane-measure-cli.ts +176 -59
- package/scripts/lane/lane-net-read.ts +44 -0
- package/scripts/lane/lane-net-time.ts +212 -0
- package/scripts/lane/lane-open.ts +16 -7
- package/scripts/lane/lane-output.ts +2 -4
- package/scripts/lane/lane-overrun-prompt.ts +147 -0
- package/scripts/lane/lane-overrun.ts +274 -0
- package/scripts/lane/lane-paths.ts +24 -1
- package/scripts/lane/lane-pause-cli.ts +4 -1
- package/scripts/lane/lane-paused-spans.ts +97 -0
- package/scripts/lane/lane-plan-check.ts +207 -0
- package/scripts/lane/lane-plan-cli.ts +41 -0
- package/scripts/lane/lane-plan.ts +144 -0
- package/scripts/lane/lane-registry.ts +14 -1
- package/scripts/lane/lane-relaunch.ts +1 -1
- package/scripts/lane/lane-round-one-stats.ts +51 -0
- package/scripts/lane/lane-sampler.ts +23 -4
- package/scripts/lane/lane-session-action.ts +93 -18
- package/scripts/lane/lane-session-broker.ts +49 -21
- package/scripts/lane/lane-session-reread-main.ts +14 -0
- package/scripts/lane/lane-session-reread.ts +51 -0
- package/scripts/lane/lane-ship-lap-stats.ts +74 -0
- package/scripts/lane/lane-sleep.ts +58 -0
- package/scripts/lane/lane-spent.ts +1 -1
- package/scripts/lane/lane-split-stats.ts +28 -0
- package/scripts/lane/lane-stage-stats.ts +13 -1
- package/scripts/lane/lane-state.ts +41 -9
- package/scripts/lane/lane-stats-tables.ts +58 -0
- package/scripts/lane/lane-stats.ts +21 -5
- package/scripts/lane/lane-stop-stats.ts +51 -19
- package/scripts/lane/lane-tail-stats.ts +32 -0
- package/scripts/lane/lane-transcript-calls.ts +67 -10
- package/scripts/lane/lane-transcript-stats.ts +44 -12
- package/scripts/lane/lane-value-cell.ts +72 -0
- package/scripts/lane/lane-value.ts +118 -0
- package/scripts/lane/lane-withdraw-closed.ts +124 -0
- package/scripts/lane/lane-withdraw.ts +108 -31
- package/scripts/lane/lane-yield.ts +85 -0
- package/scripts/lane/openai-lane-ship.ts +12 -11
- package/scripts/lane/openai-lane-supervisor-decision.ts +6 -8
- package/scripts/lane/openai-lane-supervisor-owner.ts +5 -8
- package/scripts/lane/openai-lane-supervisor.ts +5 -4
- package/scripts/lib/poll.ts +38 -9
- package/scripts/lib/settled-together.ts +10 -0
- package/scripts/lib/shell-quote.ts +21 -0
- package/scripts/lib/token-shape.ts +111 -0
- package/scripts/lint/eslint-daemon-sources.ts +79 -0
- package/scripts/lint/eslint-daemon.ts +45 -6
- package/scripts/lint/eslint-warm-cli.ts +7 -0
- package/scripts/lint/eslint-warm.ts +66 -0
- package/scripts/lint/import-graph.ts +141 -11
- package/scripts/lint/lint-gate-scope.ts +2 -2
- package/scripts/lint/lint-parallel.ts +54 -6
- package/scripts/lint/lint-related.ts +154 -33
- package/scripts/lint/rename-cli.ts +179 -0
- package/scripts/lint/rename-identifier.ts +192 -0
- package/scripts/lint/type-only-imports.ts +58 -0
- package/scripts/notify/telegram-notify.ts +12 -3
- package/scripts/observations/observation-record.ts +42 -16
- package/scripts/observations/observations-flush.ts +32 -9
- package/scripts/overrides/overrides-check.ts +9 -1
- package/scripts/release/release-approval-prune.ts +7 -1
- package/scripts/repo/required-checks-logic.ts +4 -1
- package/scripts/repo/ruleset-check.ts +4 -3
- package/scripts/report/markdown-shape.ts +28 -0
- package/scripts/report/report-format-reference.ts +15 -1
- package/scripts/report/report-labels.ts +12 -1
- package/scripts/report/report-lint-child-summary.ts +94 -0
- package/scripts/report/report-lint-cli.ts +26 -7
- package/scripts/report/report-lint.ts +2 -20
- package/scripts/review/prose-stale-cli.ts +88 -0
- package/scripts/review/prose-stale-scan.ts +152 -0
- package/scripts/review/review-attest.ts +73 -23
- package/scripts/review/review-brief-cli.ts +68 -19
- package/scripts/review/review-brief-paths.ts +22 -0
- package/scripts/review/review-brief.ts +14 -7
- package/scripts/review/review-comment-carry.ts +47 -0
- package/scripts/review/review-comment-round.ts +85 -22
- package/scripts/review/review-finding-ledger.ts +109 -7
- package/scripts/review/review-finding-text.ts +43 -0
- package/scripts/review/review-interaction.ts +11 -0
- package/scripts/review/review-lane-handover.ts +68 -0
- package/scripts/review/review-lint-cli.ts +57 -0
- package/scripts/review/review-lint-findings.ts +92 -0
- package/scripts/review/review-lint-sections.ts +80 -0
- package/scripts/review/review-lint.ts +221 -0
- package/scripts/review/review-prior-findings.ts +102 -0
- package/scripts/review/review-readers-scan.ts +4 -2
- package/scripts/review/review-record-cli.ts +177 -54
- package/scripts/review/review-record-code-round.ts +55 -0
- package/scripts/review/review-record-comment.ts +60 -0
- package/scripts/review/review-record-interaction.ts +35 -0
- package/scripts/review/review-record-pinned.ts +108 -0
- package/scripts/review/review-record.ts +25 -1
- package/scripts/review/review-reviewed-tree.ts +307 -0
- package/scripts/review/review-round-one-closure.ts +62 -0
- package/scripts/review/review-round-reuse.ts +106 -0
- package/scripts/review/review-round2-cli.ts +91 -29
- package/scripts/review/review-round2-skip-comment.ts +55 -0
- package/scripts/review/review-round2.ts +24 -8
- package/scripts/review/review-stamps.ts +7 -3
- package/scripts/review/review-stop-log.ts +20 -6
- package/scripts/review/review-stops-cli.ts +2 -1
- package/scripts/review/review-submit-cli.ts +101 -0
- package/scripts/rules/agent-model.ts +1 -1
- package/scripts/rules/bash-triggers.ts +3 -3
- package/scripts/rules/concise-reply.ts +88 -0
- package/scripts/rules/credential-body.ts +77 -0
- package/scripts/rules/decision-oracle.ts +1 -1
- package/scripts/rules/delivered-rules.ts +36 -17
- package/scripts/rules/destructive-command.ts +3 -11
- package/scripts/rules/direct-issue-comment.ts +34 -12
- package/scripts/rules/direct-issue-read.ts +191 -0
- package/scripts/rules/direct-pr-create.ts +4 -24
- package/scripts/rules/early-heartbeat.ts +2 -0
- package/scripts/rules/edit-tool.ts +27 -0
- package/scripts/rules/file-edit-rows.ts +17 -0
- package/scripts/rules/file-rewrite.ts +146 -0
- package/scripts/rules/firing-point.ts +3 -2
- package/scripts/rules/gh-api.ts +128 -7
- package/scripts/rules/gh-repo-selector.ts +84 -0
- package/scripts/rules/git-force.ts +2 -2
- package/scripts/rules/guard-remedy.ts +14 -5
- package/scripts/rules/implementation-cut.ts +61 -28
- package/scripts/rules/investigator-foreground.ts +231 -0
- package/scripts/rules/issue-citation.ts +15 -60
- package/scripts/rules/issue-comments.ts +9 -4
- package/scripts/rules/josh-git-bare.ts +1 -1
- package/scripts/rules/lane-background.ts +41 -13
- package/scripts/rules/lane-direct-tool.ts +107 -9
- package/scripts/rules/lane-interactive-ask.ts +4 -1
- package/scripts/rules/lane-park.ts +4 -2
- package/scripts/rules/lane-spilled-read.ts +90 -0
- package/scripts/rules/lane-split-park.ts +1 -1
- package/scripts/rules/lane-switch-main.ts +4 -4
- package/scripts/rules/last-prompt.ts +20 -47
- package/scripts/rules/oracle-consulted.ts +1 -1
- package/scripts/rules/permission-guards.ts +5 -1
- package/scripts/rules/piped-verification-shapes.ts +110 -0
- package/scripts/rules/piped-verification.ts +67 -17
- package/scripts/rules/poll-loop.ts +72 -9
- package/scripts/rules/pr-merge.ts +5 -5
- package/scripts/rules/pre-gate-cut.ts +3 -3
- package/scripts/rules/protected-files.ts +88 -24
- package/scripts/rules/reply-language.ts +3 -17
- package/scripts/rules/reply-prose.ts +34 -0
- package/scripts/rules/repo-admin.ts +132 -0
- package/scripts/rules/reviewer-foreground.ts +88 -0
- package/scripts/rules/round-one-check-related.ts +120 -0
- package/scripts/rules/rule-body-guard.ts +5 -15
- package/scripts/rules/rule-value-cache.ts +53 -5
- package/scripts/rules/rule-value-candidates.ts +84 -0
- package/scripts/rules/rule-value-cli.ts +59 -11
- package/scripts/rules/rule-value.ts +17 -4
- package/scripts/rules/run-tail-rule.ts +1 -1
- package/scripts/rules/sed-in-place.ts +196 -0
- package/scripts/rules/shell-segments.ts +10 -2
- package/scripts/rules/stop-rule-rows.ts +1 -13
- package/scripts/rules/stop-rules.ts +33 -58
- package/scripts/rules/test-declared-commit.ts +1 -1
- package/scripts/rules/third-party-write.ts +110 -23
- package/scripts/rules/timed-rerun.ts +1 -1
- package/scripts/rules/turn-filings.ts +90 -0
- package/scripts/rules/worktree-guard.ts +22 -7
- package/scripts/run/board/run-board-ending-reason.ts +6 -2
- package/scripts/run/board/run-board-fit.ts +24 -1
- package/scripts/run/board/run-board-found.ts +134 -0
- package/scripts/run/board/run-board-header.ts +8 -0
- package/scripts/run/board/run-board-labels.ts +11 -1
- package/scripts/run/board/run-board-lane-time.ts +1 -0
- package/scripts/run/board/run-board-link.ts +15 -2
- package/scripts/run/board/run-board-notes.ts +7 -1
- package/scripts/run/board/run-board-operation.ts +4 -2
- package/scripts/run/board/run-board-phase.ts +2 -5
- package/scripts/run/board/run-board-plan.ts +1 -1
- package/scripts/run/board/run-board-read.ts +46 -1
- package/scripts/run/board/run-board-reason.ts +20 -8
- package/scripts/run/board/run-board-render-checks.ts +3 -2
- package/scripts/run/board/run-board-render-drawn.ts +11 -0
- package/scripts/run/board/run-board-render-found.ts +157 -0
- package/scripts/run/board/run-board-render-lead.ts +9 -0
- package/scripts/run/board/run-board-render-legend.ts +19 -0
- package/scripts/run/board/run-board-render-tail.ts +1 -1
- package/scripts/run/board/run-board-render.ts +82 -18
- package/scripts/run/board/run-board-spin.ts +1 -3
- package/scripts/run/board/run-board-status.ts +2 -0
- package/scripts/run/board/run-board-tick.ts +39 -10
- package/scripts/run/carry/run-carry-ended.ts +3 -2
- package/scripts/run/carry/run-carry.ts +3 -2
- package/scripts/run/cut/run-cut-cli.ts +33 -133
- package/scripts/run/cut/run-cut-digest.ts +152 -0
- package/scripts/run/cut/run-cut-handoff.ts +52 -8
- package/scripts/run/cut/run-cut-report.ts +24 -3
- package/scripts/run/cut/run-cut-resume.ts +129 -0
- package/scripts/run/cut/run-cut-review.ts +105 -0
- package/scripts/run/cut/run-cut.ts +18 -7
- package/scripts/run/detached-launch.ts +1 -1
- package/scripts/run/entry/run-entry-cli.ts +88 -19
- package/scripts/run/entry/run-entry-spill.ts +83 -0
- package/scripts/run/entry/run-entry-stop.ts +5 -1
- package/scripts/run/entry/run-entry-trust.ts +91 -0
- package/scripts/run/event/run-event-baseline.ts +56 -0
- package/scripts/run/event/run-event-filed.ts +9 -3
- package/scripts/run/event/run-event-overrun.ts +197 -0
- package/scripts/run/event/run-event-render.ts +4 -0
- package/scripts/run/event/run-event-stream.ts +25 -3
- package/scripts/run/hold/run-stop-notify.ts +3 -8
- package/scripts/run/merge/run-merge-cap.ts +57 -0
- package/scripts/run/merge/run-merge-cli.ts +66 -23
- package/scripts/run/merge/run-merge-outcome.ts +2 -0
- package/scripts/run/merge/run-merge-ship.ts +13 -3
- package/scripts/run/merge/run-merge-signals.ts +40 -23
- package/scripts/run/merge/run-merge-steps.ts +56 -36
- package/scripts/run/merge/run-merge-usage-limit.ts +53 -0
- package/scripts/run/merge/run-merge-withdrawn.ts +53 -0
- package/scripts/run/merge/run-merge.ts +41 -14
- package/scripts/run/review/run-review-cli.ts +306 -20
- package/scripts/run/review/run-review-early-push.ts +121 -0
- package/scripts/run/review/run-review-join-read.ts +94 -0
- package/scripts/run/review/run-review-pinned-accepted.ts +126 -0
- package/scripts/run/review/run-review-pinned-join.ts +216 -0
- package/scripts/run/review/run-review-pinned-steps.ts +383 -0
- package/scripts/run/review/run-review-pinned-tree.ts +37 -0
- package/scripts/run/review/run-review-pinned.ts +53 -0
- package/scripts/run/review/run-review-steps.ts +70 -34
- package/scripts/run/review/run-review.ts +26 -6
- package/scripts/run/run-parent-cut-hook.ts +3 -4
- package/scripts/run/run-prep.ts +1 -0
- package/scripts/run/run-stage-read.ts +2 -6
- package/scripts/run/run-step-cli.ts +17 -5
- package/scripts/run/run-step-lane-plan.ts +27 -0
- package/scripts/run/run-step-section.ts +26 -7
- package/scripts/run/run-step.ts +5 -2
- package/scripts/run/ship/run-ship-args.ts +19 -0
- package/scripts/run/ship/run-ship-brokered-review.ts +106 -0
- package/scripts/run/ship/run-ship-cli.ts +131 -39
- package/scripts/run/ship/run-ship-conflict-probe.ts +59 -0
- package/scripts/run/ship/run-ship-detach.ts +10 -4
- package/scripts/run/ship/run-ship-handover.ts +106 -0
- package/scripts/run/ship/run-ship-infra-retry.ts +16 -1
- package/scripts/run/ship/run-ship-lap.ts +63 -0
- package/scripts/run/ship/run-ship-next.ts +27 -26
- package/scripts/run/ship/run-ship-overlap.ts +8 -3
- package/scripts/run/ship/run-ship-place.ts +9 -2
- package/scripts/run/ship/run-ship-planned.ts +92 -0
- package/scripts/run/ship/run-ship-pre-detach-pinned.ts +197 -0
- package/scripts/run/ship/run-ship-pre-detach-timed.ts +7 -8
- package/scripts/run/ship/run-ship-pre-detach.ts +77 -23
- package/scripts/run/ship/run-ship-preflight.ts +16 -4
- package/scripts/run/ship/run-ship-probe.ts +23 -9
- package/scripts/run/ship/run-ship-relaunch-cap.ts +43 -7
- package/scripts/run/ship/run-ship-relaunch.ts +51 -0
- package/scripts/run/ship/run-ship-return.ts +103 -29
- package/scripts/run/ship/run-ship-review-reason.ts +24 -0
- package/scripts/run/ship/run-ship-review-steps.ts +230 -59
- package/scripts/run/ship/run-ship-review.ts +171 -51
- package/scripts/run/ship/run-ship-reviewer.ts +138 -42
- package/scripts/run/ship/run-ship-scoped.ts +39 -10
- package/scripts/run/ship/run-ship-stage.ts +49 -13
- package/scripts/run/ship/run-ship-steps.ts +24 -4
- package/scripts/run/ship/run-ship-stop-cause.ts +43 -2
- package/scripts/run/ship/run-ship-stop-context.ts +50 -13
- package/scripts/run/ship/run-ship-sync.ts +171 -30
- package/scripts/run/ship/run-ship-synced-scope.ts +178 -0
- package/scripts/run/ship/run-ship-wait-cli.ts +145 -0
- package/scripts/run/ship/run-ship-waiter.ts +114 -0
- package/scripts/run/ship/run-ship.ts +16 -2
- package/scripts/run/wake/run-wake-caffeinate.ts +48 -0
- package/scripts/run/wake/run-wake-cli.ts +6 -113
- package/scripts/run/wake/run-wake-code.ts +53 -11
- package/scripts/run/wake/run-wake-driver.ts +5 -3
- package/scripts/run/wake/run-wake-finish.ts +137 -0
- package/scripts/run/wake/run-wake-loop.ts +5 -3
- package/scripts/run/wake/run-wake-ports.ts +11 -3
- package/scripts/run/wake/run-wake-session.ts +2 -0
- package/scripts/run/wake/run-wake.ts +3 -2
- package/scripts/safe-chain/ci-installer-pin.ts +49 -8
- package/scripts/safe-chain/project-config.ts +3 -2
- package/scripts/security/secretlint-scan.ts +42 -9
- package/scripts/security/security-audit-provision-main.ts +9 -1
- package/scripts/security/security-audit-provision.ts +1 -1
- package/scripts/security/security-audit.ts +21 -1
- package/scripts/security/sonar-file.ts +10 -5
- package/scripts/split/split-assess.ts +12 -3
- package/scripts/split/split-early-notice.ts +116 -0
- package/scripts/split/split-measure.ts +20 -2
- package/scripts/split/split-resolution.ts +107 -0
- package/scripts/test/direct-importers.ts +185 -0
- package/scripts/test/pure-files-entries.ts +83 -0
- package/scripts/test/related-heavy-tests.ts +81 -0
- package/scripts/test/test-no-base.ts +88 -0
- package/scripts/test/test-pinned-cache-logic.ts +363 -0
- package/scripts/test/test-pinned-cache.ts +337 -0
- package/scripts/test/test-pinned-emit.ts +49 -0
- package/scripts/test/test-pinned-functions.ts +116 -0
- package/scripts/test/test-pinned-ledger.ts +80 -0
- package/scripts/test/test-pinned-logic.ts +208 -20
- package/scripts/test/test-pinned-main.ts +84 -18
- package/scripts/test/test-pinned-pool.ts +73 -0
- package/scripts/test/test-pinned-probe.ts +254 -0
- package/scripts/test/test-pinned-prune-logic.ts +118 -0
- package/scripts/test/test-pinned-reach.ts +194 -0
- package/scripts/test/test-pinned-record.ts +196 -0
- package/scripts/test/test-pinned-rewire.ts +148 -0
- package/scripts/test/test-pinned-spawn.ts +81 -0
- package/scripts/test/test-pinned-stage.ts +70 -0
- package/scripts/test/test-pinned.ts +258 -47
- package/scripts/test/test-reach-cli.ts +61 -0
- package/scripts/test/test-read-map.ts +35 -11
- package/scripts/test/test-read-recording.ts +17 -5
- package/scripts/test/test-read-trace.ts +26 -8
- package/scripts/test/test-red-logic.ts +46 -7
- package/scripts/test/test-red.ts +34 -14
- package/scripts/test/test-related-claim.ts +37 -0
- package/scripts/test/test-related-main.ts +4 -1
- package/scripts/test/test-related-moved.ts +91 -0
- package/scripts/test/test-related-record.ts +43 -23
- package/scripts/test/test-related-scope.ts +99 -34
- package/scripts/test/test-related-synced.ts +135 -0
- package/scripts/test/test-related-touched.ts +84 -0
- package/scripts/test/test-related.ts +167 -83
- package/scripts/test/test-unit-guard.ts +28 -5
- package/scripts/test/unit-durations.ts +41 -0
- package/scripts/test/unit-worker-share.ts +5 -4
- package/scripts/test/vitest-cache-directory.ts +19 -0
- package/scripts/test/vitest-cli-excludes.ts +14 -0
- package/scripts/test/vitest-failure-summary.ts +111 -0
- package/scripts/test/whole-suite-files.ts +12 -1
- package/scripts/time-runtime/time-batch-guard.ts +42 -4
- package/scripts/time-runtime/time-bundle-call.ts +1 -1
- package/scripts/time-runtime/time-bundles.ts +36 -5
- package/scripts/time-runtime/time-markers.ts +2 -2
- package/scripts/time-runtime/time-search-call.ts +38 -0
- package/scripts/time-runtime/time-shell.ts +1 -1
- package/scripts/time-runtime/time-transcript-line.ts +17 -5
- package/scripts/version/development-engines-verdict.ts +124 -0
- package/scripts/version/latest-corepack.ts +2 -0
- package/templates/gitignore +2 -0
- package/templates/workflows/ci.yml +41 -0
- package/dist/hooks/chunk-AZX4FGQ3.js +0 -207
- package/dist/hooks/chunk-PT5R6UJD.js +0 -7131
- package/dist/hooks/chunk-TUIFS5E7.js +0 -72
- package/dist/hooks/chunk-YCDOIR3I.js +0 -3456
- package/scripts/cost-runtime/context-cut-threshold.ts +0 -11
- package/scripts/rules/filing-cap.ts +0 -139
|
@@ -1,18 +1,25 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
|
-
import { readFile
|
|
3
|
-
import path from 'node:path'
|
|
4
|
-
import { base_tree, type BaseTree } from '#scripts/git/base-tree'
|
|
2
|
+
import { readFile } from 'node:fs/promises'
|
|
5
3
|
import { change_base } from '#scripts/git/change-base'
|
|
6
4
|
import { changed_paths } from '#scripts/git/changed-paths'
|
|
7
5
|
import { git_spawn } from '#scripts/git/git-spawn'
|
|
6
|
+
import { review_code_tree } from '#scripts/review/review-code-tree'
|
|
7
|
+
import { test_pinned_cache, type LoadedCache, type Reached } from './test-pinned-cache'
|
|
8
|
+
import { test_pinned_cache_logic, type Known, type Recheck } from './test-pinned-cache-logic'
|
|
9
|
+
import { test_pinned_emit } from './test-pinned-emit'
|
|
10
|
+
import { test_pinned_functions } from './test-pinned-functions'
|
|
11
|
+
import type { PinnedOrigin } from './test-pinned-ledger'
|
|
8
12
|
import {
|
|
9
13
|
test_pinned_logic,
|
|
10
14
|
type Hunk,
|
|
15
|
+
type HunkOutcome,
|
|
11
16
|
type PinnedReport,
|
|
12
|
-
type UnpinnedHunk,
|
|
13
17
|
} from './test-pinned-logic'
|
|
18
|
+
import { test_pinned_probe, type CheckOptions, type Probe } from './test-pinned-probe'
|
|
19
|
+
import { test_pinned_reach, type Reach } from './test-pinned-reach'
|
|
20
|
+
import type { Staged } from './test-pinned-stage'
|
|
14
21
|
import { test_red } from './test-red'
|
|
15
|
-
import type {
|
|
22
|
+
import type { RedProbe } from './test-red-logic'
|
|
16
23
|
|
|
17
24
|
// `josh test:pinned` (joshuafolkken/kit#4516) — put each changed hunk of a non-test code file back to
|
|
18
25
|
// the merge-base's lines, one at a time, run that file's related tests, and list the hunks no test went
|
|
@@ -22,12 +29,48 @@ import type { RedVerdict } from './test-red-logic'
|
|
|
22
29
|
// The changed files are copied in from the working tree first, so what is reverted is the change as it
|
|
23
30
|
// stands, committed or not, and each hunk's file is restored before the next one runs.
|
|
24
31
|
|
|
25
|
-
const TREE_PREFIX = 'josh-test-pinned-'
|
|
26
32
|
const HEAD = 'HEAD'
|
|
27
33
|
|
|
34
|
+
interface StubRead {
|
|
35
|
+
hunks: ReadonlyArray<Hunk>
|
|
36
|
+
unparsed: ReadonlyArray<string>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// `rewired` counts the changed hunks left out as a rewire (`test-pinned-rewire.ts`).
|
|
40
|
+
interface ProbeRead extends StubRead {
|
|
41
|
+
rewired: number
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface RunOptions {
|
|
45
|
+
max_hunks: number
|
|
46
|
+
is_cached_only: boolean
|
|
47
|
+
is_first_unpinned?: boolean
|
|
48
|
+
rewired?: number
|
|
49
|
+
origin?: PinnedOrigin | undefined
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// One run's probing: the checked hunks, what the cache knows of each, and the cache they are written to.
|
|
53
|
+
interface ProbeRun {
|
|
54
|
+
hunks: ReadonlyArray<Hunk>
|
|
55
|
+
known: ReadonlyArray<Known>
|
|
56
|
+
cache: LoadedCache
|
|
57
|
+
keys: ReadonlyArray<string>
|
|
58
|
+
options: RunOptions
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Each hunk's verdict, and how many of the fresh probes ran in stages.
|
|
62
|
+
interface Verdicts {
|
|
63
|
+
verdicts: Array<RedProbe | undefined>
|
|
64
|
+
staged: Staged
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const NO_OUTCOME: HunkOutcome = { unpinned: [], stopped: [] }
|
|
68
|
+
const NO_REPORT = { ...NO_OUTCOME, unchecked: [], unparsed: [] } as const
|
|
69
|
+
|
|
28
70
|
// `--diff-filter=M`: an added file's one hunk is the whole file, and reverting it is a missing module
|
|
29
|
-
// every importer fails on, which says nothing about the tests
|
|
30
|
-
// `diff.mnemonicPrefix` writes `+++ w/<file>`,
|
|
71
|
+
// every importer fails on, which says nothing about the tests — its functions are probed instead
|
|
72
|
+
// (`stub_hunks_of`). The prefixes are pinned: a user's `diff.mnemonicPrefix` writes `+++ w/<file>`,
|
|
73
|
+
// which would read as no hunk at all.
|
|
31
74
|
async function read_hunks(base: string, files: ReadonlyArray<string>): Promise<Array<Hunk>> {
|
|
32
75
|
if (files.length === 0) return []
|
|
33
76
|
const diff_args = ['diff', '-U0', '--no-color', '--no-ext-diff', '--diff-filter=M']
|
|
@@ -38,63 +81,231 @@ async function read_hunks(base: string, files: ReadonlyArray<string>): Promise<A
|
|
|
38
81
|
)
|
|
39
82
|
}
|
|
40
83
|
|
|
41
|
-
// The
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
84
|
+
// The key of each hunk, read off the working file its lines sit in now.
|
|
85
|
+
async function keys_of(hunks: ReadonlyArray<Hunk>): Promise<Array<string>> {
|
|
86
|
+
const contents = await Promise.all(hunks.map(async (hunk) => await readFile(hunk.file, 'utf8')))
|
|
87
|
+
|
|
88
|
+
return test_pinned_cache_logic.distinct(
|
|
89
|
+
hunks.map((hunk, index) => test_pinned_cache_logic.hunk_key(hunk, contents[index] ?? '')),
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// The verdict the cache already holds; one left to recheck holds none yet.
|
|
94
|
+
function held_of(known: Known): RedProbe | undefined {
|
|
95
|
+
return test_pinned_cache_logic.is_recheck(known) ? undefined : known
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function recheck_of(known: Known): Recheck | undefined {
|
|
99
|
+
return test_pinned_cache_logic.is_recheck(known) ? known : undefined
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// The hunks no held verdict covers, each with its recheck where the cache named one.
|
|
103
|
+
function probes_of(hunks: ReadonlyArray<Hunk>, known: ReadonlyArray<Known>): Array<Probe> {
|
|
104
|
+
return hunks
|
|
105
|
+
.map((hunk, index) => ({ hunk, index, recheck: recheck_of(known[index]) }))
|
|
106
|
+
.filter((probe) => held_of(known[probe.index]) === undefined)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// The probes in the order they run: the fewest tests reached first (`test_pinned_logic.by_reach`),
|
|
110
|
+
// each file's count read once and carried on its probes, which a wide one runs in stages by
|
|
111
|
+
// (`test-pinned-stage.ts`); a file with no graph to read counts as 0.
|
|
112
|
+
async function by_reach(probes: ReadonlyArray<Probe>, reach: Reach): Promise<Array<Probe>> {
|
|
113
|
+
const files = test_pinned_cache_logic.distinct(probes.map((probe) => probe.hunk.file))
|
|
114
|
+
const related = await Promise.all(files.map(async (file) => await reach.related(file)))
|
|
115
|
+
const counts = new Map(files.map((file, index) => [file, related[index]?.length ?? 0]))
|
|
116
|
+
const counted = probes.map((probe) => ({ ...probe, reach: counts.get(probe.hunk.file) }))
|
|
117
|
+
|
|
118
|
+
return test_pinned_logic.by_reach(counted, counts)
|
|
119
|
+
}
|
|
46
120
|
|
|
47
|
-
|
|
121
|
+
function reached_of(verdicts: ReadonlyArray<RedProbe | undefined>): Array<Reached> {
|
|
122
|
+
return verdicts.flatMap((verdict, index) => (verdict === undefined ? [] : [[index, verdict]]))
|
|
123
|
+
}
|
|
48
124
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
125
|
+
// The fresh run's options: the hunks the cache held, then the run's own.
|
|
126
|
+
function check_options(held: number, options: RunOptions): CheckOptions {
|
|
127
|
+
return {
|
|
128
|
+
held,
|
|
129
|
+
rewired: options.rewired ?? 0,
|
|
130
|
+
is_first_unpinned: options.is_first_unpinned === true,
|
|
131
|
+
origin: options.origin,
|
|
53
132
|
}
|
|
54
133
|
}
|
|
55
134
|
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
|
|
59
|
-
|
|
135
|
+
// Each hunk's verdict: the cached one where it still holds, else a fresh run's, in the hunks' order.
|
|
136
|
+
// The held ones are written first and each fresh one as it is reached (`test_pinned_cache.writer`).
|
|
137
|
+
// Under `is_first_unpinned` a hunk the run stopped before keeps no verdict.
|
|
138
|
+
async function verdicts_on(paths: ReadonlyArray<string>, probing: ProbeRun): Promise<Verdicts> {
|
|
139
|
+
const verdicts = probing.known.map((entry) => held_of(entry))
|
|
140
|
+
const reached = reached_of(verdicts)
|
|
141
|
+
const probes = await by_reach(probes_of(probing.hunks, probing.known), probing.cache.reach)
|
|
142
|
+
const writer = test_pinned_cache.writer(probing.cache, probing.keys)
|
|
143
|
+
const options = check_options(reached.length, probing.options)
|
|
144
|
+
|
|
145
|
+
await writer.record(reached)
|
|
146
|
+
const checked = await test_pinned_probe.checked_on(
|
|
147
|
+
paths,
|
|
148
|
+
probes,
|
|
149
|
+
async (index, verdict) => {
|
|
150
|
+
verdicts[index] = verdict
|
|
151
|
+
await writer.record([[index, verdict]])
|
|
152
|
+
},
|
|
153
|
+
options,
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
return { verdicts, staged: checked.staged }
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function outcome_of(
|
|
60
160
|
hunks: ReadonlyArray<Hunk>,
|
|
61
|
-
|
|
62
|
-
|
|
161
|
+
verdicts: ReadonlyArray<RedProbe | undefined>,
|
|
162
|
+
): HunkOutcome {
|
|
163
|
+
const is_held = verdicts.every((verdict) => verdict !== undefined)
|
|
63
164
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const verdict = await verdict_of(tree, hunk)
|
|
67
|
-
if (verdict !== 'red') unpinned.push({ ...hunk, is_green: verdict === 'green' })
|
|
68
|
-
}
|
|
165
|
+
return { ...test_pinned_logic.outcome(hunks, verdicts), is_held }
|
|
166
|
+
}
|
|
69
167
|
|
|
70
|
-
|
|
168
|
+
// The hunks a run probed and stopped before (`is_first_unpinned`); none, no `cut` key.
|
|
169
|
+
function cut_of(
|
|
170
|
+
hunks: ReadonlyArray<Hunk>,
|
|
171
|
+
verdicts: ReadonlyArray<RedProbe | undefined>,
|
|
172
|
+
): Pick<HunkOutcome, 'cut'> {
|
|
173
|
+
const cut = hunks.filter((_hunk, index) => verdicts[index] === undefined)
|
|
174
|
+
|
|
175
|
+
return cut.length === 0 ? {} : { cut }
|
|
71
176
|
}
|
|
72
177
|
|
|
73
|
-
|
|
178
|
+
// A fresh cached verdict is reused without a run (`test-pinned-cache.ts`); every hunk's verdict is
|
|
179
|
+
// stored again, so a rerun on the same tree starts no vitest. `is_cached_only` runs no probe: only the
|
|
180
|
+
// verdicts the cache holds are read, and nothing is written.
|
|
181
|
+
async function outcome_on(
|
|
182
|
+
base: string,
|
|
74
183
|
paths: ReadonlyArray<string>,
|
|
75
184
|
hunks: ReadonlyArray<Hunk>,
|
|
76
|
-
|
|
77
|
-
|
|
185
|
+
options: RunOptions,
|
|
186
|
+
): Promise<HunkOutcome> {
|
|
187
|
+
if (hunks.length === 0) return NO_OUTCOME
|
|
188
|
+
const cache = await test_pinned_cache.load(base, hunks)
|
|
189
|
+
const keys = await keys_of(hunks)
|
|
190
|
+
const known = await test_pinned_cache.known(
|
|
191
|
+
cache,
|
|
192
|
+
keys,
|
|
193
|
+
hunks.map((hunk) => hunk.file),
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
if (options.is_cached_only) {
|
|
197
|
+
return outcome_of(
|
|
198
|
+
hunks,
|
|
199
|
+
known.map((entry) => held_of(entry)),
|
|
200
|
+
)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const { verdicts, staged } = await verdicts_on(paths, { hunks, known, cache, keys, options })
|
|
204
|
+
|
|
205
|
+
return { ...outcome_of(hunks, verdicts), ...cut_of(hunks, verdicts), staged }
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// A target the base's tree does not hold is added — committed on the branch or still untracked.
|
|
209
|
+
async function added_scripts(base: string, targets: ReadonlyArray<string>): Promise<Array<string>> {
|
|
210
|
+
const held = new Set(await changed_paths.read_held_at(base, targets))
|
|
78
211
|
|
|
79
|
-
return
|
|
80
|
-
|
|
212
|
+
return targets.filter((file) => !held.has(file) && test_pinned_functions.is_script(file))
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Without `typescript` (an optional peer in a consumer) no function can be read, so every added file
|
|
216
|
+
// is reported unchecked rather than passed as pinned.
|
|
217
|
+
async function stub_hunks_of(added: ReadonlyArray<string>): Promise<StubRead> {
|
|
218
|
+
const api = review_code_tree.load_typescript(process.cwd())
|
|
219
|
+
if (api === undefined) return { hunks: [], unparsed: added }
|
|
220
|
+
const contents = await Promise.all(added.map(async (file) => await readFile(file, 'utf8')))
|
|
221
|
+
const hunks = added.flatMap((file, index) =>
|
|
222
|
+
test_pinned_functions.stub_hunks(api, file, contents[index] ?? ''),
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
return { hunks, unparsed: [] }
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// A changed hunk whose revert emits the same JavaScript, or a rewire, is dropped before the cap
|
|
229
|
+
// (`test-pinned-emit.ts`), so neither is `unchecked`; without `typescript` every hunk is kept, so the
|
|
230
|
+
// run checks more rather than less.
|
|
231
|
+
async function runtime_hunks(hunks: ReadonlyArray<Hunk>): Promise<ProbeRead> {
|
|
232
|
+
const api = review_code_tree.load_typescript(process.cwd())
|
|
233
|
+
if (api === undefined) return { hunks: [...hunks], unparsed: [], rewired: 0 }
|
|
234
|
+
const contents = await Promise.all(hunks.map(async (hunk) => await readFile(hunk.file, 'utf8')))
|
|
235
|
+
|
|
236
|
+
return { ...test_pinned_emit.probed_of(api, hunks, contents), unparsed: [] }
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
async function read_probes(base: string, targets: ReadonlyArray<string>): Promise<ProbeRead> {
|
|
240
|
+
const stubs = await stub_hunks_of(await added_scripts(base, targets))
|
|
241
|
+
const changed = await runtime_hunks(await read_hunks(base, targets))
|
|
242
|
+
const hunks = [...changed.hunks, ...stubs.hunks]
|
|
243
|
+
|
|
244
|
+
return { hunks, unparsed: stubs.unparsed, rewired: changed.rewired }
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// The work tree's files that differ from `commit`, deleted ones dropped. Read since `HEAD` they are
|
|
248
|
+
// what the worktree at `HEAD` needs copied in to hold the work tree — a conflicted merge's incoming
|
|
249
|
+
// files included; read since the change base they are this branch's own change.
|
|
250
|
+
async function existing_since(commit: string): Promise<Array<string>> {
|
|
251
|
+
const changed = await changed_paths.read_changed_since(commit)
|
|
252
|
+
|
|
253
|
+
return changed.filter((file) => existsSync(file))
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
async function report_on(
|
|
257
|
+
base: string,
|
|
258
|
+
options: RunOptions,
|
|
259
|
+
has_runner: boolean,
|
|
260
|
+
): Promise<PinnedReport> {
|
|
261
|
+
const { max_hunks } = options
|
|
262
|
+
const paths = await existing_since(HEAD)
|
|
263
|
+
const changed = await existing_since(base)
|
|
264
|
+
const targets = await test_pinned_reach.probed_files(
|
|
265
|
+
changed.filter((file) => test_pinned_logic.is_target(file)),
|
|
266
|
+
)
|
|
267
|
+
const probes = await read_probes(base, targets)
|
|
268
|
+
const { checked, unchecked } = test_pinned_logic.split(probes.hunks, has_runner ? max_hunks : 0)
|
|
269
|
+
const outcome = await outcome_on(base, paths, checked, { ...options, rewired: probes.rewired })
|
|
270
|
+
|
|
271
|
+
return { ...outcome, unchecked, unparsed: probes.unparsed, max_hunks, has_runner }
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
async function report(options: RunOptions): Promise<PinnedReport> {
|
|
275
|
+
const base = await change_base.resolved_through_merge()
|
|
276
|
+
const has_runner = test_red.has_runner()
|
|
277
|
+
if (base === undefined) return { ...NO_REPORT, max_hunks: options.max_hunks, has_runner }
|
|
278
|
+
|
|
279
|
+
return await report_on(base, options, has_runner)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// No merge-base (not a repository, no default branch) checks nothing, as `josh test:red` does. The cap
|
|
283
|
+
// is shared: changed hunks first, then the added files' functions. Without Vitest (a consumer that has
|
|
284
|
+
// none) no probe runs, so every one is unchecked rather than unpinned. `is_first_unpinned` starts no
|
|
285
|
+
// probe once one is unpinned (joshuafolkken/kit#5153): the hunks left are reported `cut`. `origin` is
|
|
286
|
+
// what started the run, for its ledger row.
|
|
287
|
+
async function run(
|
|
288
|
+
max_hunks: number,
|
|
289
|
+
is_first_unpinned = false,
|
|
290
|
+
origin?: PinnedOrigin,
|
|
291
|
+
): Promise<PinnedReport> {
|
|
292
|
+
return await report({ max_hunks, is_cached_only: false, is_first_unpinned, origin })
|
|
293
|
+
}
|
|
81
294
|
|
|
82
|
-
|
|
83
|
-
|
|
295
|
+
// The unpinned hunks the cache already answers for this tree, probing nothing (joshuafolkken/kit#4936):
|
|
296
|
+
// what a check still running — or one stopped mid-way — has reached for the hunks that did not move.
|
|
297
|
+
async function cached(max_hunks: number): Promise<PinnedReport> {
|
|
298
|
+
return await report({ max_hunks, is_cached_only: true })
|
|
84
299
|
}
|
|
85
300
|
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const
|
|
90
|
-
const paths = changed.filter((file) => existsSync(file))
|
|
91
|
-
const targets = paths.filter((file) => test_pinned_logic.is_target(file))
|
|
92
|
-
const hunks = base === undefined ? [] : await read_hunks(base, targets)
|
|
93
|
-
const { checked, unchecked } = test_pinned_logic.split(hunks, max_hunks)
|
|
301
|
+
// The cached report when the cache holds every checked hunk's verdict for this tree, probing nothing
|
|
302
|
+
// (joshuafolkken/kit#5078); `undefined` when a hunk moved or was never probed, so the caller probes.
|
|
303
|
+
async function held_report(max_hunks: number): Promise<PinnedReport | undefined> {
|
|
304
|
+
const read = await cached(max_hunks)
|
|
94
305
|
|
|
95
|
-
return
|
|
306
|
+
return read.is_held === true ? read : undefined
|
|
96
307
|
}
|
|
97
308
|
|
|
98
|
-
const test_pinned = { run }
|
|
309
|
+
const test_pinned = { cached, held_report, run }
|
|
99
310
|
|
|
100
311
|
export { test_pinned }
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
import { existsSync, statSync } from 'node:fs'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
4
|
+
import { test_pinned_reach } from './test-pinned-reach'
|
|
5
|
+
|
|
6
|
+
// `josh test:reach <file...>` — how many test files each file's imports reach, the count
|
|
7
|
+
// `josh test:related` sizes its core claim by, one `<count> <file>` line per file
|
|
8
|
+
// (joshuafolkken/kit#5238): an overrun filing or a baseline measures it without a hand-written probe.
|
|
9
|
+
|
|
10
|
+
const ARGV_OFFSET = 2
|
|
11
|
+
const FAILURE_EXIT_CODE = 1
|
|
12
|
+
const USAGE = 'Usage: josh test:reach <file...>'
|
|
13
|
+
const NO_GRAPH =
|
|
14
|
+
'josh test:reach: no import graph can be built here (no typescript or tsconfig.json)'
|
|
15
|
+
|
|
16
|
+
function is_file(path: string): boolean {
|
|
17
|
+
return existsSync(path) && statSync(path).isFile()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// A path no file answers — absent, or a directory — reaches no test, so its `0` would read as a
|
|
21
|
+
// measured count: `pnpm josh` runs from the repository root, where a path typed relative to a
|
|
22
|
+
// subdirectory names nothing.
|
|
23
|
+
function refusal(argv: ReadonlyArray<string>): string | undefined {
|
|
24
|
+
if (argv.length === 0) return USAGE
|
|
25
|
+
const missing = argv.filter((file) => !is_file(file))
|
|
26
|
+
if (missing.length === 0) return undefined
|
|
27
|
+
|
|
28
|
+
return `josh test:reach: no such file from the repository root: ${missing.join(', ')}`
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function run(argv: ReadonlyArray<string>): Promise<number> {
|
|
32
|
+
const refused = refusal(argv)
|
|
33
|
+
|
|
34
|
+
if (refused !== undefined) {
|
|
35
|
+
console.error(refused)
|
|
36
|
+
|
|
37
|
+
return FAILURE_EXIT_CODE
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const counts = await test_pinned_reach.reached_test_counts(argv)
|
|
41
|
+
|
|
42
|
+
if (counts === undefined) {
|
|
43
|
+
console.error(NO_GRAPH)
|
|
44
|
+
|
|
45
|
+
return FAILURE_EXIT_CODE
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
console.info(counts.map(({ file, count }) => `${String(count)} ${file}`).join('\n'))
|
|
49
|
+
|
|
50
|
+
return 0
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function main(argv: ReadonlyArray<string>): Promise<void> {
|
|
54
|
+
process.exitCode = await run(argv)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const test_reach_cli = { USAGE, run }
|
|
58
|
+
|
|
59
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) await main(process.argv.slice(ARGV_OFFSET))
|
|
60
|
+
|
|
61
|
+
export { test_reach_cli }
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readdirSync, readFileSync, rmSync, statSync } from 'node:fs'
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
import { git_common_directory } from '#scripts/git/git-common-directory'
|
|
4
|
+
import { run_record_path } from '#scripts/josh/run-record-path'
|
|
4
5
|
import { atomic_write } from '#scripts/lib/atomic-write'
|
|
5
6
|
import { json_value } from '#scripts/lib/json-value'
|
|
6
7
|
import { test_read_trace, type ReadRecords } from './test-read-trace'
|
|
@@ -24,6 +25,10 @@ interface ReadMap {
|
|
|
24
25
|
// content then (`input_fingerprint.of_files`), so one whose content has not moved since does not count as changed
|
|
25
26
|
// (joshuafolkken/kit#4425).
|
|
26
27
|
dirty: Record<string, string>
|
|
28
|
+
// The recording checkout's change as a test reads it through git — the branch diff from the change
|
|
29
|
+
// base plus the untracked files (`changed_paths.read_changed_paths`), committed or not
|
|
30
|
+
// (joshuafolkken/kit#4734).
|
|
31
|
+
change: Array<string>
|
|
27
32
|
// The directories `commit` holds, so a directory new since then is told apart from one no test
|
|
28
33
|
// read — the map's own keys cannot say which, since an unread directory has none.
|
|
29
34
|
directories: Array<string>
|
|
@@ -32,10 +37,11 @@ interface ReadMap {
|
|
|
32
37
|
|
|
33
38
|
// Bumped whenever the shape, what a reader means or how `dirty` is digested changes, so a map an older
|
|
34
39
|
// kit wrote reads as no map at all and the next full run writes it afresh. 6: `dirty` is
|
|
35
|
-
// `input-fingerprint.ts`'s digest of every changed file (joshuafolkken/kit#4497).
|
|
36
|
-
|
|
40
|
+
// `input-fingerprint.ts`'s digest of every changed file (joshuafolkken/kit#4497). 7: `change`
|
|
41
|
+
// (joshuafolkken/kit#4734). 8: a module is a reader only of what its evaluation read
|
|
42
|
+
// (joshuafolkken/kit#5033).
|
|
43
|
+
const MAP_VERSION = 8
|
|
37
44
|
|
|
38
|
-
const MAP_DIRECTORY = 'josh'
|
|
39
45
|
const MAP_FILE_STEM = 'test-read-map'
|
|
40
46
|
const RECORD_EXTENSION = '.json'
|
|
41
47
|
|
|
@@ -84,6 +90,7 @@ const FIELD_CHECKS: ReadonlyArray<[keyof ReadMap, (field: unknown) => boolean]>
|
|
|
84
90
|
['version', (field) => field === MAP_VERSION],
|
|
85
91
|
['commit', (field) => typeof field === 'string'],
|
|
86
92
|
['dirty', is_digest_record],
|
|
93
|
+
['change', is_string_array],
|
|
87
94
|
['directories', is_string_array],
|
|
88
95
|
['readers', is_read_records],
|
|
89
96
|
]
|
|
@@ -148,7 +155,13 @@ function created_directories(
|
|
|
148
155
|
// it. A directory new since the recording is also a new entry in the listing above it and a probe of
|
|
149
156
|
// it that now answers differently; a directory that already existed reads the same to both, whatever
|
|
150
157
|
// changed deeper down.
|
|
158
|
+
//
|
|
159
|
+
// **A run record reaches only a test that read it by name** (joshuafolkken/kit#5001): a test listing or
|
|
160
|
+
// walking the root or `.josh/` reads the checkout around it, not the observation or accepted metrics
|
|
161
|
+
// a lane writes after its checks went green, so those keys would run every such test for bookkeeping.
|
|
151
162
|
function lookup_keys(relative: string, recorded: ReadonlySet<string>): Array<string> {
|
|
163
|
+
if (run_record_path.is_run_record(relative)) return [relative]
|
|
164
|
+
|
|
152
165
|
const directories = directories_above(relative)
|
|
153
166
|
const created = created_directories(directories, recorded)
|
|
154
167
|
const listed = [
|
|
@@ -170,23 +183,34 @@ function readers_of(map: ReadMap, relative: string): Array<string> {
|
|
|
170
183
|
return [...new Set(keys.flatMap((key) => map.readers[key] ?? []))]
|
|
171
184
|
}
|
|
172
185
|
|
|
173
|
-
// **A directory
|
|
174
|
-
//
|
|
175
|
-
//
|
|
176
|
-
//
|
|
186
|
+
// **A directory inside which no recorded test listed, walked or read any entry** (joshuafolkken/kit#4303).
|
|
187
|
+
// A file added to it since is one no test reads, as surely as one the tree already held there: a test
|
|
188
|
+
// that builds a path into it reads some file there, and one that enumerates it lists it, both of which
|
|
189
|
+
// leave a key whose directory is this one — a read is recorded before it runs, so a path absent then
|
|
190
|
+
// still leaves its key. **A directory new since the recording counts too** (joshuafolkken/kit#4597):
|
|
191
|
+
// a probe of it or a listing of its parent is one of `readers_of`'s keys, which the caller asks first.
|
|
192
|
+
// **A read of the recording tree's own change does not count** (joshuafolkken/kit#4734): a test that
|
|
193
|
+
// reads this checkout's change through git reads whatever file the recording lane held, so its own
|
|
194
|
+
// `.josh/metrics-accepted/<N>.json` marked that directory read and sent the next lane's to the whole
|
|
195
|
+
// suite. A listing or a walk of the directory, or a read of any other file there, still counts — except
|
|
196
|
+
// for a run record, which only a read of itself reaches (`lookup_keys`).
|
|
177
197
|
function in_unread_directory(map: ReadMap, relative: string): boolean {
|
|
178
|
-
|
|
198
|
+
if (run_record_path.is_run_record(relative)) return true
|
|
179
199
|
|
|
180
|
-
|
|
200
|
+
const directory = path.dirname(relative)
|
|
201
|
+
const change = new Set(map.change)
|
|
202
|
+
const keys = Object.keys(map.readers).filter((key) => !change.has(key))
|
|
181
203
|
|
|
182
|
-
return
|
|
204
|
+
return keys.every((key) => path.dirname(key) !== directory)
|
|
183
205
|
}
|
|
184
206
|
|
|
185
207
|
function map_path(root: string, version: number = MAP_VERSION): string | undefined {
|
|
186
208
|
const common = git_common_directory.repository(root)
|
|
187
209
|
const name = `${MAP_FILE_STEM}.v${String(version)}${RECORD_EXTENSION}`
|
|
188
210
|
|
|
189
|
-
return common === undefined
|
|
211
|
+
return common === undefined
|
|
212
|
+
? undefined
|
|
213
|
+
: path.join(common, git_common_directory.STATE_DIRECTORY, name)
|
|
190
214
|
}
|
|
191
215
|
|
|
192
216
|
// Every version's map, the unversioned one kits before joshuafolkken/kit#4423 wrote included; a
|
|
@@ -36,16 +36,28 @@ async function commit_directories(commit: string): Promise<Array<string>> {
|
|
|
36
36
|
return output.split('\0').filter((listed) => listed.length > 0)
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
type TreeSnapshot = Pick<ReadMap, 'commit' | 'dirty' | 'directories'>
|
|
39
|
+
type TreeSnapshot = Pick<ReadMap, 'commit' | 'dirty' | 'change' | 'directories'>
|
|
40
40
|
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
|
|
41
|
+
// A checkout with no change base (no default-branch ref) still records its map, with no change to
|
|
42
|
+
// discount: every read then counts, which narrows less, never wrongly.
|
|
43
|
+
async function own_change(): Promise<Array<string>> {
|
|
44
|
+
try {
|
|
45
|
+
return await changed_paths.read_changed_paths(false)
|
|
46
|
+
} catch {
|
|
47
|
+
return []
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// The tree the run read: the commit, every file that differed from it with its content's digest, the
|
|
52
|
+
// checkout's change from its change base, and the directories it holds. **Read before the run
|
|
53
|
+
// starts**: a digest taken after it would vouch for an edit made while the tests ran as content they
|
|
54
|
+
// read.
|
|
44
55
|
async function tree_snapshot(root: string): Promise<TreeSnapshot> {
|
|
45
56
|
const commit = await git_command.head_commit()
|
|
46
57
|
const dirty = input_fingerprint.of_files(root, await changed_paths.read_changed_since(commit))
|
|
58
|
+
const change = await own_change()
|
|
47
59
|
|
|
48
|
-
return { commit, dirty, directories: await commit_directories(commit) }
|
|
60
|
+
return { commit, dirty, change, directories: await commit_directories(commit) }
|
|
49
61
|
}
|
|
50
62
|
|
|
51
63
|
// A map that cannot be written — no git, a read-only common directory — leaves the previous map in
|
|
@@ -12,6 +12,15 @@ import { fileURLToPath } from 'node:url'
|
|
|
12
12
|
// makes has the test outermost, so a shared helper it reads through — every test importing it — is
|
|
13
13
|
// never the reader (joshuafolkken/kit#4417). The test file is recorded beside it, because an async
|
|
14
14
|
// callback (a directory walk inside a dependency) leaves no repository frame at all.
|
|
15
|
+
//
|
|
16
|
+
// **Only a module's evaluation makes a module the reader** (joshuafolkken/kit#5033). A read a named
|
|
17
|
+
// function makes after an `await` has that function outermost, since the continuation drops the test
|
|
18
|
+
// that called it: `import-graph.ts` read some 3,700 paths that way, and `vitest related` widened each
|
|
19
|
+
// to every test importing it. Such a read belongs to the test running it, recorded beside, so an
|
|
20
|
+
// outermost frame with a function name records no module. A module's top-level code runs with no
|
|
21
|
+
// function name; so does an anonymous callback, which keeps the widening — the safe side. A top-level
|
|
22
|
+
// `await` of a named function that reads after an `await` of its own narrows to the first importing
|
|
23
|
+
// test; no module does that today, and CI's whole suite would catch the miss.
|
|
15
24
|
|
|
16
25
|
type ReadRecords = Record<string, Array<string>>
|
|
17
26
|
|
|
@@ -95,16 +104,23 @@ function read_target(argument: unknown, cwd: string): string | undefined {
|
|
|
95
104
|
return undefined
|
|
96
105
|
}
|
|
97
106
|
|
|
107
|
+
// One call site: its script name, and the name of the function running there — empty for a module's
|
|
108
|
+
// top-level code or an anonymous callback.
|
|
109
|
+
interface CallFrame {
|
|
110
|
+
script_name: string
|
|
111
|
+
function_name: string
|
|
112
|
+
}
|
|
113
|
+
|
|
98
114
|
interface ReaderQuery {
|
|
99
115
|
root: string
|
|
100
|
-
//
|
|
101
|
-
|
|
116
|
+
// Every call site, innermost first.
|
|
117
|
+
frames: ReadonlyArray<CallFrame>
|
|
102
118
|
// The recorder's own file, which is always the top frame and never the reader.
|
|
103
119
|
recorder: string
|
|
104
120
|
}
|
|
105
121
|
|
|
106
|
-
function frame_reader(query: ReaderQuery,
|
|
107
|
-
const file_path = script_path(script_name)
|
|
122
|
+
function frame_reader(query: ReaderQuery, frame: CallFrame): string | undefined {
|
|
123
|
+
const file_path = script_path(frame.script_name)
|
|
108
124
|
|
|
109
125
|
if (file_path === undefined || file_path === query.recorder) return undefined
|
|
110
126
|
|
|
@@ -114,9 +130,11 @@ function frame_reader(query: ReaderQuery, script_name: string): string | undefin
|
|
|
114
130
|
}
|
|
115
131
|
|
|
116
132
|
function stack_reader(query: ReaderQuery): string | undefined {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
133
|
+
const outermost = query.frames.findLast((frame) => frame_reader(query, frame) !== undefined)
|
|
134
|
+
|
|
135
|
+
if (outermost?.function_name !== '') return undefined
|
|
136
|
+
|
|
137
|
+
return frame_reader(query, outermost)
|
|
120
138
|
}
|
|
121
139
|
|
|
122
140
|
function add_reader(records: Map<string, Set<string>>, read_path: string, reader: string): void {
|
|
@@ -144,5 +162,5 @@ const test_read_trace = {
|
|
|
144
162
|
to_records,
|
|
145
163
|
}
|
|
146
164
|
|
|
147
|
-
export type { ReadKind, ReaderQuery, ReadRecords }
|
|
165
|
+
export type { CallFrame, ReadKind, ReaderQuery, ReadRecords }
|
|
148
166
|
export { test_read_trace }
|