@joshuafolkken/kit 1.1784.0 → 1.2116.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/reviewer-verification.md +19 -0
- package/.claude/agents/reviewer.md +19 -0
- package/.claude/settings.json +5 -6
- package/.claude/skills/dependency-update/SKILL.md +9 -10
- package/.claude/skills/workflow-commands/SKILL.md +6 -6
- package/.claude/skills/workflow-commands/background-commands.md +8 -5
- package/.claude/skills/workflow-commands/backlogrun-child.md +3 -1
- package/.claude/skills/workflow-commands/backlogrun-lanes.md +1 -1
- package/.claude/skills/workflow-commands/backlogrun-park.md +5 -2
- package/.claude/skills/workflow-commands/backlogrun-progress.md +2 -3
- package/.claude/skills/workflow-commands/backlogrun-recovery.md +1 -1
- package/.claude/skills/workflow-commands/backlogrun-steps.md +3 -2
- package/.claude/skills/workflow-commands/backlogrun.md +1 -1
- package/.claude/skills/workflow-commands/chain-rule.md +41 -32
- package/.claude/skills/workflow-commands/delegation.md +6 -6
- package/.claude/skills/workflow-commands/entry-sequence.md +2 -2
- package/.claude/skills/workflow-commands/followup.md +7 -5
- package/.claude/skills/workflow-commands/fullrun-steps.md +6 -6
- package/.claude/skills/workflow-commands/fullrun.md +1 -1
- package/.claude/skills/workflow-commands/issue-comments.md +9 -4
- package/.claude/skills/workflow-commands/issue-fold-existing.md +2 -1
- package/.claude/skills/workflow-commands/kickoff.md +2 -2
- package/.claude/skills/workflow-commands/observation-filing.md +1 -1
- package/.claude/skills/workflow-commands/observation-ledger.md +6 -4
- package/.claude/skills/workflow-commands/pre-gate-cut.md +9 -7
- package/.claude/skills/workflow-commands/prerequisite.md +3 -2
- package/.claude/skills/workflow-commands/retrospective.md +2 -2
- package/.claude/skills/workflow-commands/split-assessment.md +7 -5
- package/.codex/hooks.json +5 -5
- package/.github/actions/setup-pnpm/action.yml +9 -16
- package/.github/dependabot.yml +16 -0
- package/.github/workflows/auto-tag.yml +45 -0
- package/.github/workflows/ci.yml +155 -15
- package/.github/workflows/dependabot-auto-merge.yml +63 -4
- package/.github/workflows/production.yml +8 -0
- package/.github/workflows/publish.yml +60 -45
- package/.vscode/settings.json +19 -0
- package/CLAUDE.md +5 -12
- package/SECURITY.md +2 -2
- package/dist/CLAUDE.md +5 -12
- package/dist/commands/document-read-cli.js +2 -1
- package/dist/commands/document-section-main.js +2 -1
- package/dist/commands/read-set-cli.js +194 -134
- package/dist/commands/run-prep-main.js +9694 -10173
- package/dist/commands/run-step-cli.js +22138 -18285
- package/dist/hooks/audit-provision.js +23 -5
- package/dist/hooks/chunk-3GKE653K.js +6204 -0
- package/dist/hooks/chunk-45CJJOO7.js +1243 -0
- package/dist/hooks/{chunk-CWMBGKYW.js → chunk-5PM2JRGV.js} +2153 -856
- package/dist/hooks/{chunk-WR2KQAYZ.js → chunk-7SIUNQXK.js} +1207 -1470
- package/dist/hooks/{chunk-O2YBIDSI.js → chunk-CQD4LJE6.js} +1682 -1130
- package/dist/hooks/{chunk-VWWCFGWK.js → chunk-OPSRGWFU.js} +1 -1
- package/dist/hooks/{chunk-XGBNSWEI.js → chunk-UJ3FPMMM.js} +132 -49
- package/dist/hooks/chunk-VVNYJWEI.js +30 -0
- package/dist/hooks/chunk-Z6DQJKH3.js +2806 -0
- package/dist/hooks/codex-hook-adapter.js +8 -8
- package/dist/hooks/format-edited.js +4 -5
- package/dist/hooks/inputs.json +386 -360
- package/dist/hooks/pretool-guard.js +7 -6
- package/dist/hooks/session-lang.js +101 -258
- package/dist/hooks/stop-guard.js +1744 -2576
- package/dist/josh.js +7133 -6368
- package/dist/version/index.js +161 -1
- package/eslint/rules/comment-why-only.js +108 -0
- package/package.json +16 -9
- package/prompts/coding-standards.md +1 -1
- package/prompts/collaboration-workflow/file-edits.md +14 -11
- package/prompts/collaboration-workflow/issue-citation.md +0 -4
- package/prompts/collaboration-workflow/issue-template.md +40 -21
- package/prompts/collaboration-workflow/lane-instructions.md +3 -1
- package/prompts/collaboration-workflow/measurement.md +8 -1
- package/prompts/collaboration-workflow/operating-rules.md +11 -2
- package/prompts/collaboration-workflow/output-bounds.md +6 -2
- package/prompts/collaboration-workflow/plan-comment.md +1 -1
- package/prompts/collaboration-workflow/principles.md +9 -0
- package/prompts/collaboration-workflow/residency.md +3 -2
- package/prompts/collaboration-workflow/rule-delivery.md +13 -1
- package/prompts/collaboration-workflow/upstream-interrupt.md +2 -2
- package/prompts/collaboration-workflow/wip-cap.md +3 -1
- package/prompts/review-rubric.md +8 -0
- package/prompts/review.md +31 -22
- package/prompts/testing-guide.md +1 -0
- package/scripts/agent/agent-argv.ts +14 -16
- package/scripts/agent/agent-provider.ts +138 -0
- package/scripts/agent/agent-role-profile.ts +108 -156
- package/scripts/agent/agent-safe-text.ts +20 -5
- package/scripts/agent/api-usage-limit.ts +65 -0
- package/scripts/agent/claude-agent-argv.ts +19 -9
- package/scripts/agent/codex-agent-argv.ts +118 -22
- package/scripts/agent/usage-limit-reset.ts +179 -0
- package/scripts/auth/claude-token-output.ts +2 -2
- package/scripts/auto-ok/auto-ok-author.ts +53 -0
- package/scripts/auto-ok/auto-ok-cli.ts +20 -9
- package/scripts/backlog/backlog-defect-priority.ts +1 -1
- package/scripts/backlog/backlog-drive-cli.ts +6 -1
- package/scripts/backlog/backlog-drive-hold.ts +3 -3
- package/scripts/backlog/backlog-drive-idle.ts +10 -0
- package/scripts/backlog/backlog-drive-launch-pass.ts +90 -0
- package/scripts/backlog/backlog-drive-launch.ts +8 -2
- package/scripts/backlog/backlog-drive-named-offer.ts +73 -30
- package/scripts/backlog/backlog-drive-named.ts +28 -7
- package/scripts/backlog/backlog-drive-paused.ts +5 -4
- package/scripts/backlog/backlog-drive-restore.ts +11 -3
- package/scripts/backlog/backlog-drive.ts +21 -60
- package/scripts/backlog/backlog-gate-scope.ts +61 -0
- package/scripts/backlog/backlog-measure-close.ts +112 -0
- package/scripts/backlog/backlog-next.ts +39 -49
- package/scripts/backlog/backlog-occupied.ts +2 -2
- package/scripts/backlog/backlog-overlap.ts +42 -8
- package/scripts/backlog/backlog-plan-cli.ts +4 -1
- package/scripts/backlog/backlog-plan-comment.ts +81 -0
- package/scripts/backlog/backlog-plan-read.ts +19 -6
- package/scripts/backlog/backlog-pool.ts +50 -12
- package/scripts/backlog/backlog-rank.ts +60 -13
- package/scripts/backlog/backlog-stalled-detect.ts +2 -1
- package/scripts/backlog/backlog-waves.ts +17 -2
- package/scripts/backlog/backlogrun-launch.ts +7 -4
- package/scripts/cost-runtime/context-cut-payback.ts +27 -25
- package/scripts/cost-runtime/cost-cli.ts +37 -16
- package/scripts/cost-runtime/cost-pricing.ts +9 -0
- package/scripts/cost-runtime/cost-verdict.ts +4 -1
- package/scripts/delegation/delegation-policy.ts +2 -2
- package/scripts/delegation/duplicate-read-guard.ts +1 -0
- package/scripts/delegation/investigation-guard.ts +14 -2
- package/scripts/delegation/investigation-reads.ts +45 -23
- package/scripts/dependabot/dependabot-cooldown.ts +3 -2
- package/scripts/discovery/repo-party.ts +80 -20
- package/scripts/discovery/session-owner-pin.ts +51 -0
- package/scripts/document/capped-print.ts +1 -1
- package/scripts/document/command-reference-line-budget.ts +42 -0
- package/scripts/document/document-byte-budget.ts +17 -7
- package/scripts/document/document-checks.ts +20 -0
- package/scripts/document/document-ratchet-check.ts +101 -0
- package/scripts/document/document-section.ts +1 -0
- package/scripts/document/entry-read-budget.ts +7 -3
- package/scripts/document/issue-citation-budget.ts +94 -0
- package/scripts/epic/epic-cli-argv.ts +2 -2
- package/scripts/epic/epic-fetch.ts +4 -2
- package/scripts/epic/epic-graph.ts +7 -2
- package/scripts/epic/epic-issue.ts +3 -1
- package/scripts/epic/epic-rank.ts +5 -0
- package/scripts/exports/unused-members-check.ts +62 -0
- package/scripts/exports/unused-members-cli.ts +6 -51
- package/scripts/followup/followup-ci-path.ts +67 -0
- package/scripts/followup/followup-coderabbit-retrigger.ts +261 -0
- package/scripts/followup/followup-coderabbit-wait.ts +13 -10
- package/scripts/followup/followup-failed-tests.ts +160 -0
- package/scripts/followup/followup-job-needs.ts +100 -0
- package/scripts/followup/followup-job-rerun.ts +303 -0
- package/scripts/followup/followup-main-move.ts +113 -0
- package/scripts/followup/git-followup-finish.ts +43 -11
- package/scripts/followup/git-followup-pending.ts +3 -3
- package/scripts/followup/git-followup-stages.ts +41 -11
- package/scripts/followup/git-pr-followup-checks.ts +55 -16
- package/scripts/followup/git-pr-followup-wrapup.ts +24 -5
- package/scripts/followup/git-pr-followup.ts +62 -27
- package/scripts/fresh-machine/fresh-machine-script.ts +5 -9
- package/scripts/fresh-machine/specs/kit-test-backlogrun-python.json +2 -2
- package/scripts/fresh-machine/specs/kit-test-backlogrun.json +2 -2
- package/scripts/gate/busy-average.ts +34 -2
- package/scripts/gate/check-related-pinned.ts +43 -0
- package/scripts/gate/check-related-reuse.ts +64 -0
- package/scripts/gate/check-related-section.ts +57 -0
- package/scripts/gate/check-related-unplanned.ts +34 -0
- package/scripts/gate/check-related.ts +265 -0
- package/scripts/gate/command-memory.ts +1 -1
- package/scripts/gate/core-admission.ts +24 -6
- package/scripts/gate/core-budget-timing.ts +20 -6
- package/scripts/gate/core-budget.ts +40 -11
- package/scripts/gate/core-wait-record.ts +3 -2
- package/scripts/gate/core-wait.ts +25 -2
- package/scripts/gate/core-weights.ts +15 -7
- package/scripts/gate/gate-labels.ts +46 -0
- package/scripts/gate/gate-ledger.ts +14 -6
- package/scripts/gate/gate-plan.ts +103 -58
- package/scripts/gate/gate-report.ts +9 -7
- package/scripts/gate/gate-run-steps.ts +26 -3
- package/scripts/gate/gate-skip.ts +45 -6
- package/scripts/gate/gate-static-group.ts +60 -0
- package/scripts/gate/gate-steps.ts +2 -1
- package/scripts/gate/gate-tree.ts +4 -2
- package/scripts/gate/hook-gate-reuse.ts +19 -2
- package/scripts/gate/metrics-totals.ts +59 -0
- package/scripts/gate/scoped-green.ts +68 -15
- package/scripts/gate/since-green.ts +14 -6
- package/scripts/gate/structural-checks.ts +96 -0
- package/scripts/gate/verification-gate.ts +51 -16
- package/scripts/gate/verification-inputs.ts +21 -6
- package/scripts/gate/verification-tail.ts +52 -0
- package/scripts/gh/gh-author-association.ts +23 -2
- package/scripts/gh/git-ai-review-scan.ts +1 -1
- package/scripts/gh/git-gh-api-path.ts +12 -3
- package/scripts/gh/git-gh-comments-unreadable.ts +36 -0
- package/scripts/gh/git-gh-exec.ts +32 -2
- package/scripts/gh/git-gh-issue-read.ts +4 -2
- package/scripts/gh/git-gh-issue-rest.ts +1 -0
- package/scripts/gh/git-gh-issue-write.ts +8 -2
- package/scripts/gh/git-gh-issue.ts +12 -5
- package/scripts/gh/git-gh-pr-auto-merge.ts +13 -6
- package/scripts/gh/git-gh-pr-graphql-state.ts +56 -0
- package/scripts/gh/git-gh-pr-read.ts +74 -13
- package/scripts/gh/git-gh-pr-rest.ts +3 -1
- package/scripts/gh/git-gh-pr-snapshot.ts +22 -7
- package/scripts/gh/git-gh-pr-too-large.ts +20 -0
- package/scripts/gh/git-gh-pr.ts +21 -7
- package/scripts/gh/git-gh-retry.ts +141 -0
- package/scripts/gh/git-pr-ai-review.ts +15 -6
- package/scripts/gh/git-pr-checks-eval.ts +3 -0
- package/scripts/gh/git-pr-checks.ts +5 -5
- package/scripts/git/base-tree.ts +30 -0
- package/scripts/git/change-base.ts +4 -10
- package/scripts/git/changed-paths-sync.ts +63 -0
- package/scripts/git/changed-paths.ts +16 -1
- package/scripts/git/git-common-directory.ts +11 -1
- package/scripts/git/git-diff-reads.ts +66 -20
- package/scripts/git/git-error.ts +9 -2
- package/scripts/git/git-schemas.ts +13 -0
- package/scripts/git/git-worktree.ts +13 -0
- package/scripts/git/gone-branch.ts +4 -1
- package/scripts/git/main-merge-budget-conflict.ts +89 -0
- package/scripts/git/main-merge-guard.ts +55 -18
- package/scripts/git/main-merge-regenerate.ts +59 -25
- package/scripts/git/main-merge.ts +53 -5
- package/scripts/git/no-base-checkout.ts +127 -0
- package/scripts/git/stash/git-stash.ts +11 -2
- package/scripts/git/stash/stash-push-cli.ts +10 -0
- package/scripts/hooks/batch-guard.ts +40 -21
- package/scripts/hooks/edited-cspell.ts +37 -11
- package/scripts/hooks/format-edited-file.ts +22 -2
- package/scripts/hooks/lane-plan-guard.ts +50 -0
- package/scripts/hooks/pre-commit-lint-switch.ts +9 -0
- package/scripts/hooks/pre-commit-lint.ts +14 -1
- package/scripts/hooks/pre-push-related-switch.ts +10 -0
- package/scripts/hooks/pre-push-unit.ts +76 -10
- package/scripts/hooks/pretool-guard.ts +2 -0
- package/scripts/hooks/reserved-run.ts +14 -1
- package/scripts/hooks/run-hook.sh +23 -8
- package/scripts/hooks/step-zero-notice.ts +6 -1
- package/scripts/hooks/stop-actions.ts +3 -15
- package/scripts/hooks/stop-guard.ts +7 -6
- package/scripts/init/distributed-paths.ts +1 -0
- package/scripts/init/hook-command-rewrite.ts +5 -1
- package/scripts/init/hook-launch.ts +4 -2
- package/scripts/issue/aggregation-split.ts +52 -0
- package/scripts/issue/defect-origin-line.ts +19 -1
- package/scripts/issue/defect-rate-cli.ts +5 -102
- package/scripts/issue/defect-report.ts +4 -4
- package/scripts/issue/effect-audit-cli.ts +178 -0
- package/scripts/issue/effect-audit.ts +185 -0
- package/scripts/issue/expected-effect-lint.ts +64 -9
- package/scripts/issue/git-next-issues.ts +5 -0
- package/scripts/issue/issue-body-or-comment.ts +38 -4
- package/scripts/issue/issue-cite-cli.ts +1 -3
- package/scripts/issue/issue-classification.ts +1 -0
- package/scripts/issue/issue-closing-pr.ts +8 -1
- package/scripts/issue/issue-evidence-exit.ts +4 -2
- package/scripts/issue/issue-file-cap.ts +58 -0
- package/scripts/issue/issue-file-cli.ts +111 -38
- package/scripts/issue/issue-file-deferral.ts +52 -0
- package/scripts/issue/issue-file-fold.ts +29 -10
- package/scripts/issue/issue-file-interrupt.ts +85 -0
- package/scripts/issue/issue-file-lane-hint.ts +30 -0
- package/scripts/issue/issue-file.ts +43 -6
- package/scripts/issue/issue-labels.ts +19 -2
- package/scripts/issue/issue-lint-cli.ts +27 -2
- package/scripts/issue/issue-measured-cli.ts +13 -35
- package/scripts/issue/issue-measured-close.ts +58 -0
- package/scripts/issue/issue-not-before-label.ts +2 -2
- package/scripts/issue/issue-not-before.ts +4 -1
- package/scripts/issue/issue-priority-cli.ts +60 -0
- package/scripts/issue/issue-priority-raise.ts +55 -0
- package/scripts/issue/issue-priority.ts +174 -43
- package/scripts/issue/issue-rank.ts +21 -4
- package/scripts/issue/issue-read-cli.ts +32 -6
- package/scripts/issue/issue-read.ts +37 -12
- package/scripts/issue/issue-sample-gate.ts +95 -74
- package/scripts/issue/issue-sample-prime.ts +127 -0
- package/scripts/issue/issue-sample-required.ts +57 -0
- package/scripts/issue/issue-sample-source.ts +12 -11
- package/scripts/issue/issue-search.ts +124 -0
- package/scripts/issue/issue-state.ts +13 -1
- package/scripts/issue/issue-template-section.ts +43 -0
- package/scripts/issue/issue-watch-diff.ts +31 -1
- package/scripts/issue/issue-watch-hook.ts +11 -2
- package/scripts/issue/issue-watch.ts +55 -12
- package/scripts/issue/markdown-section.ts +1 -0
- package/scripts/issue/measure-declaration.ts +121 -0
- package/scripts/issue/measure-rerun-cli.ts +7 -70
- package/scripts/issue/plan-consumers-section.ts +22 -1
- package/scripts/issue/reproduction-measure.ts +3 -1
- package/scripts/issue/size-estimate.ts +90 -0
- package/scripts/issue/trusted-measure.ts +84 -0
- package/scripts/josh/command-usage.ts +3 -2
- package/scripts/josh/durable-state-migrate.ts +105 -0
- package/scripts/josh/durable-state.ts +112 -0
- package/scripts/josh/josh-aliases.ts +95 -0
- package/scripts/josh/josh-command-map.ts +1 -82
- package/scripts/josh/josh-commands-agent-hooks.ts +6 -6
- package/scripts/josh/josh-commands-ai.ts +5 -5
- package/scripts/josh/josh-commands-development.ts +59 -58
- package/scripts/josh/josh-commands-issue-write.ts +23 -4
- package/scripts/josh/josh-commands-issue.ts +32 -0
- package/scripts/josh/josh-commands-lane.ts +87 -4
- package/scripts/josh/josh-commands-lint.ts +16 -3
- package/scripts/josh/josh-commands-maintenance.ts +15 -0
- package/scripts/josh/josh-commands-review.ts +41 -6
- package/scripts/josh/josh-commands-ship.ts +56 -8
- package/scripts/josh/josh-commands-test-check.ts +80 -0
- package/scripts/josh/josh-commands-workflow.ts +1 -1
- package/scripts/josh/josh-environment-file.ts +43 -3
- package/scripts/josh/josh-in-process.ts +2 -2
- package/scripts/josh/josh-logic.ts +5 -3
- package/scripts/josh/josh-run.ts +19 -1
- package/scripts/josh/run-record-path.ts +15 -0
- package/scripts/josh/stamp-file.ts +11 -2
- package/scripts/lane/lane-adopt-cli.ts +98 -0
- package/scripts/lane/lane-adopt.ts +208 -0
- package/scripts/lane/lane-await.ts +5 -8
- package/scripts/lane/lane-baseline.ts +123 -0
- package/scripts/lane/lane-breakdown-cli.ts +64 -0
- package/scripts/lane/lane-breakdown-implement.ts +170 -0
- package/scripts/lane/lane-breakdown-laps.ts +107 -0
- package/scripts/lane/lane-breakdown-pinned.ts +76 -0
- package/scripts/lane/lane-breakdown-text.ts +145 -0
- package/scripts/lane/lane-breakdown.ts +239 -0
- package/scripts/lane/lane-check-stats.ts +29 -8
- package/scripts/lane/lane-child-invocation.ts +9 -2
- package/scripts/lane/lane-child-mark-keys.ts +12 -0
- package/scripts/lane/lane-child-marker.ts +20 -1
- package/scripts/lane/lane-ci-path-stats.ts +73 -0
- package/scripts/lane/lane-claim-stats.ts +84 -0
- package/scripts/lane/lane-close.ts +8 -3
- package/scripts/lane/lane-dispatch-log.ts +3 -3
- package/scripts/lane/lane-dispatch.ts +2 -2
- package/scripts/lane/lane-gap-stats.ts +7 -6
- package/scripts/lane/lane-guard-policy.ts +7 -1
- package/scripts/lane/lane-implement-stats.ts +207 -0
- package/scripts/lane/lane-implement-subagents.ts +90 -0
- package/scripts/lane/lane-investigation-switch.ts +16 -0
- package/scripts/lane/lane-ledger-kind.ts +31 -0
- package/scripts/lane/lane-ledger-schema-ship.ts +49 -0
- package/scripts/lane/lane-ledger-schema.ts +119 -36
- package/scripts/lane/lane-ledger-write.ts +257 -0
- package/scripts/lane/lane-ledger.ts +31 -177
- package/scripts/lane/lane-load.ts +1 -1
- package/scripts/lane/lane-measure-cli.ts +176 -59
- package/scripts/lane/lane-net-read.ts +44 -0
- package/scripts/lane/lane-net-time.ts +212 -0
- package/scripts/lane/lane-open.ts +16 -7
- package/scripts/lane/lane-output.ts +2 -4
- package/scripts/lane/lane-overrun-prompt.ts +147 -0
- package/scripts/lane/lane-overrun.ts +274 -0
- package/scripts/lane/lane-paths.ts +24 -1
- package/scripts/lane/lane-pause-cli.ts +4 -1
- package/scripts/lane/lane-paused-spans.ts +97 -0
- package/scripts/lane/lane-plan-check.ts +207 -0
- package/scripts/lane/lane-plan-cli.ts +41 -0
- package/scripts/lane/lane-plan.ts +144 -0
- package/scripts/lane/lane-registry.ts +14 -1
- package/scripts/lane/lane-relaunch.ts +1 -1
- package/scripts/lane/lane-round-one-stats.ts +51 -0
- package/scripts/lane/lane-sampler.ts +23 -4
- package/scripts/lane/lane-session-action.ts +93 -18
- package/scripts/lane/lane-session-broker.ts +49 -21
- package/scripts/lane/lane-session-reread-main.ts +14 -0
- package/scripts/lane/lane-session-reread.ts +51 -0
- package/scripts/lane/lane-ship-lap-stats.ts +74 -0
- package/scripts/lane/lane-sleep.ts +58 -0
- package/scripts/lane/lane-spent.ts +1 -1
- package/scripts/lane/lane-split-stats.ts +28 -0
- package/scripts/lane/lane-stage-stats.ts +13 -1
- package/scripts/lane/lane-state.ts +41 -9
- package/scripts/lane/lane-stats-tables.ts +58 -0
- package/scripts/lane/lane-stats.ts +21 -5
- package/scripts/lane/lane-stop-stats.ts +51 -19
- package/scripts/lane/lane-tail-stats.ts +32 -0
- package/scripts/lane/lane-transcript-calls.ts +67 -10
- package/scripts/lane/lane-transcript-stats.ts +44 -12
- package/scripts/lane/lane-value-cell.ts +72 -0
- package/scripts/lane/lane-value.ts +118 -0
- package/scripts/lane/lane-withdraw-closed.ts +124 -0
- package/scripts/lane/lane-withdraw.ts +108 -31
- package/scripts/lane/lane-yield.ts +85 -0
- package/scripts/lane/openai-lane-ship.ts +12 -11
- package/scripts/lane/openai-lane-supervisor-decision.ts +6 -8
- package/scripts/lane/openai-lane-supervisor-owner.ts +5 -8
- package/scripts/lane/openai-lane-supervisor.ts +5 -4
- package/scripts/lib/poll.ts +38 -9
- package/scripts/lib/settled-together.ts +10 -0
- package/scripts/lib/shell-quote.ts +21 -0
- package/scripts/lib/token-shape.ts +111 -0
- package/scripts/lint/eslint-daemon-sources.ts +79 -0
- package/scripts/lint/eslint-daemon.ts +45 -6
- package/scripts/lint/eslint-warm-cli.ts +7 -0
- package/scripts/lint/eslint-warm.ts +66 -0
- package/scripts/lint/import-graph.ts +141 -11
- package/scripts/lint/lint-gate-scope.ts +2 -2
- package/scripts/lint/lint-parallel.ts +54 -6
- package/scripts/lint/lint-related.ts +154 -33
- package/scripts/lint/rename-cli.ts +179 -0
- package/scripts/lint/rename-identifier.ts +192 -0
- package/scripts/lint/type-only-imports.ts +58 -0
- package/scripts/notify/telegram-notify.ts +12 -3
- package/scripts/observations/observation-record.ts +42 -16
- package/scripts/observations/observations-flush.ts +32 -9
- package/scripts/overrides/overrides-check.ts +9 -1
- package/scripts/release/release-approval-prune.ts +7 -1
- package/scripts/repo/required-checks-logic.ts +4 -1
- package/scripts/repo/ruleset-check.ts +4 -3
- package/scripts/report/markdown-shape.ts +28 -0
- package/scripts/report/report-format-reference.ts +15 -1
- package/scripts/report/report-labels.ts +12 -1
- package/scripts/report/report-lint-child-summary.ts +94 -0
- package/scripts/report/report-lint-cli.ts +26 -7
- package/scripts/report/report-lint.ts +2 -20
- package/scripts/review/prose-stale-cli.ts +88 -0
- package/scripts/review/prose-stale-scan.ts +152 -0
- package/scripts/review/review-attest.ts +73 -23
- package/scripts/review/review-brief-cli.ts +68 -19
- package/scripts/review/review-brief-paths.ts +22 -0
- package/scripts/review/review-brief.ts +14 -7
- package/scripts/review/review-comment-carry.ts +47 -0
- package/scripts/review/review-comment-round.ts +85 -22
- package/scripts/review/review-finding-ledger.ts +109 -7
- package/scripts/review/review-finding-text.ts +43 -0
- package/scripts/review/review-interaction.ts +11 -0
- package/scripts/review/review-lane-handover.ts +68 -0
- package/scripts/review/review-lint-cli.ts +57 -0
- package/scripts/review/review-lint-findings.ts +92 -0
- package/scripts/review/review-lint-sections.ts +80 -0
- package/scripts/review/review-lint.ts +221 -0
- package/scripts/review/review-prior-findings.ts +102 -0
- package/scripts/review/review-readers-scan.ts +4 -2
- package/scripts/review/review-record-cli.ts +177 -54
- package/scripts/review/review-record-code-round.ts +55 -0
- package/scripts/review/review-record-comment.ts +60 -0
- package/scripts/review/review-record-interaction.ts +35 -0
- package/scripts/review/review-record-pinned.ts +108 -0
- package/scripts/review/review-record.ts +25 -1
- package/scripts/review/review-reviewed-tree.ts +307 -0
- package/scripts/review/review-round-one-closure.ts +62 -0
- package/scripts/review/review-round-reuse.ts +106 -0
- package/scripts/review/review-round2-cli.ts +91 -29
- package/scripts/review/review-round2-skip-comment.ts +55 -0
- package/scripts/review/review-round2.ts +24 -8
- package/scripts/review/review-stamps.ts +7 -3
- package/scripts/review/review-stop-log.ts +20 -6
- package/scripts/review/review-stops-cli.ts +2 -1
- package/scripts/review/review-submit-cli.ts +101 -0
- package/scripts/rules/agent-model.ts +1 -1
- package/scripts/rules/bash-triggers.ts +3 -3
- package/scripts/rules/concise-reply.ts +88 -0
- package/scripts/rules/credential-body.ts +77 -0
- package/scripts/rules/decision-oracle.ts +1 -1
- package/scripts/rules/delivered-rules.ts +36 -17
- package/scripts/rules/destructive-command.ts +3 -11
- package/scripts/rules/direct-issue-comment.ts +34 -12
- package/scripts/rules/direct-issue-read.ts +191 -0
- package/scripts/rules/direct-pr-create.ts +4 -24
- package/scripts/rules/early-heartbeat.ts +2 -0
- package/scripts/rules/edit-tool.ts +27 -0
- package/scripts/rules/file-edit-rows.ts +17 -0
- package/scripts/rules/file-rewrite.ts +146 -0
- package/scripts/rules/firing-point.ts +3 -2
- package/scripts/rules/gh-api.ts +128 -7
- package/scripts/rules/gh-repo-selector.ts +84 -0
- package/scripts/rules/git-force.ts +2 -2
- package/scripts/rules/guard-remedy.ts +14 -5
- package/scripts/rules/implementation-cut.ts +61 -28
- package/scripts/rules/investigator-foreground.ts +231 -0
- package/scripts/rules/issue-citation.ts +15 -60
- package/scripts/rules/issue-comments.ts +9 -4
- package/scripts/rules/josh-git-bare.ts +1 -1
- package/scripts/rules/lane-background.ts +41 -13
- package/scripts/rules/lane-direct-tool.ts +107 -9
- package/scripts/rules/lane-interactive-ask.ts +4 -1
- package/scripts/rules/lane-park.ts +4 -2
- package/scripts/rules/lane-spilled-read.ts +90 -0
- package/scripts/rules/lane-split-park.ts +1 -1
- package/scripts/rules/lane-switch-main.ts +4 -4
- package/scripts/rules/last-prompt.ts +20 -47
- package/scripts/rules/oracle-consulted.ts +1 -1
- package/scripts/rules/permission-guards.ts +5 -1
- package/scripts/rules/piped-verification-shapes.ts +110 -0
- package/scripts/rules/piped-verification.ts +67 -17
- package/scripts/rules/poll-loop.ts +72 -9
- package/scripts/rules/pr-merge.ts +5 -5
- package/scripts/rules/pre-gate-cut.ts +3 -3
- package/scripts/rules/protected-files.ts +88 -24
- package/scripts/rules/reply-language.ts +3 -17
- package/scripts/rules/reply-prose.ts +34 -0
- package/scripts/rules/repo-admin.ts +132 -0
- package/scripts/rules/reviewer-foreground.ts +88 -0
- package/scripts/rules/round-one-check-related.ts +120 -0
- package/scripts/rules/rule-body-guard.ts +5 -15
- package/scripts/rules/rule-value-cache.ts +53 -5
- package/scripts/rules/rule-value-candidates.ts +84 -0
- package/scripts/rules/rule-value-cli.ts +59 -11
- package/scripts/rules/rule-value.ts +17 -4
- package/scripts/rules/run-tail-rule.ts +1 -1
- package/scripts/rules/sed-in-place.ts +196 -0
- package/scripts/rules/shell-segments.ts +10 -2
- package/scripts/rules/stop-rule-rows.ts +1 -13
- package/scripts/rules/stop-rules.ts +33 -58
- package/scripts/rules/test-declared-commit.ts +1 -1
- package/scripts/rules/third-party-write.ts +110 -23
- package/scripts/rules/timed-rerun.ts +1 -1
- package/scripts/rules/turn-filings.ts +90 -0
- package/scripts/rules/worktree-guard.ts +22 -7
- package/scripts/run/board/run-board-ending-reason.ts +6 -2
- package/scripts/run/board/run-board-fit.ts +24 -1
- package/scripts/run/board/run-board-found.ts +134 -0
- package/scripts/run/board/run-board-header.ts +8 -0
- package/scripts/run/board/run-board-labels.ts +11 -1
- package/scripts/run/board/run-board-lane-time.ts +1 -0
- package/scripts/run/board/run-board-link.ts +15 -2
- package/scripts/run/board/run-board-notes.ts +7 -1
- package/scripts/run/board/run-board-operation.ts +4 -2
- package/scripts/run/board/run-board-phase.ts +2 -5
- package/scripts/run/board/run-board-plan.ts +1 -1
- package/scripts/run/board/run-board-read.ts +46 -1
- package/scripts/run/board/run-board-reason.ts +20 -8
- package/scripts/run/board/run-board-render-checks.ts +3 -2
- package/scripts/run/board/run-board-render-drawn.ts +11 -0
- package/scripts/run/board/run-board-render-found.ts +157 -0
- package/scripts/run/board/run-board-render-lead.ts +9 -0
- package/scripts/run/board/run-board-render-legend.ts +19 -0
- package/scripts/run/board/run-board-render-tail.ts +1 -1
- package/scripts/run/board/run-board-render.ts +82 -18
- package/scripts/run/board/run-board-spin.ts +1 -3
- package/scripts/run/board/run-board-status.ts +2 -0
- package/scripts/run/board/run-board-tick.ts +39 -10
- package/scripts/run/carry/run-carry-ended.ts +3 -2
- package/scripts/run/carry/run-carry.ts +3 -2
- package/scripts/run/cut/run-cut-cli.ts +33 -133
- package/scripts/run/cut/run-cut-digest.ts +152 -0
- package/scripts/run/cut/run-cut-handoff.ts +52 -8
- package/scripts/run/cut/run-cut-report.ts +24 -3
- package/scripts/run/cut/run-cut-resume.ts +129 -0
- package/scripts/run/cut/run-cut-review.ts +105 -0
- package/scripts/run/cut/run-cut.ts +18 -7
- package/scripts/run/detached-launch.ts +1 -1
- package/scripts/run/entry/run-entry-cli.ts +88 -19
- package/scripts/run/entry/run-entry-spill.ts +83 -0
- package/scripts/run/entry/run-entry-stop.ts +5 -1
- package/scripts/run/entry/run-entry-trust.ts +91 -0
- package/scripts/run/event/run-event-baseline.ts +56 -0
- package/scripts/run/event/run-event-filed.ts +9 -3
- package/scripts/run/event/run-event-overrun.ts +197 -0
- package/scripts/run/event/run-event-render.ts +4 -0
- package/scripts/run/event/run-event-stream.ts +25 -3
- package/scripts/run/hold/run-stop-notify.ts +3 -8
- package/scripts/run/merge/run-merge-cap.ts +57 -0
- package/scripts/run/merge/run-merge-cli.ts +66 -23
- package/scripts/run/merge/run-merge-outcome.ts +2 -0
- package/scripts/run/merge/run-merge-ship.ts +13 -3
- package/scripts/run/merge/run-merge-signals.ts +40 -23
- package/scripts/run/merge/run-merge-steps.ts +56 -36
- package/scripts/run/merge/run-merge-usage-limit.ts +53 -0
- package/scripts/run/merge/run-merge-withdrawn.ts +53 -0
- package/scripts/run/merge/run-merge.ts +41 -14
- package/scripts/run/review/run-review-cli.ts +306 -20
- package/scripts/run/review/run-review-early-push.ts +121 -0
- package/scripts/run/review/run-review-join-read.ts +94 -0
- package/scripts/run/review/run-review-pinned-accepted.ts +126 -0
- package/scripts/run/review/run-review-pinned-join.ts +216 -0
- package/scripts/run/review/run-review-pinned-steps.ts +383 -0
- package/scripts/run/review/run-review-pinned-tree.ts +37 -0
- package/scripts/run/review/run-review-pinned.ts +53 -0
- package/scripts/run/review/run-review-steps.ts +70 -34
- package/scripts/run/review/run-review.ts +26 -6
- package/scripts/run/run-parent-cut-hook.ts +3 -4
- package/scripts/run/run-prep.ts +1 -0
- package/scripts/run/run-stage-read.ts +2 -6
- package/scripts/run/run-step-cli.ts +17 -5
- package/scripts/run/run-step-lane-plan.ts +27 -0
- package/scripts/run/run-step-section.ts +26 -7
- package/scripts/run/run-step.ts +5 -2
- package/scripts/run/ship/run-ship-args.ts +19 -0
- package/scripts/run/ship/run-ship-brokered-review.ts +106 -0
- package/scripts/run/ship/run-ship-cli.ts +131 -39
- package/scripts/run/ship/run-ship-conflict-probe.ts +59 -0
- package/scripts/run/ship/run-ship-detach.ts +10 -4
- package/scripts/run/ship/run-ship-handover.ts +106 -0
- package/scripts/run/ship/run-ship-infra-retry.ts +16 -1
- package/scripts/run/ship/run-ship-lap.ts +63 -0
- package/scripts/run/ship/run-ship-next.ts +27 -26
- package/scripts/run/ship/run-ship-overlap.ts +8 -3
- package/scripts/run/ship/run-ship-place.ts +9 -2
- package/scripts/run/ship/run-ship-planned.ts +92 -0
- package/scripts/run/ship/run-ship-pre-detach-pinned.ts +197 -0
- package/scripts/run/ship/run-ship-pre-detach-timed.ts +7 -8
- package/scripts/run/ship/run-ship-pre-detach.ts +77 -23
- package/scripts/run/ship/run-ship-preflight.ts +16 -4
- package/scripts/run/ship/run-ship-probe.ts +23 -9
- package/scripts/run/ship/run-ship-relaunch-cap.ts +43 -7
- package/scripts/run/ship/run-ship-relaunch.ts +51 -0
- package/scripts/run/ship/run-ship-return.ts +103 -29
- package/scripts/run/ship/run-ship-review-reason.ts +24 -0
- package/scripts/run/ship/run-ship-review-steps.ts +230 -59
- package/scripts/run/ship/run-ship-review.ts +171 -51
- package/scripts/run/ship/run-ship-reviewer.ts +138 -42
- package/scripts/run/ship/run-ship-scoped.ts +39 -10
- package/scripts/run/ship/run-ship-stage.ts +49 -13
- package/scripts/run/ship/run-ship-steps.ts +24 -4
- package/scripts/run/ship/run-ship-stop-cause.ts +43 -2
- package/scripts/run/ship/run-ship-stop-context.ts +50 -13
- package/scripts/run/ship/run-ship-sync.ts +171 -30
- package/scripts/run/ship/run-ship-synced-scope.ts +178 -0
- package/scripts/run/ship/run-ship-wait-cli.ts +145 -0
- package/scripts/run/ship/run-ship-waiter.ts +114 -0
- package/scripts/run/ship/run-ship.ts +16 -2
- package/scripts/run/wake/run-wake-caffeinate.ts +48 -0
- package/scripts/run/wake/run-wake-cli.ts +6 -113
- package/scripts/run/wake/run-wake-code.ts +53 -11
- package/scripts/run/wake/run-wake-driver.ts +5 -3
- package/scripts/run/wake/run-wake-finish.ts +137 -0
- package/scripts/run/wake/run-wake-loop.ts +5 -3
- package/scripts/run/wake/run-wake-ports.ts +11 -3
- package/scripts/run/wake/run-wake-session.ts +2 -0
- package/scripts/run/wake/run-wake.ts +3 -2
- package/scripts/safe-chain/ci-installer-pin.ts +49 -8
- package/scripts/safe-chain/project-config.ts +3 -2
- package/scripts/security/secretlint-scan.ts +42 -9
- package/scripts/security/security-audit-provision-main.ts +9 -1
- package/scripts/security/security-audit-provision.ts +1 -1
- package/scripts/security/security-audit.ts +21 -1
- package/scripts/security/sonar-file.ts +10 -5
- package/scripts/split/split-assess.ts +12 -3
- package/scripts/split/split-early-notice.ts +116 -0
- package/scripts/split/split-measure.ts +20 -2
- package/scripts/split/split-resolution.ts +107 -0
- package/scripts/test/direct-importers.ts +185 -0
- package/scripts/test/pure-files-entries.ts +83 -0
- package/scripts/test/related-heavy-tests.ts +81 -0
- package/scripts/test/test-no-base.ts +88 -0
- package/scripts/test/test-pinned-cache-logic.ts +363 -0
- package/scripts/test/test-pinned-cache.ts +337 -0
- package/scripts/test/test-pinned-emit.ts +49 -0
- package/scripts/test/test-pinned-functions.ts +116 -0
- package/scripts/test/test-pinned-ledger.ts +80 -0
- package/scripts/test/test-pinned-logic.ts +208 -20
- package/scripts/test/test-pinned-main.ts +84 -18
- package/scripts/test/test-pinned-pool.ts +73 -0
- package/scripts/test/test-pinned-probe.ts +254 -0
- package/scripts/test/test-pinned-prune-logic.ts +118 -0
- package/scripts/test/test-pinned-reach.ts +194 -0
- package/scripts/test/test-pinned-record.ts +196 -0
- package/scripts/test/test-pinned-rewire.ts +148 -0
- package/scripts/test/test-pinned-spawn.ts +81 -0
- package/scripts/test/test-pinned-stage.ts +70 -0
- package/scripts/test/test-pinned.ts +258 -47
- package/scripts/test/test-reach-cli.ts +61 -0
- package/scripts/test/test-read-map.ts +35 -11
- package/scripts/test/test-read-recording.ts +17 -5
- package/scripts/test/test-read-trace.ts +26 -8
- package/scripts/test/test-red-logic.ts +46 -7
- package/scripts/test/test-red.ts +34 -14
- package/scripts/test/test-related-claim.ts +37 -0
- package/scripts/test/test-related-main.ts +4 -1
- package/scripts/test/test-related-moved.ts +91 -0
- package/scripts/test/test-related-record.ts +43 -23
- package/scripts/test/test-related-scope.ts +99 -34
- package/scripts/test/test-related-synced.ts +135 -0
- package/scripts/test/test-related-touched.ts +84 -0
- package/scripts/test/test-related.ts +167 -83
- package/scripts/test/test-unit-guard.ts +28 -5
- package/scripts/test/unit-durations.ts +41 -0
- package/scripts/test/unit-worker-share.ts +5 -4
- package/scripts/test/vitest-cache-directory.ts +19 -0
- package/scripts/test/vitest-cli-excludes.ts +14 -0
- package/scripts/test/vitest-failure-summary.ts +111 -0
- package/scripts/test/whole-suite-files.ts +12 -1
- package/scripts/time-runtime/time-batch-guard.ts +42 -4
- package/scripts/time-runtime/time-bundle-call.ts +1 -1
- package/scripts/time-runtime/time-bundles.ts +36 -5
- package/scripts/time-runtime/time-markers.ts +2 -2
- package/scripts/time-runtime/time-search-call.ts +38 -0
- package/scripts/time-runtime/time-shell.ts +1 -1
- package/scripts/time-runtime/time-transcript-line.ts +17 -5
- package/scripts/version/development-engines-verdict.ts +124 -0
- package/scripts/version/latest-corepack.ts +2 -0
- package/templates/gitignore +2 -0
- package/templates/workflows/ci.yml +41 -0
- package/dist/hooks/chunk-AZX4FGQ3.js +0 -207
- package/dist/hooks/chunk-PT5R6UJD.js +0 -7131
- package/dist/hooks/chunk-TUIFS5E7.js +0 -72
- package/dist/hooks/chunk-YCDOIR3I.js +0 -3456
- package/scripts/cost-runtime/context-cut-threshold.ts +0 -11
- package/scripts/rules/filing-cap.ts +0 -139
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// One word for a POSIX shell, in single quotes, so a `$`, a backtick or a `"` in it is never expanded
|
|
2
|
+
// or ends the word: a quote inside closes the word, adds an escaped quote and reopens it.
|
|
3
|
+
|
|
4
|
+
const QUOTE = "'"
|
|
5
|
+
const ESCAPED_QUOTE = String.raw`'\''`
|
|
6
|
+
|
|
7
|
+
function single_quoted(text: string): string {
|
|
8
|
+
return QUOTE + text.split(QUOTE).join(ESCAPED_QUOTE) + QUOTE
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// A token of only these characters means the same to the shell quoted or not, so it is left bare.
|
|
12
|
+
const BARE_WORD = /^[\w%+,./:=@-]+$/u
|
|
13
|
+
|
|
14
|
+
// `token` as one shell word: bare when quoting would change nothing, single-quoted otherwise.
|
|
15
|
+
function word(token: string): string {
|
|
16
|
+
return BARE_WORD.test(token) ? token : single_quoted(token)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const shell_quote = { single_quoted, word }
|
|
20
|
+
|
|
21
|
+
export { shell_quote }
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// cspell:words xoxb xoxp xapp xoxa xoxo xoxr
|
|
2
|
+
import { json_value } from './json-value'
|
|
3
|
+
|
|
4
|
+
// The credential shapes a body kit sends out is refused for, and the run board hides. **One list, read
|
|
5
|
+
// in-process**: every outbound body passes through here, so a regex costs microseconds where a
|
|
6
|
+
// secretlint spawn per send would cost a second.
|
|
7
|
+
//
|
|
8
|
+
// Each shape with a `secretlint` rule matches what that preset rule matches — the preset bundles its
|
|
9
|
+
// rules and exports none of their patterns, so each is restated here — and `token-shape.test.ts` runs
|
|
10
|
+
// secretlint over every shape's sample, so a pattern that drifts from the preset fails there. A shape
|
|
11
|
+
// with no rule is kit's own.
|
|
12
|
+
|
|
13
|
+
interface TokenShape {
|
|
14
|
+
name: string
|
|
15
|
+
pattern: RegExp
|
|
16
|
+
// The preset rule that flags the same shape; `undefined` for one only kit knows.
|
|
17
|
+
secretlint: string | undefined
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const REDACTED = '[REDACTED]'
|
|
21
|
+
const GITHUB_RULE = '@secretlint/secretlint-rule-github'
|
|
22
|
+
|
|
23
|
+
// `claude setup-token`'s output: no preset rule knows it, and `claude-token-output.ts` captures it.
|
|
24
|
+
const ANTHROPIC_OAUTH_TOKEN = /sk-ant-oat\d+-[\w-]+/u
|
|
25
|
+
|
|
26
|
+
const SHAPES: ReadonlyArray<TokenShape> = [
|
|
27
|
+
{
|
|
28
|
+
name: 'GitHub token',
|
|
29
|
+
pattern: /(?<!\p{L})(?:ghp|gho|ghu|ghs|ghr)_\w{36}(?!\w)/u,
|
|
30
|
+
secretlint: GITHUB_RULE,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: 'GitHub App installation token',
|
|
34
|
+
pattern: /(?<!\p{L})ghs_\d{1,20}_[\w-]{1,1000}\.[\w-]{1,10000}\.[\w-]{1,1000}(?![\w-])/u,
|
|
35
|
+
secretlint: GITHUB_RULE,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: 'GitHub fine-grained token',
|
|
39
|
+
pattern: /(?<!\p{L})github_pat_\w{82}(?!\w)/u,
|
|
40
|
+
secretlint: GITHUB_RULE,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: 'Slack token',
|
|
44
|
+
pattern:
|
|
45
|
+
/\b(?:xoxb|xoxp|xapp|xoxa|xoxo|xoxr)-(?:\d-)?(?:[a-zA-Z0-9]{1,40}-)+[a-zA-Z0-9]{1,40}\b/u,
|
|
46
|
+
secretlint: '@secretlint/secretlint-rule-slack',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: 'Anthropic API key',
|
|
50
|
+
pattern: /(?<!\p{L})sk-ant-api0\d-[\w-]{90,128}AA(?![\w-])/u,
|
|
51
|
+
secretlint: '@secretlint/secretlint-rule-anthropic',
|
|
52
|
+
},
|
|
53
|
+
{ name: 'Anthropic OAuth token', pattern: ANTHROPIC_OAUTH_TOKEN, secretlint: undefined },
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
const EVERY_SHAPE = new RegExp(SHAPES.map((shape) => shape.pattern.source).join('|'), 'gu')
|
|
57
|
+
|
|
58
|
+
// The first shape `text` holds, `undefined` for none.
|
|
59
|
+
function find(text: string): TokenShape | undefined {
|
|
60
|
+
return SHAPES.find((shape) => shape.pattern.test(text))
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Whether `text` holds any shape — `find`'s test without the shape it names.
|
|
64
|
+
function holds(text: string): boolean {
|
|
65
|
+
return SHAPES.some((shape) => shape.pattern.test(text))
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Throws when `text` holds a credential, naming the shape and never the value: `subject` is what was
|
|
69
|
+
// about to be sent, so the refusal says which send stopped.
|
|
70
|
+
function refuse(text: string, subject: string): void {
|
|
71
|
+
const shape = find(text)
|
|
72
|
+
if (shape === undefined) return
|
|
73
|
+
|
|
74
|
+
throw new Error(
|
|
75
|
+
`${subject} holds a ${shape.name}-shaped string, so it was not sent. Remove the credential and send it again.`,
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function redact(text: string): string {
|
|
80
|
+
return text.replaceAll(EVERY_SHAPE, () => REDACTED)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// A JSON-encoded body puts a token starting a line after the `n` of an escaped newline, and the
|
|
84
|
+
// shapes' "no letter before it" guard reads that `n` as a letter. So a body is scanned as the strings
|
|
85
|
+
// its JSON decodes to — what GitHub stores — and as raw text only when it is not JSON.
|
|
86
|
+
function string_leaves(value: unknown): Array<string> {
|
|
87
|
+
if (typeof value === 'string') return [value]
|
|
88
|
+
if (typeof value !== 'object' || value === null) return []
|
|
89
|
+
|
|
90
|
+
return Object.values(value).flatMap((entry: unknown) => string_leaves(entry))
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function decoded(body: string): string {
|
|
94
|
+
const value = json_value.parse_or_undefined(body)
|
|
95
|
+
|
|
96
|
+
return value === undefined ? body : string_leaves(value).join('\n')
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const token_shape = {
|
|
100
|
+
ANTHROPIC_OAUTH_TOKEN,
|
|
101
|
+
REDACTED,
|
|
102
|
+
SHAPES,
|
|
103
|
+
decoded,
|
|
104
|
+
find,
|
|
105
|
+
holds,
|
|
106
|
+
refuse,
|
|
107
|
+
redact,
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export { token_shape }
|
|
111
|
+
export type { TokenShape }
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto'
|
|
2
|
+
import { readFileSync } from 'node:fs'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import { git_spawn_sync } from '#scripts/git/git-spawn-sync'
|
|
5
|
+
|
|
6
|
+
// **What the daemon's type program may hold an old copy of: every file whose content differs from the
|
|
7
|
+
// commit checked out.** The program keeps each source it read but did not lint, and never re-reads it,
|
|
8
|
+
// so a shell edit to an imported module — one the edit hook never sees — left typed rules failing on
|
|
9
|
+
// the module's old exports, and the cache guard then recorded that verdict under the new closure hash,
|
|
10
|
+
// so it replayed even after the daemon was stopped (joshuafolkken/kit#4867). A file equal to HEAD is
|
|
11
|
+
// already covered by the HEAD in the fingerprint, so only the changed ones are hashed: one entry each,
|
|
12
|
+
// `<path>\t<content digest>`, one per line, sorted.
|
|
13
|
+
//
|
|
14
|
+
// The edit hook lints the file it edited through the daemon, which reads it fresh, so it refreshes
|
|
15
|
+
// that one entry (`refresh`); an edit it never saw leaves the entry behind, and the next run restarts.
|
|
16
|
+
|
|
17
|
+
// NUL-separated, so a path git would quote and escape — any non-ASCII name — reads as the file it is.
|
|
18
|
+
const CHANGED_FILES: ReadonlyArray<string> = ['diff', 'HEAD', '--name-only', '--relative', '-z']
|
|
19
|
+
const NEW_FILES: ReadonlyArray<string> = ['ls-files', '--others', '--exclude-standard', '-z']
|
|
20
|
+
const PATH_SEPARATOR = '\0'
|
|
21
|
+
const LINE_SEPARATOR = '\n'
|
|
22
|
+
const ENTRY_SEPARATOR = '\t'
|
|
23
|
+
const DIGEST_ALGORITHM = 'sha256'
|
|
24
|
+
const ABSENT = 'absent'
|
|
25
|
+
const UNREAD = ':unread'
|
|
26
|
+
|
|
27
|
+
// One order for `snapshot` and `refresh` alike, so a refreshed record compares equal to a fresh one.
|
|
28
|
+
function by_text(left: string, right: string): number {
|
|
29
|
+
return left.localeCompare(right)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function lines_of(text: string): ReadonlyArray<string> {
|
|
33
|
+
return text.split(LINE_SEPARATOR).filter((line) => line !== '')
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function content_digest(file: string): string {
|
|
37
|
+
try {
|
|
38
|
+
return createHash(DIGEST_ALGORITHM).update(readFileSync(file)).digest('hex')
|
|
39
|
+
} catch {
|
|
40
|
+
return ABSENT
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// A git that could not answer lists a path no file has, so its record differs from one with no changes.
|
|
45
|
+
function changed_paths(project_root: string): ReadonlyArray<string> {
|
|
46
|
+
const listed = [CHANGED_FILES, NEW_FILES].map(
|
|
47
|
+
(git_arguments) => git_spawn_sync.read(git_arguments, { cwd: project_root }) ?? UNREAD,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
const paths = listed.join(PATH_SEPARATOR).split(PATH_SEPARATOR)
|
|
51
|
+
|
|
52
|
+
return [...new Set(paths.filter((relative) => relative !== ''))]
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// The changed files' entries, sorted — nothing when no file differs from HEAD.
|
|
56
|
+
function snapshot(project_root: string): string {
|
|
57
|
+
return changed_paths(project_root)
|
|
58
|
+
.map(
|
|
59
|
+
(relative) =>
|
|
60
|
+
`${relative}${ENTRY_SEPARATOR}${content_digest(path.join(project_root, relative))}`,
|
|
61
|
+
)
|
|
62
|
+
.toSorted(by_text)
|
|
63
|
+
.join(LINE_SEPARATOR)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// A recorded fingerprint — its first line the daemon's other inputs, the rest `snapshot`'s entries —
|
|
67
|
+
// with `relative`'s entry as `current` has it now: the daemon has just read that one file fresh.
|
|
68
|
+
function refresh(recorded: string, current: string, relative: string): string {
|
|
69
|
+
const prefix = `${relative}${ENTRY_SEPARATOR}`
|
|
70
|
+
const [inputs = '', ...entries] = lines_of(recorded)
|
|
71
|
+
const others = entries.filter((line) => !line.startsWith(prefix))
|
|
72
|
+
const fresh = lines_of(current).filter((line) => line.startsWith(prefix))
|
|
73
|
+
|
|
74
|
+
return [inputs, ...[...others, ...fresh].toSorted(by_text)].join(LINE_SEPARATOR)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const eslint_daemon_sources = { refresh, snapshot, LINE_SEPARATOR }
|
|
78
|
+
|
|
79
|
+
export { eslint_daemon_sources }
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto'
|
|
1
2
|
import { lstatSync, readFileSync } from 'node:fs'
|
|
2
3
|
import { createRequire } from 'node:module'
|
|
3
4
|
import path from 'node:path'
|
|
@@ -8,6 +9,7 @@ import { git_spawn_sync } from '#scripts/git/git-spawn-sync'
|
|
|
8
9
|
import { atomic_write } from '#scripts/lib/atomic-write'
|
|
9
10
|
import { buffered_process, type BufferedProcessResult } from '#scripts/lib/buffered-process'
|
|
10
11
|
import { execa } from 'execa'
|
|
12
|
+
import { eslint_daemon_sources } from './eslint-daemon-sources'
|
|
11
13
|
|
|
12
14
|
// One warm eslint per checkout, reached by every eslint run that is not the gate's whole tree: the
|
|
13
15
|
// `PostToolUse` edit hook, `josh lint:related` and the pre-commit hook (joshuafolkken/kit#4358).
|
|
@@ -30,6 +32,9 @@ const DAEMON_RECORD = '.eslint_d'
|
|
|
30
32
|
const FINGERPRINT_RECORD = '.eslint_d-toolchain'
|
|
31
33
|
const RECORD_SEPARATOR = '\n'
|
|
32
34
|
const NO_HEAD = 'no-head'
|
|
35
|
+
// Every file the type program could resolve: tracked, staged by a merge in progress, or new.
|
|
36
|
+
const LIST_FILES: ReadonlyArray<string> = ['ls-files', '--cached', '--others', '--exclude-standard']
|
|
37
|
+
const DIGEST_ALGORITHM = 'sha256'
|
|
33
38
|
|
|
34
39
|
// Where this file sits inside the kit package. `eslint_d` is kit's dependency rather than the
|
|
35
40
|
// consumer's, and pnpm writes a `node_modules/.bin` shim only for a project's *direct* dependencies,
|
|
@@ -91,16 +96,29 @@ function eslint_arguments_of(
|
|
|
91
96
|
return pnpm_arguments.slice(PNPM_ESLINT_PREFIX_LENGTH)
|
|
92
97
|
}
|
|
93
98
|
|
|
99
|
+
function digest_of(text: string): string {
|
|
100
|
+
return createHash(DIGEST_ALGORITHM).update(text).digest('hex')
|
|
101
|
+
}
|
|
102
|
+
|
|
94
103
|
// **What a daemon is current for: the toolchain's content and the commit checked out.** The daemon's
|
|
95
104
|
// type program keeps every source it read but did not lint, so a merge that changes those types leaves
|
|
96
105
|
// typed rules failing on the old ones (joshuafolkken/kit#4443); every merge, checkout, reset, pull and
|
|
97
106
|
// commit moves HEAD, the commands that move sources under the daemon without an edit the hook sees.
|
|
98
107
|
// A content digest rather than a time: a copy or a checkout rewrites every mtime and leaves the
|
|
99
108
|
// content alone, and an edit can keep its old mtime. Outside a repository there is no HEAD.
|
|
109
|
+
// **The files the program can resolve, too**: a merge whose conflicts are being resolved brings main's
|
|
110
|
+
// new modules in without moving HEAD, and a daemon that had built its program before they arrived
|
|
111
|
+
// reported their types as unresolvable until it was stopped (joshuafolkken/kit#4701).
|
|
112
|
+
// **And the content of every file that differs from HEAD**, each on a line of its own after the rest
|
|
113
|
+
// (`eslint-daemon-sources.ts`): an edit the hook lints is read fresh and refreshes its own line, and a
|
|
114
|
+
// shell edit it never saw restarts the daemon (joshuafolkken/kit#4867).
|
|
100
115
|
function fingerprint(project_root: string): string {
|
|
101
116
|
const head = git_spawn_sync.read(['rev-parse', 'HEAD'], { cwd: project_root }) ?? NO_HEAD
|
|
117
|
+
const files = git_spawn_sync.read(LIST_FILES, { cwd: project_root }) ?? NO_HEAD
|
|
118
|
+
const inputs = `${toolchain_inputs.digest(project_root)}:${head}:${digest_of(files)}`
|
|
119
|
+
const sources = eslint_daemon_sources.snapshot(project_root)
|
|
102
120
|
|
|
103
|
-
return `${
|
|
121
|
+
return sources === '' ? inputs : `${inputs}${eslint_daemon_sources.LINE_SEPARATOR}${sources}`
|
|
104
122
|
}
|
|
105
123
|
|
|
106
124
|
// Where the eslint the daemon resolves keeps its record, or nothing without an installed eslint.
|
|
@@ -140,7 +158,7 @@ function record_text(daemon: string, current: string): string {
|
|
|
140
158
|
// so a toolchain input that moved since it started leaves it linting against the old rules, and a
|
|
141
159
|
// HEAD move leaves it typing against the old sources. A daemon this module did not record — another
|
|
142
160
|
// tool started it, or the record is from an older one — is stale too: nothing says what it loaded.
|
|
143
|
-
// The edit hook records the daemons it starts and restarts (`
|
|
161
|
+
// The edit hook records the daemons it starts and restarts (`remember_after_edit`); this catches the rest.
|
|
144
162
|
function is_stale(record: DaemonRecord, current: string): boolean {
|
|
145
163
|
if (record.daemon === undefined) return false
|
|
146
164
|
|
|
@@ -169,10 +187,31 @@ function remember(project_root: string, current: string): void {
|
|
|
169
187
|
// under the inputs as they are now, and a daemon's record changes with every start — so a record that
|
|
170
188
|
// changed across the hook's commands names a daemon they started. Recording it keeps the next lint run
|
|
171
189
|
// from stopping and cold-starting a daemon that is already current.
|
|
172
|
-
|
|
173
|
-
|
|
190
|
+
// A daemon that kept running has read the edited file fresh and nothing else, so only that file's
|
|
191
|
+
// line of a record that is current otherwise is refreshed.
|
|
192
|
+
// A borrowed install's record belongs to the lending checkout, whose files these are not.
|
|
193
|
+
function remember_read(project_root: string, record: DaemonRecord, relative: string): void {
|
|
194
|
+
const { daemon, recorded } = record
|
|
195
|
+
if (daemon === undefined || recorded === undefined || is_borrowed_install(project_root)) return
|
|
196
|
+
const prefix = record_text(daemon, '')
|
|
197
|
+
if (!recorded.startsWith(prefix)) return
|
|
198
|
+
const current = eslint_daemon_sources.snapshot(project_root)
|
|
199
|
+
|
|
200
|
+
remember(
|
|
201
|
+
project_root,
|
|
202
|
+
eslint_daemon_sources.refresh(recorded.slice(prefix.length), current, relative),
|
|
203
|
+
)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function remember_after_edit(
|
|
207
|
+
project_root: string,
|
|
208
|
+
before: DaemonRecord,
|
|
209
|
+
edited: string | undefined,
|
|
210
|
+
): void {
|
|
211
|
+
const after = read_record(project_root)
|
|
174
212
|
|
|
175
|
-
remember(project_root, fingerprint(project_root))
|
|
213
|
+
if (after.daemon !== before.daemon) remember(project_root, fingerprint(project_root))
|
|
214
|
+
else if (edited !== undefined) remember_read(project_root, after, edited)
|
|
176
215
|
}
|
|
177
216
|
|
|
178
217
|
// `cwd` decides which eslint installation and which flat config answer, and `ESLINT_D_MISS=fail`
|
|
@@ -254,7 +293,7 @@ const eslint_daemon = {
|
|
|
254
293
|
is_stale,
|
|
255
294
|
read_record,
|
|
256
295
|
record_text,
|
|
257
|
-
|
|
296
|
+
remember_after_edit,
|
|
258
297
|
resolve_daemon_cli,
|
|
259
298
|
run,
|
|
260
299
|
run_or_cold,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
import { fileURLToPath } from 'node:url'
|
|
3
|
+
import { eslint_warm } from './eslint-warm'
|
|
4
|
+
|
|
5
|
+
// The detached warm-up `eslint_warm.start` spawns in the checkout to warm (joshuafolkken/kit#4720).
|
|
6
|
+
|
|
7
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) await eslint_warm.warm(process.cwd())
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process'
|
|
2
|
+
import { fileURLToPath } from 'node:url'
|
|
3
|
+
import { git_spawn_sync } from '#scripts/git/git-spawn-sync'
|
|
4
|
+
import { resolve_tsx_runner } from '#scripts/josh/josh-logic'
|
|
5
|
+
import { LINT_TIMEOUT_MS } from '#scripts/lib/timeouts'
|
|
6
|
+
import { eslint_daemon } from './eslint-daemon'
|
|
7
|
+
|
|
8
|
+
// Warms a fresh checkout's eslint daemon before its first edit (joshuafolkken/kit#4720). A cold
|
|
9
|
+
// daemon took 5–8 s on the first edit hook's lint and 0.1–1.3 s once warm; `eslint_d start` alone
|
|
10
|
+
// warms nothing — its first lint still took 8 s — because the cost is eslint loading the config, the
|
|
11
|
+
// plugins and the type program, which only a lint of a typed source pays.
|
|
12
|
+
//
|
|
13
|
+
// **The lint goes through `eslint_daemon.run` rather than the bare daemon**, so the daemon it starts
|
|
14
|
+
// is recorded with its fingerprint: an unrecorded one is stale to `josh lint:related` and the
|
|
15
|
+
// pre-commit hook, which would stop and cold-start it on their first run.
|
|
16
|
+
|
|
17
|
+
const WARM_CLI = fileURLToPath(new URL('eslint-warm-cli.ts', import.meta.url))
|
|
18
|
+
// One typed source the type program covers; a declaration file can be ignored by the flat config.
|
|
19
|
+
const TYPED_SOURCES: ReadonlyArray<string> = ['ls-files', '--', '*.ts', ':!*.d.ts']
|
|
20
|
+
// A project with no TypeScript still loads its config and plugins through this.
|
|
21
|
+
const FALLBACK_TARGET = 'eslint.config.js'
|
|
22
|
+
const LINE_SEPARATOR = '\n'
|
|
23
|
+
|
|
24
|
+
function warm_target(project_root: string): string {
|
|
25
|
+
const listed = git_spawn_sync.read(TYPED_SOURCES, { cwd: project_root }) ?? ''
|
|
26
|
+
const [first] = listed.split(LINE_SEPARATOR)
|
|
27
|
+
|
|
28
|
+
return first === undefined || first === '' ? FALLBACK_TARGET : first
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Bounded, so a daemon that never answers ends the detached warm-up instead of orphaning it
|
|
32
|
+
// (joshuafolkken/kit#5047); a timed-out warm-up leaves the first edit cold, as before.
|
|
33
|
+
async function warm(project_root: string): Promise<void> {
|
|
34
|
+
await eslint_daemon.run(['exec', 'eslint', warm_target(project_root)], {
|
|
35
|
+
project_root,
|
|
36
|
+
timeout_ms: LINT_TIMEOUT_MS,
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function ignore_error(): void {
|
|
41
|
+
// A warm-up that could not start leaves the first edit cold, as it was before.
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Detached and unreferenced, so the caller neither waits for the lint nor keeps its process alive
|
|
45
|
+
// for it. Best-effort: nothing here may fail the caller.
|
|
46
|
+
//
|
|
47
|
+
// **A test run starts none** (joshuafolkken/kit#5047): suites drive a real `lane open` in scratch
|
|
48
|
+
// trees, and one that forgot to mock this module left a detached warm-up behind each time.
|
|
49
|
+
function start(project_root: string): void {
|
|
50
|
+
if (process.env['VITEST'] !== undefined) return
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
const runner = resolve_tsx_runner()
|
|
54
|
+
const options = { cwd: project_root, detached: true, stdio: 'ignore' } as const
|
|
55
|
+
const child = spawn(runner.executable, [...runner.leading_arguments, WARM_CLI], options)
|
|
56
|
+
|
|
57
|
+
child.on('error', ignore_error)
|
|
58
|
+
child.unref()
|
|
59
|
+
} catch {
|
|
60
|
+
ignore_error()
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const eslint_warm = { start, warm }
|
|
65
|
+
|
|
66
|
+
export { eslint_warm }
|
|
@@ -2,6 +2,7 @@ import path from 'node:path'
|
|
|
2
2
|
import { input_fingerprint } from '#scripts/gate/input-fingerprint'
|
|
3
3
|
import { file_reader } from '#scripts/lib/read-file'
|
|
4
4
|
import type ts from 'typescript'
|
|
5
|
+
import { type_only_imports } from './type-only-imports'
|
|
5
6
|
|
|
6
7
|
// What a file's lint verdict reads besides the file itself: every file its imports reach, followed
|
|
7
8
|
// through the project's own files and stopped at a package's. A type-aware rule's verdict on a file
|
|
@@ -34,6 +35,7 @@ interface GraphContext extends Resolver {
|
|
|
34
35
|
resolution_cache: ts.ModuleResolutionCache
|
|
35
36
|
ambient: ReadonlyArray<Dependency>
|
|
36
37
|
dependencies: Map<string, ReadonlyArray<Dependency>>
|
|
38
|
+
runtime_dependencies: Map<string, ReadonlyArray<Dependency>>
|
|
37
39
|
content_hashes: Map<string, string>
|
|
38
40
|
}
|
|
39
41
|
|
|
@@ -44,9 +46,20 @@ interface ProjectConfig {
|
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
interface ImportGraph {
|
|
49
|
+
closure: (file: string) => ReadonlyArray<string>
|
|
47
50
|
closure_hash: (file: string) => string
|
|
51
|
+
imports: (file: string, content?: string) => ReadonlyArray<string>
|
|
52
|
+
importers: (files: ReadonlyArray<string>, universe: ReadonlyArray<string>) => ReadonlySet<string>
|
|
53
|
+
runtime_importers: (
|
|
54
|
+
files: ReadonlyArray<string>,
|
|
55
|
+
universe: ReadonlyArray<string>,
|
|
56
|
+
) => ReadonlySet<string>
|
|
57
|
+
strings: (file: string) => ReadonlyArray<string>
|
|
48
58
|
}
|
|
49
59
|
|
|
60
|
+
// A file's direct dependencies along one kind of edge.
|
|
61
|
+
type Edges = (context: GraphContext, file: string) => ReadonlyArray<Dependency>
|
|
62
|
+
|
|
50
63
|
// `typescript` is an optional peer: a project without it has no type-aware rule to go stale.
|
|
51
64
|
async function load_typescript(): Promise<TypeScript | undefined> {
|
|
52
65
|
try {
|
|
@@ -138,12 +151,12 @@ function resolve_type(resolver: Resolver, name: string, file: string): Dependenc
|
|
|
138
151
|
return as_dependency(resolved?.resolvedFileName, resolved?.isExternalLibraryImport)
|
|
139
152
|
}
|
|
140
153
|
|
|
141
|
-
function references_of(
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
)
|
|
154
|
+
function references_of(
|
|
155
|
+
context: GraphContext,
|
|
156
|
+
file: string,
|
|
157
|
+
content: string,
|
|
158
|
+
): Array<Dependency | undefined> {
|
|
159
|
+
const processed = context.typescript.preProcessFile(content, true, true)
|
|
147
160
|
|
|
148
161
|
return [
|
|
149
162
|
...processed.importedFiles.map((reference) =>
|
|
@@ -159,13 +172,31 @@ function references_of(context: GraphContext, file: string): Array<Dependency |
|
|
|
159
172
|
function direct_dependencies(context: GraphContext, file: string): ReadonlyArray<Dependency> {
|
|
160
173
|
const known = context.dependencies.get(file)
|
|
161
174
|
if (known !== undefined) return known
|
|
162
|
-
const found = references_of(context, file
|
|
175
|
+
const found = references_of(context, file, file_reader.read_if_readable(file) ?? '').filter(
|
|
176
|
+
(dependency) => dependency !== undefined,
|
|
177
|
+
)
|
|
163
178
|
|
|
164
179
|
context.dependencies.set(file, found)
|
|
165
180
|
|
|
166
181
|
return found
|
|
167
182
|
}
|
|
168
183
|
|
|
184
|
+
// The direct dependencies the test runner follows: the imports left once the transpiler drops the
|
|
185
|
+
// type-only declarations, and no `/// <reference>` (joshuafolkken/kit#5368).
|
|
186
|
+
function runtime_dependencies(context: GraphContext, file: string): ReadonlyArray<Dependency> {
|
|
187
|
+
const known = context.runtime_dependencies.get(file)
|
|
188
|
+
if (known !== undefined) return known
|
|
189
|
+
const content = file_reader.read_if_readable(file) ?? ''
|
|
190
|
+
const found = type_only_imports
|
|
191
|
+
.runtime_specifiers(context.typescript, file, content)
|
|
192
|
+
.map((specifier) => resolve_module(context, specifier, file))
|
|
193
|
+
.filter((dependency) => dependency !== undefined)
|
|
194
|
+
|
|
195
|
+
context.runtime_dependencies.set(file, found)
|
|
196
|
+
|
|
197
|
+
return found
|
|
198
|
+
}
|
|
199
|
+
|
|
169
200
|
// A file reaches files that never import it when it is a script or declares a global or a module —
|
|
170
201
|
// SvelteKit's `src/app.d.ts` `App.Locals`, say, or a `.ts` module's `declare global` augmentation;
|
|
171
202
|
// one that only exports is read through its imports like any other module.
|
|
@@ -253,6 +284,105 @@ function closure_hash(context: GraphContext, file: string): string {
|
|
|
253
284
|
return input_fingerprint.of_entries(tokens)
|
|
254
285
|
}
|
|
255
286
|
|
|
287
|
+
// The project's own files `closure_hash` reads for `file`, a package's left out.
|
|
288
|
+
function closure(context: GraphContext, file: string): Array<string> {
|
|
289
|
+
return [...reachable(context, file).values()]
|
|
290
|
+
.filter((dependency) => !dependency.external)
|
|
291
|
+
.map((dependency) => dependency.file)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// The text of each string literal `file` holds, a template's spans included: where a file names one it
|
|
295
|
+
// starts rather than imports — the CLI a test spawns.
|
|
296
|
+
function strings(typescript: TypeScript, file: string): Array<string> {
|
|
297
|
+
const content = file_reader.read_if_readable(file) ?? ''
|
|
298
|
+
const source = typescript.createSourceFile(file, content, typescript.ScriptTarget.Latest)
|
|
299
|
+
const found: Array<string> = []
|
|
300
|
+
|
|
301
|
+
function visit(node: ts.Node): void {
|
|
302
|
+
if (typescript.isStringLiteralLike(node) || typescript.isTemplateLiteralToken(node)) {
|
|
303
|
+
found.push(node.text)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
typescript.forEachChild(node, visit)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
visit(source)
|
|
310
|
+
|
|
311
|
+
return found
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// The project's own files `file` imports directly; a package's are left out. `content` reads another
|
|
315
|
+
// text of the file in its place — its version at another revision — resolved from where it sits now.
|
|
316
|
+
function imports(context: GraphContext, file: string, content?: string): Array<string> {
|
|
317
|
+
const dependencies =
|
|
318
|
+
content === undefined
|
|
319
|
+
? direct_dependencies(context, file)
|
|
320
|
+
: references_of(context, file, content).filter((dependency) => dependency !== undefined)
|
|
321
|
+
|
|
322
|
+
return dependencies
|
|
323
|
+
.filter((dependency) => !dependency.external)
|
|
324
|
+
.map((dependency) => dependency.file)
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function append(map: Map<string, Array<string>>, key: string, value: string): void {
|
|
328
|
+
const known = map.get(key)
|
|
329
|
+
|
|
330
|
+
if (known === undefined) map.set(key, [value])
|
|
331
|
+
else known.push(value)
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function reverse_edges(
|
|
335
|
+
context: GraphContext,
|
|
336
|
+
universe: ReadonlyArray<string>,
|
|
337
|
+
edges: Edges,
|
|
338
|
+
): Map<string, Array<string>> {
|
|
339
|
+
const reverse = new Map<string, Array<string>>()
|
|
340
|
+
|
|
341
|
+
for (const file of universe) {
|
|
342
|
+
for (const dependency of edges(context, file)) {
|
|
343
|
+
append(reverse, dependency.file, file)
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return reverse
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Every file of `universe` whose `edges` reach one of `files`, the files themselves included. Over every
|
|
351
|
+
// import, the only files that can name what they export, however many re-exports and aliases stand
|
|
352
|
+
// between; over the runtime imports, the graph the test runner walks, where a file read only through
|
|
353
|
+
// `import type` reaches no test past it (joshuafolkken/kit#5368).
|
|
354
|
+
function importers(
|
|
355
|
+
context: GraphContext,
|
|
356
|
+
files: ReadonlyArray<string>,
|
|
357
|
+
universe: ReadonlyArray<string>,
|
|
358
|
+
edges: Edges,
|
|
359
|
+
): ReadonlySet<string> {
|
|
360
|
+
const reverse = reverse_edges(context, universe, edges)
|
|
361
|
+
const reached = new Set(files)
|
|
362
|
+
const pending = [...files]
|
|
363
|
+
|
|
364
|
+
for (let current = pending.pop(); current !== undefined; current = pending.pop()) {
|
|
365
|
+
const next = (reverse.get(current) ?? []).filter((file) => !reached.has(file))
|
|
366
|
+
|
|
367
|
+
for (const file of next) reached.add(file)
|
|
368
|
+
pending.push(...next)
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
return reached
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function graph_of(context: GraphContext): ImportGraph {
|
|
375
|
+
return {
|
|
376
|
+
closure: (file) => closure(context, file),
|
|
377
|
+
closure_hash: (file) => closure_hash(context, file),
|
|
378
|
+
imports: (file, content) => imports(context, file, content),
|
|
379
|
+
importers: (files, universe) => importers(context, files, universe, direct_dependencies),
|
|
380
|
+
runtime_importers: (files, universe) =>
|
|
381
|
+
importers(context, files, universe, runtime_dependencies),
|
|
382
|
+
strings: (file) => strings(context.typescript, file),
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
256
386
|
// Undefined where nothing type-aware can run: no `typescript`, or no `tsconfig.json` at the root.
|
|
257
387
|
async function create(root: string): Promise<ImportGraph | undefined> {
|
|
258
388
|
const typescript = await load_typescript()
|
|
@@ -260,17 +390,17 @@ async function create(root: string): Promise<ImportGraph | undefined> {
|
|
|
260
390
|
const parsed = parsed_config(typescript, root)
|
|
261
391
|
if (parsed === undefined) return undefined
|
|
262
392
|
const { options } = parsed
|
|
263
|
-
|
|
393
|
+
|
|
394
|
+
return graph_of({
|
|
264
395
|
root,
|
|
265
396
|
typescript,
|
|
266
397
|
options,
|
|
267
398
|
resolution_cache: typescript.createModuleResolutionCache(root, (name) => name, options),
|
|
268
399
|
ambient: ambient_of({ typescript, options }, root, parsed),
|
|
269
400
|
dependencies: new Map(),
|
|
401
|
+
runtime_dependencies: new Map(),
|
|
270
402
|
content_hashes: new Map(),
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
return { closure_hash: (file) => closure_hash(context, file) }
|
|
403
|
+
})
|
|
274
404
|
}
|
|
275
405
|
|
|
276
406
|
const import_graph = { create }
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
import { environment_flags } from '@joshuafolkken/kit/env'
|
|
4
|
-
import {
|
|
4
|
+
import { gate_labels } from '#scripts/gate/gate-labels'
|
|
5
5
|
import { verification_inputs } from '#scripts/gate/verification-inputs'
|
|
6
6
|
import {
|
|
7
7
|
changed_file_scope,
|
|
@@ -60,7 +60,7 @@ function all_scope(reason: string): ChangedFileScope {
|
|
|
60
60
|
// reads them too.
|
|
61
61
|
function configures_lint(files: ReadonlyArray<string>, root: string): boolean {
|
|
62
62
|
return verification_inputs.configures(
|
|
63
|
-
|
|
63
|
+
gate_labels.LINT_LABEL,
|
|
64
64
|
files.map((file) => path.relative(root, file).split(path.sep).join('/')),
|
|
65
65
|
)
|
|
66
66
|
}
|