
    PL
jd                   $   d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	m
Z
 ddlmZmZ ddlmZ ddd	d
dddZdWdZdXdZdYdZdZdZd[dZd\d Zd]d$Zd^d%Zd]d&Zd_d)Zd]d*Zd]d+Zd]d,Zd]d-Zd]d.Z d]d/Z!d`d0Z"d]d1Z#d]d2Z$d]d3Z%d]d4Z&d]d5Z'd]d6Z(d]d7Z)d]d8Z*d]d9Z+d]d:Z,d]d;Z-d]d<Z.d]d=Z/d]d>Z0dad@Z1d]dAZ2d]dBZ3d]dCZ4d]dDZ5d]dEZ6d]dFZ7d]dGZ8d]dHZ9d]dIZ:d]dJZ;d]dKZ<d]dLZ=d]dMZ>d]dNZ?d]dOZ@d]dPZAd]dQZBd]dRZCd]dSZDdTZEdbdVZFdS )cu"  CLI for the Hermes Kanban board — ``hermes kanban …`` subcommand.

Exposes the full 15-verb surface documented in the design spec
(``docs/hermes-kanban-v1-spec.pdf``).  All DB work is delegated to
``kanban_db``.  This module adds:

  * Argparse subcommand construction (``build_parser``).
  * Argument dispatch (``kanban_command``).
  * Output formatting (plain text + ``--json``).
  * A short shared helper that parses a single slash-style string
    (used by ``/kanban …`` in CLI and gateway) and forwards it to the
    argparse surface.
    )annotationsN)Path)AnyOptional)	kanban_dbu   ◻u   ▶   ●u   ⊘u   ✓u   —)todoreadyrunningblockeddonearchivedtsOptional[int]returnstrc                X    | sdS t          j        dt          j        |                     S )N z%Y-%m-%d %H:%M)timestrftime	localtime)r   s    5/home/kuhnn/.hermes/hermes-agent/hermes_cli/kanban.py_fmt_tsr   +   s,     r=)4>"+=+=>>>    tkb.Taskc           
         t                               | j        d          }| j        pd}| j        rd| j         dnd}| d| j         d| j        dd|d	| d| j         
S )
N?(unassigned) []r      8s20s)_STATUS_ICONSgetstatusassigneetenantidtitle)r   iconr)   r*   s       r   _fmt_task_liner.   1   s    QXs++Dz+^H!"1!(rFMMQTMMQXMMMHMM&MMAGMMMr   dict[str, Any]c                2   i d| j         d| j        d| j        d| j        d| j        d| j        d| j        d| j        d	| j        d
| j	        d| j
        d| j        d| j        d| j        d| j        rt          | j                  ng d| j        S )Nr+   r,   bodyr)   r(   priorityr*   workspace_kindworkspace_path
created_by
created_at
started_atcompleted_atresultskillsmax_retries)r+   r,   r1   r)   r(   r2   r*   r3   r4   r5   r6   r7   r8   r9   r:   listr;   )r   s    r   _task_to_dictr=   8   s    ad 	 	AJ	
 	!( 	AJ 	!( 	!* 	!* 	al 	al 	al 	 	!( 	AH4$qx..."  	q}! r   valuetuple[str, Optional[str]]c                \   | sdS |                                  }|dv r|dfS |                    d          r`|t          d          d                                          }|st          j        d          dt
          j                            |          fS t          j        d| d          )	zoParse ``--workspace`` into ``(kind, path|None)``.

    Accepts: ``scratch``, ``worktree``, ``dir:<path>``.
    )scratchN>   rA   worktreeNzdir:z0--workspace dir: requires a path after the colondirzunknown --workspace value z&: use scratch, worktree, or dir:<path>)strip
startswithlenargparseArgumentTypeErrorospath
expanduser)r>   vrJ   s      r   _parse_workspace_flagrM   M   s    
  !  A###4y||F 1V$$&& 	,B   rw))$//00

$TUTTT  r   tuple[bool, str]c                 L   	 ddl m}  n# t          $ r Y dS w xY w	  |             }n# t          $ r Y dS w xY w	 ddlm}  |            }t          |                    di                               dd                    }n# t          $ r d}Y nw xY w|r
|rdd| d	fS |r|sd
S dS )u  Return ``(running, message)``.

    - ``running=True``: a gateway is alive for this HERMES_HOME and its
      config has ``kanban.dispatch_in_gateway`` on (default). Message
      is a short status line.
    - ``running=False``: either no gateway is running, or the gateway
      is running but the config flag is off. Message is human guidance
      explaining the next step.

    Used by ``hermes kanban create`` (and callers) to warn when a task
    will sit in ``ready`` because nothing is there to pick it up.
    Defensive against import failures and config-read errors — if the
    probe itself errors, we return ``(True, "")`` so we don't spam
    false warnings (better to miss a warning than to cry wolf).
    r   )get_running_pid)Tr   load_configkanbandispatch_in_gatewayTzgateway pid=z, dispatch enabled)Fu   Gateway is running but kanban.dispatch_in_gateway=false in config.yaml — the task will sit in 'ready' until you flip it back on and restart the gateway, OR run the legacy standalone daemon (`hermes kanban daemon --force`).)Fu   No gateway is running — the task will sit in 'ready' until you start it. Run:
    hermes gateway start
The gateway hosts an embedded dispatcher (tick interval 60s by default); your task will be picked up on the next tick after the gateway comes up.)gateway.statusrP   	Exceptionhermes_cli.configrR   boolr'   )rP   pidrR   cfgdispatch_ons        r   _check_dispatcher_presencer\   c   s3    2222222   zzo   zz111111kmm3778R00445JDQQRR     >{ ><S<<<==
 
; 

 
 s*   	 

& 
44AB   BBparent_subparsersargparse._SubParsersActionargparse.ArgumentParserc           	        |                      ddd          }|                    dddd	           |                    d
          }|                     dd           |                     ddd          }|                    d          }|                     ddgd          }|                    dd           |                    ddd           |                     ddgd          }|                    d d!           |                    d"dd#$           |                    d%dd&$           |                    d'dd($           |                    d)dd*$           |                    d+dd,           |                     d-d.d/gd0          }|                    d            |                    d1dd2           |                     d3d4gd5          }|                    d            |                     d6d7gd8           |                     d9d:          }	|	                    d            |	                    d;d<           |                     dd=          }
