hypha-debugger 0.1.0__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.
Files changed (21) hide show
  1. {hypha_debugger-0.1.0 → hypha_debugger-0.1.4}/PKG-INFO +32 -9
  2. {hypha_debugger-0.1.0 → hypha_debugger-0.1.4}/README.md +31 -8
  3. {hypha_debugger-0.1.0 → hypha_debugger-0.1.4}/hypha_debugger/__init__.py +1 -1
  4. hypha_debugger-0.1.4/hypha_debugger/__main__.py +86 -0
  5. {hypha_debugger-0.1.0 → hypha_debugger-0.1.4}/hypha_debugger/debugger.py +130 -23
  6. {hypha_debugger-0.1.0 → hypha_debugger-0.1.4}/hypha_debugger.egg-info/PKG-INFO +32 -9
  7. {hypha_debugger-0.1.0 → hypha_debugger-0.1.4}/hypha_debugger.egg-info/SOURCES.txt +2 -0
  8. hypha_debugger-0.1.4/hypha_debugger.egg-info/entry_points.txt +2 -0
  9. {hypha_debugger-0.1.0 → hypha_debugger-0.1.4}/pyproject.toml +4 -1
  10. {hypha_debugger-0.1.0 → hypha_debugger-0.1.4}/hypha_debugger/services/__init__.py +0 -0
  11. {hypha_debugger-0.1.0 → hypha_debugger-0.1.4}/hypha_debugger/services/execute.py +0 -0
  12. {hypha_debugger-0.1.0 → hypha_debugger-0.1.4}/hypha_debugger/services/filesystem.py +0 -0
  13. {hypha_debugger-0.1.0 → hypha_debugger-0.1.4}/hypha_debugger/services/info.py +0 -0
  14. {hypha_debugger-0.1.0 → hypha_debugger-0.1.4}/hypha_debugger/services/inspect_vars.py +0 -0
  15. {hypha_debugger-0.1.0 → hypha_debugger-0.1.4}/hypha_debugger/utils/__init__.py +0 -0
  16. {hypha_debugger-0.1.0 → hypha_debugger-0.1.4}/hypha_debugger/utils/env.py +0 -0
  17. {hypha_debugger-0.1.0 → hypha_debugger-0.1.4}/hypha_debugger.egg-info/dependency_links.txt +0 -0
  18. {hypha_debugger-0.1.0 → hypha_debugger-0.1.4}/hypha_debugger.egg-info/requires.txt +0 -0
  19. {hypha_debugger-0.1.0 → hypha_debugger-0.1.4}/hypha_debugger.egg-info/top_level.txt +0 -0
  20. {hypha_debugger-0.1.0 → hypha_debugger-0.1.4}/setup.cfg +0 -0
  21. {hypha_debugger-0.1.0 → hypha_debugger-0.1.4}/tests/test_services.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hypha-debugger
3
- Version: 0.1.0
3
+ Version: 0.1.4
4
4
  Summary: Injectable debugger for Python processes and AI agents, powered by Hypha RPC
5
5
  Author: Amun AI AB
6
6
  License: MIT
@@ -185,6 +185,20 @@ Inject into any Python process to enable remote code execution, variable inspect
185
185
  pip install hypha-debugger
186
186
  ```
187
187
 
188
+ **CLI (simplest — just run and get instructions):**
189
+
190
+ ```bash
191
+ hypha-debugger
192
+ ```
193
+
194
+ Or with options:
195
+
196
+ ```bash
197
+ hypha-debugger --server-url https://hypha.aicell.io --service-id my-debugger
198
+ hypha-debugger --no-token # URL-secret mode, no auth needed
199
+ python -m hypha_debugger # alternative
200
+ ```
201
+
188
202
  **Async:**
189
203
 
190
204
  ```python
@@ -193,8 +207,7 @@ from hypha_debugger import start_debugger
193
207
 
194
208
  async def main():
195
209
  session = await start_debugger(server_url="https://hypha.aicell.io")
196
- print(session.service_url) # HTTP endpoint
197
- print(session.token) # JWT token
210
+ session.print_instructions() # print instructions anytime
198
211
  await session.serve_forever()
199
212
 
200
213
  asyncio.run(main())
