cmdbox-cli 1.0.0__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.
Files changed (118) hide show
  1. cmdbox_cli-1.0.0/LICENSE +21 -0
  2. cmdbox_cli-1.0.0/PKG-INFO +125 -0
  3. cmdbox_cli-1.0.0/README.md +101 -0
  4. cmdbox_cli-1.0.0/pyproject.toml +77 -0
  5. cmdbox_cli-1.0.0/setup.cfg +4 -0
  6. cmdbox_cli-1.0.0/src/cmdbox/__init__.py +0 -0
  7. cmdbox_cli-1.0.0/src/cmdbox/cli/__init__.py +0 -0
  8. cmdbox_cli-1.0.0/src/cmdbox/cli/app.py +125 -0
  9. cmdbox_cli-1.0.0/src/cmdbox/cli/commands/__init__.py +0 -0
  10. cmdbox_cli-1.0.0/src/cmdbox/cli/commands/alias_fallback.py +102 -0
  11. cmdbox_cli-1.0.0/src/cmdbox/cli/commands/command_crud.py +429 -0
  12. cmdbox_cli-1.0.0/src/cmdbox/cli/commands/command_run.py +255 -0
  13. cmdbox_cli-1.0.0/src/cmdbox/cli/commands/history.py +109 -0
  14. cmdbox_cli-1.0.0/src/cmdbox/cli/commands/init.py +54 -0
  15. cmdbox_cli-1.0.0/src/cmdbox/cli/commands/settings.py +62 -0
  16. cmdbox_cli-1.0.0/src/cmdbox/cli/commands/tag_crud.py +277 -0
  17. cmdbox_cli-1.0.0/src/cmdbox/cli/commands/variable_crud.py +349 -0
  18. cmdbox_cli-1.0.0/src/cmdbox/cli/common/__init__.py +0 -0
  19. cmdbox_cli-1.0.0/src/cmdbox/cli/common/errors.py +58 -0
  20. cmdbox_cli-1.0.0/src/cmdbox/cli/common/update_fields.py +88 -0
  21. cmdbox_cli-1.0.0/src/cmdbox/cli/completions/__init__.py +0 -0
  22. cmdbox_cli-1.0.0/src/cmdbox/cli/completions/commands.py +26 -0
  23. cmdbox_cli-1.0.0/src/cmdbox/cli/completions/fields.py +31 -0
  24. cmdbox_cli-1.0.0/src/cmdbox/cli/completions/tags.py +24 -0
  25. cmdbox_cli-1.0.0/src/cmdbox/cli/completions/variables.py +26 -0
  26. cmdbox_cli-1.0.0/src/cmdbox/cli/handlers/__init__.py +0 -0
  27. cmdbox_cli-1.0.0/src/cmdbox/cli/handlers/command_handlers.py +357 -0
  28. cmdbox_cli-1.0.0/src/cmdbox/cli/handlers/common_handlers.py +15 -0
  29. cmdbox_cli-1.0.0/src/cmdbox/cli/handlers/history_handlers.py +94 -0
  30. cmdbox_cli-1.0.0/src/cmdbox/cli/handlers/init_handler.py +127 -0
  31. cmdbox_cli-1.0.0/src/cmdbox/cli/handlers/run_handler.py +178 -0
  32. cmdbox_cli-1.0.0/src/cmdbox/cli/handlers/settings_handler.py +59 -0
  33. cmdbox_cli-1.0.0/src/cmdbox/cli/handlers/tag_handlers.py +220 -0
  34. cmdbox_cli-1.0.0/src/cmdbox/cli/handlers/variable_handlers.py +272 -0
  35. cmdbox_cli-1.0.0/src/cmdbox/cli/prompts/__init__.py +0 -0
  36. cmdbox_cli-1.0.0/src/cmdbox/cli/prompts/completers.py +161 -0
  37. cmdbox_cli-1.0.0/src/cmdbox/cli/prompts/prompts.py +108 -0
  38. cmdbox_cli-1.0.0/src/cmdbox/cli/prompts/validators.py +46 -0
  39. cmdbox_cli-1.0.0/src/cmdbox/cli/ui/__init__.py +0 -0
  40. cmdbox_cli-1.0.0/src/cmdbox/cli/ui/console.py +31 -0
  41. cmdbox_cli-1.0.0/src/cmdbox/cli/ui/editor.py +141 -0
  42. cmdbox_cli-1.0.0/src/cmdbox/cli/ui/presenters/__init__.py +0 -0
  43. cmdbox_cli-1.0.0/src/cmdbox/cli/ui/presenters/app_presenter.py +8 -0
  44. cmdbox_cli-1.0.0/src/cmdbox/cli/ui/presenters/command_presenter.py +168 -0
  45. cmdbox_cli-1.0.0/src/cmdbox/cli/ui/presenters/history_presenter.py +83 -0
  46. cmdbox_cli-1.0.0/src/cmdbox/cli/ui/presenters/init_instructions.py +52 -0
  47. cmdbox_cli-1.0.0/src/cmdbox/cli/ui/presenters/init_presenter.py +57 -0
  48. cmdbox_cli-1.0.0/src/cmdbox/cli/ui/presenters/result_presenter.py +144 -0
  49. cmdbox_cli-1.0.0/src/cmdbox/cli/ui/presenters/settings_presenter.py +130 -0
  50. cmdbox_cli-1.0.0/src/cmdbox/cli/ui/presenters/tag_presenter.py +97 -0
  51. cmdbox_cli-1.0.0/src/cmdbox/cli/ui/presenters/variable_presenter.py +103 -0
  52. cmdbox_cli-1.0.0/src/cmdbox/cli/ui/primitives.py +410 -0
  53. cmdbox_cli-1.0.0/src/cmdbox/cli/ui/theme.py +43 -0
  54. cmdbox_cli-1.0.0/src/cmdbox/cli/ui/theme_builder.py +49 -0
  55. cmdbox_cli-1.0.0/src/cmdbox/common/__init__.py +0 -0
  56. cmdbox_cli-1.0.0/src/cmdbox/common/io.py +34 -0
  57. cmdbox_cli-1.0.0/src/cmdbox/container.py +156 -0
  58. cmdbox_cli-1.0.0/src/cmdbox/core/__init__.py +0 -0
  59. cmdbox_cli-1.0.0/src/cmdbox/core/fields.py +48 -0
  60. cmdbox_cli-1.0.0/src/cmdbox/core/paths.py +52 -0
  61. cmdbox_cli-1.0.0/src/cmdbox/database.py +65 -0
  62. cmdbox_cli-1.0.0/src/cmdbox/exceptions.py +10 -0
  63. cmdbox_cli-1.0.0/src/cmdbox/init/__init__.py +0 -0
  64. cmdbox_cli-1.0.0/src/cmdbox/init/detect.py +82 -0
  65. cmdbox_cli-1.0.0/src/cmdbox/init/integrations/bash.sh +10 -0
  66. cmdbox_cli-1.0.0/src/cmdbox/init/integrations/cmd.bat +14 -0
  67. cmdbox_cli-1.0.0/src/cmdbox/init/integrations/fish.fish +11 -0
  68. cmdbox_cli-1.0.0/src/cmdbox/init/integrations/powershell.ps1 +14 -0
  69. cmdbox_cli-1.0.0/src/cmdbox/init/integrations/zsh.sh +10 -0
  70. cmdbox_cli-1.0.0/src/cmdbox/init/io.py +68 -0
  71. cmdbox_cli-1.0.0/src/cmdbox/init/specs.py +54 -0
  72. cmdbox_cli-1.0.0/src/cmdbox/logging_setup/__init__.py +0 -0
  73. cmdbox_cli-1.0.0/src/cmdbox/logging_setup/log_config.py +123 -0
  74. cmdbox_cli-1.0.0/src/cmdbox/logging_setup/log_decorators.py +40 -0
  75. cmdbox_cli-1.0.0/src/cmdbox/logging_setup/log_handlers.py +94 -0
  76. cmdbox_cli-1.0.0/src/cmdbox/migrations/__init__.py +1 -0
  77. cmdbox_cli-1.0.0/src/cmdbox/migrations/errors.py +10 -0
  78. cmdbox_cli-1.0.0/src/cmdbox/migrations/runner.py +127 -0
  79. cmdbox_cli-1.0.0/src/cmdbox/migrations/versions/__init__.py +0 -0
  80. cmdbox_cli-1.0.0/src/cmdbox/models.py +165 -0
  81. cmdbox_cli-1.0.0/src/cmdbox/repositories/__init__.py +0 -0
  82. cmdbox_cli-1.0.0/src/cmdbox/repositories/base_repository.py +181 -0
  83. cmdbox_cli-1.0.0/src/cmdbox/repositories/command_repository.py +391 -0
  84. cmdbox_cli-1.0.0/src/cmdbox/repositories/errors.py +120 -0
  85. cmdbox_cli-1.0.0/src/cmdbox/repositories/history_repository.py +155 -0
  86. cmdbox_cli-1.0.0/src/cmdbox/repositories/results.py +37 -0
  87. cmdbox_cli-1.0.0/src/cmdbox/repositories/tag_repository.py +91 -0
  88. cmdbox_cli-1.0.0/src/cmdbox/repositories/validators.py +256 -0
  89. cmdbox_cli-1.0.0/src/cmdbox/repositories/variable_repository.py +324 -0
  90. cmdbox_cli-1.0.0/src/cmdbox/resolve/__init__.py +0 -0
  91. cmdbox_cli-1.0.0/src/cmdbox/resolve/errors.py +65 -0
  92. cmdbox_cli-1.0.0/src/cmdbox/resolve/lookup.py +137 -0
  93. cmdbox_cli-1.0.0/src/cmdbox/resolve/resolver.py +402 -0
  94. cmdbox_cli-1.0.0/src/cmdbox/resolve/type_defs.py +96 -0
  95. cmdbox_cli-1.0.0/src/cmdbox/runtime/__init__.py +0 -0
  96. cmdbox_cli-1.0.0/src/cmdbox/runtime/executor.py +454 -0
  97. cmdbox_cli-1.0.0/src/cmdbox/runtime/results.py +25 -0
  98. cmdbox_cli-1.0.0/src/cmdbox/runtime/shell.py +90 -0
  99. cmdbox_cli-1.0.0/src/cmdbox/services/__init__.py +0 -0
  100. cmdbox_cli-1.0.0/src/cmdbox/services/command_services.py +261 -0
  101. cmdbox_cli-1.0.0/src/cmdbox/services/errors.py +37 -0
  102. cmdbox_cli-1.0.0/src/cmdbox/services/field_selection.py +162 -0
  103. cmdbox_cli-1.0.0/src/cmdbox/services/history_service.py +68 -0
  104. cmdbox_cli-1.0.0/src/cmdbox/services/run_service.py +204 -0
  105. cmdbox_cli-1.0.0/src/cmdbox/services/tag_services.py +134 -0
  106. cmdbox_cli-1.0.0/src/cmdbox/services/variable_services.py +224 -0
  107. cmdbox_cli-1.0.0/src/cmdbox/settings/__init__.py +0 -0
  108. cmdbox_cli-1.0.0/src/cmdbox/settings/models.py +129 -0
  109. cmdbox_cli-1.0.0/src/cmdbox/settings/settings_repository.py +36 -0
  110. cmdbox_cli-1.0.0/src/cmdbox/settings/settings_service.py +144 -0
  111. cmdbox_cli-1.0.0/src/cmdbox/version.py +1 -0
  112. cmdbox_cli-1.0.0/src/cmdbox_cli.egg-info/PKG-INFO +125 -0
  113. cmdbox_cli-1.0.0/src/cmdbox_cli.egg-info/SOURCES.txt +116 -0
  114. cmdbox_cli-1.0.0/src/cmdbox_cli.egg-info/dependency_links.txt +1 -0
  115. cmdbox_cli-1.0.0/src/cmdbox_cli.egg-info/entry_points.txt +2 -0
  116. cmdbox_cli-1.0.0/src/cmdbox_cli.egg-info/requires.txt +15 -0
  117. cmdbox_cli-1.0.0/src/cmdbox_cli.egg-info/top_level.txt +1 -0
  118. cmdbox_cli-1.0.0/tests/test_models.py +295 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Phantom Lamb
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,125 @@
1
+ Metadata-Version: 2.4
2
+ Name: cmdbox-cli
3
+ Version: 1.0.0
4
+ Summary: A cross-platform command manager for terminal workflows.
5
+ Author-email: MalloyDelacroix <malloydelacroix@phantomlamb.com>
6
+ Requires-Python: >=3.12
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Requires-Dist: typer>=0.21.0
10
+ Requires-Dist: rich>=14.0.0
11
+ Requires-Dist: peewee>=3.18.3
12
+ Requires-Dist: prompt-toolkit>=3.0.52
13
+ Requires-Dist: pyyaml>=6.0.0
14
+ Requires-Dist: tomlkit>=0.13.3
15
+ Requires-Dist: psutil>=7.2.1
16
+ Provides-Extra: dev
17
+ Requires-Dist: black>=25.0.0; extra == "dev"
18
+ Requires-Dist: isort>=5.13.0; extra == "dev"
19
+ Requires-Dist: mkdocs>=1.6.1; extra == "dev"
20
+ Requires-Dist: ruff>=0.14.0; extra == "dev"
21
+ Requires-Dist: mypy>=1.10.0; extra == "dev"
22
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
23
+ Dynamic: license-file
24
+
25
+ # CmdBox
26
+
27
+ A fast, structured, and searchable command runner for the terminal.
28
+
29
+ CmdBox replaces fragile shell history and scattered notes with a clean, organized system for
30
+ storing, searching, and executing commands. Designed for anyone who works in the terminal,
31
+ from occasional users to seasoned developers.
32
+
33
+ ---
34
+
35
+ ## Why CmdBox?
36
+
37
+ Most terminal users have commands they run regularly. Some are short. Many are long and
38
+ complex, packed with flags and options that are easy to forget. Recalling them means digging
39
+ through shell history, hunting through notes, or searching online every time.
40
+
41
+ CmdBox gives every command a short, memorable alias. Run it instantly. No retyping, no
42
+ searching, no forgetting.
43
+
44
+ ---
45
+
46
+ ## Features
47
+
48
+ - Named commands with short, memorable aliases
49
+ - Parameterized templates with saved and runtime variables
50
+ - Stored execution context per command (working directory, shell, environment variables, and timeout) with runtime
51
+ overrides
52
+ - Command execution history with the ability to rerun past executions
53
+ - Tag-based organization and filtering
54
+ - Field-based search across commands, variables, and tags
55
+ - Multi-line template execution via script
56
+ - Rich terminal UI with configurable display fields
57
+
58
+ ---
59
+
60
+ ## Quick Start
61
+
62
+ #### Save and run a command
63
+
64
+ ```bash
65
+ # Save a command under an alias
66
+ cb cmd add git-graph "git log --oneline --graph --decorate --all"
67
+
68
+ # Run it by alias, no subcommand needed
69
+ cb git-graph
70
+
71
+ # List all saved commands
72
+ cb cmd list
73
+
74
+ # Search saved commands
75
+ cb cmd search git
76
+ ```
77
+
78
+ #### Use variables for flexible commands
79
+
80
+ ```bash
81
+ # Save a command with variable placeholders
82
+ cb cmd add ssh-connect "ssh <user>@<host> -p <port>"
83
+
84
+ # Save variable values so they fill in automatically
85
+ cb var add user admin
86
+ cb var add host 10.0.0.5
87
+ cb var add port 22
88
+
89
+ # Run the command, variables are resolved before executing
90
+ cb ssh-connect
91
+
92
+ # What gets executed:
93
+ ssh admin@10.0.0.5 -p 22
94
+
95
+ # Supply a different value at runtime to override a saved one
96
+ cb ssh-connect --host 192.168.1.1
97
+ ```
98
+
99
+ ---
100
+
101
+ ## Installation
102
+
103
+ ```bash
104
+ pip install cmdbox-cli
105
+ ```
106
+
107
+ Or install from source:
108
+
109
+ ```bash
110
+ git clone https://github.com/PhantomLambSoft/CmdBox.git
111
+ cd cmdbox
112
+ pip install .
113
+ ```
114
+
115
+ After installation, verify it worked:
116
+
117
+ ```bash
118
+ cb --version
119
+ ```
120
+
121
+ ---
122
+
123
+ ## Documentation
124
+
125
+ Full documentation is available at [phantomlambsoft.github.io/CmdBox](https://phantomlambsoft.github.io/CmdBox).
@@ -0,0 +1,101 @@
1
+ # CmdBox
2
+
3
+ A fast, structured, and searchable command runner for the terminal.
4
+
5
+ CmdBox replaces fragile shell history and scattered notes with a clean, organized system for
6
+ storing, searching, and executing commands. Designed for anyone who works in the terminal,
7
+ from occasional users to seasoned developers.
8
+
9
+ ---
10
+
11
+ ## Why CmdBox?
12
+
13
+ Most terminal users have commands they run regularly. Some are short. Many are long and
14
+ complex, packed with flags and options that are easy to forget. Recalling them means digging
15
+ through shell history, hunting through notes, or searching online every time.
16
+
17
+ CmdBox gives every command a short, memorable alias. Run it instantly. No retyping, no
18
+ searching, no forgetting.
19
+
20
+ ---
21
+
22
+ ## Features
23
+
24
+ - Named commands with short, memorable aliases
25
+ - Parameterized templates with saved and runtime variables
26
+ - Stored execution context per command (working directory, shell, environment variables, and timeout) with runtime
27
+ overrides
28
+ - Command execution history with the ability to rerun past executions
29
+ - Tag-based organization and filtering
30
+ - Field-based search across commands, variables, and tags
31
+ - Multi-line template execution via script
32
+ - Rich terminal UI with configurable display fields
33
+
34
+ ---
35
+
36
+ ## Quick Start
37
+
38
+ #### Save and run a command
39
+
40
+ ```bash
41
+ # Save a command under an alias
42
+ cb cmd add git-graph "git log --oneline --graph --decorate --all"
43
+
44
+ # Run it by alias, no subcommand needed
45
+ cb git-graph
46
+
47
+ # List all saved commands
48
+ cb cmd list
49
+
50
+ # Search saved commands
51
+ cb cmd search git
52
+ ```
53
+
54
+ #### Use variables for flexible commands
55
+
56
+ ```bash
57
+ # Save a command with variable placeholders
58
+ cb cmd add ssh-connect "ssh <user>@<host> -p <port>"
59
+
60
+ # Save variable values so they fill in automatically
61
+ cb var add user admin
62
+ cb var add host 10.0.0.5
63
+ cb var add port 22
64
+
65
+ # Run the command, variables are resolved before executing
66
+ cb ssh-connect
67
+
68
+ # What gets executed:
69
+ ssh admin@10.0.0.5 -p 22
70
+
71
+ # Supply a different value at runtime to override a saved one
72
+ cb ssh-connect --host 192.168.1.1
73
+ ```
74
+
75
+ ---
76
+
77
+ ## Installation
78
+
79
+ ```bash
80
+ pip install cmdbox-cli
81
+ ```
82
+
83
+ Or install from source:
84
+
85
+ ```bash
86
+ git clone https://github.com/PhantomLambSoft/CmdBox.git
87
+ cd cmdbox
88
+ pip install .
89
+ ```
90
+
91
+ After installation, verify it worked:
92
+
93
+ ```bash
94
+ cb --version
95
+ ```
96
+
97
+ ---
98
+
99
+ ## Documentation
100
+
101
+ Full documentation is available at [phantomlambsoft.github.io/CmdBox](https://phantomlambsoft.github.io/CmdBox).
@@ -0,0 +1,77 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "cmdbox-cli"
7
+ version = "1.0.0"
8
+ description = "A cross-platform command manager for terminal workflows."
9
+ readme = "README.md"
10
+ authors = [
11
+ { name = "MalloyDelacroix", email = "malloydelacroix@phantomlamb.com" }
12
+ ]
13
+ requires-python = ">=3.12"
14
+
15
+ dependencies = [
16
+ "typer>=0.21.0",
17
+ "rich>=14.0.0",
18
+ "peewee>=3.18.3",
19
+ "prompt-toolkit>=3.0.52",
20
+ "pyyaml>=6.0.0",
21
+ "tomlkit>=0.13.3",
22
+ "psutil>=7.2.1",
23
+ ]
24
+
25
+ [project.optional-dependencies]
26
+ dev = [
27
+ "black>=25.0.0",
28
+ "isort>=5.13.0",
29
+ "mkdocs>=1.6.1",
30
+ "ruff>=0.14.0",
31
+ "mypy>=1.10.0",
32
+ "pytest>=8.0.0",
33
+ ]
34
+
35
+ [project.scripts]
36
+ cb = "cmdbox.cli.app:main"
37
+
38
+ [tool.setuptools.packages.find]
39
+ where = ["src"]
40
+ include = ["cmdbox*"]
41
+
42
+ [tool.setuptools.package-data]
43
+ cmdbox = ["*.yaml", "*.json", "*.txt", "init/integrations/*"]
44
+
45
+ [tool.black]
46
+ line-length = 88
47
+ target-version = ["py310", "py311"]
48
+
49
+ [tool.isort]
50
+ profile = "black"
51
+ line_length = 88
52
+ known_first_party = ["cmdbox"]
53
+ src_paths = ["src", "tests"]
54
+
55
+ [tool.ruff]
56
+ line-length = 88
57
+ target-version = "py310"
58
+ src = ["src", "tests"]
59
+ select = [
60
+ "E",
61
+ "F",
62
+ "I",
63
+ "B",
64
+ "UP",
65
+ ]
66
+ ignore = [
67
+ "E501",
68
+ ]
69
+
70
+ [tool.ruff.lint.isort]
71
+ known-first-party = ["cmdbox"]
72
+
73
+ [tool.mypy]
74
+ python_version = "3.14"
75
+ strict = false
76
+ ignore_missing_imports = true
77
+ show_error_codes = true
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
File without changes
File without changes
@@ -0,0 +1,125 @@
1
+ import uuid
2
+ from typing import Annotated
3
+
4
+ import typer
5
+
6
+ from cmdbox import container
7
+ from cmdbox.cli.commands.alias_fallback import AliasFallbackGroup
8
+ from cmdbox.cli.ui.presenters.app_presenter import render_version
9
+ from cmdbox.logging_setup.log_handlers import configure_logging
10
+ from cmdbox.logging_setup.log_config import build_log_config, get_logger
11
+ from cmdbox.version import __version__
12
+ from cmdbox.database import ensure_schema, get_db
13
+ from .commands.command_crud import app as command_crud_app
14
+ from .commands.command_run import app as command_run_app
15
+ from .commands.variable_crud import app as variable_crud_app
16
+ from .commands.tag_crud import app as tag_crud_app
17
+ from .commands.init import app as init_app
18
+ from .commands.settings import app as settings_app
19
+ from .commands.history import app as history_app
20
+
21
+ app = typer.Typer(
22
+ name="cb",
23
+ cls=AliasFallbackGroup,
24
+ help="CmdBox is a CLI tool for storing and recalling commands with many helpful quality of life features.",
25
+ no_args_is_help=True,
26
+ )
27
+
28
+ app.add_typer(
29
+ command_crud_app,
30
+ name="cmd",
31
+ help="CRUD (Create, Read, Update, Delete) operations for commands.",
32
+ )
33
+ app.add_typer(variable_crud_app, name="var", help="CRUD operations for variables.")
34
+ app.add_typer(tag_crud_app, name="tag", help="CRUD operations for tags.")
35
+ app.add_typer(command_run_app)
36
+ app.add_typer(init_app)
37
+ app.add_typer(settings_app, name="settings", help="Manage CmdBox settings.")
38
+ app.add_typer(
39
+ history_app, name="history", help="View and re-run command execution history."
40
+ )
41
+
42
+
43
+ def version_callback(value: bool):
44
+ if value:
45
+ console = container.get_console()
46
+ rendered_version = render_version(__version__)
47
+ console.print(rendered_version)
48
+ raise typer.Exit()
49
+
50
+
51
+ @app.callback()
52
+ def common(
53
+ test: Annotated[
54
+ bool,
55
+ typer.Option(
56
+ "--test",
57
+ "-t",
58
+ help="Enables testing mode. Database will be created in memory and will not affect the "
59
+ "applications persistent database.",
60
+ ),
61
+ ] = False,
62
+ verbose: Annotated[
63
+ bool,
64
+ typer.Option(
65
+ "--verbose",
66
+ "-v",
67
+ help="Enable additional diagnostic output in the terminal. Sets console log level to INFO.",
68
+ ),
69
+ ] = False,
70
+ debug: Annotated[
71
+ bool,
72
+ typer.Option(
73
+ "--debug",
74
+ "-d",
75
+ help="Enable full diagnostic output in the terminal. Sets console log level to DEBUG.",
76
+ ),
77
+ ] = False,
78
+ file_logs: Annotated[
79
+ bool | None,
80
+ typer.Option(
81
+ "--file-logs/--no-file-logs",
82
+ help="Enable/disables writing diagnostic logs to a file. Defaults to settings.",
83
+ ),
84
+ ] = None,
85
+ version: Annotated[
86
+ bool,
87
+ typer.Option(
88
+ "--version",
89
+ "-V",
90
+ callback=version_callback,
91
+ is_eager=True,
92
+ help="Print the app version and exit.",
93
+ ),
94
+ ] = None,
95
+ ) -> None:
96
+ if test:
97
+ get_db(testing=True)
98
+
99
+ settings = container.get_settings()
100
+
101
+ run_id = uuid.uuid4().hex[:6]
102
+ log_config = build_log_config(
103
+ settings=settings, verbose=verbose, debug=debug, file_logs=file_logs
104
+ )
105
+ configure_logging(log_config, run_id=run_id)
106
+
107
+ log = get_logger()
108
+ log.debug(
109
+ f"startup: test={test}, verbose={verbose}, debug={debug}, file_logs={file_logs}"
110
+ )
111
+ log.debug(f"file_logging={log_config.file_enabled} path={log_config.file_path}")
112
+
113
+ ensure_schema()
114
+
115
+ if test:
116
+ console = container.get_console()
117
+ console.info("Testing mode is active, database is in memory.")
118
+
119
+
120
+ def main() -> None:
121
+ app()
122
+
123
+
124
+ if __name__ == "__main__":
125
+ main()
File without changes
@@ -0,0 +1,102 @@
1
+ import click
2
+ from typer.core import TyperGroup
3
+
4
+
5
+ class AliasFallbackGroup(TyperGroup):
6
+ """
7
+ Handles command grouping with support for alias-based fallback.
8
+
9
+ This class extends the functionality of TyperGroup to include command alias
10
+ resolution. When a command is not directly found, it attempts to resolve the
11
+ command name using a predefined alias mapping and dynamically generates an
12
+ alias command that forwards its arguments to a core `run` command. This allows
13
+ users to define shorter or alternate names for commands while maintaining
14
+ flexibility.
15
+
16
+ Attributes:
17
+ _command_aliases (dict[str, str]): A mapping of alias names to their
18
+ corresponding actual command names. Used for resolving commands
19
+ through aliases.
20
+ """
21
+
22
+ _command_aliases: dict[str, str] = {
23
+ "cmds": "cmd",
24
+ "vars": "var",
25
+ "tags": "tag",
26
+ "hist": "history",
27
+ }
28
+
29
+ """
30
+ The second item in the list is the name of the command as configured by
31
+ `@app.command("command_name")`, not the method name. Further items in the list
32
+ will be supplied to that sub-command as args.
33
+ """
34
+ _shortcut_commands: dict[str, list[str]] = {"!!": ["history", "last"]}
35
+
36
+ def get_command(self, ctx: click.Context, cmd_name: str):
37
+ """
38
+ Retrieves a command based on the command name, creating an alias command if
39
+ the command was not directly found.
40
+
41
+ If the command corresponding to `cmd_name` doesn't exist, a new alias
42
+ command is generated using the `run` command, forwarding all its parameters
43
+ except the `alias` parameter.
44
+
45
+ Args:
46
+ ctx (click.Context): The Click context in which the command is being
47
+ invoked.
48
+ cmd_name (str): The name of the command to retrieve.
49
+
50
+ Returns:
51
+ click.Command: The command object corresponding to the given
52
+ `cmd_name`, or an alias command if the original command does not exist.
53
+ Returns None if `run` command is also unavailable.
54
+ """
55
+ cmd_name = self._command_aliases.get(cmd_name, cmd_name)
56
+
57
+ rv = super().get_command(ctx, cmd_name)
58
+ if rv is not None:
59
+ return rv
60
+
61
+ run_cmd = super().get_command(ctx, "run")
62
+ if run_cmd is None:
63
+ return None
64
+
65
+ forwarded_params = [p for p in run_cmd.params if p.name != "alias"]
66
+
67
+ @click.command(
68
+ cmd_name,
69
+ params=forwarded_params,
70
+ help=f"Run stored command '{cmd_name}'.",
71
+ context_settings=run_cmd.context_settings,
72
+ )
73
+ @click.pass_context
74
+ def _alias_cmd(inner_ctx: click.Context, **kwargs):
75
+ inner_ctx.meta["_extra_args"] = inner_ctx.args[:]
76
+ inner_ctx.invoke(run_cmd, alias=cmd_name, **kwargs)
77
+
78
+ return _alias_cmd
79
+
80
+ def resolve_command(self, ctx: click.Context, args: list):
81
+ """
82
+ Resolves the command by expanding shortcut commands if applicable.
83
+
84
+ This method checks whether the provided command arguments include a shortcut
85
+ command. If a shortcut command is detected, it is expanded into its full form
86
+ and the resulting extended argument list is passed to the parent class's
87
+ `resolve_command` method. If no shortcut is found, the original argument list
88
+ is passed directly.
89
+
90
+ Args:
91
+ ctx (click.Context): The Click context containing information about the
92
+ execution of the command.
93
+ args (list): A list of command-line arguments passed to the command.
94
+
95
+ Returns:
96
+ tuple: A tuple containing the command name, the command object, and a list
97
+ of remaining arguments.
98
+ """
99
+ if args and args[0] in self._shortcut_commands:
100
+ expanded = self._shortcut_commands[args[0]]
101
+ return super().resolve_command(ctx, expanded + list(args[1:]))
102
+ return super().resolve_command(ctx, args)