|
                    d>d?           |
                    d@ddA$           |
                    dBddC$           |
                    dDdEg dFG           |
                    dHdIdJ$           |
                    dKddL$           |
                    dMt          dNdOP           |
                    dQddR           |
                    dSddT$           |
                    dUddV$           |
                    dWdXdY$           |
                    dZdEg d[d\]           |
                    d^t          dd_d`t          j         dab           |
                    dddc           |                     ddgdd          }|                    deddf           |                    dBdg           |                    dhdt          t          j                  i           |                    dKdg           |                    djddk           |                    dd           |                     d6dl          }|                    dm           |                    dd           |                     dndo          }|                    dm           |                    dpdq           |                     drds          }|                    dm           |                    dtddu$           |                     dvdw          }|                    dm           |                    dpdx           |                    dyddz           |                    dtddu$           |                     d{d|gd}          }|                    d~g ddd           |                    ddd$           |                    ddd           |                     dd          }|                    d           |                    d           |                     dd          }|                    d           |                    d           |                     dd          }|                    dm           |                    dt          t          j        dP           |                     dd          }|                    dm           |                    ddd           |                    ddd$           |                     dd          }|                    ddd           |                    ddd$           |                    ddd$           |                    ddd$           |                     dd          }|                    dm           |                    ddd           |                    ddd$           |                    ddd$           |                     dd          }|                    dm           |                    ddd           |                    dddd           |                     dd          }|                    dd           |                     dd          }|                    dd           |                     dd          }|                    dm           |                    dt          d           |                     dd          }|                    ddd           |                    dt          ddP           |                    dt          t          j
        dt          j
         dP           |                    dd           |                     ddĬ          }|                    dt          ddƬP           |                    dt          ddǬP           |                    dt          t          j
                   |                    dddɬ$           |                    dddd̬           |                    ddt          j                   |                     ddϬ          }|                    dBddЬ$           |                    dKddѬ$           |                    dddӬ$           |                    dt          ddլP           |                     dd׬          }|                    dd           |                     dd٬          }|                    dm           |                    ddۦ           |                    ddۦ           |                    ddg           |                    ddg           |                    ddd$           |                     dd          } |                     dmdd           |                     dd           |                     dd          }!|!                    dm           |!                    ddۦ           |!                    ddۦ           |!                    ddg           |                     dd          }"|"                    dm           |"                    dt          ddP           |                     dd          }#|#                    dm           |#                    dd           |                     dd          }$|$                    dm           |$                    ddd$           |                     dd          }%|%                    dd           |                     dd          }&|&                    dm           |                     dd          }'|'                    dmddd           |'                    dddd           |'                    dKdd$           |'                    ddd$           |'                    ddd           |                     dd          }(|(                    dmddd            |(                    dddd           |(                    dKdd$           |(                    ddd$           |(                    ddd           |                     dd          })|)                    dt          ddP           |)                    dt          dd	P           |                    |
           |S (  zAttach the ``kanban`` subcommand tree under an existing subparsers.

    Returns the top-level ``kanban`` parser so caller can ``set_defaults``.
    rS   z:Multi-profile collaboration board (tasks, links, comments)a7  Durable SQLite-backed task board shared across Hermes profiles. Tasks are claimed atomically, can depend on other tasks, and are executed by a named profile in an isolated workspace. See https://hermes-agent.nousresearch.com/docs/user-guide/features/kanban or docs/hermes-kanban-v1-spec.pdf for the full design.)helpdescriptionz--boardNz<slug>zBoard slug to operate on. Defaults to the current board (set via `hermes kanban boards switch <slug>` or the HERMES_KANBAN_BOARD env var). Use `hermes kanban boards list` to see all boards.)defaultmetavarra   kanban_actiondestinitz(Create kanban.db if missing (idempotent))ra   boardsz9Manage kanban boards (one board per project / workstream)u  Boards let you separate unrelated streams of work (projects, repos, domains) into isolated queues. Each board has its own DB, workspaces directory, and dispatcher loop — tasks on one board cannot collide with tasks on another. The first board is 'default' and always exists.boards_actionr<   lsz List all boards with task counts)aliasesra   z--json
store_true)actionz--allzInclude archived boards too)rn   ra   createnewzCreate a new boardslugz*Board slug (kebab-case, e.g. atm10-server)z--namez<Human-readable display name (defaults to Title Case of slug))rc   ra   z--descriptionzOptional descriptionz--iconz9Optional emoji or single-character icon for the dashboardz--colorz5Optional hex color (e.g. '#8b5cf6') for the dashboardz--switchz)Switch to the new board after creating itrmremovedeletez#Archive (default) or delete a boardz--deletezxHard-delete the board directory instead of archiving it. Default is to move it to boards/_archived/ so it's recoverable.switchusez-Set the active board for subsequent CLI callsshowcurrentz%Print the currently-active board slugrenamez@Change a board's human-readable display name (slug is immutable)namezNew display namezCreate a new taskr,   z
Task titlez--bodyzOptional opening postz
--assigneezProfile name to assignz--parentappendzParent task id (repeatable))rn   rc   ra   z--workspacerA   z2scratch | worktree | dir:<path> (default: scratch)z--tenantzTenant namespacez
--priorityr   zPriority tiebreaker)typerc   ra   z--triageuJ   Park in triage — a specifier will flesh out the spec and promote to todoz--idempotency-keyzkDedup key. If a non-archived task with this key exists, its id is returned instead of creating a duplicate.z--max-runtimezPer-task runtime cap. Accepts seconds (300) or durations (90s, 30m, 2h, 1d). When exceeded, the dispatcher SIGTERMs (then SIGKILLs) the worker and re-queues the task.z--created-byuserz0Author name recorded on the task (default: user)z--skillr:   zSkill to force-load into the worker (repeatable). Appended to the built-in kanban-worker skill. Example: --skill translation --skill github-code-review)rn   rc   rg   ra   z--max-retriesNu   Per-task override for the consecutive-failure circuit breaker. Trip on the Nth failure — e.g. --max-retries 1 blocks on the first failure (no retries), --max-retries 3 allows two retries. Omit to use the dispatcher's kanban.failure_limit config (default z).)r|   rc   rd   ra   zEmit JSON outputz
List tasksz--minez%Filter by $HERMES_PROFILE as assignee)rc   z--status)rc   choicesz
--archivedzInclude archived tasksz"Show a task with comments + eventstask_idassignzAssign or reassign a taskprofilez$Profile name (or 'none' to unassign)reclaimz0Release an active worker claim on a running taskz--reasonz7Human-readable reason (recorded on the reclaimed event)reassignzCReassign a task to a different profile, optionally reclaiming firstz(New profile name (or 'none' to unassign)z	--reclaimzIRelease any active claim before reassigning (required if task is running)diagnosticsdiagz,List active diagnostics on the current boardz
--severitywarningerrorcriticalz/Only show diagnostics at or above this severity)r   rc   ra   z--taskz%Only show diagnostics for one task idz9Emit JSON (structured) instead of the default human tablelinkzAdd a parent->child dependency	parent_idchild_idunlinkz!Remove a parent->child dependencyclaimz>Atomically claim a ready task (prints resolved workspace path)z--ttlz#Claim TTL in seconds (default: 900)commentzAppend a commenttext+zComment body)nargsra   z--authorz0Author name (default: $HERMES_PROFILE or 'user')completezMark one or more tasks donetask_idsz;One or more task ids (only --result applies to all of them)z--resultzResult summaryz	--summaryzSStructured handoff summary for downstream tasks. Falls back to --result if omitted.z
--metadatazlJSON dict of structured facts (e.g. '{"changed_files": [...], "tests_run": 12}'). Stored on the closing run.editz1Edit recovery fields on an already-completed taskTz+Backfilled task result text for a done task)requiredra   z>Structured handoff summary. Falls back to --result if omitted.zCJSON dict of structured facts to store on the latest completed run.blockzMark one or more tasks blockedreason*z#Reason (also appended as a comment)z--idsz=Additional task ids to block with the same reason (bulk mode))r   rc   ra   unblockz)Return one or more blocked tasks to ready)r   archivezArchive one or more taskstailzFollow a task's event streamz
--intervalg      ?)r|   rc   dispatchz@One dispatcher pass: reclaim stale, promote ready, spawn workersz	--dry-runz<Don't actually spawn processes; just print what would happenz--maxzCap number of spawns this passz--failure-limitzrAuto-block a task after this many consecutive non-success attempts (spawn_failed, timed_out, or crashed; default: )daemonuN   DEPRECATED — dispatcher now runs in the gateway. Use `hermes gateway start`.g      N@z,Seconds between dispatch ticks (default: 60)zCap number of spawns per tickz	--pidfilez,Write the daemon's PID to this file on startz	--verbosez-vz!Log each tick's outcome to stdoutz--forcewatchz8Live-stream task_events to the terminal (Ctrl+C to exit)z3Only show events for tasks assigned to this profilez*Only show events from tasks in this tenantz--kindsz[Comma-separated event kinds to include (e.g. 'completed,blocked,gave_up,crashed,timed_out')g      ?z'Poll interval in seconds (default: 0.5)statsz3Per-status + per-assignee counts + oldest-ready agenotify-subscribeziSubscribe a gateway source to a task's terminal events (used by /kanban subscribe in the gateway adapter)z
--platform)r   z	--chat-idz--thread-idz	--user-idz--notifier-profilezNProfile gateway that owns/delivers this subscription (default: active profile)notify-listz>List notification subscriptions (optionally for a single task)r   )r   rc   notify-unsubscribez)Remove a gateway subscription from a tasklogzAPrint the worker log for a task (from <kanban-root>/kanban/logs/)z--tailzOnly print the last N bytesrunszUShow attempt history for a task (one row per run: profile, outcome, elapsed, summary)	heartbeatzBEmit a heartbeat event for a running task (worker liveness signal)z--notez3Optional short note attached to the heartbeat event	assigneeszoList known profiles + per-profile task counts (union of ~/.hermes/profiles/ and current assignees on the board)contextz[Print the full context a worker sees for a task (title + body + parent results + comments).specifyzFlesh out a triage-column task into a concrete spec (title + body) and promote it to todo. Uses the auxiliary LLM configured under auxiliary.triage_specifier.z3Task id to specify (required unless --all is given)
all_triagez1Specify every task currently in the triage column)rg   rn   ra   z7When used with --all, restrict the sweep to this tenantzSAuthor name recorded on the audit comment (default: $HERMES_PROFILE or 'specifier')z'Emit one JSON object per task on stdout	decomposezDecompose a triage-column task into a graph of child tasks routed to specialist profiles by description. Falls back to specify-style single-task promotion when the task doesn't benefit from fan-out. Uses auxiliary.kanban_decomposer.z5Task id to decompose (required unless --all is given)z3Decompose every task currently in the triage columnzTAuthor name recorded on the audit comment (default: $HERMES_PROFILE or 'decomposer')gczBGarbage-collect archived-task workspaces, old events, and old logsz--event-retention-days   zEDelete task_events older than N days for terminal tasks (default: 30)z--log-retention-daysz7Delete worker log files older than N days (default: 30))_kanban_parser)
add_parseradd_argumentadd_subparsersintkbDEFAULT_FAILURE_LIMITsortedVALID_STATUSESDEFAULT_CLAIM_TTL_SECONDSfloatDEFAULT_SPAWN_FAILURE_LIMITrG   SUPPRESSset_defaults)*r]   kanban_parsersubp_boards
boards_subb_listb_createb_rmb_switchb_renamep_createp_listp_showp_assign	p_reclaim
p_reassignp_diagp_linkp_unlinkp_claim	p_comment
p_completep_editp_block	p_unblock	p_archivep_tailp_dispp_daemonp_watchp_statsp_nsubp_nlistp_nrmp_logp_runsp_hbp_asgp_ctx	p_specifyp_decomposep_gcs*                                             r   build_parserr      s   
 &00IE	 1 
 
M  !  
 
 
 
&
&O
&
<
<C NN6 JNKKK ~~HG	  
 
H ((o(>>J""/ #  F 666
:  < < < $$5'! %  H &K  M M M(D]  _ _ _/45  7 7 7(DZ  \ \ \)TV  X X X*\J  L L L   x*2 !  D 	fj]  ^ ^ ^ $$5'< %  H &!!!4    
 $$O %  H &!!!&'9::: ~~h-@~AAH'555(D7NOOO,;STTT*Xr<  > > >-S  U U U*d9KLLL,S!BWXXX*\k  m m m-t U  V V V /4 9  : : :
 .&Q  S S S)Hbx P  Q Q Q
 /T"% H ,.+C H  H  H  I I I (<>PQQQ ^^FTF^FFF
D  F F F
d333

D &r'8 9 9  ; ; ;

D111
\5  7 7 7
666 ^^F)M^NNF
	"""
666 ~~h-H~IIH)$$$)*PQQQ ?   I 9%%%DF    
 R    J I&&&7     LX     DF     ^^;   F
 000>	     4    
 H     ^^F)I^JJF
$$$

###~~h-P~QQH+&&&*%%% nnM   G ###sB4PC  E E E y/ABBI9%%%6>BBB:t R  T T T 
1NOOJJc!^  ` ` `J;KLLLK"F  G G G L$"S  T T T ^^@   F 	"""
:    
 M    
 R     nnW+KnLLG###3XYYYT]  _ _ _ y/Z[[I:S111y/JKKI:S111 ^^F)G^HHF
	"""
5#>>> ^^O   F L[  ] ] ]
c4=  ? ? ?
) " >qOQOmq q q  r r r 666 ~~]   H ,UDM  O O O'T>  @ @ @+#"$"@  B B B+tM  O O O+tLB  D D D
 )L'0  2 2 2 nnG   G tS  U U UTJ  L L LDU  V V V E3G  I I I nnK   G ,777 ^^B   F
 	"""
t444
d333
t444
T222
d]    
 nnM   G #t<<<,777NN8   E 
y!!!	|d333	{T222	}d333 NNP   E 
y!!!	xc49  ; ; ; ^^*   F
 	"""
666 >>Q   D 	i   hP  R R R NNQ   E
 
x555 NN;   E
 
y!!! @   I B	     @	     F    
 9     6     ..G !  K D	     B	     F    
 :     6     >>W   D 	.S"b  d d d,3T  V V V m<<<r   argsargparse.Namespacer   c                  	
 t          | dd          }|sEt          | dd          }||                                 nt          dt          j                   dS t          | dd          }t
          j                            d          	d	
d;	
fd}|r	 t          j	        |          }n6# t          $ r)}t          d| t          j                   Y d}~dS d}~ww xY w|st          dt          j                   dS |t          j        k    r8t          j        |          s$t          d|d| dt          j                   dS |t
          j        d<   d
