claude-dev-env 7.5.0 → 7.6.1

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 (125) hide show
  1. package/.agents/skills/everything-search/scripts/everything_search.py +11 -0
  2. package/.agents/skills/everything-search/scripts/test_everything_search.py +1 -0
  3. package/.agents/skills/fresh-branch/SKILL.md +1 -0
  4. package/.agents/skills/fresh-branch/scripts/fresh_branch_git_commands.py +3 -0
  5. package/.agents/skills/fresh-branch/scripts/subprocess_window_access.py +43 -0
  6. package/.agents/skills/session-continuity/README.md +19 -9
  7. package/.agents/skills/syncing-submodules/SKILL.md +1 -0
  8. package/.agents/skills/syncing-submodules/scripts/submodule_sync.py +4 -0
  9. package/.agents/skills/syncing-submodules/scripts/subprocess_window_access.py +43 -0
  10. package/.agents/skills/test-runner/SKILL.md +1 -0
  11. package/.agents/skills/test-runner/scripts/preflight_checks.py +5 -0
  12. package/.agents/skills/test-runner/scripts/run_tests.py +11 -0
  13. package/.agents/skills/test-runner/scripts/subprocess_window_access.py +43 -0
  14. package/.agents/skills/test-runner/scripts/test_run_tests.py +9 -7
  15. package/_shared/pr-loop/scripts/check_bugbot_ci.py +3 -0
  16. package/_shared/pr-loop/scripts/check_convergence_gates.py +3 -0
  17. package/_shared/pr-loop/scripts/check_pending_reviews.py +3 -0
  18. package/_shared/pr-loop/scripts/code_rules_gate_parts/added_line_maps.py +3 -0
  19. package/_shared/pr-loop/scripts/code_rules_gate_parts/baseline_import_isolation.py +3 -0
  20. package/_shared/pr-loop/scripts/code_rules_gate_parts/git_blob_readers.py +5 -0
  21. package/_shared/pr-loop/scripts/code_rules_gate_parts/git_file_sets.py +4 -0
  22. package/_shared/pr-loop/scripts/code_rules_gate_parts/staged_test_regression.py +3 -0
  23. package/_shared/pr-loop/scripts/code_rules_gate_parts/staged_test_running.py +3 -0
  24. package/_shared/pr-loop/scripts/codex_usage_probe.py +3 -0
  25. package/_shared/pr-loop/scripts/copilot_quota.py +3 -0
  26. package/_shared/pr-loop/scripts/fetch_copilot_reviews.py +3 -0
  27. package/_shared/pr-loop/scripts/fix_hookspath.py +7 -0
  28. package/_shared/pr-loop/scripts/post_fix_reply.py +4 -0
  29. package/_shared/pr-loop/scripts/preflight.py +7 -0
  30. package/_shared/pr-loop/scripts/preflight_self_heal.py +5 -0
  31. package/_shared/pr-loop/scripts/run_codex_review.py +3 -0
  32. package/_shared/pr-loop/scripts/subprocess_window_access.py +41 -0
  33. package/_shared/pr-loop/scripts/terminology_sweep.py +5 -0
  34. package/_shared/process-tree/scripts/process_tree_kill.py +3 -0
  35. package/_shared/process-tree/scripts/subprocess_window_access.py +41 -0
  36. package/bin/install-constants.mjs +4 -2
  37. package/bin/install-session-continuity.mjs +73 -30
  38. package/bin/install-session-continuity.test.mjs +52 -1
  39. package/bin/install.cursor-rules.test.mjs +57 -15
  40. package/bin/install.mjs +80 -15
  41. package/bin/install.test.mjs +57 -0
  42. package/bin/pstack-model-preferences.claude.json +23 -0
  43. package/hooks/advisory/pr_done_reminder.py +7 -0
  44. package/hooks/advisory/refactor_guard.py +8 -0
  45. package/hooks/advisory/test_pr_done_reminder.py +21 -0
  46. package/hooks/advisory/test_refactor_guard.py +40 -0
  47. package/hooks/blocking/block_main_commit.py +4 -0
  48. package/hooks/blocking/code_rules_comments.py +39 -5
  49. package/hooks/blocking/pii_prevention_blocker_parts/repository_exemption.py +3 -0
  50. package/hooks/blocking/precommit_code_rules_gate.py +3 -0
  51. package/hooks/blocking/tdd_enforcer_parts/content_analysis.py +19 -3
  52. package/hooks/blocking/tdd_enforcer_parts/git_tracking.py +4 -0
  53. package/hooks/blocking/tdd_enforcer_parts/tests/test_content_analysis.py +25 -0
  54. package/hooks/blocking/test_code_rules_enforcer_comment_string_awareness.py +27 -0
  55. package/hooks/blocking/test_code_rules_enforcer_exempt_marker_chained.py +10 -0
  56. package/hooks/git-hooks/git_hooks_constants/verification_notice_constants.py +0 -2
  57. package/hooks/git-hooks/pull_request_handoff.py +3 -0
  58. package/hooks/git-hooks/subprocess_window_access.py +41 -0
  59. package/hooks/git-hooks/test_verification_start.py +4 -0
  60. package/hooks/git-hooks/verification_notice_context.py +3 -0
  61. package/hooks/git-hooks/verification_start.py +7 -8
  62. package/hooks/hooks_constants/code_rules_enforcer_constants.py +2 -0
  63. package/hooks/hooks_constants/subprocess_window.py +141 -0
  64. package/hooks/hooks_constants/subprocess_window_constants.py +9 -0
  65. package/hooks/hooks_constants/test_code_rules_enforcer_constants.py +6 -0
  66. package/hooks/hooks_constants/test_subprocess_window.py +128 -0
  67. package/hooks/lifecycle/enter_worktree_origin_prefetch.py +3 -0
  68. package/hooks/validation/mypy_validator.py +4 -0
  69. package/hooks/validators/README.md +1 -0
  70. package/hooks/validators/git_checks.py +4 -0
  71. package/hooks/validators/health_check.py +3 -0
  72. package/hooks/validators/hook_timing_harness.py +3 -0
  73. package/hooks/validators/mypy_integration.py +4 -0
  74. package/hooks/validators/ruff_integration.py +6 -0
  75. package/hooks/validators/run_all_validators.py +7 -0
  76. package/hooks/validators/subprocess_window_access.py +41 -0
  77. package/hooks/workflow/auto_formatter.py +8 -0
  78. package/hooks/workflow/test_auto_formatter.py +39 -0
  79. package/package.json +1 -1
  80. package/rules/pstack-models.md +4 -3
  81. package/scripts/automatic_advisory/checkout.py +8 -1
  82. package/scripts/automatic_advisory/cli.py +9 -3
  83. package/scripts/automatic_advisory/config/constants.py +0 -2
  84. package/scripts/automatic_advisory/execution.py +7 -1
  85. package/scripts/automatic_advisory/git.py +9 -1
  86. package/scripts/automatic_advisory/process_host.py +3 -0
  87. package/scripts/claude_chain_runner.py +3 -0
  88. package/scripts/gh_artifact_upload.py +3 -0
  89. package/scripts/grok_headless_runner.py +3 -0
  90. package/scripts/grok_patch_artifacts.py +4 -0
  91. package/scripts/grok_worker_preflight.py +3 -0
  92. package/scripts/invoke_code_review.py +3 -0
  93. package/scripts/local_verification/command_runner.py +3 -0
  94. package/scripts/local_verification/git_state.py +3 -0
  95. package/scripts/policy_lint/adapter_detectors.py +48 -2
  96. package/scripts/policy_lint/adapter_pairing.py +150 -2
  97. package/scripts/policy_lint/adapters.py +46 -4
  98. package/scripts/policy_lint/config/approved_test_pairs.py +25 -9
  99. package/scripts/policy_lint/config/constants.py +3 -0
  100. package/scripts/policy_lint/registry.py +1 -1
  101. package/scripts/policy_lint/selection_git.py +11 -0
  102. package/scripts/repository_checks/config/constants.py +5 -0
  103. package/scripts/repository_checks/config/policy_document.py +19 -0
  104. package/scripts/repository_checks/email_exemptions.py +14 -71
  105. package/scripts/repository_checks/path_exemptions.py +35 -0
  106. package/scripts/repository_checks/policy_document.py +120 -0
  107. package/scripts/repository_checks/tracked_secrets.py +27 -4
  108. package/scripts/setup_project_paths.py +3 -0
  109. package/scripts/spawn_grok_batch.py +3 -0
  110. package/scripts/subprocess_window_access.py +41 -0
  111. package/scripts/test_dispatcher_profile_import.py +4 -0
  112. package/scripts/tests/test_automatic_advisory_window_flags.py +17 -11
  113. package/scripts/tests/test_email_exemptions.py +37 -0
  114. package/scripts/tests/test_path_exemptions.py +164 -0
  115. package/scripts/tests/test_policy_document.py +104 -0
  116. package/scripts/tests/test_policy_lint_rules_function_length_scope.py +101 -0
  117. package/scripts/tests/test_policy_lint_rules_pairing.py +375 -0
  118. package/scripts/tests/test_policy_lint_rules_registry.py +116 -0
  119. package/scripts/tests/test_policy_lint_selection.py +34 -0
  120. package/scripts/tests/test_subprocess_window_access.py +118 -0
  121. package/scripts/tests/test_tracked_secrets.py +79 -0
  122. package/scripts/validate_instruction_pairs.py +3 -0
  123. package/scripts/verify_installable_package.py +5 -0
  124. package/scripts/automatic_advisory/window_flags.py +0 -41
  125. package/scripts/repository_checks/config/email_exemptions.py +0 -10
