+
    <j                     j   R t ^ RIt^ RIt^ RIHt ^ RIHt ]! ]P                  P                  RR4      4      tRt	Rt
RtR	tR
tR. R-OR. R.OR. R/OR. R0ORRR.R. R1OR. R2OR. R3O/tR R ltR R ltR4R R lltR R ltR R ltR R  ltR4R! R" lltR5R# R$ lltR% R& ltR' R( ltR) R* ltR+ R, ltR# )6a  Read/write helpers for Mitch's Obsidian vault, shared with the /pa skill.

Design contract (so Jessica never corrupts /pa's structured files):

- Anything messy or structured (notes, tasks, reminders, vitals, golf) goes to a
  dedicated voice-capture inbox (``Jessica Inbox.md``) as tagged, timestamped
  bullets. The /pa skill triages that inbox into the kanban board, vitals log,
  etc. on its morning/evening runs.
- Only simple, low-risk list appends write directly: grocery, household, and the
  pantry file (which Jessica owns outright).
- Everything else is read-only.

The vault path is read from ``$MT_VAULT`` and defaults to the known location.
N)datetime)PathMT_VAULTz$/Users/mitch_tango/Obsidian/MT_VaultzJessica Inbox.mdzTasks/Grocery List.mdzTasks/Household.mdzTasks/Task Board.mdzFood/Pantry.mdProducezMeat / ProteinDairyzBakery / PreparedFrozenfrozenicecream	Beverages	HouseholdPantryc                0    V ^8  d   QhR\         R\        /# )   relpathreturn)strr   )formats   ";/Users/mitch_tango/dev/rabbit-r1-livekit/agent/src/vault.py__annotate__r   *   s            c                    \         P                  4       p\         V ,          P                  4       pW!8w  d   WP                  9  d   \        RV  24      hV# )zHResolve a vault-relative path, refusing anything that escapes the vault.zpath escapes vault: )VAULTresolveparents
ValueError)r   rootps   &  r   
_safe_pathr   *   sE    ==?D	!!#AyT*/y9::Hr   c                >    V ^8  d   QhR\         R\         R,          /# )r   r   r   Nr   )r   s   "r   r   r   3   s     1 1s 1sTz 1r   c                 h    \        V 4      pVP                  4       '       d   VP                  4       # R # N)r   exists	read_text)r   r   s   & r   r#   r#   3   s'    7AHHJJ1;;=0D0r   c                >    V ^8  d   QhR\         R,          R\        /# )r   dtNr   )r   r   )r   s   "r   r   r   8   s     + +8d? +c +r   c                 N    T ;'       g    \         P                  ! 4       p R V R R2# )zDaily Notes/%Y.%m.%dz.md)r   now)r%   s   &r   daily_note_relpathr)   8   s&    			x||~B"Xc**r   c                @    V ^8  d   QhR\         R\         R\         RR/# )r   r   headingliner   Nr   )r   s   "r   r   r   =   s(     * *# * *3 *4 *r   c           	       aa	 \        V 4      pVP                  P                  RRR7       VP                  4       '       d   VP	                  4       MRpVP                  4       o	\        V3R l\        S	4       4       R4      pVfL   VP                  4       '       d   VP                  R4      R,           MRpVP                  V S RV R24       R# \        V	3R l\        V^,           \        S	4      4       4       \        S	4      4      pTpV^,
          V8  d0   S	V^,
          ,          P                  4       '       g   V^,          pK=  S	P                  W4       VP                  RP                  S	4      R,           4       R# )	zAppend ``line`` under the markdown ``heading`` (e.g. ``## Produce``).

Inserts after the last existing item in that section. If the heading is
absent, a new section is appended at the end of the file. Creates the file
if needed.
Tr   exist_ok c              3      <"   T FJ  w  rVP                  4       P                  4       SP                  4       P                  4       8X  g   KF  Vx  KL  	  R # 5ir!   )striplower).0ilnr+   s   &  r   	<genexpr>'append_under_heading.<locals>.<genexpr>J   s<     Z(uqBHHJ,<,<,>'--/BWBWBY,Y(s   AA
AN
z