|dk    r)	 t          |            |             S #  |             w xY w	 t          j                     n@# t          $ r3}t          d| t          j                    |             Y d}~dS d}~ww xY wi dt           dt"          dt$          dt$          dt&          dt(          dt*          dt,          dt.          d t.          d!t0          d"t2          d#t4          d$t6          d%t8          d&t:          d't<          i d(t>          d)t@          d*tB          d+tD          d,tF          d-tH          d.tJ          d/tL          d0tN          d1tP          d2tR          d3tT          d4tV          d5tX          d6tZ          d7t\          d8t^          d9t`          i}|                    |          }|s*t          d:|t          j                    |             dS 	 tc           ||           pd           |             S # t          td          f$ r=}t          d| t          j                    |             Y d}~ |             dS d}~ww xY w#  |             w xY w)<u   Entry point from ``hermes kanban …`` argparse dispatch.

    Returns a shell-style exit code (0 on success, non-zero on error).
    re   Nr   z`usage: hermes kanban <action> [options]
Run 'hermes kanban --help' for the full list of actions.filer   boardHERMES_KANBAN_BOARDFr   Nonec                 v    sd S  "t           j                            dd            d S  t           j        d<   d S )Nr   )rI   environpop)prev_board_envrestore_board_envs   r   _restore_board_envz*kanban_command.<locals>._restore_board_env  sF      	F!JNN0$777770>BJ,---r   zkanban:    zkanban: --board requires a slugzkanban: board = does not exist. Create it with `hermes kanban boards create `.   Tri   z'kanban: could not initialize database: rh   ro   r<   rk   rw   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   zkanban: unknown action )r   r   )3getattr
print_helpprintsysstderrrI   r   r'   r   _normalize_board_slug
ValueErrorDEFAULT_BOARDboard_exists_dispatch_boardsinit_dbrV   	_cmd_init_cmd_create	_cmd_list	_cmd_show_cmd_assign_cmd_reclaim_cmd_reassign_cmd_diagnostics	_cmd_link_cmd_unlink
_cmd_claim_cmd_comment_cmd_complete	_cmd_edit
_cmd_block_cmd_unblock_cmd_archive	_cmd_tail_cmd_dispatch_cmd_daemon
_cmd_watch
_cmd_stats_cmd_log	_cmd_runs_cmd_heartbeat_cmd_assignees_cmd_notify_subscribe_cmd_notify_list_cmd_notify_unsubscribe_cmd_context_cmd_specify_cmd_decompose_cmd_gcr   RuntimeError)r   rn   parserboard_overrider   normedexchandlershandlerr   r   s            @@r   kanban_commandr-    sN   
 T?D11F /66KZ   
 q T7D11NZ^^$9::N? ? ? ? ? ? ?  !	-n==FF 	 	 	"S""444411111	  	3#*EEEE1 R%%%bof.E.E%J J J?EJ J JZ   
 1,2
() 
 	!#D))        

   ===CJOOOOqqqqq
$I$K$ 	I$ 	I	$
 	I$ 	K$ 	L$ 	M$ 	'$ 	$$ 	I$ 	K$ 	J$ 	L$ 	M$  	I!$" 	J#$ $$ 	L%$& 	L'$( 	I)$* 	M+$, 	K-$. 	J/$0 	J1$2 	H3$4 	I5$6 	^7$8 	^9$: 	3;$< 	.=$> 	5?$@ 	LA$B 	LC$D 	nE$ $F 	GG$ $HJ ll6""G 222DDDDq774==%A&& 	 %   SZ0000qqq
 	sf   B, ,
C6CC!E: :F
F 
G((GG=M! !N/2(N*N2 *N//N2 2N>c                     dD ]'} t           j                            |           }|r|c S (	 ddlm}  |            pdS # t
          $ r Y dS w xY w)z4Best-effort author name for an interactive CLI call.)HERMES_PROFILE_NAMEHERMES_PROFILEr   )get_active_profile_namer}   )rI   r   r'   hermes_cli.profilesr1  rV   )envrL   r1  s      r   _profile_authorr4  "  s    8  JNN3 	HHH	??????&&((2F2   vvs   > 
AAc                P   t          | dd          pd}|dv rt          |           S |dv rt          |           S |dv rt          |           S |dv rt	          |           S |dv rt          |           S |d	k    rt          |           S t          d
|t          j	                   dS )at  Handle ``hermes kanban boards <action>``.

    Boards management is deliberately separate from the task-level
    commands: it operates on the filesystem (board directories,
    ``current`` pointer, ``board.json``), not on the per-board SQLite
    DB, so a fresh HERMES_HOME that has never called ``kanban init``
    can still run ``boards create`` / ``boards list``.
    rj   Nr<   >   rk   r<   >   rp   ro   >   rr   rt   rs   >   rv   ru   >   rw   rx   ry   zkanban boards: unknown action r   r   )
r   _cmd_boards_list_cmd_boards_create_cmd_boards_rm_cmd_boards_switch_cmd_boards_show_cmd_boards_renamer   r   r   )r   r   s     r   r  r  3  s     $
.
.
8&C
n%%%
!$'''
(((d###
!$'''
!!!%%%
h!$'''	
23
2
2DDDD1r   rq   dict[str, int]c                >   	 t          j        |           }|                                si S t          j        |           5 }|                    d                                          }ddd           n# 1 swxY w Y   d |D             S # t          $ r i cY S w xY w)zDReturn ``{status: count}`` for a board. Safe to call on an empty DB.)r   z7SELECT status, COUNT(*) AS n FROM tasks GROUP BY statusNc                F    i | ]}|d          t          |d                   S )r(   n)r   .0rs     r   
<dictcomp>z&_board_task_counts.<locals>.<dictcomp>W  s(    777Q(S3[[777r   )r   kanban_db_pathexistsconnectexecutefetchallrV   )rq   rJ   connrowss       r   _board_task_countsrK  M  s    
 t,,,{{}} 	IZd### 	t<<I hjj 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 87$7777   			s:   *B B (A6*B 6A::B =A:>B BBc           
        t          t          | dd                    }t          j        |          }t          j                    }|D ]S}|d         |k    |d<   t          |d                   |d<   t          |d                                                   |d<   Tt          | dd          r&t          t          j
        |d	d
                     dS |st          d           dS t          ddddddddd           |D ]}|d         rdnd}|d         pi }d                    d t          |                                          D                       pd}|                    d          pd}|                    d          r|dz  }t          |dd|d         dd|dd|            t                       t          d|            t          |          dk    rt          d           dS ) NallFinclude_archivedrq   
is_currentcountstotaljsonr   indentensure_asciir   uD   (no boards — create one with `hermes kanban boards create <slug>`)r   2sr#   SLUG24sNAME28s  COUNTSr   r"   , c              3  *   K   | ]\  }}| d | V  dS =N rA  krL   s      r   	<genexpr>z#_cmd_boards_list.<locals>.<genexpr>q  s0      DDTQjjQjjDDDDDDr   z(empty)rz   r   z [archived]Current board: r   z8Switch boards with `hermes kanban boards switch <slug>`.)rX   r   r   list_boardsget_current_boardrK  sumvaluesr   rS  dumpsjoinr   itemsr'   rF   )	r   rO  ri   rx   bmarkerrQ  
counts_strrz   s	            r   r6  r6  \  s9   GD%7788^-=>>>F"$$G / /V9/,(633(8++--..'

tVU## dj>>>???q TUUUq	R
8
8
8f
8
8
8F
8
8
8
8999 
I 
IL/2s8"IIDDVFLLNN-C-CDDDDD  	 uuV}}"55 	"M!DGGGaiGGGtGGG:GGHHHH	GGG	
%G
%
%&&&
6{{QHIII1r   c                   	 t          j        | j                  }n6# t          $ r)}t	          d| t
          j                   Y d }~dS d }~ww xY w|st	          dt
          j                   dS t          j        |          o|t           j        k    }t          j	        || j
        | j        | j        | j                  }|rdnd}t	          d|d	         d
| d           t	          d|                    dd                      t	          d|d                     t          | dd          r4t          j        |d	                    t	          d|d	         d           nt	          d|d	          d           dS )Nzkanban boards create: r   r   z&kanban boards create: slug is required)rz   rb   r-   colorzalready existscreatedBoard rq   r"   .  Display name: rz   r     DB path:      db_pathru   Fz  Switched to z#  Use `hermes kanban boards switch z` to make it current.r   )r   r   rq   r   r   r   r   r  r  create_boardrz   rb   r-   rq  r'   r   set_current_board)r   r)  r*  alreadymetaverbs         r   r7  r7    s   )$)44   ,s,,3:>>>>qqqqq  6SZHHHHqof%%D&B4D*DG?Y$Yj  D  '5ID	
+4<
+
+D
+
+
+,,,	
3TXXfb11
3
3444	
.T)_
.
.///tXu%% Y
T&\***0tF|0001111WDLWWWXXX1    
AA

Ac                x   	 t          j        | j        t          | dd                     }n6# t          $ r)}t          d| t          j                   Y d }~dS d }~ww xY w|d         dk    r1t          d	|d
         d|d                     t          d           nt          d	|d
         d           dS )Nrt   F)r   zkanban boards rm: r   r   rn   r   rs  rq   u    archived → new_pathzERecover by moving the directory back to <root>/kanban/boards/<slug>/.z	 deleted.r   )r   remove_boardrq   r   r   r   r   r   )r   resr*  s      r   r8  r8    s    odiWT8U5S5S1STTT   (3((sz::::qqqqq 8}
""Es6{EEC
OEEFFF . 	/ 	/ 	/ 	/ 	/s6{///0001s   +. 
A!AA!c                   	 t          j        | j                  }n6# t          $ r)}t	          d| t
          j                   Y d }~dS d }~ww xY w|st	          dt
          j                   dS t          j        |          s$t	          d|d| dt
          j                   dS t          j        |           t	          d	|d
           dS )Nzkanban boards switch: r   r   z&kanban boards switch: slug is requiredzkanban boards switch: board r   r   r   zActive board is now rt  r   )	r   r   rq   r   r   r   r   r  ry  )r   r)  r*  s      r   r9  r9    s   )$)44   ,s,,3:>>>>qqqqq  6SZHHHHq?6"" F6 F F;AF F F	
 	
 	
 	

 q   	
,
,
,
,---1r}  c                b   t          j                    }t          j        |          }t          |          }t	          |                                          }t          d|            t          d|                    dd                      |                    d          rt          d|d                     t          d|d                     t          d	| d
|rBdd                    d t          |
                                          D                        dndz              dS )Nre  ru  rz   r   rb   z  Description:  rv  rw  z  Tasks:        z total (r]  c              3  *   K   | ]\  }}| d | V  dS r_  ra  rb  s      r   rd  z#_cmd_boards_show.<locals>.<genexpr>  s0      JJ41aqJJ1JJJJJJJJr   r   r   )r   rg  read_board_metadatarK  rh  ri  r   r'   rk  r   rl  )r   rx   r{  rQ  rR  s        r   r:  r:    s<   "$$G!'**D((F  E	
%G
%
%&&&	
3TXXfb11
3
3444xx 86m!466777	
.T)_
.
.///	
*U
*
*
*M$))JJ6&,,..3I3IJJJJJMMMM  ! ! ! 1r   c                   	 t          j        | j                  }n6# t          $ r)}t	          d| t
          j                   Y d }~dS d }~ww xY w|rt          j        |          s&t	          d| j        dt
          j                   dS t          j        || j	                  }t	          d|d	|d
         d           dS )Nzkanban boards rename: r   r   zkanban boards rename: board z does not existr   )rz   rs  z renamed to rz   rt  r   )
r   r   rq   r   r   r   r   r  write_board_metadatarz   )r   r)  r*  r{  s       r   r;  r;    s    )$)44   ,s,,3:>>>>qqqqq  00 ITYIII:	 	 	 	q"6	:::D	
:6
:
:f
:
:
:;;;1r}  c                   | | dk    rdS t          |                                                                           }	 t          |          S # t          $ r Y nw xY wddddd}|rf|d         |v r\	 t          |dd                   }n%# t          $ r}t	          d	|           |d}~ww xY wt          |||d                  z            S t	          d	| d
          )u   Parse ``30s`` / ``5m`` / ``2h`` / ``1d`` or a raw integer → seconds.

    Returns None for empty input. Raises ValueError on malformed input so
    the CLI can surface a usage error cleanly.
    Nr   r   <     iQ )smhdzmalformed duration z( (expected 30s, 5m, 2h, 1d, or a number))r   rD   lowerr   r   r   )valr  unitsr?  r*  s        r   _parse_durationr    s    {cRiitC  A1vv    "4e44E %QrUe^^	EafAA 	E 	E 	E:3::;;D	E1uQrU|#$$$
Z3ZZZ
[
[[s)   A 
AA2B
 

B,B''B,c                   t          j                    }t          d|            t                       	 t          j                    }n# t          $ r g }Y nw xY w|r8t          dt          |           d           |D ]}t          d|            nt          d           t          d           t                       t          d           t          d           t                       t          d	           d
S )NzKanban DB initialized at zDiscovered z7 profile(s) on disk; any of these can be an --assignee:r#   z,No profiles found under ~/.hermes/profiles/.z@Create one with `hermes -p <name> setup` before assigning tasks.zCNext step: start the gateway so ready tasks actually get picked up.z  hermes gateway startzThe gateway hosts an embedded dispatcher that ticks every 60 seconds
by default (config: kanban.dispatch_interval_seconds). Without a
running gateway, tasks stay in 'ready' forever.r   )r   r  r   list_profiles_on_diskrV   rF   )r   rJ   profilesrz   s       r   r  r    s6   :<<D	
,d
,
,---	GGG+--    R #CMM # # # 	$ 	$ 	$ 	 	D+t++	 	<===PQQQ	GGG	
OPPP	
"###	GGG		:  
 1s   A	 	AAc           
     V   t          j                    5 }t          j        || j        t	          | dd           t          | j                            }d d d            n# 1 swxY w Y   |s&t          d| j         dt          j                   dS t          d| j                    dS )	Nnote)r  expected_run_idzcannot heartbeat z (not running?)r   r   zHeartbeat recorded for r   )	r   rF  heartbeat_workerr   r   _worker_run_id_forr   r   r   r   rI  oks      r   r  r    s    	 
 Lvt,,.t|<<	
 
 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
  ?$,???cjQQQQq	
2DL
2
23331s   ?AA#&A#c                :   t          j                    5 }t          j        |          }d d d            n# 1 swxY w Y   t          | dd          r&t	          t          j        |dd                     dS |st	          d           dS t	          ddd	d
dd           |D ]w}|d         rdnd}|d         pi }d                    d t          |	                                          D                       pd}t	          |d         dd	|dd	|            xdS )NrS  Fr   rT  r   uA   (no assignees — create a profile with `hermes -p <name> setup`)rZ  r%   r#   zON DISKr$   r\  on_diskyesnorQ  r]  c              3  *   K   | ]\  }}| d | V  dS r_  ra  rb  s      r   rd  z!_cmd_assignees.<locals>.<genexpr>9  0      LLTQjjQjjLLLLLLr   z(idle)rz   )
r   rF  known_assigneesr   r   rS  rj  rk  r   rl  )r   rI  dataentryr  rQ  	count_strs          r   r  r  +  s   	 (!$''( ( ( ( ( ( ( ( ( ( ( ( ( ( (tVU## djae<<<===q QRRRq	V
1
1
19
1
1
1
1222 A A +5%%x&BIILLVFLLNN5K5KLLLLLXPX	v???g???I??@@@@1   599c                l   t          | j                  \  }}	 t          t          | dd                     }n6# t          $ r)}t          d| t          j                   Y d }~dS d }~ww xY wt          | dd           }|'|dk     r!t          d| dt          j                   dS t          j	                    5 }t          j
        || j        | j        | j        | j        pt                      ||| j        | j        t%          | j        pd	          t)          t          | d
d                    t          | dd           |t          | dd           pd |          }t          j        ||          }d d d            n# 1 swxY w Y   t          | dd          r2t          t-          j        t1          |          dd                     njt          d| d|j         d|j        pd d           |j        dk    r:|j        r3t5                      \  }	}
|	s |
rt          d|
 t          j                   dS )Nmax_runtimezkanban: --max-runtime: r   r   r;   r   z(kanban: --max-retries must be >= 1 (got z&); use 1 to trip on the first failure.ra  triageFidempotency_keyr:   )r,   r1   r)   r5   r3   r4   r*   r2   parentsr  r  max_runtime_secondsr:   r;   rS  rT  zCreated z  (z, assignee=-r   r
   u   
⚠  r   )rM   	workspacer  r   r   r   r   r   r   rF  create_taskr,   r1   r)   r5   r4  r*   r2   tupleparentrX   get_taskrS  rj  r=   r(   r\   )r   ws_kindws_pathr  r*  r;   rI  r   taskr   messages              r   r  r  >  s   ,T^<<GW%gdM4&H&HII   ---CJ????qqqqq $t44K;??2{ 2 2 2	
 	
 	
 	

 q	 *.*];/*;*;"";]$++,,h6677#D*;TBB +44008D#
 
 
" {4))%* * * * * * * * * * * * * * *& tVU## <djt,,QUKKKLLLLTTTT[TTT]=QcTTTUUU ;'!!dm!9;;GW <w <)))
;;;;1s(   8 
A+A&&A+;B5E<<F F c           	        | j         }| j        r|st                      }t          j                    5 }t          j        |           t          j        ||| j        | j        | j	                  }d d d            n# 1 swxY w Y   t          | dd          r0t          t          j        d |D             dd                     dS 	 t          j        d          }n# t          $ r g }Y nw xY wt!          |          d	k    rFt          j                    }t!          |          d	z
  }t          d
| d| d|d	k    rdnd d           |st          d           dS |D ]}t          t%          |                     dS )N)r)   r(   r*   rO  rS  Fc                ,    g | ]}t          |          S ra  )r=   )rA  r   s     r   
<listcomp>z_cmd_list.<locals>.<listcomp>  s     :::q-**:::r   r   rT  r   rN  r   zBoard: r  z other boardr  r   u"    — `hermes kanban boards list`)
z(no matching tasks))r)   miner4  r   rF  recompute_ready
list_tasksr(   r*   r   r   r   rS  rj  rf  rV   rF   rg  r.   )r   r)   rI  tasks
all_boardsrx   other_countr   s           r   r  r  s  s   }Hy % %"$$	 

 	4   ;;!]
 
 
	

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 tVU## dj::E:::1SXYYYZZZq^U;;;

   



:&((*oo).g . .. .0;q0@0@b. . .	
 	
 	

  #$$$q ! !nQ    1s#   =A;;A?A?C C-,C-c                8   t          j                    5 }t          j        || j                  }|s1t	          d| j         t
          j                   	 d d d            dS t          j        || j                  }t          j        || j                  }t          j	        || j                  }t          j
        || j                  }t          j        || j                  }t          j        || j                  }d d d            n# 1 swxY w Y   t          | dd          r[t          |          |||d |D             d |D             d |D             d	}	t	          t          j        |	d
d                     dS t	          d|j         d|j                    t	          d|j                    t	          d|j        pd            |j        rt	          d|j                    t	          d|j         |j        r
d|j         ndz              |j        r*t	          dd                    |j                              |j        t	          d|j         d           n	 ddlm}
  |
            }|                    di           pi                     d          }n# t<          $ r d }Y nw xY w|>t?          |          t           j         k    r!t	          dt?          |           d           nt	          dt           j          d           t	          dtC          |j"                   d |j#        pd            dd!l$m%} |&                    |||          }|rFd"d#d$d%}t	          d&tO          |           d'           |D ]}t	          d(|                    |j(        d)           d*|j(         d+|j                    |j)        rg }|j)        *                                D ]l\  }}tW          |tX                    r8|-                    | d,d-                    d. |D                                   R|-                    | d,|            m|r%t	          d/d0                    |                      |j.        D ] }|j/        rt	          d1|j0                    !|j1        r$t	          d2tC          |j1                              |j2        r$t	          d3tC          |j2                              |r%t	          d4d                    |                      |r%t	          d5d                    |                      |j3        r1t	                       t	          d6           t	          |j3                   |j4        r2t	                       t	          d7           t	          |j4                   n.|r,t	                       t	          d8           t	          |           |rgt	                       t	          d9tO          |           d'           |D ]6}t	          d:tC          |j"                   d+|j5         d|j3                    7|rt	                       t	          d;tO          |           d'           |d<d          D ]Z}|j6        r
d=|j6         nd}|j7        rd>|j7         d?nd}t	          d:tC          |j"                   d?| d=|j8         |            [|r,t	                       t	          d@tO          |           d'           |D ]}|j9        rtu          d|j9        |j1        z
            nd }|| dAndB}|j;        p|j        pdB}t	          dC|j        dDd=|dEdF|j<        pd dG| dGtC          |j1                   
           |j=        r7t	          dH|j=        >                                d         d dI                     |j?        r7t	          dJ|j?        >                                d         d dI                     dS )KNno such task: r   r   rS  Fc                8    g | ]}|j         |j        |j        d S )authorr1   r6   r  )rA  cs     r   r  z_cmd_show.<locals>.<listcomp>  s8        8QV1<PP  r   c                D    g | ]}|j         |j        |j        |j        d S )kindpayloadr6   run_idr  )rA  es     r   r  z_cmd_show.<locals>.<listcomp>  sE         F y"#,h	   r   c                    g | ]G}|j         |j        |j        |j        |j        |j        |j        |j        |j        |j	        |j
        d HS )r+   r   step_keyr(   outcomesummaryr   metadata
worker_pidr7   ended_atr  r@  s     r   r  z_cmd_show.<locals>.<listcomp>  sh         $ y !
h y yW !
"#,"#, !
   r   )r  latest_summaryr  childrencommentseventsr   r   rT  r   zTask : z  status:    z  assignee:  r  z  tenant:    z  workspace: z @ r   z  skills:    r]  z  max-retries: z (task)rQ   rS   failure_limitz (config kanban.failure_limit)z
 (default)z  created:   z by kanban_diagnostics   ⚠!!!!!r   z
  Diagnostics (z):    r   r    ] r`  ,c              3  4   K   | ]}t          |          V  d S Nr   rA  xs     r   rd  z_cmd_show.<locals>.<genexpr>  (      3F3FqCFF3F3F3F3F3F3Fr          data:  |           → z  started:   z  completed: z  parents:   z  children:  zBody:zResult:zLatest summary:z
Comments (z  [zEvents (ir"   z [run r!   zRuns (r  activez  #z<3z<12z @r#   u           →    z
        ! )@r   rF  r  r   r   r   r   list_commentslist_events
parent_ids	child_ids	list_runsr  r   r=   rS  rj  r+   r,   r(   r)   r*   r3   r4   r:   rk  r;   rW   rR   r'   rV   r   r   r   r6   r5   
hermes_clir  compute_task_diagnosticsrF   severityr  rl  
isinstancer<   r{   actions	suggestedlabelr7   r8   r1   r9   r  r  r  r  r  maxr  r   r  
splitlinesr   )r   rI  r  r  r  r  r  r   r  r  rR   rZ   cfg_valkddiags
sev_markerr  bitsrc  rL   ar  r  plrun_tagrB  elapsedelr  s                                r   r  r    s	   	 ?{4.. 	14<11
CCCC	? ? ? ? ? ? ? ?
 #D$,77dl33-dl33<dl33|D$,//
 *4>>? ? ? ? ? ? ? ? ? ? ? ? ? ? ?  tVU## %!$'',  !           %"
 "
F 	dj???@@@q	
)$'
)
)TZ
)
)***	
'$+
'
'(((	
0$-.3
0
0111{ -+dk++,,,	
/$-
/
/*.*=E&$&&&2G H H H{ 86dii4466777
 #9 0999::::	555555+--Cwwx,,277HHGG 	 	 	GGG	3w<<23K#K#KPCLLPPPQQQQHB$<HHHIII	
P'$/22
P
P8N3
P
PQQQ
 433333''fd;;E 3!&5II
0#e**000111 	3 	3AS
C88SSAJSS!'SSTTTv >FLLNN 0 0DAq!!T** 0q$H$H3883F3FA3F3F3F+F+F$H$HIIIIqJJ1JJ//// ><%**T*:*:<<=== Y 3 3; 31112223  :8gdo6688999 <:gd&788::;;; 42dii0022333 53dii1133444y gdi{ 
idk	  	   n G,3x==,,,--- 	G 	GAE--EEEEQVEEFFFF H(V((())) 	H 	HA$%I5QY2B./h>*qx****BGF--FFFF!&F"FFGGGG D$s4yy$$$%%% 	D 	DA */s1aj1<7888*. ")"5G8Bi7187xG -K - -'K - -1Ac - -R - -Q\**- - . . .y HFQY%9%9%;%;A%>tt%DFFGGGw DB17#5#5#7#7#:4C4#@BBCCC1s+   AD
"BD

DD+;J' 'J65J6c                `   | j                                         dv rd n| j         }t          j                    5 }t          j        || j        |          }d d d            n# 1 swxY w Y   |s%t          d| j         t          j                   dS t          d| j         d|pd            dS )	N>   r  nonenullr  r   r   z	Assigned  to r   r   )	r   r  r   rF  assign_taskr   r   r   r   r   r   rI  r  s       r   r	  r	  =  s    l((**.CCCddG	 9^D$,889 9 9 9 9 9 9 9 9 9 9 9 9 9 9 -t|--CJ????q	
Cdl
C
C(A>
C
CDDD1s   A  A$'A$c           
     0   t          j                    5 }t          j        || j        t	          | dd                     }d d d            n# 1 swxY w Y   |s&t          d| j         dt          j                   dS t          d| j                    dS )	Nr   )r   zcannot reclaim z (not running or unknown id)r   r   z
Reclaimed r   )r   rF  reclaim_taskr   r   r   r   r   r  s      r   r
  r
  H  s    	 
_$,4400
 
 

 
 
 
 
 
 
 
 
 
 
 
 
 
 

  HdlHHH	
 	
 	
 	
 q	
%t|
%
%&&&1s   ,AAAc                   | j                                         dv rd n| j         }t          j                    5 }t          j        || j        |t          t          | dd                    t          | dd                     }d d d            n# 1 swxY w Y   |s&t          d| j         dt          j
                   d	S t          d
| j         d|pd t          | dd          rdndz              dS )N>   r  r	  r
  r   Fr   )reclaim_firstr   zcannot reassign uC    (unknown id, or still running — pass --reclaim to release first)r   r   zReassigned r  r   z (claim reclaimed)r   r   )r   r  r   rF  reassign_taskr   rX   r   r   r   r   r  s       r   r  r  X  sq   l((**.CCCddG	 
$,wtY>>??4400
 
 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
  Rt| R R R	
 	
 	
 	

 q		'dl 	' 	'$n	' 	'#*4E#B#BJ	L  
 1s   A
BBBc                   ddl m t          j                    5 }t	          | dd          rt          j        || j                  }|1t          d| j         t          j	                   	 ddd           dS | j        
                    |t          j        || j                  t          j        || j                            i}nt          |                    d                                                    }d	 |D             }|si }nEd
                    dgt#          |          z            }d |D             }|                    d| dt%          |                    D ]1}|                    |d         g                               |           2d |D             }	|                    d| dt%          |                    D ]1}|	                    |d         g                               |           2i }|D ]P}
|
d         }
                    |
|                    |g           |	                    |g                     }|r|||<   Qt	          | dd          rDt          |                                          D ]"}fd||         D             }|r|||<   ||= #i |rd
                    dgt#          |          z            }|                    d| dt%          |                                                    D ]#}
|
d         |
d         |
d         d|
d         <   $ddd           n# 1 swxY w Y   t	          | dd          rFfd|                                D             }t          t1          j        |dd                     dS |st          d            dS d!d"d#d$}t5          d% |                                D                       }t          | d&t#          |           d'           |                                D ]\  }}                    |i           }|                    d          pd(}|                    d          pd}|                    d          pd)}t          d*| d*|d+d,|d-d*|            |D ]$}t          d.|                    |j        d           d/|j         d0|j         d1|j                    |j        rg }|j                                        D ]l\  }}tA          |t                    r8|                    | d2d
                    d3 |D                                   R|                    | d2|            m|r%t          d4d5                    |                      |j!        D ] }|j"        rt          d6|j#                    !&t                       dS )7zList active diagnostics on the board. Wraps the same rule engine
    the dashboard uses, so CLI output matches what the UI shows.
    r   r  r  Nr  r   r   z.SELECT * FROM tasks WHERE status != 'archived'c                    g | ]
}|d          S )r+   ra  r@  s     r   r  z$_cmd_diagnostics.<locals>.<listcomp>  s    )))q1T7)))r   r  r   c                    i | ]}|g S ra  ra  rA  is     r   rC  z$_cmd_diagnostics.<locals>.<dictcomp>  s    ,,,1B,,,r   z,SELECT * FROM task_events WHERE task_id IN (z) ORDER BY idr   c                    i | ]}|g S ra  ra  r  s     r   rC  z$_cmd_diagnostics.<locals>.<dictcomp>  s    ---A!R---r   z*SELECT * FROM task_runs WHERE task_id IN (r+   r  c                    g | ]?}j                             |j                  j                                       k    =|@S ra  )SEVERITY_ORDERindexr  )rA  r  r  sevs     r   r  z$_cmd_diagnostics.<locals>.<listcomp>  sK    }}}a9J9P9PQRQ[9\9\`b`q`w`wx{`|`|9|9|9|9|9|r   z;SELECT id, title, status, assignee FROM tasks WHERE id IN (r   r,   r(   r)   )r,   r(   r)   rS  Fc                f    g | ]-\  }}d |i                     |i           dd |D             i.S )r   r   c                6    g | ]}|                                 S ra  )to_dict)rA  r  s     r   r  z/_cmd_diagnostics.<locals>.<listcomp>.<listcomp>  s     888		888r   )r'   )rA  tiddlr{  s      r   r  z$_cmd_diagnostics.<locals>.<listcomp>  sl     
 
 
 R	 3((3## 88R888 
 
 
r   r   rT  z$No active diagnostics on this board.r  r  r  r   c              3  4   K   | ]}t          |          V  d S r  )rF   )rA  r!  s     r   rd  z#_cmd_diagnostics.<locals>.<genexpr>  s(      99BB999999r   z active diagnostic(s) across z
 task(s):
