machineconfig 1.97__py3-none-any.whl → 2.0__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.

Potentially problematic release.


This version of machineconfig might be problematic. Click here for more details.

Files changed (166) hide show
  1. machineconfig/cluster/cloud_manager.py +22 -26
  2. machineconfig/cluster/data_transfer.py +2 -2
  3. machineconfig/cluster/distribute.py +0 -2
  4. machineconfig/cluster/file_manager.py +4 -4
  5. machineconfig/cluster/job_params.py +1 -1
  6. machineconfig/cluster/loader_runner.py +8 -8
  7. machineconfig/cluster/remote_machine.py +4 -4
  8. machineconfig/cluster/script_execution.py +2 -2
  9. machineconfig/cluster/sessions_managers/archive/create_zellij_template.py +1 -1
  10. machineconfig/cluster/sessions_managers/enhanced_command_runner.py +23 -23
  11. machineconfig/cluster/sessions_managers/wt_local.py +78 -76
  12. machineconfig/cluster/sessions_managers/wt_local_manager.py +91 -91
  13. machineconfig/cluster/sessions_managers/wt_remote.py +39 -39
  14. machineconfig/cluster/sessions_managers/wt_remote_manager.py +94 -91
  15. machineconfig/cluster/sessions_managers/wt_utils/layout_generator.py +56 -54
  16. machineconfig/cluster/sessions_managers/wt_utils/process_monitor.py +49 -49
  17. machineconfig/cluster/sessions_managers/wt_utils/remote_executor.py +18 -18
  18. machineconfig/cluster/sessions_managers/wt_utils/session_manager.py +42 -42
  19. machineconfig/cluster/sessions_managers/wt_utils/status_reporter.py +36 -36
  20. machineconfig/cluster/sessions_managers/zellij_local.py +43 -46
  21. machineconfig/cluster/sessions_managers/zellij_local_manager.py +139 -120
  22. machineconfig/cluster/sessions_managers/zellij_remote.py +35 -35
  23. machineconfig/cluster/sessions_managers/zellij_remote_manager.py +33 -33
  24. machineconfig/cluster/sessions_managers/zellij_utils/example_usage.py +15 -15
  25. machineconfig/cluster/sessions_managers/zellij_utils/layout_generator.py +25 -26
  26. machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +49 -49
  27. machineconfig/cluster/sessions_managers/zellij_utils/remote_executor.py +5 -5
  28. machineconfig/cluster/sessions_managers/zellij_utils/session_manager.py +15 -15
  29. machineconfig/cluster/sessions_managers/zellij_utils/status_reporter.py +11 -11
  30. machineconfig/cluster/templates/utils.py +3 -3
  31. machineconfig/jobs/__pycache__/__init__.cpython-311.pyc +0 -0
  32. machineconfig/jobs/python/__pycache__/__init__.cpython-311.pyc +0 -0
  33. machineconfig/jobs/python/__pycache__/python_ve_symlink.cpython-311.pyc +0 -0
  34. machineconfig/jobs/python/check_installations.py +8 -9
  35. machineconfig/jobs/python/python_cargo_build_share.py +2 -2
  36. machineconfig/jobs/python/vscode/link_ve.py +7 -7
  37. machineconfig/jobs/python/vscode/select_interpreter.py +7 -7
  38. machineconfig/jobs/python/vscode/sync_code.py +5 -5
  39. machineconfig/jobs/python_custom_installers/archive/ngrok.py +2 -2
  40. machineconfig/jobs/python_custom_installers/dev/aider.py +3 -3
  41. machineconfig/jobs/python_custom_installers/dev/alacritty.py +3 -3
  42. machineconfig/jobs/python_custom_installers/dev/brave.py +3 -3
  43. machineconfig/jobs/python_custom_installers/dev/bypass_paywall.py +5 -5
  44. machineconfig/jobs/python_custom_installers/dev/code.py +3 -3
  45. machineconfig/jobs/python_custom_installers/dev/cursor.py +9 -9
  46. machineconfig/jobs/python_custom_installers/dev/docker_desktop.py +4 -4
  47. machineconfig/jobs/python_custom_installers/dev/espanso.py +4 -4
  48. machineconfig/jobs/python_custom_installers/dev/goes.py +4 -4
  49. machineconfig/jobs/python_custom_installers/dev/lvim.py +4 -4
  50. machineconfig/jobs/python_custom_installers/dev/nerdfont.py +3 -3
  51. machineconfig/jobs/python_custom_installers/dev/redis.py +3 -3
  52. machineconfig/jobs/python_custom_installers/dev/wezterm.py +3 -3
  53. machineconfig/jobs/python_custom_installers/dev/winget.py +27 -27
  54. machineconfig/jobs/python_custom_installers/docker.py +3 -3
  55. machineconfig/jobs/python_custom_installers/gh.py +7 -7
  56. machineconfig/jobs/python_custom_installers/hx.py +1 -1
  57. machineconfig/jobs/python_custom_installers/warp-cli.py +3 -3
  58. machineconfig/jobs/python_generic_installers/config.json +412 -389
  59. machineconfig/jobs/python_windows_installers/dev/config.json +1 -1
  60. machineconfig/logger.py +50 -0
  61. machineconfig/profile/__pycache__/__init__.cpython-311.pyc +0 -0
  62. machineconfig/profile/__pycache__/create.cpython-311.pyc +0 -0
  63. machineconfig/profile/__pycache__/shell.cpython-311.pyc +0 -0
  64. machineconfig/profile/create.py +23 -16
  65. machineconfig/profile/create_hardlinks.py +8 -8
  66. machineconfig/profile/shell.py +41 -37
  67. machineconfig/scripts/__pycache__/__init__.cpython-311.pyc +0 -0
  68. machineconfig/scripts/__pycache__/__init__.cpython-313.pyc +0 -0
  69. machineconfig/scripts/linux/devops +2 -2
  70. machineconfig/scripts/linux/fire +1 -0
  71. machineconfig/scripts/linux/fire_agents +0 -1
  72. machineconfig/scripts/linux/mcinit +1 -1
  73. machineconfig/scripts/python/__pycache__/__init__.cpython-311.pyc +0 -0
  74. machineconfig/scripts/python/__pycache__/__init__.cpython-313.pyc +0 -0
  75. machineconfig/scripts/python/__pycache__/croshell.cpython-311.pyc +0 -0
  76. machineconfig/scripts/python/__pycache__/devops.cpython-311.pyc +0 -0
  77. machineconfig/scripts/python/__pycache__/devops.cpython-313.pyc +0 -0
  78. machineconfig/scripts/python/__pycache__/devops_update_repos.cpython-311.pyc +0 -0
  79. machineconfig/scripts/python/__pycache__/devops_update_repos.cpython-313.pyc +0 -0
  80. machineconfig/scripts/python/__pycache__/fire_agents.cpython-311.pyc +0 -0
  81. machineconfig/scripts/python/__pycache__/fire_jobs.cpython-311.pyc +0 -0
  82. machineconfig/scripts/python/__pycache__/repos.cpython-311.pyc +0 -0
  83. machineconfig/scripts/python/ai/__pycache__/init.cpython-311.pyc +0 -0
  84. machineconfig/scripts/python/ai/__pycache__/mcinit.cpython-311.pyc +0 -0
  85. machineconfig/scripts/python/ai/chatmodes/Thinking-Beast-Mode.chatmode.md +337 -0
  86. machineconfig/scripts/python/ai/chatmodes/Ultimate-Transparent-Thinking-Beast-Mode.chatmode.md +644 -0
  87. machineconfig/scripts/python/ai/chatmodes/deepResearch.chatmode.md +81 -0
  88. machineconfig/scripts/python/ai/configs/.gemini/settings.json +81 -0
  89. machineconfig/scripts/python/ai/instructions/python/dev.instructions.md +45 -0
  90. machineconfig/scripts/python/ai/mcinit.py +103 -0
  91. machineconfig/scripts/python/ai/prompts/allLintersAndTypeCheckers.prompt.md +5 -0
  92. machineconfig/scripts/python/ai/prompts/research-report-skeleton.prompt.md +38 -0
  93. machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +47 -0
  94. machineconfig/scripts/python/archive/tmate_conn.py +5 -5
  95. machineconfig/scripts/python/archive/tmate_start.py +3 -3
  96. machineconfig/scripts/python/choose_wezterm_theme.py +2 -2
  97. machineconfig/scripts/python/cloud_copy.py +19 -18
  98. machineconfig/scripts/python/cloud_mount.py +9 -7
  99. machineconfig/scripts/python/cloud_repo_sync.py +11 -11
  100. machineconfig/scripts/python/cloud_sync.py +1 -1
  101. machineconfig/scripts/python/croshell.py +14 -14
  102. machineconfig/scripts/python/devops.py +6 -6
  103. machineconfig/scripts/python/devops_add_identity.py +8 -6
  104. machineconfig/scripts/python/devops_add_ssh_key.py +18 -18
  105. machineconfig/scripts/python/devops_backup_retrieve.py +13 -13
  106. machineconfig/scripts/python/devops_devapps_install.py +3 -3
  107. machineconfig/scripts/python/devops_update_repos.py +1 -1
  108. machineconfig/scripts/python/dotfile.py +2 -2
  109. machineconfig/scripts/python/fire_agents.py +183 -41
  110. machineconfig/scripts/python/fire_jobs.py +17 -17
  111. machineconfig/scripts/python/ftpx.py +2 -2
  112. machineconfig/scripts/python/gh_models.py +94 -94
  113. machineconfig/scripts/python/helpers/__pycache__/__init__.cpython-311.pyc +0 -0
  114. machineconfig/scripts/python/helpers/__pycache__/cloud_helpers.cpython-311.pyc +0 -0
  115. machineconfig/scripts/python/helpers/__pycache__/helpers2.cpython-311.pyc +0 -0
  116. machineconfig/scripts/python/helpers/__pycache__/helpers4.cpython-311.pyc +0 -0
  117. machineconfig/scripts/python/helpers/cloud_helpers.py +3 -3
  118. machineconfig/scripts/python/helpers/helpers2.py +1 -1
  119. machineconfig/scripts/python/helpers/helpers4.py +8 -6
  120. machineconfig/scripts/python/helpers/helpers5.py +7 -7
  121. machineconfig/scripts/python/helpers/repo_sync_helpers.py +1 -1
  122. machineconfig/scripts/python/mount_nfs.py +3 -2
  123. machineconfig/scripts/python/mount_nw_drive.py +4 -4
  124. machineconfig/scripts/python/mount_ssh.py +3 -2
  125. machineconfig/scripts/python/repos.py +8 -8
  126. machineconfig/scripts/python/scheduler.py +1 -1
  127. machineconfig/scripts/python/start_slidev.py +8 -7
  128. machineconfig/scripts/python/start_terminals.py +1 -1
  129. machineconfig/scripts/python/viewer.py +40 -40
  130. machineconfig/scripts/python/wifi_conn.py +65 -66
  131. machineconfig/scripts/python/wsl_windows_transfer.py +1 -1
  132. machineconfig/scripts/windows/mcinit.ps1 +1 -1
  133. machineconfig/settings/linters/.ruff.toml +2 -2
  134. machineconfig/settings/shells/ipy/profiles/default/startup/playext.py +71 -71
  135. machineconfig/settings/shells/wt/settings.json +8 -8
  136. machineconfig/setup_linux/web_shortcuts/tmp.sh +2 -0
  137. machineconfig/setup_windows/wt_and_pwsh/set_pwsh_theme.py +10 -7
  138. machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +9 -7
  139. machineconfig/utils/ai/browser_user_wrapper.py +5 -5
  140. machineconfig/utils/ai/generate_file_checklist.py +11 -12
  141. machineconfig/utils/ai/url2md.py +1 -1
  142. machineconfig/utils/cloud/onedrive/setup_oauth.py +4 -4
  143. machineconfig/utils/cloud/onedrive/transaction.py +129 -129
  144. machineconfig/utils/code.py +13 -6
  145. machineconfig/utils/installer.py +51 -53
  146. machineconfig/utils/installer_utils/installer_abc.py +21 -10
  147. machineconfig/utils/installer_utils/installer_class.py +42 -16
  148. machineconfig/utils/io_save.py +3 -15
  149. machineconfig/utils/options.py +10 -3
  150. machineconfig/utils/path.py +5 -0
  151. machineconfig/utils/path_reduced.py +201 -149
  152. machineconfig/utils/procs.py +23 -23
  153. machineconfig/utils/scheduling.py +11 -12
  154. machineconfig/utils/ssh.py +270 -0
  155. machineconfig/utils/terminal.py +180 -0
  156. machineconfig/utils/utils.py +1 -2
  157. machineconfig/utils/utils2.py +43 -0
  158. machineconfig/utils/utils5.py +163 -34
  159. machineconfig/utils/ve.py +2 -2
  160. {machineconfig-1.97.dist-info → machineconfig-2.0.dist-info}/METADATA +13 -8
  161. {machineconfig-1.97.dist-info → machineconfig-2.0.dist-info}/RECORD +163 -149
  162. machineconfig/cluster/self_ssh.py +0 -57
  163. machineconfig/scripts/python/ai/init.py +0 -56
  164. machineconfig/scripts/python/ai/rules/python/dev.md +0 -31
  165. {machineconfig-1.97.dist-info → machineconfig-2.0.dist-info}/WHEEL +0 -0
  166. {machineconfig-1.97.dist-info → machineconfig-2.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,81 @@
1
+ ---
2
+ description: 'Autonomous, multi-step web research with numbered citations, cross-source verification, and a final Markdown report.'
3
+ tools: ['extensions', 'fetch', 'websearch', 'search', 'githubRepo', 'editFiles']
4
+ ---
5
+
6
+ # Deep Research mode
7
+
8
+ You are a rigorous research agent. Emulate the behavior of OpenAI ā€œDeep Researchā€ and Perplexity ā€œPro/Researchā€ modes:
9
+ - Plan first, then execute iterative searches and browsing.
10
+ - Read broadly, follow relevant links recursively, and take structured notes.
11
+ - Attribute every non-trivial claim with numbered citations and quotes.
12
+ - Cross-verify important facts across independent, high-quality sources.
13
+ - Produce a clean, self-contained Markdown report saved to ./.ai/deep_research_$suffix.md.
14
+
15
+ This mode is read-heavy. Do not modify project code. Only create or update files under ./.ai/.
16
+
17
+ ## Inputs and outputs
18
+ - Input: a research question or task, optional `suffix` for report naming, optional provided URLs.
19
+ - Output: a Markdown report written to ./.ai/deep_research_$suffix.md and a concise chat summary with key findings and links.
20
+
21
+ ## Tools you should use
22
+ - fetch: fetch page contents for provided or discovered URLs.
23
+ - websearch: perform web searches to discover authoritative sources. Iterate as needed.
24
+ - search: only for searching the local workspace when relevant (not the web).
25
+ - githubRepo: optionally pull examples or repos if directly relevant.
26
+ - editFiles: create/update the report file under ./.ai/.
27
+
28
+ ## Execution protocol
29
+ Follow these phases every time. Provide compact progress updates between phases and after every ~3–5 tool calls: what you did and what’s next.
30
+
31
+ 1) Planning and scope
32
+ - Restate the question. Extract explicit and implicit sub-questions as a checklist.
33
+ - Define success criteria (decision to be made, comparison outcome, data needed, etc.).
34
+ - Draft a search plan: keywords, entities, time range/recency requirements, likely primary sources, and anticipated pitfalls.
35
+
36
+ 2) Initial search and source triage
37
+ - Use websearch to find diverse, reputable sources (docs, standards, primary data, peer-reviewed or recognized outlets). Prefer primary sources where possible.
38
+ - For each candidate, use fetch to open it. Capture: title, author/org, publish/update date, URL, key quotes (with exact wording), and quick trust notes.
39
+ - Track sources in a table within your working notes (not necessarily in the final report) to avoid duplication.
40
+
41
+ 3) Recursive exploration and verification
42
+ - Follow relevant links found in good sources (fetch them). Stop when additional sources stop changing conclusions materially.
43
+ - Cross-check critical numbers, timelines, and quotes against at least two independent sources when available.
44
+ - If sources conflict, explain the disagreement and weigh credibility (recency, expertise, methodology, bias, primary vs. secondary).
45
+
46
+ 4) Synthesis and reporting
47
+ - Draft a clear, structured Markdown report with:
48
+ - Title and date
49
+ - Executive summary (bulleted, 5–10 lines, with [n] citations inline)
50
+ - Key findings (short sections, each claim supported by [n] citations and brief quotes)
51
+ - Analysis (trade-offs, areas of uncertainty, limitations, and what to watch next)
52
+ - Recommendations or direct answers, if applicable (with citations)
53
+ - Appendix: Sources list with numbered entries [n], each including title, author/org, date (published/updated), URL, and quoted snippets used
54
+ - Ensure the report is readable and skimmable. Keep sentences concise.
55
+
56
+ 5) Save the report
57
+ - Determine `$suffix` in this order: (a) user-provided; else (b) a short kebab-case slug from the question; append date (YYYYMMDD) if helpful.
58
+ - Ensure directory ./.ai exists; create it if missing.
59
+ - Write the report to ./.ai/deep_research_$suffix.md using editFiles.
60
+
61
+ 6) Final checks
62
+ - Verify every non-obvious statement has a citation [n] pointing to a source in Appendix.
63
+ - Verify dates are present for sources when available; prefer the most recent reputable sources.
64
+ - Remove dead links if discovered; replace with archived or alternative sources when possible.
65
+ - Share a concise chat summary with 3–6 bullets and the saved file path.
66
+
67
+ ## Citation rules
68
+ - Use numeric references [1], [2], ... inline; match them in the Appendix.
69
+ - Quote short key phrases exactly (with quotation marks) and include context.
70
+ - Include publish/update date and access date (today) when available.
71
+ - Prefer primary documentation, official standards, authors/organizations with recognized expertise, and recent updates.
72
+
73
+ ## Guardrails and quality
74
+ - Be explicit when uncertain; avoid speculation. If evidence is weak, state it.
75
+ - Distinguish proven facts vs. interpretations. Label opinions as such.
76
+ - Avoid paywalled content if it prevents verification; seek alternative open sources or include accessible abstracts.
77
+ - If new questions arise, loop back with targeted websearch/fetch until conclusions are well-supported.
78
+
79
+ ## Usage
80
+ - In chat, switch to ā€œDeep Researchā€ mode. Provide your query and optionally `suffix:` or `filename:` hint (e.g., suffix: chiplet-market-2025).
81
+ - This mode will produce the report and post the saved path, e.g., ./.ai/deep_research_chiplet-market-2025.md.
@@ -0,0 +1,81 @@
1
+ {
2
+ // Appearance
3
+ "theme": "Default", // Could also be "GitHub", "Dracula", etc.
4
+
5
+ // Authentication
6
+ "selectedAuthType": "gemini-api-key", // Options: "gemini-api-key", "oauth-personal", "vertex-ai"
7
+
8
+ // Tool usage and safety
9
+ "sandbox": false, // Enable with true or specify backend ("docker", "podman")
10
+ "autoAccept": true, // Auto-approve safe tool calls
11
+ "usageStatisticsEnabled": false, // Collect anonymized usage stats
12
+ "telemetry": {
13
+ "enabled": false,
14
+ "target": "remote", // or "local"
15
+ "logPrompts": false
16
+ },
17
+
18
+ // Work environment configuration
19
+ "preferredEditor": "vim", // or "vscode", "nano", etc.
20
+ "fileFiltering": {
21
+ "respectGitIgnore": true,
22
+ "enableRecursiveFileSearch": true
23
+ },
24
+
25
+ // Context and workspace behavior
26
+ "contextFileName": "GEMINI.md", // Can also be an array of filenames
27
+ "includeDirectories": [], // e.g., ["../shared", "~/common-utils"]
28
+ "chatCompression": {
29
+ "contextPercentageThreshold": 0.5 // Threshold for compressing history
30
+ },
31
+
32
+ // Bug reporting customization
33
+ "bugCommand": {
34
+ "urlTemplate": "https://github.com/google-gemini/gemini-cli/issues/new?template=bug_report.yml&title={title}&info={info}"
35
+ },
36
+
37
+ // Extensions and integrations via MCP servers
38
+ "mcpServers": {
39
+ // Example structure; override or extend as needed
40
+ // "myServer": {
41
+ // "command": "my_mcp_tool",
42
+ // "args": [],
43
+ // "httpUrl": "http://localhost:####/mcp",
44
+ // "headers": {},
45
+ // "timeout": 10000,
46
+ // "trust": false,
47
+ // "includeTools": [],
48
+ // "excludeTools": []
49
+ // }
50
+ },
51
+
52
+ // Control which tools are available
53
+ "coreTools": [
54
+ "EditTool",
55
+ "GlobTool",
56
+ "WebSearchTool",
57
+ "ReadFileTool",
58
+ "LSTool",
59
+ "ReadManyFilesTool",
60
+ "MemoryTool",
61
+ "GrepTool",
62
+ "ShellTool",
63
+ "WebFetchTool",
64
+ "WriteFileTool"
65
+ ],
66
+ "excludeTools": [],
67
+
68
+ // Custom color themes (optional)
69
+ "customThemes": {
70
+ "MyCustomTheme": {
71
+ "name": "MyCustomTheme",
72
+ "type": "custom",
73
+ "Background": "#181818",
74
+ "Foreground": "#F8F8F2",
75
+ "AccentBlue": "#61AFEF",
76
+ "AccentPurple": "#C678DD",
77
+ "AccentGreen": "#98C379"
78
+ // Add more as desired
79
+ }
80
+ }
81
+ }
@@ -0,0 +1,45 @@
1
+
2
+ ---
3
+ applyTo: "**/*.py"
4
+ ---
5
+
6
+ # Python Development Environment and tooling:
7
+ * If you find that uv is not available in terminal, look for how to install it in https://github.com/astral-sh/uv
8
+ * To initialize a new python project, use `cd $repo_root; uv init --python 3.13`
9
+ * To create virtual env, use `cd $repo_root; uv venv`.
10
+ * To install venv and dependency of an existing project, use `cd $repo_root; uv sync`.
11
+ * Please run any python file using `uv run $file.py`
12
+ * Same for tools, e.g. `un run python pytest $file_path`
13
+ * To add a package, use `cd $repo_root; uv add <package_name>`.
14
+ * Please never mention versions of package, so uv will bring the latest.
15
+ * On this note, I have to say that I am seriously concerned about AI using very outdated coding style.
16
+ * Use python 3.13 syntax features.
17
+ * Use modern standards, e.g. Path from pathlib.
18
+ * Never touch `pyproject.toml` manually, this file is strictly managed by `uv` tool on your behalf.
19
+ * If you are writing a test or any temporary script for discovering or undestanding something as an intermediate step, then,
20
+ please keep all your temp scripts and files under ./.ai/tmp_scripts directory, its included in .gitignore and won't litter the repo.
21
+ Its also nice if you create a subdirectory therein to contain relevant files for the task at hand, to avoid confusion with other files from other ai agents working simulataneously on other things.
22
+ * When you run a command in the terminal, please don't assume that it will run in the correct repo root directory. Always cd first to the repo root, or the desired directory, then run the command.
23
+
24
+ # Python Coding Rules
25
+ * Please type hint all the code. Use fully quilaified types, not just generics like dict, list, etc, rather dict[str, int], list[float], 'npt.NDarray[np.float32]', etc.
26
+ * Use `Any` type only if absoloutely necessary.
27
+ * Please use `# type: ignore blah blah`, to silence any warning from pyright or other linters and type checkers, but only when necessary. Otherwise, listen to them and adjust accordingly, or use cast from typing.
28
+ * Use typeddict, dataclasses and literals when necessary to avoid blackbox str or dict[str, str] etc.
29
+ * ALL functions / methods etc must clearly indicate the return type.
30
+ * Do not leave dangling imports or variables unused, prefix their name with underscore if necessary to undicate they are unused.
31
+ * Please prefer to use absolute imports, avoid relatives when possible.
32
+ * Use triple quotes and triple double quotes f-strings for string formatting and avoid when possible all goofy escaping when interpolation.
33
+ * If needed, opt for polars not pandas, whenever possible.
34
+ * when finished, run a linting static analysis check against files you touched, Any fix any mistakes.
35
+ * Please run `uv run -m pyright $file_touched` and address all issues. if `pyright is not there, first run `uv add pyright --dev`.
36
+ * For all type checkers and linters, like mypy, pyright, pyrefly and pylint, there are config files at different levels of the repo all the way up to home directory level. You don't need to worry about them, just be mindful that they exist. The tools themselves will respect the configs therein.
37
+ * If you want to run all linters and pycheckers agains the entire project to make sure everything is clean, I prepared a nice shell script, you can run it from the repo root as `./scripts/lint_and_typecheck.sh`. It will produce markdown files that are you are meant to look at @ ./.linters/*.md
38
+
39
+ # General Programming Ethos:
40
+ * Make sure all the code is rigorous, no lazy stuff.
41
+ * For example, always avoid default values in arguments of functions. Those are evil and cause confusion. Always be explicit in parameter passing.
42
+ * Unless asked explicitly, please never ever attempt to change code files by writing meta code to do string manipulation on files. Please do change the files one by one, no matter how many there is. Don't worry about time, its okay, take your time and do them one by one. You can stop in the middle and we will have another LLM to help with the rest.
43
+ * Please avoid writing README files and avoid docstring and comments in code unless absolutely necessary. Use clear naming conventions instead of documenting.
44
+ * Always prefer to functional style of programming over OOP.
45
+ * When passing arguments or constructing dicts or lists or tuples, avoid breaking lines too much, try to use ~ 150 characters per line before breaking to new one.
@@ -0,0 +1,103 @@
1
+
2
+
3
+ from pathlib import Path
4
+ from typing import Optional
5
+
6
+
7
+ installations = """
8
+ uv add --upgrade-package pylint pyright mypy pyrefly ty --dev # linters and type checkers
9
+ uv add --upgrade-package pytest --dev
10
+ """
11
+
12
+ def get_repo_root(path: Path) -> Optional[Path]:
13
+ from git import Repo, InvalidGitRepositoryError
14
+ try:
15
+ repo = Repo(path, search_parent_directories=True)
16
+ root = repo.working_tree_dir
17
+ if root is not None:
18
+ return Path(root)
19
+ except InvalidGitRepositoryError:
20
+ pass
21
+ return None
22
+
23
+ def add_ai_configs(repo_root: Path):
24
+ import machineconfig as mc
25
+ mc_root = Path(mc.__file__).parent
26
+
27
+ repo_root_resolved = get_repo_root(repo_root)
28
+ if repo_root_resolved is not None: repo_root = repo_root_resolved # this means you can run the command from any subdirectory of the repo.
29
+
30
+ if repo_root.joinpath("pyproject.toml").exists() is False:
31
+ uv_init = input(f"{repo_root} does not seem to be a python project (no pyproject.toml found), would you like to initialize one? (y/n) ")
32
+ if uv_init.strip().lower() == "y":
33
+ command_to_run = """
34
+ uv init --python 3.13
35
+ uv venv
36
+ """
37
+ import subprocess
38
+ subprocess.run(command_to_run, shell=True, check=True)
39
+ else:
40
+ print("Terminating mcinit ...")
41
+ return
42
+
43
+ instructions_repository_dir = mc_root.joinpath("scripts/python/ai/instructions")
44
+ chatmodes_dir = mc_root.joinpath("scripts/python/ai/chatmodes")
45
+ prompts_dir = mc_root.joinpath("scripts/python/ai/prompts")
46
+ # python_rules_file = instructions_repository_dir.joinpath("python/dev.md")
47
+
48
+ # VSCODE:
49
+ # as per: https://docs.github.com/en/copilot/how-tos/configure-custom-instructions/add-repository-instructions
50
+ # Copilot Chat on github website chat & basic guideline.
51
+ repo_root.joinpath(".github/chatmodes").mkdir(parents=True, exist_ok=True)
52
+ repo_root.joinpath(".github/prompts").mkdir(parents=True, exist_ok=True)
53
+ repo_root.joinpath(".github/instructions").mkdir(parents=True, exist_ok=True)
54
+ for a_chatmode in chatmodes_dir.iterdir():
55
+ repo_root.joinpath(".github/chatmodes", a_chatmode.name.split(".")[0] + ".chatmode.md").write_text(data=a_chatmode.read_text(encoding="utf-8"), encoding="utf-8")
56
+ for a_prompt in prompts_dir.iterdir():
57
+ repo_root.joinpath(".github/prompts", a_prompt.name.split(".")[0] + ".prompt.md").write_text(data=a_prompt.read_text(encoding="utf-8"), encoding="utf-8")
58
+ for an_instruction in instructions_repository_dir.rglob("*.md"):
59
+ repo_root.joinpath(".github/instructions", an_instruction.name.split(".")[0] + ".instruction.md").write_text(data=an_instruction.read_text(encoding="utf-8"), encoding="utf-8")
60
+ tmp = repo_root.joinpath(".github/copilot-instructions.md")
61
+
62
+ generic_instructions = instructions_repository_dir.joinpath("python/dev.instructions.md")
63
+ tmp.write_text(data=generic_instructions.read_text(encoding="utf-8"), encoding="utf-8")
64
+
65
+ # CURSOR, GEMINI, CLAUDE CODE, CRUSH, CLINE.
66
+ tmp = repo_root.joinpath(".cursor/rules/python_dev.mdc")
67
+ tmp.parent.mkdir(parents=True, exist_ok=True)
68
+ tmp.write_text(data=generic_instructions.read_text(encoding="utf-8"), encoding="utf-8")
69
+ tmp = repo_root.joinpath("CLAUDE.md")
70
+ tmp.write_text(data=generic_instructions.read_text(encoding="utf-8"), encoding="utf-8")
71
+ tmp = repo_root.joinpath("CRUSH.md")
72
+ tmp.write_text(data=generic_instructions.read_text(encoding="utf-8"), encoding="utf-8")
73
+
74
+ tmp = repo_root.joinpath("GEMINI.md")
75
+ tmp.write_text(data=generic_instructions.read_text(encoding="utf-8"), encoding="utf-8")
76
+ gemini_settings = mc_root.joinpath("scripts/python/ai/configs/.gemini/settings.json")
77
+ repo_root.joinpath(".gemini").mkdir(parents=True, exist_ok=True)
78
+ repo_root.joinpath(".gemini/settings.json").write_text(data=gemini_settings.read_text(encoding="utf-8"), encoding="utf-8")
79
+
80
+ # OTHERS
81
+ scripts_dir = mc_root.joinpath("scripts/python/ai/scripts")
82
+ repo_root.joinpath("scripts").mkdir(parents=True, exist_ok=True)
83
+ for a_script in scripts_dir.iterdir():
84
+ repo_root.joinpath("scripts", a_script.name).write_text(data=a_script.read_text(encoding="utf-8"), encoding="utf-8")
85
+
86
+ dot_ai_dir = repo_root.joinpath(".ai")
87
+ dot_ai_dir.mkdir(parents=True, exist_ok=True)
88
+ dot_git_ignore_path = repo_root.joinpath(".gitignore")
89
+ if dot_git_ignore_path.exists():
90
+ dot_git_ignore_content = dot_git_ignore_path.read_text(encoding="utf-8")
91
+ to_add: list[str] = []
92
+ to_check_for: list[str] = [".links", "notebooks", ".ai", "scripts",
93
+ "GEMINI.md", "CLAUDE.md", ".cursor", ".github"]
94
+ for item in to_check_for:
95
+ if item not in dot_git_ignore_content:
96
+ to_add.append(item)
97
+ # if "*.ipynb"
98
+ if len(to_add) > 0:
99
+ dot_git_ignore_path.write_text(data=dot_git_ignore_content + "\n" + "\n".join(to_add), encoding="utf-8")
100
+
101
+
102
+ if __name__ == "__main__":
103
+ add_ai_configs(repo_root=Path.cwd())
@@ -0,0 +1,5 @@
1
+ ---
2
+ mode: agent
3
+ ---
4
+
5
+ please run the following
@@ -0,0 +1,38 @@
1
+ ```prompt
2
+ ---
3
+ description: 'A minimal skeleton for deep research reports.'
4
+ ---
5
+
6
+ # <Title>
7
+
8
+ Date: <YYYY-MM-DD>
9
+
10
+ ## Executive summary
11
+ - <key point 1> [n]
12
+ - <key point 2> [n]
13
+ - <key point 3> [n]
14
+
15
+ ## Key findings
16
+ ### <Finding A>
17
+ - Claim: <text> [n]
18
+ - Evidence: "<quote>" [n]
19
+ - Notes: <brief trust/limitations>
20
+
21
+ ### <Finding B>
22
+ - Claim: <text> [n]
23
+ - Evidence: "<quote>" [n]
24
+
25
+ ## Analysis
26
+ - Trade-offs
27
+ - Uncertainties
28
+ - What to watch next
29
+
30
+ ## Recommendations / Direct answer
31
+ - <concise recommendation or answer> [n]
32
+
33
+ ## Appendix: Sources
34
+ [1] <Title> — <Author/Org>, <Date>. <URL>
35
+ [2] <Title> — <Author/Org>, <Date>. <URL>
36
+ [3] <Title> — <Author/Org>, <Date>. <URL>
37
+
38
+ ```
@@ -0,0 +1,47 @@
1
+
2
+ # gotch1: make sure we are in the right directory: repo root. Solution: check if .pyproject.toml exists, otherwise stop.
3
+ if [ ! -f "./pyproject.toml" ]; then
4
+ echo "Error: pyproject.toml not found in the current directory. Please run this script from the root of a Python project."
5
+ exit 1
6
+ fi
7
+
8
+ echo "Running linting and type checking..."
9
+
10
+ echo "Setting up environment..."
11
+ uv add pylint pyright mypy pyrefly ruff ty --dev # linters and type checkers
12
+ uv add cleanpy --dev # codebase cleaner
13
+
14
+ uv add types-requests types-toml types-PyYAML types-pytz types-paramiko types-urllib3 --dev
15
+ uv add types-mysqlclient types-SQLAlchemy --dev
16
+ uv add types-pytest-lazy-fixtures --dev
17
+
18
+ uv run -m cleanpy .
19
+ uv run -m ruff clean
20
+ uv run -m ruff format .
21
+ uv run -m ruff check . --fix
22
+
23
+
24
+ mkdir .linters
25
+
26
+ echo "Running pyright..."
27
+ rm ./.linters/pyright_result.md || true
28
+ uv run pyright . > ./.linters/pyright_result.md
29
+ echo "Results of pyright are in ./.linters/pyright_result.md"
30
+
31
+ rm ./.linters/mypy_result.md || true
32
+ uv run mypy . > ./.linters/mypy_result.md
33
+ echo "Results of mypy are in ./.linters/mypy_result.md"
34
+
35
+ rm ./.linters/pylint_result.md || true
36
+ uv run pylint ./src/ > ./.linters/pylint_result.md
37
+ echo "Results of pylint are in ./.linters/pylint_result.md"
38
+
39
+ rm ./.linters/pylint_result.md || true
40
+ uv run pyrefly check . > ./.linters/pyrefly_result.md
41
+ echo "Results of pyrefly are in ./.linters/pyrefly_result.md"
42
+
43
+ rm ./.linters/ruff_result.md || true
44
+ uv run ruff check . > ./.linters/ruff_result.md
45
+ echo "Results of ruff are in ./.linters/ruff_result.md"
46
+
47
+ echo "All done! Please check the .linters directory for results."
@@ -21,19 +21,19 @@ def get_conn_string(sess_name: str) -> str:
21
21
 
22
22
  def main():
23
23
  console.print(Panel("šŸ”Œ Tmate Connection Manager", title="[bold]Welcome[/bold]"))
24
-
24
+
25
25
  parser = argparse.ArgumentParser(description='Tmate launcher')
26
26
  parser.add_argument("sess_name", help="session name", default=random.choices(list(string.digits + string.ascii_letters), k=20))
27
27
  args = parser.parse_args()
28
-
28
+
29
29
  console.print(f"šŸ” Looking up session: {args.sess_name}")
30
30
  conn_string = get_conn_string(args.sess_name)
31
-
31
+
32
32
  console.print(Panel(f"SSH Connection String: ssh {conn_string}", title="[bold green]SSH Connection[/bold green]"))
33
-
33
+
34
34
  console.print("šŸš€ Connecting to tmate session...")
35
35
  os.system(f"ssh {conn_string}")
36
-
36
+
37
37
  console.print("āœ… Connection closed")
38
38
 
39
39
 
@@ -30,13 +30,13 @@ def main():
30
30
  console.print(f"šŸ” Looking up session configuration: {args.sess_name}")
31
31
  sess_name = creds['sessions_names'][args.sess_name]
32
32
  api_key = creds['keys']['api_key']
33
-
33
+
34
34
  console.print(Panel(f"šŸš€ Starting tmate session: {sess_name}", title="[bold green]Session Info[/bold green]"))
35
-
35
+
36
36
  res = f"tmate -a ~/.ssh/authorized_keys -k {api_key} -n {sess_name} -F"
37
37
  console.print("[bold cyan]Running:[/bold cyan] tmate with configured API key and session name")
38
38
  os.system(res)
39
-
39
+
40
40
  console.print("[green]Tmate session ended[/green]")
41
41
 
42
42
 
@@ -51,13 +51,13 @@ def main2():
51
51
 
52
52
  def set_theme(theme: str):
53
53
  print(f"šŸ”„ Setting WezTerm theme to: {theme}")
54
- txt_lines = PathExtended("~/.config/wezterm/wezterm.lua").expanduser().read_text().splitlines()
54
+ txt_lines = PathExtended("~/.config/wezterm/wezterm.lua").expanduser().read_text(encoding="utf-8").splitlines()
55
55
  res_lines = []
56
56
  for line in txt_lines:
57
57
  if 'config.color_scheme = ' in line:
58
58
  res_lines.append(f"config.color_scheme = '{theme}'")
59
59
  else: res_lines.append(line)
60
- PathExtended("~/.config/wezterm/wezterm.lua").expanduser().write_text('\n'.join(res_lines))
60
+ PathExtended("~/.config/wezterm/wezterm.lua").expanduser().write_text('\n'.join(res_lines), encoding="utf-8")
61
61
  time.sleep(0.1)
62
62
  print("šŸ’¾ Configuration saved")
63
63
 
@@ -3,7 +3,7 @@ CC
3
3
  """
4
4
 
5
5
  from machineconfig.utils.path_reduced import P as PathExtended
6
- from crocodile.meta import RepeatUntilNoException
6
+ from tenacity import retry, stop_after_attempt, wait_chain, wait_fixed
7
7
  import getpass
8
8
  import argparse
9
9
  import os
@@ -18,19 +18,19 @@ from machineconfig.utils.utils2 import pprint
18
18
 
19
19
  console = Console()
20
20
 
21
- @RepeatUntilNoException(retry=3, sleep=1)
21
+ @retry(stop=stop_after_attempt(3), wait=wait_chain(wait_fixed(1), wait_fixed(4), wait_fixed(9)))
22
22
  def get_securely_shared_file(url: Optional[str] = None, folder: Optional[str] = None) -> None:
23
23
  console.print(Panel("šŸš€ Secure File Downloader", title="[bold blue]Downloader[/bold blue]", border_style="blue"))
24
-
24
+
25
25
  folder_obj = PathExtended.cwd() if folder is None else PathExtended(folder)
26
26
  print(f"šŸ“‚ Target folder: {folder_obj}")
27
-
27
+
28
28
  if os.environ.get("DECRYPTION_PASSWORD") is not None:
29
29
  print("šŸ”‘ Using password from environment variables")
30
30
  pwd = str(os.environ.get("DECRYPTION_PASSWORD"))
31
31
  else:
32
32
  pwd = getpass.getpass(prompt="šŸ”‘ Enter decryption password: ")
33
-
33
+
34
34
  if url is None:
35
35
  if os.environ.get("SHARE_URL") is not None:
36
36
  url = os.environ.get("SHARE_URL")
@@ -38,21 +38,22 @@ def get_securely_shared_file(url: Optional[str] = None, folder: Optional[str] =
38
38
  print("šŸ”— Using URL from environment variables")
39
39
  else:
40
40
  url = input("šŸ”— Enter share URL: ")
41
-
41
+
42
42
  console.print(Panel("šŸ“” Downloading from URL...", title="[bold blue]Download[/bold blue]", border_style="blue"))
43
43
  with Progress(transient=True) as progress:
44
44
  _task = progress.add_task("Downloading... ", total=None)
45
45
  url_obj = PathExtended(url).download(folder=folder_obj)
46
-
46
+
47
47
  console.print(Panel(f"šŸ“„ Downloaded file: {url_obj}", title="[bold green]Success[/bold green]", border_style="green"))
48
-
48
+
49
49
  console.print(Panel("šŸ” Decrypting and extracting...", title="[bold blue]Processing[/bold blue]", border_style="blue"))
50
50
  with Progress(transient=True) as progress:
51
51
  _task = progress.add_task("Decrypting... ", total=None)
52
52
  tmp_folder = PathExtended.tmpdir(prefix="tmp_unzip")
53
53
  try:
54
54
  res = url_obj.decrypt(pwd=pwd, inplace=True).unzip(inplace=True, folder=tmp_folder)
55
- res.search("*").apply(lambda x: x.move(folder=folder_obj, overwrite=True))
55
+ for x in res.search("*"):
56
+ x.move(folder=folder_obj, overwrite=True)
56
57
  finally:
57
58
  # Clean up temporary folder
58
59
  if tmp_folder.exists():
@@ -61,7 +62,7 @@ def get_securely_shared_file(url: Optional[str] = None, folder: Optional[str] =
61
62
 
62
63
  def arg_parser() -> None:
63
64
  console.print(Panel("ā˜ļø Cloud Copy Utility", title="[bold blue]Cloud Copy[/bold blue]", border_style="blue", width=152))
64
-
65
+
65
66
  parser = argparse.ArgumentParser(description='šŸš€ Cloud CLI. It wraps rclone with sane defaults for optimum type time.')
66
67
 
67
68
  # positional argument
@@ -105,40 +106,40 @@ def arg_parser() -> None:
105
106
 
106
107
  console.print(Panel("šŸ” Parsing source and target paths...", title="[bold blue]Info[/bold blue]", border_style="blue"))
107
108
  cloud, source, target = parse_cloud_source_target(args=args_obj, source=source, target=target)
108
-
109
+
109
110
  console.print(Panel("āš™ļø Configuration:", title="[bold blue]Config[/bold blue]", border_style="blue"))
110
111
  pprint(args_obj.__dict__, "CLI config")
111
112
 
112
113
  if args_obj.key is not None:
113
114
  console.print(Panel("āŒ Key-based encryption is not supported yet", title="[bold red]Error[/bold red]", border_style="red"))
114
115
  raise ValueError("Key-based encryption is not supported yet.")
115
-
116
+
116
117
  if cloud in source:
117
118
  console.print(Panel(f"šŸ“„ DOWNLOADING FROM CLOUD\nā˜ļø Cloud: {cloud}\nšŸ“‚ Source: {source.replace(cloud + ':', '')}\nšŸŽÆ Target: {target}", title="[bold blue]Download[/bold blue]", border_style="blue", width=152))
118
-
119
+
119
120
  PathExtended(target).from_cloud(cloud=cloud, remotepath=source.replace(cloud + ":", ""),
120
121
  unzip=args_obj.zip, decrypt=args_obj.encrypt, pwd=args_obj.pwd,
121
122
  overwrite=args_obj.overwrite,
122
123
  rel2home=args_obj.rel2home, os_specific=args_obj.os_specific, root=args_obj.root, strict=False,
123
124
  )
124
125
  console.print(Panel("āœ… Download completed successfully", title="[bold green]Success[/bold green]", border_style="green", width=152))
125
-
126
+
126
127
  elif cloud in target:
127
128
  console.print(Panel(f"šŸ“¤ UPLOADING TO CLOUD\nā˜ļø Cloud: {cloud}\nšŸ“‚ Source: {source}\nšŸŽÆ Target: {target.replace(cloud + ':', '')}", title="[bold blue]Upload[/bold blue]", border_style="blue", width=152))
128
-
129
+
129
130
  res = PathExtended(source).to_cloud(cloud=cloud, remotepath=target.replace(cloud + ":", ""),
130
131
  zip=args_obj.zip, encrypt=args_obj.encrypt, pwd=args_obj.pwd,
131
132
  rel2home=args_obj.rel2home, root=args_obj.root, os_specific=args_obj.os_specific, strict=False,
132
133
  share=args_obj.share)
133
134
  console.print(Panel("āœ… Upload completed successfully", title="[bold green]Success[/bold green]", border_style="green", width=152))
134
-
135
+
135
136
  if args_obj.share:
136
137
  fname = f".share_url_{cloud}"
137
138
  if PathExtended(source).is_dir(): share_url_path = PathExtended(source).joinpath(fname)
138
139
  else: share_url_path = PathExtended(source).with_suffix(fname)
139
- share_url_path.write_text(res.as_url_str())
140
+ share_url_path.write_text(res.as_url_str(), encoding="utf-8")
140
141
  console.print(Panel(f"šŸ”— SHARE URL GENERATED\nšŸ“ URL file: {share_url_path}\nšŸŒ {res.as_url_str()}", title="[bold blue]Share[/bold blue]", border_style="blue", width=152))
141
- else:
142
+ else:
142
143
  console.print(Panel(f"āŒ ERROR: Cloud '{cloud}' not found in source or target", title="[bold red]Error[/bold red]", border_style="red", width=152))
143
144
  raise ValueError(f"Cloud `{cloud}` not found in source or target.")
144
145
 
@@ -28,13 +28,15 @@ def get_rclone_config():
28
28
  def get_mprocs_mount_txt(cloud: str, rclone_cmd: str, cloud_brand: str): # cloud_brand = config[cloud]["type"]
29
29
  header = f"{' ' + cloud + ' | ' + cloud_brand + ' '}".center(50, "=")
30
30
  if platform.system() == "Windows":
31
- sub_text_path = PathExtended.tmpfile(suffix=".ps1").write_text(f"""
31
+ sub_text_path = PathExtended.tmpfile(suffix=".ps1")
32
+ sub_text_path.parent.mkdir(parents=True, exist_ok=True)
33
+ sub_text_path.write_text(f"""
32
34
  echo "{header}"
33
35
  iex 'rclone about {cloud}:'
34
36
  echo 'See {DEFAULT_MOUNT}/{cloud} for the mounted cloud'
35
37
 
36
38
  echo ''
37
- """)
39
+ """, encoding="utf-8")
38
40
  txt = f"""
39
41
  cd ~
40
42
  mprocs "powershell {sub_text_path}" "{rclone_cmd}" "btm" "timeout 2 & cd {DEFAULT_MOUNT} & lf" "timeout 2 & cd {DEFAULT_MOUNT} & pwsh" "pwsh" --names "info,service,monitor,explorer,main,terminal"
@@ -49,7 +51,7 @@ def mount(cloud: Optional[str], network: Optional[str], destination: Optional[st
49
51
  # draw header box dynamically
50
52
  title = "ā˜ļø Cloud Mount Utility"
51
53
  console.print(Panel(title, title_align="left", border_style="blue"))
52
-
54
+
53
55
  config = get_rclone_config()
54
56
  if cloud is None:
55
57
  res = choose_one_option(msg="which cloud", options=config.sections(), header="CLOUD MOUNT", default=None)
@@ -62,7 +64,7 @@ def mount(cloud: Optional[str], network: Optional[str], destination: Optional[st
62
64
  mount_loc = PathExtended(DEFAULT_MOUNT).expanduser().joinpath(cloud)
63
65
  else:
64
66
  mount_loc = PathExtended(destination)
65
-
67
+
66
68
  mount_info = f"šŸ“‚ Mount location: {mount_loc}"
67
69
  console.print(Panel(mount_info, border_style="blue"))
68
70
 
@@ -81,7 +83,7 @@ def mount(cloud: Optional[str], network: Optional[str], destination: Optional[st
81
83
  pass
82
84
  else: raise ValueError("unsupported platform")
83
85
 
84
- elif network and platform.system() == "Windows":
86
+ elif network and platform.system() == "Windows":
85
87
  mount_loc = "X: --network-mode"
86
88
  print(f"šŸ”Œ Setting up network mount at {mount_loc}")
87
89
  else: raise ValueError("network mount only supported on windows")
@@ -130,7 +132,7 @@ zellij action move-focus up
130
132
  """
131
133
  else: raise ValueError("unsupported platform")
132
134
  # print(f"running command: \n{txt}")
133
- PROGRAM_PATH.write_text(txt)
135
+ PROGRAM_PATH.write_text(txt, encoding="utf-8")
134
136
  # draw success box dynamically
135
137
  title1 = "āœ… Cloud mount command prepared successfully"
136
138
  title2 = "šŸ”„ Running mount process..."
@@ -141,7 +143,7 @@ def main():
141
143
  # draw main title box dynamically
142
144
  main_title = "ā˜ļø RCLONE CLOUD MOUNT"
143
145
  console.print(Panel(main_title, title_align="left", border_style="blue"))
144
-
146
+
145
147
  parser = argparse.ArgumentParser(description='mount cloud')
146
148
  parser.add_argument('cloud', nargs='?', type=str, default=None, help='cloud to mount')
147
149
  parser.add_argument('destination', nargs='?', type=str, default=None, help='destination to mount')