
    &<iL                        d Z ddlZddlZddlmZmZ ddlmZ ddlm	Z	m
Z
mZ  ee      j                  dz  Ze G d d             Zg d	d
dg dddg dddg ddddZdefdZdefdZdedee   fdZdedefdZdefdZdedefdZdede
e   defdZde
e	   de	fd Zd!ede
e   fd"Zdede	fd#Zd$ Zed%k(  r e        yy)&u   
Task Router - 작업 설명을 분석해서 적절한 전문 팀원 선택

Usage:
    python3 memory/task-router.py route "UI 컴포넌트 만들어줘"
    python3 memory/task-router.py list
    python3 memory/task-router.py status backend-001
    N)asdict	dataclassPath)DictListOptionalzdev-team-structure.jsonc                   P    e Zd ZU dZeed<   eed<   ee   ed<   ee   ed<   eed<   y)Tasku    작업 정의 데이터클래스iddescfiles
depends_onpromptN)__name__
__module____qualname____doc__str__annotations__r        C/home/jay/workspace/.worktrees/task-2057-dev2/memory/task-router.pyr   r      s(    *G
I9S	Kr   r   )UIuiu   컴포넌트u   화면u	   스타일ReactreactCSScssu   프론트엔드frontendu	   페이지u   레이아웃u	   디자인u   버튼u   모달u   폼input
TypeScript
javascriptjsjsxtsxzfrontend-001)keywordsspecialist_id)APIapiu   서버DBdbu   데이터베이스databasezNode.jsnodePythonpythonu	   백엔드backendu   엔드포인트endpointu	   스키마schema
PostgreSQLmysqlmongoredisu   쿼리queryu   인증authjwtu   세션sessionbackend-001)	   테스트testJestjestPytestpytestCypresscypressE2Ee2eu   단위 테스트u   통합 테스트u   테스트 코드TDDtddu   테스트 작성u   테스트 케이스mockstubztesting-001)DockerdockerzCI/CDzci/cdcicd   배포deployAWSawsu	   인프라infrainfrastructureDevOpsdevopsu   깃헙액션zGitHub Actionszgithub actionsu   파이프라인pipeline
kubernetesk8su   컨테이너	containeru   빌드buildz
devops-001)r    r1   testingrU   returnc                  t   ddl } ddlm} g d} |t              j                  }g }|D ]z  }|| dz  }|j                         st        |dd      5 } | j                  |      }|j                  d	      d
k(  r"|j                  d      |j                  |       ddd       | |r|d   S y# 1 sw Y   xY w)u   
    개발실 내에서 가장 한가한 팀 반환

    Returns:
        team_id: "dev1-team" | "dev2-team" | "dev3-team"
    r   Nr   )	dev1-teamz	dev2-teamz	dev3-teamz-status.jsonrutf-8encodingstatus	availablecurrent_taskr^   )
