리눅스 환경에서 작업하다 보면 자주 쓰지 않는 복잡한 명령어 때문에 흐름이 끊기곤 합니다. 매번 구글링해서 명령어를 찾아 복사·붙여넣기 하는 번거로움을 줄이고, 터미널 내부에서 자연어로 명령어를 제안받아 즉시 실행하고자 개발한 CLI 도구입니다.
시스템 안전장치와 자동 업무 로깅 기능까지 포함하여 단일 파이썬 스크립트(project.py)로 구현했습니다.
🛠️ 주요 기능 및 구현 특징
1. 현장 밀착형 콘텍스트 전달 (Context-Aware)
AI가 현재 디렉토리 상황을 모른 채 엉뚱한 가상 파일명을 뱉는 문제를 해결했습니다. 스크립트 실행 시 현재 디렉토리의 파일 목록을 최대
15개까지 추출(os.listdir)하여 프롬프트에 자동으로 주입합니다. 덕분에 AI가 현재 폴더 상황에 맞는 실질적인 명령어를 제안합니다.
2. 시스템 보호를 위한 위험 키워드 필터링 (Danger Detection)
rm, mkfs, reboot, shutdown, dd, chmod -R 777, chown -R 등 시스템에 치명적인 영향을 줄 수 있는 명령어들을 DANGER_KEYWORDS 목록으로 관리합니다. AI가 추천한 결과에 해당 패턴이 감지되면 터미널에 붉은색 배경(ANSI Escape Code)으로 경고를 띄워 사고를 방지합니다.
3. 일일 업무 요약 및 로그 로테이션 (--summary)
명령어를 실행하면 실행 결과의 상위 3줄을 요약하여 ai_command_history.log 파일에 누적 저장합니다. 로그 파일이 무한정 커지는 것을 막기 위해 실행 시점에서 30일이 지난 데이터를 삭제하는 로테이션 로직(clean_old_logs)을 탑재했습니다.
퇴근 전 --summary 옵션을 주면 당일 수행한 업무 내역을 파싱하여 깔끔한 리포트 형태로 출력해 줍니다.
💻 전체 코드
import requests
import json
import sys
import os
import subprocess
import datetime
# ⚠️ 위험 키워드 목록 (시스템에 치명적인 명령어)
DANGER_KEYWORDS = ['rm', 'mkfs', 'reboot', 'shutdown', 'dd', 'chmod -R 777', 'chown -R']
def get_current_context():
"""현재 디렉토리의 파일 정보를 AI에게 전달"""
try:
files = os.listdir('.')[:15]
return ", ".join(files)
except:
return "정보 없음"
def clean_old_logs(filename, days=30):
"""지정한 기간(30일)이 지난 로그를 자동으로 삭제"""
if not os.path.exists(filename):
return
try:
current_time = datetime.datetime.now()
remaining_logs = []
with open(filename, "r", encoding="utf-8") as f:
content = f.read()
entries = content.split('=' * 50)
for entry in entries:
if not entry.strip(): continue
try:
# 로그 날짜 추출 및 비교
date_str = entry.strip().split('\n')[0][1:-1]
log_date = datetime.datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S')
# 🚀 설정된 기간(30일) 이내 기록만 유지
if current_time - log_date < datetime.timedelta(days=days):
remaining_logs.append(entry)
except:
remaining_logs.append(entry)
with open(filename, "w", encoding="utf-8") as f:
for log in remaining_logs:
f.write(f"{'='*50}\n{log.strip()}\n")
except Exception as e:
print(f"(로그 정리 중 오류 발생: {e})")
def show_summary(filename):
"""오늘 수행한 업무 내역 요약 리포트 출력"""
if not os.path.exists(filename):
print("\033[93m기록된 로그가 없습니다.\033[0m")
return
today = datetime.datetime.now().strftime('%Y-%m-%d')
print(f"\n\033[95m📅 [{today}] 일일 업무 요약 리포트\033[0m")
print("-" * 50)
found = False
with open(filename, "r", encoding="utf-8") as f:
content = f.read()
entries = content.split('=' * 50)
for entry in entries:
if today in entry:
lines = entry.strip().split('\n')
time = lines[0]
query = lines[1].replace("질문: ", "")
cmd = lines[2].replace("명령어: ", "")
print(f"✅ {time} | 업무: {query}")
print(f" └─ 실행: {cmd}")
found = True
if not found:
print("오늘 수행한 업무 내역이 없습니다.")
print("-" * 50)
def ask_ai(question):
"""Ollama를 통한 명령어 생성"""
url = "http://localhost:11434/api/generate"
context = get_current_context()
system_prompt = (
"너는 숙련된 리눅스 관리자야. 요구사항에 맞는 '한 줄의 쉘 명령어'만 출력해. "
"설명 없이 명령어만 응답해. 현재 파일 목록: [{context}]"
)
payload = {"model": "llama3", "prompt": f"{system_prompt}\n\n질문: {question}\n명령어:", "stream": False}
try:
response = requests.post(url, json=payload)
return response.json().get("response", "").strip()
except:
return "에러: Ollama 서비스가 응답하지 않습니다."
if __name__ == "__main__":
LOG_FILE = "ai_command_history.log"
# 🚀 실행 시 30일 지난 로그 자동 정리
clean_old_logs(LOG_FILE, days=30)
# 업무 요약 모드 체크
if len(sys.argv) >= 2 and sys.argv[1] == "--summary":
show_summary(LOG_FILE)
sys.exit(0)
if len(sys.argv) < 2:
print("\033[93m사용법: python3 project.py '명령어 질문' 또는 --summary\033[0m")
sys.exit(1)
user_query = " ".join(sys.argv[1:])
command = ask_ai(user_query)
# 위험 감지 로직
is_dangerous = any(kw in command for kw in DANGER_KEYWORDS)
print(f"\n✨ AI 추천 명령어:")
if is_dangerous:
print(f"\033[91m⚠️ 위험 키워드 감지! 실행 시 주의가 필요합니다.\033[0m")
print(f"\033[41m\033[37m {command} \033[0m\n")
else:
print(f"\033[92m{command}\033[0m\n")
# 입력 검증 루프 (y/ㅛ/n/ㅜ 외 입력 시 재질문)
while True:
confirm = input("이 명령어를 실행할까요? (y/n): ").lower()
if confirm in ['y', 'ㅛ']:
try:
# 명령어 실행 및 전체 결과 출력
result = subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT, text=True)
print("\n[실행 결과]")
print(result)
# 로그용 요약 처리 (최대 3줄 저장)
lines = result.strip().split('\n')
log_result = "\n".join(lines[:3]) + (f"\n... ({len(lines)-3}줄 생략)" if len(lines) > 3 else "")
# 로그 저장
with open(LOG_FILE, "a", encoding="utf-8") as f:
now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
f.write(f"{'='*50}\n[{now}]\n질문: {user_query}\n명령어: {command}\n결과:\n{log_result}\n")
print("\n\033[94m(성공적으로 실행되었으며 로그가 저장되었습니다.)\033[0m")
break
except subprocess.CalledProcessError as e:
print(f"\n\033[91m실행 중 오류 발생:\n{e.output}\033[0m")
break
elif confirm in ['n', 'ㅜ']:
print("\n실행을 취소했습니다.")
break
else:
print(f"\033[93m잘못된 입력입니다: '{confirm}'. y 또는 n을 입력해주세요.\033[0m")
🚀 사용 예시 (How to use)
1. 자연어로 명령어 요청 및 즉시 실행
터미널에 원하는 요구사항을 인자로 던지면 AI가 명령어를 제안하고 실행 여부를 묻습니다.

2. 오늘 사용한 코드 리포트 확인

오픈소스 기반 로컬 LLM(Ollama – Llama3)을 활용하여 외부 API 호출 없이 코드가 유출될 걱정 없는 보안 친화적 환경을 구축했다는 점이 가장 큰 장점입니다. 더불어 스크립트가 실행 환경의 컨텍스트를 스스로 수집하고 이를 프롬프트에 동적으로 반영하는 구조를 직접 구현해
볼 수 있어 유의미한 프로젝트였습니다.




