hypha-debugger 0.1.0__tar.gz → 0.1.3__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.3}/PKG-INFO +32 -9
  2. {hypha_debugger-0.1.0 → hypha_debugger-0.1.3}/README.md +31 -8
  3. {hypha_debugger-0.1.0 → hypha_debugger-0.1.3}/hypha_debugger/__init__.py +1 -1
  4. hypha_debugger-0.1.3/hypha_debugger/__main__.py +86 -0
  5. {hypha_debugger-0.1.0 → hypha_debugger-0.1.3}/hypha_debugger/debugger.py +105 -23
  6. {hypha_debugger-0.1.0 → hypha_debugger-0.1.3}/hypha_debugger.egg-info/PKG-INFO +32 -9
  7. {hypha_debugger-0.1.0 → hypha_debugger-0.1.3}/hypha_debugger.egg-info/SOURCES.txt +2 -0
  8. hypha_debugger-0.1.3/hypha_debugger.egg-info/entry_points.txt +2 -0
  9. {hypha_debugger-0.1.0 → hypha_debugger-0.1.3}/pyproject.toml +4 -1
  10. {hypha_debugger-0.1.0 → hypha_debugger-0.1.3}/hypha_debugger/services/__init__.py +0 -0
  11. {hypha_debugger-0.1.0 → hypha_debugger-0.1.3}/hypha_debugger/services/execute.py +0 -0
  12. {hypha_debugger-0.1.0 → hypha_debugger-0.1.3}/hypha_debugger/services/filesystem.py +0 -0
  13. {hypha_debugger-0.1.0 → hypha_debugger-0.1.3}/hypha_debugger/services/info.py +0 -0
  14. {hypha_debugger-0.1.0 → hypha_debugger-0.1.3}/hypha_debugger/services/inspect_vars.py +0 -0
  15. {hypha_debugger-0.1.0 → hypha_debugger-0.1.3}/hypha_debugger/utils/__init__.py +0 -0
  16. {hypha_debugger-0.1.0 → hypha_debugger-0.1.3}/hypha_debugger/utils/env.py +0 -0
  17. {hypha_debugger-0.1.0 → hypha_debugger-0.1.3}/hypha_debugger.egg-info/dependency_links.txt +0 -0
  18. {hypha_debugger-0.1.0 → hypha_debugger-0.1.3}/hypha_debugger.egg-info/requires.txt +0 -0
  19. {hypha_debugger-0.1.0 → hypha_debugger-0.1.3}/hypha_debugger.egg-info/top_level.txt +0 -0
  20. {hypha_debugger-0.1.0 → hypha_debugger-0.1.3}/setup.cfg +0 -0
  21. {hypha_debugger-0.1.0 → hypha_debugger-0.1.3}/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.3
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.3"
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,84 @@ 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
+ if require_token:
59
+ return "\n".join([
60
+ f'SERVICE_URL="{service_url}"',
61
+ f'TOKEN="{token}"',
62
+ "",
63
+ "# Quick test:",
64
+ 'curl "$SERVICE_URL/get_process_info?_mode=last" -H "Authorization: Bearer $TOKEN"',
65
+ "",
66
+ "# Execute code:",
67
+ "curl -X POST \"$SERVICE_URL/execute_code?_mode=last\" "
68
+ "-H \"Authorization: Bearer $TOKEN\" "
69
+ "-H \"Content-Type: application/json\" "
70
+ "-d '{\"code\": \"import sys; sys.version\"}'",
71
+ ])
72
+ else:
73
+ return "\n".join([
74
+ f'SERVICE_URL="{service_url}"',
75
+ "",
76
+ "# Quick test (no auth required — keep URL secret):",
77
+ 'curl "$SERVICE_URL/get_process_info?_mode=last"',
78
+ "",
79
+ "# Execute code:",
80
+ "curl -X POST \"$SERVICE_URL/execute_code?_mode=last\" "
81
+ "-H \"Content-Type: application/json\" "
82
+ "-d '{\"code\": \"import sys; sys.version\"}'",
83
+ ])
84
+
85
+
86
+ def _print_session_info(
87
+ server_url: str,
88
+ service_id: str,
89
+ service_url: str,
90
+ token: str,
91
+ require_token: bool = True,
92
+ ) -> None:
41
93
  """Print session information with remote access URLs."""
