code-context-control 2.40.0__py3-none-any.whl → 2.41.0__py3-none-any.whl

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.
cli/c3.py CHANGED
@@ -85,7 +85,7 @@ console = Console() if HAS_RICH else None
85
85
  # Config
86
86
  CONFIG_DIR = ".c3"
87
87
  CONFIG_FILE = ".c3/config.json"
88
- __version__ = "2.40.0"
88
+ __version__ = "2.41.0"
89
89
 
90
90
 
91
91
  def _command_deps() -> CommandDeps:
cli/tools/shell.py CHANGED
@@ -4,12 +4,21 @@ Wraps subprocess.Popen with the Windows-safe pattern from
4
4
  services/edit_ledger.py::_git_combined (Popen + taskkill /F /T + stdin=DEVNULL).
5
5
  Auto-filters long stdout via handle_filter, auto-logs git mutations
6
6
  to the edit ledger, and accounts stdout tokens against session budget.
7
+
8
+ Shell selection: on Windows, commands are run through Git Bash (bash.exe) when
9
+ it is available, so c3_shell speaks the same POSIX dialect as the native Bash
10
+ tool (forward-slash paths, single quotes, `$VAR`, ls/grep/cat, heredocs). This
11
+ avoids the cmd.exe/POSIX mismatch that forced callers to fall back to native
12
+ Bash for bash-flavored commands. Set C3_SHELL_BASH=0 to force cmd.exe, or point
13
+ C3_SHELL_BASH at a specific bash.exe to override discovery. POSIX platforms are
14
+ unchanged (shell=True → /bin/sh).
7
15
  """
8
16
  from __future__ import annotations
9
17
 
10
18
  import asyncio
11
19
  import os
12
20
  import re
21
+ import shutil
13
22
  import subprocess
14
23
  import sys
15
24
  import time
@@ -59,6 +68,58 @@ _MAX_TIMEOUT = 600
59
68
  _FILTER_THRESHOLD_LINES = 30
60
69
 
61
70
 
71
+ # Cache for discovered Git Bash path: [] = uncomputed, [None]/[path] = computed.
72
+ _bash_cache: list = []
73
+
74
+
75
+ def _discover_git_bash() -> str | None:
76
+ """Locate a Git-for-Windows bash.exe, never WSL/System32 bash.
77
+
78
+ WSL's bash runs in a Linux subsystem with /mnt/c paths, which would break
79
+ the Windows `cwd` semantics every caller relies on — so it is rejected.
80
+ """
81
+ candidates: list[str] = []
82
+ for base_env in ("ProgramW6432", "ProgramFiles", "ProgramFiles(x86)"):
83
+ base = os.environ.get(base_env)
84
+ if base:
85
+ candidates.append(os.path.join(base, "Git", "bin", "bash.exe"))
86
+ candidates.append(os.path.join(base, "Git", "usr", "bin", "bash.exe"))
87
+ candidates.append(r"C:\Program Files\Git\bin\bash.exe")
88
+ candidates.append(r"C:\Program Files\Git\usr\bin\bash.exe")
89
+ for path in candidates:
90
+ if os.path.isfile(path):
91
+ return path
92
+ # Last resort: PATH lookup, but reject WSL/Store bash (System32/WindowsApps).
93
+ found = shutil.which("bash")
94
+ if found:
95
+ low = found.lower()
96
+ if "system32" not in low and "windowsapps" not in low:
97
+ return found
98
+ return None
99
+
100
+
101
+ def _select_bash() -> str | None:
102
+ """Return the bash.exe to run commands through on Windows, else None.
103
+
104
+ None means "use the platform default shell" (cmd.exe on Windows via
105
+ shell=True, /bin/sh on POSIX). Honors the C3_SHELL_BASH override:
106
+ '0'/'cmd' forces the platform default; an existing file path forces that
107
+ bash. Discovery is cached after the first call.
108
+ """
109
+ if sys.platform != "win32":
110
+ return None
111
+ override = os.environ.get("C3_SHELL_BASH")
112
+ if override is not None:
113
+ if override.strip().lower() in ("0", "", "cmd", "false", "off"):
114
+ return None
115
+ if os.path.isfile(override):
116
+ return override
117
+ # Unrecognized override → fall through to discovery.
118
+ if not _bash_cache:
119
+ _bash_cache.append(_discover_git_bash())
120
+ return _bash_cache[0]
121
+
122
+
62
123
  def _popen_kwargs() -> dict:
63
124
  # Force UTF-8 in child processes so Unicode output (→, box-drawing, emoji)
64
125
  # doesn't crash on Windows' legacy cp1252 console encoding. setdefault so an
@@ -89,8 +150,17 @@ def _kill_tree(proc: subprocess.Popen) -> None:
89
150
  def _run_sync(cmd: str, cwd: str, timeout: int) -> dict:
90
151
  """Blocking subprocess run with hard kill on timeout. Returns structured dict."""
91
152
  start = time.time()
153
+ bash = _select_bash()
154
+ if bash:
155
+ # POSIX dialect via Git Bash — matches the native Bash tool.
156
+ popen_target: object = [bash, "-c", cmd]
157
+ use_shell = False
158
+ else:
159
+ # Platform default: cmd.exe on Windows, /bin/sh on POSIX.
160
+ popen_target = cmd
161
+ use_shell = True
92
162
  proc = subprocess.Popen(
93
- cmd, shell=True, cwd=cwd,
163
+ popen_target, shell=use_shell, cwd=cwd,
94
164
  stdout=subprocess.PIPE, stderr=subprocess.PIPE,
95
165
  text=True, encoding="utf-8", errors="replace",
96
166
  **_popen_kwargs(),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-context-control
3
- Version: 2.40.0
3
+ Version: 2.41.0
4
4
  Summary: Local code-intelligence layer for AI coding tools (Claude Code, Codex, Gemini, Copilot). Retrieve less, read less, edit safer.
5
5
  Author-email: Dimitri Tselenchuk <dtselenc@gmail.com>
6
6
  License-Expression: Apache-2.0
@@ -1,6 +1,6 @@
1
1
  cli/__init__.py,sha256=ec66drCZGNMRU4V6ov0zVhYZph1us12Vn8OvG_LJyRY,22
2
2
  cli/_hook_utils.py,sha256=rzW3u3Yrlvh73s_UZrQojkwGnKnS4yrPlbt4xouqQFM,5139
3
- cli/c3.py,sha256=oxxD5XSw-Bw2GemcH4dIV-cF2Bc0ZI8j1W5ZKIoG2qE,300436
3
+ cli/c3.py,sha256=Gbnou4BbpWrMR1TZdIlGcr3EeTpifBev2akFGFsgC8E,300436
4
4
  cli/docs.html,sha256=JgtBFUuUkvmYowPREYiGhhcRbB5e2UjkRc00MIF0hsU,143653
5
5
  cli/edits.html,sha256=UjAhoCmBmQ89cklGvJqzC6eyNP2tc8H6T-e01DVkLvE,43418
6
6
  cli/hook_auto_snapshot.py,sha256=amtliVDzKUQr6KBR0pdBA8vXghAV-gKr19jBaJVnP_w,5006
@@ -47,7 +47,7 @@ cli/tools/project.py,sha256=PKHLGRFZdwBBEgryyV440mybTeQMqnlLgHdfXDnPahw,11868
47
47
  cli/tools/read.py,sha256=sl-dXlfFd7zCMOz-foy5lWk0j2EF_GWfJp8YZ4GXvqo,11754
48
48
  cli/tools/search.py,sha256=qB8C3w8yuu59aepvnuJNlzbsirtSEZA8zz4neKlE7Xs,13246
49
49
  cli/tools/session.py,sha256=LIZbmEhNdh6rAsT6Dbpb21UY8xF9oubvpjGwfnXxQK4,4573
50
- cli/tools/shell.py,sha256=lTGMpT_YWnAyJzcT-WHMLjuenqq6m-p3v6uCHKCsHWM,9752
50
+ cli/tools/shell.py,sha256=vGsvzQLISo-daKF40ZhRJXS5lDA6OV1t9RWoyqdlpt4,12617
51
51
  cli/tools/status.py,sha256=yCHXskXgKzaDhJT6vHYlp3ZU5j89vhVYzf5dQOAR9yQ,12625
52
52
  cli/tools/validate.py,sha256=3GaYP9Kntep2SqKiAChUQxySWp1B-X3EuawUtIUQR40,12891
53
53
  cli/ui/api.js,sha256=wI9-lxGitIgZ5R6lqi1PVc2edD0b3TsYwMUGgcNWgfU,1342
@@ -64,7 +64,7 @@ cli/ui/components/memory.js,sha256=v5IsHTxLHpXX4xCsUaZ_UPprZEabdgP4jiWc298iV2U,2
64
64
  cli/ui/components/sessions.js,sha256=FIKtil76B8tCkAmcFV7hlj6GQ_DCJK2jCzvEmdK7NBE,30837
65
65
  cli/ui/components/settings.js,sha256=8LVTV2TQl9tcRXhXbtBEJOCBdiyk-x2QASoVYZUAuEA,71442
66
66
  cli/ui/components/sidebar.js,sha256=cAY_jwYB-o1X_wWn__VXlG4IegVObuE3NmVsuFWqxtg,7417
67
- code_context_control-2.40.0.dist-info/licenses/LICENSE,sha256=l8Kh5QCNWNvR6kIt8L0BUZvc2LAFiHv2c-FnsGnUZf4,11301
67
+ code_context_control-2.41.0.dist-info/licenses/LICENSE,sha256=l8Kh5QCNWNvR6kIt8L0BUZvc2LAFiHv2c-FnsGnUZf4,11301
68
68
  core/__init__.py,sha256=TSDCEcM4V7gcZVM3w2ykJaqEUch4Dkon-rivV17T73s,2501
69
69
  core/config.py,sha256=tF0BKg2O_77Q9y2guyqdSF3INxMrKGlqUeGbTxmHmhI,14245
70
70
  core/ide.py,sha256=9LzsDVK2LL8RVpL40l6oNGiasZ3D8OCU_9i9A0gJKBo,6876
@@ -165,8 +165,8 @@ tui/screens/search_view.py,sha256=MMHjVdlk3HZSuDBSvq8IGrqv_Mh5Us6YqXQ80bcWSMk,19
165
165
  tui/screens/session_view.py,sha256=eZ1eDwHTvPOck1wCCviixtOaCxIkBT_95ytNNNriGNA,5991
166
166
  tui/screens/stats.py,sha256=p81PjzdaIv7hllb8f45-rlVe4lJZwSdIMqu7e86_u5s,6223
167
167
  tui/screens/ui_view.py,sha256=1QJCgLh2YfgWIpvzRG1KOGXYEaOYX6ojN61Azjf2oX0,2125
168
- code_context_control-2.40.0.dist-info/METADATA,sha256=fz9LbnqjUs2XnkDTa9-niTcTDmm7g_E06ERHNbLaWhM,22274
169
- code_context_control-2.40.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
170
- code_context_control-2.40.0.dist-info/entry_points.txt,sha256=7kX_WUsDCF2hbXzvbNyscyaBb9AeA-DJY5v_5hN0DlU,93
171
- code_context_control-2.40.0.dist-info/top_level.txt,sha256=wRt41zBybVF3qAiNXHz9BURbkKvUvfhmWWtKMhaw6eE,29
172
- code_context_control-2.40.0.dist-info/RECORD,,
168
+ code_context_control-2.41.0.dist-info/METADATA,sha256=xYB3b_utLQa_yHV_8btp9ZJxKj4qS_9T0LtbImi4_Do,22274
169
+ code_context_control-2.41.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
170
+ code_context_control-2.41.0.dist-info/entry_points.txt,sha256=7kX_WUsDCF2hbXzvbNyscyaBb9AeA-DJY5v_5hN0DlU,93
171
+ code_context_control-2.41.0.dist-info/top_level.txt,sha256=wRt41zBybVF3qAiNXHz9BURbkKvUvfhmWWtKMhaw6eE,29
172
+ code_context_control-2.41.0.dist-info/RECORD,,