
    i                       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dDdZdEdZdFdZdGdZdHdZdId ZdJd$ZdKd%ZdLd&ZdJd'ZdJd(ZdJd)ZdJd*ZdJd+ZdJd,Z dJd-Z!dJd.Z"dJd/Z#dJd0Z$dJd1Z%dJd2Z&dJd3Z'dJd4Z(dJd5Z)dJd6Z*dJd7Z+dJd8Z,dJd9Z-dJd:Z.dJd;Z/dJd<Z0dJd=Z1dJd>Z2dJd?Z3dJd@Z4dJdAZ5dMdCZ6dS )Nu"  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   ✓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    6/home/ubuntu/.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)z []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                    | j         | j        | j        | j        | j        | j        | j        | j        | j        | j	        | j
        | j        | j        | j        | j        rt          | j                  ng dS )N)r)   r*   bodyr'   r&   priorityr(   workspace_kindworkspace_path
created_by
created_at
started_atcompleted_atresultskills)r)   r*   r/   r'   r&   r0   r(   r1   r2   r3   r4   r5   r6   r7   r8   list)r   s    r   _task_to_dictr:   8   so    dJ(J(**lll($%H4$qx..."  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)r>   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;   vrG   s      r   _parse_workspace_flagrJ   L   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.statusrM   	Exceptionhermes_cli.configrN   boolr%   )rM   pidrN   cfgdispatch_ons        r   _check_dispatcher_presencerX   b   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           |                    ddg d           |                    ddd           |                    ddd           |                    dt          dd            |                    d!d"d#$           |                    d%dd&           |                    d'dd(           |                    d)d*d+           |                    d,dg d-d./           |                    d0d"d1$           |                     d2d3gd45          }|                    d6d"d7$           |                    dd8           |                    d9dt	          t
          j                  :           |                    dd8           |                    d;d"d<$           |                    d0d"=           |                     d>d?	          }|                    d@           |                    d0d"=           |                     dAdB	          }|                    d@           |                    dCdD	           |                     dEdF	          }|                    dG           |                    dH           |                     dIdJ	          }|                    dG           |                    dH           |                     dKdL	          }	|	                    d@           |	                    dMt          t
          j        dN            |                     dOdP	          }
|
                    d@           |
                    dQdRdST           |
                    dUddV           |                     dWdX	          }|                    dYdRdZT           |                    d[dd\           |                    d]dd^           |                    d_dd`           |                     dadb	          }|                    d@           |                    dcdddeT           |                    dfdRddgh           |                     didj	          }|                    dYdRk           |                     dldm	          }|                    dYdRk           |                     dndo	          }|                    d@           |                    dpt          dqr           |                     dsdt	          }|                    dud"dv$           |                    dwt          ddx            |                    dyt          t
          j	        dzt
          j	         d{            |                    d0d"=           |                     d|d}	          }|                    dpt          d~d            |                    dwt          dd            |                    dyt          t
          j	        r           |                    ddd           |                    ddd"d$           |                    dd"t          j        $           |                     dd	          }|                    ddd           |                    ddd           |                    ddd           |                    dpt          dd            |                     dd	          }|                    d0d"=           |                     dd	          }|                    d@           |                    dd           |                    dd           |                    dd8           |                    dd8           |                     dd	          }|                    d@dd           |                    d0d"=           |                     dd	          }|                    d@           |                    dd           |                    dd           |                    dd8           |                     dd	          }|                    d@           |                    dt          dd            |                     dd	          }|                    d@           |                    d0d"=           |                     dd	          }|                    d@           |                    ddd           |                     dd	          }|                    d0d"=           |                     dd	          }|                    d@           |                     dd	          }|                    dt          dd            |                    dt          dd            |                    |           |S )zAttach the ``kanban`` subcommand tree under an existing subparsers.

    Returns the top-level ``kanban`` parser so caller can ``set_defaults``.
    rO   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descriptionkanban_actiondestinitz(Create kanban.db if missing (idempotent))r]   createzCreate a new taskr*   z
Task titlez--bodyNzOptional opening post)defaultr]   z
--assigneezProfile name to assignz--parentappendzParent task id (repeatable))actionrd   r]   z--workspacer>   z2scratch | worktree | dir:<path> (default: scratch)z--tenantzTenant namespacez
--priorityr   zPriority tiebreaker)typerd   r]   z--triage
store_trueuJ   Park in triage — a specifier will flesh out the spec and promote to todo)rf   r]   z--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--skillr8   zSkill to force-load into the worker (repeatable). Appended to the built-in kanban-worker skill. Example: --skill translation --skill github-code-review)rf   rd   ra   r]   z--jsonzEmit JSON outputr9   lsz
List tasks)aliasesr]   z--minez%Filter by $HERMES_PROFILE as assignee)rd   z--status)rd   choicesz
--archivedzInclude archived tasks)rf   showz"Show a task with comments + eventstask_idassignzAssign or reassign a taskprofilez$Profile name (or 'none' to unassign)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)nargsr]   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.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))ry   rd   r]   unblockz)Return one or more blocked tasks to ready)ry   archivezArchive one or more taskstailzFollow a task's event streamz
--intervalg      ?)rg   rd   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-limitzGAuto-block a task after this many consecutive spawn failures (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
--platformT)requiredz	--chat-idz--thread-idz	--user-idnotify-listz>List notification subscriptions (optionally for a single task)r   )ry   rd   notify-unsubscribez)Remove a gateway subscription from a tasklogz@Print the worker log for a task (from $HERMES_HOME/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).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_subparsersadd_argumentintsortedkbVALID_STATUSESDEFAULT_CLAIM_TTL_SECONDSfloatDEFAULT_SPAWN_FAILURE_LIMITrD   SUPPRESSset_defaults)rY   kanban_parsersubp_createp_listp_showp_assignp_linkp_unlinkp_claim	p_comment
p_complete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_gcs                                r   build_parserr      s,   
 &00IE	 1 
 
M 
&
&O
&
<
<C NN6 JNKKK ~~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
 (<>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 ^^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 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=  ? ? ?
) " >L*,*HL L L  M M M 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nnM   G #t<<<,777NN8   E 
y!!!	|d333	{T222	}d333 NNO   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!!! >>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          j                     n6# t          $ r)}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t"          dt$          dt&          dt(          dt*          dt,          dt.          t0          t2          t4          t6          t8          t:          t<          t>          t@          tB          tD          d}|#                    |          }|s t          d|t          j                   dS 	 tI           ||           pd          S # tJ          tL          f$ r)}t          d| t          j                   Y d}~dS d}~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).
    r_   Nr   z`usage: hermes kanban <action> [options]
