@joshuafolkken/kit 1.1471.0 → 1.1514.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (267) hide show
  1. package/.claude/settings.json +6 -6
  2. package/.claude/skills/epic-commands/SKILL.md +2 -14
  3. package/.claude/skills/epic-commands/epic-bundle.md +9 -5
  4. package/.claude/skills/epic-commands/execution-waves.md +1 -2
  5. package/.claude/skills/verify-ui/SKILL.md +1 -2
  6. package/.claude/skills/workflow-commands/SKILL.md +7 -9
  7. package/.claude/skills/workflow-commands/background-commands.md +3 -7
  8. package/.claude/skills/workflow-commands/backlogrun-child.md +3 -10
  9. package/.claude/skills/workflow-commands/backlogrun-lanes.md +6 -15
  10. package/.claude/skills/workflow-commands/backlogrun-park.md +2 -8
  11. package/.claude/skills/workflow-commands/backlogrun-progress.md +10 -19
  12. package/.claude/skills/workflow-commands/backlogrun-recovery.md +8 -8
  13. package/.claude/skills/workflow-commands/backlogrun-steps.md +2 -10
  14. package/.claude/skills/workflow-commands/backlogrun.md +31 -50
  15. package/.claude/skills/workflow-commands/chain-rule.md +7 -6
  16. package/.claude/skills/workflow-commands/delegation.md +12 -8
  17. package/.claude/skills/workflow-commands/entry-sequence.md +1 -3
  18. package/.claude/skills/workflow-commands/followup.md +3 -6
  19. package/.claude/skills/workflow-commands/fullrun-steps.md +3 -5
  20. package/.claude/skills/workflow-commands/fullrun.md +4 -6
  21. package/.claude/skills/workflow-commands/halfrun.md +3 -7
  22. package/.claude/skills/workflow-commands/into-target.md +1 -2
  23. package/.claude/skills/workflow-commands/issue-comments.md +3 -3
  24. package/.claude/skills/workflow-commands/issue-scout.md +3 -2
  25. package/.claude/skills/workflow-commands/latest-gate.md +2 -6
  26. package/.claude/skills/workflow-commands/needs-human-review.md +2 -5
  27. package/.claude/skills/workflow-commands/observation-filing.md +0 -14
  28. package/.claude/skills/workflow-commands/observation-ledger.md +4 -9
  29. package/.claude/skills/workflow-commands/pre-gate-cut.md +11 -16
  30. package/.claude/skills/workflow-commands/prerequisite.md +1 -2
  31. package/.claude/skills/workflow-commands/progress-watcher.md +2 -7
  32. package/.claude/skills/workflow-commands/prrun.md +3 -5
  33. package/.claude/skills/workflow-commands/retrospective.md +4 -4
  34. package/.claude/skills/workflow-commands/split-assessment.md +1 -3
  35. package/.claude/skills/workflow-commands/target-repository.md +1 -2
  36. package/.claude/skills/workflow-commands/working-tree-hold.md +2 -4
  37. package/.codex/hooks.json +6 -6
  38. package/.github/actions/setup-node/action.yml +1 -1
  39. package/.github/workflows/ci.yml +1 -1
  40. package/.github/workflows/publish.yml +2 -2
  41. package/CLAUDE.md +1 -1
  42. package/cspell/index.yaml +7 -0
  43. package/dist/CLAUDE.md +1 -1
  44. package/dist/commands/document-section-cli.js +67 -34
  45. package/dist/hooks/batch-guard.js +6 -6
  46. package/dist/hooks/chunk-4KKD2UTK.js +66 -0
  47. package/dist/hooks/{chunk-J47HU5H5.js → chunk-6TS2JD6D.js} +3 -3
  48. package/dist/hooks/chunk-7DSBJVFH.js +50 -0
  49. package/dist/hooks/{chunk-YHBZAJSV.js → chunk-A65Y4YOR.js} +3 -3
  50. package/dist/hooks/{chunk-E7OIKX5Z.js → chunk-APUO6U4J.js} +85 -7
  51. package/dist/hooks/{chunk-IX6TTTI6.js → chunk-EFXE6C37.js} +8 -22
  52. package/dist/hooks/chunk-GP4IEC4O.js +20 -0
  53. package/dist/hooks/{chunk-SHGPANFB.js → chunk-JP45SOCJ.js} +3 -3
  54. package/dist/hooks/{chunk-K4EOONYM.js → chunk-LAOV7NLM.js} +1 -1
  55. package/dist/hooks/chunk-M4HGZV7U.js +83 -0
  56. package/dist/hooks/{chunk-KC5AK2GF.js → chunk-O6GDRNJB.js} +3 -3
  57. package/dist/hooks/{chunk-YYPI7SJZ.js → chunk-PF2NZL2A.js} +5 -5
  58. package/dist/hooks/{chunk-H5HVWYXK.js → chunk-PTICX4OL.js} +3 -4
  59. package/dist/hooks/{chunk-IIGFYXKC.js → chunk-RT27QRJW.js} +581 -1438
  60. package/dist/hooks/{chunk-43ZHT22P.js → chunk-SYOTDYCI.js} +1127 -1089
  61. package/dist/hooks/{chunk-AS74OU3D.js → chunk-TNUMY6NL.js} +1507 -1336
  62. package/dist/hooks/chunk-UPUZF3AN.js +279 -0
  63. package/dist/hooks/{chunk-EUMACUK2.js → chunk-WK6SMBIC.js} +1948 -806
  64. package/dist/hooks/codex-hook-adapter.js +17 -14
  65. package/dist/hooks/duplicate-read-guard.js +7 -7
  66. package/dist/hooks/format-edited.js +5 -4
  67. package/dist/hooks/inputs.json +317 -264
  68. package/dist/hooks/investigation-guard.js +8 -11
  69. package/dist/hooks/pretool-guard.js +16 -13
  70. package/dist/hooks/session-lang.js +370 -25
  71. package/dist/hooks/stop-guard.js +2576 -176
  72. package/dist/josh.js +2124 -277
  73. package/lefthook/base.yml +5 -3
  74. package/package.json +12 -10
  75. package/prompts/collaboration-workflow/file-edits.md +1 -3
  76. package/prompts/collaboration-workflow/gh-rest.md +1 -2
  77. package/prompts/collaboration-workflow/issue-citation.md +2 -4
  78. package/prompts/collaboration-workflow/issue-template.md +10 -2
  79. package/prompts/collaboration-workflow/lane-instructions.md +35 -0
  80. package/prompts/collaboration-workflow/operating-rules.md +2 -6
  81. package/prompts/collaboration-workflow/output-bounds.md +3 -3
  82. package/prompts/collaboration-workflow/overview.md +1 -1
  83. package/prompts/collaboration-workflow/principles.md +14 -8
  84. package/prompts/collaboration-workflow/report-format.md +9 -0
  85. package/prompts/collaboration-workflow/residency.md +12 -8
  86. package/prompts/collaboration-workflow/rule-delivery.md +3 -11
  87. package/prompts/collaboration-workflow/shell-body.md +6 -6
  88. package/prompts/collaboration-workflow/turn-batching.md +5 -5
  89. package/prompts/collaboration-workflow/upstream-interrupt.md +2 -2
  90. package/prompts/collaboration-workflow/wip-cap.md +6 -6
  91. package/prompts/collaboration-workflow.md +1 -0
  92. package/prompts/review.md +4 -5
  93. package/prompts/testing-guide.md +2 -2
  94. package/scripts/agent/agent-argv.ts +20 -4
  95. package/scripts/agent/agent-role-profile.ts +101 -45
  96. package/scripts/agent/agent-safe-text.ts +60 -0
  97. package/scripts/agent/claude-agent-argv.ts +14 -0
  98. package/scripts/agent/codex-agent-argv.ts +2 -0
  99. package/scripts/agent/lane-instructions.ts +144 -0
  100. package/scripts/backlog/backlog-budget.ts +4 -4
  101. package/scripts/backlog/backlog-drive-named.ts +1 -1
  102. package/scripts/backlog/backlog-drive-restore.ts +9 -1
  103. package/scripts/backlog/backlog-occupied.ts +56 -0
  104. package/scripts/backlog/backlog-ready.ts +47 -10
  105. package/scripts/delegation/duplicate-read-guard.ts +2 -2
  106. package/scripts/delegation/investigation-guard.ts +15 -65
  107. package/scripts/delegation/investigation-reads.ts +0 -1
  108. package/scripts/document/document-byte-budget.ts +6 -5
  109. package/scripts/document/document-section-cli.ts +17 -5
  110. package/scripts/document/entry-read-budget.ts +2 -2
  111. package/scripts/document/read-set-cli.ts +4 -1
  112. package/scripts/epic/epic-audit-orphans.ts +5 -8
  113. package/scripts/epic/epic-audit.ts +52 -1
  114. package/scripts/epic/epic-bundle-evidence.ts +49 -26
  115. package/scripts/epic/epic-bundle-referenced.ts +14 -3
  116. package/scripts/epic/epic-bundle.ts +17 -9
  117. package/scripts/followup/git-followup-workflow.ts +19 -1
  118. package/scripts/gate/check-inputs.ts +129 -0
  119. package/scripts/gate/check-reuse.ts +162 -0
  120. package/scripts/gate/core-budget.ts +93 -44
  121. package/scripts/gate/core-wait.ts +130 -0
  122. package/scripts/gate/free-cores.ts +49 -0
  123. package/scripts/gate/gate-ledger.ts +17 -3
  124. package/scripts/gate/gate-plan.ts +23 -1
  125. package/scripts/gate/gate-report.ts +15 -2
  126. package/scripts/gate/gate-run-steps.ts +150 -0
  127. package/scripts/gate/held-mark.ts +55 -0
  128. package/scripts/gate/machine-capacity.ts +70 -11
  129. package/scripts/gate/pre-commit-type-check.ts +14 -1
  130. package/scripts/gate/verification-gate.ts +58 -125
  131. package/scripts/gh/git-gh-issue-rest.ts +1 -0
  132. package/scripts/gh/git-gh-issue-write.ts +24 -2
  133. package/scripts/gh/git-pr.ts +13 -1
  134. package/scripts/git/main-merge-regenerate.ts +78 -0
  135. package/scripts/git/main-merge.ts +14 -5
  136. package/scripts/hooks/batch-guard.ts +5 -8
  137. package/scripts/hooks/pre-commit-lint.ts +91 -0
  138. package/scripts/hooks/pre-push-unit.ts +1 -1
  139. package/scripts/hooks/pretool-guard.ts +27 -52
  140. package/scripts/hooks/reserved-run.ts +1 -0
  141. package/scripts/hooks/run-hook.sh +10 -12
  142. package/scripts/hooks/stop-actions.ts +204 -0
  143. package/scripts/hooks/stop-guard.ts +62 -21
  144. package/scripts/init/hook-launch.ts +12 -7
  145. package/scripts/issue/expected-effect-lint.ts +59 -0
  146. package/scripts/issue/issue-cite-cli.ts +35 -15
  147. package/scripts/issue/issue-classification.ts +1 -1
  148. package/scripts/issue/issue-lint-cli.ts +5 -3
  149. package/scripts/issue/issue-scout-cli.ts +19 -14
  150. package/scripts/issue/markdown-section.ts +19 -5
  151. package/scripts/josh/command-usage.ts +110 -0
  152. package/scripts/josh/josh-command-map.ts +2 -0
  153. package/scripts/josh/josh-command-types.ts +55 -9
  154. package/scripts/josh/josh-commands-ai.ts +13 -0
  155. package/scripts/josh/josh-commands-development.ts +1 -1
  156. package/scripts/josh/josh-commands-hooks.ts +6 -0
  157. package/scripts/josh/josh-commands-lane.ts +10 -1
  158. package/scripts/josh/josh-commands-workflow.ts +5 -0
  159. package/scripts/josh/josh-logic.ts +6 -15
  160. package/scripts/josh/josh-usage-automation.ts +121 -0
  161. package/scripts/josh/josh-usage-backlog.ts +180 -0
  162. package/scripts/josh/josh-usage-developer.ts +230 -0
  163. package/scripts/josh/josh-usage-hooks.ts +38 -0
  164. package/scripts/josh/josh-usage-issue.ts +205 -0
  165. package/scripts/josh/josh-usage-review.ts +101 -0
  166. package/scripts/josh/josh-usage-run.ts +252 -0
  167. package/scripts/josh/josh-usage-session.ts +238 -0
  168. package/scripts/josh/josh-usage-workflow.ts +212 -0
  169. package/scripts/josh/josh.ts +14 -5
  170. package/scripts/josh/package-directory.ts +20 -0
  171. package/scripts/lane/lane-capacity.ts +8 -2
  172. package/scripts/lane/lane-check-stats.ts +56 -0
  173. package/scripts/lane/lane-child-invocation.ts +35 -4
  174. package/scripts/lane/lane-dispatch.ts +3 -3
  175. package/scripts/lane/lane-guard-policy.ts +2 -2
  176. package/scripts/lane/lane-handoff.ts +8 -1
  177. package/scripts/lane/lane-install.ts +12 -4
  178. package/scripts/lane/lane-ledger.ts +43 -1
  179. package/scripts/lane/lane-limit-cli.ts +8 -9
  180. package/scripts/lane/lane-measure-cli.ts +2 -0
  181. package/scripts/lane/lane-preserve.ts +29 -1
  182. package/scripts/lane/lane-registry.ts +9 -7
  183. package/scripts/lane/lane-restart.ts +5 -26
  184. package/scripts/lane/lane-session-action.ts +146 -0
  185. package/scripts/lane/lane-session-broker.ts +57 -138
  186. package/scripts/lane/lane-withdraw-cli.ts +71 -0
  187. package/scripts/lane/lane-withdraw.ts +182 -0
  188. package/scripts/lint/format.ts +4 -4
  189. package/scripts/lint/lint-parallel.ts +10 -3
  190. package/scripts/lint/lint-related-scope.ts +4 -1
  191. package/scripts/notify/telegram-test.ts +10 -5
  192. package/scripts/report/report-format-reference.ts +2 -0
  193. package/scripts/review/acceptance-map-check.ts +61 -0
  194. package/scripts/review/acceptance-map.ts +205 -0
  195. package/scripts/review/review-brief-cli.ts +1 -1
  196. package/scripts/rules/agent-model.ts +59 -0
  197. package/scripts/rules/delivered-rules.ts +11 -2
  198. package/scripts/rules/filing-cap.ts +1 -0
  199. package/scripts/rules/firing-point.ts +6 -5
  200. package/scripts/rules/guard-remedy.ts +117 -0
  201. package/scripts/rules/issue-comments.ts +67 -6
  202. package/scripts/rules/last-prompt.ts +50 -5
  203. package/scripts/rules/oracle-list-cli.ts +7 -0
  204. package/scripts/rules/piped-verification.ts +3 -1
  205. package/scripts/rules/rule-list.ts +4 -1
  206. package/scripts/rules/rule-registry-rows.ts +10 -0
  207. package/scripts/rules/rule-registry.ts +7 -4
  208. package/scripts/rules/rule-rewrite.ts +114 -0
  209. package/scripts/rules/rule-value.ts +7 -1
  210. package/scripts/rules/shell-segments.ts +15 -0
  211. package/scripts/rules/stop-decision.ts +77 -0
  212. package/scripts/rules/stop-rules.ts +147 -47
  213. package/scripts/rules/tail-commands.ts +15 -1
  214. package/scripts/run/board/run-board-cli.ts +2 -0
  215. package/scripts/run/board/run-board-closed.ts +8 -2
  216. package/scripts/run/board/run-board-github.ts +9 -1
  217. package/scripts/run/board/run-board-header.ts +4 -1
  218. package/scripts/run/board/run-board-labels.ts +2 -0
  219. package/scripts/run/board/run-board-layout.ts +1 -1
  220. package/scripts/run/board/run-board-read.ts +16 -0
  221. package/scripts/run/board/run-board-reason.ts +10 -1
  222. package/scripts/run/board/run-board-render-legend.ts +1 -0
  223. package/scripts/run/board/run-board-render-slot.ts +1 -1
  224. package/scripts/run/board/run-board-render-waits.ts +41 -0
  225. package/scripts/run/board/run-board-render.ts +6 -1
  226. package/scripts/run/board/run-board-row-yield.ts +1 -0
  227. package/scripts/run/board/run-board-state.ts +5 -0
  228. package/scripts/run/board/run-board-status.ts +72 -21
  229. package/scripts/run/board/run-board-tick.ts +5 -1
  230. package/scripts/run/cut/run-cut-cli.ts +3 -2
  231. package/scripts/run/cut/run-cut-report.ts +16 -0
  232. package/scripts/run/detached-launch.ts +23 -4
  233. package/scripts/run/entry/run-entry-cli.ts +8 -1
  234. package/scripts/run/event/run-event-render.ts +1 -0
  235. package/scripts/run/event/run-event-scope.ts +19 -1
  236. package/scripts/run/event/run-event-stream-emit.ts +13 -6
  237. package/scripts/run/event/run-event-stream.ts +4 -0
  238. package/scripts/run/hold/run-hold-session.ts +46 -0
  239. package/scripts/run/hold/run-hold.ts +7 -1
  240. package/scripts/run/launch-priority.ts +32 -0
  241. package/scripts/run/merge/run-merge-cli.ts +16 -65
  242. package/scripts/run/merge/run-merge-signals.ts +99 -0
  243. package/scripts/run/merge/run-merge-steps.ts +11 -1
  244. package/scripts/run/merge/run-merge.ts +21 -9
  245. package/scripts/run/run-liveness.ts +1 -1
  246. package/scripts/run/run-poll-hook.ts +157 -0
  247. package/scripts/run/run-step-cli.ts +22 -15
  248. package/scripts/run/run-step-section.ts +85 -0
  249. package/scripts/run/ship/run-ship-cli.ts +5 -12
  250. package/scripts/run/ship/run-ship-detach.ts +9 -0
  251. package/scripts/run/ship/run-ship-next.ts +10 -2
  252. package/scripts/run/ship/run-ship-overlap.ts +195 -0
  253. package/scripts/run/ship/run-ship-pre-detach.ts +33 -15
  254. package/scripts/run/ship/run-ship-preflight.ts +28 -2
  255. package/scripts/run/ship/run-ship-return.ts +31 -7
  256. package/scripts/run/ship/run-ship-review-steps.ts +12 -10
  257. package/scripts/run/ship/run-ship-steps.ts +1 -1
  258. package/scripts/run/ship/run-ship-stop-context.ts +206 -0
  259. package/scripts/run/ship/run-ship-sync.ts +14 -6
  260. package/scripts/test/test-e2e-guard.ts +30 -5
  261. package/scripts/test/test-unit-guard.ts +16 -1
  262. package/scripts/test/unit-worker-share.ts +26 -4
  263. package/scripts/time-runtime/time-shell.ts +29 -4
  264. package/scripts/time-runtime/time-spans.ts +1 -0
  265. package/scripts/time-runtime/time-tool-call.ts +7 -0
  266. package/templates/gitignore +6 -2
  267. package/dist/hooks/chunk-K4LMBQC2.js +0 -68
@@ -1,22 +1,43 @@
1
1
  import {
2
- agent_role_profile,
2
+ FULL_PAGE_QUERY,
3
+ MERGED_STATE,
3
4
  detached_launch,
5
+ forget_pr_numbers,
6
+ gh_failure,
4
7
  git_common_directory,
8
+ git_gh_api_path,
9
+ git_gh_exec,
10
+ git_gh_helpers,
11
+ git_gh_pr_read,
12
+ git_gh_pr_rest,
5
13
  issue_cite,
6
14
  lane_child_invocation,
15
+ parse_json_array_or_undefined,
16
+ parse_json_object_or_undefined,
17
+ read_json_listing,
18
+ read_pull,
7
19
  repo_discovery,
8
20
  repo_origin,
21
+ require_pr_number,
9
22
  run_event_stream,
10
- run_event_stream_emit
11
- } from "./chunk-EUMACUK2.js";
23
+ run_event_stream_emit,
24
+ run_hold,
25
+ session_cite,
26
+ stamp_record,
27
+ to_gh_state
28
+ } from "./chunk-WK6SMBIC.js";
12
29
  import {
13
30
  error_text
14
31
  } from "./chunk-CDY4NFQG.js";
