@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,152 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
import { cost_transcript } from '#scripts/cost-runtime/cost-transcript'
|
|
3
|
+
import { own_session } from '#scripts/cost-runtime/own-session'
|
|
4
|
+
import { duplicate_reads } from '#scripts/delegation/duplicate-read-guard'
|
|
5
|
+
import { json_value } from '#scripts/lib/json-value'
|
|
6
|
+
import { transcript_record, type TranscriptRecord } from '#scripts/lib/transcript-record'
|
|
7
|
+
import { time_spans } from '#scripts/time-runtime/time-spans'
|
|
8
|
+
import { z } from 'zod'
|
|
9
|
+
|
|
10
|
+
// What the cut session already read and decided, derived from its own transcript so the resumed
|
|
11
|
+
// process does not spend minutes re-reading to rebuild it (joshuafolkken/kit#5040).
|
|
12
|
+
//
|
|
13
|
+
// **Derived, not written by the agent.** The reads are tool calls and the decisions are the
|
|
14
|
+
// `Auto-decided:` lines the session already logs (`CLAUDE.md` → "Decision autonomy") — in its reply,
|
|
15
|
+
// or in the Issue comment a tool call posts — so the cut takes both from the transcript: nothing to
|
|
16
|
+
// forget, and no handoff key the refusal has to spell out.
|
|
17
|
+
|
|
18
|
+
interface SessionDigest {
|
|
19
|
+
read: ReadonlyArray<string>
|
|
20
|
+
decisions: ReadonlyArray<string>
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const session_digest_schema = z.object({
|
|
24
|
+
read: z.array(z.string()),
|
|
25
|
+
decisions: z.array(z.string()),
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
// The newest entries are kept: the record has a byte bound, and the last reads are the ones the
|
|
29
|
+
// resumed work continues from.
|
|
30
|
+
const MAX_READ_ENTRIES = 40
|
|
31
|
+
const MAX_DECISIONS = 12
|
|
32
|
+
const MAX_DECISION_CHARS = 240
|
|
33
|
+
const DECISION_PREFIX = 'Auto-decided:'
|
|
34
|
+
// A logged decision wherever it starts a line or follows a quote or `body=`; the space after the colon
|
|
35
|
+
// keeps out the bare prefix a source file spells.
|
|
36
|
+
const DECISION_LINE = /(?:^|[\s'"=])(Auto-decided: [^\n]+)/gu
|
|
37
|
+
// The quote closing a `body='…'` argument.
|
|
38
|
+
const TRAILING_QUOTES = /['"]$/u
|
|
39
|
+
const ASSISTANT = 'assistant'
|
|
40
|
+
const READ_LABEL = 'Already read before the cut — re-read only the lines you need'
|
|
41
|
+
const DECISIONS_LABEL = 'Decided before the cut — do not reopen'
|
|
42
|
+
|
|
43
|
+
function shown_path(target: string, cwd: string): string {
|
|
44
|
+
const relative = path.relative(cwd, path.resolve(cwd, target))
|
|
45
|
+
|
|
46
|
+
return relative.startsWith('..') ? target : relative
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function newest_unique(entries: ReadonlyArray<string>, limit: number): Array<string> {
|
|
50
|
+
const unique = [...new Set(entries.toReversed())].toReversed()
|
|
51
|
+
|
|
52
|
+
return unique.slice(-limit)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function read_files_of(text: string, cwd: string): Array<string> {
|
|
56
|
+
const reads = time_spans
|
|
57
|
+
.parse_timeline(text)
|
|
58
|
+
.spans.filter((span) => duplicate_reads.is_successful_read(span))
|
|
59
|
+
.flatMap((span) => span.targets.map((target) => shown_path(target, cwd)))
|
|
60
|
+
|
|
61
|
+
return newest_unique(reads, MAX_READ_ENTRIES)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Where a tool call carries an Issue comment: the Bash command posting it, or the body file a `Write`
|
|
65
|
+
// prepared for it. An `Edit`'s strings are source text, so they are not read.
|
|
66
|
+
const COMMENT_INPUT_KEYS = ['command', 'content']
|
|
67
|
+
|
|
68
|
+
function input_strings(input: unknown): Array<string> {
|
|
69
|
+
if (!json_value.is_record(input)) return []
|
|
70
|
+
|
|
71
|
+
return COMMENT_INPUT_KEYS.map((key) => input[key]).filter((value) => typeof value === 'string')
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// What the session wrote: its reply text and the inputs of its tool calls, where an Issue workflow's
|
|
75
|
+
// decision comment travels.
|
|
76
|
+
function assistant_texts(record: TranscriptRecord | undefined): Array<string> {
|
|
77
|
+
if (record?.type !== ASSISTANT) return []
|
|
78
|
+
|
|
79
|
+
return transcript_record
|
|
80
|
+
.blocks_of(record)
|
|
81
|
+
.flatMap((block) => [block.text ?? '', ...input_strings(block.input)])
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function decisions_of(text: string): Array<string> {
|
|
85
|
+
const decisions = text
|
|
86
|
+
.split('\n')
|
|
87
|
+
.flatMap((line) => assistant_texts(transcript_record.parse(line)))
|
|
88
|
+
.flatMap((written) => [...written.matchAll(DECISION_LINE)].map((match) => match[1] ?? ''))
|
|
89
|
+
.map((line) => line.replace(TRAILING_QUOTES, '').slice(0, MAX_DECISION_CHARS))
|
|
90
|
+
|
|
91
|
+
return newest_unique(decisions, MAX_DECISIONS)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function digest_of(text: string, cwd: string): SessionDigest {
|
|
95
|
+
return { read: read_files_of(text, cwd), decisions: decisions_of(text) }
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// The running session's own transcript, or `undefined`. Only a session that names itself is read: the
|
|
99
|
+
// newest-file fallback could pick another session filed under the checkout (a Codex lane's reviewer).
|
|
100
|
+
function own_transcript(cwd: string, environment: NodeJS.ProcessEnv): string | undefined {
|
|
101
|
+
if (own_session.session_id_of(environment) === undefined) return undefined
|
|
102
|
+
|
|
103
|
+
const files = cost_transcript.list_sessions_across(cost_transcript.transcript_directories(cwd))
|
|
104
|
+
const selection = own_session.select_own_session(files, environment)
|
|
105
|
+
if (selection.kind === 'absent') return undefined
|
|
106
|
+
|
|
107
|
+
const file = files[selection.index]
|
|
108
|
+
|
|
109
|
+
return file === undefined ? undefined : cost_transcript.read_optional(file)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// The running session's own digest, or `undefined` when its transcript cannot be found — a cut is
|
|
113
|
+
// never refused for want of one.
|
|
114
|
+
function own_digest(
|
|
115
|
+
cwd: string = process.cwd(),
|
|
116
|
+
environment: NodeJS.ProcessEnv = process.env,
|
|
117
|
+
): SessionDigest | undefined {
|
|
118
|
+
const text = own_transcript(cwd, environment)
|
|
119
|
+
|
|
120
|
+
return text === undefined ? undefined : digest_of(text, cwd)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function describe_list(label: string, entries: ReadonlyArray<string>): Array<string> {
|
|
124
|
+
if (entries.length === 0) return []
|
|
125
|
+
|
|
126
|
+
const bullets = entries.map((entry) => ` - ${entry}`).join('\n')
|
|
127
|
+
|
|
128
|
+
return [`${label}:\n${bullets}`]
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// The block the resume prints; nothing for a digest with neither list.
|
|
132
|
+
function describe_digest(digest: SessionDigest | undefined): string | undefined {
|
|
133
|
+
if (digest === undefined) return undefined
|
|
134
|
+
|
|
135
|
+
const blocks = [
|
|
136
|
+
...describe_list(READ_LABEL, digest.read),
|
|
137
|
+
...describe_list(DECISIONS_LABEL, digest.decisions),
|
|
138
|
+
]
|
|
139
|
+
|
|
140
|
+
return blocks.length === 0 ? undefined : blocks.join('\n\n')
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const run_cut_digest = {
|
|
144
|
+
DECISION_PREFIX,
|
|
145
|
+
describe_digest,
|
|
146
|
+
digest_of,
|
|
147
|
+
own_digest,
|
|
148
|
+
session_digest_schema,
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export type { SessionDigest }
|
|
152
|
+
export { run_cut_digest }
|
|
@@ -25,6 +25,9 @@ interface Handoff {
|
|
|
25
25
|
completed: ReadonlyArray<string>
|
|
26
26
|
remaining: ReadonlyArray<string>
|
|
27
27
|
untouched: ReadonlyArray<string>
|
|
28
|
+
// An attested review round's findings not yet `review:record`ed — the conversation that held them is
|
|
29
|
+
// what the cut drops, so without this the resumed run reruns round 1 (joshuafolkken/kit#4868).
|
|
30
|
+
findings?: ReadonlyArray<string> | undefined
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
const handoff_schema = z.object({
|
|
@@ -32,6 +35,7 @@ const handoff_schema = z.object({
|
|
|
32
35
|
completed: z.array(z.string()),
|
|
33
36
|
remaining: z.array(z.string()),
|
|
34
37
|
untouched: z.array(z.string()),
|
|
38
|
+
findings: z.array(z.string()).optional(),
|
|
35
39
|
})
|
|
36
40
|
|
|
37
41
|
// The label each list is printed under when the handoff is shown to the resumed session, kept beside
|
|
@@ -40,23 +44,34 @@ const COMPLETED_LABEL = 'Completed'
|
|
|
40
44
|
const REMAINING_LABEL = 'Remaining'
|
|
41
45
|
const UNTOUCHED_LABEL = 'Deliberately untouched'
|
|
42
46
|
const INSTRUCTION_LABEL = 'Instruction (verbatim)'
|
|
47
|
+
const FINDINGS_LABEL =
|
|
48
|
+
'Round-1 findings, attested but not recorded — do not rerun round 1: fix them, then record them with `pnpm josh review:record --issue <N>`'
|
|
43
49
|
const EMPTY_LIST_NOTE = '(none)'
|
|
44
50
|
|
|
45
51
|
type HandoffKey = keyof Handoff
|
|
46
52
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
53
|
+
// The placeholders each example value is drawn with; `findings`' says which round it carries. They
|
|
54
|
+
// parse, so a copied example is read as entries — `carried_findings` drops them, or a copied
|
|
55
|
+
// `findings` would pass the unrecorded-round refusal.
|
|
56
|
+
const PLACEHOLDER = '…'
|
|
57
|
+
const FINDINGS_PLACEHOLDER = 'unrecorded'
|
|
58
|
+
const EXAMPLE_LIST = `["${PLACEHOLDER}"]`
|
|
59
|
+
|
|
60
|
+
const EXAMPLE_VALUES: Readonly<Record<HandoffKey, string>> = {
|
|
61
|
+
instruction: `"${PLACEHOLDER}"`,
|
|
62
|
+
completed: EXAMPLE_LIST,
|
|
63
|
+
remaining: EXAMPLE_LIST,
|
|
64
|
+
untouched: EXAMPLE_LIST,
|
|
65
|
+
findings: `["${FINDINGS_PLACEHOLDER}"]`,
|
|
51
66
|
}
|
|
52
67
|
|
|
53
|
-
// The shape a handoff file must have,
|
|
68
|
+
// The shape a handoff file must have, keyed from `handoff_schema` so the refusal that asks for the file
|
|
54
69
|
// and the error that rejects it can never name a key the parser does not read — a refusal listing the
|
|
55
70
|
// items in prose invites Markdown, which `parse_handoff` rejects.
|
|
56
|
-
const HANDOFF_FORMAT = `
|
|
71
|
+
const HANDOFF_FORMAT = `{${handoff_schema
|
|
57
72
|
.keyof()
|
|
58
|
-
.options.map((key) =>
|
|
59
|
-
.join(',
|
|
73
|
+
.options.map((key) => `"${key}":${EXAMPLE_VALUES[key]}`)
|
|
74
|
+
.join(',')}}`
|
|
60
75
|
|
|
61
76
|
function parse_handoff(raw: string): Handoff | undefined {
|
|
62
77
|
return json_value.parse_with(raw, handoff_schema)
|
|
@@ -115,6 +130,25 @@ function describe_list(label: string, items: ReadonlyArray<string>): string {
|
|
|
115
130
|
return `${label}:\n${bullets}`
|
|
116
131
|
}
|
|
117
132
|
|
|
133
|
+
// The findings a handoff really carries: a blank entry or an example placeholder is no finding.
|
|
134
|
+
function carried_findings(handoff: Handoff | undefined): ReadonlyArray<string> {
|
|
135
|
+
const findings = handoff?.findings ?? []
|
|
136
|
+
|
|
137
|
+
return findings.filter(
|
|
138
|
+
(finding) => ![PLACEHOLDER, FINDINGS_PLACEHOLDER, ''].includes(finding.trim()),
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Carried findings are printed only when there are some — a handoff cut before any review says nothing
|
|
143
|
+
// about one.
|
|
144
|
+
function describe_findings(handoff: Handoff): ReadonlyArray<string> {
|
|
145
|
+
const findings = carried_findings(handoff)
|
|
146
|
+
|
|
147
|
+
if (findings.length === 0) return []
|
|
148
|
+
|
|
149
|
+
return [describe_list(FINDINGS_LABEL, findings)]
|
|
150
|
+
}
|
|
151
|
+
|
|
118
152
|
// The block the resume prints to standard error so the fresh process continues on the original
|
|
119
153
|
// instruction rather than the tree alone.
|
|
120
154
|
function describe_handoff(handoff: Handoff): string {
|
|
@@ -123,6 +157,7 @@ function describe_handoff(handoff: Handoff): string {
|
|
|
123
157
|
describe_list(COMPLETED_LABEL, handoff.completed),
|
|
124
158
|
describe_list(REMAINING_LABEL, handoff.remaining),
|
|
125
159
|
describe_list(UNTOUCHED_LABEL, handoff.untouched),
|
|
160
|
+
...describe_findings(handoff),
|
|
126
161
|
].join('\n\n')
|
|
127
162
|
}
|
|
128
163
|
|
|
@@ -130,10 +165,19 @@ function describe_handoff(handoff: Handoff): string {
|
|
|
130
165
|
// untracked non-ignored file, cannot commit the note with the code. A refusal that asked for "a file"
|
|
131
166
|
// and named no place got one written beside the code and committed (joshuafolkken/kit#3603).
|
|
132
167
|
const HANDOFF_PATH = '.josh/tmp/handoff-<N>.json'
|
|
168
|
+
const ISSUE_PLACEHOLDER = '<N>'
|
|
169
|
+
|
|
170
|
+
// The handoff path for one issue, relative to the checkout — the path `HANDOFF_PATH` tells the run
|
|
171
|
+
// to write, so the implementation-cut guard can let that one write through.
|
|
172
|
+
function handoff_path_of(issue: string): string {
|
|
173
|
+
return HANDOFF_PATH.replace(ISSUE_PLACEHOLDER, () => issue)
|
|
174
|
+
}
|
|
133
175
|
|
|
134
176
|
const run_cut_handoff = {
|
|
135
177
|
HANDOFF_FORMAT,
|
|
136
178
|
HANDOFF_PATH,
|
|
179
|
+
handoff_path_of,
|
|
180
|
+
carried_findings,
|
|
137
181
|
describe_handoff,
|
|
138
182
|
handoff_schema,
|
|
139
183
|
is_complete_handoff,
|
|
@@ -38,6 +38,7 @@ const UNKNOWN_VERDICT = 'unknown'
|
|
|
38
38
|
// The asking session is over the shared context-cut threshold, so an implementation cut was not
|
|
39
39
|
// resumed into it — the same refusal `run:carry` answers `over` with.
|
|
40
40
|
const OVER_VERDICT = 'over'
|
|
41
|
+
const SPLIT_UNRESOLVED_VERDICT = 'split-unresolved'
|
|
41
42
|
|
|
42
43
|
function report(verdict: string, code: number): number {
|
|
43
44
|
console.info(verdict)
|
|
@@ -127,12 +128,13 @@ function report_under_threshold(): number {
|
|
|
127
128
|
}
|
|
128
129
|
|
|
129
130
|
// **A ship reviewer takes no cut, of either phase** (joshuafolkken/kit#3623). Its supervisor is waiting
|
|
130
|
-
// on the findings
|
|
131
|
+
// on the findings it has yet to submit, so a relaunch would stand a second child in the lane beside
|
|
131
132
|
// the one the supervisor repairs with. Answered `not-a-lane`, the verdict that already means "nothing
|
|
132
|
-
// was cut and this process carries on".
|
|
133
|
+
// was cut and this process carries on". The message names no sink: its review prompt says whether it
|
|
134
|
+
// submits through `review:submit` or, on a lane that predates it, writes a path (joshuafolkken/kit#4799).
|
|
133
135
|
function report_reviewer(): number {
|
|
134
136
|
console.error(
|
|
135
|
-
'This session is a ship reviewer, which its supervisor is waiting on, so nothing was cut and nothing was relaunched.
|
|
137
|
+
'This session is a ship reviewer, which its supervisor is waiting on, so nothing was cut and nothing was relaunched. Finish the review in this process and submit its findings the way your review prompt says.',
|
|
136
138
|
)
|
|
137
139
|
|
|
138
140
|
return report(NOT_A_LANE_VERDICT, SUCCESS_EXIT_CODE)
|
|
@@ -174,6 +176,22 @@ function report_over(): number {
|
|
|
174
176
|
return report(OVER_VERDICT, FAILURE_EXIT_CODE)
|
|
175
177
|
}
|
|
176
178
|
|
|
179
|
+
function report_missing_supervisor(issue: string): number {
|
|
180
|
+
console.error(
|
|
181
|
+
`The OpenAI supervisor for ${session_cite.issue(issue)} is not live, so this nested process was not cut and can continue. Re-dispatch the lane to recover the supervisor.`,
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
return report(FAILED_VERDICT, FAILURE_EXIT_CODE)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// The lane got the split notice and has answered it neither way, so nothing was cut and the run does
|
|
188
|
+
// not go on to the gate until it does (joshuafolkken/kit#4695). `note` says which answers it takes.
|
|
189
|
+
function report_split_unresolved(note: string): number {
|
|
190
|
+
console.error(note)
|
|
191
|
+
|
|
192
|
+
return report(SPLIT_UNRESOLVED_VERDICT, FAILURE_EXIT_CODE)
|
|
193
|
+
}
|
|
194
|
+
|
|
177
195
|
const run_cut_report = {
|
|
178
196
|
BAD_HANDOFF_VERDICT,
|
|
179
197
|
BUSY_VERDICT,
|
|
@@ -191,6 +209,7 @@ const run_cut_report = {
|
|
|
191
209
|
RELAUNCHED_CUT_MARKER,
|
|
192
210
|
RESUME_IMPL_VERDICT,
|
|
193
211
|
RESUME_VERDICT,
|
|
212
|
+
SPLIT_UNRESOLVED_VERDICT,
|
|
194
213
|
STALE_VERDICT,
|
|
195
214
|
SUCCESS_EXIT_CODE,
|
|
196
215
|
UNDER_THRESHOLD_VERDICT,
|
|
@@ -205,9 +224,11 @@ const run_cut_report = {
|
|
|
205
224
|
report_handed_off,
|
|
206
225
|
report_held_cut,
|
|
207
226
|
report_incomplete,
|
|
227
|
+
report_missing_supervisor,
|
|
208
228
|
report_over,
|
|
209
229
|
report_relaunched_cut,
|
|
210
230
|
report_reviewer,
|
|
231
|
+
report_split_unresolved,
|
|
211
232
|
report_stale,
|
|
212
233
|
report_under_threshold,
|
|
213
234
|
report_unknown,
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { cost_cli } from '#scripts/cost-runtime/cost-cli'
|
|
2
|
+
import { cost_verdict } from '#scripts/cost-runtime/cost-verdict'
|
|
3
|
+
import { issue_cite } from '#scripts/issue/issue-cite'
|
|
4
|
+
import { run_event_stream } from '#scripts/run/event/run-event-stream'
|
|
5
|
+
import { run_event_stream_emit } from '#scripts/run/event/run-event-stream-emit'
|
|
6
|
+
import { run_cut, type RunCut } from './run-cut'
|
|
7
|
+
import { run_cut_report } from './run-cut-report'
|
|
8
|
+
import { run_cut_review } from './run-cut-review'
|
|
9
|
+
|
|
10
|
+
// `josh run:cut --resume <N>` — a fresh process asking whether it resumes a cut: it verifies the tree
|
|
11
|
+
// against the record and adopts it, answering which phase it resumes into. Taking a cut is
|
|
12
|
+
// `run-cut-cli.ts`'s.
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
FRESH_VERDICT,
|
|
16
|
+
HANDED_OFF_VERDICT,
|
|
17
|
+
INCOMPLETE_VERDICT,
|
|
18
|
+
RESUME_IMPL_VERDICT,
|
|
19
|
+
RESUME_VERDICT,
|
|
20
|
+
SUCCESS_EXIT_CODE,
|
|
21
|
+
report,
|
|
22
|
+
report_busy,
|
|
23
|
+
report_handed_off,
|
|
24
|
+
report_incomplete,
|
|
25
|
+
report_over,
|
|
26
|
+
report_stale,
|
|
27
|
+
report_unreadable,
|
|
28
|
+
} = run_cut_report
|
|
29
|
+
|
|
30
|
+
// **The adoption is the resume-uniqueness guarantee**: it removes and creates exclusively, so of two
|
|
31
|
+
// racing resumes only one wins the create and the loser is answered `busy`.
|
|
32
|
+
// An implementation cut resumes back into implementation; a pre-gate one into the gate. The resuming
|
|
33
|
+
// child is told which by the verdict rather than reconstructing it from the record.
|
|
34
|
+
function resume_verdict_for(cut_record: RunCut): string {
|
|
35
|
+
return run_cut.resumes_into_implementation(cut_record.phase)
|
|
36
|
+
? RESUME_IMPL_VERDICT
|
|
37
|
+
: RESUME_VERDICT
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// **An implementation resume removes the record; a pre-gate one marks it handed off**.
|
|
41
|
+
// The cuts have different multiplicities sharing one record: the pre-gate cut fires once per lane, so
|
|
42
|
+
// its record must survive to answer a second resume `handed-off`; the implementation cut is guarded by the run's
|
|
43
|
+
// event stream rather than the cut record, so its record is cleared on resume — a lingering record
|
|
44
|
+
// would keep the pre-gate guard, which reads `carried_cut_sync`, silent for the rest of the run. A double
|
|
45
|
+
// cut stays impossible either way: `begin_cut`'s exclusive create is what prevents it.
|
|
46
|
+
function take_over(target: string, cut_record: RunCut): RunCut | undefined {
|
|
47
|
+
if (!run_cut.resumes_into_implementation(cut_record.phase)) {
|
|
48
|
+
return run_cut.adopt_cut(target, cut_record)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
run_cut.end_cut(target)
|
|
52
|
+
|
|
53
|
+
return cut_record
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// **An implementation resume appends a `resume` event**. It clears the record
|
|
57
|
+
// the `cut` event stood for, so the stream is what moves `run:step` back to implementation; a pre-gate
|
|
58
|
+
// resume keeps its record and appends nothing. Best-effort, as the cut's own append is.
|
|
59
|
+
async function emit_resume_event(issue: string, verdict: string): Promise<void> {
|
|
60
|
+
if (verdict !== RESUME_IMPL_VERDICT) return
|
|
61
|
+
|
|
62
|
+
await run_event_stream_emit.emit(
|
|
63
|
+
run_event_stream.EVENT_KIND.RESUME,
|
|
64
|
+
`${issue_cite.plain(issue)} resumed`,
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function adopt(target: string, cut_record: RunCut): Promise<number> {
|
|
69
|
+
const taken = take_over(target, cut_record)
|
|
70
|
+
|
|
71
|
+
if (taken === undefined) return report_busy(cut_record)
|
|
72
|
+
|
|
73
|
+
const verdict = resume_verdict_for(cut_record)
|
|
74
|
+
|
|
75
|
+
await run_cut_review.announce_resume(cut_record, verdict === RESUME_IMPL_VERDICT)
|
|
76
|
+
await emit_resume_event(cut_record.issue, verdict)
|
|
77
|
+
|
|
78
|
+
return report(verdict, SUCCESS_EXIT_CODE)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// A relaunched lane child and a fresh session both measure `under`, so only the session that took an
|
|
82
|
+
// implementation cut resumes over the threshold; unmeasurable is not refused.
|
|
83
|
+
function is_over_threshold_resume(cut_record: RunCut): boolean {
|
|
84
|
+
if (!run_cut.resumes_into_implementation(cut_record.phase)) return false
|
|
85
|
+
|
|
86
|
+
return cost_cli.session_verdict() === cost_verdict.OVER_VERDICT
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async function verify_and_adopt(
|
|
90
|
+
target: string,
|
|
91
|
+
cut_record: RunCut,
|
|
92
|
+
issue: string,
|
|
93
|
+
): Promise<number> {
|
|
94
|
+
const state = await run_cut.current_state()
|
|
95
|
+
const verdict = run_cut.classify_resume(cut_record, {
|
|
96
|
+
issue,
|
|
97
|
+
current_branch: state.branch,
|
|
98
|
+
is_dirty: state.is_dirty,
|
|
99
|
+
is_held: state.is_held,
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
if (verdict === HANDED_OFF_VERDICT) return report_handed_off(cut_record)
|
|
103
|
+
|
|
104
|
+
if (verdict === 'stale') return report_stale(cut_record)
|
|
105
|
+
|
|
106
|
+
if (verdict === INCOMPLETE_VERDICT) return report_incomplete(cut_record)
|
|
107
|
+
|
|
108
|
+
if (is_over_threshold_resume(cut_record)) return report_over()
|
|
109
|
+
|
|
110
|
+
return await adopt(target, cut_record)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function resume(target: string, issue: string): Promise<number> {
|
|
114
|
+
const read = run_cut.read_cut(target)
|
|
115
|
+
|
|
116
|
+
if (read.kind === 'none') return report(FRESH_VERDICT, SUCCESS_EXIT_CODE)
|
|
117
|
+
|
|
118
|
+
if (read.kind === 'unreadable') return report_unreadable()
|
|
119
|
+
|
|
120
|
+
if (read.kind === 'expired') return report_stale(read.cut)
|
|
121
|
+
|
|
122
|
+
return await verify_and_adopt(target, read.cut, issue)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const run_cut_resume = {
|
|
126
|
+
resume,
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export { run_cut_resume }
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { git_command } from '#scripts/git/git-command'
|
|
2
|
+
import { review_attest } from '#scripts/review/review-attest'
|
|
3
|
+
import { review_prior_findings } from '#scripts/review/review-prior-findings'
|
|
4
|
+
import { review_record } from '#scripts/review/review-record'
|
|
5
|
+
import { run_cut, type RunCut } from './run-cut'
|
|
6
|
+
import { run_cut_digest } from './run-cut-digest'
|
|
7
|
+
import { run_cut_handoff, type Handoff } from './run-cut-handoff'
|
|
8
|
+
|
|
9
|
+
// The review round an implementation cut has to carry across the process boundary
|
|
10
|
+
// (joshuafolkken/kit#4868). A lane child's in-session reviewer returns its findings into the
|
|
11
|
+
// conversation, and `review:record` is run after the fixes — so a cut between the two dropped the
|
|
12
|
+
// findings with the conversation, and the resumed child reran round 1 in full. The cut is refused
|
|
13
|
+
// until the round is recorded or its findings ride in the handoff, and the resume prints a recorded
|
|
14
|
+
// round back so it is continued, not rerun.
|
|
15
|
+
|
|
16
|
+
function unrecorded_note(issue: string): string {
|
|
17
|
+
return (
|
|
18
|
+
'a review round is attested on this branch but not recorded, and the handoff carries no ' +
|
|
19
|
+
`"findings" — run \`pnpm josh review:record --issue ${issue} [<finding> ...]\` before the cut, ` +
|
|
20
|
+
'or list the round\'s findings under "findings" in the handoff, so the resumed run does not ' +
|
|
21
|
+
'rerun round 1'
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const RECORDED_ROUND_HEADING =
|
|
26
|
+
'Round 1 is recorded for this issue — do not rerun it; continue the fixes, then the ship, ' +
|
|
27
|
+
'which reviews only what moved since:'
|
|
28
|
+
|
|
29
|
+
interface CutScope {
|
|
30
|
+
issue: string
|
|
31
|
+
branch: string
|
|
32
|
+
phase: string
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Attested on this branch, with no `review:record` line for the issue — the round the cut would lose.
|
|
36
|
+
async function has_unrecorded_round(issue: string, branch: string): Promise<boolean> {
|
|
37
|
+
const root = await git_command.repository_root()
|
|
38
|
+
|
|
39
|
+
if (!review_attest.is_attested_on({ branch }, root)) return false
|
|
40
|
+
|
|
41
|
+
const recorded = await review_record.check(Number(issue))
|
|
42
|
+
|
|
43
|
+
return recorded.status === 'missing'
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Only an implementation cut without carried findings can lose a round: a pre-gate cut is taken
|
|
47
|
+
// before any review.
|
|
48
|
+
function may_drop_round(scope: CutScope, handoff: Handoff | undefined): boolean {
|
|
49
|
+
if (!run_cut.resumes_into_implementation(scope.phase)) return false
|
|
50
|
+
|
|
51
|
+
return run_cut_handoff.carried_findings(handoff).length === 0
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// The note an implementation cut is refused with when it would drop an unrecorded round, else
|
|
55
|
+
// `undefined`.
|
|
56
|
+
async function unrecorded_refusal(
|
|
57
|
+
scope: CutScope,
|
|
58
|
+
handoff: Handoff | undefined,
|
|
59
|
+
): Promise<string | undefined> {
|
|
60
|
+
if (!may_drop_round(scope, handoff)) return undefined
|
|
61
|
+
|
|
62
|
+
const is_unrecorded = await has_unrecorded_round(scope.issue, scope.branch)
|
|
63
|
+
|
|
64
|
+
return is_unrecorded ? unrecorded_note(scope.issue) : undefined
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// What an implementation resume prints about a round recorded before the cut: the heading and the
|
|
68
|
+
// findings the stop log kept with their reasons; nothing when no round is recorded.
|
|
69
|
+
async function recorded_round_lines(issue: string): Promise<ReadonlyArray<string>> {
|
|
70
|
+
const recorded = await review_record.check(Number(issue))
|
|
71
|
+
|
|
72
|
+
if (recorded.status !== 'ok') return []
|
|
73
|
+
|
|
74
|
+
const findings = review_prior_findings.latest(issue, () => true)
|
|
75
|
+
|
|
76
|
+
return [RECORDED_ROUND_HEADING, ...findings.map((finding) => ` - ${finding}`)]
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// The carried instruction and work state, printed to standard error so the resumed session continues
|
|
80
|
+
// on what the run was told to do rather than on the tree alone — and, for an implementation resume,
|
|
81
|
+
// the round recorded before the cut. The record is cleared on adoption, so this is where it reaches
|
|
82
|
+
// the fresh process.
|
|
83
|
+
async function announce_resume(cut_record: RunCut, is_implementation: boolean): Promise<void> {
|
|
84
|
+
if (cut_record.handoff !== undefined) {
|
|
85
|
+
console.error(run_cut_handoff.describe_handoff(cut_record.handoff))
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const digest = run_cut_digest.describe_digest(cut_record.digest)
|
|
89
|
+
|
|
90
|
+
if (digest !== undefined) console.error(digest)
|
|
91
|
+
|
|
92
|
+
if (!is_implementation) return
|
|
93
|
+
|
|
94
|
+
const lines = await recorded_round_lines(cut_record.issue)
|
|
95
|
+
|
|
96
|
+
if (lines.length > 0) console.error(lines.join('\n'))
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const run_cut_review = {
|
|
100
|
+
RECORDED_ROUND_HEADING,
|
|
101
|
+
announce_resume,
|
|
102
|
+
unrecorded_refusal,
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export { run_cut_review }
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { agent_role_profile } from '#scripts/agent/agent-role-profile'
|
|
2
2
|
import { backlog_budget } from '#scripts/backlog/backlog-budget'
|
|
3
|
-
import { CONTEXT_CUT_THRESHOLD } from '#scripts/cost-runtime/context-cut-threshold'
|
|
4
3
|
import { git_command } from '#scripts/git/git-command'
|
|
5
4
|
import { git_common_directory } from '#scripts/git/git-common-directory'
|
|
6
5
|
import { stamp_file } from '#scripts/josh/stamp-file'
|
|
@@ -9,6 +8,7 @@ import { lane_child_invocation } from '#scripts/lane/lane-child-invocation'
|
|
|
9
8
|
import { json_value } from '#scripts/lib/json-value'
|
|
10
9
|
import { run_hold, type RunHold } from '#scripts/run/hold/run-hold'
|
|
11
10
|
import { z } from 'zod'
|
|
11
|
+
import { run_cut_digest, type SessionDigest } from './run-cut-digest'
|
|
12
12
|
import { run_cut_handoff, type Handoff } from './run-cut-handoff'
|
|
13
13
|
|
|
14
14
|
// A lane child is a detached `fullrun #<N>` process, and the thinking it accumulates while
|
|
@@ -45,11 +45,6 @@ const CUT_PREFIX = 'josh-run-cut-'
|
|
|
45
45
|
// `IMPLEMENTATION_PHASE` drops the thinking accumulated *during* implementation and resumes back into
|
|
46
46
|
// implementation (`resumes_into_implementation`); only the pre-gate cut resumes into the gate.
|
|
47
47
|
const { PRE_GATE_PHASE, IMPLEMENTATION_PHASE } = agent_role_profile
|
|
48
|
-
// **The measurement is the parent hand-off's, never a second one.** The lane child decides whether
|
|
49
|
-
// to take this cut with `pnpm josh cost --cut` — the same per-request billed-input measurement (`cost_verdict.per_request_cost`) the parent's
|
|
50
|
-
// `pnpm josh cost --cut` hand-off uses (`backlogrun-progress.md` → "The hand-off"). The shared
|
|
51
|
-
// threshold prevents the scheduler and worker boundaries from drifting apart.
|
|
52
|
-
const IMPLEMENTATION_CONTEXT_THRESHOLD = CONTEXT_CUT_THRESHOLD
|
|
53
48
|
// **The bound is `backlog-budget.ts`'s idle wait, imported rather than restated**, so the eight hours
|
|
54
49
|
// stay written once. A resume is expected within seconds of the cut, so this age is only a backstop
|
|
55
50
|
// against a fresh process that never started; an expired record is cleared and replaced by the next
|
|
@@ -92,6 +87,8 @@ interface RunCut {
|
|
|
92
87
|
// record of the scalar fields alone parses, while a resume into implementation refuses to continue without it (`classify_resume`
|
|
93
88
|
// → `incomplete`), so a session is never silently continued lacking the instruction it needs.
|
|
94
89
|
handoff?: Handoff | undefined
|
|
90
|
+
// What the cut session read and decided, printed on the resume (joshuafolkken/kit#5040).
|
|
91
|
+
digest?: SessionDigest | undefined
|
|
95
92
|
// Set when `run:merge` found this cut still unadopted after every process of the lane had gone and
|
|
96
93
|
// relaunched its successor itself. The fallback fires once per cut: a
|
|
97
94
|
// successor that dies again before adopting is not relaunched a second time, so a lane that keeps
|
|
@@ -121,6 +118,8 @@ interface CutSpec {
|
|
|
121
118
|
// The instruction and work state to carry, absent for a pre-gate cut that resumes into the gate
|
|
122
119
|
// rather than into implementation.
|
|
123
120
|
handoff?: Handoff | undefined
|
|
121
|
+
// What the cut session read and decided, derived from its transcript (`run-cut-digest.ts`).
|
|
122
|
+
digest?: SessionDigest | undefined
|
|
124
123
|
}
|
|
125
124
|
|
|
126
125
|
// What the resume classifier is asked about, gathered from the fresh process's own git state so the
|
|
@@ -155,6 +154,7 @@ const run_cut_schema = z.object({
|
|
|
155
154
|
cut_at: z.string(),
|
|
156
155
|
is_handed_off: z.boolean().optional(),
|
|
157
156
|
handoff: run_cut_handoff.handoff_schema.optional(),
|
|
157
|
+
digest: run_cut_digest.session_digest_schema.optional(),
|
|
158
158
|
is_merge_relaunched: z.boolean().optional(),
|
|
159
159
|
})
|
|
160
160
|
|
|
@@ -261,6 +261,7 @@ function fresh_cut(spec: CutSpec, now: Date): RunCut {
|
|
|
261
261
|
cut_at: now.toISOString(),
|
|
262
262
|
is_handed_off: true,
|
|
263
263
|
handoff: spec.handoff,
|
|
264
|
+
digest: spec.digest,
|
|
264
265
|
}
|
|
265
266
|
}
|
|
266
267
|
|
|
@@ -285,6 +286,16 @@ function record_within_bound(spec: CutSpec, now: Date = new Date()): boolean {
|
|
|
285
286
|
return within_handoff_bound(fresh_cut(spec, now))
|
|
286
287
|
}
|
|
287
288
|
|
|
289
|
+
// An implementation cut carries what the session read and decided (`run-cut-digest.ts`); a digest the
|
|
290
|
+
// bound cannot hold is dropped, so a cut is never refused for it, and a pre-gate cut never derives one.
|
|
291
|
+
function with_digest(spec: CutSpec, digest_of: () => SessionDigest | undefined): CutSpec {
|
|
292
|
+
if (spec.handoff === undefined) return spec
|
|
293
|
+
|
|
294
|
+
const digested = { ...spec, digest: digest_of() }
|
|
295
|
+
|
|
296
|
+
return record_within_bound(digested) ? digested : spec
|
|
297
|
+
}
|
|
298
|
+
|
|
288
299
|
// **Create-exclusively, exactly as `run-hold.ts` claims a tree.** A record already here means a cut is
|
|
289
300
|
// already in flight for this tree, so `undefined` is "do not launch a second one" rather than an
|
|
290
301
|
// error — the exclusive create is what makes a double cut, and so a double relaunch, impossible. A
|
|
@@ -455,7 +466,6 @@ const run_cut = {
|
|
|
455
466
|
CUT_MAX_AGE_HOURS,
|
|
456
467
|
CUT_MAX_AGE_MS,
|
|
457
468
|
END_COMMAND,
|
|
458
|
-
IMPLEMENTATION_CONTEXT_THRESHOLD,
|
|
459
469
|
IMPLEMENTATION_PHASE,
|
|
460
470
|
MAX_HANDOFF_BYTES,
|
|
461
471
|
PRE_GATE_PHASE,
|
|
@@ -466,6 +476,7 @@ const run_cut = {
|
|
|
466
476
|
classify,
|
|
467
477
|
classify_resume,
|
|
468
478
|
current_state,
|
|
479
|
+
with_digest,
|
|
469
480
|
cut_path,
|
|
470
481
|
describe_cut,
|
|
471
482
|
end_cut,
|
|
@@ -21,7 +21,7 @@ import { launch_priority } from '#scripts/run/launch-priority'
|
|
|
21
21
|
|
|
22
22
|
const NO_PID_NOTE = 'the process started without a pid'
|
|
23
23
|
const UNSAFE_NOTE =
|
|
24
|
-
'the wake command or its arguments contain characters that are not safe to execute'
|
|
24
|
+
'the wake command or its arguments are empty, over length, or contain characters that are not safe to execute'
|
|
25
25
|
|
|
26
26
|
// Provider-specific commands and flags are composed before this boundary. This module accepts only
|
|
27
27
|
// an argv vector and never infers policy from it; role/model/effort arrive separately as log metadata.
|