agentsecure 0.1.4__tar.gz → 0.1.5__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.
Files changed (115) hide show
  1. {agentsecure-0.1.4/agentsecure.egg-info → agentsecure-0.1.5}/PKG-INFO +19 -5
  2. {agentsecure-0.1.4 → agentsecure-0.1.5}/README.md +18 -4
  3. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/__init__.py +1 -1
  4. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/cli/main.py +40 -6
  5. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/core/agentsecure_md.py +1 -1
  6. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/gateway/proxy.py +7 -0
  7. {agentsecure-0.1.4 → agentsecure-0.1.5/agentsecure.egg-info}/PKG-INFO +19 -5
  8. {agentsecure-0.1.4 → agentsecure-0.1.5}/setup.cfg +1 -1
  9. {agentsecure-0.1.4 → agentsecure-0.1.5}/tests/test_cli.py +14 -0
  10. {agentsecure-0.1.4 → agentsecure-0.1.5}/LICENSE +0 -0
  11. {agentsecure-0.1.4 → agentsecure-0.1.5}/NOTICE +0 -0
  12. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/__main__.py +0 -0
  13. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/api/__init__.py +0 -0
  14. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/api/server.py +0 -0
  15. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/api/services.py +0 -0
  16. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/cli/__init__.py +0 -0
  17. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/cli/common.py +0 -0
  18. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/cli/demo.py +0 -0
  19. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/cli/policy.py +0 -0
  20. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/cli/project.py +0 -0
  21. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/cli/proxy.py +0 -0
  22. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/cli/receipts.py +0 -0
  23. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/cli/secrets.py +0 -0
  24. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/cli/settings.py +0 -0
  25. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/client/__init__.py +0 -0
  26. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/client/wrappers.py +0 -0
  27. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/cloud.py +0 -0
  28. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/config/__init__.py +0 -0
  29. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/config/default_agentsecure.json +0 -0
  30. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/core/__init__.py +0 -0
  31. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/core/capabilities.py +0 -0
  32. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/core/command_metadata.py +0 -0
  33. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/core/config.py +0 -0
  34. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/core/config_profiles.py +0 -0
  35. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/core/container.py +0 -0
  36. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/core/key_service.py +0 -0
  37. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/core/models.py +0 -0
  38. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/core/policy_mutation.py +0 -0
  39. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/core/policy_ports.py +0 -0
  40. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/core/policy_response.py +0 -0
  41. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/core/policy_validation.py +0 -0
  42. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/core/product.py +0 -0
  43. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/core/provider_proxy.py +0 -0
  44. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/core/time.py +0 -0
  45. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/crypto/__init__.py +0 -0
  46. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/crypto/cipher.py +0 -0
  47. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/crypto/key_provider.py +0 -0
  48. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/daemon/__init__.py +0 -0
  49. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/daemon/commands.py +0 -0
  50. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/daemon/policies.py +0 -0
  51. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/daemon/sessions.py +0 -0
  52. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/daemon/supervisor.py +0 -0
  53. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/discovery/__init__.py +0 -0
  54. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/discovery/dotenv_scanner.py +0 -0
  55. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/discovery/env_scanner.py +0 -0
  56. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/discovery/patterns.py +0 -0
  57. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/discovery/scanner.py +0 -0
  58. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/discovery/suggestions.py +0 -0
  59. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/gateway/__init__.py +0 -0
  60. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/guard/__init__.py +0 -0
  61. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/guard/command.py +0 -0
  62. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/guard/network.py +0 -0
  63. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/guard/sanitizer.py +0 -0
  64. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/guard/wrappers.py +0 -0
  65. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/implementations/__init__.py +0 -0
  66. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/implementations/audit.py +0 -0
  67. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/implementations/encrypted_secret_store.py +0 -0
  68. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/implementations/grant_store.py +0 -0
  69. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/implementations/local_secret_store.py +0 -0
  70. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/implementations/policy.py +0 -0
  71. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/implementations/secret_store_factory.py +0 -0
  72. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/implementations/secrets.py +0 -0
  73. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/interfaces/__init__.py +0 -0
  74. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/interfaces/audit.py +0 -0
  75. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/interfaces/grants.py +0 -0
  76. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/interfaces/key_store.py +0 -0
  77. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/interfaces/policy.py +0 -0
  78. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/interfaces/secrets.py +0 -0
  79. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/workspace/__init__.py +0 -0
  80. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/workspace/apply.py +0 -0
  81. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/workspace/diff.py +0 -0
  82. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/workspace/materializer.py +0 -0
  83. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/workspace/rewriter.py +0 -0
  84. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure/workspace/strategies.py +0 -0
  85. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure.egg-info/SOURCES.txt +0 -0
  86. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure.egg-info/dependency_links.txt +0 -0
  87. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure.egg-info/entry_points.txt +0 -0
  88. {agentsecure-0.1.4 → agentsecure-0.1.5}/agentsecure.egg-info/top_level.txt +0 -0
  89. {agentsecure-0.1.4 → agentsecure-0.1.5}/pyproject.toml +0 -0
  90. {agentsecure-0.1.4 → agentsecure-0.1.5}/setup.py +0 -0
  91. {agentsecure-0.1.4 → agentsecure-0.1.5}/tests/test_agentsecure_md.py +0 -0
  92. {agentsecure-0.1.4 → agentsecure-0.1.5}/tests/test_audit.py +0 -0
  93. {agentsecure-0.1.4 → agentsecure-0.1.5}/tests/test_cli_demo.py +0 -0
  94. {agentsecure-0.1.4 → agentsecure-0.1.5}/tests/test_cli_policy.py +0 -0
  95. {agentsecure-0.1.4 → agentsecure-0.1.5}/tests/test_cli_proxy.py +0 -0
  96. {agentsecure-0.1.4 → agentsecure-0.1.5}/tests/test_config_validation.py +0 -0
  97. {agentsecure-0.1.4 → agentsecure-0.1.5}/tests/test_diff.py +0 -0
  98. {agentsecure-0.1.4 → agentsecure-0.1.5}/tests/test_discovery.py +0 -0
  99. {agentsecure-0.1.4 → agentsecure-0.1.5}/tests/test_encrypted_secret_store.py +0 -0
  100. {agentsecure-0.1.4 → agentsecure-0.1.5}/tests/test_env_policy.py +0 -0
  101. {agentsecure-0.1.4 → agentsecure-0.1.5}/tests/test_env_policy_contract.py +0 -0
  102. {agentsecure-0.1.4 → agentsecure-0.1.5}/tests/test_gateway_credentials.py +0 -0
  103. {agentsecure-0.1.4 → agentsecure-0.1.5}/tests/test_guard.py +0 -0
  104. {agentsecure-0.1.4 → agentsecure-0.1.5}/tests/test_guard_network.py +0 -0
  105. {agentsecure-0.1.4 → agentsecure-0.1.5}/tests/test_key_service.py +0 -0
  106. {agentsecure-0.1.4 → agentsecure-0.1.5}/tests/test_policy.py +0 -0
  107. {agentsecure-0.1.4 → agentsecure-0.1.5}/tests/test_policy_mutation.py +0 -0
  108. {agentsecure-0.1.4 → agentsecure-0.1.5}/tests/test_product.py +0 -0
  109. {agentsecure-0.1.4 → agentsecure-0.1.5}/tests/test_provider_proxy.py +0 -0
  110. {agentsecure-0.1.4 → agentsecure-0.1.5}/tests/test_secret_scan.py +0 -0
  111. {agentsecure-0.1.4 → agentsecure-0.1.5}/tests/test_secrets.py +0 -0
  112. {agentsecure-0.1.4 → agentsecure-0.1.5}/tests/test_version.py +0 -0
  113. {agentsecure-0.1.4 → agentsecure-0.1.5}/tests/test_workspace.py +0 -0
  114. {agentsecure-0.1.4 → agentsecure-0.1.5}/tests/test_workspace_apply.py +0 -0
  115. {agentsecure-0.1.4 → agentsecure-0.1.5}/tests/test_wrappers.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentsecure
