diff --git a/apps/supercode-cli/server/package.json b/apps/supercode-cli/server/package.json index dde9ea7..1457307 100644 --- a/apps/supercode-cli/server/package.json +++ b/apps/supercode-cli/server/package.json @@ -1,6 +1,6 @@ { "name": "supercode-cli", - "version": "0.1.64", + "version": "0.1.65", "description": "AI-powered coding agent CLI", "main": "dist/main.js", "bin": { diff --git a/apps/supercode-cli/server/public/supercode-mercury.svg b/apps/supercode-cli/server/public/supercode-mercury.svg new file mode 100644 index 0000000..8e46a92 --- /dev/null +++ b/apps/supercode-cli/server/public/supercode-mercury.svg @@ -0,0 +1,4 @@ + + +Mercury API (Read-Only)Balance QueriesTransaction HistoryVendor ListingMergeDev GatewayConnector GovernancePolicy EnforcementPer-Call Audit LoggingRate Limiting & ScopedAccessComposio GatewayOAuth Flow & SessionManagementToken Storage &RefreshConnected AccountManagementMercury API ProxySupercode LayerSupercode UserBetter-Auth / GitHubOAuthPermission ManagerMCP Manager(McpManager)Both Must Authorize —Parallel Gate CheckAll tools are read-only.Enforced at OAuthscope (Composio) + policylayer (MergeDev).proxies requestspolicy + audit \ No newline at end of file diff --git a/apps/supercode-cli/server/src/cli/ai/chat/chat.ts b/apps/supercode-cli/server/src/cli/ai/chat/chat.ts index 0add274..d6b7c61 100644 --- a/apps/supercode-cli/server/src/cli/ai/chat/chat.ts +++ b/apps/supercode-cli/server/src/cli/ai/chat/chat.ts @@ -913,6 +913,25 @@ let ddListLines = 0 const atPicker = new AtPicker() const ddTracker = new DragDropTracker() +function renderChatHeader(modelName: string, mode: string): void { + const modeLabel = mode === "agent" ? "agent" : "chat" + const subtitle = modeLabel === "chat" ? `ai chat · ${modelName}` : `agent · ${modelName}` + const w = process.stdout.columns ?? 80 + const title = chalk.hex(theme.green).bold("SUPERCODE") + const tagline = chalk.hex(theme.greenDim)(`${subtitle}`) + const headerText = `${title} ${tagline}` + const headerLen = stripAnsi(headerText).length + console.log(" ".repeat(Math.max(0, Math.floor((w - headerLen) / 2))) + headerText) + console.log() + console.log( + statusBar({ + left: ["supercode", modeLabel, modelName], + right: ["ready", "type to chat"], + }), + ) + console.log() +} + // Filter the slash-command list by what the user has typed. Empty query // returns everything. Match is case-insensitive substring on the command // name (e.g. "/co" → /connect, /compact, /context). @@ -1904,6 +1923,62 @@ export async function chatLoop( process.stdout.write( `\r\n ${chalk.hex(theme.green)("◆")} verbose mode ${verboseMode ? chalk.hex(theme.green)("on") : chalk.hex(theme.greenDim)("off")} — ${verboseMode ? "per-tool debug lines enabled" : "clean UI"}\r\n\n`, ) + } else if (result?.type === "clear") { + messageCount = 0 + sessionTokens = 0 + sessionStartTime = Date.now() + lastUsage = undefined + lastElapsed = undefined + footer.unmount() + console.clear() + console.log() + renderChatHeader(provider.modelName, conversation.mode) + if (workspaceInfo) { + console.log(renderWorkspaceBanner(workspaceInfo)) + console.log() + } + console.log( + ` ${chalk.hex(theme.greenDim)("hint")} ${chalk.hex(theme.green)("·")} ${chalk.hex(theme.greenGlow)("/model")} to switch ${chalk.hex(theme.greenDim)("·")} ${chalk.hex(theme.greenGlow)("Ctrl+V")} voice ${chalk.hex(theme.greenDim)("·")} ${chalk.hex(theme.greenGlow)("/help")} for commands ${chalk.hex(theme.greenDim)("·")} ${chalk.hex(theme.greenGlow)("Tab")} to cycle mode`, + ) + console.log() + footer.mount() + footer.setTokens(0) + process.stdout.write( + ` ${chalk.hex(theme.green)("◆")} ${chalk.hex(theme.green)("session content cleared")}\r\n`, + ) + } else if (result?.type === "new_conversation") { + try { + const newConversation = await getOrCreateConversation(null, conversation.mode) + conversation.id = newConversation.id + conversation.title = newConversation.title ?? null + } catch { + process.stdout.write( + `\r\n ${chalk.hex(theme.amber)("◆")} ${chalk.hex(theme.amber)("could not create new conversation, continuing with current")}\r\n`, + ) + continue + } + messageCount = 0 + sessionTokens = 0 + sessionStartTime = Date.now() + lastUsage = undefined + lastElapsed = undefined + footer.unmount() + console.clear() + console.log() + renderChatHeader(provider.modelName, conversation.mode) + if (workspaceInfo) { + console.log(renderWorkspaceBanner(workspaceInfo)) + console.log() + } + console.log( + ` ${chalk.hex(theme.greenDim)("hint")} ${chalk.hex(theme.green)("·")} ${chalk.hex(theme.greenGlow)("/model")} to switch ${chalk.hex(theme.greenDim)("·")} ${chalk.hex(theme.greenGlow)("Ctrl+V")} voice ${chalk.hex(theme.greenDim)("·")} ${chalk.hex(theme.greenGlow)("/help")} for commands ${chalk.hex(theme.greenDim)("·")} ${chalk.hex(theme.greenGlow)("Tab")} to cycle mode`, + ) + console.log() + footer.mount() + footer.setTokens(0) + process.stdout.write( + ` ${chalk.hex(theme.green)("◆")} ${chalk.hex(theme.green)("started new conversation")}\r\n`, + ) } else if (result?.type === "unknown") { process.stdout.write(`\r\n ${chalk.hex(theme.red)("◆")} unknown slash command: ${trimmed.split(" ")[0]}\r\n\n`) } else if (result?.type === "message" && result.message) { diff --git a/apps/supercode-cli/server/src/cli/commands/slashCommands/index.ts b/apps/supercode-cli/server/src/cli/commands/slashCommands/index.ts index 5ad53bb..ddc5d71 100644 --- a/apps/supercode-cli/server/src/cli/commands/slashCommands/index.ts +++ b/apps/supercode-cli/server/src/cli/commands/slashCommands/index.ts @@ -9,11 +9,13 @@ import { theme, heavyDivider } from "src/cli/utils/tui.ts" import type { ModelProvider } from "src/cli/ai/provider.ts" export interface SlashCommandResult { - type: "model_change" | "help" | "unknown" | "exit" | "connect" | "context" | "compact" | "plan" | "scratch" | "voice" | "verbose" | "message" + type: "model_change" | "help" | "unknown" | "exit" | "connect" | "context" | "compact" | "plan" | "scratch" | "voice" | "verbose" | "message" | "clear" | "new_conversation" provider?: ModelProvider model?: string label?: string message?: string + conversationId?: string + conversationMode?: string } export const COMMANDS = [ @@ -32,6 +34,8 @@ export const COMMANDS = [ { cmd: "/parse", desc: "Parse a file (PDF, DOC, etc.) via Firecrawl" }, { cmd: "/usage", desc: "Show daily token usage and budget for Opus 4.8" }, { cmd: "/token-limit", desc: "Show token limits and usage per model per day" }, + { cmd: "/clear", desc: "Clear current session messages" }, + { cmd: "/new", desc: "Start a new conversation" }, { cmd: "/help", desc: "Show available commands and models" }, { cmd: "/exit", desc: "End the session" }, { cmd: "/mcp", desc: "Manage MCP connections (add, connect, toggle, remove)" }, @@ -105,6 +109,12 @@ const handlers: Record Promise> = interact: async (args) => ({ type: "message", message: chatify("interact", args) }), crawl: async (args) => ({ type: "message", message: chatify("crawl", args) }), parse: async (args) => ({ type: "message", message: chatify("parse", args) }), + clear: async () => { + return { type: "clear" as const } + }, + new: async () => { + return { type: "new_conversation" as const } + }, } function renderCommandList(): void {