@joshuafolkken/kit 1.1035.0 → 1.1094.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/settings.json +9 -8
- package/.claude/skills/epic-commands/SKILL.md +5 -7
- package/.claude/skills/verify-ui/SKILL.md +1 -1
- package/.claude/skills/workflow-commands/SKILL.md +21 -13
- package/.claude/skills/workflow-commands/background-commands.md +5 -4
- package/.claude/skills/workflow-commands/backlogrun-child.md +3 -3
- package/.claude/skills/workflow-commands/backlogrun-lanes.md +9 -7
- package/.claude/skills/workflow-commands/backlogrun-park.md +6 -0
- package/.claude/skills/workflow-commands/backlogrun-progress.md +31 -37
- package/.claude/skills/workflow-commands/backlogrun-steps.md +25 -25
- package/.claude/skills/workflow-commands/backlogrun.md +2 -2
- package/.claude/skills/workflow-commands/chain-rule.md +6 -4
- package/.claude/skills/workflow-commands/delegation.md +3 -3
- package/.claude/skills/workflow-commands/followup-reference.md +3 -3
- package/.claude/skills/workflow-commands/followup.md +7 -3
- package/.claude/skills/workflow-commands/fullrun-steps.md +3 -2
- package/.claude/skills/workflow-commands/fullrun.md +3 -2
- package/.claude/skills/workflow-commands/halfrun.md +16 -19
- package/.claude/skills/workflow-commands/issue-comments.md +2 -2
- package/.claude/skills/workflow-commands/issue-fold-existing.md +10 -10
- package/.claude/skills/workflow-commands/issue-scout.md +1 -1
- package/.claude/skills/workflow-commands/kickoff.md +9 -4
- package/.claude/skills/workflow-commands/latest-gate.md +1 -1
- package/.claude/skills/workflow-commands/needs-human-review.md +1 -1
- package/.claude/skills/workflow-commands/observation-filing.md +44 -89
- package/.claude/skills/workflow-commands/pre-gate-cut.md +33 -36
- package/.claude/skills/workflow-commands/prerequisite.md +1 -1
- package/.claude/skills/workflow-commands/prrun.md +36 -0
- package/.claude/skills/workflow-commands/retrospective.md +1 -1
- package/.claude/skills/workflow-commands/working-tree-hold.md +24 -4
- package/.codex/hooks.json +16 -20
- package/.github/actions/setup-pnpm/action.yml +93 -0
- package/.github/dependabot.yml +5 -1
- package/.github/workflows/auto-tag.yml +21 -0
- package/.github/workflows/ci.yml +26 -128
- package/.github/workflows/pr-classification.yml +5 -41
- package/.github/workflows/publish.yml +42 -48
- package/.github/workflows/sonar-qube.yml +37 -4
- package/AGENTS.md +12 -2
- package/CLAUDE.md +15 -16
- package/GEMINI.md +14 -2
- package/README.md +59 -18
- package/SECURITY.md +36 -6
- package/cspell/index.yaml +2 -1
- package/dist/CLAUDE.md +15 -16
- package/dist/config-merge/index.js +15 -3
- package/dist/hooks/batch-guard.js +4 -4
- package/dist/hooks/{chunk-Y27M6A7X.js → chunk-3C4YCCEF.js} +5 -13
- package/dist/hooks/{chunk-D67KVGGY.js → chunk-7ZPFAVR7.js} +17 -88
- package/dist/hooks/{chunk-HOYJU5RM.js → chunk-E54KGFEQ.js} +11 -4
- package/dist/hooks/{chunk-KG6PZD72.js → chunk-IL27YTPH.js} +2 -2
- package/dist/hooks/{chunk-GJT4BNVE.js → chunk-KHWHKJOM.js} +3 -3
- package/dist/hooks/{chunk-HU66PWWL.js → chunk-M2XDCUKD.js} +1076 -509
- package/dist/hooks/{chunk-GLBDBJOK.js → chunk-NKOG3XAV.js} +199 -304
- package/dist/hooks/{chunk-ZXNE6NY3.js → chunk-O4LL4HTI.js} +2 -7
- package/dist/hooks/{chunk-XPLP27WA.js → chunk-OIZUHPJI.js} +5 -27
- package/dist/hooks/{chunk-EIFCAJRB.js → chunk-UD24EAIL.js} +2546 -1636
- package/dist/hooks/codex-hook-adapter.js +10 -11
- package/dist/hooks/duplicate-read-guard.js +5 -5
- package/dist/hooks/format-edited.js +15 -34
- package/dist/hooks/inputs.json +279 -0
- package/dist/hooks/investigation-guard.js +5 -5
- package/dist/hooks/pretool-guard.js +23 -16
- package/dist/hooks/session-lang.js +0 -1
- package/dist/hooks/stop-guard.js +188 -509
- package/dist/josh.js +166 -225
- package/dist/managed-marker/index.js +2 -1
- package/dist/version/index.js +412 -64
- package/eslint/rules/promise.js +5 -0
- package/package.json +13 -8
- package/prompts/collaboration-workflow/file-edits.md +6 -53
- package/prompts/collaboration-workflow/issue-citation.md +5 -5
- package/prompts/collaboration-workflow/operating-rules.md +4 -4
- package/prompts/collaboration-workflow/overview.md +13 -1
- package/prompts/collaboration-workflow/report-format.md +1 -1
- package/prompts/collaboration-workflow/residency.md +4 -4
- package/prompts/collaboration-workflow/rule-delivery.md +5 -36
- package/prompts/collaboration-workflow/shell-body.md +7 -9
- package/prompts/collaboration-workflow/turn-batching.md +21 -37
- package/prompts/collaboration-workflow/upstream-interrupt.md +1 -1
- package/prompts/collaboration-workflow/wip-cap.md +36 -36
- package/prompts/collaboration-workflow.md +5 -8
- package/prompts/review-rubric.md +1 -1
- package/prompts/review.md +3 -3
- package/prompts/sonar-hotspot-handling.md +12 -4
- package/prompts/testing-guide.md +3 -3
- package/scripts/adopt/adopt-toolkits.ts +2 -2
- package/scripts/adopt/adopt.ts +0 -2
- package/scripts/agent/agent-argv.ts +0 -2
- package/scripts/agent/agent-diagnostics.ts +1 -1
- package/scripts/agent/agent-role-profile.ts +0 -7
- package/scripts/agent/claude-agent-argv.ts +0 -2
- package/scripts/agent/codex-agent-argv.ts +1 -1
- package/scripts/agent/codex-hooks.ts +92 -0
- package/scripts/agent/interactive-ask.ts +1 -1
- package/scripts/auto-ok/auto-ok-cli.ts +15 -25
- package/scripts/backlog/backlog-budget.ts +0 -2
- package/scripts/backlog/backlog-defect-priority.ts +2 -2
- package/scripts/backlog/backlog-drive-cli.ts +10 -8
- package/scripts/backlog/backlog-drive-named-offer.ts +16 -3
- package/scripts/backlog/backlog-drive-named.ts +2 -1
- package/scripts/backlog/backlog-drive.ts +76 -16
- package/scripts/backlog/backlog-named.ts +0 -3
- package/scripts/backlog/backlog-next.ts +32 -22
- package/scripts/backlog/backlog-offer-cli.ts +0 -5
- package/scripts/backlog/backlog-plan-cli.ts +6 -8
- package/scripts/backlog/backlog-plan.ts +1 -1
- package/scripts/backlog/backlog-pool.ts +34 -17
- package/scripts/backlog/backlog-rank.ts +106 -0
- package/scripts/backlog/backlog-ready.ts +19 -3
- package/scripts/backlog/backlog-scope.ts +1 -3
- package/scripts/backlog/backlog-stalled-detect.ts +2 -2
- package/scripts/backlog/backlog-stalled.ts +0 -1
- package/scripts/backlog/backlog-waves.ts +47 -31
- package/scripts/behavior/behavior-cli.ts +1 -1
- package/scripts/build/build-codex-hooks.ts +26 -0
- package/scripts/build/build-hooks.ts +92 -11
- package/scripts/build/hook-bundle-stamp.ts +111 -0
- package/scripts/cases/cases-cli.ts +1 -1
- package/scripts/cases/cases-logic.ts +1 -1
- package/scripts/ci/composite-actions.ts +30 -0
- package/scripts/ci/pr-classification.ts +3 -3
- package/scripts/claude/workflow-destination.ts +10 -1
- package/scripts/clone/clone-fingerprint.ts +0 -1
- package/scripts/clone/clone-scan-cli.ts +1 -1
- package/scripts/clone/clone-scan.ts +1 -1
- package/scripts/config-merge/json-format.ts +0 -1
- package/scripts/config-merge/patch-yaml-list.ts +1 -1
- package/scripts/cost-runtime/codex-usage.ts +2 -9
- package/scripts/cost-runtime/cost-attribute.ts +0 -1
- package/scripts/cost-runtime/cost-cli.ts +0 -3
- package/scripts/cost-runtime/cost-corpus.ts +0 -2
- package/scripts/cost-runtime/cost-format.ts +0 -3
- package/scripts/cost-runtime/cost-pricing.ts +0 -1
- package/scripts/cost-runtime/cost-tokens.ts +0 -1
- package/scripts/delegation/delegation-cli.ts +1 -1
- package/scripts/delegation/delegation-policy.ts +11 -1
- package/scripts/delegation/duplicate-read-guard.ts +0 -8
- package/scripts/delegation/fanout-cli.ts +1 -1
- package/scripts/delegation/fanout.ts +0 -2
- package/scripts/delegation/investigation-reads.ts +1 -164
- package/scripts/discovery/repo-map-logic.ts +0 -1
- package/scripts/discovery/repo-party-cli.ts +1 -1
- package/scripts/doctor/doctor-consumer.ts +4 -6
- package/scripts/doctor/doctor-logic.ts +0 -4
- package/scripts/doctor/doctor.ts +14 -9
- package/scripts/document/document-byte-budget.ts +8 -9
- package/scripts/document/document-byte-check.ts +0 -1
- package/scripts/document/document-read-cli.ts +0 -2
- package/scripts/document/document-section-cli.ts +1 -1
- package/scripts/document/document-section.ts +0 -3
- package/scripts/document/edit-files-cli.ts +0 -1
- package/scripts/document/entry-read-budget.ts +13 -4
- package/scripts/document/lane-child-read-set.ts +1 -6
- package/scripts/document/read-files-cli.ts +0 -4
- package/scripts/document/read-set-cli.ts +0 -2
- package/scripts/document/read-set-point-of-use.ts +1 -0
- package/scripts/document/read-set-pricing.ts +0 -1
- package/scripts/document/read-set-trim.ts +1 -1
- package/scripts/epic/epic-add.ts +1 -1
- package/scripts/epic/epic-audit-cli.ts +1 -4
- package/scripts/epic/epic-audit-orphans.ts +1 -3
- package/scripts/epic/epic-audit-rationale.ts +0 -1
- package/scripts/epic/epic-audit-report.ts +0 -2
- package/scripts/epic/epic-audit.ts +5 -4
- package/scripts/epic/epic-bundle-cli.ts +1 -1
- package/scripts/epic/epic-bundle-evidence.ts +0 -1
- package/scripts/epic/epic-bundle-referenced.ts +1 -5
- package/scripts/epic/epic-bundle.ts +0 -4
- package/scripts/epic/epic-busy.ts +4 -5
- package/scripts/epic/epic-candidate-confirm.ts +0 -5
- package/scripts/epic/epic-classify.ts +2 -2
- package/scripts/epic/epic-cli-argv.ts +0 -1
- package/scripts/epic/epic-close-comment.ts +1 -1
- package/scripts/epic/epic-close.ts +5 -2
- package/scripts/epic/epic-cross-repo.ts +2 -4
- package/scripts/epic/epic-decision.ts +0 -1
- package/scripts/epic/epic-fetch.ts +2 -2
- package/scripts/epic/epic-index.ts +2 -3
- package/scripts/epic/epic-issue.ts +1 -15
- package/scripts/epic/epic-lane-offer.ts +20 -30
- package/scripts/epic/epic-nested.ts +1 -1
- package/scripts/epic/epic-next-read.ts +1 -3
- package/scripts/epic/epic-next-views.ts +0 -1
- package/scripts/epic/epic-next.ts +1 -10
- package/scripts/epic/epic-parse.ts +0 -1
- package/scripts/epic/epic-promote.ts +0 -9
- package/scripts/epic/epic-rank.ts +37 -0
- package/scripts/epic/epic-read.ts +1 -2
- package/scripts/epic/epic-reconcile.ts +1 -1
- package/scripts/epic/epic-reference.ts +1 -13
- package/scripts/epic/epic-relation-recheck.ts +1 -1
- package/scripts/epic/epic-relations.ts +1 -1
- package/scripts/epic/epic-remove.ts +1 -1
- package/scripts/epic/epic-report.ts +0 -1
- package/scripts/epic/epic-run.ts +2 -3
- package/scripts/epic/epic-shape.ts +1 -1
- package/scripts/epic/epic-solo-stale.ts +107 -0
- package/scripts/epic/epic-solo.ts +32 -30
- package/scripts/epic/epic-triage.ts +1 -1
- package/scripts/epic/epic-validate.ts +1 -1
- package/scripts/epic/epic.ts +1 -1
- package/scripts/exports/unused-members-cli.ts +53 -0
- package/scripts/{git → followup}/followup-issue-number.ts +1 -6
- package/scripts/{git → followup}/git-followup-cleanup.ts +2 -1
- package/scripts/{git → followup}/git-followup-finish.ts +1 -3
- package/scripts/{git → followup}/git-followup-flush.ts +2 -2
- package/scripts/{git → followup}/git-followup-issue-close.ts +2 -2
- package/scripts/{git → followup}/git-followup-label.ts +4 -4
- package/scripts/followup/git-followup-merged.ts +112 -0
- package/scripts/{git → followup}/git-followup-pending.ts +1 -1
- package/scripts/{git → followup}/git-followup-workflow.ts +19 -11
- package/scripts/{git → followup}/git-pr-followup-wrapup.ts +9 -3
- package/scripts/{git → followup}/git-pr-followup.ts +53 -16
- package/scripts/gate/core-budget.ts +3 -9
- package/scripts/gate/gate-plan.ts +7 -4
- package/scripts/gate/gate-report.ts +0 -6
- package/scripts/gate/gate-tree.ts +1 -1
- package/scripts/gate/pre-commit-type-check.ts +0 -6
- package/scripts/gate/project-checks.ts +7 -8
- package/scripts/gate/scoped-green.ts +0 -1
- package/scripts/gate/type-check-step.ts +1 -1
- package/scripts/gate/verification-gate.ts +0 -2
- package/scripts/gh/fix-gh-packages.ts +15 -12
- package/scripts/gh/gh-spawn.ts +2 -2
- package/scripts/{git → gh}/git-ai-review-scan.ts +1 -5
- package/scripts/{git → gh}/git-gh-check.ts +2 -1
- package/scripts/{git → gh}/git-gh-exec.ts +1 -1
- package/scripts/{git → gh}/git-gh-failure.ts +1 -1
- package/scripts/{git → gh}/git-gh-helpers.ts +0 -1
- package/scripts/{git → gh}/git-gh-issue-list.ts +2 -0
- package/scripts/{git → gh}/git-gh-issue-read.ts +1 -1
- package/scripts/{git → gh}/git-gh-issue-rest.ts +6 -3
- package/scripts/{git → gh}/git-gh-pr-read.ts +24 -0
- package/scripts/{git → gh}/git-gh-pr-rest.ts +5 -2
- package/scripts/{git → gh}/git-gh-pr-review.ts +2 -2
- package/scripts/{git → gh}/git-gh-pr-rollup.ts +1 -3
- package/scripts/{git → gh}/git-gh-pr.ts +3 -1
- package/scripts/{git → gh}/git-pr-ai-review.ts +2 -5
- package/scripts/{git → gh}/git-pr-checks-eval.ts +0 -10
- package/scripts/{git → gh}/git-pr-checks-parse.ts +4 -20
- package/scripts/{git → gh}/git-pr-checks.ts +2 -1
- package/scripts/{git → gh}/git-pr-coderabbit.ts +2 -5
- package/scripts/{git → gh}/git-pr-confirmation.ts +1 -3
- package/scripts/{git → gh}/git-pr-managed-config.ts +2 -3
- package/scripts/{git → gh}/git-pr.ts +3 -3
- package/scripts/git/changed-file-scope.ts +0 -1
- package/scripts/git/git-branch.ts +3 -6
- package/scripts/git/git-command.ts +1 -1
- package/scripts/git/git-commit.ts +1 -1
- package/scripts/git/git-common-directory.ts +80 -24
- package/scripts/git/git-error.ts +66 -9
- package/scripts/git/git-execa-error.ts +6 -1
- package/scripts/git/git-issue.ts +1 -1
- package/scripts/git/git-preflight.ts +24 -6
- package/scripts/git/git-prompt.ts +6 -31
- package/scripts/git/git-push-transport.ts +12 -69
- package/scripts/git/git-push.ts +1 -1
- package/scripts/git/git-spawn.ts +79 -3
- package/scripts/git/git-ssh-keepalive.ts +74 -0
- package/scripts/git/git-staging.ts +1 -0
- package/scripts/git/git-status.ts +1 -1
- package/scripts/git/git-workflow.ts +1 -1
- package/scripts/git/gone-branch.ts +4 -2
- package/scripts/git/listing-cutoff.ts +1 -1
- package/scripts/git/main-merge.ts +1 -1
- package/scripts/git/main-sync.ts +19 -1
- package/scripts/git/parse-json-array.ts +0 -3
- package/scripts/git/repository-lock.ts +16 -16
- package/scripts/git/{git-stash.ts → stash/git-stash.ts} +1 -1
- package/scripts/git/{stash-pop-args.ts → stash/stash-pop-args.ts} +1 -1
- package/scripts/git/{stash-pop-cli.ts → stash/stash-pop-cli.ts} +0 -1
- package/scripts/git/{stash-sweep-lock.ts → stash/stash-sweep-lock.ts} +3 -3
- package/scripts/hooks/codex-hook-adapter.ts +0 -1
- package/scripts/hooks/edited-cspell.ts +1 -1
- package/scripts/hooks/format-edited-cli.ts +15 -0
- package/scripts/hooks/format-edited-file.ts +4 -9
- package/scripts/hooks/pre-push-unit.ts +0 -4
- package/scripts/hooks/pretool-guard-cli.ts +21 -0
- package/scripts/hooks/pretool-guard.ts +36 -19
- package/scripts/hooks/reserved-run.ts +1 -1
- package/scripts/hooks/step-zero-notice.ts +76 -0
- package/scripts/hooks/stop-guard.ts +47 -21
- package/scripts/init/claude-plugin-config.ts +4 -5
- package/scripts/init/hook-command-rewrite.ts +16 -8
- package/scripts/init/hook-launch.ts +41 -15
- package/scripts/init/init-basic.ts +2 -5
- package/scripts/init/init-logic.ts +7 -0
- package/scripts/init/init.ts +0 -3
- package/scripts/init/project-profile.ts +6 -11
- package/scripts/init/start-exec.ts +8 -2
- package/scripts/init/start-plan.ts +18 -5
- package/scripts/init/start-setup-pr.ts +52 -25
- package/scripts/init/start-steps.ts +42 -9
- package/scripts/init/start.ts +40 -10
- package/scripts/issue/behavior-change-lint.ts +0 -1
- package/scripts/issue/defect-rate-cli.ts +3 -3
- package/scripts/issue/defect-rate.ts +1 -2
- package/scripts/{git → issue}/git-next-issues.ts +37 -8
- package/scripts/issue/issue-backlinks-cli.ts +1 -5
- package/scripts/issue/issue-cite-cli.ts +2 -6
- package/scripts/issue/issue-cite.ts +19 -3
- package/scripts/issue/issue-classification.ts +1 -9
- package/scripts/issue/issue-closing-pr.ts +4 -4
- package/scripts/issue/issue-comment-cli.ts +2 -2
- package/scripts/issue/issue-file-cli.ts +5 -5
- package/scripts/issue/issue-file.ts +2 -2
- package/scripts/issue/issue-fold-cli.ts +1 -1
- package/scripts/issue/issue-fold-existing-cli.ts +1 -1
- package/scripts/{git → issue}/issue-labels.ts +20 -0
- package/scripts/issue/issue-lint-cli.ts +1 -1
- package/scripts/issue/issue-merged.ts +2 -2
- package/scripts/issue/issue-rank.ts +89 -0
- package/scripts/issue/issue-read-cli.ts +8 -47
- package/scripts/issue/issue-read.ts +0 -2
- package/scripts/issue/issue-report-failures.ts +80 -0
- package/scripts/issue/issue-scout-cli.ts +1 -7
- package/scripts/issue/issue-scout-closed.ts +2 -2
- package/scripts/issue/issue-scout.ts +0 -2
- package/scripts/issue/issue-state-cli.ts +5 -46
- package/scripts/issue/issue-state.ts +1 -5
- package/scripts/issue/markdown-section.ts +1 -1
- package/scripts/issue/measure-rerun-cli.ts +1 -1
- package/scripts/issue/reproduction-measure.ts +1 -1
- package/scripts/josh/cli-body.ts +1 -1
- package/scripts/josh/file-map-stamp.ts +0 -3
- package/scripts/josh/josh-command-map.ts +2 -102
- package/scripts/josh/josh-commands-ai.ts +9 -102
- package/scripts/josh/josh-commands-backlog.ts +5 -1
- package/scripts/josh/josh-commands-development.ts +10 -3
- package/scripts/josh/josh-commands-issue.ts +2 -2
- package/scripts/josh/josh-commands-maintenance.ts +7 -0
- package/scripts/josh/josh-commands-project.ts +7 -1
- package/scripts/josh/josh-commands-run.ts +114 -0
- package/scripts/josh/josh-commands-versioning.ts +8 -0
- package/scripts/josh/josh-commands-workflow.ts +2 -2
- package/scripts/josh/path-decision.ts +0 -3
- package/scripts/josh/process-owner.ts +16 -0
- package/scripts/josh/session-language-cli.ts +0 -1
- package/scripts/lane/lane-await.ts +3 -6
- package/scripts/lane/lane-capacity.ts +6 -3
- package/scripts/lane/lane-child-invocation.ts +20 -7
- package/scripts/lane/lane-child-marker.ts +16 -2
- package/scripts/lane/lane-cli.ts +33 -18
- package/scripts/lane/lane-close.ts +1 -3
- package/scripts/lane/lane-dispatch.ts +3 -4
- package/scripts/lane/lane-environment.ts +0 -9
- package/scripts/lane/lane-handoff.ts +38 -0
- package/scripts/lane/lane-launch-cli.ts +21 -11
- package/scripts/lane/lane-open.ts +0 -3
- package/scripts/lane/lane-output.ts +0 -1
- package/scripts/lane/lane-registry.ts +9 -0
- package/scripts/lane/lane-report.ts +10 -4
- package/scripts/lane/openai-lane-ship.ts +2 -0
- package/scripts/lane/openai-lane-supervisor-decision.ts +2 -1
- package/scripts/lane/openai-lane-supervisor.ts +6 -4
- package/scripts/lane/openai-review-broker.ts +3 -0
- package/scripts/lib/bounded-pool.ts +1 -0
- package/scripts/lib/json-value.ts +5 -4
- package/scripts/lib/poll.ts +3 -1
- package/scripts/lib/timed-fetch.ts +15 -0
- package/scripts/lib/timeouts.ts +13 -0
- package/scripts/{yaml → lib}/yaml-document.ts +3 -1
- package/scripts/{bytes → lines}/bytes-command.ts +0 -2
- package/scripts/lines/lines-command.ts +0 -1
- package/scripts/lint/lint-related-scope.ts +0 -1
- package/scripts/lint/lint-related.ts +1 -1
- package/scripts/{git → notify}/telegram-notify.ts +2 -2
- package/scripts/{git → notify}/telegram-test.ts +4 -4
- package/scripts/observations/observation-ledger-home.ts +0 -1
- package/scripts/observations/observation-ledger-line.ts +0 -1
- package/scripts/observations/observation-ledger-migrate.ts +1 -1
- package/scripts/observations/observations-flush-landing.ts +3 -3
- package/scripts/observations/observations-flush.ts +2 -2
- package/scripts/overrides/lockfile-overrides.ts +1 -1
- package/scripts/overrides/overrides-logic.ts +1 -1
- package/scripts/package/package-scout-cli.ts +2 -7
- package/scripts/package/package-scout.ts +0 -2
- package/scripts/propagate/propagate-git-failure.ts +0 -1
- package/scripts/propagate/propagate-git.ts +0 -2
- package/scripts/propagate/propagate-plan.ts +185 -0
- package/scripts/propagate/propagate-publish.ts +2 -3
- package/scripts/propagate/propagate-run.ts +5 -3
- package/scripts/propagate/propagate-steps.ts +19 -6
- package/scripts/propagate/propagate-targets.ts +13 -6
- package/scripts/propagate/propagate.ts +60 -46
- package/scripts/refactor/import-graph.ts +0 -1
- package/scripts/refactor/refactor-lint.ts +0 -2
- package/scripts/refactor/refactor-scan.ts +0 -1
- package/scripts/refactor/refactor-targets.ts +0 -1
- package/scripts/registry-migration/migrate-logic.ts +1 -2
- package/scripts/registry-migration/migrate.ts +19 -9
- package/scripts/release/github-release-cli.ts +8 -6
- package/scripts/release/github-release-environment.ts +46 -0
- package/scripts/release/github-release.ts +151 -94
- package/scripts/release/release-history.ts +0 -1
- package/scripts/release/release-plan.ts +0 -1
- package/scripts/release/release-publish.ts +2 -3
- package/scripts/release/release-scope-cli.ts +1 -2
- package/scripts/release/release-tag.ts +2 -4
- package/scripts/repo/auto-merge-setting-logic.ts +1 -4
- package/scripts/repo/repo-setting.ts +1 -1
- package/scripts/repo/repository-labels.ts +3 -3
- package/scripts/repo/required-checks-logic.ts +206 -0
- package/scripts/repo/required-checks-report.ts +71 -0
- package/scripts/repo/ruleset-check-cli.ts +53 -0
- package/scripts/repo/ruleset-check.ts +147 -0
- package/scripts/report/report-lint-cli.ts +0 -4
- package/scripts/review/disposition-cli.ts +1 -1
- package/scripts/review/live-evidence.ts +1 -1
- package/scripts/review/review-attest-cli.ts +0 -6
- package/scripts/review/review-attest.ts +48 -16
- package/scripts/review/review-brief-cli.ts +72 -8
- package/scripts/review/review-brief.ts +67 -9
- package/scripts/review/review-diff-parts.ts +89 -0
- package/scripts/review/review-diff-write.ts +97 -0
- package/scripts/review/review-finding-ledger.ts +0 -1
- package/scripts/review/review-record-cli.ts +1 -1
- package/scripts/review/review-record.ts +0 -1
- package/scripts/review/review-round2-cli.ts +1 -1
- package/scripts/review/review-stamps.ts +6 -2
- package/scripts/review/review-tree.ts +14 -2
- package/scripts/rules/decision-oracle-stage.ts +18 -0
- package/scripts/rules/decision-oracle.ts +10 -7
- package/scripts/rules/delivered-rules.ts +9 -1
- package/scripts/rules/destructive-command.ts +119 -0
- package/scripts/rules/direct-filing.ts +1 -1
- package/scripts/rules/file-body.ts +0 -3
- package/scripts/rules/filing-cap.ts +0 -2
- package/scripts/rules/gh-api.ts +7 -2
- package/scripts/rules/git-argv.ts +18 -7
- package/scripts/rules/git-force.ts +0 -2
- package/scripts/rules/implementation-cut.ts +1 -2
- package/scripts/rules/index-guard.ts +71 -0
- package/scripts/rules/issue-citation.ts +50 -25
- package/scripts/rules/issue-fold.ts +1 -2
- package/scripts/rules/lane-background.ts +15 -7
- package/scripts/rules/lane-carry-conflict.ts +1 -2
- package/scripts/rules/lane-park.ts +14 -8
- package/scripts/rules/last-prompt.ts +1 -0
- package/scripts/rules/oracle-consulted.ts +1 -1
- package/scripts/rules/oracle-firing.ts +1 -0
- package/scripts/rules/oracle-list-cli.ts +0 -3
- package/scripts/rules/permission-guards.ts +14 -0
- package/scripts/rules/pre-gate-cut.ts +2 -2
- package/scripts/rules/protected-files.ts +74 -0
- package/scripts/rules/reply-language.ts +1 -1
- package/scripts/rules/rule-body-guard.ts +0 -3
- package/scripts/rules/rule-value-cli.ts +0 -1
- package/scripts/rules/shell-body-trigger.ts +0 -1
- package/scripts/rules/shell-segments.ts +0 -1
- package/scripts/rules/stop-rules.ts +13 -5
- package/scripts/rules/tail-commands.ts +1 -1
- package/scripts/rules/test-declared-commit.ts +1 -1
- package/scripts/rules/third-party-write.ts +0 -1
- package/scripts/rules/worktree-guard.ts +26 -9
- package/scripts/run/run-carry-cli.ts +0 -2
- package/scripts/run/run-carry-stash.ts +2 -2
- package/scripts/run/run-carry-streak.ts +1 -1
- package/scripts/run/run-cut-cli.ts +0 -7
- package/scripts/run/run-cut.ts +8 -54
- package/scripts/run/run-ending-cli.ts +1 -1
- package/scripts/run/run-ending.ts +1 -4
- package/scripts/run/run-entry-cli.ts +101 -24
- package/scripts/run/run-entry.ts +0 -1
- package/scripts/run/run-event-cli.ts +0 -2
- package/scripts/run/run-event-follow.ts +1 -0
- package/scripts/run/run-event-render.ts +1 -1
- package/scripts/run/run-event-scope.ts +53 -4
- package/scripts/run/run-event-stream.ts +0 -3
- package/scripts/run/run-event-watch.ts +1 -0
- package/scripts/run/run-halfrun-resume.ts +20 -7
- package/scripts/run/run-headless.ts +24 -8
- package/scripts/run/run-hold-cli.ts +33 -10
- package/scripts/run/run-hold.ts +25 -5
- package/scripts/run/run-issue-number.ts +1 -1
- package/scripts/run/run-liveness-cli.ts +1 -1
- package/scripts/run/run-liveness.ts +2 -3
- package/scripts/run/run-merge-cli.ts +5 -13
- package/scripts/run/run-merge-steps.ts +5 -5
- package/scripts/run/run-merge.ts +1 -1
- package/scripts/run/run-next-cli.ts +1 -1
- package/scripts/run/run-parent-cut-hook.ts +143 -0
- package/scripts/run/run-preflight.ts +2 -9
- package/scripts/run/run-prep-cli.ts +2 -2
- package/scripts/run/run-prep-locate.ts +1 -1
- package/scripts/run/run-progress-cli.ts +4 -7
- package/scripts/run/run-progress-clock.ts +6 -34
- package/scripts/run/run-progress-config.ts +0 -4
- package/scripts/run/run-progress-read.ts +3 -3
- package/scripts/run/run-progress.ts +22 -10
- package/scripts/run/run-prrun-resume.ts +117 -0
- package/scripts/run/run-report-cli.ts +1 -2
- package/scripts/run/run-report.ts +0 -1
- package/scripts/run/run-retrospective.ts +1 -1
- package/scripts/run/run-review-cli.ts +0 -3
- package/scripts/run/run-review-steps.ts +2 -0
- package/scripts/run/run-review.ts +0 -2
- package/scripts/run/run-ship-cli.ts +27 -77
- package/scripts/run/run-ship-detach.ts +1 -0
- package/scripts/run/run-ship-next.ts +106 -0
- package/scripts/run/run-ship-preflight.ts +87 -0
- package/scripts/run/run-ship-return.ts +8 -3
- package/scripts/run/run-ship-review-steps.ts +23 -30
- package/scripts/run/run-ship-review.ts +20 -0
- package/scripts/run/run-ship-scoped.ts +45 -0
- package/scripts/run/run-ship-stage.ts +5 -1
- package/scripts/run/run-ship-steps.ts +105 -0
- package/scripts/run/run-ship.ts +2 -1
- package/scripts/run/run-stage-read.ts +62 -0
- package/scripts/run/run-stage.ts +160 -0
- package/scripts/run/run-status-cli.ts +1 -1
- package/scripts/run/run-step-cli.ts +21 -14
- package/scripts/run/run-step.ts +1 -1
- package/scripts/run/run-stop-notify.ts +1 -3
- package/scripts/run/run-stranded-cli.ts +0 -4
- package/scripts/run/run-stranded-detect.ts +2 -2
- package/scripts/run/run-tail-cli.ts +17 -11
- package/scripts/run/run-tail.ts +2 -0
- package/scripts/run/run-tidy-lanes.ts +2 -1
- package/scripts/run/run-tidy-stashes.ts +12 -12
- package/scripts/run/run-wake-cli.ts +4 -5
- package/scripts/run/run-wake-describe.ts +19 -1
- package/scripts/run/run-wake-loop.ts +2 -2
- package/scripts/run/run-wake.ts +2 -4
- package/scripts/run/run-watcher-guard-cli.ts +0 -4
- package/scripts/run/run-watcher-guard.ts +9 -7
- package/scripts/run/run-watcher-hook.ts +1 -1
- package/scripts/safe-chain/ci-installer-pin.ts +11 -5
- package/scripts/safe-chain/project-config.ts +1 -1
- package/scripts/security/security-audit-provision-logic.ts +0 -1
- package/scripts/security/security-audit-provision.ts +3 -2
- package/scripts/security/security-audit.ts +0 -1
- package/scripts/security/security-updates-logic.ts +0 -1
- package/scripts/sonar/sonar-hotspots-cli.ts +10 -52
- package/scripts/sonar/sonar-hotspots.ts +0 -1
- package/scripts/sonar/sonar-new-code-cli.ts +150 -0
- package/scripts/sonar/sonar-new-code.ts +79 -0
- package/scripts/sonar/sonar-project.ts +97 -0
- package/scripts/split/split-assess-cli.ts +1 -1
- package/scripts/split/split-assess.ts +2 -5
- package/scripts/sync/managed-config-scope-cli.ts +1 -1
- package/scripts/sync/skill-migration.ts +0 -1
- package/scripts/sync/sync-hook-safety.ts +2 -3
- package/scripts/sync/sync.ts +1 -8
- package/scripts/sync/template-source-logic.ts +0 -1
- package/scripts/sync/workflow-pin-logic.ts +16 -28
- package/scripts/test/test-declared-logic.ts +0 -1
- package/scripts/test/test-declared.ts +0 -2
- package/scripts/test/test-red-commit.ts +2 -2
- package/scripts/test/test-red.ts +14 -7
- package/scripts/test/test-type-logic.ts +1 -1
- package/scripts/test/unit-worker-share.ts +7 -16
- package/scripts/time-runtime/time-batch-guard.ts +1 -2
- package/scripts/time-runtime/time-bundle-call.ts +2 -3
- package/scripts/time-runtime/time-bundles.ts +0 -4
- package/scripts/time-runtime/time-density-hook.ts +0 -2
- package/scripts/time-runtime/time-followup-stage.ts +1 -1
- package/scripts/time-runtime/time-format.ts +0 -73
- package/scripts/time-runtime/time-round-trips.ts +0 -4
- package/scripts/time-runtime/time-single-check.ts +1 -1
- package/scripts/time-runtime/time-spans.ts +1 -1
- package/scripts/time-runtime/time-transcript-line.ts +1 -2
- package/scripts/ui/ui-routes-cli.ts +0 -5
- package/scripts/ui/ui-routes.ts +0 -5
- package/scripts/version/effective-upstream.ts +2 -2
- package/scripts/version/latest-corepack.ts +7 -9
- package/scripts/version/latest-scope-cli.ts +0 -2
- package/scripts/version/latest-update.ts +0 -2
- package/scripts/version/npm-registry.ts +97 -0
- package/scripts/version/publishable-range-check.ts +1 -1
- package/scripts/version/release-hold.ts +0 -4
- package/scripts/version/running-binary.ts +2 -2
- package/scripts/version/version-check-logic.ts +0 -2
- package/scripts/version/version-commands.ts +5 -4
- package/scripts/version/version-remote.ts +28 -14
- package/scripts/version/version-targets.ts +4 -4
- package/templates/sonar-project.properties +28 -1
- package/templates/workflows/dependabot-auto-merge.yml +5 -3
- package/templates/workflows/github-release.yml +81 -0
- package/prompts/collaboration-workflow/cross-repo-epic.md +0 -5
- package/prompts/collaboration-workflow/epic-audit.md +0 -5
- package/prompts/collaboration-workflow/epic-bundle.md +0 -5
- package/scripts/init/plugin-install-hint.ts +0 -47
- package/scripts/version/parse-json.ts +0 -13
- /package/scripts/{git → followup}/git-followup-stages.ts +0 -0
- /package/scripts/{git → gh}/git-gh-api-path.ts +0 -0
- /package/scripts/{git → gh}/git-gh-command.ts +0 -0
- /package/scripts/{git → gh}/git-gh-issue-write.ts +0 -0
- /package/scripts/{git → gh}/git-gh-issue.ts +0 -0
- /package/scripts/{git → gh}/git-gh-pr-auto-merge.ts +0 -0
- /package/scripts/{git → gh}/git-gh-pr-snapshot.ts +0 -0
- /package/scripts/{git → gh}/git-gh-reachability.ts +0 -0
- /package/scripts/{git → gh}/git-gh-repo.ts +0 -0
- /package/scripts/{git → gh}/git-gh-rest-state.ts +0 -0
- /package/scripts/{git → gh}/git-pr-checks-watch.ts +0 -0
- /package/scripts/{git → gh}/git-pr-error.ts +0 -0
- /package/scripts/{git → gh}/git-pr-messages.ts +0 -0
- /package/scripts/{git → gh}/github-issue-url.ts +0 -0
- /package/scripts/git/{stash-orphans.ts → stash/stash-orphans.ts} +0 -0
- /package/scripts/{git → issue}/issue-reference.ts +0 -0
- /package/scripts/{git → lib}/animation-helpers.ts +0 -0
- /package/scripts/{git → lib}/git-animation.ts +0 -0
- /package/scripts/{git → notify}/git-notify.ts +0 -0
- /package/scripts/{git → notify}/telegram-test-logic.ts +0 -0
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { run_issue_number } from '#scripts/run/run-issue-number'
|
|
2
|
+
import { run_ship_next, type ShipResume } from '#scripts/run/run-ship-next'
|
|
3
|
+
import type { Stage } from '#scripts/run/run-ship-stage'
|
|
4
|
+
|
|
5
|
+
interface ShipStop extends ShipResume {
|
|
6
|
+
stage: Stage
|
|
7
|
+
}
|
|
2
8
|
|
|
3
9
|
const CHILD_INVOCATION = 'fullrun'
|
|
4
10
|
const RESUME_GUIDE = '.claude/skills/workflow-commands/pre-gate-cut.md'
|
|
@@ -52,17 +58,24 @@ function outage_resume_invocation(issue: string): string {
|
|
|
52
58
|
|
|
53
59
|
// The prompt a lane child is relaunched with when its detached ship supervisor stopped at a failed
|
|
54
60
|
// stage (joshuafolkken/kit#2428) — a red gate, a High/Medium review, a failed push or red CI. The agent
|
|
55
|
-
// ended at the hand-off, so this is how control comes back to one: it reads the stopped report
|
|
56
|
-
//
|
|
57
|
-
// the
|
|
58
|
-
|
|
59
|
-
|
|
61
|
+
// ended at the hand-off, so this is how control comes back to one: it reads the stopped report, fixes it
|
|
62
|
+
// and hands the region back. It ends with `child_invocation` for the reason `resume_invocation` does —
|
|
63
|
+
// the parent's poll keeps matching the relaunched process.
|
|
64
|
+
//
|
|
65
|
+
// **A known stage puts the next command in the prompt** (joshuafolkken/kit#2964), so the relaunched
|
|
66
|
+
// session runs it rather than re-deriving it from `chain-rule.md`. An OpenAI lane's supervisor sees only
|
|
67
|
+
// that the ship failed, not where, so without a stage the prompt points at `run:step` as before.
|
|
68
|
+
function ship_stop_invocation(issue: string, stop?: ShipStop): string {
|
|
69
|
+
const opening = `Resuming the lane child for issue #${issue} after its detached ship supervisor stopped at a failed stage — do not re-read the workflow-commands entry documents (SKILL.md, fullrun.md).`
|
|
70
|
+
const next =
|
|
71
|
+
stop === undefined
|
|
72
|
+
? `Run \`pnpm josh run:step ${issue}\` and read the stopped report it names, fix what stopped the ship, then hand the region back per chain-rule.md.`
|
|
73
|
+
: run_ship_next.next_step(issue, stop.stage, stop)
|
|
60
74
|
|
|
61
|
-
return `${
|
|
75
|
+
return `${opening} ${next} Do not re-plan or re-implement what is already on the branch. ${child_invocation(issue)}`
|
|
62
76
|
}
|
|
63
77
|
|
|
64
78
|
const lane_child_invocation = {
|
|
65
|
-
CHILD_INVOCATION,
|
|
66
79
|
child_invocation,
|
|
67
80
|
outage_resume_invocation,
|
|
68
81
|
process_pattern,
|
|
@@ -19,6 +19,15 @@ import { lane_paths } from './lane-paths'
|
|
|
19
19
|
// `.claude/skills/workflow-commands/pre-gate-cut.md`.
|
|
20
20
|
const KEY = 'JOSH_LANE_CHILD'
|
|
21
21
|
|
|
22
|
+
// **A dispatched child also asks for the five-minute prompt-cache TTL** (joshuafolkken/kit#2944). A
|
|
23
|
+
// headless `claude -p` session on a subscription defaults to the one-hour TTL, whose writes bill at 2x
|
|
24
|
+
// the input rate against 1.25x for five minutes. A replay of 1,953 lane transcripts (about 57,000
|
|
25
|
+
// requests) found 0.3% of request gaps over five minutes, so the shorter TTL — re-writing the prefix on
|
|
26
|
+
// those few gaps — still costs 12-13% less. Every launcher of a child composes its environment here,
|
|
27
|
+
// so this is the one place the choice is made.
|
|
28
|
+
const CACHE_TTL_KEY = 'CLAUDE_CODE_PROMPT_CACHE_TTL'
|
|
29
|
+
const CACHE_TTL = '5m'
|
|
30
|
+
|
|
22
31
|
type MarkerSource = Readonly<Record<string, string | undefined>>
|
|
23
32
|
|
|
24
33
|
// The environment fragment that marks a child dispatched for `#<issue>`. Composed from a digits-only
|
|
@@ -27,7 +36,7 @@ type MarkerSource = Readonly<Record<string, string | undefined>>
|
|
|
27
36
|
function environment_for(issue: string): Record<string, string> {
|
|
28
37
|
run_issue_number.require_issue_number(issue)
|
|
29
38
|
|
|
30
|
-
return { [KEY]: issue }
|
|
39
|
+
return { [KEY]: issue, [CACHE_TTL_KEY]: CACHE_TTL }
|
|
31
40
|
}
|
|
32
41
|
|
|
33
42
|
// The issue a child was dispatched for, or `undefined` when the mark is absent or malformed. A blank
|
|
@@ -52,7 +61,12 @@ function is_child_of(directory: string, source: MarkerSource = process.env): boo
|
|
|
52
61
|
return marked !== undefined && marked === lane_paths.lane_issue_of(directory, { ...source })
|
|
53
62
|
}
|
|
54
63
|
|
|
55
|
-
const lane_child_marker = {
|
|
64
|
+
const lane_child_marker = {
|
|
65
|
+
KEY,
|
|
66
|
+
env_for: environment_for,
|
|
67
|
+
is_child_of,
|
|
68
|
+
marked_issue,
|
|
69
|
+
}
|
|
56
70
|
|
|
57
71
|
export type { MarkerSource }
|
|
58
72
|
export { lane_child_marker }
|
package/scripts/lane/lane-cli.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env tsx
|
|
2
2
|
import { fileURLToPath } from 'node:url'
|
|
3
3
|
import { epic_busy } from '#scripts/epic/epic-busy'
|
|
4
|
-
import { git_gh_command } from '#scripts/
|
|
4
|
+
import { git_gh_command } from '#scripts/gh/git-gh-command'
|
|
5
|
+
import type { OpenIssueData } from '#scripts/git/schemas'
|
|
6
|
+
import { issue_cite, type IssueCiter } from '#scripts/issue/issue-cite'
|
|
5
7
|
import { error_text } from '#scripts/lib/error-message'
|
|
6
8
|
import { run_carry } from '#scripts/run/run-carry'
|
|
7
9
|
import { lane_await } from './lane-await'
|
|
@@ -150,10 +152,10 @@ function report_sweep(outcome: SweepOutcome): number {
|
|
|
150
152
|
|
|
151
153
|
// `none` on standard output for the empty case as well, so `lane:list` keeps the contract the rest
|
|
152
154
|
// of the commands follow — the prose belongs on standard error with every other explanation.
|
|
153
|
-
function report_lanes(lanes: ReadonlyArray<LaneInfo
|
|
155
|
+
function report_lanes(lanes: ReadonlyArray<LaneInfo>, cite: IssueCiter): number {
|
|
154
156
|
if (lanes.length === 0) console.error(lane_report.NO_LANES)
|
|
155
157
|
|
|
156
|
-
console.info(lanes.length === 0 ? NONE_TOKEN : lane_report.describe_lanes(lanes))
|
|
158
|
+
console.info(lanes.length === 0 ? NONE_TOKEN : lane_report.describe_lanes(lanes, cite))
|
|
157
159
|
|
|
158
160
|
return SUCCESS_EXIT_CODE
|
|
159
161
|
}
|
|
@@ -192,23 +194,39 @@ const OCCUPANCY_UNREADABLE =
|
|
|
192
194
|
// The `in-progress` issues this repository shows running, read the way `epic:next` reads lane
|
|
193
195
|
// occupancy — never rebuilt (joshuafolkken/kit#2235). A read that could not see the whole listing is
|
|
194
196
|
// `undefined`, so the difference is skipped rather than computed against a set known to be partial.
|
|
195
|
-
async function
|
|
197
|
+
async function to_holders(repo: string): Promise<ReadonlyArray<OpenIssueData> | undefined> {
|
|
196
198
|
const read = await epic_busy.read_repository(repo)
|
|
197
199
|
if (read.kind === 'idle') return []
|
|
198
200
|
|
|
199
|
-
return read.kind === 'busy' ? read.issues
|
|
201
|
+
return read.kind === 'busy' ? read.issues : undefined
|
|
200
202
|
}
|
|
201
203
|
|
|
202
|
-
|
|
204
|
+
// The repository and its running issues, read once: the listing cites each lane from the titles here
|
|
205
|
+
// (joshuafolkken/kit#2943) and the occupancy check compares against the same set.
|
|
206
|
+
interface InProgress {
|
|
207
|
+
repo: string | undefined
|
|
208
|
+
holders: ReadonlyArray<OpenIssueData> | undefined
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
async function read_in_progress(): Promise<InProgress> {
|
|
203
212
|
try {
|
|
204
213
|
const repo = await git_gh_command.repo_get_name_with_owner()
|
|
205
214
|
|
|
206
|
-
return repo === undefined ? undefined : await
|
|
215
|
+
return { repo, holders: repo === undefined ? undefined : await to_holders(repo) }
|
|
207
216
|
} catch {
|
|
208
|
-
return undefined
|
|
217
|
+
return { repo: undefined, holders: undefined }
|
|
209
218
|
}
|
|
210
219
|
}
|
|
211
220
|
|
|
221
|
+
function citer_of(in_progress: InProgress): IssueCiter {
|
|
222
|
+
const holders = in_progress.holders ?? []
|
|
223
|
+
|
|
224
|
+
return issue_cite.citer(
|
|
225
|
+
in_progress.repo,
|
|
226
|
+
new Map(holders.map((issue) => [String(issue.number), issue.title])),
|
|
227
|
+
)
|
|
228
|
+
}
|
|
229
|
+
|
|
212
230
|
// A stranded lane's work tree is gone, so it holds no issue: it counts as no lane rather than a live
|
|
213
231
|
// one, which is what turns its surviving `in-progress` label into a `stopped` anomaly.
|
|
214
232
|
function live_lane_issues(lanes: ReadonlyArray<LaneInfo>): Array<number> {
|
|
@@ -217,16 +235,15 @@ function live_lane_issues(lanes: ReadonlyArray<LaneInfo>): Array<number> {
|
|
|
217
235
|
|
|
218
236
|
// The lane/label difference, printed to standard error beside the listing. Wrapped so a GitHub read
|
|
219
237
|
// that fails skips only this section — `lane:list`'s job is to list the lanes it already read.
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
if (in_progress === undefined) {
|
|
238
|
+
function report_occupancy(lanes: ReadonlyArray<LaneInfo>, in_progress: InProgress): void {
|
|
239
|
+
if (in_progress.holders === undefined) {
|
|
224
240
|
console.error(OCCUPANCY_UNREADABLE)
|
|
225
241
|
|
|
226
242
|
return
|
|
227
243
|
}
|
|
228
244
|
|
|
229
|
-
const
|
|
245
|
+
const holders = in_progress.holders.map((issue) => issue.number)
|
|
246
|
+
const report = lane_occupancy.classify(holders, {
|
|
230
247
|
kind: 'lanes',
|
|
231
248
|
issues: live_lane_issues(lanes),
|
|
232
249
|
})
|
|
@@ -239,9 +256,10 @@ async function list_command(rest: ReadonlyArray<string>): Promise<number> {
|
|
|
239
256
|
if (rest.length > 0) return report_usage()
|
|
240
257
|
|
|
241
258
|
const lanes = await lane_registry.list_lanes()
|
|
242
|
-
const
|
|
259
|
+
const in_progress = await read_in_progress()
|
|
260
|
+
const code = report_lanes(lanes, citer_of(in_progress))
|
|
243
261
|
|
|
244
|
-
|
|
262
|
+
report_occupancy(lanes, in_progress)
|
|
245
263
|
|
|
246
264
|
return code
|
|
247
265
|
}
|
|
@@ -399,9 +417,6 @@ const lane_cli = {
|
|
|
399
417
|
ALL_FLAG,
|
|
400
418
|
NONE_TOKEN,
|
|
401
419
|
USAGE,
|
|
402
|
-
main,
|
|
403
|
-
parse_issue,
|
|
404
|
-
parse_lane_issue,
|
|
405
420
|
refusal_message,
|
|
406
421
|
run,
|
|
407
422
|
}
|
|
@@ -158,6 +158,7 @@ async function close_each(issues: ReadonlyArray<string>): Promise<SweepOutcome>
|
|
|
158
158
|
const sweep: SweepOutcome = { closed: [], failed: [] }
|
|
159
159
|
|
|
160
160
|
for (const issue of issues) {
|
|
161
|
+
// eslint-disable-next-line no-await-in-loop -- worktree writes contend for the same registration directory
|
|
161
162
|
const bucket = (await try_close(issue)) ? sweep.closed : sweep.failed
|
|
162
163
|
|
|
163
164
|
bucket.push(issue)
|
|
@@ -186,10 +187,7 @@ async function close_all_lanes(): Promise<SweepOutcome> {
|
|
|
186
187
|
const lane_close = {
|
|
187
188
|
close_all_lanes,
|
|
188
189
|
close_lane,
|
|
189
|
-
lane_root_directory,
|
|
190
|
-
lane_targets,
|
|
191
190
|
prune_lanes,
|
|
192
|
-
remove_lane,
|
|
193
191
|
resolve_lane,
|
|
194
192
|
}
|
|
195
193
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { agent_argv, type AgentArgv, type AgentArgvResult } from '#scripts/agent/agent-argv'
|
|
2
2
|
import { agent_role_profile, type AgentProfile } from '#scripts/agent/agent-role-profile'
|
|
3
|
-
import { git_gh_command } from '#scripts/
|
|
4
|
-
import { IN_PROGRESS_LABEL } from '#scripts/
|
|
5
|
-
import { telegram_notify } from '#scripts/
|
|
3
|
+
import { git_gh_command } from '#scripts/gh/git-gh-command'
|
|
4
|
+
import { IN_PROGRESS_LABEL } from '#scripts/issue/issue-labels'
|
|
5
|
+
import { telegram_notify } from '#scripts/notify/telegram-notify'
|
|
6
6
|
import { detached_launch } from '#scripts/run/detached-launch'
|
|
7
7
|
import { run_ending } from '#scripts/run/run-ending'
|
|
8
8
|
import { run_event_stream } from '#scripts/run/run-event-stream'
|
|
@@ -444,7 +444,6 @@ async function warn_of_problem(outcome: DispatchOutcome, issue: string): Promise
|
|
|
444
444
|
}
|
|
445
445
|
|
|
446
446
|
const lane_dispatch = {
|
|
447
|
-
CHILD_INVOCATION: lane_child_invocation.CHILD_INVOCATION,
|
|
448
447
|
child_invocation,
|
|
449
448
|
default_log_path,
|
|
450
449
|
describe,
|
|
@@ -58,10 +58,6 @@ function is_key_line(line: string, key: string): boolean {
|
|
|
58
58
|
return body.slice(key.length).trimStart().startsWith(ASSIGNMENT_SEPARATOR)
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
function is_seed_line(line: string): boolean {
|
|
62
|
-
return is_key_line(line, PORT_SEED_KEY)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
61
|
function is_seat_line(line: string): boolean {
|
|
66
62
|
return is_key_line(line, LANE_SEAT_KEY)
|
|
67
63
|
}
|
|
@@ -235,12 +231,7 @@ function with_lane_output(content: string, output: string, profile?: AgentProfil
|
|
|
235
231
|
}
|
|
236
232
|
|
|
237
233
|
const lane_environment = {
|
|
238
|
-
LANE_OUTPUT_KEY,
|
|
239
|
-
LANE_PROVIDER_KEY,
|
|
240
|
-
LANE_ROLE_KEY,
|
|
241
|
-
is_output_line,
|
|
242
234
|
is_seat_line,
|
|
243
|
-
is_seed_line,
|
|
244
235
|
lane_file_content,
|
|
245
236
|
read_lane_output,
|
|
246
237
|
read_lane_profile,
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { git_common_directory } from '#scripts/git/git-common-directory'
|
|
2
|
+
import { run_ship_detach } from '#scripts/run/run-ship-detach'
|
|
3
|
+
import { lane_child_marker, type MarkerSource } from './lane-child-marker'
|
|
4
|
+
|
|
5
|
+
// Whether a lane has handed its post-implementation region to the detached ship (joshuafolkken/kit#2962).
|
|
6
|
+
//
|
|
7
|
+
// **A child that ran `pnpm josh ship --detach` waits on nobody when it ends.** The supervisor drives the
|
|
8
|
+
// gate, the review and the merge, and notifies on its own outcome, so the `Stop` hook's demand for a
|
|
9
|
+
// `confirmation` notify and `lane-park`'s refusal of that notify only bought a "nothing needed"
|
|
10
|
+
// Telegram and a wasted turn — measured on 2026-10-02 as 43 demands, 21 refusals and ~94 extra turns.
|
|
11
|
+
// Both hooks read this one predicate, so they cannot disagree about whether the lane was handed off.
|
|
12
|
+
//
|
|
13
|
+
// **Running, never merely recorded.** A ship that failed hands its region back to the child, whose
|
|
14
|
+
// record then reads `failed`; that child is waiting again and owes the notify, so only a live
|
|
15
|
+
// supervisor counts as a hand-off.
|
|
16
|
+
|
|
17
|
+
// A detached ship for `issue` is live in the repository `directory` belongs to — the single reading
|
|
18
|
+
// `lane:await`, `run:merge` and the two stop hooks share.
|
|
19
|
+
function is_ship_running(issue: string, directory: string): boolean {
|
|
20
|
+
const repository = git_common_directory.repository(directory)
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
repository !== undefined && run_ship_detach.read_result(repository, issue)?.result === 'running'
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// This session is the dispatched lane child for `directory` and its own ship is running.
|
|
28
|
+
function is_handed_off(directory: string, source: MarkerSource = process.env): boolean {
|
|
29
|
+
const issue = lane_child_marker.marked_issue(source)
|
|
30
|
+
|
|
31
|
+
if (issue === undefined || !lane_child_marker.is_child_of(directory, source)) return false
|
|
32
|
+
|
|
33
|
+
return is_ship_running(issue, directory)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const lane_handoff = { is_handed_off, is_ship_running }
|
|
37
|
+
|
|
38
|
+
export { lane_handoff }
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { fileURLToPath } from 'node:url'
|
|
3
3
|
import { parseArgs } from 'node:util'
|
|
4
4
|
import { josh_command } from '#scripts/josh/josh-run'
|
|
5
|
+
import { INSTALL_TIMEOUT_MS } from '#scripts/lib/timeouts'
|
|
5
6
|
import { execa } from 'execa'
|
|
6
7
|
|
|
7
8
|
// `josh lane:launch <issue> [--stash <message>]` — one composite command for a `backlogrun` lane-start
|
|
@@ -57,6 +58,7 @@ function read_context(argv: ReadonlyArray<string>): LaunchContext | undefined {
|
|
|
57
58
|
async function install(directory: string): Promise<boolean> {
|
|
58
59
|
const result = await execa(PNPM, ['--dir', directory, 'install', '--frozen-lockfile'], {
|
|
59
60
|
reject: false,
|
|
61
|
+
timeout: INSTALL_TIMEOUT_MS,
|
|
60
62
|
})
|
|
61
63
|
|
|
62
64
|
if ((result.exitCode ?? FAILURE_EXIT_CODE) === SUCCESS_EXIT_CODE) return true
|
|
@@ -82,29 +84,37 @@ async function prepare(stash: string | undefined, directory: string): Promise<bo
|
|
|
82
84
|
return await install(directory)
|
|
83
85
|
}
|
|
84
86
|
|
|
85
|
-
//
|
|
86
|
-
//
|
|
87
|
-
|
|
87
|
+
// Where the chain ended. `unopened` is a `lane:open` refusal — no lane was taken; `failed` is a step
|
|
88
|
+
// after it, which leaves the opened lane holding a seat, so a caller cannot read the two alike
|
|
89
|
+
// (joshuafolkken/kit#3027).
|
|
90
|
+
type LaunchOutcome = { kind: 'launched'; pid: string } | { kind: 'unopened' } | { kind: 'failed' }
|
|
91
|
+
|
|
92
|
+
const UNOPENED: LaunchOutcome = { kind: 'unopened' }
|
|
93
|
+
const FAILED: LaunchOutcome = { kind: 'failed' }
|
|
94
|
+
|
|
95
|
+
// The launch chain in-process. The CLI prints the pid; `backlog:drive` launches through this same
|
|
96
|
+
// chain (joshuafolkken/kit#2508).
|
|
97
|
+
async function launch_lane(context: LaunchContext): Promise<LaunchOutcome> {
|
|
88
98
|
const opened = await josh_command.josh_run(['lane:open', context.issue], should_forward_stderr)
|
|
89
99
|
|
|
90
|
-
if (opened.code !== SUCCESS_EXIT_CODE) return
|
|
100
|
+
if (opened.code !== SUCCESS_EXIT_CODE) return UNOPENED
|
|
91
101
|
|
|
92
|
-
if (!(await prepare(context.stash, opened.out))) return
|
|
102
|
+
if (!(await prepare(context.stash, opened.out))) return FAILED
|
|
93
103
|
|
|
94
104
|
const dispatched = await josh_command.josh_run(
|
|
95
105
|
['lane:dispatch', context.issue],
|
|
96
106
|
should_forward_stderr,
|
|
97
107
|
)
|
|
98
108
|
|
|
99
|
-
return dispatched.code === SUCCESS_EXIT_CODE ? dispatched.out :
|
|
109
|
+
return dispatched.code === SUCCESS_EXIT_CODE ? { kind: 'launched', pid: dispatched.out } : FAILED
|
|
100
110
|
}
|
|
101
111
|
|
|
102
112
|
async function launch(context: LaunchContext): Promise<number> {
|
|
103
|
-
const
|
|
113
|
+
const outcome = await launch_lane(context)
|
|
104
114
|
|
|
105
|
-
if (
|
|
115
|
+
if (outcome.kind !== 'launched') return FAILURE_EXIT_CODE
|
|
106
116
|
|
|
107
|
-
console.info(pid)
|
|
117
|
+
console.info(outcome.pid)
|
|
108
118
|
|
|
109
119
|
return SUCCESS_EXIT_CODE
|
|
110
120
|
}
|
|
@@ -125,9 +135,9 @@ async function main(argv: ReadonlyArray<string>): Promise<void> {
|
|
|
125
135
|
process.exitCode = await run(argv)
|
|
126
136
|
}
|
|
127
137
|
|
|
128
|
-
const lane_launch_cli = {
|
|
138
|
+
const lane_launch_cli = { launch_lane, read_context, run }
|
|
129
139
|
|
|
130
140
|
if (process.argv[1] === fileURLToPath(import.meta.url)) await main(process.argv.slice(ARGV_OFFSET))
|
|
131
141
|
|
|
132
|
-
export type { LaunchContext }
|
|
142
|
+
export type { LaunchContext, LaunchOutcome }
|
|
133
143
|
export { lane_launch_cli }
|
|
@@ -217,6 +217,14 @@ async function list_lanes(): Promise<Array<LaneInfo>> {
|
|
|
217
217
|
return lanes.toSorted((left, right) => Number(left.issue) - Number(right.issue))
|
|
218
218
|
}
|
|
219
219
|
|
|
220
|
+
// The lanes a parent is still waiting on. A stranded lane has no child working in it, so it is not
|
|
221
|
+
// in-flight — the one definition the watcher guard and the headless stop rule both read.
|
|
222
|
+
async function has_lanes_in_flight(): Promise<boolean> {
|
|
223
|
+
const lanes = await list_lanes()
|
|
224
|
+
|
|
225
|
+
return lanes.some((lane) => !lane.is_stranded)
|
|
226
|
+
}
|
|
227
|
+
|
|
220
228
|
/** The seats live lanes hold — what a new lane's seat has to avoid. */
|
|
221
229
|
function used_seats(lanes: ReadonlyArray<LaneInfo>): Array<number> {
|
|
222
230
|
return lanes.map((lane) => lane.seat).filter((seat): seat is number => seat !== undefined)
|
|
@@ -246,6 +254,7 @@ async function find_open_lane(issue: string): Promise<LaneInfo | undefined> {
|
|
|
246
254
|
const lane_registry = {
|
|
247
255
|
find_lane,
|
|
248
256
|
find_open_lane,
|
|
257
|
+
has_lanes_in_flight,
|
|
249
258
|
list_lanes,
|
|
250
259
|
main_repository_root,
|
|
251
260
|
parse_block,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { agent_role_profile } from '#scripts/agent/agent-role-profile'
|
|
2
|
+
import { issue_cite, type IssueCiter } from '#scripts/issue/issue-cite'
|
|
2
3
|
import { run_liveness } from '#scripts/run/run-liveness'
|
|
3
4
|
import type { LaneInfo } from './lane-registry'
|
|
4
5
|
|
|
@@ -48,9 +49,14 @@ function event_column(lane: LaneInfo): string {
|
|
|
48
49
|
return state ?? 'agent -'
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
|
|
52
|
+
// The plain `#N`, for a caller that could not read the repository the issue would link into.
|
|
53
|
+
const PLAIN_CITE: IssueCiter = issue_cite.citer(undefined, new Map())
|
|
54
|
+
|
|
55
|
+
// The issue leads as a citation (joshuafolkken/kit#2943): a lane status report copies this row, and a
|
|
56
|
+
// bare `#N` copied into it is what the Stop guard sends back.
|
|
57
|
+
function describe_lane(lane: LaneInfo, cite: IssueCiter = PLAIN_CITE): string {
|
|
52
58
|
return [
|
|
53
|
-
|
|
59
|
+
cite(lane.issue),
|
|
54
60
|
`seat ${value_or_unknown(lane.seat)}`,
|
|
55
61
|
`dev ${value_or_unknown(lane.development_port)}`,
|
|
56
62
|
`preview ${value_or_unknown(lane.preview_port)}`,
|
|
@@ -63,10 +69,10 @@ function describe_lane(lane: LaneInfo): string {
|
|
|
63
69
|
].join(COLUMN_SEPARATOR)
|
|
64
70
|
}
|
|
65
71
|
|
|
66
|
-
function describe_lanes(lanes: ReadonlyArray<LaneInfo
|
|
72
|
+
function describe_lanes(lanes: ReadonlyArray<LaneInfo>, cite: IssueCiter = PLAIN_CITE): string {
|
|
67
73
|
if (lanes.length === 0) return NO_LANES
|
|
68
74
|
|
|
69
|
-
return lanes.map((lane) => describe_lane(lane)).join('\n')
|
|
75
|
+
return lanes.map((lane) => describe_lane(lane, cite)).join('\n')
|
|
70
76
|
}
|
|
71
77
|
|
|
72
78
|
function describe_ports(lane: LaneInfo): string {
|
|
@@ -17,7 +17,9 @@ async function wait_for_ship(issue: string, prior_launch: string | undefined): P
|
|
|
17
17
|
if (read === undefined || read.launch_id === prior_launch) return 'none'
|
|
18
18
|
|
|
19
19
|
while (read.result === 'running') {
|
|
20
|
+
// eslint-disable-next-line no-await-in-loop -- polling: each read waits on the state the previous one saw
|
|
20
21
|
await sleep(POLL_MS)
|
|
22
|
+
// eslint-disable-next-line no-await-in-loop -- polling: each read waits on the state the previous one saw
|
|
21
23
|
read = await current(issue)
|
|
22
24
|
if (read === undefined) return 'abnormal'
|
|
23
25
|
}
|
|
@@ -48,6 +48,7 @@ async function is_approved(lane_directory: string, nonce: string): Promise<boole
|
|
|
48
48
|
const decision = read(lane_directory, nonce)?.decision
|
|
49
49
|
if (decision !== undefined) return decision === 'approved'
|
|
50
50
|
|
|
51
|
+
// eslint-disable-next-line no-await-in-loop -- polling: each read waits on the state the previous one saw
|
|
51
52
|
await new Promise((resolve) => setTimeout(resolve, APPROVAL_POLL_MS))
|
|
52
53
|
}
|
|
53
54
|
|
|
@@ -58,6 +59,6 @@ function remove(lane_directory: string, nonce: string): void {
|
|
|
58
59
|
stamp_file.remove_stamp(target(lane_directory, nonce))
|
|
59
60
|
}
|
|
60
61
|
|
|
61
|
-
const openai_lane_supervisor_decision = { approve, cancel, is_approved, remove
|
|
62
|
+
const openai_lane_supervisor_decision = { approve, cancel, is_approved, remove }
|
|
62
63
|
|
|
63
64
|
export { openai_lane_supervisor_decision }
|
|
@@ -4,6 +4,7 @@ import { fileURLToPath } from 'node:url'
|
|
|
4
4
|
import { agent_argv } from '#scripts/agent/agent-argv'
|
|
5
5
|
import type { AgentProfile } from '#scripts/agent/agent-role-profile'
|
|
6
6
|
import { process_identity } from '#scripts/josh/process-identity'
|
|
7
|
+
import { process_owner_schema } from '#scripts/josh/process-owner'
|
|
7
8
|
import { stamp_file } from '#scripts/josh/stamp-file'
|
|
8
9
|
import { detached_launch, type LaunchArgv } from '#scripts/run/detached-launch'
|
|
9
10
|
import { run_cut, type RunCut } from '#scripts/run/run-cut'
|
|
@@ -22,11 +23,12 @@ const CHILD_POLL_MS = 250
|
|
|
22
23
|
const CLAIM_POLL_MS = 50
|
|
23
24
|
const CLAIM_POLL_LIMIT = 40
|
|
24
25
|
const SUPERVISOR_SCRIPT = fileURLToPath(new URL('openai-lane-supervisor-cli.ts', import.meta.url))
|
|
25
|
-
|
|
26
|
+
// The shared owner pair, with the pid narrowed: this record is written only by a live supervisor, so a
|
|
27
|
+
// pid that is not a real one marks it as corrupt rather than as a dead owner.
|
|
28
|
+
const owner_schema = process_owner_schema.extend({
|
|
26
29
|
issue: z.string(),
|
|
27
30
|
nonce: z.string(),
|
|
28
31
|
pid: z.number().int().positive(),
|
|
29
|
-
process_start: z.string().optional(),
|
|
30
32
|
})
|
|
31
33
|
const state_schema = z.object({
|
|
32
34
|
owner_nonce: z.string(),
|
|
@@ -81,6 +83,7 @@ async function wait_for_active(lane_directory: string): Promise<SupervisorOwner
|
|
|
81
83
|
for (let attempt = 0; attempt < CLAIM_POLL_LIMIT; attempt += 1) {
|
|
82
84
|
const owner = active(lane_directory)
|
|
83
85
|
if (owner !== undefined) return owner
|
|
86
|
+
// eslint-disable-next-line no-await-in-loop -- polling: each read waits on the state the previous one saw
|
|
84
87
|
await new Promise((resolve) => setTimeout(resolve, CLAIM_POLL_MS))
|
|
85
88
|
}
|
|
86
89
|
|
|
@@ -298,6 +301,7 @@ async function wait_for_inherited_child(
|
|
|
298
301
|
child_process_start: string | undefined,
|
|
299
302
|
): Promise<void> {
|
|
300
303
|
while (process_identity.is_same_process(child_pid, child_process_start) !== false) {
|
|
304
|
+
// eslint-disable-next-line no-await-in-loop -- polling: each read waits on the state the previous one saw
|
|
301
305
|
await new Promise((resolve) => setTimeout(resolve, CHILD_POLL_MS))
|
|
302
306
|
}
|
|
303
307
|
}
|
|
@@ -350,10 +354,8 @@ const openai_lane_supervisor = {
|
|
|
350
354
|
approve: openai_lane_supervisor_decision.approve,
|
|
351
355
|
cancel: openai_lane_supervisor_decision.cancel,
|
|
352
356
|
claim,
|
|
353
|
-
decision_path: openai_lane_supervisor_decision.target,
|
|
354
357
|
marker_path,
|
|
355
358
|
new_nonce: randomUUID,
|
|
356
|
-
read,
|
|
357
359
|
release,
|
|
358
360
|
state_path,
|
|
359
361
|
supervise,
|
|
@@ -138,9 +138,11 @@ async function serve(
|
|
|
138
138
|
|
|
139
139
|
if (received?.session === session && received.nonce !== last_nonce) {
|
|
140
140
|
last_nonce = received.nonce
|
|
141
|
+
// eslint-disable-next-line no-await-in-loop -- requests are served one at a time, in arrival order
|
|
141
142
|
await process_request(lane, response, received, state)
|
|
142
143
|
}
|
|
143
144
|
|
|
145
|
+
// eslint-disable-next-line no-await-in-loop -- polling: each read waits on the state the previous one saw
|
|
144
146
|
await sleep(POLL_MS)
|
|
145
147
|
}
|
|
146
148
|
}
|
|
@@ -232,6 +234,7 @@ async function wait_response(target: string, session: string, nonce: string): Pr
|
|
|
232
234
|
const verdict = response_verdict(read_record(target, response_schema), session, nonce)
|
|
233
235
|
if (verdict !== 'wait') return verdict === 'success'
|
|
234
236
|
|
|
237
|
+
// eslint-disable-next-line no-await-in-loop -- polling: each read waits on the state the previous one saw
|
|
235
238
|
await sleep(POLL_MS)
|
|
236
239
|
}
|
|
237
240
|
|
|
@@ -70,6 +70,7 @@ async function drain<Item, Result>(
|
|
|
70
70
|
const [index, item] = entry
|
|
71
71
|
|
|
72
72
|
try {
|
|
73
|
+
// eslint-disable-next-line no-await-in-loop -- one consumer runs one task at a time; the pool's width is the concurrency
|
|
73
74
|
pool.results.push({ index, value: await worker(item, index) })
|
|
74
75
|
} catch (error) {
|
|
75
76
|
pool.failures.push(error)
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
// Reading JSON that may not be JSON (joshuafolkken/kit#1151).
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// answers "could not read this" rather than throwing, because a single bad line
|
|
6
|
-
// whole report. They had begun to carry a copy of the same try/catch each; this is the
|
|
3
|
+
// Readers under `scripts/` parse text that a defect, a truncated write or an older format can make
|
|
4
|
+
// unparseable — a transcript line, a settings file, an MCP declaration, a lock record, CLI output —
|
|
5
|
+
// and every one of them answers "could not read this" rather than throwing, because a single bad line
|
|
6
|
+
// must not fail a whole report. They had begun to carry a copy of the same try/catch each; this is the
|
|
7
|
+
// one copy, and `is_record` beside it is the one object test (joshuafolkken/kit#2986).
|
|
7
8
|
|
|
8
9
|
function parse_or_undefined(text: string): unknown {
|
|
9
10
|
try {
|
package/scripts/lib/poll.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// One bounded polling loop and one sleep, in one place.
|
|
2
2
|
//
|
|
3
|
-
// **Three modules had already written the same three-line `sleep`** — `
|
|
3
|
+
// **Three modules had already written the same three-line `sleep`** — `gh/git-pr-checks.ts`,
|
|
4
4
|
// `eval/eval-run.ts` and `propagate/propagate-publish.ts` — and the release command's tag watch
|
|
5
5
|
// (joshuafolkken/kit#1169) would have been the fourth. `CLAUDE.md` → "No clones — single-source"
|
|
6
6
|
// reads an existing duplication as the signal to single-source it rather than as a license to add to
|
|
@@ -43,8 +43,10 @@ async function poll_until(is_done: () => Promise<boolean>, options: PollOptions)
|
|
|
43
43
|
const wait = options.sleeper ?? sleep
|
|
44
44
|
|
|
45
45
|
for (let attempt = 0; attempt < options.attempts; attempt += 1) {
|
|
46
|
+
// eslint-disable-next-line no-await-in-loop -- polling: each read waits on the state the previous one saw
|
|
46
47
|
if (await is_done()) return true
|
|
47
48
|
|
|
49
|
+
// eslint-disable-next-line no-await-in-loop -- polling: each read waits on the state the previous one saw
|
|
48
50
|
await wait_between(wait, options.interval_ms, attempt, options.attempts)
|
|
49
51
|
}
|
|
50
52
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { FETCH_TIMEOUT_MS } from './timeouts'
|
|
2
|
+
|
|
3
|
+
// **The one place in `scripts/` that calls the global `fetch`** (joshuafolkken/kit#2981). Every request
|
|
4
|
+
// carries a time limit, so a stalled connection rejects instead of holding an unattended run forever;
|
|
5
|
+
// `timed-fetch-usage.test.ts` refuses a direct `fetch` call anywhere else. The signal also bounds the
|
|
6
|
+
// body read, because the response stream aborts with it.
|
|
7
|
+
async function timed_fetch(
|
|
8
|
+
url: string,
|
|
9
|
+
init: Omit<RequestInit, 'signal'> = {},
|
|
10
|
+
timeout_ms: number = FETCH_TIMEOUT_MS,
|
|
11
|
+
): Promise<Response> {
|
|
12
|
+
return await fetch(url, { ...init, signal: AbortSignal.timeout(timeout_ms) })
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export { timed_fetch }
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Shared time limits for the calls that leave the process — a network request or a spawned command.
|
|
2
|
+
// An unattended run (a lane, `followup`, a backlog drain) that waits on a request or a command with no
|
|
3
|
+
// limit stays stuck where it stopped and never comes back (joshuafolkken/kit#2981), so every such
|
|
4
|
+
// call takes one of these, and a value used in more than one place is named once here.
|
|
5
|
+
|
|
6
|
+
// One HTTP request to a registry, an API or a webhook.
|
|
7
|
+
const FETCH_TIMEOUT_MS = 10_000
|
|
8
|
+
// A short command that only answers a question (`gh --version`, `pnpm config get`).
|
|
9
|
+
const COMMAND_TIMEOUT_MS = 30_000
|
|
10
|
+
// A `pnpm install`, which can download the whole dependency tree on a cold store.
|
|
11
|
+
const INSTALL_TIMEOUT_MS = 600_000
|
|
12
|
+
|
|
13
|
+
export { COMMAND_TIMEOUT_MS, FETCH_TIMEOUT_MS, INSTALL_TIMEOUT_MS }
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { json_value } from '#scripts/lib/json-value'
|
|
1
2
|
import { json_object_schema } from '#scripts/lib/schemas'
|
|
2
3
|
import { load, loadAll, YAMLException } from 'js-yaml'
|
|
3
4
|
|
|
@@ -25,8 +26,9 @@ function parse_yaml(content: string): Record<string, unknown> {
|
|
|
25
26
|
return json_object_schema.parse(raw)
|
|
26
27
|
}
|
|
27
28
|
|
|
29
|
+
// A YAML mapping parses to the same plain object a JSON object does, so the test is `json_value`'s.
|
|
28
30
|
function is_mapping_document(value: unknown): value is Record<string, unknown> {
|
|
29
|
-
return
|
|
31
|
+
return json_value.is_record(value)
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
// pnpm 11 writes pnpm-lock.yaml as a multi-document stream (the package-manager document, then the
|