3
- Version: 0.1.4
3
+ Version: 0.1.5
4
4
  Summary: Local-first security runtime for AI coding agents
5
5
  Home-page: https://github.com/ShellFrameAI/agentsecure-community
6
6
  Author: ShellFrame AI
@@ -41,7 +41,17 @@ The community release is intentionally scoped to local CLI, local command guard,
41
41
  ## Install
42
42
 
43
43
  ```bash
44
- python3 -m pip install agentsecure
44
+ python3 -m pip install --upgrade agentsecure
45
+ python3 -m agentsecure demo
46
+ ```
47
+
48
+ `python3 -m agentsecure` works even when `pip` installs the `agentsecure`
49
+ executable into a user script directory that is not on your `PATH`. If you want
50
+ the shorter `agentsecure` command, add Python's user script directory to your
51
+ shell path:
52
+
53
+ ```bash
54
+ export PATH="$(python3 -m site --user-base)/bin:$PATH"
45
55
  agentsecure demo
46
56
  ```
47
57
 
@@ -217,11 +227,15 @@ agentsecure receipts --proxy
217
227
  Run an agent or command through local command guard:
218
228
 
219
229
  ```bash
220
- agentsecure run --protect-all -- codex
221
- agentsecure run --protect-all -- claude
222
- agentsecure run --protect-all -- python3 -c 'import subprocess; print(subprocess.check_output(["cat", ".env"]).decode())'
230
+ python3 -m agentsecure run --protect-all -- codex
231
+ python3 -m agentsecure run --protect-all -- claude
232
+ python3 -m agentsecure run --protect-all -- python3 -c 'import subprocess; print(subprocess.check_output(["cat", ".env"]).decode())'
223
233
  ```
