Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/supercode-cli/server/package.json
Original file line number Diff line number Diff line change
@@ -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": {
Expand Down
4 changes: 4 additions & 0 deletions apps/supercode-cli/server/public/supercode-mercury.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
75 changes: 75 additions & 0 deletions apps/supercode-cli/server/src/cli/ai/chat/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand All @@ -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)" },
Expand Down Expand Up @@ -105,6 +109,12 @@ const handlers: Record<string, (args: string) => Promise<SlashCommandResult>> =
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 {
Expand Down
Loading