@@ -25,6 +25,16 @@ from everything_search_command_constants.config.constants import (
25
25
  UTF8_ENCODING,
26
26
  )
27
27
 
28
+ _subprocess_window_hooks_directory = ""
29
+ for each_ancestor_directory in Path(__file__).resolve().parents:
30
+ if (each_ancestor_directory / "hooks" / "hooks_constants").is_dir():
31
+ _subprocess_window_hooks_directory = str(each_ancestor_directory / "hooks")
32
+ break
33
+ if _subprocess_window_hooks_directory not in sys.path:
34
+ sys.path.append(_subprocess_window_hooks_directory)
35
+
36
+ from hooks_constants.subprocess_window import hidden_window_creation_flags
37
+
28
38
 
29
39
  class RegistryRunFatal(ValueError):
30
40
  """Stop the run when the project-path registry is unreadable or invalid."""
@@ -134,6 +144,7 @@ def _run_search(
134
144
  encoding=UTF8_ENCODING,
135
145
  shell=False,
136
146
  text=True,
147
+ creationflags=hidden_window_creation_flags(),
137
148
  )
138
149
  except OSError as error:
139
150
  search_stderr.write(f"{error}\n")
@@ -102,6 +102,7 @@ def test_main_runs_direct_search_without_registry_or_shell() -> None:
102
102
  encoding="utf-8",
