@hunter-harness/workflow-harness 0.2.56 → 0.2.58

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 (190) hide show
  1. package/harness/bundles/general/claude-code/.harness-build.json +1 -1
  2. package/harness/bundles/general/claude-code/harness-archive/SKILL.md +1 -1
  3. package/harness/bundles/general/claude-code/harness-codebase-map/SKILL.md +1 -1
  4. package/harness/bundles/general/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
  5. package/harness/bundles/general/claude-code/harness-knowledge-query/SKILL.md +1 -1
  6. package/harness/bundles/general/claude-code/harness-plan/SKILL.md +1 -1
  7. package/harness/bundles/general/claude-code/harness-review/SKILL.md +5 -3
  8. package/harness/bundles/general/claude-code/harness-review/protocols.md +2 -1
  9. package/harness/bundles/general/claude-code/harness-run/SKILL.md +4 -4
  10. package/harness/bundles/general/claude-code/harness-submit/SKILL.md +1 -1
  11. package/harness/bundles/general/claude-code/harness-sync/SKILL.md +1 -1
  12. package/harness/bundles/general/claude-code/harness-test/SKILL.md +5 -3
  13. package/harness/bundles/general/claude-code/harness-test/reference.md +2 -0
  14. package/harness/bundles/general/claude-code/protocols/report-pipeline-protocol.md +2 -0
  15. package/harness/bundles/general/claude-code/scripts/harness_context.py +423 -77
  16. package/harness/bundles/general/claude-code/scripts/harness_events.py +102 -12
  17. package/harness/bundles/general/claude-code/scripts/harness_events_sync.py +15 -14
  18. package/harness/bundles/general/claude-code/scripts/harness_fixback.py +529 -1
  19. package/harness/bundles/general/claude-code/scripts/harness_gate.py +161 -6
  20. package/harness/bundles/general/claude-code/scripts/harness_ledger.py +81 -8
  21. package/harness/bundles/general/claude-code/scripts/harness_review.py +25 -2
  22. package/harness/bundles/general/claude-code/scripts/harness_test_runner.py +155 -1
  23. package/harness/bundles/general/codebuddy/.harness-build.json +1 -1
  24. package/harness/bundles/general/codebuddy/harness-archive/SKILL.md +1 -1
  25. package/harness/bundles/general/codebuddy/harness-codebase-map/SKILL.md +1 -1
  26. package/harness/bundles/general/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
  27. package/harness/bundles/general/codebuddy/harness-knowledge-query/SKILL.md +1 -1
  28. package/harness/bundles/general/codebuddy/harness-plan/SKILL.md +1 -1
  29. package/harness/bundles/general/codebuddy/harness-review/SKILL.md +5 -3
  30. package/harness/bundles/general/codebuddy/harness-review/protocols.md +2 -1
  31. package/harness/bundles/general/codebuddy/harness-run/SKILL.md +4 -4
  32. package/harness/bundles/general/codebuddy/harness-submit/SKILL.md +1 -1
  33. package/harness/bundles/general/codebuddy/harness-sync/SKILL.md +1 -1
  34. package/harness/bundles/general/codebuddy/harness-test/SKILL.md +5 -3
  35. package/harness/bundles/general/codebuddy/harness-test/reference.md +2 -0
  36. package/harness/bundles/general/codebuddy/protocols/report-pipeline-protocol.md +2 -0
  37. package/harness/bundles/general/codebuddy/scripts/harness_context.py +423 -77
  38. package/harness/bundles/general/codebuddy/scripts/harness_events.py +102 -12
  39. package/harness/bundles/general/codebuddy/scripts/harness_events_sync.py +15 -14
  40. package/harness/bundles/general/codebuddy/scripts/harness_fixback.py +529 -1
  41. package/harness/bundles/general/codebuddy/scripts/harness_gate.py +161 -6
  42. package/harness/bundles/general/codebuddy/scripts/harness_ledger.py +81 -8
  43. package/harness/bundles/general/codebuddy/scripts/harness_review.py +25 -2
  44. package/harness/bundles/general/codebuddy/scripts/harness_test_runner.py +155 -1
  45. package/harness/bundles/general/codex/.harness-build.json +1 -1
  46. package/harness/bundles/general/codex/harness-archive/SKILL.md +1 -1
  47. package/harness/bundles/general/codex/harness-codebase-map/SKILL.md +1 -1
  48. package/harness/bundles/general/codex/harness-knowledge-ingest/SKILL.md +1 -1
  49. package/harness/bundles/general/codex/harness-knowledge-query/SKILL.md +1 -1
  50. package/harness/bundles/general/codex/harness-plan/SKILL.md +1 -1
  51. package/harness/bundles/general/codex/harness-review/SKILL.md +3 -1
  52. package/harness/bundles/general/codex/harness-review/protocols.md +2 -1
  53. package/harness/bundles/general/codex/harness-run/SKILL.md +4 -4
  54. package/harness/bundles/general/codex/harness-submit/SKILL.md +1 -1
  55. package/harness/bundles/general/codex/harness-sync/SKILL.md +1 -1
  56. package/harness/bundles/general/codex/harness-test/SKILL.md +5 -3
  57. package/harness/bundles/general/codex/harness-test/reference.md +2 -0
  58. package/harness/bundles/general/codex/protocols/report-pipeline-protocol.md +2 -0
  59. package/harness/bundles/general/codex/scripts/harness_context.py +423 -77
  60. package/harness/bundles/general/codex/scripts/harness_events.py +102 -12
  61. package/harness/bundles/general/codex/scripts/harness_events_sync.py +15 -14
  62. package/harness/bundles/general/codex/scripts/harness_fixback.py +529 -1
  63. package/harness/bundles/general/codex/scripts/harness_gate.py +161 -6
  64. package/harness/bundles/general/codex/scripts/harness_ledger.py +81 -8
  65. package/harness/bundles/general/codex/scripts/harness_review.py +25 -2
  66. package/harness/bundles/general/codex/scripts/harness_test_runner.py +155 -1
  67. package/harness/bundles/general/cursor/.harness-build.json +1 -1
  68. package/harness/bundles/general/cursor/harness-archive/SKILL.md +1 -1
  69. package/harness/bundles/general/cursor/harness-codebase-map/SKILL.md +1 -1
  70. package/harness/bundles/general/cursor/harness-knowledge-ingest/SKILL.md +1 -1
  71. package/harness/bundles/general/cursor/harness-knowledge-query/SKILL.md +1 -1
  72. package/harness/bundles/general/cursor/harness-plan/SKILL.md +1 -1
  73. package/harness/bundles/general/cursor/harness-review/SKILL.md +3 -1
  74. package/harness/bundles/general/cursor/harness-review/protocols.md +2 -1
  75. package/harness/bundles/general/cursor/harness-run/SKILL.md +4 -4
  76. package/harness/bundles/general/cursor/harness-submit/SKILL.md +1 -1
  77. package/harness/bundles/general/cursor/harness-sync/SKILL.md +1 -1
  78. package/harness/bundles/general/cursor/harness-test/SKILL.md +5 -3
  79. package/harness/bundles/general/cursor/harness-test/reference.md +2 -0
  80. package/harness/bundles/general/cursor/protocols/report-pipeline-protocol.md +2 -0
  81. package/harness/bundles/general/cursor/scripts/harness_context.py +423 -77
  82. package/harness/bundles/general/cursor/scripts/harness_events.py +102 -12
  83. package/harness/bundles/general/cursor/scripts/harness_events_sync.py +15 -14
  84. package/harness/bundles/general/cursor/scripts/harness_fixback.py +529 -1
  85. package/harness/bundles/general/cursor/scripts/harness_gate.py +161 -6
  86. package/harness/bundles/general/cursor/scripts/harness_ledger.py +81 -8
  87. package/harness/bundles/general/cursor/scripts/harness_review.py +25 -2
  88. package/harness/bundles/general/cursor/scripts/harness_test_runner.py +155 -1
  89. package/harness/bundles/java/claude-code/.harness-build.json +1 -1
  90. package/harness/bundles/java/claude-code/harness-apidoc/SKILL.md +1 -1
  91. package/harness/bundles/java/claude-code/harness-archive/SKILL.md +1 -1
  92. package/harness/bundles/java/claude-code/harness-codebase-map/SKILL.md +1 -1
  93. package/harness/bundles/java/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
  94. package/harness/bundles/java/claude-code/harness-knowledge-query/SKILL.md +1 -1
  95. package/harness/bundles/java/claude-code/harness-package/SKILL.md +1 -1
  96. package/harness/bundles/java/claude-code/harness-plan/SKILL.md +1 -1
  97. package/harness/bundles/java/claude-code/harness-review/SKILL.md +5 -3
  98. package/harness/bundles/java/claude-code/harness-review/protocols.md +2 -1
  99. package/harness/bundles/java/claude-code/harness-run/SKILL.md +4 -4
  100. package/harness/bundles/java/claude-code/harness-submit/SKILL.md +1 -1
  101. package/harness/bundles/java/claude-code/harness-sync/SKILL.md +1 -1
  102. package/harness/bundles/java/claude-code/harness-test/SKILL.md +5 -3
  103. package/harness/bundles/java/claude-code/protocols/report-pipeline-protocol.md +2 -0
  104. package/harness/bundles/java/claude-code/scripts/harness_context.py +423 -77
  105. package/harness/bundles/java/claude-code/scripts/harness_events.py +102 -12
  106. package/harness/bundles/java/claude-code/scripts/harness_events_sync.py +15 -14
  107. package/harness/bundles/java/claude-code/scripts/harness_fixback.py +529 -1
  108. package/harness/bundles/java/claude-code/scripts/harness_gate.py +161 -6
  109. package/harness/bundles/java/claude-code/scripts/harness_ledger.py +81 -8
  110. package/harness/bundles/java/claude-code/scripts/harness_review.py +25 -2
  111. package/harness/bundles/java/claude-code/scripts/harness_test_runner.py +155 -1
  112. package/harness/bundles/java/codebuddy/.harness-build.json +1 -1
  113. package/harness/bundles/java/codebuddy/harness-apidoc/SKILL.md +1 -1
  114. package/harness/bundles/java/codebuddy/harness-archive/SKILL.md +1 -1
  115. package/harness/bundles/java/codebuddy/harness-codebase-map/SKILL.md +1 -1
  116. package/harness/bundles/java/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
  117. package/harness/bundles/java/codebuddy/harness-knowledge-query/SKILL.md +1 -1
  118. package/harness/bundles/java/codebuddy/harness-package/SKILL.md +1 -1
  119. package/harness/bundles/java/codebuddy/harness-plan/SKILL.md +1 -1
  120. package/harness/bundles/java/codebuddy/harness-review/SKILL.md +5 -3
  121. package/harness/bundles/java/codebuddy/harness-review/protocols.md +2 -1
  122. package/harness/bundles/java/codebuddy/harness-run/SKILL.md +4 -4
  123. package/harness/bundles/java/codebuddy/harness-submit/SKILL.md +1 -1
  124. package/harness/bundles/java/codebuddy/harness-sync/SKILL.md +1 -1
  125. package/harness/bundles/java/codebuddy/harness-test/SKILL.md +5 -3
  126. package/harness/bundles/java/codebuddy/protocols/report-pipeline-protocol.md +2 -0
  127. package/harness/bundles/java/codebuddy/scripts/harness_context.py +423 -77
  128. package/harness/bundles/java/codebuddy/scripts/harness_events.py +102 -12
  129. package/harness/bundles/java/codebuddy/scripts/harness_events_sync.py +15 -14
  130. package/harness/bundles/java/codebuddy/scripts/harness_fixback.py +529 -1
  131. package/harness/bundles/java/codebuddy/scripts/harness_gate.py +161 -6
  132. package/harness/bundles/java/codebuddy/scripts/harness_ledger.py +81 -8
  133. package/harness/bundles/java/codebuddy/scripts/harness_review.py +25 -2
  134. package/harness/bundles/java/codebuddy/scripts/harness_test_runner.py +155 -1
  135. package/harness/bundles/java/codex/.harness-build.json +1 -1
  136. package/harness/bundles/java/codex/harness-apidoc/SKILL.md +1 -1
  137. package/harness/bundles/java/codex/harness-archive/SKILL.md +1 -1
  138. package/harness/bundles/java/codex/harness-codebase-map/SKILL.md +1 -1
  139. package/harness/bundles/java/codex/harness-knowledge-ingest/SKILL.md +1 -1
  140. package/harness/bundles/java/codex/harness-knowledge-query/SKILL.md +1 -1
  141. package/harness/bundles/java/codex/harness-package/SKILL.md +1 -1
  142. package/harness/bundles/java/codex/harness-plan/SKILL.md +1 -1
  143. package/harness/bundles/java/codex/harness-review/SKILL.md +3 -1
  144. package/harness/bundles/java/codex/harness-review/protocols.md +2 -1
  145. package/harness/bundles/java/codex/harness-run/SKILL.md +4 -4
  146. package/harness/bundles/java/codex/harness-submit/SKILL.md +1 -1
  147. package/harness/bundles/java/codex/harness-sync/SKILL.md +1 -1
  148. package/harness/bundles/java/codex/harness-test/SKILL.md +5 -3
  149. package/harness/bundles/java/codex/protocols/report-pipeline-protocol.md +2 -0
  150. package/harness/bundles/java/codex/scripts/harness_context.py +423 -77
  151. package/harness/bundles/java/codex/scripts/harness_events.py +102 -12
  152. package/harness/bundles/java/codex/scripts/harness_events_sync.py +15 -14
  153. package/harness/bundles/java/codex/scripts/harness_fixback.py +529 -1
  154. package/harness/bundles/java/codex/scripts/harness_gate.py +161 -6
  155. package/harness/bundles/java/codex/scripts/harness_ledger.py +81 -8
  156. package/harness/bundles/java/codex/scripts/harness_review.py +25 -2
  157. package/harness/bundles/java/codex/scripts/harness_test_runner.py +155 -1
  158. package/harness/bundles/java/cursor/.harness-build.json +1 -1
  159. package/harness/bundles/java/cursor/harness-apidoc/SKILL.md +1 -1
  160. package/harness/bundles/java/cursor/harness-archive/SKILL.md +1 -1
  161. package/harness/bundles/java/cursor/harness-codebase-map/SKILL.md +1 -1
  162. package/harness/bundles/java/cursor/harness-knowledge-ingest/SKILL.md +1 -1
  163. package/harness/bundles/java/cursor/harness-knowledge-query/SKILL.md +1 -1
  164. package/harness/bundles/java/cursor/harness-package/SKILL.md +1 -1
  165. package/harness/bundles/java/cursor/harness-plan/SKILL.md +1 -1
  166. package/harness/bundles/java/cursor/harness-review/SKILL.md +3 -1
  167. package/harness/bundles/java/cursor/harness-review/protocols.md +2 -1
  168. package/harness/bundles/java/cursor/harness-run/SKILL.md +4 -4
  169. package/harness/bundles/java/cursor/harness-submit/SKILL.md +1 -1
  170. package/harness/bundles/java/cursor/harness-sync/SKILL.md +1 -1
  171. package/harness/bundles/java/cursor/harness-test/SKILL.md +5 -3
  172. package/harness/bundles/java/cursor/protocols/report-pipeline-protocol.md +2 -0
  173. package/harness/bundles/java/cursor/scripts/harness_context.py +423 -77
  174. package/harness/bundles/java/cursor/scripts/harness_events.py +102 -12
  175. package/harness/bundles/java/cursor/scripts/harness_events_sync.py +15 -14
  176. package/harness/bundles/java/cursor/scripts/harness_fixback.py +529 -1
  177. package/harness/bundles/java/cursor/scripts/harness_gate.py +161 -6
  178. package/harness/bundles/java/cursor/scripts/harness_ledger.py +81 -8
  179. package/harness/bundles/java/cursor/scripts/harness_review.py +25 -2
  180. package/harness/bundles/java/cursor/scripts/harness_test_runner.py +155 -1
  181. package/harness/manifests/general/claude-code.json +24 -24
  182. package/harness/manifests/general/codebuddy.json +24 -24
  183. package/harness/manifests/general/codex.json +24 -24
  184. package/harness/manifests/general/cursor.json +24 -24
  185. package/harness/manifests/java/claude-code.json +25 -25
  186. package/harness/manifests/java/codebuddy.json +25 -25
  187. package/harness/manifests/java/codex.json +25 -25
  188. package/harness/manifests/java/cursor.json +25 -25
  189. package/hunter-workflow-family.json +5 -5
  190. package/package.json +1 -1
