5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
# File 'lib/dkit/shell_hook.rb', line 5
def generate
<<~'ZSH'
# Generated by: dkit hook
# Add to ~/.zshrc: eval "$(dkit hook)"
_DKIT_ROOT=""
_DKIT_ACTIVE_CMDS=()
_DKIT_GLOB_PATTERNS=()
_DKIT_GLOB_CMDS=()
_dkit_reset() {
local cmd
for cmd in "${_DKIT_ACTIVE_CMDS[@]}"; do
unfunction "$cmd" 2>/dev/null
done
_DKIT_ACTIVE_CMDS=()
_DKIT_GLOB_PATTERNS=()
_DKIT_GLOB_CMDS=()
}
_dkit_verbose_fallback() {
[[ "${DKIT_VERBOSE}" == "0" || -z "${_DKIT_ROOT}" ]] && return
local _ic="${_DKIT_ROOT}/.devcontainer/dkit-intercept"
grep -qxF 'verbose: false' "$_ic" 2>/dev/null && return
printf '\033[31m[dkit] %s → host (fallback)\033[0m\n' "$1" >&2
}
_dkit_expand_glob() {
local root="$1" pattern="$2"
local full_pattern="$root/$pattern"
local matches=( ${~full_pattern}(N*) )
local m rel
for m in "${matches[@]}"; do
rel="${m#$root/}"
(( ${_DKIT_ACTIVE_CMDS[(Ie)$rel]} )) && continue
eval "function ${rel}() {
if dkit status --quiet 2>/dev/null; then
dkit run ${rel} \"\$@\"
else
_dkit_verbose_fallback \"${rel}\"
command ${rel} \"\$@\"
fi
}"
_DKIT_ACTIVE_CMDS+=("${rel}")
_DKIT_GLOB_CMDS+=("${rel}")
done
}
_dkit_refresh_globs() {
[[ -z "$_DKIT_ROOT" || ${#_DKIT_GLOB_PATTERNS[@]} -eq 0 ]] && return
local cmd
for cmd in "${_DKIT_GLOB_CMDS[@]}"; do
if [[ ! -e "$_DKIT_ROOT/$cmd" ]]; then
unfunction "$cmd" 2>/dev/null
_DKIT_ACTIVE_CMDS=("${(@)_DKIT_ACTIVE_CMDS:#$cmd}")
fi
done
_DKIT_GLOB_CMDS=()
local pat
for pat in "${_DKIT_GLOB_PATTERNS[@]}"; do
_dkit_expand_glob "$_DKIT_ROOT" "$pat"
done
}
_dkit_load() {
local root="$1"
local intercept="$root/.devcontainer/dkit-intercept"
[[ -f "$intercept" ]] || return
local cmd
while IFS= read -r cmd; do
[[ -z "$cmd" || "${cmd[1]}" == "#" ]] && continue
# Trim whitespace
cmd="${cmd## }"
cmd="${cmd%% }"
[[ -z "$cmd" ]] && continue
# Glob pattern: expand matching executables
if [[ "$cmd" == *[\*\?\[]* ]]; then
_DKIT_GLOB_PATTERNS+=("${cmd}")
_dkit_expand_glob "$root" "$cmd"
continue
fi
eval "function ${cmd}() {
if dkit status --quiet 2>/dev/null; then
dkit run ${cmd} \"\$@\"
else
_dkit_verbose_fallback \"${cmd}\"
command ${cmd} \"\$@\"
fi
}"
_DKIT_ACTIVE_CMDS+=("${cmd}")
done < "$intercept"
}
_dkit_chpwd() {
# Fast path: still inside the same project root
if [[ -n "$_DKIT_ROOT" && "$PWD" == "$_DKIT_ROOT"* ]]; then
return
fi
local new_root
new_root="$(dkit root 2>/dev/null || echo '')"
[[ "$new_root" == "$_DKIT_ROOT" ]] && return
_dkit_reset
_DKIT_ROOT="$new_root"
[[ -n "$new_root" ]] && _dkit_load "$new_root"
}
# Special commands — always available, always route to devcontainer
code() {
if dkit status --quiet 2>/dev/null; then
dkit code "$@"
else
_dkit_verbose_fallback "code"
command code "$@"
fi
}
claude() {
if dkit status --quiet 2>/dev/null; then
dkit claude "$@"
else
_dkit_verbose_fallback "claude"
command claude "$@"
fi
}
autoload -U add-zsh-hook
add-zsh-hook chpwd _dkit_chpwd
add-zsh-hook precmd _dkit_refresh_globs
_dkit_chpwd
ZSH
end
|