machineconfig 8.51__py3-none-any.whl → 8.61__py3-none-any.whl

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 (91) hide show
  1. machineconfig/jobs/installer/python_scripts/sysabc.py +13 -34
  2. machineconfig/profile/mapper_dotfiles.toml +3 -3
  3. machineconfig/scripts/python/devops.py +1 -1
  4. machineconfig/scripts/python/devops_navigator.py +1 -1
  5. machineconfig/scripts/python/helper_env/path_manager_tui.py +1 -1
  6. machineconfig/scripts/python/helpers/helper_env/env_manager_tui.py +1 -1
  7. machineconfig/scripts/python/helpers/helper_env/path_manager_tui.py +1 -1
  8. machineconfig/scripts/python/helpers/helpers_croshell/croshell_impl.py +8 -4
  9. machineconfig/scripts/python/helpers/helpers_devops/cli_config.py +33 -1
  10. machineconfig/scripts/python/helpers/helpers_devops/cli_config_mount.py +77 -0
  11. machineconfig/scripts/python/helpers/helpers_devops/cli_data.py +4 -0
  12. machineconfig/scripts/python/helpers/helpers_devops/cli_nw.py +90 -6
  13. machineconfig/scripts/python/helpers/helpers_devops/cli_repos.py +3 -3
  14. machineconfig/scripts/python/helpers/helpers_devops/cli_self.py +41 -15
  15. machineconfig/scripts/python/helpers/helpers_devops/cli_share_temp.py +69 -0
  16. machineconfig/scripts/python/helpers/helpers_devops/cli_ssh.py +4 -4
  17. machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/__init__.py +0 -0
  18. machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/commands.py +25 -0
  19. machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/device_entry.py +17 -0
  20. machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/devices.py +17 -0
  21. machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/linux.py +103 -0
  22. machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/macos.py +100 -0
  23. machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/selection.py +47 -0
  24. machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/utils.py +28 -0
  25. machineconfig/scripts/python/helpers/helpers_devops/mount_helpers/windows.py +91 -0
  26. machineconfig/scripts/python/helpers/helpers_msearch/scripts_windows/fzfg.ps1 +1 -6
  27. machineconfig/scripts/python/helpers/helpers_network/ssh/__init__.py +0 -0
  28. machineconfig/scripts/python/helpers/helpers_network/ssh/ssh_add_key_windows.py +23 -0
  29. machineconfig/scripts/python/helpers/helpers_network/{ssh_add_ssh_key.py → ssh/ssh_add_ssh_key.py} +21 -27
  30. machineconfig/scripts/python/helpers/helpers_network/ssh/ssh_cloud_init.py +33 -0
  31. machineconfig/scripts/python/helpers/helpers_network/{ssh_debug_linux.py → ssh/ssh_debug_linux.py} +70 -51
  32. machineconfig/scripts/python/helpers/helpers_network/ssh/ssh_debug_linux_utils.py +35 -0
  33. machineconfig/scripts/python/helpers/helpers_network/{ssh_debug_windows.py → ssh/ssh_debug_windows.py} +12 -42
  34. machineconfig/scripts/python/helpers/helpers_network/ssh/ssh_debug_windows_utils.py +34 -0
  35. machineconfig/scripts/python/helpers/helpers_repos/cloud_repo_sync.py +2 -3
  36. machineconfig/scripts/python/helpers/{helpers_terminal/terminal_impl.py → helpers_sessions/attach_impl.py} +16 -25
  37. machineconfig/scripts/python/helpers/helpers_sessions/sessions_impl.py +57 -129
  38. machineconfig/scripts/python/helpers/helpers_sessions/utils.py +69 -0
  39. machineconfig/scripts/python/mcfg_entry.py +0 -7
  40. machineconfig/scripts/python/sessions.py +95 -14
  41. machineconfig/scripts/python/utils.py +3 -2
  42. machineconfig/settings/shells/bash/init.sh +0 -7
  43. machineconfig/settings/shells/pwsh/init.ps1 +2 -4
  44. machineconfig/settings/shells/wezterm/wezterm.lua +1 -0
  45. machineconfig/settings/shells/wt/settings.json +13 -19
  46. machineconfig/settings/shells/zsh/init.sh +0 -1
  47. machineconfig/settings/zellij/__init__.py +0 -0
  48. machineconfig/settings/zellij/config.kdl +0 -295
  49. machineconfig/settings/zellij/layouts/__init__.py +0 -0
  50. machineconfig/settings/zellij/layouts/st.kdl +0 -1
  51. machineconfig/settings/zellij/layouts/st2.kdl +6 -2
  52. machineconfig/setup_linux/web_shortcuts/interactive.sh +10 -10
  53. machineconfig/setup_windows/web_shortcuts/interactive.ps1 +10 -10
  54. machineconfig/utils/installer_utils/installer_cli.py +6 -2
  55. machineconfig/utils/installer_utils/installer_helper.py +50 -34
  56. machineconfig/utils/installer_utils/installer_locator_utils.py +3 -13
  57. machineconfig/utils/options_utils/tv_options.py +1 -1
  58. machineconfig/utils/procs.py +35 -27
  59. machineconfig/utils/schemas/layouts/layout_types.py +10 -0
  60. machineconfig/utils/source_of_truth.py +1 -0
  61. machineconfig/utils/ssh_utils/abc.py +1 -1
  62. {machineconfig-8.51.dist-info → machineconfig-8.61.dist-info}/METADATA +2 -3
  63. {machineconfig-8.51.dist-info → machineconfig-8.61.dist-info}/RECORD +68 -72
  64. {machineconfig-8.51.dist-info → machineconfig-8.61.dist-info}/entry_points.txt +0 -1
  65. machineconfig/jobs/scripts/bash_scripts/android.sh +0 -2
  66. machineconfig/jobs/scripts/bash_scripts/mount_drive +0 -128
  67. machineconfig/jobs/scripts/bash_scripts/mount_nfs +0 -49
  68. machineconfig/jobs/scripts/bash_scripts/mount_nw_drive +0 -61
  69. machineconfig/jobs/scripts/bash_scripts/mount_smb +0 -3
  70. machineconfig/jobs/scripts/bash_scripts/share_cloud.sh +0 -64
  71. machineconfig/jobs/scripts/bash_scripts/share_nfs +0 -49
  72. machineconfig/jobs/scripts/bash_scripts/start_docker +0 -23
  73. machineconfig/jobs/scripts/powershell_scripts/Restore-ThunderbirdProfile.ps1 +0 -92
  74. machineconfig/jobs/scripts/powershell_scripts/docker.ps1 +0 -7
  75. machineconfig/jobs/scripts/powershell_scripts/mount_nfs.ps1 +0 -42
  76. machineconfig/jobs/scripts/powershell_scripts/mount_nw.ps1 +0 -9
  77. machineconfig/jobs/scripts/powershell_scripts/mount_smb.ps1 +0 -2
  78. machineconfig/jobs/scripts/powershell_scripts/mount_ssh.ps1 +0 -13
  79. machineconfig/jobs/scripts/powershell_scripts/obs.ps1 +0 -4
  80. machineconfig/jobs/scripts/powershell_scripts/power_options.ps1 +0 -7
  81. machineconfig/jobs/scripts/powershell_scripts/share_cloud.cmd +0 -34
  82. machineconfig/jobs/scripts/powershell_scripts/share_smb.ps1 +0 -16
  83. machineconfig/scripts/python/helpers/helpers_network/mount_nfs.py +0 -85
  84. machineconfig/scripts/python/helpers/helpers_network/mount_nw_drive.py +0 -48
  85. machineconfig/scripts/python/helpers/helpers_network/mount_ssh.py +0 -64
  86. machineconfig/scripts/python/terminal.py +0 -58
  87. machineconfig/settings/zellij/config.orig.kdl +0 -295
  88. /machineconfig/{scripts/python/helpers/helpers_terminal → cluster/sessions_managers/wt_utils/examples}/__init__.py +0 -0
  89. /machineconfig/scripts/python/helpers/helpers_network/{ssh_add_identity.py → ssh/ssh_add_identity.py} +0 -0
  90. {machineconfig-8.51.dist-info → machineconfig-8.61.dist-info}/WHEEL +0 -0
  91. {machineconfig-8.51.dist-info → machineconfig-8.61.dist-info}/top_level.txt +0 -0
