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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ghosttrap-cli
3
- Version: 0.3.11
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.11"
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}`. Older configs may still be keyed by `"owner/name"` — same shape inside.
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.11
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
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ghosttrap-cli"
7
- version = "0.3.11"
7
+ version = "0.3.13"
8
8
  description = "Watch for errors streaming from ghosttrap.io"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
File without changes