z
(untitled)r   r#   r$   z  @18sr  r    r  r  r`  c              3  4   K   | ]}t          |          V  d S r  r  r  s     r   rd  z#_cmd_diagnostics.<locals>.<genexpr>  r  r   r  r  r  )$r  r  r   rF  r   r  r  r   r   r   r  r  r  r<   rG  rH  rk  rF   r  
setdefaultr{   r'   keysrl  rS  rj  rh  ri  r  r  r,   r  r  r  r  r  )r   rI  r  diags_by_taskrJ  idsplaceholdersev_byrowrun_byrB  r   r!  keptout_jsonr  rR  r  r,   r(   r)   r  r  rc  rL   r  r  r{  r  s                             @@@r   r  r  o  s:    433333	 @4&& '	0;tTY//D|2ty22DDDD@ @ @ @ @ @ @ @ 	266N433Lty11 MM @ hjj D *)D)))C 0 ""xxC(899,,,,,<<^<^^^#JJ  E EC $$S^R88??DDDD-----<<\\\\#JJ  F FC %%c)nb99@@EEEE " 0 0AD'C44Q		#r8J8JFJJWZ\^L_L_``B 0-/c* dJ-- 	+M..0011 + +}}}}}=#5}}} +)-M#&&%c** !# 		88SEC,>,>$>??L\\]l]]]m((**++   
 wZ1X; !*! !QtW{@ @ @ @ @ @ @ @ @ @ @ @ @ @ @D tVU## 

 
 
 
 )..00
 
 
 	dj!%@@@AAAq 4555q #TuEEJ99-"6"6"8"899999E	 	+ 	+}	+ 	+ 	+   !&&((  RHHS"g.,x'C55$$6?3??&????????@@@ 	3 	3A]
C88]]AJ]]!&]]TUT[]]^^^v 	>FLLNN 0 0DAq!!T** 0q$H$H3883F3FA3F3F3F+F+F$H$HIIIIqJJ1JJ//// ><%**T*:*:<<===Y 3 3; 31112223 	1s   AM<J9MMMc                    t          j                    5 }t          j        || j        | j                   d d d            n# 1 swxY w Y   t          d| j         d| j                    dS )NzLinked  -> r   )r   rF  
link_tasksr   r   r   r   rI  s     r   r  r    s    	 ;
dDNDM:::; ; ; ; ; ; ; ; ; ; ; ; ; ; ;	
7DN
7
7
7
78881   !AAAc                8   t          j                    5 }t          j        || j        | j                  }d d d            n# 1 swxY w Y   |s-t          d| j         d| j         t          j                   dS t          d| j         d| j                    dS )NzNo such link: r0  r   r   z	Unlinked r   )r   rF  unlink_tasksr   r   r   r   r   r  s      r   r  r    s    	 B_T4>4=AAB B B B B B B B B B B B B B B Bt~BB4=BBTTTTq	
9dn
9
9$-
9
9:::1r3  c           	        t          j                    5 }t          j        || j        | j                  }|t          j        || j                  }|1t          d| j         t          j                   	 d d d            dS t          d| j         d|j	         d|j
        pd t          j                   	 d d d            dS t          j        |          }t          j        ||j        t          |                     d d d            n# 1 swxY w Y   t          d	|j                    t          d