@@ -71,6 +71,8 @@ EVENT_TYPES = frozenset(
71
71
  "phase.start",
72
72
  "phase.end",
73
73
  "phase.auto_sealed",
74
+ "phase.prepare.start",
75
+ "phase.prepare.end",
74
76
  "gate.blocked",
75
77
  "gate.recovered",
76
78
  "command",
@@ -160,8 +162,21 @@ _PROVENANCE_FIELDS = frozenset(
160
162
  "result_status",
161
163
  }
162
164
  )
165
+ _REVIEW_DECISION_REASON_CODES = frozenset({"REVIEW_DELEGATED"})
166
+ _REVIEW_FALLBACK_REASON_CODES = frozenset(
167
+ {
168
+ "REVIEW_INLINE_UNAVAILABLE",
169
+ "REVIEW_INLINE_SPAWN_FAILED",
170
+ "REVIEW_INLINE_INVALID_RESULT",
171
+ }
172
+ )
163
173
  _EVENT_ALLOWED_FIELDS = {
164
174
  "phase.start": frozenset({"note"}) | _PROVENANCE_FIELDS,
175
+ "phase.prepare.start": frozenset({"note"}) | _PROVENANCE_FIELDS,
176
+ "phase.prepare.end": frozenset(
177
+ {"status", "code", "message", "reason", "note", "duration_ms"}
178
+ )
179
+ | _PROVENANCE_FIELDS,
165
180
  "phase.end": frozenset(
166
181
  {"status", "duration_ms", "note", "reason", "issue_id"}
167
182
  )
@@ -212,6 +227,7 @@ _EVENT_REQUIRED_FIELDS = {
212
227
  "reason",
213
228
  ),
214
229
  "phase.auto_sealed": ("reason",),
230
+ "phase.prepare.end": ("status",),
215
231
  }
