@supatest/cli 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +9485 -157
- package/package.json +8 -5
- package/dist/commands/login.js +0 -392
- package/dist/commands/setup.js +0 -234
- package/dist/config.js +0 -29
- package/dist/core/agent.js +0 -259
- package/dist/modes/headless.js +0 -117
- package/dist/modes/interactive.js +0 -418
- package/dist/presenters/composite.js +0 -32
- package/dist/presenters/console.js +0 -163
- package/dist/presenters/react.js +0 -217
- package/dist/presenters/types.js +0 -1
- package/dist/presenters/web.js +0 -78
- package/dist/prompts/builder.js +0 -181
- package/dist/prompts/fixer.js +0 -148
- package/dist/prompts/index.js +0 -3
- package/dist/prompts/planner.js +0 -70
- package/dist/services/api-client.js +0 -244
- package/dist/services/event-streamer.js +0 -130
- package/dist/types.js +0 -1
- package/dist/ui/App.js +0 -322
- package/dist/ui/components/AuthBanner.js +0 -24
- package/dist/ui/components/AuthDialog.js +0 -32
- package/dist/ui/components/Banner.js +0 -12
- package/dist/ui/components/ExpandableSection.js +0 -17
- package/dist/ui/components/Header.js +0 -51
- package/dist/ui/components/HelpMenu.js +0 -89
- package/dist/ui/components/InputPrompt.js +0 -286
- package/dist/ui/components/MessageList.js +0 -42
- package/dist/ui/components/QueuedMessageDisplay.js +0 -31
- package/dist/ui/components/Scrollable.js +0 -103
- package/dist/ui/components/SessionSelector.js +0 -196
- package/dist/ui/components/StatusBar.js +0 -34
- package/dist/ui/components/messages/AssistantMessage.js +0 -20
- package/dist/ui/components/messages/ErrorMessage.js +0 -26
- package/dist/ui/components/messages/LoadingMessage.js +0 -28
- package/dist/ui/components/messages/ThinkingMessage.js +0 -17
- package/dist/ui/components/messages/TodoMessage.js +0 -44
- package/dist/ui/components/messages/ToolMessage.js +0 -218
- package/dist/ui/components/messages/UserMessage.js +0 -14
- package/dist/ui/contexts/KeypressContext.js +0 -527
- package/dist/ui/contexts/MouseContext.js +0 -98
- package/dist/ui/contexts/SessionContext.js +0 -129
- package/dist/ui/hooks/useAnimatedScrollbar.js +0 -83
- package/dist/ui/hooks/useBatchedScroll.js +0 -22
- package/dist/ui/hooks/useBracketedPaste.js +0 -31
- package/dist/ui/hooks/useFocus.js +0 -50
- package/dist/ui/hooks/useKeypress.js +0 -26
- package/dist/ui/hooks/useModeToggle.js +0 -25
- package/dist/ui/types/auth.js +0 -13
- package/dist/ui/utils/file-completion.js +0 -56
- package/dist/ui/utils/input.js +0 -50
- package/dist/ui/utils/markdown.js +0 -376
- package/dist/ui/utils/mouse.js +0 -189
- package/dist/ui/utils/theme.js +0 -59
- package/dist/utils/banner.js +0 -9
- package/dist/utils/encryption.js +0 -71
- package/dist/utils/events.js +0 -36
- package/dist/utils/keychain-storage.js +0 -120
- package/dist/utils/logger.js +0 -209
- package/dist/utils/node-version.js +0 -89
- package/dist/utils/plan-file.js +0 -75
- package/dist/utils/project-instructions.js +0 -23
- package/dist/utils/rich-logger.js +0 -208
- package/dist/utils/stdin.js +0 -25
- package/dist/utils/stdio.js +0 -80
- package/dist/utils/summary.js +0 -94
- package/dist/utils/token-storage.js +0 -242
- package/dist/version.js +0 -6
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Session Context
|
|
3
|
-
* Manages the state of the interactive session including messages, todos, and agent status
|
|
4
|
-
*/
|
|
5
|
-
import React, { createContext, useCallback, useContext, useState } from "react";
|
|
6
|
-
const SessionContext = createContext(null);
|
|
7
|
-
export const SessionProvider = ({ children, }) => {
|
|
8
|
-
const [messages, setMessages] = useState([]);
|
|
9
|
-
const [todos, setTodos] = useState([]);
|
|
10
|
-
const [stats, setStats] = useState({
|
|
11
|
-
filesModified: new Set(),
|
|
12
|
-
commandsRun: [],
|
|
13
|
-
iterations: 0,
|
|
14
|
-
startTime: Date.now(),
|
|
15
|
-
});
|
|
16
|
-
const [isAgentRunning, setIsAgentRunning] = useState(false);
|
|
17
|
-
const [shouldInterruptAgent, setShouldInterruptAgent] = useState(false);
|
|
18
|
-
const [sessionId, setSessionId] = useState();
|
|
19
|
-
const [webUrl, setWebUrl] = useState();
|
|
20
|
-
const [agentMode, setAgentMode] = useState('build');
|
|
21
|
-
const [planFilePath, setPlanFilePath] = useState();
|
|
22
|
-
const [allToolsExpanded, setAllToolsExpanded] = useState(true);
|
|
23
|
-
const addMessage = useCallback((message) => {
|
|
24
|
-
// Tools that support expand/collapse
|
|
25
|
-
const expandableTools = ["Bash", "BashOutput", "Command Output"];
|
|
26
|
-
const isExpandableTool = message.type === "tool" && expandableTools.includes(message.toolName || "");
|
|
27
|
-
const newMessage = {
|
|
28
|
-
...message,
|
|
29
|
-
id: `${Date.now()}-${Math.random()}`,
|
|
30
|
-
timestamp: Date.now(),
|
|
31
|
-
// Set isExpanded based on current allToolsExpanded state for expandable tools
|
|
32
|
-
isExpanded: isExpandableTool ? allToolsExpanded : message.isExpanded,
|
|
33
|
-
};
|
|
34
|
-
setMessages((prev) => [...prev, newMessage]);
|
|
35
|
-
}, [allToolsExpanded]);
|
|
36
|
-
const updateLastMessage = useCallback((updates) => {
|
|
37
|
-
setMessages((prev) => {
|
|
38
|
-
if (prev.length === 0)
|
|
39
|
-
return prev;
|
|
40
|
-
const last = prev[prev.length - 1];
|
|
41
|
-
return [...prev.slice(0, -1), { ...last, ...updates }];
|
|
42
|
-
});
|
|
43
|
-
}, []);
|
|
44
|
-
const updateMessageById = useCallback((id, updates) => {
|
|
45
|
-
setMessages((prev) => {
|
|
46
|
-
const index = prev.findIndex((msg) => msg.id === id);
|
|
47
|
-
if (index === -1)
|
|
48
|
-
return prev;
|
|
49
|
-
const updated = [...prev];
|
|
50
|
-
updated[index] = { ...updated[index], ...updates };
|
|
51
|
-
return updated;
|
|
52
|
-
});
|
|
53
|
-
}, []);
|
|
54
|
-
const updateMessageByToolId = useCallback((toolId, updates) => {
|
|
55
|
-
setMessages((prev) => {
|
|
56
|
-
const index = prev.findIndex((msg) => msg.toolUseId === toolId);
|
|
57
|
-
if (index === -1)
|
|
58
|
-
return prev;
|
|
59
|
-
const updated = [...prev];
|
|
60
|
-
updated[index] = { ...updated[index], ...updates };
|
|
61
|
-
return updated;
|
|
62
|
-
});
|
|
63
|
-
}, []);
|
|
64
|
-
const clearMessages = useCallback(() => {
|
|
65
|
-
setMessages([]);
|
|
66
|
-
setTodos([]);
|
|
67
|
-
setStats({
|
|
68
|
-
filesModified: new Set(),
|
|
69
|
-
commandsRun: [],
|
|
70
|
-
iterations: 0,
|
|
71
|
-
startTime: Date.now(),
|
|
72
|
-
});
|
|
73
|
-
// Clear the terminal screen (similar to Gemini CLI behavior)
|
|
74
|
-
console.clear();
|
|
75
|
-
}, []);
|
|
76
|
-
const loadMessages = useCallback((newMessages) => {
|
|
77
|
-
setMessages(newMessages);
|
|
78
|
-
}, []);
|
|
79
|
-
const updateStats = useCallback((updates) => {
|
|
80
|
-
setStats((prev) => ({ ...prev, ...updates }));
|
|
81
|
-
}, []);
|
|
82
|
-
const toggleAllToolOutputs = useCallback(() => {
|
|
83
|
-
setAllToolsExpanded((prev) => {
|
|
84
|
-
const newValue = !prev;
|
|
85
|
-
// Update only Bash tool messages to match the new expanded state
|
|
86
|
-
// Other tools (Grep, Glob, Read, etc.) don't have expandable output
|
|
87
|
-
const expandableTools = ["Bash", "BashOutput", "Command Output"];
|
|
88
|
-
setMessages((msgs) => msgs.map((msg) => msg.type === "tool" && msg.toolResult && expandableTools.includes(msg.toolName || "")
|
|
89
|
-
? { ...msg, isExpanded: newValue }
|
|
90
|
-
: msg));
|
|
91
|
-
return newValue;
|
|
92
|
-
});
|
|
93
|
-
}, []);
|
|
94
|
-
const value = {
|
|
95
|
-
messages,
|
|
96
|
-
addMessage,
|
|
97
|
-
updateLastMessage,
|
|
98
|
-
updateMessageById,
|
|
99
|
-
updateMessageByToolId,
|
|
100
|
-
clearMessages,
|
|
101
|
-
loadMessages,
|
|
102
|
-
toggleAllToolOutputs,
|
|
103
|
-
allToolsExpanded,
|
|
104
|
-
todos,
|
|
105
|
-
setTodos,
|
|
106
|
-
stats,
|
|
107
|
-
updateStats,
|
|
108
|
-
isAgentRunning,
|
|
109
|
-
setIsAgentRunning,
|
|
110
|
-
shouldInterruptAgent,
|
|
111
|
-
setShouldInterruptAgent,
|
|
112
|
-
sessionId,
|
|
113
|
-
setSessionId,
|
|
114
|
-
webUrl,
|
|
115
|
-
setWebUrl,
|
|
116
|
-
agentMode,
|
|
117
|
-
setAgentMode,
|
|
118
|
-
planFilePath,
|
|
119
|
-
setPlanFilePath,
|
|
120
|
-
};
|
|
121
|
-
return (React.createElement(SessionContext.Provider, { value: value }, children));
|
|
122
|
-
};
|
|
123
|
-
export const useSession = () => {
|
|
124
|
-
const context = useContext(SessionContext);
|
|
125
|
-
if (!context) {
|
|
126
|
-
throw new Error("useSession must be used within SessionProvider");
|
|
127
|
-
}
|
|
128
|
-
return context;
|
|
129
|
-
};
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Animated scrollbar hook
|
|
3
|
-
* Provides a thin, animated scrollbar that fades in/out on interaction
|
|
4
|
-
*/
|
|
5
|
-
import { useCallback, useEffect, useRef, useState } from "react";
|
|
6
|
-
export const useAnimatedScrollbar = (isFocused, scrollBy, options) => {
|
|
7
|
-
const [scrollbarColor, setScrollbarColor] = useState(options.unfocusedColor);
|
|
8
|
-
const colorRef = useRef(scrollbarColor);
|
|
9
|
-
colorRef.current = scrollbarColor;
|
|
10
|
-
const animationFrame = useRef(null);
|
|
11
|
-
const timeout = useRef(null);
|
|
12
|
-
const isAnimatingRef = useRef(false);
|
|
13
|
-
const cleanup = useCallback(() => {
|
|
14
|
-
if (animationFrame.current) {
|
|
15
|
-
clearInterval(animationFrame.current);
|
|
16
|
-
animationFrame.current = null;
|
|
17
|
-
}
|
|
18
|
-
if (timeout.current) {
|
|
19
|
-
clearTimeout(timeout.current);
|
|
20
|
-
timeout.current = null;
|
|
21
|
-
}
|
|
22
|
-
isAnimatingRef.current = false;
|
|
23
|
-
}, []);
|
|
24
|
-
const interpolateColor = useCallback((color1, color2, progress) => {
|
|
25
|
-
// Simple color interpolation
|
|
26
|
-
return progress < 0.5 ? color1 : color2;
|
|
27
|
-
}, []);
|
|
28
|
-
const flashScrollbar = useCallback(() => {
|
|
29
|
-
cleanup();
|
|
30
|
-
isAnimatingRef.current = true;
|
|
31
|
-
const fadeInDuration = 200;
|
|
32
|
-
const visibleDuration = 1000;
|
|
33
|
-
const fadeOutDuration = 300;
|
|
34
|
-
const focusedColor = options.focusedColor;
|
|
35
|
-
const unfocusedColor = options.unfocusedColor;
|
|
36
|
-
const startColor = colorRef.current;
|
|
37
|
-
// Phase 1: Fade In
|
|
38
|
-
let start = Date.now();
|
|
39
|
-
const animateFadeIn = () => {
|
|
40
|
-
const elapsed = Date.now() - start;
|
|
41
|
-
const progress = Math.max(0, Math.min(elapsed / fadeInDuration, 1));
|
|
42
|
-
setScrollbarColor(interpolateColor(startColor, focusedColor, progress));
|
|
43
|
-
if (progress === 1) {
|
|
44
|
-
if (animationFrame.current) {
|
|
45
|
-
clearInterval(animationFrame.current);
|
|
46
|
-
animationFrame.current = null;
|
|
47
|
-
}
|
|
48
|
-
// Phase 2: Wait
|
|
49
|
-
timeout.current = setTimeout(() => {
|
|
50
|
-
// Phase 3: Fade Out
|
|
51
|
-
start = Date.now();
|
|
52
|
-
const animateFadeOut = () => {
|
|
53
|
-
const elapsed = Date.now() - start;
|
|
54
|
-
const progress = Math.max(0, Math.min(elapsed / fadeOutDuration, 1));
|
|
55
|
-
setScrollbarColor(interpolateColor(focusedColor, unfocusedColor, progress));
|
|
56
|
-
if (progress === 1) {
|
|
57
|
-
cleanup();
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
animationFrame.current = setInterval(animateFadeOut, 33);
|
|
61
|
-
}, visibleDuration);
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
animationFrame.current = setInterval(animateFadeIn, 33);
|
|
65
|
-
}, [cleanup, interpolateColor, options.focusedColor, options.unfocusedColor]);
|
|
66
|
-
const wasFocused = useRef(isFocused);
|
|
67
|
-
useEffect(() => {
|
|
68
|
-
if (isFocused && !wasFocused.current) {
|
|
69
|
-
flashScrollbar();
|
|
70
|
-
}
|
|
71
|
-
else if (!isFocused && wasFocused.current) {
|
|
72
|
-
cleanup();
|
|
73
|
-
setScrollbarColor(options.unfocusedColor);
|
|
74
|
-
}
|
|
75
|
-
wasFocused.current = isFocused;
|
|
76
|
-
return cleanup;
|
|
77
|
-
}, [isFocused, flashScrollbar, cleanup, options.unfocusedColor]);
|
|
78
|
-
const scrollByWithAnimation = useCallback((delta) => {
|
|
79
|
-
scrollBy(delta);
|
|
80
|
-
flashScrollbar();
|
|
81
|
-
}, [scrollBy, flashScrollbar]);
|
|
82
|
-
return { scrollbarColor, flashScrollbar, scrollByWithAnimation };
|
|
83
|
-
};
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Batched scroll hook
|
|
3
|
-
* Batches scroll updates to prevent jittery behavior
|
|
4
|
-
*/
|
|
5
|
-
import { useCallback, useRef } from "react";
|
|
6
|
-
export const useBatchedScroll = (scrollTop) => {
|
|
7
|
-
const pendingScrollTopRef = useRef(null);
|
|
8
|
-
const currentScrollTopRef = useRef(scrollTop);
|
|
9
|
-
// Update current scroll top whenever it changes
|
|
10
|
-
currentScrollTopRef.current = scrollTop;
|
|
11
|
-
const getScrollTop = useCallback(() => {
|
|
12
|
-
return pendingScrollTopRef.current ?? currentScrollTopRef.current;
|
|
13
|
-
}, []);
|
|
14
|
-
const setPendingScrollTop = useCallback((value) => {
|
|
15
|
-
pendingScrollTopRef.current = value;
|
|
16
|
-
// Clear pending after a microtask
|
|
17
|
-
setTimeout(() => {
|
|
18
|
-
pendingScrollTopRef.current = null;
|
|
19
|
-
}, 0);
|
|
20
|
-
}, []);
|
|
21
|
-
return { getScrollTop, setPendingScrollTop };
|
|
22
|
-
};
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2025 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
import { useEffect } from 'react';
|
|
7
|
-
import { writeToStdout } from '../../utils/stdio';
|
|
8
|
-
const ENABLE_BRACKETED_PASTE = '\x1b[?2004h';
|
|
9
|
-
const DISABLE_BRACKETED_PASTE = '\x1b[?2004l';
|
|
10
|
-
/**
|
|
11
|
-
* Enables and disables bracketed paste mode in the terminal.
|
|
12
|
-
*
|
|
13
|
-
* This hook ensures that bracketed paste mode is enabled when the component
|
|
14
|
-
* mounts and disabled when it unmounts or when the process exits.
|
|
15
|
-
*
|
|
16
|
-
* Bracketed paste mode wraps pasted text in special escape sequences
|
|
17
|
-
* ([200~ and [201~) so we can distinguish between typed and pasted text.
|
|
18
|
-
*/
|
|
19
|
-
export const useBracketedPaste = () => {
|
|
20
|
-
useEffect(() => {
|
|
21
|
-
writeToStdout(ENABLE_BRACKETED_PASTE);
|
|
22
|
-
const cleanup = () => {
|
|
23
|
-
writeToStdout(DISABLE_BRACKETED_PASTE);
|
|
24
|
-
};
|
|
25
|
-
process.on('exit', cleanup);
|
|
26
|
-
return () => {
|
|
27
|
-
cleanup();
|
|
28
|
-
process.off('exit', cleanup);
|
|
29
|
-
};
|
|
30
|
-
}, []);
|
|
31
|
-
};
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2025 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
import { useStdin, useStdout } from 'ink';
|
|
7
|
-
import { useEffect, useState } from 'react';
|
|
8
|
-
import { useKeypress } from './useKeypress.js';
|
|
9
|
-
// ANSI escape codes to enable/disable terminal focus reporting
|
|
10
|
-
export const ENABLE_FOCUS_REPORTING = '\x1b[?1004h';
|
|
11
|
-
export const DISABLE_FOCUS_REPORTING = '\x1b[?1004l';
|
|
12
|
-
// ANSI escape codes for focus events
|
|
13
|
-
export const FOCUS_IN = '\x1b[I';
|
|
14
|
-
export const FOCUS_OUT = '\x1b[O';
|
|
15
|
-
export const useFocus = () => {
|
|
16
|
-
const { stdin } = useStdin();
|
|
17
|
-
const { stdout } = useStdout();
|
|
18
|
-
const [isFocused, setIsFocused] = useState(true);
|
|
19
|
-
useEffect(() => {
|
|
20
|
-
const handleData = (data) => {
|
|
21
|
-
const sequence = data.toString();
|
|
22
|
-
const lastFocusIn = sequence.lastIndexOf(FOCUS_IN);
|
|
23
|
-
const lastFocusOut = sequence.lastIndexOf(FOCUS_OUT);
|
|
24
|
-
if (lastFocusIn > lastFocusOut) {
|
|
25
|
-
setIsFocused(true);
|
|
26
|
-
}
|
|
27
|
-
else if (lastFocusOut > lastFocusIn) {
|
|
28
|
-
setIsFocused(false);
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
// Enable focus reporting
|
|
32
|
-
stdout?.write(ENABLE_FOCUS_REPORTING);
|
|
33
|
-
stdin?.on('data', handleData);
|
|
34
|
-
return () => {
|
|
35
|
-
// Disable focus reporting on cleanup
|
|
36
|
-
stdout?.write(DISABLE_FOCUS_REPORTING);
|
|
37
|
-
stdin?.removeListener('data', handleData);
|
|
38
|
-
};
|
|
39
|
-
}, [stdin, stdout]);
|
|
40
|
-
useKeypress((_) => {
|
|
41
|
-
if (!isFocused) {
|
|
42
|
-
// If the user has typed a key, and we cannot possibly be focused out.
|
|
43
|
-
// This is a workaround for some tmux use cases. It is still useful to
|
|
44
|
-
// listen for the true FOCUS_IN event as well as that will update the
|
|
45
|
-
// focus state earlier than waiting for a keypress.
|
|
46
|
-
setIsFocused(true);
|
|
47
|
-
}
|
|
48
|
-
}, { isActive: true });
|
|
49
|
-
return isFocused;
|
|
50
|
-
};
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2025 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
import { useEffect } from 'react';
|
|
7
|
-
import { useKeypressContext } from '../contexts/KeypressContext';
|
|
8
|
-
/**
|
|
9
|
-
* A hook that listens for keypress events from stdin.
|
|
10
|
-
*
|
|
11
|
-
* @param onKeypress - The callback function to execute on each keypress.
|
|
12
|
-
* @param options - Options to control the hook's behavior.
|
|
13
|
-
* @param options.isActive - Whether the hook should be actively listening for input.
|
|
14
|
-
*/
|
|
15
|
-
export function useKeypress(onKeypress, { isActive }) {
|
|
16
|
-
const { subscribe, unsubscribe } = useKeypressContext();
|
|
17
|
-
useEffect(() => {
|
|
18
|
-
if (!isActive) {
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
subscribe(onKeypress);
|
|
22
|
-
return () => {
|
|
23
|
-
unsubscribe(onKeypress);
|
|
24
|
-
};
|
|
25
|
-
}, [isActive, onKeypress, subscribe, unsubscribe]);
|
|
26
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Hook for toggling between plan and build modes
|
|
3
|
-
* Uses Shift+Tab keyboard shortcut (like Claude Code)
|
|
4
|
-
*/
|
|
5
|
-
import { useEffect } from "react";
|
|
6
|
-
import { useKeypressContext } from "../contexts/KeypressContext.js";
|
|
7
|
-
import { useSession } from "../contexts/SessionContext.js";
|
|
8
|
-
export function useModeToggle() {
|
|
9
|
-
const { subscribe, unsubscribe } = useKeypressContext();
|
|
10
|
-
const { agentMode, setAgentMode, isAgentRunning } = useSession();
|
|
11
|
-
useEffect(() => {
|
|
12
|
-
const handleKeypress = (key) => {
|
|
13
|
-
// Shift+Tab to toggle mode (like Claude Code)
|
|
14
|
-
// Only allow toggling when agent is not running
|
|
15
|
-
if (key.name === "tab" && key.shift && !isAgentRunning) {
|
|
16
|
-
const newMode = agentMode === "plan" ? "build" : "plan";
|
|
17
|
-
setAgentMode(newMode);
|
|
18
|
-
// Mode indicator is shown below the input prompt (no message needed)
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
subscribe(handleKeypress);
|
|
22
|
-
return () => unsubscribe(handleKeypress);
|
|
23
|
-
}, [agentMode, isAgentRunning, setAgentMode, subscribe, unsubscribe]);
|
|
24
|
-
return { agentMode };
|
|
25
|
-
}
|
package/dist/ui/types/auth.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Auth types for Supatest CLI
|
|
3
|
-
*
|
|
4
|
-
* Based on Gemini CLI (Apache 2.0 License)
|
|
5
|
-
* https://github.com/google-gemini/gemini-cli
|
|
6
|
-
* Copyright 2025 Google LLC
|
|
7
|
-
*/
|
|
8
|
-
export var AuthState;
|
|
9
|
-
(function (AuthState) {
|
|
10
|
-
AuthState["Unauthenticated"] = "unauthenticated";
|
|
11
|
-
AuthState["Authenticating"] = "authenticating";
|
|
12
|
-
AuthState["Authenticated"] = "authenticated";
|
|
13
|
-
})(AuthState || (AuthState = {}));
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
const IGNORED_DIRS = new Set([
|
|
4
|
-
'node_modules',
|
|
5
|
-
'.git',
|
|
6
|
-
'.turbo',
|
|
7
|
-
'dist',
|
|
8
|
-
'build',
|
|
9
|
-
'coverage',
|
|
10
|
-
'.next',
|
|
11
|
-
'.cache'
|
|
12
|
-
]);
|
|
13
|
-
const IGNORED_EXTENSIONS = new Set([
|
|
14
|
-
'.png', '.jpg', '.jpeg', '.gif', '.ico', '.svg',
|
|
15
|
-
'.woff', '.woff2', '.ttf', '.eot',
|
|
16
|
-
'.mp4', '.webm', '.mp3', '.wav',
|
|
17
|
-
'.zip', '.tar', '.gz', '.7z', '.rar',
|
|
18
|
-
'.pdf', '.doc', '.docx', '.xls', '.xlsx',
|
|
19
|
-
'.exe', '.dll', '.so', '.dylib', '.bin',
|
|
20
|
-
'.map', '.lock', '.tsbuildinfo'
|
|
21
|
-
]);
|
|
22
|
-
function shouldIgnore(name, isDir) {
|
|
23
|
-
if (name.startsWith('.'))
|
|
24
|
-
return true; // Ignore dotfiles by default for now
|
|
25
|
-
if (isDir)
|
|
26
|
-
return IGNORED_DIRS.has(name);
|
|
27
|
-
const ext = path.extname(name).toLowerCase();
|
|
28
|
-
return IGNORED_EXTENSIONS.has(ext);
|
|
29
|
-
}
|
|
30
|
-
export function getFiles(rootDir = process.cwd(), maxDepth = 3) {
|
|
31
|
-
const files = [];
|
|
32
|
-
function scan(dir, depth) {
|
|
33
|
-
if (depth > maxDepth)
|
|
34
|
-
return;
|
|
35
|
-
try {
|
|
36
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
37
|
-
for (const entry of entries) {
|
|
38
|
-
if (shouldIgnore(entry.name, entry.isDirectory()))
|
|
39
|
-
continue;
|
|
40
|
-
const fullPath = path.join(dir, entry.name);
|
|
41
|
-
const relativePath = path.relative(rootDir, fullPath);
|
|
42
|
-
if (entry.isDirectory()) {
|
|
43
|
-
scan(fullPath, depth + 1);
|
|
44
|
-
}
|
|
45
|
-
else {
|
|
46
|
-
files.push(relativePath);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
catch (error) {
|
|
51
|
-
// Ignore access errors
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
scan(rootDir, 0);
|
|
55
|
-
return files;
|
|
56
|
-
}
|
package/dist/ui/utils/input.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2025 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
export const ESC = '\u001B';
|
|
7
|
-
export const SGR_EVENT_PREFIX = `${ESC}[<`;
|
|
8
|
-
export const X11_EVENT_PREFIX = `${ESC}[M`;
|
|
9
|
-
// eslint-disable-next-line no-control-regex
|
|
10
|
-
export const SGR_MOUSE_REGEX = /^\x1b\[<(\d+);(\d+);(\d+)([mM])/; // SGR mouse events
|
|
11
|
-
// X11 is ESC [ M followed by 3 bytes.
|
|
12
|
-
// eslint-disable-next-line no-control-regex
|
|
13
|
-
export const X11_MOUSE_REGEX = /^\x1b\[M([\s\S]{3})/;
|
|
14
|
-
export function couldBeSGRMouseSequence(buffer) {
|
|
15
|
-
if (buffer.length === 0)
|
|
16
|
-
return true;
|
|
17
|
-
// Check if buffer is a prefix of a mouse sequence starter
|
|
18
|
-
if (SGR_EVENT_PREFIX.startsWith(buffer))
|
|
19
|
-
return true;
|
|
20
|
-
// Check if buffer is a mouse sequence prefix
|
|
21
|
-
if (buffer.startsWith(SGR_EVENT_PREFIX))
|
|
22
|
-
return true;
|
|
23
|
-
return false;
|
|
24
|
-
}
|
|
25
|
-
export function couldBeMouseSequence(buffer) {
|
|
26
|
-
if (buffer.length === 0)
|
|
27
|
-
return true;
|
|
28
|
-
// Check SGR prefix
|
|
29
|
-
if (SGR_EVENT_PREFIX.startsWith(buffer) ||
|
|
30
|
-
buffer.startsWith(SGR_EVENT_PREFIX))
|
|
31
|
-
return true;
|
|
32
|
-
// Check X11 prefix
|
|
33
|
-
if (X11_EVENT_PREFIX.startsWith(buffer) ||
|
|
34
|
-
buffer.startsWith(X11_EVENT_PREFIX))
|
|
35
|
-
return true;
|
|
36
|
-
return false;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Checks if the buffer *starts* with a complete mouse sequence.
|
|
40
|
-
* Returns the length of the sequence if matched, or 0 if not.
|
|
41
|
-
*/
|
|
42
|
-
export function getMouseSequenceLength(buffer) {
|
|
43
|
-
const sgrMatch = buffer.match(SGR_MOUSE_REGEX);
|
|
44
|
-
if (sgrMatch)
|
|
45
|
-
return sgrMatch[0].length;
|
|
46
|
-
const x11Match = buffer.match(X11_MOUSE_REGEX);
|
|
47
|
-
if (x11Match)
|
|
48
|
-
return x11Match[0].length;
|
|
49
|
-
return 0;
|
|
50
|
-
}
|