@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,34 @@
|
|
|
1
|
+
// The prose of a session-facing reply — the text a person reads as sentences, with code, links and
|
|
2
|
+
// bare paths taken out. Two Stop rules read it: the reply's language (`reply-language.ts`) and its
|
|
3
|
+
// length (`concise-reply.ts`).
|
|
4
|
+
|
|
5
|
+
const CODE_PATTERNS: ReadonlyArray<RegExp> = [
|
|
6
|
+
/```[\s\S]*?(?:```|$)/gu,
|
|
7
|
+
/`[^`\n]*`/gu,
|
|
8
|
+
/\]\([^)\s]*\)/gu,
|
|
9
|
+
/https?:\/\/\S+/gu,
|
|
10
|
+
]
|
|
11
|
+
// A run of printable ASCII; one holding a slash is a bare path the reply printed outside backticks.
|
|
12
|
+
const ASCII_RUN_PATTERN = /[!-~]+/gu
|
|
13
|
+
// A table row or a list item — the structure a reply's points are carried in, not its narrative.
|
|
14
|
+
const STRUCTURE_LINE_PATTERN = /^\s*(?:\||[-*+] |[・•] ?|\d+\. )/u
|
|
15
|
+
|
|
16
|
+
function prose_of(message: string): string {
|
|
17
|
+
let text = message
|
|
18
|
+
|
|
19
|
+
for (const pattern of CODE_PATTERNS) text = text.replaceAll(pattern, ' ')
|
|
20
|
+
|
|
21
|
+
return text.replaceAll(ASCII_RUN_PATTERN, (run) => (run.includes('/') ? ' ' : run))
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// The prose outside tables and lists: what a reply narrates around its one table or list.
|
|
25
|
+
function narrative_of(message: string): string {
|
|
26
|
+
return prose_of(message)
|
|
27
|
+
.split('\n')
|
|
28
|
+
.filter((line) => !STRUCTURE_LINE_PATTERN.test(line))
|
|
29
|
+
.join('\n')
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const reply_prose = { narrative_of, prose_of }
|
|
33
|
+
|
|
34
|
+
export { reply_prose }
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { bash_triggers } from './bash-triggers'
|
|
2
|
+
import { direct_pr_create } from './direct-pr-create'
|
|
3
|
+
import { gh_api } from './gh-api'
|
|
4
|
+
import { git_argv } from './git-argv'
|
|
5
|
+
import { pr_merge } from './pr-merge'
|
|
6
|
+
import { shell_segments } from './shell-segments'
|
|
7
|
+
|
|
8
|
+
// The trigger and the delivered text behind the `repo-admin` row of `delivered-rules.ts`: a write to
|
|
9
|
+
// the repository's own administration — the rulesets and branch protection, the collaborators and
|
|
10
|
+
// their invitations, the secrets and variables, the webhooks and deploy keys, and the repository's
|
|
11
|
+
// settings. The server-side ruleset is one of the two real boundaries of an unattended run, and the
|
|
12
|
+
// trust gate reads write permission, so one injected call that adds a collaborator or disables the
|
|
13
|
+
// ruleset hands the backlog to an attacker (joshuafolkken/kit#4650).
|
|
14
|
+
//
|
|
15
|
+
// **A `DELETE` is `destructive-command`'s**, which refuses every `DELETE repos/…` already; this row
|
|
16
|
+
// takes the other write methods, so one row claims each call. `gh ruleset` has no write subcommand.
|
|
17
|
+
//
|
|
18
|
+
// **It fires on every occurrence**, for the reason `git-force.ts` does.
|
|
19
|
+
|
|
20
|
+
const GH_COMMAND = 'gh'
|
|
21
|
+
const DELETE_METHOD = 'DELETE'
|
|
22
|
+
const PATCH_METHOD = 'PATCH'
|
|
23
|
+
|
|
24
|
+
// `repos/<o>/<r>` as a path or a full URL (`https://api.github.com/repos/…`), anchored on the whole
|
|
25
|
+
// argument so a path smuggled into a field value (`-f x=repos/…/hooks`) is not read as the endpoint.
|
|
26
|
+
const REPOSITORY_PREFIX = String.raw`^['"]?(?:https?:\/\/[^/\s'"]+)?\/?repos\/[^/\s'"]+\/[^/\s'"]+`
|
|
27
|
+
// The administration endpoints under it — the environments whole, since their protection rules move
|
|
28
|
+
// the deployment boundary as their secrets do.
|
|
29
|
+
const ADMIN_PATH = new RegExp(
|
|
30
|
+
REPOSITORY_PREFIX +
|
|
31
|
+
String.raw`\/(?:rulesets|branches\/[^\s'"]+\/protection|collaborators|invitations|hooks|keys|` +
|
|
32
|
+
String.raw`transfer|actions\/permissions|environments|` +
|
|
33
|
+
String.raw`(?:actions|dependabot|codespaces)\/(?:secrets|variables))(?:[/?'"]|$)`,
|
|
34
|
+
'u',
|
|
35
|
+
)
|
|
36
|
+
// The repository itself — a `PATCH` here edits its settings (visibility, default branch, merge rules).
|
|
37
|
+
const REPOSITORY_BODY = new RegExp(String.raw`${REPOSITORY_PREFIX}\/?['"]?$`, 'u')
|
|
38
|
+
// The GraphQL mutations that do what the endpoints above do. Looked for in the whole line, as
|
|
39
|
+
// `pr-merge.ts` does, since the segment cut ignores quotes; a body read from a file is `pr-merge`'s.
|
|
40
|
+
const ADMIN_MUTATIONS =
|
|
41
|
+
/\b(?:updateRepository|archiveRepository|(?:create|update|delete)(?:BranchProtectionRule|RepositoryRuleset|Environment))\b/u
|
|
42
|
+
|
|
43
|
+
function is_admin_target(argument: string, method: string | undefined): boolean {
|
|
44
|
+
return ADMIN_PATH.test(argument) || (method === PATCH_METHOD && REPOSITORY_BODY.test(argument))
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function is_admin_graphql_call(command: string, args: ReadonlyArray<string>): boolean {
|
|
48
|
+
return pr_merge.is_graphql_call(GH_COMMAND, args) && ADMIN_MUTATIONS.test(command)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Judged on the call with its wrapper cut off, as `destructive-command.ts` does.
|
|
52
|
+
function is_admin_api_call(command: string, args: ReadonlyArray<string>): boolean {
|
|
53
|
+
const call = [GH_COMMAND, ...args].join(' ')
|
|
54
|
+
|
|
55
|
+
if (!gh_api.is_gh_api(call) || !gh_api.is_write(call)) return false
|
|
56
|
+
if (is_admin_graphql_call(command, args)) return true
|
|
57
|
+
|
|
58
|
+
const method = gh_api.method_of(call)
|
|
59
|
+
|
|
60
|
+
if (method === DELETE_METHOD) return false
|
|
61
|
+
|
|
62
|
+
return args.some((argument) => is_admin_target(argument, method))
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// The read subcommands of the groups whose every other subcommand writes.
|
|
66
|
+
const READ_ACTIONS: ReadonlySet<string> = new Set(['list', 'ls', 'get', 'view'])
|
|
67
|
+
const ACTION_POSITION = 1
|
|
68
|
+
const SUB_ACTION_POSITION = 2
|
|
69
|
+
// Where the word that decides read vs write sits, keyed by the group (`gh secret <verb>`) or by the
|
|
70
|
+
// group and action (`gh repo deploy-key <verb>`); `gh repo edit` is its own verb and only writes.
|
|
71
|
+
const VERB_POSITIONS: ReadonlyMap<string, number> = new Map([
|
|
72
|
+
['secret', ACTION_POSITION],
|
|
73
|
+
['variable', ACTION_POSITION],
|
|
74
|
+
['repo edit', ACTION_POSITION],
|
|
75
|
+
['repo deploy-key', SUB_ACTION_POSITION],
|
|
76
|
+
])
|
|
77
|
+
|
|
78
|
+
// The verb of an administration subcommand, or `undefined` for every other call. Read off the
|
|
79
|
+
// positional words, so a repository selector before the group (`gh -R o/r secret set`) is skipped.
|
|
80
|
+
function admin_verb(args: ReadonlyArray<string>): string | undefined {
|
|
81
|
+
const words = direct_pr_create.positional_words(args, direct_pr_create.API_VALUE_TAKING_FLAGS)
|
|
82
|
+
const position =
|
|
83
|
+
VERB_POSITIONS.get(words[0] ?? '') ??
|
|
84
|
+
VERB_POSITIONS.get(words.slice(0, SUB_ACTION_POSITION).join(' '))
|
|
85
|
+
|
|
86
|
+
if (position === undefined) return undefined
|
|
87
|
+
|
|
88
|
+
return words[position] ?? ''
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function is_admin_cli_call(args: ReadonlyArray<string>): boolean {
|
|
92
|
+
const verb = admin_verb(args)
|
|
93
|
+
|
|
94
|
+
return verb !== undefined && !READ_ACTIONS.has(verb)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function is_admin_segment(command: string, segment: string): boolean {
|
|
98
|
+
const args = git_argv.arguments_of(segment, GH_COMMAND)
|
|
99
|
+
|
|
100
|
+
if (args === undefined) return false
|
|
101
|
+
|
|
102
|
+
return is_admin_cli_call(args) || is_admin_api_call(command, args)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function is_repo_admin_write(command: string): boolean {
|
|
106
|
+
return shell_segments.commands_of(command).some((segment) => is_admin_segment(command, segment))
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const REPO_ADMIN_REASON =
|
|
110
|
+
'⛔ repository administration: a write to the rulesets, branch protection, collaborators, ' +
|
|
111
|
+
'invitations, secrets, variables, webhooks, deploy keys or repository settings moves the ' +
|
|
112
|
+
'boundary an unattended run relies on, which is Tier C. Ask the user to run it. It fires on every occurrence ' +
|
|
113
|
+
'(`prompts/collaboration-workflow/operating-rules.md`).'
|
|
114
|
+
|
|
115
|
+
const ROW = {
|
|
116
|
+
id: 'repo-admin',
|
|
117
|
+
is_trigger: bash_triggers.on_bash_command(is_repo_admin_write),
|
|
118
|
+
reason: REPO_ADMIN_REASON,
|
|
119
|
+
decide: (): boolean => true,
|
|
120
|
+
about: {
|
|
121
|
+
title: 'Repository administration',
|
|
122
|
+
topic: '`operating-rules.md`',
|
|
123
|
+
fires:
|
|
124
|
+
'a `gh api` POST / PUT / PATCH (path or URL) to the rulesets, branch protection, collaborators, invitations, secrets, variables, hooks, keys, environments, actions permissions or transfer, a `PATCH` of the repository, the matching GraphQL mutations, `gh secret` / `gh variable` writes, `gh repo edit` / `deploy-key` writes. Every occurrence',
|
|
125
|
+
quiet:
|
|
126
|
+
'`gh secret list`, `gh variable get`, a `gh api` read — a `DELETE` is `destructive-command`',
|
|
127
|
+
},
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const repo_admin = { REPO_ADMIN_REASON, ROW, is_repo_admin_write }
|
|
131
|
+
|
|
132
|
+
export { repo_admin }
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { lane_child_marker } from '#scripts/lane/lane-child-marker'
|
|
2
|
+
import { json_value } from '#scripts/lib/json-value'
|
|
3
|
+
import type { GuardedCall } from '#scripts/time-runtime/time-batch-guard'
|
|
4
|
+
import { agent_model } from './agent-model'
|
|
5
|
+
|
|
6
|
+
// A lane child's `reviewer` dispatched without `run_in_background: false` is run in the foreground
|
|
7
|
+
// instead (joshuafolkken/kit#5154).
|
|
8
|
+
//
|
|
9
|
+
// **A headless child's turn end kills a background reviewer**, so `chain-rule.md` → "A lane child" says
|
|
10
|
+
// not to background it. The subagent tool launches in the background by default, and 23 of 178 lanes
|
|
11
|
+
// did: #5129 polled the output file in a `sleep` loop, then waited again on `run:review --join`.
|
|
12
|
+
//
|
|
13
|
+
// **The fix is the same call with one field, so the hook makes it** (`guard-remedy.ts`): no round trip,
|
|
14
|
+
// and a build whose tool declares no `run_in_background` drops the added field as it drops the typed
|
|
15
|
+
// one. Lane children only — an interactive turn is re-invoked by the background result.
|
|
16
|
+
|
|
17
|
+
// `kit:reviewer` is the consumer's spelling of the same definitions.
|
|
18
|
+
const REVIEWER_AGENTS: ReadonlySet<string> = new Set(['reviewer', 'reviewer-verification'])
|
|
19
|
+
|
|
20
|
+
const BACKGROUND_FIELD = 'run_in_background'
|
|
21
|
+
|
|
22
|
+
const CHAIN_RULE_STEP = '`.claude/skills/workflow-commands/chain-rule.md` → "A lane child"'
|
|
23
|
+
|
|
24
|
+
const KILLED = 'reviewer foreground: a lane child’s turn end kills a background `reviewer`'
|
|
25
|
+
const FOREGROUND = `\`${BACKGROUND_FIELD}: false\``
|
|
26
|
+
|
|
27
|
+
const REVIEWER_FOREGROUND_NOTE = `↻ ${KILLED}, so the call ran with ${FOREGROUND} (${CHAIN_RULE_STEP}).`
|
|
28
|
+
|
|
29
|
+
// Delivered only where the rewrite cannot reach the call.
|
|
30
|
+
const REVIEWER_FOREGROUND_REASON = `⛔ ${KILLED}. Reissue the call with ${FOREGROUND} (${CHAIN_RULE_STEP}). It fires on every occurrence.`
|
|
31
|
+
|
|
32
|
+
function is_reviewer(call: GuardedCall): boolean {
|
|
33
|
+
if (!agent_model.SUBAGENT_TOOLS.has(call.name) || !json_value.is_record(call.input)) return false
|
|
34
|
+
|
|
35
|
+
const type = call.input['subagent_type']
|
|
36
|
+
|
|
37
|
+
return typeof type === 'string' && REVIEWER_AGENTS.has(type.split(':').at(-1) ?? '')
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function is_foreground(call: GuardedCall): boolean {
|
|
41
|
+
return json_value.is_record(call.input) && call.input[BACKGROUND_FIELD] === false
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function is_background_reviewer(
|
|
45
|
+
call: GuardedCall,
|
|
46
|
+
is_lane_child: boolean = lane_child_marker.is_child_of(process.cwd()),
|
|
47
|
+
): boolean {
|
|
48
|
+
return is_lane_child && is_reviewer(call) && !is_foreground(call)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function foreground_input(
|
|
52
|
+
call: GuardedCall,
|
|
53
|
+
is_lane_child: boolean = lane_child_marker.is_child_of(process.cwd()),
|
|
54
|
+
): Record<string, unknown> | undefined {
|
|
55
|
+
if (!is_background_reviewer(call, is_lane_child) || !json_value.is_record(call.input)) {
|
|
56
|
+
return undefined
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return { ...call.input, [BACKGROUND_FIELD]: false }
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const ROW = {
|
|
63
|
+
id: 'reviewer-foreground',
|
|
64
|
+
is_trigger: (call: GuardedCall): boolean => is_background_reviewer(call),
|
|
65
|
+
reason: REVIEWER_FOREGROUND_REASON,
|
|
66
|
+
decide: (): boolean => true,
|
|
67
|
+
keeps: (call: GuardedCall): boolean => is_reviewer(call) && is_foreground(call),
|
|
68
|
+
reaches: is_reviewer,
|
|
69
|
+
rewrite: (call: GuardedCall): Record<string, unknown> | undefined => foreground_input(call),
|
|
70
|
+
rewrite_note: REVIEWER_FOREGROUND_NOTE,
|
|
71
|
+
about: {
|
|
72
|
+
title: 'Lane child reviewer dispatched in the foreground',
|
|
73
|
+
topic: CHAIN_RULE_STEP,
|
|
74
|
+
fires:
|
|
75
|
+
'a dispatched lane child’s `Agent` / `Task` call of the `reviewer` or `reviewer-verification` type without `run_in_background: false` — rewritten with it, every occurrence',
|
|
76
|
+
quiet: 'not a lane child, another agent type, or `run_in_background: false` set',
|
|
77
|
+
},
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const reviewer_foreground = {
|
|
81
|
+
REVIEWER_FOREGROUND_NOTE,
|
|
82
|
+
REVIEWER_FOREGROUND_REASON,
|
|
83
|
+
ROW,
|
|
84
|
+
foreground_input,
|
|
85
|
+
is_background_reviewer,
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export { reviewer_foreground }
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { GuardRun } from '#scripts/josh/hook-decision'
|
|
2
|
+
import { lane_child_marker } from '#scripts/lane/lane-child-marker'
|
|
3
|
+
import { time_density_hook } from '#scripts/time-runtime/time-density-hook'
|
|
4
|
+
import { time_markers } from '#scripts/time-runtime/time-markers'
|
|
5
|
+
import { time_shell } from '#scripts/time-runtime/time-shell'
|
|
6
|
+
import { time_transcript_line, type Block } from '#scripts/time-runtime/time-transcript-line'
|
|
7
|
+
import { bash_triggers } from './bash-triggers'
|
|
8
|
+
import { shell_segments } from './shell-segments'
|
|
9
|
+
import { tail_commands } from './tail-commands'
|
|
10
|
+
|
|
11
|
+
// A lane child is stopped from running `check:related` on round 1's fixes before it joins the review.
|
|
12
|
+
//
|
|
13
|
+
// **Ship reruns the scoped pair on the fixed tree.** `chain-rule.md` → "A lane child" says the round's
|
|
14
|
+
// fixes take no `check:related` unless a brief follows: `josh ship`'s pre-detach checks the tree the
|
|
15
|
+
// fixes left. The #5168 lane fixed two findings between its brief and `run:review --join` and ran
|
|
16
|
+
// `check:related` after each, 12 of its 70 minutes, because the sentence was prose with no delivery.
|
|
17
|
+
//
|
|
18
|
+
// **The material is the run's own calls, read in order off the transcript tail.** The brief is a
|
|
19
|
+
// `run:review` in its writing mode, the fix an `Edit` / `Write` after it, and the round closes at
|
|
20
|
+
// `run:review --join` or `ship --detach`. Neither the brief file nor the join leaves a record on disk
|
|
21
|
+
// that tells "briefed, not yet joined" apart, so the tail is the one source that can answer.
|
|
22
|
+
|
|
23
|
+
// Named canonically — `shell_segments.is_josh_command` expands an alias (`josh cr`) before the match.
|
|
24
|
+
const CHECK_COMMANDS: ReadonlySet<string> = new Set(['check:related'])
|
|
25
|
+
const REVIEW_COMMANDS: ReadonlySet<string> = new Set(['run:review'])
|
|
26
|
+
const SHIP_COMMANDS: ReadonlySet<string> = new Set(['ship'])
|
|
27
|
+
const JOIN_FLAG = /(?:^|\s)--join(?:[=\s]|$)/u
|
|
28
|
+
// The `run:review` modes that read a running check rather than write a brief.
|
|
29
|
+
const READING_MODE_FLAG = /(?:^|\s)--(?:pinned|push)(?:[=\s]|$)/u
|
|
30
|
+
const DETACH_FLAG = /(?:^|\s)--detach(?:[=\s]|$)/u
|
|
31
|
+
|
|
32
|
+
type RoundEvent = 'brief' | 'close' | 'edit' | 'none'
|
|
33
|
+
|
|
34
|
+
function review_event(segment: string): RoundEvent {
|
|
35
|
+
if (JOIN_FLAG.test(segment)) return 'close'
|
|
36
|
+
|
|
37
|
+
return READING_MODE_FLAG.test(segment) ? 'none' : 'brief'
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function segment_event(segment: string): RoundEvent {
|
|
41
|
+
if (shell_segments.is_josh_command(segment, REVIEW_COMMANDS)) return review_event(segment)
|
|
42
|
+
|
|
43
|
+
const is_detach =
|
|
44
|
+
shell_segments.is_josh_command(segment, SHIP_COMMANDS) && DETACH_FLAG.test(segment)
|
|
45
|
+
|
|
46
|
+
return is_detach ? 'close' : 'none'
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function block_events(block: Block): ReadonlyArray<RoundEvent> {
|
|
50
|
+
if (tail_commands.is_bash_use(block)) {
|
|
51
|
+
const segments = shell_segments.segments_of(time_shell.bash_command(block.input))
|
|
52
|
+
|
|
53
|
+
return segments.map((segment) => segment_event(segment))
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const is_edit = time_markers.tool_marker(block.name, block.input) === time_markers.EDIT_MARKER
|
|
57
|
+
|
|
58
|
+
return is_edit ? ['edit'] : []
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Whether the tail's last brief was followed by a fix and by neither a join nor a detach.
|
|
62
|
+
function fixes_an_open_round(tail: string): boolean {
|
|
63
|
+
const blocks = time_transcript_line.parse_text(tail).flatMap((line) => line.blocks)
|
|
64
|
+
const events = blocks.flatMap((block) => block_events(block))
|
|
65
|
+
const brief_at = events.lastIndexOf('brief')
|
|
66
|
+
|
|
67
|
+
if (brief_at === -1) return false
|
|
68
|
+
|
|
69
|
+
const since_brief = new Set(events.slice(brief_at))
|
|
70
|
+
|
|
71
|
+
return since_brief.has('edit') && !since_brief.has('close')
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function runs_check_related(command: string): boolean {
|
|
75
|
+
return shell_segments
|
|
76
|
+
.segments_of(command)
|
|
77
|
+
.some((segment) => shell_segments.is_josh_command(segment, CHECK_COMMANDS))
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// **The command test comes first and the world is consulted second**: a person working in a lane
|
|
81
|
+
// carries no mark and sees no refusal.
|
|
82
|
+
function is_candidate(command: string): boolean {
|
|
83
|
+
if (!runs_check_related(command)) return false
|
|
84
|
+
|
|
85
|
+
return lane_child_marker.is_child_of(process.cwd())
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Refused on every occurrence while the round stays open: the way on is the join, never a reissue.
|
|
89
|
+
function decide(_call: unknown, run: GuardRun): boolean {
|
|
90
|
+
return fixes_an_open_round(time_density_hook.read_tail(run.transcript))
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const ROUND_ONE_CHECK_RELATED_REASON =
|
|
94
|
+
"⛔ round-one check:related: round 1's fixes need no `check:related` — ship's pre-detach reruns the " +
|
|
95
|
+
'scoped pair on the fixed tree; refused on every occurrence. Go on to `pnpm josh run:review --join`; ' +
|
|
96
|
+
'`--join --fixing` while round 1 has fixes to make (`.claude/skills/workflow-commands/chain-rule.md` → "A lane child").'
|
|
97
|
+
|
|
98
|
+
// It declares no `keeps`: skipping the check is the absence of a call, so the row is reported
|
|
99
|
+
// unmeasured rather than scored on an act that does not exist (`lane-split-park.ts`).
|
|
100
|
+
const ROW = {
|
|
101
|
+
id: 'round-one-check-related',
|
|
102
|
+
is_trigger: bash_triggers.on_bash_command(is_candidate),
|
|
103
|
+
reason: ROUND_ONE_CHECK_RELATED_REASON,
|
|
104
|
+
decide,
|
|
105
|
+
about: {
|
|
106
|
+
title: "No check:related on round 1's fixes",
|
|
107
|
+
topic: '`.claude/skills/workflow-commands/chain-rule.md` → "A lane child"',
|
|
108
|
+
fires:
|
|
109
|
+
"`pnpm josh check:related` (`josh cr`) in a lane child after an `Edit` / `Write` that follows `run:review`'s brief, before `run:review --join` or `ship --detach`. Every occurrence",
|
|
110
|
+
quiet: 'no fix since the brief, already joined or detached, or not a lane child',
|
|
111
|
+
},
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const round_one_check_related = {
|
|
115
|
+
ROUND_ONE_CHECK_RELATED_REASON,
|
|
116
|
+
ROW,
|
|
117
|
+
fixes_an_open_round,
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export { round_one_check_related }
|
|
@@ -2,6 +2,7 @@ import { json_value } from '#scripts/lib/json-value'
|
|
|
2
2
|
import { file_reader } from '#scripts/lib/read-file'
|
|
3
3
|
import type { GuardedCall } from '#scripts/time-runtime/time-batch-guard'
|
|
4
4
|
import { bash_triggers } from './bash-triggers'
|
|
5
|
+
import { edit_tool } from './edit-tool'
|
|
5
6
|
import { shell_segments } from './shell-segments'
|
|
6
7
|
import { tail_commands } from './tail-commands'
|
|
7
8
|
|
|
@@ -29,10 +30,9 @@ import { tail_commands } from './tail-commands'
|
|
|
29
30
|
// refuses until it is met. It passes on answering the questions, not on reading the
|
|
30
31
|
// reminder. Keeping the rule is therefore running those two commands, which `keeps` names.
|
|
31
32
|
|
|
32
|
-
// The two edit tools the `PreToolUse` matcher routes here. A `Write` carries the whole
|
|
33
|
-
// `Edit` carries the region as `old_string` / `new_string`.
|
|
34
|
-
const
|
|
35
|
-
const WRITE_TOOL = 'Write'
|
|
33
|
+
// The two edit tools the `PreToolUse` matcher routes here (`edit-tool.ts`). A `Write` carries the whole
|
|
34
|
+
// new file; an `Edit` carries the region as `old_string` / `new_string`.
|
|
35
|
+
const { WRITE, is_edit_tool, string_field } = edit_tool
|
|
36
36
|
|
|
37
37
|
// The three rule-document families question 0 must be pushed at: the resident source, the
|
|
38
38
|
// collaboration-workflow prompts, and the skill bodies. Anchored at a path separator or the string
|
|
@@ -69,12 +69,6 @@ function adds_rule_prose(old_text: string, new_text: string): boolean {
|
|
|
69
69
|
return prose_of(new_text).length - prose_of(old_text).length >= MIN_APPENDED_PROSE
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
function string_field(input: Record<string, unknown>, key: string): string {
|
|
73
|
-
const value = input[key]
|
|
74
|
-
|
|
75
|
-
return typeof value === 'string' ? value : ''
|
|
76
|
-
}
|
|
77
|
-
|
|
78
72
|
// The file's current text, read synchronously before the write lands so a `Write` has an `old` to
|
|
79
73
|
// measure against. Injected so the suite controls it without touching the real filesystem, the way
|
|
80
74
|
// `file-body.ts` injects its existence check. A new file reads as empty, so its whole body is added.
|
|
@@ -87,7 +81,7 @@ function texts_of(
|
|
|
87
81
|
input: Record<string, unknown>,
|
|
88
82
|
read: (file_path: string) => string,
|
|
89
83
|
): { old_text: string; new_text: string } {
|
|
90
|
-
if (name ===
|
|
84
|
+
if (name === WRITE) {
|
|
91
85
|
return {
|
|
92
86
|
old_text: read(string_field(input, 'file_path')),
|
|
93
87
|
new_text: string_field(input, 'content'),
|
|
@@ -100,10 +94,6 @@ function texts_of(
|
|
|
100
94
|
}
|
|
101
95
|
}
|
|
102
96
|
|
|
103
|
-
function is_edit_tool(name: string): boolean {
|
|
104
|
-
return name === EDIT_TOOL || name === WRITE_TOOL
|
|
105
|
-
}
|
|
106
|
-
|
|
107
97
|
// The call's input when it is an edit of a rule document, and `undefined` otherwise. The tool-name and
|
|
108
98
|
// path tests run before the text read, so an ordinary edit pays nothing and a `Write`'s file read
|
|
109
99
|
// happens only for a rule document.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process'
|
|
2
2
|
import { statSync } from 'node:fs'
|
|
3
3
|
import path from 'node:path'
|
|
4
|
+
import { git_common_directory } from '#scripts/git/git-common-directory'
|
|
4
5
|
import { atomic_write } from '#scripts/lib/atomic-write'
|
|
5
6
|
import { file_reader } from '#scripts/lib/read-file'
|
|
6
7
|
import { MS_PER_MINUTE } from '#scripts/lib/timeouts'
|
|
@@ -14,7 +15,12 @@ import { MS_PER_MINUTE } from '#scripts/lib/timeouts'
|
|
|
14
15
|
// **It reports and never fails**, as `rule:value` itself does: a missing cache, an unwritable directory
|
|
15
16
|
// or a refresh that could not start prints at most nothing, and never changes the offer's answer.
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
// Outside a repository only: inside one the cache lives in the common git directory, so a lane's work
|
|
19
|
+
// tree reads the reading its parent's loop head stored rather than measuring again
|
|
20
|
+
// (joshuafolkken/kit#5186). The reading is the main checkout's — its transcripts and every lane's —
|
|
21
|
+
// because only the main checkout writes it (`is_linked_work_tree`); a lane's own measurement reaches
|
|
22
|
+
// only its own transcripts (`cost_transcript.transcript_directories`).
|
|
23
|
+
const FALLBACK_DIRECTORY = ['node_modules', '.cache', 'josh']
|
|
18
24
|
const CACHE_FILE = 'rule-value.txt'
|
|
19
25
|
// Touched when a refresh starts, so the loop head starts at most one per interval however often it runs.
|
|
20
26
|
const STAMP_FILE = 'rule-value.stamp'
|
|
@@ -28,14 +34,48 @@ interface CachePorts {
|
|
|
28
34
|
start_refresh: (cwd: string) => void
|
|
29
35
|
}
|
|
30
36
|
|
|
37
|
+
interface FreshReading {
|
|
38
|
+
text: string
|
|
39
|
+
taken_at: Date
|
|
40
|
+
}
|
|
41
|
+
|
|
31
42
|
function cache_path(cwd: string, file: string): string {
|
|
32
|
-
|
|
43
|
+
const common = git_common_directory.repository(cwd)
|
|
44
|
+
|
|
45
|
+
if (common === undefined) return path.join(cwd, ...FALLBACK_DIRECTORY, file)
|
|
46
|
+
|
|
47
|
+
return path.join(common, git_common_directory.STATE_DIRECTORY, file)
|
|
33
48
|
}
|
|
34
49
|
|
|
35
50
|
function read_cached(cwd: string): string | undefined {
|
|
36
51
|
return file_reader.read_if_readable(cache_path(cwd, CACHE_FILE))
|
|
37
52
|
}
|
|
38
53
|
|
|
54
|
+
function taken_at_if_fresh(cwd: string, now_ms: number): Date | undefined {
|
|
55
|
+
try {
|
|
56
|
+
const { mtime } = statSync(cache_path(cwd, CACHE_FILE))
|
|
57
|
+
|
|
58
|
+
return now_ms - mtime.getTime() < REFRESH_MS ? mtime : undefined
|
|
59
|
+
} catch {
|
|
60
|
+
return undefined
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// The stored reading when it was taken inside the refresh interval — what `josh rule:value` prints
|
|
65
|
+
// instead of measuring. `undefined` is a miss: no reading, or one older than the interval.
|
|
66
|
+
function read_fresh(
|
|
67
|
+
cwd: string = process.cwd(),
|
|
68
|
+
now_ms: number = Date.now(),
|
|
69
|
+
): FreshReading | undefined {
|
|
70
|
+
const taken_at = taken_at_if_fresh(cwd, now_ms)
|
|
71
|
+
|
|
72
|
+
if (taken_at === undefined) return undefined
|
|
73
|
+
|
|
74
|
+
const text = read_cached(cwd)
|
|
75
|
+
|
|
76
|
+
return text === undefined ? undefined : { text, taken_at }
|
|
77
|
+
}
|
|
78
|
+
|
|
39
79
|
function is_refresh_due(cwd: string, now_ms: number): boolean {
|
|
40
80
|
try {
|
|
41
81
|
return now_ms - statSync(cache_path(cwd, STAMP_FILE)).mtimeMs >= REFRESH_MS
|
|
@@ -63,8 +103,14 @@ function start_refresh_default(cwd: string): void {
|
|
|
63
103
|
|
|
64
104
|
const DEFAULT_PORTS: CachePorts = { now: Date.now, start_refresh: start_refresh_default }
|
|
65
105
|
|
|
106
|
+
// A linked work tree — a lane — measures its own transcripts alone, so it never writes the main
|
|
107
|
+
// checkout's reading or its stamp: either would stand in for the whole repository's for an interval.
|
|
108
|
+
function is_linked_work_tree(cwd: string): boolean {
|
|
109
|
+
return git_common_directory.resolve(cwd) !== undefined
|
|
110
|
+
}
|
|
111
|
+
|
|
66
112
|
function refresh_if_due(cwd: string, ports: CachePorts): void {
|
|
67
|
-
if (!is_refresh_due(cwd, ports.now())) return
|
|
113
|
+
if (is_linked_work_tree(cwd) || !is_refresh_due(cwd, ports.now())) return
|
|
68
114
|
|
|
69
115
|
write_cache_file(cwd, STAMP_FILE, new Date(ports.now()).toISOString())
|
|
70
116
|
ports.start_refresh(cwd)
|
|
@@ -85,10 +131,12 @@ function emit(cwd: string = process.cwd(), ports: CachePorts = DEFAULT_PORTS): v
|
|
|
85
131
|
|
|
86
132
|
// The detached refresh's body: the reading written whole, so a reader never sees half of one.
|
|
87
133
|
function store(text: string, cwd: string = process.cwd()): void {
|
|
134
|
+
if (is_linked_work_tree(cwd)) return
|
|
135
|
+
|
|
88
136
|
write_cache_file(cwd, CACHE_FILE, `${text}\n`)
|
|
89
137
|
}
|
|
90
138
|
|
|
91
|
-
const rule_value_cache = { CACHE_FILE, REFRESH_MS, STAMP_FILE, cache_path, emit, store }
|
|
139
|
+
const rule_value_cache = { CACHE_FILE, REFRESH_MS, STAMP_FILE, cache_path, emit, read_fresh, store }
|
|
92
140
|
|
|
93
|
-
export type { CachePorts }
|
|
141
|
+
export type { CachePorts, FreshReading }
|
|
94
142
|
export { rule_value_cache }
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { delivered_rules, type MeasuredRule } from './delivered-rules'
|
|
2
|
+
import type { RuleReading } from './rule-value'
|
|
3
|
+
|
|
4
|
+
// The rules `rule:value`'s reading says can go or shrink — the evidence
|
|
5
|
+
// `prompts/collaboration-workflow/residency.md` lets a retirement or a condensation rest on. **It lists, never removes**: each candidate is retired or condensed in an
|
|
6
|
+
// Issue of its own, or kept with a recorded reason.
|
|
7
|
+
//
|
|
8
|
+
// - **Retire**: no run reached the rule, over a window large enough for "never" to mean something.
|
|
9
|
+
// Below it nothing is judged, since a fresh checkout reaches no rule at all. **Measurable rows
|
|
10
|
+
// only**: an unmeasured row's trigger is the violation itself, so its `reached 0` says the rule was
|
|
11
|
+
// never broken — the guard working — not that its situation never arose. A measurable row's trigger
|
|
12
|
+
// is a neutral act or it declares `reaches` (`rule-value.ts`, `RuleReading.sessions`).
|
|
13
|
+
// - **Condense**: the hook refuses the rule on every occurrence (`decide`) and has refused it at least
|
|
14
|
+
// once, so the prose need only point at the row — the hook, not the text, keeps it.
|
|
15
|
+
|
|
16
|
+
// The one threshold: the runs a reading must cover before a rule no run reached is a retirement
|
|
17
|
+
// candidate.
|
|
18
|
+
const MIN_RUNS_FOR_RETIREMENT = 20
|
|
19
|
+
const SEPARATOR = ', '
|
|
20
|
+
const NONE = 'none'
|
|
21
|
+
|
|
22
|
+
interface RuleCandidates {
|
|
23
|
+
retire: ReadonlyArray<string>
|
|
24
|
+
condense: ReadonlyArray<string>
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function retire_candidates(readings: ReadonlyArray<RuleReading>, runs: number): Array<string> {
|
|
28
|
+
if (runs < MIN_RUNS_FOR_RETIREMENT) return []
|
|
29
|
+
|
|
30
|
+
return readings
|
|
31
|
+
.filter((reading) => reading.is_measurable && reading.sessions === 0)
|
|
32
|
+
.map((reading) => reading.id)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function is_enforced_on_every_occurrence(id: string, rules: ReadonlyArray<MeasuredRule>): boolean {
|
|
36
|
+
return rules.some((rule) => rule.id === id && rule.decide !== undefined)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function condense_candidates(
|
|
40
|
+
readings: ReadonlyArray<RuleReading>,
|
|
41
|
+
rules: ReadonlyArray<MeasuredRule> = delivered_rules.MEASURED_RULES,
|
|
42
|
+
): Array<string> {
|
|
43
|
+
return readings
|
|
44
|
+
.filter((reading) => reading.refusals > 0)
|
|
45
|
+
.filter((reading) => is_enforced_on_every_occurrence(reading.id, rules))
|
|
46
|
+
.map((reading) => reading.id)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function judge(
|
|
50
|
+
readings: ReadonlyArray<RuleReading>,
|
|
51
|
+
runs: number,
|
|
52
|
+
rules: ReadonlyArray<MeasuredRule> = delivered_rules.MEASURED_RULES,
|
|
53
|
+
): RuleCandidates {
|
|
54
|
+
return {
|
|
55
|
+
retire: retire_candidates(readings, runs),
|
|
56
|
+
condense: condense_candidates(readings, rules),
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function listed(ids: ReadonlyArray<string>): string {
|
|
61
|
+
return ids.length === 0 ? NONE : ids.join(SEPARATOR)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function render(candidates: RuleCandidates, runs: number): string {
|
|
65
|
+
const window = `${runs.toString()} runs, threshold ${MIN_RUNS_FOR_RETIREMENT.toString()}`
|
|
66
|
+
|
|
67
|
+
return [
|
|
68
|
+
'candidates:',
|
|
69
|
+
` retire (reached 0; ${window}): ${listed(candidates.retire)}`,
|
|
70
|
+
` condense (refused on every occurrence by its hook): ${listed(candidates.condense)}`,
|
|
71
|
+
].join('\n')
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const rule_value_candidates = {
|
|
75
|
+
condense_candidates,
|
|
76
|
+
judge,
|
|
77
|
+
render,
|
|
78
|
+
retire_candidates,
|
|
79
|
+
MIN_RUNS_FOR_RETIREMENT,
|
|
80
|
+
NONE,
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export type { RuleCandidates }
|
|
84
|
+
export { rule_value_candidates }
|