2026-04-17 05:45:39 +00:00
.PHONY : all build install uninstall clean help test build -all lint -docs
2026-02-04 11:06:13 +00:00
# Build variables
BINARY_NAME = picoclaw
BUILD_DIR = build
CMD_DIR = cmd/$( BINARY_NAME)
MAIN_GO = $( CMD_DIR) /main.go
2026-04-03 03:39:37 +00:00
EXT =
2026-02-04 11:06:13 +00:00
2026-04-24 09:50:59 +00:00
i f e q ( $( OS ) , W i n d o w s _ N T )
POWERSHELL = powershell -NoProfile -Command
WINDOWS_GOARCH_RAW:= $( strip $( shell go env GOARCH 2>NUL) )
e n d i f
2026-02-04 11:06:13 +00:00
# Version
2026-04-24 09:50:59 +00:00
i f e q ( $( OS ) , W i n d o w s _ N T )
VERSION_RAW:= $( strip $( shell git describe --tags --always --dirty 2>NUL) )
GIT_COMMIT_RAW:= $( strip $( shell git rev-parse --short= 8 HEAD 2>NUL) )
BUILD_TIME_RAW:= $( strip $( shell powershell -NoProfile -Command "Get-Date -Format 'yyyy-MM-ddTHH:mm:ssK'" ) )
GO_VERSION_RAW:= $( strip $( shell go env GOVERSION 2>NUL) )
e l s e
VERSION_RAW:= $( strip $( shell git describe --tags --always --dirty 2>/dev/null) )
GIT_COMMIT_RAW:= $( strip $( shell git rev-parse --short= 8 HEAD 2>/dev/null) )
BUILD_TIME_RAW:= $( strip $( shell date +%FT%T%z) )
GO_VERSION_RAW:= $( strip $( shell go env GOVERSION 2>/dev/null) )
e n d i f
VERSION ?= $( if $( VERSION_RAW) ,$( VERSION_RAW) ,dev)
GIT_COMMIT = $( if $( GIT_COMMIT_RAW) ,$( GIT_COMMIT_RAW) ,dev)
BUILD_TIME = $( if $( BUILD_TIME_RAW) ,$( BUILD_TIME_RAW) ,dev)
GO_VERSION = $( if $( GO_VERSION_RAW) ,$( GO_VERSION_RAW) ,unknown)
2026-03-10 09:42:05 +00:00
CONFIG_PKG = github.com/sipeed/picoclaw/pkg/config
2026-03-17 06:12:32 +00:00
LDFLAGS = -X $( CONFIG_PKG) .Version= $( VERSION) -X $( CONFIG_PKG) .GitCommit= $( GIT_COMMIT) -X $( CONFIG_PKG) .BuildTime= $( BUILD_TIME) -X $( CONFIG_PKG) .GoVersion= $( GO_VERSION) -s -w
2026-02-04 11:06:13 +00:00
# Go variables
2026-04-24 09:50:59 +00:00
GO ?= go
2026-03-17 07:23:49 +00:00
WEB_GO ?= $( GO)
2026-04-24 09:50:59 +00:00
CGO_ENABLED ?= 0
2026-03-23 01:29:17 +00:00
GO_BUILD_TAGS ?= goolm,stdjson
GOFLAGS ?= -v -tags $( GO_BUILD_TAGS)
2026-04-24 09:50:59 +00:00
GOCACHE ?= $( CURDIR) /.cache/go-build
GOMODCACHE ?= $( CURDIR) /.cache/go-mod
GOTOOLCHAIN ?= local
export CGO_ENABLED
export GOCACHE
export GOMODCACHE
export GOTOOLCHAIN
2026-03-24 15:40:51 +00:00
comma := ,
empty :=
space := $( empty) $( empty)
GO_BUILD_TAGS_NO_GOOLM := $( subst $( space) ,$( comma) ,$( strip $( filter-out goolm,$( subst $( comma) ,$( space) ,$( GO_BUILD_TAGS) ) ) ) )
GOFLAGS_NO_GOOLM ?= -v -tags $( GO_BUILD_TAGS_NO_GOOLM)
2026-02-04 11:06:13 +00:00
2026-03-06 11:54:56 +00:00
# Patch MIPS LE ELF e_flags (offset 36) for NaN2008-only kernels (e.g. Ingenic X2600).
#
# Bytes (octal): \004 \024 \000 \160 → little-endian 0x70001404
# 0x70000000 EF_MIPS_ARCH_32R2 MIPS32 Release 2
# 0x00001000 EF_MIPS_ABI_O32 O32 ABI
# 0x00000400 EF_MIPS_NAN2008 IEEE 754-2008 NaN encoding
# 0x00000004 EF_MIPS_CPIC PIC calling sequence
#
# Go's GOMIPS=softfloat emits no FP instructions, so the NaN mode is irrelevant
# at runtime — this is purely an ELF metadata fix to satisfy the kernel's check.
# patchelf cannot modify e_flags; dd at a fixed offset is the most portable way.
#
# Ref: https://codebrowser.dev/linux/linux/arch/mips/include/asm/elf.h.html
d e f i n e P A T C H _ M I P S _ F L A G S
@if [ -f " $( 1) " ] ; then \
printf '\004\024\000\160' | dd of = $( 1) bs = 1 seek = 36 count = 4 conv = notrunc 2>/dev/null || \
{ echo " Error: failed to patch MIPS e_flags for $( 1) " ; exit 1; } ; \
else \
echo " Error: $( 1) not found, cannot patch MIPS e_flags " ; exit 1; \
fi
e n d e f
feat(tools): add exec tool enhancement with background execution and PTY support (#1752)
- Unified exec tool with actions: run/list/poll/read/write/send-keys/kill
- PTY support using creack/pty library
- Process session management with background execution
- Process group kill for cleaning up child processes
- Session cleanup: 30-minute TTL for old sessions
- Output buffer: 100MB limit with truncation
Actions:
- run: execute command (sync or background)
- list: list all sessions
- poll: check session status
- read: read session output
- write: send input to session stdin
- send-keys: send special keys (up, down, ctrl-c, enter, etc.)
- kill: terminate session
Tests:
- PTY: allowed commands, write/read, poll, kill, process group kill
- Non-PTY: background execution, list, read, write, poll, kill, process group kill
- Session management: add/get/remove/list/cleanup
2026-03-21 14:38:03 +00:00
# Patch creack/pty for loong64 support (upstream doesn't have ztypes_loong64.go)
PTY_PATCH_LOONG64 = pty_dir = $$ ( go env GOMODCACHE) /github.com/creack/pty@v1.1.9; \
if [ -d " $$ pty_dir " ] && [ ! -f " $$ pty_dir/ztypes_loong64.go " ] ; then \
chmod +w " $$ pty_dir " 2>/dev/null || true; \
printf '//go:build linux && loong64\npackage pty\ntype (_C_int int32; _C_uint uint32)\n' > " $$ pty_dir/ztypes_loong64.go " ; \
fi
2026-02-18 19:48:23 +00:00
# Golangci-lint
GOLANGCI_LINT ?= golangci-lint
2026-02-04 11:06:13 +00:00
# Installation
INSTALL_PREFIX ?= $( HOME) /.local
INSTALL_BIN_DIR = $( INSTALL_PREFIX) /bin
INSTALL_MAN_DIR = $( INSTALL_PREFIX) /share/man/man1
2026-02-23 10:29:43 +00:00
INSTALL_TMP_SUFFIX = .new
2026-02-04 11:06:13 +00:00
# Workspace and Skills
PICOCLAW_HOME ?= $( HOME) /.picoclaw
WORKSPACE_DIR ?= $( PICOCLAW_HOME) /workspace
WORKSPACE_SKILLS_DIR = $( WORKSPACE_DIR) /skills
BUILTIN_SKILLS_DIR = $( CURDIR) /skills
2026-04-03 04:43:39 +00:00
LNCMD = ln -sf
2026-04-03 03:39:37 +00:00
2026-02-04 11:06:13 +00:00
# OS detection
2026-04-24 09:50:59 +00:00
i f e q ( $( OS ) , W i n d o w s _ N T )
UNAME_S = Windows
ifeq ( $( WINDOWS_GOARCH_RAW) ,amd64)
UNAME_M = x86_64
else ifeq ( $( WINDOWS_GOARCH_RAW) ,arm64)
UNAME_M = arm64
else ifeq ( $( WINDOWS_GOARCH_RAW) ,386)
UNAME_M = x86
else
UNAME_M = $( if $( WINDOWS_GOARCH_RAW) ,$( WINDOWS_GOARCH_RAW) ,x86_64)
endif
e l s e
UNAME_S?= $( shell uname -s)
UNAME_M?= $( shell uname -m)
e n d i f
2026-02-04 11:06:13 +00:00
# Platform-specific settings
i f e q ( $( UNAME_S ) , L i n u x )
PLATFORM = linux
ifeq ( $( UNAME_M) ,x86_64)
ARCH = amd64
else ifeq ( $( UNAME_M) ,aarch64)
ARCH = arm64
2026-02-26 09:41:01 +00:00
else ifeq ( $( UNAME_M) ,armv81)
ARCH = arm64
2026-02-17 13:31:54 +00:00
else ifeq ( $( UNAME_M) ,loongarch64)
ARCH = loong64
2026-02-04 11:06:13 +00:00
else ifeq ( $( UNAME_M) ,riscv64)
ARCH = riscv64
2026-03-06 11:54:56 +00:00
else ifeq ( $( UNAME_M) ,mipsel)
ARCH = mipsle
2026-02-04 11:06:13 +00:00
else
ARCH = $( UNAME_M)
endif
e l s e i f e q ( $( UNAME_S ) , D a r w i n )
PLATFORM = darwin
2026-04-01 15:56:46 +00:00
WEB_GO = CGO_LDFLAGS = "-mmacosx-version-min=10.11" CGO_CFLAGS = "-mmacosx-version-min=10.11" CGO_ENABLED = 1 go
2026-02-04 11:06:13 +00:00
ifeq ( $( UNAME_M) ,x86_64)
2026-04-01 15:56:46 +00:00
ARCH?= amd64
2026-02-04 11:06:13 +00:00
else ifeq ( $( UNAME_M) ,arm64)
2026-04-01 15:56:46 +00:00
ARCH?= arm64
2026-02-04 11:06:13 +00:00
else
2026-04-01 15:56:46 +00:00
ARCH?= $( UNAME_M)
2026-02-04 11:06:13 +00:00
endif
e l s e
PLATFORM = $( UNAME_S)
2026-04-03 03:39:37 +00:00
ifeq ( $( UNAME_M) ,x86_64)
ARCH?= amd64
else
ARCH?= $( UNAME_M)
endif
# Detect Windows (Git Bash / MSYS2)
IS_WINDOWS:= $( if $( findstring MINGW,$( UNAME_S) ) ,yes,$( if $( findstring MSYS,$( UNAME_S) ) ,yes,$( if $( findstring CYGWIN,$( UNAME_S) ) ,yes,no) ) )
ifeq ( $( IS_WINDOWS) ,yes)
EXT = .exe
2026-04-03 04:43:39 +00:00
LNCMD = cp
2026-04-03 03:49:24 +00:00
else ifeq ( $( UNAME_S) ,windows) # failsafe for force windows build in other OS using UNAME_S=windows
2026-04-03 03:39:37 +00:00
EXT = .exe
endif
2026-02-04 11:06:13 +00:00
e n d i f
2026-04-24 09:50:59 +00:00
i f e q ( $( OS ) , W i n d o w s _ N T )
PLATFORM = windows
ifeq ( $( UNAME_M) ,x86_64)
ARCH?= amd64
else ifeq ( $( UNAME_M) ,arm64)
ARCH?= arm64
else
ARCH?= $( UNAME_M)
endif
EXT = .exe
e n d i f
2026-04-27 09:44:26 +00:00
i f n e q ( $( strip $ ( GOOS ) ) , )
PLATFORM:= $( GOOS)
e n d i f
i f n e q ( $( strip $ ( GOARCH ) ) , )
ARCH:= $( GOARCH)
e n d i f
i f e q ( $( PLATFORM ) , w i n d o w s )
EXT = .exe
e n d i f
2026-02-04 11:06:13 +00:00
BINARY_PATH = $( BUILD_DIR) /$( BINARY_NAME) -$( PLATFORM) -$( ARCH)
# Default target
all : build
2026-02-14 23:43:46 +00:00
## generate: Run generate
generate :
@echo "Run generate..."
2026-04-24 09:50:59 +00:00
i f e q ( $( OS ) , W i n d o w s _ N T )
@$( POWERSHELL) " if (Test-Path -LiteralPath './ $( CMD_DIR) /workspace') { Remove-Item -LiteralPath './ $( CMD_DIR) /workspace' -Recurse -Force } "
2026-04-27 09:44:26 +00:00
@$( POWERSHELL) " $$ env:GOOS=''; $$ env:GOARCH=''; $( GO) generate ./... "
2026-04-24 09:50:59 +00:00
e l s e
2026-02-14 23:43:46 +00:00
@rm -r ./$( CMD_DIR) /workspace 2>/dev/null || true
2026-04-27 09:44:26 +00:00
@GOOS= $$ ( $( GO) env GOHOSTOS) GOARCH = $$ ( $( GO) env GOHOSTARCH) $( GO) generate ./...
2026-04-24 09:50:59 +00:00
e n d i f
2026-02-14 23:43:46 +00:00
@echo "Run generate complete"
2026-02-04 11:06:13 +00:00
## build: Build the picoclaw binary for current platform
2026-02-14 23:43:46 +00:00
build : generate
2026-04-03 03:39:37 +00:00
@echo " Building $( BINARY_NAME) $( EXT) for $( PLATFORM) / $( ARCH) ... "
2026-04-24 09:50:59 +00:00
i f e q ( $( OS ) , W i n d o w s _ N T )
@$( POWERSHELL) " New-Item -ItemType Directory -Force -Path ' $( BUILD_DIR) ' | Out-Null "
@$( GO) build $( GOFLAGS) -ldflags " $( LDFLAGS) " -o $( BINARY_PATH) $( EXT) ./$( CMD_DIR)
@$( POWERSHELL) " Copy-Item -LiteralPath ' $( BINARY_PATH) $( EXT) ' -Destination ' $( BUILD_DIR) / $( BINARY_NAME) $( EXT) ' -Force "
e l s e
2026-02-04 11:06:13 +00:00
@mkdir -p $( BUILD_DIR)
2026-04-27 09:44:26 +00:00
@GOOS= $( PLATFORM) GOARCH = $( ARCH) $( GO) build $( GOFLAGS) -ldflags " $( LDFLAGS) " -o $( BINARY_PATH) $( EXT) ./$( CMD_DIR)
2026-04-03 03:39:37 +00:00
@echo " Build complete: $( BINARY_PATH) $( EXT) "
2026-04-03 04:43:39 +00:00
@$( LNCMD) $( BINARY_NAME) -$( PLATFORM) -$( ARCH) $( EXT) $( BUILD_DIR) /$( BINARY_NAME) $( EXT)
2026-04-24 09:50:59 +00:00
e n d i f
@echo " Build complete: $( BUILD_DIR) / $( BINARY_NAME) $( EXT) "
2026-02-04 11:06:13 +00:00
feat(web): migrate launcher to modular web frontend/backend and improve management UX (#1275)
* refactor: remove the legacy picoclaw-launcher
* feat: create initial web frontend and backend structure
* feat(packaging): add desktop entry for PicoClaw Launcher (#1062)
- Add .desktop file with Terminal=true, named "PicoClaw Launcher"
- Install to /usr/share/applications/ for app menu visibility
- Add 512x512 PNG icon to /usr/share/icons/hicolor/
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* `make dev`: If you haven't built it before, you need to run `build` first.
* feat(web): comprehensive web UI and backend refactoring
This commit introduces a major overhaul of both the frontend web UI and the Go backend API, transitioning to a highly modular architecture and integrating new core features.
Backend:
- Refactored monolithic API endpoints into domain-specific modules (config, gateway, log, models, pico, session).
- Cleaned up obsolete files (`server.go`, `status.go`, WebSocket handlers) and outdated tests.
- Implemented Gateway process lifecycle management (start/stop/restart) and real-time log streaming.
Frontend:
- Integrated Shadcn UI components to establish a modern, consistent design system.
- Introduced a new application layout featuring a responsive sidebar (`app-sidebar`) and header.
- Implemented internationalization (i18n) with initial support for English and Chinese.
- Restructured API clients, hooks, and Zustand stores into logical domains.
- Added new management pages for Settings, Logs, Models, Providers, and Credentials.
- Upgraded the Pico chat interface with session history management and dynamic model selection.
Build & Config:
- Updated frontend dependencies, Vite configuration, and lockfiles.
- Refined routing setup and overarching application stylesheets.
* feat(web): enhance model management, sorting, and deletion logic
- Implement model sorting in UI (default > configured > unconfigured)
- Prevent deletion of default models in the frontend
- Update backend to clear default settings when a model is deleted
- Add existence validation when setting a default model via API
- Group models in chat UI by type (API Key, OAuth, Local)
- Conditionally display model selector in chat based on configuration status
* refactor(web): refactor chat page into modular components/hooks and update i18n
- split chat route into dedicated chat components (page, composer, empty state, messages, history, model selector)
- extract model/session logic into use-chat-models and use-session-history hooks
- update chat locale keys in en/zh and add empty-state/history-related translations
* refactor(models): refactor models page into modular components and improve UX
- split /models route into dedicated components (page, provider section, card, add/edit sheets, delete dialog)
- add provider grouping/sorting, provider labels/icons, and a no-default hint in the models page
- add "Set as default model" toggle to add/edit flows with safer defaults
- introduce shared form helpers and new UI primitives (field, label, switch)
- update i18n strings (en/zh) for models and gateway header text usage
- apply minor UI polish (models nav icon, separator client directive)
* fix(web): add SPA index fallback for embedded frontend routes
Serve existing static assets as-is, keep /api/* and missing asset paths returning 404, and add tests for SPA fallback behavior on refresh.
* fix(frontend/chat): normalize message timestamp units to prevent invalid far-future dates
* chore: delete TestSPARouteFallsBackToIndex
* feat: update build for web-based launcher (#1186)
- Makefile: add build-launcher target (builds frontend + Go backend)
- GoReleaser: point picoclaw-launcher build to web/backend, add frontend
build hook, restore winres hook with updated paths
- Restore icon.ico and winres config from main for Windows builds
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(credentials): add multi-provider OAuth credential management
- add backend `/api/oauth/*` endpoints for provider status, browser/device-code/token login, flow query/polling, and logout
- extend API handler with OAuth flow/state tracking and route registration, plus OAuth unit tests
- implement frontend credentials page/components for OpenAI, Anthropic, and Google Antigravity login/logout
- add OAuth API client and `useCredentialsPage` hook, with new EN/ZH i18n strings
* chore: remove placeholder index.html from dist (#1188)
The .gitkeep is sufficient for go:embed to find the dist directory.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(frontend): polish model and credential UX; remove Providers nav
- remove the Providers item from sidebar navigation and locale keys
- simplify chat composer by dropping attach/voice action buttons
- support ReactNode titles in credential cards and add provider brand icons
- refine sheet header/footer styling and device-code footer button hierarchy
- disable “Set default” when a model is unconfigured or already default
* feat(web): Update config page (#1173)
* feat(web): Update config page
* fix(web): useEffect resets editorValue whenever config changes
* fix(web): react-hooks/set-state-in-effect error & pnpm lint #1173
* feat(web): add channel management page for web console (#1190)
* feat(web): add channel management page for web console
Add a complete channel management UI that allows users to configure
messaging channels (Telegram, Discord, Slack, Feishu, etc.) directly
from the web console instead of manually editing config.json.
Backend: GET/PUT/PATCH API endpoints for listing, updating, and
toggling channels with secret field masking.
Frontend: Channel cards grid with enable/disable toggles, per-channel
configuration sheets with dedicated forms for major platforms and a
generic fallback for others.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(web/channels): move channels to own sidebar group and fix sheet padding
- Channels now has its own navigation group instead of being under Services
- Fix edit sheet form content padding (px-1 -> px-4) to match header/footer
- Fix naked return lint error in extractChannelInfo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(web): harden channel config updates and resolve frontend lint issues
- validate channel PUT/PATCH updates before saving and return structured validation errors
- require `enabled` in toggle requests to avoid silent false defaults
- support editing `allow_origins` in the generic channel form and parse string/array inputs on backend
- replace channel form `any` usage with `ChannelConfig` (`Record<string, unknown>`) and add safe value helpers
- add i18n strings for allow-origins fields and apply related frontend formatting cleanups
* fix(frontend): prevent false "Invalid JSON" errors in config editor
* feat: add startup readiness checks and propagate start availability to UI
- add gateway precondition validation for default model and credentials
- auto-start gateway on backend boot when conditions are met
- include gateway_start_allowed and gateway_start_reason in status updates
- prevent frontend start actions when gateway cannot be started
* feat(web): revamp channel config UX with catalog-based routing
- replace legacy channel management endpoints with a backend channel catalog API
- switch frontend channel updates to PATCH /api/config and per-channel config pages
- add dynamic channel items in the sidebar with support for expand/collapse
- migrate /channels to nested routes (/channels/$name) and remove old card/sheet flow
- improve channel forms with clearer hints, required/error states, and reusable switch cards
- fix Discord mention-only toggle to read/write group_trigger.mention_only
* refactor(frontend): move shared-form to components and unify default-model switch with SwitchCardField
* fix(frontend): improve model form validation and unify secret placeholder handling
- block duplicate model aliases when adding a model (with localized error messages)
- share masked secret placeholder logic across model and channel forms
- refresh gateway state after setting the default model
- apply minor UI cleanup to provider icon rendering
* feat(web): add visual system config and launcher/autostart controls
- add launcher config model and persistence (`launcher-config.json`) for port/public/CIDR settings
- add system APIs for launch-at-login and launcher parameters
- apply CIDR-based access-control middleware to backend HTTP routes
- split config routing into visual config and raw JSON config pages
- add frontend system API client and visual config sections for runtime/devices/launcher
- expand i18n strings (en/zh) for new config UI
- improve sidebar active matching and session ID generation fallback
* refactor(frontend): remove i18n fallback strings and drop providers route
- Replace `t(key, defaultValue)` calls with key-only translations across UI pages
- Clean up locale files by pruning unused keys and adding missing shared keys
- Remove the obsolete `/providers` page and update generated route tree
* fix(backend): correct gateway status detection on Windows
* fix(repo): keep web backend dist placeholder tracked
---------
Co-authored-by: Guoguo <16666742+imguoguo@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Dihubopen <dihubcn@gmail.com>
Co-authored-by: Dihubopen <130813726+Dihubopen@users.noreply.github.com>
2026-03-09 11:42:03 +00:00
## build-launcher: Build the picoclaw-launcher (web console) binary
build-launcher :
@echo " Building picoclaw-launcher for $( PLATFORM) / $( ARCH) ... "
2026-04-24 09:50:59 +00:00
i f e q ( $( OS ) , W i n d o w s _ N T )
@$( POWERSHELL) " New-Item -ItemType Directory -Force -Path ' $( BUILD_DIR) ' | Out-Null "
@$( MAKE) -C web build PLATFORM = " $( PLATFORM) " ARCH = " $( ARCH) " EXT = " $( EXT) " OUTPUT = " $( CURDIR) / $( BUILD_DIR) /picoclaw-launcher- $( PLATFORM) - $( ARCH) $( EXT) " GO_BUILD_TAGS = " $( GO_BUILD_TAGS) "
@$( POWERSHELL) " Copy-Item -LiteralPath ' $( BUILD_DIR) /picoclaw-launcher- $( PLATFORM) - $( ARCH) $( EXT) ' -Destination ' $( BUILD_DIR) /picoclaw-launcher $( EXT) ' -Force "
e l s e
feat(web): migrate launcher to modular web frontend/backend and improve management UX (#1275)
* refactor: remove the legacy picoclaw-launcher
* feat: create initial web frontend and backend structure
* feat(packaging): add desktop entry for PicoClaw Launcher (#1062)
- Add .desktop file with Terminal=true, named "PicoClaw Launcher"
- Install to /usr/share/applications/ for app menu visibility
- Add 512x512 PNG icon to /usr/share/icons/hicolor/
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* `make dev`: If you haven't built it before, you need to run `build` first.
* feat(web): comprehensive web UI and backend refactoring
This commit introduces a major overhaul of both the frontend web UI and the Go backend API, transitioning to a highly modular architecture and integrating new core features.
Backend:
- Refactored monolithic API endpoints into domain-specific modules (config, gateway, log, models, pico, session).
- Cleaned up obsolete files (`server.go`, `status.go`, WebSocket handlers) and outdated tests.
- Implemented Gateway process lifecycle management (start/stop/restart) and real-time log streaming.
Frontend:
- Integrated Shadcn UI components to establish a modern, consistent design system.
- Introduced a new application layout featuring a responsive sidebar (`app-sidebar`) and header.
- Implemented internationalization (i18n) with initial support for English and Chinese.
- Restructured API clients, hooks, and Zustand stores into logical domains.
- Added new management pages for Settings, Logs, Models, Providers, and Credentials.
- Upgraded the Pico chat interface with session history management and dynamic model selection.
Build & Config:
- Updated frontend dependencies, Vite configuration, and lockfiles.
- Refined routing setup and overarching application stylesheets.
* feat(web): enhance model management, sorting, and deletion logic
- Implement model sorting in UI (default > configured > unconfigured)
- Prevent deletion of default models in the frontend
- Update backend to clear default settings when a model is deleted
- Add existence validation when setting a default model via API
- Group models in chat UI by type (API Key, OAuth, Local)
- Conditionally display model selector in chat based on configuration status
* refactor(web): refactor chat page into modular components/hooks and update i18n
- split chat route into dedicated chat components (page, composer, empty state, messages, history, model selector)
- extract model/session logic into use-chat-models and use-session-history hooks
- update chat locale keys in en/zh and add empty-state/history-related translations
* refactor(models): refactor models page into modular components and improve UX
- split /models route into dedicated components (page, provider section, card, add/edit sheets, delete dialog)
- add provider grouping/sorting, provider labels/icons, and a no-default hint in the models page
- add "Set as default model" toggle to add/edit flows with safer defaults
- introduce shared form helpers and new UI primitives (field, label, switch)
- update i18n strings (en/zh) for models and gateway header text usage
- apply minor UI polish (models nav icon, separator client directive)
* fix(web): add SPA index fallback for embedded frontend routes
Serve existing static assets as-is, keep /api/* and missing asset paths returning 404, and add tests for SPA fallback behavior on refresh.
* fix(frontend/chat): normalize message timestamp units to prevent invalid far-future dates
* chore: delete TestSPARouteFallsBackToIndex
* feat: update build for web-based launcher (#1186)
- Makefile: add build-launcher target (builds frontend + Go backend)
- GoReleaser: point picoclaw-launcher build to web/backend, add frontend
build hook, restore winres hook with updated paths
- Restore icon.ico and winres config from main for Windows builds
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(credentials): add multi-provider OAuth credential management
- add backend `/api/oauth/*` endpoints for provider status, browser/device-code/token login, flow query/polling, and logout
- extend API handler with OAuth flow/state tracking and route registration, plus OAuth unit tests
- implement frontend credentials page/components for OpenAI, Anthropic, and Google Antigravity login/logout
- add OAuth API client and `useCredentialsPage` hook, with new EN/ZH i18n strings
* chore: remove placeholder index.html from dist (#1188)
The .gitkeep is sufficient for go:embed to find the dist directory.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(frontend): polish model and credential UX; remove Providers nav
- remove the Providers item from sidebar navigation and locale keys
- simplify chat composer by dropping attach/voice action buttons
- support ReactNode titles in credential cards and add provider brand icons
- refine sheet header/footer styling and device-code footer button hierarchy
- disable “Set default” when a model is unconfigured or already default
* feat(web): Update config page (#1173)
* feat(web): Update config page
* fix(web): useEffect resets editorValue whenever config changes
* fix(web): react-hooks/set-state-in-effect error & pnpm lint #1173
* feat(web): add channel management page for web console (#1190)
* feat(web): add channel management page for web console
Add a complete channel management UI that allows users to configure
messaging channels (Telegram, Discord, Slack, Feishu, etc.) directly
from the web console instead of manually editing config.json.
Backend: GET/PUT/PATCH API endpoints for listing, updating, and
toggling channels with secret field masking.
Frontend: Channel cards grid with enable/disable toggles, per-channel
configuration sheets with dedicated forms for major platforms and a
generic fallback for others.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(web/channels): move channels to own sidebar group and fix sheet padding
- Channels now has its own navigation group instead of being under Services
- Fix edit sheet form content padding (px-1 -> px-4) to match header/footer
- Fix naked return lint error in extractChannelInfo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(web): harden channel config updates and resolve frontend lint issues
- validate channel PUT/PATCH updates before saving and return structured validation errors
- require `enabled` in toggle requests to avoid silent false defaults
- support editing `allow_origins` in the generic channel form and parse string/array inputs on backend
- replace channel form `any` usage with `ChannelConfig` (`Record<string, unknown>`) and add safe value helpers
- add i18n strings for allow-origins fields and apply related frontend formatting cleanups
* fix(frontend): prevent false "Invalid JSON" errors in config editor
* feat: add startup readiness checks and propagate start availability to UI
- add gateway precondition validation for default model and credentials
- auto-start gateway on backend boot when conditions are met
- include gateway_start_allowed and gateway_start_reason in status updates
- prevent frontend start actions when gateway cannot be started
* feat(web): revamp channel config UX with catalog-based routing
- replace legacy channel management endpoints with a backend channel catalog API
- switch frontend channel updates to PATCH /api/config and per-channel config pages
- add dynamic channel items in the sidebar with support for expand/collapse
- migrate /channels to nested routes (/channels/$name) and remove old card/sheet flow
- improve channel forms with clearer hints, required/error states, and reusable switch cards
- fix Discord mention-only toggle to read/write group_trigger.mention_only
* refactor(frontend): move shared-form to components and unify default-model switch with SwitchCardField
* fix(frontend): improve model form validation and unify secret placeholder handling
- block duplicate model aliases when adding a model (with localized error messages)
- share masked secret placeholder logic across model and channel forms
- refresh gateway state after setting the default model
- apply minor UI cleanup to provider icon rendering
* feat(web): add visual system config and launcher/autostart controls
- add launcher config model and persistence (`launcher-config.json`) for port/public/CIDR settings
- add system APIs for launch-at-login and launcher parameters
- apply CIDR-based access-control middleware to backend HTTP routes
- split config routing into visual config and raw JSON config pages
- add frontend system API client and visual config sections for runtime/devices/launcher
- expand i18n strings (en/zh) for new config UI
- improve sidebar active matching and session ID generation fallback
* refactor(frontend): remove i18n fallback strings and drop providers route
- Replace `t(key, defaultValue)` calls with key-only translations across UI pages
- Clean up locale files by pruning unused keys and adding missing shared keys
- Remove the obsolete `/providers` page and update generated route tree
* fix(backend): correct gateway status detection on Windows
* fix(repo): keep web backend dist placeholder tracked
---------
Co-authored-by: Guoguo <16666742+imguoguo@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Dihubopen <dihubcn@gmail.com>
Co-authored-by: Dihubopen <130813726+Dihubopen@users.noreply.github.com>
2026-03-09 11:42:03 +00:00
@mkdir -p $( BUILD_DIR)
2026-04-27 09:44:26 +00:00
@GOOS= $( PLATFORM) GOARCH = $( ARCH) $( MAKE) -C web build \
2026-04-03 03:39:37 +00:00
OUTPUT = " $( CURDIR) / $( BUILD_DIR) /picoclaw-launcher- $( PLATFORM) - $( ARCH) $( EXT) " \
2026-03-30 06:45:52 +00:00
WEB_GO = '$(WEB_GO)' \
GO_BUILD_TAGS = '$(GO_BUILD_TAGS)' \
LDFLAGS = '$(LDFLAGS)'
2026-04-03 04:43:39 +00:00
@$( LNCMD) picoclaw-launcher-$( PLATFORM) -$( ARCH) $( EXT) $( BUILD_DIR) /picoclaw-launcher$( EXT)
2026-04-24 09:50:59 +00:00
e n d i f
2026-04-03 03:39:37 +00:00
@echo " Build complete: $( BUILD_DIR) /picoclaw-launcher $( EXT) "
feat(web): migrate launcher to modular web frontend/backend and improve management UX (#1275)
* refactor: remove the legacy picoclaw-launcher
* feat: create initial web frontend and backend structure
* feat(packaging): add desktop entry for PicoClaw Launcher (#1062)
- Add .desktop file with Terminal=true, named "PicoClaw Launcher"
- Install to /usr/share/applications/ for app menu visibility
- Add 512x512 PNG icon to /usr/share/icons/hicolor/
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* `make dev`: If you haven't built it before, you need to run `build` first.
* feat(web): comprehensive web UI and backend refactoring
This commit introduces a major overhaul of both the frontend web UI and the Go backend API, transitioning to a highly modular architecture and integrating new core features.
Backend:
- Refactored monolithic API endpoints into domain-specific modules (config, gateway, log, models, pico, session).
- Cleaned up obsolete files (`server.go`, `status.go`, WebSocket handlers) and outdated tests.
- Implemented Gateway process lifecycle management (start/stop/restart) and real-time log streaming.
Frontend:
- Integrated Shadcn UI components to establish a modern, consistent design system.
- Introduced a new application layout featuring a responsive sidebar (`app-sidebar`) and header.
- Implemented internationalization (i18n) with initial support for English and Chinese.
- Restructured API clients, hooks, and Zustand stores into logical domains.
- Added new management pages for Settings, Logs, Models, Providers, and Credentials.
- Upgraded the Pico chat interface with session history management and dynamic model selection.
Build & Config:
- Updated frontend dependencies, Vite configuration, and lockfiles.
- Refined routing setup and overarching application stylesheets.
* feat(web): enhance model management, sorting, and deletion logic
- Implement model sorting in UI (default > configured > unconfigured)
- Prevent deletion of default models in the frontend
- Update backend to clear default settings when a model is deleted
- Add existence validation when setting a default model via API
- Group models in chat UI by type (API Key, OAuth, Local)
- Conditionally display model selector in chat based on configuration status
* refactor(web): refactor chat page into modular components/hooks and update i18n
- split chat route into dedicated chat components (page, composer, empty state, messages, history, model selector)
- extract model/session logic into use-chat-models and use-session-history hooks
- update chat locale keys in en/zh and add empty-state/history-related translations
* refactor(models): refactor models page into modular components and improve UX
- split /models route into dedicated components (page, provider section, card, add/edit sheets, delete dialog)
- add provider grouping/sorting, provider labels/icons, and a no-default hint in the models page
- add "Set as default model" toggle to add/edit flows with safer defaults
- introduce shared form helpers and new UI primitives (field, label, switch)
- update i18n strings (en/zh) for models and gateway header text usage
- apply minor UI polish (models nav icon, separator client directive)
* fix(web): add SPA index fallback for embedded frontend routes
Serve existing static assets as-is, keep /api/* and missing asset paths returning 404, and add tests for SPA fallback behavior on refresh.
* fix(frontend/chat): normalize message timestamp units to prevent invalid far-future dates
* chore: delete TestSPARouteFallsBackToIndex
* feat: update build for web-based launcher (#1186)
- Makefile: add build-launcher target (builds frontend + Go backend)
- GoReleaser: point picoclaw-launcher build to web/backend, add frontend
build hook, restore winres hook with updated paths
- Restore icon.ico and winres config from main for Windows builds
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(credentials): add multi-provider OAuth credential management
- add backend `/api/oauth/*` endpoints for provider status, browser/device-code/token login, flow query/polling, and logout
- extend API handler with OAuth flow/state tracking and route registration, plus OAuth unit tests
- implement frontend credentials page/components for OpenAI, Anthropic, and Google Antigravity login/logout
- add OAuth API client and `useCredentialsPage` hook, with new EN/ZH i18n strings
* chore: remove placeholder index.html from dist (#1188)
The .gitkeep is sufficient for go:embed to find the dist directory.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(frontend): polish model and credential UX; remove Providers nav
- remove the Providers item from sidebar navigation and locale keys
- simplify chat composer by dropping attach/voice action buttons
- support ReactNode titles in credential cards and add provider brand icons
- refine sheet header/footer styling and device-code footer button hierarchy
- disable “Set default” when a model is unconfigured or already default
* feat(web): Update config page (#1173)
* feat(web): Update config page
* fix(web): useEffect resets editorValue whenever config changes
* fix(web): react-hooks/set-state-in-effect error & pnpm lint #1173
* feat(web): add channel management page for web console (#1190)
* feat(web): add channel management page for web console
Add a complete channel management UI that allows users to configure
messaging channels (Telegram, Discord, Slack, Feishu, etc.) directly
from the web console instead of manually editing config.json.
Backend: GET/PUT/PATCH API endpoints for listing, updating, and
toggling channels with secret field masking.
Frontend: Channel cards grid with enable/disable toggles, per-channel
configuration sheets with dedicated forms for major platforms and a
generic fallback for others.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(web/channels): move channels to own sidebar group and fix sheet padding
- Channels now has its own navigation group instead of being under Services
- Fix edit sheet form content padding (px-1 -> px-4) to match header/footer
- Fix naked return lint error in extractChannelInfo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(web): harden channel config updates and resolve frontend lint issues
- validate channel PUT/PATCH updates before saving and return structured validation errors
- require `enabled` in toggle requests to avoid silent false defaults
- support editing `allow_origins` in the generic channel form and parse string/array inputs on backend
- replace channel form `any` usage with `ChannelConfig` (`Record<string, unknown>`) and add safe value helpers
- add i18n strings for allow-origins fields and apply related frontend formatting cleanups
* fix(frontend): prevent false "Invalid JSON" errors in config editor
* feat: add startup readiness checks and propagate start availability to UI
- add gateway precondition validation for default model and credentials
- auto-start gateway on backend boot when conditions are met
- include gateway_start_allowed and gateway_start_reason in status updates
- prevent frontend start actions when gateway cannot be started
* feat(web): revamp channel config UX with catalog-based routing
- replace legacy channel management endpoints with a backend channel catalog API
- switch frontend channel updates to PATCH /api/config and per-channel config pages
- add dynamic channel items in the sidebar with support for expand/collapse
- migrate /channels to nested routes (/channels/$name) and remove old card/sheet flow
- improve channel forms with clearer hints, required/error states, and reusable switch cards
- fix Discord mention-only toggle to read/write group_trigger.mention_only
* refactor(frontend): move shared-form to components and unify default-model switch with SwitchCardField
* fix(frontend): improve model form validation and unify secret placeholder handling
- block duplicate model aliases when adding a model (with localized error messages)
- share masked secret placeholder logic across model and channel forms
- refresh gateway state after setting the default model
- apply minor UI cleanup to provider icon rendering
* feat(web): add visual system config and launcher/autostart controls
- add launcher config model and persistence (`launcher-config.json`) for port/public/CIDR settings
- add system APIs for launch-at-login and launcher parameters
- apply CIDR-based access-control middleware to backend HTTP routes
- split config routing into visual config and raw JSON config pages
- add frontend system API client and visual config sections for runtime/devices/launcher
- expand i18n strings (en/zh) for new config UI
- improve sidebar active matching and session ID generation fallback
* refactor(frontend): remove i18n fallback strings and drop providers route
- Replace `t(key, defaultValue)` calls with key-only translations across UI pages
- Clean up locale files by pruning unused keys and adding missing shared keys
- Remove the obsolete `/providers` page and update generated route tree
* fix(backend): correct gateway status detection on Windows
* fix(repo): keep web backend dist placeholder tracked
---------
Co-authored-by: Guoguo <16666742+imguoguo@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Dihubopen <dihubcn@gmail.com>
Co-authored-by: Dihubopen <130813726+Dihubopen@users.noreply.github.com>
2026-03-09 11:42:03 +00:00
2026-03-30 06:45:52 +00:00
build-launcher-frontend :
@$( MAKE) -C web build-frontend
2026-02-23 03:22:32 +00:00
## build-whatsapp-native: Build with WhatsApp native (whatsmeow) support; larger binary
build-whatsapp-native : generate
2026-02-23 04:58:59 +00:00
## @echo "Building $(BINARY_NAME) with WhatsApp native for $(PLATFORM)/$(ARCH)..."
@echo "Building for multiple platforms..."
2026-02-23 03:22:32 +00:00
@mkdir -p $( BUILD_DIR)
2026-03-24 15:40:51 +00:00
GOOS = linux GOARCH = amd64 $( GO) build -tags $( GO_BUILD_TAGS) ,whatsapp_native -ldflags " $( LDFLAGS) " -o $( BUILD_DIR) /$( BINARY_NAME) -linux-amd64 ./$( CMD_DIR)
GOOS = linux GOARCH = arm GOARM = 7 $( GO) build -tags $( GO_BUILD_TAGS) ,whatsapp_native -ldflags " $( LDFLAGS) " -o $( BUILD_DIR) /$( BINARY_NAME) -linux-arm ./$( CMD_DIR)
GOOS = linux GOARCH = arm64 $( GO) build -tags $( GO_BUILD_TAGS) ,whatsapp_native -ldflags " $( LDFLAGS) " -o $( BUILD_DIR) /$( BINARY_NAME) -linux-arm64 ./$( CMD_DIR)
GOOS = linux GOARCH = loong64 $( GO) build -tags $( GO_BUILD_TAGS) ,whatsapp_native -ldflags " $( LDFLAGS) " -o $( BUILD_DIR) /$( BINARY_NAME) -linux-loong64 ./$( CMD_DIR)
GOOS = linux GOARCH = riscv64 $( GO) build -tags $( GO_BUILD_TAGS) ,whatsapp_native -ldflags " $( LDFLAGS) " -o $( BUILD_DIR) /$( BINARY_NAME) -linux-riscv64 ./$( CMD_DIR)
GOOS = linux GOARCH = mipsle GOMIPS = softfloat $( GO) build -tags $( GO_BUILD_TAGS_NO_GOOLM) ,whatsapp_native -ldflags " $( LDFLAGS) " -o $( BUILD_DIR) /$( BINARY_NAME) -linux-mipsle ./$( CMD_DIR)
2026-03-06 11:54:56 +00:00
$( call PATCH_MIPS_FLAGS,$( BUILD_DIR) /$( BINARY_NAME) -linux-mipsle)
2026-03-24 15:40:51 +00:00
GOOS = darwin GOARCH = arm64 $( GO) build -tags $( GO_BUILD_TAGS) ,whatsapp_native -ldflags " $( LDFLAGS) " -o $( BUILD_DIR) /$( BINARY_NAME) -darwin-arm64 ./$( CMD_DIR)
GOOS = windows GOARCH = amd64 $( GO) build -tags $( GO_BUILD_TAGS) ,whatsapp_native -ldflags " $( LDFLAGS) " -o $( BUILD_DIR) /$( BINARY_NAME) -windows-amd64.exe ./$( CMD_DIR)
2026-03-17 06:12:32 +00:00
## @$(GO) build $(GOFLAGS) -tags whatsapp_native -ldflags "$(LDFLAGS)" -o $(BINARY_PATH) ./$(CMD_DIR)
2026-02-23 04:58:59 +00:00
@echo "Build complete"
## @ln -sf $(BINARY_NAME)-$(PLATFORM)-$(ARCH) $(BUILD_DIR)/$(BINARY_NAME)
2026-02-23 03:22:32 +00:00
2026-02-22 20:29:27 +00:00
## build-linux-arm: Build for Linux ARMv7 (e.g. Raspberry Pi Zero 2 W 32-bit)
build-linux-arm : generate
@echo "Building for linux/arm (GOARM=7)..."
@mkdir -p $( BUILD_DIR)
2026-03-24 15:40:51 +00:00
GOOS = linux GOARCH = arm GOARM = 7 $( GO) build $( GOFLAGS) -ldflags " $( LDFLAGS) " -o $( BUILD_DIR) /$( BINARY_NAME) -linux-arm ./$( CMD_DIR)
2026-02-22 20:29:27 +00:00
@echo " Build complete: $( BUILD_DIR) / $( BINARY_NAME) -linux-arm "
## build-linux-arm64: Build for Linux ARM64 (e.g. Raspberry Pi Zero 2 W 64-bit)
build-linux-arm64 : generate
@echo "Building for linux/arm64..."
@mkdir -p $( BUILD_DIR)
2026-03-24 15:40:51 +00:00
GOOS = linux GOARCH = arm64 $( GO) build $( GOFLAGS) -ldflags " $( LDFLAGS) " -o $( BUILD_DIR) /$( BINARY_NAME) -linux-arm64 ./$( CMD_DIR)
2026-02-22 20:29:27 +00:00
@echo " Build complete: $( BUILD_DIR) / $( BINARY_NAME) -linux-arm64 "
2026-03-06 11:54:56 +00:00
## build-linux-mipsle: Build for Linux MIPS32 LE
build-linux-mipsle : generate
@echo "Building for linux/mipsle (softfloat)..."
@mkdir -p $( BUILD_DIR)
2026-03-24 15:40:51 +00:00
GOOS = linux GOARCH = mipsle GOMIPS = softfloat $( GO) build $( GOFLAGS_NO_GOOLM) -ldflags " $( LDFLAGS) " -o $( BUILD_DIR) /$( BINARY_NAME) -linux-mipsle ./$( CMD_DIR)
2026-03-06 11:54:56 +00:00
$( call PATCH_MIPS_FLAGS,$( BUILD_DIR) /$( BINARY_NAME) -linux-mipsle)
@echo " Build complete: $( BUILD_DIR) / $( BINARY_NAME) -linux-mipsle "
2026-04-12 09:41:10 +00:00
## build-android-arm64: Build core for Android ARM64
build-android-arm64 : generate
@echo "Building for android/arm64..."
@mkdir -p $( BUILD_DIR)
GOOS = android GOARCH = arm64 $( GO) build -tags stdjson -ldflags " $( LDFLAGS) " -o $( BUILD_DIR) /$( BINARY_NAME) -android-arm64 ./$( CMD_DIR)
@echo " Build complete: $( BUILD_DIR) / $( BINARY_NAME) -android-arm64 "
## build-launcher-android-arm64: Build launcher for Android ARM64
build-launcher-android-arm64 :
@echo "Building picoclaw-launcher for android/arm64..."
@mkdir -p $( BUILD_DIR)
2026-04-12 10:50:52 +00:00
@$( MAKE) -C web build-android-arm64 \
2026-04-13 03:23:55 +00:00
OUTPUT_ANDROID_ARM64 = " $( CURDIR) / $( BUILD_DIR) /picoclaw-launcher-android-arm64 " \
GO = '$(GO)' \
LDFLAGS = '$(LDFLAGS)'
2026-04-12 09:41:10 +00:00
@echo " Build complete: $( BUILD_DIR) /picoclaw-launcher-android-arm64 "
2026-04-12 10:50:52 +00:00
## build-android-bundle: Build core and launcher for all Android architectures and package as universal zip
build-android-bundle : generate
2026-04-12 09:41:10 +00:00
@echo "Building core for all Android architectures..."
@mkdir -p $( BUILD_DIR)
GOOS = android GOARCH = arm64 $( GO) build -tags stdjson -ldflags " $( LDFLAGS) " -o $( BUILD_DIR) /$( BINARY_NAME) -android-arm64 ./$( CMD_DIR)
@echo "Building launcher for Android arm64..."
@$( MAKE) build-launcher-android-arm64
@echo "Staging JNI libs..."
@rm -rf $( BUILD_DIR) /android-staging
@mkdir -p $( BUILD_DIR) /android-staging/arm64-v8a
@cp $( BUILD_DIR) /$( BINARY_NAME) -android-arm64 $( BUILD_DIR) /android-staging/arm64-v8a/libpicoclaw.so
@cp $( BUILD_DIR) /picoclaw-launcher-android-arm64 $( BUILD_DIR) /android-staging/arm64-v8a/libpicoclaw-web.so
@cd $( BUILD_DIR) /android-staging && zip -r ../picoclaw-android-universal.zip .
@rm -rf $( BUILD_DIR) /android-staging
@echo " All Android builds complete: $( BUILD_DIR) /picoclaw-android-universal.zip "
2026-02-22 20:29:27 +00:00
## build-pi-zero: Build for Raspberry Pi Zero 2 W (32-bit and 64-bit)
build-pi-zero : build -linux -arm build -linux -arm 64
@echo " Pi Zero 2 W builds: $( BUILD_DIR) / $( BINARY_NAME) -linux-arm (32-bit), $( BUILD_DIR) / $( BINARY_NAME) -linux-arm64 (64-bit) "
2026-04-13 03:52:35 +00:00
## build-all: Build the picoclaw core binary for all Makefile-managed platforms
build-all : generate
2026-02-04 11:06:13 +00:00
@echo "Building for multiple platforms..."
@mkdir -p $( BUILD_DIR)
2026-03-24 15:40:51 +00:00
GOOS = linux GOARCH = amd64 $( GO) build $( GOFLAGS) -ldflags " $( LDFLAGS) " -o $( BUILD_DIR) /$( BINARY_NAME) -linux-amd64 ./$( CMD_DIR)
GOOS = linux GOARCH = arm GOARM = 7 $( GO) build $( GOFLAGS) -ldflags " $( LDFLAGS) " -o $( BUILD_DIR) /$( BINARY_NAME) -linux-arm ./$( CMD_DIR)
GOOS = linux GOARCH = arm64 $( GO) build $( GOFLAGS) -ldflags " $( LDFLAGS) " -o $( BUILD_DIR) /$( BINARY_NAME) -linux-arm64 ./$( CMD_DIR)
feat(tools): add exec tool enhancement with background execution and PTY support (#1752)
- Unified exec tool with actions: run/list/poll/read/write/send-keys/kill
- PTY support using creack/pty library
- Process session management with background execution
- Process group kill for cleaning up child processes
- Session cleanup: 30-minute TTL for old sessions
- Output buffer: 100MB limit with truncation
Actions:
- run: execute command (sync or background)
- list: list all sessions
- poll: check session status
- read: read session output
- write: send input to session stdin
- send-keys: send special keys (up, down, ctrl-c, enter, etc.)
- kill: terminate session
Tests:
- PTY: allowed commands, write/read, poll, kill, process group kill
- Non-PTY: background execution, list, read, write, poll, kill, process group kill
- Session management: add/get/remove/list/cleanup
2026-03-21 14:38:03 +00:00
@$( PTY_PATCH_LOONG64)
2026-03-24 15:40:51 +00:00
GOOS = linux GOARCH = loong64 $( GO) build $( GOFLAGS) -ldflags " $( LDFLAGS) " -o $( BUILD_DIR) /$( BINARY_NAME) -linux-loong64 ./$( CMD_DIR)
GOOS = linux GOARCH = riscv64 $( GO) build $( GOFLAGS) -ldflags " $( LDFLAGS) " -o $( BUILD_DIR) /$( BINARY_NAME) -linux-riscv64 ./$( CMD_DIR)
GOOS = linux GOARCH = mipsle GOMIPS = softfloat $( GO) build $( GOFLAGS_NO_GOOLM) -ldflags " $( LDFLAGS) " -o $( BUILD_DIR) /$( BINARY_NAME) -linux-mipsle ./$( CMD_DIR)
2026-03-06 11:54:56 +00:00
$( call PATCH_MIPS_FLAGS,$( BUILD_DIR) /$( BINARY_NAME) -linux-mipsle)
2026-03-24 15:40:51 +00:00
GOOS = linux GOARCH = arm GOARM = 7 $( GO) build $( GOFLAGS) -ldflags " $( LDFLAGS) " -o $( BUILD_DIR) /$( BINARY_NAME) -linux-armv7 ./$( CMD_DIR)
GOOS = darwin GOARCH = arm64 $( GO) build $( GOFLAGS) -ldflags " $( LDFLAGS) " -o $( BUILD_DIR) /$( BINARY_NAME) -darwin-arm64 ./$( CMD_DIR)
GOOS = windows GOARCH = amd64 $( GO) build $( GOFLAGS) -ldflags " $( LDFLAGS) " -o $( BUILD_DIR) /$( BINARY_NAME) -windows-amd64.exe ./$( CMD_DIR)
GOOS = netbsd GOARCH = amd64 $( GO) build $( GOFLAGS) -ldflags " $( LDFLAGS) " -o $( BUILD_DIR) /$( BINARY_NAME) -netbsd-amd64 ./$( CMD_DIR)
GOOS = netbsd GOARCH = arm64 $( GO) build $( GOFLAGS) -ldflags " $( LDFLAGS) " -o $( BUILD_DIR) /$( BINARY_NAME) -netbsd-arm64 ./$( CMD_DIR)
2026-04-13 03:23:55 +00:00
@echo "Core builds complete"
2026-02-04 11:06:13 +00:00
## install: Install picoclaw to system and copy builtin skills
install : build
@echo " Installing $( BINARY_NAME) ... "
@mkdir -p $( INSTALL_BIN_DIR)
2026-02-23 10:29:43 +00:00
# Copy binary with temporary suffix to ensure atomic update
@cp $( BUILD_DIR) /$( BINARY_NAME) $( INSTALL_BIN_DIR) /$( BINARY_NAME) $( INSTALL_TMP_SUFFIX)
@chmod +x $( INSTALL_BIN_DIR) /$( BINARY_NAME) $( INSTALL_TMP_SUFFIX)
@mv -f $( INSTALL_BIN_DIR) /$( BINARY_NAME) $( INSTALL_TMP_SUFFIX) $( INSTALL_BIN_DIR) /$( BINARY_NAME)
2026-02-04 11:06:13 +00:00
@echo " Installed binary to $( INSTALL_BIN_DIR) / $( BINARY_NAME) "
@echo "Installation complete!"
## uninstall: Remove picoclaw from system
uninstall :
@echo " Uninstalling $( BINARY_NAME) ... "
@rm -f $( INSTALL_BIN_DIR) /$( BINARY_NAME)
@echo " Removed binary from $( INSTALL_BIN_DIR) / $( BINARY_NAME) "
@echo "Note: Only the executable file has been deleted."
@echo "If you need to delete all configurations (config.json, workspace, etc.), run 'make uninstall-all'"
## uninstall-all: Remove picoclaw and all data
uninstall-all :
@echo "Removing workspace and skills..."
@rm -rf $( PICOCLAW_HOME)
@echo " Removed workspace: $( PICOCLAW_HOME) "
@echo "Complete uninstallation done!"
## clean: Remove build artifacts
clean :
@echo "Cleaning build artifacts..."
2026-04-24 09:50:59 +00:00
i f e q ( $( OS ) , W i n d o w s _ N T )
@$( POWERSHELL) " if (Test-Path -LiteralPath ' $( BUILD_DIR) ') { Remove-Item -LiteralPath ' $( BUILD_DIR) ' -Recurse -Force } "
e l s e
2026-02-04 11:06:13 +00:00
@rm -rf $( BUILD_DIR)
2026-04-24 09:50:59 +00:00
e n d i f
2026-02-04 11:06:13 +00:00
@echo "Clean complete"
2026-02-16 07:48:02 +00:00
## vet: Run go vet for static analysis
2026-02-23 12:45:04 +00:00
vet : generate
2026-03-23 01:29:17 +00:00
@packages= " $$ ( $( GO) list $( GOFLAGS) ./...) " && \
$( GO) vet $( GOFLAGS) $$ ( printf '%s\n' " $$ packages " | grep -v '^github.com/sipeed/picoclaw/web/' )
2026-03-17 07:23:49 +00:00
@cd web/backend && $( WEB_GO) vet ./...
2026-02-14 23:43:46 +00:00
2026-02-18 19:48:23 +00:00
## test: Test Go code
2026-02-23 12:45:04 +00:00
test : generate
2026-03-23 01:29:17 +00:00
@$( GO) test $( GOFLAGS) $$ ( $( GO) list $( GOFLAGS) ./... | grep -v github.com/sipeed/picoclaw/web/)
2026-03-17 06:12:32 +00:00
@cd web && make test
2026-02-14 23:43:46 +00:00
2026-02-04 11:06:13 +00:00
## fmt: Format Go code
fmt :
2026-02-18 19:48:23 +00:00
@$( GOLANGCI_LINT) fmt
2026-04-17 05:45:39 +00:00
## lint-docs: Check common documentation layout and naming conventions
lint-docs :
@./scripts/lint-docs.sh
2026-02-18 19:48:23 +00:00
## lint: Run linters
lint :
2026-03-25 06:42:29 +00:00
@$( GOLANGCI_LINT) run --build-tags $( GO_BUILD_TAGS)
2026-04-17 05:45:39 +00:00
@./scripts/lint-docs.sh
2026-02-04 11:06:13 +00:00
2026-02-24 11:04:23 +00:00
## fix: Fix linting issues
fix :
2026-03-25 06:42:29 +00:00
@$( GOLANGCI_LINT) run --fix --build-tags $( GO_BUILD_TAGS)
2026-02-24 11:04:23 +00:00
2026-02-16 07:48:02 +00:00
## deps: Download dependencies
2026-02-04 11:06:13 +00:00
deps :
2026-02-16 07:48:02 +00:00
@$( GO) mod download
@$( GO) mod verify
## update-deps: Update dependencies
update-deps :
2026-02-04 11:06:13 +00:00
@$( GO) get -u ./...
@$( GO) mod tidy
2026-04-17 05:45:39 +00:00
## check: Run deps, fmt, vet, tests, and docs consistency checks
check : deps fmt vet test lint -docs
2026-02-16 07:48:02 +00:00
2026-02-04 11:06:13 +00:00
## run: Build and run picoclaw
run : build
@$( BUILD_DIR) /$( BINARY_NAME) $( ARGS)
2026-02-16 06:48:40 +00:00
## docker-build: Build Docker image (minimal Alpine-based)
docker-build :
@echo "Building minimal Docker image (Alpine-based)..."
2026-03-01 02:56:02 +00:00
docker compose -f docker/docker-compose.yml build picoclaw-agent picoclaw-gateway
2026-02-16 06:48:40 +00:00
2026-02-16 07:40:07 +00:00
## docker-build-full: Build Docker image with full MCP support (Node.js 24)
2026-02-16 06:48:40 +00:00
docker-build-full :
2026-02-16 07:40:07 +00:00
@echo "Building full-featured Docker image (Node.js 24)..."
2026-03-01 02:56:02 +00:00
docker compose -f docker/docker-compose.full.yml build picoclaw-agent picoclaw-gateway
2026-02-16 06:48:40 +00:00
## docker-test: Test MCP tools in Docker container
docker-test :
@echo "Testing MCP tools in Docker..."
@chmod +x scripts/test-docker-mcp.sh
@./scripts/test-docker-mcp.sh
## docker-run: Run picoclaw gateway in Docker (Alpine-based)
docker-run :
2026-03-01 02:56:02 +00:00
docker compose -f docker/docker-compose.yml --profile gateway up
2026-02-16 06:48:40 +00:00
## docker-run-full: Run picoclaw gateway in Docker (full-featured)
docker-run-full :
2026-03-01 02:56:02 +00:00
docker compose -f docker/docker-compose.full.yml --profile gateway up
2026-02-16 06:48:40 +00:00
## docker-run-agent: Run picoclaw agent in Docker (interactive, Alpine-based)
docker-run-agent :
2026-03-01 02:56:02 +00:00
docker compose -f docker/docker-compose.yml run --rm picoclaw-agent
2026-02-16 06:48:40 +00:00
## docker-run-agent-full: Run picoclaw agent in Docker (interactive, full-featured)
docker-run-agent-full :
2026-03-01 02:56:02 +00:00
docker compose -f docker/docker-compose.full.yml run --rm picoclaw-agent
2026-02-16 06:48:40 +00:00
## docker-clean: Clean Docker images and volumes
docker-clean :
2026-03-01 02:56:02 +00:00
docker compose -f docker/docker-compose.yml down -v
docker compose -f docker/docker-compose.full.yml down -v
2026-02-16 06:48:40 +00:00
docker rmi picoclaw:latest picoclaw:full 2>/dev/null || true
2026-03-18 06:43:58 +00:00
## build-macos-app: Build PicoClaw macOS .app bundle (no terminal window)
2026-04-01 15:56:46 +00:00
build-macos-app : build -launcher
2026-03-18 06:43:58 +00:00
@echo "Building macOS .app bundle..."
@if [ " $( UNAME_S) " != "Darwin" ] ; then \
echo "Error: This target is only available on macOS" ; \
exit 1; \
fi
2026-04-01 15:56:46 +00:00
@./scripts/build-macos-app.sh $( PLATFORM) -$( ARCH)
2026-03-18 06:43:58 +00:00
@echo " macOS .app bundle created: $( BUILD_DIR) /PicoClaw.app "
2026-04-06 09:26:43 +00:00
## mem: Build membench, download LOCOMO data (if needed), run benchmark, and show results
mem :
@echo "Building membench..."
@mkdir -p $( BUILD_DIR)
@$( GO) build -o $( BUILD_DIR) /membench ./cmd/membench
@echo " Build complete: $( BUILD_DIR) /membench "
@if [ ! -f $( BUILD_DIR) /memdata/locomo10.json ] ; then \
echo "Downloading LOCOMO dataset..." ; \
mkdir -p $( BUILD_DIR) /memdata; \
curl -sfL "https://raw.githubusercontent.com/snap-research/locomo/main/data/locomo10.json" \
-o $( BUILD_DIR) /memdata/locomo10.json && [ -s $( BUILD_DIR) /memdata/locomo10.json ] || { echo "Error: LOCOMO download failed" ; exit 1; } ; \
echo "Download complete" ; \
else \
echo "LOCOMO dataset already exists, skipping download" ; \
fi
@echo "Running benchmark..."
@rm -rf $( BUILD_DIR) /memout
@$( BUILD_DIR) /membench run --data $( BUILD_DIR) /memdata --out $( BUILD_DIR) /memout --budget 4000
2026-02-04 11:06:13 +00:00
## help: Show this help message
help :
@echo "picoclaw Makefile"
@echo ""
@echo "Usage:"
@echo " make [target]"
@echo ""
@echo "Targets:"
2026-02-24 11:04:23 +00:00
@grep -E '^## ' $( MAKEFILE_LIST) | sort | awk -F': ' '{printf " %-16s %s\n", substr($$1, 4), $$2}'
2026-02-04 11:06:13 +00:00
@echo ""
@echo "Examples:"
@echo " make build # Build for current platform"
2026-02-11 12:41:40 +00:00
@echo " make install # Install to ~/.local/bin"
2026-02-04 11:06:13 +00:00
@echo " make uninstall # Remove from /usr/local/bin"
@echo " make install-skills # Install skills to workspace"
2026-02-16 06:48:40 +00:00
@echo " make docker-build # Build minimal Docker image"
@echo " make docker-test # Test MCP tools in Docker"
2026-02-04 11:06:13 +00:00
@echo ""
@echo "Environment Variables:"
2026-02-11 12:41:40 +00:00
@echo " INSTALL_PREFIX # Installation prefix (default: ~/.local)"
2026-02-04 11:06:13 +00:00
@echo " WORKSPACE_DIR # Workspace directory (default: ~/.picoclaw/workspace)"
@echo " VERSION # Version string (default: git describe)"
@echo ""
@echo "Current Configuration:"
@echo " Platform: $( PLATFORM) / $( ARCH) "
@echo " Binary: $( BINARY_PATH) "
@echo " Install Prefix: $( INSTALL_PREFIX) "
@echo " Workspace: $( WORKSPACE_DIR) "