
    iH                      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dUdZdVd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^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>Z0d_d@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`dTZDdS )au"  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    6/home/piyush/.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          } |                     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          }(|(                    dt          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-id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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_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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     >>W   D 	.S"b  d d d,3T  V V V m<<<r   argsargparse.Namespacer   c                b   t          | dd          }|sEt          | dd          }||                                 nt          dt          j                   dS t          | d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k    rt          |           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t0          dt2          dt4          d t6          d!t8          d"t:          i d#t<          d$t>          d%t@          d&tB          d'tD          d(tF          d)tH          d*tJ          d+tL          d,tN          d-tP          d.tR          d/tT          d0tV          d1tX          d2tZ          d3t\          }|/                    |          }|s t          d4|t          j                   d	S 	 ta           ||           pd          S # t          tb          f$ r)}t          d| t          j                   Y d}~dS d}~ww xY w)5u   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   boardzkanban:    zkanban: --board requires a slugzkanban: board = does not exist. Create it with `hermes kanban boards create `.   HERMES_KANBAN_BOARDri   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   zkanban: unknown action )2getattr
print_helpprintsysstderrr   _normalize_board_slug
ValueErrorDEFAULT_BOARDboard_existsrI   environ_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_gcr'   r   RuntimeError)r   rn   parserboard_overridenormedexchandlershandlers           r   kanban_commandr$  r  sa   
 T?D11F /66KZ   
 q T7D11N 3	-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
()
 %%%

   ===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 	GE# #HH ll6""G 222DDDDq774==%A&&&%   SZ0000qqqqqsH   -B 
B5B00B5E 
F"FFK4 4L.L))L.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.profilesr(  rV   )envrL   r(  s      r   _profile_authorr+    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<   )r<   rk   )ro   rp   )rr   rs   rt   )ru   rv   )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     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>  s(    777Q(S3[[777r   )r   kanban_db_pathexistsconnectexecutefetchallrV   )rq   rJ   connrowss       r   _board_task_countsrB    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 r8  krL   s      r   	<genexpr>z#_cmd_boards_list.<locals>.<genexpr>4  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_boardrB  sumvaluesr   rJ  dumpsjoinr   itemsr'   rF   )	r   rF  ri   rx   bmarkerrH  
counts_strrz   s	            r   r-  r-    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-   rh  r'   r   set_current_board)r   r   r!  alreadymetaverbs         r   r.  r.  B  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   rj  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   r/  r/  _  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 rk  r   )	r   r   rq   r   r   r   r   r   rp  )r   r   r!  s      r   r0  r0  n  s   )$)44   ,s,,3:>>>>qqqqq  6SZHHHHq?6"" F6 F F;AF F F	
 	
 	
 	

 q   	
,
,
,
,---1rt  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 )Nr\  rl  rz   r   rb   z  Description:  rm  rn  z  Tasks:        z total (rT  c              3  *   K   | ]\  }}| d | V  dS rV  rX  rY  s      r   r[  z#_cmd_boards_show.<locals>.<genexpr>  s0      JJ41aqJJ1JJJJJJJJr   r   r   )r   r^  read_board_metadatarB  r_  r`  r   r'   rb  r   rc  )r   rx   rr  rH  rI  s        r   r1  r1    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   rj  z renamed to rz   rk  r   )
r   r   rq   r   r   r   r   r   write_board_metadatarz   )r   r   r!  rr  s       r   r2  r2    s    )$)44   ,s,,3:>>>>qqqqq  00 ITYIII:	 	 	 	q"6	:::D	
:6
:
:f
:
:
:;;;1rt  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  unitsr6  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   r=  heartbeat_workerr   r   _worker_run_id_forr   r   r   r   r@  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 )NrJ  Fr   rK  r   uA   (no assignees — create a profile with `hermes -p <name> setup`)rQ  r%   r#   zON DISKr$   rS  on_diskyesnorH  rT  c              3  *   K   | ]\  }}| d | V  dS rV  rX  rY  s      r   r[  z!_cmd_assignees.<locals>.<genexpr>  0      LLTQjjQjjLLLLLLr   z(idle)rz   )
r   r=  known_assigneesr   r   rJ  ra  rb  r   rc  )r   r@  dataentryr  rH  	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.rX  triageFidempotency_keyr:   )r,   r1   r)   r5   r3   r4   r*   r2   parentsr  r  max_runtime_secondsr:   r;   rJ  rK  zCreated z  (z, assignee=-r   r
   u   
⚠  r   )rM   	workspacer  r   r   r   r   r   r   r=  create_taskr,   r1   r)   r5   r+  r*   r2   tupleparentrX   get_taskrJ  ra  r=   r(   r\   )r   ws_kindws_pathr  r!  r;   r@  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*   rF  rJ  Fc                ,    g | ]}t          |          S rX  )r=   )r8  r   s     r   
<listcomp>z_cmd_list.<locals>.<listcomp>F  s     :::q-**:::r   r   rK  r   rE  r   zBoard: r{  z other boardr  r   u"    — `hermes kanban boards list`)
z(no matching tasks))r)   miner+  r   r=  recompute_ready
list_tasksr(   r*   r   r   r   rJ  ra  r]  rV   rF   r^  r.   )r   r)   r@  tasks
all_boardsrx   other_countr   s           r   r   r   6  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   rJ  Fc                8    g | ]}|j         |j        |j        d S )authorr1   r6   r  )r8  cs     r   r  z_cmd_show.<locals>.<listcomp>v  s8        8QV1<PP  r   c                D    g | ]}|j         |j        |j        |j        d S )kindpayloadr6   run_idr  )r8  es     r   r  z_cmd_show.<locals>.<listcomp>z  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  r7  s     r   r  z_cmd_show.<locals>.<listcomp>  sh         $ y !
h y yW !
"#,"#, !
   r   )r  latest_summaryr  childrencommentseventsr   r   rK  r   zTask : z  status:    z  assignee:  r  z  tenant:    z  workspace: z @ r   z  skills:    rT  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    ] rW  ,c              3  4   K   | ]}t          |          V  d S Nr   r8  xs     r   r[  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   r=  r  r   r   r   r   list_commentslist_events
parent_ids	child_ids	list_runsr  r   r=   rJ  ra  r+   r,   r(   r)   r*   r3   r4   r:   rb  r;   rW   rR   r'   rV   r   r   r   r6   r5   
hermes_clir  compute_task_diagnosticsrF   severityr  rc  
isinstancer<   r{   actions	suggestedlabelr7   r8   r1   r9   r  r  r  r  r  maxr  r   r  
splitlinesr   )r   r@  r  r  r  r  r  r   r  r  rR   rZ   cfg_valkddiags
sev_markerr  bitsrZ  rL   ar  r  plrun_tagr9  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noner  nullr  r   r   z	Assigned  to r   r   )	r   r  r   r=  assign_taskr   r   r   r   r   r   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           
     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   r=  reclaim_taskr   r   r   r   r   r  s      r   r  r    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 )Nr   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   r=  reassign_taskr   rX   r   r   r   r   r  s       r   r  r    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          rCt          |                                          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+   rX  r7  s     r   r  z$_cmd_diagnostics.<locals>.<listcomp>K  s    )))q1T7)))r   r  r   c                    i | ]}|g S rX  rX  r8  is     r   r:  z$_cmd_diagnostics.<locals>.<dictcomp>P  s    ,,,1B,,,r   z,SELECT * FROM task_events WHERE task_id IN (z) ORDER BY idr   c                    i | ]}|g S rX  rX  r  s     r   r:  z$_cmd_diagnostics.<locals>.<dictcomp>V  s    ---A!R---r   z*SELECT * FROM task_runs WHERE task_id IN (r+   r  c                *    g | ]}|j         k    |S rX  )r  )r8  r  sevs     r   r  z$_cmd_diagnostics.<locals>.<listcomp>g  s%    KKKas9J9J9J9J9Jr   z;SELECT id, title, status, assignee FROM tasks WHERE id IN (r   r,   r(   r)   )r,   r(   r)   rJ  Fc                f    g | ]-\  }}d |i                     |i           dd |D             i.S )r   r   c                6    g | ]}|                                 S rX  )to_dict)r8  r  s     r   r  z/_cmd_diagnostics.<locals>.<listcomp>.<listcomp>  s     888		888r   )r'   )r8  tiddlrr  s      r   r  z$_cmd_diagnostics.<locals>.<listcomp>{  sl     
 
 
 R	 3((3## 88R888 
 
 
r   r   rK  z$No active diagnostics on this board.r  r  r  r   c              3  4   K   | ]}t          |          V  d S r  )rF   )r8  r  s     r   r[  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  rW  c              3  4   K   | ]}t          |          V  d S r  r  r  s     r   r[  z#_cmd_diagnostics.<locals>.<genexpr>  r  r   r  r  r  )$r  r  r   r=  r   r  r  r   r   r   r  r  r  r<   r>  r?  rb  rF   r  
setdefaultr{   r'   keysrc  rJ  ra  r_  r`  r  r  r,   r  r  r  r  r  )r   r  r@  r  diags_by_taskrA  idsplaceholdersev_byrowrun_byr9  r  r  keptout_jsonr  rI  r  r,   r(   r)   r  r  rZ  rL   r  rr  r  s                              @@r   r  r  2  s6    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 + +KKKK=#5KKK +)-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L?;J8L??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   r=  
link_tasksr   r   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: r&  r   r   z	Unlinked r   )r   r=  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:::1r)  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_taskr   ttlr  r   r   r   r(   
claim_lockresolve_workspaceset_workspace_pathr+   r   )r   r@  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   )
rb  r   rD   r  r+  r   r=  add_commentr   r   )r   r1   r  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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   rJ  loadsr  dictr   JSONDecodeErrorr   r=  complete_taskr9   r  r{   )	r   r  r  raw_metar  r!  failedr@  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  r<  r=  r   r   r  )r9   r  r  zcannot edit z! (unknown id or task is not done)r   zEdited r   )r   rJ  r>  r  r?  r   r@  r   r   r   r   r=  edit_completed_task_resultr   r9   )r   rB  r  r!  r@  s        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   rb  rD   r+  r   r<   r   r   r=  r5  
block_taskr  r{   r   r   r   )r   r   r  r  rC  r@  r  s          r   r  r  1  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 )Nr;  r   r   zcannot unblock z (not blocked?)z
Unblocked r   )	r<   r   r   r   r   r   r=  unblock_taskr{   r   r  rC  r@  r  s        r   r  r  G  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   )	r<   r   r   r   r   r   r=  archive_taskr{   rJ  s        r   r  r  W  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   r=  r  r+   r  r   r6   r  r   sleepr  intervalKeyboardInterrupt)r   last_idr@  r  r  r  s         r   r  r  g  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  rJ  Fc                "    g | ]\  }}}|||d S ))r   r)   r  rX  )r8  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   )rL  r   zReclaimed:    zCrashed:      r#   rT  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   r=  dispatch_oncerX  r  r   r   r   rJ  ra  r]  r^  r_  r`  ra  rb  rc  rd  rF   rb  )r   r@  rx  r  r[  r\  tags          r   r  r  y  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 )Nrn  r   r   ro  i,  rN  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   rP  z] reclaimed=z	 crashed=z timed_out=z
 promoted=z	 spawned=z auto_blocked=rO  )rX   rc  rb  r   r   r   r   r   r   r]  r^  r_  ra  r`  rF   )	rx  ready_pendingspawned_anynowdid_workHEALTH_WINDOW_ready_queue_nonemptyhealth_staterl  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   r=  has_spawnable_readyrV   )r@  s    r   rv  z*_cmd_daemon.<locals>._ready_queue_nonempty  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  )rT  rY  r  on_tickz(dispatcher stopped))r   rX   )r   r   r   r   r   r   r   r  mkdir
write_textr   rI   getpidOSErrorrX   rT  
run_daemonr  r   r   )r   ri  r!  rx  ru  rv  rw  rl  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 rX  )rD   )r8  rZ  s     r   	<setcomp>z_cmd_watch.<locals>.<setcomp>9  s-    ???qQWWYY????r   r  Nr   z'Watching kanban events. Ctrl-C to stop.TrO  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   rN  r6   r  r   10sr  z (@r  r   rQ  rR  )kindssplitr   r   r=  r>  fetchoner   r?  r  r)   r*   rJ  r>  rV   r   r   rS  rT  rU  )	r   r  cursorr@  r!  rA  r9  r  r  s	            r   r  r  6  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 )NrJ  Fr   rK  r   z
By status:)r  r	   r
   r   r   r   r#   r$   	by_statusby_assigneez
By assignee:rT  c              3  *   K   | ]\  }}| d | V  dS rV  rX  rY  s      r   r[  z_cmd_stats.<locals>.<genexpr>s  r  r   r%   oldest_ready_age_secondsz
Oldest ready task age: r  )r   r=  board_statsr   r   rJ  ra  r'   r   rc  rb  r   )r   r@  r   rZ  r[  rH  partsages           r   r  r  g  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   )r   platformchat_id	thread_iduser_idzSubscribed :r   r  r   )r   r=  r  r   r   r   r   add_notify_subr  r  r  r  r(  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 )NrJ  Fr   rK  r   z(no subscriptions)r  r  r   r#   r   r  r  r  z  (since event last_event_idr   )	r   r=  list_notify_subsr   r   r   rJ  ra  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)r   r  r  r  z(no such subscription)r   r   zUnsubscribed from r   )
r   r=  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.NrJ  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  r7  s     r   r  z_cmd_runs.<locals>.<listcomp>  sb     
 
 
  dqyAH9ALJ19ajl
 
 
 
r   r   rK  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=  r  r   r   r   rJ  ra  	enumerater  r   r   r  r7   r  r(   r   r   r  r  r   )
r   r@  r   r  r9  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   r=  build_worker_contextr   r   )r   r@  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  rJ  z0kanban: pass either a task id OR --all, not bothr   r   )r*   zNo triage tasksz for tenant r   rk  )	specifiedrI  z+kanban: specify requires a task id or --all)r  r   )r   r  r   	new_titleu    — retitled: z
Specified u	    → todozkanban: specify r  )r  r  rX   r   r+  r   r   r   r   list_triage_idsrJ  ra  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  (;g&7;;; 
 K7?KK\KKLLLLJwJJ'.JJ      )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_rootr=  r>  r?  r   resolver  relative_tor   r<  is_dirrmtreer   	gc_eventsgc_worker_logsr   )r   r  scratch_root
removed_wsr@  rA  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#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_helpre   rf   /_toprS   z(usage error: r   zerror: r   r  z(no output))io
contextlibrD   shlexr  rG   ArgumentParserexit_on_errorr   r   StringIO
parse_args
SystemExitArgumentErrorredirect_stdoutredirect_stderrr$  rV   r   r   r   getvaluerstrip)r  r  r  tokensr  r   wrapwrap_subbuf_outbuf_errargvr   r!  outerrs                  r   	run_slashr  [  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   rN   )r]   r^   r   r_   )r   r   r   r   )r   r   )rq   r   r   r3  )r   r   )r   r   r   r   )r  r   r   r   )E__doc__
__future__r   rG   rJ  rI   r  r   r   pathlibr   typingr   r   r  r   r   r&   r   r.   r=   rM   r\   r   r$  r+  r   rB  r-  r.  r/  r0  r1  r2  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  rX  r   r   <module>r     s    # " " " " "   				  



                        & & & & & &  ? ? ? ?N N N N   *   ,3 3 3 3tN N N Njl l l lf
 
 
 
"   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   G1 G1 G1 G1T& & & &Z-2 -2 -2 -2 -2 -2r   