Skip to content

Commit 825a794

Browse files
committed
feat: enhance CLI-VSCode integration and replace enquirer with inquirer
Add chat history synchronization between CLI, web server, and VSCode extension. Implement abort operation support and improve message handling for better WebSocket communication. Replace enquirer with inquirer for interactive prompts, updating the status bar configuration command. Update build output directory from 'out' to 'dist' across all packages and fix bin path configuration.
1 parent a0a8c6c commit 825a794

18 files changed

Lines changed: 377 additions & 106 deletions
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: VS Code Extension Release
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*"
7+
8+
jobs:
9+
build:
10+
runs-on: ubuntu-latest
11+
permissions:
12+
contents: write
13+
14+
steps:
15+
- uses: actions/checkout@v4
16+
17+
- name: Setup Node.js
18+
uses: actions/setup-node@v4
19+
with:
20+
node-version: 20
21+
22+
- name: Setup Bun
23+
uses: oven-sh/setup-bun@v1
24+
with:
25+
bun-version: latest
26+
27+
- name: Install Dependencies
28+
run: bun install
29+
30+
- name: Build Project
31+
run: bun run build
32+
33+
- name: Build Extension
34+
working-directory: ./vscode-extension
35+
run: |
36+
npm install -g @vscode/vsce
37+
bun run package
38+
39+
- name: Create Release
40+
uses: softprops/action-gh-release@v1
41+
with:
42+
files: vscode-extension/*.vsix
43+
generate_release_notes: true

bun.lock

Lines changed: 39 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

eslint.config.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export default [
1010
"@plugins/templates/*/dist/*.js",
1111
"@plugins/examples/*/dist/*.js.map",
1212
"@plugins/templates/*/dist/*.js.map",
13-
"vscode-extension/out/**",
13+
"vscode-extension/dist/**",
1414
],
1515
},
1616
{

package.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
},
2929
"main": "dist/index.js",
3030
"bin": {
31-
"super-agent": "super-agent.js"
31+
"super-agent": "dist/super-agent.js"
3232
},
3333
"workspaces": [
3434
"@plugins/templates/*",
@@ -37,7 +37,7 @@
3737
],
3838
"scripts": {
3939
"prebuild": "bun run format && bun run lint:fix && bun run typecheck",
40-
"build": "bun build src/index.ts --outdir ./dist --target node --packages external --format esm && bun run copy-bin && bun run build:web",
40+
"build": "bun build src/index.ts --outdir ./dist --target node --packages external --format esm && bun run copy-bin && bun run build:web && bun run build:plugins && bun run build:vscode && bun run package:vscode",
4141
"build:bun": "bun build src/index.ts --outdir ./dist --target node --packages external --format esm",
4242
"build:plugins": "bun run -F @involvex/super-agent\\* build",
4343
"build:vscode": "bun run -F super-agent-vscode build",
@@ -74,7 +74,6 @@
7474
"commander": "^14.0.3",
7575
"conventional-changelog-cli": "^5.0.0",
7676
"dotenv": "^17.2.3",
77-
"enquirer": "^2.4.1",
7877
"firebase": "^12.8.0",
7978
"fs-extra": "^11.3.3",
8079
"ignore": "^7.0.5",

src/agent/super-agent.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,13 @@ Current working directory: ${process.cwd()}`,
280280
});
281281
}
282282

283+
/**
284+
* Get the current chat history
285+
*/
286+
public getChatHistory(): ChatEntry[] {
287+
return this.chatHistory;
288+
}
289+
283290
/**
284291
* Set the active provider dynamically
285292
*/

src/commands/statusbar.ts

Lines changed: 36 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { getSettingsManager } from "../utils/settings-manager";
22
import { Command } from "commander";
3-
import { prompt } from "enquirer";
3+
import inquirer from "inquirer";
44

