@involvex/super-agent-cli 0.0.79 → 0.0.81

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/.prettierignore CHANGED
@@ -8,4 +8,6 @@ node_modules
8
8
  /*/**/node_modules/*/**
9
9
  .turbo
10
10
  /*/*/dist
11
- build
11
+ build
12
+ vscode-extension/out
13
+ vscode-extension/node_modules
Binary file
Binary file
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.79",
1734
+ version: "0.0.81",
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,20 +1759,23 @@ var require_package = __commonJS((exports, module) => {
1759
1759
  },
1760
1760
  main: "dist/index.js",
1761
1761
  bin: {
1762
- "super-agent": "dist/index.js"
1762
+ "super-agent": "super-agent.js"
1763
1763
  },
1764
1764
  workspaces: [
1765
1765
  "@plugins/templates/*",
1766
- "@plugins/examples/*"
1766
+ "@plugins/examples/*",
1767
+ "vscode-extension"
1767
1768
  ],
1768
1769
  scripts: {
1769
1770
  prebuild: "bun run format && bun run lint:fix && bun run typecheck",
1770
- 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",
1771
1772
  "build:bun": "bun build src/index.ts --outdir ./dist --target node --packages external --format esm",
1772
1773
  "build:plugins": "bun run -F @involvex/super-agent\\* build",
1774
+ "build:vscode": "bun run -F super-agent-vscode build",
1773
1775
  "build:web": "bun run scripts/build-web.ts",
1774
1776
  changelog: "conventional-changelog -p angular -i CHANGELOG.md -s -r 0",
1775
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",
1776
1779
  dev: "bun run --watch src/index.ts",
1777
1780
  "dev:node": "tsx src/index.ts",
1778
1781
  format: "prettier --write .",
@@ -1780,8 +1783,9 @@ var require_package = __commonJS((exports, module) => {
1780
1783
  "install:bun": "bun install",
1781
1784
  lint: "eslint . --ext .js,.jsx,.ts,.tsx --ignore-pattern dist",
1782
1785
  "lint:fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix --ignore-pattern dist",
1783
- start: "node dist/index.js",
1784
- "start:bun": "bun run dist/index.js",
1786
+ "package:vscode": "bun run -F super-agent-vscode package",
1787
+ start: "bun run dist/index.js",
1788
+ "start:node": "node dist/index.js",
1785
1789
  test: "vitest run",
1786
1790
  "test:coverage": "vitest run --coverage",
1787
1791
  "test:integration": "vitest run src/tests/integration",
@@ -2905,8 +2909,8 @@ init_config();
2905
2909
  init_settings_manager();
2906
2910
  import { exec as exec2 } from "child_process";
2907
2911
  import { promisify as promisify2 } from "util";
2908
- import * as fs4 from "fs-extra";
2909
2912
  import * as path4 from "path";
2913
+ import fs4 from "fs-extra";
2910
2914
  var execAsync2 = promisify2(exec2);
2911
2915
 
2912
2916
  class PluginManager {
@@ -3471,8 +3475,8 @@ async function getAllSuperAgentTools() {
3471
3475
  // src/plugins/repository-manager.ts
3472
3476
  import { exec as exec3 } from "child_process";
3473
3477
  import { promisify as promisify3 } from "util";
3474
- import * as fs5 from "fs-extra";
3475
3478
  import * as path5 from "path";
3479
+ import fs5 from "fs-extra";
3476
3480
  var execAsync3 = promisify3(exec3);
3477
3481
  var BUILTIN_REPOSITORIES = {
3478
3482
  agents: {
@@ -3962,7 +3966,7 @@ function getChatManager() {
3962
3966
  }
3963
3967
 
3964
3968
  // src/hooks/use-input-handler.ts
3965
- import * as fs11 from "fs-extra";
3969
+ import fs11 from "fs-extra";
3966
3970
  function useInputHandler({
3967
3971
  agent,
3968
3972
  chatHistory,
@@ -11708,7 +11712,6 @@ import * as fs20 from "fs-extra";
11708
11712
  import * as path20 from "path";
11709
11713
  import open from "open";
11710
11714
  import mime from "mime";
11711
- var __dirname = "/home/runner/work/super-agent-cli/super-agent-cli/src/web";
11712
11715
 
11713
11716
  class WebServer {
11714
11717
  httpServer;
@@ -11731,20 +11734,24 @@ class WebServer {
11731
11734
  }
11732
11735
  async handleHttpRequest(req, res) {
11733
11736
  const url = req.url || "/";
11734
- const requestedPath = url === "/" ? "index.html" : url;
11737
+ let requestedPath = url === "/" ? "index.html" : url.substring(1);
11735
11738
  const sanitizedPath = requestedPath.split("?")[0].split("#")[0];
11736
- const clientDir = path20.join(__dirname, "../web/client");
11737
- const absolutePath = path20.resolve(clientDir, sanitizedPath.substring(1));
11738
- if (!absolutePath.startsWith(clientDir)) {
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)) {
11739
11746
  res.writeHead(403, { "Content-Type": "text/plain" });
11740
11747
  res.end("Forbidden");
11741
11748
  return;
11742
11749
  }
11743
11750
  try {
11744
11751
  if (await fs20.pathExists(absolutePath)) {
11745
- const stat5 = await fs20.stat(absolutePath);
11752
+ const stat2 = await fs20.stat(absolutePath);
11746
11753
  let filePath = absolutePath;
11747
- if (stat5.isDirectory()) {
11754
+ if (stat2.isDirectory()) {
11748
11755
  filePath = path20.join(absolutePath, "index.html");
11749
11756
  }
11750
11757
  const content = await fs20.readFile(filePath);
@@ -12146,7 +12153,7 @@ function createIndexCommand() {
12146
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) => {
12147
12154
  try {
12148
12155
  const rootDir = path21.resolve(directory);
12149
- const outputFile2 = options.output ? path21.resolve(options.output) : path21.join(rootDir, "index.md");
12156
+ const outputFile = options.output ? path21.resolve(options.output) : path21.join(rootDir, "index.md");
12150
12157
  const maxDepth = parseInt(options.depth);
12151
12158
  console.log(chalk4.blue(`Indexing directory: ${rootDir}`));
12152
12159
  const ig = ignore().add(DEFAULT_IGNORES);
@@ -12243,8 +12250,8 @@ Date: ${new Date().toISOString()}
12243
12250
 
12244
12251
  `;
12245
12252
  }
12246
- await fs21.writeFile(outputFile2, outputContent);
12247
- console.log(chalk4.green(`✓ Index generated at: ${outputFile2}`));
12253
+ await fs21.writeFile(outputFile, outputContent);
12254
+ console.log(chalk4.green(`✓ Index generated at: ${outputFile}`));
12248
12255
  } catch (error) {
12249
12256
  console.error(chalk4.red(`Error indexing directory: ${error.message}`));
12250
12257
  process.exit(1);
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"));
@@ -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, "&amp;")
32
+ .replace(/</g, "&lt;")
33
+ .replace(/>/g, "&gt;")
34
+ .replace(/"/g, "&quot;")
35
+ .replace(/'/g, "&#039;");
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