42
94
  print(f"[hypha-debugger] Connected to {server_url}")
43
95
  print(f"[hypha-debugger] Service ID: {service_id}")
44
96
  print(f"[hypha-debugger] Service URL: {service_url}")
45
- print(f"[hypha-debugger] Token: {token}")
97
+ if require_token:
98
+ print(f"[hypha-debugger] Token: {token}")
46
99
  print()
47
- print(f"[hypha-debugger] Test it:")
48
- print(f" curl '{service_url}/get_process_info' -H 'Authorization: Bearer {token}'")
100
+ print(_build_instruction_block(service_url, token, require_token))
49
101
 
50
102
 
51
103
  @dataclass
@@ -63,6 +115,14 @@ class DebugSession:
63
115
  )
64
116
  _thread: Optional[threading.Thread] = field(default=None, repr=False)
65
117
 
118
+ def print_instructions(self) -> str:
119
+ """Print copy-paste instructions for remote access and return them."""
120
+ instructions = _build_instruction_block(
121
+ self.service_url, self.token, bool(self.token)
122
+ )
123
+ print(instructions)
124
+ return instructions
125
+
66
126
  async def serve_forever(self):
67
127
  """Block until disconnected (async)."""
68
128
  try:
@@ -102,7 +162,8 @@ async def start_debugger(
102
162
  token: str = "",
103
163
  service_id: str = "py-debugger",
104
164
  service_name: str = "Python Debugger",
105
- visibility: str = "public",
165
+ visibility: str = "",
166
+ require_token: bool = True,
106
167
  ) -> DebugSession:
107
168
  """Start the Hypha debugger (async).
108
169
 
@@ -112,16 +173,26 @@ async def start_debugger(
112
173
  Args:
113
174
  server_url: Hypha server URL (required).
114
175
  workspace: Workspace name (auto-assigned if empty).
115
- token: Authentication token.
176
+ token: Authentication token for connecting to Hypha.
116
177
  service_id: Service ID to register as.
117
178
  service_name: Human-readable service name.
118
- visibility: Service visibility ("public", "protected", "unlisted").
179
+ visibility: Service visibility override ("public", "protected", "unlisted").
180
+ Defaults to "protected" when require_token=True, "unlisted" when False.
181
+ require_token: Whether remote callers must supply a JWT token (default True).
182
+ When False, the service is registered as "unlisted" and the service ID
183
+ gets a random suffix — the URL itself acts as the secret, no token needed.
119
184
 
120
185
  Returns:
121
186
  A DebugSession with service_id, workspace, server, service_url, and token.
122
187
  """
123
188
  from hypha_rpc import connect_to_server
124
189
 
190
+ # Resolve effective service_id and visibility based on require_token.
191
+ effective_id = service_id
192
+ if not require_token and service_id == "py-debugger":
193
+ effective_id = f"py-debugger-{secrets.token_hex(8)}"
194
+ effective_visibility = visibility or ("protected" if require_token else "unlisted")
195
+
125
196
  connect_config = {"server_url": server_url}
126
197
  if workspace:
127
198
  connect_config["workspace"] = workspace
