luv-cli 0.0.15__tar.gz → 0.0.17__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: luv-cli
3
- Version: 0.0.15
3
+ Version: 0.0.17
4
4
  Summary: Launch Claude Code agents on GitHub repos with isolated workspaces and optional Docker dev environments
5
5
  Project-URL: Homepage, https://github.com/exospherehost/luv
6
6
  Project-URL: Repository, https://github.com/exospherehost/luv
@@ -87,6 +87,7 @@ All workspaces live under `~/prs/`. The number comes from the repo's GitHub issu
87
87
  | `luv [org/]<repo> -pr <number> [prompt]` | Open a PR by repo + number |
88
88
  | `luv --clean` | Delete workspaces where the branch is fully pushed/merged |
89
89
  | `luv --clean -f` | Force delete all workspaces |
90
+ | `luv --clean --safe -f` | Force delete only workspaces older than 24h |
90
91
 
91
92
  ### Flags
92
93
 
@@ -95,9 +96,10 @@ All workspaces live under `~/prs/`. The number comes from the repo's GitHub issu
95
96
  | `-n` | Navigate: open a shell instead of Claude |
96
97
  | `-r` | Resume: resume the last Claude session |
97
98
  | `-p` | Launch Claude in plan permission mode (default: `bypassPermissions`) |
98
- | `-nit` | Non-interactive: run `claude -p <prompt>` and exit (no REPL) |
99
+ | `-nit` | Non-interactive: run `claude -p <prompt>` and exit (no REPL); streams `stream-json` events to stdout |
99
100
  | `-e` | Env: pass `LUV_*` environment variables (with prefix stripped) into the session |
100
101
  | `-f`, `--force` | Skip safety checks (with `--clean`) |
102
+ | `--safe` | With `--clean -f`, only delete workspaces older than 24h (mtime) |
101
103
 
102
104
  ## Docker dev environments
103
105
 
@@ -157,7 +159,7 @@ Docker mode works with all flags: `-n` opens a bash shell in the container, `-r`
157
159
  - No unpushed commits
158
160
  - If the remote branch is gone, verifies the PR was merged and local HEAD matches
159
161
 
160
- Use `luv --clean -f` to skip all safety checks and delete everything.
162
+ Use `luv --clean -f` to skip all safety checks and delete everything. Add `--safe` (i.e. `luv --clean --safe -f`) to restrict force-delete to workspaces whose folder mtime is older than 24 hours, leaving recently-touched workspaces alone.
161
163
 
162
164
  ## Configuration
163
165
 
@@ -64,6 +64,7 @@ All workspaces live under `~/prs/`. The number comes from the repo's GitHub issu
64
64
  | `luv [org/]<repo> -pr <number> [prompt]` | Open a PR by repo + number |
65
65
  | `luv --clean` | Delete workspaces where the branch is fully pushed/merged |
66
66
  | `luv --clean -f` | Force delete all workspaces |
67
+ | `luv --clean --safe -f` | Force delete only workspaces older than 24h |
67
68
 
68
69
  ### Flags
69
70
 
@@ -72,9 +73,10 @@ All workspaces live under `~/prs/`. The number comes from the repo's GitHub issu
72
73
  | `-n` | Navigate: open a shell instead of Claude |
73
74
  | `-r` | Resume: resume the last Claude session |
74
75
  | `-p` | Launch Claude in plan permission mode (default: `bypassPermissions`) |
75
- | `-nit` | Non-interactive: run `claude -p <prompt>` and exit (no REPL) |
76
+ | `-nit` | Non-interactive: run `claude -p <prompt>` and exit (no REPL); streams `stream-json` events to stdout |
76
77
  | `-e` | Env: pass `LUV_*` environment variables (with prefix stripped) into the session |
77
78
  | `-f`, `--force` | Skip safety checks (with `--clean`) |
79
+ | `--safe` | With `--clean -f`, only delete workspaces older than 24h (mtime) |
78
80
 
79
81
  ## Docker dev environments
80
82
 
@@ -134,7 +136,7 @@ Docker mode works with all flags: `-n` opens a bash shell in the container, `-r`
134
136
  - No unpushed commits
135
137
  - If the remote branch is gone, verifies the PR was merged and local HEAD matches
136
138
 
137
- Use `luv --clean -f` to skip all safety checks and delete everything.
139
+ Use `luv --clean -f` to skip all safety checks and delete everything. Add `--safe` (i.e. `luv --clean --safe -f`) to restrict force-delete to workspaces whose folder mtime is older than 24 hours, leaving recently-touched workspaces alone.
138
140
 
139
141
  ## Configuration
140
142
 
@@ -6,6 +6,7 @@ import shutil
6
6
  import subprocess
7
7
  import sys