@@ -1,63 +1,37 @@
1
1
  """Pure Python implementations for sessions commands - no typer dependencies."""
2
2
 
3
- from typing import Optional, Literal
3
+ from typing import Literal
4
4
  from pathlib import Path
5
5
 
6
6
 
7
- def balance_load(
8
- layout_path: str,
9
- max_thresh: int,
10
- thresh_type: Literal["number", "n", "weight", "w"],
11
- breaking_method: Literal["moreLayouts", "ml", "combineTabs", "ct"],
12
- output_path: Optional[str],
13
- ) -> None:
14
- """Adjust layout file to limit max tabs per layout, etc."""
15
- thresh_type_resolved: dict[str, Literal["number", "weight"]] = {"number": "number", "n": "number", "weight": "weight", "w": "weight"}
16
- breaking_method_resolved: dict[str, Literal["moreLayouts", "combineTabs"]] = {"moreLayouts": "moreLayouts", "ml": "moreLayouts", "combineTabs": "combineTabs", "ct": "combineTabs"}
17
-
18
- layout_path_obj = Path(layout_path).expanduser().absolute()
19
-
20
- from machineconfig.utils.schemas.layouts.layout_types import LayoutsFile
21
- import json
22
- layoutfile: LayoutsFile = json.loads(layout_path_obj.read_text())
23
- layout_configs = layoutfile["layouts"]
24
- from machineconfig.cluster.sessions_managers.utils.load_balancer import limit_tab_num
25
- new_layouts = limit_tab_num(layout_configs=layout_configs, max_thresh=max_thresh, threshold_type=thresh_type_resolved[thresh_type], breaking_method=breaking_method_resolved[breaking_method])
26
- layoutfile["layouts"] = new_layouts
27
- target_file = Path(output_path) if output_path is not None else layout_path_obj.parent / f"{layout_path_obj.stem}_adjusted_{max_thresh}_{thresh_type}_{breaking_method}.json"
28
- target_file.parent.mkdir(parents=True, exist_ok=True)
29
- target_file.write_text(data=json.dumps(layoutfile, indent=4), encoding="utf-8")
30
- print(f"Adjusted layout saved to {target_file}")
31
-
32
-
33
- def select_layout(layouts_json_file: str, selected_layouts_names: Optional[list[str]], select_interactively: bool, subsitute_home: bool) -> list["LayoutConfig"]: # type: ignore[name-defined]
7
+ def select_layout(layouts_json_file: str, selected_layouts_names: list[str], select_interactively: bool) -> list["LayoutConfig"]:
34
8
  """Select layout(s) from a layout file."""