@@ -132,14 +203,14 @@ async def start_debugger(
132
203
 
133
204
  service = {
134
205
  "name": service_name,
135
- "id": service_id,
206
+ "id": effective_id,
136
207
  "type": "debugger",
137
208
  "description": (
138
209
  "Remote Python process debugger. Allows inspecting variables, "
139
210
  "executing code, browsing files, and getting process information."
140
211
  ),
141
212
  "config": {
142
- "visibility": visibility,
213
+ "visibility": effective_visibility,
143
214
  "run_in_executor": True,
144
215
  },
145
216
  "get_process_info": get_process_info,
@@ -153,11 +224,13 @@ async def start_debugger(
153
224
  }
154
225
 
155
226
  svc_info = await server.register_service(service)
156
- actual_id = svc_info.get("id", service_id) if isinstance(svc_info, dict) else service_id
227
+ actual_id = svc_info.get("id", effective_id) if isinstance(svc_info, dict) else effective_id
157
228
  ws = server.config.get("workspace", workspace) if hasattr(server.config, "get") else getattr(server.config, "workspace", workspace)
158
229
 
159
- # Generate a token for remote access
160
- session_token = await server.generate_token()
230
+ # Generate a token for remote access (24h expiry); skip in no-token mode.
231
+ session_token = ""
232
+ if require_token:
233
+ session_token = await server.generate_token({"expires_in": 86400})
161
234
 
162
235
  # Build the HTTP service URL
163
236
  service_url = _build_service_url(server_url, actual_id)
@@ -168,7 +241,7 @@ async def start_debugger(
168
241
  ws,
169
242
  actual_id,
170
243
  )
171
- _print_session_info(server_url, actual_id, service_url, session_token)
244
+ _print_session_info(server_url, actual_id, service_url, session_token, require_token)
172
245
 
173
246
  return DebugSession(
174
247
  service_id=actual_id,
@@ -186,7 +259,8 @@ def start_debugger_sync(
186
259
  token: str = "",
187
260
  service_id: str = "py-debugger",
188
261
  service_name: str = "Python Debugger",
189
- visibility: str = "public",
262
+ visibility: str = "",
263
+ require_token: bool = True,
190
264
  ) -> DebugSession:
191
265
  """Start the Hypha debugger (sync).
192
266
 
@@ -201,18 +275,24 @@ def start_debugger_sync(
201
275
  """
202
276
  from hypha_rpc.sync import connect_to_server
203
277
 
278
+ # Resolve effective service_id and visibility based on require_token.
279
+ effective_id = service_id
280
+ if not require_token and service_id == "py-debugger":
281
+ effective_id = f"py-debugger-{secrets.token_hex(8)}"
282
+ effective_visibility = visibility or ("protected" if require_token else "unlisted")
283
+
204
284
  server = connect_to_server({"server_url": server_url, **({"workspace": workspace} if workspace else {}), **({"token": token} if token else {})})
205
285
 
206
286
  service = {
207
287
  "name": service_name,
208
- "id": service_id,
288
+ "id": effective_id,
209
289
  "type": "debugger",
210
290
  "description": (
211
291
  "Remote Python process debugger. Allows inspecting variables, "
212
292
  "executing code, browsing files, and getting process information."
213
293
  ),
214
294
  "config": {
215
- "visibility": visibility,
295
+ "visibility": effective_visibility,
216
296
  "run_in_executor": True,
217
297
  },
218
298
  "get_process_info": get_process_info,
@@ -226,11 +306,13 @@ def start_debugger_sync(
226
306
  }
227
307
 
228
308
  svc_info = server.register_service(service)
229
- actual_id = svc_info.get("id", service_id) if isinstance(svc_info, dict) else service_id
309
+ actual_id = svc_info.get("id", effective_id) if isinstance(svc_info, dict) else effective_id
230
310
  ws = server.config.get("workspace", workspace) if hasattr(server.config, "get") else getattr(server.config, "workspace", workspace)
231
311
 
232
- # Generate a token for remote access
233
- session_token = server.generate_token()
312
+ # Generate a token for remote access (24h expiry); skip in no-token mode.
313
+ session_token = ""
314
+ if require_token:
315
+ session_token = server.generate_token({"expires_in": 86400})
234
316
 
235
317
  # Build the HTTP service URL
236
318
  service_url = _build_service_url(server_url, actual_id)
@@ -241,7 +323,7 @@ def start_debugger_sync(
241
323
  ws,
242
324
  actual_id,
243
325
  )
244
- _print_session_info(server_url, actual_id, service_url, session_token)
326
+ _print_session_info(server_url, actual_id, service_url, session_token, require_token)
245
327
 
246
328
  return DebugSession(
247
329
  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.3
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.3"
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