agsekit 0.9.4__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 (41) hide show
  1. agsekit-0.9.4.data/data/share/agsekit/config-example.yaml +34 -0
  2. agsekit-0.9.4.dist-info/METADATA +264 -0
  3. agsekit-0.9.4.dist-info/RECORD +41 -0
  4. agsekit-0.9.4.dist-info/WHEEL +5 -0
  5. agsekit-0.9.4.dist-info/entry_points.txt +2 -0
  6. agsekit-0.9.4.dist-info/licenses/LICENSE +21 -0
  7. agsekit-0.9.4.dist-info/top_level.txt +1 -0
  8. agsekit_cli/__init__.py +7 -0
  9. agsekit_cli/agent_scripts/claude-code.sh +12 -0
  10. agsekit_cli/agent_scripts/codex-glibc.sh +212 -0
  11. agsekit_cli/agent_scripts/codex.sh +83 -0
  12. agsekit_cli/agent_scripts/proxychains_common.sh +105 -0
  13. agsekit_cli/agent_scripts/qwen.sh +83 -0
  14. agsekit_cli/agents.py +271 -0
  15. agsekit_cli/backup.py +294 -0
  16. agsekit_cli/cli.py +166 -0
  17. agsekit_cli/commands/__init__.py +15 -0
  18. agsekit_cli/commands/backup_once.py +31 -0
  19. agsekit_cli/commands/backup_repeated.py +148 -0
  20. agsekit_cli/commands/config_example.py +42 -0
  21. agsekit_cli/commands/config_gen.py +210 -0
  22. agsekit_cli/commands/create_vm.py +83 -0
  23. agsekit_cli/commands/destroy_vm.py +112 -0
  24. agsekit_cli/commands/install_agents.py +208 -0
  25. agsekit_cli/commands/mounts.py +122 -0
  26. agsekit_cli/commands/portforward.py +141 -0
  27. agsekit_cli/commands/prepare.py +260 -0
  28. agsekit_cli/commands/run.py +171 -0
  29. agsekit_cli/commands/shell.py +72 -0
  30. agsekit_cli/commands/ssh.py +119 -0
  31. agsekit_cli/commands/start_vm.py +83 -0
  32. agsekit_cli/commands/stop.py +78 -0
  33. agsekit_cli/commands/systemd.py +108 -0
  34. agsekit_cli/config.py +370 -0
  35. agsekit_cli/i18n.py +67 -0
  36. agsekit_cli/interactive.py +487 -0
  37. agsekit_cli/locales/en.json +344 -0
  38. agsekit_cli/locales/ru.json +344 -0
  39. agsekit_cli/mounts.py +60 -0
  40. agsekit_cli/run_with_proxychains.sh +47 -0
  41. agsekit_cli/vm.py +405 -0
