hypervibed

This commit is contained in:
2026-05-25 03:01:46 +03:00
parent 3de3d9c94a
commit 810e8cc7f2
13 changed files with 625 additions and 27 deletions
+94
View File
@@ -0,0 +1,94 @@
name: Build and Package dnc
on:
push:
tags:
- 'v*'
pull_request:
workflow_dispatch:
inputs:
version:
description: 'Version to build (e.g., 0.3.0)'
required: false
default: ''
env:
KITTY_VERSION: '0.46.2'
GO_VERSION: '1.22'
jobs:
build-packages:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Determine version
id: version
shell: bash
run: |
if [ -n "${{ inputs.version }}" ]; then
VERSION="${{ inputs.version }}"
elif [[ "${{ github.ref }}" == refs/tags/v* ]]; then
VERSION="${GITHUB_REF_NAME#v}"
else
VERSION="0.2.0-$(git rev-parse --short HEAD)"
fi
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
- name: Download kitty binary
run: |
set -e
mkdir -p build
KITTY_ARCHIVE="kitty-${KITTY_VERSION}-x86_64.txz"
KITTY_URL="https://github.com/kovidgoyal/kitty/releases/download/v${KITTY_VERSION}/${KITTY_ARCHIVE}"
echo "Downloading kitty from: $KITTY_URL"
curl -fL "$KITTY_URL" -o "build/$KITTY_ARCHIVE"
tar -xJf "build/$KITTY_ARCHIVE" -C build/
mv build/kitty.app build/kitty
ls -la build/
ls -la build/kitty/bin/
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '${{ env.GO_VERSION }}'
- name: Install nfpm
run: |
go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest
export PATH="$PATH:$(go env GOPATH)/bin"
nfpm --version
- name: Build DEB package
env:
VERSION: '${{ steps.version.outputs.VERSION }}'
run: |
export PATH="$PATH:$(go env GOPATH)/bin"
mkdir -p dist
nfpm package \
--packager deb \
--config packaging/nfpm.yaml \
--target dist/
- name: Build RPM package
env:
VERSION: '${{ steps.version.outputs.VERSION }}'
run: |
export PATH="$PATH:$(go env GOPATH)/bin"
mkdir -p dist
nfpm package \
--packager rpm \
--config packaging/nfpm.yaml \
--target dist/
- name: List artifacts
run: |
echo "Packages built:"
ls -lh dist/
- name: Upload packages as artifacts
uses: actions/upload-artifact@v4
with:
name: dnc-packages
path: dist/
+138 -2
View File
@@ -1,3 +1,139 @@
# dockernecontainer
# dockernecontainer (dnc)
Dockernecontainer is a helper for creating and managing virtual development environments.
Containerized per-project development environments with TUI and GPU support.
## Dependencies
**Required**:
- Linux with **rootful** Docker (≥20.10). Rootless Docker is detected and rejected.
- Project directory you want to containerize
**GPU (choose what applies)**:
- NVIDIA: `nvidia-smi` on PATH + `nvidia-container-toolkit` installed
- Intel/AMD DRI: `/dev/dri` present on host (auto-detected)
- AMD compute (KFD): `/dev/kfd` present on host (auto-detected)
## Usage
```bash
# Create container from an image with your tools
dnc setup --image ghcr.io/lstmnemodel/dnc-test-arch:latest
# Launch bundled kitty terminal (all tabs/splits exec into container)
dnc
# Non-graphical fallback (useful for SSH sessions without display)
dnc -- /bin/bash
# Run a command in container (non-interactive or interactive)
dnc -- pacman -Syu
# Show container details
dnc info
# List all containers
dnc list
# Remove container
dnc rm
```
Each project directory gets its own container. A `.dnc` file in the project root tracks the container name. `dnc` walks up the directory tree to find it.
## How It Works
When you run `dnc` with no arguments:
1. **Finds your project**: Walks up from `$PWD` to find `.dnc` file
2. **Extracts kitty config**: Copies `~/.config/kitty/` from INSIDE your project container
3. **Launches kitty**: Bundled kitty terminal with config from container
4. **Every new tab/window**: Automatically calls `docker exec -it` into your container
Kitty runs on your host (for GPU rendering and display), but every shell you open in it runs inside your project container via `docker exec`.
## What gets forwarded
| Category | What |
|----------|------|
| Network | `--network=host`, `--pid=host`, `--ipc=host` |
| GPU | `--gpus all` (NVIDIA), `/dev/dri` bind-mount (Intel/AMD DRI), `/dev/kfd` (AMD compute) |
| Runtime dirs | `/tmp`, `/run/user/$UID` (for clipboard, temp files) |
| Git / SSH | SSH agent socket forwarded; `~/.ssh/`, `~/.gitconfig`, `~/.git-credentials` mounted at `/run/host/ssh`, `/run/host/gitconfig`, `/run/host/git-credentials` |
| User config | `~/.config/dnc/` mounted read-write at `/run/host/config/` — images can read `dnc.toml` for colors, keybinds, IDE settings |
| Shell history | Per-container history persists across rebuilds (`HISTFILE` set for bash/zsh, fish) |
| nvim state | Per-container swap/undo persists across rebuilds (`~/.local/state/nvim`) |
| Home | Fresh container home (not host bind-mount). Host home mounted read-only at `/run/host/home` |
| Host env | All host environment variables dumped to `/run/host/env` (shell-sourceable) |
| Project dir | Bind-mounted read-write at its host path |
| Sudo | Installed automatically via `pacman`/`dnf`/`apt`/etc., NOPASSWD for the container user |
## Kitty Configuration
**Kitty config lives inside your project container**, not on the host:
```
Inside container: ~/.config/kitty/kitty.conf
```
This way:
- Different projects can have different kitty configs
- Config travels with your container image
- New tabs automatically exec into your container (dnc overrides the `shell` directive)
If no config is found in the container, kitty runs with defaults plus the dnc exec wrapper.
## Extensibility via /run/host
dnc provides host data at well-known paths inside the container for optional integration:
| Path | Description |
|------|-------------|
| `/run/host/home` | Read-only bind-mount of host `$HOME` |
| `/run/host/env` | Shell-sourceable dump of all host environment variables |
| `/run/host/config` | Read-write bind-mount of `~/.config/dnc/` — user IDE config |
| `/run/host/ssh` | Read-only bind-mount of `~/.ssh/` |
| `/run/host/gitconfig` | Read-only bind-mount of `~/.gitconfig` (if present) |
| `/run/host/git-credentials` | Read-only bind-mount of `~/.git-credentials` (if present) |
| `/run/host/kitty` | Read-only mount of bundled kitty bundle — provides `kitten` binary, terminfo, and `kitten run-shell` for shell integration |
| `/run/host/state/history` | Per-container shell history (persists across rebuilds) |
| `/run/host/state/nvim` | Per-container nvim swap/undo files (persists across rebuilds) |
### Config convention
Images are expected to read `/run/host/config/dnc.toml` (if present) to generate native config files for the IDE. This lets you swap images while keeping your colors, keybinds, and preferences — write once in TOML, use across any compliant image.
### Git / SSH
SSH agent socket is forwarded automatically via `$SSH_AUTH_SOCK`. Git operations (clone, push, pull) work inside the container without additional setup if your host has SSH keys loaded and `gitconfig` configured.
### Kitty shell integration
When `TERM=xterm-kitty` and the bundled kitty bundle is available, `entry.sh` automatically delegates to `kitten run-shell`. This gives you:
- Correct terminfo (`xterm-kitty`) — neovim and TUIs get true color, italics, styled underlines, cursor shapes
- Shell integration — directory tracking in window title, clickable file paths, scroll marks
- Clean shutdown — processes exit properly on window close (no warning dialog)
No image-side configuration needed. The fallback (when `TERM` is not `xterm-kitty` or the bundle is absent) launches the user's login shell directly.
## Limitations
- **Rootful Docker only**: Rootless lacks the `--pid=host` capabilities dnc relies on.
- **Container user = host uid**: UID 1:1 mapping (required for rootful Docker). The container user gets `NOPASSWD` sudo so package installs still work.
- **No `--init` or systemd**: PID 1 is `init.sh`, not init/systemd. `systemctl` won't work.
## Commands
```
dnc Launch kitty (bundled) with container context
dnc -- Non-graphical interactive shell (docker exec)
dnc -- <cmd> Run command in container
dnc setup [--image IMG] Create container for this project
dnc rm Remove container + .dnc
dnc list List all dnc containers
dnc info Show container details
dnc web Show web IDE URL (if web_port set in .dnc)
dnc agent [--opencode] [--cursor] Create DNC.md + agent rules
dnc version Show version
dnc help Show this help
```
+36 -4
View File
@@ -3,6 +3,22 @@ set -e
IMAGE="${DNC_IMAGE:-ghcr.io/lstmnemodel/dnc:latest}"
if [ $# -eq 0 ]; then
if [ -x "/opt/dnc/libexec/dnc-kitty-launcher" ]; then
exec /opt/dnc/libexec/dnc-kitty-launcher
else
script_dir="$(cd "$(dirname "$0")" && pwd)"
if [ -x "$script_dir/../libexec/dnc-kitty-launcher" ]; then
exec "$script_dir/../libexec/dnc-kitty-launcher"
elif command -v dnc-kitty-launcher >/dev/null 2>&1; then
exec dnc-kitty-launcher
else
echo "Error: dnc-kitty-launcher not found" >&2
exit 1
fi
fi
fi
GPU=none
if command -v nvidia-smi >/dev/null 2>&1; then
GPU=nvidia
@@ -25,13 +41,26 @@ fi
DNC_CACHE="${XDG_CACHE_HOME:-$HOME/.cache}/dnc"
mkdir -p "$DNC_CACHE"
DNC_CONFIG="${XDG_CONFIG_HOME:-$HOME/.config}/dnc"
mkdir -p "$DNC_CONFIG"
printenv > "$DNC_CACHE/host.env"
TTY_FLAG=""
[ -t 0 ] && TTY_FLAG="-t"
# SSH agent socket forwarding
SSH_SOCK="${SSH_AUTH_SOCK:-}"
# Kitvy bundle path (for kitten run-shell inside containers)
DNC_KITTY_PATH=""
[ -d /opt/dnc/kitty ] && DNC_KITTY_PATH=/opt/dnc/kitty
exec docker run --rm -i ${TTY_FLAG} \
-v "$DOCKER_SOCK:/var/run/docker.sock:ro" \
-v "$PWD:$PWD" -w "$PWD" \
-v "$DNC_CACHE:/opt/dnc/host:rw" \
-v "$DNC_CACHE/host.env:/run/host/env:ro" \
-e "DNC_HOST_GPU=$GPU" \
-e "DNC_HOST_DRI=$DRI" \
-e "DNC_HOST_KFD=$KFD" \
@@ -42,8 +71,11 @@ exec docker run --rm -i ${TTY_FLAG} \
-e "DNC_HOST_SHELL=$SHELL" \
-e "DNC_HOST_GIDS=$(id -G)" \
-e "DNC_CACHE_HOST=$DNC_CACHE" \
-e DISPLAY -e WAYLAND_DISPLAY -e XAUTHORITY \
-e DBUS_SESSION_BUS_ADDRESS -e XDG_RUNTIME_DIR \
-e PULSE_SERVER -e PIPEWIRE_RUNTIME_DIR \
-e SSH_AUTH_SOCK -e TERM -e LANG \
-e "DNC_CONFIG_HOST=$DNC_CONFIG" \
-e "DNC_HOST_SSH=$HOME/.ssh" \
-e "DNC_HOST_GITCONFIG=$HOME/.gitconfig" \
-e "DNC_HOST_GITCRED=$HOME/.git-credentials" \
${DNC_KITTY_PATH:+-e "DNC_KITTY_PATH=$DNC_KITTY_PATH"} \
${SSH_SOCK:+-e "SSH_AUTH_SOCK=$SSH_SOCK"} \
-e TERM -e LANG \
"$IMAGE" "$@"
+26
View File
@@ -0,0 +1,26 @@
#!/bin/bash
# dnc-exec - Kitty shell wrapper for dnc containerized mode
if [ -z "$DNC_CONTAINER" ]; then
echo "Error: DNC_CONTAINER environment variable not set" >&2
echo "This script should be run via dnc-kitty-launcher" >&2
exit 1
fi
workdir="$PWD"
SSH_ARGS=""
[ -n "$SSH_AUTH_SOCK" ] && SSH_ARGS="-e SSH_AUTH_SOCK=$SSH_AUTH_SOCK"
if [ $# -eq 0 ]; then
exec docker exec -it $SSH_ARGS -w "$workdir" "$DNC_CONTAINER" /usr/bin/dnc-entry
else
for arg in "$@"; do
case "$arg" in
*'|'*|*'&'*|*';'*|*'<'*|*'>'*|*'$'*|*'`'*|*'"'*|*"'"*)
exec docker exec -it $SSH_ARGS -w "$workdir" "$DNC_CONTAINER" sh -c "$*"
;;
esac
done
exec docker exec -it $SSH_ARGS -w "$workdir" "$DNC_CONTAINER" "$@"
fi
+92
View File
@@ -0,0 +1,92 @@
#!/bin/bash
# dnc-kitty-launcher - Launch kitty with container context
find_dnc_file() {
local dir="$PWD"
while [ "$dir" != "/" ]; do
if [ -f "$dir/.dnc" ]; then
echo "$dir/.dnc"
return
fi
dir="$(dirname "$dir")"
done
}
dnc_file=$(find_dnc_file)
if [ -z "$dnc_file" ]; then
echo "Error: .dnc file not found. Run 'dnc setup' first." >&2
exit 1
fi
container=""
dnc_dir="$(dirname "$dnc_file")"
while IFS= read -r line; do
case "$line" in
container*)
container="$(echo "$line" | cut -d= -f2 | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
;;
esac
done < "$dnc_file"
if [ -z "$container" ]; then
echo "Error: container= not found in $dnc_file" >&2
exit 1
fi
container_status=$(docker inspect --format='{{.State.Status}}' "$container" 2>/dev/null || true)
if [ "$container_status" != "running" ]; then
echo "Starting container $container..." >&2
docker start "$container" >/dev/null
fi
tmpdir=$(mktemp -d -t dnc-kitty-XXXXXX)
cleanup() { rm -rf "$tmpdir"; }
trap cleanup EXIT
uid=$(id -u)
container_home=$(docker exec "$container" sh -c "
user_name=\$(getent passwd $uid | cut -d: -f1 2>/dev/null || echo '')
if [ -z \"\$user_name\" ]; then
echo /root
else
eval echo ~\$user_name
fi
")
config_src="$container_home/.config/kitty"
docker cp "$container:$config_src/." "$tmpdir/" 2>/dev/null || true
if [ -x "/opt/dnc/kitty/bin/kitty" ]; then
kitty="/opt/dnc/kitty/bin/kitty"
elif command -v kitty >/dev/null 2>&1; then
kitty="kitty"
else
echo "Error: kitty not found (not installed and no system kitty)" >&2
exit 1
fi
mkdir -p "$tmpdir"
if [ -x "/opt/dnc/libexec/dnc-exec" ]; then
dnc_exec="/opt/dnc/libexec/dnc-exec"
else
script_dir="$(cd "$(dirname "$0")" && pwd)"
dnc_exec="$script_dir/dnc-exec"
fi
if [ -f "$tmpdir/kitty.conf" ]; then
echo "" >> "$tmpdir/kitty.conf"
echo "# dnc: all tabs go through docker exec" >> "$tmpdir/kitty.conf"
else
:
fi
echo "shell $dnc_exec" >> "$tmpdir/kitty.conf"
export KITTY_CONFIG_DIRECTORY="$tmpdir"
export DNC_CONTAINER="$container"
cd "$dnc_dir" || exit 1
exec "$kitty" "$@"
+64
View File
@@ -0,0 +1,64 @@
name: "dnc"
arch: "amd64"
platform: "linux"
version: "${VERSION}"
section: "devel"
priority: "optional"
maintainer: "dnc"
description: |
dockernecontainer - Containerized per-project development environments.
TUI-focused with bundled kitty terminal. All tabs/splits run via
docker exec inside a project container.
vendor: "dnc"
license: "MIT"
homepage: "https://projects.vibe4d.com/lstmnemodel/nvimnemodel"
contents:
- src: build/kitty/
dst: /opt/dnc/kitty/
type: tree
file_info:
mode: 0755
- src: bin/dnc
dst: /usr/bin/dnc
type: file
file_info:
mode: 0755
- src: libexec/dnc-kitty-launcher
dst: /opt/dnc/libexec/dnc-kitty-launcher
type: file
file_info:
mode: 0755
- src: libexec/dnc-exec
dst: /opt/dnc/libexec/dnc-exec
type: file
file_info:
mode: 0755
- src: src/dnc/
dst: /opt/dnc/lib/dnc/
type: tree
file_info:
mode: 0644
- src: README.md
dst: /usr/share/doc/dnc/README.md
type: file
overrides:
deb:
depends:
- docker-ce | docker.io | containerd.io
provides:
- dnc
rpm:
depends:
- docker
provides:
- dnc
scripts:
postinstall: packaging/scripts/postinst
+28
View File
@@ -0,0 +1,28 @@
#!/bin/bash
set -e
cat <<'EOF'
dnc installed successfully!
Quick start:
dnc setup --image <image> Create container for your project
dnc Launch bundled kitty in container mode
dnc -- /bin/bash Non-graphical shell (for SSH/no-display)
dnc -- <command> Run command in container
dnc help Show full help
Installed files:
/usr/bin/dnc Main command
/opt/dnc/kitty/ Bundled kitty terminal (v0.46.2)
/opt/dnc/lib/dnc/ Python CLI modules
/opt/dnc/libexec/ Helper scripts
Kitty configuration:
Kitty config is read from INSIDE your project container:
~/.config/kitty/kitty.conf
New tabs in kitty automatically exec into your project container via docker.
EOF
exit 0
+17
View File
@@ -14,6 +14,14 @@ INIT_DST = f"{HOST_CACHE}/init.sh"
ENTRY_SRC = "/opt/dnc/lib/dnc/entry.sh"
ENTRY_DST = f"{HOST_CACHE}/entry.sh"
# Inside project container paths
CONFIG_DIR = "/run/host/config"
STATE_DIR = "/run/host/state"
SSH_DIR = "/run/host/ssh"
GITCONFIG = "/run/host/gitconfig"
GITCRED = "/run/host/git-credentials"
# Env vars set by bin/dnc for the CLI container
HOST_GPU = "DNC_HOST_GPU"
HOST_DRI = "DNC_HOST_DRI"
HOST_KFD = "DNC_HOST_KFD"
@@ -24,3 +32,12 @@ HOST_HOME = "DNC_HOST_HOME"
HOST_SHELL = "DNC_HOST_SHELL"
HOST_CACHE_HOST = "DNC_CACHE_HOST"
HOST_GIDS = "DNC_HOST_GIDS"
HOST_CONFIG = "DNC_CONFIG_HOST"
HOST_STATE = "DNC_STATE_HOST"
HOST_SSH = "DNC_HOST_SSH"
HOST_GITCONFIG = "DNC_HOST_GITCONFIG"
HOST_GITCRED = "DNC_HOST_GITCRED"
HOST_KITTY_PATH = "DNC_KITTY_PATH"
# Inside project container paths
KITTY_DIR = "/run/host/kitty"
+11
View File
@@ -8,6 +8,17 @@ run ALL commands inside the container by prefixing them with `dnc -`:
dnc - nvim
dnc - npm install
dnc - python manage.py migrate
## Config
User config lives in `~/.config/dnc/` (mounted at `/run/host/config/`).
Images can read `/run/host/config/dnc.toml` for colors, keybinds, etc.
## Git / SSH
SSH agent socket is forwarded automatically. SSH keys from `~/.ssh/`
and gitconfig from `~/.gitconfig` are available inside the container.
git push/pull works without additional setup.
"""
OPENCODE_INSTRUCTIONS = """## dnc
+14
View File
@@ -52,6 +52,7 @@ Usage:
dnc rm Remove container + .dnc
dnc list List all dnc containers
dnc info Show container details
dnc web Show web IDE URL (if applicable)
dnc agent [--opencode] [--cursor] Create DNC.md + agent rules
dnc version Show version
dnc help Show this help""")
@@ -157,6 +158,19 @@ def main():
agents_mod.create_cursor(os.getcwd())
return
if cmd == "web":
dnc_dir, name = resolve_container_name()
if name is None:
print("No .dnc found.")
sys.exit(1)
port = _read_field(dnc_dir, "web_port")
if port:
print(f"http://localhost:{port}")
else:
print(f"Container '{name}' is running with --network=host.")
print("No web_port configured in .dnc. Add 'web_port = <port>' to use 'dnc web'.")
return
if cmd == "rm":
dnc_dir, name = resolve_container_name()
if name is None:
+60 -17
View File
@@ -11,37 +11,38 @@ from docker.types import DeviceRequest
from dnc import (
__version__,
CONFIG_DIR,
ENTRY_DST,
ENTRY_SRC,
GITCONFIG,
GITCRED,
HOST_CACHE,
HOST_CACHE_HOST,
HOST_CONFIG,
HOST_DRI,
HOST_GID,
HOST_GIDS,
HOST_GITCONFIG,
HOST_GITCRED,
HOST_HOME,
HOST_KFD,
HOST_KITTY_PATH,
HOST_SHELL,
HOST_SSH,
HOST_STATE,
HOST_UID,
HOST_USER,
HOST_GPU,
INIT_DST,
INIT_SRC,
KITTY_DIR,
SSH_DIR,
STATE_DIR,
)
_FORWARD_ENV = {
"DISPLAY",
"WAYLAND_DISPLAY",
"XAUTHORITY",
"XDG_SESSION_TYPE",
"DBUS_SESSION_BUS_ADDRESS",
"XDG_RUNTIME_DIR",
"PULSE_SERVER",
"PIPEWIRE_RUNTIME_DIR",
"SSH_AUTH_SOCK",
"TERM",
"LANG",
"NVIDIA_VISIBLE_DEVICES",
"NVIDIA_DRIVER_CAPABILITIES",
}
_SKIP_ENV = {
@@ -61,6 +62,12 @@ _SKIP_ENV = {
HOST_HOME,
HOST_SHELL,
HOST_CACHE_HOST,
HOST_CONFIG,
HOST_STATE,
HOST_SSH,
HOST_GITCONFIG,
HOST_GITCRED,
HOST_KITTY_PATH,
}
@@ -81,6 +88,17 @@ def _host_cache_setup():
os.chmod(ENTRY_DST, 0o755)
def _state_dir_setup(name: str):
host_cache = os.environ.get(HOST_CACHE_HOST, "")
if not host_cache:
return "", ""
cli_state = os.path.join(HOST_CACHE, "state", name)
for sub in ("history", "nvim"):
os.makedirs(os.path.join(cli_state, sub), exist_ok=True)
host_state = os.path.join(host_cache, "state", name)
return host_state, host_state
def _default_container_name(project_dir: str) -> str:
safe = re.sub(r"[^a-zA-Z0-9_-]", "_", os.path.basename(project_dir))
h = hashlib.sha256(project_dir.encode()).hexdigest()[:8]
@@ -135,15 +153,38 @@ def create(image: str, name: str, project_dir: str):
project_dir: {"bind": project_dir, "mode": "rw"},
"/tmp": {"bind": "/tmp", "mode": "rw"},
f"/run/user/{uid}": {"bind": f"/run/user/{uid}", "mode": "rw"},
"/tmp/.X11-unix": {"bind": "/tmp/.X11-unix", "mode": "rw"},
"/etc/hosts": {"bind": "/etc/hosts", "mode": "ro"},
"/etc/resolv.conf": {"bind": "/etc/resolv.conf", "mode": "ro"},
f"{host_cache}/host.env": {"bind": "/run/host/env", "mode": "ro"},
f"{host_cache}/init.sh": {"bind": "/usr/bin/dnc-init", "mode": "ro"},
f"{host_cache}/entry.sh": {"bind": "/usr/bin/dnc-entry", "mode": "ro"},
}
if os.path.exists("/etc/hostname"):
volumes["/etc/hostname"] = {"bind": "/etc/hostname", "mode": "ro"}
host_state, _ = _state_dir_setup(name)
if host_state:
volumes[host_state] = {"bind": STATE_DIR, "mode": "rw"}
host_config = os.environ.get(HOST_CONFIG, "")
if host_config:
volumes[host_config] = {"bind": CONFIG_DIR, "mode": "rw"}
host_ssh_path = os.environ.get(HOST_SSH, "")
if host_ssh_path:
volumes[host_ssh_path] = {"bind": SSH_DIR, "mode": "ro"}
host_gitconfig_path = os.environ.get(HOST_GITCONFIG, "")
if host_gitconfig_path:
volumes[host_gitconfig_path] = {"bind": GITCONFIG, "mode": "ro"}
host_gitcred_path = os.environ.get(HOST_GITCRED, "")
if host_gitcred_path:
volumes[host_gitcred_path] = {"bind": GITCRED, "mode": "ro"}
ssh_auth_sock = os.environ.get("SSH_AUTH_SOCK", "")
if ssh_auth_sock:
volumes[ssh_auth_sock] = {"bind": ssh_auth_sock, "mode": "rw"}
host_kitty_path = os.environ.get(HOST_KITTY_PATH, "")
if host_kitty_path:
volumes[host_kitty_path] = {"bind": KITTY_DIR, "mode": "ro"}
host_dri = os.environ.get(HOST_DRI, "")
host_kfd = os.environ.get(HOST_KFD, "")
@@ -162,7 +203,6 @@ def create(image: str, name: str, project_dir: str):
env = {
"HOME": host_home,
"SHELL": os.path.basename(shell),
"container": "docker",
"CONTAINER_ID": name,
HOST_UID: uid,
@@ -172,6 +212,9 @@ def create(image: str, name: str, project_dir: str):
HOST_SHELL: shell,
}
if ssh_auth_sock:
env["SSH_AUTH_SOCK"] = ssh_auth_sock
for key in _FORWARD_ENV:
val = os.environ.get(key)
if val:
+39 -1
View File
@@ -1,4 +1,5 @@
#!/bin/sh
# Legacy: copy .gitconfig/.ssh from host home read-only mount
if [ -d /run/host/home ]; then
for f in .gitconfig .ssh; do
src="/run/host/home/$f"
@@ -8,7 +9,44 @@ if [ -d /run/host/home ]; then
fi
done
fi
# SSH: symlink host ~/.ssh/* into container home
if [ -d /run/host/ssh ]; then
mkdir -p "$HOME/.ssh"
for f in /run/host/ssh/*; do
[ -f "$f" ] && ln -sf "$f" "$HOME/.ssh/" 2>/dev/null || true
done
fi
# Git: include host gitconfig for credential helpers, aliases, etc.
if [ -f /run/host/gitconfig ]; then
git config --global include.path /run/host/gitconfig 2>/dev/null || true
fi
# nvim state: persist swap/undo across rebuilds
if [ -d /run/host/state/nvim ]; then
mkdir -p "$HOME/.local/state"
ln -sfn /run/host/state/nvim "$HOME/.local/state/nvim"
fi
# Shell history: per-container, persists across rebuilds
if [ -d /run/host/state/history ]; then
case "${SHELL##*/}" in
bash) export HISTFILE=/run/host/state/history/bash_history ;;
zsh) export HISTFILE=/run/host/state/history/zsh_history ;;
fish) export _history_filename=/run/host/state/history/fish_history ;;
esac
fi
# Kitty shell integration via kitten run-shell
if [ -x /run/host/kitty/bin/kitten ] && [ "$TERM" = "xterm-kitty" ]; then
exec /run/host/kitty/bin/kitten run-shell
fi
export DNC_CONFIG=/run/host/config
if [ -x /opt/dnc/entrypoint.sh ]; then
exec /opt/dnc/entrypoint.sh
fi
exec "${SHELL:-/bin/bash}" -l
user_shell=$(getent passwd "$(id -u)" 2>/dev/null | cut -d: -f7)
exec "${user_shell:-${SHELL:-/bin/bash}}" -l
+6 -3
View File
@@ -17,14 +17,17 @@ if [ -n "$EXISTING_USER" ] && [ "$EXISTING_USER" != "$HOST_USER" ]; then
if [ -n "$EXISTING_GROUP" ] && [ "$EXISTING_GROUP" != "$HOST_USER" ]; then
groupmod -n "$HOST_USER" "$EXISTING_GROUP" 2>/dev/null || true
fi
usermod -l "$HOST_USER" -s /bin/bash -d "$HOST_HOME" \
usermod -l "$HOST_USER" -d "$HOST_HOME" \
-m "$EXISTING_USER" 2>/dev/null || true
elif [ -z "$EXISTING_USER" ]; then
useradd -M -u "$HOST_UID" -g "$HOST_GID" -s /bin/bash \
useradd -M -u "$HOST_UID" -g "$HOST_GID" \
-d "$HOST_HOME" "$HOST_USER" 2>/dev/null || true
fi
mkdir -p "$HOST_HOME"
chown "$HOST_UID:$HOST_GID" "$HOST_HOME" 2>/dev/null || true
if [ -d /etc/skel ] && [ -n "$(ls -A /etc/skel 2>/dev/null)" ]; then
cp -r /etc/skel/. "$HOST_HOME/" 2>/dev/null || true
fi
chown -R "$HOST_UID:$HOST_GID" "$HOST_HOME" 2>/dev/null || true
SUDO_USER="$HOST_USER"
if ! command -v sudo >/dev/null 2>&1; then