Skip to content

Commit 33cba92

Browse files
idoubiclaude
andcommitted
feat: /branch /pr /stash /usage, categorized /help, 37 commands total
- /branch: create, switch, list branches via agent - /pr: create pull request via gh - /stash: save, pop, list stashes - /usage: detailed API usage with per-model breakdown - /help: reorganized into 5 categories (Core, Git, Tools, Session, Config) - Total: 37 slash commands Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 87b5ec7 commit 33cba92

2 files changed

Lines changed: 175 additions & 19 deletions

File tree

internal/slash/commands.go

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -885,6 +885,118 @@ func (h *Handler) retryCmd(args []string) Result {
885885
return Result{Message: "No previous user message to retry."}
886886
}
887887

888+
// ─── /branch ──────────────────────────────────────
889+
890+
func (h *Handler) branchCmd(args []string) Result {
891+
if len(args) == 0 {
892+
return Result{
893+
SkillPrompt: "Show the current git branch and list recent branches. For each branch, show its last commit.",
894+
}
895+
}
896+
action := args[0]
897+
switch action {
898+
case "new", "create":
899+
if len(args) < 2 {
900+
return Result{Message: "Usage: /branch new <name>"}
901+
}
902+
return Result{
903+
SkillPrompt: fmt.Sprintf("Create a new git branch named %q from the current branch and switch to it.", args[1]),
904+
}
905+
case "switch", "checkout":
906+
if len(args) < 2 {
907+
return Result{Message: "Usage: /branch switch <name>"}
908+
}
909+
return Result{
910+
SkillPrompt: fmt.Sprintf("Switch to git branch %q.", args[1]),
911+
}
912+
default:
913+
return Result{
914+
SkillPrompt: fmt.Sprintf("Git branch operation: %s", strings.Join(args, " ")),
915+
}
916+
}
917+
}
918+
919+
// ─── /pr ──────────────────────────────────────────
920+
921+
func (h *Handler) prCmd(args []string) Result {
922+
desc := strings.Join(args, " ")
923+
prompt := "Create a pull request for the current branch."
924+
if desc != "" {
925+
prompt += fmt.Sprintf("\n\nDescription: %s", desc)
926+
}
927+
prompt += "\n\nSteps:\n1. Check current branch and diff against main\n2. Push the branch if needed\n3. Create the PR with a good title and description using `gh pr create`"
928+
return Result{SkillPrompt: prompt}
929+
}
930+
931+
// ─── /stash ───────────────────────────────────────
932+
933+
func (h *Handler) stashCmd(args []string) Result {
934+
if len(args) == 0 {
935+
return Result{
936+
SkillPrompt: "Show the current git stash list. If there are stashed changes, show what each stash contains.",
937+
}
938+
}
939+
switch args[0] {
940+
case "save", "push":
941+
msg := strings.Join(args[1:], " ")
942+
if msg == "" {
943+
msg = "WIP"
944+
}
945+
return Result{
946+
SkillPrompt: fmt.Sprintf("Stash current changes with message: %q", msg),
947+
}
948+
case "pop", "apply":
949+
return Result{
950+
SkillPrompt: "Apply the most recent git stash (pop).",
951+
}
952+
default:
953+
return Result{
954+
SkillPrompt: fmt.Sprintf("Git stash operation: %s", strings.Join(args, " ")),
955+
}
956+
}
957+
}
958+
959+
// ─── /usage ───────────────────────────────────────
960+
961+
func (h *Handler) usageCmd(args []string) Result {
962+
a := h.app.GetAgent()
963+
if a == nil {
964+
return Result{Message: "No active session."}
965+
}
966+
967+
var b strings.Builder
968+
b.WriteString("API usage:\n\n")
969+
970+
tracker := a.CostTracker()
971+
if tracker != nil {
972+
b.WriteString(fmt.Sprintf(" Total cost: %s\n", tracker.FormatCost()))
973+
in, out := tracker.TotalTokens()
974+
b.WriteString(fmt.Sprintf(" Input tokens: %d\n", in))
975+
b.WriteString(fmt.Sprintf(" Output tokens: %d\n", out))
976+
b.WriteString(fmt.Sprintf(" Total tokens: %d\n", in+out))
977+
978+
// Per-model breakdown
979+
allUsage := tracker.AllModelUsage()
980+
if len(allUsage) > 0 {
981+
b.WriteString("\n By model:\n")
982+
for model, usage := range allUsage {
983+
b.WriteString(fmt.Sprintf(" %s: $%.4f (%d in / %d out)\n",
984+
model, usage.CostUSD, usage.InputTokens, usage.OutputTokens))
985+
}
986+
}
987+
988+
stats := tracker.Stats()
989+
if dur, ok := stats["totalAPIDuration"]; ok {
990+
b.WriteString(fmt.Sprintf("\n API time: %v\n", dur))
991+
}
992+
if dur, ok := stats["totalToolDuration"]; ok {
993+
b.WriteString(fmt.Sprintf(" Tool time: %v\n", dur))
994+
}
995+
}
996+
997+
return Result{Message: b.String()}
998+
}
999+
8881000
// ─── helpers ──────────────────────────────────────
8891001