8
8
  import tempfile
9
+ import time
9
10
  from pathlib import Path
10
11
 
11
12
  LUV_DIR = Path.home() / ".luv"
@@ -363,7 +364,8 @@ def launch(clone_dir: Path, prompt: str | None, plan_mode: bool = False,
363
364
  if non_interactive:
364
365
  if not prompt:
365
366
  die("-nit requires a prompt")
366
- mode_flags = []
367
+ mode_flags = ["--output-format", "stream-json",
368
+ "--verbose", "--include-partial-messages"]
367
369
  initial_args = ["-p", prompt]
368
370
  elif plan_mode:
369
371
  mode_flags = ["--permission-mode", "plan"]
@@ -390,7 +392,10 @@ def launch(clone_dir: Path, prompt: str | None, plan_mode: bool = False,
390
392
  os.execv(claude_bin, [claude_bin] + common_flags + mode_flags + initial_args)
391
393
 
392
394
 
393
- def cmd_clean(force: bool = False) -> None:
395
+ SAFE_AGE_SECONDS = 24 * 3600
396
+
397
+
398
+ def cmd_clean(force: bool = False, safe: bool = False) -> None:
394
399
  """Scan ~/prs/ and delete fully-pushed, clean work folders."""
395
400
  if not PRS_DIR.exists():
396
401
  print("luv: nothing to clean (~/prs/ does not exist)")
@@ -398,6 +403,7 @@ def cmd_clean(force: bool = False) -> None:
398
403
 
399
404
  cleaned: list[str] = []
400
405
  skipped: list[tuple[str, str]] = []
406
+ now = time.time()
401
407
 
402
408
  for entry in sorted(PRS_DIR.iterdir()):
403
409
  if not entry.is_dir():
@@ -408,6 +414,9 @@ def cmd_clean(force: bool = False) -> None:
408
414
  continue # doesn't match {repo}-{number} — skip silently
409
415
 
410
416
  if force:
417
+ if safe and (now - entry.stat().st_mtime) < SAFE_AGE_SECONDS:
418
+ skipped.append((entry.name, "younger than 24h (--safe)"))
419
+ continue
411
420
  shutil.rmtree(entry)
412
421
  cleaned.append(entry.name)
413
422
  continue
@@ -588,8 +597,9 @@ def main() -> None:
588
597
  plan_mode = "-p" in args
589
598
  non_interactive = "-nit" in args
590
599
  force = "-f" in args or "--force" in args
600
+ safe = "--safe" in args
591
601
  env_mode = "-e" in args
592
- args = [a for a in args if a not in ("-n", "-r", "-e", "-f", "--force", "-p", "-nit")]
602
+ args = [a for a in args if a not in ("-n", "-r", "-e", "-f", "--force", "-p", "-nit", "--safe")]
593
603
  extra_env = collect_luv_env() if env_mode else {}
594
604
 
595
605
  if not args or args[0] in ("-h", "--help"):
@@ -603,6 +613,7 @@ Flags:
603
613
  -nit non-interactive: run claude -p <prompt> and exit (no REPL)
604
614
  -e env: pass LUV_* environment variables (with prefix stripped) into the session
605
615
  -f, --force (with --clean) skip safety checks and delete all work folders
616
+ --safe (with --clean -f) only delete folders older than 24h
606
617
 
607
618
  Commands:
608
619
  luv --init configure default GitHub org
@@ -612,7 +623,7 @@ Commands:
612
623
  luv [org/]<repo> -pr <number> [prompt] open a GitHub PR by repo + number
613
624
  luv [org/]<repo> -n open shell in latest local clone
614
625
  luv [org/]<repo> -r resume Claude in latest local clone
615
- luv --clean [-f] delete fully-pushed work folders
626
+ luv --clean [-f] [--safe] delete fully-pushed work folders
616
627
 
617
628
  Org resolution:
618
629
  Explicit org/repo overrides the default. Run 'luv --init' to set a default.
@@ -624,8 +635,11 @@ Docker:
624
635
  "dev-environment" service. Torn down automatically on exit.""")
625
636
  sys.exit(0)
626
637
 
638
+ if safe and (args[0] != "--clean" or not force):
639
+ die("--safe only works with --clean -f")
640
+
627
641
  if args[0] == "--clean":
628
- cmd_clean(force=force)
642
+ cmd_clean(force=force, safe=safe)
629
643
  return
630
644
 
631
645
  if args[0] == "--init":
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "luv-cli"
7
- version = "0.0.15"
7
+ version = "0.0.17"
8
8
  description = "Launch Claude Code agents on GitHub repos with isolated workspaces and optional Docker dev environments"
9
9
  requires-python = ">=3.10"
10
10
  license = "MIT"
File without changes
File without changes
File without changes