@hasna/conversations 0.1.17 → 0.1.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ /*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-duration:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-red-50:oklch(97.1% .013 17.38);--color-red-100:oklch(93.6% .032 17.717);--color-red-200:oklch(88.5% .062 18.334);--color-red-300:oklch(80.8% .114 19.571);--color-red-500:oklch(63.7% .237 25.331);--color-red-700:oklch(50.5% .213 27.518);--color-red-800:oklch(44.4% .177 26.899);--color-red-900:oklch(39.6% .141 25.723);--color-red-950:oklch(25.8% .092 26.042);--color-orange-300:oklch(83.7% .128 66.29);--color-orange-400:oklch(75% .183 55.934);--color-orange-500:oklch(70.5% .213 47.604);--color-orange-600:oklch(64.6% .222 41.116);--color-orange-700:oklch(55.3% .195 38.402);--color-orange-800:oklch(47% .157 37.304);--color-amber-100:oklch(96.2% .059 95.617);--color-amber-300:oklch(87.9% .169 91.605);--color-amber-400:oklch(82.8% .189 84.429);--color-amber-700:oklch(55.5% .163 48.998);--color-amber-800:oklch(47.3% .137 46.201);--color-amber-950:oklch(27.9% .077 45.635);--color-green-50:oklch(98.2% .018 155.826);--color-green-100:oklch(96.2% .044 156.743);--color-green-200:oklch(92.5% .084 155.995);--color-green-300:oklch(87.1% .15 154.449);--color-green-400:oklch(79.2% .209 151.711);--color-green-500:oklch(72.3% .219 149.579);--color-green-700:oklch(52.7% .154 150.069);--color-green-800:oklch(44.8% .119 151.328);--color-green-900:oklch(39.3% .095 152.535);--color-green-950:oklch(26.6% .065 152.934);--color-teal-500:oklch(70.4% .14 182.503);--color-blue-400:oklch(70.7% .165 254.624);--color-blue-500:oklch(62.3% .214 259.815);--color-blue-600:oklch(54.6% .245 262.881);--color-indigo-100:oklch(93% .034 272.788);--color-indigo-300:oklch(78.5% .115 274.713);--color-indigo-500:oklch(58.5% .233 277.117);--color-indigo-700:oklch(45.7% .24 277.023);--color-indigo-950:oklch(25.7% .09 281.288);--color-purple-500:oklch(62.7% .265 303.9);--color-pink-500:oklch(65.6% .241 354.308);--color-rose-500:oklch(64.5% .246 16.439);--color-slate-100:oklch(96.8% .007 247.896);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-600:oklch(44.6% .043 257.281);--color-slate-900:oklch(20.8% .042 265.755);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-xs:20rem;--container-md:28rem;--container-lg:32rem;--container-6xl:72rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-base:1rem;--text-base--line-height: 1.5 ;--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--text-3xl:1.875rem;--text-3xl--line-height: 1.2 ;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--animate-spin:spin 1s linear infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}*{border-color:var(--border)}body{background-color:var(--background);color:var(--foreground);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.inset-0{inset:calc(var(--spacing)*0)}.inset-y-0{inset-block:calc(var(--spacing)*0)}.top-2\.5{top:calc(var(--spacing)*2.5)}.top-4{top:calc(var(--spacing)*4)}.top-\[50\%\]{top:50%}.right-0{right:calc(var(--spacing)*0)}.right-4{right:calc(var(--spacing)*4)}.right-6{right:calc(var(--spacing)*6)}.bottom-6{bottom:calc(var(--spacing)*6)}.left-2{left:calc(var(--spacing)*2)}.left-3{left:calc(var(--spacing)*3)}.left-\[50\%\]{left:50%}.z-40{z-index:40}.z-50{z-index:50}.-mx-1{margin-inline:calc(var(--spacing)*-1)}.mx-auto{margin-inline:auto}.my-1{margin-block:calc(var(--spacing)*1)}.my-2{margin-block:calc(var(--spacing)*2)}.mt-0\.5{margin-top:calc(var(--spacing)*.5)}.mt-4{margin-top:calc(var(--spacing)*4)}.mb-1{margin-bottom:calc(var(--spacing)*1)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.mb-3{margin-bottom:calc(var(--spacing)*3)}.mb-4{margin-bottom:calc(var(--spacing)*4)}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.block{display:block}.flex{display:flex}.grid{display:grid}.inline-flex{display:inline-flex}.table{display:table}.size-1\.5{width:calc(var(--spacing)*1.5);height:calc(var(--spacing)*1.5)}.size-3{width:calc(var(--spacing)*3);height:calc(var(--spacing)*3)}.size-3\.5{width:calc(var(--spacing)*3.5);height:calc(var(--spacing)*3.5)}.size-4{width:calc(var(--spacing)*4);height:calc(var(--spacing)*4)}.size-5{width:calc(var(--spacing)*5);height:calc(var(--spacing)*5)}.size-6{width:calc(var(--spacing)*6);height:calc(var(--spacing)*6)}.size-8{width:calc(var(--spacing)*8);height:calc(var(--spacing)*8)}.size-9{width:calc(var(--spacing)*9);height:calc(var(--spacing)*9)}.size-10{width:calc(var(--spacing)*10);height:calc(var(--spacing)*10)}.h-5{height:calc(var(--spacing)*5)}.h-7{height:calc(var(--spacing)*7)}.h-8{height:calc(var(--spacing)*8)}.h-9{height:calc(var(--spacing)*9)}.h-10{height:calc(var(--spacing)*10)}.h-14{height:calc(var(--spacing)*14)}.h-px{height:1px}.min-h-screen{min-height:100vh}.w-10{width:calc(var(--spacing)*10)}.w-96{width:calc(var(--spacing)*96)}.w-auto{width:auto}.w-fit{width:fit-content}.w-full{width:100%}.max-w-6xl{max-width:var(--container-6xl)}.max-w-\[calc\(100\%-2rem\)\]{max-width:calc(100% - 2rem)}.max-w-md{max-width:var(--container-md)}.max-w-xs{max-width:var(--container-xs)}.min-w-0{min-width:calc(var(--spacing)*0)}.min-w-\[1\.25rem\]{min-width:1.25rem}.min-w-\[8rem\]{min-width:8rem}.flex-1{flex:1}.shrink-0{flex-shrink:0}.caption-bottom{caption-side:bottom}.translate-x-\[-50\%\]{--tw-translate-x:-50%;translate:var(--tw-translate-x)var(--tw-translate-y)}.translate-y-\[-50\%\]{--tw-translate-y:-50%;translate:var(--tw-translate-x)var(--tw-translate-y)}.scale-0{--tw-scale-x:0%;--tw-scale-y:0%;--tw-scale-z:0%;scale:var(--tw-scale-x)var(--tw-scale-y)}.scale-100{--tw-scale-x:100%;--tw-scale-y:100%;--tw-scale-z:100%;scale:var(--tw-scale-x)var(--tw-scale-y)}.rotate-0{rotate:none}.rotate-90{rotate:90deg}.animate-spin{animation:var(--animate-spin)}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.auto-rows-min{grid-auto-rows:min-content}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-rows-\[auto_auto\]{grid-template-rows:auto auto}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1{gap:calc(var(--spacing)*1)}.gap-1\.5{gap:calc(var(--spacing)*1.5)}.gap-2{gap:calc(var(--spacing)*2)}.gap-3{gap:calc(var(--spacing)*3)}.gap-4{gap:calc(var(--spacing)*4)}.gap-6{gap:calc(var(--spacing)*6)}:where(.space-y-0\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*.5)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*.5)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*1.5)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*1.5)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*2)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*2)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*3)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*3)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*4)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*4)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*6)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*6)*calc(1 - var(--tw-space-y-reverse)))}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px*var(--tw-divide-y-reverse));border-bottom-width:calc(1px*calc(1 - var(--tw-divide-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-sm{border-radius:calc(var(--radius) - 4px)}.rounded-xl{border-radius:calc(var(--radius) + 4px)}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-l-2{border-left-style:var(--tw-border-style);border-left-width:2px}.border-amber-300{border-color:var(--color-amber-300)}.border-border{border-color:var(--border)}.border-green-200{border-color:var(--color-green-200)}.border-green-300{border-color:var(--color-green-300)}.border-input{border-color:var(--input)}.border-muted{border-color:var(--muted)}.border-muted-foreground\/30{border-color:var(--muted-foreground)}@supports (color:color-mix(in lab,red,red)){.border-muted-foreground\/30{border-color:color-mix(in oklab,var(--muted-foreground)30%,transparent)}}.border-orange-300{border-color:var(--color-orange-300)}.border-red-200{border-color:var(--color-red-200)}.border-transparent{border-color:#0000}.bg-amber-100{background-color:var(--color-amber-100)}.bg-background{background-color:var(--background)}.bg-black\/50{background-color:#00000080}@supports (color:color-mix(in lab,red,red)){.bg-black\/50{background-color:color-mix(in oklab,var(--color-black)50%,transparent)}}.bg-blue-500{background-color:var(--color-blue-500)}.bg-border{background-color:var(--border)}.bg-card{background-color:var(--card)}.bg-destructive{background-color:var(--destructive)}.bg-green-50{background-color:var(--color-green-50)}.bg-green-100{background-color:var(--color-green-100)}.bg-green-500{background-color:var(--color-green-500)}.bg-indigo-100{background-color:var(--color-indigo-100)}.bg-indigo-500{background-color:var(--color-indigo-500)}.bg-muted{background-color:var(--muted)}.bg-muted-foreground\/50{background-color:var(--muted-foreground)}@supports (color:color-mix(in lab,red,red)){.bg-muted-foreground\/50{background-color:color-mix(in oklab,var(--muted-foreground)50%,transparent)}}.bg-muted\/50{background-color:var(--muted)}@supports (color:color-mix(in lab,red,red)){.bg-muted\/50{background-color:color-mix(in oklab,var(--muted)50%,transparent)}}.bg-orange-500{background-color:var(--color-orange-500)}.bg-pink-500{background-color:var(--color-pink-500)}.bg-popover{background-color:var(--popover)}.bg-primary{background-color:var(--primary)}.bg-purple-500{background-color:var(--color-purple-500)}.bg-red-50{background-color:var(--color-red-50)}.bg-red-100{background-color:var(--color-red-100)}.bg-red-500{background-color:var(--color-red-500)}.bg-rose-500{background-color:var(--color-rose-500)}.bg-secondary{background-color:var(--secondary)}.bg-slate-100{background-color:var(--color-slate-100)}.bg-teal-500{background-color:var(--color-teal-500)}.bg-transparent{background-color:#0000}.p-1{padding:calc(var(--spacing)*1)}.p-2{padding:calc(var(--spacing)*2)}.p-4{padding:calc(var(--spacing)*4)}.p-5{padding:calc(var(--spacing)*5)}.p-6{padding:calc(var(--spacing)*6)}.p-8{padding:calc(var(--spacing)*8)}.px-1{padding-inline:calc(var(--spacing)*1)}.px-1\.5{padding-inline:calc(var(--spacing)*1.5)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-2\.5{padding-inline:calc(var(--spacing)*2.5)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-4{padding-inline:calc(var(--spacing)*4)}.px-6{padding-inline:calc(var(--spacing)*6)}.py-0\.5{padding-block:calc(var(--spacing)*.5)}.py-1{padding-block:calc(var(--spacing)*1)}.py-1\.5{padding-block:calc(var(--spacing)*1.5)}.py-2{padding-block:calc(var(--spacing)*2)}.py-2\.5{padding-block:calc(var(--spacing)*2.5)}.py-3{padding-block:calc(var(--spacing)*3)}.py-6{padding-block:calc(var(--spacing)*6)}.py-8{padding-block:calc(var(--spacing)*8)}.pt-2{padding-top:calc(var(--spacing)*2)}.pr-2{padding-right:calc(var(--spacing)*2)}.pl-3{padding-left:calc(var(--spacing)*3)}.pl-4{padding-left:calc(var(--spacing)*4)}.pl-8{padding-left:calc(var(--spacing)*8)}.pl-9{padding-left:calc(var(--spacing)*9)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.align-middle{vertical-align:middle}.font-mono{font-family:var(--font-mono)}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.leading-none{--tw-leading:1;line-height:1}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.whitespace-nowrap{white-space:nowrap}.whitespace-pre{white-space:pre}.text-amber-700{color:var(--color-amber-700)}.text-blue-600{color:var(--color-blue-600)}.text-card-foreground{color:var(--card-foreground)}.text-destructive{color:var(--destructive)}.text-foreground{color:var(--foreground)}.text-green-700{color:var(--color-green-700)}.text-green-800{color:var(--color-green-800)}.text-indigo-700{color:var(--color-indigo-700)}.text-muted-foreground{color:var(--muted-foreground)}.text-orange-600{color:var(--color-orange-600)}.text-orange-700{color:var(--color-orange-700)}.text-popover-foreground{color:var(--popover-foreground)}.text-primary{color:var(--primary)}.text-primary-foreground{color:var(--primary-foreground)}.text-red-700{color:var(--color-red-700)}.text-red-800{color:var(--color-red-800)}.text-secondary-foreground{color:var(--secondary-foreground)}.text-slate-600{color:var(--color-slate-600)}.text-white{color:var(--color-white)}.italic{font-style:italic}.underline{text-decoration-line:underline}.underline-offset-4{text-underline-offset:4px}.opacity-0{opacity:0}.opacity-70{opacity:.7}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a),0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a),0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a),0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-xs{--tw-shadow:0 1px 2px 0 var(--tw-shadow-color,#0000000d);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-offset-background{--tw-ring-offset-color:var(--background)}.outline-hidden{--tw-outline-style:none;outline-style:none}@media(forced-colors:active){.outline-hidden{outline-offset:2px;outline:2px solid #0000}}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.transition-\[color\,box-shadow\]{transition-property:color,box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.outline-none{--tw-outline-style:none;outline-style:none}.select-none{-webkit-user-select:none;user-select:none}@media(hover:hover){.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}.placeholder\:text-muted-foreground::placeholder{color:var(--muted-foreground)}.last\:mb-0:last-child{margin-bottom:calc(var(--spacing)*0)}@media(hover:hover){.hover\:border-foreground\/20:hover{border-color:var(--foreground)}@supports (color:color-mix(in lab,red,red)){.hover\:border-foreground\/20:hover{border-color:color-mix(in oklab,var(--foreground)20%,transparent)}}.hover\:bg-accent:hover{background-color:var(--accent)}.hover\:bg-destructive\/90:hover{background-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.hover\:bg-destructive\/90:hover{background-color:color-mix(in oklab,var(--destructive)90%,transparent)}}.hover\:bg-muted:hover,.hover\:bg-muted\/50:hover{background-color:var(--muted)}@supports (color:color-mix(in lab,red,red)){.hover\:bg-muted\/50:hover{background-color:color-mix(in oklab,var(--muted)50%,transparent)}}.hover\:bg-primary\/90:hover{background-color:var(--primary)}@supports (color:color-mix(in lab,red,red)){.hover\:bg-primary\/90:hover{background-color:color-mix(in oklab,var(--primary)90%,transparent)}}.hover\:bg-secondary\/80:hover{background-color:var(--secondary)}@supports (color:color-mix(in lab,red,red)){.hover\:bg-secondary\/80:hover{background-color:color-mix(in oklab,var(--secondary)80%,transparent)}}.hover\:text-accent-foreground:hover{color:var(--accent-foreground)}.hover\:text-foreground:hover{color:var(--foreground)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-80:hover{opacity:.8}.hover\:opacity-100:hover{opacity:1}}.focus\:bg-accent:focus{background-color:var(--accent)}.focus\:text-accent-foreground:focus{color:var(--accent-foreground)}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(2px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-ring:focus{--tw-ring-color:var(--ring)}.focus\:ring-offset-2:focus{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,)0 0 0 var(--tw-ring-offset-width)var(--tw-ring-offset-color)}.focus\:outline-hidden:focus{--tw-outline-style:none;outline-style:none}@media(forced-colors:active){.focus\:outline-hidden:focus{outline-offset:2px;outline:2px solid #0000}}.focus-visible\:border-ring:focus-visible{border-color:var(--ring)}.focus-visible\:ring-\[3px\]:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(3px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus-visible\:ring-destructive\/20:focus-visible{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.focus-visible\:ring-destructive\/20:focus-visible{--tw-ring-color:color-mix(in oklab,var(--destructive)20%,transparent)}}.focus-visible\:ring-ring\/50:focus-visible{--tw-ring-color:var(--ring)}@supports (color:color-mix(in lab,red,red)){.focus-visible\:ring-ring\/50:focus-visible{--tw-ring-color:color-mix(in oklab,var(--ring)50%,transparent)}}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:opacity-50:disabled{opacity:.5}.has-\[\>svg\]\:px-2\.5:has(>svg){padding-inline:calc(var(--spacing)*2.5)}.has-\[\>svg\]\:px-3:has(>svg){padding-inline:calc(var(--spacing)*3)}.has-\[\>svg\]\:px-4:has(>svg){padding-inline:calc(var(--spacing)*4)}.data-\[disabled\]\:pointer-events-none[data-disabled]{pointer-events:none}.data-\[disabled\]\:opacity-50[data-disabled]{opacity:.5}.data-\[inset\]\:pl-8[data-inset]{padding-left:calc(var(--spacing)*8)}.data-\[state\=closed\]\:animate-out[data-state=closed]{animation:.15s ease-in exit}.data-\[state\=open\]\:animate-in[data-state=open]{animation:.2s ease-out enter}.data-\[state\=selected\]\:bg-muted[data-state=selected]{background-color:var(--muted)}@media(min-width:40rem){.sm\:max-w-lg{max-width:var(--container-lg)}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:justify-end{justify-content:flex-end}.sm\:text-left{text-align:left}}@media(min-width:48rem){.md\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.md\:text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}}@media(min-width:64rem){.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media(prefers-color-scheme:dark){.dark\:scale-0{--tw-scale-x:0%;--tw-scale-y:0%;--tw-scale-z:0%;scale:var(--tw-scale-x)var(--tw-scale-y)}.dark\:scale-100{--tw-scale-x:100%;--tw-scale-y:100%;--tw-scale-z:100%;scale:var(--tw-scale-x)var(--tw-scale-y)}.dark\:-rotate-90{rotate:-90deg}.dark\:rotate-0{rotate:none}.dark\:border-amber-800{border-color:var(--color-amber-800)}.dark\:border-green-800{border-color:var(--color-green-800)}.dark\:border-green-900{border-color:var(--color-green-900)}.dark\:border-input{border-color:var(--input)}.dark\:border-orange-800{border-color:var(--color-orange-800)}.dark\:border-red-900{border-color:var(--color-red-900)}.dark\:bg-amber-950{background-color:var(--color-amber-950)}.dark\:bg-destructive\/60{background-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.dark\:bg-destructive\/60{background-color:color-mix(in oklab,var(--destructive)60%,transparent)}}.dark\:bg-green-950{background-color:var(--color-green-950)}.dark\:bg-indigo-950{background-color:var(--color-indigo-950)}.dark\:bg-input\/30{background-color:var(--input)}@supports (color:color-mix(in lab,red,red)){.dark\:bg-input\/30{background-color:color-mix(in oklab,var(--input)30%,transparent)}}.dark\:bg-red-950{background-color:var(--color-red-950)}.dark\:bg-slate-900{background-color:var(--color-slate-900)}.dark\:text-amber-300{color:var(--color-amber-300)}.dark\:text-amber-400{color:var(--color-amber-400)}.dark\:text-blue-400{color:var(--color-blue-400)}.dark\:text-green-200{color:var(--color-green-200)}.dark\:text-green-300{color:var(--color-green-300)}.dark\:text-green-400{color:var(--color-green-400)}.dark\:text-indigo-300{color:var(--color-indigo-300)}.dark\:text-orange-400{color:var(--color-orange-400)}.dark\:text-red-200{color:var(--color-red-200)}.dark\:text-red-300{color:var(--color-red-300)}.dark\:text-slate-400{color:var(--color-slate-400)}@media(hover:hover){.dark\:hover\:bg-accent\/50:hover{background-color:var(--accent)}@supports (color:color-mix(in lab,red,red)){.dark\:hover\:bg-accent\/50:hover{background-color:color-mix(in oklab,var(--accent)50%,transparent)}}.dark\:hover\:bg-input\/50:hover{background-color:var(--input)}@supports (color:color-mix(in lab,red,red)){.dark\:hover\:bg-input\/50:hover{background-color:color-mix(in oklab,var(--input)50%,transparent)}}}.dark\:focus-visible\:ring-destructive\/40:focus-visible{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab,red,red)){.dark\:focus-visible\:ring-destructive\/40:focus-visible{--tw-ring-color:color-mix(in oklab,var(--destructive)40%,transparent)}}}.\[\&_svg\]\:pointer-events-none svg{pointer-events:none}.\[\&_svg\]\:shrink-0 svg{flex-shrink:0}.\[\&_svg\:not\(\[class\*\=\'size-\'\]\)\]\:size-4 svg:not([class*=size-]){width:calc(var(--spacing)*4);height:calc(var(--spacing)*4)}.\[\&_svg\:not\(\[class\*\=\'text-\'\]\)\]\:text-muted-foreground svg:not([class*=text-]){color:var(--muted-foreground)}.\[\&_tr\]\:border-b tr{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.\[\&_tr\:last-child\]\:border-0 tr:last-child{border-style:var(--tw-border-style);border-width:0}.\[\&\:has\(\[role\=checkbox\]\)\]\:pr-0:has([role=checkbox]){padding-right:calc(var(--spacing)*0)}.\[\&\>\[role\=checkbox\]\]\:translate-y-\[2px\]>[role=checkbox]{--tw-translate-y:2px;translate:var(--tw-translate-x)var(--tw-translate-y)}.\[\&\>tr\]\:last\:border-b-0>tr:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}}@keyframes enter{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}@keyframes exit{0%{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(.95)}}:root{--radius:.625rem;--background:oklch(100% 0 0);--foreground:oklch(14.5% 0 0);--card:oklch(100% 0 0);--card-foreground:oklch(14.5% 0 0);--popover:oklch(100% 0 0);--popover-foreground:oklch(14.5% 0 0);--primary:oklch(20.5% 0 0);--primary-foreground:oklch(98.5% 0 0);--secondary:oklch(96.5% 0 0);--secondary-foreground:oklch(20.5% 0 0);--muted:oklch(96.5% 0 0);--muted-foreground:oklch(55.6% 0 0);--accent:oklch(96.5% 0 0);--accent-foreground:oklch(20.5% 0 0);--destructive:oklch(57.7% .245 27.325);--border:oklch(92.1% 0 0);--input:oklch(92.1% 0 0);--ring:oklch(70.8% 0 0)}.dark{--background:oklch(14.5% 0 0);--foreground:oklch(98.5% 0 0);--card:oklch(17.5% 0 0);--card-foreground:oklch(98.5% 0 0);--popover:oklch(17.5% 0 0);--popover-foreground:oklch(98.5% 0 0);--primary:oklch(98.5% 0 0);--primary-foreground:oklch(20.5% 0 0);--secondary:oklch(26.9% 0 0);--secondary-foreground:oklch(98.5% 0 0);--muted:oklch(26.9% 0 0);--muted-foreground:oklch(70.8% 0 0);--accent:oklch(26.9% 0 0);--accent-foreground:oklch(98.5% 0 0);--destructive:oklch(39.6% .141 25.723);--border:oklch(26.9% 0 0);--input:oklch(26.9% 0 0);--ring:oklch(43.9% 0 0)}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-duration{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}
@@ -4,8 +4,8 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>Hasna Conversations</title>
7
- <script type="module" crossorigin src="/assets/index-CCdh63JU.js"></script>
8
- <link rel="stylesheet" crossorigin href="/assets/index-VFT0_0LI.css">
7
+ <script type="module" crossorigin src="/assets/index-Bw0wMcXE.js"></script>
8
+ <link rel="stylesheet" crossorigin href="/assets/index-CF_GDtNp.css">
9
9
  </head>
10
10
  <body>
11
11
  <div id="root"></div>
package/dist/index.d.ts CHANGED
@@ -9,12 +9,14 @@
9
9
  * Or use the interactive TUI:
10
10
  * conversations
11
11
  */
