@involvex/super-agent-cli 0.0.80 → 0.0.82
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/README.md +5 -2
- package/assets/images/banner.png +0 -0
- package/dist/index.js +24 -20
- package/dist/super-agent-cli.exe +0 -0
- package/dist/super-agent.js +12 -0
- package/dist/web/app.js +418 -0
- package/dist/web/favicon.png +0 -0
- package/dist/web/index.html +71 -0
- package/dist/web/logo.png +0 -0
- package/dist/web/styles.css +444 -0
- package/package.json +6 -5
- package/super-agent.js +12 -0
- package/vscode-extension/README.md +2 -0
- package/vscode-extension/build.js +31 -0
- package/vscode-extension/package.json +5 -0
package/README.md
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
```
|
|
2
|
+
@involvex/super-agent-cli
|
|
3
|
+
```
|
|
4
|
+
|
|
5
|
+

|
|
2
6
|
|
|
3
|
-

|
|
4
7
|
[](https://github.com/involvex/super-agent-cli/actions/workflows/security.yml)
|
|
5
8
|

|
|
6
9
|
|
package/assets/images/banner.png
CHANGED
|
Binary file
|
package/dist/index.js
CHANGED
|
@@ -1021,8 +1021,8 @@ __export(exports_image_generation, {
|
|
|
1021
1021
|
getImageGenerationService: () => getImageGenerationService,
|
|
1022
1022
|
ImageGenerationService: () => ImageGenerationService
|
|
1023
1023
|
});
|
|
1024
|
-
import * as fs7 from "fs-extra";
|
|
1025
1024
|
import * as path7 from "path";
|
|
1025
|
+
import fs7 from "fs-extra";
|
|
1026
1026
|
|
|
1027
1027
|
class ImageGenerationService {
|
|
1028
1028
|
static instance;
|
|
@@ -1609,8 +1609,8 @@ __export(exports_indexer, {
|
|
|
1609
1609
|
getFileIndexer: () => getFileIndexer,
|
|
1610
1610
|
FileIndexer: () => FileIndexer
|
|
1611
1611
|
});
|
|
1612
|
-
import * as fs15 from "fs-extra";
|
|
1613
1612
|
import * as path15 from "path";
|
|
1613
|
+
import fs15 from "fs-extra";
|
|
1614
1614
|
|
|
1615
1615
|
class FileIndexer {
|
|
1616
1616
|
static instance;
|
|
@@ -1731,7 +1731,7 @@ var init_indexer = __esm(() => {
|
|
|
1731
1731
|
var require_package = __commonJS((exports, module) => {
|
|
1732
1732
|
module.exports = {
|
|
1733
1733
|
name: "@involvex/super-agent-cli",
|
|
1734
|
-
version: "0.0.
|
|
1734
|
+
version: "0.0.82",
|
|
1735
1735
|
description: "An open-source AI agent that brings the power of Super Agent directly into your terminal.",
|
|
1736
1736
|
keywords: [
|
|
1737
1737
|
"cli",
|
|
@@ -1759,7 +1759,7 @@ var require_package = __commonJS((exports, module) => {
|
|
|
1759
1759
|
},
|
|
1760
1760
|
main: "dist/index.js",
|
|
1761
1761
|
bin: {
|
|
1762
|
-
"super-agent": "
|
|
1762
|
+
"super-agent": "super-agent.js"
|
|
1763
1763
|
},
|
|
1764
1764
|
workspaces: [
|
|
1765
1765
|
"@plugins/templates/*",
|
|
@@ -1768,13 +1768,14 @@ var require_package = __commonJS((exports, module) => {
|
|
|
1768
1768
|
],
|
|
1769
1769
|
scripts: {
|
|
1770
1770
|
prebuild: "bun run format && bun run lint:fix && bun run typecheck",
|
|
1771
|
-
build: "bun build src/index.ts --outdir ./dist --target node --packages external --format esm",
|
|
1771
|
+
build: "bun build src/index.ts --outdir ./dist --target node --packages external --format esm && bun run copy-bin && bun run build:web",
|
|
1772
1772
|
"build:bun": "bun build src/index.ts --outdir ./dist --target node --packages external --format esm",
|
|
1773
1773
|
"build:plugins": "bun run -F @involvex/super-agent\\* build",
|
|
1774
1774
|
"build:vscode": "bun run -F super-agent-vscode build",
|
|
1775
1775
|
"build:web": "bun run scripts/build-web.ts",
|
|
1776
1776
|
changelog: "conventional-changelog -p angular -i CHANGELOG.md -s -r 0",
|
|
1777
1777
|
compile: "bun run prebuild && bun build --compile src/index.ts --outfile ./dist/super-agent-cli.exe --config bunfig.toml",
|
|
1778
|
+
"copy-bin": "cp super-agent.js dist/super-agent.js",
|
|
1778
1779
|
dev: "bun run --watch src/index.ts",
|
|
1779
1780
|
"dev:node": "tsx src/index.ts",
|
|
1780
1781
|
format: "prettier --write .",
|
|
@@ -1783,8 +1784,8 @@ var require_package = __commonJS((exports, module) => {
|
|
|
1783
1784
|
lint: "eslint . --ext .js,.jsx,.ts,.tsx --ignore-pattern dist",
|
|
1784
1785
|
"lint:fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix --ignore-pattern dist",
|
|
1785
1786
|
"package:vscode": "bun run -F super-agent-vscode package",
|
|
1786
|
-
start: "
|
|
1787
|
-
"start:
|
|
1787
|
+
start: "bun run dist/index.js",
|
|
1788
|
+
"start:node": "node dist/index.js",
|
|
1788
1789
|
test: "vitest run",
|
|
1789
1790
|
"test:coverage": "vitest run --coverage",
|
|
1790
1791
|
"test:integration": "vitest run src/tests/integration",
|
|
@@ -2908,8 +2909,8 @@ init_config();
|
|
|
2908
2909
|
init_settings_manager();
|
|
2909
2910
|
import { exec as exec2 } from "child_process";
|
|
2910
2911
|
import { promisify as promisify2 } from "util";
|
|
2911
|
-
import * as fs4 from "fs-extra";
|
|
2912
2912
|
import * as path4 from "path";
|
|
2913
|
+
import fs4 from "fs-extra";
|
|
2913
2914
|
var execAsync2 = promisify2(exec2);
|
|
2914
2915
|
|
|
2915
2916
|
class PluginManager {
|
|
@@ -3474,8 +3475,8 @@ async function getAllSuperAgentTools() {
|
|
|
3474
3475
|
// src/plugins/repository-manager.ts
|
|
3475
3476
|
import { exec as exec3 } from "child_process";
|
|
3476
3477
|
import { promisify as promisify3 } from "util";
|
|
3477
|
-
import * as fs5 from "fs-extra";
|
|
3478
3478
|
import * as path5 from "path";
|
|
3479
|
+
import fs5 from "fs-extra";
|
|
3479
3480
|
var execAsync3 = promisify3(exec3);
|
|
3480
3481
|
var BUILTIN_REPOSITORIES = {
|
|
3481
3482
|
agents: {
|
|
@@ -3965,7 +3966,7 @@ function getChatManager() {
|
|
|
3965
3966
|
}
|
|
3966
3967
|
|
|
3967
3968
|
// src/hooks/use-input-handler.ts
|
|
3968
|
-
import
|
|
3969
|
+
import fs11 from "fs-extra";
|
|
3969
3970
|
function useInputHandler({
|
|
3970
3971
|
agent,
|
|
3971
3972
|
chatHistory,
|
|
@@ -11711,7 +11712,6 @@ import * as fs20 from "fs-extra";
|
|
|
11711
11712
|
import * as path20 from "path";
|
|
11712
11713
|
import open from "open";
|
|
11713
11714
|
import mime from "mime";
|
|
11714
|
-
var __dirname = "/home/runner/work/super-agent-cli/super-agent-cli/src/web";
|
|
11715
11715
|
|
|
11716
11716
|
class WebServer {
|
|
11717
11717
|
httpServer;
|
|
@@ -11734,20 +11734,24 @@ class WebServer {
|
|
|
11734
11734
|
}
|
|
11735
11735
|
async handleHttpRequest(req, res) {
|
|
11736
11736
|
const url = req.url || "/";
|
|
11737
|
-
|
|
11737
|
+
let requestedPath = url === "/" ? "index.html" : url.substring(1);
|
|
11738
11738
|
const sanitizedPath = requestedPath.split("?")[0].split("#")[0];
|
|
11739
|
-
const
|
|
11740
|
-
const
|
|
11741
|
-
|
|
11739
|
+
const distWebPath = path20.join(process.cwd(), "dist", "web");
|
|
11740
|
+
const sourceWebPath = path20.join(process.cwd(), "src", "web", "client");
|
|
11741
|
+
const clientDir = await fs20.pathExists(distWebPath) ? distWebPath : sourceWebPath;
|
|
11742
|
+
const absolutePath = path20.resolve(clientDir, sanitizedPath);
|
|
11743
|
+
const normalizedClientDir = path20.resolve(clientDir);
|
|
11744
|
+
const normalizedAbsolutePath = path20.resolve(absolutePath);
|
|
11745
|
+
if (!normalizedAbsolutePath.startsWith(normalizedClientDir)) {
|
|
11742
11746
|
res.writeHead(403, { "Content-Type": "text/plain" });
|
|
11743
11747
|
res.end("Forbidden");
|
|
11744
11748
|
return;
|
|
11745
11749
|
}
|
|
11746
11750
|
try {
|
|
11747
11751
|
if (await fs20.pathExists(absolutePath)) {
|
|
11748
|
-
const
|
|
11752
|
+
const stat2 = await fs20.stat(absolutePath);
|
|
11749
11753
|
let filePath = absolutePath;
|
|
11750
|
-
if (
|
|
11754
|
+
if (stat2.isDirectory()) {
|
|
11751
11755
|
filePath = path20.join(absolutePath, "index.html");
|
|
11752
11756
|
}
|
|
11753
11757
|
const content = await fs20.readFile(filePath);
|
|
@@ -12149,7 +12153,7 @@ function createIndexCommand() {
|
|
|
12149
12153
|
const indexCommand = new Command4("index").description(" recursively index a directory and save to a file").argument("[directory]", "Directory to index", ".").option("-o, --output <file>", "Output file path (default: index.md)").option("--no-ignore", "Disable .gitignore respecting").option("-d, --depth <depth>", "Max depth to traverse", "10").action(async (directory, options) => {
|
|
12150
12154
|
try {
|
|
12151
12155
|
const rootDir = path21.resolve(directory);
|
|
12152
|
-
const
|
|
12156
|
+
const outputFile = options.output ? path21.resolve(options.output) : path21.join(rootDir, "index.md");
|
|
12153
12157
|
const maxDepth = parseInt(options.depth);
|
|
12154
12158
|
console.log(chalk4.blue(`Indexing directory: ${rootDir}`));
|
|
12155
12159
|
const ig = ignore().add(DEFAULT_IGNORES);
|
|
@@ -12246,8 +12250,8 @@ Date: ${new Date().toISOString()}
|
|
|
12246
12250
|
|
|
12247
12251
|
`;
|
|
12248
12252
|
}
|
|
12249
|
-
await fs21.writeFile(
|
|
12250
|
-
console.log(chalk4.green(`✓ Index generated at: ${
|
|
12253
|
+
await fs21.writeFile(outputFile, outputContent);
|
|
12254
|
+
console.log(chalk4.green(`✓ Index generated at: ${outputFile}`));
|
|
12251
12255
|
} catch (error) {
|
|
12252
12256
|
console.error(chalk4.red(`Error indexing directory: ${error.message}`));
|
|
12253
12257
|
process.exit(1);
|
package/dist/super-agent-cli.exe
CHANGED
|
Binary file
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
// Super Agent CLI wrapper script
|
|
3
|
+
// This ensures the bundled code runs with bun for proper module resolution
|
|
4
|
+
|
|
5
|
+
import { dirname, join } from "path";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = dirname(__filename);
|
|
10
|
+
|
|
11
|
+
// Import and run the bundled CLI
|
|
12
|
+
import(join(__dirname, "dist", "index.js"));
|
package/dist/web/app.js
ADDED
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
// WebSocket connection
|
|
2
|
+
let ws = null;
|
|
3
|
+
let isConnected = false;
|
|
4
|
+
|
|
5
|
+
const messagesContainer = document.getElementById("messages");
|
|
6
|
+
const promptInput = document.getElementById("prompt-input");
|
|
7
|
+
const sendBtn = document.getElementById("send-btn");
|
|
8
|
+
const statusEl = document.getElementById("status");
|
|
9
|
+
const autocompleteEl = document.getElementById("autocomplete");
|
|
10
|
+
const fileTreeEl = document.getElementById("file-tree");
|
|
11
|
+
const sessionsListEl = document.getElementById("sessions-list");
|
|
12
|
+
|
|
13
|
+
// Slash commands
|
|
14
|
+
const SLASH_COMMANDS = [
|
|
15
|
+
{ cmd: "/chat", desc: "Manage chat sessions" },
|
|
16
|
+
{ cmd: "/config", desc: "Configure settings" },
|
|
17
|
+
{ cmd: "/models", desc: "Select AI model" },
|
|
18
|
+
{ cmd: "/provider", desc: "Select LLM provider" },
|
|
19
|
+
{ cmd: "/mcp", desc: "MCP server management" },
|
|
20
|
+
{ cmd: "/plugin", desc: "Plugin management" },
|
|
21
|
+
{ cmd: "/search", desc: "Search files/code" },
|
|
22
|
+
{ cmd: "/help", desc: "Show help" },
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
// Security: HTML escape utility to prevent XSS
|
|
26
|
+
function escapeHtml(unsafe) {
|
|
27
|
+
if (typeof unsafe !== "string") {
|
|
28
|
+
return "";
|
|
29
|
+
}
|
|
30
|
+
return unsafe
|
|
31
|
+
.replace(/&/g, "&")
|
|
32
|
+
.replace(/</g, "<")
|
|
33
|
+
.replace(/>/g, ">")
|
|
34
|
+
.replace(/"/g, """)
|
|
35
|
+
.replace(/'/g, "'");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Connect to WebSocket
|
|
39
|
+
function connect() {
|
|
40
|
+
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
|
|
41
|
+
const wsUrl = `${protocol}//${window.location.host}`;
|
|
42
|
+
|
|
43
|
+
ws = new WebSocket(wsUrl);
|
|
44
|
+
|
|
45
|
+
ws.onopen = () => {
|
|
46
|
+
isConnected = true;
|
|
47
|
+
updateStatus("Connected", "connected");
|
|
48
|
+
sendBtn.disabled = false;
|
|
49
|
+
|
|
50
|
+
// Load initial data
|
|
51
|
+
requestFileTree();
|
|
52
|
+
requestSessions();
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
ws.onclose = () => {
|
|
56
|
+
isConnected = false;
|
|
57
|
+
updateStatus("Disconnected - Retrying...", "disconnected");
|
|
58
|
+
sendBtn.disabled = true;
|
|
59
|
+
setTimeout(connect, 2000);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
ws.onerror = error => {
|
|
63
|
+
console.error("WebSocket error:", error);
|
|
64
|
+
updateStatus("Connection error", "disconnected");
|
|
65
|
+
// Check if we're on Firebase Hosting or similar static hosting
|
|
66
|
+
// Firebase Hosting does NOT support WebSocket connections
|
|
67
|
+
// Show disconnected mode after connection fails
|
|
68
|
+
setTimeout(() => {
|
|
69
|
+
if (!isConnected) {
|
|
70
|
+
showDisconnectedMode();
|
|
71
|
+
}
|
|
72
|
+
}, 2000);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
ws.onmessage = event => {
|
|
76
|
+
try {
|
|
77
|
+
const data = JSON.parse(event.data);
|
|
78
|
+
handleMessage(data);
|
|
79
|
+
} catch (error) {
|
|
80
|
+
console.error("Error parsing message:", error);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Show disconnected mode with helpful instructions
|
|
87
|
+
* This is shown when the WebSocket connection fails, which happens on
|
|
88
|
+
* Firebase Hosting and other static hosting providers that don't support WebSocket.
|
|
89
|
+
*/
|
|
90
|
+
function showDisconnectedMode() {
|
|
91
|
+
isConnected = false;
|
|
92
|
+
updateStatus("View-only mode - CLI not connected", "disconnected");
|
|
93
|
+
|
|
94
|
+
// Check if banner already exists to avoid duplicates
|
|
95
|
+
const existingBanner = document.querySelector(".disconnected-banner");
|
|
96
|
+
if (existingBanner) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Show banner explaining the situation
|
|
101
|
+
const banner = document.createElement("div");
|
|
102
|
+
banner.className = "disconnected-banner";
|
|
103
|
+
banner.innerHTML = `
|
|
104
|
+
<div class="banner-content">
|
|
105
|
+
<strong>📡 CLI Connection Required</strong>
|
|
106
|
+
<p>This web interface is in view-only mode. For full functionality:</p>
|
|
107
|
+
<ol>
|
|
108
|
+
<li>Run <code>super-agent --web</code> in your project directory</li>
|
|
109
|
+
<li>Open <a href="http://localhost:3000">http://localhost:3000</a></li>
|
|
110
|
+
</ol>
|
|
111
|
+
<p class="note">Note: This web interface on Firebase Hosting is for demonstration only.
|
|
112
|
+
WebSocket connections are not supported on static hosting platforms.</p>
|
|
113
|
+
<button class="dismiss-btn">Dismiss</button>
|
|
114
|
+
</div>
|
|
115
|
+
`;
|
|
116
|
+
|
|
117
|
+
document.body.insertBefore(banner, document.body.firstChild);
|
|
118
|
+
|
|
119
|
+
// Add dismiss handler
|
|
120
|
+
banner.querySelector(".dismiss-btn").addEventListener("click", () => {
|
|
121
|
+
banner.remove();
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// Disable interactive elements
|
|
125
|
+
sendBtn.disabled = true;
|
|
126
|
+
promptInput.disabled = true;
|
|
127
|
+
promptInput.placeholder = "Connect to CLI to send messages...";
|
|
128
|
+
|
|
129
|
+
// Add a message to the chat
|
|
130
|
+
addMessage(
|
|
131
|
+
"⚠️ WebSocket connection failed. This interface is running on a static hosting platform " +
|
|
132
|
+
"that doesn't support WebSocket connections. Please run 'super-agent --web' locally " +
|
|
133
|
+
"and connect to http://localhost:3000 for full functionality.",
|
|
134
|
+
"error",
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Update status indicator
|
|
139
|
+
function updateStatus(text, className = "") {
|
|
140
|
+
statusEl.textContent = text;
|
|
141
|
+
statusEl.className = `status ${className}`;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Show update banner
|
|
145
|
+
function showUpdateBanner(currentVersion, latestVersion) {
|
|
146
|
+
const banner = document.createElement("div");
|
|
147
|
+
banner.className = "update-banner";
|
|
148
|
+
|
|
149
|
+
const span = document.createElement("span");
|
|
150
|
+
span.textContent = `📦 Update available: ${currentVersion} → ${latestVersion}`;
|
|
151
|
+
|
|
152
|
+
const button = document.createElement("button");
|
|
153
|
+
button.textContent = "✕";
|
|
154
|
+
button.onclick = () => banner.remove();
|
|
155
|
+
|
|
156
|
+
banner.appendChild(span);
|
|
157
|
+
banner.appendChild(button);
|
|
158
|
+
document.body.insertBefore(banner, document.body.firstChild);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Request file tree
|
|
162
|
+
function requestFileTree() {
|
|
163
|
+
if (isConnected) {
|
|
164
|
+
ws.send(JSON.stringify({ type: "get_file_tree" }));
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Request sessions list
|
|
169
|
+
function requestSessions() {
|
|
170
|
+
if (isConnected) {
|
|
171
|
+
ws.send(JSON.stringify({ type: "list_sessions" }));
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Switch session
|
|
176
|
+
function switchSession(sessionId) {
|
|
177
|
+
if (isConnected) {
|
|
178
|
+
ws.send(JSON.stringify({ type: "switch_session", sessionId }));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// View file
|
|
183
|
+
function viewFile(filePath) {
|
|
184
|
+
if (isConnected) {
|
|
185
|
+
ws.send(JSON.stringify({ type: "get_file_content", path: filePath }));
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Handle incoming messages
|
|
190
|
+
function handleMessage(data) {
|
|
191
|
+
switch (data.type) {
|
|
192
|
+
case "update_available":
|
|
193
|
+
showUpdateBanner(data.currentVersion, data.latestVersion);
|
|
194
|
+
break;
|
|
195
|
+
case "file_tree":
|
|
196
|
+
renderFileTree(data.tree);
|
|
197
|
+
break;
|
|
198
|
+
case "file_content":
|
|
199
|
+
showFilePreview(data.path, data.content);
|
|
200
|
+
break;
|
|
201
|
+
case "sessions_list":
|
|
202
|
+
renderSessions(data.sessions);
|
|
203
|
+
break;
|
|
204
|
+
case "session_switched":
|
|
205
|
+
handleSessionSwitch(data.session);
|
|
206
|
+
break;
|
|
207
|
+
case "user_message":
|
|
208
|
+
addMessage(data.content, "user");
|
|
209
|
+
break;
|
|
210
|
+
case "assistant_message":
|
|
211
|
+
addMessage(data.content, "assistant");
|
|
212
|
+
break;
|
|
213
|
+
case "tool_call":
|
|
214
|
+
addMessage(`🔧 ${data.tool}: ${data.content}`, "tool");
|
|
215
|
+
break;
|
|
216
|
+
case "tool_result":
|
|
217
|
+
addMessage(`✅ ${data.tool}: ${data.content}`, "tool");
|
|
218
|
+
break;
|
|
219
|
+
case "error":
|
|
220
|
+
addMessage(`❌ Error: ${data.content}`, "error");
|
|
221
|
+
break;
|
|
222
|
+
case "done":
|
|
223
|
+
sendBtn.disabled = false;
|
|
224
|
+
promptInput.disabled = false;
|
|
225
|
+
updateStatus("Connected", "connected");
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Render file tree
|
|
231
|
+
function renderFileTree(tree) {
|
|
232
|
+
if (!tree || tree.length === 0) {
|
|
233
|
+
fileTreeEl.innerHTML = '<p class="empty-state">No files indexed yet</p>';
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const directories = tree.filter(f => f.isDirectory);
|
|
238
|
+
const files = tree.filter(f => !f.isDirectory);
|
|
239
|
+
|
|
240
|
+
let html = "";
|
|
241
|
+
|
|
242
|
+
// Show directories first
|
|
243
|
+
directories.slice(0, 50).forEach(dir => {
|
|
244
|
+
const safeName = escapeHtml(dir.name);
|
|
245
|
+
html += `
|
|
246
|
+
<div class="file-item directory">
|
|
247
|
+
📁 ${safeName}
|
|
248
|
+
</div>
|
|
249
|
+
`;
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
// Then files
|
|
253
|
+
files.slice(0, 100).forEach(file => {
|
|
254
|
+
const safeName = escapeHtml(file.name);
|
|
255
|
+
const safePath = escapeHtml(file.path);
|
|
256
|
+
html += `
|
|
257
|
+
<div class="file-item" onclick="viewFile('${safePath}')">
|
|
258
|
+
📄 ${safeName}
|
|
259
|
+
</div>
|
|
260
|
+
`;
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
fileTreeEl.innerHTML = html;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Render sessions
|
|
267
|
+
function renderSessions(sessions) {
|
|
268
|
+
if (!sessions || sessions.length === 0) {
|
|
269
|
+
sessionsListEl.innerHTML = '<p class="empty-state">No saved sessions</p>';
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
let html = "";
|
|
274
|
+
sessions.forEach(session => {
|
|
275
|
+
const date = new Date(session.lastAccessed).toLocaleDateString();
|
|
276
|
+
const safeName = escapeHtml(session.name);
|
|
277
|
+
const safeId = escapeHtml(session.id);
|
|
278
|
+
const safeCount = escapeHtml(String(session.messageCount || 0));
|
|
279
|
+
const safeDate = escapeHtml(date);
|
|
280
|
+
|
|
281
|
+
html += `
|
|
282
|
+
<div class="session-item" onclick="switchSession('${safeId}')">
|
|
283
|
+
<div class="session-name">${safeName}</div>
|
|
284
|
+
<div class="session-meta">${safeCount} messages · ${safeDate}</div>
|
|
285
|
+
</div>
|
|
286
|
+
`;
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
sessionsListEl.innerHTML = html;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Handle session switch
|
|
293
|
+
function handleSessionSwitch(session) {
|
|
294
|
+
// Clear current messages
|
|
295
|
+
messagesContainer.innerHTML = "";
|
|
296
|
+
|
|
297
|
+
// Load session messages
|
|
298
|
+
session.messages.forEach(msg => {
|
|
299
|
+
addMessage(msg.content, msg.role);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
updateStatus(`Session: ${session.name}`, "connected");
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Show file preview
|
|
306
|
+
function showFilePreview(path, content) {
|
|
307
|
+
addMessage(`📄 ${path}:\n\`\`\`\n${content}\n\`\`\``, "assistant");
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Add message to chat
|
|
311
|
+
function addMessage(content, type) {
|
|
312
|
+
const messageEl = document.createElement("div");
|
|
313
|
+
messageEl.className = `message ${type}`;
|
|
314
|
+
messageEl.textContent = content;
|
|
315
|
+
messagesContainer.appendChild(messageEl);
|
|
316
|
+
messagesContainer.scrollTop = messagesContainer.scrollHeight;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Slash command autocomplete
|
|
320
|
+
function handleAutocomplete(input) {
|
|
321
|
+
const value = input.trim();
|
|
322
|
+
|
|
323
|
+
if (!value.startsWith("/")) {
|
|
324
|
+
autocompleteEl.classList.add("hidden");
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const query = value.toLowerCase();
|
|
329
|
+
const matches = SLASH_COMMANDS.filter(cmd =>
|
|
330
|
+
cmd.cmd.toLowerCase().startsWith(query),
|
|
331
|
+
);
|
|
332
|
+
|
|
333
|
+
if (matches.length === 0) {
|
|
334
|
+
autocompleteEl.classList.add("hidden");
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
let html = "";
|
|
339
|
+
matches.forEach((cmd, index) => {
|
|
340
|
+
const safeCmd = escapeHtml(cmd.cmd);
|
|
341
|
+
const safeDesc = escapeHtml(cmd.desc);
|
|
342
|
+
html += `
|
|
343
|
+
<div class="autocomplete-item" data-cmd="${safeCmd}" data-index="${index}">
|
|
344
|
+
<strong>${safeCmd}</strong> - ${safeDesc}
|
|
345
|
+
</div>
|
|
346
|
+
`;
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
autocompleteEl.innerHTML = html;
|
|
350
|
+
autocompleteEl.classList.remove("hidden");
|
|
351
|
+
|
|
352
|
+
// Add click handlers
|
|
353
|
+
autocompleteEl.querySelectorAll(".autocomplete-item").forEach(item => {
|
|
354
|
+
item.addEventListener("click", () => {
|
|
355
|
+
promptInput.value = item.dataset.cmd + " ";
|
|
356
|
+
autocompleteEl.classList.add("hidden");
|
|
357
|
+
promptInput.focus();
|
|
358
|
+
});
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Send message
|
|
363
|
+
function sendMessage() {
|
|
364
|
+
const prompt = promptInput.value.trim();
|
|
365
|
+
if (!prompt || !isConnected) {
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
ws.send(
|
|
370
|
+
JSON.stringify({
|
|
371
|
+
type: "prompt",
|
|
372
|
+
content: prompt,
|
|
373
|
+
}),
|
|
374
|
+
);
|
|
375
|
+
|
|
376
|
+
promptInput.value = "";
|
|
377
|
+
autocompleteEl.classList.add("hidden");
|
|
378
|
+
sendBtn.disabled = true;
|
|
379
|
+
promptInput.disabled = true;
|
|
380
|
+
updateStatus("Processing...", "");
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Event listeners
|
|
384
|
+
sendBtn.addEventListener("click", sendMessage);
|
|
385
|
+
|
|
386
|
+
promptInput.addEventListener("input", e => {
|
|
387
|
+
handleAutocomplete(e.target.value);
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
promptInput.addEventListener("keydown", e => {
|
|
391
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
392
|
+
e.preventDefault();
|
|
393
|
+
|
|
394
|
+
// Check if autocomplete is visible
|
|
395
|
+
if (!autocompleteEl.classList.contains("hidden")) {
|
|
396
|
+
const firstItem = autocompleteEl.querySelector(".autocomplete-item");
|
|
397
|
+
if (firstItem) {
|
|
398
|
+
promptInput.value = firstItem.dataset.cmd + " ";
|
|
399
|
+
autocompleteEl.classList.add("hidden");
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
sendMessage();
|
|
405
|
+
} else if (e.key === "Escape") {
|
|
406
|
+
autocompleteEl.classList.add("hidden");
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
document
|
|
411
|
+
.getElementById("refresh-files")
|
|
412
|
+
.addEventListener("click", requestFileTree);
|
|
413
|
+
document
|
|
414
|
+
.getElementById("refresh-sessions")
|
|
415
|
+
.addEventListener("click", requestSessions);
|
|
416
|
+
|
|
417
|
+
// Initialize connection
|
|
418
|
+
connect();
|
|
Binary file
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Super Agent - Web Interface</title>
|
|
7
|
+
<link rel="icon" type="image/png" href="favicon.png" />
|
|
8
|
+
<link rel="apple-touch-icon" href="logo.png" />
|
|
9
|
+
<link rel="stylesheet" href="styles.css" />
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
<div class="app-layout">
|
|
13
|
+
<!-- Sidebar -->
|
|
14
|
+
<div id="sidebar" class="sidebar">
|
|
15
|
+
<div class="sidebar-header">
|
|
16
|
+
<h3>📁 Files</h3>
|
|
17
|
+
<button id="refresh-files" class="icon-btn">↻</button>
|
|
18
|
+
</div>
|
|
19
|
+
<div id="file-tree" class="file-tree"></div>
|
|
20
|
+
|
|
21
|
+
<div class="sidebar-section">
|
|
22
|
+
<h3>💼 Sessions</h3>
|
|
23
|
+
<button id="refresh-sessions" class="icon-btn">↻</button>
|
|
24
|
+
</div>
|
|
25
|
+
<div id="sessions-list" class="sessions-list"></div>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<!-- Main Content -->
|
|
29
|
+
<div class="main-content">
|
|
30
|
+
<header>
|
|
31
|
+
<div
|
|
32
|
+
style="
|
|
33
|
+
display: flex;
|
|
34
|
+
align-items: center;
|
|
35
|
+
justify-content: center;
|
|
36
|
+
gap: 20px;
|
|
37
|
+
"
|
|
38
|
+
>
|
|
39
|
+
<img
|
|
40
|
+
src="logo.png"
|
|
41
|
+
alt="Super Agent Logo"
|
|
42
|
+
style="width: 60px; height: 60px"
|
|
43
|
+
/>
|
|
44
|
+
<div>
|
|
45
|
+
<h1>🤖 Super Agent</h1>
|
|
46
|
+
<p class="subtitle">AI-Powered Terminal Assistant</p>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
</header>
|
|
50
|
+
|
|
51
|
+
<div id="chat-container">
|
|
52
|
+
<div id="messages"></div>
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
<div class="input-container">
|
|
56
|
+
<div id="autocomplete" class="autocomplete hidden"></div>
|
|
57
|
+
<textarea
|
|
58
|
+
id="prompt-input"
|
|
59
|
+
placeholder="Ask Super Agent anything... (type / for commands)"
|
|
60
|
+
rows="3"
|
|
61
|
+
></textarea>
|
|
62
|
+
<button id="send-btn">Send</button>
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
<div id="status" class="status"></div>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
<script src="app.js"></script>
|
|
70
|
+
</body>
|
|
71
|
+
</html>
|
|
Binary file
|
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
* {
|
|
2
|
+
margin: 0;
|
|
3
|
+
padding: 0;
|
|
4
|
+
box-sizing: border-box;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
body {
|
|
8
|
+
font-family:
|
|
9
|
+
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu,
|
|
10
|
+
Cantarell, sans-serif;
|
|
11
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
12
|
+
min-height: 100vh;
|
|
13
|
+
overflow: hidden;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.update-banner {
|
|
17
|
+
position: fixed;
|
|
18
|
+
top: 0;
|
|
19
|
+
left: 0;
|
|
20
|
+
right: 0;
|
|
21
|
+
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
|
22
|
+
color: white;
|
|
23
|
+
padding: 12px 20px;
|
|
24
|
+
display: flex;
|
|
25
|
+
justify-content: space-between;
|
|
26
|
+
align-items: center;
|
|
27
|
+
z-index: 1000;
|
|
28
|
+
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
|
|
29
|
+
animation: slideDown 0.3s ease;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@keyframes slideDown {
|
|
33
|
+
from {
|
|
34
|
+
transform: translateY(-100%);
|
|
35
|
+
}
|
|
36
|
+
to {
|
|
37
|
+
transform: translateY(0);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.update-banner button {
|
|
42
|
+
background: rgba(255, 255, 255, 0.2);
|
|
43
|
+
border: none;
|
|
44
|
+
color: white;
|
|
45
|
+
padding: 5px 10px;
|
|
46
|
+
border-radius: 5px;
|
|
47
|
+
cursor: pointer;
|
|
48
|
+
font-weight: bold;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.update-banner button:hover {
|
|
52
|
+
background: rgba(255, 255, 255, 0.3);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.app-layout {
|
|
56
|
+
display: flex;
|
|
57
|
+
height: 100vh;
|
|
58
|
+
padding: 20px;
|
|
59
|
+
gap: 20px;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.sidebar {
|
|
63
|
+
width: 280px;
|
|
64
|
+
background: white;
|
|
65
|
+
border-radius: 20px;
|
|
66
|
+
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
|
67
|
+
overflow: hidden;
|
|
68
|
+
display: flex;
|
|
69
|
+
flex-direction: column;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.sidebar-header {
|
|
73
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
74
|
+
color: white;
|
|
75
|
+
padding: 20px;
|
|
76
|
+
display: flex;
|
|
77
|
+
justify-content: space-between;
|
|
78
|
+
align-items: center;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.sidebar-header h3 {
|
|
82
|
+
font-size: 1.1rem;
|
|
83
|
+
margin: 0;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.sidebar-section {
|
|
87
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
88
|
+
color: white;
|
|
89
|
+
padding: 15px 20px;
|
|
90
|
+
display: flex;
|
|
91
|
+
justify-content: space-between;
|
|
92
|
+
align-items: center;
|
|
93
|
+
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.sidebar-section h3 {
|
|
97
|
+
font-size: 1rem;
|
|
98
|
+
margin: 0;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.icon-btn {
|
|
102
|
+
background: rgba(255, 255, 255, 0.2);
|
|
103
|
+
border: none;
|
|
104
|
+
color: white;
|
|
105
|
+
width: 30px;
|
|
106
|
+
height: 30px;
|
|
107
|
+
border-radius: 50%;
|
|
108
|
+
cursor: pointer;
|
|
109
|
+
font-size: 1rem;
|
|
110
|
+
display: flex;
|
|
111
|
+
align-items: center;
|
|
112
|
+
justify-content: center;
|
|
113
|
+
transition: background 0.2s;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.icon-btn:hover {
|
|
117
|
+
background: rgba(255, 255, 255, 0.3);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.file-tree,
|
|
121
|
+
.sessions-list {
|
|
122
|
+
flex: 1;
|
|
123
|
+
overflow-y: auto;
|
|
124
|
+
padding: 10px;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.file-item,
|
|
128
|
+
.session-item {
|
|
129
|
+
padding: 10px 15px;
|
|
130
|
+
border-radius: 8px;
|
|
131
|
+
margin-bottom: 5px;
|
|
132
|
+
cursor: pointer;
|
|
133
|
+
transition: background 0.2s;
|
|
134
|
+
font-size: 0.9rem;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.file-item:hover,
|
|
138
|
+
.session-item:hover {
|
|
139
|
+
background: #f0f0f0;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.file-item.directory {
|
|
143
|
+
font-weight: 600;
|
|
144
|
+
color: #667eea;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.session-item {
|
|
148
|
+
border-left: 3px solid #667eea;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.session-name {
|
|
152
|
+
font-weight: 600;
|
|
153
|
+
margin-bottom: 4px;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.session-meta {
|
|
157
|
+
font-size: 0.8rem;
|
|
158
|
+
color: #666;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.empty-state {
|
|
162
|
+
text-align: center;
|
|
163
|
+
color: #999;
|
|
164
|
+
padding: 20px;
|
|
165
|
+
font-size: 0.9rem;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.main-content {
|
|
169
|
+
flex: 1;
|
|
170
|
+
display: flex;
|
|
171
|
+
flex-direction: column;
|
|
172
|
+
background: white;
|
|
173
|
+
border-radius: 20px;
|
|
174
|
+
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
|
175
|
+
overflow: hidden;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
header {
|
|
179
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
180
|
+
color: white;
|
|
181
|
+
padding: 30px;
|
|
182
|
+
text-align: center;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
header h1 {
|
|
186
|
+
font-size: 2.5rem;
|
|
187
|
+
margin-bottom: 10px;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.subtitle {
|
|
191
|
+
opacity: 0.9;
|
|
192
|
+
font-size: 1.1rem;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
#chat-container {
|
|
196
|
+
flex: 1;
|
|
197
|
+
overflow-y: auto;
|
|
198
|
+
padding: 30px;
|
|
199
|
+
background: #f8f9fa;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
#messages {
|
|
203
|
+
display: flex;
|
|
204
|
+
flex-direction: column;
|
|
205
|
+
gap: 15px;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.message {
|
|
209
|
+
padding: 15px 20px;
|
|
210
|
+
border-radius: 15px;
|
|
211
|
+
max-width: 80%;
|
|
212
|
+
animation: slideIn 0.3s ease;
|
|
213
|
+
white-space: pre-wrap;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
@keyframes slideIn {
|
|
217
|
+
from {
|
|
218
|
+
opacity: 0;
|
|
219
|
+
transform: translateY(10px);
|
|
220
|
+
}
|
|
221
|
+
to {
|
|
222
|
+
opacity: 1;
|
|
223
|
+
transform: translateY(0);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.message.user {
|
|
228
|
+
background: #667eea;
|
|
229
|
+
color: white;
|
|
230
|
+
align-self: flex-end;
|
|
231
|
+
margin-left: auto;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.message.assistant {
|
|
235
|
+
background: white;
|
|
236
|
+
color: #333;
|
|
237
|
+
align-self: flex-start;
|
|
238
|
+
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.message.tool {
|
|
242
|
+
background: #fff3cd;
|
|
243
|
+
color: #856404;
|
|
244
|
+
align-self: flex-start;
|
|
245
|
+
font-size: 0.9rem;
|
|
246
|
+
font-family: monospace;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.message.error {
|
|
250
|
+
background: #f8d7da;
|
|
251
|
+
color: #721c24;
|
|
252
|
+
align-self: flex-start;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.input-container {
|
|
256
|
+
padding: 20px;
|
|
257
|
+
background: white;
|
|
258
|
+
border-top: 1px solid #e9ecef;
|
|
259
|
+
position: relative;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.autocomplete {
|
|
263
|
+
position: absolute;
|
|
264
|
+
bottom: 100%;
|
|
265
|
+
left: 20px;
|
|
266
|
+
right: 20px;
|
|
267
|
+
background: white;
|
|
268
|
+
border: 2px solid #667eea;
|
|
269
|
+
border-radius: 10px;
|
|
270
|
+
box-shadow: 0 -5px 20px rgba(0, 0, 0, 0.1);
|
|
271
|
+
max-height: 200px;
|
|
272
|
+
overflow-y: auto;
|
|
273
|
+
margin-bottom: 10px;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.autocomplete.hidden {
|
|
277
|
+
display: none;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.autocomplete-item {
|
|
281
|
+
padding: 12px 15px;
|
|
282
|
+
cursor: pointer;
|
|
283
|
+
transition: background 0.2s;
|
|
284
|
+
border-bottom: 1px solid #f0f0f0;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.autocomplete-item:last-child {
|
|
288
|
+
border-bottom: none;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
.autocomplete-item:hover {
|
|
292
|
+
background: #f8f9fa;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.autocomplete-item strong {
|
|
296
|
+
color: #667eea;
|
|
297
|
+
font-size: 0.95rem;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.input-container > div:not(.autocomplete) {
|
|
301
|
+
display: flex;
|
|
302
|
+
gap: 15px;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
#prompt-input {
|
|
306
|
+
flex: 1;
|
|
307
|
+
padding: 15px;
|
|
308
|
+
border: 2px solid #e9ecef;
|
|
309
|
+
border-radius: 10px;
|
|
310
|
+
font-size: 1rem;
|
|
311
|
+
font-family: inherit;
|
|
312
|
+
resize: none;
|
|
313
|
+
transition: border-color 0.3s;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
#prompt-input:focus {
|
|
317
|
+
outline: none;
|
|
318
|
+
border-color: #667eea;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
#send-btn {
|
|
322
|
+
padding: 15px 30px;
|
|
323
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
324
|
+
color: white;
|
|
325
|
+
border: none;
|
|
326
|
+
border-radius: 10px;
|
|
327
|
+
font-size: 1rem;
|
|
328
|
+
font-weight: 600;
|
|
329
|
+
cursor: pointer;
|
|
330
|
+
transition:
|
|
331
|
+
transform 0.2s,
|
|
332
|
+
box-shadow 0.2s;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
#send-btn:hover {
|
|
336
|
+
transform: translateY(-2px);
|
|
337
|
+
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
#send-btn:active {
|
|
341
|
+
transform: translateY(0);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
#send-btn:disabled {
|
|
345
|
+
opacity: 0.5;
|
|
346
|
+
cursor: not-allowed;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.status {
|
|
350
|
+
padding: 10px 20px;
|
|
351
|
+
text-align: center;
|
|
352
|
+
font-size: 0.9rem;
|
|
353
|
+
color: #6c757d;
|
|
354
|
+
background: #e9ecef;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
.status.connected {
|
|
358
|
+
background: #d4edda;
|
|
359
|
+
color: #155724;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
.status.disconnected {
|
|
363
|
+
background: #f8d7da;
|
|
364
|
+
color: #721c24;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/* Disconnected banner styles */
|
|
368
|
+
.disconnected-banner {
|
|
369
|
+
position: fixed;
|
|
370
|
+
top: 0;
|
|
371
|
+
left: 0;
|
|
372
|
+
right: 0;
|
|
373
|
+
background: linear-gradient(135deg, #fff3cd 0%, #ffeeba 100%);
|
|
374
|
+
border-bottom: 2px solid #ffc107;
|
|
375
|
+
color: #856404;
|
|
376
|
+
padding: 20px;
|
|
377
|
+
z-index: 1000;
|
|
378
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
379
|
+
animation: slideDown 0.3s ease;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
.disconnected-banner .banner-content {
|
|
383
|
+
max-width: 800px;
|
|
384
|
+
margin: 0 auto;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
.disconnected-banner strong {
|
|
388
|
+
display: block;
|
|
389
|
+
font-size: 1.2rem;
|
|
390
|
+
margin-bottom: 10px;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
.disconnected-banner p {
|
|
394
|
+
margin: 8px 0;
|
|
395
|
+
line-height: 1.5;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
.disconnected-banner ol {
|
|
399
|
+
margin: 10px 0;
|
|
400
|
+
padding-left: 25px;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.disconnected-banner li {
|
|
404
|
+
margin: 8px 0;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
.disconnected-banner code {
|
|
408
|
+
background: rgba(0, 0, 0, 0.1);
|
|
409
|
+
padding: 3px 8px;
|
|
410
|
+
border-radius: 4px;
|
|
411
|
+
font-family: monospace;
|
|
412
|
+
font-size: 0.95rem;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
.disconnected-banner a {
|
|
416
|
+
color: #667eea;
|
|
417
|
+
font-weight: 600;
|
|
418
|
+
text-decoration: none;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
.disconnected-banner a:hover {
|
|
422
|
+
text-decoration: underline;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
.disconnected-banner .note {
|
|
426
|
+
font-size: 0.9rem;
|
|
427
|
+
opacity: 0.8;
|
|
428
|
+
margin-top: 12px;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
.disconnected-banner .dismiss-btn {
|
|
432
|
+
float: right;
|
|
433
|
+
padding: 6px 12px;
|
|
434
|
+
background: rgba(0, 0, 0, 0.1);
|
|
435
|
+
border: 1px solid rgba(0, 0, 0, 0.2);
|
|
436
|
+
border-radius: 6px;
|
|
437
|
+
cursor: pointer;
|
|
438
|
+
font-weight: 500;
|
|
439
|
+
transition: background 0.2s;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
.disconnected-banner .dismiss-btn:hover {
|
|
443
|
+
background: rgba(0, 0, 0, 0.2);
|
|
444
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@involvex/super-agent-cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.82",
|
|
4
4
|
"description": "An open-source AI agent that brings the power of Super Agent directly into your terminal.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
"main": "dist/index.js",
|
|
30
30
|
"bin": {
|
|
31
|
-
"super-agent": "
|
|
31
|
+
"super-agent": "super-agent.js"
|
|
32
32
|
},
|
|
33
33
|
"workspaces": [
|
|
34
34
|
"@plugins/templates/*",
|
|
@@ -37,13 +37,14 @@
|
|
|
37
37
|
],
|
|
38
38
|
"scripts": {
|
|
39
39
|
"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",
|
|
40
|
+
"build": "bun build src/index.ts --outdir ./dist --target node --packages external --format esm && bun run copy-bin && bun run build:web",
|
|
41
41
|
"build:bun": "bun build src/index.ts --outdir ./dist --target node --packages external --format esm",
|
|
42
42
|
"build:plugins": "bun run -F @involvex/super-agent\\* build",
|
|
43
43
|
"build:vscode": "bun run -F super-agent-vscode build",
|
|
44
44
|
"build:web": "bun run scripts/build-web.ts",
|
|
45
45
|
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0",
|
|
46
46
|
"compile": "bun run prebuild && bun build --compile src/index.ts --outfile ./dist/super-agent-cli.exe --config bunfig.toml",
|
|
47
|
+
"copy-bin": "cp super-agent.js dist/super-agent.js",
|
|
47
48
|
"dev": "bun run --watch src/index.ts",
|
|
48
49
|
"dev:node": "tsx src/index.ts",
|
|
49
50
|
"format": "prettier --write .",
|
|
@@ -52,8 +53,8 @@
|
|
|
52
53
|
"lint": "eslint . --ext .js,.jsx,.ts,.tsx --ignore-pattern dist",
|
|
53
54
|
"lint:fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix --ignore-pattern dist",
|
|
54
55
|
"package:vscode": "bun run -F super-agent-vscode package",
|
|
55
|
-
"start": "
|
|
56
|
-
"start:
|
|
56
|
+
"start": "bun run dist/index.js",
|
|
57
|
+
"start:node": "node dist/index.js",
|
|
57
58
|
"test": "vitest run",
|
|
58
59
|
"test:coverage": "vitest run --coverage",
|
|
59
60
|
"test:integration": "vitest run src/tests/integration",
|
package/super-agent.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
// Super Agent CLI wrapper script
|
|
3
|
+
// This ensures the bundled code runs with bun for proper module resolution
|
|
4
|
+
|
|
5
|
+
import { dirname, join } from "path";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = dirname(__filename);
|
|
10
|
+
|
|
11
|
+
// Import and run the bundled CLI
|
|
12
|
+
import(join(__dirname, "dist", "index.js"));
|
|
@@ -24,4 +24,35 @@ for (const file of assetsToCopy) {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
// Copy ws dependency to out/node_modules for packaging
|
|
28
|
+
const wsSrc = path.join(__dirname, "node_modules", "ws");
|
|
29
|
+
const wsDest = path.join(outDir, "node_modules", "ws");
|
|
30
|
+
|
|
31
|
+
if (fs.existsSync(wsSrc)) {
|
|
32
|
+
// Copy recursively
|
|
33
|
+
copyDirectory(wsSrc, wsDest);
|
|
34
|
+
console.log("Copied ws to out/node_modules/");
|
|
35
|
+
} else {
|
|
36
|
+
console.warn("ws not found in node_modules");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function copyDirectory(src, dest) {
|
|
40
|
+
if (!fs.existsSync(dest)) {
|
|
41
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
45
|
+
|
|
46
|
+
for (const entry of entries) {
|
|
47
|
+
const srcPath = path.join(src, entry.name);
|
|
48
|
+
const destPath = path.join(dest, entry.name);
|
|
49
|
+
|
|
50
|
+
if (entry.isDirectory()) {
|
|
51
|
+
copyDirectory(srcPath, destPath);
|
|
52
|
+
} else {
|
|
53
|
+
fs.copyFileSync(srcPath, destPath);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
27
58
|
// Note: icon.png is already in the extension root, no need to copy
|