@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
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
|
|
37
37
|
## 実装中の独立編集に効く合成コマンド(joshuafolkken/kit#2202)
|
|
38
38
|
|
|
39
|
-
レーン子ではガードが `off` なので、`Read` → `Edit` の交互の並びは誰にも止められない。**Step 0 が対象ファイルを列挙した時点で、`pnpm josh read:files <path> …` で読み取りを 1 回に畳み、続く別ファイルへの編集を 1 ターンに載せる**(`report-format.md` が導く)。書き込みは `pnpm josh edit:files` で畳む(joshuafolkken/kit#2366) — プランを 1 呼び出しで適用し、`old` が 1 箇所に一致しなければ拒否する。形式は `docs/josh-commands-
|
|
39
|
+
レーン子ではガードが `off` なので、`Read` → `Edit` の交互の並びは誰にも止められない。**Step 0 が対象ファイルを列挙した時点で、`pnpm josh read:files <path> …` で読み取りを 1 回に畳み、続く別ファイルへの編集を 1 ターンに載せる**(`report-format.md` が導く)。書き込みは `pnpm josh edit:files` で畳む(joshuafolkken/kit#2366) — プランを 1 呼び出しで適用し、`old` が 1 箇所に一致しなければ拒否する。形式は `docs/josh-commands-run.md` →「`josh read:files`」と「`josh edit:files`」、経緯は `docs/maintainers/turn-batching-rationale.md` → "The composite commands"。
|
|
40
40
|
|
|
41
41
|
## ガード発火時にも合成コマンドを手渡す(joshuafolkken/kit#2311)
|
|
42
42
|
|
|
@@ -9,13 +9,23 @@
|
|
|
9
9
|
- **トリガーは「発見」であって「ブロックし始めたとき」ではない**
|
|
10
10
|
- **起票は Tier A(確認なし)**。起票してよいか、どのリポジトリへ起票するか、いずれもユーザー確認を取らない。対象は first-party に限る(→「第三者リポジトリへの書き込みは Tier C(明示指示が必要)」)
|
|
11
11
|
- **停止は無条件**。Issue が存在する状態にしてから停止する。上流の修正を待つか先送りするかは、Issue を目の前にしたユーザーが決める
|
|
12
|
-
- **`backlogrun` の中では、停止の範囲がセッション全体ではなくその子 Issue
|
|
12
|
+
- **`backlogrun` の中では、停止の範囲がセッション全体ではなくその子 Issue に限定される**。起票と回避策の禁止は変わらない。上流の修正を待つか先送りするかは人の判断なので、該当の子に `needs-decision` を付けて park し、依存していない他の子へ進む(→ `.claude/skills/workflow-commands/backlogrun-park.md` → "Only a person's judgement carries `needs-decision`")
|
|
13
|
+
|
|
14
|
+
### 実行中のリポジトリ自身のラン機構の不具合
|
|
15
|
+
|
|
16
|
+
**この手順の対象は別パッケージであり、実行中のリポジトリ自身は含まない。** kit の中で kit のラン機構(`backlog:drive`、`run:wake`、`run:carry`、レーン、分類、カウンタ、ガードなど)の不具合を見つけた場合、それは上流の欠陥ではなく**このリポジトリの割り込み**である。上流 Issue を立てて停止する代わりに、次の手順を取る。この節がその単一ソースである。
|
|
17
|
+
|
|
18
|
+
1. **起票する** — `pnpm josh issue:file "<title>" --body-file <path> --depth <n> --route interrupt --label priority:high`。上限は効かない(`wip-cap.md` →「割り込み起票 — 上限が効かない側」の条件 2)
|
|
19
|
+
2. **止まらずに直す** — 壊れた機構を迂回しない(回避策の禁止と、検証ゲートを緩めない規則はここでも変わらない)。`backlogrun` の中では、その割り込みを次の子にし、修正が着地してから塞がれていた子へ戻る。プールから選ぶランでは `priority:high` が先頭に並べ、epic の下では `wip-cap.md` の手順 3 で挿入する。名前を指定したランのドライバーは指定された Issue しか出さないので、`pnpm josh lane:launch <N>` で自分で dispatch する。バッチの外では `wip-cap.md` の手順 4 が変わらず効く — 起票まで済ませ、打つべき `fullrun #<N>` を報告して止まる
|
|
20
|
+
3. **再開できるなら自分で再開し、動くことを確かめる** — 修正のマージ後、再開の手段がある答えには人の打ち直しを求めない。手渡し済みの記録、所有者が死んだ記録、監督プロセスの停止(`warning` Telegram)には `pnpm josh run:wake --start`、`run:carry` の `standing` には `pnpm josh run:carry --resume "<invocation>" --owner "$PPID"` を自分で打つ。そのあと `pnpm josh run:wake --list` が監督プロセスを示し、そのログに次の子の dispatch が現れることを確かめて報告する
|
|
21
|
+
4. **人に打ち直しを求めるのは再開の手段が無いときだけ** — `expired`(8 時間の上限を使い切った)、`mismatch`(別の起動の記録)、別の生きた所有者の `busy`。新しい承認を宣言するのは人だけ、という規則も変わらない
|
|
22
|
+
5. **`needs-decision` を付けない** — ランが自分で直せる不具合は人の判断を要さない(`.claude/skills/workflow-commands/backlogrun-park.md` → "Only a person's judgement carries `needs-decision`")
|
|
13
23
|
|
|
14
24
|
手順:
|
|
15
25
|
|
|
16
26
|
1. **現在の作業を退避する**: `git stash push -u -m "upstream-interrupt: paused #<N>"`(WIP コミットでも可)。退避したことを忘れないよう、この時点で stash を作る。メッセージ付きで積むのは、復元をメッセージで特定するため(下記ステップ 5)
|
|
17
27
|
2. **進行中の Issue に状況を明記する**: `pnpm josh issue:comment <N> --body-file <path>` で、(a) 作業を stash したこと、(b) 中断理由(どの別パッケージの・どんな問題で中断したか)、(c) 対象パッケージに作成した新 Issue へのリンクを `## Upstream issues` 見出しの下に `owner/repo#N` 形式で、を記載する。これにより「なぜこの Issue が一時停止しているか」と「何を待っているのか」が後から監査できる(→「起票元へのバックリンク」)
|
|
18
|
-
3. **対象パッケージのリポジトリに新しい Issue を作成する(確認なし)**: `pnpm josh issue:file "<root-cause title>" --body-file <body-file> --depth <n> --route tier-a --repo <owner>/<repo>`(`route:tier-a` は実装中の Tier A 起票を経路として集計するためのラベル — joshuafolkken/kit#1083)。本文の検査、本文が宣言する分類ラベルの付与、`## Origin` 節の確認、起票先での重複探し、`epic:bundle` はこのコマンドが実行する(`docs/josh-commands-
|
|
28
|
+
3. **対象パッケージのリポジトリに新しい Issue を作成する(確認なし)**: `pnpm josh issue:file "<root-cause title>" --body-file <body-file> --depth <n> --route tier-a --repo <owner>/<repo>`(`route:tier-a` は実装中の Tier A 起票を経路として集計するためのラベル — joshuafolkken/kit#1083)。本文の検査、本文が宣言する分類ラベルの付与、`## Origin` 節の確認、起票先での重複探し、`epic:bundle` はこのコマンドが実行する(`docs/josh-commands-backlog.md` → `josh issue:file`)。分類の単一ソースは `prompts/collaboration-workflow/issue-template.md`。根本原因・再現・期待結果を Step 1 のテンプレに沿って記載し、**本文に `## Origin` 節を置いて起票元 Issue を `owner/repo#N` 形式で書く**(→「起票元へのバックリンク」)。ここで「起票してよいか」を尋ねて停止してはならない
|
|
19
29
|
4. **`confirmation` Telegram を送って停止する**: 上流 Issue の URL と、何が止まっているかを本文に書く(→ `CLAUDE.md` → "Mid-workflow stop notification (`confirmation`)")。無人実行でも画面外でユーザーが気付ける。停止は Issue が既に存在する状態で行うので、ユーザーは「待つ / 先送りする」を Issue を見ながら 1 語で答えられる
|
|
20
30
|
5. **元の作業を再開する**: 上流の修正がマージされた、または**ユーザーが先送りを明示判断した**後に `pnpm josh stash:pop "upstream-interrupt: paused #<N>"`(位置指定や引数なしの `git stash pop` は使わない — stash は全 work tree が共有する 1 本のスタックで、別のレーンの stash を取り込む恐れがある)して、退避していた元タスクを続行する。上流 Issue を割り込みで実装するかどうかもユーザーの判断(上流パッケージの実装・PR・マージはそれぞれのワークフロー規則に従う)
|
|
21
31
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**単一ソースはこのファイルである。**
|
|
4
4
|
|
|
5
|
-
**この規則は常駐していない — 引き金つき配送に移った**(joshuafolkken/kit#1524)。`pnpm josh rule:guard` が Issue を作成する `Bash` 呼び出し(`pnpm josh issue:file`。`gh issue create` や `…/issues` への `title` 付き POST による直接起票は `direct-filing` が毎回拒否する)を拒否し、そこで数え方・拒否・2 つの免除・免除を決める 3 条件を突きつける。起票が無いターンでは何も起きず、それは上限に触れる行為が無いということである。配送は**ラン 1 回につき 1 度**なので、数えたうえで同じ呼び出しをもう一度出せばよい。機構と列挙表は `rule-delivery.md`、配送文の実体は `scripts/rules/
|
|
5
|
+
**この規則は常駐していない — 引き金つき配送に移った**(joshuafolkken/kit#1524)。`pnpm josh rule:guard` が Issue を作成する `Bash` 呼び出し(`pnpm josh issue:file`。`gh issue create` や `…/issues` への `title` 付き POST による直接起票は `direct-filing` が毎回拒否する)を拒否し、そこで数え方・拒否・2 つの免除・免除を決める 3 条件を突きつける。起票が無いターンでは何も起きず、それは上限に触れる行為が無いということである。配送は**ラン 1 回につき 1 度**なので、数えたうえで同じ呼び出しをもう一度出せばよい。機構と列挙表は `rule-delivery.md`、配送文の実体は `scripts/rules/wip-cap.ts` の `WIP_CAP_REASON` にある(固定するテストは `docs/maintainers/wip-cap-rationale.md` → "Tests that pin the wording")。
|
|
6
6
|
|
|
7
7
|
背景・測定・経緯は保守者向けの `docs/maintainers/wip-cap-rationale.md` にあり、ラン中に読む必要はない。
|
|
8
8
|
|
|
@@ -10,15 +10,15 @@
|
|
|
10
10
|
|
|
11
11
|
**オープン Issue が上限を超えている状態で新しく起票するときは、先に 1 件閉じる。**
|
|
12
12
|
|
|
13
|
-
**件数は `pnpm josh issue:file` が起票の前に数える**(joshuafolkken/kit#3181)。手で数えることも、見積もりや記憶で済ませることもない。数え方・印字・保留の詳細は `docs/josh-commands-
|
|
13
|
+
**件数は `pnpm josh issue:file` が起票の前に数える**(joshuafolkken/kit#3181)。手で数えることも、見積もりや記憶で済ませることもない。数え方・印字・保留の詳細は `docs/josh-commands-backlog.md` → "`josh issue:file`" にある。
|
|
14
14
|
|
|
15
|
-
- **上限は 30。** これを超える 1 件を作る前に 1 件閉じる。エージェントが読む文書(`CLAUDE.md`・`prompts/`・配布 skill)がこの数字を書くのはこの行だけで、一次情報は `scripts/rules/
|
|
15
|
+
- **上限は 30。** これを超える 1 件を作る前に 1 件閉じる。エージェントが読む文書(`CLAUDE.md`・`prompts/`・配布 skill)がこの数字を書くのはこの行だけで、一次情報は `scripts/rules/wip-cap.ts` の `WIP_CAP` である(一致はテストが固定する)。
|
|
16
16
|
- コマンドは起票先(`--repo` を付ければそのリポジトリ)のオープン Issue を epic も含めて数え、`wip:` 行に件数・上限・判定を印字する。上限を超えて免除が宣言されていなければ**何も送らずに保留し、免除の問いを印字する**。
|
|
17
17
|
- **免除を宣言するのはこのファイルの判断である** — `--route interrupt`(下の 3 条件)、`--route split` / `--route tier-a`(実行が詰まる起票)はルートそのものが宣言になる。ルートの無い実行が詰まる起票(利用者が `new` と打った入口など)は `--over-cap` を付けて出し直す。裁量起票(`--route review-cap` を含む)に `--over-cap` を付けてはならない。
|
|
18
18
|
|
|
19
19
|
## なぜ上限が要るのか
|
|
20
20
|
|
|
21
|
-
測定は `docs/maintainers/wip-cap-rationale.md`
|
|
21
|
+
測定は `docs/maintainers/wip-cap-rationale.md` → "Why a cap is needed — the measurement"。
|
|
22
22
|
|
|
23
23
|
**上限は、増加を見えるようにするための強制装置である。** 数を減らすこと自体が目的ではない。上限を超えた状態で起票しようとしたときに「本当にこれは 1 件増やす価値があるか」を必ず 1 回考えさせる、そこだけが役割である。
|
|
24
24
|
|
|
@@ -40,13 +40,13 @@
|
|
|
40
40
|
|
|
41
41
|
前提 Issue(`prerequisite.md`)、別パッケージ起因の割り込み Issue、ユーザーが `new` と打った入口、`issue:scout` が重複無しと答えた新規作業、**そして分割判定が作る子 Issue と epic**。**これらは起票しないと実行が進まない。**
|
|
42
42
|
|
|
43
|
-
- **上限を理由に止めない。** 理由は `docs/maintainers/wip-cap-rationale.md`
|
|
43
|
+
- **上限を理由に止めない。** 理由は `docs/maintainers/wip-cap-rationale.md` → "Why a filing a run is blocked by is not stopped"。
|
|
44
44
|
- **分割の子がここに入る理由**: 分割を検出した `fullrun` / `halfrun` は「子と epic を起票して **STOP**」と定められている(`fullrun.md` / `halfrun.md`)。**分割するかどうかを決めるのは分割判定の側**で、既定はもう「分割しない」に上がっている — 上限が二重に効く必要はない。
|
|
45
45
|
- **超過した事実は完了報告に 1 行書く**(例: 「オープン 34 件で起票した」)。上限は可視化のための装置なので、超えたことが見えていれば役割は果たしている。
|
|
46
46
|
|
|
47
47
|
### 割り込み起票 — 上限が効かない側(3 条件で機械的に決める)
|
|
48
48
|
|
|
49
|
-
**重大な欠陥の発見は、それが現在のランを止めていなくても捨ててはならない。** 上限の目的は増加を見えるようにすることであって、**発見を捨てることではない**(上の「なぜ上限が要るのか」)。由来は `docs/maintainers/wip-cap-rationale.md`
|
|
49
|
+
**重大な欠陥の発見は、それが現在のランを止めていなくても捨ててはならない。** 上限の目的は増加を見えるようにすることであって、**発見を捨てることではない**(上の「なぜ上限が要るのか」)。由来は `docs/maintainers/wip-cap-rationale.md` → "Where the interrupt category comes from"。
|
|
50
50
|
|
|
51
51
|
**別パッケージ起因の割り込みとは別の区分である。** あちらは上流リポジトリへ起票して停止する手順(`upstream-interrupt.md`、`route:tier-a`)で、実行が詰まる側に属する。ここで言う割り込みは、**このリポジトリの欠陥で、発見したランをブロックしていないもの**を指す。
|
|
52
52
|
|
|
@@ -60,20 +60,20 @@
|
|
|
60
60
|
|
|
61
61
|
**3 つのいずれにも当たらない発見は、従来どおり裁量側の出口を取る。** 改善案、設計上の好み、未検証の疑い、「あとで直したい」はここに入らない — レビュー指摘なら branch 3(PR 本文に 1 行残して落とす)であり、それは既定の出口であって上限に阻まれたときの代替ではない。
|
|
62
62
|
|
|
63
|
-
**深刻さの自己申告は条件ではない。** 理由は `docs/maintainers/wip-cap-rationale.md`
|
|
63
|
+
**深刻さの自己申告は条件ではない。** 理由は `docs/maintainers/wip-cap-rationale.md` → "Why self-reported severity is not a condition"。
|
|
64
64
|
|
|
65
65
|
#### 該当したときの手順
|
|
66
66
|
|
|
67
|
-
1. **上限に関係なく起票する。** 1 件閉じることを条件にしない。起票は `pnpm josh issue:file` で行う。本文の検査、本文が宣言する分類ラベルの付与、重複探し、`epic:bundle` はこのコマンドが実行する(`docs/josh-commands-
|
|
67
|
+
1. **上限に関係なく起票する。** 1 件閉じることを条件にしない。起票は `pnpm josh issue:file` で行う。本文の検査、本文が宣言する分類ラベルの付与、重複探し、`epic:bundle` はこのコマンドが実行する(`docs/josh-commands-backlog.md` → `josh issue:file`)。
|
|
68
68
|
|
|
69
69
|
```bash
|
|
70
70
|
pnpm josh issue:file "<title>" --body-file <body-file> --depth <n> --route interrupt
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
2. **超過している事実と、当たった条件の番号を本文に 1 行書く**(例:「オープン 37 件で起票。3 条件のうち 2(文書化された手順が完了できない)に該当」)。**どちらか一方では足りない** — 件数だけでは判定が再現できず、条件だけでは上限の可視化が効かない。
|
|
74
|
-
3. **次に実行されるものとして挿入する。** epic の下にあるなら `pnpm josh epic --add <E> <N>` で、**位置を指定せずに**追加する(`<E>` が epic、`<N>` が起票した割り込み)。**`--before` / `--after` を使ってはならない。** それらは `blocked-by` を書き込み、「発見したランをブロックしていない欠陥」という割り込みの定義と矛盾する**偽の依存関係**になる。**順序は実行側が持つ** — 先に提示させたいときは、行だけを動かす `--order-before <M>` を使う。仕組みと経緯は `docs/maintainers/wip-cap-rationale.md`
|
|
74
|
+
3. **次に実行されるものとして挿入する。** epic の下にあるなら `pnpm josh epic --add <E> <N>` で、**位置を指定せずに**追加する(`<E>` が epic、`<N>` が起票した割り込み)。**`--before` / `--after` を使ってはならない。** それらは `blocked-by` を書き込み、「発見したランをブロックしていない欠陥」という割り込みの定義と矛盾する**偽の依存関係**になる。**順序は実行側が持つ** — 先に提示させたいときは、行だけを動かす `--order-before <M>` を使う。仕組みと経緯は `docs/maintainers/wip-cap-rationale.md` → "Why an addition names no position"。**epic の下に無いなら挿入先そのものが無い**ので、この手順は飛ばして 4 だけを行う。
|
|
75
75
|
4. **着手は、既にある承認の内側でのみ、指示を待たずに行う。** `backlogrun` の中なら、打たれたキーワードがバッチを承認しているので、割り込みは次の子として着手してよい。**バッチの外では `CLAUDE.md` →「Explicit invocation required」が変わらず効く** — 起票と挿入まで済ませたうえで、利用者に打つべきコマンド(`fullrun #<N>`)を報告して止まる。**割り込みは上限の例外であって、明示起動規則の例外ではない。**
|
|
76
76
|
|
|
77
77
|
**起票と、実行されるようにするところまでが 1 つのまとまりである。** epic の下にある割り込みを起票だけして追加しなければ、`epic:next` はそれを候補にすら出さない — Issue は残るが実行されないという、コメントに埋もれるのと大差ない状態になる。**epic の外にある割り込みでは、まとまりの後半は 4 の報告そのもの**であり、打つべきコマンドを利用者に渡すまでが 1 回の行為である。上の「ひとまとまりで判定する」がここにも効く。
|
|
78
78
|
|
|
79
|
-
**割り込みをバッチの中で単独で走らせるか、並列のレーンで走らせるか**は `.claude/skills/workflow-commands/backlogrun-lanes.md` → "Lanes — running more than one child at a time" が単一ソースである(理由は `docs/maintainers/wip-cap-rationale.md`
|
|
79
|
+
**割り込みをバッチの中で単独で走らせるか、並列のレーンで走らせるか**は `.claude/skills/workflow-commands/backlogrun-lanes.md` → "Lanes — running more than one child at a time" が単一ソースである(理由は `docs/maintainers/wip-cap-rationale.md` → "Why a solo run")。上限の数字の変え方は `docs/maintainers/wip-cap-rationale.md` → "Changing the cap itself"、上限が分割判定・レビュー上限と一緒に動く理由は `docs/maintainers/wip-cap-rationale.md` → "The three move together"と `docs/maintainers/wip-cap-rationale.md` → "Why the three landed in one commit"にある。
|
package/prompts/review-rubric.md
CHANGED
|
@@ -212,8 +212,7 @@ allowed.
|
|
|
212
212
|
|
|
213
213
|
### 4. Project conventions (`CLAUDE.md`)
|
|
214
214
|
|
|
215
|
-
**Do not re-check what lint enforces — the gate has already run; lint does not catch
|
|
216
|
-
syntax over an arrow const (outside named route handlers), the early-return one-liner, duplication
|
|
215
|
+
**Do not re-check what lint enforces — the gate has already run; lint does not catch duplication
|
|
217
216
|
that is not identical, a name whose shape passes but whose meaning misleads, grouping and file layout,
|
|
218
217
|
Svelte semantics, or test placement beyond the `*.spec.*` / top-level `tests/` bans, so check those.**
|
|
219
218
|
A lint gap the change opens — a disabled rule, an ignored path, an added `eslint-disable`, a block
|
package/prompts/review.md
CHANGED
|
@@ -167,7 +167,7 @@ Only branch 2 files an Issue. What follows applies to that branch.
|
|
|
167
167
|
1. File the follow-up Issue referencing the current one, tagged `route:review-cap` — **before the current Issue closes.**
|
|
168
168
|
`pnpm josh issue:file "<title>" --body-file <body-file> --depth <n> --route review-cap`.
|
|
169
169
|
The command lints the body, applies the classification labels it declares, runs the duplicate scan
|
|
170
|
-
and then `epic:bundle` on the new Issue (`docs/josh-commands-
|
|
170
|
+
and then `epic:bundle` on the new Issue (`docs/josh-commands-backlog.md` → `josh issue:file`). The
|
|
171
171
|
`epic:bundle` candidate search reads open issues only, so once the parent has closed it answers
|
|
172
172
|
`none` permanently.
|
|
173
173
|
2. Act on the `epic:bundle` answer it prints. **`epic:bundle` recommends and writes nothing**, so acting means running the
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// The mark every agent session kit launches itself carries — a lane child, a ship reviewer, a woken
|
|
2
|
+
// `run:wake` session (joshuafolkken/kit#3245).
|
|
3
|
+
//
|
|
4
|
+
// **Those sessions run under `claude -p`, and nobody reads their replies.** Their output goes to a
|
|
5
|
+
// stream-json log, and the only reader of the final text is the exit record's failure reason. So the
|
|
6
|
+
// stop rules that correct how a reply is written — the issue citation, the session language — refused
|
|
7
|
+
// replies no person would ever see, and each refusal cost a model turn: across one baseline run, 107
|
|
8
|
+
// of them in children and wake sessions.
|
|
9
|
+
//
|
|
10
|
+
// **It is set at the one place agent sessions are launched, never read from the prompt.** Every launch
|
|
11
|
+
// that passes an agent profile composes its environment in `agent_launch_environment.build`, so the
|
|
12
|
+
// mark is exactly "kit started this agent". A person's own session is never spawned there, so it never
|
|
13
|
+
// carries the mark; a process the headless session starts inherits it, and is headless too.
|
|
14
|
+
const KEY = 'JOSH_AGENT_HEADLESS'
|
|
15
|
+
const VALUE = '1'
|
|
16
|
+
|
|
17
|
+
type EnvironmentSource = Readonly<Record<string, string | undefined>>
|
|
18
|
+
|
|
19
|
+
function environment(): Record<string, string> {
|
|
20
|
+
return { [KEY]: VALUE }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function is_headless(source: EnvironmentSource = process.env): boolean {
|
|
24
|
+
return source[KEY] === VALUE
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const agent_headless = { KEY, environment, is_headless }
|
|
28
|
+
|
|
29
|
+
export { agent_headless }
|
|
@@ -2,6 +2,7 @@ import { existsSync, lstatSync, mkdirSync, readlinkSync, symlinkSync, unlinkSync
|
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
import { gh_cli_token } from '#scripts/gh/gh-cli-token'
|
|
4
4
|
import { PLATFORM_TEMP_ROOT } from '#scripts/josh/platform-temporary'
|
|
5
|
+
import { agent_headless } from './agent-headless'
|
|
5
6
|
import { agent_role_profile, type AgentProfile } from './agent-role-profile'
|
|
6
7
|
import { codex_home_source } from './codex-home-source'
|
|
7
8
|
|
|
@@ -57,9 +58,12 @@ function build(
|
|
|
57
58
|
profile: AgentProfile | undefined,
|
|
58
59
|
environment: LaunchEnvironment = {},
|
|
59
60
|
): LaunchEnvironment {
|
|
60
|
-
if (profile
|
|
61
|
+
if (profile === undefined) return environment
|
|
61
62
|
|
|
62
|
-
const
|
|
63
|
+
const marked = { ...agent_headless.environment(), ...environment }
|
|
64
|
+
if (profile.provider !== OPENAI_PROVIDER) return marked
|
|
65
|
+
|
|
66
|
+
const base = { ...openai_environment(), ...marked }
|
|
63
67
|
|
|
64
68
|
return profile.role === agent_role_profile.REVIEWER
|
|
65
69
|
? { ...base, CODEX_HOME: reviewer_home(cwd, environment) }
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { lstatSync, mkdirSync } from 'node:fs'
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
import { git_common_directory } from '#scripts/git/git-common-directory'
|
|
4
|
+
import { OBSERVATION_LEDGER_DIRECTORY } from '#scripts/observations/observation-ledger'
|
|
4
5
|
import { agent_role_profile, type AgentProfile } from './agent-role-profile'
|
|
5
6
|
|
|
6
7
|
const AGENT_COMMAND = 'codex'
|
|
@@ -13,7 +14,7 @@ const SQLITE_CACHE_PATH = ['node_modules', '.cache', 'josh', 'openai']
|
|
|
13
14
|
const EPHEMERAL_FLAG = '--ephemeral'
|
|
14
15
|
const ADD_DIRECTORY_FLAG = '--add-dir'
|
|
15
16
|
const GIT_DIRECTORY = '.git'
|
|
16
|
-
const LEDGER_DIRECTORY =
|
|
17
|
+
const LEDGER_DIRECTORY = path.dirname(OBSERVATION_LEDGER_DIRECTORY)
|
|
17
18
|
|
|
18
19
|
interface CodexArgv {
|
|
19
20
|
command: string
|
|
@@ -5,9 +5,9 @@ import { epic_index, type FetchedEpics } from '#scripts/epic/epic-index'
|
|
|
5
5
|
import { epic_issue } from '#scripts/epic/epic-issue'
|
|
6
6
|
import { git_gh_command } from '#scripts/gh/git-gh-command'
|
|
7
7
|
import { SUMMARY_FIELDS } from '#scripts/gh/git-gh-issue'
|
|
8
|
+
import { open_issue_schema, type OpenIssueData } from '#scripts/git/git-schemas'
|
|
8
9
|
import { cutoff_cause, cutoff_of, type ScanCutoff } from '#scripts/git/listing-cutoff'
|
|
9
10
|
import { read_json_listing } from '#scripts/git/parse-json-array'
|
|
10
|
-
import { open_issue_schema, type OpenIssueData } from '#scripts/git/schemas'
|
|
11
11
|
import { git_next_issues } from '#scripts/issue/git-next-issues'
|
|
12
12
|
import { AUTO_OK_LABEL } from '#scripts/issue/issue-labels'
|
|
13
13
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { epic_triage } from '#scripts/epic/epic-triage'
|
|
2
2
|
import type { JoshResult } from '#scripts/josh/josh-run'
|
|
3
|
+
import { COMMAND_TIMEOUT_MS } from '#scripts/lib/timeouts'
|
|
3
4
|
import { run_headless } from '#scripts/run/run-headless'
|
|
4
5
|
import { backlog_next } from './backlog-next'
|
|
5
6
|
import { backlog_ready, type ReadyPorts, type ReadyReading } from './backlog-ready'
|
|
@@ -26,14 +27,13 @@ import { backlog_stalled } from './backlog-stalled'
|
|
|
26
27
|
//
|
|
27
28
|
// **Every read is bounded.** The probe is awaited inside the watcher's tick loop, so a `gh` call that
|
|
28
29
|
// hangs would otherwise freeze the loop — its `--hours` bound, its liveness ping and the exit that is
|
|
29
|
-
// the parent's wake. A read past `
|
|
30
|
+
// the parent's wake. A read past `COMMAND_TIMEOUT_MS` is killed and counts as a failed read.
|
|
30
31
|
//
|
|
31
32
|
// **And strict.** `backlog:next` exits 0 on a `retry` (a transport failure) or an `error` verdict, which
|
|
32
33
|
// the lenient pick-up read takes as an empty pool — here that empty baseline is the whole-pool wake the
|
|
33
34
|
// paragraph above rules out, so either verdict, like a non-zero exit, is a read that did not answer.
|
|
34
35
|
|
|
35
36
|
const PROBE_INTERVAL_MS = 60_000
|
|
36
|
-
const READ_TIMEOUT_MS = 30_000
|
|
37
37
|
const SUCCESS_EXIT_CODE = 0
|
|
38
38
|
const NO_FREE = 0
|
|
39
39
|
const NONE = 0
|
|
@@ -61,7 +61,7 @@ function answered_issues(result: JoshResult | undefined): ReadonlyArray<string>
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
async function bounded_ready_issues(): Promise<ReadonlyArray<string>> {
|
|
64
|
-
return answered_issues(await backlog_ready.read_backlog_next(
|
|
64
|
+
return answered_issues(await backlog_ready.read_backlog_next(COMMAND_TIMEOUT_MS))
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
const ARRIVAL_PORTS: ReadyPorts = {
|
|
@@ -59,7 +59,7 @@ type BudgetVerdict =
|
|
|
59
59
|
typeof RUN_VERDICT | typeof WATCH_VERDICT | typeof STOP_VERDICT | typeof TRIAGE_VERDICT
|
|
60
60
|
|
|
61
61
|
// What `backlog:next` answered, in the words this decision needs. The mapping is mechanical and is
|
|
62
|
-
// written once, in `docs/josh-commands-
|
|
62
|
+
// written once, in `docs/josh-commands-backlog.md` → "`josh backlog:offer`": numbers are `candidates`, `wait` is `blocked` while
|
|
63
63
|
// this run has children in flight and `exhausted` when it does not, `none` is `exhausted`, `stop` is
|
|
64
64
|
// `parked`, `triage` is `untriaged`, and `error` or a failed listing is `unreadable`.
|
|
65
65
|
const ANSWERS = ['blocked', 'candidates', 'exhausted', 'parked', 'unreadable', 'untriaged'] as const
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { cli_flags } from '#scripts/lib/cli-flags'
|
|
2
|
+
import type { DriveState } from './backlog-drive'
|
|
3
|
+
|
|
4
|
+
// The `josh backlog:drive` flags — read into a `DriveContext`, and written back as the `resume:` line —
|
|
5
|
+
// split out of `backlog-drive-cli.ts` when it neared its line limit (joshuafolkken/kit#3264).
|
|
6
|
+
// `backlog_drive_cli` re-exports `parse` and `resume_line` under the names they always had, so the move
|
|
7
|
+
// changed no call site and no suite that reads them through `backlog_drive_cli`.
|
|
8
|
+
|
|
9
|
+
const MS_PER_MINUTE = 60_000
|
|
10
|
+
const LIST_SEPARATOR = ','
|
|
11
|
+
const COUNT_PATTERN = /^\d+$/u
|
|
12
|
+
const ISSUE_PATTERN = /^[1-9]\d*$/u
|
|
13
|
+
const USAGE =
|
|
14
|
+
'Usage: josh backlog:drive --owner <pid> [--active <ISO-8601>] [--max <n>] [--idle <minutes>] [--only] [--exclude <n>[,<n>...]] [--await <n>[,<n>...]] [--window <minutes>] [--stopped <n>]'
|
|
15
|
+
|
|
16
|
+
const OPTIONS = {
|
|
17
|
+
active: { type: 'string' },
|
|
18
|
+
await: { type: 'string' },
|
|
19
|
+
exclude: { type: 'string' },
|
|
20
|
+
idle: { type: 'string' },
|
|
21
|
+
max: { type: 'string' },
|
|
22
|
+
only: { type: 'boolean' },
|
|
23
|
+
owner: { type: 'string' },
|
|
24
|
+
stopped: { type: 'string' },
|
|
25
|
+
window: { type: 'string' },
|
|
26
|
+
} as const
|
|
27
|
+
|
|
28
|
+
interface DriveContext {
|
|
29
|
+
owner: string
|
|
30
|
+
active: string | undefined
|
|
31
|
+
// Flags forwarded to `backlog:offer` unchanged — the declared budgets.
|
|
32
|
+
forwarded: ReadonlyArray<string>
|
|
33
|
+
exclude: ReadonlyArray<string>
|
|
34
|
+
awaited: ReadonlyArray<string>
|
|
35
|
+
window_ms: number | undefined
|
|
36
|
+
window: string | undefined
|
|
37
|
+
is_only: boolean
|
|
38
|
+
// The child whose merge answered `stop` before the hand-back: the resumed run starts already stopping.
|
|
39
|
+
stopped: string | undefined
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
type Values = Partial<Record<Exclude<keyof typeof OPTIONS, 'only'>, string>> & { only?: boolean }
|
|
43
|
+
|
|
44
|
+
function read_values(argv: ReadonlyArray<string>): Values | undefined {
|
|
45
|
+
return cli_flags.parse_or_undefined({ args: [...argv], options: OPTIONS, strict: true })?.values
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// A comma list of issue numbers; one entry that is not an issue number refuses the whole list.
|
|
49
|
+
function to_issues(raw: string | undefined): ReadonlyArray<string> | undefined {
|
|
50
|
+
if (raw === undefined) return []
|
|
51
|
+
|
|
52
|
+
const issues = raw.split(LIST_SEPARATOR)
|
|
53
|
+
|
|
54
|
+
return issues.some((issue) => !ISSUE_PATTERN.test(issue)) ? undefined : issues
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function forwarded_of(values: Values): ReadonlyArray<string> | undefined {
|
|
58
|
+
const pairs = (['max', 'idle'] as const).filter((name) => values[name] !== undefined)
|
|
59
|
+
|
|
60
|
+
if (pairs.some((name) => !COUNT_PATTERN.test(values[name] ?? ''))) return undefined
|
|
61
|
+
|
|
62
|
+
return pairs.flatMap((name) => [`--${name}`, values[name] ?? ''])
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// An absent window is no bound; a present one must be a count, which `is_valid_window` checks first.
|
|
66
|
+
function window_of(raw: string | undefined): number | undefined {
|
|
67
|
+
return raw === undefined ? undefined : Number(raw) * MS_PER_MINUTE
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function is_valid_window(raw: string | undefined): boolean {
|
|
71
|
+
return raw === undefined || COUNT_PATTERN.test(raw)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function is_valid_single(values: Values): boolean {
|
|
75
|
+
const is_valid_stopped = values.stopped === undefined || ISSUE_PATTERN.test(values.stopped)
|
|
76
|
+
|
|
77
|
+
return is_valid_stopped && is_valid_window(values.window)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function owner_of(values: Values | undefined): string | undefined {
|
|
81
|
+
const owner = values?.owner
|
|
82
|
+
|
|
83
|
+
return owner !== undefined && COUNT_PATTERN.test(owner) ? owner : undefined
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function to_context(values: Values, owner: string): DriveContext | undefined {
|
|
87
|
+
if (!is_valid_single(values)) return undefined
|
|
88
|
+
|
|
89
|
+
const forwarded = forwarded_of(values)
|
|
90
|
+
const exclude = to_issues(values.exclude)
|
|
91
|
+
const awaited = to_issues(values.await)
|
|
92
|
+
|
|
93
|
+
if (forwarded === undefined || exclude === undefined || awaited === undefined) return undefined
|
|
94
|
+
|
|
95
|
+
const window_ms = window_of(values.window)
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
owner,
|
|
99
|
+
active: values.active,
|
|
100
|
+
forwarded,
|
|
101
|
+
exclude,
|
|
102
|
+
awaited,
|
|
103
|
+
window_ms,
|
|
104
|
+
window: values.window,
|
|
105
|
+
is_only: values.only === true,
|
|
106
|
+
stopped: values.stopped,
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function parse(argv: ReadonlyArray<string>): DriveContext | undefined {
|
|
111
|
+
const values = read_values(argv)
|
|
112
|
+
const owner = owner_of(values)
|
|
113
|
+
|
|
114
|
+
return values === undefined || owner === undefined ? undefined : to_context(values, owner)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function resume_line(state: DriveState, context: DriveContext): string {
|
|
118
|
+
const exclude = [...new Set([...context.exclude, ...state.exclude])]
|
|
119
|
+
const flags = ['--owner', context.owner, '--active', state.active, ...context.forwarded]
|
|
120
|
+
|
|
121
|
+
if (exclude.length > 0) flags.push('--exclude', exclude.join(LIST_SEPARATOR))
|
|
122
|
+
if (context.window !== undefined) flags.push('--window', context.window)
|
|
123
|
+
if (state.stopped_by !== undefined) flags.push('--stopped', state.stopped_by)
|
|
124
|
+
|
|
125
|
+
return `resume: ${flags.join(' ')}`
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const backlog_drive_args = {
|
|
129
|
+
USAGE,
|
|
130
|
+
parse,
|
|
131
|
+
resume_line,
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export { backlog_drive_args }
|
|
135
|
+
export type { DriveContext }
|
|
@@ -4,13 +4,11 @@ import { fileURLToPath } from 'node:url'
|
|
|
4
4
|
import { hook_decision } from '#scripts/josh/hook-decision'
|
|
5
5
|
import { josh_command } from '#scripts/josh/josh-run'
|
|
6
6
|
import { lane_await, type AwaitState } from '#scripts/lane/lane-await'
|
|
7
|
-
import { lane_launch_cli, type LaunchOutcome } from '#scripts/lane/lane-launch-cli'
|
|
8
7
|
import { lane_registry } from '#scripts/lane/lane-registry'
|
|
9
|
-
import { cli_flags } from '#scripts/lib/cli-flags'
|
|
10
8
|
import { error_text } from '#scripts/lib/error-message'
|
|
11
|
-
import { run_carry, type RunCarry } from '#scripts/run/run-carry'
|
|
12
|
-
import { run_event_stream_emit } from '#scripts/run/run-event-stream-emit'
|
|
13
|
-
import { run_merge_cli, type MergeResult } from '#scripts/run/run-merge-cli'
|
|
9
|
+
import { run_carry, type RunCarry } from '#scripts/run/carry/run-carry'
|
|
10
|
+
import { run_event_stream_emit } from '#scripts/run/event/run-event-stream-emit'
|
|
11
|
+
import { run_merge_cli, type MergeResult } from '#scripts/run/merge/run-merge-cli'
|
|
14
12
|
import { z } from 'zod'
|
|
15
13
|
import {
|
|
16
14
|
backlog_drive,
|
|
@@ -19,7 +17,9 @@ import {
|
|
|
19
17
|
type LoopPorts,
|
|
20
18
|
type OfferRead,
|
|
21
19
|
} from './backlog-drive'
|
|
20
|
+
import { backlog_drive_args, type DriveContext } from './backlog-drive-args'
|
|
22
21
|
import { backlog_drive_finish } from './backlog-drive-finish'
|
|
22
|
+
import { backlog_drive_launch } from './backlog-drive-launch'
|
|
23
23
|
import { backlog_drive_named } from './backlog-drive-named'
|
|
24
24
|
import { backlog_drive_named_offer } from './backlog-drive-named-offer'
|
|
25
25
|
import { backlog_drive_offer_argv } from './backlog-drive-offer-argv'
|
|
@@ -44,114 +44,7 @@ const FAILURE_EXIT_CODE = 1
|
|
|
44
44
|
const should_forward_stderr = true
|
|
45
45
|
const POLL_MS = 5000
|
|
46
46
|
const OFFER_MS = 60_000
|
|
47
|
-
const MS_PER_MINUTE = 60_000
|
|
48
47
|
const FIRST_LINE = 0
|
|
49
|
-
const LIST_SEPARATOR = ','
|
|
50
|
-
const COUNT_PATTERN = /^\d+$/u
|
|
51
|
-
const ISSUE_PATTERN = /^[1-9]\d*$/u
|
|
52
|
-
const USAGE =
|
|
53
|
-
'Usage: josh backlog:drive --owner <pid> [--active <ISO-8601>] [--max <n>] [--idle <minutes>] [--only] [--exclude <n>[,<n>...]] [--await <n>[,<n>...]] [--window <minutes>] [--stopped <n>]'
|
|
54
|
-
|
|
55
|
-
const OPTIONS = {
|
|
56
|
-
active: { type: 'string' },
|
|
57
|
-
await: { type: 'string' },
|
|
58
|
-
exclude: { type: 'string' },
|
|
59
|
-
idle: { type: 'string' },
|
|
60
|
-
max: { type: 'string' },
|
|
61
|
-
only: { type: 'boolean' },
|
|
62
|
-
owner: { type: 'string' },
|
|
63
|
-
stopped: { type: 'string' },
|
|
64
|
-
window: { type: 'string' },
|
|
65
|
-
} as const
|
|
66
|
-
|
|
67
|
-
interface DriveContext {
|
|
68
|
-
owner: string
|
|
69
|
-
active: string | undefined
|
|
70
|
-
// Flags forwarded to `backlog:offer` unchanged — the declared budgets.
|
|
71
|
-
forwarded: ReadonlyArray<string>
|
|
72
|
-
exclude: ReadonlyArray<string>
|
|
73
|
-
awaited: ReadonlyArray<string>
|
|
74
|
-
window_ms: number | undefined
|
|
75
|
-
window: string | undefined
|
|
76
|
-
is_only: boolean
|
|
77
|
-
// The child whose merge answered `stop` before the hand-back: the resumed run starts already stopping.
|
|
78
|
-
stopped: string | undefined
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
type Values = Partial<Record<Exclude<keyof typeof OPTIONS, 'only'>, string>> & { only?: boolean }
|
|
82
|
-
|
|
83
|
-
function read_values(argv: ReadonlyArray<string>): Values | undefined {
|
|
84
|
-
return cli_flags.parse_or_undefined({ args: [...argv], options: OPTIONS, strict: true })?.values
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// A comma list of issue numbers; one entry that is not an issue number refuses the whole list.
|
|
88
|
-
function to_issues(raw: string | undefined): ReadonlyArray<string> | undefined {
|
|
89
|
-
if (raw === undefined) return []
|
|
90
|
-
|
|
91
|
-
const issues = raw.split(LIST_SEPARATOR)
|
|
92
|
-
|
|
93
|
-
return issues.some((issue) => !ISSUE_PATTERN.test(issue)) ? undefined : issues
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function forwarded_of(values: Values): ReadonlyArray<string> | undefined {
|
|
97
|
-
const pairs = (['max', 'idle'] as const).filter((name) => values[name] !== undefined)
|
|
98
|
-
|
|
99
|
-
if (pairs.some((name) => !COUNT_PATTERN.test(values[name] ?? ''))) return undefined
|
|
100
|
-
|
|
101
|
-
return pairs.flatMap((name) => [`--${name}`, values[name] ?? ''])
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// An absent window is no bound; a present one must be a count, which `is_valid_window` checks first.
|
|
105
|
-
function window_of(raw: string | undefined): number | undefined {
|
|
106
|
-
return raw === undefined ? undefined : Number(raw) * MS_PER_MINUTE
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function is_valid_window(raw: string | undefined): boolean {
|
|
110
|
-
return raw === undefined || COUNT_PATTERN.test(raw)
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function is_valid_single(values: Values): boolean {
|
|
114
|
-
const is_valid_stopped = values.stopped === undefined || ISSUE_PATTERN.test(values.stopped)
|
|
115
|
-
|
|
116
|
-
return is_valid_stopped && is_valid_window(values.window)
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function owner_of(values: Values | undefined): string | undefined {
|
|
120
|
-
const owner = values?.owner
|
|
121
|
-
|
|
122
|
-
return owner !== undefined && COUNT_PATTERN.test(owner) ? owner : undefined
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function to_context(values: Values, owner: string): DriveContext | undefined {
|
|
126
|
-
if (!is_valid_single(values)) return undefined
|
|
127
|
-
|
|
128
|
-
const forwarded = forwarded_of(values)
|
|
129
|
-
const exclude = to_issues(values.exclude)
|
|
130
|
-
const awaited = to_issues(values.await)
|
|
131
|
-
|
|
132
|
-
if (forwarded === undefined || exclude === undefined || awaited === undefined) return undefined
|
|
133
|
-
|
|
134
|
-
const window_ms = window_of(values.window)
|
|
135
|
-
|
|
136
|
-
return {
|
|
137
|
-
owner,
|
|
138
|
-
active: values.active,
|
|
139
|
-
forwarded,
|
|
140
|
-
exclude,
|
|
141
|
-
awaited,
|
|
142
|
-
window_ms,
|
|
143
|
-
window: values.window,
|
|
144
|
-
is_only: values.only === true,
|
|
145
|
-
stopped: values.stopped,
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function parse(argv: ReadonlyArray<string>): DriveContext | undefined {
|
|
150
|
-
const values = read_values(argv)
|
|
151
|
-
const owner = owner_of(values)
|
|
152
|
-
|
|
153
|
-
return values === undefined || owner === undefined ? undefined : to_context(values, owner)
|
|
154
|
-
}
|
|
155
48
|
|
|
156
49
|
// The `--json` object `backlog:offer` prints, keyed under its `JSON_KEY`.
|
|
157
50
|
const offer_read_schema = z.object({
|
|
@@ -235,14 +128,6 @@ async function merge(issue: string, owner: string): Promise<MergeResult> {
|
|
|
235
128
|
return result
|
|
236
129
|
}
|
|
237
130
|
|
|
238
|
-
async function launch(issue: string, owner: string): Promise<LaunchOutcome['kind']> {
|
|
239
|
-
await backlog_drive_owner.assert_current(owner)
|
|
240
|
-
|
|
241
|
-
const outcome = await lane_launch_cli.launch_lane({ issue, stash: undefined })
|
|
242
|
-
|
|
243
|
-
return outcome.kind
|
|
244
|
-
}
|
|
245
|
-
|
|
246
131
|
// `lane:await`'s re-confirmed check, one state per child. A child already gone when the loop starts —
|
|
247
132
|
// a restart after it ended — is read as having appeared, so it is collected after the re-confirm window
|
|
248
133
|
// rather than waited on until the never-appeared timeout. One that never appeared is collected too:
|
|
@@ -278,17 +163,6 @@ async function open_lanes(): Promise<ReadonlyArray<string>> {
|
|
|
278
163
|
return lanes.filter((lane) => !lane.is_stranded).map((lane) => lane.issue)
|
|
279
164
|
}
|
|
280
165
|
|
|
281
|
-
function resume_line(state: DriveState, context: DriveContext): string {
|
|
282
|
-
const exclude = [...new Set([...context.exclude, ...state.exclude])]
|
|
283
|
-
const flags = ['--owner', context.owner, '--active', state.active, ...context.forwarded]
|
|
284
|
-
|
|
285
|
-
if (exclude.length > 0) flags.push('--exclude', exclude.join(LIST_SEPARATOR))
|
|
286
|
-
if (context.window !== undefined) flags.push('--window', context.window)
|
|
287
|
-
if (state.stopped_by !== undefined) flags.push('--stopped', state.stopped_by)
|
|
288
|
-
|
|
289
|
-
return `resume: ${flags.join(' ')}`
|
|
290
|
-
}
|
|
291
|
-
|
|
292
166
|
function end_line(end: DriveEnd): string {
|
|
293
167
|
const token = end.token === undefined || end.token === end.reason ? [] : [end.token]
|
|
294
168
|
const issue = end.issue === undefined ? [] : [`#${end.issue}`]
|
|
@@ -306,7 +180,7 @@ function ports_of(
|
|
|
306
180
|
is_finished: finished_checker(seeded),
|
|
307
181
|
merge: async (issue) => await merge(issue, context.owner),
|
|
308
182
|
offer: async (state) => await read_offer(state, context),
|
|
309
|
-
launch: async (issue) => await launch(issue, context.owner),
|
|
183
|
+
launch: async (issue) => await backlog_drive_launch.launch(issue, context.owner),
|
|
310
184
|
free_lanes: backlog_ready.drive_free_lane_count,
|
|
311
185
|
now: () => new Date(),
|
|
312
186
|
sleep: async (milliseconds) => {
|
|
@@ -345,7 +219,7 @@ async function drive(context: DriveContext): Promise<number> {
|
|
|
345
219
|
const end = await backlog_drive.run_loop(last.state, config, ports_of(context, seeded, last))
|
|
346
220
|
|
|
347
221
|
console.info(end_line(end))
|
|
348
|
-
console.info(resume_line(last.state, context))
|
|
222
|
+
console.info(backlog_drive_args.resume_line(last.state, context))
|
|
349
223
|
|
|
350
224
|
return SUCCESS_EXIT_CODE
|
|
351
225
|
}
|
|
@@ -361,10 +235,10 @@ async function run_safe(context: DriveContext): Promise<number> {
|
|
|
361
235
|
}
|
|
362
236
|
|
|
363
237
|
async function run(argv: ReadonlyArray<string>): Promise<number> {
|
|
364
|
-
const context = parse(argv)
|
|
238
|
+
const context = backlog_drive_args.parse(argv)
|
|
365
239
|
|
|
366
240
|
if (context === undefined) {
|
|
367
|
-
console.error(USAGE)
|
|
241
|
+
console.error(backlog_drive_args.USAGE)
|
|
368
242
|
|
|
369
243
|
return FAILURE_EXIT_CODE
|
|
370
244
|
}
|
|
@@ -384,8 +258,8 @@ const backlog_drive_cli = {
|
|
|
384
258
|
merge,
|
|
385
259
|
merge_token,
|
|
386
260
|
offer_argv: backlog_drive_offer_argv.offer_argv,
|
|
387
|
-
parse,
|
|
388
|
-
resume_line,
|
|
261
|
+
parse: backlog_drive_args.parse,
|
|
262
|
+
resume_line: backlog_drive_args.resume_line,
|
|
389
263
|
to_offer,
|
|
390
264
|
}
|
|
391
265
|
|