@joshuafolkken/kit 1.1094.0 → 1.1128.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 (149) hide show
  1. package/.claude/skills/workflow-commands/SKILL.md +1 -1
  2. package/.claude/skills/workflow-commands/background-commands.md +36 -85
  3. package/.claude/skills/workflow-commands/backlogrun-progress.md +29 -32
  4. package/.claude/skills/workflow-commands/backlogrun-steps.md +2 -2
  5. package/.claude/skills/workflow-commands/fullrun.md +5 -4
  6. package/.claude/skills/workflow-commands/halfrun.md +5 -4
  7. package/.claude/skills/workflow-commands/latest-gate.md +7 -15
  8. package/.claude/skills/workflow-commands/pre-gate-cut.md +4 -8
  9. package/.claude/skills/workflow-commands/split-assessment.md +4 -18
  10. package/.github/actions/setup-node/action.yml +33 -0
  11. package/.github/actions/setup-pnpm/action.yml +4 -4
  12. package/.github/workflows/auto-tag.yml +2 -3
  13. package/.github/workflows/ci.yml +7 -8
  14. package/.github/workflows/dependabot-auto-merge.yml +1 -0
  15. package/.github/workflows/pr-classification.yml +1 -3
  16. package/.github/workflows/production.yml +1 -0
  17. package/.github/workflows/publish.yml +10 -9
  18. package/.github/workflows/sonar-qube.yml +17 -13
  19. package/.pnpmfile.mjs +29 -0
  20. package/AGENTS.md +4 -11
  21. package/CLAUDE.md +24 -17
  22. package/GEMINI.md +4 -13
  23. package/README.md +8 -3
  24. package/SECURITY.md +1 -0
  25. package/cspell/index.yaml +4 -0
  26. package/dist/CLAUDE.basic.md +6 -6
  27. package/dist/CLAUDE.md +24 -17
  28. package/dist/CLAUDE.static.md +6 -6
  29. package/dist/config-merge/index.js +33 -9
  30. package/dist/hooks/batch-guard.js +4 -4
  31. package/dist/hooks/{chunk-NKOG3XAV.js → chunk-4JZDP5X5.js} +2 -2
  32. package/dist/hooks/{chunk-3C4YCCEF.js → chunk-5SD2YM7Z.js} +4 -4
  33. package/dist/hooks/{chunk-OIZUHPJI.js → chunk-77J7IEQM.js} +1 -1
  34. package/dist/hooks/{chunk-KHWHKJOM.js → chunk-7HVB7SZG.js} +3 -3
  35. package/dist/hooks/{chunk-UD24EAIL.js → chunk-AIOIOMPX.js} +1875 -104
  36. package/dist/hooks/{chunk-M2XDCUKD.js → chunk-M7QKEKWO.js} +88 -1783
  37. package/dist/hooks/{chunk-E54KGFEQ.js → chunk-MKVGBQPA.js} +1 -1
  38. package/dist/hooks/{chunk-7ZPFAVR7.js → chunk-NXYMNPUQ.js} +3 -3
  39. package/dist/hooks/{chunk-O4LL4HTI.js → chunk-QVLT52OV.js} +2 -2
  40. package/dist/hooks/{chunk-IL27YTPH.js → chunk-XYUIQOW3.js} +2 -2
  41. package/dist/hooks/codex-hook-adapter.js +12 -47
  42. package/dist/hooks/duplicate-read-guard.js +5 -5
  43. package/dist/hooks/format-edited.js +2 -2
  44. package/dist/hooks/inputs.json +180 -179
  45. package/dist/hooks/investigation-guard.js +5 -5
  46. package/dist/hooks/pretool-guard.js +9 -9
  47. package/dist/hooks/stop-guard.js +17 -12
  48. package/dist/josh.js +79 -30
  49. package/dist/version/index.js +36 -20
  50. package/eslint/rules/unicorn.js +3 -2
  51. package/package.json +18 -2
  52. package/pnpm-workspace.yaml +5 -7
  53. package/prompts/collaboration-workflow/glossary.md +17 -0
  54. package/prompts/collaboration-workflow/issue-template.md +1 -1
  55. package/prompts/collaboration-workflow/operating-rules.md +1 -1
  56. package/prompts/collaboration-workflow/principles.md +9 -0
  57. package/prompts/collaboration-workflow.md +1 -0
  58. package/scripts/backlog/backlog-arrival.ts +30 -10
  59. package/scripts/backlog/backlog-budget-cli.ts +15 -16
  60. package/scripts/backlog/backlog-offer-cli.ts +6 -14
  61. package/scripts/backlog/backlog-plan.ts +29 -18
  62. package/scripts/backlog/backlog-ready.ts +20 -7
  63. package/scripts/config-merge/parse-jsonc.ts +33 -3
  64. package/scripts/config-merge/patch-json-key.ts +13 -6
  65. package/scripts/cost-runtime/cost-cli.ts +3 -7
  66. package/scripts/doctor/doctor-consumer.ts +3 -5
  67. package/scripts/doctor/doctor-io.ts +9 -13
  68. package/scripts/document/backlogrun-parent-read-set.ts +12 -1
  69. package/scripts/document/document-byte-budget.ts +1 -0
  70. package/scripts/document/entry-read-budget.ts +13 -7
  71. package/scripts/document/entry-read-set.ts +32 -8
  72. package/scripts/document/lane-child-read-set.ts +7 -0
  73. package/scripts/document/read-set-point-of-use.ts +8 -3
  74. package/scripts/document/read-set-trim.ts +3 -1
  75. package/scripts/epic/epic-audit.ts +3 -18
  76. package/scripts/gh/git-gh-issue-list.ts +12 -11
  77. package/scripts/gh/git-gh-issue-write.ts +4 -1
  78. package/scripts/gh/git-gh-pr-auto-merge.ts +4 -1
  79. package/scripts/git/git-command.ts +6 -1
  80. package/scripts/git/git-spawn-sync.ts +65 -0
  81. package/scripts/git/git-spawn.ts +5 -4
  82. package/scripts/git/stash/stash-pop-args.ts +1 -6
  83. package/scripts/init/init-file-action.ts +54 -0
  84. package/scripts/init/init-logic-migrate.ts +35 -17
  85. package/scripts/init/init-logic-secretlint.ts +1 -1
  86. package/scripts/init/init-logic.ts +6 -22
  87. package/scripts/init/init.ts +11 -68
  88. package/scripts/init/kit-written-paths.ts +2 -0
  89. package/scripts/init/project-profile.ts +3 -6
  90. package/scripts/init/start-steps.ts +2 -1
  91. package/scripts/issue/defect-rate-cli.ts +61 -20
  92. package/scripts/issue/issue-backlinks.ts +7 -14
  93. package/scripts/issue/issue-cite.ts +12 -6
  94. package/scripts/issue/issue-file.ts +5 -12
  95. package/scripts/issue/markdown-section.ts +21 -6
  96. package/scripts/issue/measure-rerun-cli.ts +73 -14
  97. package/scripts/josh/josh-commands-project.ts +1 -1
  98. package/scripts/josh/josh-commands-workflow.ts +1 -1
  99. package/scripts/josh/run-github-prerequisite.ts +3 -6
  100. package/scripts/lane/lane-await.ts +43 -13
  101. package/scripts/lane/lane-close.ts +4 -1
  102. package/scripts/lane/lane-launch-cli.ts +10 -16
  103. package/scripts/lane/openai-review-broker.ts +4 -1
  104. package/scripts/lib/cli-flags.ts +31 -2
  105. package/scripts/lib/error-message.ts +12 -1
  106. package/scripts/lines/line-targets.ts +0 -11
  107. package/scripts/lines/lines-command.ts +5 -3
  108. package/scripts/propagate/propagate-git.ts +3 -8
  109. package/scripts/refactor/refactor-scan.ts +2 -1
  110. package/scripts/registry-migration/migrate-logic.ts +28 -19
  111. package/scripts/registry-migration/migrate.ts +6 -5
  112. package/scripts/release/github-release-cli.ts +14 -3
  113. package/scripts/release/release-publish.ts +36 -2
  114. package/scripts/release/release-worktree.ts +97 -2
  115. package/scripts/review/review-checkout.ts +3 -2
  116. package/scripts/review/review-record-cli.ts +9 -16
  117. package/scripts/rules/early-heartbeat.ts +4 -3
  118. package/scripts/rules/lane-park.ts +9 -0
  119. package/scripts/rules/stop-rules.ts +7 -4
  120. package/scripts/run/run-carry-args.ts +8 -12
  121. package/scripts/run/run-cut-args.ts +1 -6
  122. package/scripts/run/run-ending-cli.ts +1 -5
  123. package/scripts/run/run-entry-cli.ts +40 -9
  124. package/scripts/run/run-entry-stop.ts +104 -0
  125. package/scripts/run/run-event-stream-emit.ts +7 -2
  126. package/scripts/run/run-hold.ts +4 -1
  127. package/scripts/run/run-liveness-cli.ts +1 -5
  128. package/scripts/run/run-merge-cli.ts +2 -10
  129. package/scripts/run/run-parent-cut-hook.ts +4 -1
  130. package/scripts/run/run-prep-cli.ts +4 -1
  131. package/scripts/run/run-progress-args.ts +20 -4
  132. package/scripts/run/run-progress-cli.ts +31 -29
  133. package/scripts/run/run-progress-clock.ts +4 -1
  134. package/scripts/run/run-ship-cli.ts +8 -16
  135. package/scripts/run/run-ship-probe.ts +4 -1
  136. package/scripts/run/run-status-cli.ts +2 -15
  137. package/scripts/run/run-tidy-lanes.ts +4 -1
  138. package/scripts/run/run-wake-cli.ts +2 -10
  139. package/scripts/run/run-watcher-guard.ts +9 -5
  140. package/scripts/safe-chain/pack-hook.ts +92 -0
  141. package/scripts/sync/sync-ai-files.ts +4 -0
  142. package/scripts/test/test-declared-changed.ts +13 -16
  143. package/scripts/test/test-declared.ts +3 -7
  144. package/scripts/version/version-commands.ts +11 -1
  145. package/templates/CLAUDE.basic.md +6 -6
  146. package/templates/workflows/ci.yml +16 -82
  147. package/templates/workflows/dependabot-auto-merge.yml +1 -0
  148. package/templates/workflows/github-release.yml +1 -3
  149. package/tsconfig.sonar.json +4 -22
@@ -1,32 +1,29 @@
1
1
  import {
2
2
  ALREADY_DONE_LABEL,
3
- BREAKING_CHANGE_LABEL,
4
- BUGFIX_LABEL,
5
3
  CONTEXT_CUT_THRESHOLD,
6
- ENHANCEMENT_LABEL,
7
- FULL_PAGE_QUERY,
8
4
  IN_PROGRESS_LABEL,
9
5
  NEEDS_DECISION_LABEL,
10
6
  NEEDS_HUMAN_REVIEW_LABEL,
7
+ PORCELAIN_FLAG,
11
8
  RECENT_REQUEST_WINDOW,
12
- RELEASE_CLASSIFICATION_NAMES,
13
9
  agent_role_profile,
14
10
  agent_session_environment,
15
11
  bash_triggers,
12
+ cli_flags,
16
13
  error_text,
17
14
  filing_cap,
18
- gh_failure,
19
15
  git_command,
20
16
  git_common_directory,
21
- git_gh_api_path,
22
- git_gh_exec,
17
+ git_gh_command,
18
+ git_gh_issue_read,
19
+ git_gh_pr_read,
20
+ git_spawn_sync,
23
21
  has_any_label,
24
- has_stderr_field,
25
22
  issue_cite,
26
23
  lane_background,
27
24
  lane_park,
28
25
  lane_registry,
29
- parse_json_array_or_undefined,
26
+ open_issue_schema,
30
27
  parse_json_object_safe,
31
28
  read_json_listing,
32
29
  repo_origin,
@@ -38,31 +35,31 @@ import {
38
35
  run_tail,
39
36
  shell_segments,
40
37
  tail_commands
41
- } from "./chunk-UD24EAIL.js";
38
+ } from "./chunk-AIOIOMPX.js";
42
39
  import {
43
40
  find_local_bin_upwards
44
41
  } from "./chunk-3V37IID6.js";
45
42
  import {
46
43
  batch_outcome
47
- } from "./chunk-IL27YTPH.js";
44
+ } from "./chunk-XYUIQOW3.js";
48
45
  import {
49
46
  investigation_refusal
50
- } from "./chunk-KHWHKJOM.js";
47
+ } from "./chunk-7HVB7SZG.js";
51
48
  import {
52
49
  duplicate_read_outcome
53
- } from "./chunk-3C4YCCEF.js";
50
+ } from "./chunk-5SD2YM7Z.js";
54
51
  import {
55
52
  investigation_reads
56
- } from "./chunk-7ZPFAVR7.js";
53
+ } from "./chunk-NXYMNPUQ.js";
57
54
  import {
58
55
  lane_guard_policy,
59
56
  time_batch_guard
60
- } from "./chunk-O4LL4HTI.js";
57
+ } from "./chunk-QVLT52OV.js";
61
58
  import {
62
59
  hook_decision,
63
60
  lane_child_marker,
64
61
  run_issue_number
65
- } from "./chunk-E54KGFEQ.js";
62
+ } from "./chunk-MKVGBQPA.js";
66
63
  import {
67
64
  PLATFORM_TEMP_ROOT,
68
65
  cost_attribute,
@@ -74,7 +71,7 @@ import {
74
71
  lane_paths,
75
72
  stamp_file,
76
73
  time_shell
77
- } from "./chunk-NKOG3XAV.js";
74
+ } from "./chunk-4JZDP5X5.js";
78
75
 
79
76
  // scripts/rules/direct-filing.ts
80
77
  var DIRECT_FILING_REASON = '\u26D4 direct filing: an Issue is filed with `pnpm josh issue:file "<title>" --body-file <path> --depth <0|1|2> [--route <route>] [--label <name>] [--repo <owner/repo>]`, never with `gh api \u2026/issues` or `gh issue create`. The command runs every filing step in order \u2014 the duplicate scout, the body lint and its classification labels, the depth and `route:` labels, the `## Origin` check when filing into another repository, and `epic:bundle` after the create \u2014 so none of them is a step to remember. When the scout prints candidates it holds the filing: read each, then reissue with `--distinct <N,\u2026>` for the ones that are separate deliverables. Reference: `docs/josh-commands-automation.md` \u2192 "`josh issue:file`". **This rule fires on every occurrence, not once per run.**';
@@ -298,7 +295,8 @@ function is_life_fresh(target, threshold_ms) {
298
295
  try {
299
296
  const pinged_ms = parse_pinged_at(raw);
300
297
  return pinged_ms !== void 0 && Date.now() - pinged_ms < threshold_ms;
301
- } catch {
298
+ } catch (error) {
299
+ error_text.trace_swallowed("run_progress_clock.is_life_fresh", error);
302
300
  return false;
303
301
  }
304
302
  }
@@ -442,7 +440,7 @@ function decide(call, run2, can_record) {
442
440
  if (can_record) ARM_RECORD.record(target, lands_ms);
443
441
  return false;
444
442
  }