12
- export { sendMessage, readMessages, markRead, markSessionRead, markSpaceRead, markAllRead, getMessageById, searchMessages, exportMessages, deleteMessage, editMessage, pinMessage, unpinMessage, getPinnedMessages, getUnreadBlockers, } from "./lib/messages.js";
12
+ export { sendMessage, readMessages, markRead, markSessionRead, markSpaceRead, markAllRead, getMessageById, searchMessages, exportMessages, deleteMessage, editMessage, pinMessage, unpinMessage, getPinnedMessages, getUnreadBlockers, getThreadReplies, } from "./lib/messages.js";
13
13
  export { listSessions, getSession, } from "./lib/sessions.js";
14
14
  export { createSpace, updateSpace, archiveSpace, unarchiveSpace, listSpaces, getSpace, joinSpace, leaveSpace, getSpaceMembers, isSpaceMember, getSpaceDepth, } from "./lib/spaces.js";
15
15
  export { createProject, listProjects, getProject, getProjectByName, updateProject, deleteProject, } from "./lib/projects.js";
16
16
  export { getDb, getDbPath, closeDb, } from "./lib/db.js";
17
17
  export { startPolling, useSpaceMessages, } from "./lib/poll.js";
18
18
  export { resolveIdentity, requireIdentity, } from "./lib/identity.js";