35
9
  import json
36
- from machineconfig.utils.schemas.layouts.layout_types import LayoutsFile, LayoutConfig
10
+ from machineconfig.utils.schemas.layouts.layout_types import LayoutsFile
37
11
  json_str = Path(layouts_json_file).read_text(encoding="utf-8")
38
- if subsitute_home:
39
- json_str = json_str.replace("~", str(Path.home())).replace("$HOME", str(Path.home()))
40
- json_str = json_str.replace("""Command": "f """, """Command": "~/.config/machineconfig/scripts/wrap_mcfg fire """)
41
- json_str = json_str.replace("""Command": "s """, """Command": "~/.config/machineconfig/scripts/wrap_mcfg sessions """)
42
-
43
12
  try:
44
- # src/machineconfig/utils/io.py
45
13
  layout_file: LayoutsFile = json.loads(json_str)
46
14
  except Exception:
47
15
  print(f"Failed to parse the json file {layouts_json_file}, trying to clean the comments and giving it another shot ... ")
48
16
  from machineconfig.utils.io import remove_c_style_comments
49
17
  json_str = remove_c_style_comments(json_str)
50
- # print(json_str)
51
18
  layout_file: LayoutsFile = json.loads(json_str)
52
-
53
19
  if len(layout_file["layouts"]) == 0:
54
20
  raise ValueError(f"No layouts found in {layouts_json_file}")
55
- if selected_layouts_names is None:
21
+ if len(selected_layouts_names) == 0:
56
22
  if not select_interactively:
57
23
  return layout_file["layouts"]
58
- options = [layout["layoutName"] for layout in layout_file["layouts"]]
59
- from machineconfig.utils.options import choose_from_options
60
- selected_layouts_names = choose_from_options(multi=True, options=options, prompt="Choose a layout configuration:", tv=True, msg="Choose one option")
24
+ # options = [layout["layoutName"] for layout in layout_file["layouts"]]
25
+ # from machineconfig.utils.options import choose_from_options
26
+ # selected_layouts_names = choose_from_options(multi=True, options=options, prompt="Choose a layout configuration:", tv=True, msg="Choose one option")
27
+ from machineconfig.utils.options_utils.tv_options import choose_from_dict_with_preview
28
+ selected_layouts_names = choose_from_dict_with_preview(
29
+ {layout["layoutName"]: json.dumps(layout, indent=4) for layout in layout_file["layouts"]},
30
+ extension="json",
31
+ multi=True,
32
+ preview_size_percent=40,
33
+ )
34
+
61
35
  print(f"Selected layout(s): {selected_layouts_names}")
62
36
  layouts_chosen: list[LayoutConfig] = []
63
37
  for name in selected_layouts_names:
