@joshuafolkken/kit 1.1455.0 → 1.1471.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 (211) hide show
  1. package/.claude/skills/dependency-update/SKILL.md +26 -55
  2. package/.claude/skills/epic-commands/SKILL.md +87 -148
  3. package/.claude/skills/epic-commands/epic-bundle.md +45 -77
  4. package/.claude/skills/epic-commands/execution-waves.md +44 -81
  5. package/.claude/skills/verify-ui/SKILL.md +25 -50
  6. package/.claude/skills/workflow-commands/background-commands.md +36 -47
  7. package/.claude/skills/workflow-commands/backlogrun-child.md +72 -85
  8. package/.claude/skills/workflow-commands/backlogrun-lanes.md +91 -121
  9. package/.claude/skills/workflow-commands/backlogrun-park.md +73 -117
  10. package/.claude/skills/workflow-commands/backlogrun-progress.md +7 -9
  11. package/.claude/skills/workflow-commands/backlogrun-recovery.md +11 -20
  12. package/.claude/skills/workflow-commands/backlogrun-steps.md +43 -52
  13. package/.claude/skills/workflow-commands/chain-rule.md +24 -34
  14. package/.claude/skills/workflow-commands/followup.md +57 -76
  15. package/.claude/skills/workflow-commands/issue-comments.md +43 -60
  16. package/.claude/skills/workflow-commands/kickoff.md +65 -74
  17. package/.claude/skills/workflow-commands/observation-filing.md +62 -107
  18. package/.claude/skills/workflow-commands/observation-ledger.md +56 -111
  19. package/.claude/skills/workflow-commands/pre-gate-cut.md +89 -138
  20. package/.claude/skills/workflow-commands/prerequisite.md +10 -15
  21. package/.claude/skills/workflow-commands/progress-watcher.md +21 -26
  22. package/.claude/skills/workflow-commands/retrospective.md +31 -50
  23. package/.claude/skills/workflow-commands/split-assessment.md +34 -58
  24. package/.claude/skills/workflow-commands/working-tree-hold.md +54 -71
  25. package/CLAUDE.md +6 -5
  26. package/dist/CLAUDE.md +6 -5
  27. package/dist/hooks/batch-guard.js +6 -6
  28. package/dist/hooks/{chunk-7WQBPLUN.js → chunk-43ZHT22P.js} +31 -15
  29. package/dist/hooks/{chunk-LIAFCXL7.js → chunk-AS74OU3D.js} +23 -7
  30. package/dist/hooks/{chunk-3C4XRYG6.js → chunk-E7OIKX5Z.js} +17 -12
  31. package/dist/hooks/{chunk-Z4XI7CZS.js → chunk-EUMACUK2.js} +18 -12
  32. package/dist/hooks/{chunk-WNLVGT7E.js → chunk-H5HVWYXK.js} +4 -4
  33. package/dist/hooks/{chunk-HHI6FO3R.js → chunk-IIGFYXKC.js} +345 -240
  34. package/dist/hooks/{chunk-GPLGZ6IC.js → chunk-J47HU5H5.js} +14 -3
  35. package/dist/hooks/{chunk-OLMO72ON.js → chunk-K4EOONYM.js} +1 -1
  36. package/dist/hooks/{chunk-D5QBTOCZ.js → chunk-K4LMBQC2.js} +4 -4
  37. package/dist/hooks/{chunk-TBJFTSUY.js → chunk-KC5AK2GF.js} +8 -6
  38. package/dist/hooks/chunk-SHGPANFB.js +56 -0
  39. package/dist/hooks/{chunk-5H4SSDSD.js → chunk-YHBZAJSV.js} +3 -3
  40. package/dist/hooks/{chunk-HFGWYGUV.js → chunk-YYPI7SJZ.js} +5 -5
  41. package/dist/hooks/codex-hook-adapter.js +13 -13
  42. package/dist/hooks/duplicate-read-guard.js +7 -7
  43. package/dist/hooks/format-edited.js +3 -3
  44. package/dist/hooks/inputs.json +216 -214
  45. package/dist/hooks/investigation-guard.js +7 -7
  46. package/dist/hooks/pretool-guard.js +12 -12
  47. package/dist/hooks/session-lang.js +6 -5
  48. package/dist/hooks/stop-guard.js +18 -14
  49. package/dist/josh.js +5 -6
  50. package/dist/managed-marker/index.js +1 -2
  51. package/dist/version/index.js +15 -12
  52. package/eslint/base.js +2 -1
  53. package/eslint/rules/unicorn.js +16 -0
  54. package/package.json +3 -3
  55. package/prompts/coding-standards.md +12 -22
  56. package/prompts/collaboration-workflow/file-edits.md +26 -44
  57. package/prompts/collaboration-workflow/gh-rest.md +20 -36
  58. package/prompts/collaboration-workflow/glossary.md +5 -7
  59. package/prompts/collaboration-workflow/issue-citation.md +7 -13
  60. package/prompts/collaboration-workflow/issue-template.md +29 -29
  61. package/prompts/collaboration-workflow/operating-rules.md +35 -44
  62. package/prompts/collaboration-workflow/output-bounds.md +15 -15
  63. package/prompts/collaboration-workflow/overview.md +14 -19
  64. package/prompts/collaboration-workflow/plan-comment.md +13 -13
  65. package/prompts/collaboration-workflow/principles.md +50 -53
  66. package/prompts/collaboration-workflow/proposal-request.md +1 -9
  67. package/prompts/collaboration-workflow/report-format.md +32 -49
  68. package/prompts/collaboration-workflow/residency.md +10 -10
  69. package/prompts/collaboration-workflow/rule-delivery.md +9 -9
  70. package/prompts/collaboration-workflow/shell-body.md +10 -20
  71. package/prompts/collaboration-workflow/turn-batching.md +8 -14
  72. package/prompts/collaboration-workflow/upstream-interrupt.md +26 -34
  73. package/prompts/collaboration-workflow/wip-cap.md +24 -30
  74. package/prompts/collaboration-workflow.md +24 -25
  75. package/prompts/refactoring.md +33 -43
  76. package/prompts/review-rubric.md +84 -129
  77. package/prompts/review.md +111 -141
  78. package/prompts/sonar-hotspot-handling.md +22 -50
  79. package/prompts/testing-guide.md +48 -99
  80. package/scripts/adopt/adopt-toolkits.ts +2 -4
  81. package/scripts/agent/agent-exit-record.ts +23 -1
  82. package/scripts/agent/codex-agent-argv.ts +7 -2
  83. package/scripts/backlog/backlog-budget-cli.ts +1 -2
  84. package/scripts/backlog/backlog-drive-carried.ts +26 -0
  85. package/scripts/backlog/backlog-drive-cli.ts +10 -5
  86. package/scripts/backlog/backlog-drive-named.ts +2 -4
  87. package/scripts/backlog/backlog-drive-restore.ts +19 -1
  88. package/scripts/backlog/backlog-drive-seats.ts +27 -0
  89. package/scripts/backlog/backlog-drive.ts +11 -6
  90. package/scripts/backlog/backlog-ready.ts +13 -6
  91. package/scripts/behavior/behavior-rules.ts +3 -2
  92. package/scripts/cost-runtime/codex-usage.ts +4 -2
  93. package/scripts/cost-runtime/cost-cli.ts +1 -2
  94. package/scripts/delegation/investigation-guard.ts +1 -1
  95. package/scripts/delegation/investigation-reads.ts +1 -1
  96. package/scripts/discovery/repo-discovery.ts +4 -2
  97. package/scripts/discovery/repo-origin.ts +2 -4
  98. package/scripts/doctor/doctor-logic.ts +6 -3
  99. package/scripts/document/document-byte-budget.ts +27 -27
  100. package/scripts/document/document-byte-check.ts +1 -2
  101. package/scripts/document/entry-read-budget.ts +2 -2
  102. package/scripts/epic/epic-audit-rationale.ts +8 -2
  103. package/scripts/epic/epic-bundle-cli.ts +1 -2
  104. package/scripts/epic/epic-chains.ts +6 -2
  105. package/scripts/epic/epic-close-comment.ts +1 -2
  106. package/scripts/gate/verification-gate.ts +7 -2
  107. package/scripts/gh/git-pr.ts +6 -2
  108. package/scripts/git/git-common-directory.ts +3 -3
  109. package/scripts/git/git-diff-reads.ts +16 -9
  110. package/scripts/git/git-execa-error.ts +1 -2
  111. package/scripts/hooks/format-edited-file.ts +10 -4
  112. package/scripts/hooks/pre-push-unit.ts +15 -4
  113. package/scripts/hooks/pretool-guard.ts +23 -29
  114. package/scripts/hooks/step-zero-notice.ts +3 -2
  115. package/scripts/init/hook-command-rewrite.ts +6 -2
  116. package/scripts/init/init-logic-deploy-vps.ts +4 -2
  117. package/scripts/issue/behavior-change-lint.ts +12 -6
  118. package/scripts/issue/issue-scout-cli.ts +3 -2
  119. package/scripts/josh/file-map-stamp.ts +1 -3
  120. package/scripts/josh/hook-decision.ts +17 -2
  121. package/scripts/lane/lane-await.ts +3 -2
  122. package/scripts/lane/lane-child-invocation.ts +14 -1
  123. package/scripts/lane/lane-guard-policy.ts +4 -4
  124. package/scripts/lane/lane-ledger.ts +9 -0
  125. package/scripts/lane/lane-load.ts +9 -2
  126. package/scripts/lane/lane-measure-cli.ts +2 -0
  127. package/scripts/lane/lane-parked.ts +18 -0
  128. package/scripts/lane/lane-process-load.ts +125 -0
  129. package/scripts/lane/lane-process-stats.ts +93 -0
  130. package/scripts/lane/lane-registry.ts +8 -3
  131. package/scripts/lane/lane-session-broker.ts +29 -5
  132. package/scripts/lane/lane-spent.ts +14 -3
  133. package/scripts/lane/lane-stats.ts +1 -0
  134. package/scripts/managed-marker/managed-marker-logic.ts +1 -2
  135. package/scripts/overrides/lockfile-overrides.ts +1 -3
  136. package/scripts/propagate/propagate.ts +1 -2
  137. package/scripts/release/release-progress.ts +3 -2
  138. package/scripts/report/report-lint.ts +7 -4
  139. package/scripts/review/review-record-cli.ts +6 -2
  140. package/scripts/rules/destructive-command.ts +6 -9
  141. package/scripts/rules/direct-filing.ts +3 -7
  142. package/scripts/rules/early-heartbeat.ts +7 -18
  143. package/scripts/rules/file-body.ts +6 -13
  144. package/scripts/rules/filing-cap.ts +3 -6
  145. package/scripts/rules/git-force.ts +5 -9
  146. package/scripts/rules/implementation-cut.ts +37 -35
  147. package/scripts/rules/index-guard.ts +4 -7
  148. package/scripts/rules/issue-comments.ts +5 -15
  149. package/scripts/rules/josh-git-bare.ts +3 -6
  150. package/scripts/rules/lane-background.ts +10 -21
  151. package/scripts/rules/lane-carry-conflict.ts +7 -17
  152. package/scripts/rules/lane-interactive-ask.ts +6 -11
  153. package/scripts/rules/lane-park.ts +5 -13
  154. package/scripts/rules/lane-split-park.ts +2 -7
  155. package/scripts/rules/lane-switch-main.ts +9 -12
  156. package/scripts/rules/oracle-consulted.ts +4 -5
  157. package/scripts/rules/piped-verification.ts +81 -31
  158. package/scripts/rules/poll-loop.ts +7 -17
  159. package/scripts/rules/pre-gate-cut.ts +7 -21
  160. package/scripts/rules/prior-comment-read.ts +7 -5
  161. package/scripts/rules/protected-files.ts +5 -9
  162. package/scripts/rules/raw-field-body.ts +3 -7
  163. package/scripts/rules/rule-body-guard.ts +4 -11
  164. package/scripts/rules/run-tail-rule.ts +6 -22
  165. package/scripts/rules/shell-body-trigger.ts +4 -6
  166. package/scripts/rules/shell-segments.ts +7 -0
  167. package/scripts/rules/stop-rules.ts +16 -29
  168. package/scripts/rules/test-declared-commit.ts +4 -10
  169. package/scripts/rules/third-party-write.ts +5 -10
  170. package/scripts/rules/worktree-guard.ts +5 -12
  171. package/scripts/run/board/run-board-github.ts +11 -3
  172. package/scripts/run/board/run-board-idle.ts +31 -0
  173. package/scripts/run/board/run-board-read.ts +9 -12
  174. package/scripts/run/board/run-board-reason.ts +7 -3
  175. package/scripts/run/board/run-board-state.ts +4 -0
  176. package/scripts/run/board/run-board-status.ts +18 -3
  177. package/scripts/run/board/run-board-thanks.ts +7 -2
  178. package/scripts/run/board/run-board-tick.ts +32 -7
  179. package/scripts/run/carry/run-carry-args.ts +1 -3
  180. package/scripts/run/carry/run-carry-conversation.ts +7 -2
  181. package/scripts/run/cut/run-cut-cli.ts +15 -20
  182. package/scripts/run/cut/run-cut-decline.ts +72 -0
  183. package/scripts/run/cut/run-cut-ready.ts +74 -0
  184. package/scripts/run/cut/run-cut-report.ts +13 -0
  185. package/scripts/run/cut/run-cut.ts +10 -1
  186. package/scripts/run/hold/run-hold-cli.ts +14 -3
  187. package/scripts/run/hold/run-hold.ts +6 -3
  188. package/scripts/run/merge/run-merge-cli.ts +30 -7
  189. package/scripts/run/merge/run-merge-ship.ts +59 -1
  190. package/scripts/run/merge/run-merge.ts +3 -2
  191. package/scripts/run/run-ending.ts +31 -3
  192. package/scripts/run/run-parent-cut-hook.ts +5 -10
  193. package/scripts/run/run-preflight.ts +1 -2
  194. package/scripts/run/run-stop-notify.ts +1 -2
  195. package/scripts/run/run-watcher-guard.ts +6 -3
  196. package/scripts/run/ship/run-ship-review-steps.ts +13 -4
  197. package/scripts/run/ship/run-ship-review.ts +15 -2
  198. package/scripts/run/tidy/run-tidy-cli.ts +3 -3
  199. package/scripts/run/tidy/run-tidy-lanes.ts +3 -2
  200. package/scripts/safe-chain/project-config.ts +7 -2
  201. package/scripts/sync/sync-hook-safety.ts +8 -2
  202. package/scripts/test/unit-worker-share.ts +3 -2
  203. package/scripts/time-runtime/time-batch-guard.ts +3 -3
  204. package/scripts/time-runtime/time-hook-transcript.ts +3 -2
  205. package/scripts/time-runtime/time-shell.ts +10 -0
  206. package/scripts/version/effective-upstream.ts +3 -4
  207. package/scripts/version/kit-version-config.ts +8 -2
  208. package/scripts/version/latest-corepack.ts +1 -2
  209. package/scripts/version/release-hold.ts +11 -4
  210. package/scripts/version/version-commands.ts +12 -4
  211. package/dist/hooks/chunk-UT7YC3N2.js +0 -56
