@joshuafolkken/kit 1.1136.0 → 1.1178.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.
Files changed (200) hide show
  1. package/.claude/settings.json +4 -4
  2. package/.claude/skills/epic-commands/SKILL.md +27 -239
  3. package/.claude/skills/epic-commands/epic-bundle.md +115 -0
  4. package/.claude/skills/epic-commands/execution-waves.md +126 -0
  5. package/.claude/skills/workflow-commands/SKILL.md +48 -194
  6. package/.claude/skills/workflow-commands/background-commands.md +1 -1
  7. package/.claude/skills/workflow-commands/backlogrun-child.md +12 -123
  8. package/.claude/skills/workflow-commands/backlogrun-lanes.md +14 -63
  9. package/.claude/skills/workflow-commands/backlogrun-park.md +16 -15
  10. package/.claude/skills/workflow-commands/backlogrun-progress.md +17 -173
  11. package/.claude/skills/workflow-commands/backlogrun-recovery.md +155 -0
  12. package/.claude/skills/workflow-commands/backlogrun-steps.md +65 -144
  13. package/.claude/skills/workflow-commands/backlogrun.md +5 -4
  14. package/.claude/skills/workflow-commands/chain-rule.md +3 -2
  15. package/.claude/skills/workflow-commands/delegation.md +2 -2
  16. package/.claude/skills/workflow-commands/entry-sequence.md +62 -0
  17. package/.claude/skills/workflow-commands/followup.md +104 -181
  18. package/.claude/skills/workflow-commands/fullrun-steps.md +8 -9
  19. package/.claude/skills/workflow-commands/fullrun.md +16 -73
  20. package/.claude/skills/workflow-commands/halfrun.md +10 -36
  21. package/.claude/skills/workflow-commands/into-target.md +4 -4
  22. package/.claude/skills/workflow-commands/issue-comments.md +7 -8
  23. package/.claude/skills/workflow-commands/issue-scout.md +6 -6
  24. package/.claude/skills/workflow-commands/kickoff.md +6 -6
  25. package/.claude/skills/workflow-commands/needs-human-review.md +6 -6
  26. package/.claude/skills/workflow-commands/observation-filing.md +21 -172
  27. package/.claude/skills/workflow-commands/observation-ledger.md +150 -0
  28. package/.claude/skills/workflow-commands/pre-gate-cut.md +35 -95
  29. package/.claude/skills/workflow-commands/prerequisite.md +6 -6
  30. package/.claude/skills/workflow-commands/progress-watcher.md +90 -0
  31. package/.claude/skills/workflow-commands/prrun.md +5 -5
  32. package/.claude/skills/workflow-commands/retrospective.md +9 -9
  33. package/.claude/skills/workflow-commands/split-assessment.md +2 -2
  34. package/.claude/skills/workflow-commands/target-repository.md +2 -2
  35. package/.claude/skills/workflow-commands/working-tree-hold.md +7 -5
  36. package/.codex/hooks.json +4 -4
  37. package/.github/workflows/ci.yml +15 -2
  38. package/AGENTS.md +1 -6
  39. package/CLAUDE.md +58 -120
  40. package/GEMINI.md +1 -6
  41. package/dist/CLAUDE.md +58 -120
  42. package/dist/hooks/batch-guard.js +4 -4
  43. package/dist/hooks/{chunk-NFZGFGOR.js → chunk-32GQTL4F.js} +14 -1
  44. package/dist/hooks/{chunk-HBKZLITF.js → chunk-DO6NWWHU.js} +4 -4
  45. package/dist/hooks/{chunk-KBXZLMRH.js → chunk-G6KRCKEC.js} +216 -76
  46. package/dist/hooks/{chunk-JKKTVDAG.js → chunk-GDS5N2KB.js} +186 -309
  47. package/dist/hooks/chunk-I4XSL4TT.js +56 -0
  48. package/dist/hooks/{chunk-GDU26K3J.js → chunk-S6X6WYKR.js} +886 -174
  49. package/dist/hooks/{chunk-FO2I7UT7.js → chunk-UAGLLIGZ.js} +1 -1
  50. package/dist/hooks/{chunk-RFWWUI5F.js → chunk-VESKRQOF.js} +3 -3
  51. package/dist/hooks/{chunk-KOKOAV6D.js → chunk-VQLLNFNT.js} +6 -4
  52. package/dist/hooks/{chunk-LJBLGHEH.js → chunk-ZAL3NRGL.js} +4 -6
  53. package/dist/hooks/codex-hook-adapter.js +10 -10
  54. package/dist/hooks/duplicate-read-guard.js +5 -5
  55. package/dist/hooks/format-edited.js +2 -2
  56. package/dist/hooks/inputs.json +178 -177
  57. package/dist/hooks/investigation-guard.js +5 -5
  58. package/dist/hooks/pretool-guard.js +11 -10
  59. package/dist/hooks/stop-guard.js +20 -6
  60. package/dist/josh.js +29 -3
  61. package/dist/version/index.js +5 -1
  62. package/package.json +2 -1
  63. package/prompts/collaboration-workflow/file-edits.md +11 -10
  64. package/prompts/collaboration-workflow/gh-rest.md +2 -4
  65. package/prompts/collaboration-workflow/glossary.md +1 -1
  66. package/prompts/collaboration-workflow/issue-citation.md +5 -9
  67. package/prompts/collaboration-workflow/issue-template.md +40 -115
  68. package/prompts/collaboration-workflow/operating-rules.md +4 -5
  69. package/prompts/collaboration-workflow/output-bounds.md +12 -78
  70. package/prompts/collaboration-workflow/overview.md +7 -13
  71. package/prompts/collaboration-workflow/plan-comment.md +11 -39
  72. package/prompts/collaboration-workflow/principles.md +3 -4
  73. package/prompts/collaboration-workflow/report-format.md +28 -74
  74. package/prompts/collaboration-workflow/residency.md +12 -109
  75. package/prompts/collaboration-workflow/rule-delivery.md +98 -97
  76. package/prompts/collaboration-workflow/shell-body.md +3 -13
  77. package/prompts/collaboration-workflow/turn-batching.md +14 -88
  78. package/prompts/collaboration-workflow/upstream-interrupt.md +12 -14
  79. package/prompts/collaboration-workflow/wip-cap.md +6 -45
  80. package/prompts/collaboration-workflow.md +1 -13
  81. package/prompts/review-rubric.md +8 -71
  82. package/prompts/review.md +25 -55
  83. package/prompts/testing-guide.md +18 -67
  84. package/scripts/agent/agent-role-profile.ts +1 -1
  85. package/scripts/agent/codex-hooks.ts +3 -12
  86. package/scripts/backlog/backlog-budget.ts +1 -1
  87. package/scripts/backlog/backlog-drive-cli.ts +4 -3
  88. package/scripts/backlog/backlog-drive-offer-argv.ts +10 -1
  89. package/scripts/backlog/backlog-next.ts +15 -4
  90. package/scripts/backlog/backlog-offer.ts +6 -6
  91. package/scripts/backlog/backlog-plan-cli.ts +6 -5
  92. package/scripts/backlog/backlog-rank.ts +18 -9
  93. package/scripts/backlog/backlog-restructure.ts +152 -0
  94. package/scripts/backlog/backlog-waves.ts +15 -17
  95. package/scripts/behavior/behavior-rules.ts +11 -4
  96. package/scripts/cost-runtime/context-cut-threshold.ts +1 -9
  97. package/scripts/cost-runtime/cost-verdict.ts +15 -28
  98. package/scripts/delegation/investigation-reads.ts +5 -5
  99. package/scripts/discovery/repo-discovery.ts +21 -7
  100. package/scripts/discovery/repo-origin.ts +26 -0
  101. package/scripts/discovery/repo-party.ts +42 -1
  102. package/scripts/document/backlogrun-parent-read-set.ts +14 -15
  103. package/scripts/document/document-byte-budget.ts +34 -20
  104. package/scripts/document/entry-read-budget.ts +21 -9
  105. package/scripts/document/lane-child-read-set.ts +12 -14
  106. package/scripts/document/read-set-cli.ts +4 -4
  107. package/scripts/document/read-set-point-of-use.ts +10 -2
  108. package/scripts/document/resident-budget.ts +47 -0
  109. package/scripts/epic/epic-shape.ts +10 -13
  110. package/scripts/epic/epic-solo.ts +1 -1
  111. package/scripts/exports/unused-members-cli.ts +7 -3
  112. package/scripts/followup/git-followup-stages.ts +9 -0
  113. package/scripts/followup/git-pr-followup.ts +1 -1
  114. package/scripts/gh/git-gh-api-path.ts +7 -0
  115. package/scripts/gh/git-gh-issue.ts +5 -3
  116. package/scripts/gh/git-gh-pr-read.ts +4 -0
  117. package/scripts/gh/git-pr-checks-eval.ts +8 -0
  118. package/scripts/gh/git-pr-checks.ts +11 -1
  119. package/scripts/git/constants.ts +10 -0
  120. package/scripts/git/main-merge.ts +57 -21
  121. package/scripts/git/schemas.ts +2 -0
  122. package/scripts/hooks/pretool-guard-cli.ts +2 -2
  123. package/scripts/hooks/pretool-guard.ts +45 -2
  124. package/scripts/hooks/run-hook.sh +41 -0
  125. package/scripts/init/hook-command-rewrite.ts +18 -35
  126. package/scripts/init/hook-launch.ts +21 -32
  127. package/scripts/issue/issue-auto-ok.ts +95 -0
  128. package/scripts/issue/issue-file-cli.ts +53 -7
  129. package/scripts/issue/issue-file.ts +28 -5
  130. package/scripts/issue/issue-labels.ts +12 -12
  131. package/scripts/issue/issue-rank.ts +1 -1
  132. package/scripts/issue/issue-read-cli.ts +3 -3
  133. package/scripts/issue/issue-read.ts +2 -2
  134. package/scripts/issue/issue-scout-cli.ts +2 -2
  135. package/scripts/issue/issue-state-cli.ts +1 -1
  136. package/scripts/issue/issue-state.ts +2 -2
  137. package/scripts/issue/issue-wip.ts +70 -0
  138. package/scripts/josh/hook-decision.ts +17 -0
  139. package/scripts/josh/josh-commands-development.ts +11 -1
  140. package/scripts/josh/josh-commands-issue.ts +2 -2
  141. package/scripts/lane/lane-launch-cli.ts +21 -3
  142. package/scripts/lines/bytes-command.ts +29 -6
  143. package/scripts/notify/telegram-notify.ts +26 -1
  144. package/scripts/observations/observation-ledger-line.ts +1 -1
  145. package/scripts/release/release-progress.ts +167 -0
  146. package/scripts/release/release-publish.ts +19 -8
  147. package/scripts/release/release-tag.ts +22 -8
  148. package/scripts/rules/decision-oracle-stage.ts +1 -1
  149. package/scripts/rules/decision-oracle.ts +6 -6
  150. package/scripts/rules/delivered-rules.ts +11 -11
  151. package/scripts/rules/direct-pr-create.ts +110 -0
  152. package/scripts/rules/file-body.ts +98 -42
  153. package/scripts/rules/filing-cap.ts +2 -2
  154. package/scripts/rules/filing-offer.ts +1 -1
  155. package/scripts/rules/gh-api.ts +18 -1
  156. package/scripts/rules/implementation-cut.ts +3 -1
  157. package/scripts/rules/lane-background.ts +67 -10
  158. package/scripts/rules/permission-guards.ts +10 -2
  159. package/scripts/rules/pre-gate-cut.ts +2 -2
  160. package/scripts/rules/stop-rules.ts +4 -4
  161. package/scripts/rules/test-declared-commit.ts +1 -1
  162. package/scripts/rules/third-party-write.ts +56 -12
  163. package/scripts/run/run-carry.ts +11 -5
  164. package/scripts/run/run-cut-cli.ts +1 -1
  165. package/scripts/run/run-cut-handoff.ts +21 -1
  166. package/scripts/run/run-cut-report.ts +2 -2
  167. package/scripts/run/run-entry-cli.ts +11 -3
  168. package/scripts/run/run-hold-cli.ts +16 -2
  169. package/scripts/run/run-label.ts +50 -0
  170. package/scripts/run/run-merge-steps.ts +8 -3
  171. package/scripts/run/run-merge.ts +1 -1
  172. package/scripts/run/run-prep-cli.ts +6 -2
  173. package/scripts/run/run-prep.ts +17 -0
  174. package/scripts/run/run-ship-cli.ts +27 -6
  175. package/scripts/run/run-ship-next.ts +13 -0
  176. package/scripts/run/run-ship-pre-detach.ts +66 -0
  177. package/scripts/run/run-ship-preflight.ts +34 -3
  178. package/scripts/run/run-ship-return.ts +7 -4
  179. package/scripts/run/run-ship-review-steps.ts +1 -1
  180. package/scripts/run/run-ship-review.ts +26 -5
  181. package/scripts/run/run-ship-stage.ts +13 -0
  182. package/scripts/run/run-ship-steps.ts +10 -2
  183. package/scripts/run/run-ship-sync.ts +114 -0
  184. package/scripts/run/run-ship.ts +6 -0
  185. package/scripts/run/run-step-cli.ts +20 -7
  186. package/scripts/run/run-wake-cli.ts +8 -1
  187. package/scripts/run/run-wake-driver.ts +62 -8
  188. package/scripts/run/run-wake-session.ts +2 -1
  189. package/scripts/test/test-declared-logic.ts +1 -1
  190. package/scripts/test/test-red-logic.ts +17 -2
  191. package/scripts/test/test-red.ts +8 -7
  192. package/scripts/time-runtime/time-batch-guard.ts +52 -16
  193. package/scripts/time-runtime/time-density-hook.ts +20 -2
  194. package/scripts/time-runtime/time-density.ts +4 -3
  195. package/scripts/time-runtime/time-markers.ts +15 -4
  196. package/scripts/time-runtime/time-transcript-line.ts +27 -1
  197. package/scripts/version/npm-registry.ts +11 -1
  198. package/templates/workflows/ci.yml +9 -1
  199. package/.claude/skills/workflow-commands/followup-reference.md +0 -118
  200. package/dist/hooks/chunk-HANSKHES.js +0 -464
