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>
This commit is contained in:
commit
964a841de1
3978 files changed
+58013356
No files matched your search
@@ -0,0 +1,196 @@
|
||||
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()
|
||||
Reference in new issue
Block a user