19
+ export { addReaction, removeReaction, getReactions, getReactionSummary, } from "./lib/reactions.js";
20
+ export { fireWebhooks, } from "./lib/webhooks.js";
19
21
  export { heartbeat, getPresence, listAgents, removePresence, renameAgent, } from "./lib/presence.js";
20
- export type { Message, Session, Space, SpaceInfo, SpaceMember, Project, ProjectInfo, Priority, SendMessageOptions, ReadMessagesOptions, SearchMessagesOptions, AgentPresence, } from "./types.js";
22
+ export type { Message, Session, Space, SpaceInfo, SpaceMember, Project, ProjectInfo, Priority, SendMessageOptions, ReadMessagesOptions, SearchMessagesOptions, AgentPresence, Reaction, Attachment, } from "./types.js";
package/dist/index.js CHANGED
@@ -133,6 +133,17 @@ function getDb() {
133
133
  metadata TEXT
134
134
  )
135
135
  `);
136
+ db.exec(`
137
+ CREATE TABLE IF NOT EXISTS reactions (
138
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
139
+ message_id INTEGER NOT NULL REFERENCES messages(id) ON DELETE CASCADE,
140
+ agent TEXT NOT NULL,
141
+ emoji TEXT NOT NULL,
142
+ created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
143
+ UNIQUE(message_id, agent, emoji)
144
+ )
145
+ `);
146
+ db.exec("CREATE INDEX IF NOT EXISTS idx_reactions_message ON reactions(message_id)");
136
147
  const existingTables = db.prepare("SELECT name FROM sqlite_master WHERE type='table'").all();
137
148
  const tableNames = existingTables.map((t) => t.name);
138
149
  if (tableNames.includes("channels") && tableNames.includes("spaces")) {
@@ -190,6 +201,46 @@ function getDb() {
190
201
  db.exec("ALTER TABLE messages ADD COLUMN blocking INTEGER NOT NULL DEFAULT 0");
191
202
  db.exec("CREATE INDEX IF NOT EXISTS idx_messages_blocking ON messages(blocking)");
192
203
  }
204
+ if (!colNames2.includes("attachments")) {
205
+ db.exec("ALTER TABLE messages ADD COLUMN attachments TEXT");
206
+ }
207
+ if (!colNames2.includes("reply_to")) {
208
+ db.exec("ALTER TABLE messages ADD COLUMN reply_to INTEGER REFERENCES messages(id)");
209
+ db.exec("CREATE INDEX IF NOT EXISTS idx_messages_reply_to ON messages(reply_to)");
210
+ }
211
+ const ftsExists = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='messages_fts'").get();
212
+ if (!ftsExists) {
213
+ db.exec(`
214
+ CREATE VIRTUAL TABLE messages_fts USING fts5(
215
+ content, from_agent, to_agent, space,
216
+ content_rowid='id', content='messages'
217
+ )
218
+ `);
219
+ db.exec(`
220
+ INSERT INTO messages_fts(rowid, content, from_agent, to_agent, space)
221
+ SELECT id, content, from_agent, to_agent, space FROM messages
222
+ `);
223
+ db.exec(`
224
+ CREATE TRIGGER IF NOT EXISTS messages_fts_insert AFTER INSERT ON messages BEGIN
225
+ INSERT INTO messages_fts(rowid, content, from_agent, to_agent, space)
226
+ VALUES (new.id, new.content, new.from_agent, new.to_agent, new.space);
227
+ END
228
+ `);
229
+ db.exec(`
230
+ CREATE TRIGGER IF NOT EXISTS messages_fts_delete AFTER DELETE ON messages BEGIN
231
+ INSERT INTO messages_fts(messages_fts, rowid, content, from_agent, to_agent, space)
232
+ VALUES ('delete', old.id, old.content, old.from_agent, old.to_agent, old.space);
233
+ END
234
+ `);
235
+ db.exec(`
236
+ CREATE TRIGGER IF NOT EXISTS messages_fts_update AFTER UPDATE OF content ON messages BEGIN
237
+ INSERT INTO messages_fts(messages_fts, rowid, content, from_agent, to_agent, space)
238
+ VALUES ('delete', old.id, old.content, old.from_agent, old.to_agent, old.space);
239
+ INSERT INTO messages_fts(rowid, content, from_agent, to_agent, space)
240
+ VALUES (new.id, new.content, new.from_agent, new.to_agent, new.space);
241
+ END
242
+ `);
243
+ }
193
244
  return db;
194
245
  }
195
246
  function closeDb() {
@@ -2015,6 +2066,85 @@ var require_react = __commonJS((exports, module) => {
2015
2066
  // src/lib/messages.ts
2016
2067
  init_db();
2017
2068
  import { randomUUID } from "crypto";
2069
+ import { mkdirSync as mkdirSync2, copyFileSync, statSync } from "fs";
2070
+ import { join as join3 } from "path";
2071
+ import { homedir as homedir3 } from "os";
2072
+
2073
+ // src/lib/webhooks.ts
2074
+ import { readFileSync } from "fs";
2075
+ import { join as join2 } from "path";
2076
+ import { homedir as homedir2 } from "os";
2077
+ var cachedConfig = null;
2078
+ var configLoadedAt = 0;
2079
+ var CONFIG_CACHE_MS = 1e4;
2080
+ function getConfigPath() {
2081
+ return process.env.CONVERSATIONS_CONFIG_PATH || join2(homedir2(), ".conversations", "config.json");
2082
+ }
2083
+ function loadConfig() {
2084
+ const now = Date.now();
2085
+ if (cachedConfig && now - configLoadedAt < CONFIG_CACHE_MS)
2086
+ return cachedConfig;
2087
+ try {
2088
+ const raw = readFileSync(getConfigPath(), "utf-8");
2089
+ cachedConfig = JSON.parse(raw);
2090
+ configLoadedAt = now;
2091
+ return cachedConfig;
2092
+ } catch {
2093
+ cachedConfig = {};
2094
+ configLoadedAt = now;
2095
+ return cachedConfig;
2096
+ }
2097
+ }
2098
+ function matchesEvent(webhook, msg) {
2099
+ for (const event of webhook.events) {
2100
+ if (event === "dm" && !msg.space)
2101
+ return true;
2102
+ if (event === "blocker" && msg.blocking)
2103
+ return true;
2104
+ if (event === "space" && msg.space)
2105
+ return true;
2106
+ if (event === "mention" && webhook.agent && msg.content.includes(`@${webhook.agent}`))
2107
+ return true;
2108
+ }
2109
+ return false;
2110
+ }
2111
+ function fireWebhooks(msg) {
2112
+ const config = loadConfig();
2113
+ if (!config.webhooks || config.webhooks.length === 0)
2114
+ return;
2115
+ for (const webhook of config.webhooks) {
2116
+ if (webhook.agent && msg.to_agent !== webhook.agent && !msg.space)
2117
+ continue;
2118
+ if (!matchesEvent(webhook, msg))
2119
+ continue;
2120
+ fetch(webhook.url, {
2121
+ method: "POST",
2122
+ headers: { "Content-Type": "application/json" },
2123
+ body: JSON.stringify({
2124
+ id: msg.id,
2125
+ from: msg.from_agent,
2126
+ to: msg.to_agent,
2127
+ space: msg.space,
2128
+ content: msg.content,
2129
+ priority: msg.priority,
2130
+ blocking: msg.blocking,
2131
+ created_at: msg.created_at
2132
+ })
2133
+ }).catch(() => {});
2134
+ }
2135
+ }
2136
+
2137
+ // src/lib/messages.ts
2138
+ function compactMessage(msg) {
2139
+ const result = {};
2140
+ for (const key of Object.keys(msg)) {
2141
+ const val = msg[key];
2142
+ if (val !== null && val !== undefined) {
2143
+ result[key] = val;
2144
+ }
2145
+ }
2146
+ return result;
2147
+ }
2018
2148
  function parseMessage(row) {
2019
2149
  let metadata = null;
2020
2150
  if (row.metadata) {
@@ -2024,12 +2154,54 @@ function parseMessage(row) {
2024
2154
  metadata = null;
2025
2155
  }
2026
2156
  }
2157
+ let attachments = null;
2158
+ if (row.attachments) {
2159
+ try {
2160
+ attachments = JSON.parse(row.attachments);
2161
+ } catch {
2162
+ attachments = null;
2163
+ }
2164
+ }
2027
2165
  return {
2028
2166
  ...row,
2029
2167
  metadata,
2030
- blocking: !!row.blocking
2168
+ attachments,
2169
+ blocking: !!row.blocking,
2170
+ reply_to: row.reply_to || null
2031
2171
  };
2032
2172
  }
2173
+ function getAttachmentsDir() {
2174
+ if (process.env.CONVERSATIONS_ATTACHMENTS_DIR)
2175
+ return process.env.CONVERSATIONS_ATTACHMENTS_DIR;
2176
+ return join3(homedir3(), ".conversations", "attachments");
2177
+ }
2178
+ function guessMimeType(name) {
2179
+ const ext = name.split(".").pop()?.toLowerCase();
2180
+ const mimeMap = {
2181
+ txt: "text/plain",
2182
+ md: "text/markdown",
2183
+ json: "application/json",
2184
+ js: "text/javascript",
2185
+ ts: "text/typescript",
2186
+ py: "text/x-python",
2187
+ html: "text/html",
2188
+ css: "text/css",
2189
+ xml: "application/xml",
2190
+ png: "image/png",
2191
+ jpg: "image/jpeg",
2192
+ jpeg: "image/jpeg",
2193
+ gif: "image/gif",
2194
+ svg: "image/svg+xml",
2195
+ webp: "image/webp",
2196
+ pdf: "application/pdf",
2197
+ zip: "application/zip",
2198
+ gz: "application/gzip",
2199
+ csv: "text/csv",
2200
+ yaml: "text/yaml",
2201
+ yml: "text/yaml"
2202
+ };
2203
+ return mimeMap[ext || ""] || "application/octet-stream";
2204
+ }
2033
2205
  function sendMessage(opts) {
2034
2206
  const db2 = getDb();
2035
2207
  const explicitSession = opts.session_id && opts.session_id.trim().length > 0 ? opts.session_id : undefined;
@@ -2037,13 +2209,35 @@ function sendMessage(opts) {
2037
2209
  const metadata = opts.metadata ? JSON.stringify(opts.metadata) : null;
2038
2210
  const normalizedPriority = opts.priority === "low" || opts.priority === "normal" || opts.priority === "high" || opts.priority === "urgent" ? opts.priority : "normal";
2039
2211
  const blocking = opts.blocking ? 1 : 0;
2212
+ const replyTo = opts.reply_to || null;
2040
2213
  const stmt = db2.prepare(`
