
    6j                       d Z ddlmZ ddlZddlZddlmZmZ ddlm	Z	m
Z
 ddlmZmZ g dZdZd	 Zd
 Zd Zd ZdJdZd Zd ZdKdZdLdMdZdNdZdJddddNdZd Zd Zd ZdOd ZdPd#Zdd$dQd'Z dRd(Z!dd$dRd)Z"dd$dRd*Z#ddd+dSd-Z$dTd.Z%dd$dUd/Z&d0 Z'dd$d1Z(dd$d2Z)dd$d3Z*dUd4Z+dd$dQd5Z,d6 Z-dd$dVd8Z.d9 Z/d: Z0d; Z1d< Z2d= Z3d> Z4d? Z5d@Z6dAZ7dBZ8dC Z9dD Z:dWdFZ;dWdGZ<dWdHZ=dWdIZ>dS )Xa  Hermes Kanban bridge for the WebUI.

This module exposes a full CRUD API under ``/api/kanban/*`` while keeping
Hermes Agent's ``hermes_cli.kanban_db`` as the only source of truth.

Supported operations:
- Task CRUD (create, read, patch, bulk update, archive)
- Multi-board management (list, create, archive, switch)
- Task dependency links (create, delete)
- SSE live event stream for real-time updates
- Comments and worker dispatch integration
    )annotationsN)asdictis_dataclass)parse_qsunquote)badj)triagetodoreadyrunningblockeddonez/api/kanban/tasks/c                     ddl m}  | S )Nr   )	kanban_db)
hermes_clir   )kbs    '/root/hermes-webui/api/kanban_bridge.py_kbr      s    ******I    c                    t          | j        pd                              d          pdgd         }t          |          S )a  Validate and normalise a ?board=<slug> query param.

    Returns the normalised slug, or ``None`` when the caller omitted the
    param. Raises ValueError on a malformed slug so the bridge surfaces a
    clean 400 instead of a 500 from deeper in the library.
     boardNr   )r   queryget_normalise_board_or_raise)parsedraws     r   _resolve_boardr   !   s@     FL&B''++G44>
BC$S)))r   c                    t          | t                    sdS |                     d          }|-t          |t                    r|                                dk    rdS t          |          S )zSame contract as :func:`_resolve_board` but reads ``board`` from a
    parsed JSON body (POST / PATCH / DELETE handlers receive a dict, not
    a parsed URL). Returns ``None`` when the body did not specify a board.
    Nr   r   )
isinstancedictr   strstripr   )bodyr   s     r   _resolve_board_from_bodyr&   ,   sd    
 dD!! t
((7

C
{z#s++{		r0A0At$S)))r   c                   | -t          | t                    r|                                 dk    rdS t                      }	 |                    |           }n,# t
          t          f$ r}t          d|           |d}~ww xY w|sdS 	 t          |dd          }n# t          $ r d}Y nw xY w||k    r(|	                    |          st          d|d          |S )z7Shared normalisation + existence check for board slugs.Nr   invalid board slug: DEFAULT_BOARDdefaultboard  does not exist)r!   r#   r$   r   _normalize_board_slug
ValueErrorAttributeErrorgetattr	Exceptionboard_existsLookupError)r   r   normedexcdefault_slugs        r   r   r   9   s   
{z#s++{		r0A0At	BB))#..' B B B77788cAB t!r?I>> ! ! ! !boof&=&=<6<<<===Ms*   A B (A;;B B B)(B)c                v    t                      }|                    |            |                    |           S )Nr   )r   init_dbconnect)r   r   s     r   _connr;   P   s3    	BJJUJ::E:"""r   c                    | d S t          |           rt          |           S t          | t                    rt          |           S t          t	          | di                     S )N__dict__)r   r   r!   r"   r0   )values    r   	_obj_dictr?   V   s`    }tE e}}% E{{z2..///r   c                    t          |           }|s|S 	 t                                          |           }n# t          $ r d }Y nw xY w||d<   ||d<   |                    dd            |S )Nage_secondsageprogress)r?   r   task_ager1   
setdefault)taskdatarB   s      r   
_task_dictrH   `   s    T??D eennT""   DDKOOJ%%%Ks   !7 AAreturnintc                    	 |                      d                                          }t          |d         pd          S # t          $ r Y dS w xY w)Nz6SELECT COALESCE(MAX(id), 0) AS latest FROM task_eventslatestr   )executefetchonerJ   r1   )connrows     r   _latest_event_idrQ   n   s^    llSTT]]__3x=%A&&&   qqs   =A   
AAFnamer#   r*   boolc                    t          | j        pd                              |          pd gd         }||S t          |                                                                          dv S )Nr   r   >   1onyestrue)r   r   r   r#   r$   lower)r   rR   r*   r   s       r   _bool_queryrZ   v   sb    FL&B''++D11;dVQ
?C
{s88>>!!##'AAAr   c                    t          | j        pd                              |          pd gd         }|#t          |                                          pd nd S )Nr   r   )r   r   r   r#   r$   )r   rR   r   s      r   
_str_queryr\   }   sR    FL&B''++D11;dVQ
?C'*3s88>>#tD@r   minimummaximumc                   t          | |          }||S 	 t          |          }n# t          t          f$ r |cY S w xY w|t	          ||          }|t          ||          }|S N)r\   rJ   	TypeErrorr.   maxmin)r   rR   r*   r^   r_   r   r>   s          r   
_int_queryre      s    
VT
"
"C
{Cz"   GU##GU##Ls   & <<c                R   d |D             }	 |                      d                                          }n# t          $ r |cY S w xY w|D ]\}|                    |d         ddd          dxx         dz  cc<   |                    |d         ddd          d	xx         dz  cc<   ]|S )
Nc                $    i | ]}|j         d d dS )r   parentschildren)id.0rF   s     r   
<dictcomp>z%_task_link_counts.<locals>.<dictcomp>   s$    GGGdg1!44GGGr   z*SELECT parent_id, child_id FROM task_links	parent_idr   rh   rj      child_idri   )rM   fetchallr1   rE   )rO   taskscountsrowsrP   s        r   _task_link_countsrv      s    GGGGGF||HIIRRTT    Z Z#k*q,I,IJJ:VVVZ[[VVV#j/qa+H+HII)TTTXYYTTTTMs   '6 AAc                    	 |                      d                                          }n# t          $ r i cY S w xY wd |D             S )NzASELECT task_id, COUNT(*) AS n FROM task_comments GROUP BY task_idc                J    i | ] }|d          t          |d         pd          !S )task_idnr   rJ   rm   rP   s     r   rn   z#_comment_counts.<locals>.<dictcomp>   s.    ???3C	NCCA..???r   )rM   rr   r1   )rO   ru   s     r   _comment_countsr}      se    ||O
 

(** 	    			??$????s   '* 99c                \   t          |           }t                      }t          | d          }t          | d          }t          | dd          }t          | dd          }t	          | dd d          }d }|r*|s(	 dd	lm}	  |	            pd
}n# t          $ r d
}Y nw xY w|}t          |          5 }
t          |
          }|||k    rd|ddcd d d            S |
                    |
|||          t          |
          t          |
          fdfdt          D             }|r$|                    dfdD             d           |t          d D                       t          d D                       |dd|||||ddcd d d            S # 1 swxY w Y   d S )Ntenantassigneeinclude_archivedF	only_minesincer   r^   )get_active_profile_namer*   r8   )changedlatest_event_id	read_only)r   r   r   c                    t          |           }                    | j        ddd          |d<                       | j        d          |d<   |S )Nr   rh   link_countscomment_count)rH   r   rk   )rF   rG   comment_countsr   s     r   rP   z_board_payload.<locals>.row   sT    d##D"-//$'qVW;X;X"Y"YD$2$6$6tw$B$BD!Kr   c                6    g | ]fd D             dS )c                <    g | ]}|j         k     |          S  status)rm   rF   rR   rP   s     r   
<listcomp>z-_board_payload.<locals>.<listcomp>.<listcomp>   s.    $X$X$X4DKSWDWDWSSYYDWDWDWr   rR   rs   r   )rm   rR   rP   rs   s    @r   r   z"_board_payload.<locals>.<listcomp>   sJ     
 
 
 $X$X$X$X$X5$X$X$XYY
 
 
r   archivedc                <    g | ]}|j         d k     |          S )r   r   )rm   rF   rP   s     r   r   z"_board_payload.<locals>.<listcomp>   s-    SSS
9R9R##d))9R9R9Rr   r   c                >    h | ]}t          |d d          |j        S )r   N)r0   r   rl   s     r   	<setcomp>z!_board_payload.<locals>.<setcomp>   s,    ^^^thX\@]@]^t{^^^r   c                >    h | ]}t          |d d          |j        S )r   N)r0   r   rl   s     r   r   z!_board_payload.<locals>.<setcomp>   s-     d d d4GDR\^bDcDc d d d dr   T)r   r   r   r   profile)columnstenants	assigneesr   r   r   filters)r   r   r\   rZ   re   api.profilesr   r1   r;   rQ   
list_tasksrv   r}   BOARD_COLUMNSappendsorted)r   r   r   r   r   r   r   r   r   r   rO   r   r   r   r   rP   rs   s                @@@@r   _board_payloadr      s   6""E	B))F&*--H"6+=uEEFK77Ivwa888EG  	 <<<<<<--//<9GG 	  	  	 GGG	 	U			 +
t*400/!9!9$W\]]+
 +
 +
 +
 +
 +
 +
 +

 -	  
 
 (e44(..	 	 	 	 	 	
 
 
 
 
%
 
 
  	NN"SSSSSSS    
 ^^u^^^__ d d5 d d dee. $$4&" 
 
;+
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
s+   >B B B 5F!B5F!!F%(F%r   c                    t          | pd                                                                          }t          t                    dhz  }||vrt          d|           |S )Nr   r   zinvalid status: )r#   r$   rY   setr   r.   )r   r>   alloweds      r   _validate_statusr      sf    "##%%++--E-  J</GG3E33444Lr   ry   
new_statusc                   t                      }|                    |           5  |                     d|f                                          }|	 ddd           dS |d         dk    }|                     d|||||f          }|j        dk    r	 ddd           dS d}|r@|dk    r:|d         r2	 |                    | |d	d	d
| d          }n# t          $ r d}Y nw xY w|                     d||t          j        |dd          t          t          j
                              f           ddd           n# 1 swxY w Y   |dv r7t          |d          r'	 |                    |            n# t          $ r Y nw xY wdS )u]  Direct status write for drag-drop moves not covered by structured verbs.

    Used for ``todo <-> ready`` and ``running -> ready`` transitions. The
    structured verbs (``complete_task``, ``block_task``, ``unblock_task``,
    ``archive_task``, ``claim_task``) own their own state changes; this helper
    handles the remainder while preserving the dispatcher's contract:

    - When transitioning OFF ``running`` to anything other than the terminal
      verbs, claim_lock / claim_expires / worker_pid are nulled so the
      dispatcher doesn't see a phantom-running task. The active run (if any)
      is closed with ``outcome='reclaimed'`` so attempt history isn't
      orphaned.
    - When transitioning INTO ``running``, claim fields are preserved (this
      function is NOT used for entering 'running' — that goes through
      ``kb.claim_task()`` and the bridge rejects raw 'running' status writes
      with HTTP 400).

    Mirrors the agent dashboard plugin's ``_set_status_direct``
    (plugins/kanban/dashboard/plugin_api.py) so first-party clients see
    identical behaviour from either surface.
    z5SELECT status, current_run_id FROM tasks WHERE id = ?NFr   r   a   UPDATE tasks SET status = ?,   claim_lock = CASE WHEN ? = 'running' THEN claim_lock ELSE NULL END,   claim_expires = CASE WHEN ? = 'running' THEN claim_expires ELSE NULL END,   worker_pid = CASE WHEN ? = 'running' THEN worker_pid ELSE NULL END WHERE id = ?rp   current_run_id	reclaimedzstatus changed to z (webui/direct))outcomer   summaryzbINSERT INTO task_events (task_id, run_id, kind, payload, created_at) VALUES (?, ?, 'status', ?, ?)webui)r   source)r   r   recompute_readyT)r   	write_txnrM   rN   rowcount_end_runr1   jsondumpsrJ   timehasattrr   )rO   ry   r   r   prevwas_runningcurrun_ids           r   _set_status_directr      sr   , 
B	d		 "
 "
||CJ
 
 (** 	 <"
 "
 "
 "
 "
 "
 "
 "
 8n	1ll
 ZWE
 
 <1#"
 "
 "
 "
 "
 "
 "
 "
$  
	:22t<L7M2	''LLLL %  
      	,fdjJ')R)RSSUXY]YbYdYdUeUef	
 	
 	
="
 "
 "
 "
 "
 "
 "
 "
 "
 "
 "
 "
 "
 "
 "
F &&&727H+I+I&	t$$$$ 	 	 	D	4sT   -D;3D;D;1CD;CD;CAD;;D?D?E1 1
E>=E>r8   r%   r"   c               b   t          |                     d          pd                                          }|st          d          	 t	          |                     d          pd          }n$# t
          t          f$ r t          d          w xY wt                      }|                     d          }t          |          5 }|                    |||                     d	          pd |                     d
          pd |                     d          pd|                     d          pd ||                     d          pdt          |                     d          pd          |                     d          pd|                     d          pd |                     d          pd |                     d          pd |                     d          pd           }|rt          ||d|i           t          |                    ||                    ddcd d d            S # 1 swxY w Y   d S )Ntitler   title is requiredpriorityr   priority must be an integerr   r8   r%   r   
created_byr   r   ri   r   r
   Fworkspace_kindscratchworkspace_pathidempotency_keymax_runtime_secondsskills)r   r%   r   r   r   r   ri   r
   r   r   r   r   r   rF   r   )r#   r   r$   r.   rJ   rb   r   r;   create_taskrS   _patch_taskrH   get_task)r%   r   r   r   r   requested_statusrO   ry   s           r   _create_task_payloadr   2  s   !!'R((..00E .,---8txx
++0q11z" 8 8 867778	Bxx))	U			 Tt..&!!)TXXj))1Txx--888H%%-HHY''-2**3e4488$455B88$455= HH%677?4 $)> ? ? G488H%%- ! 
 
   	Eg2B'CDDD"2;;tW#=#=>>USS'T T T T T T T T T T T T T T T T T Ts   	$A. .!BEH$$H(+H(c                "   t                      }|                    | |          }|st          d          i }d|v rLt          |                    d          pd                                          }|st          d          ||d<   d|v r|                    d          pd |d<   d|v r|                    d          pd |d<   d|v rM	 t          |                    d          pd          |d<   n$# t          t          f$ r t          d	          w xY w|	                                D ]8\  }}t          ||          r#	 t          |||           (# t          $ r Y 4w xY w9|rd
                    d |D                       }	|                     d|	 dg |                                |           t          |d          r(|                    | |dt#          |          dd           d|v r;|                    | ||                    d          pd           st          d          d|vs|                    d          dv rd S t'          |                    d                    }
|
dk    rP|                    | ||                    d          |                    d                    st          d          d S |
dk    rQ|                    | ||                    d          p|                    d                    st          d          d S |
dk    r'|                    | |          st          d          d S |
dk    rt          d          |
d k    r{|                    | |          }|st          d          |j        dk    r'|                    | |          st          d          d S t3          | |d           st          d          d S |
d!v r"t3          | ||
          st          d          d S t          d"|
           )#Ntask not foundr   r   r   r%   r   r   r   r   z, c              3      K   | ]	}| d V  
dS )z = ?Nr   )rm   fields     r   	<genexpr>z_patch_task.<locals>.<genexpr>o  s(      DD55DDDDDDr   zUPDATE tasks SET z WHERE id = ?_append_eventupdatedr   )fieldsr   r   r   )Nr   r   resultr   )r   r   r   block_reasonreasonr   r   r   zFCannot set status to 'running' directly; use the dispatcher/claim pathr   )r
   r   zunknown status: )r   r   r3   r#   r   r$   r.   rJ   rb   itemsr   setattrr1   joinrM   valuesr   listassign_taskr   complete_task
block_taskarchive_taskr   unblock_taskr   )rO   ry   r%   r   rF   updatesr   r   r>   assignmentsr   currents               r   r   r   R  s   	B;;tW%%D ,*+++G$DHHW%%+,,2244 	20111 ~~((6**2d4 HHX..6$T	<"%dhhz&:&:&?a"@"@GJ:& 	< 	< 	<:;;;	<    u4 	eU++++   	
  eiiDDGDDDDDCCCCEaw~~GWGWEaY`Eabbb2'' 	eT7I$w--[b7c7cdddT~~dGTXXj-A-A-ITJJ 	0.///ttxx11Z??dhhx0011Fgdhhx6H6HRVRZRZ[dReReff 	0.///	0 	0	9		}}T7488N3K3K3atxxX`OaOa}bb 	0.///	0 	0	:		tW-- 	0.///	0 	0	9		 T
 
 	
 
7		 ++dG,, 	0.///>Y&&??411 4!"23334 4 &dGW== 4!"23334 4	%	%	%
 "$88 	0.///	0 	0 4F44555s   	'C1 1!D?E
EEc               H   t          | pd                                          } | st          d          t                      }t	          |          5 }t          || |           t          |                    ||                     ddcd d d            S # 1 swxY w Y   d S )Nr   task_id is requiredr8   Fr   )r#   r$   r.   r   r;   r   rH   r   )ry   r%   r   r   rO   s        r   _patch_task_payloadr     s    '-R  &&((G 0.///	B	U			 TtD'4((("2;;tW#=#=>>USST T T T T T T T T T T T T T T T T Ts   7BBBc                  t          | pd                                          } t          |                    d          pd                                          }| st          d          |st          d          t	                      }t          |          5 }|                    ||           st          d          |                    || |                    d          pd|          }d	|d
dcd d d            S # 1 swxY w Y   d S )Nr   r%   r   zbody is requiredr8   r   authorr   TF)ok
comment_idr   )	r#   r$   r   r.   r   r;   r   r3   add_comment)ry   r%   r   comment_bodyr   rO   r   s          r   _comment_payloadr     s`   '-R  &&((Gtxx''-2..4466L 0./// -+,,,	B	U			 Jt{{4)) 	0.///^^D'488H3E3E3PR^__
*5II	J J J J J J J J J J J J J J J J J Js   AC??DDunlinkr   r   c                  t          |                     d          pd                                          }t          |                     d          pd                                          }|r|st          d          t	                      }t          |          5 }|                    ||          st          d          |                    ||          st          d          |r8|                    |||          }dt          |          ||d	d
cd d d            S |
                    |||           d||d	dcd d d            S # 1 swxY w Y   d S )Nro   r   rq   z#parent_id and child_id are requiredr8   zparent task not foundzchild task not foundTF)r   r   ro   rq   r   )r   ro   rq   r   )r#   r   r$   r.   r   r;   r   r3   unlink_tasksrS   
link_tasks)r%   r   r   ro   rq   r   rO   r   s           r   _link_tasks_payloadr     s   DHH[))/R006688I488J''-2..4466H @H @>???	B	U			 	^t{{4++ 	75666{{4** 	64555 	|oodIx@@G4==y^fuz{{	^ 	^ 	^ 	^ 	^ 	^ 	^ 	^ 	dIx000W\]]	^ 	^ 	^ 	^ 	^ 	^ 	^ 	^ 	^ 	^ 	^ 	^ 	^ 	^ 	^ 	^ 	^ 	^s   A8E#EEEc                x    t                      }|                    | |          |                    | |          dS )Nrh   )r   
parent_ids	child_ids)rO   ry   r   s      r   
_links_forr     s<    	B==w//LLw//  r   c          
        t                      }t          |          5 }|                    ||           }|s	 d d d            d S t          |          d |                    ||           D             d |                    ||           D             t          ||           d |                    ||           D             ddcd d d            S # 1 swxY w Y   d S )Nr8   c                ,    g | ]}t          |          S r   r?   )rm   cs     r   r   z(_task_detail_payload.<locals>.<listcomp>  s    OOO!1OOOr   c                ,    g | ]}t          |          S r   r   )rm   es     r   r   z(_task_detail_payload.<locals>.<listcomp>  s    KKKy||KKKr   c                ,    g | ]}t          |          S r   r   )rm   rs     r   r   z(_task_detail_payload.<locals>.<listcomp>  s    GGGaYq\\GGGr   F)rF   commentseventslinksrunsr   )r   r;   r   rH   list_commentslist_eventsr   	list_runs)ry   r   r   rO   rF   s        r   _task_detail_payloadr    sI   	B	U			 
t{{4)) 	
 
 
 
 
 
 
 

 t$$OOr/?/?g/N/NOOOKKR^^D'-J-JKKKg..GG2<<g+F+FGGG
 
	
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
s   CA=CCCc                z   t          |           }t          | ddd          }t          | dddd          }t          |          5 }|                    d	||f                                          }g }|}|D ]}	 |d
         rt          j        |d
                   nd }	n# t          $ r d }	Y nw xY w|                    |d         |d         |d         |d         |	|d         d           t          |d                   }t          |          }
|s
||
k    r|
n|}|||ddcd d d            S # 1 swxY w Y   d S )Nr   r   r   limit   rp   r]   r8   kSELECT id, task_id, run_id, kind, payload, created_at FROM task_events WHERE id > ? ORDER BY id ASC LIMIT ?payloadrk   ry   r   kind
created_atrk   ry   r   r  r  r  F)r  cursorr   r   )r   re   r;   rM   rr   r   loadsr1   r   rJ   rQ   )r   r   r   r  rO   ru   r  r  rP   r  rL   s              r   _events_payloadr    s   6""Evw1555EvwQDDDE	U			 ct||DEN
 
 (**	 	
  	$ 	$C8;IP$*S^444D   MM$iy>h-F"!,/     T^^FF!$'' 	:$VVEF Fv\abb3c c c c c c c c c c c c c c c c c cs7   3D0;$B D0 B/,D0.B//A4D00D47D4c                   t                      }	 t          |           5 }	 t          |                    |                    }n# t          $ r g }Y nw xY wd d d            n# 1 swxY w Y   n# t          $ r g }Y nw xY w	 ddlm}  |            pi }n# t          $ r i }Y nw xY w|                    d          pi                     d          pi }t          ||                    d          pdt          |                    dd	                    t          |                    d
d                    t          |                    dd	                    ddS )Nr8   r   )load_config	dashboardkanbandefault_tenantr   lane_by_profileTinclude_archived_by_defaultFrender_markdown)r   r   r  r  r  r  r   )
r   r;   r   known_assigneesr1   hermes_cli.configr  r   r   rS   )r   r   rO   r   r  cfgk_cfgs          r   _config_payloadr#    s   	B 	4 !3!3D!9!9::		   				 	 	 	 	 	 	 	 	 	 	 	 	 	 	
    			111111kmm!r   ggk""(b--h77=2E ))$455;		*;T B BCC'+EII6SUZ,[,['\'\		*;T B BCC  si   A/ A#"AA#AA#AA#A/ #A''A/ *A'+A/ /A>=A>B B$#B$c                   t                      }t          |           5 }t          |d          r!|                    |          cd d d            S |                    d                                          }i }i }|D ]g}t          |d         pd          }|                    |d         d          |z   ||d         <   |d         pd}|                    |d          |z   ||<   h||d	cd d d            S # 1 swxY w Y   d S )
Nr8   board_statszfSELECT status, assignee, COUNT(*) AS n FROM tasks WHERE status != 'archived' GROUP BY status, assigneerz   r   r   r   
unassigned)	by_statusby_assignee)r   r;   r   r%  rM   rr   rJ   r   )	r   r   rO   ru   r'  r(  rP   rz   r   s	            r   _stats_payloadr)  )  s   	B	U			 Dt2}%% 	(>>$''D D D D D D D D ||t
 

(** 	 	 	E 	ECCHM""A'0}}S]A'F'F'JIc(m$:6,H$/OOHa$@$@1$DK!!&{CCD D D D D D D D D D D D D D D D D Ds   %C7BC77C;>C;c                D   t                      }t          |           5 }	 t          |                    |                    }nC# t          $ r6 |                    d                                          }d |D             }Y nw xY wd d d            n# 1 swxY w Y   d|iS )Nr8   zcSELECT DISTINCT assignee FROM tasks WHERE assignee IS NOT NULL AND assignee != '' ORDER BY assigneec                    g | ]
}|d          S )r   r   r|   s     r   r   z&_assignees_payload.<locals>.<listcomp>D  s    999SZ999r   r   )r   r;   r   r  r1   rM   rr   )r   r   rO   r   ru   s        r   _assignees_payloadr,  ;  s    	B	U			 :t	:R//5566II 	: 	: 	:<<u hjj  :9D999III		:: : : : : : : : : : : : : : : ##s4   B"AB=BBBBBBc           	        t          |           }t                      }t          | dd dd          }t          |          5 }|                    ||          s	 d d d            d S 	 d d d            n# 1 swxY w Y   t          |d          s	|ddd	ddd
S |                    ||          }t          |d          r|                    |          nd }	 |r-|                                r|	                                j
        nd	}n# t          $ r d	}Y nw xY w|t          |pd          |d u||pdt          |o||k              d
S )Ntailrp   i r]   r8   read_worker_logr   Fr   )ry   pathexists
size_bytescontent	truncated)
tail_bytesworker_log_path)r   r   re   r;   r   r   r/  r6  r1  statst_sizeOSErrorr#   rS   )	r   ry   r   r   r.  rO   r3  log_pathsizes	            r   _task_log_payloadr<  H  s   6""E	BffdAyIIID	U			 t{{4)) 	       	               2()) u"B%q]_nsttt  T ::G.5b:K.L.LVr!!'***RVH*2Ox7H7HOx}}&&a    HN##%=b$.4$;//  s$   A44A8;A81D	 	DDc          
     $   d |                      d          pg D             }|st          d          g }t                      }t          |          5 }|D ]}|dd}	 |                    ||          s-|                    dd	           |                    |           L|                      d
          r.|                    ||          s|                    dd	           n;|                      d          &t          ||d|                      d          i           |                      d          C|	                    |||                      d          pd           s|                    dd	           |                      d          	 t          |                      d                    }|                    d||f           t          |d          r|                    ||d|dd           n.# t          t          f$ r |                    dd	           Y nw xY wn;# t          $ r.}	|                    dt!          |	          	           Y d }	~	nd }	~	ww xY w|                    |           	 d d d            n# 1 swxY w Y   |ddS )Nc                    g | ]D}t          |                                          #t          |                                          ES r   )r#   r$   )rm   is     r   r   z'_bulk_tasks_payload.<locals>.<listcomp>b  s9    
M
M
Mac!ffllnn
M3q66<<>>
M
M
Mr   idszids is requiredr8   T)rk   r   Fz	not found)r   errorarchivezarchive refusedr   r   zassign refusedr   z*UPDATE tasks SET priority = ? WHERE id = ?r   reprioritizedr   )r   r   r   )resultsr   )r   r.   r   r;   r   updater   r   r   r   rJ   rM   r   r   rb   r1   r#   )
r%   r   r@  rD  r   rO   ry   entryr   r5   s
             r   _bulk_tasks_payloadrG  a  s   
M
MDHHUOO$9r
M
M
MC ,*+++G	B	U			 "t 	" 	"G"$//E7{{411 LLEL===NN5)))88I&& O??499 H5FGGGXXh''3g$((8:L:L/MNNN88J''3>>$*9M9M9UQUVV G5EFFF88J''3x#&txx
';';#<#< %QT\^eSfggg"277 x,,T7OZbnuMvMvwww &z2 T T T5RSSSSST  7 7 7SXX666666667NN5!!!!5	"" " " " " " " " " " " " " " "8 U333so   JAH#!J"C+H#"G40AH#4(HH#HH#"J#
I-$IJIJJ	Jc                   t          |           }t                      }t          | dd          }t          | dddd          }t	          |d          st          d	          t          |
          5 }|                    |||          }d d d            n# 1 swxY w Y   t          |t                    r|S 	 t          |          S # t          $ r dt          |          icY S w xY w)Ndry_runFrc      rp   d   r]   dispatch_oncezdispatcher is unavailabler8   )rI  	max_spawnr   )r   r   rZ   re   r   r.   r;   rL  r!   r"   r   rb   r#   )r   r   r   rI  rM  rO   r   s          r   _dispatch_payloadrN    sI   6""E	B&)U33G65!QDDDI2'' 64555	U			 Nt!!$9!MMN N N N N N N N N N N N N N N&$ 'f~~ ' ' '#f++&&&&'s$   2BBB:C	 	C'&C'actionc                  t                      }t          | pd                                          } | st          d          t	          |          5 }|                    ||           st          d          |dk    rA|                    || |                    d          p|                    d                    }nU|d	k    r=t          |d
          r|
                    ||           }n(t          || ddi           d}nt          d|           |st          | d          t          |                    ||                     ddcd d d            S # 1 swxY w Y   d S )Nr   r   r8   r   blockr   r   r   unblockr   r   r   Tzinvalid action: z refusedFr   )r   r#   r$   r.   r;   r   r3   r   r   r   r   r   RuntimeErrorrH   )ry   r%   rO  r   r   rO   r   s          r   _task_action_payloadrT    s   	B'-R  &&((G 0.///	U			 Tt{{4)) 	0.///WtWTXXh5G5G5c488TbKcKcddBBy  r>** __T733D'Hg+>???888999 	4&222333"2;;tW#=#=>>USST T T T T T T T T T T T T T T T T Ts   C;EE"Ec                    t          | t                    s| S t          |           }dD ]&}||v r ||         t          ||                   ||<   '|S )zCoerce the library's board metadata dict into a JSON-serialisable
    form. ``list_boards`` returns dicts with Path values for ``directory``;
    json.dumps would refuse those without help.)	directorydb_pathr0  )r!   r"   r#   )metaoutkeys      r   _board_meta_dictr[    s`     dD!! 
t**C/ % %#::#c(.3s8}}CHJr   c                   t                      }|                    |           si S 	 |                    |           }n# t          $ r i cY S w xY w	 |                    d                                          }d |D             	 |                                 S # t          $ r Y S w xY w# t          $ r* i cY 	 |                                 S # t          $ r Y S w xY ww xY w# 	 |                                 w # t          $ r Y w w xY wxY w)a&  Per-status task counts for a board, used to populate the board
    switcher with a live "12 tasks" badge. Mirrors the agent dashboard's
    ``_board_counts`` helper. Returns an empty dict for boards whose
    sqlite file has not been materialized yet (freshly-created boards
    with no tasks).r8   zRSELECT status, COUNT(*) AS n FROM tasks WHERE status != 'archived' GROUP BY statusc                J    i | ] }|d          t          |d         pd          !S )r   rz   r   r{   r|   s     r   rn   z*_board_counts_for_slug.<locals>.<dictcomp>  s.    BBBcHs3s8=q11BBBr   )r   r2   r:   r1   rM   rr   close)slugr   rO   ru   s       r   _board_counts_for_slugr`    sg    
B??4   	zzz%%   			||9
 
 (** 	 CBTBBB	JJLLLL 	 	 	D	    			JJLLLL 	 	 	D		JJLLLL 	 	 	D	s{   > AA2B) B
B&%B&)C5C  7C
CCCC   D"C76D7
DDDDc                ~   t                      }t          | dd          }|                    |          }	 |                                }n# t          $ r d}Y nw xY wd |D             }t          |dd          }||vr(	 |                                 n# t          $ r Y nw xY w|}g }|D ]}t          |          }	|	                    d          }
|
)|
|k    |	d	<   t          |
          |	d
<   |	d
         r't          |	d
                                                   nd|	d<   |                    |	           ||ddS )u   GET /api/kanban/boards — return all boards on disk + active slug.

    Each entry includes per-status counts and an ``is_current`` flag so the
    UI can render the switcher in a single round-trip.
    r   F)r   r*   c                R    h | ]$}t          |                              d           %S )r_  )r[  r   )rm   rX  s     r   r   z'_list_boards_payload.<locals>.<setcomp>  s/    MMMd&t,,0088MMMr   r)   r_  N
is_currentrt   r   total)boardsr   r   )r   rZ   list_boardsget_current_boardr1   r0   clear_current_boardr[  r   r`  sumr   r   )r   r   r   re  r   visible_slugsr6   rY  raw_metarX  r_  s              r   _list_boards_payloadrl    s    
B"6+=uEE^^-=^>>F&&((   MMfMMMM2	::Lm##
	""$$$$ 	 	 	D	
C  ))xx<"go\/55X8<XMDN1133444AW

4gEBBBs#   A AA B 
B"!B"c           	        t                      }t          | t                    st          d          t	          |                     d          pd                                          }|st          d          	 |                    ||                     d          pd|                     d          pd|                     d          pd|                     d	          pd
          }n6# t          t          f$ r"}t          t	          |                    |d}~ww xY w|                     d          rS	 |	                    |d                    n6# t          t          f$ r"}t          t	          |                    |d}~ww xY w	 |
                                }n# t          $ r d}Y nw xY wt          |          |ddS )u  POST /api/kanban/boards — create a new board.

    Body fields: ``slug`` (required), ``name``, ``description``, ``icon``,
    ``color``, ``switch`` (bool — set as active after creation, default false).
    Idempotent on slug — repeating returns the existing board metadata.
    body must be a JSON objectr_  r   zslug is requiredrR   Ndescriptioniconcolor)rR   ro  rp  rq  switchr*   F)r   r   r   )r   r!   r"   r.   r#   r   r$   create_boardr/   set_current_boardrg  r1   r[  )r%   r   r_  rX  r5   r   s         r   _create_board_payloadru    s    
BdD!! 75666txx%2&&,,..D -+,,,	,&!!)T//74&!!)T((7##+t  
 
 ' , , ,S""+,xx 0	0  f....N+ 	0 	0 	0SXX&&C/	0&&((   %d++eTTTsC   ;A.C* *D;DD6E F#F  F	F F-,F-c                   t                      }t          |t                    st          d          	 |                    |           }n,# t          t
          f$ r}t          d|           |d}~ww xY w|r|                    |          st          d| d          |                    d          }t          |t                    r(|
                                                                dv }|                    ||                    d          |                    d	          |                    d
          |                    d          t          |t                    r|nd          }t          |          ddS )uZ  PATCH /api/kanban/boards/<slug> — update a board's display metadata.

    The slug itself is immutable (changing it would mean moving the on-disk
    directory and re-pointing every saved active-board cookie). Only
    ``name``, ``description``, ``icon``, ``color``, and ``archived`` are
    mutable here; the slug travels in the URL path.
    rn  r(   Nr+   r,   r   >   rU   rV   rW   rX   rR   ro  rp  rq  )rR   ro  rp  rq  r   F)r   r   )r   r!   r"   r.   r-   r/   r2   r3   r   r#   r$   rY   write_board_metadatarS   r[  )r_  r%   r   r4   r5   r   rX  s          r   _update_board_payloadrx  (  s    
BdD!! 75666C))$//' C C C88899sBC <00 <:4:::;;;xx
##H(C   J>>##))++/II""XXfHH]++XXfhhw'$77AT #  D &d++%@@@s   A
 
A3A..A3c                b   t                      }t          |dd          }	 |                    |           }n,# t          t          f$ r}t          d|           |d}~ww xY w|r|                    |          st          d| d          	 t          |dd          }n# t          $ r d}Y nw xY w||k    rt          d	          |	                    || 
          }	 |
                                }n# t          $ r d}Y nw xY wt          |t                    rt          |          n||ddS )u  DELETE /api/kanban/boards/<slug> — archive (default) or hard-delete.

    ``?delete=1`` is required to actually remove on-disk artefacts; without
    it the board is just marked archived in its metadata and remains
    enumerable via ``?include_archived=1`` on /boards.
    deleteFr(   Nr+   r,   r)   r*   zcannot remove the default board)rB  )r   r   r   )r   rZ   r-   r.   r/   r2   r3   r0   r1   remove_boardrg  r!   r"   r[  )	r_  r   r   hard_deleter4   r5   r6   resr   s	            r   _delete_board_payloadr~  G  s    
Bfh66KC))$//' C C C88899sBC <00 <:4:::;;;!r?I>> ! ! ! !:;;;
//&k//
:
:C&&((    ,6c4+@+@I"3'''c  s9   7 A AA B   B/.B/ C5 5DDc                ,   t                      }	 |                    |           }n,# t          t          f$ r}t          d|           |d}~ww xY w|r|                    |          st          d| d          |                    |           |ddS )u  POST /api/kanban/boards/<slug>/switch — set this board as active.

    The active-board pointer is stored on disk under ``<root>/kanban/current``
    and is shared by the CLI, gateway, dashboard, and WebUI — switching
    here switches everywhere. The UI also keeps a localStorage hint so
    that opening a fresh tab doesn't always have to round-trip to discover
    the active slug, but the on-disk pointer is the source of truth.
    r(   Nr+   r,   F)r   r   )r   r-   r.   r/   r2   r3   rt  )r_  r   r4   r5   s       r   _switch_board_payloadr  m  s     
BC))$//' C C C88899sBC <00 <:4:::;;;   E222s   & AA

Ag333333?g      .@r  c                   t                      }| D	 t          |dd          }n# t          $ r d}Y nw xY w| |k    r|                    |           s|g fS 	 |                    |           }n# t          $ r |g fcY S w xY w	 |                    dt          |          t          f                                          }n9# t          $ r, |g fcY 	 |	                                 S # t          $ r Y S w xY ww xY w	 	 |	                                 n:# t          $ r Y n.w xY w# 	 |	                                 w # t          $ r Y w w xY wxY wg }|}|D ]}d}		 |d         }
|
rt          j        |
          }	n# t          $ r d}	Y nw xY w|                    t          |d                   |d         |d	         |d
         |	|d         t          |d                   ndd           t          |d                   }||fS )u#  Read events with id > cursor from the given board's task_events
    table. Returns ``(new_cursor, events_list)``. Best-effort — returns
    the input cursor and an empty list on any DB error so the SSE loop
    self-heals on transient sqlite contention rather than dropping the
    client.Nr)   r*   r8   r  r  rk   ry   r   r  r  r  )r   r0   r1   r2   r:   rM   rJ   _KANBAN_SSE_BATCH_LIMITrr   r^  r   r  r   )r   r  r   r6   rO   ru   rY  
new_cursorr  r  r   s              r   _kanban_sse_fetch_newr    s    
B
 	%"2	BBLL 	% 	% 	%$LLL	%L  )?)? 2:zzz&&   rz||D[[12
 
 (**	 	
    rz	JJLLLL 	 	 	D	 		JJLLLL 	 	 	D		JJLLLL 	 	 	D	
CJ " "	I,C **S// 	 	 	GGG	

ag,,|kfI23L/2M#ao...SW
 
 	 	 	 4\\

s?s   $ 33A- -A>=A><B? >D ?C5D C$$
C10C14C55D :D 
DDE!D65E6
E EEEE33FFc           	        	 t          |          }nT# t          t          f$ r@}t          | t	          |          t          |t                    rdnd          cY d}~S d}~ww xY wt          |j        pd          }|                    d          pdgd         }|.	 | j	                            d          }n# t          $ r d}Y nw xY w	 |t          |          nd}n# t          t          f$ r d}Y nw xY w|dk     rd}|                     d	           |                     d
d           |                     dd           |                     dd           |                     dd           |                                  	 | j                            dt%          j        ||d           d                    d                     | j                                         n$# t,          t.          t          t0          f$ r Y dS w xY wt3          j                    }	 	 t7          ||          \  }}|rt%          j        ||d          }	d| d|	 d                    d          }
	 | j                            |
           | j                                         n$# t,          t.          t          t0          f$ r Y dS w xY wt3          j                    }nt3          j                    |z
  t8          k    rl	 | j                            d           | j                                         n$# t,          t.          t          t0          f$ r Y dS w xY wt3          j                    }t3          j        t<                     [# t          $ r Y dS w xY w)uY  GET /api/kanban/events/stream — long-lived SSE feed of task events.

    Query params:
      since=<int>   Resume from this event id. Defaults to 0 (full backlog
                    on first connect — the client should pass the latest
                    id it knows about so it does not re-receive historical
                    events.) Capped to the most recent _KANBAN_SSE_BATCH_LIMIT.
      board=<slug>  Pin the stream to a specific board. Switching boards
                    requires the client to close and re-open the stream.

    Header (set automatically by EventSource on reconnect):
      Last-Event-ID  Fallback resume cursor when ?since= is absent. The
                     server emits ``id: <event_id>`` on every events frame
                     so the browser can resume cleanly across drops without
                     re-receiving up to _KANBAN_SSE_BATCH_LIMIT events the
                     client already has.

    Mirrors the agent dashboard's WebSocket /events contract event-for-event
    so a client that handles one can handle the other with only the
    transport swapped.
    i    r   Nr   r   r   zLast-Event-IDr  zContent-Typez text/event-stream; charset=utf-8zCache-Controlzno-cachezX-Accel-Bufferingno
Connectionz
keep-alivezevent: hello
data: )r  r   z

zutf-8T)r  r  zid: z
event: events
data: s   : keepalive

)r   r.   r3   r   r#   r!   r   r   r   headersr1   rJ   rb   send_responsesend_headerend_headerswfilewriter   r   encodeflushBrokenPipeErrorConnectionResetErrorr9  r   	monotonicr  _KANBAN_SSE_HEARTBEAT_SECONDSsleep_KANBAN_SSE_POLL_SECONDS)handlerr   r   r5   qs	since_rawr  last_heartbeatr  r  frames              r   _handle_events_sse_streamr    s   ,Zv&&$ Z Z Z7CHHJsJ4O4O-XSSUXYYYYYYYYYZ 
&,$"	%	%B
 *TFA.I	++O<<II 	 	 	III	#,#8Yaz"   zz#(JKKK444+T222l333
W4:%.P.P#Q#QWWW^^_fgg	
 	
 	
 	1:wG   tt ^%%N 	125&AANFF 6 *&%I%IJJG6GG'GGG&//  M''...M''))))')=z7S      44 !%!1!1
 N$$~5:WWW$++,>???++----+-A:wW $ $ $#tt$%)^%5%5NJ/0007	18     tts    A#5AA#A#B8 8CCC C54C5AG" "HHA	M6 $3J M6 J95M6 8J996M6 03L$ #M6 $MM6 M1M6 6
NNbool | Nonec                ~   |j         }	 |dk    rt          | t          |                    pdS |dk    rt          | t          |                    pdS |dk    r-t          | t	          t          |                              pdS |dk    r-t          | t          t          |                              pdS |dk    r-t          | t          t          |                              pdS |dk    rt          | t          |                    pdS |d	k    rt          | |          S |
                    t                    r|                    d
          rt          |t          t                    t          d
                                                  d          }|rd|v rdS t!          ||          }|t#          | dd          S t          | |          pdS |
                    t                    rt          |t          t                    d                                       d          }|rd|v rdS t%          |t          |                    }|t#          | dd          S t          | |          pdS dS # t&          $ r}t#          | d| d          cY d}~S d}~wt(          $ r)}t#          | t+          |          d          cY d}~S d}~wt,          $ r'}t#          | t+          |                    cY d}~S d}~wt.          $ r)}t#          | t+          |          d          cY d}~S d}~ww xY w)u  Dispatch a Kanban GET. Three-valued return:

    - ``False`` — no Kanban path matched; caller should emit a 404
      (``_kanban_unknown_endpoint``) for genuinely stale-bundle requests.
    - ``None`` — a path matched and the inner handler already sent a
      response via ``bad(...)`` / ``j(...)`` (which both return ``None``).
      The caller MUST NOT emit another response.
    - ``True`` — a path matched and the inner handler succeeded.

    Treat any falsy-but-not-False return (``0``, ``''``, etc.) as a bug and
    audit the new return path; the caller uses ``is False`` identity check
    to distinguish unmatched paths from already-responded paths (#1843).
    /api/kanban/boardsTz/api/kanban/boardz/api/kanban/configr8   z/api/kanban/statsz/api/kanban/assigneesz/api/kanban/eventsz/api/kanban/events/streamz/log/FNr   r  r   kanban unavailable:     )r0  r	   rl  r   r#  r   r)  r,  r  r  
startswith_TASK_PREFIXendswithr   lenr$   r<  r   r  ImportErrorr3   r#   r.   rS  )r  r   r0  ry   r  r5   s         r   handle_kanban_getr  3  s    ;D-2 '''W26::;;CtC&&&WnV4455=='''WoN64J4JKKKLLTPTT&&&Wn>&3I3IJJJKKStS***W0~f7M7MNNNOOWSWW'''Wof5566>$>...,Wf===??<(( 	/T]]6-B-B 	/d3|#4#4c&kk\#ABCCII#NNG cWnnu'88G7$4SAAAAWg&&.$.??<(( 	/d3|#4#4#5#5677==cBBG cWnnu*7.:P:PQQQG7$4SAAAAWg&&.$.u F F F 78388EEEEEEEEE 2 2 27CHHS111111111 & & &7CHH%%%%%%%% 2 2 27CHHS1111111112s   $J $J 2J 2J 92J ,$J J 'A?J (#J J AJ <1J .J 
L<J& L<&L<3KL<L<$L L<L<L71L<7L<c           
     B   |j         }	 |dk    rt          | t          |                    pdS d}|                    |          r|                    d          rlt          |t          |          t          d                                                  d          }|rd|v rdS t          | t          |                    pdS t          |          }t          |          }||n|}|dk    rt          | t          |                    pdS |d	k    r!t          | t          ||
                    pdS |dk    r!t          | t          ||
                    pdS |dk    r!t          | t          ||
                    pdS |dk    r"t          | t          |d|                    pdS |                    t                    rt|                    d          r_|t          t                    t          d                                        d          }	t          | t!          |	||
                    pdS dD ]\  }
}|                    t                    rw|                    |
          rb|t          t                    t          |
                                        d          }	t          | t#          |	|||
                    pdc S |                    t                    rt|                    d          r_|t          t                    t          d                                        d          }	t          | t%          |	||
                    pdS n# t&          $ r}t)          | d| d          cY d}~S d}~wt*          $ r)}t)          | t-          |          d          cY d}~S d}~wt.          $ r'}t)          | t-          |                    cY d}~S d}~wt0          $ r)}t)          | t-          |          d          cY d}~S d}~ww xY wdS )ztDispatch a Kanban POST. See ``handle_kanban_get`` for the
    three-valued ``True | None | False`` contract (#1843).r  T/api/kanban/boards/z/switchr  FNz/api/kanban/dispatchz/api/kanban/tasks/bulkr8   z/api/kanban/tasks/api/kanban/linksz/api/kanban/links/deleter   z	/comments))z/blockrQ  )z/unblockrR  z/patchr  r  r   r  r  )r0  r	   ru  r  r  r   r  r$   r  r   r&   rN  rG  r   r   r  r   rT  r   r  r   r3   r#   r.   rS  )r  r   r%   r0  _BOARDS_PREFIXr_  board_qboard_br   ry   suffixrO  r5   s                r   handle_kanban_postr  r  s    ;D-2 '''W3D99::BdB.??>** 	Ct}}Y/G/G 	C4N 3 3S^^O CDEEKKCPPD 3$;;uW3D99::BdB !((*400".G)))W/7788@D@+++W1$eDDDEEMM&&&W24uEEEFFN$N&&&W1$eDDDEEMM---W1$t5QQQRRZVZZ??<(( 	TT]];-G-G 	T3|,,c+.>.>->>?EEcJJGW.wEJJJKKStSL 	d 	dNFF|,, dv1F1F ds<00#f++=>DDSII"6wfTY"Z"Z"Z[[c_cccc??<(( 	WT]]8-D-D 	W3|,,c(mm^;<BB3GGGW1'4uMMMNNVRVV F F F78388EEEEEEEEE 2 2 27CHHS111111111 & & &7CHH%%%%%%%% 2 2 27CHHS11111111125s   $M" A7M" 'M" AM" &M" 6&M" &M" 'M" ,BM" :BM" BM" "
P,N PPN71P7PO& P&P3PPPc                   |j         }	 d}|                    |          r_t          |t          |          d                                       d          }|rd|v rdS t          | t          ||                    pdS t          |          }t          |          }||n|}|                    t                    rft          |t          t                    d                                       d          }	|	rd|	v rdS t          | t          |	||                    pdS n# t          $ r}
t          | d|
 d	          cY d}
~
S d}
~
wt          $ r)}
t          | t          |
          d
	          cY d}
~
S d}
~
wt          $ r'}
t          | t          |
                    cY d}
~
S d}
~
wt           $ r)}
t          | t          |
          d	          cY d}
~
S d}
~
ww xY wdS )zuDispatch a Kanban PATCH. See ``handle_kanban_get`` for the
    three-valued ``True | None | False`` contract (#1843).r  Nr  FTr8   r  r  r   r  r  )r0  r  r   r  r$   r	   rx  r   r&   r  r   r  r   r3   r#   r.   rS  )r  r   r%   r0  r  r_  r  r  r   ry   r5   s              r   handle_kanban_patchr    sN    ;D2 /??>** 	I4N 3 3 4 4566<<SAAD 3$;;uW3D$??@@HDH !((*400".G??<(( 	Wd3|#4#4#5#5677==cBBG cWnnuW1'4uMMMNNVRVV		W
  F F F78388EEEEEEEEE 2 2 27CHHS111111111 & & &7CHH%%%%%%%% 2 2 27CHHS11111111125sg   AD$ D$ ?B D$ !D$ $
G.EGGE93G9GF("G(G5GGGc                   |j         }	 d}|                    |          r_t          |t          |          d                                       d          }|rd|v rdS t          | t          ||                    pdS t          |          }t          |          }||n|}|dk    r"t          | t          |d|                    pdS n# t          $ r}	t          | d|	 d	
          cY d}	~	S d}	~	wt          $ r)}	t          | t          |	          d
          cY d}	~	S d}	~	wt          $ r'}	t          | t          |	                    cY d}	~	S d}	~	wt          $ r)}	t          | t          |	          d
          cY d}	~	S d}	~	ww xY wdS )zvDispatch a Kanban DELETE. See ``handle_kanban_get`` for the
    three-valued ``True | None | False`` contract (#1843).r  Nr  FTr  r   r  r  r   r  r  )r0  r  r   r  r$   r	   r~  r   r&   r   r  r   r3   r#   r.   rS  )
r  r   r%   r0  r  r_  r  r  r   r5   s
             r   handle_kanban_deleter    s    ;D2 /??>** 	K4N 3 3 4 4566<<SAAD 3$;;uW3D&AABBJdJ ((*400".G&&&W1$t5QQQRRZVZZ ' F F F78388EEEEEEEEE 2 2 27CHHS111111111 & & &7CHH%%%%%%%% 2 2 27CHHS11111111125sa   AC C ?AC 
FC0*F0F=D!F!F.E
FFF;FFra   )rI   rJ   )F)rR   r#   r*   rS   rI   rS   )rR   r#   )r   r#   rI   r#   )ry   r#   r   r#   rI   rS   )r%   r"   )ry   r#   r%   r"   )r%   r"   r   rS   )ry   r#   rI   r"   )ry   r#   )ry   r#   r%   r"   rO  r#   )rI   r  )?__doc__
__future__r   r   r   dataclassesr   r   urllib.parser   r   api.helpersr   r	   r   r  r   r   r&   r   r;   r?   rH   rQ   rZ   r\   re   rv   r}   r   r   r   r   r   r   r   r   r   r  r  r#  r)  r,  r<  rG  rN  rT  r[  r`  rl  ru  rx  r~  r  r  r  r  r  r  r  r  r  r  r   r   r   <module>r     s    # " " " " "   , , , , , , , , * * * * * * * *        III#  * * *
* 
* 
*  .# # # #0 0 0     B B B B BA A A A
4      	 	 	@ @ @=
 =
 =
B   ? ? ? ?D /3 T T T T T T@V6 V6 V6 V6r <@ T T T T T T 9= J J J J J J 7<4 ^ ^ ^ ^ ^ ^"    15 
 
 
 
 
 
 c c c@ "     8 ! D D D D D$ !% 
$ 
$ 
$ 
$ 
$   2 .2 "4 "4 "4 "4 "4 "4J' ' '" JN T T T T T T>
 
 
  8#C #C #CL U  U  UFA A A># # #L3 3 3B   !%   6 6 6r` ` `F<2 <2 <2 <2~2 2 2 2j# # # #L     r   