conduct-cli 0.4.59__tar.gz → 0.4.60__tar.gz
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.
- {conduct_cli-0.4.59 → conduct_cli-0.4.60}/PKG-INFO +1 -1
- {conduct_cli-0.4.59 → conduct_cli-0.4.60}/pyproject.toml +1 -1
- {conduct_cli-0.4.59 → conduct_cli-0.4.60}/src/conduct_cli/guard.py +17 -12
- {conduct_cli-0.4.59 → conduct_cli-0.4.60}/src/conduct_cli.egg-info/PKG-INFO +1 -1
- {conduct_cli-0.4.59 → conduct_cli-0.4.60}/README.md +0 -0
- {conduct_cli-0.4.59 → conduct_cli-0.4.60}/setup.cfg +0 -0
- {conduct_cli-0.4.59 → conduct_cli-0.4.60}/setup.py +0 -0
- {conduct_cli-0.4.59 → conduct_cli-0.4.60}/src/conduct_cli/__init__.py +0 -0
- {conduct_cli-0.4.59 → conduct_cli-0.4.60}/src/conduct_cli/api.py +0 -0
- {conduct_cli-0.4.59 → conduct_cli-0.4.60}/src/conduct_cli/guardmcp.py +0 -0
- {conduct_cli-0.4.59 → conduct_cli-0.4.60}/src/conduct_cli/main.py +0 -0
- {conduct_cli-0.4.59 → conduct_cli-0.4.60}/src/conduct_cli/mcp_server.py +0 -0
- {conduct_cli-0.4.59 → conduct_cli-0.4.60}/src/conduct_cli.egg-info/SOURCES.txt +0 -0
- {conduct_cli-0.4.59 → conduct_cli-0.4.60}/src/conduct_cli.egg-info/dependency_links.txt +0 -0
- {conduct_cli-0.4.59 → conduct_cli-0.4.60}/src/conduct_cli.egg-info/entry_points.txt +0 -0
- {conduct_cli-0.4.59 → conduct_cli-0.4.60}/src/conduct_cli.egg-info/requires.txt +0 -0
- {conduct_cli-0.4.59 → conduct_cli-0.4.60}/src/conduct_cli.egg-info/top_level.txt +0 -0
- {conduct_cli-0.4.59 → conduct_cli-0.4.60}/tests/test_guard_policy.py +0 -0
- {conduct_cli-0.4.59 → conduct_cli-0.4.60}/tests/test_guard_savings.py +0 -0
- {conduct_cli-0.4.59 → conduct_cli-0.4.60}/tests/test_switch.py +0 -0
|
@@ -282,17 +282,14 @@ def _classify_text(text):
|
|
|
282
282
|
|
|
283
283
|
def _line_number_from_text(text, matched_pattern):
|
|
284
284
|
"""Extract line number where pattern matched.
|
|
285
|
-
|
|
286
|
-
Handles two formats:
|
|
287
|
-
- Read tool output: ' N\\tcode line' (cat -n style)
|
|
288
|
-
- Plain text: count newlines before match offset
|
|
285
|
+
Uses splitlines() and chr(10) — no backslash-n literals (safe inside _HOOK_SCRIPT).
|
|
289
286
|
"""
|
|
290
287
|
import re as _re
|
|
291
288
|
if not matched_pattern:
|
|
292
289
|
return None
|
|
293
290
|
try:
|
|
294
|
-
# Try cat-n format first (Read tool)
|
|
295
|
-
for raw_line in text.
|
|
291
|
+
# Try cat-n format first (Read tool outputs ' N<TAB>code line')
|
|
292
|
+
for raw_line in text.splitlines():
|
|
296
293
|
m = _re.match(r"^\s*(\d+)\t(.*)$", raw_line)
|
|
297
294
|
if m:
|
|
298
295
|
lineno, content = int(m.group(1)), m.group(2)
|
|
@@ -302,10 +299,10 @@ def _line_number_from_text(text, matched_pattern):
|
|
|
302
299
|
except Exception:
|
|
303
300
|
if matched_pattern.lower() in content.lower():
|
|
304
301
|
return lineno
|
|
305
|
-
# Fallback: count
|
|
302
|
+
# Fallback: count lines before the first match offset
|
|
306
303
|
m = _re.search(matched_pattern, text, _re.IGNORECASE)
|
|
307
304
|
if m:
|
|
308
|
-
return text[:m.start()].count(
|
|
305
|
+
return text[:m.start()].count(chr(10)) + 1
|
|
309
306
|
except Exception:
|
|
310
307
|
pass
|
|
311
308
|
return None
|
|
@@ -813,17 +810,25 @@ def _best_python() -> str:
|
|
|
813
810
|
|
|
814
811
|
def _write_hook(path: Path) -> None:
|
|
815
812
|
"""Write _HOOK_SCRIPT to path, then py_compile-validate it.
|
|
816
|
-
|
|
817
|
-
|
|
813
|
+
On syntax failure: restores previous hook (or writes a safe stub) so the
|
|
814
|
+
system is never left without a working hook file."""
|
|
818
815
|
import py_compile, tempfile, os
|
|
816
|
+
# Stash existing hook so we can restore on failure
|
|
817
|
+
backup = None
|
|
818
|
+
if path.exists():
|
|
819
|
+
backup = path.read_text()
|
|
820
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
819
821
|
path.write_text(_HOOK_SCRIPT)
|
|
820
822
|
path.chmod(0o755)
|
|
821
823
|
try:
|
|
822
824
|
py_compile.compile(str(path), doraise=True)
|
|
823
825
|
except py_compile.PyCompileError as exc:
|
|
824
|
-
|
|
826
|
+
if backup is not None:
|
|
827
|
+
path.write_text(backup)
|
|
828
|
+
else:
|
|
829
|
+
path.write_text("#!/usr/bin/env python3\nimport sys\nsys.exit(0)\n")
|
|
825
830
|
raise RuntimeError(
|
|
826
|
-
f"hook.py failed syntax check
|
|
831
|
+
f"hook.py failed syntax check — previous hook restored.\n{exc}"
|
|
827
832
|
) from exc
|
|
828
833
|
|
|
829
834
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|