flyshell 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 (32) hide show
  1. flyshell-1.0.0/LICENSE +21 -0
  2. flyshell-1.0.0/PKG-INFO +208 -0
  3. flyshell-1.0.0/README.md +194 -0
  4. flyshell-1.0.0/pyproject.toml +28 -0
  5. flyshell-1.0.0/setup.cfg +4 -0
  6. flyshell-1.0.0/src/flyshell/__init__.py +7 -0
  7. flyshell-1.0.0/src/flyshell/abstract/__init__.py +0 -0
  8. flyshell-1.0.0/src/flyshell/abstract/base_cmd.py +26 -0
  9. flyshell-1.0.0/src/flyshell/abstract/base_plugin.py +75 -0
  10. flyshell-1.0.0/src/flyshell/abstract/parent_cmd.py +59 -0
  11. flyshell-1.0.0/src/flyshell/builtin/__init__.py +0 -0
  12. flyshell-1.0.0/src/flyshell/builtin/fs.py +161 -0
  13. flyshell-1.0.0/src/flyshell/builtin/system.py +124 -0
  14. flyshell-1.0.0/src/flyshell/builtin/utils.py +113 -0
  15. flyshell-1.0.0/src/flyshell/core/__init__.py +0 -0
  16. flyshell-1.0.0/src/flyshell/core/auth.py +122 -0
  17. flyshell-1.0.0/src/flyshell/core/console.py +64 -0
  18. flyshell-1.0.0/src/flyshell/core/data.py +234 -0
  19. flyshell-1.0.0/src/flyshell/core/directory.py +242 -0
  20. flyshell-1.0.0/src/flyshell/core/loader.py +90 -0
  21. flyshell-1.0.0/src/flyshell/main.py +115 -0
  22. flyshell-1.0.0/src/flyshell.egg-info/PKG-INFO +208 -0
  23. flyshell-1.0.0/src/flyshell.egg-info/SOURCES.txt +30 -0
  24. flyshell-1.0.0/src/flyshell.egg-info/dependency_links.txt +1 -0
  25. flyshell-1.0.0/src/flyshell.egg-info/entry_points.txt +2 -0
  26. flyshell-1.0.0/src/flyshell.egg-info/requires.txt +8 -0
  27. flyshell-1.0.0/src/flyshell.egg-info/top_level.txt +1 -0
  28. flyshell-1.0.0/tests/test_auth.py +26 -0
  29. flyshell-1.0.0/tests/test_data.py +63 -0
  30. flyshell-1.0.0/tests/test_directory.py +59 -0
  31. flyshell-1.0.0/tests/test_loader.py +39 -0
  32. flyshell-1.0.0/tests/test_security.py +33 -0