|            dS )N)ttl_secondsr  r   r   zcannot claim z	: status=z lock=z(none)zClaimed zWorkspace: r   )r   rF  
claim_taskr   ttlr  r   r   r   r(   
claim_lockresolve_workspaceset_workspace_pathr+   r   )r   rI  r  existingr  s        r   r  r    s   	 =}T4<TXFFF<{466H5t|55CJGGGG= = = = = = = = : : :x : : +7x: :Z   
 = = = = = = = = (..	
dDGS^^<<<= = = = = = = = = = = = = = =  

TW

	
#	
#
#$$$1s   A$D6D<DDDc                D   d                     | j                                                  }| j        pt	                      }t          j                    5 }t          j        || j        ||           d d d            n# 1 swxY w Y   t          d| j                    dS )Nr"   zComment added to r   )
rk  r   rD   r  r4  r   rF  add_commentr   r   )r   r1   r  rI  s       r   r  r    s    88DI$$&&D[-O--F	 9
tT\648889 9 9 9 9 9 9 9 9 9 9 9 9 9 9	
,dl
,
,---1s   A>>BBr   c                    t           j                            d          | k    rd S t           j                            d          }|sd S 	 t          |          S # t          $ r Y d S w xY w)NHERMES_KANBAN_TASKHERMES_KANBAN_RUN_ID)rI   r   r'   r   r   )r   raws     r   r  r    st    	z~~*++w66t
*../
0
0C t3xx   tts   
A 
A'&A'c                p   t          | j        pg           }|st          dt          j                   dS t          | dd          }t          | dd          }t          |          dk    r!|s|rt          dt          j                   dS d}|r|	 t          j        |          }t          |t                    st          d	          nB# t          t          j        f$ r)}t          d
| t          j                   Y d}~dS d}~ww xY wg }t          j                    5 }|D ]u}t          j        ||| j        ||t#          |                    s5|                    |           t          d| dt          j                   ct          d|            v	 ddd           n# 1 swxY w Y   |sdndS )z<Mark one or more tasks done. Supports a single id or a list. at least one task_id is requiredr   r   r  Nr  zkanban: --summary / --metadata are per-task and can't be used with multiple ids (would apply the same handoff to every task). Complete tasks one at a time, or drop the flags for the bulk close.r   must be a JSON objectkanban: --metadata: )r9   r  r  r  zcannot complete z (unknown id or terminal state)z
Completed r   )r<   r   r   r   r   r   rF   rS  loadsr  dictr   JSONDecodeErrorr   rF  complete_taskr9   r  r{   )	r   r(  r  raw_metar  r*  failedrI  r   s	            r   r  r  %  sK   
t}"
#
#C 0szBBBBqdIt,,GtZ..H 3xx!|||H|R 		
 	
 	
 	
 qH 	z(++Hh-- : !8999:D01 	 	 	...SZ@@@@11111	 F	 * 	* 	*C#c{! 23 7 7   
* c"""MMMMTWT^_____(3(())))	** * * * * * * * * * * * * * * !11!s+   8C
 
D	 DD	!A9F''F+.F+c                v   t          | dd           }d }|r|	 t          j        |          }t          |t                    st          d          nB# t
          t          j        f$ r)}t          d| t          j	                   Y d }~dS d }~ww xY wt          j                    5 }t          j        || j        | j        t          | dd           |          s2t          d| j         d	t          j	                   	 d d d            d
S 	 d d d            n# 1 swxY w Y   t          d| j                    dS )Nr  rF  rG  r   r   r  )r9   r  r  zcannot edit z! (unknown id or task is not done)r   zEdited r   )r   rS  rH  r  rI  r   rJ  r   r   r   r   rF  edit_completed_task_resultr   r9   )r   rL  r  r*  rI  s        r   r  r  R  s   tZ..HH 	z(++Hh-- : !8999:D01 	 	 	...SZ@@@@11111	 
 ,L;D)T22
 
 
 	 Nt|NNNZ           	               

"DL
"
"###1s*   8A B&B

B%ADDDc           
     n   | j         r,d                    | j                                                   nd }t                      }| j        gt          t          | dd           pg           z   }g }t          j                    5 }|D ]}|rt          j	        |||d|            t          j
        |||t          |                    s4|                    |           t          d| t          j                   wt          d| |rd| nd	z              	 d d d            n# 1 swxY w Y   |sd
ndS )Nr"   r(  z	BLOCKED: )r   r  zcannot block r   zBlocked r  r   r   r   )r   rk  rD   r4  r   r<   r   r   rF  r?  
block_taskr  r{   r   r   r   )r   r   r  r(  rM  rI  r   s          r   r  r  n  s   .2kCSXXdk""((***tFF<.4eT : : @bAA
ACF	 L 	L 	LC HtS&2Ff2F2FGGG= 23 7 7	   	L c"""+c++#*=====&&&6*I-v---rJKKKK	LL L L L L L L L L L L L L L L !11!s   BD&&D*-D*c                   t          | j        pg           }|st          dt          j                   dS g }t          j                    5 }|D ]^}t          j        ||          s5|                    |           t          d| dt          j                   Lt          d|            _	 d d d            n# 1 swxY w Y   |sdndS )NrE  r   r   zcannot unblock z (not blocked?)z
Unblocked r   )	r<   r   r   r   r   r   rF  unblock_taskr{   r   r(  rM  rI  r   s        r   r  r    s%   
t}"
#
#C 0szBBBBqF	 * 	* 	*C?4-- *c"""<<<<3:NNNNN(3(())))	** * * * * * * * * * * * * * * !11!s   A"B::B>B>c                   t          | j        pg           }|st          dt          j                   dS g }t          j                    5 }|D ]]}t          j        ||          s4|                    |           t          d| t          j                   Kt          d|            ^	 d d d            n# 1 swxY w Y   |sdndS )NrE  r   r   zcannot archive z	Archived r   )	r<   r   r   r   r   r   rF  archive_taskr{   rT  s        r   r  r    s"   
t}"
#
#C 0szBBBBqF	 ) 	) 	)C?4-- )c"""---CJ?????'#''((((	)) ) ) ) ) ) ) ) ) ) ) ) ) ) ) !11!s   A!B99B= B=c                   d}t          d| j         d           	 	 t          j                    5 }t          j        || j                  }d d d            n# 1 swxY w Y   |D ]W}|j        |k    rJ|j        r
d|j         nd}t          dt          |j                   d|j	         | d	           |j        }Xt          j        t          d
| j                             # t          $ r t          d           Y dS w xY w)Nr   zTailing events for z. Ctrl-C to stop.Tr"   r   [r  flush皙?

