Full Code of ai/environment for AI

main 902886f2b8a4 cached
66 files
77.6 KB
25.0k tokens
1 requests
Download .txt
Repository: ai/environment
Branch: main
Commit: 902886f2b8a4
Files: 66
Total size: 77.6 KB

Directory structure:
gitextract_8apgxoyr/

├── .editorconfig
├── .gitignore
├── .oxfmtrc.json
├── GNOME.md
├── Install.md
├── LICENSE
├── README.md
├── batconfig
├── bin/
│   ├── backup
│   ├── backup-gnome-extensions
│   ├── build-devcontainer
│   ├── clear
│   ├── clear-weather-city
│   ├── copy-env
│   ├── dev
│   ├── force-lock
│   ├── porn
│   ├── private
│   ├── restore-gnome-extensions
│   ├── susedko
│   ├── susedko-listener
│   ├── update
│   ├── update-devcontainer-configs
│   ├── update-dockerfile
│   ├── update-extension-lists
│   ├── zed-isolate
│   └── zoom
├── devcontainer/
│   ├── Dockerfile
│   ├── devcontainer.json
│   └── install-dotfiles
├── gitconfig
├── gitignore
├── hooks-trap/
│   ├── applypatch-msg
│   ├── commit-msg
│   ├── post-applypatch
│   ├── post-checkout
│   ├── post-commit
│   ├── post-merge
│   ├── post-rewrite
│   ├── pre-applypatch
│   ├── pre-auto-gc
│   ├── pre-commit
│   ├── pre-merge-commit
│   ├── pre-push
│   ├── pre-rebase
│   └── prepare-commit-msg
├── icons/
│   ├── Zoom.desktop
│   ├── backup.desktop
│   ├── com.mattjakeman.ExtensionManager.desktop
│   ├── com.nextcloud.desktopclient.nextcloud.desktop
│   ├── hu.irl.cameractrls.desktop
│   ├── porn.desktop
│   ├── private.desktop
│   ├── update.desktop
│   └── zed-isolate.desktop
├── micro.json
├── mimeapps.list
├── mpv-input.conf
├── mpv.conf
├── pnpm-config.yaml
├── ripgreprc
├── sshconfig
├── starship.toml
├── zed-keys.json
├── zed.json
└── zshrc

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[micro.json]
indent_size = 4


================================================
FILE: .gitignore
================================================
secrets.env


================================================
FILE: .oxfmtrc.json
================================================
{
  "arrowParens": "avoid",
  "jsxSingleQuote": false,
  "quoteProps": "consistent",
  "semi": false,
  "singleQuote": true,
  "sortImports": {
    "groups": [
      "side_effect",
      "side_effect_style",
      "style",
      ["builtin", "external", "unknown"],
      ["internal", "parent", "sibling", "index"]
    ],
    "newlinesBetween": true,
    "order": "asc"
  },
  "trailingComma": "none",
  "printWidth": 80
}


================================================
FILE: GNOME.md
================================================
## GNOME Shell Extensions

