@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
|
@@ -13,6 +13,16 @@ import { issue_cite } from '#scripts/issue/issue-cite'
|
|
|
13
13
|
const PREFIX = { code: '- rf:', interaction: '- ri:' } as const
|
|
14
14
|
const FIELD_SEPARATOR = ' | '
|
|
15
15
|
const FIELD_COUNT = 5
|
|
16
|
+
// **The disposition is a sixth field, written only when given** (joshuafolkken/kit#5286): a line
|
|
17
|
+
// written before it existed keeps its five and reads as a finding with no disposition.
|
|
18
|
+
const DISPOSED_FIELD_COUNT = FIELD_COUNT + 1
|
|
19
|
+
const ISSUE_FIELD_INDEX = FIELD_COUNT - 1
|
|
20
|
+
const SEVERITY_FIELD_INDEX = 1
|
|
21
|
+
// **A code round written to the issue's file opens with a boundary line** (joshuafolkken/kit#5359):
|
|
22
|
+
// the ledger is append-only, so a stopped round's unfixed lines stay, and `josh review:round2` reads
|
|
23
|
+
// only the lines after the issue's last boundary. Its own prefix keeps it out of every `- rf:` reader.
|
|
24
|
+
const ROUND_PREFIX = '- rb:'
|
|
25
|
+
const ROUND_ISSUE_FIELD_INDEX = 1
|
|
16
26
|
|
|
17
27
|
// The nine review-rubric categories, as slugs (`prompts/review-rubric.md` → "Review categories"). A
|
|
18
28
|
// finding's category must be one of these so the aggregate stays countable rather than free text.
|
|
@@ -30,6 +40,12 @@ const CATEGORIES = [
|
|
|
30
40
|
|
|
31
41
|
const SEVERITIES = ['high', 'medium', 'low'] as const
|
|
32
42
|
|
|
43
|
+
// What became of a finding: fixed in this tree, a verified false positive, or left to another issue.
|
|
44
|
+
// Only the first two close it for `josh review:round2`.
|
|
45
|
+
const CLOSING_DISPOSITIONS = ['fixed', 'false-positive'] as const
|
|
46
|
+
const DISPOSITION_PATTERN = /^(?:fixed|false-positive|(?:filed|deferred):#[1-9]\d*)$/u
|
|
47
|
+
const DISPOSITION_SEPARATOR = ' '
|
|
48
|
+
|
|
33
49
|
// The sentinel a zero-finding round writes, so "a round ran and found nothing" is a recorded line
|
|
34
50
|
// rather than an absent one — the count's denominator survives.
|
|
35
51
|
const NONE = 'none'
|
|
@@ -43,6 +59,12 @@ interface Finding {
|
|
|
43
59
|
category: Category
|
|
44
60
|
severity: Severity
|
|
45
61
|
file: string
|
|
62
|
+
disposition?: string
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
interface DisposedSpec {
|
|
66
|
+
disposition: string | undefined
|
|
67
|
+
spec: string
|
|
46
68
|
}
|
|
47
69
|
|
|
48
70
|
interface CategoryCount {
|
|
@@ -65,6 +87,25 @@ function is_valid_file(file: string): boolean {
|
|
|
65
87
|
return file.length > 0 && !file.includes(FIELD_SEPARATOR)
|
|
66
88
|
}
|
|
67
89
|
|
|
90
|
+
function is_disposition(value: string): boolean {
|
|
91
|
+
return DISPOSITION_PATTERN.test(value)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function is_closing(disposition: string | undefined): boolean {
|
|
95
|
+
return (CLOSING_DISPOSITIONS as ReadonlyArray<string | undefined>).includes(disposition)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// A positional's leading disposition — `fixed <spec>`, `filed:#12 <spec>` — split from the spec it
|
|
99
|
+
// marks. The token the reviewer already writes before a finding it fixed, so one grammar serves both.
|
|
100
|
+
function split_disposition(positional: string): DisposedSpec {
|
|
101
|
+
const end = positional.indexOf(DISPOSITION_SEPARATOR)
|
|
102
|
+
const head = end === -1 ? '' : positional.slice(0, end)
|
|
103
|
+
|
|
104
|
+
if (!is_disposition(head)) return { disposition: undefined, spec: positional }
|
|
105
|
+
|
|
106
|
+
return { disposition: head, spec: positional.slice(end + DISPOSITION_SEPARATOR.length) }
|
|
107
|
+
}
|
|
108
|
+
|
|
68
109
|
function issue_field(issue: number): string {
|
|
69
110
|
return issue_cite.plain(issue)
|
|
70
111
|
}
|
|
@@ -79,7 +120,12 @@ function finding_line(
|
|
|
79
120
|
issue: number,
|
|
80
121
|
kind: LineKind = 'code',
|
|
81
122
|
): string {
|
|
82
|
-
|
|
123
|
+
const fields = [finding.category, finding.severity, finding.file, date, issue_field(issue)]
|
|
124
|
+
|
|
125
|
+
return line_of(
|
|
126
|
+
finding.disposition === undefined ? fields : [...fields, finding.disposition],
|
|
127
|
+
kind,
|
|
128
|
+
)
|
|
83
129
|
}
|
|
84
130
|
|
|
85
131
|
// **A zero-finding round records `none`, not nothing.** Reading its absence as "no findings" would
|
|
@@ -97,10 +143,20 @@ function fields_of(line: string, kind: LineKind = 'code'): ReadonlyArray<string>
|
|
|
97
143
|
return line.trimStart().slice(PREFIX[kind].length).split(FIELD_SEPARATOR)
|
|
98
144
|
}
|
|
99
145
|
|
|
100
|
-
|
|
101
|
-
|
|
146
|
+
// The line's fields, or `undefined` for a malformed one — five, or six with a disposition.
|
|
147
|
+
function well_formed_fields(
|
|
148
|
+
line: string,
|
|
149
|
+
kind: LineKind = 'code',
|
|
150
|
+
): ReadonlyArray<string> | undefined {
|
|
151
|
+
const fields = fields_of(line, kind)
|
|
102
152
|
|
|
103
|
-
return fields.length === FIELD_COUNT
|
|
153
|
+
return fields.length === FIELD_COUNT || fields.length === DISPOSED_FIELD_COUNT
|
|
154
|
+
? fields
|
|
155
|
+
: undefined
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function category_of(line: string): string | undefined {
|
|
159
|
+
return well_formed_fields(line)?.[0]
|
|
104
160
|
}
|
|
105
161
|
|
|
106
162
|
function increment(counts: Map<string, number>, category: string): void {
|
|
@@ -149,9 +205,50 @@ function zero_round_count(content: string): number {
|
|
|
149
205
|
// non-finding or malformed line. The record check reads this to ask whether a given issue's round was
|
|
150
206
|
// recorded at all.
|
|
151
207
|
function issue_of(line: string, kind: LineKind): string | undefined {
|
|
152
|
-
|
|
208
|
+
return well_formed_fields(line, kind)?.[ISSUE_FIELD_INDEX]
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
interface DisposedLine {
|
|
212
|
+
severity: string
|
|
213
|
+
disposition: string | undefined
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// One issue's `- rf:` lines, each with its severity and disposition — `undefined` disposition for a
|
|
217
|
+
// line written without one. `josh review:round2` reads round 1's closure from this.
|
|
218
|
+
function issue_dispositions(content: string, issue: number): ReadonlyArray<DisposedLine> {
|
|
219
|
+
const target = issue_field(issue)
|
|
220
|
+
|
|
221
|
+
return content
|
|
222
|
+
.split('\n')
|
|
223
|
+
.filter((line) => is_finding_line(line) && issue_of(line, 'code') === target)
|
|
224
|
+
.map((line) => well_formed_fields(line) ?? [])
|
|
225
|
+
.map((fields) => ({
|
|
226
|
+
severity: fields[SEVERITY_FIELD_INDEX] ?? NONE,
|
|
227
|
+
disposition: fields[FIELD_COUNT],
|
|
228
|
+
}))
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function round_line(date: string, issue: number): string {
|
|
232
|
+
return `${ROUND_PREFIX}${[date, issue_field(issue)].join(FIELD_SEPARATOR)}`
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function is_round_line(line: string, target: string): boolean {
|
|
236
|
+
const trimmed = line.trimStart()
|
|
237
|
+
|
|
238
|
+
if (!trimmed.startsWith(ROUND_PREFIX)) return false
|
|
239
|
+
|
|
240
|
+
const fields = trimmed.slice(ROUND_PREFIX.length).split(FIELD_SEPARATOR)
|
|
241
|
+
|
|
242
|
+
return fields[ROUND_ISSUE_FIELD_INDEX] === target
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// The content after the issue's last round boundary — the whole content when it has none, as a ledger
|
|
246
|
+
// written before the boundary existed does.
|
|
247
|
+
function latest_round(content: string, issue: number): string {
|
|
248
|
+
const target = issue_field(issue)
|
|
249
|
+
const lines = content.split('\n')
|
|
153
250
|
|
|
154
|
-
return
|
|
251
|
+
return lines.slice(lines.findLastIndex((line) => is_round_line(line, target)) + 1).join('\n')
|
|
155
252
|
}
|
|
156
253
|
|
|
157
254
|
// **A `none` zero-round line counts as recorded, exactly like a real finding line does.** The gate
|
|
@@ -172,13 +269,18 @@ const review_finding_ledger = {
|
|
|
172
269
|
finding_line,
|
|
173
270
|
has_issue_record,
|
|
174
271
|
is_category,
|
|
272
|
+
is_closing,
|
|
175
273
|
is_finding_line,
|
|
176
274
|
is_severity,
|
|
177
275
|
is_valid_file,
|
|
276
|
+
issue_dispositions,
|
|
277
|
+
latest_round,
|
|
278
|
+
round_line,
|
|
178
279
|
SEVERITIES,
|
|
280
|
+
split_disposition,
|
|
179
281
|
zero_round_count,
|
|
180
282
|
zero_round_line,
|
|
181
283
|
}
|
|
182
284
|
|
|
183
|
-
export type { CategoryCount, Finding, LineKind }
|
|
285
|
+
export type { CategoryCount, DisposedLine, Finding, LineKind }
|
|
184
286
|
export { review_finding_ledger }
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// A finding written in the `review:record` grammar with its reason after it — `<spec> — <sentence>` —
|
|
2
|
+
// split into the two halves, the one place both its writers read it: a ship reviewer's findings file
|
|
3
|
+
// (`run-ship-review.ts`) and an agent's own `review:record` round (`review-record-cli.ts`). The spec is
|
|
4
|
+
// what the ledger keeps; the first sentence of the reason is what the durable stop log keeps.
|
|
5
|
+
|
|
6
|
+
// What a finding line carries after its spec: one sentence saying what is wrong, so a stopped ship's
|
|
7
|
+
// log tells the resumed lane child the defect rather than only its location.
|
|
8
|
+
const DESCRIPTION_SEPARATOR = ' — '
|
|
9
|
+
// Where the spec ends on read: a reviewer that types the dash as `-`, `--` or `–` still ends it there,
|
|
10
|
+
// so its sentence never lands in the ledger's file field.
|
|
11
|
+
const DESCRIPTION_BOUNDARY = / [—–-]{1,2} /u
|
|
12
|
+
// Where a description's first sentence ends, and the cap that keeps a run-on one a line. Japanese
|
|
13
|
+
// sets no space after `。`, so it ends a sentence on its own.
|
|
14
|
+
const SENTENCE_END = /(?<=[.!?])\s|(?<=。)/u
|
|
15
|
+
const SENTENCE_LIMIT = 200
|
|
16
|
+
const ELLIPSIS = '…'
|
|
17
|
+
|
|
18
|
+
function split_description(unmarked: string): { spec: string; description: string } {
|
|
19
|
+
const boundary = DESCRIPTION_BOUNDARY.exec(unmarked)
|
|
20
|
+
|
|
21
|
+
if (boundary === null) return { spec: unmarked.trim(), description: '' }
|
|
22
|
+
|
|
23
|
+
const rest = unmarked.slice(boundary.index + boundary[0].length)
|
|
24
|
+
|
|
25
|
+
return { spec: unmarked.slice(0, boundary.index).trim(), description: rest.trim() }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function first_sentence(description: string): string {
|
|
29
|
+
const [sentence = ''] = description.split(SENTENCE_END, 1)
|
|
30
|
+
|
|
31
|
+
if (sentence.length <= SENTENCE_LIMIT) return sentence
|
|
32
|
+
|
|
33
|
+
return `${sentence.slice(0, SENTENCE_LIMIT - ELLIPSIS.length)}${ELLIPSIS}`
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const review_finding_text = {
|
|
37
|
+
DESCRIPTION_SEPARATOR,
|
|
38
|
+
SENTENCE_LIMIT,
|
|
39
|
+
first_sentence,
|
|
40
|
+
split_description,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export { review_finding_text }
|
|
@@ -2,6 +2,7 @@ import { project_checks } from '#scripts/gate/project-checks'
|
|
|
2
2
|
import { changed_paths } from '#scripts/git/changed-paths'
|
|
3
3
|
import { session_cite } from '#scripts/issue/session-cite'
|
|
4
4
|
import { observation_ledger_home } from '#scripts/observations/observation-ledger-home'
|
|
5
|
+
import { review_attest, type ReviewSlot } from './review-attest'
|
|
5
6
|
import { review_finding_ledger } from './review-finding-ledger'
|
|
6
7
|
|
|
7
8
|
// The interaction review — one adversarial pass after `/code-review`, over a change to the run
|
|
@@ -65,6 +66,15 @@ async function status(issue: number, root?: string): Promise<InteractionStatus>
|
|
|
65
66
|
return await status_of(issue, await changed_paths.read_changed_paths(false), root)
|
|
66
67
|
}
|
|
67
68
|
|
|
69
|
+
// **Round 1's slots — the interaction review beside `/code-review`'s where it is due and not yet
|
|
70
|
+
// recorded** (joshuafolkken/kit#4672, joshuafolkken/kit#4802), so it takes round 1's wait and stop.
|
|
71
|
+
// `josh ship` and `josh run:review` both open round 1 from it.
|
|
72
|
+
function round_one_slots(answer: InteractionStatus | undefined): ReadonlyArray<ReviewSlot> {
|
|
73
|
+
const { CODE, INTERACTION } = review_attest.REVIEW_SLOT
|
|
74
|
+
|
|
75
|
+
return answer === 'missing' ? [CODE, INTERACTION] : [CODE]
|
|
76
|
+
}
|
|
77
|
+
|
|
68
78
|
const MISSING_REASON =
|
|
69
79
|
'This change touches the run tooling, and no interaction review is recorded for its issue — the pass that looks for the existing features a change breaks, which `/code-review` does not (joshuafolkken/kit#4276).'
|
|
70
80
|
|
|
@@ -86,6 +96,7 @@ const review_interaction = {
|
|
|
86
96
|
NOT_DUE_LINE,
|
|
87
97
|
refusal,
|
|
88
98
|
refusal_message,
|
|
99
|
+
round_one_slots,
|
|
89
100
|
status,
|
|
90
101
|
status_of,
|
|
91
102
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { PROJECT_ROOT } from '#scripts/init/init-paths'
|
|
2
|
+
import { session_cite } from '#scripts/issue/session-cite'
|
|
3
|
+
import { lane_child_marker } from '#scripts/lane/lane-child-marker'
|
|
4
|
+
import { error_text } from '#scripts/lib/error-message'
|
|
5
|
+
import { review_round_reuse, type ReuseAnswer } from './review-round-reuse'
|
|
6
|
+
|
|
7
|
+
// joshuafolkken/kit#4850: once a lane child has recorded round 1 on a tree `josh ship` reuses, round 2
|
|
8
|
+
// is the ship's. The rule stood in `chain-rule.md` step 0 as prose alone (joshuafolkken/kit#4830), and
|
|
9
|
+
// the next lane reopened `run:review` after reading it, running a round 2 the ship then ran again. So
|
|
10
|
+
// `run:review` refuses that reopen and `review:record` names the ship as the next step.
|
|
11
|
+
//
|
|
12
|
+
// **A round the ship would review again is not handed over**: `review:record --check` then tells the
|
|
13
|
+
// lane to run round 1 itself, so `run:review` stays open for it.
|
|
14
|
+
|
|
15
|
+
const SHIP_STEP = 'pnpm josh ship --detach --review "<title> #<N>"'
|
|
16
|
+
const NEXT_STEP_LINE = `Next: hand over to \`${SHIP_STEP}\` — round 2 is the ship's; never reopen \`run:review\` (chain-rule.md step 0).`
|
|
17
|
+
|
|
18
|
+
// A reuse question git could not answer reads as not reused: the lane then reviews the round itself,
|
|
19
|
+
// which costs one review, rather than leaving it to a ship that may review it again detached.
|
|
20
|
+
// The stale read inside it fails open in `review_round_reuse.is_stale_here`, as the ship's probe reads it.
|
|
21
|
+
const UNANSWERED_CAUSE = 'git could not answer the reuse question'
|
|
22
|
+
|
|
23
|
+
async function answer_here(issue: number): Promise<ReuseAnswer> {
|
|
24
|
+
try {
|
|
25
|
+
return await review_round_reuse.answer_here(issue)
|
|
26
|
+
} catch (error) {
|
|
27
|
+
error_text.trace_swallowed('review_lane_handover.answer_here', error)
|
|
28
|
+
|
|
29
|
+
return { reuse: review_round_reuse.REUSE.AGAIN, cause: UNANSWERED_CAUSE }
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function is_reused_here(issue: number): Promise<boolean> {
|
|
34
|
+
const answer = await answer_here(issue)
|
|
35
|
+
|
|
36
|
+
return answer.reuse !== review_round_reuse.REUSE.AGAIN
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// The mark must name this issue as well as this checkout, so a person's run — or a branch whose issue
|
|
40
|
+
// is not the lane's — is never refused.
|
|
41
|
+
function is_lane_child_of(issue: number): boolean {
|
|
42
|
+
if (lane_child_marker.marked_issue() !== String(issue)) return false
|
|
43
|
+
|
|
44
|
+
return lane_child_marker.is_child_of(PROJECT_ROOT)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Reuse already requires the recorded round (`review_round_reuse.is_reusable`), so it answers both.
|
|
48
|
+
async function is_handed_over(issue: number): Promise<boolean> {
|
|
49
|
+
if (!is_lane_child_of(issue)) return false
|
|
50
|
+
|
|
51
|
+
return await is_reused_here(issue)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function refusal(issue: number): string {
|
|
55
|
+
return (
|
|
56
|
+
`⛔ run:review: round 1 of ${session_cite.issue(issue)} is recorded and josh ship reuses it, and this is a ` +
|
|
57
|
+
`dispatched lane child (\`${lane_child_marker.KEY}\`), so no brief is minted. ${NEXT_STEP_LINE}`
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const review_lane_handover = {
|
|
62
|
+
NEXT_STEP_LINE,
|
|
63
|
+
answer_here,
|
|
64
|
+
is_handed_over,
|
|
65
|
+
refusal,
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export { review_lane_handover }
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
import { text } from 'node:stream/consumers'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
4
|
+
import { review_brief_cli } from './review-brief-cli'
|
|
5
|
+
import { review_lint } from './review-lint'
|
|
6
|
+
|
|
7
|
+
// `josh review:lint` — read a review's markdown from stdin and print `ok`, or the rubric's format
|
|
8
|
+
// violations one per line, exiting non-zero so the reviewer runs it before returning its findings.
|
|
9
|
+
// `--round 2` checks the verification pass's shape instead of the full template.
|
|
10
|
+
|
|
11
|
+
const SUCCESS_EXIT_CODE = 0
|
|
12
|
+
const FAILURE_EXIT_CODE = 1
|
|
13
|
+
const OK_MESSAGE = 'ok'
|
|
14
|
+
const ARGV_OFFSET = 2
|
|
15
|
+
const USAGE = 'Usage: josh review:lint [--round <1|2>] < review.md'
|
|
16
|
+
const NO_INPUT_MESSAGE =
|
|
17
|
+
'✖ nothing on stdin — pipe the review in, e.g. `pnpm josh review:lint < review.md`'
|
|
18
|
+
|
|
19
|
+
// The lines to print on failure — a usage error, no input, or the violations — empty on a pass.
|
|
20
|
+
function failure_lines(review: string, argv: ReadonlyArray<string>): ReadonlyArray<string> {
|
|
21
|
+
const round = review_brief_cli.parse_round(argv)
|
|
22
|
+
if (round === undefined) return [USAGE]
|
|
23
|
+
if (review.trim().length === 0) return [NO_INPUT_MESSAGE]
|
|
24
|
+
|
|
25
|
+
return review_lint.with_reference(review_lint.lint_review(review, round), round)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function run(review: string, argv: ReadonlyArray<string>): number {
|
|
29
|
+
const failures = failure_lines(review, argv)
|
|
30
|
+
|
|
31
|
+
if (failures.length > 0) {
|
|
32
|
+
console.error(failures.join('\n'))
|
|
33
|
+
|
|
34
|
+
return FAILURE_EXIT_CODE
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
console.info(OK_MESSAGE)
|
|
38
|
+
|
|
39
|
+
return SUCCESS_EXIT_CODE
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function read_and_run(): Promise<number> {
|
|
43
|
+
const argv = process.argv.slice(ARGV_OFFSET)
|
|
44
|
+
if (process.stdin.isTTY) return run('', argv)
|
|
45
|
+
|
|
46
|
+
return run(await text(process.stdin), argv)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function main(): Promise<void> {
|
|
50
|
+
process.exitCode = await read_and_run()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const review_lint_cli = { run }
|
|
54
|
+
|
|
55
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) await main()
|
|
56
|
+
|
|
57
|
+
export { review_lint_cli }
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { review_lint_sections, type ReviewSection } from './review-lint-sections'
|
|
2
|
+
|
|
3
|
+
// The finding-line checks of `review:lint` (`prompts/review-rubric.md` → "Review output format"): every
|
|
4
|
+
// finding cites `file_path:line_number` and a severity, and a `low` carries its
|
|
5
|
+
// `no failure scenario — <what you tried>` line. A round-2 first-round line cites the severity it
|
|
6
|
+
// had (`(was high)`) and its resolution instead.
|
|
7
|
+
|
|
8
|
+
interface ItemRule {
|
|
9
|
+
readonly holds: (block: string) => boolean
|
|
10
|
+
readonly message: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const FILE_LINE = /`[^`\s]+:\d+(?:-\d+)?`/u
|
|
14
|
+
const SEVERITY = /\((?:high|medium|low)\)/u
|
|
15
|
+
const LOW_MARKER = '(low)'
|
|
16
|
+
const NO_FAILURE_SCENARIO = 'no failure scenario —'
|
|
17
|
+
const PRIOR_SEVERITY = /\(was (?:high|medium|low)\)/u
|
|
18
|
+
const RESOLUTION = /\bresolved\b/u
|
|
19
|
+
// An item that is a trace, a `No issues` proof or an empty section's `None` is the verdict, not a finding.
|
|
20
|
+
const VERDICT_ITEM = /^(?:Traced\b|No issues|None\b)/u
|
|
21
|
+
|
|
22
|
+
function cites_file_line(block: string): boolean {
|
|
23
|
+
return FILE_LINE.test(block)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function states_severity(block: string): boolean {
|
|
27
|
+
return SEVERITY.test(block)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// The finding's own severity is its first one; a `(low)` later in its prose is not a severity.
|
|
31
|
+
function low_has_scenario_line(block: string): boolean {
|
|
32
|
+
return SEVERITY.exec(block)?.[0] !== LOW_MARKER || block.includes(NO_FAILURE_SCENARIO)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function states_prior_severity(block: string): boolean {
|
|
36
|
+
return PRIOR_SEVERITY.test(block)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function states_resolution(block: string): boolean {
|
|
40
|
+
return RESOLUTION.test(block)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const FINDING_RULES: ReadonlyArray<ItemRule> = [
|
|
44
|
+
{ holds: cites_file_line, message: 'finding without a `file:line` citation' },
|
|
45
|
+
{ holds: states_severity, message: 'finding without a severity (high|medium|low)' },
|
|
46
|
+
{
|
|
47
|
+
holds: low_has_scenario_line,
|
|
48
|
+
message: `low finding without "${NO_FAILURE_SCENARIO} <what you tried>"`,
|
|
49
|
+
},
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
const FIRST_ROUND_RULES: ReadonlyArray<ItemRule> = [
|
|
53
|
+
{ holds: cites_file_line, message: 'first-round line without a `file:line` citation' },
|
|
54
|
+
{ holds: states_prior_severity, message: 'first-round line without "(was <severity>)"' },
|
|
55
|
+
{ holds: states_resolution, message: 'first-round line without "resolved" or "not resolved"' },
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
function first_line(block: string): string {
|
|
59
|
+
return block.split('\n', 1)[0]?.trim() ?? ''
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function rule_violations(
|
|
63
|
+
block: string,
|
|
64
|
+
heading: string,
|
|
65
|
+
rules: ReadonlyArray<ItemRule>,
|
|
66
|
+
): ReadonlyArray<string> {
|
|
67
|
+
const where = `under ### ${heading}: ${first_line(block)}`
|
|
68
|
+
|
|
69
|
+
return rules.filter((rule) => !rule.holds(block)).map((rule) => `✖ ${rule.message} ${where}`)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function finding_blocks(section: ReviewSection): ReadonlyArray<string> {
|
|
73
|
+
return review_lint_sections
|
|
74
|
+
.item_blocks(section.lines)
|
|
75
|
+
.filter((block) => !VERDICT_ITEM.test(review_lint_sections.item_text(block)))
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function finding_violations(section: ReviewSection): ReadonlyArray<string> {
|
|
79
|
+
return finding_blocks(section).flatMap((block) =>
|
|
80
|
+
rule_violations(block, section.heading, FINDING_RULES),
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function first_round_violations(section: ReviewSection): ReadonlyArray<string> {
|
|
85
|
+
return review_lint_sections
|
|
86
|
+
.item_blocks(section.lines)
|
|
87
|
+
.flatMap((block) => rule_violations(block, section.heading, FIRST_ROUND_RULES))
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const review_lint_findings = { finding_blocks, finding_violations, first_round_violations }
|
|
91
|
+
|
|
92
|
+
export { review_lint_findings }
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { document_section } from '#scripts/document/document-section'
|
|
2
|
+
|
|
3
|
+
// The parsing half of `review:lint`: a review's markdown split into its `###` sections, and a
|
|
4
|
+
// section's list items grouped with their indented continuation lines. The checks live in
|
|
5
|
+
// `review-lint.ts` and `review-lint-findings.ts`; nothing here judges what it reads.
|
|
6
|
+
|
|
7
|
+
interface ReviewSection {
|
|
8
|
+
readonly heading: string
|
|
9
|
+
readonly lines: ReadonlyArray<string>
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const HEADING_PREFIX = '### '
|
|
13
|
+
// `### 1. Bug risks & logic errors` and `### Project conventions (`CLAUDE.md`)` are the rubric's own
|
|
14
|
+
// category headings, so the number and a trailing parenthetical are dropped before the name is read.
|
|
15
|
+
const NUMBER_PREFIX = /^\d+\.\s+/u
|
|
16
|
+
const TRAILING_NOTE = / \([^)]*\)$/u
|
|
17
|
+
// A list item at column 0; an indented one is a continuation of the item above it.
|
|
18
|
+
const TOP_LEVEL_ITEM = /^(?:[-*]|\d+\.)\s+/u
|
|
19
|
+
const CONTINUATION = /^\s+\S/u
|
|
20
|
+
|
|
21
|
+
function heading_name(line: string): string {
|
|
22
|
+
return line
|
|
23
|
+
.slice(HEADING_PREFIX.length)
|
|
24
|
+
.trim()
|
|
25
|
+
.replace(NUMBER_PREFIX, '')
|
|
26
|
+
.replace(TRAILING_NOTE, '')
|
|
27
|
+
.trim()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Lines before the first heading belong to no section and are not read; a `###` line inside a code
|
|
31
|
+
// fence is quoted text, not a heading.
|
|
32
|
+
function parse_sections(review: string): ReadonlyArray<ReviewSection> {
|
|
33
|
+
const lines = review.split('\n')
|
|
34
|
+
const fenced = document_section.fenced_flags(lines)
|
|
35
|
+
const heading_flags = lines.map(
|
|
36
|
+
(line, index) => fenced[index] !== true && line.startsWith(HEADING_PREFIX),
|
|
37
|
+
)
|
|
38
|
+
const sections: Array<{ heading: string; lines: Array<string> }> = []
|
|
39
|
+
|
|
40
|
+
for (const [index, line] of lines.entries()) {
|
|
41
|
+
if (heading_flags[index] === true) sections.push({ heading: heading_name(line), lines: [] })
|
|
42
|
+
else sections.at(-1)?.lines.push(line)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return sections
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function has_content(section: ReviewSection): boolean {
|
|
49
|
+
return section.lines.some((line) => line.trim().length > 0)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function body_text(section: ReviewSection): string {
|
|
53
|
+
return section.lines.join('\n').trim()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// A line extends the block above it only when indented; any other non-blank line opens a new block —
|
|
57
|
+
// an item's own, or a closed one for prose, which closes the item above it and takes no continuation.
|
|
58
|
+
function add_line(blocks: Array<Array<string> | undefined>, line: string): void {
|
|
59
|
+
if (CONTINUATION.test(line)) blocks.at(-1)?.push(line)
|
|
60
|
+
else if (line.trim().length > 0) blocks.push(TOP_LEVEL_ITEM.test(line) ? [line] : undefined)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Each top-level item with its indented continuation lines, joined; a sentence after a list is never
|
|
64
|
+
// read as part of its last item.
|
|
65
|
+
function item_blocks(lines: ReadonlyArray<string>): ReadonlyArray<string> {
|
|
66
|
+
const blocks: Array<Array<string> | undefined> = []
|
|
67
|
+
|
|
68
|
+
for (const line of lines) add_line(blocks, line)
|
|
69
|
+
|
|
70
|
+
return blocks.filter((block) => block !== undefined).map((block) => block.join('\n'))
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function item_text(block: string): string {
|
|
74
|
+
return block.replace(TOP_LEVEL_ITEM, '')
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const review_lint_sections = { parse_sections, has_content, body_text, item_blocks, item_text }
|
|
78
|
+
|
|
79
|
+
export type { ReviewSection }
|
|
80
|
+
export { review_lint_sections }
|