@joshuafolkken/kit 1.1178.0 → 1.1240.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 +7 -3
- package/.claude/skills/workflow-commands/backlogrun-park.md +23 -2
- package/.claude/skills/workflow-commands/backlogrun-progress.md +9 -4
- package/.claude/skills/workflow-commands/backlogrun-recovery.md +4 -3
- package/.claude/skills/workflow-commands/backlogrun-steps.md +21 -13
- package/.claude/skills/workflow-commands/chain-rule.md +1 -1
- package/.claude/skills/workflow-commands/delegation.md +2 -2
- package/.claude/skills/workflow-commands/followup.md +10 -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 +2 -1
- package/.claude/skills/workflow-commands/latest-gate.md +1 -1
- package/.claude/skills/workflow-commands/observation-ledger.md +3 -3
- package/.claude/skills/workflow-commands/pre-gate-cut.md +6 -1
- package/.claude/skills/workflow-commands/prerequisite.md +2 -2
- package/.claude/skills/workflow-commands/progress-watcher.md +1 -1
- package/.claude/skills/workflow-commands/working-tree-hold.md +1 -1
- package/.codex/hooks.json +2 -2
- package/.cursorrules +6 -41
- package/.github/actions/setup-node/action.yml +1 -1
- package/.github/workflows/auto-tag.yml +3 -4
- package/.github/workflows/ci.yml +32 -31
- package/.github/workflows/dependabot-auto-merge.yml +13 -6
- package/.github/workflows/publish.yml +50 -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 +44 -38
- 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-G6KRCKEC.js → chunk-4TZVB44A.js} +496 -378
- package/dist/hooks/chunk-5VNDSNG3.js +12 -0
- package/dist/hooks/chunk-CDY4NFQG.js +15 -0
- package/dist/hooks/chunk-ELCN5LCH.js +135 -0
- package/dist/hooks/{chunk-VQLLNFNT.js → chunk-F3ELQ2AF.js} +3 -3
- package/dist/hooks/{chunk-I4XSL4TT.js → chunk-GPTFMK5E.js} +1 -1
- package/dist/hooks/{chunk-3V37IID6.js → chunk-JBBMAPC4.js} +23 -14
- package/dist/hooks/{chunk-UAGLLIGZ.js → chunk-KHGB5S3Y.js} +7 -6
- package/dist/hooks/{chunk-GDS5N2KB.js → chunk-KHX4U3BG.js} +735 -683
- package/dist/hooks/{chunk-VESKRQOF.js → chunk-KRBERBBI.js} +3 -3
- package/dist/hooks/{chunk-DO6NWWHU.js → chunk-QVSWU24O.js} +4 -4
- package/dist/hooks/{chunk-S6X6WYKR.js → chunk-WK2XSHSI.js} +1643 -923
- package/dist/hooks/{chunk-ZAL3NRGL.js → chunk-XZYKEM6J.js} +25 -10
- package/dist/hooks/{chunk-32GQTL4F.js → chunk-ZQGD4GBY.js} +4 -2
- 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 +203 -179
- package/dist/hooks/investigation-guard.js +6 -5
- package/dist/hooks/pretool-guard.js +12 -10
- package/dist/hooks/session-lang.js +2 -4
- package/dist/hooks/stop-guard.js +66 -72
- package/dist/josh.js +1088 -78
- 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/issue-template.md +1 -0
- package/prompts/collaboration-workflow/operating-rules.md +17 -9
- package/prompts/collaboration-workflow/overview.md +2 -2
- package/prompts/collaboration-workflow/principles.md +14 -12
- package/prompts/collaboration-workflow/report-format.md +1 -1
- package/prompts/collaboration-workflow/residency.md +1 -1
- package/prompts/collaboration-workflow/rule-delivery.md +6 -6
- package/prompts/collaboration-workflow/shell-body.md +6 -6
- package/prompts/collaboration-workflow/turn-batching.md +1 -1
- package/prompts/collaboration-workflow/upstream-interrupt.md +12 -2
- package/prompts/collaboration-workflow/wip-cap.md +10 -10
- package/prompts/review-rubric.md +1 -2
- package/prompts/review.md +1 -1
- package/scripts/agent/agent-headless.ts +29 -0
- package/scripts/agent/agent-launch-environment.ts +6 -2
- package/scripts/agent/codex-agent-argv.ts +2 -1
- package/scripts/auto-ok/auto-ok-cli.ts +1 -1
- package/scripts/backlog/backlog-arrival.ts +3 -3
- package/scripts/backlog/backlog-budget.ts +1 -1
- package/scripts/backlog/backlog-drive-args.ts +135 -0
- package/scripts/backlog/backlog-drive-cli.ts +11 -137
- package/scripts/backlog/backlog-drive-launch.ts +39 -0
- package/scripts/backlog/backlog-drive-named-offer.ts +3 -5
- package/scripts/backlog/backlog-drive-named.ts +3 -3
- package/scripts/backlog/backlog-drive-offer-argv.ts +1 -1
- package/scripts/backlog/backlog-drive-owner.ts +1 -1
- package/scripts/backlog/backlog-drive-restore.ts +1 -1
- package/scripts/backlog/backlog-drive-retrospective.ts +1 -1
- package/scripts/backlog/backlog-drive.ts +1 -1
- package/scripts/backlog/backlog-next.ts +16 -5
- package/scripts/backlog/backlog-offer-cli.ts +6 -6
- package/scripts/backlog/backlog-offer.ts +1 -1
- package/scripts/backlog/backlog-plan-cli.ts +1 -1
- package/scripts/backlog/backlog-pool.ts +57 -11
- package/scripts/backlog/backlog-ready.ts +1 -1
- package/scripts/backlog/backlog-scope.ts +1 -1
- package/scripts/backlog/backlog-stalled-detect.ts +2 -2
- package/scripts/backlog/backlog-stalled.ts +1 -1
- package/scripts/build/build-codex-hooks.ts +3 -1
- package/scripts/build/build-commands.ts +66 -0
- package/scripts/build/build-hooks.ts +2 -1
- package/scripts/build/build-library.ts +12 -3
- package/scripts/build/build.ts +70 -0
- package/scripts/build/local-bin.ts +3 -13
- package/scripts/delegation/investigation-reads.ts +3 -1
- package/scripts/discovery/repo-origin.ts +5 -5
- package/scripts/doctor/doctor-consumer.ts +2 -2
- package/scripts/doctor/doctor-io.ts +2 -3
- package/scripts/document/capped-print-part.ts +30 -0
- package/scripts/document/capped-print.ts +3 -4
- package/scripts/document/document-byte-budget.ts +11 -2
- package/scripts/document/document-scan.ts +117 -0
- package/scripts/document/document-section.ts +143 -16
- package/scripts/document/entry-read-budget.ts +5 -3
- package/scripts/document/entry-read-set.ts +10 -89
- package/scripts/document/read-set-cost.ts +98 -0
- package/scripts/epic/epic-add-body.ts +1 -0
- package/scripts/epic/epic-audit-checks.ts +1 -1
- package/scripts/epic/epic-audit-rationale.ts +4 -3
- package/scripts/epic/epic-bundle-cli.ts +14 -3
- package/scripts/epic/epic-bundle-poll.ts +41 -0
- package/scripts/epic/epic-busy.ts +1 -1
- package/scripts/epic/epic-candidate-confirm.ts +3 -2
- package/scripts/epic/epic-classify.ts +1 -1
- package/scripts/epic/epic-cli-argv.ts +78 -46
- package/scripts/epic/epic-cli-remove.ts +11 -19
- package/scripts/epic/epic-cli.ts +74 -73
- package/scripts/epic/epic-close-comment.ts +1 -1
- package/scripts/epic/epic-close.ts +1 -1
- package/scripts/epic/epic-cross-repo.ts +5 -5
- package/scripts/epic/epic-graph.ts +1 -1
- package/scripts/epic/epic-index.ts +1 -1
- package/scripts/epic/epic-issue.ts +2 -6
- package/scripts/epic/epic-lane-offer.ts +2 -2
- package/scripts/epic/epic-next.ts +29 -42
- package/scripts/epic/epic-solo-stale.ts +1 -1
- package/scripts/epic/epic-triage.ts +8 -4
- package/scripts/epic/epic-validate.ts +1 -1
- package/scripts/followup/git-followup-finish.ts +2 -2
- package/scripts/followup/git-followup-label.ts +2 -2
- package/scripts/followup/git-followup-merged.ts +2 -2
- package/scripts/followup/git-pr-followup-checks.ts +142 -0
- package/scripts/followup/git-pr-followup.ts +4 -129
- package/scripts/gate/core-admission.ts +162 -0
- package/scripts/gate/core-budget.ts +190 -68
- package/scripts/gate/gate-plan.ts +80 -7
- package/scripts/gate/gate-report.ts +28 -9
- package/scripts/gate/gate-skip.ts +38 -7
- package/scripts/gate/hook-gate-reuse.ts +12 -10
- package/scripts/gate/machine-capacity.ts +175 -0
- 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 +34 -10
- package/scripts/gh/git-gh-api-path.ts +2 -2
- package/scripts/gh/git-gh-issue-rest.ts +3 -3
- package/scripts/gh/git-gh-issue-write.ts +53 -7
- package/scripts/gh/git-gh-pr-read.ts +64 -19
- package/scripts/gh/git-gh-pr-rest.ts +1 -1
- package/scripts/gh/git-gh-pr.ts +5 -1
- package/scripts/gh/git-pr-ai-review.ts +1 -1
- package/scripts/gh/git-pr-checks-eval.ts +1 -3
- package/scripts/gh/git-pr-checks-parse.ts +1 -1
- package/scripts/gh/git-pr-checks-watch.ts +6 -5
- package/scripts/gh/git-pr-checks.ts +7 -5
- package/scripts/gh/git-pr-coderabbit.ts +1 -1
- package/scripts/gh/git-pr-error.ts +1 -3
- package/scripts/gh/git-pr.ts +9 -13
- package/scripts/gh/github-issue-url.ts +2 -2
- package/scripts/git/constants.ts +2 -6
- package/scripts/git/git-command.ts +20 -218
- package/scripts/git/git-diff-reads.ts +225 -0
- package/scripts/git/git-error.ts +4 -12
- package/scripts/git/git-pre-push-hook.ts +139 -0
- package/scripts/git/git-prompt.ts +2 -6
- package/scripts/git/git-spawn-sync.ts +3 -1
- package/scripts/git/git-spawn.ts +1 -1
- package/scripts/git/git-staging.ts +4 -6
- package/scripts/git/git-status.ts +3 -9
- package/scripts/hooks/codex-hook-adapter.ts +1 -1
- package/scripts/hooks/edited-cspell.ts +2 -4
- package/scripts/hooks/format-edited-file.ts +3 -12
- package/scripts/hooks/pre-push-unit.ts +31 -9
- package/scripts/hooks/reserved-run.ts +2 -2
- package/scripts/hooks/run-hook.sh +5 -4
- package/scripts/hooks/stop-guard.ts +5 -3
- package/scripts/init/init-actions.ts +0 -5
- package/scripts/init/init-ai-copy.ts +13 -2
- package/scripts/init/init-logic-json-merge.ts +19 -0
- package/scripts/init/init-logic-secretlint.ts +7 -7
- package/scripts/init/init-logic-workspace.ts +41 -2
- package/scripts/init/init-logic.ts +16 -26
- package/scripts/init/init.ts +10 -16
- 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/package-manager-pin.ts +35 -0
- 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 +32 -7
- 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 +72 -22
- package/scripts/issue/issue-file.ts +29 -1
- package/scripts/issue/issue-labels.ts +13 -0
- package/scripts/issue/issue-release-cli.ts +155 -0
- package/scripts/issue/issue-release.ts +58 -0
- 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 +14 -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 +18 -0
- package/scripts/josh/josh-commands-document.ts +1 -0
- package/scripts/josh/josh-commands-issue.ts +8 -1
- package/scripts/josh/josh-commands-lane.ts +24 -1
- package/scripts/josh/josh-commands-maintenance.ts +6 -6
- package/scripts/josh/josh-commands-run.ts +12 -7
- package/scripts/josh/josh-in-process.ts +28 -9
- package/scripts/josh/josh-logic.ts +34 -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 +12 -4
- package/scripts/lane/lane-dispatch.ts +14 -10
- package/scripts/lane/lane-environment.ts +5 -1
- package/scripts/lane/lane-handoff.ts +1 -1
- package/scripts/lane/lane-install.ts +2 -13
- package/scripts/lane/lane-launch-cli.ts +15 -1
- package/scripts/lane/lane-ledger.ts +145 -0
- package/scripts/lane/lane-leftover.ts +44 -30
- 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-open.ts +5 -5
- package/scripts/lane/lane-paths.ts +13 -0
- package/scripts/lane/lane-reap.ts +1 -3
- package/scripts/lane/lane-registry.ts +11 -0
- package/scripts/lane/lane-relaunch.ts +1 -1
- package/scripts/lane/lane-stats.ts +224 -0
- package/scripts/lane/lane-stray.ts +140 -0
- package/scripts/lane/lane-vacant.ts +36 -0
- package/scripts/lane/openai-lane-ship.ts +2 -2
- package/scripts/lane/openai-lane-supervisor-owner.ts +180 -0
- package/scripts/lane/openai-lane-supervisor.ts +7 -165
- package/scripts/lane/openai-review-broker.ts +2 -4
- package/scripts/lib/ancestor-directories.ts +35 -0
- package/scripts/lib/animation-helpers.ts +2 -2
- package/scripts/lib/buffered-process.ts +3 -7
- package/scripts/lib/cli-flags.ts +71 -1
- package/scripts/lib/spawn-exit.ts +2 -2
- package/scripts/lib/timeouts.ts +35 -2
- package/scripts/lines/line-budget.ts +4 -6
- package/scripts/notify/telegram-test.ts +6 -0
- package/scripts/observations/observation-ledger-line.ts +6 -6
- package/scripts/observations/observation-ledger-migrate.ts +55 -4
- package/scripts/observations/observation-ledger.ts +26 -7
- package/scripts/overrides/lockfile-overrides.ts +1 -1
- package/scripts/overrides/overrides-logic.ts +1 -1
- package/scripts/propagate/propagate-git.ts +1 -1
- package/scripts/propagate/propagate-publish.ts +2 -2
- package/scripts/propagate/propagate-steps.ts +20 -15
- package/scripts/propagate/propagate.ts +36 -27
- package/scripts/refactor/import-graph.ts +18 -1
- package/scripts/refactor/refactor-lint.ts +4 -4
- package/scripts/release/github-release-environment.ts +1 -0
- package/scripts/release/github-release-runs.ts +115 -0
- package/scripts/release/github-release.ts +13 -67
- package/scripts/repo/repository-labels.ts +2 -2
- package/scripts/repo/required-checks-logic.ts +1 -3
- package/scripts/review/live-evidence.ts +2 -4
- package/scripts/review/review-brief-cli.ts +1 -1
- package/scripts/review/review-finding-ledger.ts +1 -1
- package/scripts/review/review-findings-cli.ts +1 -3
- package/scripts/rules/decision-oracle-batch.ts +128 -0
- package/scripts/rules/decision-oracle-tokens.ts +21 -0
- package/scripts/rules/decision-oracle.ts +8 -120
- package/scripts/rules/delivered-rules.ts +26 -182
- package/scripts/rules/direct-filing.ts +1 -1
- package/scripts/rules/early-heartbeat.ts +3 -3
- package/scripts/rules/git-argv.ts +1 -1
- package/scripts/rules/git-force.ts +1 -1
- package/scripts/rules/implementation-cut.ts +2 -2
- package/scripts/rules/index-guard.ts +1 -1
- package/scripts/rules/issue-comments.ts +118 -0
- package/scripts/rules/{issue-fold.ts → issue-fold-rule.ts} +2 -2
- package/scripts/rules/lane-background.ts +2 -2
- package/scripts/rules/lane-park.ts +18 -0
- package/scripts/rules/lane-split-park.ts +128 -0
- package/scripts/rules/oracle-firing.ts +1 -1
- package/scripts/rules/poll-loop.ts +1 -1
- package/scripts/rules/pre-gate-cut.ts +1 -1
- package/scripts/rules/protected-files.ts +59 -4
- package/scripts/rules/{run-tail.ts → run-tail-rule.ts} +2 -2
- package/scripts/rules/shell-body-trigger.ts +1 -1
- package/scripts/rules/stop-rules.ts +18 -7
- package/scripts/rules/test-declared-commit.ts +4 -4
- package/scripts/rules/wip-cap.ts +63 -0
- package/scripts/run/{run-carry-args.ts → carry/run-carry-args.ts} +37 -13
- package/scripts/run/{run-carry-change.ts → carry/run-carry-change.ts} +29 -7
- package/scripts/run/{run-carry-cli.ts → carry/run-carry-cli.ts} +4 -6
- package/scripts/run/{run-carry.ts → carry/run-carry.ts} +1 -1
- package/scripts/run/{run-cut-args.ts → cut/run-cut-args.ts} +1 -1
- package/scripts/run/{run-cut-cli.ts → cut/run-cut-cli.ts} +18 -5
- 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-render.ts → event/run-event-render.ts} +1 -0
- 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} +20 -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 +7 -4
- package/scripts/run/run-stop-notify.ts +1 -1
- package/scripts/run/run-stranded-detect.ts +4 -4
- package/scripts/run/run-stranded.ts +2 -2
- package/scripts/run/run-watcher-guard-cli.ts +1 -1
- package/scripts/run/run-watcher-guard.ts +5 -3
- package/scripts/run/run-watcher-hook.ts +1 -1
- package/scripts/run/{run-ship-cli.ts → ship/run-ship-cli.ts} +2 -2
- package/scripts/run/{run-ship-detach.ts → ship/run-ship-detach.ts} +3 -3
- package/scripts/run/ship/run-ship-lock.ts +50 -0
- package/scripts/run/{run-ship-preflight.ts → ship/run-ship-preflight.ts} +6 -2
- package/scripts/run/{run-ship-probe.ts → ship/run-ship-probe.ts} +2 -2
- package/scripts/run/{run-ship-return.ts → ship/run-ship-return.ts} +4 -3
- package/scripts/run/{run-ship-review-steps.ts → ship/run-ship-review-steps.ts} +3 -3
- package/scripts/run/{run-ship-scoped.ts → ship/run-ship-scoped.ts} +10 -1
- package/scripts/run/{run-ship-steps.ts → ship/run-ship-steps.ts} +11 -12
- package/scripts/run/ship/run-ship-stop-text.ts +13 -0
- package/scripts/run/{run-ship-sync.ts → ship/run-ship-sync.ts} +25 -11
- package/scripts/run/{run-tidy-lanes.ts → tidy/run-tidy-lanes.ts} +1 -1
- package/scripts/run/{run-wake-cli.ts → wake/run-wake-cli.ts} +25 -11
- package/scripts/run/{run-wake-describe.ts → wake/run-wake-describe.ts} +58 -7
- package/scripts/run/{run-wake-driver.ts → wake/run-wake-driver.ts} +59 -8
- package/scripts/run/{run-wake-handoff.ts → wake/run-wake-handoff.ts} +1 -1
- package/scripts/run/{run-wake-loop.ts → wake/run-wake-loop.ts} +13 -15
- 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} +16 -65
- package/scripts/safe-chain/preinstall-command.ts +20 -21
- package/scripts/safe-chain/project-config.ts +19 -15
- package/scripts/sync/sync-ai-files.ts +1 -1
- package/scripts/sync/sync-configs.ts +2 -1
- package/scripts/sync/sync.ts +15 -2
- package/scripts/test/unit-worker-share.ts +1 -0
- package/scripts/time-runtime/time-background.ts +5 -1
- package/scripts/time-runtime/time-instant.ts +3 -1
- package/scripts/time-runtime/time-spans.ts +6 -139
- package/scripts/time-runtime/time-tool-call.ts +160 -0
- package/scripts/version/effective-upstream.ts +2 -20
- package/scripts/version/latest-corepack.ts +124 -93
- 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 +6 -0
- package/scripts/build/build-config-merge.ts +0 -27
- package/scripts/build/build-managed-marker.ts +0 -27
- package/scripts/build/build-self-sync-guard.ts +0 -27
- package/scripts/build/build-version.ts +0 -26
- package/scripts/version/preinstall-version-update.ts +0 -86
- /package/scripts/git/{schemas.ts → git-schemas.ts} +0 -0
- /package/scripts/overrides/{schemas.ts → overrides-schemas.ts} +0 -0
- /package/scripts/run/{run-carry-conversation.ts → carry/run-carry-conversation.ts} +0 -0
- /package/scripts/run/{run-carry-reclaim.ts → carry/run-carry-reclaim.ts} +0 -0
- /package/scripts/run/{run-carry-stash.ts → carry/run-carry-stash.ts} +0 -0
- /package/scripts/run/{run-carry-streak.ts → carry/run-carry-streak.ts} +0 -0
- /package/scripts/run/{run-cut-handoff.ts → cut/run-cut-handoff.ts} +0 -0
- /package/scripts/run/{run-cut-report.ts → cut/run-cut-report.ts} +0 -0
- /package/scripts/run/{run-entry-stop.ts → entry/run-entry-stop.ts} +0 -0
- /package/scripts/run/{run-event-cli.ts → event/run-event-cli.ts} +0 -0
- /package/scripts/run/{run-event-follow.ts → event/run-event-follow.ts} +0 -0
- /package/scripts/run/{run-event-watch.ts → event/run-event-watch.ts} +0 -0
- /package/scripts/run/{run-hold.ts → hold/run-hold.ts} +0 -0
- /package/scripts/run/{run-progress-args.ts → progress/run-progress-args.ts} +0 -0
- /package/scripts/run/{run-progress-clock.ts → progress/run-progress-clock.ts} +0 -0
- /package/scripts/run/{run-review-cli.ts → review/run-review-cli.ts} +0 -0
- /package/scripts/run/{run-review.ts → review/run-review.ts} +0 -0
- /package/scripts/run/{run-ship-next.ts → ship/run-ship-next.ts} +0 -0
- /package/scripts/run/{run-ship-pre-detach.ts → ship/run-ship-pre-detach.ts} +0 -0
- /package/scripts/run/{run-ship-review.ts → ship/run-ship-review.ts} +0 -0
- /package/scripts/run/{run-ship-stage.ts → ship/run-ship-stage.ts} +0 -0
- /package/scripts/run/{run-ship.ts → ship/run-ship.ts} +0 -0
- /package/scripts/run/{run-tidy-cli.ts → tidy/run-tidy-cli.ts} +0 -0
- /package/scripts/run/{run-tidy-stashes.ts → tidy/run-tidy-stashes.ts} +0 -0
- /package/scripts/run/{run-tidy.ts → tidy/run-tidy.ts} +0 -0
|
@@ -3,8 +3,8 @@ import { backlog_budget } from '#scripts/backlog/backlog-budget'
|
|
|
3
3
|
import { process_identity } from '#scripts/josh/process-identity'
|
|
4
4
|
import { process_owner_schema } from '#scripts/josh/process-owner'
|
|
5
5
|
import { stamp_file } from '#scripts/josh/stamp-file'
|
|
6
|
+
import type { CarryRead } from '#scripts/run/carry/run-carry'
|
|
6
7
|
import { z } from 'zod'
|
|
7
|
-
import type { CarryRead } from './run-carry'
|
|
8
8
|
|
|
9
9
|
// joshuafolkken/kit#1719. joshuafolkken/kit#1714 made a `backlogrun`'s budget survive the session cut
|
|
10
10
|
// and left out the one thing that starts the next session, so the record was carried and the
|
|
@@ -126,14 +126,6 @@ interface RunWake {
|
|
|
126
126
|
// session that is merely slow is still doing the run's work, and a supervisor that killed what it
|
|
127
127
|
// could not account for would destroy exactly the work it exists to keep going.
|
|
128
128
|
woke_pid?: number | undefined
|
|
129
|
-
// When the wait on a still-running predecessor began. **It is its own field rather than a second
|
|
130
|
-
// use of `woke_at`, and that is the whole of the bound working as described.** Marked on `woke_at`,
|
|
131
|
-
// the first pass of a wait was the last one that could see the predecessor exit — every later pass
|
|
132
|
-
// read the mark as an outstanding wake and answered `pending` — so a predecessor that ended two
|
|
133
|
-
// seconds after the hold still cost the full grace window on a supervisor whose point is not to
|
|
134
|
-
// stall. Kept apart, the predecessor's liveness is read on every pass and the mark only bounds how
|
|
135
|
-
// long the wait may last.
|
|
136
|
-
held_at?: string | undefined
|
|
137
129
|
// The transcript ids of every session this supervisor forced with `--session-id`
|
|
138
130
|
// (joshuafolkken/kit#2407). `josh time --run` attributes a whiff only to a session in this list, so
|
|
139
131
|
// an unrelated read-only session that moved while the supervisor was alive is no longer counted
|
|
@@ -164,7 +156,6 @@ type WakeDecision =
|
|
|
164
156
|
| { kind: 'idle' }
|
|
165
157
|
| { kind: 'wait' }
|
|
166
158
|
| { kind: 'pending' }
|
|
167
|
-
| { kind: 'hold' }
|
|
168
159
|
| { kind: 'failed' }
|
|
169
160
|
| { kind: 'stop'; reason: WakeStopReason }
|
|
170
161
|
|
|
@@ -172,16 +163,16 @@ interface WakeDecisionInput {
|
|
|
172
163
|
read: CarryRead
|
|
173
164
|
woke_at: string | undefined
|
|
174
165
|
attempts: number
|
|
175
|
-
// Whether the process named on the carry record is still running
|
|
176
|
-
//
|
|
177
|
-
//
|
|
178
|
-
//
|
|
179
|
-
//
|
|
180
|
-
//
|
|
166
|
+
// Whether the process named on the carry record is still running — read only for a record no cut
|
|
167
|
+
// handed off, where it tells a session at work from a crashed one (`decide_not_handed_off`).
|
|
168
|
+
//
|
|
169
|
+
// **A handed-off record is launched from whether its cutting process lives or not**
|
|
170
|
+
// (joshuafolkken/kit#3363). The supervisor used to wait that process out, for up to the grace
|
|
171
|
+
// window, because `run-carry.ts` → `classify_claim` once tested liveness before the hand-off and
|
|
172
|
+
// would have answered the successor `busy`. joshuafolkken/kit#1935 put the hand-off first, so the
|
|
173
|
+
// wait guarded nothing — and an interactive session outlives its own cut, so every cut paid the
|
|
174
|
+
// whole ten minutes before the driver started.
|
|
181
175
|
is_owner_live: boolean
|
|
182
|
-
// When the wait on that predecessor began, so the wait can be bounded without spending the mark
|
|
183
|
-
// that measures a launch.
|
|
184
|
-
held_at: string | undefined
|
|
185
176
|
// **Whether a woken session would find anything to do** (joshuafolkken/kit#2417). Before this the
|
|
186
177
|
// decision read the carry record alone, so a session was launched whether or not the backlog held a
|
|
187
178
|
// runnable issue or a lane was free — and a session that found nothing ended without touching
|
|
@@ -198,7 +189,6 @@ const WAKE_DECISION: WakeDecision = { kind: 'wake' }
|
|
|
198
189
|
const IDLE_DECISION: WakeDecision = { kind: 'idle' }
|
|
199
190
|
const WAIT_DECISION: WakeDecision = { kind: 'wait' }
|
|
200
191
|
const PENDING_DECISION: WakeDecision = { kind: 'pending' }
|
|
201
|
-
const HOLD_DECISION: WakeDecision = { kind: 'hold' }
|
|
202
192
|
const FAILED_DECISION: WakeDecision = { kind: 'failed' }
|
|
203
193
|
|
|
204
194
|
// The three carry reads that are not `carried`, each mapped to why the supervisor stops. `none` is the
|
|
@@ -220,7 +210,6 @@ const run_wake_schema = process_owner_schema.extend({
|
|
|
220
210
|
// reads as "no attempt has been made yet" and would restart the retry count on every pass.
|
|
221
211
|
attempts: z.number().optional(),
|
|
222
212
|
woke_pid: z.number().optional(),
|
|
223
|
-
held_at: z.string().optional(),
|
|
224
213
|
spawned: z.array(z.string()).optional(),
|
|
225
214
|
idle_since: z.string().optional(),
|
|
226
215
|
profile: agent_role_profile.PROFILE_SCHEMA.optional(),
|
|
@@ -279,32 +268,10 @@ function decide_not_handed_off(input: WakeDecisionInput): WakeDecision {
|
|
|
279
268
|
return decide_launch(input)
|
|
280
269
|
}
|
|
281
270
|
|
|
282
|
-
//
|
|
283
|
-
// woken session declares, and waiting on it again would stall the grace window indefinitely.
|
|
284
|
-
//
|
|
285
|
-
// **The wait is bounded, and the bound is not decoration.** The owner is the agent process of the
|
|
286
|
-
// session that cut, and an interactive one often outlives its own cut — waited on without a bound, the
|
|
287
|
-
// supervisor would pend every interval for the record's whole life, wake nothing, and end on `expired`,
|
|
288
|
-
// which sends no warning. That is a silent overnight failure, which is worse than the `busy` race this
|
|
289
|
-
// wait exists to avoid: a `busy` merely costs one attempt, and attempts are retried. So the wait is
|
|
290
|
-
// marked when it starts and expires into an ordinary wake through the same grace window everything
|
|
291
|
-
// else uses.
|
|
292
|
-
//
|
|
293
|
-
// **And the wait ends the moment the predecessor does, because its liveness is read on every pass.**
|
|
294
|
-
// The bound is the ceiling on the wait, never its length: a predecessor that exits two seconds after
|
|
295
|
-
// the hold is waited two seconds. That is what `held_at` is a separate field for — marked on `woke_at`,
|
|
296
|
-
// this test could not fire a second time, so every wait cost the whole ceiling.
|
|
297
|
-
function is_predecessor_exiting(input: WakeDecisionInput): boolean {
|
|
298
|
-
if (input.woke_at !== undefined || !input.is_owner_live) return false
|
|
299
|
-
|
|
300
|
-
return input.held_at === undefined || !is_overdue(input.held_at, input.now)
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
// The whole policy, in four lines. Nothing else in this module decides whether to wake.
|
|
271
|
+
// The whole policy, in three lines. Nothing else in this module decides whether to wake.
|
|
304
272
|
function decide(input: WakeDecisionInput): WakeDecision {
|
|
305
273
|
if (input.read.kind !== 'carried') return { kind: 'stop', reason: STOP_REASONS[input.read.kind] }
|
|
306
274
|
if (input.read.carry.is_handed_off !== true) return decide_not_handed_off(input)
|
|
307
|
-
if (is_predecessor_exiting(input)) return HOLD_DECISION
|
|
308
275
|
|
|
309
276
|
return decide_launch(input)
|
|
310
277
|
}
|
|
@@ -367,10 +334,9 @@ function is_supervisor_live(wake: RunWake): boolean {
|
|
|
367
334
|
// inside the grace window would otherwise see no wake mark, launch a second session for the *same*
|
|
368
335
|
// cut, count it as another cut served, and leave two sessions racing for one record. The invocation
|
|
369
336
|
// has to match — a different one is a different run, and its state is not this one's.
|
|
370
|
-
// **`woke_pid`
|
|
371
|
-
//
|
|
372
|
-
//
|
|
373
|
-
// restarts the bounded wait, which is the ceiling sliding by another road.
|
|
337
|
+
// **`woke_pid` comes across too.** Without it, a restart inside the grace window that then spends its
|
|
338
|
+
// retries reports "the last one was none" in the warning — the one fact the warning exists to hand the
|
|
339
|
+
// person, dropped exactly where it is needed.
|
|
374
340
|
function carried_state(existing: RunWake | undefined, invocation: string): Partial<RunWake> {
|
|
375
341
|
if (existing?.invocation !== invocation) return { woke: NO_WAKES }
|
|
376
342
|
|
|
@@ -379,7 +345,6 @@ function carried_state(existing: RunWake | undefined, invocation: string): Parti
|
|
|
379
345
|
woke_at: existing.woke_at,
|
|
380
346
|
attempts: existing.attempts,
|
|
381
347
|
woke_pid: existing.woke_pid,
|
|
382
|
-
held_at: existing.held_at,
|
|
383
348
|
// **`spawned` carries across too, or a restart mid-run would lose the ids of every session it
|
|
384
349
|
// already started** (joshuafolkken/kit#2407) — and `josh time --run`, reading the record after
|
|
385
350
|
// the restart, would under-count the whiffs and read the loss as a saving.
|
|
@@ -447,24 +412,12 @@ function count_wake(wake: RunWake, now: Date, pid: number, session_id: string):
|
|
|
447
412
|
spawned,
|
|
448
413
|
woke_at,
|
|
449
414
|
woke_pid: pid,
|
|
450
|
-
held_at: undefined,
|
|
451
415
|
idle_since: undefined,
|
|
452
416
|
}
|
|
453
417
|
}
|
|
454
418
|
|
|
455
|
-
// Starts the
|
|
456
|
-
//
|
|
457
|
-
// running until the carry record does.
|
|
458
|
-
//
|
|
459
|
-
// **Marked once, so the ceiling does not slide.** A mark rewritten on every pass would measure from the
|
|
460
|
-
// latest pass rather than from the start of the wait, and a predecessor that never exits would then be
|
|
461
|
-
// waited on for ever — the unbounded wait this bound exists to prevent, arrived at by another road.
|
|
462
|
-
function mark_wait(wake: RunWake, now: Date): RunWake {
|
|
463
|
-
return wake.held_at === undefined ? { ...wake, held_at: now.toISOString() } : wake
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
// Starts the idle stretch a deferred launch is bounded by (joshuafolkken/kit#2417). Marked once, for
|
|
467
|
-
// the reason `mark_wait` is: rewritten each pass, the ceiling would slide and never be reached.
|
|
419
|
+
// Starts the idle stretch a deferred launch is bounded by (joshuafolkken/kit#2417). Marked once:
|
|
420
|
+
// rewritten each pass, the ceiling would slide and never be reached.
|
|
468
421
|
function mark_idle(wake: RunWake, now: Date): RunWake {
|
|
469
422
|
return wake.idle_since === undefined ? { ...wake, idle_since: now.toISOString() } : wake
|
|
470
423
|
}
|
|
@@ -489,7 +442,6 @@ function count_claim(wake: RunWake): RunWake {
|
|
|
489
442
|
woke,
|
|
490
443
|
woke_at: undefined,
|
|
491
444
|
attempts: undefined,
|
|
492
|
-
held_at: undefined,
|
|
493
445
|
idle_since: undefined,
|
|
494
446
|
}
|
|
495
447
|
}
|
|
@@ -589,7 +541,6 @@ const run_wake = {
|
|
|
589
541
|
fresh_wake,
|
|
590
542
|
is_supervisor_live,
|
|
591
543
|
mark_idle,
|
|
592
|
-
mark_wait,
|
|
593
544
|
parse_wake,
|
|
594
545
|
read_own_wake,
|
|
595
546
|
read_wake,
|
|
@@ -1,38 +1,37 @@
|
|
|
1
|
-
// `
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
// The `preinstall` kit writes fetches nothing: it only checks that safe-chain is scanning the install
|
|
2
|
+
// and warns when it is not (joshuafolkken/kit#3269). It used to run `pnpm dlx @aikidosec/safe-chain
|
|
3
|
+
// setup-ci`, which downloaded an unverified package on every install and — `setup-ci` acting only on
|
|
4
|
+
// a CI runner, where kit installs with `--ignore-scripts` — protected nothing. safe-chain's shell
|
|
5
|
+
// integration runs pnpm behind its registry proxy and hands `GLOBAL_AGENT_HTTP_PROXY` to it, which a
|
|
6
|
+
// bare pnpm never sets — the one signal a lifecycle script can read (joshuafolkken/kit#2707).
|
|
7
|
+
const INSTALL_GUIDE_ANCHOR = 'installing-safe-chain'
|
|
8
|
+
const INSTALL_GUIDE_URL = `https://github.com/joshuafolkken/kit/blob/main/SECURITY.md#${INSTALL_GUIDE_ANCHOR}`
|
|
9
|
+
// `.pnpmfile.mjs` recognizes the command by the package name, so the hint names it.
|
|
7
10
|
const INTEGRATION_HINT =
|
|
8
|
-
'Warning: safe-chain is not scanning this install because its shell
|
|
9
|
-
|
|
11
|
+
'Warning: safe-chain (@aikidosec/safe-chain) is not scanning this install because its shell' +
|
|
12
|
+
` integration is not active. Install it with the hash-verified steps at ${INSTALL_GUIDE_URL}` +
|
|
10
13
|
' - then restart your terminal.'
|
|
11
14
|
// `preinstall` runs before any dependency is installed, kit included, so the check is plain Node with
|
|
12
15
|
// no imports. It never fails the install and stays silent on CI, where the runner is set up instead.
|
|
13
16
|
// The source avoids double quotes, `$` and backticks so the shell passes it to Node verbatim.
|
|
14
17
|
const LOCAL_INTEGRATION_CHECK_SOURCE = `if(!process.env.CI&&!process.env.GLOBAL_AGENT_HTTP_PROXY)console.warn('${INTEGRATION_HINT}')`
|
|
15
|
-
const
|
|
18
|
+
const SAFE_CHAIN_CMD = `node -e "${LOCAL_INTEGRATION_CHECK_SOURCE}"`
|
|
19
|
+
// Every `preinstall` an earlier kit wrote: `setup-ci` alone, pinned or not, or followed by the
|
|
20
|
+
// `node -e` check of any earlier wording.
|
|
21
|
+
const LEGACY_PREINSTALL_RE =
|
|
22
|
+
/^pnpm dlx @aikidosec\/safe-chain(?:@\S+)? setup-ci(?: && node -e "[^"]*")?$/u
|
|
16
23
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// Upgrade a `preinstall` kit wrote before the check existed, pinned version included; any other
|
|
22
|
-
// value is the consumer's own and is left exactly as it is.
|
|
24
|
+
// Replace a `preinstall` kit wrote earlier; any other value is the consumer's own and is left exactly
|
|
25
|
+
// as it is.
|
|
23
26
|
function migrate_preinstall(value: string): string {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
return with_local_check(value)
|
|
27
|
+
return LEGACY_PREINSTALL_RE.test(value) ? SAFE_CHAIN_CMD : value
|
|
27
28
|
}
|
|
28
29
|
|
|
29
|
-
const SAFE_CHAIN_CMD = with_local_check(SETUP_CI_CMD)
|
|
30
|
-
|
|
31
30
|
const safe_chain_preinstall = {
|
|
32
31
|
SAFE_CHAIN_CMD,
|
|
33
|
-
LOCAL_INTEGRATION_CHECK_CMD,
|
|
34
32
|
LOCAL_INTEGRATION_CHECK_SOURCE,
|
|
35
33
|
INTEGRATION_HINT,
|
|
34
|
+
INSTALL_GUIDE_ANCHOR,
|
|
36
35
|
migrate_preinstall,
|
|
37
36
|
}
|
|
38
37
|
|
|
@@ -8,7 +8,6 @@ import { z } from 'zod'
|
|
|
8
8
|
|
|
9
9
|
const WORKSPACE_FILE = 'pnpm-workspace.yaml'
|
|
10
10
|
const PROJECT_CONFIG_FILE = '.aikido'
|
|
11
|
-
const NPMRC_FILE = '.npmrc'
|
|
12
11
|
const EXCLUSIONS_FIELD = 'minimumPackageAgeExclusions'
|
|
13
12
|
const AGE_FIELD = 'minimumPackageAgeHours'
|
|
14
13
|
const MINUTES_PER_HOUR = 60
|
|
@@ -78,18 +77,22 @@ function replace_safe_chain_block(existing: string, safe_chain: Record<string, u
|
|
|
78
77
|
}
|
|
79
78
|
|
|
80
79
|
// Safe Chain enforces its own minimum package age (48 hours by default), so CI refused lockfiles pnpm
|
|
81
|
-
// had resolved under
|
|
82
|
-
// floored to whole hours so Safe Chain is never stricter than pnpm, and an
|
|
83
|
-
// nothing; an explicit `0` opt-out is written as 0 so an earlier
|
|
84
|
-
|
|
85
|
-
|
|
80
|
+
// had resolved under pnpm's shorter window (kit #2743). The workspace's `minimumReleaseAge` is the
|
|
81
|
+
// source: its minutes are floored to whole hours so Safe Chain is never stricter than pnpm, and an
|
|
82
|
+
// undeclared window writes nothing; an explicit `0` opt-out is written as 0 so an earlier
|
|
83
|
+
// synchronized age cannot outlive it.
|
|
84
|
+
function package_age_hours(workspace: string): number | undefined {
|
|
85
|
+
const minutes = release_age.parse_declared_minimum_release_age(workspace)
|
|
86
86
|
if (minutes === undefined) return undefined
|
|
87
87
|
|
|
88
88
|
return Math.floor(minutes / MINUTES_PER_HOUR)
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
function merge_age(
|
|
92
|
-
|
|
91
|
+
function merge_age(
|
|
92
|
+
safe_chain: Record<string, unknown>,
|
|
93
|
+
workspace: string,
|
|
94
|
+
): Record<string, unknown> {
|
|
95
|
+
const hours = package_age_hours(workspace)
|
|
93
96
|
if (hours === undefined) return safe_chain
|
|
94
97
|
|
|
95
98
|
return { ...safe_chain, [AGE_FIELD]: hours }
|
|
@@ -107,22 +110,24 @@ function merge_exclusions(
|
|
|
107
110
|
function has_nothing_to_write(
|
|
108
111
|
existing: string,
|
|
109
112
|
exclusions: ReadonlyArray<string>,
|
|
110
|
-
|
|
113
|
+
workspace: string,
|
|
111
114
|
): boolean {
|
|
112
|
-
return
|
|
115
|
+
return (
|
|
116
|
+
existing.length === 0 && exclusions.length === 0 && package_age_hours(workspace) === undefined
|
|
117
|
+
)
|
|
113
118
|
}
|
|
114
119
|
|
|
115
120
|
function read_exclusions(workspace: string): ReadonlyArray<string> {
|
|
116
121
|
return workspace_schema.parse(yaml_document.parse_yaml(workspace)).minimumReleaseAgeExclude ?? []
|
|
117
122
|
}
|
|
118
123
|
|
|
119
|
-
function merge_project_config(existing: string, workspace: string
|
|
124
|
+
function merge_project_config(existing: string, workspace: string): string {
|
|
120
125
|
const exclusions = read_exclusions(workspace)
|
|
121
126
|
const aikido = yaml_document.parse_yaml(existing)
|
|
122
127
|
const safe_chain = read_mapping(aikido['safe-chain'], 'safe-chain')
|
|
123
|
-
const merged = merge_age(merge_exclusions(safe_chain, exclusions),
|
|
128
|
+
const merged = merge_age(merge_exclusions(safe_chain, exclusions), workspace)
|
|
124
129
|
if (JSON.stringify(merged) === JSON.stringify(safe_chain)) return existing
|
|
125
|
-
if (has_nothing_to_write(existing, exclusions,
|
|
130
|
+
if (has_nothing_to_write(existing, exclusions, workspace)) return existing
|
|
126
131
|
|
|
127
132
|
return replace_safe_chain_block(existing, merged)
|
|
128
133
|
}
|
|
@@ -133,8 +138,7 @@ function sync_project_config(root: string): boolean {
|
|
|
133
138
|
const config_path = path.join(root, PROJECT_CONFIG_FILE)
|
|
134
139
|
const existing = file_reader.read_file_or_empty(config_path)
|
|
135
140
|
const workspace = readFileSync(workspace_path, 'utf8')
|
|
136
|
-
const
|
|
137
|
-
const merged = merge_project_config(existing, workspace, npmrc)
|
|
141
|
+
const merged = merge_project_config(existing, workspace)
|
|
138
142
|
if (merged === existing) return false
|
|
139
143
|
writeFileSync(config_path, merged)
|
|
140
144
|
|
|
@@ -71,7 +71,7 @@ function sync_workspace_yaml(
|
|
|
71
71
|
destination_path: string,
|
|
72
72
|
is_force = false,
|
|
73
73
|
): boolean {
|
|
74
|
-
const template =
|
|
74
|
+
const template = init_ai_copy.read_workspace_template(template_path, destination_path)
|
|
75
75
|
const existing = is_force ? '' : file_reader.read_file_or_empty(destination_path)
|
|
76
76
|
const merged = init_logic.merge_workspace_yaml(existing, template)
|
|
77
77
|
|
|
@@ -29,7 +29,8 @@ function sync_with_merge(
|
|
|
29
29
|
console.info(` ✔ synced ${destination_name}`)
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
//
|
|
32
|
+
// Removes only the exact settings lines earlier kit releases wrote, which pnpm 12 ignores in
|
|
33
|
+
// `.npmrc` (joshuafolkken/kit#3267); every other line, a `_authToken` line included, is left alone.
|
|
33
34
|
// Sync used to remove the env-var form, which broke every project that had opted its project
|
|
34
35
|
// .npmrc in via `npmrcAuthFile` — there the line is the live credential, and the opt-in itself
|
|
35
36
|
// can live in a deploy platform's dashboard where sync cannot see it (joshuafolkken/kit#759).
|
package/scripts/sync/sync.ts
CHANGED
|
@@ -192,12 +192,23 @@ function sync_prepare_lefthook_warning(destination_path: string): void {
|
|
|
192
192
|
)
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
+
// The `preinstall` earlier kits wrote fetched safe-chain on every install (joshuafolkken/kit#3269);
|
|
196
|
+
// `josh init` replaces it, and this covers everyone already initialized.
|
|
197
|
+
function sync_safe_chain_preinstall(destination_path: string): void {
|
|
198
|
+
sync_package_json_with(
|
|
199
|
+
destination_path,
|
|
200
|
+
(existing) => init_logic.upgrade_safe_chain_preinstall(existing),
|
|
201
|
+
' ✔ synced preinstall safe-chain check',
|
|
202
|
+
)
|
|
203
|
+
}
|
|
204
|
+
|
|
195
205
|
// Every migration an already-initialized consumer needs applied to its own manifest, run as one
|
|
196
206
|
// group so the next one is added here rather than at the call site.
|
|
197
207
|
function sync_package_json_migrations(destination_path: string): void {
|
|
198
208
|
sync_package_manager_version(destination_path)
|
|
199
209
|
sync_secretlint_development_deps(destination_path)
|
|
200
210
|
sync_prepare_lefthook_warning(destination_path)
|
|
211
|
+
sync_safe_chain_preinstall(destination_path)
|
|
201
212
|
}
|
|
202
213
|
|
|
203
214
|
// Two distributed artifacts each depend on a repository setting kit cannot write, and both reports
|
|
@@ -230,8 +241,8 @@ function sync_project_artifacts(is_force: boolean): void {
|
|
|
230
241
|
|
|
231
242
|
sync_sonar_with_template(name_with_owner, is_force)
|
|
232
243
|
sync_config_files()
|
|
233
|
-
// After `
|
|
234
|
-
// (joshuafolkken/kit#2743).
|
|
244
|
+
// After `sync_ai_copy_all`, which may add the `pnpm-workspace.yaml` window `.aikido`'s age is
|
|
245
|
+
// derived from (joshuafolkken/kit#2743, #3267).
|
|
235
246
|
project_config.sync_project_config(PROJECT_ROOT)
|
|
236
247
|
sync_package_json_migrations(path.join(PROJECT_ROOT, PACKAGE_JSON))
|
|
237
248
|
report_repository_settings(name_with_owner)
|
|
@@ -277,6 +288,8 @@ const sync = {
|
|
|
277
288
|
sync_package_manager_version,
|
|
278
289
|
sync_secretlint_development_deps,
|
|
279
290
|
sync_prepare_lefthook_warning,
|
|
291
|
+
sync_safe_chain_preinstall,
|
|
292
|
+
sync_package_json_migrations,
|
|
280
293
|
migrate_prettierrc: did_migrate_prettierrc,
|
|
281
294
|
}
|
|
282
295
|
|
|
@@ -49,7 +49,11 @@ const NO_FINISH = 0
|
|
|
49
49
|
|
|
50
50
|
// The launch's own result body, which is the only place the harness writes the id it assigns. Read
|
|
51
51
|
// as a derived fact and the body discarded, exactly as `has_failure_line` and `followup_stages` are.
|
|
52
|
-
|
|
52
|
+
// **A foreground call that outran its timeout is a launch too** (joshuafolkken/kit#3304): the harness
|
|
53
|
+
// moves it to the background and says so as `moved to the background (ID: <id>)`. Missing that spelling
|
|
54
|
+
// let the #3273 lane child end its turn on a running task the stop hook never saw.
|
|
55
|
+
const LAUNCH_PATTERN =
|
|
56
|
+
/(?:running in background with ID:|moved to the background \(ID:)\s*([\w-]+)/iu
|
|
53
57
|
// A backgrounded subagent's launch result, which names its id on an `agentId:` line of its own.
|
|
54
58
|
const AGENT_LAUNCH_PATTERN = /^Async agent launched[\s\S]*?\bagentId:\s*([\w-]+)/u
|
|
55
59
|
// The notice the harness writes when a task it took into the background ends
|
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
// clone `CLAUDE.md` prohibits, and the two copies would disagree the first time one of them learned
|
|
11
11
|
// to accept another format.
|
|
12
12
|
function parse_instant(raw: string | null | undefined): number | undefined {
|
|
13
|
-
|
|
13
|
+
if (raw === null || raw === undefined) return undefined
|
|
14
|
+
|
|
15
|
+
const parsed = Date.parse(raw)
|
|
14
16
|
|
|
15
17
|
return Number.isNaN(parsed) ? undefined : parsed
|
|
16
18
|
}
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import { cost_blocks } from '#scripts/cost-runtime/cost-blocks'
|
|
2
2
|
import type { FollowupStage } from '#scripts/followup/git-followup-stages'
|
|
3
3
|
import { time_background } from './time-background'
|
|
4
|
-
import { time_bundle_call } from './time-bundle-call'
|
|
5
4
|
import { time_followup_stage } from './time-followup-stage'
|
|
6
|
-
import { time_markers, type PhaseMarker } from './time-markers'
|
|
7
5
|
import { time_reported_failure } from './time-reported-failure'
|
|
8
6
|
import { time_shell } from './time-shell'
|
|
9
|
-
import {
|
|
7
|
+
import { time_tool_call, type ToolCall } from './time-tool-call'
|
|
10
8
|
import { time_transcript_line, type Block, type TranscriptLine } from './time-transcript-line'
|
|
11
|
-
import { time_writes } from './time-writes'
|
|
12
9
|
|
|
13
10
|
const { NO_MESSAGE_ID, parse_line } = time_transcript_line
|
|
11
|
+
const { NO_CALL, UNKNOWN_CALL, UNKNOWN_TOOL, to_tool_call } = time_tool_call
|
|
14
12
|
|
|
15
13
|
// Turning a session transcript into timed spans (joshuafolkken/kit#1267).
|
|
16
14
|
//
|
|
@@ -24,6 +22,10 @@ const { NO_MESSAGE_ID, parse_line } = time_transcript_line
|
|
|
24
22
|
// the move changed no call site. `cost_blocks`' three type constants are still imported rather than
|
|
25
23
|
// restated.
|
|
26
24
|
//
|
|
25
|
+
// **Reading a `tool_use` block into a `ToolCall` is `time-tool-call.ts`'s** since
|
|
26
|
+
// joshuafolkken/kit#3264, when this file reached its length limit again. `UNKNOWN_TOOL` and
|
|
27
|
+
// `to_tool_call` are re-exported below, so that move changed no call site either.
|
|
28
|
+
//
|
|
27
29
|
// **The partition is by gap, not by pair.** Every span is the interval between two consecutive
|
|
28
30
|
// events, classified by the *later* one: a span ending at an assistant line is model wait, one
|
|
29
31
|
// ending at a tool result is that tool's execution, one ending at a user prompt is human wait.
|
|
@@ -34,7 +36,6 @@ const { NO_MESSAGE_ID, parse_line } = time_transcript_line
|
|
|
34
36
|
|
|
35
37
|
const ASSISTANT_TYPE = 'assistant'
|
|
36
38
|
const USER_TYPE = 'user'
|
|
37
|
-
const UNKNOWN_TOOL = 'unknown'
|
|
38
39
|
|
|
39
40
|
type SpanCategory = 'model' | 'tool' | 'human'
|
|
40
41
|
|
|
@@ -90,96 +91,6 @@ const NO_RESULT: ResultFacts = {
|
|
|
90
91
|
followup_stages: time_followup_stage.NO_STAGES,
|
|
91
92
|
}
|
|
92
93
|
|
|
93
|
-
// What a tool span is labelled with. `josh_command` is empty for everything that is not a
|
|
94
|
-
// `pnpm josh <cmd>` invocation, and the report drops empty labels rather than printing a bucket.
|
|
95
|
-
//
|
|
96
|
-
// `marker` names the workflow boundary the call is, for the phase breakdown that slices the same
|
|
97
|
-
// spans by stage (joshuafolkken/kit#1269). It is carried here rather than re-derived later because
|
|
98
|
-
// the tool's *input* is what decides it, and a span keeps no input — only the label read off it.
|
|
99
|
-
//
|
|
100
|
-
// `is_bundleable` and `targets` are carried for exactly that reason too (joshuafolkken/kit#1344).
|
|
101
|
-
// Whether a call could have gone out beside another, and what it names, are both read off the input —
|
|
102
|
-
// so a module asking about them after the fact would have nothing to read. `time-bundle-call.ts`
|
|
103
|
-
// decides both; the rule each one follows is stated there.
|
|
104
|
-
//
|
|
105
|
-
// `check_key` is the fourth, and the third time this reason has applied (joshuafolkken/kit#1383). Two
|
|
106
|
-
// runs of one verification check are the same call only if they named the same files, and the files
|
|
107
|
-
// are in the input — so `josh_command` alone cannot say, and nothing downstream could recover it.
|
|
108
|
-
// `time-single-check.ts` decides it.
|
|
109
|
-
//
|
|
110
|
-
// `message_id` is the fifth, and it is the one that says which *turn* a call belongs to
|
|
111
|
-
// (joshuafolkken/kit#1406). It is read off the line the `tool_use` block sat on rather than off the
|
|
112
|
-
// result that closes the span, because a `tool_result` line carries no message id at all — so a span
|
|
113
|
-
// that did not keep it here could never be attributed to the turn that issued it.
|
|
114
|
-
//
|
|
115
|
-
// `writes` is the sixth, and it is what `targets` could not say (joshuafolkken/kit#1472). `targets`
|
|
116
|
-
// names what a call mentioned; `marker` says a call was *an* edit but not of what, and for a tool
|
|
117
|
-
// outside `BUNDLEABLE_TOOLS` it arrived with no target at all. So a consumer subtracting edits from
|
|
118
|
-
// reads — `investigation-reads.ts` — had nothing to subtract for `MultiEdit` / `NotebookEdit`, and
|
|
119
|
-
// nothing at all to tell an in-place `sed -i` from the `sed -n` it shares a label with.
|
|
120
|
-
// `time-writes.ts` decides it, from the input this span is about to discard.
|
|
121
|
-
// `issue` is the seventh, and it is the one `branch` could not carry (joshuafolkken/kit#1617). Under
|
|
122
|
-
// lanes the session writing the transcript stays on the default branch while the work runs in a linked
|
|
123
|
-
// work tree, so `branch` names no issue on any line of the run; the `in-progress` label call does, and
|
|
124
|
-
// like every field above it that answer is read off the *input* a span is about to discard.
|
|
125
|
-
// `time_markers.NO_ISSUE` for every call that declares nothing, which is all but one call per run.
|
|
126
|
-
interface ToolCall {
|
|
127
|
-
label: string
|
|
128
|
-
josh_command: string
|
|
129
|
-
// Every josh subcommand the call ran, where `josh_command` is only the first (joshuafolkken/kit#1883).
|
|
130
|
-
// A chained `pnpm josh lint:related && pnpm josh test:related` carries both; the count tables expand
|
|
131
|
-
// it so the ones `josh_command` drops are still counted.
|
|
132
|
-
josh_commands: ReadonlyArray<string>
|
|
133
|
-
check_key: string
|
|
134
|
-
marker: PhaseMarker
|
|
135
|
-
is_bundleable: boolean
|
|
136
|
-
targets: ReadonlyArray<string>
|
|
137
|
-
// Carried beside `targets` because sharing a target means something different depending on it: a
|
|
138
|
-
// second write to one file is independent work, a read of a file just written is not
|
|
139
|
-
// (joshuafolkken/kit#1509).
|
|
140
|
-
is_writing: boolean
|
|
141
|
-
// The conservative write answer `is_read_only_call` asks of a live call, carried so a reader of the
|
|
142
|
-
// transcript asks the same read-only question as the guard (joshuafolkken/kit#3139).
|
|
143
|
-
may_write: boolean
|
|
144
|
-
// Whether this is a subagent launch whose prompt builds on an earlier launch's finding
|
|
145
|
-
// (joshuafolkken/kit#1854). Carried for the reason every field here is — the prompt it is read from
|
|
146
|
-
// is the input, and a span keeps none. `time-agent-bundles.ts` reads it.
|
|
147
|
-
has_prior_reference: boolean
|
|
148
|
-
writes: ReadonlyArray<string>
|
|
149
|
-
message_id: string
|
|
150
|
-
issue: number
|
|
151
|
-
// The background run this call reads the output of, and `''` for every other call
|
|
152
|
-
// (joshuafolkken/kit#1662). It is the eighth field carried for the reason the seven above are:
|
|
153
|
-
// the id sits in the command string, which a span does not keep, and it is the only thing that
|
|
154
|
-
// says a `tail` two turns later is the join of a command started minutes ago.
|
|
155
|
-
reads_background: string
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const NO_CALL: ToolCall = {
|
|
159
|
-
label: '',
|
|
160
|
-
josh_command: '',
|
|
161
|
-
josh_commands: [],
|
|
162
|
-
check_key: time_single_check.NO_CHECK,
|
|
163
|
-
marker: time_markers.NO_MARKER,
|
|
164
|
-
message_id: NO_MESSAGE_ID,
|
|
165
|
-
writes: [],
|
|
166
|
-
issue: time_markers.NO_ISSUE,
|
|
167
|
-
reads_background: time_background.NO_BACKGROUND,
|
|
168
|
-
...time_bundle_call.not_bundleable(),
|
|
169
|
-
}
|
|
170
|
-
const UNKNOWN_CALL: ToolCall = {
|
|
171
|
-
label: UNKNOWN_TOOL,
|
|
172
|
-
josh_command: '',
|
|
173
|
-
josh_commands: [],
|
|
174
|
-
check_key: time_single_check.NO_CHECK,
|
|
175
|
-
marker: time_markers.NO_MARKER,
|
|
176
|
-
message_id: NO_MESSAGE_ID,
|
|
177
|
-
writes: [],
|
|
178
|
-
issue: time_markers.NO_ISSUE,
|
|
179
|
-
reads_background: time_background.NO_BACKGROUND,
|
|
180
|
-
...time_bundle_call.not_bundleable(),
|
|
181
|
-
}
|
|
182
|
-
|
|
183
94
|
// `ended_ms` is the absolute instant the span closed, so `[ended_ms - duration_ms, ended_ms]` is the
|
|
184
95
|
// interval it occupied. A duration alone cannot say *when*, and two things need that: the CI wait,
|
|
185
96
|
// which is the part of the PR-open→merge window no span covers (joshuafolkken/kit#1268), and the
|
|
@@ -242,50 +153,6 @@ interface Timeline {
|
|
|
242
153
|
spans: Array<Span>
|
|
243
154
|
}
|
|
244
155
|
|
|
245
|
-
// Everything but Bash: the tool's own name is the label, and nothing it runs is a shell command to
|
|
246
|
-
// read a check key, a josh command or a declared issue off.
|
|
247
|
-
function non_bash_call(name: string, input: unknown, message_id: string): ToolCall {
|
|
248
|
-
return {
|
|
249
|
-
label: name,
|
|
250
|
-
josh_command: '',
|
|
251
|
-
josh_commands: [],
|
|
252
|
-
check_key: time_single_check.NO_CHECK,
|
|
253
|
-
marker: time_markers.tool_marker(name, input),
|
|
254
|
-
message_id,
|
|
255
|
-
writes: time_writes.tool_writes(name, input),
|
|
256
|
-
issue: time_markers.NO_ISSUE,
|
|
257
|
-
// A non-Bash tool joins a backgrounded command too — `BashOutput` carries the shell id in a
|
|
258
|
-
// field of its own, `Monitor` names the same `…/tasks/<id>.output` path in a command — so the
|
|
259
|
-
// same reader is asked here rather than the field being left empty for every tool but `Bash`.
|
|
260
|
-
reads_background: time_background.read_id_of(input),
|
|
261
|
-
...time_bundle_call.tool_facts(name, input),
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
function bash_call(input: unknown, message_id: string): ToolCall {
|
|
266
|
-
const command = time_shell.bash_command(input)
|
|
267
|
-
const josh_command = time_shell.josh_command_of(command)
|
|
268
|
-
|
|
269
|
-
return {
|
|
270
|
-
label: time_shell.bash_label(command),
|
|
271
|
-
josh_command,
|
|
272
|
-
josh_commands: time_shell.josh_commands_of(command),
|
|
273
|
-
check_key: time_single_check.check_key(josh_command, command),
|
|
274
|
-
marker: time_markers.bash_marker(command),
|
|
275
|
-
message_id,
|
|
276
|
-
writes: time_writes.bash_writes(command),
|
|
277
|
-
issue: time_markers.bash_issue(command),
|
|
278
|
-
reads_background: time_background.read_id_of(input),
|
|
279
|
-
...time_bundle_call.bash_facts(command),
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
function to_tool_call(name: string, input: unknown, message_id: string): ToolCall {
|
|
284
|
-
if (name !== cost_blocks.BASH_TOOL) return non_bash_call(name, input, message_id)
|
|
285
|
-
|
|
286
|
-
return bash_call(input, message_id)
|
|
287
|
-
}
|
|
288
|
-
|
|
289
156
|
// Identified calls only. A `tool_use` written without an `id` would otherwise be registered under
|
|
290
157
|
// the empty string, where the next result that carries no `tool_use_id` would match it and be
|
|
291
158
|
// labelled with an unrelated tool — a wrong name where `UNKNOWN_TOOL` is the honest one.
|