jsonpathlibr   __file__parentexistsopenloadgetappend)	rf   r   teamsteam_status_diravailable_teamsteam_idstatus_filefrc   s	            r   get_available_dev_teamru      s      4E8n++OO 	4%7)<(@@k39 4Q"1 ::h';66::n;U;]#**734 4		4 q!! 4 4s   A	B..B7	c                      	 t        t        dd      5 } t        j                  |       cddd       S # 1 sw Y   yxY w# t        $ r ddt         icY S t        j
                  $ r}dd| icY d}~S d}~ww xY w)u   팀 구조 JSON 파일 로드r_   r`   ra   Nerroru.   팀 구조 파일을 찾을 수 없습니다: u   JSON 파싱 오류: )rk   TEAM_STRUCTURE_PATHrf   rl   FileNotFoundErrorJSONDecodeError)rt   es     r   load_team_structurer|      s|    5%sW= 	 99Q<	  	  	  aIJ]I^_`` 5/s3445s5   ? 3	? <? ? A8A8'A3-A83A8	member_idc                     t               }d|v ry|j                  dg       D ]'  }|j                  dg       D ]  }|d   | k(  s|c c S  ) |j                  dg       D ]  }|d   | k(  s|c S  y)u   
    팀원 정보 반환 (모델 포함)

    Args:
        member_id: 팀원 ID (예: "frontend-001")

    Returns:
        팀원 정보 딕셔너리 또는 None
    rw   N	sub_teamsmembersr   r|   rm   )r}   teamsub_teammembers       r   get_member_infor      s      D$ HH["- ll9b1 	Fd|y(	 ((9b) $<9$M r   task_descriptionc                    | r| j                         sddddddS i }i }t        j                         D ]C  \  }}g }|d   D ]  }|| v s|j                  |        |s+t	        |      ||d   <   |||d   <   E |sRt        d      }d|r|j                  d      nd|r|j                  d	      ndd
dg d|r|j                  dg       dS g dS t        ||j                        }||   }t        dt	        |      dz  z   d      }	|j                  d      d   j                         }
|
 ddj                  |dd        }t	        |      dkD  r|dt	        |      dz
   dz  }t        |      }t               }|j                  dd      }||||r|j                  d      nd|r|j                  d	      ndt        |	d      |||r|j                  dg       d	S g d	S )u  
    작업 설명을 분석해서 적절한 팀원 선택

    Args:
        task_description: 작업 설명 문자열

    Returns:
        {
            "specialist": "frontend-001",
            "model": "claude-3-sonnet",
            "model_tier": "lightweight",
            "confidence": 0.9,
            "reason": "UI 키워드 감지",
            "matched_keywords": ["UI", "컴포넌트"],
            "skills": ["React", "TypeScript", "CSS", "UI/UX"]
        }

    Examples:
        >>> route_task("UI 컴포넌트 만들어줘")
        {"specialist": "frontend-001", "model": "zai/glm-4.7-flash", ...}
        >>> route_task("API 엔드포인트 구현해줘")
        {"specialist": "backend-001", "model": "zai/glm-4.7-flash", ...}
    u#   작업 설명이 비어있습니다Ng        )rw   
specialistmodel
model_tier
confidencer'   r(   r<   r   r   g333333?u.   키워드 매칭 실패, 기본 backend 할당u.   명확한 키워드가 없어 기본값 할당skills)r   r   r   r   reasonmatched_keywordswarningr   )key      ?皙?g      ?-r   u    키워드 감지: ,    u    외 u   개z-teamz
-team-lead   )	r   r   	team_leadr   r   r   r   r   r   )stripKEYWORD_MAPPINGitemsrn   lenr   rm   maxminsplitupperjoinru   replaceround)r   scoresmatched_keywords_by_specialty	specialtyconfigr   keywordmember_infobest_specialistr   specialty_namer   available_teamteam_lead_ids                 r   
route_taskr      sX   0 #3#9#9#;:
 	
 F$&!,224 V	6j) 	1G** ''0	1 .12B.CF6/*+EU)&*ABV %m4'1<[__W-$;F+//,7DF "G7Bkooh3	
 		
 IK	
 		
 &fjj1O4_E SC 01C78#>J %**3/288:N2499=Mbq=Q3R2STF
q E#./!34C88 "/2K ,-N "))'<@L &!-8)d7Bkool3J*,3>+//(B/
 
 EG
 
r   c                      t               } d| v r| S | j                  dg       }|D cg c]  }|d   	 c}t        |      dS c c}w )u   전체 팀원 목록 반환rw   r   r   )r   count)r|   rm   r   )r   r   ms      r   list_membersr   B  sG     D$hhy"%G)01A$1CLII1s   Ac                     t               }d|v r|S |j                  dg       D ]#  }|d   | k(  s|d   |d   |d   |d   |d   dc S  d	|  |j                  dg       D cg c]  }|d   	 c}d
S c c}w )u   특정 팀원 상태 확인rw   r   r   r   rc   re   r   )r   r   rc   re   r   u#   팀원을 찾을 수 없습니다: )rw   available_membersr   )r}   r   r   r   s       r   get_member_statusr   L  s     D$((9b) $<9$Tl#K0 * &~ 6 *  7ykB/3xx	2/FG!agG Gs   !A2task	all_tasksc                     | j                   ry|D ]I  }|j                  | j                  k7  st        | j                        t        |j                        z  sI y y)uB  
    작업의 의존성 여부 확인

    확인 사항:
    1. 명시적 의존성 (depends_on)
    2. 파일 충돌 (같은 파일을 건드리는 다른 작업)

    Args:
        task: 검사할 작업
        all_tasks: 전체 작업 리스트

    Returns:
        의존성이 있으면 True, 없으면 False
    TF)r   r   setr   )r   r   others      r   has_dependenciesr   b  sP        88tww4::U[[!11
 r   tasksc                    g }| D ]  }t        |t              r|j                  t        |j	                  dd      |j	                  d|j	                  dd            |j	                  dg       |j	                  d|j	                  dg             |j	                  dd      	             |j                  |        g }g }g g d
}g }|D ]  }t        ||      r|j                  |j                         |D ]|  }|j                  |j                  k7  st        |j                        t        |j                        z  }|sK|j                  |j                  |j                  t        |      d       ~ |j                  |j                          |r|d   j                  |       |D ]  }	|d   j                  |	g        |sd}
n|sd}
nd}
|||
||dS )u  
    작업 의존성 분석 (Task dataclass 지원)

    Args:
        tasks: 작업 리스트 (Dict 또는 Task dataclass)
            Dict 형식 (기존 호환성):
            [
                {"id": "task1", "description": "A파일 작성", "dependencies": []},
                {"id": "task2", "description": "B파일 작성", "dependencies": []},
                {"id": "task3", "description": "설계", "dependencies": []},
                {"id": "task4", "description": "구현", "dependencies": ["task3"]},
                {"id": "task5", "description": "테스트", "dependencies": ["task4"]}
            ]

            Task dataclass 형식 (새로운):
            [
                Task(id="task1", desc="A파일 작성", files=["a.py"], depends_on=[], prompt="..."),
                Task(id="task2", desc="B파일 작성", files=["b.py"], depends_on=[], prompt="..."),
                Task(id="task3", desc="설계", files=["design.md"], depends_on=[], prompt="..."),
                Task(id="task4", desc="구현", files=["impl.py"], depends_on=["task3"], prompt="..."),
                Task(id="task5", desc="테스트", files=["test.py"], depends_on=["task4"], prompt="...")
            ]

    Returns:
        {
            "parallel_tasks": ["task1", "task2"],
            "sequential_tasks": ["task3", "task4", "task5"],
            "recommendation": "hybrid",  # parallel, sequential, hybrid
            "execution_plan": {
                "parallel": [["task1", "task2"]],
                "sequential": [["task3"], ["task4"], ["task5"]]
            },
            "file_conflicts": [  # 파일 충돌 정보
                {"task1": "a.py", "task2": "a.py", "conflict": "a.py"}
            ]
        }
    r    descriptionr   r   dependenciesr   r   )r   r   r   r   r   )parallel
sequential)task1task2conflict_filesr   r   hybrid)parallel_taskssequential_tasksrecommendationexecution_planfile_conflicts)

isinstancedictrn   r   rm   r   r   r   r   list)r   normalized_tasksr   r   r   r   r   r   r   task_idr   s              r   analyze_task_dependenciesr   ~  s   P  *dD!##xxb)-&"1EF((7B/#xxr8RS88Hb1 ##D)* N"$B7NN ! +D"23##DGG, * 88tww&%(_s5;;7G%GN%&--&*ggTXYgThi	 !!$''*+  z")).9 $ 7|$++WI67 #%! ),((( r   r   c                 j    g d}g d}dgdgdgdgd}|D ]  }|| v s|j                  |g       c S  g S )u   
    작업 설명에서 의존성 자동 감지

    키워드 기반 감지:
    - "설계" → 의존성 없음
    - "구현" → "설계" 의존
    - "테스트" → "구현" 의존
    - "작성", "생성" → 의존성 없음
    )   구현r=      검증rN      실행)   작성   생성	   문서화   로깅   캐시   설계r   r=   r   )r   r=   r   rN   )rm   )r   sequential_keywordsparallel_keywordsdependency_rulesr   s        r   $detect_dependencies_from_descriptionr     sb     P N $,*H:R]Q^ksjtu& 5k!#''445 Ir   c                      g d}g d}t         fd|D              }t         fd|D              }||kD  rdd| dt        dd	|d
z  z         dS ||kD  rdd| dt        dd	|d
z  z         dS ddd	dS )u   
    작업 설명을 기반으로 실행 모드 추천

    Returns:
        {
            "mode": "parallel" | "sequential",
            "reason": "이유",
            "confidence": 0.0-1.0
        }
    )r   r=   r   rN   r   r   )r   r   r   r   r   u	   독립적c              3   ,   K   | ]  }|v sd   yw   Nr   .0kwr   s     r   	<genexpr>z)suggest_execution_mode.<locals>.<genexpr>  s     UbDT>T1U   	c              3   ,   K   | ]  }|v sd   ywr   r   r   s     r   r   z)suggest_execution_mode.<locals>.<genexpr>  s     Qr"@P:PQr   r   u   순차 처리 키워드 u
   개 감지g?r   r   )moder   r   r   u   병렬 처리 키워드 u/   명확하지 않음, 안전하게 순차 처리)sumr   )r   r   r   sequential_scoreparallel_scores   `    r   suggest_execution_moder     s     Z [ U':UUQ%6QQN .( 01A0B*Mc3)9C)?#?@
 	

 
*	*00@
Kc3#)=#=>
 	
 %0aqtuur   c                     t        t        j                        dk  rAt        d       t        d       t        d       t        d       t        j                  d       t        j                  d   } | dk(  rCt        t        j                  dd	g d
t        t        j                               dd             y| dk(  rt        t        j                        dk  r+t        d       t        d       t        j                  d       dj                  t        j                  dd       }t        |      }t        t        j                  |dd             y| dk(  rRt               }d|v r&t        d|d           t        j                  d       t        dj                  |d                y| dk(  rt        t        j                        dk  r+t        d       t        d       t        j                  d       t        j                  d   }t        |      }t        t        j                  |dd             y| dk(  r}t        t        j                        dkD  rUt        j                  d   }t        j                  |      }t        |      }t        t        j                  |dd             yt        d       y| d k(  rht        t        j                        dkD  r@t        j                  d   }t!        |      }t        t        j                  |dd             yt        d!       yt        d"|         t        d#       t        j                  d       y)$u   CLI 인터페이스r   u
   사용법:u5     python3 memory/task-router.py route "작업 설명"z$  python3 memory/task-router.py listz2  python3 memory/task-router.py status <member_id>r   r>   loaded