224
234
 
235
+ Bare interactive agent launches keep the terminal attached so tools such as
236
+ Claude Code can open normally. Non-interactive commands are still output
237
+ sanitized by AgentSecure.
238
+
225
239
  Use workspace copy mode when you want review-before-apply:
226
240
 
227
241
  ```bash
@@ -15,7 +15,17 @@ The community release is intentionally scoped to local CLI, local command guard,
15
15
  ## Install
16
16
 
17
17
  ```bash
18
- python3 -m pip install agentsecure
18
+ python3 -m pip install --upgrade agentsecure
19
+ python3 -m agentsecure demo
20
+ ```
21
+
22
+ `python3 -m agentsecure` works even when `pip` installs the `agentsecure`
23
+ executable into a user script directory that is not on your `PATH`. If you want
24
+ the shorter `agentsecure` command, add Python's user script directory to your
25
+ shell path:
26
+
27
+ ```bash
28
+ export PATH="$(python3 -m site --user-base)/bin:$PATH"
19
29
  agentsecure demo
20
30
  ```
21
31
 
@@ -191,11 +201,15 @@ agentsecure receipts --proxy
191
201
  Run an agent or command through local command guard:
192
202
 
193
203
  ```bash
194
- agentsecure run --protect-all -- codex
195
- agentsecure run --protect-all -- claude
196
- agentsecure run --protect-all -- python3 -c 'import subprocess; print(subprocess.check_output(["cat", ".env"]).decode())'
204
+ python3 -m agentsecure run --protect-all -- codex
205
+ python3 -m agentsecure run --protect-all -- claude
206
+ python3 -m agentsecure run --protect-all -- python3 -c 'import subprocess; print(subprocess.check_output(["cat", ".env"]).decode())'
197
207
  ```
198
208
 
209
+ Bare interactive agent launches keep the terminal attached so tools such as
210
+ Claude Code can open normally. Non-interactive commands are still output
211
+ sanitized by AgentSecure.
212
+
199
213
  Use workspace copy mode when you want review-before-apply:
200
214
 
201
215
  ```bash
@@ -1,3 +1,3 @@
1
1
  """AgentSecure local-first security runtime."""
2
2
 
3
- __version__ = "0.1.4"
3
+ __version__ = "0.1.5"
@@ -85,6 +85,19 @@ from agentsecure.workspace.diff import WorkspaceDiff
85
85
  from agentsecure.workspace.materializer import WorkspaceMaterializer, make_tree_writable
86
86
 
87
87
 
88
+ INTERACTIVE_AGENT_COMMANDS = set(SUPPORTED_AGENTS)
89
+
90
+
91
+ class LocalGatewayHandle:
92
+ def __init__(self, gateway: LocalGateway, thread: threading.Thread) -> None:
93
+ self.gateway = gateway
94
+ self.thread = thread
95
+
96
+ def shutdown(self) -> None:
97
+ self.gateway.shutdown()
98
+ self.thread.join(timeout=2)
99
+
100
+
88
101
  def main(argv: Optional[List[str]] = None) -> int:
89
102
  parser = build_parser()
90
103
  args = parser.parse_args(argv)
@@ -338,7 +351,7 @@ def run_agent(args: argparse.Namespace) -> int:
338
351
 
339
352
  daemon = _running_daemon()
340
353
  daemon_session = None
341
- gateway_thread = None
354
+ gateway_handle = None
342
355
  if daemon:
343
356
  daemon_session = _daemon_create_session(
344
357
  daemon,
@@ -357,9 +370,9 @@ def run_agent(args: argparse.Namespace) -> int:
357
370
  else:
358
371
  gateway_host = container.config.gateway.host
359
372
  gateway_port = _available_gateway_port(gateway_host, container.config.gateway.port)
360
- gateway_thread = _start_local_gateway_thread(container, gateway_host, gateway_port)
361
- if isinstance(gateway_thread, int):
362
- return gateway_thread
373
+ gateway_handle = _start_local_gateway_thread(container, gateway_host, gateway_port)
374
+ if isinstance(gateway_handle, int):
375
+ return gateway_handle
363
376
 
364
377
  env = os.environ.copy()
365
378
  for env_name in container.config.env_policy.rules:
@@ -411,7 +424,13 @@ def run_agent(args: argparse.Namespace) -> int:
411
424
  session_finished = False
412
425
  try:
413
426
  output_sanitizer = SecretOutputSanitizer.from_config_path(args.config)
414
- process = _start_agent_process(argv, env, run_cwd, sanitize_output=True)
427
+ preserve_tty = _should_preserve_interactive_tty(argv)
428
+ if preserve_tty:
429
+ print(
430
+ "AgentSecure interactive terminal mode: command output is not post-processed.",
431
+ flush=True,
432
+ )
433
+ process = _start_agent_process(argv, env, run_cwd, sanitize_output=not preserve_tty)
415
434
  process_group_id = _process_group_id(process)
416
435
  if cloud_session and cloud and cloud.status().get("enrolled"):
417
436
  command_executor = _run_command_executor(
@@ -465,6 +484,8 @@ def run_agent(args: argparse.Namespace) -> int:
465
484
  cloud_stop.set()
466
485
  if cloud_thread:
467
486
  cloud_thread.join(timeout=2)
487
+ if gateway_handle:
488
+ gateway_handle.shutdown()
468
489
  if workspace_session and not args.workspace_keep:
469
490
  materializer.make_writable(workspace_session.workspace_root)
470
491
  shutil.rmtree(workspace_session.workspace_root, ignore_errors=True)
@@ -489,6 +510,19 @@ def _start_agent_process(argv: List[str], env, cwd: str, sanitize_output: bool =
489
510
  return subprocess.Popen(argv, env=env, cwd=cwd, stdout=stdout, stderr=stderr)
490
511
 
491
512
 
513
+ def _should_preserve_interactive_tty(argv: List[str]) -> bool:
514
+ if not argv or not _stdio_is_tty():
515
+ return False
516
+ command = os.path.basename(argv[0])
517
+ if command not in INTERACTIVE_AGENT_COMMANDS:
518
+ return False
519
+ return len(argv) == 1
520
+
521
+
522
+ def _stdio_is_tty() -> bool:
523
+ return sys.stdin.isatty() and sys.stdout.isatty() and sys.stderr.isatty()
524
+
525
+
492
526
  def _wait_for_agent_process(process, sanitizer: SecretOutputSanitizer) -> int:
493
527
  if process.stdout is None and process.stderr is None:
494
528
  return process.wait()
@@ -665,7 +699,7 @@ def _start_local_gateway_thread(container: Container, host: str, port: int):
665
699
  if isinstance(gateway_status, Exception):
666
700
  sys.stderr.write("agentsecure: gateway failed to start: %s\n" % gateway_status)
667
701
  return 1
668
- return gateway_thread
702
+ return LocalGatewayHandle(gateway, gateway_thread)
669
703
 
670
704
 
671
705
  def _proxy_url(host: str, port: int, session_id: str = "") -> str:
@@ -4,7 +4,7 @@ from typing import Any, Dict, List
4
4
 
5
5
 
6
6
  AGENTSECURE_MD = "AGENTSECURE.md"
7
- AGENTSECURE_MD_TEMPLATE_VERSION = "0.1.4"
7
+ AGENTSECURE_MD_TEMPLATE_VERSION = "0.1.5"
8
8
 
9
9
  AGENTSECURE_MD_TEMPLATE = """# AGENTSECURE.md
10
10
 
@@ -568,6 +568,10 @@ class LocalGateway:
568
568
  ready_callback()
569
569
  server.serve_forever()
570
570
 
571
+ def shutdown(self) -> None:
572
+ if self._server is not None:
573
+ self._server.shutdown()
574
+
571
575
  def _handler_class(self):
572
576
  class BoundGatewayRequestHandler(GatewayRequestHandler):
573
577
  pass
@@ -585,3 +589,6 @@ class LocalGateway:
585
589
  class ReusableThreadingTCPServer(socketserver.ThreadingTCPServer):
586
590
  allow_reuse_address = True
587
591
  daemon_threads = True
592
+
593
+ def handle_error(self, request, client_address) -> None:
594
+ return
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentsecure
3
- Version: 0.1.4
3
+ Version: 0.1.5
4
4
  Summary: Local-first security runtime for AI coding agents
5
5
  Home-page: https://github.com/ShellFrameAI/agentsecure-community
6
6
  Author: ShellFrame AI
@@ -41,7 +41,17 @@ The community release is intentionally scoped to local CLI, local command guard,
41
41
  ## Install
42
42
 
43
43
  ```bash
44
- python3 -m pip install agentsecure
44
+ python3 -m pip install --upgrade agentsecure
45
+ python3 -m agentsecure demo
46
+ ```
47
+
48
+ `python3 -m agentsecure` works even when `pip` installs the `agentsecure`
49
+ executable into a user script directory that is not on your `PATH`. If you want
50
+ the shorter `agentsecure` command, add Python's user script directory to your
51
+ shell path:
52
+
53
+ ```bash
54
+ export PATH="$(python3 -m site --user-base)/bin:$PATH"
45
55
  agentsecure demo
46
56
  ```
47
57
 
@@ -217,11 +227,15 @@ agentsecure receipts --proxy
217
227
  Run an agent or command through local command guard:
218
228
 
219
229
  ```bash
220
- agentsecure run --protect-all -- codex
221
- agentsecure run --protect-all -- claude
222
- agentsecure run --protect-all -- python3 -c 'import subprocess; print(subprocess.check_output(["cat", ".env"]).decode())'
230
+ python3 -m agentsecure run --protect-all -- codex
231
+ python3 -m agentsecure run --protect-all -- claude
232
+ python3 -m agentsecure run --protect-all -- python3 -c 'import subprocess; print(subprocess.check_output(["cat", ".env"]).decode())'
223
233
  ```
224
234
 
235
+ Bare interactive agent launches keep the terminal attached so tools such as
236
+ Claude Code can open normally. Non-interactive commands are still output
237
+ sanitized by AgentSecure.
238
+
225
239
  Use workspace copy mode when you want review-before-apply:
226
240
 
227
241
  ```bash
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = agentsecure
3
- version = 0.1.4
3
+ version = 0.1.5
4
4
  description = Local-first security runtime for AI coding agents
5
5
  long_description = file: README.md
6
6
  long_description_content_type = text/markdown
@@ -2,6 +2,7 @@ import unittest
2
2
  import socket
3
3
  from io import StringIO
4
4
  from contextlib import redirect_stdout
5
+ from unittest.mock import patch
5
6
 
6
7
  from agentsecure.cli.main import (
7
8
  _apply_proxy_environment,
@@ -11,6 +12,7 @@ from agentsecure.cli.main import (
11
12
  build_parser,
12
13
  _merge_no_proxy,
13
14
  _proxy_url,
15
+ _should_preserve_interactive_tty,
14
16
  )
15
17
  from agentsecure.core.models import AgentSecureConfig, SecretBinding
16
18
 
@@ -117,6 +119,18 @@ class CliTest(unittest.TestCase):
117
119
  finally:
118
120
  sock.close()
119
121
 
122
+ def test_preserves_tty_for_bare_interactive_agent(self):
123
+ with patch("agentsecure.cli.main._stdio_is_tty", return_value=True):
124
+ self.assertTrue(_should_preserve_interactive_tty(["claude"]))
125
+
126
+ def test_does_not_preserve_tty_for_regular_commands(self):
127
+ with patch("agentsecure.cli.main._stdio_is_tty", return_value=True):
128
+ self.assertFalse(_should_preserve_interactive_tty(["cat", ".env"]))
129
+
130
+ def test_does_not_preserve_tty_when_agent_has_arguments(self):
131
+ with patch("agentsecure.cli.main._stdio_is_tty", return_value=True):
132
+ self.assertFalse(_should_preserve_interactive_tty(["claude", "--print", "hello"]))
133
+
120
134
 
121
135
  if __name__ == "__main__":
122
136
  unittest.main()
File without changes
File without changes
File without changes
File without changes