ghosttrap-cli 0.3.6__tar.gz → 0.3.8__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.
- {ghosttrap_cli-0.3.6 → ghosttrap_cli-0.3.8}/PKG-INFO +3 -1
- {ghosttrap_cli-0.3.6 → ghosttrap_cli-0.3.8}/README.md +2 -0
- {ghosttrap_cli-0.3.6 → ghosttrap_cli-0.3.8}/ghosttrap_cli/cli.py +43 -16
- {ghosttrap_cli-0.3.6 → ghosttrap_cli-0.3.8}/ghosttrap_cli.egg-info/PKG-INFO +3 -1
- {ghosttrap_cli-0.3.6 → ghosttrap_cli-0.3.8}/pyproject.toml +1 -1
- {ghosttrap_cli-0.3.6 → ghosttrap_cli-0.3.8}/ghosttrap_cli/__init__.py +0 -0
- {ghosttrap_cli-0.3.6 → ghosttrap_cli-0.3.8}/ghosttrap_cli.egg-info/SOURCES.txt +0 -0
- {ghosttrap_cli-0.3.6 → ghosttrap_cli-0.3.8}/ghosttrap_cli.egg-info/dependency_links.txt +0 -0
- {ghosttrap_cli-0.3.6 → ghosttrap_cli-0.3.8}/ghosttrap_cli.egg-info/entry_points.txt +0 -0
- {ghosttrap_cli-0.3.6 → ghosttrap_cli-0.3.8}/ghosttrap_cli.egg-info/requires.txt +0 -0
- {ghosttrap_cli-0.3.6 → ghosttrap_cli-0.3.8}/ghosttrap_cli.egg-info/top_level.txt +0 -0
- {ghosttrap_cli-0.3.6 → ghosttrap_cli-0.3.8}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ghosttrap-cli
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.8
|
|
4
4
|
Summary: Watch for errors streaming from ghosttrap.io
|
|
5
5
|
Project-URL: Homepage, https://github.com/alex-rowley/ghosttrap-cli
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -47,7 +47,9 @@ Your app needs [ghosttrap-sdk](https://github.com/alex-rowley/ghosttrap-sdk) to
|
|
|
47
47
|
|---------|-------------|
|
|
48
48
|
| `ghosttrap setup` | Claim a repo, install the Claude Code skill |
|
|
49
49
|
| `ghosttrap peek` | Wait for the next error, print it, exit |
|
|
50
|
+
| `ghosttrap peek --clear` | Skip outstanding errors, then wait for the next one |
|
|
50
51
|
| `ghosttrap watch` | Stream all errors continuously |
|
|
52
|
+
| `ghosttrap clear` | Skip all outstanding errors |
|
|
51
53
|
|
|
52
54
|
## How it works
|
|
53
55
|
|
|
@@ -38,7 +38,9 @@ Your app needs [ghosttrap-sdk](https://github.com/alex-rowley/ghosttrap-sdk) to
|
|
|
38
38
|
|---------|-------------|
|
|
39
39
|
| `ghosttrap setup` | Claim a repo, install the Claude Code skill |
|
|
40
40
|
| `ghosttrap peek` | Wait for the next error, print it, exit |
|
|
41
|
+
| `ghosttrap peek --clear` | Skip outstanding errors, then wait for the next one |
|
|
41
42
|
| `ghosttrap watch` | Stream all errors continuously |
|
|
43
|
+
| `ghosttrap clear` | Skip all outstanding errors |
|
|
42
44
|
|
|
43
45
|
## How it works
|
|
44
46
|
|
|
@@ -59,14 +59,18 @@ Read `~/.ghosttrap/config.json` for state. It contains:
|
|
|
59
59
|
1. Detect the current repo from `git config --get remote.origin.url`.
|
|
60
60
|
2. Look it up in the config. If the repo isn't there, tell the user to run `ghosttrap setup`.
|
|
61
61
|
3. If `sdk_installed` is false or missing: install the SDK (`pip install ghosttrap-sdk`), wire `ghosttrap.init("<token>")` into the app startup. For Django projects, also add `"ghosttrap.django.GhostTrapApp"` to INSTALLED_APPS (re-attaches logging handler after Django's dictConfig) and `"ghosttrap.django.GhostTrapMiddleware"` to MIDDLEWARE (catches unhandled view exceptions). The SDK auto-hooks into Celery task_failure if Celery is installed, and attaches a logging handler for logger.exception() calls. Use whatever pattern the project already uses for configuration (env vars, settings files, hardcoded — match the existing style). Then update the config: set `sdk_installed: true`, `sdk_version`, `init_file` to record what you did.
|
|
62
|
-
4. Run `ghosttrap peek` with `run_in_background: true`.
|
|
62
|
+
4. Run `ghosttrap peek --clear` with `run_in_background: true`. The `--clear` flag skips any stale backlog from prior sessions so you only get fresh errors.
|
|
63
63
|
|
|
64
64
|
## When peek returns
|
|
65
65
|
|
|
66
|
-
1. **Immediately restart peek** in the background before doing anything else — this ensures you're listening for the next error while you work on the current one.
|
|
66
|
+
1. **Immediately restart peek** in the background before doing anything else — this ensures you're listening for the next error while you work on the current one. Use plain `ghosttrap peek` here (no `--clear`) — you only want to skip backlog at session start.
|
|
67
67
|
2. Read the JSON output: `error.repo`, `error.type`, `error.message`, `error.traceback` (list of strings), `error.frames` (list of `{file, line, function, code}`).
|
|
68
68
|
3. Open the file from the last frame, diagnose, fix.
|
|
69
69
|
|
|
70
|
+
## Other commands
|
|
71
|
+
|
|
72
|
+
- `ghosttrap clear` — manually skip outstanding errors without waiting. Useful if the user explicitly wants to drop the queue.
|
|
73
|
+
|
|
70
74
|
## Rules
|
|
71
75
|
|
|
72
76
|
- Always `run_in_background: true` for peek — it blocks.
|
|
@@ -251,6 +255,15 @@ def _write_skill():
|
|
|
251
255
|
f.write(SKILL_CONTENT)
|
|
252
256
|
|
|
253
257
|
|
|
258
|
+
def _refresh_skill_if_stale():
|
|
259
|
+
if not os.path.exists(SKILL_FILE):
|
|
260
|
+
return
|
|
261
|
+
with open(SKILL_FILE) as f:
|
|
262
|
+
if f.read() != SKILL_CONTENT:
|
|
263
|
+
_write_skill()
|
|
264
|
+
print("ghosttrap skill file updated", file=sys.stderr)
|
|
265
|
+
|
|
266
|
+
|
|
254
267
|
async def setup(server_url, token):
|
|
255
268
|
config = _load_config()
|
|
256
269
|
|
|
@@ -314,25 +327,30 @@ async def peek(server_url, token):
|
|
|
314
327
|
await asyncio.sleep(60)
|
|
315
328
|
|
|
316
329
|
|
|
330
|
+
def _advance_cursor(config, token):
|
|
331
|
+
since = config.get("cursor", 0)
|
|
332
|
+
server = GHOSTTRAP_SERVER.replace("wss://", "https://").replace("/stream/", "")
|
|
333
|
+
url = f"{server}/latest/{token}/?since={since}"
|
|
334
|
+
req = urllib.request.Request(url, headers={"User-Agent": "ghosttrap-cli"})
|
|
335
|
+
with urllib.request.urlopen(req, timeout=10) as resp:
|
|
336
|
+
data = json.loads(resp.read())
|
|
337
|
+
latest_id = data.get("latest_id", 0)
|
|
338
|
+
pending = data.get("pending", 0)
|
|
339
|
+
config["cursor"] = latest_id
|
|
340
|
+
_save_config(config)
|
|
341
|
+
return pending
|
|
342
|
+
|
|
343
|
+
|
|
317
344
|
def clear():
|
|
318
345
|
_require_setup()
|
|
319
346
|
config = _load_config()
|
|
320
347
|
token = _get_repo_token(config)
|
|
321
|
-
since = config.get("cursor", 0)
|
|
322
|
-
server = GHOSTTRAP_SERVER.replace("wss://", "https://").replace("/stream/", "")
|
|
323
|
-
url = f"{server}/latest/{token}/?since={since}"
|
|
324
348
|
try:
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
config["cursor"] = latest_id
|
|
331
|
-
_save_config(config)
|
|
332
|
-
if pending:
|
|
333
|
-
print(f"cleared {pending} error(s)", file=sys.stderr)
|
|
334
|
-
else:
|
|
335
|
-
print(f"nothing to clear", file=sys.stderr)
|
|
349
|
+
pending = _advance_cursor(config, token)
|
|
350
|
+
if pending:
|
|
351
|
+
print(f"cleared {pending} error(s)", file=sys.stderr)
|
|
352
|
+
else:
|
|
353
|
+
print(f"nothing to clear", file=sys.stderr)
|
|
336
354
|
except Exception as e:
|
|
337
355
|
print(f"error: {e}", file=sys.stderr)
|
|
338
356
|
sys.exit(1)
|
|
@@ -350,6 +368,7 @@ def main():
|
|
|
350
368
|
|
|
351
369
|
peek_parser = sub.add_parser("peek", help="Wait for the next error then exit")
|
|
352
370
|
peek_parser.add_argument("--server", default=GHOSTTRAP_SERVER, help="WebSocket server URL")
|
|
371
|
+
peek_parser.add_argument("--clear", action="store_true", help="Skip outstanding errors before waiting")
|
|
353
372
|
|
|
354
373
|
args = parser.parse_args()
|
|
355
374
|
|
|
@@ -360,13 +379,21 @@ def main():
|
|
|
360
379
|
clear()
|
|
361
380
|
elif args.command == "watch":
|
|
362
381
|
_require_setup()
|
|
382
|
+
_refresh_skill_if_stale()
|
|
363
383
|
config = _load_config()
|
|
364
384
|
token = _get_repo_token(config)
|
|
365
385
|
asyncio.run(watch(args.server, token))
|
|
366
386
|
elif args.command == "peek":
|
|
367
387
|
_require_setup()
|
|
388
|
+
_refresh_skill_if_stale()
|
|
368
389
|
config = _load_config()
|
|
369
390
|
token = _get_repo_token(config)
|
|
391
|
+
if args.clear:
|
|
392
|
+
try:
|
|
393
|
+
_advance_cursor(config, token)
|
|
394
|
+
except Exception as e:
|
|
395
|
+
print(f"error: {e}", file=sys.stderr)
|
|
396
|
+
sys.exit(1)
|
|
370
397
|
asyncio.run(peek(args.server, token))
|
|
371
398
|
else:
|
|
372
399
|
parser.print_help()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ghosttrap-cli
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.8
|
|
4
4
|
Summary: Watch for errors streaming from ghosttrap.io
|
|
5
5
|
Project-URL: Homepage, https://github.com/alex-rowley/ghosttrap-cli
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -47,7 +47,9 @@ Your app needs [ghosttrap-sdk](https://github.com/alex-rowley/ghosttrap-sdk) to
|
|
|
47
47
|
|---------|-------------|
|
|
48
48
|
| `ghosttrap setup` | Claim a repo, install the Claude Code skill |
|
|
49
49
|
| `ghosttrap peek` | Wait for the next error, print it, exit |
|
|
50
|
+
| `ghosttrap peek --clear` | Skip outstanding errors, then wait for the next one |
|
|
50
51
|
| `ghosttrap watch` | Stream all errors continuously |
|
|
52
|
+
| `ghosttrap clear` | Skip all outstanding errors |
|
|
51
53
|
|
|
52
54
|
## How it works
|
|
53
55
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|