(stopped))r   r   r   rF  r  r+   r  r   r6   r  r   sleepr  intervalKeyboardInterrupt)r   last_idrI  r  r  r  s         r   r  r    s`   G	
?
?
?
?@@@	0 <dl;;< < < < < < < < < < < < < < < # #4'>>,-I=QY2BCgal33CCqvCrCC4PPPPdGJs3..///	0    mqqs5   C$ AC$ AC$ ABC$ $D Dc                   t          j                    5 }t          j        || j        | j        t          | dt           j                            }d d d            n# 1 swxY w Y   t          | dd          r`t          t          j	        |j
        |j        |j        |j        |j        d |j        D             |j        |j        dd                     d	S t          d
|j
                    t          dt%          |j                              |j        r*t          dd                    |j                              t          dt%          |j                              |j        r*t          dd                    |j                              t          dt%          |j                              |j        r*t          dd                    |j                              t          d|j                    t          dt%          |j                              |j        D ]-\  }}}| j        rdnd}t          d| d| d|pd |            .|j        r*t          dd                    |j                              |j        r*t          dd                    |j                              d	S )Nr  )dry_run	max_spawnr  rS  Fc                "    g | ]\  }}}|||d S ))r   r)   r  ra  )rA  r   whowss       r   r  z!_cmd_dispatch.<locals>.<listcomp>  s8       "S#r  SrBB  r   )	reclaimedcrashed	timed_outauto_blockedpromotedspawnedskipped_unassignedskipped_nonspawnabler   )rU  r   zReclaimed:    zCrashed:      r#   r]  zTimed out:    zAuto-blocked: zPromoted:     zSpawned:      z (dry)r   z  - z  ->  z  @ r  zSkipped (unassigned): u8   Skipped (non-spawnable assignee — terminal lane, OK): )r   rF  dispatch_oncerb  r  r   r   r   rS  rj  rg  rh  ri  rj  rk  rl  rm  rn  rF   rk  )r   rI  r  r   re  rf  tags          r   r  r    sD   	 
Lh!$9WXX	
 
 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 tVU## dj{, &)k   #&"8$'$<
 
    	 	 	 q	
