diff --git a/cmd/picoclaw-launcher-tui/internal/ui/app.go b/cmd/picoclaw-launcher-tui/internal/ui/app.go index 9e0d5dd4a..72a622701 100644 --- a/cmd/picoclaw-launcher-tui/internal/ui/app.go +++ b/cmd/picoclaw-launcher-tui/internal/ui/app.go @@ -12,6 +12,7 @@ import ( configstore "jane/cmd/picoclaw-launcher-tui/internal/config" picoclawconfig "jane/pkg/config" + "jane/pkg/runtimepaths" ) type appState struct { @@ -204,7 +205,7 @@ func refreshMainMenu(menu *Menu, s *appState) { }, { Label: "Start Talk", - Description: "Open picoclaw agent in terminal", + Description: "Open Jane AI agent in terminal", Action: func() { s.requestStartTalk() }, @@ -359,7 +360,7 @@ func (s *appState) startTalk() { return } s.app.Suspend(func() { - cmd := exec.Command("picoclaw", "agent") + cmd := exec.Command(runtimepaths.BinaryPath(), "agent") cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr @@ -380,7 +381,7 @@ func (s *appState) startGateway() { return } _ = stopGatewayProcess() - cmd := exec.Command("picoclaw", "gateway") + cmd := exec.Command(runtimepaths.BinaryPath(), "gateway") logFile, err := os.OpenFile(s.logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o644) if err != nil { s.showMessage("Gateway failed", err.Error()) diff --git a/cmd/picoclaw-launcher-tui/internal/ui/gateway_posix.go b/cmd/picoclaw-launcher-tui/internal/ui/gateway_posix.go index 143e5558a..2d7cb06be 100644 --- a/cmd/picoclaw-launcher-tui/internal/ui/gateway_posix.go +++ b/cmd/picoclaw-launcher-tui/internal/ui/gateway_posix.go @@ -8,11 +8,11 @@ import "os/exec" var execCommand = exec.Command func isGatewayProcessRunning() bool { - cmd := execCommand("sh", "-c", "pgrep -f 'picoclaw\\s+gateway' >/dev/null 2>&1") + cmd := execCommand("sh", "-c", "pgrep -f '(jane-ai|picoclaw)\\s+gateway' >/dev/null 2>&1") return cmd.Run() == nil } func stopGatewayProcess() error { - cmd := execCommand("sh", "-c", "pkill -f 'picoclaw\\s+gateway' >/dev/null 2>&1") + cmd := execCommand("sh", "-c", "pkill -f '(jane-ai|picoclaw)\\s+gateway' >/dev/null 2>&1") return cmd.Run() } diff --git a/cmd/picoclaw-launcher-tui/internal/ui/gateway_windows.go b/cmd/picoclaw-launcher-tui/internal/ui/gateway_windows.go index 8b4c12096..6e4165d5f 100644 --- a/cmd/picoclaw-launcher-tui/internal/ui/gateway_windows.go +++ b/cmd/picoclaw-launcher-tui/internal/ui/gateway_windows.go @@ -8,11 +8,11 @@ import "os/exec" var execCommand = exec.Command func isGatewayProcessRunning() bool { - cmd := execCommand("tasklist", "/FI", "IMAGENAME eq picoclaw.exe") + cmd := execCommand("cmd", "/C", `tasklist /FI "IMAGENAME eq jane-ai.exe" | findstr /I /C:"jane-ai.exe" >NUL || tasklist /FI "IMAGENAME eq picoclaw.exe" | findstr /I /C:"picoclaw.exe" >NUL`) return cmd.Run() == nil } func stopGatewayProcess() error { - cmd := execCommand("taskkill", "/F", "/IM", "picoclaw.exe") + cmd := execCommand("cmd", "/C", `taskkill /F /IM jane-ai.exe >NUL 2>&1 || taskkill /F /IM picoclaw.exe >NUL 2>&1`) return cmd.Run() } diff --git a/cmd/picoclaw-launcher-tui/internal/ui/gateway_windows_test.go b/cmd/picoclaw-launcher-tui/internal/ui/gateway_windows_test.go index 645ae602b..ba5410d51 100644 --- a/cmd/picoclaw-launcher-tui/internal/ui/gateway_windows_test.go +++ b/cmd/picoclaw-launcher-tui/internal/ui/gateway_windows_test.go @@ -53,10 +53,10 @@ func TestIsGatewayProcessRunning(t *testing.T) { if got != tt.wantResult { t.Errorf("isGatewayProcessRunning() = %v, want %v", got, tt.wantResult) } - if gotName != "tasklist" { - t.Errorf("expected command name tasklist, got %s", gotName) + if gotName != "cmd" { + t.Errorf("expected command name cmd, got %s", gotName) } - expectedArgs := []string{"/FI", "IMAGENAME eq picoclaw.exe"} + expectedArgs := []string{"/C", `tasklist /FI "IMAGENAME eq jane-ai.exe" | findstr /I /C:"jane-ai.exe" >NUL || tasklist /FI "IMAGENAME eq picoclaw.exe" | findstr /I /C:"picoclaw.exe" >NUL`} if !reflect.DeepEqual(gotArgs, expectedArgs) { t.Errorf("expected args %v, got %v", expectedArgs, gotArgs) } @@ -106,10 +106,10 @@ func TestStopGatewayProcess(t *testing.T) { if (err != nil) != tt.wantErr { t.Errorf("stopGatewayProcess() error = %v, wantErr %v", err, tt.wantErr) } - if gotName != "taskkill" { - t.Errorf("expected command name taskkill, got %s", gotName) + if gotName != "cmd" { + t.Errorf("expected command name cmd, got %s", gotName) } - expectedArgs := []string{"/F", "/IM", "picoclaw.exe"} + expectedArgs := []string{"/C", `taskkill /F /IM jane-ai.exe >NUL 2>&1 || taskkill /F /IM picoclaw.exe >NUL 2>&1`} if !reflect.DeepEqual(gotArgs, expectedArgs) { t.Errorf("expected args %v, got %v", expectedArgs, gotArgs) } diff --git a/cmd/picoclaw/internal/auth/helpers.go b/cmd/picoclaw/internal/auth/helpers.go index d17df9931..9d7269637 100644 --- a/cmd/picoclaw/internal/auth/helpers.go +++ b/cmd/picoclaw/internal/auth/helpers.go @@ -162,7 +162,7 @@ func authLoginGoogleAntigravity() error { fmt.Println("\n✓ Google Antigravity login successful!") fmt.Println("Default model set to: gemini-flash") - fmt.Println("Try it: picoclaw agent -m \"Hello world\"") + fmt.Println("Try it: jane-ai agent -m \"Hello world\"") return nil } @@ -412,7 +412,7 @@ func authStatusCmd() error { if len(store.Credentials) == 0 { fmt.Println("No authenticated providers.") - fmt.Println("Run: picoclaw auth login --provider ") + fmt.Println("Run: jane-ai auth login --provider ") return nil } @@ -460,7 +460,7 @@ func authModelsCmd() error { cred, err := auth.GetCredential("google-antigravity") if err != nil || cred == nil { return fmt.Errorf( - "not logged in to Google Antigravity.\nrun: picoclaw auth login --provider google-antigravity", + "not logged in to Google Antigravity.\nrun: jane-ai auth login --provider google-antigravity", ) } diff --git a/cmd/picoclaw/internal/gateway/command.go b/cmd/picoclaw/internal/gateway/command.go index 130b59119..82aac7e48 100644 --- a/cmd/picoclaw/internal/gateway/command.go +++ b/cmd/picoclaw/internal/gateway/command.go @@ -16,7 +16,7 @@ func NewGatewayCommand() *cobra.Command { cmd := &cobra.Command{ Use: "gateway", Aliases: []string{"g"}, - Short: "Start picoclaw gateway", + Short: "Start the Jane AI gateway", Args: cobra.NoArgs, PreRunE: func(_ *cobra.Command, _ []string) error { if noTruncate && !debug { diff --git a/cmd/picoclaw/internal/gateway/command_test.go b/cmd/picoclaw/internal/gateway/command_test.go index 4d591ea67..0b11f9733 100644 --- a/cmd/picoclaw/internal/gateway/command_test.go +++ b/cmd/picoclaw/internal/gateway/command_test.go @@ -13,7 +13,7 @@ func TestNewGatewayCommand(t *testing.T) { require.NotNil(t, cmd) assert.Equal(t, "gateway", cmd.Use) - assert.Equal(t, "Start picoclaw gateway", cmd.Short) + assert.Equal(t, "Start the Jane AI gateway", cmd.Short) assert.Len(t, cmd.Aliases, 1) assert.True(t, cmd.HasAlias("g")) diff --git a/cmd/picoclaw/internal/migrate/command.go b/cmd/picoclaw/internal/migrate/command.go index 72d9412c6..e91bda68f 100644 --- a/cmd/picoclaw/internal/migrate/command.go +++ b/cmd/picoclaw/internal/migrate/command.go @@ -11,13 +11,13 @@ func NewMigrateCommand() *cobra.Command { cmd := &cobra.Command{ Use: "migrate", - Short: "Migrate from xxxclaw(openclaw, etc.) to picoclaw", + Short: "Migrate from xxxclaw(openclaw, etc.) to Jane AI", Args: cobra.NoArgs, - Example: ` picoclaw migrate - picoclaw migrate --from openclaw - picoclaw migrate --dry-run - picoclaw migrate --refresh - picoclaw migrate --force`, + Example: ` jane-ai migrate + jane-ai migrate --from openclaw + jane-ai migrate --dry-run + jane-ai migrate --refresh + jane-ai migrate --force`, RunE: func(cmd *cobra.Command, _ []string) error { m := migrate.NewMigrateInstance(opts) result, err := m.Run(opts) diff --git a/cmd/picoclaw/internal/migrate/command_test.go b/cmd/picoclaw/internal/migrate/command_test.go index 5110249a2..344cbe580 100644 --- a/cmd/picoclaw/internal/migrate/command_test.go +++ b/cmd/picoclaw/internal/migrate/command_test.go @@ -13,7 +13,7 @@ func TestNewMigrateCommand(t *testing.T) { require.NotNil(t, cmd) assert.Equal(t, "migrate", cmd.Use) - assert.Equal(t, "Migrate from xxxclaw(openclaw, etc.) to picoclaw", cmd.Short) + assert.Equal(t, "Migrate from xxxclaw(openclaw, etc.) to Jane AI", cmd.Short) assert.Len(t, cmd.Aliases, 0) diff --git a/cmd/picoclaw/internal/onboard/command.go b/cmd/picoclaw/internal/onboard/command.go index ec1012959..4853a377e 100644 --- a/cmd/picoclaw/internal/onboard/command.go +++ b/cmd/picoclaw/internal/onboard/command.go @@ -14,7 +14,7 @@ func NewOnboardCommand() *cobra.Command { cmd := &cobra.Command{ Use: "onboard", Aliases: []string{"o"}, - Short: "Initialize picoclaw configuration and workspace", + Short: "Initialize Jane AI configuration and workspace", Run: func(cmd *cobra.Command, args []string) { onboard() }, diff --git a/cmd/picoclaw/internal/onboard/command_test.go b/cmd/picoclaw/internal/onboard/command_test.go index bc799a079..279a128f9 100644 --- a/cmd/picoclaw/internal/onboard/command_test.go +++ b/cmd/picoclaw/internal/onboard/command_test.go @@ -13,7 +13,7 @@ func TestNewOnboardCommand(t *testing.T) { require.NotNil(t, cmd) assert.Equal(t, "onboard", cmd.Use) - assert.Equal(t, "Initialize picoclaw configuration and workspace", cmd.Short) + assert.Equal(t, "Initialize Jane AI configuration and workspace", cmd.Short) assert.Len(t, cmd.Aliases, 1) assert.True(t, cmd.HasAlias("o")) diff --git a/cmd/picoclaw/internal/onboard/helpers.go b/cmd/picoclaw/internal/onboard/helpers.go index fe03daf0c..f98939e75 100644 --- a/cmd/picoclaw/internal/onboard/helpers.go +++ b/cmd/picoclaw/internal/onboard/helpers.go @@ -33,7 +33,7 @@ func onboard() { workspace := cfg.WorkspacePath() createWorkspaceTemplates(workspace) - fmt.Printf("%s picoclaw is ready!\n", internal.Logo) + fmt.Printf("%s Jane AI is ready!\n", internal.Logo) fmt.Println("\nNext steps:") fmt.Println(" 1. Add your API key to", configPath) fmt.Println("") @@ -43,7 +43,7 @@ func onboard() { fmt.Println("") fmt.Println(" See README.md for 17+ supported providers.") fmt.Println("") - fmt.Println(" 2. Chat: picoclaw agent -m \"Hello!\"") + fmt.Println(" 2. Chat: jane-ai agent -m \"Hello!\"") } func createWorkspaceTemplates(workspace string) { diff --git a/cmd/picoclaw/internal/status/command.go b/cmd/picoclaw/internal/status/command.go index 9303ae2ec..7b4381a68 100644 --- a/cmd/picoclaw/internal/status/command.go +++ b/cmd/picoclaw/internal/status/command.go @@ -8,7 +8,7 @@ func NewStatusCommand() *cobra.Command { cmd := &cobra.Command{ Use: "status", Aliases: []string{"s"}, - Short: "Show picoclaw status", + Short: "Show Jane AI status", Run: func(cmd *cobra.Command, args []string) { statusCmd() }, diff --git a/cmd/picoclaw/internal/status/command_test.go b/cmd/picoclaw/internal/status/command_test.go index 974b4ea3d..bbe0a6038 100644 --- a/cmd/picoclaw/internal/status/command_test.go +++ b/cmd/picoclaw/internal/status/command_test.go @@ -17,7 +17,7 @@ func TestNewStatusCommand(t *testing.T) { assert.Len(t, cmd.Aliases, 1) assert.True(t, cmd.HasAlias("s")) - assert.Equal(t, "Show picoclaw status", cmd.Short) + assert.Equal(t, "Show Jane AI status", cmd.Short) assert.False(t, cmd.HasSubCommands()) diff --git a/cmd/picoclaw/internal/status/helpers.go b/cmd/picoclaw/internal/status/helpers.go index 9d3dede3c..0d1de09de 100644 --- a/cmd/picoclaw/internal/status/helpers.go +++ b/cmd/picoclaw/internal/status/helpers.go @@ -18,7 +18,7 @@ func statusCmd() { configPath := internal.GetConfigPath() - fmt.Printf("%s picoclaw Status\n", internal.Logo) + fmt.Printf("%s Jane AI Status\n", internal.Logo) fmt.Printf("Version: %s\n", config.FormatVersion()) build, _ := config.FormatBuildInfo() if build != "" { diff --git a/cmd/picoclaw/internal/version/command.go b/cmd/picoclaw/internal/version/command.go index 72d61dec9..fea970573 100644 --- a/cmd/picoclaw/internal/version/command.go +++ b/cmd/picoclaw/internal/version/command.go @@ -23,7 +23,7 @@ func NewVersionCommand() *cobra.Command { } func printVersion() { - fmt.Printf("%s picoclaw %s\n", internal.Logo, config.FormatVersion()) + fmt.Printf("%s jane-ai %s\n", internal.Logo, config.FormatVersion()) build, goVer := config.FormatBuildInfo() if build != "" { fmt.Printf(" Build: %s\n", build) diff --git a/cmd/picoclaw/main.go b/cmd/picoclaw/main.go index 115fd9a64..895bc84a2 100644 --- a/cmd/picoclaw/main.go +++ b/cmd/picoclaw/main.go @@ -27,12 +27,12 @@ import ( ) func NewPicoclawCommand() *cobra.Command { - short := fmt.Sprintf("%s picoclaw - Personal AI Assistant v%s\n\n", internal.Logo, config.GetVersion()) + short := fmt.Sprintf("%s jane-ai - Personal AI Assistant v%s\n\n", internal.Logo, config.GetVersion()) cmd := &cobra.Command{ - Use: "picoclaw", + Use: "jane-ai", Short: short, - Example: "picoclaw version", + Example: "jane-ai version", } cmd.AddCommand( @@ -52,16 +52,16 @@ func NewPicoclawCommand() *cobra.Command { } const ( - colorBlue = "\033[1;38;2;62;93;185m" - colorRed = "\033[1;38;2;213;70;70m" - banner = "\r\n" + - colorBlue + "██████╗ █████╗ ███╗ ██╗███████╗" + colorRed + " █████╗ ██╗\n" + - colorBlue + "╚══██╔╝██╔══██╗████╗ ██║██╔════╝" + colorRed + " ██╔══██╗██║\n" + - colorBlue + " ██║ ███████║██╔██╗ ██║█████╗ " + colorRed + " ███████║██║\n" + - colorBlue + " ██║ ██╔══██║██║╚██╗██║██╔══╝ " + colorRed + " ██╔══██║██║\n" + - colorBlue + "█████║ ██║ ██║██║ ╚████║███████╗" + colorRed + " ██╗██║ ██║██║\n" + - colorBlue + "╚════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝" + colorRed + " ╚═╝╚═╝ ╚═╝╚═╝\n" + - "\033[0m\r\n" + colorBlue = "\033[1;38;2;62;93;185m" + colorRed = "\033[1;38;2;213;70;70m" + banner = "\r\n" + + colorBlue + "██████╗ █████╗ ███╗ ██╗███████╗" + colorRed + " █████╗ ██╗\n" + + colorBlue + "╚══██╔╝██╔══██╗████╗ ██║██╔════╝" + colorRed + " ██╔══██╗██║\n" + + colorBlue + " ██║ ███████║██╔██╗ ██║█████╗ " + colorRed + " ███████║██║\n" + + colorBlue + " ██║ ██╔══██║██║╚██╗██║██╔══╝ " + colorRed + " ██╔══██║██║\n" + + colorBlue + "█████║ ██║ ██║██║ ╚████║███████╗" + colorRed + " ██╗██║ ██║██║\n" + + colorBlue + "╚════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝" + colorRed + " ╚═╝╚═╝ ╚═╝╚═╝\n" + + "\033[0m\r\n" ) func main() { diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index b6fc724b5..1ef537538 100644 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -4,12 +4,22 @@ set -e # First-run: neither config nor workspace exists. # If config.json is already mounted but workspace is missing we skip onboard to # avoid the interactive "Overwrite? (y/n)" prompt hanging in a non-TTY container. -if [ ! -d "${HOME}/.picoclaw/workspace" ] && [ ! -f "${HOME}/.picoclaw/config.json" ]; then - picoclaw onboard +BIN="${JANE_AI_BINARY:-jane-ai}" +if ! command -v "$BIN" >/dev/null 2>&1; then + BIN="picoclaw" +fi + +HOME_DIR="${JANE_AI_HOME:-${PICOCLAW_HOME:-${HOME}/.jane-ai}}" +if [ ! -e "${HOME_DIR}/config.json" ] && [ -e "${HOME}/.picoclaw/config.json" ]; then + HOME_DIR="${HOME}/.picoclaw" +fi + +if [ ! -d "${HOME_DIR}/workspace" ] && [ ! -f "${HOME_DIR}/config.json" ]; then + "$BIN" onboard echo "" echo "First-run setup complete." - echo "Edit ${HOME}/.picoclaw/config.json (add your API key, etc.) then restart the container." + echo "Edit ${HOME_DIR}/config.json (add your API key, etc.) then restart the container." exit 0 fi -exec picoclaw gateway "$@" +exec "$BIN" gateway "$@" diff --git a/pkg/agent/context.go b/pkg/agent/context.go index 514aacdc0..e1d9baa21 100644 --- a/pkg/agent/context.go +++ b/pkg/agent/context.go @@ -79,9 +79,9 @@ func (cb *ContextBuilder) getIdentity() string { version := config.FormatVersion() return fmt.Sprintf( - `# picoclaw 🦞 (%s) + `# Jane AI (%s) -You are picoclaw, a helpful AI assistant. +You are Jane AI, a helpful AI assistant. ## Workspace Your workspace is at: %s diff --git a/pkg/runtimepaths/binary.go b/pkg/runtimepaths/binary.go new file mode 100644 index 000000000..f446fcfa7 --- /dev/null +++ b/pkg/runtimepaths/binary.go @@ -0,0 +1,32 @@ +package runtimepaths + +import ( + "os" + "os/exec" + "path/filepath" + "runtime" +) + +func BinaryPath() string { + if path := firstEnv("JANE_AI_BINARY", "PICOCLAW_BINARY"); path != "" { + return path + } + names := []string{"jane-ai", "picoclaw"} + if runtime.GOOS == "windows" { + names = []string{"jane-ai.exe", "picoclaw.exe"} + } + if exe, err := os.Executable(); err == nil { + for _, name := range names { + path := filepath.Join(filepath.Dir(exe), name) + if info, err := os.Stat(path); err == nil && !info.IsDir() { + return path + } + } + } + for _, name := range names { + if path, err := exec.LookPath(name); err == nil { + return path + } + } + return names[len(names)-1] +} diff --git a/web/backend/main.go b/web/backend/main.go index 380e37dc8..b25cc7cd4 100644 --- a/web/backend/main.go +++ b/web/backend/main.go @@ -1,13 +1,13 @@ -// PicoClaw Web Console - Web-based chat and management interface +// Jane AI Web Console - Web-based chat and management interface // -// Provides a web UI for chatting with PicoClaw via the Pico Channel WebSocket, +// Provides a web UI for chatting with Jane AI via the Pico Channel WebSocket, // with configuration management and gateway process control. // // Usage: // -// go build -o picoclaw-web ./web/backend/ -// ./picoclaw-web [config.json] -// ./picoclaw-web -public config.json +// go build -o jane-ai-web ./web/backend/ +// ./jane-ai-web [config.json] +// ./jane-ai-web -public config.json package main @@ -34,10 +34,10 @@ func main() { noBrowser := flag.Bool("no-browser", false, "Do not auto-open browser on startup") flag.Usage = func() { - fmt.Fprintf(os.Stderr, "PicoClaw Launcher - A web-based configuration editor\n\n") + fmt.Fprintf(os.Stderr, "Jane AI Launcher - A web-based configuration editor\n\n") fmt.Fprintf(os.Stderr, "Usage: %s [options] [config.json]\n\n", os.Args[0]) fmt.Fprintf(os.Stderr, "Arguments:\n") - fmt.Fprintf(os.Stderr, " config.json Path to the configuration file (default: ~/.picoclaw/config.json)\n\n") + fmt.Fprintf(os.Stderr, " config.json Path to the configuration file (default: ~/.jane-ai/config.json)\n\n") fmt.Fprintf(os.Stderr, "Options:\n") flag.PrintDefaults() fmt.Fprintf(os.Stderr, "\nExamples:\n") @@ -63,7 +63,7 @@ func main() { } err = utils.EnsureOnboarded(absPath) if err != nil { - logger.WarnCF("main", "Failed to initialize PicoClaw config automatically", map[string]any{"error": err.Error()}) + logger.WarnCF("main", "Failed to initialize Jane AI config automatically", map[string]any{"error": err.Error()}) } var explicitPort bool diff --git a/web/backend/utils/runtime.go b/web/backend/utils/runtime.go index 96cc62c02..bbb18ccba 100644 --- a/web/backend/utils/runtime.go +++ b/web/backend/utils/runtime.go @@ -34,34 +34,7 @@ func GetDefaultConfigPath() string { // 2. Same directory as the current executable // 3. Falls back to "jane-ai" or "picoclaw" on $PATH func FindPicoclawBinary() string { - if p := os.Getenv("JANE_AI_BINARY"); p != "" { - if info, _ := os.Stat(p); info != nil && !info.IsDir() { - return p - } - } - if p := os.Getenv("PICOCLAW_BINARY"); p != "" { - if info, _ := os.Stat(p); info != nil && !info.IsDir() { - return p - } - } - - binaryNames := []string{"jane-ai", "picoclaw"} - if runtime.GOOS == "windows" { - binaryNames = []string{"jane-ai.exe", "picoclaw.exe"} - } - if exe, err := os.Executable(); err == nil { - for _, binaryName := range binaryNames { - candidate := filepath.Join(filepath.Dir(exe), binaryName) - if info, err := os.Stat(candidate); err == nil && !info.IsDir() { - return candidate - } - } - } - - if path, err := exec.LookPath(binaryNames[0]); err == nil { - return path - } - return "picoclaw" + return runtimepaths.BinaryPath() } // GetLocalIP returns the local IP address of the machine.