@joshuafolkken/kit 1.1166.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 +9 -5
- package/.claude/skills/workflow-commands/backlogrun-park.md +29 -9
- 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 +24 -15
- 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 +10 -5
- 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 +47 -33
- 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-DYAVAM6S.js → chunk-55HHG5PX.js} +1405 -631
- package/dist/hooks/{chunk-A6P7PN7P.js → chunk-5VMKCCC4.js} +25 -10
- package/dist/hooks/chunk-5VNDSNG3.js +12 -0
- package/dist/hooks/{chunk-5KTCMCOT.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-ENA7P5FB.js → chunk-F56MFS4B.js} +3 -3
- package/dist/hooks/{chunk-ANJ2WGFD.js → chunk-FIVDHQGT.js} +7 -6
- package/dist/hooks/{chunk-3V37IID6.js → chunk-JBBMAPC4.js} +23 -14
- package/dist/hooks/{chunk-GU5MATVE.js → chunk-JUDKDCDP.js} +499 -389
- package/dist/hooks/{chunk-ZDZ555YH.js → chunk-NV2JRZZO.js} +743 -909
- package/dist/hooks/{chunk-V2BTOZHT.js → chunk-RNWHN5BP.js} +3 -3
- package/dist/hooks/{chunk-URJA6XY4.js → chunk-TQNPDZNH.js} +4 -4
- package/dist/hooks/{chunk-GYNGP7HI.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 +232 -210
- 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 +81 -59
- package/dist/josh.js +872 -75
- 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 +31 -9
- package/scripts/backlog/backlog-offer-cli.ts +6 -6
- package/scripts/backlog/backlog-offer.ts +1 -1
- package/scripts/backlog/backlog-plan-cli.ts +7 -6
- package/scripts/backlog/backlog-pool.ts +57 -11
- package/scripts/backlog/backlog-rank.ts +18 -9
- package/scripts/backlog/backlog-ready.ts +1 -1
- package/scripts/backlog/backlog-restructure.ts +152 -0
- 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/backlog/backlog-waves.ts +15 -17
- 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/cost-runtime/context-cut-threshold.ts +1 -9
- package/scripts/cost-runtime/cost-verdict.ts +15 -28
- 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-followup-stages.ts +9 -0
- package/scripts/followup/git-pr-followup-checks.ts +142 -0
- package/scripts/followup/git-pr-followup.ts +5 -130
- 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-issue.ts +5 -3
- package/scripts/gh/git-gh-pr-read.ts +68 -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 +9 -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 +18 -6
- 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 +12 -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/{schemas.ts → git-schemas.ts} +2 -0
- 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/git/main-merge.ts +57 -21
- 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 +11 -1
- 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 +35 -3
- 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-notify.ts +26 -1
- 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 +3 -3
- 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} +12 -6
- 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} +3 -3
- package/scripts/run/{run-cut-report.ts → cut/run-cut-report.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} +29 -8
- 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-next.ts → ship/run-ship-next.ts} +13 -0
- package/scripts/run/ship/run-ship-pre-detach.ts +66 -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} +10 -6
- 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-stage.ts → ship/run-ship-stage.ts} +13 -0
- package/scripts/run/{run-ship-steps.ts → ship/run-ship-steps.ts} +15 -8
- package/scripts/run/ship/run-ship-stop-text.ts +13 -0
- package/scripts/run/ship/run-ship-sync.ts +128 -0
- package/scripts/run/{run-ship.ts → ship/run-ship.ts} +6 -0
- 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} +31 -9
- 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} +99 -17
- 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/test-red-logic.ts +17 -2
- package/scripts/test/test-red.ts +8 -7
- 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/time-runtime/time-transcript-line.ts +27 -1
- 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/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-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-review.ts → ship/run-ship-review.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
|
@@ -11,12 +11,12 @@
|
|
|
11
11
|
* major equals the `packageManager` pin keeps both invariants: never below the adopted
|
|
12
12
|
* major, and advancing while that major is the current one.
|
|
13
13
|
*
|
|
14
|
-
* The `
|
|
15
|
-
* safe-chain filters the registry only when the process tree was launched through one
|
|
16
|
-
* its wrapped shell commands, so `josh latest` and `pnpm josh latest` used to resolve
|
|
14
|
+
* The `minimumReleaseAge` quarantine is applied natively from `pnpm-workspace.yaml` (kit#768,
|
|
15
|
+
* #3267). safe-chain filters the registry only when the process tree was launched through one
|
|
16
|
+
* of its wrapped shell commands, so `josh latest` and `pnpm josh latest` used to resolve
|
|
17
17
|
* different answers and the pin oscillated. Reading the window from the repo-managed
|
|
18
|
-
*
|
|
19
|
-
* invocation context; right after a pnpm release the answer is simply the previous
|
|
18
|
+
* `pnpm-workspace.yaml` and filtering by publish timestamp makes the resolution identical in
|
|
19
|
+
* every invocation context; right after a pnpm release the answer is simply the previous
|
|
20
20
|
* release, exactly as the filtered view behaved.
|
|
21
21
|
*
|
|
22
22
|
* The resolved version is floored at the current `packageManager` pin: a filtered registry
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
import { readFileSync, writeFileSync } from 'node:fs'
|
|
39
39
|
import { fileURLToPath } from 'node:url'
|
|
40
40
|
import { json_value } from '#scripts/lib/json-value'
|
|
41
|
+
import { COMMAND_TIMEOUT_MS } from '#scripts/lib/timeouts'
|
|
41
42
|
import { execaSync } from 'execa'
|
|
42
43
|
import semver from 'semver'
|
|
43
44
|
import { z } from 'zod'
|
|
@@ -49,8 +50,7 @@ const PACKAGE_MANAGER_RE = /"packageManager"\s*:\s*"pnpm@(\d+)(?:[^\d]|$)/u
|
|
|
49
50
|
const PINNED_VERSION_RE = /"packageManager"\s*:\s*"pnpm@([^"+]+)/u
|
|
50
51
|
const TARGET_PREFIX = 'pnpm@'
|
|
51
52
|
const FAILURE_EXIT_CODE = 1
|
|
52
|
-
const
|
|
53
|
-
const VIEW_TIMEOUT_MS = 30_000
|
|
53
|
+
const WORKSPACE_PATH = 'pnpm-workspace.yaml'
|
|
54
54
|
const SHA512_BYTES = 64
|
|
55
55
|
const INTEGRITY_RE = /^sha512-([A-Za-z0-9+/]+={0,2})$/u
|
|
56
56
|
const PACKAGE_MANAGER_VALUE_RE = /("packageManager"\s*:\s*")pnpm@[^"]+(")/u
|
|
@@ -121,7 +121,7 @@ function extract_times_json(stdout: string): Record<string, string> | undefined
|
|
|
121
121
|
function query_release_times(): Record<string, string> | undefined {
|
|
122
122
|
const result = execaSync('pnpm', ['view', 'pnpm', 'time', '--json'], {
|
|
123
123
|
reject: false,
|
|
124
|
-
timeout:
|
|
124
|
+
timeout: COMMAND_TIMEOUT_MS,
|
|
125
125
|
})
|
|
126
126
|
if ((result.exitCode ?? FAILURE_EXIT_CODE) !== 0) return undefined
|
|
127
127
|
|
|
@@ -134,14 +134,14 @@ function query_major_latest_version(major: string): string | undefined {
|
|
|
134
134
|
const times = query_release_times()
|
|
135
135
|
if (times === undefined) return undefined
|
|
136
136
|
|
|
137
|
-
// The project's own
|
|
138
|
-
// latest` reads `package.json` and writes the pnpm pin relative to the working
|
|
139
|
-
// has no subdirectory case — and honouring
|
|
140
|
-
// project that declares none (joshuafolkken/kit#808).
|
|
137
|
+
// The project's own `pnpm-workspace.yaml`, deliberately not the upward walk the version check
|
|
138
|
+
// uses: `josh latest` reads `package.json` and writes the pnpm pin relative to the working
|
|
139
|
+
// directory, so it has no subdirectory case — and honouring an ancestor's policy here could freeze
|
|
140
|
+
// pnpm bumps in a project that declares none (joshuafolkken/kit#808).
|
|
141
141
|
return release_age.select_aged_version(
|
|
142
142
|
times,
|
|
143
143
|
major,
|
|
144
|
-
release_age.read_minimum_release_age(
|
|
144
|
+
release_age.read_minimum_release_age(WORKSPACE_PATH),
|
|
145
145
|
Date.now(),
|
|
146
146
|
)
|
|
147
147
|
}
|
|
@@ -156,7 +156,7 @@ function parse_latest_version(stdout: string): string | undefined {
|
|
|
156
156
|
function query_latest_version(): string | undefined {
|
|
157
157
|
const result = execaSync('pnpm', ['view', 'pnpm', 'version', '--json'], {
|
|
158
158
|
reject: false,
|
|
159
|
-
timeout:
|
|
159
|
+
timeout: COMMAND_TIMEOUT_MS,
|
|
160
160
|
})
|
|
161
161
|
if ((result.exitCode ?? FAILURE_EXIT_CODE) !== 0) return undefined
|
|
162
162
|
|
|
@@ -179,8 +179,8 @@ function warn_skip(reason: string): void {
|
|
|
179
179
|
console.warn(`⚠ Skipped pnpm bump (${reason}); the chain continues.`)
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
-
function warn_unresolved(major: string | undefined): void {
|
|
183
|
-
warn_skip(`no pnpm ${major
|
|
182
|
+
function warn_unresolved(major: string | undefined = ''): void {
|
|
183
|
+
warn_skip(`no pnpm ${major} release resolvable from the registry`)
|
|
184
184
|
}
|
|
185
185
|
|
|
186
186
|
function run_pnpm_update(target: string): number {
|
|
@@ -247,7 +247,7 @@ function extract_encoded_integrity(stdout: string): string | undefined {
|
|
|
247
247
|
function query_integrity(target: string): string | undefined {
|
|
248
248
|
const result = execaSync('pnpm', ['view', target, 'dist.integrity', '--json'], {
|
|
249
249
|
reject: false,
|
|
250
|
-
timeout:
|
|
250
|
+
timeout: COMMAND_TIMEOUT_MS,
|
|
251
251
|
})
|
|
252
252
|
if ((result.exitCode ?? FAILURE_EXIT_CODE) !== 0) return undefined
|
|
253
253
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { package_with_deps_schema } from '#scripts/overrides/schemas'
|
|
1
|
+
import { package_with_deps_schema } from '#scripts/overrides/overrides-schemas'
|
|
2
2
|
import semver from 'semver'
|
|
3
3
|
|
|
4
4
|
// `pnpm update --latest` sets each range to whatever the registry reports as newest. When a
|
|
@@ -13,7 +13,7 @@ import { overrides_check } from '#scripts/overrides/overrides-logic'
|
|
|
13
13
|
import { execaSync } from 'execa'
|
|
14
14
|
import { fresh_metadata_cache } from './fresh-metadata-cache'
|
|
15
15
|
import { latest_regression, type VersionRegression } from './latest-regression'
|
|
16
|
-
import {
|
|
16
|
+
import { safe_chain_version_update } from './safe-chain-version-update'
|
|
17
17
|
|
|
18
18
|
const PACKAGE_JSON_PATH = 'package.json'
|
|
19
19
|
const LOCKFILE_PATH = 'pnpm-lock.yaml'
|
|
@@ -175,11 +175,11 @@ function main(): void {
|
|
|
175
175
|
report_overrides(overrides)
|
|
176
176
|
report_lockfile_overrides()
|
|
177
177
|
|
|
178
|
-
// Skipped after a rollback so the tree really is left exactly as it was found — this sync
|
|
179
|
-
//
|
|
178
|
+
// Skipped after a rollback so the tree really is left exactly as it was found — this sync rewrites
|
|
179
|
+
// the workflows' pinned safe-chain installer, which would contradict the notice that
|
|
180
180
|
// nothing changed.
|
|
181
181
|
if (outcome.status === 0 && !outcome.is_rolled_back) {
|
|
182
|
-
|
|
182
|
+
safe_chain_version_update.sync()
|
|
183
183
|
}
|
|
184
184
|
}
|
|
185
185
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { json_value } from '#scripts/lib/json-value'
|
|
2
|
+
import { FETCH_TIMEOUT_MS } from '#scripts/lib/timeouts'
|
|
2
3
|
import { migrate_logic } from '#scripts/registry-migration/migrate-logic'
|
|
3
4
|
import { execaSync } from 'execa'
|
|
5
|
+
import semver from 'semver'
|
|
4
6
|
import { z } from 'zod'
|
|
5
7
|
import { release_age } from './release-age'
|
|
6
8
|
|
|
@@ -12,7 +14,6 @@ const PUBLIC_REGISTRY = 'https://registry.npmjs.org'
|
|
|
12
14
|
// The abbreviated packument carries `dist-tags` without every version's full manifest.
|
|
13
15
|
const ABBREVIATED_ACCEPT = 'application/vnd.npm.install-v1+json'
|
|
14
16
|
const FULL_ACCEPT = 'application/json'
|
|
15
|
-
const REQUEST_TIMEOUT_MS = 10_000
|
|
16
17
|
const SCOPE_SEPARATOR = '/'
|
|
17
18
|
const ENCODED_SCOPE_SEPARATOR = '%2f'
|
|
18
19
|
const SCOPE_PATTERN = /^@[^/]+(?=\/)/u
|
|
@@ -29,7 +30,10 @@ const FETCH_SCRIPT = [
|
|
|
29
30
|
'process.stdout.write(await response.text())',
|
|
30
31
|
].join('\n')
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
// A registry-supplied version is used only when it is exactly a semver version — it ends up inside an
|
|
34
|
+
// install command, so `1.0.0;curl…|sh` or any other text is refused at the source, not downstream.
|
|
35
|
+
const version_schema = z.string().refine((value) => semver.valid(value) === value)
|
|
36
|
+
const latest_schema = z.looseObject({ 'dist-tags': z.looseObject({ latest: version_schema }) })
|
|
33
37
|
const times_schema = z.looseObject({ time: release_age.release_times_schema })
|
|
34
38
|
|
|
35
39
|
// The packument URL for a package name; a scoped name keeps its `@` and encodes the separator, the
|
|
@@ -42,7 +46,7 @@ function read_packument(package_name: string, accept: string): unknown {
|
|
|
42
46
|
const result = execaSync(
|
|
43
47
|
process.execPath,
|
|
44
48
|
['--input-type=module', '-e', FETCH_SCRIPT, packument_url(package_name), accept],
|
|
45
|
-
{ reject: false, timeout:
|
|
49
|
+
{ reject: false, timeout: FETCH_TIMEOUT_MS },
|
|
46
50
|
)
|
|
47
51
|
if (result.exitCode !== 0) return undefined
|
|
48
52
|
|
|
@@ -59,7 +63,7 @@ function is_github_scope(scope: string): boolean {
|
|
|
59
63
|
if (is_cached_github !== undefined) return is_cached_github
|
|
60
64
|
const result = execaSync('pnpm', ['config', 'get', `${scope}${SCOPE_REGISTRY_SUFFIX}`], {
|
|
61
65
|
reject: false,
|
|
62
|
-
timeout:
|
|
66
|
+
timeout: FETCH_TIMEOUT_MS,
|
|
63
67
|
})
|
|
64
68
|
const is_github = result.exitCode === 0 && migrate_logic.is_github_tarball(result.stdout.trim())
|
|
65
69
|
|
|
@@ -102,6 +106,17 @@ function has_public_version(package_name: string, version: string): boolean {
|
|
|
102
106
|
return parsed.success && parsed.data.time[version] !== undefined
|
|
103
107
|
}
|
|
104
108
|
|
|
105
|
-
|
|
109
|
+
// The version itself, or nothing when it is not exactly a semver version.
|
|
110
|
+
function valid_version(value: string): string | undefined {
|
|
111
|
+
return version_schema.safeParse(value).success ? value : undefined
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const npm_registry = {
|
|
115
|
+
has_public_version,
|
|
116
|
+
packument_url,
|
|
117
|
+
read_latest,
|
|
118
|
+
read_release_times,
|
|
119
|
+
valid_version,
|
|
120
|
+
}
|
|
106
121
|
|
|
107
122
|
export { npm_registry }
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { readFileSync } from 'node:fs'
|
|
8
8
|
import { fileURLToPath } from 'node:url'
|
|
9
|
+
import { COMMAND_TIMEOUT_MS } from '#scripts/lib/timeouts'
|
|
9
10
|
import { execaSync } from 'execa'
|
|
10
11
|
import {
|
|
11
12
|
publishable_range,
|
|
@@ -15,7 +16,6 @@ import {
|
|
|
15
16
|
} from './publishable-range'
|
|
16
17
|
|
|
17
18
|
const PACKAGE_JSON_PATH = 'package.json'
|
|
18
|
-
const VIEW_TIMEOUT_MS = 30_000
|
|
19
19
|
const FAILURE_EXIT_CODE = 1
|
|
20
20
|
|
|
21
21
|
// A registry query rather than a direct fetch: safe-chain installs shims ahead of the package
|
|
@@ -29,7 +29,7 @@ const FAILURE_EXIT_CODE = 1
|
|
|
29
29
|
function probe_range(name: string, range: string): ProbeResult {
|
|
30
30
|
const result = execaSync('pnpm', ['view', `${name}@${range}`, 'version'], {
|
|
31
31
|
reject: false,
|
|
32
|
-
timeout:
|
|
32
|
+
timeout: COMMAND_TIMEOUT_MS,
|
|
33
33
|
})
|
|
34
34
|
|
|
35
35
|
return { exit_code: result.exitCode ?? FAILURE_EXIT_CODE, stdout: result.stdout }
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { package_with_deps_schema } from '#scripts/overrides/schemas'
|
|
1
|
+
import { package_with_deps_schema } from '#scripts/overrides/overrides-schemas'
|
|
2
2
|
import semver from 'semver'
|
|
3
3
|
|
|
4
4
|
// kit ships a `preinstall` hook that installs @aikidosec/safe-chain, whose minimum-age policy hides
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs'
|
|
2
2
|
import path from 'node:path'
|
|
3
|
+
import { yaml_document } from '#scripts/lib/yaml-document'
|
|
3
4
|
import semver from 'semver'
|
|
4
5
|
import { z } from 'zod'
|
|
5
6
|
|
|
@@ -7,30 +8,41 @@ import { z } from 'zod'
|
|
|
7
8
|
// safe-chain's interception. safe-chain filters the registry only when the process tree was
|
|
8
9
|
// started through one of its six wrapped shell commands, so `josh latest` and
|
|
9
10
|
// `pnpm josh latest` used to resolve different "newest release" answers. These functions
|
|
10
|
-
// make the resolution deterministic: the policy comes from the repo-managed
|
|
11
|
-
// publish timestamps from the registry, and the selection is a pure computation over both.
|
|
11
|
+
// make the resolution deterministic: the policy comes from the repo-managed `pnpm-workspace.yaml`,
|
|
12
|
+
// the publish timestamps from the registry, and the selection is a pure computation over both.
|
|
13
|
+
// pnpm 12 reads its settings from `pnpm-workspace.yaml` — a `minimum-release-age` line in `.npmrc`
|
|
14
|
+
// is ignored there, so reading it would report a window pnpm does not apply (kit#3267).
|
|
12
15
|
|
|
13
|
-
const MINIMUM_RELEASE_AGE_RE = /^minimum-release-age\s*=\s*(\d+)\s*$/mu
|
|
14
16
|
const NO_QUARANTINE_MINUTES = 0
|
|
15
|
-
const
|
|
17
|
+
const WORKSPACE_PATH = 'pnpm-workspace.yaml'
|
|
18
|
+
const workspace_age_schema = z.object({ minimumReleaseAge: z.number().int().nonnegative() })
|
|
16
19
|
|
|
17
20
|
// A version → ISO publish date map, the shape both the registry and the GitHub Packages API are
|
|
18
21
|
// reduced to before the aged-version selection runs.
|
|
19
22
|
const release_times_schema = z.record(z.string(), z.string())
|
|
20
23
|
const MS_PER_MINUTE = 60_000
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
function parse_workspace(workspace_content: string): unknown {
|
|
26
|
+
try {
|
|
27
|
+
return yaml_document.parse_yaml(workspace_content)
|
|
28
|
+
} catch {
|
|
29
|
+
return undefined
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// The window `pnpm-workspace.yaml` content declares, or nothing when it does not declare one or the
|
|
34
|
+
// document is malformed — an explicit `minimumReleaseAge: 0` stays 0 rather than collapsing into
|
|
35
|
+
// "not declared".
|
|
36
|
+
function parse_declared_minimum_release_age(workspace_content: string): number | undefined {
|
|
37
|
+
const parsed = workspace_age_schema.safeParse(parse_workspace(workspace_content))
|
|
26
38
|
|
|
27
|
-
return
|
|
39
|
+
return parsed.success ? parsed.data.minimumReleaseAge : undefined
|
|
28
40
|
}
|
|
29
41
|
|
|
30
|
-
// The quarantine window in minutes from
|
|
31
|
-
// quarantine, matching pnpm's own default for the setting.
|
|
32
|
-
function parse_minimum_release_age(
|
|
33
|
-
return parse_declared_minimum_release_age(
|
|
42
|
+
// The quarantine window in minutes from `pnpm-workspace.yaml`; a missing or malformed entry means
|
|
43
|
+
// no quarantine, matching pnpm's own default for the setting.
|
|
44
|
+
function parse_minimum_release_age(workspace_content: string): number {
|
|
45
|
+
return parse_declared_minimum_release_age(workspace_content) ?? NO_QUARANTINE_MINUTES
|
|
34
46
|
}
|
|
35
47
|
|
|
36
48
|
// Stable releases only, on the requested major, published at or before the cutoff. The
|
|
@@ -83,49 +95,47 @@ function select_aged_version(
|
|
|
83
95
|
return eligible[0]
|
|
84
96
|
}
|
|
85
97
|
|
|
86
|
-
// The window declared in one
|
|
87
|
-
// declare the setting. Distinguishing "not declared" from "declared as 0" is what lets an
|
|
88
|
-
// `
|
|
89
|
-
function read_declared_minimum_release_age(
|
|
98
|
+
// The window declared in one `pnpm-workspace.yaml`, or nothing when the file is absent, unreadable,
|
|
99
|
+
// or does not declare the setting. Distinguishing "not declared" from "declared as 0" is what lets an
|
|
100
|
+
// explicit `minimumReleaseAge: 0` opt-out stop the walk instead of falling through to an ancestor's.
|
|
101
|
+
function read_declared_minimum_release_age(workspace_path: string): number | undefined {
|
|
90
102
|
try {
|
|
91
|
-
return parse_declared_minimum_release_age(readFileSync(
|
|
103
|
+
return parse_declared_minimum_release_age(readFileSync(workspace_path, 'utf8'))
|
|
92
104
|
} catch {
|
|
93
105
|
return undefined
|
|
94
106
|
}
|
|
95
107
|
}
|
|
96
108
|
|
|
97
|
-
// The quarantine window declared by one specific
|
|
98
|
-
// absent, unreadable, or undeclared setting means no quarantine — the policy is advisory,
|
|
99
|
-
// project without one is not held back.
|
|
109
|
+
// The quarantine window declared by one specific `pnpm-workspace.yaml`, defaulting to the project's
|
|
110
|
+
// own. An absent, unreadable, or undeclared setting means no quarantine — the policy is advisory,
|
|
111
|
+
// and a project without one is not held back.
|
|
100
112
|
//
|
|
101
113
|
// Deliberately not the upward walk below: `josh latest` resolves this against the working directory
|
|
102
|
-
// it also writes `corepack use` into, and honouring
|
|
114
|
+
// it also writes `corepack use` into, and honouring an ancestor's policy there could freeze pnpm
|
|
103
115
|
// bumps in a project that declares none (joshuafolkken/kit#808).
|
|
104
|
-
function read_minimum_release_age(
|
|
105
|
-
return read_declared_minimum_release_age(
|
|
116
|
+
function read_minimum_release_age(workspace_path: string = WORKSPACE_PATH): number {
|
|
117
|
+
return read_declared_minimum_release_age(workspace_path) ?? NO_QUARANTINE_MINUTES
|
|
106
118
|
}
|
|
107
119
|
|
|
108
|
-
// The window declared by the nearest
|
|
120
|
+
// The window declared by the nearest `pnpm-workspace.yaml` at or above `start`, or nothing.
|
|
109
121
|
//
|
|
110
|
-
//
|
|
111
|
-
//
|
|
112
|
-
// alone would silently read "no quarantine" in every subdirectory.
|
|
113
|
-
//
|
|
114
|
-
// not mask a `~/.npmrc` carrying the policy (joshuafolkken/kit#808).
|
|
122
|
+
// This walks rather than reading one path because `josh version` and `josh latest` both run from
|
|
123
|
+
// anywhere inside a project — and from outside one — so resolving against the working directory
|
|
124
|
+
// alone would silently read "no quarantine" in every subdirectory (joshuafolkken/kit#808). pnpm
|
|
125
|
+
// finds its workspace root the same way, by walking up to the nearest `pnpm-workspace.yaml`.
|
|
115
126
|
//
|
|
116
|
-
// `boundary` stops the walk at a known root. Production passes none
|
|
117
|
-
//
|
|
127
|
+
// `boundary` stops the walk at a known root. Production passes none, while tests bound the search
|
|
128
|
+
// so it cannot depend on the directories above the machine's temp root.
|
|
118
129
|
//
|
|
119
|
-
// Simplification:
|
|
120
|
-
//
|
|
121
|
-
//
|
|
122
|
-
//
|
|
123
|
-
// complexity here.
|
|
130
|
+
// Simplification: a nearer workspace file that does not declare the window falls through to an
|
|
131
|
+
// ancestor's, and pnpm's user-level `config.yaml` is not consulted. The consequence is one
|
|
132
|
+
// informational `Held:` line — the value never suppresses a command — so modelling pnpm's exact
|
|
133
|
+
// lookup is not worth its complexity here.
|
|
124
134
|
function find_declared_minimum_release_age(
|
|
125
135
|
start: string,
|
|
126
136
|
boundary: string | undefined,
|
|
127
137
|
): number | undefined {
|
|
128
|
-
const declared = read_declared_minimum_release_age(path.join(start,
|
|
138
|
+
const declared = read_declared_minimum_release_age(path.join(start, WORKSPACE_PATH))
|
|
129
139
|
if (declared !== undefined) return declared
|
|
130
140
|
if (start === boundary) return undefined
|
|
131
141
|
const parent = path.dirname(start)
|
|
@@ -8,7 +8,7 @@ import { release_age } from './release-age'
|
|
|
8
8
|
// is by definition the youngest (joshuafolkken/kit#808).
|
|
9
9
|
//
|
|
10
10
|
// **The window binds unpinned resolution only.** Measured on pnpm 11.22.0 with
|
|
11
|
-
// `
|
|
11
|
+
// `minimumReleaseAge: 1440` and a release published 3.5 h earlier:
|
|
12
12
|
//
|
|
13
13
|
// pnpm add pkg@1.80.0 -> 1.80.0 (pnpm records a `minimumReleaseAgeExclude` entry)
|
|
14
14
|
// pnpm add pkg -> 1.78.0 (the newest release past the window)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { COMMAND_TIMEOUT_MS } from '#scripts/lib/timeouts'
|
|
2
|
+
import { ci_installer_pin } from '#scripts/safe-chain/ci-installer-pin'
|
|
3
|
+
import { npm_registry } from '#scripts/version/npm-registry'
|
|
4
|
+
import { execaSync } from 'execa'
|
|
5
|
+
|
|
6
|
+
const SAFE_CHAIN_PKG = '@aikidosec/safe-chain'
|
|
7
|
+
|
|
8
|
+
// The registry's answer is trusted only as an exact semver version: it ends up in workflow files and
|
|
9
|
+
// in the installer URL (joshuafolkken/kit#3266).
|
|
10
|
+
function fetch_latest_version(): string | undefined {
|
|
11
|
+
const result = execaSync('npm', ['view', SAFE_CHAIN_PKG, 'version'], {
|
|
12
|
+
reject: false,
|
|
13
|
+
timeout: COMMAND_TIMEOUT_MS,
|
|
14
|
+
})
|
|
15
|
+
if (result.exitCode !== 0 || !result.stdout) return undefined
|
|
16
|
+
|
|
17
|
+
return npm_registry.valid_version(result.stdout.trim())
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// The hash-verified installer pinned in the workflows is the one place a safe-chain release is
|
|
21
|
+
// recorded; `preinstall` no longer names one (joshuafolkken/kit#3269). Every repository moves the
|
|
22
|
+
// files that carry the pin — app-kit's own `dast.yml` / `load.yml` included (joshuafolkken/kit#2830).
|
|
23
|
+
function sync(): void {
|
|
24
|
+
const latest = fetch_latest_version()
|
|
25
|
+
|
|
26
|
+
if (latest === undefined) {
|
|
27
|
+
console.warn(`\n⚠ Could not fetch a valid latest version of ${SAFE_CHAIN_PKG}; skipping`)
|
|
28
|
+
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
ci_installer_pin.sync(latest)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const safe_chain_version_update = {
|
|
36
|
+
sync,
|
|
37
|
+
fetch_latest_version,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export { safe_chain_version_update }
|
|
@@ -1,9 +1,28 @@
|
|
|
1
1
|
import type { PackageVersionConfig } from './version-command-config'
|
|
2
2
|
|
|
3
|
+
// One upgrade the version commands offer and run: `text` is the line printed after `Run:`, and
|
|
4
|
+
// `steps` are the argument vectors executed in order, each only after the one before it succeeded.
|
|
5
|
+
// A command kit builds itself is spawned without a shell, so a registry-supplied version is never
|
|
6
|
+
// parsed by one; only the consumer's own configured command goes through `sh -c`.
|
|
7
|
+
interface UpgradeCommand {
|
|
8
|
+
text: string
|
|
9
|
+
steps: ReadonlyArray<ReadonlyArray<string>>
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const STEP_SEPARATOR = ' && '
|
|
13
|
+
|
|
3
14
|
function update_scope_flag(is_local: boolean): string {
|
|
4
15
|
return is_local ? '-D' : '-g'
|
|
5
16
|
}
|
|
6
17
|
|
|
18
|
+
function update_argv(
|
|
19
|
+
latest: string,
|
|
20
|
+
is_local: boolean,
|
|
21
|
+
config: PackageVersionConfig,
|
|
22
|
+
): Array<string> {
|
|
23
|
+
return ['pnpm', 'add', update_scope_flag(is_local), `${config.package_name}@${latest}`]
|
|
24
|
+
}
|
|
25
|
+
|
|
7
26
|
// The bare `pnpm add` invocation that installs one package at an exact version, in the global or the
|
|
8
27
|
// project (dev-dependency) scope.
|
|
9
28
|
function format_update_command(
|
|
@@ -11,20 +30,41 @@ function format_update_command(
|
|
|
11
30
|
is_local: boolean,
|
|
12
31
|
config: PackageVersionConfig,
|
|
13
32
|
): string {
|
|
14
|
-
return
|
|
33
|
+
return update_argv(latest, is_local, config).join(' ')
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// The upgrade for one target. A project-scope install is followed by kit's lockfile repair
|
|
37
|
+
// (`fix-gh-packages`), which a global install does not need. The printed text is derived from the
|
|
38
|
+
// steps, so the hint and what actually runs cannot drift apart.
|
|
39
|
+
function build_upgrade_command(
|
|
40
|
+
latest: string,
|
|
41
|
+
is_local: boolean,
|
|
42
|
+
config: PackageVersionConfig,
|
|
43
|
+
): UpgradeCommand {
|
|
44
|
+
const steps = [update_argv(latest, is_local, config)]
|
|
45
|
+
if (is_local) steps.push(['node_modules/.bin/tsx', config.fix_gh_packages_path])
|
|
46
|
+
|
|
47
|
+
return { text: steps.map((step) => step.join(' ')).join(STEP_SEPARATOR), steps }
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// The consumer's own configured command — `pnpm add -g …`, or a chain with `&&` — is inside the trust
|
|
51
|
+
// boundary and needs a shell to mean what it says.
|
|
52
|
+
function shell_upgrade_command(command: string): UpgradeCommand {
|
|
53
|
+
return { text: command, steps: [['sh', '-c', command]] }
|
|
15
54
|
}
|
|
16
55
|
|
|
17
|
-
// The full shell command for one upgrade target. A project-scope install is chained with kit's
|
|
18
|
-
// lockfile repair (`fix-gh-packages`), which a global install does not need.
|
|
19
56
|
function build_upgrade_shell_command(
|
|
20
57
|
latest: string,
|
|
21
58
|
is_local: boolean,
|
|
22
59
|
config: PackageVersionConfig,
|
|
23
60
|
): string {
|
|
24
|
-
|
|
25
|
-
if (!is_local) return add_command
|
|
26
|
-
|
|
27
|
-
return `${add_command} && node_modules/.bin/tsx ${config.fix_gh_packages_path}`
|
|
61
|
+
return build_upgrade_command(latest, is_local, config).text
|
|
28
62
|
}
|
|
29
63
|
|
|
30
|
-
export {
|
|
64
|
+
export type { UpgradeCommand }
|
|
65
|
+
export {
|
|
66
|
+
build_upgrade_command,
|
|
67
|
+
build_upgrade_shell_command,
|
|
68
|
+
format_update_command,
|
|
69
|
+
shell_upgrade_command,
|
|
70
|
+
}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { release_hold } from './release-hold'
|
|
2
2
|
import { is_no_op_upgrade_command, type InstalledVersions } from './upgrade-command-guard'
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
build_upgrade_command,
|
|
5
|
+
build_upgrade_shell_command,
|
|
6
|
+
format_update_command,
|
|
7
|
+
shell_upgrade_command,
|
|
8
|
+
type UpgradeCommand,
|
|
9
|
+
} from './upgrade-shell-command'
|
|
4
10
|
import type { PackageVersionConfig } from './version-command-config'
|
|
5
11
|
|
|
6
12
|
const NOT_INSTALLED = 'not installed'
|
|
@@ -161,11 +167,11 @@ function resolve_effective_upgrade_hint(report: UpstreamReport): EffectiveUpgrad
|
|
|
161
167
|
// The consumer-supplied global upgrade command for a stale effective upstream, or nothing. Skipped
|
|
162
168
|
// when the consumer did not opt in, the effective install is up to date / unresolved, or the command
|
|
163
169
|
// provably cannot change the effective version it was meant to fix (see the note line instead).
|
|
164
|
-
function build_effective_upgrade_commands(report: UpstreamReport): Array<
|
|
170
|
+
function build_effective_upgrade_commands(report: UpstreamReport): Array<UpgradeCommand> {
|
|
165
171
|
const hint = resolve_effective_upgrade_hint(report)
|
|
166
172
|
if (hint === undefined || hint.is_no_op) return []
|
|
167
173
|
|
|
168
|
-
return [hint.command]
|
|
174
|
+
return [shell_upgrade_command(hint.command)]
|
|
169
175
|
}
|
|
170
176
|
|
|
171
177
|
// The explanation that replaces a suppressed `Run:` hint, so a stale effective install is never left
|
|
@@ -202,8 +208,9 @@ function format_upstream_lines(report: UpstreamReport): Array<string> {
|
|
|
202
208
|
// Drop repeated commands while preserving first-seen order. A consumer with several upstreams can
|
|
203
209
|
// return the same chain-pinning global command from each of them (game-kit returns one command for
|
|
204
210
|
// both app-kit and kit), which would otherwise print an identical `Run:` line once per upstream.
|
|
205
|
-
|
|
206
|
-
|
|
211
|
+
// Keyed on the printed text, which the steps are derived from or carried verbatim inside.
|
|
212
|
+
function unique_upgrade_commands(commands: ReadonlyArray<UpgradeCommand>): Array<UpgradeCommand> {
|
|
213
|
+
return [...new Map(commands.map((command) => [command.text, command])).values()]
|
|
207
214
|
}
|
|
208
215
|
|
|
209
216
|
// The outcome line for an effective install the upgrade command left exactly where it was.
|
|
@@ -235,37 +242,39 @@ function format_effective_outcome(report: UpstreamReport, after: string | undefi
|
|
|
235
242
|
|
|
236
243
|
// The project-scope upgrade command when the upstream's project dependency is installed and stale.
|
|
237
244
|
// Always local (with lockfile repair), since the project path is the only scope kit resolves.
|
|
238
|
-
function build_project_upgrade_commands(report: UpstreamReport): Array<
|
|
245
|
+
function build_project_upgrade_commands(report: UpstreamReport): Array<UpgradeCommand> {
|
|
239
246
|
if (!is_target_stale(report.project_version, report.latest)) return []
|
|
240
247
|
|
|
241
|
-
return [
|
|
248
|
+
return [build_upgrade_command(report.latest, true, report.config)]
|
|
242
249
|
}
|
|
243
250
|
|
|
244
251
|
// Build the upgrade commands for every upstream: the consumer's global command for a stale effective
|
|
245
252
|
// install first, then the project-scope command, mirroring the main report's global-before-project
|
|
246
253
|
// order. Upstreams without either stale target contribute nothing.
|
|
247
|
-
function build_upstream_upgrade_commands(
|
|
254
|
+
function build_upstream_upgrade_commands(
|
|
255
|
+
reports: ReadonlyArray<UpstreamReport>,
|
|
256
|
+
): Array<UpgradeCommand> {
|
|
248
257
|
return reports.flatMap((report) => [
|
|
249
258
|
...build_effective_upgrade_commands(report),
|
|
250
259
|
...build_project_upgrade_commands(report),
|
|
251
260
|
])
|
|
252
261
|
}
|
|
253
262
|
|
|
254
|
-
// Build the
|
|
263
|
+
// Build the upgrade commands for whichever of the two targets are installed and stale.
|
|
255
264
|
// Order: global first, then project (mirrors the display order).
|
|
256
265
|
function build_dual_upgrade_commands(
|
|
257
266
|
snapshot: VersionSnapshot,
|
|
258
267
|
config: PackageVersionConfig,
|
|
259
|
-
): Array<
|
|
268
|
+
): Array<UpgradeCommand> {
|
|
260
269
|
const { global_version, project_version, latest } = snapshot
|
|
261
|
-
const commands: Array<
|
|
270
|
+
const commands: Array<UpgradeCommand> = []
|
|
262
271
|
|
|
263
272
|
if (is_target_stale(global_version, latest)) {
|
|
264
|
-
commands.push(
|
|
273
|
+
commands.push(build_upgrade_command(latest, false, config))
|
|
265
274
|
}
|
|
266
275
|
|
|
267
276
|
if (is_target_stale(project_version, latest)) {
|
|
268
|
-
commands.push(
|
|
277
|
+
commands.push(build_upgrade_command(latest, true, config))
|
|
269
278
|
}
|
|
270
279
|
|
|
271
280
|
return commands
|
|
@@ -298,7 +307,7 @@ function format_dual_version_output(
|
|
|
298
307
|
const hints = unique_upgrade_commands([
|
|
299
308
|
...build_dual_upgrade_commands(snapshot, config),
|
|
300
309
|
...build_upstream_upgrade_commands(upstreams),
|
|
301
|
-
]).map((command) => `Run: ${command}`)
|
|
310
|
+
]).map((command) => `Run: ${command.text}`)
|
|
302
311
|
if (hints.length > 0) lines.push('', ...hints)
|
|
303
312
|
if (extras.warning !== undefined) lines.push('', extras.warning)
|
|
304
313
|
|