55
export function createStatusBarCommand(): Command {
66
const command = new Command("statusbar");
@@ -17,45 +17,42 @@ export function createStatusBarCommand(): Command {
1717
};
1818

1919
try {
20-
const response = await prompt<{
20+
const response = await inquirer.prompt<{
2121
features: string[];
22-
}>({
23-
type: "multiselect",
24-
name: "features",
25-
message: "Select status bar features to display:",
26-
choices: [
27-
{
28-
name: "show_model",
29-
message: "Model Name",
30-
value: "show_model",
31-
enabled: currentConfig.show_model,
32-
},
33-
{
34-
name: "show_tokens",
35-
message: "Token Count",
36-
value: "show_tokens",
37-
enabled: currentConfig.show_tokens,
38-
},
39-
{
40-
name: "show_git_status",
41-
message: "Git Status",
42-
value: "show_git_status",
43-
enabled: currentConfig.show_git_status,
44-
},
45-
{
46-
name: "show_memory",
47-
message: "Memory Usage",
48-
value: "show_memory",
49-
enabled: currentConfig.show_memory,
50-
},
51-
{
52-
name: "show_context",
53-
message: "Context Size",
54-
value: "show_context",
55-
enabled: currentConfig.show_context,
56-
},
57-
],
58-
});
22+
}>([
23+
{
24+
type: "checkbox",
25+
name: "features",
26+
message: "Select status bar features to display:",
27+
choices: [
28+
{
29+
name: "Model Name",
30+
value: "show_model",
31+
checked: currentConfig.show_model,
32+
},
33+
{
34+
name: "Token Count",
35+
value: "show_tokens",
36+
checked: currentConfig.show_tokens,
37+
},
38+
{
39+
name: "Git Status",
40+
value: "show_git_status",
41+
checked: currentConfig.show_git_status,
42+
},
43+
{
44+
name: "Memory Usage",
45+
value: "show_memory",
46+
checked: currentConfig.show_memory,
47+
},
48+
{
49+
name: "Context Size",
50+
value: "show_context",
51+
checked: currentConfig.show_context,
52+
},
53+
],
54+
},
55+
]);
5956

6057
// Convert array of selected features back to config object
6158
const newConfig = {

src/hooks/use-keyboard-input.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export function useKeyboardInput(
1010
onSubmit: (command: string) => Promise<void>,
1111
isProcessing: boolean,
1212
confirmationOptions: unknown,
13+
onEscape?: () => void,
1314
) {
1415
useInput(
1516
useCallback(
@@ -23,6 +24,13 @@ export function useKeyboardInput(
2324
process.exit(0);
2425
}
2526

27+
if (key.escape) {
28+
if (onEscape) {
29+
onEscape();
30+
}
31+
return;
32+
}
33+
2634
if (key.return) {
2735
if (input.trim() === "exit" || input.trim() === "quit") {
2836
process.exit(0);

src/ui/app.tsx

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@ import { Box } from "ink";
1010

1111
import { useCommandHistory } from "../hooks/use-command-history";
1212
import { useKeyboardInput } from "../hooks/use-keyboard-input";
13+
import { getSettingsManager } from "../utils/settings-manager";
1314
import { CommandHistory } from "./components/command-history";
15+
import { ConfigViewer } from "./components/config-viewer";
1416
import { CommandInput } from "./components/command-input";
1517
import { CommandHelp } from "./components/command-help";
18+
import { StatusBar } from "./components/statusbar";
1619
import { Header } from "./components/header";
1720

1821
interface Props {
@@ -23,6 +26,9 @@ export default function App({ agent }: Props) {
2326
const [input, setInput] = useState("");
2427
const [confirmationOptions, setConfirmationOptions] =
2528
useState<ConfirmationOptions | null>(null);
29+
const [showConfig, setShowConfig] = useState(false);
30+
const [tokenCount, setTokenCount] = useState(0);
31+
const [toolCallsCount, setToolCallsCount] = useState(0);
2632

2733
const confirmationService = useMemo(
2834
() => ConfirmationService.getInstance(),
@@ -33,20 +39,43 @@ export default function App({ agent }: Props) {
3339
useCommandHistory();
3440

3541
const handleSubmit = async (command: string) => {
42+
// Handle slash commands
43+
if (command.trim() === "/settings" || command.trim() === "/config") {
44+
setShowConfig(true);
45+
return;
46+
}
47+
3648
setIsProcessing(true);
3749
const result = await agent.processCommand(command);
3850
addEntry(command, result);
3951
setIsProcessing(false);
4052
};
4153

54+
const currentSettings = getSettingsManager().getEffectiveSettings();
55+
const configInfo = {
56+
activeProvider: currentSettings.active_provider || "grok",
57+
apiKeySet: !!getSettingsManager().getApiKey(),
58+
baseUrl:
59+
currentSettings.providers?.[currentSettings.active_provider || "grok"]
60+
?.base_url,
61+
model:
62+
currentSettings.providers?.[currentSettings.active_provider || "grok"]
63+
?.model,
64+
theme: currentSettings.ui?.theme || "zinc",
65+
};
66+
4267
useKeyboardInput(
4368
input,
4469
setInput,
4570
handleSubmit,
4671
isProcessing,
4772
confirmationOptions,
73+
() => {
74+
if (showConfig) {
75+
setShowConfig(false);
76+
}
77+
},
4878
);
49-
5079
useEffect(() => {
5180
const handleConfirmationRequest = (options: ConfirmationOptions) => {
5281
setConfirmationOptions(options);
@@ -88,11 +117,28 @@ export default function App({ agent }: Props) {
88117
);
89118
}
90119

120+
if (showConfig) {
121+
return (
122+
<ConfigViewer config={configInfo} onClose={() => setShowConfig(false)} />
123+
);
124+
}
125+
91126
return (
92-
<Box flexDirection="column" padding={1}>
93-
<Header />
94-
<CommandHelp />
95-
<CommandHistory history={history} />
127+
<Box flexDirection="column" padding={1} height="100%">
128+
<Box flexDirection="column" flexGrow={1}>
129+
<Header />
130+
<CommandHelp />
131+
<CommandHistory history={history} />
132+
</Box>
133+
134+
<StatusBar
135+
currentModel={getSettingsManager().getCurrentModel()}
136+
isProcessing={isProcessing}
137+
tokenCount={tokenCount}
138+
toolCallsCount={toolCallsCount}
139+
contextSize={0} // TODO: Hook up real context size
140+
/>
141+
96142
<CommandInput input={input} isProcessing={isProcessing} />
97143
</Box>
98144
);

src/ui/components/config-viewer.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,15 @@ interface ConfigInfo {
1010

1111
interface ConfigViewerProps {
1212
config: ConfigInfo;
13-
isVisible: boolean;
13+
isVisible?: boolean;
14+
onClose?: () => void;
1415
}
1516

16-
export function ConfigViewer({ config, isVisible }: ConfigViewerProps) {
17+
export function ConfigViewer({
18+
config,
19+
isVisible = true,
20+
onClose,
21+
}: ConfigViewerProps) {
1722
if (!isVisible) {
1823
return null;
1924
}

src/web/server.ts

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,16 +107,25 @@ export class WebServer {
107107
try {
108108
const message = JSON.parse(data.toString());
109109

110-
if (message.type === "prompt") {
111-
await this.handlePrompt(message.content, ws);
110+
if (message.type === "prompt" || message.type === "chat_message") {
111+
const content = message.content?.message || message.content || "";
112+
await this.handlePrompt(content, ws);
112113
} else if (message.type === "get_file_tree") {
113114
await this.handleGetFileTree(ws);
114115
} else if (message.type === "get_file_content") {
115-
await this.handleGetFileContent(message.path, ws);
116+
const filePath = message.path || message.filePath;
117+
await this.handleGetFileContent(filePath, ws);
116118
} else if (message.type === "list_sessions") {
117119
await this.handleListSessions(ws);
118120
} else if (message.type === "switch_session") {
119121
await this.handleSwitchSession(message.sessionId, ws);
122+
} else if (message.type === "get_chat_history") {
123+
await this.handleGetChatHistory(ws);
124+
} else if (message.type === "abort") {
125+
this.agent.abortCurrentOperation();
126+
ws.send(
127+
JSON.stringify({ type: "done", content: "Operation aborted" }),
128+
);
120129
}
121130
} catch (error) {
122131
console.error("WebSocket message error:", error);
@@ -292,6 +301,26 @@ export class WebServer {
292301
}
293302
}
294303

304+
private async handleGetChatHistory(ws: WebSocket): Promise<void> {
305+
try {
306+
const history = this.agent.getChatHistory();
307+
ws.send(
308+
JSON.stringify({
309+
type: "chat_history",
310+
messages: history.map(entry => ({
311+
role: entry.type === "user" ? "user" : "assistant",
312+
content: entry.content,
313+
timestamp: entry.timestamp,
314+
toolCall: entry.toolCall,
315+
toolResult: entry.toolResult,
316+
})),
317+
}),
318+
);
319+
} catch (error: any) {
320+
ws.send(JSON.stringify({ type: "error", content: error.message }));
321+
}
322+
}
323+
295324
private async checkAndSendUpdateNotification(ws: WebSocket): Promise<void> {
296325
try {
297326
const pkg = await import("../../package.json");

0 commit comments

Comments
 (0)