devlaunch 0.0.1__tar.gz → 0.0.2__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: devlaunch
3
- Version: 0.0.1
3
+ Version: 0.0.2
4
4
  Summary: DevLaunch - A streamlined CLI for devpod workspaces
5
5
  Project-URL: Source, https://github.com/blooop/devlaunch
6
6
  Project-URL: Home, https://github.com/blooop/devlaunch
@@ -5,14 +5,11 @@ _dl_completion() {
5
5
  cur="${COMP_WORDS[COMP_CWORD]}"
6
6
  prev="${COMP_WORDS[COMP_CWORD-1]}"
7
7
 
8
- # Command options
9
- opts="--ls --repos --stop --rm --code --status --recreate --reset --install --help"
8
+ # Global command options (only valid as first arg)
9
+ local global_opts="--ls --install --help -h --version"
10
10
 
11
- # Flag completion
12
- if [[ ${cur} == -* ]]; then
13
- COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
14
- return 0
15
- fi
11
+ # Workspace subcommands
12
+ local ws_cmds="stop rm code restart recreate reset --"
16
13
 
17
14
  # Cache file location (honors XDG_CACHE_HOME)
18
15
  local cache_dir="${XDG_CACHE_HOME:-$HOME/.cache}/dl"
@@ -28,16 +25,14 @@ _dl_completion() {
28
25
  source "$cache_file"
29
26
  fi
30
27
 
31
- # Commands that need workspace completion
32
- if [[ "$prev" == "--stop" || "$prev" == "--rm" || "$prev" == "--code" || "$prev" == "--status" || "$prev" == "--recreate" || "$prev" == "--reset" ]]; then
33
- if [[ -n "$DL_WORKSPACES" ]]; then
34
- COMPREPLY=( $(compgen -W "${DL_WORKSPACES}" -- ${cur}) )
28
+ # First argument: global flags, workspaces, repos, owners, or paths
29
+ if [[ ${COMP_CWORD} -eq 1 ]]; then
30
+ # Global flags
31
+ if [[ ${cur} == -* ]]; then
32
+ COMPREPLY=( $(compgen -W "${global_opts}" -- ${cur}) )
33
+ return 0
35
34
  fi
36
- return 0
37
- fi
38
35
 
39
- # First positional argument: workspace, owner/repo, or path
40
- if [[ ${COMP_CWORD} -eq 1 ]]; then
41
36
  # Don't add space after completion to allow @branch suffix
42
37
  compopt -o nospace
43
38
 
@@ -71,6 +66,19 @@ _dl_completion() {
71
66
  return 0
72
67
  fi
73
68
 
69
+ # Second argument (after workspace): subcommands
70
+ if [[ ${COMP_CWORD} -eq 2 ]]; then
71
+ # Don't complete after global flags
72
+ local first="${COMP_WORDS[1]}"
73
+ if [[ "$first" == --* ]]; then
74
+ return 0
75
+ fi
76
+
77
+ COMPREPLY=( $(compgen -W "${ws_cmds}" -- ${cur}) )
78
+ return 0
79
+ fi
80
+
81
+ # After "--": no completion (user types shell command)
74
82
  return 0
75
83
  }
76
84
 
@@ -25,11 +25,21 @@ import logging
25
25
  import os
26
26
  import pathlib
27
27
  import re
28
+ from importlib.metadata import version as pkg_version, PackageNotFoundError
28
29
  from typing import List, Optional, Dict, Any
29
30
  from dataclasses import dataclass
30
31
 
31
32
  from .completion import install_completions
32
33
 
34
+
35
+ def get_version() -> str:
36
+ """Get the package version."""
37
+ try:
38
+ return pkg_version("devlaunch")
39
+ except PackageNotFoundError:
40
+ return "unknown"
41
+
42
+
33
43
  logging.basicConfig(level=logging.INFO, format="%(message)s")
34
44
 
35
45
 
@@ -485,32 +495,41 @@ def print_help():
485
495
  help_text = """dl - DevLaunch CLI
486
496
 
487
497
  Usage:
488
- dl Interactive workspace selector (fzf)
489
- dl <workspace> Start workspace and attach shell
490
- dl <workspace> <command> Run command in workspace
491
- dl owner/repo Create workspace from GitHub repo
492
- dl owner/repo@branch Create workspace from specific branch
493
- dl ./path Create workspace from local path
494
-
495
- Commands:
496
- --ls List all workspaces
497
- --stop <workspace> Stop a workspace
498
- --rm <workspace> Delete a workspace
499
- --code <workspace> Open workspace in VS Code
500
- --status <workspace> Show workspace status
501
- --recreate <workspace> Recreate workspace container
502
- --reset <workspace> Reset workspace (clean slate)
503
- --install Install shell completions
504
- --help, -h Show this help
498
+ dl Interactive workspace selector (fzf)
499
+ dl <user/repo> Start workspace and attach shell
500
+ dl <user/repo> <cmd> Run workspace command (stop, code, etc.)
501
+ dl <user/repo> -- <shell> Run shell command in workspace
502
+
503
+ Workspace sources:
504
+ dl myproject Existing workspace by name
505
+ dl user/repo Create from GitHub repo
506
+ dl user/repo@branch Create from specific branch
507
+ dl ./path Create from local path
508
+
509
+ Workspace commands:
510
+ dl <user/repo> stop Stop the workspace
511
+ dl <user/repo> rm, prune Delete the workspace
512
+ dl <user/repo> code Open in VS Code
513
+ dl <user/repo> restart Stop and start (no rebuild)
514
+ dl <user/repo> recreate Recreate container
515
+ dl <user/repo> reset Clean slate (remove all, recreate)
516
+ dl <user/repo> -- <command> Run shell command in workspace
517
+
518
+ Global commands:
519
+ dl --ls List all workspaces
520
+ dl --install Install shell completions
521
+ dl --help, -h Show this help
522
+ dl --version Show version
505
523
 
506
524
  Examples:
507
- dl # Select workspace with fzf
508
- dl myproject # Open existing workspace
509
- dl loft-sh/devpod # Create from GitHub
510
- dl blooop/devlaunch@main # Create from specific branch
511
- dl ./my-project # Create from local folder
512
- dl --code myproject # Open in VS Code
513
- dl myproject 'make test' # Run command in workspace
525
+ dl # Select workspace with fzf
526
+ dl devpod # Open existing workspace
527
+ dl loft-sh/devpod # Create from GitHub
528
+ dl blooop/devlaunch@main # Create from specific branch
529
+ dl ./my-project # Create from local folder
530
+ dl blooop/devlaunch code # Open in VS Code
531
+ dl blooop/devlaunch -- make test # Run command in workspace
532
+ dl blooop/devlaunch stop # Stop workspace
514
533
  """
515
534
  print(help_text)
516
535
 
@@ -519,20 +538,24 @@ def main() -> int:
519
538
  """Main entry point for dl CLI."""
520
539
  args = sys.argv[1:]
521
540
 
522
- # Handle help
523
- if not args or (len(args) == 1 and args[0] in ("--help", "-h")):
524
- if not args:
525
- # No args - try fzf selection
526
- selected = fuzzy_select_workspace()
527
- if not selected:
528
- print_help()
529
- return 1
530
- workspace_up(selected)
531
- return workspace_ssh(selected)
541
+ # No args - try fzf selection
542
+ if not args:
543
+ selected = fuzzy_select_workspace()
544
+ if not selected:
545
+ print_help()
546
+ return 1
547
+ workspace_up(selected)
548
+ return workspace_ssh(selected)
549
+
550
+ # Global commands (no workspace required)
551
+ if args[0] in ("--help", "-h"):
532
552
  print_help()
533
553
  return 0
534
554
 
535
- # Handle flags
555
+ if args[0] == "--version":
556
+ print(f"dl {get_version()}")
557
+ return 0
558
+
536
559
  if args[0] == "--ls":
537
560
  print_workspaces()
538
561
  return 0
@@ -572,80 +595,9 @@ def main() -> int:
572
595
  update_completion_cache()
573
596
  return install_completions(rc_path)
574
597
 
575
- if args[0] == "--stop":
576
- if len(args) < 2:
577
- workspace = fuzzy_select_workspace()
578
- if not workspace:
579
- logging.error("Usage: dl --stop <workspace>")
580
- return 1
581
- else:
582
- workspace = args[1]
583
- return workspace_stop(workspace)
584
-
585
- if args[0] == "--rm":
586
- if len(args) < 2:
587
- workspace = fuzzy_select_workspace()
588
- if not workspace:
589
- logging.error("Usage: dl --rm <workspace>")
590
- return 1
591
- else:
592
- workspace = args[1]
593
- return workspace_delete(workspace)
594
-
595
- if args[0] == "--status":
596
- if len(args) < 2:
597
- workspace = fuzzy_select_workspace()
598
- if not workspace:
599
- logging.error("Usage: dl --status <workspace>")
600
- return 1
601
- else:
602
- workspace = args[1]
603
- return workspace_status(workspace)
604
-
605
- if args[0] == "--code":
606
- if len(args) < 2:
607
- workspace = fuzzy_select_workspace()
608
- if not workspace:
609
- logging.error("Usage: dl --code <workspace>")
610
- return 1
611
- else:
612
- workspace = args[1]
613
- result = workspace_up(workspace, ide="vscode")
614
- return result.returncode
615
-
616
- if args[0] == "--recreate":
617
- if len(args) < 2:
618
- workspace = fuzzy_select_workspace()
619
- if not workspace:
620
- logging.error("Usage: dl --recreate <workspace>")
621
- return 1
622
- else:
623
- workspace = args[1]
624
- workspace_spec = expand_workspace_spec(workspace)
625
- workspace_id = spec_to_workspace_id(workspace)
626
- result = workspace_up(workspace_spec, recreate=True)
627
- if result.returncode != 0:
628
- return result.returncode
629
- return workspace_ssh(workspace_id)
630
-
631
- if args[0] == "--reset":
632
- if len(args) < 2:
633
- workspace = fuzzy_select_workspace()
634
- if not workspace:
635
- logging.error("Usage: dl --reset <workspace>")
636
- return 1
637
- else:
638
- workspace = args[1]
639
- workspace_spec = expand_workspace_spec(workspace)
640
- workspace_id = spec_to_workspace_id(workspace)
641
- result = workspace_up(workspace_spec, reset=True)
642
- if result.returncode != 0:
643
- return result.returncode
644
- return workspace_ssh(workspace_id)
645
-
646
- # Default: workspace name and optional command
598
+ # Workspace commands: dl <workspace> [subcommand] [-- command]
647
599
  raw_spec = args[0]
648
- command = " ".join(args[1:]) if len(args) > 1 else None
600
+ subcommand = args[1] if len(args) > 1 else None
649
601
 
650
602
  # Validate the workspace spec
651
603
  existing_ids = get_workspace_ids()
@@ -654,8 +606,7 @@ def main() -> int:
654
606
  logging.error(error)
655
607
  return 1
656
608
 
657
- # Use raw spec as-is if it's an existing workspace ID, otherwise expand
658
- # This prevents owner/repo-style workspace IDs from being rewritten
609
+ # Resolve workspace spec and ID
659
610
  if raw_spec in existing_ids:
660
611
  workspace_spec = raw_spec
661
612
  workspace_id = raw_spec
@@ -663,13 +614,58 @@ def main() -> int:
663
614
  workspace_spec = expand_workspace_spec(raw_spec)
664
615
  workspace_id = spec_to_workspace_id(raw_spec)
665
616
 
666
- # Start the workspace
617
+ # Handle workspace subcommands
618
+ if subcommand == "stop":
619
+ return workspace_stop(workspace_id)
620
+
621
+ if subcommand in ("rm", "prune"):
622
+ return workspace_delete(workspace_id)
623
+
624
+ if subcommand == "code":
625
+ result = workspace_up(workspace_spec, ide="vscode")
626
+ return result.returncode
627
+
628
+ if subcommand == "recreate":
629
+ result = workspace_up(workspace_spec, recreate=True)
630
+ if result.returncode != 0:
631
+ return result.returncode
632
+ return workspace_ssh(workspace_id)
633
+
634
+ if subcommand == "restart":
635
+ # Stop and start without rebuilding
636
+ stop_ret = workspace_stop(workspace_id)
637
+ if stop_ret != 0:
638
+ return stop_ret
639
+ result = workspace_up(workspace_spec)
640
+ if result.returncode != 0:
641
+ return result.returncode
642
+ return workspace_ssh(workspace_id)
643
+
644
+ if subcommand == "reset":
645
+ # Clean slate - remove everything and recreate
646
+ result = workspace_up(workspace_spec, reset=True)
647
+ if result.returncode != 0:
648
+ return result.returncode
649
+ return workspace_ssh(workspace_id)
650
+
651
+ # Check for shell command (after --)
652
+ shell_command = None
653
+ if subcommand == "--" and len(args) > 2:
654
+ shell_command = " ".join(args[2:])
655
+ elif subcommand is not None and subcommand != "--":
656
+ # Unknown subcommand - treat as error
657
+ logging.error(
658
+ f"Unknown command '{subcommand}'. Use 'dl {raw_spec} -- {subcommand}' to run a shell command."
659
+ )
660
+ return 1
661
+
662
+ # Default: start workspace and attach shell
667
663
  result = workspace_up(workspace_spec)
668
664
  if result.returncode != 0:
669
665
  return result.returncode
670
666
 
671
- # Attach to workspace using the ID (not the full spec)
672
- ret = workspace_ssh(workspace_id, command)
667
+ # Attach to workspace
668
+ ret = workspace_ssh(workspace_id, shell_command)
673
669
 
674
670
  # Update cache in background after workspace operations
675
671
  update_cache_background()
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "devlaunch"
3
- version = "0.0.1"
3
+ version = "0.0.2"
4
4
  authors = [{ name = "Austin Gregg-Smith", email = "blooop@gmail.com" }]
5
5
  description = "DevLaunch - A streamlined CLI for devpod workspaces"
6
6
  readme = "README.md"
@@ -109,7 +109,7 @@ extension-pkg-whitelist = ["numpy"]
109
109
  jobs = 16 #detect number of cores
110
110
 
111
111
  [tool.pylint.'MESSAGES CONTROL']
112
- disable = "C,logging-fstring-interpolation,line-too-long,fixme,broad-exception-caught,missing-module-docstring,too-many-instance-attributes,too-few-public-methods,too-many-arguments,too-many-locals,too-many-branches,too-many-statements,too-many-return-statements,use-dict-literal,cyclic-import,duplicate-code,too-many-public-methods"
112
+ disable = "C,logging-fstring-interpolation,line-too-long,fixme,broad-exception-caught,missing-module-docstring,too-many-instance-attributes,too-few-public-methods,too-many-arguments,too-many-positional-arguments,too-many-locals,too-many-branches,too-many-statements,too-many-return-statements,use-dict-literal,cyclic-import,duplicate-code,too-many-public-methods"
113
113
  enable = "no-else-return,consider-using-in"
114
114
 
115
115
  [tool.coverage.run]
File without changes
File without changes
File without changes