2041
- INSERT INTO messages (session_id, from_agent, to_agent, space, content, priority, working_dir, repository, branch, metadata, blocking)
2042
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2214
+ INSERT INTO messages (session_id, from_agent, to_agent, space, content, priority, working_dir, repository, branch, metadata, blocking, reply_to)
2215
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2043
2216
  RETURNING *
2044
2217
  `);
2045
- const row = stmt.get(sessionId, opts.from, opts.to, opts.space || null, opts.content, normalizedPriority, opts.working_dir || null, opts.repository || null, opts.branch || null, metadata, blocking);
2046
- return parseMessage(row);
2218
+ const row = stmt.get(sessionId, opts.from, opts.to, opts.space || null, opts.content, normalizedPriority, opts.working_dir || null, opts.repository || null, opts.branch || null, metadata, blocking, replyTo);
2219
+ const message = parseMessage(row);
2220
+ if (opts.attachments && opts.attachments.length > 0) {
2221
+ const attachmentsDir = join3(getAttachmentsDir(), String(message.id));
2222
+ mkdirSync2(attachmentsDir, { recursive: true });
2223
+ const attachmentInfos = [];
2224
+ for (const att of opts.attachments) {
2225
+ const destPath = join3(attachmentsDir, att.name);
2226
+ copyFileSync(att.source_path, destPath);
2227
+ const stat = statSync(destPath);
2228
+ attachmentInfos.push({
2229
+ name: att.name,
2230
+ path: destPath,
2231
+ size: stat.size,
2232
+ mime_type: guessMimeType(att.name)
2233
+ });
2234
+ }
2235
+ const attachmentsJson = JSON.stringify(attachmentInfos);
2236
+ db2.prepare("UPDATE messages SET attachments = ? WHERE id = ?").run(attachmentsJson, message.id);
2237
+ message.attachments = attachmentInfos;
2238
+ }
2239
+ fireWebhooks(message);
2240
+ return message;
2047
2241
  }
2048
2242
  function readMessages(opts = {}) {
2049
2243
  const db2 = getDb();
@@ -2077,10 +2271,13 @@ function readMessages(opts = {}) {
2077
2271
  conditions.push("read_at IS NULL");
2078
2272
  }
2079
2273
  const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
2080
- const limit = Number.isFinite(opts.limit) && opts.limit > 0 ? `LIMIT ${Math.floor(opts.limit)}` : "";
2274
+ const resolvedLimit = Number.isFinite(opts.limit) && opts.limit > 0 ? Math.floor(opts.limit) : 20;
2081
2275
  const order = opts.order?.toLowerCase() === "desc" ? "DESC" : "ASC";
2082
- const rows = db2.prepare(`SELECT * FROM messages ${where} ORDER BY created_at ${order}, id ${order} ${limit}`).all(...params);
2083
- return rows.map(parseMessage);
2276
+ const rows = db2.prepare(`SELECT * FROM messages ${where} ORDER BY created_at ${order}, id ${order} LIMIT ${resolvedLimit}`).all(...params);
2277
+ const messages = rows.map(parseMessage);
2278
+ if (opts.compact)
2279
+ return messages.map(compactMessage);
2280
+ return messages;
2084
2281
  }
2085
2282
  function markRead(ids, reader) {
2086
2283
  const db2 = getDb();
@@ -2224,8 +2421,40 @@ function getUnreadBlockers(agent) {
2224
2421
  `).all(agent, agent);