@@ -0,0 +1,34 @@
1
+ vms: # параметры виртуальных машин (можно иметь несколько)
2
+ agent-ubuntu: # имя виртуальной машины
3
+ cpu: 2 # количество vCPU
4
+ ram: 4G # объём оперативной памяти
5
+ disk: 20G # размер диска
6
+ proxychains: "" # укажите адрес прокси (scheme://host:port) — agsekit сам создаст временный proxychains.conf и обернёт команды Multipass
7
+ cloud-init: {} # здесь можно разместить стандартный конфиг cloud-init, но он не обязателен
8
+ port-forwarding: # проброс портов через multipass shell при запуске агента и установке
9
+ - type: remote
10
+ host-addr: 127.0.0.1:80
11
+ vm-addr: 127.0.0.1:8080
12
+ - type: local
13
+ host-addr: 0.0.0.0:15432
14
+ vm-addr: 127.0.0.1:5432
15
+ - type: socks5
16
+ vm-addr: 127.0.0.1:8088
17
+ mounts:
18
+ - source: /host/path/project # путь к исходной папке на хосте
19
+ target: /home/ubuntu/project # точка монтирования внутри ВМ; если не указана, будет /home/ubuntu/<имя_папки_source>
20
+ backup: /host/backups/project # каталог для бэкапов; если не указан, будет backups-<имя_папки> рядом с source
21
+ interval: 5 # интервал бэкапа в минутах; по умолчанию 5
22
+ vm: agent-ubuntu # имя VM, если не указан - берётся первая VM из конфигурации
23
+ agents:
24
+ qwen: # имя агента, можно добавить столько, сколько нужно
25
+ type: qwen # тип агента: qwen (используется бинарник qwen), codex, codex-glibc (бинарник codex-glibc) или claude-code
26
+ env: # произвольные переменные окружения, которые будут переданы агенту
27
+ OPENAI_API_KEY: "my_local_key"
28
+ OPENAI_BASE_URL: "https://127.0.0.1:11556/v1"
29
+ OPENAI_MODEL: "Qwen/Qwen3-Coder-30B-A3B-Instruct-FP8"
30
+ default-args: # аргументы, которые будут переданы агенту при запуске, если пользователь не указал их сам
31
+ - "--openai-api-key=my_local_key"
32
+ - "--openai-base-url=https://127.0.0.1:11556/v1"
33
+ socks5_proxy: 10.0.0.2:1234 # если нужно, трафик агента пойдет через этот socks5-прокси посредством proxychains
34
+ vm: qwen-ubuntu # ВМ по умолчанию для запуска агента; если не указана, используется ВМ из монтирования или первая в списке
@@ -0,0 +1,264 @@
1
+ Metadata-Version: 2.4
2
+ Name: agsekit
3
+ Version: 0.9.4
4
+ Summary: Agent Safety Kit command-line utilities
5
+ Author-email: Mihanentalpo <mihanentalpo@yandex.ru>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2025 Mihanentalpo
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Requires-Python: >=3.9
29
+ Description-Content-Type: text/markdown
30
+ License-File: LICENSE
31
+ Requires-Dist: click<9,>=8.1
32
+ Requires-Dist: PyYAML<7,>=6.0
33
+ Requires-Dist: questionary<3,>=2.0
34
+ Dynamic: license-file
35
+
36
+ [README.md на русском](README-ru.md)
37
+
38
+ # Agent Safety Kit
39
+
40
+ A toolkit for running AI agents in an isolated environment inside a Multipass virtual machine.
41
+
42
+ ## Why this matters
43
+
44
+ <img width="437" height="379" alt="image" src="https://github.com/user-attachments/assets/c3486072-e96a-4197-8b1f-d6ac228c2cc6" />
45
+
46
+ Some stories (you can find plenty more):
47
+
48
+ * [Qwen Coder agent destroys working builds](https://github.com/QwenLM/qwen-code/issues/354)
49
+ * [Codex keeps deleting unrelated and uncommitted files! even ignoring rejected requests](https://github.com/openai/codex/issues/4969)
50
+ * [comment: qwen-code CLI destroyed my entire project, deleted important files](https://www.reddit.com/r/DeepSeek/comments/1mmfjsl/right_now_qwen_is_the_best_model_they_have_the/)
51
+ * [Claude Code deleted my entire workspace, here's the proof](https://www.reddit.com/r/ClaudeAI/comments/1m299f5/claude_code_deleted_my_entire_workspace_heres_the/)
52
+ * [I Asked Claude Code to Fix All Bugs, and It Deleted the Whole Repo](https://levelup.gitconnected.com/i-asked-claude-code-to-fix-all-bugs-and-it-deleted-the-whole-repo-e7f24f5390c5)
53
+ * [Codex has twice deleted and corrupted my files (r/ClaudeAI comment)](https://www.reddit.com/r/ClaudeAI/comments/1nhvyu0/openai_drops_gpt5_codex_cli_right_after/)
54
+
55
+ Everyone says "you should have backups" and "everything must live in git", but console AI agents still lack built-in snapshots to roll back after every change they make. Until sandboxes catch up, this toolkit helps you manage that yourself.
56
+
57
+ ## Key ideas
58
+
59
+ - Agents run only inside a virtual machine.
60
+ - The VM is launched via Multipass (a simple Canonical tool to start Ubuntu VMs with a single command).
61
+ - Project folders from the host are mounted into the VM; an automatic backup job runs in parallel to a sibling directory at a configurable interval (defaults to every five minutes and only when changes are detected), using `rsync` with hardlinks to save space.
62
+ - VM, mount, and cloud-init settings are stored in a YAML config.
63
+ - You can run the agent without entering the guest via `multipass shell`—it still executes inside the VM.
64
+ - Multipass commands and agent runs can be wrapped in proxychains: set a proxy URL per VM or override it once with `--proxychains` to generate a temporary proxychains config automatically.
65
+
66
+ ## Working agents
67
+
68
+ Currently confirmed working agent types are:
69
+
70
+ - qwen
71
+ - codex
72
+ - codex-glibc (built dynamically)
73
+
74
+ ## Quick start
75
+
76
+ 1. Install the package with pip (requires Python 3.9 or newer):
77
+ ```bash
78
+ python3 -m venv ./venv
79
+ source ./venv/bin/activate
80
+ pip install agsekit
81
+ ```
82
+ This makes the `agsekit` command available inside the virtual environment.
83
+
84
+ 2. Alternatively, clone the repository and install from sources:
85
+ ```bash
86
+ git clone https://github.com/MihanEntalpo/agent-safety-kit/
87
+ cd agent-safety-kit
88
+ pip install .
89
+ ```
90
+
91
+ 3. Create a YAML configuration (the CLI checks `--config`, then `CONFIG_PATH`, then `~/.config/agsekit/config.yaml`):
92
+ ```bash
93
+ agsekit config-example
94
+ # edit vms/mounts/cloud-init to your needs
95
+ ```
96
+ When working from a cloned repository, you can also copy the file directly:
97
+ ```bash
98
+ mkdir -p ~/.config/agsekit
99
+ cp config-example.yaml ~/.config/agsekit/config.yaml
100
+ ```
101
+ You can also run `agsekit config-gen` to answer a few questions and save the config (defaults to `~/.config/agsekit/config.yaml`; use `--overwrite` to replace an existing file).
102
+
103
+ 4. Install required system dependencies (in particular, Multipass; requires sudo and currently works only on Debian-based systems):
104
+ ```bash
105
+ agsekit prepare
106
+ ```
107
+
108
+ 5. Create the virtual machines defined in YAML:
109
+ ```bash
110
+ agsekit create-vms
111
+ ```
112
+
113
+ To launch just one VM, use `agsekit create-vm <name>`. If the config contains only one VM, you can omit `<name>` and it will be used automatically. If a VM already exists, the command compares the desired resources with the current ones and reports any differences. Changing resources of an existing VM is not supported yet.
114
+
115
+ 6. Mount your folders (assuming mounts are already configured in the YAML file):
116
+ ```bash
117
+ agsekit mount --all
118
+ ```
119
+
120
+ 7. Install all configured agents into their default VMs:
121
+ ```bash
122
+ agsekit install-agents --all-agents
123
+ ```
124
+
125
+ 8. Launch an agent inside its VM (example runs `qwen` in the folder where `/host/path/project` is mounted, with backups enabled by default):
126
+ ```bash
127
+ agsekit run qwen /host/path/project --vm agent-ubuntu
128
+ ```
129
+ On the very first run with backups enabled, the CLI creates an initial snapshot with progress output before launching the agent, so wait for it to complete.
130
+
131
+ ## agsekit commands
132
+
133
+ ### Setup and VM lifecycle
134
+
135
+ * `agsekit prepare` — installs required system dependencies (including Multipass; requires sudo and currently works only on Debian-based systems).
136
+ * `agsekit config-gen [--config <path>] [--overwrite]` — interactive wizard that asks about VMs, mounts, and agents, then writes a YAML config to the chosen path (defaults to `~/.config/agsekit/config.yaml`). Without `--overwrite`, the command warns if the file already exists.
137
+ * `agsekit config-example [<path>]` — copies `config-example.yaml` to the target path (defaults to `~/.config/agsekit/config.yaml`). If the default config already exists, the command skips copying.
138
+ * `agsekit create-vms` — creates every VM defined in the YAML configuration.
139
+ * `agsekit create-vm <name>` — launches just one VM. If the config contains only one VM, you can omit `<name>` and it will be used automatically. If a VM already exists, the command compares the desired resources with the current ones and reports any differences. Changing resources of an existing VM is not supported yet.
140
+ * `agsekit shell [<vm_name>] [--config <path>]` — opens an interactive `multipass shell` session inside the chosen VM, applying any configured port forwarding. If only
141
+ one VM is defined in the config, the CLI connects there even without `vm_name`. When multiple VMs exist and the command runs in
142
+ a TTY, the CLI prompts you to pick one; in non-interactive mode, an explicit `vm_name` is required.
143
+ * `agsekit ssh <vm_name> [--config <path>] [<ssh_args...>]` — connects to the VM over SSH using `~/.config/agsekit/ssh/id_rsa` and forwards any extra arguments directly to the `ssh` command (for example, `-L`, `-R`, `-N`).
144
+ * `agsekit portforward [--config <path>]` — starts a dedicated `agsekit ssh` tunnel for each VM that defines `port-forwarding` rules, monitoring the child processes and restarting them if they exit. Stop with Ctrl+C to gracefully terminate the tunnels.
145
+ * `agsekit start-vm <vm_name> [--config <path>]` — starts the specified VM from the configuration. If only one VM is configured, the name can be omitted.
146
+ * `agsekit start-vm --all-vms [--config <path>]` — starts every VM declared in the config file.
147
+ * `agsekit stop-vm <vm_name> [--config <path>]` — stops the specified VM from the configuration. If only one VM is configured, the name can be omitted.
148
+ * `agsekit stop-vm --all-vms [--config <path>]` — stops every VM declared in the config file.
149
+ * `agsekit destroy-vm <vm_name> [--config <path>] [-y]` — deletes the specified VM from Multipass. Without `-y`, the CLI asks for interactive confirmation.
150
+ * `agsekit destroy-vm --all [--config <path>] [-y]` — deletes every VM from the configuration, with the same confirmation requirement.
151
+ * `agsekit systemd install [--config <path>]` — writes `~/.config/agsekit/systemd.env` with absolute paths to `agsekit`, the config, and the current project directory, then registers and starts the user unit from `systemd/agsekit-portforward.service` via `systemctl --user` (link, daemon-reload, start, enable).
152
+ * `agsekit systemd uninstall` — stops and disables the user unit, then removes the linked `systemd/agsekit-portforward.service` from systemd via `systemctl --user`.
153
+
154
+ ### Mount management
155
+
156
+ * `agsekit mount --source-dir <path> [--config <path>]` — mounts the directory described by `source` in the configuration file (default search: `--config`, `CONFIG_PATH`, `~/.config/agsekit/config.yaml`) into its VM using `multipass mount`. Use `--all` to mount every entry from the config. When there is only one mount in the config, the command can be run without `--source-dir` or `--all`.
157
+ * `agsekit umount --source-dir <path> [--config <path>]` — unmounts the directory described by `source` in the config (or `CONFIG_PATH`/`--config`); `--all` unmounts every configured path. If only one mount is configured, the command will unmount it even without explicit flags.
158
+
159
+ ### Backups
160
+
161
+ #### One-off backup
162
+
163
+ `agsekit backup-once --source-dir <path> --dest-dir <path> [--exclude <pattern> ...] [--progress]` — runs a single backup of the source directory into the specified destination using `rsync`.
164
+ The command creates a timestamped directory with a `-partial` suffix, supports incremental copies via `--link-dest` to the previous backup, and honors exclusions from `.backupignore` and `--exclude` arguments. When finished, the temporary folder is renamed to a final timestamp without the suffix. If nothing changed relative to the last backup, no new snapshot is created and the tool reports the absence of updates.
165
+ Pass `--progress` to forward rsync progress flags and show a console progress bar while files are copied.
166
+
167
+ `.backupignore` examples:
168
+ ```
169
+ # exclude virtual environments and dependencies
170
+ venv/
171
+ node_modules/
172
+
173
+ # ignore temporary and log files by pattern
174
+ *.log
175
+ *.tmp
176
+
177
+ # include a specific file inside an excluded folder
178
+ !logs/important.log
179
+
180
+ # skip documentation build artifacts
181
+ docs/build/
182
+ ```
183
+
184
+ Backups use `rsync` with incremental links (`--link-dest`) to the previous copy: if only a small set of files changed, the new snapshot stores just the updated data, while unchanged files are hardlinked to the prior snapshot. This keeps a chain of dated directories while consuming minimal space when changes are rare.
185
+
186
+ #### Repeated backups
187
+
188
+ * `agsekit backup-repeated --source-dir <path> --dest-dir <path> [--exclude <pattern> ...] [--interval <minutes>] [--skip-first]` — runs an immediate backup and then repeats it every `interval` minutes (defaults to five minutes). With `--skip-first`, the loop waits for the first interval before performing the initial run. After each backup it prints `Done, waiting N minutes` with the actual interval value.
189
+ * `agsekit backup-repeated-mount --mount <path> [--config <path>]` — looks up the mount by its `source` path in the configuration file (default search: `--config`, `CONFIG_PATH`, `~/.config/agsekit/config.yaml`) and launches repeated backups using the paths and interval from the config. When only one mount is present, `--mount` can be omitted; with multiple mounts, an explicit choice is required.
190
+ * `agsekit backup-repeated-all [--config <path>]` — reads all mounts from the config (default search: `--config`, `CONFIG_PATH`, `~/.config/agsekit/config.yaml`) and starts concurrent repeated backups for each entry within a single process. Use Ctrl+C to stop the loops.
191
+
192
+ ### Agent installation
193
+
194
+ * `agsekit install-agents <agent_name> [<vm>|--all-vms] [--config <path>] [--proxychains <value>]` — runs the prepared installation script for the chosen agent type inside the specified VM (or the agent's default VM if none is provided). If the config defines only one agent, you can skip `<agent_name>` and it will be picked automatically. Use `--proxychains <scheme://host:port>` to override the VM proxy for this installation or `--proxychains ""` to ignore it once.
195
+ * `agsekit install-agents --all-agents [--all-vms] [--config <path>] [--proxychains <value>]` — installs every configured agent either into their default VM or into every VM when `--all-vms` is set.
196
+
197
+ The installation scripts live in `agsekit_cli/agent_scripts/`: `codex` installs the npm CLI, `codex-glibc` builds the Rust sources with the glibc target and installs the binary as `codex-glibc`, and `qwen`/`claude-code` follow their upstream steps (the `qwen` script installs the qwen-code CLI). Other agent types are not supported yet.
198
+
199
+ ### Running agents
200
+
201
+ * `agsekit run <agent_name> [<source_dir>|--vm <vm_name>] [--config <path>] [--proxychains <value>] [--disable-backups] [--skip-default-args] [--debug] -- <agent_args...>` — starts an interactive agent command inside Multipass. Environment variables from the config are passed to the process. If a `source_dir` from the mounts list is provided, the agent starts inside the mounted target path in the matching VM; otherwise it launches in the home directory of the default VM. Unless `--disable-backups` is set, background repeated backups for the selected mount are started for the duration of the run. When no backups exist yet, the CLI first creates an initial snapshot with progress output before launching the agent and then starts the repeated loop with the initial run skipped. Arguments from `agents.<name>.default-args` are added unless `--skip-default-args` is set; if the user already passed an option with the same name (for example `--openai-api-key`), the default value is skipped. With `--debug`, the CLI prints every external command before executing it to help troubleshoot agent launches. Use `--proxychains <scheme://host:port>` to override the VM setting for one run; pass an empty string to disable it temporarily.
202
+
203
+ ### Interactive mode
204
+
205
+ In a TTY you don’t have to type full commands every time: the CLI can guide you through an interactive menu that fills in parameters for you.
206
+
207
+ * Run `agsekit` without arguments to open the interactive menu, choose a command, and select options such as the config path, mounts, or agent parameters.
208
+ * Start a command without mandatory arguments (for example, `agsekit run`) to automatically fall back to the interactive flow after the CLI prints a “not enough parameters” hint. Use `--non-interactive` if you prefer the usual help output instead of prompts.
209
+
210
+ ## Localization
211
+
212
+ The CLI reads the system locale and falls back to English if it cannot detect a supported language. You can override this behavior with the `AGSEKIT_LANG` environment variable:
213
+
214
+ ```bash
215
+ AGSEKIT_LANG=ru agsekit --help
216
+ ```
217
+
218
+ ## YAML configuration
219
+
220
+ The configuration file (looked up via `--config`, `CONFIG_PATH`, or `~/.config/agsekit/config.yaml`) describes VM parameters, mounted directories, and any `cloud-init` settings. A base example lives in `config-example.yaml`:
221
+
222
+ ```yaml
223
+ vms: # VM parameters for Multipass (you can define multiple)
224
+ agent-ubuntu: # VM name
225
+ cpu: 2 # number of vCPUs
226
+ ram: 4G # RAM size (supports 2G, 4096M, etc.)
227
+ disk: 20G # disk size
228
+ proxychains: "" # optional proxy URL (scheme://host:port); agsekit writes a temporary proxychains.conf and wraps Multipass commands automatically
229
+ cloud-init: {} # place your standard cloud-init config here if needed
230
+ port-forwarding: # Port forwarding config
231
+ - type: remote # Open port inside VM and pass connections to Host machine's port
232
+ host-addr: 127.0.0.1:80
233
+ vm-addr: 127.0.0.1:8080
234
+ - type: local # Open port on Host machine, and pass connections to VM's port
235
+ host-addr: 0.0.0.0:15432
236
+ vm-addr: 127.0.0.1:5432
237
+ - type: socks5 # Open socks5-proxy port inside VM, directing traffic to Host machine's network
238
+ vm-addr: 127.0.0.1:8088
239
+ mounts:
240
+ - source: /host/path/project # path to the source folder on the host
241
+ target: /home/ubuntu/project # mount point inside the VM; defaults to /home/ubuntu/<source_basename>
242
+ backup: /host/backups/project # backup directory; defaults to backups-<source_basename> next to source
243
+ interval: 5 # backup interval in minutes; defaults to 5 if omitted
244
+ vm: agent-ubuntu # VM name; defaults to the first VM in the configuration
245
+ agents:
246
+ qwen: # agent name; add as many as you need
247
+ type: qwen # agent type: qwen (installs and uses the `qwen` binary), codex, codex-glibc (installs the `codex-glibc` binary), or claude-code (other types are not supported yet)
248
+ env: # arbitrary environment variables passed to the agent process
249
+ OPENAI_API_KEY: "my_local_key"
250
+ OPENAI_BASE_URL: "https://127.0.0.1:11556/v1"
251
+ OPENAI_MODEL: "Qwen/Qwen3-Coder-30B-A3B-Instruct-FP8"
252
+ default-args: # arguments passed to the agent unless the user overrides them
253
+ - "--openai-api-key=my_local_key"
254
+ - "--openai-base-url=https://127.0.0.1:11556/v1"
255
+ vm: qwen-ubuntu # default VM for this agent; falls back to the mount VM or the first VM in the list
256
+ codex:
257
+ type: codex
258
+ claude:
259
+ type: claude-code
260
+ codex2:
261
+ type: codex-glibc
262
+ ```
263
+
264
+ > **Note:** Prefer ASCII-only paths for both `source` and `target` mount points: AppArmor may refuse to mount directories whose paths contain non-ASCII characters.
@@ -0,0 +1,41 @@
1
+ agsekit-0.9.4.data/data/share/agsekit/config-example.yaml,sha256=lLmwBZMt73DWRZvLnbotXf-_xRZvkIFqOkqq_Cg3fEg,2930
2
+ agsekit-0.9.4.dist-info/licenses/LICENSE,sha256=pnZSO0USEZMgsTY7AT3cpFEGf6oXuttYjaqRDCbFfgE,1069
3
+ agsekit_cli/__init__.py,sha256=mCdVHm86jUsPqY47wFYottJeymbJOYHs3YEUPJWVC-M,104
4
+ agsekit_cli/agents.py,sha256=1j_dkmHhVrSSS0iSiHVPbmrtDTlLjAV2_2udwR3iY5M,9377
5
+ agsekit_cli/backup.py,sha256=EiaiB7DctfZMZ9s6BDGVIEfMI9ar1iQokb7Pz87YINk,9444
6
+ agsekit_cli/cli.py,sha256=6ZNoNCYh2RmZ343990xpUii2Z5izIN6Za4Zuk1HeMdE,5207
7
+ agsekit_cli/config.py,sha256=-y0FGrTDJcerhQL0xHblcDl_NmcIHAR4QYmDgx-ysDk,12562
8
+ agsekit_cli/i18n.py,sha256=y1jOnsRwkKBz79ZVL5tf0Kk4TaPUQESo9nIglkVpMvU,2011
9
+ agsekit_cli/interactive.py,sha256=99EsXlapPnYQ8vci9VUQKIDljh1QumTNFtiLpCqGbFI,17243
10
+ agsekit_cli/mounts.py,sha256=lMRmznFpW0ljGUCMyp5PElGvWGhTVIba2bEwXKJWAZM,2099
11
+ agsekit_cli/run_with_proxychains.sh,sha256=slX55xLkDWLV08jBmp-C8OW_93oJ8eAnR5QLBF7p-zQ,837
12
+ agsekit_cli/vm.py,sha256=fIFKyQXG2uhaAdO--CSbdCYrj4xBVWJRv9nwwDU4eXI,13255
13
+ agsekit_cli/agent_scripts/claude-code.sh,sha256=mG6KkWqZQ9L2TH0hPHPl6yFY8jjmLMz4iNcyHlhUdWY,325
14
+ agsekit_cli/agent_scripts/codex-glibc.sh,sha256=mcC5CECTB2sGfC8emaumeXMmdRO-38VZlXxg_stM_48,6364
15
+ agsekit_cli/agent_scripts/codex.sh,sha256=p6Uf9YGIFy2pb_hoEUdwa_KjR2gDLoLmwjOzLO7cDAQ,2469
16
+ agsekit_cli/agent_scripts/proxychains_common.sh,sha256=FCwLrP0myL2RchaVMLGemLGrRC5t12umGd7vx6D7aS0,2638
17
+ agsekit_cli/agent_scripts/qwen.sh,sha256=n4Anj8CgNqxDjsKg4EBBm4yT6b2nLp0YB4fuYxVHEtM,2463
18
+ agsekit_cli/commands/__init__.py,sha256=ZVo_Y6jwAec2M9WVSYSJG7XcpW4prAsN3lhmcnhwgew,269
19
+ agsekit_cli/commands/backup_once.py,sha256=nPpfj40Qwl6gb_Xm3vXJr6hDtbtkFhHa9GodSdpouxs,1224
20
+ agsekit_cli/commands/backup_repeated.py,sha256=4bWaCgS0QUdl2NMmUH4Au3Ro0t-07vX82QddgortALI,4939
21
+ agsekit_cli/commands/config_example.py,sha256=GZVFIachUVr3tzLRPqQqi6C8rbI0UVwWWdYt8WkcX3g,1436
22
+ agsekit_cli/commands/config_gen.py,sha256=yPyuJNfW6uc_RwwzUIs7PjOlHq2sdAdmwJ9kQwutvbU,6873
23
+ agsekit_cli/commands/create_vm.py,sha256=Tha1h1Agw0iirdIjGdPlB62taEholULLnl8cd3iFktY,2808
24
+ agsekit_cli/commands/destroy_vm.py,sha256=KFOB8pNS0HOERyeNB6dO-cSm3N2CAOTdNjsSsFnwXfY,3870
25
+ agsekit_cli/commands/install_agents.py,sha256=-ZYznJqLK9UptTFhUHXwChAlxB8_YkRkhBgNmP_9oSk,7907
26
+ agsekit_cli/commands/mounts.py,sha256=56sBJQf8VZTjMvy6x6exUsGVj5jlxpNN-VzKp1E1bdc,4109
27
+ agsekit_cli/commands/portforward.py,sha256=EdJunlZOAlMMEHRLODuaWcU4Gd7LVBi1w3z5NOC3n-Q,4333
28
+ agsekit_cli/commands/prepare.py,sha256=NllYmbNm4G5KMefFg8-ighp9Mm8hd6jMX49EkxKzqZY,9256
29
+ agsekit_cli/commands/run.py,sha256=Wy-QPIOAC22sQeXmwSidNHCXVrrLZzSpnb1idftpJ_c,5623
30
+ agsekit_cli/commands/shell.py,sha256=_VB94EuPMbQ93sEeo89Q6Zb5Eu8lKXHjFlGDc4NuGYU,2334
31
+ agsekit_cli/commands/ssh.py,sha256=pYQlFcTWkUovAEVJV3W-UTiOLkhwaQX8g6LOOraur_I,3672
32
+ agsekit_cli/commands/start_vm.py,sha256=jqGDWYzeqfdBuTYzt6Lss8tGaSymI2r90lq033St3MA,2719
33
+ agsekit_cli/commands/stop.py,sha256=FqsFEJXWvgkxoFXjybiqfAONRaYhyvvEGJK9whnzGiE,2693
34
+ agsekit_cli/commands/systemd.py,sha256=YpOvhSWsh-s8S2BpT19IlvhMxkQw9qqBhrU5Y5i2Ydc,3935
35
+ agsekit_cli/locales/en.json,sha256=g3t4fUAy_UKB7OKnchOaL2OXatB74BkLGZwIhGWlb-g,26632
36
+ agsekit_cli/locales/ru.json,sha256=zGpQ35RPiAlBjfg5jZ96Zj6FwuxL7c4am65QWXikK2k,36535
37
+ agsekit-0.9.4.dist-info/METADATA,sha256=FrXzyLTliHf0-rwM7V666w0l4PYdojQFPksx0JEJ488,18432
38
+ agsekit-0.9.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
39
+ agsekit-0.9.4.dist-info/entry_points.txt,sha256=7DEDCsqtJhUtqqYhY64NhimWs-5paT-i28GRbYXUGJc,49
40
+ agsekit-0.9.4.dist-info/top_level.txt,sha256=djDyVGoLJs_ypRel9LAc3wHcB-7oJTrt7cOI12CcXA8,12
41
+ agsekit-0.9.4.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ agsekit = agsekit_cli.cli:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Mihanentalpo
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 @@
1
+ agsekit_cli
@@ -0,0 +1,7 @@
1
+ """Agent Safety Kit command-line utilities."""
2
+
3
+ __all__ = [
4
+ "__version__",
5
+ ]
6
+
7
+ __version__ = "0.5.0"
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ # shellcheck disable=SC1091
6
+ . "$SCRIPT_DIR/proxychains_common.sh"
7
+
8
+ PROXYCHAINS_PROXY="${AGSEKIT_PROXYCHAINS_PROXY:-}"
9
+
10
+ echo "Installing Claude Code agent..."
11
+
12
+ run_with_proxychains curl -fsSL https://claude.ai/install.sh | bash
@@ -0,0 +1,212 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ # shellcheck disable=SC1091
6
+ . "$SCRIPT_DIR/proxychains_common.sh"
7
+
8
+ PROXYCHAINS_PROXY="${AGSEKIT_PROXYCHAINS_PROXY:-}"
9
+ SWAP_FILE=""
10
+ SWAP_CREATED=0
11
+ BUILD_ROOT=""
12
+ INSTALL_SUCCESS=0
13
+ INSTALLED_CODEX_PATH=""
14
+
15
+
16
+ run_privileged() {
17
+ if command -v sudo >/dev/null 2>&1 && [ "$(id -u)" -ne 0 ]; then
18
+ sudo "$@"
19
+ else
20
+ "$@"
21
+ fi
22
+ }
23
+
24
+ cleanup_swap() {
25
+ if [ "$SWAP_CREATED" -eq 1 ] && [ -n "${SWAP_FILE:-}" ]; then
26
+ echo "отключаю и удаляю временный swap-файл ${SWAP_FILE}"
27
+ run_privileged swapoff "$SWAP_FILE" 2>/dev/null || true
28
+ run_privileged rm -f "$SWAP_FILE"
29
+ SWAP_CREATED=0
30
+ SWAP_FILE=""
31
+ fi
32
+ }
33
+
34
+ cleanup() {
35
+ cleanup_swap
36
+ if [ -n "${BUILD_ROOT:-}" ]; then
37
+ if [ -n "$INSTALLED_CODEX_PATH" ] && [ -x "$INSTALLED_CODEX_PATH" ]; then
38
+ if "$INSTALLED_CODEX_PATH" --version >/dev/null 2>&1; then
39
+ rm -rf "$BUILD_ROOT"
40
+ else
41
+ echo "codex-glibc is unavailable or not runnable, keeping build directory at ${BUILD_ROOT}"
42
+ fi
43
+ else
44
+ echo "codex-glibc is unavailable or not runnable, keeping build directory at ${BUILD_ROOT}"
45
+ fi
46
+ fi
47
+ }
48
+
49
+ ensure_swap_for_build() {
50
+ local min_free_kb mem_available_kb swap_free_kb total_free_kb needed_kb swap_bytes swap_mb
51
+ min_free_kb=$((3 * 1024 * 1024))
52
+ mem_available_kb="$(awk '/MemAvailable:/ {print $2}' /proc/meminfo)"
53
+ swap_free_kb="$(awk '/SwapFree:/ {print $2}' /proc/meminfo)"
54
+ mem_available_kb="${mem_available_kb:-0}"
55
+ swap_free_kb="${swap_free_kb:-0}"
56
+ total_free_kb=$((mem_available_kb + swap_free_kb))
57
+
58
+ if [ "$total_free_kb" -ge "$min_free_kb" ]; then
59
+ echo "Checking available RAM: there is enough RAM to build codex-glibc."
60
+ return
61
+ fi
62
+
63
+ needed_kb=$((min_free_kb - total_free_kb))
64
+ swap_bytes=$((needed_kb * 1024))
65
+ swap_mb=$(((needed_kb + 1023) / 1024))
66
+
67
+ echo "Not enough RAM to build codex-glibc, creating a swap file."
68
+
69
+ if command -v sudo >/dev/null 2>&1 && [ "$(id -u)" -ne 0 ]; then
70
+ SWAP_FILE="$(sudo mktemp --tmpdir=/ codex-glibc-swap-XXXXXX)"
71
+ else
72
+ SWAP_FILE="$(mktemp --tmpdir=/ codex-glibc-swap-XXXXXX)"
73
+ fi
74
+
75
+ if command -v fallocate >/dev/null 2>&1; then
76
+ run_privileged fallocate -l "$swap_bytes" "$SWAP_FILE"
77
+ else
78
+ run_privileged dd if=/dev/zero of="$SWAP_FILE" bs=1M count="$swap_mb" status=none
79
+ fi
80
+
81
+ run_privileged chmod 600 "$SWAP_FILE"
82
+ run_privileged mkswap "$SWAP_FILE" >/dev/null
83
+ run_privileged swapon "$SWAP_FILE"
84
+ SWAP_CREATED=1
85
+ }
86
+
87
+ trap cleanup EXIT INT TERM
88
+
89
+ echo "Building Codex agent with glibc toolchain..."
90
+
91
+ ensure_swap_for_build
92
+
93
+ sudo apt-get update -y
94
+ sudo apt-get install -y build-essential pkg-config libssl-dev curl git
95
+
96
+ if ! command -v rustup >/dev/null 2>&1; then
97
+ echo "Installing Rust toolchain via rustup..."
98
+ RUSTUP_INSTALLER="$(mktemp -t rustup-init-XXXXXX.sh)"
99
+ echo "Downloading rustup installer to $RUSTUP_INSTALLER ..."
100
+ run_with_proxychains curl --proto '=https' --tlsv1.2 -fL https://sh.rustup.rs -o "$RUSTUP_INSTALLER"
101
+ echo "Running rustup installer in batch mode (-y)..."
102
+ export RUSTUP_INIT_SKIP_PATH_CHECK=yes
103
+ ( set -x; sh "$RUSTUP_INSTALLER" -y --no-modify-path )
104
+ rm -f "$RUSTUP_INSTALLER"
105
+ echo "Rustup installation finished."
106
+ fi
107
+
108
+ if [ -f "$HOME/.cargo/env" ]; then
109
+ # shellcheck disable=SC1090
110
+ . "$HOME/.cargo/env"
111
+ fi
112
+
113
+ if ! command -v cargo >/dev/null 2>&1; then
114
+ echo "Cargo is unavailable after rustup installation. Please check your Rust setup."
115
+ exit 1
116
+ fi
117
+
118
+ HOST_TARGET="$(rustc -Vv | awk '/host:/ {print $2}')"
119
+ if [ -z "$HOST_TARGET" ]; then
120
+ ARCH="$(uname -m)"
121
+ HOST_TARGET="${ARCH}-unknown-linux-gnu"
122
+ fi
123
+
124
+ run_with_proxychains rustup target add "$HOST_TARGET"
125
+
126
+ BUILD_ROOT="$(mktemp -d -t codex-src-XXXXXX)"
127
+
128
+ echo "Cloning codex repository..."
129
+ run_with_proxychains git clone --depth 1 https://github.com/openai/codex.git "$BUILD_ROOT/codex"
130
+
131
+ MANIFEST_PATH="$(
132
+ python3 - "$BUILD_ROOT/codex" <<'PYCODE'
133
+ import pathlib
134
+ import sys
135
+ import tomllib
136
+
137
+ root = pathlib.Path(sys.argv[1])
138
+ candidates = []
139
+
140
+ for path in root.rglob("Cargo.toml"):
141
+ try:
142
+ data = tomllib.loads(path.read_text(encoding="utf-8"))
143
+ except Exception:
144
+ continue
145
+
146
+ pkg_name = data.get("package", {}).get("name")
147
+ bins = data.get("bin", []) or []
148
+ has_codex_bin = any(isinstance(item, dict) and item.get("name") == "codex" for item in bins)
149
+ score = 0
150
+ if pkg_name == "codex-cli":
151
+ score = 3
152
+ elif has_codex_bin:
153
+ score = 2
154
+ elif pkg_name == "codex":
155
+ score = 1
156
+
157
+ if score:
158
+ candidates.append((score, len(path.parts), str(path)))
159
+
160
+ if not candidates:
161
+ sys.exit(0)
162
+
163
+ best = sorted(candidates, key=lambda item: (-item[0], item[1]))[0]
164
+ print(best[2])
165
+ PYCODE
166
+ )"
167
+
168
+ if [ -z "$MANIFEST_PATH" ]; then
169
+ echo "Unable to locate Cargo.toml for codex build."
170
+ exit 1
171
+ fi
172
+
173
+ echo "Compiling codex for target ${HOST_TARGET}..."
174
+ echo "Using Cargo manifest at ${MANIFEST_PATH}."
175
+ CARGO_CACHE_ROOT="${HOME}/.tmp/build-codex-glibc"
176
+ export CARGO_TARGET_DIR="${CARGO_CACHE_ROOT}/target"
177
+ mkdir -p "$CARGO_TARGET_DIR"
178
+ export CARGO_BUILD_JOBS=1
179
+ export CARGO_PROFILE_RELEASE_LTO=off
180
+ export CARGO_PROFILE_RELEASE_CODEGEN_UNITS=1
181
+ export CARGO_PROFILE_RELEASE_DEBUG=false
182
+ run_with_proxychains cargo build --release --target "$HOST_TARGET" --manifest-path "$MANIFEST_PATH"
183
+ cleanup_swap
184
+
185
+ BUILT_BINARY="$CARGO_TARGET_DIR/$HOST_TARGET/release/codex"
186
+ if [ ! -x "$BUILT_BINARY" ]; then
187
+ echo "Expected binary not found at $BUILT_BINARY"
188
+ exit 1
189
+ fi
190
+
191
+ DEST_PATH="/usr/local/bin/codex-glibc"
192
+ if command -v sudo >/dev/null 2>&1 && sudo -n true >/dev/null 2>&1; then
193
+ sudo install -m 0755 "$BUILT_BINARY" "$DEST_PATH"
194
+ echo "Installed codex-glibc to $DEST_PATH using sudo."
195
+ INSTALLED_CODEX_PATH="$DEST_PATH"
196
+ else
197
+ mkdir -p "$HOME/.local/bin"
198
+ install -m 0755 "$BUILT_BINARY" "$HOME/.local/bin/codex-glibc"
199
+ DEST_PATH="$HOME/.local/bin/codex-glibc"
200
+ INSTALLED_CODEX_PATH="$DEST_PATH"
201
+ if ! grep -q 'export PATH="$HOME/.local/bin:$PATH"' "$HOME/.profile" 2>/dev/null; then
202
+ echo 'export PATH="$HOME/.local/bin:$PATH"' >> "$HOME/.profile"
203
+ echo "Added $HOME/.local/bin to PATH in ~/.profile."
204
+ fi
205
+ echo "Installed codex-glibc to $DEST_PATH."
206
+ fi
207
+
208
+ if "$INSTALLED_CODEX_PATH" --version >/dev/null 2>&1; then
209
+ INSTALL_SUCCESS=1
210
+ else
211
+ echo "codex-glibc is unavailable or not runnable after installation."
212
+ fi