*3=
*
*+++	
-3s{++
-
-...
{ -+499S[))++,,,	
/3s}--
/
/000
} /-499S]++--...	
23s/00
2
2333
 20499S-..00111	
)3<
)
)***	
-3s{++
-
-... ; ;S",.hhB9S9999s9C99::::
 LJtyy1G'H'HJJKKK
 
5yy1225 5	
 	
 	
 1s   <AA #A c           	     H   t          | dd          st          dt          j                   dS t	          j                     t          | dd          }|r	 t          |          j                            dd	           t          |          	                    t          t          j                              d
           n8# t          $ r+}t          d| d| t          j                   Y d}~nd}~ww xY wt          t          | dd                    t          d| j         dt          j                     dt          j                   ddddfd}dd	 t	          j        | j        | j        t          | dt          j                  |           |r3	 t          |                                           nK# t          $ r Y n?w xY wn:# |r3	 t          |                                           w # t          $ r Y w w xY ww xY wt          d           dS )u:  Deprecated — the dispatcher now runs inside the gateway.

    Left in as a stub so users with the old command in scripts/systemd
    units get a clear migration message instead of a cryptic
    "no such command" error. A ``--force`` escape hatch keeps the old
    standalone daemon alive for the rare edge case where someone truly
    cannot run the gateway (e.g. running on a host that forbids
    long-lived background services), but the default path exits 2
    with guidance so nobody accidentally keeps running two dispatchers
    against the same kanban.db.
    forceFuy  hermes kanban daemon: DEPRECATED — the dispatcher now runs
inside the gateway. To use kanban:

    hermes gateway start       # starts the gateway + embedded dispatcher

Ready tasks will be picked up on the next dispatcher tick
(default: every 60 seconds). Configure via config.yaml:

    kanban:
      dispatch_in_gateway: true      # default
      dispatch_interval_seconds: 60
      failure_limit: 2              # consecutive non-success attempts before auto-block

Running both the gateway AND this standalone daemon will
race for claims. If you truly need the old standalone
daemon (no gateway available), rerun with --force.r   r   pidfileNT)r  exist_okzutf-8)encodingz!warning: could not write pidfile r  verbosez;Kanban dispatcher running STANDALONE via --force (interval=zs, pid=z). Ctrl-C to stop. NOTE: if a gateway is also running with dispatch_in_gateway=true (default), you have two dispatchers racing for claims.   r   )	bad_tickslast_warn_atc                6   t          | j                  p	             }t          | j                  }|r|sdxx         dz  cc<   ndd<   d         k    rjt          t	          j                              }|d         z
  dk    r;t          dt          |           dd          dt          j        d	
           |d<   sd S | j	        p"| j
        p| j        p| j        p| j        p| j        }|rt          dt          t          t	          j                                         d| j	         dt          | j
                   dt          | j                   d| j         dt          | j                   dt          | j                   d	           d S d S )Nrx  r   r   ry  i,  rX  z3] WARN dispatcher stuck: ready queue non-empty for z consecutive ticks but 0 workers spawned successfully. Check profile health (venv, PATH, credentials) and `hermes kanban list --status ready` / `hermes kanban list --status blocked` for recent spawn_failed tasks.T)r   rZ  z] reclaimed=z	 crashed=z timed_out=z
 promoted=z	 spawned=z auto_blocked=rY  )rX   rm  rl  r   r   r   r   r   r   rg  rh  ri  rk  rj  rF   )	r  ready_pendingspawned_anynowdid_workHEALTH_WINDOW_ready_queue_nonemptyhealth_staterv  s	        r   _on_tickz_cmd_daemon.<locals>._on_tick*  s&   S344O8M8M8O8O3;'' 	* 	*%%%*%%%%()L% $55dikk""C\.11S88+ + +1=k1J+ + + 4	 	 	 	 03^, 	FM /S[ /CM /S\ /{/!. 	  	8GC	,,-- 8 8 ]8 8585E5E8 8 //8 8  L8 8 47s{3C3C8 8 !$C$4 5 5	8 8
      	 	r   r   rX   c                     	 t          j                    5 } t          j        |           cddd           S # 1 swxY w Y   dS # t          $ r Y dS w xY w)u  Cheap probe — is there at least one ready+assigned+unclaimed
        task whose assignee maps to a real Hermes profile (i.e. one the
        dispatcher would actually try to spawn for)?

        Filters out tasks assigned to control-plane lanes
        (e.g. ``orion-cc``, ``orion-research``) that are pulled by
        terminals via ``claim_task`` directly — those are correctly idle
        from the dispatcher's perspective, not stuck.
        NF)r   rF  has_spawnable_readyrV   )rI  s    r   r  z*_cmd_daemon.<locals>._ready_queue_nonemptyR  s    	 4-d334 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 	 	 	55	s,   A 6A :A :A 
AAr  )r^  rc  r  on_tickz(dispatcher stopped))r   rX   )r   r   r   r   r   r  r   r  mkdir
write_textr   rI   getpidOSErrorrX   r^  
run_daemonr  r   r   )r   rs  r*  r  r  r  r  rv  s       @@@@r   r  r    s    4%(( A  #	
 	
 	
 	
& q
 JLLLdIt,,G Y	YMM &&td&CCCMM$$S%5%5$HHHH 	Y 	Y 	YFgFFFFSZXXXXXXXXX	Y 74E2233G		]	 	+-9;;	 	 	
 Z    M!"A66L& & & & & & & &P    
]h!$9WXX		
 	
 	
 	
  	W$$&&&&   	7 	W$$&&&&   	
 

 !!!1s[   A+C 
C;!C66C;(;G &!G 
GGH!G?>H?
H	HHHc                p   | j         r$d | j                             d          D             nd}d}t          dd           t          j                    5 }|                    d                                          }t          |d	                   }ddd           n# 1 swxY w Y   	 	 t          j                    5 }|                    d
|f                                          }ddd           n# 1 swxY w Y   |D ]}t          |t          |d                             }|r|d         |vr2| j
        r|d         | j
        k    rK| j        r|d         | j        k    rd	 |d         rt          j        |d                   nd}n# t          $ r d}Y nw xY w|rd| nd}t          dt          |d                    d|d         dd|d         dd|d         pd d| 
d           t!          j        t          d| j                             n# t&          $ r t          d           Y dS w xY w)z(Live-stream task_events to the terminal.c                ^    h | ]*}|                                 |                                 +S ra  )rD   )rA  rc  s     r   	<setcomp>z_cmd_watch.<locals>.<setcomp>v  s-    ???qQWWYY????r   r  Nr   z'Watching kanban events. Ctrl-C to stop.TrY  z1SELECT COALESCE(MAX(id), 0) AS m FROM task_eventsr  zSELECT e.id, e.task_id, e.kind, e.payload, e.created_at,        t.assignee, t.tenant FROM task_events e LEFT JOIN tasks t ON t.id = e.task_id WHERE e.id > ? ORDER BY e.id ASC LIMIT 200r+   r  r)   r*   r  r"   r   rX  r6   r  r   10sr#  z (@r  r   r[  r\  )kindssplitr   r   rF  rG  fetchoner   rH  r  r)   r*   rS  rH  rV   r   r   r]  r^  r_  )	r   r  cursorrI  r+  rJ  rB  r  r  s	            r   r  r  s  s?    :	 ??DJ,,S11???? 
 F	
34@@@@	 ll?
 

(** 	 SX	              	0 ||A I  (**                  VS4\\22 QvYe33= Qz]dm%C%C; 1X;$+#=#=#:;I,Pdj9666DGG  # # #"GGG#&-5]]]]2E,00 E EAiLG E EyDE E)*:)=#E E@BE E    
 Js3..///7	08    mqqsn   =BB!$B!)H =*C3'H 3C77H :C7;A)H %$F
	H 
FH FA?H H54H5c           
        t          j                    5 }t          j        |          }d d d            n# 1 swxY w Y   t          | dd          r&t	          t          j        |dd                     dS t	          d           dD ]2}t	          d|d	d|d
                             |d                      3|d         rt	          d           t          |d         	                                          D ]Y\  }}d
                    d t          |	                                          D                       }t	          d|dd|            Z|d         }| t	          dt          |           d           dS )NrS  Fr   rT  r   z
By status:)r  r	   r
   r   r   r   r#   r$   	by_statusby_assigneez
By assignee:r]  c              3  *   K   | ]\  }}| d | V  dS r_  ra  rb  s      r   rd  z_cmd_stats.<locals>.<genexpr>  r  r   r%   oldest_ready_age_secondsz
Oldest ready task age: r  )r   rF  board_statsr   r   rS  rj  r'   r   rl  rk  r   )r   rI  r   rc  re  rQ  partsages           r   r  r    s   	 %t$$% % % % % % % % % % % % % % %tVU## djqu===>>>q	,F ; ;919995-11!Q7799::::] +!%"6"<"<">">?? 	+ 	+KCIILLVFLLNN5K5KLLLLLE)s)))%))****
*
+C
5#c((5556661r  c                   t          j                    5 }t          j        || j                  1t	          d| j         t
          j                   	 d d d            dS t          j        || j        | j        | j	        | j
        | j        | j        pt                                 d d d            n# 1 swxY w Y   t	          d| j         d| j	         | j
        r
d| j
         ndz   d| j         z              d	S )
Nr  r   r   )r   platformchat_id	thread_iduser_idnotifier_profilezSubscribed :r   r  r   )r   rF  r  r   r   r   r   add_notify_subr  r  r  r  r  r4  r2  s     r   r  r    sh   	 	
;tT\**214<11
CCCC	
 	
 	
 	
 	
 	
 	
 	
 	$,]DLndl!2Go6G6G		
 	
 	
 	
		
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 

6
6
6
6
6%)^;!!!!=!4<!!" # # # 1s   ?B3 AB33B7:B7c                (   t          j                    5 }t          j        || j                  }d d d            n# 1 swxY w Y   t	          | dd          r&t          t          j        |dd                     dS |st          d           dS |D ]}|                    d          rd|d          nd	}|                    d
          rd|d
          nd	}t          d|d         dd|d          d|d          | d|d          d|            dS )NrS  Fr   rT  r   z(no subscriptions)r  r  r   r  z  owner=r#   r   r  r  r  z  (since event last_event_idr   )	r   rF  list_notify_subsr   r   r   rS  rj  r'   )r   rI  subsr  throwners         r   r   r     s   	 7"4667 7 7 7 7 7 7 7 7 7 7 7 7 7 7tVU## djae<<<===q "###q > >&'eeK&8&8@"!K."""b67ee<N6O6OW21/0222UW =1Y<J = =q} = =q| =S = = !/ 2= =5:= = 	> 	> 	> 	>1   ;??c                "   t          j                    5 }t          j        || j        | j        | j        | j                  }d d d            n# 1 swxY w Y   |st          dt          j	                   dS t          d| j                    dS )N)r   r  r  r  z(no such subscription)r   r   zUnsubscribed from r   )
r   rF  remove_notify_subr   r  r  r  r   r   r   r  s      r   r!  r!    s    	 
!$,]DLn
 
 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
  &SZ8888q	
-t|
-
-...1s   .AAAc                <   t          j        | j        | j                  }|&t	          d| j         dt
          j                   dS t
          j                            |           |	                    d          st
          j                            d           dS )N)
tail_bytesz(no log for u#    — task may not have spawned yet)r   r   
r   )
r   read_worker_logr   r   r   r   r   stdoutwriteendswith)r   contents     r   r  r    s     $)DDDGNT\NNN:	 	 	 	qJWD!! 
1r   c                   t          j                    5 }t          j        || j                  }ddd           n# 1 swxY w Y   t	          | dd          r0t          t          j        d |D             dd                     dS |st          d| j         d	           dS t          d
ddddddddddd           t          |d          D ] \  }}|j	        pt          t          j                              }t          d||j        z
            }|dk     r| d}n|dk     r	|dz   d}n	|dz  dd}|j        p|j	        sdn|j        }t          |dd|dd|j        pddd|ddt#          |j                   	           |j        r9|j                                        d         dd         }	t          d|	            |j        rt          d |j        dd                     "dS )!z Show attempt history for a task.NrS  Fc                    g | ]G}|j         |j        |j        |j        |j        |j        |j        |j        |j        |j	        |j
        d HS )r+   r   r(   r  r7   r  r  r   r  r  r  r  r@  s     r   r  z_cmd_runs.<locals>.<listcomp>  sb     
 
 
  dqyAH9ALJ19ajl
 
 
 
r   r   rT  r   z(no runs yet for r   #3sr#   OUTCOME12sPROFILE16sELAPSEDz>8sz	  STARTEDr   r  r  r  r  z.1fr  z	(running)3dr  d   u	        → u	        ✖ )r   rF  r  r   r   r   rS  rj  	enumerater  r   r   r  r7   r  r(   r   r   r  r  r   )
r   rI  r   r  rB  endr  r  r  r  s
             r   r  r    s   	 0|D$,//0 0 0 0 0 0 0 0 0 0 0 0 0 0 0tVU## 
dj 
 
 
 
 
 %) ) ) 	* 	* 	* q 1$,111222q	S
