@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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { telegram_notify } from '#scripts/notify/telegram-notify'
|
|
2
|
-
import { run_event_stream, type RunEvent } from '#scripts/run/run-event-stream'
|
|
3
|
-
import { run_event_stream_emit } from '#scripts/run/run-event-stream-emit'
|
|
2
|
+
import { run_event_stream, type RunEvent } from '#scripts/run/event/run-event-stream'
|
|
3
|
+
import { run_event_stream_emit } from '#scripts/run/event/run-event-stream-emit'
|
|
4
4
|
import { backlog_ready, type ReadyPorts } from './backlog-ready'
|
|
5
5
|
import { backlog_stalled, type StallReading, type StallVerdict } from './backlog-stalled'
|
|
6
6
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { epic_triage } from '#scripts/epic/epic-triage'
|
|
2
|
-
import { run_event_stream, type RunEvent } from '#scripts/run/run-event-stream'
|
|
2
|
+
import { run_event_stream, type RunEvent } from '#scripts/run/event/run-event-stream'
|
|
3
3
|
|
|
4
4
|
// When ready backlog work sits undispatched while lanes are free, nobody notices until a person asks
|
|
5
5
|
// (joshuafolkken/kit#2359). This is the mechanical judge of that state: three facts read, never
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
NEEDS_DECISION_LABEL,
|
|
11
11
|
} from '#scripts/issue/issue-labels'
|
|
12
12
|
import { backlog_plan, type PlanContext } from './backlog-plan'
|
|
13
|
-
import { backlog_rank } from './backlog-rank'
|
|
13
|
+
import { backlog_rank, type GateScope } from './backlog-rank'
|
|
14
14
|
|
|
15
15
|
// The order a `backlogrun` takes, wave by wave, before it starts (joshuafolkken/kit#2778).
|
|
16
16
|
//
|
|
@@ -18,7 +18,8 @@ import { backlog_rank } from './backlog-rank'
|
|
|
18
18
|
// made from, so the order past the first answer was left for a person to work out by hand. This plays
|
|
19
19
|
// the asks forward under one assumption: **every issue of a wave merges before the next wave starts**.
|
|
20
20
|
//
|
|
21
|
-
// **No rule is written twice.** The first wave is `backlog_rank.select` — rank, `run:solo` gate,
|
|
21
|
+
// **No rule is written twice.** The first wave is `backlog_rank.select` — rank, `run:solo` gate,
|
|
22
|
+
// restructure separation, cap —
|
|
22
23
|
// over the very candidates `backlog:next` resolves, asked of an idle repository — so it is what
|
|
23
24
|
// `backlog:next` prints when nothing is running (joshuafolkken/kit#2928). Each later wave marks the earlier waves closed and re-classifies the same pool
|
|
24
25
|
// through `epic_classify.classify_children` with the resolver `epic:next` sorted it with the first
|
|
@@ -28,6 +29,7 @@ import { backlog_rank } from './backlog-rank'
|
|
|
28
29
|
|
|
29
30
|
const IDLE: BusyRead = { kind: 'idle' }
|
|
30
31
|
const CLOSED = 'CLOSED'
|
|
32
|
+
const EMPTY_SCOPE: GateScope = { standalone: new Set(), declared: new Map() }
|
|
31
33
|
|
|
32
34
|
const HEADING_ASSUMPTION =
|
|
33
35
|
'Assumes every issue in a wave merges before the next wave starts. Issues a run already has are left out, and only issues of this repository are planned.'
|
|
@@ -59,17 +61,17 @@ interface WavePool {
|
|
|
59
61
|
children: ReadonlyArray<EpicChild>
|
|
60
62
|
running: ReadonlySet<string>
|
|
61
63
|
repo: string
|
|
62
|
-
|
|
64
|
+
scope: GateScope
|
|
63
65
|
}
|
|
64
66
|
|
|
65
|
-
function pool_of(result: EpicNextResult, repo: string,
|
|
67
|
+
function pool_of(result: EpicNextResult, repo: string, scope: GateScope): WavePool {
|
|
66
68
|
const all = backlog_rank.everything_in(result)
|
|
67
69
|
|
|
68
70
|
return {
|
|
69
71
|
children: all.filter((child) => !is_running(child)),
|
|
70
72
|
running: epic_outside_blocker.running_keys(all),
|
|
71
73
|
repo,
|
|
72
|
-
|
|
74
|
+
scope,
|
|
73
75
|
}
|
|
74
76
|
}
|
|
75
77
|
|
|
@@ -78,9 +80,9 @@ function offer(
|
|
|
78
80
|
children: ReadonlyArray<EpicChild>,
|
|
79
81
|
pool: WavePool,
|
|
80
82
|
): ReadonlyArray<EpicChild> {
|
|
81
|
-
const { repo,
|
|
83
|
+
const { repo, scope } = pool
|
|
82
84
|
|
|
83
|
-
return backlog_rank.select({ candidates, pool: children, read: IDLE, repo,
|
|
85
|
+
return backlog_rank.select({ candidates, pool: children, read: IDLE, repo, ...scope }).offered
|
|
84
86
|
}
|
|
85
87
|
|
|
86
88
|
// Ranked against the whole result, exactly as `backlog:next` ranks it, so the two agree.
|
|
@@ -106,14 +108,10 @@ function next_wave(pool: WavePool, done: ReadonlySet<string>): ReadonlyArray<Epi
|
|
|
106
108
|
}
|
|
107
109
|
|
|
108
110
|
// Each wave is closed before the next is asked for; a wave that offers nothing ends the plan, which
|
|
109
|
-
// the pool's size bounds because every wave closes at least one child. `
|
|
110
|
-
// offer's cap bounds; left empty, no wave is capped.
|
|
111
|
-
function build(
|
|
112
|
-
result
|
|
113
|
-
repo: string,
|
|
114
|
-
standalone: ReadonlySet<string> = new Set(),
|
|
115
|
-
): WavePlan {
|
|
116
|
-
const pool = pool_of(result, repo, standalone)
|
|
111
|
+
// the pool's size bounds because every wave closes at least one child. `scope` names the rows the
|
|
112
|
+
// offer's cap bounds and the paths each issue restructures; left empty, no wave is capped or separated.
|
|
113
|
+
function build(result: EpicNextResult, repo: string, scope: GateScope = EMPTY_SCOPE): WavePlan {
|
|
114
|
+
const pool = pool_of(result, repo, scope)
|
|
117
115
|
const done = new Set<string>()
|
|
118
116
|
const waves: Array<ReadonlyArray<EpicChild>> = []
|
|
119
117
|
|
|
@@ -155,11 +153,11 @@ function unreached_lines(plan: WavePlan, context: PlanContext): Array<string> {
|
|
|
155
153
|
function format_waves(
|
|
156
154
|
result: EpicNextResult,
|
|
157
155
|
context: PlanContext,
|
|
158
|
-
|
|
156
|
+
scope: GateScope = EMPTY_SCOPE,
|
|
159
157
|
): string {
|
|
160
158
|
if (result.verdict === 'error') return backlog_plan.format_unusable(result)
|
|
161
159
|
|
|
162
|
-
const plan = build(result, context.repo,
|
|
160
|
+
const plan = build(result, context.repo, scope)
|
|
163
161
|
const waves = plan.waves.map((wave, index) => wave_line(wave, index, context.repo))
|
|
164
162
|
|
|
165
163
|
return [
|
|
@@ -10,7 +10,9 @@ const CODEX_HOOKS = path.join(REPO_ROOT, '.codex', 'hooks.json')
|
|
|
10
10
|
|
|
11
11
|
// Regenerate `.codex/hooks.json` from `.claude/settings.json` (joshuafolkken/kit#2997). The output is
|
|
12
12
|
// committed rather than gitignored: Codex reads it straight from a fresh clone of kit, before any
|
|
13
|
-
// build has run, and `josh init` / `josh sync` copy it to consumers from the package.
|
|
13
|
+
// build has run, and `josh init` / `josh sync` copy it to consumers from the package. It is run by
|
|
14
|
+
// hand, never from `pnpm build`, so a build never rewrites a committed file (joshuafolkken/kit#3324):
|
|
15
|
+
// `codex-project-config.test.ts` fails the gate when the committed copy has drifted.
|
|
14
16
|
function build_codex_hooks(): string {
|
|
15
17
|
writeFileSync(CODEX_HOOKS, codex_hooks.codex_hooks_text(readFileSync(CLAUDE_SETTINGS, 'utf8')))
|
|
16
18
|
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
import { rmSync } from 'node:fs'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import { fileURLToPath } from 'node:url'
|
|
5
|
+
import { COMMAND_MAP } from '#scripts/josh/josh-command-map'
|
|
6
|
+
import { BUNDLED_COMMAND_DIRECTORY, josh_in_process } from '#scripts/josh/josh-in-process'
|
|
7
|
+
import { error_text } from '#scripts/lib/error-message'
|
|
8
|
+
import { build } from 'esbuild'
|
|
9
|
+
|
|
10
|
+
const PACKAGE_DIR = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', '..')
|
|
11
|
+
const OUT_DIR = path.join(PACKAGE_DIR, BUNDLED_COMMAND_DIRECTORY)
|
|
12
|
+
|
|
13
|
+
// Each `is_bundled` command is pre-built to its own `dist/commands/<script basename>.js`, so a
|
|
14
|
+
// consumer's `dist/josh.js` imports it under plain node instead of spawning tsx for its `.ts`
|
|
15
|
+
// (joshuafolkken/kit#3328, `docs/maintainers/runtime-bundling.md`).
|
|
16
|
+
//
|
|
17
|
+
// **No code splitting, and that is why the import closure is checked.** Every entry is one
|
|
18
|
+
// self-contained file, so every module it imports shares the entry's `import.meta.url`; a second
|
|
19
|
+
// `process.argv[1] === fileURLToPath(import.meta.url)` guard inside the closure would fire with the
|
|
20
|
+
// entry's own. `build-commands.test.ts` refuses a bundled command whose closure carries one.
|
|
21
|
+
//
|
|
22
|
+
// The bundle sits two levels under the package root, exactly as its source does under `scripts/`,
|
|
23
|
+
// so a module that finds the package from its own `import.meta.url` resolves the same directory.
|
|
24
|
+
function bundled_scripts(): Array<string> {
|
|
25
|
+
return Object.values(COMMAND_MAP)
|
|
26
|
+
.filter((entry) => entry.is_bundled === true)
|
|
27
|
+
.map((entry) => entry.script ?? '')
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function entry_point(script: string): { in: string; out: string } {
|
|
31
|
+
const out = path.basename(josh_in_process.bundled_script_path(PACKAGE_DIR, script), '.js')
|
|
32
|
+
|
|
33
|
+
return { in: path.join(PACKAGE_DIR, script), out }
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Nothing in this checkout launches `dist/commands/` (kit's own `pnpm josh` runs the source), so the
|
|
37
|
+
// directory is emptied first rather than pruned after, which drops the output of a command no longer
|
|
38
|
+
// bundled.
|
|
39
|
+
async function build_commands(out_directory: string = OUT_DIR): Promise<string> {
|
|
40
|
+
rmSync(out_directory, { recursive: true, force: true })
|
|
41
|
+
await build({
|
|
42
|
+
absWorkingDir: PACKAGE_DIR,
|
|
43
|
+
entryPoints: bundled_scripts().map((script) => entry_point(script)),
|
|
44
|
+
outdir: out_directory,
|
|
45
|
+
bundle: true,
|
|
46
|
+
platform: 'node',
|
|
47
|
+
format: 'esm',
|
|
48
|
+
target: 'node22',
|
|
49
|
+
packages: 'external',
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
return out_directory
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async function main(): Promise<void> {
|
|
56
|
+
try {
|
|
57
|
+
console.info(` ✔ ${await build_commands()} built`)
|
|
58
|
+
} catch (error) {
|
|
59
|
+
console.error(error_text.message_of(error))
|
|
60
|
+
process.exit(1)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) await main()
|
|
65
|
+
|
|
66
|
+
export { build_commands, bundled_scripts, OUT_DIR }
|
|
@@ -49,7 +49,7 @@ interface HookBundle {
|
|
|
49
49
|
out: string
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
// The
|
|
52
|
+
// The settings.json hooks (the session-start audit provisioner among them), the Codex input adapter, and the three guards `pretool-guard`
|
|
53
53
|
// composes: `batch-guard`, `investigation-guard` and `duplicate-read-guard` each self-invoke, so they
|
|
54
54
|
// must be their own entries to keep their `import.meta.url` out of `pretool-guard`'s file.
|
|
55
55
|
// `delivered-rules` (the fourth guard) has no self-invoke, so it stays inlined.
|
|
@@ -59,6 +59,7 @@ const HOOK_BUNDLES: ReadonlyArray<HookBundle> = [
|
|
|
59
59
|
{ source: 'scripts/hooks/stop-guard.ts', out: 'stop-guard' },
|
|
60
60
|
{ source: 'scripts/hooks/format-edited-cli.ts', out: 'format-edited' },
|
|
61
61
|
{ source: 'scripts/josh/session-language-cli.ts', out: 'session-lang' },
|
|
62
|
+
{ source: 'scripts/security/security-audit-provision.ts', out: 'audit-provision' },
|
|
62
63
|
{ source: 'scripts/hooks/batch-guard.ts', out: 'batch-guard' },
|
|
63
64
|
{ source: 'scripts/delegation/investigation-guard.ts', out: 'investigation-guard' },
|
|
64
65
|
{ source: 'scripts/delegation/duplicate-read-guard.ts', out: 'duplicate-read-guard' },
|
|
@@ -7,6 +7,13 @@ import { dts } from 'rollup-plugin-dts'
|
|
|
7
7
|
|
|
8
8
|
const PACKAGE_DIR = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', '..')
|
|
9
9
|
const SCRIPTS_IMPORT_PREFIX = '#scripts/'
|
|
10
|
+
// Every public library `pnpm build` bundles — each one a `./<name>` export in package.json.
|
|
11
|
+
const PUBLIC_LIBRARIES: ReadonlyArray<string> = [
|
|
12
|
+
'version',
|
|
13
|
+
'config-merge',
|
|
14
|
+
'managed-marker',
|
|
15
|
+
'self-sync-guard',
|
|
16
|
+
]
|
|
10
17
|
|
|
11
18
|
interface LibraryPaths {
|
|
12
19
|
entry_point: string
|
|
@@ -73,11 +80,13 @@ async function build_library_dts(entry_point: string, dts_file: string): Promise
|
|
|
73
80
|
async function build_library(name: string): Promise<LibraryPaths> {
|
|
74
81
|
const paths = library_paths(name)
|
|
75
82
|
|
|
76
|
-
await
|
|
77
|
-
|
|
83
|
+
await Promise.all([
|
|
84
|
+
build_library_js(paths.entry_point, paths.outfile),
|
|
85
|
+
build_library_dts(paths.entry_point, paths.dts_file),
|
|
86
|
+
])
|
|
78
87
|
|
|
79
88
|
return paths
|
|
80
89
|
}
|
|
81
90
|
|
|
82
91
|
export type { LibraryPaths }
|
|
83
|
-
export { build_library, library_paths }
|
|
92
|
+
export { build_library, library_paths, PUBLIC_LIBRARIES }
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
import { fileURLToPath } from 'node:url'
|
|
3
|
+
import { error_text } from '#scripts/lib/error-message'
|
|
4
|
+
import { OUTFILE as BIN_OUTFILE, build_bin } from './build-bin'
|
|
5
|
+
import { build_claude_md } from './build-claude-md'
|
|
6
|
+
import { build_commands } from './build-commands'
|
|
7
|
+
import { build_hooks, OUT_DIR as HOOKS_OUT_DIR } from './build-hooks'
|
|
8
|
+
import { build_library, PUBLIC_LIBRARIES } from './build-library'
|
|
9
|
+
|
|
10
|
+
interface BuildStep {
|
|
11
|
+
name: string
|
|
12
|
+
run: () => Promise<string>
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async function bin_step(): Promise<string> {
|
|
16
|
+
await build_bin()
|
|
17
|
+
|
|
18
|
+
return BIN_OUTFILE
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function hooks_step(): Promise<string> {
|
|
22
|
+
await build_hooks()
|
|
23
|
+
|
|
24
|
+
return HOOKS_OUT_DIR
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function library_step(name: string): Promise<string> {
|
|
28
|
+
const { outfile } = await build_library(name)
|
|
29
|
+
|
|
30
|
+
return outfile
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function claude_md_step(): Promise<string> {
|
|
34
|
+
return build_claude_md()
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Every step `pnpm build` runs (joshuafolkken/kit#3324). The steps write disjoint paths under
|
|
38
|
+
// `dist/`, so they run concurrently from this one entry instead of eight serial `tsx` launches.
|
|
39
|
+
// Nothing here writes a git-tracked file: `.codex/hooks.json` is regenerated by hand with
|
|
40
|
+
// `tsx scripts/build/build-codex-hooks.ts`, and `codex-project-config.test.ts` fails the gate when
|
|
41
|
+
// the committed copy drifts from `.claude/settings.json`.
|
|
42
|
+
function build_steps(): ReadonlyArray<BuildStep> {
|
|
43
|
+
return [
|
|
44
|
+
{ name: 'bin', run: bin_step },
|
|
45
|
+
{ name: 'hooks', run: hooks_step },
|
|
46
|
+
{ name: 'commands', run: async () => await build_commands() },
|
|
47
|
+
...PUBLIC_LIBRARIES.map((name) => ({ name, run: async () => await library_step(name) })),
|
|
48
|
+
{ name: 'claude-md', run: claude_md_step },
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function build_all(): Promise<ReadonlyArray<string>> {
|
|
53
|
+
return await Promise.all(build_steps().map(async (step) => await step.run()))
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function main(): Promise<void> {
|
|
57
|
+
try {
|
|
58
|
+
const outputs = await build_all()
|
|
59
|
+
|
|
60
|
+
for (const output of outputs) console.info(` ✔ ${output} built`)
|
|
61
|
+
} catch (error) {
|
|
62
|
+
console.error(error_text.message_of(error))
|
|
63
|
+
process.exit(1)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) await main()
|
|
68
|
+
|
|
69
|
+
export type { BuildStep }
|
|
70
|
+
export { build_all, build_steps }
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'node:fs'
|
|
2
2
|
import { createRequire } from 'node:module'
|
|
3
3
|
import path from 'node:path'
|
|
4
|
+
import { ancestor_directories } from '#scripts/lib/ancestor-directories'
|
|
4
5
|
import { package_bin_schema } from '#scripts/lib/schemas'
|
|
5
6
|
|
|
6
7
|
const NODE_MODULES = 'node_modules'
|
|
@@ -27,20 +28,9 @@ function resolve_local_bin(project_root: string, bin_name: string): string {
|
|
|
27
28
|
// in `src/lib` would miss the toolkit its sibling checks resolve fine (joshuafolkken/kit#934).
|
|
28
29
|
// Ascending for the shim itself, rather than for a `package.json` first, is what keeps the two in
|
|
29
30
|
// step: a nested manifest that owns no `node_modules` is not where pnpm would stop either.
|
|
30
|
-
function ancestor_directories(start_directory: string): ReadonlyArray<string> {
|
|
31
|
-
const directories: Array<string> = []
|
|
32
|
-
let current = start_directory
|
|
33
|
-
|
|
34
|
-
while (!directories.includes(current)) {
|
|
35
|
-
directories.push(current)
|
|
36
|
-
current = path.dirname(current)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return directories
|
|
40
|
-
}
|
|
41
|
-
|
|
42
31
|
function find_local_bin_upwards(start_directory: string, bin_name: string): string | undefined {
|
|
43
|
-
return ancestor_directories
|
|
32
|
+
return ancestor_directories
|
|
33
|
+
.list(start_directory)
|
|
44
34
|
.map((directory) => resolve_local_bin(directory, bin_name))
|
|
45
35
|
.find((candidate) => existsSync(candidate))
|
|
46
36
|
}
|
|
@@ -10,12 +10,4 @@ import { context_cut_payback } from './context-cut-payback'
|
|
|
10
10
|
// from the cache-price multipliers and the horizon rather than restated, so it moves with the model.
|
|
11
11
|
const CONTEXT_CUT_THRESHOLD = context_cut_payback.break_even_context()
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
// (joshuafolkken/kit#2295). A long parent session's whole-session average lags its current context by
|
|
15
|
-
// dozens of requests — measured at 85 requests (~4 hours) behind on the 2026-09-21 parent — so it
|
|
16
|
-
// keeps supervising an already-oversized context long after a cut was due. Ten requests is enough to
|
|
17
|
-
// smooth a single outlier without reaching back into the cheap early context; it sits beside the
|
|
18
|
-
// threshold so the window and the limit are read from one place and cannot drift.
|
|
19
|
-
const RECENT_REQUEST_WINDOW = 10
|
|
20
|
-
|
|
21
|
-
export { CONTEXT_CUT_THRESHOLD, RECENT_REQUEST_WINDOW }
|
|
13
|
+
export { CONTEXT_CUT_THRESHOLD }
|
|
@@ -3,42 +3,31 @@
|
|
|
3
3
|
// of a session will cost, and takes only the figures its verdict needs — an over measurement — never
|
|
4
4
|
// a whole report. The `--cap` counterfactual it once sat beside was retired in #2016 as readerless.
|
|
5
5
|
|
|
6
|
-
import { RECENT_REQUEST_WINDOW } from './context-cut-threshold'
|
|
7
|
-
|
|
8
6
|
const FAILURE_EXIT_CODE = 1
|
|
9
7
|
const OVER_VERDICT = 'over'
|
|
10
8
|
const UNDER_VERDICT = 'under'
|
|
11
9
|
|
|
12
|
-
// What `--over` reads of a session: the billed input each request paid, oldest first. The
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
// context by dozens of requests, so a sum could not answer what the recent window actually cost.
|
|
10
|
+
// What `--over` reads of a session: the billed input each request paid, oldest first. The sequence
|
|
11
|
+
// is carried rather than a single sum because the hand-off prices the newest request alone
|
|
12
|
+
// (joshuafolkken/kit#3224) — a sum could not answer what the session's current context costs.
|
|
16
13
|
interface OverMeasurement {
|
|
17
14
|
billed_input_per_request: ReadonlyArray<number>
|
|
18
15
|
}
|
|
19
16
|
|
|
20
|
-
// The most recent requests the hand-off prices, oldest first — the whole sequence when it is shorter
|
|
21
|
-
// than the window, so a session with fewer than `RECENT_REQUEST_WINDOW` requests is priced on what it
|
|
22
|
-
// has rather than padded.
|
|
23
|
-
function recent_requests(measurement: OverMeasurement): ReadonlyArray<number> {
|
|
24
|
-
return measurement.billed_input_per_request.slice(-RECENT_REQUEST_WINDOW)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
17
|
// What a turn costs is decided by the accumulated preamble, not by what the turn does, so the
|
|
28
|
-
// marginal cost of a session is the billed input its
|
|
18
|
+
// marginal cost of a session is the billed input its newest request paid. Measured across one
|
|
29
19
|
// `epicrun` that ran six children in one context: 222k per request during the first child, 645k
|
|
30
20
|
// during the sixth — the same work at 2.9x the price (joshuafolkken/kit#968).
|
|
31
21
|
//
|
|
32
|
-
// The
|
|
33
|
-
//
|
|
34
|
-
//
|
|
22
|
+
// **The newest request, not an average.** joshuafolkken/kit#2295 replaced the whole-session average,
|
|
23
|
+
// which lagged a long parent by dozens of requests, with the average of the last ten; that still
|
|
24
|
+
// lagged. A session's billed input only grows between compactions (a unit writes its own transcript),
|
|
25
|
+
// so an average smooths no outlier — it only trails the context it averages. On 2026-10-05 wake
|
|
26
|
+
// session 03367124 crossed the threshold at request 65 and its ten-request average at request 70
|
|
27
|
+
// (joshuafolkken/kit#3224). The threshold is a break-even on the *current* context
|
|
28
|
+
// (`context-cut-payback.ts`), so the current context is what it is compared against.
|
|
35
29
|
function per_request_cost(measurement: OverMeasurement): number {
|
|
36
|
-
|
|
37
|
-
if (window.length === 0) return 0
|
|
38
|
-
|
|
39
|
-
const total = window.reduce((sum, billed) => sum + billed, 0)
|
|
40
|
-
|
|
41
|
-
return Math.round(total / window.length)
|
|
30
|
+
return measurement.billed_input_per_request.at(-1) ?? 0
|
|
42
31
|
}
|
|
43
32
|
|
|
44
33
|
// The bare over/under decision, without a report: `run:status` reads this same verdict read-only
|
|
@@ -51,14 +40,12 @@ function classify(
|
|
|
51
40
|
return per_request_cost(measurement) > limit ? OVER_VERDICT : UNDER_VERDICT
|
|
52
41
|
}
|
|
53
42
|
|
|
54
|
-
// The stderr line names
|
|
55
|
-
// from
|
|
56
|
-
// session is longer than the window and the whole count when it is shorter.
|
|
43
|
+
// The stderr line names which request was priced, so the reader can tell the newest request's cost
|
|
44
|
+
// from an average over the session (joshuafolkken/kit#3224).
|
|
57
45
|
function over_summary(measurement: OverMeasurement, limit: number): string {
|
|
58
46
|
const total = measurement.billed_input_per_request.length
|
|
59
|
-
const window = recent_requests(measurement).length
|
|
60
47
|
|
|
61
|
-
return `${String(per_request_cost(measurement))} billed input tokens per request
|
|
48
|
+
return `${String(per_request_cost(measurement))} billed input tokens per request, on the newest of ${String(total)} request(s); limit ${String(limit)}`
|
|
62
49
|
}
|
|
63
50
|
|
|
64
51
|
// A verdict, not a table: the point of the flag is that the hand-off is decided by a number rather
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import path from 'node:path'
|
|
2
2
|
import { cost_blocks } from '#scripts/cost-runtime/cost-blocks'
|
|
3
3
|
import { cost_transcript } from '#scripts/cost-runtime/cost-transcript'
|
|
4
|
+
import { capped_print_part } from '#scripts/document/capped-print-part'
|
|
4
5
|
import { hook_decision, type GuardRun } from '#scripts/josh/hook-decision'
|
|
5
6
|
import { time_batch_guard, type GuardedCall } from '#scripts/time-runtime/time-batch-guard'
|
|
6
7
|
import { time_bundle_call } from '#scripts/time-runtime/time-bundle-call'
|
|
@@ -212,7 +213,8 @@ function is_session_artifact(target: string): boolean {
|
|
|
212
213
|
|
|
213
214
|
return (
|
|
214
215
|
segments.some((_segment, index) => has_state_root(segments, index)) ||
|
|
215
|
-
is_harness_output(segments)
|
|
216
|
+
is_harness_output(segments) ||
|
|
217
|
+
capped_print_part.is_part_file(absolute)
|
|
216
218
|
)
|
|
217
219
|
}
|
|
218
220
|
|
|
@@ -111,12 +111,12 @@ function origin_section_lines(lines: ReadonlyArray<string>): Array<string> {
|
|
|
111
111
|
return end === NOT_FOUND ? rest : rest.slice(0, end)
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
// The value of a `
|
|
114
|
+
// The value of a `url = value` entry, or nothing when the line declares a different key. Split on
|
|
115
115
|
// the first separator rather than matched, for the reason `parse_scp_like` is split by hand.
|
|
116
|
-
function
|
|
116
|
+
function url_value(line: string): string | undefined {
|
|
117
117
|
const separator = line.indexOf('=')
|
|
118
118
|
if (separator === NOT_FOUND) return undefined
|
|
119
|
-
if (line.slice(0, separator).trim() !==
|
|
119
|
+
if (line.slice(0, separator).trim() !== URL_KEY) return undefined
|
|
120
120
|
|
|
121
121
|
return line.slice(separator + 1).trim()
|
|
122
122
|
}
|
|
@@ -129,7 +129,7 @@ function parse_origin_from_config(content: string): string | undefined {
|
|
|
129
129
|
const lines = content.split('\n').map((line) => line.trim())
|
|
130
130
|
|
|
131
131
|
return origin_section_lines(lines)
|
|
132
|
-
.map((line) =>
|
|
132
|
+
.map((line) => url_value(line))
|
|
133
133
|
.find((url) => url !== undefined)
|
|
134
134
|
}
|
|
135
135
|
|
|
@@ -153,7 +153,7 @@ function parse_remote_urls_from_config(content: string): Array<string> {
|
|
|
153
153
|
|
|
154
154
|
return section_groups(lines)
|
|
155
155
|
.filter((group) => REMOTE_SECTION.test(group[0] ?? ''))
|
|
156
|
-
.flatMap((group) => group.map((line) =>
|
|
156
|
+
.flatMap((group) => group.map((line) => url_value(line)))
|
|
157
157
|
.filter((url) => url !== undefined)
|
|
158
158
|
}
|
|
159
159
|
|
|
@@ -3,6 +3,7 @@ import path from 'node:path'
|
|
|
3
3
|
import { git_spawn_sync } from '#scripts/git/git-spawn-sync'
|
|
4
4
|
import { json_value } from '#scripts/lib/json-value'
|
|
5
5
|
import { file_reader } from '#scripts/lib/read-file'
|
|
6
|
+
import { PROBE_TIMEOUT_MS } from '#scripts/lib/timeouts'
|
|
6
7
|
import { KIT_PACKAGE_NAME } from '#scripts/version/kit-descriptor'
|
|
7
8
|
import { z } from 'zod'
|
|
8
9
|
|
|
@@ -20,7 +21,6 @@ const PLUGIN_ID = 'kit@kit'
|
|
|
20
21
|
// full document, so this pointer is also what tells a consumer repository apart from kit itself.
|
|
21
22
|
const CLAUDE_MD_POINTER = `@${NODE_MODULES}/${KIT_PACKAGE_NAME}/dist/${CLAUDE_MD}`
|
|
22
23
|
const SECRETLINT_BIN = path.join(NODE_MODULES, '.bin', 'secretlint')
|
|
23
|
-
const GIT_TIMEOUT_MS = 2000
|
|
24
24
|
|
|
25
25
|
const manifest_schema = z.object({
|
|
26
26
|
name: z.string().optional(),
|
|
@@ -77,7 +77,7 @@ function is_plugin_declared(root: string): boolean {
|
|
|
77
77
|
// from installing kit's git hooks — the failure is silent but for one stderr line.
|
|
78
78
|
function configured_hooks_path(root: string): string | undefined {
|
|
79
79
|
const value = git_spawn_sync.read(['-C', root, 'config', '--get', 'core.hooksPath'], {
|
|
80
|
-
timeout:
|
|
80
|
+
timeout: PROBE_TIMEOUT_MS,
|
|
81
81
|
})
|
|
82
82
|
|
|
83
83
|
return value === '' ? undefined : value
|
|
@@ -2,11 +2,11 @@ import { existsSync, readFileSync } from 'node:fs'
|
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
import { git_spawn_sync } from '#scripts/git/git-spawn-sync'
|
|
4
4
|
import { read_spawn_stdout } from '#scripts/lib/spawn-exit'
|
|
5
|
+
import { PROBE_TIMEOUT_MS } from '#scripts/lib/timeouts'
|
|
5
6
|
import { execaSync } from 'execa'
|
|
6
7
|
import { doctor_logic } from './doctor-logic'
|
|
7
8
|
|
|
8
9
|
const JOSH_BIN = 'josh'
|
|
9
|
-
const GIT_TIMEOUT_MS = 2000
|
|
10
10
|
const NOT_A_REPOSITORY_MESSAGE = 'not a git repository'
|
|
11
11
|
const NPM_VERSION_UPDATES_DISABLED = 'open-pull-requests-limit: 0'
|
|
12
12
|
const DEPENDABOT_CONFIG_PATH = '.github/dependabot.yml'
|
|
@@ -72,7 +72,7 @@ function classify_git_failure(exit_code: number | undefined, stderr: string): Gi
|
|
|
72
72
|
function resolve_git_top_level(): GitTopLevel {
|
|
73
73
|
// The C locale `toplevel` asks under is what keeps the stderr match below from failing on a
|
|
74
74
|
// translated message and bringing the spurious warning back.
|
|
75
|
-
const result = git_spawn_sync.toplevel(
|
|
75
|
+
const result = git_spawn_sync.toplevel(PROBE_TIMEOUT_MS)
|
|
76
76
|
|
|
77
77
|
if (result.exit_code === 0) return classify_top_level(result.stdout.trim())
|
|
78
78
|
|
|
@@ -194,7 +194,6 @@ type GitTopLevel =
|
|
|
194
194
|
{ state: 'inside'; top_level: string } | { state: 'outside' } | { state: 'undetermined' }
|
|
195
195
|
|
|
196
196
|
const doctor_io = {
|
|
197
|
-
GIT_TIMEOUT_MS,
|
|
198
197
|
resolve_path_josh,
|
|
199
198
|
resolve_pnpm_global_josh,
|
|
200
199
|
has_distributed_dependabot_config,
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
|
|
3
|
+
// Where `capped-print.ts` writes the parts of an over-cap output, and how a path is recognized as one
|
|
4
|
+
// of them (joshuafolkken/kit#3332). Both halves live here so the writer and the investigation guard,
|
|
5
|
+
// which must not count a read of a part as reading the Issue's subject, share one spelling of the
|
|
6
|
+
// shape — kept free of the writer's own imports, since the guard runs as a hook on every tool call.
|
|
7
|
+
|
|
8
|
+
const DIRECTORY_PREFIX = 'josh-capped-print-'
|
|
9
|
+
const PART_PREFIX = 'part-'
|
|
10
|
+
const PART_SUFFIX = '.md'
|
|
11
|
+
// A part is `part-<N>.md` and nothing else, so a run's own file that happens to sit beside one is not
|
|
12
|
+
// mistaken for it.
|
|
13
|
+
const PART_PATTERN = /^part-[1-9]\d*\.md$/u
|
|
14
|
+
|
|
15
|
+
function part_name(index: number): string {
|
|
16
|
+
return `${PART_PREFIX}${String(index + 1)}${PART_SUFFIX}`
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// **The file's own parent, and the file's own name, both have to match.** A directory prefix alone
|
|
20
|
+
// would exempt anything a run unpacked under a similarly named directory; the caller also requires the
|
|
21
|
+
// path to lie outside the checkout, so no repository file is ever exempted by its name.
|
|
22
|
+
function is_part_file(absolute: string): boolean {
|
|
23
|
+
const parent = path.basename(path.dirname(absolute))
|
|
24
|
+
|
|
25
|
+
return parent.startsWith(DIRECTORY_PREFIX) && PART_PATTERN.test(path.basename(absolute))
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const capped_print_part = { DIRECTORY_PREFIX, part_name, is_part_file }
|
|
29
|
+
|
|
30
|
+
export { capped_print_part }
|
|
@@ -3,6 +3,7 @@ import path from 'node:path'
|
|
|
3
3
|
import { PLATFORM_TEMP_ROOT } from '#scripts/josh/platform-temporary'
|
|
4
4
|
import { review_diff_parts } from '#scripts/review/review-diff-parts'
|
|
5
5
|
import { bash_output_cap_reader } from './bash-output-cap'
|
|
6
|
+
import { capped_print_part } from './capped-print-part'
|
|
6
7
|
|
|
7
8
|
// Prints a command's output whole when it fits under the Bash output cap, and as part files when it
|
|
8
9
|
// does not (joshuafolkken/kit#3143). Past `BASH_MAX_OUTPUT_LENGTH` Claude Code saves the output and
|
|
@@ -17,9 +18,7 @@ import { bash_output_cap_reader } from './bash-output-cap'
|
|
|
17
18
|
// in one turn, and a shared directory replaced on every call would delete one call's parts while
|
|
18
19
|
// another call's listing still names them.
|
|
19
20
|
|
|
20
|
-
const DIRECTORY_PREFIX = 'josh-capped-print-'
|
|
21
21
|
const FILE_MODE = 0o600
|
|
22
|
-
const PART_SUFFIX = '.md'
|
|
23
22
|
const LINE_BREAK = '\n'
|
|
24
23
|
// What else shares the Bash result with this output: the launcher line, a script banner, a few
|
|
25
24
|
// stderr lines. Measured at about 80 characters for `pnpm josh doc:section` in kit, so 512 holds the
|
|
@@ -27,10 +26,10 @@ const LINE_BREAK = '\n'
|
|
|
27
26
|
const HEADROOM_CHARS = 512
|
|
28
27
|
|
|
29
28
|
function write_parts(label: string, text: string, cap: number): Array<string> {
|
|
30
|
-
const directory = mkdtempSync(path.join(PLATFORM_TEMP_ROOT, DIRECTORY_PREFIX))
|
|
29
|
+
const directory = mkdtempSync(path.join(PLATFORM_TEMP_ROOT, capped_print_part.DIRECTORY_PREFIX))
|
|
31
30
|
|
|
32
31
|
return review_diff_parts.part_texts(label, text, cap).map((part, index) => {
|
|
33
|
-
const file = path.join(directory,
|
|
32
|
+
const file = path.join(directory, capped_print_part.part_name(index))
|
|
34
33
|
|
|
35
34
|
writeFileSync(file, part, { flag: 'wx', mode: FILE_MODE })
|
|
36
35
|
|
|
@@ -88,8 +88,17 @@ const DOCUMENT_BYTE_BUDGET: ReadonlyArray<DocumentBudget> = [
|
|
|
88
88
|
// joshuafolkken/kit#2998 split the reference: the developer commands stay, the rest moved out.
|
|
89
89
|
// joshuafolkken/kit#3175 raised it: the supervisor, provider-table and answer-to-budget prose moved
|
|
90
90
|
// here out of `backlogrun-steps.md`, so a run reads it only when it asks about those commands.
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
// joshuafolkken/kit#3277 moved the run, lane and session commands to `docs/josh-commands-run.md`.
|
|
92
|
+
// joshuafolkken/kit#3280 moved the issue, epic, backlog and review commands to
|
|
93
|
+
// `docs/josh-commands-backlog.md`.
|
|
94
|
+
// joshuafolkken/kit#3278 moved `josh latest` and `josh overrides` — commands a person types — from
|
|
95
|
+
// the automation page to `docs/josh-commands.md`, which grew one block and the automation page shrank one.
|
|
96
|
+
{ path: 'docs/josh-commands-automation.md', bytes: 49_152 },
|
|
97
|
+
{ path: 'docs/josh-commands-run.md', bytes: 57_344 },
|
|
98
|
+
{ path: 'docs/josh-commands-backlog.md', bytes: 57_344 },
|
|
99
|
+
{ path: 'docs/josh-commands.md', bytes: 40_960 },
|
|
100
|
+
// joshuafolkken/kit#3279 moved the label sections here out of `docs/josh-commands-backlog.md`.
|
|
101
|
+
{ path: 'docs/labels-and-run-states.md', bytes: 8192 },
|
|
93
102
|
{ path: 'prompts/coding-standards.md', bytes: 8192 },
|
|
94
103
|
{ path: 'prompts/collaboration-workflow.md', bytes: 8192 },
|
|
95
104
|
{ path: 'prompts/collaboration-workflow/file-edits.md', bytes: 12_288 },
|