32
+ import {
33
+ agent_role_profile,
34
+ agent_session_role
35
+ } from "./chunk-UPUZF3AN.js";
15
36
  import {
16
37
  CHECK_STATUS_FAIL,
17
38
  CHECK_STATUS_PENDING,
18
39
  PrConflictError,
19
- blocking_issue_schema,
40
+ cost_attribute,
20
41
  cost_blocks,
21
42
  describe_pr_failure,
22
43
  evaluate_pr_state,
@@ -26,25 +47,28 @@ import {
26
47
  is_review_decision_decisive,
27
48
  parse_pr_state_snapshot,
28
49
  read_string,
29
- rest_comment_schema,
30
50
  time_density_hook,
31
51
  time_shell,
32
52
  time_transcript_line
33
- } from "./chunk-AS74OU3D.js";
53
+ } from "./chunk-TNUMY6NL.js";
34
54
  import {
35
55
  lane_child_marker
36
- } from "./chunk-K4EOONYM.js";
56
+ } from "./chunk-LAOV7NLM.js";
37
57
  import {
38
- agent_session_environment,
39
58
  backlog_budget,
59
+ blocking_issue_schema,
60
+ cli_flags,
61
+ cost_transcript,
40
62
  cost_usage,
41
63
  git_command,
42
- has_timed_out,
64
+ issue_number_shape,
43
65
  json_value,
66
+ lane_paths,
67
+ own_session,
44
68
  process_identity
45
- } from "./chunk-E7OIKX5Z.js";
69
+ } from "./chunk-APUO6U4J.js";
46
70
  import {
47
- COMMAND_TIMEOUT_MS,
71
+ PLATFORM_TEMP_ROOT,
48
72
  PROJECT_ROOT,
49
73
  stamp_file
50
74
  } from "./chunk-DGT54IH5.js";
@@ -84,6 +108,27 @@ async function bounded_map(items, limit, worker) {
84
108
  }
85
109
  var bounded_pool = { bounded_map, pool_width };
86
110
 
111
+ // scripts/rules/tail-commands.ts
112
+ function is_bash_use(block) {
113
+ return block.type === cost_blocks.TOOL_USE_TYPE && block.name === cost_blocks.BASH_TOOL;
114
+ }
115
+ function bash_commands_of(line) {
116
+ const parsed = time_transcript_line.parse_line(line);
117
+ if (parsed === void 0) return [];
118
+ return parsed.blocks.filter((block) => is_bash_use(block)).map((block) => time_shell.bash_command(block.input));
119
+ }
120
+ function prior_bash_commands(tail) {
121
+ return tail.split("\n").flatMap((line) => bash_commands_of(line));
122
+ }
123
+ function answered(text, is_call, token) {
124
+ const blocks = time_transcript_line.parse_text(text).flatMap((line) => line.blocks);
125
+ const call_ids = new Set(
126
+ blocks.filter((block) => is_call(time_shell.bash_command(block.input))).map((block) => block.id)
127
+ );
128
+ return blocks.some((block) => call_ids.has(block.result_id) && block.token_lines.includes(token));
129
+ }
130
+ var tail_commands = { answered, is_bash_use, prior_bash_commands };
131
+
87
132
  // scripts/rules/shell-segments.ts
88
133
  var SEGMENT_SEPARATOR = /&&|\|\||;|\n/u;
89
134
  var SEGMENT_PARTS = new RegExp(`(${SEGMENT_SEPARATOR.source})`, "u");