2225
2422
  return rows.map(parseMessage);
2226
2423
  }
2424
+ function getThreadReplies(messageId) {
2425
+ const db2 = getDb();
2426
+ const rows = db2.prepare("SELECT * FROM messages WHERE reply_to = ? ORDER BY created_at ASC, id ASC").all(messageId);
2427
+ return rows.map(parseMessage);
2428
+ }
2227
2429
  function searchMessages(opts) {
2228
2430
  const db2 = getDb();
2431
+ const limit = Number.isFinite(opts.limit) && opts.limit > 0 ? Math.floor(opts.limit) : 20;
2432
+ try {
2433
+ const ftsConditions = [];
2434
+ const ftsParams = [];
2435
+ const words = opts.query.trim().split(/\s+/).filter(Boolean);
2436
+ const ftsQuery = words.map((w) => `"${w.replace(/"/g, '""')}"`).join(" ");
2437
+ ftsConditions.push("messages_fts MATCH ?");
2438
+ ftsParams.push(ftsQuery);
2439
+ let extraWhere = "";
2440
+ if (opts.space) {
2441
+ extraWhere += " AND m.space = ?";
2442
+ ftsParams.push(opts.space);
2443
+ }
2444
+ if (opts.from) {
2445
+ extraWhere += " AND m.from_agent = ?";
2446
+ ftsParams.push(opts.from);
2447
+ }
2448
+ if (opts.to) {
2449
+ extraWhere += " AND m.to_agent = ?";
2450
+ ftsParams.push(opts.to);
2451
+ }
2452
+ const rows2 = db2.prepare(`SELECT m.* FROM messages m
2453
+ JOIN messages_fts ON messages_fts.rowid = m.id
2454
+ WHERE ${ftsConditions.join(" AND ")}${extraWhere}
2455
+ ORDER BY m.created_at DESC, m.id DESC LIMIT ${limit}`).all(...ftsParams);
2456
+ return rows2.map(parseMessage);
2457
+ } catch {}
2229
2458
  const conditions = ["content LIKE ?"];
2230
2459
  const params = [`%${opts.query}%`];
2231
2460
  if (opts.space) {
@@ -2240,7 +2469,6 @@ function searchMessages(opts) {
2240
2469
  conditions.push("to_agent = ?");
2241
2470
  params.push(opts.to);
2242
2471
  }
2243
- const limit = Number.isFinite(opts.limit) && opts.limit > 0 ? Math.floor(opts.limit) : 50;
2244
2472
  const where = `WHERE ${conditions.join(" AND ")}`;
2245
2473
  const rows = db2.prepare(`SELECT * FROM messages ${where} ORDER BY created_at DESC, id DESC LIMIT ${limit}`).all(...params);
2246
2474
  return rows.map(parseMessage);
@@ -2720,9 +2948,9 @@ function useSpaceMessages(spaceName) {
2720
2948
  return messages;
2721
2949
  }
2722
2950
  // src/lib/identity.ts
2723
- import { readFileSync, writeFileSync, mkdirSync as mkdirSync2 } from "fs";
2724
- import { join as join2, dirname as dirname2 } from "path";
2725
- import { homedir as homedir2 } from "os";
2951
+ import { readFileSync as readFileSync2, writeFileSync, mkdirSync as mkdirSync3 } from "fs";
2952
+ import { join as join4, dirname as dirname2 } from "path";
2953
+ import { homedir as homedir4 } from "os";
2726
2954
 
2727
2955
  // src/lib/names.ts
2728
2956
  var AGENT_NAMES = [
@@ -3074,7 +3302,7 @@ var AGENT_NAMES = [
3074
3302
  ];
3075
3303
 
3076
3304
  // src/lib/identity.ts
3077
- var AGENT_ID_FILE = join2(homedir2(), ".conversations", "agent-id");
3305
+ var AGENT_ID_FILE = join4(homedir4(), ".conversations", "agent-id");
3078
3306
  var cachedAutoName = null;
3079
3307
  function isNameTaken(name) {
3080
3308
  try {
@@ -3090,7 +3318,7 @@ function getAutoName() {
3090
3318
  if (cachedAutoName)
3091
3319
  return cachedAutoName;
3092
3320
  try {
3093
- const name2 = readFileSync(AGENT_ID_FILE, "utf-8").trim();
3321
+ const name2 = readFileSync2(AGENT_ID_FILE, "utf-8").trim();
3094
3322
  if (name2) {
3095
3323
  cachedAutoName = name2;
3096
3324
  return name2;
@@ -3106,7 +3334,7 @@ function getAutoName() {
3106
3334
  }
3107
3335
  cachedAutoName = name;
3108
3336
  try {
3109
- mkdirSync2(dirname2(AGENT_ID_FILE), { recursive: true });
3337
+ mkdirSync3(dirname2(AGENT_ID_FILE), { recursive: true });
3110
3338
  writeFileSync(AGENT_ID_FILE, name + `
3111
3339
  `, "utf-8");
3112
3340
  } catch {}
@@ -3130,6 +3358,45 @@ function requireIdentity(explicit) {
3130
3358
  return envValue;
3131
3359
  throw new Error("Agent identity required. Set CONVERSATIONS_AGENT_ID env var or pass --from flag.");
3132
3360
  }
3361
+ // src/lib/reactions.ts
3362
+ init_db();
3363
+ function addReaction(messageId, agent, emoji) {
3364
+ const db2 = getDb();
3365
+ const stmt = db2.prepare(`
3366
+ INSERT INTO reactions (message_id, agent, emoji)
3367
+ VALUES (?, ?, ?)
3368
+ ON CONFLICT (message_id, agent, emoji) DO UPDATE SET agent = agent
3369
+ RETURNING *
3370
+ `);
3371
+ const row = stmt.get(messageId, agent, emoji);
3372
+ return row;
3373
+ }
3374
+ function removeReaction(messageId, agent, emoji) {
3375
+ const db2 = getDb();
3376
+ const stmt = db2.prepare("DELETE FROM reactions WHERE message_id = ? AND agent = ? AND emoji = ?");
3377
+ const result = stmt.run(messageId, agent, emoji);
3378
+ return result.changes > 0;
3379
+ }
3380
+ function getReactions(messageId) {
3381
+ const db2 = getDb();
3382
+ const rows = db2.prepare("SELECT * FROM reactions WHERE message_id = ? ORDER BY created_at ASC, id ASC").all(messageId);
3383
+ return rows;
3384
+ }
3385
+ function getReactionSummary(messageId) {
3386
+ const db2 = getDb();
3387
+ const rows = db2.prepare(`
3388
+ SELECT emoji, GROUP_CONCAT(agent) as agents, COUNT(*) as count
3389
+ FROM reactions
3390
+ WHERE message_id = ?
3391
+ GROUP BY emoji
3392
+ ORDER BY count DESC, MIN(created_at) ASC
3393
+ `).all(messageId);
3394
+ return rows.map((row) => ({
3395
+ emoji: row.emoji,
3396
+ count: row.count,
3397
+ agents: row.agents.split(",")
3398
+ }));
3399
+ }
3133
3400
  // src/lib/presence.ts
3134
3401
  init_db();
3135
3402
  var ONLINE_THRESHOLD_SECONDS = 60;
@@ -3211,6 +3478,7 @@ export {
3211
3478
  resolveIdentity,
3212
3479
  requireIdentity,
3213
3480
  renameAgent,
3481
+ removeReaction,
3214
3482
  removePresence,
3215
3483
  readMessages,
3216
3484
  pinMessage,
@@ -3227,10 +3495,13 @@ export {
3227
3495
  isSpaceMember,
3228
3496
  heartbeat,
3229
3497
  getUnreadBlockers,
3498
+ getThreadReplies,
3230
3499
  getSpaceMembers,
3231
3500
  getSpaceDepth,
3232
3501
  getSpace,
3233
3502
  getSession,
3503
+ getReactions,
3504
+ getReactionSummary,
3234
3505
  getProjectByName,
3235
3506
  getProject,
3236
3507
  getPresence,
@@ -3238,6 +3509,7 @@ export {
3238
3509
  getMessageById,
3239
3510
  getDbPath,
3240
3511
  getDb,
3512
+ fireWebhooks,
3241
3513
  exportMessages,
3242
3514
  editMessage,
3243
3515
  deleteProject,
@@ -3245,5 +3517,6 @@ export {
3245
3517
  createSpace,
3246
3518
  createProject,
3247
3519
  closeDb,
3248
- archiveSpace
3520
+ archiveSpace,
3521
+ addReaction
3249
3522
  };
@@ -1,4 +1,6 @@
1
1
  import type { Message, SendMessageOptions, ReadMessagesOptions, SearchMessagesOptions } from "../types.js";
2
+ /** Strip null/undefined fields from a message for compact output. */
3
+ export declare function compactMessage(msg: Message): Partial<Message>;
2
4
  export declare function sendMessage(opts: SendMessageOptions): Message;
3
5
  export declare function readMessages(opts?: ReadMessagesOptions): Message[];
4
6
  export declare function markRead(ids: number[], reader: string): number;
@@ -25,4 +27,5 @@ export declare function getPinnedMessages(opts?: {
25
27
  limit?: number;
26
28
  }): Message[];
27
29
  export declare function getUnreadBlockers(agent: string): Message[];
30
+ export declare function getThreadReplies(messageId: number): Message[];
28
31
  export declare function searchMessages(opts: SearchMessagesOptions): Message[];
@@ -0,0 +1,10 @@
1
+ import type { Reaction } from "../types.js";
2
+ export declare function addReaction(messageId: number, agent: string, emoji: string): Reaction;
3
+ export declare function removeReaction(messageId: number, agent: string, emoji: string): boolean;
4
+ export declare function getReactions(messageId: number): Reaction[];
5
+ export interface ReactionSummary {
6
+ emoji: string;
7
+ count: number;
8
+ agents: string[];
9
+ }
10
+ export declare function getReactionSummary(messageId: number): ReactionSummary[];
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Render inline markdown formatting for terminal output.
3
+ * Handles: inline code, bold+italic, bold, italic, strikethrough.
4
+ */
5
+ export declare const renderInline: (text: string) => string;
6
+ /**
7
+ * Render markdown content for terminal output.
8
+ * Handles: headings, bullet lists, ordered lists, blockquotes,
9
+ * code block markers, inline formatting.
10
+ */
11
+ export declare const renderContent: (content: string) => string;
@@ -0,0 +1,11 @@
1
+ import type { Message } from "../types.js";
2
+ export interface WebhookConfig {
3
+ url: string;
4
+ events: ("dm" | "blocker" | "space" | "mention")[];
5
+ agent?: string;
6
+ }
7
+ /**
8
+ * Fire webhooks for a message. Runs async, never blocks sendMessage.
9
+ * Matches webhooks by event type and optionally by agent (to_agent).
10
+ */
11
+ export declare function fireWebhooks(msg: Message): void;
@@ -0,0 +1 @@
1
+ export {};
package/dist/types.d.ts CHANGED
@@ -16,6 +16,21 @@ export interface Message {
16
16
  edited_at: string | null;
17
17
  pinned_at: string | null;
18
18
  blocking: boolean;
19
+ attachments: Attachment[] | null;
20
+ reply_to: number | null;
21
+ }
22
+ export interface Reaction {
23
+ id: number;
24
+ message_id: number;
25
+ agent: string;
26
+ emoji: string;
27
+ created_at: string;
28
+ }
29
+ export interface Attachment {
30
+ name: string;
31
+ path: string;
32
+ size: number;
33
+ mime_type: string;
19
34
  }
20
35
  export interface Session {
21
36
  session_id: string;
@@ -71,6 +86,11 @@ export interface SendMessageOptions {
71
86
  branch?: string;
72
87
  metadata?: Record<string, unknown>;
73
88
  blocking?: boolean;
89
+ attachments?: {
90
+ name: string;
91
+ source_path: string;
92
+ }[];
93
+ reply_to?: number;
74
94
  }
75
95
  export interface ReadMessagesOptions {
76
96
  session_id?: string;
@@ -82,6 +102,7 @@ export interface ReadMessagesOptions {
82
102
  limit?: number;
83
103
  unread_only?: boolean;
84
104
  order?: "asc" | "desc";
105
+ compact?: boolean;
85
106
  }
86
107
  export interface SearchMessagesOptions {
87
108
  query: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/conversations",
3
- "version": "0.1.17",
3
+ "version": "0.1.19",
4
4
  "description": "Real-time CLI messaging for AI agents",
5
5
  "type": "module",
6
6
  "bin": {