| name | doctor |
| description | Diagnose and fix oh-my-copilot installation issues. Checks plugin path, broken symlinks, dependencies (sqlite3/jq/git), hooks.json validity, script permissions, and plugin version. Trigger with "doctor", "์ง๋จ", "install check", "ํฌ์ค์ฒดํฌ", "health check". |
oh-my-copilot Doctor โ ์ค์น ์ง๋จ ๋ฐ ์๋ ์์
๋ชฉ์ : oh-my-copilot ํ๋ฌ๊ทธ์ธ์ ์ค์น ์ํ๋ฅผ ์ง๋จํ๊ณ , ๋ฐ๊ฒฌ๋ ๋ฌธ์ ๋ฅผ ์ฌ์ฉ์ ํ์ธ ํ ์๋ ์์ ํฉ๋๋ค.
ํธ๋ฆฌ๊ฑฐ ํค์๋
doctor ยท ์ง๋จ ยท install check ยท ํฌ์ค์ฒดํฌ ยท health check ยท ์ค์น ํ์ธ
Phase 0: ํ๋ฌ๊ทธ์ธ ๋๋ ํ ๋ฆฌ ํ์ง
OMC_DIR=""
for d in \
"$HOME/.copilot/installed-plugins/_direct/Lee-SiHyeon--oh-my-copilot" \
"$HOME/.copilot/installed-plugins/oh-my-copilot"; do
if [ -d "$d" ]; then
OMC_DIR="$d"
break
fi
done
if [ -z "$OMC_DIR" ]; then
echo "โ FATAL: oh-my-copilot ํ๋ฌ๊ทธ์ธ ๋๋ ํ ๋ฆฌ๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค."
echo " ํ์ธํ ๊ฒฝ๋ก:"
echo " โข $HOME/.copilot/installed-plugins/_direct/Lee-SiHyeon--oh-my-copilot"
echo " โข $HOME/.copilot/installed-plugins/oh-my-copilot"
echo ""
echo " ์ฌ์ค์น ๋ฐฉ๋ฒ: GitHub Copilot CLI์์ ํ๋ฌ๊ทธ์ธ์ ๋ค์ ์ค์นํ์ธ์."
exit 1
fi
echo "โ
ํ๋ฌ๊ทธ์ธ ๋๋ ํ ๋ฆฌ: $OMC_DIR"
Phase 1: ์ง๋จ ํญ๋ชฉ ์คํ
๊ฐ ํญ๋ชฉ์ ์์๋๋ก ์คํํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ์์งํฉ๋๋ค.
1-1. ํ๋ฌ๊ทธ์ธ ์ค์น ๊ฒฝ๋ก ํ์ธ
CHECK_PLUGIN_DIR="PASS"
PLUGIN_DIR_NOTE="$OMC_DIR"
if [ ! -d "$OMC_DIR" ]; then
CHECK_PLUGIN_DIR="FAIL"
PLUGIN_DIR_NOTE="๋๋ ํ ๋ฆฌ ์์"
fi
echo "[1] ํ๋ฌ๊ทธ์ธ ๊ฒฝ๋ก: $CHECK_PLUGIN_DIR โ $PLUGIN_DIR_NOTE"
1-2. Broken symlink ํ์ง
BROKEN_LINKS=""
BROKEN_LINKS=$(find "$OMC_DIR" -type l -exec sh -c \
'test ! -e "$1" && echo "$1"' _ {} \; 2>/dev/null)
if [ -z "$BROKEN_LINKS" ]; then
CHECK_SYMLINKS="PASS"
SYMLINK_NOTE="์์"
else
CHECK_SYMLINKS="FAIL"
SYMLINK_NOTE=$(echo "$BROKEN_LINKS" | wc -l | tr -d ' ')๊ฐ
echo " Broken symlinks ๋ชฉ๋ก:"
echo "$BROKEN_LINKS" | sed 's/^/ โข /'
fi
echo "[2] Broken symlink: $CHECK_SYMLINKS โ ${SYMLINK_NOTE}"
1-3. ์์กด์ฑ ํ์ธ (sqlite3 / jq / git)
MISSING_DEPS=""
for dep in sqlite3 jq git; do
if ! command -v "$dep" > /dev/null 2>&1; then
MISSING_DEPS="$MISSING_DEPS $dep"
fi
done
if [ -z "$MISSING_DEPS" ]; then
CHECK_DEPS="PASS"
DEPS_NOTE="sqlite3 โ jq โ git โ"
else
CHECK_DEPS="FAIL"
DEPS_NOTE="๋๋ฝ:$(echo $MISSING_DEPS | tr ' ' ',')"
fi
echo "[3] ์์กด์ฑ: $CHECK_DEPS โ $DEPS_NOTE"
1-4. hooks.json ์ ํจ์ฑ ๊ฒ์ฌ
HOOKS_FILE="$OMC_DIR/hooks.json"
if [ ! -f "$HOOKS_FILE" ]; then
CHECK_HOOKS="FAIL"
HOOKS_NOTE="hooks.json ํ์ผ ์์"
elif jq empty "$HOOKS_FILE" > /dev/null 2>&1; then
CHECK_HOOKS="PASS"
HOOK_COUNT=$(jq '[.hooks | to_entries[].value | length] | add // 0' "$HOOKS_FILE" 2>/dev/null)
HOOKS_NOTE="์ ํจํ JSON, ํ
์ํธ๋ฆฌ ${HOOK_COUNT}๊ฐ"
else
CHECK_HOOKS="FAIL"
HOOKS_NOTE="JSON ํ์ฑ ์ค๋ฅ: $(jq empty "$HOOKS_FILE" 2>&1 | head -1)"
fi
echo "[4] hooks.json: $CHECK_HOOKS โ $HOOKS_NOTE"
1-5. ์คํฌ๋ฆฝํธ ์คํ๊ถํ ํ์ธ (scripts/*.sh)
NO_EXEC_SCRIPTS=""
for script in "$OMC_DIR"/scripts/*.sh; do
[ -f "$script" ] || continue
if [ ! -x "$script" ]; then
NO_EXEC_SCRIPTS="$NO_EXEC_SCRIPTS\n$script"
fi
done
if [ -z "$NO_EXEC_SCRIPTS" ]; then
CHECK_PERMS="PASS"
PERMS_NOTE="๋ชจ๋ ์คํฌ๋ฆฝํธ ์คํ ๊ฐ๋ฅ"
else
CHECK_PERMS="FAIL"
COUNT=$(printf '%b' "$NO_EXEC_SCRIPTS" | grep -c '^/' || true)
PERMS_NOTE="${COUNT}๊ฐ ์คํฌ๋ฆฝํธ ์คํ๊ถํ ์์"
echo " ์คํ๊ถํ ์๋ ์คํฌ๋ฆฝํธ:"
printf '%b' "$NO_EXEC_SCRIPTS" | grep '^/' | sed 's/^/ โข /'
fi
echo "[5] ์คํฌ๋ฆฝํธ ๊ถํ: $CHECK_PERMS โ $PERMS_NOTE"
1-6. plugin.json ๋ฒ์ ํ์ธ
PLUGIN_JSON="$OMC_DIR/plugin.json"
if [ ! -f "$PLUGIN_JSON" ]; then
CHECK_VERSION="WARN"
VERSION_NOTE="plugin.json ์์"
elif jq empty "$PLUGIN_JSON" > /dev/null 2>&1; then
INSTALLED_VERSION=$(jq -r '.version // "unknown"' "$PLUGIN_JSON")
CHECK_VERSION="INFO"
VERSION_NOTE="v${INSTALLED_VERSION}"
else
CHECK_VERSION="WARN"
VERSION_NOTE="plugin.json ํ์ฑ ์คํจ"
fi
echo "[6] ๋ฒ์ : $CHECK_VERSION โ $VERSION_NOTE"
Phase 2: ์ง๋จ ๊ฒฐ๊ณผ ๋ฆฌํฌํธ
echo ""
echo "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
echo " oh-my-copilot Doctor Report"
echo " ํ๋ฌ๊ทธ์ธ ๊ฒฝ๋ก: $OMC_DIR"
echo "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
echo ""
printf "%-5s %-25s %-10s %s\n" "No." "ํญ๋ชฉ" "์ํ" "์์ธ"
echo "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
printf "%-5s %-25s %-10s %s\n" "[1]" "ํ๋ฌ๊ทธ์ธ ์ค์น ๊ฒฝ๋ก" "$CHECK_PLUGIN_DIR" "$PLUGIN_DIR_NOTE"
printf "%-5s %-25s %-10s %s\n" "[2]" "Broken symlink" "$CHECK_SYMLINKS" "$SYMLINK_NOTE"
printf "%-5s %-25s %-10s %s\n" "[3]" "์์กด์ฑ (sqlite3/jq/git)" "$CHECK_DEPS" "$DEPS_NOTE"
printf "%-5s %-25s %-10s %s\n" "[4]" "hooks.json ์ ํจ์ฑ" "$CHECK_HOOKS" "$HOOKS_NOTE"
printf "%-5s %-25s %-10s %s\n" "[5]" "์คํฌ๋ฆฝํธ ์คํ๊ถํ" "$CHECK_PERMS" "$PERMS_NOTE"
printf "%-5s %-25s %-10s %s\n" "[6]" "์ค์น ๋ฒ์ " "$CHECK_VERSION" "$VERSION_NOTE"
echo "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
ALL_PASS=true
for status in "$CHECK_PLUGIN_DIR" "$CHECK_SYMLINKS" "$CHECK_DEPS" "$CHECK_HOOKS" "$CHECK_PERMS"; do
[ "$status" = "FAIL" ] && ALL_PASS=false
done
if $ALL_PASS; then
echo ""
echo "โ
๋ชจ๋ ์ง๋จ ํญ๋ชฉ ํต๊ณผ. oh-my-copilot์ด ์ ์ ์ค์น๋์ด ์์ต๋๋ค."
else
echo ""
echo "โ ๏ธ ๋ฌธ์ ๊ฐ ๋ฐ๊ฒฌ๋์์ต๋๋ค. Phase 3 ์๋ ์์ ์ ์งํํฉ๋๋ค."
fi
echo ""
Phase 3: ์๋ ์์ (๋ฌธ์ ๋ฐ๊ฒฌ ์๋ง ์คํ)
๊ฐ ์์ ์ ์ฌ์ฉ์์๊ฒ ํ์ธ์ ๊ตฌํฉ๋๋ค. ์ฌ์ฉ์๊ฐ ๊ฑฐ๋ถํ๋ฉด ํด๋น ํญ๋ชฉ์ ๊ฑด๋๋๋๋ค.
3-1. Broken symlink ์ ๊ฑฐ
if [ "$CHECK_SYMLINKS" = "FAIL" ] && [ -n "$BROKEN_LINKS" ]; then
echo "๐ง [์์ 1/3] Broken symlink ์ ๊ฑฐ"
echo " ๋ค์ broken symlink๋ฅผ ์ ๊ฑฐํฉ๋๋ค:"
echo "$BROKEN_LINKS" | sed 's/^/ โข /'
echo ""
echo " โ ์ฌ์ฉ์ ํ์ธ ํ ์๋ ๋ช
๋ น์ ์คํํ์ธ์:"
echo ""
echo "$BROKEN_LINKS" | while IFS= read -r link; do
[ -n "$link" ] && echo " rm -f \"$link\""
done
echo ""
echo "$BROKEN_LINKS" | while IFS= read -r link; do
if [ -n "$link" ] && [ -L "$link" ]; then
rm -f "$link"
echo " โ
์ ๊ฑฐ๋จ: $link"
fi
done
fi
3-2. ์คํฌ๋ฆฝํธ ์คํ๊ถํ ๋ถ์ฌ
if [ "$CHECK_PERMS" = "FAIL" ] && [ -n "$NO_EXEC_SCRIPTS" ]; then
echo "๐ง [์์ 2/3] ์คํฌ๋ฆฝํธ ์คํ๊ถํ ๋ถ์ฌ (chmod +x)"
printf '%b' "$NO_EXEC_SCRIPTS" | grep '^/' | while IFS= read -r script; do
if [ -f "$script" ] && [ ! -x "$script" ]; then
chmod +x "$script"
echo " โ
chmod +x: $script"
fi
done
echo ""
fi
3-3. ์์กด์ฑ ๋๋ฝ ์๋ด
if [ "$CHECK_DEPS" = "FAIL" ] && [ -n "$MISSING_DEPS" ]; then
echo "๐ง [์์ 3/3] ๋๋ฝ ์์กด์ฑ ์ค์น ์๋ด"
echo " ๋๋ฝ๋ ํจํค์ง:$(echo $MISSING_DEPS)"
echo ""
echo " install.sh๋ฅผ ์คํํ์ฌ ์์กด์ฑ์ ์ค์นํ ์ ์์ต๋๋ค:"
echo ""
echo " bash \"$OMC_DIR/scripts/install.sh\""
echo ""
echo " โ ๏ธ ์๋ ์คํ์ ํ์ง ์์ต๋๋ค. ์ ๋ช
๋ น์ ์ง์ ์คํํ์ธ์."
echo ""
fi
Phase 4: ์์ ํ ์ฌ๊ฒ์ฆ
echo "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
echo " ์ฌ๊ฒ์ฆ ๊ฒฐ๊ณผ"
echo "โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ"
REMAINING_BROKEN=$(find "$OMC_DIR" -type l -exec sh -c \
'test ! -e "$1" && echo "$1"' _ {} \; 2>/dev/null)
if [ -z "$REMAINING_BROKEN" ]; then
echo "โ
Broken symlink: ์์"
else
echo "โ Broken symlink: ์์ง ๋จ์์์"
echo "$REMAINING_BROKEN" | sed 's/^/ โข /'
fi
STILL_NO_EXEC=""
for script in "$OMC_DIR"/scripts/*.sh; do
[ -f "$script" ] && [ ! -x "$script" ] && STILL_NO_EXEC="$STILL_NO_EXEC $script"
done
if [ -z "$STILL_NO_EXEC" ]; then
echo "โ
์คํฌ๋ฆฝํธ ์คํ๊ถํ: ์ ์"
else
echo "โ ์คํฌ๋ฆฝํธ ์คํ๊ถํ: ์ผ๋ถ ๋ฏธํด๊ฒฐ"
fi
echo ""
echo "Doctor ์ง๋จ ์๋ฃ."
์ง๋จ ํญ๋ชฉ ์์ฝํ
| No. | ํญ๋ชฉ | ํ์ธ ๋ฐฉ๋ฒ | ์๋ ์์ |
|---|
| 1 | ํ๋ฌ๊ทธ์ธ ์ค์น ๊ฒฝ๋ก | [ -d <plugin_dir> ] | โ (์ฌ์ค์น ์๋ด) |
| 2 | Broken symlink | find -type l + test ! -e | โ
rm -f |
| 3 | ์์กด์ฑ (sqlite3/jq/git) | command -v | โ (install.sh ์๋ด) |
| 4 | hooks.json ์ ํจ์ฑ | jq empty hooks.json | โ (์๋ ํ์ธ ํ์) |
| 5 | ์คํฌ๋ฆฝํธ ์คํ๊ถํ | [ -x scripts/*.sh ] | โ
chmod +x |
| 6 | ์ค์น ๋ฒ์ | jq .version plugin.json | โ (์ ๋ณด ํ์) |
์๋ ค์ง ๋ฌธ์ ๋ฐ ์์ธ
| ์ฆ์ | ์์ธ | ํด๊ฒฐ |
|---|
Copilot CLI ENOENT ์ค๋ฅ | tests/bats/bin/bats โ /usr/bin/bats broken symlink | [2] ์๋ ์์ |
| hook ๋ฏธ์คํ | session-start.sh ์คํ๊ถํ ์์ | [5] ์๋ ์์ |
| jq/sqlite3 ๋ช
๋ น ์์ | ์์กด์ฑ ๋ฏธ์ค์น | scripts/install.sh ์คํ |
| hooks.json ํ์ฑ ์คํจ | JSON ํ์ ์ค๋ฅ | ์ง์ ํธ์ง ํ์ |