ghosttrap-cli 0.3.11__tar.gz → 0.3.13__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.11 → ghosttrap_cli-0.3.13}/PKG-INFO +2 -1
- {ghosttrap_cli-0.3.11 → ghosttrap_cli-0.3.13}/README.md +1 -0
- {ghosttrap_cli-0.3.11 → ghosttrap_cli-0.3.13}/ghosttrap_cli/cli.py +62 -9
- {ghosttrap_cli-0.3.11 → ghosttrap_cli-0.3.13}/ghosttrap_cli.egg-info/PKG-INFO +2 -1
- {ghosttrap_cli-0.3.11 → ghosttrap_cli-0.3.13}/pyproject.toml +1 -1
- {ghosttrap_cli-0.3.11 → ghosttrap_cli-0.3.13}/ghosttrap_cli/__init__.py +0 -0
- {ghosttrap_cli-0.3.11 → ghosttrap_cli-0.3.13}/ghosttrap_cli.egg-info/SOURCES.txt +0 -0
- {ghosttrap_cli-0.3.11 → ghosttrap_cli-0.3.13}/ghosttrap_cli.egg-info/dependency_links.txt +0 -0
- {ghosttrap_cli-0.3.11 → ghosttrap_cli-0.3.13}/ghosttrap_cli.egg-info/entry_points.txt +0 -0
- {ghosttrap_cli-0.3.11 → ghosttrap_cli-0.3.13}/ghosttrap_cli.egg-info/requires.txt +0 -0
- {ghosttrap_cli-0.3.11 → ghosttrap_cli-0.3.13}/ghosttrap_cli.egg-info/top_level.txt +0 -0
- {ghosttrap_cli-0.3.11 → ghosttrap_cli-0.3.13}/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.13
|
|
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
|
|
@@ -52,6 +52,7 @@ Your app needs [ghosttrap-sdk](https://github.com/alex-rowley/ghosttrap-sdk) to
|
|
|
52
52
|
| `ghosttrap last --clear` | Fetch the most recent error and skip everything older |
|
|
53
53
|
| `ghosttrap watch` | Stream all errors continuously |
|
|
54
54
|
| `ghosttrap clear` | Skip all outstanding errors |
|
|
55
|
+
| `ghosttrap nuke` | Permanently delete every server-side row for the current repo (errors + token). Requires typed confirmation. |
|
|
55
56
|
|
|
56
57
|
## How it works
|
|
57
58
|
|
|
@@ -43,6 +43,7 @@ Your app needs [ghosttrap-sdk](https://github.com/alex-rowley/ghosttrap-sdk) to
|
|
|
43
43
|
| `ghosttrap last --clear` | Fetch the most recent error and skip everything older |
|
|
44
44
|
| `ghosttrap watch` | Stream all errors continuously |
|
|
45
45
|
| `ghosttrap clear` | Skip all outstanding errors |
|
|
46
|
+
| `ghosttrap nuke` | Permanently delete every server-side row for the current repo (errors + token). Requires typed confirmation. |
|
|
46
47
|
|
|
47
48
|
## How it works
|
|
48
49
|
|
|
@@ -19,9 +19,11 @@ KNOWN_SKILL_HASHES = {
|
|
|
19
19
|
"5759b2e0dc8ca47c3801915fd688cc8da878a7ab8d405f5183ffd7e8c8df4c55", # v0.3.4..v0.3.7
|
|
20
20
|
"0651bb4247cf5c68960ff5b63d6a5d0c85ff1ce08e7966ab4823601ff02cf1f4", # v0.3.9
|
|
21
21
|
"38810f43867a2a91420cc3dacbc71d2acabd7125596fd5b43f222b49725c9696", # v0.3.10
|
|
22
|
+
"19b67d913dc5214ee4db3610bd8749da67324c174b904b5da71ee6de13e23e63", # v0.3.11
|
|
23
|
+
"bf7768c3de266b7018d5c722c6c9991b487e7897786b3a406c460842cdcde8b5", # v0.3.12
|
|
22
24
|
}
|
|
23
25
|
|
|
24
|
-
__version__ = "0.3.
|
|
26
|
+
__version__ = "0.3.13"
|
|
25
27
|
|
|
26
28
|
GHOSTTRAP_SERVER = "wss://ghosttrap.io/stream/"
|
|
27
29
|
CONFIG_DIR = os.path.expanduser("~/.ghosttrap")
|
|
@@ -61,7 +63,7 @@ description: Production error monitoring via ghosttrap.io. Trigger when starting
|
|
|
61
63
|
# Ghosttrap
|
|
62
64
|
|
|
63
65
|
Read `~/.ghosttrap/config.json` for state. It contains:
|
|
64
|
-
- `repos`: map keyed by GitHub repo id (stringified int) to `{"github_id": int, "owner": str, "name": str, "token": "t_xxx", "sdk_installed": bool, "sdk_version": str, "init_file": str}`.
|
|
66
|
+
- `repos`: map keyed by GitHub repo id (stringified int) to `{"github_id": int, "owner": str, "name": str, "token": "t_xxx", "sdk_installed": bool, "sdk_version": str, "init_file": str}`.
|
|
65
67
|
- `cursor`: last seen error ID
|
|
66
68
|
|
|
67
69
|
## On session start
|
|
@@ -81,6 +83,7 @@ Read `~/.ghosttrap/config.json` for state. It contains:
|
|
|
81
83
|
|
|
82
84
|
- `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.
|
|
83
85
|
- `ghosttrap clear` — manually skip outstanding errors without waiting. Useful if the user explicitly wants to drop the queue.
|
|
86
|
+
- `ghosttrap nuke` — permanently delete every server-side row for the current repo (errors + the Repo row + its token). Requires the user to type the repo name `owner/name` to confirm. Only run if the user explicitly asks to wipe server data — never proactively. After it succeeds the token is dead; the user would need to `ghosttrap setup` again to use this repo.
|
|
84
87
|
|
|
85
88
|
## Rules
|
|
86
89
|
|
|
@@ -121,11 +124,6 @@ def _save_repos(config, repos):
|
|
|
121
124
|
for r in repos:
|
|
122
125
|
key = _repo_key(r)
|
|
123
126
|
existing = config["repos"].get(key, {})
|
|
124
|
-
# Drop any legacy slug-keyed entry now superseded by a github_id key.
|
|
125
|
-
if r.get("github_id") is not None:
|
|
126
|
-
legacy_key = f"{r.get('owner')}/{r.get('name')}"
|
|
127
|
-
if legacy_key in config["repos"] and legacy_key != key:
|
|
128
|
-
existing = {**config["repos"].pop(legacy_key), **existing}
|
|
129
127
|
existing.update({
|
|
130
128
|
"github_id": r.get("github_id"),
|
|
131
129
|
"owner": r["owner"],
|
|
@@ -210,8 +208,6 @@ def _get_repo_token(config):
|
|
|
210
208
|
for entry in repos.values():
|
|
211
209
|
if f"{entry.get('owner')}/{entry.get('name')}" == cwd_repo:
|
|
212
210
|
return entry["token"]
|
|
213
|
-
if cwd_repo in repos:
|
|
214
|
-
return repos[cwd_repo]["token"]
|
|
215
211
|
if repos:
|
|
216
212
|
return next(iter(repos.values()))["token"]
|
|
217
213
|
print("error: no repos configured. run 'ghosttrap setup' first.", file=sys.stderr)
|
|
@@ -396,6 +392,59 @@ def clear():
|
|
|
396
392
|
sys.exit(1)
|
|
397
393
|
|
|
398
394
|
|
|
395
|
+
def nuke():
|
|
396
|
+
_require_setup()
|
|
397
|
+
config = _load_config()
|
|
398
|
+
repos = config.get("repos", {})
|
|
399
|
+
cwd_repo = _detect_repo_from_cwd()
|
|
400
|
+
if not cwd_repo:
|
|
401
|
+
print("error: not in a git repo with a github remote", file=sys.stderr)
|
|
402
|
+
sys.exit(1)
|
|
403
|
+
|
|
404
|
+
entry_key = None
|
|
405
|
+
entry = None
|
|
406
|
+
for k, e in repos.items():
|
|
407
|
+
if f"{e.get('owner')}/{e.get('name')}" == cwd_repo:
|
|
408
|
+
entry_key, entry = k, e
|
|
409
|
+
break
|
|
410
|
+
if entry is None:
|
|
411
|
+
print(f"error: {cwd_repo} is not in your config. run 'ghosttrap setup' to claim it first.", file=sys.stderr)
|
|
412
|
+
sys.exit(1)
|
|
413
|
+
|
|
414
|
+
canonical = f"{entry['owner']}/{entry['name']}"
|
|
415
|
+
print(f"\nthis will permanently delete ALL data on the server for {canonical}:", file=sys.stderr)
|
|
416
|
+
print(f" - every Error row for this repo", file=sys.stderr)
|
|
417
|
+
print(f" - the Repo row itself (token will stop working)", file=sys.stderr)
|
|
418
|
+
print(f"\ntype the repo name to confirm: ", file=sys.stderr, end="")
|
|
419
|
+
sys.stderr.flush()
|
|
420
|
+
try:
|
|
421
|
+
typed = input().strip()
|
|
422
|
+
except (EOFError, KeyboardInterrupt):
|
|
423
|
+
print("\naborted", file=sys.stderr)
|
|
424
|
+
sys.exit(1)
|
|
425
|
+
if typed != canonical:
|
|
426
|
+
print("aborted (did not match)", file=sys.stderr)
|
|
427
|
+
sys.exit(1)
|
|
428
|
+
|
|
429
|
+
server = GHOSTTRAP_SERVER.replace("wss://", "https://").replace("/stream/", "")
|
|
430
|
+
url = f"{server}/nuke/{entry['token']}/"
|
|
431
|
+
try:
|
|
432
|
+
req = urllib.request.Request(url, method="DELETE", headers={"User-Agent": "ghosttrap-cli"})
|
|
433
|
+
with urllib.request.urlopen(req, timeout=10) as resp:
|
|
434
|
+
data = json.loads(resp.read())
|
|
435
|
+
except Exception as e:
|
|
436
|
+
print(f"error: {e}", file=sys.stderr)
|
|
437
|
+
sys.exit(1)
|
|
438
|
+
|
|
439
|
+
print(json.dumps(data))
|
|
440
|
+
print(f"\nnuked {data.get('repo')}:", file=sys.stderr)
|
|
441
|
+
print(f" errors deleted: {data.get('errors_deleted')}", file=sys.stderr)
|
|
442
|
+
print(f" repos deleted: {data.get('repo_deleted')}", file=sys.stderr)
|
|
443
|
+
|
|
444
|
+
repos.pop(entry_key, None)
|
|
445
|
+
_save_config(config)
|
|
446
|
+
|
|
447
|
+
|
|
399
448
|
def last(do_clear=False):
|
|
400
449
|
_require_setup()
|
|
401
450
|
config = _load_config()
|
|
@@ -453,6 +502,8 @@ def main():
|
|
|
453
502
|
last_parser = sub.add_parser("last", help="Fetch the most recent error then exit")
|
|
454
503
|
last_parser.add_argument("--clear", action="store_true", help="Also skip remaining outstanding errors")
|
|
455
504
|
|
|
505
|
+
sub.add_parser("nuke", help="Permanently delete all server data for the current repo")
|
|
506
|
+
|
|
456
507
|
args = parser.parse_args()
|
|
457
508
|
|
|
458
509
|
if args.command == "setup":
|
|
@@ -481,6 +532,8 @@ def main():
|
|
|
481
532
|
elif args.command == "last":
|
|
482
533
|
_refresh_skill_if_stale()
|
|
483
534
|
last(do_clear=args.clear)
|
|
535
|
+
elif args.command == "nuke":
|
|
536
|
+
nuke()
|
|
484
537
|
else:
|
|
485
538
|
parser.print_help()
|
|
486
539
|
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.13
|
|
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
|
|
@@ -52,6 +52,7 @@ Your app needs [ghosttrap-sdk](https://github.com/alex-rowley/ghosttrap-sdk) to
|
|
|
52
52
|
| `ghosttrap last --clear` | Fetch the most recent error and skip everything older |
|
|
53
53
|
| `ghosttrap watch` | Stream all errors continuously |
|
|
54
54
|
| `ghosttrap clear` | Skip all outstanding errors |
|
|
55
|
+
| `ghosttrap nuke` | Permanently delete every server-side row for the current repo (errors + token). Requires typed confirmation. |
|
|
55
56
|
|
|
56
57
|
## How it works
|
|
57
58
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|