8901002
func min(a, b int) int {

internal/slash/slash.go

Lines changed: 63 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ func AllCommands() []CommandDef {
8989
{Name: "/copy", Description: "Copy last response to clipboard"},
9090
{Name: "/stats", Description: "Detailed session statistics"},
9191
{Name: "/retry", Description: "Retry last message"},
92+
{Name: "/usage", Description: "Detailed API usage breakdown"},
93+
// More Git
94+
{Name: "/branch", Description: "Git branch management", HasArgs: true},
95+
{Name: "/pr", Description: "Create pull request", HasArgs: true},
96+
{Name: "/stash", Description: "Git stash management", HasArgs: true},
9297
}
9398
}
9499

@@ -208,6 +213,14 @@ func (h *Handler) Handle(input string) Result {
208213
return h.statsCmd(args)
209214
case "/retry":
210215
return h.retryCmd(args)
216+
case "/usage":
217+
return h.usageCmd(args)
218+
case "/branch":
219+
return h.branchCmd(args)
220+
case "/pr":
221+
return h.prCmd(args)
222+
case "/stash":
223+
return h.stashCmd(args)
211224
default:
212225
// Try skill invocation
213226
if result, ok := h.HandleSkillInvocation(cmd, args); ok {
@@ -219,25 +232,56 @@ func (h *Handler) Handle(input string) Result {
219232

220233
func (h *Handler) help() Result {
221234
var b strings.Builder
222-
b.WriteString("Available commands:\n")
223-
for _, cmd := range AllCommands() {
224-
aliases := ""
225-
if len(cmd.Aliases) > 0 {
226-
aliases = " (" + strings.Join(cmd.Aliases, ", ") + ")"
227-
}
228-
b.WriteString(fmt.Sprintf(" %-16s %s%s\n", cmd.Name, cmd.Description, aliases))
229-
}
230-
b.WriteString("\nKeyboard shortcuts:\n")
231-
b.WriteString(" Enter Send message\n")
232-
b.WriteString(" Shift+Enter New line\n")
233-
b.WriteString(" Ctrl+C Cancel query / Exit\n")
234-
b.WriteString(" Ctrl+D Exit (when input empty)\n")
235-
b.WriteString(" Ctrl+L Clear conversation\n")
236-
b.WriteString(" Ctrl+O Toggle expand tool output\n")
237-
b.WriteString(" Up/Down Input history / Scroll\n")
238-
b.WriteString(" PgUp/PgDown Scroll messages\n")
239-
b.WriteString(" Esc Clear input\n")
240-
b.WriteString(" ! <cmd> Run shell command\n")
235+
236+
b.WriteString("Core:\n")
237+
b.WriteString(" /help Show this help\n")
238+
b.WriteString(" /clear Clear conversation\n")
239+
b.WriteString(" /compact Compact with optional instructions\n")
240+
b.WriteString(" /model [name] Show or change model\n")
241+
b.WriteString(" /fast Toggle faster model\n")
242+
b.WriteString(" /plan [task] Toggle plan mode / plan a task\n")
243+
b.WriteString(" /quit Exit\n")
244+
245+
b.WriteString("\nGit & Code:\n")
246+
b.WriteString(" /commit [msg] Create git commit\n")
247+
b.WriteString(" /review Code review\n")
248+
b.WriteString(" /diff Show git diff summary\n")
249+
b.WriteString(" /branch Branch management\n")
250+
b.WriteString(" /pr [desc] Create pull request\n")
251+
b.WriteString(" /stash Stash management\n")
252+
b.WriteString(" /bug <desc> Investigate a bug\n")
253+
b.WriteString(" /test Run tests\n")
254+
255+
b.WriteString("\nTools & Context:\n")
256+
b.WriteString(" /mcp Manage MCP servers\n")
257+
b.WriteString(" /skills List skills\n")
258+
b.WriteString(" /plugin List plugins\n")
259+
b.WriteString(" /hooks Show hooks\n")
260+
b.WriteString(" /context Show context sources\n")
261+
b.WriteString(" /init Initialize project\n")
262+
263+
b.WriteString("\nSession:\n")
264+
b.WriteString(" /cost Cost and token usage\n")
265+
b.WriteString(" /usage Detailed API usage\n")
266+
b.WriteString(" /stats Session statistics\n")
267+
b.WriteString(" /session Session details\n")
268+
b.WriteString(" /files Files accessed\n")
269+
b.WriteString(" /resume Recent sessions\n")
270+
b.WriteString(" /export Export conversation\n")
271+
b.WriteString(" /copy Copy last response\n")
272+
b.WriteString(" /retry Retry last message\n")
273+
274+
b.WriteString("\nConfig:\n")
275+
b.WriteString(" /config Show configuration\n")
276+
b.WriteString(" /permissions Permission mode\n")
277+
b.WriteString(" /login <key> Set API key\n")
278+
b.WriteString(" /logout Remove API key\n")
279+
b.WriteString(" /doctor Environment check\n")
280+
b.WriteString(" /theme Color theme\n")
281+
282+
b.WriteString("\nKeys: Enter send · Shift+Enter newline · Ctrl+C cancel · Ctrl+L clear")
283+
b.WriteString("\n Ctrl+O expand · PgUp/Down scroll · !cmd shell · Tab complete")
284+
241285
return Result{Message: b.String()}
242286
}
243287

0 commit comments

Comments
 (0)