Run 'hermes kanban --help' for the full list of actions.filer   z'kanban: could not initialize database:    rb   rc   r9   rj   rm   ro   rq   rt   ru   rv   rz   r|   r   r   r   r   r   )r   r   r   r   r   r   r   r   r   r   r   zkanban: unknown action    zkanban: )'getattr
print_helpprintsysstderrr   init_dbrR   	_cmd_init_cmd_create	_cmd_list	_cmd_show_cmd_assign	_cmd_link_cmd_unlink
_cmd_claim_cmd_comment_cmd_complete
_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_gcr%   r   
ValueErrorRuntimeError)r   rf   parserexchandlershandlers         r   kanban_commandr     s}   
 T?D11F /66KZ   
 q

   ===CJOOOOqqqqqIK 	I 	I	
 	I 	K 	I 	K 	J 	L 	M 	J 	L 	L 	I  	M!" 	K#$ ##3.5 9  H< ll6""G 222DDDDq774==%A&&&%   SZ0000qqqqqs0   A. .
B!8BB!+G G?G::G?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_nameri   )rF   environr%   hermes_cli.profilesr   rR   )envrI   r   s      r   _profile_authorr     s    8  JNN3 	HHH	??????&&((2F2   vvs   > 
AA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   rA   lowerr   r   r   )valr   unitsnr   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_diskrR   rC   )r   rG   profilesnames       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           
     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 )	Nnote)r  zcannot heartbeat z (not running?)r   r   zHeartbeat recorded for r   )r   connectheartbeat_workerrn   r   r   r   r   r   connoks      r   r   r   >  s    	 W t|'$PT:U:UVVVW W W W W W W W W W W W W W W ?$,???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 )NjsonFr   indentensure_asciir   uA   (no assignees — create a profile with `hermes -p <name> setup`)NAMEr#   r!   zON DISKr"   z  COUNTSon_diskyesnocounts, c              3  *   K   | ]\  }}| d | V  dS =N .0krI   s      r   	<genexpr>z!_cmd_assignees.<locals>.<genexpr>V  0      LLTQjjQjjLLLLLLr   z(idle)r  )