c              3      <"   T F5  pSV,          P                  4       P                  R 4      '       g   K1  Vx  K7  	  R# 5i)## N)lstrip
startswith)r4   jliness   & r   r7   r8   S   s.     W/q58??3D3O3OPU3V/s
   .A 
A )r   parentmkdirr"   r#   
splitlinesnext	enumerater2   rstrip
write_textrangeleninsertjoin)
r   r+   r,   r   texthidxprefixend	insert_atr?   s
   &f&      @r   append_under_headingrP   =   s'    	7AHHNN4$N/HHJJ1;;=BDOOEZ	%(ZD |15$++d#f,2	xy4&34
WE$(CJ/WE
C I
a-$
uY]';'A'A'C'CQ		LL!LL5!D()r   c                <    V ^8  d   QhR\         R\         R\         /# )r   kindrK   r   r   )r   s   "r   r   r   ]   s!      # S S r   c                *   \         P                  ! 4       pRVR 2pRVR RV P                  4        RVP                  4        2p\	        \
        4      pVP                  4       '       g   VP                  RV RV R24       R	# \        \
        W44       R	# )
zIAppend a tagged, timestamped bullet to the voice inbox for /pa to triage.r;   r'   z- [ ] [z%H:%Mz] z: z^# Jessica Inbox

Voice captures from Jessica, for /pa to triage on its morning/evening runs.