@@ -93,12 +138,19 @@ function segments_of(command) {
93
138
  function parts_of(command) {
94
139
  return command.split(SEGMENT_PARTS);
95
140
  }
141
+ function first_of(command) {
142
+ const plain = time_shell.blanked(command);
143
+ if (plain === void 0) return void 0;
144
+ const cut = plain.search(SEGMENT_SEPARATOR);
145
+ return (cut === -1 ? command : command.slice(0, cut)).trim();
146
+ }
96
147
  function is_josh_command(segment, names) {
97
148
  const named = time_shell.josh_command_of(segment);
98
149
  if (!named.startsWith(time_shell.JOSH_PREFIX)) return false;
99
150
  return names.has(named.slice(time_shell.JOSH_PREFIX.length));
100
151
  }
101
152
  var shell_segments = {
153
+ first_of,
102
154
  is_josh_command,
103
155
  parts_of,
104
156
  segments_of
@@ -124,20 +176,6 @@ function is_issue_filing(command) {
124
176
  }
125
177
  var bash_triggers = { is_direct_filing, is_issue_filing, on_bash_command };
126
178
 
127
- // scripts/rules/tail-commands.ts
128
- function is_bash_use(block) {
129
- return block.type === cost_blocks.TOOL_USE_TYPE && block.name === cost_blocks.BASH_TOOL;
130
- }
131
- function bash_commands_of(line) {
132
- const parsed = time_transcript_line.parse_line(line);
133
- if (parsed === void 0) return [];
134
- return parsed.blocks.filter((block) => is_bash_use(block)).map((block) => time_shell.bash_command(block.input));
135
- }
136
- function prior_bash_commands(tail) {
137
- return tail.split("\n").flatMap((line) => bash_commands_of(line));
138
- }
139
- var tail_commands = { is_bash_use, prior_bash_commands };
140
-
141
179
  // scripts/rules/filing-cap.ts
142
180
  var FILING_CAP = 10;
143
181
  var CAP_REACHED = FILING_CAP;
@@ -176,8 +214,8 @@ function current_turn(tail) {
176
214
  function turn_filing_count(tail) {
177
215
  return prior_filing_count(current_turn(tail));
178
216
  }
179
- function decide(_call, run) {
180
- return prior_filing_count(time_density_hook.read_tail(run.transcript)) >= CAP_REACHED;
217
+ function decide(_call, run2) {
218
+ return prior_filing_count(time_density_hook.read_tail(run2.transcript)) >= CAP_REACHED;
181
219
  }
182
220
  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\`).`;
183
221
  var ROW = {
@@ -190,340 +228,12 @@ var filing_cap = {
190
228
  FILING_CAP,
191
229
  FILING_CAP_REASON,
192
230
  ROW,
231
+ current_turn,
193
232
  is_prompt_line,
194
233
  prior_filing_count,
195
234
  turn_filing_count
196
235
  };
197
236
 
198
- // scripts/rules/issue-citation.ts
199
- var ISSUE_NUMBER = /#\d+/gu;
200
- var REFERENCE_BOUNDARY = /[\s#()[\]<>|]/u;
201
- var OWNER_REPO = /^[^\s/#]+\/[^\s/#]+$/u;
202
- var MARKDOWN_LINK = /\[[^[\]]*\]\([^()]*\)/gu;
203
- var NUMBER_CONTINUATION = /^(?:\w|-[a-z])/iu;
204
- var CONTINUATION_WIDTH = 2;
205
- var GLUED_LEAD = /[&./]/u;
206
- var FENCE_MARKER = /^\s*(?:`{3,}|~{3,})/u;
207
- var QUOTE_LINE = /^\s*>/u;
208
- var PR_PREFIX = /\b(?:pr|pull request)\s*$/iu;
209
- var BACKTICK_PAIR = 2;
210
- function link_covers(link, index) {
211
- const start = link.index ?? 0;
212
- return index >= start && index < start + link[0].length;
213
- }
214
- function is_linked_at(line, index) {
215
- for (const link of line.matchAll(MARKDOWN_LINK)) {
216
- if (link_covers(link, index)) return true;
217
- }
218
- return false;
219
- }
220
- function lead_token(message, hash_index) {
221
- let start = hash_index;
222
- while (start > 0 && !REFERENCE_BOUNDARY.test(message.charAt(start - 1))) start -= 1;
223
- return message.slice(start, hash_index);
224
- }
225
- function repo_prefix(message, hash_index) {
226
- const token = lead_token(message, hash_index);
227
- return OWNER_REPO.test(token) ? token : "";
228
- }
229
- function is_inline_code_at(line, index) {
230
- const backticks = line.slice(0, index).split("`").length - 1;
231
- return backticks % BACKTICK_PAIR === 1;
232
- }
233
- function is_bare_at(line, index) {
234
- if (is_linked_at(line, index) || is_inline_code_at(line, index)) return false;
235
- return !PR_PREFIX.test(line.slice(0, index));
236
- }
237
- function is_glued(line, reference) {
238
- const end = reference.index + reference.text.length;
239
- if (NUMBER_CONTINUATION.test(line.slice(end, end + CONTINUATION_WIDTH))) return true;
240
- return reference.prefix === "" && GLUED_LEAD.test(lead_token(line, reference.index));
241
- }
242
- function line_references(line) {
243
- const references = [];
244
- for (const match of line.matchAll(ISSUE_NUMBER)) {
245
- const reference = { index: match.index, prefix: repo_prefix(line, match.index), text: match[0] };
246
- if (!is_glued(line, reference) && is_bare_at(line, match.index)) references.push(reference);
247
- }
248
- return references;
249
- }
250
- function collect_line_references(line, found) {
251
- for (const reference of line_references(line)) found.push(`${reference.prefix}${reference.text}`);
252
- }
253
- function lines_outside_fences(message) {
254
- const lines = [];
255
- let is_in_fence = false;
256
- for (const line of message.split("\n")) {
257
- if (FENCE_MARKER.test(line)) is_in_fence = !is_in_fence;
258
- else if (!is_in_fence) lines.push(line);
259
- }
260
- return lines;
261
- }
262
- function prose_lines(message) {
263
- return lines_outside_fences(message).filter((line) => !QUOTE_LINE.test(line));
264
- }
265
- function bare_references(message) {
266
- const found = [];
267
- for (const line of prose_lines(message)) collect_line_references(line, found);
268
- return [...new Set(found)];
269
- }
270
- function prompt_references(prompt) {
271
- const found = /* @__PURE__ */ new Set();
272
- for (const match of prompt.matchAll(ISSUE_NUMBER)) {
273
- found.add(repo_prefix(prompt, match.index) + match[0]);
274
- }
275
- return found;
276
- }
277
- function unquoted_references(message, prompt) {
278
- const quoted = prompt_references(prompt);
279
- return bare_references(message).filter((reference) => !quoted.has(reference));
280
- }
281
- function has_bare_reference(message) {
282
- return bare_references(message).length > 0;
283
- }
284
- function cite_argument(reference) {
285
- return reference.startsWith("#") ? reference.slice(1) : reference;
286
- }
287
- function cite_arguments(references) {
288
- return references.map((reference) => cite_argument(reference));
289
- }
290
- function reference_link(reference, default_slug) {
291
- const slug = reference.prefix === "" ? default_slug : reference.prefix;
292
- const number = reference.text.slice(1);
293
- return `[${reference.prefix}${reference.text}](${issue_cite.issue_url(slug, number)})`;
294
- }
295
- function linkify_line(line, slug) {
296
- let result = "";
297
- let cursor = 0;
298
- for (const reference of line_references(line)) {
299
- const start = reference.index - reference.prefix.length;
300
- result += line.slice(cursor, start) + reference_link(reference, slug);
301
- cursor = reference.index + reference.text.length;
302
- }
303
- return result + line.slice(cursor);
304
- }
305
- function rewrite_line(line, slug, is_in_fence) {
306
- if (is_in_fence || FENCE_MARKER.test(line) || QUOTE_LINE.test(line)) return line;
307
- return linkify_line(line, slug);
308
- }
309
- function linkify(message, slug) {
310
- const out = [];
311
- let is_in_fence = false;
312
- for (const line of message.split("\n")) {
313
- if (FENCE_MARKER.test(line)) is_in_fence = !is_in_fence;
314
- out.push(rewrite_line(line, slug, is_in_fence));
315
- }
316
- return out.join("\n");
317
- }
318
- var issue_citation = {
319
- bare_references,
320
- cite_arguments,
321
- has_bare_reference,
322
- linkify,
323
- prose_lines,
324
- unquoted_references
325
- };
326
-
327
- // scripts/issue/session-cite.ts
328
- function session_repo() {
329
- const url = repo_discovery.read_origin_url(process.cwd());
330
- const identity = url === void 0 ? void 0 : repo_origin.parse_origin_url(url);
331
- return identity === void 0 ? void 0 : `${identity.owner}/${identity.repo}`;
332
- }
333
- function issue(number, title, repo = session_repo()) {
334
- return issue_cite.reference(repo, String(number), title);
335
- }
336
- function text(message) {
337
- const repo = session_repo();
338
- return repo === void 0 ? message : issue_citation.linkify(message, repo);
339
- }
340
- var session_cite = {
341
- issue,
342
- session_repo,
343
- text
344
- };
345
-
346
- // scripts/josh/stamp-record.ts
347
- var NONE_READ = { kind: "none" };
348
- var UNREADABLE_READ = { kind: "unreadable" };
349
- function is_older_than(iso, max_age_ms, now) {
350
- const at = Date.parse(iso);
351
- if (Number.isNaN(at)) return true;
352
- return now.getTime() - at > max_age_ms;
353
- }
354
- function classify(raw, spec, now) {
355
- if (raw === void 0) return NONE_READ;
356
- const record = spec.parse(raw);
357
- if (record === void 0) return UNREADABLE_READ;
358
- const is_expired3 = is_older_than(spec.timestamp_of(record), spec.max_age_ms, now);
359
- return { kind: is_expired3 ? "expired" : "carried", record };
360
- }
361
- var stamp_record = { classify, is_older_than };
362
-
363
- // scripts/run/hold/run-hold.ts
364
- import { z } from "zod";
365
- var HOLD_PREFIX = "josh-run-hold-";
366
- var UNNUMBERED_ISSUE = "new";
367
- var HOLD_MAX_AGE_HOURS = 8;
368
- var MILLISECONDS_PER_HOUR = 36e5;
369
- var HOLD_MAX_AGE_MS = HOLD_MAX_AGE_HOURS * MILLISECONDS_PER_HOUR;
370
- var RELEASE_COMMAND = "pnpm josh run:release";
371
- var FORCE_RELEASE_COMMAND = `${RELEASE_COMMAND} --force`;
372
- var NOT_IDLE = 'that is not "nothing is running here"';
373
- var FREE_READ = { kind: "free" };
374
- var UNREADABLE_READ2 = { kind: "unreadable" };
375
- function hold_path(git_directory) {
376
- return stamp_file.stamp_path(HOLD_PREFIX, git_directory);
377
- }
378
- async function worktree_directory() {
379
- const directories = await git_command.git_directories();
380
- return directories[0];
381
- }
382
- async function is_linked_worktree() {
383
- const directories = await git_command.git_directories();
384
- return directories[0] !== void 0 && directories[0] !== directories[1];
385
- }
386
- var run_hold_schema = z.object({
387
- issue: z.string(),
388
- taken_at: z.string(),
389
- pid: z.number(),
390
- is_fullrun: z.boolean().optional(),
391
- is_halfrun_stop: z.boolean().optional(),
392
- prrun_stop_head: z.string().optional(),
393
- owner_pid: z.number().optional(),
394
- owner_start: z.string().optional()
395
- });
396
- function parse_hold(raw) {
397
- return json_value.parse_with(raw, run_hold_schema);
398
- }
399
- function is_expired(hold, now) {
400
- return stamp_record.is_older_than(hold.taken_at, HOLD_MAX_AGE_MS, now);
401
- }
402
- function is_stop_marked(hold) {
403
- return hold.is_halfrun_stop === true || hold.prrun_stop_head !== void 0;
404
- }
405
- function is_owner_gone(hold) {
406
- if (is_stop_marked(hold) || hold.owner_pid === void 0) return false;
407
- return process_identity.is_same_process(hold.owner_pid, hold.owner_start) === false;
408
- }
409
- function is_stale(hold, now) {
410
- return is_expired(hold, now) || is_owner_gone(hold);
411
- }
412
- function classify2(raw, now) {
413
- if (raw === void 0) return FREE_READ;
414
- const hold = parse_hold(raw);
415
- if (hold === void 0) return UNREADABLE_READ2;
416
- return { kind: is_stale(hold, now) ? "stale" : "held", hold };
417
- }
418
- function read_hold(target, now = /* @__PURE__ */ new Date()) {
419
- return classify2(stamp_file.read_stamp_text(target), now);
420
- }
421
- function session_owner(environment = process.env) {
422
- const pid = Number(environment[agent_session_environment.AGENT_PID_KEY]);
423
- if (!Number.isSafeInteger(pid) || pid <= 0) return {};
424
- return { owner_pid: pid, owner_start: process_identity.read_start(pid) };
425
- }
426
- function build_hold(issue2, now, is_fullrun) {
427
- return { issue: issue2, taken_at: now.toISOString(), pid: process.pid, is_fullrun, ...session_owner() };
428
- }
429
- function write_hold(target, issue2, now = /* @__PURE__ */ new Date()) {
430
- const hold = build_hold(issue2, now);
431
- stamp_file.write_stamp(target, hold);
432
- return hold;
433
- }
434
- function create_hold(target, issue2, now = /* @__PURE__ */ new Date(), is_fullrun) {
435
- return stamp_file.create_stamp(target, build_hold(issue2, now, is_fullrun));
436
- }
437
- var HALFRUN_STOP_FIELDS = { is_halfrun_stop: true };
438
- function create_stop_hold(target, issue2, mark, now = /* @__PURE__ */ new Date()) {
439
- return stamp_file.create_stamp(target, { ...build_hold(issue2, now), ...mark });
440
- }
441
- function create_halfrun_stop_hold(target, issue2, now = /* @__PURE__ */ new Date()) {
442
- return create_stop_hold(target, issue2, HALFRUN_STOP_FIELDS, now);
443
- }
444
- async function is_tree_dirty(directory) {
445
- try {
446
- const status = await git_command.status(directory);
447
- return status.trim() !== "";
448
- } catch (error) {
449
- error_text.trace_swallowed("run_hold.is_tree_dirty", error);
450
- return true;
451
- }
452
- }
453
- function release_hold(target) {
454
- stamp_file.remove_stamp(target);
455
- }
456
- function describe_holder(hold) {
457
- const holder = hold.issue === UNNUMBERED_ISSUE ? "an unnumbered run" : session_cite.issue(hold.issue);
458
- return `${holder}, recorded ${hold.taken_at} (pid ${String(hold.owner_pid ?? hold.pid)})`;
459
- }
460
- function own_release_command(issue2) {
461
- return issue2 === UNNUMBERED_ISSUE ? RELEASE_COMMAND : `${RELEASE_COMMAND} ${issue2}`;
462
- }
463
- function is_own_hold(hold, claimant) {
464
- return hold.issue === claimant;
465
- }
466
- function is_reentry(hold, claimant) {
467
- return claimant !== UNNUMBERED_ISSUE && is_own_hold(hold, claimant);
468
- }
469
- function held_message(hold) {
470
- return `This working tree is already held by ${describe_holder(hold)}. One run at a time per working tree: a second run here commits its files onto the other run's branch. If that record is stale, run \`${FORCE_RELEASE_COMMAND}\` in this working tree \u2014 it removes a record this run did not write, so be sure the run that did has ended \u2014 and ask again.`;
471
- }
472
- function foreign_release_message(hold) {
473
- return `This working tree is held by ${describe_holder(hold)}, and this release did not claim it \u2014 nothing was removed. Release it as that run with \`${own_release_command(hold.issue)}\`, or, once you are sure it has ended, remove the record with \`${FORCE_RELEASE_COMMAND}\`.`;
474
- }
475
- function forced_release_message(hold) {
476
- return `Forced: removed the run record held by ${describe_holder(hold)}.`;
477
- }
478
- function unreadable_message() {
479
- return `This working tree's run record could not be read \u2014 ${NOT_IDLE}. Run \`${FORCE_RELEASE_COMMAND}\` in this working tree to clear it, then ask again.`;
480
- }
481
- function stale_message(hold) {
482
- const why = is_owner_gone(hold) ? "the session that wrote it has ended" : `older than ${String(HOLD_MAX_AGE_HOURS)} hours`;
483
- return `Replaced a stale run record held by ${describe_holder(hold)}: ${why}, so the run that wrote it has ended without releasing it.`;
484
- }
485
- function uncommitted_message(hold) {
486
- return `This working tree still has uncommitted changes, and its run record \u2014 held by ${describe_holder(hold)} \u2014 has expired or outlived its session. That is a run which stopped for a person rather than one that finished, so the tree is not free: commit or stash the work, or run \`${own_release_command(hold.issue)}\` once you are done with it, then ask again.`;
487
- }
488
- function race_message(read, target) {
489
- if (read.kind === "held") return held_message(read.hold);
490
- return `A record already exists at ${target} and this run did not write it \u2014 ${NOT_IDLE}. Either another run claimed the tree at the same moment, or the record belongs to another account. Run \`${FORCE_RELEASE_COMMAND}\`, and remove that file by hand if it is still there.`;
491
- }
492
- function unknown_message() {
493
- return `Could not read this working tree's git directory \u2014 ${NOT_IDLE}. Run this from inside the checkout the run will edit.`;
494
- }
495
- var run_hold = {
496
- is_stop_marked,
497
- FORCE_RELEASE_COMMAND,
498
- HOLD_MAX_AGE_HOURS,
499
- HOLD_MAX_AGE_MS,
500
- RELEASE_COMMAND,
501
- UNNUMBERED_ISSUE,
502
- classify: classify2,
503
- create_halfrun_stop_hold,
504
- create_stop_hold,
505
- HALFRUN_STOP_FIELDS,
506
- create_hold,
507
- foreign_release_message,
508
- forced_release_message,
509
- held_message,
510
- hold_path,
511
- is_linked_worktree,
512
- is_own_hold,
513
- is_reentry,
514
- is_tree_dirty,
515
- own_release_command,
516
- race_message,
517
- read_hold,
518
- release_hold,
519
- stale_message,
520
- uncommitted_message,
521
- unknown_message,
522
- unreadable_message,
523
- worktree_directory,
524
- write_hold
525
- };
526
-
527
237
  // scripts/cost-runtime/cost-pricing.ts
528
238
  var CACHE_WRITE_5M_MULTIPLIER = 1.25;
529
239
  var CACHE_WRITE_1H_MULTIPLIER = 2;
@@ -668,16 +378,16 @@ var context_cut_payback = {
668
378
  var CONTEXT_CUT_THRESHOLD = context_cut_payback.break_even_context();
669
379
 
670
380
  // scripts/run/cut/run-cut.ts
671
- import { z as z3 } from "zod";
381
+ import { z as z2 } from "zod";
672
382
 
673
383
  // scripts/run/cut/run-cut-handoff.ts
674
384
  import { readFileSync } from "node:fs";
675
- import { z as z2 } from "zod";
676
- var handoff_schema = z2.object({
677
- instruction: z2.string(),
678
- completed: z2.array(z2.string()),
679
- remaining: z2.array(z2.string()),
680
- untouched: z2.array(z2.string())
385
+ import { z } from "zod";
386
+ var handoff_schema = z.object({
387
+ instruction: z.string(),
388
+ completed: z.array(z.string()),
389
+ remaining: z.array(z.string()),
390
+ untouched: z.array(z.string())
681
391
  });
682
392
  var COMPLETED_LABEL = "Completed";
683
393
  var REMAINING_LABEL = "Remaining";
@@ -685,7 +395,7 @@ var UNTOUCHED_LABEL = "Deliberately untouched";
685
395
  var INSTRUCTION_LABEL = "Instruction (verbatim)";
686
396
  var EMPTY_LIST_NOTE = "(none)";
687
397
  function describe_key(key2) {
688
- const value = handoff_schema.shape[key2] instanceof z2.ZodArray ? '["\u2026"]' : '"\u2026"';
398
+ const value = handoff_schema.shape[key2] instanceof z.ZodArray ? '["\u2026"]' : '"\u2026"';
689
399
  return `"${key2}": ${value}`;
690
400
  }
691
401
  var HANDOFF_FORMAT = `a JSON object {${handoff_schema.keyof().options.map((key2) => describe_key(key2)).join(", ")}}`;
@@ -755,22 +465,22 @@ var CUT_MAX_AGE_HOURS = backlog_budget.IDLE_WAIT_HOURS;
755
465
  var END_COMMAND = "pnpm josh run:cut --end";
756
466
  var READ_COMMAND = "pnpm josh run:cut --json";
757
467
  var MAX_HANDOFF_BYTES = 8192;
758
- var run_cut_schema = z3.object({
759
- invocation: z3.string(),
760
- issue: z3.string(),
761
- branch: z3.string(),
762
- phase: z3.string(),
763
- cut_at: z3.string(),
764
- is_handed_off: z3.boolean().optional(),
468
+ var run_cut_schema = z2.object({
469
+ invocation: z2.string(),
470
+ issue: z2.string(),
471
+ branch: z2.string(),
472
+ phase: z2.string(),
473
+ cut_at: z2.string(),
474
+ is_handed_off: z2.boolean().optional(),
765
475
  handoff: run_cut_handoff.handoff_schema.optional(),
766
- is_merge_relaunched: z3.boolean().optional()
476
+ is_merge_relaunched: z2.boolean().optional()
767
477
  });
768
478
  function cut_path(git_directory) {
769
479
  return stamp_file.stamp_path(CUT_PREFIX, git_directory);
770
480
  }
771
- var { worktree_directory: worktree_directory2 } = run_hold;
772
- function invocation_for(issue2) {
773
- return lane_child_invocation.child_invocation(issue2);
481
+ var { worktree_directory } = run_hold;
482
+ function invocation_for(issue) {
483
+ return lane_child_invocation.child_invocation(issue);
774
484
  }
775
485
  function parse_cut(raw) {
776
486
  return json_value.parse_with(raw, run_cut_schema);
@@ -783,24 +493,24 @@ var CUT_SPEC = {
783
493
  timestamp_of: cut_at_of,
784
494
  max_age_ms: CUT_MAX_AGE_MS
785
495
  };
786
- function is_expired2(cut, now) {
496
+ function is_expired(cut, now) {
787
497
  return stamp_record.is_older_than(cut_at_of(cut), CUT_MAX_AGE_MS, now);
788
498
  }
789
- function classify3(raw, now) {
790
- const read = stamp_record.classify(raw, CUT_SPEC, now);
791
- if (!("record" in read)) return read;
792
- return { kind: read.kind, cut: read.record };
499
+ function classify(raw, now) {
500
+ const read2 = stamp_record.classify(raw, CUT_SPEC, now);
501
+ if (!("record" in read2)) return read2;
502
+ return { kind: read2.kind, cut: read2.record };
793
503
  }
794
504
  function read_cut(target, now = /* @__PURE__ */ new Date()) {
795
- return classify3(stamp_file.read_stamp_text(target), now);
505
+ return classify(stamp_file.read_stamp_text(target), now);
796
506
  }
797
507
  function worktree_git_directory_sync() {
798
508
  return git_common_directory.own();
799
509
  }
800
510
  function carried_cut_sync(now = /* @__PURE__ */ new Date(), directory = worktree_git_directory_sync()) {
801
511
  if (directory === void 0) return void 0;
802
- const read = read_cut(cut_path(directory), now);
803
- return read.kind === "carried" ? read.cut : void 0;
512
+ const read2 = read_cut(cut_path(directory), now);
513
+ return read2.kind === "carried" ? read2.cut : void 0;
804
514
  }
805
515
  function lane_cut_sync(lane_directory) {
806
516
  const directory = git_common_directory.own(lane_directory);
@@ -833,20 +543,20 @@ function begin_cut(target, spec, now = /* @__PURE__ */ new Date()) {
833
543
  if (!within_handoff_bound(cut)) return void 0;
834
544
  return stamp_file.create_stamp(target, cut) ? cut : void 0;
835
545
  }
836
- function is_declared_cut(cut, issue2) {
837
- return cut.is_handed_off === true && cut.invocation === invocation_for(issue2);
546
+ function is_declared_cut(cut, issue) {
547
+ return cut.is_handed_off === true && cut.invocation === invocation_for(issue);
838
548
  }
839
549
  function matches_state(cut, request) {
840
550
  return cut.branch === request.current_branch && cut.issue === request.issue && request.is_dirty && request.is_held;
841
551
  }
842
- function is_adopted_cut(cut, issue2) {
843
- return cut.is_handed_off === false && cut.invocation === invocation_for(issue2);
552
+ function is_adopted_cut(cut, issue) {
553
+ return cut.is_handed_off === false && cut.invocation === invocation_for(issue);
844
554
  }
845
555
  function has_required_handoff(cut) {
846
556
  return !resumes_into_implementation(cut.phase) || run_cut_handoff.is_complete_handoff(cut.handoff);
847
557
  }
848
- function is_relaunchable(cut, issue2) {
849
- return is_declared_cut(cut, issue2) && has_required_handoff(cut) && cut.is_merge_relaunched !== true;
558
+ function is_relaunchable(cut, issue) {
559
+ return is_declared_cut(cut, issue) && has_required_handoff(cut) && cut.is_merge_relaunched !== true;
850
560
  }
851
561
  function mark_merge_relaunched(target, cut) {
852
562
  stamp_file.remove_stamp(target);
@@ -867,8 +577,8 @@ function end_cut(target) {
867
577
  }
868
578
  function hold_of(directory) {
869
579
  if (directory === void 0) return void 0;
870
- const read = run_hold.read_hold(run_hold.hold_path(directory));
871
- return read.kind === "held" || read.kind === "stale" ? read.hold : void 0;
580
+ const read2 = run_hold.read_hold(run_hold.hold_path(directory));
581
+ return read2.kind === "held" || read2.kind === "stale" ? read2.hold : void 0;
872
582
  }
873
583
  function fullrun_issue(hold) {
874
584
  return hold?.is_fullrun === true ? hold.issue : void 0;
@@ -879,7 +589,7 @@ function held_issue_sync() {
879
589
  async function current_state() {
880
590
  const branch = await git_command.branch();
881
591
  const is_dirty = await run_hold.is_tree_dirty();
882
- const hold = hold_of(await worktree_directory2());
592
+ const hold = hold_of(await worktree_directory());
883
593
  return {
884
594
  branch,
885
595
  is_dirty,
@@ -897,16 +607,16 @@ function busy_message(cut) {
897
607
  function handed_off_message(cut) {
898
608
  return `This cut was already handed off to a successor \u2014 ${describe_cut(cut)}. Nothing was resumed here; the run is being carried on by the process that adopted it, so this one has nothing to do.`;
899
609
  }
900
- function stale_message2(cut) {
610
+ function stale_message(cut) {
901
611
  return `This cut does not match the current tree \u2014 ${describe_cut(cut)}. Resume failed; verify the branch and the uncommitted work, then clear it with \`${END_COMMAND}\` if the run is over.`;
902
612
  }
903
613
  function incomplete_message(cut) {
904
614
  return `This cut carries no instruction to resume on \u2014 ${describe_cut(cut)}. Resume was refused rather than continuing without it; recover the run's instruction and work state before implementing, and clear the record with \`${END_COMMAND}\` if the run is over.`;
905
615
  }
906
- function unreadable_message2() {
616
+ function unreadable_message() {
907
617
  return `A cut record is here but could not be read; clear it with \`${END_COMMAND}\` once you know no run is using it. Read it with \`${READ_COMMAND}\`.`;
908
618
  }
909
- function unknown_message2() {
619
+ function unknown_message() {
910
620
  return "This working tree\u2019s git directory could not be read, so no cut record was acted on.";
911
621
  }
912
622
  var run_cut = {
@@ -921,7 +631,7 @@ var run_cut = {
921
631
  begin_cut,
922
632
  busy_message,
923
633
  carried_cut_sync,
924
- classify: classify3,
634
+ classify,
925
635
  classify_resume,
926
636
  current_state,
927
637
  cut_path,
@@ -935,18 +645,18 @@ var run_cut = {
935
645
  hold_of,
936
646
  incomplete_message,
937
647
  invocation_for,
938
- is_expired: is_expired2,
648
+ is_expired,
939
649
  is_relaunchable,
940
650
  lane_cut_sync,
941
651
  mark_merge_relaunched,
942
652
  read_cut,
943
653
  record_within_bound,
944
654
  resumes_into_implementation,
945
- stale_message: stale_message2,
946
- unknown_message: unknown_message2,
947
- unreadable_message: unreadable_message2,
655
+ stale_message,
656
+ unknown_message,
657
+ unreadable_message,
948
658
  within_handoff_bound,
949
- worktree_directory: worktree_directory2,
659
+ worktree_directory,
950
660
  worktree_git_directory_sync
951
661
  };
952
662
 
@@ -1077,7 +787,7 @@ var lane_background = {
1077
787
  // scripts/run/ship/run-ship-detach.ts
1078
788
  import { randomUUID } from "node:crypto";
1079
789
  import { setTimeout as sleep } from "node:timers/promises";
1080
- import { z as z4 } from "zod";
790
+ import { z as z3 } from "zod";
1081
791
  var LOG_PREFIX = "josh-ship-log-";
1082
792
  var PID_PREFIX = "josh-ship-pid-";
1083
793
  var BODY_PREFIX = "josh-ship-notify-";
@@ -1098,14 +808,14 @@ var RESULT_PREFIX = "josh-ship-result-";
1098
808
  var RECORD_POLL_MS = 25;
1099
809
  var RECORD_WAIT_ATTEMPTS = 200;
1100
810
  var CLAIM_WINDOW_MS = 12e4;
1101
- var ship_record_schema = z4.object({
1102
- pid: z4.number().int().positive().optional(),
1103
- process_start: z4.string().optional(),
1104
- launched_at: z4.number().optional(),
1105
- launcher_pid: z4.number().int().positive().optional(),
1106
- launcher_start: z4.string().optional(),
1107
- launch_id: z4.string(),
1108
- result: z4.enum(["success", "failed"]).optional()
811
+ var ship_record_schema = z3.object({
812
+ pid: z3.number().int().positive().optional(),
813
+ process_start: z3.string().optional(),
814
+ launched_at: z3.number().optional(),
815
+ launcher_pid: z3.number().int().positive().optional(),
816
+ launcher_start: z3.string().optional(),
817
+ launch_id: z3.string(),
818
+ result: z3.enum(["success", "failed"]).optional()
1109
819
  });
1110
820
  var LAUNCH_MARK = " \xB7 started by process ";
1111
821
  var HEADER_START = "\n";
@@ -1168,6 +878,10 @@ function current_record(repository, number) {
1168
878
  const record = read_record(repository, number);
1169
879
  return record?.launch_id === process.env[LAUNCH_ID_KEY] ? record : void 0;
1170
880
  }
881
+ function running_since(repository, number) {
882
+ const record = read_record(repository, number);
883
+ return record !== void 0 && result_of(record) === "running" ? record.launched_at : void 0;
884
+ }
1171
885
  function is_pending(record) {
1172
886
  return record !== void 0 && record.pid === void 0;
1173
887
  }
@@ -1275,14 +989,14 @@ async function detach(request) {
1275
989
  }
1276
990
  return result;
1277
991
  }
1278
- function last_launch(text2) {
1279
- const mark = text2.lastIndexOf(LAUNCH_MARK);
1280
- if (mark === -1) return text2;
1281
- return text2.slice(text2.lastIndexOf(HEADER_START, mark) + HEADER_START.length);
992
+ function last_launch(text) {
993
+ const mark = text.lastIndexOf(LAUNCH_MARK);
994
+ if (mark === -1) return text;
995
+ return text.slice(text.lastIndexOf(HEADER_START, mark) + HEADER_START.length);
1282
996
  }
1283
997
  function read_log(repository, number) {
1284
- const text2 = stamp_file.read_stamp_text(log_path(repository, number));
1285
- return text2 === void 0 ? void 0 : last_launch(text2);
998
+ const text = stamp_file.read_stamp_text(log_path(repository, number));
999
+ return text === void 0 ? void 0 : last_launch(text);
1286
1000
  }
1287
1001
  function is_supervised(source = process.env) {
1288
1002
  return source[SUPERVISED_KEY] === SUPERVISED_VALUE;
@@ -1301,20 +1015,25 @@ var run_ship_detach = {
1301
1015
  last_launch,
1302
1016
  log_path,
1303
1017
  read_log,
1018
+ running_since,
1304
1019
  supervisor_argv
1305
1020
  };
1306
1021
 
1307
1022
  // scripts/lane/lane-handoff.ts
1308
- function is_ship_running(issue2, directory) {
1023
+ function is_ship_running(issue, directory) {
1309
1024
  const repository = git_common_directory.repository(directory);
1310
- return repository !== void 0 && run_ship_detach.read_result(repository, issue2)?.result === "running";
1025
+ return repository !== void 0 && run_ship_detach.read_result(repository, issue)?.result === "running";
1026
+ }
1027
+ function ship_running_since(issue, directory) {
1028
+ const repository = git_common_directory.repository(directory);
1029
+ return repository === void 0 ? void 0 : run_ship_detach.running_since(repository, issue);
1311
1030
  }
1312
1031
  function is_handed_off(directory, source = process.env) {
1313
- const issue2 = lane_child_marker.marked_issue(source);
1314
- if (issue2 === void 0 || !lane_child_marker.is_child_of(directory, source)) return false;
1315
- return is_ship_running(issue2, directory);
1032
+ const issue = lane_child_marker.marked_issue(source);
1033
+ if (issue === void 0 || !lane_child_marker.is_child_of(directory, source)) return false;
1034
+ return is_ship_running(issue, directory);
1316
1035
  }
1317
- var lane_handoff = { is_handed_off, is_ship_running };
1036
+ var lane_handoff = { is_handed_off, is_ship_running, ship_running_since };
1318
1037
 
1319
1038
  // scripts/issue/issue-labels.ts
1320
1039
  var EPIC_LABEL = "epic";
@@ -1482,9 +1201,9 @@ function is_confirmation_notify(command) {
1482
1201
  }
1483
1202
  var NOTIFY_INVOCATION = /josh\s+(?:notify|nf)\b/u;
1484
1203
  var COMMAND_NOTIFY_MARKER = "stop notified: a confirmation Telegram was sent by this command";
1485
- function mentions_confirmation_notify(text2) {
1486
- if (text2.includes(COMMAND_NOTIFY_MARKER)) return true;
1487
- return NOTIFY_INVOCATION.test(text2) && CONFIRMATION_TASK_TYPE.test(text2);
1204
+ function mentions_confirmation_notify(text) {
1205
+ if (text.includes(COMMAND_NOTIFY_MARKER)) return true;
1206
+ return NOTIFY_INVOCATION.test(text) && CONFIRMATION_TASK_TYPE.test(text);
1488
1207
  }
1489
1208
  function is_parking_child(directory = process.cwd()) {
1490
1209
  return lane_child_marker.is_child_of(directory) && !lane_handoff.is_handed_off(directory);
@@ -1518,373 +1237,494 @@ var lane_park = {
1518
1237
  records_the_park
1519
1238
  };
1520
1239
 
1521
- // scripts/discovery/repo-party.ts
1522
- var FIRST_PARTY = "first-party";
1523
- var THIRD_PARTY = "third-party";
1524
- var UNKNOWN = "unknown";
1525
- var GH_REPO_ENV_KEY = "GH_REPO";
1526
- var GH_REPO_PATH_SEGMENTS = 2;
1527
- function classify4(session_owner2, target) {
1528
- if (session_owner2 === void 0 || target === void 0) return UNKNOWN;
1529
- return session_owner2.toLowerCase() === target.toLowerCase() ? FIRST_PARTY : THIRD_PARTY;
1530
- }
1531
- function target_owner(owner_repo) {
1532
- return repo_origin.parse_origin_url(`https://${repo_origin.GITHUB_HOST}/${owner_repo}`)?.owner;
1240
+ // scripts/cost-runtime/cost-cli.ts
1241
+ import { fileURLToPath } from "node:url";
1242
+
1243
+ // scripts/cost-runtime/codex-usage.ts
1244
+ import { globSync, readFileSync as readFileSync2 } from "node:fs";
1245
+ import path from "node:path";
1246
+ import { z as z4 } from "zod";
1247
+ var THREAD_ID_PATTERN = /^[A-Za-z0-9-]+$/u;
1248
+ var SESSION_META_SCHEMA = z4.looseObject({
1249
+ type: z4.literal("session_meta"),
1250
+ payload: z4.looseObject({ id: z4.string(), cwd: z4.string() })
1251
+ });
1252
+ var TOTAL_USAGE_SCHEMA = z4.looseObject({ input_tokens: z4.number().nonnegative() });
1253
+ var TOKEN_COUNT_SCHEMA = z4.looseObject({
1254
+ type: z4.literal("event_msg"),
1255
+ payload: z4.looseObject({
1256
+ type: z4.literal("token_count"),
1257
+ info: z4.looseObject({
1258
+ total_token_usage: TOTAL_USAGE_SCHEMA,
1259
+ last_token_usage: TOTAL_USAGE_SCHEMA
1260
+ })
1261
+ })
1262
+ });
1263
+ function same_project(cwd, target) {
1264
+ return cost_transcript.session_cwd(cwd) === cost_transcript.session_cwd(target);
1533
1265
  }
1534
- function current_owner(repository_path = process.cwd()) {
1535
- return repo_discovery.resolve_current_owner(repository_path);
1266
+ function billed_per_request(usages) {
1267
+ return usages.map((usage) => usage.last_token_usage.input_tokens);
1536
1268
  }
1537
- function gh_repo_owners(gh_repo) {
1538
- return [target_owner(gh_repo.split("/").slice(-GH_REPO_PATH_SEGMENTS).join("/"))];
1269
+ function measurement_from(content, target, thread_id) {
1270
+ const values = content.split("\n").map((line) => json_value.parse_or_undefined(line));
1271
+ const metadata = values.flatMap((value) => {
1272
+ const parsed = SESSION_META_SCHEMA.safeParse(value);
1273
+ return parsed.success ? [parsed.data] : [];
1274
+ });
1275
+ const usages = values.flatMap((value) => {
1276
+ const parsed = TOKEN_COUNT_SCHEMA.safeParse(value);
1277
+ return parsed.success ? [parsed.data.payload.info] : [];
1278
+ });
1279
+ const session = metadata.find((entry) => entry.payload.id === thread_id);
1280
+ if (session === void 0 || usages.length === 0 || !same_project(session.payload.cwd, target)) {
1281
+ return void 0;
1282
+ }
1283
+ return { billed_input_per_request: billed_per_request(usages) };
1539
1284
  }
1540
- function remote_owners(repository_path) {
1541
- return repo_discovery.read_remote_urls(repository_path).map((url) => repo_origin.parse_origin_url(url)?.owner);
1285
+ function rollout_files(home, thread_id) {
1286
+ if (!THREAD_ID_PATTERN.test(thread_id)) return [];
1287
+ return globSync(`sessions/**/*${thread_id}.jsonl`, { cwd: home }).map(
1288
+ (file) => path.join(home, file)
1289
+ );
1542
1290
  }
1543
- function placeholder_owners(repository_path = process.cwd(), environment = process.env) {
1544
- const gh_repo = environment[GH_REPO_ENV_KEY];
1545
- return gh_repo === void 0 || gh_repo === "" ? remote_owners(repository_path) : gh_repo_owners(gh_repo);
1291
+ function read_measurement(file, target, thread_id) {
1292
+ try {
1293
+ return measurement_from(readFileSync2(file, "utf8"), target, thread_id);
1294
+ } catch {
1295
+ return void 0;
1296
+ }
1546
1297
  }
1547
- var repo_party = {
1548
- FIRST_PARTY,
1549
- THIRD_PARTY,
1550
- UNKNOWN,
1551
- classify: classify4,
1552
- current_owner,
1553
- placeholder_owners,
1554
- target_owner
1555
- };
1556
-
1557
- // scripts/gh/git-gh-api-path.ts
1558
- var FULL_PAGE_QUERY = "?per_page=100";
1559
- function repo_api_path(repo = "{owner}/{repo}") {
1560
- return `repos/${repo}`;
1298
+ function latest_measurement(files, target, thread_id) {
1299
+ for (const file of files.toReversed()) {
1300
+ const measured = read_measurement(file, target, thread_id);
1301
+ if (measured !== void 0) return measured;
1302
+ }
1303
+ return void 0;
1561
1304
  }
1562
- function issues_api_path(repo) {
1563
- return `${repo_api_path(repo)}/issues`;
1305
+ function measurement(target, default_home, environment = process.env) {
1306
+ const thread_id = environment["CODEX_THREAD_ID"];
1307
+ if (thread_id === void 0) return void 0;
1308
+ const home = environment["CODEX_HOME"] ?? path.join(default_home, ".codex");
1309
+ return latest_measurement(rollout_files(home, thread_id), target, thread_id);
1564
1310
  }
1565
- function issue_api_path(issue_number, repo) {
1566
- return `${issues_api_path(repo)}/${issue_number}`;
1311
+ var codex_usage = { measurement };
1312
+
1313
+ // scripts/cost-runtime/cost-corpus.ts
1314
+ function accumulate_missing(sessions) {
1315
+ return {
1316
+ no_usage_lines: sessions.reduce((sum, session) => sum + session.no_usage_lines, 0),
1317
+ malformed_lines: sessions.reduce((sum, session) => sum + session.malformed_lines, 0),
1318
+ unreadable_sessions: sessions.filter((session) => !session.is_readable).length,
1319
+ // Filled by the attribution, which is the only step that knows a unit could not follow its
1320
+ // parent; a per-session tally cannot see it, so it is zero here and set for an issue scope below.
1321
+ unattributed_sessions: 0
1322
+ };
1567
1323
  }
1568
- function blocked_by_api_path(issue_number, repo) {
1569
- return `${issue_api_path(issue_number, repo)}/dependencies/blocked_by`;
1324
+ function load_corpus(cwd) {
1325
+ const files = cost_transcript.list_sessions_across(cost_transcript.transcript_directories(cwd));
1326
+ const sessions = files.map((file) => cost_transcript.read_session(file));
1327
+ return { sessions, files, missing: accumulate_missing(sessions) };
1570
1328
  }
1571
- function issue_comments_api_path(issue_number, repo) {
1572
- return `${issue_api_path(issue_number, repo)}/comments`;
1329
+ function session_meta(corpus) {
1330
+ return new Map(
1331
+ corpus.files.map((file) => [
1332
+ file.session_id,
1333
+ { is_delegated: file.is_delegated, owner: cost_transcript.owning_session_id(file) }
1334
+ ])
1335
+ );
1573
1336
  }
1574
- function pulls_api_path(repo) {
1575
- return `${repo_api_path(repo)}/pulls`;
1337
+ function issue_set(records) {
1338
+ const issues = cost_attribute.group_by_issue(records).map((group) => group.issue).filter((issue) => issue !== cost_attribute.UNATTRIBUTED_KEY);
1339
+ return new Set(issues);
1576
1340
  }
1577
- function pull_api_path(pr_number, repo) {
1578
- return `${pulls_api_path(repo)}/${pr_number}`;
1341
+ function sole_of(issues) {
1342
+ if (issues.size !== 1) return cost_attribute.UNATTRIBUTED_KEY;
1343
+ return [...issues][0] ?? cost_attribute.UNATTRIBUTED_KEY;
1579
1344
  }
1580
- function pull_merge_api_path(pr_number, repo) {
1581
- return `${pull_api_path(pr_number, repo)}/merge`;
1345
+ function owner_sets(corpus, meta) {
1346
+ const own = corpus.sessions.filter(
1347
+ (session) => meta.get(session.session_id)?.is_delegated !== true
1348
+ );
1349
+ return new Map(own.map((session) => [session.session_id, issue_set(session.records)]));
1350
+ }
1351
+ function pairs_with_inherited(session, inherited, is_delegated) {
1352
+ return cost_attribute.group_by_issue(session.records).flatMap(
1353
+ (group) => group.records.map((record) => ({
1354
+ record,
1355
+ issue: group.issue === cost_attribute.UNATTRIBUTED_KEY ? inherited : group.issue,
1356
+ baseline_tokens: session.baseline_tokens,
1357
+ session_id: session.session_id,
1358
+ is_delegated
1359
+ }))
1360
+ );
1582
1361
  }
1583
- function pull_comments_api_path(pr_number, repo) {
1584
- return `${pull_api_path(pr_number, repo)}/comments`;
1362
+ var NO_ISSUES = /* @__PURE__ */ new Set();
1363
+ function parent_issues(session, meta, owners) {
1364
+ const entry = meta.get(session.session_id);
1365
+ if (entry?.is_delegated !== true) return NO_ISSUES;
1366
+ return owners.get(entry.owner) ?? NO_ISSUES;
1367
+ }
1368
+ function pairs_of_session(session, meta, owners) {
1369
+ const is_delegated = meta.get(session.session_id)?.is_delegated === true;
1370
+ const candidates = parent_issues(session, meta, owners);
1371
+ const inherited = is_delegated ? sole_of(candidates) : cost_attribute.UNATTRIBUTED_KEY;
1372
+ const pairs = pairs_with_inherited(session, inherited, is_delegated);
1373
+ const has_unattributed = pairs.some((pair) => pair.issue === cost_attribute.UNATTRIBUTED_KEY);
1374
+ if (!is_delegated || !has_unattributed) return { pairs };
1375
+ return { pairs, unattributed_candidates: candidates };
1376
+ }
1377
+ function attribute_corpus(corpus) {
1378
+ const meta = session_meta(corpus);
1379
+ const owners = owner_sets(corpus, meta);
1380
+ const per_session = corpus.sessions.map((session) => pairs_of_session(session, meta, owners));
1381
+ return {
1382
+ pairs: per_session.flatMap((one) => one.pairs),
1383
+ unattributed: per_session.flatMap(
1384
+ (one) => one.unattributed_candidates === void 0 ? [] : [one.unattributed_candidates]
1385
+ )
1386
+ };
1585
1387
  }
1586
- function pull_reviews_api_path(pr_number, repo) {
1587
- return `${pull_api_path(pr_number, repo)}/reviews`;
1388
+ function floor_for_issue(unattributed, issue_number) {
1389
+ return unattributed.filter((set) => set.size === 0 || set.has(issue_number)).length;
1588
1390
  }
1589
- function commit_api_path(commit_sha, repo) {
1590
- return `${repo_api_path(repo)}/commits/${commit_sha}`;
1391
+ function is_better(candidate, existing) {
1392
+ const { UNATTRIBUTED_KEY } = cost_attribute;
1393
+ return existing.issue === UNATTRIBUTED_KEY && candidate.issue !== UNATTRIBUTED_KEY;
1591
1394
  }
1592
- function commit_check_runs_api_path(commit_sha, repo) {
1593
- return `${commit_api_path(commit_sha, repo)}/check-runs`;
1395
+ function values_of(best) {
1396
+ const collected = [];
1397
+ for (const [, pair] of best) collected.push(pair);
1398
+ return collected;
1594
1399
  }
1595
- function commit_status_api_path(commit_sha, repo) {
1596
- return `${commit_api_path(commit_sha, repo)}/status`;
1400
+ function dedupe_across_sessions(pairs) {
1401
+ const best = /* @__PURE__ */ new Map();
1402
+ for (const pair of pairs) {
1403
+ const existing = best.get(pair.record.request_id);
1404
+ if (existing === void 0 || is_better(pair, existing)) {
1405
+ best.set(pair.record.request_id, pair);
1406
+ }
1407
+ }
1408
+ return values_of(best);
1597
1409
  }
1598
- function tag_reference_api_path(tag, repo) {
1599
- return `${repo_api_path(repo)}/git/ref/tags/${tag}`;
1410
+ function attributed(corpus) {
1411
+ return dedupe_across_sessions(attribute_corpus(corpus).pairs);
1600
1412
  }
1601
- function release_by_tag_api_path(tag, repo) {
1602
- return `${repo_api_path(repo)}/releases/tags/${tag}`;
1413
+ function mainline_records(pairs) {
1414
+ const groups = /* @__PURE__ */ new Map();
1415
+ for (const pair of pairs) {
1416
+ if (pair.is_delegated) continue;
1417
+ groups.set(pair.session_id, [...groups.get(pair.session_id) ?? [], pair.record]);
1418
+ }
1419
+ return [...groups.values()];
1603
1420
  }
1604
- var git_gh_api_path = {
1605
- FULL_PAGE_QUERY,
1606
- repo_api_path,
1607
- tag_ref_api_path: tag_reference_api_path,
1608
- release_by_tag_api_path,
1609
- issues_api_path,
1610
- issue_api_path,
1611
- blocked_by_api_path,
1612
- issue_comments_api_path,
1613
- pulls_api_path,
1614
- pull_api_path,
1615
- pull_merge_api_path,
1616
- pull_comments_api_path,
1617
- pull_reviews_api_path,
1618
- commit_api_path,
1619
- commit_check_runs_api_path,
1620
- commit_status_api_path
1421
+ var cost_corpus = {
1422
+ load_corpus,
1423
+ attribute_corpus,
1424
+ floor_for_issue,
1425
+ attributed,
1426
+ mainline_records
1621
1427
  };
1622
1428
 
1623
- // scripts/gh/git-gh-exec.ts
1624
- import { execa as execa2, execaSync } from "execa";
1429
+ // scripts/cost-runtime/cost-verdict.ts
1430
+ var FAILURE_EXIT_CODE = 1;
1431
+ var OVER_VERDICT = "over";
1432
+ var UNDER_VERDICT = "under";
1433
+ function per_request_cost(measurement2) {
1434
+ return measurement2.billed_input_per_request.at(-1) ?? 0;
1435
+ }
1436
+ function classify2(measurement2, limit) {
1437
+ return per_request_cost(measurement2) > limit ? OVER_VERDICT : UNDER_VERDICT;
1438
+ }
1439
+ function over_summary(measurement2, limit) {
1440
+ const total = measurement2.billed_input_per_request.length;
1441
+ return `${String(per_request_cost(measurement2))} billed input tokens per request, on the newest of ${String(total)} request(s); limit ${String(limit)}`;
1442
+ }
1443
+ function report_over(measurement2, limit) {
1444
+ if (measurement2 === void 0 || measurement2.billed_input_per_request.length === 0) {
1445
+ console.error("No requests in this session; there is nothing to hand off.");
1446
+ return FAILURE_EXIT_CODE;
1447
+ }
1448
+ console.info(classify2(measurement2, limit));
1449
+ console.error(over_summary(measurement2, limit));
1450
+ return 0;
1451
+ }
1452
+ var cost_verdict = {
1453
+ OVER_VERDICT,
1454
+ UNDER_VERDICT,
1455
+ classify: classify2,
1456
+ per_request_cost,
1457
+ report_over
1458
+ };
1625
1459
 
1626
- // scripts/gh/git-gh-check.ts
1627
- import { execa } from "execa";
1628
- var GH_NOT_INSTALLED_MSG = "gh CLI is not installed. Install it from https://cli.github.com/";
1629
- var gh_check = {};
1630
- async function run_gh_check() {
1631
- try {
1632
- await execa("gh", ["--version"], { timeout: COMMAND_TIMEOUT_MS });
1633
- } catch {
1634
- delete gh_check.promise;
1635
- throw new Error(GH_NOT_INSTALLED_MSG);
1636
- }
1637
- }
1638
- async function check_gh_installed() {
1639
- gh_check.promise ??= run_gh_check();
1640
- await gh_check.promise;
1460
+ // scripts/cost-runtime/transcript-cwd.ts
1461
+ import path2 from "node:path";
1462
+ function resolve(target, cwd) {
1463
+ return target === void 0 ? cwd : path2.resolve(target);
1641
1464
  }
1465
+ var transcript_cwd = { resolve };
1642
1466
 
1643
- // scripts/git/parse-json-array.ts
1644
- function parse_json_loose(raw_json) {
1645
- return json_value.parse_or_undefined(raw_json);
1467
+ // scripts/cost-runtime/cost-cli.ts
1468
+ var ARGV_OFFSET = 2;
1469
+ var FAILURE_EXIT_CODE2 = 1;
1470
+ var USAGE = "Usage: josh cost (--cut | --over <tokens-per-request>) [--path <dir>]";
1471
+ var UNMEASURABLE_VERDICT = "unmeasurable";
1472
+ function to_threshold(raw) {
1473
+ if (raw === void 0 || raw.trim() === "") return void 0;
1474
+ const parsed = Number(raw);
1475
+ return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : void 0;
1476
+ }
1477
+ function is_unparsed(raw, parsed) {
1478
+ return parsed === void 0 && raw !== void 0;
1479
+ }
1480
+ function selected_threshold(values) {
1481
+ if (values.cut === true) return CONTEXT_CUT_THRESHOLD;
1482
+ return to_threshold(values.over);
1483
+ }
1484
+ function threshold_option(over) {
1485
+ return over === void 0 ? {} : { over };
1486
+ }
1487
+ function path_option(path4) {
1488
+ return path4 === void 0 ? {} : { path: path4 };
1489
+ }
1490
+ function to_options(values) {
1491
+ if (values.cut === true && values.over !== void 0) return void 0;
1492
+ const over = selected_threshold(values);
1493
+ if (is_unparsed(values.over, over)) return void 0;
1494
+ return { ...threshold_option(over), ...path_option(values.path) };
1495
+ }
1496
+ var PARSE_ARGS_OPTIONS = {
1497
+ cut: { type: "boolean" },
1498
+ over: { type: "string" },
1499
+ path: { type: "string" }
1500
+ };
1501
+ function parse_options(argv) {
1502
+ const values = cli_flags.values_of(argv, PARSE_ARGS_OPTIONS);
1503
+ return values === void 0 ? void 0 : to_options(values);
1646
1504
  }
1647
- function parse_json_array_or_undefined(raw_json, element_schema) {
1648
- const value = parse_json_loose(raw_json);
1649
- if (!Array.isArray(value)) return void 0;
1650
- return element_schema.array().parse(value);
1505
+ function report_empty(cwd, session_id) {
1506
+ const searched = cost_transcript.searched_directories(cost_transcript.transcript_directories(cwd));
1507
+ for (const line of cost_transcript.missing_message(searched, session_id)) console.error(line);
1508
+ return FAILURE_EXIT_CODE2;
1651
1509
  }
1652
- function read_json_listing(raw_json, element_schema) {
1653
- try {
1654
- const rows = parse_json_array_or_undefined(raw_json, element_schema);
1655
- return rows === void 0 ? { kind: "unreadable" } : { kind: "read", rows };
1656
- } catch {
1657
- return { kind: "unexpected_shape" };
1658
- }
1510
+ function provider_of(environment) {
1511
+ const resolved = agent_role_profile.resolve_provider(environment);
1512
+ if (resolved.kind !== "provider" || resolved.is_default === true) return void 0;
1513
+ return resolved.provider;
1659
1514
  }
1660
- function parse_json_object_or_undefined(raw_json, schema) {
1661
- const value = parse_json_loose(raw_json);
1662
- if (value === void 0) return void 0;
1663
- return schema.parse(value);
1664
- }
1665
- var parse_json = {
1666
- parse_json_object_or_undefined
1667
- };
1668
-
1669
- // scripts/gh/git-gh-failure.ts
1670
- import { z as z5 } from "zod";
1671
- var error_document_schema = z5.object({ status: z5.union([z5.string(), z5.number()]).optional() }).catch({});
1672
- var GH_FAILURE_FIELD = "gh_failure";
1673
- function has_gh_failure(error) {
1674
- return error instanceof Error && Object.hasOwn(error, GH_FAILURE_FIELD);
1675
- }
1676
- function parse_response_status(stdout) {
1677
- const document = parse_json.parse_json_object_or_undefined(stdout, error_document_schema);
1678
- if (document?.status === void 0) return void 0;
1679
- const status = Number(document.status);
1680
- return Number.isSafeInteger(status) ? status : void 0;
1681
- }
1682
- function classify_stdout(stdout) {
1683
- return { status: parse_response_status(stdout) };
1684
- }
1685
- function attach(error, failure) {
1686
- Object.defineProperty(error, GH_FAILURE_FIELD, {
1687
- value: failure,
1688
- enumerable: false,
1689
- configurable: true
1690
- });
1691
- return error;
1515
+ function measurement_of(session) {
1516
+ return {
1517
+ billed_input_per_request: session.records.map(
1518
+ (record) => cost_usage.billed_input(record.totals)
1519
+ )
1520
+ };
1692
1521
  }
1693
- function failure_of(error) {
1694
- return has_gh_failure(error) ? error.gh_failure : void 0;
1522
+ function anthropic_own(target, environment) {
1523
+ const corpus = cost_corpus.load_corpus(target);
1524
+ const selection = own_session.select_own_session(corpus.files, environment);
1525
+ if (selection.kind === "absent") return { kind: "absent", session_id: selection.session_id };
1526
+ const session = corpus.sessions[selection.index];
1527
+ if (session === void 0) return { kind: "empty" };
1528
+ return { kind: "measured", measurement: measurement_of(session) };
1695
1529
  }
1696
- var gh_failure = { attach, classify_stdout, failure_of, parse_response_status };
1697
-
1698
- // scripts/gh/git-gh-exec.ts
1699
- var BODY_FROM_STDIN = "-";
1700
- var GH_REQUEST_TIMEOUT_MS = 6e4;
1701
- function to_timeout_option(timeout_ms) {
1702
- return { timeout: timeout_ms ?? GH_REQUEST_TIMEOUT_MS };
1530
+ function anthropic_measurement(target, environment) {
1531
+ const own = anthropic_own(target, environment);
1532
+ return own.kind === "measured" ? own.measurement : void 0;
1703
1533
  }
1704
- function direct_environment() {
1705
- const removed = agent_session_environment.removed_proxy_environment();
1706
- return Object.keys(removed).length > 0 ? { env: removed } : {};
1534
+ function same_openai_project(target, cwd) {
1535
+ return cost_transcript.session_cwd(target) === cost_transcript.session_cwd(cwd);
1707
1536
  }
1708
- function to_spawn_options(timeout_ms, cwd) {
1709
- return {
1710
- ...to_timeout_option(timeout_ms),
1711
- ...direct_environment(),
1712
- ...cwd !== void 0 && { cwd }
1713
- };
1537
+ function reject_openai_cross_project(context, target, cwd) {
1538
+ if (context.provider !== "openai" || context.path === void 0 || same_openai_project(target, cwd)) {
1539
+ return false;
1540
+ }
1541
+ console.error(
1542
+ "OpenAI --path cannot select a thread from another project; run josh cost in that project."
1543
+ );
1544
+ return true;
1714
1545
  }
1715
- var GH_REQUEST_TIMEOUT_MESSAGE = "gh request timed out";
1716
- function has_stderr_field(error) {
1717
- return error instanceof Error && "stderr" in error && typeof error.stderr === "string";
1718
- }
1719
- function has_stdout_field(error) {
1720
- return error instanceof Error && "stdout" in error && typeof error.stdout === "string";
1721
- }
1722
- function to_timeout_prefix(error) {
1723
- return has_timed_out(error) ? `${GH_REQUEST_TIMEOUT_MESSAGE}: ` : "";
1724
- }
1725
- function to_gh_error(error) {
1726
- const stderr = has_stderr_field(error) ? error.stderr.trim() : "";
1727
- const stdout = has_stdout_field(error) ? error.stdout.trim() : "";
1728
- const summary = stderr.length > 0 ? stderr : error_text.message_of(error);
1729
- const detail = stdout.length > 0 ? `${summary}
1730
- ${stdout}` : summary;
1731
- return gh_failure.attach(
1732
- new Error(`${to_timeout_prefix(error)}${detail}`, { cause: error }),
1733
- gh_failure.classify_stdout(stdout)
1546
+ function measure(target, provider, environment) {
1547
+ return provider === "openai" ? codex_usage.measurement(target, cost_transcript.home_directory(), environment) : anthropic_measurement(target, environment);
1548
+ }
1549
+ function run_over_anthropic(own, target, limit) {
1550
+ if (own.kind === "measured") return cost_verdict.report_over(own.measurement, limit);
1551
+ return report_empty(target, own.kind === "absent" ? own.session_id : void 0);
1552
+ }
1553
+ function run_over_codex(target, limit, environment) {
1554
+ const measurement2 = measure(target, "openai", environment);
1555
+ if (measurement2 !== void 0) return cost_verdict.report_over(measurement2, limit);
1556
+ console.error(`No Codex usage found for the current OpenAI thread under ${target}.`);
1557
+ return FAILURE_EXIT_CODE2;
1558
+ }
1559
+ function run_over(target, limit, provider, environment) {
1560
+ if (provider === "anthropic") {
1561
+ return run_over_anthropic(anthropic_own(target, environment), target, limit);
1562
+ }
1563
+ return run_over_codex(target, limit, environment);
1564
+ }
1565
+ function verdict_of(measurement2) {
1566
+ if (measurement2 === void 0 || measurement2.billed_input_per_request.length === 0) {
1567
+ return UNMEASURABLE_VERDICT;
1568
+ }
1569
+ return cost_verdict.classify(measurement2, CONTEXT_CUT_THRESHOLD);
1570
+ }
1571
+ function session_verdict(cwd = process.cwd(), environment = process.env) {
1572
+ const provider = provider_of(environment);
1573
+ if (provider === void 0) return UNMEASURABLE_VERDICT;
1574
+ return verdict_of(measure(cwd, provider, environment));
1575
+ }
1576
+ function run_context(argv, environment) {
1577
+ const options = parse_options(argv);
1578
+ if (options?.over === void 0) return void 0;
1579
+ const provider = provider_of(environment);
1580
+ if (provider === void 0) return void 0;
1581
+ return { over: options.over, path: options.path, provider };
1582
+ }
1583
+ function run(argv, cwd = process.cwd(), environment = process.env) {
1584
+ const context = run_context(argv, environment);
1585
+ if (context === void 0) {
1586
+ console.error(USAGE);
1587
+ return FAILURE_EXIT_CODE2;
1588
+ }
1589
+ const target = transcript_cwd.resolve(context.path, cwd);
1590
+ if (reject_openai_cross_project(context, target, cwd)) return FAILURE_EXIT_CODE2;
1591
+ return run_over(target, context.over, context.provider, environment);
1592
+ }
1593
+ function main(argv) {
1594
+ process.exitCode = run(argv);
1595
+ }
1596
+ var cost_cli = {
1597
+ UNMEASURABLE_VERDICT,
1598
+ USAGE,
1599
+ parse_options,
1600
+ to_threshold,
1601
+ run,
1602
+ session_verdict
1603
+ };
1604
+ if (process.argv[1] === fileURLToPath(import.meta.url)) main(process.argv.slice(ARGV_OFFSET));
1605
+
1606
+ // scripts/rules/pre-gate-cut.ts
1607
+ var GATE_COMMANDS = /* @__PURE__ */ new Set(["gate"]);
1608
+ var CUT_COMMANDS = /* @__PURE__ */ new Set(["run:cut"]);
1609
+ var CUT_MODE_FLAG = /(?:^|\s)--(?:resume|end|json)(?:[=\s]|$)/u;
1610
+ var HOLD_COMMANDS = /* @__PURE__ */ new Set(["run:hold"]);
1611
+ var HOLD_MODE_FLAG = /(?:^|\s)--release(?:[=\s]|$)/u;
1612
+ function invokes_josh(command, names, mode_flag) {
1613
+ return shell_segments.segments_of(command).some(
1614
+ (segment) => shell_segments.is_josh_command(segment, names) && mode_flag?.test(segment) !== true
1734
1615
  );
1735
1616
  }
1736
- async function exec_gh_command(arguments_, timeout_ms, cwd) {
1737
- await check_gh_installed();
1738
- const options = to_spawn_options(timeout_ms, cwd);
1739
- try {
1740
- const { stdout } = await execa2("gh", arguments_, options);
1741
- return stdout.trimEnd();
1742
- } catch (error) {
1743
- throw to_gh_error(error);
1744
- }
1617
+ function runs_the_gate(command) {
1618
+ return invokes_josh(command, GATE_COMMANDS);
1745
1619
  }
1746
- async function exec_gh_command_with_stdin(input) {
1747
- await check_gh_installed();
1748
- const options = { input: input.stdin_body, ...to_spawn_options(input.timeout_ms, input.cwd) };
1749
- try {
1750
- const { stdout } = await execa2("gh", input.args, options);
1751
- return stdout.trimEnd();
1752
- } catch (error) {
1753
- throw to_gh_error(error);
1754
- }
1620
+ function takes_the_cut(command) {
1621
+ return invokes_josh(command, CUT_COMMANDS, CUT_MODE_FLAG);
1755
1622
  }
1756
- var STATUS_LINE_PATTERN = /^HTTP\/[\d.]+ (?<status>\d{3})\b/u;
1757
- function parse_status_line(output) {
1758
- const { status } = STATUS_LINE_PATTERN.exec(output)?.groups ?? {};
1759
- return status === void 0 ? void 0 : Number(status);
1623
+ function claims_the_hold(command) {
1624
+ return invokes_josh(command, HOLD_COMMANDS, HOLD_MODE_FLAG);
1760
1625
  }
1761
- function status_of_failure(error) {
1762
- return has_stdout_field(error) ? parse_status_line(error.stdout) : void 0;
1626
+ function asks_about_the_cut(command) {
1627
+ return invokes_josh(command, CUT_COMMANDS);
1763
1628
  }
1764
- async function exec_gh_api_status(path, timeout_ms) {
1765
- const options = to_spawn_options(timeout_ms);
1766
- try {
1767
- await check_gh_installed();
1768
- const { stdout } = await execa2("gh", ["api", "--include", "--silent", path], options);
1769
- return parse_status_line(stdout);
1770
- } catch (error) {
1771
- return status_of_failure(error);
1772
- }
1629
+ function current_state2() {
1630
+ return {
1631
+ directory: process.cwd(),
1632
+ carried: run_cut.carried_cut_sync,
1633
+ marked_issue: lane_child_marker.marked_issue(),
1634
+ is_reviewer: agent_session_role.is_reviewer(),
1635
+ context_verdict: cost_cli.session_verdict
1636
+ };
1773
1637
  }
1774
- function exec_gh_api_status_sync(path, timeout_ms) {
1775
- const options = to_spawn_options(timeout_ms);
1776
- try {
1777
- const { stdout } = execaSync("gh", ["api", "--include", "--silent", path], options);
1778
- return parse_status_line(stdout);
1779
- } catch (error) {
1780
- return status_of_failure(error);
1781
- }
1638
+ function dispatched_issue(state) {
1639
+ return state.is_reviewer ? void 0 : state.marked_issue;
1640
+ }
1641
+ function uncut_lane_issue(state) {
1642
+ const issue = lane_paths.lane_issue_of(state.directory);
1643
+ if (issue === void 0 || dispatched_issue(state) !== issue) return void 0;
1644
+ return state.carried()?.issue === issue ? void 0 : issue;
1645
+ }
1646
+ function warrants_the_cut(verdict) {
1647
+ return verdict !== cost_verdict.UNDER_VERDICT;
1648
+ }
1649
+ function is_uncut_gate(command, state = current_state2()) {
1650
+ if (!runs_the_gate(command) || uncut_lane_issue(state) === void 0) return false;
1651
+ return warrants_the_cut(state.context_verdict());
1652
+ }
1653
+ var PRE_GATE_CUT_REASON = "\u26D4 pre-gate cut: this checkout is a lane dispatched for this issue and the gate is the boundary to cut at. Issue `pnpm josh run:cut <N>`: on `cut`, end the turn immediately \u2014 no Telegram is owed; on any other verdict (`not-a-lane`, `busy`, \u2026), reissue the gate \u2014 this fires once per run (`.claude/skills/workflow-commands/pre-gate-cut.md`).";
1654
+ function reaches_the_pre_gate_boundary(call, _turn, run2) {
1655
+ if (!bash_triggers.on_bash_command(asks_about_the_cut)(call)) return false;
1656
+ return run2.some((issued) => bash_triggers.on_bash_command(claims_the_hold)(issued));
1657
+ }
1658
+ var pre_gate_cut = {
1659
+ PRE_GATE_CUT_REASON,
1660
+ asks_about_the_cut,
1661
+ claims_the_hold,
1662
+ is_uncut_gate,
1663
+ reaches_the_pre_gate_boundary,
1664
+ runs_the_gate,
1665
+ takes_the_cut,
1666
+ uncut_lane_issue
1667
+ };
1668
+
1669
+ // scripts/discovery/repo-party.ts
1670
+ var FIRST_PARTY = "first-party";
1671
+ var THIRD_PARTY = "third-party";
1672
+ var UNKNOWN = "unknown";
1673
+ var GH_REPO_ENV_KEY = "GH_REPO";
1674
+ var GH_REPO_PATH_SEGMENTS = 2;
1675
+ function classify3(session_owner, target) {
1676
+ if (session_owner === void 0 || target === void 0) return UNKNOWN;
1677
+ return session_owner.toLowerCase() === target.toLowerCase() ? FIRST_PARTY : THIRD_PARTY;
1782
1678
  }
1783
- var METHOD_FLAG = "--method";
1784
- var INPUT_FLAG = "--input";
1785
- var PAGINATE_FLAG = "--paginate";
1786
- var SLURP_FLAG = "--slurp";
1787
- var JQ_FLAG = "--jq";
1788
- function optional_flag(flag, value) {
1789
- return value === void 0 ? [] : [flag, value];
1790
- }
1791
- function to_gh_api_args(request) {
1792
- const body_args = request.body === void 0 ? [] : [INPUT_FLAG, BODY_FROM_STDIN];
1793
- const paginate_args = request.should_paginate === true ? [PAGINATE_FLAG] : [];
1794
- const slurp_args = request.should_slurp === true ? [SLURP_FLAG] : [];
1795
- return [
1796
- "api",
1797
- request.path,
1798
- ...optional_flag(METHOD_FLAG, request.method),
1799
- ...body_args,
1800
- ...paginate_args,
1801
- ...slurp_args,
1802
- ...optional_flag(JQ_FLAG, request.jq_filter)
1803
- ];
1679
+ function target_owner(owner_repo) {
1680
+ return repo_origin.parse_origin_url(`https://${repo_origin.GITHUB_HOST}/${owner_repo}`)?.owner;
1804
1681
  }
1805
- async function exec_gh_api(request) {
1806
- const args = to_gh_api_args(request);
1807
- if (request.body === void 0) {
1808
- return await exec_gh_command(args, request.timeout_ms, request.cwd);
1809
- }
1810
- return await exec_gh_command_with_stdin({
1811
- args,
1812
- stdin_body: request.body,
1813
- timeout_ms: request.timeout_ms,
1814
- cwd: request.cwd
1815
- });
1682
+ function current_owner(repository_path = process.cwd()) {
1683
+ return repo_discovery.resolve_current_owner(repository_path);
1816
1684
  }
1817
- function exec_gh_api_sync(request) {
1818
- const body_option = request.body === void 0 ? {} : { input: request.body };
1819
- const options = { ...body_option, ...to_spawn_options(request.timeout_ms, request.cwd) };
1820
- try {
1821
- const { stdout } = execaSync("gh", to_gh_api_args(request), options);
1822
- return stdout.trimEnd();
1823
- } catch (error) {
1824
- throw to_gh_error(error);
1825
- }
1685
+ function gh_repo_owners(gh_repo) {
1686
+ return [target_owner(gh_repo.split("/").slice(-GH_REPO_PATH_SEGMENTS).join("/"))];
1826
1687
  }
1827
- function read_gh_api_sync(request) {
1828
- try {
1829
- return exec_gh_api_sync(request);
1830
- } catch {
1831
- return void 0;
1832
- }
1688
+ function remote_owners(repository_path) {
1689
+ return repo_discovery.read_remote_urls(repository_path).map((url) => repo_origin.parse_origin_url(url)?.owner);
1690
+ }
1691
+ function placeholder_owners(repository_path = process.cwd(), environment = process.env) {
1692
+ const gh_repo = environment[GH_REPO_ENV_KEY];
1693
+ return gh_repo === void 0 || gh_repo === "" ? remote_owners(repository_path) : gh_repo_owners(gh_repo);
1833
1694
  }
1834
- var git_gh_exec = {
1835
- direct_environment,
1836
- exec_gh_command,
1837
- exec_gh_command_with_stdin,
1838
- exec_gh_api,
1839
- exec_gh_api_sync,
1840
- read_gh_api_sync,
1841
- exec_gh_api_status,
1842
- exec_gh_api_status_sync,
1843
- parse_status_line
1695
+ var repo_party = {
1696
+ FIRST_PARTY,
1697
+ THIRD_PARTY,
1698
+ UNKNOWN,
1699
+ classify: classify3,
1700
+ current_owner,
1701
+ placeholder_owners,
1702
+ target_owner
1844
1703
  };
1845
1704
 
1846
- // scripts/gh/git-gh-helpers.ts
1847
- function parse_pr_state_string(result) {
1848
- const trimmed = result.trim();
1849
- return trimmed.length > 0 ? trimmed : void 0;
1850
- }
1851
- function is_pr_already_exists_message(error_message) {
1852
- return error_message.toLowerCase().includes("already exists");
1853
- }
1854
- function get_error_message_with_stderr(error) {
1855
- if (!(error instanceof Error)) return String(error);
1856
- if (has_stderr_field(error) && error.stderr.length > 0) return `${error.message}
1857
- ${error.stderr}`;
1858
- return error.message;
1859
- }
1860
- function handle_pr_create_error(error) {
1861
- const error_message = get_error_message_with_stderr(error);
1862
- if (is_pr_already_exists_message(error_message)) {
1863
- throw new Error("PR_ALREADY_EXISTS");
1705
+ // scripts/gh/git-gh-repo.ts
1706
+ async function repo_get_name_with_owner() {
1707
+ try {
1708
+ const result = await git_gh_exec.exec_gh_api({
1709
+ path: git_gh_api_path.repo_api_path(),
1710
+ jq_filter: ".full_name"
1711
+ });
1712
+ return git_gh_helpers.parse_pr_state_string(result);
1713
+ } catch {
1714
+ return void 0;
1864
1715
  }
1865
- throw error;
1866
1716
  }
1867
- var git_gh_helpers = {
1868
- parse_pr_state_string,
1869
- get_error_message_with_stderr,
1870
- handle_pr_create_error
1717
+ var git_gh_repo = {
1718
+ repo_get_name_with_owner
1871
1719
  };
1872
1720
 
1873
1721
  // scripts/gh/git-gh-issue-rest.ts
1874
- import { z as z6 } from "zod";
1875
-
1876
- // scripts/gh/git-gh-rest-state.ts
1877
- var MERGED_STATE = "MERGED";
1878
- function to_gh_state(state) {
1879
- return state?.toUpperCase();
1880
- }
1881
-
1882
- // scripts/gh/git-gh-issue-rest.ts
1883
- var rest_issue_schema = z6.looseObject({
1884
- number: z6.number(),
1885
- issue_dependencies_summary: z6.looseObject({ total_blocked_by: z6.number().optional() }).nullish(),
1722
+ import { z as z5 } from "zod";
1723
+ var rest_issue_schema = z5.looseObject({
1724
+ number: z5.number(),
1725
+ issue_dependencies_summary: z5.looseObject({ total_blocked_by: z5.number().optional() }).nullish(),
1886
1726
  // Present only on a pull request, which this endpoint serves as readily as an issue.
1887
- pull_request: z6.looseObject({ merged_at: z6.string().nullish() }).nullish()
1727
+ pull_request: z5.looseObject({ merged_at: z5.string().nullish() }).nullish()
1888
1728
  });
1889
1729
  var REPOSITORY_URL = /\/repos\/([\w.-]+\/[\w.-]+)$/u;
1890
1730
  var REPOSITORY_URL_GROUP = 1;
@@ -1898,6 +1738,7 @@ var REST_FIELD_NAMES = /* @__PURE__ */ new Map([
1898
1738
  ["url", "html_url"],
1899
1739
  ["createdAt", "created_at"],
1900
1740
  ["closedAt", "closed_at"],
1741
+ ["stateReason", "state_reason"],
1901
1742
  ["updatedAt", "updated_at"]
1902
1743
  ]);
1903
1744
  var NOT_AN_ISSUE_MESSAGE = "gh api answered something other than an issue object";
@@ -2046,23 +1887,23 @@ function to_read_failure(error) {
2046
1887
  }
2047
1888
  async function issue_view_json_classified(issue_number, fields, repo) {
2048
1889
  try {
2049
- const issue2 = await read_issue_fields(issue_number, fields, repo);
2050
- return { kind: "read", json: JSON.stringify(issue2) };
1890
+ const issue = await read_issue_fields(issue_number, fields, repo);
1891
+ return { kind: "read", json: JSON.stringify(issue) };
2051
1892
  } catch (error) {
2052
1893
  return to_read_failure(error);
2053
1894
  }
2054
1895
  }
2055
1896
  async function issue_view_field_classified(issue_number, field, repo) {
2056
1897
  try {
2057
- const issue2 = await read_issue_fields(issue_number, field, repo);
2058
- return { kind: "read", text: git_gh_issue_rest.to_field_text(issue2[field]) };
1898
+ const issue = await read_issue_fields(issue_number, field, repo);
1899
+ return { kind: "read", text: git_gh_issue_rest.to_field_text(issue[field]) };
2059
1900
  } catch (error) {
2060
1901
  return to_read_failure(error);
2061
1902
  }
2062
1903
  }
2063
1904
  async function issue_view_field(issue_number, field, repo) {
2064
- const read = await issue_view_field_classified(issue_number, field, repo);
2065
- return read.kind === "read" ? read.text : void 0;
1905
+ const read2 = await issue_view_field_classified(issue_number, field, repo);
1906
+ return read2.kind === "read" ? read2.text : void 0;
2066
1907
  }
2067
1908
  async function issue_get_title(issue_number, repo) {
2068
1909
  const result = await issue_view_field(issue_number, "title", repo);
@@ -2075,8 +1916,8 @@ async function issue_get_body_classified(issue_number, repo) {
2075
1916
  return await issue_view_field_classified(issue_number, "body", repo);
2076
1917
  }
2077
1918
  async function issue_view_json(issue_number, fields, repo) {
2078
- const read = await issue_view_json_classified(issue_number, fields, repo);
2079
- return read.kind === "read" ? read.json : void 0;
1919
+ const read2 = await issue_view_json_classified(issue_number, fields, repo);
1920
+ return read2.kind === "read" ? read2.json : void 0;
2080
1921
  }
2081
1922
  var STATE_AND_RELATIONS_FIELDS = "number,state,labels,blockedBy";
2082
1923
  async function issue_get_state_and_relations(issue_number, repo) {
@@ -2099,9 +1940,9 @@ async function issue_get_labels_and_body(issue_number) {
2099
1940
  return await issue_view_json(issue_number, "number,state,labels,body");
2100
1941
  }
2101
1942
  async function issue_list_comments(issue_number, timeout_ms) {
2102
- const path = `${git_gh_api_path.issue_comments_api_path(issue_number)}${git_gh_api_path.FULL_PAGE_QUERY}`;
1943
+ const path4 = `${git_gh_api_path.issue_comments_api_path(issue_number)}${git_gh_api_path.FULL_PAGE_QUERY}`;
2103
1944
  try {
2104
- return await git_gh_exec.exec_gh_api({ path, should_paginate: true, timeout_ms });
1945
+ return await git_gh_exec.exec_gh_api({ path: path4, should_paginate: true, timeout_ms });
2105
1946
  } catch {
2106
1947
  return void 0;
2107
1948
  }
@@ -2176,8 +2017,8 @@ function is_selected(rest, request) {
2176
2017
  return !git_gh_issue_rest.is_pull_request(rest) && matches_body(rest, request.body_term);
2177
2018
  }
2178
2019
  async function fetch_page(request, page) {
2179
- const path = listing_path(request, page);
2180
- const rows = git_gh_issue_rest.parse_rest_issues(await git_gh_exec.exec_gh_api({ path }));
2020
+ const path4 = listing_path(request, page);
2021
+ const rows = git_gh_issue_rest.parse_rest_issues(await git_gh_exec.exec_gh_api({ path: path4 }));
2181
2022
  return {
2182
2023
  selected: rows.filter((row) => is_selected(row, request)),
2183
2024
  is_full: rows.length >= PER_PAGE
@@ -2229,7 +2070,7 @@ var git_gh_issue_list = {
2229
2070
  };
2230
2071
 
2231
2072
  // scripts/issue/issue-watch-diff.ts
2232
- import { z as z7 } from "zod";
2073
+ import { z as z6 } from "zod";
2233
2074
  var RUN_MARKER = "<!-- josh:run -->";
2234
2075
  var BOT_TYPE = "Bot";
2235
2076
  var BOT_SUFFIX = "[bot]";
@@ -2244,11 +2085,11 @@ var AT = " at ";
2244
2085
  var SECTION_SEPARATOR = "\n\n";
2245
2086
  var LINE_SEPARATOR = "\n";
2246
2087
  var CRLF = "\r\n";
2247
- var comment_schema = z7.looseObject({
2248
- id: z7.number(),
2249
- user: z7.looseObject({ login: z7.string(), type: z7.string().optional() }).nullish(),
2250
- created_at: z7.string().optional(),
2251
- body: z7.string().nullish()
2088
+ var comment_schema = z6.looseObject({
2089
+ id: z6.number(),
2090
+ user: z6.looseObject({ login: z6.string(), type: z6.string().optional() }).nullish(),
2091
+ created_at: z6.string().optional(),
2092
+ body: z6.string().nullish()
2252
2093
  });
2253
2094
  function is_bot(user) {
2254
2095
  return user?.type === BOT_TYPE || (user?.login.endsWith(BOT_SUFFIX) ?? false);
@@ -2320,6 +2161,7 @@ var LABEL_NAMES_FILTER = ".[].name";
2320
2161
  var LABELS_SEGMENT = "/labels";
2321
2162
  var COMMENTS_SEGMENT = "/comments";
2322
2163
  var CLOSED_STATE = "closed";
2164
+ var NOT_PLANNED_REASON = "not_planned";
2323
2165
  var COLOR_HASH = "#";
2324
2166
  var UNPROCESSABLE_STATUS = 422;
2325
2167
  var ALREADY_EXISTS_CODE = "already_exists";
@@ -2352,16 +2194,25 @@ ${issue_watch_diff.RUN_MARKER}` }),
2352
2194
  async function issue_try_comment(issue_number, body) {
2353
2195
  return await did_write_succeed(async () => await issue_comment(issue_number, body));
2354
2196
  }
2355
- async function issue_close(issue_number, comment) {
2197
+ async function close_with(issue_number, comment, state) {
2356
2198
  return await did_write_succeed(async () => {
2357
2199
  if (comment !== void 0) await issue_comment(issue_number, comment);
2358
2200
  await git_gh_exec.exec_gh_api({
2359
2201
  path: git_gh_api_path.issue_api_path(issue_number),
2360
2202
  method: PATCH_METHOD,
2361
- body: JSON.stringify({ state: CLOSED_STATE })
2203
+ body: JSON.stringify(state)
2362
2204
  });
2363
2205
  });
2364
2206
  }
2207
+ async function issue_close(issue_number, comment) {
2208
+ return await close_with(issue_number, comment, { state: CLOSED_STATE });
2209
+ }
2210
+ async function issue_close_not_planned(issue_number, comment) {
2211
+ return await close_with(issue_number, comment, {
2212
+ state: CLOSED_STATE,
2213
+ state_reason: NOT_PLANNED_REASON
2214
+ });
2215
+ }
2365
2216
  function to_label_color(color) {
2366
2217
  return color.startsWith(COLOR_HASH) ? color.slice(COLOR_HASH.length) : color;
2367
2218
  }
@@ -2474,6 +2325,7 @@ var git_gh_issue_write = {
2474
2325
  issue_comment,
2475
2326
  issue_try_comment,
2476
2327
  issue_close,
2328
+ issue_close_not_planned,
2477
2329
  label_ensure,
2478
2330
  issue_create_request,
2479
2331
  issue_create_with_label,
@@ -2543,20 +2395,20 @@ var git_gh_issue = {
2543
2395
  };
2544
2396
 
2545
2397
  // scripts/ci/pr-classification.ts
2546
- import { readFileSync as readFileSync2 } from "node:fs";
2547
- import { fileURLToPath } from "node:url";
2548
- import { z as z8 } from "zod";
2398
+ import { readFileSync as readFileSync3 } from "node:fs";
2399
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
2400
+ import { z as z7 } from "zod";
2549
2401
  var CLASSIFICATION_SET = new Set(RELEASE_CLASSIFICATION_NAMES);
2550
2402
  var ISSUE_BUG_LABEL = "bug";
2551
2403
  var DECLARATION_PREFIX = "- \u30EA\u30EA\u30FC\u30B9\u5206\u985E: ";
2552
2404
  var DECLARATION = new RegExp(`^${DECLARATION_PREFIX}(.+)$`, "gmu");
2553
2405
  var LEGACY_LABELS = /* @__PURE__ */ new Set(["semver-major", "semver-minor"]);
2554
- var LABEL = z8.object({ name: z8.string() });
2555
- var USER = z8.object({ login: z8.string() });
2556
- var PULL_REQUEST = z8.object({ number: z8.number(), user: USER });
2557
- var EVENT = z8.object({
2406
+ var LABEL = z7.object({ name: z7.string() });
2407
+ var USER = z7.object({ login: z7.string() });
2408
+ var PULL_REQUEST = z7.object({ number: z7.number(), user: USER });
2409
+ var EVENT = z7.object({
2558
2410
  pull_request: PULL_REQUEST,
2559
- repository: z8.object({ full_name: z8.string() })
2411
+ repository: z7.object({ full_name: z7.string() })
2560
2412
  });
2561
2413
  function classification_error(labels, author) {
2562
2414
  const legacy = labels.filter((label) => LEGACY_LABELS.has(label.toLowerCase()));
@@ -2579,9 +2431,9 @@ function release_candidates(candidates) {
2579
2431
  return candidates.filter((candidate) => candidate !== ENHANCEMENT_LABEL);
2580
2432
  }
2581
2433
  function issue_candidates(issue_json) {
2582
- const issue2 = z8.object({ labels: z8.array(LABEL), body: z8.string().nullable() }).parse(JSON.parse(issue_json));
2583
- const names = issue2.labels.map((label) => label.name.toLowerCase());
2584
- const declared = [...(issue2.body ?? "").matchAll(DECLARATION)].map((match) => match[1] ?? "");
2434
+ const issue = z7.object({ labels: z7.array(LABEL), body: z7.string().nullable() }).parse(JSON.parse(issue_json));
2435
+ const names = issue.labels.map((label) => label.name.toLowerCase());
2436
+ const declared = [...(issue.body ?? "").matchAll(DECLARATION)].map((match) => match[1] ?? "");
2585
2437
  const candidates = [...release_candidates([...names, ...declared].filter(is_classification))];
2586
2438
  const unknown = declared.filter((value) => !is_classification(value));
2587
2439
  if (unknown.length > 0) throw new Error(`Unknown release classification: ${unknown.join(", ")}`);
@@ -2602,9 +2454,9 @@ function select_issue_classification(issue_json) {
2602
2454
  return label;
2603
2455
  }
2604
2456
  function fetch_current_labels(repository, pull_number) {
2605
- const path = `repos/${repository}/issues/${String(pull_number)}/labels`;
2457
+ const path4 = `repos/${repository}/issues/${String(pull_number)}/labels`;
2606
2458
  try {
2607
- const names = git_gh_exec.exec_gh_api_sync({ path, jq_filter: ".[].name" });
2459
+ const names = git_gh_exec.exec_gh_api_sync({ path: path4, jq_filter: ".[].name" });
2608
2460
  return names.split("\n").filter((name) => name !== "");
2609
2461
  } catch (error) {
2610
2462
  const detail = error_text.message_of(error);
@@ -2612,11 +2464,11 @@ function fetch_current_labels(repository, pull_number) {
2612
2464
  }
2613
2465
  }
2614
2466
  function check_event(event_path, read_labels = fetch_current_labels) {
2615
- const event = EVENT.parse(JSON.parse(readFileSync2(event_path, "utf8")));
2467
+ const event = EVENT.parse(JSON.parse(readFileSync3(event_path, "utf8")));
2616
2468
  const labels = read_labels(event.repository.full_name, event.pull_request.number);
2617
2469
  return classification_error(labels, event.pull_request.user.login);
2618
2470
  }
2619
- if (process.argv[1] === fileURLToPath(import.meta.url)) {
2471
+ if (process.argv[1] === fileURLToPath2(import.meta.url)) {
2620
2472
  const event_path = process.env["GITHUB_EVENT_PATH"];
2621
2473
  if (!event_path) throw new Error("GITHUB_EVENT_PATH is required");
2622
2474
  const error = check_event(event_path);
@@ -2636,8 +2488,8 @@ var pr_classification = {
2636
2488
 
2637
2489
  // scripts/lib/poll.ts
2638
2490
  async function sleep2(duration_ms) {
2639
- await new Promise((resolve) => {
2640
- setTimeout(resolve, duration_ms);
2491
+ await new Promise((resolve2) => {
2492
+ setTimeout(resolve2, duration_ms);
2641
2493
  });
2642
2494
  }
2643
2495
  async function wait_between(wait, interval_ms, attempt, attempts) {
@@ -2654,256 +2506,17 @@ async function poll_until(is_done, options) {
2654
2506
  var poll = { poll_until, sleep: sleep2 };
2655
2507
 
2656
2508
  // scripts/gh/git-gh-pr.ts
2657
- import { z as z12 } from "zod";
2658
-
2659
- // scripts/gh/git-gh-pr-rest.ts
2660
- import { z as z9 } from "zod";
2661
- var rest_repo_schema = z9.looseObject({ full_name: z9.string().optional() }).nullish();
2662
- var rest_pull_side_schema = z9.looseObject({ repo: rest_repo_schema });
2663
- var rest_pull_schema = z9.looseObject({
2664
- number: z9.number(),
2665
- html_url: z9.string().optional(),
2666
- body: z9.string().nullish(),
2667
- state: z9.string().optional(),
2668
- merged: z9.boolean().nullish(),
2669
- merged_at: z9.string().nullish(),
2670
- mergeable: z9.boolean().nullish(),
2671
- mergeable_state: z9.string().optional(),
2672
- // `sha` is the head commit, which is what both halves of the merge-gate rollup are keyed by —
2673
- // REST hangs the check runs and the status contexts off the commit rather than off the pull
2674
- // request.
2675
- head: z9.looseObject({ ref: z9.string().optional(), sha: z9.string().optional(), repo: rest_repo_schema }).nullish(),
2676
- base: rest_pull_side_schema.nullish(),
2677
- // `node_id` is what the GraphQL auto-merge mutation addresses a pull request by, and `auto_merge`
2678
- // is `null` until auto-merge is enabled — both read by `git-gh-pr-auto-merge.ts`.
2679
- node_id: z9.string().optional(),
2680
- auto_merge: z9.looseObject({}).nullish()
2681
- });
2682
- var NOT_A_PULL_MESSAGE = "gh api answered something other than a pull request object";
2683
- var NOT_A_PULL_LISTING_MESSAGE = "gh api answered something other than a pull request listing";
2684
- var NOT_A_COMMENT_LISTING_MESSAGE = "gh api answered something other than a comment listing";
2685
- var OPEN_STATE = "open";
2686
- var EMPTY_BODY2 = "";
2687
- function parse_rest_pull(rest_json) {
2688
- const parsed = parse_json_object_or_undefined(rest_json, rest_pull_schema);
2689
- if (parsed === void 0) throw new Error(NOT_A_PULL_MESSAGE);
2690
- return parsed;
2691
- }
2692
- function parse_rest_pulls(rest_json) {
2693
- const parsed = parse_json_array_or_undefined(rest_json, rest_pull_schema);
2694
- if (parsed === void 0) throw new Error(NOT_A_PULL_LISTING_MESSAGE);
2695
- return parsed;
2696
- }
2697
- function select_pull(pulls) {
2698
- return pulls.find((pull) => pull.state === OPEN_STATE) ?? pulls[0];
2699
- }
2700
- function is_merged(pull) {
2701
- return pull.merged === true || typeof pull.merged_at === "string";
2702
- }
2703
- function to_pr_state(pull) {
2704
- return is_merged(pull) ? MERGED_STATE : to_gh_state(pull.state);
2705
- }
2706
- function to_repo_name(side) {
2707
- return side?.repo?.full_name;
2708
- }
2709
- function is_same_repository_head(pull) {
2710
- const head_repo = to_repo_name(pull.head);
2711
- return head_repo !== void 0 && head_repo === to_repo_name(pull.base);
2712
- }
2713
- function to_pr_info(pull) {
2714
- return {
2715
- mergeable: pull.mergeable,
2716
- mergeStateStatus: to_gh_state(pull.mergeable_state),
2717
- state: to_pr_state(pull)
2718
- };
2719
- }
2720
- function to_pr_comments(rest_json) {
2721
- const parsed = parse_json_array_or_undefined(rest_json, rest_comment_schema);
2722
- if (parsed === void 0) throw new Error(NOT_A_COMMENT_LISTING_MESSAGE);
2723
- return parsed.map((comment) => ({
2724
- body: comment.body ?? EMPTY_BODY2,
2725
- url: comment.html_url,
2726
- author: { login: comment.user?.login }
2727
- }));
2728
- }
2729
- var git_gh_pr_rest = {
2730
- parse_rest_pull,
2731
- parse_rest_pulls,
2732
- select_pull,
2733
- is_same_repository_head,
2734
- is_merged,
2735
- to_pr_state,
2736
- to_pr_info,
2737
- to_pr_comments
2738
- };
2739
-
2740
- // scripts/gh/git-gh-pr-read.ts
2741
- var pr_number_by_branch = /* @__PURE__ */ new Map();
2742
- var LOOKUP_QUERY = "state=all&sort=created&direction=desc&per_page=100";
2743
- var COMMENTS_QUERY = FULL_PAGE_QUERY;
2744
- var OWNER_PLACEHOLDER = "{owner}";
2745
- var NO_PULL_REQUEST_MESSAGE = "gh api found no pull request for branch";
2746
- var UNREADABLE_PULL_REQUEST_MESSAGE = "gh api could not read the pull requests for branch";
2747
- function lookup_path(branch_name) {
2748
- const head = `${OWNER_PLACEHOLDER}:${encodeURIComponent(branch_name)}`;
2749
- return `${git_gh_api_path.pulls_api_path()}?head=${head}&${LOOKUP_QUERY}`;
2750
- }
2751
- async function fetch_pr_number(branch_name) {
2752
- const json = await git_gh_exec.exec_gh_api({ path: lookup_path(branch_name) });
2753
- return git_gh_pr_rest.select_pull(git_gh_pr_rest.parse_rest_pulls(json))?.number;
2754
- }
2755
- var pending_pr_number_by_branch = /* @__PURE__ */ new Map();
2756
- var pull_by_number = /* @__PURE__ */ new Map();
2757
- async function fetch_pr_number_read(branch_name) {
2758
- try {
2759
- const pr_number = await fetch_pr_number(branch_name);
2760
- if (pr_number === void 0) return { kind: "missing" };
2761
- pr_number_by_branch.set(branch_name, pr_number);
2762
- return { kind: "read", pr_number };
2763
- } catch (error) {
2764
- return { kind: "unreadable", cause: error };
2765
- }
2766
- }
2767
- async function start_pr_number_read(branch_name) {
2768
- const pending = pending_pr_number_by_branch.get(branch_name);
2769
- if (pending !== void 0) return await pending;
2770
- const lookup = fetch_pr_number_read(branch_name);
2771
- pending_pr_number_by_branch.set(branch_name, lookup);
2772
- try {
2773
- return await lookup;
2774
- } finally {
2775
- pending_pr_number_by_branch.delete(branch_name);
2776
- }
2777
- }
2778
- function forget_pr_numbers() {
2779
- pr_number_by_branch.clear();
2780
- pending_pr_number_by_branch.clear();
2781
- pull_by_number.clear();
2782
- }
2783
- async function read_pr_number(branch_name) {
2784
- const cached = pr_number_by_branch.get(branch_name);
2785
- if (cached !== void 0) return { kind: "read", pr_number: cached };
2786
- return await start_pr_number_read(branch_name);
2787
- }
2788
- async function resolve_pr_number(branch_name) {
2789
- const read = await read_pr_number(branch_name);
2790
- return read.kind === "read" ? read.pr_number : void 0;
2791
- }
2792
- function to_unreadable_error(branch_name, cause) {
2793
- return new Error(`${UNREADABLE_PULL_REQUEST_MESSAGE}: ${branch_name}`, { cause });
2794
- }
2795
- async function require_pr_number(branch_name) {
2796
- const read = await read_pr_number(branch_name);
2797
- if (read.kind === "read") return read.pr_number;
2798
- if (read.kind === "missing") throw new Error(`${NO_PULL_REQUEST_MESSAGE}: ${branch_name}`);
2799
- throw to_unreadable_error(branch_name, read.cause);
2800
- }
2801
- async function read_pull(pr_number) {
2802
- const json = await git_gh_exec.exec_gh_api({
2803
- path: git_gh_api_path.pull_api_path(String(pr_number))
2804
- });
2805
- return git_gh_pr_rest.parse_rest_pull(json);
2806
- }
2807
- async function read_remembered_pull(pr_number) {
2808
- const pending = pull_by_number.get(pr_number) ?? read_pull(pr_number);
2809
- pull_by_number.set(pr_number, pending);
2810
- try {
2811
- return await pending;
2812
- } catch (error) {
2813
- if (pull_by_number.get(pr_number) === pending) pull_by_number.delete(pr_number);
2814
- throw error;
2815
- }
2816
- }
2817
- async function read_pull_of_branch(branch_name, read = read_remembered_pull) {
2818
- const number_read = await read_pr_number(branch_name);
2819
- if (number_read.kind !== "read") return number_read;
2820
- try {
2821
- return { kind: "read", pull: await read(number_read.pr_number) };
2822
- } catch (error) {
2823
- return { kind: "unreadable", cause: error };
2824
- }
2825
- }
2826
- async function read_pull_or_undefined(branch_name) {
2827
- const read = await read_pull_of_branch(branch_name);
2828
- return read.kind === "read" ? read.pull : void 0;
2829
- }
2830
- async function pr_exists(branch_name) {
2831
- const read = await read_pr_number(branch_name);
2832
- if (read.kind === "unreadable") throw to_unreadable_error(branch_name, read.cause);
2833
- return read.kind === "read";
2834
- }
2835
- async function pr_get_number(branch_name) {
2836
- return await resolve_pr_number(branch_name);
2837
- }
2838
- async function pr_get_url(branch_name) {
2839
- const pull = await read_pull_or_undefined(branch_name);
2840
- if (pull?.html_url === void 0) return void 0;
2841
- return git_gh_helpers.parse_pr_state_string(pull.html_url);
2842
- }
2843
- async function pr_get_merge_state(branch_name) {
2844
- const read = await read_pull_of_branch(branch_name, read_pull);
2845
- if (read.kind !== "read") return void 0;
2846
- const { pull } = read;
2847
- return {
2848
- is_merged: git_gh_pr_rest.is_merged(pull),
2849
- merged_at: pull.merged_at ?? void 0,
2850
- head_sha: pull.head?.sha,
2851
- merge_state_status: to_gh_state(pull.mergeable_state)
2852
- };
2853
- }
2854
- async function pr_get_body(branch_name) {
2855
- const pull = await read_pull_or_undefined(branch_name);
2856
- const body = pull?.body;
2857
- return typeof body === "string" && body.length > 0 ? body : void 0;
2858
- }
2859
- async function pr_view(branch_name) {
2860
- const read = await read_pull_of_branch(branch_name, read_pull);
2861
- if (read.kind === "unreadable") throw to_unreadable_error(branch_name, read.cause);
2862
- if (read.kind === "missing") return "";
2863
- return JSON.stringify(git_gh_pr_rest.to_pr_info(read.pull));
2864
- }
2865
- async function read_comments(branch_name, to_path, to_json) {
2866
- const pr_number = await resolve_pr_number(branch_name);
2867
- if (pr_number === void 0) return void 0;
2868
- const path = `${to_path(String(pr_number))}${COMMENTS_QUERY}`;
2869
- try {
2870
- return to_json(await git_gh_exec.exec_gh_api({ path, should_paginate: true }));
2871
- } catch {
2872
- return void 0;
2873
- }
2874
- }
2875
- function to_comments_json(raw) {
2876
- return JSON.stringify(git_gh_pr_rest.to_pr_comments(raw));
2877
- }
2878
- function as_served(raw) {
2879
- return raw;
2880
- }
2881
- async function pr_get_comments(branch_name) {
2882
- return await read_comments(branch_name, git_gh_api_path.issue_comments_api_path, to_comments_json);
2883
- }
2884
- async function pr_get_review_comments(branch_name) {
2885
- return await read_comments(branch_name, git_gh_api_path.pull_comments_api_path, as_served);
2886
- }
2887
- var git_gh_pr_read = {
2888
- pr_exists,
2889
- pr_get_number,
2890
- pr_get_url,
2891
- pr_get_body,
2892
- pr_get_merge_state,
2893
- pr_view,
2894
- pr_get_comments,
2895
- pr_get_review_comments
2896
- };
2509
+ import { z as z10 } from "zod";
2897
2510
 
2898
2511
  // scripts/gh/git-gh-pr-review.ts
2899
- import { z as z10 } from "zod";
2512
+ import { z as z8 } from "zod";
2900
2513
  var REVIEW_APPROVED = "APPROVED";
2901
2514
  var REVIEW_CHANGES_REQUESTED = "CHANGES_REQUESTED";
2902
2515
  var REVIEW_NONE = "";
2903
2516
  var STATE_CHANGING_REVIEWS = /* @__PURE__ */ new Set([REVIEW_APPROVED, REVIEW_CHANGES_REQUESTED]);
2904
- var rest_review_schema = z10.looseObject({
2905
- state: z10.string().optional(),
2906
- user: z10.looseObject({ login: z10.string().optional() }).nullish()
2517
+ var rest_review_schema = z8.looseObject({
2518
+ state: z8.string().optional(),
2519
+ user: z8.looseObject({ login: z8.string().optional() }).nullish()
2907
2520
  });
2908
2521
  var NOT_A_REVIEW_LISTING = "gh api answered something other than a review listing";
2909
2522
  function parse_rest_reviews(reviews_json) {
@@ -2936,18 +2549,18 @@ function to_review_decision(reviews_json) {
2936
2549
  var git_gh_pr_review = { to_review_decision };
2937
2550
 
2938
2551
  // scripts/gh/git-gh-pr-rollup.ts
2939
- import { z as z11 } from "zod";
2552
+ import { z as z9 } from "zod";
2940
2553
  var STATUS_CONTEXT_TYPE_NAME = "StatusContext";
2941
2554
  var TYPE_NAME_KEY = "__typename";
2942
- var rollup_element_schema = z11.looseObject({});
2943
- var check_runs_page_schema = z11.looseObject({
2555
+ var rollup_element_schema = z9.looseObject({});
2556
+ var check_runs_page_schema = z9.looseObject({
2944
2557
  // Required, not optional: GitHub always names the key, and accepting a page without one would
2945
2558
  // answer an empty rollup — which `git-pr-followup.ts` reports as "this branch has no checks".
2946
- check_runs: z11.array(rollup_element_schema)
2559
+ check_runs: z9.array(rollup_element_schema)
2947
2560
  });
2948
- var id_holder_schema = z11.object({ id: z11.number() });
2949
- var status_page_schema = z11.looseObject({
2950
- statuses: z11.array(rollup_element_schema)
2561
+ var id_holder_schema = z9.object({ id: z9.number() });
2562
+ var status_page_schema = z9.looseObject({
2563
+ statuses: z9.array(rollup_element_schema)
2951
2564
  });
2952
2565
  var NOT_A_CHECK_RUNS_LISTING = "gh api answered something other than a check run listing";
2953
2566
  var NOT_A_STATUS_LISTING = "gh api answered something other than a commit status listing";
@@ -2961,15 +2574,15 @@ function read_id(value) {
2961
2574
  const parsed = id_holder_schema.safeParse(value);
2962
2575
  return parsed.success ? parsed.data.id : void 0;
2963
2576
  }
2964
- function check_run_group_key(run) {
2965
- const { name, app } = run;
2577
+ function check_run_group_key(run2) {
2578
+ const { name, app } = run2;
2966
2579
  if (typeof name !== "string") return void 0;
2967
2580
  return JSON.stringify([name, read_id(app)]);
2968
2581
  }
2969
- function read_rank(run) {
2970
- const id = read_id(run);
2582
+ function read_rank(run2) {
2583
+ const id = read_id(run2);
2971
2584
  if (id === void 0) return void 0;
2972
- return { suite: read_id(run["check_suite"]) ?? NO_SUITE, run: id };
2585
+ return { suite: read_id(run2["check_suite"]) ?? NO_SUITE, run: id };
2973
2586
  }
2974
2587
  function is_ranked_above(candidate, current) {
2975
2588
  if (candidate.suite !== current.suite) return candidate.suite > current.suite;
@@ -2979,23 +2592,23 @@ function should_replace(previous, rank) {
2979
2592
  const previous_rank = previous === void 0 ? void 0 : read_rank(previous);
2980
2593
  return previous_rank === void 0 || is_ranked_above(rank, previous_rank);
2981
2594
  }
2982
- function remember_newest_run(run, newest) {
2983
- const key2 = check_run_group_key(run);
2984
- const rank = read_rank(run);
2595
+ function remember_newest_run(run2, newest) {
2596
+ const key2 = check_run_group_key(run2);
2597
+ const rank = read_rank(run2);
2985
2598
  if (key2 === void 0 || rank === void 0) return;
2986
- if (should_replace(newest.get(key2), rank)) newest.set(key2, run);
2599
+ if (should_replace(newest.get(key2), rank)) newest.set(key2, run2);
2987
2600
  }
2988
- function is_newest_run(run, newest) {
2989
- const key2 = check_run_group_key(run);
2990
- if (key2 === void 0 || read_rank(run) === void 0) return true;
2991
- return newest.get(key2) === run;
2601
+ function is_newest_run(run2, newest) {
2602
+ const key2 = check_run_group_key(run2);
2603
+ if (key2 === void 0 || read_rank(run2) === void 0) return true;
2604
+ return newest.get(key2) === run2;
2992
2605
  }
2993
2606
  function to_check_run_items(check_runs_json) {
2994
2607
  const pages = read_pages(check_runs_json, check_runs_page_schema, NOT_A_CHECK_RUNS_LISTING);
2995
2608
  const runs = pages.flatMap((page) => page.check_runs);
2996
2609
  const newest = /* @__PURE__ */ new Map();
2997
- for (const run of runs) remember_newest_run(run, newest);
2998
- return runs.filter((run) => is_newest_run(run, newest));
2610
+ for (const run2 of runs) remember_newest_run(run2, newest);
2611
+ return runs.filter((run2) => is_newest_run(run2, newest));
2999
2612
  }
3000
2613
  function to_status_context_items(status_json) {
3001
2614
  const pages = read_pages(status_json, status_page_schema, NOT_A_STATUS_LISTING);
@@ -3013,16 +2626,16 @@ var git_gh_pr_rollup = {
3013
2626
 
3014
2627
  // scripts/gh/git-gh-pr-snapshot.ts
3015
2628
  var NO_HEAD_SHA_MESSAGE = "gh api answered a pull request with no head commit";
3016
- async function read_object_pages(path) {
2629
+ async function read_object_pages(path4) {
3017
2630
  return await git_gh_exec.exec_gh_api({
3018
- path: `${path}${FULL_PAGE_QUERY}`,
2631
+ path: `${path4}${FULL_PAGE_QUERY}`,
3019
2632
  should_paginate: true,
3020
2633
  should_slurp: true
3021
2634
  });
3022
2635
  }
3023
- async function read_array_pages(path) {
2636
+ async function read_array_pages(path4) {
3024
2637
  return await git_gh_exec.exec_gh_api({
3025
- path: `${path}${FULL_PAGE_QUERY}`,
2638
+ path: `${path4}${FULL_PAGE_QUERY}`,
3026
2639
  should_paginate: true
3027
2640
  });
3028
2641
  }
@@ -3039,8 +2652,8 @@ async function read_status_check_rollup(commit_sha) {
3039
2652
  return git_gh_pr_rollup.to_status_check_rollup({ check_runs_json, status_json });
3040
2653
  }
3041
2654
  async function pr_get_review_decision(pr_number) {
3042
- const path = git_gh_api_path.pull_reviews_api_path(String(pr_number));
3043
- return git_gh_pr_review.to_review_decision(await read_array_pages(path));
2655
+ const path4 = git_gh_api_path.pull_reviews_api_path(String(pr_number));
2656
+ return git_gh_pr_review.to_review_decision(await read_array_pages(path4));
3044
2657
  }
3045
2658
  async function build_checks_fields(pull) {
3046
2659
  return {
@@ -3081,7 +2694,7 @@ var MERGE_READ_BACK_ATTEMPTS = 3;
3081
2694
  var MERGE_READ_BACK_INTERVAL_MS = 1e3;
3082
2695
  var PR_NUMBER_PATTERN = /\/pull\/([1-9]\d*)$/u;
3083
2696
  var LABELS_SEGMENT2 = "/labels";
3084
- var PR_LABELS = z12.array(z12.object({ name: z12.string() }));
2697
+ var PR_LABELS = z10.array(z10.object({ name: z10.string() }));
3085
2698
  async function add_pr_classification(number, label) {
3086
2699
  await git_gh_exec.exec_gh_api({
3087
2700
  path: `${git_gh_api_path.issue_api_path(number)}${LABELS_SEGMENT2}`,
@@ -3163,8 +2776,8 @@ async function sleep_between_read_backs(attempt) {
3163
2776
  }
3164
2777
  async function has_merge_landed(pr_number, merge_error) {
3165
2778
  for (let attempt = 0; attempt < MERGE_READ_BACK_ATTEMPTS; attempt += 1) {
3166
- const is_merged2 = await read_merge_state(pr_number);
3167
- if (is_merged2 !== void 0) return is_merged2;
2779
+ const is_merged = await read_merge_state(pr_number);
2780
+ if (is_merged !== void 0) return is_merged;
3168
2781
  await sleep_between_read_backs(attempt);
3169
2782
  }
3170
2783
  throw new Error(MERGE_UNCONFIRMED_MESSAGE, { cause: merge_error });
@@ -3235,22 +2848,6 @@ var git_gh_pr_auto_merge = {
3235
2848
  pr_list_open_with_head_prefix
3236
2849
  };
3237
2850
 
3238
- // scripts/gh/git-gh-repo.ts
3239
- async function repo_get_name_with_owner() {
3240
- try {
3241
- const result = await git_gh_exec.exec_gh_api({
3242
- path: git_gh_api_path.repo_api_path(),
3243
- jq_filter: ".full_name"
3244
- });
3245
- return git_gh_helpers.parse_pr_state_string(result);
3246
- } catch {
3247
- return void 0;
3248
- }
3249
- }
3250
- var git_gh_repo = {
3251
- repo_get_name_with_owner
3252
- };
3253
-
3254
2851
  // scripts/gh/git-pr-checks.ts
3255
2852
  var SECONDS_TO_MS = 1e3;
3256
2853
  var CHECK_WAIT_INTERVAL_MS = 1e4;
@@ -3325,16 +2922,16 @@ function to_exhaustion_error(last_read_failure) {
3325
2922
  }
3326
2923
  async function attempt_pr_success_poll(input) {
3327
2924
  const evaluator = input.options.evaluator ?? MERGE_GATE_EVALUATOR;
3328
- const read = await read_pr_state(input, evaluator);
3329
- if (read.kind === "unreadable") return await retry_after_unreadable(input, read.cause);
2925
+ const read2 = await read_pr_state(input, evaluator);
2926
+ if (read2.kind === "unreadable") return await retry_after_unreadable(input, read2.cause);
3330
2927
  const classification = classify_poll_result({
3331
- snapshot: read.snapshot,
2928
+ snapshot: read2.snapshot,
3332
2929
  stable_count: input.stable_count,
3333
2930
  required_stable_reads: input.options.required_stable_reads,
3334
2931
  evaluator
3335
2932
  });
3336
2933
  if (classification.is_done) {
3337
- return { snapshot: read.snapshot, next_stable_count: 0, next_failure_count: 0 };
2934
+ return { snapshot: read2.snapshot, next_stable_count: 0, next_failure_count: 0 };
3338
2935
  }
3339
2936
  await sleep_before_next_attempt(input);
3340
2937
  return { next_stable_count: classification.next_stable_count, next_failure_count: 0 };
@@ -3375,20 +2972,20 @@ var PR_CHECKS_WATCH_TIMEOUT_MS = 12e4;
3375
2972
  var WATCH_TIMED_OUT_NOTE = "\u23F1\uFE0F pr checks --watch timed out.";
3376
2973
  var NO_CHECKS_MESSAGE = "gh api reported no checks on the branch";
3377
2974
  var CHECKS_FAILED_MESSAGE = "gh api reported a failing check on the branch";
3378
- function is_awaited_check(check) {
3379
- return !is_coderabbit_check(check.name) || is_required_check(check.name);
2975
+ function is_awaited_check(check2) {
2976
+ return !is_coderabbit_check(check2.name) || is_required_check(check2.name);
3380
2977
  }
3381
2978
  function evaluate_checks_settled(snapshot) {
3382
- const awaited = snapshot.rollup.filter((check) => is_awaited_check(check));
2979
+ const awaited = snapshot.rollup.filter((check2) => is_awaited_check(check2));
3383
2980
  const considered = awaited.length === 0 ? snapshot.rollup : awaited;
3384
- if (considered.length === 0 || considered.some((check) => check.status === CHECK_STATUS_PENDING)) {
2981
+ if (considered.length === 0 || considered.some((check2) => check2.status === CHECK_STATUS_PENDING)) {
3385
2982
  return "pending";
3386
2983
  }
3387
- return snapshot.rollup.some((check) => check.status === CHECK_STATUS_FAIL) ? "failure" : "success";
2984
+ return snapshot.rollup.some((check2) => check2.status === CHECK_STATUS_FAIL) ? "failure" : "success";
3388
2985
  }
3389
2986
  function describe_checks_failure(snapshot) {
3390
- const failed = snapshot.rollup.filter((check) => check.status === CHECK_STATUS_FAIL);
3391
- return `${CHECKS_FAILED_MESSAGE}: ${failed.map((check) => check.name).join(", ")}`;
2987
+ const failed = snapshot.rollup.filter((check2) => check2.status === CHECK_STATUS_FAIL);
2988
+ return `${CHECKS_FAILED_MESSAGE}: ${failed.map((check2) => check2.name).join(", ")}`;
3392
2989
  }
3393
2990
  function should_never_read_review_decision() {
3394
2991
  return false;
@@ -3457,39 +3054,480 @@ function get_repo_name_with_owner_within(timeout_ms) {
3457
3054
  }
3458
3055
  var gh_spawn = { get_repo_name_with_owner, get_repo_name_with_owner_within };
3459
3056
 
3057
+ // scripts/issue/issue-state.ts
3058
+ import { z as z11 } from "zod";
3059
+ var NO_LABELS = "(none)";
3060
+ var LABEL_SEPARATOR = ", ";
3061
+ var STATE_LABEL = "state: ";
3062
+ var LABELS_LABEL = "labels: ";
3063
+ var HUMAN_REVIEW_LABEL_LINE = "human_review: ";
3064
+ var YES = "yes";
3065
+ var NO = "no";
3066
+ var ISSUE_LABEL = "issue: ";
3067
+ var HUMAN_REVIEW_LABELS = /* @__PURE__ */ new Set([NEEDS_HUMAN_REVIEW_LABEL]);
3068
+ var label_schema = z11.looseObject({ name: z11.string() });
3069
+ var issue_state_schema = z11.looseObject({
3070
+ state: z11.string(),
3071
+ labels: label_schema.array().optional()
3072
+ });
3073
+ function parse_issue_state(json) {
3074
+ try {
3075
+ const parsed = parse_json_object_or_undefined(json, issue_state_schema);
3076
+ if (parsed === void 0) return void 0;
3077
+ const labels = parsed.labels ?? [];
3078
+ return {
3079
+ state: parsed.state,
3080
+ labels: labels.map((label) => label.name),
3081
+ is_human_review: has_any_label(labels, HUMAN_REVIEW_LABELS)
3082
+ };
3083
+ } catch {
3084
+ return void 0;
3085
+ }
3086
+ }
3087
+ function format_labels(labels) {
3088
+ return labels.length === 0 ? NO_LABELS : labels.join(LABEL_SEPARATOR);
3089
+ }
3090
+ function format_issue_state(state) {
3091
+ const human_review = `${HUMAN_REVIEW_LABEL_LINE}${state.is_human_review ? YES : NO}`;
3092
+ return `${STATE_LABEL}${state.state}
3093
+ ${LABELS_LABEL}${format_labels(state.labels)}
3094
+ ${human_review}`;
3095
+ }
3096
+ function format_attributed_issue_state(issue_number, state) {
3097
+ return `${ISSUE_LABEL}${issue_number}
3098
+ ${format_issue_state(state)}`;
3099
+ }
3100
+ var issue_state = {
3101
+ NO_LABELS,
3102
+ parse_issue_state,
3103
+ format_issue_state,
3104
+ format_attributed_issue_state
3105
+ };
3106
+
3107
+ // scripts/run/run-liveness.ts
3108
+ import { readFileSync as readFileSync4, realpathSync, statSync } from "node:fs";
3109
+ import { homedir, tmpdir } from "node:os";
3110
+ import path3 from "node:path";
3111
+ import { setTimeout as sleep3 } from "node:timers/promises";
3112
+
3113
+ // scripts/agent/agent-event.ts
3114
+ import { z as z14 } from "zod";
3115
+
3116
+ // scripts/agent/claude-result-event.ts
3117
+ import { z as z13 } from "zod";
3118
+
3119
+ // scripts/agent/interactive-ask.ts
3120
+ import { z as z12 } from "zod";
3121
+ var INTERACTIVE_TOOLS = /* @__PURE__ */ new Set(["AskUserQuestion"]);
3122
+ function is_interactive_tool(name) {
3123
+ return INTERACTIVE_TOOLS.has(name);
3124
+ }
3125
+ var OPTION_SCHEMA = z12.looseObject({ label: z12.string().optional() });
3126
+ var QUESTION_SCHEMA = z12.looseObject({
3127
+ question: z12.string().optional(),
3128
+ options: z12.array(OPTION_SCHEMA).optional()
3129
+ });
3130
+ var ASK_INPUT_SCHEMA = z12.looseObject({ questions: z12.array(QUESTION_SCHEMA).optional() });
3131
+ var DENIAL_SCHEMA = z12.looseObject({
3132
+ tool_name: z12.string().optional(),
3133
+ tool_input: z12.unknown().optional()
3134
+ });
3135
+ var UNKNOWN_QUESTION = "(question text unavailable)";
3136
+ var OPTION_SEPARATOR = " / ";
3137
+ var QUESTION_SEPARATOR = "; ";
3138
+ function labels_of(question) {
3139
+ return (question.options ?? []).map((option) => option.label ?? "").filter((label) => label !== "");
3140
+ }
3141
+ function render_question(question) {
3142
+ const labels = labels_of(question);
3143
+ const text = question.question ?? UNKNOWN_QUESTION;
3144
+ return labels.length === 0 ? text : `${text} [${labels.join(OPTION_SEPARATOR)}]`;
3145
+ }
3146
+ function interactive_input(raw) {
3147
+ const denial = DENIAL_SCHEMA.safeParse(raw);
3148
+ if (!denial.success || !is_interactive_tool(denial.data.tool_name ?? "")) return void 0;
3149
+ const input = ASK_INPUT_SCHEMA.safeParse(denial.data.tool_input);
3150
+ return input.success ? input.data : void 0;
3151
+ }
3152
+ function refused_ask_of(permission_denials) {
3153
+ if (!Array.isArray(permission_denials)) return void 0;
3154
+ const input = permission_denials.map((raw) => interactive_input(raw)).find((one) => one !== void 0);
3155
+ const questions = input?.questions ?? [];
3156
+ if (questions.length === 0) return void 0;
3157
+ return questions.map((question) => render_question(question)).join(QUESTION_SEPARATOR);
3158
+ }
3159
+ var interactive_ask = { is_interactive_tool, refused_ask_of };
3160
+
3161
+ // scripts/agent/claude-result-event.ts
3162
+ var RESULT_EVENT_SCHEMA = z13.looseObject({
3163
+ type: z13.literal("result"),
3164
+ is_error: z13.unknown().optional(),
3165
+ subtype: z13.unknown().optional(),
3166
+ num_turns: z13.unknown().optional(),
3167
+ permission_denials: z13.unknown().optional(),
3168
+ result: z13.unknown().optional(),
3169
+ session_id: z13.unknown().optional(),
3170
+ usage: z13.unknown().optional()
3171
+ });
3172
+ var USAGE_SCHEMA = z13.looseObject({
3173
+ input_tokens: z13.unknown().optional(),
3174
+ cache_read_input_tokens: z13.unknown().optional(),
3175
+ output_tokens: z13.unknown().optional()
3176
+ });
3177
+ function usable_reason(value) {
3178
+ return typeof value === "string" && value.trim() !== "" ? value : void 0;
3179
+ }
3180
+ function numeric_value(value) {
3181
+ return typeof value === "number" ? value : void 0;
3182
+ }
3183
+ function denial_count(value) {
3184
+ return Array.isArray(value) ? value.length : 0;
3185
+ }
3186
+ function usage_of(value) {
3187
+ const parsed = USAGE_SCHEMA.safeParse(value);
3188
+ if (!parsed.success) return void 0;
3189
+ const usage = {
3190
+ input_tokens: numeric_value(parsed.data.input_tokens),
3191
+ cached_input_tokens: numeric_value(parsed.data.cache_read_input_tokens),
3192
+ output_tokens: numeric_value(parsed.data.output_tokens)
3193
+ };
3194
+ return Object.values(usage).some((count) => count !== void 0) ? usage : void 0;
3195
+ }
3196
+ function decode(value) {
3197
+ const parsed = RESULT_EVENT_SCHEMA.safeParse(value);
3198
+ if (!parsed.success) return void 0;
3199
+ const is_error = parsed.data.is_error === true;
3200
+ return {
3201
+ is_error,
3202
+ subtype: usable_reason(parsed.data.subtype),
3203
+ num_turns: numeric_value(parsed.data.num_turns),
3204
+ permission_denials: denial_count(parsed.data.permission_denials),
3205
+ refused_ask: interactive_ask.refused_ask_of(parsed.data.permission_denials),
3206
+ reason: is_error ? usable_reason(parsed.data.result) ?? usable_reason(parsed.data.subtype) : void 0,
3207
+ session_id: usable_reason(parsed.data.session_id),
3208
+ usage: usage_of(parsed.data.usage)
3209
+ };
3210
+ }
3211
+ var claude_result_event = { decode };
3212
+
3213
+ // scripts/agent/agent-event.ts
3214
+ var TEXT_BLOCK_SCHEMA = z14.looseObject({ type: z14.literal("text"), text: z14.string() });
3215
+ var CLAUDE_MESSAGE_SCHEMA = z14.looseObject({ content: z14.array(z14.unknown()).optional() });
3216
+ var CLAUDE_INIT_SCHEMA = z14.looseObject({ type: z14.literal("system"), subtype: z14.literal("init") });
3217
+ var CLAUDE_ASSISTANT_SCHEMA = z14.looseObject({
3218
+ type: z14.literal("assistant"),
3219
+ message: CLAUDE_MESSAGE_SCHEMA
3220
+ });
3221
+ var USAGE_SCHEMA2 = z14.looseObject({
3222
+ input_tokens: z14.number().optional(),
3223
+ cached_input_tokens: z14.number().optional(),
3224
+ output_tokens: z14.number().optional()
3225
+ });
3226
+ var CODEX_START_SCHEMA = z14.looseObject({ type: z14.enum(["thread.started", "turn.started"]) });
3227
+ var CODEX_PROGRESS_SCHEMA = z14.looseObject({
3228
+ type: z14.enum(["item.started", "item.updated", "item.completed"]),
3229
+ item: z14.looseObject({ type: z14.string(), text: z14.string().optional() }).optional()
3230
+ });
3231
+ var CODEX_COMPLETE_SCHEMA = z14.looseObject({
3232
+ type: z14.literal("turn.completed"),
3233
+ usage: USAGE_SCHEMA2.optional()
3234
+ });
3235
+ var CODEX_FAILURE_SCHEMA = z14.looseObject({
3236
+ type: z14.enum(["turn.failed", "error"]),
3237
+ error: z14.looseObject({ message: z14.string().optional() }).optional(),
3238
+ message: z14.string().optional()
3239
+ });
3240
+ var EMPTY_STATE = {
3241
+ provider: void 0,
3242
+ launch: "pending",
3243
+ progress: void 0,
3244
+ result: "running",
3245
+ reason: void 0,
3246
+ usage: void 0
3247
+ };
3248
+ var LAUNCH_HEADER_PREFIX = "=== ";
3249
+ var LAUNCH_HEADER_MARKER = " \xB7 started by process ";
3250
+ function usable_text(value) {
3251
+ return typeof value === "string" && value.trim() !== "" ? value : void 0;
3252
+ }
3253
+ function claude_progress(content) {
3254
+ return content.map((block) => TEXT_BLOCK_SCHEMA.safeParse(block)).filter((parsed) => parsed.success).map((parsed) => parsed.data.text).findLast((text) => text.trim() !== "");
3255
+ }
3256
+ function claude_result(value, state) {
3257
+ const result = claude_result_event.decode(value);
3258
+ if (result === void 0) return void 0;
3259
+ return {
3260
+ ...state,
3261
+ provider: "anthropic",
3262
+ result: result.is_error ? "failed" : "completed",
3263
+ reason: result.is_error ? result.reason ?? state.reason : state.reason,
3264
+ usage: result.usage
3265
+ };
3266
+ }
3267
+ function claude_assistant(value, state) {
3268
+ const assistant = CLAUDE_ASSISTANT_SCHEMA.safeParse(value);
3269
+ if (!assistant.success) return void 0;
3270
+ const progress = claude_progress(assistant.data.message.content ?? []) ?? state.progress;
3271
+ return { ...state, provider: "anthropic", progress };
3272
+ }
3273
+ function claude_terminal(value, state) {
3274
+ return claude_result(value, state);
3275
+ }
3276
+ function claude_event(value, state) {
3277
+ if (CLAUDE_INIT_SCHEMA.safeParse(value).success) {
3278
+ return { ...state, provider: "anthropic", launch: "started" };
3279
+ }
3280
+ return claude_assistant(value, state) ?? claude_terminal(value, state);
3281
+ }
3282
+ function codex_progress(value, state) {
3283
+ const parsed = CODEX_PROGRESS_SCHEMA.safeParse(value);
3284
+ if (!parsed.success) return void 0;
3285
+ const progress = usable_text(parsed.data.item?.text) ?? state.progress;
3286
+ return { ...state, provider: "openai", progress };
3287
+ }
3288
+ function codex_completed(value, state) {
3289
+ const completed = CODEX_COMPLETE_SCHEMA.safeParse(value);
3290
+ if (!completed.success) return void 0;
3291
+ return { ...state, provider: "openai", result: "completed", usage: completed.data.usage };
3292
+ }
3293
+ function codex_failed(value, state) {
3294
+ const failed = CODEX_FAILURE_SCHEMA.safeParse(value);
3295
+ if (!failed.success) return void 0;
3296
+ const reason = usable_text(failed.data.error?.message) ?? usable_text(failed.data.message);
3297
+ return { ...state, provider: "openai", result: "failed", reason: reason ?? state.reason };
3298
+ }
3299
+ function codex_terminal(value, state) {
3300
+ return codex_completed(value, state) ?? codex_failed(value, state);
3301
+ }
3302
+ function codex_event(value, state) {
3303
+ if (CODEX_START_SCHEMA.safeParse(value).success) {
3304
+ return { ...state, provider: "openai", launch: "started" };
3305
+ }
3306
+ return codex_progress(value, state) ?? codex_terminal(value, state);
3307
+ }
3308
+ function normalized(value, state) {
3309
+ return claude_event(value, state) ?? codex_event(value, state) ?? state;
3310
+ }
3311
+ function next_state(line, state) {
3312
+ const is_header = line.startsWith(LAUNCH_HEADER_PREFIX) && line.includes(LAUNCH_HEADER_MARKER);
3313
+ if (is_header) return EMPTY_STATE;
3314
+ return normalized(json_value.parse_or_undefined(line), state);
3315
+ }
3316
+ function read(transcript) {
3317
+ let state = EMPTY_STATE;
3318
+ for (const line of transcript.split("\n")) state = next_state(line, state);
3319
+ return state;
3320
+ }
3321
+ function describe(state) {
3322
+ const progress = state.progress === void 0 ? "" : ` progress=${state.progress}`;
3323
+ const reason = state.reason === void 0 ? "" : ` reason=${state.reason}`;
3324
+ return `launch=${state.launch} result=${state.result}${progress}${reason}`;
3325
+ }
3326
+ var agent_event = { describe, read };
3327
+
3328
+ // scripts/run/run-liveness.ts
3329
+ var ALIVE_VERDICT = "alive";
3330
+ var SETTLED_VERDICT = "settled";
3331
+ var STOPPED_VERDICT = "stopped";
3332
+ var UNDETERMINED_VERDICT = "undetermined";
3333
+ var PROCESS_ALIVE = "alive";
3334
+ var PROCESS_NONE = "none";
3335
+ var PROCESS_UNKNOWN = "unknown";
3336
+ var DEFAULT_SILENT_MINUTES = 30;
3337
+ var DEFAULT_GAP_SECONDS = 5;
3338
+ var MS_PER_MINUTE = 6e4;
3339
+ var MS_PER_SECOND = 1e3;
3340
+ var OPEN_STATE = "OPEN";
3341
+ var STATE_FIELDS = "state,labels";
3342
+ var REASONS = {
3343
+ [ALIVE_VERDICT]: "The unit is still working: its output moved, or a process of the child is alive.",
3344
+ [SETTLED_VERDICT]: "The child is closed, parked with `needs-decision`, or marked `already-done`, so there is nothing here to recover.",
3345
+ [STOPPED_VERDICT]: "The output has been frozen past the silent window and no process of the child is alive in that checkout.",
3346
+ [UNDETERMINED_VERDICT]: "A trace could not be read, so this says nothing about the unit. A trace that could not be read answers `undetermined`, never `stopped`."
3347
+ };
3348
+ var ALIVE_ADVICE = "Keep waiting on `pnpm josh lane:await`; do not touch the child.";
3349
+ var SETTLED_ADVICE = "Read the child with `pnpm josh issue:state <N>` and take the branch its state says.";
3350
+ var STOPPED_CLEAN_ADVICE = 'The unit ended \u2014 classify how before booking it. Run `pnpm josh run:merge <N> --output <path>` (add `--epic <E> --repo <owner/repo> --owner "$PPID"` for a named epic): it reads the child\'s exit record without waiting for the unit to return, re-dispatches a child that could not reach the API (counting the outage; a run of them trips the environment guard and stops the run), and parks an abandoned child with `needs-decision` against the consecutive-failure guard. The checkout is clean, so there is nothing to stash.';
3351
+ var STOPPED_DIRTY_ADVICE = 'Stash the half-finished work with `git stash push -u -m "backlogrun: stopped unit for #<N>"` and record it on the Issue, then classify how the unit ended with `pnpm josh run:merge <N> --output <path>` (add `--epic <E> --repo <owner/repo> --owner "$PPID"` for a named epic): it re-dispatches an API-outage child (counting the outage; a run of them trips the environment guard) and parks an abandoned child with `needs-decision` against the consecutive-failure guard, without waiting for the unit to return.';
3352
+ var UNDETERMINED_ADVICE = "Read the trace that failed and ask again. Where the process trace was given as `unknown`, leave `--process` out so the command reads it. Two of these in a row is a fault in the check itself rather than a slow unit: stop polling and report it.";
3353
+ function is_output_moving(traces) {
3354
+ return traces.is_output_frozen === false;
3355
+ }
3356
+ function is_agent_state_finished(state) {
3357
+ return state?.result === "completed" || state?.result === "failed";
3358
+ }
3359
+ function is_agent_finished(traces) {
3360
+ return is_agent_state_finished(traces.agent_state);
3361
+ }
3362
+ function definitive_verdict(traces) {
3363
+ if (traces.is_child_settled === true) return SETTLED_VERDICT;
3364
+ if (is_agent_finished(traces)) return STOPPED_VERDICT;
3365
+ if (is_output_moving(traces)) return ALIVE_VERDICT;
3366
+ return void 0;
3367
+ }
3368
+ function is_check_running(traces) {
3369
+ return traces.process_trace === PROCESS_ALIVE;
3370
+ }
3371
+ function has_unreadable_trace(traces) {
3372
+ return traces.is_child_settled === void 0 || traces.is_output_frozen === void 0 || traces.process_trace === PROCESS_UNKNOWN;
3373
+ }
3374
+ function to_verdict(traces) {
3375
+ const definitive = definitive_verdict(traces);
3376
+ if (definitive !== void 0) return definitive;
3377
+ if (has_unreadable_trace(traces)) return UNDETERMINED_VERDICT;
3378
+ return is_check_running(traces) ? ALIVE_VERDICT : STOPPED_VERDICT;
3379
+ }
3380
+ function to_advice(verdict, has_work_to_stash) {
3381
+ if (verdict === ALIVE_VERDICT) return ALIVE_ADVICE;
3382
+ if (verdict === SETTLED_VERDICT) return SETTLED_ADVICE;
3383
+ if (verdict === UNDETERMINED_VERDICT) return UNDETERMINED_ADVICE;
3384
+ return has_work_to_stash ? STOPPED_DIRTY_ADVICE : STOPPED_CLEAN_ADVICE;
3385
+ }
3386
+ function decide3(traces) {
3387
+ const verdict = to_verdict(traces);
3388
+ const has_work_to_stash = verdict === STOPPED_VERDICT && traces.is_tree_dirty;
3389
+ return {
3390
+ advice: to_advice(verdict, has_work_to_stash),
3391
+ has_work_to_stash,
3392
+ reason: traces.agent_state?.reason ?? REASONS[verdict],
3393
+ verdict
3394
+ };
3395
+ }
3396
+ function to_resolved_root(root) {
3397
+ try {
3398
+ return realpathSync(root);
3399
+ } catch {
3400
+ return root;
3401
+ }
3402
+ }
3403
+ var ALLOWED_ROOTS = [
3404
+ ...new Set(
3405
+ [homedir(), tmpdir(), PLATFORM_TEMP_ROOT].flatMap((root) => [root, to_resolved_root(root)])
3406
+ )
3407
+ ];
3408
+ function is_within(candidate, root) {
3409
+ const relative = path3.relative(root, candidate);
3410
+ return relative !== "" && !relative.startsWith("..") && !path3.isAbsolute(relative);
3411
+ }
3412
+ function to_safe_path(output_path) {
3413
+ const normalized2 = path3.normalize(output_path);
3414
+ if (!path3.isAbsolute(normalized2)) return void 0;
3415
+ return ALLOWED_ROOTS.some((root) => is_within(normalized2, root)) ? normalized2 : void 0;
3416
+ }
3417
+ function sample_output(output_path) {
3418
+ const safe_path = to_safe_path(output_path);
3419
+ if (safe_path === void 0) return void 0;
3420
+ const stats = statSync(safe_path, { throwIfNoEntry: false });
3421
+ if (!stats?.isFile()) return void 0;
3422
+ return { mtime_ms: stats.mtimeMs, size: stats.size };
3423
+ }
3424
+ function read_agent_state(output_path) {
3425
+ const safe_path = to_safe_path(output_path);
3426
+ if (safe_path === void 0) return void 0;
3427
+ try {
3428
+ const state = agent_event.read(readFileSync4(safe_path, "utf8"));
3429
+ return state.provider === void 0 ? void 0 : state;
3430
+ } catch {
3431
+ return void 0;
3432
+ }
3433
+ }
3434
+ function describe_agent_state(output_path) {
3435
+ const state = read_agent_state(output_path);
3436
+ return state === void 0 ? void 0 : `agent: ${state.provider ?? "unknown"} ${agent_event.describe(state)}`;
3437
+ }
3438
+ async function read_output_frozen(request) {
3439
+ const first = sample_output(request.output_path);
3440
+ if (first === void 0) return void 0;
3441
+ if (request.now_ms - first.mtime_ms < request.silent_window_ms) return false;
3442
+ await sleep3(request.gap_ms);
3443
+ const second = sample_output(request.output_path);
3444
+ if (second === void 0) return void 0;
3445
+ return second.mtime_ms === first.mtime_ms && second.size === first.size;
3446
+ }
3447
+ function carries_label(labels, wanted) {
3448
+ return labels.some((label) => label.toLowerCase() === wanted);
3449
+ }
3450
+ var SETTLED_LABELS = [NEEDS_DECISION_LABEL, ALREADY_DONE_LABEL];
3451
+ function carries_settled_label(labels) {
3452
+ return SETTLED_LABELS.some((label) => carries_label(labels, label));
3453
+ }
3454
+ async function read_child_settled(issue, repo) {
3455
+ const json = await git_gh_issue_read.issue_view_json(issue, STATE_FIELDS, repo);
3456
+ if (json === void 0) return void 0;
3457
+ const state = issue_state.parse_issue_state(json);
3458
+ if (state === void 0) return void 0;
3459
+ return state.state !== OPEN_STATE || carries_settled_label(state.labels);
3460
+ }
3461
+ async function read_traces(request) {
3462
+ const [is_initial_child_settled, is_output_frozen, is_tree_dirty] = await Promise.all([
3463
+ read_child_settled(request.issue, request.repo),
3464
+ read_output_frozen({
3465
+ gap_ms: request.gap_ms ?? DEFAULT_GAP_SECONDS * MS_PER_SECOND,
3466
+ now_ms: Date.now(),
3467
+ output_path: request.output_path,
3468
+ silent_window_ms: request.silent_window_ms ?? DEFAULT_SILENT_MINUTES * MS_PER_MINUTE
3469
+ }),
3470
+ run_hold.is_tree_dirty()
3471
+ ]);
3472
+ const agent_state = read_agent_state(request.output_path);
3473
+ const is_latest_child_settled = is_agent_state_finished(agent_state) ? await read_child_settled(request.issue, request.repo) : void 0;
3474
+ const is_child_settled = is_latest_child_settled ?? is_initial_child_settled;
3475
+ return {
3476
+ agent_state,
3477
+ is_child_settled,
3478
+ is_output_frozen,
3479
+ is_tree_dirty,
3480
+ process_trace: request.process_trace
3481
+ };
3482
+ }
3483
+ async function check(request) {
3484
+ issue_number_shape.require_issue_number(request.issue);
3485
+ return decide3(await read_traces(request));
3486
+ }
3487
+ var run_liveness = {
3488
+ check,
3489
+ decide: decide3,
3490
+ describe_agent_state,
3491
+ read_child_settled,
3492
+ read_output_frozen,
3493
+ sample_output,
3494
+ to_safe_path
3495
+ };
3496
+
3460
3497
  export {
3461
3498
  bounded_pool,
3462
- git_gh_api_path,
3463
- read_json_listing,
3464
- parse_json_object_or_undefined,
3465
- has_stdout_field,
3466
- git_gh_exec,
3467
3499
  git_gh_issue_read,
3468
3500
  issue_watch_diff,
3469
- issue_citation,
3470
- session_cite,
3471
3501
  shell_segments,
3472
3502
  bash_triggers,
3473
3503
  tail_commands,
3474
3504
  filing_cap,
3475
3505
  CONTEXT_CUT_THRESHOLD,
3476
- run_hold,
3506
+ cost_verdict,
3507
+ cost_cli,
3477
3508
  run_cut_handoff,
3478
3509
  run_cut,
3479
3510
  run_tail_rule,
3480
3511
  lane_background,
3512
+ interactive_ask,
3481
3513
  IN_PROGRESS_LABEL,
3482
3514
  NEEDS_DECISION_LABEL,
3483
3515
  RUN_SOLO_LABEL,
3484
3516
  RUN_LANE_LABEL,
3485
- NEEDS_HUMAN_REVIEW_LABEL,
3486
3517
  ALREADY_DONE_LABEL,
3487
3518
  has_any_label,
3519
+ label_name_of,
3488
3520
  has_label_name,
3489
3521
  lane_handoff,
3490
3522
  lane_park,
3523
+ pre_gate_cut,
3491
3524
  gh_spawn,
3492
3525
  repo_party,
3493
- git_gh_pr_read,
3494
- git_gh_command
3526
+ git_gh_repo,
3527
+ git_gh_command,
3528
+ issue_state,
3529
+ PROCESS_ALIVE,
3530
+ PROCESS_NONE,
3531
+ PROCESS_UNKNOWN,
3532
+ run_liveness
3495
3533
  };