103
103
  shell=False,
104
104
  text=True,
105
+ creationflags=search.hidden_window_creation_flags(),
105
106
  )
106
107
 
107
108
 
@@ -121,6 +121,7 @@ Further edits for the new branch belong in `worktree_path`, not in the caller's
121
121
  | `CLAUDE.md` | Package map for agents browsing the skill folder |
122
122
  | `scripts/create_fresh_branch.py` | **Execute** — deterministic fetch + worktree branch CLI |
123
123
  | `scripts/fresh_branch_git_commands.py` | Git command helpers behind the CLI (fetch, ref checks, worktree add) |
124
+ | `scripts/subprocess_window_access.py` | Deployed-path shim re-exporting the hidden-window helpers |
124
125
  | `scripts/test_create_fresh_branch.py` | Real-repo tests for agent/path/CLI behavior |
125
126
  | `scripts/test_fresh_branch_git_commands.py` | Real-repo tests for the git command helpers |
126
127
  | `scripts/fresh_branch_scripts_constants/` | Named constants for the CLI |
@@ -46,6 +46,8 @@ from fresh_branch_scripts_constants.fresh_branch_cli_constants import (
46
46
  GIT_WORKTREE_ADD,
47
47
  )
48
48
 
49
+ from subprocess_window_access import hidden_window_creation_flags
50
+
49
51
 
