@joshuafolkken/kit 1.1240.0 → 1.1370.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/agents/investigator.md +1 -0
- package/.claude/settings.json +4 -0
- package/.claude/skills/dependency-update/SKILL.md +5 -3
- package/.claude/skills/epic-commands/SKILL.md +82 -113
- package/.claude/skills/epic-commands/epic-bundle.md +38 -63
- package/.claude/skills/epic-commands/execution-waves.md +30 -51
- package/.claude/skills/verify-ui/SKILL.md +13 -20
- package/.claude/skills/workflow-commands/SKILL.md +10 -10
- package/.claude/skills/workflow-commands/background-commands.md +4 -4
- package/.claude/skills/workflow-commands/backlogrun-child.md +30 -105
- package/.claude/skills/workflow-commands/backlogrun-handoff-report.md +29 -0
- package/.claude/skills/workflow-commands/backlogrun-lanes.md +45 -131
- package/.claude/skills/workflow-commands/backlogrun-park.md +36 -53
- package/.claude/skills/workflow-commands/backlogrun-progress.md +81 -331
- package/.claude/skills/workflow-commands/backlogrun-recovery.md +29 -83
- package/.claude/skills/workflow-commands/backlogrun-steps.md +105 -424
- package/.claude/skills/workflow-commands/backlogrun.md +50 -61
- package/.claude/skills/workflow-commands/chain-rule.md +36 -40
- package/.claude/skills/workflow-commands/entry-sequence.md +6 -6
- package/.claude/skills/workflow-commands/followup.md +19 -20
- package/.claude/skills/workflow-commands/fullrun-steps.md +23 -27
- package/.claude/skills/workflow-commands/fullrun.md +10 -10
- package/.claude/skills/workflow-commands/halfrun.md +9 -8
- package/.claude/skills/workflow-commands/into-target.md +12 -18
- package/.claude/skills/workflow-commands/issue-comments.md +11 -26
- package/.claude/skills/workflow-commands/kickoff.md +26 -16
- package/.claude/skills/workflow-commands/latest-gate.md +17 -28
- package/.claude/skills/workflow-commands/needs-human-review.md +13 -24
- package/.claude/skills/workflow-commands/observation-filing.md +37 -28
- package/.claude/skills/workflow-commands/observation-ledger.md +48 -38
- package/.claude/skills/workflow-commands/pre-gate-cut.md +9 -9
- package/.claude/skills/workflow-commands/prerequisite.md +23 -15
- package/.claude/skills/workflow-commands/progress-watcher.md +17 -11
- package/.claude/skills/workflow-commands/prrun.md +3 -3
- package/.claude/skills/workflow-commands/retrospective.md +13 -18
- package/.claude/skills/workflow-commands/split-assessment.md +6 -4
- package/.claude/skills/workflow-commands/target-repository.md +25 -28
- package/.claude/skills/workflow-commands/working-tree-hold.md +11 -17
- package/.gitattributes +2 -1
- package/.github/workflows/ci.yml +14 -0
- package/.vscode/tasks.json +14 -0
- package/CLAUDE.md +10 -61
- package/README.md +29 -47
- package/SECURITY.md +1 -1
- package/dist/CLAUDE.md +10 -61
- package/dist/commands/document-section-cli.js +42 -10
- package/dist/config-merge/index.js +11 -2
- package/dist/hooks/audit-provision.js +2 -2
- package/dist/hooks/batch-guard.js +7 -7
- package/dist/hooks/{chunk-KHGB5S3Y.js → chunk-43G45XJF.js} +18 -20
- package/dist/hooks/{chunk-4TZVB44A.js → chunk-4TW4MQUL.js} +284 -362
- package/dist/hooks/{chunk-XZYKEM6J.js → chunk-76RK6E3H.js} +13 -11
- package/dist/hooks/{chunk-F3ELQ2AF.js → chunk-DZWZ3DKY.js} +4 -4
- package/dist/hooks/{chunk-5VNDSNG3.js → chunk-FZ6FUSBM.js} +1 -1
- package/dist/hooks/{chunk-GPTFMK5E.js → chunk-GG72ANKI.js} +1 -1
- package/dist/hooks/{chunk-ZQGD4GBY.js → chunk-KPM4YIIX.js} +8 -44
- package/dist/hooks/chunk-MXVQMLDP.js +3705 -0
- package/dist/hooks/{chunk-ELCN5LCH.js → chunk-NEC4AT4Z.js} +34 -12
- package/dist/hooks/{chunk-QVSWU24O.js → chunk-NZBHG6FW.js} +7 -5
- package/dist/hooks/chunk-NZN2UFI6.js +2409 -0
- package/dist/hooks/{chunk-KRBERBBI.js → chunk-R6CRQEAL.js} +4 -4
- package/dist/hooks/chunk-SYSRHRWU.js +1589 -0
- package/dist/hooks/{chunk-WK2XSHSI.js → chunk-TLJYAGZK.js} +549 -874
- package/dist/hooks/chunk-Z5TMJIPW.js +45 -0
- package/dist/hooks/codex-hook-adapter.js +26 -21
- package/dist/hooks/duplicate-read-guard.js +8 -8
- package/dist/hooks/format-edited.js +4 -4
- package/dist/hooks/inputs.json +216 -202
- package/dist/hooks/investigation-guard.js +8 -8
- package/dist/hooks/pretool-guard.js +15 -15
- package/dist/hooks/session-lang.js +406 -8
- package/dist/hooks/stop-guard.js +122 -187
- package/dist/josh.js +281 -94
- package/dist/version/index.js +15 -13
- package/eslint/base.js +43 -5
- package/eslint/rules/english-only-prose.js +3 -3
- package/eslint/rules/import.js +12 -0
- package/eslint/rules/namespace-object-export.js +2 -2
- package/package.json +16 -10
- package/pnpm-workspace.yaml +2 -4
- package/prompts/coding-standards.md +14 -48
- package/prompts/collaboration-workflow/file-edits.md +1 -1
- package/prompts/collaboration-workflow/issue-citation.md +1 -1
- package/prompts/collaboration-workflow/issue-template.md +3 -10
- package/prompts/collaboration-workflow/operating-rules.md +7 -8
- package/prompts/collaboration-workflow/output-bounds.md +1 -1
- package/prompts/collaboration-workflow/overview.md +1 -1
- package/prompts/collaboration-workflow/plan-comment.md +2 -1
- package/prompts/collaboration-workflow/principles.md +21 -3
- package/prompts/collaboration-workflow/report-format.md +16 -29
- package/prompts/collaboration-workflow/residency.md +1 -1
- package/prompts/collaboration-workflow/rule-delivery.md +7 -95
- package/prompts/collaboration-workflow/shell-body.md +3 -23
- package/prompts/collaboration-workflow/turn-batching.md +4 -13
- package/prompts/collaboration-workflow/wip-cap.md +5 -11
- package/prompts/refactoring.md +1 -1
- package/prompts/review-rubric.md +3 -22
- package/prompts/review.md +15 -38
- package/prompts/testing-guide.md +2 -4
- package/scripts/adopt/adopt-logic.ts +5 -5
- package/scripts/adopt/adopt-toolkits.ts +4 -5
- package/scripts/adopt/adopt.ts +2 -3
- package/scripts/agent/agent-argv.ts +7 -7
- package/scripts/agent/agent-diagnostics.ts +2 -2
- package/scripts/agent/agent-exit-record.ts +1 -1
- package/scripts/agent/agent-headless.ts +1 -1
- package/scripts/agent/agent-launch-environment.ts +6 -1
- package/scripts/agent/agent-role-profile.ts +49 -22
- package/scripts/agent/agent-session-role.ts +32 -0
- package/scripts/agent/api-outage.ts +1 -1
- package/scripts/agent/claude-agent-argv.ts +4 -4
- package/scripts/agent/claude-result-event.ts +4 -4
- package/scripts/agent/codex-hooks.ts +2 -2
- package/scripts/agent/interactive-ask.ts +3 -6
- package/scripts/auto-ok/auto-ok-cli.ts +46 -60
- package/scripts/backlog/backlog-arrival-added.ts +34 -0
- package/scripts/backlog/backlog-arrival.ts +54 -17
- package/scripts/backlog/backlog-budget-cli.ts +34 -6
- package/scripts/backlog/backlog-budget.ts +17 -24
- package/scripts/backlog/backlog-defect-priority.ts +1 -1
- package/scripts/backlog/backlog-drive-args.ts +5 -4
- package/scripts/backlog/backlog-drive-cli.ts +14 -10
- package/scripts/backlog/backlog-drive-epic.ts +85 -0
- package/scripts/backlog/backlog-drive-launch.ts +1 -1
- package/scripts/backlog/backlog-drive-named-offer.ts +60 -9
- package/scripts/backlog/backlog-drive-named.ts +39 -9
- package/scripts/backlog/backlog-drive-offer-argv.ts +1 -1
- package/scripts/backlog/backlog-drive-restore.ts +1 -1
- package/scripts/backlog/backlog-drive-retrospective.ts +2 -2
- package/scripts/backlog/backlog-drive.ts +43 -28
- package/scripts/backlog/backlog-idle.ts +88 -0
- package/scripts/backlog/backlog-named.ts +11 -15
- package/scripts/backlog/backlog-next.ts +26 -30
- package/scripts/backlog/backlog-offer-cli.ts +28 -23
- package/scripts/backlog/backlog-offer.ts +7 -7
- package/scripts/backlog/backlog-overlap.ts +178 -0
- package/scripts/backlog/backlog-plan-cli.ts +14 -90
- package/scripts/backlog/backlog-plan-read.ts +111 -0
- package/scripts/backlog/backlog-plan.ts +11 -10
- package/scripts/backlog/backlog-pool.ts +13 -14
- package/scripts/backlog/backlog-rank.ts +11 -11
- package/scripts/backlog/backlog-ready.ts +15 -10
- package/scripts/backlog/backlog-scope.ts +14 -15
- package/scripts/backlog/backlog-stalled-cli.ts +2 -2
- package/scripts/backlog/backlog-stalled-detect.ts +4 -4
- package/scripts/backlog/backlog-stalled.ts +5 -6
- package/scripts/backlog/backlog-waves.ts +4 -4
- package/scripts/backlog/backlogrun-args.ts +74 -0
- package/scripts/backlog/backlogrun-cli.ts +113 -0
- package/scripts/backlog/backlogrun-launch.ts +178 -0
- package/scripts/behavior/behavior-assertion.ts +6 -8
- package/scripts/behavior/behavior-cli.ts +1 -1
- package/scripts/behavior/behavior-rules.ts +3 -3
- package/scripts/build/build-claude-md.ts +4 -4
- package/scripts/build/build-codex-hooks.ts +2 -2
- package/scripts/build/build-commands.ts +1 -1
- package/scripts/build/build-hooks.ts +5 -5
- package/scripts/build/build.ts +1 -1
- package/scripts/build/hook-bundle-stamp.ts +109 -7
- package/scripts/build/local-bin.ts +2 -2
- package/scripts/cases/cases-cli.ts +1 -1
- package/scripts/cases/cases-logic.ts +2 -2
- package/scripts/ci/composite-actions.ts +1 -2
- package/scripts/ci/pr-classification.ts +2 -2
- package/scripts/claude/workflow-destination.ts +1 -1
- package/scripts/clone/clone-aggregate.ts +1 -1
- package/scripts/clone/clone-fingerprint.ts +1 -1
- package/scripts/clone/clone-scan-cli.ts +1 -1
- package/scripts/clone/clone-scan.ts +1 -1
- package/scripts/config-merge/index.ts +1 -1
- package/scripts/config-merge/json-format.ts +1 -3
- package/scripts/config-merge/patch-json-array.ts +90 -0
- package/scripts/config-merge/patch-json-key.ts +6 -3
- package/scripts/config-merge/patch-json-list.ts +1 -1
- package/scripts/cost-runtime/codex-usage.ts +1 -1
- package/scripts/cost-runtime/context-cut-payback.ts +4 -5
- package/scripts/cost-runtime/context-cut-threshold.ts +4 -6
- package/scripts/cost-runtime/cost-attribute.ts +3 -3
- package/scripts/cost-runtime/cost-blocks.ts +3 -4
- package/scripts/cost-runtime/cost-cli.ts +14 -11
- package/scripts/cost-runtime/cost-corpus.ts +11 -11
- package/scripts/cost-runtime/cost-pricing.ts +4 -4
- package/scripts/cost-runtime/cost-tokens.ts +1 -2
- package/scripts/cost-runtime/cost-transcript.ts +29 -29
- package/scripts/cost-runtime/cost-usage.ts +6 -7
- package/scripts/cost-runtime/cost-verdict.ts +10 -11
- package/scripts/cost-runtime/own-session.ts +1 -1
- package/scripts/cost-runtime/transcript-cwd.ts +2 -2
- package/scripts/delegation/delegation-cli.ts +4 -4
- package/scripts/delegation/delegation-policy.ts +13 -15
- package/scripts/delegation/duplicate-read-guard.ts +9 -10
- package/scripts/delegation/fanout-cli.ts +1 -1
- package/scripts/delegation/fanout.ts +1 -1
- package/scripts/delegation/investigation-guard.ts +18 -22
- package/scripts/delegation/investigation-reads.ts +48 -238
- package/scripts/discovery/repo-discovery.ts +1 -1
- package/scripts/discovery/repo-map-logic.ts +1 -2
- package/scripts/discovery/repo-origin.ts +3 -3
- package/scripts/discovery/repo-party-cli.ts +2 -2
- package/scripts/discovery/repo-party.ts +2 -2
- package/scripts/doctor/doctor-consumer.ts +1 -1
- package/scripts/doctor/doctor-io.ts +6 -7
- package/scripts/doctor/doctor-logic.ts +1 -1
- package/scripts/doctor/doctor-ports.ts +1 -1
- package/scripts/doctor/doctor.ts +8 -9
- package/scripts/document/backlogrun-parent-read-set.ts +5 -6
- package/scripts/document/bash-output-cap.ts +5 -7
- package/scripts/document/capped-print-part.ts +1 -1
- package/scripts/document/capped-print.ts +1 -1
- package/scripts/document/document-byte-budget.ts +33 -64
- package/scripts/document/document-byte-check.ts +4 -4
- package/scripts/document/document-reachability.ts +7 -8
- package/scripts/document/document-read-cli.ts +2 -2
- package/scripts/document/document-scan.ts +26 -2
- package/scripts/document/document-section-cli.ts +6 -8
- package/scripts/document/document-section.ts +8 -12
- package/scripts/document/edit-files-cli.ts +3 -4
- package/scripts/document/entry-read-budget.ts +8 -70
- package/scripts/document/entry-read-set.ts +51 -34
- package/scripts/document/lane-child-read-set.ts +9 -9
- package/scripts/document/read-files-cli.ts +1 -2
- package/scripts/document/read-set-cli.ts +16 -19
- package/scripts/document/read-set-cost.ts +4 -4
- package/scripts/document/read-set-point-of-use.ts +28 -38
- package/scripts/document/read-set-pricing.ts +1 -1
- package/scripts/document/read-set-trim.ts +3 -3
- package/scripts/document/resident-budget.ts +8 -10
- package/scripts/epic/epic-add-body.ts +15 -18
- package/scripts/epic/epic-add-plan.ts +26 -28
- package/scripts/epic/epic-add.ts +32 -25
- package/scripts/epic/epic-audit-checks.ts +27 -37
- package/scripts/epic/epic-audit-cli.ts +21 -22
- package/scripts/epic/epic-audit-orphans.ts +16 -17
- package/scripts/epic/epic-audit-rationale.ts +10 -15
- package/scripts/epic/epic-audit-report.ts +2 -5
- package/scripts/epic/epic-audit.ts +18 -14
- package/scripts/epic/epic-body.ts +10 -10
- package/scripts/epic/epic-bundle-cli.ts +36 -34
- package/scripts/epic/epic-bundle-evidence.ts +5 -5
- package/scripts/epic/epic-bundle-gaps.ts +6 -9
- package/scripts/epic/epic-bundle-poll.ts +1 -1
- package/scripts/epic/epic-bundle-referenced.ts +11 -14
- package/scripts/epic/epic-bundle.ts +19 -20
- package/scripts/epic/epic-busy.ts +44 -21
- package/scripts/epic/epic-candidate-confirm.ts +15 -18
- package/scripts/epic/epic-chains.ts +18 -23
- package/scripts/epic/epic-classify.ts +11 -12
- package/scripts/epic/epic-cli-argv.ts +5 -6
- package/scripts/epic/epic-cli-remove.ts +9 -4
- package/scripts/epic/epic-cli.ts +38 -26
- package/scripts/epic/epic-close-comment.ts +14 -15
- package/scripts/epic/epic-close.ts +25 -29
- package/scripts/epic/epic-cross-repo.ts +18 -21
- package/scripts/epic/epic-decision.ts +14 -18
- package/scripts/epic/epic-fetch.ts +25 -31
- package/scripts/epic/epic-graph.ts +15 -17
- package/scripts/epic/epic-index.ts +14 -16
- package/scripts/epic/epic-issue.ts +9 -11
- package/scripts/epic/epic-label-age.ts +74 -0
- package/scripts/epic/epic-lane-offer.ts +35 -24
- package/scripts/epic/epic-nested.ts +1 -1
- package/scripts/epic/epic-next-read.ts +8 -8
- package/scripts/epic/epic-next-views.ts +12 -12
- package/scripts/epic/epic-next.ts +29 -33
- package/scripts/epic/epic-outside-blocker.ts +11 -10
- package/scripts/epic/epic-parse.ts +22 -24
- package/scripts/epic/epic-promote.ts +3 -2
- package/scripts/epic/epic-rank.ts +1 -1
- package/scripts/epic/epic-read.ts +10 -8
- package/scripts/epic/epic-reconcile.ts +8 -6
- package/scripts/epic/epic-reference.ts +5 -4
- package/scripts/epic/epic-relation-recheck.ts +10 -11
- package/scripts/epic/epic-relations.ts +9 -8
- package/scripts/epic/epic-remove-plan.ts +4 -5
- package/scripts/epic/epic-remove.ts +7 -5
- package/scripts/epic/epic-report.ts +18 -20
- package/scripts/epic/epic-run.ts +6 -5
- package/scripts/epic/epic-sections.ts +2 -2
- package/scripts/epic/epic-shape.ts +3 -3
- package/scripts/epic/epic-solo-stale.ts +3 -2
- package/scripts/epic/epic-solo.ts +8 -8
- package/scripts/epic/epic-triage.ts +5 -4
- package/scripts/epic/epic-validate.ts +8 -7
- package/scripts/epic/epic.ts +5 -5
- package/scripts/exports/unused-members-cli.ts +1 -1
- package/scripts/followup/followup-issue-number.ts +1 -2
- package/scripts/followup/git-followup-cleanup.ts +6 -7
- package/scripts/followup/git-followup-finish.ts +11 -13
- package/scripts/followup/git-followup-flush.ts +11 -7
- package/scripts/followup/git-followup-issue-close.ts +16 -13
- package/scripts/followup/git-followup-label.ts +9 -6
- package/scripts/followup/git-followup-merged.ts +1 -1
- package/scripts/followup/git-followup-pending.ts +7 -9
- package/scripts/followup/git-followup-stages.ts +28 -17
- package/scripts/followup/git-followup-workflow.ts +19 -21
- package/scripts/followup/git-pr-followup-checks.ts +13 -20
- package/scripts/followup/git-pr-followup-wrapup.ts +7 -7
- package/scripts/followup/git-pr-followup.ts +18 -17
- package/scripts/gate/core-admission.ts +2 -2
- package/scripts/gate/core-budget.ts +15 -26
- package/scripts/gate/gate-ledger.ts +114 -0
- package/scripts/gate/gate-log.ts +7 -9
- package/scripts/gate/gate-plan.ts +70 -35
- package/scripts/gate/gate-report.ts +14 -15
- package/scripts/gate/gate-skip.ts +11 -13
- package/scripts/gate/gate-steps.ts +5 -1
- package/scripts/gate/gate-tree.ts +3 -4
- package/scripts/gate/hook-gate-reuse.ts +9 -9
- package/scripts/gate/machine-capacity.ts +168 -30
- package/scripts/gate/pre-commit-type-check.ts +4 -4
- package/scripts/gate/project-checks.ts +12 -4
- package/scripts/gate/scoped-green.ts +11 -18
- package/scripts/gate/type-check-command.ts +2 -2
- package/scripts/gate/type-check-step.ts +4 -4
- package/scripts/gate/verification-gate.ts +53 -51
- package/scripts/gh/gh-spawn.ts +2 -2
- package/scripts/gh/git-ai-review-scan.ts +3 -2
- package/scripts/gh/git-gh-api-path.ts +10 -11
- package/scripts/gh/git-gh-exec.ts +43 -48
- package/scripts/gh/git-gh-failure.ts +6 -9
- package/scripts/gh/git-gh-helpers.ts +1 -1
- package/scripts/gh/git-gh-issue-list.ts +15 -19
- package/scripts/gh/git-gh-issue-read.ts +43 -60
- package/scripts/gh/git-gh-issue-rest.ts +14 -15
- package/scripts/gh/git-gh-issue-write.ts +52 -40
- package/scripts/gh/git-gh-issue.ts +23 -24
- package/scripts/gh/git-gh-pr-auto-merge.ts +3 -3
- package/scripts/gh/git-gh-pr-read.ts +46 -50
- package/scripts/gh/git-gh-pr-rest.ts +23 -26
- package/scripts/gh/git-gh-pr-review.ts +2 -2
- package/scripts/gh/git-gh-pr-rollup.ts +4 -4
- package/scripts/gh/git-gh-pr-snapshot.ts +8 -10
- package/scripts/gh/git-gh-pr.ts +16 -16
- package/scripts/gh/git-gh-reachability.ts +11 -12
- package/scripts/gh/git-gh-repo.ts +2 -3
- package/scripts/gh/git-gh-rest-state.ts +1 -1
- package/scripts/gh/git-pr-ai-review.ts +6 -5
- package/scripts/gh/git-pr-checks-eval.ts +28 -30
- package/scripts/gh/git-pr-checks-parse.ts +14 -16
- package/scripts/gh/git-pr-checks-watch.ts +17 -17
- package/scripts/gh/git-pr-checks.ts +20 -23
- package/scripts/gh/git-pr-coderabbit.ts +8 -6
- package/scripts/gh/git-pr-confirmation.ts +5 -5
- package/scripts/gh/git-pr-managed-config.ts +7 -9
- package/scripts/gh/git-pr-messages.ts +1 -1
- package/scripts/gh/git-pr.ts +15 -16
- package/scripts/gh/github-issue-url.ts +8 -9
- package/scripts/git/base-tree.ts +66 -0
- package/scripts/git/change-base.ts +42 -2
- package/scripts/git/changed-file-scope.ts +5 -5
- package/scripts/git/changed-paths.ts +1 -2
- package/scripts/git/constants.ts +2 -2
- package/scripts/git/git-branch.ts +1 -1
- package/scripts/git/git-closes-keyword.ts +3 -3
- package/scripts/git/git-command.ts +53 -41
- package/scripts/git/git-common-directory.ts +3 -3
- package/scripts/git/git-diff-reads.ts +14 -15
- package/scripts/git/git-error.ts +1 -1
- package/scripts/git/git-execa-error.ts +1 -2
- package/scripts/git/git-issue.ts +10 -8
- package/scripts/git/git-location-environment.ts +3 -4
- package/scripts/git/git-ls-remote.ts +6 -8
- package/scripts/git/git-pre-push-hook.ts +11 -10
- package/scripts/git/git-preflight.ts +5 -5
- package/scripts/git/git-push-transport.ts +2 -2
- package/scripts/git/git-remote-branch.ts +1 -2
- package/scripts/git/git-schemas.ts +16 -23
- package/scripts/git/git-spawn-sync.ts +1 -1
- package/scripts/git/git-spawn.ts +37 -14
- package/scripts/git/git-ssh-keepalive.ts +12 -5
- package/scripts/git/git-staging.ts +7 -8
- package/scripts/git/git-workflow.ts +1 -1
- package/scripts/git/git-worktree.ts +35 -27
- package/scripts/git/gone-branch.ts +2 -2
- package/scripts/git/listing-cutoff.ts +1 -2
- package/scripts/git/lockfile-sync.ts +65 -0
- package/scripts/git/main-merge-guard.ts +1 -2
- package/scripts/git/main-merge.ts +7 -7
- package/scripts/git/main-sync.ts +23 -8
- package/scripts/git/parse-json-array.ts +18 -23
- package/scripts/git/repository-lock.ts +34 -2
- package/scripts/git/stash/git-stash.ts +4 -5
- package/scripts/git/stash/stash-orphans.ts +5 -3
- package/scripts/git/stash/stash-pop-args.ts +1 -1
- package/scripts/git/stash/stash-pop-cli.ts +3 -3
- package/scripts/git/stash/stash-sweep-lock.ts +2 -2
- package/scripts/hooks/batch-guard.ts +11 -13
- package/scripts/hooks/check-commit-message.ts +12 -9
- package/scripts/hooks/codex-hook-adapter.ts +16 -10
- package/scripts/hooks/edited-cspell.ts +3 -4
- package/scripts/hooks/format-edited-cli.ts +1 -1
- package/scripts/hooks/format-edited-file.ts +11 -17
- package/scripts/hooks/format-rewrite-notice.ts +19 -17
- package/scripts/hooks/pre-push-unit.ts +10 -14
- package/scripts/hooks/pretool-guard-cli.ts +4 -4
- package/scripts/hooks/pretool-guard.ts +93 -18
- package/scripts/hooks/reserved-run.ts +2 -2
- package/scripts/hooks/step-zero-notice.ts +1 -1
- package/scripts/hooks/stop-guard.ts +21 -10
- package/scripts/init/basic-path-migration.ts +2 -2
- package/scripts/init/claude-kit-only-settings.ts +2 -2
- package/scripts/init/claude-plugin-config.ts +2 -2
- package/scripts/init/distributed-paths.ts +4 -4
- package/scripts/init/hook-command-rewrite.ts +3 -3
- package/scripts/init/hook-launch.ts +5 -5
- package/scripts/init/init-actions.ts +13 -0
- package/scripts/init/init-ai-copy.ts +11 -11
- package/scripts/init/init-bootstrap.ts +3 -3
- package/scripts/init/init-copy-content.ts +4 -4
- package/scripts/init/init-logic-json-merge.ts +7 -9
- package/scripts/init/init-logic-migrate.ts +1 -1
- package/scripts/init/init-logic-templates.ts +1 -1
- package/scripts/init/init-logic-workspace.ts +4 -4
- package/scripts/init/init-logic-yaml-merge.ts +2 -2
- package/scripts/init/init-logic.ts +19 -22
- package/scripts/init/init.ts +7 -7
- package/scripts/init/kit-base-preset.ts +1 -1
- package/scripts/init/kit-setup-state.ts +1 -1
- package/scripts/init/kit-written-paths.ts +1 -2
- package/scripts/init/package-manager-pin.ts +1 -1
- package/scripts/init/project-profile-cli.ts +1 -1
- package/scripts/init/project-profile.ts +3 -3
- package/scripts/init/session-language-environment.ts +1 -1
- package/scripts/init/start-exec.ts +3 -4
- package/scripts/init/start-plan.ts +2 -2
- package/scripts/init/start-setup-pr.ts +3 -2
- package/scripts/init/start-steps.ts +2 -2
- package/scripts/init/tsconfig-preset-migration.ts +1 -1
- package/scripts/init/vscode-tasks.ts +62 -0
- package/scripts/issue/baseline-measure.ts +2 -2
- package/scripts/issue/behavior-change-lint.ts +2 -2
- package/scripts/issue/defect-rate-cli.ts +6 -7
- package/scripts/issue/defect-rate.ts +37 -27
- package/scripts/issue/git-next-issues.ts +9 -8
- package/scripts/issue/issue-auto-ok.ts +24 -11
- package/scripts/issue/issue-backlinks-cli.ts +5 -5
- package/scripts/issue/issue-backlinks.ts +6 -6
- package/scripts/issue/issue-cite-cli.ts +20 -18
- package/scripts/issue/issue-cite.ts +18 -8
- package/scripts/issue/issue-closing-pr.ts +4 -4
- package/scripts/issue/issue-comment-cli.ts +6 -4
- package/scripts/issue/issue-file-cli.ts +52 -15
- package/scripts/issue/issue-file-fold.ts +155 -0
- package/scripts/issue/issue-file.ts +9 -6
- package/scripts/issue/issue-fold-cli.ts +14 -9
- package/scripts/issue/issue-fold.ts +23 -8
- package/scripts/issue/issue-labels.ts +34 -38
- package/scripts/issue/issue-lint-cli.ts +2 -2
- package/scripts/issue/issue-lint.ts +1 -1
- package/scripts/issue/issue-merged.ts +10 -4
- package/scripts/issue/issue-number-shape.ts +27 -0
- package/scripts/issue/issue-rank.ts +1 -1
- package/scripts/issue/issue-read-cli.ts +4 -5
- package/scripts/issue/issue-read.ts +4 -5
- package/scripts/issue/issue-reference.ts +5 -5
- package/scripts/issue/issue-release-cli.ts +17 -7
- package/scripts/issue/issue-release.ts +3 -3
- package/scripts/issue/issue-report-failures.ts +7 -4
- package/scripts/issue/issue-scout-cli.ts +11 -11
- package/scripts/issue/issue-scout-closed.ts +4 -4
- package/scripts/issue/issue-scout.ts +4 -5
- package/scripts/issue/issue-state-cli.ts +17 -10
- package/scripts/issue/issue-state.ts +12 -13
- package/scripts/issue/issue-wip.ts +7 -7
- package/scripts/issue/markdown-section.ts +3 -3
- package/scripts/issue/measure-rerun-cli.ts +10 -9
- package/scripts/issue/reproduction-measure.ts +3 -3
- package/scripts/issue/session-cite.ts +56 -0
- package/scripts/josh/agent-session-environment.ts +10 -8
- package/scripts/josh/cli-body.ts +2 -2
- package/scripts/josh/command-suggest.ts +1 -1
- package/scripts/josh/file-map-stamp.ts +20 -23
- package/scripts/josh/hook-decision.ts +24 -28
- package/scripts/josh/josh-command-map.ts +4 -1
- package/scripts/josh/josh-command-types.ts +30 -35
- package/scripts/josh/josh-commands-ai.ts +6 -6
- package/scripts/josh/josh-commands-backlog.ts +15 -3
- package/scripts/josh/josh-commands-clone.ts +1 -1
- package/scripts/josh/josh-commands-development.ts +25 -4
- package/scripts/josh/josh-commands-document.ts +3 -3
- package/scripts/josh/josh-commands-guard.ts +3 -3
- package/scripts/josh/josh-commands-issue.ts +4 -5
- package/scripts/josh/josh-commands-lane.ts +14 -4
- package/scripts/josh/josh-commands-lint.ts +1 -1
- package/scripts/josh/josh-commands-run.ts +20 -6
- package/scripts/josh/josh-commands-split.ts +1 -2
- package/scripts/josh/josh-commands-versioning.ts +5 -5
- package/scripts/josh/josh-commands-workflow.ts +30 -22
- package/scripts/josh/josh-environment-file.ts +1 -1
- package/scripts/josh/josh-in-process.ts +3 -3
- package/scripts/josh/josh-logic.ts +6 -7
- package/scripts/josh/josh-run.ts +3 -3
- package/scripts/josh/josh-verdict.ts +9 -12
- package/scripts/josh/josh.ts +3 -3
- package/scripts/josh/kit-only.ts +2 -2
- package/scripts/josh/path-decision.ts +3 -3
- package/scripts/josh/platform-temporary.ts +7 -5
- package/scripts/josh/process-identity.ts +24 -6
- package/scripts/josh/process-owner.ts +4 -4
- package/scripts/josh/session-language-cli.ts +53 -11
- package/scripts/josh/session-language.ts +1 -1
- package/scripts/josh/stamp-file.ts +48 -29
- package/scripts/josh/stamp-record.ts +57 -0
- package/scripts/lane/lane-await.ts +35 -11
- package/scripts/lane/lane-cache.ts +6 -6
- package/scripts/lane/lane-capacity.ts +32 -17
- package/scripts/lane/lane-child-invocation.ts +17 -15
- package/scripts/lane/lane-child-marker.ts +12 -12
- package/scripts/lane/lane-cli.ts +12 -13
- package/scripts/lane/lane-close.ts +6 -6
- package/scripts/lane/lane-dispatch.ts +61 -72
- package/scripts/lane/lane-environment.ts +5 -5
- package/scripts/lane/lane-guard-policy.ts +7 -21
- package/scripts/lane/lane-handoff.ts +2 -2
- package/scripts/lane/lane-install.ts +9 -10
- package/scripts/lane/lane-launch-cli.ts +13 -8
- package/scripts/lane/lane-ledger.ts +73 -11
- package/scripts/lane/lane-leftover.ts +2 -2
- package/scripts/lane/lane-limit-cli.ts +160 -0
- package/scripts/lane/lane-limit-override.ts +74 -0
- package/scripts/lane/lane-load.ts +19 -68
- package/scripts/lane/lane-measure-cli.ts +15 -25
- package/scripts/lane/lane-occupancy.ts +6 -4
- package/scripts/lane/lane-open.ts +20 -19
- package/scripts/lane/lane-output.ts +4 -3
- package/scripts/lane/lane-paths.ts +12 -11
- package/scripts/lane/lane-phase.ts +33 -0
- package/scripts/lane/lane-reap.ts +2 -2
- package/scripts/lane/lane-registry.ts +16 -15
- package/scripts/lane/lane-relaunch.ts +9 -9
- package/scripts/lane/lane-report.ts +5 -4
- package/scripts/lane/lane-resume.ts +2 -2
- package/scripts/lane/lane-sampler.ts +55 -0
- package/scripts/lane/lane-seed.ts +7 -7
- package/scripts/lane/lane-stage-stats.ts +135 -0
- package/scripts/lane/lane-start-point.ts +8 -11
- package/scripts/lane/lane-stats.ts +60 -15
- package/scripts/lane/lane-stray.ts +1 -1
- package/scripts/lane/lane-vacant.ts +1 -1
- package/scripts/lane/openai-lane-supervisor-decision.ts +3 -7
- package/scripts/lane/openai-lane-supervisor-owner.ts +3 -9
- package/scripts/lane/openai-review-broker.ts +2 -4
- package/scripts/lib/ancestor-directories.ts +1 -1
- package/scripts/lib/bounded-pool.ts +2 -2
- package/scripts/lib/buffered-process.ts +4 -6
- package/scripts/lib/caddy-logs.sh +0 -0
- package/scripts/lib/cli-flags.ts +39 -6
- package/scripts/lib/error-message.ts +1 -1
- package/scripts/lib/json-value.ts +17 -3
- package/scripts/lib/poll.ts +1 -1
- package/scripts/lib/status-icons.ts +3 -3
- package/scripts/lib/timed-fetch.ts +1 -1
- package/scripts/lib/timeouts.ts +1 -1
- package/scripts/lines/bytes-command.ts +3 -4
- package/scripts/lines/effective-limit.ts +25 -12
- package/scripts/lines/line-budget.ts +47 -55
- package/scripts/lines/line-targets.ts +6 -2
- package/scripts/lines/lines-command.ts +3 -3
- package/scripts/lint/cspell-cached.ts +1 -1
- package/scripts/lint/cycle-recheck.ts +122 -0
- package/scripts/lint/format.ts +1 -2
- package/scripts/lint/lint-parallel.ts +34 -19
- package/scripts/lint/lint-related-scope.ts +25 -15
- package/scripts/lint/lint-related.ts +6 -7
- package/scripts/managed-marker/index.ts +1 -1
- package/scripts/managed-marker/managed-marker-logic.ts +1 -2
- package/scripts/notify/git-notify.ts +9 -7
- package/scripts/notify/telegram-notify.ts +53 -37
- package/scripts/notify/telegram-test-logic.ts +3 -3
- package/scripts/notify/telegram-test.ts +45 -30
- package/scripts/observations/observation-ledger-home.ts +14 -8
- package/scripts/observations/observation-ledger-line.ts +3 -2
- package/scripts/observations/observation-ledger-migrate.ts +3 -4
- package/scripts/observations/observation-ledger-prepare.ts +4 -4
- package/scripts/observations/observation-ledger.ts +14 -15
- package/scripts/observations/observation-record-cli.ts +83 -0
- package/scripts/observations/observation-record.ts +91 -0
- package/scripts/observations/observations-flush-cli.ts +1 -1
- package/scripts/observations/observations-flush-landing.ts +7 -6
- package/scripts/observations/observations-flush.ts +26 -27
- package/scripts/overrides/overrides-check.ts +18 -8
- package/scripts/package/package-scout-cli.ts +1 -1
- package/scripts/package/package-scout-format.ts +2 -2
- package/scripts/package/package-scout.ts +1 -1
- package/scripts/propagate/propagate-git-failure.ts +1 -1
- package/scripts/propagate/propagate-git.ts +7 -7
- package/scripts/propagate/propagate-plan.ts +2 -2
- package/scripts/propagate/propagate-publish.ts +2 -3
- package/scripts/propagate/propagate-run.ts +5 -7
- package/scripts/propagate/propagate-select.ts +1 -1
- package/scripts/propagate/propagate-steps.ts +19 -20
- package/scripts/propagate/propagate-targets.ts +6 -10
- package/scripts/propagate/propagate.ts +5 -5
- package/scripts/refactor/import-graph.ts +1 -1
- package/scripts/refactor/refactor-lint.ts +4 -10
- package/scripts/refactor/refactor-scan-cli.ts +1 -1
- package/scripts/refactor/refactor-scan.ts +2 -2
- package/scripts/refactor/refactor-targets.ts +1 -1
- package/scripts/release/github-release-cli.ts +25 -3
- package/scripts/release/github-release-runs.ts +1 -1
- package/scripts/release/release-cli.ts +21 -4
- package/scripts/release/release-history.ts +6 -10
- package/scripts/release/release-plan.ts +3 -3
- package/scripts/release/release-progress.ts +3 -4
- package/scripts/release/release-publish.ts +8 -9
- package/scripts/release/release-scope-cli.ts +8 -10
- package/scripts/release/release-tag.ts +6 -8
- package/scripts/release/release-worktree.ts +5 -5
- package/scripts/repo/auto-merge-setting-logic.ts +7 -9
- package/scripts/repo/auto-merge-setting.ts +1 -1
- package/scripts/repo/repo-setting.ts +4 -4
- package/scripts/repo/repository-labels.ts +1 -1
- package/scripts/repo/required-checks-logic.ts +3 -3
- package/scripts/repo/required-checks-report.ts +1 -1
- package/scripts/repo/ruleset-check-cli.ts +1 -1
- package/scripts/repo/ruleset-check.ts +1 -1
- package/scripts/report/report-format-reference.ts +26 -0
- package/scripts/report/report-lint-cli.ts +2 -2
- package/scripts/report/report-lint.ts +16 -2
- package/scripts/review/disposition-cli.ts +2 -2
- package/scripts/review/disposition-logic.ts +1 -1
- package/scripts/review/live-evidence.ts +9 -6
- package/scripts/review/review-attest-cli.ts +1 -2
- package/scripts/review/review-attest.ts +3 -3
- package/scripts/review/review-brief-cli.ts +19 -20
- package/scripts/review/review-brief.ts +29 -32
- package/scripts/review/review-checkout.ts +2 -2
- package/scripts/review/review-diff-parts.ts +3 -5
- package/scripts/review/review-diff-write.ts +1 -1
- package/scripts/review/review-finding-ledger.ts +7 -4
- package/scripts/review/review-findings-cli.ts +2 -2
- package/scripts/review/review-level.ts +4 -7
- package/scripts/review/review-record-cli.ts +73 -16
- package/scripts/review/review-record.ts +5 -4
- package/scripts/review/review-round2-cli.ts +2 -3
- package/scripts/review/review-round2.ts +13 -21
- package/scripts/review/review-stamps.ts +9 -71
- package/scripts/review/review-tree.ts +4 -5
- package/scripts/rules/bash-triggers.ts +4 -4
- package/scripts/rules/decision-oracle-batch.ts +5 -6
- package/scripts/rules/decision-oracle-stage.ts +1 -1
- package/scripts/rules/decision-oracle-tokens.ts +1 -2
- package/scripts/rules/decision-oracle.ts +2 -2
- package/scripts/rules/delivered-rules.ts +61 -406
- package/scripts/rules/destructive-command.ts +2 -2
- package/scripts/rules/direct-filing.ts +4 -4
- package/scripts/rules/direct-pr-create.ts +2 -2
- package/scripts/rules/early-heartbeat.ts +15 -19
- package/scripts/rules/file-body.ts +5 -6
- package/scripts/rules/filing-cap.ts +6 -7
- package/scripts/rules/filing-offer.ts +1 -1
- package/scripts/rules/firing-point.ts +6 -6
- package/scripts/rules/gh-api.ts +2 -2
- package/scripts/rules/git-argv.ts +3 -3
- package/scripts/rules/git-force.ts +2 -2
- package/scripts/rules/hook-context-line.ts +31 -0
- package/scripts/rules/implementation-cut-verdict.ts +5 -8
- package/scripts/rules/implementation-cut.ts +35 -32
- package/scripts/rules/index-guard.ts +2 -2
- package/scripts/rules/issue-citation.ts +7 -7
- package/scripts/rules/issue-comments.ts +21 -13
- package/scripts/rules/josh-git-bare.ts +2 -2
- package/scripts/rules/lane-background.ts +14 -16
- package/scripts/rules/lane-carry-conflict.ts +41 -5
- package/scripts/rules/lane-interactive-ask.ts +6 -9
- package/scripts/rules/lane-park.ts +12 -16
- package/scripts/rules/lane-split-park.ts +1 -2
- package/scripts/rules/lane-switch-main.ts +10 -13
- package/scripts/rules/last-prompt.ts +1 -1
- package/scripts/rules/oracle-consulted.ts +5 -5
- package/scripts/rules/oracle-firing.ts +6 -9
- package/scripts/rules/oracle-list-cli.ts +2 -2
- package/scripts/rules/permission-guards.ts +2 -2
- package/scripts/rules/piped-verification.ts +79 -9
- package/scripts/rules/poll-loop.ts +9 -11
- package/scripts/rules/pre-gate-cut.ts +33 -30
- package/scripts/rules/prior-comment-read.ts +3 -3
- package/scripts/rules/protected-files.ts +25 -13
- package/scripts/rules/raw-field-body.ts +3 -4
- package/scripts/rules/reply-language.ts +1 -1
- package/scripts/rules/rule-body-guard.ts +10 -12
- package/scripts/rules/rule-guard.ts +1 -1
- package/scripts/rules/rule-list.ts +51 -0
- package/scripts/rules/rule-registry-rows.ts +282 -0
- package/scripts/rules/rule-registry.ts +109 -0
- package/scripts/rules/rule-value-cache.ts +2 -2
- package/scripts/rules/rule-value-cli.ts +6 -4
- package/scripts/rules/rule-value.ts +61 -22
- package/scripts/rules/run-tail-rule.ts +11 -15
- package/scripts/rules/shell-body-trigger.ts +7 -7
- package/scripts/rules/shell-segments.ts +2 -4
- package/scripts/rules/stop-rules.ts +54 -41
- package/scripts/rules/tail-commands.ts +1 -1
- package/scripts/rules/test-declared-commit.ts +2 -2
- package/scripts/rules/third-party-write.ts +3 -3
- package/scripts/rules/worktree-guard.ts +12 -5
- package/scripts/run/add/run-add-cli.ts +165 -0
- package/scripts/run/add/run-add.ts +124 -0
- package/scripts/run/board/run-board-cli.ts +207 -0
- package/scripts/run/board/run-board-closed.ts +95 -0
- package/scripts/run/board/run-board-every.ts +60 -0
- package/scripts/run/board/run-board-fetch.ts +38 -0
- package/scripts/run/board/run-board-fit.ts +219 -0
- package/scripts/run/board/run-board-github.ts +162 -0
- package/scripts/run/board/run-board-header.ts +275 -0
- package/scripts/run/board/run-board-kind.ts +35 -0
- package/scripts/run/board/run-board-labels.ts +299 -0
- package/scripts/run/board/run-board-layout.ts +222 -0
- package/scripts/run/board/run-board-link.ts +31 -0
- package/scripts/run/board/run-board-machine.ts +198 -0
- package/scripts/run/board/run-board-notes.ts +103 -0
- package/scripts/run/board/run-board-phase.ts +136 -0
- package/scripts/run/board/run-board-plan.ts +129 -0
- package/scripts/run/board/run-board-read.ts +62 -0
- package/scripts/run/board/run-board-render-legend.ts +82 -0
- package/scripts/run/board/run-board-render-notes.ts +77 -0
- package/scripts/run/board/run-board-render-slot.ts +50 -0
- package/scripts/run/board/run-board-render.ts +407 -0
- package/scripts/run/board/run-board-scope.ts +17 -0
- package/scripts/run/board/run-board-screen.ts +43 -0
- package/scripts/run/board/run-board-span.ts +66 -0
- package/scripts/run/board/run-board-spin.ts +115 -0
- package/scripts/run/board/run-board-state.ts +113 -0
- package/scripts/run/board/run-board-status.ts +279 -0
- package/scripts/run/board/run-board-tick.ts +210 -0
- package/scripts/run/board/run-board-track.ts +22 -0
- package/scripts/run/board/run-board-usage-read.ts +255 -0
- package/scripts/run/board/run-board-usage-rusage.ts +124 -0
- package/scripts/run/board/run-board-usage-text.ts +80 -0
- package/scripts/run/board/run-board-usage.ts +165 -0
- package/scripts/run/carry/run-carry-added.ts +62 -0
- package/scripts/run/carry/run-carry-args.ts +25 -22
- package/scripts/run/carry/run-carry-change.ts +1 -1
- package/scripts/run/carry/run-carry-cli.ts +71 -48
- package/scripts/run/carry/run-carry-conversation.ts +6 -7
- package/scripts/run/carry/run-carry-ended.ts +85 -0
- package/scripts/run/carry/run-carry-reclaim.ts +1 -1
- package/scripts/run/carry/run-carry-stash.ts +3 -2
- package/scripts/run/carry/run-carry-streak.ts +8 -10
- package/scripts/run/carry/run-carry.ts +85 -89
- package/scripts/run/cut/run-cut-args.ts +7 -7
- package/scripts/run/cut/run-cut-cli.ts +54 -36
- package/scripts/run/cut/run-cut-handoff.ts +15 -15
- package/scripts/run/cut/run-cut-report.ts +37 -16
- package/scripts/run/cut/run-cut.ts +63 -77
- package/scripts/run/detached-launch.ts +35 -50
- package/scripts/run/entry/run-entry-cli.ts +48 -27
- package/scripts/run/entry/run-entry-stop.ts +7 -9
- package/scripts/run/entry/run-entry.ts +5 -6
- package/scripts/run/event/run-event-cli.ts +5 -6
- package/scripts/run/event/run-event-filed.ts +69 -0
- package/scripts/run/event/run-event-follow.ts +3 -3
- package/scripts/run/event/run-event-plan.ts +38 -0
- package/scripts/run/event/run-event-render.ts +9 -4
- package/scripts/run/event/run-event-scope.ts +47 -18
- package/scripts/run/event/run-event-stream-emit.ts +64 -11
- package/scripts/run/event/run-event-stream.ts +171 -46
- package/scripts/run/event/run-event-watch.ts +4 -6
- package/scripts/run/hold/run-hold-cli.ts +65 -62
- package/scripts/run/hold/run-hold.ts +88 -46
- package/scripts/run/merge/run-merge-cli.ts +116 -77
- package/scripts/run/merge/run-merge-collect.ts +107 -0
- package/scripts/run/merge/run-merge-steps.ts +112 -65
- package/scripts/run/merge/run-merge-token.ts +30 -0
- package/scripts/run/merge/run-merge.ts +31 -22
- package/scripts/run/progress/run-progress-args.ts +4 -4
- package/scripts/run/progress/run-progress-cli.ts +39 -50
- package/scripts/run/progress/run-progress-clock.ts +25 -32
- package/scripts/run/progress/run-progress-config.ts +6 -9
- package/scripts/run/progress/run-progress-read.ts +9 -10
- package/scripts/run/progress/run-progress.ts +48 -53
- package/scripts/run/review/run-review-cli.ts +6 -6
- package/scripts/run/review/run-review-steps.ts +6 -6
- package/scripts/run/review/run-review.ts +9 -11
- package/scripts/run/run-cli-fault.ts +29 -0
- package/scripts/run/run-ending-cli.ts +3 -3
- package/scripts/run/run-ending.ts +10 -14
- package/scripts/run/run-halfrun-resume.ts +6 -8
- package/scripts/run/run-headless.ts +25 -12
- package/scripts/run/run-invocation.ts +17 -22
- package/scripts/run/run-label.ts +7 -5
- package/scripts/run/run-liveness-cli.ts +19 -6
- package/scripts/run/run-liveness.ts +27 -38
- package/scripts/run/run-next-cli.ts +5 -9
- package/scripts/run/run-next.ts +4 -5
- package/scripts/run/run-parent-cut-hook.ts +10 -12
- package/scripts/run/run-preflight.ts +25 -29
- package/scripts/run/run-prep-cli.ts +17 -13
- package/scripts/run/run-prep-locate.ts +4 -5
- package/scripts/run/run-prep.ts +7 -10
- package/scripts/run/run-prrun-resume.ts +2 -2
- package/scripts/run/run-report-cli.ts +4 -4
- package/scripts/run/run-report.ts +9 -14
- package/scripts/run/run-retrospective.ts +3 -3
- package/scripts/run/run-section.ts +42 -0
- package/scripts/run/run-stage-read.ts +2 -2
- package/scripts/run/run-stage.ts +6 -4
- package/scripts/run/run-status-cli.ts +7 -5
- package/scripts/run/run-status.ts +6 -7
- package/scripts/run/run-step-cli.ts +13 -15
- package/scripts/run/run-step.ts +58 -47
- package/scripts/run/run-stop-notify.ts +7 -8
- package/scripts/run/run-stranded-cli.ts +1 -1
- package/scripts/run/run-stranded-detect.ts +4 -4
- package/scripts/run/run-stranded.ts +11 -13
- package/scripts/run/run-tail-cli.ts +15 -16
- package/scripts/run/run-tail.ts +14 -33
- package/scripts/run/run-watcher-guard-cli.ts +3 -4
- package/scripts/run/run-watcher-guard.ts +11 -12
- package/scripts/run/run-watcher-hook.ts +6 -12
- package/scripts/run/ship/run-ship-cli.ts +67 -33
- package/scripts/run/ship/run-ship-detach.ts +15 -13
- package/scripts/run/ship/run-ship-lock.ts +1 -1
- package/scripts/run/ship/run-ship-next.ts +7 -8
- package/scripts/run/ship/run-ship-pre-detach.ts +27 -11
- package/scripts/run/ship/run-ship-preflight.ts +10 -11
- package/scripts/run/ship/run-ship-probe.ts +4 -4
- package/scripts/run/ship/run-ship-return.ts +1 -1
- package/scripts/run/ship/run-ship-review-steps.ts +43 -24
- package/scripts/run/ship/run-ship-review.ts +12 -14
- package/scripts/run/ship/run-ship-scoped.ts +15 -6
- package/scripts/run/ship/run-ship-stage.ts +80 -26
- package/scripts/run/ship/run-ship-steps.ts +26 -16
- package/scripts/run/ship/run-ship-stop-text.ts +4 -2
- package/scripts/run/ship/run-ship-sync.ts +9 -8
- package/scripts/run/ship/run-ship.ts +17 -32
- package/scripts/run/tidy/run-tidy-cli.ts +9 -5
- package/scripts/run/tidy/run-tidy-lanes.ts +18 -7
- package/scripts/run/tidy/run-tidy-stashes.ts +8 -8
- package/scripts/run/tidy/run-tidy.ts +4 -3
- package/scripts/run/wake/run-wake-cli.ts +27 -32
- package/scripts/run/wake/run-wake-describe.ts +24 -28
- package/scripts/run/wake/run-wake-driver.ts +14 -14
- package/scripts/run/wake/run-wake-handoff.ts +6 -6
- package/scripts/run/wake/run-wake-loop.ts +9 -9
- package/scripts/run/wake/run-wake-restart.ts +4 -5
- package/scripts/run/wake/run-wake-session.ts +23 -27
- package/scripts/run/wake/run-wake.ts +57 -279
- package/scripts/safe-chain/ci-installer-pin.ts +3 -3
- package/scripts/safe-chain/pack-hook.ts +2 -2
- package/scripts/safe-chain/preinstall-command.ts +2 -2
- package/scripts/security/security-audit-logic.ts +1 -1
- package/scripts/security/security-audit-provision-logic.ts +1 -1
- package/scripts/security/security-audit-provision.ts +2 -2
- package/scripts/security/security-audit.ts +5 -5
- package/scripts/security/security-updates-logic.ts +2 -3
- package/scripts/security/security-updates.ts +2 -4
- package/scripts/self-sync-guard/index.ts +1 -1
- package/scripts/self-sync-guard/self-sync-guard-logic.ts +2 -2
- package/scripts/self-sync-guard/self-sync-refusal.ts +1 -1
- package/scripts/sonar/sonar-hotspots-cli.ts +1 -1
- package/scripts/sonar/sonar-hotspots.ts +1 -1
- package/scripts/sonar/sonar-new-code-cli.ts +1 -1
- package/scripts/sonar/sonar-new-code.ts +1 -1
- package/scripts/sonar/sonar-project.ts +1 -1
- package/scripts/split/split-assess-cli.ts +1 -1
- package/scripts/split/split-assess.ts +3 -3
- package/scripts/sync/directory-copy-guard.ts +2 -3
- package/scripts/sync/managed-config-scope-cli.ts +1 -2
- package/scripts/sync/managed-config-scope.ts +4 -4
- package/scripts/sync/plugin-skill-directories.ts +2 -2
- package/scripts/sync/reconcile-templates.ts +17 -8
- package/scripts/sync/removed-skill-manifest.ts +2 -3
- package/scripts/sync/sync-ai-files.ts +7 -7
- package/scripts/sync/sync-configs.ts +30 -3
- package/scripts/sync/sync-hook-safety.ts +2 -2
- package/scripts/sync/sync.ts +23 -10
- package/scripts/sync/synced-paths.ts +2 -1
- package/scripts/sync/workflow-pin-logic.ts +1 -1
- package/scripts/test/test-declared-changed.ts +4 -4
- package/scripts/test/test-declared-logic.ts +2 -3
- package/scripts/test/test-declared-match.ts +25 -4
- package/scripts/test/test-declared.ts +26 -9
- package/scripts/test/test-red-commit.ts +3 -2
- package/scripts/test/test-red-logic.ts +7 -14
- package/scripts/test/test-red.ts +12 -47
- package/scripts/test/test-related-scope.ts +2 -3
- package/scripts/test/test-related.ts +3 -3
- package/scripts/test/test-type-logic.ts +1 -2
- package/scripts/test/test-unit-guard.ts +13 -17
- package/scripts/test/unit-worker-share.ts +7 -8
- package/scripts/time-runtime/time-agent-bundles.ts +2 -4
- package/scripts/time-runtime/time-background.ts +17 -21
- package/scripts/time-runtime/time-batch-guard.ts +67 -342
- package/scripts/time-runtime/time-bundle-call.ts +26 -28
- package/scripts/time-runtime/time-bundles.ts +11 -12
- package/scripts/time-runtime/time-call-identity.ts +1 -1
- package/scripts/time-runtime/time-command-key.ts +2 -2
- package/scripts/time-runtime/time-density-hook.ts +8 -11
- package/scripts/time-runtime/time-density.ts +5 -5
- package/scripts/time-runtime/time-followup-stage.ts +7 -7
- package/scripts/time-runtime/time-format.ts +5 -5
- package/scripts/time-runtime/time-hook-transcript.ts +3 -3
- package/scripts/time-runtime/time-instant.ts +1 -1
- package/scripts/time-runtime/time-markers.ts +15 -19
- package/scripts/time-runtime/time-phase-names.ts +3 -3
- package/scripts/time-runtime/time-reported-failure.ts +15 -19
- package/scripts/time-runtime/time-round-trips.ts +20 -23
- package/scripts/time-runtime/time-shell.ts +8 -8
- package/scripts/time-runtime/time-single-check.ts +1 -2
- package/scripts/time-runtime/time-spans.ts +35 -40
- package/scripts/time-runtime/time-tool-call.ts +15 -16
- package/scripts/time-runtime/time-transcript-line.ts +53 -34
- package/scripts/time-runtime/time-writes.ts +5 -5
- package/scripts/ui/ui-routes-cli.ts +1 -2
- package/scripts/ui/ui-routes.ts +1 -2
- package/scripts/version/bump-version.ts +1 -1
- package/scripts/version/fresh-metadata-cache.ts +2 -2
- package/scripts/version/latest-corepack.ts +26 -26
- package/scripts/version/latest-lane-guard.ts +1 -1
- package/scripts/version/latest-scope-cli.ts +2 -2
- package/scripts/version/latest-stamp.ts +1 -2
- package/scripts/version/latest-update.ts +2 -2
- package/scripts/version/npm-registry.ts +2 -2
- package/scripts/version/package-manager-version.ts +18 -0
- package/scripts/version/publishable-range-check.ts +2 -1
- package/scripts/version/publishable-range.ts +1 -1
- package/scripts/version/release-age.ts +11 -11
- package/scripts/version/release-hold.ts +2 -2
- package/scripts/version/safe-chain-version-update.ts +3 -3
- package/scripts/version/version-check-logic.ts +2 -3
- package/scripts/version/version-check.ts +1 -2
- package/scripts/version/version-command-config.ts +2 -2
- package/scripts/version/version-commands.ts +3 -3
- package/scripts/version/version-remote.ts +4 -4
- package/scripts/version/version-targets.ts +2 -2
- package/templates/gitignore +7 -0
- package/dist/hooks/chunk-KHX4U3BG.js +0 -6400
- package/dist/hooks/chunk-RKUAD3I6.js +0 -90
- package/dist/hooks/chunk-WPALEIRX.js +0 -18
- package/scripts/backlog/backlog-restructure.ts +0 -152
- package/scripts/rules/issue-fold-rule.ts +0 -72
- package/scripts/rules/wip-cap.ts +0 -63
- package/scripts/run/run-issue-number.ts +0 -19
|
@@ -1,84 +1,123 @@
|
|
|
1
1
|
import {
|
|
2
2
|
duplicate_read_outcome
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-NZBHG6FW.js";
|
|
4
4
|
import {
|
|
5
5
|
ALREADY_DONE_LABEL,
|
|
6
6
|
CONTEXT_CUT_THRESHOLD,
|
|
7
7
|
IN_PROGRESS_LABEL,
|
|
8
8
|
NEEDS_DECISION_LABEL,
|
|
9
9
|
NEEDS_HUMAN_REVIEW_LABEL,
|
|
10
|
-
PORCELAIN_FLAG,
|
|
11
|
-
agent_role_profile,
|
|
12
10
|
bash_triggers,
|
|
13
|
-
cli_flags,
|
|
14
11
|
filing_cap,
|
|
15
|
-
git_command,
|
|
16
|
-
git_common_directory,
|
|
17
12
|
git_gh_command,
|
|
18
13
|
git_gh_issue_read,
|
|
19
14
|
git_gh_pr_read,
|
|
20
|
-
git_spawn_sync,
|
|
21
15
|
has_any_label,
|
|
22
|
-
issue_cite,
|
|
23
16
|
lane_background,
|
|
24
17
|
lane_park,
|
|
25
|
-
|
|
26
|
-
own_session,
|
|
27
|
-
parse_json_object_safe,
|
|
18
|
+
parse_json_object_or_undefined,
|
|
28
19
|
read_json_listing,
|
|
29
|
-
repo_origin,
|
|
30
20
|
repo_party,
|
|
31
|
-
run_carry,
|
|
32
21
|
run_cut,
|
|
33
22
|
run_cut_handoff,
|
|
34
|
-
|
|
23
|
+
run_event_scope,
|
|
24
|
+
run_event_stream,
|
|
25
|
+
run_event_stream_emit,
|
|
35
26
|
run_hold,
|
|
36
27
|
run_tail_rule,
|
|
28
|
+
session_cite,
|
|
37
29
|
shell_segments,
|
|
38
30
|
tail_commands
|
|
39
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-MXVQMLDP.js";
|
|
40
32
|
import {
|
|
41
33
|
ancestor_directories,
|
|
42
34
|
find_local_bin_upwards
|
|
43
35
|
} from "./chunk-JBBMAPC4.js";
|
|
36
|
+
import {
|
|
37
|
+
agent_role_profile,
|
|
38
|
+
agent_session_role,
|
|
39
|
+
git_common_directory,
|
|
40
|
+
issue_cite,
|
|
41
|
+
lane_registry,
|
|
42
|
+
repo_origin,
|
|
43
|
+
run_headless
|
|
44
|
+
} from "./chunk-SYSRHRWU.js";
|
|
44
45
|
import {
|
|
45
46
|
error_text
|
|
46
47
|
} from "./chunk-CDY4NFQG.js";
|
|
47
48
|
import {
|
|
48
49
|
batch_outcome
|
|
49
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-DZWZ3DKY.js";
|
|
50
51
|
import {
|
|
51
52
|
investigation_refusal
|
|
52
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-R6CRQEAL.js";
|
|
53
54
|
import {
|
|
54
55
|
investigation_reads
|
|
55
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-76RK6E3H.js";
|
|
56
57
|
import {
|
|
57
58
|
lane_guard_policy
|
|
58
|
-
} from "./chunk-
|
|
59
|
+
} from "./chunk-GG72ANKI.js";
|
|
59
60
|
import {
|
|
60
|
-
hook_decision
|
|
61
|
-
|
|
62
|
-
run_issue_number
|
|
63
|
-
} from "./chunk-ZQGD4GBY.js";
|
|
61
|
+
hook_decision
|
|
62
|
+
} from "./chunk-KPM4YIIX.js";
|
|
64
63
|
import {
|
|
65
64
|
cost_attribute,
|
|
66
65
|
cost_blocks,
|
|
66
|
+
open_issue_schema,
|
|
67
|
+
time_batch_guard,
|
|
68
|
+
time_density_hook,
|
|
69
|
+
time_shell
|
|
70
|
+
} from "./chunk-TLJYAGZK.js";
|
|
71
|
+
import {
|
|
72
|
+
lane_child_marker
|
|
73
|
+
} from "./chunk-Z5TMJIPW.js";
|
|
74
|
+
import {
|
|
75
|
+
PORCELAIN_FLAG,
|
|
76
|
+
cli_flags,
|
|
67
77
|
cost_transcript,
|
|
68
78
|
cost_usage,
|
|
69
79
|
file_reader,
|
|
80
|
+
git_command,
|
|
81
|
+
git_spawn_sync,
|
|
82
|
+
issue_number_shape,
|
|
70
83
|
json_value,
|
|
71
84
|
lane_paths,
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
time_shell
|
|
76
|
-
} from "./chunk-WK2XSHSI.js";
|
|
85
|
+
own_session,
|
|
86
|
+
run_carry
|
|
87
|
+
} from "./chunk-NZN2UFI6.js";
|
|
77
88
|
import {
|
|
78
89
|
PLATFORM_TEMP_ROOT,
|
|
79
90
|
PROBE_TIMEOUT_MS,
|
|
91
|
+
platform_temporary,
|
|
80
92
|
stamp_file
|
|
81
|
-
} from "./chunk-
|
|
93
|
+
} from "./chunk-NEC4AT4Z.js";
|
|
94
|
+
|
|
95
|
+
// scripts/run/event/run-event-plan.ts
|
|
96
|
+
var KIND = run_event_stream.EVENT_KIND.PLAN;
|
|
97
|
+
var PLAN_VERB = "planned";
|
|
98
|
+
function plan_text(issue) {
|
|
99
|
+
return `${PLAN_VERB} ${issue_cite.plain(issue)}`;
|
|
100
|
+
}
|
|
101
|
+
function has_plan(events, issue) {
|
|
102
|
+
return run_event_scope.since_own_launch(events, issue).some((event) => event.kind === KIND && run_event_scope.issue_named(event) === issue);
|
|
103
|
+
}
|
|
104
|
+
async function emit_plan(issue) {
|
|
105
|
+
if (has_plan(await run_event_stream_emit.invocation_or_all_events(), issue)) return;
|
|
106
|
+
await run_event_stream_emit.emit(KIND, plan_text(issue));
|
|
107
|
+
}
|
|
108
|
+
var run_event_plan = { emit_plan, plan_text };
|
|
109
|
+
|
|
110
|
+
// scripts/lane/lane-phase.ts
|
|
111
|
+
async function mark_implement(directory = process.cwd(), source = process.env) {
|
|
112
|
+
const issue = lane_child_marker.marked_issue(source);
|
|
113
|
+
if (issue === void 0 || !lane_child_marker.is_child_of(directory, source)) return;
|
|
114
|
+
await run_event_plan.emit_plan(issue);
|
|
115
|
+
await run_event_stream_emit.emit(
|
|
116
|
+
run_event_stream.EVENT_KIND.LANE_PHASE,
|
|
117
|
+
`${issue_cite.plain(issue)} implement`
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
var lane_phase = { mark_implement };
|
|
82
121
|
|
|
83
122
|
// scripts/rules/direct-filing.ts
|
|
84
123
|
var DIRECT_FILING_REASON = '\u26D4 direct filing: an Issue is filed with `pnpm josh issue:file "<title>" --body-file <path> --depth <0|1|2> [--route <route>] [--label <name>] [--repo <owner/repo>]`, never with `gh api \u2026/issues` or `gh issue create`. The command runs every filing step in order \u2014 the duplicate scout, the body lint and its classification labels, the depth and `route:` labels, the `## Origin` check when filing into another repository, and `epic:bundle` after the create \u2014 so none of them is a step to remember. When the scout prints candidates it holds the filing: read each, then reissue with `--distinct <N,\u2026>` for the ones that are separate deliverables. Reference: `docs/josh-commands-backlog.md` \u2192 "`josh issue:file`". **This rule fires on every occurrence, not once per run.**';
|
|
@@ -101,6 +140,8 @@ var INTERVAL_KEY = "JOSH_PROGRESS_INTERVAL_MINUTES";
|
|
|
101
140
|
var MS_PER_MINUTE = 6e4;
|
|
102
141
|
var MS_PER_SECOND = 1e3;
|
|
103
142
|
var DEFAULT_INTERVAL_MS = DEFAULT_INTERVAL_MINUTES * MS_PER_MINUTE;
|
|
143
|
+
var DISABLED_KEY = "JOSH_PROGRESS";
|
|
144
|
+
var DISABLED_VALUE = "0";
|
|
104
145
|
var NO_LANES = "none";
|
|
105
146
|
var NO_CHILD_YET = "no in-progress child yet";
|
|
106
147
|
var NO_NEXT = "none";
|
|
@@ -193,9 +234,14 @@ function minutes_from(raw) {
|
|
|
193
234
|
}
|
|
194
235
|
return minutes;
|
|
195
236
|
}
|
|
237
|
+
function is_disabled() {
|
|
238
|
+
return process.env[DISABLED_KEY] === DISABLED_VALUE;
|
|
239
|
+
}
|
|
196
240
|
var run_progress = {
|
|
197
241
|
DEFAULT_INTERVAL_MINUTES,
|
|
198
242
|
DEFAULT_INTERVAL_MS,
|
|
243
|
+
DISABLED_KEY,
|
|
244
|
+
DISABLED_VALUE,
|
|
199
245
|
INTERVAL_KEY,
|
|
200
246
|
MS_PER_MINUTE,
|
|
201
247
|
MS_PER_SECOND,
|
|
@@ -208,6 +254,7 @@ var run_progress = {
|
|
|
208
254
|
format_next_line,
|
|
209
255
|
format_next_report,
|
|
210
256
|
format_report,
|
|
257
|
+
is_disabled,
|
|
211
258
|
is_due,
|
|
212
259
|
minutes_from,
|
|
213
260
|
next_state,
|
|
@@ -234,11 +281,7 @@ function parse_stamp(raw) {
|
|
|
234
281
|
function read_last_line(target) {
|
|
235
282
|
const raw = stamp_file.read_stamp_text(target);
|
|
236
283
|
if (raw === void 0) return void 0;
|
|
237
|
-
|
|
238
|
-
return report_stamp_schema.safeParse(JSON.parse(raw)).data?.line;
|
|
239
|
-
} catch {
|
|
240
|
-
return void 0;
|
|
241
|
-
}
|
|
284
|
+
return json_value.parse_with(raw, report_stamp_schema)?.line;
|
|
242
285
|
}
|
|
243
286
|
function read_last_report(target) {
|
|
244
287
|
const raw = stamp_file.read_stamp_text(target);
|
|
@@ -351,8 +394,7 @@ var package_schema = z2.object({
|
|
|
351
394
|
function read_declared_minutes(directory) {
|
|
352
395
|
try {
|
|
353
396
|
const raw = readFileSync(path.join(directory, PACKAGE_FILE), "utf8");
|
|
354
|
-
|
|
355
|
-
return parsed.success ? parsed.data.josh?.progress_interval_minutes : void 0;
|
|
397
|
+
return json_value.parse_with(raw, package_schema)?.josh?.progress_interval_minutes;
|
|
356
398
|
} catch {
|
|
357
399
|
return void 0;
|
|
358
400
|
}
|
|
@@ -437,7 +479,7 @@ function decide(call, run2, can_record) {
|
|
|
437
479
|
if (can_record) ARM_RECORD.record(target, lands_ms);
|
|
438
480
|
return false;
|
|
439
481
|
}
|
|
440
|
-
var EARLY_HEARTBEAT_REASON = "\u26D4 early heartbeat: this call arms a wait timer of its own, and the progress clock is not yours to keep. `pnpm josh run:progress --wait` keeps it for you (`JOSH_PROGRESS_INTERVAL_MINUTES`, or `josh.progress_interval_minutes` in `package.json`, default 20 minutes): start it once in the background and it reports the five labelled lines to the run's event stream on its own, without waking you \u2014 relay nothing, and start it again only after it exits, which it does when newly runnable work arrives. Two timers armed at once is what produced reports 3\u20135 minutes apart on a 15-minute setting (joshuafolkken/kit#1570): a new one was armed on the turn a timer fired and again on the turn a child's completion woke the run, and `--mark` recorded each report without anything refusing the early ones. **An explicit ask is not a heartbeat**: if the person asked for progress now, run `pnpm josh run:progress --once`, which prints the five labelled lines whatever the clock says. If you are waiting on something rather than on a clock, wait on the thing itself \u2014 `pnpm josh followup` waits for CI. The procedure is `.claude/skills/workflow-commands/backlogrun.md` \u2192 \"Progress while the run is quiet\". **This rule fires on every early arm, not once per run**, so reissuing the same sleep will be refused again.";
|
|
482
|
+
var EARLY_HEARTBEAT_REASON = "\u26D4 early heartbeat: this call arms a wait timer of its own, and the progress clock is not yours to keep. `pnpm josh run:progress --wait` keeps it for you (`JOSH_PROGRESS_INTERVAL_MINUTES`, or `josh.progress_interval_minutes` in `package.json`, default 20 minutes): start it once in the background and it reports the five labelled lines to the run's event stream on its own, without waking you \u2014 relay nothing, and start it again only after it exits, which it does when newly runnable work arrives. Two timers armed at once is what produced reports 3\u20135 minutes apart on a 15-minute setting (joshuafolkken/kit#1570): a new one was armed on the turn a timer fired and again on the turn a child's completion woke the run, and `--mark` recorded each report without anything refusing the early ones. **An explicit ask is not a heartbeat**: if the person asked for progress now, run `pnpm josh run:progress --once`, which prints the five labelled lines whatever the clock says \u2014 under `backlogrun`, `pnpm josh run:board --chat` instead. If you are waiting on something rather than on a clock, wait on the thing itself \u2014 `pnpm josh followup` waits for CI. The procedure is `.claude/skills/workflow-commands/backlogrun.md` \u2192 \"Progress while the run is quiet\". **This rule fires on every early arm, not once per run**, so reissuing the same sleep will be refused again.";
|
|
441
483
|
var PROGRESS_NAMES = /* @__PURE__ */ new Set(["run:progress"]);
|
|
442
484
|
var WATCH_FLAG = /(?:^|\s)--(?:wait|once)(?=\s|$)/u;
|
|
443
485
|
function is_progress_watch_segment(segment) {
|
|
@@ -931,7 +973,8 @@ function report_empty(cwd, session_id) {
|
|
|
931
973
|
}
|
|
932
974
|
function provider_of(environment) {
|
|
933
975
|
const resolved = agent_role_profile.resolve_provider(environment);
|
|
934
|
-
|
|
976
|
+
if (resolved.kind !== "provider" || resolved.is_default === true) return void 0;
|
|
977
|
+
return resolved.provider;
|
|
935
978
|
}
|
|
936
979
|
function measurement_of(session) {
|
|
937
980
|
return {
|
|
@@ -1060,12 +1103,9 @@ function cache_path(directory) {
|
|
|
1060
1103
|
function cached_verdict(target, now_ms) {
|
|
1061
1104
|
const raw = stamp_file.read_stamp_text(target);
|
|
1062
1105
|
if (raw === void 0) return void 0;
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
} catch {
|
|
1067
|
-
return void 0;
|
|
1068
|
-
}
|
|
1106
|
+
const cached = json_value.parse_with(raw, cache_schema);
|
|
1107
|
+
if (cached === void 0) return void 0;
|
|
1108
|
+
return now_ms - cached.read_at_ms < VERDICT_REUSE_MS ? cached.verdict : void 0;
|
|
1069
1109
|
}
|
|
1070
1110
|
function reused_verdict(read2, directory = process.cwd(), now_ms = Date.now()) {
|
|
1071
1111
|
const target = cache_path(directory);
|
|
@@ -1100,7 +1140,7 @@ function current_state() {
|
|
|
1100
1140
|
source: process.env,
|
|
1101
1141
|
carried: run_cut.carried_cut_sync,
|
|
1102
1142
|
held_issue: run_cut.held_issue_sync,
|
|
1103
|
-
// **Read through the short reuse window
|
|
1143
|
+
// **Read through the short reuse window**. The row now fires per
|
|
1104
1144
|
// threshold crossing rather than once per run, so this predicate is a candidate on every edit;
|
|
1105
1145
|
// the window collapses one turn's burst of edits to a single whole-transcript price.
|
|
1106
1146
|
verdict: () => implementation_cut_verdict.reused_verdict(() => cost_cli.session_verdict())
|
|
@@ -1114,8 +1154,12 @@ function held_run_issue(state) {
|
|
|
1114
1154
|
if (lane_paths.lane_issue_of(state.directory, { ...state.source }) !== void 0) return void 0;
|
|
1115
1155
|
return state.held_issue();
|
|
1116
1156
|
}
|
|
1157
|
+
function implementing_run_issue(state) {
|
|
1158
|
+
if (agent_session_role.is_reviewer(state.source)) return void 0;
|
|
1159
|
+
return lane_child_issue(state) ?? held_run_issue(state);
|
|
1160
|
+
}
|
|
1117
1161
|
function uncut_run_issue(state) {
|
|
1118
|
-
const issue =
|
|
1162
|
+
const issue = implementing_run_issue(state);
|
|
1119
1163
|
if (issue === void 0) return void 0;
|
|
1120
1164
|
return state.carried()?.issue === issue ? void 0 : issue;
|
|
1121
1165
|
}
|
|
@@ -1129,7 +1173,7 @@ function is_over_threshold_edit(call, state = current_state()) {
|
|
|
1129
1173
|
return warrants_the_cut(state);
|
|
1130
1174
|
}
|
|
1131
1175
|
var THRESHOLD_TEXT = `${cost_format.format_tokens(CONTEXT_CUT_THRESHOLD)}-token`;
|
|
1132
|
-
var IMPLEMENTATION_CUT_REASON = `\u26D4 implementation-phase cut: this checkout is a lane dispatched for this issue, or a run holds it for this issue (joshuafolkken/kit#2760), and its recent-context cost has crossed the shared ${THRESHOLD_TEXT} threshold mid-implementation, so the thinking accumulated so far is now re-read on every later request. Take the cut before this edit. First write a handoff file with the Write tool \u2014 the user\u2019s instruction verbatim, what you have completed, what remains, and what you deliberately did not touch, as ${run_cut_handoff.HANDOFF_FORMAT} (Markdown is refused) \u2014 and pass it as \`--handoff <path>\`, so the fresh process resumes on the original instruction rather than the working tree alone (joshuafolkken/kit#2354); a resume that finds no instruction is refused \`incomplete\` rather than continuing blind. \`pnpm josh run:cut --impl <N> --handoff <path>\` ends this process and relaunches a fresh one that resumes back into implementation (\`resume-impl\`), dropping the accumulated context rather than carrying it \u2014 joshuafolkken/kit#1933 built the boundary and joshuafolkken/kit#2310 measured it firing 0 times because the verdict was only ever read at session entry, where the context has not yet grown. The verdict is \`pnpm josh cost --cut\`'s exactly \u2014 the same per-request billed-input statistic against the same threshold, never a second measurement. Issue \`pnpm josh run:cut --impl <N> --handoff <path>\` now and read the verdict: on \`cut\`, **end the turn immediately** \u2014 in a lane the fresh process owns the run and continues implementing, so it must not be waited for; outside a lane nothing is relaunched, so first send the \`confirmation\` Telegram naming the resume command \`fullrun #<N>\` and keep the hold; on \`not-a-lane\`, \`unready\`, \`busy\`, \`failed\` or \`unknown\`, this process carries the run on and the edit is simply the next call. Never relaunch a second process after \`busy\`. This fired because the dispatch mark names this lane or the run hold names this issue; a person working here carries no mark and holds no run, so sees no refusal, so there is no human-or-child judgement left to make. The procedure is \`.claude/skills/workflow-commands/pre-gate-cut.md\`. Reissue this edit once the cut has answered \u2014 an edit reissued right after this refusal passes, so \`busy\` / \`failed\` cannot wedge the run edit after edit; this fires again on the next threshold crossing rather than once per run.`;
|
|
1176
|
+
var IMPLEMENTATION_CUT_REASON = `\u26D4 implementation-phase cut: this checkout is a lane dispatched for this issue, or a run holds it for this issue (joshuafolkken/kit#2760), and its recent-context cost has crossed the shared ${THRESHOLD_TEXT} threshold mid-implementation, so the thinking accumulated so far is now re-read on every later request. Take the cut before this edit. First write a handoff file at \`${run_cut_handoff.HANDOFF_PATH}\` (ignored, so it is never committed) with the Write tool \u2014 the user\u2019s instruction verbatim, what you have completed, what remains, and what you deliberately did not touch, as ${run_cut_handoff.HANDOFF_FORMAT} (Markdown is refused) \u2014 and pass it as \`--handoff <path>\`, so the fresh process resumes on the original instruction rather than the working tree alone (joshuafolkken/kit#2354); a resume that finds no instruction is refused \`incomplete\` rather than continuing blind. \`pnpm josh run:cut --impl <N> --handoff <path>\` ends this process and relaunches a fresh one that resumes back into implementation (\`resume-impl\`), dropping the accumulated context rather than carrying it \u2014 joshuafolkken/kit#1933 built the boundary and joshuafolkken/kit#2310 measured it firing 0 times because the verdict was only ever read at session entry, where the context has not yet grown. The verdict is \`pnpm josh cost --cut\`'s exactly \u2014 the same per-request billed-input statistic against the same threshold, never a second measurement. Issue \`pnpm josh run:cut --impl <N> --handoff <path>\` now and read the verdict: on \`cut\`, **end the turn immediately** \u2014 in a lane the fresh process owns the run and continues implementing, so it must not be waited for; outside a lane nothing is relaunched, so first send the \`confirmation\` Telegram naming the resume command \`fullrun #<N>\` and keep the hold; on \`not-a-lane\`, \`unready\`, \`busy\`, \`failed\` or \`unknown\`, this process carries the run on and the edit is simply the next call. Never relaunch a second process after \`busy\`. This fired because the dispatch mark names this lane or the run hold names this issue; a person working here carries no mark and holds no run, so sees no refusal, so there is no human-or-child judgement left to make. The procedure is \`.claude/skills/workflow-commands/pre-gate-cut.md\`. Reissue this edit once the cut has answered \u2014 an edit reissued right after this refusal passes, so \`busy\` / \`failed\` cannot wedge the run edit after edit; this fires again on the next threshold crossing rather than once per run.`;
|
|
1133
1177
|
var REISSUE_WINDOW_MS = 9e4;
|
|
1134
1178
|
function is_reissued_refusal(now_ms, delivered_at_ms) {
|
|
1135
1179
|
return now_ms - delivered_at_ms < REISSUE_WINDOW_MS;
|
|
@@ -1201,7 +1245,6 @@ var gh_api = {
|
|
|
1201
1245
|
var ISSUE_PATH_NUMBER = /issues\/(\d+)/gu;
|
|
1202
1246
|
var ISSUE_VIEW_NUMBER = /\bissue\s+view\s+(?:-{1,2}\S+\s+)*(\d+)/u;
|
|
1203
1247
|
var ISSUE_READ_ARGUMENTS = /\bissue:read\b([\s\d]*)/u;
|
|
1204
|
-
var A_NUMBER = /^\d+$/u;
|
|
1205
1248
|
var COMMENTS_ENDPOINT = /issues\/\d+\/comments\b/u;
|
|
1206
1249
|
var VIEW_WITH_COMMENTS = /\bissue\s+view\b[^\n]*--comments\b/u;
|
|
1207
1250
|
var ISSUE_READ_COMMAND = /\bissue:read\b/u;
|
|
@@ -1210,7 +1253,7 @@ function add_issue_read_numbers(command, numbers) {
|
|
|
1210
1253
|
if (match === null) return;
|
|
1211
1254
|
const tokens = (match[1] ?? "").split(/\s+/u);
|
|
1212
1255
|
for (const token of tokens) {
|
|
1213
|
-
if (
|
|
1256
|
+
if (issue_number_shape.ISSUE_NUMBER_PATTERN.test(token)) numbers.add(Number(token));
|
|
1214
1257
|
}
|
|
1215
1258
|
}
|
|
1216
1259
|
function issue_numbers_of(command) {
|
|
@@ -1275,13 +1318,15 @@ function is_body_only_issue_read(command) {
|
|
|
1275
1318
|
function reads_issue_comments(command) {
|
|
1276
1319
|
return shell_segments.segments_of(command).some((segment) => fetches_issue_comments(segment));
|
|
1277
1320
|
}
|
|
1278
|
-
var ISSUE_COMMENTS_REASON = "\u26D4 an Issue's comments are part of the Issue
|
|
1321
|
+
var ISSUE_COMMENTS_REASON = "\u26D4 issue comments: pnpm josh issue:read <N>\nRun that in place of this read: <N> is the Issue it names, and an Issue's comments are part of the Issue, so the body and every comment come back together. Without josh, add `gh api repos/{owner}/{repo}/issues/<N>/comments --jq '.[] | {user: .user.login, created_at, body}'` beside the body read, or `gh issue view <N> --comments` where GraphQL is reachable.\nWhy: a decision recorded after the body was written lives only in a comment \u2014 a corrected diagnosis (joshuafolkken/kit#1537), a changed default and an added acceptance criterion (joshuafolkken/kit#1520), a scope handed to another Issue (joshuafolkken/kit#1304) \u2014 and nothing in the body says it was superseded, so a body-only reader builds the wrong thing and sees no contradiction. Then the later text is the agreement in force \u2014 a comment supersedes the body it contradicts \u2014 except for two answers that are not the run's to make: work a comment reassigns to another Issue is out of scope and is not implemented, and a comment saying the Issue no longer has a reason to exist stops the run with a `confirmation` Telegram. The procedure is `.claude/skills/workflow-commands/issue-comments.md`. Every body-only read is refused until the comments are read.";
|
|
1279
1322
|
var ROW5 = {
|
|
1280
1323
|
id: "issue-comments",
|
|
1281
1324
|
is_trigger: bash_triggers.on_bash_command(is_body_only_issue_read),
|
|
1282
1325
|
reason: ISSUE_COMMENTS_REASON,
|
|
1283
1326
|
already_satisfied: prior_comment_read.already_read_for_call,
|
|
1284
|
-
keeps: bash_triggers.on_bash_command(reads_issue_comments)
|
|
1327
|
+
keeps: bash_triggers.on_bash_command(reads_issue_comments),
|
|
1328
|
+
// The opening the reason carried before it led with the command.
|
|
1329
|
+
former_reasons: ["\u26D4 an Issue's comments are part of the Issue: read them before implementing"]
|
|
1285
1330
|
};
|
|
1286
1331
|
var issue_comments = {
|
|
1287
1332
|
ISSUE_COMMENTS_REASON,
|
|
@@ -1289,25 +1334,6 @@ var issue_comments = {
|
|
|
1289
1334
|
is_body_only_issue_read
|
|
1290
1335
|
};
|
|
1291
1336
|
|
|
1292
|
-
// scripts/rules/issue-fold-rule.ts
|
|
1293
|
-
var FOLD_NAMES = /* @__PURE__ */ new Set(["issue:fold"]);
|
|
1294
|
-
function runs_the_fold(command) {
|
|
1295
|
-
return shell_segments.segments_of(command).some((segment) => shell_segments.is_josh_command(segment, FOLD_NAMES));
|
|
1296
|
-
}
|
|
1297
|
-
function already_folded(tail, _call) {
|
|
1298
|
-
if (filing_cap.prior_filing_count(tail) === 0) return true;
|
|
1299
|
-
return tail_commands.prior_bash_commands(tail).some((command) => runs_the_fold(command));
|
|
1300
|
-
}
|
|
1301
|
-
var ISSUE_FOLD_REASON = '\u26D4 issue fold: this run has filed an Issue before and is filing another with no `pnpm josh issue:fold` between them. Several findings from one session fold into one Issue by default \u2014 the filing-time counterpart to the split assessment, whose two questions it reuses: are the findings separable, and does the whole clearly exceed one verification gate (the size half is `split:assess`, called not recomputed). Reissue after folding: `pnpm josh issue:fold "<title>" "<title>" \u2026` \u2014 `fold` means file one Issue covering them, `separate` means file them apart (separable findings whose combined size clears the split guide), and the default is `fold`. Add `--not-separable` when they are really one deliverable. The procedure is `.claude/skills/workflow-commands/split-assessment.md` \u2192 "The question". Every later filing is refused until the fold is on the transcript.';
|
|
1302
|
-
var ROW6 = {
|
|
1303
|
-
id: "issue-fold",
|
|
1304
|
-
is_trigger: bash_triggers.on_bash_command(bash_triggers.is_issue_filing),
|
|
1305
|
-
reason: ISSUE_FOLD_REASON,
|
|
1306
|
-
already_satisfied: already_folded,
|
|
1307
|
-
keeps: bash_triggers.on_bash_command(runs_the_fold)
|
|
1308
|
-
};
|
|
1309
|
-
var issue_fold_rule = { ISSUE_FOLD_REASON, ROW: ROW6, already_folded, runs_the_fold };
|
|
1310
|
-
|
|
1311
1337
|
// scripts/rules/josh-git-bare.ts
|
|
1312
1338
|
var GIT_COMMAND2 = /* @__PURE__ */ new Set(["git"]);
|
|
1313
1339
|
var CONFIRM_FLAGS = /* @__PURE__ */ new Set(["-y", "--yes"]);
|
|
@@ -1322,7 +1348,7 @@ function is_bare_josh_git(command) {
|
|
|
1322
1348
|
return shell_segments.segments_of(command).some((segment) => is_bare_segment(segment));
|
|
1323
1349
|
}
|
|
1324
1350
|
var JOSH_GIT_BARE_REASON = '\u26D4 bare `pnpm josh git`: this prompts to confirm the staging, and with no TTY the prompt falls to its cancel branch \u2014 `Checking unstaged files... Found` then `Operation cancelled.` \u2014 so the call throws away the time it takes to fail (about 31 seconds in one measured lane) and you reissue it with `-y` anyway (joshuafolkken/kit#2297). Run it unattended from the start: `pnpm josh git -y "<title> #<N>"`. The recovery form that opens the PR for a push that already landed is `pnpm josh git -y --skip-commit --skip-push`. This rule fires on every occurrence, not once per run.';
|
|
1325
|
-
var
|
|
1351
|
+
var ROW6 = {
|
|
1326
1352
|
id: "josh-git-bare",
|
|
1327
1353
|
is_trigger: bash_triggers.on_bash_command(is_bare_josh_git),
|
|
1328
1354
|
reason: JOSH_GIT_BARE_REASON,
|
|
@@ -1330,21 +1356,32 @@ var ROW7 = {
|
|
|
1330
1356
|
};
|
|
1331
1357
|
var josh_git_bare = {
|
|
1332
1358
|
JOSH_GIT_BARE_REASON,
|
|
1333
|
-
ROW:
|
|
1359
|
+
ROW: ROW6,
|
|
1334
1360
|
is_bare_josh_git
|
|
1335
1361
|
};
|
|
1336
1362
|
|
|
1337
1363
|
// scripts/rules/lane-carry-conflict.ts
|
|
1338
1364
|
var RUN_BUDGET_COMMANDS = /* @__PURE__ */ new Set(["run:merge", "run:carry"]);
|
|
1365
|
+
var LEADING_ASSIGNMENT = String.raw`[A-Za-z_]\w*=(?:"[^"]*"|'[^']*'|\$\((?:[^()]|\([^()]*\))*\)|[^\s"'])*\s+`;
|
|
1366
|
+
var REDIRECTED_PREFIX = new RegExp(
|
|
1367
|
+
String.raw`^(?:${LEADING_ASSIGNMENT})*${platform_temporary.TEMP_ROOT_KEY}=(?!""|''|\s|$|"?\$\{?[A-Za-z_])`,
|
|
1368
|
+
"u"
|
|
1369
|
+
);
|
|
1370
|
+
var SHARED_STATE_COMMANDS = /* @__PURE__ */ new Set(["run:merge"]);
|
|
1371
|
+
var LEADING_ASSIGNMENTS = new RegExp(`^(?:${LEADING_ASSIGNMENT})*`, "u");
|
|
1372
|
+
function is_budget_segment(segment) {
|
|
1373
|
+
const commands = REDIRECTED_PREFIX.test(segment) ? SHARED_STATE_COMMANDS : RUN_BUDGET_COMMANDS;
|
|
1374
|
+
return shell_segments.is_josh_command(segment.replace(LEADING_ASSIGNMENTS, ""), commands);
|
|
1375
|
+
}
|
|
1339
1376
|
function invokes_budget_command(command) {
|
|
1340
|
-
return shell_segments.segments_of(command).some((segment) =>
|
|
1377
|
+
return shell_segments.segments_of(command).some((segment) => is_budget_segment(segment));
|
|
1341
1378
|
}
|
|
1342
1379
|
function is_carry_conflict(command, is_lane_child = lane_child_marker.is_child_of(process.cwd())) {
|
|
1343
1380
|
if (!invokes_budget_command(command)) return false;
|
|
1344
1381
|
return is_lane_child;
|
|
1345
1382
|
}
|
|
1346
|
-
var LANE_CARRY_CONFLICT_REASON = '\u26D4 lane child carry conflict: this session is a dispatched lane child, and `pnpm josh run:merge` / `pnpm josh run:carry` are the parent backlogrun budget commands \u2014 a child must never run them. The live carry record here belongs to the parent that launched this child, not to a competing run: the parent holds the one run budget for the repository, and every lane shares the common git directory it is keyed on, so a live owner a lane child reads is always its parent (joshuafolkken/kit#2267, measured 2026-09-21 in backlogrun #2252 \u2014 a child read run:merge `busy` as a competitor and parked #2258 unimplemented). Do not run this command, and do not treat it as a conflict: no `needs-decision`, no `confirmation` Telegram, no question to a person \u2014 a dispatched child cannot ask, and there is nothing to decide. Continue implementing this Issue; the parent owns the budget and counts the outcome at the return. The procedure is `.claude/skills/workflow-commands/pre-gate-cut.md` and `backlogrun-progress.md` \u2192 "The hand-off". This rule fires on every occurrence, not once per run.';
|
|
1347
|
-
var
|
|
1383
|
+
var LANE_CARRY_CONFLICT_REASON = '\u26D4 lane child carry conflict: this session is a dispatched lane child, and `pnpm josh run:merge` / `pnpm josh run:carry` are the parent backlogrun budget commands \u2014 a child must never run them. The live carry record here belongs to the parent that launched this child, not to a competing run: the parent holds the one run budget for the repository, and every lane shares the common git directory it is keyed on, so a live owner a lane child reads is always its parent (joshuafolkken/kit#2267, measured 2026-09-21 in backlogrun #2252 \u2014 a child read run:merge `busy` as a competitor and parked #2258 unimplemented). Do not run this command, and do not treat it as a conflict: no `needs-decision`, no `confirmation` Telegram, no question to a person \u2014 a dispatched child cannot ask, and there is nothing to decide. Continue implementing this Issue; the parent owns the budget and counts the outcome at the return. The procedure is `.claude/skills/workflow-commands/pre-gate-cut.md` and `backlogrun-progress.md` \u2192 "The hand-off". Live evidence of `run:carry` is taken with a fresh `JOSH_TEMP_ROOT` prefixed to the call, which this rule lets through (joshuafolkken/kit#3458); `run:merge` is refused under any root, because it also syncs main, closes lanes and writes to GitHub. This rule fires on every occurrence, not once per run.';
|
|
1384
|
+
var ROW7 = {
|
|
1348
1385
|
id: "lane-carry-conflict",
|
|
1349
1386
|
is_trigger: bash_triggers.on_bash_command(is_carry_conflict),
|
|
1350
1387
|
reason: LANE_CARRY_CONFLICT_REASON,
|
|
@@ -1352,7 +1389,7 @@ var ROW8 = {
|
|
|
1352
1389
|
};
|
|
1353
1390
|
var lane_carry_conflict = {
|
|
1354
1391
|
LANE_CARRY_CONFLICT_REASON,
|
|
1355
|
-
ROW:
|
|
1392
|
+
ROW: ROW7,
|
|
1356
1393
|
invokes_budget_command,
|
|
1357
1394
|
is_carry_conflict
|
|
1358
1395
|
};
|
|
@@ -1405,13 +1442,13 @@ function is_interactive_ask(call, is_lane_child = lane_child_marker.is_child_of(
|
|
|
1405
1442
|
return is_lane_child;
|
|
1406
1443
|
}
|
|
1407
1444
|
var LANE_INTERACTIVE_ASK_REASON = '\u26D4 lane child interactive ask: this session is a dispatched lane child and cannot ask a person, so this call is refused. Left to run it would end the turn with nothing on the Issue \u2014 the parent then finds an OPEN Issue with `in-progress` and no question (joshuafolkken/kit#2201; joshuafolkken/kit#2034 placed the same rule one tool-call too late). Do not ask: park the decision instead. Apply `needs-decision` and post a comment carrying the question, the options and whether work was stashed \u2014 `gh api repos/{owner}/{repo}/issues/<N>/labels -f \'labels[]=needs-decision\'` then `pnpm josh issue:comment <N> --body-file <path>` \u2014 then send the `confirmation` Telegram and stop. The procedure is `.claude/skills/workflow-commands/pre-gate-cut.md` \u2192 "A lane child records its park before it stops", and the park itself is `backlogrun-park.md` \u2192 "park and continue". This rule fires on every occurrence, not once per run.';
|
|
1408
|
-
var
|
|
1445
|
+
var ROW8 = {
|
|
1409
1446
|
id: "lane-interactive-ask",
|
|
1410
1447
|
is_trigger: is_interactive_ask,
|
|
1411
1448
|
reason: LANE_INTERACTIVE_ASK_REASON,
|
|
1412
1449
|
decide: () => true
|
|
1413
1450
|
};
|
|
1414
|
-
var lane_interactive_ask = { LANE_INTERACTIVE_ASK_REASON, ROW:
|
|
1451
|
+
var lane_interactive_ask = { LANE_INTERACTIVE_ASK_REASON, ROW: ROW8, is_interactive_ask };
|
|
1415
1452
|
|
|
1416
1453
|
// scripts/rules/lane-split-park.ts
|
|
1417
1454
|
var EPIC_COMMANDS = /* @__PURE__ */ new Set(["epic"]);
|
|
@@ -1461,7 +1498,7 @@ function decide3(_call, run2) {
|
|
|
1461
1498
|
return issue !== void 0 && promoted_issues(commands).has(issue);
|
|
1462
1499
|
}
|
|
1463
1500
|
var LANE_SPLIT_PARK_REASON = '\u26D4 lane split park: this session is a dispatched lane child that promoted its own Issue to an epic this run, and a split is not a park \u2014 do not apply `needs-decision` to the promoted epic and do not send a `confirmation` Telegram. The parent reads an open Issue carrying `epic` as a split and continues through its children; a question here has nobody to answer it (joshuafolkken/kit#3296, measured 2026-10-06 when the child for #3255 parked its promoted epic). If what remains of the original work needs a person, park that child issue instead, then end the turn. The procedure is `.claude/skills/workflow-commands/backlogrun-park.md` \u2192 "Splitting a child mid-run". This rule fires on every occurrence, not once per run.';
|
|
1464
|
-
var
|
|
1501
|
+
var ROW9 = {
|
|
1465
1502
|
id: "lane-split-park",
|
|
1466
1503
|
is_trigger: bash_triggers.on_bash_command(is_candidate),
|
|
1467
1504
|
reason: LANE_SPLIT_PARK_REASON,
|
|
@@ -1469,7 +1506,7 @@ var ROW10 = {
|
|
|
1469
1506
|
};
|
|
1470
1507
|
var lane_split_park = {
|
|
1471
1508
|
LANE_SPLIT_PARK_REASON,
|
|
1472
|
-
ROW:
|
|
1509
|
+
ROW: ROW9,
|
|
1473
1510
|
promoted_issues
|
|
1474
1511
|
};
|
|
1475
1512
|
|
|
@@ -1501,8 +1538,8 @@ function is_switch_away_from_lane(command, is_lane_child = lane_child_marker.is_
|
|
|
1501
1538
|
if (!is_lane_child || own_branch === void 0) return false;
|
|
1502
1539
|
return switch_targets(command).some((target) => target !== own_branch);
|
|
1503
1540
|
}
|
|
1504
|
-
var LANE_SWITCH_MAIN_REASON = "\u26D4 lane child on `git switch main`: this session is a dispatched lane child, and switching to the default branch here always fails \u2014 a lane is a linked work tree, the primary checkout holds the default branch, and git allows one branch in one work tree at a time (`fatal: main is already used by worktree at <the primary checkout>`, measured 11 times in the 2026-09-21 backlogrun). Do not switch: the lane is already on its own issue branch, branched from a fresh default before it opened, and the latest default is brought in during the gate by `pnpm josh main:merge`. So skip this step and keep implementing on the current branch \u2014 no `git switch`, no `git pull`. `pnpm josh main:sync` (`josh ms`) is refused in a lane for the same reason, and a lane is finished with `pnpm josh lane:close <issue-number>`. The parent runs `
|
|
1505
|
-
var
|
|
1541
|
+
var LANE_SWITCH_MAIN_REASON = "\u26D4 lane child on `git switch main`: this session is a dispatched lane child, and switching to the default branch here always fails \u2014 a lane is a linked work tree, the primary checkout holds the default branch, and git allows one branch in one work tree at a time (`fatal: main is already used by worktree at <the primary checkout>`, measured 11 times in the 2026-09-21 backlogrun). Do not switch: the lane is already on its own issue branch, branched from a fresh default before it opened, and the latest default is brought in during the gate by `pnpm josh main:merge`. So skip this step and keep implementing on the current branch \u2014 no `git switch`, no `git pull`. `pnpm josh main:sync` (`josh ms`) is refused in a lane for the same reason, and a lane is finished with `pnpm josh lane:close <issue-number>`. The parent runs `pnpm josh ms` in the primary checkout before each lane opens, never the child \u2014 `backlogrun-lanes.md` and `backlogrun-child.md` are the single sources. This rule fires on every occurrence, not once per run.";
|
|
1542
|
+
var ROW10 = {
|
|
1506
1543
|
id: "lane-switch-main",
|
|
1507
1544
|
is_trigger: bash_triggers.on_bash_command(is_switch_away_from_lane),
|
|
1508
1545
|
reason: LANE_SWITCH_MAIN_REASON,
|
|
@@ -1510,7 +1547,7 @@ var ROW11 = {
|
|
|
1510
1547
|
};
|
|
1511
1548
|
var lane_switch_main = {
|
|
1512
1549
|
LANE_SWITCH_MAIN_REASON,
|
|
1513
|
-
ROW:
|
|
1550
|
+
ROW: ROW10,
|
|
1514
1551
|
is_switch_away_from_lane,
|
|
1515
1552
|
switch_target,
|
|
1516
1553
|
switch_targets
|
|
@@ -1693,12 +1730,12 @@ function next_commands(command) {
|
|
|
1693
1730
|
return COMMANDS.slice(COMMANDS.indexOf(command) + 1);
|
|
1694
1731
|
}
|
|
1695
1732
|
function next_line(command, issue) {
|
|
1696
|
-
const commands = next_commands(command).map((next) => `${next}
|
|
1733
|
+
const commands = next_commands(command).map((next) => `${next} ${issue_cite.plain(issue)}`);
|
|
1697
1734
|
return `${NEXT_PREFIX}${commands.join(NEXT_SEPARATOR)}`;
|
|
1698
1735
|
}
|
|
1699
1736
|
function format_decision(issue, decision) {
|
|
1700
1737
|
const fields = [`at: ${decision.state}`, `to: ${decision.command}`, `start: ${decision.start}`];
|
|
1701
|
-
return `stage
|
|
1738
|
+
return `stage ${issue_cite.plain(issue)} \u2014 ${fields.join(" \xB7 ")}`;
|
|
1702
1739
|
}
|
|
1703
1740
|
function cell(state, command) {
|
|
1704
1741
|
const decision = decide4(state, command);
|
|
@@ -1838,7 +1875,7 @@ var DECISION_ORACLES = [
|
|
|
1838
1875
|
name: "issue:fold",
|
|
1839
1876
|
decision: "Whether findings filed from one session fold into one issue or stay separate",
|
|
1840
1877
|
args: "<title...>",
|
|
1841
|
-
vocabulary: ["fold", "separate", "no-fold-needed"],
|
|
1878
|
+
vocabulary: ["fold", "separate", "no-fold-needed", "undetermined"],
|
|
1842
1879
|
single_source: SPLIT_ASSESSMENT_QUESTION
|
|
1843
1880
|
},
|
|
1844
1881
|
{
|
|
@@ -1960,10 +1997,7 @@ var NOT_NAMED = /* @__PURE__ */ new Map([
|
|
|
1960
1997
|
["epic:bundle", FILING_STEP_REASON],
|
|
1961
1998
|
["issue:scout", FILING_STEP_REASON],
|
|
1962
1999
|
["issue:lint", FILING_STEP_REASON],
|
|
1963
|
-
[
|
|
1964
|
-
"issue:fold",
|
|
1965
|
-
"the second filing it governs is already gated by the `issue-fold` delivered rule"
|
|
1966
|
-
],
|
|
2000
|
+
["issue:fold", "`issue:file` asks the fold question itself on the second filing it governs"],
|
|
1967
2001
|
["cases", READ],
|
|
1968
2002
|
["issue:state", READ],
|
|
1969
2003
|
["run:cut:resume", SELF],
|
|
@@ -2083,13 +2117,13 @@ function is_destructive_command(command) {
|
|
|
2083
2117
|
return shell_segments.segments_of(command).some((segment) => is_destructive_segment2(segment));
|
|
2084
2118
|
}
|
|
2085
2119
|
var DESTRUCTIVE_COMMAND_REASON = "\u26D4 destructive command: a recursive forced `rm` (`rm -rf`, `rm -fr`, `rm -r -f`, `rm --recursive --force`), `gh repo delete` / `archive`, `gh repo edit --visibility`, `gh pr close`, or a `gh api -X DELETE repos/\u2026` call deletes or closes something that cannot be restored, which is Tier C and needs explicit current-turn user instruction (`prompts/collaboration-workflow/operating-rules.md`). The `.claude/settings.json` deny list matches prefix globs, so it misses these spellings; this row reads the argv instead. Remove a file or directory one path at a time without `-f`, or ask the user to run the command in their own terminal. `gh issue close` and removing a label from an Issue (`DELETE repos/<o>/<r>/issues/<N>/labels/<name>`) are not refused. **This rule fires on every occurrence, not once per run.**";
|
|
2086
|
-
var
|
|
2120
|
+
var ROW11 = {
|
|
2087
2121
|
id: "destructive-command",
|
|
2088
2122
|
is_trigger: bash_triggers.on_bash_command(is_destructive_command),
|
|
2089
2123
|
reason: DESTRUCTIVE_COMMAND_REASON,
|
|
2090
2124
|
decide: () => true
|
|
2091
2125
|
};
|
|
2092
|
-
var destructive_command = { DESTRUCTIVE_COMMAND_REASON, ROW:
|
|
2126
|
+
var destructive_command = { DESTRUCTIVE_COMMAND_REASON, ROW: ROW11, is_destructive_command };
|
|
2093
2127
|
|
|
2094
2128
|
// scripts/rules/direct-pr-create.ts
|
|
2095
2129
|
var GH_COMMAND2 = "gh";
|
|
@@ -2144,13 +2178,13 @@ function is_direct_pr_create(command) {
|
|
|
2144
2178
|
return shell_segments.segments_of(command).some((segment) => is_pr_create_segment(segment));
|
|
2145
2179
|
}
|
|
2146
2180
|
var DIRECT_PR_CREATE_REASON = "\u26D4 direct PR creation: `gh pr create` (or a `gh api` POST to `repos/<o>/<r>/pulls`) bypasses `build_body`, which writes the `closes #N` line \u2014 the Issue would stay open after the merge (`CLAUDE.md` \u2192 Git Rules). Open the PR with `pnpm josh pr` instead; after a failed push, fix, push, then run `pnpm josh pr`. **This rule fires on every occurrence, not once per run.**";
|
|
2147
|
-
var
|
|
2181
|
+
var ROW12 = {
|
|
2148
2182
|
id: "direct-pr-create",
|
|
2149
2183
|
is_trigger: bash_triggers.on_bash_command(is_direct_pr_create),
|
|
2150
2184
|
reason: DIRECT_PR_CREATE_REASON,
|
|
2151
2185
|
decide: () => true
|
|
2152
2186
|
};
|
|
2153
|
-
var direct_pr_create = { DIRECT_PR_CREATE_REASON, ROW:
|
|
2187
|
+
var direct_pr_create = { DIRECT_PR_CREATE_REASON, ROW: ROW12, is_direct_pr_create };
|
|
2154
2188
|
|
|
2155
2189
|
// scripts/rules/worktree-guard.ts
|
|
2156
2190
|
var CHECKOUT_SUBCOMMAND = "checkout";
|
|
@@ -2211,15 +2245,15 @@ function is_unauthorized_segment(segment) {
|
|
|
2211
2245
|
function is_unauthorized_worktree_change(command) {
|
|
2212
2246
|
return shell_segments.segments_of(command).some((segment) => is_unauthorized_segment(segment));
|
|
2213
2247
|
}
|
|
2214
|
-
var WORKTREE_MUTATION_REASON = '\u26D4 unauthorized working-tree change: `git checkout -- <path>`, `git restore <path>`, a forced `git clean` and an unauthorized `git stash` discard work or mutate the repository-wide stash every work tree shares, and none is on the `.claude/settings.json` deny list (`operating-rules.md`). Do not run them on your own judgement. A commit goes through `pnpm josh git`; a stash pop goes through `pnpm josh stash:pop "<message>"`, never a positional `git stash pop` a shared stack lets another lane divert. A stash push is authorized only inside a documented flow and only with a findable message \u2014 `git stash push -u -m "<message>"` \u2014 which this row allows; a bare `git stash`, a message-less push, or `pop` / `apply` / `drop` is refused. **This rule fires on every occurrence, not once per run.**';
|
|
2215
|
-
var
|
|
2248
|
+
var WORKTREE_MUTATION_REASON = '\u26D4 unauthorized working-tree change: `git checkout -- <path>`, `git restore <path>`, a forced `git clean` and an unauthorized `git stash` discard work or mutate the repository-wide stash every work tree shares, and none is on the `.claude/settings.json` deny list (`operating-rules.md`). Do not run them on your own judgement. A commit goes through `pnpm josh git`; a stash pop goes through `pnpm josh stash:pop "<message>"`, never a positional `git stash pop` a shared stack lets another lane divert. A stash push is authorized only inside a documented flow and only with a findable message \u2014 `git stash push -u -m "<message>"` \u2014 which this row allows; a bare `git stash`, a message-less push, or `pop` / `apply` / `drop` is refused. A plan that restores a handed-over stash with `git stash apply` / `git stash pop` is read as `pnpm josh stash:pop "<message>"`: apply it that way, continue, and record the substitution on the Issue \u2014 Tier A, never a `needs-decision` park unless the plan says why the owner keeps the stash: then stop and confirm (`operating-rules.md` \u2192 "no-self-staging"). **This rule fires on every occurrence, not once per run.**';
|
|
2249
|
+
var ROW13 = {
|
|
2216
2250
|
id: "worktree-mutation",
|
|
2217
2251
|
is_trigger: bash_triggers.on_bash_command(is_unauthorized_worktree_change),
|
|
2218
2252
|
reason: WORKTREE_MUTATION_REASON,
|
|
2219
2253
|
decide: () => true
|
|
2220
2254
|
};
|
|
2221
2255
|
var worktree_guard = {
|
|
2222
|
-
ROW:
|
|
2256
|
+
ROW: ROW13,
|
|
2223
2257
|
WORKTREE_MUTATION_REASON,
|
|
2224
2258
|
is_unauthorized_worktree_change,
|
|
2225
2259
|
touches_worktree
|
|
@@ -2248,13 +2282,13 @@ function is_index_mutation(command) {
|
|
|
2248
2282
|
return shell_segments.segments_of(command).some((segment) => is_index_segment(segment));
|
|
2249
2283
|
}
|
|
2250
2284
|
var INDEX_MUTATION_REASON = '\u26D4 git index mutation: `git add` / `stage` / `commit` / `reset` / `rm` / `mv` and `git restore --staged` overwrite the user\'s staged snapshot, which `CLAUDE.md` \u2192 Git Rules forbids on your own judgement (`prompts/collaboration-workflow/operating-rules.md` \u2192 "no-self-staging"). The `.claude/settings.json` deny list matches prefix globs, so it misses `git -C . commit`, `git -c k=v commit` and `env git commit`; this row reads the argv instead, so the spelling does not matter. A commit goes through `pnpm josh git -y`; any other staging needs explicit current-turn user instruction, run by the user in their own terminal. **This rule fires on every occurrence, not once per run.**';
|
|
2251
|
-
var
|
|
2285
|
+
var ROW14 = {
|
|
2252
2286
|
id: "index-mutation",
|
|
2253
2287
|
is_trigger: bash_triggers.on_bash_command(is_index_mutation),
|
|
2254
2288
|
reason: INDEX_MUTATION_REASON,
|
|
2255
2289
|
decide: () => true
|
|
2256
2290
|
};
|
|
2257
|
-
var index_guard = { INDEX_MUTATION_REASON, ROW:
|
|
2291
|
+
var index_guard = { INDEX_MUTATION_REASON, ROW: ROW14, is_index_mutation };
|
|
2258
2292
|
|
|
2259
2293
|
// scripts/rules/protected-files.ts
|
|
2260
2294
|
import path5 from "node:path";
|
|
@@ -2382,7 +2416,9 @@ var doctor_consumer = {
|
|
|
2382
2416
|
// scripts/rules/protected-files.ts
|
|
2383
2417
|
var READ_TOOL = "Read";
|
|
2384
2418
|
var EDIT_TOOLS2 = /* @__PURE__ */ new Set(["Edit", "Write"]);
|
|
2385
|
-
var
|
|
2419
|
+
var SECRET_FILES = /* @__PURE__ */ new Set([".env", ".dev.vars"]);
|
|
2420
|
+
var ENVIRONMENT_VARIANT_PREFIX = ".env.";
|
|
2421
|
+
var TRACKED_VARIANTS = /* @__PURE__ */ new Set([".env.example", ".env.test"]);
|
|
2386
2422
|
var SETTINGS_FILE = path5.join(".claude", "settings.json");
|
|
2387
2423
|
var WHITESPACE3 = /\s+/u;
|
|
2388
2424
|
var TOKEN_QUOTES = /["']/gu;
|
|
@@ -2413,7 +2449,9 @@ function file_path_of(call) {
|
|
|
2413
2449
|
return typeof value === "string" ? value : "";
|
|
2414
2450
|
}
|
|
2415
2451
|
function is_environment_path(token) {
|
|
2416
|
-
|
|
2452
|
+
const name = path5.basename(token.replaceAll(TOKEN_QUOTES, ""));
|
|
2453
|
+
if (TRACKED_VARIANTS.has(name)) return false;
|
|
2454
|
+
return SECRET_FILES.has(name) || name.startsWith(ENVIRONMENT_VARIANT_PREFIX);
|
|
2417
2455
|
}
|
|
2418
2456
|
function is_environment_read_segment(segment) {
|
|
2419
2457
|
const words = segment.replaceAll(INPUT_REDIRECT, " < ").split(WHITESPACE3).filter((word) => word !== "");
|
|
@@ -2439,14 +2477,14 @@ function is_consumer_settings_edit(call, is_kit_consumer2) {
|
|
|
2439
2477
|
function is_protected_file_call(call, is_kit_consumer2 = doctor_consumer.is_kit_consumer) {
|
|
2440
2478
|
return is_environment_read(call) || is_consumer_settings_edit(call, is_kit_consumer2);
|
|
2441
2479
|
}
|
|
2442
|
-
var PROTECTED_FILE_REASON = '\u26D4 protected file: `.env` holds the Telegram bot token, so reading
|
|
2443
|
-
var
|
|
2480
|
+
var PROTECTED_FILE_REASON = '\u26D4 protected file: `.env` holds the Telegram bot token, and a `.env.*` variant or `.dev.vars` holds the same kind of secret, so reading one \u2014 with the Read tool or a shell reader such as `cat` / `grep` / `source` \u2014 puts a secret in the transcript \u2014 the scripts that need it load it in their own process (the tracked `.env.example` and `.env.test` stay readable). `.claude/settings.json` in a consumer repository is the deny list and the hooks every other rule rests on, so a run must not rewrite it; `josh sync` owns it, and a change belongs upstream in kit (`CLAUDE.md` \u2192 "Route distributed-doc / config changes upstream to kit"). Leave these files alone, or ask the user. **This rule fires on every occurrence, not once per run.**';
|
|
2481
|
+
var ROW15 = {
|
|
2444
2482
|
id: "protected-file",
|
|
2445
2483
|
is_trigger: is_protected_file_call,
|
|
2446
2484
|
reason: PROTECTED_FILE_REASON,
|
|
2447
2485
|
decide: () => true
|
|
2448
2486
|
};
|
|
2449
|
-
var protected_files = { ROW:
|
|
2487
|
+
var protected_files = { ROW: ROW15, is_protected_file_call };
|
|
2450
2488
|
|
|
2451
2489
|
// scripts/rules/permission-guards.ts
|
|
2452
2490
|
var ROWS2 = [
|
|
@@ -2482,8 +2520,11 @@ function is_masked_verification(command) {
|
|
|
2482
2520
|
return time_shell.discarded_commands(command).some((segment) => is_verification_command(segment));
|
|
2483
2521
|
}
|
|
2484
2522
|
var PIPED_VERIFICATION_REASON = "\u26D4 piped verification: a pipeline exits with its last command's status, so `pnpm josh gate | tail` reports success on a gate that failed, and the verdict is discarded before anything reads it. Run the check without the pipe \u2014 josh prints its verdict line last, so the harness output cap keeps it even when the middle is elided. Where the output genuinely has to be narrowed, redirect it to a file and read ranges from that file, or prefix `set -o pipefail` so the pipeline carries the check's status. Read the printed verdict either way, never the exit code alone. Read-only listings are untouched \u2014 this fires only on a command whose result means pass or fail. The rule is in `prompts/collaboration-workflow/output-bounds.md`. Reissue this call with no pipe \u2014 it fires once per run and cannot repeat on the call in hand.";
|
|
2523
|
+
function pipelines_of(command) {
|
|
2524
|
+
return shell_segments.segments_of(time_shell.unquoted(command)).map((segment) => segment.split("|").map((piece) => piece.trim()));
|
|
2525
|
+
}
|
|
2485
2526
|
function command_pieces(command) {
|
|
2486
|
-
return
|
|
2527
|
+
return pipelines_of(command).flat();
|
|
2487
2528
|
}
|
|
2488
2529
|
function runs_verification(command) {
|
|
2489
2530
|
return command_pieces(command).some((piece) => is_verification_command(piece));
|
|
@@ -2491,11 +2532,38 @@ function runs_verification(command) {
|
|
|
2491
2532
|
function keeps_verdict_intact(command) {
|
|
2492
2533
|
return runs_verification(command) && !is_masked_verification(command);
|
|
2493
2534
|
}
|
|
2535
|
+
var PIPEFAIL_PREFIX = "set -o pipefail; ";
|
|
2536
|
+
var FULL_READING_FILTER = /^(?:tail|grep)\b/u;
|
|
2537
|
+
var EARLY_EXIT_GREP = /^grep\b.*\s(?:-[a-zA-Z]*[lLmq]|--(?:quiet|silent|max-count|files-with(?:out)?-match))/u;
|
|
2538
|
+
var ALLOWED_OPERATORS = /2>&1|&&/gu;
|
|
2539
|
+
var SIDE_EFFECT_SYNTAX = /[&<>`]|\$\(/u;
|
|
2540
|
+
var PIPEFAIL_NOTE = "\u21BB piped verification: the josh check was piped, so `set -o pipefail;` was prefixed and the call ran with the check's status carried to the exit code. Read the printed verdict, never the exit code alone \u2014 `prompts/collaboration-workflow/output-bounds.md` (joshuafolkken/kit#3570).";
|
|
2541
|
+
function reads_to_the_end(piece) {
|
|
2542
|
+
return FULL_READING_FILTER.test(piece) && !EARLY_EXIT_GREP.test(piece);
|
|
2543
|
+
}
|
|
2544
|
+
function is_filtered_check(pipeline) {
|
|
2545
|
+
const [head = "", ...filters] = pipeline;
|
|
2546
|
+
return is_verification_command(head) && filters.every((piece) => reads_to_the_end(piece));
|
|
2547
|
+
}
|
|
2548
|
+
function has_side_effect_syntax(command) {
|
|
2549
|
+
return SIDE_EFFECT_SYNTAX.test(command.replaceAll(ALLOWED_OPERATORS, " "));
|
|
2550
|
+
}
|
|
2551
|
+
function is_pipefail_rewritable(command) {
|
|
2552
|
+
return is_masked_verification(command) && !has_side_effect_syntax(command) && pipelines_of(command).every((pipeline) => is_filtered_check(pipeline));
|
|
2553
|
+
}
|
|
2554
|
+
function pipefail_input(call) {
|
|
2555
|
+
if (call.name !== cost_blocks.BASH_TOOL || !json_value.is_record(call.input)) return void 0;
|
|
2556
|
+
const command = time_shell.bash_command(call.input);
|
|
2557
|
+
if (!is_pipefail_rewritable(command)) return void 0;
|
|
2558
|
+
return { ...call.input, command: `${PIPEFAIL_PREFIX}${command}` };
|
|
2559
|
+
}
|
|
2494
2560
|
var piped_verification = {
|
|
2495
2561
|
PIPED_VERIFICATION_REASON,
|
|
2562
|
+
PIPEFAIL_NOTE,
|
|
2496
2563
|
VERIFICATION_COMMANDS,
|
|
2497
2564
|
is_masked_verification,
|
|
2498
2565
|
keeps_verdict_intact,
|
|
2566
|
+
pipefail_input,
|
|
2499
2567
|
runs_verification
|
|
2500
2568
|
};
|
|
2501
2569
|
|
|
@@ -2525,7 +2593,7 @@ function is_poll_loop(command) {
|
|
|
2525
2593
|
return LOOP_KEYWORD2.test(plain) && SLEEP_COMMAND.test(plain);
|
|
2526
2594
|
}
|
|
2527
2595
|
var POLL_LOOP_REASON = '\u26D4 output poll loop: this hand-writes a `while`/`until` wait loop over a command\'s output, a marker file or a process \u2014 with a `sleep` or, worse, without one \u2014 and the loop does not know when the command finished. A regex that never matches waits to the harness block limit; one that matches a mid-run line exits too early \u2014 either way the command exit is not what ends the wait, and each pass spends a full-context round trip (joshuafolkken/kit#2371 measured about 45 minutes, 13% of six lanes, lost to exactly this). Do not poll the output file. A command known to take minutes \u2014 `pnpm josh gate`, `pnpm josh followup`, `pnpm josh format` \u2014 is started detached from the first with `run_in_background` set, and the harness re-invokes you when it exits: its completion notification is what ends the wait, on the task exit rather than a regex or the block limit. So issue the long command in the background and end the turn \u2014 do not arm a loop; the wake-up brings you back. To glance at interim output, `Read` the output file once, never in a sleep loop. If you are waiting on CI, `pnpm josh followup` waits on it for you. The procedure is `.claude/skills/workflow-commands/background-commands.md`, "A command that can take minutes is issued in the background". **This rule fires on every occurrence, not once per run.**';
|
|
2528
|
-
var
|
|
2596
|
+
var ROW16 = {
|
|
2529
2597
|
id: "poll-loop",
|
|
2530
2598
|
is_trigger: bash_triggers.on_bash_command(is_poll_loop),
|
|
2531
2599
|
reason: POLL_LOOP_REASON,
|
|
@@ -2533,7 +2601,7 @@ var ROW17 = {
|
|
|
2533
2601
|
};
|
|
2534
2602
|
var poll_loop = {
|
|
2535
2603
|
POLL_LOOP_REASON,
|
|
2536
|
-
ROW:
|
|
2604
|
+
ROW: ROW16,
|
|
2537
2605
|
is_poll_loop
|
|
2538
2606
|
};
|
|
2539
2607
|
|
|
@@ -2565,13 +2633,17 @@ function current_state2() {
|
|
|
2565
2633
|
directory: process.cwd(),
|
|
2566
2634
|
carried: run_cut.carried_cut_sync,
|
|
2567
2635
|
marked_issue: lane_child_marker.marked_issue(),
|
|
2636
|
+
is_reviewer: agent_session_role.is_reviewer(),
|
|
2568
2637
|
context_verdict: cost_cli.session_verdict
|
|
2569
2638
|
};
|
|
2570
2639
|
}
|
|
2640
|
+
function dispatched_issue(state) {
|
|
2641
|
+
return state.is_reviewer ? void 0 : state.marked_issue;
|
|
2642
|
+
}
|
|
2571
2643
|
function uncut_lane_issue(state) {
|
|
2572
2644
|
const issue = lane_paths.lane_issue_of(state.directory);
|
|
2573
2645
|
if (issue === void 0) return void 0;
|
|
2574
|
-
if (state
|
|
2646
|
+
if (dispatched_issue(state) !== issue) return void 0;
|
|
2575
2647
|
return state.carried()?.issue === issue ? void 0 : issue;
|
|
2576
2648
|
}
|
|
2577
2649
|
function warrants_the_cut2(verdict) {
|
|
@@ -2603,13 +2675,13 @@ function posts_at_path_literally(command) {
|
|
|
2603
2675
|
return RAW_FIELD_BODY_AT.test(command);
|
|
2604
2676
|
}
|
|
2605
2677
|
var RAW_FIELD_BODY_REASON = "\u26D4 literal @path body: this passes `body=@<path>` to `gh api` with a raw field flag (`-f` / `--raw-field`), which sends the value verbatim \u2014 the string `@<path>` is posted as the comment, not the file it points at. `-F` / `--field` is the flag that reads the file, and the two spellings differ by one character while `gh` exits 0 and returns a comment URL either way, so the break is invisible until a person reads the issue (joshuafolkken/kit#2304 lost two park comments this way). Post an issue or PR comment with `pnpm josh issue:comment <N> --body-file <path>` \u2014 the one spelling, which cannot take the wrong flag. The rule and the safe forms are in `prompts/collaboration-workflow/shell-body.md`. This rule fires on every occurrence, not once per run.";
|
|
2606
|
-
var
|
|
2678
|
+
var ROW17 = {
|
|
2607
2679
|
id: "raw-field-body",
|
|
2608
2680
|
is_trigger: bash_triggers.on_bash_command(posts_at_path_literally),
|
|
2609
2681
|
reason: RAW_FIELD_BODY_REASON,
|
|
2610
2682
|
decide: () => true
|
|
2611
2683
|
};
|
|
2612
|
-
var raw_field_body = { RAW_FIELD_BODY_REASON, ROW:
|
|
2684
|
+
var raw_field_body = { RAW_FIELD_BODY_REASON, ROW: ROW17, posts_at_path_literally };
|
|
2613
2685
|
|
|
2614
2686
|
// scripts/rules/rule-body-guard.ts
|
|
2615
2687
|
var EDIT_TOOL = "Edit";
|
|
@@ -2680,7 +2752,7 @@ function runs_placement_oracle(command) {
|
|
|
2680
2752
|
(names) => shell_segments.segments_of(command).some((segment) => shell_segments.is_josh_command(segment, names))
|
|
2681
2753
|
);
|
|
2682
2754
|
}
|
|
2683
|
-
var
|
|
2755
|
+
var ROW18 = {
|
|
2684
2756
|
id: "rule-body",
|
|
2685
2757
|
is_trigger: writes_rule_prose,
|
|
2686
2758
|
reason: RULE_BODY_REASON,
|
|
@@ -2689,7 +2761,7 @@ var ROW19 = {
|
|
|
2689
2761
|
};
|
|
2690
2762
|
var rule_body_guard = {
|
|
2691
2763
|
RULE_BODY_REASON,
|
|
2692
|
-
ROW:
|
|
2764
|
+
ROW: ROW18,
|
|
2693
2765
|
answered_placement,
|
|
2694
2766
|
is_rule_document,
|
|
2695
2767
|
writes_rule_prose
|
|
@@ -2925,6 +2997,9 @@ function project_root(directory) {
|
|
|
2925
2997
|
(candidate) => existsSync4(path7.join(candidate, PACKAGE_JSON))
|
|
2926
2998
|
) ?? directory;
|
|
2927
2999
|
}
|
|
3000
|
+
function is_kit_repository(directory) {
|
|
3001
|
+
return !doctor_consumer.is_kit_consumer(project_root(directory));
|
|
3002
|
+
}
|
|
2928
3003
|
function is_ignored(entry) {
|
|
2929
3004
|
return entry.split(/[/\\]/u).some((part) => IGNORED_DIRS.has(part));
|
|
2930
3005
|
}
|
|
@@ -2998,6 +3073,7 @@ var project_checks = {
|
|
|
2998
3073
|
has_config,
|
|
2999
3074
|
has_files,
|
|
3000
3075
|
is_basic,
|
|
3076
|
+
is_kit_repository,
|
|
3001
3077
|
prettier_skip_reason,
|
|
3002
3078
|
project_root,
|
|
3003
3079
|
skip_notice,
|
|
@@ -3121,8 +3197,8 @@ function is_untested_commit(call) {
|
|
|
3121
3197
|
return test_declared_changed.current_verdict() === "required";
|
|
3122
3198
|
}
|
|
3123
3199
|
var REASON = '\u26D4 test declared: this commits a runtime code change with no test beside it \u2014 `pnpm josh test:declared` reads the working tree as `required` (a changed file that is neither a test \u2014 `*.test.ts` / `*.e2e.ts` \u2014 nor a mechanically-exempt non-runtime path). `CLAUDE.md` \u2192 Code Change Rules requires a test for ALL code changes: a bug fix gets a regression test, a refactor gets tests pinning behavior first, logic gets a unit test, an observable UI/timing change gets an E2E. Add the declared test and reissue this commit. **If the change genuinely touches no executable runtime path** it is the pre-approved non-runtime exception \u2014 declare it in your Step 0 work summary with the reason it is exempt (non-executable config, a cosmetic asset swap) and reissue; the exception is a presentation, not a stop. Run `pnpm josh test:declared` to see the files it names. The procedure is `prompts/collaboration-workflow/rule-delivery.md` \u2192 "\u914D\u9001\u3055\u308C\u3066\u3044\u308B\u898F\u5247". This fires once per run, so reissuing will not repeat on the call in hand.';
|
|
3124
|
-
var
|
|
3125
|
-
var test_declared_commit = { REASON, ROW:
|
|
3200
|
+
var ROW19 = { id: "test-declared", is_trigger: is_untested_commit, reason: REASON };
|
|
3201
|
+
var test_declared_commit = { REASON, ROW: ROW19 };
|
|
3126
3202
|
|
|
3127
3203
|
// scripts/rules/third-party-write.ts
|
|
3128
3204
|
function is_third_party_write_segment(segment, session_owner, resolve_placeholder_owners) {
|
|
@@ -3160,67 +3236,30 @@ function writes_third_party(command, resolve_owner = repo_party.current_owner, r
|
|
|
3160
3236
|
);
|
|
3161
3237
|
}
|
|
3162
3238
|
var THIRD_PARTY_WRITE_REASON = '\u26D4 third-party write: this `gh api` call writes to a repository whose owner is not this session \u2014 a tracker we do not own is Tier C, and every write there (Issue, comment, PR, Discussion, review) needs explicit current-turn user instruction; typing the target, or holding a correct diagnosis, is not that instruction (`CLAUDE.md` \u2192 "Third-party repositories are Tier C", `prompts/collaboration-workflow/upstream-interrupt.md`). Confirm the party with `pnpm josh repo:party <owner/repo>` \u2014 owner equality, computed not judged. A read (`-X GET`, or no field flag) passes untouched; only a write (`-f`/`-F`/`--field`/`--raw-field`/`--input`, or `-X POST|PATCH|PUT|DELETE`) is refused. Record the finding on our own Issue and draft the artifact for a person to post \u2014 do not publish it yourself. **This rule fires on every occurrence, not once per run.**';
|
|
3163
|
-
var
|
|
3239
|
+
var ROW20 = {
|
|
3164
3240
|
id: "third-party-write",
|
|
3165
3241
|
is_trigger: bash_triggers.on_bash_command((command) => writes_third_party(command)),
|
|
3166
3242
|
reason: THIRD_PARTY_WRITE_REASON,
|
|
3167
3243
|
decide: () => true
|
|
3168
3244
|
};
|
|
3169
3245
|
var third_party_write = {
|
|
3170
|
-
ROW:
|
|
3246
|
+
ROW: ROW20,
|
|
3171
3247
|
THIRD_PARTY_WRITE_REASON,
|
|
3172
3248
|
writes_third_party
|
|
3173
3249
|
};
|
|
3174
3250
|
|
|
3175
|
-
// scripts/rules/wip-cap.ts
|
|
3176
|
-
var WIP_CAP = 30;
|
|
3177
|
-
var WIP_CAP_REASON = `\u26D4 backlog WIP cap: \`pnpm josh issue:file\` counts the target repository's open Issues before filing. With more than ${String(WIP_CAP)} open, close one first; nothing honestly closable means do not file \u2014 the command holds such a filing. Two filings are exempt and proceed while stating the overage \u2014 one the run is blocked by (\`--over-cap\`, or the \`tier-a\` / \`split\` route), and an interrupt (\`--route interrupt\`), decided by three tests rather than judgement: a verification answers wrongly, a documented workflow cannot complete, or data is lost or written outside the repository. Meeting none of the three, the finding is discretionary and waits. Both procedures are in \`prompts/collaboration-workflow/wip-cap.md\`. Reissue this call and let the command count \u2014 it fires once per run and cannot repeat on the call in hand.`;
|
|
3178
|
-
var ISSUE_LISTING = /^gh\s+(?:-{1,2}[\w-]+(?:[= ]\S+)?\s+)*issue\s+list\b/u;
|
|
3179
|
-
var ISSUES_QUERY = /repos\/[^\s'"]*\/issues\?[^\s'"]*state=open/u;
|
|
3180
|
-
var OPEN_STATE = /--state[= ]open|state=open/u;
|
|
3181
|
-
var LABEL_FILTER = /--label\b|[?&]labels=/u;
|
|
3182
|
-
function counts_open_issues(command) {
|
|
3183
|
-
return shell_segments.segments_of(command).some((segment) => {
|
|
3184
|
-
if (LABEL_FILTER.test(segment)) return false;
|
|
3185
|
-
return ISSUE_LISTING.test(segment) && OPEN_STATE.test(segment) || ISSUES_QUERY.test(segment);
|
|
3186
|
-
});
|
|
3187
|
-
}
|
|
3188
|
-
var ROW22 = {
|
|
3189
|
-
id: "wip-cap",
|
|
3190
|
-
is_trigger: bash_triggers.on_bash_command(bash_triggers.is_issue_filing),
|
|
3191
|
-
reason: WIP_CAP_REASON,
|
|
3192
|
-
keeps: bash_triggers.on_bash_command(counts_open_issues)
|
|
3193
|
-
};
|
|
3194
|
-
var wip_cap = { ROW: ROW22, WIP_CAP, WIP_CAP_REASON };
|
|
3195
|
-
|
|
3196
3251
|
// scripts/rules/delivered-rules.ts
|
|
3197
3252
|
var SWITCH_ENV_KEY = "JOSH_RULE_GUARD";
|
|
3198
3253
|
var STAMP_PREFIX = "josh-rule-guard-";
|
|
3199
3254
|
var { is_issue_filing, on_bash_command } = bash_triggers;
|
|
3200
3255
|
var { SHELL_BODY_REASON: SHELL_BODY_REASON2, carries_a_body: carries_a_body2, is_shell_evaluated_body: is_shell_evaluated_body2, keeps_body_safe: keeps_body_safe2 } = shell_body_trigger;
|
|
3201
3256
|
var DELIVERED_RULES = [
|
|
3202
|
-
//
|
|
3203
|
-
// that files an Issue into a repository we do not own trips both this row and `wip-cap` /
|
|
3204
|
-
// `issue-scout` / `filing-cap` — but the backlog count, the scout and the per-run cap are all about
|
|
3205
|
-
// filing into *our own* backlog, so on a third-party target the right answer is to stop the write
|
|
3206
|
-
// entirely rather than to count anything. Placing it first means a third-party write is refused
|
|
3207
|
-
// before any of those speak; on a first-party filing it is silent (the owners match), so `wip-cap`
|
|
3208
|
-
// still speaks first, exactly as before. It fires on every occurrence (`git-force.ts`).
|
|
3257
|
+
// First: a third-party write is stopped before the first-party filing rows count anything.
|
|
3209
3258
|
third_party_write.ROW,
|
|
3210
|
-
//
|
|
3211
|
-
// `
|
|
3212
|
-
// `epic:bundle` itself. It claims the direct call only, so the rows below — which trigger on the
|
|
3213
|
-
// `issue:file` call — never overlap it.
|
|
3259
|
+
// The direct call only; `filing-cap` below triggers on `issue:file`. The WIP cap and the fold
|
|
3260
|
+
// question are `issue:file`'s own steps, so no row gates them.
|
|
3214
3261
|
direct_filing.ROW,
|
|
3215
|
-
wip_cap.ROW,
|
|
3216
|
-
// **Two more rows share the filing trigger** (joshuafolkken/kit#2119, joshuafolkken/kit#2213), listed
|
|
3217
|
-
// after `wip-cap` so the backlog count still speaks first: `filing-cap` refuses every filing past
|
|
3218
|
-
// the per-run ceiling, and `issue-fold` refuses a *second* filing the run has not folded. Each is a
|
|
3219
|
-
// real instance of the admissible overlap the comment on `delivery` describes — the losing rule's
|
|
3220
|
-
// delivery is still correct one reissue later — so an unfolded, over-cap second filing is delivered
|
|
3221
|
-
// `wip-cap`, then `filing-cap`, then `issue-fold` across its reissues.
|
|
3222
3262
|
filing_cap.ROW,
|
|
3223
|
-
issue_fold_rule.ROW,
|
|
3224
3263
|
issue_comments.ROW,
|
|
3225
3264
|
{
|
|
3226
3265
|
id: "shell-body",
|
|
@@ -3229,19 +3268,15 @@ var DELIVERED_RULES = [
|
|
|
3229
3268
|
keeps: on_bash_command(keeps_body_safe2),
|
|
3230
3269
|
reaches: on_bash_command(carries_a_body2)
|
|
3231
3270
|
},
|
|
3232
|
-
// **The sibling of `shell-body`, one call further along** (joshuafolkken/kit#2304). `shell-body`
|
|
3233
|
-
// refuses a body passed inline so the shell evaluates it; this refuses a body passed by path with
|
|
3234
|
-
// the raw field flag (`-f` / `--raw-field body=@<path>`), which posts the literal `@<path>`. It
|
|
3235
|
-
// claims no command any row above does — `shell-body` triggers on a backtick or `$`, which the
|
|
3236
|
-
// `@<path>` misfire carries neither, and `is_issue_filing` leaves the comment endpoint alone — so
|
|
3237
|
-
// the exactly-one-rule invariant over its fixtures holds. It fires on every occurrence (`git-force.ts`).
|
|
3238
3271
|
raw_field_body.ROW,
|
|
3239
3272
|
{
|
|
3240
3273
|
id: "piped-verification",
|
|
3241
3274
|
is_trigger: on_bash_command(piped_verification.is_masked_verification),
|
|
3242
3275
|
reason: piped_verification.PIPED_VERIFICATION_REASON,
|
|
3243
3276
|
keeps: on_bash_command(piped_verification.keeps_verdict_intact),
|
|
3244
|
-
reaches: on_bash_command(piped_verification.runs_verification)
|
|
3277
|
+
reaches: on_bash_command(piped_verification.runs_verification),
|
|
3278
|
+
// A `| tail` / `| grep` masking is rewritten under `pipefail` by `pretool-guard.ts`, never refused.
|
|
3279
|
+
rewrite_note: piped_verification.PIPEFAIL_NOTE
|
|
3245
3280
|
},
|
|
3246
3281
|
{
|
|
3247
3282
|
id: "early-heartbeat",
|
|
@@ -3251,29 +3286,11 @@ var DELIVERED_RULES = [
|
|
|
3251
3286
|
keeps: on_bash_command(early_heartbeat.is_progress_watch),
|
|
3252
3287
|
reaches: on_bash_command(early_heartbeat.waits_for_progress)
|
|
3253
3288
|
},
|
|
3254
|
-
//
|
|
3255
|
-
// foreground `pnpm josh git -y` with no test beside the change is claimed by both: `test-declared`
|
|
3256
|
-
// decides whether the commit should happen at all, so it is listed first, exactly as `wip-cap`
|
|
3257
|
-
// precedes `shell-body` for deciding whether an Issue should exist. Nothing is lost by `run-tail`
|
|
3258
|
-
// losing the race — the stamps are keyed per `id`, so the reissued push is delivered `run-tail`,
|
|
3259
|
-
// which is asserted rather than assumed. The overlap only arises in a real checkout where the
|
|
3260
|
-
// verdict is `required`; in the hermetic non-repo suite the git read fails to `exempt`, so
|
|
3261
|
-
// `test-declared` claims nothing and the "exactly one rule" invariant over `run-tail`'s fixture holds.
|
|
3289
|
+
// Before `run-tail`: whether to commit at all is decided before how to push.
|
|
3262
3290
|
test_declared_commit.ROW,
|
|
3263
|
-
//
|
|
3264
|
-
// headless child's background tasks die with its turn, so a backgrounded `josh gate` / `git` /
|
|
3265
|
-
// `followup` is killed before it reports; this refuses the launch and hands back `josh ship
|
|
3266
|
-
// --detach`, whose supervisor outlives the turn. **Listed before `run-tail`, whose push it claims in
|
|
3267
|
-
// a child**: that row answers a foreground push with "reissue it backgrounded", the reissue this row
|
|
3268
|
-
// refuses, so a child is sent to the detached ship on its first refusal instead of through both.
|
|
3269
|
-
// Outside a child it claims nothing. A backgrounded bare `josh git` also trips `josh-git-bare`
|
|
3270
|
-
// below; this row wins, and `ship --detach` satisfies both. It fires on every occurrence.
|
|
3291
|
+
// Before `run-tail`, so a lane child goes straight to `ship --detach` instead of through both.
|
|
3271
3292
|
lane_background.ROW,
|
|
3272
|
-
//
|
|
3273
|
-
// own tool-name check rather than going through `on_bash_command`: a push step already issued with
|
|
3274
|
-
// `run_in_background` is the rule obeyed, and refusing it would charge a run for doing the right
|
|
3275
|
-
// thing. It supplies `decide` because a push is a recurring act — one per child in a batch, and a
|
|
3276
|
-
// second inside one `fullrun` when round 2 fixes a finding in place.
|
|
3293
|
+
// Reads `run_in_background` beside the command; `decide`, since a push recurs.
|
|
3277
3294
|
{
|
|
3278
3295
|
id: "run-tail",
|
|
3279
3296
|
is_trigger: run_tail_rule.is_foreground_push_step,
|
|
@@ -3282,36 +3299,10 @@ var DELIVERED_RULES = [
|
|
|
3282
3299
|
keeps: run_tail_rule.is_backgrounded_push_step,
|
|
3283
3300
|
reaches: run_tail_rule.is_push_step_call
|
|
3284
3301
|
},
|
|
3285
|
-
//
|
|
3286
|
-
//
|
|
3287
|
-
//
|
|
3288
|
-
//
|
|
3289
|
-
//
|
|
3290
|
-
// **Once per run rather than `decide`, and the direction of the error is why.** Taking the cut ends
|
|
3291
|
-
// the process, so this is not the recurring act joshuafolkken/kit#1570 wrote `decide` for — and the
|
|
3292
|
-
// five verdicts that legitimately leave a run at the gate (`not-a-lane`, `unready`, `busy`,
|
|
3293
|
-
// `failed`, `unknown`) all need the reissue to go through. A row that refused every time would wedge exactly
|
|
3294
|
-
// those runs; a row that refuses once cannot.
|
|
3295
|
-
//
|
|
3296
|
-
// **`pnpm josh rule:value` read this row with a ceiling of about 50%, and joshuafolkken/kit#1867 is
|
|
3297
|
-
// what removed it** (the ceiling was recorded here by joshuafolkken/kit#1864's review round 2). A
|
|
3298
|
-
// cut relaunches a *new session*, which the measurement groups as a run of its own, and that
|
|
3299
|
-
// resumed run issues the entry check — so scored on the asking alone it joined the denominator
|
|
3300
|
-
// while never being able to satisfy `keeps`, which only the cutting run can, and ten perfectly
|
|
3301
|
-
// obedient children read as ten kept out of twenty. **The two halves are separable, just not from
|
|
3302
|
-
// one call**: both processes issue byte-identical `--resume` strings, but the `fresh` verdict sends
|
|
3303
|
-
// a run on to claim the working-tree hold while the `resume` verdict tells its counterpart to skip
|
|
3304
|
-
// that claim. `reaches_the_pre_gate_boundary` is that conjunction, and it is why `CallTest` is
|
|
3305
|
-
// handed the run's calls beside the turn's rather than a second predicate slot of its own.
|
|
3306
|
-
// Dropping `reaches` altogether is still strictly worse — the trigger evaluates against the
|
|
3307
|
-
// *measuring* process's working directory, so it is always false from the main checkout and the row
|
|
3308
|
-
// would read as no runs at all.
|
|
3309
|
-
//
|
|
3310
|
-
// **It overlaps `piped-verification` on a piped gate call, and the order is safe in both
|
|
3311
|
-
// directions.** `pnpm josh gate | tail` in an uncut lane is a real instance of both defects; the
|
|
3312
|
-
// earlier row speaks, its own reason says to reissue, and this one delivers on the reissue — the
|
|
3313
|
-
// reading "the losing rule's delivery is still correct one call later" that the comment below
|
|
3314
|
-
// requires of any admissible overlap.
|
|
3302
|
+
// Reads the lane name and the cut record. Once per run, not `decide`: taking the cut ends the
|
|
3303
|
+
// process, and the verdicts that leave a run at the gate all need the reissue through. `reaches`
|
|
3304
|
+
// tells the cutting run from the resumed one by the run's calls. Overlaps `piped-verification`
|
|
3305
|
+
// safely: that row speaks first and this one delivers on the reissue.
|
|
3315
3306
|
{
|
|
3316
3307
|
id: "pre-gate-cut",
|
|
3317
3308
|
is_trigger: on_bash_command(pre_gate_cut.is_uncut_gate),
|
|
@@ -3319,125 +3310,25 @@ var DELIVERED_RULES = [
|
|
|
3319
3310
|
keeps: on_bash_command(pre_gate_cut.takes_the_cut),
|
|
3320
3311
|
reaches: pre_gate_cut.reaches_the_pre_gate_boundary
|
|
3321
3312
|
},
|
|
3322
|
-
//
|
|
3323
|
-
// "is this a dispatched lane child" is the dispatch mark against this checkout's own issue, read
|
|
3324
|
-
// synchronously by `lane_child_marker.is_child_of`, and the command match runs first so an ordinary
|
|
3325
|
-
// run pays nothing for it.
|
|
3326
|
-
// Its once-per-run disposition is stated beside the row in `lane-park.ts`.
|
|
3327
|
-
//
|
|
3328
|
-
// **A split child's park is refused first** (joshuafolkken/kit#3296): a lane child that promoted its
|
|
3329
|
-
// own Issue to an epic this run has nothing to park, so `lane-split-park` refuses the label write
|
|
3330
|
-
// and the confirmation notify onto that epic on every occurrence. It shares the notify with
|
|
3331
|
-
// `lane-park` and is listed first; a run that promoted nothing falls through to `lane-park`.
|
|
3313
|
+
// A split child's park is refused before `lane-park` sees it.
|
|
3332
3314
|
lane_split_park.ROW,
|
|
3333
3315
|
lane_park.ROW,
|
|
3334
|
-
// **joshuafolkken/kit#2034's rule, one tool-call earlier** (joshuafolkken/kit#2201). `lane-park`
|
|
3335
|
-
// fires on the `confirmation` notify a routed child reaches; a child that reaches for
|
|
3336
|
-
// `AskUserQuestion` never gets there, because the harness ends its turn at the refused ask. This
|
|
3337
|
-
// row's trigger is that ask, so the refusal becomes an instruction — park the question — instead of
|
|
3338
|
-
// the child's death. Its trigger reads the input's tool name and consults the dispatch mark, like
|
|
3339
|
-
// `lane-park`, and shares no command with any Bash row, so it claims no `gh` / `git` / `josh` call.
|
|
3340
|
-
// It fires on every occurrence (`decide` returns true), the disposition `git-force.ts` takes: an
|
|
3341
|
-
// interactive ask must never succeed in a child, and the route is always the park, never a reissue.
|
|
3342
3316
|
lane_interactive_ask.ROW,
|
|
3343
|
-
// **The parent budget commands a lane child must never run** (joshuafolkken/kit#2267). A dispatched
|
|
3344
|
-
// child that ran `pnpm josh run:merge` read its `busy` as a competing session and parked its Issue
|
|
3345
|
-
// unimplemented — but the live carry record is the parent that launched it, never a competitor. This
|
|
3346
|
-
// row refuses `run:merge` / `run:carry` in a lane child and hands back the mechanical branch: the
|
|
3347
|
-
// record is the parent's, so continue implementing rather than park or ask. Its trigger claims a
|
|
3348
|
-
// `josh` subcommand no other row does (the filing rows are `gh`, `run-tail` is `git push`), so it
|
|
3349
|
-
// overlaps nothing. It fires on every occurrence (`decide` returns true): a child must never run
|
|
3350
|
-
// these, and the route is always "continue", never a reissue (`git-force.ts`).
|
|
3351
3317
|
lane_carry_conflict.ROW,
|
|
3352
|
-
// **The `git switch main` a lane child can never succeed at** (joshuafolkken/kit#2313), the fifth of
|
|
3353
|
-
// the "always fails" misfires joshuafolkken/kit#2297 catalogued. A lane is a linked work tree and the
|
|
3354
|
-
// primary checkout holds the default branch, so a child's `git switch main` fails structurally
|
|
3355
|
-
// (`already used by worktree`); this refuses it before it fails and hands back the next command —
|
|
3356
|
-
// skip the step, `pnpm josh main:merge` brings the default in during the gate. Its trigger reads the
|
|
3357
|
-
// dispatch mark and the lane branch like `lane-carry-conflict`, and claims a `git switch` no row
|
|
3358
|
-
// above matches — `git-force` is `git push` / `git branch`, `worktree-mutation` is `git checkout --`
|
|
3359
|
-
// / `restore` / `stash` — so no two rows claim one command. It fires on every occurrence (`decide`
|
|
3360
|
-
// returns true): a child must never run this, and the route is always "continue" (`git-force.ts`).
|
|
3361
3318
|
lane_switch_main.ROW,
|
|
3362
|
-
//
|
|
3363
|
-
// prompts to confirm the staging, the no-TTY prompt cancels, and the run reissues with `-y` after
|
|
3364
|
-
// throwing away the time it took to fail. This row refuses the bare call and hands back the `-y`
|
|
3365
|
-
// form. It is disjoint from `run-tail` by the flag — that row requires `-y`, this refuses its
|
|
3366
|
-
// absence — so no two rows claim one command. It fires on every occurrence (`decide` returns true):
|
|
3367
|
-
// a bare call wastes the same time each time, so the route is always the `-y` reissue
|
|
3368
|
-
// (`git-force.ts`).
|
|
3319
|
+
// Disjoint from `run-tail` by the `-y` flag.
|
|
3369
3320
|
josh_git_bare.ROW,
|
|
3370
|
-
//
|
|
3371
|
-
//
|
|
3372
|
-
// force/delete is `git push` / `git branch`, the worktree change is `git checkout` / `restore` /
|
|
3373
|
-
// `stash`, and the file body is a heredoc / `node -e` / `perl -i` — so no two rows claim one command,
|
|
3374
|
-
// which `delivered-rules-bash.test.ts` pins. Each declares `decide` returning true: a destructive or
|
|
3375
|
-
// billed act is refused on every occurrence, never once per run (`git-force.ts`).
|
|
3321
|
+
// The Bash-string gaps the deny glob cannot express, read by argv; `delivered-rules-bash.test.ts`
|
|
3322
|
+
// pins that no two rows claim one command.
|
|
3376
3323
|
git_force.ROW,
|
|
3377
3324
|
worktree_guard.ROW,
|
|
3378
3325
|
file_body.ROW,
|
|
3379
|
-
// **The deny-list bypasses closed by argv and path rather than glob** (joshuafolkken/kit#2983) — an
|
|
3380
|
-
// index mutation, a recursive forced `rm` or destructive `gh` call, and a protected file. Each
|
|
3381
|
-
// claims a command or file no row above does and refuses every occurrence (`permission-guards.ts`).
|
|
3382
3326
|
...permission_guards.ROWS,
|
|
3383
|
-
// **The hand-written wait loop a lane child improvises over a backgrounded command's output**
|
|
3384
|
-
// (joshuafolkken/kit#2371). `early-heartbeat` refuses a bare `sleep` and stands down on any loop
|
|
3385
|
-
// keyword; this is the loop it left — a `while`/`until` that sleeps between probes of an output
|
|
3386
|
-
// file. Its trigger claims a command no row above matches: the loop-plus-`sleep` shape carries no
|
|
3387
|
-
// `gh` / `git` / `josh` subcommand any other trigger keys on, and a poll loop is never a bare
|
|
3388
|
-
// `sleep` (the loop keyword makes `early-heartbeat.is_wait_timer` false), so the Bash
|
|
3389
|
-
// `rules_claiming` invariant holds. It fires on every occurrence (`decide` returns true): a poll
|
|
3390
|
-
// loop wastes the same round trips each time, so the route is always "background it and end the
|
|
3391
|
-
// turn", never a reissue (`git-force.ts`).
|
|
3392
3327
|
poll_loop.ROW,
|
|
3393
|
-
//
|
|
3394
|
-
//
|
|
3395
|
-
// child whose recent-context cost has crossed the threshold" reads the dispatch mark, the cut record
|
|
3396
|
-
// on disk and the synchronous `pnpm josh cost --cut` verdict — the same measurement the parent
|
|
3397
|
-
// hand-off uses, never a second one (joshuafolkken/kit#1933). The `Edit` / `Write` name match runs
|
|
3398
|
-
// first, then the lane read, then the transcript-priced verdict, so a run that is not a dispatched
|
|
3399
|
-
// child in an uncut lane pays nothing for it. It self-gates on the tool name, so it claims no `Bash`
|
|
3400
|
-
// command any row above matches — the Bash `rules_claiming` invariant is untouched.
|
|
3401
|
-
//
|
|
3402
|
-
// **Listed before `rule-body`, the one row it can overlap.** Both trigger on an `Edit` / `Write`; a
|
|
3403
|
-
// rule-document edit made in a lane child that is already over threshold trips both. The cut is the
|
|
3404
|
-
// right thing to do first — end the process and drop the accumulated context — and on the reissue in
|
|
3405
|
-
// the fresh, under-threshold process this row is silent and `rule-body` delivers, the "losing rule's
|
|
3406
|
-
// delivery still correct one reissue later" reading any admissible overlap needs.
|
|
3407
|
-
//
|
|
3408
|
-
// **It carries `decide`, and the inversion of the pre-gate cut's reasoning is why** (joshuafolkken/kit#2385).
|
|
3409
|
-
// `pre-gate-cut` and `lane-park` are once per run because taking the cut, or the park, *ends the
|
|
3410
|
-
// process* — the one act is not a recurring one, and the five verdicts that leave a run holding it
|
|
3411
|
-
// all need the one reissue to go through. This cut ends the process too, but its *trigger* does not:
|
|
3412
|
-
// crossing the threshold mid-implementation is a recurring state that once-per-run silenced for the
|
|
3413
|
-
// rest of a process the moment its first refusal landed — so a `busy` / `failed` / `unready` verdict,
|
|
3414
|
-
// or an edit the model reissued unchanged, left the context to grow unwatched (joshuafolkken/kit#2382
|
|
3415
|
-
// ran to 282,747 tokens with the cut never taken). `decide` re-asks on every over-threshold edit, and
|
|
3416
|
-
// its `delivered_at_ms` lets an edit reissued right after a refusal through, so `busy` / `failed`
|
|
3417
|
-
// cannot wedge the run edit after edit — the reissue path once-per-run gave for free, now made
|
|
3418
|
-
// explicit. The fresh process after a successful cut reads its own transcript under threshold, so it
|
|
3419
|
-
// is silent without needing a carried record to quiet it.
|
|
3420
|
-
//
|
|
3421
|
-
// **No `reaches`, because the occasion is live-only.** `pre-gate-cut` gives a `reaches` because both
|
|
3422
|
-
// its halves leave a command-string trace (`run:cut --resume` at entry); this row's occasion —
|
|
3423
|
-
// crossing the threshold mid-implementation — is the working directory, the cut record and the cost
|
|
3424
|
-
// verdict, none of which a transcript records. `pnpm josh rule:value` therefore reads it as no runs
|
|
3425
|
-
// rather than as 0% kept (`keeps` stays, so the compliance act is named for a future measurement
|
|
3426
|
-
// redesign), the same honest-unmeasured stance the batching and investigation rows take for the same
|
|
3427
|
-
// reason: a trigger no transcript can reconstruct. The row itself lives in `implementation-cut.ts`.
|
|
3328
|
+
// Before `rule-body`, its one overlap: the cut is the right first act, and `rule-body` delivers on
|
|
3329
|
+
// the reissue in the fresh process.
|
|
3428
3330
|
implementation_cut.ROW,
|
|
3429
|
-
// **The first row whose trigger is an `Edit` / `Write` rather than a shell call**
|
|
3430
|
-
// (joshuafolkken/kit#2272). It delivers the residency questions at the edit that writes a rule into
|
|
3431
|
-
// prose, and self-gates on the tool name and the file path, so it claims no `Bash` command any row
|
|
3432
|
-
// above matches — the `rules_claiming` invariant over Bash fixtures is untouched. It carries no
|
|
3433
|
-
// `decide`, so it is once per run and takes the batching stand-aside `is_first_delivery` gives every
|
|
3434
|
-
// default row: the batching guard treats an `Edit` as a candidate, exactly as it treats an Issue
|
|
3435
|
-
// read, so this row stands aside on a batched turn and delivers on the reissue.
|
|
3436
3331
|
rule_body_guard.ROW,
|
|
3437
|
-
// **The generic oracle-consulted rows, one per oracle that declared a firing point**
|
|
3438
|
-
// (joshuafolkken/kit#2324). Each refuses the action the oracle governs when the run has not run that
|
|
3439
|
-
// oracle's command first, stood down once it has. Listed last; the one firing point left
|
|
3440
|
-
// (`pkg:scout` on a package add) claims a command no row above matches.
|
|
3441
3332
|
...oracle_consulted.ROWS
|
|
3442
3333
|
];
|
|
3443
3334
|
var ALONE_IN_TURN = 1;
|
|
@@ -3511,7 +3402,6 @@ var delivered_rules = {
|
|
|
3511
3402
|
FILING_CAP_REASON: filing_cap.FILING_CAP_REASON,
|
|
3512
3403
|
GIT_FORCE_REASON: git_force.GIT_FORCE_REASON,
|
|
3513
3404
|
ISSUE_COMMENTS_REASON: issue_comments.ISSUE_COMMENTS_REASON,
|
|
3514
|
-
ISSUE_FOLD_REASON: issue_fold_rule.ISSUE_FOLD_REASON,
|
|
3515
3405
|
LANE_INTERACTIVE_ASK_REASON: lane_interactive_ask.LANE_INTERACTIVE_ASK_REASON,
|
|
3516
3406
|
LANE_PARK_REASON: lane_park.LANE_PARK_REASON,
|
|
3517
3407
|
MEASURED_RULES,
|
|
@@ -3523,8 +3413,6 @@ var delivered_rules = {
|
|
|
3523
3413
|
SHELL_BODY_REASON: SHELL_BODY_REASON2,
|
|
3524
3414
|
SWITCH_ENV_KEY,
|
|
3525
3415
|
THIRD_PARTY_WRITE_REASON: third_party_write.THIRD_PARTY_WRITE_REASON,
|
|
3526
|
-
WIP_CAP: wip_cap.WIP_CAP,
|
|
3527
|
-
WIP_CAP_REASON: wip_cap.WIP_CAP_REASON,
|
|
3528
3416
|
WORKTREE_MUTATION_REASON: worktree_guard.WORKTREE_MUTATION_REASON,
|
|
3529
3417
|
delivery,
|
|
3530
3418
|
delivery_path,
|
|
@@ -3539,17 +3427,23 @@ import { loadavg } from "node:os";
|
|
|
3539
3427
|
// scripts/epic/epic-busy.ts
|
|
3540
3428
|
var LISTING_LIMIT = 100;
|
|
3541
3429
|
var PARKED_LABELS = /* @__PURE__ */ new Set([NEEDS_DECISION_LABEL, ALREADY_DONE_LABEL]);
|
|
3542
|
-
|
|
3543
|
-
|
|
3430
|
+
var NO_AGES = /* @__PURE__ */ new Map();
|
|
3431
|
+
function format_holder(issue, repo, ages) {
|
|
3432
|
+
const cite = session_cite.issue(issue.number, issue.title, repo);
|
|
3433
|
+
const age = ages.get(issue.number);
|
|
3434
|
+
return age === void 0 ? cite : `${cite} (${age})`;
|
|
3435
|
+
}
|
|
3436
|
+
function format_holders(issues, repo, ages) {
|
|
3437
|
+
return issues.map((issue) => format_holder(issue, repo, ages)).join(", ");
|
|
3544
3438
|
}
|
|
3545
3439
|
function occupied_lanes(read2) {
|
|
3546
3440
|
return read2.kind === "busy" ? read2.issues.length : 0;
|
|
3547
3441
|
}
|
|
3548
|
-
function occupancy_message(issues, repo, limit) {
|
|
3549
|
-
return `${String(issues.length)} of ${String(limit)} lanes in use in ${repo}: ${format_holders(issues)}.`;
|
|
3442
|
+
function occupancy_message(issues, repo, limit, ages = NO_AGES) {
|
|
3443
|
+
return `${String(issues.length)} of ${String(limit)} lanes in use in ${repo}: ${format_holders(issues, repo, ages)}.`;
|
|
3550
3444
|
}
|
|
3551
|
-
function lanes_full_message(issues, repo, limit) {
|
|
3552
|
-
return `${occupancy_message(issues, repo, limit)} No lane is free, so nothing is offered here. A lane is released when its child merges or is parked; if a label is stale, remove it and ask again, and \`JOSH_LANE_LIMIT\` is what raises the ceiling.`;
|
|
3445
|
+
function lanes_full_message(issues, repo, limit, ages = NO_AGES) {
|
|
3446
|
+
return `${occupancy_message(issues, repo, limit, ages)} No lane is free, so nothing is offered here. A lane is released when its child merges or is parked; if a label is stale, remove it and ask again, and \`JOSH_LANE_LIMIT\` is what raises the ceiling.`;
|
|
3553
3447
|
}
|
|
3554
3448
|
function unreadable_message(repo) {
|
|
3555
3449
|
return `Could not read the \`${IN_PROGRESS_LABEL}\` listing for ${repo}. That is not "nothing is running" \u2014 check \`gh auth status\` and ask again.`;
|
|
@@ -3561,8 +3455,8 @@ var BUSY_REASONS = {
|
|
|
3561
3455
|
unreadable: unreadable_message,
|
|
3562
3456
|
truncated: truncated_message
|
|
3563
3457
|
};
|
|
3564
|
-
function busy_reason(read2, repo, limit) {
|
|
3565
|
-
if (read2.kind === "busy") return lanes_full_message(read2.issues, repo, limit);
|
|
3458
|
+
function busy_reason(read2, repo, limit, ages = NO_AGES) {
|
|
3459
|
+
if (read2.kind === "busy") return lanes_full_message(read2.issues, repo, limit, ages);
|
|
3566
3460
|
if (read2.kind === "idle") return "";
|
|
3567
3461
|
return BUSY_REASONS[read2.kind](repo);
|
|
3568
3462
|
}
|
|
@@ -3792,7 +3686,7 @@ var issue_state_schema = z10.looseObject({
|
|
|
3792
3686
|
});
|
|
3793
3687
|
function parse_issue_state(json) {
|
|
3794
3688
|
try {
|
|
3795
|
-
const parsed =
|
|
3689
|
+
const parsed = parse_json_object_or_undefined(json, issue_state_schema);
|
|
3796
3690
|
if (parsed === void 0) return void 0;
|
|
3797
3691
|
const labels = parsed.labels ?? [];
|
|
3798
3692
|
return {
|
|
@@ -3835,7 +3729,7 @@ var DEFAULT_SILENT_MINUTES = 30;
|
|
|
3835
3729
|
var DEFAULT_GAP_SECONDS = 5;
|
|
3836
3730
|
var MS_PER_MINUTE3 = 6e4;
|
|
3837
3731
|
var MS_PER_SECOND2 = 1e3;
|
|
3838
|
-
var
|
|
3732
|
+
var OPEN_STATE = "OPEN";
|
|
3839
3733
|
var STATE_FIELDS = "state,labels";
|
|
3840
3734
|
var REASONS = {
|
|
3841
3735
|
[ALIVE_VERDICT]: "The unit is still working: its output moved, or a process of the child is alive.",
|
|
@@ -3847,7 +3741,7 @@ var ALIVE_ADVICE = "Keep polling; do not touch the child.";
|
|
|
3847
3741
|
var SETTLED_ADVICE = "Read the child with `pnpm josh issue:state <N>` and take the branch its state says.";
|
|
3848
3742
|
var STOPPED_CLEAN_ADVICE = 'The unit ended \u2014 classify how before booking it. Run `pnpm josh run:merge <N> --output <path>` (add `--epic <E> --repo <owner/repo> --owner "$PPID"` for a named epic): it reads the child\'s exit record without waiting for the unit to return, re-dispatches a child that could not reach the API (counting the outage; a run of them trips the environment guard and stops the run), and parks an abandoned child with `needs-decision` against the consecutive-failure guard. The checkout is clean, so there is nothing to stash.';
|
|
3849
3743
|
var STOPPED_DIRTY_ADVICE = 'Stash the half-finished work with `git stash push -u -m "backlogrun: stopped unit for #<N>"` and record it on the Issue, then classify how the unit ended with `pnpm josh run:merge <N> --output <path>` (add `--epic <E> --repo <owner/repo> --owner "$PPID"` for a named epic): it re-dispatches an API-outage child (counting the outage; a run of them trips the environment guard) and parks an abandoned child with `needs-decision` against the consecutive-failure guard, without waiting for the unit to return.';
|
|
3850
|
-
var UNDETERMINED_ADVICE = "Read the trace that failed and ask again. Where the process trace was
|
|
3744
|
+
var UNDETERMINED_ADVICE = "Read the trace that failed and ask again. Where the process trace was given as `unknown`, leave `--process` out so the command reads it. Two of these in a row is a fault in the check itself rather than a slow unit: stop polling and report it.";
|
|
3851
3745
|
function is_output_moving(traces) {
|
|
3852
3746
|
return traces.is_output_frozen === false;
|
|
3853
3747
|
}
|
|
@@ -3954,7 +3848,7 @@ async function read_child_settled(issue, repo) {
|
|
|
3954
3848
|
if (json === void 0) return void 0;
|
|
3955
3849
|
const state = issue_state.parse_issue_state(json);
|
|
3956
3850
|
if (state === void 0) return void 0;
|
|
3957
|
-
return state.state !==
|
|
3851
|
+
return state.state !== OPEN_STATE || carries_settled_label(state.labels);
|
|
3958
3852
|
}
|
|
3959
3853
|
async function read_traces(request) {
|
|
3960
3854
|
const [is_initial_child_settled, is_output_frozen, is_tree_dirty] = await Promise.all([
|
|
@@ -3979,7 +3873,7 @@ async function read_traces(request) {
|
|
|
3979
3873
|
};
|
|
3980
3874
|
}
|
|
3981
3875
|
async function check(request) {
|
|
3982
|
-
|
|
3876
|
+
issue_number_shape.require_issue_number(request.issue);
|
|
3983
3877
|
return decide5(await read_traces(request));
|
|
3984
3878
|
}
|
|
3985
3879
|
var run_liveness = {
|
|
@@ -3994,14 +3888,14 @@ var run_liveness = {
|
|
|
3994
3888
|
|
|
3995
3889
|
// scripts/lane/lane-report.ts
|
|
3996
3890
|
var NO_LANES2 = "No lanes are open.";
|
|
3997
|
-
var
|
|
3891
|
+
var OPEN_STATE2 = "open";
|
|
3998
3892
|
var STRANDED_STATE = "stranded";
|
|
3999
3893
|
var UNREADABLE_STATE = "unreadable";
|
|
4000
3894
|
var UNKNOWN_VALUE = "-";
|
|
4001
3895
|
var COLUMN_SEPARATOR = " ";
|
|
4002
3896
|
function lane_state(lane) {
|
|
4003
3897
|
if (lane.is_stranded) return STRANDED_STATE;
|
|
4004
|
-
return lane.seat === void 0 ? UNREADABLE_STATE :
|
|
3898
|
+
return lane.seat === void 0 ? UNREADABLE_STATE : OPEN_STATE2;
|
|
4005
3899
|
}
|
|
4006
3900
|
function value_or_unknown(value) {
|
|
4007
3901
|
return value === void 0 ? UNKNOWN_VALUE : String(value);
|
|
@@ -4041,11 +3935,11 @@ function describe_ports(lane) {
|
|
|
4041
3935
|
return `seat ${String(lane.seat)}, dev ${value_or_unknown(lane.development_port)}, preview ${value_or_unknown(lane.preview_port)}`;
|
|
4042
3936
|
}
|
|
4043
3937
|
function describe_opened(lane) {
|
|
4044
|
-
return `Opened a lane for
|
|
3938
|
+
return `Opened a lane for ${session_cite.issue(lane.issue)} on ${lane.branch}: ${describe_ports(lane)}.`;
|
|
4045
3939
|
}
|
|
4046
3940
|
var lane_report = {
|
|
4047
3941
|
NO_LANES: NO_LANES2,
|
|
4048
|
-
OPEN_STATE:
|
|
3942
|
+
OPEN_STATE: OPEN_STATE2,
|
|
4049
3943
|
STRANDED_STATE,
|
|
4050
3944
|
UNREADABLE_STATE,
|
|
4051
3945
|
describe_lane,
|
|
@@ -4076,7 +3970,7 @@ var CLEAN_ADVICE = "Start the child.";
|
|
|
4076
3970
|
var RESUME_ADVICE = "Reuse the branch and run the whole verification gate from the start \u2014 refactor, `pnpm josh gate`, `/code-review` \u2014 never only the part the interrupted run had not reached. Nobody verified what it already committed.";
|
|
4077
3971
|
var PARK_ADVICE = "Park the child: add `needs-decision` and comment what was found. Do not delete the branch, do not reopen the pull request, and do not commit on top of it.";
|
|
4078
3972
|
var STASH_LABEL_PREFIX = "run:hold reclaimed before #";
|
|
4079
|
-
var { require_issue_number } =
|
|
3973
|
+
var { require_issue_number } = issue_number_shape;
|
|
4080
3974
|
var UNREADABLE_PR_MESSAGE = "The pull request could not be read for branch ";
|
|
4081
3975
|
function needs_reclaim(tree) {
|
|
4082
3976
|
return tree.is_dirty || tree.branch !== tree.default_branch;
|
|
@@ -4118,13 +4012,13 @@ function reclaim_steps(tree, issue) {
|
|
|
4118
4012
|
if (!tree.is_dirty) return [];
|
|
4119
4013
|
return [
|
|
4120
4014
|
`git stash push -u -m "${STASH_LABEL_PREFIX}${issue}"`,
|
|
4121
|
-
`Record the stash on
|
|
4015
|
+
`Record the stash on ${session_cite.issue(issue)} \u2014 the comment is what gets it popped; nothing pops it for you.`
|
|
4122
4016
|
];
|
|
4123
4017
|
}
|
|
4124
4018
|
function reclaim_advice(tree, issue) {
|
|
4125
4019
|
return [
|
|
4126
4020
|
...reclaim_steps(tree, issue),
|
|
4127
|
-
|
|
4021
|
+
"pnpm josh ms",
|
|
4128
4022
|
"Then ask this command again: it is re-askable, and the clean tree gets its own answer."
|
|
4129
4023
|
].join("\n");
|
|
4130
4024
|
}
|
|
@@ -4143,11 +4037,7 @@ function decide6(tree, child, issue) {
|
|
|
4143
4037
|
};
|
|
4144
4038
|
}
|
|
4145
4039
|
function read_pr_field(raw) {
|
|
4146
|
-
|
|
4147
|
-
return pr_info_schema.parse(JSON.parse(raw)).state;
|
|
4148
|
-
} catch {
|
|
4149
|
-
return void 0;
|
|
4150
|
-
}
|
|
4040
|
+
return json_value.parse_with(raw, pr_info_schema)?.state;
|
|
4151
4041
|
}
|
|
4152
4042
|
function to_pr_state(raw) {
|
|
4153
4043
|
const state = read_pr_field(raw);
|
|
@@ -4372,12 +4262,7 @@ var SWITCH_ENV_KEY2 = "JOSH_WATCHER_GUARD";
|
|
|
4372
4262
|
var STAMP_PREFIX2 = "josh-watcher-guard-";
|
|
4373
4263
|
var payload_schema = z12.object({ transcript_path: z12.string().min(1) });
|
|
4374
4264
|
function transcript_of(raw_payload) {
|
|
4375
|
-
|
|
4376
|
-
const parsed = payload_schema.safeParse(JSON.parse(raw_payload));
|
|
4377
|
-
return parsed.success ? parsed.data.transcript_path : void 0;
|
|
4378
|
-
} catch {
|
|
4379
|
-
return void 0;
|
|
4380
|
-
}
|
|
4265
|
+
return json_value.parse_with(raw_payload, payload_schema)?.transcript_path;
|
|
4381
4266
|
}
|
|
4382
4267
|
function fires_once(transcript, now_ms) {
|
|
4383
4268
|
const stamp = hook_decision.create_refusal_stamp(STAMP_PREFIX2);
|
|
@@ -4415,7 +4300,7 @@ var THRESHOLD_TEXT2 = `${cost_format.format_tokens(CONTEXT_CUT_THRESHOLD)}-token
|
|
|
4415
4300
|
var PARENT_CUT_REASON = `\u26D4 backlogrun parent hand-off: this session drives a \`backlogrun\` (it owns the live carry record) and its recent-context cost has crossed the shared ${THRESHOLD_TEXT2} threshold between merges, so every later request re-reads the accumulated context (joshuafolkken/kit#2947). Take the hand-off now rather than at the next merge: follow \`.claude/skills/workflow-commands/backlogrun-progress.md\` \u2192 "The hand-off" from its \`over\` branch \u2014 open no new lane and take no new child, read \`pnpm josh lane:list\`, make sure every lane in flight records an output path, then run \`pnpm josh run:carry --cut --owner "$PPID"\` and, unless it answers \`capped\`, \`pnpm josh run:wake\`, post the progress comment and end the turn. A lane nobody can poll means the cut does not happen; carry on and this asks again later. Reissue this call when the hand-off is done or cannot be taken \u2014 the guard stays quiet for a while after it refuses, so the hand-off calls themselves are not refused.`;
|
|
4416
4301
|
async function is_due2(state) {
|
|
4417
4302
|
const carry = await state.carry();
|
|
4418
|
-
if (carry === void 0 ||
|
|
4303
|
+
if (carry === void 0 || run_headless.is_cut_capped(carry)) return false;
|
|
4419
4304
|
return state.verdict() === cost_verdict.OVER_VERDICT;
|
|
4420
4305
|
}
|
|
4421
4306
|
function is_quiet(target, now_ms) {
|
|
@@ -4522,6 +4407,9 @@ function guard_outcome(raw_payload) {
|
|
|
4522
4407
|
function pretool_outcome(raw_payload) {
|
|
4523
4408
|
return with_step_zero_notice(guard_outcome(raw_payload), raw_payload);
|
|
4524
4409
|
}
|
|
4410
|
+
async function mark_phase(outcome) {
|
|
4411
|
+
if (outcome.notice === step_zero_notice.NOTICE) await lane_phase.mark_implement();
|
|
4412
|
+
}
|
|
4525
4413
|
async function async_reason(raw_payload) {
|
|
4526
4414
|
const watcher = await run_watcher_hook.watcher_hook_reason(raw_payload);
|
|
4527
4415
|
return watcher ?? await run_parent_cut_hook.parent_cut_reason(raw_payload);
|
|
@@ -4531,7 +4419,9 @@ async function pretool_outcome_async(raw_payload) {
|
|
|
4531
4419
|
if (!is_clear(base)) return base;
|
|
4532
4420
|
const reason = await async_reason(raw_payload);
|
|
4533
4421
|
if (reason !== void 0) return { reason, notice: void 0, fault: void 0 };
|
|
4534
|
-
|
|
4422
|
+
const outcome = with_step_zero_notice(base, raw_payload);
|
|
4423
|
+
await mark_phase(outcome);
|
|
4424
|
+
return outcome;
|
|
4535
4425
|
}
|
|
4536
4426
|
function guarded_call(raw_payload) {
|
|
4537
4427
|
try {
|
|
@@ -4541,23 +4431,55 @@ function guarded_call(raw_payload) {
|
|
|
4541
4431
|
return void 0;
|
|
4542
4432
|
}
|
|
4543
4433
|
}
|
|
4434
|
+
function rewrite_context(note, outcome) {
|
|
4435
|
+
return [note, outcome.notice ?? outcome.fault].filter(Boolean).join("\n\n");
|
|
4436
|
+
}
|
|
4544
4437
|
function foreground_rewrite(outcome, raw_payload, is_lane_child) {
|
|
4545
4438
|
if (outcome.reason !== void 0) return void 0;
|
|
4546
4439
|
const call = guarded_call(raw_payload);
|
|
4547
4440
|
const input = call === void 0 ? void 0 : lane_background.foreground_input(call, is_lane_child);
|
|
4548
4441
|
if (input === void 0) return void 0;
|
|
4549
|
-
|
|
4550
|
-
|
|
4442
|
+
return hook_decision.rewrite_envelope(
|
|
4443
|
+
input,
|
|
4444
|
+
rewrite_context(lane_background.FOREGROUND_NOTE, outcome)
|
|
4445
|
+
);
|
|
4551
4446
|
}
|
|
4552
|
-
function
|
|
4553
|
-
|
|
4447
|
+
function pipefail_rewrite(raw_payload) {
|
|
4448
|
+
if (!delivered_rules.is_enabled()) return void 0;
|
|
4449
|
+
const call = guarded_call(raw_payload);
|
|
4450
|
+
const input = call === void 0 ? void 0 : piped_verification.pipefail_input(call);
|
|
4451
|
+
const payload = json_value.parse_or_undefined(raw_payload);
|
|
4452
|
+
if (input === void 0 || !json_value.is_record(payload)) return void 0;
|
|
4453
|
+
return { payload: JSON.stringify({ ...payload, tool_input: input }), input };
|
|
4454
|
+
}
|
|
4455
|
+
function pipefail_envelope(outcome, input) {
|
|
4456
|
+
if (input === void 0 || outcome.reason !== void 0) return void 0;
|
|
4457
|
+
return hook_decision.rewrite_envelope(
|
|
4458
|
+
input,
|
|
4459
|
+
rewrite_context(piped_verification.PIPEFAIL_NOTE, outcome)
|
|
4460
|
+
);
|
|
4461
|
+
}
|
|
4462
|
+
function emit(raw_payload, outcome, pipefail_input2) {
|
|
4463
|
+
const rewrite = pipefail_envelope(outcome, pipefail_input2) ?? foreground_rewrite(outcome, raw_payload);
|
|
4554
4464
|
if (rewrite === void 0) hook_decision.emit_outcome(outcome);
|
|
4555
4465
|
else process.stdout.write(`${rewrite}
|
|
4556
4466
|
`);
|
|
4557
4467
|
}
|
|
4558
|
-
|
|
4468
|
+
async function respond(raw_payload) {
|
|
4469
|
+
const pipefail = pipefail_rewrite(raw_payload);
|
|
4470
|
+
const judged = pipefail?.payload ?? raw_payload;
|
|
4471
|
+
emit(judged, await pretool_outcome_async(judged), pipefail?.input);
|
|
4472
|
+
}
|
|
4473
|
+
var pretool_guard = {
|
|
4474
|
+
combine_outcomes,
|
|
4475
|
+
emit,
|
|
4476
|
+
foreground_rewrite,
|
|
4477
|
+
mark_phase,
|
|
4478
|
+
pipefail_rewrite,
|
|
4479
|
+
pretool_outcome,
|
|
4480
|
+
respond
|
|
4481
|
+
};
|
|
4559
4482
|
|
|
4560
4483
|
export {
|
|
4561
|
-
pretool_outcome_async,
|
|
4562
4484
|
pretool_guard
|
|
4563
4485
|
};
|