r9   z	Captured.)	r   r(   upperr2   r   INBOXr"   rF   rP   )rR   rK   r(   day_headingr,   r   s   &&    r   capturerW   ]   s    
,,.CH~&KSKr$**,r$**,@D5A88::	^m2dV2'	

 2r   c                0    V ^8  d   QhR\         R\         /# r   itemr   r   )r   s   "r   r   r   n   s      S S r   c                2  a \         P                  ! RV P                  4       4      p\        V4      pV F}  p\	        V4      ^8  d,   VP                  R4      '       d   VP                  VRR	 4       \	        V4      ^8  g   KP  VP                  R4      '       g   Ki  VP                  VRR
 4       K  	  \        P                  4        FJ  w  po\        ;QJ d    V3R lV 4       F  '       g   K   RM	  RM! V3R lV 4       4      '       g   KH  Vu # 	  R# )zIBest-effort map of a grocery item to a store section. Defaults to Pantry.z[a-z]+sNesc              3   ,   <"   T F	  qS9   x  K  	  R # 5ir!    )r4   wkeywordss   & r   r7   %categorize_grocery.<locals>.<genexpr>z   s     ,eH}es   TFr   )
refindallr3   setrH   endswithadd_GROCERY_SECTIONSitemsany)rZ   rawwordsr`   sectionra   s   &    @r   categorize_groceryrp   n   s    
**Y


-C HEq6A:!**S//IIafq6A:!**T**IIaf	 
 /4463,e,333,e,,,N 7 r   c                J    V ^8  d   QhR\         R\         R,          R\         /# )r   rZ   ro   Nr   r   )r   s   "r   r   r      s%      c C$J # r   c                z    T;'       g    \        V 4      p\        \        RV 2RV P                  4        24       V# )z;Add a grocery item under its (auto-detected) store section.r;   - [ ] )rp   rP   GROCERYr2   )rZ   ro   s   &&r   add_groceryru      s9    11+D1GCy/VDJJL>3JKNr   c                <    V ^8  d   QhR\         R\         R\         /# )r   rZ   tierr   r   )r   s   "r   r   r      s!       3  r   c                 P    \        \        R V 2RV P                  4        24       V# )r;   rs   )rP   	HOUSEHOLDr2   )rZ   rw   s   &&r   add_householdrz      s&    c$LF4::<.2IJKr   c                :    V ^8  d   QhR\         \        ,          /# r   r   listr   )r   s   "r   r   r      s      $s) r   c                    \        \        4      p V '       g   . # V P                  4       p\        R \	        V4       4       R4      pVf   . # . pW^,           R  Fz  pVP                  4       P                  R4      '       d    V# \        P                  ! RV4      pV'       g   KL  VP                  VP                  ^4      P                  4       4       K|  	  V# )zDReturn the task lines under the Task Board's 'Today / Focus' column.c              3      "   T F^  w  rVP                  4       P                  R 4      '       g   K,  RVP                  4       9   g   KC  RVP                  4       9   g   KZ  Vx  K`  	  R# 5i)r;   todayfocusN)r<   r=   r3   )r4   r5   r6   s   &  r   r7   #read_today_focus.<locals>.<genexpr>   sY      	
)yy{%%e, 18BHHJ1F KRVXV^V^V`K` A)s   )A(A(A(
A(Nr;   \s*- \[[ xX]\]\s*(.+))r#   
TASK_BOARDrB   rC   rD   r<   r=   re   matchappendgroupr2   )rK   r?   startrk   r6   ms         r   read_today_focusr      s    Z D	OOE	
"5)	

 	E }	EAIK 99;!!%(( L HH-r21LL))+, ! Lr   c                :    V ^8  d   QhR\         \        ,          /# r|   r}   )r   s   "r   r   r      s      T#Y r   c                      \        \        4      p V '       g   . # V P                  4        Uu. uFC  p\        P                  ! R V4      ;p'       g   K$  VP                  ^4      P                  4       NKE  	  up# u upi )r   )r#   PANTRYrB   re   r   r   r2   )rK   r6   r   s      r   read_pantryr      sl    VD	 //##B2B77A7 	
#  s   !A8#A8c                (    V ^8  d   QhR\         RR/# )r   rZ   r   Nr   )r   s   "r   r   r      s     F FS FT Fr   c                     \        \        4      pVP                  P                  R R R7       VP	                  4       '       g   VP                  R4       \        \        RRV P                  4        24       R# )Tr.   z2# Pantry

What's on hand. Maintained by Jessica.

z# Pantryrs   N)r   r   r@   rA   r"   rF   rP   r2   )rZ   r   s   & r   
add_pantryr      sQ    6AHHNN4$N/88::	MNvdjjl^-DEr   c                0    V ^8  d   QhR\         R\        /# rY   )r   bool)r   s   "r   r   r      s        r   c                   \        \        4      pVP                  4       '       g   R# V P                  4       P	                  4       p. RrCVP                  4       P                  4        Fp  p\        P                  ! RV4      pV'       g>   V'       d6   W&P                  ^4      P                  4       P	                  4       9   d   RpK_  VP                  V4       Kr  	  V'       d(   VP                  RP                  V4      R,           4       V# )zMRemove the first pantry entry matching ``item`` (case-insensitive substring).Fr   Tr9   )r   r   r"   r2   r3   r#   rB   re   r   r   r   rF   rJ   )rZ   r   needleoutremovedr6   r   s   &      r   remove_pantryr      s    6A88::ZZ\!Fukkm&&(HH-r21771:+;+;+=+C+C+E!EG

2 ) 	TYYs^d*+Nr   )lettuceoniongarlictomatopeppercarrotceleryapplebananalemonlimeherbparsleycilantrobasilspinachkalepotatoavocadobroccoli	asparagusmushroomcucumberzucchinifruit	vegetablescallionshallotginger)chickenbeefporkbaconsausageturkeyfishsalmonshrimpeggeggstofu
prosciuttosteaklambground)milkcheesebutteryogurtcreamparmesan
mozzarellafeta)breadbunbageltortilla	croissanteclairrollbaguette)waterjuicesodawinebeercoffeeteaseltzer)towel	detergentsoapfoilwrapnapkinspongetrashbagcleanertoilet)floursugarsaltoilvinegarricepastabulgurstockbrothbeanspicesaucebakingcuminpaprikaoregano
cornstarchhoneysyrupmustardketchupmayocantomatoesnutsoatscerealr!   )zWhen I Get To It)__doc__osre   r   pathlibr   environgetr   rU   rt   ry   r   r   rj   r   r#   r)   rP   rW   rp   ru   rz   r   r   r   r   r_   r   r   <module>r     s    
 	  RZZ^^J(NOP
! 	"
	   ~  l^ix$Wx  V	 1
+
*@""
:Fr   