50
52
  def run_git(
51
53
  all_git_arguments: list[str],
@@ -66,6 +68,7 @@ def run_git(
66
68
  check=False,
67
69
  capture_output=True,
68
70
  text=True,
71
+ creationflags=hidden_window_creation_flags(),
69
72
  )
70
73
 
71
74
 
@@ -0,0 +1,43 @@
1
+ """Reach the hidden-window helpers from the scripts this directory deploys.
2
+
3
+ The installer copies this directory into a profile that holds no installed
4
+ Python distribution, and this repository's own tests run the deployed scripts
5
+ under ``python -S -E``, which hides every installed package from the child
6
+ process. On both routes ``hooks_constants`` is reachable only through the
7
+ deployed ``hooks`` directory, so this module puts that directory on
8
+ ``sys.path`` and re-exports the helpers a caller asks for::
9
+
10
+ from subprocess_window_access import hidden_window_creation_flags
11
+
12
+ The directory goes on the end of ``sys.path``. ``PathFinder`` runs ahead of
13
+ every editable-install finder, so a trailing entry still selects the deployed
14
+ copy, and the head of ``sys.path`` stays exactly as the caller left it. A
15
+ caller that prepended its own roots keeps them first.
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import sys
21
+ from pathlib import Path
22
+
23
+ _subprocess_window_hooks_directory = ""
24
+ for each_ancestor_directory in Path(__file__).resolve().parents:
25
+ if (each_ancestor_directory / "hooks" / "hooks_constants").is_dir():
26
+ _subprocess_window_hooks_directory = str(each_ancestor_directory / "hooks")
27
+ break
28
+ if _subprocess_window_hooks_directory not in sys.path:
29
+ sys.path.append(_subprocess_window_hooks_directory)
30
+
31
+ from hooks_constants.subprocess_window import (
32
+ HiddenWindowStartupInfo,
33
+ detached_hidden_window_creation_flags,
34
+ hidden_window_creation_flags,
35
+ inherited_stream_startup_info,
36
+ )
37
+
38
+ __all__ = [
39
+ "HiddenWindowStartupInfo",
40
+ "detached_hidden_window_creation_flags",
41
+ "hidden_window_creation_flags",
42
+ "inherited_stream_startup_info",
43
+ ]
@@ -1,7 +1,10 @@
1
1
  # Session continuity companion
2
2
 
3
3
  Status: draft implementation. Claude, Codex, and Cursor adapters have
4
- repository-level contract tests. Installed-host activation, reload, and agent
4
+ repository-level contract tests. Claude installed-host automatic activation is
5
+ verified: a headless `claude -p` session on Claude Code 2.1.268 created a new
6
+ session-scope record carrying the `automatic` flag, with no user invocation.
7
+ Codex and Cursor installed-host activation, post-compaction reload, and agent
5
8
  compliance remain unverified.
6
9
 
7
10
  Every supported host activates Poteto Mode automatically when a session starts
@@ -27,21 +30,28 @@ pstack manifest refresher exposes namespaced Claude skills and leaves pstack
27
30
  content with its existing owner. The companion edits none of that source,
28
31
  manifest, invocation code, or model policy.
29
32
 
30
- From this checkout, run the full existing installer, then the focused hook setup:
33
+ From this checkout, run the full existing installer:
31
34
 
32
35
  ```sh
33
36
  node packages/claude-dev-env/bin/install.mjs
37
+ ```
38
+
39
+ The full installer publishes this skill under the canonical agents home and
40
+ registers its hooks in every host configuration the install root resolves. No
41
+ second command is needed. A selective `--only <group>` install skips both steps,
42
+ and a plugin-only installation needs the canonical installed skill first. For
43
+ either of those, or to configure one host alone, run the focused setup:
44
+
45
+ ```sh
34
46
  node packages/claude-dev-env/bin/install-session-continuity.mjs
35
47
  ```
36
48
 
37
- The full installer publishes this skill under the canonical agents home. This
38
- setup is required once for each selected host/profile, not once per invocation.
39
- The existing selective `--only core` list does not include the companion in this
40
- draft. Use the full install above. Plugin-only installations need the same
41
- canonical installed skill before this setup can run.
49
+ The focused setup defaults to `claude codex cursor`. Pass one or more host names
50
+ to configure that subset alone. Registration is idempotent, so running it after a
51
+ full install reports each host as already configured.
42
52
 
43
- The setup defaults to `claude codex cursor`. Pass one or more host names to
44
- configure that subset alone.
53
+ An uninstall removes the companion's registrations along with its files, so no
54
+ host keeps a hook pointing at a script that is gone.
45
55
  It uses `bin/resolve-install-root.mjs`, including `CLAUDE_CONFIG_DIR` and
46
56
  `CODEX_HOME`. It merges only its own hook groups into Claude `settings.json` and
47
57
  Codex `hooks.json`, preserves other settings, writes a one-time backup before
@@ -89,6 +89,7 @@ If `/pr-title-description` is not installed, report `pull_request_url` and finis
89
89
  | `reference/run-tasks.md` | Task seeds for each repository-changing run |
90
90
  | `scripts/sync_parent_pointer.py` | Execute the parent pointer sync and return one JSON result |
91
91
  | `scripts/submodule_sync.py` | Own the Git operation and typed sync report |
92
+ | `scripts/subprocess_window_access.py` | Re-export the hidden-window helpers from the deployed hooks directory |
92
93
  | `scripts/test_sync_parent_pointer.py` | Prove command parsing, JSON output, and hook deletion |
93
94
  | `scripts/test_submodule_sync.py` | Prove exact commits, preserved staging, no-op states, and failures |
94
95
  | `scripts/submodule_sync_constants/__init__.py` | Mark the constants package |
@@ -46,6 +46,8 @@ from submodule_sync_constants.config.constants import (
46
46
  UTF8_ENCODING,
47
47
  )
48
48
 
49
+ from subprocess_window_access import hidden_window_creation_flags
50
+
49
51
 
50
52
  class SyncStatus(StrEnum):
51
53
  """States reported by one parent-pointer sync."""
@@ -123,6 +125,7 @@ def _execute_git(
123
125
  errors=DECODE_ERRORS_POLICY,
124
126
  env=_build_child_environment(),
125
127
  timeout=GIT_COMMAND_TIMEOUT_SECONDS,
128
+ creationflags=hidden_window_creation_flags(),
126
129
  )
127
130
  except subprocess.TimeoutExpired as error:
128
131
  raise _GitCommandFailure(
@@ -179,6 +182,7 @@ def lookup_pull_request_url(repository: Path) -> str | None:
179
182
  errors=DECODE_ERRORS_POLICY,
180
183
  env=_build_child_environment(),
181
184
  timeout=GH_COMMAND_TIMEOUT_SECONDS,
185
+ creationflags=hidden_window_creation_flags(),
182
186
  )
183
187
  except (OSError, subprocess.SubprocessError):
184
188
  return None
@@ -0,0 +1,43 @@
1
+ """Reach the hidden-window helpers from the scripts this directory deploys.
2
+
3
+ The installer copies this directory into a profile that holds no installed
4
+ Python distribution, and this repository's own tests run the deployed scripts
5
+ under ``python -S -E``, which hides every installed package from the child
6
+ process. On both routes ``hooks_constants`` is reachable only through the
7
+ deployed ``hooks`` directory, so this module puts that directory on
8
+ ``sys.path`` and re-exports the helpers a caller asks for::
9
+
10
+ from subprocess_window_access import hidden_window_creation_flags
11
+
12
+ The directory goes on the end of ``sys.path``. ``PathFinder`` runs ahead of
13
+ every editable-install finder, so a trailing entry still selects the deployed
14
+ copy, and the head of ``sys.path`` stays exactly as the caller left it. A
15
+ caller that prepended its own roots keeps them first.
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import sys
21
+ from pathlib import Path
22
+
23
+ _subprocess_window_hooks_directory = ""
24
+ for each_ancestor_directory in Path(__file__).resolve().parents:
25
+ if (each_ancestor_directory / "hooks" / "hooks_constants").is_dir():
26
+ _subprocess_window_hooks_directory = str(each_ancestor_directory / "hooks")
27
+ break
28
+ if _subprocess_window_hooks_directory not in sys.path:
29
+ sys.path.append(_subprocess_window_hooks_directory)
30
+
31
+ from hooks_constants.subprocess_window import (
32
+ HiddenWindowStartupInfo,
33
+ detached_hidden_window_creation_flags,
34
+ hidden_window_creation_flags,
35
+ inherited_stream_startup_info,
36
+ )
37
+
38
+ __all__ = [
39
+ "HiddenWindowStartupInfo",
40
+ "detached_hidden_window_creation_flags",
41
+ "hidden_window_creation_flags",
42
+ "inherited_stream_startup_info",
43
+ ]
@@ -64,6 +64,7 @@ run migrations, or repair a failed preflight.
64
64
  - `SKILL.md` covers invocation, checks, and the command boundary.
65
65
  - `scripts/run_tests.py` parses the command, runs preflight, and launches the child.
66
66
  - `scripts/preflight_checks.py` runs Django and Playwright readiness checks.
67
+ - `scripts/subprocess_window_access.py` re-exports the hidden-window helpers from the deployed hooks directory.
67
68
  - `scripts/test_run_tests.py` covers the command and preflight.
68
69
  - `scripts/test_preflight_checks.py` covers the readiness checks.
69
70
  - `scripts/test_runner_constants/` holds command names, messages, and limits.
@@ -48,6 +48,8 @@ from test_runner_constants.config.constants import (
48
48
  UNREACHABLE_ERROR_TEMPLATE,
49
49
  )
50
50
 
51
+ from subprocess_window_access import hidden_window_creation_flags
52
+
51
53
  try:
52
54
  import psutil
53
55
  except ImportError:
@@ -70,6 +72,7 @@ def check_server_health(target_url: str) -> str | None:
70
72
  text=True,
71
73
  timeout=HEALTH_CHECK_TIMEOUT_SECONDS,
72
74
  check=False,
75
+ creationflags=hidden_window_creation_flags(),
73
76
  )
