@joshuafolkken/kit 1.1178.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 +6 -2
- package/.claude/skills/workflow-commands/backlogrun-park.md +23 -2
- 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 +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 +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 +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 +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-S6X6WYKR.js → chunk-55HHG5PX.js} +1210 -711
- package/dist/hooks/{chunk-ZAL3NRGL.js → chunk-5VMKCCC4.js} +25 -10
- package/dist/hooks/chunk-5VNDSNG3.js +12 -0
- package/dist/hooks/{chunk-32GQTL4F.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-VESKRQOF.js → chunk-F56MFS4B.js} +3 -3
- package/dist/hooks/{chunk-UAGLLIGZ.js → chunk-FIVDHQGT.js} +7 -6
- package/dist/hooks/{chunk-3V37IID6.js → chunk-JBBMAPC4.js} +23 -14
- package/dist/hooks/{chunk-G6KRCKEC.js → chunk-JUDKDCDP.js} +496 -378
- package/dist/hooks/{chunk-GDS5N2KB.js → chunk-NV2JRZZO.js} +718 -681
- package/dist/hooks/{chunk-VQLLNFNT.js → chunk-RNWHN5BP.js} +3 -3
- package/dist/hooks/{chunk-DO6NWWHU.js → chunk-TQNPDZNH.js} +4 -4
- package/dist/hooks/{chunk-I4XSL4TT.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 +217 -195
- 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 -58
- package/dist/josh.js +868 -74
- 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 +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-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-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 +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 +10 -0
- 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 +15 -1
- 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-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 +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} +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} +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} +23 -8
- 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} +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} +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/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 +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/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-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-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
|
@@ -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.
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { cost_blocks } from '#scripts/cost-runtime/cost-blocks'
|
|
2
|
+
import { time_background } from './time-background'
|
|
3
|
+
import { time_bundle_call } from './time-bundle-call'
|
|
4
|
+
import { time_markers, type PhaseMarker } from './time-markers'
|
|
5
|
+
import { time_shell } from './time-shell'
|
|
6
|
+
import { time_single_check } from './time-single-check'
|
|
7
|
+
import { time_transcript_line } from './time-transcript-line'
|
|
8
|
+
import { time_writes } from './time-writes'
|
|
9
|
+
|
|
10
|
+
// Reading a `tool_use` block into the label a span carries — split out of `time-spans.ts` when it
|
|
11
|
+
// reached its line limit (joshuafolkken/kit#3264). `time_spans` re-exports `UNKNOWN_TOOL` and
|
|
12
|
+
// `to_tool_call` under the names they always had, so the move changed no call site.
|
|
13
|
+
|
|
14
|
+
const { NO_MESSAGE_ID } = time_transcript_line
|
|
15
|
+
|
|
16
|
+
const UNKNOWN_TOOL = 'unknown'
|
|
17
|
+
|
|
18
|
+
// What a tool span is labelled with. `josh_command` is empty for everything that is not a
|
|
19
|
+
// `pnpm josh <cmd>` invocation, and the report drops empty labels rather than printing a bucket.
|
|
20
|
+
//
|
|
21
|
+
// `marker` names the workflow boundary the call is, for the phase breakdown that slices the same
|
|
22
|
+
// spans by stage (joshuafolkken/kit#1269). It is carried here rather than re-derived later because
|
|
23
|
+
// the tool's *input* is what decides it, and a span keeps no input — only the label read off it.
|
|
24
|
+
//
|
|
25
|
+
// `is_bundleable` and `targets` are carried for exactly that reason too (joshuafolkken/kit#1344).
|
|
26
|
+
// Whether a call could have gone out beside another, and what it names, are both read off the input —
|
|
27
|
+
// so a module asking about them after the fact would have nothing to read. `time-bundle-call.ts`
|
|
28
|
+
// decides both; the rule each one follows is stated there.
|
|
29
|
+
//
|
|
30
|
+
// `check_key` is the fourth, and the third time this reason has applied (joshuafolkken/kit#1383). Two
|
|
31
|
+
// runs of one verification check are the same call only if they named the same files, and the files
|
|
32
|
+
// are in the input — so `josh_command` alone cannot say, and nothing downstream could recover it.
|
|
33
|
+
// `time-single-check.ts` decides it.
|
|
34
|
+
//
|
|
35
|
+
// `message_id` is the fifth, and it is the one that says which *turn* a call belongs to
|
|
36
|
+
// (joshuafolkken/kit#1406). It is read off the line the `tool_use` block sat on rather than off the
|
|
37
|
+
// result that closes the span, because a `tool_result` line carries no message id at all — so a span
|
|
38
|
+
// that did not keep it here could never be attributed to the turn that issued it.
|
|
39
|
+
//
|
|
40
|
+
// `writes` is the sixth, and it is what `targets` could not say (joshuafolkken/kit#1472). `targets`
|
|
41
|
+
// names what a call mentioned; `marker` says a call was *an* edit but not of what, and for a tool
|
|
42
|
+
// outside `BUNDLEABLE_TOOLS` it arrived with no target at all. So a consumer subtracting edits from
|
|
43
|
+
// reads — `investigation-reads.ts` — had nothing to subtract for `MultiEdit` / `NotebookEdit`, and
|
|
44
|
+
// nothing at all to tell an in-place `sed -i` from the `sed -n` it shares a label with.
|
|
45
|
+
// `time-writes.ts` decides it, from the input this span is about to discard.
|
|
46
|
+
// `issue` is the seventh, and it is the one `branch` could not carry (joshuafolkken/kit#1617). Under
|
|
47
|
+
// lanes the session writing the transcript stays on the default branch while the work runs in a linked
|
|
48
|
+
// work tree, so `branch` names no issue on any line of the run; the `in-progress` label call does, and
|
|
49
|
+
// like every field above it that answer is read off the *input* a span is about to discard.
|
|
50
|
+
// `time_markers.NO_ISSUE` for every call that declares nothing, which is all but one call per run.
|
|
51
|
+
interface ToolCall {
|
|
52
|
+
label: string
|
|
53
|
+
josh_command: string
|
|
54
|
+
// Every josh subcommand the call ran, where `josh_command` is only the first (joshuafolkken/kit#1883).
|
|
55
|
+
// A chained `pnpm josh lint:related && pnpm josh test:related` carries both; the count tables expand
|
|
56
|
+
// it so the ones `josh_command` drops are still counted.
|
|
57
|
+
josh_commands: ReadonlyArray<string>
|
|
58
|
+
check_key: string
|
|
59
|
+
marker: PhaseMarker
|
|
60
|
+
is_bundleable: boolean
|
|
61
|
+
targets: ReadonlyArray<string>
|
|
62
|
+
// Carried beside `targets` because sharing a target means something different depending on it: a
|
|
63
|
+
// second write to one file is independent work, a read of a file just written is not
|
|
64
|
+
// (joshuafolkken/kit#1509).
|
|
65
|
+
is_writing: boolean
|
|
66
|
+
// The conservative write answer `is_read_only_call` asks of a live call, carried so a reader of the
|
|
67
|
+
// transcript asks the same read-only question as the guard (joshuafolkken/kit#3139).
|
|
68
|
+
may_write: boolean
|
|
69
|
+
// Whether this is a subagent launch whose prompt builds on an earlier launch's finding
|
|
70
|
+
// (joshuafolkken/kit#1854). Carried for the reason every field here is — the prompt it is read from
|
|
71
|
+
// is the input, and a span keeps none. `time-agent-bundles.ts` reads it.
|
|
72
|
+
has_prior_reference: boolean
|
|
73
|
+
writes: ReadonlyArray<string>
|
|
74
|
+
message_id: string
|
|
75
|
+
issue: number
|
|
76
|
+
// The background run this call reads the output of, and `''` for every other call
|
|
77
|
+
// (joshuafolkken/kit#1662). It is the eighth field carried for the reason the seven above are:
|
|
78
|
+
// the id sits in the command string, which a span does not keep, and it is the only thing that
|
|
79
|
+
// says a `tail` two turns later is the join of a command started minutes ago.
|
|
80
|
+
reads_background: string
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const NO_CALL: ToolCall = {
|
|
84
|
+
label: '',
|
|
85
|
+
josh_command: '',
|
|
86
|
+
josh_commands: [],
|
|
87
|
+
check_key: time_single_check.NO_CHECK,
|
|
88
|
+
marker: time_markers.NO_MARKER,
|
|
89
|
+
message_id: NO_MESSAGE_ID,
|
|
90
|
+
writes: [],
|
|
91
|
+
issue: time_markers.NO_ISSUE,
|
|
92
|
+
reads_background: time_background.NO_BACKGROUND,
|
|
93
|
+
...time_bundle_call.not_bundleable(),
|
|
94
|
+
}
|
|
95
|
+
const UNKNOWN_CALL: ToolCall = {
|
|
96
|
+
label: UNKNOWN_TOOL,
|
|
97
|
+
josh_command: '',
|
|
98
|
+
josh_commands: [],
|
|
99
|
+
check_key: time_single_check.NO_CHECK,
|
|
100
|
+
marker: time_markers.NO_MARKER,
|
|
101
|
+
message_id: NO_MESSAGE_ID,
|
|
102
|
+
writes: [],
|
|
103
|
+
issue: time_markers.NO_ISSUE,
|
|
104
|
+
reads_background: time_background.NO_BACKGROUND,
|
|
105
|
+
...time_bundle_call.not_bundleable(),
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Everything but Bash: the tool's own name is the label, and nothing it runs is a shell command to
|
|
109
|
+
// read a check key, a josh command or a declared issue off.
|
|
110
|
+
function non_bash_call(name: string, input: unknown, message_id: string): ToolCall {
|
|
111
|
+
return {
|
|
112
|
+
label: name,
|
|
113
|
+
josh_command: '',
|
|
114
|
+
josh_commands: [],
|
|
115
|
+
check_key: time_single_check.NO_CHECK,
|
|
116
|
+
marker: time_markers.tool_marker(name, input),
|
|
117
|
+
message_id,
|
|
118
|
+
writes: time_writes.tool_writes(name, input),
|
|
119
|
+
issue: time_markers.NO_ISSUE,
|
|
120
|
+
// A non-Bash tool joins a backgrounded command too — `BashOutput` carries the shell id in a
|
|
121
|
+
// field of its own, `Monitor` names the same `…/tasks/<id>.output` path in a command — so the
|
|
122
|
+
// same reader is asked here rather than the field being left empty for every tool but `Bash`.
|
|
123
|
+
reads_background: time_background.read_id_of(input),
|
|
124
|
+
...time_bundle_call.tool_facts(name, input),
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function bash_call(input: unknown, message_id: string): ToolCall {
|
|
129
|
+
const command = time_shell.bash_command(input)
|
|
130
|
+
const josh_command = time_shell.josh_command_of(command)
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
label: time_shell.bash_label(command),
|
|
134
|
+
josh_command,
|
|
135
|
+
josh_commands: time_shell.josh_commands_of(command),
|
|
136
|
+
check_key: time_single_check.check_key(josh_command, command),
|
|
137
|
+
marker: time_markers.bash_marker(command),
|
|
138
|
+
message_id,
|
|
139
|
+
writes: time_writes.bash_writes(command),
|
|
140
|
+
issue: time_markers.bash_issue(command),
|
|
141
|
+
reads_background: time_background.read_id_of(input),
|
|
142
|
+
...time_bundle_call.bash_facts(command),
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function to_tool_call(name: string, input: unknown, message_id: string): ToolCall {
|
|
147
|
+
if (name !== cost_blocks.BASH_TOOL) return non_bash_call(name, input, message_id)
|
|
148
|
+
|
|
149
|
+
return bash_call(input, message_id)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const time_tool_call = {
|
|
153
|
+
UNKNOWN_TOOL,
|
|
154
|
+
NO_CALL,
|
|
155
|
+
UNKNOWN_CALL,
|
|
156
|
+
to_tool_call,
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export type { ToolCall }
|
|
160
|
+
export { time_tool_call }
|
|
@@ -1,13 +1,11 @@
|
|
|
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 { json_value } from '#scripts/lib/json-value'
|
|
5
6
|
import { package_named_version_schema } from '#scripts/lib/schemas'
|
|
6
7
|
|
|
7
8
|
const PACKAGE_JSON = 'package.json'
|
|
8
|
-
// Node module paths never nest anywhere near this deep; the bound only guards against an unexpected
|
|
9
|
-
// filesystem cycle so the walk-up cannot loop forever.
|
|
10
|
-
const MAX_WALK_DEPTH = 64
|
|
11
9
|
|
|
12
10
|
// Options for `resolve_effective_upstream_version`. `resolve_marker` is a subpath specifier used for
|
|
13
11
|
// `createRequire().resolve()` when the package root itself is not directly resolvable — e.g. kit does
|
|
@@ -31,26 +29,10 @@ function read_matching_version(manifest_path: string, package_name: string): str
|
|
|
31
29
|
return parsed.data.version
|
|
32
30
|
}
|
|
33
31
|
|
|
34
|
-
// The directory itself and each of its ancestors up to the filesystem root, nearest-first. Bounded
|
|
35
|
-
// by MAX_WALK_DEPTH so an unexpected filesystem cycle cannot produce an unbounded list.
|
|
36
|
-
function ancestor_directories(start_directory: string): Array<string> {
|
|
37
|
-
const directories: Array<string> = []
|
|
38
|
-
let current = start_directory
|
|
39
|
-
|
|
40
|
-
for (let depth = 0; depth < MAX_WALK_DEPTH; depth += 1) {
|
|
41
|
-
directories.push(current)
|
|
42
|
-
const parent = path.dirname(current)
|
|
43
|
-
if (parent === current) break
|
|
44
|
-
current = parent
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return directories
|
|
48
|
-
}
|
|
49
|
-
|
|
50
32
|
// Walk up from a resolved file's directory to the package root, returning the version of the first
|
|
51
33
|
// ancestor package.json whose `name` matches the target — or undefined when no matching root exists.
|
|
52
34
|
function walk_up_for_version(start_directory: string, package_name: string): string | undefined {
|
|
53
|
-
for (const directory of ancestor_directories(start_directory)) {
|
|
35
|
+
for (const directory of ancestor_directories.list(start_directory)) {
|
|
54
36
|
const version = read_matching_version(path.join(directory, PACKAGE_JSON), package_name)
|
|
55
37
|
if (version !== undefined) return version
|
|
56
38
|
}
|
|
@@ -11,12 +11,12 @@
|
|
|
11
11
|
* major equals the `packageManager` pin keeps both invariants: never below the adopted
|
|
12
12
|
* major, and advancing while that major is the current one.
|
|
13
13
|
*
|
|
14
|
-
* The `
|
|
15
|
-
* safe-chain filters the registry only when the process tree was launched through one
|
|
16
|
-
* its wrapped shell commands, so `josh latest` and `pnpm josh latest` used to resolve
|
|
14
|
+
* The `minimumReleaseAge` quarantine is applied natively from `pnpm-workspace.yaml` (kit#768,
|
|
15
|
+
* #3267). safe-chain filters the registry only when the process tree was launched through one
|
|
16
|
+
* of its wrapped shell commands, so `josh latest` and `pnpm josh latest` used to resolve
|
|
17
17
|
* different answers and the pin oscillated. Reading the window from the repo-managed
|
|
18
|
-
*
|
|
19
|
-
* invocation context; right after a pnpm release the answer is simply the previous
|
|
18
|
+
* `pnpm-workspace.yaml` and filtering by publish timestamp makes the resolution identical in
|
|
19
|
+
* every invocation context; right after a pnpm release the answer is simply the previous
|
|
20
20
|
* release, exactly as the filtered view behaved.
|
|
21
21
|
*
|
|
22
22
|
* The resolved version is floored at the current `packageManager` pin: a filtered registry
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
import { readFileSync, writeFileSync } from 'node:fs'
|
|
39
39
|
import { fileURLToPath } from 'node:url'
|
|
40
40
|
import { json_value } from '#scripts/lib/json-value'
|
|
41
|
+
import { COMMAND_TIMEOUT_MS } from '#scripts/lib/timeouts'
|
|
41
42
|
import { execaSync } from 'execa'
|
|
42
43
|
import semver from 'semver'
|
|
43
44
|
import { z } from 'zod'
|
|
@@ -49,8 +50,7 @@ const PACKAGE_MANAGER_RE = /"packageManager"\s*:\s*"pnpm@(\d+)(?:[^\d]|$)/u
|
|
|
49
50
|
const PINNED_VERSION_RE = /"packageManager"\s*:\s*"pnpm@([^"+]+)/u
|
|
50
51
|
const TARGET_PREFIX = 'pnpm@'
|
|
51
52
|
const FAILURE_EXIT_CODE = 1
|
|
52
|
-
const
|
|
53
|
-
const VIEW_TIMEOUT_MS = 30_000
|
|
53
|
+
const WORKSPACE_PATH = 'pnpm-workspace.yaml'
|
|
54
54
|
const SHA512_BYTES = 64
|
|
55
55
|
const INTEGRITY_RE = /^sha512-([A-Za-z0-9+/]+={0,2})$/u
|
|
56
56
|
const PACKAGE_MANAGER_VALUE_RE = /("packageManager"\s*:\s*")pnpm@[^"]+(")/u
|
|
@@ -121,7 +121,7 @@ function extract_times_json(stdout: string): Record<string, string> | undefined
|
|
|
121
121
|
function query_release_times(): Record<string, string> | undefined {
|
|
122
122
|
const result = execaSync('pnpm', ['view', 'pnpm', 'time', '--json'], {
|
|
123
123
|
reject: false,
|
|
124
|
-
timeout:
|
|
124
|
+
timeout: COMMAND_TIMEOUT_MS,
|
|
125
125
|
})
|
|
126
126
|
if ((result.exitCode ?? FAILURE_EXIT_CODE) !== 0) return undefined
|
|
127
127
|
|
|
@@ -134,14 +134,14 @@ function query_major_latest_version(major: string): string | undefined {
|
|
|
134
134
|
const times = query_release_times()
|
|
135
135
|
if (times === undefined) return undefined
|
|
136
136
|
|
|
137
|
-
// The project's own
|
|
138
|
-
// latest` reads `package.json` and writes the pnpm pin relative to the working
|
|
139
|
-
// has no subdirectory case — and honouring
|
|
140
|
-
// project that declares none (joshuafolkken/kit#808).
|
|
137
|
+
// The project's own `pnpm-workspace.yaml`, deliberately not the upward walk the version check
|
|
138
|
+
// uses: `josh latest` reads `package.json` and writes the pnpm pin relative to the working
|
|
139
|
+
// directory, so it has no subdirectory case — and honouring an ancestor's policy here could freeze
|
|
140
|
+
// pnpm bumps in a project that declares none (joshuafolkken/kit#808).
|
|
141
141
|
return release_age.select_aged_version(
|
|
142
142
|
times,
|
|
143
143
|
major,
|
|
144
|
-
release_age.read_minimum_release_age(
|
|
144
|
+
release_age.read_minimum_release_age(WORKSPACE_PATH),
|
|
145
145
|
Date.now(),
|
|
146
146
|
)
|
|
147
147
|
}
|
|
@@ -156,7 +156,7 @@ function parse_latest_version(stdout: string): string | undefined {
|
|
|
156
156
|
function query_latest_version(): string | undefined {
|
|
157
157
|
const result = execaSync('pnpm', ['view', 'pnpm', 'version', '--json'], {
|
|
158
158
|
reject: false,
|
|
159
|
-
timeout:
|
|
159
|
+
timeout: COMMAND_TIMEOUT_MS,
|
|
160
160
|
})
|
|
161
161
|
if ((result.exitCode ?? FAILURE_EXIT_CODE) !== 0) return undefined
|
|
162
162
|
|
|
@@ -179,8 +179,8 @@ function warn_skip(reason: string): void {
|
|
|
179
179
|
console.warn(`⚠ Skipped pnpm bump (${reason}); the chain continues.`)
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
-
function warn_unresolved(major: string | undefined): void {
|
|
183
|
-
warn_skip(`no pnpm ${major
|
|
182
|
+
function warn_unresolved(major: string | undefined = ''): void {
|
|
183
|
+
warn_skip(`no pnpm ${major} release resolvable from the registry`)
|
|
184
184
|
}
|
|
185
185
|
|
|
186
186
|
function run_pnpm_update(target: string): number {
|
|
@@ -247,7 +247,7 @@ function extract_encoded_integrity(stdout: string): string | undefined {
|
|
|
247
247
|
function query_integrity(target: string): string | undefined {
|
|
248
248
|
const result = execaSync('pnpm', ['view', target, 'dist.integrity', '--json'], {
|
|
249
249
|
reject: false,
|
|
250
|
-
timeout:
|
|
250
|
+
timeout: COMMAND_TIMEOUT_MS,
|
|
251
251
|
})
|
|
252
252
|
if ((result.exitCode ?? FAILURE_EXIT_CODE) !== 0) return undefined
|
|
253
253
|
|