@@ -206,20 +219,30 @@ asyncio.run(main())
206
219
  from hypha_debugger import start_debugger_sync
207
220
 
208
221
  session = start_debugger_sync(server_url="https://hypha.aicell.io")
209
- # Debugger runs in background, main thread continues
210
- print(session.service_url)
222
+ session.print_instructions() # print instructions anytime
211
223
  ```
212
224
 
213
225
  ### What You Get
214
226
 
227
+ The debugger prints copy-paste instructions on startup:
228
+
215
229
  ```
216
230
  [hypha-debugger] Connected to https://hypha.aicell.io
217
- [hypha-debugger] Service URL: https://hypha.aicell.io/ws-xxx/services/clientId:py-debugger
218
- [hypha-debugger] Token: eyJ...
219
- [hypha-debugger] Test it:
220
- curl 'https://hypha.aicell.io/ws-xxx/services/clientId:py-debugger/get_process_info' -H 'Authorization: Bearer eyJ...'
231
+ [hypha-debugger] Service ID: ws-xxx/clientId:py-debugger
232
+ [hypha-debugger] Service URL: https://hypha.aicell.io/ws-xxx/services/py-debugger
233
+
234
+ SERVICE_URL="https://hypha.aicell.io/ws-xxx/services/py-debugger"
235
+ TOKEN="eyJ..."
236
+
237
+ # Quick test:
238
+ curl "$SERVICE_URL/get_process_info?_mode=last" -H "Authorization: Bearer $TOKEN"
239
+
240
+ # Execute code:
241
+ curl -X POST "$SERVICE_URL/execute_code?_mode=last" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"code": "import sys; sys.version"}'
221
242
  ```
222
243
 
244
+ Call `session.print_instructions()` anytime to reprint them.
245
+
223
246
  ### Service Functions (Python)
224
247
 
225
248
  | Function | Description |
@@ -157,6 +157,20 @@ Inject into any Python process to enable remote code execution, variable inspect
157
157
  pip install hypha-debugger
158
158
  ```
159
159
 
160
+ **CLI (simplest — just run and get instructions):**
161
+
162
+ ```bash
163
+ hypha-debugger
164
+ ```
165
+
166
+ Or with options:
167
+
168
+ ```bash
169
+ hypha-debugger --server-url https://hypha.aicell.io --service-id my-debugger
170
+ hypha-debugger --no-token # URL-secret mode, no auth needed
171
+ python -m hypha_debugger # alternative
172
+ ```
173
+
160
174
  **Async:**
161
175
 
162
176
  ```python
@@ -165,8 +179,7 @@ from hypha_debugger import start_debugger
165
179
 
166
180
  async def main():
167
181
  session = await start_debugger(server_url="https://hypha.aicell.io")
168
- print(session.service_url) # HTTP endpoint
169
- print(session.token) # JWT token
182
+ session.print_instructions() # print instructions anytime
170
183
  await session.serve_forever()
171
184
 
172
185
  asyncio.run(main())
@@ -178,20 +191,30 @@ asyncio.run(main())
178
191
  from hypha_debugger import start_debugger_sync
179
192
 
180
193
  session = start_debugger_sync(server_url="https://hypha.aicell.io")
181
- # Debugger runs in background, main thread continues
182
- print(session.service_url)
194
+ session.print_instructions() # print instructions anytime
183
195
  ```
184
196
 
185
197
  ### What You Get
186
198
 
199
+ The debugger prints copy-paste instructions on startup:
200
+
187
201
  ```
188
202
  [hypha-debugger] Connected to https://hypha.aicell.io
189
- [hypha-debugger] Service URL: https://hypha.aicell.io/ws-xxx/services/clientId:py-debugger
190
- [hypha-debugger] Token: eyJ...
191
- [hypha-debugger] Test it:
192
- curl 'https://hypha.aicell.io/ws-xxx/services/clientId:py-debugger/get_process_info' -H 'Authorization: Bearer eyJ...'
203
+ [hypha-debugger] Service ID: ws-xxx/clientId:py-debugger
204
+ [hypha-debugger] Service URL: https://hypha.aicell.io/ws-xxx/services/py-debugger
205
+
206
+ SERVICE_URL="https://hypha.aicell.io/ws-xxx/services/py-debugger"
207
+ TOKEN="eyJ..."
208
+
209
+ # Quick test:
210
+ curl "$SERVICE_URL/get_process_info?_mode=last" -H "Authorization: Bearer $TOKEN"
211
+
212
+ # Execute code:
213
+ curl -X POST "$SERVICE_URL/execute_code?_mode=last" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"code": "import sys; sys.version"}'
193
214
  ```
