@buoy-gg/ask-buoy 7.0.78 → 7.0.80
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.
- package/lib/commonjs/blocks/ExtraBlocks.js +1 -1
- package/lib/commonjs/blocks/choiceLogic.js +1 -0
- package/lib/commonjs/blocks/choiceLogic.test.js +1 -0
- package/lib/commonjs/components/AskBuoyModal.js +1 -1
- package/lib/commonjs/components/EmptyState.js +1 -1
- package/lib/commonjs/components/sheetText.test.js +1 -0
- package/lib/commonjs/store/askBuoyStore.js +2 -2
- package/lib/commonjs/store/transcriptPersistence.js +1 -1
- package/lib/commonjs/store/transcriptPersistence.test.js +1 -1
- package/lib/commonjs/store/useAskBuoy.js +1 -1
- package/lib/module/blocks/ExtraBlocks.js +1 -1
- package/lib/module/blocks/choiceLogic.js +1 -0
- package/lib/module/blocks/choiceLogic.test.js +1 -0
- package/lib/module/components/AskBuoyModal.js +1 -1
- package/lib/module/components/EmptyState.js +1 -1
- package/lib/module/components/sheetText.test.js +1 -0
- package/lib/module/store/askBuoyStore.js +1 -1
- package/lib/module/store/transcriptPersistence.js +1 -1
- package/lib/module/store/transcriptPersistence.test.js +1 -1
- package/lib/module/store/useAskBuoy.js +1 -1
- package/lib/typescript/blocks/choiceLogic.d.ts +41 -0
- package/lib/typescript/blocks/choiceLogic.test.d.ts +2 -0
- package/lib/typescript/components/sheetText.test.d.ts +2 -0
- package/lib/typescript/store/askBuoyStore.d.ts +6 -0
- package/lib/typescript/store/transcriptPersistence.d.ts +14 -0
- package/lib/typescript/sync/wire.d.ts +8 -6
- package/lib/web/index.mjs +11 -11
- package/package.json +7 -7
- package/lib/commonjs/blocks/AskBlocks.test.js +0 -1
- package/lib/commonjs/components/Composer.test.js +0 -1
- package/lib/commonjs/components/EmptyState.test.js +0 -1
- package/lib/module/blocks/AskBlocks.test.js +0 -1
- package/lib/module/components/Composer.test.js +0 -1
- package/lib/module/components/EmptyState.test.js +0 -1
- package/lib/typescript/blocks/AskBlocks.test.d.ts +0 -2
- package/lib/typescript/components/Composer.test.d.ts +0 -2
- package/lib/typescript/components/EmptyState.test.d.ts +0 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.Banner=Banner;exports.CardCarousel=CardCarousel;exports.CardView=CardView;exports.Checkpoint=Checkpoint;exports.Claim=Claim;exports.Compare=Compare;exports.DateTime=DateTime;exports.Details=Details;exports.File=File;exports.Form=Form;exports.LivePill=LivePill;exports.MultiSelect=MultiSelect;exports.Plan=Plan;exports.Proposal=Proposal;exports.Screenshot=Screenshot;exports.Select=Select;exports.Slider=Slider;exports.Sparkline=Sparkline;exports.Suggestions=Suggestions;exports.Tabs=Tabs;exports.Task=Task;exports.Timeline=Timeline;exports.Upload=Upload;var _sharedUi=require("@buoy-gg/shared-ui");var _reactNative=require("react-native");var _react=require("react");var _context=require("./context");var _primitives=require("./primitives");var _jsxRuntime=require("react/jsx-runtime");const fmt=e=>typeof e==="string"?e:e===void 0?"\u2014":JSON.stringify(e);function Suggestions({block:e}){const i=(0,_context.useBlockHandlers)();return(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.chips,testID:`buoy-block-suggestions-${e.id}`,children:e.chips.slice(0,4).map(t=>(0,_jsxRuntime.jsx)(_reactNative.Pressable,{disabled:!!i.busy,onPress:()=>void i.runAction({label:t.label,send:t.send??t.label},e.id),style:({pressed:n})=>[styles.chip,n&&styles.pressed],accessibilityRole:"button",children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.chipText,children:t.label})},t.label))})}function MultiSelect({block:e}){const i=(0,_context.useBlockHandlers)();const t=i.answered[e.id];const n=!!t;const[o,l]=(0,_react.useState)([]);const r=t?.kind==="multi"?t.optionIds:o;const d=a=>l(s=>s.includes(a)?s.filter(c=>c!==a):[...s,a]);const h=o.length>=(e.min??1)&&(!e.max||o.length<=e.max);return(0,_jsxRuntime.jsxs)(_primitives.Card,{testID:`buoy-block-multi-${e.id}`,tone:n?void 0:"info",children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.question,children:e.question}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.optionsBox,children:e.options.map((a,s)=>{const c=r.includes(a.id);return(0,_jsxRuntime.jsxs)(_reactNative.Pressable,{disabled:n,onPress:()=>d(a.id),style:[styles.option,s>0&&_primitives.blockStyles.rowDivider,n&&!c&&styles.dim],accessibilityRole:"checkbox",accessibilityState:{checked:c},children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.checkbox,c&&styles.checkboxOn],children:c?(0,_jsxRuntime.jsx)(_sharedUi.Check,{size:11,color:_sharedUi.night.color.onAccent}):null}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.flex,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.optionLabel,children:a.label}),a.detail?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.optionDetail,children:a.detail}):null]})]},a.id)})}),n?null:(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.rowEnd,children:(0,_jsxRuntime.jsx)(_reactNative.Pressable,{testID:"buoy-block-multi-submit",disabled:!h,onPress:()=>i.answer({blockId:e.id,kind:"multi",optionIds:o,labels:e.options.filter(a=>o.includes(a.id)).map(a=>a.label)}),style:[styles.button,styles.buttonPrimary,!h&&styles.disabled],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.buttonTextPrimary,children:e.submitLabel??`Use ${o.length||""}`.trim()})})})]})}const SEARCH_FROM=8;function Select({block:e}){const i=(0,_context.useBlockHandlers)();const t=i.answered[e.id];const[n,o]=(0,_react.useState)("");const[l,r]=(0,_react.useState)(false);const d=t?.kind==="select"?t.label:null;const h=e.options.filter(s=>!n||s.label.toLowerCase().includes(n.toLowerCase())).slice(0,8);const a=e.searchable!==false&&e.options.length>=SEARCH_FROM;return(0,_jsxRuntime.jsxs)(_primitives.Card,{testID:`buoy-block-select-${e.id}`,tone:t?void 0:"info",children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.question,children:e.label}),d?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.decided,children:d}):(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.selectBox,children:[(0,_jsxRuntime.jsxs)(_reactNative.Pressable,{onPress:()=>r(s=>!s),style:styles.selectField,accessibilityRole:"button",children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.selectPlaceholder,children:l?"Choose\u2026":`${e.options.length} options`}),(0,_jsxRuntime.jsx)(_sharedUi.ChevronDown,{size:14,color:_sharedUi.night.color.textSecondary})]}),l&&(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[a&&(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.search,children:[(0,_jsxRuntime.jsx)(_sharedUi.Search,{size:12,color:_sharedUi.night.color.textSecondary}),(0,_jsxRuntime.jsx)(_reactNative.TextInput,{style:styles.searchInput,value:n,onChangeText:o,placeholder:"Search",placeholderTextColor:_sharedUi.night.color.placeholder,autoCapitalize:"none",autoCorrect:false})]}),h.map((s,c)=>(0,_jsxRuntime.jsxs)(_reactNative.Pressable,{onPress:()=>i.answer({blockId:e.id,kind:"select",optionId:s.id,label:s.label}),style:[styles.option,c>0&&_primitives.blockStyles.rowDivider],accessibilityRole:"button",children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.flex,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.optionLabel,children:s.label}),s.detail?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.optionDetail,children:s.detail}):null]}),(0,_jsxRuntime.jsx)(_sharedUi.ChevronRight,{size:12,color:_sharedUi.night.color.textTertiary})]},s.id)),e.options.length>h.length?(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.hint,children:[e.options.length-h.length," more \u2014 keep typing"]}):null]})]})]})}function SliderControl({min:e,max:i,step:t=1,value:n,unit:o,onChange:l,disabled:r}){const d=(0,_react.useRef)(0);const h=i>e?(n-e)/(i-e)*100:0;const a=g=>Math.min(i,Math.max(e,+(Math.round((g-e)/t)*t+e).toFixed(6)));const s=g=>!r&&l(a(n+g*t));const c=g=>{if(r||d.current<=0)return;const x=Math.min(1,Math.max(0,g.nativeEvent.locationX/d.current));l(a(e+x*(i-e)))};const u=g=>{d.current=g.nativeEvent.layout.width};return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.sliderRow,children:[(0,_jsxRuntime.jsx)(_reactNative.Pressable,{disabled:r,onPress:()=>s(-1),style:styles.stepBtn,accessibilityRole:"button",accessibilityLabel:"Decrease",children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.stepText,children:"\u2212"})}),(0,_jsxRuntime.jsx)(_reactNative.Pressable,{style:styles.trackHit,onLayout:u,onPress:c,disabled:r,accessibilityRole:"adjustable",accessibilityValue:{min:e,max:i,now:n},accessibilityActions:[{name:"increment"},{name:"decrement"}],onAccessibilityAction:g=>s(g.nativeEvent.actionName==="increment"?1:-1),children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.track,pointerEvents:"none",children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.fill,{width:`${h}%`}]}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.thumb,{left:`${h}%`}]})]})}),(0,_jsxRuntime.jsx)(_reactNative.Pressable,{disabled:r,onPress:()=>s(1),style:styles.stepBtn,accessibilityRole:"button",accessibilityLabel:"Increase",children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.stepText,children:"+"})}),(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.sliderValue,children:[n,o?` ${o}`:""]})]})}function Slider({block:e}){const i=(0,_context.useBlockHandlers)();const t=i.answered[e.id];const[n,o]=(0,_react.useState)(e.value??e.min);return(0,_jsxRuntime.jsxs)(_primitives.Card,{testID:`buoy-block-slider-${e.id}`,tone:t?void 0:"info",children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.question,children:e.label}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.pad,children:(0,_jsxRuntime.jsx)(SliderControl,{min:e.min,max:e.max,step:e.step,value:t?.kind==="slider"?t.value:n,unit:e.unit,onChange:o,disabled:!!t})}),t?null:(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.rowEnd,children:(0,_jsxRuntime.jsx)(_reactNative.Pressable,{onPress:()=>i.answer({blockId:e.id,kind:"slider",value:n,unit:e.unit}),style:[styles.button,styles.buttonPrimary],children:(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.buttonTextPrimary,children:["Use ",n,e.unit?` ${e.unit}`:""]})})})]})}function DateTime({block:e}){const i=(0,_context.useBlockHandlers)();const t=i.answered[e.id];const[n,o]=(0,_react.useState)("");const l=e.presets??[{label:"Now",value:new Date().toISOString()},{label:"Tomorrow",value:new Date(Date.now()+864e5).toISOString()},{label:"+7 days",value:new Date(Date.now()+7*864e5).toISOString()},{label:"+30 days",value:new Date(Date.now()+30*864e5).toISOString()}];return(0,_jsxRuntime.jsxs)(_primitives.Card,{testID:`buoy-block-datetime-${e.id}`,tone:t?void 0:"info",children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.question,children:e.label}),t?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.decided,children:t.kind==="dateTime"?t.label??t.value:"(skipped)"}):(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.chips,styles.pad],children:l.map(r=>(0,_jsxRuntime.jsx)(_reactNative.Pressable,{onPress:()=>i.answer({blockId:e.id,kind:"dateTime",value:r.value,label:r.label}),style:styles.chip,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.chipText,children:r.label})},r.label))}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:[styles.inputRow,styles.pad],children:[(0,_jsxRuntime.jsx)(_reactNative.TextInput,{style:styles.input,value:n,onChangeText:o,placeholder:e.mode==="time"?"14:30":"2026-09-15",placeholderTextColor:_sharedUi.night.color.placeholder,keyboardType:"numbers-and-punctuation"}),(0,_jsxRuntime.jsx)(_reactNative.Pressable,{disabled:!n.trim(),onPress:()=>i.answer({blockId:e.id,kind:"dateTime",value:n.trim()}),style:[styles.button,styles.buttonPrimary,!n.trim()&&styles.disabled],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.buttonTextPrimary,children:"Use"})})]})]})]})}function FieldRow({f:e,value:i,onChange:t,disabled:n}){if(e.type==="toggle"){return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.fieldRow,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.fieldLabel,children:e.label}),(0,_jsxRuntime.jsx)(_reactNative.Switch,{value:!!i,onValueChange:t,disabled:n,trackColor:{true:_sharedUi.night.color.accent,false:_sharedUi.night.color.fillTertiary},thumbColor:_sharedUi.night.color.knob})]})}if(e.type==="select"){return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.fieldCol,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.fieldLabel,children:e.label}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.chips,children:e.options.map(o=>(0,_jsxRuntime.jsx)(_reactNative.Pressable,{disabled:n,onPress:()=>t(o.id),style:[styles.chip,i===o.id&&styles.chipOn],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.chipText,i===o.id&&styles.chipTextOn],children:o.label})},o.id))})]})}if(e.type==="slider"){return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.fieldCol,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.fieldLabel,children:e.label}),(0,_jsxRuntime.jsx)(SliderControl,{min:e.min,max:e.max,step:e.step,unit:e.unit,value:typeof i==="number"?i:e.min,onChange:t,disabled:n})]})}return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.fieldRow,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.fieldLabel,children:e.label}),(0,_jsxRuntime.jsx)(_reactNative.TextInput,{style:styles.fieldInput,value:i===void 0||i===null?"":String(i),onChangeText:t,editable:!n,placeholder:e.placeholder??"",placeholderTextColor:_sharedUi.night.color.placeholder,keyboardType:e.type==="number"?"numeric":"ascii-capable",secureTextEntry:e.type==="secret",autoCapitalize:"none",autoCorrect:false})]})}function useFormValues(e){const[i,t]=(0,_react.useState)(()=>Object.fromEntries(e.map(n=>[n.key,n.value])));return{values:i,set:(n,o)=>t(l=>({...l,[n]:o}))}}function Form({block:e}){const i=(0,_context.useBlockHandlers)();const t=i.answered[e.id];const{values:n,set:o}=useFormValues(e.fields);return(0,_jsxRuntime.jsxs)(_primitives.Card,{title:e.title,testID:`buoy-block-form-${e.id}`,tone:t?void 0:"info",children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.pad,children:e.fields.map(l=>(0,_jsxRuntime.jsx)(FieldRow,{f:l,value:n[l.key],onChange:r=>o(l.key,r),disabled:!!t},l.key))}),t?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.decided,children:"Sent"}):(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.rowEnd,children:(0,_jsxRuntime.jsx)(_reactNative.Pressable,{onPress:()=>i.answer({blockId:e.id,kind:"form",values:n}),style:[styles.button,styles.buttonPrimary],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.buttonTextPrimary,children:e.submitLabel??"Send"})})})]})}function Proposal({block:e}){const i=(0,_context.useBlockHandlers)();const t=i.answered[e.id];const{values:n,set:o}=useFormValues(e.fields);const l=t?.kind==="proposal"?t.approved:null;return(0,_jsxRuntime.jsxs)(_primitives.Card,{testID:`buoy-block-proposal-${e.id}`,tone:t?void 0:"warning",children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.confirmTitle,children:e.title}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.confirmChange,children:e.change}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.pad,children:e.fields.map(r=>(0,_jsxRuntime.jsx)(FieldRow,{f:r,value:n[r.key],onChange:d=>o(r.key,d),disabled:!!t},r.key))}),e.consequence?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.consequence,children:e.consequence}):null,(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.actionsRow,children:t?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.decided,children:l?"\u2713 Applied with these values":"\u2715 Not applied"}):(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(_reactNative.Pressable,{onPress:()=>i.answer({blockId:e.id,kind:"proposal",approved:true,values:n}),style:[styles.button,styles.buttonPrimary],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.buttonTextPrimary,children:e.approveLabel??"Apply"})}),(0,_jsxRuntime.jsx)(_reactNative.Pressable,{onPress:()=>i.answer({blockId:e.id,kind:"proposal",approved:false}),style:[styles.button,styles.buttonPlate],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.buttonTextPlate,children:"Not now"})})]})})]})}function Claim({block:e}){const i=(0,_context.useBlockHandlers)();const[t,n]=(0,_react.useState)(null);const o=i.actionState?.[`${e.id}:${e.verify?.label??"Verify"}`];const l=e.verified||o==="done";return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.claim,testID:`buoy-block-claim-${e.id}`,children:[(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.claimText,children:[e.text,e.sources.map((r,d)=>(0,_jsxRuntime.jsxs)(_reactNative.Text,{onPress:()=>n(t===d?null:d),style:styles.cite,children:[" [",d+1,"]"]},d)),l?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.verified,children:" \u2713 verified"}):null]}),t!==null&&e.sources[t]?(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.citeBox,children:[(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.citeLabel,children:["[",t+1,"] ",e.sources[t].label]}),e.sources[t].detail?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.citeDetail,children:e.sources[t].detail}):null]}):null,e.verify&&!l?(0,_jsxRuntime.jsxs)(_reactNative.Pressable,{onPress:()=>void i.runAction(e.verify,e.id),style:styles.verifyBtn,accessibilityRole:"button",children:[(0,_jsxRuntime.jsx)(_sharedUi.RefreshCw,{size:11,color:_sharedUi.night.color.accent}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.verifyText,children:o==="running"?"Checking\u2026":e.verify.label})]}):null]})}function Details({block:e}){const[i,t]=(0,_react.useState)(!!e.open);return(0,_jsxRuntime.jsxs)(_primitives.Card,{testID:`buoy-block-details-${e.id}`,children:[(0,_jsxRuntime.jsxs)(_reactNative.Pressable,{onPress:()=>t(n=>!n),style:_primitives.blockStyles.row,accessibilityRole:"button",accessibilityState:{expanded:i},children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:_primitives.blockStyles.rowTitle,children:e.summary}),i?(0,_jsxRuntime.jsx)(_sharedUi.ChevronDown,{size:12,color:_sharedUi.night.color.textTertiary}):(0,_jsxRuntime.jsx)(_sharedUi.ChevronRight,{size:12,color:_sharedUi.night.color.textTertiary})]}),i?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.detailsBody,selectable:true,children:e.body}):null]})}function Tabs({block:e,renderNested:i}){const[t,n]=(0,_react.useState)(0);const o=e.tabs.map((r,d)=>({key:String(d),label:r.label}));const l=e.tabs[t];return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.tabsWrap,testID:`buoy-block-tabs-${e.id}`,children:[(0,_jsxRuntime.jsx)(_sharedUi.NightSegmented,{tabs:o,activeKey:String(t),onChange:r=>n(Number(r)),size:"sm"}),l&&i?i(l.block):null]})}const TIMELINE_CAP=10;function Timeline({block:e}){const i=(0,_primitives.usePaged)(e.events,TIMELINE_CAP);return(0,_jsxRuntime.jsxs)(_primitives.Card,{title:e.title??"What happened",source:e.source,testID:`buoy-block-timeline-${e.id}`,children:[i.visible.map((t,n)=>(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.tlRow,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.tlAt,children:t.at}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.tlLine,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.tlDot,{backgroundColor:(0,_primitives.toneColor)(t.tone??"muted")}]}),n<i.visible.length-1?(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.tlStem}):null]}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.flex,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.tlSource,children:t.source.toUpperCase()}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:_primitives.blockStyles.rowTitle,numberOfLines:2,children:t.label})]})]},n)),(0,_jsxRuntime.jsx)(_primitives.More,{paged:i})]})}function Sparkline({block:e}){const i=e.series.slice(-60);const t=Math.max(1,...i);const n=Math.min(...i,0);const o=44;return(0,_jsxRuntime.jsxs)(_primitives.Card,{title:e.title,source:e.source,testID:`buoy-block-sparkline-${e.id}`,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.sparkHead,children:[(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.sparkCurrent,children:[e.current??i[i.length-1],e.unit?(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.sparkUnit,children:[" ",e.unit]}):null]}),e.live?(0,_jsxRuntime.jsx)(LivePill,{}):null]}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.spark,{height:o}],children:i.map((l,r)=>(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.sparkBar,{height:Math.max(2,(l-n)/(t-n||1)*o),backgroundColor:r===i.length-1?_sharedUi.night.color.accent:_sharedUi.night.color.accentBorderStrong}]},r))}),e.label?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.hint,children:e.label}):null]})}function LivePill(){const e=(0,_react.useRef)(new _reactNative.Animated.Value(1)).current;(0,_react.useEffect)(()=>{const i=_reactNative.Animated.loop(_reactNative.Animated.sequence([_reactNative.Animated.timing(e,{toValue:.3,duration:700,useNativeDriver:true}),_reactNative.Animated.timing(e,{toValue:1,duration:700,useNativeDriver:true})]));i.start();return()=>i.stop()},[e]);return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.live,children:[(0,_jsxRuntime.jsx)(_reactNative.Animated.View,{style:[styles.liveDot,{opacity:e}]}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.liveText,children:"LIVE"})]})}function Compare({block:e}){const i=[...new Set([...e.left.pairs.map(o=>o.key),...e.right.pairs.map(o=>o.key)])];const t=Object.fromEntries(e.left.pairs.map(o=>[o.key,o.value]));const n=Object.fromEntries(e.right.pairs.map(o=>[o.key,o.value]));return(0,_jsxRuntime.jsxs)(_primitives.Card,{title:e.title,source:e.source,testID:`buoy-block-compare-${e.id}`,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.cmpHead,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.cmpKey}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.cmpCol,children:e.left.title}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.cmpCol,children:e.right.title})]}),i.map((o,l)=>{const r=JSON.stringify(t[o])!==JSON.stringify(n[o]);return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:[styles.cmpRow,l>0&&_primitives.blockStyles.rowDivider,r&&styles.cmpDiff],children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.cmpKey,numberOfLines:1,children:o}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.cmpVal,r&&{color:_sharedUi.night.color.danger}],numberOfLines:2,children:fmt(t[o])}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.cmpVal,r&&{color:_sharedUi.night.color.accent}],numberOfLines:2,children:fmt(n[o])})]},o)})]})}function CardBody({c:e,id:i}){return(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[e.image?(0,_jsxRuntime.jsx)(_reactNative.Image,{testID:"buoy-internal-chat-image",source:{uri:e.image},style:styles.cardImage,resizeMode:"contain",accessibilityLabel:e.title}):null,(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.cardText,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.cardTitle,numberOfLines:2,children:e.title}),e.subtitle?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:_primitives.blockStyles.rowSub,numberOfLines:2,children:e.subtitle}):null,e.facts?.slice(0,4).map(t=>(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.fact,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.factLabel,children:t.label}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.factValue,t.tone&&{color:(0,_primitives.toneColor)(t.tone)}],children:t.value})]},t.label))]}),(0,_jsxRuntime.jsx)(_primitives.ActionRow,{actions:e.actions,blockId:i})]})}function CardView({block:e}){return(0,_jsxRuntime.jsx)(_primitives.Card,{source:e.source,testID:`buoy-block-card-${e.id}`,children:(0,_jsxRuntime.jsx)(CardBody,{c:e,id:e.id})})}function CardCarousel({block:e}){return(0,_jsxRuntime.jsxs)(_reactNative.View,{testID:`buoy-block-cardcarousel-${e.id}`,children:[e.title?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.carouselTitle,children:e.title}):null,(0,_jsxRuntime.jsx)(_reactNative.ScrollView,{horizontal:true,showsHorizontalScrollIndicator:false,snapToInterval:232,decelerationRate:"fast",contentContainerStyle:styles.carousel,children:e.cards.slice(0,8).map((i,t)=>(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.carouselCard,children:(0,_jsxRuntime.jsx)(CardBody,{c:i,id:`${e.id}-${t}`})},`${i.title}-${t}`))})]})}function Screenshot({block:e}){const[i,t]=(0,_react.useState)(false);return(0,_jsxRuntime.jsxs)(_primitives.Card,{title:e.route?`Screen \xB7 ${e.route}`:"Screen",source:e.source,testID:`buoy-block-screenshot-${e.id}`,children:[(0,_jsxRuntime.jsx)(_reactNative.Pressable,{onPress:()=>t(n=>!n),accessibilityRole:"imagebutton",accessibilityLabel:e.caption??"Screenshot",children:(0,_jsxRuntime.jsx)(_reactNative.Image,{testID:"buoy-internal-chat-image",source:{uri:e.url},style:[styles.shot,i&&styles.shotBig],resizeMode:"contain"})}),e.caption?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.hint,children:e.caption}):null]})}function Plan({block:e}){const i=e.steps.filter(t=>t.state==="done").length;return(0,_jsxRuntime.jsxs)(_primitives.Card,{title:e.title,testID:`buoy-block-plan-${e.id}`,tone:e.pending?"info":void 0,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.progress,children:(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.progressFill,{width:`${i/Math.max(1,e.steps.length)*100}%`}]})}),e.steps.map((t,n)=>(0,_jsxRuntime.jsxs)(_reactNative.View,{style:[styles.step,n>0&&_primitives.blockStyles.rowDivider],children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.stepMark,t.state==="done"&&styles.stepDone,t.state==="failed"&&styles.stepFailed,t.state==="running"&&styles.stepRunning],children:t.state==="done"?(0,_jsxRuntime.jsx)(_sharedUi.Check,{size:10,color:_sharedUi.night.color.onAccent}):t.state==="failed"?(0,_jsxRuntime.jsx)(_sharedUi.X,{size:10,color:_sharedUi.night.color.text}):(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.stepNum,children:n+1})}),(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:[_primitives.blockStyles.rowTitle,t.state==="done"&&styles.muted],children:[t.text,t.state==="running"?"\u2026":""]})]},n)),(0,_jsxRuntime.jsx)(_primitives.ActionRow,{actions:e.actions??(e.pending?[{label:"Go",primary:true,send:"Go ahead with the plan."},{label:"Change it",send:"Let me change the plan first."}]:void 0),blockId:e.id})]})}function Checkpoint({block:e}){const i=(0,_context.useBlockHandlers)();return(0,_jsxRuntime.jsxs)(_reactNative.Pressable,{testID:`buoy-block-checkpoint-${e.id}`,disabled:!e.restore,onPress:()=>e.restore&&void i.runAction(e.restore,e.id),style:styles.checkpoint,accessibilityRole:"button",children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.cpFlag}),(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.cpText,children:[e.label,e.at?` \xB7 ${e.at}`:""]}),e.restore?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.cpRestore,children:e.restore.label}):null]})}function Task({block:e}){const i=e.status==="failed"?_sharedUi.night.color.danger:e.status==="done"?_sharedUi.night.color.accent:_sharedUi.night.color.info;return(0,_jsxRuntime.jsxs)(_primitives.Card,{testID:`buoy-block-task-${e.id}`,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.taskHead,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.cardTitle,children:e.title}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:[_primitives.blockStyles.pill,{backgroundColor:`${i}22`}],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[_primitives.blockStyles.pillText,{color:i}],children:e.status.toUpperCase()})})]}),e.progress!==void 0?(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.progress,styles.pad],children:(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.progressFill,{width:`${Math.round(e.progress*100)}%`,backgroundColor:i}]})}):null,e.detail?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.hint,children:e.detail}):null,(0,_jsxRuntime.jsx)(_primitives.ActionRow,{actions:e.actions,blockId:e.id})]})}function Banner({block:e}){const i=e.tone==="danger"?_sharedUi.night.color.danger:e.tone==="warning"?_sharedUi.night.color.warning:_sharedUi.night.color.info;return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:[styles.banner,{borderColor:i,backgroundColor:`${i}1A`}],testID:`buoy-block-banner-${e.id}`,children:[(0,_jsxRuntime.jsx)(_sharedUi.AlertTriangle,{size:13,color:i}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.bannerText,{color:i}],numberOfLines:2,children:e.text}),e.actions?.[0]?(0,_jsxRuntime.jsx)(_primitives.ActionRow,{actions:e.actions.slice(0,1),blockId:e.id,align:"right"}):null]})}function File({block:e}){return(0,_jsxRuntime.jsxs)(_primitives.Card,{testID:`buoy-block-file-${e.id}`,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:_primitives.blockStyles.row,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.fileIcon,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.fileExt,children:(e.type??e.name.split(".").pop()??"file").toUpperCase().slice(0,4)})}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.flex,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:_primitives.blockStyles.rowTitle,numberOfLines:1,children:e.name}),e.size?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:_primitives.blockStyles.rowSub,children:e.size}):null]})]}),(0,_jsxRuntime.jsx)(_primitives.ActionRow,{actions:e.actions,blockId:e.id})]})}function Upload({block:e}){const i=(0,_context.useBlockHandlers)();const t=i.answered[e.id];return(0,_jsxRuntime.jsxs)(_primitives.Card,{testID:`buoy-block-upload-${e.id}`,tone:t?void 0:"info",children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.question,children:e.label}),t?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.decided,children:t.kind==="upload"?`Attached ${t.name}`:"(skipped)"}):(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.rowEnd,{justifyContent:"flex-start"}],children:(0,_jsxRuntime.jsx)(_reactNative.Pressable,{onPress:()=>i.answer({blockId:e.id,kind:"upload",name:"screenshot.png"}),style:[styles.button,styles.buttonPlate],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.buttonTextPlate,children:e.accept==="image"?"Choose a screenshot":"Choose a file"})})})]})}const styles=_reactNative.StyleSheet.create({flex:{flex:1},pad:{paddingHorizontal:12,paddingBottom:8},muted:{color:_sharedUi.night.color.textSecondary},dim:{opacity:.45},disabled:{opacity:.5},pressed:{opacity:.7},question:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.row,fontWeight:"600",lineHeight:20,paddingHorizontal:12,paddingTop:12,paddingBottom:8},hint:{color:_sharedUi.night.color.textTertiary,fontSize:_sharedUi.night.font.micro,paddingHorizontal:12,paddingBottom:10},decided:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption,fontWeight:"600",paddingHorizontal:12,paddingVertical:10},rowEnd:{flexDirection:"row",justifyContent:"flex-end",paddingHorizontal:12,paddingBottom:12,gap:8},actionsRow:{flexDirection:"row",gap:8,paddingHorizontal:12,paddingVertical:12,alignItems:"center"},button:{paddingHorizontal:14,paddingVertical:9,borderRadius:_sharedUi.night.radius.row},buttonPrimary:{backgroundColor:_sharedUi.night.color.accent},buttonPlate:{backgroundColor:_sharedUi.night.color.button},buttonTextPrimary:{color:_sharedUi.night.color.onAccent,fontSize:_sharedUi.night.font.caption,fontWeight:"600"},buttonTextPlate:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.caption,fontWeight:"600"},chips:{flexDirection:"row",flexWrap:"wrap",gap:6},chip:{paddingHorizontal:12,paddingVertical:7,borderRadius:_sharedUi.night.radius.chip,backgroundColor:_sharedUi.night.color.fill,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.border},chipOn:{backgroundColor:_sharedUi.night.color.accentSoft,borderColor:_sharedUi.night.color.accentBorderStrong},chipText:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.caption},chipTextOn:{color:_sharedUi.night.color.accent,fontWeight:"600"},optionsBox:{marginHorizontal:8,marginBottom:8,borderRadius:_sharedUi.night.radius.row,backgroundColor:_sharedUi.night.color.surfaceElevated,overflow:"hidden"},option:{flexDirection:"row",alignItems:"center",gap:10,paddingHorizontal:12,paddingVertical:10},optionLabel:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.body,fontWeight:"500"},optionDetail:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption},checkbox:{width:20,height:20,borderRadius:6,borderWidth:1.5,borderColor:_sharedUi.night.color.textTertiary,alignItems:"center",justifyContent:"center"},checkboxOn:{backgroundColor:_sharedUi.night.color.accent,borderColor:_sharedUi.night.color.accent},selectBox:{marginHorizontal:12,marginBottom:12,borderRadius:_sharedUi.night.radius.row,backgroundColor:_sharedUi.night.color.surfaceElevated,overflow:"hidden"},selectField:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",paddingHorizontal:12,paddingVertical:11},selectPlaceholder:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.body},search:{flexDirection:"row",alignItems:"center",gap:6,paddingHorizontal:12,paddingVertical:6,borderTopWidth:_reactNative.StyleSheet.hairlineWidth,borderTopColor:_sharedUi.night.color.separator},searchInput:{flex:1,color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.caption,paddingVertical:4},sliderRow:{flexDirection:"row",alignItems:"center",gap:8},stepBtn:{width:28,height:28,borderRadius:14,backgroundColor:_sharedUi.night.color.fill,alignItems:"center",justifyContent:"center"},stepText:{color:_sharedUi.night.color.text,fontSize:16,fontWeight:"600"},trackHit:{flex:1,height:36,justifyContent:"center"},track:{height:6,borderRadius:3,backgroundColor:_sharedUi.night.color.fillTertiary,justifyContent:"center"},fill:{height:6,borderRadius:3,backgroundColor:_sharedUi.night.color.accent},thumb:{position:"absolute",width:20,height:20,borderRadius:10,backgroundColor:_sharedUi.night.color.knob,marginLeft:-10,shadowColor:"#000",shadowOpacity:.35,shadowRadius:3,shadowOffset:{width:0,height:1}},sliderValue:{width:64,textAlign:"right",color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.caption,fontWeight:"600"},inputRow:{flexDirection:"row",alignItems:"center",gap:8,paddingBottom:12},input:{flex:1,height:38,paddingHorizontal:12,borderRadius:_sharedUi.night.radius.row,backgroundColor:_sharedUi.night.color.surfaceElevated,color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.body},fieldRow:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",gap:10,paddingVertical:6},fieldCol:{paddingVertical:6,gap:6},fieldLabel:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption,width:110},fieldInput:{flex:1,height:34,paddingHorizontal:10,borderRadius:_sharedUi.night.radius.segment,backgroundColor:_sharedUi.night.color.surfaceElevated,color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.caption},confirmTitle:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.row,fontWeight:"600",paddingHorizontal:12,paddingTop:12},confirmChange:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.body,lineHeight:19,paddingHorizontal:12,paddingTop:6,paddingBottom:6},consequence:{color:_sharedUi.night.color.warning,fontSize:_sharedUi.night.font.caption,paddingHorizontal:12},claim:{gap:6,paddingHorizontal:2},claimText:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.row,lineHeight:22},cite:{color:_sharedUi.night.color.accent,fontSize:_sharedUi.night.font.caption,fontWeight:"700"},verified:{color:_sharedUi.night.color.accent,fontSize:_sharedUi.night.font.caption,fontWeight:"600"},citeBox:{padding:10,borderRadius:_sharedUi.night.radius.row,backgroundColor:_sharedUi.night.color.surface,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.border,gap:2},citeLabel:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.caption,fontWeight:"600"},citeDetail:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption,fontFamily:_reactNative.Platform.OS==="web"?_sharedUi.monoFont:"Menlo"},verifyBtn:{alignSelf:"flex-start",flexDirection:"row",alignItems:"center",gap:5,paddingHorizontal:10,paddingVertical:5,borderRadius:_sharedUi.night.radius.chip,backgroundColor:_sharedUi.night.color.accentSoft},verifyText:{color:_sharedUi.night.color.accent,fontSize:_sharedUi.night.font.micro,fontWeight:"700"},detailsBody:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption,lineHeight:18,paddingHorizontal:12,paddingBottom:12},tabsWrap:{gap:8},tabBar:{flexDirection:"row",gap:6},tab:{paddingHorizontal:12,paddingVertical:6,borderRadius:_sharedUi.night.radius.badge,backgroundColor:_sharedUi.night.color.fill},tabOn:{backgroundColor:_sharedUi.night.color.accentSoft},tabText:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption,fontWeight:"600"},tabTextOn:{color:_sharedUi.night.color.accent},tlRow:{flexDirection:"row",gap:10,paddingHorizontal:12,paddingVertical:4,alignItems:"flex-start"},tlAt:{width:46,color:_sharedUi.night.color.textTertiary,fontSize:_sharedUi.night.font.micro,fontFamily:_reactNative.Platform.OS==="web"?_sharedUi.monoFont:"Menlo",paddingTop:3},tlLine:{width:12,alignItems:"center"},tlDot:{width:8,height:8,borderRadius:4,marginTop:5},tlStem:{width:1,flex:1,minHeight:18,backgroundColor:_sharedUi.night.color.separator,marginTop:2},tlSource:{color:_sharedUi.night.color.textTertiary,fontSize:9,fontWeight:"700",letterSpacing:.6},sparkHead:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",paddingHorizontal:12,paddingTop:8},sparkCurrent:{color:_sharedUi.night.color.text,fontSize:22,fontWeight:"700"},sparkUnit:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption,fontWeight:"500"},spark:{flexDirection:"row",alignItems:"flex-end",gap:2,paddingHorizontal:12,paddingTop:6,paddingBottom:6},sparkBar:{flex:1,borderRadius:1},live:{flexDirection:"row",alignItems:"center",gap:5,paddingHorizontal:8,paddingVertical:3,borderRadius:_sharedUi.night.radius.badge,backgroundColor:_sharedUi.night.color.dangerSoft},liveDot:{width:6,height:6,borderRadius:3,backgroundColor:_sharedUi.night.color.danger},liveText:{color:_sharedUi.night.color.danger,fontSize:9,fontWeight:"800",letterSpacing:.8},cmpHead:{flexDirection:"row",paddingHorizontal:12,paddingVertical:6,backgroundColor:_sharedUi.night.color.fill,gap:8},cmpCol:{flex:1,color:_sharedUi.night.color.textTertiary,fontSize:_sharedUi.night.font.micro,fontWeight:"700",letterSpacing:.6,textTransform:"uppercase"},cmpRow:{flexDirection:"row",paddingHorizontal:12,paddingVertical:8,gap:8,alignItems:"flex-start"},cmpDiff:{backgroundColor:_sharedUi.night.color.fill},cmpKey:{width:90,color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption},cmpVal:{flex:1,color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.caption,fontFamily:_reactNative.Platform.OS==="web"?_sharedUi.monoFont:"Menlo"},cardImage:{width:"100%",height:140,backgroundColor:_sharedUi.night.color.fill},cardText:{paddingHorizontal:12,paddingTop:10,paddingBottom:4,gap:4},cardTitle:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.row,fontWeight:"600"},fact:{flexDirection:"row",justifyContent:"space-between",gap:8},factLabel:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption},factValue:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.caption,fontWeight:"500"},carouselTitle:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.caption,fontWeight:"600",paddingBottom:8},carousel:{gap:8,paddingRight:8},carouselCard:{width:224,borderRadius:_sharedUi.night.radius.card,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.border,backgroundColor:_sharedUi.night.color.surface,overflow:"hidden"},shot:{width:"100%",height:220,backgroundColor:_sharedUi.night.color.fill},shotBig:{height:520},progress:{height:4,backgroundColor:_sharedUi.night.color.fill,marginHorizontal:12,marginTop:6,marginBottom:8,borderRadius:2,overflow:"hidden"},progressFill:{height:4,backgroundColor:_sharedUi.night.color.accent},step:{flexDirection:"row",alignItems:"center",gap:10,paddingHorizontal:12,paddingVertical:9},stepMark:{width:20,height:20,borderRadius:10,backgroundColor:_sharedUi.night.color.fillTertiary,alignItems:"center",justifyContent:"center"},stepDone:{backgroundColor:_sharedUi.night.color.accent},stepFailed:{backgroundColor:_sharedUi.night.color.danger},stepRunning:{backgroundColor:_sharedUi.night.color.info},stepNum:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.micro,fontWeight:"700"},checkpoint:{alignSelf:"flex-start",flexDirection:"row",alignItems:"center",gap:8,paddingHorizontal:12,paddingVertical:7,borderRadius:_sharedUi.night.radius.chip,backgroundColor:_sharedUi.night.color.fill},cpFlag:{width:8,height:8,borderRadius:2,backgroundColor:_sharedUi.night.color.info},cpText:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption},cpRestore:{color:_sharedUi.night.color.accent,fontSize:_sharedUi.night.font.caption,fontWeight:"600"},taskHead:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",gap:8,paddingHorizontal:12,paddingTop:12},banner:{flexDirection:"row",alignItems:"center",gap:8,paddingLeft:12,paddingRight:4,paddingVertical:4,borderRadius:_sharedUi.night.radius.row,borderWidth:_reactNative.StyleSheet.hairlineWidth},bannerText:{flex:1,fontSize:_sharedUi.night.font.caption,fontWeight:"600"},fileIcon:{width:40,height:40,borderRadius:8,backgroundColor:_sharedUi.night.color.fill,alignItems:"center",justifyContent:"center"},fileExt:{color:_sharedUi.night.color.textSecondary,fontSize:10,fontWeight:"800"}});
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.Banner=Banner;exports.CardCarousel=CardCarousel;exports.CardView=CardView;exports.Checkpoint=Checkpoint;exports.Claim=Claim;exports.Compare=Compare;exports.DateTime=DateTime;exports.Details=Details;exports.File=File;exports.Form=Form;exports.LivePill=LivePill;exports.MultiSelect=MultiSelect;exports.Plan=Plan;exports.Proposal=Proposal;exports.Screenshot=Screenshot;exports.Select=Select;exports.Slider=Slider;exports.Sparkline=Sparkline;exports.Suggestions=Suggestions;exports.Tabs=Tabs;exports.Task=Task;exports.Timeline=Timeline;exports.Upload=Upload;var _sharedUi=require("@buoy-gg/shared-ui");var _reactNative=require("react-native");var _react=require("react");var _context=require("./context");var _primitives=require("./primitives");var _choiceLogic=require("./choiceLogic");var _jsxRuntime=require("react/jsx-runtime");const fmt=e=>typeof e==="string"?e:e===void 0?"\u2014":JSON.stringify(e);function Suggestions({block:e}){const i=(0,_context.useBlockHandlers)();return(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.chips,testID:`buoy-block-suggestions-${e.id}`,children:e.chips.slice(0,4).map(t=>(0,_jsxRuntime.jsx)(_reactNative.Pressable,{disabled:!!i.busy,onPress:()=>void i.runAction({label:t.label,send:t.send??t.label},e.id),style:({pressed:n})=>[styles.chip,n&&styles.pressed],accessibilityRole:"button",children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.chipText,children:t.label})},t.label))})}function MultiSelect({block:e}){const i=(0,_context.useBlockHandlers)();const t=i.answered[e.id];const n=!!t;const[o,l]=(0,_react.useState)([]);const r=t?.kind==="multi"?t.optionIds:o;const s=c=>l(d=>d.includes(c)?d.filter(a=>a!==c):[...d,c]);const h=o.length>=(e.min??1)&&(!e.max||o.length<=e.max);return(0,_jsxRuntime.jsxs)(_primitives.Card,{testID:`buoy-block-multi-${e.id}`,tone:n?void 0:"info",children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.question,children:e.question}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.optionsBox,children:e.options.map((c,d)=>{const a=r.includes(c.id);return(0,_jsxRuntime.jsxs)(_reactNative.Pressable,{disabled:n,onPress:()=>s(c.id),style:[styles.option,d>0&&_primitives.blockStyles.rowDivider,n&&!a&&styles.dim],accessibilityRole:"checkbox",accessibilityState:{checked:a},children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.checkbox,a&&styles.checkboxOn],children:a?(0,_jsxRuntime.jsx)(_sharedUi.Check,{size:11,color:_sharedUi.night.color.onAccent}):null}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.flex,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.optionLabel,children:c.label}),c.detail?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.optionDetail,children:c.detail}):null]})]},c.id)})}),n?null:(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.rowEnd,children:(0,_jsxRuntime.jsx)(_reactNative.Pressable,{testID:"buoy-block-multi-submit",disabled:!h,onPress:()=>i.answer({blockId:e.id,kind:"multi",...(0,_choiceLogic.multiAnswer)(e.options,o)}),style:[styles.button,styles.buttonPrimary,!h&&styles.disabled],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.buttonTextPrimary,children:e.submitLabel??`Use ${o.length||""}`.trim()})})})]})}function Select({block:e}){const i=(0,_context.useBlockHandlers)();const t=i.answered[e.id];const[n,o]=(0,_react.useState)("");const[l,r]=(0,_react.useState)(false);const s=t?.kind==="select"?t.label:null;const{showSearch:h,items:c,hidden:d}=(0,_choiceLogic.selectView)(e.options,n,e.searchable);return(0,_jsxRuntime.jsxs)(_primitives.Card,{testID:`buoy-block-select-${e.id}`,tone:t?void 0:"info",children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.question,children:e.label}),s?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.decided,children:s}):(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.selectBox,children:[(0,_jsxRuntime.jsxs)(_reactNative.Pressable,{onPress:()=>r(a=>!a),style:styles.selectField,accessibilityRole:"button",children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.selectPlaceholder,children:l?"Choose\u2026":`${e.options.length} options`}),(0,_jsxRuntime.jsx)(_sharedUi.ChevronDown,{size:14,color:_sharedUi.night.color.textSecondary})]}),l&&(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[h&&(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.search,children:[(0,_jsxRuntime.jsx)(_sharedUi.Search,{size:12,color:_sharedUi.night.color.textSecondary}),(0,_jsxRuntime.jsx)(_reactNative.TextInput,{style:styles.searchInput,value:n,onChangeText:o,placeholder:"Search",placeholderTextColor:_sharedUi.night.color.placeholder,autoCapitalize:"none",autoCorrect:false})]}),c.map((a,u)=>(0,_jsxRuntime.jsxs)(_reactNative.Pressable,{onPress:()=>i.answer({blockId:e.id,kind:"select",optionId:a.id,label:a.label}),style:[styles.option,u>0&&_primitives.blockStyles.rowDivider],accessibilityRole:"button",children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.flex,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.optionLabel,children:a.label}),a.detail?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.optionDetail,children:a.detail}):null]}),(0,_jsxRuntime.jsx)(_sharedUi.ChevronRight,{size:12,color:_sharedUi.night.color.textTertiary})]},a.id)),d>0?(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.hint,children:[d," more \u2014 keep typing"]}):null]})]})]})}function SliderControl({min:e,max:i,step:t=1,value:n,unit:o,onChange:l,disabled:r}){const s=(0,_react.useRef)(0);const h=i>e?(n-e)/(i-e)*100:0;const c=g=>Math.min(i,Math.max(e,+(Math.round((g-e)/t)*t+e).toFixed(6)));const d=g=>!r&&l(c(n+g*t));const a=g=>{if(r||s.current<=0)return;const x=Math.min(1,Math.max(0,g.nativeEvent.locationX/s.current));l(c(e+x*(i-e)))};const u=g=>{s.current=g.nativeEvent.layout.width};return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.sliderRow,children:[(0,_jsxRuntime.jsx)(_reactNative.Pressable,{disabled:r,onPress:()=>d(-1),style:styles.stepBtn,accessibilityRole:"button",accessibilityLabel:"Decrease",children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.stepText,children:"\u2212"})}),(0,_jsxRuntime.jsx)(_reactNative.Pressable,{style:styles.trackHit,onLayout:u,onPress:a,disabled:r,accessibilityRole:"adjustable",accessibilityValue:{min:e,max:i,now:n},accessibilityActions:[{name:"increment"},{name:"decrement"}],onAccessibilityAction:g=>d(g.nativeEvent.actionName==="increment"?1:-1),children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.track,pointerEvents:"none",children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.fill,{width:`${h}%`}]}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.thumb,{left:`${h}%`}]})]})}),(0,_jsxRuntime.jsx)(_reactNative.Pressable,{disabled:r,onPress:()=>d(1),style:styles.stepBtn,accessibilityRole:"button",accessibilityLabel:"Increase",children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.stepText,children:"+"})}),(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.sliderValue,children:[n,o?` ${o}`:""]})]})}function Slider({block:e}){const i=(0,_context.useBlockHandlers)();const t=i.answered[e.id];const[n,o]=(0,_react.useState)(e.value??e.min);return(0,_jsxRuntime.jsxs)(_primitives.Card,{testID:`buoy-block-slider-${e.id}`,tone:t?void 0:"info",children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.question,children:e.label}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.pad,children:(0,_jsxRuntime.jsx)(SliderControl,{min:e.min,max:e.max,step:e.step,value:t?.kind==="slider"?t.value:n,unit:e.unit,onChange:o,disabled:!!t})}),t?null:(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.rowEnd,children:(0,_jsxRuntime.jsx)(_reactNative.Pressable,{onPress:()=>i.answer({blockId:e.id,kind:"slider",value:n,unit:e.unit}),style:[styles.button,styles.buttonPrimary],children:(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.buttonTextPrimary,children:["Use ",n,e.unit?` ${e.unit}`:""]})})})]})}function DateTime({block:e}){const i=(0,_context.useBlockHandlers)();const t=i.answered[e.id];const[n,o]=(0,_react.useState)("");const l=e.presets??[{label:"Now",value:new Date().toISOString()},{label:"Tomorrow",value:new Date(Date.now()+864e5).toISOString()},{label:"+7 days",value:new Date(Date.now()+7*864e5).toISOString()},{label:"+30 days",value:new Date(Date.now()+30*864e5).toISOString()}];return(0,_jsxRuntime.jsxs)(_primitives.Card,{testID:`buoy-block-datetime-${e.id}`,tone:t?void 0:"info",children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.question,children:e.label}),t?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.decided,children:t.kind==="dateTime"?t.label??t.value:"(skipped)"}):(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.chips,styles.pad],children:l.map(r=>(0,_jsxRuntime.jsx)(_reactNative.Pressable,{onPress:()=>i.answer({blockId:e.id,kind:"dateTime",value:r.value,label:r.label}),style:styles.chip,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.chipText,children:r.label})},r.label))}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:[styles.inputRow,styles.pad],children:[(0,_jsxRuntime.jsx)(_reactNative.TextInput,{style:styles.input,value:n,onChangeText:o,placeholder:e.mode==="time"?"14:30":"2026-09-15",placeholderTextColor:_sharedUi.night.color.placeholder,keyboardType:"numbers-and-punctuation"}),(0,_jsxRuntime.jsx)(_reactNative.Pressable,{disabled:!n.trim(),onPress:()=>i.answer({blockId:e.id,kind:"dateTime",value:n.trim()}),style:[styles.button,styles.buttonPrimary,!n.trim()&&styles.disabled],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.buttonTextPrimary,children:"Use"})})]})]})]})}function FieldRow({f:e,value:i,onChange:t,disabled:n}){if(e.type==="toggle"){return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.fieldRow,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.fieldLabel,children:e.label}),(0,_jsxRuntime.jsx)(_reactNative.Switch,{value:!!i,onValueChange:t,disabled:n,trackColor:{true:_sharedUi.night.color.accent,false:_sharedUi.night.color.fillTertiary},thumbColor:_sharedUi.night.color.knob})]})}if(e.type==="select"){return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.fieldCol,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.fieldLabel,children:e.label}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.chips,children:e.options.map(o=>(0,_jsxRuntime.jsx)(_reactNative.Pressable,{disabled:n,onPress:()=>t(o.id),style:[styles.chip,i===o.id&&styles.chipOn],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.chipText,i===o.id&&styles.chipTextOn],children:o.label})},o.id))})]})}if(e.type==="slider"){return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.fieldCol,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.fieldLabel,children:e.label}),(0,_jsxRuntime.jsx)(SliderControl,{min:e.min,max:e.max,step:e.step,unit:e.unit,value:typeof i==="number"?i:e.min,onChange:t,disabled:n})]})}return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.fieldRow,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.fieldLabel,children:e.label}),(0,_jsxRuntime.jsx)(_reactNative.TextInput,{style:styles.fieldInput,value:i===void 0||i===null?"":String(i),onChangeText:t,editable:!n,placeholder:e.placeholder??"",placeholderTextColor:_sharedUi.night.color.placeholder,keyboardType:e.type==="number"?"numeric":"ascii-capable",secureTextEntry:e.type==="secret",autoCapitalize:"none",autoCorrect:false})]})}function useFormValues(e){const[i,t]=(0,_react.useState)(()=>Object.fromEntries(e.map(n=>[n.key,n.value])));return{values:i,set:(n,o)=>t(l=>({...l,[n]:o}))}}function Form({block:e}){const i=(0,_context.useBlockHandlers)();const t=i.answered[e.id];const{values:n,set:o}=useFormValues(e.fields);const l=(0,_choiceLogic.shownFormValues)(t,n);return(0,_jsxRuntime.jsxs)(_primitives.Card,{title:e.title,testID:`buoy-block-form-${e.id}`,tone:t?void 0:"info",children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.pad,children:e.fields.map(r=>(0,_jsxRuntime.jsx)(FieldRow,{f:r,value:l[r.key],onChange:s=>o(r.key,s),disabled:!!t},r.key))}),t?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.decided,children:"Sent"}):(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.rowEnd,children:(0,_jsxRuntime.jsx)(_reactNative.Pressable,{onPress:()=>i.answer({blockId:e.id,kind:"form",values:l}),style:[styles.button,styles.buttonPrimary],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.buttonTextPrimary,children:e.submitLabel??"Send"})})})]})}function Proposal({block:e}){const i=(0,_context.useBlockHandlers)();const t=i.answered[e.id];const{values:n,set:o}=useFormValues(e.fields);const l=(0,_choiceLogic.shownFormValues)(t,n);const r=t?.kind==="proposal"?t.approved:null;return(0,_jsxRuntime.jsxs)(_primitives.Card,{testID:`buoy-block-proposal-${e.id}`,tone:t?void 0:"warning",children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.confirmTitle,children:e.title}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.confirmChange,children:e.change}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.pad,children:e.fields.map(s=>(0,_jsxRuntime.jsx)(FieldRow,{f:s,value:l[s.key],onChange:h=>o(s.key,h),disabled:!!t},s.key))}),e.consequence?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.consequence,children:e.consequence}):null,(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.actionsRow,children:t?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.decided,children:r?"\u2713 Applied with these values":"\u2715 Not applied"}):(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(_reactNative.Pressable,{onPress:()=>i.answer({blockId:e.id,kind:"proposal",approved:true,values:l}),style:[styles.button,styles.buttonPrimary],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.buttonTextPrimary,children:e.approveLabel??"Apply"})}),(0,_jsxRuntime.jsx)(_reactNative.Pressable,{onPress:()=>i.answer({blockId:e.id,kind:"proposal",approved:false}),style:[styles.button,styles.buttonPlate],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.buttonTextPlate,children:"Not now"})})]})})]})}function Claim({block:e}){const i=(0,_context.useBlockHandlers)();const[t,n]=(0,_react.useState)(null);const o=i.actionState?.[`${e.id}:${e.verify?.label??"Verify"}`];const l=e.verified||o==="done";return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.claim,testID:`buoy-block-claim-${e.id}`,children:[(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.claimText,children:[e.text,e.sources.map((r,s)=>(0,_jsxRuntime.jsxs)(_reactNative.Text,{onPress:()=>n(t===s?null:s),style:styles.cite,children:[" [",s+1,"]"]},s)),l?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.verified,children:" \u2713 verified"}):null]}),t!==null&&e.sources[t]?(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.citeBox,children:[(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.citeLabel,children:["[",t+1,"] ",e.sources[t].label]}),e.sources[t].detail?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.citeDetail,children:e.sources[t].detail}):null]}):null,e.verify&&!l?(0,_jsxRuntime.jsxs)(_reactNative.Pressable,{onPress:()=>void i.runAction(e.verify,e.id),style:styles.verifyBtn,accessibilityRole:"button",children:[(0,_jsxRuntime.jsx)(_sharedUi.RefreshCw,{size:11,color:_sharedUi.night.color.accent}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.verifyText,children:o==="running"?"Checking\u2026":e.verify.label})]}):null]})}function Details({block:e}){const[i,t]=(0,_react.useState)(!!e.open);return(0,_jsxRuntime.jsxs)(_primitives.Card,{testID:`buoy-block-details-${e.id}`,children:[(0,_jsxRuntime.jsxs)(_reactNative.Pressable,{onPress:()=>t(n=>!n),style:_primitives.blockStyles.row,accessibilityRole:"button",accessibilityState:{expanded:i},children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:_primitives.blockStyles.rowTitle,children:e.summary}),i?(0,_jsxRuntime.jsx)(_sharedUi.ChevronDown,{size:12,color:_sharedUi.night.color.textTertiary}):(0,_jsxRuntime.jsx)(_sharedUi.ChevronRight,{size:12,color:_sharedUi.night.color.textTertiary})]}),i?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.detailsBody,selectable:true,children:e.body}):null]})}function Tabs({block:e,renderNested:i}){const[t,n]=(0,_react.useState)(0);const o=e.tabs.map((r,s)=>({key:String(s),label:r.label}));const l=e.tabs[t];return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.tabsWrap,testID:`buoy-block-tabs-${e.id}`,children:[(0,_jsxRuntime.jsx)(_sharedUi.NightSegmented,{tabs:o,activeKey:String(t),onChange:r=>n(Number(r)),size:"sm"}),l&&i?i(l.block):null]})}const TIMELINE_CAP=10;function Timeline({block:e}){const i=(0,_primitives.usePaged)(e.events,TIMELINE_CAP);return(0,_jsxRuntime.jsxs)(_primitives.Card,{title:e.title??"What happened",source:e.source,testID:`buoy-block-timeline-${e.id}`,children:[i.visible.map((t,n)=>(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.tlRow,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.tlAt,children:t.at}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.tlLine,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.tlDot,{backgroundColor:(0,_primitives.toneColor)(t.tone??"muted")}]}),n<i.visible.length-1?(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.tlStem}):null]}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.flex,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.tlSource,children:t.source.toUpperCase()}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:_primitives.blockStyles.rowTitle,numberOfLines:2,children:t.label})]})]},n)),(0,_jsxRuntime.jsx)(_primitives.More,{paged:i})]})}function Sparkline({block:e}){const i=e.series.slice(-60);const t=Math.max(1,...i);const n=Math.min(...i,0);const o=44;return(0,_jsxRuntime.jsxs)(_primitives.Card,{title:e.title,source:e.source,testID:`buoy-block-sparkline-${e.id}`,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.sparkHead,children:[(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.sparkCurrent,children:[e.current??i[i.length-1],e.unit?(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.sparkUnit,children:[" ",e.unit]}):null]}),e.live?(0,_jsxRuntime.jsx)(LivePill,{}):null]}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.spark,{height:o}],children:i.map((l,r)=>(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.sparkBar,{height:Math.max(2,(l-n)/(t-n||1)*o),backgroundColor:r===i.length-1?_sharedUi.night.color.accent:_sharedUi.night.color.accentBorderStrong}]},r))}),e.label?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.hint,children:e.label}):null]})}function LivePill(){const e=(0,_react.useRef)(new _reactNative.Animated.Value(1)).current;(0,_react.useEffect)(()=>{const i=_reactNative.Animated.loop(_reactNative.Animated.sequence([_reactNative.Animated.timing(e,{toValue:.3,duration:700,useNativeDriver:true}),_reactNative.Animated.timing(e,{toValue:1,duration:700,useNativeDriver:true})]));i.start();return()=>i.stop()},[e]);return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.live,children:[(0,_jsxRuntime.jsx)(_reactNative.Animated.View,{style:[styles.liveDot,{opacity:e}]}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.liveText,children:"LIVE"})]})}function Compare({block:e}){const i=[...new Set([...e.left.pairs.map(o=>o.key),...e.right.pairs.map(o=>o.key)])];const t=Object.fromEntries(e.left.pairs.map(o=>[o.key,o.value]));const n=Object.fromEntries(e.right.pairs.map(o=>[o.key,o.value]));return(0,_jsxRuntime.jsxs)(_primitives.Card,{title:e.title,source:e.source,testID:`buoy-block-compare-${e.id}`,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.cmpHead,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.cmpKey}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.cmpCol,children:e.left.title}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.cmpCol,children:e.right.title})]}),i.map((o,l)=>{const r=JSON.stringify(t[o])!==JSON.stringify(n[o]);return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:[styles.cmpRow,l>0&&_primitives.blockStyles.rowDivider,r&&styles.cmpDiff],children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.cmpKey,numberOfLines:1,children:o}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.cmpVal,r&&{color:_sharedUi.night.color.danger}],numberOfLines:2,children:fmt(t[o])}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.cmpVal,r&&{color:_sharedUi.night.color.accent}],numberOfLines:2,children:fmt(n[o])})]},o)})]})}function CardBody({c:e,id:i}){return(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[e.image?(0,_jsxRuntime.jsx)(_reactNative.Image,{testID:"buoy-internal-chat-image",source:{uri:e.image},style:styles.cardImage,resizeMode:"contain",accessibilityLabel:e.title}):null,(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.cardText,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.cardTitle,numberOfLines:2,children:e.title}),e.subtitle?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:_primitives.blockStyles.rowSub,numberOfLines:2,children:e.subtitle}):null,e.facts?.slice(0,4).map(t=>(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.fact,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.factLabel,children:t.label}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.factValue,t.tone&&{color:(0,_primitives.toneColor)(t.tone)}],children:t.value})]},t.label))]}),(0,_jsxRuntime.jsx)(_primitives.ActionRow,{actions:e.actions,blockId:i})]})}function CardView({block:e}){return(0,_jsxRuntime.jsx)(_primitives.Card,{source:e.source,testID:`buoy-block-card-${e.id}`,children:(0,_jsxRuntime.jsx)(CardBody,{c:e,id:e.id})})}function CardCarousel({block:e}){return(0,_jsxRuntime.jsxs)(_reactNative.View,{testID:`buoy-block-cardcarousel-${e.id}`,children:[e.title?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.carouselTitle,children:e.title}):null,(0,_jsxRuntime.jsx)(_reactNative.ScrollView,{horizontal:true,showsHorizontalScrollIndicator:false,snapToInterval:232,decelerationRate:"fast",contentContainerStyle:styles.carousel,children:e.cards.slice(0,8).map((i,t)=>(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.carouselCard,children:(0,_jsxRuntime.jsx)(CardBody,{c:i,id:`${e.id}-${t}`})},`${i.title}-${t}`))})]})}function Screenshot({block:e}){const[i,t]=(0,_react.useState)(false);return(0,_jsxRuntime.jsxs)(_primitives.Card,{title:e.route?`Screen \xB7 ${e.route}`:"Screen",source:e.source,testID:`buoy-block-screenshot-${e.id}`,children:[(0,_jsxRuntime.jsx)(_reactNative.Pressable,{onPress:()=>t(n=>!n),accessibilityRole:"imagebutton",accessibilityLabel:e.caption??"Screenshot",children:(0,_jsxRuntime.jsx)(_reactNative.Image,{testID:"buoy-internal-chat-image",source:{uri:e.url},style:[styles.shot,i&&styles.shotBig],resizeMode:"contain"})}),e.caption?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.hint,children:e.caption}):null]})}function Plan({block:e}){const i=e.steps.filter(t=>t.state==="done").length;return(0,_jsxRuntime.jsxs)(_primitives.Card,{title:e.title,testID:`buoy-block-plan-${e.id}`,tone:e.pending?"info":void 0,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.progress,children:(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.progressFill,{width:`${i/Math.max(1,e.steps.length)*100}%`}]})}),e.steps.map((t,n)=>(0,_jsxRuntime.jsxs)(_reactNative.View,{style:[styles.step,n>0&&_primitives.blockStyles.rowDivider],children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.stepMark,t.state==="done"&&styles.stepDone,t.state==="failed"&&styles.stepFailed,t.state==="running"&&styles.stepRunning],children:t.state==="done"?(0,_jsxRuntime.jsx)(_sharedUi.Check,{size:10,color:_sharedUi.night.color.onAccent}):t.state==="failed"?(0,_jsxRuntime.jsx)(_sharedUi.X,{size:10,color:_sharedUi.night.color.text}):(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.stepNum,children:n+1})}),(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:[_primitives.blockStyles.rowTitle,t.state==="done"&&styles.muted],children:[t.text,t.state==="running"?"\u2026":""]})]},n)),(0,_jsxRuntime.jsx)(_primitives.ActionRow,{actions:e.actions??(e.pending?[{label:"Go",primary:true,send:"Go ahead with the plan."},{label:"Change it",send:"Let me change the plan first."}]:void 0),blockId:e.id})]})}function Checkpoint({block:e}){const i=(0,_context.useBlockHandlers)();return(0,_jsxRuntime.jsxs)(_reactNative.Pressable,{testID:`buoy-block-checkpoint-${e.id}`,disabled:!e.restore,onPress:()=>e.restore&&void i.runAction(e.restore,e.id),style:styles.checkpoint,accessibilityRole:"button",children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.cpFlag}),(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.cpText,children:[e.label,e.at?` \xB7 ${e.at}`:""]}),e.restore?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.cpRestore,children:e.restore.label}):null]})}function Task({block:e}){const i=e.status==="failed"?_sharedUi.night.color.danger:e.status==="done"?_sharedUi.night.color.accent:_sharedUi.night.color.info;return(0,_jsxRuntime.jsxs)(_primitives.Card,{testID:`buoy-block-task-${e.id}`,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.taskHead,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.cardTitle,children:e.title}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:[_primitives.blockStyles.pill,{backgroundColor:`${i}22`}],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[_primitives.blockStyles.pillText,{color:i}],children:e.status.toUpperCase()})})]}),e.progress!==void 0?(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.progress,styles.pad],children:(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.progressFill,{width:`${Math.round(e.progress*100)}%`,backgroundColor:i}]})}):null,e.detail?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.hint,children:e.detail}):null,(0,_jsxRuntime.jsx)(_primitives.ActionRow,{actions:e.actions,blockId:e.id})]})}function Banner({block:e}){const i=e.tone==="danger"?_sharedUi.night.color.danger:e.tone==="warning"?_sharedUi.night.color.warning:_sharedUi.night.color.info;return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:[styles.banner,{borderColor:i,backgroundColor:`${i}1A`}],testID:`buoy-block-banner-${e.id}`,children:[(0,_jsxRuntime.jsx)(_sharedUi.AlertTriangle,{size:13,color:i}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.bannerText,{color:i}],numberOfLines:2,children:e.text}),e.actions?.[0]?(0,_jsxRuntime.jsx)(_primitives.ActionRow,{actions:e.actions.slice(0,1),blockId:e.id,align:"right"}):null]})}function File({block:e}){return(0,_jsxRuntime.jsxs)(_primitives.Card,{testID:`buoy-block-file-${e.id}`,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:_primitives.blockStyles.row,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.fileIcon,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.fileExt,children:(e.type??e.name.split(".").pop()??"file").toUpperCase().slice(0,4)})}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.flex,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:_primitives.blockStyles.rowTitle,numberOfLines:1,children:e.name}),e.size?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:_primitives.blockStyles.rowSub,children:e.size}):null]})]}),(0,_jsxRuntime.jsx)(_primitives.ActionRow,{actions:e.actions,blockId:e.id})]})}function Upload({block:e}){const i=(0,_context.useBlockHandlers)();const t=i.answered[e.id];return(0,_jsxRuntime.jsxs)(_primitives.Card,{testID:`buoy-block-upload-${e.id}`,tone:t?void 0:"info",children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.question,children:e.label}),t?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.decided,children:t.kind==="upload"?`Attached ${t.name}`:"(skipped)"}):(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.rowEnd,{justifyContent:"flex-start"}],children:(0,_jsxRuntime.jsx)(_reactNative.Pressable,{onPress:()=>i.answer({blockId:e.id,kind:"upload",name:"screenshot.png"}),style:[styles.button,styles.buttonPlate],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.buttonTextPlate,children:e.accept==="image"?"Choose a screenshot":"Choose a file"})})})]})}const styles=_reactNative.StyleSheet.create({flex:{flex:1},pad:{paddingHorizontal:12,paddingBottom:8},muted:{color:_sharedUi.night.color.textSecondary},dim:{opacity:.45},disabled:{opacity:.5},pressed:{opacity:.7},question:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.row,fontWeight:"600",lineHeight:20,paddingHorizontal:12,paddingTop:12,paddingBottom:8},hint:{color:_sharedUi.night.color.textTertiary,fontSize:_sharedUi.night.font.micro,paddingHorizontal:12,paddingBottom:10},decided:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption,fontWeight:"600",paddingHorizontal:12,paddingVertical:10},rowEnd:{flexDirection:"row",justifyContent:"flex-end",paddingHorizontal:12,paddingBottom:12,gap:8},actionsRow:{flexDirection:"row",gap:8,paddingHorizontal:12,paddingVertical:12,alignItems:"center"},button:{paddingHorizontal:14,paddingVertical:9,borderRadius:_sharedUi.night.radius.row},buttonPrimary:{backgroundColor:_sharedUi.night.color.accent},buttonPlate:{backgroundColor:_sharedUi.night.color.button},buttonTextPrimary:{color:_sharedUi.night.color.onAccent,fontSize:_sharedUi.night.font.caption,fontWeight:"600"},buttonTextPlate:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.caption,fontWeight:"600"},chips:{flexDirection:"row",flexWrap:"wrap",gap:6},chip:{paddingHorizontal:12,paddingVertical:7,borderRadius:_sharedUi.night.radius.chip,backgroundColor:_sharedUi.night.color.fill,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.border},chipOn:{backgroundColor:_sharedUi.night.color.accentSoft,borderColor:_sharedUi.night.color.accentBorderStrong},chipText:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.caption},chipTextOn:{color:_sharedUi.night.color.accent,fontWeight:"600"},optionsBox:{marginHorizontal:8,marginBottom:8,borderRadius:_sharedUi.night.radius.row,backgroundColor:_sharedUi.night.color.surfaceElevated,overflow:"hidden"},option:{flexDirection:"row",alignItems:"center",gap:10,paddingHorizontal:12,paddingVertical:10},optionLabel:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.body,fontWeight:"500"},optionDetail:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption},checkbox:{width:20,height:20,borderRadius:6,borderWidth:1.5,borderColor:_sharedUi.night.color.textTertiary,alignItems:"center",justifyContent:"center"},checkboxOn:{backgroundColor:_sharedUi.night.color.accent,borderColor:_sharedUi.night.color.accent},selectBox:{marginHorizontal:12,marginBottom:12,borderRadius:_sharedUi.night.radius.row,backgroundColor:_sharedUi.night.color.surfaceElevated,overflow:"hidden"},selectField:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",paddingHorizontal:12,paddingVertical:11},selectPlaceholder:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.body},search:{flexDirection:"row",alignItems:"center",gap:6,paddingHorizontal:12,paddingVertical:6,borderTopWidth:_reactNative.StyleSheet.hairlineWidth,borderTopColor:_sharedUi.night.color.separator},searchInput:{flex:1,color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.caption,paddingVertical:4},sliderRow:{flexDirection:"row",alignItems:"center",gap:8},stepBtn:{width:28,height:28,borderRadius:14,backgroundColor:_sharedUi.night.color.fill,alignItems:"center",justifyContent:"center"},stepText:{color:_sharedUi.night.color.text,fontSize:16,fontWeight:"600"},trackHit:{flex:1,height:36,justifyContent:"center"},track:{height:6,borderRadius:3,backgroundColor:_sharedUi.night.color.fillTertiary,justifyContent:"center"},fill:{height:6,borderRadius:3,backgroundColor:_sharedUi.night.color.accent},thumb:{position:"absolute",width:20,height:20,borderRadius:10,backgroundColor:_sharedUi.night.color.knob,marginLeft:-10,shadowColor:"#000",shadowOpacity:.35,shadowRadius:3,shadowOffset:{width:0,height:1}},sliderValue:{width:64,textAlign:"right",color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.caption,fontWeight:"600"},inputRow:{flexDirection:"row",alignItems:"center",gap:8,paddingBottom:12},input:{flex:1,height:38,paddingHorizontal:12,borderRadius:_sharedUi.night.radius.row,backgroundColor:_sharedUi.night.color.surfaceElevated,color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.body},fieldRow:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",gap:10,paddingVertical:6},fieldCol:{paddingVertical:6,gap:6},fieldLabel:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption,width:110},fieldInput:{flex:1,height:34,paddingHorizontal:10,borderRadius:_sharedUi.night.radius.segment,backgroundColor:_sharedUi.night.color.surfaceElevated,color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.caption},confirmTitle:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.row,fontWeight:"600",paddingHorizontal:12,paddingTop:12},confirmChange:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.body,lineHeight:19,paddingHorizontal:12,paddingTop:6,paddingBottom:6},consequence:{color:_sharedUi.night.color.warning,fontSize:_sharedUi.night.font.caption,paddingHorizontal:12},claim:{gap:6,paddingHorizontal:2},claimText:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.row,lineHeight:22},cite:{color:_sharedUi.night.color.accent,fontSize:_sharedUi.night.font.caption,fontWeight:"700"},verified:{color:_sharedUi.night.color.accent,fontSize:_sharedUi.night.font.caption,fontWeight:"600"},citeBox:{padding:10,borderRadius:_sharedUi.night.radius.row,backgroundColor:_sharedUi.night.color.surface,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.border,gap:2},citeLabel:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.caption,fontWeight:"600"},citeDetail:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption,fontFamily:_reactNative.Platform.OS==="web"?_sharedUi.monoFont:"Menlo"},verifyBtn:{alignSelf:"flex-start",flexDirection:"row",alignItems:"center",gap:5,paddingHorizontal:10,paddingVertical:5,borderRadius:_sharedUi.night.radius.chip,backgroundColor:_sharedUi.night.color.accentSoft},verifyText:{color:_sharedUi.night.color.accent,fontSize:_sharedUi.night.font.micro,fontWeight:"700"},detailsBody:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption,lineHeight:18,paddingHorizontal:12,paddingBottom:12},tabsWrap:{gap:8},tabBar:{flexDirection:"row",gap:6},tab:{paddingHorizontal:12,paddingVertical:6,borderRadius:_sharedUi.night.radius.badge,backgroundColor:_sharedUi.night.color.fill},tabOn:{backgroundColor:_sharedUi.night.color.accentSoft},tabText:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption,fontWeight:"600"},tabTextOn:{color:_sharedUi.night.color.accent},tlRow:{flexDirection:"row",gap:10,paddingHorizontal:12,paddingVertical:4,alignItems:"flex-start"},tlAt:{width:46,color:_sharedUi.night.color.textTertiary,fontSize:_sharedUi.night.font.micro,fontFamily:_reactNative.Platform.OS==="web"?_sharedUi.monoFont:"Menlo",paddingTop:3},tlLine:{width:12,alignItems:"center"},tlDot:{width:8,height:8,borderRadius:4,marginTop:5},tlStem:{width:1,flex:1,minHeight:18,backgroundColor:_sharedUi.night.color.separator,marginTop:2},tlSource:{color:_sharedUi.night.color.textTertiary,fontSize:9,fontWeight:"700",letterSpacing:.6},sparkHead:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",paddingHorizontal:12,paddingTop:8},sparkCurrent:{color:_sharedUi.night.color.text,fontSize:22,fontWeight:"700"},sparkUnit:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption,fontWeight:"500"},spark:{flexDirection:"row",alignItems:"flex-end",gap:2,paddingHorizontal:12,paddingTop:6,paddingBottom:6},sparkBar:{flex:1,borderRadius:1},live:{flexDirection:"row",alignItems:"center",gap:5,paddingHorizontal:8,paddingVertical:3,borderRadius:_sharedUi.night.radius.badge,backgroundColor:_sharedUi.night.color.dangerSoft},liveDot:{width:6,height:6,borderRadius:3,backgroundColor:_sharedUi.night.color.danger},liveText:{color:_sharedUi.night.color.danger,fontSize:9,fontWeight:"800",letterSpacing:.8},cmpHead:{flexDirection:"row",paddingHorizontal:12,paddingVertical:6,backgroundColor:_sharedUi.night.color.fill,gap:8},cmpCol:{flex:1,color:_sharedUi.night.color.textTertiary,fontSize:_sharedUi.night.font.micro,fontWeight:"700",letterSpacing:.6,textTransform:"uppercase"},cmpRow:{flexDirection:"row",paddingHorizontal:12,paddingVertical:8,gap:8,alignItems:"flex-start"},cmpDiff:{backgroundColor:_sharedUi.night.color.fill},cmpKey:{width:90,color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption},cmpVal:{flex:1,color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.caption,fontFamily:_reactNative.Platform.OS==="web"?_sharedUi.monoFont:"Menlo"},cardImage:{width:"100%",height:140,backgroundColor:_sharedUi.night.color.fill},cardText:{paddingHorizontal:12,paddingTop:10,paddingBottom:4,gap:4},cardTitle:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.row,fontWeight:"600"},fact:{flexDirection:"row",justifyContent:"space-between",gap:8},factLabel:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption},factValue:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.caption,fontWeight:"500"},carouselTitle:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.caption,fontWeight:"600",paddingBottom:8},carousel:{gap:8,paddingRight:8},carouselCard:{width:224,borderRadius:_sharedUi.night.radius.card,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.border,backgroundColor:_sharedUi.night.color.surface,overflow:"hidden"},shot:{width:"100%",height:220,backgroundColor:_sharedUi.night.color.fill},shotBig:{height:520},progress:{height:4,backgroundColor:_sharedUi.night.color.fill,marginHorizontal:12,marginTop:6,marginBottom:8,borderRadius:2,overflow:"hidden"},progressFill:{height:4,backgroundColor:_sharedUi.night.color.accent},step:{flexDirection:"row",alignItems:"center",gap:10,paddingHorizontal:12,paddingVertical:9},stepMark:{width:20,height:20,borderRadius:10,backgroundColor:_sharedUi.night.color.fillTertiary,alignItems:"center",justifyContent:"center"},stepDone:{backgroundColor:_sharedUi.night.color.accent},stepFailed:{backgroundColor:_sharedUi.night.color.danger},stepRunning:{backgroundColor:_sharedUi.night.color.info},stepNum:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.micro,fontWeight:"700"},checkpoint:{alignSelf:"flex-start",flexDirection:"row",alignItems:"center",gap:8,paddingHorizontal:12,paddingVertical:7,borderRadius:_sharedUi.night.radius.chip,backgroundColor:_sharedUi.night.color.fill},cpFlag:{width:8,height:8,borderRadius:2,backgroundColor:_sharedUi.night.color.info},cpText:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption},cpRestore:{color:_sharedUi.night.color.accent,fontSize:_sharedUi.night.font.caption,fontWeight:"600"},taskHead:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",gap:8,paddingHorizontal:12,paddingTop:12},banner:{flexDirection:"row",alignItems:"center",gap:8,paddingLeft:12,paddingRight:4,paddingVertical:4,borderRadius:_sharedUi.night.radius.row,borderWidth:_reactNative.StyleSheet.hairlineWidth},bannerText:{flex:1,fontSize:_sharedUi.night.font.caption,fontWeight:"600"},fileIcon:{width:40,height:40,borderRadius:8,backgroundColor:_sharedUi.night.color.fill,alignItems:"center",justifyContent:"center"},fileExt:{color:_sharedUi.night.color.textSecondary,fontSize:10,fontWeight:"800"}});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.SEARCH_FROM=exports.SEARCH_CAP=void 0;exports.multiAnswer=multiAnswer;exports.selectView=selectView;exports.shownFormValues=shownFormValues;const SEARCH_FROM=exports.SEARCH_FROM=8;const SEARCH_CAP=exports.SEARCH_CAP=8;function selectView(e,s,o){const t=o!==false&&e.length>=SEARCH_FROM;const l=t?s.trim().toLowerCase():"";const r=l?e.filter(i=>i.label.toLowerCase().includes(l)):e;const n=t?r.slice(0,SEARCH_CAP):r;return{showSearch:t,items:n,hidden:r.length-n.length}}function multiAnswer(e,s){const o=e.filter(t=>s.includes(t.id));return{optionIds:o.map(t=>t.id),labels:o.map(t=>t.label)}}function shownFormValues(e,s){if(e?.kind==="form")return e.values;if(e?.kind==="proposal"&&e.approved&&e.values)return e.values;return s}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var _vitest=require("vitest");var _choiceLogic=require("./choiceLogic");const opts=(e,t=o=>`Option ${o}`)=>Array.from({length:e},(o,s)=>({id:`o${s}`,label:t(s)}));(0,_vitest.describe)("selectView",()=>{(0,_vitest.it)("a short list shows every option and no search",()=>{const e=(0,_choiceLogic.selectView)(opts(5),"");(0,_vitest.expect)(e.showSearch).toBe(false);(0,_vitest.expect)(e.items).toHaveLength(5);(0,_vitest.expect)(e.hidden).toBe(0)});(0,_vitest.it)("searchable:false with a long list shows ALL options, not 8",()=>{const e=(0,_choiceLogic.selectView)(opts(20),"",false);(0,_vitest.expect)(e.showSearch).toBe(false);(0,_vitest.expect)(e.items).toHaveLength(20);(0,_vitest.expect)(e.hidden).toBe(0)});(0,_vitest.it)("searchable:false ignores a stale query",()=>{(0,_vitest.expect)((0,_choiceLogic.selectView)(opts(20),"zzz",false).items).toHaveLength(20)});(0,_vitest.it)("a long searchable list caps at 8 and counts the rest",()=>{const e=(0,_choiceLogic.selectView)(opts(20),"");(0,_vitest.expect)(e.showSearch).toBe(true);(0,_vitest.expect)(e.items.map(t=>t.id)).toEqual(opts(8).map(t=>t.id));(0,_vitest.expect)(e.hidden).toBe(12)});(0,_vitest.it)("the 'more' count only counts options that match the query",()=>{const e=opts(20,o=>o%2?`odd ${o}`:`even ${o}`);const t=(0,_choiceLogic.selectView)(e,"EVEN");(0,_vitest.expect)(t.items).toHaveLength(8);(0,_vitest.expect)(t.items.every(o=>o.label.startsWith("even"))).toBe(true);(0,_vitest.expect)(t.hidden).toBe(2)});(0,_vitest.it)("no 'more' count when every match fits",()=>{const e=opts(20,o=>o<3?`pick ${o}`:`other ${o}`);const t=(0,_choiceLogic.selectView)(e,"pick");(0,_vitest.expect)(t.items).toHaveLength(3);(0,_vitest.expect)(t.hidden).toBe(0)});(0,_vitest.it)("no matches shows nothing and counts nothing",()=>{const e=(0,_choiceLogic.selectView)(opts(20),"nope");(0,_vitest.expect)(e.items).toHaveLength(0);(0,_vitest.expect)(e.hidden).toBe(0)})});(0,_vitest.describe)("multiAnswer",()=>{const e=[{id:"a",label:"Alpha"},{id:"b",label:"Bravo"},{id:"c",label:"Charlie"}];(0,_vitest.it)("ids and labels are both in list order, whatever the tap order",()=>{(0,_vitest.expect)((0,_choiceLogic.multiAnswer)(e,["c","a"])).toEqual({optionIds:["a","c"],labels:["Alpha","Charlie"]})});(0,_vitest.it)("drops ids that are not options so ids and labels pair up",()=>{(0,_vitest.expect)((0,_choiceLogic.multiAnswer)(e,["zz","b"])).toEqual({optionIds:["b"],labels:["Bravo"]})})});(0,_vitest.describe)("shownFormValues",()=>{const e={port:8080};(0,_vitest.it)("unanswered shows local edits",()=>{(0,_vitest.expect)((0,_choiceLogic.shownFormValues)(void 0,e)).toBe(e)});(0,_vitest.it)("a sent form shows the sent values, not reset local state",()=>{const t={port:9e3};(0,_vitest.expect)((0,_choiceLogic.shownFormValues)({blockId:"f",kind:"form",values:t},{})).toBe(t)});(0,_vitest.it)("an applied proposal shows the applied values",()=>{const t={port:9e3};(0,_vitest.expect)((0,_choiceLogic.shownFormValues)({blockId:"p",kind:"proposal",approved:true,values:t},e)).toBe(t)});(0,_vitest.it)("a declined proposal keeps local values (nothing was applied)",()=>{(0,_vitest.expect)((0,_choiceLogic.shownFormValues)({blockId:"p",kind:"proposal",approved:false},e)).toBe(e)})});
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.AskBuoyModal=AskBuoyModal;var _react=require("react");var _reactNative=require("react-native");var _agentCore=require("@buoy-gg/agent-core");var _sharedUi=require("@buoy-gg/shared-ui");var _blocks=require("../blocks");var _ApprovalCard=require("./ApprovalCard");var _ChangesBar=require("./ChangesBar");var _ruleStates=require("../blocks/ruleStates");var _Composer=require("./Composer");var _KeyboardPad=require("./KeyboardPad");var _AskBuoyHeader=require("./AskBuoyHeader");var _AskBuoySettings=require("./AskBuoySettings");var _EmptyState=require("./EmptyState");var _MessageList=require("./MessageList");var _QueuedMessages=require("./QueuedMessages");var _askBuoyStore=require("../store/askBuoyStore");var _ticketPrompt=require("../store/ticketPrompt");var _useAskBuoy=require("../store/useAskBuoy");var _useAskBuoySettings=require("../store/useAskBuoySettings");var _askBuoySettings=require("../store/askBuoySettings");var _jsxRuntime=require("react/jsx-runtime");function AskBuoyModal({visible:f,onClose:v,onBack:S,onMinimize:u,persistenceKey:$,config:a}){const{state:e,send:c,stop:h,reset:d,undoThenReset:x,approve:E,retry:L,answer:A,runAction:B,editQueued:N,removeQueued:O,configured:k,toolCount:K,availableToolIds:D}=(0,_useAskBuoy.useAskBuoy)(a);const[V,z]=(0,_react.useState)(false);const U=(0,_react.useCallback)(()=>{h();v()},[h,v]);const F=(0,_react.useCallback)(()=>_askBuoyStore.askBuoyStore.clearDraft(),[]);const[g,b]=(0,_react.useState)(false);const Q=(0,_react.useCallback)(()=>b(false),[]);const W=(0,_react.useCallback)(()=>b(true),[]);const r=!f;const C=!!e.pending||!!e.awaitingBlockId;const o=e.messages[e.messages.length-1];const y=(0,_react.useRef)(false);const T=(0,_react.useRef)(e.busy);(0,_react.useEffect)(()=>{if(r&&T.current&&!e.busy)y.current=true;if(!r)y.current=false;T.current=e.busy},[r,e.busy]);(0,_react.useEffect)(()=>{if(!r){(0,_sharedUi.setToolAttention)("ask-buoy",null);return}if(C){(0,_sharedUi.setToolAttention)("ask-buoy",{kind:"needsInput",label:e.pending?"Needs your approval":"Has a question for you"})}else if(y.current&&o?.role==="assistant"&&o.error){(0,_sharedUi.setToolAttention)("ask-buoy",{kind:"failed",label:"The last turn failed"})}else if(y.current&&!e.busy){(0,_sharedUi.setToolAttention)("ask-buoy",{kind:"done",label:"Finished"})}else{(0,_sharedUi.setToolAttention)("ask-buoy",null)}},[r,C,e.busy,e.pending,o]);(0,_react.useEffect)(()=>()=>(0,_sharedUi.setToolAttention)("ask-buoy",null),[]);(0,_react.useEffect)(()=>{if(e.pending&&g)b(false)},[e.pending,g]);const G=(0,_sharedUi.useSafeAreaInsets)({minBottom:16});const[J,Y]=(0,_react.useState)("bottomSheet");const X=J==="floating"?0:G.bottom;const Z=(0,_react.useCallback)(()=>{const t=_askBuoyStore.askBuoyStore.getLedger();if(!t)return;void(async()=>{const s=await t.revertAll(_sharedUi.dispatchToolAction);if(s.failed.length===0){_askBuoyStore.askBuoyStore.setNotice(null);return}const n=s.failed.map(l=>`${l.label} (${l.error})`).join("; ");_askBuoyStore.askBuoyStore.setNotice(`Couldn't undo ${s.failed.length} change${s.failed.length===1?"":"s"} \u2014 ${n}`)})()},[]);const ee=(0,_react.useCallback)(()=>z(t=>!t),[]);const i=(0,_react.useRef)(new _reactNative.Animated.Value(560)).current;const m=(0,_react.useRef)(false);const w=(0,_react.useCallback)(()=>{if(m.current)return;m.current=true;i.stopAnimation(t=>{const s=typeof t==="number"&&t>200?t:560;_reactNative.Animated.timing(i,{toValue:120,duration:220,useNativeDriver:false}).start(()=>{setTimeout(()=>{_reactNative.Animated.spring(i,{toValue:s,friction:9,useNativeDriver:false}).start(()=>{m.current=false})},2500)})})},[i]);const p=(0,_react.useMemo)(()=>{const t=e.messages[e.messages.length-1];if(!t||t.role!=="assistant")return"";const s=t.blocks.filter(n=>n.block.kind==="peek").length;return s>0?`${t.id}:${s}`:""},[e.messages]);const j=(0,_react.useRef)("");(0,_react.useEffect)(()=>{if(p&&p!==j.current&&a?.peek!==false)w();j.current=p},[p,w,a]);const te=(0,_react.useCallback)(()=>{const t=_askBuoyStore.askBuoyStore.getLedger();const s=t?.list().filter(n=>!n.undoneAt&&(0,_agentCore.isReversible)(n.effect)).length??0;if(s===0){d();return}_reactNative.Alert.alert("Undo changes first?",`Ask Buoy made ${s} change${s===1?"":"s"} that can still be undone. Clearing the conversation loses the only automatic undo for ${s===1?"it":"them"}.`,[{text:"Undo, then clear",onPress:()=>{void(async()=>{const n=await x();if(n.cleared)return;const l=n.reverted+n.failed.length;const ce=n.failed.map(R=>`${R.label} (${R.error})`).join("\n");_reactNative.Alert.alert(`Couldn't undo ${n.failed.length} of ${l} change${l===1?"":"s"}`,`${ce}
|
|
2
2
|
|
|
3
|
-
Still applied in the app. Clear the conversation anyway?`,[{text:"Keep conversation",style:"cancel"},{text:"Clear anyway",style:"destructive",onPress:d}])})()}},{text:"Clear anyway",style:"destructive",onPress:d},{text:"Cancel",style:"cancel"}])},[d,x]);const se=(0,_react.useMemo)(()=>{const t=e.messages[e.messages.length-1];if(!t||t.role!=="assistant"||!t.streaming)return null;return t.toolCalls.find(s=>s.status==="running")?.label??null},[e.messages]);const q=(0,_ChangesBar.useLedgerEntries)(_askBuoyStore.askBuoyStore.getLedger());const _=(0,_react.useMemo)(()=>(0,_ruleStates.ruleStatesFrom)(q),[q]);const oe=(0,_react.useMemo)(()=>({answer:A,runAction:(t,s)=>{if(t.minimize){u?.({mode:"bottomSheet"});return}return B(t,s)},answered:e.answers,actionState:e.actionState,busy:e.busy,supports:{openTool:false,minimize:!!u,dispatch:true},rules:_}),[A,B,u,e.answers,e.actionState,e.busy,_]);const ne=!e.busy&&o?.role==="assistant"&&!!o.error;const P=!e.busy&&o?.role==="assistant"&&o.stopped&&!o.error?o.id:null;const ae=(0,_askBuoyStore.queuePauseReason)(e);const{showThinking:M,readOnly:H,claudeNoticeSeen:re}=(0,_useAskBuoySettings.useAskBuoySettings)();const I=a?.hosted===true&&!re;const ie=(0,_react.useCallback)(()=>(0,_MessageList.transcriptToText)(e.messages,M),[e.messages,M]);const le=(0,_react.useCallback)(()=>c(_ticketPrompt.TICKET_PROMPT),[c]);const ue=g?(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader,{children:[(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation,{onBack:Q}),(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Content,{title:"Settings",subtitle:"Ask Buoy",testID:"buoy-ask-buoy-settings-title"})]}):(0,_jsxRuntime.jsx)(_AskBuoyHeader.AskBuoyHeader,{configured:k,busy:e.busy,failed:ne,activeLabel:se,awaitingApproval:!!e.pending,startedAt:o?.role==="assistant"&&o.streaming?o.startedAt??null:null,stopping:e.stopping,readOnly:H,toolCount:K,hasMessages:e.messages.length>0,onBack:S,onReset:te,getTranscript:ie,onOpenSettings:W,onTicket:le});return(0,_jsxRuntime.jsx)(_sharedUi.JsModal,{visible:f,onClose:U,disableScrollWrapper:true,
|
|
3
|
+
Still applied in the app. Clear the conversation anyway?`,[{text:"Keep conversation",style:"cancel"},{text:"Clear anyway",style:"destructive",onPress:d}])})()}},{text:"Clear anyway",style:"destructive",onPress:d},{text:"Cancel",style:"cancel"}])},[d,x]);const se=(0,_react.useMemo)(()=>{const t=e.messages[e.messages.length-1];if(!t||t.role!=="assistant"||!t.streaming)return null;return t.toolCalls.find(s=>s.status==="running")?.label??null},[e.messages]);const q=(0,_ChangesBar.useLedgerEntries)(_askBuoyStore.askBuoyStore.getLedger());const _=(0,_react.useMemo)(()=>(0,_ruleStates.ruleStatesFrom)(q),[q]);const oe=(0,_react.useMemo)(()=>({answer:A,runAction:(t,s)=>{if(t.minimize){u?.({mode:"bottomSheet"});return}return B(t,s)},answered:e.answers,actionState:e.actionState,busy:e.busy,supports:{openTool:false,minimize:!!u,dispatch:true},rules:_}),[A,B,u,e.answers,e.actionState,e.busy,_]);const ne=!e.busy&&o?.role==="assistant"&&!!o.error;const P=!e.busy&&o?.role==="assistant"&&o.stopped&&!o.error?o.id:null;const ae=(0,_askBuoyStore.queuePauseReason)(e);const{showThinking:M,readOnly:H,claudeNoticeSeen:re}=(0,_useAskBuoySettings.useAskBuoySettings)();const I=a?.hosted===true&&!re;const ie=(0,_react.useCallback)(()=>(0,_MessageList.transcriptToText)(e.messages,M),[e.messages,M]);const le=(0,_react.useCallback)(()=>c(_ticketPrompt.TICKET_PROMPT),[c]);const ue=g?(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader,{children:[(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation,{onBack:Q}),(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Content,{title:"Settings",subtitle:"Ask Buoy",testID:"buoy-ask-buoy-settings-title"})]}):(0,_jsxRuntime.jsx)(_AskBuoyHeader.AskBuoyHeader,{configured:k,busy:e.busy,failed:ne,activeLabel:se,awaitingApproval:!!e.pending,startedAt:o?.role==="assistant"&&o.streaming?o.startedAt??null:null,stopping:e.stopping,readOnly:H,toolCount:K,hasMessages:e.messages.length>0,onBack:S,onReset:te,getTranscript:ie,onOpenSettings:W,onTicket:le});return(0,_jsxRuntime.jsx)(_sharedUi.JsModal,{avoidKeyboard:false,visible:f,onClose:U,disableScrollWrapper:true,background:false,initialHeight:560,animatedHeight:i,header:{customContent:ue,showToggleButton:false},onBack:S,onMinimize:u,onModeChange:Y,persistenceKey:$??"buoy-ask-buoy",enablePersistence:true,children:(0,_jsxRuntime.jsx)(_blocks.BlockHandlersProvider,{value:oe,children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:[styles.root,{paddingBottom:X}],children:[(0,_jsxRuntime.jsx)(_ChangesBar.ChangesBar,{ledger:_askBuoyStore.askBuoyStore.getLedger(),onUndoAll:Z,expanded:V,onToggle:ee}),I&&(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.notice,testID:"buoy-ask-buoy-hosted-notice",children:[(0,_jsxRuntime.jsx)(_sharedUi.Info,{size:14,color:_sharedUi.night.color.info}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:{flex:1,gap:8},children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.noticeText,children:"Hosted Ask Buoy (beta) sends your question, and the app data it needs to answer, to Anthropic for Claude. If Claude is down, it goes to OpenAI through OpenRouter for Luna instead. Buoy keeps the cost of each answer, never the chat. Your plan includes weekly credits."}),(0,_jsxRuntime.jsx)(_reactNative.Pressable,{testID:"buoy-ask-buoy-hosted-notice-ok",accessibilityRole:"button",onPress:()=>{_askBuoySettings.askBuoySettings.set("claudeNoticeSeen",true);_askBuoySettings.askBuoySettings.set("hostedNoticeSeen",true)},style:({pressed:t})=>[styles.noticeButton,t&&{opacity:.7}],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.noticeButtonText,children:"Got it"})})]})]}),e.notice&&(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.notice,testID:"buoy-ask-buoy-notice",children:[(0,_jsxRuntime.jsx)(_sharedUi.Info,{size:14,color:_sharedUi.night.color.info}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.noticeText,children:e.notice})]}),(0,_jsxRuntime.jsx)(_KeyboardPad.KeyboardPad,{children:(0,_jsxRuntime.jsx)(_sharedUi.FeatureGate,{featureName:"Ask Buoy",children:g?(0,_jsxRuntime.jsx)(_AskBuoySettings.AskBuoySettings,{}):(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(_MessageList.MessageList,{messages:e.messages,onRetry:L,waitingOnUser:!!e.pending||!!e.awaitingBlockId,ListEmptyComponent:(0,_jsxRuntime.jsx)(_EmptyState.EmptyState,{configured:k,onPick:c,availableToolIds:D,readOnly:H||!!a?.policy?.readOnly})}),(0,_jsxRuntime.jsx)(_QueuedMessages.QueuedMessages,{items:e.queued,paused:ae,onEdit:N,onRemove:O}),e.pending&&(0,_jsxRuntime.jsx)(_ApprovalCard.ApprovalCard,{pending:e.pending,onAnswer:E}),(0,_jsxRuntime.jsx)(_Composer.Composer,{onSend:c,onStop:h,busy:e.busy,draft:e.draft,onDraftTaken:F,disabled:!k||I,focusKey:P,canFocus:f,placeholder:P?"Tell it what to do differently\u2026":e.awaitingBlockId?"Pick an option above, or type\u2026":void 0})]})})})]})})})}const styles=_reactNative.StyleSheet.create({root:{flex:1,backgroundColor:"transparent"},notice:{flexDirection:"row",alignItems:"flex-start",gap:8,paddingHorizontal:_sharedUi.night.gutter,paddingVertical:10,backgroundColor:_sharedUi.night.color.infoSoft},noticeText:{flex:1,color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.caption,lineHeight:18},noticeButton:{alignSelf:"flex-start",paddingHorizontal:12,paddingVertical:6,borderRadius:_sharedUi.night.radius.row,backgroundColor:_sharedUi.night.color.button},noticeButtonText:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.caption,fontWeight:"600"}});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.EmptyState=EmptyState;var _sharedUi=require("@buoy-gg/shared-ui");var _reactNative=require("react-native");var _suggestions=require("../store/suggestions");var _jsxRuntime=require("react/jsx-runtime");const isRelease=typeof __DEV__!=="undefined"&&!__DEV__;function EmptyState({configured:e,onPick:t,availableToolIds:o=[],readOnly:i=false}){const r=(0,_suggestions.pickSuggestions)({availableToolIds:o,readOnly:i,isRelease});if(!e){return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.wrap,testID:"buoy-ask-buoy-unconfigured",children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.title,children:"Not set up yet"}),(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.body,children:["Ask Buoy talks to your own company's AI endpoint. Nothing goes to Buoy. A developer needs to add the ",(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.code,children:"askBuoy"})," setting where the app sets up Buoy. It needs your team's endpoint and model."]})]})}return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.wrap,testID:"buoy-ask-buoy-empty",children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.title,children:"Ask about this app"}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.body,children:"Ask what the app is doing right now, or tell it to change something. Anything it changes shows up in a bar at the top, with what can be undone."}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.buildLine,testID:"buoy-ask-buoy-build-line",children:isRelease?"Release build \u2014 reading, impersonation and navigation work; simulations (forcing server responses, driving the screen) need a dev build.":"Dev build \u2014 full simulation available."}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.group,children:[(0,_jsxRuntime.jsx)(_sharedUi.NightSectionLabel,{children:"Try asking"}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.card,children:r.map((n,s)=>(0,_jsxRuntime.jsx)(Suggestion,{text:n,onPick:t,last:s===r.length-1},n))})]})]})}function Suggestion({text:e,onPick:t,last:o}){return(0,_jsxRuntime.jsxs)(_reactNative.Pressable,{testID:`buoy-ask-buoy-suggestion-${e.slice(0,12)}`,accessibilityRole:"button",onPress:()=>t(e),style:({pressed:i})=>[styles.row,!o&&styles.rowDivider,i&&styles.pressed],children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.rowText,children:e}),(0,_jsxRuntime.jsx)(_sharedUi.ChevronRight,{size:14,color:_sharedUi.night.color.textTertiary})]})}const styles=_reactNative.StyleSheet.create({wrap:{flex:1,justifyContent:"center",paddingHorizontal:_sharedUi.night.gutter,paddingVertical:24,gap:8},title:{color:_sharedUi.night.color.text,fontSize:22,fontWeight:"700",letterSpacing:-.3},body:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.body,lineHeight:20},code:{color:_sharedUi.night.color.text,fontFamily:_reactNative.Platform.OS==="web"?_sharedUi.monoFont:"Menlo"},buildLine:{marginTop:8,color:_sharedUi.night.color.textTertiary,fontSize:_sharedUi.night.font.micro,lineHeight:15},group:{marginTop:_sharedUi.night.groupGap-8},card:{borderRadius:_sharedUi.night.radius.card,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.border,backgroundColor:_sharedUi.night.color.surface,overflow:"hidden"},row:{flexDirection:"row",alignItems:"center",gap:10,paddingHorizontal:_sharedUi.night.rowPadH,paddingVertical:13},rowDivider:{borderBottomWidth:_reactNative.StyleSheet.hairlineWidth,borderBottomColor:_sharedUi.night.color.separator},rowText:{flex:1,color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.body,lineHeight:19},pressed:{backgroundColor:_sharedUi.night.color.fill}});
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.EmptyState=EmptyState;var _sharedUi=require("@buoy-gg/shared-ui");var _reactNative=require("react-native");var _suggestions=require("../store/suggestions");var _jsxRuntime=require("react/jsx-runtime");const isRelease=typeof __DEV__!=="undefined"&&!__DEV__;function EmptyState({configured:e,onPick:t,availableToolIds:o=[],readOnly:i=false}){const r=(0,_suggestions.pickSuggestions)({availableToolIds:o,readOnly:i,isRelease});if(!e){return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.wrap,testID:"buoy-ask-buoy-unconfigured",children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.title,children:"Not set up yet"}),(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.body,children:["Ask Buoy talks to your own company's AI endpoint. Nothing goes to Buoy. A developer needs to add the ",(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.code,children:"askBuoy"})," setting. It goes where the app sets up Buoy. It needs your team's endpoint and model."]})]})}return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.wrap,testID:"buoy-ask-buoy-empty",children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.title,children:"Ask about this app"}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.body,children:"Ask what the app is doing right now, or tell it to change something. Anything it changes shows up in a bar at the top, with what can be undone."}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.buildLine,testID:"buoy-ask-buoy-build-line",children:isRelease?"Release build \u2014 reading, impersonation and navigation work; simulations (forcing server responses, driving the screen) need a dev build.":"Dev build \u2014 full simulation available."}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.group,children:[(0,_jsxRuntime.jsx)(_sharedUi.NightSectionLabel,{children:"Try asking"}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.card,children:r.map((n,s)=>(0,_jsxRuntime.jsx)(Suggestion,{text:n,onPick:t,last:s===r.length-1},n))})]})]})}function Suggestion({text:e,onPick:t,last:o}){return(0,_jsxRuntime.jsxs)(_reactNative.Pressable,{testID:`buoy-ask-buoy-suggestion-${e.slice(0,12)}`,accessibilityRole:"button",onPress:()=>t(e),style:({pressed:i})=>[styles.row,!o&&styles.rowDivider,i&&styles.pressed],children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.rowText,children:e}),(0,_jsxRuntime.jsx)(_sharedUi.ChevronRight,{size:14,color:_sharedUi.night.color.textTertiary})]})}const styles=_reactNative.StyleSheet.create({wrap:{flex:1,justifyContent:"center",paddingHorizontal:_sharedUi.night.gutter,paddingVertical:24,gap:8},title:{color:_sharedUi.night.color.text,fontSize:22,fontWeight:"700",letterSpacing:-.3},body:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.body,lineHeight:20},code:{color:_sharedUi.night.color.text,fontFamily:_reactNative.Platform.OS==="web"?_sharedUi.monoFont:"Menlo"},buildLine:{marginTop:8,color:_sharedUi.night.color.textTertiary,fontSize:_sharedUi.night.font.micro,lineHeight:15},group:{marginTop:_sharedUi.night.groupGap-8},card:{borderRadius:_sharedUi.night.radius.card,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.border,backgroundColor:_sharedUi.night.color.surface,overflow:"hidden"},row:{flexDirection:"row",alignItems:"center",gap:10,paddingHorizontal:_sharedUi.night.rowPadH,paddingVertical:13},rowDivider:{borderBottomWidth:_reactNative.StyleSheet.hairlineWidth,borderBottomColor:_sharedUi.night.color.separator},rowText:{flex:1,color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.body,lineHeight:19},pressed:{backgroundColor:_sharedUi.night.color.fill}});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var _vitest=require("vitest");var _AskBlocks=require("../blocks/AskBlocks");var _Composer=require("./Composer");var _EmptyState=require("./EmptyState");_vitest.vi.mock("react",async e=>({...await e(),useState:t=>[typeof t==="function"?t():t,()=>{}],useRef:t=>({current:t}),useEffect:()=>{},useCallback:t=>t}));_vitest.vi.mock("../blocks/context",async e=>({...await e(),useBlockHandlers:()=>({answer:()=>{},runAction:()=>{},answered:{}})}));function elements(e){if(Array.isArray(e))return e.flatMap(elements);if(!e||typeof e!=="object")return[];const t=e;return[t,...elements(t.props?.children)]}function text(e){if(typeof e==="string"||typeof e==="number")return String(e);if(Array.isArray(e))return e.map(text).join("");return e&&typeof e==="object"?text(e.props?.children):""}(0,_vitest.describe)("the setup message",()=>{(0,_vitest.it)("names the setting, not a React component",()=>{const e=text((0,_EmptyState.EmptyState)({configured:false,onPick:()=>{}}));(0,_vitest.expect)(e).toContain("askBuoy");(0,_vitest.expect)(e).not.toContain("FloatingDevTools")})});(0,_vitest.describe)("the message box",()=>{(0,_vitest.it)("has a name a screen reader can say",()=>{const e=elements((0,_Composer.Composer)({onSend:()=>{},onStop:()=>{},busy:false})).find(t=>t.props?.testID==="buoy-ask-buoy-input");(0,_vitest.expect)(e?.props?.accessibilityLabel).toBe("Message for Ask Buoy")})});(0,_vitest.describe)("a choice card",()=>{const e={id:"ask-1",kind:"choice",question:"If you want the value of `e2e-after-local`, ask and I'll read it.",options:[{id:"yes",label:"Yes, go ahead"},{id:"no",label:"No thanks"}]};(0,_vitest.it)("shows the question the model wrote",()=>{(0,_vitest.expect)(text((0,_AskBlocks.Choice)({block:e}))).toContain("e2e-after-local")});(0,_vitest.it)("leaves it out when the answer above already says it",()=>{const t=text((0,_AskBlocks.Choice)({block:{...e,questionInAnswer:true}}));(0,_vitest.expect)(t).not.toContain("e2e-after-local");(0,_vitest.expect)(t).toContain("Yes, go ahead")})});
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.askBuoyStore=void 0;exports.queuePauseReason=queuePauseReason;exports.turnPhaseOf=turnPhaseOf;var _agentCore=require("@buoy-gg/agent-core");var _sharedUi=require("@buoy-gg/shared-ui");var _transcriptPersistence=require("./transcriptPersistence");const nextId=(0,_agentCore.idFactory)("m");const MAX_PARAM_CHARS=400;function encodeParams(t){if(!t||Object.keys(t).length===0)return void 0;try{const e=JSON.stringify(t);return e.length>MAX_PARAM_CHARS?`${e.slice(0,MAX_PARAM_CHARS)}\u2026`:e}catch{return void 0}}const nextQueuedId=(0,_agentCore.idFactory)("q");let state={messages:[],busy:false,stopping:false,pending:null,trusted:[],notice:null,configured:false,answers:{},awaitingBlockId:null,actionState:{},queued:[],draft:null,usage:{input:0,output:0,requests:0},credits:null,claudeOut:false,meta:{}};let reporter=null;let usageReader=null;const listeners=new Set;let ledgerRef=null;let stopLedgerSave=null;let heldSession=null;function set(t){state={...state,...t};for(const e of listeners){try{e()}catch{}}}const askBuoyStore=exports.askBuoyStore={getState:()=>state,subscribe(t){listeners.add(t);return()=>listeners.delete(t)},setLedger(t){if(t===ledgerRef)return;stopLedgerSave?.();ledgerRef=t;stopLedgerSave=t?t.subscribe(()=>void(0,_transcriptPersistence.writeSavedLedger)(t.list())):null},getLedger(){return ledgerRef},holdSession(t,e){heldSession={session:t,signature:e}},getHeldSession(){return heldSession},setReporter(t){reporter=t},getReporter(){return reporter},setUsageReader(t){usageReader=t},getUsageReader(){return usageReader},setNotice(t){set({notice:t})},setConfigured(t){if(t!==state.configured)set({configured:t})},setClaudeOut(t){if(state.claudeOut!==t)set({claudeOut:t})},setMeta(t){const e=Object.keys(t).every(r=>state.meta[r]===t[r]);if(!e)set({meta:{...state.meta,...t}})},addUser(t){set({messages:[...state.messages,{id:nextId(),role:"user",text:t,toolCalls:[],blocks:[]}],busy:true})},beginTurn(){set({busy:true})},enqueue(t){const e={id:nextQueuedId(),text:t};set({queued:[...state.queued,e]});return e},removeQueued(t){if(!state.queued.some(e=>e.id===t))return;set({queued:state.queued.filter(e=>e.id!==t)})},shiftQueued(){const[t,...e]=state.queued;if(!t)return void 0;set({queued:e});return t},takeQueuedToDraft(t){const e=state.queued.find(r=>r.id===t);if(!e)return;set({queued:state.queued.filter(r=>r.id!==t),draft:e.text})},requestStop(){if(!state.busy||state.stopping)return;set({stopping:true})},clearDraft(){if(state.draft===null)return;set({draft:null})},removeMessage(t){set({messages:state.messages.filter(e=>e.id!==t)})},recordAnswer(t){set({answers:{...state.answers,[t.blockId]:t},awaitingBlockId:state.awaitingBlockId===t.blockId?null:state.awaitingBlockId})},setActionState(t,e){const r={...state.actionState};if(e===null)delete r[t];else r[t]=e;set({actionState:r})},startAssistant(){const t=nextId();set({messages:[...state.messages,{id:t,role:"assistant",text:"",toolCalls:[],blocks:[],streaming:true,startedAt:(0,_sharedUi.realNow)()}]});return t},applyEvent(t,e){if(e.type==="history-trimmed"){const s=state.messages.findIndex(
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.askBuoyStore=void 0;exports.queuePauseReason=queuePauseReason;exports.turnPhaseOf=turnPhaseOf;var _agentCore=require("@buoy-gg/agent-core");var _sharedUi=require("@buoy-gg/shared-ui");var _transcriptPersistence=require("./transcriptPersistence");const nextId=(0,_agentCore.idFactory)("m");const MAX_PARAM_CHARS=400;function encodeParams(t){if(!t||Object.keys(t).length===0)return void 0;try{const e=JSON.stringify(t);return e.length>MAX_PARAM_CHARS?`${e.slice(0,MAX_PARAM_CHARS)}\u2026`:e}catch{return void 0}}const nextQueuedId=(0,_agentCore.idFactory)("q");let state={messages:[],busy:false,stopping:false,pending:null,trusted:[],notice:null,configured:false,answers:{},awaitingBlockId:null,actionState:{},queued:[],draft:null,usage:{input:0,output:0,requests:0},credits:null,claudeOut:false,meta:{}};let reporter=null;let usageReader=null;const listeners=new Set;let ledgerRef=null;let stopLedgerSave=null;let heldSession=null;function set(t){state={...state,...t};for(const e of listeners){try{e()}catch{}}}const askBuoyStore=exports.askBuoyStore={getState:()=>state,subscribe(t){listeners.add(t);return()=>listeners.delete(t)},setLedger(t){if(t===ledgerRef)return;stopLedgerSave?.();ledgerRef=t;stopLedgerSave=t?t.subscribe(()=>void(0,_transcriptPersistence.writeSavedLedger)(t.list())):null},getLedger(){return ledgerRef},holdSession(t,e){heldSession={session:t,signature:e}},getHeldSession(){return heldSession},setReporter(t){reporter=t},getReporter(){return reporter},setUsageReader(t){usageReader=t},getUsageReader(){return usageReader},setNotice(t){set({notice:t})},setConfigured(t){if(t!==state.configured)set({configured:t})},setClaudeOut(t){if(state.claudeOut!==t)set({claudeOut:t})},setMeta(t){const e=Object.keys(t).every(r=>state.meta[r]===t[r]);if(!e)set({meta:{...state.meta,...t}})},addUser(t){set({messages:[...state.messages,{id:nextId(),role:"user",text:t,toolCalls:[],blocks:[]}],busy:true})},beginTurn(){set({busy:true})},enqueue(t){const e={id:nextQueuedId(),text:t};set({queued:[...state.queued,e]});return e},removeQueued(t){if(!state.queued.some(e=>e.id===t))return;set({queued:state.queued.filter(e=>e.id!==t)})},shiftQueued(){const[t,...e]=state.queued;if(!t)return void 0;set({queued:e});return t},takeQueuedToDraft(t){const e=state.queued.find(r=>r.id===t);if(!e)return;set({queued:state.queued.filter(r=>r.id!==t),draft:e.text})},requestStop(){if(!state.busy||state.stopping)return;set({stopping:true})},clearDraft(){if(state.draft===null)return;set({draft:null})},removeMessage(t){set({messages:state.messages.filter(e=>e.id!==t)})},recordAnswer(t){set({answers:{...state.answers,[t.blockId]:t},awaitingBlockId:state.awaitingBlockId===t.blockId?null:state.awaitingBlockId})},setActionState(t,e){const r={...state.actionState};if(e===null)delete r[t];else r[t]=e;set({actionState:r})},startAssistant(){const t=nextId();set({messages:[...state.messages,{id:t,role:"assistant",text:"",toolCalls:[],blocks:[],streaming:true,startedAt:(0,_sharedUi.realNow)()}]});return t},applyEvent(t,e){if(e.type==="history-trimmed"){const s=state.messages.findIndex(o=>o.id===t);const n={id:nextId(),role:"assistant",system:true,text:`Older messages were trimmed from the agent's memory (${e.droppedRounds} exchange${e.droppedRounds===1?"":"s"}).`+(e.droppedPinned?` ${e.droppedPinned===1?"One of them made a change that is":`${e.droppedPinned} of them made changes that are`} still applied \u2014 the changes bar still lists ${e.droppedPinned===1?"it":"them"}, but the agent no longer remembers making ${e.droppedPinned===1?"it":"them"}.`:" It may not recall setup from earlier in this chat \u2014 the changes bar still lists what is applied."),toolCalls:[],blocks:[],endedAt:(0,_sharedUi.realNow)()};const a=[...state.messages];a.splice(s<0?a.length:s,0,n);set({messages:a});return}const r=state.messages.map(s=>{if(s.id!==t)return s;switch(e.type){case"retrying":{const n=Math.max(1,Math.round(e.inMs/1e3));return{...s,waiting:e.reason==="throttled"?`Endpoint busy \u2014 retrying in ${n}s (${e.attempt} of ${e.maxAttempts})`:e.reason==="network"?"Connection dropped \u2014 trying again":`Request too large \u2014 trimming older messages and retrying`}}case"text":return{...s,waiting:void 0,text:(s.breakBeforeNextText||e.breakBefore)&&s.text?`${s.text.trimEnd()}
|
|
2
2
|
|
|
3
|
-
${e.delta}`:s.text+e.delta,breakBeforeNextText:false};case"reasoning":return{...s,breakBeforeNextText:true,reasoning:[...s.reasoning??[],{text:e.text,afterCalls:s.toolCalls.length}]};case"tool-start":return{...s,waiting:void 0,toolCalls:[...s.toolCalls,{id:e.id,toolId:e.toolId,action:e.action,label:e.label,description:e.description,status:"running",params:encodeParams(e.params),effect:e.effect,startedAt:(0,_sharedUi.realNow)()}]};case"tool-end":return{...s,breakBeforeNextText:true,toolCalls:s.toolCalls.map(n=>n.id===e.id?{...n,status:!e.ok&&e.summary==="refused"?"refused":!e.ok&&e.summary==="declined"?"declined":!e.ok&&e.summary==="stopped"?"stopped":e.ok?"ok":"failed",summary:e.summary,durationMs:e.durationMs,result:e.result}:n)};case"tool-verified":return{...s,toolCalls:s.toolCalls.map(n=>n.id===e.id?{...n,verification:e.verification}:n)};case"block":return{...s,breakBeforeNextText:true,blocks:[...s.blocks,{block:e.block,forToolCallId:e.forToolCallId}]};case"usage":return{...s,usage:{input:(s.usage?.input??0)+e.input,output:(s.usage?.output??0)+e.output,requests:(s.usage?.requests??0)+1}};case"error":return{...s,waiting:void 0,error:e.message,...e.hosted?{errorInfo:{code:e.hosted.code,requestId:e.hosted.request_id,action:e.hosted.action,resetAt:e.hosted.reset_at,helpUrl:e.hosted.help_url}}:{}};default:return s}});set({messages:r,...e.type==="awaiting-user"?{awaitingBlockId:e.blockId}:{},...e.type==="error"&&e.hosted?.code==="claude_paused"?{claudeOut:true}:{},...e.type==="meter"&&e.frame.phase==="end"?{credits:{left:e.frame.credits_left??state.credits?.left??null,resetAt:e.frame.credits_reset??state.credits?.resetAt??null,pending:e.frame.pending===true}}:{},...e.type==="usage"?{usage:{input:state.usage.input+e.input,output:state.usage.output+e.output,requests:state.usage.requests+1}}:{}})},markStopped(t){set({messages:state.messages.map(e=>e.id===t?{...e,stopped:true}:e)})},finishAssistant(t){set({messages:state.messages.map(e=>e.id===t?{...e,streaming:false,endedAt:(0,_sharedUi.realNow)()}:e),busy:false,stopping:false})},askApproval(t){return new Promise(e=>{set({pending:{...t,resolve:e}})})},answerApproval(t){const e=state.pending;const r=typeof t==="boolean"?t:t.approved;const s=typeof t!=="boolean"&&t.trust===true&&r;const n=e?`${e.toolId}.${e.action}`:"";set({pending:null,...s&&e&&!state.trusted.some(a=>a.key===n)?{trusted:[...state.trusted,{key:n,label:e.label}]}:{}});e?.resolve(t)},untrust(t){heldSession?.session.untrust(t);set({trusted:state.trusted.filter(e=>e.key!==t)})},restorePending(t){if(state.pending||state.busy)return false;set({pending:{...t,restored:true,resolve:()=>{}}});return true},addNote(t){set({messages:[...state.messages,{id:nextId(),role:"assistant",text:t,toolCalls:[],blocks:[],endedAt:(0,_sharedUi.realNow)()}]})},hydrate(t){if(state.messages.length>0||state.busy)return false;set({messages:t.messages.map(e=>({...e,restored:true})),answers:t.answers,usage:t.usage,queued:t.queued??[]});return true},reset(){state.pending?.resolve(false);set({messages:[],busy:false,stopping:false,pending:null,trusted:[],notice:null,answers:{},awaitingBlockId:null,actionState:{},queued:[],draft:null,usage:{input:0,output:0,requests:0}})}};function turnPhaseOf(t){if(t.pending)return"awaitingApproval";if(t.busy)return t.stopping?"stopping":"running";if(t.awaitingBlockId)return"awaitingAnswer";return"idle"}function queuePauseReason(t){const e=turnPhaseOf(t);if(e==="running"||e==="stopping")return null;if(e==="awaitingApproval")return"Paused \u2014 answer the approval above first.";if(e==="awaitingAnswer")return"Paused \u2014 answer the question above first.";const r=t.messages[t.messages.length-1];if(r?.role==="assistant"&&r.error)return"Paused \u2014 the last turn failed.";if(r?.role==="assistant"&&r.stopped)return"Paused \u2014 you stopped the last turn.";return null}
|
|
3
|
+
${e.delta}`:s.text+e.delta,breakBeforeNextText:false};case"reasoning":return{...s,breakBeforeNextText:true,reasoning:[...s.reasoning??[],{text:e.text,afterCalls:s.toolCalls.length}]};case"tool-start":return{...s,waiting:void 0,toolCalls:[...s.toolCalls,{id:e.id,toolId:e.toolId,action:e.action,label:e.label,description:e.description,status:"running",params:encodeParams(e.params),effect:e.effect,startedAt:(0,_sharedUi.realNow)()}]};case"tool-end":return{...s,breakBeforeNextText:true,toolCalls:s.toolCalls.map(n=>n.id===e.id?{...n,status:!e.ok&&e.summary==="refused"?"refused":!e.ok&&e.summary==="declined"?"declined":!e.ok&&e.summary==="stopped"?"stopped":e.ok?"ok":"failed",summary:e.summary,durationMs:e.durationMs,result:e.result}:n)};case"tool-verified":return{...s,toolCalls:s.toolCalls.map(n=>n.id===e.id?{...n,verification:e.verification}:n)};case"block":return{...s,breakBeforeNextText:true,blocks:[...s.blocks,{block:e.block,forToolCallId:e.forToolCallId}]};case"done":return e.stopReason==="realm-died"?{...s,reloadedApp:true}:s;case"usage":return{...s,usage:{input:(s.usage?.input??0)+e.input,output:(s.usage?.output??0)+e.output,requests:(s.usage?.requests??0)+1}};case"error":return{...s,waiting:void 0,error:e.message,...e.hosted?{errorInfo:{code:e.hosted.code,requestId:e.hosted.request_id,action:e.hosted.action,resetAt:e.hosted.reset_at,helpUrl:e.hosted.help_url}}:{}};default:return s}});set({messages:r,...e.type==="awaiting-user"?{awaitingBlockId:e.blockId}:{},...e.type==="error"&&e.hosted?.code==="claude_paused"?{claudeOut:true}:{},...e.type==="meter"&&e.frame.phase==="end"?{credits:{left:e.frame.credits_left??state.credits?.left??null,resetAt:e.frame.credits_reset??state.credits?.resetAt??null,pending:e.frame.pending===true}}:{},...e.type==="usage"?{usage:{input:state.usage.input+e.input,output:state.usage.output+e.output,requests:state.usage.requests+1}}:{}})},markStopped(t){set({messages:state.messages.map(e=>e.id===t?{...e,stopped:true}:e)})},finishAssistant(t){set({messages:state.messages.map(e=>e.id===t?{...e,streaming:false,endedAt:(0,_sharedUi.realNow)()}:e),busy:false,stopping:false})},askApproval(t){return new Promise(e=>{set({pending:{...t,resolve:e}})})},answerApproval(t){const e=state.pending;const r=typeof t==="boolean"?t:t.approved;const s=typeof t!=="boolean"&&t.trust===true&&r;const n=e?`${e.toolId}.${e.action}`:"";set({pending:null,...s&&e&&!state.trusted.some(a=>a.key===n)?{trusted:[...state.trusted,{key:n,label:e.label}]}:{}});e?.resolve(t)},untrust(t){heldSession?.session.untrust(t);set({trusted:state.trusted.filter(e=>e.key!==t)})},restorePending(t){if(state.pending||state.busy)return false;set({pending:{...t,restored:true,resolve:()=>{}}});return true},addNote(t){set({messages:[...state.messages,{id:nextId(),role:"assistant",text:t,toolCalls:[],blocks:[],endedAt:(0,_sharedUi.realNow)()}]})},hydrate(t){if(state.messages.length>0||state.busy)return false;set({messages:t.messages.map(e=>({...e,restored:true})),answers:t.answers,usage:t.usage,queued:t.queued??[]});return true},reset(){state.pending?.resolve(false);set({messages:[],busy:false,stopping:false,pending:null,trusted:[],notice:null,answers:{},awaitingBlockId:null,actionState:{},queued:[],draft:null,usage:{input:0,output:0,requests:0}})}};function turnPhaseOf(t){if(t.pending)return"awaitingApproval";if(t.busy)return t.stopping?"stopping":"running";if(t.awaitingBlockId)return"awaitingAnswer";return"idle"}function queuePauseReason(t){const e=turnPhaseOf(t);if(e==="running"||e==="stopping")return null;if(e==="awaitingApproval")return"Paused \u2014 answer the approval above first.";if(e==="awaitingAnswer")return"Paused \u2014 answer the question above first.";const r=t.messages[t.messages.length-1];if(r?.role==="assistant"&&r.error)return"Paused \u2014 the last turn failed.";if(r?.role==="assistant"&&r.stopped)return"Paused \u2014 you stopped the last turn.";return null}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.TRANSCRIPT_KEY=void 0;exports.buildPayload=buildPayload;exports.clearTranscript=clearTranscript;exports.fitToCaps=fitToCaps;exports.parsePayload=parsePayload;exports.readTranscript=readTranscript;exports.writeSavedLedger=writeSavedLedger;exports.writeTranscript=writeTranscript;var _sharedUi=require("@buoy-gg/shared-ui");var _wire=require("../sync/wire");const TRANSCRIPT_KEY=exports.TRANSCRIPT_KEY=`${_sharedUi.devToolsStorageKeys.base}_ask_buoy_transcript`;const VERSION=1;const MAX_MESSAGES=60;const MAX_BYTES=256e3;const DROPPED_RESULT="[not kept across a restart \u2014 read it again if you need it]";function scrub(t){return t?(0,_wire.redactForWire)(t):t}function settle(t){const e=t.streaming===true;return{...t,text:scrub(t.text),streaming:false,reasoning:t.reasoning?.map(r=>({...r,text:scrub(r.text)})),toolCalls:t.toolCalls.map(r=>{const s=r.params?scrub(r.params):void 0;const{result:a,...n}=r;return r.status==="running"?{...n,params:s,status:"failed",summary:"Interrupted"}:{...n,params:s}}),error:t.error??(e&&!t.text?"This answer was interrupted \u2014 the app restarted mid-turn.":void 0)}}function withoutResults(t){return t.map(e=>{if(e.role==="tool-results"){return{...e,results:e.results.map(r=>({...r,content:DROPPED_RESULT}))}}if(e.role==="assistant")return{...e,text:scrub(e.text)};return{...e,text:scrub(e.text)}})}function fitToCaps(t){let e={...t,messages:t.messages.slice(-MAX_MESSAGES),history:t.history.slice(-MAX_MESSAGES*2)};let r=JSON.stringify(e);while(r.length>MAX_BYTES&&e.messages.length>1){e={...e,messages:e.messages.slice(1),history:e.history.slice(Math.min(2,e.history.length))};r=JSON.stringify(e)}return e}function storableApproval(t){if(!t)return null;const e=t.params;if(!e)return null;let r;try{r=JSON.stringify(e)}catch{return null}if((0,_wire.redactForWire)(r)!==r)return null;return{id:t.id,toolId:t.toolId,action:t.action,label:scrub(t.label),description:t.description?scrub(t.description):void 0,reason:scrub(t.reason),params:e,targetDigest:t.targetDigest}}function isStoredApproval(t){if(typeof t!=="object"||t===null)return false;const e=t;return typeof e.id==="string"&&typeof e.toolId==="string"&&typeof e.action==="string"&&typeof e.label==="string"&&typeof e.reason==="string"&&typeof e.params==="object"&&e.params!==null}function storableLedger(t){if(!t?.length)return void 0;const e=t.filter(r=>{try{const s=JSON.stringify(r);return(0,_wire.redactForWire)(s)===s}catch{return false}});return e.length?e:void 0}function buildPayload(t){return fitToCaps({v:VERSION,savedAt:Date.now(),messages:t.messages.map(settle),history:withoutResults(t.history),answers:t.answers,usage:t.usage,pending:storableApproval(t.pending),ledger:storableLedger(t.ledger),queued:t.queued?.length?t.queued.map(e=>({id:e.id,text:scrub(e.text)})):void 0})}function parsePayload(t){if(!t)return null;try{const e=JSON.parse(t);if(e?.v!==VERSION||!Array.isArray(e.messages))return null;if(e.messages.length===0)return null;return{v:VERSION,savedAt:typeof e.savedAt==="number"?e.savedAt:0,messages:e.messages,history:Array.isArray(e.history)?e.history:[],answers:e.answers??{},usage:e.usage??{input:0,output:0,requests:0},pending:isStoredApproval(e.pending)?e.pending:null,ledger:Array.isArray(e.ledger)?e.ledger.filter(r=>typeof r==="object"&&r!==null&&typeof r.id==="string"):void 0,queued:Array.isArray(e.queued)?e.queued.filter(r=>typeof r==="object"&&r!==null&&typeof r.id==="string"&&typeof r.text==="string"):void 0}}catch{return null}}async function readTranscript(){try{return parsePayload(await _sharedUi.persistentStorage.getItem(TRANSCRIPT_KEY))}catch{return null}}let writeEpoch=0;async function writeTranscript(t){writeEpoch+=1;try{await _sharedUi.persistentStorage.setItem(TRANSCRIPT_KEY,JSON.stringify(t))}catch{}}async function writeSavedLedger(t){const e=writeEpoch;const r=await readTranscript();if(!r||e!==writeEpoch)return;await writeTranscript(fitToCaps({...r,ledger:storableLedger(t)}))}async function clearTranscript(){writeEpoch+=1;try{await _sharedUi.persistentStorage.removeItem(TRANSCRIPT_KEY)}catch{}}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.TRANSCRIPT_KEY=exports.RESUME_AFTER_RELOAD=exports.RELOAD_NOTE=void 0;exports.afterReload=afterReload;exports.buildPayload=buildPayload;exports.clearTranscript=clearTranscript;exports.fitToCaps=fitToCaps;exports.parsePayload=parsePayload;exports.readTranscript=readTranscript;exports.writeSavedLedger=writeSavedLedger;exports.writeTranscript=writeTranscript;var _sharedUi=require("@buoy-gg/shared-ui");var _wire=require("../sync/wire");const TRANSCRIPT_KEY=exports.TRANSCRIPT_KEY=`${_sharedUi.devToolsStorageKeys.base}_ask_buoy_transcript`;const VERSION=1;const MAX_MESSAGES=60;const MAX_BYTES=256e3;const DROPPED_RESULT="[not kept across a restart \u2014 read it again if you need it]";function scrub(t){return t?(0,_wire.redactForWire)(t):t}function settle(t){const e=t.streaming===true;return{...t,text:scrub(t.text),streaming:false,reasoning:t.reasoning?.map(r=>({...r,text:scrub(r.text)})),toolCalls:t.toolCalls.map(r=>{const s=r.params?scrub(r.params):void 0;const{result:a,...n}=r;return r.status==="running"?{...n,params:s,status:"failed",summary:"Interrupted"}:{...n,params:s}}),error:t.error??(e&&!t.text?"This answer was interrupted \u2014 the app restarted mid-turn.":void 0)}}function withoutResults(t){return t.map(e=>{if(e.role==="tool-results"){return{...e,results:e.results.map(r=>({...r,content:DROPPED_RESULT}))}}if(e.role==="assistant")return{...e,text:scrub(e.text)};return{...e,text:scrub(e.text)}})}function fitToCaps(t){let e={...t,messages:t.messages.slice(-MAX_MESSAGES),history:t.history.slice(-MAX_MESSAGES*2)};let r=JSON.stringify(e);while(r.length>MAX_BYTES&&e.messages.length>1){e={...e,messages:e.messages.slice(1),history:e.history.slice(Math.min(2,e.history.length))};r=JSON.stringify(e)}return e}function storableApproval(t){if(!t)return null;const e=t.params;if(!e)return null;let r;try{r=JSON.stringify(e)}catch{return null}if((0,_wire.redactForWire)(r)!==r)return null;return{id:t.id,toolId:t.toolId,action:t.action,label:scrub(t.label),description:t.description?scrub(t.description):void 0,reason:scrub(t.reason),params:e,targetDigest:t.targetDigest}}function isStoredApproval(t){if(typeof t!=="object"||t===null)return false;const e=t;return typeof e.id==="string"&&typeof e.toolId==="string"&&typeof e.action==="string"&&typeof e.label==="string"&&typeof e.reason==="string"&&typeof e.params==="object"&&e.params!==null}function storableLedger(t){if(!t?.length)return void 0;const e=t.filter(r=>{try{const s=JSON.stringify(r);return(0,_wire.redactForWire)(s)===s}catch{return false}});return e.length?e:void 0}function buildPayload(t){return fitToCaps({v:VERSION,savedAt:Date.now(),messages:t.messages.map(settle),history:withoutResults(t.history),answers:t.answers,usage:t.usage,pending:storableApproval(t.pending),ledger:storableLedger(t.ledger),queued:t.queued?.length?t.queued.map(e=>({id:e.id,text:scrub(e.text)})):void 0})}function parsePayload(t){if(!t)return null;try{const e=JSON.parse(t);if(e?.v!==VERSION||!Array.isArray(e.messages))return null;if(e.messages.length===0)return null;return{v:VERSION,savedAt:typeof e.savedAt==="number"?e.savedAt:0,messages:e.messages,history:Array.isArray(e.history)?e.history:[],answers:e.answers??{},usage:e.usage??{input:0,output:0,requests:0},pending:isStoredApproval(e.pending)?e.pending:null,ledger:Array.isArray(e.ledger)?e.ledger.filter(r=>typeof r==="object"&&r!==null&&typeof r.id==="string"):void 0,queued:Array.isArray(e.queued)?e.queued.filter(r=>typeof r==="object"&&r!==null&&typeof r.id==="string"&&typeof r.text==="string"):void 0}}catch{return null}}const RESUME_AFTER_RELOAD=exports.RESUME_AFTER_RELOAD="The app reloaded. Please finish what you were doing.";const RELOAD_NOTE=exports.RELOAD_NOTE='The app reloaded during my last step. Say "continue" to finish.';const RESUME_WINDOW_MS=2*6e4;function afterReload(t,e){const r=t.messages[t.messages.length-1];if(r?.role!=="assistant"||!r.reloadedApp)return null;const s=[...t.messages].reverse().find(n=>n.role==="user");const a=e-t.savedAt<RESUME_WINDOW_MS;return a&&s?.text!==RESUME_AFTER_RELOAD?"resume":"note"}async function readTranscript(){try{return parsePayload(await _sharedUi.persistentStorage.getItem(TRANSCRIPT_KEY))}catch{return null}}let writeEpoch=0;async function writeTranscript(t){writeEpoch+=1;try{await _sharedUi.persistentStorage.setItem(TRANSCRIPT_KEY,JSON.stringify(t))}catch{}}async function writeSavedLedger(t){const e=writeEpoch;const r=await readTranscript();if(!r||e!==writeEpoch)return;await writeTranscript(fitToCaps({...r,ledger:storableLedger(t)}))}async function clearTranscript(){writeEpoch+=1;try{await _sharedUi.persistentStorage.removeItem(TRANSCRIPT_KEY)}catch{}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var _vitest=require("vitest");var _transcriptPersistence=require("./transcriptPersistence");const msg=(e={})=>({id:"m1",role:"assistant",text:"ok",toolCalls:[],blocks:[],...e});const build=(e,s=[])=>(0,_transcriptPersistence.buildPayload)({messages:e,history:s,answers:{},usage:{input:0,output:0,requests:0}});(0,_vitest.describe)("what reaches the disk",()=>{(0,_vitest.it)("never writes a tool result",()=>{const e=[{role:"user",text:"what's in the bag?"},{role:"assistant",text:"",toolCalls:[{id:"c1",name:"buoy_zustand",input:{}}]},{role:"tool-results",results:[{toolCallId:"c1",content:'{"lines":[{"card":"4111111111111111"}]}'}]},{role:"assistant",text:"Five items."}];const s=build([msg()],e);const t=JSON.stringify(s);(0,_vitest.expect)(t).not.toContain("4111111111111111");(0,_vitest.expect)(s.history.map(a=>a.role)).toEqual(["user","assistant","tool-results","assistant"])});(0,_vitest.it)("never writes a step's result, even when it writes the step",()=>{const e=build([msg({toolCalls:[{id:"c1",toolId:"zustand",action:"getStoreState",label:"Read the bag",status:"ok",summary:"Done",params:'{"storeName":"bag"}',result:'{"card":"4111111111111111"}'}]})]);(0,_vitest.expect)(JSON.stringify(e)).not.toContain("4111111111111111");(0,_vitest.expect)(e.messages[0].toolCalls[0].result).toBeUndefined();(0,_vitest.expect)(e.messages[0].toolCalls[0].action).toBe("getStoreState")});(0,_vitest.it)("scrubs credential shapes out of what the agent said",()=>{const e=build([msg({text:"The header was Bearer abcdefghijklmnop123456"})]);(0,_vitest.expect)(e.messages[0].text).not.toContain("abcdefghijklmnop123456")});(0,_vitest.it)("caps a long session instead of growing a file forever",()=>{const e=Array.from({length:400},(t,a)=>msg({id:`m${a}`,text:`answer ${a}`}));const s=build(e);(0,_vitest.expect)(s.messages.length).toBeLessThanOrEqual(60);(0,_vitest.expect)(s.messages[s.messages.length-1].text).toBe("answer 399")});(0,_vitest.it)("drops from the oldest end until a heavy transcript fits",()=>{const e=Array.from({length:20},(t,a)=>msg({id:`m${a}`,text:"x".repeat(4e4)}));const s=(0,_transcriptPersistence.fitToCaps)({v:1,savedAt:0,messages:e,history:[],answers:{},usage:{input:0,output:0,requests:0}});(0,_vitest.expect)(JSON.stringify(s).length).toBeLessThanOrEqual(256e3);(0,_vitest.expect)(s.messages.length).toBeGreaterThan(0)})});(0,_vitest.describe)("what comes back",()=>{(0,_vitest.it)("marks a turn the app died in as interrupted rather than blank",()=>{const e=build([msg({text:"",streaming:true})]);(0,_vitest.expect)(e.messages[0].streaming).toBe(false);(0,_vitest.expect)(e.messages[0].error).toMatch(/interrupted/i)});(0,_vitest.it)("never restores a tool call still claiming to run",()=>{const e=build([msg({streaming:true,toolCalls:[{id:"c1",toolId:"storage",action:"set",label:"Write a key",status:"running"}]})]);(0,_vitest.expect)(e.messages[0].toolCalls[0].status).toBe("failed");(0,_vitest.expect)(e.messages[0].toolCalls[0].summary).toBe("Interrupted")});(0,_vitest.it)("keeps an answer that already finished exactly as it was",()=>{const e=build([msg({text:"Five items.",streaming:false})]);(0,_vitest.expect)(e.messages[0].error).toBeUndefined();(0,_vitest.expect)(e.messages[0].text).toBe("Five items.")});(0,_vitest.it)("treats anything it cannot trust as no transcript at all",()=>{(0,_vitest.expect)((0,_transcriptPersistence.parsePayload)(null)).toBeNull();(0,_vitest.expect)((0,_transcriptPersistence.parsePayload)("not json")).toBeNull();(0,_vitest.expect)((0,_transcriptPersistence.parsePayload)(JSON.stringify({v:0,messages:[msg()]}))).toBeNull();(0,_vitest.expect)((0,_transcriptPersistence.parsePayload)(JSON.stringify({v:1,messages:[]}))).toBeNull()});(0,_vitest.it)("round-trips a real conversation",()=>{const e=build([msg({role:"user",text:"hi"}),msg({id:"m2",text:"hello"})]);const s=(0,_transcriptPersistence.parsePayload)(JSON.stringify(e));(0,_vitest.expect)(s?.messages.map(t=>t.text)).toEqual(["hi","hello"])})});(0,_vitest.describe)("an unanswered approval",()=>{const e={id:"c1",toolId:"zustand",action:"setState",label:"Update the Pok\xE9 Mart bag store",description:"Change a live zustand store.",reason:"This will change the app's state.",params:{storeName:"bag",data:{lines:[]}},resolve:()=>{}};const s=(t={})=>(0,_transcriptPersistence.buildPayload)({messages:[msg()],history:[],answers:{},usage:{input:0,output:0,requests:0},pending:{...e,...t}});(0,_vitest.it)("survives the round trip with the exact call it asked about",()=>{const t=(0,_transcriptPersistence.parsePayload)(JSON.stringify(s()));(0,_vitest.expect)(t?.pending).toMatchObject({toolId:"zustand",action:"setState",label:"Update the Pok\xE9 Mart bag store",params:{storeName:"bag",data:{lines:[]}}})});(0,_vitest.it)("is saved again after it has already been restored once",()=>{(0,_vitest.expect)(s({restored:true}).pending).toBeTruthy()});(0,_vitest.it)("is dropped rather than scrubbed when the call carries a credential",()=>{const t=s({params:{key:"auth",value:"Bearer abcdefghijklmnop123456"}});(0,_vitest.expect)(t.pending).toBeNull();(0,_vitest.expect)(JSON.stringify(t)).not.toContain("abcdefghijklmnop123456")});(0,_vitest.it)("reads back as absent from a transcript written before it existed",()=>{const t=build([msg()]);(0,_vitest.expect)((0,_transcriptPersistence.parsePayload)(JSON.stringify(t))?.pending).toBeNull()});(0,_vitest.it)("refuses a malformed one rather than restoring half a question",()=>{const t=JSON.stringify({...build([msg()]),pending:{toolId:"zustand"}});(0,_vitest.expect)((0,_transcriptPersistence.parsePayload)(t)?.pending).toBeNull()})});(0,_vitest.describe)("the effect ledger",()=>{const e={id:"fx-1-1",at:1,toolId:"storage",action:"async.setItem",effect:{kind:"storage-write",toolId:"storage",action:"async.setItem",label:"Save @qa/key",key:"@qa/key",had:true,previous:"old value"}};const s=t=>(0,_transcriptPersistence.buildPayload)({messages:[msg()],history:[],answers:{},usage:{input:0,output:0,requests:0},ledger:t});(0,_vitest.it)("survives the round trip with the prior value an undo needs",()=>{const t=(0,_transcriptPersistence.parsePayload)(JSON.stringify(s([e])));(0,_vitest.expect)(t?.ledger).toHaveLength(1);(0,_vitest.expect)(t?.ledger?.[0]).toMatchObject({toolId:"storage",action:"async.setItem"})});(0,_vitest.it)("drops an entry holding a credential rather than rewriting it",()=>{const t={...e,effect:{...e.effect,previous:"Bearer abcdefghijklmnop123456"}};const a=s([t]);(0,_vitest.expect)(a.ledger).toBeUndefined();(0,_vitest.expect)(JSON.stringify(a)).not.toContain("abcdefghijklmnop123456")});(0,_vitest.it)("reads back as absent from a transcript written before it existed",()=>{(0,_vitest.expect)((0,_transcriptPersistence.parsePayload)(JSON.stringify(build([msg()])))?.ledger).toBeUndefined()})});
|
|
1
|
+
"use strict";var _vitest=require("vitest");var _transcriptPersistence=require("./transcriptPersistence");var _askBuoyStore=require("./askBuoyStore");const msg=(e={})=>({id:"m1",role:"assistant",text:"ok",toolCalls:[],blocks:[],...e});const build=(e,s=[])=>(0,_transcriptPersistence.buildPayload)({messages:e,history:s,answers:{},usage:{input:0,output:0,requests:0}});(0,_vitest.describe)("what reaches the disk",()=>{(0,_vitest.it)("never writes a tool result",()=>{const e=[{role:"user",text:"what's in the bag?"},{role:"assistant",text:"",toolCalls:[{id:"c1",name:"buoy_zustand",input:{}}]},{role:"tool-results",results:[{toolCallId:"c1",content:'{"lines":[{"card":"4111111111111111"}]}'}]},{role:"assistant",text:"Five items."}];const s=build([msg()],e);const t=JSON.stringify(s);(0,_vitest.expect)(t).not.toContain("4111111111111111");(0,_vitest.expect)(s.history.map(a=>a.role)).toEqual(["user","assistant","tool-results","assistant"])});(0,_vitest.it)("never writes a step's result, even when it writes the step",()=>{const e=build([msg({toolCalls:[{id:"c1",toolId:"zustand",action:"getStoreState",label:"Read the bag",status:"ok",summary:"Done",params:'{"storeName":"bag"}',result:'{"card":"4111111111111111"}'}]})]);(0,_vitest.expect)(JSON.stringify(e)).not.toContain("4111111111111111");(0,_vitest.expect)(e.messages[0].toolCalls[0].result).toBeUndefined();(0,_vitest.expect)(e.messages[0].toolCalls[0].action).toBe("getStoreState")});(0,_vitest.it)("scrubs credential shapes out of what the agent said",()=>{const e=build([msg({text:"The header was Bearer abcdefghijklmnop123456"})]);(0,_vitest.expect)(e.messages[0].text).not.toContain("abcdefghijklmnop123456")});(0,_vitest.it)("caps a long session instead of growing a file forever",()=>{const e=Array.from({length:400},(t,a)=>msg({id:`m${a}`,text:`answer ${a}`}));const s=build(e);(0,_vitest.expect)(s.messages.length).toBeLessThanOrEqual(60);(0,_vitest.expect)(s.messages[s.messages.length-1].text).toBe("answer 399")});(0,_vitest.it)("drops from the oldest end until a heavy transcript fits",()=>{const e=Array.from({length:20},(t,a)=>msg({id:`m${a}`,text:"x".repeat(4e4)}));const s=(0,_transcriptPersistence.fitToCaps)({v:1,savedAt:0,messages:e,history:[],answers:{},usage:{input:0,output:0,requests:0}});(0,_vitest.expect)(JSON.stringify(s).length).toBeLessThanOrEqual(256e3);(0,_vitest.expect)(s.messages.length).toBeGreaterThan(0)})});(0,_vitest.describe)("what comes back",()=>{(0,_vitest.it)("marks a turn the app died in as interrupted rather than blank",()=>{const e=build([msg({text:"",streaming:true})]);(0,_vitest.expect)(e.messages[0].streaming).toBe(false);(0,_vitest.expect)(e.messages[0].error).toMatch(/interrupted/i)});(0,_vitest.it)("never restores a tool call still claiming to run",()=>{const e=build([msg({streaming:true,toolCalls:[{id:"c1",toolId:"storage",action:"set",label:"Write a key",status:"running"}]})]);(0,_vitest.expect)(e.messages[0].toolCalls[0].status).toBe("failed");(0,_vitest.expect)(e.messages[0].toolCalls[0].summary).toBe("Interrupted")});(0,_vitest.it)("keeps an answer that already finished exactly as it was",()=>{const e=build([msg({text:"Five items.",streaming:false})]);(0,_vitest.expect)(e.messages[0].error).toBeUndefined();(0,_vitest.expect)(e.messages[0].text).toBe("Five items.")});(0,_vitest.it)("treats anything it cannot trust as no transcript at all",()=>{(0,_vitest.expect)((0,_transcriptPersistence.parsePayload)(null)).toBeNull();(0,_vitest.expect)((0,_transcriptPersistence.parsePayload)("not json")).toBeNull();(0,_vitest.expect)((0,_transcriptPersistence.parsePayload)(JSON.stringify({v:0,messages:[msg()]}))).toBeNull();(0,_vitest.expect)((0,_transcriptPersistence.parsePayload)(JSON.stringify({v:1,messages:[]}))).toBeNull()});(0,_vitest.it)("round-trips a real conversation",()=>{const e=build([msg({role:"user",text:"hi"}),msg({id:"m2",text:"hello"})]);const s=(0,_transcriptPersistence.parsePayload)(JSON.stringify(e));(0,_vitest.expect)(s?.messages.map(t=>t.text)).toEqual(["hi","hello"])})});(0,_vitest.describe)("an unanswered approval",()=>{const e={id:"c1",toolId:"zustand",action:"setState",label:"Update the Pok\xE9 Mart bag store",description:"Change a live zustand store.",reason:"This will change the app's state.",params:{storeName:"bag",data:{lines:[]}},resolve:()=>{}};const s=(t={})=>(0,_transcriptPersistence.buildPayload)({messages:[msg()],history:[],answers:{},usage:{input:0,output:0,requests:0},pending:{...e,...t}});(0,_vitest.it)("survives the round trip with the exact call it asked about",()=>{const t=(0,_transcriptPersistence.parsePayload)(JSON.stringify(s()));(0,_vitest.expect)(t?.pending).toMatchObject({toolId:"zustand",action:"setState",label:"Update the Pok\xE9 Mart bag store",params:{storeName:"bag",data:{lines:[]}}})});(0,_vitest.it)("is saved again after it has already been restored once",()=>{(0,_vitest.expect)(s({restored:true}).pending).toBeTruthy()});(0,_vitest.it)("is dropped rather than scrubbed when the call carries a credential",()=>{const t=s({params:{key:"auth",value:"Bearer abcdefghijklmnop123456"}});(0,_vitest.expect)(t.pending).toBeNull();(0,_vitest.expect)(JSON.stringify(t)).not.toContain("abcdefghijklmnop123456")});(0,_vitest.it)("reads back as absent from a transcript written before it existed",()=>{const t=build([msg()]);(0,_vitest.expect)((0,_transcriptPersistence.parsePayload)(JSON.stringify(t))?.pending).toBeNull()});(0,_vitest.it)("refuses a malformed one rather than restoring half a question",()=>{const t=JSON.stringify({...build([msg()]),pending:{toolId:"zustand"}});(0,_vitest.expect)((0,_transcriptPersistence.parsePayload)(t)?.pending).toBeNull()})});(0,_vitest.describe)("the effect ledger",()=>{const e={id:"fx-1-1",at:1,toolId:"storage",action:"async.setItem",effect:{kind:"storage-write",toolId:"storage",action:"async.setItem",label:"Save @qa/key",key:"@qa/key",had:true,previous:"old value"}};const s=t=>(0,_transcriptPersistence.buildPayload)({messages:[msg()],history:[],answers:{},usage:{input:0,output:0,requests:0},ledger:t});(0,_vitest.it)("survives the round trip with the prior value an undo needs",()=>{const t=(0,_transcriptPersistence.parsePayload)(JSON.stringify(s([e])));(0,_vitest.expect)(t?.ledger).toHaveLength(1);(0,_vitest.expect)(t?.ledger?.[0]).toMatchObject({toolId:"storage",action:"async.setItem"})});(0,_vitest.it)("drops an entry holding a credential rather than rewriting it",()=>{const t={...e,effect:{...e.effect,previous:"Bearer abcdefghijklmnop123456"}};const a=s([t]);(0,_vitest.expect)(a.ledger).toBeUndefined();(0,_vitest.expect)(JSON.stringify(a)).not.toContain("abcdefghijklmnop123456")});(0,_vitest.it)("reads back as absent from a transcript written before it existed",()=>{(0,_vitest.expect)((0,_transcriptPersistence.parsePayload)(JSON.stringify(build([msg()])))?.ledger).toBeUndefined()})});(0,_vitest.describe)("a turn that reloaded the app",()=>{const e=a=>msg({id:`u-${a}`,role:"user",text:a});const s=msg({id:"a1",text:"The app is reloading.",reloadedApp:true});const t=a=>(0,_transcriptPersistence.parsePayload)(JSON.stringify(build(a)));(0,_vitest.it)("is marked when the engine stops for a reload",()=>{_askBuoyStore.askBuoyStore.reset();const a=_askBuoyStore.askBuoyStore.startAssistant();_askBuoyStore.askBuoyStore.applyEvent(a,{type:"done",stopReason:"realm-died"});(0,_vitest.expect)(_askBuoyStore.askBuoyStore.getState().messages[0].reloadedApp).toBe(true)});(0,_vitest.it)("picks the task back up once, right after the reload",()=>{const a=t([e("make /v0 fail, reload, then undo"),s]);(0,_vitest.expect)((0,_transcriptPersistence.afterReload)(a,a.savedAt+1e3)).toBe("resume")});(0,_vitest.it)("leaves a note instead of looping when the picked-up task reloads again",()=>{const a=t([e("make /v0 fail, reload, then undo"),s,e(_transcriptPersistence.RESUME_AFTER_RELOAD),s]);(0,_vitest.expect)((0,_transcriptPersistence.afterReload)(a,a.savedAt+1e3)).toBe("note")});(0,_vitest.it)("leaves a note for a chat opened long after the reload",()=>{const a=t([e("reload the app"),s]);(0,_vitest.expect)((0,_transcriptPersistence.afterReload)(a,a.savedAt+10*6e4)).toBe("note")});(0,_vitest.it)("does nothing for a turn that ended any other way",()=>{const a=t([e("hi"),msg({text:"Hello."})]);(0,_vitest.expect)((0,_transcriptPersistence.afterReload)(a,a.savedAt)).toBeNull()})});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.useAskBuoy=useAskBuoy;exports.useAskBuoyState=useAskBuoyState;var _sharedUi=require("@buoy-gg/shared-ui");var _react=require("react");var _reactNative=require("react-native");var _agentCore=require("@buoy-gg/agent-core");var _askBuoyStore=require("./askBuoyStore");var _resetConversation=require("./resetConversation");var _transcriptPersistence=require("./transcriptPersistence");var _useAskBuoySettings=require("./useAskBuoySettings");var _hostedModel=require("../hostedModel");var _hostedModelSetting=require("./hostedModelSetting");const isRelease=typeof __DEV__!=="undefined"&&!__DEV__;function questionBehind(u){for(const r of _askBuoyStore.askBuoyStore.getState().messages){if(!r.restored)continue;for(const f of r.blocks){const l=f.block;if(l?.id!==u)continue;const d=l.question??l.label??l.title;return typeof d==="string"&&d.trim()?d.trim():void 0}}return void 0}function readAvailableActions(){try{const u=(0,_sharedUi.listToolActions)();for(const r of(0,_sharedUi.listSnapshotToolIds)()){if(!u[r])u[r]=[];if(!u[r].includes(_agentCore.SNAPSHOT_ACTION)){u[r]=[_agentCore.SNAPSHOT_ACTION,...u[r]]}}return u}catch{return{}}}const SAVE_DEBOUNCE_MS=600;function useAskBuoyState(){return(0,_react.useSyncExternalStore)(_askBuoyStore.askBuoyStore.subscribe,_askBuoyStore.askBuoyStore.getState,_askBuoyStore.askBuoyStore.getState)}function useAskBuoy(u){const r=useAskBuoyState();const f=(0,_hostedModelSetting.useHostedModel)();const l=(0,_react.useMemo)(()=>(0,_hostedModel.pickHostedModel)(u,f,r.claudeOut),[u,f,r.claudeOut]);const d=(0,_react.useRef)(l);if(r.messages.length===0||!d.current)d.current=l;const t=d.current;const q=(0,_react.useRef)(u);q.current=u;const E=!!u?.hostedModels?.claude;const I=r.messages.length===0;(0,_react.useEffect)(()=>{const e=q.current?.readUsage;if(!E||f!=="claude"||!I||!e)return;let o=true;e().then(s=>{if(o&&s.claude)_askBuoyStore.askBuoyStore.setClaudeOut(!s.claude.available)}).catch(()=>{});return()=>{o=false}},[E,f,I]);const S=(0,_sharedUi.getUseIsPro)()();const g=(0,_react.useRef)(S);g.current=S;const B=(0,_react.useCallback)((...e)=>{if(!(0,_sharedUi.hasAccountAccess)()||!g.current)return Promise.reject(new Error("Ask Buoy requires Pro access."));return(0,_sharedUi.dispatchToolAction)(...e)},[]);const i=(0,_react.useRef)(null);const P=(0,_react.useRef)(false);const y=(0,_react.useRef)(null);const M=(0,_react.useRef)(t);M.current=t;const b=!!t?.endpoint&&!!t?.model;const A=t?.persistTranscript!==false;const{bypassApprovals:m,readOnly:v}=(0,_useAskBuoySettings.useAskBuoySettings)();const O=(0,_react.useRef)(m);O.current=m;const w=(0,_react.useRef)(v);w.current=v;const T=(0,_react.useCallback)(()=>w.current?{...t?.policy??{},readOnly:true}:t?.policy??{},[t]);const[j,F]=(0,_react.useState)(0);(0,_react.useEffect)(()=>{let e=false;void(0,_sharedUi.waitForToolRegistry)().then(()=>{if(!e)F(o=>o+1)});return()=>{e=true}},[]);const k=(0,_react.useMemo)(()=>readAvailableActions(),[j]);const H=Object.keys(k).sort().join(",");(0,_react.useEffect)(()=>{_askBuoyStore.askBuoyStore.setConfigured(b);_askBuoyStore.askBuoyStore.setMeta({model:t?.model,protocol:t?.protocol??(t?"anthropic":void 0),appName:t?.appName,platform:_reactNative.Platform.OS,build:isRelease?"release":"development"});if(!b||!t){i.current=null;_askBuoyStore.askBuoyStore.setNotice("Ask Buoy isn't set up in this app yet. A developer needs to point it at your team's AI endpoint.");return}const e=t.protocol??"anthropic";if(isRelease&&t.apiKey){_askBuoyStore.askBuoyStore.setNotice("This build carries a plaintext apiKey \u2014 that's dev-only and it ships to every install. Use the headers callback with your own gateway for distributed builds.")}else if(e==="anthropic"&&/^https?:\/\/api\.openai\.com\//i.test(t.endpoint)){_askBuoyStore.askBuoyStore.setNotice('This endpoint is api.openai.com but the protocol is "anthropic". Set protocol: "openai" in the askBuoy config.')}else if(e==="openai"&&/^https?:\/\/api\.anthropic\.com\//i.test(t.endpoint)){_askBuoyStore.askBuoyStore.setNotice('This endpoint is api.anthropic.com but the protocol is "openai". Remove protocol or set it to "anthropic".')}else{_askBuoyStore.askBuoyStore.setNotice(null)}_askBuoyStore.askBuoyStore.setReporter(t.reportProblem??null);_askBuoyStore.askBuoyStore.setUsageReader(t.readUsage??null);const o=[t.endpoint,t.protocol??"anthropic",t.model].join("|");const s=_askBuoyStore.askBuoyStore.getHeldSession();if(s&&s.signature===o){i.current=s.session;s.session.setAvailableActions(k);s.session.setApprovalBypass(O.current);s.session.setReadOnly(w.current);_askBuoyStore.askBuoyStore.setLedger(s.session.ledger);return}const n=(0,_agentCore.createAskBuoySession)({endpoint:t.endpoint,protocol:t.protocol??"anthropic",model:t.model,headers:t.headers,apiKey:t.apiKey,maxTokens:t.maxTokens,anthropicVersion:t.anthropicVersion,requestOverrides:t.requestOverrides,hosted:t.hosted===true,...t.hostedFallback?{fallback:t.hostedFallback,onModelSwitch:a=>{const R=(a==="fallback"?t.hostedFallback?.model:t.model)===_hostedModel.HOSTED_CLAUDE_MODEL;_askBuoyStore.askBuoyStore.setMeta({model:a==="fallback"?t.hostedFallback?.model:t.model});if(a==="fallback"){if(!R)_askBuoyStore.askBuoyStore.setClaudeOut(true);_askBuoyStore.askBuoyStore.setNotice(R?"Luna is down right now, so Claude is answering.":"Claude is busy right now, so Luna is answering.")}else{_askBuoyStore.askBuoyStore.setNotice(null)}}}:{},catalog:t.tools?.length?[..._agentCore.CATALOG,...t.tools]:void 0,dispatch:B,readSnapshot:_sharedUi.readToolSnapshot,availableActions:k,policy:t.policy,context:t.context,isRelease,appName:t.appName,platform:_reactNative.Platform.OS,requestApproval:a=>_askBuoyStore.askBuoyStore.askApproval(a)});i.current=n;n.setApprovalBypass(O.current);n.setReadOnly(w.current);_askBuoyStore.askBuoyStore.holdSession(n,o);_askBuoyStore.askBuoyStore.setLedger(n.ledger);let c=false;void(0,_sharedUi.waitForToolRegistry)().then(a=>{if(a&&!c)void n.prime()});if(A&&!P.current){P.current=true;void(0,_transcriptPersistence.readTranscript)().then(a=>{if(!a)return;const R=_askBuoyStore.askBuoyStore.hydrate({messages:a.messages,answers:a.answers,usage:a.usage,queued:a.queued});if(!R)return;i.current?.restore(a.history);if(a.ledger?.length)i.current?.ledger.restore(a.ledger);if(a.pending)_askBuoyStore.askBuoyStore.restorePending(a.pending)})}return()=>{c=true}},[b,t,k,H,A]);(0,_react.useEffect)(()=>{i.current?.setApprovalBypass(m)},[m]);(0,_react.useEffect)(()=>{i.current?.setReadOnly(v)},[v]);const N=r.messages;const x=r.answers;const $=r.usage;const L=r.busy;const _=r.pending;const D=r.queued;(0,_react.useEffect)(()=>{if(!A)return;if(N.length===0)return;const e=()=>{void(0,_transcriptPersistence.writeTranscript)((0,_transcriptPersistence.buildPayload)({messages:N,history:i.current?.messages??[],answers:x,usage:$,pending:_,ledger:_askBuoyStore.askBuoyStore.getLedger()?.list(),queued:D}))};if(!L||_){e();return}const o=setTimeout(e,SAVE_DEBOUNCE_MS);return()=>clearTimeout(o)},[A,L,N,x,$,_,D]);const C=(0,_react.useCallback)(e=>{if(!(0,_sharedUi.hasAccountAccess)()||!g.current)return;const o=i.current;if(!o)return;_askBuoyStore.askBuoyStore.beginTurn();const s=_askBuoyStore.askBuoyStore.startAssistant();const n=new AbortController;y.current=n;o.setAvailableActions(readAvailableActions());const c=M.current?.onEvent;void(async()=>{try{for await(const a of o.send(e,n.signal)){_askBuoyStore.askBuoyStore.applyEvent(s,a);if(c){try{c(a)}catch{}}}}catch(a){if(!n.signal.aborted){_askBuoyStore.askBuoyStore.applyEvent(s,{type:"error",message:a instanceof Error?a.message:"Something went wrong talking to your AI endpoint."})}}finally{if(n.signal.aborted)_askBuoyStore.askBuoyStore.markStopped(s);_askBuoyStore.askBuoyStore.finishAssistant(s);y.current=null}})()},[]);const p=(0,_react.useCallback)(e=>{if(!(0,_sharedUi.hasAccountAccess)()||!g.current)return;const o=e.trim();if(!i.current||!o)return;if(_askBuoyStore.askBuoyStore.getState().busy){_askBuoyStore.askBuoyStore.enqueue(o);return}const s=_askBuoyStore.askBuoyStore.getState().awaitingBlockId;if(s)_askBuoyStore.askBuoyStore.recordAnswer({blockId:s,kind:"skipped"});_askBuoyStore.askBuoyStore.addUser(o);C(o)},[C]);const G=(0,_react.useCallback)(()=>{const{messages:e,busy:o}=_askBuoyStore.askBuoyStore.getState();if(o||!i.current)return;const s=[...e].reverse().find(n=>n.role==="user");if(!s)return;C(s.text)},[C]);const h=(0,_react.useCallback)(()=>{_askBuoyStore.askBuoyStore.requestStop();if(_askBuoyStore.askBuoyStore.getState().pending)_askBuoyStore.askBuoyStore.answerApproval(false);y.current?.abort();y.current=null},[]);(0,_react.useEffect)(()=>{const e=(0,_sharedUi.subscribeAccountAccess)(()=>{if(!(0,_sharedUi.hasAccountAccess)())h()});return()=>{e();h()}},[h]);(0,_react.useEffect)(()=>{if(!S)h()},[S,h]);(0,_react.useEffect)(()=>{if(r.queued.length===0)return;if((0,_askBuoyStore.turnPhaseOf)(r)!=="idle")return;if((0,_askBuoyStore.queuePauseReason)(r)!==null)return;const e=_askBuoyStore.askBuoyStore.shiftQueued();if(e)p(e.text)},[r,p]);const K=(0,_react.useCallback)(e=>_askBuoyStore.askBuoyStore.takeQueuedToDraft(e),[]);const Q=(0,_react.useCallback)(e=>_askBuoyStore.askBuoyStore.removeQueued(e),[]);const V=(0,_react.useCallback)(()=>{y.current?.abort();y.current=null;(0,_resetConversation.clearConversation)()},[]);const W=(0,_react.useCallback)(()=>(0,_resetConversation.resetConversation)({dispatch:_sharedUi.dispatchToolAction,undoFirst:true}),[]);const U=(0,_react.useCallback)(async e=>{const o=_askBuoyStore.askBuoyStore.getLedger();if(!o){_askBuoyStore.askBuoyStore.setNotice(`${e.label} couldn't run \u2014 no active Ask Buoy session.`);return}const s=t?.tools?.length?[..._agentCore.CATALOG,...t.tools]:void 0;if(e.targetDigest){const c=await(0,_agentCore.readTargetDigest)({toolId:e.toolId,action:e.action,params:e.params??{},dispatch:B,catalog:s});if(c!==void 0&&c!==e.targetDigest){_askBuoyStore.askBuoyStore.addNote(`\u201C${e.label}\u201D wasn't applied \u2014 what it would change has moved on since the app restarted. Nothing was written. Ask again if you still want it.`);return}}const n=await(0,_agentCore.runGatedAction)({toolId:e.toolId,action:e.action,params:e.params??{},dispatch:B,ledger:o,policy:T(),isRelease,catalog:s});if(n.ok){_askBuoyStore.askBuoyStore.addNote(`Applied \u201C${e.label}\u201D, which was still waiting when the app restarted. Whatever else that answer was going to do is gone \u2014 ask again if there was more to it.`)}else{_askBuoyStore.askBuoyStore.setNotice(`${e.label} failed \u2014 ${n.error}`)}},[t,T]);const z=(0,_react.useCallback)(e=>{const o=_askBuoyStore.askBuoyStore.getState().pending;const s=typeof e==="boolean"?e:e.approved;_askBuoyStore.askBuoyStore.answerApproval(e);if(!o?.restored)return;if(!s){_askBuoyStore.askBuoyStore.addNote(`Skipped \u201C${o.label}\u201D. Nothing was changed.`);return}void U(o)},[U]);const J=(0,_react.useCallback)(e=>{_askBuoyStore.askBuoyStore.recordAnswer(e);const o=questionBehind(e.blockId);p(o?`${o} \u2014 ${(0,_agentCore.answerToText)(e)}`:(0,_agentCore.answerToText)(e))},[p]);const X=(0,_react.useCallback)(async(e,o)=>{if(!(0,_sharedUi.hasAccountAccess)()||!g.current){_askBuoyStore.askBuoyStore.setNotice("Ask Buoy requires Pro access.");return}if(e.send){p(e.send);return}if(!e.dispatch)return;const s=`${o}:${e.label}`;const n=_askBuoyStore.askBuoyStore.getLedger();if(!n){_askBuoyStore.askBuoyStore.setNotice(`${e.label} failed \u2014 no active Ask Buoy session.`);return}_askBuoyStore.askBuoyStore.setActionState(s,"running");const c=await(0,_agentCore.runGatedAction)({toolId:e.dispatch.toolId,action:e.dispatch.action,params:e.dispatch.params??{},dispatch:B,ledger:n,policy:T(),isRelease,catalog:t?.tools?.length?[..._agentCore.CATALOG,...t.tools]:void 0});if(c.ok){_askBuoyStore.askBuoyStore.setActionState(s,"done")}else{_askBuoyStore.askBuoyStore.setActionState(s,"failed");_askBuoyStore.askBuoyStore.setNotice(`${e.label} failed \u2014 ${c.error}`)}},[p,t,T]);return{state:r,send:p,stop:h,reset:V,undoThenReset:W,approve:z,retry:G,answer:J,runAction:X,editQueued:K,removeQueued:Q,configured:b,toolCount:Object.keys(k).length,availableToolIds:Object.keys(k)}}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.useAskBuoy=useAskBuoy;exports.useAskBuoyState=useAskBuoyState;var _sharedUi=require("@buoy-gg/shared-ui");var _react=require("react");var _reactNative=require("react-native");var _agentCore=require("@buoy-gg/agent-core");var _askBuoyStore=require("./askBuoyStore");var _resetConversation=require("./resetConversation");var _transcriptPersistence=require("./transcriptPersistence");var _useAskBuoySettings=require("./useAskBuoySettings");var _hostedModel=require("../hostedModel");var _hostedModelSetting=require("./hostedModelSetting");const isRelease=typeof __DEV__!=="undefined"&&!__DEV__;function questionBehind(u){for(const a of _askBuoyStore.askBuoyStore.getState().messages){if(!a.restored)continue;for(const f of a.blocks){const d=f.block;if(d?.id!==u)continue;const p=d.question??d.label??d.title;return typeof p==="string"&&p.trim()?p.trim():void 0}}return void 0}function readAvailableActions(){try{const u=(0,_sharedUi.listToolActions)();for(const a of(0,_sharedUi.listSnapshotToolIds)()){if(!u[a])u[a]=[];if(!u[a].includes(_agentCore.SNAPSHOT_ACTION)){u[a]=[_agentCore.SNAPSHOT_ACTION,...u[a]]}}return u}catch{return{}}}const SAVE_DEBOUNCE_MS=600;function useAskBuoyState(){return(0,_react.useSyncExternalStore)(_askBuoyStore.askBuoyStore.subscribe,_askBuoyStore.askBuoyStore.getState,_askBuoyStore.askBuoyStore.getState)}function useAskBuoy(u){const a=useAskBuoyState();const f=(0,_hostedModelSetting.useHostedModel)();const d=(0,_react.useMemo)(()=>(0,_hostedModel.pickHostedModel)(u,f,a.claudeOut),[u,f,a.claudeOut]);const p=(0,_react.useRef)(d);if(a.messages.length===0||!p.current)p.current=d;const t=p.current;const q=(0,_react.useRef)(u);q.current=u;const I=!!u?.hostedModels?.claude;const P=a.messages.length===0;(0,_react.useEffect)(()=>{const e=q.current?.readUsage;if(!I||f!=="claude"||!P||!e)return;let o=true;e().then(s=>{if(o&&s.claude)_askBuoyStore.askBuoyStore.setClaudeOut(!s.claude.available)}).catch(()=>{});return()=>{o=false}},[I,f,P]);const y=(0,_sharedUi.getUseIsPro)()();const S=(0,_react.useRef)(y);S.current=y;const A=(0,_react.useCallback)((...e)=>{if(!(0,_sharedUi.hasAccountAccess)()||!S.current)return Promise.reject(new Error("Ask Buoy requires Pro access."));return(0,_sharedUi.dispatchToolAction)(...e)},[]);const i=(0,_react.useRef)(null);const M=(0,_react.useRef)(false);const[x,L]=(0,_react.useState)(false);const k=(0,_react.useRef)(null);const D=(0,_react.useRef)(t);D.current=t;const B=!!t?.endpoint&&!!t?.model;const b=t?.persistTranscript!==false;const{bypassApprovals:m,readOnly:v}=(0,_useAskBuoySettings.useAskBuoySettings)();const O=(0,_react.useRef)(m);O.current=m;const w=(0,_react.useRef)(v);w.current=v;const R=(0,_react.useCallback)(()=>w.current?{...t?.policy??{},readOnly:true}:t?.policy??{},[t]);const[E,K]=(0,_react.useState)(0);(0,_react.useEffect)(()=>{let e=false;void(0,_sharedUi.waitForToolRegistry)().then(()=>{if(!e)K(o=>o+1)});return()=>{e=true}},[]);const h=(0,_react.useMemo)(()=>readAvailableActions(),[E]);const Q=Object.keys(h).sort().join(",");(0,_react.useEffect)(()=>{_askBuoyStore.askBuoyStore.setConfigured(B);_askBuoyStore.askBuoyStore.setMeta({model:t?.model,protocol:t?.protocol??(t?"anthropic":void 0),appName:t?.appName,platform:_reactNative.Platform.OS,build:isRelease?"release":"development"});if(!B||!t){i.current=null;_askBuoyStore.askBuoyStore.setNotice("Ask Buoy isn't set up in this app yet. A developer needs to point it at your team's AI endpoint.");return}const e=t.protocol??"anthropic";if(isRelease&&t.apiKey){_askBuoyStore.askBuoyStore.setNotice("This build carries a plaintext apiKey \u2014 that's dev-only and it ships to every install. Use the headers callback with your own gateway for distributed builds.")}else if(e==="anthropic"&&/^https?:\/\/api\.openai\.com\//i.test(t.endpoint)){_askBuoyStore.askBuoyStore.setNotice('This endpoint is api.openai.com but the protocol is "anthropic". Set protocol: "openai" in the askBuoy config.')}else if(e==="openai"&&/^https?:\/\/api\.anthropic\.com\//i.test(t.endpoint)){_askBuoyStore.askBuoyStore.setNotice('This endpoint is api.anthropic.com but the protocol is "openai". Remove protocol or set it to "anthropic".')}else{_askBuoyStore.askBuoyStore.setNotice(null)}_askBuoyStore.askBuoyStore.setReporter(t.reportProblem??null);_askBuoyStore.askBuoyStore.setUsageReader(t.readUsage??null);const o=[t.endpoint,t.protocol??"anthropic",t.model].join("|");const s=_askBuoyStore.askBuoyStore.getHeldSession();if(s&&s.signature===o){i.current=s.session;s.session.setAvailableActions(h);s.session.setApprovalBypass(O.current);s.session.setReadOnly(w.current);_askBuoyStore.askBuoyStore.setLedger(s.session.ledger);return}const n=(0,_agentCore.createAskBuoySession)({endpoint:t.endpoint,protocol:t.protocol??"anthropic",model:t.model,headers:t.headers,apiKey:t.apiKey,maxTokens:t.maxTokens,anthropicVersion:t.anthropicVersion,requestOverrides:t.requestOverrides,hosted:t.hosted===true,...t.hostedFallback?{fallback:t.hostedFallback,onModelSwitch:r=>{const C=(r==="fallback"?t.hostedFallback?.model:t.model)===_hostedModel.HOSTED_CLAUDE_MODEL;_askBuoyStore.askBuoyStore.setMeta({model:r==="fallback"?t.hostedFallback?.model:t.model});if(r==="fallback"){if(!C)_askBuoyStore.askBuoyStore.setClaudeOut(true);_askBuoyStore.askBuoyStore.setNotice(C?"Luna is down right now, so Claude is answering.":"Claude is busy right now, so Luna is answering.")}else{_askBuoyStore.askBuoyStore.setNotice(null)}}}:{},catalog:t.tools?.length?[..._agentCore.CATALOG,...t.tools]:void 0,dispatch:A,readSnapshot:_sharedUi.readToolSnapshot,availableActions:h,policy:t.policy,context:t.context,isRelease,inApp:true,appName:t.appName,platform:_reactNative.Platform.OS,requestApproval:r=>_askBuoyStore.askBuoyStore.askApproval(r)});i.current=n;n.setApprovalBypass(O.current);n.setReadOnly(w.current);_askBuoyStore.askBuoyStore.holdSession(n,o);_askBuoyStore.askBuoyStore.setLedger(n.ledger);let c=false;void(0,_sharedUi.waitForToolRegistry)().then(r=>{if(r&&!c)void n.prime()});if(b&&!M.current){M.current=true;void(0,_transcriptPersistence.readTranscript)().then(r=>{if(!r)return;const C=_askBuoyStore.askBuoyStore.hydrate({messages:r.messages,answers:r.answers,usage:r.usage,queued:r.queued});if(!C)return;i.current?.restore(r.history);if(r.ledger?.length)i.current?.ledger.restore(r.ledger);if(r.pending)_askBuoyStore.askBuoyStore.restorePending(r.pending);const G=(0,_transcriptPersistence.afterReload)(r,Date.now());if(G==="resume")L(true);else if(G==="note")_askBuoyStore.askBuoyStore.addNote(_transcriptPersistence.RELOAD_NOTE)})}return()=>{c=true}},[B,t,h,Q,b]);(0,_react.useEffect)(()=>{i.current?.setApprovalBypass(m)},[m]);(0,_react.useEffect)(()=>{i.current?.setReadOnly(v)},[v]);const N=a.messages;const $=a.answers;const U=a.usage;const F=a.busy;const _=a.pending;const j=a.queued;(0,_react.useEffect)(()=>{if(!b)return;if(N.length===0)return;const e=()=>{void(0,_transcriptPersistence.writeTranscript)((0,_transcriptPersistence.buildPayload)({messages:N,history:i.current?.messages??[],answers:$,usage:U,pending:_,ledger:_askBuoyStore.askBuoyStore.getLedger()?.list(),queued:j}))};if(!F||_){e();return}const o=setTimeout(e,SAVE_DEBOUNCE_MS);return()=>clearTimeout(o)},[b,F,N,$,U,_,j]);const T=(0,_react.useCallback)(e=>{if(!(0,_sharedUi.hasAccountAccess)()||!S.current)return;const o=i.current;if(!o)return;_askBuoyStore.askBuoyStore.beginTurn();const s=_askBuoyStore.askBuoyStore.startAssistant();const n=new AbortController;k.current=n;o.setAvailableActions(readAvailableActions());const c=D.current?.onEvent;void(async()=>{try{for await(const r of o.send(e,n.signal)){_askBuoyStore.askBuoyStore.applyEvent(s,r);if(c){try{c(r)}catch{}}}}catch(r){if(!n.signal.aborted){_askBuoyStore.askBuoyStore.applyEvent(s,{type:"error",message:r instanceof Error?r.message:"Something went wrong talking to your AI endpoint."})}}finally{if(n.signal.aborted)_askBuoyStore.askBuoyStore.markStopped(s);_askBuoyStore.askBuoyStore.finishAssistant(s);k.current=null}})()},[]);const l=(0,_react.useCallback)(e=>{if(!(0,_sharedUi.hasAccountAccess)()||!S.current)return;const o=e.trim();if(!i.current||!o)return;if(_askBuoyStore.askBuoyStore.getState().busy){_askBuoyStore.askBuoyStore.enqueue(o);return}const s=_askBuoyStore.askBuoyStore.getState().awaitingBlockId;if(s)_askBuoyStore.askBuoyStore.recordAnswer({blockId:s,kind:"skipped"});_askBuoyStore.askBuoyStore.addUser(o);T(o)},[T]);(0,_react.useEffect)(()=>{if(!x||!y||!(0,_sharedUi.hasAccountAccess)()||!i.current||E===0)return;L(false);l(_transcriptPersistence.RESUME_AFTER_RELOAD)},[x,y,E,l]);const V=(0,_react.useCallback)(()=>{const{messages:e,busy:o}=_askBuoyStore.askBuoyStore.getState();if(o||!i.current)return;const s=[...e].reverse().find(n=>n.role==="user");if(!s)return;T(s.text)},[T]);const g=(0,_react.useCallback)(()=>{_askBuoyStore.askBuoyStore.requestStop();if(_askBuoyStore.askBuoyStore.getState().pending)_askBuoyStore.askBuoyStore.answerApproval(false);k.current?.abort();k.current=null},[]);(0,_react.useEffect)(()=>{const e=(0,_sharedUi.subscribeAccountAccess)(()=>{if(!(0,_sharedUi.hasAccountAccess)())g()});return()=>{e();g()}},[g]);(0,_react.useEffect)(()=>{if(!y)g()},[y,g]);(0,_react.useEffect)(()=>{if(a.queued.length===0)return;if((0,_askBuoyStore.turnPhaseOf)(a)!=="idle")return;if((0,_askBuoyStore.queuePauseReason)(a)!==null)return;const e=_askBuoyStore.askBuoyStore.shiftQueued();if(e)l(e.text)},[a,l]);const W=(0,_react.useCallback)(e=>_askBuoyStore.askBuoyStore.takeQueuedToDraft(e),[]);const z=(0,_react.useCallback)(e=>_askBuoyStore.askBuoyStore.removeQueued(e),[]);const J=(0,_react.useCallback)(()=>{k.current?.abort();k.current=null;(0,_resetConversation.clearConversation)()},[]);const X=(0,_react.useCallback)(()=>(0,_resetConversation.resetConversation)({dispatch:_sharedUi.dispatchToolAction,undoFirst:true}),[]);const H=(0,_react.useCallback)(async e=>{const o=_askBuoyStore.askBuoyStore.getLedger();if(!o){_askBuoyStore.askBuoyStore.setNotice(`${e.label} couldn't run \u2014 no active Ask Buoy session.`);return}const s=t?.tools?.length?[..._agentCore.CATALOG,...t.tools]:void 0;if(e.targetDigest){const c=await(0,_agentCore.readTargetDigest)({toolId:e.toolId,action:e.action,params:e.params??{},dispatch:A,catalog:s});if(c!==void 0&&c!==e.targetDigest){_askBuoyStore.askBuoyStore.addNote(`\u201C${e.label}\u201D wasn't applied \u2014 what it would change has moved on since the app restarted. Nothing was written. Ask again if you still want it.`);return}}const n=await(0,_agentCore.runGatedAction)({toolId:e.toolId,action:e.action,params:e.params??{},dispatch:A,ledger:o,policy:R(),isRelease,catalog:s});if(n.ok){_askBuoyStore.askBuoyStore.addNote(`Applied \u201C${e.label}\u201D, which was still waiting when the app restarted. Whatever else that answer was going to do is gone \u2014 ask again if there was more to it.`)}else{_askBuoyStore.askBuoyStore.setNotice(`${e.label} failed \u2014 ${n.error}`)}},[t,R]);const Y=(0,_react.useCallback)(e=>{const o=_askBuoyStore.askBuoyStore.getState().pending;const s=typeof e==="boolean"?e:e.approved;_askBuoyStore.askBuoyStore.answerApproval(e);if(!o?.restored)return;if(!s){_askBuoyStore.askBuoyStore.addNote(`Skipped \u201C${o.label}\u201D. Nothing was changed.`);return}void H(o)},[H]);const Z=(0,_react.useCallback)(e=>{_askBuoyStore.askBuoyStore.recordAnswer(e);const o=questionBehind(e.blockId);l(o?`${o} \u2014 ${(0,_agentCore.answerToText)(e)}`:(0,_agentCore.answerToText)(e))},[l]);const ee=(0,_react.useCallback)(async(e,o)=>{if(!(0,_sharedUi.hasAccountAccess)()||!S.current){_askBuoyStore.askBuoyStore.setNotice("Ask Buoy requires Pro access.");return}if(e.send){l(e.send);return}if(!e.dispatch)return;const s=`${o}:${e.label}`;const n=_askBuoyStore.askBuoyStore.getLedger();if(!n){_askBuoyStore.askBuoyStore.setNotice(`${e.label} failed \u2014 no active Ask Buoy session.`);return}_askBuoyStore.askBuoyStore.setActionState(s,"running");const c=await(0,_agentCore.runGatedAction)({toolId:e.dispatch.toolId,action:e.dispatch.action,params:e.dispatch.params??{},dispatch:A,ledger:n,policy:R(),isRelease,catalog:t?.tools?.length?[..._agentCore.CATALOG,...t.tools]:void 0});if(c.ok){_askBuoyStore.askBuoyStore.setActionState(s,"done")}else{_askBuoyStore.askBuoyStore.setActionState(s,"failed");_askBuoyStore.askBuoyStore.setNotice(`${e.label} failed \u2014 ${c.error}`)}},[l,t,R]);return{state:a,send:l,stop:g,reset:J,undoThenReset:X,approve:Y,retry:V,answer:Z,runAction:ee,editQueued:W,removeQueued:z,configured:B,toolCount:Object.keys(h).length,availableToolIds:Object.keys(h)}}
|