@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
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { stripVTControlCharacters } from 'node:util'
|
|
2
|
+
import { gate_log } from '#scripts/gate/gate-log'
|
|
3
|
+
import { verification_tail } from '#scripts/gate/verification-tail'
|
|
4
|
+
import { PROJECT_ROOT } from '#scripts/init/init-paths'
|
|
5
|
+
import { stamp_file } from '#scripts/josh/stamp-file'
|
|
6
|
+
|
|
7
|
+
// A failed vitest run's answer, put where a `tail` reaches it (joshuafolkken/kit#4869).
|
|
8
|
+
//
|
|
9
|
+
// **The console's end is the last failure's stack, not the list of what failed.** vitest prints its
|
|
10
|
+
// failures in order and then a summary of counts, so `josh test:related 2>&1 | tail -40` kept one stack
|
|
11
|
+
// and no names, and the only way to learn the rest was to run the suite again. So every run's output
|
|
12
|
+
// goes to a file, and a failed one ends with the failed tests' names and that file's path — the same
|
|
13
|
+
// log and notice `josh gate` uses, imported rather than re-derived.
|
|
14
|
+
|
|
15
|
+
const UNIT_LOG_PREFIX = 'josh-unit-log-'
|
|
16
|
+
const UNIT_LOG_HEADER = 'vitest'
|
|
17
|
+
const FAILED_LINE = /^FAIL\s+(?<name>\S.*)$/u
|
|
18
|
+
const FAILED_HEADING = 'failed tests:'
|
|
19
|
+
const NONE_NAMED = ' (none named in the output — read the full output)'
|
|
20
|
+
const NONE_NAMED_VERDICT = 'none named'
|
|
21
|
+
// A name is `<file> > <suite> > <test>` or `<file> [ <file> ]`, prefixed `|<project>| ` in a workspace —
|
|
22
|
+
// or, with color on, ` <project> ` once its badge's escapes are stripped (joshuafolkken/kit#5171).
|
|
23
|
+
const FAILED_FILE = /^(?:\|[^|]*\|\s+|\S+\s{2,})?(?<file>\S+)/u
|
|
24
|
+
// The guarded unit run, filtered to those files: it reserves its cores and ends a failure with this
|
|
25
|
+
// same summary (joshuafolkken/kit#5023).
|
|
26
|
+
const RERUN_PREFIX = 'rerun failed: pnpm josh test:unit '
|
|
27
|
+
|
|
28
|
+
// One path per checkout and vitest mode, overwritten by each run, beside the gate's own log. **The
|
|
29
|
+
// mode is in the name** because the gate's whole-suite `run` and a `related` run started beside it
|
|
30
|
+
// overlap, and one shared file would hand the failed run's reader the other run's output.
|
|
31
|
+
function unit_log_path(vitest_arguments: ReadonlyArray<string>): string {
|
|
32
|
+
const prefix = `${UNIT_LOG_PREFIX}${vitest_arguments[0] ?? UNIT_LOG_HEADER}-`
|
|
33
|
+
|
|
34
|
+
return stamp_file.stamp_path(prefix, PROJECT_ROOT, gate_log.GATE_LOG_SUFFIX)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function failed_name(line: string): string | undefined {
|
|
38
|
+
return FAILED_LINE.exec(stripVTControlCharacters(line).trim())?.groups?.['name']
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// vitest names each failed test on a ` FAIL <file> > <suite> > <test>` line, and a file that could
|
|
42
|
+
// not load on ` FAIL <file> [ <file> ]`. A name printed twice is listed once.
|
|
43
|
+
function failed_tests(output: string): ReadonlyArray<string> {
|
|
44
|
+
const names = output.split('\n').map((line) => failed_name(line))
|
|
45
|
+
|
|
46
|
+
return [...new Set(names.filter((name) => name !== undefined))]
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// The files the failed names belong to, each once — what to run after a fix, before the whole related
|
|
50
|
+
// set again (joshuafolkken/kit#5023).
|
|
51
|
+
function failed_files(names: ReadonlyArray<string>): ReadonlyArray<string> {
|
|
52
|
+
const files = names.map((name) => FAILED_FILE.exec(name)?.groups?.['file'])
|
|
53
|
+
|
|
54
|
+
return [...new Set(files.filter((file) => file !== undefined))]
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function name_lines(names: ReadonlyArray<string>): ReadonlyArray<string> {
|
|
58
|
+
if (names.length === 0) return [NONE_NAMED]
|
|
59
|
+
|
|
60
|
+
return [...names.map((name) => ` ${name}`), `${RERUN_PREFIX}${failed_files(names).join(' ')}`]
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// The verdict names the failed files, so the last line alone says what to fix (joshuafolkken/kit#5162).
|
|
64
|
+
function format_failure_summary(
|
|
65
|
+
output: string,
|
|
66
|
+
log_path: string | undefined,
|
|
67
|
+
label: string = UNIT_LOG_HEADER,
|
|
68
|
+
): string {
|
|
69
|
+
const names = failed_tests(output)
|
|
70
|
+
const failures = `${[FAILED_HEADING, ...name_lines(names)].join('\n')}\n`
|
|
71
|
+
const failed = names.length === 0 ? [NONE_NAMED_VERDICT] : failed_files(names)
|
|
72
|
+
const verdict = verification_tail.format_verdict(label, failed)
|
|
73
|
+
|
|
74
|
+
return verification_tail.format_tail({ failures, log: { path: log_path }, verdict })
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function format_green_summary(log_path: string | undefined, label: string): string {
|
|
78
|
+
const verdict = verification_tail.format_verdict(label, [])
|
|
79
|
+
|
|
80
|
+
return verification_tail.format_tail({ failures: '', log: { path: log_path }, verdict })
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Written on every run, as the gate's is, headed by the run's own invocation, and ended as every josh
|
|
84
|
+
// check ends (`verification-tail.ts`): a green run's last line is its verdict, not vitest's counts.
|
|
85
|
+
function report(
|
|
86
|
+
vitest_arguments: ReadonlyArray<string>,
|
|
87
|
+
output: string,
|
|
88
|
+
exit_code: number,
|
|
89
|
+
target: string = unit_log_path(vitest_arguments),
|
|
90
|
+
): void {
|
|
91
|
+
const header = [UNIT_LOG_HEADER, ...vitest_arguments].join(' ')
|
|
92
|
+
const log_path = gate_log.write_gate_log([{ header, output }], target)
|
|
93
|
+
const label = [UNIT_LOG_HEADER, ...vitest_arguments.slice(0, 1)].join(' ')
|
|
94
|
+
const summary =
|
|
95
|
+
exit_code === 0
|
|
96
|
+
? format_green_summary(log_path, label)
|
|
97
|
+
: format_failure_summary(output, log_path, label)
|
|
98
|
+
|
|
99
|
+
process.stdout.write(summary)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const vitest_failure_summary = {
|
|
103
|
+
RERUN_PREFIX,
|
|
104
|
+
failed_files,
|
|
105
|
+
failed_tests,
|
|
106
|
+
format_failure_summary,
|
|
107
|
+
report,
|
|
108
|
+
unit_log_path,
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export { vitest_failure_summary }
|
|
@@ -36,12 +36,16 @@ const IMPORTED_BY_EVERY_TEST: ReadonlyArray<string> = [
|
|
|
36
36
|
'scripts/josh/process-identity.ts',
|
|
37
37
|
'scripts/josh/process-owner.ts',
|
|
38
38
|
'scripts/josh/stamp-file.ts',
|
|
39
|
+
'scripts/lane/lane-child-mark-keys.ts',
|
|
39
40
|
'scripts/lib/atomic-write.ts',
|
|
40
41
|
'scripts/lib/json-value.ts',
|
|
41
42
|
'scripts/lib/read-file.ts',
|
|
42
43
|
'scripts/lib/timeouts.ts',
|
|
44
|
+
'scripts/test/unit-durations.ts',
|
|
43
45
|
'scripts/test/unit-run-marker.ts',
|
|
44
46
|
'scripts/test/unit-setup-files.ts',
|
|
47
|
+
'scripts/test/vitest-cache-directory.ts',
|
|
48
|
+
'scripts/test/vitest-cli-excludes.ts',
|
|
45
49
|
'tools/test/duration-sequencer.ts',
|
|
46
50
|
'tools/test/duration-shard.ts',
|
|
47
51
|
'tools/test/pure-files.ts',
|
|
@@ -58,6 +62,13 @@ const WHOLE_SUITE_FILES: ReadonlySet<string> = new Set(
|
|
|
58
62
|
[...ROOT_FILES, ...IMPORTED_BY_EVERY_TEST, ...SETUP_FILES].map((file) => path.normalize(file)),
|
|
59
63
|
)
|
|
60
64
|
|
|
61
|
-
|
|
65
|
+
// The part of `WHOLE_SUITE_FILES` a scoped run narrows to the test files importing it directly
|
|
66
|
+
// (`direct-importers.ts`, joshuafolkken/kit#5122): each is a module some test imports by name, unlike a
|
|
67
|
+
// root or setup file, which only the whole suite reaches.
|
|
68
|
+
const EVERY_TEST_IMPORTS: ReadonlySet<string> = new Set(
|
|
69
|
+
IMPORTED_BY_EVERY_TEST.map((file) => path.normalize(file)),
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
const whole_suite_files = { EVERY_TEST_IMPORTS, WHOLE_SUITE_FILES }
|
|
62
73
|
|
|
63
74
|
export { whole_suite_files }
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { time_bundle_call, type BundleFacts } from './time-bundle-call'
|
|
2
2
|
import { time_bundles } from './time-bundles'
|
|
3
3
|
import { time_call_identity } from './time-call-identity'
|
|
4
|
+
import { time_search_call } from './time-search-call'
|
|
4
5
|
import { time_spans, type Span } from './time-spans'
|
|
6
|
+
import type { ToolCall } from './time-tool-call'
|
|
5
7
|
import { time_transcript_line } from './time-transcript-line'
|
|
6
8
|
|
|
7
9
|
// Whether the call about to go out should be refused because the run has stopped batching. What a
|
|
@@ -154,6 +156,16 @@ function is_reissued_refusal(spans: ReadonlyArray<Span>, call: GuardedCall): boo
|
|
|
154
156
|
)
|
|
155
157
|
}
|
|
156
158
|
|
|
159
|
+
// The closed history a refusal judges; empty where the call is not refusable or is a reissue, and an
|
|
160
|
+
// empty history never reaches the limit.
|
|
161
|
+
function refusable_spans(text: string, call: GuardedCall): ReadonlyArray<Span> {
|
|
162
|
+
if (!is_guarded_call(call)) return []
|
|
163
|
+
|
|
164
|
+
const { spans } = time_spans.parse_timeline(text)
|
|
165
|
+
|
|
166
|
+
return is_reissued_refusal(spans, call) ? [] : spans
|
|
167
|
+
}
|
|
168
|
+
|
|
157
169
|
// The lane-child notice passes `NOTICE_REFIRE_EVERY` to recur on the notice's cadence.
|
|
158
170
|
function should_block(
|
|
159
171
|
text: string,
|
|
@@ -161,13 +173,37 @@ function should_block(
|
|
|
161
173
|
refused_at_ms: number,
|
|
162
174
|
refire_every: number = REFIRE_EVERY,
|
|
163
175
|
): boolean {
|
|
164
|
-
|
|
176
|
+
return is_at_limit(refusable_spans(text, call), call, refused_at_ms, refire_every)
|
|
177
|
+
}
|
|
165
178
|
|
|
166
|
-
|
|
179
|
+
function as_tool_call(call: GuardedCall): ToolCall {
|
|
180
|
+
return time_spans.to_tool_call(call.name, call.input, time_spans.NO_MESSAGE_ID)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Asked before the transcript is read, like `is_guarded_call`, for the search-chain refusal alone.
|
|
184
|
+
function is_search_chain_call(call: GuardedCall): boolean {
|
|
185
|
+
return is_guarded_call(call) && time_search_call.is_search_chain_call(as_tool_call(call))
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// The turns that make the limit — the last closed ones and the call in hand — are all searches.
|
|
189
|
+
function is_search_chain(spans: ReadonlyArray<Span>, call: GuardedCall): boolean {
|
|
190
|
+
const recent = time_bundles.open_sequence(spans).slice(-SEQUENCE_BEFORE_LIMIT)
|
|
191
|
+
|
|
192
|
+
return [...recent, as_tool_call(call)].every((turn) =>
|
|
193
|
+
time_search_call.is_search_chain_call(turn),
|
|
194
|
+
)
|
|
195
|
+
}
|
|
167
196
|
|
|
168
|
-
|
|
197
|
+
// The narrower refusal a lane child keeps (`search-batching` in `lane-guard-policy.ts`): only a chain
|
|
198
|
+
// of searches issued one per turn, the largest share of the child's single-call pairs.
|
|
199
|
+
function should_block_search_chain(
|
|
200
|
+
text: string,
|
|
201
|
+
call: GuardedCall,
|
|
202
|
+
refused_at_ms: number,
|
|
203
|
+
): boolean {
|
|
204
|
+
const spans = refusable_spans(text, call)
|
|
169
205
|
|
|
170
|
-
return is_at_limit(spans, call, refused_at_ms,
|
|
206
|
+
return is_search_chain(spans, call) && is_at_limit(spans, call, refused_at_ms, REFIRE_EVERY)
|
|
171
207
|
}
|
|
172
208
|
|
|
173
209
|
// `notified_at_ms` is the notice's own record, so a notice never silences a later refusal.
|
|
@@ -279,9 +315,11 @@ const time_batch_guard = {
|
|
|
279
315
|
is_guarded_call,
|
|
280
316
|
is_notice_call,
|
|
281
317
|
is_read_only_call,
|
|
318
|
+
is_search_chain_call,
|
|
282
319
|
pairing_candidates,
|
|
283
320
|
recent_candidates,
|
|
284
321
|
should_block,
|
|
322
|
+
should_block_search_chain,
|
|
285
323
|
should_notify,
|
|
286
324
|
}
|
|
287
325
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { cost_blocks } from '#scripts/cost-runtime/cost-blocks'
|
|
2
|
-
import { canonical_command } from '#scripts/josh/josh-
|
|
2
|
+
import { canonical_command } from '#scripts/josh/josh-aliases'
|
|
3
3
|
import { json_value } from '#scripts/lib/json-value'
|
|
4
4
|
import { time_shell } from './time-shell'
|
|
5
5
|
|
|
@@ -95,15 +95,29 @@ interface BundleTotals {
|
|
|
95
95
|
recoverable_round_trips: number
|
|
96
96
|
by_tool: ReadonlyArray<BundleToolRow>
|
|
97
97
|
unattributed_round_trips: number
|
|
98
|
+
single_call: SingleCallSplit
|
|
98
99
|
is_measured: boolean
|
|
99
100
|
}
|
|
100
101
|
|
|
102
|
+
// The consecutive single-call turns alone, split by the target test — what `josh time:density` reads.
|
|
103
|
+
// **The spread-apart `Agent` launch series is left out** of every field here: the walk never sees a
|
|
104
|
+
// launch, so it can be neither dependent nor independent, and folding its count into one side would
|
|
105
|
+
// make the two sides measure different populations.
|
|
106
|
+
interface SingleCallSplit {
|
|
107
|
+
// Turns that could have gone out beside the single-call turn before them.
|
|
108
|
+
independent_round_trips: number
|
|
109
|
+
// Turns whose call shared a target with the open sequence, so needed the turn before.
|
|
110
|
+
dependent_round_trips: number
|
|
111
|
+
by_tool: ReadonlyArray<BundleToolRow>
|
|
112
|
+
}
|
|
113
|
+
|
|
101
114
|
const NO_BUNDLES: BundleTotals = {
|
|
102
115
|
sequence_count: 0,
|
|
103
116
|
longest_sequence: 0,
|
|
104
117
|
recoverable_round_trips: 0,
|
|
105
118
|
by_tool: [],
|
|
106
119
|
unattributed_round_trips: 0,
|
|
120
|
+
single_call: { independent_round_trips: 0, dependent_round_trips: 0, by_tool: [] },
|
|
107
121
|
is_measured: false,
|
|
108
122
|
}
|
|
109
123
|
|
|
@@ -191,10 +205,11 @@ interface Walk {
|
|
|
191
205
|
pending: Array<Span>
|
|
192
206
|
sequence: Array<Span>
|
|
193
207
|
closed: Array<Array<Span>>
|
|
208
|
+
dependent: number
|
|
194
209
|
}
|
|
195
210
|
|
|
196
211
|
function new_walk(): Walk {
|
|
197
|
-
return { pending: [], sequence: [], closed: [] }
|
|
212
|
+
return { pending: [], sequence: [], closed: [], dependent: NONE }
|
|
198
213
|
}
|
|
199
214
|
|
|
200
215
|
function flush(walk: Walk): void {
|
|
@@ -204,9 +219,13 @@ function flush(walk: Walk): void {
|
|
|
204
219
|
}
|
|
205
220
|
|
|
206
221
|
// A conflicting call does not end the run of single-call turns; it starts a new sequence at itself,
|
|
207
|
-
// because everything after it may still have been bundleable with it.
|
|
222
|
+
// because everything after it may still have been bundleable with it. The conflict is the one place a
|
|
223
|
+
// dependent pair is seen, so it is counted here rather than by a second walk.
|
|
208
224
|
function extend(walk: Walk, span: Span): void {
|
|
209
|
-
if (conflicts(span, walk.sequence))
|
|
225
|
+
if (conflicts(span, walk.sequence)) {
|
|
226
|
+
walk.dependent += ONE_CALL
|
|
227
|
+
flush(walk)
|
|
228
|
+
}
|
|
210
229
|
|
|
211
230
|
walk.sequence.push(span)
|
|
212
231
|
}
|
|
@@ -359,6 +378,14 @@ function with_agent_row(
|
|
|
359
378
|
return [...rows, row].toSorted(by_weight)
|
|
360
379
|
}
|
|
361
380
|
|
|
381
|
+
function single_call_split(walk: Walk, sizes: ReadonlyArray<number>): SingleCallSplit {
|
|
382
|
+
return {
|
|
383
|
+
independent_round_trips: recoverable_of(sizes),
|
|
384
|
+
dependent_round_trips: walk.dependent,
|
|
385
|
+
by_tool: tool_rows(walk.closed),
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
362
389
|
function build_bundles(spans: ReadonlyArray<Span>): BundleTotals {
|
|
363
390
|
const walk = new_walk()
|
|
364
391
|
|
|
@@ -373,8 +400,9 @@ function build_bundles(spans: ReadonlyArray<Span>): BundleTotals {
|
|
|
373
400
|
// is never bundleable, so it cannot have entered a sequence above — so their counts simply add.
|
|
374
401
|
const sizes = sizes_of(walk.closed)
|
|
375
402
|
const agent_sizes = time_agent_bundles.agent_bundles(spans)
|
|
376
|
-
const
|
|
377
|
-
const
|
|
403
|
+
const single_call = single_call_split(walk, sizes)
|
|
404
|
+
const by_tool = with_agent_row(single_call.by_tool, agent_sizes)
|
|
405
|
+
const recoverable_round_trips = single_call.independent_round_trips + recoverable_of(agent_sizes)
|
|
378
406
|
|
|
379
407
|
return {
|
|
380
408
|
sequence_count: sizes.length + agent_sizes.length,
|
|
@@ -382,6 +410,7 @@ function build_bundles(spans: ReadonlyArray<Span>): BundleTotals {
|
|
|
382
410
|
recoverable_round_trips,
|
|
383
411
|
by_tool,
|
|
384
412
|
unattributed_round_trips: recoverable_round_trips - attributed_of(by_tool),
|
|
413
|
+
single_call,
|
|
385
414
|
is_measured: time_spans.has_transcript_data(spans.length),
|
|
386
415
|
}
|
|
387
416
|
}
|
|
@@ -524,9 +553,11 @@ const time_bundles = {
|
|
|
524
553
|
NO_BUNDLES,
|
|
525
554
|
build_bundles,
|
|
526
555
|
bundle_lines,
|
|
556
|
+
by_weight,
|
|
527
557
|
is_dependent,
|
|
528
558
|
open_sequence,
|
|
529
559
|
shares_target,
|
|
530
560
|
}
|
|
531
561
|
|
|
562
|
+
export type { BundleToolRow }
|
|
532
563
|
export { time_bundles }
|
|
@@ -32,8 +32,8 @@ import { json_value } from '#scripts/lib/json-value'
|
|
|
32
32
|
// which the main line loaded the skill itself.
|
|
33
33
|
//
|
|
34
34
|
// **The launch is recognized by its prompt carrying both `/code-review` and `review:attest`.** The
|
|
35
|
-
// first is the instruction to invoke the review skill; the second is the attestation
|
|
36
|
-
// `pnpm josh review
|
|
35
|
+
// first is the instruction to invoke the review skill; the second is the attestation step the launch
|
|
36
|
+
// prompt `pnpm josh run:review` prints beside each brief file names (joshuafolkken/kit#4863).
|
|
37
37
|
// Neither alone is enough: an investigation subagent about the review tooling quotes `/code-review`
|
|
38
38
|
// in prose and is handed no brief, so `review:attest` is what tells a genuine review launch from a
|
|
39
39
|
// discussion of one — measured against five real launches, it admits the review and rejects every
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { time_shell } from './time-shell'
|
|
2
|
+
import type { ToolCall } from './time-tool-call'
|
|
3
|
+
|
|
4
|
+
// Which calls are a search, the one answer the investigation guard and the batching guard both read.
|
|
5
|
+
// A search carries no file text but costs a turn, so it is what a run issues one per turn while it
|
|
6
|
+
// locates the next edit.
|
|
7
|
+
|
|
8
|
+
const SEARCH_COMMANDS: ReadonlyArray<string> = ['fd', 'find', 'grep', 'rg']
|
|
9
|
+
const SEARCH_LABELS: ReadonlySet<string> = new Set(
|
|
10
|
+
SEARCH_COMMANDS.map((command) => time_shell.bash_label(command)),
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
// A search chain also prints the lines a search found, so `sed` (read-only) joins it: `grep` → `sed`
|
|
14
|
+
// was measured the second-largest single-call pair in lane children.
|
|
15
|
+
const CHAIN_COMMANDS: ReadonlyArray<string> = [...SEARCH_COMMANDS, 'sed']
|
|
16
|
+
const CHAIN_LABELS: ReadonlySet<string> = new Set(
|
|
17
|
+
CHAIN_COMMANDS.map((command) => time_shell.bash_label(command)),
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
type SearchFacts = Pick<ToolCall, 'label' | 'is_bundleable' | 'may_write' | 'is_writing'>
|
|
21
|
+
|
|
22
|
+
// `may_write` over-calls, as the investigation guard's refusal test must.
|
|
23
|
+
function is_read_only_search(call: SearchFacts): boolean {
|
|
24
|
+
return SEARCH_LABELS.has(call.label) && call.is_bundleable && !call.may_write
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// `may_write` holds for every `sed`, so the chain asks `is_writing` — certain, and false for `sed -n`.
|
|
28
|
+
function is_search_chain_call(call: SearchFacts): boolean {
|
|
29
|
+
return CHAIN_LABELS.has(call.label) && call.is_bundleable && !call.is_writing
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const time_search_call = {
|
|
33
|
+
is_read_only_search,
|
|
34
|
+
is_search_chain_call,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export type { SearchFacts }
|
|
38
|
+
export { time_search_call }
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { cost_blocks } from '#scripts/cost-runtime/cost-blocks'
|
|
2
|
-
import { canonical_command } from '#scripts/josh/josh-
|
|
2
|
+
import { canonical_command } from '#scripts/josh/josh-aliases'
|
|
3
3
|
import { json_value } from '#scripts/lib/json-value'
|
|
4
4
|
|
|
5
5
|
// Reading a shell command well enough to name what it ran.
|
|
@@ -118,6 +118,9 @@ interface TranscriptLine {
|
|
|
118
118
|
// every line lacking an id would otherwise fall into one bucket spanning the whole file.
|
|
119
119
|
message_id: string
|
|
120
120
|
blocks: Array<Block>
|
|
121
|
+
// The reason a Stop-hook block sent this turn back with, its label stripped, or `''` for every
|
|
122
|
+
// other line.
|
|
123
|
+
stop_feedback: string
|
|
121
124
|
// The guard whose Stop-hook block sent this turn back, or `''` for every other line
|
|
122
125
|
// — read the way `Block.refusal_guard` is, off the reason's opening.
|
|
123
126
|
stop_guard: string
|
|
@@ -135,6 +138,11 @@ function block_names(raw: TranscriptBlock): Pick<Block, 'type' | 'name' | 'id' |
|
|
|
135
138
|
}
|
|
136
139
|
}
|
|
137
140
|
|
|
141
|
+
// The body a refusal opens with, the harness's own label stripped — shared with `rule-value.ts`.
|
|
142
|
+
function refusal_body(text: string): string {
|
|
143
|
+
return text.trimStart().replace(HOOK_ERROR_LABEL, '')
|
|
144
|
+
}
|
|
145
|
+
|
|
138
146
|
// **A refusal is identified by what its body opens with, never by what it carries inside**.
|
|
139
147
|
// The hook denies a call on behalf of the one guard whose trigger fired and
|
|
140
148
|
// writes that guard's reason back as the whole result, so the speaker is the token after the `⛔` and
|
|
@@ -146,7 +154,7 @@ function block_names(raw: TranscriptBlock): Pick<Block, 'type' | 'name' | 'id' |
|
|
|
146
154
|
// label is stripped before the opening is read. Without it no live refusal
|
|
147
155
|
// carried a guard: the fixtures wrote the bare `⛔` body and passed while every recorded one read `''`.
|
|
148
156
|
function guard_from_refusal(text: string): string {
|
|
149
|
-
const trimmed = text
|
|
157
|
+
const trimmed = refusal_body(text)
|
|
150
158
|
if (!trimmed.startsWith(REFUSAL_MARKER)) return ''
|
|
151
159
|
|
|
152
160
|
const headline = trimmed.slice(REFUSAL_MARKER.length).split('\n', 1)[0]?.trimStart() ?? ''
|
|
@@ -157,12 +165,12 @@ function guard_from_refusal(text: string): string {
|
|
|
157
165
|
|
|
158
166
|
// **Only the harness's own feedback line counts.** It writes a Stop block back as a user turn whose
|
|
159
167
|
// whole body is `Stop hook feedback:` and the reason, so a prompt that merely quotes one never opens
|
|
160
|
-
// with the label and reads `''`.
|
|
161
|
-
function
|
|
168
|
+
// with the label and reads `''`. The reason is kept whole, so `rule-value.ts` can match it to its row.
|
|
169
|
+
function stop_feedback_of(data: TranscriptRecord): string {
|
|
162
170
|
const content = data.message?.content
|
|
163
171
|
if (typeof content !== 'string' || !STOP_FEEDBACK_LABEL.test(content)) return ''
|
|
164
172
|
|
|
165
|
-
return
|
|
173
|
+
return content.replace(STOP_FEEDBACK_LABEL, '').trim()
|
|
166
174
|
}
|
|
167
175
|
|
|
168
176
|
function token_lines_of(text: string): Array<string> {
|
|
@@ -254,12 +262,15 @@ function to_line(data: TranscriptRecord): TranscriptLine | undefined {
|
|
|
254
262
|
|
|
255
263
|
if (timestamp_ms === undefined) return undefined
|
|
256
264
|
|
|
265
|
+
const stop_feedback = stop_feedback_of(data)
|
|
266
|
+
|
|
257
267
|
return {
|
|
258
268
|
type: data.type ?? '',
|
|
259
269
|
timestamp_ms,
|
|
260
270
|
branch: data.gitBranch ?? UNKNOWN_BRANCH,
|
|
261
271
|
finished_background: finished_background(data),
|
|
262
|
-
|
|
272
|
+
stop_feedback,
|
|
273
|
+
stop_guard: guard_from_refusal(stop_feedback),
|
|
263
274
|
...message_fields(data.message),
|
|
264
275
|
}
|
|
265
276
|
}
|
|
@@ -282,6 +293,7 @@ const time_transcript_line = {
|
|
|
282
293
|
guard_from_refusal,
|
|
283
294
|
parse_line,
|
|
284
295
|
parse_text,
|
|
296
|
+
refusal_body,
|
|
285
297
|
}
|
|
286
298
|
|
|
287
299
|
export type { Block, TranscriptLine }
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs'
|
|
2
|
+
import { isDeepStrictEqual } from 'node:util'
|
|
3
|
+
import { git_spawn_sync } from '#scripts/git/git-spawn-sync'
|
|
4
|
+
import { PACKAGE_JSON } from '#scripts/lib/package-manifest'
|
|
5
|
+
import { z } from 'zod'
|
|
6
|
+
import { package_manager_version } from './package-manager-version'
|
|
7
|
+
|
|
8
|
+
// The `devEngines` verdict a dependency update is judged by (`.claude/skills/dependency-update`):
|
|
9
|
+
// the committed manifest against the working tree, printed as one line so nobody compares the two
|
|
10
|
+
// strings by eye. `kept` is the lockstep pnpm bump — the version equal to the `packageManager` pin,
|
|
11
|
+
// integrity suffix included — and `josh sync`'s `onFail` move from `error` to `download`; any other
|
|
12
|
+
// change is `restore`, with the reason in brackets.
|
|
13
|
+
const HEAD_PACKAGE_JSON = `HEAD:./${PACKAGE_JSON}`
|
|
14
|
+
const NOT_JUDGED = `devEngines: not judged (no ${PACKAGE_JSON} at HEAD to compare against)`
|
|
15
|
+
const PACKAGE_MANAGER_KEY = 'packageManager'
|
|
16
|
+
const VERSION_KEY = 'version'
|
|
17
|
+
const ON_FAIL_KEY = 'onFail'
|
|
18
|
+
const ON_FAIL_FROM = 'error'
|
|
19
|
+
const ON_FAIL_TO = 'download'
|
|
20
|
+
const UNCHANGED = 'devEngines: unchanged'
|
|
21
|
+
const KEPT = 'devEngines: kept'
|
|
22
|
+
const SUFFIX_MISSING = 'integrity suffix missing'
|
|
23
|
+
const NO_PIN = 'no pnpm@ packageManager pin to match'
|
|
24
|
+
|
|
25
|
+
type Entries = Record<string, unknown>
|
|
26
|
+
|
|
27
|
+
const entries_schema = z.record(z.string(), z.unknown())
|
|
28
|
+
const manifest_schema = z.looseObject({
|
|
29
|
+
packageManager: z.string().default(''),
|
|
30
|
+
devEngines: entries_schema.default({}),
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
type Manifest = z.infer<typeof manifest_schema>
|
|
34
|
+
|
|
35
|
+
function read_manifest(content: string): Manifest {
|
|
36
|
+
return manifest_schema.parse(JSON.parse(content))
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function is_entries(value: unknown): value is Entries {
|
|
40
|
+
return entries_schema.safeParse(value).success
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function read_package_manager(development_engines: Entries): Entries {
|
|
44
|
+
const value = development_engines[PACKAGE_MANAGER_KEY]
|
|
45
|
+
|
|
46
|
+
return is_entries(value) ? value : {}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// `packageManager` is compared key by key only when both sides are objects; the npm array form, or
|
|
50
|
+
// a block added or removed whole, is a structural change in itself.
|
|
51
|
+
function is_compared_inside(key: string, before: Entries, after: Entries): boolean {
|
|
52
|
+
return key === PACKAGE_MANAGER_KEY && is_entries(before[key]) && is_entries(after[key])
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function changed_keys(before: Entries, after: Entries): Array<string> {
|
|
56
|
+
const keys = new Set([...Object.keys(before), ...Object.keys(after)])
|
|
57
|
+
|
|
58
|
+
return [...keys].filter((key) => !isDeepStrictEqual(before[key], after[key]))
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// The version is judged against the pin below, so only its presence counts here.
|
|
62
|
+
function is_expected_change(key: string, before: Entries, after: Entries): boolean {
|
|
63
|
+
if (key === VERSION_KEY) return typeof after[key] === 'string'
|
|
64
|
+
|
|
65
|
+
return key === ON_FAIL_KEY && before[key] === ON_FAIL_FROM && after[key] === ON_FAIL_TO
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function find_structure_change(before: Entries, after: Entries): string | undefined {
|
|
69
|
+
const outer = changed_keys(before, after).filter((key) => !is_compared_inside(key, before, after))
|
|
70
|
+
const pm_before = read_package_manager(before)
|
|
71
|
+
const pm_after = read_package_manager(after)
|
|
72
|
+
const inner = changed_keys(pm_before, pm_after).filter(
|
|
73
|
+
(key) => !is_expected_change(key, pm_before, pm_after),
|
|
74
|
+
)
|
|
75
|
+
const keys = [...outer, ...inner.map((key) => `${PACKAGE_MANAGER_KEY}.${key}`)]
|
|
76
|
+
|
|
77
|
+
return keys.length === 0 ? undefined : `structure changed: ${keys.join(', ')}`
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Without a `pnpm@` pin there is nothing the version could be kept in lockstep with.
|
|
81
|
+
function find_version_mismatch(after: Manifest): string | undefined {
|
|
82
|
+
const pin = package_manager_version.extract_pnpm_pin(after.packageManager)
|
|
83
|
+
if (pin === undefined) return NO_PIN
|
|
84
|
+
const current = String(read_package_manager(after.devEngines)[VERSION_KEY])
|
|
85
|
+
if (current === pin) return undefined
|
|
86
|
+
if (pin.startsWith(`${current}+`)) return SUFFIX_MISSING
|
|
87
|
+
|
|
88
|
+
return `version ${current} is not the packageManager pin ${pin}`
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function judge(before_content: string, after_content: string): string {
|
|
92
|
+
const before = read_manifest(before_content).devEngines
|
|
93
|
+
const after = read_manifest(after_content)
|
|
94
|
+
if (isDeepStrictEqual(before, after.devEngines)) return UNCHANGED
|
|
95
|
+
const reason = find_structure_change(before, after.devEngines) ?? find_version_mismatch(after)
|
|
96
|
+
|
|
97
|
+
return reason === undefined ? KEPT : `devEngines: restore (${reason})`
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// A manifest that does not parse is answered apart from every verdict rather than thrown, so the
|
|
101
|
+
// overrides check that follows still runs.
|
|
102
|
+
function judge_or_explain(head: string, current: string): string {
|
|
103
|
+
try {
|
|
104
|
+
return judge(head, current)
|
|
105
|
+
} catch (error) {
|
|
106
|
+
return `devEngines: not judged (${PACKAGE_JSON} unreadable: ${String(error)})`
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function describe(head: string | undefined, current: string): string {
|
|
111
|
+
return head === undefined ? NOT_JUDGED : judge_or_explain(head, current)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// A `git show` that fails — no commit yet, no repository — answers apart from every verdict, so it
|
|
115
|
+
// never reads as a `devEngines` block the update added.
|
|
116
|
+
function report(): void {
|
|
117
|
+
const head = git_spawn_sync.read(['show', HEAD_PACKAGE_JSON])
|
|
118
|
+
|
|
119
|
+
console.info(describe(head, readFileSync(PACKAGE_JSON, 'utf8')))
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const development_engines_verdict = { judge, describe, report }
|
|
123
|
+
|
|
124
|
+
export { development_engines_verdict }
|
|
@@ -46,6 +46,7 @@ import { PACKAGE_JSON } from '#scripts/lib/package-manifest'
|
|
|
46
46
|
import { execaSync } from 'execa'
|
|
47
47
|
import semver from 'semver'
|
|
48
48
|
import { z } from 'zod'
|
|
49
|
+
import { development_engines_verdict } from './development-engines-verdict'
|
|
49
50
|
import { npm_registry } from './npm-registry'
|
|
50
51
|
import { package_manager_version } from './package-manager-version'
|
|
51
52
|
import { release_age } from './release-age'
|
|
@@ -392,6 +393,7 @@ function main(): number {
|
|
|
392
393
|
const status = bump_to_registry_target(original, extract_pnpm_major(original))
|
|
393
394
|
|
|
394
395
|
sync_development_engines()
|
|
396
|
+
development_engines_verdict.report()
|
|
395
397
|
|
|
396
398
|
return status
|
|
397
399
|
}
|
package/templates/gitignore
CHANGED
|
@@ -77,6 +77,8 @@ e2e/.auth/chrome-profile/
|
|
|
77
77
|
# Claude Code runtime artifacts
|
|
78
78
|
.claude/scheduled_tasks.lock
|
|
79
79
|
.claude/tmp/
|
|
80
|
+
# The machine-local permission allowlist (commands and paths), never shared
|
|
81
|
+
.claude/settings.local.json
|
|
80
82
|
|
|
81
83
|
# Scratch files any agent writes (Issue / PR bodies, plans, handoffs, logs); the rest of .josh/ is tracked
|
|
82
84
|
.josh/tmp/
|
|
@@ -247,6 +247,47 @@ jobs:
|
|
|
247
247
|
echo 'size-limit is not installed — skipping the bundle-size check.'
|
|
248
248
|
fi
|
|
249
249
|
|
|
250
|
+
# The pre-commit secretlint scan skips when its binary is missing and never runs on a commit made
|
|
251
|
+
# with `--no-verify`, so this job scans the pull request's changes again where neither applies
|
|
252
|
+
# (joshuafolkken/kit#4657). It needs no other job and none needs it, so it stays off the critical
|
|
253
|
+
# path, and its own `Secret Scan` context is what makes a finding block the merge. Only the files
|
|
254
|
+
# the pull request adds or changes are read: the merge commit's first parent is the base, which is
|
|
255
|
+
# why the checkout fetches two commits. secretlint comes from the same store cache every other job
|
|
256
|
+
# installs from, and `JOSH_SECRETLINT_REQUIRE` turns the hook's missing-binary skip into a failure.
|
|
257
|
+
# `shell: bash` adds `pipefail`, so a diff that fails cannot hand `xargs` an empty list and pass.
|
|
258
|
+
secret-scan:
|
|
259
|
+
name: Secret Scan
|
|
260
|
+
if: github.event_name == 'pull_request'
|
|
261
|
+
runs-on: ubuntu-latest
|
|
262
|
+
timeout-minutes: 5
|
|
263
|
+
permissions:
|
|
264
|
+
contents: read
|
|
265
|
+
packages: read
|
|
266
|
+
steps:
|
|
267
|
+
- name: Checkout code
|
|
268
|
+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
269
|
+
with:
|
|
270
|
+
persist-credentials: false
|
|
271
|
+
fetch-depth: 2
|
|
272
|
+
|
|
273
|
+
- name: Setup Node.js
|
|
274
|
+
uses: ./.github/actions/setup-node
|
|
275
|
+
|
|
276
|
+
- name: Configure GitHub Packages authentication for existing projects
|
|
277
|
+
run: printf '//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}\n' >> "$HOME/.npmrc"
|
|
278
|
+
|
|
279
|
+
- name: Setup pnpm and install dependencies
|
|
280
|
+
uses: ./.github/actions/setup-pnpm
|
|
281
|
+
with:
|
|
282
|
+
node-auth-token: ${{ secrets.GITHUB_TOKEN }}
|
|
283
|
+
|
|
284
|
+
- name: Scan the changed files for secrets
|
|
285
|
+
id: scan
|
|
286
|
+
shell: bash
|
|
287
|
+
env:
|
|
288
|
+
JOSH_SECRETLINT_REQUIRE: '1'
|
|
289
|
+
run: git diff -z --name-only --diff-filter=d HEAD^1 HEAD | xargs -0 -r pnpm josh secretlint-scan
|
|
290
|
+
|
|
250
291
|
security:
|
|
251
292
|
name: Security Audit
|
|
252
293
|
runs-on: ubuntu-latest
|