445
- var EARLY_HEARTBEAT_REASON = '\u26D4 early heartbeat: this call arms a wait timer of its own, and the progress clock is not yours to keep. `pnpm josh run:progress --wait` waits the interval out for you (`JOSH_PROGRESS_INTERVAL_MINUTES`, or `josh.progress_interval_minutes` in `package.json`, default 20 minutes), prints the five labelled lines and exits \u2014 start it in the background, relay the lines it printed when it exits, and start the next one. Two timers armed at once is what produced reports 3\u20135 minutes apart on a 15-minute setting (joshuafolkken/kit#1570): a new one was armed on the turn a timer fired and again on the turn a child\'s completion woke the run, and `--mark` recorded each report without anything refusing the early ones. **An explicit ask is not a heartbeat**: if the person asked for progress now, run `pnpm josh run:progress --once`, which prints the five labelled lines whatever the clock says. If you are waiting on something rather than on a clock, wait on the thing itself \u2014 `pnpm josh followup` waits for CI. The procedure is `.claude/skills/workflow-commands/backlogrun.md` \u2192 "Progress while the run is quiet". **This rule fires on every early arm, not once per run**, so reissuing the same sleep will be refused again.';
443
+ var EARLY_HEARTBEAT_REASON = "\u26D4 early heartbeat: this call arms a wait timer of its own, and the progress clock is not yours to keep. `pnpm josh run:progress --wait` keeps it for you (`JOSH_PROGRESS_INTERVAL_MINUTES`, or `josh.progress_interval_minutes` in `package.json`, default 20 minutes): start it once in the background and it reports the five labelled lines to the run's event stream on its own, without waking you \u2014 relay nothing, and start it again only after it exits, which it does when newly runnable work arrives. Two timers armed at once is what produced reports 3\u20135 minutes apart on a 15-minute setting (joshuafolkken/kit#1570): a new one was armed on the turn a timer fired and again on the turn a child's completion woke the run, and `--mark` recorded each report without anything refusing the early ones. **An explicit ask is not a heartbeat**: if the person asked for progress now, run `pnpm josh run:progress --once`, which prints the five labelled lines whatever the clock says. If you are waiting on something rather than on a clock, wait on the thing itself \u2014 `pnpm josh followup` waits for CI. The procedure is `.claude/skills/workflow-commands/backlogrun.md` \u2192 \"Progress while the run is quiet\". **This rule fires on every early arm, not once per run**, so reissuing the same sleep will be refused again.";
446
444
  var PROGRESS_NAMES = /* @__PURE__ */ new Set(["run:progress"]);
447
445
  var WATCH_FLAG = /(?:^|\s)--(?:wait|once)(?=\s|$)/u;