@@ -1,20 +1,33 @@
1
1
  import {
2
2
  lane_child_marker,
3
3
  run_issue_number
4
- } from "./chunk-NFZGFGOR.js";
4
+ } from "./chunk-32GQTL4F.js";
5
5
  import {
6
+ CHECK_STATUS_FAIL,
7
+ CHECK_STATUS_PENDING,
6
8
  PLATFORM_TEMP_ROOT,
9
+ PrConflictError,
10
+ blocking_issue_schema,
7
11
  cost_blocks,
8
12
  cost_transcript,
9
13
  cost_usage,
14
+ describe_pr_failure,
15
+ evaluate_pr_state,
10
16
  file_reader,
17
+ is_coderabbit_check,
18
+ is_merge_conflict,
19
+ is_required_check,
20
+ is_review_decision_decisive,
11
21
  json_value,
12
22
  lane_paths,
23
+ parse_pr_state_snapshot,
24
+ read_string,
25
+ rest_comment_schema,
13
26
  stamp_file,
14
27
  time_density_hook,
15
28
  time_shell,
16
29
  time_transcript_line
17
- } from "./chunk-GDU26K3J.js";
30
+ } from "./chunk-S6X6WYKR.js";
18
31
  import {
19
32
  ENV_FILE_NAME,
20
33
  LANE_SEAT_KEY,
@@ -147,7 +160,7 @@ function turn_filing_count(tail) {
147
160
  function decide(_call, run3) {
148
161
  return prior_filing_count(time_density_hook.read_tail(run3.transcript)) >= CAP_REACHED;
149
162
  }
150
- var FILING_CAP_REASON = `\u26D4 filing cap: this run has already filed ${String(FILING_CAP)} Issues, the per-run ceiling \u2014 on reaching it, stop and report rather than filing more. Automatic filing is capped so a run cannot manufacture Issues faster than they can be closed (\`.claude/skills/workflow-commands/SKILL.md\` \u2192 \xA72d, \`observation-filing.md\`). A further Issue that genuinely must exist is a person's call, not this run's. **This rule fires on every filing past the cap, not once per run**, so reissuing the same filing will be refused again.`;
163
+ var FILING_CAP_REASON = `\u26D4 filing cap: this run has already filed ${String(FILING_CAP)} Issues, the per-run ceiling \u2014 on reaching it, stop and report rather than filing more. Automatic filing is capped so a run cannot manufacture Issues faster than they can be closed (\`.claude/skills/workflow-commands/SKILL.md\` \u2192 \`prerequisite.md\`, \`observation-filing.md\`). A further Issue that genuinely must exist is a person's call, not this run's. **This rule fires on every filing past the cap, not once per run**, so reissuing the same filing will be refused again.`;
151
164
  var ROW = {
152
165
  id: "filing-cap",
153
166
  is_trigger: bash_triggers.on_bash_command(bash_triggers.is_issue_filing),
@@ -168,6 +181,7 @@ import { platform } from "node:os";
168
181
  var GIT_COMMAND_UNIX = "/usr/bin/git";
169
182
  var PORCELAIN_FLAG = "--porcelain";
170
183
  var UNTRACKED_FILES_FLAG = "--untracked-files=all";
184
+ var GIT_BINARY_KEY = "JOSH_GIT_BINARY";
171
185
  function get_git_command() {
172
186
  if (platform() === "win32") {
173
187
  return String.raw`"C:\Program Files\Git\cmd\git.exe"`;
@@ -175,6 +189,8 @@ function get_git_command() {
175
189
  return GIT_COMMAND_UNIX;
176
190
  }
177
191
  function get_git_command_for_spawn() {
192
+ const binary = process.env[GIT_BINARY_KEY];
193
+ if (binary !== void 0 && binary !== "") return binary;
178
194
  if (platform() === "win32") {
179
195
  return String.raw`C:\Program Files\Git\cmd\git.exe`;
180
196
  }
@@ -1319,7 +1335,6 @@ var context_cut_payback = {
1319
1335
 
1320
1336
  // scripts/cost-runtime/context-cut-threshold.ts
1321
1337
  var CONTEXT_CUT_THRESHOLD = context_cut_payback.break_even_context();
1322
- var RECENT_REQUEST_WINDOW = 10;
1323
1338
 
1324
1339
  // scripts/git/git-common-directory.ts
1325
1340
  import { execFileSync } from "node:child_process";
@@ -1415,6 +1430,7 @@ var STAGE = {
1415
1430
  PREFLIGHT: "preflight",
1416
1431
  REVIEW: "review",
1417
1432
  GATE: "gate",
1433
+ SYNC: "sync",
1418
1434
  COMMIT: "commit",
1419
1435
  ROUND_TWO: "round-2",
1420
1436
  FOLLOWUP: "followup",
@@ -1464,6 +1480,9 @@ var DONE_BY = {
1464
1480
  // the recorded round, and only a commit pins the tree that round read.
1465
1481
  [STAGE.REVIEW]: (_done, state) => state.is_merged || state.is_committed,
1466
1482
  [STAGE.GATE]: (_done, state) => state.is_merged || state.is_committed,
1483
+ // The merge of the default branch before the commit (joshuafolkken/kit#3221): once committed, a
1484
+ // conflicting pull request is the followup's to merge again.
1485
+ [STAGE.SYNC]: (_done, state) => state.is_merged || state.is_committed,
1467
1486
  [STAGE.COMMIT]: (done, state) => state.is_merged || done.has(STAGE.COMMIT) && is_shipped(state),
1468
1487
  // The round-2 pass (joshuafolkken/kit#2489) reads the pushed fix delta, so its record is honored only
1469
1488
  // while that push still stands — new work pushed on top reruns it.
@@ -1484,6 +1503,10 @@ function commit_flags(state) {
1484
1503
  function event_text(issue, stage, phase) {
1485
1504
  return `#${issue} ${stage} ${phase}`;
1486
1505
  }
1506
+ var CONFLICT = "conflict";
1507
+ function stop_reason2(stage, conflicts = []) {
1508
+ return conflicts.length > 0 ? CONFLICT : stage;
1509
+ }
1487
1510
  var run_ship_stage = {
1488
1511
  PHASE,
1489
1512
  STAGE,
@@ -1493,7 +1516,8 @@ var run_ship_stage = {
1493
1516
  is_done,
1494
1517
  mark_done,
1495
1518
  read_done,
1496
- record_path
1519
+ record_path,
1520
+ stop_reason: stop_reason2
1497
1521
  };
1498
1522
 
1499
1523
  // scripts/run/run-ship-next.ts
@@ -1534,12 +1558,18 @@ var AFTER_FIX = {
1534
1558
  [STAGE2.PREFLIGHT]: detach_as_started,
1535
1559
  [STAGE2.REVIEW]: detach_as_started,
1536
1560
  [STAGE2.GATE]: detach_as_started,
1561
+ [STAGE2.SYNC]: detach_as_started,
1537
1562
  [STAGE2.COMMIT]: detach_as_started,
1538
1563
  [STAGE2.ROUND_TWO]: detach_again,
1539
1564
  [STAGE2.FOLLOWUP]: detach_again,
1540
1565
  [STAGE2.REPORT]: detach_again
1541
1566
  };
1567
+ function conflict_step(conflicts) {
1568
+ return `Resolve the conflict with origin/main in ${conflicts.join(", ")} (the merge is left in progress: remove the conflict markers in those files), then`;
1569
+ }
1542
1570
  function next_step(issue, stage, resume) {
1571
+ const conflicts = resume.conflicts ?? [];
1572
+ if (conflicts.length > 0) return `${conflict_step(conflicts)} ${AFTER_FIX[stage](resume)}`;
1543
1573
  return `Read the stopped report with \`${COMMAND.LOG} ${issue}\`, fix the ${stage} failure, then ${AFTER_FIX[stage](resume)}`;
1544
1574
  }
1545
1575
  var run_ship_next = { COMMAND, next_step, quoted, resume_of };
@@ -1594,6 +1624,11 @@ var REMAINING_LABEL = "Remaining";
1594
1624
  var UNTOUCHED_LABEL = "Deliberately untouched";
1595
1625
  var INSTRUCTION_LABEL = "Instruction (verbatim)";
1596
1626
  var EMPTY_LIST_NOTE = "(none)";
1627
+ function describe_key(key2) {
1628
+ const value = handoff_schema.shape[key2] instanceof z4.ZodArray ? '["\u2026"]' : '"\u2026"';
1629
+ return `"${key2}": ${value}`;
1630
+ }
1631
+ var HANDOFF_FORMAT = `a JSON object {${handoff_schema.keyof().options.map((key2) => describe_key(key2)).join(", ")}}`;
1597
1632
  function parse_handoff(raw) {
1598
1633
  try {
1599
1634
  const parsed = handoff_schema.safeParse(JSON.parse(raw));
@@ -1619,7 +1654,10 @@ function load_handoff(handoff_path, max_bytes) {
1619
1654
  if (handoff_path === void 0) return { kind: "ok", handoff: void 0 };
1620
1655
  const handoff = read_handoff_file(handoff_path);
1621
1656
  if (handoff === void 0) {
1622
- return { kind: "bad", note: `--handoff ${handoff_path} is not a readable handoff file` };
1657
+ return {
1658
+ kind: "bad",
1659
+ note: `--handoff ${handoff_path} is not a readable handoff file \u2014 write ${HANDOFF_FORMAT}`
1660
+ };
1623
1661
  }
1624
1662
  if (!is_within_bound(handoff, max_bytes)) {
1625
1663
  return { kind: "bad", note: `--handoff ${handoff_path} is too large to carry across the cut` };
@@ -1642,6 +1680,7 @@ ${handoff.instruction}`,
1642
1680
  ].join("\n\n");
1643
1681
  }
1644
1682
  var run_cut_handoff = {
1683
+ HANDOFF_FORMAT,
1645
1684
  describe_handoff,
1646
1685
  handoff_schema,
1647
1686
  is_complete_handoff,
@@ -1899,24 +1938,47 @@ var run_tail = {
1899
1938
  };
1900
1939
 
1901
1940
  // scripts/rules/lane-background.ts
1902
- var LONG_RUNNING_COMMANDS = new Set(
1903
- ["gate", "git", "followup", "ship"].map((name) => `${time_shell.JOSH_PREFIX}${name}`)
1904
- );
1941
+ var SHIP_COMMAND = `${time_shell.JOSH_PREFIX}ship`;
1942
+ var LONG_RUNNING_COMMANDS = /* @__PURE__ */ new Set([
1943
+ ...["gate", "git", "followup"].map((name) => `${time_shell.JOSH_PREFIX}${name}`),
1944
+ SHIP_COMMAND
1945
+ ]);
1905
1946
  var BACKGROUND_KEY2 = "run_in_background";
1947
+ var TIMEOUT_KEY = "timeout";
1948
+ var FOREGROUND_TIMEOUT_MS = 6e5;
1906
1949
  function is_backgrounded2(input) {
1907
1950
  return json_value.is_record(input) && input[BACKGROUND_KEY2] === true;
1908
1951
  }
1909
- function runs_long_command(command) {
1910
- return time_shell.josh_commands_of(command).some((name) => LONG_RUNNING_COMMANDS.has(name));
1952
+ function long_commands_of(command) {
1953
+ return time_shell.josh_commands_of(command).filter((name) => LONG_RUNNING_COMMANDS.has(name));
1954
+ }
1955
+ function ships_alone(command) {
1956
+ const names = long_commands_of(command);
1957
+ return names.length > 0 && names.every((name) => name === SHIP_COMMAND);
1958
+ }
1959
+ function backgrounded_bash_command(call) {
1960
+ if (call.name !== cost_blocks.BASH_TOOL || !is_backgrounded2(call.input)) return void 0;
1961
+ return time_shell.bash_command(call.input);
1962
+ }
1963
+ function is_backgrounded_ship(call) {
1964
+ const command = backgrounded_bash_command(call);
1965
+ return command !== void 0 && ships_alone(command);
1911
1966
  }
1912
1967
  function is_candidate(call) {
1913
1968
  if (run_tail.is_push_step_call(call)) return true;
1914
- if (call.name !== cost_blocks.BASH_TOOL || !is_backgrounded2(call.input)) return false;
1915
- return runs_long_command(time_shell.bash_command(call.input));
1969
+ const command = backgrounded_bash_command(call);
1970
+ if (command === void 0 || is_backgrounded_ship(call)) return false;
1971
+ return long_commands_of(command).length > 0;
1916
1972
  }
1917
1973
  function is_background_long_run(call, is_lane_child = () => lane_child_marker.is_child_of(process.cwd())) {
1918
1974
  return is_candidate(call) && is_lane_child();
1919
1975
  }
1976
+ function foreground_input(call, is_lane_child = () => lane_child_marker.is_child_of(process.cwd())) {
1977
+ if (!is_backgrounded_ship(call) || !json_value.is_record(call.input)) return void 0;
1978
+ if (!is_lane_child()) return void 0;
1979
+ return { ...call.input, [BACKGROUND_KEY2]: false, [TIMEOUT_KEY]: FOREGROUND_TIMEOUT_MS };
1980
+ }
1981
+ var FOREGROUND_NOTE = "lane background: this lane child backgrounded `josh ship`, which would die with the headless turn before its supervisor exists \u2014 so it was run in the foreground instead, where it detaches itself after the preflight. End the turn on `launched` / `busy` (joshuafolkken/kit#3154).";
1920
1982
  function unfinished_ids(tail, launched_ids) {
1921
1983
  const lines = tail.split("\n").map((line) => time_transcript_line.parse_line(line));
1922
1984
  const finished = new Set(lines.map((line) => line?.finished_background ?? ""));
@@ -1930,7 +1992,7 @@ function pending_background_ids(tail) {
1930
1992
  function pending_agent_ids(tail) {
1931
1993
  return unfinished_ids(tail, (block) => [block.agent_id]);
1932
1994
  }
1933
- var LANE_BACKGROUND_REASON = '\u26D4 lane background: this session is a dispatched lane child (`JOSH_LANE_CHILD`), a headless `claude -p` process whose background Bash tasks are killed when the turn ends \u2014 so a backgrounded `josh gate` / `josh git` / `josh followup` / `josh ship` never re-invokes you; it dies at `exit code 143` (joshuafolkken/kit#2704, measured on the #2606 child: implementation, review and live verification done, the run parked instead of merged). Hand the gate-to-merge region to the detached supervisor instead: `pnpm josh ship --detach --review "<title> #<N>"` (add `--cite <N>`) issued in the foreground \u2014 its preflight runs in this process before the supervisor exists, so a backgrounded `ship` dies with the turn (joshuafolkken/kit#3027) \u2014 then end the turn on `launched` / `busy`. `.claude/skills/workflow-commands/chain-rule.md` step 0 is the single source. A single check you must read before continuing runs in the foreground within the tool timeout; the commit-push step does not \u2014 in a child it too belongs to the detached ship, in either spelling. This rule fires on every occurrence, not once per run.';
1995
+ var LANE_BACKGROUND_REASON = '\u26D4 lane background: this session is a dispatched lane child (`JOSH_LANE_CHILD`), a headless `claude -p` process whose background Bash tasks are killed when the turn ends \u2014 so a backgrounded `josh gate` / `josh git` / `josh followup` / `josh ship` never re-invokes you; it dies at `exit code 143` (joshuafolkken/kit#2704, measured on the #2606 child: implementation, review and live verification done, the run parked instead of merged). Hand the gate-to-merge region to the detached supervisor instead: `pnpm josh ship --detach --review "<title> #<N>"` (add `--cite <N>`) issued in the foreground \u2014 its preflight runs in this process before the supervisor exists, so a backgrounded `ship` dies with the turn (joshuafolkken/kit#3027; a backgrounded `ship` issued alone is moved to the foreground for you, joshuafolkken/kit#3154) \u2014 then end the turn on `launched` / `busy`. `.claude/skills/workflow-commands/chain-rule.md` step 0 is the single source. A single check you must read before continuing runs in the foreground within the tool timeout; the commit-push step does not \u2014 in a child it too belongs to the detached ship, in either spelling. This rule fires on every occurrence, not once per run.';
1934
1996
  var LANE_BACKGROUND_STOP_REASON = "\u26D4 lane background stop: this is a dispatched lane child (`JOSH_LANE_CHILD`) and a background task it launched has not finished \u2014 ending this headless turn kills it, and nothing re-invokes you afterwards (joshuafolkken/kit#2704). Do not send a notification and do not stop: wait for the task in the foreground and act on its result, or re-issue the work through `pnpm josh ship --detach`, whose supervisor outlives the turn (`.claude/skills/workflow-commands/chain-rule.md` step 0). Do not repeat your previous reply.";
1935
1997
  var ROW2 = {
1936
1998
  id: "lane-background",
@@ -1939,9 +2001,11 @@ var ROW2 = {
1939
2001
  decide: () => true
1940
2002
  };
1941
2003
  var lane_background = {
2004
+ FOREGROUND_NOTE,
1942
2005
  LANE_BACKGROUND_REASON,
1943
2006
  LANE_BACKGROUND_STOP_REASON,
1944
2007
  ROW: ROW2,
2008
+ foreground_input,
1945
2009
  is_background_long_run,
1946
2010
  pending_agent_ids,
1947
2011
  pending_background_ids
@@ -2724,8 +2788,11 @@ function mismatch_message(carry, invocation) {
2724
2788
  function busy_message2(carry) {
2725
2789
  return `A live run holds this budget \u2014 ${describe_carry(carry)}, owner pid ${String(carry.owner_pid)} still running. Nothing was established. Wait for that run, or end its record with \`${END_COMMAND2}\` once you know it is over.`;
2726
2790
  }
2791
+ function claim_command(invocation) {
2792
+ return `${RESUME_COMMAND} "${invocation}" ${OWNER_ARGUMENT}`;
2793
+ }
2727
2794
  function standing_message(carry) {
2728
- return `A run record is standing here that no cut handed off \u2014 ${describe_carry(carry)}. Nothing was established. Carry that budget with \`${RESUME_COMMAND} "${carry.invocation}" ${OWNER_ARGUMENT}\`, or discard it with \`${END_COMMAND2}\` and begin again.`;
2795
+ return `A run record is standing here that no cut handed off \u2014 ${describe_carry(carry)}. Nothing was established. Carry that budget with \`${claim_command(carry.invocation)}\`, or discard it with \`${END_COMMAND2}\` and begin again.`;
2729
2796
  }
2730
2797
  function count_refused_message(carry) {
2731
2798
  if (carry.is_handed_off === true) {
@@ -2757,6 +2824,7 @@ var run_carry = {
2757
2824
  begin_carry,
2758
2825
  busy_message: busy_message2,
2759
2826
  carry_path,
2827
+ claim_command,
2760
2828
  classify: classify3,
2761
2829
  classify_claim,
2762
2830
  count_refused_message,
@@ -3559,17 +3627,17 @@ var DEPTH_LABELS = [
3559
3627
  {
3560
3628
  name: DEPTH_0_LABEL,
3561
3629
  color: "0e8a16",
3562
- description: "Depth 0 \u2014 what a consumer of this package touches (SKILL.md \xA72i)"
3630
+ description: "Depth 0 \u2014 what a consumer of this package touches (observation-filing.md)"
3563
3631
  },
3564
3632
  {
3565
3633
  name: DEPTH_1_LABEL,
3566
3634
  color: "fbc02d",
3567
- description: "Depth 1 \u2014 the run orchestration that executes an Issue (SKILL.md \xA72i)"
3635
+ description: "Depth 1 \u2014 the run orchestration that executes an Issue (observation-filing.md)"
3568
3636
  },
3569
3637
  {
3570
3638
  name: DEPTH_2_LABEL,
3571
3639
  color: "c5def5",
3572
- description: "Depth 2 \u2014 what measures a run (SKILL.md \xA72i)"
3640
+ description: "Depth 2 \u2014 what measures a run (observation-filing.md)"
3573
3641
  }
3574
3642
  ];
3575
3643
  var WORKFLOW_LABELS = [
@@ -3687,6 +3755,7 @@ var REPO_PATH_SEGMENTS = 2;
3687
3755
  var NOT_FOUND3 = -1;
3688
3756
  var SECTION_PREFIX = "[";
3689
3757
  var ORIGIN_SECTION = /^\[remote\s+"origin"\]$/u;
3758
+ var REMOTE_SECTION = /^\[remote\s+"[^"]+"\]$/u;
3690
3759
  var URL_KEY = "url";
3691
3760
  function is_github_hostname(host) {
3692
3761
  return host.toLowerCase() === GITHUB_HOST;
@@ -3746,6 +3815,18 @@ function parse_origin_from_config(content) {
3746
3815
  const lines = content.split("\n").map((line) => line.trim());
3747
3816
  return origin_section_lines(lines).map((line) => entry_value(line, URL_KEY)).find((url) => url !== void 0);
3748
3817
  }
3818
+ function section_groups(lines) {
3819
+ const groups = [];
3820
+ for (const line of lines) {
3821
+ if (is_section_header(line)) groups.push([line]);
3822
+ else groups.at(-1)?.push(line);
3823
+ }
3824
+ return groups;
3825
+ }
3826
+ function parse_remote_urls_from_config(content) {
3827
+ const lines = content.split("\n").map((line) => line.trim());
3828
+ return section_groups(lines).filter((group) => REMOTE_SECTION.test(group[0] ?? "")).flatMap((group) => group.map((line) => entry_value(line, URL_KEY))).filter((url) => url !== void 0);
3829
+ }
3749
3830
  function format_identity(identity) {
3750
3831
  return `${identity.owner}${PATH_SEPARATOR2}${identity.repo}`.toLowerCase();
3751
3832
  }
@@ -3755,6 +3836,7 @@ var repo_origin = {
3755
3836
  is_github_ssh_host,
3756
3837
  parse_origin_from_config,
3757
3838
  parse_origin_url,
3839
+ parse_remote_urls_from_config,
3758
3840
  format_identity
3759
3841
  };
3760
3842
 
@@ -3829,17 +3911,23 @@ function resolve_git_directory(repository_path) {
3829
3911
  return void 0;
3830
3912
  }
3831
3913
  }
3832
- function read_origin_url(repository_path) {
3914
+ function read_config(repository_path) {
3833
3915
  const git_directory = resolve_git_directory(repository_path);
3834
3916
  if (git_directory === void 0) return void 0;
3835
3917
  try {
3836
- return repo_origin.parse_origin_from_config(
3837
- readFileSync3(path5.join(git_directory, GIT_CONFIG), "utf8")
3838
- );
3918
+ return readFileSync3(path5.join(git_directory, GIT_CONFIG), "utf8");
3839
3919
  } catch {
3840
3920
  return void 0;
3841
3921
  }
3842
3922
  }
3923
+ function read_origin_url(repository_path) {
3924
+ const config = read_config(repository_path);
3925
+ return config === void 0 ? void 0 : repo_origin.parse_origin_from_config(config);
3926
+ }
3927
+ function read_remote_urls(repository_path) {
3928
+ const config = read_config(repository_path);
3929
+ return config === void 0 ? [] : repo_origin.parse_remote_urls_from_config(config);
3930
+ }
3843
3931
  function sibling_directories(parent) {
3844
3932
  try {
3845
3933
  return readdirSync(parent, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => path5.join(parent, entry.name)).toSorted((left, right) => left.localeCompare(right));
@@ -3878,6 +3966,7 @@ var repo_discovery = {
3878
3966
  OVERRIDE_ENV_KEY,
3879
3967
  main_worktree,
3880
3968
  read_origin_url,
3969
+ read_remote_urls,
3881
3970
  resolve_current_owner,
3882
3971
  scan_siblings,
3883
3972
  discover_repositories
@@ -3887,6 +3976,8 @@ var repo_discovery = {
3887
3976
  var FIRST_PARTY = "first-party";
3888
3977
  var THIRD_PARTY = "third-party";
3889
3978
  var UNKNOWN = "unknown";
3979
+ var GH_REPO_ENV_KEY = "GH_REPO";
3980
+ var GH_REPO_PATH_SEGMENTS = 2;
3890
3981
  function classify4(session_owner, target) {
3891
3982
  if (session_owner === void 0 || target === void 0) return UNKNOWN;
3892
3983
  return session_owner.toLowerCase() === target.toLowerCase() ? FIRST_PARTY : THIRD_PARTY;
@@ -3897,7 +3988,25 @@ function target_owner(owner_repo) {
3897
3988
  function current_owner(repository_path = process.cwd()) {
3898
3989
  return repo_discovery.resolve_current_owner(repository_path);
3899
3990
  }
3900
- var repo_party = { FIRST_PARTY, THIRD_PARTY, UNKNOWN, classify: classify4, current_owner, target_owner };
3991
+ function gh_repo_owners(gh_repo) {
3992
+ return [target_owner(gh_repo.split("/").slice(-GH_REPO_PATH_SEGMENTS).join("/"))];
3993
+ }
3994
+ function remote_owners(repository_path) {
3995
+ return repo_discovery.read_remote_urls(repository_path).map((url) => repo_origin.parse_origin_url(url)?.owner);
3996
+ }
3997
+ function placeholder_owners(repository_path = process.cwd(), environment2 = process.env) {
3998
+ const gh_repo = environment2[GH_REPO_ENV_KEY];
3999
+ return gh_repo === void 0 || gh_repo === "" ? remote_owners(repository_path) : gh_repo_owners(gh_repo);
4000
+ }
4001
+ var repo_party = {
4002
+ FIRST_PARTY,
4003
+ THIRD_PARTY,
4004
+ UNKNOWN,
4005
+ classify: classify4,
4006
+ current_owner,
4007
+ placeholder_owners,
4008
+ target_owner
4009
+ };
3901
4010
 
3902
4011
  // scripts/lane/lane-reap.ts
3903
4012
  import { execFileSync as execFileSync3 } from "node:child_process";
@@ -4494,10 +4603,14 @@ function commit_status_api_path(commit_sha, repo) {
4494
4603
  function tag_reference_api_path(tag, repo) {
4495
4604
  return `${repo_api_path(repo)}/git/ref/tags/${tag}`;
4496
4605
  }
4606
+ function release_by_tag_api_path(tag, repo) {
4607
+ return `${repo_api_path(repo)}/releases/tags/${tag}`;
4608
+ }
4497
4609
  var git_gh_api_path = {
4498
4610
  FULL_PAGE_QUERY,
4499
4611
  repo_api_path,
4500
4612
  tag_ref_api_path: tag_reference_api_path,
4613
+ release_by_tag_api_path,
4501
4614
  issues_api_path,
4502
4615
  issue_api_path,
4503
4616
  blocked_by_api_path,
@@ -4772,77 +4885,8 @@ var git_gh_helpers = {
4772
4885
  handle_pr_create_error
4773
4886
  };
4774
4887
 
4775
- // scripts/git/schemas.ts
4776
- import { z as z11 } from "zod";
4777
- var package_name_schema = z11.object({ name: z11.string().min(1) });
4778
- var rollup_item_schema = z11.looseObject({
4779
- // eslint-disable-next-line @typescript-eslint/naming-convention -- GraphQL field name from GitHub API
4780
- __typename: z11.string().optional(),
4781
- state: z11.string().optional(),
4782
- status: z11.string().optional(),
4783
- conclusion: z11.string().optional(),
4784
- name: z11.string().optional(),
4785
- context: z11.string().optional()
4786
- });
4787
- var pr_raw_schema = z11.object({
4788
- statusCheckRollup: z11.array(rollup_item_schema).optional(),
4789
- mergeStateStatus: z11.string().optional(),
4790
- reviewDecision: z11.string().optional()
4791
- });
4792
- var pull_comment_schema = z11.object({
4793
- body: z11.string().optional(),
4794
- html_url: z11.string().optional(),
4795
- user: z11.object({ login: z11.string().optional() }).optional()
4796
- });
4797
- var ai_review_pull_comment_schema = z11.object({
4798
- body: z11.string().optional(),
4799
- url: z11.string().optional(),
4800
- author: z11.object({ login: z11.string().optional() }).optional()
4801
- });
4802
- var pr_info_schema = z11.object({
4803
- mergeable: z11.union([z11.boolean(), z11.string()]).nullable().optional(),
4804
- mergeStateStatus: z11.string().nullable().optional(),
4805
- state: z11.string().optional()
4806
- });
4807
- var epic_issue_schema = z11.object({
4808
- number: z11.number(),
4809
- body: z11.string().optional()
4810
- });
4811
- var blocking_issue_schema = z11.object({
4812
- number: z11.number(),
4813
- state: z11.string().optional(),
4814
- repository_url: z11.string().optional()
4815
- });
4816
- var blocked_by_schema = z11.object({
4817
- nodes: z11.array(blocking_issue_schema).default([]),
4818
- totalCount: z11.number().optional()
4819
- }).optional();
4820
- var epic_child_schema = z11.object({
4821
- state: z11.string().optional(),
4822
- blockedBy: blocked_by_schema
4823
- });
4824
- var rest_comment_schema = z11.looseObject({
4825
- body: z11.string().nullish(),
4826
- html_url: z11.string().optional(),
4827
- user: z11.looseObject({ login: z11.string().optional() }).nullish()
4828
- });
4829
- var issue_label_schema = z11.object({ name: z11.string() });
4830
- var epic_subject_schema = z11.object({
4831
- number: z11.number(),
4832
- state: z11.string().optional(),
4833
- labels: z11.array(issue_label_schema).optional(),
4834
- body: z11.string().optional()
4835
- });
4836
- var open_issue_schema = z11.object({
4837
- number: z11.number(),
4838
- title: z11.string(),
4839
- labels: z11.array(issue_label_schema).optional(),
4840
- createdAt: z11.string(),
4841
- blockedBy: blocked_by_schema
4842
- });
4843
-
4844
4888
  // scripts/gh/git-gh-issue-rest.ts
4845
- import { z as z12 } from "zod";
4889
+ import { z as z11 } from "zod";
4846
4890
 
4847
4891
  // scripts/gh/git-gh-rest-state.ts
4848
4892
  var MERGED_STATE = "MERGED";
@@ -4851,11 +4895,11 @@ function to_gh_state(state) {
4851
4895
  }
4852
4896
 
4853
4897
  // scripts/gh/git-gh-issue-rest.ts
4854
- var rest_issue_schema = z12.looseObject({
4855
- number: z12.number(),
4856
- issue_dependencies_summary: z12.looseObject({ total_blocked_by: z12.number().optional() }).nullish(),
4898
+ var rest_issue_schema = z11.looseObject({
4899
+ number: z11.number(),
4900
+ issue_dependencies_summary: z11.looseObject({ total_blocked_by: z11.number().optional() }).nullish(),
4857
4901
  // Present only on a pull request, which this endpoint serves as readily as an issue.
4858
- pull_request: z12.looseObject({ merged_at: z12.string().nullish() }).nullish()
4902
+ pull_request: z11.looseObject({ merged_at: z11.string().nullish() }).nullish()
4859
4903
  });
4860
4904
  var REPOSITORY_URL = /\/repos\/([\w.-]+\/[\w.-]+)$/u;
4861
4905
  var REPOSITORY_URL_GROUP = 1;
@@ -5340,7 +5384,7 @@ var NUMBER_AND_BODY_FIELDS = "number,body";
5340
5384
  var BACKLOG_SCAN_FIELDS = `number,title,body,${BLOCKED_BY_COUNT_FIELD}`;
5341
5385
  var NUMBER_TITLE_AND_LABELS_FIELDS = "number,title,labels";
5342
5386
  var SUMMARY_FIELDS = "number,title,labels,createdAt";
5343
- var PICKUP_FIELDS = `${SUMMARY_FIELDS},blockedBy`;
5387
+ var PICKUP_FIELDS = `${SUMMARY_FIELDS},blockedBy,body`;
5344
5388
  var { issue_list: issue_list2 } = git_gh_issue_list;
5345
5389
  async function issue_list_recent(limit) {
5346
5390
  return await issue_list2({ json_fields: SUMMARY_FIELDS, limit });
@@ -5391,18 +5435,18 @@ var git_gh_issue = {
5391
5435
  // scripts/ci/pr-classification.ts
5392
5436
  import { readFileSync as readFileSync4 } from "node:fs";
5393
5437
  import { fileURLToPath as fileURLToPath2 } from "node:url";
5394
- import { z as z13 } from "zod";
5438
+ import { z as z12 } from "zod";
5395
5439
  var CLASSIFICATION_SET = new Set(RELEASE_CLASSIFICATION_NAMES);
5396
5440
  var ISSUE_BUG_LABEL = "bug";
5397
5441
  var DECLARATION_PREFIX = "- \u30EA\u30EA\u30FC\u30B9\u5206\u985E: ";
5398
5442
  var DECLARATION = new RegExp(`^${DECLARATION_PREFIX}(.+)$`, "gmu");
5399
5443
  var LEGACY_LABELS = /* @__PURE__ */ new Set(["semver-major", "semver-minor"]);
5400
- var LABEL = z13.object({ name: z13.string() });
5401
- var USER = z13.object({ login: z13.string() });
5402
- var PULL_REQUEST = z13.object({ number: z13.number(), user: USER });
5403
- var EVENT = z13.object({
5444
+ var LABEL = z12.object({ name: z12.string() });
5445
+ var USER = z12.object({ login: z12.string() });
5446
+ var PULL_REQUEST = z12.object({ number: z12.number(), user: USER });
5447
+ var EVENT = z12.object({
5404
5448
  pull_request: PULL_REQUEST,
5405
- repository: z13.object({ full_name: z13.string() })
5449
+ repository: z12.object({ full_name: z12.string() })
5406
5450
  });
5407
5451
  function classification_error(labels, author) {
5408
5452
  const legacy = labels.filter((label2) => LEGACY_LABELS.has(label2.toLowerCase()));
@@ -5425,7 +5469,7 @@ function release_candidates(candidates) {
5425
5469
  return candidates.filter((candidate) => candidate !== ENHANCEMENT_LABEL);
5426
5470
  }
5427
5471
  function issue_candidates(issue_json) {
5428
- const issue = z13.object({ labels: z13.array(LABEL), body: z13.string().nullable() }).parse(JSON.parse(issue_json));
5472
+ const issue = z12.object({ labels: z12.array(LABEL), body: z12.string().nullable() }).parse(JSON.parse(issue_json));
5429
5473
  const names = issue.labels.map((label2) => label2.name.toLowerCase());
5430
5474
  const declared = [...(issue.body ?? "").matchAll(DECLARATION)].map((match) => match[1] ?? "");
5431
5475
  const candidates = [...release_candidates([...names, ...declared].filter(is_classification))];
@@ -5500,31 +5544,31 @@ async function poll_until(is_done2, options) {
5500
5544
  var poll = { poll_until, sleep: sleep3 };
5501
5545
 
5502
5546
  // scripts/gh/git-gh-pr.ts
5503
- import { z as z17 } from "zod";
5547
+ import { z as z16 } from "zod";
5504
5548
 
5505
5549
  // scripts/gh/git-gh-pr-rest.ts
5506
- import { z as z14 } from "zod";
5507
- var rest_repo_schema = z14.looseObject({ full_name: z14.string().optional() }).nullish();
5508
- var rest_pull_side_schema = z14.looseObject({ repo: rest_repo_schema });
5509
- var rest_pull_schema = z14.looseObject({
5510
- number: z14.number(),
5511
- html_url: z14.string().optional(),
5512
- body: z14.string().nullish(),
5513
- state: z14.string().optional(),
5514
- merged: z14.boolean().nullish(),
5515
- merged_at: z14.string().nullish(),
5516
- mergeable: z14.boolean().nullish(),
5517
- mergeable_state: z14.string().optional(),
5550
+ import { z as z13 } from "zod";
5551
+ var rest_repo_schema = z13.looseObject({ full_name: z13.string().optional() }).nullish();
5552
+ var rest_pull_side_schema = z13.looseObject({ repo: rest_repo_schema });
5553
+ var rest_pull_schema = z13.looseObject({
5554
+ number: z13.number(),
5555
+ html_url: z13.string().optional(),
5556
+ body: z13.string().nullish(),
5557
+ state: z13.string().optional(),
5558
+ merged: z13.boolean().nullish(),
5559
+ merged_at: z13.string().nullish(),
5560
+ mergeable: z13.boolean().nullish(),
5561
+ mergeable_state: z13.string().optional(),
5518
5562
  // `sha` is the head commit, which is what both halves of the merge-gate rollup are keyed by —
5519
5563
  // REST hangs the check runs and the status contexts off the commit rather than off the pull
5520
5564
  // request (joshuafolkken/kit#1028).
5521
- head: z14.looseObject({ ref: z14.string().optional(), sha: z14.string().optional(), repo: rest_repo_schema }).nullish(),
5565
+ head: z13.looseObject({ ref: z13.string().optional(), sha: z13.string().optional(), repo: rest_repo_schema }).nullish(),
5522
5566
  base: rest_pull_side_schema.nullish(),
5523
5567
  // `node_id` is what the GraphQL auto-merge mutation addresses a pull request by, and `auto_merge`
5524
5568
  // is `null` until auto-merge is enabled — both read by `git-gh-pr-auto-merge.ts`
5525
5569
  // (joshuafolkken/kit#2497).
5526
- node_id: z14.string().optional(),
5527
- auto_merge: z14.looseObject({}).nullish()
5570
+ node_id: z13.string().optional(),
5571
+ auto_merge: z13.looseObject({}).nullish()
5528
5572
  });
5529
5573
  var NOT_A_PULL_MESSAGE = "gh api answered something other than a pull request object";
5530
5574
  var NOT_A_PULL_LISTING_MESSAGE = "gh api answered something other than a pull request listing";
@@ -5677,7 +5721,8 @@ async function pr_get_merge_state(branch_name) {
5677
5721
  return {
5678
5722
  is_merged: git_gh_pr_rest.is_merged(pull),
5679
5723
  merged_at: pull.merged_at ?? void 0,
5680
- head_sha: pull.head?.sha
5724
+ head_sha: pull.head?.sha,
5725
+ merge_state_status: to_gh_state(pull.mergeable_state)
5681
5726
  };
5682
5727
  }
5683
5728
  async function pr_get_body(branch_name) {
@@ -5724,14 +5769,14 @@ var git_gh_pr_read = {
5724
5769
  };
5725
5770
 
5726
5771
  // scripts/gh/git-gh-pr-review.ts
5727
- import { z as z15 } from "zod";
5772
+ import { z as z14 } from "zod";
5728
5773
  var REVIEW_APPROVED = "APPROVED";
5729
5774
  var REVIEW_CHANGES_REQUESTED = "CHANGES_REQUESTED";
5730
5775
  var REVIEW_NONE = "";
5731
5776
  var STATE_CHANGING_REVIEWS = /* @__PURE__ */ new Set([REVIEW_APPROVED, REVIEW_CHANGES_REQUESTED]);
5732
- var rest_review_schema = z15.looseObject({
5733
- state: z15.string().optional(),
5734
- user: z15.looseObject({ login: z15.string().optional() }).nullish()
5777
+ var rest_review_schema = z14.looseObject({
5778
+ state: z14.string().optional(),
5779
+ user: z14.looseObject({ login: z14.string().optional() }).nullish()
5735
5780
  });
5736
5781
  var NOT_A_REVIEW_LISTING = "gh api answered something other than a review listing";
5737
5782
  function parse_rest_reviews(reviews_json) {
@@ -5764,18 +5809,18 @@ function to_review_decision(reviews_json) {
5764
5809
  var git_gh_pr_review = { to_review_decision };
5765
5810
 
5766
5811
  // scripts/gh/git-gh-pr-rollup.ts
5767
- import { z as z16 } from "zod";
5812
+ import { z as z15 } from "zod";
5768
5813
  var STATUS_CONTEXT_TYPE_NAME = "StatusContext";
5769
5814
  var TYPE_NAME_KEY = "__typename";
5770
- var rollup_element_schema = z16.looseObject({});
5771
- var check_runs_page_schema = z16.looseObject({
5815
+ var rollup_element_schema = z15.looseObject({});
5816
+ var check_runs_page_schema = z15.looseObject({
5772
5817
  // Required, not optional: GitHub always names the key, and accepting a page without one would
5773
5818
  // answer an empty rollup — which `git-pr-followup.ts` reports as "this branch has no checks".
5774
- check_runs: z16.array(rollup_element_schema)
5819
+ check_runs: z15.array(rollup_element_schema)
5775
5820
  });
5776
- var id_holder_schema = z16.object({ id: z16.number() });
5777
- var status_page_schema = z16.looseObject({
5778
- statuses: z16.array(rollup_element_schema)
5821
+ var id_holder_schema = z15.object({ id: z15.number() });
5822
+ var status_page_schema = z15.looseObject({
5823
+ statuses: z15.array(rollup_element_schema)
5779
5824
  });
5780
5825
  var NOT_A_CHECK_RUNS_LISTING = "gh api answered something other than a check run listing";
5781
5826
  var NOT_A_STATUS_LISTING = "gh api answered something other than a commit status listing";
@@ -5909,7 +5954,7 @@ var MERGE_READ_BACK_ATTEMPTS = 3;
5909
5954
  var MERGE_READ_BACK_INTERVAL_MS = 1e3;
5910
5955
  var PR_NUMBER_PATTERN = /\/pull\/([1-9]\d*)$/u;
5911
5956
  var LABELS_SEGMENT2 = "/labels";
5912
- var PR_LABELS = z17.array(z17.object({ name: z17.string() }));
5957
+ var PR_LABELS = z16.array(z16.object({ name: z16.string() }));
5913
5958
  async function add_pr_classification(number, label2) {
5914
5959
  await git_gh_exec.exec_gh_api({
5915
5960
  path: `${git_gh_api_path.issue_api_path(number)}${LABELS_SEGMENT2}`,
@@ -6077,178 +6122,6 @@ var git_gh_repo = {
6077
6122
  repo_get_name_with_owner
6078
6123
  };
6079
6124
 
6080
- // scripts/gh/git-pr-checks-parse.ts
6081
- var CHECK_STATUS_PASS = "pass";
6082
- var CHECK_STATUS_PENDING = "pending";
6083
- var CHECK_STATUS_FAIL = "fail";
6084
- var CHECK_STATUS_MISSING = "missing";
6085
- var PASSING_CONCLUSIONS = /* @__PURE__ */ new Set(["success", "skipped", "neutral"]);
6086
- var KEY_TYPE_NAME = "__typename";
6087
- var KEY_STATE = "state";
6088
- var KEY_STATUS = "status";
6089
- var KEY_CONCLUSION = "conclusion";
6090
- var KEY_NAME = "name";
6091
- var KEY_CONTEXT = "context";
6092
- function read_string(value) {
6093
- if (typeof value !== "string") return void 0;
6094
- const trimmed2 = value.trim();
6095
- if (trimmed2.length === 0) return void 0;
6096
- return trimmed2;
6097
- }
6098
- var PENDING_STATUS_STATES = /* @__PURE__ */ new Set(["pending", "expected"]);
6099
- function parse_status_context(item) {
6100
- const state = read_string(item[KEY_STATE])?.toLowerCase();
6101
- if (state === "success") return CHECK_STATUS_PASS;
6102
- if (state !== void 0 && PENDING_STATUS_STATES.has(state)) return CHECK_STATUS_PENDING;
6103
- return CHECK_STATUS_FAIL;
6104
- }
6105
- function is_passing_conclusion(item) {
6106
- const conclusion = read_string(item[KEY_CONCLUSION])?.toLowerCase();
6107
- return conclusion !== void 0 && PASSING_CONCLUSIONS.has(conclusion);
6108
- }
6109
- function parse_check_run(item) {
6110
- const status2 = read_string(item[KEY_STATUS])?.toLowerCase();
6111
- if (status2 !== "completed") return CHECK_STATUS_PENDING;
6112
- return is_passing_conclusion(item) ? CHECK_STATUS_PASS : CHECK_STATUS_FAIL;
6113
- }
6114
- function parse_rollup_status(item) {
6115
- const type_name = read_string(item[KEY_TYPE_NAME]);
6116
- if (type_name === "StatusContext") return parse_status_context(item);
6117
- return parse_check_run(item);
6118
- }
6119
- function read_rollup_array(parsed) {
6120
- const result = pr_raw_schema.safeParse(parsed);
6121
- if (!result.success) return [];
6122
- return result.data.statusCheckRollup ?? [];
6123
- }
6124
- function parse_rollup_item(item) {
6125
- const name = read_string(item[KEY_NAME]) ?? read_string(item[KEY_CONTEXT]);
6126
- if (name === void 0) return void 0;
6127
- return { name, status: parse_rollup_status(item) };
6128
- }
6129
- function parse_rollup_checks(raw_json) {
6130
- const parsed = json_value.parse_or_undefined(raw_json);
6131
- const rollup = read_rollup_array(parsed);
6132
- const checks = [];
6133
- for (const item of rollup) {
6134
- const parsed_item = parse_rollup_item(item);
6135
- if (parsed_item !== void 0) checks.push(parsed_item);
6136
- }
6137
- return checks;
6138
- }
6139
- function parse_pr_state_snapshot(raw_json) {
6140
- const parsed = json_value.parse_or_undefined(raw_json);
6141
- const result = pr_raw_schema.safeParse(parsed);
6142
- const data = result.success ? result.data : void 0;
6143
- return {
6144
- rollup: parse_rollup_checks(raw_json),
6145
- merge_state_status: read_string(data?.mergeStateStatus),
6146
- review_decision: read_string(data?.reviewDecision)
6147
- };
6148
- }
6149
-
6150
- // scripts/gh/git-pr-checks-eval.ts
6151
- var DEFAULT_REQUIRED_CHECKS = ["SonarQube"];
6152
- var CODERABBIT_CHECK_NAME = "CodeRabbit";
6153
- var REQUIRED_CHECKS_ENV_VAR = "JOSH_REQUIRED_CHECKS";
6154
- function parse_required_checks() {
6155
- const raw = process.env[REQUIRED_CHECKS_ENV_VAR];
6156
- if (!raw) return DEFAULT_REQUIRED_CHECKS;
6157
- return raw.split(",").map((check) => check.trim()).filter((check) => check.length > 0);
6158
- }
6159
- var REQUIRED_CHECKS = parse_required_checks();
6160
- var MERGE_STATE_CLEAN = "CLEAN";
6161
- var MERGE_STATE_UNSTABLE = "UNSTABLE";
6162
- var MERGE_STATE_DIRTY = "DIRTY";
6163
- var REVIEW_CHANGES_REQUESTED2 = "CHANGES_REQUESTED";
6164
- var CHECK_SUITE_SEPARATOR = " / ";
6165
- var FAILURE_MESSAGE_PREFIX = "PR checks failed";
6166
- var FAILURE_REASON_REVIEW = "review requested changes";
6167
- var FAILURE_REASON_CHECKS = "failed checks";
6168
- var FAILURE_REASON_CONFLICT = "merge conflict";
6169
- function is_required_match(check_name, required_name) {
6170
- if (check_name === required_name) return true;
6171
- return check_name.startsWith(`${required_name}${CHECK_SUITE_SEPARATOR}`);
6172
- }
6173
- function find_required_check(checks, required_name) {
6174
- return checks.find((check) => is_required_match(check.name, required_name));
6175
- }
6176
- function read_required_statuses(checks) {
6177
- return REQUIRED_CHECKS.map(
6178
- (name) => find_required_check(checks, name)?.status ?? CHECK_STATUS_MISSING
6179
- );
6180
- }
6181
- function is_review_blocked(review_decision) {
6182
- return review_decision === REVIEW_CHANGES_REQUESTED2;
6183
- }
6184
- function is_merge_conflict(merge_state_status) {
6185
- return merge_state_status === MERGE_STATE_DIRTY;
6186
- }
6187
- function evaluate_failure_state(input) {
6188
- if (is_merge_conflict(input.merge_state_status) || is_review_blocked(input.review_decision) || input.failed_checks.length > 0) {
6189
- return "failure";
6190
- }
6191
- return void 0;
6192
- }
6193
- function is_merge_state_clean(merge_state_status) {
6194
- return merge_state_status === MERGE_STATE_CLEAN;
6195
- }
6196
- function is_every_required_passing(statuses) {
6197
- return statuses.every((status2) => status2 === CHECK_STATUS_PASS);
6198
- }
6199
- function is_coderabbit_check(check_name) {
6200
- return is_required_match(check_name, CODERABBIT_CHECK_NAME);
6201
- }
6202
- function is_unstable_only_from_coderabbit(snapshot) {
6203
- if (snapshot.merge_state_status !== MERGE_STATE_UNSTABLE) return false;
6204
- const non_passing = snapshot.rollup.filter((check) => check.status !== CHECK_STATUS_PASS);
6205
- if (non_passing.length === 0) return false;
6206
- return non_passing.every((check) => is_coderabbit_check(check.name));
6207
- }
6208
- function is_required_check(check_name) {
6209
- return REQUIRED_CHECKS.some((required) => is_required_match(check_name, required));
6210
- }
6211
- function is_blocking_failure(check) {
6212
- if (check.status !== CHECK_STATUS_FAIL) return false;
6213
- return !is_coderabbit_check(check.name) || is_required_check(check.name);
6214
- }
6215
- function collect_blocking_failures(snapshot) {
6216
- return snapshot.rollup.filter((check) => is_blocking_failure(check)).map((check) => check.name);
6217
- }
6218
- function is_mergeable_state(snapshot) {
6219
- if (is_merge_state_clean(snapshot.merge_state_status)) return true;
6220
- return is_unstable_only_from_coderabbit(snapshot);
6221
- }
6222
- function collect_failure_reasons(snapshot) {
6223
- const reasons = [];
6224
- if (is_merge_conflict(snapshot.merge_state_status)) reasons.push(FAILURE_REASON_CONFLICT);
6225
- if (is_review_blocked(snapshot.review_decision)) reasons.push(FAILURE_REASON_REVIEW);
6226
- const failed = collect_blocking_failures(snapshot);
6227
- if (failed.length > 0) reasons.push(`${FAILURE_REASON_CHECKS}: ${failed.join(", ")}`);
6228
- return reasons;
6229
- }
6230
- function describe_pr_failure(snapshot) {
6231
- const reasons = collect_failure_reasons(snapshot);
6232
- if (reasons.length === 0) return `${FAILURE_MESSAGE_PREFIX}.`;
6233
- return `${FAILURE_MESSAGE_PREFIX} (${reasons.join("; ")}).`;
6234
- }
6235
- function evaluate_pr_state(snapshot) {
6236
- const statuses = read_required_statuses(snapshot.rollup);
6237
- const failure = evaluate_failure_state({
6238
- review_decision: snapshot.review_decision,
6239
- failed_checks: collect_blocking_failures(snapshot),
6240
- merge_state_status: snapshot.merge_state_status
6241
- });
6242
- if (failure !== void 0) return failure;
6243
- if (is_mergeable_state(snapshot) && is_every_required_passing(statuses)) {
6244
- return "success";
6245
- }
6246
- return "pending";
6247
- }
6248
- function is_review_decision_decisive(snapshot) {
6249
- return evaluate_pr_state(snapshot) !== "pending";
6250
- }
6251
-
6252
6125
  // scripts/gh/git-pr-checks.ts
6253
6126
  var SECONDS_TO_MS = 1e3;
6254
6127
  var CHECK_WAIT_INTERVAL_MS = 1e4;
@@ -6277,9 +6150,14 @@ var MERGE_GATE_EVALUATOR = {
6277
6150
  function advance_stable_count(previous, state) {
6278
6151
  return state === "success" ? previous + 1 : 0;
6279
6152
  }
6153
+ function failure_error(message, snapshot) {
6154
+ return is_merge_conflict(snapshot.merge_state_status) ? new PrConflictError(message) : new Error(message);
6155
+ }
6280
6156
  function classify_poll_result(input) {
6281
6157
  const state = input.evaluator.evaluate(input.snapshot);
6282
- if (state === "failure") throw new Error(input.evaluator.describe(input.snapshot));
6158
+ if (state === "failure") {
6159
+ throw failure_error(input.evaluator.describe(input.snapshot), input.snapshot);
6160
+ }
6283
6161
  const next_stable_count = advance_stable_count(input.stable_count, state);
6284
6162
  return {
6285
6163
  is_done: next_stable_count >= input.required_stable_reads,
@@ -6430,11 +6308,11 @@ export {
6430
6308
  tail_commands,
6431
6309
  filing_cap,
6432
6310
  CONTEXT_CUT_THRESHOLD,
6433
- RECENT_REQUEST_WINDOW,
6434
6311
  agent_role_profile,
6435
6312
  cli_flags,
6436
6313
  own_session,
6437
6314
  backlog_budget,
6315
+ run_cut_handoff,
6438
6316
  run_hold,
6439
6317
  run_cut,
6440
6318
  run_tail,
@@ -6464,7 +6342,6 @@ export {
6464
6342
  read_json_listing,
6465
6343
  parse_json_object_safe,
6466
6344
  git_gh_exec,
6467
- open_issue_schema,
6468
6345
  git_gh_issue_read,
6469
6346
  git_gh_pr_read,
6470
6347
  git_gh_command