Files
Pier_v1/.hmcmkit/tools/bootup.py
T
ahnyongjooandClaude Sonnet 5.5 964a841de1 chore(rebar): Pier_T_rebar 작업 폴더 초기 구성 및 외부 의존 파일 통합
- Code\rebar_pipeline, review_pipeline, pier-program을 정션에서 실제 폴더로 전환
- Code\rhino_mcp 및 CLAUDE_rhino배경.md 추가, .mcp.json은 PYTHONPATH로 새 위치 사용
- pier-program 내부 .git 제거(이력은 backup\pier-program_20261028.bundle에 보관)
- worktree 가이드 반영(CLAUDE.local.md, HANDOFF.md)
- D:\Rhino-MCP 경로 참조를 새 위치로 치환

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-28 11:20:18 +09:00

197 lines
7.3 KiB
Python

import os
import sys
import json
import datetime
import shutil
import re
from state_engine import ContextManager, Guardrails
def detect_stale_features(ctx):
features = ctx.state.get('features', {})
stale = []
now = datetime.datetime.now()
for fname, fdata in features.items():
# archive된거 제외하려면 로직 필요하나 일단 history 마지막 날짜 기준
if fdata.get('phase') in ['REPORT', 'ARCHIVE']:
continue
history = fdata.get('history', [])
if not history: continue
try:
last_time = datetime.datetime.fromisoformat(history[-1].get('timestamp', ''))
days_idle = (now - last_time).days
if days_idle >= 2: # Reduce to 2 for tighter detection in AI contexts
stale.append({"feature": fname, "daysIdle": days_idle, "phase": fdata.get('phase')})
except:
pass
return stale
def print_agent_context_injection(ctx):
"""
Prints a markdown-formatted context for the agent to consume immediately.
"""
state = ctx.state
current_feature = state.get('current_feature')
level = state.get('project_level', 'Starter')
# Read blueprint for goal
blueprint_path = os.path.join(".hmcmkit", "blueprint.md")
goal = "Unknown"
if os.path.exists(blueprint_path):
try:
with open(blueprint_path, "r", encoding="utf-8") as f:
content = f.read()
# Simple extraction for goal
match = re.search(r"- \*\*Goal\*\*: (.*)", content)
if match:
goal = match.group(1)
except Exception:
pass
print("\n" + "="*60)
print("🚀 HMCMkit DYNAMIC CONTEXT INJECTION (Action Items)")
print("="*60)
print(f"\n### 📍 Current Project Status")
print(f"- **Project Name**: {state.get('project_name')}")
print(f"- **Project Goal**: {goal}")
print(f"- **Project Level**: {level}")
print(f"- **Active Feature**: {current_feature or 'None (Ready for new task)'}")
if current_feature:
feature_data = state.get('features', {}).get(current_feature, {})
print(f"- **Current Phase**: {feature_data.get('phase', 'PLAN')}")
print(f"- **Match Rate**: {feature_data.get('match_rate', 0)}%")
print(f"\n### 🎯 Recommended Next Action")
if not current_feature:
print("1. 상단 `blueprint.md`를 읽고 프로젝트의 현황을 파악하세요.")
print("2. 사용자에게 다음에 개발할 기능(Feature)이 무엇인지 물어보거나, `blueprint.md`에 명시된 할 일을 제안하세요.")
else:
phase = state.get('features', {}).get(current_feature, {}).get('phase', 'PLAN')
print(f"1. 현재 활성화된 기능 `{current_feature}`의 `{phase}` 단계를 계속 진행하세요.")
print(f"2. 만약 `{phase}` 단계가 완료되었다면, `Check` 단계를 거쳐 다음 단계로 전이(Transition)를 제안하세요.")
guard = Guardrails(ctx)
loop_check = guard.check_loop(current_feature)
if not loop_check['safe']:
print(f"\n 🚨 [루프 차단 가드레일]: {loop_check['reason']}")
stale = detect_stale_features(ctx)
if stale:
print("\n### ⚠️ Stale Feature 경고")
for s in stale:
print(f"- `{s['feature']}`: {s['daysIdle']}일 동안 변경 사항이 없습니다. (현재: {s['phase']})")
print("\n" + "="*60 + "\n")
def sync_skills_to_native_ide():
"""
Syncs HMCMkit skills to the native .agent/skills directory.
Uses Symlink first, fallbacks to Copy on error.
"""
src_dir = os.path.join(".hmcmkit", "knowledge", "skills")
dest_dir = os.path.join(".agents", "skills")
if not os.path.exists(src_dir):
return
if not os.path.exists(dest_dir):
os.makedirs(dest_dir, exist_ok=True)
print(f"🔄 Syncing skills to native IDE: {dest_dir}")
for item in os.listdir(src_dir):
s_path = os.path.abspath(os.path.join(src_dir, item))
d_path = os.path.abspath(os.path.join(dest_dir, item))
# Cleanup existing
if os.path.exists(d_path) or os.path.islink(d_path):
try:
if os.path.islink(d_path) or os.path.isfile(d_path):
os.remove(d_path)
elif os.path.isdir(d_path):
shutil.rmtree(d_path)
except Exception as e:
print(f" ⚠️ Could not cleanup {item}: {e}")
continue
# Try Symlink first
try:
os.symlink(s_path, d_path, target_is_directory=os.path.isdir(s_path))
print(f" [LINK] {item}")
except Exception as e:
# Fallback to Copy
try:
if os.path.isdir(s_path):
shutil.copytree(s_path, d_path)
else:
shutil.copy2(s_path, d_path)
print(f" [COPY] {item} (Symlink failed: {e})")
except Exception as copy_e:
print(f" ⚠️ Failed to sync {item}: {copy_e}")
def bootup_check():
"""
Simulates hooks/session-start.js logic.
Checks if .hmcmkit environment is valid and updates last_access timestamp.
"""
hmcmkit_root = ".hmcmkit"
if not os.path.exists(hmcmkit_root):
print(f"Error: {hmcmkit_root} directory not found. Please initialize first.")
return False
# Check core files
required_files = [
os.path.join(hmcmkit_root, "config.json"),
os.path.join(hmcmkit_root, "state.json")
]
missing = [f for f in required_files if not os.path.exists(f)]
if missing:
print(f"❌ Error: Missing core files: {missing}")
return False
# v1.0.2: Auto-generate Index if missing
index_path = os.path.join(hmcmkit_root, "system", "_GRAPH-INDEX.md")
if not os.path.exists(index_path):
print("🔍 Knowledge Index missing. Generating...")
try:
from graph_index import generate_graph_index
generate_graph_index(hmcmkit_root)
except Exception as e:
print(f"⚠️ Warning: Could not generate Knowledge Index: {e}")
# Update state last_access
ctx = ContextManager(os.path.join(hmcmkit_root, "state.json"))
ctx.state['last_bootup'] = datetime.datetime.now().isoformat()
ctx._save_state()
# Auto-detect Project Level
level = ctx.detect_project_level()
ctx._save_state()
# v1.0.1: Ensure backup dir exists
backup_dir = os.path.join(hmcmkit_root, "backups")
if not os.path.exists(backup_dir):
os.makedirs(backup_dir)
# NATIVE SKILL SYNC
sync_skills_to_native_ide()
# Check for active feature
current_feature = ctx.get_active_feature()
print(f"\n✅ System Ready (Level: {level})")
print(f" Active Feature: {current_feature or 'None'}")
# DYNAMIC CONTEXT INJECTION
print_agent_context_injection(ctx)
print("\n [Usage Hints]")
print(" - Plan : 'I need a feature...'")
print(" - Do : 'Implement the feature...'")
print(" - Check: 'Verify my work...'")
return True
if __name__ == "__main__":
bootup_check()