- [All-in-One Clipboard](https://extensions.gnome.org/extension/8671/all-in-one-clipboard/)
- [Alphabetical App Grid](https://extensions.gnome.org/extension/4269/alphabetical-app-grid/)
- [App Hider](https://extensions.gnome.org/extension/5895/app-hider/)
- [Auto Power Profile](https://extensions.gnome.org/extension/6583/auto-power-profile/)
- [Autohide Battery](https://extensions.gnome.org/extension/595/autohide-battery/)
- [Battery Health Charging](https://extensions.gnome.org/extension/5724/battery-health-charging/)
- [Battery Power Mode Indicator](https://extensions.gnome.org/extension/9204/battery-power-mode-indicator/)
- [Battery time](https://extensions.gnome.org/extension/5425/battery-time/)
- [Battery Usage Wattmeter](https://extensions.gnome.org/extension/6278/battery-usage-wattmeter/)
- [Bluetooth Battery Monitor](https://extensions.gnome.org/extension/9308/bluetooth-battery-monitor/)
- [Blur my Shell](https://extensions.gnome.org/extension/3193/blur-my-shell/)
- [Dim Completed Calendar Events](https://extensions.gnome.org/extension/5979/dim-completed-calendar-events/)
- [Do Not Disturb While Screen Sharing Or Recording](https://extensions.gnome.org/extension/5985/do-not-disturb-while-screen-sharing-or-recording/)
- [Double Click Activities to App Grid](https://extensions.gnome.org/extension/9339/double-click-activities-to-app-grid/)
- [Dynamic Calendar, Clocks and Weather Icons ](https://extensions.gnome.org/extension/8640/dynamic-calendar-clocks-and-weather-icons-reborn/)
- [Dynamic Music Pill](https://extensions.gnome.org/extension/9334/dynamic-music-pill/)
- [Folder Search Provider](https://extensions.gnome.org/extension/8227/folder-search-provider/)
- [Forge](https://extensions.gnome.org/extension/4481/forge/)
- [Gnome 4x UI Improvements](https://extensions.gnome.org/extension/4158/gnome-40-ui-improvements/)
- [GSConnect](https://extensions.gnome.org/extension/1319/gsconnect/)
- [Hide Keyboard Layout](https://extensions.gnome.org/extension/2848/hide-keyboard-layout/)
- [Home Assistant Extension](https://extensions.gnome.org/extension/4170/home-assistant-extension/)
- [Launch New Instance](https://extensions.gnome.org/extension/600/launch-new-instance/)
- [Night Theme Switcher](https://extensions.gnome.org/extension/2236/night-theme-switcher/)
- [Quick Settings Tweaks](https://extensions.gnome.org/extension/5446/quick-settings-tweaker/)
- [Right Click Next](https://extensions.gnome.org/extension/7600/right-click-next/)
- [Screenshot OCR](https://extensions.gnome.org/extension/9338/screenshot-ocr/)
- [Top Panel Workspace Scroll](https://extensions.gnome.org/extension/701/top-panel-workspace-scroll/)
- [Tweaks & Extensions in System Menu](https://extensions.gnome.org/extension/1653/tweaks-in-system-menu/)
- [Weather O'Clock](https://extensions.gnome.org/extension/5470/weather-oclock/)


================================================
FILE: Install.md
================================================
## How I install my system

### Preparing

Download [Fedora image](https://getfedora.org/ru/workstation/)
and write it to the USB drive:

```sh
flatpak install flathub io.gitlab.adhami3310.Impression
```

Copy `.ssh` and `.local/share/gnupg` into `Документы/.Private`.

Clean `node_modules`:

```sh
rm -R ~/Dev/*/node_modules ~/Dev/*/*/node_modules ~/Dev/*/coverage ~/Dev/susedko/fedora-coreos.iso
```

Copy these files to external SDD:

- `Dev/`
- `Vídeos/*`
- `Документы/.Private/`

### BIOS

1. Boot to BIOS and set supervisor password.
2. Set Game Optimized iGPU.
3. Temporary enable USB boot.

### Install

Start installer:

1. Select English language.
2. Use entire disk mode with encryption.

Reboot to USB drive again. Mount laptop SSD.

Open `etc/fstab`.

Add `noatime,nodiratime` to root & home partitions.

Move `/tmp` and `/var/tmp` to RAM:

```
vartmp /var/tmp tmpfs defaults,noatime,nodiratime 0 0
vartmp /tmp     tmpfs defaults,noatime,nodiratime 0 0
```

Reboot to BIOS. Block boot from USB.

Reboot to system. Set Russian language, name to `Andrey Sitnik` and login `ai`.

Set laptop name:

```sh
sudo hostnamectl set-hostname savoia
```

Reboot.

Copy `Dev/` and `Документы/.Private/` from external SDD and open `Install.md` locally.

Reduce swap usage by creating `/etc/sysctl.d/99-swappiness.conf` with:

```
vm.swappiness = 10
```

Fix booting video glitch:

```sh
sudo grubby --update-kernel=ALL --args="plymouth.use-simpledrm=0"
```

Enable `Rendimiento`, disable `Ahorro de energía automático`,
`Suspender automaticámente` in Energía settings.

### System Update

Set `KEYMAP=us` and `XKBLAYOUT=us` in `/etc/vconsole.conf`.

Remove unnecessary packages:

```sh
sudo dnf remove cheese rhythmbox gnome-boxesd orca gnome-contacts gnome-getting-started-docs nautilus-sendto gnome-shell-extension-* libreoffice-* gnome-characters gnome-maps gnome-photos simple-scan virtualbox-guest-additions gedit gnome-boxes gnome-tour gnome-connections mediawriter eog gnome-system-monitor baobab gnome-log gnome-calculator gnome-weather gnome-text-editor gnome-font-viewer gnome-clocks gnome-calendar evince totem ffmpeg-free snapshot intel-media-driver cups-browsed anaconda malcontent-control loupe
```

Run Software Center, disable `Fedora Flatpak` and enable Flathub and Chrome.

Add RPM Fusion (for codecs) and Terra (for Zed):

```sh
sudo dnf install --nogpgcheck http://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm http://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm
sudo dnf install --nogpgcheck --repofrompath 'terra,https://repos.fyralabs.com/terra$releasever' terra-release
```

Update system via Software Center.

Install software:

```sh
sudo dnf swap ffmpeg-free ffmpeg --allowerasing
sudo dnf swap mesa-va-drivers mesa-va-drivers-freeworld
sudo dnf swap mesa-vdpau-drivers mesa-vdpau-drivers-freeworld
sudo dnf copr enable atim/starship
sudo dnf copr enable dusansimic/themes
sudo dnf copr enable hyperreal/better_fonts
sudo dnf install xclip micro fuse-encfs zenity borgbackup openssl ffmpegthumbnailer nss-tools mosquitto ydotool amrnb amrwb faac faad2 flac gstreamer1-libav gstreamer1-plugins-bad-freeworld gstreamer-ffmpeg gstreamer-plugins-bad-nonfree gstreamer-plugins-espeak gstreamer-plugins-ugly lame libdca libmad libmatroska x264 x265 xvidcore gstreamer1-plugins-bad-free gstreamer1-plugins-base gstreamer1-plugins-good gstreamer-plugins-bad gstreamer1-plugins-ugly-free mpv ffmpeg xorg-x11-drv-intel intel-media-driver webp-pixbuf-loader heif-pixbuf-loader avif-pixbuf-loader libheif-freeworld ffmpeg-libs libva libva-utils gstreamer1-vaapi mozilla-openh264 libheif-tools unrar p7zip p7zip-plugins speech-dispatcher speech-dispatcher-utils google-chrome-stable nodejs podman git tig ripgrep xkill bat make difftastic nextcloud-client zsh util-linux-user starship sqlite  morewaita-icon-theme nethogs fuse-sshfs logiops libgda libgda-sqlite playerctl cabextract xorg-x11-font-utils tesseract tesseract-devel zed
sudo rpm -ivh --nodigest --nofiledigest https://downloads.sourceforge.net/project/mscorefonts2/rpms/msttcore-fonts-installer-2.6-1.noarch.rpm
```

Set Flatpak languages:

```sh
flatpak config languages --set "es;en;ru"
sudo flatpak update
```

Install applications from Flatpak:

```sh
flatpak install flathub de.haeckerfelix.Fragments org.telegram.desktop org.nickvision.tubeconverter org.gnome.Loupe com.mattjakeman.ExtensionManager io.gitlab.adhami3310.Converter net.nokyan.Resources org.gnome.Calculator org.gnome.Logs org.gnome.Weather org.gnome.clocks org.gnome.Calendar org.gnome.Epiphany org.inkscape.Inkscape org.gnome.gitlab.YaLTeR.VideoTrimmer org.gnome.World.Iotas app.devsuite.Ptyxis hu.irl.cameractrls org.gnome.Snapshot org.gnome.Papers org.gimp.GIMP be.alexandervanhee.gradia com.github.PintaProject.Pinta com.yubico.yubioath org.gnome.font-viewer
```

Install [Zoom](https://zoom.us/download).

Remove default GNOME console.

Set `Ctrl + C` and `Ctrl + V` for copy/paste in new terminal settings.

Fix unnecessary folder creation in Zoom:

```sh
flatpak override --user us.zoom.Zoom --nofilesystem=~/Documents/Zoom
mkdir -p ~/.local/share/flatpak/exports/share/applications/
cp /var/lib/flatpak/exports/share/applications/us.zoom.Zoom.desktop ~/.local/share/flatpak/exports/share/applications/
```

Replace `Exec` to `/home/ai/Dev/environment/bin/zoom @@u %U @@` in `~/.local/share/flatpak/exports/share/applications/us.zoom.Zoom.desktop`.

Add Autostart and fingers to user settings.

Disable Software auto-update and notifications.

Set [color profile](https://www.notebookcheck.net/uploads/tx_nbc2/BOE0CB4.icm)
in `Color` settings.

Install `micro` and its plugins:

```sh
micro -plugin install editorconfig
sudo dnf remove nano
```

Disable waking up by mouse by creating `/etc/udev/rules.d/logitech-bolt.rules`:

```sh
ACTION=="add", SUBSYSTEM=="usb", DRIVERS=="usb", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c548", ATTR{power/wakeup}="disabled"
```

Disable file system scanning:

```sh
dconf write /org/freedesktop/tracker/miner/files/crawling-interval -2
```

### Personal Files

Copy `.ssh` and `.local/share/gnupg`:

```sh
~/Dev/environment/bin/private
```

Change permissions:

```sh
chmod 744 ~/.ssh
chmod 700 ~/.local/share/gnupg/
chmod 644 ~/.ssh/* ~/.local/share/gnupg/*
chmod 700 ~/.local/share/gnupg/private-keys-v1.d
chmod 600 ~/.ssh/id_* ~/.local/share/gnupg/private-keys-v1.d/*
```

Copy configs:

```sh
~/Dev/environment/bin/copy-env system
```

## Input

Set mouse buttons config at `/etc/logid.cfg`:

```
devices: ({
  name: "MX Master 3S";

  smartshift: { on: false; }

  hiresscroll: { hires: false; invert: false; target: false; };

  buttons: (
    {
      cid: 0x53;  # Back
      action = {
        type: "Keypress";
        keys: ["KEY_LEFTCTRL", "KEY_V"];
      };
    },
    {
      cid: 0x56;  # Forward
      action = {
        type: "Keypress";
        keys: ["KEY_LEFTCTRL", "KEY_C"];
      };
    }
  );
});
```

Add `-c /etc/logid.cfg` to `Exec` field of `/usr/lib/systemd/system/logid.service`.

Enable mouse extensions:

```sh
sudo systemctl enable --now logid
```

Install custom universal keyboard layouts:

```sh
mkdir -p ~/.config/xkb/symbols/ ~/.config/xkb/rules/
wget -O ~/.config/xkb/symbols/universal_en https://raw.githubusercontent.com/ai/universal-layout/main/universal_en.xkb
wget -O ~/.config/xkb/symbols/universal_ru https://raw.githubusercontent.com/ai/universal-layout/main/universal_ru.xkb
wget -O ~/.config/xkb/rules/evdev.xml https://raw.githubusercontent.com/ai/universal-layout/main/evdev.xml
```

Set keyboard settings:

```sh
dconf write /org/gnome/desktop/input-sources/xkb-options "['grp_led:caps', 'lv3:ralt_switch', 'grp:shift_caps_switch']"
```

### Terminal

Install eza:

```sh
curl -sL https://github.com/eza-community/eza/releases/latest/download/eza_x86_64-unknown-linux-gnu.tar.gz | tar xz
chmod +x eza
mkdir -p ~/.local/bin/
mv eza ~/.local/bin
```

Install atuin:

```sh
curl -sL https://github.com/atuinsh/atuin/releases/download/v18.6.1/atuin-x86_64-unknown-linux-gnu.tar.gz | tar xz --strip-components=1 atuin-x86_64-unknown-linux-gnu/atuin
mv atuin ~/.local/bin
```

Install zsh:

```sh
mkdir -p ~/.local/share/history
chmod 700 ~/.local/share/history
git clone https://github.com/zsh-users/zsh-syntax-highlighting ~/.local/lib/zsh/zsh-syntax-highlighting
git clone https://github.com/zsh-users/zsh-autosuggestions ~/.local/lib/zsh/zsh-autosuggestions
git clone https://github.com/jimhester/per-directory-history ~/.local/lib/zsh/per-directory-history
chsh -s /bin/zsh
```

Create `/root/.zshrc`:

```sh
eval "$(starship init zsh)"
```

Reboot.

Select `Russian Universal` and `English/Spanish/Catalan Universal` layouts.

```sh
rm ~/.bash*
```

Open backup and copy files from it.

```sh
mkdir ~/backup
borg mount "ai@susedko.local:/var/mnt/vault/ai/backup" ~/backup
```

Copy files.

```sh
borg umount ~/backup
rmdir ~/backup
```

Start copying `Vídeos/*` from SDD.

### Text Editors

Move Claude Code:

```bash
mkdir -p ~/.config/environment.d/
mkdir -p ~/.local/share/claude
echo "GNUPGHOME=$HOME/.local/share/gnupg" >> ~/.config/environment.d/90-clean-home.conf
echo "NODE_COMPILE_CACHE=$HOME/.cache/node" >> ~/.config/environment.d/90-clean-home.conf
echo "NPM_CONFIG_USERCONFIG=$HOME/.config/npmrc" >> ~/.config/environment.d/90-clean-home.conf
echo "CLAUDE_CONFIG_DIR=$HOME/.local/share/claude" >> ~/.config/environment.d/90-clean-home.conf
```

Sign-in into accounts in Zed.

Install Zed plugins: `ini`, `dockerfile`, `toml`, `svelte`, `make`, `adwaita-pastel`, `material icon theme`, `codebook`, `sql`, `nginx`, `git-firefly`, `pug`, `xml`, `po`, `env`, `oxc`.

Open Iotas app, log-in into Nextcloud account.

### GNOME Settings

Open Clock and add `Vladivostok`, `Moscow`, `Lisbon`, and `San Francisco`.

Run Weather app and set current location.

Install [Lilex](https://lilex.myrt.co).

```sh
mkdir -p ~/.local/share/fonts
# Copy variable fonts
fc-cache -f -v
gsettings set org.gnome.desktop.interface monospace-font-name "Lilex 12"
```

Open settings:

- **Appearance:** use standard GNOME wallpaper.
- **Notifications:** disable Notifications on lock screen.
- **Search:** keep only Calculator and Settings.
- **Multitask:** disable Active corners.
- **Online accounts:** add Google.
- **Power:** enable Show percentage and disable screen lock.
- **Mouse:** mouse speed to 75%, touchpad speed to 90%.
- **Date and time:** enable seconds and week day on top panel.
- **Privacy** → disable File History.

Boost volume over 100%:

```sh
gsettings set org.gnome.desktop.sound allow-volume-above-100-percent true
```

Login to NextCloud client to `sync.sitnik.es`.

Nautilus:

- Enable Sort folders before files.
- Enable Single click to open items.
- Enable preview, search, file numbers for remote folders.

Disable GNOME extension version check:

```sh
gsettings set org.gnome.shell disable-extension-version-validation true
```

Download the latest [`framework_tool`](https://github.com/FrameworkComputer/framework-system/actions?query=branch%3Amain), extract and copy to the system:

```sh
sudo cp ~/Descargas/framework_tool /usr/local/bin
```

Install tool for clipboard manager:

```bash
mkdir -p ~/.local/share/copyous@boerdereinar.dev/
curl https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/es/highlight.min.js > ~/.local/share/copyous@boerdereinar.dev/highlight.min.js
```

Install extensions from [`GNOME.md`](./GNOME.md).

Restore settings file from backup:

```sh
~/Dev/environment/bin/restore-gnome-extensions
```

Clean up applications list.

Add Iceland NordVPN.

[Disable](https://discussion.fedoraproject.org/t/please-enter-passphrase-for-disk-has-returned/150626/5) disk name in password prompt.

### Folders

Create empty file template:

```sh
mkdir ~/.local/share/desktop
mkdir ~/.local/share/templates
touch ~/.local/share/templates/Пустой\ файл
```

Fix folders at `~/.config/user-dirs.dirs`:

```sh
XDG_DESKTOP_DIR="$HOME/.local/share/desktop"
XDG_DOWNLOAD_DIR="$HOME/Загрузки"
XDG_TEMPLATES_DIR="$HOME/.local/share/templates"
XDG_PUBLICSHARE_DIR="$HOME/.local/share/desktop"
XDG_DOCUMENTS_DIR="$HOME/Документы"
XDG_MUSIC_DIR="$HOME"
XDG_PICTURES_DIR="$HOME"
XDG_VIDEOS_DIR="$HOME/Видео"
```

Clean bookmarks:

```sh
echo "" > ~/.config/gtk-3.0/bookmarks
```

Remove unnecessary folders:

```sh
mkdir "Снимки экрана"
```

Connect to server in Files by `sftp://ai@susedko.local/` and add `vault` to Favorites places. Add `Загрузки` and `Снимки экрана` to Favorites places.

Left only Telegram, Firefox, Nautilus, Terminal, Iotas, System Update, and
Backup in the dock.

Add icon theme:

```sh
gsettings set org.gnome.desktop.interface icon-theme 'MoreWaita'
```

Set icons:

- `/usr/share/icons/MoreWaita/scalable/places/folder-code.svg`
  for `~/Dev/`.
- `/usr/share/icons/Adwaita/scalable/places/folder-pictures.svg`
  for `~/Capturas de pantalla/`.

## Home Server

Add server’s certificate to the system:

```sh
mkdir -p ~/.pki/nssdb
certutil -N -d sql:$HOME/.pki/nssdb --empty-password
certutil -d sql:$HOME/.pki/nssdb -A -t "C,," -n sitnik -i ~/Dev/susedko/sitniks.crt
sudo cp ~/Dev/susedko/sitniks.crt /etc/pki/ca-trust/source/anchors/sitniks.pem
sudo update-ca-trust
```

Add service to `~/.config/systemd/user/force-lock.service`:

```ini
[Unit]
Description=Force Lock

[Service]
ExecStart=/home/ai/Dev/environment/bin/force-lock
Restart=on-failure
RestartSec=30s

[Install]
WantedBy=default.target
```

Add service to `~/.config/systemd/user/susedko-listener.service`:

```ini
[Unit]
Description=Susedko Listener
After=network-online.target
Wants=network-online.target

[Service]
ExecStart=/home/ai/Dev/environment/bin/susedko-listener
Restart=on-failure
RestartSec=30s
StartLimitBurst=5

[Install]
WantedBy=default.target
```

Add service to `/etc/systemd/system/ydotoold.service`:

```ini
[Unit]
Description=ydotool Daemon

[Service]
ExecStart=ydotoold --socket-path="/run/.ydotool_socket" --socket-own="1000:1000"
Restart=on-failure
RestartSec=30s

[Install]
WantedBy=default.target
```

Enable services:

```sh
sudo systemctl enable ydotoold.service
sudo systemctl start ydotoold.service
systemctl --user enable susedko-listener.service force-lock.service
systemctl --user start susedko-listener.service force-lock.service
```

### Development Tools

Install Node.js, TypeScript, and Dev Containers.

```sh
npm config set cache "$HOME/.cache/npm"
mkdir -p ~/.local/lib/node/
tee -a ~/.local/lib/node/package.json << EOM
{
  "dependencies": {
    "@devcontainers/cli": ">=0.80.1"
  }
}
EOM
cd ~/.local/lib/node && npm install && cd

mkdir -p ~/.local/share/multiocular
mkdir -p ~/.local/share/history
chmod 700 ~/.local/share/history
podman volume create shell-history
podman volume create pnpm-store

~/Dev/environment/bin/build-devcontainer
cd ~/Dev/nanostores
devup
# Find container ID
podman exec -it --user root $container_id zsh
mkdir /home/ai/.local/share/pnpm/store/v11
chown ai:ai /home/ai/.local/share/pnpm/store/v11
chown ai:ai /home/ai/.local/share/history/histfile
```

Fix Dev Container with Podman in Zed:

```sh
sudo ln -s $(which podman) /usr/local/bin/docker
```

Install Keybase:

```sh
sudo dnf install https://prerelease.keybase.io/keybase_amd64.rpm
run_keybase
```

Disable autostart in Keybase settings and revoke old laptop.

## LanguageTool Server

Prepare [ngrams](https://languagetool.org/download/ngram-data/):

```sh
mkdir -p ~/.local/share/ngrams
cd ~/.local/share/ngrams
wget https://languagetool.org/download/ngram-data/ngrams-en-20150817.zip
wget https://languagetool.org/download/ngram-data/ngrams-es-20150915.zip
wget https://languagetool.org/download/ngram-data/untested/ngram-ru-20150914.zip
unzip ngrams-en-20150817.zip
unzip ngrams-es-20150915.zip
unzip ngram-ru-20150914.zip
rm ngram*.zip
```

```sh
mkdir -p ~/.config/systemd/user/
```

Create service unit `~/.config/systemd/user/languagetool.service`:

```ini
[Unit]
Description=LanguageTool Server

[Service]
ExecStart=podman run --rm --replace --name languagetool \
  -p 8081:8010 \
  -e langtool_languageModel=/ngrams \
  -e Java_Xms=512m -e Java_Xmx=2g \
  -v /home/ai/.local/share/fasttext:/fasttext:Z \
  -v /home/ai/.local/share/ngrams:/ngrams:Z \
  docker.io/erikvl87/languagetool:latest

[Install]
WantedBy=default.target
```

Install LanguageTool:

```sh
~/Dev/environment/bin/update-languagetool
```

Enable service.

```sh
systemctl --user daemon-reload
systemctl --user enable --now languagetool.service
systemctl --user start --now languagetool.service
```


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright 2013 Andrey Sitnik <andrey@sitnik.es>

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: README.md
================================================
My home configs, scripts and [installation process](./Install.md).

See also [my keyboard layout](https://github.com/ai/universal-layout).

### Configs

- [GNOME Shell extensions](./GNOME.md)
- [`.gitconfig`](./gitconfig)


================================================
FILE: batconfig
================================================
--plain


================================================
FILE: bin/backup
================================================
#!/bin/sh

TITLE='\033[0;32m\033[1m'
GRAY='\033[0;90m'
NC='\033[0m'

hour=$(date +"%H")
if [[ hour -lt 9 || hour -ge 22 ]]; then
  echo -e "${TITLE}Подготовка кровати ко сну${GRAY}"
  ~/Dev/environment/bin/susedko script/turn_on script.heat_bedroom
  echo -e "${NC}\n"
fi

echo -e "${TITLE}Сохранение расширений GNOME${GRAY}"
~/Dev/environment/bin/backup-gnome-extensions
echo -e "${NC}\n"

echo -e "${TITLE}Сохранение домашнего сервера${GRAY}"
cd ~/Dev/susedko
make ha_backup
cd
echo -e "${NC}\n"

echo -e "${TITLE}Сохранение файлов${GRAY}"
export BORG_REPO=ai@susedko.local:/var/mnt/vault/ai/backup
SERVICE_NAME="BorgBackup"
USERNAME="backup"
BORG_PASSPHRASE=$(secret-tool lookup service "BorgBackup" username "ai")
if [ -z "$BORG_PASSPHRASE" ]; then
  read -sp "Пароль от бэкапа: " BORG_PASSPHRASE
  echo "$BORG_PASSPHRASE" | secret-tool store --label="Password for backup" service "BorgBackup" username "ai"
fi
export BORG_PASSPHRASE
borg create                                                \
    --verbose                                              \
    --filter AME                                           \
    --list                                                 \
    --stats                                                \
    --show-rc                                              \
    --progress                                             \
    --compression lz4                                      \
    --exclude-caches                                       \
    --exclude '*.iso'                                      \
    --exclude '**/node_modules'                            \
    --exclude '**/.config/mozilla/**/lock'                 \
    --exclude '**/.config/mozilla/**/crashes'              \
    --exclude '**/.config/mozilla/**/bookmarkbackups'      \
    --exclude '**/.config/mozilla/**/datareporting/archived' \
    --exclude '**/.config/mozilla/**/weave/logs'           \
    --exclude '**/.config/mozilla/**/cache'                \
    --exclude '**/.config/mozilla/firefox/firefox-mpris'   \
    --exclude '**/.config/mozilla/firefox/Crash Reports'   \
    --exclude '**/.var/app/**/cache'                       \
    --exclude '**/.var/app/**/Cache'                       \
    --exclude '**/.var/app/**/media_cache'                 \
    --exclude '**/.var/app/**/temp_data'                   \
    --exclude '**/.var/app/**/cache_*'                     \
    --exclude '**/.var/app/org.gnome.Epiphany'             \
    --exclude '**/.var/app/org.inkscape.Inkscape'          \
    --exclude '**/.var/app/io.missioncenter.MissionCenter' \
    --exclude '**/.var/app/com.belmoussaoui.Decoder'       \
    --exclude '**/.var/app/us.zoom.Zoom/.zoom/data/Emojis' \
    --exclude '**/.ld.so'                                  \
    --exclude '**/*.log'                                   \
    --exclude '**/sitnik.es/dist'                          \
    ::'{hostname}-{now}'                                   \
    ~/Dev/susedko                                          \
    ~/Dev/environment                                      \
    ~/Dev/sitnik.es                                        \
    ~/.ssh                                                 \
    ~/.local/share/gnupg                                   \
    ~/Документы/.Private                                   \
    ~/.config/mozilla                                             \
    ~/.config/gsconnect                                    \
    ~/.local/share/gnome-shell-extensions-settings         \
    ~/.var/app
borg prune                         \
    --list                         \
    --show-rc                      \
    --keep-last 14
borg compact
unset BORG_PASSPHRASE
echo -e "${NC}\n"

echo -e "${TITLE}Синхронизация видео${GRAY}"
rsync -a --delete --progress \
  --no-perms --no-owner --no-group \
  /home/ai/Видео/Эротика/ ai@susedko.local:/var/mnt/vault/ai/Selected

exit ${global_exit}


================================================
FILE: bin/backup-gnome-extensions
================================================
#!/bin/bash

backup_dir="$HOME/.local/share/gnome-shell-extensions-settings"
rm -r "$backup_dir"
mkdir -p "$backup_dir"

extensions=$(gsettings get org.gnome.shell enabled-extensions | tr -d "[],'")

for extension in $extensions; do
  base_name=$(echo "$extension" | sed 's/@.*//')
  output_file="$backup_dir/${extension}.ini"
  settings=$(dconf dump "/org/gnome/shell/extensions/$base_name/")
  if [ -n "$settings" ]; then
    echo "$settings" > "$output_file"
    echo "Настройки $extension сохранены"
  fi
done


================================================
FILE: bin/build-devcontainer
================================================
#!/bin/bash

~/Dev/environment/bin/copy-env

podman build -t localhost/ai-opensource \
  -f /home/ai/Dev/environment/devcontainer/Dockerfile \
  /home/ai/Dev/environment


================================================
FILE: bin/clear
================================================
#!/bin/sh

echo "Было $(df -h / | tail -1 | awk '{print $4}')"
echo

podman rmi --all --force
pnpm store prune
yarn cache clean
npm cache clean -f
rm -Rf ~/.local/share/Trash/

echo
echo "Стало $(df -h / | tail -1 | awk '{print $4}')"


================================================
FILE: bin/clear-weather-city
================================================
#!/bin/sh

gsettings reset org.gnome.Weather locations


================================================
FILE: bin/copy-env
================================================
#!/bin/sh
# Copy config and scripts to or from repo

if [ "$1" == "system" ]; then
  rm ~/.local/share/applications/*.{desktop,svg} -f
  cp ~/Dev/environment/icons/* ~/.local/share/applications/
  mkdir -p ~/.config/bat/
  mkdir -p ~/.config/mpv/
  mkdir -p ~/.config/git/
  mkdir -p ~/.config/micro/
  mkdir -p ~/.config/zed/
  rm -f ~/.zshrc
  ln ~/Dev/environment/zshrc ~/.zshrc
  cp ~/Dev/environment/.oxfmtrc.json ~/.oxfmtrc.json
  cp ~/Dev/environment/zed.json ~/.config/zed/settings.json
  cp ~/Dev/environment/zed-keys.json ~/.config/zed/keymap.json
  cp ~/Dev/environment/mpv.conf ~/.config/mpv/mpv.conf
  cp ~/Dev/environment/ripgreprc ~/.config/ripgreprc
  cp ~/Dev/environment/sshconfig ~/.ssh/config
  cp ~/Dev/environment/batconfig ~/.config/bat/config
  cp ~/Dev/environment/gitconfig ~/.config/git/config
  cp ~/Dev/environment/gitignore ~/.config/git/ignore
  cp ~/Dev/environment/starship.toml ~/.config/starship.toml
  cp ~/Dev/environment/mimeapps.list ~/.config/mimeapps.list
  cp ~/Dev/environment/mpv-input.conf ~/.config/mpv/input.conf
  cp ~/Dev/environment/micro.json ~/.config/micro/settings.json
else
  rm ~/Dev/environment/icons/*.{svg,desktop} -f
  cp ~/.oxfmtrc.json ~/Dev/environment/.oxfmtrc.json
  cp ~/.ssh/config ~/Dev/environment/sshconfig
  cp ~/.config/ripgreprc ~/Dev/environment/ripgreprc
  cp ~/.config/git/config ~/Dev/environment/gitconfig
  cp ~/.config/git/ignore ~/Dev/environment/gitignore
  cp ~/.config/bat/config ~/Dev/environment/batconfig
  cp ~/.config/mpv/mpv.conf ~/Dev/environment/mpv.conf
  cp ~/.config/starship.toml ~/Dev/environment/starship.toml
  cp ~/.config/mpv/input.conf ~/Dev/environment/mpv-input.conf
  cp ~/.config/mimeapps.list ~/Dev/environment/mimeapps.list
  cp ~/.config/micro/settings.json ~/Dev/environment/micro.json
  cp ~/.local/share/applications/*.{svg,desktop} ~/Dev/environment/icons/
  cp ~/.config/zed/settings.json ~/Dev/environment/zed.json
  cp ~/.config/zed/keymap.json ~/Dev/environment/zed-keys.json
  rm ~/Dev/environment/icons/chrome-* -f
  rm ~/Dev/environment/icons/userapp-* -f
  rm ~/Dev/environment/icons/org.gnome.Shell.Extensions.* -f
  ~/Dev/environment/bin/update-extension-lists
fi


================================================
FILE: bin/dev
================================================
#!/bin/bash

set -e

function get_container_runtime() {
  if command -v podman &> /dev/null; then
    echo "podman"
  elif command -v docker &> /dev/null; then
    echo "docker"
  else
    echo "Error: Neither podman nor docker found" >&2
    return 1
  fi
}

function devcontainer_root() {
  local dir=$PWD
  while [ "$dir" != "/" ]; do
    if [[ -f "$dir/.devcontainer.json" ]] || [[ -d "$dir/.devcontainer" ]]; then
      echo $dir
      return
    fi
    dir=$(dirname "$dir")
  done
  echo "No .devcontainer.json or .devcontainer/ found" >&2
  return 1
}

function devcontainer_config() {
  if [[ -f "$1/.devcontainer/podman/devcontainer.json" ]]; then
    echo "$1/.devcontainer/podman/devcontainer.json"
  elif [[ -f "$1/.devcontainer/devcontainer.json" ]]; then
    echo "$1/.devcontainer/devcontainer.json"
  else
    echo "$1/.devcontainer.json"
  fi
}

function get_container_id() {
  local runtime=$(get_container_runtime)
  $runtime ps -q --filter label=devcontainer.local_folder=$root
}

function get_username() {
  local username=""
  if [ -f "$root/.devcontainer/Dockerfile" ]; then
    username=$(
      awk -v IGNORECASE=1 '/^\s*USER\s+/{u=$2} END{print u}' "$root/.devcontainer/Dockerfile"
    )
  fi
  echo "${username:-ai}"
}

if [ "$1" = "--isolate" ]; then
  cp ~/Dev/environment/devcontainer/devcontainer.json .devcontainer.json
  if [ -d .git ]; then
    sed -i '/devcontainer/d' .git/info/exclude
    echo '.devcontainer.json' >> .git/info/exclude
  fi
  exit
fi

root=$(devcontainer_root)
if [ "$root" = "" ]; then
  echo "No .devcontainer.json or .devcontainer/ found" >&2
  return 1
fi

if [ "$1" = "--up" ]; then
  runtime=$(get_container_runtime)
  devcontainer_args=(
    "--docker-path" "$runtime"
    "--mount" "type=bind,source=${SSH_AUTH_SOCK},target=/run/user/1000/gcr/ssh"
    "--dotfiles-repository" "https://github.com/ai/environment.git"
    "--dotfiles-install-command" "devcontainer/install-dotfiles"
    "--workspace-folder" "$root"
    "--config" "$(devcontainer_config $root)"
  )
  if [ -d /home/ai/.local/share/multiocular ]; then
    devcontainer_args+=(
      "--mount" "type=bind,source=/home/ai/.local/share/multiocular,target=/home/$(get_username)/.local/share/multiocular"
    )
  fi
  if [ -d /home/ai/.local/share/claude ]; then
    devcontainer_args+=(
      "--mount" "type=bind,source=/home/ai/.local/share/claude,target=/home/$(get_username)/.local/share/claude"
      "--mount" "type=bind,source=/home/ai/.local/share/claude,target=/home/$(get_username)/.claude"
    )
  fi
  if [ -d /home/ai/.local/share/zed ]; then
    devcontainer_args+=(
      "--mount" "type=bind,source=/home/ai/.local/share/zed,target=/home/$(get_username)/.local/share/zed"
      "--mount" "type=bind,source=/home/ai/.config/zed,target=/home/$(get_username)/.config/zed"
      "--mount" "type=bind,source=/home/ai/.local/share/zed_server,target=/home/$(get_username)/.zed_server"
    )
  fi
  devcontainer up "${devcontainer_args[@]}"

elif [ "$1" = "--down" ]; then
  runtime=$(get_container_runtime)
  container_id=$(get_container_id)
  if [ "$container_id" == "" ]; then
    echo "Container is not running"
  else
    $runtime kill $container_id
  fi

elif [ "$1" = "--rebuild" ]; then
  ~/Dev/environment/bin/dev --up
  container_id=$(~/Dev/environment/bin/dev --down)
  runtime=$(get_container_runtime)
  $runtime container rm $container_id
  search_pattern="vsc-$(basename "$root")-[0-9a-f]\+-uid"
  image_id=$($runtime image ls --format "{{.Repository}}:{{.Tag}}" | grep "$search_pattern" | awk '{print $1}')
  if [ "$image_id" != "" ]; then
    $runtime image rm --force $image_id
  fi
  ~/Dev/environment/bin/dev --up

elif [ "$1" = "--port" ]; then
  if [[ "$2" =~ ^[0-9]+$ ]]; then
    # $2 is a number, use it as port
    port="$2"
    shift 2
    args="$*"
  else
    # No port specified or $2 is not a number, generate random port
    while true; do
      port=$(shuf -i 1024-9999 -n 1)
      if ! ss -tuln | grep -q ":${port}\s"; then
        break
      fi
    done
    shift 1
    args="$* --port $port"
  fi

  runtime=$(get_container_runtime)
  container_args=(
    "--rm"
    "-w" "/workspaces/$(basename $root)"
    "-p" "${port}:${port}"
    "--mount" "type=bind,source=$root,target=/workspaces/$(basename $root)"
    "--security-opt" "label=disable"
    "--userns=keep-id"
    "--ulimit=host"
    "--cap-add=NET_RAW"
  )

  if [ -d "/home/ai/.local/share/multiocular" ]; then
    container_args+=(
      "--mount" "type=bind,source=/home/ai/.local/share/multiocular,target=/home/$(get_username)/.local/share/multiocular"
    )
  fi
  if [[ "$args" == pnpm\ multiocular* ]] && [ -f ~/Dev/multiocular/.env ]; then
    container_args+=("--env-file")
    container_args+=("/home/ai/Dev/multiocular/.env")
  fi

  $runtime run "${container_args[@]}" -it localhost/ai-opensource $args

else
  runtime=$(get_container_runtime)
  container_id=$(get_container_id)
  if [ "$container_id" == "" ]; then
    ~/Dev/environment/bin/dev --up
    container_id=$(get_container_id)
  fi
  subdir=""
  if [ "$PWD" != "$root" ]; then
    subdir="${PWD#$root/}"
  fi
  workdir="/workspaces/$(basename $root)/$subdir"
  if [ -z "$1" ]; then
    $runtime exec -w $workdir -it $container_id zsh
  else
    $runtime exec -w $workdir -it $container_id zsh -ic "$*"
  fi
fi


================================================
FILE: bin/force-lock
================================================
#!/bin/bash
IDLE_TIME=240000
LANG=en

log() { echo "$(date '+%H:%M:%S') $*"; }

while true; do
  CURRENT_IDLE=$(gdbus call --session \
    --dest org.gnome.Mutter.IdleMonitor \
    --object-path /org/gnome/Mutter/IdleMonitor/Core \
    --method org.gnome.Mutter.IdleMonitor.GetIdletime \
    | awk '{print $2}' | tr -d ',)')

  if [ "$CURRENT_IDLE" -ge "$IDLE_TIME" ]; then
    IS_ACTIVE=$(gdbus call --session \
      --dest org.gnome.ScreenSaver \
      --object-path /org/gnome/ScreenSaver \
      --method org.gnome.ScreenSaver.GetActive)

    if echo "$IS_ACTIVE" | grep -qPo "false"; then
      LOCK_DISABLED=""

      for player in $(playerctl --list-all); do
        URL=$(playerctl --player="$player" metadata xesam:url 2>/dev/null)
        IS_YOUTUBE=$(echo "$URL" | grep -q "youtube.com/watch" && echo true)
        STATUS=$(playerctl --player="$player" status 2>/dev/null)
        if [ "$IS_YOUTUBE" = "true" ] && [ "$STATUS" = "Playing" ]; then
          log "YouTube playing, skipping lock"
          LOCK_DISABLED="true"
          break
        fi
      done

      if pactl list sink-inputs | grep -qi "application\.name = \"mpv\""; then
        log "mpv playing, skipping lock"
        LOCK_DISABLED="true"
      fi

      if pactl list source-outputs | grep -q "Source Output #"; then
        log "Ongoing call, skipping lock"
        LOCK_DISABLED="true"
      fi

      if [ -z "$LOCK_DISABLED" ]; then
        log "Locking session"
        loginctl lock-session
      fi
    fi
  fi
  sleep 60
done


================================================
FILE: bin/porn
================================================
#!/bin/sh
# Run movies from specific category

if [[ "$1" == "--new" ]]; then
  mkdir -p ~/.susedko_new
  sshfs ai@susedko.local:/var/mnt/vault/ai/New/ ~/.susedko_new
  mpv --shuffle --fullscreen --playlist=<(
      find ~/.susedko_new -type f \
          ! -name '*.part' \
          ! -name '*.png' \
          ! -name '*.jpg' \
          ! -name '*.jpeg'
  )
  fusermount -u ~/.susedko_new
  rmdir ~/.susedko_new
else
  find /home/ai/Видео/Эротика -type f -print0 | tr '\0' '\n' | mpv --shuffle --fullscreen --playlist=-
fi


================================================
FILE: bin/private
================================================
#!/bin/sh
# Private encrypted folder

STORE=$HOME/Документы/.Private
LINK=$HOME/Private

if [ -e "$LINK" ]; then
  # Lock
  fusermount -u "$LINK"
  rm -R "$LINK"
else
  # Unlock
  mkdir "$LINK"
  encfs "$STORE" "$LINK" --extpass "zenity --password"
  nautilus "$LINK"
fi


================================================
FILE: bin/restore-gnome-extensions
================================================
#!/bin/bash

backup_dir="$HOME/.local/share/gnome-shell-extensions-settings"

if [ ! -d "$backup_dir" ]; then
  echo "Settings directory $backup_dir not found. Exiting."
  exit 1
fi

extensions=$(gsettings get org.gnome.shell enabled-extensions | tr -d "[],'")

for settings in "$backup_dir"/*.ini; do
  extension=$(basename "$settings" .ini)
  base_name=$(echo "$extension" | sed 's/@.*//')
  if [[ $extensions == *"$extension"* ]]; then
    dconf load "/org/gnome/shell/extensions/$base_name/" < "$settings"
    echo "Настройки $extension востановлены"
  else
    echo "Расширение $extension не установлено или не включено, пропускаем"
  fi
done


================================================
FILE: bin/susedko
================================================
#!/bin/bash

if nmcli -t -f TYPE,STATE device | grep -q "^ethernet:connected"; then
  home_ip=$(timeout 1 getent hosts home.local | awk '{ print $1 }')
  if [[ "$home_ip" == "192.168.50.125" ]]; then
    source ~/Dev/environment/secrets.env
    curl -s \
      -H "Authorization: Bearer $HA_TOKEN" \
      -H "Content-Type: application/json" \
      -d "{\"entity_id\": \"$2\"}" \
      "https://home.local/api/services/$1"
    echo ""
  fi
fi


================================================
FILE: bin/susedko-listener
================================================
#!/bin/bash

source ~/Dev/susedko/secrets.env
MQTT_BROKER="192.168.50.125"

mosquitto_sub -h "$MQTT_BROKER" -t ai_laptop -u home -P "$HOME_PASSWORD" | while read -r payload
do
  if nmcli -t -f TYPE,STATE device | grep -q "^ethernet:connected"; then
    case "$payload" in
      "LOCK")
        loginctl lock-session
        ;;
      "WAKE")
        was_locked=$(dbus-send --session --dest=org.gnome.Shell --print-reply /org/gnome/Shell org.gnome.Shell.GetScreenShieldLock)
        if echo "$lock_status" | grep -q "boolean true"; then
          YDOTOOL_SOCKET=/run/.ydotool_socket ydotool key 28:1 28:0
        fi
        ;;
      *)
        echo "Unknown command: $payload"
        ;;
    esac
  fi
done


================================================
FILE: bin/update
================================================
#!/bin/zsh

set -e

TITLE='\033[0;32m\033[1m'
GRAY='\033[0;90m'
NC='\033[0m'

echo -e "${TITLE}Обновление системы${NC}"
pkexec dnf update --refresh -y

echo -e "\n${TITLE}Обновление приложений из Flatpak${NC}"
flatpak update -y

echo -e "\n${TITLE}Обновление Dev Container${NC}"
cd ~/.local/lib/node
npm update
~/Dev/environment/bin/update-dockerfile

echo -e "\n${TITLE}Обновление темы Firefox${GRAY}"
cd ~/.config/mozilla/firefox/iesxdh6c.default-release/chrome/firefox-gnome-theme
git pull origin master

echo -e "\n${TITLE}Обновление расширений GNOME${GRAY}"
gdbus call --session --dest org.gnome.Shell.Extensions \
     --object-path /org/gnome/Shell/Extensions \
     --method org.gnome.Shell.Extensions.CheckForUpdates

echo -e "\n${TITLE}Готово${NC}"
read


================================================
FILE: bin/update-devcontainer-configs
================================================
#!/bin/bash

for dir in ~/Dev/*/; do
  target_file="${dir}.devcontainer.json"
  if [[ -f "$target_file" ]]; then
    if grep -q "localhost/ai-opensource" "$target_file"; then
      echo "Replaced in $dir"
      ~/Dev/environment/bin/dev --isolate
    fi
  fi
done
podman image rm --all --force


================================================
FILE: bin/update-dockerfile
================================================
#!/bin/zsh

DOCKERFILE_PATH="/home/ai/Dev/environment/devcontainer/Dockerfile"

latest_node=$(curl -s "https://nodejs.org/dist/index.json" | jq -r '.[0].version' | sed 's/v//')
latest_pnpm=$(curl -s "https://api.github.com/repos/pnpm/pnpm/releases/latest" | jq -r '.tag_name' | sed 's/v//')

current_node=$(grep -oP 'NODE_VERSION=\K[^ \\]+' "$DOCKERFILE_PATH")
current_pnpm=$(grep -oP 'PNPM_VERSION=\K[^ \\]+' "$DOCKERFILE_PATH")

update_needed=false

RED='\033[0;31m'
GREEN='\033[0;32m'
GRAY='\033[0;90m'
NC='\033[0m'

if [[ "$current_node" != "$latest_node" ]] && [[ -n "$latest_node" ]]; then
  echo -e "Обновление Node.js: ${RED}$current_node${NC} → ${GREEN}${latest_node}${NC}"
  sed -i "s/NODE_VERSION=$current_node/NODE_VERSION=$latest_node/" "$DOCKERFILE_PATH"
  update_needed=true
fi

if [[ "$current_pnpm" != "$latest_pnpm" ]] && [[ -n "$latest_pnpm" ]] && [[ "$latest_pnpm" != "null" ]]; then
  echo -e "Обновление pnpm: ${RED}$current_pnpm${NC} to ${GREEN}${latest_pnpm}${NC}"
  sed -i "s/PNPM_VERSION=$current_pnpm/PNPM_VERSION=$latest_pnpm/" "$DOCKERFILE_PATH"
  update_needed=true
fi

if [ "$update_needed" = true ]; then
  echo -e "Удаляем все старые образы"
  podman rmi --all --force
  echo -e "Перезапускаем LanguageTool"
  systemctl restart --user languagetool.service
  echo -e "${NC}Создаём новый базовый образ Dev Container${GRAY}"
  ~/Dev/environment/bin/build-devcontainer
else
  echo -e "${GRAY}Нет обновлений для Dev Container${NC}"
fi


================================================
FILE: bin/update-extension-lists
================================================
#!/usr/bin/env node

let { readFile, writeFile } = require('fs/promises')
let { join } = require('path')
let { promisify } = require('util')
let { exec } = require('child_process')

exec = promisify(exec)

function gray(str) {
  return `\x1b[90m${str}\x1b[39m`
}

async function updateGnome() {
  let listFile = join(__dirname, '..', 'GNOME.md')
  let [gnome, docs] = await Promise.all([
    exec(`gnome-extensions list`),
    readFile(listFile)
  ])
  let meta = await Promise.all(
    gnome.stdout
      .trim()
      .split('\n')
      .map(async name => exec(`LANG=en gnome-extensions show ${name}`))
  )
  let details = await Promise.all(
    meta
      .map(result => {
        let uuid = result.stdout.split('\n')[0]
        let enabled = result.stdout.includes('State: ACTIVE')
        let name = result.stdout.match(/Name: (.*)/)[1]
        let hasRepo = result.stdout.match(/URL: (.*)/)
        return { uuid, name, enabled, hasRepo }
      })
      .filter(({ enabled, hasRepo, name }) => {
        if (!hasRepo) {
          console.log(gray(`Игнорируем ${name}`))
        }
        return hasRepo
      })
      .map(async ({ name, uuid }) => {
        let response = await fetch(
          `https://extensions.gnome.org/extension-query/?` +
            `sort=relevance&` +
            `page=1&` +
            `shell_version=all&` +
            `search=${encodeURIComponent(name)}`
        )
        if (!response.ok) {
          process.stderr.write(`Response ${response.status} for ${name}`)
          process.stderr.write(gray(`\n${await response.text()}\n`))
          response = await fetch(
            `https://extensions.gnome.org/extension-query/?` +
              `sort=relevance&` +
              `page=1&` +
              `shell_version=all&` +
              `search=${encodeURIComponent(name)}`)
          if (!response.ok) process.exit(1)
        }
        let json = await response.json()
        let extension = json.extensions.find(i => i.uuid === uuid)
        if (!extension) {
          throw new Error(`Расширение не найдено: ${name} (${uuid})`)
        }
        return {
          name: extension.name,
          url: `https://extensions.gnome.org${extension.link}`
        }
      })
  )
  let extensions = details
    .map(({ name, url }) => ({ url, name: name.replace(/\[.*\]\s*/, '') }))
    .sort((a, b) => a.name.localeCompare(b.name))
    .map(({ name, url }) => `- [${name}](${url})`)
    .join('\n')
  let cleaned = docs
    .toString()
    .split('\n')
    .filter(line => line && !line.startsWith('-'))
    .join('\n')
  await writeFile(listFile, cleaned + '\n\n' + extensions + '\n')
}

updateGnome()


================================================
FILE: bin/zed-isolate
================================================
#!/bin/bash

set -e

LOG_FILE="/var/run/user/1000/zed-isolate.log"

show_error_log() {
  if [ -f "$LOG_FILE" ]; then
    zenity --text-info \
        --title="Dev Container Error" \
        --font="Lilex Regular 12" \
        --width=800 \
        --height=600 \
        --filename="$LOG_FILE" 2>/dev/null
  fi
  exit 1
}

trap show_error_log ERR

exec > "$LOG_FILE" 2>&1

if [ "$1" != "" ]; then
  cd "$1"
fi

if [ -f .devcontainer.json ]; then
  config="$(pwd)/.devcontainer.json"
fi
if [ -f .devcontainer/devcontainer.json ]; then
  config="$(pwd)/.devcontainer/devcontainer.json"
fi
if [ "$config" == "" ]; then
  echo "Dev Container is disabled because of lack of Dev Container config"
  zed --new ./
  exit 0
fi

export PATH="/home/ai/.local/lib/node/node_modules/.bin/:$PATH"

echo "Starting Dev Container"
~/Dev/environment/bin/dev --up | \
  zenity --progress --text="Starting" --title="Dev Container" --pulsate --auto-close --no-cancel

container_id=$(podman ps -q --filter label=devcontainer.local_folder=$(pwd))

if [ "$container_id" == "" ]; then
  echo "ERROR: Running container was not found"
  show_error_log
  exit 1
fi

zed --new --dev-container . --wait

~/Dev/environment/bin/dev --down


================================================
FILE: bin/zoom
================================================
#!/bin/zsh

source ~/Dev/environment/secrets.env

call_scene() {
  curl -s -S -f \
    -H "Authorization: Bearer $HA_TOKEN" \
    -H "Content-Type: application/json" \
    -d "{\"entity_id\": \"$1\"}" \
    "https://home.local/api/services/scene/turn_on" || true
}

call_scene "scene.andrey_calling"

zoom "$@"

call_scene "scene.andrey_working_night"


================================================
FILE: devcontainer/Dockerfile
================================================
FROM registry.fedoraproject.org/fedora:44

ENV NODE_VERSION=25.9.0 \
  PNPM_VERSION=11.0.0 \
  NODE_24=24.15.0 \
  NODE_22=22.22.2 \
  DIFFT_VERSION=0.68.0 \
  BAT_VERSION=0.26.1 \
  RG_VERSION=15.1.0 \
  ATUIN_VERSION=18.16.0 \
  STARSHIP_VERSION=1.25.0 \
  PNPM_COMPETITION_VERSION=0.5.5

ADD https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.gz /node.tar.xz
ADD https://nodejs.org/dist/v${NODE_24}/node-v${NODE_24}-linux-x64.tar.gz /node24.tar.xz
ADD https://nodejs.org/dist/v${NODE_22}/node-v${NODE_22}-linux-x64.tar.gz /node22.tar.xz
ADD https://github.com/pnpm/pnpm/releases/download/v$PNPM_VERSION/pnpm-linux-x64.tar.gz /pnpm.tar.gz
ADD https://github.com/eza-community/eza/releases/latest/download/eza_x86_64-unknown-linux-musl.tar.gz /eza.tar.gz
ADD https://github.com/Wilfred/difftastic/releases/download/$DIFFT_VERSION/difft-x86_64-unknown-linux-musl.tar.gz /difft.tar.gz
ADD https://github.com/sharkdp/bat/releases/download/v$BAT_VERSION/bat-v$BAT_VERSION-x86_64-unknown-linux-musl.tar.gz /bat.tar.gz
ADD https://github.com/BurntSushi/ripgrep/releases/download/$RG_VERSION/ripgrep-$RG_VERSION-x86_64-unknown-linux-musl.tar.gz /rg.tar.gz
ADD https://github.com/atuinsh/atuin/releases/download/v$ATUIN_VERSION/atuin-x86_64-unknown-linux-musl.tar.gz /atuin.tar.gz
ADD https://github.com/starship/starship/releases/download/v$STARSHIP_VERSION/starship-x86_64-unknown-linux-musl.tar.gz /starship.tar.gz
ADD https://github.com/g-plane/pnpm-shell-completion/releases/download/v$PNPM_COMPETITION_VERSION/pnpm-shell-completion_x86_64-unknown-linux-musl.tar.gz /pnpm-completion.tar.gz

RUN dnf install -yq zsh micro git tig make awk psmisc procps-ng curl \
  bind-utils iputils iproute libatomic nss dbus-libs atk at-spi2-atk cups-libs \
  libdrm libXcomposite libXdamage libXrandr mesa-libgbm pango alsa-lib \
  && dnf clean all \
  && rm -rf /var/cache/dnf

RUN mkdir /usr/local/share/pnpm \
  && tar -xz -f /pnpm.tar.gz -C /usr/local/share/pnpm \
  && ln -s /usr/local/share/pnpm/pnpm /usr/local/bin/pnpm \
  && rm /pnpm.tar.gz \
  \
  && tar -xz -f /node.tar.xz -C /usr/local --remove-files --strip-components=1 \
  --exclude='*.md' --exclude='LICENSE' \
  --exclude='share' --exclude='bin/corepack' \
  && rm /node.tar.xz \
  \
  && tar -xzf /node24.tar.xz -O "node-v$NODE_24-linux-x64/bin/node" > /usr/local/bin/node24 \
  && tar -xzf /node22.tar.xz -O "node-v$NODE_22-linux-x64/bin/node" > /usr/local/bin/node22 \
  && chmod a+rx /usr/local/bin/node24 \
  && chmod a+rx /usr/local/bin/node22 \
  \
  && tar -xz -f /eza.tar.gz \
  && mv eza /usr/local/bin/eza \
  && chmod +x /usr/local/bin/eza \
  && rm /eza.tar.gz \
  \
  && tar -xz -f /difft.tar.gz \
  && mv difft /usr/local/bin/difft \
  && chmod +x /usr/local/bin/difft \
  && rm /difft.tar.gz \
  \
  && tar -xz -f /bat.tar.gz --strip-components=1 bat-v$BAT_VERSION-x86_64-unknown-linux-musl/bat \
  && mv bat /usr/local/bin/bat \
  && chmod +x /usr/local/bin/bat \
  && rm /bat.tar.gz \
  \
  && tar -xz -f /rg.tar.gz --strip-components=1 ripgrep-$RG_VERSION-x86_64-unknown-linux-musl/rg \
  && mv rg /usr/local/bin/rg \
  && chmod +x /usr/local/bin/rg \
  && rm /rg.tar.gz \
  \
  && tar -xz -f /atuin.tar.gz --strip-components=1 atuin-x86_64-unknown-linux-musl/atuin \
  && mv atuin /usr/local/bin/atuin \
  && chmod +x /usr/local/bin/atuin \
  && rm /atuin.tar.gz \
  \
  && tar -xz -f /starship.tar.gz \
  && mv starship /usr/local/bin/starship \
  && chmod +x /usr/local/bin/starship \
  && rm /starship.tar.gz \
  \
  && mkdir -p /usr/local/lib/zsh \
  && git clone -q https://github.com/zsh-users/zsh-syntax-highlighting /usr/local/lib/zsh/zsh-syntax-highlighting \
  && git clone https://github.com/zsh-users/zsh-autosuggestions /usr/local/lib/zsh/zsh-autosuggestions \
  && git clone https://github.com/jimhester/per-directory-history /usr/local/lib/zsh/per-directory-history \
  && mkdir -p /usr/local/lib/zsh/pnpm-shell-completion \
  && tar -xz -f /pnpm-completion.tar.gz -C /usr/local/lib/zsh/pnpm-shell-completion pnpm-shell-completion pnpm-shell-completion.plugin.zsh \
  && chmod a+x /usr/local/lib/zsh/pnpm-shell-completion/pnpm-shell-completion \
  && rm /pnpm-completion.tar.gz \
  \
  && useradd -s /bin/zsh ai

RUN echo '{"arrowParens":"avoid","jsxSingleQuote":false,"quoteProps":"consistent","semi":false,"singleQuote":true,"sortImports":{"groups":["side_effect","side_effect_style","style",["builtin","external","unknown"],["internal","parent","sibling","index"]],"newlinesBetween":true,"order":"asc"},"trailingComma":"none","printWidth":80}' > /.oxfmtrc.json

USER ai

RUN micro -plugin install editorconfig \
  && mkdir -p /home/ai/.local/share/pnpm/

VOLUME /home/ai/.local/share/pnpm/store
VOLUME /home/ai/.shell-history


================================================
FILE: devcontainer/devcontainer.json
================================================
{
  "image": "localhost/ai-opensource:latest",
  "mounts": [
    {
      "source": "pnpm-store",
      "target": "/home/ai/.local/share/pnpm/store",
      "type": "volume",
    },
    {
      "source": "shell-history",
      "target": "/home/ai/.local/share/history/",
      "type": "volume",
    },
  ],
  "runArgs": ["--net=bridge"],
}


================================================
FILE: devcontainer/install-dotfiles
================================================
#!/bin/sh

MICRO_VERSION="2.0.15"
DIFFT_VERSION="0.68.0"
BAT_VERSION="0.26.1"
RG_VERSION="15.1.0"
ATUIN_VERSION="18.13.3"
STARSHIP_VERSION="1.24.2"
PNPM_COMPETITION_VERSION="0.5.5"

ARCH=$(uname -m)
echo "Detected architecture: $ARCH"
case "$ARCH" in
  x86_64)
    ARCH_SUFFIX="x86_64-unknown-linux-musl"
    ;;
  aarch64)
    ARCH_SUFFIX="aarch64-unknown-linux-gnu"
    ;;
  *)
    echo "Unsupported architecture: $ARCH"
    exit 1
    ;;
esac

mkdir -p ~/.config/micro
mkdir -p ~/.config/bat
mkdir -p ~/.config/git
mkdir -p ~/.config/pnpm

cp -f ~/dotfiles/zshrc ~/.zshrc
cp -f ~/dotfiles/gitconfig ~/.config/git/config
cp -f ~/dotfiles/ripgreprc ~/.config/ripgreprc
cp -f ~/dotfiles/micro.json ~/.config/micro/settings.json
cp -f ~/dotfiles/batconfig ~/.config/bat/config
cp -f ~/dotfiles/gitignore ~/.config/git/ignore
cp -f ~/dotfiles/starship.toml ~/.config/starship.toml
cp -f ~/dotfiles/pnpm-config.yaml ~/.config/pnpm/config.yaml
sed -i '/^\s*\$username\\/d;/^\s*\$hostname\\/d' ~/.config/starship.toml

git config set core.hooksPath ".git/hooks"

mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl" > ~/.ssh/known_hosts
echo "github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=" > ~/.ssh/known_hosts
echo "github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk=" > ~/.ssh/known_hosts
chmod 600 ~/.ssh/known_hosts

mkdir -p ~/.local/share/history/
touch ~/.local/share/history/histfile
mkdir -p ~/.local/bin

cmd_exists() {
  command -v "$1" >/dev/null 2>&1
}

miss_lib() {
  [ ! -d ~/.local/lib/$1 ] && [ ! -d /usr/local/lib/$1 ]
}

if ! cmd_exists micro; then
  if [ "$ARCH" = "x86_64" ]; then
    MICRO_ARCH="linux64-static"
  else
    MICRO_ARCH="linux-arm64"
  fi
  curl -sL https://github.com/zyedidia/micro/releases/download/v$MICRO_VERSION/micro-$MICRO_VERSION-$MICRO_ARCH.tar.gz | tar xz
  mv micro-$MICRO_VERSION/micro ~/.local/bin
  chmod +x ~/.local/bin/micro
  rm -rf micro-$MICRO_VERSION
fi

if [ ! -d ~/.config/micro/plug/editorconfig ]; then
  if cmd_exists micro; then
    micro -plugin install editorconfig
  elif [ -f ~/.local/bin/micro ]; then
    ~/.local/bin/micro -plugin install editorconfig
  fi
fi

if ! cmd_exists eza; then
  curl -sL https://github.com/eza-community/eza/releases/latest/download/eza_$ARCH_SUFFIX.tar.gz | tar xz
  chmod +x eza
  mv eza ~/.local/bin
fi

if ! cmd_exists difft; then
  curl -sL https://github.com/Wilfred/difftastic/releases/download/$DIFFT_VERSION/difft-$ARCH_SUFFIX.tar.gz | tar xz
  chmod +x difft
  mv difft ~/.local/bin
fi

if ! cmd_exists bat; then
  curl -sL https://github.com/sharkdp/bat/releases/download/v$BAT_VERSION/bat-v$BAT_VERSION-$ARCH_SUFFIX.tar.gz | tar xz --strip-components=1 bat-v$BAT_VERSION-$ARCH_SUFFIX/bat
  chmod +x bat
  mv bat ~/.local/bin
fi

if ! cmd_exists rg; then
  curl -sL https://github.com/BurntSushi/ripgrep/releases/download/$RG_VERSION/ripgrep-$RG_VERSION-$ARCH_SUFFIX.tar.gz | tar xz --strip-components=1 ripgrep-$RG_VERSION-$ARCH_SUFFIX/rg
  chmod +x rg
  mv rg ~/.local/bin
fi

if ! cmd_exists atuin; then
  curl -sL https://github.com/atuinsh/atuin/releases/download/v$ATUIN_VERSION/atuin-$ARCH_SUFFIX.tar.gz | tar xz --strip-components=1 atuin-$ARCH_SUFFIX/atuin
  chmod +x atuin
  mv atuin ~/.local/bin
fi

if [ ! -f ~/.local/bin/starship ] && [ ! -f /usr/local/bin/starship ]; then
  if [ "$ARCH" = "x86_64" ]; then
    MICRO_ARCH="$ARCH_SUFFIX"
  else
    MICRO_ARCH="aarch64-unknown-linux-musl"
  fi
  curl -sL https://github.com/starship/starship/releases/download/v$STARSHIP_VERSION/starship-$MICRO_ARCH.tar.gz | tar xz
  chmod +x starship
  mv starship ~/.local/bin
fi

mkdir -p ~/.local/lib/zsh
if cmd_exists git && cmd_exists zsh; then
  if miss_lib zsh/zsh-syntax-highlighting; then
    git clone -q https://github.com/zsh-users/zsh-syntax-highlighting \
      ~/.local/lib/zsh/zsh-syntax-highlighting
  fi

  if miss_lib zsh/zsh-autosuggestions; then
    git clone https://github.com/zsh-users/zsh-autosuggestions \
      ~/.local/lib/zsh/zsh-autosuggestions
  fi

  if miss_lib zsh/per-directory-history; then
    git clone https://github.com/jimhester/per-directory-history \
      ~/.local/lib/zsh/per-directory-history
  fi

  if miss_lib zsh/pnpm-shell-completion; then
    mkdir -p ~/.local/lib/zsh/pnpm-shell-completion
    curl -sSL https://github.com/g-plane/pnpm-shell-completion/releases/download/v$PNPM_COMPETITION_VERSION/pnpm-shell-completion_$ARCH_SUFFIX.tar.gz > ~/pnpm-completion.tar.gz
    tar -xzf ~/pnpm-completion.tar.gz \
      -C ~/.local/lib/zsh/pnpm-shell-completion \
      pnpm-shell-completion pnpm-shell-completion.plugin.zsh
    chmod a+x ~/.local/lib/zsh/pnpm-shell-completion/pnpm-shell-completion
    rm ~/pnpm-completion.tar.gz
  fi
fi


================================================
FILE: gitconfig
================================================
[user]
  name  = Andrey Sitnik
  email = andrey@sitnik.es
  signingKey = key::ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHfKri8pwCoINL3A88gGpZDjt3jyfxrIoYfQ8gaY3AoQ andrey@sitnik.es
[alias]
  current-branch = "!git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \\(.*\\)/\\1/'"
  a  = "!git add . && git s"
  ch = "!echo 'Stop using git checkout' && false"
  c  = commit -S -m
  s  = status --short --branch
  d  = diff
  l  = "!git pull origin $(git current-branch) --rebase"
  h  = "!git push origin $(git current-branch)"
  lh = "!git l && git h"
  r  = "!git rm $(git ls-files --deleted) && git status"
  hf = push --force-with-lease
  sw = switch
[color]
  diff   = auto
  status = auto
  branch = auto
[branch]
  autosetuprebase = always
[core]
  autocrlf = input
  editor = micro
[init]
  defaultBranch = main
[gpg]
  format = ssh
[commit]
  gpgsign = true
[push]
  default = current
  followtags = true
[rerere]
  enabled = true
[diff]
  external = difft
  algorithm = histogram
  colorMoved = true
  indentHeuristic = true


================================================
FILE: gitignore
================================================
.pnpm-*.log
.npm-release/
.zed
.eslintcache
.claude


================================================
FILE: hooks-trap/applypatch-msg
================================================
#!/bin/bash

project_hooks=$(git config get --local core.hooksPath)
if [ -n "$project_hooks" ] && [ -d "$project_hooks" ]; then
  if [ -x "$project_hooks/applypatch-msg" ]; then
    /home/ai/Dev/environment/bin/dev CI=1 $project_hooks/applypatch-msg
  fi
fi


================================================
FILE: hooks-trap/commit-msg
================================================
#!/bin/bash

project_hooks=$(git config get --local core.hooksPath)
if [ -n "$project_hooks" ] && [ -d "$project_hooks" ]; then
  if [ -x "$project_hooks/commit-msg" ]; then
    /home/ai/Dev/environment/bin/dev CI=1 $project_hooks/commit-msg
  fi
fi


================================================
FILE: hooks-trap/post-applypatch
================================================
#!/bin/bash

project_hooks=$(git config get --local core.hooksPath)
if [ -n "$project_hooks" ] && [ -d "$project_hooks" ]; then
  if [ -x "$project_hooks/post-applypatch" ]; then
    /home/ai/Dev/environment/bin/dev CI=1 $project_hooks/post-applypatch
  fi
fi


================================================
FILE: hooks-trap/post-checkout
================================================
#!/bin/bash

project_hooks=$(git config get --local core.hooksPath)
if [ -n "$project_hooks" ] && [ -d "$project_hooks" ]; then
  if [ -x "$project_hooks/post-checkout" ]; then
    /home/ai/Dev/environment/bin/dev CI=1 $project_hooks/post-checkout
  fi
fi


================================================
FILE: hooks-trap/post-commit
================================================
#!/bin/bash

project_hooks=$(git config get --local core.hooksPath)
if [ -n "$project_hooks" ] && [ -d "$project_hooks" ]; then
  if [ -x "$project_hooks/post-commit" ]; then
    /home/ai/Dev/environment/bin/dev CI=1 $project_hooks/post-commit
  fi
fi


================================================
FILE: hooks-trap/post-merge
================================================
#!/bin/bash

project_hooks=$(git config get --local core.hooksPath)
if [ -n "$project_hooks" ] && [ -d "$project_hooks" ]; then
  if [ -x "$project_hooks/post-merge" ]; then
    /home/ai/Dev/environment/bin/dev CI=1 $project_hooks/post-merge
  fi
fi


================================================
FILE: hooks-trap/post-rewrite
================================================
#!/bin/bash

project_hooks=$(git config get --local core.hooksPath)
if [ -n "$project_hooks" ] && [ -d "$project_hooks" ]; then
  if [ -x "$project_hooks/post-rewrite" ]; then
    /home/ai/Dev/environment/bin/dev CI=1 $project_hooks/post-rewrite
  fi
fi


================================================
FILE: hooks-trap/pre-applypatch
================================================
#!/bin/bash

project_hooks=$(git config get --local core.hooksPath)
if [ -n "$project_hooks" ] && [ -d "$project_hooks" ]; then
  if [ -x "$project_hooks/pre-applypatch" ]; then
    /home/ai/Dev/environment/bin/dev CI=1 $project_hooks/pre-applypatch
  fi
fi


================================================
FILE: hooks-trap/pre-auto-gc
================================================
#!/bin/bash

project_hooks=$(git config get --local core.hooksPath)
if [ -n "$project_hooks" ] && [ -d "$project_hooks" ]; then
  if [ -x "$project_hooks/pre-auto-gc" ]; then
    /home/ai/Dev/environment/bin/dev CI=1 $project_hooks/pre-auto-gc
  fi
fi


================================================
FILE: hooks-trap/pre-commit
================================================
#!/bin/bash

project_hooks=$(git config get --local core.hooksPath)
if [ -n "$project_hooks" ] && [ -d "$project_hooks" ]; then
  if [ -x "$project_hooks/pre-commit" ]; then
    /home/ai/Dev/environment/bin/dev CI=1 $project_hooks/pre-commit
  fi
fi


================================================
FILE: hooks-trap/pre-merge-commit
================================================
#!/bin/bash

project_hooks=$(git config get --local core.hooksPath)
if [ -n "$project_hooks" ] && [ -d "$project_hooks" ]; then
  if [ -x "$project_hooks/pre-merge-commit" ]; then
    /home/ai/Dev/environment/bin/dev CI=1 $project_hooks/pre-merge-commit
  fi
fi


================================================
FILE: hooks-trap/pre-push
================================================
#!/bin/bash

project_hooks=$(git config get --local core.hooksPath)
if [ -n "$project_hooks" ] && [ -d "$project_hooks" ]; then
  if [ -x "$project_hooks/pre-push" ]; then
    /home/ai/Dev/environment/bin/dev CI=1 $project_hooks/pre-push
  fi
fi


================================================
FILE: hooks-trap/pre-rebase
================================================
#!/bin/bash

project_hooks=$(git config get --local core.hooksPath)
if [ -n "$project_hooks" ] && [ -d "$project_hooks" ]; then
  if [ -x "$project_hooks/pre-rebase" ]; then
    /home/ai/Dev/environment/bin/dev CI=1 $project_hooks/pre-rebase
  fi
fi


================================================
FILE: hooks-trap/prepare-commit-msg
================================================
#!/bin/bash

project_hooks=$(git config get --local core.hooksPath)
if [ -n "$project_hooks" ] && [ -d "$project_hooks" ]; then
  if [ -x "$project_hooks/prepare-commit-msg" ]; then
    /home/ai/Dev/environment/bin/dev CI=1 $project_hooks/prepare-commit-msg
  fi
fi


================================================
FILE: icons/Zoom.desktop
================================================
[Desktop Entry]
Name=Zoom
Comment=Zoom Video Conference
Exec=/home/ai/Dev/environment/bin/zoom @@u %U @@
Icon=Zoom
Terminal=false
Type=Application
Encoding=UTF-8
Categories=Network;Application;
StartupWMClass=zoom
MimeType=x-scheme-handler/zoommtg;x-scheme-handler/zoomus;x-scheme-handler/tel;x-scheme-handler/callto;x-scheme-handler/zoomphonecall;x-scheme-handler/zoomphonesms;x-scheme-handler/zoomcontactcentercall;application/x-zoom
X-KDE-Protocols=zoommtg;zoomus;tel;callto;zoomphonecall;zoomphonesms;zoomcontactcentercall;
Name[en_US]=Zoom


================================================
FILE: icons/backup.desktop
================================================
[Desktop Entry]
Type=Application
Name=Резервное копирование
Comment=Backup
Icon=/home/ai/.local/share/applications/backup.svg
Exec=flatpak run app.devsuite.Ptyxis -- /home/ai/Dev/environment/bin/backup
PrefersNonDefaultGPU=false
Hidden=false
NoDisplay=false
StartupNotify=false
Terminal=false


================================================
FILE: icons/com.mattjakeman.ExtensionManager.desktop
================================================
[Desktop Entry]
Name=Расширения
Exec=/usr/bin/flatpak run --branch=stable --arch=x86_64 --command=extension-manager --file-forwarding com.mattjakeman.ExtensionManager @@u %U @@
Icon=com.mattjakeman.ExtensionManager
Terminal=false
Type=Application
Categories=GTK;Utility
OnlyShowIn=GNOME;
StartupNotify=true
MimeType=x-scheme-handler/gnome-extensions;
Comment=Управление расширениями GNOME Shell
Keywords=extension;manager;shell;менеджер;расширение;
X-Flatpak=com.mattjakeman.ExtensionManager
PrefersNonDefaultGPU=false
Hidden=false
NoDisplay=false


================================================
FILE: icons/com.nextcloud.desktopclient.nextcloud.desktop
================================================
[Desktop Entry]
Categories=Utility;X-SuSE-SyncUtility;
Type=Application
Exec=nextcloud %u
Name=Nextcloud
Comment=Настольный клиент синхронизации Nextcloud
GenericName=Folder Sync
Icon=Nextcloud
Keywords=Nextcloud;syncing;file;sharing;
X-GNOME-Autostart-Delay=3
MimeType=application/vnd.nextcloud;x-scheme-handler/nc;
SingleMainWindow=true
Actions=Quit;
Implements=org.freedesktop.CloudProviders
PrefersNonDefaultGPU=false
Hidden=false
NoDisplay=false
StartupNotify=false
Terminal=false

[org.freedesktop.CloudProviders]
BusName=com.nextcloudgmbh.Nextcloud
ObjectPath=/com/nextcloudgmbh/Nextcloud

[Desktop Action Quit]
Exec=nextcloud --quit
Name=Quit Nextcloud
Icon=nextcloud
Name[ru]=Quit Nextcloud
Name[ru_RU]=Quit Nextcloud
Name[ru_RU.UTF-8]=Quit Nextcloud


================================================
FILE: icons/hu.irl.cameractrls.desktop
================================================
[Desktop Entry]
Type=Application
Version=1.0
Name=Настройки камеры
Comment=Camera controls for Linux
Exec=/usr/bin/flatpak run --branch=stable --arch=x86_64 --command=cameractrlsgtk.py hu.irl.cameractrls
Icon=hu.irl.cameractrls
Terminal=false
Categories=Settings;AudioVideo;Video;Office;Utility;GNOME;GTK;
Keywords=picture;photos;camera;webcam;
X-Flatpak=hu.irl.cameractrls
PrefersNonDefaultGPU=false
Hidden=false
NoDisplay=false
StartupNotify=false


================================================
FILE: icons/porn.desktop
================================================
[Desktop Entry]
Type=Application
Name=Эротика
Comment=Play porn movies
Icon=strawberry
Exec=/home/ai/Dev/environment/bin/porn
Actions=New;
Name[ru]=Эротика
Name[ru_RU]=Эротика
Name[ru_RU.UTF-8]=Эротика
Comment[ru]=Play porn movies
Comment[ru_RU]=Play porn movies
Comment[ru_RU.UTF-8]=Play porn movies
PrefersNonDefaultGPU=false
Hidden=false
NoDisplay=false
StartupNotify=false
Terminal=false

[Desktop Action New]
Name=Новое
Exec=/home/ai/Dev/environment/bin/porn --new


================================================
FILE: icons/private.desktop
================================================
[Desktop Entry]
Type=Application
Name=Личная папка
Comment=Decrypt safe storage
Icon=/home/ai/.local/share/applications/private.svg
Exec=/home/ai/Dev/environment/bin/private


================================================
FILE: icons/update.desktop
================================================
[Desktop Entry]
Type=Application
Name=Обновление системы
Comment=Update RPM, Flatpak, and Mozilla Theme
Icon=org.fedoraproject.AnacondaInstaller
Exec=flatpak run app.devsuite.Ptyxis -- /home/ai/Dev/environment/bin/update


================================================
FILE: icons/zed-isolate.desktop
================================================
[Desktop Entry]
Type=Application
Name=Zed Dev Container
Icon=zed
Exec=/home/ai/Dev/environment/bin/zed-isolate %U
MimeType=inode/directory;
Categories=Utility;TextEditor;Development;IDE;


================================================
FILE: micro.json
================================================
{
    "colorscheme": "simple",
    "mkparents": true
}


================================================
FILE: mimeapps.list
================================================
[Added Associations]
x-scheme-handler/sms=org.gnome.Shell.Extensions.GSConnect.desktop;
x-scheme-handler/tel=org.gnome.Shell.Extensions.GSConnect.desktop;
image/jpeg=org.gimp.GIMP.desktop;org.gnome.Loupe.desktop;
image/avif=org.gnome.eog.desktop;org.gimp.GIMP.desktop;org.gnome.Loupe.desktop;
image/webp=org.gnome.eog.desktop;
image/svg+xml=zed.desktop;
application/x-bittorrent=io.github.TransmissionRemoteGtk.desktop;
image/png=org.gimp.GIMP.desktop;org.gnome.Loupe.desktop;
image/heif=org.gimp.GIMP.desktop;org.gnome.Loupe.desktop;
text/vnd.trolltech.linguist=mpv.desktop;zed.desktop;
font/ttf=org.gnome.font-viewer.desktop;
x-scheme-handler/http=org.mozilla.firefox.desktop;
text/html=org.mozilla.firefox.desktop;
application/xhtml+xml=org.mozilla.firefox.desktop;
x-scheme-handler/https=org.mozilla.firefox.desktop;
audio/aac=mpv.desktop;
audio/x-aac=mpv.desktop;
audio/vnd.dolby.heaac.1=mpv.desktop;
audio/vnd.dolby.heaac.2=mpv.desktop;
audio/aiff=mpv.desktop;
audio/x-aiff=mpv.desktop;
audio/m4a=mpv.desktop;
audio/x-m4a=mpv.desktop;
audio/mp1=mpv.desktop;
audio/x-mp1=mpv.desktop;
audio/mp2=mpv.desktop;
audio/x-mp2=mpv.desktop;
audio/mp3=mpv.desktop;
audio/x-mp3=mpv.desktop;
audio/mpeg=mpv.desktop;
audio/mpeg2=mpv.desktop;
audio/mpeg3=mpv.desktop;
audio/mpegurl=mpv.desktop;
audio/x-mpegurl=mpv.desktop;
audio/mpg=mpv.desktop;
audio/x-mpg=mpv.desktop;
audio/rn-mpeg=mpv.desktop;
audio/musepack=mpv.desktop;
audio/x-musepack=mpv.desktop;
audio/ogg=mpv.desktop;
audio/scpls=mpv.desktop;
audio/x-scpls=mpv.desktop;
audio/vnd.rn-realaudio=mpv.desktop;
audio/wav=mpv.desktop;
audio/x-pn-wav=mpv.desktop;
audio/x-pn-windows-pcm=mpv.desktop;
audio/x-realaudio=mpv.desktop;
audio/x-pn-realaudio=mpv.desktop;org.gnome.Totem.desktop;
audio/x-ms-wma=mpv.desktop;
audio/x-pls=mpv.desktop;
audio/x-wav=mpv.desktop;
audio/x-ms-asf=mpv.desktop;
audio/x-matroska=mpv.desktop;
audio/webm=mpv.desktop;
audio/vorbis=mpv.desktop;
audio/x-vorbis=mpv.desktop;
audio/x-shorten=mpv.desktop;
audio/x-ape=mpv.desktop;
audio/x-wavpack=mpv.desktop;
audio/x-tta=mpv.desktop;
audio/AMR=mpv.desktop;
audio/ac3=mpv.desktop;
audio/eac3=mpv.desktop;
audio/amr-wb=mpv.desktop;
audio/flac=mpv.desktop;
audio/mp4=mpv.desktop;
audio/x-pn-au=mpv.desktop;
audio/3gpp=mpv.desktop;
audio/3gpp2=mpv.desktop;
audio/dv=mpv.desktop;
audio/opus=mpv.desktop;
audio/vnd.dts=mpv.desktop;
audio/vnd.dts.hd=mpv.desktop;
audio/x-adpcm=mpv.desktop;
audio/m3u=mpv.desktop;
audio/x-vorbis+ogg=org.gnome.Totem.desktop;
video/x-mpeg2=mpv.desktop;
video/x-mpeg3=mpv.desktop;
video/mp4v-es=mpv.desktop;
video/x-m4v=mpv.desktop;
video/divx=mpv.desktop;
video/vnd.divx=mpv.desktop;
video/msvideo=mpv.desktop;
video/ogg=mpv.desktop;
video/vnd.rn-realvideo=mpv.desktop;
video/x-ms-afs=mpv.desktop;
video/x-ms-asf=mpv.desktop;
video/x-ms-wmx=mpv.desktop;
video/x-ms-wvxvideo=mpv.desktop;
video/x-avi=mpv.desktop;
video/avi=mpv.desktop;
video/x-flic=mpv.desktop;
video/fli=mpv.desktop;
video/x-flc=mpv.desktop;
video/flv=mpv.desktop;
video/x-theora=mpv.desktop;
video/x-theora+ogg=mpv.desktop;
video/mkv=mpv.desktop;
video/x-ogm=mpv.desktop;
video/vnd.mpegurl=mpv.desktop;
video/3gp=mpv.desktop;
video/3gpp2=mpv.desktop;
video/dv=mpv.desktop;
application/xml=zed.desktop;
application/zip=org.gnome.Nautilus.desktop;
application/pdf=org.gnome.Papers.desktop;
x-scheme-handler/gnome-extensions=com.mattjakeman.ExtensionManager.desktop;
application/vnd.nextcloud=com.nextcloud.desktopclient.nextcloud.desktop;
x-scheme-handler/nc=com.nextcloud.desktopclient.nextcloud.desktop;
text/x-opml+xml=zed.desktop;
application/atom+xml=zed.desktop;
application/rss+xml=zed.desktop;

[Default Applications]
video/x-matroska=mpv.desktop
video/mp4=mpv.desktop
video/x-ms-wmv=mpv.desktop
video/x-msvideo=mpv.desktop
video/x-flv=mpv.desktop
video/mpeg=mpv.desktop
video/mp2t=mpv.desktop
video/webm=mpv.desktop
video/quicktime=mpv.desktop
application/x-bittorrent=io.github.TransmissionRemoteGtk.desktop
text/vnd.trolltech.linguist=zed.desktop
image/jpeg=org.gnome.Loupe.desktop
image/avif=org.gnome.Loupe.desktop
image/png=org.gnome.Loupe.desktop
image/heif=org.gnome.Loupe.desktop
font/ttf=org.gnome.font-viewer.desktop
video/3gpp=mpv.desktop
x-scheme-handler/http=org.mozilla.firefox.desktop
text/html=org.mozilla.firefox.desktop
application/xhtml+xml=org.mozilla.firefox.desktop
x-scheme-handler/https=org.mozilla.firefox.desktop
audio/x-vorbis+ogg=org.gnome.Totem.desktop
audio/aac=mpv.desktop
audio/x-aac=mpv.desktop
audio/vnd.dolby.heaac.1=mpv.desktop
audio/vnd.dolby.heaac.2=mpv.desktop
audio/aiff=mpv.desktop
audio/x-aiff=mpv.desktop
audio/m4a=mpv.desktop
audio/x-m4a=mpv.desktop
audio/mp1=mpv.desktop
audio/x-mp1=mpv.desktop
audio/mp2=mpv.desktop
audio/x-mp2=mpv.desktop
audio/mp3=mpv.desktop
audio/x-mp3=mpv.desktop
audio/mpeg=mpv.desktop
audio/mpeg2=mpv.desktop
audio/mpeg3=mpv.desktop
audio/mpegurl=mpv.desktop
audio/x-mpegurl=mpv.desktop
audio/mpg=mpv.desktop
audio/x-mpg=mpv.desktop
audio/rn-mpeg=mpv.desktop
audio/musepack=mpv.desktop
audio/x-musepack=mpv.desktop
audio/ogg=mpv.desktop
audio/scpls=mpv.desktop
audio/x-scpls=mpv.desktop
audio/vnd.rn-realaudio=mpv.desktop
audio/wav=mpv.desktop
audio/x-pn-wav=mpv.desktop
audio/x-pn-windows-pcm=mpv.desktop
audio/x-realaudio=mpv.desktop
audio/x-pn-realaudio=org.gnome.Totem.desktop
audio/x-ms-wma=mpv.desktop
audio/x-pls=mpv.desktop
audio/x-wav=mpv.desktop
audio/x-ms-asf=mpv.desktop
audio/x-matroska=mpv.desktop
audio/webm=mpv.desktop
audio/vorbis=mpv.desktop
audio/x-vorbis=mpv.desktop
audio/x-shorten=mpv.desktop
audio/x-ape=mpv.desktop
audio/x-wavpack=mpv.desktop
audio/x-tta=mpv.desktop
audio/AMR=mpv.desktop
audio/ac3=mpv.desktop
audio/eac3=mpv.desktop
audio/amr-wb=mpv.desktop
audio/flac=mpv.desktop
audio/mp4=mpv.desktop
audio/x-pn-au=mpv.desktop
audio/3gpp=mpv.desktop
audio/3gpp2=mpv.desktop
audio/dv=mpv.desktop
audio/opus=mpv.desktop
audio/vnd.dts=mpv.desktop
audio/vnd.dts.hd=mpv.desktop
audio/x-adpcm=mpv.desktop
audio/m3u=mpv.desktop
video/x-ogm+ogg=mpv.desktop
video/x-mpeg2=mpv.desktop
video/x-mpeg3=mpv.desktop
video/mp4v-es=mpv.desktop
video/x-m4v=mpv.desktop
video/divx=mpv.desktop
video/vnd.divx=mpv.desktop
video/msvideo=mpv.desktop
video/ogg=mpv.desktop
video/vnd.rn-realvideo=mpv.desktop
video/x-ms-afs=mpv.desktop
video/x-ms-asf=mpv.desktop
video/x-ms-wmx=mpv.desktop
video/x-ms-wvxvideo=mpv.desktop
video/x-avi=mpv.desktop
video/avi=mpv.desktop
video/x-flic=mpv.desktop
video/fli=mpv.desktop
video/x-flc=mpv.desktop
video/flv=mpv.desktop
video/x-theora=mpv.desktop
video/x-theora+ogg=mpv.desktop
video/mkv=mpv.desktop
video/x-ogm=mpv.desktop
video/vnd.mpegurl=mpv.desktop
video/3gp=mpv.desktop
video/3gpp2=mpv.desktop
video/dv=mpv.desktop
application/xml=zed.desktop
application/pdf=org.gnome.Papers.desktop
text/x-opml+xml=zed.desktop
application/atom+xml=zed.desktop
application/rss+xml=zed.desktop


================================================
FILE: mpv-input.conf
================================================
й quit
а cycle fullscreen
MOUSE_BTN3 ignore
MOUSE_BTN4 ignore


================================================
FILE: mpv.conf
================================================
slang=ru
alang=jpn,ja,eng,en


================================================
FILE: pnpm-config.yaml
================================================
blockExoticSubdeps: true
minimumReleaseAge: 1440
storeDir: ~/.local/share/pnpm/store
trustPolicy: true
trustPolicyIgnoreAfter: true


================================================
FILE: ripgreprc
================================================
--smart-case
--glob=!.git/
--glob=!.yarn/
--hidden
--no-heading


================================================
FILE: sshconfig
================================================
Host *
    ForwardAgent no

Host github.com
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_ed25519

Host susedko.local
    HostName susedko.local
    User ai
    IdentityFile ~/.ssh/id_ed25519

Host 127.0.0.1
    StrictHostKeyChecking no
    UserKnownHostsFile=/dev/null

Host *
  AddKeysToAgent yes
  IdentityFile ~/.ssh/id_ed25519
  IdentityFile ~/.ssh/id_ed25519_ru

GSSAPIAuthentication no
TCPKeepAlive yes
ServerAliveInterval 3


================================================
FILE: starship.toml
================================================
format = """
$username\
$hostname\
$container\
$shlvl\
$directory\
$git_branch\
$git_commit\
$git_state\
$git_metrics\
$git_status\
$sudo\
$cmd_duration\
$line_break\
$jobs\
$status\
$shell\
$character"""

[container]
format = '[$symbol]($style) '


================================================
FILE: zed-keys.json
================================================
[
  {
    "bindings": {
      "ctrl-q": null
    }
  },
  {
    "context": "Terminal",
    "bindings": {
      "ctrl-s": ["terminal::SendKeystroke", "ctrl-s"],
      "ctrl-c": "terminal::Copy",
      "ctrl-v": "terminal::Paste"
    }
  }
]


================================================
FILE: zed.json
================================================
{
  "outline_panel": {
    "dock": "left"
  },
  "collaboration_panel": {
    "dock": "left"
  },
  "git_panel": {
    "dock": "left"
  },
  "project_panel": {
    "dock": "left"
  },
  "diff_view_style": "unified",
  "agent_servers": {
    "claude-acp": {
      "default_config_options": {
        "mode": "bypassPermissions"
      },
      "type": "registry"
    }
  },
  "colorize_brackets": true,
  "indent_guides": {
    "coloring": "indent_aware",
    "background_coloring": "disabled"
  },
  "prettier": {
    "allowed": true
  },
  "use_podman": true,
  "show_completions_on_input": true,
  "buffer_font_family": "Lilex",
  "agent": {
    "dock": "right",
    "tool_permissions": {
      "default": "allow"
    },
    "default_profile": "write",
    "notify_when_agent_waiting": "primary_screen",
    "play_sound_when_agent_done": "always",
    "model_parameters": [],
    "default_model": {
      "effort": "high",
      "enable_thinking": true,
      "provider": "zed.dev",
      "model": "claude-sonnet-4-6"
    }
  },
  "edit_predictions": {
    "provider": "zed",
    "mode": "subtle",
    "copilot": {
      "proxy": null,
      "proxy_no_verify": null
    }
  },
  "icon_theme": "Material Icon Theme",
  "terminal": {
    "dock": "right"
  },
  "soft_wrap": "preferred_line_length",
  "preferred_line_length": 80,
  "wrap_guides": [80],
  "ui_font_size": 16,
  "buffer_font_size": 16,
  "theme": {
    "mode": "system",
    "light": "Adwaita Pastel Light",
    "dark": "Adwaita Pastel Dark"
  },
  "git": {
    "inline_blame": {
      "enabled": false
    }
  },
  "file_types": {
    "XML": ["svg"],
    "YAML": ["**/*.bu"],
    "JSON": ["**/*.webmanifest"]
  },
  "lsp": {
    "oxfmt": {
      "initialization_options": {
        "settings": {
          "fmt.configPath": null
        }
      }
    },
    "oxlint": {
      "initialization_options": {
        "settings": {
          "configPath": null,
          "fixKind": "safe_fix",
          "run": "onType",
          "unusedDisableDirectives": "deny"
        }
      }
    }
  },
  "languages": {
    "JavaScript": {
      "format_on_save": "on",
      "prettier": {
        "allowed": false
      },
      "language_servers": ["!eslint", "!tailwindcss-language-server", "..."],
      "formatter": [
        {
          "language_server": {
            "name": "oxfmt"
          }
        }
      ]
    },
    "Svelte": {
      "code_actions_on_format": {
        "source.fixAll.eslint": true
      },
      "language_servers": ["!tailwindcss-language-server", "..."]
    },
    "TypeScript": {
      "format_on_save": "on",
      "prettier": {
        "allowed": false
      },
      "language_servers": ["!eslint", "!tailwindcss-language-server", "..."],
      "formatter": [
        {
          "language_server": {
            "name": "oxfmt"
          }
        }
      ]
    },
    "HTML": {
      "format_on_save": "on",
      "prettier": {
        "allowed": false
      },
      "language_servers": ["!tailwindcss-language-server", "..."],
      "formatter": [
        {
          "language_server": {
            "name": "oxfmt"
          }
        }
      ]
    },
    "CSS": {
      "format_on_save": "on",
      "prettier": {
        "allowed": false
      },
      "formatter": [
        {
          "language_server": {
            "name": "oxfmt"
          }
        }
      ]
    },
    "JSON": {
      "format_on_save": "on",
      "prettier": {
        "allowed": false
      },
      "formatter": [
        {
          "language_server": {
            "name": "oxfmt"
          }
        }
      ]
    },
    "JSONC": {
      "format_on_save": "on",
      "prettier": {
        "allowed": false
      },
      "formatter": [
        {
          "language_server": {
            "name": "oxfmt"
          }
        }
      ]
    },
    "YAML": {
      "format_on_save": "on",
      "prettier": {
        "allowed": false
      },
      "formatter": [
        {
          "language_server": {
            "name": "oxfmt"
          }
        }
      ]
    },
    "Markdown": {
      "format_on_save": "on",
      "prettier": {
        "allowed": false
      },
      "formatter": [
        {
          "language_server": {
            "name": "oxfmt"
          }
        }
      ]
    }
  }
}


================================================
FILE: zshrc
================================================
# History
HISTSIZE=10000
SAVEHIST=10000
HISTFILE=~/.local/share/history/histfile
setopt appendhistory
setopt inc_append_history
setopt hist_ignore_all_dups

# Colors
autoload -U colors && colors

# Key bindings
bindkey -e
bindkey ';5D' backward-word # Ctrl+Left
bindkey ';5C' forward-word  # Ctrl+Right
stty intr ^X                # Replace Ctrl+C to Ctrl+X
stty susp undef             # Disable Ctrl + Z

# Force keeping home folder clean
export XDG_CACHE_HOME="$HOME/.cache"
export XDG_CONFIG_HOME="$HOME/.config"
export XDG_DATA_HOME="$HOME/.local/share"
export GNUPGHOME="$XDG_DATA_HOME/gnupg"
export NODE_COMPILE_CACHE="$XDG_CACHE_HOME/node"
export NPM_CONFIG_USERCONFIG="$XDG_CONFIG_HOME/npmrc"
export RIPGREP_CONFIG_PATH="$XDG_CONFIG_HOME/ripgreprc"
export CLAUDE_CONFIG_DIR="$XDG_DATA_HOME/claude"

# Completion
zstyle :compinstall filename "$HOME/.zshrc"
autoload -Uz compinit
compinit -i -d "$XDG_CACHE_HOME/zcompcache"

# Zsh plugins
export HISTORY_BASE="$XDG_CACHE_HOME/zsh_directory_history"
for plugin in \
  zsh-syntax-highlighting/zsh-syntax-highlighting.zsh \
  zsh-autosuggestions/zsh-autosuggestions.zsh \
  per-directory-history/per-directory-history.zsh \
  pnpm-shell-completion/pnpm-shell-completion.plugin.zsh
do
  for dir in ~/.local/lib/zsh /usr/local/lib/zsh; do
    if [[ -f $dir/$plugin ]]; then
      source $dir/$plugin
      break
    fi
  done
done

# Local binaries
export PATH="$HOME/.local/bin:$PATH"

# Prompt
if command -v starship > /dev/null 2>&1; then
  eval "$(starship init zsh)"
elif [ -f ~/.local/bin/starship ]; then
  eval "$(~/.local/bin/starship init zsh)"
fi

# History
if [ -f ~/.local/bin/atuin ]; then
  eval "$(~/.local/bin/atuin init zsh --disable-up-arrow)"
fi

# Rip Grep

# Console editor
export EDITOR=micro

# Fix Bat in light console
export BAT_THEME=ansi

# Release function
release() {
  local VERSION=$(grep -oP '(?<="version": ")[^"]*' package.json)

  if [ -z "$VERSION" ]; then
    echo "Version not found in package.json"
    return 1
  fi

  git add .
  git commit -m "Release $VERSION version"
  git tag -s "$VERSION" -m "$VERSION"
  git push
}

# Aliases
alias g='git'
alias ..='cd ..'
alias l='ls --all'
alias ll='ls --long --all --git'

if command -v bat > /dev/null 2>&1; then
  alias cat='bat'
fi
if command -v eza > /dev/null 2>&1; then
  alias ls='eza'
fi

alias r='dev node --run'
alias t='dev node --run test'
alias pm='dev pnpm'
alias pnx='dev pnpm dlx'
alias pui='pnpm update --interactive --latest -r --include-workspace-root'
alias pu='pnpm update -r --include-workspace-root'
alias pui1='pnpm update --interactive --latest'
alias pu1='pnpm update'

if [ -n "$container" ]; then
  if [ -d "$HOME/.local/share/pnpm" ]; then
    export PNPM_HOME="$HOME/.local/share/pnpm"
    export PATH="$PNPM_HOME/bin/:$PATH"
  fi
  alias dev='command'

  if [ -z "$SSH_AUTH_SOCK" ] && [ -S "/run/user/1000/gcr/ssh" ]; then
    export SSH_AUTH_SOCK="/run/user/1000/gcr/ssh"
  fi
else
  export PATH="/home/ai/.local/lib/node/node_modules/.bin/:$PATH"

  alias dev='/home/ai/Dev/environment/bin/dev'
  alias devup='dev --up'
  alias devdown='dev --down'
  alias pnpm='dev pnpm'
  alias node='dev node'
  alias multiocular='dev --port pnpm multiocular'

  # Run git hooks inside Dev Container
  export GIT_CONFIG_PARAMETERS="'core.hooksPath=/home/ai/Dev/environment/hooks-trap'"

  # Fast way to Dev projects
  if [ -d ~/Dev ]; then
    cdpath=(. ~/Dev)
  fi

  # Zed
  alias e='~/Dev/environment/bin/zed-isolate .'

  # Development
  alias p='dev pnpm clean-publish --temp-dir .npm-release --without-publish \
    && cd .npm-release \
    && npm publish --access public \
    && cd .. \
    && rm -R  .npm-release'
fi
Download .txt
gitextract_8apgxoyr/

├── .editorconfig
├── .gitignore
├── .oxfmtrc.json
├── GNOME.md
├── Install.md
├── LICENSE
├── README.md
├── batconfig
├── bin/
│   ├── backup
│   ├── backup-gnome-extensions
│   ├── build-devcontainer
│   ├── clear
│   ├── clear-weather-city
│   ├── copy-env
│   ├── dev
│   ├── force-lock
│   ├── porn
│   ├── private
│   ├── restore-gnome-extensions
│   ├── susedko
│   ├── susedko-listener
│   ├── update
│   ├── update-devcontainer-configs
│   ├── update-dockerfile
│   ├── update-extension-lists
│   ├── zed-isolate
│   └── zoom
├── devcontainer/
│   ├── Dockerfile
│   ├── devcontainer.json
│   └── install-dotfiles
├── gitconfig
├── gitignore
├── hooks-trap/
│   ├── applypatch-msg
│   ├── commit-msg
│   ├── post-applypatch
│   ├── post-checkout
│   ├── post-commit
│   ├── post-merge
│   ├── post-rewrite
│   ├── pre-applypatch
│   ├── pre-auto-gc
│   ├── pre-commit
│   ├── pre-merge-commit
│   ├── pre-push
│   ├── pre-rebase
│   └── prepare-commit-msg
├── icons/
│   ├── Zoom.desktop
│   ├── backup.desktop
│   ├── com.mattjakeman.ExtensionManager.desktop
│   ├── com.nextcloud.desktopclient.nextcloud.desktop
│   ├── hu.irl.cameractrls.desktop
│   ├── porn.desktop
│   ├── private.desktop
│   ├── update.desktop
│   └── zed-isolate.desktop
├── micro.json
├── mimeapps.list
├── mpv-input.conf
├── mpv.conf
├── pnpm-config.yaml
├── ripgreprc
├── sshconfig
├── starship.toml
├── zed-keys.json
├── zed.json
└── zshrc
Condensed preview — 66 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (88K chars).
[
  {
    "path": ".editorconfig",
    "chars": 177,
    "preview": "root = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ni"
  },
  {
    "path": ".gitignore",
    "chars": 12,
    "preview": "secrets.env\n"
  },
  {
    "path": ".oxfmtrc.json",
    "chars": 422,
    "preview": "{\n  \"arrowParens\": \"avoid\",\n  \"jsxSingleQuote\": false,\n  \"quoteProps\": \"consistent\",\n  \"semi\": false,\n  \"singleQuote\": t"
  },
  {
    "path": "GNOME.md",
    "chars": 2876,
    "preview": "## GNOME Shell Extensions\n\n- [All-in-One Clipboard](https://extensions.gnome.org/extension/8671/all-in-one-clipboard/)\n-"
  },
  {
    "path": "Install.md",
    "chars": 16559,
    "preview": "## How I install my system\n\n### Preparing\n\nDownload [Fedora image](https://getfedora.org/ru/workstation/)\nand write it t"
  },
  {
    "path": "LICENSE",
    "chars": 1095,
    "preview": "The MIT License (MIT)\n\nCopyright 2013 Andrey Sitnik <andrey@sitnik.es>\n\nPermission is hereby granted, free of charge, to"
  },
  {
    "path": "README.md",
    "chars": 222,
    "preview": "My home configs, scripts and [installation process](./Install.md).\n\nSee also [my keyboard layout](https://github.com/ai/"
  },
  {
    "path": "batconfig",
    "chars": 8,
    "preview": "--plain\n"
  },
  {
    "path": "bin/backup",
    "chars": 3912,
    "preview": "#!/bin/sh\n\nTITLE='\\033[0;32m\\033[1m'\nGRAY='\\033[0;90m'\nNC='\\033[0m'\n\nhour=$(date +\"%H\")\nif [[ hour -lt 9 || hour -ge 22 "
  },
  {
    "path": "bin/backup-gnome-extensions",
    "chars": 514,
    "preview": "#!/bin/bash\n\nbackup_dir=\"$HOME/.local/share/gnome-shell-extensions-settings\"\nrm -r \"$backup_dir\"\nmkdir -p \"$backup_dir\"\n"
  },
  {
    "path": "bin/build-devcontainer",
    "chars": 170,
    "preview": "#!/bin/bash\n\n~/Dev/environment/bin/copy-env\n\npodman build -t localhost/ai-opensource \\\n  -f /home/ai/Dev/environment/dev"
  },
  {
    "path": "bin/clear",
    "chars": 235,
    "preview": "#!/bin/sh\n\necho \"Было $(df -h / | tail -1 | awk '{print $4}')\"\necho\n\npodman rmi --all --force\npnpm store prune\nyarn cach"
  },
  {
    "path": "bin/clear-weather-city",
    "chars": 55,
    "preview": "#!/bin/sh\n\ngsettings reset org.gnome.Weather locations\n"
  },
  {
    "path": "bin/copy-env",
    "chars": 2187,
    "preview": "#!/bin/sh\n# Copy config and scripts to or from repo\n\nif [ \"$1\" == \"system\" ]; then\n  rm ~/.local/share/applications/*.{d"
  },
  {
    "path": "bin/dev",
    "chars": 5307,
    "preview": "#!/bin/bash\n\nset -e\n\nfunction get_container_runtime() {\n  if command -v podman &> /dev/null; then\n    echo \"podman\"\n  el"
  },
  {
    "path": "bin/force-lock",
    "chars": 1520,
    "preview": "#!/bin/bash\nIDLE_TIME=240000\nLANG=en\n\nlog() { echo \"$(date '+%H:%M:%S') $*\"; }\n\nwhile true; do\n  CURRENT_IDLE=$(gdbus ca"
  },
  {
    "path": "bin/porn",
    "chars": 527,
    "preview": "#!/bin/sh\n# Run movies from specific category\n\nif [[ \"$1\" == \"--new\" ]]; then\n  mkdir -p ~/.susedko_new\n  sshfs ai@sused"
  },
  {
    "path": "bin/private",
    "chars": 271,
    "preview": "#!/bin/sh\n# Private encrypted folder\n\nSTORE=$HOME/Документы/.Private\nLINK=$HOME/Private\n\nif [ -e \"$LINK\" ]; then\n  # Loc"
  },
  {
    "path": "bin/restore-gnome-extensions",
    "chars": 648,
    "preview": "#!/bin/bash\n\nbackup_dir=\"$HOME/.local/share/gnome-shell-extensions-settings\"\n\nif [ ! -d \"$backup_dir\" ]; then\n  echo \"Se"
  },
  {
    "path": "bin/susedko",
    "chars": 444,
    "preview": "#!/bin/bash\n\nif nmcli -t -f TYPE,STATE device | grep -q \"^ethernet:connected\"; then\n  home_ip=$(timeout 1 getent hosts h"
  },
  {
    "path": "bin/susedko-listener",
    "chars": 705,
    "preview": "#!/bin/bash\n\nsource ~/Dev/susedko/secrets.env\nMQTT_BROKER=\"192.168.50.125\"\n\nmosquitto_sub -h \"$MQTT_BROKER\" -t ai_laptop"
  },
  {
    "path": "bin/update",
    "chars": 764,
    "preview": "#!/bin/zsh\n\nset -e\n\nTITLE='\\033[0;32m\\033[1m'\nGRAY='\\033[0;90m'\nNC='\\033[0m'\n\necho -e \"${TITLE}Обновление системы${NC}\"\n"
  },
  {
    "path": "bin/update-devcontainer-configs",
    "chars": 294,
    "preview": "#!/bin/bash\n\nfor dir in ~/Dev/*/; do\n  target_file=\"${dir}.devcontainer.json\"\n  if [[ -f \"$target_file\" ]]; then\n    if "
  },
  {
    "path": "bin/update-dockerfile",
    "chars": 1463,
    "preview": "#!/bin/zsh\n\nDOCKERFILE_PATH=\"/home/ai/Dev/environment/devcontainer/Dockerfile\"\n\nlatest_node=$(curl -s \"https://nodejs.or"
  },
  {
    "path": "bin/update-extension-lists",
    "chars": 2648,
    "preview": "#!/usr/bin/env node\n\nlet { readFile, writeFile } = require('fs/promises')\nlet { join } = require('path')\nlet { promisify"
  },
  {
    "path": "bin/zed-isolate",
    "chars": 1207,
    "preview": "#!/bin/bash\n\nset -e\n\nLOG_FILE=\"/var/run/user/1000/zed-isolate.log\"\n\nshow_error_log() {\n  if [ -f \"$LOG_FILE\" ]; then\n   "
  },
  {
    "path": "bin/zoom",
    "chars": 352,
    "preview": "#!/bin/zsh\n\nsource ~/Dev/environment/secrets.env\n\ncall_scene() {\n  curl -s -S -f \\\n    -H \"Authorization: Bearer $HA_TOK"
  },
  {
    "path": "devcontainer/Dockerfile",
    "chars": 4742,
    "preview": "FROM registry.fedoraproject.org/fedora:44\n\nENV NODE_VERSION=25.9.0 \\\n  PNPM_VERSION=11.0.0 \\\n  NODE_24=24.15.0 \\\n  NODE_"
  },
  {
    "path": "devcontainer/devcontainer.json",
    "chars": 338,
    "preview": "{\n  \"image\": \"localhost/ai-opensource:latest\",\n  \"mounts\": [\n    {\n      \"source\": \"pnpm-store\",\n      \"target\": \"/home/"
  },
  {
    "path": "devcontainer/install-dotfiles",
    "chars": 5403,
    "preview": "#!/bin/sh\n\nMICRO_VERSION=\"2.0.15\"\nDIFFT_VERSION=\"0.68.0\"\nBAT_VERSION=\"0.26.1\"\nRG_VERSION=\"15.1.0\"\nATUIN_VERSION=\"18.13.3"
  },
  {
    "path": "gitconfig",
    "chars": 1027,
    "preview": "[user]\n  name  = Andrey Sitnik\n  email = andrey@sitnik.es\n  signingKey = key::ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHfKri"
  },
  {
    "path": "gitignore",
    "chars": 52,
    "preview": ".pnpm-*.log\n.npm-release/\n.zed\n.eslintcache\n.claude\n"
  },
  {
    "path": "hooks-trap/applypatch-msg",
    "chars": 258,
    "preview": "#!/bin/bash\n\nproject_hooks=$(git config get --local core.hooksPath)\nif [ -n \"$project_hooks\" ] && [ -d \"$project_hooks\" "
  },
  {
    "path": "hooks-trap/commit-msg",
    "chars": 250,
    "preview": "#!/bin/bash\n\nproject_hooks=$(git config get --local core.hooksPath)\nif [ -n \"$project_hooks\" ] && [ -d \"$project_hooks\" "
  },
  {
    "path": "hooks-trap/post-applypatch",
    "chars": 260,
    "preview": "#!/bin/bash\n\nproject_hooks=$(git config get --local core.hooksPath)\nif [ -n \"$project_hooks\" ] && [ -d \"$project_hooks\" "
  },
  {
    "path": "hooks-trap/post-checkout",
    "chars": 256,
    "preview": "#!/bin/bash\n\nproject_hooks=$(git config get --local core.hooksPath)\nif [ -n \"$project_hooks\" ] && [ -d \"$project_hooks\" "
  },
  {
    "path": "hooks-trap/post-commit",
    "chars": 252,
    "preview": "#!/bin/bash\n\nproject_hooks=$(git config get --local core.hooksPath)\nif [ -n \"$project_hooks\" ] && [ -d \"$project_hooks\" "
  },
  {
    "path": "hooks-trap/post-merge",
    "chars": 250,
    "preview": "#!/bin/bash\n\nproject_hooks=$(git config get --local core.hooksPath)\nif [ -n \"$project_hooks\" ] && [ -d \"$project_hooks\" "
  },
  {
    "path": "hooks-trap/post-rewrite",
    "chars": 254,
    "preview": "#!/bin/bash\n\nproject_hooks=$(git config get --local core.hooksPath)\nif [ -n \"$project_hooks\" ] && [ -d \"$project_hooks\" "
  },
  {
    "path": "hooks-trap/pre-applypatch",
    "chars": 258,
    "preview": "#!/bin/bash\n\nproject_hooks=$(git config get --local core.hooksPath)\nif [ -n \"$project_hooks\" ] && [ -d \"$project_hooks\" "
  },
  {
    "path": "hooks-trap/pre-auto-gc",
    "chars": 252,
    "preview": "#!/bin/bash\n\nproject_hooks=$(git config get --local core.hooksPath)\nif [ -n \"$project_hooks\" ] && [ -d \"$project_hooks\" "
  },
  {
    "path": "hooks-trap/pre-commit",
    "chars": 250,
    "preview": "#!/bin/bash\n\nproject_hooks=$(git config get --local core.hooksPath)\nif [ -n \"$project_hooks\" ] && [ -d \"$project_hooks\" "
  },
  {
    "path": "hooks-trap/pre-merge-commit",
    "chars": 262,
    "preview": "#!/bin/bash\n\nproject_hooks=$(git config get --local core.hooksPath)\nif [ -n \"$project_hooks\" ] && [ -d \"$project_hooks\" "
  },
  {
    "path": "hooks-trap/pre-push",
    "chars": 246,
    "preview": "#!/bin/bash\n\nproject_hooks=$(git config get --local core.hooksPath)\nif [ -n \"$project_hooks\" ] && [ -d \"$project_hooks\" "
  },
  {
    "path": "hooks-trap/pre-rebase",
    "chars": 250,
    "preview": "#!/bin/bash\n\nproject_hooks=$(git config get --local core.hooksPath)\nif [ -n \"$project_hooks\" ] && [ -d \"$project_hooks\" "
  },
  {
    "path": "hooks-trap/prepare-commit-msg",
    "chars": 266,
    "preview": "#!/bin/bash\n\nproject_hooks=$(git config get --local core.hooksPath)\nif [ -n \"$project_hooks\" ] && [ -d \"$project_hooks\" "
  },
  {
    "path": "icons/Zoom.desktop",
    "chars": 545,
    "preview": "[Desktop Entry]\nName=Zoom\nComment=Zoom Video Conference\nExec=/home/ai/Dev/environment/bin/zoom @@u %U @@\nIcon=Zoom\nTermi"
  },
  {
    "path": "icons/backup.desktop",
    "chars": 293,
    "preview": "[Desktop Entry]\nType=Application\nName=Резервное копирование\nComment=Backup\nIcon=/home/ai/.local/share/applications/backu"
  },
  {
    "path": "icons/com.mattjakeman.ExtensionManager.desktop",
    "chars": 548,
    "preview": "[Desktop Entry]\nName=Расширения\nExec=/usr/bin/flatpak run --branch=stable --arch=x86_64 --command=extension-manager --fi"
  },
  {
    "path": "icons/com.nextcloud.desktopclient.nextcloud.desktop",
    "chars": 760,
    "preview": "[Desktop Entry]\nCategories=Utility;X-SuSE-SyncUtility;\nType=Application\nExec=nextcloud %u\nName=Nextcloud\nComment=Настоль"
  },
  {
    "path": "icons/hu.irl.cameractrls.desktop",
    "chars": 450,
    "preview": "[Desktop Entry]\nType=Application\nVersion=1.0\nName=Настройки камеры\nComment=Camera controls for Linux\nExec=/usr/bin/flatp"
  },
  {
    "path": "icons/porn.desktop",
    "chars": 470,
    "preview": "[Desktop Entry]\nType=Application\nName=Эротика\nComment=Play porn movies\nIcon=strawberry\nExec=/home/ai/Dev/environment/bin"
  },
  {
    "path": "icons/private.desktop",
    "chars": 174,
    "preview": "[Desktop Entry]\nType=Application\nName=Личная папка\nComment=Decrypt safe storage\nIcon=/home/ai/.local/share/applications/"
  },
  {
    "path": "icons/update.desktop",
    "chars": 221,
    "preview": "[Desktop Entry]\nType=Application\nName=Обновление системы\nComment=Update RPM, Flatpak, and Mozilla Theme\nIcon=org.fedorap"
  },
  {
    "path": "icons/zed-isolate.desktop",
    "chars": 187,
    "preview": "[Desktop Entry]\nType=Application\nName=Zed Dev Container\nIcon=zed\nExec=/home/ai/Dev/environment/bin/zed-isolate %U\nMimeTy"
  },
  {
    "path": "micro.json",
    "chars": 55,
    "preview": "{\n    \"colorscheme\": \"simple\",\n    \"mkparents\": true\n}\n"
  },
  {
    "path": "mimeapps.list",
    "chars": 6818,
    "preview": "[Added Associations]\nx-scheme-handler/sms=org.gnome.Shell.Extensions.GSConnect.desktop;\nx-scheme-handler/tel=org.gnome.S"
  },
  {
    "path": "mpv-input.conf",
    "chars": 62,
    "preview": "й quit\nа cycle fullscreen\nMOUSE_BTN3 ignore\nMOUSE_BTN4 ignore\n"
  },
  {
    "path": "mpv.conf",
    "chars": 29,
    "preview": "slang=ru\nalang=jpn,ja,eng,en\n"
  },
  {
    "path": "pnpm-config.yaml",
    "chars": 132,
    "preview": "blockExoticSubdeps: true\nminimumReleaseAge: 1440\nstoreDir: ~/.local/share/pnpm/store\ntrustPolicy: true\ntrustPolicyIgnore"
  },
  {
    "path": "ripgreprc",
    "chars": 64,
    "preview": "--smart-case\n--glob=!.git/\n--glob=!.yarn/\n--hidden\n--no-heading\n"
  },
  {
    "path": "sshconfig",
    "chars": 450,
    "preview": "Host *\n    ForwardAgent no\n\nHost github.com\n    HostName github.com\n    User git\n    IdentityFile ~/.ssh/id_ed25519\n\nHos"
  },
  {
    "path": "starship.toml",
    "chars": 248,
    "preview": "format = \"\"\"\n$username\\\n$hostname\\\n$container\\\n$shlvl\\\n$directory\\\n$git_branch\\\n$git_commit\\\n$git_state\\\n$git_metrics\\\n$"
  },
  {
    "path": "zed-keys.json",
    "chars": 240,
    "preview": "[\n  {\n    \"bindings\": {\n      \"ctrl-q\": null\n    }\n  },\n  {\n    \"context\": \"Terminal\",\n    \"bindings\": {\n      \"ctrl-s\":"
  },
  {
    "path": "zed.json",
    "chars": 4284,
    "preview": "{\n  \"outline_panel\": {\n    \"dock\": \"left\"\n  },\n  \"collaboration_panel\": {\n    \"dock\": \"left\"\n  },\n  \"git_panel\": {\n    \""
  },
  {
    "path": "zshrc",
    "chars": 3683,
    "preview": "# History\nHISTSIZE=10000\nSAVEHIST=10000\nHISTFILE=~/.local/share/history/histfile\nsetopt appendhistory\nsetopt inc_append_"
  }
]

About this extraction

This page contains the full source code of the ai/environment GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 66 files (77.6 KB), approximately 25.0k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!