Merge 1e8754634b into 08fc305d5e
This commit is contained in:
commit
733848d476
9 changed files with 143 additions and 7 deletions
35
.editorconfig
Normal file
35
.editorconfig
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
# EditorConfig is awesome: https://EditorConfig.org
|
||||||
|
|
||||||
|
# top-most EditorConfig file
|
||||||
|
root = true
|
||||||
|
|
||||||
|
# Default settings for all files
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
# Go files
|
||||||
|
[*.go]
|
||||||
|
indent_style = tab
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
# JSON, YAML, and Markdown files
|
||||||
|
[*.{json,yml,yaml,md}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
# JavaScript/TypeScript files
|
||||||
|
[*.{js,ts,tsx}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
# Shell scripts
|
||||||
|
[*.sh]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
# Makefile
|
||||||
|
[Makefile]
|
||||||
|
indent_style = tab
|
||||||
21
.gitignore
vendored
21
.gitignore
vendored
|
|
@ -69,3 +69,24 @@ web/backend/dist/*
|
||||||
docker/data
|
docker/data
|
||||||
|
|
||||||
.omc/
|
.omc/
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
*.tmp
|
||||||
|
*.temp
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Local development
|
||||||
|
local/
|
||||||
|
local.*
|
||||||
|
|
||||||
|
# Node modules for frontend
|
||||||
|
web/frontend/node_modules/
|
||||||
|
web/frontend/dist/
|
||||||
|
web/frontend/.cache/
|
||||||
|
|
||||||
|
# Python virtual environments
|
||||||
|
venv/
|
||||||
|
env/
|
||||||
|
ENV/
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
<h3>$10 Hardware · 10MB RAM · ms Boot · Let's Go, PicoClaw!</h3>
|
<h3>$10 Hardware · 10MB RAM · ms Boot · Let's Go, PicoClaw!</h3>
|
||||||
<p>
|
<p>
|
||||||
<img src="https://img.shields.io/badge/Go-1.25+-00ADD8?style=flat&logo=go&logoColor=white" alt="Go">
|
<img src="https://img.shields.io/badge/Go-1.23+-00ADD8?style=flat&logo=go&logoColor=white" alt="Go">
|
||||||
<img src="https://img.shields.io/badge/Arch-x86__64%2C%20ARM64%2C%20MIPS%2C%20RISC--V%2C%20LoongArch-blue" alt="Hardware">
|
<img src="https://img.shields.io/badge/Arch-x86__64%2C%20ARM64%2C%20MIPS%2C%20RISC--V%2C%20LoongArch-blue" alt="Hardware">
|
||||||
<img src="https://img.shields.io/badge/license-MIT-green" alt="License">
|
<img src="https://img.shields.io/badge/license-MIT-green" alt="License">
|
||||||
<br>
|
<br>
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,14 @@ package gateway
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"github.com/sipeed/picoclaw/cmd/picoclaw/internal"
|
"github.com/sipeed/picoclaw/cmd/picoclaw/internal"
|
||||||
"github.com/sipeed/picoclaw/pkg/gateway"
|
"github.com/sipeed/picoclaw/pkg/gateway"
|
||||||
"github.com/sipeed/picoclaw/pkg/logger"
|
"github.com/sipeed/picoclaw/pkg/logger"
|
||||||
|
"github.com/sipeed/picoclaw/pkg/pid"
|
||||||
"github.com/sipeed/picoclaw/pkg/utils"
|
"github.com/sipeed/picoclaw/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -48,5 +50,42 @@ func NewGatewayCommand() *cobra.Command {
|
||||||
"Continue starting even when no default model is configured",
|
"Continue starting even when no default model is configured",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Add stop subcommand
|
||||||
|
cmd.AddCommand(newGatewayStopCommand())
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newGatewayStopCommand() *cobra.Command {
|
||||||
|
return &cobra.Command{
|
||||||
|
Use: "stop",
|
||||||
|
Short: "Stop the running picoclaw gateway",
|
||||||
|
Long: "Stop the running picoclaw gateway by reading its PID file and sending a termination signal.",
|
||||||
|
Args: cobra.NoArgs,
|
||||||
|
RunE: func(_ *cobra.Command, _ []string) error {
|
||||||
|
homePath := internal.GetPicoclawHome()
|
||||||
|
|
||||||
|
// Read PID file and check if process is running
|
||||||
|
data := pid.ReadPidFileWithCheck(homePath)
|
||||||
|
if data == nil {
|
||||||
|
fmt.Println("gateway is not running")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the process
|
||||||
|
process, err := os.FindProcess(data.PID)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to find gateway process (PID: %d): %w", data.PID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send termination signal
|
||||||
|
fmt.Printf("stopping gateway (PID: %d)...\n", data.PID)
|
||||||
|
if err := stopProcess(process); err != nil {
|
||||||
|
return fmt.Errorf("failed to stop gateway (PID: %d): %w", data.PID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("gateway stopped successfully")
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
13
cmd/picoclaw/internal/gateway/stop_unix.go
Normal file
13
cmd/picoclaw/internal/gateway/stop_unix.go
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
//go:build !windows
|
||||||
|
|
||||||
|
package gateway
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// stopProcess sends SIGTERM to the process for graceful shutdown on Unix-like systems.
|
||||||
|
func stopProcess(process *os.Process) error {
|
||||||
|
return process.Signal(syscall.SIGTERM)
|
||||||
|
}
|
||||||
12
cmd/picoclaw/internal/gateway/stop_windows.go
Normal file
12
cmd/picoclaw/internal/gateway/stop_windows.go
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package gateway
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// stopProcess kills the process on Windows (SIGTERM is not supported).
|
||||||
|
func stopProcess(process *os.Process) error {
|
||||||
|
return process.Kill()
|
||||||
|
}
|
||||||
|
|
@ -10,6 +10,10 @@ services:
|
||||||
container_name: picoclaw-agent-full
|
container_name: picoclaw-agent-full
|
||||||
profiles:
|
profiles:
|
||||||
- agent
|
- agent
|
||||||
|
environment:
|
||||||
|
# PicoClaw runs as root in container by default
|
||||||
|
# If running as non-root user, update these paths to match the user's home directory
|
||||||
|
- HOME=/root
|
||||||
volumes:
|
volumes:
|
||||||
- ../config/config.json:/root/.picoclaw/config.json:ro
|
- ../config/config.json:/root/.picoclaw/config.json:ro
|
||||||
- picoclaw-workspace:/root/.picoclaw/workspace
|
- picoclaw-workspace:/root/.picoclaw/workspace
|
||||||
|
|
@ -30,6 +34,10 @@ services:
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
profiles:
|
profiles:
|
||||||
- gateway
|
- gateway
|
||||||
|
environment:
|
||||||
|
# PicoClaw runs as root in container by default
|
||||||
|
# If running as non-root user, update these paths to match the user's home directory
|
||||||
|
- HOME=/root
|
||||||
volumes:
|
volumes:
|
||||||
# Configuration file
|
# Configuration file
|
||||||
- ../config/config.json:/root/.picoclaw/config.json:ro
|
- ../config/config.json:/root/.picoclaw/config.json:ro
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ services:
|
||||||
#extra_hosts:
|
#extra_hosts:
|
||||||
# - "host.docker.internal:host-gateway"
|
# - "host.docker.internal:host-gateway"
|
||||||
volumes:
|
volumes:
|
||||||
- ./data:/root/.picoclaw
|
- ./data:/home/picoclaw/.picoclaw
|
||||||
entrypoint: ["picoclaw", "agent"]
|
entrypoint: ["picoclaw", "agent"]
|
||||||
stdin_open: true
|
stdin_open: true
|
||||||
tty: true
|
tty: true
|
||||||
|
|
@ -31,7 +31,7 @@ services:
|
||||||
#extra_hosts:
|
#extra_hosts:
|
||||||
# - "host.docker.internal:host-gateway"
|
# - "host.docker.internal:host-gateway"
|
||||||
volumes:
|
volumes:
|
||||||
- ./data:/root/.picoclaw
|
- ./data:/home/picoclaw/.picoclaw
|
||||||
|
|
||||||
# ─────────────────────────────────────────────
|
# ─────────────────────────────────────────────
|
||||||
# PicoClaw Launcher (Web Console + Gateway)
|
# PicoClaw Launcher (Web Console + Gateway)
|
||||||
|
|
@ -52,4 +52,4 @@ services:
|
||||||
- "18800:18800"
|
- "18800:18800"
|
||||||
- "18790:18790"
|
- "18790:18790"
|
||||||
volumes:
|
volumes:
|
||||||
- ./data:/root/.picoclaw
|
- ./data:/home/picoclaw/.picoclaw
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -128,9 +129,16 @@ func NewBaseChannel(
|
||||||
// currently defaults to accepting messages from ANYONE. To explicitly
|
// currently defaults to accepting messages from ANYONE. To explicitly
|
||||||
// acknowledge and permit this (e.g. for a public bot), use ["*"].
|
// acknowledge and permit this (e.g. for a public bot), use ["*"].
|
||||||
if len(bc.allowList) == 0 {
|
if len(bc.allowList) == 0 {
|
||||||
logger.WarnCF("channels", "SECURITY: Channel allows EVERYONE (allow_from is empty)", map[string]any{
|
logger.WarnCF("channels", fmt.Sprintf("SECURITY: Channel '%s' allows EVERYONE (allow_from is empty). This is a potential security risk.", bc.name), map[string]any{
|
||||||
"channel": bc.name,
|
"channel": bc.name,
|
||||||
"hint": "Set allow_from to your ID, or use '*' to explicitly acknowledge open access.",
|
"channelID": bc.name,
|
||||||
|
"hint": "Set allow_from to your ID, or use ['*'] to explicitly acknowledge open access. See: https://github.com/sipeed/picoclaw/blob/main/docs/configuration.md",
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
logger.InfoCF("channels", fmt.Sprintf("Channel '%s' allow_from configured (%d entries)", bc.name, len(bc.allowList)), map[string]any{
|
||||||
|
"channel": bc.name,
|
||||||
|
"allow_list": bc.allowList,
|
||||||
|
"count": len(bc.allowList),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue