Add command history in ragflow cli (#13538)

### What problem does this PR solve?

In ragflow cli,  use Up/Down arrows to navigate command history,

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
qinling0210
2026-03-11 19:14:18 +08:00
committed by GitHub
parent 852393c114
commit d201a81db7
4 changed files with 74 additions and 19 deletions

2
go.mod
View File

@ -40,10 +40,12 @@ require (
github.com/leodido/go-urn v1.2.4 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.3 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.1.1 // indirect
github.com/peterh/liner v1.2.2 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect

5
go.sum
View File

@ -75,6 +75,8 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.3 h1:a+kO+98RDGEfo6asOGMmpodZq4FNtnGP54yps8BzLR4=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@ -84,6 +86,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/peterh/liner v1.2.2 h1:aJ4AOodmL+JxOZZEL2u9iJf8omNRpqHc/EbrK+3mAXw=
github.com/peterh/liner v1.2.2/go.mod h1:xFwJyiKIXJZUKItq5dGHZSTBRAuG/CpeNpWLyiNRNwI=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@ -152,6 +156,7 @@ golang.org/x/exp v0.0.0-20231226003508-02704c960a9b h1:kLiC65FbiHWFAOu+lxwNPujcs
golang.org/x/exp v0.0.0-20231226003508-02704c960a9b/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=

View File

@ -17,57 +17,91 @@
package cli
import (
"bufio"
"fmt"
"os"
"strings"
"github.com/peterh/liner"
)
// HistoryFile returns the path to the history file
func HistoryFile() string {
return os.Getenv("HOME") + "/" + historyFileName
}
const historyFileName = ".ragflow_cli_history"
// CLI represents the command line interface
type CLI struct {
parser *Parser
client *RAGFlowClient
prompt string
running bool
line *liner.State
}
// NewCLI creates a new CLI instance
func NewCLI() (*CLI, error) {
// Create liner first
line := liner.NewLiner()
// Create client with password prompt using liner
client := NewRAGFlowClient("user") // Default to user mode
client.PasswordPrompt = line.PasswordPrompt
return &CLI{
prompt: "RAGFlow> ",
client: NewRAGFlowClient("user"), // Default to user mode
client: client,
line: line,
}, nil
}
// Run starts the interactive CLI
func (c *CLI) Run() error {
c.running = true
scanner := bufio.NewScanner(os.Stdin)
// Load history from file
histFile := HistoryFile()
if f, err := os.Open(histFile); err == nil {
c.line.ReadHistory(f)
f.Close()
}
// Save history on exit
defer func() {
if f, err := os.Create(histFile); err == nil {
c.line.WriteHistory(f)
f.Close()
}
c.line.Close()
}()
fmt.Println("Welcome to RAGFlow CLI")
fmt.Println("Type \\? for help, \\q to quit")
fmt.Println()
for c.running {
fmt.Print(c.prompt)
if !scanner.Scan() {
break
input, err := c.line.Prompt(c.prompt)
if err != nil {
fmt.Printf("Error reading input: %v\n", err)
continue
}
input := scanner.Text()
input = strings.TrimSpace(input)
if input == "" {
continue
}
// Add to history (skip meta commands)
if !strings.HasPrefix(input, "\\") {
c.line.AppendHistory(input)
}
if err := c.execute(input); err != nil {
fmt.Printf("Error: %v\n", err)
}
}
return scanner.Err()
return nil
}
func (c *CLI) execute(input string) error {
@ -125,9 +159,9 @@ SQL Commands:
... and many more
Meta Commands:
\\? or \\h - Show this help
\\q or \\quit - Exit CLI
\\c or \\clear - Clear screen
\? or \h - Show this help
\q or \quit - Exit CLI
\c or \clear - Clear screen
For more information, see documentation.
`

View File

@ -26,10 +26,14 @@ import (
"unsafe"
)
// PasswordPromptFunc is a function type for password input
type PasswordPromptFunc func(prompt string) (string, error)
// RAGFlowClient handles API interactions with the RAGFlow server
type RAGFlowClient struct {
HTTPClient *HTTPClient
ServerType string // "admin" or "user"
HTTPClient *HTTPClient
ServerType string // "admin" or "user"
PasswordPrompt PasswordPromptFunc // Function for password input
}
// NewRAGFlowClient creates a new RAGFlow client
@ -61,10 +65,20 @@ func (c *RAGFlowClient) LoginUser(cmd *Command) error {
}
// Get password from user input (hidden)
fmt.Printf("password for %s: ", email)
password, err := readPassword()
if err != nil {
return fmt.Errorf("failed to read password: %w", err)
var password string
if c.PasswordPrompt != nil {
pwd, err := c.PasswordPrompt(fmt.Sprintf("password for %s: ", email))
if err != nil {
return fmt.Errorf("failed to read password: %w", err)
}
password = pwd
} else {
fmt.Printf("password for %s: ", email)
pwd, err := readPassword()
if err != nil {
return fmt.Errorf("failed to read password: %w", err)
}
password = pwd
}
password = strings.TrimSpace(password)