448
446
  function is_progress_watch_segment(segment) {
@@ -671,7 +669,6 @@ var git_force = {
671
669
 
672
670
  // scripts/cost-runtime/cost-cli.ts
673
671
  import { fileURLToPath } from "node:url";
674
- import { parseArgs } from "node:util";
675
672
 
676
673
  // scripts/cost-runtime/codex-usage.ts
677
674
  import { globSync, readFileSync as readFileSync2 } from "node:fs";
@@ -958,12 +955,8 @@ var PARSE_ARGS_OPTIONS = {
958
955
  path: { type: "string" }
959
956
  };
960
957
  function parse_options(argv) {
961
- try {
962
- const { values } = parseArgs({ args: [...argv], options: PARSE_ARGS_OPTIONS, strict: true });
963
- return to_options(values);
964
- } catch {
965
- return void 0;
966
- }
958
+ const values = cli_flags.values_of(argv, PARSE_ARGS_OPTIONS);
959
+ return values === void 0 ? void 0 : to_options(values);
967
960
  }
968
961
  function report_empty(cwd, session_id) {
969
962
  const searched = cost_transcript.searched_directories(cost_transcript.transcript_directories(cwd));
@@ -2026,16 +2019,10 @@ import path5 from "node:path";
2026
2019
  import { existsSync as existsSync2 } from "node:fs";
2027
2020
  import path4 from "node:path";
2028
2021
 
2029
- // scripts/lib/spawn-exit.ts
2030
- function read_spawn_stdout(result) {
2031
- return result.stdout ?? "";
2032
- }
2033
-
2034
2022
  // scripts/version/kit-descriptor.ts
2035
2023
  var KIT_PACKAGE_NAME = "@joshuafolkken/kit";
2036
2024
 
2037
2025
  // scripts/doctor/doctor-consumer.ts
2038
- import { execaSync } from "execa";
2039
2026
  import { z as z6 } from "zod";
2040
2027
  var NODE_MODULES = "node_modules";
2041
2028
  var SETTINGS_PATH = path4.join(".claude", "settings.json");
@@ -2077,11 +2064,9 @@ function is_plugin_declared(root) {
2077
2064
  return parsed.success && parsed.data.enabledPlugins?.[PLUGIN_ID] === true;
2078
2065
  }
2079
2066
  function configured_hooks_path(root) {
2080
- const result = execaSync("git", ["-C", root, "config", "--get", "core.hooksPath"], {
2081
- reject: false,
2067
+ const value = git_spawn_sync.read(["-C", root, "config", "--get", "core.hooksPath"], {
2082
2068
  timeout: GIT_TIMEOUT_MS
2083
2069
  });
2084
- const value = read_spawn_stdout(result).trim();
2085
2070
  return value === "" ? void 0 : value;
2086
2071
  }
2087
2072
  function claude_md_state(root) {
@@ -2141,6 +2126,7 @@ function report_consumer_setup(root) {
2141
2126
  var doctor_consumer = {
2142
2127
  claude_md_line,
2143
2128
  claude_md_state,
2129
+ configured_hooks_path,
2144
2130
  hooks_path_line,
2145
2131
  is_kit_consumer,
2146
2132
  is_plugin_declared,
@@ -2543,9 +2529,6 @@ var shell_body_trigger = {
2543
2529
  keeps_body_safe
2544
2530
  };
2545
2531
 
2546
- // scripts/test/test-declared-changed.ts
2547
- import { execFileSync } from "node:child_process";
2548
-
2549
2532
  // scripts/gate/project-checks.ts
2550
2533
  import { existsSync as existsSync4, globSync as globSync2, readFileSync as readFileSync4 } from "node:fs";
2551
2534
  import path7 from "node:path";
@@ -2553,7 +2536,6 @@ import path7 from "node:path";
2553
2536
  // scripts/init/project-profile.ts
2554
2537
  import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync3 } from "node:fs";
2555
2538
  import path6 from "node:path";
2556
- import { execaSync as execaSync2 } from "execa";
2557
2539
  var IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([".git", "node_modules", "dist", "build", ".svelte-kit"]);
2558
2540
  var WEB_EXTENSIONS = /* @__PURE__ */ new Set([".html", ".css", ".js", ".jsx", ".mjs", ".cjs"]);
2559
2541
  var TYPESCRIPT_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx"]);
@@ -2644,11 +2626,8 @@ function scan_files(root) {
2644
2626
  return { has_web, has_typescript };
2645
2627
  }
2646
2628
  function has_github_remote(root) {
2647
- const result = execaSync2("git", ["config", "--get", "remote.origin.url"], {
2648
- cwd: root,
2649
- reject: false
2650
- });
2651
- return result.exitCode === 0 && repo_origin.parse_origin_url(result.stdout) !== void 0;
2629
+ const url = git_spawn_sync.origin_url(root);
2630
+ return url !== void 0 && repo_origin.parse_origin_url(url) !== void 0;
2652
2631
  }
2653
2632
  function inspect_project(root, requested) {
2654
2633
  const profile = resolve_profile(root, requested);
@@ -2874,15 +2853,9 @@ function path_of(line) {
2874
2853
  return arrow === -1 ? body : body.slice(arrow + RENAME_ARROW.length);
2875
2854
  }
2876
2855
  function read_changed_paths_sync() {
2877
- try {
2878
- const output = execFileSync("git", ["status", "--porcelain"], {
2879
- encoding: "utf8",
2880
- stdio: ["ignore", "pipe", "ignore"]
2881
- });
2882
- return output.split("\n").filter((line) => line.length > STATUS_PREFIX_LENGTH).map((line) => path_of(line));
2883
- } catch {
2884
- return [];
2885
- }
2856
+ const output = git_spawn_sync.run(["status", PORCELAIN_FLAG], { timeout: 0 });
2857
+ if (output.exit_code !== 0) return [];
2858
+ return output.stdout.split("\n").filter((line) => line.length > STATUS_PREFIX_LENGTH).map((line) => path_of(line));
2886
2859
  }
2887
2860
  var injected = {};
2888
2861
  function source_paths() {
@@ -3344,1680 +3317,11 @@ var delivered_rules = {
3344
3317
  };
3345
3318
 
3346
3319
  // scripts/run/run-watcher-hook.ts
3347
- import { z as z19 } from "zod";
3320
+ import { z as z12 } from "zod";
3348
3321
 
3349
3322
  // scripts/run/run-progress-read.ts
3350
3323
  import { loadavg } from "node:os";
3351
3324
 
3352
- // scripts/gh/git-gh-helpers.ts
3353
- function parse_pr_state_string(result) {
3354
- const trimmed = result.trim();
3355
- return trimmed.length > 0 ? trimmed : void 0;
3356
- }
3357
- function is_pr_already_exists_message(error_message) {
3358
- return error_message.toLowerCase().includes("already exists");
3359
- }
3360
- function get_error_message_with_stderr(error) {
3361
- if (!(error instanceof Error)) return String(error);
3362
- if (has_stderr_field(error) && error.stderr.length > 0) return `${error.message}
3363
- ${error.stderr}`;
3364
- return error.message;
3365
- }
3366
- function handle_pr_create_error(error) {
3367
- const error_message = get_error_message_with_stderr(error);
3368
- if (is_pr_already_exists_message(error_message)) {
3369
- throw new Error("PR_ALREADY_EXISTS");
3370
- }
3371
- throw error;
3372
- }
3373
- var git_gh_helpers = {
3374
- parse_pr_state_string,
3375
- get_error_message_with_stderr,
3376
- handle_pr_create_error
3377
- };
3378
-
3379
- // scripts/git/schemas.ts
3380
- import { z as z8 } from "zod";
3381
- var package_name_schema = z8.object({ name: z8.string().min(1) });
3382
- var rollup_item_schema = z8.looseObject({
3383
- // eslint-disable-next-line @typescript-eslint/naming-convention -- GraphQL field name from GitHub API
3384
- __typename: z8.string().optional(),
3385
- state: z8.string().optional(),
3386
- status: z8.string().optional(),
3387
- conclusion: z8.string().optional(),
3388
- name: z8.string().optional(),
3389
- context: z8.string().optional()
3390
- });
3391
- var pr_raw_schema = z8.object({
3392
- statusCheckRollup: z8.array(rollup_item_schema).optional(),
3393
- mergeStateStatus: z8.string().optional(),
3394
- reviewDecision: z8.string().optional()
3395
- });
3396
- var pull_comment_schema = z8.object({
3397
- body: z8.string().optional(),
3398
- html_url: z8.string().optional(),
3399
- user: z8.object({ login: z8.string().optional() }).optional()
3400
- });
3401
- var ai_review_pull_comment_schema = z8.object({
3402
- body: z8.string().optional(),
3403
- url: z8.string().optional(),
3404
- author: z8.object({ login: z8.string().optional() }).optional()
3405
- });
3406
- var pr_info_schema = z8.object({
3407
- mergeable: z8.union([z8.boolean(), z8.string()]).nullable().optional(),
3408
- mergeStateStatus: z8.string().nullable().optional(),
3409
- state: z8.string().optional()
3410
- });
3411
- var epic_issue_schema = z8.object({
3412
- number: z8.number(),
3413
- body: z8.string().optional()
3414
- });
3415
- var blocking_issue_schema = z8.object({
3416
- number: z8.number(),
3417
- state: z8.string().optional(),
3418
- repository_url: z8.string().optional()
3419
- });
3420
- var blocked_by_schema = z8.object({
3421
- nodes: z8.array(blocking_issue_schema).default([]),
3422
- totalCount: z8.number().optional()
3423
- }).optional();
3424
- var epic_child_schema = z8.object({
3425
- state: z8.string().optional(),
3426
- blockedBy: blocked_by_schema
3427
- });
3428
- var rest_comment_schema = z8.looseObject({
3429
- body: z8.string().nullish(),
3430
- html_url: z8.string().optional(),
3431
- user: z8.looseObject({ login: z8.string().optional() }).nullish()
3432
- });
3433
- var issue_label_schema = z8.object({ name: z8.string() });
3434
- var epic_subject_schema = z8.object({
3435
- number: z8.number(),
3436
- state: z8.string().optional(),
3437
- labels: z8.array(issue_label_schema).optional(),
3438
- body: z8.string().optional()
3439
- });
3440
- var open_issue_schema = z8.object({
3441
- number: z8.number(),
3442
- title: z8.string(),
3443
- labels: z8.array(issue_label_schema).optional(),
3444
- createdAt: z8.string(),
3445
- blockedBy: blocked_by_schema
3446
- });
3447
-
3448
- // scripts/gh/git-gh-issue-rest.ts
3449
- import { z as z9 } from "zod";
3450
-
3451
- // scripts/gh/git-gh-rest-state.ts
3452
- var MERGED_STATE = "MERGED";
3453
- function to_gh_state(state) {
3454
- return state?.toUpperCase();
3455
- }
3456
-
3457
- // scripts/gh/git-gh-issue-rest.ts
3458
- var rest_issue_schema = z9.looseObject({
3459
- number: z9.number(),
3460
- issue_dependencies_summary: z9.looseObject({ total_blocked_by: z9.number().optional() }).nullish(),
3461
- // Present only on a pull request, which this endpoint serves as readily as an issue.
3462
- pull_request: z9.looseObject({ merged_at: z9.string().nullish() }).nullish()
3463
- });
3464
- var REPOSITORY_URL = /\/repos\/([\w.-]+\/[\w.-]+)$/u;
3465
- var REPOSITORY_URL_GROUP = 1;
3466
- var BLOCKED_BY_FIELD = "blockedBy";
3467
- var BLOCKED_BY_COUNT_FIELD = "blocked_by_count";
3468
- var STATE_FIELD = "state";
3469
- var BODY_FIELD = "body";
3470
- var FIELD_SEPARATOR = ",";
3471
- var EMPTY_BODY = "";
3472
- var REST_FIELD_NAMES = /* @__PURE__ */ new Map([
3473
- ["url", "html_url"],
3474
- ["createdAt", "created_at"]
3475
- ]);
3476
- var NOT_AN_ISSUE_MESSAGE = "gh api answered something other than an issue object";
3477
- var NOT_AN_ISSUE_LISTING_MESSAGE = "gh api answered something other than an issue listing";
3478
- var NOT_A_BLOCKER_LISTING_MESSAGE = "gh api answered something other than a blocked-by listing";
3479
- function rest_field_name(field) {
3480
- return REST_FIELD_NAMES.get(field) ?? field;
3481
- }
3482
- function split_fields(fields) {
3483
- return fields.split(FIELD_SEPARATOR).map((field) => field.trim()).filter((field) => field.length > 0);
3484
- }
3485
- function to_issue_state(rest, value) {
3486
- if (typeof rest.pull_request?.merged_at === "string") return MERGED_STATE;
3487
- return typeof value === "string" ? to_gh_state(value) : value;
3488
- }
3489
- function total_blocked_by(rest) {
3490
- return rest.issue_dependencies_summary?.total_blocked_by;
3491
- }
3492
- function to_gh_field_value(field, rest) {
3493
- if (field === BLOCKED_BY_COUNT_FIELD) return total_blocked_by(rest);
3494
- const value = rest[rest_field_name(field)];
3495
- if (field === STATE_FIELD) return to_issue_state(rest, value);
3496
- return field === BODY_FIELD ? value ?? EMPTY_BODY : value;
3497
- }
3498
- function parse_rest_issue(rest_json) {
3499
- const parsed = parse_json_object_safe(rest_json, rest_issue_schema);
3500
- if (parsed === void 0) throw new Error(NOT_AN_ISSUE_MESSAGE);
3501
- return parsed;
3502
- }
3503
- function is_pull_request(rest) {
3504
- return rest.pull_request !== void 0 && rest.pull_request !== null;
3505
- }
3506
- function parse_rest_issues(rest_json) {
3507
- const parsed = parse_json_array_or_undefined(rest_json, rest_issue_schema);
3508
- if (parsed === void 0) throw new Error(NOT_AN_ISSUE_LISTING_MESSAGE);
3509
- return parsed;
3510
- }
3511
- function empty_blocked_by() {
3512
- return { nodes: [], totalCount: 0 };
3513
- }
3514
- function repo_of_url(repository_url) {
3515
- const match = REPOSITORY_URL.exec(repository_url ?? "");
3516
- return match?.[REPOSITORY_URL_GROUP];
3517
- }
3518
- function to_blocked_by(blockers_json, exact_total) {
3519
- const parsed = parse_json_array_or_undefined(blockers_json, blocking_issue_schema);
3520
- if (parsed === void 0) throw new Error(NOT_A_BLOCKER_LISTING_MESSAGE);
3521
- const nodes = parsed.map((blocker) => ({ ...blocker, state: to_gh_state(blocker.state) }));
3522
- return { nodes, totalCount: exact_total ?? nodes.length };
3523
- }
3524
- function to_gh_issue(rest, fields, blocked_by) {
3525
- return Object.fromEntries(
3526
- fields.map((field) => [
3527
- field,
3528
- field === BLOCKED_BY_FIELD ? blocked_by : to_gh_field_value(field, rest)
3529
- ])
3530
- );
3531
- }
3532
- function to_field_text(value) {
3533
- if (typeof value === "string") return value;
3534
- return value === void 0 || value === null ? EMPTY_BODY : JSON.stringify(value);
3535
- }
3536
- var CLOSED = "CLOSED";
3537
- function reference_of_blocker(node, fallback_repo) {
3538
- const repo = repo_of_url(node.repository_url) ?? fallback_repo;
3539
- if (node.state === void 0) return { repo, number: node.number };
3540
- return { repo, number: node.number, state: node.state.toUpperCase() === CLOSED ? CLOSED : "OPEN" };
3541
- }
3542
- var git_gh_issue_rest = {
3543
- empty_blocked_by,
3544
- repo_of_url,
3545
- reference_of_blocker,
3546
- split_fields,
3547
- is_pull_request,
3548
- parse_rest_issue,
3549
- parse_rest_issues,
3550
- total_blocked_by,
3551
- to_blocked_by,
3552
- to_gh_issue,
3553
- to_field_text
3554
- };
3555
-
3556
- // scripts/gh/git-gh-reachability.ts
3557
- var RATE_LIMITED_STATUS = 429;
3558
- var SERVER_ERROR_FLOOR = 500;
3559
- function is_retryable_status(status) {
3560
- if (status >= SERVER_ERROR_FLOOR) return true;
3561
- return status === RATE_LIMITED_STATUS;
3562
- }
3563
- function classify_status(status) {
3564
- if (status === void 0) return "unreachable";
3565
- return is_retryable_status(status) ? "unreachable" : "reachable";
3566
- }
3567
- var gh_reachability = { classify_status };
3568
-
3569
- // scripts/gh/git-gh-issue-read.ts
3570
- async function read_blocked_by_listing(issue_number, repo, exact_total) {
3571
- const json = await git_gh_exec.exec_gh_api({
3572
- path: `${git_gh_api_path.blocked_by_api_path(issue_number, repo)}${git_gh_api_path.FULL_PAGE_QUERY}`
3573
- });
3574
- return git_gh_issue_rest.to_blocked_by(json, exact_total);
3575
- }
3576
- async function read_blocked_by(issue_number, rest, repo) {
3577
- if (git_gh_issue_rest.is_pull_request(rest)) return git_gh_issue_rest.empty_blocked_by();
3578
- const exact_total = git_gh_issue_rest.total_blocked_by(rest);
3579
- if (exact_total === 0) return git_gh_issue_rest.empty_blocked_by();
3580
- return await read_blocked_by_listing(issue_number, repo, exact_total);
3581
- }
3582
- function mark_followup(error) {
3583
- if (!(error instanceof Error)) return error;
3584
- const failure = gh_failure.failure_of(error);
3585
- if (failure === void 0) return error;
3586
- return gh_failure.attach(error, { ...failure, is_followup: true });
3587
- }
3588
- async function read_relations(issue_number, rest, repo) {
3589
- try {
3590
- return await read_blocked_by(issue_number, rest, repo);
3591
- } catch (error) {
3592
- throw mark_followup(error);
3593
- }
3594
- }
3595
- async function read_issue_fields(issue_number, fields, repo) {
3596
- const rest = git_gh_issue_rest.parse_rest_issue(
3597
- await git_gh_exec.exec_gh_api({ path: git_gh_api_path.issue_api_path(issue_number, repo) })
3598
- );
3599
- const requested = git_gh_issue_rest.split_fields(fields);
3600
- const blocked_by = requested.includes(BLOCKED_BY_FIELD) ? await read_relations(issue_number, rest, repo) : void 0;
3601
- return git_gh_issue_rest.to_gh_issue(rest, requested, blocked_by);
3602
- }
3603
- var NOT_FOUND_STATUS = 404;
3604
- function is_number_unresolved(failure) {
3605
- return failure.status === NOT_FOUND_STATUS && failure.is_followup !== true;
3606
- }
3607
- function to_unreadable_reason(status) {
3608
- return gh_reachability.classify_status(status) === "unreachable" ? "unreachable" : "rejected";
3609
- }
3610
- function to_read_failure(error) {
3611
- const failure = gh_failure.failure_of(error);
3612
- if (failure === void 0) return { kind: "unreadable", reason: "malformed", status: void 0 };
3613
- if (is_number_unresolved(failure)) return { kind: "missing" };
3614
- return {
3615
- kind: "unreadable",
3616
- reason: to_unreadable_reason(failure.status),
3617
- status: failure.status
3618
- };
3619
- }
3620
- async function issue_view_json_classified(issue_number, fields, repo) {
3621
- try {
3622
- const issue = await read_issue_fields(issue_number, fields, repo);
3623
- return { kind: "read", json: JSON.stringify(issue) };
3624
- } catch (error) {
3625
- return to_read_failure(error);
3626
- }
3627
- }
3628
- async function issue_view_field_classified(issue_number, field, repo) {
3629
- try {
3630
- const issue = await read_issue_fields(issue_number, field, repo);
3631
- return { kind: "read", text: git_gh_issue_rest.to_field_text(issue[field]) };
3632
- } catch (error) {
3633
- return to_read_failure(error);
3634
- }
3635
- }
3636
- async function issue_view_field(issue_number, field, repo) {
3637
- const read2 = await issue_view_field_classified(issue_number, field, repo);
3638
- return read2.kind === "read" ? read2.text : void 0;
3639
- }
3640
- async function issue_get_title(issue_number, repo) {
3641
- const result = await issue_view_field(issue_number, "title", repo);
3642
- return result === void 0 ? void 0 : git_gh_helpers.parse_pr_state_string(result);
3643
- }
3644
- async function issue_get_body(issue_number, repo) {
3645
- return await issue_view_field(issue_number, "body", repo);
3646
- }
3647
- async function issue_get_body_classified(issue_number, repo) {
3648
- return await issue_view_field_classified(issue_number, "body", repo);
3649
- }
3650
- async function issue_view_json(issue_number, fields, repo) {
3651
- const read2 = await issue_view_json_classified(issue_number, fields, repo);
3652
- return read2.kind === "read" ? read2.json : void 0;
3653
- }
3654
- var STATE_AND_RELATIONS_FIELDS = "number,state,labels,blockedBy";
3655
- async function issue_get_state_and_relations(issue_number, repo) {
3656
- return await issue_view_json(issue_number, STATE_AND_RELATIONS_FIELDS, repo);
3657
- }
3658
- async function issue_get_state_and_relations_classified(issue_number, repo) {
3659
- return await issue_view_json_classified(issue_number, STATE_AND_RELATIONS_FIELDS, repo);
3660
- }
3661
- function is_unreachable_read(failure) {
3662
- return failure.kind === "unreadable" && failure.reason === "unreachable";
3663
- }
3664
- var PLAN_FIELDS = "number,title,body,state,url,labels,blockedBy";
3665
- async function issue_get_plan_fields(issue_number) {
3666
- return await issue_view_json(issue_number, PLAN_FIELDS);
3667
- }
3668
- async function issue_get_plan_fields_classified(issue_number) {
3669
- return await issue_view_json_classified(issue_number, PLAN_FIELDS);
3670
- }
3671
- async function issue_get_labels_and_body(issue_number) {
3672
- return await issue_view_json(issue_number, "number,state,labels,body");
3673
- }
3674
- async function issue_list_comments(issue_number) {
3675
- const path10 = `${git_gh_api_path.issue_comments_api_path(issue_number)}${git_gh_api_path.FULL_PAGE_QUERY}`;
3676
- try {
3677
- return await git_gh_exec.exec_gh_api({ path: path10, should_paginate: true });
3678
- } catch {
3679
- return void 0;
3680
- }
3681
- }
3682
- async function has_no_relations_endpoint(issue_number, repo) {
3683
- const status = await git_gh_exec.exec_gh_api_status(
3684
- git_gh_api_path.blocked_by_api_path(issue_number, repo)
3685
- );
3686
- return status === NOT_FOUND_STATUS;
3687
- }
3688
- async function issue_blocked_by_references(issue_number, own_repo, repo) {
3689
- try {
3690
- const listing = await read_blocked_by_listing(issue_number, repo);
3691
- return listing.nodes.map((blocker) => git_gh_issue_rest.reference_of_blocker(blocker, own_repo));
3692
- } catch (error) {
3693
- if (await has_no_relations_endpoint(issue_number, repo)) return [];
3694
- throw error;
3695
- }
3696
- }
3697
- async function issue_blocked_by_numbers(issue_number, repo) {
3698
- const references = await issue_blocked_by_references(issue_number, "", repo);
3699
- return references.map((blocker) => blocker.number);
3700
- }
3701
- var git_gh_issue_read = {
3702
- issue_blocked_by_numbers,
3703
- issue_blocked_by_references,
3704
- issue_get_title,
3705
- issue_get_body,
3706
- issue_get_body_classified,
3707
- issue_view_json,
3708
- issue_view_json_classified,
3709
- issue_get_state_and_relations,
3710
- issue_get_state_and_relations_classified,
3711
- is_unreachable_read,
3712
- issue_get_plan_fields,
3713
- issue_get_plan_fields_classified,
3714
- issue_get_labels_and_body,
3715
- issue_list_comments
3716
- };
3717
-
3718
- // scripts/gh/git-gh-issue-list.ts
3719
- var PER_PAGE = 100;
3720
- var FIRST_PAGE = 1;
3721
- var DEFAULT_STATE = "open";
3722
- var DEFAULT_SORT = "created";
3723
- var LISTING_DIRECTION = "direction=desc";
3724
- function listing_query(request) {
3725
- const state = request.state ?? DEFAULT_STATE;
3726
- const sort = request.sort ?? DEFAULT_SORT;
3727
- return `state=${state}&sort=${sort}&${LISTING_DIRECTION}`;
3728
- }
3729
- function listing_path(request, page) {
3730
- const label = request.label === void 0 ? "" : `&labels=${encodeURIComponent(request.label)}`;
3731
- const paging = `&per_page=${String(PER_PAGE)}&page=${String(page)}`;
3732
- return `${git_gh_api_path.issues_api_path(request.repo)}?${listing_query(request)}${label}${paging}`;
3733
- }
3734
- var DIGIT_PATTERN = /\d/u;
3735
- function has_token_occurrence(body, term) {
3736
- let index = body.indexOf(term);
3737
- while (index !== -1) {
3738
- if (!DIGIT_PATTERN.test(body.charAt(index + term.length))) return true;
3739
- index = body.indexOf(term, index + 1);
3740
- }
3741
- return false;
3742
- }
3743
- function matches_body(rest, term) {
3744
- if (term === void 0) return true;
3745
- const { body } = rest;
3746
- return typeof body === "string" && has_token_occurrence(body, term);
3747
- }
3748
- function is_selected(rest, request) {
3749
- return !git_gh_issue_rest.is_pull_request(rest) && matches_body(rest, request.body_term);
3750
- }
3751
- async function fetch_page(request, page) {
3752
- const path10 = listing_path(request, page);
3753
- const rows = git_gh_issue_rest.parse_rest_issues(await git_gh_exec.exec_gh_api({ path: path10 }));
3754
- return {
3755
- selected: rows.filter((row) => is_selected(row, request)),
3756
- is_full: rows.length >= PER_PAGE
3757
- };
3758
- }
3759
- var MAX_PAGES = 5;
3760
- var MAX_SCANNED = MAX_PAGES * PER_PAGE;
3761
- function wants_more(has_more, selected_count, limit) {
3762
- return has_more && selected_count < limit;
3763
- }
3764
- async function fetch_selected(request) {
3765
- const selected = [];
3766
- let page = FIRST_PAGE;
3767
- let has_more = true;
3768
- while (page <= MAX_PAGES && wants_more(has_more, selected.length, request.limit)) {
3769
- const result = await fetch_page(request, page);
3770
- selected.push(...result.selected);
3771
- has_more = result.is_full;
3772
- page += 1;
3773
- }
3774
- return {
3775
- rows: selected.slice(0, request.limit),
3776
- is_capped: wants_more(has_more, selected.length, request.limit)
3777
- };
3778
- }
3779
- async function read_relations2(rows, repo) {
3780
- const relations = [];
3781
- for (const row of rows) {
3782
- relations.push(await read_blocked_by(String(row.number), row, repo));
3783
- }
3784
- return relations;
3785
- }
3786
- async function issue_list(request) {
3787
- try {
3788
- const { rows, is_capped } = await fetch_selected(request);
3789
- const fields = git_gh_issue_rest.split_fields(request.json_fields);
3790
- const relations = fields.includes(BLOCKED_BY_FIELD) ? await read_relations2(rows, request.repo) : void 0;
3791
- const mapped = rows.map(
3792
- (row, index) => git_gh_issue_rest.to_gh_issue(row, fields, relations?.[index])
3793
- );
3794
- return { json: JSON.stringify(mapped), is_capped };
3795
- } catch {
3796
- return { json: void 0, is_capped: false };
3797
- }
3798
- }
3799
- var git_gh_issue_list = {
3800
- issue_list
3801
- };
3802
-
3803
- // scripts/gh/git-gh-issue-write.ts
3804
- var PATCH_METHOD = "PATCH";
3805
- var DELETE_METHOD2 = "DELETE";
3806
- var HTML_URL_FILTER = ".html_url";
3807
- var ID_FILTER = ".id";
3808
- var LABELS_SEGMENT = "/labels";
3809
- var COMMENTS_SEGMENT = "/comments";
3810
- var CLOSED_STATE = "closed";
3811
- var COLOR_HASH = "#";
3812
- async function did_write_succeed(write) {
3813
- try {
3814
- await write();
3815
- return true;
3816
- } catch {
3817
- return false;
3818
- }
3819
- }
3820
- async function issue_edit_body(issue_number, body) {
3821
- return await git_gh_exec.exec_gh_api({
3822
- path: git_gh_api_path.issue_api_path(issue_number),
3823
- method: PATCH_METHOD,
3824
- body: JSON.stringify({ body }),
3825
- jq_filter: HTML_URL_FILTER
3826
- });
3827
- }
3828
- async function issue_comment(issue_number, body) {
3829
- return await git_gh_exec.exec_gh_api({
3830
- path: `${git_gh_api_path.issue_api_path(issue_number)}${COMMENTS_SEGMENT}`,
3831
- body: JSON.stringify({ body }),
3832
- jq_filter: HTML_URL_FILTER
3833
- });
3834
- }
3835
- async function issue_try_comment(issue_number, body) {
3836
- return await did_write_succeed(async () => await issue_comment(issue_number, body));
3837
- }
3838
- async function issue_close(issue_number, comment) {
3839
- return await did_write_succeed(async () => {
3840
- if (comment !== void 0) await issue_comment(issue_number, comment);
3841
- await git_gh_exec.exec_gh_api({
3842
- path: git_gh_api_path.issue_api_path(issue_number),
3843
- method: PATCH_METHOD,
3844
- body: JSON.stringify({ state: CLOSED_STATE })
3845
- });
3846
- });
3847
- }
3848
- function to_label_color(color) {
3849
- return color.startsWith(COLOR_HASH) ? color.slice(COLOR_HASH.length) : color;
3850
- }
3851
- async function label_ensure(input) {
3852
- try {
3853
- await git_gh_exec.exec_gh_api({
3854
- path: `${git_gh_api_path.repo_api_path()}${LABELS_SEGMENT}`,
3855
- body: JSON.stringify({
3856
- name: input.name,
3857
- color: to_label_color(input.color),
3858
- description: input.description
3859
- })
3860
- });
3861
- } catch {
3862
- }
3863
- }
3864
- function issue_create_request(input) {
3865
- const { labels } = input;
3866
- return {
3867
- path: git_gh_api_path.issues_api_path(input.repo),
3868
- body: JSON.stringify({
3869
- title: input.title,
3870
- ...labels !== void 0 && { labels },
3871
- body: input.body
3872
- }),
3873
- jq_filter: HTML_URL_FILTER
3874
- };
3875
- }
3876
- async function issue_create_with_label(input) {
3877
- return await git_gh_exec.exec_gh_api(
3878
- issue_create_request({ title: input.title, body: input.body, labels: [input.label] })
3879
- );
3880
- }
3881
- async function issue_add_label(issue_number, label) {
3882
- return await did_write_succeed(
3883
- async () => await git_gh_exec.exec_gh_api({
3884
- path: `${git_gh_api_path.issue_api_path(issue_number)}${LABELS_SEGMENT}`,
3885
- body: JSON.stringify({ labels: [label] })
3886
- })
3887
- );
3888
- }
3889
- async function issue_remove_label(issue_number, label) {
3890
- const labels_path = `${git_gh_api_path.issue_api_path(issue_number)}${LABELS_SEGMENT}`;
3891
- await git_gh_exec.exec_gh_api({
3892
- path: `${labels_path}/${encodeURIComponent(label)}`,
3893
- method: DELETE_METHOD2
3894
- });
3895
- }
3896
- async function read_issue_id(issue_number) {
3897
- const raw = await git_gh_exec.exec_gh_api({
3898
- path: git_gh_api_path.issue_api_path(issue_number),
3899
- jq_filter: ID_FILTER
3900
- });
3901
- const issue_id = Number(raw.trim());
3902
- if (!Number.isSafeInteger(issue_id) || issue_id <= 0) {
3903
- throw new Error(`gh api answered no database id for issue #${issue_number}`);
3904
- }
3905
- return issue_id;
3906
- }
3907
- async function issue_add_blocked_by(issue_number, blocker) {
3908
- return await did_write_succeed(async () => {
3909
- const issue_id = await read_issue_id(blocker);
3910
- await git_gh_exec.exec_gh_api({
3911
- path: git_gh_api_path.blocked_by_api_path(issue_number),
3912
- body: JSON.stringify({ issue_id })
3913
- });
3914
- });
3915
- }
3916
- async function issue_remove_blocked_by(issue_number, blocker) {
3917
- return await did_write_succeed(async () => {
3918
- const issue_id = await read_issue_id(blocker);
3919
- const relations_path = git_gh_api_path.blocked_by_api_path(issue_number);
3920
- await git_gh_exec.exec_gh_api({
3921
- path: `${relations_path}/${String(issue_id)}`,
3922
- method: DELETE_METHOD2
3923
- });
3924
- });
3925
- }
3926
- var git_gh_issue_write = {
3927
- issue_edit_body,
3928
- issue_comment,
3929
- issue_try_comment,
3930
- issue_close,
3931
- label_ensure,
3932
- issue_create_request,
3933
- issue_create_with_label,
3934
- issue_add_label,
3935
- issue_remove_label,
3936
- issue_add_blocked_by,
3937
- issue_remove_blocked_by
3938
- };
3939
-
3940
- // scripts/gh/git-gh-issue.ts
3941
- var NUMBER_AND_BODY_FIELDS = "number,body";
3942
- var BACKLOG_SCAN_FIELDS = `number,title,body,${BLOCKED_BY_COUNT_FIELD}`;
3943
- var NUMBER_TITLE_AND_LABELS_FIELDS = "number,title,labels";
3944
- var SUMMARY_FIELDS = "number,title,labels,createdAt";
3945
- var PICKUP_FIELDS = `${SUMMARY_FIELDS},blockedBy`;
3946
- var { issue_list: issue_list2 } = git_gh_issue_list;
3947
- async function issue_list_recent(limit) {
3948
- return await issue_list2({ json_fields: SUMMARY_FIELDS, limit });
3949
- }
3950
- async function issue_list_open_bodies(limit) {
3951
- return await issue_list2({ json_fields: BACKLOG_SCAN_FIELDS, limit });
3952
- }
3953
- async function issue_list_recently_closed(limit) {
3954
- return await issue_list2({
3955
- json_fields: NUMBER_TITLE_AND_LABELS_FIELDS,
3956
- limit,
3957
- state: "closed",
3958
- sort: "updated"
3959
- });
3960
- }
3961
- async function issue_search_body(term, limit) {
3962
- return await issue_list2({
3963
- json_fields: NUMBER_AND_BODY_FIELDS,
3964
- limit,
3965
- body_term: term
3966
- });
3967
- }
3968
- async function issue_list_by_label(label, limit) {
3969
- return await issue_list2({ json_fields: NUMBER_AND_BODY_FIELDS, limit, label });
3970
- }
3971
- async function issue_list_by_label_summary(label, limit, options) {
3972
- return await issue_list2({
3973
- json_fields: options?.json_fields ?? PICKUP_FIELDS,
3974
- limit,
3975
- label
3976
- });
3977
- }
3978
- async function issue_list_by_label_in_repo(label, limit, repo) {
3979
- return await issue_list2({ json_fields: SUMMARY_FIELDS, limit, label, repo });
3980
- }
3981
- var git_gh_issue = {
3982
- ...git_gh_issue_read,
3983
- ...git_gh_issue_write,
3984
- issue_list_recent,
3985
- issue_list_by_label,
3986
- issue_list_by_label_in_repo,
3987
- issue_list_by_label_summary,
3988
- issue_search_body,
3989
- issue_list_open_bodies,
3990
- issue_list_recently_closed
3991
- };
3992
-
3993
- // scripts/ci/pr-classification.ts
3994
- import { readFileSync as readFileSync5 } from "node:fs";
3995
- import { fileURLToPath as fileURLToPath2 } from "node:url";
3996
- import { z as z10 } from "zod";
3997
- var CLASSIFICATION_SET = new Set(RELEASE_CLASSIFICATION_NAMES);
3998
- var ISSUE_BUG_LABEL = "bug";
3999
- var DECLARATION_PREFIX = "- \u30EA\u30EA\u30FC\u30B9\u5206\u985E: ";
4000
- var DECLARATION = new RegExp(`^${DECLARATION_PREFIX}(.+)$`, "gmu");
4001
- var LEGACY_LABELS = /* @__PURE__ */ new Set(["semver-major", "semver-minor"]);
4002
- var LABEL = z10.object({ name: z10.string() });
4003
- var USER = z10.object({ login: z10.string() });
4004
- var PULL_REQUEST = z10.object({ number: z10.number(), user: USER });
4005
- var EVENT = z10.object({
4006
- pull_request: PULL_REQUEST,
4007
- repository: z10.object({ full_name: z10.string() })
4008
- });
4009
- function classification_error(labels, author) {
4010
- const legacy = labels.filter((label) => LEGACY_LABELS.has(label.toLowerCase()));
4011
- if (legacy.length > 0) return `Remove legacy release labels: ${legacy.join(", ")}`;
4012
- const selected = labels.filter((label) => CLASSIFICATION_SET.has(label.toLowerCase()));
4013
- if (selected.length > 1) {
4014
- return `Choose exactly one release classification; found: ${selected.join(", ")}`;
4015
- }
4016
- if (selected.length === 1 || author.endsWith("[bot]")) return void 0;
4017
- return `Choose one release classification: ${RELEASE_CLASSIFICATION_NAMES.join(", ")}`;
4018
- }
4019
- function declaration(label) {
4020
- return `${DECLARATION_PREFIX}${label}`;
4021
- }
4022
- function is_classification(value) {
4023
- return CLASSIFICATION_SET.has(value);
4024
- }
4025
- function release_candidates(candidates) {
4026
- if (!candidates.includes(BREAKING_CHANGE_LABEL)) return candidates;
4027
- return candidates.filter((candidate) => candidate !== ENHANCEMENT_LABEL);
4028
- }
4029
- function issue_candidates(issue_json) {
4030
- const issue = z10.object({ labels: z10.array(LABEL), body: z10.string().nullable() }).parse(JSON.parse(issue_json));
4031
- const names = issue.labels.map((label) => label.name.toLowerCase());
4032
- const declared = [...(issue.body ?? "").matchAll(DECLARATION)].map((match) => match[1] ?? "");
4033
- const candidates = [...release_candidates([...names, ...declared].filter(is_classification))];
4034
- const unknown = declared.filter((value) => !is_classification(value));
4035
- if (unknown.length > 0) throw new Error(`Unknown release classification: ${unknown.join(", ")}`);
4036
- if (names.includes(ISSUE_BUG_LABEL) && !candidates.includes(BREAKING_CHANGE_LABEL)) {
4037
- candidates.push(BUGFIX_LABEL);
4038
- }
4039
- return candidates;
4040
- }
4041
- function select_issue_classification(issue_json) {
4042
- const candidates = issue_candidates(issue_json);
4043
- const selected = [...new Set(candidates)];
4044
- const [label] = selected;
4045
- if (label === void 0 || selected.length > 1) {
4046
- throw new Error(
4047
- `Choose one release classification before opening the PR: ${RELEASE_CLASSIFICATION_NAMES.join(", ")}; found: ${selected.join(", ") || "none"}. Add "${DECLARATION_PREFIX}<label>" to the Issue body.`
4048
- );
4049
- }
4050
- return label;
4051
- }
4052
- function fetch_current_labels(repository, pull_number) {
4053
- const path10 = `repos/${repository}/issues/${String(pull_number)}/labels`;
4054
- try {
4055
- const names = git_gh_exec.exec_gh_api_sync({ path: path10, jq_filter: ".[].name" });
4056
- return names.split("\n").filter((name) => name !== "");
4057
- } catch (error) {
4058
- const detail = error_text.message_of(error);
4059
- throw new Error(`Could not read the pull request labels: ${detail}`, { cause: error });
4060
- }
4061
- }
4062
- function check_event(event_path, read_labels = fetch_current_labels) {
4063
- const event = EVENT.parse(JSON.parse(readFileSync5(event_path, "utf8")));
4064
- const labels = read_labels(event.repository.full_name, event.pull_request.number);
4065
- return classification_error(labels, event.pull_request.user.login);
4066
- }
4067
- if (process.argv[1] === fileURLToPath2(import.meta.url)) {
4068
- const event_path = process.env["GITHUB_EVENT_PATH"];
4069
- if (!event_path) throw new Error("GITHUB_EVENT_PATH is required");
4070
- const error = check_event(event_path);
4071
- if (error) {
4072
- console.error(`::error::${error}`);
4073
- process.exitCode = 1;
4074
- }
4075
- }
4076
- var pr_classification = {
4077
- classification_error,
4078
- check_event,
4079
- fetch_current_labels,
4080
- declaration,
4081
- is_classification,
4082
- select_issue_classification
4083
- };
4084
-
4085
- // scripts/lib/poll.ts
4086
- async function sleep(duration_ms) {
4087
- await new Promise((resolve2) => {
4088
- setTimeout(resolve2, duration_ms);
4089
- });
4090
- }
4091
- async function wait_between(wait, interval_ms, attempt, attempts) {
4092
- if (attempt < attempts - 1) await wait(interval_ms);
4093
- }
4094
- async function poll_until(is_done, options) {
4095
- const wait = options.sleeper ?? sleep;
4096
- for (let attempt = 0; attempt < options.attempts; attempt += 1) {
4097
- if (await is_done()) return true;
4098
- await wait_between(wait, options.interval_ms, attempt, options.attempts);
4099
- }
4100
- return false;
4101
- }
4102
- var poll = { poll_until, sleep };
4103
-
4104
- // scripts/gh/git-gh-pr.ts
4105
- import { z as z14 } from "zod";
4106
-
4107
- // scripts/gh/git-gh-pr-rest.ts
4108
- import { z as z11 } from "zod";
4109
- var rest_repo_schema = z11.looseObject({ full_name: z11.string().optional() }).nullish();
4110
- var rest_pull_side_schema = z11.looseObject({ repo: rest_repo_schema });
4111
- var rest_pull_schema = z11.looseObject({
4112
- number: z11.number(),
4113
- html_url: z11.string().optional(),
4114
- body: z11.string().nullish(),
4115
- state: z11.string().optional(),
4116
- merged: z11.boolean().nullish(),
4117
- merged_at: z11.string().nullish(),
4118
- mergeable: z11.boolean().nullish(),
4119
- mergeable_state: z11.string().optional(),
4120
- // `sha` is the head commit, which is what both halves of the merge-gate rollup are keyed by —
4121
- // REST hangs the check runs and the status contexts off the commit rather than off the pull
4122
- // request (joshuafolkken/kit#1028).
4123
- head: z11.looseObject({ ref: z11.string().optional(), sha: z11.string().optional(), repo: rest_repo_schema }).nullish(),
4124
- base: rest_pull_side_schema.nullish(),
4125
- // `node_id` is what the GraphQL auto-merge mutation addresses a pull request by, and `auto_merge`
4126
- // is `null` until auto-merge is enabled — both read by `git-gh-pr-auto-merge.ts`
4127
- // (joshuafolkken/kit#2497).
4128
- node_id: z11.string().optional(),
4129
- auto_merge: z11.looseObject({}).nullish()
4130
- });
4131
- var NOT_A_PULL_MESSAGE = "gh api answered something other than a pull request object";
4132
- var NOT_A_PULL_LISTING_MESSAGE = "gh api answered something other than a pull request listing";
4133
- var NOT_A_COMMENT_LISTING_MESSAGE = "gh api answered something other than a comment listing";
4134
- var OPEN_STATE2 = "open";
4135
- var EMPTY_BODY2 = "";
4136
- function parse_rest_pull(rest_json) {
4137
- const parsed = parse_json_object_safe(rest_json, rest_pull_schema);
4138
- if (parsed === void 0) throw new Error(NOT_A_PULL_MESSAGE);
4139
- return parsed;
4140
- }
4141
- function parse_rest_pulls(rest_json) {
4142
- const parsed = parse_json_array_or_undefined(rest_json, rest_pull_schema);
4143
- if (parsed === void 0) throw new Error(NOT_A_PULL_LISTING_MESSAGE);
4144
- return parsed;
4145
- }
4146
- function select_pull(pulls) {
4147
- return pulls.find((pull) => pull.state === OPEN_STATE2) ?? pulls[0];
4148
- }
4149
- function is_merged(pull) {
4150
- return pull.merged === true || typeof pull.merged_at === "string";
4151
- }
4152
- function to_pr_state(pull) {
4153
- return is_merged(pull) ? MERGED_STATE : to_gh_state(pull.state);
4154
- }
4155
- function to_repo_name(side) {
4156
- return side?.repo?.full_name;
4157
- }
4158
- function is_same_repository_head(pull) {
4159
- const head_repo = to_repo_name(pull.head);
4160
- return head_repo !== void 0 && head_repo === to_repo_name(pull.base);
4161
- }
4162
- function to_pr_info(pull) {
4163
- return {
4164
- mergeable: pull.mergeable,
4165
- mergeStateStatus: to_gh_state(pull.mergeable_state),
4166
- state: to_pr_state(pull)
4167
- };
4168
- }
4169
- function to_pr_comments(rest_json) {
4170
- const parsed = parse_json_array_or_undefined(rest_json, rest_comment_schema);
4171
- if (parsed === void 0) throw new Error(NOT_A_COMMENT_LISTING_MESSAGE);
4172
- return parsed.map((comment) => ({
4173
- body: comment.body ?? EMPTY_BODY2,
4174
- url: comment.html_url,
4175
- author: { login: comment.user?.login }
4176
- }));
4177
- }
4178
- var git_gh_pr_rest = {
4179
- parse_rest_pull,
4180
- parse_rest_pulls,
4181
- select_pull,
4182
- is_same_repository_head,
4183
- is_merged,
4184
- to_pr_state,
4185
- to_pr_info,
4186
- to_pr_comments
4187
- };
4188
-
4189
- // scripts/gh/git-gh-pr-read.ts
4190
- var pr_number_by_branch = /* @__PURE__ */ new Map();
4191
- var LOOKUP_QUERY = "state=all&sort=created&direction=desc&per_page=100";
4192
- var COMMENTS_QUERY = FULL_PAGE_QUERY;
4193
- var OWNER_PLACEHOLDER = "{owner}";
4194
- var NO_PULL_REQUEST_MESSAGE = "gh api found no pull request for branch";
4195
- var UNREADABLE_PULL_REQUEST_MESSAGE = "gh api could not read the pull requests for branch";
4196
- function lookup_path(branch_name) {
4197
- const head = `${OWNER_PLACEHOLDER}:${encodeURIComponent(branch_name)}`;
4198
- return `${git_gh_api_path.pulls_api_path()}?head=${head}&${LOOKUP_QUERY}`;
4199
- }
4200
- async function fetch_pr_number(branch_name) {
4201
- const json = await git_gh_exec.exec_gh_api({ path: lookup_path(branch_name) });
4202
- return git_gh_pr_rest.select_pull(git_gh_pr_rest.parse_rest_pulls(json))?.number;
4203
- }
4204
- var pending_pr_number_by_branch = /* @__PURE__ */ new Map();
4205
- async function fetch_pr_number_read(branch_name) {
4206
- try {
4207
- const pr_number = await fetch_pr_number(branch_name);
4208
- if (pr_number === void 0) return { kind: "missing" };
4209
- pr_number_by_branch.set(branch_name, pr_number);
4210
- return { kind: "read", pr_number };
4211
- } catch (error) {
4212
- return { kind: "unreadable", cause: error };
4213
- }
4214
- }
4215
- async function start_pr_number_read(branch_name) {
4216
- const pending = pending_pr_number_by_branch.get(branch_name);
4217
- if (pending !== void 0) return await pending;
4218
- const lookup = fetch_pr_number_read(branch_name);
4219
- pending_pr_number_by_branch.set(branch_name, lookup);
4220
- try {
4221
- return await lookup;
4222
- } finally {
4223
- pending_pr_number_by_branch.delete(branch_name);
4224
- }
4225
- }
4226
- function forget_pr_numbers() {
4227
- pr_number_by_branch.clear();
4228
- pending_pr_number_by_branch.clear();
4229
- }
4230
- async function read_pr_number(branch_name) {
4231
- const cached = pr_number_by_branch.get(branch_name);
4232
- if (cached !== void 0) return { kind: "read", pr_number: cached };
4233
- return await start_pr_number_read(branch_name);
4234
- }
4235
- async function resolve_pr_number(branch_name) {
4236
- const read2 = await read_pr_number(branch_name);
4237
- return read2.kind === "read" ? read2.pr_number : void 0;
4238
- }
4239
- function to_unreadable_error(branch_name, cause) {
4240
- return new Error(`${UNREADABLE_PULL_REQUEST_MESSAGE}: ${branch_name}`, { cause });
4241
- }
4242
- async function require_pr_number(branch_name) {
4243
- const read2 = await read_pr_number(branch_name);
4244
- if (read2.kind === "read") return read2.pr_number;
4245
- if (read2.kind === "missing") throw new Error(`${NO_PULL_REQUEST_MESSAGE}: ${branch_name}`);
4246
- throw to_unreadable_error(branch_name, read2.cause);
4247
- }
4248
- async function read_pull(pr_number) {
4249
- const json = await git_gh_exec.exec_gh_api({
4250
- path: git_gh_api_path.pull_api_path(String(pr_number))
4251
- });
4252
- return git_gh_pr_rest.parse_rest_pull(json);
4253
- }
4254
- async function read_pull_of_branch(branch_name) {
4255
- const pr_number = await resolve_pr_number(branch_name);
4256
- if (pr_number === void 0) return void 0;
4257
- try {
4258
- return await read_pull(pr_number);
4259
- } catch {
4260
- return void 0;
4261
- }
4262
- }
4263
- async function pr_exists(branch_name) {
4264
- const read2 = await read_pr_number(branch_name);
4265
- if (read2.kind === "unreadable") throw to_unreadable_error(branch_name, read2.cause);
4266
- return read2.kind === "read";
4267
- }
4268
- async function pr_get_number(branch_name) {
4269
- return await resolve_pr_number(branch_name);
4270
- }
4271
- async function pr_get_url(branch_name) {
4272
- const pull = await read_pull_of_branch(branch_name);
4273
- if (pull?.html_url === void 0) return void 0;
4274
- return git_gh_helpers.parse_pr_state_string(pull.html_url);
4275
- }
4276
- async function pr_get_merge_state(branch_name) {
4277
- const pull = await read_pull_of_branch(branch_name);
4278
- if (pull === void 0) return void 0;
4279
- return {
4280
- is_merged: git_gh_pr_rest.is_merged(pull),
4281
- merged_at: pull.merged_at ?? void 0,
4282
- head_sha: pull.head?.sha
4283
- };
4284
- }
4285
- async function pr_get_body(branch_name) {
4286
- const pull = await read_pull_of_branch(branch_name);
4287
- const body = pull?.body;
4288
- return typeof body === "string" && body.length > 0 ? body : void 0;
4289
- }
4290
- async function pr_view(branch_name) {
4291
- const pull = await read_pull_of_branch(branch_name);
4292
- if (pull === void 0) return "";
4293
- return JSON.stringify(git_gh_pr_rest.to_pr_info(pull));
4294
- }
4295
- async function read_comments(branch_name, to_path, to_json) {
4296
- const pr_number = await resolve_pr_number(branch_name);
4297
- if (pr_number === void 0) return void 0;
4298
- const path10 = `${to_path(String(pr_number))}${COMMENTS_QUERY}`;
4299
- try {
4300
- return to_json(await git_gh_exec.exec_gh_api({ path: path10, should_paginate: true }));
4301
- } catch {
4302
- return void 0;
4303
- }
4304
- }
4305
- function to_comments_json(raw) {
4306
- return JSON.stringify(git_gh_pr_rest.to_pr_comments(raw));
4307
- }
4308
- function as_served(raw) {
4309
- return raw;
4310
- }
4311
- async function pr_get_comments(branch_name) {
4312
- return await read_comments(branch_name, git_gh_api_path.issue_comments_api_path, to_comments_json);
4313
- }
4314
- async function pr_get_review_comments(branch_name) {
4315
- return await read_comments(branch_name, git_gh_api_path.pull_comments_api_path, as_served);
4316
- }
4317
- var git_gh_pr_read = {
4318
- pr_exists,
4319
- pr_get_number,
4320
- pr_get_url,
4321
- pr_get_body,
4322
- pr_get_merge_state,
4323
- pr_view,
4324
- pr_get_comments,
4325
- pr_get_review_comments
4326
- };
4327
-
4328
- // scripts/gh/git-gh-pr-review.ts
4329
- import { z as z12 } from "zod";
4330
- var REVIEW_APPROVED = "APPROVED";
4331
- var REVIEW_CHANGES_REQUESTED = "CHANGES_REQUESTED";
4332
- var REVIEW_NONE = "";
4333
- var STATE_CHANGING_REVIEWS = /* @__PURE__ */ new Set([REVIEW_APPROVED, REVIEW_CHANGES_REQUESTED]);
4334
- var rest_review_schema = z12.looseObject({
4335
- state: z12.string().optional(),
4336
- user: z12.looseObject({ login: z12.string().optional() }).nullish()
4337
- });
4338
- var NOT_A_REVIEW_LISTING = "gh api answered something other than a review listing";
4339
- function parse_rest_reviews(reviews_json) {
4340
- const parsed = parse_json_array_or_undefined(reviews_json, rest_review_schema);
4341
- if (parsed === void 0) throw new Error(NOT_A_REVIEW_LISTING);
4342
- return parsed;
4343
- }
4344
- var UNATTRIBUTED_REVIEWER = "(no author)";
4345
- function read_reviewer(review) {
4346
- const login = review.user?.login;
4347
- return typeof login === "string" && login.length > 0 ? login : UNATTRIBUTED_REVIEWER;
4348
- }
4349
- function read_state_changing(review) {
4350
- const state = review.state?.toUpperCase();
4351
- return state !== void 0 && STATE_CHANGING_REVIEWS.has(state) ? state : void 0;
4352
- }
4353
- function fold_latest_states(reviews) {
4354
- const latest = /* @__PURE__ */ new Map();
4355
- for (const review of reviews) {
4356
- const state = read_state_changing(review);
4357
- if (state !== void 0) latest.set(read_reviewer(review), state);
4358
- }
4359
- return latest;
4360
- }
4361
- function to_review_decision(reviews_json) {
4362
- const latest = new Set(fold_latest_states(parse_rest_reviews(reviews_json)).values());
4363
- if (latest.has(REVIEW_CHANGES_REQUESTED)) return REVIEW_CHANGES_REQUESTED;
4364
- return latest.has(REVIEW_APPROVED) ? REVIEW_APPROVED : REVIEW_NONE;
4365
- }
4366
- var git_gh_pr_review = { to_review_decision };
4367
-
4368
- // scripts/gh/git-gh-pr-rollup.ts
4369
- import { z as z13 } from "zod";
4370
- var STATUS_CONTEXT_TYPE_NAME = "StatusContext";
4371
- var TYPE_NAME_KEY = "__typename";
4372
- var rollup_element_schema = z13.looseObject({});
4373
- var check_runs_page_schema = z13.looseObject({
4374
- // Required, not optional: GitHub always names the key, and accepting a page without one would
4375
- // answer an empty rollup — which `git-pr-followup.ts` reports as "this branch has no checks".
4376
- check_runs: z13.array(rollup_element_schema)
4377
- });
4378
- var id_holder_schema = z13.object({ id: z13.number() });
4379
- var status_page_schema = z13.looseObject({
4380
- statuses: z13.array(rollup_element_schema)
4381
- });
4382
- var NOT_A_CHECK_RUNS_LISTING = "gh api answered something other than a check run listing";
4383
- var NOT_A_STATUS_LISTING = "gh api answered something other than a commit status listing";
4384
- function read_pages(raw_json, schema, message) {
4385
- const pages = parse_json_array_or_undefined(raw_json, schema);
4386
- if (pages === void 0) throw new Error(message);
4387
- return pages;
4388
- }
4389
- var NO_SUITE = -1;
4390
- function read_id(value) {
4391
- const parsed = id_holder_schema.safeParse(value);
4392
- return parsed.success ? parsed.data.id : void 0;
4393
- }
4394
- function check_run_group_key(run2) {
4395
- const { name, app } = run2;
4396
- if (typeof name !== "string") return void 0;
4397
- return JSON.stringify([name, read_id(app)]);
4398
- }
4399
- function read_rank(run2) {
4400
- const id = read_id(run2);
4401
- if (id === void 0) return void 0;
4402
- return { suite: read_id(run2["check_suite"]) ?? NO_SUITE, run: id };
4403
- }
4404
- function is_ranked_above(candidate, current) {
4405
- if (candidate.suite !== current.suite) return candidate.suite > current.suite;
4406
- return candidate.run > current.run;
4407
- }
4408
- function should_replace(previous, rank) {
4409
- const previous_rank = previous === void 0 ? void 0 : read_rank(previous);
4410
- return previous_rank === void 0 || is_ranked_above(rank, previous_rank);
4411
- }
4412
- function remember_newest_run(run2, newest) {
4413
- const key = check_run_group_key(run2);
4414
- const rank = read_rank(run2);
4415
- if (key === void 0 || rank === void 0) return;
4416
- if (should_replace(newest.get(key), rank)) newest.set(key, run2);
4417
- }
4418
- function is_newest_run(run2, newest) {
4419
- const key = check_run_group_key(run2);
4420
- if (key === void 0 || read_rank(run2) === void 0) return true;
4421
- return newest.get(key) === run2;
4422
- }
4423
- function to_check_run_items(check_runs_json) {
4424
- const pages = read_pages(check_runs_json, check_runs_page_schema, NOT_A_CHECK_RUNS_LISTING);
4425
- const runs = pages.flatMap((page) => page.check_runs);
4426
- const newest = /* @__PURE__ */ new Map();
4427
- for (const run2 of runs) remember_newest_run(run2, newest);
4428
- return runs.filter((run2) => is_newest_run(run2, newest));
4429
- }
4430
- function to_status_context_items(status_json) {
4431
- const pages = read_pages(status_json, status_page_schema, NOT_A_STATUS_LISTING);
4432
- return pages.flatMap((page) => page.statuses).map((status) => ({ ...status, [TYPE_NAME_KEY]: STATUS_CONTEXT_TYPE_NAME }));
4433
- }
4434
- function to_status_check_rollup(input) {
4435
- return [
4436
- ...to_check_run_items(input.check_runs_json),
4437
- ...to_status_context_items(input.status_json)
4438
- ];
4439
- }
4440
- var git_gh_pr_rollup = {
4441
- to_status_check_rollup
4442
- };
4443
-
4444
- // scripts/gh/git-gh-pr-snapshot.ts
4445
- var NO_HEAD_SHA_MESSAGE = "gh api answered a pull request with no head commit";
4446
- async function read_object_pages(path10) {
4447
- return await git_gh_exec.exec_gh_api({
4448
- path: `${path10}${FULL_PAGE_QUERY}`,
4449
- should_paginate: true,
4450
- should_slurp: true
4451
- });
4452
- }
4453
- async function read_array_pages(path10) {
4454
- return await git_gh_exec.exec_gh_api({
4455
- path: `${path10}${FULL_PAGE_QUERY}`,
4456
- should_paginate: true
4457
- });
4458
- }
4459
- function read_head_sha(pull) {
4460
- const sha = pull.head?.sha;
4461
- if (sha === void 0) throw new Error(NO_HEAD_SHA_MESSAGE);
4462
- return sha;
4463
- }
4464
- async function read_status_check_rollup(commit_sha) {
4465
- const [check_runs_json, status_json] = await Promise.all([
4466
- read_object_pages(git_gh_api_path.commit_check_runs_api_path(commit_sha)),
4467
- read_object_pages(git_gh_api_path.commit_status_api_path(commit_sha))
4468
- ]);
4469
- return git_gh_pr_rollup.to_status_check_rollup({ check_runs_json, status_json });
4470
- }
4471
- async function pr_get_review_decision(pr_number) {
4472
- const path10 = git_gh_api_path.pull_reviews_api_path(String(pr_number));
4473
- return git_gh_pr_review.to_review_decision(await read_array_pages(path10));
4474
- }
4475
- async function build_checks_fields(pull) {
4476
- return {
4477
- statusCheckRollup: await read_status_check_rollup(read_head_sha(pull)),
4478
- mergeStateStatus: to_gh_state(pull.mergeable_state)
4479
- };
4480
- }
4481
- async function resolve_pull(branch_name) {
4482
- const pr_number = await require_pr_number(branch_name);
4483
- return { pr_number, pull: await read_pull(pr_number) };
4484
- }
4485
- async function pr_get_checks_snapshot(branch_name) {
4486
- const { pr_number, pull } = await resolve_pull(branch_name);
4487
- return { pr_number, snapshot_json: JSON.stringify(await build_checks_fields(pull)) };
4488
- }
4489
- async function pr_get_state_snapshot(branch_name) {
4490
- const { pr_number, pull } = await resolve_pull(branch_name);
4491
- const [fields, review_decision] = await Promise.all([
4492
- build_checks_fields(pull),
4493
- pr_get_review_decision(pr_number)
4494
- ]);
4495
- return JSON.stringify({ ...fields, reviewDecision: review_decision });
4496
- }
4497
- var git_gh_pr_snapshot = {
4498
- pr_get_state_snapshot,
4499
- pr_get_checks_snapshot,
4500
- pr_get_review_decision
4501
- };
4502
-
4503
- // scripts/gh/git-gh-pr.ts
4504
- var HTML_URL_FILTER2 = ".html_url";
4505
- var PUT_METHOD = "PUT";
4506
- var PATCH_METHOD2 = "PATCH";
4507
- var MERGE_COMMIT_METHOD = "merge";
4508
- var MERGE_REQUEST_TIMEOUT_MS = 18e4;
4509
- var MERGE_UNCONFIRMED_MESSAGE = "gh api could not read the pull request back after the merge request failed";
4510
- var MERGE_READ_BACK_ATTEMPTS = 3;
4511
- var MERGE_READ_BACK_INTERVAL_MS = 1e3;
4512
- var PR_NUMBER_PATTERN = /\/pull\/([1-9]\d*)$/u;
4513
- var LABELS_SEGMENT2 = "/labels";
4514
- var PR_LABELS = z14.array(z14.object({ name: z14.string() }));
4515
- async function add_pr_classification(number, label) {
4516
- await git_gh_exec.exec_gh_api({
4517
- path: `${git_gh_api_path.issue_api_path(number)}${LABELS_SEGMENT2}`,
4518
- body: JSON.stringify({ labels: [label] })
4519
- });
4520
- }
4521
- async function pr_get_classification(branch_name) {
4522
- const number = await require_pr_number(branch_name);
4523
- const response = await git_gh_exec.exec_gh_api({
4524
- path: `${git_gh_api_path.issue_api_path(String(number))}${LABELS_SEGMENT2}`
4525
- });
4526
- const names = PR_LABELS.parse(JSON.parse(response)).map((label) => label.name.toLowerCase());
4527
- const selected = names.filter((name) => pr_classification.is_classification(name));
4528
- if (selected.length === 0) return void 0;
4529
- const error = pr_classification.classification_error(names, "human");
4530
- if (error !== void 0) throw new Error(error);
4531
- return selected[0];
4532
- }
4533
- async function pr_ensure_classification(branch_name, label) {
4534
- if (await pr_get_classification(branch_name) !== void 0) return;
4535
- const number = await require_pr_number(branch_name);
4536
- await add_pr_classification(String(number), label);
4537
- }
4538
- async function post_pull_request(title, body) {
4539
- const base = await git_command.get_default_branch();
4540
- const head = await git_command.branch();
4541
- forget_pr_numbers();
4542
- try {
4543
- return await git_gh_exec.exec_gh_api({
4544
- path: git_gh_api_path.pulls_api_path(),
4545
- body: JSON.stringify({ title, body, head, base }),
4546
- jq_filter: HTML_URL_FILTER2
4547
- });
4548
- } catch (error) {
4549
- return git_gh_helpers.handle_pr_create_error(error);
4550
- }
4551
- }
4552
- async function pr_create(title, body, label) {
4553
- const classification_error2 = pr_classification.classification_error([label], "human");
4554
- if (classification_error2 !== void 0) throw new Error(classification_error2);
4555
- const url = await post_pull_request(title, body);
4556
- const number = PR_NUMBER_PATTERN.exec(url)?.[1];
4557
- if (number === void 0) throw new Error(`Could not identify the created pull request: ${url}`);
4558
- await add_pr_classification(number, label);
4559
- return url;
4560
- }
4561
- async function pr_comment(branch_name, body) {
4562
- const pr_number = await require_pr_number(branch_name);
4563
- return await git_gh_issue_write.issue_comment(String(pr_number), body);
4564
- }
4565
- async function pr_update_body(branch_name, body) {
4566
- const pr_number = await require_pr_number(branch_name);
4567
- await git_gh_exec.exec_gh_api({
4568
- path: git_gh_api_path.pull_api_path(String(pr_number)),
4569
- method: PATCH_METHOD2,
4570
- body: JSON.stringify({ body })
4571
- });
4572
- }
4573
- async function put_merge(pr_number) {
4574
- await git_gh_exec.exec_gh_api({
4575
- path: git_gh_api_path.pull_merge_api_path(String(pr_number)),
4576
- method: PUT_METHOD,
4577
- body: JSON.stringify({ merge_method: MERGE_COMMIT_METHOD }),
4578
- timeout_ms: MERGE_REQUEST_TIMEOUT_MS
4579
- });
4580
- }
4581
- async function read_merge_state(pr_number) {
4582
- try {
4583
- return git_gh_pr_rest.is_merged(await read_pull(pr_number));
4584
- } catch (error) {
4585
- console.warn(`Could not read the pull request back: ${String(error)}`);
4586
- return void 0;
4587
- }
4588
- }
4589
- async function sleep_between_read_backs(attempt) {
4590
- if (attempt < MERGE_READ_BACK_ATTEMPTS - 1) await poll.sleep(MERGE_READ_BACK_INTERVAL_MS);
4591
- }
4592
- async function has_merge_landed(pr_number, merge_error) {
4593
- for (let attempt = 0; attempt < MERGE_READ_BACK_ATTEMPTS; attempt += 1) {
4594
- const is_merged2 = await read_merge_state(pr_number);
4595
- if (is_merged2 !== void 0) return is_merged2;
4596
- await sleep_between_read_backs(attempt);
4597
- }
4598
- throw new Error(MERGE_UNCONFIRMED_MESSAGE, { cause: merge_error });
4599
- }
4600
- async function pr_merge(branch_name) {
4601
- const pr_number = await require_pr_number(branch_name);
4602
- try {
4603
- await put_merge(pr_number);
4604
- } catch (error) {
4605
- if (!await has_merge_landed(pr_number, error)) throw error;
4606
- }
4607
- }
4608
- var git_gh_pr = {
4609
- ...git_gh_pr_read,
4610
- ...git_gh_pr_snapshot,
4611
- pr_create,
4612
- pr_get_classification,
4613
- pr_ensure_classification,
4614
- pr_comment,
4615
- pr_merge,
4616
- pr_update_body
4617
- };
4618
-
4619
- // scripts/gh/git-gh-pr-auto-merge.ts
4620
- var GRAPHQL_PATH = "graphql";
4621
- var OPEN_PULLS_QUERY = `${git_gh_api_path.FULL_PAGE_QUERY}&state=open`;
4622
- var MISSING_NODE_ID_MESSAGE = "gh api answered a pull request without a node_id";
4623
- var ENABLE_AUTO_MERGE_MUTATION = "mutation($id: ID!) { enablePullRequestAutoMerge(input: { pullRequestId: $id, mergeMethod: MERGE }) { clientMutationId } }";
4624
- async function pr_enable_auto_merge(branch_name) {
4625
- const pull = await read_pull(await require_pr_number(branch_name));
4626
- if (pull.node_id === void 0) throw new Error(MISSING_NODE_ID_MESSAGE);
4627
- await git_gh_exec.exec_gh_api({
4628
- path: GRAPHQL_PATH,
4629
- body: JSON.stringify({ query: ENABLE_AUTO_MERGE_MUTATION, variables: { id: pull.node_id } })
4630
- });
4631
- }
4632
- async function pr_is_merged(branch_name) {
4633
- try {
4634
- return git_gh_pr_rest.is_merged(await read_pull(await require_pr_number(branch_name)));
4635
- } catch {
4636
- return false;
4637
- }
4638
- }
4639
- function head_reference_of(pull) {
4640
- return pull.head?.ref ?? "";
4641
- }
4642
- function has_head_prefix(pull, prefix) {
4643
- return git_gh_pr_rest.is_same_repository_head(pull) && head_reference_of(pull).startsWith(prefix);
4644
- }
4645
- function to_open_pull(pull) {
4646
- return {
4647
- number: pull.number,
4648
- head_ref: head_reference_of(pull),
4649
- has_auto_merge: pull.auto_merge !== null && pull.auto_merge !== void 0
4650
- };
4651
- }
4652
- async function pr_list_open_with_head_prefix(prefix) {
4653
- const json = await git_gh_exec.exec_gh_api({
4654
- path: `${git_gh_api_path.pulls_api_path()}${OPEN_PULLS_QUERY}`,
4655
- should_paginate: true
4656
- });
4657
- return git_gh_pr_rest.parse_rest_pulls(json).filter((pull) => has_head_prefix(pull, prefix)).map((pull) => to_open_pull(pull));
4658
- }
4659
- var git_gh_pr_auto_merge = {
4660
- pr_enable_auto_merge,
4661
- pr_is_merged,
4662
- pr_list_open_with_head_prefix
4663
- };
4664
-
4665
- // scripts/gh/git-gh-repo.ts
4666
- async function repo_get_name_with_owner() {
4667
- try {
4668
- const result = await git_gh_exec.exec_gh_api({
4669
- path: git_gh_api_path.repo_api_path(),
4670
- jq_filter: ".full_name"
4671
- });
4672
- return git_gh_helpers.parse_pr_state_string(result);
4673
- } catch {
4674
- return void 0;
4675
- }
4676
- }
4677
- var git_gh_repo = {
4678
- repo_get_name_with_owner
4679
- };
4680
-
4681
- // scripts/gh/git-pr-checks-parse.ts
4682
- var CHECK_STATUS_PASS = "pass";
4683
- var CHECK_STATUS_PENDING = "pending";
4684
- var CHECK_STATUS_FAIL = "fail";
4685
- var CHECK_STATUS_MISSING = "missing";
4686
- var PASSING_CONCLUSIONS = /* @__PURE__ */ new Set(["success", "skipped", "neutral"]);
4687
- var KEY_TYPE_NAME = "__typename";
4688
- var KEY_STATE = "state";
4689
- var KEY_STATUS = "status";
4690
- var KEY_CONCLUSION = "conclusion";
4691
- var KEY_NAME = "name";
4692
- var KEY_CONTEXT = "context";
4693
- function read_string(value) {
4694
- if (typeof value !== "string") return void 0;
4695
- const trimmed = value.trim();
4696
- if (trimmed.length === 0) return void 0;
4697
- return trimmed;
4698
- }
4699
- var PENDING_STATUS_STATES = /* @__PURE__ */ new Set(["pending", "expected"]);
4700
- function parse_status_context(item) {
4701
- const state = read_string(item[KEY_STATE])?.toLowerCase();
4702
- if (state === "success") return CHECK_STATUS_PASS;
4703
- if (state !== void 0 && PENDING_STATUS_STATES.has(state)) return CHECK_STATUS_PENDING;
4704
- return CHECK_STATUS_FAIL;
4705
- }
4706
- function is_passing_conclusion(item) {
4707
- const conclusion = read_string(item[KEY_CONCLUSION])?.toLowerCase();
4708
- return conclusion !== void 0 && PASSING_CONCLUSIONS.has(conclusion);
4709
- }
4710
- function parse_check_run(item) {
4711
- const status = read_string(item[KEY_STATUS])?.toLowerCase();
4712
- if (status !== "completed") return CHECK_STATUS_PENDING;
4713
- return is_passing_conclusion(item) ? CHECK_STATUS_PASS : CHECK_STATUS_FAIL;
4714
- }
4715
- function parse_rollup_status(item) {
4716
- const type_name = read_string(item[KEY_TYPE_NAME]);
4717
- if (type_name === "StatusContext") return parse_status_context(item);
4718
- return parse_check_run(item);
4719
- }
4720
- function read_rollup_array(parsed) {
4721
- const result = pr_raw_schema.safeParse(parsed);
4722
- if (!result.success) return [];
4723
- return result.data.statusCheckRollup ?? [];
4724
- }
4725
- function parse_rollup_item(item) {
4726
- const name = read_string(item[KEY_NAME]) ?? read_string(item[KEY_CONTEXT]);
4727
- if (name === void 0) return void 0;
4728
- return { name, status: parse_rollup_status(item) };
4729
- }
4730
- function parse_rollup_checks(raw_json) {
4731
- const parsed = json_value.parse_or_undefined(raw_json);
4732
- const rollup = read_rollup_array(parsed);
4733
- const checks = [];
4734
- for (const item of rollup) {
4735
- const parsed_item = parse_rollup_item(item);
4736
- if (parsed_item !== void 0) checks.push(parsed_item);
4737
- }
4738
- return checks;
4739
- }
4740
- function parse_pr_state_snapshot(raw_json) {
4741
- const parsed = json_value.parse_or_undefined(raw_json);
4742
- const result = pr_raw_schema.safeParse(parsed);
4743
- const data = result.success ? result.data : void 0;
4744
- return {
4745
- rollup: parse_rollup_checks(raw_json),
4746
- merge_state_status: read_string(data?.mergeStateStatus),
4747
- review_decision: read_string(data?.reviewDecision)
4748
- };
4749
- }
4750
-
4751
- // scripts/gh/git-pr-checks-eval.ts
4752
- var DEFAULT_REQUIRED_CHECKS = ["SonarQube"];
4753
- var CODERABBIT_CHECK_NAME = "CodeRabbit";
4754
- var REQUIRED_CHECKS_ENV_VAR = "JOSH_REQUIRED_CHECKS";
4755
- function parse_required_checks() {
4756
- const raw = process.env[REQUIRED_CHECKS_ENV_VAR];
4757
- if (!raw) return DEFAULT_REQUIRED_CHECKS;
4758
- return raw.split(",").map((check4) => check4.trim()).filter((check4) => check4.length > 0);
4759
- }
4760
- var REQUIRED_CHECKS = parse_required_checks();
4761
- var MERGE_STATE_CLEAN = "CLEAN";
4762
- var MERGE_STATE_UNSTABLE = "UNSTABLE";
4763
- var MERGE_STATE_DIRTY = "DIRTY";
4764
- var REVIEW_CHANGES_REQUESTED2 = "CHANGES_REQUESTED";
4765
- var CHECK_SUITE_SEPARATOR = " / ";
4766
- var FAILURE_MESSAGE_PREFIX = "PR checks failed";
4767
- var FAILURE_REASON_REVIEW = "review requested changes";
4768
- var FAILURE_REASON_CHECKS = "failed checks";
4769
- var FAILURE_REASON_CONFLICT = "merge conflict";
4770
- function is_required_match(check_name, required_name) {
4771
- if (check_name === required_name) return true;
4772
- return check_name.startsWith(`${required_name}${CHECK_SUITE_SEPARATOR}`);
4773
- }
4774
- function find_required_check(checks, required_name) {
4775
- return checks.find((check4) => is_required_match(check4.name, required_name));
4776
- }
4777
- function read_required_statuses(checks) {
4778
- return REQUIRED_CHECKS.map(
4779
- (name) => find_required_check(checks, name)?.status ?? CHECK_STATUS_MISSING
4780
- );
4781
- }
4782
- function is_review_blocked(review_decision) {
4783
- return review_decision === REVIEW_CHANGES_REQUESTED2;
4784
- }
4785
- function is_merge_conflict(merge_state_status) {
4786
- return merge_state_status === MERGE_STATE_DIRTY;
4787
- }
4788
- function evaluate_failure_state(input) {
4789
- if (is_merge_conflict(input.merge_state_status) || is_review_blocked(input.review_decision) || input.failed_checks.length > 0) {
4790
- return "failure";
4791
- }
4792
- return void 0;
4793
- }
4794
- function is_merge_state_clean(merge_state_status) {
4795
- return merge_state_status === MERGE_STATE_CLEAN;
4796
- }
4797
- function is_every_required_passing(statuses) {
4798
- return statuses.every((status) => status === CHECK_STATUS_PASS);
4799
- }
4800
- function is_coderabbit_check(check_name) {
4801
- return is_required_match(check_name, CODERABBIT_CHECK_NAME);
4802
- }
4803
- function is_unstable_only_from_coderabbit(snapshot) {
4804
- if (snapshot.merge_state_status !== MERGE_STATE_UNSTABLE) return false;
4805
- const non_passing = snapshot.rollup.filter((check4) => check4.status !== CHECK_STATUS_PASS);
4806
- if (non_passing.length === 0) return false;
4807
- return non_passing.every((check4) => is_coderabbit_check(check4.name));
4808
- }
4809
- function is_required_check(check_name) {
4810
- return REQUIRED_CHECKS.some((required) => is_required_match(check_name, required));
4811
- }
4812
- function is_blocking_failure(check4) {
4813
- if (check4.status !== CHECK_STATUS_FAIL) return false;
4814
- return !is_coderabbit_check(check4.name) || is_required_check(check4.name);
4815
- }
4816
- function collect_blocking_failures(snapshot) {
4817
- return snapshot.rollup.filter((check4) => is_blocking_failure(check4)).map((check4) => check4.name);
4818
- }
4819
- function is_mergeable_state(snapshot) {
4820
- if (is_merge_state_clean(snapshot.merge_state_status)) return true;
4821
- return is_unstable_only_from_coderabbit(snapshot);
4822
- }
4823
- function collect_failure_reasons(snapshot) {
4824
- const reasons = [];
4825
- if (is_merge_conflict(snapshot.merge_state_status)) reasons.push(FAILURE_REASON_CONFLICT);
4826
- if (is_review_blocked(snapshot.review_decision)) reasons.push(FAILURE_REASON_REVIEW);
4827
- const failed = collect_blocking_failures(snapshot);
4828
- if (failed.length > 0) reasons.push(`${FAILURE_REASON_CHECKS}: ${failed.join(", ")}`);
4829
- return reasons;
4830
- }
4831
- function describe_pr_failure(snapshot) {
4832
- const reasons = collect_failure_reasons(snapshot);
4833
- if (reasons.length === 0) return `${FAILURE_MESSAGE_PREFIX}.`;
4834
- return `${FAILURE_MESSAGE_PREFIX} (${reasons.join("; ")}).`;
4835
- }
4836
- function evaluate_pr_state(snapshot) {
4837
- const statuses = read_required_statuses(snapshot.rollup);
4838
- const failure = evaluate_failure_state({
4839
- review_decision: snapshot.review_decision,
4840
- failed_checks: collect_blocking_failures(snapshot),
4841
- merge_state_status: snapshot.merge_state_status
4842
- });
4843
- if (failure !== void 0) return failure;
4844
- if (is_mergeable_state(snapshot) && is_every_required_passing(statuses)) {
4845
- return "success";
4846
- }
4847
- return "pending";
4848
- }
4849
- function is_review_decision_decisive(snapshot) {
4850
- return evaluate_pr_state(snapshot) !== "pending";
4851
- }
4852
-
4853
- // scripts/gh/git-pr-checks.ts
4854
- var SECONDS_TO_MS = 1e3;
4855
- var CHECK_WAIT_INTERVAL_MS = 1e4;
4856
- var DEFAULT_TIMEOUT_SECONDS = 1920;
4857
- function compute_max_attempts(timeout_seconds, interval_ms) {
4858
- return Math.ceil(timeout_seconds / (interval_ms / SECONDS_TO_MS)) + 1;
4859
- }
4860
- var DEFAULT_MAX_ATTEMPTS = compute_max_attempts(DEFAULT_TIMEOUT_SECONDS, CHECK_WAIT_INTERVAL_MS);
4861
- function get_configured_max_attempts() {
4862
- const environment_seconds = Number(process.env["JOSH_CI_TIMEOUT_SECONDS"]);
4863
- return Number.isFinite(environment_seconds) && environment_seconds > 0 ? compute_max_attempts(environment_seconds, CHECK_WAIT_INTERVAL_MS) : DEFAULT_MAX_ATTEMPTS;
4864
- }
4865
- var CHECK_MAX_ATTEMPTS = get_configured_max_attempts();
4866
- var DEFAULT_STABLE_READS = 2;
4867
- var MAX_CONSECUTIVE_READ_FAILURES = 3;
4868
- var PR_CHECKS_TIMEOUT_MESSAGE = "Timed out while waiting for PR checks to complete.";
4869
- function is_pr_checks_timeout(error) {
4870
- return error instanceof Error && error.message === PR_CHECKS_TIMEOUT_MESSAGE;
4871
- }
4872
- var SHOULD_ALWAYS_READ_REVIEW_DECISION = () => true;
4873
- var MERGE_GATE_EVALUATOR = {
4874
- evaluate: evaluate_pr_state,
4875
- describe: describe_pr_failure,
4876
- should_read_review_decision: is_review_decision_decisive
4877
- };
4878
- function advance_stable_count(previous, state) {
4879
- return state === "success" ? previous + 1 : 0;
4880
- }
4881
- function classify_poll_result(input) {
4882
- const state = input.evaluator.evaluate(input.snapshot);
4883
- if (state === "failure") throw new Error(input.evaluator.describe(input.snapshot));
4884
- const next_stable_count = advance_stable_count(input.stable_count, state);
4885
- return {
4886
- is_done: next_stable_count >= input.required_stable_reads,
4887
- next_stable_count
4888
- };
4889
- }
4890
- async function read_pr_state(input, evaluator) {
4891
- try {
4892
- const snapshot = await input.options.fetcher(
4893
- input.options.branch_name,
4894
- evaluator.should_read_review_decision ?? SHOULD_ALWAYS_READ_REVIEW_DECISION
4895
- );
4896
- return { kind: "read", snapshot };
4897
- } catch (error) {
4898
- return { kind: "unreadable", cause: error };
4899
- }
4900
- }
4901
- async function sleep_before_next_attempt(input) {
4902
- if (input.attempt < input.options.max_attempts - 1) {
4903
- await poll.sleep(input.options.interval_ms);
4904
- }
4905
- }
4906
- async function retry_after_unreadable(input, cause) {
4907
- const next_failure_count = input.failure_count + 1;
4908
- if (next_failure_count >= MAX_CONSECUTIVE_READ_FAILURES) throw cause;
4909
- console.warn(
4910
- `Could not read the PR state (${String(next_failure_count)}/${String(MAX_CONSECUTIVE_READ_FAILURES)}); asking again on the next poll: ${String(cause)}`
4911
- );
4912
- await sleep_before_next_attempt(input);
4913
- return { next_stable_count: 0, next_failure_count, read_failure: cause };
4914
- }
4915
- function to_exhaustion_error(last_read_failure) {
4916
- return last_read_failure ?? new Error(PR_CHECKS_TIMEOUT_MESSAGE);
4917
- }
4918
- async function attempt_pr_success_poll(input) {
4919
- const evaluator = input.options.evaluator ?? MERGE_GATE_EVALUATOR;
4920
- const read2 = await read_pr_state(input, evaluator);
4921
- if (read2.kind === "unreadable") return await retry_after_unreadable(input, read2.cause);
4922
- const classification = classify_poll_result({
4923
- snapshot: read2.snapshot,
4924
- stable_count: input.stable_count,
4925
- required_stable_reads: input.options.required_stable_reads,
4926
- evaluator
4927
- });
4928
- if (classification.is_done) {
4929
- return { snapshot: read2.snapshot, next_stable_count: 0, next_failure_count: 0 };
4930
- }
4931
- await sleep_before_next_attempt(input);
4932
- return { next_stable_count: classification.next_stable_count, next_failure_count: 0 };
4933
- }
4934
- async function wait_for_pr_success(options) {
4935
- let carried = { next_stable_count: 0, next_failure_count: 0 };
4936
- for (let attempt = 0; attempt < options.max_attempts; attempt += 1) {
4937
- console.info(`Checking PR status\u2026 (${String(attempt + 1)}/${String(options.max_attempts)})`);
4938
- carried = await attempt_pr_success_poll({
4939
- options,
4940
- stable_count: carried.next_stable_count,
4941
- failure_count: carried.next_failure_count,
4942
- attempt
4943
- });
4944
- if (carried.snapshot !== void 0) return carried.snapshot;
4945
- }
4946
- throw to_exhaustion_error(carried.read_failure);
4947
- }
4948
- async function default_fetch_pr_state(branch_name, should_read_review_decision = SHOULD_ALWAYS_READ_REVIEW_DECISION) {
4949
- const checks = await git_gh_pr_snapshot.pr_get_checks_snapshot(branch_name);
4950
- const snapshot = parse_pr_state_snapshot(checks.snapshot_json);
4951
- if (!should_read_review_decision(snapshot)) return snapshot;
4952
- const decision = await git_gh_pr_snapshot.pr_get_review_decision(checks.pr_number);
4953
- return { ...snapshot, review_decision: read_string(decision) };
4954
- }
4955
-
4956
- // scripts/gh/git-pr-checks-watch.ts
4957
- var PR_CHECKS_WATCH_TIMEOUT_MS = 12e4;
4958
- var WATCH_TIMED_OUT_NOTE = "\u23F1\uFE0F pr checks --watch timed out.";
4959
- var NO_CHECKS_MESSAGE = "gh api reported no checks on the branch";
4960
- var CHECKS_FAILED_MESSAGE = "gh api reported a failing check on the branch";
4961
- function is_awaited_check(check4) {
4962
- return !is_coderabbit_check(check4.name) || is_required_check(check4.name);
4963
- }
4964
- function evaluate_checks_settled(snapshot) {
4965
- const awaited = snapshot.rollup.filter((check4) => is_awaited_check(check4));
4966
- const considered = awaited.length === 0 ? snapshot.rollup : awaited;
4967
- if (considered.length === 0 || considered.some((check4) => check4.status === CHECK_STATUS_PENDING)) {
4968
- return "pending";
4969
- }
4970
- return snapshot.rollup.some((check4) => check4.status === CHECK_STATUS_FAIL) ? "failure" : "success";
4971
- }
4972
- function describe_checks_failure(snapshot) {
4973
- const failed = snapshot.rollup.filter((check4) => check4.status === CHECK_STATUS_FAIL);
4974
- return `${CHECKS_FAILED_MESSAGE}: ${failed.map((check4) => check4.name).join(", ")}`;
4975
- }
4976
- var SHOULD_NEVER_READ_REVIEW_DECISION = () => false;
4977
- var CHECKS_SETTLED_EVALUATOR = {
4978
- evaluate: evaluate_checks_settled,
4979
- describe: describe_checks_failure,
4980
- should_read_review_decision: SHOULD_NEVER_READ_REVIEW_DECISION
4981
- };
4982
- async function watch_until_settled(branch_name) {
4983
- await wait_for_pr_success({
4984
- branch_name,
4985
- fetcher: default_fetch_pr_state,
4986
- interval_ms: CHECK_WAIT_INTERVAL_MS,
4987
- max_attempts: compute_max_attempts(
4988
- PR_CHECKS_WATCH_TIMEOUT_MS / SECONDS_TO_MS,
4989
- CHECK_WAIT_INTERVAL_MS
4990
- ),
4991
- required_stable_reads: DEFAULT_STABLE_READS,
4992
- evaluator: CHECKS_SETTLED_EVALUATOR
4993
- });
4994
- }
4995
- async function fail_when_no_checks(branch_name) {
4996
- const snapshot = await default_fetch_pr_state(branch_name, SHOULD_NEVER_READ_REVIEW_DECISION);
4997
- if (snapshot.rollup.length === 0) throw new Error(NO_CHECKS_MESSAGE);
4998
- }
4999
- async function pr_checks_watch(branch_name) {
5000
- try {
5001
- await watch_until_settled(branch_name);
5002
- return { timed_out: false };
5003
- } catch (error) {
5004
- if (!is_pr_checks_timeout(error)) throw error;
5005
- await fail_when_no_checks(branch_name);
5006
- console.info(WATCH_TIMED_OUT_NOTE);
5007
- return { timed_out: true };
5008
- }
5009
- }
5010
- var git_pr_checks_watch = { pr_checks_watch };
5011
-
5012
- // scripts/gh/git-gh-command.ts
5013
- var git_gh_command = {
5014
- ...git_gh_pr,
5015
- ...git_gh_pr_auto_merge,
5016
- pr_checks_watch: git_pr_checks_watch.pr_checks_watch,
5017
- ...git_gh_issue,
5018
- ...git_gh_repo
5019
- };
5020
-
5021
3325
  // scripts/epic/epic-busy.ts
5022
3326
  var LISTING_LIMIT = 100;
5023
3327
  var PARKED_LABELS = /* @__PURE__ */ new Set([NEEDS_DECISION_LABEL, ALREADY_DONE_LABEL]);
@@ -5080,30 +3384,30 @@ var epic_busy = {
5080
3384
  };
5081
3385
 
5082
3386
  // scripts/run/run-liveness.ts
5083
- import { readFileSync as readFileSync6, realpathSync, statSync } from "node:fs";
3387
+ import { readFileSync as readFileSync5, realpathSync, statSync } from "node:fs";
5084
3388
  import { homedir, tmpdir } from "node:os";
5085
3389
  import path8 from "node:path";
5086
- import { setTimeout as sleep2 } from "node:timers/promises";
3390
+ import { setTimeout as sleep } from "node:timers/promises";
5087
3391
 
5088
3392
  // scripts/agent/agent-event.ts
5089
- import { z as z16 } from "zod";
3393
+ import { z as z9 } from "zod";
5090
3394
 
5091
3395
  // scripts/agent/claude-result-event.ts
5092
- import { z as z15 } from "zod";
5093
- var RESULT_EVENT_SCHEMA = z15.looseObject({
5094
- type: z15.literal("result"),
5095
- is_error: z15.unknown().optional(),
5096
- subtype: z15.unknown().optional(),
5097
- num_turns: z15.unknown().optional(),
5098
- permission_denials: z15.unknown().optional(),
5099
- result: z15.unknown().optional(),
5100
- session_id: z15.unknown().optional(),
5101
- usage: z15.unknown().optional()
3396
+ import { z as z8 } from "zod";
3397
+ var RESULT_EVENT_SCHEMA = z8.looseObject({
3398
+ type: z8.literal("result"),
3399
+ is_error: z8.unknown().optional(),
3400
+ subtype: z8.unknown().optional(),
3401
+ num_turns: z8.unknown().optional(),
3402
+ permission_denials: z8.unknown().optional(),
3403
+ result: z8.unknown().optional(),
3404
+ session_id: z8.unknown().optional(),
3405
+ usage: z8.unknown().optional()
5102
3406
  });
5103
- var USAGE_SCHEMA = z15.looseObject({
5104
- input_tokens: z15.unknown().optional(),
5105
- cache_read_input_tokens: z15.unknown().optional(),
5106
- output_tokens: z15.unknown().optional()
3407
+ var USAGE_SCHEMA = z8.looseObject({
3408
+ input_tokens: z8.unknown().optional(),
3409
+ cache_read_input_tokens: z8.unknown().optional(),
3410
+ output_tokens: z8.unknown().optional()
5107
3411
  });
5108
3412
  function usable_reason(value) {
5109
3413
  return typeof value === "string" && value.trim() !== "" ? value : void 0;
@@ -5142,31 +3446,31 @@ function decode(value) {
5142
3446
  var claude_result_event = { decode };
5143
3447
 
5144
3448
  // scripts/agent/agent-event.ts
5145
- var TEXT_BLOCK_SCHEMA = z16.looseObject({ type: z16.literal("text"), text: z16.string() });
5146
- var CLAUDE_MESSAGE_SCHEMA = z16.looseObject({ content: z16.array(z16.unknown()).optional() });
5147
- var CLAUDE_INIT_SCHEMA = z16.looseObject({ type: z16.literal("system"), subtype: z16.literal("init") });
5148
- var CLAUDE_ASSISTANT_SCHEMA = z16.looseObject({
5149
- type: z16.literal("assistant"),
3449
+ var TEXT_BLOCK_SCHEMA = z9.looseObject({ type: z9.literal("text"), text: z9.string() });
3450
+ var CLAUDE_MESSAGE_SCHEMA = z9.looseObject({ content: z9.array(z9.unknown()).optional() });
3451
+ var CLAUDE_INIT_SCHEMA = z9.looseObject({ type: z9.literal("system"), subtype: z9.literal("init") });
3452
+ var CLAUDE_ASSISTANT_SCHEMA = z9.looseObject({
3453
+ type: z9.literal("assistant"),
5150
3454
  message: CLAUDE_MESSAGE_SCHEMA
5151
3455
  });
5152
- var USAGE_SCHEMA2 = z16.looseObject({
5153
- input_tokens: z16.number().optional(),
5154
- cached_input_tokens: z16.number().optional(),
5155
- output_tokens: z16.number().optional()
3456
+ var USAGE_SCHEMA2 = z9.looseObject({
3457
+ input_tokens: z9.number().optional(),
3458
+ cached_input_tokens: z9.number().optional(),
3459
+ output_tokens: z9.number().optional()
5156
3460
  });
5157
- var CODEX_START_SCHEMA = z16.looseObject({ type: z16.enum(["thread.started", "turn.started"]) });
5158
- var CODEX_PROGRESS_SCHEMA = z16.looseObject({
5159
- type: z16.enum(["item.started", "item.updated", "item.completed"]),
5160
- item: z16.looseObject({ type: z16.string(), text: z16.string().optional() }).optional()
3461
+ var CODEX_START_SCHEMA = z9.looseObject({ type: z9.enum(["thread.started", "turn.started"]) });
3462
+ var CODEX_PROGRESS_SCHEMA = z9.looseObject({
3463
+ type: z9.enum(["item.started", "item.updated", "item.completed"]),
3464
+ item: z9.looseObject({ type: z9.string(), text: z9.string().optional() }).optional()
5161
3465
  });
5162
- var CODEX_COMPLETE_SCHEMA = z16.looseObject({
5163
- type: z16.literal("turn.completed"),
3466
+ var CODEX_COMPLETE_SCHEMA = z9.looseObject({
3467
+ type: z9.literal("turn.completed"),
5164
3468
  usage: USAGE_SCHEMA2.optional()
5165
3469
  });
5166
- var CODEX_FAILURE_SCHEMA = z16.looseObject({
5167
- type: z16.enum(["turn.failed", "error"]),
5168
- error: z16.looseObject({ message: z16.string().optional() }).optional(),
5169
- message: z16.string().optional()
3470
+ var CODEX_FAILURE_SCHEMA = z9.looseObject({
3471
+ type: z9.enum(["turn.failed", "error"]),
3472
+ error: z9.looseObject({ message: z9.string().optional() }).optional(),
3473
+ message: z9.string().optional()
5170
3474
  });
5171
3475
  var EMPTY_STATE = {
5172
3476
  provider: void 0,
@@ -5257,7 +3561,7 @@ function describe(state) {
5257
3561
  var agent_event = { describe, read };
5258
3562
 
5259
3563
  // scripts/issue/issue-state.ts
5260
- import { z as z17 } from "zod";
3564
+ import { z as z10 } from "zod";
5261
3565
  var NO_LABELS = "(none)";
5262
3566
  var LABEL_SEPARATOR = ", ";
5263
3567
  var STATE_LABEL = "state: ";
@@ -5267,9 +3571,9 @@ var YES = "yes";
5267
3571
  var NO = "no";
5268
3572
  var ISSUE_LABEL = "issue: ";
5269
3573
  var HUMAN_REVIEW_LABELS = /* @__PURE__ */ new Set([NEEDS_HUMAN_REVIEW_LABEL]);
5270
- var label_schema = z17.looseObject({ name: z17.string() });
5271
- var issue_state_schema = z17.looseObject({
5272
- state: z17.string(),
3574
+ var label_schema = z10.looseObject({ name: z10.string() });
3575
+ var issue_state_schema = z10.looseObject({
3576
+ state: z10.string(),
5273
3577
  labels: label_schema.array().optional()
5274
3578
  });
5275
3579
  function parse_issue_state(json) {
@@ -5317,7 +3621,7 @@ var DEFAULT_SILENT_MINUTES = 30;
5317
3621
  var DEFAULT_GAP_SECONDS = 5;
5318
3622
  var MS_PER_MINUTE3 = 6e4;
5319
3623
  var MS_PER_SECOND2 = 1e3;
5320
- var OPEN_STATE3 = "OPEN";
3624
+ var OPEN_STATE2 = "OPEN";
5321
3625
  var STATE_FIELDS = "state,labels";
5322
3626
  var REASONS = {
5323
3627
  [ALIVE_VERDICT]: "The unit is still working: its output moved, or a process of the child is alive.",
@@ -5405,7 +3709,7 @@ function read_agent_state(output_path) {
5405
3709
  const safe_path = to_safe_path(output_path);
5406
3710
  if (safe_path === void 0) return void 0;
5407
3711
  try {
5408
- const state = agent_event.read(readFileSync6(safe_path, "utf8"));
3712
+ const state = agent_event.read(readFileSync5(safe_path, "utf8"));
5409
3713
  return state.provider === void 0 ? void 0 : state;
5410
3714
  } catch {
5411
3715
  return void 0;
@@ -5419,7 +3723,7 @@ async function read_output_frozen(request) {
5419
3723
  const first = sample_output(request.output_path);
5420
3724
  if (first === void 0) return void 0;
5421
3725
  if (request.now_ms - first.mtime_ms < request.silent_window_ms) return false;
5422
- await sleep2(request.gap_ms);
3726
+ await sleep(request.gap_ms);
5423
3727
  const second = sample_output(request.output_path);
5424
3728
  if (second === void 0) return void 0;
5425
3729
  return second.mtime_ms === first.mtime_ms && second.size === first.size;
@@ -5436,7 +3740,7 @@ async function read_child_settled(issue, repo) {
5436
3740
  if (json === void 0) return void 0;
5437
3741
  const state = issue_state.parse_issue_state(json);
5438
3742
  if (state === void 0) return void 0;
5439
- return state.state !== OPEN_STATE3 || carries_settled_label(state.labels);
3743
+ return state.state !== OPEN_STATE2 || carries_settled_label(state.labels);
5440
3744
  }
5441
3745
  async function read_traces(request) {
5442
3746
  const [is_initial_child_settled, is_output_frozen, is_tree_dirty] = await Promise.all([
@@ -5476,14 +3780,14 @@ var run_liveness = {
5476
3780
 
5477
3781
  // scripts/lane/lane-report.ts
5478
3782
  var NO_LANES2 = "No lanes are open.";
5479
- var OPEN_STATE4 = "open";
3783
+ var OPEN_STATE3 = "open";
5480
3784
  var STRANDED_STATE = "stranded";
5481
3785
  var UNREADABLE_STATE = "unreadable";
5482
3786
  var UNKNOWN_VALUE = "-";
5483
3787
  var COLUMN_SEPARATOR = " ";
5484
3788
  function lane_state(lane) {
5485
3789
  if (lane.is_stranded) return STRANDED_STATE;
5486
- return lane.seat === void 0 ? UNREADABLE_STATE : OPEN_STATE4;
3790
+ return lane.seat === void 0 ? UNREADABLE_STATE : OPEN_STATE3;
5487
3791
  }
5488
3792
  function value_or_unknown(value) {
5489
3793
  return value === void 0 ? UNKNOWN_VALUE : String(value);
@@ -5527,7 +3831,7 @@ function describe_opened(lane) {
5527
3831
  }
5528
3832
  var lane_report = {
5529
3833
  NO_LANES: NO_LANES2,
5530
- OPEN_STATE: OPEN_STATE4,
3834
+ OPEN_STATE: OPEN_STATE3,
5531
3835
  STRANDED_STATE,
5532
3836
  UNREADABLE_STATE,
5533
3837
  describe_lane,
@@ -5537,7 +3841,7 @@ var lane_report = {
5537
3841
  };
5538
3842
 
5539
3843
  // scripts/run/run-preflight.ts
5540
- import { z as z18 } from "zod";
3844
+ import { z as z11 } from "zod";
5541
3845
  var CLEAN_VERDICT = "clean";
5542
3846
  var RECLAIM_VERDICT = "reclaim";
5543
3847
  var RESUME_VERDICT = "resume";
@@ -5547,7 +3851,7 @@ var OPEN_PR = "open";
5547
3851
  var MERGED_PR = "merged";
5548
3852
  var CLOSED_PR = "closed";
5549
3853
  var NO_CHILD_WORK = { branch_name: void 0, pr_state: NO_PR };
5550
- var pr_info_schema2 = z18.object({ state: z18.string().optional() });
3854
+ var pr_info_schema = z11.object({ state: z11.string().optional() });
5551
3855
  var GH_PR_STATES = /* @__PURE__ */ new Map([
5552
3856
  ["CLOSED", CLOSED_PR],
5553
3857
  ["MERGED", MERGED_PR],
@@ -5626,12 +3930,12 @@ function decide5(tree, child, issue) {
5626
3930
  }
5627
3931
  function read_pr_field(raw) {
5628
3932
  try {
5629
- return pr_info_schema2.parse(JSON.parse(raw)).state;
3933
+ return pr_info_schema.parse(JSON.parse(raw)).state;
5630
3934
  } catch {
5631
3935
  return void 0;
5632
3936
  }
5633
3937
  }
5634
- function to_pr_state2(raw) {
3938
+ function to_pr_state(raw) {
5635
3939
  const state = read_pr_field(raw);
5636
3940
  return (state === void 0 ? void 0 : GH_PR_STATES.get(state)) ?? NO_PR;
5637
3941
  }
@@ -5643,17 +3947,17 @@ async function read_tree_state() {
5643
3947
  ]);
5644
3948
  return { branch: current, default_branch, is_dirty };
5645
3949
  }
5646
- async function read_pr_state2(branch_name) {
3950
+ async function read_pr_state(branch_name) {
5647
3951
  if (!await git_gh_pr_read.pr_exists(branch_name)) return NO_PR;
5648
3952
  const raw = await git_gh_pr_read.pr_view(branch_name);
5649
3953
  if (raw === "") throw new Error(`${UNREADABLE_PR_MESSAGE}${branch_name}`);
5650
- return to_pr_state2(raw);
3954
+ return to_pr_state(raw);
5651
3955
  }
5652
3956
  function is_pr_open(state) {
5653
3957
  return state === OPEN_PR;
5654
3958
  }
5655
3959
  async function read_pr_of_branch(branch_name) {
5656
- return { branch_name, pr_state: await read_pr_state2(branch_name) };
3960
+ return { branch_name, pr_state: await read_pr_state(branch_name) };
5657
3961
  }
5658
3962
  function pick_child_state(reads) {
5659
3963
  const decided = reads.find((read2) => is_pr_decided(read2.pr_state));
@@ -5728,8 +4032,8 @@ var run_preflight = {
5728
4032
  check: check2,
5729
4033
  decide: decide5,
5730
4034
  read_child_state,
5731
- read_pr_state: read_pr_state2,
5732
- to_pr_state: to_pr_state2
4035
+ read_pr_state,
4036
+ to_pr_state
5733
4037
  };
5734
4038
 
5735
4039
  // scripts/run/run-progress-read.ts
@@ -5829,7 +4133,7 @@ var TICK_MULTIPLIER = 3;
5829
4133
  var MS_PER_SECOND3 = 1e3;
5830
4134
  var STALE_THRESHOLD_MS = WATCHER_TICK_MS * TICK_MULTIPLIER;
5831
4135
  var STALE_THRESHOLD_S = STALE_THRESHOLD_MS / MS_PER_SECOND3;
5832
- var STALE_NOTE = `Lane children are in-flight but the progress watcher has not pinged in the last ${String(STALE_THRESHOLD_S)}s \u2014 run \`pnpm josh run:progress --wait\` in the background before proceeding`;
4136
+ var STALE_NOTE = `Lane children are in-flight but the progress watcher has not pinged in the last ${String(STALE_THRESHOLD_S)}s \u2014 run \`pnpm josh run:progress --wait\` in the background before proceeding. It reports to the run event stream on its own and exits only when newly runnable work arrives, so start it once and relay nothing`;
5833
4137
  var OK_RESULT = { kind: "ok" };
5834
4138
  async function owes_watcher() {
5835
4139
  if (!await run_headless.is_backlog_parent()) return false;
@@ -5849,7 +4153,7 @@ var run_watcher_guard = {
5849
4153
  // scripts/run/run-watcher-hook.ts
5850
4154
  var SWITCH_ENV_KEY2 = "JOSH_WATCHER_GUARD";
5851
4155
  var STAMP_PREFIX2 = "josh-watcher-guard-";
5852
- var payload_schema = z19.object({ transcript_path: z19.string().min(1) });
4156
+ var payload_schema = z12.object({ transcript_path: z12.string().min(1) });
5853
4157
  function transcript_of(raw_payload) {
5854
4158
  try {
5855
4159
  const parsed = payload_schema.safeParse(JSON.parse(raw_payload));
@@ -5910,7 +4214,8 @@ async function refusal_for(transcript, now_ms, state) {
5910
4214
  function is_unit_call(raw_payload) {
5911
4215
  try {
5912
4216
  return (hook_decision.parse_hook_payload(raw_payload)?.agent_id ?? "") !== "";
5913
- } catch {
4217
+ } catch (error) {
4218
+ error_text.trace_swallowed("run_parent_cut_hook.is_unit_call", error);
5914
4219
  return false;
5915
4220
  }
5916
4221
  }