o
    cil.                     @   s"  d Z ddlZddlZddlZddlmZ ddlmZ ddlmZm	Z	 edZ
edZedZd	d
dddddddddddZddddddZdefddZdefddZdefddZdedee defdd Zdee fd!d"Zdee fd#d$Zdee fd%d&Zd'edefd(d)Zd*ed+ede	ee ee f fd,d-Zd*ed+ede	ee ee f fd.d/Zd0ed+edee fd1d2Zd3ed4edefd5d6Zd7ed8ed9efd:d;Zd7ed8ed9efd<d=Z ded*ed>ed?ed@ef
dAdBZ!dCedDed+edEee dFee f
dGdHZ"dIdJ Z#e$dKkre#  dS dS )La  Create OR update an item on Kanban, Dashboard, and Action Board JSON stores.

Default behavior (backwards compatible): create a new item on all boards.

Update behavior (new): if you pass --update-title and the target exists, it will:
- append the provided --body as an update note
- optionally move the Action Board card to the requested column

Usage examples:

  # Create new item on all boards
  add_to_boards.py --id <email_id> --title "..." --body "..." --area "ToAssistant" --priority "Medium"

  # Update existing items (prefer exact match)
  add_to_boards.py --id <email_id>     --title "ToAssistant:FW: ..."     --body "New context..."     --update-title "BDMI Finance inbox visibility / forwarding (1745Ventures)"     --action-move waiting

Matching mode:
- If --update-title is provided, we try exact match by title/name first.
- If not found and --fuzzy is set, we do a conservative contains-match.

Action Board column ids (current): overdue, urgent, do_now, waiting, quick_wins, someday, done_recent
    N)datetime)Path)OptionalTuplez3/home/isthekid/.openclaw/workspace/kanban/data.jsonz6/home/isthekid/.openclaw/workspace/dashboard/data.jsonz3/home/isthekid/.openclaw/workspace/action/data.jsonoverdueurgentdo_nowwaiting
quick_winssomedaydone_recent)r   r   r   	doing_nowzdo nowr	   waiting_on_othersr
   r   r   donezdone recentlytododoingr   )r   zto dor   r	   r   returnc                   C   s   t   jdd S )Nr   )microsecond)r   now
astimezonereplace	isoformat r   r   7/home/isthekid/.openclaw/workspace/bin/add_to_boards.py
now_iso_et@   s   r   pathc                 C   s   t |  S )N)jsonloads	read_text)r   r   r   r   	load_jsonD   s   r   c                 C   s   |  tj|dddd  d S )N   F)indentensure_ascii
)
write_textr   dumps)r   datar   r   r   	save_jsonH   s   r'   base_idusedc                 C   s2   | }d}||v r|  d| }|d7 }||v s|S )Nr    _   r   )r(   r)   cidir   r   r   ensure_unique_idL   s   r.   c                 C   T   t  }| dg D ]}|dg pg D ]}t|tr&|dr&||d  qq	|S Ncolumnscardsidsetget
isinstancedictadddocidscolcr   r   r   collect_ids_kanbanU      r?   c                 C   r/   r0   r4   r:   r   r   r   collect_ids_action^   r@   rA   c                 C   sB   t  }| dg p
g D ]}t|tr|dr||d  q|S )Nprojectsr3   r4   )r;   r<   pr   r   r   collect_ids_dashboardg   s   rD   sc                 C   s   d | pd  S )N  )joinsplitstrip)rE   r   r   r   normalize_wso   s   rK   titlefuzzyc           
      C   s*  t |}|sdS | dg D ]}|dg pg D ]}t |d|kr+||f    S qq|s1dS | }g }| dg D ]-}|dg pFg D ]"}t |d}|sSqG| }	||	v s_|	|v ri|t|||f qGq=t|dkr}|d d |d d fS |r|jdd	 d
 |d d |d d fS dS )zReturns (card, column)NNr1   r2   rL   r+   r   r    c                 S      | d S Nr   r   xr   r   r   <lambda>       z#_find_action_card.<locals>.<lambda>keyrK   r6   lowerappendlensort
r;   rL   rM   tr=   r>   tl
candidatesctctlr   r   r   _find_action_cards   s:   rb   c           
      C   s  t |}|sdS | dg D ]}|dg pg D ]}t |d|kr+||f    S qq|s1dS | }g }| dg D ]-}|dg pFg D ]"}t |d}|sSqG| }	||	v s_|	|v ri|t|||f qGq=|r|jdd d |d d	 |d d
 fS dS )NrN   r1   r2   rL   c                 S   rO   rP   r   rQ   r   r   r   rS      rT   z#_find_kanban_card.<locals>.<lambda>rU   r   r+   r    rW   r\   r   r   r   _find_kanban_card   s6   rc   namec           	      C   s   t |}|sd S | dg pg D ]}t |d|kr|  S q|s$d S | }g }| dg p1g D ]!}t |d}|s>q2| }||v sJ||v rS|t||f q2|rd|jdd d |d d S d S )NrB   rd   c                 S   rO   rP   r   rQ   r   r   r   rS      rT   z)_find_dashboard_project.<locals>.<lambda>rU   r   r+   rW   )	r;   rd   rM   r]   rC   r^   r_   pnpnlr   r   r   _find_dashboard_project   s.   rg   existing_textupdatec                 C   sV   |pd  }|s| pdS t  d}d| d| }| p d} || v r'| S | | S )NrG   %Y-%m-%d %H:%M %Zz


