@joshuafolkken/kit 1.1178.0 → 1.1240.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 +7 -3
- package/.claude/skills/workflow-commands/backlogrun-park.md +23 -2
- package/.claude/skills/workflow-commands/backlogrun-progress.md +9 -4
- 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 +10 -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 +2 -1
- package/.claude/skills/workflow-commands/latest-gate.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 +50 -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 +44 -38
- 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-G6KRCKEC.js → chunk-4TZVB44A.js} +496 -378
- package/dist/hooks/chunk-5VNDSNG3.js +12 -0
- package/dist/hooks/chunk-CDY4NFQG.js +15 -0
- package/dist/hooks/chunk-ELCN5LCH.js +135 -0
- package/dist/hooks/{chunk-VQLLNFNT.js → chunk-F3ELQ2AF.js} +3 -3
- package/dist/hooks/{chunk-I4XSL4TT.js → chunk-GPTFMK5E.js} +1 -1
- package/dist/hooks/{chunk-3V37IID6.js → chunk-JBBMAPC4.js} +23 -14
- package/dist/hooks/{chunk-UAGLLIGZ.js → chunk-KHGB5S3Y.js} +7 -6
- package/dist/hooks/{chunk-GDS5N2KB.js → chunk-KHX4U3BG.js} +735 -683
- package/dist/hooks/{chunk-VESKRQOF.js → chunk-KRBERBBI.js} +3 -3
- package/dist/hooks/{chunk-DO6NWWHU.js → chunk-QVSWU24O.js} +4 -4
- package/dist/hooks/{chunk-S6X6WYKR.js → chunk-WK2XSHSI.js} +1643 -923
- package/dist/hooks/{chunk-ZAL3NRGL.js → chunk-XZYKEM6J.js} +25 -10
- package/dist/hooks/{chunk-32GQTL4F.js → chunk-ZQGD4GBY.js} +4 -2
- 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 +203 -179
- 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 -72
- package/dist/josh.js +1088 -78
- 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/issue-template.md +1 -0
- 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-admission.ts +162 -0
- package/scripts/gate/core-budget.ts +190 -68
- package/scripts/gate/gate-plan.ts +80 -7
- package/scripts/gate/gate-report.ts +28 -9
- package/scripts/gate/gate-skip.ts +38 -7
- package/scripts/gate/hook-gate-reuse.ts +12 -10
- package/scripts/gate/machine-capacity.ts +175 -0
- 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 +34 -10
- 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 +10 -16
- 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/package-manager-pin.ts +35 -0
- 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 +32 -7
- 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 +72 -22
- package/scripts/issue/issue-file.ts +29 -1
- package/scripts/issue/issue-labels.ts +13 -0
- package/scripts/issue/issue-release-cli.ts +155 -0
- package/scripts/issue/issue-release.ts +58 -0
- 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 +14 -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 +18 -0
- package/scripts/josh/josh-commands-document.ts +1 -0
- package/scripts/josh/josh-commands-issue.ts +8 -1
- package/scripts/josh/josh-commands-lane.ts +24 -1
- package/scripts/josh/josh-commands-maintenance.ts +6 -6
- package/scripts/josh/josh-commands-run.ts +12 -7
- package/scripts/josh/josh-in-process.ts +28 -9
- package/scripts/josh/josh-logic.ts +34 -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 +12 -4
- 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 +44 -30
- 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-open.ts +5 -5
- package/scripts/lane/lane-paths.ts +13 -0
- package/scripts/lane/lane-reap.ts +1 -3
- package/scripts/lane/lane-registry.ts +11 -0
- package/scripts/lane/lane-relaunch.ts +1 -1
- package/scripts/lane/lane-stats.ts +224 -0
- package/scripts/lane/lane-stray.ts +140 -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/release/github-release-environment.ts +1 -0
- package/scripts/release/github-release-runs.ts +115 -0
- package/scripts/release/github-release.ts +13 -67
- 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} +18 -5
- 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-render.ts → event/run-event-render.ts} +1 -0
- 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} +20 -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 +7 -4
- 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} +25 -11
- package/scripts/run/{run-wake-describe.ts → wake/run-wake-describe.ts} +58 -7
- 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} +13 -15
- 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} +16 -65
- 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 +124 -93
- 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 +6 -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-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,128 @@
|
|
|
1
|
+
import type { GuardRun } from '#scripts/josh/hook-decision'
|
|
2
|
+
import { lane_child_marker } from '#scripts/lane/lane-child-marker'
|
|
3
|
+
import { time_density_hook } from '#scripts/time-runtime/time-density-hook'
|
|
4
|
+
import { bash_triggers } from './bash-triggers'
|
|
5
|
+
import { lane_park } from './lane-park'
|
|
6
|
+
import { shell_segments } from './shell-segments'
|
|
7
|
+
import { tail_commands } from './tail-commands'
|
|
8
|
+
|
|
9
|
+
// A dispatched lane child that split its own Issue is stopped from parking the epic it promoted
|
|
10
|
+
// (joshuafolkken/kit#3296).
|
|
11
|
+
//
|
|
12
|
+
// **A split is not a park.** On 2026-10-06, inside a `backlogrun`, the lane child for #3255 promoted
|
|
13
|
+
// its Issue to an epic with `pnpm josh epic --promote 3255`, filed #3291–#3294, then applied
|
|
14
|
+
// `needs-decision` to #3255 and sent a `confirmation` Telegram asking whether to run the epic. The
|
|
15
|
+
// children were already opted in, so the question had no answer to wait for, and the same run's child
|
|
16
|
+
// for #3247 had split without parking. `backlogrun-park.md` → "Splitting a child mid-run" says
|
|
17
|
+
// splitting alone never adds `needs-decision` to the promoted epic; the parent reads an open Issue that
|
|
18
|
+
// carries `epic` as a split (`run-merge.ts`), so the label is never what tells it.
|
|
19
|
+
//
|
|
20
|
+
// **The material is the run's own calls.** The promotion is a `josh epic --promote <N>` this run issued,
|
|
21
|
+
// read off the transcript tail as `filing-cap.ts` reads its filings — a tool call, never prose, so a
|
|
22
|
+
// child that merely read a document quoting the command is not mistaken for one that ran it. Only a
|
|
23
|
+
// promotion of the dispatched issue counts: the epic a mid-run split promotes is the child's own Issue.
|
|
24
|
+
|
|
25
|
+
// `josh epic`, named canonically — `shell_segments.is_josh_command` expands an alias before the match.
|
|
26
|
+
const EPIC_COMMANDS: ReadonlySet<string> = new Set(['epic'])
|
|
27
|
+
const PROMOTED_ISSUE = /--promote[=\s]+["']?(?<issue>\d+)\b/u
|
|
28
|
+
// The issue a label write targets, in the two spellings `lane_park.records_the_park` accepts: the REST
|
|
29
|
+
// path `…/issues/<N>/labels` and `gh issue edit <N>`.
|
|
30
|
+
const LABEL_TARGETS: ReadonlyArray<RegExp> = [
|
|
31
|
+
/\/issues\/(?<issue>\d+)\/labels\b/u,
|
|
32
|
+
/\bissue\s+edit\s+["']?(?<issue>\d+)\b/u,
|
|
33
|
+
]
|
|
34
|
+
// The issue a confirmation notify is about, read off its `--issue-url` the way `stop-rules.ts` spells it.
|
|
35
|
+
const ISSUE_URL = /--issue-url[=\s]+["']?([^\s"']+)/u
|
|
36
|
+
const URL_ISSUE = /\/issues\/(\d+)\b/u
|
|
37
|
+
|
|
38
|
+
function promoted_in(segment: string): string | undefined {
|
|
39
|
+
if (!shell_segments.is_josh_command(segment, EPIC_COMMANDS)) return undefined
|
|
40
|
+
|
|
41
|
+
return PROMOTED_ISSUE.exec(segment)?.groups?.['issue']
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Every issue a `josh epic --promote` among these commands promoted.
|
|
45
|
+
function promoted_issues(commands: ReadonlyArray<string>): ReadonlySet<string> {
|
|
46
|
+
const segments = commands.flatMap((command) => shell_segments.segments_of(command))
|
|
47
|
+
const issues = segments.map((segment) => promoted_in(segment))
|
|
48
|
+
|
|
49
|
+
return new Set(issues.filter((issue) => issue !== undefined))
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function label_target(command: string): string | undefined {
|
|
53
|
+
for (const pattern of LABEL_TARGETS) {
|
|
54
|
+
const issue = pattern.exec(command)?.groups?.['issue']
|
|
55
|
+
|
|
56
|
+
if (issue !== undefined) return issue
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return undefined
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// **Both acts of the park are refused: the label write and the stop Telegram.** Refusing the label
|
|
63
|
+
// alone left the notify to `lane-park`, whose once-per-run refusal asks for this very label and lets the
|
|
64
|
+
// reissue through, so the Telegram still went out. This row is listed before `lane-park` and shares the
|
|
65
|
+
// notify with it — an overlap that is safe because a run that promoted nothing is left to `lane-park`
|
|
66
|
+
// (`decide` answers false and the call falls through). Either act onto another issue — the leftover
|
|
67
|
+
// child the procedure does park — is not the epic's park, so it is left alone.
|
|
68
|
+
function is_park_of(command: string, issue: string): boolean {
|
|
69
|
+
return lane_park.records_the_park(command) && label_target(command) === issue
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function notified_issue(command: string): string | undefined {
|
|
73
|
+
const [, url = ''] = ISSUE_URL.exec(command) ?? []
|
|
74
|
+
const [, issue] = URL_ISSUE.exec(url) ?? []
|
|
75
|
+
|
|
76
|
+
return issue
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function is_notify_of(command: string, issue: string): boolean {
|
|
80
|
+
return lane_park.is_confirmation_notify(command) && notified_issue(command) === issue
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// **The command test comes first and the world is consulted second**, exactly as `lane-park.ts` gates
|
|
84
|
+
// its own read: a person working in a lane carries no mark and sees no refusal.
|
|
85
|
+
function is_candidate(command: string): boolean {
|
|
86
|
+
const issue = lane_child_marker.marked_issue()
|
|
87
|
+
|
|
88
|
+
if (issue === undefined) return false
|
|
89
|
+
if (!is_park_of(command, issue) && !is_notify_of(command, issue)) return false
|
|
90
|
+
|
|
91
|
+
return lane_child_marker.is_child_of(process.cwd())
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Refused only once the run has promoted the dispatched issue, and on every occurrence: a split child
|
|
95
|
+
// must never park its epic, so the route is always "return the split", never a reissue.
|
|
96
|
+
function decide(_call: unknown, run: GuardRun): boolean {
|
|
97
|
+
const issue = lane_child_marker.marked_issue()
|
|
98
|
+
const commands = tail_commands.prior_bash_commands(time_density_hook.read_tail(run.transcript))
|
|
99
|
+
|
|
100
|
+
return issue !== undefined && promoted_issues(commands).has(issue)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const LANE_SPLIT_PARK_REASON =
|
|
104
|
+
'⛔ lane split park: this session is a dispatched lane child that promoted its own Issue to an epic ' +
|
|
105
|
+
'this run, and a split is not a park — do not apply `needs-decision` to the promoted epic and do not ' +
|
|
106
|
+
'send a `confirmation` Telegram. The parent reads an open Issue carrying `epic` as a split and ' +
|
|
107
|
+
'continues through its children; a question here has nobody to answer it (joshuafolkken/kit#3296, ' +
|
|
108
|
+
'measured 2026-10-06 when the child for #3255 parked its promoted epic). If what remains of the ' +
|
|
109
|
+
'original work needs a person, park that child issue instead, then end the turn. The procedure is ' +
|
|
110
|
+
'`.claude/skills/workflow-commands/backlogrun-park.md` → "Splitting a child mid-run". This rule fires ' +
|
|
111
|
+
'on every occurrence, not once per run.'
|
|
112
|
+
|
|
113
|
+
// It declares no `keeps`: not parking is the absence of a call, so the row is reported unmeasured
|
|
114
|
+
// rather than scored on an act that does not exist (`lane-carry-conflict.ts`).
|
|
115
|
+
const ROW = {
|
|
116
|
+
id: 'lane-split-park',
|
|
117
|
+
is_trigger: bash_triggers.on_bash_command(is_candidate),
|
|
118
|
+
reason: LANE_SPLIT_PARK_REASON,
|
|
119
|
+
decide,
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const lane_split_park = {
|
|
123
|
+
LANE_SPLIT_PARK_REASON,
|
|
124
|
+
ROW,
|
|
125
|
+
promoted_issues,
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export { lane_split_park }
|
|
@@ -133,7 +133,7 @@ function firing_oracles(): ReadonlyArray<{
|
|
|
133
133
|
return decision_oracle.DECISION_ORACLES.flatMap((oracle) => {
|
|
134
134
|
const firing_point = FIRING.get(oracle.name)
|
|
135
135
|
|
|
136
|
-
return firing_point === undefined ? [] :
|
|
136
|
+
return firing_point === undefined ? [] : { oracle, firing_point }
|
|
137
137
|
})
|
|
138
138
|
}
|
|
139
139
|
|
|
@@ -17,7 +17,7 @@ import { bash_triggers } from './bash-triggers'
|
|
|
17
17
|
// way the command's *exit* is not what ends the wait, and each pass spends a full-context round trip.
|
|
18
18
|
// A command backgrounded with `run_in_background` re-invokes the run when it exits — the completion
|
|
19
19
|
// notification is what ends the wait on the task itself, which is the mechanism this row hands back,
|
|
20
|
-
// the same reading joshuafolkken/kit#1510 took for the foreground push (`run-tail.ts`).
|
|
20
|
+
// the same reading joshuafolkken/kit#1510 took for the foreground push (`run-tail-rule.ts`).
|
|
21
21
|
//
|
|
22
22
|
// **It fires on every occurrence**, for the reason `git-force.ts` does: a poll loop wastes the same
|
|
23
23
|
// round trips each time it is armed, so refused-once-and-free-after would put every loop but the first
|
|
@@ -2,7 +2,7 @@ import { cost_cli, type CostVerdict } from '#scripts/cost-runtime/cost-cli'
|
|
|
2
2
|
import { cost_verdict } from '#scripts/cost-runtime/cost-verdict'
|
|
3
3
|
import { lane_child_marker } from '#scripts/lane/lane-child-marker'
|
|
4
4
|
import { lane_paths } from '#scripts/lane/lane-paths'
|
|
5
|
-
import { run_cut, type RunCut } from '#scripts/run/run-cut'
|
|
5
|
+
import { run_cut, type RunCut } from '#scripts/run/cut/run-cut'
|
|
6
6
|
import type { GuardedCall } from '#scripts/time-runtime/time-batch-guard'
|
|
7
7
|
import { bash_triggers } from './bash-triggers'
|
|
8
8
|
import { shell_segments } from './shell-segments'
|
|
@@ -2,12 +2,15 @@ import path from 'node:path'
|
|
|
2
2
|
import { doctor_consumer } from '#scripts/doctor/doctor-consumer'
|
|
3
3
|
import { json_value } from '#scripts/lib/json-value'
|
|
4
4
|
import type { GuardedCall } from '#scripts/time-runtime/time-batch-guard'
|
|
5
|
+
import { bash_triggers } from './bash-triggers'
|
|
6
|
+
import { shell_segments } from './shell-segments'
|
|
5
7
|
|
|
6
8
|
// The trigger and the delivered text behind the `protected-file` row of `delivered-rules.ts`
|
|
7
9
|
// (joshuafolkken/kit#2983): the two files a run's own file tools must not touch.
|
|
8
10
|
//
|
|
9
|
-
// - **`.env` is never read
|
|
10
|
-
//
|
|
11
|
+
// - **`.env` is never read** — by the `Read` tool or by a shell reader in a `Bash` call. It carries the
|
|
12
|
+
// Telegram bot token, and either read lands it in the transcript. The scripts that need it load it
|
|
13
|
+
// in their own process, so refusing the call costs them nothing.
|
|
11
14
|
// - **`.claude/settings.json` is never edited in a consumer repository.** It is the deny list and the
|
|
12
15
|
// hooks that enforce every other rule, so a run that rewrites it can switch the guards off; `josh
|
|
13
16
|
// sync` owns it there. Only a kit consumer's file is refused — decided per file from the repository
|
|
@@ -20,6 +23,29 @@ const READ_TOOL = 'Read'
|
|
|
20
23
|
const EDIT_TOOLS: ReadonlySet<string> = new Set(['Edit', 'Write'])
|
|
21
24
|
const ENVIRONMENT_FILE = '.env'
|
|
22
25
|
const SETTINGS_FILE = path.join('.claude', 'settings.json')
|
|
26
|
+
const WHITESPACE = /\s+/u
|
|
27
|
+
const TOKEN_QUOTES = /["']/gu
|
|
28
|
+
const INPUT_REDIRECT = '<'
|
|
29
|
+
const SHELL_READERS: ReadonlySet<string> = new Set([
|
|
30
|
+
'.',
|
|
31
|
+
'awk',
|
|
32
|
+
'bat',
|
|
33
|
+
'cat',
|
|
34
|
+
'cut',
|
|
35
|
+
'grep',
|
|
36
|
+
'head',
|
|
37
|
+
'less',
|
|
38
|
+
'more',
|
|
39
|
+
'nl',
|
|
40
|
+
'od',
|
|
41
|
+
'rg',
|
|
42
|
+
'sed',
|
|
43
|
+
'sort',
|
|
44
|
+
'source',
|
|
45
|
+
'strings',
|
|
46
|
+
'tail',
|
|
47
|
+
'xxd',
|
|
48
|
+
])
|
|
23
49
|
|
|
24
50
|
function file_path_of(call: GuardedCall): string {
|
|
25
51
|
if (!json_value.is_record(call.input)) return ''
|
|
@@ -29,8 +55,36 @@ function file_path_of(call: GuardedCall): string {
|
|
|
29
55
|
return typeof value === 'string' ? value : ''
|
|
30
56
|
}
|
|
31
57
|
|
|
58
|
+
function is_environment_path(token: string): boolean {
|
|
59
|
+
return path.basename(token.replaceAll(TOKEN_QUOTES, '')) === ENVIRONMENT_FILE
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// A shell read reaches the same bytes a `Read` does, so a segment that runs a reader (`cat .env`,
|
|
63
|
+
// `source .env`) or redirects the file into a command (`< .env`) is refused too. `.env.example` and
|
|
64
|
+
// `.env.local` keep passing: only a token whose basename is exactly `.env` counts.
|
|
65
|
+
function is_environment_read_segment(segment: string): boolean {
|
|
66
|
+
const words = segment
|
|
67
|
+
.replaceAll(INPUT_REDIRECT, ' < ')
|
|
68
|
+
.split(WHITESPACE)
|
|
69
|
+
.filter((word) => word !== '')
|
|
70
|
+
const is_redirected = words.some(
|
|
71
|
+
(word, index) => word === INPUT_REDIRECT && is_environment_path(words[index + 1] ?? ''),
|
|
72
|
+
)
|
|
73
|
+
const [command = '', ...rest] = words
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
is_redirected || (SHELL_READERS.has(command) && rest.some((word) => is_environment_path(word)))
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function is_environment_shell_read(command: string): boolean {
|
|
81
|
+
return shell_segments.segments_of(command).some((segment) => is_environment_read_segment(segment))
|
|
82
|
+
}
|
|
83
|
+
|
|
32
84
|
function is_environment_read(call: GuardedCall): boolean {
|
|
33
|
-
|
|
85
|
+
if (call.name === READ_TOOL) return is_environment_path(file_path_of(call))
|
|
86
|
+
|
|
87
|
+
return bash_triggers.on_bash_command(is_environment_shell_read)(call)
|
|
34
88
|
}
|
|
35
89
|
|
|
36
90
|
// The repository the settings file belongs to is two levels above it (`<root>/.claude/settings.json`).
|
|
@@ -55,7 +109,8 @@ function is_protected_file_call(
|
|
|
55
109
|
}
|
|
56
110
|
|
|
57
111
|
const PROTECTED_FILE_REASON =
|
|
58
|
-
'⛔ protected file: `.env` holds the Telegram bot token, so reading it
|
|
112
|
+
'⛔ protected file: `.env` holds the Telegram bot token, so reading it — with the Read tool or a ' +
|
|
113
|
+
'shell reader such as `cat` / `grep` / `source` — puts a secret in the ' +
|
|
59
114
|
'transcript — the scripts that need it load it in their own process. `.claude/settings.json` in a ' +
|
|
60
115
|
'consumer repository is the deny list and the hooks every other rule rests on, so a run must not ' +
|
|
61
116
|
'rewrite it; `josh sync` owns it, and a change belongs upstream in kit (`CLAUDE.md` → "Route ' +
|
|
@@ -166,7 +166,7 @@ const RUN_TAIL_REASON =
|
|
|
166
166
|
'run**, so ' +
|
|
167
167
|
'reissuing the same call in the foreground will be refused again.'
|
|
168
168
|
|
|
169
|
-
const
|
|
169
|
+
const run_tail_rule = {
|
|
170
170
|
RUN_TAIL_REASON,
|
|
171
171
|
decide,
|
|
172
172
|
is_backgrounded_push_step,
|
|
@@ -175,4 +175,4 @@ const run_tail = {
|
|
|
175
175
|
is_push_step_call,
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
-
export {
|
|
178
|
+
export { run_tail_rule }
|
|
@@ -140,7 +140,7 @@ const BODY_FLAG = new RegExp(
|
|
|
140
140
|
'u',
|
|
141
141
|
)
|
|
142
142
|
|
|
143
|
-
// **A flag is only a flag outside the quotes**, the same reading `run-tail.ts` takes of a pull-request
|
|
143
|
+
// **A flag is only a flag outside the quotes**, the same reading `run-tail-rule.ts` takes of a pull-request
|
|
144
144
|
// title. This repository's own refusal text names `--body-file <path>`, so a `grep` or an `echo`
|
|
145
145
|
// quoting it would otherwise be scored as a run that passed a body by path. The quoted spellings of
|
|
146
146
|
// the same thing are not lost by blanking: `--field "body=@<path>"` is a whole-value file reference,
|
|
@@ -83,6 +83,9 @@ interface StopContext {
|
|
|
83
83
|
handed_off: boolean
|
|
84
84
|
// The resolved `JOSH_SESSION_LANG` — `session_language.resolve_session_lang` (joshuafolkken/kit#2470).
|
|
85
85
|
session_lang: string
|
|
86
|
+
// This session is an agent kit launched under `claude -p` — `agent_headless.is_headless`
|
|
87
|
+
// (joshuafolkken/kit#3245). No person reads its reply, so the rules on how a reply is written stand down.
|
|
88
|
+
headless_agent: boolean
|
|
86
89
|
}
|
|
87
90
|
|
|
88
91
|
interface StopOutcome {
|
|
@@ -170,12 +173,10 @@ const HEADLESS_WAIT_CALLS = ['"command":"pnpm josh lane:await']
|
|
|
170
173
|
const HEADLESS_WAIT_BODY =
|
|
171
174
|
' this is a `claude -p` `backlogrun` parent (`JOSH_RUN_HEADLESS`) with lanes still ' +
|
|
172
175
|
'in flight, and ending this turn ends the process — its background waits are killed with it and the ' +
|
|
173
|
-
|
|
174
|
-
'
|
|
175
|
-
'`pnpm josh run:
|
|
176
|
-
'
|
|
177
|
-
'after `pnpm josh run:carry --cut` or `--end` (`backlogrun-progress.md` → "The parent keeps no clock ' +
|
|
178
|
-
'of its own").'
|
|
176
|
+
"lanes are left without a parent. Do not watch them yourself: the `run:wake` supervisor's driver " +
|
|
177
|
+
'watches the lanes and wakes a session only for a branch that needs judging. Hand the loop back with ' +
|
|
178
|
+
'`pnpm josh run:carry --cut --owner "$PPID"` (or `--end` when the run is over), then end the turn ' +
|
|
179
|
+
'(`backlogrun-progress.md` → "Picking the lanes up in the fresh session").'
|
|
179
180
|
|
|
180
181
|
const HEADLESS_WAIT_REASON = `${HEADLESS_WAIT_MARKER}${HEADLESS_WAIT_BODY}`
|
|
181
182
|
|
|
@@ -263,13 +264,23 @@ function citation_reason(context: StopContext): string | undefined {
|
|
|
263
264
|
return build_citation_reason(references)
|
|
264
265
|
}
|
|
265
266
|
|
|
267
|
+
// The two rules on how a reply is written. **A headless agent's reply has no reader**
|
|
268
|
+
// (joshuafolkken/kit#3245): its text lands in a stream-json log, so correcting its citations or its
|
|
269
|
+
// language costs a turn and reaches nobody. The artifacts a person does read — a Telegram, an Issue, a
|
|
270
|
+
// pull request — are held to the same rules by their own guards, not here.
|
|
271
|
+
function wording_reason(context: StopContext): string | undefined {
|
|
272
|
+
if (context.headless_agent) return undefined
|
|
273
|
+
|
|
274
|
+
return citation_reason(context) ?? language_reason(context)
|
|
275
|
+
}
|
|
276
|
+
|
|
266
277
|
// The three rules that read the reply itself, filing offer first and the language last. A drifted reply
|
|
267
278
|
// refused for another reason is not rewritten, but the drift still ends: `block_envelope` appends the
|
|
268
279
|
// session-language note to every refusal, so the turn it continues is written in the session language.
|
|
269
280
|
function reply_reason(context: StopContext): string | undefined {
|
|
270
281
|
if (needs_filing(context)) return FILING_OFFER_REASON
|
|
271
282
|
|
|
272
|
-
return
|
|
283
|
+
return wording_reason(context)
|
|
273
284
|
}
|
|
274
285
|
|
|
275
286
|
// The headless wait holds past the loop-breaker until the spin bound is reached.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { test_declared_changed } from '#scripts/test/test-declared-changed'
|
|
2
2
|
import type { GuardedCall } from '#scripts/time-runtime/time-batch-guard'
|
|
3
|
-
import {
|
|
3
|
+
import { run_tail_rule } from './run-tail-rule'
|
|
4
4
|
|
|
5
5
|
// The trigger and the delivered text behind the `test-declared` row of `delivered-rules.ts`
|
|
6
|
-
// (joshuafolkken/kit#2118). It lives beside `run-tail.ts` and the other per-rule modules rather than
|
|
6
|
+
// (joshuafolkken/kit#2118). It lives beside `run-tail-rule.ts` and the other per-rule modules rather than
|
|
7
7
|
// inline in the enumeration, so the enumeration stays a list of rows.
|
|
8
8
|
//
|
|
9
9
|
// **A commit whose code change carries no test, refused at the commit stage `run-tail` already
|
|
@@ -11,7 +11,7 @@ import { run_tail } from './run-tail'
|
|
|
11
11
|
// the input is mechanical — the changed paths, the test-file spelling, the exempt-path enumeration —
|
|
12
12
|
// so it is a delivered rule rather than resident prose.
|
|
13
13
|
//
|
|
14
|
-
// **No new delivery path.** The command half is `
|
|
14
|
+
// **No new delivery path.** The command half is `run_tail_rule.is_push_step_call`, reused verbatim, and the
|
|
15
15
|
// only thing added is the world-read: the working-tree verdict `pnpm josh test:declared` prints. Like
|
|
16
16
|
// `pre-gate-cut`, the command test comes first and the git read second, so an ordinary `Bash` call
|
|
17
17
|
// pays nothing and only a `pnpm josh git -y` spawns `git status`.
|
|
@@ -23,7 +23,7 @@ import { run_tail } from './run-tail'
|
|
|
23
23
|
// commit; refusing once and passing the reissue is the same safe direction `issue-comments` takes, and
|
|
24
24
|
// a compliant reissue that adds a test flips the verdict to `satisfied` and stops matching anyway.
|
|
25
25
|
function is_untested_commit(call: GuardedCall): boolean {
|
|
26
|
-
if (!
|
|
26
|
+
if (!run_tail_rule.is_push_step_call(call)) return false
|
|
27
27
|
|
|
28
28
|
return test_declared_changed.current_verdict() === 'required'
|
|
29
29
|
}
|
|
@@ -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
|