@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
|
@@ -2,7 +2,7 @@ function extract_yaml_top_level_keys(content: string): Array<string> {
|
|
|
2
2
|
return content.split('\n').flatMap((line) => {
|
|
3
3
|
const key = /^([a-zA-Z][a-zA-Z0-9_-]*):/u.exec(line)?.[1]
|
|
4
4
|
|
|
5
|
-
return key
|
|
5
|
+
return key ?? []
|
|
6
6
|
})
|
|
7
7
|
}
|
|
8
8
|
|
|
@@ -125,6 +125,45 @@ function add_missing_build_entries(existing: string, template: string): string {
|
|
|
125
125
|
return existing.replace(block, () => [block, ...missing].join('\n'))
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
+
interface MovedNpmrcSetting {
|
|
129
|
+
npmrc_key: string
|
|
130
|
+
workspace_key: string
|
|
131
|
+
value_pattern: RegExp
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// `.npmrc` settings pnpm 12 reads only from `pnpm-workspace.yaml`, with the value shape each takes.
|
|
135
|
+
// A project's own value (a longer age window, `engine-strict=false`) replaces the template's, so the
|
|
136
|
+
// move neither loosens nor tightens what the project chose (joshuafolkken/kit#3267).
|
|
137
|
+
const MOVED_NPMRC_SETTINGS: ReadonlyArray<MovedNpmrcSetting> = [
|
|
138
|
+
{ npmrc_key: 'minimum-release-age', workspace_key: 'minimumReleaseAge', value_pattern: /^\d+$/u },
|
|
139
|
+
{ npmrc_key: 'engine-strict', workspace_key: 'engineStrict', value_pattern: /^(?:true|false)$/u },
|
|
140
|
+
]
|
|
141
|
+
|
|
142
|
+
// The last assignment wins, as it does when npm reads the file.
|
|
143
|
+
function npmrc_value(npmrc: string, key: string): string | undefined {
|
|
144
|
+
const pattern = new RegExp(String.raw`^[ \t]*${key}[ \t]*=[ \t]*(\S+)[ \t]*$`, 'gmu')
|
|
145
|
+
|
|
146
|
+
return [...npmrc.matchAll(pattern)].at(-1)?.[1]
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function carry_npmrc_setting(template: string, npmrc: string, setting: MovedNpmrcSetting): string {
|
|
150
|
+
const value = npmrc_value(npmrc, setting.npmrc_key)
|
|
151
|
+
if (value === undefined || !setting.value_pattern.test(value)) return template
|
|
152
|
+
const line_pattern = new RegExp(`^${setting.workspace_key}:.*$`, 'mu')
|
|
153
|
+
|
|
154
|
+
return template.replace(line_pattern, () => `${setting.workspace_key}: ${value}`)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function carry_npmrc_settings(template: string, npmrc: string): string {
|
|
158
|
+
let result = template
|
|
159
|
+
|
|
160
|
+
for (const setting of MOVED_NPMRC_SETTINGS) {
|
|
161
|
+
result = carry_npmrc_setting(result, npmrc, setting)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return result
|
|
165
|
+
}
|
|
166
|
+
|
|
128
167
|
function merge_workspace_yaml(existing: string, template: string): string {
|
|
129
168
|
if (!existing.trim()) return template
|
|
130
169
|
const normalized = existing.endsWith('\n') ? existing : `${existing}\n`
|
|
@@ -138,6 +177,6 @@ function merge_workspace_yaml(existing: string, template: string): string {
|
|
|
138
177
|
return append_user_blocks(cleaned, new_keys, template)
|
|
139
178
|
}
|
|
140
179
|
|
|
141
|
-
const init_logic_workspace = { merge_workspace_yaml, template_build_values }
|
|
180
|
+
const init_logic_workspace = { carry_npmrc_settings, merge_workspace_yaml, template_build_values }
|
|
142
181
|
|
|
143
182
|
export { init_logic_workspace }
|
|
@@ -14,16 +14,15 @@ const DEV_ENGINES_VALUE = {
|
|
|
14
14
|
packageManager: { name: 'pnpm', version: '>=12.1.0', onFail: 'error' },
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
|
|
17
|
+
// The settings lines earlier kit releases wrote into a project `.npmrc`. pnpm 12 reads only registry
|
|
18
|
+
// and auth settings from `.npmrc`, so all four are inert there: the age window and engine check now
|
|
19
|
+
// live in `pnpm-workspace.yaml`, and `confirmModulesPurge` no longer exists (joshuafolkken/kit#3267).
|
|
20
|
+
const LEGACY_NPMRC_LINES: ReadonlySet<string> = new Set([
|
|
20
21
|
'engine-strict=true',
|
|
21
22
|
'minimum-release-age=1440',
|
|
22
23
|
'confirmModulesPurge=false',
|
|
23
|
-
// Pin full GitHub Packages tarball URLs in the lockfile so pnpm >=11.5 frozen-lockfile
|
|
24
|
-
// installs hit the correct authenticated download path (avoids ERR_PNPM_FETCH_401 on CI).
|
|
25
24
|
'lockfile-include-tarball-url=true',
|
|
26
|
-
]
|
|
25
|
+
])
|
|
27
26
|
|
|
28
27
|
const CSPELL_IMPORT = '@joshuafolkken/kit/cspell'
|
|
29
28
|
|
|
@@ -254,10 +253,6 @@ function generate_cspell_config(): string {
|
|
|
254
253
|
return `version: "0.2"\nimport:\n - "${CSPELL_IMPORT}"\nwords: []\nignorePaths: []\n`
|
|
255
254
|
}
|
|
256
255
|
|
|
257
|
-
function generate_npmrc(): string {
|
|
258
|
-
return `${NPMRC_LINES.join('\n')}\n`
|
|
259
|
-
}
|
|
260
|
-
|
|
261
256
|
// Append `missing` lines to `existing`, inserting a separating newline when the base is
|
|
262
257
|
// non-empty and lacks a trailing one. Returns `existing` untouched when nothing is missing.
|
|
263
258
|
function append_missing_lines(existing: string, missing: ReadonlyArray<string>): string {
|
|
@@ -267,18 +262,19 @@ function append_missing_lines(existing: string, missing: ReadonlyArray<string>):
|
|
|
267
262
|
return `${prefix}${missing.join('\n')}\n`
|
|
268
263
|
}
|
|
269
264
|
|
|
270
|
-
//
|
|
271
|
-
//
|
|
272
|
-
//
|
|
273
|
-
//
|
|
274
|
-
// `PNPM_CONFIG_NPMRC_AUTH_FILE`, for instance) gets
|
|
275
|
-
// live in a deploy platform's dashboard — so no
|
|
276
|
-
// apart from a live one. Deleting it took down a
|
|
277
|
-
//
|
|
265
|
+
// Removes only an exact kit-written legacy line; every other line survives verbatim, including a
|
|
266
|
+
// `_authToken` line the consumer added themselves and a setting carrying a value of their own. Kit
|
|
267
|
+
// removed the env-var auth form until #759, on the premise that pnpm always ignores it in a project
|
|
268
|
+
// .npmrc — true only while `npmrcAuthFile` is unset. A consumer that declares the project file its
|
|
269
|
+
// trusted auth file (Cloudflare Workers Builds via `PNPM_CONFIG_NPMRC_AUTH_FILE`, for instance) gets
|
|
270
|
+
// the credential expanded, and that setting can live in a deploy platform's dashboard — so no
|
|
271
|
+
// reading of the repository tells an inert auth line apart from a live one. Deleting it took down a
|
|
272
|
+
// working production deploy. See docs/authentication.md §4(d).
|
|
278
273
|
function merge_npmrc(content: string): string {
|
|
279
|
-
const
|
|
274
|
+
const lines = content.split('\n')
|
|
275
|
+
const kept = lines.filter((line) => !LEGACY_NPMRC_LINES.has(line.trim()))
|
|
280
276
|
|
|
281
|
-
return
|
|
277
|
+
return kept.length === lines.length ? content : kept.join('\n')
|
|
282
278
|
}
|
|
283
279
|
|
|
284
280
|
// A gitignore line worth appending during a union merge: real ignore patterns only.
|
|
@@ -349,10 +345,6 @@ function strip_kit_only_vscode_settings_content(raw: string): string {
|
|
|
349
345
|
return json_format.format_json(stripped)
|
|
350
346
|
}
|
|
351
347
|
|
|
352
|
-
function get_npmrc_lines(): ReadonlyArray<string> {
|
|
353
|
-
return NPMRC_LINES
|
|
354
|
-
}
|
|
355
|
-
|
|
356
348
|
function get_development_engines_value(): typeof DEV_ENGINES_VALUE {
|
|
357
349
|
return DEV_ENGINES_VALUE
|
|
358
350
|
}
|
|
@@ -436,7 +428,6 @@ const init_logic = {
|
|
|
436
428
|
get_tsconfig_exclude_entries,
|
|
437
429
|
generate_lefthook_config,
|
|
438
430
|
generate_cspell_config,
|
|
439
|
-
generate_npmrc,
|
|
440
431
|
merge_npmrc,
|
|
441
432
|
merge_gitignore,
|
|
442
433
|
get_tsconfig_extends_entry,
|
|
@@ -450,7 +441,6 @@ const init_logic = {
|
|
|
450
441
|
SAFE_CHAIN_CMD,
|
|
451
442
|
GUARDED_LEFTHOOK_CMD,
|
|
452
443
|
upgrade_prepare_lefthook_warning,
|
|
453
|
-
get_npmrc_lines,
|
|
454
444
|
get_development_engines_value,
|
|
455
445
|
get_ai_copy_files,
|
|
456
446
|
get_ai_copy_file_mappings,
|
package/scripts/init/init.ts
CHANGED
|
@@ -23,6 +23,7 @@ import { init_file_action } from './init-file-action'
|
|
|
23
23
|
import { init_install } from './init-install'
|
|
24
24
|
import { init_logic } from './init-logic'
|
|
25
25
|
import { PACKAGE_DIR, PROJECT_ROOT } from './init-paths'
|
|
26
|
+
import { kit_development_versions } from './kit-development-versions'
|
|
26
27
|
import { kit_setup_state } from './kit-setup-state'
|
|
27
28
|
import { project_profile, type ProjectProfile, type ProjectShape } from './project-profile'
|
|
28
29
|
|
|
@@ -81,21 +82,10 @@ function tool_dependency_names(has_git: boolean): ReadonlyArray<string> {
|
|
|
81
82
|
|
|
82
83
|
// Versions mirror kit's own devDependencies, so the consumer runs the toolchain kit is verified with.
|
|
83
84
|
function get_toolchain_development_dependencies(has_git: boolean): Record<string, string> {
|
|
84
|
-
|
|
85
|
-
.
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
})
|
|
89
|
-
.parse(init_actions.read_package_json(PACKAGE_JSON))
|
|
90
|
-
const names = [...Object.keys(manifest.peerDependencies), ...tool_dependency_names(has_git)]
|
|
91
|
-
const entries = names.map((name): [string, string] => {
|
|
92
|
-
const version = manifest.devDependencies[name]
|
|
93
|
-
if (version === undefined) throw new Error(`Missing development version for ${name}`)
|
|
94
|
-
|
|
95
|
-
return [name, version]
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
return Object.fromEntries(entries)
|
|
85
|
+
return kit_development_versions.versions_of([
|
|
86
|
+
...kit_development_versions.peer_names(),
|
|
87
|
+
...tool_dependency_names(has_git),
|
|
88
|
+
])
|
|
99
89
|
}
|
|
100
90
|
|
|
101
91
|
function apply_dependency_merges(content: string, has_git = true): string {
|
|
@@ -6,17 +6,17 @@ import { start_exec } from './start-exec'
|
|
|
6
6
|
const DEFAULT_BRANCH = 'main'
|
|
7
7
|
|
|
8
8
|
function create_repository(root: string): void {
|
|
9
|
-
start_exec.
|
|
9
|
+
start_exec.git_run(['init', `--initial-branch=${DEFAULT_BRANCH}`], root)
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
function commit_all(root: string): void {
|
|
13
|
-
start_exec.
|
|
13
|
+
start_exec.git_run(['add', '--all'], root)
|
|
14
14
|
// The first commit of a new repository has no branch to come from, so the hook that keeps commits
|
|
15
15
|
// off main — installed by the initialize step in a full project — would refuse the only commit
|
|
16
16
|
// that has to land there.
|
|
17
|
-
start_exec.
|
|
17
|
+
start_exec.git_run(['commit', '--no-verify', '--message', 'Initial commit'], root)
|
|
18
18
|
// A repository created by an older `git init` may name its unborn branch `master`.
|
|
19
|
-
start_exec.
|
|
19
|
+
start_exec.git_run(['branch', '--move', '--force', DEFAULT_BRANCH], root)
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
const initial_commit = { create_repository, commit_all }
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs'
|
|
2
|
+
import { z } from 'zod'
|
|
3
|
+
import { package_path } from './init-paths'
|
|
4
|
+
|
|
5
|
+
const PACKAGE_JSON = 'package.json'
|
|
6
|
+
|
|
7
|
+
const kit_manifest_schema = z.object({
|
|
8
|
+
peerDependencies: z.record(z.string(), z.string()).default({}),
|
|
9
|
+
devDependencies: z.record(z.string(), z.string()),
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
type KitManifest = z.infer<typeof kit_manifest_schema>
|
|
13
|
+
|
|
14
|
+
function read_kit_manifest(): KitManifest {
|
|
15
|
+
const content = readFileSync(package_path(PACKAGE_JSON), 'utf8')
|
|
16
|
+
|
|
17
|
+
return kit_manifest_schema.parse(JSON.parse(content))
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// The version kit's own devDependencies carry for each name, so a consumer runs the toolchain kit
|
|
21
|
+
// is verified with rather than a copy of it that drifts.
|
|
22
|
+
function versions_of(names: ReadonlyArray<string>): Record<string, string> {
|
|
23
|
+
const { devDependencies: versions } = read_kit_manifest()
|
|
24
|
+
const entries = names.map((name): [string, string] => {
|
|
25
|
+
const version = versions[name]
|
|
26
|
+
if (version === undefined) throw new Error(`Missing development version for ${name}`)
|
|
27
|
+
|
|
28
|
+
return [name, version]
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
return Object.fromEntries(entries)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function peer_names(): ReadonlyArray<string> {
|
|
35
|
+
return Object.keys(read_kit_manifest().peerDependencies)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const kit_development_versions = { peer_names, versions_of }
|
|
39
|
+
|
|
40
|
+
export { kit_development_versions }
|
|
@@ -8,13 +8,13 @@ const START_HINT =
|
|
|
8
8
|
// reached the branch, so `josh start` has no setup pull request to open (joshuafolkken/kit#2816).
|
|
9
9
|
function is_kit_committed(root: string): boolean {
|
|
10
10
|
// `./` resolves the path from `root` rather than from the repository's top level.
|
|
11
|
-
const manifest = start_exec.
|
|
11
|
+
const manifest = start_exec.git_read(['show', 'HEAD:./package.json'], root)
|
|
12
12
|
|
|
13
13
|
return manifest?.includes(`"${KIT_PACKAGE_NAME}"`) ?? false
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
function is_git_work_tree(root: string): boolean {
|
|
17
|
-
return start_exec.
|
|
17
|
+
return start_exec.git_succeeds(['rev-parse', '--is-inside-work-tree'], root)
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
// The line `josh init` ends with in a Git repository whose checkout does not hold kit yet: the setup is
|
|
@@ -1,39 +1,80 @@
|
|
|
1
1
|
import { git_gh_exec } from '#scripts/gh/git-gh-exec'
|
|
2
2
|
import { git_location_environment } from '#scripts/git/git-location-environment'
|
|
3
|
+
import { git_spawn_sync } from '#scripts/git/git-spawn-sync'
|
|
4
|
+
import { COMMAND_TIMEOUT_MS, SUITE_TIMEOUT_MS } from '#scripts/lib/timeouts'
|
|
3
5
|
import { execaSync } from 'execa'
|
|
6
|
+
import type { Visibility } from './start-plan'
|
|
4
7
|
|
|
5
|
-
// The
|
|
6
|
-
//
|
|
8
|
+
// The spawn shapes every `josh start` step uses, shared by `start-steps.ts`, the setup pull request
|
|
9
|
+
// step and the `josh init` hint so none of them keeps a copy of its own.
|
|
7
10
|
//
|
|
8
|
-
// The
|
|
11
|
+
// The git shapes below act on `root`, so `cwd` has to mean it: an inherited `GIT_DIR` and friends beat `cwd`
|
|
9
12
|
// and would carry a `git init` or commit into whichever repository a calling hook was firing in
|
|
10
13
|
// (joshuafolkken/kit#3151).
|
|
14
|
+
//
|
|
15
|
+
// **Every git and gh call here is bounded** (joshuafolkken/kit#3262). A read asks the local
|
|
16
|
+
// repository and takes git's own budget. A write — and `gh repo create --push` — can fire the
|
|
17
|
+
// project's own commit and push hooks, which may run its whole suite, so it takes the suite budget:
|
|
18
|
+
// long enough for that, short enough that a push that never answers ends the run.
|
|
19
|
+
const SUCCESS_EXIT_CODE = 0
|
|
20
|
+
|
|
11
21
|
function root_environment(): Record<string, string | undefined> {
|
|
12
22
|
return git_location_environment.location_free_environment()
|
|
13
23
|
}
|
|
14
24
|
|
|
15
|
-
function
|
|
16
|
-
return (
|
|
17
|
-
execaSync(command, args, { cwd: root, env: root_environment(), reject: false }).exitCode === 0
|
|
18
|
-
)
|
|
25
|
+
function git_succeeds(args: ReadonlyArray<string>, root: string): boolean {
|
|
26
|
+
return git_spawn_sync.run(args, { cwd: root, env: root_environment() }).exit_code === 0
|
|
19
27
|
}
|
|
20
28
|
|
|
21
|
-
function
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const
|
|
29
|
+
function git_read(args: ReadonlyArray<string>, root: string): string | undefined {
|
|
30
|
+
return git_spawn_sync.read(args, { cwd: root, env: root_environment() })
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function git_run(args: ReadonlyArray<string>, root: string): void {
|
|
34
|
+
const options = { cwd: root, env: root_environment(), timeout: SUITE_TIMEOUT_MS }
|
|
35
|
+
const { exit_code } = git_spawn_sync.run(args, { ...options, stdio: 'inherit' })
|
|
36
|
+
|
|
37
|
+
if (exit_code === SUCCESS_EXIT_CODE) return
|
|
27
38
|
|
|
28
|
-
|
|
39
|
+
const outcome = exit_code === undefined ? 'did not finish' : `exited with ${String(exit_code)}`
|
|
40
|
+
|
|
41
|
+
throw new Error(`git ${args.join(' ')} ${outcome}`)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Every gh spawn here dials GitHub directly, past a scanner's loopback proxy, the same as every
|
|
45
|
+
// other `gh` spawn under scripts/ (joshuafolkken/kit#2436). Each argument list is written inline so
|
|
46
|
+
// `gh-subcommand-guard.ts` reads its subcommand rather than `<dynamic>`.
|
|
47
|
+
interface GhProbeOptions {
|
|
48
|
+
cwd: string
|
|
49
|
+
env: Record<string, string | undefined>
|
|
50
|
+
timeout: number
|
|
51
|
+
reject: false
|
|
29
52
|
}
|
|
30
53
|
|
|
31
|
-
|
|
32
|
-
// other `gh` spawn under scripts/ (joshuafolkken/kit#2436); a local `git` step is unaffected by it.
|
|
33
|
-
function run(command: string, args: ReadonlyArray<string>, root: string): void {
|
|
54
|
+
function gh_probe_options(root: string): GhProbeOptions {
|
|
34
55
|
const environment = { ...root_environment(), ...git_gh_exec.direct_environment().env }
|
|
35
56
|
|
|
36
|
-
|
|
57
|
+
return { cwd: root, env: environment, timeout: COMMAND_TIMEOUT_MS, reject: false }
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function is_gh_installed(root: string): boolean {
|
|
61
|
+
const result = execaSync('gh', ['--version'], gh_probe_options(root)) // NOSONAR S8705: execa array args (no shell), trusted dev CLI tooling
|
|
62
|
+
|
|
63
|
+
return result.exitCode === SUCCESS_EXIT_CODE
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function is_gh_signed_in(root: string): boolean {
|
|
67
|
+
const result = execaSync('gh', ['auth', 'status'], gh_probe_options(root)) // NOSONAR S8705: execa array args (no shell), trusted dev CLI tooling
|
|
68
|
+
|
|
69
|
+
return result.exitCode === SUCCESS_EXIT_CODE
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function create_github_repository(name: string, visibility: Visibility, root: string): void {
|
|
73
|
+
const source = ['--source', '.', '--remote', 'origin', '--push']
|
|
74
|
+
const { env } = gh_probe_options(root)
|
|
75
|
+
const options = { cwd: root, env, timeout: SUITE_TIMEOUT_MS, stdio: 'inherit' } as const
|
|
76
|
+
|
|
77
|
+
execaSync('gh', ['repo', 'create', name, `--${visibility}`, ...source], options) // NOSONAR S8705: execa array args (no shell), trusted dev CLI tooling
|
|
37
78
|
}
|
|
38
79
|
|
|
39
80
|
// A caller's own initialize command stands in for the in-process `josh init`, so it keeps the
|
|
@@ -42,6 +83,14 @@ function run_local(command: string, args: ReadonlyArray<string>, root: string):
|
|
|
42
83
|
execaSync(command, args, { cwd: root, stdio: 'inherit' })
|
|
43
84
|
}
|
|
44
85
|
|
|
45
|
-
const start_exec = {
|
|
86
|
+
const start_exec = {
|
|
87
|
+
git_succeeds,
|
|
88
|
+
git_read,
|
|
89
|
+
git_run,
|
|
90
|
+
is_gh_installed,
|
|
91
|
+
is_gh_signed_in,
|
|
92
|
+
create_github_repository,
|
|
93
|
+
run_local,
|
|
94
|
+
}
|
|
46
95
|
|
|
47
96
|
export { start_exec }
|
|
@@ -22,12 +22,12 @@ const FIRST_SETUP_ISSUE_FILTER = `[.[] | select(.title == "${SETUP_TITLE}") | .n
|
|
|
22
22
|
|
|
23
23
|
// Listings are read NUL-separated (`-z`), so a path is never quoted — a name a caller's initialize
|
|
24
24
|
// command wrote need not be ASCII the way kit's own are (#2872).
|
|
25
|
-
function paths_of(output: string | undefined): Array<string> {
|
|
26
|
-
return
|
|
25
|
+
function paths_of(output: string | undefined = ''): Array<string> {
|
|
26
|
+
return output.split('\0').filter((listed) => listed.length > 0)
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
function listing(args: ReadonlyArray<string>, root: string): Array<string> {
|
|
30
|
-
return paths_of(start_exec.
|
|
30
|
+
return paths_of(start_exec.git_read([...args, '-z'], root))
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
function setup_issue(issue_number: string): IssueInfo {
|
|
@@ -103,13 +103,13 @@ function switch_to(branch: string, current: string | undefined, root: string): v
|
|
|
103
103
|
|
|
104
104
|
const reference = `refs/heads/${branch}`
|
|
105
105
|
|
|
106
|
-
if (start_exec.
|
|
106
|
+
if (start_exec.git_succeeds(['rev-parse', '--verify', '--quiet', reference], root)) {
|
|
107
107
|
throw new Error(
|
|
108
108
|
`The setup branch ${branch} already exists. Run git switch ${branch}, then josh start again.`,
|
|
109
109
|
)
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
start_exec.
|
|
112
|
+
start_exec.git_run(['switch', '--create', branch], root)
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
// The paths are named on the commit as well as on the add, so anything the user had staged before
|
|
@@ -117,8 +117,8 @@ function switch_to(branch: string, current: string | undefined, root: string): v
|
|
|
117
117
|
function commit_kit_paths(paths: ReadonlyArray<string>, issue: IssueInfo, root: string): void {
|
|
118
118
|
if (paths.length === 0) return
|
|
119
119
|
|
|
120
|
-
start_exec.
|
|
121
|
-
start_exec.
|
|
120
|
+
start_exec.git_run(['add', '--', ...paths], root)
|
|
121
|
+
start_exec.git_run(['commit', '--message', issue.commit_message, '--', ...paths], root)
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
// A caller's initialize command writes files kit cannot name, so with a `baseline` — what was already
|
|
@@ -143,7 +143,7 @@ function setup_paths(
|
|
|
143
143
|
// Issue → branch → only the setup's files committed → push → pull request. The merge is left to a
|
|
144
144
|
// person: it is the one step that changes main.
|
|
145
145
|
async function open(root: string, baseline?: ReadonlyArray<string>): Promise<void> {
|
|
146
|
-
const current = start_exec.
|
|
146
|
+
const current = start_exec.git_read(['symbolic-ref', '--short', 'HEAD'], root)
|
|
147
147
|
const paths = setup_paths(root, baseline, current)
|
|
148
148
|
|
|
149
149
|
if (paths.length === 0) {
|
|
@@ -156,7 +156,7 @@ async function open(root: string, baseline?: ReadonlyArray<string>): Promise<voi
|
|
|
156
156
|
|
|
157
157
|
switch_to(issue.branch_name, current, root)
|
|
158
158
|
commit_kit_paths(paths, issue, root)
|
|
159
|
-
start_exec.
|
|
159
|
+
start_exec.git_run(['push', '--set-upstream', 'origin', issue.branch_name], root)
|
|
160
160
|
await git_pr.create_with_issue_info(issue)
|
|
161
161
|
}
|
|
162
162
|
|
|
@@ -29,7 +29,7 @@ const GH_INSTALL_HINT =
|
|
|
29
29
|
const GH_AUTH_HINT =
|
|
30
30
|
'GitHub CLI is not signed in. Run gh auth login, then run josh start again. Nothing was changed.'
|
|
31
31
|
|
|
32
|
-
const {
|
|
32
|
+
const { git_succeeds, git_read, run_local } = start_exec
|
|
33
33
|
|
|
34
34
|
function read_git_state(root: string, shape: ProjectShape): GitState {
|
|
35
35
|
const { has_git, has_github } = shape
|
|
@@ -46,8 +46,8 @@ function read_git_state(root: string, shape: ProjectShape): GitState {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
const has_origin = git_spawn_sync.origin_url(root) !== undefined
|
|
49
|
-
const branch =
|
|
50
|
-
const has_commits =
|
|
49
|
+
const branch = git_read(['symbolic-ref', '--short', 'HEAD'], root)
|
|
50
|
+
const has_commits = git_succeeds(['rev-parse', '--verify', '--quiet', 'HEAD'], root)
|
|
51
51
|
const has_kit_committed = kit_setup_state.is_kit_committed(root)
|
|
52
52
|
|
|
53
53
|
return { has_git, has_github, has_origin, branch, has_commits, has_kit_committed }
|
|
@@ -56,8 +56,8 @@ function read_git_state(root: string, shape: ProjectShape): GitState {
|
|
|
56
56
|
// Every step talks to GitHub, so the CLI is checked before the first write rather than at the step
|
|
57
57
|
// that needs it — a missing `gh` then leaves the directory exactly as it was.
|
|
58
58
|
function github_cli_refusal(root: string): string | undefined {
|
|
59
|
-
if (!
|
|
60
|
-
if (!
|
|
59
|
+
if (!start_exec.is_gh_installed(root)) return GH_INSTALL_HINT
|
|
60
|
+
if (!start_exec.is_gh_signed_in(root)) return GH_AUTH_HINT
|
|
61
61
|
|
|
62
62
|
return undefined
|
|
63
63
|
}
|
|
@@ -94,11 +94,7 @@ function commit_all(context: StepContext): void {
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
function create_github_repository(context: StepContext): void {
|
|
97
|
-
|
|
98
|
-
const visibility = `--${context.visibility}`
|
|
99
|
-
const source = ['--source', '.', '--remote', 'origin', '--push']
|
|
100
|
-
|
|
101
|
-
run('gh', ['repo', 'create', name, visibility, ...source], context.root)
|
|
97
|
+
start_exec.create_github_repository(path.basename(context.root), context.visibility, context.root)
|
|
102
98
|
}
|
|
103
99
|
|
|
104
100
|
// The repository was created by the step before, so `gh` resolves the placeholder from the
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { fileURLToPath } from 'node:url'
|
|
3
3
|
import { git_gh_command } from '#scripts/gh/git-gh-command'
|
|
4
4
|
import { git_gh_exec } from '#scripts/gh/git-gh-exec'
|
|
5
|
+
import { issue_label_schema } from '#scripts/git/git-schemas'
|
|
5
6
|
import { parse_json } from '#scripts/git/parse-json-array'
|
|
6
|
-
import { issue_label_schema } from '#scripts/git/schemas'
|
|
7
7
|
import { bounded_pool } from '#scripts/lib/bounded-pool'
|
|
8
8
|
import { cli_flags } from '#scripts/lib/cli-flags'
|
|
9
9
|
import { z } from 'zod'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { git_gh_command } from '#scripts/gh/git-gh-command'
|
|
2
|
+
import { open_issue_schema, type OpenIssueData } from '#scripts/git/git-schemas'
|
|
2
3
|
import { parse_json_array_safe } from '#scripts/git/parse-json-array'
|
|
3
|
-
import { open_issue_schema, type OpenIssueData } from '#scripts/git/schemas'
|
|
4
4
|
import { has_any_label, NOT_DIRECTLY_RUNNABLE_LABELS } from './issue-labels'
|
|
5
5
|
import { issue_rank, type DependencyRow } from './issue-rank'
|
|
6
6
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { git_branch } from '#scripts/git/git-branch'
|
|
2
2
|
import { git_command } from '#scripts/git/git-command'
|
|
3
|
-
import { run_carry } from '#scripts/run/run-carry'
|
|
3
|
+
import { run_carry } from '#scripts/run/carry/run-carry'
|
|
4
4
|
import { issue_file } from './issue-file'
|
|
5
5
|
import { AUTO_OK_LABEL, has_label_name } from './issue-labels'
|
|
6
6
|
import { issue_state_cli } from './issue-state-cli'
|
|
@@ -34,8 +34,8 @@ async function read_upstream(reference: string): Promise<UpstreamEntry | undefin
|
|
|
34
34
|
const match = REF_PATTERN.exec(reference)
|
|
35
35
|
if (match === null) return undefined
|
|
36
36
|
|
|
37
|
-
const [, repo, number] = match
|
|
38
|
-
const body = await read_body(number
|
|
37
|
+
const [, repo, number = ''] = match
|
|
38
|
+
const body = await read_body(number, repo)
|
|
39
39
|
|
|
40
40
|
return body === undefined ? undefined : { ref: reference, body }
|
|
41
41
|
}
|
|
@@ -33,11 +33,11 @@ function has_heading(body: string, heading: string): boolean {
|
|
|
33
33
|
return markdown_section.has_line(body, heading)
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
// The lines under
|
|
37
|
-
function
|
|
38
|
-
if (!has_heading(body,
|
|
36
|
+
// The lines under the upstream heading, up to the next `##` heading; `undefined` when it is absent.
|
|
37
|
+
function upstream_section_lines(body: string): ReadonlyArray<string> | undefined {
|
|
38
|
+
if (!has_heading(body, UPSTREAM_ISSUES_HEADING)) return undefined
|
|
39
39
|
|
|
40
|
-
return markdown_section.section_lines(body,
|
|
40
|
+
return markdown_section.section_lines(body, UPSTREAM_ISSUES_HEADING)
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
// A heading that looks like the upstream one but is not exactly it (`## Upstream`, `## Upstreams`,
|
|
@@ -59,8 +59,8 @@ function tokens_of(section: ReadonlyArray<string>): ReadonlyArray<string> {
|
|
|
59
59
|
.filter((token) => token.length > 0)
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
function has_two_segments(path: string | undefined): boolean {
|
|
63
|
-
const segments =
|
|
62
|
+
function has_two_segments(path: string | undefined = ''): boolean {
|
|
63
|
+
const segments = path.split(PATH_SEPARATOR)
|
|
64
64
|
|
|
65
65
|
return segments.length === PATH_SEGMENT_COUNT && segments.every((segment) => segment.length > 0)
|
|
66
66
|
}
|
|
@@ -115,7 +115,7 @@ function classify_backlinks(
|
|
|
115
115
|
): BacklinkVerdict {
|
|
116
116
|
if (has_wrong_upstream_heading(origin_body)) return WRONG_HEADING
|
|
117
117
|
|
|
118
|
-
const section =
|
|
118
|
+
const section = upstream_section_lines(origin_body)
|
|
119
119
|
|
|
120
120
|
return section === undefined
|
|
121
121
|
? verdict_without_section(origin_body)
|
|
@@ -125,7 +125,7 @@ function classify_backlinks(
|
|
|
125
125
|
// The `owner/repo#N` references the upstream section lists, so the CLI knows which upstream bodies to
|
|
126
126
|
// fetch and check for `## Origin`.
|
|
127
127
|
function upstream_references(origin_body: string): ReadonlyArray<string> {
|
|
128
|
-
const section =
|
|
128
|
+
const section = upstream_section_lines(origin_body)
|
|
129
129
|
if (section === undefined) return []
|
|
130
130
|
|
|
131
131
|
return tokens_of(section).filter((token) => is_qualified_reference(token))
|
|
@@ -138,7 +138,7 @@ function upstream_references(origin_body: string): ReadonlyArray<string> {
|
|
|
138
138
|
function needs_upstreams(origin_body: string): boolean {
|
|
139
139
|
if (has_wrong_upstream_heading(origin_body)) return false
|
|
140
140
|
|
|
141
|
-
const section =
|
|
141
|
+
const section = upstream_section_lines(origin_body)
|
|
142
142
|
if (section === undefined) return false
|
|
143
143
|
|
|
144
144
|
return !is_malformed_upstream_section(section)
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { fileURLToPath } from 'node:url'
|
|
3
3
|
import { git_gh_command } from '#scripts/gh/git-gh-command'
|
|
4
4
|
import { cli_body } from '#scripts/josh/cli-body'
|
|
5
|
+
import { cli_flags } from '#scripts/lib/cli-flags'
|
|
5
6
|
import { error_text } from '#scripts/lib/error-message'
|
|
6
7
|
|
|
7
8
|
// `josh issue:comment <N> --body <text> | --body-file <path>` — post one comment to an issue (a PR
|
|
@@ -28,25 +29,30 @@ interface CommentRequest {
|
|
|
28
29
|
body: string
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
// The
|
|
32
|
-
// both-flags-at-once refusal and the file read
|
|
33
|
-
|
|
34
|
-
const index = argv.indexOf(flag)
|
|
32
|
+
// The read is strict (joshuafolkken/kit#3261): an unknown flag refuses the call rather than being
|
|
33
|
+
// ignored. `cli_body.resolve` owns the both-flags-at-once refusal and the file read.
|
|
34
|
+
const OPTIONS = { body: { type: 'string' }, 'body-file': { type: 'string' } } as const
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
// The number is the one positional, and it must be a real issue number: a missing, malformed or
|
|
37
|
+
// second one refuses the whole call rather than posting to some other issue.
|
|
38
|
+
function single_issue_number(positionals: ReadonlyArray<string>): string | undefined {
|
|
39
|
+
const [issue_number, ...rest] = positionals
|
|
40
|
+
const is_single = rest.length === 0 && issue_number !== undefined
|
|
41
|
+
|
|
42
|
+
return is_single && ISSUE_NUMBER_PATTERN.test(issue_number) ? issue_number : undefined
|
|
37
43
|
}
|
|
38
44
|
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
// flags are given, which `run` reports — the message names the two flags a caller must pick between.
|
|
45
|
+
// `resolve` may throw when both body flags are given, which `run` reports — the message names the two
|
|
46
|
+
// flags a caller must pick between.
|
|
42
47
|
function parse_request(argv: ReadonlyArray<string>): CommentRequest | undefined {
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
const parsed = cli_flags.arguments_of(argv, OPTIONS)
|
|
49
|
+
if (parsed === undefined) return undefined
|
|
50
|
+
const issue_number = single_issue_number(parsed.positionals)
|
|
51
|
+
if (issue_number === undefined) return undefined
|
|
46
52
|
|
|
47
53
|
const body = cli_body.resolve({
|
|
48
|
-
inline:
|
|
49
|
-
file_path:
|
|
54
|
+
inline: parsed.values.body,
|
|
55
|
+
file_path: parsed.values['body-file'],
|
|
50
56
|
inline_flag: BODY_FLAG,
|
|
51
57
|
file_flag: BODY_FILE_FLAG,
|
|
52
58
|
})
|