@@ -9,12 +9,12 @@ import {
9
9
  load_environment_file,
10
10
  notice_refusal_path,
11
11
  refusal_path
12
- } from "./chunk-5H4SSDSD.js";
13
- import "./chunk-UT7YC3N2.js";
14
- import "./chunk-GPLGZ6IC.js";
15
- import "./chunk-LIAFCXL7.js";
16
- import "./chunk-OLMO72ON.js";
17
- import "./chunk-3C4XRYG6.js";
12
+ } from "./chunk-YHBZAJSV.js";
13
+ import "./chunk-SHGPANFB.js";
14
+ import "./chunk-J47HU5H5.js";
15
+ import "./chunk-AS74OU3D.js";
16
+ import "./chunk-K4EOONYM.js";
17
+ import "./chunk-E7OIKX5Z.js";
18
18
  import "./chunk-DGT54IH5.js";
19
19
  export {
20
20
  DISABLED_VALUES,
@@ -8,7 +8,7 @@ import {
8
8
  repo_origin,
9
9
  run_event_stream,
10
10
  run_event_stream_emit
11
- } from "./chunk-Z4XI7CZS.js";
11
+ } from "./chunk-EUMACUK2.js";
12
12
  import {
13
13
  error_text
14
14
  } from "./chunk-CDY4NFQG.js";
