@joshuafolkken/kit 1.1178.0 → 1.1229.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/.claude-plugin/plugin.json +1 -1
- package/.claude/settings.json +2 -2
- package/.claude/skills/dependency-update/SKILL.md +4 -8
- package/.claude/skills/epic-commands/SKILL.md +2 -2
- package/.claude/skills/epic-commands/epic-bundle.md +1 -1
- package/.claude/skills/workflow-commands/SKILL.md +2 -4
- package/.claude/skills/workflow-commands/backlogrun-child.md +6 -4
- package/.claude/skills/workflow-commands/backlogrun-lanes.md +6 -2
- package/.claude/skills/workflow-commands/backlogrun-park.md +23 -2
- package/.claude/skills/workflow-commands/backlogrun-progress.md +7 -2
- package/.claude/skills/workflow-commands/backlogrun-recovery.md +4 -3
- package/.claude/skills/workflow-commands/backlogrun-steps.md +21 -13
- package/.claude/skills/workflow-commands/chain-rule.md +1 -1
- package/.claude/skills/workflow-commands/delegation.md +2 -2
- package/.claude/skills/workflow-commands/followup.md +5 -0
- package/.claude/skills/workflow-commands/fullrun-steps.md +1 -1
- package/.claude/skills/workflow-commands/halfrun.md +1 -1
- package/.claude/skills/workflow-commands/issue-scout.md +1 -1
- package/.claude/skills/workflow-commands/kickoff.md +1 -1
- package/.claude/skills/workflow-commands/observation-ledger.md +3 -3
- package/.claude/skills/workflow-commands/pre-gate-cut.md +6 -1
- package/.claude/skills/workflow-commands/prerequisite.md +2 -2
- package/.claude/skills/workflow-commands/progress-watcher.md +1 -1
- package/.claude/skills/workflow-commands/working-tree-hold.md +1 -1
- package/.codex/hooks.json +2 -2
- package/.cursorrules +6 -41
- package/.github/actions/setup-node/action.yml +1 -1
- package/.github/workflows/auto-tag.yml +3 -4
- package/.github/workflows/ci.yml +32 -31
- package/.github/workflows/dependabot-auto-merge.yml +13 -6
- package/.github/workflows/publish.yml +48 -4
- package/.github/workflows/sonar-qube.yml +3 -0
- package/.pnpmfile.mjs +4 -3
- package/.prettierignore +8 -2
- package/CLAUDE.md +18 -20
- package/README.md +26 -19
- package/SECURITY.md +15 -1
- package/dist/CLAUDE.md +18 -20
- package/dist/commands/document-section-cli.js +734 -0
- package/dist/hooks/audit-provision.js +346 -0
- package/dist/hooks/batch-guard.js +5 -4
- package/dist/hooks/{chunk-S6X6WYKR.js → chunk-55HHG5PX.js} +1210 -711
- package/dist/hooks/{chunk-ZAL3NRGL.js → chunk-5VMKCCC4.js} +25 -10
- package/dist/hooks/chunk-5VNDSNG3.js +12 -0
- package/dist/hooks/{chunk-32GQTL4F.js → chunk-6HJJXRBX.js} +4 -2
- package/dist/hooks/chunk-CDY4NFQG.js +15 -0
- package/dist/hooks/chunk-ELCN5LCH.js +135 -0
- package/dist/hooks/{chunk-VESKRQOF.js → chunk-F56MFS4B.js} +3 -3
- package/dist/hooks/{chunk-UAGLLIGZ.js → chunk-FIVDHQGT.js} +7 -6
- package/dist/hooks/{chunk-3V37IID6.js → chunk-JBBMAPC4.js} +23 -14
- package/dist/hooks/{chunk-G6KRCKEC.js → chunk-JUDKDCDP.js} +496 -378
- package/dist/hooks/{chunk-GDS5N2KB.js → chunk-NV2JRZZO.js} +718 -681
- package/dist/hooks/{chunk-VQLLNFNT.js → chunk-RNWHN5BP.js} +3 -3
- package/dist/hooks/{chunk-DO6NWWHU.js → chunk-TQNPDZNH.js} +4 -4
- package/dist/hooks/{chunk-I4XSL4TT.js → chunk-VC3PZPZO.js} +1 -1
- package/dist/hooks/codex-hook-adapter.js +14 -12
- package/dist/hooks/duplicate-read-guard.js +6 -5
- package/dist/hooks/format-edited.js +4 -3
- package/dist/hooks/inputs.json +217 -195
- package/dist/hooks/investigation-guard.js +6 -5
- package/dist/hooks/pretool-guard.js +12 -10
- package/dist/hooks/session-lang.js +2 -4
- package/dist/hooks/stop-guard.js +66 -58
- package/dist/josh.js +868 -74
- package/dist/version/index.d.ts +7 -2
- package/dist/version/index.js +152 -75
- package/eslint/base.js +23 -1
- package/eslint/rules/code-quality.js +3 -0
- package/eslint/rules/early-return-one-liner.js +98 -0
- package/eslint/rules/unicorn.js +16 -1
- package/package.json +7 -6
- package/pnpm-workspace.yaml +9 -4
- package/prettier/basic.d.ts +3 -1
- package/prettier/index.d.ts +3 -1
- package/prettier/static.d.ts +3 -1
- package/prompts/coding-standards.md +1 -1
- package/prompts/collaboration-workflow/file-edits.md +4 -4
- package/prompts/collaboration-workflow/glossary.md +1 -1
- package/prompts/collaboration-workflow/operating-rules.md +17 -9
- package/prompts/collaboration-workflow/overview.md +2 -2
- package/prompts/collaboration-workflow/principles.md +14 -12
- package/prompts/collaboration-workflow/report-format.md +1 -1
- package/prompts/collaboration-workflow/residency.md +1 -1
- package/prompts/collaboration-workflow/rule-delivery.md +6 -6
- package/prompts/collaboration-workflow/shell-body.md +6 -6
- package/prompts/collaboration-workflow/turn-batching.md +1 -1
- package/prompts/collaboration-workflow/upstream-interrupt.md +12 -2
- package/prompts/collaboration-workflow/wip-cap.md +10 -10
- package/prompts/review-rubric.md +1 -2
- package/prompts/review.md +1 -1
- package/scripts/agent/agent-headless.ts +29 -0
- package/scripts/agent/agent-launch-environment.ts +6 -2
- package/scripts/agent/codex-agent-argv.ts +2 -1
- package/scripts/auto-ok/auto-ok-cli.ts +1 -1
- package/scripts/backlog/backlog-arrival.ts +3 -3
- package/scripts/backlog/backlog-budget.ts +1 -1
- package/scripts/backlog/backlog-drive-args.ts +135 -0
- package/scripts/backlog/backlog-drive-cli.ts +11 -137
- package/scripts/backlog/backlog-drive-launch.ts +39 -0
- package/scripts/backlog/backlog-drive-named-offer.ts +3 -5
- package/scripts/backlog/backlog-drive-named.ts +3 -3
- package/scripts/backlog/backlog-drive-offer-argv.ts +1 -1
- package/scripts/backlog/backlog-drive-owner.ts +1 -1
- package/scripts/backlog/backlog-drive-restore.ts +1 -1
- package/scripts/backlog/backlog-drive-retrospective.ts +1 -1
- package/scripts/backlog/backlog-drive.ts +1 -1
- package/scripts/backlog/backlog-next.ts +16 -5
- package/scripts/backlog/backlog-offer-cli.ts +6 -6
- package/scripts/backlog/backlog-offer.ts +1 -1
- package/scripts/backlog/backlog-plan-cli.ts +1 -1
- package/scripts/backlog/backlog-pool.ts +57 -11
- package/scripts/backlog/backlog-ready.ts +1 -1
- package/scripts/backlog/backlog-scope.ts +1 -1
- package/scripts/backlog/backlog-stalled-detect.ts +2 -2
- package/scripts/backlog/backlog-stalled.ts +1 -1
- package/scripts/build/build-codex-hooks.ts +3 -1
- package/scripts/build/build-commands.ts +66 -0
- package/scripts/build/build-hooks.ts +2 -1
- package/scripts/build/build-library.ts +12 -3
- package/scripts/build/build.ts +70 -0
- package/scripts/build/local-bin.ts +3 -13
- package/scripts/delegation/investigation-reads.ts +3 -1
- package/scripts/discovery/repo-origin.ts +5 -5
- package/scripts/doctor/doctor-consumer.ts +2 -2
- package/scripts/doctor/doctor-io.ts +2 -3
- package/scripts/document/capped-print-part.ts +30 -0
- package/scripts/document/capped-print.ts +3 -4
- package/scripts/document/document-byte-budget.ts +11 -2
- package/scripts/document/document-scan.ts +117 -0
- package/scripts/document/document-section.ts +143 -16
- package/scripts/document/entry-read-budget.ts +5 -3
- package/scripts/document/entry-read-set.ts +10 -89
- package/scripts/document/read-set-cost.ts +98 -0
- package/scripts/epic/epic-add-body.ts +1 -0
- package/scripts/epic/epic-audit-checks.ts +1 -1
- package/scripts/epic/epic-audit-rationale.ts +4 -3
- package/scripts/epic/epic-bundle-cli.ts +14 -3
- package/scripts/epic/epic-bundle-poll.ts +41 -0
- package/scripts/epic/epic-busy.ts +1 -1
- package/scripts/epic/epic-candidate-confirm.ts +3 -2
- package/scripts/epic/epic-classify.ts +1 -1
- package/scripts/epic/epic-cli-argv.ts +78 -46
- package/scripts/epic/epic-cli-remove.ts +11 -19
- package/scripts/epic/epic-cli.ts +74 -73
- package/scripts/epic/epic-close-comment.ts +1 -1
- package/scripts/epic/epic-close.ts +1 -1
- package/scripts/epic/epic-cross-repo.ts +5 -5
- package/scripts/epic/epic-graph.ts +1 -1
- package/scripts/epic/epic-index.ts +1 -1
- package/scripts/epic/epic-issue.ts +2 -6
- package/scripts/epic/epic-lane-offer.ts +2 -2
- package/scripts/epic/epic-next.ts +29 -42
- package/scripts/epic/epic-solo-stale.ts +1 -1
- package/scripts/epic/epic-triage.ts +8 -4
- package/scripts/epic/epic-validate.ts +1 -1
- package/scripts/followup/git-followup-finish.ts +2 -2
- package/scripts/followup/git-followup-label.ts +2 -2
- package/scripts/followup/git-followup-merged.ts +2 -2
- package/scripts/followup/git-pr-followup-checks.ts +142 -0
- package/scripts/followup/git-pr-followup.ts +4 -129
- package/scripts/gate/core-budget.ts +69 -1
- package/scripts/gate/gate-plan.ts +47 -7
- package/scripts/gate/gate-skip.ts +38 -7
- package/scripts/gate/hook-gate-reuse.ts +12 -10
- package/scripts/gate/pre-commit-type-check.ts +4 -1
- package/scripts/gate/project-checks.ts +6 -9
- package/scripts/gate/type-check-step.ts +2 -3
- package/scripts/gate/verification-gate.ts +27 -8
- package/scripts/gh/git-gh-api-path.ts +2 -2
- package/scripts/gh/git-gh-issue-rest.ts +3 -3
- package/scripts/gh/git-gh-issue-write.ts +53 -7
- package/scripts/gh/git-gh-pr-read.ts +64 -19
- package/scripts/gh/git-gh-pr-rest.ts +1 -1
- package/scripts/gh/git-gh-pr.ts +5 -1
- package/scripts/gh/git-pr-ai-review.ts +1 -1
- package/scripts/gh/git-pr-checks-eval.ts +1 -3
- package/scripts/gh/git-pr-checks-parse.ts +1 -1
- package/scripts/gh/git-pr-checks-watch.ts +6 -5
- package/scripts/gh/git-pr-checks.ts +7 -5
- package/scripts/gh/git-pr-coderabbit.ts +1 -1
- package/scripts/gh/git-pr-error.ts +1 -3
- package/scripts/gh/git-pr.ts +9 -13
- package/scripts/gh/github-issue-url.ts +2 -2
- package/scripts/git/constants.ts +2 -6
- package/scripts/git/git-command.ts +20 -218
- package/scripts/git/git-diff-reads.ts +225 -0
- package/scripts/git/git-error.ts +4 -12
- package/scripts/git/git-pre-push-hook.ts +139 -0
- package/scripts/git/git-prompt.ts +2 -6
- package/scripts/git/git-spawn-sync.ts +3 -1
- package/scripts/git/git-spawn.ts +1 -1
- package/scripts/git/git-staging.ts +4 -6
- package/scripts/git/git-status.ts +3 -9
- package/scripts/hooks/codex-hook-adapter.ts +1 -1
- package/scripts/hooks/edited-cspell.ts +2 -4
- package/scripts/hooks/format-edited-file.ts +3 -12
- package/scripts/hooks/pre-push-unit.ts +31 -9
- package/scripts/hooks/reserved-run.ts +2 -2
- package/scripts/hooks/run-hook.sh +5 -4
- package/scripts/hooks/stop-guard.ts +5 -3
- package/scripts/init/init-actions.ts +0 -5
- package/scripts/init/init-ai-copy.ts +13 -2
- package/scripts/init/init-logic-json-merge.ts +19 -0
- package/scripts/init/init-logic-secretlint.ts +7 -7
- package/scripts/init/init-logic-workspace.ts +41 -2
- package/scripts/init/init-logic.ts +16 -26
- package/scripts/init/init.ts +5 -15
- package/scripts/init/initial-commit.ts +4 -4
- package/scripts/init/kit-development-versions.ts +40 -0
- package/scripts/init/kit-setup-state.ts +2 -2
- package/scripts/init/start-exec.ts +68 -19
- package/scripts/init/start-setup-pr.ts +9 -9
- package/scripts/init/start-steps.ts +6 -10
- package/scripts/issue/defect-rate-cli.ts +1 -1
- package/scripts/issue/git-next-issues.ts +1 -1
- package/scripts/issue/issue-auto-ok.ts +1 -1
- package/scripts/issue/issue-backlinks-cli.ts +2 -2
- package/scripts/issue/issue-backlinks.ts +9 -9
- package/scripts/issue/issue-comment-cli.ts +19 -13
- package/scripts/issue/issue-file-cli.ts +45 -18
- package/scripts/issue/issue-file.ts +24 -1
- package/scripts/issue/issue-scout-closed.ts +1 -1
- package/scripts/issue/issue-state-cli.ts +30 -74
- package/scripts/josh/josh-command-map.ts +2 -0
- package/scripts/josh/josh-command-types.ts +11 -0
- package/scripts/josh/josh-commands-ai.ts +4 -4
- package/scripts/josh/josh-commands-backlog.ts +4 -1
- package/scripts/josh/josh-commands-development.ts +10 -0
- package/scripts/josh/josh-commands-document.ts +1 -0
- package/scripts/josh/josh-commands-lane.ts +22 -0
- package/scripts/josh/josh-commands-maintenance.ts +4 -4
- package/scripts/josh/josh-commands-run.ts +12 -7
- package/scripts/josh/josh-in-process.ts +28 -9
- package/scripts/josh/josh-logic.ts +33 -15
- package/scripts/josh/process-identity.ts +1 -3
- package/scripts/josh/session-language-cli.ts +3 -4
- package/scripts/lane/lane-await.ts +5 -1
- package/scripts/lane/lane-child-invocation.ts +2 -2
- package/scripts/lane/lane-cli.ts +3 -3
- package/scripts/lane/lane-dispatch.ts +14 -10
- package/scripts/lane/lane-environment.ts +5 -1
- package/scripts/lane/lane-handoff.ts +1 -1
- package/scripts/lane/lane-install.ts +2 -13
- package/scripts/lane/lane-launch-cli.ts +15 -1
- package/scripts/lane/lane-ledger.ts +145 -0
- package/scripts/lane/lane-leftover.ts +1 -1
- package/scripts/lane/lane-load.ts +108 -0
- package/scripts/lane/lane-measure-cli.ts +149 -0
- package/scripts/lane/lane-occupancy.ts +3 -0
- package/scripts/lane/lane-reap.ts +1 -3
- package/scripts/lane/lane-relaunch.ts +1 -1
- package/scripts/lane/lane-stats.ts +224 -0
- package/scripts/lane/lane-vacant.ts +36 -0
- package/scripts/lane/openai-lane-ship.ts +2 -2
- package/scripts/lane/openai-lane-supervisor-owner.ts +180 -0
- package/scripts/lane/openai-lane-supervisor.ts +7 -165
- package/scripts/lane/openai-review-broker.ts +2 -4
- package/scripts/lib/ancestor-directories.ts +35 -0
- package/scripts/lib/animation-helpers.ts +2 -2
- package/scripts/lib/buffered-process.ts +3 -7
- package/scripts/lib/cli-flags.ts +71 -1
- package/scripts/lib/spawn-exit.ts +2 -2
- package/scripts/lib/timeouts.ts +35 -2
- package/scripts/lines/line-budget.ts +4 -6
- package/scripts/notify/telegram-test.ts +6 -0
- package/scripts/observations/observation-ledger-line.ts +6 -6
- package/scripts/observations/observation-ledger-migrate.ts +55 -4
- package/scripts/observations/observation-ledger.ts +26 -7
- package/scripts/overrides/lockfile-overrides.ts +1 -1
- package/scripts/overrides/overrides-logic.ts +1 -1
- package/scripts/propagate/propagate-git.ts +1 -1
- package/scripts/propagate/propagate-publish.ts +2 -2
- package/scripts/propagate/propagate-steps.ts +20 -15
- package/scripts/propagate/propagate.ts +36 -27
- package/scripts/refactor/import-graph.ts +18 -1
- package/scripts/refactor/refactor-lint.ts +4 -4
- package/scripts/repo/repository-labels.ts +2 -2
- package/scripts/repo/required-checks-logic.ts +1 -3
- package/scripts/review/live-evidence.ts +2 -4
- package/scripts/review/review-brief-cli.ts +1 -1
- package/scripts/review/review-finding-ledger.ts +1 -1
- package/scripts/review/review-findings-cli.ts +1 -3
- package/scripts/rules/decision-oracle-batch.ts +128 -0
- package/scripts/rules/decision-oracle-tokens.ts +21 -0
- package/scripts/rules/decision-oracle.ts +8 -120
- package/scripts/rules/delivered-rules.ts +26 -182
- package/scripts/rules/direct-filing.ts +1 -1
- package/scripts/rules/early-heartbeat.ts +3 -3
- package/scripts/rules/git-argv.ts +1 -1
- package/scripts/rules/git-force.ts +1 -1
- package/scripts/rules/implementation-cut.ts +2 -2
- package/scripts/rules/index-guard.ts +1 -1
- package/scripts/rules/issue-comments.ts +118 -0
- package/scripts/rules/{issue-fold.ts → issue-fold-rule.ts} +2 -2
- package/scripts/rules/lane-background.ts +2 -2
- package/scripts/rules/lane-park.ts +18 -0
- package/scripts/rules/lane-split-park.ts +128 -0
- package/scripts/rules/oracle-firing.ts +1 -1
- package/scripts/rules/poll-loop.ts +1 -1
- package/scripts/rules/pre-gate-cut.ts +1 -1
- package/scripts/rules/protected-files.ts +59 -4
- package/scripts/rules/{run-tail.ts → run-tail-rule.ts} +2 -2
- package/scripts/rules/shell-body-trigger.ts +1 -1
- package/scripts/rules/stop-rules.ts +18 -7
- package/scripts/rules/test-declared-commit.ts +4 -4
- package/scripts/rules/wip-cap.ts +63 -0
- package/scripts/run/{run-carry-args.ts → carry/run-carry-args.ts} +37 -13
- package/scripts/run/{run-carry-change.ts → carry/run-carry-change.ts} +29 -7
- package/scripts/run/{run-carry-cli.ts → carry/run-carry-cli.ts} +4 -6
- package/scripts/run/{run-carry.ts → carry/run-carry.ts} +1 -1
- package/scripts/run/{run-cut-args.ts → cut/run-cut-args.ts} +1 -1
- package/scripts/run/{run-cut-cli.ts → cut/run-cut-cli.ts} +2 -2
- package/scripts/run/{run-cut.ts → cut/run-cut.ts} +1 -1
- package/scripts/run/{run-entry-cli.ts → entry/run-entry-cli.ts} +11 -11
- package/scripts/run/{run-entry.ts → entry/run-entry.ts} +2 -2
- package/scripts/run/{run-event-scope.ts → event/run-event-scope.ts} +1 -1
- package/scripts/run/{run-event-stream-emit.ts → event/run-event-stream-emit.ts} +1 -1
- package/scripts/run/{run-event-stream.ts → event/run-event-stream.ts} +16 -2
- package/scripts/run/{run-hold-cli.ts → hold/run-hold-cli.ts} +5 -5
- package/scripts/run/{run-merge-cli.ts → merge/run-merge-cli.ts} +10 -5
- package/scripts/run/{run-merge-steps.ts → merge/run-merge-steps.ts} +53 -5
- package/scripts/run/{run-merge.ts → merge/run-merge.ts} +1 -1
- package/scripts/run/{run-progress-cli.ts → progress/run-progress-cli.ts} +1 -1
- package/scripts/run/{run-progress-config.ts → progress/run-progress-config.ts} +2 -17
- package/scripts/run/{run-progress-read.ts → progress/run-progress-read.ts} +5 -5
- package/scripts/run/{run-progress.ts → progress/run-progress.ts} +1 -1
- package/scripts/run/{run-review-steps.ts → review/run-review-steps.ts} +2 -3
- package/scripts/run/run-ending.ts +2 -2
- package/scripts/run/run-halfrun-resume.ts +6 -1
- package/scripts/run/run-headless.ts +1 -1
- package/scripts/run/run-invocation.ts +85 -84
- package/scripts/run/run-liveness.ts +1 -1
- package/scripts/run/run-parent-cut-hook.ts +1 -1
- package/scripts/run/run-preflight.ts +6 -6
- package/scripts/run/run-prep-cli.ts +1 -1
- package/scripts/run/run-prrun-resume.ts +1 -1
- package/scripts/run/run-report-cli.ts +4 -4
- package/scripts/run/run-report.ts +2 -2
- package/scripts/run/run-status-cli.ts +1 -1
- package/scripts/run/run-step-cli.ts +3 -3
- package/scripts/run/run-step.ts +2 -2
- package/scripts/run/run-stop-notify.ts +1 -1
- package/scripts/run/run-stranded-detect.ts +4 -4
- package/scripts/run/run-stranded.ts +2 -2
- package/scripts/run/run-watcher-guard-cli.ts +1 -1
- package/scripts/run/run-watcher-guard.ts +5 -3
- package/scripts/run/run-watcher-hook.ts +1 -1
- package/scripts/run/{run-ship-cli.ts → ship/run-ship-cli.ts} +2 -2
- package/scripts/run/{run-ship-detach.ts → ship/run-ship-detach.ts} +3 -3
- package/scripts/run/ship/run-ship-lock.ts +50 -0
- package/scripts/run/{run-ship-preflight.ts → ship/run-ship-preflight.ts} +6 -2
- package/scripts/run/{run-ship-probe.ts → ship/run-ship-probe.ts} +2 -2
- package/scripts/run/{run-ship-return.ts → ship/run-ship-return.ts} +4 -3
- package/scripts/run/{run-ship-review-steps.ts → ship/run-ship-review-steps.ts} +3 -3
- package/scripts/run/{run-ship-scoped.ts → ship/run-ship-scoped.ts} +10 -1
- package/scripts/run/{run-ship-steps.ts → ship/run-ship-steps.ts} +11 -12
- package/scripts/run/ship/run-ship-stop-text.ts +13 -0
- package/scripts/run/{run-ship-sync.ts → ship/run-ship-sync.ts} +25 -11
- package/scripts/run/{run-tidy-lanes.ts → tidy/run-tidy-lanes.ts} +1 -1
- package/scripts/run/{run-wake-cli.ts → wake/run-wake-cli.ts} +23 -8
- package/scripts/run/{run-wake-describe.ts → wake/run-wake-describe.ts} +3 -3
- package/scripts/run/{run-wake-driver.ts → wake/run-wake-driver.ts} +59 -8
- package/scripts/run/{run-wake-handoff.ts → wake/run-wake-handoff.ts} +1 -1
- package/scripts/run/{run-wake-loop.ts → wake/run-wake-loop.ts} +8 -2
- package/scripts/run/wake/run-wake-restart.ts +58 -0
- package/scripts/run/{run-wake-session.ts → wake/run-wake-session.ts} +3 -3
- package/scripts/run/{run-wake.ts → wake/run-wake.ts} +1 -1
- package/scripts/safe-chain/preinstall-command.ts +20 -21
- package/scripts/safe-chain/project-config.ts +19 -15
- package/scripts/sync/sync-ai-files.ts +1 -1
- package/scripts/sync/sync-configs.ts +2 -1
- package/scripts/sync/sync.ts +15 -2
- package/scripts/test/unit-worker-share.ts +1 -0
- package/scripts/time-runtime/time-background.ts +5 -1
- package/scripts/time-runtime/time-instant.ts +3 -1
- package/scripts/time-runtime/time-spans.ts +6 -139
- package/scripts/time-runtime/time-tool-call.ts +160 -0
- package/scripts/version/effective-upstream.ts +2 -20
- package/scripts/version/latest-corepack.ts +17 -17
- package/scripts/version/latest-regression.ts +1 -1
- package/scripts/version/latest-update.ts +4 -4
- package/scripts/version/npm-registry.ts +20 -5
- package/scripts/version/publishable-range-check.ts +2 -2
- package/scripts/version/publishable-range.ts +1 -1
- package/scripts/version/release-age.ts +48 -38
- package/scripts/version/release-hold.ts +1 -1
- package/scripts/version/safe-chain-version-update.ts +40 -0
- package/scripts/version/upgrade-shell-command.ts +48 -8
- package/scripts/version/version-check-logic.ts +23 -14
- package/scripts/version/version-commands.ts +23 -11
- package/scripts/version/version-remote.ts +28 -13
- package/templates/pnpm-workspace.basic.yaml +4 -0
- package/templates/workflows/dependabot-auto-merge.yml +5 -5
- package/templates/workflows/github-release.yml +2 -0
- package/scripts/build/build-config-merge.ts +0 -27
- package/scripts/build/build-managed-marker.ts +0 -27
- package/scripts/build/build-self-sync-guard.ts +0 -27
- package/scripts/build/build-version.ts +0 -26
- package/scripts/version/preinstall-version-update.ts +0 -86
- /package/scripts/git/{schemas.ts → git-schemas.ts} +0 -0
- /package/scripts/overrides/{schemas.ts → overrides-schemas.ts} +0 -0
- /package/scripts/run/{run-carry-conversation.ts → carry/run-carry-conversation.ts} +0 -0
- /package/scripts/run/{run-carry-reclaim.ts → carry/run-carry-reclaim.ts} +0 -0
- /package/scripts/run/{run-carry-stash.ts → carry/run-carry-stash.ts} +0 -0
- /package/scripts/run/{run-carry-streak.ts → carry/run-carry-streak.ts} +0 -0
- /package/scripts/run/{run-cut-handoff.ts → cut/run-cut-handoff.ts} +0 -0
- /package/scripts/run/{run-cut-report.ts → cut/run-cut-report.ts} +0 -0
- /package/scripts/run/{run-entry-stop.ts → entry/run-entry-stop.ts} +0 -0
- /package/scripts/run/{run-event-cli.ts → event/run-event-cli.ts} +0 -0
- /package/scripts/run/{run-event-follow.ts → event/run-event-follow.ts} +0 -0
- /package/scripts/run/{run-event-render.ts → event/run-event-render.ts} +0 -0
- /package/scripts/run/{run-event-watch.ts → event/run-event-watch.ts} +0 -0
- /package/scripts/run/{run-hold.ts → hold/run-hold.ts} +0 -0
- /package/scripts/run/{run-progress-args.ts → progress/run-progress-args.ts} +0 -0
- /package/scripts/run/{run-progress-clock.ts → progress/run-progress-clock.ts} +0 -0
- /package/scripts/run/{run-review-cli.ts → review/run-review-cli.ts} +0 -0
- /package/scripts/run/{run-review.ts → review/run-review.ts} +0 -0
- /package/scripts/run/{run-ship-next.ts → ship/run-ship-next.ts} +0 -0
- /package/scripts/run/{run-ship-pre-detach.ts → ship/run-ship-pre-detach.ts} +0 -0
- /package/scripts/run/{run-ship-review.ts → ship/run-ship-review.ts} +0 -0
- /package/scripts/run/{run-ship-stage.ts → ship/run-ship-stage.ts} +0 -0
- /package/scripts/run/{run-ship.ts → ship/run-ship.ts} +0 -0
- /package/scripts/run/{run-tidy-cli.ts → tidy/run-tidy-cli.ts} +0 -0
- /package/scripts/run/{run-tidy-stashes.ts → tidy/run-tidy-stashes.ts} +0 -0
- /package/scripts/run/{run-tidy.ts → tidy/run-tidy.ts} +0 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { bash_triggers } from './bash-triggers'
|
|
2
|
+
import { shell_segments } from './shell-segments'
|
|
3
|
+
|
|
4
|
+
// The trigger and the delivered text behind the `wip-cap` row of `delivered-rules.ts`, moved out of
|
|
5
|
+
// the enumeration so the list stays a list (joshuafolkken/kit#3264).
|
|
6
|
+
|
|
7
|
+
// The whole of the WIP cap, in the shape a refusal can carry: the count, the refusal, the two
|
|
8
|
+
// exemptions and the three tests that decide the second one. The three tests are spelled out rather
|
|
9
|
+
// than named, because a delivery that said only "an interrupt is exempt" would hand the deciding back
|
|
10
|
+
// to judgement at exactly the moment nothing else is open to read (joshuafolkken/kit#1518).
|
|
11
|
+
// `WIP_CAP` is the number's single source; `wip-cap.md` states it once and a test pins the two equal.
|
|
12
|
+
const WIP_CAP = 30
|
|
13
|
+
const WIP_CAP_REASON =
|
|
14
|
+
`⛔ backlog WIP cap: \`pnpm josh issue:file\` counts the target repository's open Issues before filing. With more than ${String(WIP_CAP)} ` +
|
|
15
|
+
'open, close one first; nothing honestly closable means do not file — the command holds such a filing. ' +
|
|
16
|
+
'Two filings are exempt and proceed while stating the overage — one the run is blocked by (`--over-cap`, ' +
|
|
17
|
+
'or the `tier-a` / `split` route), and an interrupt (`--route interrupt`), decided by three tests rather ' +
|
|
18
|
+
'than judgement: a verification answers wrongly, a documented workflow cannot complete, or data is lost ' +
|
|
19
|
+
'or written outside the repository. Meeting none of the three, the finding is discretionary and waits. ' +
|
|
20
|
+
'Both procedures are in `prompts/collaboration-workflow/wip-cap.md`. Reissue this call and let the ' +
|
|
21
|
+
'command count — it fires once per run and cannot repeat on the call in hand.'
|
|
22
|
+
|
|
23
|
+
// **Keeping the WIP cap is counting the open Issues**, which is the one act the rule asks for before
|
|
24
|
+
// a filing.
|
|
25
|
+
//
|
|
26
|
+
// **It has to be Issues, open, and a listing — all three, in one segment.** A pattern that took any
|
|
27
|
+
// of them alone scored `gh pr list --state open` and `epic:bundle`'s candidate search as the count,
|
|
28
|
+
// and those inflate exactly the ratio the retirement decision reads. `gh issue list` alone is not
|
|
29
|
+
// enough either: the cap is about *open* Issues, and a listing that does not say so is some other
|
|
30
|
+
// question. Segment-wise like the comments predicate, so a spelling quoted inside a filing's body
|
|
31
|
+
// is not read as the count that filing skipped.
|
|
32
|
+
const ISSUE_LISTING = /^gh\s+(?:-{1,2}[\w-]+(?:[= ]\S+)?\s+)*issue\s+list\b/u
|
|
33
|
+
const ISSUES_QUERY = /repos\/[^\s'"]*\/issues\?[^\s'"]*state=open/u
|
|
34
|
+
const OPEN_STATE = /--state[= ]open|state=open/u
|
|
35
|
+
// **A label filter makes it a different question.** `gh issue list --label epic --state open` and
|
|
36
|
+
// `…/issues?labels=epic&state=open` ask which epics are open, which is what `epic:bundle` and the
|
|
37
|
+
// Issue template do; counting either as the WIP count would credit the cap as kept by a run that
|
|
38
|
+
// never counted the backlog. The residual the pattern cannot separate is named in
|
|
39
|
+
// `docs/josh-commands.md`: the inventory command in the `diag` skill is byte-identical to a hand count
|
|
40
|
+
// of the backlog, so no pattern can tell those two apart.
|
|
41
|
+
const LABEL_FILTER = /--label\b|[?&]labels=/u
|
|
42
|
+
|
|
43
|
+
function counts_open_issues(command: string): boolean {
|
|
44
|
+
return shell_segments.segments_of(command).some((segment) => {
|
|
45
|
+
if (LABEL_FILTER.test(segment)) return false
|
|
46
|
+
|
|
47
|
+
return (ISSUE_LISTING.test(segment) && OPEN_STATE.test(segment)) || ISSUES_QUERY.test(segment)
|
|
48
|
+
})
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// The enumeration row itself, so `delivered-rules.ts` spreads one entry rather than restating the
|
|
52
|
+
// trigger and reason it already single-sources here. Once per run: the refusal changes what the run
|
|
53
|
+
// knows, so the reissue is let through.
|
|
54
|
+
const ROW = {
|
|
55
|
+
id: 'wip-cap',
|
|
56
|
+
is_trigger: bash_triggers.on_bash_command(bash_triggers.is_issue_filing),
|
|
57
|
+
reason: WIP_CAP_REASON,
|
|
58
|
+
keeps: bash_triggers.on_bash_command(counts_open_issues),
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const wip_cap = { ROW, WIP_CAP, WIP_CAP_REASON }
|
|
62
|
+
|
|
63
|
+
export { wip_cap }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { cli_flags } from '#scripts/lib/cli-flags'
|
|
2
|
+
import { run_issue_number } from '#scripts/run/run-issue-number'
|
|
2
3
|
import { run_carry, type CarryChange, type CarryClaimRequest, type CarryOwner } from './run-carry'
|
|
3
|
-
import { run_issue_number } from './run-issue-number'
|
|
4
4
|
|
|
5
5
|
// The argument half of `josh run:carry`. It sat inside `run-carry-cli.ts` until the ownership answers
|
|
6
6
|
// joshuafolkken/kit#1722 added took that file to 96% of the 300-line limit, and the seam it split on
|
|
@@ -9,6 +9,7 @@ import { run_issue_number } from './run-issue-number'
|
|
|
9
9
|
|
|
10
10
|
const NO_INCREMENT = 0
|
|
11
11
|
const ONE_CUT = 1
|
|
12
|
+
const ONE_MERGE = 1
|
|
12
13
|
// The four request groups below are mutually exclusive, so more than one of them named in a single
|
|
13
14
|
// invocation is a usage error rather than an order to guess.
|
|
14
15
|
const ONE_GROUP = 1
|
|
@@ -22,7 +23,7 @@ const MIN_PID = 1
|
|
|
22
23
|
// cannot advance a budget that is no longer its own. `--end` alone accepts it and ignores it, and a
|
|
23
24
|
// usage line that offered it there would be promising an ownership check nothing performs.
|
|
24
25
|
const USAGE =
|
|
25
|
-
'Usage: josh run:carry [--json] | --begin <invocation> [--owner <pid>] | --resume <invocation> [--owner <pid>] | (--cut | --merged <
|
|
26
|
+
'Usage: josh run:carry [--json] | --begin <invocation> [--owner <pid>] | --resume <invocation> [--owner <pid>] | (--cut | --merged <issue> | --filed <count> | --done <issue> | --retrospective --summary <text>) [--owner <pid>] | --end [--stopped <reason>]'
|
|
26
27
|
|
|
27
28
|
const OPTIONS = {
|
|
28
29
|
begin: { type: 'string' },
|
|
@@ -89,12 +90,12 @@ function to_count(value: OptionValue): number | undefined {
|
|
|
89
90
|
return COUNT_PATTERN.test(text) ? Number(text) : undefined
|
|
90
91
|
}
|
|
91
92
|
|
|
92
|
-
// **`--done`
|
|
93
|
-
// `run-issue-number.ts`'s, which already refuses `0` and a leading zero — the same rule the `run:*`
|
|
93
|
+
// **`--done` and `--merged` name an issue, so each is checked as one and not as a count.** The shape
|
|
94
|
+
// is `run-issue-number.ts`'s, which already refuses `0` and a leading zero — the same rule the `run:*`
|
|
94
95
|
// commands interpolate a number under, imported rather than restated. Absent is an empty object rather
|
|
95
96
|
// than a zero: there is no issue to record, which is a different fact from recording issue zero. A
|
|
96
|
-
// present-but-malformed value invalidates the whole invocation
|
|
97
|
-
function
|
|
97
|
+
// present-but-malformed value is `undefined`, which invalidates the whole invocation.
|
|
98
|
+
function to_issue(value: OptionValue): { issue?: number } | undefined {
|
|
98
99
|
const text = cli_flags.string_of(value)
|
|
99
100
|
|
|
100
101
|
if (text === undefined) return {}
|
|
@@ -106,7 +107,30 @@ function to_done(value: OptionValue): Pick<CarryChange, 'done'> | undefined {
|
|
|
106
107
|
// The pattern is anchored on digits and bounds nothing, so the magnitude check is separate — the
|
|
107
108
|
// same shape `backlog_budget_cli.to_count` ends with. A number past the safe range would be
|
|
108
109
|
// recorded as a different number and never match anything in `remaining`.
|
|
109
|
-
return Number.isSafeInteger(issue) ? {
|
|
110
|
+
return Number.isSafeInteger(issue) ? { issue } : undefined
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function to_done(value: OptionValue): Pick<CarryChange, 'done'> | undefined {
|
|
114
|
+
const parsed = to_issue(value)
|
|
115
|
+
|
|
116
|
+
if (parsed === undefined) return undefined
|
|
117
|
+
|
|
118
|
+
return parsed.issue === undefined ? {} : { done: parsed.issue }
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// **`--merged` names the issue that merged, never a count** (joshuafolkken/kit#3296). A bare count
|
|
122
|
+
// could not be matched against `merged_issues`, so a parent that counted a merge by hand and the
|
|
123
|
+
// driver's `run:merge` for the same issue added two for one merge. Naming the issue makes the hand
|
|
124
|
+
// count the same change `run:merge` applies — one merge plus its number — so `apply_change`'s
|
|
125
|
+
// duplicate check holds whichever of the two arrives first.
|
|
126
|
+
function to_merged(value: OptionValue): Pick<CarryChange, 'merged' | 'merged_issue'> | undefined {
|
|
127
|
+
const parsed = to_issue(value)
|
|
128
|
+
|
|
129
|
+
if (parsed === undefined) return undefined
|
|
130
|
+
|
|
131
|
+
return parsed.issue === undefined
|
|
132
|
+
? { merged: NO_INCREMENT }
|
|
133
|
+
: { merged: ONE_MERGE, merged_issue: parsed.issue }
|
|
110
134
|
}
|
|
111
135
|
|
|
112
136
|
// The two boolean marks in the counting group — `--cut` and `--retrospective` — as the partial the
|
|
@@ -119,18 +143,18 @@ function to_marks(values: ParsedValues): Pick<CarryChange, 'cuts' | 'retrospecti
|
|
|
119
143
|
}
|
|
120
144
|
|
|
121
145
|
function to_change(values: ParsedValues): CarryChange | undefined {
|
|
122
|
-
const merged =
|
|
146
|
+
const merged = to_merged(values.merged)
|
|
123
147
|
const filed = to_count(values.filed)
|
|
124
148
|
const done = to_done(values.done)
|
|
125
149
|
|
|
126
150
|
if (merged === undefined || filed === undefined || done === undefined) return undefined
|
|
127
151
|
|
|
128
|
-
return { merged, filed, ...to_marks(values), ...done }
|
|
152
|
+
return { ...merged, filed, ...to_marks(values), ...done }
|
|
129
153
|
}
|
|
130
154
|
|
|
131
|
-
// **A counting flag is what makes a count, never the sum of one.** `--
|
|
132
|
-
// that
|
|
133
|
-
//
|
|
155
|
+
// **A counting flag is what makes a count, never the sum of one.** `--filed 0` is a run reporting
|
|
156
|
+
// that it filed nothing, and reading it as a bare read would answer `none` with exit 0 against a
|
|
157
|
+
// record that is not there — the silent zero `docs/josh-commands.md` says exits 1.
|
|
134
158
|
function has_count(values: ParsedValues): boolean {
|
|
135
159
|
return (
|
|
136
160
|
values.cut === true ||
|
|
@@ -189,7 +213,7 @@ function is_summary_paired(values: ParsedValues): boolean {
|
|
|
189
213
|
|
|
190
214
|
// The counting group, split out so the shape below stays a flat list of exits. The summary rides along
|
|
191
215
|
// only when it is there — guaranteed paired with `--retrospective` by `is_summary_paired` — so a plain
|
|
192
|
-
// `--merged`
|
|
216
|
+
// `--merged` never carries one.
|
|
193
217
|
function to_count_request(values: ParsedValues, owner: CarryOwner): Request | undefined {
|
|
194
218
|
const change = to_change(values)
|
|
195
219
|
|
|
@@ -18,7 +18,9 @@ function next_merged_issues(
|
|
|
18
18
|
): ReadonlyArray<number> | undefined {
|
|
19
19
|
if (issue === undefined) return carry.merged_issues
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
const current = carry.merged_issues ?? []
|
|
22
|
+
|
|
23
|
+
return current.includes(issue) ? current : [...current, issue]
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
function is_duplicate_merge(carry: RunCarry, change: CarryChange): boolean {
|
|
@@ -27,6 +29,24 @@ function is_duplicate_merge(carry: RunCarry, change: CarryChange): boolean {
|
|
|
27
29
|
return issue !== undefined && carry.merged_issues?.includes(issue) === true
|
|
28
30
|
}
|
|
29
31
|
|
|
32
|
+
// Whether a change carries anything besides its merge — a filing, a cut, a streak step, a done issue
|
|
33
|
+
// or the retrospective mark.
|
|
34
|
+
function has_other_change(change: CarryChange): boolean {
|
|
35
|
+
const amounts = [change.filed, change.cuts, change.failures, change.outages]
|
|
36
|
+
const has_amount = amounts.some((amount) => (amount ?? NO_INCREMENT) > NO_INCREMENT)
|
|
37
|
+
|
|
38
|
+
return has_amount || change.done !== undefined || change.retrospective === true
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// **A duplicate merge drops only the merge** (joshuafolkken/kit#3296): `--merged <issue>` may ride
|
|
42
|
+
// beside `--filed` or `--done` in one call, and those are still increments the record has not seen.
|
|
43
|
+
// Only a duplicate carrying nothing else leaves the record untouched, which is `undefined` here.
|
|
44
|
+
function effective_change(carry: RunCarry, change: CarryChange): CarryChange | undefined {
|
|
45
|
+
if (!is_duplicate_merge(carry, change)) return change
|
|
46
|
+
|
|
47
|
+
return has_other_change(change) ? { ...change, merged: NO_INCREMENT } : undefined
|
|
48
|
+
}
|
|
49
|
+
|
|
30
50
|
function next_counts(
|
|
31
51
|
carry: RunCarry,
|
|
32
52
|
change: CarryChange,
|
|
@@ -47,18 +67,20 @@ function apply_change(
|
|
|
47
67
|
change: CarryChange,
|
|
48
68
|
now: Date = new Date(),
|
|
49
69
|
): RunCarry {
|
|
50
|
-
|
|
70
|
+
const effective = effective_change(carry, change)
|
|
71
|
+
|
|
72
|
+
if (effective === undefined) return carry
|
|
51
73
|
|
|
52
|
-
const streak = run_carry_streak.next_state(carry,
|
|
74
|
+
const streak = run_carry_streak.next_state(carry, effective, now)
|
|
53
75
|
const next: RunCarry = {
|
|
54
76
|
...carry,
|
|
55
|
-
...next_counts(carry,
|
|
56
|
-
merged_issues: next_merged_issues(carry,
|
|
77
|
+
...next_counts(carry, effective),
|
|
78
|
+
merged_issues: next_merged_issues(carry, effective.merged_issue),
|
|
57
79
|
failures: streak.failures,
|
|
58
80
|
outages: streak.outages,
|
|
59
81
|
last_outage_at: streak.last_outage_at,
|
|
60
|
-
done: next_done(carry,
|
|
61
|
-
retrospective:
|
|
82
|
+
done: next_done(carry, effective.done),
|
|
83
|
+
retrospective: effective.retrospective === true || carry.retrospective,
|
|
62
84
|
}
|
|
63
85
|
|
|
64
86
|
stamp_file.write_stamp(target, next)
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
import { fileURLToPath } from 'node:url'
|
|
3
3
|
import { cost_cli } from '#scripts/cost-runtime/cost-cli'
|
|
4
4
|
import { cost_verdict } from '#scripts/cost-runtime/cost-verdict'
|
|
5
|
+
import { run_event_stream } from '#scripts/run/event/run-event-stream'
|
|
6
|
+
import { run_event_stream_emit } from '#scripts/run/event/run-event-stream-emit'
|
|
7
|
+
import { run_stop_notify } from '#scripts/run/run-stop-notify'
|
|
5
8
|
import {
|
|
6
9
|
run_carry,
|
|
7
10
|
type CarryClaim,
|
|
@@ -12,9 +15,6 @@ import {
|
|
|
12
15
|
import { run_carry_args, type CountRequest, type Request } from './run-carry-args'
|
|
13
16
|
import { run_carry_conversation } from './run-carry-conversation'
|
|
14
17
|
import { run_carry_stash } from './run-carry-stash'
|
|
15
|
-
import { run_event_stream } from './run-event-stream'
|
|
16
|
-
import { run_event_stream_emit } from './run-event-stream-emit'
|
|
17
|
-
import { run_stop_notify } from './run-stop-notify'
|
|
18
18
|
|
|
19
19
|
// `josh run:carry` — the record that carries one invocation's budget across its own session cuts
|
|
20
20
|
// (joshuafolkken/kit#1714). A `backlogrun` begins it, counts a merge and a filing into it, marks each
|
|
@@ -303,9 +303,7 @@ function blocked_count(
|
|
|
303
303
|
request: CountRequest,
|
|
304
304
|
is_json: boolean,
|
|
305
305
|
): number | undefined {
|
|
306
|
-
if (run_carry.is_count_refused(carry, request.owner))
|
|
307
|
-
return report_count_refused(carry, is_json)
|
|
308
|
-
}
|
|
306
|
+
if (run_carry.is_count_refused(carry, request.owner)) return report_count_refused(carry, is_json)
|
|
309
307
|
|
|
310
308
|
if (is_cut_count(request) && run_carry.is_at_cut_cap(carry)) {
|
|
311
309
|
return report_cut_capped(carry, is_json)
|
|
@@ -2,10 +2,10 @@ import { backlog_budget } from '#scripts/backlog/backlog-budget'
|
|
|
2
2
|
import { git_command } from '#scripts/git/git-command'
|
|
3
3
|
import { process_identity } from '#scripts/josh/process-identity'
|
|
4
4
|
import { stamp_file } from '#scripts/josh/stamp-file'
|
|
5
|
+
import { run_invocation } from '#scripts/run/run-invocation'
|
|
5
6
|
import { z } from 'zod'
|
|
6
7
|
import { run_carry_change } from './run-carry-change'
|
|
7
8
|
import { run_carry_conversation } from './run-carry-conversation'
|
|
8
|
-
import { run_invocation } from './run-invocation'
|
|
9
9
|
|
|
10
10
|
// joshuafolkken/kit#1714: a `backlogrun` declares a budget — `--max`, `--idle` and the 8-hour
|
|
11
11
|
// whole-run bound — and then loses all of it at the session cut, because the cut ends the session and
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { cli_flags } from '#scripts/lib/cli-flags'
|
|
2
|
-
import { run_issue_number } from '
|
|
2
|
+
import { run_issue_number } from '#scripts/run/run-issue-number'
|
|
3
3
|
|
|
4
4
|
// `josh run:cut` turns its `argv` into one of four requests. The contract mirrors `run-carry-args.ts`:
|
|
5
5
|
// parsing lives here, acting on the record lives in `run-cut-cli.ts`, and a malformed command line is
|
|
@@ -6,12 +6,12 @@ import { git_command } from '#scripts/git/git-command'
|
|
|
6
6
|
import { lane_registry, type LaneInfo } from '#scripts/lane/lane-registry'
|
|
7
7
|
import { lane_relaunch } from '#scripts/lane/lane-relaunch'
|
|
8
8
|
import { openai_lane_supervisor } from '#scripts/lane/openai-lane-supervisor'
|
|
9
|
+
import { run_event_stream } from '#scripts/run/event/run-event-stream'
|
|
10
|
+
import { run_event_stream_emit } from '#scripts/run/event/run-event-stream-emit'
|
|
9
11
|
import { run_cut, type CutState, type RunCut } from './run-cut'
|
|
10
12
|
import { run_cut_args, type Request } from './run-cut-args'
|
|
11
13
|
import { run_cut_handoff } from './run-cut-handoff'
|
|
12
14
|
import { run_cut_report } from './run-cut-report'
|
|
13
|
-
import { run_event_stream } from './run-event-stream'
|
|
14
|
-
import { run_event_stream_emit } from './run-event-stream-emit'
|
|
15
15
|
|
|
16
16
|
// `josh run:cut` — the record that lets a lane child end its process before the gate and a fresh one
|
|
17
17
|
// resume from it (joshuafolkken/kit#1839). `run:cut <N>` writes the record and relaunches a fresh
|
|
@@ -5,9 +5,9 @@ import { git_command } from '#scripts/git/git-command'
|
|
|
5
5
|
import { git_common_directory } from '#scripts/git/git-common-directory'
|
|
6
6
|
import { stamp_file } from '#scripts/josh/stamp-file'
|
|
7
7
|
import { lane_child_invocation } from '#scripts/lane/lane-child-invocation'
|
|
8
|
+
import { run_hold, type RunHold } from '#scripts/run/hold/run-hold'
|
|
8
9
|
import { z } from 'zod'
|
|
9
10
|
import { run_cut_handoff, type Handoff } from './run-cut-handoff'
|
|
10
|
-
import { run_hold, type RunHold } from './run-hold'
|
|
11
11
|
|
|
12
12
|
// joshuafolkken/kit#1839: a lane child is a detached `fullrun #<N>` process, and the thinking it
|
|
13
13
|
// accumulates while implementing rides on every later API call in the same session — measured at 176K
|
|
@@ -2,19 +2,19 @@
|
|
|
2
2
|
import { fileURLToPath } from 'node:url'
|
|
3
3
|
import { josh_command } from '#scripts/josh/josh-run'
|
|
4
4
|
import { lane_child_marker } from '#scripts/lane/lane-child-marker'
|
|
5
|
-
import { run_cut_report } from '
|
|
5
|
+
import { run_cut_report } from '#scripts/run/cut/run-cut-report'
|
|
6
|
+
import { run_hold_cli } from '#scripts/run/hold/run-hold-cli'
|
|
7
|
+
import { run_halfrun_resume } from '#scripts/run/run-halfrun-resume'
|
|
8
|
+
import { run_label } from '#scripts/run/run-label'
|
|
9
|
+
import { run_next } from '#scripts/run/run-next'
|
|
10
|
+
import { run_prep } from '#scripts/run/run-prep'
|
|
11
|
+
import { run_prep_cli } from '#scripts/run/run-prep-cli'
|
|
12
|
+
import { run_prrun_resume } from '#scripts/run/run-prrun-resume'
|
|
13
|
+
import { run_stage, type StageCommand, type StageDecision } from '#scripts/run/run-stage'
|
|
14
|
+
import { run_stage_read, type StageRead } from '#scripts/run/run-stage-read'
|
|
15
|
+
import { run_step } from '#scripts/run/run-step'
|
|
6
16
|
import { run_entry, type EntryParts } from './run-entry'
|
|
7
17
|
import { run_entry_stop } from './run-entry-stop'
|
|
8
|
-
import { run_halfrun_resume } from './run-halfrun-resume'
|
|
9
|
-
import { run_hold_cli } from './run-hold-cli'
|
|
10
|
-
import { run_label } from './run-label'
|
|
11
|
-
import { run_next } from './run-next'
|
|
12
|
-
import { run_prep } from './run-prep'
|
|
13
|
-
import { run_prep_cli } from './run-prep-cli'
|
|
14
|
-
import { run_prrun_resume } from './run-prrun-resume'
|
|
15
|
-
import { run_stage, type StageCommand, type StageDecision } from './run-stage'
|
|
16
|
-
import { run_stage_read, type StageRead } from './run-stage-read'
|
|
17
|
-
import { run_step } from './run-step'
|
|
18
18
|
|
|
19
19
|
// `josh run:entry <N>` — one call for the fixed entry sequence a lane opens on (joshuafolkken/kit#2372).
|
|
20
20
|
// The loop used to spend a round trip on `run:hold`, one on `cost --cut`, one on `run:prep` and one on
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { run_hold_cli } from '
|
|
2
|
-
import { run_step } from '
|
|
1
|
+
import { run_hold_cli } from '#scripts/run/hold/run-hold-cli'
|
|
2
|
+
import { run_step } from '#scripts/run/run-step'
|
|
3
3
|
|
|
4
4
|
// `josh run:entry <N>` — the one call a `fullrun` makes to open a run (joshuafolkken/kit#2372). It
|
|
5
5
|
// folds the fixed entry sequence a lane spends four separate round trips on — claim the tree
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CarryRead } from '
|
|
1
|
+
import type { CarryRead } from '#scripts/run/carry/run-carry'
|
|
2
2
|
import { run_event_stream, type RunEvent } from './run-event-stream'
|
|
3
3
|
|
|
4
4
|
// The one place a stream consumer scopes the event stream to a single invocation (joshuafolkken/kit#2395).
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { error_text } from '#scripts/lib/error-message'
|
|
2
|
-
import { run_carry } from '
|
|
2
|
+
import { run_carry } from '#scripts/run/carry/run-carry'
|
|
3
3
|
import { run_event_scope } from './run-event-scope'
|
|
4
4
|
import { run_event_stream, type RunEvent } from './run-event-stream'
|
|
5
5
|
|
|
@@ -168,6 +168,20 @@ function last_position(events: ReadonlyArray<RunEvent>): number {
|
|
|
168
168
|
|
|
169
169
|
// The bounded stream serialized back to JSONL. The newest `EVENT_CAP` are kept and the oldest roll off;
|
|
170
170
|
// each survivor keeps its original `pos`, so the bound never renumbers a position a reader is holding.
|
|
171
|
+
// The stream held to `EVENT_CAP`, dropping the oldest trace events before any position
|
|
172
|
+
// (joshuafolkken/kit#3245). A long run's ship-stage and heartbeat lines once filled 396 of the 500 slots
|
|
173
|
+
// and pushed its cuts off, so the retrospective counted `cut 0` for a run with thirteen; a trace says only
|
|
174
|
+
// that the run was alive, so it is the first to go. Only a stream of positions alone rolls them off.
|
|
175
|
+
function bounded(events: ReadonlyArray<RunEvent>): ReadonlyArray<RunEvent> {
|
|
176
|
+
const excess = events.length - EVENT_CAP
|
|
177
|
+
|
|
178
|
+
if (excess <= 0) return events
|
|
179
|
+
|
|
180
|
+
const dropped = new Set(events.filter((event) => TRACE_KINDS.has(event.kind)).slice(0, excess))
|
|
181
|
+
|
|
182
|
+
return events.filter((event) => !dropped.has(event)).slice(-EVENT_CAP)
|
|
183
|
+
}
|
|
184
|
+
|
|
171
185
|
function serialize(events: ReadonlyArray<RunEvent>): string {
|
|
172
186
|
return `${events.map((event) => JSON.stringify(event)).join(LINE_SEPARATOR)}${LINE_SEPARATOR}`
|
|
173
187
|
}
|
|
@@ -184,9 +198,9 @@ function append(target: string, kind: string, text: string, at: string): AppendR
|
|
|
184
198
|
|
|
185
199
|
const existing = read_events(target)
|
|
186
200
|
const position = last_position(existing) + POSITION_INCREMENT
|
|
187
|
-
const
|
|
201
|
+
const events = bounded([...existing, { pos: position, at, kind, text }])
|
|
188
202
|
|
|
189
|
-
stamp_file.write_text_stamp(target, serialize(
|
|
203
|
+
stamp_file.write_text_stamp(target, serialize(events))
|
|
190
204
|
|
|
191
205
|
return { appended: true, position }
|
|
192
206
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env tsx
|
|
2
2
|
import { fileURLToPath } from 'node:url'
|
|
3
|
-
import { run_halfrun_resume } from '
|
|
3
|
+
import { run_halfrun_resume } from '#scripts/run/run-halfrun-resume'
|
|
4
|
+
import { run_label } from '#scripts/run/run-label'
|
|
5
|
+
import { run_preflight, type PreflightDecision } from '#scripts/run/run-preflight'
|
|
6
|
+
import { run_prrun_resume } from '#scripts/run/run-prrun-resume'
|
|
7
|
+
import { run_tidy_cli } from '#scripts/run/tidy/run-tidy-cli'
|
|
4
8
|
import { run_hold, type HoldRead, type RunHold } from './run-hold'
|
|
5
|
-
import { run_label } from './run-label'
|
|
6
|
-
import { run_preflight, type PreflightDecision } from './run-preflight'
|
|
7
|
-
import { run_prrun_resume } from './run-prrun-resume'
|
|
8
|
-
import { run_tidy_cli } from './run-tidy-cli'
|
|
9
9
|
|
|
10
10
|
// `josh run:hold [<N>]` and `josh run:release [<N> | --force]` — the working-tree guard the typed
|
|
11
11
|
// entry points ask before they start (joshuafolkken/kit#1091).
|
|
@@ -5,12 +5,13 @@ import { CONTEXT_CUT_THRESHOLD } from '#scripts/cost-runtime/context-cut-thresho
|
|
|
5
5
|
import { issue_closing_pr } from '#scripts/issue/issue-closing-pr'
|
|
6
6
|
import { issue_state_cli } from '#scripts/issue/issue-state-cli'
|
|
7
7
|
import { lane_handoff } from '#scripts/lane/lane-handoff'
|
|
8
|
+
import { lane_ledger } from '#scripts/lane/lane-ledger'
|
|
8
9
|
import { cli_flags } from '#scripts/lib/cli-flags'
|
|
9
|
-
import { run_carry, type CarryOwner, type RunCarry } from '
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import { run_issue_number } from '
|
|
10
|
+
import { run_carry, type CarryOwner, type RunCarry } from '#scripts/run/carry/run-carry'
|
|
11
|
+
import { run_event_stream } from '#scripts/run/event/run-event-stream'
|
|
12
|
+
import { run_event_stream_emit } from '#scripts/run/event/run-event-stream-emit'
|
|
13
|
+
import { run_ending } from '#scripts/run/run-ending'
|
|
14
|
+
import { run_issue_number } from '#scripts/run/run-issue-number'
|
|
14
15
|
import { run_merge, type ChildOutcome, type EndingSignals } from './run-merge'
|
|
15
16
|
import { run_merge_steps, type MergeContext } from './run-merge-steps'
|
|
16
17
|
|
|
@@ -234,6 +235,7 @@ async function on_merged(ctx: MergeContext): Promise<MergeVerdict> {
|
|
|
234
235
|
if (refused !== undefined) return report_count_refused(refused)
|
|
235
236
|
|
|
236
237
|
await run_event_stream_emit.emit(run_event_stream.EVENT_KIND.MERGE, `#${ctx.child} merged`)
|
|
238
|
+
await lane_ledger.record_merge(Number(ctx.child))
|
|
237
239
|
|
|
238
240
|
if (await run_merge_steps.is_over_budget(ctx.over)) return emit(OVER_TOKEN, SUCCESS_EXIT_CODE)
|
|
239
241
|
|
|
@@ -316,7 +318,10 @@ async function on_parked(ctx: MergeContext): Promise<MergeVerdict> {
|
|
|
316
318
|
return emit(await run_merge_steps.ask_next(ctx), SUCCESS_EXIT_CODE)
|
|
317
319
|
}
|
|
318
320
|
|
|
321
|
+
// A split child: nothing is counted, and its lane is closed when it holds nothing, so the promoted
|
|
322
|
+
// epic does not keep a seat the next child needs (joshuafolkken/kit#3334).
|
|
319
323
|
async function on_skipped(ctx: MergeContext): Promise<MergeVerdict> {
|
|
324
|
+
await run_merge_steps.close_split_lane(ctx.child)
|
|
320
325
|
await run_event_stream_emit.emit(run_event_stream.EVENT_KIND.SPLIT, `#${ctx.child} split`)
|
|
321
326
|
|
|
322
327
|
return emit(await run_merge_steps.ask_next(ctx), SUCCESS_EXIT_CODE)
|
|
@@ -9,9 +9,16 @@ import { lane_close } from '#scripts/lane/lane-close'
|
|
|
9
9
|
import { lane_reap } from '#scripts/lane/lane-reap'
|
|
10
10
|
import { lane_registry, type LaneInfo } from '#scripts/lane/lane-registry'
|
|
11
11
|
import { lane_relaunch } from '#scripts/lane/lane-relaunch'
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
12
|
+
import { lane_vacant } from '#scripts/lane/lane-vacant'
|
|
13
|
+
import { poll } from '#scripts/lib/poll'
|
|
14
|
+
import {
|
|
15
|
+
run_carry,
|
|
16
|
+
type CarryChange,
|
|
17
|
+
type CarryOwner,
|
|
18
|
+
type RunCarry,
|
|
19
|
+
} from '#scripts/run/carry/run-carry'
|
|
20
|
+
import { run_carry_conversation } from '#scripts/run/carry/run-carry-conversation'
|
|
21
|
+
import { run_cut, type RunCut } from '#scripts/run/cut/run-cut'
|
|
15
22
|
import { run_merge } from './run-merge'
|
|
16
23
|
|
|
17
24
|
// The result of attempting to apply a carry change. Distinguishing `refused` from `applied` lets
|
|
@@ -38,6 +45,7 @@ const LANE_CLOSE_OCCASION = 'lane close'
|
|
|
38
45
|
const GIT_ENTRY = '.git'
|
|
39
46
|
const MERGE_CLOSER = 'pnpm josh run:merge'
|
|
40
47
|
const SINGLE_READ = { attempts: 1, interval_ms: 0 }
|
|
48
|
+
const SYNC_RETRY = { attempts: 3, interval_ms: 5000 }
|
|
41
49
|
// What the driver judged when it parks a child, stated on the issue (joshuafolkken/kit#2769).
|
|
42
50
|
const FAILED_CAUSE = 'the child’s session ended with its issue still open and unfinished.'
|
|
43
51
|
const CUT_RELAUNCH_CAUSE =
|
|
@@ -125,10 +133,27 @@ async function refused_carry(ctx: MergeContext): Promise<RunCarry | undefined> {
|
|
|
125
133
|
return record.carry
|
|
126
134
|
}
|
|
127
135
|
|
|
136
|
+
// **A failed `main:sync` is retried before it ends the run** (joshuafolkken/kit#3323): one failure
|
|
137
|
+
// right after a merge — measured while several lanes merged at once — stopped the whole drive, and a
|
|
138
|
+
// hand-run `main:sync` minutes later succeeded. **The error carries the step's stderr, not its
|
|
139
|
+
// stdout**: `main:sync` reports git's refusal on stderr, while stdout carries the wrapper's guard
|
|
140
|
+
// statistics, which is all the old message showed.
|
|
128
141
|
async function sync_main(): Promise<void> {
|
|
129
|
-
|
|
142
|
+
// `poll_until` answers only whether it succeeded, so the last attempt's stderr is kept here.
|
|
143
|
+
let error_output = ''
|
|
130
144
|
|
|
131
|
-
|
|
145
|
+
const is_synced = await poll.poll_until(
|
|
146
|
+
async () => {
|
|
147
|
+
const result = await josh(['main:sync'])
|
|
148
|
+
|
|
149
|
+
error_output = result.err ?? ''
|
|
150
|
+
|
|
151
|
+
return result.code === 0
|
|
152
|
+
},
|
|
153
|
+
{ ...SYNC_RETRY, sleeper: poll.sleep },
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
if (!is_synced) throw new Error(`main:sync failed: ${error_output}`)
|
|
132
157
|
}
|
|
133
158
|
|
|
134
159
|
async function close_lane(child: string): Promise<void> {
|
|
@@ -172,6 +197,28 @@ async function preserve_uncommitted(child: string): Promise<boolean> {
|
|
|
172
197
|
}
|
|
173
198
|
}
|
|
174
199
|
|
|
200
|
+
function kept_lane_comment(directory: string): string {
|
|
201
|
+
return `The split left this issue's lane open: it still holds a commit, an uncommitted change or a live process — ${directory}`
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// A child promoted to an epic by a split leaves its lane holding a seat (joshuafolkken/kit#3334): the
|
|
205
|
+
// epic root is never dispatched again, so nothing else would ever close it. The lane is closed only
|
|
206
|
+
// when it holds nothing — no commit, no change, no live process (`lane_vacant`); any other lane is
|
|
207
|
+
// kept, and why is stated on the issue.
|
|
208
|
+
async function close_split_lane(child: string): Promise<void> {
|
|
209
|
+
const lane = await lane_registry.find_open_lane(child)
|
|
210
|
+
|
|
211
|
+
if (lane === undefined) return
|
|
212
|
+
|
|
213
|
+
if (await lane_vacant.is_vacant(lane)) {
|
|
214
|
+
await close_lane(child)
|
|
215
|
+
|
|
216
|
+
return
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
await git_gh_issue_write.issue_try_comment(child, kept_lane_comment(lane.directory))
|
|
220
|
+
}
|
|
221
|
+
|
|
175
222
|
// The progress comment is a human-readable mirror of the carry record, so it is best-effort and only
|
|
176
223
|
// where a named epic has a body to carry it — a pure backlog run keeps the record alone.
|
|
177
224
|
async function post_counters(ctx: MergeContext, carry: RunCarry | undefined): Promise<void> {
|
|
@@ -356,6 +403,7 @@ async function ask_next(ctx: MergeContext): Promise<string> {
|
|
|
356
403
|
const run_merge_steps = {
|
|
357
404
|
CUT_RELAUNCH_CAUSE,
|
|
358
405
|
ask_next,
|
|
406
|
+
close_split_lane,
|
|
359
407
|
do_failed,
|
|
360
408
|
do_merged,
|
|
361
409
|
do_outage,
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
NEEDS_DECISION_LABEL,
|
|
6
6
|
} from '#scripts/issue/issue-labels'
|
|
7
7
|
import type { IssueState } from '#scripts/issue/issue-state'
|
|
8
|
-
import type { CarryChange, RunCarry } from '
|
|
8
|
+
import type { CarryChange, RunCarry } from '#scripts/run/carry/run-carry'
|
|
9
9
|
|
|
10
10
|
// joshuafolkken/kit#2024: a `backlogrun` merge event was two parent turns — a reading turn and an
|
|
11
11
|
// acting turn — spent at the session whose context is largest and whose per-turn cost is highest.
|
|
@@ -6,7 +6,7 @@ import { backlog_ready } from '#scripts/backlog/backlog-ready'
|
|
|
6
6
|
import { gh_spawn } from '#scripts/gh/gh-spawn'
|
|
7
7
|
import { lane_child_marker } from '#scripts/lane/lane-child-marker'
|
|
8
8
|
import { error_text } from '#scripts/lib/error-message'
|
|
9
|
-
import { run_event_stream_emit } from '
|
|
9
|
+
import { run_event_stream_emit } from '#scripts/run/event/run-event-stream-emit'
|
|
10
10
|
import { run_progress, type ProgressState } from './run-progress'
|
|
11
11
|
import { run_progress_args, type ParsedValues } from './run-progress-args'
|
|
12
12
|
import { run_progress_clock } from './run-progress-clock'
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs'
|
|
2
2
|
import path from 'node:path'
|
|
3
|
+
import { ancestor_directories } from '#scripts/lib/ancestor-directories'
|
|
3
4
|
import { z } from 'zod'
|
|
4
5
|
import { run_progress } from './run-progress'
|
|
5
6
|
|
|
@@ -28,10 +29,6 @@ import { run_progress } from './run-progress'
|
|
|
28
29
|
|
|
29
30
|
const PACKAGE_FILE = 'package.json'
|
|
30
31
|
|
|
31
|
-
// Deep enough to cross a workspace package and its root, and bounded so a path that never reaches a
|
|
32
|
-
// root — a broken mount, a mocked `dirname` — cannot spin.
|
|
33
|
-
const MAX_DEPTH = 10
|
|
34
|
-
|
|
35
32
|
// Unknown keys are stripped rather than rejected: this reads a whole `package.json`, and every other
|
|
36
33
|
// field in it is none of this module's business. A present-but-unusable interval fails the parse and
|
|
37
34
|
// falls through, which is the same answer an unusable environment variable already gets.
|
|
@@ -39,18 +36,6 @@ const package_schema = z.object({
|
|
|
39
36
|
josh: z.object({ progress_interval_minutes: z.number().positive() }).optional(),
|
|
40
37
|
})
|
|
41
38
|
|
|
42
|
-
function ancestors_of(start: string): ReadonlyArray<string> {
|
|
43
|
-
const directories: Array<string> = []
|
|
44
|
-
let current = path.resolve(start)
|
|
45
|
-
|
|
46
|
-
while (directories.length < MAX_DEPTH && !directories.includes(current)) {
|
|
47
|
-
directories.push(current)
|
|
48
|
-
current = path.dirname(current)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return directories
|
|
52
|
-
}
|
|
53
|
-
|
|
54
39
|
function read_declared_minutes(directory: string): number | undefined {
|
|
55
40
|
try {
|
|
56
41
|
const raw = readFileSync(path.join(directory, PACKAGE_FILE), 'utf8')
|
|
@@ -63,7 +48,7 @@ function read_declared_minutes(directory: string): number | undefined {
|
|
|
63
48
|
}
|
|
64
49
|
|
|
65
50
|
function read_package_minutes(start: string): number | undefined {
|
|
66
|
-
for (const directory of
|
|
51
|
+
for (const directory of ancestor_directories.list(start)) {
|
|
67
52
|
const minutes = read_declared_minutes(directory)
|
|
68
53
|
|
|
69
54
|
if (minutes !== undefined) return minutes
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { loadavg } from 'node:os'
|
|
2
2
|
import { epic_busy } from '#scripts/epic/epic-busy'
|
|
3
3
|
import { git_command } from '#scripts/git/git-command'
|
|
4
|
-
import type { OpenIssueData } from '#scripts/git/schemas'
|
|
4
|
+
import type { OpenIssueData } from '#scripts/git/git-schemas'
|
|
5
5
|
import { lane_registry } from '#scripts/lane/lane-registry'
|
|
6
6
|
import { lane_report } from '#scripts/lane/lane-report'
|
|
7
|
-
import { run_carry, type CarryRead } from '
|
|
8
|
-
import { run_hold, type HoldRead } from '
|
|
9
|
-
import { run_liveness } from '
|
|
10
|
-
import { run_preflight } from '
|
|
7
|
+
import { run_carry, type CarryRead } from '#scripts/run/carry/run-carry'
|
|
8
|
+
import { run_hold, type HoldRead } from '#scripts/run/hold/run-hold'
|
|
9
|
+
import { run_liveness } from '#scripts/run/run-liveness'
|
|
10
|
+
import { run_preflight } from '#scripts/run/run-preflight'
|
|
11
11
|
import type { ChildObservation, LaneObservation, Observations } from './run-progress'
|
|
12
12
|
import { run_progress_clock } from './run-progress-clock'
|
|
13
13
|
|