194
215
 
216
+ Call `session.print_instructions()` anytime to reprint them.
217
+
195
218
  ### Service Functions (Python)
196
219
 
197
220
  | Function | Description |
@@ -12,5 +12,5 @@ Usage (sync):
12
12
 
13
13
  from hypha_debugger.debugger import start_debugger, start_debugger_sync, DebugSession
14
14
 
15
- __version__ = "0.1.0"
15
+ __version__ = "0.1.4"
16
16
  __all__ = ["start_debugger", "start_debugger_sync", "DebugSession", "__version__"]
@@ -0,0 +1,86 @@
1
+ """CLI entry point: python -m hypha_debugger
2
+
3
+ Starts a debugger session and prints instructions for remote access.
4
+ """
5
+
6
+ import argparse
7
+ import asyncio
8
+ import signal
9
+ import sys
10
+
11
+ from hypha_debugger.debugger import start_debugger
12
+
13
+
14
+ def main():
15
+ parser = argparse.ArgumentParser(
16
+ prog="hypha-debugger",
17
+ description="Start a Hypha debugger session for this Python process.",
18
+ )
19
+ parser.add_argument(
20
+ "--server-url",
21
+ default="https://hypha.aicell.io",
22
+ help="Hypha server URL (default: https://hypha.aicell.io)",
23
+ )
24
+ parser.add_argument(
25
+ "--workspace",
26
+ default="",
27
+ help="Workspace name (auto-assigned if omitted)",
28
+ )
29
+ parser.add_argument(
30
+ "--token",
31
+ default="",
32
+ help="Authentication token for connecting to Hypha",
33
+ )
34
+ parser.add_argument(
35
+ "--service-id",
36
+ default="py-debugger",
37
+ help="Service ID to register as (default: py-debugger)",
38
+ )
39
+ parser.add_argument(
40
+ "--service-name",
41
+ default="Python Debugger",
42
+ help="Human-readable service name (default: Python Debugger)",
43
+ )
44
+ parser.add_argument(
45
+ "--no-token",
46
+ action="store_true",
47
+ help="Disable token requirement (URL-secret mode)",
48
+ )
49
+ args = parser.parse_args()
50
+
51
+ async def run():
52
+ session = await start_debugger(
53
+ server_url=args.server_url,
54
+ workspace=args.workspace,
55
+ token=args.token,
56
+ service_id=args.service_id,
57
+ service_name=args.service_name,
58
+ require_token=not args.no_token,
59
+ )
60
+
61
+ print()
62
+ print("[hypha-debugger] Debugger is running. Press Ctrl+C to stop.")
63
+ print()
64
+
65
+ # Handle graceful shutdown
66
+ stop = asyncio.Event()
67
+
68
+ def _signal_handler():
69
+ stop.set()
70
+
71
+ loop = asyncio.get_running_loop()
72
+ for sig in (signal.SIGINT, signal.SIGTERM):
73
+ loop.add_signal_handler(sig, _signal_handler)
74
+
75
+ await stop.wait()
76
+ print("\n[hypha-debugger] Shutting down...")
77
+ await session.destroy()
78
+
79
+ try:
80
+ asyncio.run(run())
81
+ except KeyboardInterrupt:
82
+ pass
83
+
84
+
85
+ if __name__ == "__main__":
86
+ main()
@@ -2,6 +2,7 @@
2
2
 
3
3
  import asyncio
4
4
  import logging
5
+ import secrets
5
6
  import threading
6
7
  from dataclasses import dataclass, field
7
8
  from typing import Optional
@@ -19,33 +20,102 @@ logger = logging.getLogger("hypha_debugger")
19
20
 
20
21
 
21
22
  def _build_service_url(server_url: str, service_id: str) -> str:
22
- """Build the HTTP base URL for a registered service.
23
+ """Build a stable, predictable HTTP service URL.
24
+
25
+ Strips the clientId prefix so the URL uses only the bare service name.
26
+ Callers append ?_mode=last to resolve the most recent instance.
23
27
 
24
28
  Args:
25
29
  server_url: e.g. "https://hypha.aicell.io"
26
30
  service_id: e.g. "ws-xxx/clientId:py-debugger"
27
31
 
28
32
  Returns:
29
- e.g. "https://hypha.aicell.io/ws-xxx/services/clientId:py-debugger"
33
+ e.g. "https://hypha.aicell.io/ws-xxx/services/py-debugger"
30
34
  """
31
35
  base = server_url.rstrip("/")
32
36
  # service_id format: "workspace/clientId:svcName"
33
37
  parts = service_id.split("/", 1)
34
38
  if len(parts) == 2:
35
39
  workspace, svc_part = parts
36
- return f"{base}/{workspace}/services/{svc_part}"
40
+ # Strip clientId: "abc123:py-debugger" → "py-debugger"
41
+ if ":" in svc_part:
42
+ svc_name = svc_part.split(":", 1)[1]
43
+ else:
44
+ svc_name = svc_part
45
+ return f"{base}/{workspace}/services/{svc_name}"
37
46
  return f"{base}/services/{service_id}"
38
47
 
39
48
 
40
- def _print_session_info(server_url: str, service_id: str, service_url: str, token: str) -> None:
49
+ def _build_instruction_block(
50
+ service_url: str,
51
+ token: str,
52
+ require_token: bool = True,
53
+ ) -> str:
54
+ """Build the instruction block with copy-paste commands for remote access.
55
+
56
+ Returns a formatted string similar to the JS overlay instructions.
57
+ """
58
+ auth_header = f' -H "Authorization: Bearer $TOKEN"' if require_token else ""
59
+ lines = [
60
+ "# Hypha Remote Debugger — Python Process",
61
+ "# A debugger is attached to a running Python process.",
62
+ "# You can remotely inspect variables, execute code, browse files,",
63
+ "# and query process info via the HTTP API below.",
64
+ "#",
65
+ "# Available functions: get_process_info, execute_code, get_variable,",
66
+ "# list_variables, get_stack_trace, list_files, read_file, get_installed_packages",
67
+ "#",
68
+ "# All endpoints require ?_mode=last suffix. POST endpoints accept JSON body.",
69
+ "",
70
+ f'SERVICE_URL="{service_url}"',
71
+ ]
72
+ if require_token:
73
+ lines.append(f'TOKEN="{token}"')
74
+ lines += [
75
+ "",
76
+ "# Get process info (PID, Python version, CWD, memory):",
77
+ f'curl "$SERVICE_URL/get_process_info?_mode=last"{auth_header}',
78
+ "",
79
+ "# Execute Python code remotely:",
80
+ f"curl -X POST \"$SERVICE_URL/execute_code?_mode=last\""
81
+ f"{auth_header}"
82
+ " -H \"Content-Type: application/json\""
83
+ " -d '{\"code\": \"import sys; sys.version\"}'",
84
+ "",
85
+ "# Inspect a variable:",
86
+ f"curl -X POST \"$SERVICE_URL/get_variable?_mode=last\""
87
+ f"{auth_header}"
88
+ " -H \"Content-Type: application/json\""
89
+ " -d '{\"name\": \"my_var\"}'",
90
+ "",
91
+ "# List files in working directory:",
92
+ f'curl "$SERVICE_URL/list_files?_mode=last"{auth_header}',
93
+ ]
94
+ return "\n".join(lines)
95
+
96
+
97
+ def _print_session_info(
98
+ server_url: str,
99
+ service_id: str,
100
+ service_url: str,
101
+ token: str,
102
+ require_token: bool = True,
103
+ ) -> None:
41
104
  """Print session information with remote access URLs."""
42
105
  print(f"[hypha-debugger] Connected to {server_url}")
43
106
  print(f"[hypha-debugger] Service ID: {service_id}")
44
107
  print(f"[hypha-debugger] Service URL: {service_url}")
45
- print(f"[hypha-debugger] Token: {token}")
108
+ if require_token:
109
+ print(f"[hypha-debugger] Token: {token}")
110
+ print()
111
+ sep = "=" * 60
112
+ print(f"{sep}")
113
+ print(" Copy the text below to your AI agent")
114
+ print(f"{sep}")
46
115
  print()
47
- print(f"[hypha-debugger] Test it:")
48
- print(f" curl '{service_url}/get_process_info' -H 'Authorization: Bearer {token}'")
116
+ print(_build_instruction_block(service_url, token, require_token))
117
+ print()
118
+ print(f"{sep}")
49
119
 
50
120
 
51
121
  @dataclass
@@ -63,6 +133,21 @@ class DebugSession:
63
133
  )
64
134
  _thread: Optional[threading.Thread] = field(default=None, repr=False)
65
135
 
136
+ def print_instructions(self) -> str:
137
+ """Print copy-paste instructions for remote access and return them."""
138
+ instructions = _build_instruction_block(
139
+ self.service_url, self.token, bool(self.token)
140
+ )
141
+ sep = "=" * 60
142
+ print(f"{sep}")
143
+ print(" Copy the text below to your AI agent")
144
+ print(f"{sep}")
145
+ print()
146
+ print(instructions)
147
+ print()
148
+ print(f"{sep}")
149
+ return instructions
150
+
66
151
  async def serve_forever(self):
67
152
  """Block until disconnected (async)."""
68
153
  try:
@@ -102,7 +187,8 @@ async def start_debugger(
102
187
  token: str = "",
103
188
  service_id: str = "py-debugger",
104
189
  service_name: str = "Python Debugger",
105
- visibility: str = "public",
190
+ visibility: str = "",
191
+ require_token: bool = True,
106
192
  ) -> DebugSession:
107
193
  """Start the Hypha debugger (async).