@@ -70,7 +44,6 @@ def select_layout(layouts_json_file: str, selected_layouts_names: Optional[list[
70
44
  layouts_chosen.append(layout_chosen)
71
45
  return layouts_chosen
72
46
 
73
-
74
47
  def find_layout_file(layout_path: str) -> str:
75
48
  """Find layout file from a path."""
76
49
  from machineconfig.utils.path_helper import search_for_files_of_interest, match_file_name, sanitize_path
@@ -90,97 +63,52 @@ def find_layout_file(layout_path: str) -> str:
90
63
 
91
64
 
92
65
  def run_layouts(
93
- layout_path: Optional[str],
94
- max_tabs: int,
95
- max_layouts: int,
96
66
  sleep_inbetween: float,
97
67
  monitor: bool,
98
- parallel: bool,
68
+ sequential: bool,
99
69
  kill_upon_completion: bool,
100
- choose: Optional[str],
101
- choose_interactively: bool,
102
- subsitute_home: bool,
70
+ backend: Literal["zellij", "windows-terminal"],
71
+ layouts_selected: list["LayoutConfig"],
103
72
  ) -> None:
104
73
  """Launch terminal sessions based on a layout configuration file."""
105
- if layout_path is None:
106
- raise ValueError("layout_path is required")
107
-
108
- layout_path_resolved = find_layout_file(layout_path=layout_path)
109
- layouts_selected = select_layout(layouts_json_file=layout_path_resolved, selected_layouts_names=choose.split(",") if choose else None, select_interactively=choose_interactively, subsitute_home=subsitute_home)
110
-
111
- if parallel and len(layouts_selected) > max_layouts:
112
- raise ValueError(f"Number of layouts {len(layouts_selected)} exceeds the maximum allowed {max_layouts}. Please adjust your layout file.")
113
- for a_layout in layouts_selected:
114
- if len(a_layout["layoutTabs"]) > max_tabs:
115
- raise ValueError(f"Layout '{a_layout.get('layoutName', 'Unnamed')}' has {len(a_layout['layoutTabs'])} tabs which exceeds the max of {max_tabs}.")
116
-
117
74
  import time
118
- import platform
119
- if platform.system() == "Linux" or platform.system() == "Darwin":
120
- from machineconfig.cluster.sessions_managers.zellij_local_manager import ZellijLocalManager
121
- if not parallel:
122
- iterable = [[item] for item in layouts_selected]
123
- else:
124
- iterable = [layouts_selected]
125
- for i, a_layouts in enumerate(iterable):
126
- manager = ZellijLocalManager(session_layouts=a_layouts)
127
- manager.start_all_sessions(poll_interval=2, poll_seconds=2)
128
- if monitor:
129
- manager.run_monitoring_routine(wait_ms=2000)
130
- if kill_upon_completion:
131
- manager.kill_all_sessions()
132
- if i < len(layouts_selected) - 1:
133
- time.sleep(sleep_inbetween)
134
- elif platform.system() == "Windows":
135
- from machineconfig.cluster.sessions_managers.wt_local_manager import WTLocalManager
136
- if not parallel:
137
- iterable = [[item] for item in layouts_selected]
138
- else:
75
+ match backend:
76
+ case "zellij":
77
+ from machineconfig.cluster.sessions_managers.zellij_local_manager import ZellijLocalManager
78
+ if sequential:
79
+ iterable: list[list[LayoutConfig]] = [[item] for item in layouts_selected]
80
+ else:
81
+ iterable = [layouts_selected]
82
+ for i, a_layouts in enumerate(iterable):
83
+ manager = ZellijLocalManager(session_layouts=a_layouts)
84
+ manager.start_all_sessions(poll_interval=2, poll_seconds=2)
85
+ if monitor:
86
+ manager.run_monitoring_routine(wait_ms=2000)
87
+ if kill_upon_completion:
88
+ manager.kill_all_sessions()
89
+ if i < len(layouts_selected) - 1:
90
+ time.sleep(sleep_inbetween)
91
+ case "windows-terminal":
92
+ if sequential:
93
+ from machineconfig.cluster.sessions_managers.wt_local import run_wt_layout
94
+ for a_layout in layouts_selected:
95
+ run_wt_layout(layout_config=a_layout)
96
+ return
139
97
  iterable = [layouts_selected]
140
- for i, a_layouts in enumerate(iterable):
141
- manager = WTLocalManager(session_layouts=a_layouts)
142
- manager.start_all_sessions()
143
- if monitor:
144
- manager.run_monitoring_routine(wait_ms=2000)
145
- if kill_upon_completion:
146
- manager.kill_all_sessions()
147
- if i < len(layouts_selected) - 1:
148
- time.sleep(sleep_inbetween)
149
- else:
150
- print(f"❌ Unsupported platform: {platform.system()}")
151
-
152
-
153
- def create_template(name: Optional[str], num_tabs: int) -> None:
154
- """Create a layout template file."""
155
- from machineconfig.utils.schemas.layouts.layout_types import LayoutsFile, TabConfig, LayoutConfig
156
- tabs: list[TabConfig] = []
157
- for i in range(1, num_tabs + 1):
158
- tab: TabConfig = {
159
- "tabName": f"Tab{i}",
160
- "startDir": "~/" + str(Path.cwd().relative_to(Path.home())),
161
- "command": "bash",
162
- }
163
- tabs.append(tab)
164
- layouts: list[LayoutConfig] = [
165
- {
166
- "layoutName": f"{Path.cwd().name}Layout",
167
- "layoutTabs": tabs,
168
- }
169
- ]
170
- file: LayoutsFile = {
171
- "$schema": "https://bit.ly/cfglayout", # type: ignore
172
- "version": "0.1",
173
- "layouts": layouts,
174
- }
175
- import json
176
- json_string = json.dumps(file, indent=4)
177
- if name is None:
178
- layout_path = Path.cwd() / "layout.json"
179
- else:
180
- layout_path = Path.cwd() / (name.replace(".json", "") + ".json")
181
- layout_path.parent.mkdir(parents=True, exist_ok=True)
182
- if layout_path.exists():
183
- print(f"❌ File {layout_path} already exists. Aborting to avoid overwriting.")
184
- return
185
- layout_path.write_text(json_string, encoding="utf-8")
186
- print(f"✅ Created layout template at {layout_path}")
98
+ from machineconfig.cluster.sessions_managers.wt_local_manager import WTLocalManager
99
+ for i, a_layouts in enumerate(iterable):
100
+ manager = WTLocalManager(session_layouts=a_layouts)
101
+ manager.start_all_sessions()
102
+ if monitor:
103
+ manager.run_monitoring_routine(wait_ms=2000)
104
+ if kill_upon_completion:
105
+ manager.kill_all_sessions()
106
+ if i < len(layouts_selected) - 1:
107
+ time.sleep(sleep_inbetween)
108
+ case _:
109
+ raise ValueError(f"Unsupported backend: {backend}")
110
+
111
+
112
+ if __name__ == "__main__":
113
+ from machineconfig.utils.schemas.layouts.layout_types import LayoutConfig
114
+ _ = LayoutConfig
@@ -0,0 +1,69 @@
1
+ from pathlib import Path
2
+ from typing import Literal, Optional
3
+
4
+
5
+ def balance_load(
6
+ layout_path: str,
7
+ max_thresh: int,
8
+ thresh_type: Literal["number", "n", "weight", "w"],
9
+ breaking_method: Literal["moreLayouts", "ml", "combineTabs", "ct"],
10
+ output_path: Optional[str],
11
+ ) -> None:
12
+ """Adjust layout file to limit max tabs per layout, etc."""
13
+ thresh_type_resolved: dict[str, Literal["number", "weight"]] = {"number": "number", "n": "number", "weight": "weight", "w": "weight"}
14
+ breaking_method_resolved: dict[str, Literal["moreLayouts", "combineTabs"]] = {"moreLayouts": "moreLayouts", "ml": "moreLayouts", "combineTabs": "combineTabs", "ct": "combineTabs"}
15
+
16
+ layout_path_obj = Path(layout_path).expanduser().absolute()
17
+
18
+ from machineconfig.utils.schemas.layouts.layout_types import LayoutsFile
19
+ import json
20
+ layoutfile: LayoutsFile = json.loads(layout_path_obj.read_text())
21
+ layout_configs = layoutfile["layouts"]
22
+ from machineconfig.cluster.sessions_managers.utils.load_balancer import limit_tab_num
23
+ new_layouts = limit_tab_num(layout_configs=layout_configs, max_thresh=max_thresh, threshold_type=thresh_type_resolved[thresh_type], breaking_method=breaking_method_resolved[breaking_method])
24
+ layoutfile["layouts"] = new_layouts
25
+ target_file = Path(output_path) if output_path is not None else layout_path_obj.parent / f"{layout_path_obj.stem}_adjusted_{max_thresh}_{thresh_type}_{breaking_method}.json"
26
+ target_file.parent.mkdir(parents=True, exist_ok=True)
27
+ target_file.write_text(data=json.dumps(layoutfile, indent=4), encoding="utf-8")
28
+ print(f"Adjusted layout saved to {target_file}")
29
+
30
+
31
+ def create_template(name: Optional[str], num_tabs: int) -> None:
32
+ """Create a layout template file."""
33
+ from machineconfig.utils.schemas.layouts.layout_types import LayoutsFile, TabConfig, LayoutConfig
34
+ tabs: list[TabConfig] = []
35
+ import platform
36
+ if platform.system().lower() == "windows":
37
+ default_command = "powershell"
38
+ else:
39
+ default_command = "bash"
40
+ for i in range(1, num_tabs + 1):
41
+ tab: TabConfig = {
42
+ "tabName": f"Tab{i}",
43
+ "startDir": "~/" + str(Path.cwd().relative_to(Path.home())),
44
+ "command": default_command,
45
+ }
46
+ tabs.append(tab)
47
+ layouts: list[LayoutConfig] = [
48
+ {
49
+ "layoutName": f"{Path.cwd().name}Layout",
50
+ "layoutTabs": tabs,
51
+ }
52
+ ]
53
+ file: LayoutsFile = {
54
+ "$schema": "https://bit.ly/cfglayout", # type: ignore
55
+ "version": "0.1",
56
+ "layouts": layouts,
57
+ }
58
+ import json
59
+ json_string = json.dumps(file, indent=4)
60
+ if name is None:
61
+ layout_path = Path.cwd() / "layout.json"
62
+ else:
63
+ layout_path = Path.cwd() / (name.replace(".json", "") + ".json")
64
+ layout_path.parent.mkdir(parents=True, exist_ok=True)
65
+ if layout_path.exists():
66
+ print(f"❌ File {layout_path} already exists. Aborting to avoid overwriting.")
67
+ return
68
+ layout_path.write_text(json_string, encoding="utf-8")
69
+ print(f"✅ Created layout template at {layout_path}")
@@ -100,11 +100,6 @@ def utils(ctx: typer.Context) -> None:
100
100
  get_app()(ctx.args, standalone_mode=not ctx.args)
101
101
 
102
102
 
103
- def terminal(ctx: typer.Context) -> None:
104
- """[t] Terminal management commands."""
105
- from machineconfig.scripts.python.terminal import get_app
106
- get_app()(ctx.args, standalone_mode=not ctx.args)
107
-
108
103
 
109
104
  def get_app() -> typer.Typer:
110
105
  app = typer.Typer(help="MachineConfig CLI - Manage your machine configurations and workflows", no_args_is_help=True, add_help_option=True, add_completion=False)
@@ -121,8 +116,6 @@ def get_app() -> typer.Typer:
121
116
  app.command(name="a", hidden=True, context_settings=ctx_settings)(agents)
122
117
  app.command(name="utils", help="[u] Utility commands", context_settings=ctx_settings)(utils)
123
118
  app.command(name="u", hidden=True, context_settings=ctx_settings)(utils)
124
- app.command(name="terminal", help="[t] Terminal management commands", context_settings=ctx_settings)(terminal)
125
- app.command(name="t", hidden=True, context_settings=ctx_settings)(terminal)
126
119
 
127
120
  app.command(name="fire", help="[f] Fire and manage jobs", no_args_is_help=False, context_settings={"allow_extra_args": True, "allow_interspersed_args": False})(fire)
128
121
  app.command(name="f", hidden=True, no_args_is_help=False, context_settings={"allow_extra_args": True, "allow_interspersed_args": False})(fire)
@@ -12,44 +12,122 @@ def balance_load(
12
12
  output_path: Annotated[Optional[str], typer.Option(..., "--output-path", "-o", help="Path to write the adjusted layout.json file")] = None,
13
13
  ) -> None:
14
14
  """Adjust layout file to limit max tabs per layout, etc."""
15
- from machineconfig.scripts.python.helpers.helpers_sessions.sessions_impl import balance_load as impl
15
+ from machineconfig.scripts.python.helpers.helpers_sessions.utils import balance_load as impl
16
16
  impl(layout_path=layout_path, max_thresh=max_thresh, thresh_type=thresh_type, breaking_method=breaking_method, output_path=output_path)
17
17
 
18
18
 
19
19
  def run(
20
20
  ctx: typer.Context,
21
- layout_path: Annotated[Optional[str], typer.Argument(..., help="Path to the layout.json file")] = None,
21
+ layouts_file: Annotated[Optional[str], typer.Option(..., "--layouts-file", "-f", help="Path to the layout.json file")] = None,
22
+ choose: Annotated[Optional[str], typer.Option(..., "--choose", "-c", help="Comma separated names of layouts to be selected from the layout file passed")] = None,
23
+ choose_interactively: Annotated[bool, typer.Option(..., "--choose-interactively", "-i", help="Select layouts interactively")] = False,
24
+
22
25
  sleep_inbetween: Annotated[float, typer.Option(..., "--sleep-inbetween", "-si", help="Sleep time in seconds between launching layouts")] = 1.0,
23
26
  monitor: Annotated[bool, typer.Option(..., "--monitor", "-m", help="Monitor the layout sessions for completion")] = False,
24
- parallel: Annotated[bool, typer.Option(..., "--parallel", "-p", help="Launch multiple layouts in parallel")] = False,
27
+ sequential: Annotated[bool, typer.Option(..., "--sequential", "-s", help="Launch layouts sequentially")] = False,
25
28
  kill_upon_completion: Annotated[bool, typer.Option(..., "--kill-upon-completion", "-k", help="Kill session(s) upon completion (only relevant if monitor flag is set)")] = False,
26
- choose: Annotated[Optional[str], typer.Option(..., "--choose", "-c", help="Comma separated names of layouts to be selected from the layout file passed")] = None,
27
- choose_interactively: Annotated[bool, typer.Option(..., "--choose-interactively", "-i", help="Select layouts interactively")] = False,
28
29
  subsitute_home: Annotated[bool, typer.Option(..., "--substitute-home", "-sh", help="Substitute ~ and $HOME in layout file with actual home directory path")] = False,
29
30
  max_tabs: Annotated[int, typer.Option(..., "--max-tabs", "-mt", help="A Sanity checker that throws an error if any layout exceeds the maximum number of tabs to launch.")] = 25,
30
31
  max_layouts: Annotated[int, typer.Option(..., "--max-layouts", "-ml", help="A Sanity checker that throws an error if the total number of *parallel layouts exceeds this number.")] = 25,
32
+ backend: Annotated[Literal["zellij", "z", "windows-terminal", "wt", "auto", "a"], typer.Option(..., "--backend", "-b", help="Backend terminal multiplexer or emulator to use")] = "auto",
31
33
  ) -> None:
32
34
  """Launch terminal sessions based on a layout configuration file."""
33
- if layout_path is None:
35
+ from machineconfig.scripts.python.helpers.helpers_sessions.sessions_impl import run_layouts, find_layout_file, select_layout
36
+
37
+ from pathlib import Path
38
+ if layouts_file is not None:
39
+ layouts_file_resolved = Path(find_layout_file(layout_path=layouts_file))
40
+ else:
41
+ layouts_file_resolved = Path.home().joinpath("dotfiles/machineconfig/layouts.json")
42
+ if not layouts_file_resolved.exists():
34
43
  typer.echo(ctx.get_help())
35
- raise typer.Exit()
36
- from machineconfig.scripts.python.helpers.helpers_sessions.sessions_impl import run_layouts
44
+ typer.echo(f"❌ Layouts file not found: {layouts_file_resolved}", err=True)
45
+ raise typer.Exit(code=1)
46
+
47
+ if choose is None: layouts_names_resolved: list[str] = []
48
+ else: layouts_names_resolved = [name.strip() for name in choose.split(",") if name.strip()]
49
+ layouts_selected = select_layout(layouts_json_file=str(layouts_file_resolved), selected_layouts_names=layouts_names_resolved,
50
+ select_interactively=choose_interactively,)
51
+ if subsitute_home:
52
+ from machineconfig.utils.schemas.layouts.layout_types import substitute_home, LayoutConfig
53
+ layouts_modified: list["LayoutConfig"] = []
54
+ for a_layout in layouts_selected:
55
+ a_layout["layoutTabs"] = substitute_home(tabs=a_layout["layoutTabs"])
56
+ layouts_modified.append(a_layout)
57
+ layouts_selected = layouts_modified
58
+
59
+ import platform
60
+ backend_resolved: Literal["zellij", "windows-terminal"]
61
+ match backend:
62
+ case "windows-terminal" | "wt":
63
+ if platform.system().lower() != "windows":
64
+ typer.echo("Error: Windows Terminal layouts can only be started on Windows systems.", err=True)
65
+ raise typer.Exit(code=1)
66
+ backend_resolved = "windows-terminal"
67
+ case "zellij" | "z":
68
+ if platform.system().lower() == "windows":
69
+ typer.echo("Error: Zellij is not supported on Windows.", err=True)
70
+ raise typer.Exit(code=1)
71
+ backend_resolved = "zellij"
72
+ case "auto" | "a":
73
+ if platform.system().lower() == "windows":
74
+ backend_resolved = "windows-terminal"
75
+ else:
76
+ backend_resolved = "zellij"
77
+ case _:
78
+ typer.echo(f"Error: Unsupported backend '{backend}'.", err=True)
79
+ raise typer.Exit(code=1)
80
+
81
+ if not sequential and len(layouts_selected) > max_layouts:
82
+ raise ValueError(f"Number of layouts {len(layouts_selected)} exceeds the maximum allowed {max_layouts}. Please adjust your layout file.")
83
+ for a_layout in layouts_selected:
84
+ if len(a_layout["layoutTabs"]) > max_tabs:
85
+ raise ValueError(f"Layout '{a_layout.get('layoutName', 'Unnamed')}' has {len(a_layout['layoutTabs'])} tabs which exceeds the max of {max_tabs}.")
86
+
37
87
  try:
38
- run_layouts(layout_path=layout_path, max_tabs=max_tabs, max_layouts=max_layouts, sleep_inbetween=sleep_inbetween, monitor=monitor, parallel=parallel, kill_upon_completion=kill_upon_completion, choose=choose, choose_interactively=choose_interactively, subsitute_home=subsitute_home)
88
+ run_layouts(
89
+ sleep_inbetween=sleep_inbetween, monitor=monitor, sequential=sequential, kill_upon_completion=kill_upon_completion,
90
+ layouts_selected=layouts_selected,
91
+ backend=backend_resolved)
39
92
  except ValueError as e:
40
93
  typer.echo(str(e))
41
94
  raise typer.Exit(1) from e
42
95
 
43
96
 
97
+ def attach_to_session(
98
+ name: Annotated[str | None, typer.Argument(help="Name of the Zellij session to attach to. If not provided, a list will be shown to choose from.")] = None,
99
+ new_session: Annotated[bool, typer.Option("--new-session", "-n", help="Create a new Zellij session instead of attaching to an existing one.", show_default=True)] = False,
100
+ kill_all: Annotated[bool, typer.Option("--kill-all", "-k", help="Kill all existing Zellij sessions before creating a new one.", show_default=True)] = False) -> None:
101
+ """Choose a Zellij session to attach to."""
102
+ import platform
103
+ if platform.system().lower() == "windows":
104
+ typer.echo("Error: Zellij is not supported on Windows.", err=True, color=True)
105
+ raise typer.Exit()
106
+ from machineconfig.scripts.python.helpers.helpers_sessions.attach_impl import choose_zellij_session as impl
107
+ action, payload = impl(name=name, new_session=new_session, kill_all=kill_all)
108
+ if action == "error":
109
+ typer.echo(payload, err=True, color=True)
110
+ raise typer.Exit()
111
+ if action == "run_script" and payload:
112
+ from machineconfig.utils.code import exit_then_run_shell_script
113
+ exit_then_run_shell_script(script= payload, strict=True)
114
+
115
+
116
+
117
+ def get_session_tabs() -> list[tuple[str, str]]:
118
+ """Get all Zellij session tabs."""
119
+ from machineconfig.scripts.python.helpers.helpers_sessions.attach_impl import get_session_tabs as impl
120
+ result = impl()
121
+ print(result)
122
+ return result
44
123
  def create_template(
45
124
  name: Annotated[Optional[str], typer.Argument(..., help="Name of the layout template to create")] = None,
46
125
  num_tabs: Annotated[int, typer.Option(..., "--num-tabs", "-t", help="Number of tabs to include in the template")] = 3,
47
126
  ) -> None:
48
127
  """Create a layout template file."""
49
- from machineconfig.scripts.python.helpers.helpers_sessions.sessions_impl import create_template as impl
128
+ from machineconfig.scripts.python.helpers.helpers_sessions.utils import create_template as impl
50
129
  impl(name=name, num_tabs=num_tabs)
51
130
 
52
-
53
131
  def create_from_function(
54
132
  num_process: Annotated[int, typer.Option(..., "--num-process", "-n", help="Number of parallel processes to run")],
55
133
  path: Annotated[str, typer.Option(..., "--path", "-p", help="Path to a Python or Shell script file or a directory containing such files")] = ".",
@@ -63,12 +141,15 @@ def create_from_function(
63
141
  def get_app() -> typer.Typer:
64
142
  layouts_app = typer.Typer(help="Layouts management subcommands", no_args_is_help=True, add_help_option=True, add_completion=False)
65
143
 
66
- layouts_app.command("create-from-function", no_args_is_help=True, short_help="[c] Create a layout from a function")(create_from_function)
67
- layouts_app.command("c", no_args_is_help=True, hidden=True)(create_from_function)
68
-
69
144
  layouts_app.command("run", no_args_is_help=True, help=run.__doc__, short_help="[r] Run the selected layout(s)")(run)
70
145
  layouts_app.command("r", no_args_is_help=True, help=run.__doc__, hidden=True)(run)
71
146
 
147
+ layouts_app.command("attach", no_args_is_help=False, help=attach_to_session.__doc__, short_help="[a] Attach to a Zellij session")(attach_to_session)
148
+ layouts_app.command("a", no_args_is_help=False, help=attach_to_session.__doc__, hidden=True)(attach_to_session)
149
+
150
+ layouts_app.command("create-from-function", no_args_is_help=True, short_help="[c] Create a layout from a function")(create_from_function)
151
+ layouts_app.command("c", no_args_is_help=True, hidden=True)(create_from_function)
152
+
72
153
  layouts_app.command("balance-load", no_args_is_help=True, help=balance_load.__doc__, short_help="[b] Balance the load across sessions")(balance_load)
73
154
  layouts_app.command("b", no_args_is_help=True, help=balance_load.__doc__, hidden=True)(balance_load)
74
155
 
@@ -6,9 +6,10 @@ from typing import Annotated, Optional, Literal
6
6
 
7
7
  def kill_process(interactive: Annotated[bool, typer.Option(..., "--interactive", "-i", help="Interactively choose the process to kill")] = True) -> None:
8
8
  """⚔️ Choose a process to kill."""
9
- from machineconfig.utils.procs import main, ProcessManager
9
+ from machineconfig.utils.procs import ProcessManager
10
10
  if interactive:
11
- main()
11
+ proc = ProcessManager()
12
+ proc.choose_and_kill()
12
13
  return
13
14
  _ = ProcessManager
14
15
 
@@ -56,7 +56,6 @@ alias fx='wrap_in_shell_script ftpx'
56
56
  alias f='wrap_in_shell_script fire'
57
57
  alias r='wrap_in_shell_script croshell'
58
58
  alias u='wrap_in_shell_script utils'
59
- alias t='wrap_in_shell_script terminal'
60
59
  alias ms='wrap_in_shell_script msearch'
61
60
  alias x='wrap_in_shell_script explore'
62
61
 
@@ -73,12 +72,6 @@ alias x='wrap_in_shell_script explore'
73
72
  # gh copilot explain "Input command is: $x The output is this: $y"
74
73
  # }
75
74
 
76
- # 📦 Node Version Manager
77
- # export NVM_DIR="$HOME/.nvm"
78
- # [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
79
- # [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
80
-
81
-
82
75
  # https://github.com/atuinsh/atuin
83
76
  # eval "$(atuin init bash)"
84
77
 
@@ -40,12 +40,11 @@ if (Test-Path "$CONFIG_ROOT\scripts\wrap_mcfg.ps1") {
40
40
  function d { wrap_in_shell_script devops $args }
41
41
  function c { wrap_in_shell_script cloud $args }
42
42
  function a { wrap_in_shell_script agents $args }
43
- function sx { wrap_in_shell_script sessions $args }
44
43
  function fx { wrap_in_shell_script ftpx $args }
44
+ function s { wrap_in_shell_script sessions $args }
45
45
  function f { wrap_in_shell_script fire $args }
46
46
  function rr { wrap_in_shell_script croshell $args }
47
47
  function u { wrap_in_shell_script utils $args }
48
- function t { wrap_in_shell_script terminal $args }
49
48
  function ms { wrap_in_shell_script msearch $args }
50
49
 
51
50
  }
@@ -56,12 +55,11 @@ else {
56
55
  function d { devops $args }
57
56
  function c { cloud $args }
58
57
  function a { agents $args }
59
- function sx { sessions $args }
58
+ function s { sessions $args }
60
59
  function fx { ftpx $args }
61
60
  function f { fire $args }
62
61
  function rr { croshell $args }
63
62
  function u { utils $args }
64
- function t { terminal $args }
65
63
  function ms { msearch $args }
66
64
  }
67
65
 
@@ -157,6 +157,7 @@ config.inactive_pane_hsb = {
157
157
  }
158
158
 
159
159
  -- config.ime_preedit_rendering = 'System'
160
+ config.enable_tab_bar = false
160
161
  config.hide_tab_bar_if_only_one_tab = true
161
162
  config.use_fancy_tab_bar = false
162
163
  config.show_tabs_in_tab_bar = true
@@ -6,8 +6,7 @@
6
6
  "copyOnSelect": true,
7
7
  "defaultProfile": "{574e775e-4f2a-5b96-ac1e-a2962a402336}",
8
8
  "focusFollowMouse": true,
9
- "keybindings":
10
- [
9
+ "keybindings": [
11
10
  {
12
11
  "id": "Terminal.FindText",
13
12
  "keys": "ctrl+shift+f"
@@ -38,28 +37,26 @@
38
37
  }
39
38
  ],
40
39
  "launchMode": "fullscreen",
41
- "newTabMenu":
42
- [
40
+ "newTabMenu": [
43
41
  {
44
42
  "type": "remainingProfiles"
45
43
  }
46
44
  ],
47
- "profiles":
48
- {
49
- "defaults":
50
- {
45
+ "profiles": {
46
+ "defaults": {
51
47
  "colorScheme": "Campbell (modified)",
52
48
  "padding": "0",
53
- "useAcrylic": false
49
+ "useAcrylic": false,
50
+ "font": {
51
+ "face": "CaskaydiaCove Nerd Font"
52
+ }
54
53
  },
55
- "list":
56
- [
54
+ "list": [
57
55
  {
58
56
  "commandline": "C:\\Program Files\\PowerShell\\7\\pwsh.exe",
59
57
  "cursorColor": "#D4D8E1",
60
58
  "cursorShape": "filledBox",
61
- "font":
62
- {
59
+ "font": {
63
60
  "face": "CaskaydiaCove Nerd Font"
64
61
  },
65
62
  "guid": "{574e775e-4f2a-5b96-ac1e-a2962a402336}",
@@ -71,8 +68,7 @@
71
68
  },
72
69
  {
73
70
  "commandline": "%SystemRoot%\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
74
- "font":
75
- {
71
+ "font": {
76
72
  "face": "CaskaydiaCove Nerd Font"
77
73
  },
78
74
  "guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
@@ -93,8 +89,7 @@
93
89
  },
94
90
  {
95
91
  "commandline": "nu.exe",
96
- "font":
97
- {
92
+ "font": {
98
93
  "face": "CaskaydiaCove Nerd Font"
99
94
  },
100
95
  "guid": "{4b9d9cef-cb7d-4a8c-8b08-0de52621c3ff}",
@@ -157,8 +152,7 @@
157
152
  }
158
153
  ]
159
154
  },
160
- "schemes":
161
- [
155
+ "schemes": [
162
156
  {
163
157
  "background": "#000000",
164
158
  "black": "#000000",
@@ -59,7 +59,6 @@ alias fx='wrap_in_shell_script ftpx'
59
59
  alias f='wrap_in_shell_script fire'
60
60
  alias r='wrap_in_shell_script croshell'
61
61
  alias u='wrap_in_shell_script utils'
62
- alias t='wrap_in_shell_script terminal'
63
62
  alias ms='wrap_in_shell_script msearch'
64
63
  alias x='. $CONFIG_ROOT/scripts/wrap_mcfg explore'
65
64
 
File without changes