@joshuafolkken/kit 1.1455.0 → 1.1514.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 +6 -6
- package/.claude/skills/dependency-update/SKILL.md +26 -55
- package/.claude/skills/epic-commands/SKILL.md +83 -156
- package/.claude/skills/epic-commands/epic-bundle.md +51 -79
- package/.claude/skills/epic-commands/execution-waves.md +43 -81
- package/.claude/skills/verify-ui/SKILL.md +24 -50
- package/.claude/skills/workflow-commands/SKILL.md +7 -9
- package/.claude/skills/workflow-commands/background-commands.md +31 -46
- package/.claude/skills/workflow-commands/backlogrun-child.md +65 -85
- package/.claude/skills/workflow-commands/backlogrun-lanes.md +86 -125
- package/.claude/skills/workflow-commands/backlogrun-park.md +68 -118
- package/.claude/skills/workflow-commands/backlogrun-progress.md +17 -28
- package/.claude/skills/workflow-commands/backlogrun-recovery.md +17 -26
- package/.claude/skills/workflow-commands/backlogrun-steps.md +35 -52
- package/.claude/skills/workflow-commands/backlogrun.md +31 -50
- package/.claude/skills/workflow-commands/chain-rule.md +31 -40
- package/.claude/skills/workflow-commands/delegation.md +12 -8
- package/.claude/skills/workflow-commands/entry-sequence.md +1 -3
- package/.claude/skills/workflow-commands/followup.md +55 -77
- package/.claude/skills/workflow-commands/fullrun-steps.md +3 -5
- package/.claude/skills/workflow-commands/fullrun.md +4 -6
- package/.claude/skills/workflow-commands/halfrun.md +3 -7
- package/.claude/skills/workflow-commands/into-target.md +1 -2
- package/.claude/skills/workflow-commands/issue-comments.md +43 -60
- package/.claude/skills/workflow-commands/issue-scout.md +3 -2
- package/.claude/skills/workflow-commands/kickoff.md +65 -74
- package/.claude/skills/workflow-commands/latest-gate.md +2 -6
- package/.claude/skills/workflow-commands/needs-human-review.md +2 -5
- package/.claude/skills/workflow-commands/observation-filing.md +59 -118
- package/.claude/skills/workflow-commands/observation-ledger.md +52 -112
- package/.claude/skills/workflow-commands/pre-gate-cut.md +88 -142
- package/.claude/skills/workflow-commands/prerequisite.md +11 -17
- package/.claude/skills/workflow-commands/progress-watcher.md +23 -33
- package/.claude/skills/workflow-commands/prrun.md +3 -5
- package/.claude/skills/workflow-commands/retrospective.md +35 -54
- package/.claude/skills/workflow-commands/split-assessment.md +32 -58
- package/.claude/skills/workflow-commands/target-repository.md +1 -2
- package/.claude/skills/workflow-commands/working-tree-hold.md +54 -73
- package/.codex/hooks.json +6 -6
- package/.github/actions/setup-node/action.yml +1 -1
- package/.github/workflows/ci.yml +1 -1
- package/.github/workflows/publish.yml +2 -2
- package/CLAUDE.md +7 -6
- package/cspell/index.yaml +7 -0
- package/dist/CLAUDE.md +7 -6
- package/dist/commands/document-section-cli.js +67 -34
- package/dist/hooks/batch-guard.js +6 -6
- package/dist/hooks/chunk-4KKD2UTK.js +66 -0
- package/dist/hooks/{chunk-GPLGZ6IC.js → chunk-6TS2JD6D.js} +14 -3
- package/dist/hooks/chunk-7DSBJVFH.js +50 -0
- package/dist/hooks/{chunk-5H4SSDSD.js → chunk-A65Y4YOR.js} +3 -3
- package/dist/hooks/{chunk-3C4XRYG6.js → chunk-APUO6U4J.js} +102 -19
- package/dist/hooks/{chunk-IX6TTTI6.js → chunk-EFXE6C37.js} +8 -22
- package/dist/hooks/chunk-GP4IEC4O.js +20 -0
- package/dist/hooks/chunk-JP45SOCJ.js +56 -0
- package/dist/hooks/{chunk-OLMO72ON.js → chunk-LAOV7NLM.js} +1 -1
- package/dist/hooks/chunk-M4HGZV7U.js +83 -0
- package/dist/hooks/{chunk-TBJFTSUY.js → chunk-O6GDRNJB.js} +9 -7
- package/dist/hooks/{chunk-HFGWYGUV.js → chunk-PF2NZL2A.js} +5 -5
- package/dist/hooks/{chunk-WNLVGT7E.js → chunk-PTICX4OL.js} +4 -5
- package/dist/hooks/{chunk-HHI6FO3R.js → chunk-RT27QRJW.js} +763 -1515
- package/dist/hooks/{chunk-7WQBPLUN.js → chunk-SYOTDYCI.js} +1149 -1095
- package/dist/hooks/{chunk-LIAFCXL7.js → chunk-TNUMY6NL.js} +1519 -1332
- package/dist/hooks/chunk-UPUZF3AN.js +279 -0
- package/dist/hooks/{chunk-Z4XI7CZS.js → chunk-WK6SMBIC.js} +1932 -784
- package/dist/hooks/codex-hook-adapter.js +17 -14
- package/dist/hooks/duplicate-read-guard.js +7 -7
- package/dist/hooks/format-edited.js +5 -4
- package/dist/hooks/inputs.json +302 -247
- package/dist/hooks/investigation-guard.js +8 -11
- package/dist/hooks/pretool-guard.js +16 -13
- package/dist/hooks/session-lang.js +372 -26
- package/dist/hooks/stop-guard.js +2593 -189
- package/dist/josh.js +2128 -282
- package/dist/managed-marker/index.js +1 -2
- package/dist/version/index.js +15 -12
- package/eslint/base.js +2 -1
- package/eslint/rules/unicorn.js +16 -0
- package/lefthook/base.yml +5 -3
- package/package.json +14 -12
- package/prompts/coding-standards.md +12 -22
- package/prompts/collaboration-workflow/file-edits.md +25 -45
- package/prompts/collaboration-workflow/gh-rest.md +19 -36
- package/prompts/collaboration-workflow/glossary.md +5 -7
- package/prompts/collaboration-workflow/issue-citation.md +6 -14
- package/prompts/collaboration-workflow/issue-template.md +40 -32
- package/prompts/collaboration-workflow/lane-instructions.md +35 -0
- package/prompts/collaboration-workflow/operating-rules.md +33 -46
- package/prompts/collaboration-workflow/output-bounds.md +15 -15
- package/prompts/collaboration-workflow/overview.md +14 -19
- package/prompts/collaboration-workflow/plan-comment.md +13 -13
- package/prompts/collaboration-workflow/principles.md +57 -54
- package/prompts/collaboration-workflow/proposal-request.md +1 -9
- package/prompts/collaboration-workflow/report-format.md +41 -49
- package/prompts/collaboration-workflow/residency.md +15 -11
- package/prompts/collaboration-workflow/rule-delivery.md +7 -15
- package/prompts/collaboration-workflow/shell-body.md +10 -20
- package/prompts/collaboration-workflow/turn-batching.md +8 -14
- package/prompts/collaboration-workflow/upstream-interrupt.md +26 -34
- package/prompts/collaboration-workflow/wip-cap.md +26 -32
- package/prompts/collaboration-workflow.md +25 -25
- package/prompts/refactoring.md +33 -43
- package/prompts/review-rubric.md +84 -129
- package/prompts/review.md +110 -141
- package/prompts/sonar-hotspot-handling.md +22 -50
- package/prompts/testing-guide.md +48 -99
- package/scripts/adopt/adopt-toolkits.ts +2 -4
- package/scripts/agent/agent-argv.ts +20 -4
- package/scripts/agent/agent-exit-record.ts +23 -1
- package/scripts/agent/agent-role-profile.ts +101 -45
- package/scripts/agent/agent-safe-text.ts +60 -0
- package/scripts/agent/claude-agent-argv.ts +14 -0
- package/scripts/agent/codex-agent-argv.ts +9 -2
- package/scripts/agent/lane-instructions.ts +144 -0
- package/scripts/backlog/backlog-budget-cli.ts +1 -2
- package/scripts/backlog/backlog-budget.ts +4 -4
- package/scripts/backlog/backlog-drive-carried.ts +26 -0
- package/scripts/backlog/backlog-drive-cli.ts +10 -5
- package/scripts/backlog/backlog-drive-named.ts +3 -5
- package/scripts/backlog/backlog-drive-restore.ts +28 -2
- package/scripts/backlog/backlog-drive-seats.ts +27 -0
- package/scripts/backlog/backlog-drive.ts +11 -6
- package/scripts/backlog/backlog-occupied.ts +56 -0
- package/scripts/backlog/backlog-ready.ts +59 -15
- package/scripts/behavior/behavior-rules.ts +3 -2
- package/scripts/cost-runtime/codex-usage.ts +4 -2
- package/scripts/cost-runtime/cost-cli.ts +1 -2
- package/scripts/delegation/duplicate-read-guard.ts +2 -2
- package/scripts/delegation/investigation-guard.ts +15 -65
- package/scripts/delegation/investigation-reads.ts +1 -2
- package/scripts/discovery/repo-discovery.ts +4 -2
- package/scripts/discovery/repo-origin.ts +2 -4
- package/scripts/doctor/doctor-logic.ts +6 -3
- package/scripts/document/document-byte-budget.ts +28 -27
- package/scripts/document/document-byte-check.ts +1 -2
- package/scripts/document/document-section-cli.ts +17 -5
- package/scripts/document/entry-read-budget.ts +3 -3
- package/scripts/document/read-set-cli.ts +4 -1
- package/scripts/epic/epic-audit-orphans.ts +5 -8
- package/scripts/epic/epic-audit-rationale.ts +8 -2
- package/scripts/epic/epic-audit.ts +52 -1
- package/scripts/epic/epic-bundle-cli.ts +1 -2
- package/scripts/epic/epic-bundle-evidence.ts +49 -26
- package/scripts/epic/epic-bundle-referenced.ts +14 -3
- package/scripts/epic/epic-bundle.ts +17 -9
- package/scripts/epic/epic-chains.ts +6 -2
- package/scripts/epic/epic-close-comment.ts +1 -2
- package/scripts/followup/git-followup-workflow.ts +19 -1
- package/scripts/gate/check-inputs.ts +129 -0
- package/scripts/gate/check-reuse.ts +162 -0
- package/scripts/gate/core-budget.ts +93 -44
- package/scripts/gate/core-wait.ts +130 -0
- package/scripts/gate/free-cores.ts +49 -0
- package/scripts/gate/gate-ledger.ts +17 -3
- package/scripts/gate/gate-plan.ts +23 -1
- package/scripts/gate/gate-report.ts +15 -2
- package/scripts/gate/gate-run-steps.ts +150 -0
- package/scripts/gate/held-mark.ts +55 -0
- package/scripts/gate/machine-capacity.ts +70 -11
- package/scripts/gate/pre-commit-type-check.ts +14 -1
- package/scripts/gate/verification-gate.ts +65 -127
- package/scripts/gh/git-gh-issue-rest.ts +1 -0
- package/scripts/gh/git-gh-issue-write.ts +24 -2
- package/scripts/gh/git-pr.ts +19 -3
- package/scripts/git/git-common-directory.ts +3 -3
- package/scripts/git/git-diff-reads.ts +16 -9
- package/scripts/git/git-execa-error.ts +1 -2
- package/scripts/git/main-merge-regenerate.ts +78 -0
- package/scripts/git/main-merge.ts +14 -5
- package/scripts/hooks/batch-guard.ts +5 -8
- package/scripts/hooks/format-edited-file.ts +10 -4
- package/scripts/hooks/pre-commit-lint.ts +91 -0
- package/scripts/hooks/pre-push-unit.ts +15 -4
- package/scripts/hooks/pretool-guard.ts +48 -79
- package/scripts/hooks/reserved-run.ts +1 -0
- package/scripts/hooks/run-hook.sh +10 -12
- package/scripts/hooks/step-zero-notice.ts +3 -2
- package/scripts/hooks/stop-actions.ts +204 -0
- package/scripts/hooks/stop-guard.ts +62 -21
- package/scripts/init/hook-command-rewrite.ts +6 -2
- package/scripts/init/hook-launch.ts +12 -7
- package/scripts/init/init-logic-deploy-vps.ts +4 -2
- package/scripts/issue/behavior-change-lint.ts +12 -6
- package/scripts/issue/expected-effect-lint.ts +59 -0
- package/scripts/issue/issue-cite-cli.ts +35 -15
- package/scripts/issue/issue-classification.ts +1 -1
- package/scripts/issue/issue-lint-cli.ts +5 -3
- package/scripts/issue/issue-scout-cli.ts +22 -16
- package/scripts/issue/markdown-section.ts +19 -5
- package/scripts/josh/command-usage.ts +110 -0
- package/scripts/josh/file-map-stamp.ts +1 -3
- package/scripts/josh/hook-decision.ts +17 -2
- package/scripts/josh/josh-command-map.ts +2 -0
- package/scripts/josh/josh-command-types.ts +55 -9
- package/scripts/josh/josh-commands-ai.ts +13 -0
- package/scripts/josh/josh-commands-development.ts +1 -1
- package/scripts/josh/josh-commands-hooks.ts +6 -0
- package/scripts/josh/josh-commands-lane.ts +10 -1
- package/scripts/josh/josh-commands-workflow.ts +5 -0
- package/scripts/josh/josh-logic.ts +6 -15
- package/scripts/josh/josh-usage-automation.ts +121 -0
- package/scripts/josh/josh-usage-backlog.ts +180 -0
- package/scripts/josh/josh-usage-developer.ts +230 -0
- package/scripts/josh/josh-usage-hooks.ts +38 -0
- package/scripts/josh/josh-usage-issue.ts +205 -0
- package/scripts/josh/josh-usage-review.ts +101 -0
- package/scripts/josh/josh-usage-run.ts +252 -0
- package/scripts/josh/josh-usage-session.ts +238 -0
- package/scripts/josh/josh-usage-workflow.ts +212 -0
- package/scripts/josh/josh.ts +14 -5
- package/scripts/josh/package-directory.ts +20 -0
- package/scripts/lane/lane-await.ts +3 -2
- package/scripts/lane/lane-capacity.ts +8 -2
- package/scripts/lane/lane-check-stats.ts +56 -0
- package/scripts/lane/lane-child-invocation.ts +49 -5
- package/scripts/lane/lane-dispatch.ts +3 -3
- package/scripts/lane/lane-guard-policy.ts +5 -5
- package/scripts/lane/lane-handoff.ts +8 -1
- package/scripts/lane/lane-install.ts +12 -4
- package/scripts/lane/lane-ledger.ts +52 -1
- package/scripts/lane/lane-limit-cli.ts +8 -9
- package/scripts/lane/lane-load.ts +9 -2
- package/scripts/lane/lane-measure-cli.ts +4 -0
- package/scripts/lane/lane-parked.ts +18 -0
- package/scripts/lane/lane-preserve.ts +29 -1
- package/scripts/lane/lane-process-load.ts +125 -0
- package/scripts/lane/lane-process-stats.ts +93 -0
- package/scripts/lane/lane-registry.ts +17 -10
- package/scripts/lane/lane-restart.ts +5 -26
- package/scripts/lane/lane-session-action.ts +146 -0
- package/scripts/lane/lane-session-broker.ts +68 -125
- package/scripts/lane/lane-spent.ts +14 -3
- package/scripts/lane/lane-stats.ts +1 -0
- package/scripts/lane/lane-withdraw-cli.ts +71 -0
- package/scripts/lane/lane-withdraw.ts +182 -0
- package/scripts/lint/format.ts +4 -4
- package/scripts/lint/lint-parallel.ts +10 -3
- package/scripts/lint/lint-related-scope.ts +4 -1
- package/scripts/managed-marker/managed-marker-logic.ts +1 -2
- package/scripts/notify/telegram-test.ts +10 -5
- package/scripts/overrides/lockfile-overrides.ts +1 -3
- package/scripts/propagate/propagate.ts +1 -2
- package/scripts/release/release-progress.ts +3 -2
- package/scripts/report/report-format-reference.ts +2 -0
- package/scripts/report/report-lint.ts +7 -4
- package/scripts/review/acceptance-map-check.ts +61 -0
- package/scripts/review/acceptance-map.ts +205 -0
- package/scripts/review/review-brief-cli.ts +1 -1
- package/scripts/review/review-record-cli.ts +6 -2
- package/scripts/rules/agent-model.ts +59 -0
- package/scripts/rules/delivered-rules.ts +11 -2
- package/scripts/rules/destructive-command.ts +6 -9
- package/scripts/rules/direct-filing.ts +3 -7
- package/scripts/rules/early-heartbeat.ts +7 -18
- package/scripts/rules/file-body.ts +6 -13
- package/scripts/rules/filing-cap.ts +4 -6
- package/scripts/rules/firing-point.ts +6 -5
- package/scripts/rules/git-force.ts +5 -9
- package/scripts/rules/guard-remedy.ts +117 -0
- package/scripts/rules/implementation-cut.ts +37 -35
- package/scripts/rules/index-guard.ts +4 -7
- package/scripts/rules/issue-comments.ts +67 -16
- package/scripts/rules/josh-git-bare.ts +3 -6
- package/scripts/rules/lane-background.ts +10 -21
- package/scripts/rules/lane-carry-conflict.ts +7 -17
- package/scripts/rules/lane-interactive-ask.ts +6 -11
- package/scripts/rules/lane-park.ts +5 -13
- package/scripts/rules/lane-split-park.ts +2 -7
- package/scripts/rules/lane-switch-main.ts +9 -12
- package/scripts/rules/last-prompt.ts +50 -5
- package/scripts/rules/oracle-consulted.ts +4 -5
- package/scripts/rules/oracle-list-cli.ts +7 -0
- package/scripts/rules/piped-verification.ts +84 -32
- package/scripts/rules/poll-loop.ts +7 -17
- package/scripts/rules/pre-gate-cut.ts +7 -21
- package/scripts/rules/prior-comment-read.ts +7 -5
- package/scripts/rules/protected-files.ts +5 -9
- package/scripts/rules/raw-field-body.ts +3 -7
- package/scripts/rules/rule-body-guard.ts +4 -11
- package/scripts/rules/rule-list.ts +4 -1
- package/scripts/rules/rule-registry-rows.ts +10 -0
- package/scripts/rules/rule-registry.ts +7 -4
- package/scripts/rules/rule-rewrite.ts +114 -0
- package/scripts/rules/rule-value.ts +7 -1
- package/scripts/rules/run-tail-rule.ts +6 -22
- package/scripts/rules/shell-body-trigger.ts +4 -6
- package/scripts/rules/shell-segments.ts +22 -0
- package/scripts/rules/stop-decision.ts +77 -0
- package/scripts/rules/stop-rules.ts +164 -77
- package/scripts/rules/tail-commands.ts +15 -1
- package/scripts/rules/test-declared-commit.ts +4 -10
- package/scripts/rules/third-party-write.ts +5 -10
- package/scripts/rules/worktree-guard.ts +5 -12
- package/scripts/run/board/run-board-cli.ts +2 -0
- package/scripts/run/board/run-board-closed.ts +8 -2
- package/scripts/run/board/run-board-github.ts +19 -3
- package/scripts/run/board/run-board-header.ts +4 -1
- package/scripts/run/board/run-board-idle.ts +31 -0
- package/scripts/run/board/run-board-labels.ts +2 -0
- package/scripts/run/board/run-board-layout.ts +1 -1
- package/scripts/run/board/run-board-read.ts +25 -12
- package/scripts/run/board/run-board-reason.ts +17 -4
- package/scripts/run/board/run-board-render-legend.ts +1 -0
- package/scripts/run/board/run-board-render-slot.ts +1 -1
- package/scripts/run/board/run-board-render-waits.ts +41 -0
- package/scripts/run/board/run-board-render.ts +6 -1
- package/scripts/run/board/run-board-row-yield.ts +1 -0
- package/scripts/run/board/run-board-state.ts +9 -0
- package/scripts/run/board/run-board-status.ts +89 -23
- package/scripts/run/board/run-board-thanks.ts +7 -2
- package/scripts/run/board/run-board-tick.ts +37 -8
- package/scripts/run/carry/run-carry-args.ts +1 -3
- package/scripts/run/carry/run-carry-conversation.ts +7 -2
- package/scripts/run/cut/run-cut-cli.ts +18 -22
- package/scripts/run/cut/run-cut-decline.ts +72 -0
- package/scripts/run/cut/run-cut-ready.ts +74 -0
- package/scripts/run/cut/run-cut-report.ts +29 -0
- package/scripts/run/cut/run-cut.ts +10 -1
- package/scripts/run/detached-launch.ts +23 -4
- package/scripts/run/entry/run-entry-cli.ts +8 -1
- package/scripts/run/event/run-event-render.ts +1 -0
- package/scripts/run/event/run-event-scope.ts +19 -1
- package/scripts/run/event/run-event-stream-emit.ts +13 -6
- package/scripts/run/event/run-event-stream.ts +4 -0
- package/scripts/run/hold/run-hold-cli.ts +14 -3
- package/scripts/run/hold/run-hold-session.ts +46 -0
- package/scripts/run/hold/run-hold.ts +13 -4
- package/scripts/run/launch-priority.ts +32 -0
- package/scripts/run/merge/run-merge-cli.ts +16 -42
- package/scripts/run/merge/run-merge-ship.ts +59 -1
- package/scripts/run/merge/run-merge-signals.ts +99 -0
- package/scripts/run/merge/run-merge-steps.ts +11 -1
- package/scripts/run/merge/run-merge.ts +22 -9
- package/scripts/run/run-ending.ts +31 -3
- package/scripts/run/run-liveness.ts +1 -1
- package/scripts/run/run-parent-cut-hook.ts +5 -10
- package/scripts/run/run-poll-hook.ts +157 -0
- package/scripts/run/run-preflight.ts +1 -2
- package/scripts/run/run-step-cli.ts +22 -15
- package/scripts/run/run-step-section.ts +85 -0
- package/scripts/run/run-stop-notify.ts +1 -2
- package/scripts/run/run-watcher-guard.ts +6 -3
- package/scripts/run/ship/run-ship-cli.ts +5 -12
- package/scripts/run/ship/run-ship-detach.ts +9 -0
- package/scripts/run/ship/run-ship-next.ts +10 -2
- package/scripts/run/ship/run-ship-overlap.ts +195 -0
- package/scripts/run/ship/run-ship-pre-detach.ts +33 -15
- package/scripts/run/ship/run-ship-preflight.ts +28 -2
- package/scripts/run/ship/run-ship-return.ts +31 -7
- package/scripts/run/ship/run-ship-review-steps.ts +25 -14
- package/scripts/run/ship/run-ship-review.ts +15 -2
- package/scripts/run/ship/run-ship-steps.ts +1 -1
- package/scripts/run/ship/run-ship-stop-context.ts +206 -0
- package/scripts/run/ship/run-ship-sync.ts +14 -6
- package/scripts/run/tidy/run-tidy-cli.ts +3 -3
- package/scripts/run/tidy/run-tidy-lanes.ts +3 -2
- package/scripts/safe-chain/project-config.ts +7 -2
- package/scripts/sync/sync-hook-safety.ts +8 -2
- package/scripts/test/test-e2e-guard.ts +30 -5
- package/scripts/test/test-unit-guard.ts +16 -1
- package/scripts/test/unit-worker-share.ts +26 -3
- package/scripts/time-runtime/time-batch-guard.ts +3 -3
- package/scripts/time-runtime/time-hook-transcript.ts +3 -2
- package/scripts/time-runtime/time-shell.ts +39 -4
- package/scripts/time-runtime/time-spans.ts +1 -0
- package/scripts/time-runtime/time-tool-call.ts +7 -0
- package/scripts/version/effective-upstream.ts +3 -4
- package/scripts/version/kit-version-config.ts +8 -2
- package/scripts/version/latest-corepack.ts +1 -2
- package/scripts/version/release-hold.ts +11 -4
- package/scripts/version/version-commands.ts +12 -4
- package/templates/gitignore +6 -2
- package/dist/hooks/chunk-D5QBTOCZ.js +0 -68
- package/dist/hooks/chunk-UT7YC3N2.js +0 -56
|
@@ -1,102 +1,110 @@
|
|
|
1
1
|
import {
|
|
2
2
|
duplicate_read_outcome
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-PF2NZL2A.js";
|
|
4
4
|
import {
|
|
5
5
|
ALREADY_DONE_LABEL,
|
|
6
6
|
CONTEXT_CUT_THRESHOLD,
|
|
7
7
|
IN_PROGRESS_LABEL,
|
|
8
8
|
NEEDS_DECISION_LABEL,
|
|
9
|
-
NEEDS_HUMAN_REVIEW_LABEL,
|
|
10
9
|
bash_triggers,
|
|
10
|
+
cost_cli,
|
|
11
|
+
cost_verdict,
|
|
11
12
|
filing_cap,
|
|
12
|
-
git_gh_api_path,
|
|
13
13
|
git_gh_command,
|
|
14
|
-
git_gh_exec,
|
|
15
14
|
git_gh_issue_read,
|
|
16
|
-
git_gh_pr_read,
|
|
17
15
|
has_any_label,
|
|
18
|
-
|
|
16
|
+
interactive_ask,
|
|
19
17
|
issue_watch_diff,
|
|
20
18
|
lane_background,
|
|
21
19
|
lane_park,
|
|
22
|
-
|
|
23
|
-
read_json_listing,
|
|
20
|
+
pre_gate_cut,
|
|
24
21
|
repo_party,
|
|
25
22
|
run_cut,
|
|
26
23
|
run_cut_handoff,
|
|
27
|
-
|
|
24
|
+
run_liveness,
|
|
28
25
|
run_tail_rule,
|
|
29
|
-
session_cite,
|
|
30
26
|
shell_segments,
|
|
31
27
|
tail_commands
|
|
32
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-SYOTDYCI.js";
|
|
33
29
|
import {
|
|
34
|
-
ancestor_directories,
|
|
35
30
|
find_local_bin_upwards,
|
|
36
31
|
json_object_schema,
|
|
37
32
|
string_array_schema,
|
|
38
33
|
string_record_schema,
|
|
39
34
|
vscode_settings_schema
|
|
40
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-EFXE6C37.js";
|
|
36
|
+
import {
|
|
37
|
+
distributed_paths
|
|
38
|
+
} from "./chunk-M4HGZV7U.js";
|
|
41
39
|
import {
|
|
42
|
-
agent_role_profile,
|
|
43
|
-
agent_session_role,
|
|
44
40
|
git_common_directory,
|
|
41
|
+
git_gh_api_path,
|
|
42
|
+
git_gh_exec,
|
|
43
|
+
has_stdout_field,
|
|
45
44
|
issue_cite,
|
|
46
45
|
lane_registry,
|
|
46
|
+
read_json_listing,
|
|
47
47
|
repo_origin,
|
|
48
48
|
run_event_scope,
|
|
49
49
|
run_event_stream,
|
|
50
50
|
run_event_stream_emit,
|
|
51
51
|
run_headless,
|
|
52
|
+
run_hold,
|
|
53
|
+
run_preflight,
|
|
54
|
+
session_cite,
|
|
52
55
|
session_language
|
|
53
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-WK6SMBIC.js";
|
|
57
|
+
import {
|
|
58
|
+
ancestor_directories
|
|
59
|
+
} from "./chunk-GP4IEC4O.js";
|
|
54
60
|
import {
|
|
55
61
|
error_text
|
|
56
62
|
} from "./chunk-CDY4NFQG.js";
|
|
57
63
|
import {
|
|
58
64
|
batch_outcome
|
|
59
|
-
} from "./chunk-
|
|
65
|
+
} from "./chunk-A65Y4YOR.js";
|
|
60
66
|
import {
|
|
61
|
-
|
|
62
|
-
} from "./chunk-
|
|
67
|
+
investigation_outcome
|
|
68
|
+
} from "./chunk-7DSBJVFH.js";
|
|
63
69
|
import {
|
|
64
70
|
investigation_reads
|
|
65
|
-
} from "./chunk-
|
|
71
|
+
} from "./chunk-PTICX4OL.js";
|
|
72
|
+
import {
|
|
73
|
+
agent_role_profile,
|
|
74
|
+
agent_session_role
|
|
75
|
+
} from "./chunk-UPUZF3AN.js";
|
|
66
76
|
import {
|
|
67
77
|
lane_guard_policy
|
|
68
|
-
} from "./chunk-
|
|
78
|
+
} from "./chunk-JP45SOCJ.js";
|
|
69
79
|
import {
|
|
70
80
|
hook_decision
|
|
71
|
-
} from "./chunk-
|
|
81
|
+
} from "./chunk-6TS2JD6D.js";
|
|
72
82
|
import {
|
|
73
|
-
cost_attribute,
|
|
74
83
|
cost_blocks,
|
|
75
|
-
open_issue_schema,
|
|
76
84
|
time_batch_guard,
|
|
77
85
|
time_density_hook,
|
|
78
|
-
|
|
79
|
-
|
|
86
|
+
time_hook_transcript,
|
|
87
|
+
time_shell,
|
|
88
|
+
time_spans
|
|
89
|
+
} from "./chunk-TNUMY6NL.js";
|
|
80
90
|
import {
|
|
81
91
|
lane_child_marker
|
|
82
|
-
} from "./chunk-
|
|
92
|
+
} from "./chunk-LAOV7NLM.js";
|
|
83
93
|
import {
|
|
84
94
|
GIT_LOCATION_VARIABLES,
|
|
85
95
|
PORCELAIN_FLAG,
|
|
86
|
-
|
|
87
|
-
cost_transcript,
|
|
88
|
-
cost_usage,
|
|
96
|
+
UNTRACKED_FILES_FLAG,
|
|
89
97
|
file_reader,
|
|
90
98
|
git_command,
|
|
99
|
+
git_diff_reads,
|
|
91
100
|
git_spawn_sync,
|
|
92
101
|
issue_number_shape,
|
|
93
102
|
json_value,
|
|
94
103
|
lane_paths,
|
|
95
|
-
|
|
104
|
+
open_issue_schema,
|
|
96
105
|
run_carry
|
|
97
|
-
} from "./chunk-
|
|
106
|
+
} from "./chunk-APUO6U4J.js";
|
|
98
107
|
import {
|
|
99
|
-
PLATFORM_TEMP_ROOT,
|
|
100
108
|
PROBE_TIMEOUT_MS,
|
|
101
109
|
PROJECT_ROOT,
|
|
102
110
|
package_path,
|
|
@@ -114,9 +122,9 @@ var HEADER_BODY_SEPARATOR = /\r?\n\r?\n/u;
|
|
|
114
122
|
var ETAG_HEADER = /^etag: *(?<etag>[^\r\n]+)/imu;
|
|
115
123
|
var UNCHANGED = { kind: "unchanged" };
|
|
116
124
|
var UNREADABLE = { kind: "unreadable" };
|
|
117
|
-
function to_args(
|
|
125
|
+
function to_args(path13, etag) {
|
|
118
126
|
const header = etag === void 0 ? [] : [HEADER_FLAG, `${IF_NONE_MATCH}${etag}`];
|
|
119
|
-
return ["api", INCLUDE_FLAG, ...header,
|
|
127
|
+
return ["api", INCLUDE_FLAG, ...header, path13];
|
|
120
128
|
}
|
|
121
129
|
function to_changed(output) {
|
|
122
130
|
const [headers = "", ...rest] = output.split(HEADER_BODY_SEPARATOR);
|
|
@@ -130,9 +138,9 @@ function failure_status(error) {
|
|
|
130
138
|
const cause = error instanceof Error ? error.cause : void 0;
|
|
131
139
|
return has_stdout_field(cause) ? git_gh_exec.parse_status_line(cause.stdout) : void 0;
|
|
132
140
|
}
|
|
133
|
-
async function read_conditional(
|
|
141
|
+
async function read_conditional(path13, etag, timeout_ms) {
|
|
134
142
|
try {
|
|
135
|
-
return to_read(await git_gh_exec.exec_gh_command(to_args(
|
|
143
|
+
return to_read(await git_gh_exec.exec_gh_command(to_args(path13, etag), timeout_ms));
|
|
136
144
|
} catch (error) {
|
|
137
145
|
return failure_status(error) === NOT_MODIFIED_STATUS ? UNCHANGED : UNREADABLE;
|
|
138
146
|
}
|
|
@@ -162,9 +170,9 @@ function read_record(root) {
|
|
|
162
170
|
const raw = stamp_file.read_stamp_text(record_path(root));
|
|
163
171
|
return raw === void 0 ? void 0 : json_value.parse_with(raw, record_schema);
|
|
164
172
|
}
|
|
165
|
-
function write_record(
|
|
166
|
-
stamp_file.replace_stamp(record_path(root),
|
|
167
|
-
return
|
|
173
|
+
function write_record(record2, root) {
|
|
174
|
+
stamp_file.replace_stamp(record_path(root), record2);
|
|
175
|
+
return record2;
|
|
168
176
|
}
|
|
169
177
|
function clear(root) {
|
|
170
178
|
stamp_file.remove_stamp(record_path(root));
|
|
@@ -204,44 +212,44 @@ async function record_baseline_here(issue) {
|
|
|
204
212
|
async function clear_here() {
|
|
205
213
|
clear(await git_command.repository_root());
|
|
206
214
|
}
|
|
207
|
-
function with_fetched(
|
|
208
|
-
if (fetched.kind !== "read") return { ...
|
|
209
|
-
const pending = issue_watch_diff.unread_diff(
|
|
210
|
-
return { ...
|
|
215
|
+
function with_fetched(record2, fetched, checked_at) {
|
|
216
|
+
if (fetched.kind !== "read") return { ...record2, checked_at };
|
|
217
|
+
const pending = issue_watch_diff.unread_diff(record2, fetched.snapshot);
|
|
218
|
+
return { ...record2, checked_at, etag: fetched.etag, pending };
|
|
211
219
|
}
|
|
212
|
-
function is_due(
|
|
213
|
-
return now.getTime() - Date.parse(
|
|
220
|
+
function is_due(record2, options, now) {
|
|
221
|
+
return now.getTime() - Date.parse(record2.checked_at) >= options.interval_ms;
|
|
214
222
|
}
|
|
215
|
-
async function refresh(
|
|
223
|
+
async function refresh(record2, options, now, root) {
|
|
216
224
|
const fetched = await fetch_issue({
|
|
217
|
-
issue:
|
|
218
|
-
etag:
|
|
225
|
+
issue: record2.issue,
|
|
226
|
+
etag: record2.etag,
|
|
219
227
|
timeout_ms: options.timeout_ms
|
|
220
228
|
});
|
|
221
229
|
if (fetched.kind === "closed") {
|
|
222
230
|
clear(root);
|
|
223
231
|
return void 0;
|
|
224
232
|
}
|
|
225
|
-
return write_record(with_fetched(
|
|
233
|
+
return write_record(with_fetched(record2, fetched, now.toISOString()), root);
|
|
226
234
|
}
|
|
227
235
|
async function poll(options, root) {
|
|
228
|
-
const
|
|
236
|
+
const record2 = read_record(root);
|
|
229
237
|
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
230
|
-
if (
|
|
231
|
-
return await refresh(
|
|
238
|
+
if (record2 === void 0 || !is_due(record2, options, now)) return record2;
|
|
239
|
+
return await refresh(record2, options, now, root);
|
|
232
240
|
}
|
|
233
|
-
function mark_shown(
|
|
234
|
-
return write_record({ ...
|
|
241
|
+
function mark_shown(record2, root) {
|
|
242
|
+
return write_record({ ...record2, shown: record2.pending }, root);
|
|
235
243
|
}
|
|
236
244
|
async function acknowledge(root, now = /* @__PURE__ */ new Date()) {
|
|
237
|
-
const
|
|
238
|
-
if (
|
|
239
|
-
const fetched = await fetch_issue({ issue:
|
|
245
|
+
const record2 = read_record(root);
|
|
246
|
+
if (record2 === void 0) return void 0;
|
|
247
|
+
const fetched = await fetch_issue({ issue: record2.issue });
|
|
240
248
|
if (fetched.kind !== "read") return void 0;
|
|
241
|
-
const diff = issue_watch_diff.unread_diff(
|
|
242
|
-
const acknowledged_at = diff === void 0 ?
|
|
243
|
-
write_record(fresh_record(
|
|
244
|
-
return { issue:
|
|
249
|
+
const diff = issue_watch_diff.unread_diff(record2, fetched.snapshot);
|
|
250
|
+
const acknowledged_at = diff === void 0 ? record2.acknowledged_at : now.toISOString();
|
|
251
|
+
write_record(fresh_record(record2.issue, fetched, now, acknowledged_at), root);
|
|
252
|
+
return { issue: record2.issue, diff };
|
|
245
253
|
}
|
|
246
254
|
var issue_watch = {
|
|
247
255
|
acknowledge,
|
|
@@ -444,16 +452,16 @@ var EVERY_CALL_MS = 0;
|
|
|
444
452
|
function ack_command(issue) {
|
|
445
453
|
return `pnpm josh issue:ack ${issue}`;
|
|
446
454
|
}
|
|
447
|
-
function unread_message(
|
|
455
|
+
function unread_message(record2) {
|
|
448
456
|
return [
|
|
449
|
-
`A person updated issue ${session_cite.issue(
|
|
450
|
-
|
|
451
|
-
`Read it, compare it with the acceptance criteria, fix what it changes, then run \`${ack_command(
|
|
457
|
+
`A person updated issue ${session_cite.issue(record2.issue)} after this run read it, and the run has not taken the update in:`,
|
|
458
|
+
record2.pending ?? "",
|
|
459
|
+
`Read it, compare it with the acceptance criteria, fix what it changes, then run \`${ack_command(record2.issue)}\` to record that it was read.`
|
|
452
460
|
].join("\n\n");
|
|
453
461
|
}
|
|
454
|
-
function review_message(
|
|
462
|
+
function review_message(record2, briefed_at) {
|
|
455
463
|
return [
|
|
456
|
-
`Issue ${session_cite.issue(
|
|
464
|
+
`Issue ${session_cite.issue(record2.issue)} was updated after the review was briefed (taken in at ${record2.acknowledged_at}, briefed at ${briefed_at}), so the review read the earlier specification.`,
|
|
457
465
|
"Re-run `/code-review` with a fresh `pnpm josh review:brief`, so the review reads the change against the updated issue."
|
|
458
466
|
].join("\n");
|
|
459
467
|
}
|
|
@@ -461,16 +469,16 @@ async function polled(root) {
|
|
|
461
469
|
return await issue_watch.poll({ interval_ms: EVERY_CALL_MS }, root);
|
|
462
470
|
}
|
|
463
471
|
async function unread_refusal(root) {
|
|
464
|
-
const
|
|
465
|
-
return
|
|
472
|
+
const record2 = await polled(root);
|
|
473
|
+
return record2?.pending === void 0 ? void 0 : unread_message(record2);
|
|
466
474
|
}
|
|
467
475
|
async function review_refusal(root) {
|
|
468
|
-
const
|
|
469
|
-
if (
|
|
470
|
-
if (
|
|
476
|
+
const record2 = await polled(root);
|
|
477
|
+
if (record2 === void 0) return void 0;
|
|
478
|
+
if (record2.pending !== void 0) return unread_message(record2);
|
|
471
479
|
const pointer = review_attest.read_pointer(root);
|
|
472
|
-
if (pointer === void 0 ||
|
|
473
|
-
return review_message(
|
|
480
|
+
if (pointer === void 0 || record2.acknowledged_at <= pointer.taken_at) return void 0;
|
|
481
|
+
return review_message(record2, pointer.taken_at);
|
|
474
482
|
}
|
|
475
483
|
async function review_refusal_here() {
|
|
476
484
|
return await review_refusal(await git_command.repository_root());
|
|
@@ -490,18 +498,18 @@ var issue_watch_gate = {
|
|
|
490
498
|
// scripts/issue/issue-watch-hook.ts
|
|
491
499
|
var POLL_INTERVAL_MS = 18e4;
|
|
492
500
|
var POLL_TIMEOUT_MS = 5e3;
|
|
493
|
-
function is_new_to_run(
|
|
494
|
-
return
|
|
501
|
+
function is_new_to_run(record2) {
|
|
502
|
+
return record2?.pending !== void 0 && record2.pending !== record2.shown;
|
|
495
503
|
}
|
|
496
504
|
async function new_update_reason(now) {
|
|
497
|
-
const
|
|
505
|
+
const record2 = await issue_watch.poll({
|
|
498
506
|
interval_ms: POLL_INTERVAL_MS,
|
|
499
507
|
timeout_ms: POLL_TIMEOUT_MS,
|
|
500
508
|
now
|
|
501
509
|
});
|
|
502
|
-
if (!is_new_to_run(
|
|
503
|
-
issue_watch.mark_shown(
|
|
504
|
-
return issue_watch_gate.unread_message(
|
|
510
|
+
if (!is_new_to_run(record2)) return void 0;
|
|
511
|
+
issue_watch.mark_shown(record2);
|
|
512
|
+
return issue_watch_gate.unread_message(record2);
|
|
505
513
|
}
|
|
506
514
|
async function watch_reason(now = /* @__PURE__ */ new Date()) {
|
|
507
515
|
try {
|
|
@@ -540,12 +548,41 @@ async function mark_implement(directory = process.cwd(), source = process.env) {
|
|
|
540
548
|
}
|
|
541
549
|
var lane_phase = { mark_implement };
|
|
542
550
|
|
|
551
|
+
// scripts/rules/agent-model.ts
|
|
552
|
+
var SUBAGENT_TOOLS = /* @__PURE__ */ new Set(["Agent", "Task"]);
|
|
553
|
+
var GENERAL_PURPOSE = "general-purpose";
|
|
554
|
+
function is_general_purpose(call) {
|
|
555
|
+
if (!SUBAGENT_TOOLS.has(call.name) || !json_value.is_record(call.input)) return false;
|
|
556
|
+
const type = call.input["subagent_type"];
|
|
557
|
+
return type === void 0 || type === GENERAL_PURPOSE;
|
|
558
|
+
}
|
|
559
|
+
function names_model(call) {
|
|
560
|
+
const model = json_value.is_record(call.input) ? call.input["model"] : void 0;
|
|
561
|
+
return typeof model === "string" && model.length > 0;
|
|
562
|
+
}
|
|
563
|
+
function is_unnamed_model(call) {
|
|
564
|
+
return is_general_purpose(call) && !names_model(call);
|
|
565
|
+
}
|
|
566
|
+
function keeps_model(call) {
|
|
567
|
+
return is_general_purpose(call) && names_model(call);
|
|
568
|
+
}
|
|
569
|
+
var AGENT_MODEL_REASON = "\u26D4 agent model: a `general-purpose` subagent with no `model` inherits the parent model. Reissue the call with `model` set \u2014 `sonnet` for routine work, `opus` for judgment such as a review. It fires on every occurrence (`.claude/skills/workflow-commands/delegation.md`).";
|
|
570
|
+
var ROW = {
|
|
571
|
+
id: "agent-model",
|
|
572
|
+
is_trigger: is_unnamed_model,
|
|
573
|
+
reason: AGENT_MODEL_REASON,
|
|
574
|
+
decide: () => true,
|
|
575
|
+
keeps: keeps_model,
|
|
576
|
+
reaches: is_general_purpose
|
|
577
|
+
};
|
|
578
|
+
var agent_model = { AGENT_MODEL_REASON, ROW, is_unnamed_model };
|
|
579
|
+
|
|
543
580
|
// scripts/rules/direct-filing.ts
|
|
544
|
-
var DIRECT_FILING_REASON = '\u26D4 direct filing: an Issue is filed with `pnpm josh issue:file "<title>" --body-file <path> --depth <0|1|2
|
|
581
|
+
var DIRECT_FILING_REASON = '\u26D4 direct filing: an Issue is filed with `pnpm josh issue:file "<title>" --body-file <path> --depth <0|1|2>`, never with `gh api \u2026/issues` or `gh issue create` \u2014 it runs the scout, the lint, the labels and `epic:bundle` itself. It fires on every occurrence (`docs/josh-commands-backlog.md` \u2192 "`josh issue:file`").';
|
|
545
582
|
function is_any_filing(command) {
|
|
546
583
|
return bash_triggers.is_direct_filing(command) || bash_triggers.is_issue_filing(command);
|
|
547
584
|
}
|
|
548
|
-
var
|
|
585
|
+
var ROW2 = {
|
|
549
586
|
id: "direct-filing",
|
|
550
587
|
is_trigger: bash_triggers.on_bash_command(bash_triggers.is_direct_filing),
|
|
551
588
|
reason: DIRECT_FILING_REASON,
|
|
@@ -553,7 +590,7 @@ var ROW = {
|
|
|
553
590
|
keeps: bash_triggers.on_bash_command(bash_triggers.is_issue_filing),
|
|
554
591
|
reaches: bash_triggers.on_bash_command(is_any_filing)
|
|
555
592
|
};
|
|
556
|
-
var direct_filing = { DIRECT_FILING_REASON, ROW };
|
|
593
|
+
var direct_filing = { DIRECT_FILING_REASON, ROW: ROW2 };
|
|
557
594
|
|
|
558
595
|
// scripts/run/progress/run-progress.ts
|
|
559
596
|
var DEFAULT_INTERVAL_MINUTES = 20;
|
|
@@ -890,17 +927,17 @@ function landing_ms(command, now_ms, last_report_ms) {
|
|
|
890
927
|
const lands_ms = now_ms + duration_ms;
|
|
891
928
|
return run_progress.is_due(last_report_ms, lands_ms, interval_ms) ? lands_ms : void 0;
|
|
892
929
|
}
|
|
893
|
-
function decide(call,
|
|
930
|
+
function decide(call, run, can_record) {
|
|
894
931
|
const last_report_ms = run_progress_clock.read_last_report_sync();
|
|
895
932
|
if (last_report_ms === void 0) return false;
|
|
896
|
-
const target = ARM_RECORD.path(
|
|
897
|
-
if (is_armed(target,
|
|
898
|
-
const lands_ms = landing_ms(time_shell.bash_command(call.input),
|
|
933
|
+
const target = ARM_RECORD.path(run.transcript);
|
|
934
|
+
if (is_armed(target, run.now_ms)) return true;
|
|
935
|
+
const lands_ms = landing_ms(time_shell.bash_command(call.input), run.now_ms, last_report_ms);
|
|
899
936
|
if (lands_ms === void 0) return true;
|
|
900
937
|
if (can_record) ARM_RECORD.record(target, lands_ms);
|
|
901
938
|
return false;
|
|
902
939
|
}
|
|
903
|
-
var EARLY_HEARTBEAT_REASON = "\u26D4 early heartbeat: this call arms a wait timer of its own
|
|
940
|
+
var EARLY_HEARTBEAT_REASON = "\u26D4 early heartbeat: this call arms a wait timer of its own. Start `pnpm josh run:progress --wait` once in the background: it reports to the run's event stream on its own \u2014 relay nothing. When asked, `pnpm josh run:progress --once` \u2014 under `backlogrun`, `pnpm josh run:board --chat`; for CI, `pnpm josh followup`. It fires on every occurrence (`.claude/skills/workflow-commands/progress-watcher.md`).";
|
|
904
941
|
var PROGRESS_NAMES = /* @__PURE__ */ new Set(["run:progress"]);
|
|
905
942
|
var WATCH_FLAG = /(?:^|\s)--(?:wait|once)(?=\s|$)/u;
|
|
906
943
|
function is_progress_watch_segment(segment) {
|
|
@@ -998,8 +1035,8 @@ function carries_a_file_body(command, has_file = existsSync) {
|
|
|
998
1035
|
(line) => is_heredoc_write(line, has_file) || has_body_interpreter(line)
|
|
999
1036
|
);
|
|
1000
1037
|
}
|
|
1001
|
-
var FILE_BODY_REASON = "\u26D4 file body in a shell command: this carries a file's new text inline
|
|
1002
|
-
var
|
|
1038
|
+
var FILE_BODY_REASON = "\u26D4 file body in a shell command: this carries a file's new text inline, which is re-read on every later request. Edit a region with the Edit tool, rewrite a whole file with the Write tool, and pass a body by path (`--body-file <path>`); a new-file `cat > <new-file> <<EOF` stays allowed. This rule fires on every occurrence (`prompts/collaboration-workflow/file-edits.md`).";
|
|
1039
|
+
var ROW3 = {
|
|
1003
1040
|
id: "file-body",
|
|
1004
1041
|
is_trigger: bash_triggers.on_bash_command((command) => carries_a_file_body(command)),
|
|
1005
1042
|
reason: FILE_BODY_REASON,
|
|
@@ -1007,7 +1044,7 @@ var ROW2 = {
|
|
|
1007
1044
|
};
|
|
1008
1045
|
var file_body = {
|
|
1009
1046
|
FILE_BODY_REASON,
|
|
1010
|
-
ROW:
|
|
1047
|
+
ROW: ROW3,
|
|
1011
1048
|
carries_a_file_body
|
|
1012
1049
|
};
|
|
1013
1050
|
|
|
@@ -1109,8 +1146,8 @@ function is_destructive_segment(segment) {
|
|
|
1109
1146
|
function is_force_or_delete(command) {
|
|
1110
1147
|
return shell_segments.segments_of(command).some((segment) => is_destructive_segment(segment));
|
|
1111
1148
|
}
|
|
1112
|
-
var GIT_FORCE_REASON = "\u26D4 force push or branch delete: this rewrites or removes shared history, which is Tier C and needs explicit current-turn user instruction
|
|
1113
|
-
var
|
|
1149
|
+
var GIT_FORCE_REASON = "\u26D4 force push or branch delete: this rewrites or removes shared history, which is Tier C and needs explicit current-turn user instruction. Push with `pnpm josh git`; leave a force push or branch delete to the user's own terminal. This rule fires on every occurrence (`prompts/collaboration-workflow/operating-rules.md`).";
|
|
1150
|
+
var ROW4 = {
|
|
1114
1151
|
id: "git-force",
|
|
1115
1152
|
is_trigger: bash_triggers.on_bash_command(is_force_or_delete),
|
|
1116
1153
|
reason: GIT_FORCE_REASON,
|
|
@@ -1118,376 +1155,10 @@ var ROW3 = {
|
|
|
1118
1155
|
};
|
|
1119
1156
|
var git_force = {
|
|
1120
1157
|
GIT_FORCE_REASON,
|
|
1121
|
-
ROW:
|
|
1158
|
+
ROW: ROW4,
|
|
1122
1159
|
is_force_or_delete
|
|
1123
1160
|
};
|
|
1124
1161
|
|
|
1125
|
-
// scripts/cost-runtime/cost-cli.ts
|
|
1126
|
-
import { fileURLToPath } from "node:url";
|
|
1127
|
-
|
|
1128
|
-
// scripts/cost-runtime/codex-usage.ts
|
|
1129
|
-
import { globSync, readFileSync as readFileSync2 } from "node:fs";
|
|
1130
|
-
import path2 from "node:path";
|
|
1131
|
-
import { z as z4 } from "zod";
|
|
1132
|
-
var THREAD_ID_PATTERN = /^[A-Za-z0-9-]+$/u;
|
|
1133
|
-
var SESSION_META_SCHEMA = z4.looseObject({
|
|
1134
|
-
type: z4.literal("session_meta"),
|
|
1135
|
-
payload: z4.looseObject({ id: z4.string(), cwd: z4.string() })
|
|
1136
|
-
});
|
|
1137
|
-
var TOTAL_USAGE_SCHEMA = z4.looseObject({ input_tokens: z4.number().nonnegative() });
|
|
1138
|
-
var TOKEN_COUNT_SCHEMA = z4.looseObject({
|
|
1139
|
-
type: z4.literal("event_msg"),
|
|
1140
|
-
payload: z4.looseObject({
|
|
1141
|
-
type: z4.literal("token_count"),
|
|
1142
|
-
info: z4.looseObject({
|
|
1143
|
-
total_token_usage: TOTAL_USAGE_SCHEMA,
|
|
1144
|
-
last_token_usage: TOTAL_USAGE_SCHEMA
|
|
1145
|
-
})
|
|
1146
|
-
})
|
|
1147
|
-
});
|
|
1148
|
-
function same_project(cwd, target) {
|
|
1149
|
-
return cost_transcript.session_cwd(cwd) === cost_transcript.session_cwd(target);
|
|
1150
|
-
}
|
|
1151
|
-
function billed_per_request(usages) {
|
|
1152
|
-
return usages.map((usage) => usage.last_token_usage.input_tokens);
|
|
1153
|
-
}
|
|
1154
|
-
function measurement_from(content, target, thread_id) {
|
|
1155
|
-
const values = content.split("\n").map((line) => json_value.parse_or_undefined(line));
|
|
1156
|
-
const metadata = values.flatMap((value) => {
|
|
1157
|
-
const parsed = SESSION_META_SCHEMA.safeParse(value);
|
|
1158
|
-
return parsed.success ? [parsed.data] : [];
|
|
1159
|
-
});
|
|
1160
|
-
const usages = values.flatMap((value) => {
|
|
1161
|
-
const parsed = TOKEN_COUNT_SCHEMA.safeParse(value);
|
|
1162
|
-
return parsed.success ? [parsed.data.payload.info] : [];
|
|
1163
|
-
});
|
|
1164
|
-
const session = metadata.find((entry) => entry.payload.id === thread_id);
|
|
1165
|
-
if (session === void 0 || usages.length === 0) return void 0;
|
|
1166
|
-
if (!same_project(session.payload.cwd, target)) return void 0;
|
|
1167
|
-
return { billed_input_per_request: billed_per_request(usages) };
|
|
1168
|
-
}
|
|
1169
|
-
function rollout_files(home, thread_id) {
|
|
1170
|
-
if (!THREAD_ID_PATTERN.test(thread_id)) return [];
|
|
1171
|
-
return globSync(`sessions/**/*${thread_id}.jsonl`, { cwd: home }).map(
|
|
1172
|
-
(file) => path2.join(home, file)
|
|
1173
|
-
);
|
|
1174
|
-
}
|
|
1175
|
-
function read_measurement(file, target, thread_id) {
|
|
1176
|
-
try {
|
|
1177
|
-
return measurement_from(readFileSync2(file, "utf8"), target, thread_id);
|
|
1178
|
-
} catch {
|
|
1179
|
-
return void 0;
|
|
1180
|
-
}
|
|
1181
|
-
}
|
|
1182
|
-
function latest_measurement(files, target, thread_id) {
|
|
1183
|
-
for (const file of files.toReversed()) {
|
|
1184
|
-
const measured = read_measurement(file, target, thread_id);
|
|
1185
|
-
if (measured !== void 0) return measured;
|
|
1186
|
-
}
|
|
1187
|
-
return void 0;
|
|
1188
|
-
}
|
|
1189
|
-
function measurement(target, default_home, environment = process.env) {
|
|
1190
|
-
const thread_id = environment["CODEX_THREAD_ID"];
|
|
1191
|
-
if (thread_id === void 0) return void 0;
|
|
1192
|
-
const home = environment["CODEX_HOME"] ?? path2.join(default_home, ".codex");
|
|
1193
|
-
return latest_measurement(rollout_files(home, thread_id), target, thread_id);
|
|
1194
|
-
}
|
|
1195
|
-
var codex_usage = { measurement };
|
|
1196
|
-
|
|
1197
|
-
// scripts/cost-runtime/cost-corpus.ts
|
|
1198
|
-
function accumulate_missing(sessions) {
|
|
1199
|
-
return {
|
|
1200
|
-
no_usage_lines: sessions.reduce((sum, session) => sum + session.no_usage_lines, 0),
|
|
1201
|
-
malformed_lines: sessions.reduce((sum, session) => sum + session.malformed_lines, 0),
|
|
1202
|
-
unreadable_sessions: sessions.filter((session) => !session.is_readable).length,
|
|
1203
|
-
// Filled by the attribution, which is the only step that knows a unit could not follow its
|
|
1204
|
-
// parent; a per-session tally cannot see it, so it is zero here and set for an issue scope below.
|
|
1205
|
-
unattributed_sessions: 0
|
|
1206
|
-
};
|
|
1207
|
-
}
|
|
1208
|
-
function load_corpus(cwd) {
|
|
1209
|
-
const files = cost_transcript.list_sessions_across(cost_transcript.transcript_directories(cwd));
|
|
1210
|
-
const sessions = files.map((file) => cost_transcript.read_session(file));
|
|
1211
|
-
return { sessions, files, missing: accumulate_missing(sessions) };
|
|
1212
|
-
}
|
|
1213
|
-
function session_meta(corpus) {
|
|
1214
|
-
return new Map(
|
|
1215
|
-
corpus.files.map((file) => [
|
|
1216
|
-
file.session_id,
|
|
1217
|
-
{ is_delegated: file.is_delegated, owner: cost_transcript.owning_session_id(file) }
|
|
1218
|
-
])
|
|
1219
|
-
);
|
|
1220
|
-
}
|
|
1221
|
-
function issue_set(records) {
|
|
1222
|
-
const issues = cost_attribute.group_by_issue(records).map((group) => group.issue).filter((issue) => issue !== cost_attribute.UNATTRIBUTED_KEY);
|
|
1223
|
-
return new Set(issues);
|
|
1224
|
-
}
|
|
1225
|
-
function sole_of(issues) {
|
|
1226
|
-
if (issues.size !== 1) return cost_attribute.UNATTRIBUTED_KEY;
|
|
1227
|
-
return [...issues][0] ?? cost_attribute.UNATTRIBUTED_KEY;
|
|
1228
|
-
}
|
|
1229
|
-
function owner_sets(corpus, meta) {
|
|
1230
|
-
const own = corpus.sessions.filter(
|
|
1231
|
-
(session) => meta.get(session.session_id)?.is_delegated !== true
|
|
1232
|
-
);
|
|
1233
|
-
return new Map(own.map((session) => [session.session_id, issue_set(session.records)]));
|
|
1234
|
-
}
|
|
1235
|
-
function pairs_with_inherited(session, inherited, is_delegated) {
|
|
1236
|
-
return cost_attribute.group_by_issue(session.records).flatMap(
|
|
1237
|
-
(group) => group.records.map((record) => ({
|
|
1238
|
-
record,
|
|
1239
|
-
issue: group.issue === cost_attribute.UNATTRIBUTED_KEY ? inherited : group.issue,
|
|
1240
|
-
baseline_tokens: session.baseline_tokens,
|
|
1241
|
-
session_id: session.session_id,
|
|
1242
|
-
is_delegated
|
|
1243
|
-
}))
|
|
1244
|
-
);
|
|
1245
|
-
}
|
|
1246
|
-
var NO_ISSUES = /* @__PURE__ */ new Set();
|
|
1247
|
-
function parent_issues(session, meta, owners) {
|
|
1248
|
-
const entry = meta.get(session.session_id);
|
|
1249
|
-
if (entry?.is_delegated !== true) return NO_ISSUES;
|
|
1250
|
-
return owners.get(entry.owner) ?? NO_ISSUES;
|
|
1251
|
-
}
|
|
1252
|
-
function pairs_of_session(session, meta, owners) {
|
|
1253
|
-
const is_delegated = meta.get(session.session_id)?.is_delegated === true;
|
|
1254
|
-
const candidates = parent_issues(session, meta, owners);
|
|
1255
|
-
const inherited = is_delegated ? sole_of(candidates) : cost_attribute.UNATTRIBUTED_KEY;
|
|
1256
|
-
const pairs = pairs_with_inherited(session, inherited, is_delegated);
|
|
1257
|
-
const has_unattributed = pairs.some((pair) => pair.issue === cost_attribute.UNATTRIBUTED_KEY);
|
|
1258
|
-
if (!is_delegated || !has_unattributed) return { pairs };
|
|
1259
|
-
return { pairs, unattributed_candidates: candidates };
|
|
1260
|
-
}
|
|
1261
|
-
function attribute_corpus(corpus) {
|
|
1262
|
-
const meta = session_meta(corpus);
|
|
1263
|
-
const owners = owner_sets(corpus, meta);
|
|
1264
|
-
const per_session = corpus.sessions.map((session) => pairs_of_session(session, meta, owners));
|
|
1265
|
-
return {
|
|
1266
|
-
pairs: per_session.flatMap((one) => one.pairs),
|
|
1267
|
-
unattributed: per_session.flatMap(
|
|
1268
|
-
(one) => one.unattributed_candidates === void 0 ? [] : [one.unattributed_candidates]
|
|
1269
|
-
)
|
|
1270
|
-
};
|
|
1271
|
-
}
|
|
1272
|
-
function floor_for_issue(unattributed, issue_number) {
|
|
1273
|
-
return unattributed.filter((set) => set.size === 0 || set.has(issue_number)).length;
|
|
1274
|
-
}
|
|
1275
|
-
function is_better(candidate, existing) {
|
|
1276
|
-
const { UNATTRIBUTED_KEY } = cost_attribute;
|
|
1277
|
-
return existing.issue === UNATTRIBUTED_KEY && candidate.issue !== UNATTRIBUTED_KEY;
|
|
1278
|
-
}
|
|
1279
|
-
function values_of(best) {
|
|
1280
|
-
const collected = [];
|
|
1281
|
-
for (const [, pair] of best) collected.push(pair);
|
|
1282
|
-
return collected;
|
|
1283
|
-
}
|
|
1284
|
-
function dedupe_across_sessions(pairs) {
|
|
1285
|
-
const best = /* @__PURE__ */ new Map();
|
|
1286
|
-
for (const pair of pairs) {
|
|
1287
|
-
const existing = best.get(pair.record.request_id);
|
|
1288
|
-
if (existing === void 0 || is_better(pair, existing)) {
|
|
1289
|
-
best.set(pair.record.request_id, pair);
|
|
1290
|
-
}
|
|
1291
|
-
}
|
|
1292
|
-
return values_of(best);
|
|
1293
|
-
}
|
|
1294
|
-
function attributed(corpus) {
|
|
1295
|
-
return dedupe_across_sessions(attribute_corpus(corpus).pairs);
|
|
1296
|
-
}
|
|
1297
|
-
function mainline_records(pairs) {
|
|
1298
|
-
const groups = /* @__PURE__ */ new Map();
|
|
1299
|
-
for (const pair of pairs) {
|
|
1300
|
-
if (pair.is_delegated) continue;
|
|
1301
|
-
groups.set(pair.session_id, [...groups.get(pair.session_id) ?? [], pair.record]);
|
|
1302
|
-
}
|
|
1303
|
-
return [...groups.values()];
|
|
1304
|
-
}
|
|
1305
|
-
var cost_corpus = {
|
|
1306
|
-
load_corpus,
|
|
1307
|
-
attribute_corpus,
|
|
1308
|
-
floor_for_issue,
|
|
1309
|
-
attributed,
|
|
1310
|
-
mainline_records
|
|
1311
|
-
};
|
|
1312
|
-
|
|
1313
|
-
// scripts/cost-runtime/cost-verdict.ts
|
|
1314
|
-
var FAILURE_EXIT_CODE = 1;
|
|
1315
|
-
var OVER_VERDICT = "over";
|
|
1316
|
-
var UNDER_VERDICT = "under";
|
|
1317
|
-
function per_request_cost(measurement2) {
|
|
1318
|
-
return measurement2.billed_input_per_request.at(-1) ?? 0;
|
|
1319
|
-
}
|
|
1320
|
-
function classify(measurement2, limit) {
|
|
1321
|
-
return per_request_cost(measurement2) > limit ? OVER_VERDICT : UNDER_VERDICT;
|
|
1322
|
-
}
|
|
1323
|
-
function over_summary(measurement2, limit) {
|
|
1324
|
-
const total = measurement2.billed_input_per_request.length;
|
|
1325
|
-
return `${String(per_request_cost(measurement2))} billed input tokens per request, on the newest of ${String(total)} request(s); limit ${String(limit)}`;
|
|
1326
|
-
}
|
|
1327
|
-
function report_over(measurement2, limit) {
|
|
1328
|
-
if (measurement2 === void 0 || measurement2.billed_input_per_request.length === 0) {
|
|
1329
|
-
console.error("No requests in this session; there is nothing to hand off.");
|
|
1330
|
-
return FAILURE_EXIT_CODE;
|
|
1331
|
-
}
|
|
1332
|
-
console.info(classify(measurement2, limit));
|
|
1333
|
-
console.error(over_summary(measurement2, limit));
|
|
1334
|
-
return 0;
|
|
1335
|
-
}
|
|
1336
|
-
var cost_verdict = {
|
|
1337
|
-
OVER_VERDICT,
|
|
1338
|
-
UNDER_VERDICT,
|
|
1339
|
-
classify,
|
|
1340
|
-
per_request_cost,
|
|
1341
|
-
report_over
|
|
1342
|
-
};
|
|
1343
|
-
|
|
1344
|
-
// scripts/cost-runtime/transcript-cwd.ts
|
|
1345
|
-
import path3 from "node:path";
|
|
1346
|
-
function resolve(target, cwd) {
|
|
1347
|
-
return target === void 0 ? cwd : path3.resolve(target);
|
|
1348
|
-
}
|
|
1349
|
-
var transcript_cwd = { resolve };
|
|
1350
|
-
|
|
1351
|
-
// scripts/cost-runtime/cost-cli.ts
|
|
1352
|
-
var ARGV_OFFSET = 2;
|
|
1353
|
-
var FAILURE_EXIT_CODE2 = 1;
|
|
1354
|
-
var USAGE = "Usage: josh cost (--cut | --over <tokens-per-request>) [--path <dir>]";
|
|
1355
|
-
var UNMEASURABLE_VERDICT = "unmeasurable";
|
|
1356
|
-
function to_threshold(raw) {
|
|
1357
|
-
if (raw === void 0) return void 0;
|
|
1358
|
-
if (raw.trim() === "") return void 0;
|
|
1359
|
-
const parsed = Number(raw);
|
|
1360
|
-
return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : void 0;
|
|
1361
|
-
}
|
|
1362
|
-
function is_unparsed(raw, parsed) {
|
|
1363
|
-
return parsed === void 0 && raw !== void 0;
|
|
1364
|
-
}
|
|
1365
|
-
function selected_threshold(values) {
|
|
1366
|
-
if (values.cut === true) return CONTEXT_CUT_THRESHOLD;
|
|
1367
|
-
return to_threshold(values.over);
|
|
1368
|
-
}
|
|
1369
|
-
function threshold_option(over) {
|
|
1370
|
-
return over === void 0 ? {} : { over };
|
|
1371
|
-
}
|
|
1372
|
-
function path_option(path16) {
|
|
1373
|
-
return path16 === void 0 ? {} : { path: path16 };
|
|
1374
|
-
}
|
|
1375
|
-
function to_options(values) {
|
|
1376
|
-
if (values.cut === true && values.over !== void 0) return void 0;
|
|
1377
|
-
const over = selected_threshold(values);
|
|
1378
|
-
if (is_unparsed(values.over, over)) return void 0;
|
|
1379
|
-
return { ...threshold_option(over), ...path_option(values.path) };
|
|
1380
|
-
}
|
|
1381
|
-
var PARSE_ARGS_OPTIONS = {
|
|
1382
|
-
cut: { type: "boolean" },
|
|
1383
|
-
over: { type: "string" },
|
|
1384
|
-
path: { type: "string" }
|
|
1385
|
-
};
|
|
1386
|
-
function parse_options(argv) {
|
|
1387
|
-
const values = cli_flags.values_of(argv, PARSE_ARGS_OPTIONS);
|
|
1388
|
-
return values === void 0 ? void 0 : to_options(values);
|
|
1389
|
-
}
|
|
1390
|
-
function report_empty(cwd, session_id) {
|
|
1391
|
-
const searched = cost_transcript.searched_directories(cost_transcript.transcript_directories(cwd));
|
|
1392
|
-
for (const line of cost_transcript.missing_message(searched, session_id)) console.error(line);
|
|
1393
|
-
return FAILURE_EXIT_CODE2;
|
|
1394
|
-
}
|
|
1395
|
-
function provider_of(environment) {
|
|
1396
|
-
const resolved = agent_role_profile.resolve_provider(environment);
|
|
1397
|
-
if (resolved.kind !== "provider" || resolved.is_default === true) return void 0;
|
|
1398
|
-
return resolved.provider;
|
|
1399
|
-
}
|
|
1400
|
-
function measurement_of(session) {
|
|
1401
|
-
return {
|
|
1402
|
-
billed_input_per_request: session.records.map(
|
|
1403
|
-
(record) => cost_usage.billed_input(record.totals)
|
|
1404
|
-
)
|
|
1405
|
-
};
|
|
1406
|
-
}
|
|
1407
|
-
function anthropic_own(target, environment) {
|
|
1408
|
-
const corpus = cost_corpus.load_corpus(target);
|
|
1409
|
-
const selection = own_session.select_own_session(corpus.files, environment);
|
|
1410
|
-
if (selection.kind === "absent") return { kind: "absent", session_id: selection.session_id };
|
|
1411
|
-
const session = corpus.sessions[selection.index];
|
|
1412
|
-
if (session === void 0) return { kind: "empty" };
|
|
1413
|
-
return { kind: "measured", measurement: measurement_of(session) };
|
|
1414
|
-
}
|
|
1415
|
-
function anthropic_measurement(target, environment) {
|
|
1416
|
-
const own = anthropic_own(target, environment);
|
|
1417
|
-
return own.kind === "measured" ? own.measurement : void 0;
|
|
1418
|
-
}
|
|
1419
|
-
function same_openai_project(target, cwd) {
|
|
1420
|
-
return cost_transcript.session_cwd(target) === cost_transcript.session_cwd(cwd);
|
|
1421
|
-
}
|
|
1422
|
-
function reject_openai_cross_project(context, target, cwd) {
|
|
1423
|
-
if (context.provider !== "openai" || context.path === void 0 || same_openai_project(target, cwd)) {
|
|
1424
|
-
return false;
|
|
1425
|
-
}
|
|
1426
|
-
console.error(
|
|
1427
|
-
"OpenAI --path cannot select a thread from another project; run josh cost in that project."
|
|
1428
|
-
);
|
|
1429
|
-
return true;
|
|
1430
|
-
}
|
|
1431
|
-
function measure(target, provider, environment) {
|
|
1432
|
-
return provider === "openai" ? codex_usage.measurement(target, cost_transcript.home_directory(), environment) : anthropic_measurement(target, environment);
|
|
1433
|
-
}
|
|
1434
|
-
function run_over_anthropic(own, target, limit) {
|
|
1435
|
-
if (own.kind === "measured") return cost_verdict.report_over(own.measurement, limit);
|
|
1436
|
-
return report_empty(target, own.kind === "absent" ? own.session_id : void 0);
|
|
1437
|
-
}
|
|
1438
|
-
function run_over_codex(target, limit, environment) {
|
|
1439
|
-
const measurement2 = measure(target, "openai", environment);
|
|
1440
|
-
if (measurement2 !== void 0) return cost_verdict.report_over(measurement2, limit);
|
|
1441
|
-
console.error(`No Codex usage found for the current OpenAI thread under ${target}.`);
|
|
1442
|
-
return FAILURE_EXIT_CODE2;
|
|
1443
|
-
}
|
|
1444
|
-
function run_over(target, limit, provider, environment) {
|
|
1445
|
-
if (provider === "anthropic") {
|
|
1446
|
-
return run_over_anthropic(anthropic_own(target, environment), target, limit);
|
|
1447
|
-
}
|
|
1448
|
-
return run_over_codex(target, limit, environment);
|
|
1449
|
-
}
|
|
1450
|
-
function verdict_of(measurement2) {
|
|
1451
|
-
if (measurement2 === void 0 || measurement2.billed_input_per_request.length === 0) {
|
|
1452
|
-
return UNMEASURABLE_VERDICT;
|
|
1453
|
-
}
|
|
1454
|
-
return cost_verdict.classify(measurement2, CONTEXT_CUT_THRESHOLD);
|
|
1455
|
-
}
|
|
1456
|
-
function session_verdict(cwd = process.cwd(), environment = process.env) {
|
|
1457
|
-
const provider = provider_of(environment);
|
|
1458
|
-
if (provider === void 0) return UNMEASURABLE_VERDICT;
|
|
1459
|
-
return verdict_of(measure(cwd, provider, environment));
|
|
1460
|
-
}
|
|
1461
|
-
function run_context(argv, environment) {
|
|
1462
|
-
const options = parse_options(argv);
|
|
1463
|
-
if (options?.over === void 0) return void 0;
|
|
1464
|
-
const provider = provider_of(environment);
|
|
1465
|
-
if (provider === void 0) return void 0;
|
|
1466
|
-
return { over: options.over, path: options.path, provider };
|
|
1467
|
-
}
|
|
1468
|
-
function run(argv, cwd = process.cwd(), environment = process.env) {
|
|
1469
|
-
const context = run_context(argv, environment);
|
|
1470
|
-
if (context === void 0) {
|
|
1471
|
-
console.error(USAGE);
|
|
1472
|
-
return FAILURE_EXIT_CODE2;
|
|
1473
|
-
}
|
|
1474
|
-
const target = transcript_cwd.resolve(context.path, cwd);
|
|
1475
|
-
if (reject_openai_cross_project(context, target, cwd)) return FAILURE_EXIT_CODE2;
|
|
1476
|
-
return run_over(target, context.over, context.provider, environment);
|
|
1477
|
-
}
|
|
1478
|
-
function main(argv) {
|
|
1479
|
-
process.exitCode = run(argv);
|
|
1480
|
-
}
|
|
1481
|
-
var cost_cli = {
|
|
1482
|
-
UNMEASURABLE_VERDICT,
|
|
1483
|
-
USAGE,
|
|
1484
|
-
parse_options,
|
|
1485
|
-
to_threshold,
|
|
1486
|
-
run,
|
|
1487
|
-
session_verdict
|
|
1488
|
-
};
|
|
1489
|
-
if (process.argv[1] === fileURLToPath(import.meta.url)) main(process.argv.slice(ARGV_OFFSET));
|
|
1490
|
-
|
|
1491
1162
|
// scripts/cost-runtime/cost-format.ts
|
|
1492
1163
|
var USD_DECIMALS = 4;
|
|
1493
1164
|
var PERCENT_SCALE = 100;
|
|
@@ -1508,6 +1179,69 @@ var cost_format = {
|
|
|
1508
1179
|
format_share
|
|
1509
1180
|
};
|
|
1510
1181
|
|
|
1182
|
+
// scripts/run/cut/run-cut-decline.ts
|
|
1183
|
+
import { z as z4 } from "zod";
|
|
1184
|
+
var DECLINE_PREFIX = "josh-run-cut-decline-";
|
|
1185
|
+
var decline_schema = z4.object({ issue: z4.string(), hold_taken_at: z4.string().optional() });
|
|
1186
|
+
function decline_path(git_directory) {
|
|
1187
|
+
return stamp_file.stamp_path(DECLINE_PREFIX, git_directory);
|
|
1188
|
+
}
|
|
1189
|
+
function record(git_directory, decline) {
|
|
1190
|
+
stamp_file.replace_stamp(decline_path(git_directory), decline);
|
|
1191
|
+
}
|
|
1192
|
+
function read(git_directory) {
|
|
1193
|
+
const raw = stamp_file.read_stamp_text(decline_path(git_directory));
|
|
1194
|
+
return raw === void 0 ? void 0 : json_value.parse_with(raw, decline_schema);
|
|
1195
|
+
}
|
|
1196
|
+
function matches(recorded, current) {
|
|
1197
|
+
return recorded?.issue === current.issue && recorded.hold_taken_at === current.hold_taken_at;
|
|
1198
|
+
}
|
|
1199
|
+
function is_declined_sync(issue, directory = run_cut.worktree_git_directory_sync()) {
|
|
1200
|
+
if (directory === void 0) return false;
|
|
1201
|
+
const hold_taken_at = run_cut.hold_of(directory)?.taken_at;
|
|
1202
|
+
return matches(read(directory), { issue, hold_taken_at });
|
|
1203
|
+
}
|
|
1204
|
+
async function declined(request2, state, code) {
|
|
1205
|
+
if (request2.phase !== run_cut.IMPLEMENTATION_PHASE) return code;
|
|
1206
|
+
const directory = await run_cut.worktree_directory();
|
|
1207
|
+
if (directory !== void 0) {
|
|
1208
|
+
record(directory, { issue: request2.issue, hold_taken_at: state.hold_taken_at });
|
|
1209
|
+
}
|
|
1210
|
+
return code;
|
|
1211
|
+
}
|
|
1212
|
+
var run_cut_decline = { decline_path, declined, is_declined_sync, read, record };
|
|
1213
|
+
|
|
1214
|
+
// scripts/run/cut/run-cut-ready.ts
|
|
1215
|
+
function is_ready(tree) {
|
|
1216
|
+
return tree.branch !== tree.default_branch && tree.is_dirty;
|
|
1217
|
+
}
|
|
1218
|
+
async function is_lane_branch(state) {
|
|
1219
|
+
const default_branch = await git_command.get_default_branch();
|
|
1220
|
+
return is_ready({ branch: state.branch, default_branch, is_dirty: state.is_dirty });
|
|
1221
|
+
}
|
|
1222
|
+
var STATUS_ARGUMENTS = ["status", "--porcelain=v2", "--branch", UNTRACKED_FILES_FLAG];
|
|
1223
|
+
var HEADER_PREFIX = "#";
|
|
1224
|
+
var BRANCH_HEADER = "# branch.head ";
|
|
1225
|
+
function tree_of(status, default_branch) {
|
|
1226
|
+
const lines = status.split("\n").filter((line) => line !== "");
|
|
1227
|
+
const header = lines.find((line) => line.startsWith(BRANCH_HEADER));
|
|
1228
|
+
if (header === void 0) return void 0;
|
|
1229
|
+
const branch = header.slice(BRANCH_HEADER.length);
|
|
1230
|
+
const is_dirty = lines.some((line) => !line.startsWith(HEADER_PREFIX));
|
|
1231
|
+
return { branch, default_branch, is_dirty };
|
|
1232
|
+
}
|
|
1233
|
+
function read_tree_sync() {
|
|
1234
|
+
const status = git_spawn_sync.read(STATUS_ARGUMENTS);
|
|
1235
|
+
if (status === void 0) return void 0;
|
|
1236
|
+
const reference = git_spawn_sync.read(git_diff_reads.DEFAULT_BRANCH_ARGUMENTS);
|
|
1237
|
+
return tree_of(status, git_diff_reads.default_branch_of(reference));
|
|
1238
|
+
}
|
|
1239
|
+
function is_ready_sync(read2 = read_tree_sync) {
|
|
1240
|
+
const tree = read2();
|
|
1241
|
+
return tree === void 0 || is_ready(tree);
|
|
1242
|
+
}
|
|
1243
|
+
var run_cut_ready = { is_lane_branch, is_ready, is_ready_sync, tree_of };
|
|
1244
|
+
|
|
1511
1245
|
// scripts/rules/implementation-cut-verdict.ts
|
|
1512
1246
|
import { z as z5 } from "zod";
|
|
1513
1247
|
var VERDICT_CACHE_PREFIX = "josh-impl-cut-verdict-";
|
|
@@ -1555,6 +1289,9 @@ function is_impl_cut_segment(segment) {
|
|
|
1555
1289
|
function takes_the_impl_cut(command) {
|
|
1556
1290
|
return shell_segments.segments_of(command).some((segment) => is_impl_cut_segment(segment));
|
|
1557
1291
|
}
|
|
1292
|
+
function can_cut_sync(issue) {
|
|
1293
|
+
return !run_cut_decline.is_declined_sync(issue) && run_cut_ready.is_ready_sync();
|
|
1294
|
+
}
|
|
1558
1295
|
function current_state() {
|
|
1559
1296
|
return {
|
|
1560
1297
|
directory: process.cwd(),
|
|
@@ -1564,7 +1301,8 @@ function current_state() {
|
|
|
1564
1301
|
// **Read through the short reuse window**. The row now fires per
|
|
1565
1302
|
// threshold crossing rather than once per run, so this predicate is a candidate on every edit;
|
|
1566
1303
|
// the window collapses one turn's burst of edits to a single whole-transcript price.
|
|
1567
|
-
verdict: () => implementation_cut_verdict.reused_verdict(() => cost_cli.session_verdict())
|
|
1304
|
+
verdict: () => implementation_cut_verdict.reused_verdict(() => cost_cli.session_verdict()),
|
|
1305
|
+
can_cut: can_cut_sync
|
|
1568
1306
|
};
|
|
1569
1307
|
}
|
|
1570
1308
|
function lane_child_issue(state) {
|
|
@@ -1590,29 +1328,36 @@ function warrants_the_cut(state) {
|
|
|
1590
1328
|
return verdict !== cost_verdict.UNDER_VERDICT;
|
|
1591
1329
|
}
|
|
1592
1330
|
function is_over_threshold_edit(call, state = current_state()) {
|
|
1593
|
-
if (!is_edit_tool(call.name)
|
|
1594
|
-
|
|
1331
|
+
if (!is_edit_tool(call.name)) return false;
|
|
1332
|
+
const issue = uncut_run_issue(state);
|
|
1333
|
+
if (issue === void 0) return false;
|
|
1334
|
+
return warrants_the_cut(state) && state.can_cut(issue);
|
|
1595
1335
|
}
|
|
1596
1336
|
var THRESHOLD_TEXT = `${cost_format.format_tokens(CONTEXT_CUT_THRESHOLD)}-token`;
|
|
1597
|
-
var IMPLEMENTATION_CUT_REASON = `\u26D4 implementation-phase cut:
|
|
1337
|
+
var IMPLEMENTATION_CUT_REASON = `\u26D4 implementation-phase cut: refused on every edit past the ${THRESHOLD_TEXT} line. Write \`${run_cut_handoff.HANDOFF_PATH}\` as ${run_cut_handoff.HANDOFF_FORMAT}, run \`pnpm josh run:cut --impl <N> --handoff <path>\`; \`cut\`: end the turn immediately, no Telegram is owed; else reissue the edit (\`.claude/skills/workflow-commands/pre-gate-cut.md\`).`;
|
|
1598
1338
|
var REISSUE_WINDOW_MS = 9e4;
|
|
1599
1339
|
function is_reissued_refusal(now_ms, delivered_at_ms) {
|
|
1600
1340
|
return now_ms - delivered_at_ms < REISSUE_WINDOW_MS;
|
|
1601
1341
|
}
|
|
1602
|
-
function decide2(_call,
|
|
1603
|
-
return !is_reissued_refusal(
|
|
1342
|
+
function decide2(_call, run, _can_record, delivered_at_ms) {
|
|
1343
|
+
return !is_reissued_refusal(run.now_ms, delivered_at_ms);
|
|
1604
1344
|
}
|
|
1605
|
-
var
|
|
1345
|
+
var ROW5 = {
|
|
1606
1346
|
id: "implementation-cut",
|
|
1607
1347
|
is_trigger: is_over_threshold_edit,
|
|
1608
1348
|
reason: IMPLEMENTATION_CUT_REASON,
|
|
1609
1349
|
decide: decide2,
|
|
1610
|
-
keeps: bash_triggers.on_bash_command(takes_the_impl_cut)
|
|
1350
|
+
keeps: bash_triggers.on_bash_command(takes_the_impl_cut),
|
|
1351
|
+
// The opening the reason carried before it was cut to the action and the next command.
|
|
1352
|
+
former_reasons: [
|
|
1353
|
+
"\u26D4 implementation-phase cut: this checkout is a lane dispatched",
|
|
1354
|
+
"\u26D4 implementation-phase cut: this run's context crossed the"
|
|
1355
|
+
]
|
|
1611
1356
|
};
|
|
1612
1357
|
var implementation_cut = {
|
|
1613
1358
|
IMPLEMENTATION_CUT_REASON,
|
|
1614
1359
|
REISSUE_WINDOW_MS,
|
|
1615
|
-
ROW:
|
|
1360
|
+
ROW: ROW5,
|
|
1616
1361
|
decide: decide2,
|
|
1617
1362
|
is_over_threshold_edit,
|
|
1618
1363
|
is_reissued_refusal,
|
|
@@ -1665,10 +1410,10 @@ var gh_api = {
|
|
|
1665
1410
|
// scripts/rules/prior-comment-read.ts
|
|
1666
1411
|
var ISSUE_PATH_NUMBER = /issues\/(\d+)/gu;
|
|
1667
1412
|
var ISSUE_VIEW_NUMBER = /\bissue\s+view\s+(?:-{1,2}\S+\s+)*(\d+)/u;
|
|
1668
|
-
var ISSUE_READ_ARGUMENTS = /\
|
|
1413
|
+
var ISSUE_READ_ARGUMENTS = /\b(?:issue:read|run:entry|run:prep)\b([\s\d]*)/u;
|
|
1669
1414
|
var COMMENTS_ENDPOINT = /issues\/\d+\/comments\b/u;
|
|
1670
1415
|
var VIEW_WITH_COMMENTS = /\bissue\s+view\b[^\n]*--comments\b/u;
|
|
1671
|
-
var ISSUE_READ_COMMAND = /\
|
|
1416
|
+
var ISSUE_READ_COMMAND = /\b(?:issue:read|run:entry|run:prep)\b/u;
|
|
1672
1417
|
function add_issue_read_numbers(command, numbers) {
|
|
1673
1418
|
const match = ISSUE_READ_ARGUMENTS.exec(command);
|
|
1674
1419
|
if (match === null) return;
|
|
@@ -1739,19 +1484,48 @@ function is_body_only_issue_read(command) {
|
|
|
1739
1484
|
function reads_issue_comments(command) {
|
|
1740
1485
|
return shell_segments.segments_of(command).some((segment) => fetches_issue_comments(segment));
|
|
1741
1486
|
}
|
|
1742
|
-
var
|
|
1743
|
-
var
|
|
1487
|
+
var RULE_DOC = "`.claude/skills/workflow-commands/issue-comments.md`";
|
|
1488
|
+
var COMMENTS_FALLBACK = "gh api repos/{owner}/{repo}/issues/<N>/comments";
|
|
1489
|
+
var ISSUE_COMMENTS_REASON = `\u26D4 issue comments: pnpm josh issue:read <N>
|
|
1490
|
+
Run that in place of this read \u2014 an Issue's comments are part of it, and a later comment supersedes the body it contradicts; refused until that command is on the transcript. Without josh, read \`${COMMENTS_FALLBACK}\` beside the body (${RULE_DOC}).`;
|
|
1491
|
+
var COMMENTS_JQ = String.raw`'.[] | "— \(.user.login) \(.created_at)\n\(.body)\n"'`;
|
|
1492
|
+
var COMMENTS_NOTE = `\u21BB issue comments: this read returned only the Issue's body, so the Issue's comments were fetched on the same line \u2014 a later comment supersedes the body it contradicts (${RULE_DOC}).`;
|
|
1493
|
+
function rewritable_path(command) {
|
|
1494
|
+
const read2 = shell_segments.first_of(command);
|
|
1495
|
+
if (read2 === void 0 || ISSUE_VIEW_COMMAND.test(read2)) return void 0;
|
|
1496
|
+
return is_body_read_segment(read2) ? ISSUE_BODY_PATH.exec(read2)?.[0] : void 0;
|
|
1497
|
+
}
|
|
1498
|
+
function comments_command(command) {
|
|
1499
|
+
if (!is_body_only_issue_read(command)) return void 0;
|
|
1500
|
+
const path13 = rewritable_path(command);
|
|
1501
|
+
if (path13 === void 0) return void 0;
|
|
1502
|
+
return `gh api --paginate ${path13}/comments --jq ${COMMENTS_JQ}
|
|
1503
|
+
${command}`;
|
|
1504
|
+
}
|
|
1505
|
+
function comments_input(call, tail) {
|
|
1506
|
+
if (call.name !== cost_blocks.BASH_TOOL || !json_value.is_record(call.input)) return void 0;
|
|
1507
|
+
const command = comments_command(time_shell.bash_command(call.input));
|
|
1508
|
+
if (command === void 0 || prior_comment_read.already_read_for_call(tail(), call)) {
|
|
1509
|
+
return void 0;
|
|
1510
|
+
}
|
|
1511
|
+
return { ...call.input, command };
|
|
1512
|
+
}
|
|
1513
|
+
var ROW6 = {
|
|
1744
1514
|
id: "issue-comments",
|
|
1745
1515
|
is_trigger: bash_triggers.on_bash_command(is_body_only_issue_read),
|
|
1746
1516
|
reason: ISSUE_COMMENTS_REASON,
|
|
1747
1517
|
already_satisfied: prior_comment_read.already_read_for_call,
|
|
1748
1518
|
keeps: bash_triggers.on_bash_command(reads_issue_comments),
|
|
1519
|
+
rewrite: comments_input,
|
|
1520
|
+
rewrite_note: COMMENTS_NOTE,
|
|
1749
1521
|
// The opening the reason carried before it led with the command.
|
|
1750
1522
|
former_reasons: ["\u26D4 an Issue's comments are part of the Issue: read them before implementing"]
|
|
1751
1523
|
};
|
|
1752
1524
|
var issue_comments = {
|
|
1525
|
+
COMMENTS_NOTE,
|
|
1753
1526
|
ISSUE_COMMENTS_REASON,
|
|
1754
|
-
ROW:
|
|
1527
|
+
ROW: ROW6,
|
|
1528
|
+
comments_input,
|
|
1755
1529
|
is_body_only_issue_read
|
|
1756
1530
|
};
|
|
1757
1531
|
|
|
@@ -1768,8 +1542,8 @@ function is_bare_segment(segment) {
|
|
|
1768
1542
|
function is_bare_josh_git(command) {
|
|
1769
1543
|
return shell_segments.segments_of(command).some((segment) => is_bare_segment(segment));
|
|
1770
1544
|
}
|
|
1771
|
-
var JOSH_GIT_BARE_REASON = '\u26D4 bare `pnpm josh git`: this prompts to confirm the staging, and with no TTY the prompt falls to its cancel branch
|
|
1772
|
-
var
|
|
1545
|
+
var JOSH_GIT_BARE_REASON = '\u26D4 bare `pnpm josh git`: this prompts to confirm the staging, and with no TTY the prompt falls to its cancel branch. Run `pnpm josh git -y "<title> #<N>"`, or `pnpm josh git -y --skip-commit --skip-push` to open the PR for a push that already landed. It fires on every occurrence.';
|
|
1546
|
+
var ROW7 = {
|
|
1773
1547
|
id: "josh-git-bare",
|
|
1774
1548
|
is_trigger: bash_triggers.on_bash_command(is_bare_josh_git),
|
|
1775
1549
|
reason: JOSH_GIT_BARE_REASON,
|
|
@@ -1777,7 +1551,7 @@ var ROW6 = {
|
|
|
1777
1551
|
};
|
|
1778
1552
|
var josh_git_bare = {
|
|
1779
1553
|
JOSH_GIT_BARE_REASON,
|
|
1780
|
-
ROW:
|
|
1554
|
+
ROW: ROW7,
|
|
1781
1555
|
is_bare_josh_git
|
|
1782
1556
|
};
|
|
1783
1557
|
|
|
@@ -1801,8 +1575,8 @@ function is_carry_conflict(command, is_lane_child = lane_child_marker.is_child_o
|
|
|
1801
1575
|
if (!invokes_budget_command(command)) return false;
|
|
1802
1576
|
return is_lane_child;
|
|
1803
1577
|
}
|
|
1804
|
-
var LANE_CARRY_CONFLICT_REASON =
|
|
1805
|
-
var
|
|
1578
|
+
var LANE_CARRY_CONFLICT_REASON = "\u26D4 lane child carry conflict: this session is a dispatched lane child, and `run:merge` / `run:carry` are the parent budget commands; the live record belongs to the parent, not to a competing run. Continue implementing this Issue: no `needs-decision`, no Telegram. Live `run:carry` evidence takes a fresh `JOSH_TEMP_ROOT`; `run:merge` is refused under any root, on every occurrence.";
|
|
1579
|
+
var ROW8 = {
|
|
1806
1580
|
id: "lane-carry-conflict",
|
|
1807
1581
|
is_trigger: bash_triggers.on_bash_command(is_carry_conflict),
|
|
1808
1582
|
reason: LANE_CARRY_CONFLICT_REASON,
|
|
@@ -1810,66 +1584,24 @@ var ROW7 = {
|
|
|
1810
1584
|
};
|
|
1811
1585
|
var lane_carry_conflict = {
|
|
1812
1586
|
LANE_CARRY_CONFLICT_REASON,
|
|
1813
|
-
ROW:
|
|
1587
|
+
ROW: ROW8,
|
|
1814
1588
|
invokes_budget_command,
|
|
1815
1589
|
is_carry_conflict
|
|
1816
1590
|
};
|
|
1817
1591
|
|
|
1818
|
-
// scripts/agent/interactive-ask.ts
|
|
1819
|
-
import { z as z6 } from "zod";
|
|
1820
|
-
var INTERACTIVE_TOOLS = /* @__PURE__ */ new Set(["AskUserQuestion"]);
|
|
1821
|
-
function is_interactive_tool(name) {
|
|
1822
|
-
return INTERACTIVE_TOOLS.has(name);
|
|
1823
|
-
}
|
|
1824
|
-
var OPTION_SCHEMA = z6.looseObject({ label: z6.string().optional() });
|
|
1825
|
-
var QUESTION_SCHEMA = z6.looseObject({
|
|
1826
|
-
question: z6.string().optional(),
|
|
1827
|
-
options: z6.array(OPTION_SCHEMA).optional()
|
|
1828
|
-
});
|
|
1829
|
-
var ASK_INPUT_SCHEMA = z6.looseObject({ questions: z6.array(QUESTION_SCHEMA).optional() });
|
|
1830
|
-
var DENIAL_SCHEMA = z6.looseObject({
|
|
1831
|
-
tool_name: z6.string().optional(),
|
|
1832
|
-
tool_input: z6.unknown().optional()
|
|
1833
|
-
});
|
|
1834
|
-
var UNKNOWN_QUESTION = "(question text unavailable)";
|
|
1835
|
-
var OPTION_SEPARATOR = " / ";
|
|
1836
|
-
var QUESTION_SEPARATOR = "; ";
|
|
1837
|
-
function labels_of(question) {
|
|
1838
|
-
return (question.options ?? []).map((option) => option.label ?? "").filter((label) => label !== "");
|
|
1839
|
-
}
|
|
1840
|
-
function render_question(question) {
|
|
1841
|
-
const labels = labels_of(question);
|
|
1842
|
-
const text = question.question ?? UNKNOWN_QUESTION;
|
|
1843
|
-
return labels.length === 0 ? text : `${text} [${labels.join(OPTION_SEPARATOR)}]`;
|
|
1844
|
-
}
|
|
1845
|
-
function interactive_input(raw) {
|
|
1846
|
-
const denial = DENIAL_SCHEMA.safeParse(raw);
|
|
1847
|
-
if (!denial.success || !is_interactive_tool(denial.data.tool_name ?? "")) return void 0;
|
|
1848
|
-
const input = ASK_INPUT_SCHEMA.safeParse(denial.data.tool_input);
|
|
1849
|
-
return input.success ? input.data : void 0;
|
|
1850
|
-
}
|
|
1851
|
-
function refused_ask_of(permission_denials) {
|
|
1852
|
-
if (!Array.isArray(permission_denials)) return void 0;
|
|
1853
|
-
const input = permission_denials.map((raw) => interactive_input(raw)).find((one) => one !== void 0);
|
|
1854
|
-
const questions = input?.questions ?? [];
|
|
1855
|
-
if (questions.length === 0) return void 0;
|
|
1856
|
-
return questions.map((question) => render_question(question)).join(QUESTION_SEPARATOR);
|
|
1857
|
-
}
|
|
1858
|
-
var interactive_ask = { is_interactive_tool, refused_ask_of };
|
|
1859
|
-
|
|
1860
1592
|
// scripts/rules/lane-interactive-ask.ts
|
|
1861
1593
|
function is_interactive_ask(call, is_lane_child = lane_child_marker.is_child_of(process.cwd())) {
|
|
1862
1594
|
if (!interactive_ask.is_interactive_tool(call.name)) return false;
|
|
1863
1595
|
return is_lane_child;
|
|
1864
1596
|
}
|
|
1865
|
-
var LANE_INTERACTIVE_ASK_REASON =
|
|
1866
|
-
var
|
|
1597
|
+
var LANE_INTERACTIVE_ASK_REASON = "\u26D4 lane child interactive ask: this session is a dispatched lane child and cannot ask a person, so park instead: `gh api repos/{owner}/{repo}/issues/<N>/labels -f 'labels[]=needs-decision'`, `pnpm josh issue:comment <N> --body-file <path>`, the `confirmation` Telegram, stop. It fires on every occurrence (`.claude/skills/workflow-commands/pre-gate-cut.md`, `backlogrun-park.md`).";
|
|
1598
|
+
var ROW9 = {
|
|
1867
1599
|
id: "lane-interactive-ask",
|
|
1868
1600
|
is_trigger: is_interactive_ask,
|
|
1869
1601
|
reason: LANE_INTERACTIVE_ASK_REASON,
|
|
1870
1602
|
decide: () => true
|
|
1871
1603
|
};
|
|
1872
|
-
var lane_interactive_ask = { LANE_INTERACTIVE_ASK_REASON, ROW:
|
|
1604
|
+
var lane_interactive_ask = { LANE_INTERACTIVE_ASK_REASON, ROW: ROW9, is_interactive_ask };
|
|
1873
1605
|
|
|
1874
1606
|
// scripts/rules/lane-split-park.ts
|
|
1875
1607
|
var EPIC_COMMANDS = /* @__PURE__ */ new Set(["epic"]);
|
|
@@ -1913,13 +1645,13 @@ function is_candidate(command) {
|
|
|
1913
1645
|
if (!is_park_of(command, issue) && !is_notify_of(command, issue)) return false;
|
|
1914
1646
|
return lane_child_marker.is_child_of(process.cwd());
|
|
1915
1647
|
}
|
|
1916
|
-
function decide3(_call,
|
|
1648
|
+
function decide3(_call, run) {
|
|
1917
1649
|
const issue = lane_child_marker.marked_issue();
|
|
1918
|
-
const commands = tail_commands.prior_bash_commands(time_density_hook.read_tail(
|
|
1650
|
+
const commands = tail_commands.prior_bash_commands(time_density_hook.read_tail(run.transcript));
|
|
1919
1651
|
return issue !== void 0 && promoted_issues(commands).has(issue);
|
|
1920
1652
|
}
|
|
1921
|
-
var LANE_SPLIT_PARK_REASON = '\u26D4 lane split park: this session is a dispatched lane child that promoted its own Issue to an epic this run, and a split is not a park
|
|
1922
|
-
var
|
|
1653
|
+
var LANE_SPLIT_PARK_REASON = '\u26D4 lane split park: this session is a dispatched lane child that promoted its own Issue to an epic this run, and a split is not a park: no `needs-decision` on the epic, no `confirmation` Telegram, on every occurrence. Park a child issue if the rest needs a person, else end the turn (`.claude/skills/workflow-commands/backlogrun-park.md` \u2192 "Splitting a child mid-run").';
|
|
1654
|
+
var ROW10 = {
|
|
1923
1655
|
id: "lane-split-park",
|
|
1924
1656
|
is_trigger: bash_triggers.on_bash_command(is_candidate),
|
|
1925
1657
|
reason: LANE_SPLIT_PARK_REASON,
|
|
@@ -1927,7 +1659,7 @@ var ROW9 = {
|
|
|
1927
1659
|
};
|
|
1928
1660
|
var lane_split_park = {
|
|
1929
1661
|
LANE_SPLIT_PARK_REASON,
|
|
1930
|
-
ROW:
|
|
1662
|
+
ROW: ROW10,
|
|
1931
1663
|
promoted_issues
|
|
1932
1664
|
};
|
|
1933
1665
|
|
|
@@ -1944,8 +1676,9 @@ var NON_COLLIDING_FLAGS = /* @__PURE__ */ new Set([
|
|
|
1944
1676
|
var FLAG_PREFIX2 = "-";
|
|
1945
1677
|
function switch_target(segment) {
|
|
1946
1678
|
const call = git_argv.parse(segment);
|
|
1947
|
-
if (call?.subcommand !== SWITCH_SUBCOMMAND)
|
|
1948
|
-
|
|
1679
|
+
if (call?.subcommand !== SWITCH_SUBCOMMAND || call.args.some((argument) => NON_COLLIDING_FLAGS.has(argument))) {
|
|
1680
|
+
return void 0;
|
|
1681
|
+
}
|
|
1949
1682
|
return call.args.find((argument) => !argument.startsWith(FLAG_PREFIX2));
|
|
1950
1683
|
}
|
|
1951
1684
|
function switch_targets(command) {
|
|
@@ -1959,8 +1692,8 @@ function is_switch_away_from_lane(command, is_lane_child = lane_child_marker.is_
|
|
|
1959
1692
|
if (!is_lane_child || own_branch === void 0) return false;
|
|
1960
1693
|
return switch_targets(command).some((target) => target !== own_branch);
|
|
1961
1694
|
}
|
|
1962
|
-
var LANE_SWITCH_MAIN_REASON = "\u26D4 lane child on `git switch main`: this session is a dispatched lane child, and switching to the default branch here always fails
|
|
1963
|
-
var
|
|
1695
|
+
var LANE_SWITCH_MAIN_REASON = "\u26D4 lane child on `git switch main`: this session is a dispatched lane child, and switching to the default branch here always fails (`already used by worktree`: the primary checkout holds it). Skip this step and keep implementing on the current branch; `pnpm josh main:merge` brings the default in during the gate. Refused on every occurrence (`backlogrun-lanes.md`, `backlogrun-child.md`).";
|
|
1696
|
+
var ROW11 = {
|
|
1964
1697
|
id: "lane-switch-main",
|
|
1965
1698
|
is_trigger: bash_triggers.on_bash_command(is_switch_away_from_lane),
|
|
1966
1699
|
reason: LANE_SWITCH_MAIN_REASON,
|
|
@@ -1968,7 +1701,7 @@ var ROW10 = {
|
|
|
1968
1701
|
};
|
|
1969
1702
|
var lane_switch_main = {
|
|
1970
1703
|
LANE_SWITCH_MAIN_REASON,
|
|
1971
|
-
ROW:
|
|
1704
|
+
ROW: ROW11,
|
|
1972
1705
|
is_switch_away_from_lane,
|
|
1973
1706
|
switch_target,
|
|
1974
1707
|
switch_targets
|
|
@@ -2471,7 +2204,7 @@ function command_line(oracle) {
|
|
|
2471
2204
|
return oracle.args ? `pnpm josh ${command} ${oracle.args}` : `pnpm josh ${command}`;
|
|
2472
2205
|
}
|
|
2473
2206
|
function reason_for(oracle, firing_point) {
|
|
2474
|
-
return `\u26D4 decision oracle not consulted: this is ${firing_point.describes}
|
|
2207
|
+
return `\u26D4 decision oracle not consulted: this is ${firing_point.describes}. Run \`${command_line(oracle)}\` first \u2014 it decides ${oracle.decision.toLowerCase()} and answers ${oracle.vocabulary.join(" | ")} (${oracle.single_source}). Every such call is refused until that command is on the transcript.`;
|
|
2475
2208
|
}
|
|
2476
2209
|
function row_for(oracle, firing_point) {
|
|
2477
2210
|
const names = command_names(oracle);
|
|
@@ -2537,14 +2270,16 @@ function is_destructive_segment2(segment) {
|
|
|
2537
2270
|
function is_destructive_command(command) {
|
|
2538
2271
|
return shell_segments.segments_of(command).some((segment) => is_destructive_segment2(segment));
|
|
2539
2272
|
}
|
|
2540
|
-
var DESTRUCTIVE_COMMAND_REASON = "\u26D4 destructive command: a recursive forced `rm
|
|
2541
|
-
var
|
|
2273
|
+
var DESTRUCTIVE_COMMAND_REASON = "\u26D4 destructive command: a recursive forced `rm`, a `gh repo delete` / `archive` / visibility edit, `gh pr close` or a `gh api -X DELETE` cannot be undone, which is Tier C. Remove one path at a time without `-f`, or ask the user to run it. It fires on every occurrence (`prompts/collaboration-workflow/operating-rules.md`).";
|
|
2274
|
+
var ROW12 = {
|
|
2542
2275
|
id: "destructive-command",
|
|
2543
2276
|
is_trigger: bash_triggers.on_bash_command(is_destructive_command),
|
|
2544
2277
|
reason: DESTRUCTIVE_COMMAND_REASON,
|
|
2545
|
-
decide: () => true
|
|
2278
|
+
decide: () => true,
|
|
2279
|
+
// The opening the reason carried before it was cut to the action and the next command.
|
|
2280
|
+
former_reasons: ["\u26D4 destructive command: a recursive forced `rm` (`rm -rf`"]
|
|
2546
2281
|
};
|
|
2547
|
-
var destructive_command = { DESTRUCTIVE_COMMAND_REASON, ROW:
|
|
2282
|
+
var destructive_command = { DESTRUCTIVE_COMMAND_REASON, ROW: ROW12, is_destructive_command };
|
|
2548
2283
|
|
|
2549
2284
|
// scripts/rules/direct-pr-create.ts
|
|
2550
2285
|
var GH_COMMAND2 = "gh";
|
|
@@ -2599,13 +2334,13 @@ function is_direct_pr_create(command) {
|
|
|
2599
2334
|
return shell_segments.segments_of(command).some((segment) => is_pr_create_segment(segment));
|
|
2600
2335
|
}
|
|
2601
2336
|
var DIRECT_PR_CREATE_REASON = "\u26D4 direct PR creation: `gh pr create` (or a `gh api` POST to `repos/<o>/<r>/pulls`) bypasses `build_body`, which writes the `closes #N` line \u2014 the Issue would stay open after the merge (`CLAUDE.md` \u2192 Git Rules). Open the PR with `pnpm josh pr` instead; after a failed push, fix, push, then run `pnpm josh pr`. **This rule fires on every occurrence, not once per run.**";
|
|
2602
|
-
var
|
|
2337
|
+
var ROW13 = {
|
|
2603
2338
|
id: "direct-pr-create",
|
|
2604
2339
|
is_trigger: bash_triggers.on_bash_command(is_direct_pr_create),
|
|
2605
2340
|
reason: DIRECT_PR_CREATE_REASON,
|
|
2606
2341
|
decide: () => true
|
|
2607
2342
|
};
|
|
2608
|
-
var direct_pr_create = { DIRECT_PR_CREATE_REASON, ROW:
|
|
2343
|
+
var direct_pr_create = { DIRECT_PR_CREATE_REASON, ROW: ROW13, is_direct_pr_create };
|
|
2609
2344
|
|
|
2610
2345
|
// scripts/rules/worktree-guard.ts
|
|
2611
2346
|
var CHECKOUT_SUBCOMMAND = "checkout";
|
|
@@ -2666,15 +2401,15 @@ function is_unauthorized_segment(segment) {
|
|
|
2666
2401
|
function is_unauthorized_worktree_change(command) {
|
|
2667
2402
|
return shell_segments.segments_of(command).some((segment) => is_unauthorized_segment(segment));
|
|
2668
2403
|
}
|
|
2669
|
-
var WORKTREE_MUTATION_REASON = '\u26D4 unauthorized working-tree change: `git checkout
|
|
2670
|
-
var
|
|
2404
|
+
var WORKTREE_MUTATION_REASON = '\u26D4 unauthorized working-tree change: `git checkout --`, `git restore`, `git clean -f`, `git stash`. A documented flow stashes with `git stash push -u -m "<message>"`; a handed-over stash is `pnpm josh stash:pop "<message>"`; record the substitution on the Issue (Tier A) unless the plan says why the owner keeps the stash: then stop and confirm. It fires on every occurrence (`operating-rules.md`).';
|
|
2405
|
+
var ROW14 = {
|
|
2671
2406
|
id: "worktree-mutation",
|
|
2672
2407
|
is_trigger: bash_triggers.on_bash_command(is_unauthorized_worktree_change),
|
|
2673
2408
|
reason: WORKTREE_MUTATION_REASON,
|
|
2674
2409
|
decide: () => true
|
|
2675
2410
|
};
|
|
2676
2411
|
var worktree_guard = {
|
|
2677
|
-
ROW:
|
|
2412
|
+
ROW: ROW14,
|
|
2678
2413
|
WORKTREE_MUTATION_REASON,
|
|
2679
2414
|
is_unauthorized_worktree_change,
|
|
2680
2415
|
touches_worktree
|
|
@@ -2702,46 +2437,46 @@ function is_index_segment(segment) {
|
|
|
2702
2437
|
function is_index_mutation(command) {
|
|
2703
2438
|
return shell_segments.segments_of(command).some((segment) => is_index_segment(segment));
|
|
2704
2439
|
}
|
|
2705
|
-
var INDEX_MUTATION_REASON =
|
|
2706
|
-
var
|
|
2440
|
+
var INDEX_MUTATION_REASON = "\u26D4 git index mutation: `git add` / `stage` / `commit` / `reset` / `rm` / `mv` and `git restore --staged` overwrite the user's staged snapshot. Commit with `pnpm josh git -y`; any other staging is the user's, on explicit instruction. It fires on every occurrence (`prompts/collaboration-workflow/operating-rules.md` \u2192 \"no-self-staging\").";
|
|
2441
|
+
var ROW15 = {
|
|
2707
2442
|
id: "index-mutation",
|
|
2708
2443
|
is_trigger: bash_triggers.on_bash_command(is_index_mutation),
|
|
2709
2444
|
reason: INDEX_MUTATION_REASON,
|
|
2710
2445
|
decide: () => true
|
|
2711
2446
|
};
|
|
2712
|
-
var index_guard = { INDEX_MUTATION_REASON, ROW:
|
|
2447
|
+
var index_guard = { INDEX_MUTATION_REASON, ROW: ROW15, is_index_mutation };
|
|
2713
2448
|
|
|
2714
2449
|
// scripts/rules/protected-files.ts
|
|
2715
|
-
import
|
|
2450
|
+
import path3 from "node:path";
|
|
2716
2451
|
|
|
2717
2452
|
// scripts/doctor/doctor-consumer.ts
|
|
2718
2453
|
import { existsSync as existsSync2 } from "node:fs";
|
|
2719
|
-
import
|
|
2454
|
+
import path2 from "node:path";
|
|
2720
2455
|
|
|
2721
2456
|
// scripts/version/kit-descriptor.ts
|
|
2722
2457
|
var KIT_PACKAGE_NAME = "@joshuafolkken/kit";
|
|
2723
2458
|
|
|
2724
2459
|
// scripts/doctor/doctor-consumer.ts
|
|
2725
|
-
import { z as
|
|
2460
|
+
import { z as z6 } from "zod";
|
|
2726
2461
|
var NODE_MODULES = "node_modules";
|
|
2727
|
-
var SETTINGS_PATH =
|
|
2462
|
+
var SETTINGS_PATH = path2.join(".claude", "settings.json");
|
|
2728
2463
|
var CLAUDE_MD = "CLAUDE.md";
|
|
2729
2464
|
var PLUGIN_ID = "kit@kit";
|
|
2730
2465
|
var CLAUDE_MD_POINTER = `@${NODE_MODULES}/${KIT_PACKAGE_NAME}/dist/${CLAUDE_MD}`;
|
|
2731
|
-
var SECRETLINT_BIN =
|
|
2732
|
-
var manifest_schema =
|
|
2733
|
-
name:
|
|
2734
|
-
dependencies:
|
|
2735
|
-
devDependencies:
|
|
2466
|
+
var SECRETLINT_BIN = path2.join(NODE_MODULES, ".bin", "secretlint");
|
|
2467
|
+
var manifest_schema = z6.object({
|
|
2468
|
+
name: z6.string().optional(),
|
|
2469
|
+
dependencies: z6.record(z6.string(), z6.string()).optional(),
|
|
2470
|
+
devDependencies: z6.record(z6.string(), z6.string()).optional()
|
|
2736
2471
|
});
|
|
2737
|
-
var settings_schema =
|
|
2738
|
-
enabledPlugins:
|
|
2472
|
+
var settings_schema = z6.object({
|
|
2473
|
+
enabledPlugins: z6.record(z6.string(), z6.boolean()).optional()
|
|
2739
2474
|
});
|
|
2740
2475
|
var STATE_OK = "ok";
|
|
2741
2476
|
var STATE_TARGET_MISSING = "target-missing";
|
|
2742
2477
|
var STATE_MISSING = "missing";
|
|
2743
2478
|
function parse_manifest(root) {
|
|
2744
|
-
const content = file_reader.read_if_readable(
|
|
2479
|
+
const content = file_reader.read_if_readable(path2.join(root, "package.json"));
|
|
2745
2480
|
if (content === void 0) return void 0;
|
|
2746
2481
|
const parsed = manifest_schema.safeParse(json_value.parse_or_undefined(content));
|
|
2747
2482
|
return parsed.success ? parsed.data : void 0;
|
|
@@ -2753,10 +2488,10 @@ function lists_kit_dependency(manifest) {
|
|
|
2753
2488
|
function is_kit_consumer(root) {
|
|
2754
2489
|
const manifest = parse_manifest(root);
|
|
2755
2490
|
if (manifest?.name === KIT_PACKAGE_NAME) return false;
|
|
2756
|
-
return lists_kit_dependency(manifest) || existsSync2(
|
|
2491
|
+
return lists_kit_dependency(manifest) || existsSync2(path2.join(root, NODE_MODULES, KIT_PACKAGE_NAME));
|
|
2757
2492
|
}
|
|
2758
2493
|
function is_plugin_declared(root) {
|
|
2759
|
-
const content = file_reader.read_if_readable(
|
|
2494
|
+
const content = file_reader.read_if_readable(path2.join(root, SETTINGS_PATH));
|
|
2760
2495
|
if (content === void 0) return false;
|
|
2761
2496
|
const parsed = settings_schema.safeParse(json_value.parse_or_undefined(content));
|
|
2762
2497
|
return parsed.success && parsed.data.enabledPlugins?.[PLUGIN_ID] === true;
|
|
@@ -2768,13 +2503,13 @@ function configured_hooks_path(root) {
|
|
|
2768
2503
|
return value === "" ? void 0 : value;
|
|
2769
2504
|
}
|
|
2770
2505
|
function claude_md_state(root) {
|
|
2771
|
-
const content = file_reader.read_if_readable(
|
|
2506
|
+
const content = file_reader.read_if_readable(path2.join(root, CLAUDE_MD));
|
|
2772
2507
|
if (content === void 0) return STATE_MISSING;
|
|
2773
2508
|
if (!content.includes(CLAUDE_MD_POINTER)) return STATE_OK;
|
|
2774
|
-
return existsSync2(
|
|
2509
|
+
return existsSync2(path2.join(root, NODE_MODULES, KIT_PACKAGE_NAME, "dist", CLAUDE_MD)) ? STATE_OK : STATE_TARGET_MISSING;
|
|
2775
2510
|
}
|
|
2776
2511
|
function is_secretlint_runnable(root) {
|
|
2777
|
-
return existsSync2(
|
|
2512
|
+
return existsSync2(path2.join(root, SECRETLINT_BIN));
|
|
2778
2513
|
}
|
|
2779
2514
|
function status_line(is_ok, ok_text, warn_text) {
|
|
2780
2515
|
return is_ok ? ` \u2713 ${ok_text}` : ` \u26A0 ${warn_text}`;
|
|
@@ -2840,7 +2575,7 @@ var EDIT_TOOLS2 = /* @__PURE__ */ new Set(["Edit", "Write"]);
|
|
|
2840
2575
|
var SECRET_FILES = /* @__PURE__ */ new Set([".env", ".dev.vars"]);
|
|
2841
2576
|
var ENVIRONMENT_VARIANT_PREFIX = ".env.";
|
|
2842
2577
|
var TRACKED_VARIANTS = /* @__PURE__ */ new Set([".env.example", ".env.test"]);
|
|
2843
|
-
var SETTINGS_FILE =
|
|
2578
|
+
var SETTINGS_FILE = path3.join(".claude", "settings.json");
|
|
2844
2579
|
var WHITESPACE3 = /\s+/u;
|
|
2845
2580
|
var TOKEN_QUOTES = /["']/gu;
|
|
2846
2581
|
var INPUT_REDIRECT = "<";
|
|
@@ -2870,7 +2605,7 @@ function file_path_of(call) {
|
|
|
2870
2605
|
return typeof value === "string" ? value : "";
|
|
2871
2606
|
}
|
|
2872
2607
|
function is_environment_path(token) {
|
|
2873
|
-
const name =
|
|
2608
|
+
const name = path3.basename(token.replaceAll(TOKEN_QUOTES, ""));
|
|
2874
2609
|
if (TRACKED_VARIANTS.has(name)) return false;
|
|
2875
2610
|
return SECRET_FILES.has(name) || name.startsWith(ENVIRONMENT_VARIANT_PREFIX);
|
|
2876
2611
|
}
|
|
@@ -2891,21 +2626,23 @@ function is_environment_read(call) {
|
|
|
2891
2626
|
}
|
|
2892
2627
|
function is_consumer_settings_edit(call, is_kit_consumer2) {
|
|
2893
2628
|
if (!EDIT_TOOLS2.has(call.name)) return false;
|
|
2894
|
-
const file_path =
|
|
2895
|
-
if (!file_path.endsWith(`${
|
|
2896
|
-
return is_kit_consumer2(
|
|
2629
|
+
const file_path = path3.resolve(file_path_of(call));
|
|
2630
|
+
if (!file_path.endsWith(`${path3.sep}${SETTINGS_FILE}`)) return false;
|
|
2631
|
+
return is_kit_consumer2(path3.dirname(path3.dirname(file_path)));
|
|
2897
2632
|
}
|
|
2898
2633
|
function is_protected_file_call(call, is_kit_consumer2 = doctor_consumer.is_kit_consumer) {
|
|
2899
2634
|
return is_environment_read(call) || is_consumer_settings_edit(call, is_kit_consumer2);
|
|
2900
2635
|
}
|
|
2901
|
-
var PROTECTED_FILE_REASON =
|
|
2902
|
-
var
|
|
2636
|
+
var PROTECTED_FILE_REASON = "\u26D4 protected file: `.env`, a `.env.*` variant and `.dev.vars` hold secrets, and a consumer `.claude/settings.json` is owned by `josh sync` (a change belongs upstream in kit). Leave these files alone, or ask the user. It fires on every occurrence.";
|
|
2637
|
+
var ROW16 = {
|
|
2903
2638
|
id: "protected-file",
|
|
2904
2639
|
is_trigger: is_protected_file_call,
|
|
2905
2640
|
reason: PROTECTED_FILE_REASON,
|
|
2906
|
-
decide: () => true
|
|
2641
|
+
decide: () => true,
|
|
2642
|
+
// The opening the reason carried before it was cut to the action and the next command.
|
|
2643
|
+
former_reasons: ["\u26D4 protected file: `.env` holds the Telegram bot token"]
|
|
2907
2644
|
};
|
|
2908
|
-
var protected_files = { ROW:
|
|
2645
|
+
var protected_files = { ROW: ROW16, is_protected_file_call };
|
|
2909
2646
|
|
|
2910
2647
|
// scripts/rules/permission-guards.ts
|
|
2911
2648
|
var ROWS2 = [
|
|
@@ -2940,7 +2677,7 @@ function is_verification_command(segment) {
|
|
|
2940
2677
|
function is_masked_verification(command) {
|
|
2941
2678
|
return time_shell.discarded_commands(command).some((segment) => is_verification_command(segment));
|
|
2942
2679
|
}
|
|
2943
|
-
var PIPED_VERIFICATION_REASON = "\u26D4 piped verification: a pipeline exits with its last command's status, so `pnpm josh gate | tail` reports success on a gate that failed
|
|
2680
|
+
var PIPED_VERIFICATION_REASON = "\u26D4 piped verification: a pipeline exits with its last command's status, so `pnpm josh gate | tail` reports success on a gate that failed. Reissue this call with no pipe (josh prints its verdict last), or redirect it to a file and read ranges from that file, or prefix `set -o pipefail`; read the verdict line, never the exit code alone (`prompts/collaboration-workflow/output-bounds.md`).";
|
|
2944
2681
|
function pipelines_of(command) {
|
|
2945
2682
|
return shell_segments.segments_of(time_shell.unquoted(command)).map((segment) => segment.split("|").map((piece) => piece.trim()));
|
|
2946
2683
|
}
|
|
@@ -2953,12 +2690,15 @@ function runs_verification(command) {
|
|
|
2953
2690
|
function keeps_verdict_intact(command) {
|
|
2954
2691
|
return runs_verification(command) && !is_masked_verification(command);
|
|
2955
2692
|
}
|
|
2956
|
-
var
|
|
2957
|
-
var
|
|
2693
|
+
var PIPEFAIL_OPEN = "(set -o pipefail; ";
|
|
2694
|
+
var PIPEFAIL_CLOSE = ")";
|
|
2695
|
+
var COMMENT_START = /(?:^|\s)#/u;
|
|
2696
|
+
var FULL_READING_FILTER = /^(?:tail|grep|cut|sort|uniq|wc)\b/u;
|
|
2958
2697
|
var EARLY_EXIT_GREP = /^grep\b.*\s(?:-[a-zA-Z]*[lLmq]|--(?:quiet|silent|max-count|files-with(?:out)?-match))/u;
|
|
2959
2698
|
var ALLOWED_OPERATORS = /2>&1|&&/gu;
|
|
2960
2699
|
var SIDE_EFFECT_SYNTAX = /[&<>`]|\$\(/u;
|
|
2961
|
-
var
|
|
2700
|
+
var GROUP_SYNTAX = /[()]/u;
|
|
2701
|
+
var PIPEFAIL_NOTE = "\u21BB piped verification: the josh check was piped, so its pipeline was wrapped in `(set -o pipefail; \u2026)` to carry the check's status, and the rest of the line ran as typed. Read the printed verdict, never the exit code alone \u2014 `prompts/collaboration-workflow/output-bounds.md`.";
|
|
2962
2702
|
function reads_to_the_end(piece) {
|
|
2963
2703
|
return FULL_READING_FILTER.test(piece) && !EARLY_EXIT_GREP.test(piece);
|
|
2964
2704
|
}
|
|
@@ -2969,14 +2709,40 @@ function is_filtered_check(pipeline) {
|
|
|
2969
2709
|
function has_side_effect_syntax(command) {
|
|
2970
2710
|
return SIDE_EFFECT_SYNTAX.test(command.replaceAll(ALLOWED_OPERATORS, " "));
|
|
2971
2711
|
}
|
|
2972
|
-
function
|
|
2973
|
-
|
|
2712
|
+
function is_rewritable_part(raw, judged) {
|
|
2713
|
+
const pipeline = judged.split("|").map((piece) => piece.trim());
|
|
2714
|
+
return !has_side_effect_syntax(raw) && !GROUP_SYNTAX.test(judged) && is_filtered_check(pipeline);
|
|
2715
|
+
}
|
|
2716
|
+
function code_end(judged) {
|
|
2717
|
+
const comment = COMMENT_START.exec(judged);
|
|
2718
|
+
return comment === null ? judged.length : comment.index;
|
|
2719
|
+
}
|
|
2720
|
+
function wrapped(raw, judged) {
|
|
2721
|
+
const code = raw.slice(0, code_end(judged));
|
|
2722
|
+
const core = code.trim();
|
|
2723
|
+
const lead = code.slice(0, code.indexOf(core));
|
|
2724
|
+
return `${lead}${PIPEFAIL_OPEN}${core}${PIPEFAIL_CLOSE}${raw.slice(lead.length + core.length)}`;
|
|
2725
|
+
}
|
|
2726
|
+
function rewritten_part(raw, judged) {
|
|
2727
|
+
if (!is_masked_verification(judged)) return raw;
|
|
2728
|
+
return is_rewritable_part(raw, judged) ? wrapped(raw, judged) : void 0;
|
|
2729
|
+
}
|
|
2730
|
+
function pipefail_command(command) {
|
|
2731
|
+
const judged = time_shell.blanked(command);
|
|
2732
|
+
if (judged === void 0 || !is_masked_verification(command)) return void 0;
|
|
2733
|
+
const offset = { at: 0 };
|
|
2734
|
+
const parts = shell_segments.parts_of(judged).map((part) => {
|
|
2735
|
+
const raw = command.slice(offset.at, offset.at + part.length);
|
|
2736
|
+
offset.at += part.length;
|
|
2737
|
+
return rewritten_part(raw, part);
|
|
2738
|
+
});
|
|
2739
|
+
const rewritten = parts.includes(void 0) ? void 0 : parts.join("");
|
|
2740
|
+
return rewritten === command ? void 0 : rewritten;
|
|
2974
2741
|
}
|
|
2975
2742
|
function pipefail_input(call) {
|
|
2976
2743
|
if (call.name !== cost_blocks.BASH_TOOL || !json_value.is_record(call.input)) return void 0;
|
|
2977
|
-
const command = time_shell.bash_command(call.input);
|
|
2978
|
-
|
|
2979
|
-
return { ...call.input, command: `${PIPEFAIL_PREFIX}${command}` };
|
|
2744
|
+
const command = pipefail_command(time_shell.bash_command(call.input));
|
|
2745
|
+
return command === void 0 ? void 0 : { ...call.input, command };
|
|
2980
2746
|
}
|
|
2981
2747
|
var piped_verification = {
|
|
2982
2748
|
PIPED_VERIFICATION_REASON,
|
|
@@ -3013,8 +2779,8 @@ function is_poll_loop(command) {
|
|
|
3013
2779
|
if (is_state_wait(plain)) return true;
|
|
3014
2780
|
return LOOP_KEYWORD2.test(plain) && SLEEP_COMMAND.test(plain);
|
|
3015
2781
|
}
|
|
3016
|
-
var POLL_LOOP_REASON =
|
|
3017
|
-
var
|
|
2782
|
+
var POLL_LOOP_REASON = "\u26D4 output poll loop: this hand-writes a `while`/`until` wait loop over a command's output, a marker file or a process, and the loop does not know when the command finished. Issue the long command with `run_in_background` set and end the turn \u2014 its exit re-invokes you; for CI, `pnpm josh followup` (`.claude/skills/workflow-commands/background-commands.md`). It fires on every occurrence.";
|
|
2783
|
+
var ROW17 = {
|
|
3018
2784
|
id: "poll-loop",
|
|
3019
2785
|
is_trigger: bash_triggers.on_bash_command(is_poll_loop),
|
|
3020
2786
|
reason: POLL_LOOP_REASON,
|
|
@@ -3022,87 +2788,23 @@ var ROW16 = {
|
|
|
3022
2788
|
};
|
|
3023
2789
|
var poll_loop = {
|
|
3024
2790
|
POLL_LOOP_REASON,
|
|
3025
|
-
ROW:
|
|
2791
|
+
ROW: ROW17,
|
|
3026
2792
|
is_poll_loop
|
|
3027
2793
|
};
|
|
3028
2794
|
|
|
3029
|
-
// scripts/rules/pre-gate-cut.ts
|
|
3030
|
-
var GATE_COMMANDS = /* @__PURE__ */ new Set(["gate"]);
|
|
3031
|
-
var CUT_COMMANDS2 = /* @__PURE__ */ new Set(["run:cut"]);
|
|
3032
|
-
var CUT_MODE_FLAG = /(?:^|\s)--(?:resume|end|json)(?:[=\s]|$)/u;
|
|
3033
|
-
var HOLD_COMMANDS = /* @__PURE__ */ new Set(["run:hold"]);
|
|
3034
|
-
var HOLD_MODE_FLAG = /(?:^|\s)--release(?:[=\s]|$)/u;
|
|
3035
|
-
function invokes_josh(command, names, mode_flag) {
|
|
3036
|
-
return shell_segments.segments_of(command).some(
|
|
3037
|
-
(segment) => shell_segments.is_josh_command(segment, names) && mode_flag?.test(segment) !== true
|
|
3038
|
-
);
|
|
3039
|
-
}
|
|
3040
|
-
function runs_the_gate(command) {
|
|
3041
|
-
return invokes_josh(command, GATE_COMMANDS);
|
|
3042
|
-
}
|
|
3043
|
-
function takes_the_cut(command) {
|
|
3044
|
-
return invokes_josh(command, CUT_COMMANDS2, CUT_MODE_FLAG);
|
|
3045
|
-
}
|
|
3046
|
-
function claims_the_hold(command) {
|
|
3047
|
-
return invokes_josh(command, HOLD_COMMANDS, HOLD_MODE_FLAG);
|
|
3048
|
-
}
|
|
3049
|
-
function asks_about_the_cut(command) {
|
|
3050
|
-
return invokes_josh(command, CUT_COMMANDS2);
|
|
3051
|
-
}
|
|
3052
|
-
function current_state2() {
|
|
3053
|
-
return {
|
|
3054
|
-
directory: process.cwd(),
|
|
3055
|
-
carried: run_cut.carried_cut_sync,
|
|
3056
|
-
marked_issue: lane_child_marker.marked_issue(),
|
|
3057
|
-
is_reviewer: agent_session_role.is_reviewer(),
|
|
3058
|
-
context_verdict: cost_cli.session_verdict
|
|
3059
|
-
};
|
|
3060
|
-
}
|
|
3061
|
-
function dispatched_issue(state) {
|
|
3062
|
-
return state.is_reviewer ? void 0 : state.marked_issue;
|
|
3063
|
-
}
|
|
3064
|
-
function uncut_lane_issue(state) {
|
|
3065
|
-
const issue = lane_paths.lane_issue_of(state.directory);
|
|
3066
|
-
if (issue === void 0) return void 0;
|
|
3067
|
-
if (dispatched_issue(state) !== issue) return void 0;
|
|
3068
|
-
return state.carried()?.issue === issue ? void 0 : issue;
|
|
3069
|
-
}
|
|
3070
|
-
function warrants_the_cut2(verdict) {
|
|
3071
|
-
return verdict !== cost_verdict.UNDER_VERDICT;
|
|
3072
|
-
}
|
|
3073
|
-
function is_uncut_gate(command, state = current_state2()) {
|
|
3074
|
-
if (!runs_the_gate(command) || uncut_lane_issue(state) === void 0) return false;
|
|
3075
|
-
return warrants_the_cut2(state.context_verdict());
|
|
3076
|
-
}
|
|
3077
|
-
var PRE_GATE_CUT_REASON = "\u26D4 pre-gate cut: this checkout is a lane dispatched for this issue and the gate is the boundary to cut at, so take the cut before running it. `pnpm josh run:cut <N>` ends this process and relaunches a fresh one that resumes from the gate, dropping the thinking built up while implementing rather than carrying it on every later request \u2014 joshuafolkken/kit#1839 measured 176K of 204K output riding across that boundary, and joshuafolkken/kit#1864 measured the step itself firing 0 times in 6 lane children while it was carried as prose. Issue `pnpm josh run:cut <N>` now, and read the verdict: on `cut`, **end the turn immediately** \u2014 the fresh process owns the run from there and must not be waited for, and **no Telegram is owed** for a cut that resumes itself; on `not-a-lane`, `unready`, `busy`, `failed` or `unknown`, this process carries the run on and the gate is simply the next call. Never relaunch a second process after `busy`. This fired because the dispatch mark names this lane; a person working here carries no mark and sees no refusal, so there is no human-or-child judgement left to make. The procedure is `.claude/skills/workflow-commands/pre-gate-cut.md`. Reissue the gate once the cut has answered \u2014 this fires once per run, so it cannot repeat on the call in hand.";
|
|
3078
|
-
function reaches_the_pre_gate_boundary(call, _turn, run2) {
|
|
3079
|
-
if (!bash_triggers.on_bash_command(asks_about_the_cut)(call)) return false;
|
|
3080
|
-
return run2.some((issued) => bash_triggers.on_bash_command(claims_the_hold)(issued));
|
|
3081
|
-
}
|
|
3082
|
-
var pre_gate_cut = {
|
|
3083
|
-
PRE_GATE_CUT_REASON,
|
|
3084
|
-
asks_about_the_cut,
|
|
3085
|
-
claims_the_hold,
|
|
3086
|
-
is_uncut_gate,
|
|
3087
|
-
reaches_the_pre_gate_boundary,
|
|
3088
|
-
runs_the_gate,
|
|
3089
|
-
takes_the_cut,
|
|
3090
|
-
uncut_lane_issue
|
|
3091
|
-
};
|
|
3092
|
-
|
|
3093
2795
|
// scripts/rules/raw-field-body.ts
|
|
3094
2796
|
var RAW_FIELD_BODY_AT = /(?:^|\s)(?:-f|--raw-field)[\s=]+['"]?body=['"]?@/u;
|
|
3095
2797
|
function posts_at_path_literally(command) {
|
|
3096
2798
|
return RAW_FIELD_BODY_AT.test(command);
|
|
3097
2799
|
}
|
|
3098
|
-
var RAW_FIELD_BODY_REASON = "\u26D4 literal @path body: this passes `body=@<path>` to `gh api` with a raw field flag (`-f` / `--raw-field`), which
|
|
3099
|
-
var
|
|
2800
|
+
var RAW_FIELD_BODY_REASON = "\u26D4 literal @path body: this passes `body=@<path>` to `gh api` with a raw field flag (`-f` / `--raw-field`), which posts the string `@<path>` rather than the file. Post the comment with `pnpm josh issue:comment <N> --body-file <path>`; this rule fires on every occurrence (`prompts/collaboration-workflow/shell-body.md`).";
|
|
2801
|
+
var ROW18 = {
|
|
3100
2802
|
id: "raw-field-body",
|
|
3101
2803
|
is_trigger: bash_triggers.on_bash_command(posts_at_path_literally),
|
|
3102
2804
|
reason: RAW_FIELD_BODY_REASON,
|
|
3103
2805
|
decide: () => true
|
|
3104
2806
|
};
|
|
3105
|
-
var raw_field_body = { RAW_FIELD_BODY_REASON, ROW:
|
|
2807
|
+
var raw_field_body = { RAW_FIELD_BODY_REASON, ROW: ROW18, posts_at_path_literally };
|
|
3106
2808
|
|
|
3107
2809
|
// scripts/rules/rule-body-guard.ts
|
|
3108
2810
|
var EDIT_TOOL = "Edit";
|
|
@@ -3154,7 +2856,7 @@ function writes_rule_prose(call, read2 = read_existing) {
|
|
|
3154
2856
|
const { old_text, new_text } = texts_of(call.name, input, read2);
|
|
3155
2857
|
return adds_rule_prose(old_text, new_text);
|
|
3156
2858
|
}
|
|
3157
|
-
var RULE_BODY_REASON = "\u26D4 rule written into prose: this edit adds rule text to CLAUDE.md, a `prompts/**` doc or a skill body.
|
|
2859
|
+
var RULE_BODY_REASON = "\u26D4 rule written into prose: this edit adds rule text to CLAUDE.md, a `prompts/**` doc or a skill body. Answer question 0 (`pnpm josh oracle:list`) and the ordering question (`pnpm josh run:step`) of `prompts/collaboration-workflow/residency.md`; refused until both commands are on the transcript, then reissue this as a trigger-plus-pointer line (`prompts/collaboration-workflow/rule-delivery.md`).";
|
|
3158
2860
|
var PLACEMENT_ORACLES = [
|
|
3159
2861
|
/* @__PURE__ */ new Set(["oracle:list"]),
|
|
3160
2862
|
/* @__PURE__ */ new Set(["run:step", "run:next"])
|
|
@@ -3173,7 +2875,7 @@ function runs_placement_oracle(command) {
|
|
|
3173
2875
|
(names) => shell_segments.segments_of(command).some((segment) => shell_segments.is_josh_command(segment, names))
|
|
3174
2876
|
);
|
|
3175
2877
|
}
|
|
3176
|
-
var
|
|
2878
|
+
var ROW19 = {
|
|
3177
2879
|
id: "rule-body",
|
|
3178
2880
|
is_trigger: writes_rule_prose,
|
|
3179
2881
|
reason: RULE_BODY_REASON,
|
|
@@ -3182,7 +2884,7 @@ var ROW18 = {
|
|
|
3182
2884
|
};
|
|
3183
2885
|
var rule_body_guard = {
|
|
3184
2886
|
RULE_BODY_REASON,
|
|
3185
|
-
ROW:
|
|
2887
|
+
ROW: ROW19,
|
|
3186
2888
|
answered_placement,
|
|
3187
2889
|
is_rule_document,
|
|
3188
2890
|
writes_rule_prose
|
|
@@ -3250,7 +2952,7 @@ function carries_a_body(command) {
|
|
|
3250
2952
|
if (BODY_FLAG.test(command.replaceAll(QUOTED_SPAN, " "))) return true;
|
|
3251
2953
|
return inline_body_literals(command).length > 0;
|
|
3252
2954
|
}
|
|
3253
|
-
var SHELL_BODY_REASON = "\u26D4 shell-evaluated body: this command carries a body inline in double quotes, and that body contains a backtick or a `$`, so the shell
|
|
2955
|
+
var SHELL_BODY_REASON = "\u26D4 shell-evaluated body: this command carries a body inline in double quotes, and that body contains a backtick or a `$`, so the shell executes it. Reissue this call once the body is in a file, passed by path (`pnpm josh issue:comment <N> --body-file <path>`, `--notify-message-file <path>`), or use `$'\u2026'` quoting (`prompts/collaboration-workflow/shell-body.md`).";
|
|
3254
2956
|
var shell_body_trigger = {
|
|
3255
2957
|
SHELL_BODY_REASON,
|
|
3256
2958
|
carries_a_body,
|
|
@@ -3259,12 +2961,12 @@ var shell_body_trigger = {
|
|
|
3259
2961
|
};
|
|
3260
2962
|
|
|
3261
2963
|
// scripts/gate/project-checks.ts
|
|
3262
|
-
import { existsSync as existsSync7, globSync
|
|
3263
|
-
import
|
|
2964
|
+
import { existsSync as existsSync7, globSync, readFileSync as readFileSync5 } from "node:fs";
|
|
2965
|
+
import path11 from "node:path";
|
|
3264
2966
|
|
|
3265
2967
|
// scripts/init/own-formatter.ts
|
|
3266
2968
|
import { existsSync as existsSync3 } from "node:fs";
|
|
3267
|
-
import
|
|
2969
|
+
import path4 from "node:path";
|
|
3268
2970
|
var OWN_FORMATTER_CONFIGS = [
|
|
3269
2971
|
"biome.json",
|
|
3270
2972
|
"biome.jsonc",
|
|
@@ -3274,18 +2976,18 @@ var OWN_FORMATTER_CONFIGS = [
|
|
|
3274
2976
|
".dprint.jsonc"
|
|
3275
2977
|
];
|
|
3276
2978
|
function find_config(root) {
|
|
3277
|
-
return OWN_FORMATTER_CONFIGS.find((name) => existsSync3(
|
|
2979
|
+
return OWN_FORMATTER_CONFIGS.find((name) => existsSync3(path4.join(root, name)));
|
|
3278
2980
|
}
|
|
3279
2981
|
var own_formatter = { find_config };
|
|
3280
2982
|
|
|
3281
2983
|
// scripts/init/project-profile.ts
|
|
3282
|
-
import { existsSync as existsSync6, readdirSync, readFileSync as
|
|
3283
|
-
import
|
|
2984
|
+
import { existsSync as existsSync6, readdirSync, readFileSync as readFileSync4 } from "node:fs";
|
|
2985
|
+
import path10 from "node:path";
|
|
3284
2986
|
|
|
3285
2987
|
// scripts/safe-chain/pack-hook.ts
|
|
3286
|
-
import { z as
|
|
2988
|
+
import { z as z7 } from "zod";
|
|
3287
2989
|
var PACK_HOOK_FILE = ".pnpmfile.mjs";
|
|
3288
|
-
var manifest_schema2 =
|
|
2990
|
+
var manifest_schema2 = z7.looseObject({ private: z7.boolean().optional() });
|
|
3289
2991
|
var MESSAGES = {
|
|
3290
2992
|
written: ` \u2714 synced ${PACK_HOOK_FILE} (run \`pnpm install\` to refresh pnpmfileChecksum)`,
|
|
3291
2993
|
unchanged: ` \u2714 unchanged ${PACK_HOOK_FILE}`,
|
|
@@ -3321,15 +3023,15 @@ var yaml_document = { is_mapping_document, parse_yaml, parse_yaml_documents };
|
|
|
3321
3023
|
|
|
3322
3024
|
// scripts/version/release-age.ts
|
|
3323
3025
|
import semver from "semver";
|
|
3324
|
-
import { z as
|
|
3325
|
-
var workspace_age_schema =
|
|
3326
|
-
var release_times_schema =
|
|
3026
|
+
import { z as z8 } from "zod";
|
|
3027
|
+
var workspace_age_schema = z8.object({ minimumReleaseAge: z8.number().int().nonnegative() });
|
|
3028
|
+
var release_times_schema = z8.record(z8.string(), z8.string());
|
|
3327
3029
|
|
|
3328
3030
|
// scripts/safe-chain/project-config.ts
|
|
3329
3031
|
import { dump } from "js-yaml";
|
|
3330
|
-
import { z as
|
|
3032
|
+
import { z as z9 } from "zod";
|
|
3331
3033
|
var PROJECT_CONFIG_FILE = ".aikido";
|
|
3332
|
-
var workspace_schema =
|
|
3034
|
+
var workspace_schema = z9.object({ minimumReleaseAgeExclude: z9.array(z9.string()).optional() });
|
|
3333
3035
|
|
|
3334
3036
|
// scripts/config-merge/json-format.ts
|
|
3335
3037
|
var PRINT_WIDTH = 100;
|
|
@@ -3374,9 +3076,9 @@ function inline_short_arrays(text) {
|
|
|
3374
3076
|
const output = [];
|
|
3375
3077
|
let index = 0;
|
|
3376
3078
|
while (index < lines.length) {
|
|
3377
|
-
const
|
|
3378
|
-
output.push(...
|
|
3379
|
-
index =
|
|
3079
|
+
const rewrite3 = rewrite_at(lines, index, lines[index] ?? "");
|
|
3080
|
+
output.push(...rewrite3.lines);
|
|
3081
|
+
index = rewrite3.next;
|
|
3380
3082
|
}
|
|
3381
3083
|
return output.join("\n");
|
|
3382
3084
|
}
|
|
@@ -3411,86 +3113,6 @@ var safe_chain_preinstall = {
|
|
|
3411
3113
|
migrate_preinstall
|
|
3412
3114
|
};
|
|
3413
3115
|
|
|
3414
|
-
// scripts/init/distributed-paths.ts
|
|
3415
|
-
var KIT_PACKAGE_PATH_PREFIX = "node_modules/@joshuafolkken/kit/";
|
|
3416
|
-
var PROMPTS_PACKAGE_PREFIX = `${KIT_PACKAGE_PATH_PREFIX}prompts/`;
|
|
3417
|
-
var ESLINT_PACKAGE_PREFIX = `${KIT_PACKAGE_PATH_PREFIX}eslint/`;
|
|
3418
|
-
var GITHUB_REPO_BLOB_BASE = "https://github.com/joshuafolkken/kit/blob/main/";
|
|
3419
|
-
var GITHUB_REPO_TREE_BASE = "https://github.com/joshuafolkken/kit/tree/main/";
|
|
3420
|
-
var CLAUDE_MD_IMPORT_LINE = "@node_modules/@joshuafolkken/kit/dist/CLAUDE.md";
|
|
3421
|
-
var OLD_CLAUDE_MD_BOOTSTRAP = "> Fresh checkout: if kit is not installed, run `pnpm install` first, then reread this file before doing any other work.";
|
|
3422
|
-
var CLAUDE_MD_BOOTSTRAP = '> Fresh checkout: before `pnpm install`, run `pnpm config get "@joshuafolkken:registry"` from the project root to check the effective registry, including user-level settings. If it points to GitHub Packages, [set up authentication](https://github.com/joshuafolkken/kit/blob/main/docs/authentication.md#1-get-a-token-from-the-gh-cli) first. Then run `pnpm install` and reread this file before doing any other work.';
|
|
3423
|
-
function transform_prompt_paths(content) {
|
|
3424
|
-
return content.replaceAll(
|
|
3425
|
-
/`prompts\/([^`*]+)`/gu,
|
|
3426
|
-
(_match, prompt_path) => `\`${PROMPTS_PACKAGE_PREFIX}${prompt_path}\``
|
|
3427
|
-
);
|
|
3428
|
-
}
|
|
3429
|
-
function transform_eslint_paths(content) {
|
|
3430
|
-
return content.replaceAll(
|
|
3431
|
-
/`eslint\/([^`*]+)`/gu,
|
|
3432
|
-
(_match, eslint_path) => `\`${ESLINT_PACKAGE_PREFIX}${eslint_path}\``
|
|
3433
|
-
);
|
|
3434
|
-
}
|
|
3435
|
-
function transform_test_file_paths(content) {
|
|
3436
|
-
return content.replaceAll(
|
|
3437
|
-
/`([^`*]+\.(?:test|spec)\.ts)`/gu,
|
|
3438
|
-
(_match, test_path) => `\`${GITHUB_REPO_BLOB_BASE}${test_path}\``
|
|
3439
|
-
);
|
|
3440
|
-
}
|
|
3441
|
-
function github_url_base(reference_path) {
|
|
3442
|
-
return reference_path.endsWith("/") ? GITHUB_REPO_TREE_BASE : GITHUB_REPO_BLOB_BASE;
|
|
3443
|
-
}
|
|
3444
|
-
function transform_documentation_paths(content) {
|
|
3445
|
-
return content.replaceAll(
|
|
3446
|
-
/`(docs\/[^`*]*)`/gu,
|
|
3447
|
-
(_match, documentation_path) => `\`${github_url_base(documentation_path)}${documentation_path}\``
|
|
3448
|
-
);
|
|
3449
|
-
}
|
|
3450
|
-
function transform_distributed_paths(content) {
|
|
3451
|
-
const with_prompts = transform_prompt_paths(content);
|
|
3452
|
-
const with_eslint = transform_eslint_paths(with_prompts);
|
|
3453
|
-
const with_tests = transform_test_file_paths(with_eslint);
|
|
3454
|
-
return transform_documentation_paths(with_tests);
|
|
3455
|
-
}
|
|
3456
|
-
function ensure_claude_md_import(existing) {
|
|
3457
|
-
if (existing === void 0) return `${CLAUDE_MD_BOOTSTRAP}
|
|
3458
|
-
|
|
3459
|
-
${CLAUDE_MD_IMPORT_LINE}
|
|
3460
|
-
`;
|
|
3461
|
-
const updated = existing.replace(OLD_CLAUDE_MD_BOOTSTRAP, () => CLAUDE_MD_BOOTSTRAP);
|
|
3462
|
-
if (updated.includes(CLAUDE_MD_IMPORT_LINE)) {
|
|
3463
|
-
if (updated.includes(CLAUDE_MD_BOOTSTRAP)) return updated;
|
|
3464
|
-
return `${CLAUDE_MD_BOOTSTRAP}
|
|
3465
|
-
|
|
3466
|
-
${updated}`;
|
|
3467
|
-
}
|
|
3468
|
-
return `${CLAUDE_MD_BOOTSTRAP}
|
|
3469
|
-
|
|
3470
|
-
${CLAUDE_MD_IMPORT_LINE}
|
|
3471
|
-
|
|
3472
|
-
${updated}`;
|
|
3473
|
-
}
|
|
3474
|
-
var FULL_CLAUDE_MD_LINES = /* @__PURE__ */ new Set([
|
|
3475
|
-
CLAUDE_MD_BOOTSTRAP,
|
|
3476
|
-
OLD_CLAUDE_MD_BOOTSTRAP,
|
|
3477
|
-
CLAUDE_MD_IMPORT_LINE
|
|
3478
|
-
]);
|
|
3479
|
-
function remove_claude_md_import(content) {
|
|
3480
|
-
const lines = content.split("\n");
|
|
3481
|
-
return lines.filter((line, index) => {
|
|
3482
|
-
if (FULL_CLAUDE_MD_LINES.has(line)) return false;
|
|
3483
|
-
return line !== "" || !FULL_CLAUDE_MD_LINES.has(lines[index - 1] ?? "");
|
|
3484
|
-
}).join("\n");
|
|
3485
|
-
}
|
|
3486
|
-
var distributed_paths = {
|
|
3487
|
-
transform_prompt_paths,
|
|
3488
|
-
transform_distributed_paths,
|
|
3489
|
-
ensure_claude_md_import,
|
|
3490
|
-
remove_claude_md_import,
|
|
3491
|
-
CLAUDE_MD_IMPORT_LINE
|
|
3492
|
-
};
|
|
3493
|
-
|
|
3494
3116
|
// scripts/init/init-logic-deploy-vps.ts
|
|
3495
3117
|
import semver2 from "semver";
|
|
3496
3118
|
var PNPM_INSTALL_PATTERN = /npm install -g pnpm@\d[\d.]{0,19}/gu;
|
|
@@ -3518,8 +3140,9 @@ function patch_deploy_vps_pnpm(content) {
|
|
|
3518
3140
|
PNPM_INSTALL_PATTERN,
|
|
3519
3141
|
(command) => replace_outdated_install(command)
|
|
3520
3142
|
);
|
|
3521
|
-
if (with_pnpm12.includes(VERSION_CHECK_MARKER)
|
|
3522
|
-
|
|
3143
|
+
if (with_pnpm12.includes(VERSION_CHECK_MARKER) || !OLD_PNPM_CHECK_PATTERN.test(with_pnpm12)) {
|
|
3144
|
+
return with_pnpm12;
|
|
3145
|
+
}
|
|
3523
3146
|
return with_pnpm12.replace(OLD_MAJOR_LINE_PATTERN, "").replace(OLD_PNPM_CHECK_PATTERN, (_, indent) => build_version_check(indent));
|
|
3524
3147
|
}
|
|
3525
3148
|
var init_logic_deploy_vps = { patch_deploy_vps_pnpm };
|
|
@@ -3771,10 +3394,10 @@ function set_json_key(content, key, value) {
|
|
|
3771
3394
|
const indented = fit_value(content, value_text, line_indent(content, existing.offset));
|
|
3772
3395
|
return with_trailing_newline(replace_range(content, existing, indented));
|
|
3773
3396
|
}
|
|
3774
|
-
function resolve_parent(content,
|
|
3397
|
+
function resolve_parent(content, path13) {
|
|
3775
3398
|
const root = parse_root(content);
|
|
3776
3399
|
if (root === void 0) return void 0;
|
|
3777
|
-
const parent =
|
|
3400
|
+
const parent = path13.length > 1 ? findNodeAtLocation(root, path13.slice(0, -1)) : root;
|
|
3778
3401
|
return parent?.type === "object" ? parent : void 0;
|
|
3779
3402
|
}
|
|
3780
3403
|
function cut_ranges(content, parent, ranges) {
|
|
@@ -3785,24 +3408,24 @@ function cut_ranges(content, parent, ranges) {
|
|
|
3785
3408
|
}
|
|
3786
3409
|
return next;
|
|
3787
3410
|
}
|
|
3788
|
-
function rebalance_new_last(content,
|
|
3789
|
-
const parent = resolve_parent(content,
|
|
3411
|
+
function rebalance_new_last(content, path13) {
|
|
3412
|
+
const parent = resolve_parent(content, path13);
|
|
3790
3413
|
const last = parent?.children?.at(-1);
|
|
3791
3414
|
if (parent === void 0 || last === void 0) return content;
|
|
3792
3415
|
return rebalance(content, last, has_separator_after(content, parent.offset, parent.offset));
|
|
3793
3416
|
}
|
|
3794
|
-
function cut_property(content, parent,
|
|
3795
|
-
const index = property_index(parent,
|
|
3417
|
+
function cut_property(content, parent, path13) {
|
|
3418
|
+
const index = property_index(parent, path13.at(-1) ?? "");
|
|
3796
3419
|
const ranges = removal_ranges(content, parent, index);
|
|
3797
3420
|
if (ranges.length === 0) return content;
|
|
3798
3421
|
const cut = cut_ranges(content, parent, ranges);
|
|
3799
3422
|
const did_end_object = index === (parent.children ?? []).length - 1;
|
|
3800
|
-
return did_end_object ? rebalance_new_last(cut,
|
|
3423
|
+
return did_end_object ? rebalance_new_last(cut, path13) : cut;
|
|
3801
3424
|
}
|
|
3802
|
-
function remove_json_path(content,
|
|
3803
|
-
const parent = resolve_parent(content,
|
|
3425
|
+
function remove_json_path(content, path13) {
|
|
3426
|
+
const parent = resolve_parent(content, path13);
|
|
3804
3427
|
if (parent === void 0) return content;
|
|
3805
|
-
const next = cut_property(content, parent,
|
|
3428
|
+
const next = cut_property(content, parent, path13);
|
|
3806
3429
|
return next === content ? content : with_trailing_newline(next);
|
|
3807
3430
|
}
|
|
3808
3431
|
function remove_json_key(content, key) {
|
|
@@ -4033,13 +3656,13 @@ var kit_base_preset = {
|
|
|
4033
3656
|
|
|
4034
3657
|
// scripts/init/tsconfig-preset-migration.ts
|
|
4035
3658
|
import { existsSync as existsSync4 } from "node:fs";
|
|
4036
|
-
import
|
|
3659
|
+
import path5 from "node:path";
|
|
4037
3660
|
var LEGACY_PRESET_ENTRY = /@joshuafolkken\/[^/]+\/tsconfig\/[^/]+\.jsonc$/u;
|
|
4038
3661
|
var LEGACY_SUFFIX = ".jsonc";
|
|
4039
3662
|
var CURRENT_SUFFIX = ".json";
|
|
4040
3663
|
var EXTENDS_FIELD = "extends";
|
|
4041
3664
|
function is_migration_target_present(base_directory, entry) {
|
|
4042
|
-
return existsSync4(
|
|
3665
|
+
return existsSync4(path5.resolve(base_directory, entry));
|
|
4043
3666
|
}
|
|
4044
3667
|
function migrate_entry(base_directory, entry) {
|
|
4045
3668
|
if (!LEGACY_PRESET_ENTRY.test(entry)) return entry;
|
|
@@ -4271,15 +3894,15 @@ var init_logic_json_merge = {
|
|
|
4271
3894
|
};
|
|
4272
3895
|
|
|
4273
3896
|
// scripts/init/kit-development-versions.ts
|
|
4274
|
-
import { readFileSync as
|
|
4275
|
-
import { z as
|
|
3897
|
+
import { readFileSync as readFileSync2 } from "node:fs";
|
|
3898
|
+
import { z as z10 } from "zod";
|
|
4276
3899
|
var PACKAGE_JSON = "package.json";
|
|
4277
|
-
var kit_manifest_schema =
|
|
4278
|
-
peerDependencies:
|
|
4279
|
-
devDependencies:
|
|
3900
|
+
var kit_manifest_schema = z10.object({
|
|
3901
|
+
peerDependencies: z10.record(z10.string(), z10.string()).default({}),
|
|
3902
|
+
devDependencies: z10.record(z10.string(), z10.string())
|
|
4280
3903
|
});
|
|
4281
3904
|
function read_kit_manifest() {
|
|
4282
|
-
const content =
|
|
3905
|
+
const content = readFileSync2(package_path(PACKAGE_JSON), "utf8");
|
|
4283
3906
|
return kit_manifest_schema.parse(JSON.parse(content));
|
|
4284
3907
|
}
|
|
4285
3908
|
function versions_of(names) {
|
|
@@ -4440,9 +4063,9 @@ function merge_sonar_properties(existing, template_content) {
|
|
|
4440
4063
|
return key !== void 0 && !existing_keys.has(key);
|
|
4441
4064
|
});
|
|
4442
4065
|
if (lines_to_add.length === 0) return merged_existing;
|
|
4443
|
-
const
|
|
4066
|
+
const normalized = merged_existing.endsWith("\n") ? merged_existing : `${merged_existing}
|
|
4444
4067
|
`;
|
|
4445
|
-
return `${
|
|
4068
|
+
return `${normalized}
|
|
4446
4069
|
${lines_to_add.join("\n")}
|
|
4447
4070
|
`;
|
|
4448
4071
|
}
|
|
@@ -4455,8 +4078,8 @@ var init_logic_sonar = {
|
|
|
4455
4078
|
};
|
|
4456
4079
|
|
|
4457
4080
|
// scripts/init/init-logic-templates.ts
|
|
4458
|
-
import { existsSync as existsSync5, readFileSync as
|
|
4459
|
-
import
|
|
4081
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3 } from "node:fs";
|
|
4082
|
+
import path6 from "node:path";
|
|
4460
4083
|
var ESLINT_VANILLA = `import { create_vanilla_config } from '@joshuafolkken/kit/eslint/vanilla'
|
|
4461
4084
|
|
|
4462
4085
|
export default create_vanilla_config({
|
|
@@ -4541,7 +4164,7 @@ function merge_eslint_config(existing) {
|
|
|
4541
4164
|
return apply_rules_template(rules_blocks.join(",\n"));
|
|
4542
4165
|
}
|
|
4543
4166
|
function detect_tailwind_stylesheet(project_root2) {
|
|
4544
|
-
return existsSync5(
|
|
4167
|
+
return existsSync5(path6.join(project_root2, DEFAULT_TAILWIND_STYLESHEET)) ? DEFAULT_TAILWIND_STYLESHEET : void 0;
|
|
4545
4168
|
}
|
|
4546
4169
|
function generate_prettier_config(stylesheet) {
|
|
4547
4170
|
const stylesheet_line = stylesheet === void 0 ? "" : ` tailwindStylesheet: '${stylesheet}',
|
|
@@ -4555,14 +4178,14 @@ ${stylesheet_line}}
|
|
|
4555
4178
|
}
|
|
4556
4179
|
function existing_stylesheet(existing, project_root2) {
|
|
4557
4180
|
const named = TAILWIND_STYLESHEET_PATTERN.exec(existing)?.[1];
|
|
4558
|
-
return named !== void 0 && existsSync5(
|
|
4181
|
+
return named !== void 0 && existsSync5(path6.resolve(project_root2, named)) ? named : void 0;
|
|
4559
4182
|
}
|
|
4560
4183
|
function merge_prettier_config(existing, project_root2) {
|
|
4561
4184
|
const stylesheet = existing_stylesheet(existing, project_root2) ?? detect_tailwind_stylesheet(project_root2);
|
|
4562
4185
|
return generate_prettier_config(stylesheet);
|
|
4563
4186
|
}
|
|
4564
4187
|
function generate_playwright_config() {
|
|
4565
|
-
return
|
|
4188
|
+
return readFileSync3(PLAYWRIGHT_TEMPLATE_PATH, "utf8");
|
|
4566
4189
|
}
|
|
4567
4190
|
var init_logic_templates = {
|
|
4568
4191
|
generate_eslint_config,
|
|
@@ -4634,9 +4257,9 @@ function extract_yaml_block(content, key) {
|
|
|
4634
4257
|
}
|
|
4635
4258
|
function append_user_blocks(base, user_keys, existing) {
|
|
4636
4259
|
const user_blocks = user_keys.map((k) => extract_yaml_block(existing, k)).filter(Boolean).join("\n");
|
|
4637
|
-
const
|
|
4260
|
+
const normalized = base.endsWith("\n") ? base : `${base}
|
|
4638
4261
|
`;
|
|
4639
|
-
return `${
|
|
4262
|
+
return `${normalized}
|
|
4640
4263
|
${user_blocks}
|
|
4641
4264
|
`;
|
|
4642
4265
|
}
|
|
@@ -4729,9 +4352,9 @@ function carry_npmrc_settings(template, npmrc) {
|
|
|
4729
4352
|
}
|
|
4730
4353
|
function merge_workspace_yaml(existing, template) {
|
|
4731
4354
|
if (!existing.trim()) return template;
|
|
4732
|
-
const
|
|
4355
|
+
const normalized = existing.endsWith("\n") ? existing : `${existing}
|
|
4733
4356
|
`;
|
|
4734
|
-
const answered = answer_build_placeholders(remove_deprecated_yaml_keys(
|
|
4357
|
+
const answered = answer_build_placeholders(remove_deprecated_yaml_keys(normalized), template);
|
|
4735
4358
|
const cleaned = add_missing_build_entries(answered, template);
|
|
4736
4359
|
if (!cleaned.trim()) return template;
|
|
4737
4360
|
const existing_keys = new Set(extract_yaml_top_level_keys(cleaned));
|
|
@@ -5070,23 +4693,23 @@ var AI_COPY_DIRECTORIES_LIST = "AI_COPY_DIRECTORIES";
|
|
|
5070
4693
|
var SYNCED_PATHS_LIST = "SYNCED_PATHS";
|
|
5071
4694
|
var PLUGIN_SKILL_DIRECTORIES_LIST = "PLUGIN_SKILL_DIRECTORIES";
|
|
5072
4695
|
var PATH_SEPARATOR = "/";
|
|
5073
|
-
function is_inside(
|
|
5074
|
-
return
|
|
4696
|
+
function is_inside(path13, directory) {
|
|
4697
|
+
return path13 === directory || path13.startsWith(`${directory}${PATH_SEPARATOR}`);
|
|
5075
4698
|
}
|
|
5076
|
-
function matches_file(
|
|
5077
|
-
return init_logic.get_ai_copy_files().includes(
|
|
4699
|
+
function matches_file(path13) {
|
|
4700
|
+
return init_logic.get_ai_copy_files().includes(path13);
|
|
5078
4701
|
}
|
|
5079
|
-
function matches_mapping(
|
|
5080
|
-
return init_logic.get_ai_copy_file_mappings().some((mapping) => mapping.src ===
|
|
4702
|
+
function matches_mapping(path13) {
|
|
4703
|
+
return init_logic.get_ai_copy_file_mappings().some((mapping) => mapping.src === path13 || mapping.dest === path13);
|
|
5081
4704
|
}
|
|
5082
|
-
function matches_directory(
|
|
5083
|
-
return init_logic.get_ai_copy_directories().some((directory) => is_inside(
|
|
4705
|
+
function matches_directory(path13) {
|
|
4706
|
+
return init_logic.get_ai_copy_directories().some((directory) => is_inside(path13, directory));
|
|
5084
4707
|
}
|
|
5085
|
-
function matches_plugin_skill(
|
|
5086
|
-
return PLUGIN_SKILL_DIRECTORIES.some((directory) => is_inside(
|
|
4708
|
+
function matches_plugin_skill(path13) {
|
|
4709
|
+
return PLUGIN_SKILL_DIRECTORIES.some((directory) => is_inside(path13, directory));
|
|
5087
4710
|
}
|
|
5088
|
-
function matches_synced_path(
|
|
5089
|
-
return synced_paths.get_synced_paths().includes(
|
|
4711
|
+
function matches_synced_path(path13) {
|
|
4712
|
+
return synced_paths.get_synced_paths().includes(path13);
|
|
5090
4713
|
}
|
|
5091
4714
|
var MATCHERS = [
|
|
5092
4715
|
{ list: AI_COPY_FILES_LIST, matches: matches_file },
|
|
@@ -5095,18 +4718,18 @@ var MATCHERS = [
|
|
|
5095
4718
|
{ list: PLUGIN_SKILL_DIRECTORIES_LIST, matches: matches_plugin_skill },
|
|
5096
4719
|
{ list: SYNCED_PATHS_LIST, matches: matches_synced_path }
|
|
5097
4720
|
];
|
|
5098
|
-
function find_list(
|
|
5099
|
-
return MATCHERS.find((matcher) => matcher.matches(
|
|
4721
|
+
function find_list(path13) {
|
|
4722
|
+
return MATCHERS.find((matcher) => matcher.matches(path13))?.list;
|
|
5100
4723
|
}
|
|
5101
|
-
function to_hit(
|
|
5102
|
-
const list = find_list(
|
|
5103
|
-
return list === void 0 ? void 0 : { path:
|
|
4724
|
+
function to_hit(path13) {
|
|
4725
|
+
const list = find_list(path13);
|
|
4726
|
+
return list === void 0 ? void 0 : { path: path13, list };
|
|
5104
4727
|
}
|
|
5105
4728
|
function find_managed_paths(paths) {
|
|
5106
|
-
return paths.flatMap((
|
|
4729
|
+
return paths.flatMap((path13) => to_hit(path13) ?? []);
|
|
5107
4730
|
}
|
|
5108
4731
|
function has_managed_path(paths) {
|
|
5109
|
-
return paths.some((
|
|
4732
|
+
return paths.some((path13) => find_list(path13) !== void 0);
|
|
5110
4733
|
}
|
|
5111
4734
|
function format_hit(hit) {
|
|
5112
4735
|
return `${hit.path} (${hit.list})`;
|
|
@@ -5122,8 +4745,8 @@ var managed_config_scope = {
|
|
|
5122
4745
|
};
|
|
5123
4746
|
|
|
5124
4747
|
// scripts/init/session-language-environment.ts
|
|
5125
|
-
import
|
|
5126
|
-
var CLAUDE_SETTINGS_PATH =
|
|
4748
|
+
import path7 from "node:path";
|
|
4749
|
+
var CLAUDE_SETTINGS_PATH = path7.join(".claude", "settings.json");
|
|
5127
4750
|
var KEY_LINE_PATTERN = new RegExp(
|
|
5128
4751
|
String.raw`^\s*(?:export\s+)?${session_language.ENV_KEY}\s*=`,
|
|
5129
4752
|
"mu"
|
|
@@ -5133,8 +4756,8 @@ var KEY_LINE_PATTERN = new RegExp(
|
|
|
5133
4756
|
import { findNodeAtLocation as findNodeAtLocation2, getNodeValue as getNodeValue2, parseTree as parseTree3 } from "jsonc-parser";
|
|
5134
4757
|
|
|
5135
4758
|
// scripts/init/vscode-tasks.ts
|
|
5136
|
-
import { z as
|
|
5137
|
-
var task_array_schema =
|
|
4759
|
+
import { z as z11 } from "zod";
|
|
4760
|
+
var task_array_schema = z11.array(json_object_schema);
|
|
5138
4761
|
|
|
5139
4762
|
// scripts/init/init-actions.ts
|
|
5140
4763
|
var BASIC_PRETTIER_CONFIG = "prettier.config.mjs";
|
|
@@ -5144,11 +4767,11 @@ var MARKER_TOKEN = "josh-managed-workflow:";
|
|
|
5144
4767
|
var MARKER_PREFIX = `# ${MARKER_TOKEN}`;
|
|
5145
4768
|
|
|
5146
4769
|
// scripts/init/claude-plugin-config.ts
|
|
5147
|
-
import
|
|
4770
|
+
import path8 from "node:path";
|
|
5148
4771
|
var MARKETPLACE_NAME = "kit";
|
|
5149
4772
|
var PLUGIN_ID2 = "kit@kit";
|
|
5150
4773
|
var MARKETPLACE_PATH = "./node_modules/@joshuafolkken/kit";
|
|
5151
|
-
var CLAUDE_SETTINGS_DESTINATION =
|
|
4774
|
+
var CLAUDE_SETTINGS_DESTINATION = path8.join(".claude", "settings.json");
|
|
5152
4775
|
var PLUGIN_SETTINGS = {
|
|
5153
4776
|
extraKnownMarketplaces: {
|
|
5154
4777
|
[MARKETPLACE_NAME]: { source: { source: "directory", path: MARKETPLACE_PATH } }
|
|
@@ -5172,9 +4795,9 @@ var claude_plugin_config = {
|
|
|
5172
4795
|
// scripts/init/hook-launch.ts
|
|
5173
4796
|
var HOOK_DIST_DIR = "dist/hooks";
|
|
5174
4797
|
var RUN_HOOK_SCRIPT = "scripts/hooks/run-hook.sh";
|
|
5175
|
-
var
|
|
4798
|
+
var LOCATION_VARIABLES = GIT_LOCATION_VARIABLES.join(" ");
|
|
5176
4799
|
var ROOT_LOOKUP = "git rev-parse --show-toplevel";
|
|
5177
|
-
var PROJECT_ROOT_PREFIX = `project_root="$(
|
|
4800
|
+
var PROJECT_ROOT_PREFIX = `if project_root="$(unset ${LOCATION_VARIABLES}; ${ROOT_LOOKUP} 2>/dev/null)"; then unset ${LOCATION_VARIABLES}; else project_root="$(${ROOT_LOOKUP})"; fi && cd "$project_root" && `;
|
|
5178
4801
|
function hook_launch_command(name) {
|
|
5179
4802
|
return `${PROJECT_ROOT_PREFIX}sh ${RUN_HOOK_SCRIPT} ${name}`;
|
|
5180
4803
|
}
|
|
@@ -5210,7 +4833,7 @@ var PLAIN_KIT_COMMANDS = new Set(
|
|
|
5210
4833
|
var PROJECT_ROOT_PREFIX2 = JSON.stringify(hook_launch.PROJECT_ROOT_PREFIX).slice(1, -1);
|
|
5211
4834
|
|
|
5212
4835
|
// scripts/init/security-policy.ts
|
|
5213
|
-
import
|
|
4836
|
+
import path9 from "node:path";
|
|
5214
4837
|
var SECURITY_MD = "SECURITY.md";
|
|
5215
4838
|
var SECURITY_TEMPLATE = "templates/SECURITY.md";
|
|
5216
4839
|
var REPOSITORY_PLACEHOLDER = "{{REPOSITORY}}";
|
|
@@ -5226,15 +4849,15 @@ function apply_repository(content, repository) {
|
|
|
5226
4849
|
return content.replaceAll(REPOSITORY_PLACEHOLDER, () => repository);
|
|
5227
4850
|
}
|
|
5228
4851
|
function apply_repository_for_destination(destination_path, content) {
|
|
5229
|
-
if (
|
|
5230
|
-
const repository = repository_at(
|
|
4852
|
+
if (path9.basename(destination_path) !== SECURITY_MD) return content;
|
|
4853
|
+
const repository = repository_at(path9.dirname(destination_path));
|
|
5231
4854
|
if (repository === void 0) {
|
|
5232
4855
|
throw new Error(`${SECURITY_MD} needs a GitHub origin to name the repository it reports to`);
|
|
5233
4856
|
}
|
|
5234
4857
|
return apply_repository(content, repository);
|
|
5235
4858
|
}
|
|
5236
4859
|
function does_report_to_kit(root) {
|
|
5237
|
-
const existing = file_reader.read_if_readable(
|
|
4860
|
+
const existing = file_reader.read_if_readable(path9.join(root, SECURITY_MD)) ?? "";
|
|
5238
4861
|
return new Set(existing.split(LINK_DELIMITER)).has(KIT_ADVISORY_URL);
|
|
5239
4862
|
}
|
|
5240
4863
|
function unresolved_warning(root) {
|
|
@@ -5354,9 +4977,9 @@ function requested_profile(args, usage = "josh init [--profile basic|full]") {
|
|
|
5354
4977
|
throw new Error("Profile must be basic or full");
|
|
5355
4978
|
}
|
|
5356
4979
|
function read_manifest(root) {
|
|
5357
|
-
const filename =
|
|
4980
|
+
const filename = path10.join(root, "package.json");
|
|
5358
4981
|
if (!existsSync6(filename)) return void 0;
|
|
5359
|
-
const parsed = JSON.parse(
|
|
4982
|
+
const parsed = JSON.parse(readFileSync4(filename, "utf8"));
|
|
5360
4983
|
if (!json_value.is_record(parsed)) throw new Error("package.json must contain an object");
|
|
5361
4984
|
return parsed;
|
|
5362
4985
|
}
|
|
@@ -5397,12 +5020,12 @@ function should_visit(entry) {
|
|
|
5397
5020
|
function scan_directory(directory, pending) {
|
|
5398
5021
|
const entries = readdirSync(directory, { withFileTypes: true });
|
|
5399
5022
|
pending.push(
|
|
5400
|
-
...entries.filter((entry) => should_visit(entry)).map((entry) =>
|
|
5023
|
+
...entries.filter((entry) => should_visit(entry)).map((entry) => path10.join(directory, entry.name))
|
|
5401
5024
|
);
|
|
5402
|
-
return entries.filter((entry) => entry.isFile()).map((entry) =>
|
|
5025
|
+
return entries.filter((entry) => entry.isFile()).map((entry) => path10.join(directory, entry.name));
|
|
5403
5026
|
}
|
|
5404
5027
|
function is_project_file(root, file) {
|
|
5405
|
-
const relative_path =
|
|
5028
|
+
const relative_path = path10.relative(root, file).split(path10.sep).join(path10.posix.sep);
|
|
5406
5029
|
return !kit_written_paths.is_kit_written(relative_path);
|
|
5407
5030
|
}
|
|
5408
5031
|
function list_files(root) {
|
|
@@ -5414,7 +5037,7 @@ function list_files(root) {
|
|
|
5414
5037
|
return files;
|
|
5415
5038
|
}
|
|
5416
5039
|
function file_extensions(root) {
|
|
5417
|
-
return list_files(root).filter((file) => is_project_file(root, file)).map((file) =>
|
|
5040
|
+
return list_files(root).filter((file) => is_project_file(root, file)).map((file) => path10.extname(file));
|
|
5418
5041
|
}
|
|
5419
5042
|
function scan_files(root) {
|
|
5420
5043
|
const extensions = file_extensions(root);
|
|
@@ -5428,7 +5051,7 @@ function has_github_remote(root) {
|
|
|
5428
5051
|
return url !== void 0 && repo_origin.parse_origin_url(url) !== void 0;
|
|
5429
5052
|
}
|
|
5430
5053
|
function has_git(root) {
|
|
5431
|
-
return existsSync6(
|
|
5054
|
+
return existsSync6(path10.join(root, ".git"));
|
|
5432
5055
|
}
|
|
5433
5056
|
function has_workflow(root) {
|
|
5434
5057
|
return workflow_mark.is_requested() || workflow_mark.is_recorded(read_manifest(root));
|
|
@@ -5461,7 +5084,7 @@ var SKIP_MARKER = "\u2014 skipping";
|
|
|
5461
5084
|
var NOT_USED_MARKER = "which this project does not use";
|
|
5462
5085
|
|
|
5463
5086
|
// scripts/gate/project-checks.ts
|
|
5464
|
-
import { z as
|
|
5087
|
+
import { z as z12 } from "zod";
|
|
5465
5088
|
var PACKAGE_JSON2 = "package.json";
|
|
5466
5089
|
var IGNORED_DIRS = /* @__PURE__ */ new Set([
|
|
5467
5090
|
"node_modules",
|
|
@@ -5496,11 +5119,11 @@ var CSPELL_CONFIGS = [
|
|
|
5496
5119
|
];
|
|
5497
5120
|
var TYPE_CONFIGS = ["tsconfig.json", "jsconfig.json"];
|
|
5498
5121
|
var DEPENDENCY_FIELDS = ["dependencies", "devDependencies"];
|
|
5499
|
-
var object_schema =
|
|
5122
|
+
var object_schema = z12.record(z12.string(), z12.unknown());
|
|
5500
5123
|
function project_root(directory) {
|
|
5501
5124
|
return ancestor_directories.nearest(
|
|
5502
5125
|
directory,
|
|
5503
|
-
(candidate) => existsSync7(
|
|
5126
|
+
(candidate) => existsSync7(path11.join(candidate, PACKAGE_JSON2))
|
|
5504
5127
|
) ?? directory;
|
|
5505
5128
|
}
|
|
5506
5129
|
function is_kit_repository(directory) {
|
|
@@ -5510,10 +5133,10 @@ function is_ignored(entry) {
|
|
|
5510
5133
|
return entry.split(/[/\\]/u).some((part) => IGNORED_DIRS.has(part));
|
|
5511
5134
|
}
|
|
5512
5135
|
function has_files(directory, pattern) {
|
|
5513
|
-
return
|
|
5136
|
+
return globSync(pattern, { cwd: project_root(directory), exclude: is_ignored }).length > 0;
|
|
5514
5137
|
}
|
|
5515
5138
|
function has_config(directory, names) {
|
|
5516
|
-
return names.some((name) => existsSync7(
|
|
5139
|
+
return names.some((name) => existsSync7(path11.join(project_root(directory), name)));
|
|
5517
5140
|
}
|
|
5518
5141
|
function has_bin(directory, bin_name) {
|
|
5519
5142
|
return find_local_bin_upwards(directory, bin_name) !== void 0;
|
|
@@ -5528,8 +5151,8 @@ function is_basic_manifest(manifest) {
|
|
|
5528
5151
|
}
|
|
5529
5152
|
function read_manifest2(directory) {
|
|
5530
5153
|
try {
|
|
5531
|
-
const manifest_path =
|
|
5532
|
-
return json_value.parse_or_undefined(
|
|
5154
|
+
const manifest_path = path11.join(project_root(directory), PACKAGE_JSON2);
|
|
5155
|
+
return json_value.parse_or_undefined(readFileSync5(manifest_path, "utf8"));
|
|
5533
5156
|
} catch {
|
|
5534
5157
|
return void 0;
|
|
5535
5158
|
}
|
|
@@ -5549,11 +5172,11 @@ function missing_tool_reason(directory, package_name, bin_name) {
|
|
|
5549
5172
|
if (has_bin(directory, bin_name) || is_declared2(directory, package_name)) return void 0;
|
|
5550
5173
|
return `${package_name} is not installed`;
|
|
5551
5174
|
}
|
|
5552
|
-
function skip_notice(
|
|
5553
|
-
return `josh ${
|
|
5175
|
+
function skip_notice(check3, reason) {
|
|
5176
|
+
return `josh ${check3}: ${reason} ${SKIP_MARKER} ${check3}, ${NOT_USED_MARKER}.`;
|
|
5554
5177
|
}
|
|
5555
|
-
function ran_notice(
|
|
5556
|
-
return `josh ${
|
|
5178
|
+
function ran_notice(check3) {
|
|
5179
|
+
return `josh ${check3}: ran and reported no problems.`;
|
|
5557
5180
|
}
|
|
5558
5181
|
function type_check_skip_reason(directory) {
|
|
5559
5182
|
if (!is_basic(directory)) return void 0;
|
|
@@ -5617,40 +5240,40 @@ var BASIC_REQUIRED_SUFFIXES = [
|
|
|
5617
5240
|
".toml"
|
|
5618
5241
|
];
|
|
5619
5242
|
function normalize(paths) {
|
|
5620
|
-
return paths.map((
|
|
5243
|
+
return paths.map((path13) => path13.trim()).filter((path13) => path13 !== "");
|
|
5621
5244
|
}
|
|
5622
|
-
function is_test_file(
|
|
5623
|
-
return TEST_SUFFIXES.some((suffix) =>
|
|
5245
|
+
function is_test_file(path13) {
|
|
5246
|
+
return TEST_SUFFIXES.some((suffix) => path13.endsWith(suffix));
|
|
5624
5247
|
}
|
|
5625
|
-
function is_basic_manual(
|
|
5626
|
-
const lower =
|
|
5248
|
+
function is_basic_manual(path13, is_basic2) {
|
|
5249
|
+
const lower = path13.toLowerCase();
|
|
5627
5250
|
return is_basic2 && BASIC_REQUIRED_SUFFIXES.every((suffix) => !lower.endsWith(suffix));
|
|
5628
5251
|
}
|
|
5629
|
-
function is_basic_visual(
|
|
5630
|
-
const lower =
|
|
5252
|
+
function is_basic_visual(path13) {
|
|
5253
|
+
const lower = path13.toLowerCase();
|
|
5631
5254
|
return BASIC_VISUAL_SUFFIXES.some((suffix) => lower.endsWith(suffix));
|
|
5632
5255
|
}
|
|
5633
|
-
function is_exempt(
|
|
5634
|
-
if (EXEMPT_PATHS.includes(
|
|
5635
|
-
return EXEMPT_SUFFIXES.some((suffix) =>
|
|
5256
|
+
function is_exempt(path13, is_basic2 = false) {
|
|
5257
|
+
if (EXEMPT_PATHS.includes(path13) || is_basic_manual(path13, is_basic2)) return true;
|
|
5258
|
+
return EXEMPT_SUFFIXES.some((suffix) => path13.endsWith(suffix)) || EXEMPT_PREFIXES.some((prefix) => path13.startsWith(prefix));
|
|
5636
5259
|
}
|
|
5637
|
-
function is_runtime(
|
|
5638
|
-
return !is_test_file(
|
|
5260
|
+
function is_runtime(path13, is_basic2 = false) {
|
|
5261
|
+
return !is_test_file(path13) && !is_exempt(path13, is_basic2);
|
|
5639
5262
|
}
|
|
5640
5263
|
function verdict_for2(paths, is_basic2 = false) {
|
|
5641
5264
|
const changed = normalize(paths);
|
|
5642
|
-
if (changed.some((
|
|
5643
|
-
if (changed.some((
|
|
5265
|
+
if (changed.some((path13) => is_test_file(path13))) return "satisfied";
|
|
5266
|
+
if (changed.some((path13) => is_runtime(path13, is_basic2))) return "required";
|
|
5644
5267
|
return "exempt";
|
|
5645
5268
|
}
|
|
5646
5269
|
function runtime_files(paths, is_basic2 = false) {
|
|
5647
|
-
return normalize(paths).filter((
|
|
5270
|
+
return normalize(paths).filter((path13) => is_runtime(path13, is_basic2));
|
|
5648
5271
|
}
|
|
5649
5272
|
function exempt_files(paths, is_basic2 = false) {
|
|
5650
|
-
return normalize(paths).filter((
|
|
5273
|
+
return normalize(paths).filter((path13) => is_exempt(path13, is_basic2));
|
|
5651
5274
|
}
|
|
5652
5275
|
function manual_check_files(paths, is_basic2) {
|
|
5653
|
-
return normalize(paths).filter((
|
|
5276
|
+
return normalize(paths).filter((path13) => is_exempt(path13, is_basic2) && !is_exempt(path13));
|
|
5654
5277
|
}
|
|
5655
5278
|
var test_declared_logic = {
|
|
5656
5279
|
EXEMPT_PATHS,
|
|
@@ -5709,9 +5332,9 @@ function is_untested_commit(call) {
|
|
|
5709
5332
|
if (!run_tail_rule.is_push_step_call(call)) return false;
|
|
5710
5333
|
return test_declared_changed.current_verdict() === "required";
|
|
5711
5334
|
}
|
|
5712
|
-
var REASON =
|
|
5713
|
-
var
|
|
5714
|
-
var test_declared_commit = { REASON, ROW:
|
|
5335
|
+
var REASON = "\u26D4 test declared: this commits a runtime code change with no test beside it \u2014 `pnpm josh test:declared` reads it `required` and names the files. Tests are required for ALL code changes: add the test and reissue, or, for a change that touches no runtime path, declare the non-runtime exception in your Step 0 work summary and reissue. It fires once per run (`CLAUDE.md` \u2192 Code Change Rules).";
|
|
5336
|
+
var ROW20 = { id: "test-declared", is_trigger: is_untested_commit, reason: REASON };
|
|
5337
|
+
var test_declared_commit = { REASON, ROW: ROW20 };
|
|
5715
5338
|
|
|
5716
5339
|
// scripts/rules/third-party-write.ts
|
|
5717
5340
|
function is_third_party_write_segment(segment, session_owner, resolve_placeholder_owners) {
|
|
@@ -5748,15 +5371,15 @@ function writes_third_party(command, resolve_owner = repo_party.current_owner, r
|
|
|
5748
5371
|
)
|
|
5749
5372
|
);
|
|
5750
5373
|
}
|
|
5751
|
-
var THIRD_PARTY_WRITE_REASON =
|
|
5752
|
-
var
|
|
5374
|
+
var THIRD_PARTY_WRITE_REASON = "\u26D4 third-party write: this `gh api` call writes to a repository whose owner is not this session, which is Tier C and needs explicit current-turn user instruction. Check with `pnpm josh repo:party <owner/repo>`, then record the finding on our own Issue and draft the artifact for a person to post. This rule fires on every occurrence (`prompts/collaboration-workflow/upstream-interrupt.md`).";
|
|
5375
|
+
var ROW21 = {
|
|
5753
5376
|
id: "third-party-write",
|
|
5754
5377
|
is_trigger: bash_triggers.on_bash_command((command) => writes_third_party(command)),
|
|
5755
5378
|
reason: THIRD_PARTY_WRITE_REASON,
|
|
5756
5379
|
decide: () => true
|
|
5757
5380
|
};
|
|
5758
5381
|
var third_party_write = {
|
|
5759
|
-
ROW:
|
|
5382
|
+
ROW: ROW21,
|
|
5760
5383
|
THIRD_PARTY_WRITE_REASON,
|
|
5761
5384
|
writes_third_party
|
|
5762
5385
|
};
|
|
@@ -5788,7 +5411,8 @@ var DELIVERED_RULES = [
|
|
|
5788
5411
|
reason: piped_verification.PIPED_VERIFICATION_REASON,
|
|
5789
5412
|
keeps: on_bash_command(piped_verification.keeps_verdict_intact),
|
|
5790
5413
|
reaches: on_bash_command(piped_verification.runs_verification),
|
|
5791
|
-
// A
|
|
5414
|
+
// A masking whose filter reads to the end is rewritten under `pipefail`, never refused.
|
|
5415
|
+
rewrite: piped_verification.pipefail_input,
|
|
5792
5416
|
rewrite_note: piped_verification.PIPEFAIL_NOTE
|
|
5793
5417
|
},
|
|
5794
5418
|
{
|
|
@@ -5827,6 +5451,7 @@ var DELIVERED_RULES = [
|
|
|
5827
5451
|
lane_split_park.ROW,
|
|
5828
5452
|
lane_park.ROW,
|
|
5829
5453
|
lane_interactive_ask.ROW,
|
|
5454
|
+
agent_model.ROW,
|
|
5830
5455
|
lane_carry_conflict.ROW,
|
|
5831
5456
|
lane_switch_main.ROW,
|
|
5832
5457
|
// Disjoint from `run-tail` by the `-y` flag.
|
|
@@ -5866,22 +5491,22 @@ var MEASURED_RULES = [
|
|
|
5866
5491
|
];
|
|
5867
5492
|
var BATCH_STAMP = hook_decision.create_refusal_stamp(time_batch_guard.STAMP_PREFIX);
|
|
5868
5493
|
var BATCH_REFUSAL_WINDOW_MS = 1e4;
|
|
5869
|
-
function will_batch_guard_refuse(tail, call,
|
|
5494
|
+
function will_batch_guard_refuse(tail, call, run) {
|
|
5870
5495
|
if (lane_guard_policy.mode_here("batching") !== "refuse") return false;
|
|
5871
|
-
const refused_at_ms = BATCH_STAMP.last_ms(BATCH_STAMP.path(
|
|
5872
|
-
if (
|
|
5496
|
+
const refused_at_ms = BATCH_STAMP.last_ms(BATCH_STAMP.path(run.transcript));
|
|
5497
|
+
if (run.now_ms - refused_at_ms < BATCH_REFUSAL_WINDOW_MS) return true;
|
|
5873
5498
|
return time_batch_guard.should_block(tail, call, refused_at_ms);
|
|
5874
5499
|
}
|
|
5875
|
-
function is_first_delivery(tail, call, delivered_at_ms,
|
|
5876
|
-
return delivered_at_ms === hook_decision.NEVER_MS && !will_batch_guard_refuse(tail, call,
|
|
5500
|
+
function is_first_delivery(tail, call, delivered_at_ms, run) {
|
|
5501
|
+
return delivered_at_ms === hook_decision.NEVER_MS && !will_batch_guard_refuse(tail, call, run);
|
|
5877
5502
|
}
|
|
5878
5503
|
function delivery_decision(rule) {
|
|
5879
|
-
const { decide:
|
|
5880
|
-
if (
|
|
5881
|
-
return function should_block(tail, call, delivered_at_ms,
|
|
5504
|
+
const { decide: decide5, already_satisfied } = rule;
|
|
5505
|
+
if (decide5 === void 0 && already_satisfied === void 0) return is_first_delivery;
|
|
5506
|
+
return function should_block(tail, call, delivered_at_ms, run) {
|
|
5882
5507
|
if (already_satisfied?.(tail, call) === true) return false;
|
|
5883
|
-
if (
|
|
5884
|
-
return
|
|
5508
|
+
if (decide5 === void 0) return true;
|
|
5509
|
+
return decide5(call, run, !will_batch_guard_refuse(tail, call, run), delivered_at_ms);
|
|
5885
5510
|
};
|
|
5886
5511
|
}
|
|
5887
5512
|
function guard_of(rule) {
|
|
@@ -5934,6 +5559,144 @@ var delivered_rules = {
|
|
|
5934
5559
|
is_issue_filing
|
|
5935
5560
|
};
|
|
5936
5561
|
|
|
5562
|
+
// scripts/rules/guard-remedy.ts
|
|
5563
|
+
var REWRITTEN = "the hook makes the same call right itself; it refuses only a spelling it cannot rewrite";
|
|
5564
|
+
var ANOTHER_TOOL = "the right form is another tool, which `updatedInput` cannot switch to";
|
|
5565
|
+
var ANOTHER_COMMAND = "the right act is another command, whose arguments the call does not carry";
|
|
5566
|
+
var NO_RUN = "the call must not run at all, or only on a person's word \u2014 refusing is the remedy";
|
|
5567
|
+
var STOP_NOTIFY = "the hook sends the notify itself; it blocks only when the send fails";
|
|
5568
|
+
var HOLD_RELEASE = "the hook releases the hold itself; it blocks only when that release fails";
|
|
5569
|
+
var ISSUE_CITATION = "the hook prints the citation lines itself; it blocks only on a number it cannot cite";
|
|
5570
|
+
var FILING_OFFER = "the filing needs a title and a body only the model can write";
|
|
5571
|
+
function rewrite() {
|
|
5572
|
+
return { remedy: "rewrite", why: REWRITTEN };
|
|
5573
|
+
}
|
|
5574
|
+
function judgment(why) {
|
|
5575
|
+
return { remedy: "judgment", why };
|
|
5576
|
+
}
|
|
5577
|
+
var GUARD_REMEDIES = {
|
|
5578
|
+
// The rewrites: each fix is the same call made right.
|
|
5579
|
+
"piped-verification": rewrite(),
|
|
5580
|
+
// wrapped in `(set -o pipefail; …)`
|
|
5581
|
+
"issue-comments": rewrite(),
|
|
5582
|
+
// the same Issue's comments read on the same line
|
|
5583
|
+
"lane-background": rewrite(),
|
|
5584
|
+
// a lane child's `ship` run in the foreground (`pretool-guard.ts`)
|
|
5585
|
+
"file-body": judgment(ANOTHER_TOOL),
|
|
5586
|
+
// Edit or Write
|
|
5587
|
+
"shell-body": judgment(
|
|
5588
|
+
"which part of the body the shell was meant to expand is the author's, not the hook's"
|
|
5589
|
+
),
|
|
5590
|
+
"raw-field-body": judgment("the body moves to a file the call does not name"),
|
|
5591
|
+
"rule-body": judgment("a trigger-plus-pointer line is written, not derived"),
|
|
5592
|
+
"direct-filing": judgment(ANOTHER_COMMAND),
|
|
5593
|
+
"direct-pr-create": judgment(ANOTHER_COMMAND),
|
|
5594
|
+
"josh-git-bare": judgment(ANOTHER_COMMAND),
|
|
5595
|
+
"run-tail": judgment(ANOTHER_COMMAND),
|
|
5596
|
+
"pre-gate-cut": judgment(ANOTHER_COMMAND),
|
|
5597
|
+
"implementation-cut": judgment(ANOTHER_COMMAND),
|
|
5598
|
+
"early-heartbeat": judgment(ANOTHER_COMMAND),
|
|
5599
|
+
"poll-loop": judgment(ANOTHER_COMMAND),
|
|
5600
|
+
"lane-park": judgment(ANOTHER_COMMAND),
|
|
5601
|
+
"lane-split-park": judgment(ANOTHER_COMMAND),
|
|
5602
|
+
"lane-interactive-ask": judgment(ANOTHER_COMMAND),
|
|
5603
|
+
"agent-model": judgment("which model fits the unit is the author's call"),
|
|
5604
|
+
"lane-carry-conflict": judgment(ANOTHER_COMMAND),
|
|
5605
|
+
"lane-switch-main": judgment(ANOTHER_COMMAND),
|
|
5606
|
+
"oracle-consulted": judgment(ANOTHER_COMMAND),
|
|
5607
|
+
"test-declared": judgment(ANOTHER_COMMAND),
|
|
5608
|
+
batching: judgment(ANOTHER_COMMAND),
|
|
5609
|
+
investigation: judgment(ANOTHER_COMMAND),
|
|
5610
|
+
"duplicate-read": judgment(ANOTHER_COMMAND),
|
|
5611
|
+
"run-watcher": judgment(ANOTHER_COMMAND),
|
|
5612
|
+
"parent-cut": judgment(ANOTHER_COMMAND),
|
|
5613
|
+
"issue-watch": judgment(ANOTHER_COMMAND),
|
|
5614
|
+
"third-party-write": judgment(NO_RUN),
|
|
5615
|
+
"filing-cap": judgment(NO_RUN),
|
|
5616
|
+
"git-force": judgment(NO_RUN),
|
|
5617
|
+
"worktree-mutation": judgment(NO_RUN),
|
|
5618
|
+
"index-mutation": judgment(NO_RUN),
|
|
5619
|
+
"destructive-command": judgment(NO_RUN),
|
|
5620
|
+
"protected-file": judgment(NO_RUN),
|
|
5621
|
+
// The `Stop` rows: the hook judges a finished reply, so it has no call to rewrite.
|
|
5622
|
+
"stop-notify": judgment(STOP_NOTIFY),
|
|
5623
|
+
"issue-citation": judgment(ISSUE_CITATION),
|
|
5624
|
+
"filing-offer": judgment(FILING_OFFER),
|
|
5625
|
+
"hold-release": judgment(HOLD_RELEASE)
|
|
5626
|
+
};
|
|
5627
|
+
var FAMILY_SEPARATOR = ":";
|
|
5628
|
+
function entry_of(id) {
|
|
5629
|
+
return GUARD_REMEDIES[id] ?? GUARD_REMEDIES[id.split(FAMILY_SEPARATOR)[0] ?? ""];
|
|
5630
|
+
}
|
|
5631
|
+
function remedy_of(id) {
|
|
5632
|
+
return entry_of(id)?.remedy;
|
|
5633
|
+
}
|
|
5634
|
+
function why_of(id) {
|
|
5635
|
+
return entry_of(id)?.why;
|
|
5636
|
+
}
|
|
5637
|
+
function is_rewrite(id) {
|
|
5638
|
+
return remedy_of(id) === "rewrite";
|
|
5639
|
+
}
|
|
5640
|
+
var guard_remedy = {
|
|
5641
|
+
GUARD_REMEDIES,
|
|
5642
|
+
is_rewrite,
|
|
5643
|
+
remedy_of,
|
|
5644
|
+
why_of
|
|
5645
|
+
};
|
|
5646
|
+
|
|
5647
|
+
// scripts/rules/rule-rewrite.ts
|
|
5648
|
+
var REWRITING_RULES = delivered_rules.DELIVERED_RULES.filter(
|
|
5649
|
+
(rule) => guard_remedy.is_rewrite(rule.id) && rule.rewrite !== void 0
|
|
5650
|
+
);
|
|
5651
|
+
var NOTE_SEPARATOR = "\n\n";
|
|
5652
|
+
function read_payload_tail(raw_payload) {
|
|
5653
|
+
try {
|
|
5654
|
+
const payload = hook_decision.parse_hook_payload(raw_payload);
|
|
5655
|
+
return payload ? time_density_hook.read_tail(
|
|
5656
|
+
time_hook_transcript.transcript_of(payload.transcript_path, payload.agent_id)
|
|
5657
|
+
) : "";
|
|
5658
|
+
} catch {
|
|
5659
|
+
return "";
|
|
5660
|
+
}
|
|
5661
|
+
}
|
|
5662
|
+
function tail_reader(raw_payload) {
|
|
5663
|
+
const cache = {};
|
|
5664
|
+
return function tail() {
|
|
5665
|
+
cache.tail ??= read_payload_tail(raw_payload);
|
|
5666
|
+
return cache.tail;
|
|
5667
|
+
};
|
|
5668
|
+
}
|
|
5669
|
+
function fold(name, typed, tail) {
|
|
5670
|
+
const folded = { input: typed, notes: [] };
|
|
5671
|
+
for (const rule of REWRITING_RULES) {
|
|
5672
|
+
const input = rule.rewrite?.({ name, input: folded.input }, tail);
|
|
5673
|
+
if (input === void 0) {
|
|
5674
|
+
continue;
|
|
5675
|
+
}
|
|
5676
|
+
folded.input = input;
|
|
5677
|
+
folded.notes = [...folded.notes, rule.rewrite_note ?? ""];
|
|
5678
|
+
}
|
|
5679
|
+
return folded;
|
|
5680
|
+
}
|
|
5681
|
+
function typed_payload(raw_payload) {
|
|
5682
|
+
const fields = json_value.parse_or_undefined(raw_payload);
|
|
5683
|
+
if (!json_value.is_record(fields)) return void 0;
|
|
5684
|
+
const input = fields["tool_input"];
|
|
5685
|
+
return json_value.is_record(input) ? { fields, name: String(fields["tool_name"]), input } : void 0;
|
|
5686
|
+
}
|
|
5687
|
+
function rewrite2(raw_payload) {
|
|
5688
|
+
const typed = delivered_rules.is_enabled() ? typed_payload(raw_payload) : void 0;
|
|
5689
|
+
if (typed === void 0) return void 0;
|
|
5690
|
+
const { input, notes } = fold(typed.name, typed.input, tail_reader(raw_payload));
|
|
5691
|
+
if (notes.length === 0) return void 0;
|
|
5692
|
+
const note = notes.join(NOTE_SEPARATOR);
|
|
5693
|
+
return { payload: JSON.stringify({ ...typed.fields, tool_input: input }), input, note };
|
|
5694
|
+
}
|
|
5695
|
+
var rule_rewrite = {
|
|
5696
|
+
NOTE_SEPARATOR,
|
|
5697
|
+
rewrite: rewrite2
|
|
5698
|
+
};
|
|
5699
|
+
|
|
5937
5700
|
// scripts/run/progress/run-progress-read.ts
|
|
5938
5701
|
import { loadavg } from "node:os";
|
|
5939
5702
|
|
|
@@ -6004,411 +5767,16 @@ var epic_busy = {
|
|
|
6004
5767
|
read_repository
|
|
6005
5768
|
};
|
|
6006
5769
|
|
|
6007
|
-
// scripts/run/run-liveness.ts
|
|
6008
|
-
import { readFileSync as readFileSync7, realpathSync, statSync } from "node:fs";
|
|
6009
|
-
import { homedir, tmpdir } from "node:os";
|
|
6010
|
-
import path14 from "node:path";
|
|
6011
|
-
import { setTimeout as sleep } from "node:timers/promises";
|
|
6012
|
-
|
|
6013
|
-
// scripts/agent/agent-event.ts
|
|
6014
|
-
import { z as z15 } from "zod";
|
|
6015
|
-
|
|
6016
|
-
// scripts/agent/claude-result-event.ts
|
|
6017
|
-
import { z as z14 } from "zod";
|
|
6018
|
-
var RESULT_EVENT_SCHEMA = z14.looseObject({
|
|
6019
|
-
type: z14.literal("result"),
|
|
6020
|
-
is_error: z14.unknown().optional(),
|
|
6021
|
-
subtype: z14.unknown().optional(),
|
|
6022
|
-
num_turns: z14.unknown().optional(),
|
|
6023
|
-
permission_denials: z14.unknown().optional(),
|
|
6024
|
-
result: z14.unknown().optional(),
|
|
6025
|
-
session_id: z14.unknown().optional(),
|
|
6026
|
-
usage: z14.unknown().optional()
|
|
6027
|
-
});
|
|
6028
|
-
var USAGE_SCHEMA = z14.looseObject({
|
|
6029
|
-
input_tokens: z14.unknown().optional(),
|
|
6030
|
-
cache_read_input_tokens: z14.unknown().optional(),
|
|
6031
|
-
output_tokens: z14.unknown().optional()
|
|
6032
|
-
});
|
|
6033
|
-
function usable_reason(value) {
|
|
6034
|
-
return typeof value === "string" && value.trim() !== "" ? value : void 0;
|
|
6035
|
-
}
|
|
6036
|
-
function numeric_value(value) {
|
|
6037
|
-
return typeof value === "number" ? value : void 0;
|
|
6038
|
-
}
|
|
6039
|
-
function denial_count(value) {
|
|
6040
|
-
return Array.isArray(value) ? value.length : 0;
|
|
6041
|
-
}
|
|
6042
|
-
function usage_of(value) {
|
|
6043
|
-
const parsed = USAGE_SCHEMA.safeParse(value);
|
|
6044
|
-
if (!parsed.success) return void 0;
|
|
6045
|
-
const usage = {
|
|
6046
|
-
input_tokens: numeric_value(parsed.data.input_tokens),
|
|
6047
|
-
cached_input_tokens: numeric_value(parsed.data.cache_read_input_tokens),
|
|
6048
|
-
output_tokens: numeric_value(parsed.data.output_tokens)
|
|
6049
|
-
};
|
|
6050
|
-
return Object.values(usage).some((count) => count !== void 0) ? usage : void 0;
|
|
6051
|
-
}
|
|
6052
|
-
function decode(value) {
|
|
6053
|
-
const parsed = RESULT_EVENT_SCHEMA.safeParse(value);
|
|
6054
|
-
if (!parsed.success) return void 0;
|
|
6055
|
-
const is_error = parsed.data.is_error === true;
|
|
6056
|
-
return {
|
|
6057
|
-
is_error,
|
|
6058
|
-
subtype: usable_reason(parsed.data.subtype),
|
|
6059
|
-
num_turns: numeric_value(parsed.data.num_turns),
|
|
6060
|
-
permission_denials: denial_count(parsed.data.permission_denials),
|
|
6061
|
-
refused_ask: interactive_ask.refused_ask_of(parsed.data.permission_denials),
|
|
6062
|
-
reason: is_error ? usable_reason(parsed.data.result) ?? usable_reason(parsed.data.subtype) : void 0,
|
|
6063
|
-
session_id: usable_reason(parsed.data.session_id),
|
|
6064
|
-
usage: usage_of(parsed.data.usage)
|
|
6065
|
-
};
|
|
6066
|
-
}
|
|
6067
|
-
var claude_result_event = { decode };
|
|
6068
|
-
|
|
6069
|
-
// scripts/agent/agent-event.ts
|
|
6070
|
-
var TEXT_BLOCK_SCHEMA = z15.looseObject({ type: z15.literal("text"), text: z15.string() });
|
|
6071
|
-
var CLAUDE_MESSAGE_SCHEMA = z15.looseObject({ content: z15.array(z15.unknown()).optional() });
|
|
6072
|
-
var CLAUDE_INIT_SCHEMA = z15.looseObject({ type: z15.literal("system"), subtype: z15.literal("init") });
|
|
6073
|
-
var CLAUDE_ASSISTANT_SCHEMA = z15.looseObject({
|
|
6074
|
-
type: z15.literal("assistant"),
|
|
6075
|
-
message: CLAUDE_MESSAGE_SCHEMA
|
|
6076
|
-
});
|
|
6077
|
-
var USAGE_SCHEMA2 = z15.looseObject({
|
|
6078
|
-
input_tokens: z15.number().optional(),
|
|
6079
|
-
cached_input_tokens: z15.number().optional(),
|
|
6080
|
-
output_tokens: z15.number().optional()
|
|
6081
|
-
});
|
|
6082
|
-
var CODEX_START_SCHEMA = z15.looseObject({ type: z15.enum(["thread.started", "turn.started"]) });
|
|
6083
|
-
var CODEX_PROGRESS_SCHEMA = z15.looseObject({
|
|
6084
|
-
type: z15.enum(["item.started", "item.updated", "item.completed"]),
|
|
6085
|
-
item: z15.looseObject({ type: z15.string(), text: z15.string().optional() }).optional()
|
|
6086
|
-
});
|
|
6087
|
-
var CODEX_COMPLETE_SCHEMA = z15.looseObject({
|
|
6088
|
-
type: z15.literal("turn.completed"),
|
|
6089
|
-
usage: USAGE_SCHEMA2.optional()
|
|
6090
|
-
});
|
|
6091
|
-
var CODEX_FAILURE_SCHEMA = z15.looseObject({
|
|
6092
|
-
type: z15.enum(["turn.failed", "error"]),
|
|
6093
|
-
error: z15.looseObject({ message: z15.string().optional() }).optional(),
|
|
6094
|
-
message: z15.string().optional()
|
|
6095
|
-
});
|
|
6096
|
-
var EMPTY_STATE = {
|
|
6097
|
-
provider: void 0,
|
|
6098
|
-
launch: "pending",
|
|
6099
|
-
progress: void 0,
|
|
6100
|
-
result: "running",
|
|
6101
|
-
reason: void 0,
|
|
6102
|
-
usage: void 0
|
|
6103
|
-
};
|
|
6104
|
-
var LAUNCH_HEADER_PREFIX = "=== ";
|
|
6105
|
-
var LAUNCH_HEADER_MARKER = " \xB7 started by process ";
|
|
6106
|
-
function usable_text(value) {
|
|
6107
|
-
return typeof value === "string" && value.trim() !== "" ? value : void 0;
|
|
6108
|
-
}
|
|
6109
|
-
function claude_progress(content) {
|
|
6110
|
-
return content.map((block) => TEXT_BLOCK_SCHEMA.safeParse(block)).filter((parsed) => parsed.success).map((parsed) => parsed.data.text).findLast((text) => text.trim() !== "");
|
|
6111
|
-
}
|
|
6112
|
-
function claude_result(value, state) {
|
|
6113
|
-
const result = claude_result_event.decode(value);
|
|
6114
|
-
if (result === void 0) return void 0;
|
|
6115
|
-
return {
|
|
6116
|
-
...state,
|
|
6117
|
-
provider: "anthropic",
|
|
6118
|
-
result: result.is_error ? "failed" : "completed",
|
|
6119
|
-
reason: result.is_error ? result.reason ?? state.reason : state.reason,
|
|
6120
|
-
usage: result.usage
|
|
6121
|
-
};
|
|
6122
|
-
}
|
|
6123
|
-
function claude_assistant(value, state) {
|
|
6124
|
-
const assistant = CLAUDE_ASSISTANT_SCHEMA.safeParse(value);
|
|
6125
|
-
if (!assistant.success) return void 0;
|
|
6126
|
-
const progress = claude_progress(assistant.data.message.content ?? []) ?? state.progress;
|
|
6127
|
-
return { ...state, provider: "anthropic", progress };
|
|
6128
|
-
}
|
|
6129
|
-
function claude_terminal(value, state) {
|
|
6130
|
-
return claude_result(value, state);
|
|
6131
|
-
}
|
|
6132
|
-
function claude_event(value, state) {
|
|
6133
|
-
if (CLAUDE_INIT_SCHEMA.safeParse(value).success) {
|
|
6134
|
-
return { ...state, provider: "anthropic", launch: "started" };
|
|
6135
|
-
}
|
|
6136
|
-
return claude_assistant(value, state) ?? claude_terminal(value, state);
|
|
6137
|
-
}
|
|
6138
|
-
function codex_progress(value, state) {
|
|
6139
|
-
const parsed = CODEX_PROGRESS_SCHEMA.safeParse(value);
|
|
6140
|
-
if (!parsed.success) return void 0;
|
|
6141
|
-
const progress = usable_text(parsed.data.item?.text) ?? state.progress;
|
|
6142
|
-
return { ...state, provider: "openai", progress };
|
|
6143
|
-
}
|
|
6144
|
-
function codex_completed(value, state) {
|
|
6145
|
-
const completed = CODEX_COMPLETE_SCHEMA.safeParse(value);
|
|
6146
|
-
if (!completed.success) return void 0;
|
|
6147
|
-
return { ...state, provider: "openai", result: "completed", usage: completed.data.usage };
|
|
6148
|
-
}
|
|
6149
|
-
function codex_failed(value, state) {
|
|
6150
|
-
const failed = CODEX_FAILURE_SCHEMA.safeParse(value);
|
|
6151
|
-
if (!failed.success) return void 0;
|
|
6152
|
-
const reason = usable_text(failed.data.error?.message) ?? usable_text(failed.data.message);
|
|
6153
|
-
return { ...state, provider: "openai", result: "failed", reason: reason ?? state.reason };
|
|
6154
|
-
}
|
|
6155
|
-
function codex_terminal(value, state) {
|
|
6156
|
-
return codex_completed(value, state) ?? codex_failed(value, state);
|
|
6157
|
-
}
|
|
6158
|
-
function codex_event(value, state) {
|
|
6159
|
-
if (CODEX_START_SCHEMA.safeParse(value).success) {
|
|
6160
|
-
return { ...state, provider: "openai", launch: "started" };
|
|
6161
|
-
}
|
|
6162
|
-
return codex_progress(value, state) ?? codex_terminal(value, state);
|
|
6163
|
-
}
|
|
6164
|
-
function normalized(value, state) {
|
|
6165
|
-
return claude_event(value, state) ?? codex_event(value, state) ?? state;
|
|
6166
|
-
}
|
|
6167
|
-
function next_state2(line, state) {
|
|
6168
|
-
const is_header = line.startsWith(LAUNCH_HEADER_PREFIX) && line.includes(LAUNCH_HEADER_MARKER);
|
|
6169
|
-
if (is_header) return EMPTY_STATE;
|
|
6170
|
-
return normalized(json_value.parse_or_undefined(line), state);
|
|
6171
|
-
}
|
|
6172
|
-
function read(transcript) {
|
|
6173
|
-
let state = EMPTY_STATE;
|
|
6174
|
-
for (const line of transcript.split("\n")) state = next_state2(line, state);
|
|
6175
|
-
return state;
|
|
6176
|
-
}
|
|
6177
|
-
function describe(state) {
|
|
6178
|
-
const progress = state.progress === void 0 ? "" : ` progress=${state.progress}`;
|
|
6179
|
-
const reason = state.reason === void 0 ? "" : ` reason=${state.reason}`;
|
|
6180
|
-
return `launch=${state.launch} result=${state.result}${progress}${reason}`;
|
|
6181
|
-
}
|
|
6182
|
-
var agent_event = { describe, read };
|
|
6183
|
-
|
|
6184
|
-
// scripts/issue/issue-state.ts
|
|
6185
|
-
import { z as z16 } from "zod";
|
|
6186
|
-
var NO_LABELS = "(none)";
|
|
6187
|
-
var LABEL_SEPARATOR = ", ";
|
|
6188
|
-
var STATE_LABEL = "state: ";
|
|
6189
|
-
var LABELS_LABEL = "labels: ";
|
|
6190
|
-
var HUMAN_REVIEW_LABEL_LINE = "human_review: ";
|
|
6191
|
-
var YES = "yes";
|
|
6192
|
-
var NO = "no";
|
|
6193
|
-
var ISSUE_LABEL = "issue: ";
|
|
6194
|
-
var HUMAN_REVIEW_LABELS = /* @__PURE__ */ new Set([NEEDS_HUMAN_REVIEW_LABEL]);
|
|
6195
|
-
var label_schema = z16.looseObject({ name: z16.string() });
|
|
6196
|
-
var issue_state_schema = z16.looseObject({
|
|
6197
|
-
state: z16.string(),
|
|
6198
|
-
labels: label_schema.array().optional()
|
|
6199
|
-
});
|
|
6200
|
-
function parse_issue_state(json) {
|
|
6201
|
-
try {
|
|
6202
|
-
const parsed = parse_json_object_or_undefined(json, issue_state_schema);
|
|
6203
|
-
if (parsed === void 0) return void 0;
|
|
6204
|
-
const labels = parsed.labels ?? [];
|
|
6205
|
-
return {
|
|
6206
|
-
state: parsed.state,
|
|
6207
|
-
labels: labels.map((label) => label.name),
|
|
6208
|
-
is_human_review: has_any_label(labels, HUMAN_REVIEW_LABELS)
|
|
6209
|
-
};
|
|
6210
|
-
} catch {
|
|
6211
|
-
return void 0;
|
|
6212
|
-
}
|
|
6213
|
-
}
|
|
6214
|
-
function format_labels(labels) {
|
|
6215
|
-
return labels.length === 0 ? NO_LABELS : labels.join(LABEL_SEPARATOR);
|
|
6216
|
-
}
|
|
6217
|
-
function format_issue_state(state) {
|
|
6218
|
-
const human_review = `${HUMAN_REVIEW_LABEL_LINE}${state.is_human_review ? YES : NO}`;
|
|
6219
|
-
return `${STATE_LABEL}${state.state}
|
|
6220
|
-
${LABELS_LABEL}${format_labels(state.labels)}
|
|
6221
|
-
${human_review}`;
|
|
6222
|
-
}
|
|
6223
|
-
function format_attributed_issue_state(issue_number, state) {
|
|
6224
|
-
return `${ISSUE_LABEL}${issue_number}
|
|
6225
|
-
${format_issue_state(state)}`;
|
|
6226
|
-
}
|
|
6227
|
-
var issue_state = {
|
|
6228
|
-
NO_LABELS,
|
|
6229
|
-
parse_issue_state,
|
|
6230
|
-
format_issue_state,
|
|
6231
|
-
format_attributed_issue_state
|
|
6232
|
-
};
|
|
6233
|
-
|
|
6234
|
-
// scripts/run/run-liveness.ts
|
|
6235
|
-
var ALIVE_VERDICT = "alive";
|
|
6236
|
-
var SETTLED_VERDICT = "settled";
|
|
6237
|
-
var STOPPED_VERDICT = "stopped";
|
|
6238
|
-
var UNDETERMINED_VERDICT = "undetermined";
|
|
6239
|
-
var PROCESS_ALIVE = "alive";
|
|
6240
|
-
var PROCESS_UNKNOWN = "unknown";
|
|
6241
|
-
var DEFAULT_SILENT_MINUTES = 30;
|
|
6242
|
-
var DEFAULT_GAP_SECONDS = 5;
|
|
6243
|
-
var MS_PER_MINUTE3 = 6e4;
|
|
6244
|
-
var MS_PER_SECOND2 = 1e3;
|
|
6245
|
-
var OPEN_STATE = "OPEN";
|
|
6246
|
-
var STATE_FIELDS = "state,labels";
|
|
6247
|
-
var REASONS = {
|
|
6248
|
-
[ALIVE_VERDICT]: "The unit is still working: its output moved, or a process of the child is alive.",
|
|
6249
|
-
[SETTLED_VERDICT]: "The child is closed, parked with `needs-decision`, or marked `already-done`, so there is nothing here to recover.",
|
|
6250
|
-
[STOPPED_VERDICT]: "The output has been frozen past the silent window and no process of the child is alive in that checkout.",
|
|
6251
|
-
[UNDETERMINED_VERDICT]: "A trace could not be read, so this says nothing about the unit. A trace that could not be read answers `undetermined`, never `stopped`."
|
|
6252
|
-
};
|
|
6253
|
-
var ALIVE_ADVICE = "Keep polling; do not touch the child.";
|
|
6254
|
-
var SETTLED_ADVICE = "Read the child with `pnpm josh issue:state <N>` and take the branch its state says.";
|
|
6255
|
-
var STOPPED_CLEAN_ADVICE = 'The unit ended \u2014 classify how before booking it. Run `pnpm josh run:merge <N> --output <path>` (add `--epic <E> --repo <owner/repo> --owner "$PPID"` for a named epic): it reads the child\'s exit record without waiting for the unit to return, re-dispatches a child that could not reach the API (counting the outage; a run of them trips the environment guard and stops the run), and parks an abandoned child with `needs-decision` against the consecutive-failure guard. The checkout is clean, so there is nothing to stash.';
|
|
6256
|
-
var STOPPED_DIRTY_ADVICE = 'Stash the half-finished work with `git stash push -u -m "backlogrun: stopped unit for #<N>"` and record it on the Issue, then classify how the unit ended with `pnpm josh run:merge <N> --output <path>` (add `--epic <E> --repo <owner/repo> --owner "$PPID"` for a named epic): it re-dispatches an API-outage child (counting the outage; a run of them trips the environment guard) and parks an abandoned child with `needs-decision` against the consecutive-failure guard, without waiting for the unit to return.';
|
|
6257
|
-
var UNDETERMINED_ADVICE = "Read the trace that failed and ask again. Where the process trace was given as `unknown`, leave `--process` out so the command reads it. Two of these in a row is a fault in the check itself rather than a slow unit: stop polling and report it.";
|
|
6258
|
-
function is_output_moving(traces) {
|
|
6259
|
-
return traces.is_output_frozen === false;
|
|
6260
|
-
}
|
|
6261
|
-
function is_agent_state_finished(state) {
|
|
6262
|
-
return state?.result === "completed" || state?.result === "failed";
|
|
6263
|
-
}
|
|
6264
|
-
function is_agent_finished(traces) {
|
|
6265
|
-
return is_agent_state_finished(traces.agent_state);
|
|
6266
|
-
}
|
|
6267
|
-
function definitive_verdict(traces) {
|
|
6268
|
-
if (traces.is_child_settled === true) return SETTLED_VERDICT;
|
|
6269
|
-
if (is_agent_finished(traces)) return STOPPED_VERDICT;
|
|
6270
|
-
if (is_output_moving(traces)) return ALIVE_VERDICT;
|
|
6271
|
-
return void 0;
|
|
6272
|
-
}
|
|
6273
|
-
function is_check_running(traces) {
|
|
6274
|
-
return traces.process_trace === PROCESS_ALIVE;
|
|
6275
|
-
}
|
|
6276
|
-
function has_unreadable_trace(traces) {
|
|
6277
|
-
return traces.is_child_settled === void 0 || traces.is_output_frozen === void 0 || traces.process_trace === PROCESS_UNKNOWN;
|
|
6278
|
-
}
|
|
6279
|
-
function to_verdict(traces) {
|
|
6280
|
-
const definitive = definitive_verdict(traces);
|
|
6281
|
-
if (definitive !== void 0) return definitive;
|
|
6282
|
-
if (has_unreadable_trace(traces)) return UNDETERMINED_VERDICT;
|
|
6283
|
-
return is_check_running(traces) ? ALIVE_VERDICT : STOPPED_VERDICT;
|
|
6284
|
-
}
|
|
6285
|
-
function to_advice(verdict, has_work_to_stash) {
|
|
6286
|
-
if (verdict === ALIVE_VERDICT) return ALIVE_ADVICE;
|
|
6287
|
-
if (verdict === SETTLED_VERDICT) return SETTLED_ADVICE;
|
|
6288
|
-
if (verdict === UNDETERMINED_VERDICT) return UNDETERMINED_ADVICE;
|
|
6289
|
-
return has_work_to_stash ? STOPPED_DIRTY_ADVICE : STOPPED_CLEAN_ADVICE;
|
|
6290
|
-
}
|
|
6291
|
-
function decide5(traces) {
|
|
6292
|
-
const verdict = to_verdict(traces);
|
|
6293
|
-
const has_work_to_stash = verdict === STOPPED_VERDICT && traces.is_tree_dirty;
|
|
6294
|
-
return {
|
|
6295
|
-
advice: to_advice(verdict, has_work_to_stash),
|
|
6296
|
-
has_work_to_stash,
|
|
6297
|
-
reason: traces.agent_state?.reason ?? REASONS[verdict],
|
|
6298
|
-
verdict
|
|
6299
|
-
};
|
|
6300
|
-
}
|
|
6301
|
-
function to_resolved_root(root) {
|
|
6302
|
-
try {
|
|
6303
|
-
return realpathSync(root);
|
|
6304
|
-
} catch {
|
|
6305
|
-
return root;
|
|
6306
|
-
}
|
|
6307
|
-
}
|
|
6308
|
-
var ALLOWED_ROOTS = [
|
|
6309
|
-
...new Set(
|
|
6310
|
-
[homedir(), tmpdir(), PLATFORM_TEMP_ROOT].flatMap((root) => [root, to_resolved_root(root)])
|
|
6311
|
-
)
|
|
6312
|
-
];
|
|
6313
|
-
function is_within(candidate, root) {
|
|
6314
|
-
const relative = path14.relative(root, candidate);
|
|
6315
|
-
return relative !== "" && !relative.startsWith("..") && !path14.isAbsolute(relative);
|
|
6316
|
-
}
|
|
6317
|
-
function to_safe_path(output_path) {
|
|
6318
|
-
const normalized2 = path14.normalize(output_path);
|
|
6319
|
-
if (!path14.isAbsolute(normalized2)) return void 0;
|
|
6320
|
-
return ALLOWED_ROOTS.some((root) => is_within(normalized2, root)) ? normalized2 : void 0;
|
|
6321
|
-
}
|
|
6322
|
-
function sample_output(output_path) {
|
|
6323
|
-
const safe_path = to_safe_path(output_path);
|
|
6324
|
-
if (safe_path === void 0) return void 0;
|
|
6325
|
-
const stats = statSync(safe_path, { throwIfNoEntry: false });
|
|
6326
|
-
if (!stats?.isFile()) return void 0;
|
|
6327
|
-
return { mtime_ms: stats.mtimeMs, size: stats.size };
|
|
6328
|
-
}
|
|
6329
|
-
function read_agent_state(output_path) {
|
|
6330
|
-
const safe_path = to_safe_path(output_path);
|
|
6331
|
-
if (safe_path === void 0) return void 0;
|
|
6332
|
-
try {
|
|
6333
|
-
const state = agent_event.read(readFileSync7(safe_path, "utf8"));
|
|
6334
|
-
return state.provider === void 0 ? void 0 : state;
|
|
6335
|
-
} catch {
|
|
6336
|
-
return void 0;
|
|
6337
|
-
}
|
|
6338
|
-
}
|
|
6339
|
-
function describe_agent_state(output_path) {
|
|
6340
|
-
const state = read_agent_state(output_path);
|
|
6341
|
-
return state === void 0 ? void 0 : `agent: ${state.provider ?? "unknown"} ${agent_event.describe(state)}`;
|
|
6342
|
-
}
|
|
6343
|
-
async function read_output_frozen(request2) {
|
|
6344
|
-
const first = sample_output(request2.output_path);
|
|
6345
|
-
if (first === void 0) return void 0;
|
|
6346
|
-
if (request2.now_ms - first.mtime_ms < request2.silent_window_ms) return false;
|
|
6347
|
-
await sleep(request2.gap_ms);
|
|
6348
|
-
const second = sample_output(request2.output_path);
|
|
6349
|
-
if (second === void 0) return void 0;
|
|
6350
|
-
return second.mtime_ms === first.mtime_ms && second.size === first.size;
|
|
6351
|
-
}
|
|
6352
|
-
function carries_label(labels, wanted) {
|
|
6353
|
-
return labels.some((label) => label.toLowerCase() === wanted);
|
|
6354
|
-
}
|
|
6355
|
-
var SETTLED_LABELS = [NEEDS_DECISION_LABEL, ALREADY_DONE_LABEL];
|
|
6356
|
-
function carries_settled_label(labels) {
|
|
6357
|
-
return SETTLED_LABELS.some((label) => carries_label(labels, label));
|
|
6358
|
-
}
|
|
6359
|
-
async function read_child_settled(issue, repo) {
|
|
6360
|
-
const json = await git_gh_issue_read.issue_view_json(issue, STATE_FIELDS, repo);
|
|
6361
|
-
if (json === void 0) return void 0;
|
|
6362
|
-
const state = issue_state.parse_issue_state(json);
|
|
6363
|
-
if (state === void 0) return void 0;
|
|
6364
|
-
return state.state !== OPEN_STATE || carries_settled_label(state.labels);
|
|
6365
|
-
}
|
|
6366
|
-
async function read_traces(request2) {
|
|
6367
|
-
const [is_initial_child_settled, is_output_frozen, is_tree_dirty] = await Promise.all([
|
|
6368
|
-
read_child_settled(request2.issue, request2.repo),
|
|
6369
|
-
read_output_frozen({
|
|
6370
|
-
gap_ms: request2.gap_ms ?? DEFAULT_GAP_SECONDS * MS_PER_SECOND2,
|
|
6371
|
-
now_ms: Date.now(),
|
|
6372
|
-
output_path: request2.output_path,
|
|
6373
|
-
silent_window_ms: request2.silent_window_ms ?? DEFAULT_SILENT_MINUTES * MS_PER_MINUTE3
|
|
6374
|
-
}),
|
|
6375
|
-
run_hold.is_tree_dirty()
|
|
6376
|
-
]);
|
|
6377
|
-
const agent_state = read_agent_state(request2.output_path);
|
|
6378
|
-
const is_latest_child_settled = is_agent_state_finished(agent_state) ? await read_child_settled(request2.issue, request2.repo) : void 0;
|
|
6379
|
-
const is_child_settled = is_latest_child_settled ?? is_initial_child_settled;
|
|
6380
|
-
return {
|
|
6381
|
-
agent_state,
|
|
6382
|
-
is_child_settled,
|
|
6383
|
-
is_output_frozen,
|
|
6384
|
-
is_tree_dirty,
|
|
6385
|
-
process_trace: request2.process_trace
|
|
6386
|
-
};
|
|
6387
|
-
}
|
|
6388
|
-
async function check2(request2) {
|
|
6389
|
-
issue_number_shape.require_issue_number(request2.issue);
|
|
6390
|
-
return decide5(await read_traces(request2));
|
|
6391
|
-
}
|
|
6392
|
-
var run_liveness = {
|
|
6393
|
-
check: check2,
|
|
6394
|
-
decide: decide5,
|
|
6395
|
-
describe_agent_state,
|
|
6396
|
-
read_child_settled,
|
|
6397
|
-
read_output_frozen,
|
|
6398
|
-
sample_output,
|
|
6399
|
-
to_safe_path
|
|
6400
|
-
};
|
|
6401
|
-
|
|
6402
5770
|
// scripts/lane/lane-report.ts
|
|
6403
5771
|
var NO_LANES2 = "No lanes are open.";
|
|
6404
|
-
var
|
|
5772
|
+
var OPEN_STATE = "open";
|
|
6405
5773
|
var STRANDED_STATE = "stranded";
|
|
6406
5774
|
var UNREADABLE_STATE = "unreadable";
|
|
6407
5775
|
var UNKNOWN_VALUE = "-";
|
|
6408
5776
|
var COLUMN_SEPARATOR = " ";
|
|
6409
5777
|
function lane_state(lane) {
|
|
6410
5778
|
if (lane.is_stranded) return STRANDED_STATE;
|
|
6411
|
-
return lane.seat === void 0 ? UNREADABLE_STATE :
|
|
5779
|
+
return lane.seat === void 0 ? UNREADABLE_STATE : OPEN_STATE;
|
|
6412
5780
|
}
|
|
6413
5781
|
function value_or_unknown(value) {
|
|
6414
5782
|
return value === void 0 ? UNKNOWN_VALUE : String(value);
|
|
@@ -6452,7 +5820,7 @@ function describe_opened(lane) {
|
|
|
6452
5820
|
}
|
|
6453
5821
|
var lane_report = {
|
|
6454
5822
|
NO_LANES: NO_LANES2,
|
|
6455
|
-
OPEN_STATE
|
|
5823
|
+
OPEN_STATE,
|
|
6456
5824
|
STRANDED_STATE,
|
|
6457
5825
|
UNREADABLE_STATE,
|
|
6458
5826
|
describe_lane,
|
|
@@ -6461,198 +5829,6 @@ var lane_report = {
|
|
|
6461
5829
|
lane_state
|
|
6462
5830
|
};
|
|
6463
5831
|
|
|
6464
|
-
// scripts/run/run-preflight.ts
|
|
6465
|
-
import { z as z17 } from "zod";
|
|
6466
|
-
var CLEAN_VERDICT = "clean";
|
|
6467
|
-
var RECLAIM_VERDICT = "reclaim";
|
|
6468
|
-
var RESUME_VERDICT = "resume";
|
|
6469
|
-
var PARK_VERDICT = "park";
|
|
6470
|
-
var NO_PR = "none";
|
|
6471
|
-
var OPEN_PR = "open";
|
|
6472
|
-
var MERGED_PR = "merged";
|
|
6473
|
-
var CLOSED_PR = "closed";
|
|
6474
|
-
var NO_CHILD_WORK = { branch_name: void 0, pr_state: NO_PR };
|
|
6475
|
-
var pr_info_schema = z17.object({ state: z17.string().optional() });
|
|
6476
|
-
var GH_PR_STATES = /* @__PURE__ */ new Map([
|
|
6477
|
-
["CLOSED", CLOSED_PR],
|
|
6478
|
-
["MERGED", MERGED_PR],
|
|
6479
|
-
["OPEN", OPEN_PR]
|
|
6480
|
-
]);
|
|
6481
|
-
var CLEAN_REASON = "Nothing was left behind: the tree is clean, HEAD is on the default branch, and this issue has no pull request and no branch holding work.";
|
|
6482
|
-
var CLEAN_ADVICE = "Start the child.";
|
|
6483
|
-
var RESUME_ADVICE = "Reuse the branch and run the whole verification gate from the start \u2014 refactor, `pnpm josh gate`, `/code-review` \u2014 never only the part the interrupted run had not reached. Nobody verified what it already committed.";
|
|
6484
|
-
var PARK_ADVICE = "Park the child: add `needs-decision` and comment what was found. Do not delete the branch, do not reopen the pull request, and do not commit on top of it.";
|
|
6485
|
-
var STASH_LABEL_PREFIX = "run:hold reclaimed before #";
|
|
6486
|
-
var { require_issue_number } = issue_number_shape;
|
|
6487
|
-
var UNREADABLE_PR_MESSAGE = "The pull request could not be read for branch ";
|
|
6488
|
-
function needs_reclaim(tree) {
|
|
6489
|
-
return tree.is_dirty || tree.branch !== tree.default_branch;
|
|
6490
|
-
}
|
|
6491
|
-
function is_pr_decided(state) {
|
|
6492
|
-
return state === MERGED_PR || state === CLOSED_PR;
|
|
6493
|
-
}
|
|
6494
|
-
function has_leftover_work(child) {
|
|
6495
|
-
return child.branch_name !== void 0 || child.pr_state === OPEN_PR;
|
|
6496
|
-
}
|
|
6497
|
-
function to_verdict2(tree, child) {
|
|
6498
|
-
if (needs_reclaim(tree)) return RECLAIM_VERDICT;
|
|
6499
|
-
if (is_pr_decided(child.pr_state)) return PARK_VERDICT;
|
|
6500
|
-
if (has_leftover_work(child)) return RESUME_VERDICT;
|
|
6501
|
-
return CLEAN_VERDICT;
|
|
6502
|
-
}
|
|
6503
|
-
function reclaim_reason(tree) {
|
|
6504
|
-
const findings = [
|
|
6505
|
-
tree.is_dirty ? "uncommitted changes" : void 0,
|
|
6506
|
-
tree.branch === tree.default_branch ? void 0 : `HEAD on ${tree.branch}`
|
|
6507
|
-
].filter((entry) => entry !== void 0);
|
|
6508
|
-
return `An earlier run left ${findings.join(" and ")} in this working tree.`;
|
|
6509
|
-
}
|
|
6510
|
-
function park_reason(state) {
|
|
6511
|
-
return `The pull request for this issue is ${state}, so whether any work is still owed is a person's call.`;
|
|
6512
|
-
}
|
|
6513
|
-
function resume_reason(child) {
|
|
6514
|
-
const branch_part = child.branch_name === void 0 ? "" : ` on branch ${child.branch_name}`;
|
|
6515
|
-
const pr_part = child.pr_state === OPEN_PR ? ", and its pull request is still open" : "";
|
|
6516
|
-
return `An earlier run left a partial implementation${branch_part}${pr_part}.`;
|
|
6517
|
-
}
|
|
6518
|
-
function to_reason(verdict, tree, child) {
|
|
6519
|
-
if (verdict === RECLAIM_VERDICT) return reclaim_reason(tree);
|
|
6520
|
-
if (verdict === PARK_VERDICT) return park_reason(child.pr_state);
|
|
6521
|
-
if (verdict === RESUME_VERDICT) return resume_reason(child);
|
|
6522
|
-
return CLEAN_REASON;
|
|
6523
|
-
}
|
|
6524
|
-
function reclaim_steps(tree, issue) {
|
|
6525
|
-
if (!tree.is_dirty) return [];
|
|
6526
|
-
return [
|
|
6527
|
-
`git stash push -u -m "${STASH_LABEL_PREFIX}${issue}"`,
|
|
6528
|
-
`Record the stash on ${session_cite.issue(issue)} \u2014 the comment is what gets it popped; nothing pops it for you.`
|
|
6529
|
-
];
|
|
6530
|
-
}
|
|
6531
|
-
function reclaim_advice(tree, issue) {
|
|
6532
|
-
return [
|
|
6533
|
-
...reclaim_steps(tree, issue),
|
|
6534
|
-
"pnpm josh ms",
|
|
6535
|
-
"Then ask this command again: it is re-askable, and the clean tree gets its own answer."
|
|
6536
|
-
].join("\n");
|
|
6537
|
-
}
|
|
6538
|
-
function to_advice2(verdict, issue, tree) {
|
|
6539
|
-
if (verdict === RECLAIM_VERDICT) return reclaim_advice(tree, issue);
|
|
6540
|
-
if (verdict === RESUME_VERDICT) return RESUME_ADVICE;
|
|
6541
|
-
if (verdict === PARK_VERDICT) return PARK_ADVICE;
|
|
6542
|
-
return CLEAN_ADVICE;
|
|
6543
|
-
}
|
|
6544
|
-
function decide6(tree, child, issue) {
|
|
6545
|
-
const verdict = to_verdict2(tree, child);
|
|
6546
|
-
return {
|
|
6547
|
-
advice: to_advice2(verdict, issue, tree),
|
|
6548
|
-
reason: to_reason(verdict, tree, child),
|
|
6549
|
-
verdict
|
|
6550
|
-
};
|
|
6551
|
-
}
|
|
6552
|
-
function read_pr_field(raw) {
|
|
6553
|
-
return json_value.parse_with(raw, pr_info_schema)?.state;
|
|
6554
|
-
}
|
|
6555
|
-
function to_pr_state(raw) {
|
|
6556
|
-
const state = read_pr_field(raw);
|
|
6557
|
-
return (state === void 0 ? void 0 : GH_PR_STATES.get(state)) ?? NO_PR;
|
|
6558
|
-
}
|
|
6559
|
-
async function read_tree_state() {
|
|
6560
|
-
const [is_dirty, current, default_branch] = await Promise.all([
|
|
6561
|
-
run_hold.is_tree_dirty(),
|
|
6562
|
-
git_command.branch(),
|
|
6563
|
-
git_command.get_default_branch()
|
|
6564
|
-
]);
|
|
6565
|
-
return { branch: current, default_branch, is_dirty };
|
|
6566
|
-
}
|
|
6567
|
-
async function read_pr_state(branch_name) {
|
|
6568
|
-
if (!await git_gh_pr_read.pr_exists(branch_name)) return NO_PR;
|
|
6569
|
-
const raw = await git_gh_pr_read.pr_view(branch_name);
|
|
6570
|
-
if (raw === "") throw new Error(`${UNREADABLE_PR_MESSAGE}${branch_name}`);
|
|
6571
|
-
return to_pr_state(raw);
|
|
6572
|
-
}
|
|
6573
|
-
function is_pr_open(state) {
|
|
6574
|
-
return state === OPEN_PR;
|
|
6575
|
-
}
|
|
6576
|
-
async function read_pr_of_branch(branch_name) {
|
|
6577
|
-
return { branch_name, pr_state: await read_pr_state(branch_name) };
|
|
6578
|
-
}
|
|
6579
|
-
function pick_child_state(reads) {
|
|
6580
|
-
const decided = reads.find((read2) => is_pr_decided(read2.pr_state));
|
|
6581
|
-
const open = reads.find((read2) => is_pr_open(read2.pr_state));
|
|
6582
|
-
return decided ?? open ?? { branch_name: reads[0]?.branch_name, pr_state: NO_PR };
|
|
6583
|
-
}
|
|
6584
|
-
var ISSUE_BRANCH_SUFFIX = "-*";
|
|
6585
|
-
var ANY_REMOTE_PREFIX = "*/";
|
|
6586
|
-
var REMOTE_SEPARATOR = "/";
|
|
6587
|
-
var NOT_FOUND_INDEX = -1;
|
|
6588
|
-
function to_head_branch(name) {
|
|
6589
|
-
const separator_index = name.indexOf(REMOTE_SEPARATOR);
|
|
6590
|
-
return separator_index === NOT_FOUND_INDEX ? name : name.slice(separator_index + 1);
|
|
6591
|
-
}
|
|
6592
|
-
function group_by_head(pairs) {
|
|
6593
|
-
const groups = /* @__PURE__ */ new Map();
|
|
6594
|
-
for (const [name, reference] of pairs) groups.set(name, [...groups.get(name) ?? [], reference]);
|
|
6595
|
-
return groups;
|
|
6596
|
-
}
|
|
6597
|
-
async function read_branch_candidates(issue) {
|
|
6598
|
-
const pattern = `${issue}${ISSUE_BRANCH_SUFFIX}`;
|
|
6599
|
-
const [local, remote] = await Promise.all([
|
|
6600
|
-
git_command.branch_names(pattern),
|
|
6601
|
-
git_command.branch_names_remote(`${ANY_REMOTE_PREFIX}${pattern}`)
|
|
6602
|
-
]);
|
|
6603
|
-
return group_by_head([
|
|
6604
|
-
...local.map((name) => [name, name]),
|
|
6605
|
-
...remote.map((reference) => [to_head_branch(reference), reference])
|
|
6606
|
-
]);
|
|
6607
|
-
}
|
|
6608
|
-
async function has_commits_beyond(base, references) {
|
|
6609
|
-
const counts = await Promise.all(
|
|
6610
|
-
references.map(async (reference) => await git_command.commit_count_beyond(base, reference))
|
|
6611
|
-
);
|
|
6612
|
-
return counts.some((count) => count > 0);
|
|
6613
|
-
}
|
|
6614
|
-
async function is_held_dirty(name, lane) {
|
|
6615
|
-
if (lane?.branch !== name || lane.is_stranded) return false;
|
|
6616
|
-
return await run_hold.is_tree_dirty(lane.directory);
|
|
6617
|
-
}
|
|
6618
|
-
async function read_candidate(name, references, context) {
|
|
6619
|
-
const state = await read_pr_of_branch(name);
|
|
6620
|
-
if (state.pr_state !== NO_PR) return state;
|
|
6621
|
-
if (await has_commits_beyond(context.base, references)) return state;
|
|
6622
|
-
return await is_held_dirty(name, context.lane) ? state : void 0;
|
|
6623
|
-
}
|
|
6624
|
-
async function read_child_state(issue) {
|
|
6625
|
-
const candidates = await read_branch_candidates(issue);
|
|
6626
|
-
if (candidates.size === 0) return NO_CHILD_WORK;
|
|
6627
|
-
const [base, lane] = await Promise.all([
|
|
6628
|
-
git_command.default_branch_reference(),
|
|
6629
|
-
lane_registry.find_open_lane(issue)
|
|
6630
|
-
]);
|
|
6631
|
-
const reads = await Promise.all(
|
|
6632
|
-
[...candidates].map(
|
|
6633
|
-
async ([name, references]) => await read_candidate(name, references, { base, lane })
|
|
6634
|
-
)
|
|
6635
|
-
);
|
|
6636
|
-
return pick_child_state(reads.filter((read2) => read2 !== void 0));
|
|
6637
|
-
}
|
|
6638
|
-
async function check3(issue) {
|
|
6639
|
-
require_issue_number(issue);
|
|
6640
|
-
const tree = await read_tree_state();
|
|
6641
|
-
if (needs_reclaim(tree)) return decide6(tree, NO_CHILD_WORK, issue);
|
|
6642
|
-
return decide6(tree, await read_child_state(issue), issue);
|
|
6643
|
-
}
|
|
6644
|
-
var run_preflight = {
|
|
6645
|
-
CLEAN_VERDICT,
|
|
6646
|
-
RESUME_ADVICE,
|
|
6647
|
-
MERGED_PR,
|
|
6648
|
-
STASH_LABEL_PREFIX,
|
|
6649
|
-
check: check3,
|
|
6650
|
-
decide: decide6,
|
|
6651
|
-
read_child_state,
|
|
6652
|
-
read_pr_state,
|
|
6653
|
-
to_pr_state
|
|
6654
|
-
};
|
|
6655
|
-
|
|
6656
5832
|
// scripts/run/progress/run-progress-read.ts
|
|
6657
5833
|
var { mark: mark2, parse_stamp: parse_stamp2, read_last_report: read_last_report2 } = run_progress_clock;
|
|
6658
5834
|
var FIRST_LOAD_AVERAGE = 0;
|
|
@@ -6745,35 +5921,36 @@ var run_progress_read = {
|
|
|
6745
5921
|
};
|
|
6746
5922
|
|
|
6747
5923
|
// scripts/run/run-watcher-hook.ts
|
|
6748
|
-
import { z as
|
|
5924
|
+
import { z as z13 } from "zod";
|
|
6749
5925
|
|
|
6750
5926
|
// scripts/run/run-watcher-guard.ts
|
|
6751
5927
|
var WATCHER_TICK_MS = 3e4;
|
|
6752
5928
|
var TICK_MULTIPLIER = 3;
|
|
6753
|
-
var
|
|
5929
|
+
var MS_PER_SECOND2 = 1e3;
|
|
6754
5930
|
var STALE_THRESHOLD_MS = WATCHER_TICK_MS * TICK_MULTIPLIER;
|
|
6755
|
-
var STALE_THRESHOLD_S = STALE_THRESHOLD_MS /
|
|
5931
|
+
var STALE_THRESHOLD_S = STALE_THRESHOLD_MS / MS_PER_SECOND2;
|
|
6756
5932
|
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. It reports to the run event stream on its own and exits only when newly runnable work arrives, so start it once and relay nothing`;
|
|
6757
5933
|
var OK_RESULT = { kind: "ok" };
|
|
6758
5934
|
async function owes_watcher() {
|
|
6759
5935
|
if (run_headless.is_headless() || !await run_headless.is_backlog_parent()) return false;
|
|
6760
5936
|
return await lane_registry.has_lanes_in_flight();
|
|
6761
5937
|
}
|
|
6762
|
-
async function
|
|
6763
|
-
if (!await owes_watcher())
|
|
6764
|
-
|
|
5938
|
+
async function check2(life_target) {
|
|
5939
|
+
if (!await owes_watcher() || run_progress_clock.is_life_fresh(life_target, STALE_THRESHOLD_MS)) {
|
|
5940
|
+
return OK_RESULT;
|
|
5941
|
+
}
|
|
6765
5942
|
return { kind: "stale", note: STALE_NOTE };
|
|
6766
5943
|
}
|
|
6767
5944
|
var run_watcher_guard = {
|
|
6768
5945
|
STALE_NOTE,
|
|
6769
5946
|
STALE_THRESHOLD_MS,
|
|
6770
|
-
check:
|
|
5947
|
+
check: check2
|
|
6771
5948
|
};
|
|
6772
5949
|
|
|
6773
5950
|
// scripts/run/run-watcher-hook.ts
|
|
6774
5951
|
var SWITCH_ENV_KEY2 = "JOSH_WATCHER_GUARD";
|
|
6775
5952
|
var STAMP_PREFIX2 = "josh-watcher-guard-";
|
|
6776
|
-
var payload_schema =
|
|
5953
|
+
var payload_schema = z13.object({ transcript_path: z13.string().min(1) });
|
|
6777
5954
|
function transcript_of(raw_payload) {
|
|
6778
5955
|
return json_value.parse_with(raw_payload, payload_schema)?.transcript_path;
|
|
6779
5956
|
}
|
|
@@ -6803,14 +5980,14 @@ var run_watcher_hook = { transcript_of, watcher_hook_reason };
|
|
|
6803
5980
|
var SWITCH_ENV_KEY3 = "JOSH_PARENT_CUT_GUARD";
|
|
6804
5981
|
var STAMP_PREFIX3 = "josh-parent-cut-guard-";
|
|
6805
5982
|
var QUIET_WINDOW_MS = 6e5;
|
|
6806
|
-
function
|
|
5983
|
+
function current_state2() {
|
|
6807
5984
|
return {
|
|
6808
5985
|
carry: async () => await run_headless.driving_carry(),
|
|
6809
5986
|
verdict: () => implementation_cut_verdict.reused_verdict(() => cost_cli.session_verdict())
|
|
6810
5987
|
};
|
|
6811
5988
|
}
|
|
6812
5989
|
var THRESHOLD_TEXT2 = `${cost_format.format_tokens(CONTEXT_CUT_THRESHOLD)}-token`;
|
|
6813
|
-
var PARENT_CUT_REASON = `\u26D4 backlogrun parent hand-off: this session drives a \`backlogrun\`
|
|
5990
|
+
var PARENT_CUT_REASON = `\u26D4 backlogrun parent hand-off: this session drives a \`backlogrun\` and its recent-context cost crossed the ${THRESHOLD_TEXT2} threshold between merges. Take the hand-off now: open no new lane, follow \`backlogrun-progress.md\` \u2192 "The hand-off" (\`pnpm josh run:carry --cut --owner "$PPID"\`, then \`pnpm josh run:wake\` unless \`capped\`) and end the turn. Reissue this call once done or if it cannot be taken.`;
|
|
6814
5991
|
async function is_due3(state) {
|
|
6815
5992
|
const carry = await state.carry();
|
|
6816
5993
|
if (carry === void 0 || run_headless.is_cut_capped(carry)) return false;
|
|
@@ -6837,7 +6014,7 @@ function is_unit_call(raw_payload) {
|
|
|
6837
6014
|
function is_exempt2(raw_payload) {
|
|
6838
6015
|
return !hook_decision.is_switch_enabled(SWITCH_ENV_KEY3) || is_unit_call(raw_payload);
|
|
6839
6016
|
}
|
|
6840
|
-
async function parent_cut_reason(raw_payload, now_ms = Date.now(), state =
|
|
6017
|
+
async function parent_cut_reason(raw_payload, now_ms = Date.now(), state = current_state2()) {
|
|
6841
6018
|
if (is_exempt2(raw_payload)) return void 0;
|
|
6842
6019
|
const transcript = run_watcher_hook.transcript_of(raw_payload);
|
|
6843
6020
|
if (transcript === void 0) return void 0;
|
|
@@ -6850,8 +6027,95 @@ var run_parent_cut_hook = {
|
|
|
6850
6027
|
parent_cut_reason
|
|
6851
6028
|
};
|
|
6852
6029
|
|
|
6030
|
+
// scripts/run/run-poll-hook.ts
|
|
6031
|
+
var SWITCH_ENV_KEY4 = "JOSH_POLL_GUARD";
|
|
6032
|
+
var BASH_TOOL = "Bash";
|
|
6033
|
+
var STATE_READS = /* @__PURE__ */ new Set([
|
|
6034
|
+
"josh lane:list",
|
|
6035
|
+
"josh lane:output",
|
|
6036
|
+
"josh run:board",
|
|
6037
|
+
"josh run:carry",
|
|
6038
|
+
"josh run:liveness",
|
|
6039
|
+
"josh run:progress",
|
|
6040
|
+
"josh run:wake"
|
|
6041
|
+
]);
|
|
6042
|
+
var POLL_REASON = '\u26D4 poll: this `backlogrun` session repeats a state read with nothing decided in between, on every occurrence. Wait on `pnpm josh backlog:drive`, or `pnpm josh lane:await <N...> --owner "$PPID"` in the background, and end the turn; its exit is the wake.';
|
|
6043
|
+
var WRITING_FLAGS = /* @__PURE__ */ new Set([
|
|
6044
|
+
"--begin",
|
|
6045
|
+
"--cut",
|
|
6046
|
+
"--done",
|
|
6047
|
+
"--end",
|
|
6048
|
+
"--every",
|
|
6049
|
+
"--filed",
|
|
6050
|
+
"--loop",
|
|
6051
|
+
"--mark",
|
|
6052
|
+
"--merged",
|
|
6053
|
+
"--resume",
|
|
6054
|
+
"--retrospective",
|
|
6055
|
+
"--start",
|
|
6056
|
+
"--stop",
|
|
6057
|
+
"--wait"
|
|
6058
|
+
]);
|
|
6059
|
+
var FLAG_PREFIX4 = "-";
|
|
6060
|
+
var NAME_WORDS = 2;
|
|
6061
|
+
var SIGNATURE_SEPARATOR = " ";
|
|
6062
|
+
function read_key(signature) {
|
|
6063
|
+
const words = signature.split(SIGNATURE_SEPARATOR);
|
|
6064
|
+
const name = words.slice(0, NAME_WORDS).join(SIGNATURE_SEPARATOR);
|
|
6065
|
+
if (!STATE_READS.has(name) || words.some((word) => WRITING_FLAGS.has(word))) return void 0;
|
|
6066
|
+
return words.filter((word) => !word.startsWith(FLAG_PREFIX4)).join(SIGNATURE_SEPARATOR);
|
|
6067
|
+
}
|
|
6068
|
+
function read_keys(signatures) {
|
|
6069
|
+
return signatures.map((signature) => read_key(signature)).filter((key) => key !== void 0);
|
|
6070
|
+
}
|
|
6071
|
+
function state_reads_of(command) {
|
|
6072
|
+
return read_keys(time_shell.josh_signatures_of(command));
|
|
6073
|
+
}
|
|
6074
|
+
function command_of(input) {
|
|
6075
|
+
if (typeof input !== "object" || input === null || !("command" in input)) return "";
|
|
6076
|
+
return typeof input.command === "string" ? input.command : "";
|
|
6077
|
+
}
|
|
6078
|
+
function candidate_reads(raw_payload) {
|
|
6079
|
+
const payload = hook_decision.parse_hook_payload(raw_payload);
|
|
6080
|
+
if (payload?.tool_name !== BASH_TOOL || (payload.agent_id ?? "") !== "") return [];
|
|
6081
|
+
return state_reads_of(command_of(payload.tool_input));
|
|
6082
|
+
}
|
|
6083
|
+
function last_step(tail) {
|
|
6084
|
+
return time_spans.parse_timeline(tail).spans.findLast((span) => span.category !== time_spans.MODEL_CATEGORY);
|
|
6085
|
+
}
|
|
6086
|
+
function repeats_last_call(tail, reads) {
|
|
6087
|
+
const last = last_step(tail);
|
|
6088
|
+
if (last?.category !== time_spans.TOOL_CATEGORY) return false;
|
|
6089
|
+
const last_reads = read_keys(last.josh_signatures);
|
|
6090
|
+
return reads.some((key) => last_reads.includes(key));
|
|
6091
|
+
}
|
|
6092
|
+
function is_repeat(raw_payload) {
|
|
6093
|
+
const reads = hook_decision.is_switch_enabled(SWITCH_ENV_KEY4) ? candidate_reads(raw_payload) : [];
|
|
6094
|
+
const transcript = reads.length === 0 ? void 0 : run_watcher_hook.transcript_of(raw_payload);
|
|
6095
|
+
if (transcript === void 0) return false;
|
|
6096
|
+
return repeats_last_call(time_density_hook.read_tail(transcript), reads);
|
|
6097
|
+
}
|
|
6098
|
+
async function poll_reason(raw_payload, is_parent = run_headless.is_backlog_parent) {
|
|
6099
|
+
if (!is_repeat(raw_payload)) return void 0;
|
|
6100
|
+
return await is_parent() ? POLL_REASON : void 0;
|
|
6101
|
+
}
|
|
6102
|
+
async function safe_poll_reason(raw_payload) {
|
|
6103
|
+
try {
|
|
6104
|
+
return await poll_reason(raw_payload);
|
|
6105
|
+
} catch (error) {
|
|
6106
|
+
error_text.trace_swallowed("run_poll_hook.poll_reason", error);
|
|
6107
|
+
return void 0;
|
|
6108
|
+
}
|
|
6109
|
+
}
|
|
6110
|
+
var run_poll_hook = {
|
|
6111
|
+
POLL_REASON,
|
|
6112
|
+
SWITCH_ENV_KEY: SWITCH_ENV_KEY4,
|
|
6113
|
+
poll_reason,
|
|
6114
|
+
safe_poll_reason
|
|
6115
|
+
};
|
|
6116
|
+
|
|
6853
6117
|
// scripts/hooks/step-zero-notice.ts
|
|
6854
|
-
import
|
|
6118
|
+
import path12 from "node:path";
|
|
6855
6119
|
var STAMP_PREFIX4 = "josh-step-zero-notice-";
|
|
6856
6120
|
var EDIT_TOOLS3 = /* @__PURE__ */ new Set(["Edit", "Write"]);
|
|
6857
6121
|
var PARENT_PREFIX = "..";
|
|
@@ -6866,9 +6130,9 @@ function edited_paths(tool_input) {
|
|
|
6866
6130
|
);
|
|
6867
6131
|
}
|
|
6868
6132
|
function is_runtime_file(file_path, root) {
|
|
6869
|
-
const relative =
|
|
6870
|
-
if (relative.startsWith(PARENT_PREFIX) ||
|
|
6871
|
-
return !test_declared_logic.is_exempt(relative.split(
|
|
6133
|
+
const relative = path12.relative(root, path12.resolve(root, file_path));
|
|
6134
|
+
if (relative.startsWith(PARENT_PREFIX) || path12.isAbsolute(relative)) return false;
|
|
6135
|
+
return !test_declared_logic.is_exempt(relative.split(path12.sep).join("/"));
|
|
6872
6136
|
}
|
|
6873
6137
|
function is_candidate2(raw_payload, root) {
|
|
6874
6138
|
const payload = hook_decision.parse_hook_payload(raw_payload);
|
|
@@ -6882,26 +6146,22 @@ function notice(raw_payload, root = process.cwd()) {
|
|
|
6882
6146
|
const transcript = is_candidate2(raw_payload, root);
|
|
6883
6147
|
if (transcript === void 0) return void 0;
|
|
6884
6148
|
const target = STAMP.path(transcript);
|
|
6885
|
-
if (STAMP.last_ms(target) !== hook_decision.NEVER_MS
|
|
6886
|
-
|
|
6149
|
+
if (STAMP.last_ms(target) !== hook_decision.NEVER_MS || !STAMP.record(target, Date.now())) {
|
|
6150
|
+
return void 0;
|
|
6151
|
+
}
|
|
6887
6152
|
return NOTICE;
|
|
6888
6153
|
}
|
|
6889
6154
|
var step_zero_notice = { NOTICE, notice, stamp_path: STAMP.path };
|
|
6890
6155
|
|
|
6891
6156
|
// scripts/hooks/pretool-guard.ts
|
|
6892
|
-
|
|
6893
|
-
if (batch.reason !== void 0) return batch;
|
|
6894
|
-
if (extra_reason !== void 0) {
|
|
6895
|
-
return { reason: extra_reason, notice: void 0, fault: void 0 };
|
|
6896
|
-
}
|
|
6897
|
-
return batch;
|
|
6898
|
-
}
|
|
6157
|
+
var CLEAR = { reason: void 0, notice: void 0, fault: void 0 };
|
|
6899
6158
|
function is_clear(outcome) {
|
|
6900
6159
|
return outcome.reason === void 0 && outcome.notice === void 0 && outcome.fault === void 0;
|
|
6901
6160
|
}
|
|
6902
|
-
function
|
|
6903
|
-
|
|
6904
|
-
|
|
6161
|
+
function combine_outcomes(outcomes, rule_reason) {
|
|
6162
|
+
const reason = outcomes.find((outcome) => outcome.reason !== void 0)?.reason ?? rule_reason;
|
|
6163
|
+
if (reason !== void 0) return { reason, notice: void 0, fault: void 0 };
|
|
6164
|
+
return outcomes.find((outcome) => !is_clear(outcome)) ?? CLEAR;
|
|
6905
6165
|
}
|
|
6906
6166
|
function with_step_zero_notice(outcome, raw_payload) {
|
|
6907
6167
|
if (!is_clear(outcome)) return outcome;
|
|
@@ -6909,13 +6169,12 @@ function with_step_zero_notice(outcome, raw_payload) {
|
|
|
6909
6169
|
return notice2 === void 0 ? outcome : { reason: void 0, notice: notice2, fault: void 0 };
|
|
6910
6170
|
}
|
|
6911
6171
|
function guard_outcome(raw_payload) {
|
|
6912
|
-
const
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
|
|
6916
|
-
|
|
6917
|
-
|
|
6918
|
-
return with_duplicate_notice(combined, duplicate.notice);
|
|
6172
|
+
const outcomes = [
|
|
6173
|
+
batch_outcome(raw_payload),
|
|
6174
|
+
investigation_outcome(raw_payload),
|
|
6175
|
+
duplicate_read_outcome(raw_payload)
|
|
6176
|
+
];
|
|
6177
|
+
return combine_outcomes(outcomes, delivered_rules.delivery(raw_payload));
|
|
6919
6178
|
}
|
|
6920
6179
|
function pretool_outcome(raw_payload) {
|
|
6921
6180
|
return with_step_zero_notice(guard_outcome(raw_payload), raw_payload);
|
|
@@ -6926,7 +6185,8 @@ async function mark_phase(outcome) {
|
|
|
6926
6185
|
async function async_reason(raw_payload) {
|
|
6927
6186
|
const watcher = await run_watcher_hook.watcher_hook_reason(raw_payload);
|
|
6928
6187
|
const cut = watcher ?? await run_parent_cut_hook.parent_cut_reason(raw_payload);
|
|
6929
|
-
|
|
6188
|
+
const poll2 = cut ?? await run_poll_hook.safe_poll_reason(raw_payload);
|
|
6189
|
+
return poll2 ?? await issue_watch_hook.watch_reason();
|
|
6930
6190
|
}
|
|
6931
6191
|
async function pretool_outcome_async(raw_payload) {
|
|
6932
6192
|
const base = guard_outcome(raw_payload);
|
|
@@ -6958,38 +6218,26 @@ function foreground_rewrite(outcome, raw_payload, is_lane_child) {
|
|
|
6958
6218
|
rewrite_context(lane_background.FOREGROUND_NOTE, outcome)
|
|
6959
6219
|
);
|
|
6960
6220
|
}
|
|
6961
|
-
function
|
|
6962
|
-
if (
|
|
6963
|
-
|
|
6964
|
-
const input = call === void 0 ? void 0 : piped_verification.pipefail_input(call);
|
|
6965
|
-
const payload = json_value.parse_or_undefined(raw_payload);
|
|
6966
|
-
if (input === void 0 || !json_value.is_record(payload)) return void 0;
|
|
6967
|
-
return { payload: JSON.stringify({ ...payload, tool_input: input }), input };
|
|
6968
|
-
}
|
|
6969
|
-
function pipefail_envelope(outcome, input) {
|
|
6970
|
-
if (input === void 0 || outcome.reason !== void 0) return void 0;
|
|
6971
|
-
return hook_decision.rewrite_envelope(
|
|
6972
|
-
input,
|
|
6973
|
-
rewrite_context(piped_verification.PIPEFAIL_NOTE, outcome)
|
|
6974
|
-
);
|
|
6221
|
+
function rule_envelope(outcome, rewrite3) {
|
|
6222
|
+
if (rewrite3 === void 0 || outcome.reason !== void 0) return void 0;
|
|
6223
|
+
return hook_decision.flow_rewrite_envelope(rewrite3.input, rewrite_context(rewrite3.note, outcome));
|
|
6975
6224
|
}
|
|
6976
|
-
function emit(raw_payload, outcome,
|
|
6977
|
-
const
|
|
6978
|
-
if (
|
|
6979
|
-
else process.stdout.write(`${
|
|
6225
|
+
function emit(raw_payload, outcome, rewrite3) {
|
|
6226
|
+
const envelope = rule_envelope(outcome, rewrite3) ?? foreground_rewrite(outcome, raw_payload);
|
|
6227
|
+
if (envelope === void 0) hook_decision.emit_outcome(outcome);
|
|
6228
|
+
else process.stdout.write(`${envelope}
|
|
6980
6229
|
`);
|
|
6981
6230
|
}
|
|
6982
6231
|
async function respond(raw_payload) {
|
|
6983
|
-
const
|
|
6984
|
-
const judged =
|
|
6985
|
-
emit(judged, await pretool_outcome_async(judged),
|
|
6232
|
+
const rewrite3 = rule_rewrite.rewrite(raw_payload);
|
|
6233
|
+
const judged = rewrite3?.payload ?? raw_payload;
|
|
6234
|
+
emit(judged, await pretool_outcome_async(judged), rewrite3);
|
|
6986
6235
|
}
|
|
6987
6236
|
var pretool_guard = {
|
|
6988
6237
|
combine_outcomes,
|
|
6989
6238
|
emit,
|
|
6990
6239
|
foreground_rewrite,
|
|
6991
6240
|
mark_phase,
|
|
6992
|
-
pipefail_rewrite,
|
|
6993
6241
|
pretool_outcome,
|
|
6994
6242
|
respond
|
|
6995
6243
|
};
|