@@ -30,10 +30,10 @@ import {
30
30
  time_density_hook,
31
31
  time_shell,
32
32
  time_transcript_line
33
- } from "./chunk-LIAFCXL7.js";
33
+ } from "./chunk-AS74OU3D.js";
34
34
  import {
35
35
  lane_child_marker
36
- } from "./chunk-OLMO72ON.js";
36
+ } from "./chunk-K4EOONYM.js";
37
37
  import {
38
38
  agent_session_environment,
39
39
  backlog_budget,
@@ -42,7 +42,7 @@ import {
42
42
  has_timed_out,
43
43
  json_value,
44
44
  process_identity
45
- } from "./chunk-3C4XRYG6.js";
45
+ } from "./chunk-E7OIKX5Z.js";
46
46
  import {
47
47
  COMMAND_TIMEOUT_MS,
48
48
  PROJECT_ROOT,
@@ -86,9 +86,13 @@ var bounded_pool = { bounded_map, pool_width };
86
86
 
87
87
  // scripts/rules/shell-segments.ts
88
88
  var SEGMENT_SEPARATOR = /&&|\|\||;|\n/u;
89
+ var SEGMENT_PARTS = new RegExp(`(${SEGMENT_SEPARATOR.source})`, "u");
89
90
  function segments_of(command) {
90
91
  return command.split(SEGMENT_SEPARATOR).map((segment) => segment.trim());
91
92
  }
93
+ function parts_of(command) {
94
+ return command.split(SEGMENT_PARTS);
95
+ }
92
96
  function is_josh_command(segment, names) {
93
97
  const named = time_shell.josh_command_of(segment);
94
98
  if (!named.startsWith(time_shell.JOSH_PREFIX)) return false;
@@ -96,6 +100,7 @@ function is_josh_command(segment, names) {
96
100
  }
97
101
  var shell_segments = {
98
102
  is_josh_command,
103
+ parts_of,
99
104
  segments_of
100
105
  };
101
106
 
@@ -174,7 +179,7 @@ function turn_filing_count(tail) {
174
179
  function decide(_call, run) {
175
180
  return prior_filing_count(time_density_hook.read_tail(run.transcript)) >= CAP_REACHED;
176
181
  }
177
- 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.`;
182
+ var FILING_CAP_REASON = `\u26D4 filing cap: this run has already filed ${String(FILING_CAP)} Issues, the per-run ceiling. Stop filing and report; a further Issue is a person's call. It fires on every occurrence (\`.claude/skills/workflow-commands/observation-filing.md\`).`;
178
183
  var ROW = {
179
184
  id: "filing-cap",
180
185
  is_trigger: bash_triggers.on_bash_command(bash_triggers.is_issue_filing),
@@ -394,9 +399,11 @@ function parse_hold(raw) {
394
399
  function is_expired(hold, now) {
395
400
  return stamp_record.is_older_than(hold.taken_at, HOLD_MAX_AGE_MS, now);
396
401
  }
402
+ function is_stop_marked(hold) {
403
+ return hold.is_halfrun_stop === true || hold.prrun_stop_head !== void 0;
404
+ }
397
405
  function is_owner_gone(hold) {
398
- const is_stop_mark = hold.is_halfrun_stop === true || hold.prrun_stop_head !== void 0;
399
- if (is_stop_mark || hold.owner_pid === void 0) return false;
406
+ if (is_stop_marked(hold) || hold.owner_pid === void 0) return false;
400
407
  return process_identity.is_same_process(hold.owner_pid, hold.owner_start) === false;
401
408
  }
402
409
  function is_stale(hold, now) {
@@ -486,6 +493,7 @@ function unknown_message() {
486
493
  return `Could not read this working tree's git directory \u2014 ${NOT_IDLE}. Run this from inside the checkout the run will edit.`;
487
494
  }
488
495
  var run_hold = {
496
+ is_stop_marked,
489
497
  FORCE_RELEASE_COMMAND,
490
498
  HOLD_MAX_AGE_HOURS,
491
499
  HOLD_MAX_AGE_MS,
@@ -872,7 +880,13 @@ async function current_state() {
872
880
  const branch = await git_command.branch();
873
881
  const is_dirty = await run_hold.is_tree_dirty();
874
882
  const hold = hold_of(await worktree_directory2());
875
- return { branch, is_dirty, is_held: hold !== void 0, held_issue: fullrun_issue(hold) };
883
+ return {
884
+ branch,
885
+ is_dirty,
886
+ is_held: hold !== void 0,
887
+ held_issue: fullrun_issue(hold),
888
+ hold_taken_at: hold?.taken_at
889
+ };
876
890
  }
877
891
  function describe_cut(cut) {
878
892
  return `${cut.invocation} cut at ${cut.cut_at} on ${cut.branch} (${cut.phase})`;
@@ -918,6 +932,7 @@ var run_cut = {
918
932
  handed_off_message,
919
933
  has_required_handoff,
920
934
  held_issue_sync,
935
+ hold_of,
921
936
  incomplete_message,
922
937
  invocation_for,
923
938
  is_expired: is_expired2,
@@ -974,7 +989,7 @@ function is_foreground_push_step(call) {
974
989
  function decide2() {
975
990
  return true;
976
991
  }
977
- var RUN_TAIL_REASON = '\u26D4 run tail: this issues the commit-push-PR step in the foreground, where the harness decides when to stop waiting. Reissue it with `run_in_background` set. In `fullrun #1501` this call was given a 900-second timeout, the harness detached it at its own 600-second cap, and nothing read the output for a further 6m28s \u2014 45m03s of wall clock on about 17 minutes of work (joshuafolkken/kit#1510). **Never give a foreground call a timeout above the harness cap**: the cap decides, not the number. A backgrounded call re-invokes you when it exits, so the completion notification is what resumes the run. **When it arrives, the turn that reads it goes straight through any branch-2 filing and `pnpm josh epic:bundle` to `pnpm josh followup` \u2014 the turn never ends at the push.** CI went green 6m06s before the merge started in that run, and it started only because the person asked; joshuafolkken/kit#1333 had already settled that the merge is issued in the turn the review closes. While the push runs, do the work that writes nothing \u2014 drafting the completion body to a file, deciding the branch-2 disposition. `pnpm josh followup` itself stays in the **foreground** \u2014 nearly every step after it reads its result. But a tail does follow the merge, measured at 3.0 min and 5.9% of a run (joshuafolkken/kit#1462), so empty it beforehand: the steps that read the merge result stay after `followup`, and the rest are composed in the turn that issues it, bar the one exception background-commands.md names. The procedure is `.claude/skills/workflow-commands/background-commands.md`, "A command that can take minutes is issued in the background". **This rule fires on every foreground push, not once per run**, so reissuing the same call in the foreground will be refused again.';
992
+ var RUN_TAIL_REASON = "\u26D4 run tail: this issues the commit-push-PR step in the foreground, where the harness decides when to stop waiting. Reissue it with `run_in_background` set; when it exits, go straight on to `pnpm josh followup` in the foreground \u2014 the turn never ends at the push (`.claude/skills/workflow-commands/background-commands.md`). It fires on every foreground push, not once per run.";
978
993
  var run_tail_rule = {
979
994
  RUN_TAIL_REASON,
980
995
  decide: decide2,
@@ -1021,11 +1036,12 @@ function is_background_long_run(call, is_lane_child = () => lane_child_marker.is
1021
1036
  return is_candidate(call) && is_lane_child();
1022
1037
  }
1023
1038
  function foreground_input(call, is_lane_child = () => lane_child_marker.is_child_of(process.cwd())) {
1024
- if (!is_backgrounded_ship(call) || !json_value.is_record(call.input)) return void 0;
1025
- if (!is_lane_child()) return void 0;
1039
+ if (!is_backgrounded_ship(call) || !json_value.is_record(call.input) || !is_lane_child()) {
1040
+ return void 0;
1041
+ }
1026
1042
  return { ...call.input, [BACKGROUND_KEY2]: false, [TIMEOUT_KEY]: FOREGROUND_TIMEOUT_MS };
1027
1043
  }
1028
- 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).";
1044
+ 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`.";
1029
1045
  function unfinished_ids(tail, launched_ids) {
1030
1046
  const lines = tail.split("\n").map((line) => time_transcript_line.parse_line(line));
1031
1047
  const finished = new Set(lines.map((line) => line?.finished_background ?? ""));
@@ -1039,8 +1055,8 @@ function pending_background_ids(tail) {
1039
1055
  function pending_agent_ids(tail) {
1040
1056
  return unfinished_ids(tail, (block) => [block.agent_id]);
1041
1057
  }
1042
- 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.';
1043
- 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.";
1058
+ var LANE_BACKGROUND_REASON = '\u26D4 lane background: this session is a dispatched lane child (`JOSH_LANE_CHILD`), a headless process whose background tasks die when the turn ends. Hand over to `pnpm josh ship --detach --review "<title> #<N>"`, issued in the foreground, then end the turn on `launched` / `busy`. It fires on every occurrence (`.claude/skills/workflow-commands/chain-rule.md` step 0).';
1059
+ 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, and ending this turn kills it. Wait for it in the foreground, or re-issue the work through `pnpm josh ship --detach` \u2014 do not notify, stop or repeat your reply.";
1044
1060
  var ROW2 = {
1045
1061
  id: "lane-background",
1046
1062
  is_trigger: (call) => is_background_long_run(call),
@@ -1484,7 +1500,7 @@ var APPLIES_NEEDS_DECISION = new RegExp(
1484
1500
  function records_the_park(command) {
1485
1501
  return APPLIES_NEEDS_DECISION.test(command);
1486
1502
  }
1487
- var LANE_PARK_REASON = '\u26D4 lane child park: this session is a dispatched lane child, and a stop that waits on a person must leave the question on the Issue before it sends this Telegram \u2014 otherwise the parent finds an OPEN Issue with `in-progress` and no question, and a person cannot tell what to answer (joshuafolkken/kit#2034 measured this twice in one run). The child is the only process that knows the question, the options and whether it stashed, so it records the park itself rather than leaving the parent to guess from a log. Before you notify and stop: apply `needs-decision` and post a comment carrying the question, the options, and whether work was stashed \u2014 `gh api repos/{owner}/{repo}/issues/<N>/labels -f \'labels[]=needs-decision\'` then `pnpm josh issue:comment <N> --body-file <path>`. If this stop is a `needs-human-review` or `already-done` one, that label is already on the Issue and there is nothing to add. Then reissue this notify \u2014 it fires once per run and cannot repeat on the call in hand. The procedure is `.claude/skills/workflow-commands/pre-gate-cut.md` \u2192 "A lane child records its park before it stops", and the park itself is `backlogrun-park.md` \u2192 "park and continue".';
1503
+ var LANE_PARK_REASON = "\u26D4 lane child park: this session is a dispatched lane child, so a stop for a person parks first: `gh api repos/{owner}/{repo}/issues/<N>/labels -f 'labels[]=needs-decision'`; `pnpm josh issue:comment <N> --body-file <path>` (question, options, stash); a `needs-human-review` / `already-done` stop already is. Reissue this notify, once per run (`.claude/skills/workflow-commands/pre-gate-cut.md`).";
1488
1504
  var ROW3 = {
1489
1505
  id: "lane-park",
1490
1506
  is_trigger: bash_triggers.on_bash_command(is_unparked_stop),
@@ -6,7 +6,7 @@ import {
6
6
  process_owner_schema,
7
7
  run_carry,
8
8
  time_instant
9
- } from "./chunk-3C4XRYG6.js";
9
+ } from "./chunk-E7OIKX5Z.js";
10
10
  import {
11
11
  PLATFORM_TEMP_ROOT,
12
12
  PROBE_TIMEOUT_MS,
@@ -862,8 +862,9 @@ function is_worker_flag(argument) {
862
862
  return WORKER_FLAGS.some((flag) => argument === flag || argument.startsWith(`${flag}=`));
863
863
  }
864
864
  function worker_arguments(vitest_arguments, share) {
865
- if (share === void 0) return [];
866
- if (vitest_arguments.some((argument) => is_worker_flag(argument))) return [];
865
+ if (share === void 0 || vitest_arguments.some((argument) => is_worker_flag(argument))) {
866
+ return [];
867
+ }
867
868
  return [`${WORKER_FLAG}=${String(share)}`];
868
869
  }
869
870
  function mark_run_started(target2) {
@@ -2345,6 +2346,10 @@ function without_heredoc_bodies(command) {
2345
2346
  function unquoted(command) {
2346
2347
  return without_heredoc_bodies(command).replaceAll(QUOTED_SPAN_PATTERN, " ");
2347
2348
  }
2349
+ function blanked(command) {
2350
+ if (HEREDOC_MARKER.test(command)) return void 0;
2351
+ return command.replaceAll(QUOTED_SPAN_PATTERN, (span) => " ".repeat(span.length));
2352
+ }
2348
2353
  function discarded_commands(command) {
2349
2354
  const plain = unquoted(command);
2350
2355
  if (PIPEFAIL_PATTERN.test(plain)) return [];
@@ -2392,6 +2397,7 @@ var time_shell = {
2392
2397
  JOSH_PREFIX,
2393
2398
  bash_command,
2394
2399
  bash_label,
2400
+ blanked,
2395
2401
  command_segment,
2396
2402
  discarded_commands,
2397
2403
  josh_arguments,
@@ -2776,13 +2782,22 @@ var gate_schema = z4.object({
2776
2782
  // whichever was higher. Absent when the machine could not be read.
2777
2783
  external_cores: z4.number().optional()
2778
2784
  });
2785
+ var process_kind_schema = z4.object({
2786
+ kind: z4.string(),
2787
+ cpu_percent: z4.number(),
2788
+ rss_mb: z4.number(),
2789
+ count: z4.number()
2790
+ });
2779
2791
  var load_schema = z4.object({
2780
2792
  kind: z4.literal(KIND.LOAD),
2781
2793
  at: z4.string(),
2782
2794
  load: z4.number(),
2783
2795
  available_mb: z4.number().optional(),
2784
2796
  swapped_mb: z4.number().optional(),
2785
- lanes: z4.number().optional()
2797
+ lanes: z4.number().optional(),
2798
+ // The heaviest process kinds at the instant of the sample (`lane-process-load.ts`), so the load the
2799
+ // core budget's ledger does not explain can be read back by what made it (joshuafolkken/kit#3874).
2800
+ processes: z4.array(process_kind_schema).optional()
2786
2801
  });
2787
2802
  var dispatch_schema = z4.object({
2788
2803
  kind: z4.literal(KIND.DISPATCH),
@@ -4345,7 +4360,7 @@ var NAMED_CANDIDATE_COUNT = 3;
4345
4360
  var SEQUENCE_BEFORE_LIMIT = CONSECUTIVE_LIMIT - ONE_TURN;
4346
4361
  var RULE_POINTER = "`prompts/collaboration-workflow/turn-batching.md`";
4347
4362
  var STREAK = `${String(CONSECUTIVE_LIMIT)} single-call turns in a row`;
4348
- var REASON = `\u26D4 batching: ${STREAK}. Reissue this with the calls that do not need its result \u2014 the test is whether a call's input needs another call's result, not what kind of call it is (edits are covered exactly as reads), and it never authorizes weakening a verification gate or a review. Already batching, or nothing to pair? Reissue it unchanged; this fires once per streak. ${RULE_POINTER}`;
4363
+ var REASON = `\u26D4 batching: ${STREAK}. Reissue this with the calls that do not need its result \u2014 the test is whether a call's input needs another call's result, not what kind of call it is (edits are covered exactly as reads); it never authorizes weakening a verification gate or a review. Nothing to pair? Reissue it unchanged. ${RULE_POINTER}`;
4349
4364
  var NOTICE = `\u{1F4A1} batching: ${STREAK}; the Write proceeds. Issue the writes that do not need its result in one turn, never by weakening a gate or a review. ${RULE_POINTER}`;
4350
4365
  var LANE_NOTICE = `\u{1F4A1} batching: ${STREAK}; the call proceeds. Pair independent calls. ${RULE_POINTER}`;
4351
4366
  var WHOLE_FILE_WRITE_TOOL = "Write";
@@ -4485,8 +4500,9 @@ function fork_path(transcript_path, agent_id) {
4485
4500
  return path3.join(cost_transcript.unit_directory(directory, session_id), file_name);
4486
4501
  }
4487
4502
  function transcript_of(transcript_path, agent_id) {
4488
- if (!is_agent_id(agent_id)) return transcript_path;
4489
- if (!transcript_path.endsWith(TRANSCRIPT_EXTENSION)) return transcript_path;
4503
+ if (!is_agent_id(agent_id) || !transcript_path.endsWith(TRANSCRIPT_EXTENSION)) {
4504
+ return transcript_path;
4505
+ }
4490
4506
  return fork_path(transcript_path, agent_id);
4491
4507
  }
4492
4508
  var time_hook_transcript = {
@@ -51,8 +51,7 @@ import { execa as execa3 } from "execa";
51
51
 
52
52
  // scripts/git/git-execa-error.ts
53
53
  function get_exit_code(error) {
54
- if (typeof error !== "object" || error === null) return void 0;
55
- if (!("exitCode" in error)) return void 0;
54
+ if (typeof error !== "object" || error === null || !("exitCode" in error)) return void 0;
56
55
  const { exitCode: exit_code } = error;
57
56
  return typeof exit_code === "number" ? exit_code : void 0;
58
57
  }
@@ -207,16 +206,18 @@ var git_spawn = {
207
206
  var REFS_REMOTES_ORIGIN_PREFIX = "refs/remotes/origin/";
208
207
  var NAME_ONLY_FLAG = "--name-only";
209
208
  var DEFAULT_BRANCH_FALLBACK = "main";
209
+ var DEFAULT_BRANCH_ARGUMENTS = ["symbolic-ref", "refs/remotes/origin/HEAD"];
210
+ function default_branch_of(output) {
211
+ const trimmed = output?.trim() ?? "";
212
+ if (!trimmed.startsWith(REFS_REMOTES_ORIGIN_PREFIX)) return DEFAULT_BRANCH_FALLBACK;
213
+ return trimmed.slice(REFS_REMOTES_ORIGIN_PREFIX.length);
214
+ }
210
215
  async function get_default_branch() {
211
216
  try {
212
- const output = await git_spawn.read(["symbolic-ref", "refs/remotes/origin/HEAD"]);
213
- const trimmed = output.trim();
214
- if (trimmed.startsWith(REFS_REMOTES_ORIGIN_PREFIX)) {
215
- return trimmed.slice(REFS_REMOTES_ORIGIN_PREFIX.length);
216
- }
217
+ return default_branch_of(await git_spawn.read([...DEFAULT_BRANCH_ARGUMENTS]));
217
218
  } catch {
219
+ return DEFAULT_BRANCH_FALLBACK;
218
220
  }
219
- return DEFAULT_BRANCH_FALLBACK;
220
221
  }
221
222
  var MERGE_BASE_COMMAND = "merge-base";
222
223
  async function reference_exists(reference) {
@@ -293,8 +294,10 @@ async function untracked_names() {
293
294
  ]);
294
295
  }
295
296
  var git_diff_reads = {
297
+ DEFAULT_BRANCH_ARGUMENTS,
296
298
  change_base,
297
299
  change_base_commit,
300
+ default_branch_of,
298
301
  default_branch_reference,
299
302
  diff_cached_names,
300
303
  diff_main,
@@ -1185,8 +1188,7 @@ function build_input(values, now_ms) {
1185
1188
  const answer = to_answer(cli_flags.string_of(values.answer));
1186
1189
  if (answer === void 0) return void 0;
1187
1190
  const started_at_ms = to_time_ms(cli_flags.string_of(values.started));
1188
- if (started_at_ms === void 0) return void 0;
1189
- if (!are_values_readable(values)) return void 0;
1191
+ if (started_at_ms === void 0 || !are_values_readable(values)) return void 0;
1190
1192
  return input_of(values, { answer, now_ms, started_at_ms });
1191
1193
  }
1192
1194
  function print_json(input, decision) {
@@ -2031,8 +2033,9 @@ function is_same_conversation(carry, owner) {
2031
2033
  return owner.transcript !== void 0 && owner.transcript === carry.owner_transcript;
2032
2034
  }
2033
2035
  function reclaim_owner(carry, owner) {
2034
- if (carry.is_handed_off === true || !is_same_conversation(carry, owner)) return carry;
2035
- if (owner.pid === carry.owner_pid) return carry;
2036
+ if (carry.is_handed_off === true || !is_same_conversation(carry, owner) || owner.pid === carry.owner_pid) {
2037
+ return carry;
2038
+ }
2036
2039
  return { ...carry, owner_pid: owner.pid, owner_start: owner.start };
2037
2040
  }
2038
2041
  var run_carry_conversation = {
@@ -2346,9 +2349,11 @@ export {
2346
2349
  process_identity,
2347
2350
  process_owner_schema,
2348
2351
  PORCELAIN_FLAG,
2352
+ UNTRACKED_FILES_FLAG,
2349
2353
  git_utilities,
2350
2354
  has_timed_out,
2351
2355
  git_spawn,
2356
+ git_diff_reads,
2352
2357
  GIT_LOCATION_VARIABLES,
2353
2358
  git_location_environment,
2354
2359
  git_spawn_sync,
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-CDY4NFQG.js";
4
4
  import {
5
5
  lane_child_marker
6
- } from "./chunk-OLMO72ON.js";
6
+ } from "./chunk-K4EOONYM.js";
7
7
  import {
8
8
  ENV_FILE_NAME,
9
9
  GIT_LOCATION_VARIABLES,
@@ -23,7 +23,7 @@ import {
23
23
  process_identity,
24
24
  process_owner_schema,
25
25
  run_carry
26
- } from "./chunk-3C4XRYG6.js";
26
+ } from "./chunk-E7OIKX5Z.js";
27
27
  import {
28
28
  INSTALL_TIMEOUT_MS,
29
29
  PLATFORM_TEMP_ROOT,
@@ -299,6 +299,7 @@ var run_ship_next = { COMMAND, next_step, quoted, resume_of };
299
299
 
300
300
  // scripts/lane/lane-child-invocation.ts
301
301
  var CHILD_INVOCATION = "fullrun";
302
+ var REVIEW_INVOCATION = "the reviewer of lane";
302
303
  var RESUME_GUIDE = ".claude/skills/workflow-commands/pre-gate-cut.md";
303
304
  var SHIP_PROCESS = String.raw`(josh(\.[jt]s)? ship|run-ship-cli\.ts)`;
304
305
  function child_invocation(issue) {
@@ -307,7 +308,11 @@ function child_invocation(issue) {
307
308
  }
308
309
  function process_pattern(issue) {
309
310
  issue_number_shape.require_issue_number(issue);
310
- return `(${CHILD_INVOCATION}|${SHIP_PROCESS} .*) ${issue_cite.plain(issue)}$`;
311
+ return `(${CHILD_INVOCATION}|${REVIEW_INVOCATION}|${SHIP_PROCESS} .*) ${issue_cite.plain(issue)}$`;
312
+ }
313
+ function review_invocation(issue) {
314
+ issue_number_shape.require_issue_number(issue);
315
+ return `${REVIEW_INVOCATION} ${issue_cite.plain(issue)}`;
311
316
  }
312
317
  function resume_invocation(issue) {
313
318
  const preamble = `Resuming the lane child for issue ${issue_cite.plain(issue)} \u2014 do not re-read the workflow-commands entry documents (SKILL.md, fullrun.md). Run \`pnpm josh run:cut --resume ${issue}\` before anything else and follow the matching verdict in ${RESUME_GUIDE}: \`resume\` goes to the gate, \`resume-impl\` continues implementation. Only on \`fresh\` proceed as an ordinary`;
@@ -327,6 +332,7 @@ var lane_child_invocation = {
327
332
  outage_resume_invocation,
328
333
  process_pattern,
329
334
  resume_invocation,
335
+ review_invocation,
330
336
  ship_stop_invocation
331
337
  };
332
338
 
@@ -473,8 +479,7 @@ function parse_scp_like(url) {
473
479
  const user_end = url.indexOf(USER_SEPARATOR);
474
480
  const authority = user_end === NOT_FOUND ? url : url.slice(user_end + 1);
475
481
  const host_end = authority.indexOf(HOST_SEPARATOR);
476
- if (host_end === NOT_FOUND) return void 0;
477
- if (!is_github_ssh_host(authority.slice(0, host_end))) return void 0;
482
+ if (host_end === NOT_FOUND || !is_github_ssh_host(authority.slice(0, host_end))) return void 0;
478
483
  return to_identity(authority.slice(host_end + 1));
479
484
  }
480
485
  function parse_url_like(url) {
@@ -502,8 +507,7 @@ function origin_section_lines(lines) {
502
507
  }
503
508
  function url_value(line) {
504
509
  const separator = line.indexOf("=");
505
- if (separator === NOT_FOUND) return void 0;
506
- if (line.slice(0, separator).trim() !== URL_KEY) return void 0;
510
+ if (separator === NOT_FOUND || line.slice(0, separator).trim() !== URL_KEY) return void 0;
507
511
  return line.slice(separator + 1).trim();
508
512
  }
509
513
  function parse_origin_from_config(content) {
@@ -643,8 +647,9 @@ function resolve_current_owner(repository_path) {
643
647
  }
644
648
  function main_worktree(repository_path) {
645
649
  const git_directory = resolve_git_directory(repository_path);
646
- if (git_directory === void 0) return repository_path;
647
- if (path2.basename(git_directory) !== GIT_DIRECTORY) return repository_path;
650
+ if (git_directory === void 0 || path2.basename(git_directory) !== GIT_DIRECTORY) {
651
+ return repository_path;
652
+ }
648
653
  return path2.dirname(git_directory);
649
654
  }
650
655
  function discover_repositories(repository_path, environment3 = process.env) {
@@ -731,7 +736,7 @@ function repository(cwd) {
731
736
  function select_linked(found) {
732
737
  const own_directory = found[OWN_GIT_DIRECTORY];
733
738
  const common = found[COMMON_GIT_DIRECTORY];
734
- return own_directory !== void 0 && common !== void 0 && own_directory !== common ? common : void 0;
739
+ return own_directory === void 0 || common === void 0 || own_directory === common ? void 0 : common;
735
740
  }
736
741
  function resolve(cwd) {
737
742
  return select_linked(directories(cwd));
@@ -1253,8 +1258,9 @@ function parse_block(block, root) {
1253
1258
  const directory = line_value(lines, WORKTREE_PREFIX);
1254
1259
  const branch = line_value(lines, BRANCH_PREFIX);
1255
1260
  const issue = branch_issue(branch);
1256
- if (directory === void 0 || branch === void 0 || issue === void 0) return void 0;
1257
- if (!is_lane_directory(root, issue, directory)) return void 0;
1261
+ if (directory === void 0 || branch === void 0 || issue === void 0 || !is_lane_directory(root, issue, directory)) {
1262
+ return void 0;
1263
+ }
1258
1264
  return build_lane(issue, branch, directory, is_gone(directory));
1259
1265
  }
1260
1266
  function is_lane(lane) {
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  hook_decision
3
- } from "./chunk-GPLGZ6IC.js";
3
+ } from "./chunk-J47HU5H5.js";
4
4
  import {
5
5
  cost_blocks,
6
6
  time_batch_guard,
7
7
  time_bundle_call,
8
8
  time_shell,
9
9
  time_spans
10
- } from "./chunk-LIAFCXL7.js";
10
+ } from "./chunk-AS74OU3D.js";
11
11
  import {
12
12
  cost_transcript
13
- } from "./chunk-3C4XRYG6.js";
13
+ } from "./chunk-E7OIKX5Z.js";
14
14
 
15
15
  // scripts/delegation/investigation-reads.ts
16
16
  import path2 from "node:path";
@@ -176,7 +176,7 @@ var SEARCH_LABELS = new Set(
176
176
  SEARCH_COMMANDS.map((command) => time_shell.bash_label(command))
177
177
  );
178
178
  var INVESTIGATOR_AGENT = "investigator";
179
- var REASON = `\u26D4 investigation: ${String(delegation_policy.INVESTIGATION_FILE_THRESHOLD)} files read and not edited, or ${String(delegation_policy.INVESTIGATION_SEARCH_TURN_THRESHOLD)} search turns, since the last delegated unit, so the reading from here goes to a unit of its own (a successful write also starts the search count over). Ask \`pnpm josh delegate investigation\`, then dispatch the \`${INVESTIGATOR_AGENT}\` agent (\`kit:${INVESTIGATOR_AGENT}\` in a consumer) with a brief of what the main line has already concluded and what is left to find out; it returns the conclusion plus its \`file:line\` citations, never the file text. Keep a read in the main line only where this run will edit that file \u2014 an \`Edit\` cannot be issued against text you do not hold. This run's own instructions and the harness's own session files \u2014 a backgrounded call's output, a persisted tool result, this session's scratchpad \u2014 never count toward the files, so they are not what took the file count here; every read-only search turn counts, whatever it names. The rule is \`.claude/skills/workflow-commands/delegation.md\` \u2192 "The pre-implementation reading".`;
179
+ var REASON = `\u26D4 investigation: ${String(delegation_policy.INVESTIGATION_FILE_THRESHOLD)} files read and not edited, or ${String(delegation_policy.INVESTIGATION_SEARCH_TURN_THRESHOLD)} search turns, since the last delegated unit. Run \`pnpm josh delegate investigation\`, then dispatch the \`${INVESTIGATOR_AGENT}\` agent (\`kit:${INVESTIGATOR_AGENT}\` in a consumer); it returns \`file:line\` citations, never the file text. Keep main-line reads to files you will edit; every read-only search turn counts. \`.claude/skills/workflow-commands/delegation.md\``;
180
180
  var INSTRUCTION_PATHS = ["prompts", ".claude/skills"];
181
181
  var INSTRUCTION_FILES = /* @__PURE__ */ new Set(["CLAUDE.md", "AGENTS.md", "GEMINI.md"]);
182
182
  var REPOSITORY_ROOT = process.cwd();