@buoy-gg/ask-buoy 7.0.77 → 7.0.78

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.
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.ApprovalCard=ApprovalCard;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _jsxRuntime=require("react/jsx-runtime");function ApprovalCard({pending:e,onAnswer:t}){const[o,r]=(0,_react.useState)("");return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.card,testID:"buoy-ask-buoy-approval",children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.titleRow,children:[(0,_jsxRuntime.jsx)(_sharedUi.AlertTriangle,{size:14,color:_sharedUi.night.color.warning}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.title,children:"Allow this change?"})]}),e.restored?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.restored,testID:"buoy-ask-buoy-approval-restored",children:"Asked before the app restarted \u2014 check it still applies."}):null,(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.label,children:e.label}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.reason,children:e.reason}),e.description?(0,_jsxRuntime.jsx)(ApprovalDetails,{text:e.description}):null,(0,_jsxRuntime.jsx)(_reactNative.TextInput,{testID:"buoy-ask-buoy-approval-note",value:o,onChangeText:r,placeholder:"Add a note for the agent (optional)",placeholderTextColor:_sharedUi.night.color.textTertiary,style:styles.note,returnKeyType:"done",blurOnSubmit:true}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.actions,children:[(0,_jsxRuntime.jsx)(_reactNative.Pressable,{testID:"buoy-ask-buoy-approve",accessibilityRole:"button",onPress:()=>t({approved:true,reason:o}),style:({pressed:i})=>[styles.button,styles.approve,i&&styles.pressed],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.approveText,children:"Allow"})}),e.restored?null:(0,_jsxRuntime.jsx)(_reactNative.Pressable,{testID:"buoy-ask-buoy-approve-trust",accessibilityRole:"button",onPress:()=>t({approved:true,reason:o,trust:true}),style:({pressed:i})=>[styles.button,styles.trust,i&&styles.pressed],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.trustText,children:"Allow for this chat"})}),(0,_jsxRuntime.jsx)(_reactNative.Pressable,{testID:"buoy-ask-buoy-reject",accessibilityRole:"button",onPress:()=>t({approved:false,reason:o}),style:({pressed:i})=>[styles.button,styles.reject,i&&styles.pressed],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.rejectText,children:"Not now"})})]})]})}function ApprovalDetails({text:e}){const[t,o]=(0,_react.useState)(false);return(0,_jsxRuntime.jsxs)(_reactNative.View,{children:[(0,_jsxRuntime.jsxs)(_reactNative.Pressable,{testID:"buoy-ask-buoy-approval-details",accessibilityRole:"button",accessibilityState:{expanded:t},onPress:()=>o(r=>!r),style:({pressed:r})=>[styles.disclosure,r&&styles.pressed],hitSlop:6,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:t?styles.chevronOpen:styles.chevronClosed,children:(0,_jsxRuntime.jsx)(_sharedUi.ChevronDown,{size:12,color:_sharedUi.night.color.textTertiary})}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.disclosureText,children:t?"Hide details":"Details"})]}),t?(0,_jsxRuntime.jsx)(_reactNative.ScrollView,{style:styles.detail,contentContainerStyle:styles.detailContent,nestedScrollEnabled:true,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.description,children:e})}):null]})}const styles=_reactNative.StyleSheet.create({card:{marginHorizontal:_sharedUi.night.gutter,marginBottom:10,padding:_sharedUi.night.cardPad,borderRadius:_sharedUi.night.radius.card,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.accentBorderStrong,backgroundColor:_sharedUi.night.color.surface,gap:6},titleRow:{flexDirection:"row",alignItems:"center",gap:6},title:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.caption,fontWeight:"600"},label:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.row,fontWeight:"600",lineHeight:20},description:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption,lineHeight:18},reason:{color:_sharedUi.night.color.warning,fontSize:_sharedUi.night.font.caption,lineHeight:18},restored:{color:_sharedUi.night.color.info,backgroundColor:_sharedUi.night.color.infoSoft,fontSize:_sharedUi.night.font.micro,lineHeight:16,paddingHorizontal:8,paddingVertical:5,borderRadius:8},disclosure:{flexDirection:"row",alignItems:"center",gap:4,paddingVertical:4},disclosureText:{color:_sharedUi.night.color.textTertiary,fontSize:_sharedUi.night.font.micro,fontWeight:"600"},chevronOpen:{transform:[{rotate:"0deg"}]},chevronClosed:{transform:[{rotate:"-90deg"}]},detail:{maxHeight:150,marginTop:2},detailContent:{paddingBottom:2},note:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.caption,paddingHorizontal:10,paddingVertical:7,borderRadius:_sharedUi.night.radius.row,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.border,backgroundColor:_sharedUi.night.color.button,marginTop:2},actions:{flexDirection:"row",flexWrap:"wrap",gap:8,marginTop:6},button:{paddingHorizontal:16,paddingVertical:9,borderRadius:_sharedUi.night.radius.row},approve:{backgroundColor:_sharedUi.night.color.accent},approveText:{color:_sharedUi.night.color.onAccent,fontWeight:"600",fontSize:_sharedUi.night.font.caption},trust:{backgroundColor:_sharedUi.night.color.button,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.accentBorderStrong},trustText:{color:_sharedUi.night.color.accent,fontWeight:"600",fontSize:_sharedUi.night.font.caption},reject:{backgroundColor:_sharedUi.night.color.button},rejectText:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.caption},pressed:{opacity:.7}});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.ApprovalCard=ApprovalCard;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _jsxRuntime=require("react/jsx-runtime");function ApprovalCard({pending:e,onAnswer:t}){const[o,r]=(0,_react.useState)("");return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.card,testID:"buoy-ask-buoy-approval",children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.titleRow,children:[(0,_jsxRuntime.jsx)(_sharedUi.AlertTriangle,{size:14,color:_sharedUi.night.color.warning}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.title,children:"Allow this change?"})]}),e.restored?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.restored,testID:"buoy-ask-buoy-approval-restored",children:"Asked before the app restarted \u2014 check it still applies."}):null,(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.label,children:e.label}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.reason,children:e.reason}),e.description?(0,_jsxRuntime.jsx)(ApprovalDetails,{text:e.description}):null,(0,_jsxRuntime.jsx)(_reactNative.TextInput,{testID:"buoy-ask-buoy-approval-note",value:o,onChangeText:r,placeholder:"Add a note for the agent (optional)",placeholderTextColor:_sharedUi.night.color.textTertiary,style:styles.note,returnKeyType:"done",blurOnSubmit:true}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.actions,children:[(0,_jsxRuntime.jsx)(_reactNative.Pressable,{testID:"buoy-ask-buoy-approve",accessibilityRole:"button",onPress:()=>t({approved:true,reason:o}),style:({pressed:i})=>[styles.button,styles.approve,i&&styles.pressed],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.approveText,children:"Allow"})}),e.restored?null:(0,_jsxRuntime.jsx)(_reactNative.Pressable,{testID:"buoy-ask-buoy-approve-trust",accessibilityRole:"button",onPress:()=>t({approved:true,reason:o,trust:true}),style:({pressed:i})=>[styles.button,styles.trust,i&&styles.pressed],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.trustText,children:"Allow for this chat"})}),(0,_jsxRuntime.jsx)(_reactNative.Pressable,{testID:"buoy-ask-buoy-reject",accessibilityRole:"button",onPress:()=>t({approved:false,reason:o}),style:({pressed:i})=>[styles.button,styles.reject,i&&styles.pressed],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.rejectText,children:"Not now"})})]})]})}function ApprovalDetails({text:e}){const[t,o]=(0,_react.useState)(false);return(0,_jsxRuntime.jsxs)(_reactNative.View,{children:[(0,_jsxRuntime.jsxs)(_reactNative.Pressable,{testID:"buoy-ask-buoy-approval-details",accessibilityRole:"button",accessibilityState:{expanded:t},onPress:()=>o(r=>!r),style:({pressed:r})=>[styles.disclosure,r&&styles.pressed],hitSlop:6,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:t?styles.chevronOpen:styles.chevronClosed,children:(0,_jsxRuntime.jsx)(_sharedUi.ChevronDown,{size:12,color:_sharedUi.night.color.textTertiary})}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.disclosureText,children:t?"Hide details":"Details"})]}),t?(0,_jsxRuntime.jsx)(_reactNative.ScrollView,{keyboardShouldPersistTaps:"handled",style:styles.detail,contentContainerStyle:styles.detailContent,nestedScrollEnabled:true,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.description,children:e})}):null]})}const styles=_reactNative.StyleSheet.create({card:{marginHorizontal:_sharedUi.night.gutter,marginBottom:10,padding:_sharedUi.night.cardPad,borderRadius:_sharedUi.night.radius.card,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.accentBorderStrong,backgroundColor:_sharedUi.night.color.surface,gap:6},titleRow:{flexDirection:"row",alignItems:"center",gap:6},title:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.caption,fontWeight:"600"},label:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.row,fontWeight:"600",lineHeight:20},description:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption,lineHeight:18},reason:{color:_sharedUi.night.color.warning,fontSize:_sharedUi.night.font.caption,lineHeight:18},restored:{color:_sharedUi.night.color.info,backgroundColor:_sharedUi.night.color.infoSoft,fontSize:_sharedUi.night.font.micro,lineHeight:16,paddingHorizontal:8,paddingVertical:5,borderRadius:8},disclosure:{flexDirection:"row",alignItems:"center",gap:4,paddingVertical:4},disclosureText:{color:_sharedUi.night.color.textTertiary,fontSize:_sharedUi.night.font.micro,fontWeight:"600"},chevronOpen:{transform:[{rotate:"0deg"}]},chevronClosed:{transform:[{rotate:"-90deg"}]},detail:{maxHeight:150,marginTop:2},detailContent:{paddingBottom:2},note:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.caption,paddingHorizontal:10,paddingVertical:7,borderRadius:_sharedUi.night.radius.row,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.border,backgroundColor:_sharedUi.night.color.button,marginTop:2},actions:{flexDirection:"row",flexWrap:"wrap",gap:8,marginTop:6},button:{paddingHorizontal:16,paddingVertical:9,borderRadius:_sharedUi.night.radius.row},approve:{backgroundColor:_sharedUi.night.color.accent},approveText:{color:_sharedUi.night.color.onAccent,fontWeight:"600",fontSize:_sharedUi.night.font.caption},trust:{backgroundColor:_sharedUi.night.color.button,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.accentBorderStrong},trustText:{color:_sharedUi.night.color.accent,fontWeight:"600",fontSize:_sharedUi.night.font.caption},reject:{backgroundColor:_sharedUi.night.color.button},rejectText:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.caption},pressed:{opacity:.7}});
@@ -1,3 +1,3 @@
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:D,availableToolIds:K}=(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}
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:D,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,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:K,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"}});
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,avoidKeyboard:false,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.AskBuoySettings=AskBuoySettings;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _useAskBuoySettings=require("../store/useAskBuoySettings");var _askBuoySettings=require("../store/askBuoySettings");var _hostedModelSetting=require("../store/hostedModelSetting");var _askBuoyStore=require("../store/askBuoyStore");var _useAskBuoy=require("../store/useAskBuoy");var _jsxRuntime=require("react/jsx-runtime");function AskBuoySettings(){const t=(0,_useAskBuoySettings.useAskBuoySettings)();const s=(0,_useAskBuoy.useAskBuoyState)().trusted;return(0,_jsxRuntime.jsxs)(_reactNative.ScrollView,{style:styles.scroll,contentContainerStyle:styles.content,testID:"buoy-ask-buoy-settings",children:[(0,_jsxRuntime.jsx)(HostedCredits,{}),(0,_jsxRuntime.jsx)(HostedModel,{}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.section,children:"CHAT"}),(0,_jsxRuntime.jsx)(_sharedUi.ToggleRow,{testID:"buoy-ask-buoy-setting-thinking",label:"Show agent thinking",description:"Adds a collapsed strip under each answer: the model's reasoning, and every step it ran with its parameters, result, duration and token cost. Copy includes the steps and reasoning while this is on, so you can read the run outside the app.",value:t.showThinking,onValueChange:e=>_askBuoySettings.askBuoySettings.set("showThinking",e)}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.note,children:"Not every model reports reasoning. Claude thinks by default; most OpenAI models return none, and the strip then shows the steps alone."}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.section,children:"PERMISSIONS"}),(0,_jsxRuntime.jsx)(_sharedUi.ToggleRow,{testID:"buoy-ask-buoy-setting-readonly",label:"Read only",description:"Inspect the app, change nothing. Every write and simulation is refused until this is off. Undo still works \u2014 putting things back is the safe direction.",value:t.readOnly,onValueChange:e=>_askBuoySettings.askBuoySettings.set("readOnly",e)}),t.readOnly?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.note,testID:"buoy-ask-buoy-readonly-note",children:"On across reloads until you turn it off here. The header says \u201CRead only\u201D while it is on. It adds to whatever this app already restricts \u2014 it never loosens anything."}):null,(0,_jsxRuntime.jsx)(_sharedUi.ToggleRow,{testID:"buoy-ask-buoy-setting-bypass",tone:"warning",emphasizeLabel:t.bypassApprovals,disabled:t.readOnly,label:"Skip approval prompts",description:t.readOnly?"Unavailable while Read only is on \u2014 nothing can be approved.":"Runs every action the moment the agent calls it, with no Allow card \u2014 including the destructive ones that wipe or reset data.",value:t.bypassApprovals,onValueChange:e=>_askBuoySettings.askBuoySettings.set("bypassApprovals",e)}),t.bypassApprovals&&!t.readOnly?(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.warning,testID:"buoy-ask-buoy-bypass-warning",children:[(0,_jsxRuntime.jsx)(_sharedUi.AlertTriangle,{size:14,color:_sharedUi.night.color.warning}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.warningText,children:"Nothing will ask before a change lands. A wipe or a reset runs on the model's word alone, and Undo only reverses the changes that can be reversed \u2014 the bar tells you which. This stays on across reloads and app restarts until you turn it off here, so leave it off on any device holding data you care about. It does not widen what the agent may reach: read-only mode, this app's deny list and the release-build refusals still apply."})]}):(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.note,children:"On by default for destructive actions only \u2014 reads and ordinary writes already run without asking, and the changes bar records them."}),s.length>0?(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.trustedBox,testID:"buoy-ask-buoy-trusted",children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.section,children:"ALLOWED WITHOUT ASKING \u2014 THIS CHAT"}),s.map(e=>(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.trustedRow,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.trustedLabel,numberOfLines:2,children:e.label}),(0,_jsxRuntime.jsx)(_reactNative.Pressable,{testID:`buoy-ask-buoy-untrust-${e.key}`,accessibilityRole:"button",onPress:()=>_askBuoyStore.askBuoyStore.untrust(e.key),style:({pressed:o})=>[styles.forget,o&&{opacity:.7}],hitSlop:6,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.forgetText,children:"Ask again"})})]},e.key))]}):null]})}function formatReset(t){const s=Date.parse(t.length===10?`${t}T00:00:00Z`:t);if(Number.isNaN(s))return t;const e=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];const o=new Date(s);return`${e[o.getUTCMonth()]} ${o.getUTCDate()}`}function HostedCredits(){const t=_askBuoyStore.askBuoyStore.getUsageReader();const[s,e]=(0,_react.useState)({kind:"loading"});const o=(0,_react.useCallback)(()=>{if(!t)return;e({kind:"loading"});t().then(n=>{if(n.claude)_askBuoyStore.askBuoyStore.setClaudeOut(!n.claude.available);e({kind:"ok",usage:n})}).catch(n=>e({kind:"error",message:n instanceof Error?n.message:"Could not load credits."}))},[t]);(0,_react.useEffect)(o,[o]);if(!t)return null;return(0,_jsxRuntime.jsxs)(_reactNative.View,{testID:"buoy-ask-buoy-credits",children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.section,children:"HOSTED AI CREDITS"}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.trustedRow,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:{flex:1,gap:2},children:s.kind==="ok"?(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.trustedLabel,children:[s.usage.creditsLeft.toLocaleString()," of ",s.usage.grantCredits.toLocaleString()," credits left"]}),(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.note,children:[s.usage.resetAt?`Resets ${formatReset(s.usage.resetAt)}. `:"","That's about ",Math.floor(s.usage.creditsLeft/5).toLocaleString()," more asks, included with your plan."]})]}):s.kind==="error"?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.note,children:s.message}):(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.note,children:"Loading\u2026"})}),(0,_jsxRuntime.jsx)(_reactNative.Pressable,{testID:"buoy-ask-buoy-credits-refresh",accessibilityRole:"button",onPress:o,style:({pressed:n})=>[styles.forget,n&&{opacity:.7}],hitSlop:6,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.forgetText,children:"Refresh"})})]})]})}const MODELS=[{id:"claude",label:"Claude Haiku 5.5",note:"The default. Answers faster."},{id:"luna",label:"GPT-6 Luna",note:"Uses fewer credits."}];function HostedModel(){const t=(0,_hostedModelSetting.useHostedModel)();const{claudeOut:s}=(0,_useAskBuoy.useAskBuoyState)();if(!_askBuoyStore.askBuoyStore.getUsageReader())return null;return(0,_jsxRuntime.jsxs)(_reactNative.View,{testID:"buoy-ask-buoy-model",style:{gap:6},children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.section,children:"MODEL"}),MODELS.map(e=>{const o=t===e.id;return(0,_jsxRuntime.jsxs)(_reactNative.Pressable,{testID:`buoy-ask-buoy-model-${e.id}`,accessibilityRole:"radio",accessibilityState:{checked:o},onPress:()=>_hostedModelSetting.hostedModelSetting.set(e.id),style:({pressed:n})=>[styles.trustedRow,o&&styles.picked,n&&{opacity:.7}],children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:{flex:1,gap:2},children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.trustedLabel,children:e.label}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.note,children:e.note})]}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.forgetText,children:o?"On":""})]},e.id)}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.note,testID:"buoy-ask-buoy-model-note",children:t==="claude"&&s?"Claude is busy right now. New chats use Luna until it opens again.":"If one model is down, the other answers. A change starts with your next new chat. You can also pick it on buoy.gg, on the Ask Buoy tab."})]})}const styles=_reactNative.StyleSheet.create({picked:{borderColor:_sharedUi.night.color.info},scroll:{flex:1},content:{padding:_sharedUi.night.gutter,gap:10,paddingBottom:32},section:{color:_sharedUi.night.color.textTertiary,fontSize:10,fontWeight:"700",letterSpacing:.6,paddingHorizontal:4,paddingTop:4},warning:{flexDirection:"row",gap:8,padding:_sharedUi.night.cardPad,borderRadius:_sharedUi.night.radius.card,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.warning,backgroundColor:_sharedUi.night.color.surface},warningText:{flex:1,color:_sharedUi.night.color.warning,fontSize:_sharedUi.night.font.micro,lineHeight:16},trustedBox:{gap:6,paddingTop:6},trustedRow:{flexDirection:"row",alignItems:"center",gap:10,padding:_sharedUi.night.cardPad,borderRadius:_sharedUi.night.radius.card,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.border,backgroundColor:_sharedUi.night.color.surface},trustedLabel:{flex:1,color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.caption,lineHeight:18},forget:{paddingHorizontal:10,paddingVertical:6,borderRadius:_sharedUi.night.radius.row,backgroundColor:_sharedUi.night.color.button},forgetText:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.micro,fontWeight:"600"},note:{color:_sharedUi.night.color.textTertiary,fontSize:_sharedUi.night.font.micro,lineHeight:16,paddingHorizontal:4}});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.AskBuoySettings=AskBuoySettings;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _useAskBuoySettings=require("../store/useAskBuoySettings");var _askBuoySettings=require("../store/askBuoySettings");var _hostedModelSetting=require("../store/hostedModelSetting");var _askBuoyStore=require("../store/askBuoyStore");var _useAskBuoy=require("../store/useAskBuoy");var _jsxRuntime=require("react/jsx-runtime");function AskBuoySettings(){const t=(0,_useAskBuoySettings.useAskBuoySettings)();const s=(0,_useAskBuoy.useAskBuoyState)().trusted;return(0,_jsxRuntime.jsxs)(_reactNative.ScrollView,{keyboardShouldPersistTaps:"handled",style:styles.scroll,contentContainerStyle:styles.content,testID:"buoy-ask-buoy-settings",children:[(0,_jsxRuntime.jsx)(HostedCredits,{}),(0,_jsxRuntime.jsx)(HostedModel,{}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.section,children:"CHAT"}),(0,_jsxRuntime.jsx)(_sharedUi.ToggleRow,{testID:"buoy-ask-buoy-setting-thinking",label:"Show agent thinking",description:"Adds a collapsed strip under each answer: the model's reasoning, and every step it ran with its parameters, result, duration and token cost. Copy includes the steps and reasoning while this is on, so you can read the run outside the app.",value:t.showThinking,onValueChange:e=>_askBuoySettings.askBuoySettings.set("showThinking",e)}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.note,children:"Not every model reports reasoning. Claude thinks by default; most OpenAI models return none, and the strip then shows the steps alone."}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.section,children:"PERMISSIONS"}),(0,_jsxRuntime.jsx)(_sharedUi.ToggleRow,{testID:"buoy-ask-buoy-setting-readonly",label:"Read only",description:"Inspect the app, change nothing. Every write and simulation is refused until this is off. Undo still works \u2014 putting things back is the safe direction.",value:t.readOnly,onValueChange:e=>_askBuoySettings.askBuoySettings.set("readOnly",e)}),t.readOnly?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.note,testID:"buoy-ask-buoy-readonly-note",children:"On across reloads until you turn it off here. The header says \u201CRead only\u201D while it is on. It adds to whatever this app already restricts \u2014 it never loosens anything."}):null,(0,_jsxRuntime.jsx)(_sharedUi.ToggleRow,{testID:"buoy-ask-buoy-setting-bypass",tone:"warning",emphasizeLabel:t.bypassApprovals,disabled:t.readOnly,label:"Skip approval prompts",description:t.readOnly?"Unavailable while Read only is on \u2014 nothing can be approved.":"Runs every action the moment the agent calls it, with no Allow card \u2014 including the destructive ones that wipe or reset data.",value:t.bypassApprovals,onValueChange:e=>_askBuoySettings.askBuoySettings.set("bypassApprovals",e)}),t.bypassApprovals&&!t.readOnly?(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.warning,testID:"buoy-ask-buoy-bypass-warning",children:[(0,_jsxRuntime.jsx)(_sharedUi.AlertTriangle,{size:14,color:_sharedUi.night.color.warning}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.warningText,children:"Nothing will ask before a change lands. A wipe or a reset runs on the model's word alone, and Undo only reverses the changes that can be reversed \u2014 the bar tells you which. This stays on across reloads and app restarts until you turn it off here, so leave it off on any device holding data you care about. It does not widen what the agent may reach: read-only mode, this app's deny list and the release-build refusals still apply."})]}):(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.note,children:"On by default for destructive actions only \u2014 reads and ordinary writes already run without asking, and the changes bar records them."}),s.length>0?(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.trustedBox,testID:"buoy-ask-buoy-trusted",children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.section,children:"ALLOWED WITHOUT ASKING \u2014 THIS CHAT"}),s.map(e=>(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.trustedRow,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.trustedLabel,numberOfLines:2,children:e.label}),(0,_jsxRuntime.jsx)(_reactNative.Pressable,{testID:`buoy-ask-buoy-untrust-${e.key}`,accessibilityRole:"button",onPress:()=>_askBuoyStore.askBuoyStore.untrust(e.key),style:({pressed:o})=>[styles.forget,o&&{opacity:.7}],hitSlop:6,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.forgetText,children:"Ask again"})})]},e.key))]}):null]})}function formatReset(t){const s=Date.parse(t.length===10?`${t}T00:00:00Z`:t);if(Number.isNaN(s))return t;const e=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];const o=new Date(s);return`${e[o.getUTCMonth()]} ${o.getUTCDate()}`}function HostedCredits(){const t=_askBuoyStore.askBuoyStore.getUsageReader();const[s,e]=(0,_react.useState)({kind:"loading"});const o=(0,_react.useCallback)(()=>{if(!t)return;e({kind:"loading"});t().then(n=>{if(n.claude)_askBuoyStore.askBuoyStore.setClaudeOut(!n.claude.available);e({kind:"ok",usage:n})}).catch(n=>e({kind:"error",message:n instanceof Error?n.message:"Could not load credits."}))},[t]);(0,_react.useEffect)(o,[o]);if(!t)return null;return(0,_jsxRuntime.jsxs)(_reactNative.View,{testID:"buoy-ask-buoy-credits",children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.section,children:"HOSTED AI CREDITS"}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.trustedRow,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:{flex:1,gap:2},children:s.kind==="ok"?(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.trustedLabel,children:[s.usage.creditsLeft.toLocaleString()," of ",s.usage.grantCredits.toLocaleString()," credits left"]}),(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.note,children:[s.usage.resetAt?`Resets ${formatReset(s.usage.resetAt)}. `:"","That's about ",Math.floor(s.usage.creditsLeft/5).toLocaleString()," more asks, included with your plan."]})]}):s.kind==="error"?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.note,children:s.message}):(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.note,children:"Loading\u2026"})}),(0,_jsxRuntime.jsx)(_reactNative.Pressable,{testID:"buoy-ask-buoy-credits-refresh",accessibilityRole:"button",onPress:o,style:({pressed:n})=>[styles.forget,n&&{opacity:.7}],hitSlop:6,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.forgetText,children:"Refresh"})})]})]})}const MODELS=[{id:"claude",label:"Claude Haiku 5.5",note:"The default. Answers faster."},{id:"luna",label:"GPT-6 Luna",note:"Uses fewer credits."}];function HostedModel(){const t=(0,_hostedModelSetting.useHostedModel)();const{claudeOut:s}=(0,_useAskBuoy.useAskBuoyState)();if(!_askBuoyStore.askBuoyStore.getUsageReader())return null;return(0,_jsxRuntime.jsxs)(_reactNative.View,{testID:"buoy-ask-buoy-model",style:{gap:6},children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.section,children:"MODEL"}),MODELS.map(e=>{const o=t===e.id;return(0,_jsxRuntime.jsxs)(_reactNative.Pressable,{testID:`buoy-ask-buoy-model-${e.id}`,accessibilityRole:"radio",accessibilityState:{checked:o},onPress:()=>_hostedModelSetting.hostedModelSetting.set(e.id),style:({pressed:n})=>[styles.trustedRow,o&&styles.picked,n&&{opacity:.7}],children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:{flex:1,gap:2},children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.trustedLabel,children:e.label}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.note,children:e.note})]}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.forgetText,children:o?"On":""})]},e.id)}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.note,testID:"buoy-ask-buoy-model-note",children:t==="claude"&&s?"Claude is busy right now. New chats use Luna until it opens again.":"If one model is down, the other answers. A change starts with your next new chat. You can also pick it on buoy.gg, on the Ask Buoy tab."})]})}const styles=_reactNative.StyleSheet.create({picked:{borderColor:_sharedUi.night.color.info},scroll:{flex:1},content:{padding:_sharedUi.night.gutter,gap:10,paddingBottom:32},section:{color:_sharedUi.night.color.textTertiary,fontSize:10,fontWeight:"700",letterSpacing:.6,paddingHorizontal:4,paddingTop:4},warning:{flexDirection:"row",gap:8,padding:_sharedUi.night.cardPad,borderRadius:_sharedUi.night.radius.card,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.warning,backgroundColor:_sharedUi.night.color.surface},warningText:{flex:1,color:_sharedUi.night.color.warning,fontSize:_sharedUi.night.font.micro,lineHeight:16},trustedBox:{gap:6,paddingTop:6},trustedRow:{flexDirection:"row",alignItems:"center",gap:10,padding:_sharedUi.night.cardPad,borderRadius:_sharedUi.night.radius.card,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.border,backgroundColor:_sharedUi.night.color.surface},trustedLabel:{flex:1,color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.caption,lineHeight:18},forget:{paddingHorizontal:10,paddingVertical:6,borderRadius:_sharedUi.night.radius.row,backgroundColor:_sharedUi.night.color.button},forgetText:{color:_sharedUi.night.color.text,fontSize:_sharedUi.night.font.micro,fontWeight:"600"},note:{color:_sharedUi.night.color.textTertiary,fontSize:_sharedUi.night.font.micro,lineHeight:16,paddingHorizontal:4}});
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.Markdown=Markdown;exports.renderInline=renderInline;var _sharedUi=require("@buoy-gg/shared-ui");var _reactNative=require("react-native");var _react=require("react");var _markdownParse=require("./markdownParse");var _jsxRuntime=require("react/jsx-runtime");function renderInline(l,o){const t=l.replace(/!?\[([^\]]*)\]\([^)]*\)/g,"$1");const e=[];const i=/(\*\*[^*]+\*\*|`[^`]+`|\*[^*\s][^*]*\*|_[^_\s][^_]*_)/g;let n=0;let c;let s=0;while(c=i.exec(t)){if(c.index>n)e.push(t.slice(n,c.index));const r=c[0];if(r.startsWith("**")){e.push((0,_jsxRuntime.jsx)(_reactNative.Text,{style:[o,styles.bold],children:r.slice(2,-2)},s++))}else if(r.startsWith("`")){e.push((0,_jsxRuntime.jsx)(_reactNative.Text,{style:[o,styles.code],children:r.slice(1,-1)},s++))}else{e.push((0,_jsxRuntime.jsx)(_reactNative.Text,{style:[o,styles.italic],children:r.slice(1,-1)},s++))}n=c.index+r.length}if(n<t.length)e.push(t.slice(n));return e}const stripLinks=l=>l.replace(/!?\[([^\]]*)\]\([^)]*\)/g,"$1");function MarkdownTable({header:l,rows:o}){const[t,e]=(0,_react.useState)(false);const i=(0,_markdownParse.tableTruncation)(l,o);const n=t?l:l.slice(0,_markdownParse.TABLE_PREVIEW_COLS);const c=t?o:o.slice(0,_markdownParse.TABLE_PREVIEW_ROWS);const s=(0,_jsxRuntime.jsxs)(_reactNative.View,{style:t&&styles.tableWide,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.tableHead,children:n.map((r,d)=>(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.th,d===0&&styles.firstCol,t&&styles.colFixed],numberOfLines:1,children:r.replace(/\*\*/g,"")},d))}),c.map((r,d)=>(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.tr,d>0&&styles.trDivider],children:n.map((h,a)=>(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.td,a===0&&styles.firstCol,a===0&&styles.tdFirst,t&&styles.colFixed],numberOfLines:t?3:2,children:renderInline(stripLinks(r[a]??""),styles.td)},a))},d))]});return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.table,testID:"buoy-ask-buoy-md-table",children:[t?(0,_jsxRuntime.jsx)(_reactNative.ScrollView,{style:styles.tableScrollV,nestedScrollEnabled:true,children:(0,_jsxRuntime.jsx)(_reactNative.ScrollView,{horizontal:true,showsHorizontalScrollIndicator:true,children:s})}):s,i?(0,_jsxRuntime.jsxs)(_reactNative.Pressable,{testID:"buoy-ask-buoy-md-table-toggle",accessibilityRole:"button",accessibilityLabel:t?"Show fewer rows":"Show all rows and columns",onPress:()=>e(r=>!r),style:({pressed:r})=>[styles.tfoot,r&&styles.pressed],children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.tfootText,children:t?`All ${o.length} rows \xB7 ${l.length} columns`:i}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.tfootAction,children:t?"Show fewer":"Show all"})]}):null]})}function Markdown({text:l,style:o}){const t=(0,_markdownParse.parseBlocks)(l);return(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.wrap,children:t.map((e,i)=>{if(e.kind==="table")return(0,_jsxRuntime.jsx)(MarkdownTable,{header:e.header,rows:e.rows},i);if(e.kind==="code"){return(0,_jsxRuntime.jsx)(_reactNative.ScrollView,{horizontal:true,style:styles.codeBlock,contentContainerStyle:styles.codeBlockContent,testID:"buoy-ask-buoy-md-code",children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.codeText,selectable:true,children:e.text})},i)}if(e.kind==="li"){return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:[styles.li,{paddingLeft:4+e.depth*14}],children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[o,styles.marker],children:e.marker}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[o,styles.liText],selectable:true,children:renderInline(e.text,o)})]},i)}return(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[o,e.kind==="h"&&styles.bold],selectable:true,children:renderInline(e.text,o)},i)})})}const styles=_reactNative.StyleSheet.create({wrap:{gap:8},bold:{fontWeight:"600"},italic:{fontStyle:"italic"},code:{fontFamily:_reactNative.Platform.OS==="web"?_sharedUi.monoFont:"Menlo",fontSize:13,color:_sharedUi.night.color.accent,backgroundColor:_sharedUi.night.color.fill},codeBlock:{borderRadius:_sharedUi.night.radius.row,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.border,backgroundColor:_sharedUi.night.color.surface},codeBlockContent:{paddingHorizontal:12,paddingVertical:10},codeText:{fontFamily:_reactNative.Platform.OS==="web"?_sharedUi.monoFont:"Menlo",fontSize:12,lineHeight:18,color:_sharedUi.night.color.text},li:{flexDirection:"row",gap:8},table:{borderRadius:_sharedUi.night.radius.row,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.border,backgroundColor:_sharedUi.night.color.surface,overflow:"hidden"},tableWide:{minWidth:"100%"},tableScrollV:{maxHeight:320},tableHead:{flexDirection:"row",paddingHorizontal:10,paddingVertical:6,gap:8,backgroundColor:_sharedUi.night.color.fill},th:{flex:1,color:_sharedUi.night.color.textTertiary,fontSize:_sharedUi.night.font.micro,fontWeight:"700",letterSpacing:.6,textTransform:"uppercase"},tr:{flexDirection:"row",paddingHorizontal:10,paddingVertical:7,gap:8},trDivider:{borderTopWidth:_reactNative.StyleSheet.hairlineWidth,borderTopColor:_sharedUi.night.color.separator},td:{flex:1,color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption,lineHeight:17},tdFirst:{color:_sharedUi.night.color.text,fontWeight:"500"},firstCol:{flex:1.3},colFixed:{flex:0,width:110},tfoot:{flexDirection:"row",justifyContent:"space-between",alignItems:"center",paddingHorizontal:10,paddingVertical:8,borderTopWidth:_reactNative.StyleSheet.hairlineWidth,borderTopColor:_sharedUi.night.color.border},tfootText:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.micro},tfootAction:{color:_sharedUi.night.color.accent,fontSize:_sharedUi.night.font.micro,fontWeight:"600"},pressed:{opacity:.7},marker:{color:_sharedUi.night.color.textSecondary,minWidth:14,textAlign:"right"},liText:{flex:1}});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.Markdown=Markdown;exports.renderInline=renderInline;var _sharedUi=require("@buoy-gg/shared-ui");var _reactNative=require("react-native");var _react=require("react");var _markdownParse=require("./markdownParse");var _jsxRuntime=require("react/jsx-runtime");function renderInline(l,o){const t=l.replace(/!?\[([^\]]*)\]\([^)]*\)/g,"$1");const e=[];const i=/(\*\*[^*]+\*\*|`[^`]+`|\*[^*\s][^*]*\*|_[^_\s][^_]*_)/g;let n=0;let c;let s=0;while(c=i.exec(t)){if(c.index>n)e.push(t.slice(n,c.index));const r=c[0];if(r.startsWith("**")){e.push((0,_jsxRuntime.jsx)(_reactNative.Text,{style:[o,styles.bold],children:r.slice(2,-2)},s++))}else if(r.startsWith("`")){e.push((0,_jsxRuntime.jsx)(_reactNative.Text,{style:[o,styles.code],children:r.slice(1,-1)},s++))}else{e.push((0,_jsxRuntime.jsx)(_reactNative.Text,{style:[o,styles.italic],children:r.slice(1,-1)},s++))}n=c.index+r.length}if(n<t.length)e.push(t.slice(n));return e}const stripLinks=l=>l.replace(/!?\[([^\]]*)\]\([^)]*\)/g,"$1");function MarkdownTable({header:l,rows:o}){const[t,e]=(0,_react.useState)(false);const i=(0,_markdownParse.tableTruncation)(l,o);const n=t?l:l.slice(0,_markdownParse.TABLE_PREVIEW_COLS);const c=t?o:o.slice(0,_markdownParse.TABLE_PREVIEW_ROWS);const s=(0,_jsxRuntime.jsxs)(_reactNative.View,{style:t&&styles.tableWide,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.tableHead,children:n.map((r,d)=>(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.th,d===0&&styles.firstCol,t&&styles.colFixed],numberOfLines:1,children:r.replace(/\*\*/g,"")},d))}),c.map((r,d)=>(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.tr,d>0&&styles.trDivider],children:n.map((h,a)=>(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.td,a===0&&styles.firstCol,a===0&&styles.tdFirst,t&&styles.colFixed],numberOfLines:t?3:2,children:renderInline(stripLinks(r[a]??""),styles.td)},a))},d))]});return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.table,testID:"buoy-ask-buoy-md-table",children:[t?(0,_jsxRuntime.jsx)(_reactNative.ScrollView,{keyboardShouldPersistTaps:"handled",style:styles.tableScrollV,nestedScrollEnabled:true,children:(0,_jsxRuntime.jsx)(_reactNative.ScrollView,{horizontal:true,showsHorizontalScrollIndicator:true,children:s})}):s,i?(0,_jsxRuntime.jsxs)(_reactNative.Pressable,{testID:"buoy-ask-buoy-md-table-toggle",accessibilityRole:"button",accessibilityLabel:t?"Show fewer rows":"Show all rows and columns",onPress:()=>e(r=>!r),style:({pressed:r})=>[styles.tfoot,r&&styles.pressed],children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.tfootText,children:t?`All ${o.length} rows \xB7 ${l.length} columns`:i}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.tfootAction,children:t?"Show fewer":"Show all"})]}):null]})}function Markdown({text:l,style:o}){const t=(0,_markdownParse.parseBlocks)(l);return(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.wrap,children:t.map((e,i)=>{if(e.kind==="table")return(0,_jsxRuntime.jsx)(MarkdownTable,{header:e.header,rows:e.rows},i);if(e.kind==="code"){return(0,_jsxRuntime.jsx)(_reactNative.ScrollView,{horizontal:true,style:styles.codeBlock,contentContainerStyle:styles.codeBlockContent,testID:"buoy-ask-buoy-md-code",children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.codeText,selectable:true,children:e.text})},i)}if(e.kind==="li"){return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:[styles.li,{paddingLeft:4+e.depth*14}],children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[o,styles.marker],children:e.marker}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[o,styles.liText],selectable:true,children:renderInline(e.text,o)})]},i)}return(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[o,e.kind==="h"&&styles.bold],selectable:true,children:renderInline(e.text,o)},i)})})}const styles=_reactNative.StyleSheet.create({wrap:{gap:8},bold:{fontWeight:"600"},italic:{fontStyle:"italic"},code:{fontFamily:_reactNative.Platform.OS==="web"?_sharedUi.monoFont:"Menlo",fontSize:13,color:_sharedUi.night.color.accent,backgroundColor:_sharedUi.night.color.fill},codeBlock:{borderRadius:_sharedUi.night.radius.row,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.border,backgroundColor:_sharedUi.night.color.surface},codeBlockContent:{paddingHorizontal:12,paddingVertical:10},codeText:{fontFamily:_reactNative.Platform.OS==="web"?_sharedUi.monoFont:"Menlo",fontSize:12,lineHeight:18,color:_sharedUi.night.color.text},li:{flexDirection:"row",gap:8},table:{borderRadius:_sharedUi.night.radius.row,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_sharedUi.night.color.border,backgroundColor:_sharedUi.night.color.surface,overflow:"hidden"},tableWide:{minWidth:"100%"},tableScrollV:{maxHeight:320},tableHead:{flexDirection:"row",paddingHorizontal:10,paddingVertical:6,gap:8,backgroundColor:_sharedUi.night.color.fill},th:{flex:1,color:_sharedUi.night.color.textTertiary,fontSize:_sharedUi.night.font.micro,fontWeight:"700",letterSpacing:.6,textTransform:"uppercase"},tr:{flexDirection:"row",paddingHorizontal:10,paddingVertical:7,gap:8},trDivider:{borderTopWidth:_reactNative.StyleSheet.hairlineWidth,borderTopColor:_sharedUi.night.color.separator},td:{flex:1,color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.caption,lineHeight:17},tdFirst:{color:_sharedUi.night.color.text,fontWeight:"500"},firstCol:{flex:1.3},colFixed:{flex:0,width:110},tfoot:{flexDirection:"row",justifyContent:"space-between",alignItems:"center",paddingHorizontal:10,paddingVertical:8,borderTopWidth:_reactNative.StyleSheet.hairlineWidth,borderTopColor:_sharedUi.night.color.border},tfootText:{color:_sharedUi.night.color.textSecondary,fontSize:_sharedUi.night.font.micro},tfootAction:{color:_sharedUi.night.color.accent,fontSize:_sharedUi.night.font.micro,fontWeight:"600"},pressed:{opacity:.7},marker:{color:_sharedUi.night.color.textSecondary,minWidth:14,textAlign:"right"},liText:{flex:1}});
@@ -1 +1 @@
1
- "use strict";import{useState as h}from"react";import{Pressable as p,ScrollView as b,StyleSheet as u,Text as r,TextInput as y,View as s}from"react-native";import{AlertTriangle as f,ChevronDown as g,night as o}from"@buoy-gg/shared-ui";import{jsx as t,jsxs as d}from"react/jsx-runtime";export function ApprovalCard({pending:l,onAnswer:n}){const[i,a]=h("");return d(s,{style:e.card,testID:"buoy-ask-buoy-approval",children:[d(s,{style:e.titleRow,children:[t(f,{size:14,color:o.color.warning}),t(r,{style:e.title,children:"Allow this change?"})]}),l.restored?t(r,{style:e.restored,testID:"buoy-ask-buoy-approval-restored",children:"Asked before the app restarted \u2014 check it still applies."}):null,t(r,{style:e.label,children:l.label}),t(r,{style:e.reason,children:l.reason}),l.description?t(x,{text:l.description}):null,t(y,{testID:"buoy-ask-buoy-approval-note",value:i,onChangeText:a,placeholder:"Add a note for the agent (optional)",placeholderTextColor:o.color.textTertiary,style:e.note,returnKeyType:"done",blurOnSubmit:true}),d(s,{style:e.actions,children:[t(p,{testID:"buoy-ask-buoy-approve",accessibilityRole:"button",onPress:()=>n({approved:true,reason:i}),style:({pressed:c})=>[e.button,e.approve,c&&e.pressed],children:t(r,{style:e.approveText,children:"Allow"})}),l.restored?null:t(p,{testID:"buoy-ask-buoy-approve-trust",accessibilityRole:"button",onPress:()=>n({approved:true,reason:i,trust:true}),style:({pressed:c})=>[e.button,e.trust,c&&e.pressed],children:t(r,{style:e.trustText,children:"Allow for this chat"})}),t(p,{testID:"buoy-ask-buoy-reject",accessibilityRole:"button",onPress:()=>n({approved:false,reason:i}),style:({pressed:c})=>[e.button,e.reject,c&&e.pressed],children:t(r,{style:e.rejectText,children:"Not now"})})]})]})}function x({text:l}){const[n,i]=h(false);return d(s,{children:[d(p,{testID:"buoy-ask-buoy-approval-details",accessibilityRole:"button",accessibilityState:{expanded:n},onPress:()=>i(a=>!a),style:({pressed:a})=>[e.disclosure,a&&e.pressed],hitSlop:6,children:[t(s,{style:n?e.chevronOpen:e.chevronClosed,children:t(g,{size:12,color:o.color.textTertiary})}),t(r,{style:e.disclosureText,children:n?"Hide details":"Details"})]}),n?t(b,{style:e.detail,contentContainerStyle:e.detailContent,nestedScrollEnabled:true,children:t(r,{style:e.description,children:l})}):null]})}const e=u.create({card:{marginHorizontal:o.gutter,marginBottom:10,padding:o.cardPad,borderRadius:o.radius.card,borderWidth:u.hairlineWidth,borderColor:o.color.accentBorderStrong,backgroundColor:o.color.surface,gap:6},titleRow:{flexDirection:"row",alignItems:"center",gap:6},title:{color:o.color.text,fontSize:o.font.caption,fontWeight:"600"},label:{color:o.color.text,fontSize:o.font.row,fontWeight:"600",lineHeight:20},description:{color:o.color.textSecondary,fontSize:o.font.caption,lineHeight:18},reason:{color:o.color.warning,fontSize:o.font.caption,lineHeight:18},restored:{color:o.color.info,backgroundColor:o.color.infoSoft,fontSize:o.font.micro,lineHeight:16,paddingHorizontal:8,paddingVertical:5,borderRadius:8},disclosure:{flexDirection:"row",alignItems:"center",gap:4,paddingVertical:4},disclosureText:{color:o.color.textTertiary,fontSize:o.font.micro,fontWeight:"600"},chevronOpen:{transform:[{rotate:"0deg"}]},chevronClosed:{transform:[{rotate:"-90deg"}]},detail:{maxHeight:150,marginTop:2},detailContent:{paddingBottom:2},note:{color:o.color.text,fontSize:o.font.caption,paddingHorizontal:10,paddingVertical:7,borderRadius:o.radius.row,borderWidth:u.hairlineWidth,borderColor:o.color.border,backgroundColor:o.color.button,marginTop:2},actions:{flexDirection:"row",flexWrap:"wrap",gap:8,marginTop:6},button:{paddingHorizontal:16,paddingVertical:9,borderRadius:o.radius.row},approve:{backgroundColor:o.color.accent},approveText:{color:o.color.onAccent,fontWeight:"600",fontSize:o.font.caption},trust:{backgroundColor:o.color.button,borderWidth:u.hairlineWidth,borderColor:o.color.accentBorderStrong},trustText:{color:o.color.accent,fontWeight:"600",fontSize:o.font.caption},reject:{backgroundColor:o.color.button},rejectText:{color:o.color.text,fontSize:o.font.caption},pressed:{opacity:.7}});
1
+ "use strict";import{useState as h}from"react";import{Pressable as p,ScrollView as b,StyleSheet as u,Text as r,TextInput as y,View as c}from"react-native";import{AlertTriangle as f,ChevronDown as g,night as o}from"@buoy-gg/shared-ui";import{jsx as t,jsxs as d}from"react/jsx-runtime";export function ApprovalCard({pending:l,onAnswer:n}){const[i,a]=h("");return d(c,{style:e.card,testID:"buoy-ask-buoy-approval",children:[d(c,{style:e.titleRow,children:[t(f,{size:14,color:o.color.warning}),t(r,{style:e.title,children:"Allow this change?"})]}),l.restored?t(r,{style:e.restored,testID:"buoy-ask-buoy-approval-restored",children:"Asked before the app restarted \u2014 check it still applies."}):null,t(r,{style:e.label,children:l.label}),t(r,{style:e.reason,children:l.reason}),l.description?t(x,{text:l.description}):null,t(y,{testID:"buoy-ask-buoy-approval-note",value:i,onChangeText:a,placeholder:"Add a note for the agent (optional)",placeholderTextColor:o.color.textTertiary,style:e.note,returnKeyType:"done",blurOnSubmit:true}),d(c,{style:e.actions,children:[t(p,{testID:"buoy-ask-buoy-approve",accessibilityRole:"button",onPress:()=>n({approved:true,reason:i}),style:({pressed:s})=>[e.button,e.approve,s&&e.pressed],children:t(r,{style:e.approveText,children:"Allow"})}),l.restored?null:t(p,{testID:"buoy-ask-buoy-approve-trust",accessibilityRole:"button",onPress:()=>n({approved:true,reason:i,trust:true}),style:({pressed:s})=>[e.button,e.trust,s&&e.pressed],children:t(r,{style:e.trustText,children:"Allow for this chat"})}),t(p,{testID:"buoy-ask-buoy-reject",accessibilityRole:"button",onPress:()=>n({approved:false,reason:i}),style:({pressed:s})=>[e.button,e.reject,s&&e.pressed],children:t(r,{style:e.rejectText,children:"Not now"})})]})]})}function x({text:l}){const[n,i]=h(false);return d(c,{children:[d(p,{testID:"buoy-ask-buoy-approval-details",accessibilityRole:"button",accessibilityState:{expanded:n},onPress:()=>i(a=>!a),style:({pressed:a})=>[e.disclosure,a&&e.pressed],hitSlop:6,children:[t(c,{style:n?e.chevronOpen:e.chevronClosed,children:t(g,{size:12,color:o.color.textTertiary})}),t(r,{style:e.disclosureText,children:n?"Hide details":"Details"})]}),n?t(b,{keyboardShouldPersistTaps:"handled",style:e.detail,contentContainerStyle:e.detailContent,nestedScrollEnabled:true,children:t(r,{style:e.description,children:l})}):null]})}const e=u.create({card:{marginHorizontal:o.gutter,marginBottom:10,padding:o.cardPad,borderRadius:o.radius.card,borderWidth:u.hairlineWidth,borderColor:o.color.accentBorderStrong,backgroundColor:o.color.surface,gap:6},titleRow:{flexDirection:"row",alignItems:"center",gap:6},title:{color:o.color.text,fontSize:o.font.caption,fontWeight:"600"},label:{color:o.color.text,fontSize:o.font.row,fontWeight:"600",lineHeight:20},description:{color:o.color.textSecondary,fontSize:o.font.caption,lineHeight:18},reason:{color:o.color.warning,fontSize:o.font.caption,lineHeight:18},restored:{color:o.color.info,backgroundColor:o.color.infoSoft,fontSize:o.font.micro,lineHeight:16,paddingHorizontal:8,paddingVertical:5,borderRadius:8},disclosure:{flexDirection:"row",alignItems:"center",gap:4,paddingVertical:4},disclosureText:{color:o.color.textTertiary,fontSize:o.font.micro,fontWeight:"600"},chevronOpen:{transform:[{rotate:"0deg"}]},chevronClosed:{transform:[{rotate:"-90deg"}]},detail:{maxHeight:150,marginTop:2},detailContent:{paddingBottom:2},note:{color:o.color.text,fontSize:o.font.caption,paddingHorizontal:10,paddingVertical:7,borderRadius:o.radius.row,borderWidth:u.hairlineWidth,borderColor:o.color.border,backgroundColor:o.color.button,marginTop:2},actions:{flexDirection:"row",flexWrap:"wrap",gap:8,marginTop:6},button:{paddingHorizontal:16,paddingVertical:9,borderRadius:o.radius.row},approve:{backgroundColor:o.color.accent},approveText:{color:o.color.onAccent,fontWeight:"600",fontSize:o.font.caption},trust:{backgroundColor:o.color.button,borderWidth:u.hairlineWidth,borderColor:o.color.accentBorderStrong},trustText:{color:o.color.accent,fontWeight:"600",fontSize:o.font.caption},reject:{backgroundColor:o.color.button},rejectText:{color:o.color.text,fontSize:o.font.caption},pressed:{opacity:.7}});
@@ -1,3 +1,3 @@
1
- "use strict";import{useCallback as a,useEffect as y,useMemo as T,useRef as h,useState as H}from"react";import{Alert as Y,Animated as R,Pressable as Pe,StyleSheet as $e,Text as N,View as B}from"react-native";import{isReversible as He}from"@buoy-gg/agent-core";import{dispatchToolAction as Re,FeatureGate as Ne,Info as X,JsModal as Oe,ModalHeader as O,night as i,setToolAttention as u,useSafeAreaInsets as De}from"@buoy-gg/shared-ui";import{BlockHandlersProvider as Le}from"../blocks";import{ApprovalCard as Me}from"./ApprovalCard";import{ChangesBar as Ke,useLedgerEntries as Ee}from"./ChangesBar";import{ruleStatesFrom as je}from"../blocks/ruleStates";import{Composer as qe}from"./Composer";import{KeyboardPad as ze}from"./KeyboardPad";import{AskBuoyHeader as Fe}from"./AskBuoyHeader";import{AskBuoySettings as Ve}from"./AskBuoySettings";import{EmptyState as Ue}from"./EmptyState";import{MessageList as _e,transcriptToText as Qe}from"./MessageList";import{QueuedMessages as We}from"./QueuedMessages";import{askBuoyStore as l,queuePauseReason as Ge}from"../store/askBuoyStore";import{TICKET_PROMPT as Je}from"../store/ticketPrompt";import{useAskBuoy as Ye}from"../store/useAskBuoy";import{useAskBuoySettings as Xe}from"../store/useAskBuoySettings";import{askBuoySettings as Z}from"../store/askBuoySettings";import{jsx as o,jsxs as d,Fragment as Ze}from"react/jsx-runtime";export function AskBuoyModal({visible:x,onClose:D,onBack:L,onMinimize:b,persistenceKey:ee,config:g}){const{state:e,send:k,stop:C,reset:S,undoThenReset:M,approve:te,retry:oe,answer:K,runAction:E,editQueued:ne,removeQueued:se,configured:I,toolCount:re,availableToolIds:ae}=Ye(g);const[ie,le]=H(false);const ce=a(()=>{C();D()},[C,D]);const ue=a(()=>l.clearDraft(),[]);const[v,P]=H(false);const de=a(()=>P(false),[]);const ge=a(()=>P(true),[]);const p=!x;const j=!!e.pending||!!e.awaitingBlockId;const s=e.messages[e.messages.length-1];const w=h(false);const q=h(e.busy);y(()=>{if(p&&q.current&&!e.busy)w.current=true;if(!p)w.current=false;q.current=e.busy},[p,e.busy]);y(()=>{if(!p){u("ask-buoy",null);return}if(j){u("ask-buoy",{kind:"needsInput",label:e.pending?"Needs your approval":"Has a question for you"})}else if(w.current&&s?.role==="assistant"&&s.error){u("ask-buoy",{kind:"failed",label:"The last turn failed"})}else if(w.current&&!e.busy){u("ask-buoy",{kind:"done",label:"Finished"})}else{u("ask-buoy",null)}},[p,j,e.busy,e.pending,s]);y(()=>()=>u("ask-buoy",null),[]);y(()=>{if(e.pending&&v)P(false)},[e.pending,v]);const pe=De({minBottom:16});const[fe,me]=H("bottomSheet");const ye=fe==="floating"?0:pe.bottom;const he=a(()=>{const t=l.getLedger();if(!t)return;void(async()=>{const n=await t.revertAll(Re);if(n.failed.length===0){l.setNotice(null);return}const r=n.failed.map(m=>`${m.label} (${m.error})`).join("; ");l.setNotice(`Couldn't undo ${n.failed.length} change${n.failed.length===1?"":"s"} \u2014 ${r}`)})()},[]);const be=a(()=>le(t=>!t),[]);const f=h(new R.Value(560)).current;const $=h(false);const z=a(()=>{if($.current)return;$.current=true;f.stopAnimation(t=>{const n=typeof t==="number"&&t>200?t:560;R.timing(f,{toValue:120,duration:220,useNativeDriver:false}).start(()=>{setTimeout(()=>{R.spring(f,{toValue:n,friction:9,useNativeDriver:false}).start(()=>{$.current=false})},2500)})})},[f]);const A=T(()=>{const t=e.messages[e.messages.length-1];if(!t||t.role!=="assistant")return"";const n=t.blocks.filter(r=>r.block.kind==="peek").length;return n>0?`${t.id}:${n}`:""},[e.messages]);const F=h("");y(()=>{if(A&&A!==F.current&&g?.peek!==false)z();F.current=A},[A,z,g]);const ke=a(()=>{const t=l.getLedger();const n=t?.list().filter(r=>!r.undoneAt&&He(r.effect)).length??0;if(n===0){S();return}Y.alert("Undo changes first?",`Ask Buoy made ${n} change${n===1?"":"s"} that can still be undone. Clearing the conversation loses the only automatic undo for ${n===1?"it":"them"}.`,[{text:"Undo, then clear",onPress:()=>{void(async()=>{const r=await M();if(r.cleared)return;const m=r.reverted+r.failed.length;const Ie=r.failed.map(J=>`${J.label} (${J.error})`).join("\n");Y.alert(`Couldn't undo ${r.failed.length} of ${m} change${m===1?"":"s"}`,`${Ie}
1
+ "use strict";import{useCallback as a,useEffect as y,useMemo as T,useRef as h,useState as H}from"react";import{Alert as Y,Animated as R,Pressable as Pe,StyleSheet as $e,Text as N,View as B}from"react-native";import{isReversible as He}from"@buoy-gg/agent-core";import{dispatchToolAction as Re,FeatureGate as Ne,Info as X,JsModal as Oe,ModalHeader as O,night as i,setToolAttention as u,useSafeAreaInsets as De}from"@buoy-gg/shared-ui";import{BlockHandlersProvider as Le}from"../blocks";import{ApprovalCard as Ke}from"./ApprovalCard";import{ChangesBar as Me,useLedgerEntries as Ee}from"./ChangesBar";import{ruleStatesFrom as je}from"../blocks/ruleStates";import{Composer as qe}from"./Composer";import{KeyboardPad as ze}from"./KeyboardPad";import{AskBuoyHeader as Fe}from"./AskBuoyHeader";import{AskBuoySettings as Ve}from"./AskBuoySettings";import{EmptyState as Ue}from"./EmptyState";import{MessageList as _e,transcriptToText as Qe}from"./MessageList";import{QueuedMessages as We}from"./QueuedMessages";import{askBuoyStore as l,queuePauseReason as Ge}from"../store/askBuoyStore";import{TICKET_PROMPT as Je}from"../store/ticketPrompt";import{useAskBuoy as Ye}from"../store/useAskBuoy";import{useAskBuoySettings as Xe}from"../store/useAskBuoySettings";import{askBuoySettings as Z}from"../store/askBuoySettings";import{jsx as o,jsxs as d,Fragment as Ze}from"react/jsx-runtime";export function AskBuoyModal({visible:x,onClose:D,onBack:L,onMinimize:b,persistenceKey:ee,config:g}){const{state:e,send:k,stop:C,reset:S,undoThenReset:K,approve:te,retry:oe,answer:M,runAction:E,editQueued:se,removeQueued:ne,configured:I,toolCount:re,availableToolIds:ae}=Ye(g);const[ie,le]=H(false);const ce=a(()=>{C();D()},[C,D]);const ue=a(()=>l.clearDraft(),[]);const[v,P]=H(false);const de=a(()=>P(false),[]);const ge=a(()=>P(true),[]);const p=!x;const j=!!e.pending||!!e.awaitingBlockId;const n=e.messages[e.messages.length-1];const w=h(false);const q=h(e.busy);y(()=>{if(p&&q.current&&!e.busy)w.current=true;if(!p)w.current=false;q.current=e.busy},[p,e.busy]);y(()=>{if(!p){u("ask-buoy",null);return}if(j){u("ask-buoy",{kind:"needsInput",label:e.pending?"Needs your approval":"Has a question for you"})}else if(w.current&&n?.role==="assistant"&&n.error){u("ask-buoy",{kind:"failed",label:"The last turn failed"})}else if(w.current&&!e.busy){u("ask-buoy",{kind:"done",label:"Finished"})}else{u("ask-buoy",null)}},[p,j,e.busy,e.pending,n]);y(()=>()=>u("ask-buoy",null),[]);y(()=>{if(e.pending&&v)P(false)},[e.pending,v]);const pe=De({minBottom:16});const[fe,me]=H("bottomSheet");const ye=fe==="floating"?0:pe.bottom;const he=a(()=>{const t=l.getLedger();if(!t)return;void(async()=>{const s=await t.revertAll(Re);if(s.failed.length===0){l.setNotice(null);return}const r=s.failed.map(m=>`${m.label} (${m.error})`).join("; ");l.setNotice(`Couldn't undo ${s.failed.length} change${s.failed.length===1?"":"s"} \u2014 ${r}`)})()},[]);const be=a(()=>le(t=>!t),[]);const f=h(new R.Value(560)).current;const $=h(false);const z=a(()=>{if($.current)return;$.current=true;f.stopAnimation(t=>{const s=typeof t==="number"&&t>200?t:560;R.timing(f,{toValue:120,duration:220,useNativeDriver:false}).start(()=>{setTimeout(()=>{R.spring(f,{toValue:s,friction:9,useNativeDriver:false}).start(()=>{$.current=false})},2500)})})},[f]);const A=T(()=>{const t=e.messages[e.messages.length-1];if(!t||t.role!=="assistant")return"";const s=t.blocks.filter(r=>r.block.kind==="peek").length;return s>0?`${t.id}:${s}`:""},[e.messages]);const F=h("");y(()=>{if(A&&A!==F.current&&g?.peek!==false)z();F.current=A},[A,z,g]);const ke=a(()=>{const t=l.getLedger();const s=t?.list().filter(r=>!r.undoneAt&&He(r.effect)).length??0;if(s===0){S();return}Y.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 r=await K();if(r.cleared)return;const m=r.reverted+r.failed.length;const Ie=r.failed.map(J=>`${J.label} (${J.error})`).join("\n");Y.alert(`Couldn't undo ${r.failed.length} of ${m} change${m===1?"":"s"}`,`${Ie}
2
2
 
3
- Still applied in the app. Clear the conversation anyway?`,[{text:"Keep conversation",style:"cancel"},{text:"Clear anyway",style:"destructive",onPress:S}])})()}},{text:"Clear anyway",style:"destructive",onPress:S},{text:"Cancel",style:"cancel"}])},[S,M]);const Se=T(()=>{const t=e.messages[e.messages.length-1];if(!t||t.role!=="assistant"||!t.streaming)return null;return t.toolCalls.find(n=>n.status==="running")?.label??null},[e.messages]);const V=Ee(l.getLedger());const U=T(()=>je(V),[V]);const ve=T(()=>({answer:K,runAction:(t,n)=>{if(t.minimize){b?.({mode:"bottomSheet"});return}return E(t,n)},answered:e.answers,actionState:e.actionState,busy:e.busy,supports:{openTool:false,minimize:!!b,dispatch:true},rules:U}),[K,E,b,e.answers,e.actionState,e.busy,U]);const we=!e.busy&&s?.role==="assistant"&&!!s.error;const _=!e.busy&&s?.role==="assistant"&&s.stopped&&!s.error?s.id:null;const Ae=Ge(e);const{showThinking:Q,readOnly:W,claudeNoticeSeen:Te}=Xe();const G=g?.hosted===true&&!Te;const Be=a(()=>Qe(e.messages,Q),[e.messages,Q]);const xe=a(()=>k(Je),[k]);const Ce=v?d(O,{children:[o(O.Navigation,{onBack:de}),o(O.Content,{title:"Settings",subtitle:"Ask Buoy",testID:"buoy-ask-buoy-settings-title"})]}):o(Fe,{configured:I,busy:e.busy,failed:we,activeLabel:Se,awaitingApproval:!!e.pending,startedAt:s?.role==="assistant"&&s.streaming?s.startedAt??null:null,stopping:e.stopping,readOnly:W,toolCount:re,hasMessages:e.messages.length>0,onBack:L,onReset:ke,getTranscript:Be,onOpenSettings:ge,onTicket:xe});return o(Oe,{visible:x,onClose:ce,disableScrollWrapper:true,background:false,initialHeight:560,animatedHeight:f,header:{customContent:Ce,showToggleButton:false},onBack:L,onMinimize:b,onModeChange:me,persistenceKey:ee??"buoy-ask-buoy",enablePersistence:true,children:o(Le,{value:ve,children:d(B,{style:[c.root,{paddingBottom:ye}],children:[o(Ke,{ledger:l.getLedger(),onUndoAll:he,expanded:ie,onToggle:be}),G&&d(B,{style:c.notice,testID:"buoy-ask-buoy-hosted-notice",children:[o(X,{size:14,color:i.color.info}),d(B,{style:{flex:1,gap:8},children:[o(N,{style:c.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."}),o(Pe,{testID:"buoy-ask-buoy-hosted-notice-ok",accessibilityRole:"button",onPress:()=>{Z.set("claudeNoticeSeen",true);Z.set("hostedNoticeSeen",true)},style:({pressed:t})=>[c.noticeButton,t&&{opacity:.7}],children:o(N,{style:c.noticeButtonText,children:"Got it"})})]})]}),e.notice&&d(B,{style:c.notice,testID:"buoy-ask-buoy-notice",children:[o(X,{size:14,color:i.color.info}),o(N,{style:c.noticeText,children:e.notice})]}),o(ze,{children:o(Ne,{featureName:"Ask Buoy",children:v?o(Ve,{}):d(Ze,{children:[o(_e,{messages:e.messages,onRetry:oe,waitingOnUser:!!e.pending||!!e.awaitingBlockId,ListEmptyComponent:o(Ue,{configured:I,onPick:k,availableToolIds:ae,readOnly:W||!!g?.policy?.readOnly})}),o(We,{items:e.queued,paused:Ae,onEdit:ne,onRemove:se}),e.pending&&o(Me,{pending:e.pending,onAnswer:te}),o(qe,{onSend:k,onStop:C,busy:e.busy,draft:e.draft,onDraftTaken:ue,disabled:!I||G,focusKey:_,canFocus:x,placeholder:_?"Tell it what to do differently\u2026":e.awaitingBlockId?"Pick an option above, or type\u2026":void 0})]})})})]})})})}const c=$e.create({root:{flex:1,backgroundColor:"transparent"},notice:{flexDirection:"row",alignItems:"flex-start",gap:8,paddingHorizontal:i.gutter,paddingVertical:10,backgroundColor:i.color.infoSoft},noticeText:{flex:1,color:i.color.text,fontSize:i.font.caption,lineHeight:18},noticeButton:{alignSelf:"flex-start",paddingHorizontal:12,paddingVertical:6,borderRadius:i.radius.row,backgroundColor:i.color.button},noticeButtonText:{color:i.color.text,fontSize:i.font.caption,fontWeight:"600"}});
3
+ Still applied in the app. Clear the conversation anyway?`,[{text:"Keep conversation",style:"cancel"},{text:"Clear anyway",style:"destructive",onPress:S}])})()}},{text:"Clear anyway",style:"destructive",onPress:S},{text:"Cancel",style:"cancel"}])},[S,K]);const Se=T(()=>{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 V=Ee(l.getLedger());const U=T(()=>je(V),[V]);const ve=T(()=>({answer:M,runAction:(t,s)=>{if(t.minimize){b?.({mode:"bottomSheet"});return}return E(t,s)},answered:e.answers,actionState:e.actionState,busy:e.busy,supports:{openTool:false,minimize:!!b,dispatch:true},rules:U}),[M,E,b,e.answers,e.actionState,e.busy,U]);const we=!e.busy&&n?.role==="assistant"&&!!n.error;const _=!e.busy&&n?.role==="assistant"&&n.stopped&&!n.error?n.id:null;const Ae=Ge(e);const{showThinking:Q,readOnly:W,claudeNoticeSeen:Te}=Xe();const G=g?.hosted===true&&!Te;const Be=a(()=>Qe(e.messages,Q),[e.messages,Q]);const xe=a(()=>k(Je),[k]);const Ce=v?d(O,{children:[o(O.Navigation,{onBack:de}),o(O.Content,{title:"Settings",subtitle:"Ask Buoy",testID:"buoy-ask-buoy-settings-title"})]}):o(Fe,{configured:I,busy:e.busy,failed:we,activeLabel:Se,awaitingApproval:!!e.pending,startedAt:n?.role==="assistant"&&n.streaming?n.startedAt??null:null,stopping:e.stopping,readOnly:W,toolCount:re,hasMessages:e.messages.length>0,onBack:L,onReset:ke,getTranscript:Be,onOpenSettings:ge,onTicket:xe});return o(Oe,{visible:x,onClose:ce,disableScrollWrapper:true,avoidKeyboard:false,background:false,initialHeight:560,animatedHeight:f,header:{customContent:Ce,showToggleButton:false},onBack:L,onMinimize:b,onModeChange:me,persistenceKey:ee??"buoy-ask-buoy",enablePersistence:true,children:o(Le,{value:ve,children:d(B,{style:[c.root,{paddingBottom:ye}],children:[o(Me,{ledger:l.getLedger(),onUndoAll:he,expanded:ie,onToggle:be}),G&&d(B,{style:c.notice,testID:"buoy-ask-buoy-hosted-notice",children:[o(X,{size:14,color:i.color.info}),d(B,{style:{flex:1,gap:8},children:[o(N,{style:c.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."}),o(Pe,{testID:"buoy-ask-buoy-hosted-notice-ok",accessibilityRole:"button",onPress:()=>{Z.set("claudeNoticeSeen",true);Z.set("hostedNoticeSeen",true)},style:({pressed:t})=>[c.noticeButton,t&&{opacity:.7}],children:o(N,{style:c.noticeButtonText,children:"Got it"})})]})]}),e.notice&&d(B,{style:c.notice,testID:"buoy-ask-buoy-notice",children:[o(X,{size:14,color:i.color.info}),o(N,{style:c.noticeText,children:e.notice})]}),o(ze,{children:o(Ne,{featureName:"Ask Buoy",children:v?o(Ve,{}):d(Ze,{children:[o(_e,{messages:e.messages,onRetry:oe,waitingOnUser:!!e.pending||!!e.awaitingBlockId,ListEmptyComponent:o(Ue,{configured:I,onPick:k,availableToolIds:ae,readOnly:W||!!g?.policy?.readOnly})}),o(We,{items:e.queued,paused:Ae,onEdit:se,onRemove:ne}),e.pending&&o(Ke,{pending:e.pending,onAnswer:te}),o(qe,{onSend:k,onStop:C,busy:e.busy,draft:e.draft,onDraftTaken:ue,disabled:!I||G,focusKey:_,canFocus:x,placeholder:_?"Tell it what to do differently\u2026":e.awaitingBlockId?"Pick an option above, or type\u2026":void 0})]})})})]})})})}const c=$e.create({root:{flex:1,backgroundColor:"transparent"},notice:{flexDirection:"row",alignItems:"flex-start",gap:8,paddingHorizontal:i.gutter,paddingVertical:10,backgroundColor:i.color.infoSoft},noticeText:{flex:1,color:i.color.text,fontSize:i.font.caption,lineHeight:18},noticeButton:{alignSelf:"flex-start",paddingHorizontal:12,paddingVertical:6,borderRadius:i.radius.row,backgroundColor:i.color.button},noticeButtonText:{color:i.color.text,fontSize:i.font.caption,fontWeight:"600"}});
@@ -1 +1 @@
1
- "use strict";import{useCallback as f,useEffect as k,useState as w}from"react";import{Pressable as h,ScrollView as m,StyleSheet as y,Text as r,View as c}from"react-native";import{AlertTriangle as S,night as s,ToggleRow as g}from"@buoy-gg/shared-ui";import{useAskBuoySettings as T}from"../store/useAskBuoySettings";import{askBuoySettings as p}from"../store/askBuoySettings";import{hostedModelSetting as x,useHostedModel as I}from"../store/hostedModelSetting";import{askBuoyStore as u}from"../store/askBuoyStore";import{useAskBuoyState as b}from"../store/useAskBuoy";import{jsx as t,jsxs as l,Fragment as A}from"react/jsx-runtime";export function AskBuoySettings(){const n=T();const a=b().trusted;return l(m,{style:e.scroll,contentContainerStyle:e.content,testID:"buoy-ask-buoy-settings",children:[t(D,{}),t(v,{}),t(r,{style:e.section,children:"CHAT"}),t(g,{testID:"buoy-ask-buoy-setting-thinking",label:"Show agent thinking",description:"Adds a collapsed strip under each answer: the model's reasoning, and every step it ran with its parameters, result, duration and token cost. Copy includes the steps and reasoning while this is on, so you can read the run outside the app.",value:n.showThinking,onValueChange:o=>p.set("showThinking",o)}),t(r,{style:e.note,children:"Not every model reports reasoning. Claude thinks by default; most OpenAI models return none, and the strip then shows the steps alone."}),t(r,{style:e.section,children:"PERMISSIONS"}),t(g,{testID:"buoy-ask-buoy-setting-readonly",label:"Read only",description:"Inspect the app, change nothing. Every write and simulation is refused until this is off. Undo still works \u2014 putting things back is the safe direction.",value:n.readOnly,onValueChange:o=>p.set("readOnly",o)}),n.readOnly?t(r,{style:e.note,testID:"buoy-ask-buoy-readonly-note",children:"On across reloads until you turn it off here. The header says \u201CRead only\u201D while it is on. It adds to whatever this app already restricts \u2014 it never loosens anything."}):null,t(g,{testID:"buoy-ask-buoy-setting-bypass",tone:"warning",emphasizeLabel:n.bypassApprovals,disabled:n.readOnly,label:"Skip approval prompts",description:n.readOnly?"Unavailable while Read only is on \u2014 nothing can be approved.":"Runs every action the moment the agent calls it, with no Allow card \u2014 including the destructive ones that wipe or reset data.",value:n.bypassApprovals,onValueChange:o=>p.set("bypassApprovals",o)}),n.bypassApprovals&&!n.readOnly?l(c,{style:e.warning,testID:"buoy-ask-buoy-bypass-warning",children:[t(S,{size:14,color:s.color.warning}),t(r,{style:e.warningText,children:"Nothing will ask before a change lands. A wipe or a reset runs on the model's word alone, and Undo only reverses the changes that can be reversed \u2014 the bar tells you which. This stays on across reloads and app restarts until you turn it off here, so leave it off on any device holding data you care about. It does not widen what the agent may reach: read-only mode, this app's deny list and the release-build refusals still apply."})]}):t(r,{style:e.note,children:"On by default for destructive actions only \u2014 reads and ordinary writes already run without asking, and the changes bar records them."}),a.length>0?l(c,{style:e.trustedBox,testID:"buoy-ask-buoy-trusted",children:[t(r,{style:e.section,children:"ALLOWED WITHOUT ASKING \u2014 THIS CHAT"}),a.map(o=>l(c,{style:e.trustedRow,children:[t(r,{style:e.trustedLabel,numberOfLines:2,children:o.label}),t(h,{testID:`buoy-ask-buoy-untrust-${o.key}`,accessibilityRole:"button",onPress:()=>u.untrust(o.key),style:({pressed:i})=>[e.forget,i&&{opacity:.7}],hitSlop:6,children:t(r,{style:e.forgetText,children:"Ask again"})})]},o.key))]}):null]})}function C(n){const a=Date.parse(n.length===10?`${n}T00:00:00Z`:n);if(Number.isNaN(a))return n;const o=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];const i=new Date(a);return`${o[i.getUTCMonth()]} ${i.getUTCDate()}`}function D(){const n=u.getUsageReader();const[a,o]=w({kind:"loading"});const i=f(()=>{if(!n)return;o({kind:"loading"});n().then(d=>{if(d.claude)u.setClaudeOut(!d.claude.available);o({kind:"ok",usage:d})}).catch(d=>o({kind:"error",message:d instanceof Error?d.message:"Could not load credits."}))},[n]);k(i,[i]);if(!n)return null;return l(c,{testID:"buoy-ask-buoy-credits",children:[t(r,{style:e.section,children:"HOSTED AI CREDITS"}),l(c,{style:e.trustedRow,children:[t(c,{style:{flex:1,gap:2},children:a.kind==="ok"?l(A,{children:[l(r,{style:e.trustedLabel,children:[a.usage.creditsLeft.toLocaleString()," of ",a.usage.grantCredits.toLocaleString()," credits left"]}),l(r,{style:e.note,children:[a.usage.resetAt?`Resets ${C(a.usage.resetAt)}. `:"","That's about ",Math.floor(a.usage.creditsLeft/5).toLocaleString()," more asks, included with your plan."]})]}):a.kind==="error"?t(r,{style:e.note,children:a.message}):t(r,{style:e.note,children:"Loading\u2026"})}),t(h,{testID:"buoy-ask-buoy-credits-refresh",accessibilityRole:"button",onPress:i,style:({pressed:d})=>[e.forget,d&&{opacity:.7}],hitSlop:6,children:t(r,{style:e.forgetText,children:"Refresh"})})]})]})}const R=[{id:"claude",label:"Claude Haiku 5.5",note:"The default. Answers faster."},{id:"luna",label:"GPT-6 Luna",note:"Uses fewer credits."}];function v(){const n=I();const{claudeOut:a}=b();if(!u.getUsageReader())return null;return l(c,{testID:"buoy-ask-buoy-model",style:{gap:6},children:[t(r,{style:e.section,children:"MODEL"}),R.map(o=>{const i=n===o.id;return l(h,{testID:`buoy-ask-buoy-model-${o.id}`,accessibilityRole:"radio",accessibilityState:{checked:i},onPress:()=>x.set(o.id),style:({pressed:d})=>[e.trustedRow,i&&e.picked,d&&{opacity:.7}],children:[l(c,{style:{flex:1,gap:2},children:[t(r,{style:e.trustedLabel,children:o.label}),t(r,{style:e.note,children:o.note})]}),t(r,{style:e.forgetText,children:i?"On":""})]},o.id)}),t(r,{style:e.note,testID:"buoy-ask-buoy-model-note",children:n==="claude"&&a?"Claude is busy right now. New chats use Luna until it opens again.":"If one model is down, the other answers. A change starts with your next new chat. You can also pick it on buoy.gg, on the Ask Buoy tab."})]})}const e=y.create({picked:{borderColor:s.color.info},scroll:{flex:1},content:{padding:s.gutter,gap:10,paddingBottom:32},section:{color:s.color.textTertiary,fontSize:10,fontWeight:"700",letterSpacing:.6,paddingHorizontal:4,paddingTop:4},warning:{flexDirection:"row",gap:8,padding:s.cardPad,borderRadius:s.radius.card,borderWidth:y.hairlineWidth,borderColor:s.color.warning,backgroundColor:s.color.surface},warningText:{flex:1,color:s.color.warning,fontSize:s.font.micro,lineHeight:16},trustedBox:{gap:6,paddingTop:6},trustedRow:{flexDirection:"row",alignItems:"center",gap:10,padding:s.cardPad,borderRadius:s.radius.card,borderWidth:y.hairlineWidth,borderColor:s.color.border,backgroundColor:s.color.surface},trustedLabel:{flex:1,color:s.color.text,fontSize:s.font.caption,lineHeight:18},forget:{paddingHorizontal:10,paddingVertical:6,borderRadius:s.radius.row,backgroundColor:s.color.button},forgetText:{color:s.color.text,fontSize:s.font.micro,fontWeight:"600"},note:{color:s.color.textTertiary,fontSize:s.font.micro,lineHeight:16,paddingHorizontal:4}});
1
+ "use strict";import{useCallback as f,useEffect as k,useState as w}from"react";import{Pressable as h,ScrollView as m,StyleSheet as y,Text as r,View as c}from"react-native";import{AlertTriangle as S,night as s,ToggleRow as g}from"@buoy-gg/shared-ui";import{useAskBuoySettings as T}from"../store/useAskBuoySettings";import{askBuoySettings as p}from"../store/askBuoySettings";import{hostedModelSetting as x,useHostedModel as I}from"../store/hostedModelSetting";import{askBuoyStore as u}from"../store/askBuoyStore";import{useAskBuoyState as b}from"../store/useAskBuoy";import{jsx as t,jsxs as l,Fragment as A}from"react/jsx-runtime";export function AskBuoySettings(){const n=T();const a=b().trusted;return l(m,{keyboardShouldPersistTaps:"handled",style:e.scroll,contentContainerStyle:e.content,testID:"buoy-ask-buoy-settings",children:[t(D,{}),t(v,{}),t(r,{style:e.section,children:"CHAT"}),t(g,{testID:"buoy-ask-buoy-setting-thinking",label:"Show agent thinking",description:"Adds a collapsed strip under each answer: the model's reasoning, and every step it ran with its parameters, result, duration and token cost. Copy includes the steps and reasoning while this is on, so you can read the run outside the app.",value:n.showThinking,onValueChange:o=>p.set("showThinking",o)}),t(r,{style:e.note,children:"Not every model reports reasoning. Claude thinks by default; most OpenAI models return none, and the strip then shows the steps alone."}),t(r,{style:e.section,children:"PERMISSIONS"}),t(g,{testID:"buoy-ask-buoy-setting-readonly",label:"Read only",description:"Inspect the app, change nothing. Every write and simulation is refused until this is off. Undo still works \u2014 putting things back is the safe direction.",value:n.readOnly,onValueChange:o=>p.set("readOnly",o)}),n.readOnly?t(r,{style:e.note,testID:"buoy-ask-buoy-readonly-note",children:"On across reloads until you turn it off here. The header says \u201CRead only\u201D while it is on. It adds to whatever this app already restricts \u2014 it never loosens anything."}):null,t(g,{testID:"buoy-ask-buoy-setting-bypass",tone:"warning",emphasizeLabel:n.bypassApprovals,disabled:n.readOnly,label:"Skip approval prompts",description:n.readOnly?"Unavailable while Read only is on \u2014 nothing can be approved.":"Runs every action the moment the agent calls it, with no Allow card \u2014 including the destructive ones that wipe or reset data.",value:n.bypassApprovals,onValueChange:o=>p.set("bypassApprovals",o)}),n.bypassApprovals&&!n.readOnly?l(c,{style:e.warning,testID:"buoy-ask-buoy-bypass-warning",children:[t(S,{size:14,color:s.color.warning}),t(r,{style:e.warningText,children:"Nothing will ask before a change lands. A wipe or a reset runs on the model's word alone, and Undo only reverses the changes that can be reversed \u2014 the bar tells you which. This stays on across reloads and app restarts until you turn it off here, so leave it off on any device holding data you care about. It does not widen what the agent may reach: read-only mode, this app's deny list and the release-build refusals still apply."})]}):t(r,{style:e.note,children:"On by default for destructive actions only \u2014 reads and ordinary writes already run without asking, and the changes bar records them."}),a.length>0?l(c,{style:e.trustedBox,testID:"buoy-ask-buoy-trusted",children:[t(r,{style:e.section,children:"ALLOWED WITHOUT ASKING \u2014 THIS CHAT"}),a.map(o=>l(c,{style:e.trustedRow,children:[t(r,{style:e.trustedLabel,numberOfLines:2,children:o.label}),t(h,{testID:`buoy-ask-buoy-untrust-${o.key}`,accessibilityRole:"button",onPress:()=>u.untrust(o.key),style:({pressed:i})=>[e.forget,i&&{opacity:.7}],hitSlop:6,children:t(r,{style:e.forgetText,children:"Ask again"})})]},o.key))]}):null]})}function C(n){const a=Date.parse(n.length===10?`${n}T00:00:00Z`:n);if(Number.isNaN(a))return n;const o=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];const i=new Date(a);return`${o[i.getUTCMonth()]} ${i.getUTCDate()}`}function D(){const n=u.getUsageReader();const[a,o]=w({kind:"loading"});const i=f(()=>{if(!n)return;o({kind:"loading"});n().then(d=>{if(d.claude)u.setClaudeOut(!d.claude.available);o({kind:"ok",usage:d})}).catch(d=>o({kind:"error",message:d instanceof Error?d.message:"Could not load credits."}))},[n]);k(i,[i]);if(!n)return null;return l(c,{testID:"buoy-ask-buoy-credits",children:[t(r,{style:e.section,children:"HOSTED AI CREDITS"}),l(c,{style:e.trustedRow,children:[t(c,{style:{flex:1,gap:2},children:a.kind==="ok"?l(A,{children:[l(r,{style:e.trustedLabel,children:[a.usage.creditsLeft.toLocaleString()," of ",a.usage.grantCredits.toLocaleString()," credits left"]}),l(r,{style:e.note,children:[a.usage.resetAt?`Resets ${C(a.usage.resetAt)}. `:"","That's about ",Math.floor(a.usage.creditsLeft/5).toLocaleString()," more asks, included with your plan."]})]}):a.kind==="error"?t(r,{style:e.note,children:a.message}):t(r,{style:e.note,children:"Loading\u2026"})}),t(h,{testID:"buoy-ask-buoy-credits-refresh",accessibilityRole:"button",onPress:i,style:({pressed:d})=>[e.forget,d&&{opacity:.7}],hitSlop:6,children:t(r,{style:e.forgetText,children:"Refresh"})})]})]})}const R=[{id:"claude",label:"Claude Haiku 5.5",note:"The default. Answers faster."},{id:"luna",label:"GPT-6 Luna",note:"Uses fewer credits."}];function v(){const n=I();const{claudeOut:a}=b();if(!u.getUsageReader())return null;return l(c,{testID:"buoy-ask-buoy-model",style:{gap:6},children:[t(r,{style:e.section,children:"MODEL"}),R.map(o=>{const i=n===o.id;return l(h,{testID:`buoy-ask-buoy-model-${o.id}`,accessibilityRole:"radio",accessibilityState:{checked:i},onPress:()=>x.set(o.id),style:({pressed:d})=>[e.trustedRow,i&&e.picked,d&&{opacity:.7}],children:[l(c,{style:{flex:1,gap:2},children:[t(r,{style:e.trustedLabel,children:o.label}),t(r,{style:e.note,children:o.note})]}),t(r,{style:e.forgetText,children:i?"On":""})]},o.id)}),t(r,{style:e.note,testID:"buoy-ask-buoy-model-note",children:n==="claude"&&a?"Claude is busy right now. New chats use Luna until it opens again.":"If one model is down, the other answers. A change starts with your next new chat. You can also pick it on buoy.gg, on the Ask Buoy tab."})]})}const e=y.create({picked:{borderColor:s.color.info},scroll:{flex:1},content:{padding:s.gutter,gap:10,paddingBottom:32},section:{color:s.color.textTertiary,fontSize:10,fontWeight:"700",letterSpacing:.6,paddingHorizontal:4,paddingTop:4},warning:{flexDirection:"row",gap:8,padding:s.cardPad,borderRadius:s.radius.card,borderWidth:y.hairlineWidth,borderColor:s.color.warning,backgroundColor:s.color.surface},warningText:{flex:1,color:s.color.warning,fontSize:s.font.micro,lineHeight:16},trustedBox:{gap:6,paddingTop:6},trustedRow:{flexDirection:"row",alignItems:"center",gap:10,padding:s.cardPad,borderRadius:s.radius.card,borderWidth:y.hairlineWidth,borderColor:s.color.border,backgroundColor:s.color.surface},trustedLabel:{flex:1,color:s.color.text,fontSize:s.font.caption,lineHeight:18},forget:{paddingHorizontal:10,paddingVertical:6,borderRadius:s.radius.row,backgroundColor:s.color.button},forgetText:{color:s.color.text,fontSize:s.font.micro,fontWeight:"600"},note:{color:s.color.textTertiary,fontSize:s.font.micro,lineHeight:16,paddingHorizontal:4}});
@@ -1 +1 @@
1
- "use strict";import{monoFont as y}from"@buoy-gg/shared-ui";import{Platform as w}from"react-native";import{useState as S}from"react";import{Pressable as W,ScrollView as g,StyleSheet as x,Text as c,View as p}from"react-native";import{night as o}from"@buoy-gg/shared-ui";import{parseBlocks as k,TABLE_PREVIEW_COLS as T,TABLE_PREVIEW_ROWS as C,tableTruncation as z}from"./markdownParse";import{jsx as r,jsxs as m}from"react/jsx-runtime";export function renderInline(d,i){const l=d.replace(/!?\[([^\]]*)\]\([^)]*\)/g,"$1");const t=[];const s=/(\*\*[^*]+\*\*|`[^`]+`|\*[^*\s][^*]*\*|_[^_\s][^_]*_)/g;let a=0;let h;let f=0;while(h=s.exec(l)){if(h.index>a)t.push(l.slice(a,h.index));const n=h[0];if(n.startsWith("**")){t.push(r(c,{style:[i,e.bold],children:n.slice(2,-2)},f++))}else if(n.startsWith("`")){t.push(r(c,{style:[i,e.code],children:n.slice(1,-1)},f++))}else{t.push(r(c,{style:[i,e.italic],children:n.slice(1,-1)},f++))}a=h.index+n.length}if(a<l.length)t.push(l.slice(a));return t}const _=d=>d.replace(/!?\[([^\]]*)\]\([^)]*\)/g,"$1");function H({header:d,rows:i}){const[l,t]=S(false);const s=z(d,i);const a=l?d:d.slice(0,T);const h=l?i:i.slice(0,C);const f=m(p,{style:l&&e.tableWide,children:[r(p,{style:e.tableHead,children:a.map((n,u)=>r(c,{style:[e.th,u===0&&e.firstCol,l&&e.colFixed],numberOfLines:1,children:n.replace(/\*\*/g,"")},u))}),h.map((n,u)=>r(p,{style:[e.tr,u>0&&e.trDivider],children:a.map((V,b)=>r(c,{style:[e.td,b===0&&e.firstCol,b===0&&e.tdFirst,l&&e.colFixed],numberOfLines:l?3:2,children:renderInline(_(n[b]??""),e.td)},b))},u))]});return m(p,{style:e.table,testID:"buoy-ask-buoy-md-table",children:[l?r(g,{style:e.tableScrollV,nestedScrollEnabled:true,children:r(g,{horizontal:true,showsHorizontalScrollIndicator:true,children:f})}):f,s?m(W,{testID:"buoy-ask-buoy-md-table-toggle",accessibilityRole:"button",accessibilityLabel:l?"Show fewer rows":"Show all rows and columns",onPress:()=>t(n=>!n),style:({pressed:n})=>[e.tfoot,n&&e.pressed],children:[r(c,{style:e.tfootText,children:l?`All ${i.length} rows \xB7 ${d.length} columns`:s}),r(c,{style:e.tfootAction,children:l?"Show fewer":"Show all"})]}):null]})}export function Markdown({text:d,style:i}){const l=k(d);return r(p,{style:e.wrap,children:l.map((t,s)=>{if(t.kind==="table")return r(H,{header:t.header,rows:t.rows},s);if(t.kind==="code"){return r(g,{horizontal:true,style:e.codeBlock,contentContainerStyle:e.codeBlockContent,testID:"buoy-ask-buoy-md-code",children:r(c,{style:e.codeText,selectable:true,children:t.text})},s)}if(t.kind==="li"){return m(p,{style:[e.li,{paddingLeft:4+t.depth*14}],children:[r(c,{style:[i,e.marker],children:t.marker}),r(c,{style:[i,e.liText],selectable:true,children:renderInline(t.text,i)})]},s)}return r(c,{style:[i,t.kind==="h"&&e.bold],selectable:true,children:renderInline(t.text,i)},s)})})}const e=x.create({wrap:{gap:8},bold:{fontWeight:"600"},italic:{fontStyle:"italic"},code:{fontFamily:w.OS==="web"?y:"Menlo",fontSize:13,color:o.color.accent,backgroundColor:o.color.fill},codeBlock:{borderRadius:o.radius.row,borderWidth:x.hairlineWidth,borderColor:o.color.border,backgroundColor:o.color.surface},codeBlockContent:{paddingHorizontal:12,paddingVertical:10},codeText:{fontFamily:w.OS==="web"?y:"Menlo",fontSize:12,lineHeight:18,color:o.color.text},li:{flexDirection:"row",gap:8},table:{borderRadius:o.radius.row,borderWidth:x.hairlineWidth,borderColor:o.color.border,backgroundColor:o.color.surface,overflow:"hidden"},tableWide:{minWidth:"100%"},tableScrollV:{maxHeight:320},tableHead:{flexDirection:"row",paddingHorizontal:10,paddingVertical:6,gap:8,backgroundColor:o.color.fill},th:{flex:1,color:o.color.textTertiary,fontSize:o.font.micro,fontWeight:"700",letterSpacing:.6,textTransform:"uppercase"},tr:{flexDirection:"row",paddingHorizontal:10,paddingVertical:7,gap:8},trDivider:{borderTopWidth:x.hairlineWidth,borderTopColor:o.color.separator},td:{flex:1,color:o.color.textSecondary,fontSize:o.font.caption,lineHeight:17},tdFirst:{color:o.color.text,fontWeight:"500"},firstCol:{flex:1.3},colFixed:{flex:0,width:110},tfoot:{flexDirection:"row",justifyContent:"space-between",alignItems:"center",paddingHorizontal:10,paddingVertical:8,borderTopWidth:x.hairlineWidth,borderTopColor:o.color.border},tfootText:{color:o.color.textSecondary,fontSize:o.font.micro},tfootAction:{color:o.color.accent,fontSize:o.font.micro,fontWeight:"600"},pressed:{opacity:.7},marker:{color:o.color.textSecondary,minWidth:14,textAlign:"right"},liText:{flex:1}});
1
+ "use strict";import{monoFont as y}from"@buoy-gg/shared-ui";import{Platform as w}from"react-native";import{useState as S}from"react";import{Pressable as k,ScrollView as g,StyleSheet as b,Text as c,View as p}from"react-native";import{night as o}from"@buoy-gg/shared-ui";import{parseBlocks as W,TABLE_PREVIEW_COLS as T,TABLE_PREVIEW_ROWS as C,tableTruncation as z}from"./markdownParse";import{jsx as r,jsxs as m}from"react/jsx-runtime";export function renderInline(d,i){const l=d.replace(/!?\[([^\]]*)\]\([^)]*\)/g,"$1");const t=[];const s=/(\*\*[^*]+\*\*|`[^`]+`|\*[^*\s][^*]*\*|_[^_\s][^_]*_)/g;let a=0;let h;let f=0;while(h=s.exec(l)){if(h.index>a)t.push(l.slice(a,h.index));const n=h[0];if(n.startsWith("**")){t.push(r(c,{style:[i,e.bold],children:n.slice(2,-2)},f++))}else if(n.startsWith("`")){t.push(r(c,{style:[i,e.code],children:n.slice(1,-1)},f++))}else{t.push(r(c,{style:[i,e.italic],children:n.slice(1,-1)},f++))}a=h.index+n.length}if(a<l.length)t.push(l.slice(a));return t}const _=d=>d.replace(/!?\[([^\]]*)\]\([^)]*\)/g,"$1");function H({header:d,rows:i}){const[l,t]=S(false);const s=z(d,i);const a=l?d:d.slice(0,T);const h=l?i:i.slice(0,C);const f=m(p,{style:l&&e.tableWide,children:[r(p,{style:e.tableHead,children:a.map((n,u)=>r(c,{style:[e.th,u===0&&e.firstCol,l&&e.colFixed],numberOfLines:1,children:n.replace(/\*\*/g,"")},u))}),h.map((n,u)=>r(p,{style:[e.tr,u>0&&e.trDivider],children:a.map((V,x)=>r(c,{style:[e.td,x===0&&e.firstCol,x===0&&e.tdFirst,l&&e.colFixed],numberOfLines:l?3:2,children:renderInline(_(n[x]??""),e.td)},x))},u))]});return m(p,{style:e.table,testID:"buoy-ask-buoy-md-table",children:[l?r(g,{keyboardShouldPersistTaps:"handled",style:e.tableScrollV,nestedScrollEnabled:true,children:r(g,{horizontal:true,showsHorizontalScrollIndicator:true,children:f})}):f,s?m(k,{testID:"buoy-ask-buoy-md-table-toggle",accessibilityRole:"button",accessibilityLabel:l?"Show fewer rows":"Show all rows and columns",onPress:()=>t(n=>!n),style:({pressed:n})=>[e.tfoot,n&&e.pressed],children:[r(c,{style:e.tfootText,children:l?`All ${i.length} rows \xB7 ${d.length} columns`:s}),r(c,{style:e.tfootAction,children:l?"Show fewer":"Show all"})]}):null]})}export function Markdown({text:d,style:i}){const l=W(d);return r(p,{style:e.wrap,children:l.map((t,s)=>{if(t.kind==="table")return r(H,{header:t.header,rows:t.rows},s);if(t.kind==="code"){return r(g,{horizontal:true,style:e.codeBlock,contentContainerStyle:e.codeBlockContent,testID:"buoy-ask-buoy-md-code",children:r(c,{style:e.codeText,selectable:true,children:t.text})},s)}if(t.kind==="li"){return m(p,{style:[e.li,{paddingLeft:4+t.depth*14}],children:[r(c,{style:[i,e.marker],children:t.marker}),r(c,{style:[i,e.liText],selectable:true,children:renderInline(t.text,i)})]},s)}return r(c,{style:[i,t.kind==="h"&&e.bold],selectable:true,children:renderInline(t.text,i)},s)})})}const e=b.create({wrap:{gap:8},bold:{fontWeight:"600"},italic:{fontStyle:"italic"},code:{fontFamily:w.OS==="web"?y:"Menlo",fontSize:13,color:o.color.accent,backgroundColor:o.color.fill},codeBlock:{borderRadius:o.radius.row,borderWidth:b.hairlineWidth,borderColor:o.color.border,backgroundColor:o.color.surface},codeBlockContent:{paddingHorizontal:12,paddingVertical:10},codeText:{fontFamily:w.OS==="web"?y:"Menlo",fontSize:12,lineHeight:18,color:o.color.text},li:{flexDirection:"row",gap:8},table:{borderRadius:o.radius.row,borderWidth:b.hairlineWidth,borderColor:o.color.border,backgroundColor:o.color.surface,overflow:"hidden"},tableWide:{minWidth:"100%"},tableScrollV:{maxHeight:320},tableHead:{flexDirection:"row",paddingHorizontal:10,paddingVertical:6,gap:8,backgroundColor:o.color.fill},th:{flex:1,color:o.color.textTertiary,fontSize:o.font.micro,fontWeight:"700",letterSpacing:.6,textTransform:"uppercase"},tr:{flexDirection:"row",paddingHorizontal:10,paddingVertical:7,gap:8},trDivider:{borderTopWidth:b.hairlineWidth,borderTopColor:o.color.separator},td:{flex:1,color:o.color.textSecondary,fontSize:o.font.caption,lineHeight:17},tdFirst:{color:o.color.text,fontWeight:"500"},firstCol:{flex:1.3},colFixed:{flex:0,width:110},tfoot:{flexDirection:"row",justifyContent:"space-between",alignItems:"center",paddingHorizontal:10,paddingVertical:8,borderTopWidth:b.hairlineWidth,borderTopColor:o.color.border},tfootText:{color:o.color.textSecondary,fontSize:o.font.micro},tfootAction:{color:o.color.accent,fontSize:o.font.micro,fontWeight:"600"},pressed:{opacity:.7},marker:{color:o.color.textSecondary,minWidth:14,textAlign:"right"},liText:{flex:1}});