216
232
  _CORRECTION_PROTECTED_FIELDS = frozenset(
217
233
  {"schema_version", "id", "timestamp", "phase", "type"}
@@ -591,10 +607,28 @@ def append_event(
591
607
  phase: str,
592
608
  type_: str,
593
609
  note: str = "",
610
+ status: str | None = None,
611
+ code: str | None = None,
612
+ message: str | None = None,
613
+ reason: str | None = None,
614
+ duration_ms: int | None = None,
594
615
  kind: str | None = None,
595
616
  path: str | None = None,
596
617
  run_id: str | None = None,
618
+ attempt: int | None = None,
597
619
  executor_tool: str | None = None,
620
+ executor_agent: str | None = None,
621
+ executor_model: str | None = None,
622
+ execution_mode: str | None = None,
623
+ decision_reason_code: str | None = None,
624
+ fallback_reason_code: str | None = None,
625
+ trigger: str | None = None,
626
+ from_phase: str | None = None,
627
+ result_status: str | None = None,
628
+ runner_ms: int | None = None,
629
+ orchestration_active_ms: int | None = None,
630
+ wall_clock_ms: int | None = None,
631
+ user_wait_ms: int | None = None,
598
632
  renamed_from: str | None = None,
599
633
  renamed_to: str | None = None,
600
634
  change_uuid: str | None = None,
@@ -615,14 +649,14 @@ def append_event(
615
649
  executor_tool=executor_tool,
616
650
  command=None,
617
651
  exit_code=None,
618
- duration_ms=None,
619
- status=None,
652
+ duration_ms=duration_ms,
653
+ status=status,
620
654
  name=None,
621
- code=None,
655
+ code=code,
622
656
  severity=None,
623
- message=None,
657
+ message=message,
624
658
  decision=None,
625
- reason=None,
659
+ reason=reason,
626
660
  issue_id=None,
627
661
  scope=None,
628
662
  target_event_id=None,
@@ -632,18 +666,24 @@ def append_event(
632
666
  renamed_from=renamed_from,
633
667
  renamed_to=renamed_to,
634
668
  change_uuid=change_uuid,
635
- attempt=None,
636
- executor_agent=None,
637
- executor_model=None,
669
+ attempt=attempt,
670
+ executor_agent=executor_agent,
671
+ executor_model=executor_model,
638
672
  handoff_from_tool=None,
639
673
  handoff_reason=None,
640
674
  trace_id=None,
641
675
  span_id=None,
642
676
  parent_span_id=None,
643
- runner_ms=None,
644
- orchestration_active_ms=None,
645
- wall_clock_ms=None,
646
- user_wait_ms=None,
677
+ runner_ms=runner_ms,
678
+ orchestration_active_ms=orchestration_active_ms,
679
+ wall_clock_ms=wall_clock_ms,
680
+ user_wait_ms=user_wait_ms,
681
+ execution_mode=execution_mode,
682
+ decision_reason_code=decision_reason_code,
683
+ fallback_reason_code=fallback_reason_code,
684
+ trigger=trigger,
685
+ from_phase=from_phase,
686
+ result_status=result_status,
647
687
  legacy_lenient=False,
648
688
  json=True,
649
689
  )
@@ -875,6 +915,56 @@ def validate_append_event(args: argparse.Namespace) -> tuple[str, str] | None:
875
915
  "EVENT_TIMING_FIELD_INVALID",
876
916
  f"EVENT_TIMING_FIELD_INVALID: --{field.replace('_', '-')} must be a nonnegative integer",
877
917
  )
918
+ if event_type == "decision" and str(getattr(args, "phase", "")) == "review":
919
+ body = "\n".join(
920
+ str(getattr(args, field, "") or "")
921
+ for field in ("decision", "reason", "note")
922
+ )
923
+ if re.search(r"\bREVIEW_[A-Z0-9_]+\b", body):
924
+ return (
925
+ "EVENT_REVIEW_REASON_IN_BODY",
926
+ "EVENT_REVIEW_REASON_IN_BODY: 评审原因码只能写入结构化字段,正文请使用中文说明",
927
+ )
928
+ execution_mode = str(getattr(args, "execution_mode", "") or "").strip()
929
+ decision_code = str(
930
+ getattr(args, "decision_reason_code", "") or ""
931
+ ).strip()
932
+ fallback_code = str(
933
+ getattr(args, "fallback_reason_code", "") or ""
934
+ ).strip()
935
+ structured = bool(execution_mode or decision_code or fallback_code)
936
+ if structured and execution_mode not in {"delegated", "inline"}:
937
+ return (
938
+ "EVENT_REVIEW_EXECUTION_MODE_INVALID",
939
+ "EVENT_REVIEW_EXECUTION_MODE_INVALID: execution-mode 必须为 delegated 或 inline",
940
+ )
941
+ if decision_code and decision_code not in _REVIEW_DECISION_REASON_CODES:
942
+ return (
943
+ "EVENT_REVIEW_REASON_INVALID",
944
+ "EVENT_REVIEW_REASON_INVALID: 未知的评审委派原因码",
945
+ )
946
+ if fallback_code and fallback_code not in _REVIEW_FALLBACK_REASON_CODES:
947
+ return (
948
+ "EVENT_REVIEW_REASON_INVALID",
949
+ "EVENT_REVIEW_REASON_INVALID: 未知的评审回退原因码",
950
+ )
951
+ if execution_mode == "delegated":
952
+ if (
953
+ decision_code != "REVIEW_DELEGATED"
954
+ or fallback_code
955
+ or not str(getattr(args, "executor_agent", "") or "").strip()
956
+ ):
957
+ return (
958
+ "EVENT_REVIEW_REASON_INVALID",
959
+ "EVENT_REVIEW_REASON_INVALID: 委派评审必须记录执行 Agent 和 REVIEW_DELEGATED",
960
+ )
961
+ if execution_mode == "inline" and (
962
+ decision_code or fallback_code not in _REVIEW_FALLBACK_REASON_CODES
963
+ ):
964
+ return (
965
+ "EVENT_REVIEW_REASON_INVALID",
966
+ "EVENT_REVIEW_REASON_INVALID: 主会话评审必须记录一个稳定的回退原因码",
967
+ )
878
968
  if event_type == "phase.auto_sealed":
879
969
  reason_value = str(getattr(args, "reason", "") or "").strip()
880
970
  if reason_value and reason_value not in _AUTO_SEAL_REASONS:
@@ -804,25 +804,26 @@ class _CrossProcessLock:
804
804
  def _windowless_python_executable(
805
805
  executable: str, base_executable: str | None
806
806
  ) -> str:
807
- """Return a Windows interpreter that cannot allocate a console window.
808
-
809
- Virtual-environment ``python.exe`` files may be forwarding launchers. Even
810
- when the first process is created with ``CREATE_NO_WINDOW``, such a launcher
811
- can start the real console interpreter and make Windows Terminal flash. A
812
- sibling ``pythonw.exe`` preserves the windowless subsystem across that hop.
807
+ """Return the real Windows interpreter, bypassing venv forwarding launchers.
808
+
809
+ Virtual-environment ``python.exe`` and ``pythonw.exe`` files may both be
810
+ forwarding launchers. The forwarding hop can start the real console
811
+ interpreter without preserving ``CREATE_NO_WINDOW`` and make Windows
812
+ Terminal appear. Prefer the base runtime directly; its ``pythonw.exe`` is
813
+ ideal, while its console executable remains windowless under our explicit
814
+ process creation flags.
813
815
  """
814
816
  executable_path = Path(executable)
815
- candidates = [executable_path.with_name("pythonw.exe")]
816
817
  if base_executable:
817
818
  base_path = Path(base_executable)
818
819
  base_windowless = base_path.with_name("pythonw.exe")
819
- if base_windowless not in candidates:
820
- candidates.append(base_windowless)
821
- for candidate in candidates:
822
- if candidate.is_file():
823
- return str(candidate)
824
- if base_executable and Path(base_executable).is_file():
825
- return str(Path(base_executable))
820
+ if base_windowless.is_file():
821
+ return str(base_windowless)
822
+ if base_path.is_file():
823
+ return str(base_path)
824
+ windowless = executable_path.with_name("pythonw.exe")
825
+ if windowless.is_file():
826
+ return str(windowless)
826
827
  return str(executable_path)
827
828
 
828
829