Q
Q
Qy
Q
Q
Q	
Q
Q
Q
Q
Q
Q
QRRR$"" / /1j,C	,,aq|+,,R<<BBt^^rM$$$BBdN))))B)L1: K18cccccc)9cccc"cccGTUT`LaLaccddd9 	)i**,,Q/5G'g''(((7 	/-agdsdm--...1r  c                    t          j                    5 }t          j        || j                  }d d d            n# 1 swxY w Y   t	          |           dS )Nr   )r   rF  build_worker_contextr   r   )r   rI  r   s      r   r"  r"    s    	 ;&tT\::; ; ; ; ; ; ; ; ; ; ; ; ; ; ;	$KKK1r  c           
        ddl m} t          t          | dd                    }t          | dd          }t          | dd          pt	                      }t          t          | dd                    }| j        r|rt          d	t          j        
           dS |r`|	                    |          }|sGd|rd|ndz   dz   }|r%t          t          j        ddd                     nt          |           dS n-| j        r	| j        g}nt          dt          j        
           dS d}d}	|D ]}
|                    |
|          }|j        r|dz  }n|	dz  }	|r;t          t          j        |j        |j        |j        |j        d                     h|j        r.|j        r
d|j        nd}t          d|j         d|            t          d|j         d|j         t          j        
           |s
|dk    rdndS |dk    s|sdndS )z{Flesh out a triage task (or all of them) via auxiliary LLM,
    then promote to todo. Thin wrapper over ``kanban_specify``.r   )kanban_specifyr   Fr*   Nr  rS  0kanban: pass either a task id OR --all, not bothr   r   r*   No triage tasks for tenant r   rt  )	specifiedrR  z+kanban: specify requires a task id or --allr  r   )r   r  r   	new_title    — retitled: 
Specified u	    → todozkanban: specify r  )r  r  rX   r   r4  r   r   r   r   list_triage_idsrS  rj  specify_taskr  r   r  )r   specall_flagr*   r  	want_jsonr(  msgok_count
fail_countr   r  title_suffixs                r   r#  r#  #  s    211111GD,6677HT8T**FT8T**?o.?.?FWT651122I|  >	
 	
 	
 	
 q ""&"11 
	!06>,&,,,B@ 
  djq1!=!=>>????c


1
	 
 |n9	
 	
 	
 	
 qHJ  ##C#77: 	MHH!OJ 	$*"?j!.$.	        Z 	 $7'"3777 
 GwGGGGHHHHF7?FFgnFFZ      )MMqqq( AS11q0r   c                   ddl m} t          t          | dd                    }t          | dd          }t          | dd          pt	                      }t          t          | dd                    }| j        r|rt          d	t          j        
           dS |r`|	                    |          }|sGd|rd|ndz   dz   }|r%t          t          j        ddd                     nt          |           dS n-| j        r	| j        g}nt          dt          j        
           dS d}|D ](}	|                    |	|          }
|
j        r|dz  }|rGt          t          j        |
j        |
j        |
j        |
j        |
j        |
j        d                     o|
j        r|
j        rR|
j        rKd                    |
j                  }t          d|
j         dt'          |
j                   d| d           |
j        r
d|
j        nd}t          d|
j         d|            t          d|
j         d|
j         t          j        
           *|s
|dk    rdndS |dk    s|sdndS ) zFan a triage task (or all of them) out into a graph of child
    tasks via the auxiliary LLM, routed to specialist profiles by
    description. Thin wrapper over ``kanban_decompose``.r   )kanban_decomposer   Fr*   Nr  rS  r  r   r   r  r  r  r   rt  )
decomposedrR  z-kanban: decompose requires a task id or --allr  r   )r   r  r   fanoutr  r  r]  zDecomposed u    → z children (z); root promoted to todor  r  u    → todo (no fanout)zkanban: decompose r  )r  r  rX   r   r4  r   r   r   r   r  rS  rj  decompose_taskr  r   r  r  r  rk  rF   )r   decompr  r*   r  r  r(  r  r  r   r  child_summaryr  s                r   r$  r$  l  sm    655555GD,6677HT8T**FT8T**?o.?.?FWT651122I|  >	
 	
 	
 	
 q $$F$33 
	!06>,&,,,B@ 
  djA!>!>??@@@@c


1
	 
 |n;	
 	
 	
 	
 qH " "''F';;: 	MH 	$*"?j!.!.$.$.        Z 	~ '"3  $		'*; < <I'/ I IG<M8N8N I I!.I I I    (;g&7;;; 
 1 1 1".1 1   
 HW_HHHHZ      )MMqqq(AS11q0r   c           	        ddl }t          j                    }d}t          j                    5 }|                    d                                          }ddd           n# 1 swxY w Y   |D ]}|d         dk    rt          |d         p
||d         z            }	 |                                }n# t          $ r Y Qw xY w	 |	                    |                                           n# t          $ r Y w xY w|                                r0|                                r|                    |d	           |d
z  }t          | dd          }t          | dd          }	t          j                    5 }t          j        ||dz  dz            }
ddd           n# 1 swxY w Y   t          j        |	dz  dz            }t#          d| d|
 d| d           dS )z^Remove scratch workspaces of archived tasks, prune old events, and
    delete old worker logs.r   NzNSELECT id, workspace_kind, workspace_path FROM tasks WHERE status = 'archived'r3   rA   r4   r+   T)ignore_errorsr   event_retention_daysr   log_retention_days   r  )older_than_secondszGC complete: z workspace(s), z event row(s), z log file(s) removed)shutilr   workspaces_rootrF  rG  rH  r   resolver  relative_tor   rE  is_dirrmtreer   	gc_eventsgc_worker_logsr   )r   r  scratch_root
removed_wsrI  rJ  r+  rJ   
event_dayslog_daysremoved_eventsremoved_logss               r   r%  r%    s    MMM%''LJ	 ||\
 

(** 	                  I--C()GlSY.FHH	<<>>DD 	 	 	H		\11334444 	 	 	H	 ;;== 	T[[]] 	MM$dM333!OJ5r::Jt1266H	 
Z"_t%;
 
 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 $#b=4/  L 
 O* O OO O,8O O O P P P1sG   (A!!A%(A%B33
C ?C 'C,,
C98C96FF#&F#u%  **/kanban** — manage the shared task board.

Common subcommands:
  `list` (alias `ls`)   List tasks on the current board
  `show <id>`           Task details + comments + events
  `stats`               Per-status / per-assignee counts
  `create <title>…`     Create a task (auto-subscribes you to events)
  `comment <id> <msg>`  Append a comment
  `complete <id>…`      Mark task(s) done
  `block <id> [reason]` Mark blocked; `unblock <id>` to revive
  `assign <id> <profile>`  Reassign
  `boards list`         Show all boards
  `assignees`           Known profiles + counts
  `context <id>`        Full worker-context dump
  `runs <id>`           Attempt history
  `log <id>`            Worker log

Run `/kanban <subcommand> -h` for arguments. Read-only commands are safe while an agent is running.restc                Z   ddl }ddl}| r(|                                 rt          j        |           ng }|r
|d         dv rt
          S t          j        dd          }d|_        |	                    d          }t          |          }d	|_        d|_        |j        D ]L}t          |t          j                  r0|j                                        D ]\  }}	d
| |	_        d|	_        M|                                }
|                                }	 |                    |
          5  |                    |          5  |                    |          }ddd           n# 1 swxY w Y   ddd           n# 1 swxY w Y   n# t*          $ ru}|
                                                                }|                                                                }|j        dv r	|r|cY d}~S |p|}|rd| ndcY d}~S d}~wt          j        $ r}d| cY d}~S d}~ww xY w|                    |
          5  |                    |          5  	 t5          |           n@# t*          $ r Y n4t6          $ r(}t9          d| t:          j                   Y d}~nd}~ww xY wddd           n# 1 swxY w Y   ddd           n# 1 swxY w Y   |
                                                                }|                                                                }|r	|r| d| S |r|n|pdS )u  Execute a ``/kanban …`` string and return captured stdout/stderr.

    ``rest`` is everything after ``/kanban`` (may be empty).  Used from
    both the interactive CLI (``self._handle_kanban_command``) and the
    gateway (``_handle_kanban_command``) so formatting is identical.
    r   N>   -h--helpra   r   z/kanban-wrapF)progadd_help_toprf   z/kanbanz/kanban >   Nr   u   ⚠ /kanban usage error
u   ⚠ /kanban usage erroru   ⚠ /kanban usage error: zerror: r   r  z(no output))io
contextlibrD   shlexr  _SLASH_KANBAN_HELPrG   ArgumentParserexit_on_errorr   r   r  _actionsr  _SubParsersActionr   rl  StringIOredirect_stdoutredirect_stderr
parse_args
SystemExitgetvaluerstripcodeArgumentErrorr-  rV   r   r   r   )r  r  r  tokens_wrap_top_subr   _action_name_choicebuf_outbuf_errr   r*  outerrr1   s                    r   	run_slashr  	  s    III"&?4::<<?U[RF  "VAY"???!! #%HHHEE###00H **M"M"'M ) . .gx9:: 	.")/"7"7"9"9 . .w1%11(-%%kkmmGkkmmG1''00 	4 	4*2L2LW2U2U 	4 	4 ++F33D	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 Y Y Y  ''))  ''))8y  S JJJJJJzc59X14111?XXXXXXX! 1 1 103000000001 
	#	#G	,	, 4 4j.H.H.Q.Q 4 4	44     	 	 	D 	4 	4 	4/C//
333333333	44 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 




#
#
%
%C





#
#
%
%C
 s 133C0=1s   F *E9 E"E9"E&	&E9)E&	*E9-F 9E==F  E=F 
H AG?'H -G?9H ?H HH H 8KJ,I J, 
J*J,,	J5JJ,JJ, K,J0	0K3J0	4KK
K)r   r   r   r   )r   r   r   r   )r   r   r   r/   )r>   r   r   r?   )r   rN   )r]   r^   r   r_   )r   r   r   r   )r   r   )rq   r   r   r<  )r   r   )r   r   r   r   )r  r   r   r   )G__doc__
__future__r   rG   rS  rI   r  r   r   pathlibr   typingr   r   r  r   r   r&   r   r.   r=   rM   r\   r   r-  r4  r  rK  r6  r7  r8  r9  r:  r;  r  r  r  r  r  r  r  r	  r
  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r   r!  r  r  r"  r#  r$  r%  r  r  ra  r   r   <module>r     s    # " " " " "   				  



                        & & & & & &  ? ? ? ?N N N N   *   ,3 3 3 3tw w w w|@ @ @ @N
 
 
 
"   4          F   :      *       $\ \ \ \2   B      &2 2 2 2j& & & &R^ ^ ^ ^B          .w w w wt         ,   	 	 	 	*" *" *" *"Z   8" " " "," " " " " " " "    $- - - -`J J J JZ. . . .b   (   "   "   	 	 	 	% % % %P   F1 F1 F1 F1RN1 N1 N1 N1b& & & &Z .B2 B2 B2 B2 B2 B2r   