ghosttrap-cli 0.3.8__tar.gz → 0.3.10__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.8 → ghosttrap_cli-0.3.10}/PKG-INFO +3 -1
- {ghosttrap_cli-0.3.8 → ghosttrap_cli-0.3.10}/README.md +2 -0
- {ghosttrap_cli-0.3.8 → ghosttrap_cli-0.3.10}/ghosttrap_cli/cli.py +62 -3
- {ghosttrap_cli-0.3.8 → ghosttrap_cli-0.3.10}/ghosttrap_cli.egg-info/PKG-INFO +3 -1
- {ghosttrap_cli-0.3.8 → ghosttrap_cli-0.3.10}/pyproject.toml +1 -1
- {ghosttrap_cli-0.3.8 → ghosttrap_cli-0.3.10}/ghosttrap_cli/__init__.py +0 -0
- {ghosttrap_cli-0.3.8 → ghosttrap_cli-0.3.10}/ghosttrap_cli.egg-info/SOURCES.txt +0 -0
- {ghosttrap_cli-0.3.8 → ghosttrap_cli-0.3.10}/ghosttrap_cli.egg-info/dependency_links.txt +0 -0
- {ghosttrap_cli-0.3.8 → ghosttrap_cli-0.3.10}/ghosttrap_cli.egg-info/entry_points.txt +0 -0
- {ghosttrap_cli-0.3.8 → ghosttrap_cli-0.3.10}/ghosttrap_cli.egg-info/requires.txt +0 -0
- {ghosttrap_cli-0.3.8 → ghosttrap_cli-0.3.10}/ghosttrap_cli.egg-info/top_level.txt +0 -0
- {ghosttrap_cli-0.3.8 → ghosttrap_cli-0.3.10}/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.10
|
|
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
|
|
@@ -48,6 +48,8 @@ Your app needs [ghosttrap-sdk](https://github.com/alex-rowley/ghosttrap-sdk) to
|
|
|
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
50
|
| `ghosttrap peek --clear` | Skip outstanding errors, then wait for the next one |
|
|
51
|
+
| `ghosttrap last` | Fetch the most recent error and exit (no waiting) |
|
|
52
|
+
| `ghosttrap last --clear` | Fetch the most recent error and skip everything older |
|
|
51
53
|
| `ghosttrap watch` | Stream all errors continuously |
|
|
52
54
|
| `ghosttrap clear` | Skip all outstanding errors |
|
|
53
55
|
|
|
@@ -39,6 +39,8 @@ Your app needs [ghosttrap-sdk](https://github.com/alex-rowley/ghosttrap-sdk) to
|
|
|
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
41
|
| `ghosttrap peek --clear` | Skip outstanding errors, then wait for the next one |
|
|
42
|
+
| `ghosttrap last` | Fetch the most recent error and exit (no waiting) |
|
|
43
|
+
| `ghosttrap last --clear` | Fetch the most recent error and skip everything older |
|
|
42
44
|
| `ghosttrap watch` | Stream all errors continuously |
|
|
43
45
|
| `ghosttrap clear` | Skip all outstanding errors |
|
|
44
46
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import argparse
|
|
4
4
|
import asyncio
|
|
5
|
+
import hashlib
|
|
5
6
|
import json
|
|
6
7
|
import os
|
|
7
8
|
import subprocess
|
|
@@ -11,6 +12,14 @@ import urllib.request
|
|
|
11
12
|
|
|
12
13
|
import websockets
|
|
13
14
|
|
|
15
|
+
KNOWN_SKILL_HASHES = {
|
|
16
|
+
"aeda67bc5971bd8af4d7ebe819ebcce5acead562fa618227a1798b4b5ae7143e", # v0.2.0
|
|
17
|
+
"0f2d2f4105e393fc69084d404d5a8154ba5d97fd23f92810c51345e3dc68e9a0", # v0.3.0
|
|
18
|
+
"8564b65b8ab5c63283cda1706e30ca62bc4e111d33ba8918220f4b556ad01da1", # v0.3.1..v0.3.3
|
|
19
|
+
"5759b2e0dc8ca47c3801915fd688cc8da878a7ab8d405f5183ffd7e8c8df4c55", # v0.3.4..v0.3.7
|
|
20
|
+
"0651bb4247cf5c68960ff5b63d6a5d0c85ff1ce08e7966ab4823601ff02cf1f4", # v0.3.9
|
|
21
|
+
}
|
|
22
|
+
|
|
14
23
|
__version__ = "0.3.0"
|
|
15
24
|
|
|
16
25
|
GHOSTTRAP_SERVER = "wss://ghosttrap.io/stream/"
|
|
@@ -69,6 +78,7 @@ Read `~/.ghosttrap/config.json` for state. It contains:
|
|
|
69
78
|
|
|
70
79
|
## Other commands
|
|
71
80
|
|
|
81
|
+
- `ghosttrap last` — fetch the single most recent error and exit immediately, no waiting. Useful when the user wants to look at the latest error without starting a watch. Add `--clear` to also skip everything older in one shot.
|
|
72
82
|
- `ghosttrap clear` — manually skip outstanding errors without waiting. Useful if the user explicitly wants to drop the queue.
|
|
73
83
|
|
|
74
84
|
## Rules
|
|
@@ -259,9 +269,12 @@ def _refresh_skill_if_stale():
|
|
|
259
269
|
if not os.path.exists(SKILL_FILE):
|
|
260
270
|
return
|
|
261
271
|
with open(SKILL_FILE) as f:
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
272
|
+
content = f.read()
|
|
273
|
+
if content == SKILL_CONTENT:
|
|
274
|
+
return
|
|
275
|
+
if hashlib.sha256(content.encode()).hexdigest() in KNOWN_SKILL_HASHES:
|
|
276
|
+
_write_skill()
|
|
277
|
+
print("ghosttrap skill file updated", file=sys.stderr)
|
|
265
278
|
|
|
266
279
|
|
|
267
280
|
async def setup(server_url, token):
|
|
@@ -356,6 +369,46 @@ def clear():
|
|
|
356
369
|
sys.exit(1)
|
|
357
370
|
|
|
358
371
|
|
|
372
|
+
def last(do_clear=False):
|
|
373
|
+
_require_setup()
|
|
374
|
+
config = _load_config()
|
|
375
|
+
_check_cli_version(config)
|
|
376
|
+
token = _get_repo_token(config)
|
|
377
|
+
server = GHOSTTRAP_SERVER.replace("wss://", "https://").replace("/stream/", "")
|
|
378
|
+
url = f"{server}/last/{token}/"
|
|
379
|
+
try:
|
|
380
|
+
req = urllib.request.Request(url, headers={"User-Agent": "ghosttrap-cli"})
|
|
381
|
+
with urllib.request.urlopen(req, timeout=10) as resp:
|
|
382
|
+
data = json.loads(resp.read())
|
|
383
|
+
except Exception as e:
|
|
384
|
+
print(f"error: {e}", file=sys.stderr)
|
|
385
|
+
sys.exit(1)
|
|
386
|
+
|
|
387
|
+
error = data.get("error")
|
|
388
|
+
if not error:
|
|
389
|
+
print("no errors yet", file=sys.stderr)
|
|
390
|
+
return
|
|
391
|
+
|
|
392
|
+
print(json.dumps({"type": "error", "error": error}))
|
|
393
|
+
sys.stdout.flush()
|
|
394
|
+
|
|
395
|
+
print(f"\n{'='*60}", file=sys.stderr)
|
|
396
|
+
print(f" {error.get('repo', '?')}", file=sys.stderr)
|
|
397
|
+
print(f" {error.get('type', '?')}: {error.get('message', '')}", file=sys.stderr)
|
|
398
|
+
frames = error.get("frames", [])
|
|
399
|
+
if frames:
|
|
400
|
+
f = frames[-1]
|
|
401
|
+
print(f" at {f.get('file', '?')}:{f.get('line', '?')} in {f.get('function', '?')}", file=sys.stderr)
|
|
402
|
+
print(f"{'='*60}", file=sys.stderr)
|
|
403
|
+
|
|
404
|
+
if do_clear:
|
|
405
|
+
try:
|
|
406
|
+
_advance_cursor(config, token)
|
|
407
|
+
except Exception as e:
|
|
408
|
+
print(f"error: {e}", file=sys.stderr)
|
|
409
|
+
sys.exit(1)
|
|
410
|
+
|
|
411
|
+
|
|
359
412
|
def main():
|
|
360
413
|
parser = argparse.ArgumentParser(prog="ghosttrap", description="Watch for errors from ghosttrap.io")
|
|
361
414
|
sub = parser.add_subparsers(dest="command")
|
|
@@ -370,6 +423,9 @@ def main():
|
|
|
370
423
|
peek_parser.add_argument("--server", default=GHOSTTRAP_SERVER, help="WebSocket server URL")
|
|
371
424
|
peek_parser.add_argument("--clear", action="store_true", help="Skip outstanding errors before waiting")
|
|
372
425
|
|
|
426
|
+
last_parser = sub.add_parser("last", help="Fetch the most recent error then exit")
|
|
427
|
+
last_parser.add_argument("--clear", action="store_true", help="Also skip remaining outstanding errors")
|
|
428
|
+
|
|
373
429
|
args = parser.parse_args()
|
|
374
430
|
|
|
375
431
|
if args.command == "setup":
|
|
@@ -395,6 +451,9 @@ def main():
|
|
|
395
451
|
print(f"error: {e}", file=sys.stderr)
|
|
396
452
|
sys.exit(1)
|
|
397
453
|
asyncio.run(peek(args.server, token))
|
|
454
|
+
elif args.command == "last":
|
|
455
|
+
_refresh_skill_if_stale()
|
|
456
|
+
last(do_clear=args.clear)
|
|
398
457
|
else:
|
|
399
458
|
parser.print_help()
|
|
400
459
|
sys.exit(1)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ghosttrap-cli
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.10
|
|
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
|
|
@@ -48,6 +48,8 @@ Your app needs [ghosttrap-sdk](https://github.com/alex-rowley/ghosttrap-sdk) to
|
|
|
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
50
|
| `ghosttrap peek --clear` | Skip outstanding errors, then wait for the next one |
|
|
51
|
+
| `ghosttrap last` | Fetch the most recent error and exit (no waiting) |
|
|
52
|
+
| `ghosttrap last --clear` | Fetch the most recent error and skip everything older |
|
|
51
53
|
| `ghosttrap watch` | Stream all errors continuously |
|
|
52
54
|
| `ghosttrap clear` | Skip all outstanding errors |
|
|
53
55
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|