UPDATE (z):
)rJ   r   r   r   strftime)rh   ri   stampblockr   r   r   append_update   s   rn   cardfrom_col	to_col_idc                        r|sd S | d|krd S  fdd| dpg D |d< |  dg D ]}| d|kr;|dg d   d S q%td| d)	Nr3   c                       g | ]}| ur|qS r   r   .0r>   ro   r   r   
<listcomp>       z-move_card_between_columns.<locals>.<listcomp>r2   r1   r   zAction Board column '' not foundr6   
setdefaultinsertRuntimeErrorr;   ro   rp   rq   r=   r   rv   r   move_card_between_columns   s    r   c                    rr   )	Nr3   c                    rs   r   r   rt   rv   r   r   rw      rx   z$move_kanban_card.<locals>.<listcomp>r2   r1   r   zKanban column 'ry   rz   r~   r   rv   r   move_kanban_card   s    r   bodyareapriorityc                 C   s  t t}t| t|}d| d| }||d |d||d}|dg D ]}	|	ddkr8|	dg d	|  nq#td
t |di d< t	t| t t
}
t| t|
}|||d|g g d |d	}|
dg d	| t |
di d< t	t
|
 t t}t| t|}||||d d |r|d d gng g ddddgd}|dg D ]}	|	ddkr|	dg d	|  nqtdt |di d< t	t| |||fS )NzStatus: New
Priority: z	

Notes:
New)r3   rL   duer   statusr   notesr1   r3   r   r2   r   zKanban column 'todo' not foundmeta	updatedAt)	r3   rd   r   r   r   nextActionsblockersr   r   rB     shortselfzboards:auto)r3   rL   r   r   r   daysUntilDuer   r   effortactionOwnerr   tagsr	   z'Action Board column 'waiting' not found)r   KANBAN_PATHr.   r?   r6   r{   r|   r}   r   r'   DASHBOARD_PATHrD   ACTION_PATHrA   )r(   rL   r   r   r   kdockidr   kcardr=   ddocdidprojadocaidacardr   r   r   
create_new   sT   



r   update_titleupdate_bodyaction_movekanban_movec                C   s  t t}t|| |d\}}|rbt  d}d| d|   }	|dp*g }
|	r;|	|
vr;|
	d|	d d  |
|d< |rTt
|  | }t|||| t |di d	< tt| t t}t|| |d\}}|rt|d
pxd||d
< |rt|  | }t|||| t |di d	< tt| t t}t|| |d}|rt|d
pd||d
< t |di d	< tt| t|t|t|dS )N)rM   rj   zUPDATE (z): r   r   r   r   r   r   rG   )actionUpdatedkanbanUpdateddashboardUpdated)r   r   rb   r   r   r   rk   rJ   r6   r|   ACTION_COL_IDSrX   r   r   r{   r'   r   rc   rn   KANBAN_COL_IDSr   r   rg   bool)r   r   rM   r   r   r   r   acolrl   entrynacol_idr   r   kcolr   r   r   r   r   update_existing)  sB   


r   c                  C   s  t  } | jddd | jddd | jddd | jdd	d | jd
d d | jdd dd | jdddd | jdd dd | jdd dd |  }|jpVdtt  }|jrt|j|j	|j
|j|jd}t| st||j|j	|j|j\}}}ttjdd|||dddd d S ttjddd|dd d S t||j|j	|j|j\}}}ttjdd|||dddd d S ) Nz--titleT)requiredz--bodyz--areaToAssistant)defaultz
--priorityMediumz--idz--update-titlez*Existing card/project title/name to update)r   helpz--fuzzy
store_truez1Allow conservative fuzzy match if exact not found)actionr   z--action-movezEMove Action Board card to column (e.g., waiting, do_now, done_recent)z--kanban-movez7Move Kanban card to column (todo, doing, waiting, done)boards_)rM   r   r   create_fallback)kanban	dashboardr   )okmoder<   r    )r!   ri   )r   r   create)argparseArgumentParseradd_argument
parse_argsr3   inttimer   r   r   rM   r   r   anyvaluesr   rL   r   r   printr   r%   )apargsr(   resr   r   r   r   r   r   mainW  s8   	"&r   __main__)%__doc__r   r   r   r   pathlibr   typingr   r   r   r   r   r   r   strr   r   r'   r5   r.   r?   rA   rD   rK   r   r8   rb   rc   rg   rn   r   r   r   r   r   __name__r   r   r   r   <module>   sb   				&&&&4.
)
