centaurus-cli 3.1.3 → 3.1.4
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/cli-adapter.js +685 -153
- package/dist/cli-adapter.js.map +1 -1
- package/dist/config/defaultConfig.js +1 -4
- package/dist/config/defaultConfig.js.map +1 -1
- package/dist/config/models.js +4 -0
- package/dist/config/models.js.map +1 -1
- package/dist/config/slash-commands.js +66 -2
- package/dist/config/slash-commands.js.map +1 -1
- package/dist/config/types.js +4 -4
- package/dist/config/types.js.map +1 -1
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -1
- package/dist/services/ai-context-injector.js +109 -0
- package/dist/services/ai-context-injector.js.map +1 -1
- package/dist/services/api-client.js.map +1 -1
- package/dist/services/background-task-manager.js +59 -0
- package/dist/services/background-task-manager.js.map +1 -1
- package/dist/services/local-chat-storage.js +2 -0
- package/dist/services/local-chat-storage.js.map +1 -1
- package/dist/services/skill-storage.js +141 -0
- package/dist/services/skill-storage.js.map +1 -0
- package/dist/services/sub-agent-manager.js +49 -8
- package/dist/services/sub-agent-manager.js.map +1 -1
- package/dist/services/warpify-detector.js +17 -5
- package/dist/services/warpify-detector.js.map +1 -1
- package/dist/tools/background-command.js +5 -2
- package/dist/tools/background-command.js.map +1 -1
- package/dist/tools/command.js +367 -109
- package/dist/tools/command.js.map +1 -1
- package/dist/tools/file-ops.js +23 -6
- package/dist/tools/file-ops.js.map +1 -1
- package/dist/tools/plan-mode.js +184 -336
- package/dist/tools/plan-mode.js.map +1 -1
- package/dist/tools/sub-agent.js +24 -5
- package/dist/tools/sub-agent.js.map +1 -1
- package/dist/tools/todo-list.js +157 -0
- package/dist/tools/todo-list.js.map +1 -0
- package/dist/types/skill.js +30 -0
- package/dist/types/skill.js.map +1 -0
- package/dist/ui/components/App.js +956 -162
- package/dist/ui/components/App.js.map +1 -1
- package/dist/ui/components/AuthScreen.js +3 -1
- package/dist/ui/components/AuthScreen.js.map +1 -1
- package/dist/ui/components/AuthWelcomeScreen.js +3 -1
- package/dist/ui/components/AuthWelcomeScreen.js.map +1 -1
- package/dist/ui/components/CodeBlock.js +3 -1
- package/dist/ui/components/CodeBlock.js.map +1 -1
- package/dist/ui/components/CompactShellPreview.js +44 -0
- package/dist/ui/components/CompactShellPreview.js.map +1 -0
- package/dist/ui/components/ConfigViewer.js +3 -1
- package/dist/ui/components/ConfigViewer.js.map +1 -1
- package/dist/ui/components/ConfirmPrompt.js +3 -1
- package/dist/ui/components/ConfirmPrompt.js.map +1 -1
- package/dist/ui/components/ConnectionStatusMessage.js +3 -1
- package/dist/ui/components/ConnectionStatusMessage.js.map +1 -1
- package/dist/ui/components/DetailedPlanReviewScreen.js +84 -74
- package/dist/ui/components/DetailedPlanReviewScreen.js.map +1 -1
- package/dist/ui/components/DiffViewer.js +6 -3
- package/dist/ui/components/DiffViewer.js.map +1 -1
- package/dist/ui/components/FileCreationPreview.js.map +1 -1
- package/dist/ui/components/FileTagAutocomplete.js +4 -2
- package/dist/ui/components/FileTagAutocomplete.js.map +1 -1
- package/dist/ui/components/InputBox.js +243 -40
- package/dist/ui/components/InputBox.js.map +1 -1
- package/dist/ui/components/InteractiveShell.js +5 -3
- package/dist/ui/components/InteractiveShell.js.map +1 -1
- package/dist/ui/components/KeyboardHelp.js +4 -1
- package/dist/ui/components/KeyboardHelp.js.map +1 -1
- package/dist/ui/components/LoadingIndicator.js +3 -1
- package/dist/ui/components/LoadingIndicator.js.map +1 -1
- package/dist/ui/components/MCPAddScreen.js +63 -13
- package/dist/ui/components/MCPAddScreen.js.map +1 -1
- package/dist/ui/components/MarkdownRenderer.js +3 -1
- package/dist/ui/components/MarkdownRenderer.js.map +1 -1
- package/dist/ui/components/MessageDisplay.js +9 -7
- package/dist/ui/components/MessageDisplay.js.map +1 -1
- package/dist/ui/components/ModelPicker.js +170 -0
- package/dist/ui/components/ModelPicker.js.map +1 -0
- package/dist/ui/components/MonitorModeAIPanel.js +3 -1
- package/dist/ui/components/MonitorModeAIPanel.js.map +1 -1
- package/dist/ui/components/PlanAcceptedMessage.js +12 -6
- package/dist/ui/components/PlanAcceptedMessage.js.map +1 -1
- package/dist/ui/components/PlanQuestionMessage.js +37 -0
- package/dist/ui/components/PlanQuestionMessage.js.map +1 -0
- package/dist/ui/components/PlanQuestionScreen.js +138 -0
- package/dist/ui/components/PlanQuestionScreen.js.map +1 -0
- package/dist/ui/components/PlanReviewScreen.js +7 -9
- package/dist/ui/components/PlanReviewScreen.js.map +1 -1
- package/dist/ui/components/RulesEditorScreen.js +65 -28
- package/dist/ui/components/RulesEditorScreen.js.map +1 -1
- package/dist/ui/components/SelectPrompt.js +3 -1
- package/dist/ui/components/SelectPrompt.js.map +1 -1
- package/dist/ui/components/SkillCreatorScreen.js +217 -0
- package/dist/ui/components/SkillCreatorScreen.js.map +1 -0
- package/dist/ui/components/SlashCommandAutocomplete.js +4 -2
- package/dist/ui/components/SlashCommandAutocomplete.js.map +1 -1
- package/dist/ui/components/StatusBar.js +4 -2
- package/dist/ui/components/StatusBar.js.map +1 -1
- package/dist/ui/components/StreamingMessageDisplay.js +5 -3
- package/dist/ui/components/StreamingMessageDisplay.js.map +1 -1
- package/dist/ui/components/SubAgentListScreen.js +65 -0
- package/dist/ui/components/SubAgentListScreen.js.map +1 -0
- package/dist/ui/components/SubAgentViewScreen.js +123 -0
- package/dist/ui/components/SubAgentViewScreen.js.map +1 -0
- package/dist/ui/components/TaskCompletedMessage.js +40 -8
- package/dist/ui/components/TaskCompletedMessage.js.map +1 -1
- package/dist/ui/components/TaskProgressIndicator.js +6 -4
- package/dist/ui/components/TaskProgressIndicator.js.map +1 -1
- package/dist/ui/components/TextEditor.js +297 -0
- package/dist/ui/components/TextEditor.js.map +1 -0
- package/dist/ui/components/TodoListMessage.js +59 -0
- package/dist/ui/components/TodoListMessage.js.map +1 -0
- package/dist/ui/components/ToolExecutionMessage.js +134 -84
- package/dist/ui/components/ToolExecutionMessage.js.map +1 -1
- package/dist/ui/components/ToolExecutionStatus.js +3 -1
- package/dist/ui/components/ToolExecutionStatus.js.map +1 -1
- package/dist/ui/components/WelcomeBanner.js +33 -33
- package/dist/ui/components/WelcomeBanner.js.map +1 -1
- package/dist/ui/components/WorkflowCreatorScreen.js +5 -3
- package/dist/ui/components/WorkflowCreatorScreen.js.map +1 -1
- package/dist/ui/theme.js +97 -0
- package/dist/ui/theme.js.map +1 -0
- package/dist/ui/utils/chat-history-limit.js +247 -0
- package/dist/ui/utils/chat-history-limit.js.map +1 -0
- package/dist/utils/chat-formatter.js +22 -9
- package/dist/utils/chat-formatter.js.map +1 -1
- package/dist/utils/input-classifier.js +11 -1
- package/dist/utils/input-classifier.js.map +1 -1
- package/dist/utils/output-truncation.js +175 -0
- package/dist/utils/output-truncation.js.map +1 -0
- package/dist/utils/rule-reference-resolver.js +3 -3
- package/dist/utils/rule-reference-resolver.js.map +1 -1
- package/dist/utils/tunnel-commands-manager.js +134 -0
- package/dist/utils/tunnel-commands-manager.js.map +1 -0
- package/package.json +91 -90
- package/postinstall.js +4 -11
- package/dist/ui/components/MultiLineInput.js +0 -255
- package/dist/ui/components/MultiLineInput.js.map +0 -1
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import React, { useState, useEffect } from "react";
|
|
2
2
|
import { Box, Text, useInput } from "ink";
|
|
3
3
|
import { LoadingIndicator } from "./LoadingIndicator.js";
|
|
4
|
+
import { useTheme } from "../theme.js";
|
|
4
5
|
const AuthScreen = ({ onAuthComplete, onAuthError }) => {
|
|
5
6
|
const [status, setStatus] = useState("init");
|
|
6
7
|
const [errorMessage, setErrorMessage] = useState("");
|
|
8
|
+
const theme = useTheme();
|
|
7
9
|
useInput((input, key) => {
|
|
8
10
|
if (key.ctrl && input === "c") {
|
|
9
11
|
process.exit(0);
|
|
@@ -17,7 +19,7 @@ const AuthScreen = ({ onAuthComplete, onAuthError }) => {
|
|
|
17
19
|
if (status === "error") {
|
|
18
20
|
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", padding: 2 }, /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "red", bold: true }, "\u274C Authentication Failed")), /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, null, errorMessage)), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "Press Ctrl+C to exit")));
|
|
19
21
|
}
|
|
20
|
-
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", padding: 2 }, /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color:
|
|
22
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", padding: 2 }, /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: theme.accent }, "\u{1F510} Authentication Required")), /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, null, "To use Centaurus CLI, you need to sign in with your Google account.")), /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, null, "A browser window will open for you to complete the authentication.")), /* @__PURE__ */ React.createElement(Box, { marginBottom: 2 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "If the browser doesn't open automatically, copy and paste the URL shown below.")), /* @__PURE__ */ React.createElement(LoadingIndicator, null));
|
|
21
23
|
};
|
|
22
24
|
export {
|
|
23
25
|
AuthScreen
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/ui/components/AuthScreen.tsx"],"sourcesContent":["import React, { useState, useEffect } from 'react';\r\nimport { Box, Text, useInput } from 'ink';\r\nimport { LoadingIndicator } from './LoadingIndicator.js';\r\n\r\ninterface AuthScreenProps {\r\n onAuthComplete: () => void;\r\n onAuthError: (error: string) => void;\r\n}\r\n\r\nexport const AuthScreen: React.FC<AuthScreenProps> = ({ onAuthComplete, onAuthError }) => {\r\n const [status, setStatus] = useState<'init' | 'waiting' | 'error'>('init');\r\n const [errorMessage, setErrorMessage] = useState<string>('');\r\n\r\n useInput((input, key) => {\r\n if (key.ctrl && input === 'c') {\r\n process.exit(0);\r\n }\r\n });\r\n\r\n useEffect(() => {\r\n if (status === 'init') {\r\n setStatus('waiting');\r\n }\r\n }, [status]);\r\n\r\n if (status === 'error') {\r\n return (\r\n <Box flexDirection=\"column\" padding={2}>\r\n <Box marginBottom={1}>\r\n <Text color=\"red\" bold>❌ Authentication Failed</Text>\r\n </Box>\r\n <Box marginBottom={1}>\r\n <Text>{errorMessage}</Text>\r\n </Box>\r\n <Box>\r\n <Text dimColor>Press Ctrl+C to exit</Text>\r\n </Box>\r\n </Box>\r\n );\r\n }\r\n\r\n return (\r\n <Box flexDirection=\"column\" padding={2}>\r\n <Box marginBottom={1}>\r\n <Text bold color
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/components/AuthScreen.tsx"],"sourcesContent":["import React, { useState, useEffect } from 'react';\r\nimport { Box, Text, useInput } from 'ink';\r\nimport { LoadingIndicator } from './LoadingIndicator.js';\r\nimport { useTheme } from '../theme.js';\r\n\r\ninterface AuthScreenProps {\r\n onAuthComplete: () => void;\r\n onAuthError: (error: string) => void;\r\n}\r\n\r\nexport const AuthScreen: React.FC<AuthScreenProps> = ({ onAuthComplete, onAuthError }) => {\r\n const [status, setStatus] = useState<'init' | 'waiting' | 'error'>('init');\r\n const [errorMessage, setErrorMessage] = useState<string>('');\r\n const theme = useTheme();\r\n\r\n useInput((input, key) => {\r\n if (key.ctrl && input === 'c') {\r\n process.exit(0);\r\n }\r\n });\r\n\r\n useEffect(() => {\r\n if (status === 'init') {\r\n setStatus('waiting');\r\n }\r\n }, [status]);\r\n\r\n if (status === 'error') {\r\n return (\r\n <Box flexDirection=\"column\" padding={2}>\r\n <Box marginBottom={1}>\r\n <Text color=\"red\" bold>❌ Authentication Failed</Text>\r\n </Box>\r\n <Box marginBottom={1}>\r\n <Text>{errorMessage}</Text>\r\n </Box>\r\n <Box>\r\n <Text dimColor>Press Ctrl+C to exit</Text>\r\n </Box>\r\n </Box>\r\n );\r\n }\r\n\r\n return (\r\n <Box flexDirection=\"column\" padding={2}>\r\n <Box marginBottom={1}>\r\n <Text bold color={theme.accent}>🔐 Authentication Required</Text>\r\n </Box>\r\n <Box marginBottom={1}>\r\n <Text>\r\n To use Centaurus CLI, you need to sign in with your Google account.\r\n </Text>\r\n </Box>\r\n <Box marginBottom={1}>\r\n <Text>\r\n A browser window will open for you to complete the authentication.\r\n </Text>\r\n </Box>\r\n <Box marginBottom={2}>\r\n <Text dimColor>\r\n If the browser doesn't open automatically, copy and paste the URL shown below.\r\n </Text>\r\n </Box>\r\n <LoadingIndicator />\r\n </Box>\r\n );\r\n};\r\n"],"mappings":"AAAA,OAAO,SAAS,UAAU,iBAAiB;AAC3C,SAAS,KAAK,MAAM,gBAAgB;AACpC,SAAS,wBAAwB;AACjC,SAAS,gBAAgB;AAOlB,MAAM,aAAwC,CAAC,EAAE,gBAAgB,YAAY,MAAM;AACtF,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAuC,MAAM;AACzE,QAAM,CAAC,cAAc,eAAe,IAAI,SAAiB,EAAE;AAC3D,QAAM,QAAQ,SAAS;AAEvB,WAAS,CAAC,OAAO,QAAQ;AACrB,QAAI,IAAI,QAAQ,UAAU,KAAK;AAC3B,cAAQ,KAAK,CAAC;AAAA,IAClB;AAAA,EACJ,CAAC;AAED,YAAU,MAAM;AACZ,QAAI,WAAW,QAAQ;AACnB,gBAAU,SAAS;AAAA,IACvB;AAAA,EACJ,GAAG,CAAC,MAAM,CAAC;AAEX,MAAI,WAAW,SAAS;AACpB,WACI,oCAAC,OAAI,eAAc,UAAS,SAAS,KACjC,oCAAC,OAAI,cAAc,KACf,oCAAC,QAAK,OAAM,OAAM,MAAI,QAAC,8BAAuB,CAClD,GACA,oCAAC,OAAI,cAAc,KACf,oCAAC,YAAM,YAAa,CACxB,GACA,oCAAC,WACG,oCAAC,QAAK,UAAQ,QAAC,sBAAoB,CACvC,CACJ;AAAA,EAER;AAEA,SACI,oCAAC,OAAI,eAAc,UAAS,SAAS,KACjC,oCAAC,OAAI,cAAc,KACf,oCAAC,QAAK,MAAI,MAAC,OAAO,MAAM,UAAQ,mCAA0B,CAC9D,GACA,oCAAC,OAAI,cAAc,KACf,oCAAC,YAAK,qEAEN,CACJ,GACA,oCAAC,OAAI,cAAc,KACf,oCAAC,YAAK,oEAEN,CACJ,GACA,oCAAC,OAAI,cAAc,KACf,oCAAC,QAAK,UAAQ,QAAC,gFAEf,CACJ,GACA,oCAAC,sBAAiB,CACtB;AAER;","names":[]}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
3
|
import { SelectPrompt } from "./SelectPrompt.js";
|
|
4
|
+
import { useTheme } from "../theme.js";
|
|
4
5
|
const AuthWelcomeScreen = ({
|
|
5
6
|
onSignIn,
|
|
6
7
|
onExit
|
|
7
8
|
}) => {
|
|
9
|
+
const theme = useTheme();
|
|
8
10
|
const handleSelect = (value) => {
|
|
9
11
|
if (value === "signin") {
|
|
10
12
|
onSignIn();
|
|
@@ -12,7 +14,7 @@ const AuthWelcomeScreen = ({
|
|
|
12
14
|
onExit();
|
|
13
15
|
}
|
|
14
16
|
};
|
|
15
|
-
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginTop: 1, marginBottom: 1, paddingX: 1 }, /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color:
|
|
17
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginTop: 1, marginBottom: 1, paddingX: 1 }, /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: theme.accent }, "\u{1F510} Authentication Required")), /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, null, "To use Centaurus CLI, you need to sign in with Google."))), /* @__PURE__ */ React.createElement(Box, { paddingX: 1 }, /* @__PURE__ */ React.createElement(
|
|
16
18
|
SelectPrompt,
|
|
17
19
|
{
|
|
18
20
|
message: "What would you like to do?",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/ui/components/AuthWelcomeScreen.tsx"],"sourcesContent":["import React from 'react';\r\nimport { Box, Text } from 'ink';\r\nimport { SelectPrompt } from './SelectPrompt.js';\r\n\r\ninterface AuthWelcomeScreenProps {\r\n onSignIn: () => void;\r\n onExit: () => void;\r\n}\r\n\r\nexport const AuthWelcomeScreen: React.FC<AuthWelcomeScreenProps> = ({\r\n onSignIn,\r\n onExit,\r\n}) => {\r\n const handleSelect = (value: string) => {\r\n if (value === 'signin') {\r\n onSignIn();\r\n } else {\r\n onExit();\r\n }\r\n };\r\n\r\n return (\r\n <Box flexDirection=\"column\">\r\n {/* Authentication Info */}\r\n <Box flexDirection=\"column\" marginTop={1} marginBottom={1} paddingX={1}>\r\n <Box marginBottom={1}>\r\n <Text bold color
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/components/AuthWelcomeScreen.tsx"],"sourcesContent":["import React from 'react';\r\nimport { Box, Text } from 'ink';\r\nimport { SelectPrompt } from './SelectPrompt.js';\r\nimport { useTheme } from '../theme.js';\r\n\r\ninterface AuthWelcomeScreenProps {\r\n onSignIn: () => void;\r\n onExit: () => void;\r\n}\r\n\r\nexport const AuthWelcomeScreen: React.FC<AuthWelcomeScreenProps> = ({\r\n onSignIn,\r\n onExit,\r\n}) => {\r\n const theme = useTheme();\r\n\r\n const handleSelect = (value: string) => {\r\n if (value === 'signin') {\r\n onSignIn();\r\n } else {\r\n onExit();\r\n }\r\n };\r\n\r\n return (\r\n <Box flexDirection=\"column\">\r\n {/* Authentication Info */}\r\n <Box flexDirection=\"column\" marginTop={1} marginBottom={1} paddingX={1}>\r\n <Box marginBottom={1}>\r\n <Text bold color={theme.accent}>🔐 Authentication Required</Text>\r\n </Box>\r\n\r\n <Box marginBottom={1}>\r\n <Text>\r\n To use Centaurus CLI, you need to sign in with Google.\r\n </Text>\r\n </Box>\r\n </Box>\r\n\r\n {/* Picker */}\r\n <Box paddingX={1}>\r\n <SelectPrompt\r\n message=\"What would you like to do?\"\r\n choices={[\r\n { label: '🔑 Sign in with Google', value: 'signin' },\r\n { label: '❌ Exit', value: 'exit' },\r\n ]}\r\n onSelect={handleSelect}\r\n width={(process.stdout.columns || 120) - 2}\r\n />\r\n </Box>\r\n </Box>\r\n );\r\n};\r\n"],"mappings":"AAAA,OAAO,WAAW;AAClB,SAAS,KAAK,YAAY;AAC1B,SAAS,oBAAoB;AAC7B,SAAS,gBAAgB;AAOlB,MAAM,oBAAsD,CAAC;AAAA,EAClE;AAAA,EACA;AACF,MAAM;AACJ,QAAM,QAAQ,SAAS;AAEvB,QAAM,eAAe,CAAC,UAAkB;AACtC,QAAI,UAAU,UAAU;AACtB,eAAS;AAAA,IACX,OAAO;AACL,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SACE,oCAAC,OAAI,eAAc,YAEjB,oCAAC,OAAI,eAAc,UAAS,WAAW,GAAG,cAAc,GAAG,UAAU,KACnE,oCAAC,OAAI,cAAc,KACjB,oCAAC,QAAK,MAAI,MAAC,OAAO,MAAM,UAAQ,mCAA0B,CAC5D,GAEA,oCAAC,OAAI,cAAc,KACjB,oCAAC,YAAK,wDAEN,CACF,CACF,GAGA,oCAAC,OAAI,UAAU,KACb;AAAA,IAAC;AAAA;AAAA,MACC,SAAQ;AAAA,MACR,SAAS;AAAA,QACP,EAAE,OAAO,iCAA0B,OAAO,SAAS;AAAA,QACnD,EAAE,OAAO,eAAU,OAAO,OAAO;AAAA,MACnC;AAAA,MACA,UAAU;AAAA,MACV,QAAQ,QAAQ,OAAO,WAAW,OAAO;AAAA;AAAA,EAC3C,CACF,CACF;AAEJ;","names":[]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { useState } from "react";
|
|
2
2
|
import { Box, Text, useInput } from "ink";
|
|
3
|
+
import { useTheme } from "../theme.js";
|
|
3
4
|
const MAX_PREVIEW_LINES = 8;
|
|
4
5
|
const MAX_FULL_VIEW_LINES = 1e3;
|
|
5
6
|
const CodeBlock = React.memo(({
|
|
@@ -7,6 +8,7 @@ const CodeBlock = React.memo(({
|
|
|
7
8
|
language = "text",
|
|
8
9
|
title
|
|
9
10
|
}) => {
|
|
11
|
+
const theme = useTheme();
|
|
10
12
|
const [showFull, setShowFull] = useState(false);
|
|
11
13
|
useInput((input, key) => {
|
|
12
14
|
if (input === "o" && key.ctrl) {
|
|
@@ -19,7 +21,7 @@ const CodeBlock = React.memo(({
|
|
|
19
21
|
const shouldTruncate = totalLines > limit;
|
|
20
22
|
const displayLines = shouldTruncate ? lines.slice(0, limit) : lines;
|
|
21
23
|
const hiddenLines = shouldTruncate ? totalLines - limit : 0;
|
|
22
|
-
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", borderStyle: "round", borderColor:
|
|
24
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", borderStyle: "round", borderColor: theme.bgAccent, paddingX: 1, paddingY: 1 }, title && /* @__PURE__ */ React.createElement(Box, { marginBottom: 1, justifyContent: "space-between" }, /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: theme.accent, bold: true }, "\u{1F4C4} ", title), language && /* @__PURE__ */ React.createElement(Text, { color: "#666666" }, " (", language, ")")), /* @__PURE__ */ React.createElement(Text, { color: "#666666", dimColor: true }, showFull ? "Press Ctrl+O to collapse" : "Press Ctrl+O to expand")), displayLines.map((line, idx) => /* @__PURE__ */ React.createElement(Box, { key: idx }, /* @__PURE__ */ React.createElement(Text, { color: "#666666" }, String(idx + 1).padStart(3, " "), " \u2502 "), /* @__PURE__ */ React.createElement(Text, { color: "#ffffff" }, line))), shouldTruncate && /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: theme.accent, dimColor: true }, "... ", hiddenLines, " more ", hiddenLines === 1 ? "line" : "lines", " not shown ...")));
|
|
23
25
|
});
|
|
24
26
|
export {
|
|
25
27
|
CodeBlock
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/ui/components/CodeBlock.tsx"],"sourcesContent":["import React, { useState } from 'react';\r\nimport { Box, Text, useInput } from 'ink';\r\n\r\ninterface CodeBlockProps {\r\n code: string;\r\n language?: string;\r\n title?: string;\r\n}\r\n\r\n// Maximum number of lines to show before truncating\r\nconst MAX_PREVIEW_LINES = 8;\r\n// Maximum number of lines to show in full view\r\nconst MAX_FULL_VIEW_LINES = 1000;\r\n\r\nexport const CodeBlock: React.FC<CodeBlockProps> = React.memo(({\r\n code,\r\n language = 'text',\r\n title\r\n}) => {\r\n const [showFull, setShowFull] = useState(false);\r\n\r\n useInput((input, key) => {\r\n if (input === 'o' && key.ctrl) {\r\n setShowFull(prev => !prev);\r\n }\r\n });\r\n\r\n const lines = code.split('\\n');\r\n\r\n // Determine if we need to truncate\r\n const totalLines = lines.length;\r\n const limit = showFull ? MAX_FULL_VIEW_LINES : MAX_PREVIEW_LINES;\r\n const shouldTruncate = totalLines > limit;\r\n const displayLines = shouldTruncate ? lines.slice(0, limit) : lines;\r\n const hiddenLines = shouldTruncate ? totalLines - limit : 0;\r\n\r\n return (\r\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/components/CodeBlock.tsx"],"sourcesContent":["import React, { useState } from 'react';\r\nimport { Box, Text, useInput } from 'ink';\r\nimport { useTheme } from '../theme.js';\r\n\r\ninterface CodeBlockProps {\r\n code: string;\r\n language?: string;\r\n title?: string;\r\n}\r\n\r\n// Maximum number of lines to show before truncating\r\nconst MAX_PREVIEW_LINES = 8;\r\n// Maximum number of lines to show in full view\r\nconst MAX_FULL_VIEW_LINES = 1000;\r\n\r\nexport const CodeBlock: React.FC<CodeBlockProps> = React.memo(({\r\n code,\r\n language = 'text',\r\n title\r\n}) => {\r\n const theme = useTheme();\r\n const [showFull, setShowFull] = useState(false);\r\n\r\n useInput((input, key) => {\r\n if (input === 'o' && key.ctrl) {\r\n setShowFull(prev => !prev);\r\n }\r\n });\r\n\r\n const lines = code.split('\\n');\r\n\r\n // Determine if we need to truncate\r\n const totalLines = lines.length;\r\n const limit = showFull ? MAX_FULL_VIEW_LINES : MAX_PREVIEW_LINES;\r\n const shouldTruncate = totalLines > limit;\r\n const displayLines = shouldTruncate ? lines.slice(0, limit) : lines;\r\n const hiddenLines = shouldTruncate ? totalLines - limit : 0;\r\n\r\n return (\r\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor={theme.bgAccent} paddingX={1} paddingY={1}>\r\n {title && (\r\n <Box marginBottom={1} justifyContent=\"space-between\">\r\n <Box>\r\n <Text color={theme.accent} bold>📄 {title}</Text>\r\n {language && <Text color=\"#666666\"> ({language})</Text>}\r\n </Box>\r\n <Text color=\"#666666\" dimColor>\r\n {showFull ? 'Press Ctrl+O to collapse' : 'Press Ctrl+O to expand'}\r\n </Text>\r\n </Box>\r\n )}\r\n\r\n {displayLines.map((line, idx) => (\r\n <Box key={idx}>\r\n <Text color=\"#666666\">{String(idx + 1).padStart(3, ' ')} │ </Text>\r\n <Text color=\"#ffffff\">{line}</Text>\r\n </Box>\r\n ))}\r\n\r\n {/* Truncation notice */}\r\n {shouldTruncate && (\r\n <Box marginTop={1}>\r\n <Text color={theme.accent} dimColor>\r\n ... {hiddenLines} more {hiddenLines === 1 ? 'line' : 'lines'} not shown ...\r\n </Text>\r\n </Box>\r\n )}\r\n </Box>\r\n );\r\n});\r\n"],"mappings":"AAAA,OAAO,SAAS,gBAAgB;AAChC,SAAS,KAAK,MAAM,gBAAgB;AACpC,SAAS,gBAAgB;AASzB,MAAM,oBAAoB;AAE1B,MAAM,sBAAsB;AAErB,MAAM,YAAsC,MAAM,KAAK,CAAC;AAAA,EAC7D;AAAA,EACA,WAAW;AAAA,EACX;AACF,MAAM;AACJ,QAAM,QAAQ,SAAS;AACvB,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAE9C,WAAS,CAAC,OAAO,QAAQ;AACvB,QAAI,UAAU,OAAO,IAAI,MAAM;AAC7B,kBAAY,UAAQ,CAAC,IAAI;AAAA,IAC3B;AAAA,EACF,CAAC;AAED,QAAM,QAAQ,KAAK,MAAM,IAAI;AAG7B,QAAM,aAAa,MAAM;AACzB,QAAM,QAAQ,WAAW,sBAAsB;AAC/C,QAAM,iBAAiB,aAAa;AACpC,QAAM,eAAe,iBAAiB,MAAM,MAAM,GAAG,KAAK,IAAI;AAC9D,QAAM,cAAc,iBAAiB,aAAa,QAAQ;AAE1D,SACE,oCAAC,OAAI,eAAc,UAAS,aAAY,SAAQ,aAAa,MAAM,UAAU,UAAU,GAAG,UAAU,KACjG,SACC,oCAAC,OAAI,cAAc,GAAG,gBAAe,mBACnC,oCAAC,WACC,oCAAC,QAAK,OAAO,MAAM,QAAQ,MAAI,QAAC,cAAI,KAAM,GACzC,YAAY,oCAAC,QAAK,OAAM,aAAU,MAAG,UAAS,GAAC,CAClD,GACA,oCAAC,QAAK,OAAM,WAAU,UAAQ,QAC3B,WAAW,6BAA6B,wBAC3C,CACF,GAGD,aAAa,IAAI,CAAC,MAAM,QACvB,oCAAC,OAAI,KAAK,OACR,oCAAC,QAAK,OAAM,aAAW,OAAO,MAAM,CAAC,EAAE,SAAS,GAAG,GAAG,GAAE,UAAG,GAC3D,oCAAC,QAAK,OAAM,aAAW,IAAK,CAC9B,CACD,GAGA,kBACC,oCAAC,OAAI,WAAW,KACd,oCAAC,QAAK,OAAO,MAAM,QAAQ,UAAQ,QAAC,QAC7B,aAAY,UAAO,gBAAgB,IAAI,SAAS,SAAQ,gBAC/D,CACF,CAEJ;AAEJ,CAAC;","names":[]}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
import Spinner from "ink-spinner";
|
|
4
|
+
import stripAnsi from "strip-ansi";
|
|
5
|
+
import { processTerminalOutput } from "../../utils/terminal-output.js";
|
|
6
|
+
import { useTheme } from "../theme.js";
|
|
7
|
+
function truncateCmd(cmd, max = 50) {
|
|
8
|
+
if (!cmd || cmd.length <= max) return cmd;
|
|
9
|
+
return cmd.substring(0, max) + "...";
|
|
10
|
+
}
|
|
11
|
+
const CompactShellPreview = React.memo(({
|
|
12
|
+
command,
|
|
13
|
+
output,
|
|
14
|
+
isRunning,
|
|
15
|
+
remoteContext,
|
|
16
|
+
timeoutTransferred
|
|
17
|
+
}) => {
|
|
18
|
+
const theme = useTheme();
|
|
19
|
+
const cleanOutput = stripAnsi(processTerminalOutput(output || "")).replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
|
|
20
|
+
const allLines = cleanOutput.split("\n").filter((l) => l.trim().length > 0);
|
|
21
|
+
const lastLines = allLines.slice(-2);
|
|
22
|
+
const borderColor = timeoutTransferred ? "#f59e0b" : theme.accent;
|
|
23
|
+
const headerColor = timeoutTransferred ? "#f59e0b" : theme.accent;
|
|
24
|
+
return /* @__PURE__ */ React.createElement(
|
|
25
|
+
Box,
|
|
26
|
+
{
|
|
27
|
+
flexDirection: "column",
|
|
28
|
+
borderStyle: "round",
|
|
29
|
+
borderColor,
|
|
30
|
+
paddingX: 1,
|
|
31
|
+
paddingY: 0,
|
|
32
|
+
width: "100%"
|
|
33
|
+
},
|
|
34
|
+
/* @__PURE__ */ React.createElement(Box, { flexDirection: "row", justifyContent: "space-between" }, /* @__PURE__ */ React.createElement(Box, { flexShrink: 1, minWidth: 0 }, /* @__PURE__ */ React.createElement(Text, null, isRunning && /* @__PURE__ */ React.createElement(Text, { color: headerColor }, /* @__PURE__ */ React.createElement(Spinner, { type: "dots" }), " "), !isRunning && /* @__PURE__ */ React.createElement(Text, { color: "#00cc66" }, "\u2713 "), /* @__PURE__ */ React.createElement(Text, { color: headerColor, bold: true }, "Shell "), /* @__PURE__ */ React.createElement(Text, { color: "#666666" }, truncateCmd(command)))), /* @__PURE__ */ React.createElement(Box, { flexShrink: 0 }, allLines.length > 2 && /* @__PURE__ */ React.createElement(Text, { color: "#666666", dimColor: true }, " [truncated]"))),
|
|
35
|
+
lastLines.length > 0 && /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, lastLines.map((line, i) => /* @__PURE__ */ React.createElement(Text, { key: i, color: "#aaaaaa", wrap: "truncate-end" }, line))),
|
|
36
|
+
lastLines.length === 0 && isRunning && /* @__PURE__ */ React.createElement(Text, { color: "#666666", dimColor: true }, "Waiting for output...")
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
var CompactShellPreview_default = CompactShellPreview;
|
|
40
|
+
export {
|
|
41
|
+
CompactShellPreview,
|
|
42
|
+
CompactShellPreview_default as default
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=CompactShellPreview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/components/CompactShellPreview.tsx"],"sourcesContent":["/**\r\n * CompactShellPreview Component\r\n * \r\n * A minimal 2-line live preview of a running shell command,\r\n * used in compact/small-terminal mode where the full InteractiveShell\r\n * would take too much vertical space.\r\n * \r\n * Shows:\r\n * - Header with command name and \"truncated\" indicator\r\n * - Last 2 lines of terminal output (live-updating)\r\n */\r\n\r\nimport React from 'react';\r\nimport { Box, Text } from 'ink';\r\nimport Spinner from 'ink-spinner';\r\nimport stripAnsi from 'strip-ansi';\r\nimport { processTerminalOutput } from '../../utils/terminal-output.js';\r\nimport { useTheme } from '../theme.js';\r\n\r\ninterface CompactShellPreviewProps {\r\n command: string;\r\n output: string;\r\n isRunning: boolean;\r\n remoteContext?: string;\r\n timeoutTransferred?: boolean;\r\n}\r\n\r\n/**\r\n * Truncate a command string for compact display\r\n */\r\nfunction truncateCmd(cmd: string, max: number = 50): string {\r\n if (!cmd || cmd.length <= max) return cmd;\r\n return cmd.substring(0, max) + '...';\r\n}\r\n\r\nexport const CompactShellPreview: React.FC<CompactShellPreviewProps> = React.memo(({\r\n command,\r\n output,\r\n isRunning,\r\n remoteContext,\r\n timeoutTransferred,\r\n}) => {\r\n const theme = useTheme();\r\n\r\n // Process and get last 2 lines of output\r\n const cleanOutput = stripAnsi(processTerminalOutput(output || ''))\r\n .replace(/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F]/g, '');\r\n const allLines = cleanOutput.split('\\n').filter(l => l.trim().length > 0);\r\n const lastLines = allLines.slice(-2);\r\n\r\n const borderColor = timeoutTransferred ? '#f59e0b' : theme.accent;\r\n const headerColor = timeoutTransferred ? '#f59e0b' : theme.accent;\r\n\r\n return (\r\n <Box\r\n flexDirection=\"column\"\r\n borderStyle=\"round\"\r\n borderColor={borderColor}\r\n paddingX={1}\r\n paddingY={0}\r\n width=\"100%\"\r\n >\r\n {/* Header: spinner + command + truncated label */}\r\n <Box flexDirection=\"row\" justifyContent=\"space-between\">\r\n <Box flexShrink={1} minWidth={0}>\r\n <Text>\r\n {isRunning && (\r\n <Text color={headerColor}><Spinner type=\"dots\" /> </Text>\r\n )}\r\n {!isRunning && <Text color=\"#00cc66\">✓ </Text>}\r\n <Text color={headerColor} bold>Shell </Text>\r\n <Text color=\"#666666\">{truncateCmd(command)}</Text>\r\n </Text>\r\n </Box>\r\n <Box flexShrink={0}>\r\n {allLines.length > 2 && (\r\n <Text color=\"#666666\" dimColor> [truncated]</Text>\r\n )}\r\n </Box>\r\n </Box>\r\n\r\n {/* Last 2 lines of output */}\r\n {lastLines.length > 0 && (\r\n <Box flexDirection=\"column\">\r\n {lastLines.map((line, i) => (\r\n <Text key={i} color=\"#aaaaaa\" wrap=\"truncate-end\">{line}</Text>\r\n ))}\r\n </Box>\r\n )}\r\n {lastLines.length === 0 && isRunning && (\r\n <Text color=\"#666666\" dimColor>Waiting for output...</Text>\r\n )}\r\n </Box>\r\n );\r\n});\r\n\r\nexport default CompactShellPreview;\r\n"],"mappings":"AAYA,OAAO,WAAW;AAClB,SAAS,KAAK,YAAY;AAC1B,OAAO,aAAa;AACpB,OAAO,eAAe;AACtB,SAAS,6BAA6B;AACtC,SAAS,gBAAgB;AAazB,SAAS,YAAY,KAAa,MAAc,IAAY;AACxD,MAAI,CAAC,OAAO,IAAI,UAAU,IAAK,QAAO;AACtC,SAAO,IAAI,UAAU,GAAG,GAAG,IAAI;AACnC;AAEO,MAAM,sBAA0D,MAAM,KAAK,CAAC;AAAA,EAC/E;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACJ,MAAM;AACF,QAAM,QAAQ,SAAS;AAGvB,QAAM,cAAc,UAAU,sBAAsB,UAAU,EAAE,CAAC,EAC5D,QAAQ,qCAAqC,EAAE;AACpD,QAAM,WAAW,YAAY,MAAM,IAAI,EAAE,OAAO,OAAK,EAAE,KAAK,EAAE,SAAS,CAAC;AACxE,QAAM,YAAY,SAAS,MAAM,EAAE;AAEnC,QAAM,cAAc,qBAAqB,YAAY,MAAM;AAC3D,QAAM,cAAc,qBAAqB,YAAY,MAAM;AAE3D,SACI;AAAA,IAAC;AAAA;AAAA,MACG,eAAc;AAAA,MACd,aAAY;AAAA,MACZ;AAAA,MACA,UAAU;AAAA,MACV,UAAU;AAAA,MACV,OAAM;AAAA;AAAA,IAGN,oCAAC,OAAI,eAAc,OAAM,gBAAe,mBACpC,oCAAC,OAAI,YAAY,GAAG,UAAU,KAC1B,oCAAC,YACI,aACG,oCAAC,QAAK,OAAO,eAAa,oCAAC,WAAQ,MAAK,QAAO,GAAE,GAAC,GAErD,CAAC,aAAa,oCAAC,QAAK,OAAM,aAAU,SAAE,GACvC,oCAAC,QAAK,OAAO,aAAa,MAAI,QAAC,QAAM,GACrC,oCAAC,QAAK,OAAM,aAAW,YAAY,OAAO,CAAE,CAChD,CACJ,GACA,oCAAC,OAAI,YAAY,KACZ,SAAS,SAAS,KACf,oCAAC,QAAK,OAAM,WAAU,UAAQ,QAAC,cAAY,CAEnD,CACJ;AAAA,IAGC,UAAU,SAAS,KAChB,oCAAC,OAAI,eAAc,YACd,UAAU,IAAI,CAAC,MAAM,MAClB,oCAAC,QAAK,KAAK,GAAG,OAAM,WAAU,MAAK,kBAAgB,IAAK,CAC3D,CACL;AAAA,IAEH,UAAU,WAAW,KAAK,aACvB,oCAAC,QAAK,OAAM,WAAU,UAAQ,QAAC,uBAAqB;AAAA,EAE5D;AAER,CAAC;AAED,IAAO,8BAAQ;","names":[]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Box, Text, useInput } from "ink";
|
|
3
|
+
import { useTheme } from "../theme.js";
|
|
3
4
|
const ConfigViewer = ({
|
|
4
5
|
provider,
|
|
5
6
|
model,
|
|
@@ -7,12 +8,13 @@ const ConfigViewer = ({
|
|
|
7
8
|
autoAcceptMode,
|
|
8
9
|
onClose
|
|
9
10
|
}) => {
|
|
11
|
+
const theme = useTheme();
|
|
10
12
|
useInput((input, key) => {
|
|
11
13
|
if (key.escape || input === "q") {
|
|
12
14
|
onClose();
|
|
13
15
|
}
|
|
14
16
|
});
|
|
15
|
-
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", borderStyle: "round", borderColor:
|
|
17
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, marginY: 1 }, /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { color: theme.accent, bold: true }, "Current Configuration")), /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "#ffaa00" }, "Provider: "), /* @__PURE__ */ React.createElement(Text, { color: "#ffffff" }, provider)), /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "#ffaa00" }, "Model: "), /* @__PURE__ */ React.createElement(Text, { color: "#ffffff" }, model)), /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "#ffaa00" }, "API Key: "), /* @__PURE__ */ React.createElement(Text, { color: "#ffffff" }, apiKeyMasked)), /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "#ffaa00" }, "Auto-Accept: "), /* @__PURE__ */ React.createElement(Text, { color: autoAcceptMode ? "#00cc66" : "#ff3366" }, autoAcceptMode ? "ON" : "OFF")), /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "#666666", dimColor: true }, "Press ESC or Q to close")));
|
|
16
18
|
};
|
|
17
19
|
export {
|
|
18
20
|
ConfigViewer
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/ui/components/ConfigViewer.tsx"],"sourcesContent":["import React from 'react';\r\nimport { Box, Text, useInput } from 'ink';\r\n\r\ninterface ConfigViewerProps {\r\n provider: string;\r\n model: string;\r\n apiKeyMasked: string;\r\n autoAcceptMode: boolean;\r\n onClose: () => void;\r\n}\r\n\r\nexport const ConfigViewer: React.FC<ConfigViewerProps> = ({ \r\n provider, \r\n model, \r\n apiKeyMasked, \r\n autoAcceptMode,\r\n onClose \r\n}) => {\r\n useInput((input, key) => {\r\n if (key.escape || input === 'q') {\r\n onClose();\r\n }\r\n });\r\n\r\n return (\r\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/components/ConfigViewer.tsx"],"sourcesContent":["import React from 'react';\r\nimport { Box, Text, useInput } from 'ink';\r\nimport { useTheme } from '../theme.js';\r\n\r\ninterface ConfigViewerProps {\r\n provider: string;\r\n model: string;\r\n apiKeyMasked: string;\r\n autoAcceptMode: boolean;\r\n onClose: () => void;\r\n}\r\n\r\nexport const ConfigViewer: React.FC<ConfigViewerProps> = ({ \r\n provider, \r\n model, \r\n apiKeyMasked, \r\n autoAcceptMode,\r\n onClose \r\n}) => {\r\n const theme = useTheme();\r\n\r\n useInput((input, key) => {\r\n if (key.escape || input === 'q') {\r\n onClose();\r\n }\r\n });\r\n\r\n return (\r\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor={theme.accent} paddingX={1} marginY={1}>\r\n <Box marginBottom={1}>\r\n <Text color={theme.accent} bold>Current Configuration</Text>\r\n </Box>\r\n \r\n <Box marginBottom={1}>\r\n <Text color=\"#ffaa00\">Provider: </Text>\r\n <Text color=\"#ffffff\">{provider}</Text>\r\n </Box>\r\n \r\n <Box marginBottom={1}>\r\n <Text color=\"#ffaa00\">Model: </Text>\r\n <Text color=\"#ffffff\">{model}</Text>\r\n </Box>\r\n \r\n <Box marginBottom={1}>\r\n <Text color=\"#ffaa00\">API Key: </Text>\r\n <Text color=\"#ffffff\">{apiKeyMasked}</Text>\r\n </Box>\r\n \r\n <Box marginBottom={1}>\r\n <Text color=\"#ffaa00\">Auto-Accept: </Text>\r\n <Text color={autoAcceptMode ? '#00cc66' : '#ff3366'}>\r\n {autoAcceptMode ? 'ON' : 'OFF'}\r\n </Text>\r\n </Box>\r\n\r\n <Box marginTop={1}>\r\n <Text color=\"#666666\" dimColor>\r\n Press ESC or Q to close\r\n </Text>\r\n </Box>\r\n </Box>\r\n );\r\n};\r\n"],"mappings":"AAAA,OAAO,WAAW;AAClB,SAAS,KAAK,MAAM,gBAAgB;AACpC,SAAS,gBAAgB;AAUlB,MAAM,eAA4C,CAAC;AAAA,EACxD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,QAAQ,SAAS;AAEvB,WAAS,CAAC,OAAO,QAAQ;AACvB,QAAI,IAAI,UAAU,UAAU,KAAK;AAC/B,cAAQ;AAAA,IACV;AAAA,EACF,CAAC;AAED,SACE,oCAAC,OAAI,eAAc,UAAS,aAAY,SAAQ,aAAa,MAAM,QAAQ,UAAU,GAAG,SAAS,KAC/F,oCAAC,OAAI,cAAc,KACjB,oCAAC,QAAK,OAAO,MAAM,QAAQ,MAAI,QAAC,uBAAqB,CACvD,GAEA,oCAAC,OAAI,cAAc,KACjB,oCAAC,QAAK,OAAM,aAAU,YAAU,GAChC,oCAAC,QAAK,OAAM,aAAW,QAAS,CAClC,GAEA,oCAAC,OAAI,cAAc,KACjB,oCAAC,QAAK,OAAM,aAAU,SAAO,GAC7B,oCAAC,QAAK,OAAM,aAAW,KAAM,CAC/B,GAEA,oCAAC,OAAI,cAAc,KACjB,oCAAC,QAAK,OAAM,aAAU,WAAS,GAC/B,oCAAC,QAAK,OAAM,aAAW,YAAa,CACtC,GAEA,oCAAC,OAAI,cAAc,KACjB,oCAAC,QAAK,OAAM,aAAU,eAAa,GACnC,oCAAC,QAAK,OAAO,iBAAiB,YAAY,aACvC,iBAAiB,OAAO,KAC3B,CACF,GAEA,oCAAC,OAAI,WAAW,KACd,oCAAC,QAAK,OAAM,WAAU,UAAQ,QAAC,yBAE/B,CACF,CACF;AAEJ;","names":[]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { useState } from "react";
|
|
2
2
|
import { Box, Text, useInput } from "ink";
|
|
3
|
+
import { useTheme } from "../theme.js";
|
|
3
4
|
const ConfirmPrompt = React.memo(({
|
|
4
5
|
message,
|
|
5
6
|
onYes,
|
|
@@ -9,6 +10,7 @@ const ConfirmPrompt = React.memo(({
|
|
|
9
10
|
warningMessage
|
|
10
11
|
}) => {
|
|
11
12
|
const [selected, setSelected] = useState("yes");
|
|
13
|
+
const theme = useTheme();
|
|
12
14
|
useInput((input, key) => {
|
|
13
15
|
if (key.upArrow || key.downArrow) {
|
|
14
16
|
if (showFeedbackOption) {
|
|
@@ -42,7 +44,7 @@ const ConfirmPrompt = React.memo(({
|
|
|
42
44
|
return;
|
|
43
45
|
}
|
|
44
46
|
});
|
|
45
|
-
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", borderStyle: "round", borderColor: warningMessage ? "#ff6600" : "#ffaa00", paddingX: 1, paddingY: 1 }, warningMessage && /* @__PURE__ */ React.createElement(Box, { marginBottom: 1, borderStyle: "single", borderColor: "#ff3366", paddingX: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "#ff3366", bold: true }, "\u26A0\uFE0F ", warningMessage)), /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "#ffaa00", bold: true }, message)), /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: selected === "yes" ? "#00cc66" : "#666666", bold: selected === "yes" }, selected === "yes" ? "> " : " ", "1. Yes")), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: selected === "no" ? "#ff3366" : "#666666", bold: selected === "no" }, selected === "no" ? "> " : " ", "2. No")), showFeedbackOption && /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: selected === "feedback" ?
|
|
47
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", borderStyle: "round", borderColor: warningMessage ? "#ff6600" : "#ffaa00", paddingX: 1, paddingY: 1 }, warningMessage && /* @__PURE__ */ React.createElement(Box, { marginBottom: 1, borderStyle: "single", borderColor: "#ff3366", paddingX: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "#ff3366", bold: true }, "\u26A0\uFE0F ", warningMessage)), /* @__PURE__ */ React.createElement(Box, { marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "#ffaa00", bold: true }, message)), /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: selected === "yes" ? "#00cc66" : "#666666", bold: selected === "yes" }, selected === "yes" ? "> " : " ", "1. Yes")), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: selected === "no" ? "#ff3366" : "#666666", bold: selected === "no" }, selected === "no" ? "> " : " ", "2. No")), showFeedbackOption && /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: selected === "feedback" ? theme.accent : "#666666", bold: selected === "feedback" }, selected === "feedback" ? "> " : " ", "3. Feedback"))));
|
|
46
48
|
}, (prevProps, nextProps) => {
|
|
47
49
|
return prevProps.message === nextProps.message && prevProps.showFeedbackOption === nextProps.showFeedbackOption && prevProps.warningMessage === nextProps.warningMessage;
|
|
48
50
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/ui/components/ConfirmPrompt.tsx"],"sourcesContent":["import React, { useState } from 'react';\r\nimport { Box, Text, useInput } from 'ink';\r\n\r\ninterface ConfirmPromptProps {\r\n message: string;\r\n onYes: () => void;\r\n onNo: () => void;\r\n onFeedback?: () => void;\r\n showFeedbackOption?: boolean;\r\n /** Optional warning message to display above the prompt (shown in orange/red) */\r\n warningMessage?: string;\r\n}\r\n\r\nexport const ConfirmPrompt: React.FC<ConfirmPromptProps> = React.memo(({\r\n message,\r\n onYes,\r\n onNo,\r\n onFeedback,\r\n showFeedbackOption = false,\r\n warningMessage\r\n}) => {\r\n const [selected, setSelected] = useState<'yes' | 'no' | 'feedback'>('yes');\r\n\r\n useInput((input, key) => {\r\n if (key.upArrow || key.downArrow) {\r\n if (showFeedbackOption) {\r\n setSelected(prev => {\r\n const options: Array<'yes' | 'no' | 'feedback'> = ['yes', 'no', 'feedback'];\r\n const currentIdx = options.indexOf(prev);\r\n const nextIdx = key.upArrow\r\n ? (currentIdx - 1 + options.length) % options.length\r\n : (currentIdx + 1) % options.length;\r\n return options[nextIdx];\r\n });\r\n } else {\r\n setSelected(prev => prev === 'yes' ? 'no' : 'yes');\r\n }\r\n return;\r\n }\r\n\r\n // Y key for yes\r\n if (input === 'y' || input === 'Y') {\r\n onYes();\r\n return;\r\n }\r\n\r\n // N key for no\r\n if (input === 'n' || input === 'N') {\r\n onNo();\r\n return;\r\n }\r\n\r\n // F key for feedback\r\n if (showFeedbackOption && (input === 'f' || input === 'F') && onFeedback) {\r\n onFeedback();\r\n return;\r\n }\r\n\r\n // Enter key to confirm selection\r\n if (key.return) {\r\n if (selected === 'yes') onYes();\r\n else if (selected === 'no') onNo();\r\n else if (selected === 'feedback' && onFeedback) onFeedback();\r\n return;\r\n }\r\n });\r\n\r\n return (\r\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor={warningMessage ? \"#ff6600\" : \"#ffaa00\"} paddingX={1} paddingY={1}>\r\n {/* Warning message if provided */}\r\n {warningMessage && (\r\n <Box marginBottom={1} borderStyle=\"single\" borderColor=\"#ff3366\" paddingX={1}>\r\n <Text color=\"#ff3366\" bold>⚠️ {warningMessage}</Text>\r\n </Box>\r\n )}\r\n <Box marginBottom={1}>\r\n <Text color=\"#ffaa00\" bold>{message}</Text>\r\n </Box>\r\n <Box flexDirection=\"column\">\r\n <Box>\r\n <Text color={selected === 'yes' ? '#00cc66' : '#666666'} bold={selected === 'yes'}>\r\n {selected === 'yes' ? '> ' : ' '}1. Yes\r\n </Text>\r\n </Box>\r\n <Box>\r\n <Text color={selected === 'no' ? '#ff3366' : '#666666'} bold={selected === 'no'}>\r\n {selected === 'no' ? '> ' : ' '}2. No\r\n </Text>\r\n </Box>\r\n {showFeedbackOption && (\r\n <Box>\r\n <Text color={selected === 'feedback' ?
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/components/ConfirmPrompt.tsx"],"sourcesContent":["import React, { useState } from 'react';\r\nimport { Box, Text, useInput } from 'ink';\r\nimport { useTheme } from '../theme.js';\r\n\r\ninterface ConfirmPromptProps {\r\n message: string;\r\n onYes: () => void;\r\n onNo: () => void;\r\n onFeedback?: () => void;\r\n showFeedbackOption?: boolean;\r\n /** Optional warning message to display above the prompt (shown in orange/red) */\r\n warningMessage?: string;\r\n}\r\n\r\nexport const ConfirmPrompt: React.FC<ConfirmPromptProps> = React.memo(({\r\n message,\r\n onYes,\r\n onNo,\r\n onFeedback,\r\n showFeedbackOption = false,\r\n warningMessage\r\n}) => {\r\n const [selected, setSelected] = useState<'yes' | 'no' | 'feedback'>('yes');\r\n const theme = useTheme();\r\n\r\n useInput((input, key) => {\r\n if (key.upArrow || key.downArrow) {\r\n if (showFeedbackOption) {\r\n setSelected(prev => {\r\n const options: Array<'yes' | 'no' | 'feedback'> = ['yes', 'no', 'feedback'];\r\n const currentIdx = options.indexOf(prev);\r\n const nextIdx = key.upArrow\r\n ? (currentIdx - 1 + options.length) % options.length\r\n : (currentIdx + 1) % options.length;\r\n return options[nextIdx];\r\n });\r\n } else {\r\n setSelected(prev => prev === 'yes' ? 'no' : 'yes');\r\n }\r\n return;\r\n }\r\n\r\n // Y key for yes\r\n if (input === 'y' || input === 'Y') {\r\n onYes();\r\n return;\r\n }\r\n\r\n // N key for no\r\n if (input === 'n' || input === 'N') {\r\n onNo();\r\n return;\r\n }\r\n\r\n // F key for feedback\r\n if (showFeedbackOption && (input === 'f' || input === 'F') && onFeedback) {\r\n onFeedback();\r\n return;\r\n }\r\n\r\n // Enter key to confirm selection\r\n if (key.return) {\r\n if (selected === 'yes') onYes();\r\n else if (selected === 'no') onNo();\r\n else if (selected === 'feedback' && onFeedback) onFeedback();\r\n return;\r\n }\r\n });\r\n\r\n return (\r\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor={warningMessage ? \"#ff6600\" : \"#ffaa00\"} paddingX={1} paddingY={1}>\r\n {/* Warning message if provided */}\r\n {warningMessage && (\r\n <Box marginBottom={1} borderStyle=\"single\" borderColor=\"#ff3366\" paddingX={1}>\r\n <Text color=\"#ff3366\" bold>⚠️ {warningMessage}</Text>\r\n </Box>\r\n )}\r\n <Box marginBottom={1}>\r\n <Text color=\"#ffaa00\" bold>{message}</Text>\r\n </Box>\r\n <Box flexDirection=\"column\">\r\n <Box>\r\n <Text color={selected === 'yes' ? '#00cc66' : '#666666'} bold={selected === 'yes'}>\r\n {selected === 'yes' ? '> ' : ' '}1. Yes\r\n </Text>\r\n </Box>\r\n <Box>\r\n <Text color={selected === 'no' ? '#ff3366' : '#666666'} bold={selected === 'no'}>\r\n {selected === 'no' ? '> ' : ' '}2. No\r\n </Text>\r\n </Box>\r\n {showFeedbackOption && (\r\n <Box>\r\n <Text color={selected === 'feedback' ? theme.accent : '#666666'} bold={selected === 'feedback'}>\r\n {selected === 'feedback' ? '> ' : ' '}3. Feedback\r\n </Text>\r\n </Box>\r\n )}\r\n </Box>\r\n </Box>\r\n );\r\n}, (prevProps, nextProps) => {\r\n // Only re-render if message or showFeedbackOption changes\r\n return prevProps.message === nextProps.message &&\r\n prevProps.showFeedbackOption === nextProps.showFeedbackOption &&\r\n prevProps.warningMessage === nextProps.warningMessage;\r\n});\r\n\r\n"],"mappings":"AAAA,OAAO,SAAS,gBAAgB;AAChC,SAAS,KAAK,MAAM,gBAAgB;AACpC,SAAS,gBAAgB;AAYlB,MAAM,gBAA8C,MAAM,KAAK,CAAC;AAAA,EACrE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,qBAAqB;AAAA,EACrB;AACF,MAAM;AACJ,QAAM,CAAC,UAAU,WAAW,IAAI,SAAoC,KAAK;AACzE,QAAM,QAAQ,SAAS;AAEvB,WAAS,CAAC,OAAO,QAAQ;AACvB,QAAI,IAAI,WAAW,IAAI,WAAW;AAChC,UAAI,oBAAoB;AACtB,oBAAY,UAAQ;AAClB,gBAAM,UAA4C,CAAC,OAAO,MAAM,UAAU;AAC1E,gBAAM,aAAa,QAAQ,QAAQ,IAAI;AACvC,gBAAM,UAAU,IAAI,WACf,aAAa,IAAI,QAAQ,UAAU,QAAQ,UAC3C,aAAa,KAAK,QAAQ;AAC/B,iBAAO,QAAQ,OAAO;AAAA,QACxB,CAAC;AAAA,MACH,OAAO;AACL,oBAAY,UAAQ,SAAS,QAAQ,OAAO,KAAK;AAAA,MACnD;AACA;AAAA,IACF;AAGA,QAAI,UAAU,OAAO,UAAU,KAAK;AAClC,YAAM;AACN;AAAA,IACF;AAGA,QAAI,UAAU,OAAO,UAAU,KAAK;AAClC,WAAK;AACL;AAAA,IACF;AAGA,QAAI,uBAAuB,UAAU,OAAO,UAAU,QAAQ,YAAY;AACxE,iBAAW;AACX;AAAA,IACF;AAGA,QAAI,IAAI,QAAQ;AACd,UAAI,aAAa,MAAO,OAAM;AAAA,eACrB,aAAa,KAAM,MAAK;AAAA,eACxB,aAAa,cAAc,WAAY,YAAW;AAC3D;AAAA,IACF;AAAA,EACF,CAAC;AAED,SACE,oCAAC,OAAI,eAAc,UAAS,aAAY,SAAQ,aAAa,iBAAiB,YAAY,WAAW,UAAU,GAAG,UAAU,KAEzH,kBACC,oCAAC,OAAI,cAAc,GAAG,aAAY,UAAS,aAAY,WAAU,UAAU,KACzE,oCAAC,QAAK,OAAM,WAAU,MAAI,QAAC,iBAAI,cAAe,CAChD,GAEF,oCAAC,OAAI,cAAc,KACjB,oCAAC,QAAK,OAAM,WAAU,MAAI,QAAE,OAAQ,CACtC,GACA,oCAAC,OAAI,eAAc,YACjB,oCAAC,WACC,oCAAC,QAAK,OAAO,aAAa,QAAQ,YAAY,WAAW,MAAM,aAAa,SACzE,aAAa,QAAQ,OAAO,MAAK,QACpC,CACF,GACA,oCAAC,WACC,oCAAC,QAAK,OAAO,aAAa,OAAO,YAAY,WAAW,MAAM,aAAa,QACxE,aAAa,OAAO,OAAO,MAAK,OACnC,CACF,GACC,sBACC,oCAAC,WACC,oCAAC,QAAK,OAAO,aAAa,aAAa,MAAM,SAAS,WAAW,MAAM,aAAa,cACjF,aAAa,aAAa,OAAO,MAAK,aACzC,CACF,CAEJ,CACF;AAEJ,GAAG,CAAC,WAAW,cAAc;AAE3B,SAAO,UAAU,YAAY,UAAU,WACrC,UAAU,uBAAuB,UAAU,sBAC3C,UAAU,mBAAmB,UAAU;AAC3C,CAAC;","names":[]}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
3
|
import Spinner from "ink-spinner";
|
|
4
|
+
import { useTheme } from "../theme.js";
|
|
4
5
|
const ConnectionStatusMessage = React.memo(({ status }) => {
|
|
6
|
+
const theme = useTheme();
|
|
5
7
|
const getTypeLabel = () => {
|
|
6
8
|
switch (status.type) {
|
|
7
9
|
case "ssh":
|
|
@@ -15,7 +17,7 @@ const ConnectionStatusMessage = React.memo(({ status }) => {
|
|
|
15
17
|
}
|
|
16
18
|
};
|
|
17
19
|
if (status.status === "connecting") {
|
|
18
|
-
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", borderStyle: "round", borderColor: "#9945FF", paddingX: 1, marginBottom: 1, alignSelf: "flex-start" }, /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color:
|
|
20
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", borderStyle: "round", borderColor: "#9945FF", paddingX: 1, marginBottom: 1, alignSelf: "flex-start" }, /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: theme.accent }, /* @__PURE__ */ React.createElement(Spinner, { type: "dots" })), /* @__PURE__ */ React.createElement(Text, { color: "#9945FF" }, " Tunnelling to ", getTypeLabel(), " environment...")));
|
|
19
21
|
}
|
|
20
22
|
if (status.status === "connected") {
|
|
21
23
|
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", borderStyle: "round", borderColor: "#00cc66", paddingX: 1, marginBottom: 1, alignSelf: "flex-start" }, /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: "#00cc66", bold: true }, "\u2713"), /* @__PURE__ */ React.createElement(Text, { color: "#00cc66" }, " Established Wormhole to ", getTypeLabel(), " environment"), status.connectionString && /* @__PURE__ */ React.createElement(Text, { color: "#666666" }, " [", getTypeLabel(), " ", status.connectionString, "]")));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/ui/components/ConnectionStatusMessage.tsx"],"sourcesContent":["import React from 'react';\r\nimport { Box, Text } from 'ink';\r\nimport Spinner from 'ink-spinner';\r\n\r\nexport interface ConnectionStatus {\r\n type: 'ssh' | 'wsl' | 'docker';\r\n status: 'connecting' | 'connected' | 'error' | 'disconnected';\r\n connectionString?: string; // e.g., \"rohan@localhost\" for SSH, \"Ubuntu\" for WSL\r\n error?: string;\r\n}\r\n\r\ninterface ConnectionStatusMessageProps {\r\n status: ConnectionStatus;\r\n}\r\n\r\n/**\r\n * Dynamic connection status message that shows a spinner while connecting\r\n * and transforms to a static \"Connected\" message once connected.\r\n */\r\nexport const ConnectionStatusMessage: React.FC<ConnectionStatusMessageProps> = React.memo(({ status }) => {\r\n const getTypeLabel = () => {\r\n switch (status.type) {\r\n case 'ssh': return 'ssh';\r\n case 'wsl': return 'WSL';\r\n case 'docker': return 'Docker';\r\n default: return status.type;\r\n }\r\n };\r\n\r\n // CONNECTING state - shows spinner\r\n if (status.status === 'connecting') {\r\n return (\r\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor=\"#9945FF\" paddingX={1} marginBottom={1} alignSelf=\"flex-start\">\r\n <Box>\r\n <Text color
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/components/ConnectionStatusMessage.tsx"],"sourcesContent":["import React from 'react';\r\nimport { Box, Text } from 'ink';\r\nimport Spinner from 'ink-spinner';\r\nimport { useTheme } from '../theme.js';\r\n\r\nexport interface ConnectionStatus {\r\n type: 'ssh' | 'wsl' | 'docker';\r\n status: 'connecting' | 'connected' | 'error' | 'disconnected';\r\n connectionString?: string; // e.g., \"rohan@localhost\" for SSH, \"Ubuntu\" for WSL\r\n error?: string;\r\n}\r\n\r\ninterface ConnectionStatusMessageProps {\r\n status: ConnectionStatus;\r\n}\r\n\r\n/**\r\n * Dynamic connection status message that shows a spinner while connecting\r\n * and transforms to a static \"Connected\" message once connected.\r\n */\r\nexport const ConnectionStatusMessage: React.FC<ConnectionStatusMessageProps> = React.memo(({ status }) => {\r\n const theme = useTheme();\r\n\r\n const getTypeLabel = () => {\r\n switch (status.type) {\r\n case 'ssh': return 'ssh';\r\n case 'wsl': return 'WSL';\r\n case 'docker': return 'Docker';\r\n default: return status.type;\r\n }\r\n };\r\n\r\n // CONNECTING state - shows spinner\r\n if (status.status === 'connecting') {\r\n return (\r\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor=\"#9945FF\" paddingX={1} marginBottom={1} alignSelf=\"flex-start\">\r\n <Box>\r\n <Text color={theme.accent}><Spinner type=\"dots\" /></Text>\r\n <Text color=\"#9945FF\"> Tunnelling to {getTypeLabel()} environment...</Text>\r\n </Box>\r\n </Box>\r\n );\r\n }\r\n\r\n // CONNECTED state - static success message\r\n if (status.status === 'connected') {\r\n return (\r\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor=\"#00cc66\" paddingX={1} marginBottom={1} alignSelf=\"flex-start\">\r\n <Box>\r\n <Text color=\"#00cc66\" bold>✓</Text>\r\n <Text color=\"#00cc66\"> Established Wormhole to {getTypeLabel()} environment</Text>\r\n {status.connectionString && (\r\n <Text color=\"#666666\"> [{getTypeLabel()} {status.connectionString}]</Text>\r\n )}\r\n </Box>\r\n </Box>\r\n );\r\n }\r\n\r\n // ERROR state\r\n if (status.status === 'error') {\r\n return (\r\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor=\"#ff3366\" paddingX={1} marginBottom={1} alignSelf=\"flex-start\">\r\n <Box>\r\n <Text color=\"#ff3366\" bold>✗</Text>\r\n <Text color=\"#ff3366\"> Failed to connect to {getTypeLabel()} environment</Text>\r\n </Box>\r\n {status.error && (\r\n <Box paddingLeft={1} marginTop={0}>\r\n <Text color=\"#ff3366\">{status.error.slice(0, 300)}{status.error.length > 300 ? '...' : ''}</Text>\r\n </Box>\r\n )}\r\n </Box>\r\n );\r\n }\r\n\r\n // DISCONNECTED state - shows disconnect notification\r\n if (status.status === 'disconnected') {\r\n return (\r\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor=\"#ff9900\" paddingX={1} marginBottom={1} alignSelf=\"flex-start\">\r\n <Box>\r\n <Text color=\"#ff9900\" bold>✗</Text>\r\n <Text color=\"#ff9900\"> Disconnected from {getTypeLabel()} environment</Text>\r\n {status.connectionString && (\r\n <Text color=\"#666666\"> [{getTypeLabel()} {status.connectionString}]</Text>\r\n )}\r\n </Box>\r\n {status.error && (\r\n <Box>\r\n <Text color=\"#ff9900\"> {status.error.slice(0, 300)}{status.error.length > 300 ? '...' : ''}</Text>\r\n </Box>\r\n )}\r\n </Box>\r\n );\r\n }\r\n\r\n return null;\r\n}, (prevProps, nextProps) => {\r\n // Only re-render if status changes\r\n return prevProps.status.status === nextProps.status.status &&\r\n prevProps.status.type === nextProps.status.type &&\r\n prevProps.status.connectionString === nextProps.status.connectionString &&\r\n prevProps.status.error === nextProps.status.error;\r\n});\r\n"],"mappings":"AAAA,OAAO,WAAW;AAClB,SAAS,KAAK,YAAY;AAC1B,OAAO,aAAa;AACpB,SAAS,gBAAgB;AAiBlB,MAAM,0BAAkE,MAAM,KAAK,CAAC,EAAE,OAAO,MAAM;AACtG,QAAM,QAAQ,SAAS;AAEvB,QAAM,eAAe,MAAM;AACvB,YAAQ,OAAO,MAAM;AAAA,MACjB,KAAK;AAAO,eAAO;AAAA,MACnB,KAAK;AAAO,eAAO;AAAA,MACnB,KAAK;AAAU,eAAO;AAAA,MACtB;AAAS,eAAO,OAAO;AAAA,IAC3B;AAAA,EACJ;AAGA,MAAI,OAAO,WAAW,cAAc;AAChC,WACI,oCAAC,OAAI,eAAc,UAAS,aAAY,SAAQ,aAAY,WAAU,UAAU,GAAG,cAAc,GAAG,WAAU,gBAC1G,oCAAC,WACG,oCAAC,QAAK,OAAO,MAAM,UAAQ,oCAAC,WAAQ,MAAK,QAAO,CAAE,GAClD,oCAAC,QAAK,OAAM,aAAU,mBAAgB,aAAa,GAAE,iBAAe,CACxE,CACJ;AAAA,EAER;AAGA,MAAI,OAAO,WAAW,aAAa;AAC/B,WACI,oCAAC,OAAI,eAAc,UAAS,aAAY,SAAQ,aAAY,WAAU,UAAU,GAAG,cAAc,GAAG,WAAU,gBAC1G,oCAAC,WACG,oCAAC,QAAK,OAAM,WAAU,MAAI,QAAC,QAAC,GAC5B,oCAAC,QAAK,OAAM,aAAU,6BAA0B,aAAa,GAAE,cAAY,GAC1E,OAAO,oBACJ,oCAAC,QAAK,OAAM,aAAU,MAAG,aAAa,GAAE,KAAE,OAAO,kBAAiB,GAAC,CAE3E,CACJ;AAAA,EAER;AAGA,MAAI,OAAO,WAAW,SAAS;AAC3B,WACI,oCAAC,OAAI,eAAc,UAAS,aAAY,SAAQ,aAAY,WAAU,UAAU,GAAG,cAAc,GAAG,WAAU,gBAC1G,oCAAC,WACG,oCAAC,QAAK,OAAM,WAAU,MAAI,QAAC,QAAC,GAC5B,oCAAC,QAAK,OAAM,aAAU,0BAAuB,aAAa,GAAE,cAAY,CAC5E,GACC,OAAO,SACJ,oCAAC,OAAI,aAAa,GAAG,WAAW,KAC5B,oCAAC,QAAK,OAAM,aAAW,OAAO,MAAM,MAAM,GAAG,GAAG,GAAG,OAAO,MAAM,SAAS,MAAM,QAAQ,EAAG,CAC9F,CAER;AAAA,EAER;AAGA,MAAI,OAAO,WAAW,gBAAgB;AAClC,WACI,oCAAC,OAAI,eAAc,UAAS,aAAY,SAAQ,aAAY,WAAU,UAAU,GAAG,cAAc,GAAG,WAAU,gBAC1G,oCAAC,WACG,oCAAC,QAAK,OAAM,WAAU,MAAI,QAAC,QAAC,GAC5B,oCAAC,QAAK,OAAM,aAAU,uBAAoB,aAAa,GAAE,cAAY,GACpE,OAAO,oBACJ,oCAAC,QAAK,OAAM,aAAU,MAAG,aAAa,GAAE,KAAE,OAAO,kBAAiB,GAAC,CAE3E,GACC,OAAO,SACJ,oCAAC,WACG,oCAAC,QAAK,OAAM,aAAU,KAAE,OAAO,MAAM,MAAM,GAAG,GAAG,GAAG,OAAO,MAAM,SAAS,MAAM,QAAQ,EAAG,CAC/F,CAER;AAAA,EAER;AAEA,SAAO;AACX,GAAG,CAAC,WAAW,cAAc;AAEzB,SAAO,UAAU,OAAO,WAAW,UAAU,OAAO,UAChD,UAAU,OAAO,SAAS,UAAU,OAAO,QAC3C,UAAU,OAAO,qBAAqB,UAAU,OAAO,oBACvD,UAAU,OAAO,UAAU,UAAU,OAAO;AACpD,CAAC;","names":[]}
|
|
@@ -1,104 +1,114 @@
|
|
|
1
1
|
import React, { useState } from "react";
|
|
2
2
|
import { Box, Text, useInput, useStdout } from "ink";
|
|
3
|
+
import { useTheme } from "../theme.js";
|
|
4
|
+
import { MarkdownRenderer } from "./MarkdownRenderer.js";
|
|
3
5
|
const DetailedPlanReviewScreen = ({
|
|
4
6
|
plan,
|
|
5
7
|
onApprove,
|
|
6
8
|
onEdit
|
|
7
9
|
}) => {
|
|
10
|
+
const theme = useTheme();
|
|
8
11
|
const { stdout } = useStdout();
|
|
9
12
|
const terminalHeight = stdout?.rows || 24;
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
13
|
+
const terminalWidth = stdout?.columns || 80;
|
|
14
|
+
const SAFETY_BUFFER = 5;
|
|
15
|
+
const HEADER_ROWS = 3;
|
|
16
|
+
const visibleSteps = Math.min(plan.implementationSteps.length, 10);
|
|
17
|
+
const hasOverflow = plan.implementationSteps.length > 10;
|
|
18
|
+
const STEPS_ROWS = 2 + 1 + visibleSteps + (hasOverflow ? 1 : 0);
|
|
19
|
+
const APPROVAL_ROWS = 4;
|
|
20
|
+
const MARGINS = 3;
|
|
21
|
+
const fixedRows = HEADER_ROWS + STEPS_ROWS + APPROVAL_ROWS + MARGINS + SAFETY_BUFFER;
|
|
22
|
+
const rawDocBudget = terminalHeight - fixedRows;
|
|
23
|
+
const DOC_BOX_OVERHEAD = 2;
|
|
24
|
+
const docContentBudget = rawDocBudget - DOC_BOX_OVERHEAD;
|
|
25
|
+
const showDocument = docContentBudget >= 5;
|
|
26
|
+
const availableDocHeight = showDocument ? docContentBudget : 0;
|
|
14
27
|
const [scrollOffset, setScrollOffset] = useState(0);
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
const statusIcon = step.status === "completed" ? "[x]" : "[ ]";
|
|
18
|
-
taskListItems.push({
|
|
19
|
-
type: "task",
|
|
20
|
-
content: `${taskIndex + 1}. ${step.description}`,
|
|
21
|
-
status: statusIcon
|
|
22
|
-
});
|
|
23
|
-
step.subtasks?.forEach((subtask, subIndex) => {
|
|
24
|
-
const subStatusIcon = subtask.status === "completed" ? "[x]" : "[ ]";
|
|
25
|
-
taskListItems.push({
|
|
26
|
-
type: "subtask",
|
|
27
|
-
content: ` ${taskIndex + 1}.${subIndex + 1}. ${subtask.description}`,
|
|
28
|
-
status: subStatusIcon
|
|
29
|
-
});
|
|
30
|
-
});
|
|
31
|
-
});
|
|
32
|
-
const maxScroll = Math.max(0, taskListItems.length - availableTaskHeight);
|
|
28
|
+
const docLines = plan.document.split("\n");
|
|
29
|
+
const maxScroll = Math.max(0, docLines.length - availableDocHeight);
|
|
33
30
|
useInput((input, key) => {
|
|
34
31
|
if (key.return || input.toLowerCase() === "y") {
|
|
35
32
|
onApprove();
|
|
36
33
|
} else if (input.toLowerCase() === "n") {
|
|
37
34
|
onEdit();
|
|
38
35
|
} else if (key.upArrow) {
|
|
39
|
-
setScrollOffset((prev) => Math.max(0, prev -
|
|
36
|
+
setScrollOffset((prev) => Math.max(0, prev - 3));
|
|
40
37
|
} else if (key.downArrow) {
|
|
41
|
-
setScrollOffset((prev) => Math.min(maxScroll, prev +
|
|
38
|
+
setScrollOffset((prev) => Math.min(maxScroll, prev + 3));
|
|
39
|
+
} else if (key.pageDown) {
|
|
40
|
+
setScrollOffset((prev) => Math.min(maxScroll, prev + availableDocHeight));
|
|
41
|
+
} else if (key.pageUp) {
|
|
42
|
+
setScrollOffset((prev) => Math.max(0, prev - availableDocHeight));
|
|
42
43
|
}
|
|
43
44
|
});
|
|
44
|
-
const
|
|
45
|
+
const visibleDocContent = docLines.slice(scrollOffset, scrollOffset + availableDocHeight).join("\n");
|
|
45
46
|
const showScrollUp = scrollOffset > 0;
|
|
46
47
|
const showScrollDown = scrollOffset < maxScroll;
|
|
47
|
-
|
|
48
|
-
const totalSubtasks = plan.steps.reduce((acc, step) => acc + (step.subtasks?.length || 0), 0);
|
|
49
|
-
const totalItems = totalSubtasks > 0 ? totalSubtasks : totalTasks;
|
|
50
|
-
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", paddingX: 1, paddingY: 0 }, /* @__PURE__ */ React.createElement(
|
|
51
|
-
Box,
|
|
52
|
-
{
|
|
53
|
-
borderStyle: "double",
|
|
54
|
-
borderColor: "#ffaa00",
|
|
55
|
-
paddingX: 2,
|
|
56
|
-
paddingY: 0,
|
|
57
|
-
marginBottom: 1
|
|
58
|
-
},
|
|
59
|
-
/* @__PURE__ */ React.createElement(Text, { color: "#ffaa00", bold: true }, "\u{1F4CB} PLAN REVIEW: "),
|
|
60
|
-
/* @__PURE__ */ React.createElement(Text, { color: "#00ccff", bold: true }, plan.title)
|
|
61
|
-
), plan.designSummary && /* @__PURE__ */ React.createElement(
|
|
48
|
+
return /* @__PURE__ */ React.createElement(
|
|
62
49
|
Box,
|
|
63
50
|
{
|
|
64
51
|
flexDirection: "column",
|
|
65
|
-
borderStyle: "round",
|
|
66
|
-
borderColor: "#4a4a4a",
|
|
67
52
|
paddingX: 1,
|
|
68
53
|
paddingY: 0,
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
/* @__PURE__ */ React.createElement(Text, { color: "#666666", dimColor: true }, "\u{1F4D6} Design Summary:"),
|
|
72
|
-
/* @__PURE__ */ React.createElement(Box, { marginLeft: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "#888888", wrap: "truncate-end" }, plan.designSummary.length > 300 ? plan.designSummary.substring(0, 300) + "..." : plan.designSummary))
|
|
73
|
-
), plan.summary && /* @__PURE__ */ React.createElement(Box, { marginBottom: 1, marginLeft: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "#888888" }, plan.summary)), /* @__PURE__ */ React.createElement(
|
|
74
|
-
Box,
|
|
75
|
-
{
|
|
76
|
-
flexDirection: "column",
|
|
77
|
-
borderStyle: "round",
|
|
78
|
-
borderColor: "#00ccff",
|
|
79
|
-
paddingX: 1,
|
|
80
|
-
paddingY: 0,
|
|
81
|
-
marginBottom: 1
|
|
82
|
-
},
|
|
83
|
-
/* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: "#00ccff", bold: true }, "\u{1F4DD} Tasks"), /* @__PURE__ */ React.createElement(Text, { color: "#666666" }, " (", totalItems, " items in ", totalTasks, " phases)")),
|
|
84
|
-
showScrollUp && /* @__PURE__ */ React.createElement(Box, { justifyContent: "center" }, /* @__PURE__ */ React.createElement(Text, { color: "#666666" }, "\u2191 scroll up (\u2191 key)")),
|
|
85
|
-
/* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginY: 0 }, visibleItems.map((item, index) => {
|
|
86
|
-
const isTask = item.type === "task";
|
|
87
|
-
return /* @__PURE__ */ React.createElement(Box, { key: scrollOffset + index }, /* @__PURE__ */ React.createElement(Text, { color: isTask ? "#cccccc" : "#999999", wrap: "wrap" }, item.status, " ", item.content));
|
|
88
|
-
})),
|
|
89
|
-
showScrollDown && /* @__PURE__ */ React.createElement(Box, { justifyContent: "center" }, /* @__PURE__ */ React.createElement(Text, { color: "#666666" }, "\u2193 scroll down (\u2193 key)"))
|
|
90
|
-
), /* @__PURE__ */ React.createElement(
|
|
91
|
-
Box,
|
|
92
|
-
{
|
|
93
|
-
flexDirection: "column",
|
|
94
|
-
borderStyle: "round",
|
|
95
|
-
borderColor: "#00cc66",
|
|
96
|
-
paddingX: 2,
|
|
97
|
-
paddingY: 0
|
|
54
|
+
height: terminalHeight,
|
|
55
|
+
overflow: "hidden"
|
|
98
56
|
},
|
|
99
|
-
/* @__PURE__ */ React.createElement(
|
|
100
|
-
|
|
101
|
-
|
|
57
|
+
/* @__PURE__ */ React.createElement(
|
|
58
|
+
Box,
|
|
59
|
+
{
|
|
60
|
+
borderStyle: "double",
|
|
61
|
+
borderColor: "#ffaa00",
|
|
62
|
+
paddingX: 2,
|
|
63
|
+
paddingY: 0,
|
|
64
|
+
marginBottom: 1
|
|
65
|
+
},
|
|
66
|
+
/* @__PURE__ */ React.createElement(Text, { color: "#ffaa00", bold: true }, "PLAN REVIEW: "),
|
|
67
|
+
/* @__PURE__ */ React.createElement(Text, { color: theme.accent, bold: true }, plan.title)
|
|
68
|
+
),
|
|
69
|
+
showDocument && /* @__PURE__ */ React.createElement(
|
|
70
|
+
Box,
|
|
71
|
+
{
|
|
72
|
+
flexDirection: "column",
|
|
73
|
+
borderStyle: "round",
|
|
74
|
+
borderColor: "#4a4a4a",
|
|
75
|
+
paddingX: 1,
|
|
76
|
+
paddingY: 0,
|
|
77
|
+
marginBottom: 1,
|
|
78
|
+
height: availableDocHeight + DOC_BOX_OVERHEAD,
|
|
79
|
+
overflow: "hidden"
|
|
80
|
+
},
|
|
81
|
+
showScrollUp && /* @__PURE__ */ React.createElement(Box, { justifyContent: "center" }, /* @__PURE__ */ React.createElement(Text, { color: "#666666" }, "--- scroll up (arrow keys) ---")),
|
|
82
|
+
/* @__PURE__ */ React.createElement(Box, { flexDirection: "column", height: availableDocHeight }, /* @__PURE__ */ React.createElement(MarkdownRenderer, { content: visibleDocContent, maxWidth: terminalWidth - 6 })),
|
|
83
|
+
showScrollDown && /* @__PURE__ */ React.createElement(Box, { justifyContent: "center" }, /* @__PURE__ */ React.createElement(Text, { color: "#666666" }, "--- scroll down (arrow keys) ---"))
|
|
84
|
+
),
|
|
85
|
+
!showDocument && /* @__PURE__ */ React.createElement(Box, { marginBottom: 1, marginLeft: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "#666666", dimColor: true }, "Plan document hidden (terminal too small) - resize to view")),
|
|
86
|
+
/* @__PURE__ */ React.createElement(
|
|
87
|
+
Box,
|
|
88
|
+
{
|
|
89
|
+
flexDirection: "column",
|
|
90
|
+
borderStyle: "round",
|
|
91
|
+
borderColor: theme.accent,
|
|
92
|
+
paddingX: 1,
|
|
93
|
+
paddingY: 0,
|
|
94
|
+
marginBottom: 1
|
|
95
|
+
},
|
|
96
|
+
/* @__PURE__ */ React.createElement(Text, { color: theme.accent, bold: true }, "Implementation Steps (", plan.implementationSteps.length, " steps)"),
|
|
97
|
+
/* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginTop: 0 }, plan.implementationSteps.slice(0, 10).map((step) => /* @__PURE__ */ React.createElement(Box, { key: step.id }, /* @__PURE__ */ React.createElement(Text, { color: "#999999", wrap: "truncate-end" }, " ", step.description.length > terminalWidth - 8 ? step.description.substring(0, terminalWidth - 11) + "..." : step.description))), hasOverflow && /* @__PURE__ */ React.createElement(Text, { color: "#666666", dimColor: true }, " ... and ", plan.implementationSteps.length - 10, " more steps"))
|
|
98
|
+
),
|
|
99
|
+
/* @__PURE__ */ React.createElement(
|
|
100
|
+
Box,
|
|
101
|
+
{
|
|
102
|
+
flexDirection: "column",
|
|
103
|
+
borderStyle: "round",
|
|
104
|
+
borderColor: "#00cc66",
|
|
105
|
+
paddingX: 2,
|
|
106
|
+
paddingY: 0
|
|
107
|
+
},
|
|
108
|
+
/* @__PURE__ */ React.createElement(Text, { color: "#00cc66", bold: true }, "Implement this plan?"),
|
|
109
|
+
/* @__PURE__ */ React.createElement(Box, { marginTop: 0 }, /* @__PURE__ */ React.createElement(Box, { marginRight: 4 }, /* @__PURE__ */ React.createElement(Text, { color: "#888888" }, "Press "), /* @__PURE__ */ React.createElement(Text, { color: "#00cc66", bold: true }, "Y"), /* @__PURE__ */ React.createElement(Text, { color: "#888888" }, " or "), /* @__PURE__ */ React.createElement(Text, { color: "#00cc66", bold: true }, "Enter"), /* @__PURE__ */ React.createElement(Text, { color: "#888888" }, " to implement")), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: "#888888" }, "Press "), /* @__PURE__ */ React.createElement(Text, { color: "#ff6666", bold: true }, "N"), /* @__PURE__ */ React.createElement(Text, { color: "#888888" }, " to cancel")))
|
|
110
|
+
)
|
|
111
|
+
);
|
|
102
112
|
};
|
|
103
113
|
var DetailedPlanReviewScreen_default = DetailedPlanReviewScreen;
|
|
104
114
|
export {
|