feat(sagi): spawn a real claude session for Sagi's Ask handoff
Unmatched Ask questions now adopt a dedicated "Sagi" lane (POST /api/lanes/ensure, cwd defaults to $HOME) and spawn a tmux-backed claude run there instead of just prefilling the Run page composer.
This commit is contained in:
@@ -87,6 +87,10 @@ export interface SagiBrain {
|
||||
status: SagiStatus;
|
||||
bubble: string | null;
|
||||
dismissBubble: () => void;
|
||||
/** Imperative bubble setter for one-off messages from the shell (e.g. spawn
|
||||
* errors). Bypasses the throttle because the caller decided this message
|
||||
* must be seen right now. Auto-clears after the standard bubble TTL. */
|
||||
setBubble: (text: string) => void;
|
||||
muted: boolean;
|
||||
toggleMute: () => void;
|
||||
clearAlerts: () => void;
|
||||
@@ -103,7 +107,7 @@ export function useSagiBrain(): SagiBrain {
|
||||
connected: true,
|
||||
}));
|
||||
const [tick, setTick] = useState(now0);
|
||||
const [bubble, setBubble] = useState<string | null>(null);
|
||||
const [bubble, setBubbleState] = useState<string | null>(null);
|
||||
const [muted, setMuted] = useState<boolean>(() => sagiPrefs.getMuted());
|
||||
|
||||
const bubbleTimer = useRef<ReturnType<typeof setTimeout>>();
|
||||
@@ -121,8 +125,8 @@ export function useSagiBrain(): SagiBrain {
|
||||
if (!force && t - lastBubbleAt.current < BUBBLE_THROTTLE_MS) return;
|
||||
lastBubbleAt.current = t;
|
||||
clearTimeout(bubbleTimer.current);
|
||||
setBubble(text);
|
||||
bubbleTimer.current = setTimeout(() => setBubble(null), BUBBLE_MS);
|
||||
setBubbleState(text);
|
||||
bubbleTimer.current = setTimeout(() => setBubbleState(null), BUBBLE_MS);
|
||||
}, []);
|
||||
|
||||
// Seed from the REST snapshot on mount so counts are accurate immediately -
|
||||
@@ -176,7 +180,7 @@ export function useSagiBrain(): SagiBrain {
|
||||
|
||||
const dismissBubble = useCallback(() => {
|
||||
clearTimeout(bubbleTimer.current);
|
||||
setBubble(null);
|
||||
setBubbleState(null);
|
||||
}, []);
|
||||
|
||||
const toggleMute = useCallback(() => {
|
||||
@@ -193,5 +197,25 @@ export function useSagiBrain(): SagiBrain {
|
||||
[]
|
||||
);
|
||||
|
||||
return { mood, status, bubble, dismissBubble, muted, toggleMute, clearAlerts, setThinking };
|
||||
// One-shot bubble: clears itself after BUBBLE_MS. Used by the shell for
|
||||
// imperative messages (e.g. spawn errors) that must appear now and fade,
|
||||
// bypassing the throttled mood-driven showBubble path.
|
||||
const setBubble = useCallback((text: string) => {
|
||||
if (!text) return;
|
||||
clearTimeout(bubbleTimer.current);
|
||||
setBubbleState(text);
|
||||
bubbleTimer.current = setTimeout(() => setBubbleState(null), BUBBLE_MS);
|
||||
}, []);
|
||||
|
||||
return {
|
||||
mood,
|
||||
status,
|
||||
bubble,
|
||||
dismissBubble,
|
||||
setBubble,
|
||||
muted,
|
||||
toggleMute,
|
||||
clearAlerts,
|
||||
setThinking,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user