74
77
  http_status_code = int(completed_process.stdout.strip())
75
78
  except (OSError, ValueError, subprocess.TimeoutExpired):
@@ -215,6 +218,7 @@ def _read_process_listing() -> str | None:
215
218
  text=True,
216
219
  timeout=PROCESS_CURL_TIMEOUT_SECONDS,
217
220
  check=False,
221
+ creationflags=hidden_window_creation_flags(),
218
222
  )
219
223
  except (OSError, subprocess.TimeoutExpired):
220
224
  return None
@@ -359,6 +363,7 @@ def _run_preparation(
359
363
  text=True,
360
364
  timeout=BUILD_TIMEOUT_SECONDS,
361
365
  check=False,
366
+ creationflags=hidden_window_creation_flags(),
362
367
  )
363
368
  except (OSError, subprocess.TimeoutExpired):
364
369
  return True
@@ -55,6 +55,16 @@ from test_runner_constants.config.constants import (
55
55
  SERVER_URL_PATTERN,
56
56
  )
57
57
 
58
+ _subprocess_window_hooks_directory = ""
59
+ for each_ancestor_directory in Path(__file__).resolve().parents:
60
+ if (each_ancestor_directory / "hooks" / "hooks_constants").is_dir():
61
+ _subprocess_window_hooks_directory = str(each_ancestor_directory / "hooks")
62
+ break
63
+ if _subprocess_window_hooks_directory not in sys.path:
64
+ sys.path.append(_subprocess_window_hooks_directory)
65
+
66
+ from hooks_constants.subprocess_window import inherited_stream_startup_info
67
+
58
68
  build_frontend = preflight_checks.build_frontend
59
69
  check_django_database = preflight_checks.check_django_database
60
70
  check_runserver_port_conflicts = preflight_checks.check_runserver_port_conflicts
@@ -277,6 +287,7 @@ def run_child_process(
277
287
  list(all_child_arguments),
278
288
  cwd=project_root,
279
289
  check=False,
290
+ startupinfo=inherited_stream_startup_info(),
280
291
  )
281
292
  except OSError as error:
282
293
  print(ERROR_CHILD_LAUNCH_TEMPLATE.format(error), file=sys.stderr)