flyshell-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 kianodev
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,208 @@
1
+ Metadata-Version: 2.4
2
+ Name: flyshell
3
+ Version: 1.0.0
4
+ Summary: A modular, zero-dependency command-line environment in Python.
5
+ License: MIT
6
+ Requires-Python: >=3.10
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Provides-Extra: dev
10
+ Requires-Dist: pytest; extra == "dev"
11
+ Provides-Extra: readline
12
+ Requires-Dist: pyreadline3; sys_platform == "win32" and extra == "readline"
13
+ Dynamic: license-file
14
+
15
+ # Flyshell
16
+
17
+ ![Python Version](https://img.shields.io/badge/python-3.10%2B-blue.svg)
18
+ ![Licence](https://img.shields.io/badge/license-MIT-green.svg)
19
+ ![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux-lightgrey.svg)
20
+ ![Dependencies](https://img.shields.io/badge/dependencies-zero-brightgreen.svg)
21
+ ![Tests](https://github.com/kianodev/flyshell/actions/workflows/pytest.yml/badge.svg)
22
+
23
+ > Documentation last updated: v1.0.0
24
+
25
+ A modular, zero-dependency command-line environment and extensible runtime interface built in Python.
26
+
27
+ Flyshell provides a modular, extensible shell environment featuring dynamic runtime plugin loading, session persistence, secure authentication, and cross-platform process isolation, using only Python standard libraries.
28
+
29
+ No extra packages required, just install and enjoy!
30
+
31
+ ## Key Features
32
+
33
+ 1. **Zero External Dependencies** - Flyshell is built entirely with native Python modules with absolutely zero third-party packages required to enjoy full functionality.
34
+ 2. **Dynamic Plugin Architecture**: Flyshell employs a dynamic plugin architecture that automatically scans for plugins in the User Directory following the standard defined in `src/flyshell/abstract/base_plugin.py`.
35
+ 3. **Secure Authentication**: Flyshell uses salted PBKDF2 HMAC (SHA-256, 600,000 iterations) with constant-time equality comparisons to prevent timing attacks on password information.
36
+ 4. **Cross-Platform Support**: Flyshell is fully supported by Windows (NT), macOS (Darwin) and Linux installations with native OS management and POSIX-aware parsing. Note that Flyshell is **not** supported by any other systems.
37
+ 5. **State and History Persistence**: Flyshell has a fully encapsulated SQL storage system using SQLite3 providing session metrics and ISO 8601 UTC audit logging.
38
+
39
+ ## System Requirements
40
+
41
+ 1. **Python**: Your Python installation or IDE must support **Python 3.10 or newer** as Flyshell utilises structural pattern matching features. Older Python installations will be rejected by Flyshell on boot or could crash the system.
42
+ 2. **Operating System**: Your operating system must be **Windows 10/11, macOS (Darwin) or Linux**. Any other operating system will be rejected by Flyshell on boot.
43
+
44
+ ## System Architecture
45
+
46
+ ```
47
+ flyshell/
48
+ ├── .github/
49
+ │ └── workflows/
50
+ │ └── pytest.yml
51
+ ├── src/
52
+ │ └── flyshell/
53
+ │ ├── abstract/
54
+ │ │ ├── __init__.py
55
+ │ │ ├── base_cmd.py
56
+ │ │ ├── base_plugin.py
57
+ │ │ └── parent_cmd.py
58
+ │ ├── builtin/
59
+ │ │ ├── __init__.py
60
+ │ │ ├── fs.py
61
+ │ │ ├── system.py
62
+ │ │ └── utils.py
63
+ │ ├── core/
64
+ │ │ ├── __init__.py
65
+ │ │ ├── auth.py
66
+ │ │ ├── console.py
67
+ │ │ ├── data.py
68
+ │ │ ├── directory.py
69
+ │ │ └── loader.py
70
+ │ ├── __init__.py
71
+ │ └── main.py
72
+ ├── tests/
73
+ │ ├── test_auth.py
74
+ │ ├── test_data.py
75
+ │ ├── test_directory.py
76
+ │ ├── test_loader.py
77
+ │ └── test_security.py
78
+ ├── .gitignore
79
+ ├── LICENSE
80
+ ├── pyproject.toml
81
+ └── README.md
82
+ ```
83
+
84
+ ## Installing Flyshell
85
+
86
+ There are two methods to install Flyshell.
87
+
88
+ ### Method 1: Install via `pip` (Best for General Use)
89
+
90
+ Install Flyshell through `pip`:
91
+ ```bash
92
+ pip install flyshell
93
+ ```
94
+
95
+ Then, you can simply run Flyshell:
96
+ ```bash
97
+ flyshell
98
+ ```
99
+
100
+ ### Method 2: Install from source via `git` (Best for Development & Custom Plugins)
101
+
102
+ Clone the GitHub repository:
103
+ ```bash
104
+ git clone https://github.com/kianodev/flyshell.git
105
+ ```
106
+
107
+ Switch to the Flyshell directory and install in editable mode:
108
+ ```bash
109
+ cd flyshell
110
+ pip install -e .
111
+ ```
112
+
113
+ ### Adding optional dependencies
114
+
115
+ To install Readline (on Windows):
116
+ ```bash
117
+ pip install -e .[readline]
118
+ ```
119
+
120
+ To install the development and testing suite (including Pytest):
121
+ ```bash
122
+ pip install -e .[dev]
123
+ ```
124
+
125
+ ## Exploring Flyshell
126
+
127
+ Once you have installed Flyshell using either of the methods above, you will be prompted to initialise your user profile. Once this is complete, you will be greeted with a prompt that looks like this:
128
+ ```console
129
+ Flyshell [v1.x.x] (current_dir)>>
130
+ ```
131
+
132
+ From this stage, you can enter a wide variety of commands. To see the commands list for your installation, type `cmds` or `help` to return a full up-to-date directory. Use `fs plugins` to return plugin information.
133
+
134
+ Flyshell also supports command chaining out of the box. Use `;` to chain commands together regardless of result, `&&` to execute only on success and `||` to execute only on failure.
135
+
136
+ Use `-h` or `--help` after any command to return that command's specific help list.
137
+
138
+ To close Flyshell once you are done, enter `kill` onto the command line then confirm, or press Ctrl + D to close the session immediately.
139
+
140
+ ## Creating Custom Plugins
141
+
142
+ Flyshell features an extensible plugin API. This API supports both single-file and multi-file plugins. Follow the below guide to create your own.
143
+
144
+ Plugins must inherit from the `BasePlugin` contract defined in `src/flyshell/abstract/base_plugin.py`. Plugins are stored in the User Directory. Navigate to your App Storage folder:
145
+ - **Windows**: `%APPDATA%\Flyshell\plugins`
146
+ - **macOS**: `~/Library/Application Support/Flyshell/plugins`
147
+ - **Linux**: `~/.local/share/Flyshell/plugins`
148
+
149
+ Place your plugins inside the `plugins/` folder.
150
+
151
+ All plugins should define the required attributes. Flyshell can read this information for both `fs plugins` and `[my_plugin] -h` / `--help` which are both supported out of the box. Flyshell will discover, inspect and import your plugin from the `plugins/` folder without you having to alter any internal code.
152
+
153
+ ### The Entry-Point
154
+
155
+ All plugins must have an entry-point file. For single-file plugins, this is the plugin file. For multi-file plugins, this file must be named `plugin.py` and stored directly inside of your plugin's own folder.
156
+
157
+ This file is what enables Flyshell to speak to your plugin.
158
+
159
+ ```python
160
+ # Entry-point (my_plugin.py or my_plugin\plugin.py)
161
+
162
+ from flyshell import BasePlugin # This is required
163
+
164
+ class MyPlugin(BasePlugin):
165
+ name = "My Plugin" # The name you want visible to Flyshell
166
+ description = "This is my plugin." # A short one-line explaining what your plugin does
167
+ version = "1.0.0" # Default is 1.0.0
168
+ author = "kianodev" # You can put your name, your GitHub handle, or leave blank to make it 'Unknown'
169
+ usage = "" # (OPTIONAL) Explain how to use your plugin
170
+ extended_help = "" # (OPTIONAL) A more detailed, multi-line guide containing specific assistance
171
+
172
+ def on_load(self): # (OPTIONAL) Enables your program to handle specialist set-up tasks before execute()
173
+ pass
174
+
175
+ def on_unload(self): # (OPTIONAL) Enables your program to handle specialist shut-down tasks
176
+ super().on_unload() # If you use a custom on_unload(), end it with this
177
+
178
+
179
+ def execute(self, args): # This is what Flyshell calls to execute
180
+ print(f"Hello! Arguments: {args}")
181
+ return
182
+ ```
183
+
184
+ ### Extra Functions
185
+
186
+ Additional functions are available for you to use:
187
+
188
+ 1. `get_data(key, default=None)`: Retrieves a value from local plugin memory.
189
+ 2. `set_data(key, value)`: Updates a key in local memory and automatically persists it to SQLite via `save_storage()`.
190
+ 3. `load_storage()`: Reloads fresh key-value pairs directly from SQLite into `self.storage`.
191
+ 4. `save_storage()`: Writes all in-memory key-value pairs in `self.storage` back to SQLite.
192
+
193
+ Plugins save automatically on shut-down. If `on_unload()` is not used, it is automatic. If `on_unload()` is used, `super().on_unload()` saves your files.
194
+
195
+ ### Built-in Attributes
196
+
197
+ Every plugin has direct access to the following instance variables:
198
+
199
+ - `self.plugin_name` (`str`): The unique name identifier used to invoke the plugin.
200
+ - `self.storage` (`dict`): In-memory key-value data automatically loaded from the persistent database.
201
+ - `self.context` (`dict`): Environmental metadata provided at start-up, within it:
202
+ - `self.context["metadata"]["host_os"]`: Operating system (e.g., `'Windows'`, `'Linux'`, `'Darwin'`).
203
+ - `self.context["metadata"]["version"]`: Current Flyshell version.
204
+ - `self.context["file_path"]`: Full path to the plugin's source file.
205
+
206
+ ### Extra Notes
207
+
208
+ You are welcome to catch errors yourself. However, Flyshell will handle them automatically. That said, if you would like your plugin to continue after an error, you need to implement error handling yourself as the default system closes your plugin.
@@ -0,0 +1,194 @@
1
+ # Flyshell
2
+
3
+ ![Python Version](https://img.shields.io/badge/python-3.10%2B-blue.svg)
4
+ ![Licence](https://img.shields.io/badge/license-MIT-green.svg)
5
+ ![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux-lightgrey.svg)
6
+ ![Dependencies](https://img.shields.io/badge/dependencies-zero-brightgreen.svg)
7
+ ![Tests](https://github.com/kianodev/flyshell/actions/workflows/pytest.yml/badge.svg)
8
+
9
+ > Documentation last updated: v1.0.0
10
+
11
+ A modular, zero-dependency command-line environment and extensible runtime interface built in Python.
12
+
13
+ Flyshell provides a modular, extensible shell environment featuring dynamic runtime plugin loading, session persistence, secure authentication, and cross-platform process isolation, using only Python standard libraries.
14
+
15
+ No extra packages required, just install and enjoy!
16
+
17
+ ## Key Features
18
+
19
+ 1. **Zero External Dependencies** - Flyshell is built entirely with native Python modules with absolutely zero third-party packages required to enjoy full functionality.
20
+ 2. **Dynamic Plugin Architecture**: Flyshell employs a dynamic plugin architecture that automatically scans for plugins in the User Directory following the standard defined in `src/flyshell/abstract/base_plugin.py`.
21
+ 3. **Secure Authentication**: Flyshell uses salted PBKDF2 HMAC (SHA-256, 600,000 iterations) with constant-time equality comparisons to prevent timing attacks on password information.
22
+ 4. **Cross-Platform Support**: Flyshell is fully supported by Windows (NT), macOS (Darwin) and Linux installations with native OS management and POSIX-aware parsing. Note that Flyshell is **not** supported by any other systems.
23
+ 5. **State and History Persistence**: Flyshell has a fully encapsulated SQL storage system using SQLite3 providing session metrics and ISO 8601 UTC audit logging.
24
+
25
+ ## System Requirements
26
+
27
+ 1. **Python**: Your Python installation or IDE must support **Python 3.10 or newer** as Flyshell utilises structural pattern matching features. Older Python installations will be rejected by Flyshell on boot or could crash the system.
28
+ 2. **Operating System**: Your operating system must be **Windows 10/11, macOS (Darwin) or Linux**. Any other operating system will be rejected by Flyshell on boot.
29
+
30
+ ## System Architecture
31
+
32
+ ```
33
+ flyshell/
34
+ ├── .github/
35
+ │ └── workflows/
36
+ │ └── pytest.yml
37
+ ├── src/
38
+ │ └── flyshell/
39
+ │ ├── abstract/
40
+ │ │ ├── __init__.py
41
+ │ │ ├── base_cmd.py
42
+ │ │ ├── base_plugin.py
43
+ │ │ └── parent_cmd.py
44
+ │ ├── builtin/
45
+ │ │ ├── __init__.py
46
+ │ │ ├── fs.py
47
+ │ │ ├── system.py
48
+ │ │ └── utils.py
49
+ │ ├── core/
50
+ │ │ ├── __init__.py
51
+ │ │ ├── auth.py
52
+ │ │ ├── console.py
53
+ │ │ ├── data.py
54
+ │ │ ├── directory.py
55
+ │ │ └── loader.py
56
+ │ ├── __init__.py
57
+ │ └── main.py
58
+ ├── tests/
59
+ │ ├── test_auth.py
60
+ │ ├── test_data.py
61
+ │ ├── test_directory.py
62
+ │ ├── test_loader.py
63
+ │ └── test_security.py
64
+ ├── .gitignore
65
+ ├── LICENSE
66
+ ├── pyproject.toml
67
+ └── README.md
68
+ ```
69
+
70
+ ## Installing Flyshell
71
+
72
+ There are two methods to install Flyshell.
73
+
74
+ ### Method 1: Install via `pip` (Best for General Use)
75
+
76
+ Install Flyshell through `pip`:
77
+ ```bash
78
+ pip install flyshell
79
+ ```
80
+
81
+ Then, you can simply run Flyshell:
82
+ ```bash
83
+ flyshell
84
+ ```
85
+
86
+ ### Method 2: Install from source via `git` (Best for Development & Custom Plugins)
87
+
88
+ Clone the GitHub repository:
89
+ ```bash
90
+ git clone https://github.com/kianodev/flyshell.git
91
+ ```
92
+
93
+ Switch to the Flyshell directory and install in editable mode:
94
+ ```bash
95
+ cd flyshell
96
+ pip install -e .
97
+ ```
98
+
99
+ ### Adding optional dependencies
100
+
101
+ To install Readline (on Windows):
102
+ ```bash
103
+ pip install -e .[readline]
104
+ ```
105
+
106
+ To install the development and testing suite (including Pytest):
107
+ ```bash
108
+ pip install -e .[dev]
109
+ ```
110
+
111
+ ## Exploring Flyshell
112
+
113
+ Once you have installed Flyshell using either of the methods above, you will be prompted to initialise your user profile. Once this is complete, you will be greeted with a prompt that looks like this:
114
+ ```console
115
+ Flyshell [v1.x.x] (current_dir)>>
116
+ ```
117
+
118
+ From this stage, you can enter a wide variety of commands. To see the commands list for your installation, type `cmds` or `help` to return a full up-to-date directory. Use `fs plugins` to return plugin information.
119
+
120
+ Flyshell also supports command chaining out of the box. Use `;` to chain commands together regardless of result, `&&` to execute only on success and `||` to execute only on failure.
121
+
122
+ Use `-h` or `--help` after any command to return that command's specific help list.
123
+
124
+ To close Flyshell once you are done, enter `kill` onto the command line then confirm, or press Ctrl + D to close the session immediately.
125
+
126
+ ## Creating Custom Plugins
127
+
128
+ Flyshell features an extensible plugin API. This API supports both single-file and multi-file plugins. Follow the below guide to create your own.
129
+
130
+ Plugins must inherit from the `BasePlugin` contract defined in `src/flyshell/abstract/base_plugin.py`. Plugins are stored in the User Directory. Navigate to your App Storage folder:
131
+ - **Windows**: `%APPDATA%\Flyshell\plugins`
132
+ - **macOS**: `~/Library/Application Support/Flyshell/plugins`
133
+ - **Linux**: `~/.local/share/Flyshell/plugins`
134
+
135
+ Place your plugins inside the `plugins/` folder.
136
+
137
+ All plugins should define the required attributes. Flyshell can read this information for both `fs plugins` and `[my_plugin] -h` / `--help` which are both supported out of the box. Flyshell will discover, inspect and import your plugin from the `plugins/` folder without you having to alter any internal code.
138
+
139
+ ### The Entry-Point
140
+
141
+ All plugins must have an entry-point file. For single-file plugins, this is the plugin file. For multi-file plugins, this file must be named `plugin.py` and stored directly inside of your plugin's own folder.
142
+
143
+ This file is what enables Flyshell to speak to your plugin.
144
+
145
+ ```python
146
+ # Entry-point (my_plugin.py or my_plugin\plugin.py)
147
+
148
+ from flyshell import BasePlugin # This is required
149
+
150
+ class MyPlugin(BasePlugin):
151
+ name = "My Plugin" # The name you want visible to Flyshell
152
+ description = "This is my plugin." # A short one-line explaining what your plugin does
153
+ version = "1.0.0" # Default is 1.0.0
154
+ author = "kianodev" # You can put your name, your GitHub handle, or leave blank to make it 'Unknown'
155
+ usage = "" # (OPTIONAL) Explain how to use your plugin
156
+ extended_help = "" # (OPTIONAL) A more detailed, multi-line guide containing specific assistance
157
+
158
+ def on_load(self): # (OPTIONAL) Enables your program to handle specialist set-up tasks before execute()
159
+ pass
160
+
161
+ def on_unload(self): # (OPTIONAL) Enables your program to handle specialist shut-down tasks
162
+ super().on_unload() # If you use a custom on_unload(), end it with this
163
+
164
+
165
+ def execute(self, args): # This is what Flyshell calls to execute
166
+ print(f"Hello! Arguments: {args}")
167
+ return
168
+ ```
169
+
170
+ ### Extra Functions
171
+
172
+ Additional functions are available for you to use:
173
+
174
+ 1. `get_data(key, default=None)`: Retrieves a value from local plugin memory.
175
+ 2. `set_data(key, value)`: Updates a key in local memory and automatically persists it to SQLite via `save_storage()`.
176
+ 3. `load_storage()`: Reloads fresh key-value pairs directly from SQLite into `self.storage`.
177
+ 4. `save_storage()`: Writes all in-memory key-value pairs in `self.storage` back to SQLite.
178
+
179
+ Plugins save automatically on shut-down. If `on_unload()` is not used, it is automatic. If `on_unload()` is used, `super().on_unload()` saves your files.
180
+
181
+ ### Built-in Attributes
182
+
183
+ Every plugin has direct access to the following instance variables:
184
+
185
+ - `self.plugin_name` (`str`): The unique name identifier used to invoke the plugin.
186
+ - `self.storage` (`dict`): In-memory key-value data automatically loaded from the persistent database.
187
+ - `self.context` (`dict`): Environmental metadata provided at start-up, within it:
188
+ - `self.context["metadata"]["host_os"]`: Operating system (e.g., `'Windows'`, `'Linux'`, `'Darwin'`).
189
+ - `self.context["metadata"]["version"]`: Current Flyshell version.
190
+ - `self.context["file_path"]`: Full path to the plugin's source file.
191
+
192
+ ### Extra Notes
193
+
194
+ You are welcome to catch errors yourself. However, Flyshell will handle them automatically. That said, if you would like your plugin to continue after an error, you need to implement error handling yourself as the default system closes your plugin.
@@ -0,0 +1,28 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "flyshell"
7
+ dynamic = ["version"]
8
+ description = "A modular, zero-dependency command-line environment in Python."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "MIT" }
12
+
13
+ [project.scripts]
14
+ flyshell = "flyshell.main:main"
15
+
16
+ [tool.setuptools.dynamic]
17
+ version = { attr = "flyshell.core.data.VERSION" }
18
+
19
+ [tool.setuptools.packages.find]
20
+ where = ["src"]
21
+
22
+ [project.optional-dependencies]
23
+ dev = [
24
+ "pytest",
25
+ ]
26
+ readline = [
27
+ "pyreadline3; sys_platform == 'win32'",
28
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,7 @@
1
+ try:
2
+ from flyshell.abstract.base_plugin import BasePlugin
3
+ __all__ = ["BasePlugin"]
4
+ except ImportError:
5
+ BasePlugin = None
6
+ __all__ = []
7
+ pass
File without changes
@@ -0,0 +1,26 @@
1
+ # src\flyshell\abstract\base_cmd.py
2
+
3
+ from typing import List, Optional, Tuple, Union
4
+
5
+ class BaseCmd:
6
+ name: str = ""
7
+ description: str = ""
8
+ min_args: int = 0
9
+ options: Optional[str] = None
10
+ aliases: List[str] = []
11
+
12
+ def execute(self, args: List[str]) -> Union[int, Tuple[int, str], str, None]:
13
+ raise NotImplementedError(f"Command '{self.__class__.__name__}' has not implemented the execute method")
14
+
15
+ def help(self, prefix: str = ""):
16
+ full_name = f"{prefix} {self.name}".strip() if prefix else self.name
17
+ print(f"\nCommand: {full_name}")
18
+ if prefix:
19
+ print(f"Parent: Part of the '{prefix}' family of commands")
20
+ if self.aliases:
21
+ print(f"Aliases: {', '.join(self.aliases)}")
22
+ print(f"Description: {self.description}")
23
+ print(f"Required Arguments: {self.min_args}")
24
+ if self.options:
25
+ print(f"Accepted Arguments: {self.options}")
26
+ print()
@@ -0,0 +1,75 @@
1
+ # src\flyshell\abstract\base_plugin.py
2
+
3
+ from flyshell.core import data
4
+ from pathlib import Path
5
+
6
+ class BasePlugin:
7
+ name: str = "Unnamed Plugin"
8
+ description: str = "No description provided."
9
+ version: str = "1.0.0"
10
+ author: str = "Unknown"
11
+ usage: str = ""
12
+ extended_help: str = ""
13
+
14
+ def __init__(self, context: dict):
15
+ self.context = context
16
+ self.plugin_name = context.get("plugin_name", self.name)
17
+ self.storage = context.get("storage", {})
18
+ self.on_load()
19
+
20
+ def on_load(self):
21
+ pass
22
+
23
+ def on_unload(self):
24
+ self.save_storage()
25
+
26
+ def execute(self, args: list):
27
+ raise NotImplementedError("Plugins must implement the execute method")
28
+
29
+ def help(self):
30
+ lines = [
31
+ f"\nPlugin: {self.name} (v{self.version})",
32
+ f"Description: {self.description}",
33
+ f"Author: {self.author}"
34
+ ]
35
+ if self.usage:
36
+ lines.append(f"Usage: {self.usage}")
37
+ if self.extended_help:
38
+ lines.append("\nDetails:")
39
+ lines.append(self.extended_help)
40
+ print("\n".join(lines))
41
+
42
+ def show_docs(self) -> bool:
43
+ plugin_path = self.context.get("file_path")
44
+ if plugin_path:
45
+ p = Path(plugin_path)
46
+ doc_file = (p.parent / "README.md") if p.is_file() else (p / "README.md")
47
+ if doc_file.exists():
48
+ print(f"\nDocumentation: {self.name}")
49
+ print(doc_file.read_text(encoding="utf-8"))
50
+ print("-" * 40)
51
+ return True
52
+ if self.__doc__:
53
+ print(f"\nDocumentation: {self.name}")
54
+ print(self.__doc__.strip())
55
+ print("-" * 40)
56
+ return True
57
+ return False
58
+
59
+ def get_data(self, key: str, default=None):
60
+ return self.storage.get(key, default)
61
+
62
+ def set_data(self, key: str, value):
63
+ self.storage[key] = value
64
+ self.save_storage()
65
+
66
+ def load_storage(self) -> dict:
67
+ fresh_data = data.get_all_plugin_data(self.plugin_name)
68
+ self.storage = fresh_data
69
+ self.context["storage"] = fresh_data
70
+ return self.storage
71
+
72
+ def save_storage(self):
73
+ for k, v in self.storage.items():
74
+ data.set_plugin_data(self.plugin_name, k, v)
75
+ self.context["storage"] = self.storage
@@ -0,0 +1,59 @@
1
+ # src\flyshell\abstract\parent_cmd.py
2
+
3
+ from flyshell.abstract.base_cmd import BaseCmd
4
+
5
+ from typing import Dict, List, Optional, Tuple, Union
6
+
7
+ class ParentCmd(BaseCmd):
8
+ min_args: int = 1
9
+ subcommands: Dict[str, BaseCmd] = {}
10
+
11
+ def __init__(self):
12
+ super().__init__() if hasattr(super(), "__init__") else None
13
+ self._sub_registry: Dict[str, BaseCmd] = {}
14
+ self._build_registry()
15
+
16
+ def _build_registry(self):
17
+ for cmd_obj in self.get_subcommands():
18
+ self._sub_registry[cmd_obj.name] = cmd_obj
19
+ for alias in getattr(cmd_obj, "aliases", []):
20
+ self._sub_registry[alias] = cmd_obj
21
+
22
+ def get_subcommands(self) -> List[BaseCmd]:
23
+ return []
24
+
25
+ def help(self):
26
+ print(f"\nCommand Family: {self.name}")
27
+ print(f"Description: {self.description}")
28
+ print(f"\nSubcommands of '{self.name}':")
29
+ seen = set()
30
+ for sub in self._sub_registry.values():
31
+ if sub in seen:
32
+ continue
33
+ seen.add(sub)
34
+ label = f"{sub.name} (alias: {', '.join(sub.aliases)})" if sub.aliases else sub.name
35
+ opt = f" [args: {sub.options}]" if sub.options else ""
36
+ print(f"{label} - {sub.description}{opt}")
37
+ print(f"\nFor subcommand assistance use '{self.name} <subcmd> -h' or '--help'\n")
38
+
39
+ def execute(self, args: List[str]) -> Union[int, Tuple[int, str], str, None]:
40
+ if not args or args[0] in ("-h", "--help"):
41
+ self.help()
42
+ return 0
43
+ sub_name = args[0].lower()
44
+ sub_args = args[1:]
45
+ if sub_name not in self._sub_registry:
46
+ print(f"\nCommand Error: Unknown subcommand '{sub_name}' for '{self.name}'.")
47
+ print(f"Use '{self.name} -h' or '--help' to see all valid subcommands.\n")
48
+ return 1
49
+ target = self._sub_registry[sub_name]
50
+ if "-h" in sub_args or "--help" in sub_args:
51
+ target.help(prefix=self.name)
52
+ return 0
53
+ if len(sub_args) < target.min_args:
54
+ print(f"\nCommand Error: '{self.name} {target.name}' requires at least {target.min_args} argument(s).")
55
+ if target.options:
56
+ print(f"Accepted arguments: {target.options}")
57
+ print()
58
+ return 1
59
+ return target.execute(sub_args)
File without changes