guard-cli 0.1.2__tar.gz → 0.1.4__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.
- {guard_cli-0.1.2 → guard_cli-0.1.4}/PKG-INFO +1 -1
- {guard_cli-0.1.2 → guard_cli-0.1.4}/guard_cli/cli.py +6 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/guard_cli/hook.py +8 -18
- {guard_cli-0.1.2 → guard_cli-0.1.4}/guard_cli.egg-info/PKG-INFO +1 -1
- {guard_cli-0.1.2 → guard_cli-0.1.4}/pyproject.toml +1 -1
- {guard_cli-0.1.2 → guard_cli-0.1.4}/tests/test_api_and_hook.py +31 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/LICENSE +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/README.md +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/guard_cli/__init__.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/guard_cli/agent_integration.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/guard_cli/api.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/guard_cli/backend.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/guard_cli/db.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/guard_cli/decision.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/guard_cli/doctor_cmd.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/guard_cli/events.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/guard_cli/feedback.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/guard_cli/ingest/__init__.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/guard_cli/ingest/coverage.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/guard_cli/ingest/static.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/guard_cli/init_cmd.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/guard_cli/integrations/__init__.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/guard_cli/integrations/antigravity.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/guard_cli/integrations/claude.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/guard_cli/state.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/guard_cli/thin_slice.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/guard_cli.egg-info/SOURCES.txt +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/guard_cli.egg-info/dependency_links.txt +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/guard_cli.egg-info/entry_points.txt +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/guard_cli.egg-info/requires.txt +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/guard_cli.egg-info/top_level.txt +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/setup.cfg +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/tests/test_antigravity_integration.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/tests/test_antigravity_pre_recording_fixes.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/tests/test_backend.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/tests/test_commit_bypass.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/tests/test_commit_bypass_fresh_session.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/tests/test_coverage.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/tests/test_db.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/tests/test_decision.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/tests/test_doctor_cmd.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/tests/test_embedded_platform.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/tests/test_event_reasons.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/tests/test_feedback.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/tests/test_fingerprint_invalidation.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/tests/test_hook_timeout.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/tests/test_init_cmd.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/tests/test_integration_init_doctor.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/tests/test_static.py +0 -0
- {guard_cli-0.1.2 → guard_cli-0.1.4}/tests/test_thin_slice.py +0 -0
|
@@ -287,16 +287,19 @@ def main(argv=None) -> int:
|
|
|
287
287
|
hk_inst.add_argument("--repo", default=None, help="path to repo root")
|
|
288
288
|
hk_inst.add_argument("--shared", action="store_true", help="install to settings.json instead of settings.local.json")
|
|
289
289
|
hk_inst.add_argument("--antigravity", action="store_true", help="install to Antigravity .agents/hooks.json instead of Claude Code settings")
|
|
290
|
+
hk_inst.set_defaults(fn=cmd_hook_install)
|
|
290
291
|
|
|
291
292
|
hk_uninst = hk_sub.add_parser("uninstall", help="Uninstall Stop hook from agent settings (Claude Code by default, Antigravity with --antigravity)")
|
|
292
293
|
hk_uninst.add_argument("--repo", default=None, help="path to repo root")
|
|
293
294
|
hk_uninst.add_argument("--shared", action="store_true", help="uninstall from settings.json instead of settings.local.json")
|
|
294
295
|
hk_uninst.add_argument("--antigravity", action="store_true", help="uninstall from Antigravity .agents/hooks.json instead of Claude Code settings")
|
|
296
|
+
hk_uninst.set_defaults(fn=cmd_hook_uninstall)
|
|
295
297
|
|
|
296
298
|
hk_stat = hk_sub.add_parser("status", help="Check hook installation status (Claude Code by default, Antigravity with --antigravity)")
|
|
297
299
|
hk_stat.add_argument("--repo", default=None, help="path to repo root")
|
|
298
300
|
hk_stat.add_argument("--shared", action="store_true", help="check settings.json instead of settings.local.json")
|
|
299
301
|
hk_stat.add_argument("--antigravity", action="store_true", help="check Antigravity .agents/hooks.json instead of Claude Code settings")
|
|
302
|
+
hk_stat.set_defaults(fn=cmd_hook_status)
|
|
300
303
|
|
|
301
304
|
fb = sub.add_parser("feedback")
|
|
302
305
|
fb.add_argument("--function", required=True, help="Function ID where fault was missed")
|
|
@@ -336,6 +339,9 @@ def main(argv=None) -> int:
|
|
|
336
339
|
cov.set_defaults(fn=cmd_covering_tests)
|
|
337
340
|
|
|
338
341
|
args = p.parse_args(argv)
|
|
342
|
+
if not hasattr(args, "fn"):
|
|
343
|
+
p.print_help()
|
|
344
|
+
return 1
|
|
339
345
|
return args.fn(args)
|
|
340
346
|
|
|
341
347
|
|
|
@@ -530,16 +530,11 @@ def run_stop_hook(
|
|
|
530
530
|
if is_antigravity:
|
|
531
531
|
resp: dict[str, Any] = {"decision": "stop", "reason": reason or ""}
|
|
532
532
|
payload = json.dumps(resp) + "\n"
|
|
533
|
-
if
|
|
533
|
+
target_out = real_out if real_out is not None else saved_stdout
|
|
534
|
+
if target_out is not None:
|
|
534
535
|
try:
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
except Exception:
|
|
538
|
-
pass
|
|
539
|
-
if real_out is not None and real_out is not saved_stdout:
|
|
540
|
-
try:
|
|
541
|
-
real_out.write(payload)
|
|
542
|
-
real_out.flush()
|
|
536
|
+
target_out.write(payload)
|
|
537
|
+
target_out.flush()
|
|
543
538
|
except Exception:
|
|
544
539
|
pass
|
|
545
540
|
return 0
|
|
@@ -548,16 +543,11 @@ def run_stop_hook(
|
|
|
548
543
|
if is_antigravity:
|
|
549
544
|
resp: dict[str, Any] = {"decision": "continue", "reason": reason_text}
|
|
550
545
|
payload = json.dumps(resp) + "\n"
|
|
551
|
-
if
|
|
552
|
-
|
|
553
|
-
saved_stdout.write(payload)
|
|
554
|
-
saved_stdout.flush()
|
|
555
|
-
except Exception:
|
|
556
|
-
pass
|
|
557
|
-
if real_out is not None and real_out is not saved_stdout:
|
|
546
|
+
target_out = real_out if real_out is not None else saved_stdout
|
|
547
|
+
if target_out is not None:
|
|
558
548
|
try:
|
|
559
|
-
|
|
560
|
-
|
|
549
|
+
target_out.write(payload)
|
|
550
|
+
target_out.flush()
|
|
561
551
|
except Exception:
|
|
562
552
|
pass
|
|
563
553
|
sys.stderr.write(reason_text)
|
|
@@ -421,3 +421,34 @@ def test_claude_settings_uninstall_only_removes_guard(temp_repo):
|
|
|
421
421
|
|
|
422
422
|
stat = claude.status(repo_path=temp_repo, shared=False)
|
|
423
423
|
assert stat["installed"] is False
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
def test_cli_hook_subcommands(temp_repo, capsys):
|
|
427
|
+
"""Test CLI dispatch for hook status, install, and uninstall."""
|
|
428
|
+
from guard_cli.cli import main
|
|
429
|
+
|
|
430
|
+
# Status before install
|
|
431
|
+
ret = main(["hook", "status", "--repo", str(temp_repo)])
|
|
432
|
+
assert ret == 0
|
|
433
|
+
captured = capsys.readouterr().out
|
|
434
|
+
data = json.loads(captured)
|
|
435
|
+
assert "claude" in data
|
|
436
|
+
assert "antigravity" in data
|
|
437
|
+
assert data["antigravity"]["installed"] is False
|
|
438
|
+
|
|
439
|
+
# Install antigravity hook
|
|
440
|
+
ret = main(["hook", "install", "--repo", str(temp_repo), "--antigravity"])
|
|
441
|
+
assert ret == 0
|
|
442
|
+
capsys.readouterr()
|
|
443
|
+
|
|
444
|
+
# Status after install
|
|
445
|
+
ret = main(["hook", "status", "--repo", str(temp_repo)])
|
|
446
|
+
assert ret == 0
|
|
447
|
+
captured = capsys.readouterr().out
|
|
448
|
+
data = json.loads(captured)
|
|
449
|
+
assert data["antigravity"]["installed"] is True
|
|
450
|
+
|
|
451
|
+
# Uninstall antigravity hook
|
|
452
|
+
ret = main(["hook", "uninstall", "--repo", str(temp_repo), "--antigravity"])
|
|
453
|
+
assert ret == 0
|
|
454
|
+
|
|
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
|
|
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
|
|
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
|