@@ -0,0 +1,43 @@
1
+ """Reach the hidden-window helpers from the scripts this directory deploys.
2
+
3
+ The installer copies this directory into a profile that holds no installed
4
+ Python distribution, and this repository's own tests run the deployed scripts
5
+ under ``python -S -E``, which hides every installed package from the child
6
+ process. On both routes ``hooks_constants`` is reachable only through the
7
+ deployed ``hooks`` directory, so this module puts that directory on
8
+ ``sys.path`` and re-exports the helpers a caller asks for::
9
+
10
+ from subprocess_window_access import hidden_window_creation_flags
11
+
12
+ The directory goes on the end of ``sys.path``. ``PathFinder`` runs ahead of
13
+ every editable-install finder, so a trailing entry still selects the deployed
14
+ copy, and the head of ``sys.path`` stays exactly as the caller left it. A
15
+ caller that prepended its own roots keeps them first.
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import sys
21
+ from pathlib import Path
22
+
23
+ _subprocess_window_hooks_directory = ""
24
+ for each_ancestor_directory in Path(__file__).resolve().parents:
25
+ if (each_ancestor_directory / "hooks" / "hooks_constants").is_dir():
26
+ _subprocess_window_hooks_directory = str(each_ancestor_directory / "hooks")
27
+ break
28
+ if _subprocess_window_hooks_directory not in sys.path:
29
+ sys.path.append(_subprocess_window_hooks_directory)
30
+
31
+ from hooks_constants.subprocess_window import (
32
+ HiddenWindowStartupInfo,
33
+ detached_hidden_window_creation_flags,
34
+ hidden_window_creation_flags,
35
+ inherited_stream_startup_info,
36
+ )
37
+
38
+ __all__ = [
39
+ "HiddenWindowStartupInfo",
40
+ "detached_hidden_window_creation_flags",
41
+ "hidden_window_creation_flags",
42
+ "inherited_stream_startup_info",
43
+ ]
@@ -128,13 +128,15 @@ def test_main_runs_plain_pytest_without_django_preflight(
128
128
  )
129
129
 
130
130
  assert exit_code == 7
131
- assert all_calls == [
132
- {
133
- "arguments": ["python", "-m", "pytest", "tests"],
134
- "cwd": tmp_path.resolve(),
135
- "check": False,
136
- }
137
- ]
131
+ assert len(all_calls) == 1
132
+ recorded_call = dict(all_calls[0])
133
+ recorded_startup_information = recorded_call.pop("startupinfo")
134
+ assert recorded_call == {
135
+ "arguments": ["python", "-m", "pytest", "tests"],
136
+ "cwd": tmp_path.resolve(),
137
+ "check": False,
138
+ }
139
+ assert (recorded_startup_information is None) == (sys.platform != "win32")
138
140
 
139
141
 
140
142
  def test_missing_django_database_stops_before_child_launch(
@@ -43,6 +43,8 @@ from pr_converge_skill_constants.constants import (
43
43
  GH_CHECK_RUNS_PATH_TEMPLATE,
44
44
  )
45
45
 
46
+ from subprocess_window_access import hidden_window_creation_flags
47
+
46
48
 
47
49
  def _run_check_runs_api(
48
50
  *, owner: str, repo: str, sha: str
@@ -62,6 +64,7 @@ def _run_check_runs_api(
62
64
  encoding="utf-8",
63
65
  errors="replace",
64
66
  check=False,
67
+ creationflags=hidden_window_creation_flags(),
65
68
  )
66
69
 
67
70
 
@@ -32,6 +32,8 @@ from pr_converge_scripts_constants.convergence_gate_constants import (
32
32
  SHORT_SHA_LENGTH,
33
33
  )
34
34
 
35
+ from subprocess_window_access import hidden_window_creation_flags
36
+
35
37
  JsonObject = dict[str, object]
36
38
  ReviewStateGroup = tuple[str, ...]
37
39
 
@@ -44,6 +46,7 @@ def _run_gh_command(all_arguments: list[str]) -> tuple[int, str]:
44
46
  encoding="utf-8",
45
47
  errors="replace",
46
48
  check=False,
49
+ creationflags=hidden_window_creation_flags(),
47
50
  )
48
51
  return completed_process.returncode, completed_process.stdout
49
52
 
@@ -27,6 +27,8 @@ from pr_converge_skill_constants.constants import (
27
27
  REVIEWS_PER_PAGE,
28
28
  )
29
29
 
30
+ from subprocess_window_access import hidden_window_creation_flags
31
+
30
32
 
31
33
  def fetch_pending_reviews(
32
34
  *, owner: str, repo: str, number: int, user_filter: str | None = None
@@ -56,6 +58,7 @@ def fetch_pending_reviews(
56
58
  encoding="utf-8",
57
59
  errors="replace",
58
60
  check=False,
61
+ creationflags=hidden_window_creation_flags(),
59
62
  )
60
63
  if completed_process.returncode != 0:
61
64
  print(f"gh api error: {completed_process.stderr}", file=sys.stderr)
@@ -24,6 +24,8 @@ from code_rules_gate_parts.git_file_sets import (
24
24
  )
25
25
  from code_rules_gate_parts.violation_scoping import parse_added_line_numbers
26
26
 
27
+ from subprocess_window_access import hidden_window_creation_flags
28
+
27
29
 
28
30
  def _run_git_text_capture(
29
31
  repository_root: Path, all_git_arguments: list[str]
@@ -38,6 +40,7 @@ def _run_git_text_capture(
38
40
  errors="replace",
39
41
  check=False,
40
42
  env=repository_environment(),
43
+ creationflags=hidden_window_creation_flags(),
41
44
  )
42
45
 
43
46
 
@@ -49,6 +49,8 @@ from pr_loop_shared_constants.code_rules_gate_constants import (
49
49
  PYTHONPATH_ENV_VAR,
50
50
  )
51
51
 
52
+ from subprocess_window_access import hidden_window_creation_flags
53
+
52
54
 
53
55
  def _resolved_directory(path_text: str) -> Path | None:
54
56
  """Return *path_text* resolved to an absolute path, or None when it is unusable."""
@@ -152,6 +154,7 @@ def _completed_import_root_probe(
152
154
  text=True,
153
155
  check=False,
154
156
  timeout=BASELINE_IMPORT_PROBE_TIMEOUT_SECONDS,
157
+ creationflags=hidden_window_creation_flags(),
155
158
  )
156
159
  except subprocess.TimeoutExpired:
157
160
  sys.stderr.write(
@@ -11,6 +11,8 @@ from pathlib import Path
11
11
 
12
12
  from terminology_sweep import repository_environment
13
13
 
14
+ from subprocess_window_access import hidden_window_creation_flags
15
+
14
16
 
15
17
  def read_prior_committed_content(
16
18
  repository_root: Path, relative_path_posix: str, ref: str = "HEAD"
@@ -38,6 +40,7 @@ def read_prior_committed_content(
38
40
  errors="replace",
39
41
  check=False,
40
42
  env=repository_environment(),
43
+ creationflags=hidden_window_creation_flags(),
41
44
  )
42
45
  if completed.returncode != 0:
43
46
  return ""
@@ -61,6 +64,7 @@ def read_staged_content(repository_root: Path, relative_path_posix: str) -> str
61
64
  capture_output=True,
62
65
  check=False,
63
66
  env=repository_environment(),
67
+ creationflags=hidden_window_creation_flags(),
64
68
  )
65
69
  if completed.returncode != 0:
66
70
  return None
@@ -87,5 +91,6 @@ def staged_blob_exists(repository_root: Path, relative_path_posix: str) -> bool:
87
91
  capture_output=True,
88
92
  check=False,
89
93
  env=repository_environment(),
94
+ creationflags=hidden_window_creation_flags(),
90
95
  )
91
96
  return completed.returncode == 0
@@ -19,6 +19,8 @@ from pr_loop_shared_constants.code_rules_gate_constants import (
19
19
  )
20
20
  from terminology_sweep import repository_environment
21
21
 
22
+ from subprocess_window_access import hidden_window_creation_flags
23
+
22
24
  __all__ = [
23
25
  "repository_environment",
24
26
  "resolve_merge_base",
@@ -57,6 +59,7 @@ def _git_text_or_exit(
57
59
  errors="replace",
58
60
  check=False,
59
61
  env=repository_environment(),
62
+ creationflags=hidden_window_creation_flags(),
60
63
  )
61
64
  if completed.returncode != 0:
62
65
  sys.stderr.write(f"{failure_prefix}:\n{completed.stderr}\n")
@@ -86,6 +89,7 @@ def _git_bytes_or_exit(
86
89
  capture_output=True,
87
90
  check=False,
88
91
  env=repository_environment(),
92
+ creationflags=hidden_window_creation_flags(),
89
93
  )
90
94
  if completed.returncode != 0:
91
95
  stderr_text = completed.stderr.decode("utf-8", errors="replace")
@@ -66,6 +66,8 @@ from terminology_sweep import repository_environment
66
66
 
67
67
  from code_rules_gate_parts import baseline_import_isolation, staged_test_running
68
68
 
69
+ from subprocess_window_access import hidden_window_creation_flags
70
+
69
71
  TestIdentity = tuple[str, str]
70
72
 
71
73
 
@@ -93,6 +95,7 @@ def _run_git(
93
95
  text=True,
94
96
  check=False,
95
97
  env=repository_environment(),
98
+ creationflags=hidden_window_creation_flags(),
96
99
  )
97
100
 
98
101
 
@@ -59,6 +59,8 @@ from terminology_sweep import repository_environment
59
59
  from code_rules_gate_parts.git_file_sets import paths_from_git_staged
60
60
  from code_rules_gate_parts.wrapper_plumb_check import is_test_path
61
61
 
62
+ from subprocess_window_access import inherited_stream_startup_info
63
+
62
64
 
63
65
  def _is_conftest_path(file_path: Path) -> bool:
64
66
  """Return True when *file_path* is a pytest ``conftest.py`` fixture module."""
@@ -411,6 +413,7 @@ def _pytest_batch_exit_code(
411
413
  timeout=STAGED_PYTEST_TIMEOUT_SECONDS,
412
414
  check=False,
413
415
  env=environment,
416
+ startupinfo=inherited_stream_startup_info(),
414
417
  )
415
418
  if pytest_process.returncode == PYTEST_NO_TESTS_COLLECTED_EXIT_CODE:
416
419
  return 0
@@ -118,6 +118,8 @@ from codex_review_scripts_constants.codex_usage_probe_constants import ( # noqa
118
118
  WINDOWS_OS_NAME,
119
119
  )
120
120
 
121
+ from subprocess_window_access import hidden_window_creation_flags
122
+
121
123
 
122
124
  class AppServerExchange(Protocol):
123
125
  """Callable that sends JSON-RPC request objects and returns stdout lines."""
@@ -464,6 +466,7 @@ def _exchange_app_server_messages_via_subprocess(
464
466
  encoding=UTF8_ENCODING,
465
467
  shell=False,
466
468
  start_new_session=should_start_new_session(),
469
+ creationflags=hidden_window_creation_flags(),
467
470
  ) as server_process:
468
471
  server_stdin = server_process.stdin
469
472
  server_stdout = server_process.stdout
@@ -46,6 +46,8 @@ from pr_loop_shared_constants.copilot_quota_constants import (
46
46
  QUOTA_SNAPSHOTS_FIELD_NAME,
47
47
  )
48
48
 
49
+ from subprocess_window_access import hidden_window_creation_flags
50
+
49
51
 
50
52
  @dataclass(frozen=True)
51
53
  class QuotaDecision:
@@ -86,6 +88,7 @@ def _run_gh(
86
88
  errors="replace",
87
89
  check=False,
88
90
  env=process_environment,
91
+ creationflags=hidden_window_creation_flags(),
89
92
  )
90
93
  return completed_process.returncode, completed_process.stdout
91
94
 
@@ -25,6 +25,8 @@ from pr_converge_skill_constants.constants import (
25
25
  REVIEWS_PER_PAGE,
26
26
  )
27
27
 
28
+ from subprocess_window_access import hidden_window_creation_flags
29
+
28
30
 
29
31
  def fetch_copilot_reviews(
30
32
  *, owner: str, repo: str, number: int
@@ -56,6 +58,7 @@ def fetch_copilot_reviews(
56
58
  encoding="utf-8",
57
59
  errors="replace",
58
60
  check=False,
61
+ creationflags=hidden_window_creation_flags(),
59
62
  )
60
63
  if completed_process.returncode != 0:
61
64
  print(f"gh api error: {completed_process.stderr}", file=sys.stderr)
@@ -17,6 +17,8 @@ from pr_loop_shared_constants.fix_hookspath_constants import ( # noqa: E402
17
17
  )
18
18
  from pr_loop_shared_constants.preflight_constants import GIT_DIRECTORY_NAME # noqa: E402
19
19
 
20
+ from subprocess_window_access import hidden_window_creation_flags, inherited_stream_startup_info
21
+
20
22
 
21
23
  def resolve_canonical_hooks_directory(
22
24
  all_environment_overrides: dict[str, str] | None,
@@ -74,6 +76,7 @@ def list_local_core_hooks_path_values(
74
76
  errors="replace",
75
77
  check=False,
76
78
  env=all_environment_overrides,
79
+ creationflags=hidden_window_creation_flags(),
77
80
  )
78
81
  if completed_process.returncode != 0:
79
82
  diagnostic_stderr = completed_process.stderr.strip()
@@ -115,6 +118,7 @@ def read_global_core_hooks_path(
115
118
  errors="replace",
116
119
  check=False,
117
120
  env=all_environment_overrides,
121
+ creationflags=hidden_window_creation_flags(),
118
122
  )
119
123
  if completed_process.returncode != 0:
120
124
  diagnostic_stderr = completed_process.stderr.strip()
@@ -156,6 +160,7 @@ def unset_local_core_hooks_path(
156
160
  text=True,
157
161
  check=False,
158
162
  env=all_environment_overrides,
163
+ creationflags=hidden_window_creation_flags(),
159
164
  )
160
165
  return completed_process.returncode
161
166
 
@@ -181,6 +186,7 @@ def set_global_core_hooks_path(
181
186
  text=True,
182
187
  check=False,
183
188
  env=all_environment_overrides,
189
+ creationflags=hidden_window_creation_flags(),
184
190
  )
185
191
  return completed_process.returncode
186
192
 
@@ -241,6 +247,7 @@ def rerun_preflight(
241
247
  rerun_command,
242
248
  check=False,
243
249
  env=all_environment_overrides,
250
+ startupinfo=inherited_stream_startup_info(),
244
251
  )
245
252
  return completed_process.returncode
246
253