r   r  known_assigneesr   r   r  dumpsjoinr   items)r   r	  dataentryr  r  	count_strs          r   r   r   H  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                   t          | j                  \  }}	 t          t          | dd                     }n6# t          $ r)}t          d| t          j                   Y d }~dS d }~ww xY w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  triageFidempotency_keyr8   )r*   r/   r'   r3   r1   r2   r(   r0   parentsr)  r*  max_runtime_secondsr8   r  r  zCreated z  (z, assignee=-r   r	   u   
⚠  r   )rJ   	workspacer   r   r   r   r   r   r   r  create_taskr*   r/   r'   r3   r   r(   r0   tupleparentrT   get_taskr  r   r:   r&   rX   )
r   ws_kindws_pathr(  r   r	  rn   taskr
   messages
             r   r   r   [  sV   ,T^<<GW%gdM4&H&HII   ---CJ????qqqqq 
 *.*];/*;*;"";]$++,,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+B4EEE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 |st          d           dS |D ]}t          t          |                     dS )	N)r'   r&   r(   include_archivedr  Fc                ,    g | ]}t          |          S r  )r:   )r  r   s     r   
<listcomp>z_cmd_list.<locals>.<listcomp>  s     :::q-**:::r   r   r  r   z(no matching tasks))r'   miner   r   r  recompute_ready
list_tasksr&   r(   r   r   r   r  r   r,   )r   r'   r	  tasksr   s        r   r   r     sT   }Hy % %"$$	 

 	4   ;;!]
 
 
	

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 tVU## dj::E:::1SXYYYZZZq #$$$q ! !nQ    1s   =A;;A?A?c                @   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                  }d d d            n# 1 swxY w Y   t          | dd          rZt          |          ||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                              t	          dt3          |j                   d|j        pd            |j        r$t	          dt3          |j                              |j        r$t	          dt3          |j                              |r%t	          dd                    |                      |r%t	          dd                    |                      |j        r1t	                       t	          d           t	          |j                   |j        r1t	                       t	          d           t	          |j                   |rgt	                       t	          d tA          |           d!           |D ]6}	t	          d"t3          |	j                   d#|	j!         d|	j                    7|rt	                       t	          d$tA          |           d!           |d%d          D ]Z}
|
j"        r
d&|
j"         nd}|
j#        rd'|
j#         d(nd}t	          d"t3          |
j                   d(| d&|
j$         |            [|r,t	                       t	          d)tA          |           d!           |D ]}|j%        rtM          d|j%        |j        z
            nd }|| d*nd+}|j'        p|j        pd+}t	          d,|j        d-d&|d.d/|j(        pd d0| d0t3          |j                   
           |j)        r7t	          d1|j)        *                                d         d d2                     |j+        r7t	          d3|j+        *                                d         d d2                     dS )4Nno such task: r   r   r  Fc                8    g | ]}|j         |j        |j        d S )authorr/   r4   rB  )r  cs     r   r:  z_cmd_show.<locals>.<listcomp>  s8        8QV1<PP  r   c                D    g | ]}|j         |j        |j        |j        d S )kindpayloadr4   run_idrF  )r  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)   rp   step_keyr&   outcomesummaryerrormetadata
worker_pidr5   ended_atrL  r  rs     r   r:  z_cmd_show.<locals>.<listcomp>  sh         $ y !
h y yW !
"#,"#, !
   r   )r5  r+  childrencommentseventsr   r   r  r   zTask : z  status:    z  assignee:  r-  z  tenant:    z  workspace: z @ r   z  skills:    r  z  created:   z by z  started:   z  completed: z  parents:   z  children:  zBody:zResult:z
Comments (z):z  [] zEvents (ir    z [run r   zRuns (r   activez  #z<3z<12z @r!   u           →    z
        ! ),r   r  r2  rn   r   r   r   list_commentslist_events
parent_ids	child_ids	list_runsr   r:   r  r   r)   r*   r&   r'   r(   r1   r2   r8   r!  r   r4   r3   r5   r6   r/   r7   rC   rC  rH  rI  rG  rS  maxrN  rp   rO  
splitlinesrP  )r   r	  r5  rW  rX  r+  rV  r   rH  rD  rJ  plrun_tagrU  elapsedelrN  s                    r   r   r     s   	 	0{4.. 	14<11
CCCC		0 	0 	0 	0 	0 	0 	0 	0
 #D$,77dl33-dl33<dl33|D$,//	0 	0 	0 	0 	0 	0 	0 	0 	0 	0 	0 	0 	0 	0 	0 tVU## $!$''  !           #!
 !
D 	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	
P'$/22
P
P8N3
P
PQQQ :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 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C0"BC00C47C4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)noner-  nullr@  r   r   z	Assigned  to r   r   )	rp   r   r   r  assign_taskrn   r   r   r   )r   rp   r	  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                    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   r  
link_tasksrr   rs   r   r   r	  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: rn  r   r   z	Unlinked r   )r   r  unlink_tasksrr   rs   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:::1rq  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   r  
claim_taskrn   ttlr2  r   r   r   r&   
claim_lockresolve_workspaceset_workspace_pathr)   r   )r   r	  r5  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   )
r!  rw   rA   rC  r   r   r  add_commentrn   r   )r   r/   rC  r	  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c           	     T   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 ]g}t          j        ||| j        ||          s5|                    |           t          d| dt          j                   Ut          d|            h	 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   rO  NrQ  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   zmust be a JSON objectzkanban: --metadata: )r7   rO  rQ  zcannot complete z (unknown id or terminal state)z
Completed r   )r9   r{   r   r   r   r   rC   r  loads
isinstancedictr   JSONDecodeErrorr   r  complete_taskr7   re   )	r   idsrO  raw_metarQ  r   failedr	  tids	            r   r   r   F  s@   
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{!	   	* c"""MMMMTWT^_____(3(())))
	** * * * * * * * * * * * * * * !11!s+   8C
 
D	 DD	!A+FF Fc           	     R   | 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
        |||          s4|                    |           t          d| t          j                   it          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}   zcannot block r   zBlocked rY  r   r   r   )r}   r!  rA   r   rn   r9   r   r   r  r}  
block_taskre   r   r   r   )r   r}   rC  r  r  r	  r  s          r   r   r   r  s   .2kCSXXdk""((***tFF<.4eT : : @bAA
ACF	 L 	L 	LC HtS&2Ff2F2FGGG=s6::: 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 )Nr  r   r   zcannot unblock z (not blocked?)z
Unblocked r   )	r9   r{   r   r   r   r   r  unblock_taskre   r   r  r  r	  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 )Nr  r   r   zcannot archive z	Archived r   )	r9   r{   r   r   r   r   r  archive_taskre   r  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   [rZ  flush皙?

(stopped))r   rn   r   r  r^  r)   rH  r   r4   rG  r   sleeprb  intervalKeyboardInterrupt)r   last_idr	  rX  rJ  rd  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          rZt          t          j	        |j
        |j        |j        |j        |j        d |j        D             |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                              d	S )Nfailure_limit)dry_run	max_spawnr  r  Fc                "    g | ]\  }}}|||d S ))rn   r'   r.  r  )r  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_unassignedr   )r  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): )r   r  dispatch_oncer  rb  r   r   r   r  r   r  r  r  r  r  r  r  rC   r!  )r   r	  resr  r  r  tags          r   r   r     s   	 
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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.
    forceFu   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

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 rY  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 )Nr  r   r   r  i,  r  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   r  z] reclaimed=z	 crashed=z timed_out=z
 promoted=z	 spawned=z auto_blocked=r  )rT   r  r  r   r   r   r   r   r   r  r  r  r  r  rC   )	r  ready_pendingspawned_anynowdid_workHEALTH_WINDOW_ready_queue_nonemptyhealth_stater  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   rT   c                     	 t          j                    5 } |                     d                                          }|du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 SELECT — just asks whether there's at least one ready
        task with an assignee that the dispatcher could have picked up.zfSELECT 1 FROM tasks WHERE status = 'ready' AND assignee IS NOT NULL     AND claim_lock IS NULL LIMIT 1NF)r   r  executefetchonerR   )r	  rows     r   r  z*_cmd_daemon.<locals>._ready_queue_nonemptyJ  s    		 'll9  (**	 
 $' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '  	 	 	55	s4   A +A A AA AA 
A('A(r  )r  r  r  on_tickz(dispatcher stopped))r   rT   )r   r   r   r   r   r   r   r1  mkdir
write_textr   rF   getpidOSErrorrT   r  
run_daemonrb  r   rt   )r   r  r   r  r  r  r  r  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 r  )rA   )r  r  s     r   	<setcomp>z_cmd_watch.<locals>.<setcomp>l  s-    ???qQWWYY????r   ,Nr   z'Watching kanban events. Ctrl-C to stop.Tr  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)   rG  r'   r(   rH  r    r   r  r4   rZ  rn   10s18sz (@r-  r   r  r  )kindssplitr   r   r  r  r  r   fetchallrb  r'   r(   r  r  rR   r   r   r  r  r  )	r   r  cursorr	  r  rowsrU  rH  rd  s	            r   r   r   i  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 )Nr  Fr   r  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  r  r  s      r   r  z_cmd_stats.<locals>.<genexpr>  r  r   r#   oldest_ready_age_secondsz
Oldest ready task age: r   )r   r  board_statsr   r   r  r   r%   r   r"  r!  r   )r   r	  r   r  r  r  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                   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   )rn   platformchat_id	thread_iduser_idzSubscribed :r   rk  r   )r   r  r2  rn   r   r   r   add_notify_subr  r  r  r  rp  s     r   r   r     sW   	 
;tT\**214<11
CCCC
 
 
 
 
 
 
 
 	$,]DLndl	
 	
 	
 	
	
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

6
6
6
6
6%)^;!!!!=!4<!!" # # # 1s   ?B 3BB#&B#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	}t          d
|d         dd
|d          d|d          | d|d          d
           \dS )Nr  Fr   r  r   z(no subscriptions)r  r  r   r!   rn   r  r  r  z  (since event last_event_idr   )	r   r  list_notify_subsrn   r   r   r  r   r%   )r   r	  subsr   thrs        r   r   r     sq   	 7"4667 7 7 7 7 7 7 7 7 7 7 7 7 7 7tVU## djae<<<===q "###q 7 7&'eeK&8&8@"!K."""b 61Y<J 6 6q} 6 6q| 6S 6 6 !/ 26 6 6 	7 	7 	7 	7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)rn   r  r  r  z(no such subscription)r   r   zUnsubscribed from r   )
r   r  remove_notify_subrn   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_logrn   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.Nr  Fc                    g | ]G}|j         |j        |j        |j        |j        |j        |j        |j        |j        |j	        |j
        d HS )r)   rp   r&   rN  r5   rS  rO  rP  rQ  rR  rM  r  rT  s     r   r:  z_cmd_runs.<locals>.<listcomp>  sb     
 
 
  dqyAH9ALJ19ajl
 
 
 
r   r   r  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   r  ra  rn   r   r   r  r   	enumeraterS  r   r   rb  r5   rN  r&   rp   r   rO  rc  rP  )
r   r	  r   irU  endrf  rg  rN  rO  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   r  build_worker_contextrn   r   )r   r	  rw   s      r   r   r     s    	 ;&tT\::; ; ; ; ; ; ; ; ; ; ; ; ; ; ;	$KKK1r  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'r1   r>   r2   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_rootr  r  r  r   resolver  relative_tor   existsis_dirrmtreer   	gc_eventsgc_worker_logsr   )r   r  scratch_root
removed_wsr	  r  r  rG   
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#restc                n   ddl }ddl}| r(|                                 rt          j        |           ng }t          j        dd          }d|_        |                    d          }t          j        dd          }d|_        |                    d	          }t          |           |
                                }|
                                }		 |rd
g|nd
g}
|                    |
          }n:# t          $ r}d| dcY d}~S d}~wt
          j        $ r}d| dcY d}~S d}~ww xY w|                    |          5  |                    |	          5  	 t!          |           n@# t          $ r Y n4t"          $ r(}t%          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   Nz/kanbanF)progadd_helpr_   r`   /_toprO   z(usage error: r   zerror: r   r  z(no output))io
contextlibrA   shlexr  rD   ArgumentParserexit_on_errorr   r   StringIO
parse_args
SystemExitArgumentErrorredirect_stdoutredirect_stderrr   rR   r   r   r   getvaluerstrip)r  r  r  tokensr   r   wrapwrap_subbuf_outbuf_errargvr   r   outerrs                  r   	run_slashr2  D  s0    III"&?4::<<?U[RF$)eDDDF F


_

5
5C "e<<<DD"""//HkkmmGkkmmG'&,<"6""8*t$$ ' ' '&&&&&&&&&&! ' ' '&&&&&&&&&&' 
	#	#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   C3 3
D*=DD*D*D%D*%D*GF6E*)F6*
F'4F66	F'?F"F6"F''F6*G6F:	:G=F:	>GGG)r   r   r   r   )r   r   r   r   )r   r   r   r-   )r;   r   r   r<   )r   rK   )rY   rZ   r   r[   )r   r   r   r   )r   r   )r   r   )r  r   r   r   )7__doc__
__future__r   rD   r  rF   r  r   r   pathlibr   typingr   r   
hermes_clir   r   r$   r   r,   r:   rJ   rX   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   r2  r  r   r   <module>r8     s    # " " " " "   				  



                        & & & & & &  ? ? ? ?N N N N   (   ,3 3 3 3tG G G G\F F F FZ
 
 
 
\ \ \ \2   B      &) ) ) )X   4g g g gT            ,   )" )" )" )"X" " " """ " " " " " " "    $' ' ' 'TG G G GT. . . .b   (           	 	 	 	% % % %P   & & & &Z-2 -2 -2 -2 -2 -2r   