@joshuafolkken/kit 1.1050.0 → 1.1094.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/settings.json +9 -8
- package/.claude/skills/epic-commands/SKILL.md +5 -7
- package/.claude/skills/workflow-commands/SKILL.md +19 -11
- package/.claude/skills/workflow-commands/background-commands.md +4 -3
- package/.claude/skills/workflow-commands/backlogrun-child.md +1 -1
- package/.claude/skills/workflow-commands/backlogrun-lanes.md +8 -6
- package/.claude/skills/workflow-commands/backlogrun-progress.md +1 -1
- package/.claude/skills/workflow-commands/backlogrun-steps.md +10 -10
- package/.claude/skills/workflow-commands/backlogrun.md +2 -2
- package/.claude/skills/workflow-commands/chain-rule.md +4 -2
- package/.claude/skills/workflow-commands/delegation.md +3 -3
- package/.claude/skills/workflow-commands/followup-reference.md +1 -1
- package/.claude/skills/workflow-commands/followup.md +7 -3
- package/.claude/skills/workflow-commands/fullrun-steps.md +3 -2
- package/.claude/skills/workflow-commands/fullrun.md +3 -2
- package/.claude/skills/workflow-commands/halfrun.md +16 -19
- package/.claude/skills/workflow-commands/issue-comments.md +1 -1
- package/.claude/skills/workflow-commands/issue-fold-existing.md +10 -10
- package/.claude/skills/workflow-commands/issue-scout.md +1 -1
- package/.claude/skills/workflow-commands/kickoff.md +9 -4
- package/.claude/skills/workflow-commands/latest-gate.md +1 -1
- package/.claude/skills/workflow-commands/needs-human-review.md +1 -1
- package/.claude/skills/workflow-commands/observation-filing.md +3 -3
- package/.claude/skills/workflow-commands/prerequisite.md +1 -1
- package/.claude/skills/workflow-commands/prrun.md +36 -0
- package/.claude/skills/workflow-commands/retrospective.md +1 -1
- package/.claude/skills/workflow-commands/working-tree-hold.md +22 -2
- package/.codex/hooks.json +16 -20
- package/.github/actions/setup-pnpm/action.yml +93 -0
- package/.github/dependabot.yml +5 -1
- package/.github/workflows/ci.yml +26 -128
- package/.github/workflows/pr-classification.yml +5 -41
- package/.github/workflows/publish.yml +33 -38
- package/.github/workflows/sonar-qube.yml +37 -4
- package/AGENTS.md +12 -2
- package/CLAUDE.md +15 -16
- package/GEMINI.md +14 -2
- package/README.md +59 -18
- package/SECURITY.md +36 -6
- package/cspell/index.yaml +2 -1
- package/dist/CLAUDE.md +15 -16
- package/dist/config-merge/index.js +15 -3
- package/dist/hooks/batch-guard.js +4 -4
- package/dist/hooks/{chunk-HJIISEAC.js → chunk-3C4YCCEF.js} +5 -13
- package/dist/hooks/{chunk-EJDX2TOB.js → chunk-7ZPFAVR7.js} +7 -88
- package/dist/hooks/{chunk-WQ4OSBSS.js → chunk-E54KGFEQ.js} +2 -2
- package/dist/hooks/{chunk-GQ7KP45M.js → chunk-IL27YTPH.js} +2 -2
- package/dist/hooks/{chunk-DMQN45FN.js → chunk-KHWHKJOM.js} +3 -3
- package/dist/hooks/{chunk-5BK3K7V4.js → chunk-M2XDCUKD.js} +997 -478
- package/dist/hooks/{chunk-7VPDUBRN.js → chunk-NKOG3XAV.js} +150 -153
- package/dist/hooks/{chunk-NJQOBE6L.js → chunk-O4LL4HTI.js} +2 -7
- package/dist/hooks/{chunk-NAS4C7GP.js → chunk-OIZUHPJI.js} +2 -2
- package/dist/hooks/{chunk-RLDX5SOC.js → chunk-UD24EAIL.js} +2084 -1412
- package/dist/hooks/codex-hook-adapter.js +10 -11
- package/dist/hooks/duplicate-read-guard.js +5 -5
- package/dist/hooks/format-edited.js +2 -2
- package/dist/hooks/inputs.json +279 -0
- package/dist/hooks/investigation-guard.js +5 -5
- package/dist/hooks/pretool-guard.js +9 -9
- package/dist/hooks/session-lang.js +0 -1
- package/dist/hooks/stop-guard.js +178 -324
- package/dist/josh.js +162 -119
- package/dist/managed-marker/index.js +2 -1
- package/dist/version/index.js +34 -58
- package/eslint/rules/promise.js +5 -0
- package/package.json +9 -4
- package/prompts/collaboration-workflow/issue-citation.md +5 -5
- package/prompts/collaboration-workflow/operating-rules.md +4 -4
- package/prompts/collaboration-workflow/overview.md +13 -1
- package/prompts/collaboration-workflow/report-format.md +1 -1
- package/prompts/collaboration-workflow/residency.md +3 -3
- package/prompts/collaboration-workflow/rule-delivery.md +1 -1
- package/prompts/collaboration-workflow/turn-batching.md +3 -3
- package/prompts/collaboration-workflow/upstream-interrupt.md +1 -1
- package/prompts/collaboration-workflow/wip-cap.md +25 -22
- package/prompts/collaboration-workflow.md +5 -8
- package/prompts/review-rubric.md +1 -1
- package/prompts/review.md +3 -3
- package/prompts/sonar-hotspot-handling.md +11 -3
- package/prompts/testing-guide.md +3 -3
- package/scripts/adopt/adopt-toolkits.ts +0 -2
- package/scripts/adopt/adopt.ts +0 -2
- package/scripts/agent/agent-argv.ts +0 -2
- package/scripts/agent/agent-diagnostics.ts +1 -1
- package/scripts/agent/agent-role-profile.ts +0 -7
- package/scripts/agent/claude-agent-argv.ts +0 -2
- package/scripts/agent/codex-agent-argv.ts +1 -1
- package/scripts/agent/codex-hooks.ts +92 -0
- package/scripts/agent/interactive-ask.ts +1 -1
- package/scripts/auto-ok/auto-ok-cli.ts +6 -16
- package/scripts/backlog/backlog-budget.ts +0 -2
- package/scripts/backlog/backlog-defect-priority.ts +2 -2
- package/scripts/backlog/backlog-drive-cli.ts +10 -8
- package/scripts/backlog/backlog-drive-named-offer.ts +16 -3
- package/scripts/backlog/backlog-drive-named.ts +2 -1
- package/scripts/backlog/backlog-drive.ts +76 -16
- package/scripts/backlog/backlog-named.ts +0 -3
- package/scripts/backlog/backlog-next.ts +9 -15
- package/scripts/backlog/backlog-offer-cli.ts +0 -5
- package/scripts/backlog/backlog-plan-cli.ts +1 -7
- package/scripts/backlog/backlog-plan.ts +1 -1
- package/scripts/backlog/backlog-pool.ts +3 -6
- package/scripts/backlog/backlog-rank.ts +2 -2
- package/scripts/backlog/backlog-ready.ts +19 -3
- package/scripts/backlog/backlog-scope.ts +1 -3
- package/scripts/backlog/backlog-stalled-detect.ts +2 -2
- package/scripts/backlog/backlog-stalled.ts +0 -1
- package/scripts/backlog/backlog-waves.ts +5 -2
- package/scripts/behavior/behavior-cli.ts +1 -1
- package/scripts/build/build-codex-hooks.ts +26 -0
- package/scripts/build/build-hooks.ts +85 -9
- package/scripts/build/hook-bundle-stamp.ts +111 -0
- package/scripts/cases/cases-cli.ts +1 -1
- package/scripts/cases/cases-logic.ts +1 -1
- package/scripts/ci/composite-actions.ts +30 -0
- package/scripts/ci/pr-classification.ts +3 -3
- package/scripts/claude/workflow-destination.ts +10 -1
- package/scripts/clone/clone-fingerprint.ts +0 -1
- package/scripts/clone/clone-scan-cli.ts +1 -1
- package/scripts/clone/clone-scan.ts +1 -1
- package/scripts/config-merge/json-format.ts +0 -1
- package/scripts/config-merge/patch-yaml-list.ts +1 -1
- package/scripts/cost-runtime/codex-usage.ts +2 -9
- package/scripts/cost-runtime/cost-attribute.ts +0 -1
- package/scripts/cost-runtime/cost-cli.ts +0 -3
- package/scripts/cost-runtime/cost-corpus.ts +0 -2
- package/scripts/cost-runtime/cost-format.ts +0 -3
- package/scripts/cost-runtime/cost-pricing.ts +0 -1
- package/scripts/cost-runtime/cost-tokens.ts +0 -1
- package/scripts/delegation/delegation-cli.ts +1 -1
- package/scripts/delegation/delegation-policy.ts +0 -1
- package/scripts/delegation/duplicate-read-guard.ts +0 -8
- package/scripts/delegation/fanout-cli.ts +1 -1
- package/scripts/delegation/fanout.ts +0 -2
- package/scripts/delegation/investigation-reads.ts +1 -164
- package/scripts/discovery/repo-map-logic.ts +0 -1
- package/scripts/discovery/repo-party-cli.ts +1 -1
- package/scripts/doctor/doctor-consumer.ts +4 -6
- package/scripts/doctor/doctor-logic.ts +0 -4
- package/scripts/doctor/doctor.ts +14 -9
- package/scripts/document/document-byte-budget.ts +4 -5
- package/scripts/document/document-byte-check.ts +0 -1
- package/scripts/document/document-read-cli.ts +0 -2
- package/scripts/document/document-section-cli.ts +1 -1
- package/scripts/document/document-section.ts +0 -3
- package/scripts/document/edit-files-cli.ts +0 -1
- package/scripts/document/entry-read-budget.ts +10 -2
- package/scripts/document/lane-child-read-set.ts +1 -6
- package/scripts/document/read-files-cli.ts +0 -4
- package/scripts/document/read-set-cli.ts +0 -2
- package/scripts/document/read-set-point-of-use.ts +1 -0
- package/scripts/document/read-set-pricing.ts +0 -1
- package/scripts/document/read-set-trim.ts +1 -1
- package/scripts/epic/epic-add.ts +1 -1
- package/scripts/epic/epic-audit-cli.ts +1 -4
- package/scripts/epic/epic-audit-orphans.ts +1 -3
- package/scripts/epic/epic-audit-rationale.ts +0 -1
- package/scripts/epic/epic-audit-report.ts +0 -2
- package/scripts/epic/epic-audit.ts +5 -4
- package/scripts/epic/epic-bundle-cli.ts +1 -1
- package/scripts/epic/epic-bundle-evidence.ts +0 -1
- package/scripts/epic/epic-bundle-referenced.ts +1 -5
- package/scripts/epic/epic-bundle.ts +0 -4
- package/scripts/epic/epic-busy.ts +4 -5
- package/scripts/epic/epic-candidate-confirm.ts +0 -5
- package/scripts/epic/epic-classify.ts +2 -2
- package/scripts/epic/epic-cli-argv.ts +0 -1
- package/scripts/epic/epic-close-comment.ts +1 -1
- package/scripts/epic/epic-close.ts +5 -2
- package/scripts/epic/epic-cross-repo.ts +2 -4
- package/scripts/epic/epic-decision.ts +0 -1
- package/scripts/epic/epic-fetch.ts +2 -2
- package/scripts/epic/epic-index.ts +2 -3
- package/scripts/epic/epic-issue.ts +1 -15
- package/scripts/epic/epic-lane-offer.ts +9 -8
- package/scripts/epic/epic-nested.ts +1 -1
- package/scripts/epic/epic-next-read.ts +1 -3
- package/scripts/epic/epic-next-views.ts +0 -1
- package/scripts/epic/epic-next.ts +1 -10
- package/scripts/epic/epic-parse.ts +0 -1
- package/scripts/epic/epic-promote.ts +0 -9
- package/scripts/epic/epic-rank.ts +2 -2
- package/scripts/epic/epic-read.ts +1 -2
- package/scripts/epic/epic-reconcile.ts +1 -1
- package/scripts/epic/epic-reference.ts +1 -13
- package/scripts/epic/epic-relation-recheck.ts +1 -1
- package/scripts/epic/epic-relations.ts +1 -1
- package/scripts/epic/epic-remove.ts +1 -1
- package/scripts/epic/epic-report.ts +0 -1
- package/scripts/epic/epic-run.ts +2 -3
- package/scripts/epic/epic-shape.ts +1 -1
- package/scripts/epic/epic-solo-stale.ts +107 -0
- package/scripts/epic/epic-solo.ts +3 -2
- package/scripts/epic/epic-triage.ts +1 -1
- package/scripts/epic/epic-validate.ts +1 -1
- package/scripts/epic/epic.ts +1 -1
- package/scripts/exports/unused-members-cli.ts +53 -0
- package/scripts/{git → followup}/followup-issue-number.ts +1 -6
- package/scripts/{git → followup}/git-followup-cleanup.ts +2 -1
- package/scripts/{git → followup}/git-followup-finish.ts +1 -3
- package/scripts/{git → followup}/git-followup-flush.ts +2 -2
- package/scripts/{git → followup}/git-followup-issue-close.ts +2 -2
- package/scripts/{git → followup}/git-followup-label.ts +4 -4
- package/scripts/followup/git-followup-merged.ts +112 -0
- package/scripts/{git → followup}/git-followup-pending.ts +1 -1
- package/scripts/{git → followup}/git-followup-workflow.ts +19 -11
- package/scripts/{git → followup}/git-pr-followup-wrapup.ts +9 -3
- package/scripts/{git → followup}/git-pr-followup.ts +53 -16
- package/scripts/gate/core-budget.ts +3 -9
- package/scripts/gate/gate-plan.ts +7 -4
- package/scripts/gate/gate-report.ts +0 -6
- package/scripts/gate/gate-tree.ts +1 -1
- package/scripts/gate/pre-commit-type-check.ts +0 -6
- package/scripts/gate/project-checks.ts +7 -8
- package/scripts/gate/scoped-green.ts +0 -1
- package/scripts/gate/type-check-step.ts +1 -1
- package/scripts/gate/verification-gate.ts +0 -2
- package/scripts/gh/fix-gh-packages.ts +15 -12
- package/scripts/gh/gh-spawn.ts +2 -2
- package/scripts/{git → gh}/git-ai-review-scan.ts +1 -5
- package/scripts/{git → gh}/git-gh-check.ts +2 -1
- package/scripts/{git → gh}/git-gh-exec.ts +1 -1
- package/scripts/{git → gh}/git-gh-failure.ts +1 -1
- package/scripts/{git → gh}/git-gh-helpers.ts +0 -1
- package/scripts/{git → gh}/git-gh-issue-list.ts +2 -0
- package/scripts/{git → gh}/git-gh-issue-read.ts +1 -1
- package/scripts/{git → gh}/git-gh-issue-rest.ts +6 -3
- package/scripts/{git → gh}/git-gh-pr-read.ts +24 -0
- package/scripts/{git → gh}/git-gh-pr-rest.ts +5 -2
- package/scripts/{git → gh}/git-gh-pr-review.ts +2 -2
- package/scripts/{git → gh}/git-gh-pr-rollup.ts +1 -3
- package/scripts/{git → gh}/git-gh-pr.ts +3 -1
- package/scripts/{git → gh}/git-pr-ai-review.ts +2 -5
- package/scripts/{git → gh}/git-pr-checks-eval.ts +0 -10
- package/scripts/{git → gh}/git-pr-checks-parse.ts +4 -20
- package/scripts/{git → gh}/git-pr-checks.ts +2 -1
- package/scripts/{git → gh}/git-pr-coderabbit.ts +2 -5
- package/scripts/{git → gh}/git-pr-confirmation.ts +1 -3
- package/scripts/{git → gh}/git-pr-managed-config.ts +2 -3
- package/scripts/{git → gh}/git-pr.ts +3 -3
- package/scripts/git/changed-file-scope.ts +0 -1
- package/scripts/git/git-branch.ts +3 -6
- package/scripts/git/git-commit.ts +1 -1
- package/scripts/git/git-common-directory.ts +80 -24
- package/scripts/git/git-error.ts +66 -9
- package/scripts/git/git-issue.ts +1 -1
- package/scripts/git/git-preflight.ts +2 -2
- package/scripts/git/git-prompt.ts +6 -31
- package/scripts/git/git-push.ts +1 -1
- package/scripts/git/git-staging.ts +1 -0
- package/scripts/git/git-status.ts +1 -1
- package/scripts/git/git-workflow.ts +1 -1
- package/scripts/git/gone-branch.ts +1 -0
- package/scripts/git/listing-cutoff.ts +1 -1
- package/scripts/git/main-merge.ts +1 -1
- package/scripts/git/main-sync.ts +19 -1
- package/scripts/git/parse-json-array.ts +0 -3
- package/scripts/git/repository-lock.ts +16 -16
- package/scripts/git/{git-stash.ts → stash/git-stash.ts} +1 -1
- package/scripts/git/{stash-pop-args.ts → stash/stash-pop-args.ts} +1 -1
- package/scripts/git/{stash-pop-cli.ts → stash/stash-pop-cli.ts} +0 -1
- package/scripts/git/{stash-sweep-lock.ts → stash/stash-sweep-lock.ts} +3 -3
- package/scripts/hooks/codex-hook-adapter.ts +0 -1
- package/scripts/hooks/edited-cspell.ts +1 -1
- package/scripts/hooks/format-edited-file.ts +2 -0
- package/scripts/hooks/pre-push-unit.ts +0 -4
- package/scripts/hooks/pretool-guard.ts +22 -4
- package/scripts/hooks/reserved-run.ts +1 -1
- package/scripts/hooks/step-zero-notice.ts +76 -0
- package/scripts/hooks/stop-guard.ts +47 -21
- package/scripts/init/claude-plugin-config.ts +4 -5
- package/scripts/init/hook-command-rewrite.ts +16 -8
- package/scripts/init/hook-launch.ts +41 -15
- package/scripts/init/init-basic.ts +2 -5
- package/scripts/init/init-logic.ts +7 -0
- package/scripts/init/init.ts +0 -3
- package/scripts/init/project-profile.ts +6 -11
- package/scripts/init/start-exec.ts +1 -1
- package/scripts/init/start-setup-pr.ts +6 -6
- package/scripts/init/start-steps.ts +1 -0
- package/scripts/issue/behavior-change-lint.ts +0 -1
- package/scripts/issue/defect-rate-cli.ts +3 -3
- package/scripts/issue/defect-rate.ts +1 -2
- package/scripts/{git → issue}/git-next-issues.ts +3 -3
- package/scripts/issue/issue-backlinks-cli.ts +1 -5
- package/scripts/issue/issue-cite-cli.ts +2 -6
- package/scripts/issue/issue-cite.ts +0 -2
- package/scripts/issue/issue-classification.ts +1 -9
- package/scripts/issue/issue-closing-pr.ts +4 -4
- package/scripts/issue/issue-comment-cli.ts +2 -2
- package/scripts/issue/issue-file-cli.ts +5 -5
- package/scripts/issue/issue-file.ts +2 -2
- package/scripts/issue/issue-fold-cli.ts +1 -1
- package/scripts/issue/issue-fold-existing-cli.ts +1 -1
- package/scripts/{git → issue}/issue-labels.ts +8 -0
- package/scripts/issue/issue-lint-cli.ts +1 -1
- package/scripts/issue/issue-merged.ts +2 -2
- package/scripts/{git → issue}/issue-rank.ts +1 -1
- package/scripts/issue/issue-read-cli.ts +8 -47
- package/scripts/issue/issue-read.ts +0 -2
- package/scripts/issue/issue-report-failures.ts +80 -0
- package/scripts/issue/issue-scout-cli.ts +1 -7
- package/scripts/issue/issue-scout-closed.ts +2 -2
- package/scripts/issue/issue-scout.ts +0 -2
- package/scripts/issue/issue-state-cli.ts +5 -46
- package/scripts/issue/issue-state.ts +1 -5
- package/scripts/issue/markdown-section.ts +1 -1
- package/scripts/issue/measure-rerun-cli.ts +1 -1
- package/scripts/issue/reproduction-measure.ts +1 -1
- package/scripts/josh/cli-body.ts +1 -1
- package/scripts/josh/file-map-stamp.ts +0 -3
- package/scripts/josh/josh-command-map.ts +2 -0
- package/scripts/josh/josh-commands-ai.ts +9 -102
- package/scripts/josh/josh-commands-backlog.ts +5 -1
- package/scripts/josh/josh-commands-development.ts +8 -1
- package/scripts/josh/josh-commands-issue.ts +2 -2
- package/scripts/josh/josh-commands-maintenance.ts +7 -0
- package/scripts/josh/josh-commands-project.ts +6 -0
- package/scripts/josh/josh-commands-run.ts +114 -0
- package/scripts/josh/josh-commands-versioning.ts +8 -0
- package/scripts/josh/josh-commands-workflow.ts +2 -2
- package/scripts/josh/path-decision.ts +0 -3
- package/scripts/josh/process-owner.ts +16 -0
- package/scripts/josh/session-language-cli.ts +0 -1
- package/scripts/lane/lane-await.ts +3 -6
- package/scripts/lane/lane-capacity.ts +6 -3
- package/scripts/lane/lane-child-invocation.ts +20 -7
- package/scripts/lane/lane-cli.ts +1 -4
- package/scripts/lane/lane-close.ts +1 -3
- package/scripts/lane/lane-dispatch.ts +3 -4
- package/scripts/lane/lane-environment.ts +0 -9
- package/scripts/lane/lane-handoff.ts +38 -0
- package/scripts/lane/lane-launch-cli.ts +21 -11
- package/scripts/lane/lane-open.ts +0 -3
- package/scripts/lane/lane-output.ts +0 -1
- package/scripts/lane/lane-registry.ts +9 -0
- package/scripts/lane/openai-lane-ship.ts +2 -0
- package/scripts/lane/openai-lane-supervisor-decision.ts +2 -1
- package/scripts/lane/openai-lane-supervisor.ts +6 -4
- package/scripts/lane/openai-review-broker.ts +3 -0
- package/scripts/lib/bounded-pool.ts +1 -0
- package/scripts/lib/json-value.ts +5 -4
- package/scripts/lib/poll.ts +3 -1
- package/scripts/lib/timed-fetch.ts +15 -0
- package/scripts/lib/timeouts.ts +13 -0
- package/scripts/{yaml → lib}/yaml-document.ts +3 -1
- package/scripts/{bytes → lines}/bytes-command.ts +0 -2
- package/scripts/lines/lines-command.ts +0 -1
- package/scripts/lint/lint-related-scope.ts +0 -1
- package/scripts/lint/lint-related.ts +1 -1
- package/scripts/{git → notify}/telegram-notify.ts +2 -2
- package/scripts/{git → notify}/telegram-test.ts +4 -4
- package/scripts/observations/observation-ledger-home.ts +0 -1
- package/scripts/observations/observation-ledger-line.ts +0 -1
- package/scripts/observations/observation-ledger-migrate.ts +1 -1
- package/scripts/observations/observations-flush-landing.ts +3 -3
- package/scripts/observations/observations-flush.ts +2 -2
- package/scripts/overrides/lockfile-overrides.ts +1 -1
- package/scripts/overrides/overrides-logic.ts +1 -1
- package/scripts/package/package-scout-cli.ts +2 -7
- package/scripts/package/package-scout.ts +0 -2
- package/scripts/propagate/propagate-git-failure.ts +0 -1
- package/scripts/propagate/propagate-git.ts +0 -2
- package/scripts/propagate/propagate-publish.ts +2 -3
- package/scripts/propagate/propagate-run.ts +0 -2
- package/scripts/propagate/propagate-steps.ts +3 -5
- package/scripts/propagate/propagate-targets.ts +0 -4
- package/scripts/propagate/propagate.ts +0 -4
- package/scripts/refactor/import-graph.ts +0 -1
- package/scripts/refactor/refactor-lint.ts +0 -2
- package/scripts/refactor/refactor-scan.ts +0 -1
- package/scripts/refactor/refactor-targets.ts +0 -1
- package/scripts/registry-migration/migrate-logic.ts +0 -2
- package/scripts/registry-migration/migrate.ts +19 -9
- package/scripts/release/github-release-cli.ts +8 -6
- package/scripts/release/github-release-environment.ts +46 -0
- package/scripts/release/github-release.ts +151 -94
- package/scripts/release/release-history.ts +0 -1
- package/scripts/release/release-plan.ts +0 -1
- package/scripts/release/release-publish.ts +2 -3
- package/scripts/release/release-scope-cli.ts +1 -2
- package/scripts/release/release-tag.ts +2 -4
- package/scripts/repo/auto-merge-setting-logic.ts +1 -4
- package/scripts/repo/repo-setting.ts +1 -1
- package/scripts/repo/repository-labels.ts +3 -3
- package/scripts/repo/required-checks-logic.ts +206 -0
- package/scripts/repo/required-checks-report.ts +71 -0
- package/scripts/repo/ruleset-check-cli.ts +53 -0
- package/scripts/repo/ruleset-check.ts +147 -0
- package/scripts/report/report-lint-cli.ts +0 -4
- package/scripts/review/disposition-cli.ts +1 -1
- package/scripts/review/live-evidence.ts +1 -1
- package/scripts/review/review-attest-cli.ts +0 -6
- package/scripts/review/review-attest.ts +4 -16
- package/scripts/review/review-brief-cli.ts +23 -6
- package/scripts/review/review-brief.ts +21 -8
- package/scripts/review/review-diff-parts.ts +89 -0
- package/scripts/review/review-diff-write.ts +97 -0
- package/scripts/review/review-finding-ledger.ts +0 -1
- package/scripts/review/review-record-cli.ts +1 -1
- package/scripts/review/review-record.ts +0 -1
- package/scripts/review/review-round2-cli.ts +1 -1
- package/scripts/review/review-stamps.ts +0 -3
- package/scripts/review/review-tree.ts +14 -2
- package/scripts/rules/decision-oracle-stage.ts +18 -0
- package/scripts/rules/decision-oracle.ts +10 -7
- package/scripts/rules/delivered-rules.ts +9 -1
- package/scripts/rules/destructive-command.ts +119 -0
- package/scripts/rules/direct-filing.ts +1 -1
- package/scripts/rules/file-body.ts +0 -3
- package/scripts/rules/filing-cap.ts +0 -2
- package/scripts/rules/gh-api.ts +7 -2
- package/scripts/rules/git-argv.ts +18 -7
- package/scripts/rules/git-force.ts +0 -2
- package/scripts/rules/implementation-cut.ts +0 -1
- package/scripts/rules/index-guard.ts +71 -0
- package/scripts/rules/issue-citation.ts +50 -25
- package/scripts/rules/lane-background.ts +15 -7
- package/scripts/rules/lane-park.ts +13 -6
- package/scripts/rules/last-prompt.ts +1 -0
- package/scripts/rules/oracle-consulted.ts +1 -1
- package/scripts/rules/oracle-firing.ts +1 -0
- package/scripts/rules/oracle-list-cli.ts +0 -3
- package/scripts/rules/permission-guards.ts +14 -0
- package/scripts/rules/protected-files.ts +74 -0
- package/scripts/rules/reply-language.ts +1 -1
- package/scripts/rules/rule-body-guard.ts +0 -3
- package/scripts/rules/rule-value-cli.ts +0 -1
- package/scripts/rules/shell-body-trigger.ts +0 -1
- package/scripts/rules/shell-segments.ts +0 -1
- package/scripts/rules/stop-rules.ts +13 -5
- package/scripts/rules/tail-commands.ts +1 -1
- package/scripts/rules/test-declared-commit.ts +1 -1
- package/scripts/rules/third-party-write.ts +0 -1
- package/scripts/rules/worktree-guard.ts +26 -9
- package/scripts/run/run-carry-cli.ts +0 -2
- package/scripts/run/run-carry-stash.ts +2 -2
- package/scripts/run/run-carry-streak.ts +1 -1
- package/scripts/run/run-cut-cli.ts +0 -7
- package/scripts/run/run-cut.ts +8 -54
- package/scripts/run/run-ending-cli.ts +1 -1
- package/scripts/run/run-ending.ts +1 -4
- package/scripts/run/run-entry-cli.ts +101 -24
- package/scripts/run/run-entry.ts +0 -1
- package/scripts/run/run-event-cli.ts +0 -2
- package/scripts/run/run-event-follow.ts +1 -0
- package/scripts/run/run-event-render.ts +1 -1
- package/scripts/run/run-event-scope.ts +53 -4
- package/scripts/run/run-event-stream.ts +0 -3
- package/scripts/run/run-event-watch.ts +1 -0
- package/scripts/run/run-halfrun-resume.ts +20 -7
- package/scripts/run/run-headless.ts +2 -2
- package/scripts/run/run-hold-cli.ts +33 -10
- package/scripts/run/run-hold.ts +25 -5
- package/scripts/run/run-issue-number.ts +1 -1
- package/scripts/run/run-liveness-cli.ts +1 -1
- package/scripts/run/run-liveness.ts +2 -3
- package/scripts/run/run-merge-cli.ts +5 -13
- package/scripts/run/run-merge-steps.ts +5 -5
- package/scripts/run/run-merge.ts +1 -1
- package/scripts/run/run-next-cli.ts +1 -1
- package/scripts/run/run-parent-cut-hook.ts +0 -1
- package/scripts/run/run-preflight.ts +2 -9
- package/scripts/run/run-prep-cli.ts +2 -2
- package/scripts/run/run-prep-locate.ts +1 -1
- package/scripts/run/run-progress-cli.ts +4 -7
- package/scripts/run/run-progress-clock.ts +6 -34
- package/scripts/run/run-progress-config.ts +0 -4
- package/scripts/run/run-progress-read.ts +1 -2
- package/scripts/run/run-progress.ts +1 -2
- package/scripts/run/run-prrun-resume.ts +117 -0
- package/scripts/run/run-report-cli.ts +1 -2
- package/scripts/run/run-report.ts +0 -1
- package/scripts/run/run-retrospective.ts +1 -1
- package/scripts/run/run-review-cli.ts +0 -3
- package/scripts/run/run-review-steps.ts +2 -0
- package/scripts/run/run-review.ts +0 -2
- package/scripts/run/run-ship-cli.ts +21 -3
- package/scripts/run/run-ship-detach.ts +1 -0
- package/scripts/run/run-ship-next.ts +106 -0
- package/scripts/run/run-ship-preflight.ts +1 -1
- package/scripts/run/run-ship-return.ts +8 -3
- package/scripts/run/run-ship-review-steps.ts +18 -4
- package/scripts/run/run-ship-review.ts +11 -0
- package/scripts/run/run-ship-scoped.ts +1 -0
- package/scripts/run/run-ship-steps.ts +1 -1
- package/scripts/run/run-ship.ts +0 -1
- package/scripts/run/run-stage-read.ts +62 -0
- package/scripts/run/run-stage.ts +160 -0
- package/scripts/run/run-status-cli.ts +1 -1
- package/scripts/run/run-step-cli.ts +21 -14
- package/scripts/run/run-step.ts +1 -1
- package/scripts/run/run-stop-notify.ts +1 -3
- package/scripts/run/run-stranded-cli.ts +0 -4
- package/scripts/run/run-stranded-detect.ts +2 -2
- package/scripts/run/run-tail-cli.ts +17 -11
- package/scripts/run/run-tail.ts +2 -0
- package/scripts/run/run-tidy-lanes.ts +2 -1
- package/scripts/run/run-tidy-stashes.ts +12 -12
- package/scripts/run/run-wake-cli.ts +2 -3
- package/scripts/run/run-wake-loop.ts +2 -2
- package/scripts/run/run-wake.ts +2 -4
- package/scripts/run/run-watcher-guard-cli.ts +0 -4
- package/scripts/run/run-watcher-guard.ts +9 -7
- package/scripts/run/run-watcher-hook.ts +1 -1
- package/scripts/safe-chain/ci-installer-pin.ts +11 -5
- package/scripts/safe-chain/project-config.ts +1 -1
- package/scripts/security/security-audit-provision-logic.ts +0 -1
- package/scripts/security/security-audit-provision.ts +3 -2
- package/scripts/security/security-audit.ts +0 -1
- package/scripts/security/security-updates-logic.ts +0 -1
- package/scripts/sonar/sonar-hotspots-cli.ts +10 -52
- package/scripts/sonar/sonar-hotspots.ts +0 -1
- package/scripts/sonar/sonar-new-code-cli.ts +150 -0
- package/scripts/sonar/sonar-new-code.ts +79 -0
- package/scripts/sonar/sonar-project.ts +97 -0
- package/scripts/split/split-assess-cli.ts +1 -1
- package/scripts/split/split-assess.ts +2 -5
- package/scripts/sync/managed-config-scope-cli.ts +1 -1
- package/scripts/sync/skill-migration.ts +0 -1
- package/scripts/sync/sync-hook-safety.ts +2 -3
- package/scripts/sync/sync.ts +1 -8
- package/scripts/sync/template-source-logic.ts +0 -1
- package/scripts/sync/workflow-pin-logic.ts +16 -28
- package/scripts/test/test-declared-logic.ts +0 -1
- package/scripts/test/test-declared.ts +0 -2
- package/scripts/test/test-red-commit.ts +2 -2
- package/scripts/test/test-red.ts +14 -7
- package/scripts/test/test-type-logic.ts +1 -1
- package/scripts/test/unit-worker-share.ts +7 -16
- package/scripts/time-runtime/time-batch-guard.ts +1 -2
- package/scripts/time-runtime/time-bundle-call.ts +0 -1
- package/scripts/time-runtime/time-bundles.ts +0 -4
- package/scripts/time-runtime/time-density-hook.ts +0 -2
- package/scripts/time-runtime/time-followup-stage.ts +1 -1
- package/scripts/time-runtime/time-format.ts +0 -73
- package/scripts/time-runtime/time-round-trips.ts +0 -4
- package/scripts/time-runtime/time-single-check.ts +1 -1
- package/scripts/time-runtime/time-spans.ts +1 -1
- package/scripts/time-runtime/time-transcript-line.ts +1 -2
- package/scripts/ui/ui-routes-cli.ts +0 -5
- package/scripts/ui/ui-routes.ts +0 -5
- package/scripts/version/effective-upstream.ts +2 -2
- package/scripts/version/latest-corepack.ts +7 -9
- package/scripts/version/latest-scope-cli.ts +0 -2
- package/scripts/version/latest-update.ts +0 -2
- package/scripts/version/npm-registry.ts +2 -2
- package/scripts/version/publishable-range-check.ts +1 -1
- package/scripts/version/release-hold.ts +0 -4
- package/scripts/version/running-binary.ts +2 -2
- package/scripts/version/version-check-logic.ts +0 -2
- package/scripts/version/version-remote.ts +3 -3
- package/scripts/version/version-targets.ts +4 -4
- package/templates/sonar-project.properties +28 -1
- package/templates/workflows/dependabot-auto-merge.yml +5 -3
- package/templates/workflows/github-release.yml +81 -0
- package/prompts/collaboration-workflow/cross-repo-epic.md +0 -5
- package/prompts/collaboration-workflow/epic-audit.md +0 -5
- package/prompts/collaboration-workflow/epic-bundle.md +0 -5
- package/scripts/init/plugin-install-hint.ts +0 -47
- package/scripts/version/parse-json.ts +0 -13
- /package/scripts/{git → followup}/git-followup-stages.ts +0 -0
- /package/scripts/{git → gh}/git-gh-api-path.ts +0 -0
- /package/scripts/{git → gh}/git-gh-command.ts +0 -0
- /package/scripts/{git → gh}/git-gh-issue-write.ts +0 -0
- /package/scripts/{git → gh}/git-gh-issue.ts +0 -0
- /package/scripts/{git → gh}/git-gh-pr-auto-merge.ts +0 -0
- /package/scripts/{git → gh}/git-gh-pr-snapshot.ts +0 -0
- /package/scripts/{git → gh}/git-gh-reachability.ts +0 -0
- /package/scripts/{git → gh}/git-gh-repo.ts +0 -0
- /package/scripts/{git → gh}/git-gh-rest-state.ts +0 -0
- /package/scripts/{git → gh}/git-pr-checks-watch.ts +0 -0
- /package/scripts/{git → gh}/git-pr-error.ts +0 -0
- /package/scripts/{git → gh}/git-pr-messages.ts +0 -0
- /package/scripts/{git → gh}/github-issue-url.ts +0 -0
- /package/scripts/git/{stash-orphans.ts → stash/stash-orphans.ts} +0 -0
- /package/scripts/{git → issue}/issue-reference.ts +0 -0
- /package/scripts/{git → lib}/animation-helpers.ts +0 -0
- /package/scripts/{git → lib}/git-animation.ts +0 -0
- /package/scripts/{git → notify}/git-notify.ts +0 -0
- /package/scripts/{git → notify}/telegram-test-logic.ts +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
lane_child_marker,
|
|
3
3
|
run_issue_number
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-E54KGFEQ.js";
|
|
5
5
|
import {
|
|
6
6
|
PLATFORM_TEMP_ROOT,
|
|
7
7
|
cost_blocks,
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
time_density_hook,
|
|
14
14
|
time_shell,
|
|
15
15
|
time_transcript_line
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-NKOG3XAV.js";
|
|
17
17
|
import {
|
|
18
18
|
ENV_FILE_NAME,
|
|
19
19
|
LANE_SEAT_KEY,
|
|
@@ -32,7 +32,6 @@ function is_josh_command(segment, names) {
|
|
|
32
32
|
return names.has(named.slice(time_shell.JOSH_PREFIX.length));
|
|
33
33
|
}
|
|
34
34
|
var shell_segments = {
|
|
35
|
-
SEGMENT_SEPARATOR,
|
|
36
35
|
is_josh_command,
|
|
37
36
|
segments_of
|
|
38
37
|
};
|
|
@@ -69,7 +68,7 @@ function bash_commands_of(line) {
|
|
|
69
68
|
function prior_bash_commands(tail) {
|
|
70
69
|
return tail.split("\n").flatMap((line) => bash_commands_of(line));
|
|
71
70
|
}
|
|
72
|
-
var tail_commands = {
|
|
71
|
+
var tail_commands = { is_bash_use, prior_bash_commands };
|
|
73
72
|
|
|
74
73
|
// scripts/rules/filing-cap.ts
|
|
75
74
|
var FILING_CAP = 10;
|
|
@@ -123,8 +122,6 @@ var filing_cap = {
|
|
|
123
122
|
FILING_CAP,
|
|
124
123
|
FILING_CAP_REASON,
|
|
125
124
|
ROW,
|
|
126
|
-
current_turn,
|
|
127
|
-
decide,
|
|
128
125
|
is_prompt_line,
|
|
129
126
|
prior_filing_count,
|
|
130
127
|
turn_filing_count
|
|
@@ -601,19 +598,20 @@ function hold_path(git_directory) {
|
|
|
601
598
|
return stamp_file.stamp_path(HOLD_PREFIX, git_directory);
|
|
602
599
|
}
|
|
603
600
|
async function worktree_directory() {
|
|
604
|
-
const
|
|
605
|
-
return
|
|
601
|
+
const directories2 = await git_command.git_directories();
|
|
602
|
+
return directories2[0];
|
|
606
603
|
}
|
|
607
604
|
async function is_linked_worktree() {
|
|
608
|
-
const
|
|
609
|
-
return
|
|
605
|
+
const directories2 = await git_command.git_directories();
|
|
606
|
+
return directories2[0] !== void 0 && directories2[0] !== directories2[1];
|
|
610
607
|
}
|
|
611
608
|
var run_hold_schema = z.object({
|
|
612
609
|
issue: z.string(),
|
|
613
610
|
taken_at: z.string(),
|
|
614
611
|
pid: z.number(),
|
|
615
612
|
is_fullrun: z.boolean().optional(),
|
|
616
|
-
is_halfrun_stop: z.boolean().optional()
|
|
613
|
+
is_halfrun_stop: z.boolean().optional(),
|
|
614
|
+
prrun_stop_head: z.string().optional()
|
|
617
615
|
});
|
|
618
616
|
function parse_hold(raw) {
|
|
619
617
|
try {
|
|
@@ -648,8 +646,12 @@ function write_hold(target, issue, now = /* @__PURE__ */ new Date()) {
|
|
|
648
646
|
function create_hold(target, issue, now = /* @__PURE__ */ new Date(), is_fullrun) {
|
|
649
647
|
return stamp_file.create_stamp(target, build_hold(issue, now, is_fullrun));
|
|
650
648
|
}
|
|
649
|
+
var HALFRUN_STOP_FIELDS = { is_halfrun_stop: true };
|
|
650
|
+
function create_stop_hold(target, issue, mark, now = /* @__PURE__ */ new Date()) {
|
|
651
|
+
return stamp_file.create_stamp(target, { ...build_hold(issue, now), ...mark });
|
|
652
|
+
}
|
|
651
653
|
function create_halfrun_stop_hold(target, issue, now = /* @__PURE__ */ new Date()) {
|
|
652
|
-
return
|
|
654
|
+
return create_stop_hold(target, issue, HALFRUN_STOP_FIELDS, now);
|
|
653
655
|
}
|
|
654
656
|
async function is_tree_dirty(directory) {
|
|
655
657
|
try {
|
|
@@ -705,8 +707,9 @@ var run_hold = {
|
|
|
705
707
|
UNNUMBERED_ISSUE,
|
|
706
708
|
classify,
|
|
707
709
|
create_halfrun_stop_hold,
|
|
710
|
+
create_stop_hold,
|
|
711
|
+
HALFRUN_STOP_FIELDS,
|
|
708
712
|
create_hold,
|
|
709
|
-
describe_holder,
|
|
710
713
|
foreign_release_message,
|
|
711
714
|
forced_release_message,
|
|
712
715
|
held_message,
|
|
@@ -715,7 +718,6 @@ var run_hold = {
|
|
|
715
718
|
is_own_hold,
|
|
716
719
|
is_tree_dirty,
|
|
717
720
|
own_release_command,
|
|
718
|
-
parse_hold,
|
|
719
721
|
race_message,
|
|
720
722
|
read_hold,
|
|
721
723
|
release_hold,
|
|
@@ -727,9 +729,6 @@ var run_hold = {
|
|
|
727
729
|
write_hold
|
|
728
730
|
};
|
|
729
731
|
|
|
730
|
-
// scripts/run/run-cut.ts
|
|
731
|
-
import { execFileSync } from "node:child_process";
|
|
732
|
-
|
|
733
732
|
// scripts/josh/agent-session-environment.ts
|
|
734
733
|
var SESSION_ID_KEY = "CLAUDE_CODE_SESSION_ID";
|
|
735
734
|
var PARENT_SESSION_KEYS = [
|
|
@@ -774,13 +773,13 @@ function is_declared(value) {
|
|
|
774
773
|
return value !== void 0 && value !== NO_HOST;
|
|
775
774
|
}
|
|
776
775
|
function loopback_proxy_keys(source, is_removed = is_loopback_proxy) {
|
|
777
|
-
const declared = PROXY_KEYS.filter((
|
|
778
|
-
const matched = declared.filter((
|
|
776
|
+
const declared = PROXY_KEYS.filter((key2) => is_declared(source[key2]));
|
|
777
|
+
const matched = declared.filter((key2) => is_removed(source[key2]));
|
|
779
778
|
const is_certificate_included = matched.length > 0 && matched.length === declared.length;
|
|
780
779
|
return is_certificate_included ? [...matched, PROXY_CERTIFICATE_KEY] : matched;
|
|
781
780
|
}
|
|
782
781
|
function to_removed(keys) {
|
|
783
|
-
return Object.fromEntries(keys.map((
|
|
782
|
+
return Object.fromEntries(keys.map((key2) => [key2, void 0]));
|
|
784
783
|
}
|
|
785
784
|
function removed_environment(source = process.env) {
|
|
786
785
|
return to_removed([...PARENT_SESSION_KEYS, ...loopback_proxy_keys(source)]);
|
|
@@ -883,27 +882,27 @@ function trimmed(value) {
|
|
|
883
882
|
return result === void 0 || result.length === EMPTY_LENGTH ? void 0 : result;
|
|
884
883
|
}
|
|
885
884
|
function override_value(role, field, environment2) {
|
|
886
|
-
const
|
|
887
|
-
const value = trimmed(environment2[
|
|
888
|
-
if (value !== void 0) return { key, value };
|
|
889
|
-
if (role !== WORKER) return { key, value: void 0 };
|
|
885
|
+
const key2 = ENV_KEYS[role][field];
|
|
886
|
+
const value = trimmed(environment2[key2]);
|
|
887
|
+
if (value !== void 0) return { key: key2, value };
|
|
888
|
+
if (role !== WORKER) return { key: key2, value: void 0 };
|
|
890
889
|
const legacy = LEGACY_WORKER_KEYS[field];
|
|
891
890
|
const legacy_value = trimmed(environment2[legacy]);
|
|
892
|
-
return legacy_value === void 0 ? { key, value: void 0 } : { key: legacy, value: legacy_value };
|
|
891
|
+
return legacy_value === void 0 ? { key: key2, value: void 0 } : { key: legacy, value: legacy_value };
|
|
893
892
|
}
|
|
894
893
|
function model_override(role, environment2, provider) {
|
|
895
|
-
const
|
|
896
|
-
return provider === OPENAI_PROVIDER ? { key, value: void 0 } : override_value(role, "model", environment2);
|
|
894
|
+
const key2 = ENV_KEYS[role].model;
|
|
895
|
+
return provider === OPENAI_PROVIDER ? { key: key2, value: void 0 } : override_value(role, "model", environment2);
|
|
897
896
|
}
|
|
898
|
-
function rejection(
|
|
899
|
-
return { kind: "rejected", note: `${
|
|
897
|
+
function rejection(key2, value, expected) {
|
|
898
|
+
return { kind: "rejected", note: `${key2}=${value} ${expected}, so the agent was not started` };
|
|
900
899
|
}
|
|
901
900
|
function resolved_effort(override, fallback) {
|
|
902
901
|
const parsed = EFFORT_SCHEMA.safeParse(override.value ?? fallback);
|
|
903
902
|
return parsed.success ? { kind: "effort", effort: parsed.data } : rejection(override.key, override.value ?? "", "is not an allowed effort");
|
|
904
903
|
}
|
|
905
904
|
function has_session(environment2, keys) {
|
|
906
|
-
return keys.some((
|
|
905
|
+
return keys.some((key2) => trimmed(environment2[key2]) !== void 0);
|
|
907
906
|
}
|
|
908
907
|
function session_rejection(is_conflicting) {
|
|
909
908
|
const note = is_conflicting ? "both Codex and Claude Code sessions were detected" : "no Codex or Claude Code session was detected";
|
|
@@ -976,17 +975,11 @@ function parse(value) {
|
|
|
976
975
|
}
|
|
977
976
|
var agent_role_profile = {
|
|
978
977
|
DEFAULT_PROFILES,
|
|
979
|
-
EFFORT_SCHEMA,
|
|
980
|
-
ENV_KEYS,
|
|
981
978
|
HANDED_PROVIDER_KEY,
|
|
982
979
|
IMPLEMENTATION_PHASE,
|
|
983
|
-
LEGACY_WORKER_KEYS,
|
|
984
980
|
MAX_VALUE_LENGTH,
|
|
985
981
|
OPENAI_PROFILES,
|
|
986
|
-
PHASE_EFFORT,
|
|
987
|
-
PHASE_SCHEMA,
|
|
988
982
|
PRE_GATE_PHASE,
|
|
989
|
-
PROVIDER_SCHEMA,
|
|
990
983
|
PROFILE_SCHEMA,
|
|
991
984
|
REVIEWER,
|
|
992
985
|
SCHEDULER,
|
|
@@ -996,7 +989,6 @@ var agent_role_profile = {
|
|
|
996
989
|
has_completion_callback,
|
|
997
990
|
is_safe_value,
|
|
998
991
|
parse,
|
|
999
|
-
phase_effort,
|
|
1000
992
|
resolve,
|
|
1001
993
|
resolve_provider,
|
|
1002
994
|
with_phase_effort
|
|
@@ -1103,7 +1095,6 @@ function decide2(input) {
|
|
|
1103
1095
|
}
|
|
1104
1096
|
var backlog_budget = {
|
|
1105
1097
|
ANSWERS,
|
|
1106
|
-
ANSWER_STOP_REASONS,
|
|
1107
1098
|
BLOCKED_REASON,
|
|
1108
1099
|
DEFAULT_IDLE_MINUTES,
|
|
1109
1100
|
DEFAULT_IDLE_MS,
|
|
@@ -1118,7 +1109,6 @@ var backlog_budget = {
|
|
|
1118
1109
|
UNREADABLE_REASON,
|
|
1119
1110
|
WATCH_VERDICT,
|
|
1120
1111
|
WHOLE_RUN_BUDGET_HOURS,
|
|
1121
|
-
WHOLE_RUN_BUDGET_MINUTES,
|
|
1122
1112
|
WHOLE_RUN_BUDGET_MS,
|
|
1123
1113
|
WHOLE_RUN_REASON,
|
|
1124
1114
|
decide: decide2,
|
|
@@ -1204,7 +1194,6 @@ var cost_pricing = {
|
|
|
1204
1194
|
CACHE_WRITE_5M_MULTIPLIER,
|
|
1205
1195
|
CACHE_WRITE_1H_MULTIPLIER,
|
|
1206
1196
|
CACHE_READ_MULTIPLIER,
|
|
1207
|
-
MODEL_PRICES,
|
|
1208
1197
|
resolve_price,
|
|
1209
1198
|
estimate_cost,
|
|
1210
1199
|
estimate_composition,
|
|
@@ -1243,6 +1232,9 @@ var context_cut_payback = {
|
|
|
1243
1232
|
var CONTEXT_CUT_THRESHOLD = context_cut_payback.break_even_context();
|
|
1244
1233
|
var RECENT_REQUEST_WINDOW = 10;
|
|
1245
1234
|
|
|
1235
|
+
// scripts/git/git-common-directory.ts
|
|
1236
|
+
import { execFileSync } from "node:child_process";
|
|
1237
|
+
|
|
1246
1238
|
// scripts/git/git-location-environment.ts
|
|
1247
1239
|
var GIT_LOCATION_VARIABLES = [
|
|
1248
1240
|
"GIT_ALTERNATE_OBJECT_DIRECTORIES",
|
|
@@ -1272,6 +1264,197 @@ function clear_git_location_variables() {
|
|
|
1272
1264
|
}
|
|
1273
1265
|
var git_location_environment = { clear_git_location_variables, location_free_environment };
|
|
1274
1266
|
|
|
1267
|
+
// scripts/git/git-common-directory.ts
|
|
1268
|
+
var OWN_GIT_DIRECTORY = 0;
|
|
1269
|
+
var COMMON_GIT_DIRECTORY = 1;
|
|
1270
|
+
var PROBE_TIMEOUT_MS = 5e3;
|
|
1271
|
+
var answers = /* @__PURE__ */ new Map();
|
|
1272
|
+
function probe_environment(cwd) {
|
|
1273
|
+
if (cwd === void 0) return process.env;
|
|
1274
|
+
return { ...process.env, ...git_location_environment.location_free_environment() };
|
|
1275
|
+
}
|
|
1276
|
+
function cache_key(cwd) {
|
|
1277
|
+
if (cwd !== void 0) return `explicit\0${cwd}`;
|
|
1278
|
+
const locations = GIT_LOCATION_VARIABLES.map((name) => process.env[name] ?? "");
|
|
1279
|
+
return ["inherited", process.cwd(), ...locations].join("\0");
|
|
1280
|
+
}
|
|
1281
|
+
function read_directories(cwd) {
|
|
1282
|
+
try {
|
|
1283
|
+
const output = execFileSync(
|
|
1284
|
+
git_utilities.get_git_command_for_spawn(),
|
|
1285
|
+
[...git_command.GIT_DIRECTORY_ARGUMENTS],
|
|
1286
|
+
{
|
|
1287
|
+
cwd,
|
|
1288
|
+
env: probe_environment(cwd),
|
|
1289
|
+
encoding: "utf8",
|
|
1290
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
1291
|
+
timeout: PROBE_TIMEOUT_MS
|
|
1292
|
+
}
|
|
1293
|
+
);
|
|
1294
|
+
return output.split("\n").filter((line) => line !== "");
|
|
1295
|
+
} catch {
|
|
1296
|
+
return [];
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
function directories(cwd) {
|
|
1300
|
+
const key2 = cache_key(cwd);
|
|
1301
|
+
const known = answers.get(key2);
|
|
1302
|
+
if (known !== void 0) return known;
|
|
1303
|
+
const read2 = read_directories(cwd);
|
|
1304
|
+
if (read2.length > 0) answers.set(key2, read2);
|
|
1305
|
+
return read2;
|
|
1306
|
+
}
|
|
1307
|
+
function own(cwd) {
|
|
1308
|
+
return directories(cwd)[OWN_GIT_DIRECTORY];
|
|
1309
|
+
}
|
|
1310
|
+
function repository(cwd) {
|
|
1311
|
+
return directories(cwd)[COMMON_GIT_DIRECTORY];
|
|
1312
|
+
}
|
|
1313
|
+
function select_linked(found) {
|
|
1314
|
+
const own_directory = found[OWN_GIT_DIRECTORY];
|
|
1315
|
+
const common = found[COMMON_GIT_DIRECTORY];
|
|
1316
|
+
return own_directory !== void 0 && common !== void 0 && own_directory !== common ? common : void 0;
|
|
1317
|
+
}
|
|
1318
|
+
function resolve2(cwd) {
|
|
1319
|
+
return select_linked(directories(cwd));
|
|
1320
|
+
}
|
|
1321
|
+
var git_common_directory = { directories, own, repository, resolve: resolve2, select_linked };
|
|
1322
|
+
|
|
1323
|
+
// scripts/run/run-ship-stage.ts
|
|
1324
|
+
import { z as z3 } from "zod";
|
|
1325
|
+
var STAGE = {
|
|
1326
|
+
PREFLIGHT: "preflight",
|
|
1327
|
+
REVIEW: "review",
|
|
1328
|
+
GATE: "gate",
|
|
1329
|
+
COMMIT: "commit",
|
|
1330
|
+
ROUND_TWO: "round-2",
|
|
1331
|
+
FOLLOWUP: "followup",
|
|
1332
|
+
REPORT: "report"
|
|
1333
|
+
};
|
|
1334
|
+
var PHASE = {
|
|
1335
|
+
START: "start",
|
|
1336
|
+
DONE: "done",
|
|
1337
|
+
FAILED: "failed",
|
|
1338
|
+
SKIPPED: "skipped"
|
|
1339
|
+
};
|
|
1340
|
+
var RECORD_PREFIX = "josh-ship-stages-";
|
|
1341
|
+
var RECORD_SEPARATOR = "-";
|
|
1342
|
+
var SKIP_COMMIT_FLAG = "--skip-commit";
|
|
1343
|
+
var SKIP_PUSH_FLAG = "--skip-push";
|
|
1344
|
+
var record_schema = z3.object({ done: z3.array(z3.string()) });
|
|
1345
|
+
function record_path(repository2, issue) {
|
|
1346
|
+
return stamp_file.stamp_path(`${RECORD_PREFIX}${issue}${RECORD_SEPARATOR}`, repository2);
|
|
1347
|
+
}
|
|
1348
|
+
function parse_done(raw) {
|
|
1349
|
+
try {
|
|
1350
|
+
return new Set(record_schema.parse(JSON.parse(raw)).done);
|
|
1351
|
+
} catch {
|
|
1352
|
+
return /* @__PURE__ */ new Set();
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
function read_done(target) {
|
|
1356
|
+
const raw = stamp_file.read_stamp_text(target);
|
|
1357
|
+
return raw === void 0 ? /* @__PURE__ */ new Set() : parse_done(raw);
|
|
1358
|
+
}
|
|
1359
|
+
function mark_done(target, stage) {
|
|
1360
|
+
const done = /* @__PURE__ */ new Set([...read_done(target), stage]);
|
|
1361
|
+
stamp_file.replace_stamp(target, { done: [...done] });
|
|
1362
|
+
}
|
|
1363
|
+
function clear(target) {
|
|
1364
|
+
stamp_file.remove_stamp(target);
|
|
1365
|
+
}
|
|
1366
|
+
function is_shipped(state) {
|
|
1367
|
+
return state.is_committed && state.is_pushed;
|
|
1368
|
+
}
|
|
1369
|
+
var DONE_BY = {
|
|
1370
|
+
// The preflight (joshuafolkken/kit#2946) asks what the commit stage would refuse on, so a commit is
|
|
1371
|
+
// its output as it is the gate's; a resumed commit stage still asks `git -y`'s own preflight.
|
|
1372
|
+
[STAGE.PREFLIGHT]: (_done, state) => state.is_merged || state.is_committed,
|
|
1373
|
+
// The `--review` round (joshuafolkken/kit#2427) precedes the commit, so a commit is its output as it
|
|
1374
|
+
// is the gate's. A record alone is not honored: before a commit the tree may have been edited since
|
|
1375
|
+
// the recorded round, and only a commit pins the tree that round read.
|
|
1376
|
+
[STAGE.REVIEW]: (_done, state) => state.is_merged || state.is_committed,
|
|
1377
|
+
[STAGE.GATE]: (_done, state) => state.is_merged || state.is_committed,
|
|
1378
|
+
[STAGE.COMMIT]: (done, state) => state.is_merged || done.has(STAGE.COMMIT) && is_shipped(state),
|
|
1379
|
+
// The round-2 pass (joshuafolkken/kit#2489) reads the pushed fix delta, so its record is honored only
|
|
1380
|
+
// while that push still stands — new work pushed on top reruns it.
|
|
1381
|
+
[STAGE.ROUND_TWO]: (done, state) => state.is_merged || done.has(STAGE.ROUND_TWO) && is_shipped(state),
|
|
1382
|
+
// A recorded followup still needs the shipped state: a record left by a merged ship whose report
|
|
1383
|
+
// failed must not pass over the followup of new, not-yet-pushed work on the same issue.
|
|
1384
|
+
[STAGE.FOLLOWUP]: (done, state) => state.is_merged || done.has(STAGE.FOLLOWUP) && is_shipped(state),
|
|
1385
|
+
[STAGE.REPORT]: (done) => done.has(STAGE.REPORT)
|
|
1386
|
+
};
|
|
1387
|
+
function is_done(stage, done, state, has_body = false) {
|
|
1388
|
+
if (has_body && stage === STAGE.COMMIT && !state.is_merged) return false;
|
|
1389
|
+
return DONE_BY[stage](done, state);
|
|
1390
|
+
}
|
|
1391
|
+
function commit_flags(state) {
|
|
1392
|
+
if (!state.is_committed) return [];
|
|
1393
|
+
return state.is_pushed ? [SKIP_COMMIT_FLAG, SKIP_PUSH_FLAG] : [SKIP_COMMIT_FLAG];
|
|
1394
|
+
}
|
|
1395
|
+
function event_text(issue, stage, phase) {
|
|
1396
|
+
return `#${issue} ${stage} ${phase}`;
|
|
1397
|
+
}
|
|
1398
|
+
var run_ship_stage = {
|
|
1399
|
+
PHASE,
|
|
1400
|
+
STAGE,
|
|
1401
|
+
clear,
|
|
1402
|
+
commit_flags,
|
|
1403
|
+
event_text,
|
|
1404
|
+
is_done,
|
|
1405
|
+
mark_done,
|
|
1406
|
+
read_done,
|
|
1407
|
+
record_path
|
|
1408
|
+
};
|
|
1409
|
+
|
|
1410
|
+
// scripts/run/run-ship-next.ts
|
|
1411
|
+
var { STAGE: STAGE2 } = run_ship_stage;
|
|
1412
|
+
var COMMAND = {
|
|
1413
|
+
LOG: "pnpm josh ship --log",
|
|
1414
|
+
DETACH: "pnpm josh ship --detach",
|
|
1415
|
+
DETACH_REVIEW: "pnpm josh ship --detach --review"
|
|
1416
|
+
};
|
|
1417
|
+
var ESCAPED_QUOTE = String.raw`'\''`;
|
|
1418
|
+
var BARE_WORD = /^[\w%+,./:=@-]+$/u;
|
|
1419
|
+
function quoted(title) {
|
|
1420
|
+
return `'${title.split("'").join(ESCAPED_QUOTE)}'`;
|
|
1421
|
+
}
|
|
1422
|
+
function shell_word(token) {
|
|
1423
|
+
return BARE_WORD.test(token) ? token : quoted(token);
|
|
1424
|
+
}
|
|
1425
|
+
function resume_of(args) {
|
|
1426
|
+
const cites = args.cites.flatMap((cite) => ["--cite", cite]);
|
|
1427
|
+
return {
|
|
1428
|
+
title: args.title,
|
|
1429
|
+
flags: [...args.notify, ...args.body, ...cites],
|
|
1430
|
+
is_review: args.is_review
|
|
1431
|
+
};
|
|
1432
|
+
}
|
|
1433
|
+
function ship_command(command, resume) {
|
|
1434
|
+
const words = [...resume.flags, resume.title].map((token) => shell_word(token));
|
|
1435
|
+
return [command, ...words].join(" ");
|
|
1436
|
+
}
|
|
1437
|
+
function detach_again(resume) {
|
|
1438
|
+
return `leave the fix uncommitted and run \`${ship_command(COMMAND.DETACH, resume)}\`.`;
|
|
1439
|
+
}
|
|
1440
|
+
function detach_as_started(resume) {
|
|
1441
|
+
const command = resume.is_review ? COMMAND.DETACH_REVIEW : COMMAND.DETACH;
|
|
1442
|
+
return `leave the fix uncommitted and run \`${ship_command(command, resume)}\`.`;
|
|
1443
|
+
}
|
|
1444
|
+
var AFTER_FIX = {
|
|
1445
|
+
[STAGE2.PREFLIGHT]: detach_as_started,
|
|
1446
|
+
[STAGE2.REVIEW]: detach_as_started,
|
|
1447
|
+
[STAGE2.GATE]: detach_as_started,
|
|
1448
|
+
[STAGE2.COMMIT]: detach_as_started,
|
|
1449
|
+
[STAGE2.ROUND_TWO]: detach_again,
|
|
1450
|
+
[STAGE2.FOLLOWUP]: detach_again,
|
|
1451
|
+
[STAGE2.REPORT]: detach_again
|
|
1452
|
+
};
|
|
1453
|
+
function next_step(issue, stage, resume) {
|
|
1454
|
+
return `Read the stopped report with \`${COMMAND.LOG} ${issue}\`, fix the ${stage} failure, then ${AFTER_FIX[stage](resume)}`;
|
|
1455
|
+
}
|
|
1456
|
+
var run_ship_next = { COMMAND, next_step, quoted, resume_of };
|
|
1457
|
+
|
|
1275
1458
|
// scripts/lane/lane-child-invocation.ts
|
|
1276
1459
|
var CHILD_INVOCATION = "fullrun";
|
|
1277
1460
|
var RESUME_GUIDE = ".claude/skills/workflow-commands/pre-gate-cut.md";
|
|
@@ -1292,12 +1475,12 @@ function outage_resume_invocation(issue) {
|
|
|
1292
1475
|
const preamble = `Resuming the lane child for issue #${issue} after an API disconnection \u2014 your session was restored with its full context, so do not re-read the workflow-commands entry documents (SKILL.md, fullrun.md). Continue the run from where it stopped: run \`pnpm josh run:step ${issue}\` to find the next action, redoing only the last step if it did not complete.`;
|
|
1293
1476
|
return `${preamble} ${child_invocation(issue)}`;
|
|
1294
1477
|
}
|
|
1295
|
-
function ship_stop_invocation(issue) {
|
|
1296
|
-
const
|
|
1297
|
-
|
|
1478
|
+
function ship_stop_invocation(issue, stop) {
|
|
1479
|
+
const opening = `Resuming the lane child for issue #${issue} after its detached ship supervisor stopped at a failed stage \u2014 do not re-read the workflow-commands entry documents (SKILL.md, fullrun.md).`;
|
|
1480
|
+
const next = stop === void 0 ? `Run \`pnpm josh run:step ${issue}\` and read the stopped report it names, fix what stopped the ship, then hand the region back per chain-rule.md.` : run_ship_next.next_step(issue, stop.stage, stop);
|
|
1481
|
+
return `${opening} ${next} Do not re-plan or re-implement what is already on the branch. ${child_invocation(issue)}`;
|
|
1298
1482
|
}
|
|
1299
1483
|
var lane_child_invocation = {
|
|
1300
|
-
CHILD_INVOCATION,
|
|
1301
1484
|
child_invocation,
|
|
1302
1485
|
outage_resume_invocation,
|
|
1303
1486
|
process_pattern,
|
|
@@ -1306,16 +1489,16 @@ var lane_child_invocation = {
|
|
|
1306
1489
|
};
|
|
1307
1490
|
|
|
1308
1491
|
// scripts/run/run-cut.ts
|
|
1309
|
-
import { z as
|
|
1492
|
+
import { z as z5 } from "zod";
|
|
1310
1493
|
|
|
1311
1494
|
// scripts/run/run-cut-handoff.ts
|
|
1312
1495
|
import { readFileSync } from "node:fs";
|
|
1313
|
-
import { z as
|
|
1314
|
-
var handoff_schema =
|
|
1315
|
-
instruction:
|
|
1316
|
-
completed:
|
|
1317
|
-
remaining:
|
|
1318
|
-
untouched:
|
|
1496
|
+
import { z as z4 } from "zod";
|
|
1497
|
+
var handoff_schema = z4.object({
|
|
1498
|
+
instruction: z4.string(),
|
|
1499
|
+
completed: z4.array(z4.string()),
|
|
1500
|
+
remaining: z4.array(z4.string()),
|
|
1501
|
+
untouched: z4.array(z4.string())
|
|
1319
1502
|
});
|
|
1320
1503
|
var COMPLETED_LABEL = "Completed";
|
|
1321
1504
|
var REMAINING_LABEL = "Remaining";
|
|
@@ -1384,22 +1567,20 @@ var { PRE_GATE_PHASE: PRE_GATE_PHASE2, IMPLEMENTATION_PHASE: IMPLEMENTATION_PHAS
|
|
|
1384
1567
|
var IMPLEMENTATION_CONTEXT_THRESHOLD = CONTEXT_CUT_THRESHOLD;
|
|
1385
1568
|
var CUT_MAX_AGE_MS = backlog_budget.WHOLE_RUN_BUDGET_MS;
|
|
1386
1569
|
var CUT_MAX_AGE_HOURS = backlog_budget.WHOLE_RUN_BUDGET_HOURS;
|
|
1387
|
-
var GIT_READ_TIMEOUT_MS = 5e3;
|
|
1388
|
-
var WORKTREE_DIRECTORY_INDEX = 0;
|
|
1389
1570
|
var END_COMMAND = "pnpm josh run:cut --end";
|
|
1390
1571
|
var READ_COMMAND = "pnpm josh run:cut --json";
|
|
1391
1572
|
var MAX_HANDOFF_BYTES = 8192;
|
|
1392
1573
|
var NONE_READ = { kind: "none" };
|
|
1393
1574
|
var UNREADABLE_READ2 = { kind: "unreadable" };
|
|
1394
|
-
var run_cut_schema =
|
|
1395
|
-
invocation:
|
|
1396
|
-
issue:
|
|
1397
|
-
branch:
|
|
1398
|
-
phase:
|
|
1399
|
-
cut_at:
|
|
1400
|
-
is_handed_off:
|
|
1575
|
+
var run_cut_schema = z5.object({
|
|
1576
|
+
invocation: z5.string(),
|
|
1577
|
+
issue: z5.string(),
|
|
1578
|
+
branch: z5.string(),
|
|
1579
|
+
phase: z5.string(),
|
|
1580
|
+
cut_at: z5.string(),
|
|
1581
|
+
is_handed_off: z5.boolean().optional(),
|
|
1401
1582
|
handoff: run_cut_handoff.handoff_schema.optional(),
|
|
1402
|
-
is_merge_relaunched:
|
|
1583
|
+
is_merge_relaunched: z5.boolean().optional()
|
|
1403
1584
|
});
|
|
1404
1585
|
function cut_path(git_directory) {
|
|
1405
1586
|
return stamp_file.stamp_path(CUT_PREFIX, git_directory);
|
|
@@ -1430,36 +1611,8 @@ function classify2(raw, now) {
|
|
|
1430
1611
|
function read_cut(target, now = /* @__PURE__ */ new Date()) {
|
|
1431
1612
|
return classify2(stamp_file.read_stamp_text(target), now);
|
|
1432
1613
|
}
|
|
1433
|
-
function git_directories_sync(cwd) {
|
|
1434
|
-
try {
|
|
1435
|
-
const output = execFileSync(
|
|
1436
|
-
git_utilities.get_git_command_for_spawn(),
|
|
1437
|
-
[...git_command.GIT_DIRECTORY_ARGUMENTS],
|
|
1438
|
-
// git's own diagnostics are discarded: a checkout it cannot describe is already the
|
|
1439
|
-
// `undefined` below, and a hook that let `fatal: not a git repository` through would print it
|
|
1440
|
-
// in front of a tool call that is about to be allowed.
|
|
1441
|
-
// A `PreToolUse` hook holds the tool call while it runs, so the read is bounded rather than
|
|
1442
|
-
// left to whatever git does.
|
|
1443
|
-
// `cwd` is set only by `lane_cut_sync`, which reads another lane's record from the parent.
|
|
1444
|
-
// With a `cwd`, the git location variables are cleared so it is what git answers for: a hook
|
|
1445
|
-
// exports `GIT_DIR`, which beats `cwd` and would name the hook's checkout instead
|
|
1446
|
-
// (joshuafolkken/kit#2515). Without one the environment is kept, so this read resolves the same
|
|
1447
|
-
// checkout as the asynchronous `git_directories` that writes the record.
|
|
1448
|
-
{
|
|
1449
|
-
cwd,
|
|
1450
|
-
env: cwd === void 0 ? process.env : { ...process.env, ...git_location_environment.location_free_environment() },
|
|
1451
|
-
encoding: "utf8",
|
|
1452
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
1453
|
-
timeout: GIT_READ_TIMEOUT_MS
|
|
1454
|
-
}
|
|
1455
|
-
);
|
|
1456
|
-
return output.split("\n").filter((line) => line !== "");
|
|
1457
|
-
} catch {
|
|
1458
|
-
return [];
|
|
1459
|
-
}
|
|
1460
|
-
}
|
|
1461
1614
|
function worktree_git_directory_sync() {
|
|
1462
|
-
return
|
|
1615
|
+
return git_common_directory.own();
|
|
1463
1616
|
}
|
|
1464
1617
|
function carried_cut_sync(now = /* @__PURE__ */ new Date(), directory = worktree_git_directory_sync()) {
|
|
1465
1618
|
if (directory === void 0) return void 0;
|
|
@@ -1467,7 +1620,7 @@ function carried_cut_sync(now = /* @__PURE__ */ new Date(), directory = worktree
|
|
|
1467
1620
|
return read2.kind === "carried" ? read2.cut : void 0;
|
|
1468
1621
|
}
|
|
1469
1622
|
function lane_cut_sync(lane_directory) {
|
|
1470
|
-
const directory =
|
|
1623
|
+
const directory = git_common_directory.own(lane_directory);
|
|
1471
1624
|
if (directory === void 0) return void 0;
|
|
1472
1625
|
const cut = carried_cut_sync(/* @__PURE__ */ new Date(), directory);
|
|
1473
1626
|
return cut === void 0 ? void 0 : { target: cut_path(directory), cut };
|
|
@@ -1658,7 +1811,7 @@ var run_tail = {
|
|
|
1658
1811
|
|
|
1659
1812
|
// scripts/rules/lane-background.ts
|
|
1660
1813
|
var LONG_RUNNING_COMMANDS = new Set(
|
|
1661
|
-
["gate", "git", "followup"].map((name) => `${time_shell.JOSH_PREFIX}${name}`)
|
|
1814
|
+
["gate", "git", "followup", "ship"].map((name) => `${time_shell.JOSH_PREFIX}${name}`)
|
|
1662
1815
|
);
|
|
1663
1816
|
var BACKGROUND_KEY2 = "run_in_background";
|
|
1664
1817
|
function is_backgrounded2(input) {
|
|
@@ -1679,8 +1832,8 @@ function unfinished_ids(tail, launched_ids) {
|
|
|
1679
1832
|
const lines = tail.split("\n").map((line) => time_transcript_line.parse_line(line));
|
|
1680
1833
|
const finished = new Set(lines.map((line) => line?.finished_background ?? ""));
|
|
1681
1834
|
const blocks = lines.flatMap((line) => line?.blocks ?? []);
|
|
1682
|
-
const
|
|
1683
|
-
return
|
|
1835
|
+
const launched2 = blocks.flatMap((block) => launched_ids(block));
|
|
1836
|
+
return launched2.filter((id) => id !== "" && !finished.has(id));
|
|
1684
1837
|
}
|
|
1685
1838
|
function pending_background_ids(tail) {
|
|
1686
1839
|
return unfinished_ids(tail, (block) => [block.background_id, block.agent_id]);
|
|
@@ -1688,7 +1841,7 @@ function pending_background_ids(tail) {
|
|
|
1688
1841
|
function pending_agent_ids(tail) {
|
|
1689
1842
|
return unfinished_ids(tail, (block) => [block.agent_id]);
|
|
1690
1843
|
}
|
|
1691
|
-
var LANE_BACKGROUND_REASON = '\u26D4 lane background: this session is a dispatched lane child (`JOSH_LANE_CHILD`), a headless `claude -p` process whose background Bash tasks are killed when the turn ends \u2014 so a backgrounded `josh gate` / `josh git` / `josh followup` never re-invokes you; it dies at `exit code 143` (joshuafolkken/kit#2704, measured on the #2606 child: implementation, review and live verification done, the run parked instead of merged). Hand the gate-to-merge region to the detached supervisor instead: `pnpm josh ship --detach --review "<title> #<N>"` (add `--cite <N>`), then end the turn on `launched` / `busy
|
|
1844
|
+
var LANE_BACKGROUND_REASON = '\u26D4 lane background: this session is a dispatched lane child (`JOSH_LANE_CHILD`), a headless `claude -p` process whose background Bash tasks are killed when the turn ends \u2014 so a backgrounded `josh gate` / `josh git` / `josh followup` / `josh ship` never re-invokes you; it dies at `exit code 143` (joshuafolkken/kit#2704, measured on the #2606 child: implementation, review and live verification done, the run parked instead of merged). Hand the gate-to-merge region to the detached supervisor instead: `pnpm josh ship --detach --review "<title> #<N>"` (add `--cite <N>`) issued in the foreground \u2014 its preflight runs in this process before the supervisor exists, so a backgrounded `ship` dies with the turn (joshuafolkken/kit#3027) \u2014 then end the turn on `launched` / `busy`. `.claude/skills/workflow-commands/chain-rule.md` step 0 is the single source. A single check you must read before continuing runs in the foreground within the tool timeout; the commit-push step does not \u2014 in a child it too belongs to the detached ship, in either spelling. This rule fires on every occurrence, not once per run.';
|
|
1692
1845
|
var LANE_BACKGROUND_STOP_REASON = "\u26D4 lane background stop: this is a dispatched lane child (`JOSH_LANE_CHILD`) and a background task it launched has not finished \u2014 ending this headless turn kills it, and nothing re-invokes you afterwards (joshuafolkken/kit#2704). Do not send a notification and do not stop: wait for the task in the foreground and act on its result, or re-issue the work through `pnpm josh ship --detach`, whose supervisor outlives the turn (`.claude/skills/workflow-commands/chain-rule.md` step 0). Do not repeat your previous reply.";
|
|
1693
1846
|
var ROW2 = {
|
|
1694
1847
|
id: "lane-background",
|
|
@@ -1705,1234 +1858,1960 @@ var lane_background = {
|
|
|
1705
1858
|
pending_background_ids
|
|
1706
1859
|
};
|
|
1707
1860
|
|
|
1708
|
-
// scripts/
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
var
|
|
1715
|
-
var
|
|
1716
|
-
var
|
|
1717
|
-
var
|
|
1718
|
-
var
|
|
1719
|
-
var
|
|
1720
|
-
var
|
|
1721
|
-
var
|
|
1722
|
-
var
|
|
1723
|
-
var
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
}
|
|
1738
|
-
|
|
1739
|
-
name: SPLIT_ROUTE_LABEL,
|
|
1740
|
-
color: "0e8a16",
|
|
1741
|
-
description: "A child issue created by a split (split-assessment.md)"
|
|
1742
|
-
},
|
|
1743
|
-
{
|
|
1744
|
-
name: TIER_A_ROUTE_LABEL,
|
|
1745
|
-
color: "d93f0b",
|
|
1746
|
-
description: "Filed Tier A during implementation \u2014 an upstream defect or a prerequisite"
|
|
1861
|
+
// scripts/josh/process-identity.ts
|
|
1862
|
+
import { execFileSync as execFileSync2, spawnSync } from "node:child_process";
|
|
1863
|
+
import { randomUUID } from "node:crypto";
|
|
1864
|
+
import { readFileSync as readFileSync2, rmSync } from "node:fs";
|
|
1865
|
+
import { createServer } from "node:net";
|
|
1866
|
+
import path from "node:path";
|
|
1867
|
+
var PS_COMMAND = "/bin/ps";
|
|
1868
|
+
var FORMAT_FLAG = "-o";
|
|
1869
|
+
var START_TIME_FORMAT = "lstart=";
|
|
1870
|
+
var PID_FLAG = "-p";
|
|
1871
|
+
var PROBE_ENVIRONMENT = { TZ: "UTC", LC_ALL: "C" };
|
|
1872
|
+
var PROBE_TIMEOUT_MS2 = 2e3;
|
|
1873
|
+
var LIVENESS_SIGNAL = 0;
|
|
1874
|
+
var LOWEST_REAL_PID = 1;
|
|
1875
|
+
var PROC_START_FIELD_INDEX = 19;
|
|
1876
|
+
var BEACON_SCHEME = "socket:";
|
|
1877
|
+
var BEACON_SUFFIX = ".sock";
|
|
1878
|
+
var BEACON_PREFIX = `josh-process-identity-${String(process.getuid?.() ?? "")}-`;
|
|
1879
|
+
var BEACON_ID_LENGTH = 36;
|
|
1880
|
+
var BEACON_ID_PATTERN = /^[\da-f-]+$/u;
|
|
1881
|
+
var WINDOWS_PLATFORM = "win32";
|
|
1882
|
+
var SOCKET_PROBE_SOURCE = "const net=require('node:net');const socket=net.createConnection(process.argv[1]);socket.once('connect',()=>process.exit(0));socket.once('error',()=>process.exit(1));socket.setTimeout(1000,()=>process.exit(1));";
|
|
1883
|
+
var beacons = /* @__PURE__ */ new Map();
|
|
1884
|
+
var exit_cleanup = { is_registered: false };
|
|
1885
|
+
function is_live_pid(pid) {
|
|
1886
|
+
if (pid < LOWEST_REAL_PID) return false;
|
|
1887
|
+
try {
|
|
1888
|
+
process.kill(pid, LIVENESS_SIGNAL);
|
|
1889
|
+
return true;
|
|
1890
|
+
} catch {
|
|
1891
|
+
return false;
|
|
1747
1892
|
}
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
},
|
|
1758
|
-
{
|
|
1759
|
-
name: DEPTH_1_LABEL,
|
|
1760
|
-
color: "fbc02d",
|
|
1761
|
-
description: "Depth 1 \u2014 the run orchestration that executes an Issue (SKILL.md \xA72i)"
|
|
1762
|
-
},
|
|
1763
|
-
{
|
|
1764
|
-
name: DEPTH_2_LABEL,
|
|
1765
|
-
color: "c5def5",
|
|
1766
|
-
description: "Depth 2 \u2014 what measures a run (SKILL.md \xA72i)"
|
|
1893
|
+
}
|
|
1894
|
+
function read_proc_start(pid) {
|
|
1895
|
+
try {
|
|
1896
|
+
const stat = readFileSync2(`/proc/${String(pid)}/stat`, "utf8");
|
|
1897
|
+
const fields = stat.slice(stat.lastIndexOf(")") + 1).trim().split(/\s+/u);
|
|
1898
|
+
const start = fields[PROC_START_FIELD_INDEX];
|
|
1899
|
+
return start === void 0 ? void 0 : `proc:${start}`;
|
|
1900
|
+
} catch {
|
|
1901
|
+
return void 0;
|
|
1767
1902
|
}
|
|
1768
|
-
];
|
|
1769
|
-
var WORKFLOW_LABELS = [
|
|
1770
|
-
{
|
|
1771
|
-
name: EPIC_LABEL,
|
|
1772
|
-
color: "5319e7",
|
|
1773
|
-
description: "Tracks a batch of child issues from one split"
|
|
1774
|
-
},
|
|
1775
|
-
{ name: IN_PROGRESS_LABEL, color: "0075ca", description: "Work is actively in progress" },
|
|
1776
|
-
{
|
|
1777
|
-
name: RUN_SOLO_LABEL,
|
|
1778
|
-
color: "b60205",
|
|
1779
|
-
description: "Runs alone in a backlogrun: nothing starts beside it"
|
|
1780
|
-
},
|
|
1781
|
-
{
|
|
1782
|
-
name: RUN_LANE_LABEL,
|
|
1783
|
-
color: "0e8a16",
|
|
1784
|
-
description: "Judged safe to run beside others in a backlogrun"
|
|
1785
|
-
},
|
|
1786
|
-
{
|
|
1787
|
-
name: PRIORITY_HIGH_LABEL,
|
|
1788
|
-
color: "e99695",
|
|
1789
|
-
description: "Offered first in a backlogrun; only a person removes it"
|
|
1790
|
-
},
|
|
1791
|
-
...FILING_ROUTE_LABELS,
|
|
1792
|
-
...DEPTH_LABELS
|
|
1793
|
-
];
|
|
1794
|
-
var BUGFIX_LABEL = "bugfix";
|
|
1795
|
-
var OTHER_CHANGE_LABEL = "other-change";
|
|
1796
|
-
var IGNORE_FOR_RELEASE_LABEL = "ignore-for-release";
|
|
1797
|
-
var RELEASE_CLASSIFICATION_NAMES = [
|
|
1798
|
-
BREAKING_CHANGE_LABEL,
|
|
1799
|
-
ENHANCEMENT_LABEL,
|
|
1800
|
-
BUGFIX_LABEL,
|
|
1801
|
-
OTHER_CHANGE_LABEL,
|
|
1802
|
-
IGNORE_FOR_RELEASE_LABEL
|
|
1803
|
-
];
|
|
1804
|
-
var RELEASE_CLASSIFICATION_METADATA = {
|
|
1805
|
-
[BREAKING_CHANGE_LABEL]: { color: "d93f0b", description: "Release: a breaking change (major)" },
|
|
1806
|
-
[ENHANCEMENT_LABEL]: { color: "84b6eb", description: "Release: a new feature (minor)" },
|
|
1807
|
-
[BUGFIX_LABEL]: { color: "d73a4a", description: "Release: a bug fix (patch)" },
|
|
1808
|
-
[OTHER_CHANGE_LABEL]: { color: "c2e0c6", description: "Release: any other change (patch)" },
|
|
1809
|
-
[IGNORE_FOR_RELEASE_LABEL]: { color: "cfd3d7", description: "Release: left out of the notes" }
|
|
1810
|
-
};
|
|
1811
|
-
var RELEASE_CLASSIFICATION_LABELS = RELEASE_CLASSIFICATION_NAMES.map((name) => ({ name, ...RELEASE_CLASSIFICATION_METADATA[name] }));
|
|
1812
|
-
var REPOSITORY_LABELS = [
|
|
1813
|
-
...WORKFLOW_LABELS,
|
|
1814
|
-
...RELEASE_CLASSIFICATION_LABELS
|
|
1815
|
-
];
|
|
1816
|
-
function has_any_label(labels, wanted) {
|
|
1817
|
-
return (labels ?? []).some((label2) => wanted.has(label2.name.toLowerCase()));
|
|
1818
1903
|
}
|
|
1819
|
-
function
|
|
1820
|
-
|
|
1821
|
-
|
|
1904
|
+
function read_ps_start(pid) {
|
|
1905
|
+
try {
|
|
1906
|
+
const printed = execFileSync2(
|
|
1907
|
+
PS_COMMAND,
|
|
1908
|
+
[FORMAT_FLAG, START_TIME_FORMAT, PID_FLAG, String(pid)],
|
|
1909
|
+
{
|
|
1910
|
+
encoding: "utf8",
|
|
1911
|
+
timeout: PROBE_TIMEOUT_MS2,
|
|
1912
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
1913
|
+
env: PROBE_ENVIRONMENT
|
|
1914
|
+
}
|
|
1915
|
+
).trim();
|
|
1916
|
+
return printed.length > 0 ? printed : void 0;
|
|
1917
|
+
} catch {
|
|
1918
|
+
return void 0;
|
|
1919
|
+
}
|
|
1822
1920
|
}
|
|
1823
|
-
|
|
1824
|
-
|
|
1921
|
+
var START_PROBES = { read_proc_start, read_ps_start };
|
|
1922
|
+
function safe_probe(probe, pid) {
|
|
1923
|
+
try {
|
|
1924
|
+
return probe(pid);
|
|
1925
|
+
} catch {
|
|
1926
|
+
return void 0;
|
|
1927
|
+
}
|
|
1825
1928
|
}
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
var NOTIFY_COMMANDS = /* @__PURE__ */ new Set(["notify"]);
|
|
1829
|
-
var CONFIRMATION_TASK_TYPE = /(?:^|\s)--task-type[=\s]+["']?confirmation\b/u;
|
|
1830
|
-
function is_confirmation_notify(command) {
|
|
1831
|
-
return shell_segments.segments_of(command).some(
|
|
1832
|
-
(segment) => shell_segments.is_josh_command(segment, NOTIFY_COMMANDS) && CONFIRMATION_TASK_TYPE.test(segment)
|
|
1833
|
-
);
|
|
1834
|
-
}
|
|
1835
|
-
var NOTIFY_INVOCATION = /josh\s+(?:notify|nf)\b/u;
|
|
1836
|
-
function mentions_confirmation_notify(text) {
|
|
1837
|
-
return NOTIFY_INVOCATION.test(text) && CONFIRMATION_TASK_TYPE.test(text);
|
|
1838
|
-
}
|
|
1839
|
-
function is_unparked_stop(command, is_lane_child = lane_child_marker.is_child_of(process.cwd())) {
|
|
1840
|
-
if (!is_confirmation_notify(command)) return false;
|
|
1841
|
-
return is_lane_child;
|
|
1842
|
-
}
|
|
1843
|
-
var APPLIES_NEEDS_DECISION = new RegExp(
|
|
1844
|
-
String.raw`(?:labels\[\]=|--add-label[= ]'?)${NEEDS_DECISION_LABEL}\b`,
|
|
1845
|
-
"u"
|
|
1846
|
-
);
|
|
1847
|
-
function records_the_park(command) {
|
|
1848
|
-
return APPLIES_NEEDS_DECISION.test(command);
|
|
1929
|
+
function read_start(pid, probes = START_PROBES) {
|
|
1930
|
+
return safe_probe(probes.read_proc_start, pid) ?? safe_probe(probes.read_ps_start, pid);
|
|
1849
1931
|
}
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
records_the_park
|
|
1857
|
-
};
|
|
1858
|
-
|
|
1859
|
-
// scripts/discovery/repo-discovery.ts
|
|
1860
|
-
import { existsSync, readdirSync, readFileSync as readFileSync2, statSync } from "node:fs";
|
|
1861
|
-
import path from "node:path";
|
|
1862
|
-
|
|
1863
|
-
// scripts/discovery/repo-origin.ts
|
|
1864
|
-
var GITHUB_HOST = "github.com";
|
|
1865
|
-
var SSH_ALIAS_PATTERN = /^github(?:-\w+)*$/u;
|
|
1866
|
-
var GIT_SUFFIX = ".git";
|
|
1867
|
-
var PATH_SEPARATOR2 = "/";
|
|
1868
|
-
var USER_SEPARATOR = "@";
|
|
1869
|
-
var HOST_SEPARATOR = ":";
|
|
1870
|
-
var OWNER_INDEX = 0;
|
|
1871
|
-
var REPO_INDEX = 1;
|
|
1872
|
-
var REPO_PATH_SEGMENTS = 2;
|
|
1873
|
-
var NOT_FOUND = -1;
|
|
1874
|
-
var SECTION_PREFIX = "[";
|
|
1875
|
-
var ORIGIN_SECTION = /^\[remote\s+"origin"\]$/u;
|
|
1876
|
-
var URL_KEY = "url";
|
|
1877
|
-
function is_github_hostname(host) {
|
|
1878
|
-
return host.toLowerCase() === GITHUB_HOST;
|
|
1932
|
+
function close_beacon(token) {
|
|
1933
|
+
const server = beacons.get(token);
|
|
1934
|
+
if (server === void 0) return;
|
|
1935
|
+
beacons.delete(token);
|
|
1936
|
+
server.close();
|
|
1937
|
+
rmSync(token.slice(BEACON_SCHEME.length), { force: true });
|
|
1879
1938
|
}
|
|
1880
|
-
function
|
|
1881
|
-
const
|
|
1882
|
-
return is_github_hostname(normalized) || SSH_ALIAS_PATTERN.test(normalized);
|
|
1939
|
+
function close_beacons() {
|
|
1940
|
+
for (const token of beacons.keys()) close_beacon(token);
|
|
1883
1941
|
}
|
|
1884
|
-
function
|
|
1885
|
-
|
|
1942
|
+
function ensure_exit_cleanup() {
|
|
1943
|
+
if (exit_cleanup.is_registered) return;
|
|
1944
|
+
exit_cleanup.is_registered = true;
|
|
1945
|
+
process.once("exit", close_beacons);
|
|
1886
1946
|
}
|
|
1887
|
-
function
|
|
1888
|
-
const segments = repository_path.split(PATH_SEPARATOR2).filter((segment) => segment !== "");
|
|
1889
|
-
if (segments.length !== REPO_PATH_SEGMENTS) return void 0;
|
|
1890
|
-
const owner = segments[OWNER_INDEX] ?? "";
|
|
1891
|
-
const repo = strip_git_suffix(segments[REPO_INDEX] ?? "");
|
|
1892
|
-
return repo === "" ? void 0 : { owner, repo };
|
|
1947
|
+
function ignore_beacon_error() {
|
|
1893
1948
|
}
|
|
1894
|
-
function
|
|
1895
|
-
|
|
1896
|
-
const authority = user_end === NOT_FOUND ? url : url.slice(user_end + 1);
|
|
1897
|
-
const host_end = authority.indexOf(HOST_SEPARATOR);
|
|
1898
|
-
if (host_end === NOT_FOUND) return void 0;
|
|
1899
|
-
if (!is_github_ssh_host(authority.slice(0, host_end))) return void 0;
|
|
1900
|
-
return to_identity(authority.slice(host_end + 1));
|
|
1949
|
+
function bind_beacon(target) {
|
|
1950
|
+
return createServer().on("error", ignore_beacon_error).listen(target);
|
|
1901
1951
|
}
|
|
1902
|
-
function
|
|
1952
|
+
function try_bind_beacon(bind, target) {
|
|
1903
1953
|
try {
|
|
1904
|
-
const
|
|
1905
|
-
return
|
|
1954
|
+
const server = bind(target);
|
|
1955
|
+
return server.listening ? server : void 0;
|
|
1906
1956
|
} catch {
|
|
1907
1957
|
return void 0;
|
|
1908
1958
|
}
|
|
1909
1959
|
}
|
|
1910
|
-
function
|
|
1911
|
-
const
|
|
1912
|
-
|
|
1913
|
-
|
|
1960
|
+
function open_beacon(bind = bind_beacon) {
|
|
1961
|
+
const target = path.join(PLATFORM_TEMP_ROOT, `${BEACON_PREFIX}${randomUUID()}${BEACON_SUFFIX}`);
|
|
1962
|
+
const token = `${BEACON_SCHEME}${target}`;
|
|
1963
|
+
const server = try_bind_beacon(bind, target);
|
|
1964
|
+
if (server === void 0) return void 0;
|
|
1965
|
+
server.unref();
|
|
1966
|
+
beacons.set(token, server);
|
|
1967
|
+
ensure_exit_cleanup();
|
|
1968
|
+
return token;
|
|
1914
1969
|
}
|
|
1915
|
-
function
|
|
1916
|
-
|
|
1970
|
+
function resolve_own_start(probes = START_PROBES, platform2 = process.platform) {
|
|
1971
|
+
const start = read_start(process.pid, probes);
|
|
1972
|
+
if (start !== void 0 || platform2 === WINDOWS_PLATFORM) return start;
|
|
1973
|
+
return open_beacon();
|
|
1917
1974
|
}
|
|
1918
|
-
function
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
const end = rest.findIndex((line) => is_section_header(line));
|
|
1923
|
-
return end === NOT_FOUND ? rest : rest.slice(0, end);
|
|
1975
|
+
function is_valid_beacon_name(name) {
|
|
1976
|
+
if (!name.startsWith(BEACON_PREFIX) || !name.endsWith(BEACON_SUFFIX)) return false;
|
|
1977
|
+
const id = name.slice(BEACON_PREFIX.length, -BEACON_SUFFIX.length);
|
|
1978
|
+
return id.length === BEACON_ID_LENGTH && BEACON_ID_PATTERN.test(id);
|
|
1924
1979
|
}
|
|
1925
|
-
function
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
if (
|
|
1929
|
-
return
|
|
1980
|
+
function beacon_target(token) {
|
|
1981
|
+
if (!token.startsWith(BEACON_SCHEME)) return void 0;
|
|
1982
|
+
const target = token.slice(BEACON_SCHEME.length);
|
|
1983
|
+
if (path.dirname(target) !== PLATFORM_TEMP_ROOT) return void 0;
|
|
1984
|
+
return is_valid_beacon_name(path.basename(target)) ? target : void 0;
|
|
1930
1985
|
}
|
|
1931
|
-
function
|
|
1932
|
-
|
|
1933
|
-
|
|
1986
|
+
function is_live_beacon(target) {
|
|
1987
|
+
return spawnSync(process.execPath, ["-e", SOCKET_PROBE_SOURCE, target], {
|
|
1988
|
+
stdio: "ignore",
|
|
1989
|
+
timeout: PROBE_TIMEOUT_MS2
|
|
1990
|
+
}).status === 0;
|
|
1934
1991
|
}
|
|
1935
|
-
function
|
|
1936
|
-
|
|
1992
|
+
function has_matching_start(pid, recorded_start, read2) {
|
|
1993
|
+
const observed = read2(pid);
|
|
1994
|
+
return observed === void 0 ? void 0 : observed === recorded_start;
|
|
1937
1995
|
}
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
is_github_ssh_host,
|
|
1942
|
-
parse_origin_from_config,
|
|
1943
|
-
parse_origin_url,
|
|
1944
|
-
format_identity
|
|
1945
|
-
};
|
|
1946
|
-
|
|
1947
|
-
// scripts/discovery/repo-map-logic.ts
|
|
1948
|
-
var OVERRIDE_ENTRY_SEPARATOR = ",";
|
|
1949
|
-
var OVERRIDE_PAIR_SEPARATOR = "=";
|
|
1950
|
-
var OVERRIDE_PAIR_PARTS = 2;
|
|
1951
|
-
var KEY_INDEX = 0;
|
|
1952
|
-
var PATH_INDEX = 1;
|
|
1953
|
-
function is_same_owner(identity, current_owner2) {
|
|
1954
|
-
return identity.owner.toLowerCase() === current_owner2.toLowerCase();
|
|
1996
|
+
function matches_recorded_start(pid, recorded_start, read2) {
|
|
1997
|
+
const target = beacon_target(recorded_start);
|
|
1998
|
+
return target === void 0 ? has_matching_start(pid, recorded_start, read2) : is_live_beacon(target);
|
|
1955
1999
|
}
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
target.set(repo_origin.format_identity(identity), repository_path);
|
|
2000
|
+
var own_probe = /* @__PURE__ */ new Map();
|
|
2001
|
+
function own_start() {
|
|
2002
|
+
if (!own_probe.has(process.pid)) own_probe.set(process.pid, resolve_own_start());
|
|
2003
|
+
return own_probe.get(process.pid);
|
|
1961
2004
|
}
|
|
1962
|
-
function
|
|
1963
|
-
const
|
|
1964
|
-
|
|
1965
|
-
const key = parts[KEY_INDEX] ?? "";
|
|
1966
|
-
const repository_path = parts[PATH_INDEX] ?? "";
|
|
1967
|
-
if (repository_path === "") return void 0;
|
|
1968
|
-
return { path: repository_path, origin_url: `https://${repo_origin.GITHUB_HOST}/${key}` };
|
|
2005
|
+
function own_fields() {
|
|
2006
|
+
const start = own_start();
|
|
2007
|
+
return { pid: process.pid, ...start !== void 0 && { process_start: start } };
|
|
1969
2008
|
}
|
|
1970
|
-
function
|
|
1971
|
-
if (
|
|
1972
|
-
|
|
2009
|
+
function is_same_process(pid, recorded_start, read2 = read_start) {
|
|
2010
|
+
if (pid === void 0 || !is_live_pid(pid)) return false;
|
|
2011
|
+
if (recorded_start === void 0) return void 0;
|
|
2012
|
+
return matches_recorded_start(pid, recorded_start, read2);
|
|
1973
2013
|
}
|
|
1974
|
-
function
|
|
1975
|
-
|
|
1976
|
-
for (const entry of discovered) add_entry(result, entry.origin_url, entry.path, current_owner2);
|
|
1977
|
-
for (const entry of parse_overrides(override_value2)) {
|
|
1978
|
-
add_entry(result, entry.origin_url, entry.path, current_owner2);
|
|
1979
|
-
}
|
|
1980
|
-
return result;
|
|
2014
|
+
function is_own_process(pid, recorded_start) {
|
|
2015
|
+
return pid === process.pid && recorded_start === own_start();
|
|
1981
2016
|
}
|
|
1982
|
-
var
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
2017
|
+
var process_identity = {
|
|
2018
|
+
close_beacon,
|
|
2019
|
+
is_live_pid,
|
|
2020
|
+
is_own_process,
|
|
2021
|
+
is_same_process,
|
|
2022
|
+
open_beacon,
|
|
2023
|
+
own_fields,
|
|
2024
|
+
own_start,
|
|
2025
|
+
read_start,
|
|
2026
|
+
resolve_own_start
|
|
1986
2027
|
};
|
|
1987
2028
|
|
|
1988
|
-
// scripts/
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
var
|
|
1993
|
-
var
|
|
1994
|
-
function
|
|
1995
|
-
|
|
1996
|
-
if (!existsSync(pointer)) return git_directory;
|
|
1997
|
-
try {
|
|
1998
|
-
return path.resolve(git_directory, readFileSync2(pointer, "utf8").trim());
|
|
1999
|
-
} catch {
|
|
2000
|
-
return git_directory;
|
|
2001
|
-
}
|
|
2029
|
+
// scripts/run/run-carry.ts
|
|
2030
|
+
import { z as z6 } from "zod";
|
|
2031
|
+
|
|
2032
|
+
// scripts/run/run-carry-streak.ts
|
|
2033
|
+
var NO_INCREMENT = 0;
|
|
2034
|
+
var OUTAGE_FOLD_WINDOW_MS = 12e4;
|
|
2035
|
+
function has_increment(value) {
|
|
2036
|
+
return (value ?? NO_INCREMENT) > NO_INCREMENT;
|
|
2002
2037
|
}
|
|
2003
|
-
function
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
return path.resolve(repository_path, pointer.slice(GITDIR_PREFIX.length).trim());
|
|
2038
|
+
function next_failures(carry, change) {
|
|
2039
|
+
if (has_increment(change.merged)) return NO_INCREMENT;
|
|
2040
|
+
return carry.failures + (change.failures ?? NO_INCREMENT);
|
|
2007
2041
|
}
|
|
2008
|
-
function
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
const linked = follow_git_file(repository_path, candidate);
|
|
2014
|
-
return linked === void 0 ? void 0 : resolve_common_directory(linked);
|
|
2015
|
-
} catch {
|
|
2016
|
-
return void 0;
|
|
2017
|
-
}
|
|
2042
|
+
function is_within_fold_window(last_outage_at, now) {
|
|
2043
|
+
if (last_outage_at === void 0) return false;
|
|
2044
|
+
const last = Date.parse(last_outage_at);
|
|
2045
|
+
if (Number.isNaN(last)) return false;
|
|
2046
|
+
return now.getTime() - last <= OUTAGE_FOLD_WINDOW_MS;
|
|
2018
2047
|
}
|
|
2019
|
-
function
|
|
2020
|
-
|
|
2021
|
-
if (git_directory === void 0) return void 0;
|
|
2022
|
-
try {
|
|
2023
|
-
return repo_origin.parse_origin_from_config(
|
|
2024
|
-
readFileSync2(path.join(git_directory, GIT_CONFIG), "utf8")
|
|
2025
|
-
);
|
|
2026
|
-
} catch {
|
|
2027
|
-
return void 0;
|
|
2028
|
-
}
|
|
2048
|
+
function folded_outage(carry) {
|
|
2049
|
+
return { outages: carry.outages, last_outage_at: carry.last_outage_at };
|
|
2029
2050
|
}
|
|
2030
|
-
function
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2051
|
+
function counted_outage(carry, change, now) {
|
|
2052
|
+
const outages = carry.outages + (change.outages ?? NO_INCREMENT);
|
|
2053
|
+
return { outages, last_outage_at: now.toISOString() };
|
|
2054
|
+
}
|
|
2055
|
+
function next_outage(carry, change, now) {
|
|
2056
|
+
if (has_increment(change.outages)) {
|
|
2057
|
+
return is_within_fold_window(carry.last_outage_at, now) ? folded_outage(carry) : counted_outage(carry, change, now);
|
|
2035
2058
|
}
|
|
2059
|
+
const is_reachable = has_increment(change.merged) || has_increment(change.failures);
|
|
2060
|
+
return is_reachable ? { outages: NO_INCREMENT, last_outage_at: void 0 } : folded_outage(carry);
|
|
2036
2061
|
}
|
|
2037
|
-
function
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
const origin_url = read_origin_url(repository_path);
|
|
2045
|
-
if (origin_url === void 0) return void 0;
|
|
2046
|
-
return repo_origin.parse_origin_url(origin_url)?.owner;
|
|
2062
|
+
function next_state(carry, change, now) {
|
|
2063
|
+
const outage = next_outage(carry, change, now);
|
|
2064
|
+
return {
|
|
2065
|
+
failures: next_failures(carry, change),
|
|
2066
|
+
outages: outage.outages,
|
|
2067
|
+
last_outage_at: outage.last_outage_at
|
|
2068
|
+
};
|
|
2047
2069
|
}
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2070
|
+
var run_carry_streak = { next_state };
|
|
2071
|
+
|
|
2072
|
+
// scripts/run/run-carry-change.ts
|
|
2073
|
+
var NO_INCREMENT2 = 0;
|
|
2074
|
+
function next_done(carry, done) {
|
|
2075
|
+
if (done === void 0) return carry.done;
|
|
2076
|
+
const current = carry.done ?? [];
|
|
2077
|
+
return current.includes(done) ? current : [...current, done];
|
|
2053
2078
|
}
|
|
2054
|
-
function
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
if (current_owner2 === void 0) return /* @__PURE__ */ new Map();
|
|
2058
|
-
return repo_map_logic.build_repository_map(
|
|
2059
|
-
scan_siblings(path.dirname(main2)),
|
|
2060
|
-
current_owner2,
|
|
2061
|
-
environment2[OVERRIDE_ENV_KEY]
|
|
2062
|
-
);
|
|
2079
|
+
function next_merged_issues(carry, issue) {
|
|
2080
|
+
if (issue === void 0) return carry.merged_issues;
|
|
2081
|
+
return [...carry.merged_issues ?? [], issue];
|
|
2063
2082
|
}
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
read_origin_url,
|
|
2068
|
-
resolve_current_owner,
|
|
2069
|
-
scan_siblings,
|
|
2070
|
-
discover_repositories
|
|
2071
|
-
};
|
|
2072
|
-
|
|
2073
|
-
// scripts/discovery/repo-party.ts
|
|
2074
|
-
var FIRST_PARTY = "first-party";
|
|
2075
|
-
var THIRD_PARTY = "third-party";
|
|
2076
|
-
var UNKNOWN = "unknown";
|
|
2077
|
-
function classify3(session_owner, target) {
|
|
2078
|
-
if (session_owner === void 0 || target === void 0) return UNKNOWN;
|
|
2079
|
-
return session_owner.toLowerCase() === target.toLowerCase() ? FIRST_PARTY : THIRD_PARTY;
|
|
2083
|
+
function is_duplicate_merge(carry, change) {
|
|
2084
|
+
const issue = change.merged_issue;
|
|
2085
|
+
return issue !== void 0 && carry.merged_issues?.includes(issue) === true;
|
|
2080
2086
|
}
|
|
2081
|
-
function
|
|
2082
|
-
|
|
2087
|
+
function next_counts(carry, change) {
|
|
2088
|
+
const cuts = change.cuts ?? NO_INCREMENT2;
|
|
2089
|
+
return {
|
|
2090
|
+
merged: carry.merged + (change.merged ?? NO_INCREMENT2),
|
|
2091
|
+
filed: carry.filed + (change.filed ?? NO_INCREMENT2),
|
|
2092
|
+
cuts: carry.cuts + cuts,
|
|
2093
|
+
is_handed_off: cuts > NO_INCREMENT2
|
|
2094
|
+
};
|
|
2083
2095
|
}
|
|
2084
|
-
function
|
|
2085
|
-
|
|
2096
|
+
function apply_change(target, carry, change, now = /* @__PURE__ */ new Date()) {
|
|
2097
|
+
if (is_duplicate_merge(carry, change)) return carry;
|
|
2098
|
+
const streak = run_carry_streak.next_state(carry, change, now);
|
|
2099
|
+
const next = {
|
|
2100
|
+
...carry,
|
|
2101
|
+
...next_counts(carry, change),
|
|
2102
|
+
merged_issues: next_merged_issues(carry, change.merged_issue),
|
|
2103
|
+
failures: streak.failures,
|
|
2104
|
+
outages: streak.outages,
|
|
2105
|
+
last_outage_at: streak.last_outage_at,
|
|
2106
|
+
done: next_done(carry, change.done),
|
|
2107
|
+
retrospective: change.retrospective === true || carry.retrospective
|
|
2108
|
+
};
|
|
2109
|
+
stamp_file.write_stamp(target, next);
|
|
2110
|
+
return next;
|
|
2086
2111
|
}
|
|
2087
|
-
var
|
|
2112
|
+
var run_carry_change = { apply_change };
|
|
2088
2113
|
|
|
2089
|
-
// scripts/
|
|
2090
|
-
import {
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
var PARENT_FORMAT = ["-o", "ppid=", "-p"];
|
|
2096
|
-
var TERMINATE_SIGNAL = "SIGTERM";
|
|
2097
|
-
var PROBE_TIMEOUT_MS = 2e3;
|
|
2098
|
-
var LOWEST_CHILD_PID = 2;
|
|
2099
|
-
function parse_pids(printed) {
|
|
2100
|
-
return printed.split("\n").map((line) => Number(line.trim())).filter((pid) => Number.isSafeInteger(pid) && pid >= LOWEST_CHILD_PID);
|
|
2101
|
-
}
|
|
2102
|
-
function run_probe(command, args) {
|
|
2103
|
-
try {
|
|
2104
|
-
return execFileSync2(command, [...args], {
|
|
2105
|
-
encoding: "utf8",
|
|
2106
|
-
timeout: PROBE_TIMEOUT_MS,
|
|
2107
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
2108
|
-
});
|
|
2109
|
-
} catch {
|
|
2110
|
-
return "";
|
|
2111
|
-
}
|
|
2114
|
+
// scripts/backlog/backlog-budget-cli.ts
|
|
2115
|
+
import { fileURLToPath } from "node:url";
|
|
2116
|
+
|
|
2117
|
+
// scripts/git/changed-paths.ts
|
|
2118
|
+
function to_paths(raw) {
|
|
2119
|
+
return raw.split("\n").map((line) => line.trim()).filter((line) => line !== "");
|
|
2112
2120
|
}
|
|
2113
|
-
function
|
|
2114
|
-
|
|
2121
|
+
async function read_changed_paths(is_staged) {
|
|
2122
|
+
if (is_staged) return to_paths(await git_command.diff_cached_names());
|
|
2123
|
+
const tracked = to_paths(await git_command.diff_main_names());
|
|
2124
|
+
const untracked = to_paths(await git_command.untracked_names());
|
|
2125
|
+
return [...tracked, ...untracked];
|
|
2115
2126
|
}
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2127
|
+
var changed_paths = { read_changed_paths, to_paths };
|
|
2128
|
+
|
|
2129
|
+
// scripts/josh/path-decision.ts
|
|
2130
|
+
var STAGED_FLAG = "--staged";
|
|
2131
|
+
var JSON_FLAG = "--json";
|
|
2132
|
+
var KNOWN_FLAGS = [STAGED_FLAG, JSON_FLAG];
|
|
2133
|
+
var FAILURE_EXIT_CODE = 1;
|
|
2134
|
+
var MAX_LISTED_PATHS = 5;
|
|
2135
|
+
function has_unknown_flag(argv, known) {
|
|
2136
|
+
return argv.some((argument) => !known.includes(argument));
|
|
2123
2137
|
}
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
parent_of,
|
|
2128
|
-
terminate
|
|
2129
|
-
};
|
|
2130
|
-
function ancestry_of(pid, probes) {
|
|
2131
|
-
const ancestry = /* @__PURE__ */ new Set([pid]);
|
|
2132
|
-
let current = probes.parent_of(pid);
|
|
2133
|
-
while (current !== void 0 && !ancestry.has(current)) {
|
|
2134
|
-
ancestry.add(current);
|
|
2135
|
-
current = probes.parent_of(current);
|
|
2136
|
-
}
|
|
2137
|
-
return ancestry;
|
|
2138
|
+
function parse_options(argv) {
|
|
2139
|
+
if (has_unknown_flag(argv, KNOWN_FLAGS)) return void 0;
|
|
2140
|
+
return { is_staged: argv.includes(STAGED_FLAG), is_json: argv.includes(JSON_FLAG) };
|
|
2138
2141
|
}
|
|
2139
|
-
function
|
|
2140
|
-
|
|
2142
|
+
function format_path_list(paths) {
|
|
2143
|
+
const listed = paths.slice(0, MAX_LISTED_PATHS).join(", ");
|
|
2144
|
+
if (paths.length <= MAX_LISTED_PATHS) return listed;
|
|
2145
|
+
return `${listed}, +${String(paths.length - MAX_LISTED_PATHS)} more`;
|
|
2141
2146
|
}
|
|
2142
|
-
function
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
while (next !== void 0) {
|
|
2147
|
-
if (!tree.includes(next)) {
|
|
2148
|
-
tree.push(next);
|
|
2149
|
-
pending.push(...probes.children_of(next));
|
|
2150
|
-
}
|
|
2151
|
-
next = pending.shift();
|
|
2147
|
+
function print_decision(key2, answer, reason, is_json) {
|
|
2148
|
+
if (is_json) {
|
|
2149
|
+
console.info(JSON.stringify({ [key2]: answer, reason }));
|
|
2150
|
+
return;
|
|
2152
2151
|
}
|
|
2153
|
-
|
|
2152
|
+
console.info(answer);
|
|
2153
|
+
console.error(reason);
|
|
2154
2154
|
}
|
|
2155
|
-
function
|
|
2156
|
-
const
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2155
|
+
async function run_path_decision(argv, command) {
|
|
2156
|
+
const options = parse_options(argv);
|
|
2157
|
+
if (options === void 0) {
|
|
2158
|
+
console.error(command.usage);
|
|
2159
|
+
return FAILURE_EXIT_CODE;
|
|
2160
|
+
}
|
|
2161
|
+
const paths = await changed_paths.read_changed_paths(options.is_staged);
|
|
2162
|
+
const answer = command.decide(paths);
|
|
2163
|
+
print_decision(command.key, answer, command.explain(paths, answer), options.is_json);
|
|
2164
|
+
return 0;
|
|
2161
2165
|
}
|
|
2162
|
-
var
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
+
var path_decision = {
|
|
2167
|
+
format_path_list,
|
|
2168
|
+
has_unknown_flag,
|
|
2169
|
+
JSON_FLAG,
|
|
2170
|
+
parse_options,
|
|
2171
|
+
print_decision,
|
|
2172
|
+
run_path_decision
|
|
2166
2173
|
};
|
|
2167
2174
|
|
|
2168
|
-
// scripts/
|
|
2169
|
-
import {
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
var START_TIME_FORMAT = "lstart=";
|
|
2177
|
-
var PID_FLAG = "-p";
|
|
2178
|
-
var PROBE_ENVIRONMENT = { TZ: "UTC", LC_ALL: "C" };
|
|
2179
|
-
var PROBE_TIMEOUT_MS2 = 2e3;
|
|
2180
|
-
var LIVENESS_SIGNAL = 0;
|
|
2181
|
-
var LOWEST_REAL_PID = 1;
|
|
2182
|
-
var PROC_START_FIELD_INDEX = 19;
|
|
2183
|
-
var BEACON_SCHEME = "socket:";
|
|
2184
|
-
var BEACON_SUFFIX = ".sock";
|
|
2185
|
-
var BEACON_PREFIX = `josh-process-identity-${String(process.getuid?.() ?? "")}-`;
|
|
2186
|
-
var BEACON_ID_LENGTH = 36;
|
|
2187
|
-
var BEACON_ID_PATTERN = /^[\da-f-]+$/u;
|
|
2188
|
-
var WINDOWS_PLATFORM = "win32";
|
|
2189
|
-
var SOCKET_PROBE_SOURCE = "const net=require('node:net');const socket=net.createConnection(process.argv[1]);socket.once('connect',()=>process.exit(0));socket.once('error',()=>process.exit(1));socket.setTimeout(1000,()=>process.exit(1));";
|
|
2190
|
-
var beacons = /* @__PURE__ */ new Map();
|
|
2191
|
-
var exit_cleanup = { is_registered: false };
|
|
2192
|
-
function is_live_pid(pid) {
|
|
2193
|
-
if (pid < LOWEST_REAL_PID) return false;
|
|
2194
|
-
try {
|
|
2195
|
-
process.kill(pid, LIVENESS_SIGNAL);
|
|
2196
|
-
return true;
|
|
2197
|
-
} catch {
|
|
2198
|
-
return false;
|
|
2199
|
-
}
|
|
2200
|
-
}
|
|
2201
|
-
function read_proc_start(pid) {
|
|
2202
|
-
try {
|
|
2203
|
-
const stat = readFileSync3(`/proc/${String(pid)}/stat`, "utf8");
|
|
2204
|
-
const fields = stat.slice(stat.lastIndexOf(")") + 1).trim().split(/\s+/u);
|
|
2205
|
-
const start = fields[PROC_START_FIELD_INDEX];
|
|
2206
|
-
return start === void 0 ? void 0 : `proc:${start}`;
|
|
2207
|
-
} catch {
|
|
2208
|
-
return void 0;
|
|
2209
|
-
}
|
|
2175
|
+
// scripts/lib/cli-flags.ts
|
|
2176
|
+
import { parseArgs } from "node:util";
|
|
2177
|
+
function refuse_unknown_flags(argv, known_flags, command) {
|
|
2178
|
+
const unknown = argv.filter((argument) => !known_flags.includes(argument));
|
|
2179
|
+
if (unknown.length === 0) return void 0;
|
|
2180
|
+
const usage = `Usage: josh ${command} [${known_flags.join("] [")}]`;
|
|
2181
|
+
return `Unknown argument(s): ${unknown.join(" ")}
|
|
2182
|
+
${usage}`;
|
|
2210
2183
|
}
|
|
2211
|
-
function
|
|
2184
|
+
function parse_or_undefined(config) {
|
|
2212
2185
|
try {
|
|
2213
|
-
|
|
2214
|
-
PS_COMMAND2,
|
|
2215
|
-
[FORMAT_FLAG, START_TIME_FORMAT, PID_FLAG, String(pid)],
|
|
2216
|
-
{
|
|
2217
|
-
encoding: "utf8",
|
|
2218
|
-
timeout: PROBE_TIMEOUT_MS2,
|
|
2219
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
2220
|
-
env: PROBE_ENVIRONMENT
|
|
2221
|
-
}
|
|
2222
|
-
).trim();
|
|
2223
|
-
return printed.length > 0 ? printed : void 0;
|
|
2186
|
+
return parseArgs(config);
|
|
2224
2187
|
} catch {
|
|
2225
2188
|
return void 0;
|
|
2226
2189
|
}
|
|
2227
2190
|
}
|
|
2228
|
-
var
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
}
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
}
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
}
|
|
2246
|
-
function
|
|
2247
|
-
|
|
2191
|
+
var cli_flags = { refuse_unknown_flags, parse_or_undefined };
|
|
2192
|
+
|
|
2193
|
+
// scripts/backlog/backlog-budget-cli.ts
|
|
2194
|
+
var ARGV_OFFSET = 2;
|
|
2195
|
+
var SUCCESS_EXIT_CODE = 0;
|
|
2196
|
+
var FAILURE_EXIT_CODE2 = 1;
|
|
2197
|
+
var JSON_KEY = "budget";
|
|
2198
|
+
var USAGE = `Usage: josh backlog:budget --answer <${backlog_budget.ANSWERS.join("|")}> --started <ISO-8601> [--active <ISO-8601>, required unless the watch is off] [--merged <count>] [--running <count>] [--max <count>] [--idle <minutes>, 0 to turn the watch off] [--json]`;
|
|
2199
|
+
var OPTIONS = {
|
|
2200
|
+
active: { type: "string" },
|
|
2201
|
+
answer: { type: "string" },
|
|
2202
|
+
idle: { type: "string" },
|
|
2203
|
+
json: { type: "boolean" },
|
|
2204
|
+
max: { type: "string" },
|
|
2205
|
+
merged: { type: "string" },
|
|
2206
|
+
running: { type: "string" },
|
|
2207
|
+
started: { type: "string" }
|
|
2208
|
+
};
|
|
2209
|
+
function read_arguments(argv) {
|
|
2210
|
+
return cli_flags.parse_or_undefined({ args: [...argv], options: OPTIONS, strict: true })?.values;
|
|
2248
2211
|
}
|
|
2249
|
-
function
|
|
2250
|
-
|
|
2251
|
-
exit_cleanup.is_registered = true;
|
|
2252
|
-
process.once("exit", close_beacons);
|
|
2212
|
+
function text_of(value) {
|
|
2213
|
+
return typeof value === "string" ? value : void 0;
|
|
2253
2214
|
}
|
|
2254
|
-
function
|
|
2215
|
+
function to_answer(raw) {
|
|
2216
|
+
return backlog_budget.ANSWERS.find((answer) => answer === raw);
|
|
2255
2217
|
}
|
|
2256
|
-
function
|
|
2257
|
-
|
|
2218
|
+
function to_time_ms(raw) {
|
|
2219
|
+
if (raw === void 0) return void 0;
|
|
2220
|
+
const parsed = Date.parse(raw);
|
|
2221
|
+
return Number.isNaN(parsed) ? void 0 : parsed;
|
|
2258
2222
|
}
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
return void 0;
|
|
2265
|
-
}
|
|
2223
|
+
var COUNT_PATTERN = /^\d+$/u;
|
|
2224
|
+
function to_count(raw) {
|
|
2225
|
+
if (raw === void 0 || !COUNT_PATTERN.test(raw)) return void 0;
|
|
2226
|
+
const parsed = Number(raw);
|
|
2227
|
+
return Number.isSafeInteger(parsed) ? parsed : void 0;
|
|
2266
2228
|
}
|
|
2267
|
-
function
|
|
2268
|
-
|
|
2269
|
-
const token = `${BEACON_SCHEME}${target}`;
|
|
2270
|
-
const server = try_bind_beacon(bind, target);
|
|
2271
|
-
if (server === void 0) return void 0;
|
|
2272
|
-
server.unref();
|
|
2273
|
-
beacons.set(token, server);
|
|
2274
|
-
ensure_exit_cleanup();
|
|
2275
|
-
return token;
|
|
2229
|
+
function is_readable(raw, parsed) {
|
|
2230
|
+
return raw === void 0 || parsed !== void 0;
|
|
2276
2231
|
}
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2232
|
+
var COUNT_NAMES = ["idle", "max", "merged", "running"];
|
|
2233
|
+
function counts_of(values) {
|
|
2234
|
+
return {
|
|
2235
|
+
idle: to_count(text_of(values.idle)),
|
|
2236
|
+
max: to_count(text_of(values.max)),
|
|
2237
|
+
merged: to_count(text_of(values.merged)),
|
|
2238
|
+
running: to_count(text_of(values.running))
|
|
2239
|
+
};
|
|
2281
2240
|
}
|
|
2282
|
-
function
|
|
2283
|
-
|
|
2284
|
-
const id = name.slice(BEACON_PREFIX.length, -BEACON_SUFFIX.length);
|
|
2285
|
-
return id.length === BEACON_ID_LENGTH && BEACON_ID_PATTERN.test(id);
|
|
2241
|
+
function are_counts_readable(values, counts) {
|
|
2242
|
+
return COUNT_NAMES.every((name) => is_readable(text_of(values[name]), counts[name]));
|
|
2286
2243
|
}
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
if (
|
|
2291
|
-
return
|
|
2244
|
+
var NO_IDLE_MINUTES = 0;
|
|
2245
|
+
function to_idle_ms(idle_minutes) {
|
|
2246
|
+
if (idle_minutes === void 0) return backlog_budget.DEFAULT_IDLE_MS;
|
|
2247
|
+
if (idle_minutes === NO_IDLE_MINUTES) return void 0;
|
|
2248
|
+
return idle_minutes * backlog_budget.MS_PER_MINUTE;
|
|
2292
2249
|
}
|
|
2293
|
-
function
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
timeout: PROBE_TIMEOUT_MS2
|
|
2297
|
-
}).status === 0;
|
|
2250
|
+
function is_watch_readable(values) {
|
|
2251
|
+
if (to_idle_ms(to_count(text_of(values.idle))) === void 0) return true;
|
|
2252
|
+
return text_of(values.active) !== void 0;
|
|
2298
2253
|
}
|
|
2299
|
-
function
|
|
2300
|
-
|
|
2301
|
-
return observed === void 0 ? void 0 : observed === recorded_start;
|
|
2254
|
+
function are_values_readable(values) {
|
|
2255
|
+
return is_readable(text_of(values.active), to_time_ms(text_of(values.active))) && is_watch_readable(values) && are_counts_readable(values, counts_of(values));
|
|
2302
2256
|
}
|
|
2303
|
-
function
|
|
2304
|
-
const
|
|
2305
|
-
return
|
|
2257
|
+
function input_of(values, base) {
|
|
2258
|
+
const counts = counts_of(values);
|
|
2259
|
+
return {
|
|
2260
|
+
...base,
|
|
2261
|
+
active_at_ms: to_time_ms(text_of(values.active)) ?? base.started_at_ms,
|
|
2262
|
+
merged: counts.merged ?? 0,
|
|
2263
|
+
running: counts.running ?? 0,
|
|
2264
|
+
max_issues: counts.max,
|
|
2265
|
+
idle_budget_ms: to_idle_ms(counts.idle)
|
|
2266
|
+
};
|
|
2306
2267
|
}
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
if (
|
|
2310
|
-
|
|
2268
|
+
function build_input(values, now_ms) {
|
|
2269
|
+
const answer = to_answer(text_of(values.answer));
|
|
2270
|
+
if (answer === void 0) return void 0;
|
|
2271
|
+
const started_at_ms = to_time_ms(text_of(values.started));
|
|
2272
|
+
if (started_at_ms === void 0) return void 0;
|
|
2273
|
+
if (!are_values_readable(values)) return void 0;
|
|
2274
|
+
return input_of(values, { answer, now_ms, started_at_ms });
|
|
2311
2275
|
}
|
|
2312
|
-
function
|
|
2313
|
-
|
|
2314
|
-
return
|
|
2276
|
+
function refuse() {
|
|
2277
|
+
console.error(USAGE);
|
|
2278
|
+
return FAILURE_EXIT_CODE2;
|
|
2315
2279
|
}
|
|
2316
|
-
function
|
|
2317
|
-
|
|
2318
|
-
if (
|
|
2319
|
-
|
|
2280
|
+
function run(argv, now_ms = Date.now()) {
|
|
2281
|
+
const values = read_arguments(argv);
|
|
2282
|
+
if (values === void 0) return refuse();
|
|
2283
|
+
const input = build_input(values, now_ms);
|
|
2284
|
+
if (input === void 0) return refuse();
|
|
2285
|
+
const { verdict, reason } = backlog_budget.decide(input);
|
|
2286
|
+
if (values.json === true) {
|
|
2287
|
+
console.info(
|
|
2288
|
+
JSON.stringify({ [JSON_KEY]: verdict, reason, is_finish: backlog_budget.is_finish(input) })
|
|
2289
|
+
);
|
|
2290
|
+
return SUCCESS_EXIT_CODE;
|
|
2291
|
+
}
|
|
2292
|
+
path_decision.print_decision(JSON_KEY, verdict, reason, false);
|
|
2293
|
+
return SUCCESS_EXIT_CODE;
|
|
2320
2294
|
}
|
|
2321
|
-
function
|
|
2322
|
-
|
|
2295
|
+
function main(argv) {
|
|
2296
|
+
process.exitCode = run(argv);
|
|
2323
2297
|
}
|
|
2324
|
-
var
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2298
|
+
var backlog_budget_cli = {
|
|
2299
|
+
JSON_KEY,
|
|
2300
|
+
OPTIONS,
|
|
2301
|
+
SUCCESS_EXIT_CODE,
|
|
2302
|
+
USAGE,
|
|
2303
|
+
build_input,
|
|
2304
|
+
main,
|
|
2305
|
+
read_arguments,
|
|
2306
|
+
run,
|
|
2307
|
+
to_answer,
|
|
2308
|
+
to_count,
|
|
2309
|
+
to_time_ms
|
|
2334
2310
|
};
|
|
2311
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) main(process.argv.slice(ARGV_OFFSET));
|
|
2335
2312
|
|
|
2336
|
-
// scripts/run/run-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
var
|
|
2341
|
-
var
|
|
2342
|
-
|
|
2343
|
-
|
|
2313
|
+
// scripts/run/run-invocation.ts
|
|
2314
|
+
var BACKLOG_COMMAND = "backlogrun";
|
|
2315
|
+
var KNOWN_FLAGS2 = ["--max", "--idle"];
|
|
2316
|
+
var ONLY_FLAG = "--only";
|
|
2317
|
+
var ISSUE_PREFIX = "#";
|
|
2318
|
+
var TOKEN_SEPARATOR = " ";
|
|
2319
|
+
var FIRST_TOKEN = 0;
|
|
2320
|
+
var FIRST_ARGUMENT_INDEX = 1;
|
|
2321
|
+
var VALUE_OFFSET = 1;
|
|
2322
|
+
var FLAG_PAIR_LENGTH = 2;
|
|
2323
|
+
var ONLY_STEP = 1;
|
|
2324
|
+
var EMPTY_LENGTH2 = 0;
|
|
2325
|
+
var NOT_FOUND = -1;
|
|
2326
|
+
function tokens_of(invocation) {
|
|
2327
|
+
return invocation.split(TOKEN_SEPARATOR).filter((token) => token.length > EMPTY_LENGTH2);
|
|
2344
2328
|
}
|
|
2345
|
-
function
|
|
2346
|
-
|
|
2347
|
-
|
|
2329
|
+
function flag_token(token, raw) {
|
|
2330
|
+
const flag = KNOWN_FLAGS2.find((known) => known === token);
|
|
2331
|
+
const value = backlog_budget_cli.to_count(raw);
|
|
2332
|
+
if (flag === void 0 || value === void 0) return void 0;
|
|
2333
|
+
return `${flag} ${String(value)}`;
|
|
2348
2334
|
}
|
|
2349
|
-
function
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
return
|
|
2335
|
+
function read_flag(tokens, index) {
|
|
2336
|
+
const token = tokens[index] ?? "";
|
|
2337
|
+
if (token === ONLY_FLAG) return { part: ONLY_FLAG, advance: ONLY_STEP };
|
|
2338
|
+
const part = flag_token(token, tokens[index + VALUE_OFFSET]);
|
|
2339
|
+
return part === void 0 ? void 0 : { part, advance: FLAG_PAIR_LENGTH };
|
|
2354
2340
|
}
|
|
2355
|
-
function
|
|
2356
|
-
|
|
2341
|
+
function flag_tokens(tokens, start) {
|
|
2342
|
+
const rendered = [];
|
|
2343
|
+
let index = start;
|
|
2344
|
+
while (index < tokens.length) {
|
|
2345
|
+
const read2 = read_flag(tokens, index);
|
|
2346
|
+
if (read2 === void 0) return void 0;
|
|
2347
|
+
rendered.push(read2.part);
|
|
2348
|
+
index += read2.advance;
|
|
2349
|
+
}
|
|
2350
|
+
return rendered;
|
|
2357
2351
|
}
|
|
2358
|
-
function
|
|
2359
|
-
|
|
2360
|
-
|
|
2352
|
+
function issue_of(token) {
|
|
2353
|
+
if (!token.startsWith(ISSUE_PREFIX)) return void 0;
|
|
2354
|
+
const digits = token.slice(ISSUE_PREFIX.length);
|
|
2355
|
+
if (!run_issue_number.ISSUE_NUMBER_PATTERN.test(digits)) return void 0;
|
|
2356
|
+
const issue = Number(digits);
|
|
2357
|
+
return Number.isSafeInteger(issue) ? issue : void 0;
|
|
2361
2358
|
}
|
|
2362
|
-
function
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
}
|
|
2366
|
-
const is_reachable = has_increment(change.merged) || has_increment(change.failures);
|
|
2367
|
-
return is_reachable ? { outages: NO_INCREMENT, last_outage_at: void 0 } : folded_outage(carry);
|
|
2359
|
+
function take_leading_prefixed(args) {
|
|
2360
|
+
const stop = args.findIndex((token) => !token.startsWith(ISSUE_PREFIX));
|
|
2361
|
+
return args.slice(FIRST_TOKEN, stop === NOT_FOUND ? args.length : stop);
|
|
2368
2362
|
}
|
|
2369
|
-
function
|
|
2370
|
-
const
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
}
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
// scripts/run/run-carry-change.ts
|
|
2380
|
-
var NO_INCREMENT2 = 0;
|
|
2381
|
-
function next_done(carry, done) {
|
|
2382
|
-
if (done === void 0) return carry.done;
|
|
2383
|
-
const current = carry.done ?? [];
|
|
2384
|
-
return current.includes(done) ? current : [...current, done];
|
|
2385
|
-
}
|
|
2386
|
-
function next_merged_issues(carry, issue) {
|
|
2387
|
-
if (issue === void 0) return carry.merged_issues;
|
|
2388
|
-
return [...carry.merged_issues ?? [], issue];
|
|
2389
|
-
}
|
|
2390
|
-
function is_duplicate_merge(carry, change) {
|
|
2391
|
-
const issue = change.merged_issue;
|
|
2392
|
-
return issue !== void 0 && carry.merged_issues?.includes(issue) === true;
|
|
2393
|
-
}
|
|
2394
|
-
function next_counts(carry, change) {
|
|
2395
|
-
const cuts = change.cuts ?? NO_INCREMENT2;
|
|
2396
|
-
return {
|
|
2397
|
-
merged: carry.merged + (change.merged ?? NO_INCREMENT2),
|
|
2398
|
-
filed: carry.filed + (change.filed ?? NO_INCREMENT2),
|
|
2399
|
-
cuts: carry.cuts + cuts,
|
|
2400
|
-
is_handed_off: cuts > NO_INCREMENT2
|
|
2401
|
-
};
|
|
2402
|
-
}
|
|
2403
|
-
function apply_change(target, carry, change, now = /* @__PURE__ */ new Date()) {
|
|
2404
|
-
if (is_duplicate_merge(carry, change)) return carry;
|
|
2405
|
-
const streak = run_carry_streak.next_state(carry, change, now);
|
|
2406
|
-
const next = {
|
|
2407
|
-
...carry,
|
|
2408
|
-
...next_counts(carry, change),
|
|
2409
|
-
merged_issues: next_merged_issues(carry, change.merged_issue),
|
|
2410
|
-
failures: streak.failures,
|
|
2411
|
-
outages: streak.outages,
|
|
2412
|
-
last_outage_at: streak.last_outage_at,
|
|
2413
|
-
done: next_done(carry, change.done),
|
|
2414
|
-
retrospective: change.retrospective === true || carry.retrospective
|
|
2415
|
-
};
|
|
2416
|
-
stamp_file.write_stamp(target, next);
|
|
2417
|
-
return next;
|
|
2418
|
-
}
|
|
2419
|
-
var run_carry_change = { apply_change };
|
|
2420
|
-
|
|
2421
|
-
// scripts/backlog/backlog-budget-cli.ts
|
|
2422
|
-
import { fileURLToPath } from "node:url";
|
|
2423
|
-
|
|
2424
|
-
// scripts/git/changed-paths.ts
|
|
2425
|
-
function to_paths(raw) {
|
|
2426
|
-
return raw.split("\n").map((line) => line.trim()).filter((line) => line !== "");
|
|
2363
|
+
function leading_issues(tokens) {
|
|
2364
|
+
const issues = [];
|
|
2365
|
+
const prefixed = take_leading_prefixed(tokens.slice(FIRST_ARGUMENT_INDEX));
|
|
2366
|
+
for (const token of prefixed) {
|
|
2367
|
+
const issue = issue_of(token);
|
|
2368
|
+
if (issue === void 0) return void 0;
|
|
2369
|
+
issues.push(issue);
|
|
2370
|
+
}
|
|
2371
|
+
return issues;
|
|
2427
2372
|
}
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
const tracked = to_paths(await git_command.diff_main_names());
|
|
2431
|
-
const untracked = to_paths(await git_command.untracked_names());
|
|
2432
|
-
return [...tracked, ...untracked];
|
|
2373
|
+
function issue_token(issue) {
|
|
2374
|
+
return `${ISSUE_PREFIX}${String(issue)}`;
|
|
2433
2375
|
}
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
// scripts/josh/path-decision.ts
|
|
2437
|
-
var STAGED_FLAG = "--staged";
|
|
2438
|
-
var JSON_FLAG = "--json";
|
|
2439
|
-
var KNOWN_FLAGS = [STAGED_FLAG, JSON_FLAG];
|
|
2440
|
-
var FAILURE_EXIT_CODE = 1;
|
|
2441
|
-
var MAX_LISTED_PATHS = 5;
|
|
2442
|
-
function has_unknown_flag(argv, known) {
|
|
2443
|
-
return argv.some((argument) => !known.includes(argument));
|
|
2376
|
+
function joined(command, rendered) {
|
|
2377
|
+
return [command, ...rendered].join(TOKEN_SEPARATOR);
|
|
2444
2378
|
}
|
|
2445
|
-
function
|
|
2446
|
-
|
|
2447
|
-
|
|
2379
|
+
function rebuilt_backlog(tokens) {
|
|
2380
|
+
const issues = leading_issues(tokens);
|
|
2381
|
+
if (issues === void 0) return void 0;
|
|
2382
|
+
const flags = flag_tokens(tokens, FIRST_ARGUMENT_INDEX + issues.length);
|
|
2383
|
+
if (flags === void 0) return void 0;
|
|
2384
|
+
return joined(BACKLOG_COMMAND, [...issues.map((issue) => issue_token(issue)), ...flags]);
|
|
2448
2385
|
}
|
|
2449
|
-
function
|
|
2450
|
-
const
|
|
2451
|
-
if (
|
|
2452
|
-
return
|
|
2386
|
+
function rebuild(invocation) {
|
|
2387
|
+
const tokens = tokens_of(invocation);
|
|
2388
|
+
if (tokens[FIRST_TOKEN] !== BACKLOG_COMMAND) return void 0;
|
|
2389
|
+
return rebuilt_backlog(tokens);
|
|
2453
2390
|
}
|
|
2454
|
-
function
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
console.error(reason);
|
|
2391
|
+
function issue_numbers(invocation) {
|
|
2392
|
+
const tokens = tokens_of(invocation);
|
|
2393
|
+
if (tokens[FIRST_TOKEN] !== BACKLOG_COMMAND) return void 0;
|
|
2394
|
+
const issues = leading_issues(tokens);
|
|
2395
|
+
if (issues === void 0 || issues.length === EMPTY_LENGTH2) return void 0;
|
|
2396
|
+
return issues;
|
|
2461
2397
|
}
|
|
2462
|
-
|
|
2463
|
-
const
|
|
2464
|
-
if (
|
|
2465
|
-
|
|
2466
|
-
return FAILURE_EXIT_CODE;
|
|
2467
|
-
}
|
|
2468
|
-
const paths = await changed_paths.read_changed_paths(options.is_staged);
|
|
2469
|
-
const answer = command.decide(paths);
|
|
2470
|
-
print_decision(command.key, answer, command.explain(paths, answer), options.is_json);
|
|
2471
|
-
return 0;
|
|
2398
|
+
function has_only(invocation) {
|
|
2399
|
+
const tokens = tokens_of(invocation);
|
|
2400
|
+
if (tokens[FIRST_TOKEN] !== BACKLOG_COMMAND) return false;
|
|
2401
|
+
return tokens.slice(FIRST_ARGUMENT_INDEX).includes(ONLY_FLAG);
|
|
2472
2402
|
}
|
|
2473
|
-
var
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
KNOWN_FLAGS,
|
|
2478
|
-
MAX_LISTED_PATHS,
|
|
2479
|
-
parse_options,
|
|
2480
|
-
print_decision,
|
|
2481
|
-
run_path_decision,
|
|
2482
|
-
STAGED_FLAG
|
|
2403
|
+
var run_invocation = {
|
|
2404
|
+
has_only,
|
|
2405
|
+
issue_numbers,
|
|
2406
|
+
rebuild
|
|
2483
2407
|
};
|
|
2484
2408
|
|
|
2485
|
-
// scripts/
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2409
|
+
// scripts/run/run-carry.ts
|
|
2410
|
+
var CARRY_PREFIX = "josh-run-carry-";
|
|
2411
|
+
var REPOSITORY_DIRECTORY_INDEX = 1;
|
|
2412
|
+
var CARRY_MAX_AGE_HOURS = backlog_budget.WHOLE_RUN_BUDGET_HOURS;
|
|
2413
|
+
var CARRY_MAX_AGE_MS = backlog_budget.WHOLE_RUN_BUDGET_MS;
|
|
2414
|
+
var NO_INCREMENT3 = 0;
|
|
2415
|
+
var MAX_CUTS = 6;
|
|
2416
|
+
var END_COMMAND2 = "pnpm josh run:carry --end";
|
|
2417
|
+
var RESUME_COMMAND = "pnpm josh run:carry --resume";
|
|
2418
|
+
var READ_COMMAND2 = "pnpm josh run:carry --json";
|
|
2419
|
+
var OWNER_ARGUMENT = '--owner "$PPID"';
|
|
2420
|
+
var NONE_READ2 = { kind: "none" };
|
|
2421
|
+
var UNREADABLE_READ3 = { kind: "unreadable" };
|
|
2422
|
+
var NO_OWNER = {};
|
|
2423
|
+
var run_carry_schema = z6.object({
|
|
2424
|
+
invocation: z6.string(),
|
|
2425
|
+
started_at: z6.string(),
|
|
2426
|
+
merged: z6.number(),
|
|
2427
|
+
merged_issues: z6.array(z6.number()).optional(),
|
|
2428
|
+
filed: z6.number(),
|
|
2429
|
+
cuts: z6.number(),
|
|
2430
|
+
// Defaulted, so a record written before this field existed parses with a zero streak rather than
|
|
2431
|
+
// failing to read — the same backward-compatibility the optional owner fields below carry.
|
|
2432
|
+
failures: z6.number().default(0),
|
|
2433
|
+
// Defaulted for the same backward-compatibility as `failures` (joshuafolkken/kit#2240).
|
|
2434
|
+
outages: z6.number().default(0),
|
|
2435
|
+
// Optional, so a record written before the outage fold existed still parses (joshuafolkken/kit#2317).
|
|
2436
|
+
last_outage_at: z6.string().optional(),
|
|
2437
|
+
// Optional, so a record written by the previous shape still parses. Read as "no owner declared",
|
|
2438
|
+
// which is the not-provably-live answer rather than a live one.
|
|
2439
|
+
owner_pid: z6.number().optional(),
|
|
2440
|
+
owner_start: z6.string().optional(),
|
|
2441
|
+
is_handed_off: z6.boolean().optional(),
|
|
2442
|
+
done: z6.array(z6.number()).optional(),
|
|
2443
|
+
// Optional, so a record written before the retrospective existed still parses (joshuafolkken/kit#2328).
|
|
2444
|
+
retrospective: z6.boolean().optional()
|
|
2445
|
+
});
|
|
2446
|
+
function carry_path(git_directory) {
|
|
2447
|
+
return stamp_file.stamp_path(CARRY_PREFIX, git_directory);
|
|
2493
2448
|
}
|
|
2494
|
-
function
|
|
2449
|
+
async function repository_directory() {
|
|
2450
|
+
const directories2 = await git_command.git_directories();
|
|
2451
|
+
return directories2[REPOSITORY_DIRECTORY_INDEX];
|
|
2452
|
+
}
|
|
2453
|
+
function parse_carry(raw) {
|
|
2495
2454
|
try {
|
|
2496
|
-
|
|
2455
|
+
const parsed = run_carry_schema.safeParse(JSON.parse(raw));
|
|
2456
|
+
return parsed.success ? parsed.data : void 0;
|
|
2497
2457
|
} catch {
|
|
2498
2458
|
return void 0;
|
|
2499
2459
|
}
|
|
2500
2460
|
}
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
var SUCCESS_EXIT_CODE = 0;
|
|
2506
|
-
var FAILURE_EXIT_CODE2 = 1;
|
|
2507
|
-
var JSON_KEY = "budget";
|
|
2508
|
-
var USAGE = `Usage: josh backlog:budget --answer <${backlog_budget.ANSWERS.join("|")}> --started <ISO-8601> [--active <ISO-8601>, required unless the watch is off] [--merged <count>] [--running <count>] [--max <count>] [--idle <minutes>, 0 to turn the watch off] [--json]`;
|
|
2509
|
-
var OPTIONS = {
|
|
2510
|
-
active: { type: "string" },
|
|
2511
|
-
answer: { type: "string" },
|
|
2512
|
-
idle: { type: "string" },
|
|
2513
|
-
json: { type: "boolean" },
|
|
2514
|
-
max: { type: "string" },
|
|
2515
|
-
merged: { type: "string" },
|
|
2516
|
-
running: { type: "string" },
|
|
2517
|
-
started: { type: "string" }
|
|
2518
|
-
};
|
|
2519
|
-
function read_arguments(argv) {
|
|
2520
|
-
return cli_flags.parse_or_undefined({ args: [...argv], options: OPTIONS, strict: true })?.values;
|
|
2521
|
-
}
|
|
2522
|
-
function text_of(value) {
|
|
2523
|
-
return typeof value === "string" ? value : void 0;
|
|
2524
|
-
}
|
|
2525
|
-
function to_answer(raw) {
|
|
2526
|
-
return backlog_budget.ANSWERS.find((answer) => answer === raw);
|
|
2461
|
+
function is_expired2(carry, now) {
|
|
2462
|
+
const started = Date.parse(carry.started_at);
|
|
2463
|
+
if (Number.isNaN(started)) return true;
|
|
2464
|
+
return now.getTime() - started > CARRY_MAX_AGE_MS;
|
|
2527
2465
|
}
|
|
2528
|
-
function
|
|
2529
|
-
if (raw === void 0) return
|
|
2530
|
-
const
|
|
2531
|
-
|
|
2466
|
+
function classify3(raw, now) {
|
|
2467
|
+
if (raw === void 0) return NONE_READ2;
|
|
2468
|
+
const carry = parse_carry(raw);
|
|
2469
|
+
if (carry === void 0) return UNREADABLE_READ3;
|
|
2470
|
+
return { kind: is_expired2(carry, now) ? "expired" : "carried", carry };
|
|
2532
2471
|
}
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
if (raw === void 0 || !COUNT_PATTERN.test(raw)) return void 0;
|
|
2536
|
-
const parsed = Number(raw);
|
|
2537
|
-
return Number.isSafeInteger(parsed) ? parsed : void 0;
|
|
2472
|
+
function read_carry(target, now = /* @__PURE__ */ new Date()) {
|
|
2473
|
+
return classify3(stamp_file.read_stamp_text(target), now);
|
|
2538
2474
|
}
|
|
2539
|
-
function
|
|
2540
|
-
return
|
|
2475
|
+
function owner_of(pid, read2 = process_identity.read_start) {
|
|
2476
|
+
return { pid, start: read2(pid) };
|
|
2541
2477
|
}
|
|
2542
|
-
|
|
2543
|
-
function counts_of(values) {
|
|
2478
|
+
function fresh_carry(invocation, owner, now) {
|
|
2544
2479
|
return {
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
merged:
|
|
2548
|
-
|
|
2480
|
+
invocation,
|
|
2481
|
+
started_at: now.toISOString(),
|
|
2482
|
+
merged: NO_INCREMENT3,
|
|
2483
|
+
filed: NO_INCREMENT3,
|
|
2484
|
+
cuts: NO_INCREMENT3,
|
|
2485
|
+
failures: NO_INCREMENT3,
|
|
2486
|
+
outages: NO_INCREMENT3,
|
|
2487
|
+
owner_pid: owner.pid,
|
|
2488
|
+
owner_start: owner.start
|
|
2549
2489
|
};
|
|
2550
2490
|
}
|
|
2551
|
-
function
|
|
2552
|
-
|
|
2491
|
+
function begin_carry(target, invocation, owner = NO_OWNER, now = /* @__PURE__ */ new Date()) {
|
|
2492
|
+
const carry = fresh_carry(invocation, owner, now);
|
|
2493
|
+
return stamp_file.create_stamp(target, carry) ? carry : void 0;
|
|
2553
2494
|
}
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
if (idle_minutes === NO_IDLE_MINUTES) return void 0;
|
|
2558
|
-
return idle_minutes * backlog_budget.MS_PER_MINUTE;
|
|
2495
|
+
function replace_carry(target, invocation, owner = NO_OWNER, now = /* @__PURE__ */ new Date()) {
|
|
2496
|
+
stamp_file.remove_stamp(target);
|
|
2497
|
+
return begin_carry(target, invocation, owner, now);
|
|
2559
2498
|
}
|
|
2560
|
-
function
|
|
2561
|
-
|
|
2562
|
-
|
|
2499
|
+
function adopt_carry(target, carry, owner = NO_OWNER) {
|
|
2500
|
+
const next = {
|
|
2501
|
+
...carry,
|
|
2502
|
+
owner_pid: owner.pid,
|
|
2503
|
+
owner_start: owner.start,
|
|
2504
|
+
is_handed_off: false
|
|
2505
|
+
};
|
|
2506
|
+
stamp_file.remove_stamp(target);
|
|
2507
|
+
return stamp_file.create_stamp(target, next) ? next : void 0;
|
|
2563
2508
|
}
|
|
2564
|
-
function
|
|
2565
|
-
return
|
|
2509
|
+
function is_owner_live(carry) {
|
|
2510
|
+
return process_identity.is_same_process(carry.owner_pid, carry.owner_start) !== false;
|
|
2566
2511
|
}
|
|
2567
|
-
function
|
|
2568
|
-
|
|
2512
|
+
function is_owned_by(carry, owner) {
|
|
2513
|
+
return carry.owner_pid === owner.pid && carry.owner_start === owner.start;
|
|
2514
|
+
}
|
|
2515
|
+
function is_foreign_live_owner(carry, owner) {
|
|
2516
|
+
return is_owner_live(carry) && !is_owned_by(carry, owner);
|
|
2517
|
+
}
|
|
2518
|
+
function is_handed_off_to(carry, invocation) {
|
|
2519
|
+
return carry.is_handed_off === true && carry.invocation === invocation;
|
|
2520
|
+
}
|
|
2521
|
+
function classify_claim(carry, request) {
|
|
2522
|
+
if (is_handed_off_to(carry, request.invocation)) return "resume";
|
|
2523
|
+
if (is_foreign_live_owner(carry, request.owner)) return "busy";
|
|
2524
|
+
if (carry.invocation !== request.invocation) return "mismatch";
|
|
2525
|
+
return request.is_adoption ? "resume" : "standing";
|
|
2526
|
+
}
|
|
2527
|
+
function is_count_refused(carry, owner) {
|
|
2528
|
+
return carry.is_handed_off === true || is_foreign_live_owner(carry, owner);
|
|
2529
|
+
}
|
|
2530
|
+
function is_at_cut_cap(carry) {
|
|
2531
|
+
return carry.cuts >= MAX_CUTS;
|
|
2532
|
+
}
|
|
2533
|
+
function end_carry(target) {
|
|
2534
|
+
stamp_file.remove_stamp(target);
|
|
2535
|
+
}
|
|
2536
|
+
function retrospective_done_of(read2) {
|
|
2537
|
+
if (read2.kind !== "carried" && read2.kind !== "expired") return false;
|
|
2538
|
+
return read2.carry.retrospective === true;
|
|
2539
|
+
}
|
|
2540
|
+
function remaining_of(carry) {
|
|
2541
|
+
if (carry === void 0) return void 0;
|
|
2542
|
+
const declared = run_invocation.issue_numbers(carry.invocation);
|
|
2543
|
+
if (declared === void 0) return void 0;
|
|
2544
|
+
const done = carry.done ?? [];
|
|
2545
|
+
return declared.filter((issue) => !done.includes(issue));
|
|
2546
|
+
}
|
|
2547
|
+
function done_note(carry) {
|
|
2548
|
+
const done = carry.done ?? [];
|
|
2549
|
+
return done.length === 0 ? "" : `, issues ${done.join(", ")} done`;
|
|
2550
|
+
}
|
|
2551
|
+
function describe_carry(carry) {
|
|
2552
|
+
return `${carry.invocation} started ${carry.started_at}; ${String(carry.merged)} merged, ${String(carry.filed)} filed, ${String(carry.failures)} failed in a row, ${String(carry.outages)} outage(s) in a row, ${String(carry.cuts)} cut(s) crossed${done_note(carry)}`;
|
|
2553
|
+
}
|
|
2554
|
+
function expired_message(carry) {
|
|
2555
|
+
return `The ${String(CARRY_MAX_AGE_HOURS)}-hour whole-run bound is spent: ${describe_carry(carry)}. Clear it with \`${END_COMMAND2}\`.`;
|
|
2556
|
+
}
|
|
2557
|
+
function mismatch_message(carry, invocation) {
|
|
2558
|
+
return `A different invocation is carried here \u2014 ${describe_carry(carry)}. This one is \`${invocation}\`. End the standing record with \`${END_COMMAND2}\` once you know its run is over, then begin again.`;
|
|
2559
|
+
}
|
|
2560
|
+
function busy_message2(carry) {
|
|
2561
|
+
return `A live run holds this budget \u2014 ${describe_carry(carry)}, owner pid ${String(carry.owner_pid)} still running. Nothing was established. Wait for that run, or end its record with \`${END_COMMAND2}\` once you know it is over.`;
|
|
2562
|
+
}
|
|
2563
|
+
function standing_message(carry) {
|
|
2564
|
+
return `A run record is standing here that no cut handed off \u2014 ${describe_carry(carry)}. Nothing was established. Carry that budget with \`${RESUME_COMMAND} "${carry.invocation}" ${OWNER_ARGUMENT}\`, or discard it with \`${END_COMMAND2}\` and begin again.`;
|
|
2565
|
+
}
|
|
2566
|
+
function count_refused_message(carry) {
|
|
2567
|
+
if (carry.is_handed_off === true) {
|
|
2568
|
+
return `This budget was handed off at a cut and is waiting for its successor \u2014 ${describe_carry(carry)}. Nothing was counted; the cutting session must not advance a handed-off budget.`;
|
|
2569
|
+
}
|
|
2570
|
+
return `A live run owns this budget \u2014 ${describe_carry(carry)}, owner pid ${String(carry.owner_pid)} still running. Nothing was counted; only its owner advances the budget.`;
|
|
2571
|
+
}
|
|
2572
|
+
function lost_message() {
|
|
2573
|
+
return `Another process established a run record here first, so nothing was established. Read it with \`${READ_COMMAND2}\`.`;
|
|
2574
|
+
}
|
|
2575
|
+
function nothing_to_resume_message() {
|
|
2576
|
+
return `Nothing is carried here, so there is no budget to resume. Begin one with \`pnpm josh run:carry --begin "<invocation>"\`.`;
|
|
2577
|
+
}
|
|
2578
|
+
function unreadable_message3() {
|
|
2579
|
+
return `A run record is here but could not be read; clear it with \`${END_COMMAND2}\` once you know no run is using it.`;
|
|
2580
|
+
}
|
|
2581
|
+
function unknown_message3() {
|
|
2582
|
+
return "This repository\u2019s git directory could not be read, so no run record was established.";
|
|
2583
|
+
}
|
|
2584
|
+
var run_carry = {
|
|
2585
|
+
CARRY_MAX_AGE_HOURS,
|
|
2586
|
+
CARRY_MAX_AGE_MS,
|
|
2587
|
+
END_COMMAND: END_COMMAND2,
|
|
2588
|
+
MAX_CUTS,
|
|
2589
|
+
NO_OWNER,
|
|
2590
|
+
RESUME_COMMAND,
|
|
2591
|
+
adopt_carry,
|
|
2592
|
+
apply_change: run_carry_change.apply_change,
|
|
2593
|
+
begin_carry,
|
|
2594
|
+
busy_message: busy_message2,
|
|
2595
|
+
carry_path,
|
|
2596
|
+
classify: classify3,
|
|
2597
|
+
classify_claim,
|
|
2598
|
+
count_refused_message,
|
|
2599
|
+
is_at_cut_cap,
|
|
2600
|
+
describe_carry,
|
|
2601
|
+
end_carry,
|
|
2602
|
+
expired_message,
|
|
2603
|
+
mismatch_message,
|
|
2604
|
+
fresh_carry,
|
|
2605
|
+
is_count_refused,
|
|
2606
|
+
is_expired: is_expired2,
|
|
2607
|
+
is_foreign_live_owner,
|
|
2608
|
+
is_owner_live,
|
|
2609
|
+
lost_message,
|
|
2610
|
+
nothing_to_resume_message,
|
|
2611
|
+
owner_of,
|
|
2612
|
+
parse_carry,
|
|
2613
|
+
read_carry,
|
|
2614
|
+
remaining_of,
|
|
2615
|
+
replace_carry,
|
|
2616
|
+
repository_directory,
|
|
2617
|
+
retrospective_done_of,
|
|
2618
|
+
standing_message,
|
|
2619
|
+
unknown_message: unknown_message3,
|
|
2620
|
+
unreadable_message: unreadable_message3
|
|
2621
|
+
};
|
|
2622
|
+
|
|
2623
|
+
// scripts/run/run-ship-detach.ts
|
|
2624
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
2625
|
+
import { setTimeout as sleep } from "node:timers/promises";
|
|
2626
|
+
import { z as z8 } from "zod";
|
|
2627
|
+
|
|
2628
|
+
// scripts/run/detached-launch.ts
|
|
2629
|
+
import { spawn } from "node:child_process";
|
|
2630
|
+
import { closeSync, constants, openSync, writeSync } from "node:fs";
|
|
2631
|
+
|
|
2632
|
+
// scripts/agent/agent-launch-environment.ts
|
|
2633
|
+
import { existsSync, lstatSync, mkdirSync, readlinkSync, symlinkSync, unlinkSync } from "node:fs";
|
|
2634
|
+
import path3 from "node:path";
|
|
2635
|
+
|
|
2636
|
+
// scripts/gh/gh-cli-token.ts
|
|
2637
|
+
import { execaSync } from "execa";
|
|
2638
|
+
var GH_CLI_TIMEOUT_MS = 5e3;
|
|
2639
|
+
function get() {
|
|
2640
|
+
try {
|
|
2641
|
+
const { stdout } = execaSync("gh", ["auth", "token"], { timeout: GH_CLI_TIMEOUT_MS });
|
|
2642
|
+
const token = stdout.trim();
|
|
2643
|
+
return token.length > 0 ? token : void 0;
|
|
2644
|
+
} catch {
|
|
2645
|
+
return void 0;
|
|
2646
|
+
}
|
|
2647
|
+
}
|
|
2648
|
+
var gh_cli_token = { get };
|
|
2649
|
+
|
|
2650
|
+
// scripts/agent/codex-home-source.ts
|
|
2651
|
+
import os from "node:os";
|
|
2652
|
+
import path2 from "node:path";
|
|
2653
|
+
function default_home() {
|
|
2654
|
+
return path2.join(os.homedir(), ".codex");
|
|
2655
|
+
}
|
|
2656
|
+
var codex_home_source = { default_home };
|
|
2657
|
+
|
|
2658
|
+
// scripts/agent/agent-launch-environment.ts
|
|
2659
|
+
var OPENAI_PROVIDER2 = "openai";
|
|
2660
|
+
var REVIEWER_HOME = ["node_modules", ".cache", "josh", "openai", "reviewer-home"];
|
|
2661
|
+
var HOME_FILES = ["auth.json", "config.toml"];
|
|
2662
|
+
var PRIVATE_DIRECTORY_MODE = 448;
|
|
2663
|
+
function openai_environment() {
|
|
2664
|
+
const token = gh_cli_token.get();
|
|
2665
|
+
return token === void 0 ? { TMPDIR: PLATFORM_TEMP_ROOT } : { GH_TOKEN: token, TMPDIR: PLATFORM_TEMP_ROOT };
|
|
2666
|
+
}
|
|
2667
|
+
function remove_old_home_link(source, target) {
|
|
2668
|
+
const current = lstatSync(target, { throwIfNoEntry: false });
|
|
2669
|
+
if (current === void 0) return false;
|
|
2670
|
+
if (!current.isSymbolicLink()) throw new Error(`Reviewer home file is not a link: ${target}`);
|
|
2671
|
+
if (existsSync(source) && readlinkSync(target) === source) return true;
|
|
2672
|
+
unlinkSync(target);
|
|
2673
|
+
return false;
|
|
2674
|
+
}
|
|
2675
|
+
function link_home_file(source_home, target_home, name) {
|
|
2676
|
+
const source = path3.join(source_home, name);
|
|
2677
|
+
const target = path3.join(target_home, name);
|
|
2678
|
+
if (!remove_old_home_link(source, target) && existsSync(source)) symlinkSync(source, target);
|
|
2679
|
+
}
|
|
2680
|
+
function reviewer_home(cwd, environment2) {
|
|
2681
|
+
const source = environment2["CODEX_HOME"] ?? process.env["CODEX_HOME"] ?? codex_home_source.default_home();
|
|
2682
|
+
const target = path3.resolve(cwd, ...REVIEWER_HOME);
|
|
2683
|
+
mkdirSync(target, { recursive: true, mode: PRIVATE_DIRECTORY_MODE });
|
|
2684
|
+
for (const name of HOME_FILES) link_home_file(source, target, name);
|
|
2685
|
+
return target;
|
|
2686
|
+
}
|
|
2687
|
+
function build(cwd, profile, environment2 = {}) {
|
|
2688
|
+
if (profile?.provider !== OPENAI_PROVIDER2) return environment2;
|
|
2689
|
+
const base = { ...openai_environment(), ...environment2 };
|
|
2690
|
+
return profile.role === agent_role_profile.REVIEWER ? { ...base, CODEX_HOME: reviewer_home(cwd, environment2) } : base;
|
|
2691
|
+
}
|
|
2692
|
+
var agent_launch_environment = { build };
|
|
2693
|
+
|
|
2694
|
+
// scripts/run/detached-launch.ts
|
|
2695
|
+
var NO_PID_NOTE = "the process started without a pid";
|
|
2696
|
+
var UNSAFE_NOTE = "the wake command or its arguments contain characters that are not safe to execute";
|
|
2697
|
+
var { is_safe_value: is_safe_value2 } = agent_role_profile;
|
|
2698
|
+
function is_safe_argv(argv) {
|
|
2699
|
+
return is_safe_value2(argv.command) && argv.args.every((value) => is_safe_value2(value));
|
|
2700
|
+
}
|
|
2701
|
+
function note_of(error) {
|
|
2702
|
+
return error instanceof Error ? error.message : JSON.stringify(error);
|
|
2703
|
+
}
|
|
2704
|
+
function launched(pid) {
|
|
2705
|
+
return { kind: "launched", pid };
|
|
2706
|
+
}
|
|
2707
|
+
var LOG_FLAGS = constants.O_WRONLY | constants.O_APPEND | constants.O_CREAT | constants.O_NOFOLLOW;
|
|
2708
|
+
var LOG_MODE = 384;
|
|
2709
|
+
function profile_suffix(profile) {
|
|
2710
|
+
return profile === void 0 ? "" : ` \xB7 ${agent_role_profile.describe(profile)}`;
|
|
2711
|
+
}
|
|
2712
|
+
function log_header(argv, profile) {
|
|
2713
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
2714
|
+
return `
|
|
2715
|
+
=== ${stamp} \xB7 started by process ${String(process.pid)} \xB7 ${argv.command}${profile_suffix(profile)} ===
|
|
2716
|
+
`;
|
|
2717
|
+
}
|
|
2718
|
+
function opened_log(log_path2, on_error) {
|
|
2719
|
+
const descriptor = openSync(log_path2, LOG_FLAGS, LOG_MODE);
|
|
2720
|
+
if (!stamp_file.is_own_regular_file(log_path2)) {
|
|
2721
|
+
closeSync(descriptor);
|
|
2722
|
+
on_error(`${log_path2} is not this account's own file, so nothing is kept there`);
|
|
2723
|
+
return void 0;
|
|
2724
|
+
}
|
|
2725
|
+
return descriptor;
|
|
2726
|
+
}
|
|
2727
|
+
function stamped(descriptor, argv, profile, on_error) {
|
|
2728
|
+
if (descriptor === void 0) return;
|
|
2729
|
+
try {
|
|
2730
|
+
writeSync(descriptor, log_header(argv, profile));
|
|
2731
|
+
} catch (error) {
|
|
2732
|
+
on_error(`the session log could not be written: ${note_of(error)}`);
|
|
2733
|
+
}
|
|
2734
|
+
}
|
|
2735
|
+
function open_log(log_path2, on_error) {
|
|
2736
|
+
if (log_path2 === void 0) return void 0;
|
|
2737
|
+
try {
|
|
2738
|
+
return opened_log(log_path2, on_error);
|
|
2739
|
+
} catch (error) {
|
|
2740
|
+
on_error(`the session log at ${log_path2} could not be opened: ${note_of(error)}`);
|
|
2741
|
+
return void 0;
|
|
2742
|
+
}
|
|
2743
|
+
}
|
|
2744
|
+
function ensure_log(log_path2, on_error) {
|
|
2745
|
+
const descriptor = open_log(log_path2, on_error);
|
|
2746
|
+
if (descriptor !== void 0) closeSync(descriptor);
|
|
2747
|
+
}
|
|
2748
|
+
function spawn_options(cwd, log, environment2 = {}, is_detached = true) {
|
|
2569
2749
|
return {
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
max_issues: counts.max,
|
|
2575
|
-
idle_budget_ms: to_idle_ms(counts.idle)
|
|
2750
|
+
cwd,
|
|
2751
|
+
detached: is_detached,
|
|
2752
|
+
stdio: log === void 0 ? "ignore" : ["ignore", log, log],
|
|
2753
|
+
env: { ...process.env, ...agent_session_environment.removed_environment(), ...environment2 }
|
|
2576
2754
|
};
|
|
2577
2755
|
}
|
|
2578
|
-
function
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
}
|
|
2586
|
-
function refuse() {
|
|
2587
|
-
console.error(USAGE);
|
|
2588
|
-
return FAILURE_EXIT_CODE2;
|
|
2756
|
+
function notify_spawn(pid, on_spawn, on_error) {
|
|
2757
|
+
if (pid === void 0) return;
|
|
2758
|
+
try {
|
|
2759
|
+
on_spawn(pid);
|
|
2760
|
+
} catch (error) {
|
|
2761
|
+
on_error(`the child state could not be recorded: ${note_of(error)}`);
|
|
2762
|
+
}
|
|
2589
2763
|
}
|
|
2590
|
-
function
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
console.info(
|
|
2598
|
-
JSON.stringify({ [JSON_KEY]: verdict, reason, is_finish: backlog_budget.is_finish(input) })
|
|
2764
|
+
async function attached_spawn(request, log, on_error, on_spawn) {
|
|
2765
|
+
return await new Promise((resolve3) => {
|
|
2766
|
+
const environment2 = agent_launch_environment.build(request.cwd, request.profile, request.env);
|
|
2767
|
+
const child = spawn(
|
|
2768
|
+
request.argv.command,
|
|
2769
|
+
[...request.argv.args],
|
|
2770
|
+
spawn_options(request.cwd, log, environment2, false)
|
|
2599
2771
|
);
|
|
2600
|
-
|
|
2772
|
+
child.once("error", (error) => {
|
|
2773
|
+
on_error(note_of(error));
|
|
2774
|
+
resolve3({ kind: "failed", note: note_of(error) });
|
|
2775
|
+
});
|
|
2776
|
+
child.once("exit", (exit_code) => {
|
|
2777
|
+
resolve3({ kind: "completed", pid: child.pid ?? 0, exit_code });
|
|
2778
|
+
});
|
|
2779
|
+
notify_spawn(child.pid, on_spawn, on_error);
|
|
2780
|
+
});
|
|
2781
|
+
}
|
|
2782
|
+
function ignore_spawn(_pid) {
|
|
2783
|
+
}
|
|
2784
|
+
function spawned(request, log, on_error) {
|
|
2785
|
+
const { command, args } = request.argv;
|
|
2786
|
+
const environment2 = agent_launch_environment.build(request.cwd, request.profile, request.env);
|
|
2787
|
+
const child = spawn(command, [...args], spawn_options(request.cwd, log, environment2));
|
|
2788
|
+
child.on("error", (error) => {
|
|
2789
|
+
on_error(note_of(error));
|
|
2790
|
+
});
|
|
2791
|
+
child.unref();
|
|
2792
|
+
return child.pid === void 0 ? { kind: "failed", note: NO_PID_NOTE } : launched(child.pid);
|
|
2793
|
+
}
|
|
2794
|
+
function launch(request, on_error) {
|
|
2795
|
+
if (!is_safe_argv(request.argv)) return { kind: "failed", note: UNSAFE_NOTE };
|
|
2796
|
+
const log = open_log(request.log_path, on_error);
|
|
2797
|
+
try {
|
|
2798
|
+
stamped(log, request.argv, request.profile, on_error);
|
|
2799
|
+
return spawned(request, log, on_error);
|
|
2800
|
+
} catch (error) {
|
|
2801
|
+
return { kind: "failed", note: note_of(error) };
|
|
2802
|
+
} finally {
|
|
2803
|
+
if (log !== void 0) closeSync(log);
|
|
2601
2804
|
}
|
|
2602
|
-
path_decision.print_decision(JSON_KEY, verdict, reason, false);
|
|
2603
|
-
return SUCCESS_EXIT_CODE;
|
|
2604
2805
|
}
|
|
2605
|
-
function
|
|
2606
|
-
|
|
2806
|
+
async function launch_attached(request, on_error, on_spawn = ignore_spawn) {
|
|
2807
|
+
if (!is_safe_argv(request.argv)) return { kind: "failed", note: UNSAFE_NOTE };
|
|
2808
|
+
const log = open_log(request.log_path, on_error);
|
|
2809
|
+
try {
|
|
2810
|
+
stamped(log, request.argv, request.profile, on_error);
|
|
2811
|
+
return await attached_spawn(request, log, on_error, on_spawn);
|
|
2812
|
+
} catch (error) {
|
|
2813
|
+
return { kind: "failed", note: note_of(error) };
|
|
2814
|
+
} finally {
|
|
2815
|
+
if (log !== void 0) closeSync(log);
|
|
2816
|
+
}
|
|
2607
2817
|
}
|
|
2608
|
-
var
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
to_answer,
|
|
2618
|
-
to_count,
|
|
2619
|
-
to_time_ms
|
|
2818
|
+
var detached_launch = {
|
|
2819
|
+
UNSAFE_NOTE,
|
|
2820
|
+
ensure_log,
|
|
2821
|
+
is_safe_argv,
|
|
2822
|
+
is_safe_value: is_safe_value2,
|
|
2823
|
+
launch,
|
|
2824
|
+
launch_attached,
|
|
2825
|
+
log_header,
|
|
2826
|
+
note_of
|
|
2620
2827
|
};
|
|
2621
|
-
if (process.argv[1] === fileURLToPath(import.meta.url)) main(process.argv.slice(ARGV_OFFSET));
|
|
2622
2828
|
|
|
2623
|
-
// scripts/run/run-
|
|
2624
|
-
|
|
2625
|
-
var
|
|
2626
|
-
var
|
|
2627
|
-
var
|
|
2628
|
-
var
|
|
2629
|
-
var
|
|
2630
|
-
var
|
|
2631
|
-
var
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2829
|
+
// scripts/run/run-event-stream.ts
|
|
2830
|
+
import { z as z7 } from "zod";
|
|
2831
|
+
var EVENT_PREFIX = "josh-run-events-";
|
|
2832
|
+
var EVENT_SUFFIX = ".jsonl";
|
|
2833
|
+
var EVENT_CAP = 500;
|
|
2834
|
+
var FIRST_POSITION = 0;
|
|
2835
|
+
var POSITION_INCREMENT = 1;
|
|
2836
|
+
var LINE_SEPARATOR = "\n";
|
|
2837
|
+
var EVENT_KIND = {
|
|
2838
|
+
PLAN: "plan",
|
|
2839
|
+
CHILD_LAUNCH: "child-launch",
|
|
2840
|
+
MERGE: "merge",
|
|
2841
|
+
PARK: "park",
|
|
2842
|
+
SPLIT: "split",
|
|
2843
|
+
OUTAGE: "outage",
|
|
2844
|
+
CUT: "cut",
|
|
2845
|
+
// The backlog emptied while nothing of the run's own was in flight — the drain
|
|
2846
|
+
// (joshuafolkken/kit#2335). It marks the position at which the end-of-run retrospective is owed,
|
|
2847
|
+
// *before* the idle watch opens, so `run:step` fires the retrospective at the drain rather than after
|
|
2848
|
+
// the watch runs its course. It is not itself a stop: the run watches on once the retrospective has
|
|
2849
|
+
// run, and the real `STOP` follows when the watch expires.
|
|
2850
|
+
DRAIN: "drain",
|
|
2851
|
+
STOP: "stop",
|
|
2852
|
+
PR_OPENED: "pr-opened",
|
|
2853
|
+
REVIEW_ROUND: "review-round",
|
|
2854
|
+
// The end-of-run retrospective's result, recorded when the run marks the retrospective done
|
|
2855
|
+
// (joshuafolkken/kit#2342). A retrospective that files zero improvements and one that never ran look
|
|
2856
|
+
// the same from outside — no new Issue either way — so the result is put on the stream the report is
|
|
2857
|
+
// generated from: the issues filed (or that none were), and the candidates dropped with why. It is
|
|
2858
|
+
// emitted from the `run:carry --retrospective` close, so marking the retrospective done and recording
|
|
2859
|
+
// what it found are one action rather than two the run could do only one of.
|
|
2860
|
+
RETROSPECTIVE: "retrospective",
|
|
2861
|
+
// Ready backlog work is sitting undispatched while a lane is free and nothing has dispatched for a
|
|
2862
|
+
// while (joshuafolkken/kit#2359). Emitted once per stall episode by the stop-time detector, it is
|
|
2863
|
+
// both the dedup marker — `emit_once_since` refuses a second until a `CHILD_LAUNCH` intervenes
|
|
2864
|
+
// (joshuafolkken/kit#2464) — and the line a
|
|
2865
|
+
// terminal reader following the stream sees. `run:step` reads it as `backlog:next`, so a run that
|
|
2866
|
+
// stalled is pointed straight at dispatching the work rather than left waiting.
|
|
2867
|
+
STALL: "stall",
|
|
2868
|
+
// The run's own driver is gone: the cut handed the budget off, the owner has died, and no supervisor
|
|
2869
|
+
// is watching (joshuafolkken/kit#2375). Emitted once per strand episode by the stop-time detector,
|
|
2870
|
+
// exactly as `STALL` is — the newest-event dedup keeps a run polled every stop from notifying more
|
|
2871
|
+
// than once, and a terminal reader following the stream sees the line. The strand is the step before
|
|
2872
|
+
// the stall: a stalled run still has a driver that could dispatch, a stranded one has none.
|
|
2873
|
+
STRANDED: "stranded",
|
|
2874
|
+
// One `josh ship` stage starting, succeeding or failing (joshuafolkken/kit#2426). It is a trace of the
|
|
2875
|
+
// composite's progress rather than a position the run is at — the positions a ship leaves behind are
|
|
2876
|
+
// the closed issue its `followup` merges, or a detached supervisor's `SHIP_LAUNCH` / `SHIP_STOP` below
|
|
2877
|
+
// — so it is one of the `TRACE_KINDS` the last-event read skips.
|
|
2878
|
+
SHIP_STAGE: "ship-stage",
|
|
2879
|
+
// One progress watcher line — the `at … / next …` heartbeat `run:progress` prints
|
|
2880
|
+
// (joshuafolkken/kit#2437). Printed only to the watcher's own output, a headless successor's heartbeat
|
|
2881
|
+
// was buried in its log after a cut; on the stream it reaches the attached session's relay. It says
|
|
2882
|
+
// the run is alive rather than where it is, so it is a trace kind like `SHIP_STAGE`.
|
|
2883
|
+
HEARTBEAT: "heartbeat",
|
|
2884
|
+
// The post-implementation region handed to a detached `josh ship --detach` supervisor
|
|
2885
|
+
// (joshuafolkken/kit#2428). Unlike a stage trace it is a position: the agent has ended and the
|
|
2886
|
+
// supervisor carries the run, so `run:step` answers `wait` until it stops or the issue closes.
|
|
2887
|
+
SHIP_LAUNCH: "ship-launch",
|
|
2888
|
+
// The supervisor stopped at a failed stage — a red gate, a High/Medium review, a failed push, red CI
|
|
2889
|
+
// (joshuafolkken/kit#2428). The position that hands control back: `run:step` prints the command that
|
|
2890
|
+
// shows the stopped report, so the agent fixes it and relaunches rather than rebuilding the context.
|
|
2891
|
+
SHIP_STOP: "ship-stop"
|
|
2892
|
+
};
|
|
2893
|
+
var EVENT_KINDS = Object.values(EVENT_KIND);
|
|
2894
|
+
var TRACE_KINDS = /* @__PURE__ */ new Set([EVENT_KIND.SHIP_STAGE, EVENT_KIND.HEARTBEAT]);
|
|
2895
|
+
var event_schema = z7.object({
|
|
2896
|
+
pos: z7.number(),
|
|
2897
|
+
at: z7.string(),
|
|
2898
|
+
kind: z7.string(),
|
|
2899
|
+
text: z7.string()
|
|
2900
|
+
});
|
|
2901
|
+
function is_event_kind(value) {
|
|
2902
|
+
return EVENT_KINDS.includes(value);
|
|
2638
2903
|
}
|
|
2639
|
-
function
|
|
2640
|
-
|
|
2641
|
-
const value = backlog_budget_cli.to_count(raw);
|
|
2642
|
-
if (flag === void 0 || value === void 0) return void 0;
|
|
2643
|
-
return `${flag} ${String(value)}`;
|
|
2904
|
+
function target_of(repository2) {
|
|
2905
|
+
return stamp_file.stamp_path(EVENT_PREFIX, repository2, EVENT_SUFFIX);
|
|
2644
2906
|
}
|
|
2645
|
-
function
|
|
2646
|
-
|
|
2647
|
-
if (token === ONLY_FLAG) return { part: ONLY_FLAG, advance: ONLY_STEP };
|
|
2648
|
-
const part = flag_token(token, tokens[index + VALUE_OFFSET]);
|
|
2649
|
-
return part === void 0 ? void 0 : { part, advance: FLAG_PAIR_LENGTH };
|
|
2907
|
+
function is_present(event) {
|
|
2908
|
+
return event !== void 0;
|
|
2650
2909
|
}
|
|
2651
|
-
function
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2910
|
+
function parse_line(line) {
|
|
2911
|
+
return event_schema.safeParse(json_value.parse_or_undefined(line)).data;
|
|
2912
|
+
}
|
|
2913
|
+
function read_events(target) {
|
|
2914
|
+
const raw = stamp_file.read_stamp_text(target);
|
|
2915
|
+
if (raw === void 0) return [];
|
|
2916
|
+
return raw.split(LINE_SEPARATOR).map((line) => line.trim()).filter((line) => line.length > 0).map((line) => parse_line(line)).filter(is_present);
|
|
2917
|
+
}
|
|
2918
|
+
function last_position(events) {
|
|
2919
|
+
return events[events.length - POSITION_INCREMENT]?.pos ?? FIRST_POSITION;
|
|
2920
|
+
}
|
|
2921
|
+
function serialize(events) {
|
|
2922
|
+
return `${events.map((event) => JSON.stringify(event)).join(LINE_SEPARATOR)}${LINE_SEPARATOR}`;
|
|
2923
|
+
}
|
|
2924
|
+
function append(target, kind, text, at) {
|
|
2925
|
+
if (!is_event_kind(kind)) return { appended: false, position: FIRST_POSITION };
|
|
2926
|
+
const existing = read_events(target);
|
|
2927
|
+
const position = last_position(existing) + POSITION_INCREMENT;
|
|
2928
|
+
const bounded = [...existing, { pos: position, at, kind, text }].slice(-EVENT_CAP);
|
|
2929
|
+
stamp_file.write_text_stamp(target, serialize(bounded));
|
|
2930
|
+
return { appended: true, position };
|
|
2931
|
+
}
|
|
2932
|
+
function read_from(target, position) {
|
|
2933
|
+
const events = read_events(target);
|
|
2934
|
+
return {
|
|
2935
|
+
events: events.filter((event) => event.pos > position),
|
|
2936
|
+
next_position: last_position(events)
|
|
2937
|
+
};
|
|
2938
|
+
}
|
|
2939
|
+
function read_last(target) {
|
|
2940
|
+
return read_events(target).findLast((event) => !TRACE_KINDS.has(event.kind));
|
|
2941
|
+
}
|
|
2942
|
+
function has_since(events, kind, reset_kind) {
|
|
2943
|
+
const reset_at = events.findLastIndex((event) => event.kind === reset_kind);
|
|
2944
|
+
return events.slice(reset_at + POSITION_INCREMENT).some((event) => event.kind === kind);
|
|
2945
|
+
}
|
|
2946
|
+
var FIELD_SEPARATOR = " \xB7 ";
|
|
2947
|
+
function format_event(event) {
|
|
2948
|
+
return [event.at, event.kind, event.text].join(FIELD_SEPARATOR);
|
|
2949
|
+
}
|
|
2950
|
+
var run_event_stream = {
|
|
2951
|
+
EVENT_CAP,
|
|
2952
|
+
EVENT_KIND,
|
|
2953
|
+
EVENT_KINDS,
|
|
2954
|
+
TRACE_KINDS,
|
|
2955
|
+
append,
|
|
2956
|
+
format_event,
|
|
2957
|
+
has_since,
|
|
2958
|
+
read_events,
|
|
2959
|
+
read_from,
|
|
2960
|
+
read_last,
|
|
2961
|
+
target_of
|
|
2962
|
+
};
|
|
2963
|
+
|
|
2964
|
+
// scripts/run/run-event-scope.ts
|
|
2965
|
+
var SINCE_SCOPE = "since";
|
|
2966
|
+
var UNKNOWN_SCOPE = "unknown";
|
|
2967
|
+
var UNKNOWN_EVENT_SCOPE = { kind: UNKNOWN_SCOPE };
|
|
2968
|
+
function moment_of(at) {
|
|
2969
|
+
const parsed = Date.parse(at);
|
|
2970
|
+
return Number.isNaN(parsed) ? void 0 : parsed;
|
|
2971
|
+
}
|
|
2972
|
+
function is_within(event, floor) {
|
|
2973
|
+
const at = moment_of(event.at);
|
|
2974
|
+
return at !== void 0 && at >= floor;
|
|
2975
|
+
}
|
|
2976
|
+
function scoped_events(events, scope) {
|
|
2977
|
+
if (scope.kind === UNKNOWN_SCOPE) return void 0;
|
|
2978
|
+
const floor = moment_of(scope.started_at);
|
|
2979
|
+
if (floor === void 0) return void 0;
|
|
2980
|
+
return events.filter((event) => is_within(event, floor));
|
|
2981
|
+
}
|
|
2982
|
+
function scope_of(read2) {
|
|
2983
|
+
if (read2.kind === "carried" || read2.kind === "expired") {
|
|
2984
|
+
return { kind: SINCE_SCOPE, started_at: read2.carry.started_at };
|
|
2659
2985
|
}
|
|
2660
|
-
return
|
|
2986
|
+
return UNKNOWN_EVENT_SCOPE;
|
|
2661
2987
|
}
|
|
2662
|
-
function
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
const issue = Number(digits);
|
|
2667
|
-
return Number.isSafeInteger(issue) ? issue : void 0;
|
|
2988
|
+
function last_scoped_event(events, scope) {
|
|
2989
|
+
return scoped_events(events, scope)?.findLast(
|
|
2990
|
+
(event) => !run_event_stream.TRACE_KINDS.has(event.kind)
|
|
2991
|
+
);
|
|
2668
2992
|
}
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2993
|
+
var SHIP_POSITION_KINDS = /* @__PURE__ */ new Set([
|
|
2994
|
+
run_event_stream.EVENT_KIND.SHIP_LAUNCH,
|
|
2995
|
+
run_event_stream.EVENT_KIND.SHIP_STOP
|
|
2996
|
+
]);
|
|
2997
|
+
var KIND = run_event_stream.EVENT_KIND;
|
|
2998
|
+
var BATCH_RECORD_KINDS = /* @__PURE__ */ new Set([
|
|
2999
|
+
KIND.CHILD_LAUNCH,
|
|
3000
|
+
KIND.PARK,
|
|
3001
|
+
KIND.SPLIT,
|
|
3002
|
+
KIND.RETROSPECTIVE,
|
|
3003
|
+
KIND.STRANDED
|
|
3004
|
+
]);
|
|
3005
|
+
var ISSUE_REFERENCE = /#(\d+)/u;
|
|
3006
|
+
function is_foreign_ship_event(event, issue) {
|
|
3007
|
+
return SHIP_POSITION_KINDS.has(event.kind) && !event.text.startsWith(`#${issue} `);
|
|
3008
|
+
}
|
|
3009
|
+
function is_own_ship_event(event, issue) {
|
|
3010
|
+
return SHIP_POSITION_KINDS.has(event.kind) && !is_foreign_ship_event(event, issue);
|
|
3011
|
+
}
|
|
3012
|
+
function names_issue(event, issue) {
|
|
3013
|
+
return ISSUE_REFERENCE.exec(event.text)?.[1] === issue;
|
|
3014
|
+
}
|
|
3015
|
+
function is_lane_position(event, issue) {
|
|
3016
|
+
return !BATCH_RECORD_KINDS.has(event.kind) && names_issue(event, issue);
|
|
3017
|
+
}
|
|
3018
|
+
function since_own_launch(events, issue) {
|
|
3019
|
+
const launch3 = events.findLastIndex(
|
|
3020
|
+
(event) => event.kind === KIND.CHILD_LAUNCH && names_issue(event, issue)
|
|
3021
|
+
);
|
|
3022
|
+
return events.slice(launch3 + 1);
|
|
3023
|
+
}
|
|
3024
|
+
function is_foreign_event(event, issue, is_lane_child) {
|
|
3025
|
+
if (is_lane_child) return !is_lane_position(event, issue);
|
|
3026
|
+
return is_foreign_ship_event(event, issue);
|
|
3027
|
+
}
|
|
3028
|
+
function last_issue_event(events, scope, issue, is_lane_child) {
|
|
3029
|
+
const attempt = is_lane_child ? since_own_launch(events, issue) : events;
|
|
3030
|
+
const own2 = attempt.filter((event) => !is_foreign_event(event, issue, is_lane_child));
|
|
3031
|
+
if (scope.kind === SINCE_SCOPE) return last_scoped_event(own2, scope);
|
|
3032
|
+
return own2.findLast((event) => is_own_ship_event(event, issue));
|
|
3033
|
+
}
|
|
3034
|
+
var run_event_scope = {
|
|
3035
|
+
UNKNOWN_EVENT_SCOPE,
|
|
3036
|
+
last_issue_event,
|
|
3037
|
+
last_scoped_event,
|
|
3038
|
+
scope_of,
|
|
3039
|
+
scoped_events
|
|
3040
|
+
};
|
|
3041
|
+
|
|
3042
|
+
// scripts/run/run-event-stream-emit.ts
|
|
3043
|
+
function now_iso() {
|
|
3044
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
2672
3045
|
}
|
|
2673
|
-
function
|
|
2674
|
-
const
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
3046
|
+
async function stream_target() {
|
|
3047
|
+
const repository2 = await run_carry.repository_directory();
|
|
3048
|
+
return repository2 === void 0 ? void 0 : run_event_stream.target_of(repository2);
|
|
3049
|
+
}
|
|
3050
|
+
async function emit(kind, text) {
|
|
3051
|
+
try {
|
|
3052
|
+
const target = await stream_target();
|
|
3053
|
+
if (target === void 0) return;
|
|
3054
|
+
run_event_stream.append(target, kind, text, now_iso());
|
|
3055
|
+
} catch {
|
|
2680
3056
|
}
|
|
2681
|
-
return issues;
|
|
2682
3057
|
}
|
|
2683
|
-
function
|
|
2684
|
-
|
|
3058
|
+
async function emit_once(kind, text) {
|
|
3059
|
+
try {
|
|
3060
|
+
const target = await stream_target();
|
|
3061
|
+
if (target === void 0 || run_event_stream.read_last(target)?.kind === kind) return false;
|
|
3062
|
+
return run_event_stream.append(target, kind, text, now_iso()).appended;
|
|
3063
|
+
} catch {
|
|
3064
|
+
return false;
|
|
3065
|
+
}
|
|
2685
3066
|
}
|
|
2686
|
-
function
|
|
2687
|
-
|
|
3067
|
+
function invocation_events(repository2, target) {
|
|
3068
|
+
const events = run_event_stream.read_events(target);
|
|
3069
|
+
const scope = run_event_scope.scope_of(run_carry.read_carry(run_carry.carry_path(repository2)));
|
|
3070
|
+
return run_event_scope.scoped_events(events, scope) ?? events;
|
|
2688
3071
|
}
|
|
2689
|
-
function
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
3072
|
+
async function emit_once_since(kind, text, reset_kind) {
|
|
3073
|
+
try {
|
|
3074
|
+
const repository2 = await run_carry.repository_directory();
|
|
3075
|
+
if (repository2 === void 0) return false;
|
|
3076
|
+
const target = run_event_stream.target_of(repository2);
|
|
3077
|
+
if (run_event_stream.has_since(invocation_events(repository2, target), kind, reset_kind)) {
|
|
3078
|
+
return false;
|
|
3079
|
+
}
|
|
3080
|
+
return run_event_stream.append(target, kind, text, now_iso()).appended;
|
|
3081
|
+
} catch {
|
|
3082
|
+
return false;
|
|
3083
|
+
}
|
|
2695
3084
|
}
|
|
2696
|
-
function
|
|
2697
|
-
|
|
2698
|
-
if (tokens[FIRST_TOKEN] !== BACKLOG_COMMAND) return void 0;
|
|
2699
|
-
return rebuilt_backlog(tokens);
|
|
3085
|
+
async function emit_heartbeat(line) {
|
|
3086
|
+
await emit(run_event_stream.EVENT_KIND.HEARTBEAT, line);
|
|
2700
3087
|
}
|
|
2701
|
-
function
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
3088
|
+
async function current_events() {
|
|
3089
|
+
try {
|
|
3090
|
+
const repository2 = await run_carry.repository_directory();
|
|
3091
|
+
if (repository2 === void 0) return [];
|
|
3092
|
+
const read2 = run_carry.read_carry(run_carry.carry_path(repository2));
|
|
3093
|
+
const scope = run_event_scope.scope_of(read2);
|
|
3094
|
+
const events = run_event_stream.read_events(run_event_stream.target_of(repository2));
|
|
3095
|
+
return run_event_scope.scoped_events(events, scope) ?? [];
|
|
3096
|
+
} catch {
|
|
3097
|
+
return [];
|
|
3098
|
+
}
|
|
3099
|
+
}
|
|
3100
|
+
var run_event_stream_emit = {
|
|
3101
|
+
current_events,
|
|
3102
|
+
emit,
|
|
3103
|
+
emit_heartbeat,
|
|
3104
|
+
emit_once,
|
|
3105
|
+
emit_once_since,
|
|
3106
|
+
stream_target
|
|
3107
|
+
};
|
|
3108
|
+
|
|
3109
|
+
// scripts/run/run-ship-detach.ts
|
|
3110
|
+
var LOG_PREFIX = "josh-ship-log-";
|
|
3111
|
+
var PID_PREFIX = "josh-ship-pid-";
|
|
3112
|
+
var BODY_PREFIX = "josh-ship-notify-";
|
|
3113
|
+
var KEY_SEPARATOR = "-";
|
|
3114
|
+
var LOG_SUFFIX = ".log";
|
|
3115
|
+
var BODY_SUFFIX = ".txt";
|
|
3116
|
+
var PNPM = "pnpm";
|
|
3117
|
+
var INLINE_NOTIFY = "--notify-message";
|
|
3118
|
+
var FILE_NOTIFY = "--notify-message-file";
|
|
3119
|
+
var NOTIFY_VALUE_INDEX = 1;
|
|
3120
|
+
var SUPERVISED_KEY = "JOSH_SHIP_SUPERVISED";
|
|
3121
|
+
var LAUNCH_ID_KEY = "JOSH_SHIP_LAUNCH_ID";
|
|
3122
|
+
var SUPERVISED_VALUE = "1";
|
|
3123
|
+
var LAUNCHED = "launched";
|
|
3124
|
+
var BUSY = "busy";
|
|
3125
|
+
var FAILED = "failed";
|
|
3126
|
+
var RESULT_PREFIX = "josh-ship-result-";
|
|
3127
|
+
var RECORD_POLL_MS = 25;
|
|
3128
|
+
var RECORD_WAIT_ATTEMPTS = 200;
|
|
3129
|
+
var CLAIM_WINDOW_MS = 12e4;
|
|
3130
|
+
var ship_record_schema = z8.object({
|
|
3131
|
+
pid: z8.number().int().positive().optional(),
|
|
3132
|
+
process_start: z8.string().optional(),
|
|
3133
|
+
launched_at: z8.number().optional(),
|
|
3134
|
+
launcher_pid: z8.number().int().positive().optional(),
|
|
3135
|
+
launcher_start: z8.string().optional(),
|
|
3136
|
+
launch_id: z8.string(),
|
|
3137
|
+
result: z8.enum(["success", "failed"]).optional()
|
|
3138
|
+
});
|
|
3139
|
+
var LAUNCH_MARK = " \xB7 started by process ";
|
|
3140
|
+
var HEADER_START = "\n";
|
|
3141
|
+
function key(prefix, request) {
|
|
3142
|
+
return stamp_file.stamp_path(`${prefix}${request.number}${KEY_SEPARATOR}`, request.repository);
|
|
3143
|
+
}
|
|
3144
|
+
function log_path(repository2, number) {
|
|
3145
|
+
return stamp_file.stamp_path(`${LOG_PREFIX}${number}${KEY_SEPARATOR}`, repository2, LOG_SUFFIX);
|
|
3146
|
+
}
|
|
3147
|
+
function result_path(repository2, number) {
|
|
3148
|
+
return stamp_file.stamp_path(`${RESULT_PREFIX}${number}${KEY_SEPARATOR}`, repository2);
|
|
3149
|
+
}
|
|
3150
|
+
function read_record(repository2, number) {
|
|
3151
|
+
try {
|
|
3152
|
+
const raw = stamp_file.read_stamp_text(result_path(repository2, number));
|
|
3153
|
+
if (raw === void 0) return void 0;
|
|
3154
|
+
const value = JSON.parse(raw);
|
|
3155
|
+
const parsed = ship_record_schema.safeParse(value);
|
|
3156
|
+
return parsed.success ? parsed.data : void 0;
|
|
3157
|
+
} catch {
|
|
3158
|
+
return void 0;
|
|
3159
|
+
}
|
|
3160
|
+
}
|
|
3161
|
+
function record_launch(request, pid, launch_id) {
|
|
3162
|
+
stamp_file.write_text_stamp(key(PID_PREFIX, request), String(pid));
|
|
3163
|
+
const process_start = process_identity.read_start(pid);
|
|
3164
|
+
stamp_file.replace_stamp(result_path(request.repository, request.number), {
|
|
3165
|
+
pid,
|
|
3166
|
+
launch_id,
|
|
3167
|
+
launched_at: Date.now(),
|
|
3168
|
+
...process_start !== void 0 && { process_start }
|
|
3169
|
+
});
|
|
3170
|
+
}
|
|
3171
|
+
function supervisor_environment(launch_id) {
|
|
3172
|
+
return {
|
|
3173
|
+
...agent_role_profile.handoff_environment(),
|
|
3174
|
+
[SUPERVISED_KEY]: SUPERVISED_VALUE,
|
|
3175
|
+
[LAUNCH_ID_KEY]: launch_id
|
|
3176
|
+
};
|
|
3177
|
+
}
|
|
3178
|
+
function is_within_claim_window(record) {
|
|
3179
|
+
return record.launched_at !== void 0 && Date.now() - record.launched_at < CLAIM_WINDOW_MS;
|
|
3180
|
+
}
|
|
3181
|
+
function has_live_identity(pid, record) {
|
|
3182
|
+
if (record.process_start === void 0) {
|
|
3183
|
+
return is_within_claim_window(record) && process_identity.is_live_pid(pid);
|
|
3184
|
+
}
|
|
3185
|
+
return process_identity.is_same_process(pid, record.process_start) !== false;
|
|
3186
|
+
}
|
|
3187
|
+
function result_of(record) {
|
|
3188
|
+
if (record.pid === void 0) {
|
|
3189
|
+
const is_launcher = process_identity.is_same_process(record.launcher_pid, record.launcher_start);
|
|
3190
|
+
return is_launcher === false ? "abnormal" : "running";
|
|
3191
|
+
}
|
|
3192
|
+
if (has_live_identity(record.pid, record)) return "running";
|
|
3193
|
+
return record.result ?? "abnormal";
|
|
3194
|
+
}
|
|
3195
|
+
function read_result(repository2, number) {
|
|
3196
|
+
const record = read_record(repository2, number);
|
|
3197
|
+
return record === void 0 ? void 0 : { launch_id: record.launch_id, result: result_of(record) };
|
|
3198
|
+
}
|
|
3199
|
+
function current_record(repository2, number) {
|
|
3200
|
+
const record = read_record(repository2, number);
|
|
3201
|
+
return record?.launch_id === process.env[LAUNCH_ID_KEY] ? record : void 0;
|
|
3202
|
+
}
|
|
3203
|
+
function is_pending(record) {
|
|
3204
|
+
return record !== void 0 && record.pid === void 0;
|
|
3205
|
+
}
|
|
3206
|
+
async function ready_record(repository2, number) {
|
|
3207
|
+
let record = current_record(repository2, number);
|
|
3208
|
+
for (let attempt = 0; attempt < RECORD_WAIT_ATTEMPTS; attempt += 1) {
|
|
3209
|
+
if (!is_pending(record)) return record;
|
|
3210
|
+
await sleep(RECORD_POLL_MS);
|
|
3211
|
+
record = current_record(repository2, number);
|
|
3212
|
+
}
|
|
3213
|
+
return void 0;
|
|
3214
|
+
}
|
|
3215
|
+
async function update_record(repository2, number, fields) {
|
|
3216
|
+
const record = await ready_record(repository2, number);
|
|
3217
|
+
if (record === void 0) return;
|
|
3218
|
+
stamp_file.replace_stamp(result_path(repository2, number), { ...record, ...fields });
|
|
3219
|
+
}
|
|
3220
|
+
async function mark_result(repository2, number, code) {
|
|
3221
|
+
await update_record(repository2, number, { result: code === 0 ? "success" : "failed" });
|
|
3222
|
+
}
|
|
3223
|
+
async function claim_identity(repository2, number) {
|
|
3224
|
+
const own2 = process_identity.own_fields();
|
|
3225
|
+
if (own2.process_start === void 0) return;
|
|
3226
|
+
await update_record(repository2, number, own2);
|
|
3227
|
+
}
|
|
3228
|
+
function failed_launch(request, note) {
|
|
3229
|
+
stamp_file.remove_stamp(result_path(request.repository, request.number));
|
|
3230
|
+
return { verdict: FAILED, note };
|
|
3231
|
+
}
|
|
3232
|
+
function notify_arguments(request) {
|
|
3233
|
+
const [flag, value] = [request.notify[0], request.notify[NOTIFY_VALUE_INDEX]];
|
|
3234
|
+
if (flag !== INLINE_NOTIFY || value === void 0) return request.notify;
|
|
3235
|
+
const body_path = stamp_file.stamp_path(
|
|
3236
|
+
`${BODY_PREFIX}${request.number}${KEY_SEPARATOR}`,
|
|
3237
|
+
request.repository,
|
|
3238
|
+
BODY_SUFFIX
|
|
3239
|
+
);
|
|
3240
|
+
stamp_file.write_text_stamp(body_path, value);
|
|
3241
|
+
return [FILE_NOTIFY, body_path];
|
|
3242
|
+
}
|
|
3243
|
+
function supervisor_argv(request) {
|
|
3244
|
+
const review = request.is_review ? ["--review"] : [];
|
|
3245
|
+
const cites = request.cites.flatMap((cite) => ["--cite", cite]);
|
|
3246
|
+
return {
|
|
3247
|
+
command: PNPM,
|
|
3248
|
+
args: [
|
|
3249
|
+
"josh",
|
|
3250
|
+
"ship",
|
|
3251
|
+
...review,
|
|
3252
|
+
...notify_arguments(request),
|
|
3253
|
+
...request.body,
|
|
3254
|
+
...cites,
|
|
3255
|
+
request.title
|
|
3256
|
+
]
|
|
3257
|
+
};
|
|
3258
|
+
}
|
|
3259
|
+
function prepare_launch(request) {
|
|
3260
|
+
const launch_id = randomUUID2();
|
|
3261
|
+
const launcher = process_identity.own_fields();
|
|
3262
|
+
stamp_file.replace_stamp(result_path(request.repository, request.number), {
|
|
3263
|
+
launch_id,
|
|
3264
|
+
launcher_pid: launcher.pid,
|
|
3265
|
+
...launcher.process_start !== void 0 && { launcher_start: launcher.process_start }
|
|
3266
|
+
});
|
|
3267
|
+
return launch_id;
|
|
3268
|
+
}
|
|
3269
|
+
function launch2(request) {
|
|
3270
|
+
const notes = [];
|
|
3271
|
+
const log = log_path(request.repository, request.number);
|
|
3272
|
+
const launch_id = prepare_launch(request);
|
|
3273
|
+
const result = detached_launch.launch(
|
|
3274
|
+
{
|
|
3275
|
+
argv: supervisor_argv(request),
|
|
3276
|
+
cwd: request.cwd,
|
|
3277
|
+
log_path: log,
|
|
3278
|
+
// The provider travels as a mark because the launch strips the session keys that name it, and
|
|
3279
|
+
// `ship --review` resolves its reviewer from it (joshuafolkken/kit#2456).
|
|
3280
|
+
env: supervisor_environment(launch_id)
|
|
3281
|
+
},
|
|
3282
|
+
(note) => {
|
|
3283
|
+
notes.push(note);
|
|
3284
|
+
}
|
|
3285
|
+
);
|
|
3286
|
+
if (result.kind === "failed") return failed_launch(request, result.note);
|
|
3287
|
+
record_launch(request, result.pid, launch_id);
|
|
3288
|
+
return {
|
|
3289
|
+
verdict: LAUNCHED,
|
|
3290
|
+
note: [`supervisor ${String(result.pid)} \u2014 log: ${log}`, ...notes].join("\n")
|
|
3291
|
+
};
|
|
3292
|
+
}
|
|
3293
|
+
async function detach(request) {
|
|
3294
|
+
if (read_result(request.repository, request.number)?.result === "running") {
|
|
3295
|
+
return { verdict: BUSY, note: `a ship supervisor for #${request.number} is already running` };
|
|
3296
|
+
}
|
|
3297
|
+
const result = launch2(request);
|
|
3298
|
+
if (result.verdict === LAUNCHED) {
|
|
3299
|
+
await run_event_stream_emit.emit(
|
|
3300
|
+
run_event_stream.EVENT_KIND.SHIP_LAUNCH,
|
|
3301
|
+
`#${request.number} ship supervisor launched`
|
|
3302
|
+
);
|
|
3303
|
+
}
|
|
3304
|
+
return result;
|
|
3305
|
+
}
|
|
3306
|
+
function last_launch(text) {
|
|
3307
|
+
const mark = text.lastIndexOf(LAUNCH_MARK);
|
|
3308
|
+
if (mark === -1) return text;
|
|
3309
|
+
return text.slice(text.lastIndexOf(HEADER_START, mark) + HEADER_START.length);
|
|
3310
|
+
}
|
|
3311
|
+
function read_log(repository2, number) {
|
|
3312
|
+
const text = stamp_file.read_stamp_text(log_path(repository2, number));
|
|
3313
|
+
return text === void 0 ? void 0 : last_launch(text);
|
|
3314
|
+
}
|
|
3315
|
+
function is_supervised(source = process.env) {
|
|
3316
|
+
return source[SUPERVISED_KEY] === SUPERVISED_VALUE;
|
|
3317
|
+
}
|
|
3318
|
+
var run_ship_detach = {
|
|
3319
|
+
BUSY,
|
|
3320
|
+
FAILED,
|
|
3321
|
+
LAUNCHED,
|
|
3322
|
+
LAUNCH_ID_KEY,
|
|
3323
|
+
claim_identity,
|
|
3324
|
+
mark_result,
|
|
3325
|
+
read_result,
|
|
3326
|
+
SUPERVISED_KEY,
|
|
3327
|
+
detach,
|
|
3328
|
+
is_supervised,
|
|
3329
|
+
last_launch,
|
|
3330
|
+
log_path,
|
|
3331
|
+
read_log,
|
|
3332
|
+
supervisor_argv
|
|
3333
|
+
};
|
|
3334
|
+
|
|
3335
|
+
// scripts/lane/lane-handoff.ts
|
|
3336
|
+
function is_ship_running(issue, directory) {
|
|
3337
|
+
const repository2 = git_common_directory.repository(directory);
|
|
3338
|
+
return repository2 !== void 0 && run_ship_detach.read_result(repository2, issue)?.result === "running";
|
|
3339
|
+
}
|
|
3340
|
+
function is_handed_off(directory, source = process.env) {
|
|
3341
|
+
const issue = lane_child_marker.marked_issue(source);
|
|
3342
|
+
if (issue === void 0 || !lane_child_marker.is_child_of(directory, source)) return false;
|
|
3343
|
+
return is_ship_running(issue, directory);
|
|
3344
|
+
}
|
|
3345
|
+
var lane_handoff = { is_handed_off, is_ship_running };
|
|
3346
|
+
|
|
3347
|
+
// scripts/issue/issue-labels.ts
|
|
3348
|
+
var EPIC_LABEL = "epic";
|
|
3349
|
+
var ENHANCEMENT_LABEL = "enhancement";
|
|
3350
|
+
var BREAKING_CHANGE_LABEL = "breaking-change";
|
|
3351
|
+
var IN_PROGRESS_LABEL = "in-progress";
|
|
3352
|
+
var PLANNED_LABEL = "run:planned";
|
|
3353
|
+
var NEEDS_DECISION_LABEL = "needs-decision";
|
|
3354
|
+
var RUN_SOLO_LABEL = "run:solo";
|
|
3355
|
+
var RUN_LANE_LABEL = "run:lane";
|
|
3356
|
+
var PRIORITY_HIGH_LABEL = "priority:high";
|
|
3357
|
+
var NEEDS_HUMAN_REVIEW_LABEL = "needs-human-review";
|
|
3358
|
+
var ALREADY_DONE_LABEL = "already-done";
|
|
3359
|
+
var INTERRUPT_ROUTE_LABEL = "route:interrupt";
|
|
3360
|
+
var REVIEW_CAP_ROUTE_LABEL = "route:review-cap";
|
|
3361
|
+
var SPLIT_ROUTE_LABEL = "route:split";
|
|
3362
|
+
var TIER_A_ROUTE_LABEL = "route:tier-a";
|
|
3363
|
+
var FILING_ROUTE_LABELS = [
|
|
3364
|
+
{
|
|
3365
|
+
name: INTERRUPT_ROUTE_LABEL,
|
|
3366
|
+
// Not `5319e7`, which is the `epic` label's purple: in a listing an interrupt would render as
|
|
3367
|
+
// an epic, and the two are read at a glance rather than by name.
|
|
3368
|
+
color: "1d76db",
|
|
3369
|
+
// Keyed to the tests rather than to severity. "A serious defect" is the self-assessment
|
|
3370
|
+
// `wip-cap.md` bans as a criterion, and this string is what a person reads in `gh label list`.
|
|
3371
|
+
description: "Filed past the WIP cap \u2014 meets one of the three interrupt tests (wip-cap.md)"
|
|
3372
|
+
},
|
|
3373
|
+
{
|
|
3374
|
+
name: REVIEW_CAP_ROUTE_LABEL,
|
|
3375
|
+
color: "eab308",
|
|
3376
|
+
description: "Filed by the review round cap's carry-forward (prompts/review.md \u2192 Review round cap)"
|
|
3377
|
+
},
|
|
3378
|
+
{
|
|
3379
|
+
name: SPLIT_ROUTE_LABEL,
|
|
3380
|
+
color: "0e8a16",
|
|
3381
|
+
description: "A child issue created by a split (split-assessment.md)"
|
|
3382
|
+
},
|
|
3383
|
+
{
|
|
3384
|
+
name: TIER_A_ROUTE_LABEL,
|
|
3385
|
+
color: "d93f0b",
|
|
3386
|
+
description: "Filed Tier A during implementation \u2014 an upstream defect or a prerequisite"
|
|
3387
|
+
}
|
|
3388
|
+
];
|
|
3389
|
+
var DEPTH_0_LABEL = "depth:0";
|
|
3390
|
+
var DEPTH_1_LABEL = "depth:1";
|
|
3391
|
+
var DEPTH_2_LABEL = "depth:2";
|
|
3392
|
+
var DEPTH_LABELS = [
|
|
3393
|
+
{
|
|
3394
|
+
name: DEPTH_0_LABEL,
|
|
3395
|
+
color: "0e8a16",
|
|
3396
|
+
description: "Depth 0 \u2014 what a consumer of this package touches (SKILL.md \xA72i)"
|
|
3397
|
+
},
|
|
3398
|
+
{
|
|
3399
|
+
name: DEPTH_1_LABEL,
|
|
3400
|
+
color: "fbc02d",
|
|
3401
|
+
description: "Depth 1 \u2014 the run orchestration that executes an Issue (SKILL.md \xA72i)"
|
|
3402
|
+
},
|
|
3403
|
+
{
|
|
3404
|
+
name: DEPTH_2_LABEL,
|
|
3405
|
+
color: "c5def5",
|
|
3406
|
+
description: "Depth 2 \u2014 what measures a run (SKILL.md \xA72i)"
|
|
3407
|
+
}
|
|
3408
|
+
];
|
|
3409
|
+
var WORKFLOW_LABELS = [
|
|
3410
|
+
{
|
|
3411
|
+
name: EPIC_LABEL,
|
|
3412
|
+
color: "5319e7",
|
|
3413
|
+
description: "Tracks a batch of child issues from one split"
|
|
3414
|
+
},
|
|
3415
|
+
{ name: IN_PROGRESS_LABEL, color: "0075ca", description: "Work is actively in progress" },
|
|
3416
|
+
{ name: PLANNED_LABEL, color: "c2e0c6", description: "kickoff posted the plan" },
|
|
3417
|
+
{
|
|
3418
|
+
name: RUN_SOLO_LABEL,
|
|
3419
|
+
color: "b60205",
|
|
3420
|
+
description: "Runs alone in a backlogrun: nothing starts beside it"
|
|
3421
|
+
},
|
|
3422
|
+
{
|
|
3423
|
+
name: RUN_LANE_LABEL,
|
|
3424
|
+
color: "0e8a16",
|
|
3425
|
+
description: "Judged safe to run beside others in a backlogrun"
|
|
3426
|
+
},
|
|
3427
|
+
{
|
|
3428
|
+
name: PRIORITY_HIGH_LABEL,
|
|
3429
|
+
color: "e99695",
|
|
3430
|
+
description: "Offered first in a backlogrun; only a person removes it"
|
|
3431
|
+
},
|
|
3432
|
+
...FILING_ROUTE_LABELS,
|
|
3433
|
+
...DEPTH_LABELS
|
|
3434
|
+
];
|
|
3435
|
+
var BUGFIX_LABEL = "bugfix";
|
|
3436
|
+
var OTHER_CHANGE_LABEL = "other-change";
|
|
3437
|
+
var IGNORE_FOR_RELEASE_LABEL = "ignore-for-release";
|
|
3438
|
+
var RELEASE_CLASSIFICATION_NAMES = [
|
|
3439
|
+
BREAKING_CHANGE_LABEL,
|
|
3440
|
+
ENHANCEMENT_LABEL,
|
|
3441
|
+
BUGFIX_LABEL,
|
|
3442
|
+
OTHER_CHANGE_LABEL,
|
|
3443
|
+
IGNORE_FOR_RELEASE_LABEL
|
|
3444
|
+
];
|
|
3445
|
+
var RELEASE_CLASSIFICATION_METADATA = {
|
|
3446
|
+
[BREAKING_CHANGE_LABEL]: { color: "d93f0b", description: "Release: a breaking change (major)" },
|
|
3447
|
+
[ENHANCEMENT_LABEL]: { color: "84b6eb", description: "Release: a new feature (minor)" },
|
|
3448
|
+
[BUGFIX_LABEL]: { color: "d73a4a", description: "Release: a bug fix (patch)" },
|
|
3449
|
+
[OTHER_CHANGE_LABEL]: { color: "c2e0c6", description: "Release: any other change (patch)" },
|
|
3450
|
+
[IGNORE_FOR_RELEASE_LABEL]: { color: "cfd3d7", description: "Release: left out of the notes" }
|
|
3451
|
+
};
|
|
3452
|
+
var RELEASE_CLASSIFICATION_LABELS = RELEASE_CLASSIFICATION_NAMES.map((name) => ({ name, ...RELEASE_CLASSIFICATION_METADATA[name] }));
|
|
3453
|
+
var REPOSITORY_LABELS = [
|
|
3454
|
+
...WORKFLOW_LABELS,
|
|
3455
|
+
...RELEASE_CLASSIFICATION_LABELS
|
|
3456
|
+
];
|
|
3457
|
+
function has_any_label(labels, wanted) {
|
|
3458
|
+
return (labels ?? []).some((label2) => wanted.has(label2.name.toLowerCase()));
|
|
3459
|
+
}
|
|
3460
|
+
function label_name_of(labels, wanted) {
|
|
3461
|
+
const target = wanted.toLowerCase();
|
|
3462
|
+
return labels.find((label2) => label2.toLowerCase() === target);
|
|
3463
|
+
}
|
|
3464
|
+
function has_label_name(labels, wanted) {
|
|
3465
|
+
return label_name_of(labels, wanted) !== void 0;
|
|
3466
|
+
}
|
|
3467
|
+
|
|
3468
|
+
// scripts/rules/lane-park.ts
|
|
3469
|
+
var NOTIFY_COMMANDS = /* @__PURE__ */ new Set(["notify"]);
|
|
3470
|
+
var CONFIRMATION_TASK_TYPE = /(?:^|\s)--task-type[=\s]+["']?confirmation\b/u;
|
|
3471
|
+
function is_confirmation_notify(command) {
|
|
3472
|
+
return shell_segments.segments_of(command).some(
|
|
3473
|
+
(segment) => shell_segments.is_josh_command(segment, NOTIFY_COMMANDS) && CONFIRMATION_TASK_TYPE.test(segment)
|
|
3474
|
+
);
|
|
3475
|
+
}
|
|
3476
|
+
var NOTIFY_INVOCATION = /josh\s+(?:notify|nf)\b/u;
|
|
3477
|
+
function mentions_confirmation_notify(text) {
|
|
3478
|
+
return NOTIFY_INVOCATION.test(text) && CONFIRMATION_TASK_TYPE.test(text);
|
|
2707
3479
|
}
|
|
2708
|
-
function
|
|
2709
|
-
|
|
2710
|
-
if (tokens[FIRST_TOKEN] !== BACKLOG_COMMAND) return false;
|
|
2711
|
-
return tokens.slice(FIRST_ARGUMENT_INDEX).includes(ONLY_FLAG);
|
|
3480
|
+
function is_parking_child(directory = process.cwd()) {
|
|
3481
|
+
return lane_child_marker.is_child_of(directory) && !lane_handoff.is_handed_off(directory);
|
|
2712
3482
|
}
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
3483
|
+
function is_unparked_stop(command, is_child = is_parking_child) {
|
|
3484
|
+
if (!is_confirmation_notify(command)) return false;
|
|
3485
|
+
return is_child();
|
|
3486
|
+
}
|
|
3487
|
+
var APPLIES_NEEDS_DECISION = new RegExp(
|
|
3488
|
+
String.raw`(?:labels\[\]=|--add-label[= ]'?)${NEEDS_DECISION_LABEL}\b`,
|
|
3489
|
+
"u"
|
|
3490
|
+
);
|
|
3491
|
+
function records_the_park(command) {
|
|
3492
|
+
return APPLIES_NEEDS_DECISION.test(command);
|
|
3493
|
+
}
|
|
3494
|
+
var LANE_PARK_REASON = '\u26D4 lane child park: this session is a dispatched lane child, and a stop that waits on a person must leave the question on the Issue before it sends this Telegram \u2014 otherwise the parent finds an OPEN Issue with `in-progress` and no question, and a person cannot tell what to answer (joshuafolkken/kit#2034 measured this twice in one run). The child is the only process that knows the question, the options and whether it stashed, so it records the park itself rather than leaving the parent to guess from a log. Before you notify and stop: 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>`. If this stop is a `needs-human-review` or `already-done` one, that label is already on the Issue and there is nothing to add. Then reissue this notify \u2014 it fires once per run and cannot repeat on the call in hand. 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".';
|
|
3495
|
+
var lane_park = {
|
|
3496
|
+
LANE_PARK_REASON,
|
|
3497
|
+
is_confirmation_notify,
|
|
3498
|
+
is_parking_child,
|
|
3499
|
+
is_unparked_stop,
|
|
3500
|
+
mentions_confirmation_notify,
|
|
3501
|
+
records_the_park
|
|
2717
3502
|
};
|
|
2718
3503
|
|
|
2719
|
-
// scripts/
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
var
|
|
2725
|
-
var
|
|
2726
|
-
var
|
|
2727
|
-
var
|
|
2728
|
-
var
|
|
2729
|
-
var
|
|
2730
|
-
var
|
|
2731
|
-
var
|
|
2732
|
-
var
|
|
2733
|
-
var
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
cuts: z5.number(),
|
|
2740
|
-
// Defaulted, so a record written before this field existed parses with a zero streak rather than
|
|
2741
|
-
// failing to read — the same backward-compatibility the optional owner fields below carry.
|
|
2742
|
-
failures: z5.number().default(0),
|
|
2743
|
-
// Defaulted for the same backward-compatibility as `failures` (joshuafolkken/kit#2240).
|
|
2744
|
-
outages: z5.number().default(0),
|
|
2745
|
-
// Optional, so a record written before the outage fold existed still parses (joshuafolkken/kit#2317).
|
|
2746
|
-
last_outage_at: z5.string().optional(),
|
|
2747
|
-
// Optional, so a record written by the previous shape still parses. Read as "no owner declared",
|
|
2748
|
-
// which is the not-provably-live answer rather than a live one.
|
|
2749
|
-
owner_pid: z5.number().optional(),
|
|
2750
|
-
owner_start: z5.string().optional(),
|
|
2751
|
-
is_handed_off: z5.boolean().optional(),
|
|
2752
|
-
done: z5.array(z5.number()).optional(),
|
|
2753
|
-
// Optional, so a record written before the retrospective existed still parses (joshuafolkken/kit#2328).
|
|
2754
|
-
retrospective: z5.boolean().optional()
|
|
2755
|
-
});
|
|
2756
|
-
function carry_path(git_directory) {
|
|
2757
|
-
return stamp_file.stamp_path(CARRY_PREFIX, git_directory);
|
|
3504
|
+
// scripts/discovery/repo-discovery.ts
|
|
3505
|
+
import { existsSync as existsSync2, readdirSync, readFileSync as readFileSync3, statSync } from "node:fs";
|
|
3506
|
+
import path4 from "node:path";
|
|
3507
|
+
|
|
3508
|
+
// scripts/discovery/repo-origin.ts
|
|
3509
|
+
var GITHUB_HOST = "github.com";
|
|
3510
|
+
var SSH_ALIAS_PATTERN = /^github(?:-\w+)*$/u;
|
|
3511
|
+
var GIT_SUFFIX = ".git";
|
|
3512
|
+
var PATH_SEPARATOR2 = "/";
|
|
3513
|
+
var USER_SEPARATOR = "@";
|
|
3514
|
+
var HOST_SEPARATOR = ":";
|
|
3515
|
+
var OWNER_INDEX = 0;
|
|
3516
|
+
var REPO_INDEX = 1;
|
|
3517
|
+
var REPO_PATH_SEGMENTS = 2;
|
|
3518
|
+
var NOT_FOUND2 = -1;
|
|
3519
|
+
var SECTION_PREFIX = "[";
|
|
3520
|
+
var ORIGIN_SECTION = /^\[remote\s+"origin"\]$/u;
|
|
3521
|
+
var URL_KEY = "url";
|
|
3522
|
+
function is_github_hostname(host) {
|
|
3523
|
+
return host.toLowerCase() === GITHUB_HOST;
|
|
2758
3524
|
}
|
|
2759
|
-
|
|
2760
|
-
const
|
|
2761
|
-
return
|
|
3525
|
+
function is_github_ssh_host(host) {
|
|
3526
|
+
const normalized = host.toLowerCase();
|
|
3527
|
+
return is_github_hostname(normalized) || SSH_ALIAS_PATTERN.test(normalized);
|
|
2762
3528
|
}
|
|
2763
|
-
function
|
|
3529
|
+
function strip_git_suffix(name) {
|
|
3530
|
+
return name.endsWith(GIT_SUFFIX) ? name.slice(0, -GIT_SUFFIX.length) : name;
|
|
3531
|
+
}
|
|
3532
|
+
function to_identity(repository_path) {
|
|
3533
|
+
const segments = repository_path.split(PATH_SEPARATOR2).filter((segment) => segment !== "");
|
|
3534
|
+
if (segments.length !== REPO_PATH_SEGMENTS) return void 0;
|
|
3535
|
+
const owner = segments[OWNER_INDEX] ?? "";
|
|
3536
|
+
const repo = strip_git_suffix(segments[REPO_INDEX] ?? "");
|
|
3537
|
+
return repo === "" ? void 0 : { owner, repo };
|
|
3538
|
+
}
|
|
3539
|
+
function parse_scp_like(url) {
|
|
3540
|
+
const user_end = url.indexOf(USER_SEPARATOR);
|
|
3541
|
+
const authority = user_end === NOT_FOUND2 ? url : url.slice(user_end + 1);
|
|
3542
|
+
const host_end = authority.indexOf(HOST_SEPARATOR);
|
|
3543
|
+
if (host_end === NOT_FOUND2) return void 0;
|
|
3544
|
+
if (!is_github_ssh_host(authority.slice(0, host_end))) return void 0;
|
|
3545
|
+
return to_identity(authority.slice(host_end + 1));
|
|
3546
|
+
}
|
|
3547
|
+
function parse_url_like(url) {
|
|
2764
3548
|
try {
|
|
2765
|
-
const parsed =
|
|
2766
|
-
return parsed.
|
|
3549
|
+
const parsed = new URL(url);
|
|
3550
|
+
return is_github_hostname(parsed.hostname) ? to_identity(parsed.pathname) : void 0;
|
|
2767
3551
|
} catch {
|
|
2768
3552
|
return void 0;
|
|
2769
3553
|
}
|
|
2770
3554
|
}
|
|
2771
|
-
function
|
|
2772
|
-
const
|
|
2773
|
-
if (
|
|
2774
|
-
return
|
|
3555
|
+
function parse_origin_url(url) {
|
|
3556
|
+
const trimmed2 = url.trim();
|
|
3557
|
+
if (trimmed2 === "") return void 0;
|
|
3558
|
+
return parse_url_like(trimmed2) ?? parse_scp_like(trimmed2);
|
|
2775
3559
|
}
|
|
2776
|
-
function
|
|
2777
|
-
|
|
2778
|
-
const carry = parse_carry(raw);
|
|
2779
|
-
if (carry === void 0) return UNREADABLE_READ3;
|
|
2780
|
-
return { kind: is_expired2(carry, now) ? "expired" : "carried", carry };
|
|
3560
|
+
function is_section_header(line) {
|
|
3561
|
+
return line.startsWith(SECTION_PREFIX);
|
|
2781
3562
|
}
|
|
2782
|
-
function
|
|
2783
|
-
|
|
3563
|
+
function origin_section_lines(lines) {
|
|
3564
|
+
const start = lines.findIndex((line) => ORIGIN_SECTION.test(line));
|
|
3565
|
+
if (start === NOT_FOUND2) return [];
|
|
3566
|
+
const rest = lines.slice(start + 1);
|
|
3567
|
+
const end = rest.findIndex((line) => is_section_header(line));
|
|
3568
|
+
return end === NOT_FOUND2 ? rest : rest.slice(0, end);
|
|
2784
3569
|
}
|
|
2785
|
-
function
|
|
2786
|
-
|
|
3570
|
+
function entry_value(line, key2) {
|
|
3571
|
+
const separator = line.indexOf("=");
|
|
3572
|
+
if (separator === NOT_FOUND2) return void 0;
|
|
3573
|
+
if (line.slice(0, separator).trim() !== key2) return void 0;
|
|
3574
|
+
return line.slice(separator + 1).trim();
|
|
2787
3575
|
}
|
|
2788
|
-
function
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
started_at: now.toISOString(),
|
|
2792
|
-
merged: NO_INCREMENT3,
|
|
2793
|
-
filed: NO_INCREMENT3,
|
|
2794
|
-
cuts: NO_INCREMENT3,
|
|
2795
|
-
failures: NO_INCREMENT3,
|
|
2796
|
-
outages: NO_INCREMENT3,
|
|
2797
|
-
owner_pid: owner.pid,
|
|
2798
|
-
owner_start: owner.start
|
|
2799
|
-
};
|
|
3576
|
+
function parse_origin_from_config(content) {
|
|
3577
|
+
const lines = content.split("\n").map((line) => line.trim());
|
|
3578
|
+
return origin_section_lines(lines).map((line) => entry_value(line, URL_KEY)).find((url) => url !== void 0);
|
|
2800
3579
|
}
|
|
2801
|
-
function
|
|
2802
|
-
|
|
2803
|
-
return stamp_file.create_stamp(target, carry) ? carry : void 0;
|
|
3580
|
+
function format_identity(identity) {
|
|
3581
|
+
return `${identity.owner}${PATH_SEPARATOR2}${identity.repo}`.toLowerCase();
|
|
2804
3582
|
}
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
3583
|
+
var repo_origin = {
|
|
3584
|
+
GITHUB_HOST,
|
|
3585
|
+
is_github_hostname,
|
|
3586
|
+
is_github_ssh_host,
|
|
3587
|
+
parse_origin_from_config,
|
|
3588
|
+
parse_origin_url,
|
|
3589
|
+
format_identity
|
|
3590
|
+
};
|
|
3591
|
+
|
|
3592
|
+
// scripts/discovery/repo-map-logic.ts
|
|
3593
|
+
var OVERRIDE_ENTRY_SEPARATOR = ",";
|
|
3594
|
+
var OVERRIDE_PAIR_SEPARATOR = "=";
|
|
3595
|
+
var OVERRIDE_PAIR_PARTS = 2;
|
|
3596
|
+
var KEY_INDEX = 0;
|
|
3597
|
+
var PATH_INDEX = 1;
|
|
3598
|
+
function is_same_owner(identity, current_owner2) {
|
|
3599
|
+
return identity.owner.toLowerCase() === current_owner2.toLowerCase();
|
|
2808
3600
|
}
|
|
2809
|
-
function
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
is_handed_off: false
|
|
2815
|
-
};
|
|
2816
|
-
stamp_file.remove_stamp(target);
|
|
2817
|
-
return stamp_file.create_stamp(target, next) ? next : void 0;
|
|
3601
|
+
function add_entry(target, origin_url, repository_path, current_owner2) {
|
|
3602
|
+
if (origin_url === void 0) return;
|
|
3603
|
+
const identity = repo_origin.parse_origin_url(origin_url);
|
|
3604
|
+
if (identity === void 0 || !is_same_owner(identity, current_owner2)) return;
|
|
3605
|
+
target.set(repo_origin.format_identity(identity), repository_path);
|
|
2818
3606
|
}
|
|
2819
|
-
function
|
|
2820
|
-
|
|
3607
|
+
function parse_override_entry(entry) {
|
|
3608
|
+
const parts = entry.split(OVERRIDE_PAIR_SEPARATOR).map((part) => part.trim());
|
|
3609
|
+
if (parts.length !== OVERRIDE_PAIR_PARTS) return void 0;
|
|
3610
|
+
const key2 = parts[KEY_INDEX] ?? "";
|
|
3611
|
+
const repository_path = parts[PATH_INDEX] ?? "";
|
|
3612
|
+
if (repository_path === "") return void 0;
|
|
3613
|
+
return { path: repository_path, origin_url: `https://${repo_origin.GITHUB_HOST}/${key2}` };
|
|
2821
3614
|
}
|
|
2822
|
-
function
|
|
2823
|
-
|
|
3615
|
+
function parse_overrides(raw) {
|
|
3616
|
+
if (raw === void 0) return [];
|
|
3617
|
+
return raw.split(OVERRIDE_ENTRY_SEPARATOR).map((entry) => parse_override_entry(entry)).filter((entry) => entry !== void 0);
|
|
2824
3618
|
}
|
|
2825
|
-
function
|
|
2826
|
-
|
|
3619
|
+
function build_repository_map(discovered, current_owner2, override_value2) {
|
|
3620
|
+
const result = /* @__PURE__ */ new Map();
|
|
3621
|
+
for (const entry of discovered) add_entry(result, entry.origin_url, entry.path, current_owner2);
|
|
3622
|
+
for (const entry of parse_overrides(override_value2)) {
|
|
3623
|
+
add_entry(result, entry.origin_url, entry.path, current_owner2);
|
|
3624
|
+
}
|
|
3625
|
+
return result;
|
|
2827
3626
|
}
|
|
2828
|
-
|
|
2829
|
-
|
|
3627
|
+
var repo_map_logic = {
|
|
3628
|
+
is_same_owner,
|
|
3629
|
+
build_repository_map
|
|
3630
|
+
};
|
|
3631
|
+
|
|
3632
|
+
// scripts/discovery/repo-discovery.ts
|
|
3633
|
+
var GIT_DIRECTORY = ".git";
|
|
3634
|
+
var GIT_CONFIG = "config";
|
|
3635
|
+
var GITDIR_PREFIX = "gitdir:";
|
|
3636
|
+
var COMMON_DIRECTORY_FILE = "commondir";
|
|
3637
|
+
var OVERRIDE_ENV_KEY = "JOSH_REPO_PATHS";
|
|
3638
|
+
function resolve_common_directory(git_directory) {
|
|
3639
|
+
const pointer = path4.join(git_directory, COMMON_DIRECTORY_FILE);
|
|
3640
|
+
if (!existsSync2(pointer)) return git_directory;
|
|
3641
|
+
try {
|
|
3642
|
+
return path4.resolve(git_directory, readFileSync3(pointer, "utf8").trim());
|
|
3643
|
+
} catch {
|
|
3644
|
+
return git_directory;
|
|
3645
|
+
}
|
|
2830
3646
|
}
|
|
2831
|
-
function
|
|
2832
|
-
|
|
2833
|
-
if (
|
|
2834
|
-
|
|
2835
|
-
return request.is_adoption ? "resume" : "standing";
|
|
3647
|
+
function follow_git_file(repository_path, git_file) {
|
|
3648
|
+
const pointer = readFileSync3(git_file, "utf8").trim();
|
|
3649
|
+
if (!pointer.startsWith(GITDIR_PREFIX)) return void 0;
|
|
3650
|
+
return path4.resolve(repository_path, pointer.slice(GITDIR_PREFIX.length).trim());
|
|
2836
3651
|
}
|
|
2837
|
-
function
|
|
2838
|
-
|
|
3652
|
+
function resolve_git_directory(repository_path) {
|
|
3653
|
+
const candidate = path4.join(repository_path, GIT_DIRECTORY);
|
|
3654
|
+
if (!existsSync2(candidate)) return void 0;
|
|
3655
|
+
try {
|
|
3656
|
+
if (statSync(candidate).isDirectory()) return candidate;
|
|
3657
|
+
const linked = follow_git_file(repository_path, candidate);
|
|
3658
|
+
return linked === void 0 ? void 0 : resolve_common_directory(linked);
|
|
3659
|
+
} catch {
|
|
3660
|
+
return void 0;
|
|
3661
|
+
}
|
|
2839
3662
|
}
|
|
2840
|
-
function
|
|
2841
|
-
|
|
3663
|
+
function read_origin_url(repository_path) {
|
|
3664
|
+
const git_directory = resolve_git_directory(repository_path);
|
|
3665
|
+
if (git_directory === void 0) return void 0;
|
|
3666
|
+
try {
|
|
3667
|
+
return repo_origin.parse_origin_from_config(
|
|
3668
|
+
readFileSync3(path4.join(git_directory, GIT_CONFIG), "utf8")
|
|
3669
|
+
);
|
|
3670
|
+
} catch {
|
|
3671
|
+
return void 0;
|
|
3672
|
+
}
|
|
2842
3673
|
}
|
|
2843
|
-
function
|
|
2844
|
-
|
|
3674
|
+
function sibling_directories(parent) {
|
|
3675
|
+
try {
|
|
3676
|
+
return readdirSync(parent, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => path4.join(parent, entry.name)).toSorted((left, right) => left.localeCompare(right));
|
|
3677
|
+
} catch {
|
|
3678
|
+
return [];
|
|
3679
|
+
}
|
|
3680
|
+
}
|
|
3681
|
+
function scan_siblings(parent) {
|
|
3682
|
+
return sibling_directories(parent).map((repository_path) => ({
|
|
3683
|
+
path: repository_path,
|
|
3684
|
+
origin_url: read_origin_url(repository_path)
|
|
3685
|
+
}));
|
|
3686
|
+
}
|
|
3687
|
+
function resolve_current_owner(repository_path) {
|
|
3688
|
+
const origin_url = read_origin_url(repository_path);
|
|
3689
|
+
if (origin_url === void 0) return void 0;
|
|
3690
|
+
return repo_origin.parse_origin_url(origin_url)?.owner;
|
|
2845
3691
|
}
|
|
2846
|
-
function
|
|
2847
|
-
|
|
2848
|
-
|
|
3692
|
+
function main_worktree(repository_path) {
|
|
3693
|
+
const git_directory = resolve_git_directory(repository_path);
|
|
3694
|
+
if (git_directory === void 0) return repository_path;
|
|
3695
|
+
if (path4.basename(git_directory) !== GIT_DIRECTORY) return repository_path;
|
|
3696
|
+
return path4.dirname(git_directory);
|
|
2849
3697
|
}
|
|
2850
|
-
function
|
|
2851
|
-
|
|
2852
|
-
const
|
|
2853
|
-
if (
|
|
2854
|
-
|
|
2855
|
-
|
|
3698
|
+
function discover_repositories(repository_path, environment2 = process.env) {
|
|
3699
|
+
const main2 = main_worktree(repository_path);
|
|
3700
|
+
const current_owner2 = resolve_current_owner(main2);
|
|
3701
|
+
if (current_owner2 === void 0) return /* @__PURE__ */ new Map();
|
|
3702
|
+
return repo_map_logic.build_repository_map(
|
|
3703
|
+
scan_siblings(path4.dirname(main2)),
|
|
3704
|
+
current_owner2,
|
|
3705
|
+
environment2[OVERRIDE_ENV_KEY]
|
|
3706
|
+
);
|
|
2856
3707
|
}
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
3708
|
+
var repo_discovery = {
|
|
3709
|
+
OVERRIDE_ENV_KEY,
|
|
3710
|
+
main_worktree,
|
|
3711
|
+
read_origin_url,
|
|
3712
|
+
resolve_current_owner,
|
|
3713
|
+
scan_siblings,
|
|
3714
|
+
discover_repositories
|
|
3715
|
+
};
|
|
3716
|
+
|
|
3717
|
+
// scripts/discovery/repo-party.ts
|
|
3718
|
+
var FIRST_PARTY = "first-party";
|
|
3719
|
+
var THIRD_PARTY = "third-party";
|
|
3720
|
+
var UNKNOWN = "unknown";
|
|
3721
|
+
function classify4(session_owner, target) {
|
|
3722
|
+
if (session_owner === void 0 || target === void 0) return UNKNOWN;
|
|
3723
|
+
return session_owner.toLowerCase() === target.toLowerCase() ? FIRST_PARTY : THIRD_PARTY;
|
|
2860
3724
|
}
|
|
2861
|
-
function
|
|
2862
|
-
return
|
|
3725
|
+
function target_owner(owner_repo) {
|
|
3726
|
+
return repo_origin.parse_origin_url(`https://${repo_origin.GITHUB_HOST}/${owner_repo}`)?.owner;
|
|
2863
3727
|
}
|
|
2864
|
-
function
|
|
2865
|
-
return
|
|
3728
|
+
function current_owner(repository_path = process.cwd()) {
|
|
3729
|
+
return repo_discovery.resolve_current_owner(repository_path);
|
|
2866
3730
|
}
|
|
2867
|
-
|
|
2868
|
-
|
|
3731
|
+
var repo_party = { FIRST_PARTY, THIRD_PARTY, UNKNOWN, classify: classify4, current_owner, target_owner };
|
|
3732
|
+
|
|
3733
|
+
// scripts/lane/lane-reap.ts
|
|
3734
|
+
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
3735
|
+
var PGREP_COMMAND = "pgrep";
|
|
3736
|
+
var MATCH_FULL_COMMAND_LINE = "-f";
|
|
3737
|
+
var CHILDREN_OF_FLAG = "-P";
|
|
3738
|
+
var PS_COMMAND2 = "/bin/ps";
|
|
3739
|
+
var PARENT_FORMAT = ["-o", "ppid=", "-p"];
|
|
3740
|
+
var TERMINATE_SIGNAL = "SIGTERM";
|
|
3741
|
+
var PROBE_TIMEOUT_MS3 = 2e3;
|
|
3742
|
+
var LOWEST_CHILD_PID = 2;
|
|
3743
|
+
function parse_pids(printed) {
|
|
3744
|
+
return printed.split("\n").map((line) => Number(line.trim())).filter((pid) => Number.isSafeInteger(pid) && pid >= LOWEST_CHILD_PID);
|
|
2869
3745
|
}
|
|
2870
|
-
function
|
|
2871
|
-
|
|
3746
|
+
function run_probe(command, args) {
|
|
3747
|
+
try {
|
|
3748
|
+
return execFileSync3(command, [...args], {
|
|
3749
|
+
encoding: "utf8",
|
|
3750
|
+
timeout: PROBE_TIMEOUT_MS3,
|
|
3751
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
3752
|
+
});
|
|
3753
|
+
} catch {
|
|
3754
|
+
return "";
|
|
3755
|
+
}
|
|
2872
3756
|
}
|
|
2873
|
-
function
|
|
2874
|
-
return
|
|
3757
|
+
function parent_of(pid) {
|
|
3758
|
+
return parse_pids(run_probe(PS_COMMAND2, [...PARENT_FORMAT, String(pid)]))[0];
|
|
2875
3759
|
}
|
|
2876
|
-
function
|
|
2877
|
-
|
|
2878
|
-
|
|
3760
|
+
function terminate(pid) {
|
|
3761
|
+
try {
|
|
3762
|
+
process.kill(pid, TERMINATE_SIGNAL);
|
|
3763
|
+
return true;
|
|
3764
|
+
} catch {
|
|
3765
|
+
return false;
|
|
2879
3766
|
}
|
|
2880
|
-
return `A live run owns this budget \u2014 ${describe_carry(carry)}, owner pid ${String(carry.owner_pid)} still running. Nothing was counted; only its owner advances the budget.`;
|
|
2881
3767
|
}
|
|
2882
|
-
|
|
2883
|
-
|
|
3768
|
+
var SYSTEM_PROBES = {
|
|
3769
|
+
matching: (pattern) => parse_pids(run_probe(PGREP_COMMAND, [MATCH_FULL_COMMAND_LINE, pattern])),
|
|
3770
|
+
children_of: (pid) => parse_pids(run_probe(PGREP_COMMAND, [CHILDREN_OF_FLAG, String(pid)])),
|
|
3771
|
+
parent_of,
|
|
3772
|
+
terminate
|
|
3773
|
+
};
|
|
3774
|
+
function ancestry_of(pid, probes) {
|
|
3775
|
+
const ancestry = /* @__PURE__ */ new Set([pid]);
|
|
3776
|
+
let current = probes.parent_of(pid);
|
|
3777
|
+
while (current !== void 0 && !ancestry.has(current)) {
|
|
3778
|
+
ancestry.add(current);
|
|
3779
|
+
current = probes.parent_of(current);
|
|
3780
|
+
}
|
|
3781
|
+
return ancestry;
|
|
2884
3782
|
}
|
|
2885
|
-
function
|
|
2886
|
-
return
|
|
3783
|
+
function own_ancestry(probes = SYSTEM_PROBES) {
|
|
3784
|
+
return ancestry_of(process.pid, probes);
|
|
2887
3785
|
}
|
|
2888
|
-
function
|
|
2889
|
-
|
|
3786
|
+
function tree_of(roots, probes) {
|
|
3787
|
+
const tree = [];
|
|
3788
|
+
const pending = [...roots];
|
|
3789
|
+
let next = pending.shift();
|
|
3790
|
+
while (next !== void 0) {
|
|
3791
|
+
if (!tree.includes(next)) {
|
|
3792
|
+
tree.push(next);
|
|
3793
|
+
pending.push(...probes.children_of(next));
|
|
3794
|
+
}
|
|
3795
|
+
next = pending.shift();
|
|
3796
|
+
}
|
|
3797
|
+
return tree;
|
|
2890
3798
|
}
|
|
2891
|
-
function
|
|
2892
|
-
|
|
3799
|
+
function reap_child(issue, probes = SYSTEM_PROBES) {
|
|
3800
|
+
const own2 = own_ancestry(probes);
|
|
3801
|
+
const pattern = lane_child_invocation.process_pattern(issue);
|
|
3802
|
+
const roots = probes.matching(pattern).filter((pid) => !own2.has(pid));
|
|
3803
|
+
const doomed = tree_of(roots, probes).filter((pid) => !own2.has(pid));
|
|
3804
|
+
return doomed.filter((pid) => probes.terminate(pid));
|
|
2893
3805
|
}
|
|
2894
|
-
var
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
MAX_CUTS,
|
|
2899
|
-
NO_OWNER,
|
|
2900
|
-
RESUME_COMMAND,
|
|
2901
|
-
adopt_carry,
|
|
2902
|
-
apply_change: run_carry_change.apply_change,
|
|
2903
|
-
begin_carry,
|
|
2904
|
-
busy_message: busy_message2,
|
|
2905
|
-
carry_path,
|
|
2906
|
-
classify: classify4,
|
|
2907
|
-
classify_claim,
|
|
2908
|
-
count_refused_message,
|
|
2909
|
-
is_at_cut_cap,
|
|
2910
|
-
describe_carry,
|
|
2911
|
-
end_carry,
|
|
2912
|
-
expired_message,
|
|
2913
|
-
mismatch_message,
|
|
2914
|
-
fresh_carry,
|
|
2915
|
-
is_count_refused,
|
|
2916
|
-
is_expired: is_expired2,
|
|
2917
|
-
is_foreign_live_owner,
|
|
2918
|
-
is_owner_live,
|
|
2919
|
-
lost_message,
|
|
2920
|
-
nothing_to_resume_message,
|
|
2921
|
-
owner_of,
|
|
2922
|
-
parse_carry,
|
|
2923
|
-
read_carry,
|
|
2924
|
-
remaining_of,
|
|
2925
|
-
replace_carry,
|
|
2926
|
-
repository_directory,
|
|
2927
|
-
retrospective_done_of,
|
|
2928
|
-
standing_message,
|
|
2929
|
-
unknown_message: unknown_message3,
|
|
2930
|
-
unreadable_message: unreadable_message3
|
|
3806
|
+
var lane_reap = {
|
|
3807
|
+
own_ancestry,
|
|
3808
|
+
parse_pids,
|
|
3809
|
+
reap_child
|
|
2931
3810
|
};
|
|
2932
3811
|
|
|
2933
3812
|
// scripts/lane/lane-registry.ts
|
|
2934
|
-
import { existsSync as
|
|
2935
|
-
import
|
|
3813
|
+
import { existsSync as existsSync3 } from "node:fs";
|
|
3814
|
+
import path5 from "node:path";
|
|
2936
3815
|
|
|
2937
3816
|
// scripts/git/git-ls-remote.ts
|
|
2938
3817
|
var LS_REMOTE_COMMAND = "ls-remote";
|
|
@@ -2944,58 +3823,23 @@ function ls_remote_branch_arguments(branch_name) {
|
|
|
2944
3823
|
}
|
|
2945
3824
|
|
|
2946
3825
|
// scripts/git/repository-lock.ts
|
|
2947
|
-
import { randomUUID as
|
|
3826
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
2948
3827
|
import { linkSync, renameSync, rmSync as rmSync2 } from "node:fs";
|
|
2949
|
-
import { setTimeout as
|
|
3828
|
+
import { setTimeout as sleep2 } from "node:timers/promises";
|
|
2950
3829
|
|
|
2951
|
-
// scripts/
|
|
2952
|
-
import {
|
|
2953
|
-
var
|
|
2954
|
-
var COMMON_GIT_DIRECTORY = 1;
|
|
2955
|
-
var PROBE_TIMEOUT_MS3 = 2e3;
|
|
2956
|
-
function read_directories(cwd) {
|
|
2957
|
-
const git = git_utilities.get_git_command_for_spawn();
|
|
2958
|
-
const output = execFileSync4(git, [...git_command.GIT_DIRECTORY_ARGUMENTS], {
|
|
2959
|
-
cwd,
|
|
2960
|
-
encoding: "utf8",
|
|
2961
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
2962
|
-
timeout: PROBE_TIMEOUT_MS3
|
|
2963
|
-
});
|
|
2964
|
-
return output.trim().split("\n");
|
|
2965
|
-
}
|
|
2966
|
-
function select_linked(directories) {
|
|
2967
|
-
const own = directories[OWN_GIT_DIRECTORY];
|
|
2968
|
-
const common = directories[COMMON_GIT_DIRECTORY];
|
|
2969
|
-
return own !== void 0 && common !== void 0 && own !== common ? common : void 0;
|
|
2970
|
-
}
|
|
2971
|
-
function resolve2(cwd) {
|
|
2972
|
-
try {
|
|
2973
|
-
return select_linked(read_directories(cwd));
|
|
2974
|
-
} catch {
|
|
2975
|
-
return void 0;
|
|
2976
|
-
}
|
|
2977
|
-
}
|
|
2978
|
-
function repository(cwd) {
|
|
2979
|
-
try {
|
|
2980
|
-
return read_directories(cwd)[COMMON_GIT_DIRECTORY];
|
|
2981
|
-
} catch {
|
|
2982
|
-
return void 0;
|
|
2983
|
-
}
|
|
2984
|
-
}
|
|
2985
|
-
var git_common_directory = { repository, resolve: resolve2, select_linked };
|
|
3830
|
+
// scripts/josh/process-owner.ts
|
|
3831
|
+
import { z as z9 } from "zod";
|
|
3832
|
+
var process_owner_schema = z9.object({ pid: z9.number(), process_start: z9.string().optional() });
|
|
2986
3833
|
|
|
2987
3834
|
// scripts/git/repository-lock.ts
|
|
2988
3835
|
var POLL_INTERVAL_MS = 200;
|
|
2989
|
-
function lock_path(prefix, cwd
|
|
2990
|
-
return stamp_file.stamp_path(prefix, git_common_directory.repository(cwd) ?? cwd);
|
|
3836
|
+
function lock_path(prefix, cwd) {
|
|
3837
|
+
return stamp_file.stamp_path(prefix, git_common_directory.repository(cwd) ?? cwd ?? process.cwd());
|
|
2991
3838
|
}
|
|
2992
3839
|
function parse_owner(raw) {
|
|
2993
3840
|
if (raw === void 0) return void 0;
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
} catch {
|
|
2997
|
-
return void 0;
|
|
2998
|
-
}
|
|
3841
|
+
const parsed = process_owner_schema.safeParse(json_value.parse_or_undefined(raw));
|
|
3842
|
+
return parsed.success ? parsed.data : void 0;
|
|
2999
3843
|
}
|
|
3000
3844
|
function read_owner(target) {
|
|
3001
3845
|
return parse_owner(stamp_file.read_stamp_text(target));
|
|
@@ -3015,7 +3859,7 @@ function stale_record(target, is_gone2) {
|
|
|
3015
3859
|
return owner !== void 0 && is_gone2(owner) ? raw : void 0;
|
|
3016
3860
|
}
|
|
3017
3861
|
function move_aside(target) {
|
|
3018
|
-
const aside = `${target}.${String(process.pid)}.${
|
|
3862
|
+
const aside = `${target}.${String(process.pid)}.${randomUUID3()}`;
|
|
3019
3863
|
try {
|
|
3020
3864
|
renameSync(target, aside);
|
|
3021
3865
|
return aside;
|
|
@@ -3045,7 +3889,7 @@ async function acquire(target, max_wait_ms) {
|
|
|
3045
3889
|
const deadline = Date.now() + max_wait_ms;
|
|
3046
3890
|
while (!claim(target)) {
|
|
3047
3891
|
if (Date.now() >= deadline) return false;
|
|
3048
|
-
await
|
|
3892
|
+
await sleep2(POLL_INTERVAL_MS);
|
|
3049
3893
|
}
|
|
3050
3894
|
return true;
|
|
3051
3895
|
}
|
|
@@ -3125,13 +3969,10 @@ function strip_export(line) {
|
|
|
3125
3969
|
const trimmed2 = line.trimStart();
|
|
3126
3970
|
return trimmed2.startsWith(EXPORT_PREFIX) ? trimmed2.slice(EXPORT_PREFIX.length).trimStart() : trimmed2;
|
|
3127
3971
|
}
|
|
3128
|
-
function is_key_line(line,
|
|
3972
|
+
function is_key_line(line, key2) {
|
|
3129
3973
|
const body = strip_export(line);
|
|
3130
|
-
if (!body.startsWith(
|
|
3131
|
-
return body.slice(
|
|
3132
|
-
}
|
|
3133
|
-
function is_seed_line(line) {
|
|
3134
|
-
return is_key_line(line, PORT_SEED_KEY);
|
|
3974
|
+
if (!body.startsWith(key2)) return false;
|
|
3975
|
+
return body.slice(key2.length).trimStart().startsWith(ASSIGNMENT_SEPARATOR);
|
|
3135
3976
|
}
|
|
3136
3977
|
function is_seat_line(line) {
|
|
3137
3978
|
return is_key_line(line, LANE_SEAT_KEY);
|
|
@@ -3154,8 +3995,8 @@ function unquote(raw) {
|
|
|
3154
3995
|
function assignment_value(line) {
|
|
3155
3996
|
return unquote(line.slice(line.indexOf(ASSIGNMENT_SEPARATOR) + FIRST_CHARACTER_END).trim());
|
|
3156
3997
|
}
|
|
3157
|
-
function read_assignment(content,
|
|
3158
|
-
const line = split_lines(content).findLast((entry) => is_key_line(entry,
|
|
3998
|
+
function read_assignment(content, key2) {
|
|
3999
|
+
const line = split_lines(content).findLast((entry) => is_key_line(entry, key2));
|
|
3159
4000
|
return line === void 0 ? void 0 : assignment_value(line);
|
|
3160
4001
|
}
|
|
3161
4002
|
function read_root_seed(content) {
|
|
@@ -3188,17 +4029,17 @@ function read_lane_profile(content) {
|
|
|
3188
4029
|
effort: read_assignment(content, LANE_EFFORT_KEY)
|
|
3189
4030
|
});
|
|
3190
4031
|
}
|
|
3191
|
-
function replace_assignment(lines, keep, assignment,
|
|
4032
|
+
function replace_assignment(lines, keep, assignment, key2) {
|
|
3192
4033
|
return lines.flatMap((entry, index) => {
|
|
3193
4034
|
if (index === keep) return [assignment];
|
|
3194
|
-
return is_key_line(entry,
|
|
4035
|
+
return is_key_line(entry, key2) ? [] : [entry];
|
|
3195
4036
|
});
|
|
3196
4037
|
}
|
|
3197
|
-
function upsert_assignment(content,
|
|
3198
|
-
const assignment = `${
|
|
4038
|
+
function upsert_assignment(content, key2, value) {
|
|
4039
|
+
const assignment = `${key2}${ASSIGNMENT_SEPARATOR}${value}`;
|
|
3199
4040
|
const lines = split_lines(content);
|
|
3200
|
-
const last = lines.findLastIndex((entry) => is_key_line(entry,
|
|
3201
|
-
const body = last === -1 ? [...lines, assignment] : replace_assignment(lines, last, assignment,
|
|
4041
|
+
const last = lines.findLastIndex((entry) => is_key_line(entry, key2));
|
|
4042
|
+
const body = last === -1 ? [...lines, assignment] : replace_assignment(lines, last, assignment, key2);
|
|
3202
4043
|
return `${body.join("\n")}
|
|
3203
4044
|
`;
|
|
3204
4045
|
}
|
|
@@ -3214,12 +4055,7 @@ function with_lane_output(content, output, profile) {
|
|
|
3214
4055
|
return upsert_assignment(with_model, LANE_EFFORT_KEY, profile.effort);
|
|
3215
4056
|
}
|
|
3216
4057
|
var lane_environment = {
|
|
3217
|
-
LANE_OUTPUT_KEY,
|
|
3218
|
-
LANE_PROVIDER_KEY,
|
|
3219
|
-
LANE_ROLE_KEY,
|
|
3220
|
-
is_output_line,
|
|
3221
4058
|
is_seat_line,
|
|
3222
|
-
is_seed_line,
|
|
3223
4059
|
lane_file_content,
|
|
3224
4060
|
read_lane_output,
|
|
3225
4061
|
read_lane_profile,
|
|
@@ -3253,7 +4089,7 @@ function held_seat(content) {
|
|
|
3253
4089
|
return seat_from_content(content) ?? EMPTY_SEAT;
|
|
3254
4090
|
}
|
|
3255
4091
|
function read_environment(directory) {
|
|
3256
|
-
return file_reader.read_if_readable(
|
|
4092
|
+
return file_reader.read_if_readable(path5.join(directory, ENV_FILE_NAME));
|
|
3257
4093
|
}
|
|
3258
4094
|
function branch_issue(branch2) {
|
|
3259
4095
|
if (!branch2?.endsWith(lane_paths.LANE_BRANCH_SUFFIX)) return void 0;
|
|
@@ -3261,7 +4097,7 @@ function branch_issue(branch2) {
|
|
|
3261
4097
|
return ISSUE_PATTERN.test(issue) ? issue : void 0;
|
|
3262
4098
|
}
|
|
3263
4099
|
function is_gone(directory) {
|
|
3264
|
-
return !
|
|
4100
|
+
return !existsSync3(directory);
|
|
3265
4101
|
}
|
|
3266
4102
|
function build_lane(issue, branch2, directory, is_stranded) {
|
|
3267
4103
|
const content = is_stranded ? void 0 : read_environment(directory);
|
|
@@ -3308,6 +4144,10 @@ async function list_lanes() {
|
|
|
3308
4144
|
const lanes = blocks.map((block) => parse_block(block, root)).filter(is_lane);
|
|
3309
4145
|
return lanes.toSorted((left, right) => Number(left.issue) - Number(right.issue));
|
|
3310
4146
|
}
|
|
4147
|
+
async function has_lanes_in_flight() {
|
|
4148
|
+
const lanes = await list_lanes();
|
|
4149
|
+
return lanes.some((lane) => !lane.is_stranded);
|
|
4150
|
+
}
|
|
3311
4151
|
function used_seats(lanes) {
|
|
3312
4152
|
return lanes.map((lane) => lane.seat).filter((seat) => seat !== void 0);
|
|
3313
4153
|
}
|
|
@@ -3323,6 +4163,7 @@ async function find_open_lane(issue) {
|
|
|
3323
4163
|
var lane_registry = {
|
|
3324
4164
|
find_lane,
|
|
3325
4165
|
find_open_lane,
|
|
4166
|
+
has_lanes_in_flight,
|
|
3326
4167
|
list_lanes,
|
|
3327
4168
|
main_repository_root,
|
|
3328
4169
|
parse_block,
|
|
@@ -3331,171 +4172,6 @@ var lane_registry = {
|
|
|
3331
4172
|
used_seats
|
|
3332
4173
|
};
|
|
3333
4174
|
|
|
3334
|
-
// scripts/run/run-progress-clock.ts
|
|
3335
|
-
import { execaSync } from "execa";
|
|
3336
|
-
import { z as z6 } from "zod";
|
|
3337
|
-
var PROGRESS_PREFIX = "josh-run-progress-";
|
|
3338
|
-
var LIFE_PREFIX = "josh-run-progress-life-";
|
|
3339
|
-
var LOG_SUFFIX = ".log";
|
|
3340
|
-
var LOG_KEEP = 12;
|
|
3341
|
-
var MS_PER_MINUTE2 = 6e4;
|
|
3342
|
-
var LOG_STALE_MINUTES = 90;
|
|
3343
|
-
var LOG_STALE_MS = LOG_STALE_MINUTES * MS_PER_MINUTE2;
|
|
3344
|
-
var BLOCK_SEPARATOR2 = "\n\n";
|
|
3345
|
-
var GIT_TIMEOUT_MS = 5e3;
|
|
3346
|
-
var GIT_DIRECTORY_ARGUMENTS2 = ["rev-parse", "--absolute-git-dir"];
|
|
3347
|
-
var report_stamp_schema = z6.object({ reported_at: z6.string(), line: z6.string().optional() });
|
|
3348
|
-
function parse_stamp(raw) {
|
|
3349
|
-
const parsed = report_stamp_schema.safeParse(JSON.parse(raw));
|
|
3350
|
-
if (!parsed.success) return void 0;
|
|
3351
|
-
const reported_at = Date.parse(parsed.data.reported_at);
|
|
3352
|
-
return Number.isNaN(reported_at) ? void 0 : reported_at;
|
|
3353
|
-
}
|
|
3354
|
-
function read_last_line(target) {
|
|
3355
|
-
const raw = stamp_file.read_stamp_text(target);
|
|
3356
|
-
if (raw === void 0) return void 0;
|
|
3357
|
-
try {
|
|
3358
|
-
return report_stamp_schema.safeParse(JSON.parse(raw)).data?.line;
|
|
3359
|
-
} catch {
|
|
3360
|
-
return void 0;
|
|
3361
|
-
}
|
|
3362
|
-
}
|
|
3363
|
-
function read_last_report(target) {
|
|
3364
|
-
const raw = stamp_file.read_stamp_text(target);
|
|
3365
|
-
if (raw === void 0) return void 0;
|
|
3366
|
-
try {
|
|
3367
|
-
return parse_stamp(raw);
|
|
3368
|
-
} catch {
|
|
3369
|
-
return void 0;
|
|
3370
|
-
}
|
|
3371
|
-
}
|
|
3372
|
-
function log_path_of(target) {
|
|
3373
|
-
return `${target}${LOG_SUFFIX}`;
|
|
3374
|
-
}
|
|
3375
|
-
function is_log_stale(target, now_ms) {
|
|
3376
|
-
const previous_ms = read_last_report(target);
|
|
3377
|
-
return previous_ms === void 0 || now_ms - previous_ms > LOG_STALE_MS;
|
|
3378
|
-
}
|
|
3379
|
-
function recent_blocks(log_target, is_fresh) {
|
|
3380
|
-
if (is_fresh) return [];
|
|
3381
|
-
const raw = stamp_file.read_stamp_text(log_target);
|
|
3382
|
-
if (raw === void 0) return [];
|
|
3383
|
-
return raw.split(BLOCK_SEPARATOR2).map((block) => block.trimEnd()).filter((block) => block.length > 0);
|
|
3384
|
-
}
|
|
3385
|
-
function append_line(log_target, reported_at, line, is_fresh) {
|
|
3386
|
-
const block = `${reported_at}
|
|
3387
|
-
${line}`;
|
|
3388
|
-
const blocks = [...recent_blocks(log_target, is_fresh), block].slice(-LOG_KEEP);
|
|
3389
|
-
stamp_file.write_text_stamp(log_target, `${blocks.join(BLOCK_SEPARATOR2)}
|
|
3390
|
-
`);
|
|
3391
|
-
}
|
|
3392
|
-
function mark(target, now_ms, line) {
|
|
3393
|
-
const reported_at = new Date(now_ms).toISOString();
|
|
3394
|
-
const kept = line ?? read_last_line(target);
|
|
3395
|
-
if (line !== void 0) {
|
|
3396
|
-
append_line(log_path_of(target), reported_at, line, is_log_stale(target, now_ms));
|
|
3397
|
-
}
|
|
3398
|
-
stamp_file.write_stamp(target, kept === void 0 ? { reported_at } : { reported_at, line: kept });
|
|
3399
|
-
}
|
|
3400
|
-
function stamp_target_of(git_directory) {
|
|
3401
|
-
return stamp_file.stamp_path(PROGRESS_PREFIX, git_directory);
|
|
3402
|
-
}
|
|
3403
|
-
function life_target_of(git_directory) {
|
|
3404
|
-
return stamp_file.stamp_path(LIFE_PREFIX, git_directory);
|
|
3405
|
-
}
|
|
3406
|
-
var life_schema = z6.object({ alive: z6.literal(true), pinged_at: z6.string().optional() });
|
|
3407
|
-
function begin_life(target) {
|
|
3408
|
-
stamp_file.write_stamp(target, { alive: true, pinged_at: (/* @__PURE__ */ new Date()).toISOString() });
|
|
3409
|
-
}
|
|
3410
|
-
function ping_life(target) {
|
|
3411
|
-
begin_life(target);
|
|
3412
|
-
}
|
|
3413
|
-
function parse_pinged_at(raw) {
|
|
3414
|
-
const parsed = life_schema.safeParse(JSON.parse(raw));
|
|
3415
|
-
if (!parsed.success || parsed.data.pinged_at === void 0) return void 0;
|
|
3416
|
-
const pinged_ms = Date.parse(parsed.data.pinged_at);
|
|
3417
|
-
return Number.isNaN(pinged_ms) ? void 0 : pinged_ms;
|
|
3418
|
-
}
|
|
3419
|
-
function is_life_fresh(target, threshold_ms) {
|
|
3420
|
-
const raw = stamp_file.read_stamp_text(target);
|
|
3421
|
-
if (raw === void 0) return false;
|
|
3422
|
-
try {
|
|
3423
|
-
const pinged_ms = parse_pinged_at(raw);
|
|
3424
|
-
return pinged_ms !== void 0 && Date.now() - pinged_ms < threshold_ms;
|
|
3425
|
-
} catch {
|
|
3426
|
-
return false;
|
|
3427
|
-
}
|
|
3428
|
-
}
|
|
3429
|
-
function is_life_ended(target) {
|
|
3430
|
-
return stamp_file.read_stamp_text(target) === void 0;
|
|
3431
|
-
}
|
|
3432
|
-
function end_life(target) {
|
|
3433
|
-
stamp_file.remove_stamp(target);
|
|
3434
|
-
}
|
|
3435
|
-
function git_directory_sync() {
|
|
3436
|
-
const git_binary = git_utilities.get_git_command_for_spawn();
|
|
3437
|
-
const result = execaSync(git_binary, GIT_DIRECTORY_ARGUMENTS2, {
|
|
3438
|
-
reject: false,
|
|
3439
|
-
timeout: GIT_TIMEOUT_MS
|
|
3440
|
-
});
|
|
3441
|
-
if (result.exitCode !== 0) return void 0;
|
|
3442
|
-
const output = result.stdout.trim();
|
|
3443
|
-
return output === "" ? void 0 : output;
|
|
3444
|
-
}
|
|
3445
|
-
function stamp_target_sync() {
|
|
3446
|
-
const directory = git_directory_sync();
|
|
3447
|
-
return directory === void 0 ? void 0 : stamp_target_of(directory);
|
|
3448
|
-
}
|
|
3449
|
-
function read_last_report_sync() {
|
|
3450
|
-
const target = stamp_target_sync();
|
|
3451
|
-
return target === void 0 ? void 0 : read_last_report(target);
|
|
3452
|
-
}
|
|
3453
|
-
var run_progress_clock = {
|
|
3454
|
-
LIFE_PREFIX,
|
|
3455
|
-
LOG_KEEP,
|
|
3456
|
-
LOG_STALE_MS,
|
|
3457
|
-
PROGRESS_PREFIX,
|
|
3458
|
-
append_line,
|
|
3459
|
-
begin_life,
|
|
3460
|
-
end_life,
|
|
3461
|
-
is_life_ended,
|
|
3462
|
-
is_life_fresh,
|
|
3463
|
-
life_target_of,
|
|
3464
|
-
log_path_of,
|
|
3465
|
-
mark,
|
|
3466
|
-
parse_stamp,
|
|
3467
|
-
ping_life,
|
|
3468
|
-
read_last_line,
|
|
3469
|
-
read_last_report,
|
|
3470
|
-
read_last_report_sync,
|
|
3471
|
-
stamp_target_of,
|
|
3472
|
-
stamp_target_sync
|
|
3473
|
-
};
|
|
3474
|
-
|
|
3475
|
-
// scripts/run/run-watcher-guard.ts
|
|
3476
|
-
var WATCHER_TICK_MS = 3e4;
|
|
3477
|
-
var TICK_MULTIPLIER = 3;
|
|
3478
|
-
var MS_PER_SECOND3 = 1e3;
|
|
3479
|
-
var STALE_THRESHOLD_MS = WATCHER_TICK_MS * TICK_MULTIPLIER;
|
|
3480
|
-
var STALE_THRESHOLD_S = STALE_THRESHOLD_MS / MS_PER_SECOND3;
|
|
3481
|
-
var STALE_NOTE = `Lane children are in-flight but the progress watcher has not pinged in the last ${String(STALE_THRESHOLD_S)}s \u2014 run \`pnpm josh run:progress --wait\` in the background before proceeding`;
|
|
3482
|
-
var OK_RESULT = { kind: "ok" };
|
|
3483
|
-
async function has_lanes_in_flight() {
|
|
3484
|
-
const all_lanes = await lane_registry.list_lanes();
|
|
3485
|
-
return all_lanes.some((lane) => !lane.is_stranded);
|
|
3486
|
-
}
|
|
3487
|
-
async function check(life_target) {
|
|
3488
|
-
if (!await has_lanes_in_flight()) return OK_RESULT;
|
|
3489
|
-
if (run_progress_clock.is_life_fresh(life_target, STALE_THRESHOLD_MS)) return OK_RESULT;
|
|
3490
|
-
return { kind: "stale", note: STALE_NOTE };
|
|
3491
|
-
}
|
|
3492
|
-
var run_watcher_guard = {
|
|
3493
|
-
STALE_NOTE,
|
|
3494
|
-
STALE_THRESHOLD_MS,
|
|
3495
|
-
check,
|
|
3496
|
-
has_lanes_in_flight
|
|
3497
|
-
};
|
|
3498
|
-
|
|
3499
4175
|
// scripts/run/run-headless.ts
|
|
3500
4176
|
var HEADLESS_ENV_KEY = "JOSH_RUN_HEADLESS";
|
|
3501
4177
|
var HEADLESS_VALUE = "1";
|
|
@@ -3514,7 +4190,7 @@ async function read_carry_here() {
|
|
|
3514
4190
|
}
|
|
3515
4191
|
async function must_keep_waiting(source = process.env) {
|
|
3516
4192
|
const is_candidate2 = is_headless(source) && lane_child_marker.marked_issue(source) === void 0;
|
|
3517
|
-
if (!is_candidate2 || !await
|
|
4193
|
+
if (!is_candidate2 || !await lane_registry.has_lanes_in_flight()) return false;
|
|
3518
4194
|
return is_driving(await read_carry_here());
|
|
3519
4195
|
}
|
|
3520
4196
|
async function current_carry() {
|
|
@@ -3593,18 +4269,16 @@ function no_repo_line(target) {
|
|
|
3593
4269
|
return `\u2716 ${label(target)}: could not read this repository \u2014 check gh auth and the origin remote`;
|
|
3594
4270
|
}
|
|
3595
4271
|
var issue_cite = {
|
|
3596
|
-
SUMMARY_SEPARATOR,
|
|
3597
4272
|
citation_line,
|
|
3598
4273
|
citer,
|
|
3599
4274
|
issue_url,
|
|
3600
|
-
label,
|
|
3601
4275
|
missing_line,
|
|
3602
4276
|
no_repo_line,
|
|
3603
4277
|
parse_target,
|
|
3604
4278
|
unreadable_line
|
|
3605
4279
|
};
|
|
3606
4280
|
|
|
3607
|
-
// scripts/
|
|
4281
|
+
// scripts/gh/git-gh-api-path.ts
|
|
3608
4282
|
var FULL_PAGE_QUERY = "?per_page=100";
|
|
3609
4283
|
function repo_api_path(repo) {
|
|
3610
4284
|
return `repos/${repo ?? "{owner}/{repo}"}`;
|
|
@@ -3666,22 +4340,26 @@ var git_gh_api_path = {
|
|
|
3666
4340
|
commit_status_api_path
|
|
3667
4341
|
};
|
|
3668
4342
|
|
|
4343
|
+
// scripts/lib/timeouts.ts
|
|
4344
|
+
var FETCH_TIMEOUT_MS = 1e4;
|
|
4345
|
+
var COMMAND_TIMEOUT_MS = 3e4;
|
|
4346
|
+
|
|
3669
4347
|
// scripts/lib/error-message.ts
|
|
3670
4348
|
function message_of(error) {
|
|
3671
4349
|
return error instanceof Error ? error.message : String(error);
|
|
3672
4350
|
}
|
|
3673
4351
|
var error_text = { message_of };
|
|
3674
4352
|
|
|
3675
|
-
// scripts/
|
|
4353
|
+
// scripts/gh/git-gh-exec.ts
|
|
3676
4354
|
import { execa as execa5, execaSync as execaSync2 } from "execa";
|
|
3677
4355
|
|
|
3678
|
-
// scripts/
|
|
4356
|
+
// scripts/gh/git-gh-check.ts
|
|
3679
4357
|
import { execa as execa4 } from "execa";
|
|
3680
4358
|
var GH_NOT_INSTALLED_MSG = "gh CLI is not installed. Install it from https://cli.github.com/";
|
|
3681
4359
|
var gh_check = {};
|
|
3682
4360
|
async function run_gh_check() {
|
|
3683
4361
|
try {
|
|
3684
|
-
await execa4("gh", ["--version"]);
|
|
4362
|
+
await execa4("gh", ["--version"], { timeout: COMMAND_TIMEOUT_MS });
|
|
3685
4363
|
} catch {
|
|
3686
4364
|
delete gh_check.promise;
|
|
3687
4365
|
throw new Error(GH_NOT_INSTALLED_MSG);
|
|
@@ -3692,9 +4370,6 @@ async function check_gh_installed() {
|
|
|
3692
4370
|
await gh_check.promise;
|
|
3693
4371
|
}
|
|
3694
4372
|
|
|
3695
|
-
// scripts/git/git-gh-failure.ts
|
|
3696
|
-
import { z as z7 } from "zod";
|
|
3697
|
-
|
|
3698
4373
|
// scripts/git/parse-json-array.ts
|
|
3699
4374
|
var MALFORMED_JSON = /* @__PURE__ */ Symbol("malformed-json");
|
|
3700
4375
|
function parse_json_loose(raw_json) {
|
|
@@ -3718,25 +4393,18 @@ function read_json_listing(raw_json, element_schema) {
|
|
|
3718
4393
|
return { kind: "unexpected_shape" };
|
|
3719
4394
|
}
|
|
3720
4395
|
}
|
|
3721
|
-
function parse_json_array_safe(raw_json, element_schema) {
|
|
3722
|
-
const value = parse_json_loose(raw_json);
|
|
3723
|
-
if (value === MALFORMED_JSON) return [];
|
|
3724
|
-
return element_schema.array().parse(value);
|
|
3725
|
-
}
|
|
3726
4396
|
function parse_json_object_safe(raw_json, schema) {
|
|
3727
4397
|
const value = parse_json_loose(raw_json);
|
|
3728
4398
|
if (value === MALFORMED_JSON) return void 0;
|
|
3729
4399
|
return schema.parse(value);
|
|
3730
4400
|
}
|
|
3731
4401
|
var parse_json = {
|
|
3732
|
-
|
|
3733
|
-
parse_json_array_or_undefined,
|
|
3734
|
-
parse_json_object_safe,
|
|
3735
|
-
read_json_listing
|
|
4402
|
+
parse_json_object_safe
|
|
3736
4403
|
};
|
|
3737
4404
|
|
|
3738
|
-
// scripts/
|
|
3739
|
-
|
|
4405
|
+
// scripts/gh/git-gh-failure.ts
|
|
4406
|
+
import { z as z10 } from "zod";
|
|
4407
|
+
var error_document_schema = z10.object({ status: z10.union([z10.string(), z10.number()]).optional() }).catch({});
|
|
3740
4408
|
var GH_FAILURE_FIELD = "gh_failure";
|
|
3741
4409
|
function has_gh_failure(error) {
|
|
3742
4410
|
return error instanceof Error && Object.hasOwn(error, GH_FAILURE_FIELD);
|
|
@@ -3763,7 +4431,7 @@ function failure_of(error) {
|
|
|
3763
4431
|
}
|
|
3764
4432
|
var gh_failure = { attach, classify_stdout, failure_of, parse_response_status };
|
|
3765
4433
|
|
|
3766
|
-
// scripts/
|
|
4434
|
+
// scripts/gh/git-gh-exec.ts
|
|
3767
4435
|
var BODY_FROM_STDIN = "-";
|
|
3768
4436
|
var GH_REQUEST_TIMEOUT_MS = 6e4;
|
|
3769
4437
|
function to_timeout_option(timeout_ms) {
|
|
@@ -3829,20 +4497,20 @@ function parse_status_line(output) {
|
|
|
3829
4497
|
function status_of_failure(error) {
|
|
3830
4498
|
return has_stdout_field(error) ? parse_status_line(error.stdout) : void 0;
|
|
3831
4499
|
}
|
|
3832
|
-
async function exec_gh_api_status(
|
|
4500
|
+
async function exec_gh_api_status(path6, timeout_ms) {
|
|
3833
4501
|
const options = to_spawn_options(timeout_ms);
|
|
3834
4502
|
try {
|
|
3835
4503
|
await check_gh_installed();
|
|
3836
|
-
const { stdout } = await execa5("gh", ["api", "--include", "--silent",
|
|
4504
|
+
const { stdout } = await execa5("gh", ["api", "--include", "--silent", path6], options);
|
|
3837
4505
|
return parse_status_line(stdout);
|
|
3838
4506
|
} catch (error) {
|
|
3839
4507
|
return status_of_failure(error);
|
|
3840
4508
|
}
|
|
3841
4509
|
}
|
|
3842
|
-
function exec_gh_api_status_sync(
|
|
4510
|
+
function exec_gh_api_status_sync(path6, timeout_ms) {
|
|
3843
4511
|
const options = to_spawn_options(timeout_ms);
|
|
3844
4512
|
try {
|
|
3845
|
-
const { stdout } = execaSync2("gh", ["api", "--include", "--silent",
|
|
4513
|
+
const { stdout } = execaSync2("gh", ["api", "--include", "--silent", path6], options);
|
|
3846
4514
|
return parse_status_line(stdout);
|
|
3847
4515
|
} catch (error) {
|
|
3848
4516
|
return status_of_failure(error);
|
|
@@ -3915,7 +4583,8 @@ export {
|
|
|
3915
4583
|
shell_segments,
|
|
3916
4584
|
bash_triggers,
|
|
3917
4585
|
issue_cite,
|
|
3918
|
-
|
|
4586
|
+
git_command,
|
|
4587
|
+
git_common_directory,
|
|
3919
4588
|
tail_commands,
|
|
3920
4589
|
filing_cap,
|
|
3921
4590
|
CONTEXT_CUT_THRESHOLD,
|
|
@@ -3923,7 +4592,6 @@ export {
|
|
|
3923
4592
|
agent_session_environment,
|
|
3924
4593
|
agent_role_profile,
|
|
3925
4594
|
backlog_budget,
|
|
3926
|
-
git_command,
|
|
3927
4595
|
run_hold,
|
|
3928
4596
|
run_cut,
|
|
3929
4597
|
run_tail,
|
|
@@ -3940,18 +4608,22 @@ export {
|
|
|
3940
4608
|
RELEASE_CLASSIFICATION_NAMES,
|
|
3941
4609
|
has_any_label,
|
|
3942
4610
|
has_label_name,
|
|
3943
|
-
lane_park,
|
|
3944
|
-
repo_origin,
|
|
3945
|
-
repo_party,
|
|
3946
4611
|
process_identity,
|
|
4612
|
+
run_event_stream,
|
|
3947
4613
|
run_invocation,
|
|
3948
4614
|
run_carry,
|
|
4615
|
+
run_event_stream_emit,
|
|
4616
|
+
lane_handoff,
|
|
4617
|
+
lane_park,
|
|
4618
|
+
repo_origin,
|
|
4619
|
+
repo_party,
|
|
4620
|
+
process_owner_schema,
|
|
3949
4621
|
lane_registry,
|
|
3950
|
-
run_watcher_guard,
|
|
3951
4622
|
run_headless,
|
|
3952
4623
|
FULL_PAGE_QUERY,
|
|
3953
4624
|
git_gh_api_path,
|
|
3954
4625
|
error_text,
|
|
4626
|
+
FETCH_TIMEOUT_MS,
|
|
3955
4627
|
parse_json_array_or_undefined,
|
|
3956
4628
|
read_json_listing,
|
|
3957
4629
|
parse_json_object_safe,
|