TaskRouter)router   rc   )rc   routercommandsspecialtiesF)ensure_asciir   r   u'   Error: 작업 설명이 필요합니다uG   예: python3 memory/task-router.py route "UI 컴포넌트 만들어줘" N)r   indentr   rw   zError: r   r   rc   u#   Error: member_id가 필요합니다u5   예: python3 memory/task-router.py status backend-001analyze)r   r   z5Usage: python3 memory/task-router.py analyze '<json>'suggestz<Usage: python3 memory/task-router.py suggest '<description>'u   알 수 없는 명령어: uA   사용 가능한 명령어: route, list, status, analyze, suggest)r   sysargvprintexitrf   dumpsr   r   keysr   r   r   r   loadsr   r   )commandr   resultr}   
tasks_jsonr   r   s          r   mainr  &  sx   
388}qlEF45BChhqkG&JJ&* ;#'(<(<(>#?	 #
	
 
G	sxx=1;<[\HHQK88CHHQRL1,-djjeA>?	F	fGF7O,-.HHQKdiiy)*+	H	sxx=178IJHHQKHHQK	"9-djjeA>?	I	sxx=1!JJJz*E.u5F$**VAEBCIJ	I	sxx=1((1+K+K8F$**VAEBCPQ 	*7)45QRr   __main__) r   rf   r   dataclassesr   r   rg   r   typingr   r   r	   rh   ri   rx   r   r   r   ru   r   r|   r   r   r   r   boolr   r   r   r   r  r   r   r   r   <module>r	     s    
 )  ' ' 8n++.GG    
2 (5:
< '? D
* '-2
6 &9mtn   F5T 5s x~ 8] ] ]@Jd J  ,4 DJ 4 8cT$Z cD cLc d3i 6$vS $vT $vNJZ zF r   