108
194
 
@@ -112,16 +198,26 @@ async def start_debugger(
112
198
  Args:
113
199
  server_url: Hypha server URL (required).
114
200
  workspace: Workspace name (auto-assigned if empty).
115
- token: Authentication token.
201
+ token: Authentication token for connecting to Hypha.
116
202
  service_id: Service ID to register as.
117
203
  service_name: Human-readable service name.
118
- visibility: Service visibility ("public", "protected", "unlisted").
204
+ visibility: Service visibility override ("public", "protected", "unlisted").
205
+ Defaults to "protected" when require_token=True, "unlisted" when False.
206
+ require_token: Whether remote callers must supply a JWT token (default True).
207
+ When False, the service is registered as "unlisted" and the service ID
208
+ gets a random suffix — the URL itself acts as the secret, no token needed.
119
209
 
120
210
  Returns:
121
211
  A DebugSession with service_id, workspace, server, service_url, and token.
122
212
  """
123
213
  from hypha_rpc import connect_to_server
124
214
 
215
+ # Resolve effective service_id and visibility based on require_token.
216
+ effective_id = service_id
217
+ if not require_token and service_id == "py-debugger":
218
+ effective_id = f"py-debugger-{secrets.token_hex(8)}"
219
+ effective_visibility = visibility or ("protected" if require_token else "unlisted")
220
+
125
221
  connect_config = {"server_url": server_url}
126
222
  if workspace:
127
223
  connect_config["workspace"] = workspace
@@ -132,14 +228,14 @@ async def start_debugger(
132
228
 
133
229
  service = {
134
230
  "name": service_name,
135
- "id": service_id,
231
+ "id": effective_id,
136
232
  "type": "debugger",
137
233
  "description": (
138
234
  "Remote Python process debugger. Allows inspecting variables, "
139
235
  "executing code, browsing files, and getting process information."
140
236
  ),
141
237
  "config": {
142
- "visibility": visibility,
238
+ "visibility": effective_visibility,
143
239
  "run_in_executor": True,
144
240
  },
145
241
  "get_process_info": get_process_info,
@@ -153,11 +249,13 @@ async def start_debugger(
153
249
  }
154
250
 
155
251
  svc_info = await server.register_service(service)
156
- actual_id = svc_info.get("id", service_id) if isinstance(svc_info, dict) else service_id
252
+ actual_id = svc_info.get("id", effective_id) if isinstance(svc_info, dict) else effective_id
157
253
  ws = server.config.get("workspace", workspace) if hasattr(server.config, "get") else getattr(server.config, "workspace", workspace)
158
254
 
159
- # Generate a token for remote access
160
- session_token = await server.generate_token()
255
+ # Generate a token for remote access (24h expiry); skip in no-token mode.
256
+ session_token = ""
257
+ if require_token:
258
+ session_token = await server.generate_token({"expires_in": 86400})
161
259
 
162
260
  # Build the HTTP service URL
163
261
  service_url = _build_service_url(server_url, actual_id)
@@ -168,7 +266,7 @@ async def start_debugger(
168
266
  ws,
169
267
  actual_id,
170
268
  )
171
- _print_session_info(server_url, actual_id, service_url, session_token)
269
+ _print_session_info(server_url, actual_id, service_url, session_token, require_token)
172
270
 
173
271
  return DebugSession(
174
272
  service_id=actual_id,
@@ -186,7 +284,8 @@ def start_debugger_sync(
186
284
  token: str = "",
187
285
  service_id: str = "py-debugger",
188
286
  service_name: str = "Python Debugger",
189
- visibility: str = "public",
287
+ visibility: str = "",
288
+ require_token: bool = True,
190
289
  ) -> DebugSession:
191
290
  """Start the Hypha debugger (sync).
192
291
 
@@ -201,18 +300,24 @@ def start_debugger_sync(
201
300
  """
202
301
  from hypha_rpc.sync import connect_to_server
203
302
 
303
+ # Resolve effective service_id and visibility based on require_token.
304
+ effective_id = service_id
305
+ if not require_token and service_id == "py-debugger":
306
+ effective_id = f"py-debugger-{secrets.token_hex(8)}"
307
+ effective_visibility = visibility or ("protected" if require_token else "unlisted")
308
+
204
309
  server = connect_to_server({"server_url": server_url, **({"workspace": workspace} if workspace else {}), **({"token": token} if token else {})})
205
310
 
206
311
  service = {
207
312
  "name": service_name,
208
- "id": service_id,
313
+ "id": effective_id,
209
314
  "type": "debugger",
210
315
  "description": (
211
316
  "Remote Python process debugger. Allows inspecting variables, "
212
317
  "executing code, browsing files, and getting process information."
213
318
  ),
214
319
  "config": {
215
- "visibility": visibility,
320
+ "visibility": effective_visibility,
216
321
  "run_in_executor": True,
217
322
  },
218
323
  "get_process_info": get_process_info,
@@ -226,11 +331,13 @@ def start_debugger_sync(
226
331
  }
227
332
 
228
333
  svc_info = server.register_service(service)
229
- actual_id = svc_info.get("id", service_id) if isinstance(svc_info, dict) else service_id
334
+ actual_id = svc_info.get("id", effective_id) if isinstance(svc_info, dict) else effective_id
230
335
  ws = server.config.get("workspace", workspace) if hasattr(server.config, "get") else getattr(server.config, "workspace", workspace)
231
336
 
232
- # Generate a token for remote access
233
- session_token = server.generate_token()
337
+ # Generate a token for remote access (24h expiry); skip in no-token mode.
338
+ session_token = ""
339
+ if require_token:
340
+ session_token = server.generate_token({"expires_in": 86400})
234
341
 
235
342
  # Build the HTTP service URL
236
343
  service_url = _build_service_url(server_url, actual_id)
@@ -241,7 +348,7 @@ def start_debugger_sync(
241
348
  ws,
242
349
  actual_id,
243
350
  )
244
- _print_session_info(server_url, actual_id, service_url, session_token)
351
+ _print_session_info(server_url, actual_id, service_url, session_token, require_token)
245
352
 
246
353
  return DebugSession(
247
354
  service_id=actual_id,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hypha-debugger
3
- Version: 0.1.0
3
+ Version: 0.1.4
4
4
  Summary: Injectable debugger for Python processes and AI agents, powered by Hypha RPC
5
5
  Author: Amun AI AB
6
6
  License: MIT
@@ -185,6 +185,20 @@ Inject into any Python process to enable remote code execution, variable inspect
185
185
  pip install hypha-debugger
186
186
  ```
187
187
 
188
+ **CLI (simplest — just run and get instructions):**
189
+
190
+ ```bash
191
+ hypha-debugger
192
+ ```
193
+
194
+ Or with options:
195
+
196
+ ```bash
197
+ hypha-debugger --server-url https://hypha.aicell.io --service-id my-debugger
198
+ hypha-debugger --no-token # URL-secret mode, no auth needed
199
+ python -m hypha_debugger # alternative
200
+ ```
201
+
188
202
  **Async:**
189
203
 
190
204
  ```python
@@ -193,8 +207,7 @@ from hypha_debugger import start_debugger
193
207
 
194
208
  async def main():
195
209
  session = await start_debugger(server_url="https://hypha.aicell.io")
196
- print(session.service_url) # HTTP endpoint
197
- print(session.token) # JWT token
210
+ session.print_instructions() # print instructions anytime
198
211
  await session.serve_forever()
199
212
 
200
213
  asyncio.run(main())
@@ -206,20 +219,30 @@ asyncio.run(main())
206
219
  from hypha_debugger import start_debugger_sync
207
220
 
208
221
  session = start_debugger_sync(server_url="https://hypha.aicell.io")
209
- # Debugger runs in background, main thread continues
210
- print(session.service_url)
222
+ session.print_instructions() # print instructions anytime
211
223
  ```
212
224
 
213
225
  ### What You Get
214
226
 
227
+ The debugger prints copy-paste instructions on startup:
228
+
215
229
  ```
216
230
  [hypha-debugger] Connected to https://hypha.aicell.io
217
- [hypha-debugger] Service URL: https://hypha.aicell.io/ws-xxx/services/clientId:py-debugger
218
- [hypha-debugger] Token: eyJ...
219
- [hypha-debugger] Test it:
220
- curl 'https://hypha.aicell.io/ws-xxx/services/clientId:py-debugger/get_process_info' -H 'Authorization: Bearer eyJ...'
231
+ [hypha-debugger] Service ID: ws-xxx/clientId:py-debugger
232
+ [hypha-debugger] Service URL: https://hypha.aicell.io/ws-xxx/services/py-debugger
233
+
234
+ SERVICE_URL="https://hypha.aicell.io/ws-xxx/services/py-debugger"
235
+ TOKEN="eyJ..."
236
+
237
+ # Quick test:
238
+ curl "$SERVICE_URL/get_process_info?_mode=last" -H "Authorization: Bearer $TOKEN"
239
+
240
+ # Execute code:
241
+ curl -X POST "$SERVICE_URL/execute_code?_mode=last" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{"code": "import sys; sys.version"}'
221
242
  ```
222
243
 
244
+ Call `session.print_instructions()` anytime to reprint them.
245
+
223
246
  ### Service Functions (Python)
224
247
 
225
248
  | Function | Description |
@@ -1,10 +1,12 @@
1
1
  README.md
2
2
  pyproject.toml
3
3
  hypha_debugger/__init__.py
4
+ hypha_debugger/__main__.py
4
5
  hypha_debugger/debugger.py
5
6
  hypha_debugger.egg-info/PKG-INFO
6
7
  hypha_debugger.egg-info/SOURCES.txt
7
8
  hypha_debugger.egg-info/dependency_links.txt
9
+ hypha_debugger.egg-info/entry_points.txt
8
10
  hypha_debugger.egg-info/requires.txt
9
11
  hypha_debugger.egg-info/top_level.txt
10
12
  hypha_debugger/services/__init__.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ hypha-debugger = hypha_debugger.__main__:main
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "hypha-debugger"
7
- version = "0.1.0"
7
+ version = "0.1.4"
8
8
  description = "Injectable debugger for Python processes and AI agents, powered by Hypha RPC"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -40,6 +40,9 @@ full = [
40
40
  "psutil>=5.9",
41
41
  ]
42
42
 
43
+ [project.scripts]
44
+ hypha-debugger = "hypha_debugger.__main__:main"
45
+
43
46
  [tool.setuptools.packages.find]
44
47
  where = ["."]
45
48
  include = ["hypha_debugger*"]
File without changes