From f7e768152e076d863ce3bd20019256dc96fad44e Mon Sep 17 00:00:00 2001
From: Liu Yuan
Date: Mon, 13 Apr 2026 11:04:45 +0800
Subject: [PATCH 1/6] feat(agent): /clear now clears seahorse DB in addition to
JSONL
- Add Clear(ctx, sessionKey) to ContextManager interface
- Implement Clear for legacy (JSONL) and seahorse (DB + JSONL)
- Add Engine.ClearSession + Store.ClearConversation
- Fix FTS5 DELETE trigger syntax in schema (was using wrong
external-content FTS5 syntax; now uses standard DELETE FROM)
- Fix ClearSession to skip sessions never ingested (was creating
blank conversations record via GetOrCreateConversation)
- Simplify summary_parents DELETE into single OR statement
- Add TestStoreClearConversation unit test
---
pkg/agent/context_legacy.go | 10 ++++
pkg/agent/context_manager.go | 4 ++
pkg/agent/context_manager_test.go | 3 ++
pkg/agent/context_seahorse.go | 13 +++++
pkg/agent/loop.go | 17 +++---
pkg/seahorse/schema.go | 4 +-
pkg/seahorse/short_engine.go | 13 +++++
pkg/seahorse/store.go | 51 ++++++++++++++++++
pkg/seahorse/store_test.go | 90 ++++++++++++++++++++++++++++++-
9 files changed, 192 insertions(+), 13 deletions(-)
diff --git a/pkg/agent/context_legacy.go b/pkg/agent/context_legacy.go
index 0f10decb3..85e331ae9 100644
--- a/pkg/agent/context_legacy.go
+++ b/pkg/agent/context_legacy.go
@@ -61,6 +61,16 @@ func (m *legacyContextManager) Ingest(_ context.Context, _ *IngestRequest) error
return nil
}
+func (m *legacyContextManager) Clear(_ context.Context, sessionKey string) error {
+ agent := m.al.registry.GetDefaultAgent()
+ if agent == nil || agent.Sessions == nil {
+ return fmt.Errorf("sessions not initialized")
+ }
+ agent.Sessions.SetHistory(sessionKey, []providers.Message{})
+ agent.Sessions.SetSummary(sessionKey, "")
+ return agent.Sessions.Save(sessionKey)
+}
+
// maybeSummarize triggers summarization if the session history exceeds thresholds.
// It runs asynchronously in a goroutine.
func (m *legacyContextManager) maybeSummarize(sessionKey string) {
diff --git a/pkg/agent/context_manager.go b/pkg/agent/context_manager.go
index 5f8701812..5a5dfe97c 100644
--- a/pkg/agent/context_manager.go
+++ b/pkg/agent/context_manager.go
@@ -24,6 +24,10 @@ type ContextManager interface {
// Ingest records a message into the ContextManager's own storage.
// Called after each message is persisted to session JSONL.
Ingest(ctx context.Context, req *IngestRequest) error
+
+ // Clear removes all stored context for a session (messages, summaries, etc.).
+ // Called when the user issues /clear or /reset.
+ Clear(ctx context.Context, sessionKey string) error
}
// AssembleRequest is the input to Assemble.
diff --git a/pkg/agent/context_manager_test.go b/pkg/agent/context_manager_test.go
index 6bde5e1a9..629d11fcb 100644
--- a/pkg/agent/context_manager_test.go
+++ b/pkg/agent/context_manager_test.go
@@ -690,6 +690,7 @@ func (m *noopContextManager) Assemble(_ context.Context, req *AssembleRequest) (
}
func (m *noopContextManager) Compact(_ context.Context, _ *CompactRequest) error { return nil }
func (m *noopContextManager) Ingest(_ context.Context, _ *IngestRequest) error { return nil }
+func (m *noopContextManager) Clear(_ context.Context, _ string) error { return nil }
// trackingContextManager tracks call counts for each method.
type trackingContextManager struct {
@@ -726,6 +727,8 @@ func (m *trackingContextManager) Ingest(_ context.Context, req *IngestRequest) e
return nil
}
+func (m *trackingContextManager) Clear(_ context.Context, _ string) error { return nil }
+
// resetCMRegistry clears the global factory registry and returns a cleanup
// function that restores the original state after the test.
func resetCMRegistry() func() {
diff --git a/pkg/agent/context_seahorse.go b/pkg/agent/context_seahorse.go
index 327c6162a..c6e5b30ac 100644
--- a/pkg/agent/context_seahorse.go
+++ b/pkg/agent/context_seahorse.go
@@ -154,6 +154,19 @@ func (m *seahorseContextManager) Ingest(ctx context.Context, req *IngestRequest)
return err
}
+// Clear removes all stored context for a session (seahorse DB + JSONL).
+func (m *seahorseContextManager) Clear(ctx context.Context, sessionKey string) error {
+ if err := m.engine.ClearSession(ctx, sessionKey); err != nil {
+ return err
+ }
+ if m.sessions != nil {
+ m.sessions.SetHistory(sessionKey, []providers.Message{})
+ m.sessions.SetSummary(sessionKey, "")
+ return m.sessions.Save(sessionKey)
+ }
+ return nil
+}
+
// bootstrapSession reconciles JSONL session history into seahorse SQLite.
func (m *seahorseContextManager) bootstrapSession(ctx context.Context, sessionKey string) {
if m.sessions == nil {
diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go
index a856c0fca..f67802663 100644
--- a/pkg/agent/loop.go
+++ b/pkg/agent/loop.go
@@ -3368,7 +3368,7 @@ func (al *AgentLoop) handleCommand(
return "", false
}
- rt := al.buildCommandsRuntime(agent, opts)
+ rt := al.buildCommandsRuntime(ctx, agent, opts)
executor := commands.NewExecutor(al.cmdRegistry, rt)
var commandReply string
@@ -3488,7 +3488,11 @@ func (al *AgentLoop) applyExplicitSkillCommand(
return true, false, ""
}
-func (al *AgentLoop) buildCommandsRuntime(agent *AgentInstance, opts *processOptions) *commands.Runtime {
+func (al *AgentLoop) buildCommandsRuntime(
+ ctx context.Context,
+ agent *AgentInstance,
+ opts *processOptions,
+) *commands.Runtime {
registry := al.GetRegistry()
cfg := al.GetConfig()
rt := &commands.Runtime{
@@ -3570,14 +3574,7 @@ func (al *AgentLoop) buildCommandsRuntime(agent *AgentInstance, opts *processOpt
if opts == nil {
return fmt.Errorf("process options not available")
}
- if agent.Sessions == nil {
- return fmt.Errorf("sessions not initialized for agent")
- }
-
- agent.Sessions.SetHistory(opts.SessionKey, make([]providers.Message, 0))
- agent.Sessions.SetSummary(opts.SessionKey, "")
- agent.Sessions.Save(opts.SessionKey)
- return nil
+ return al.contextManager.Clear(ctx, opts.SessionKey)
}
}
return rt
diff --git a/pkg/seahorse/schema.go b/pkg/seahorse/schema.go
index effa6d60d..bf32d548b 100644
--- a/pkg/seahorse/schema.go
+++ b/pkg/seahorse/schema.go
@@ -123,10 +123,10 @@ func runSchema(db *sql.DB) error {
INSERT INTO summaries_fts (summary_id, content) VALUES (new.summary_id, new.content);
END`,
`CREATE TRIGGER IF NOT EXISTS summaries_ad AFTER DELETE ON summaries BEGIN
- INSERT INTO summaries_fts (summaries_fts, summary_id, content) VALUES ('delete', old.summary_id, old.content);
+ DELETE FROM summaries_fts WHERE summary_id = old.summary_id;
END`,
`CREATE TRIGGER IF NOT EXISTS summaries_au AFTER UPDATE ON summaries BEGIN
- INSERT INTO summaries_fts (summaries_fts, summary_id, content) VALUES ('delete', old.summary_id, old.content);
+ DELETE FROM summaries_fts WHERE summary_id = old.summary_id;
INSERT INTO summaries_fts (summary_id, content) VALUES (new.summary_id, new.content);
END`,
diff --git a/pkg/seahorse/short_engine.go b/pkg/seahorse/short_engine.go
index 4cd4d3887..f584788ce 100644
--- a/pkg/seahorse/short_engine.go
+++ b/pkg/seahorse/short_engine.go
@@ -377,6 +377,19 @@ func (e *Engine) IngestMessages(ctx context.Context, sessionKey string, messages
return e.Ingest(ctx, sessionKey, messages)
}
+// ClearSession removes all stored data for a session (messages, summaries, context).
+// If the session has no prior seahorse record, it is a no-op.
+func (e *Engine) ClearSession(ctx context.Context, sessionKey string) error {
+ conv, err := e.store.GetConversationBySessionKey(ctx, sessionKey)
+ if err != nil {
+ return err
+ }
+ if conv == nil {
+ return nil // session never ingested, nothing to clear
+ }
+ return e.store.ClearConversation(ctx, conv.ConversationID)
+}
+
// Bootstrap reconciles a session's messages with the database.
// Called once at startup for each known session.
// Bootstrap reconciles JSONL history with SQLite by ingesting only the delta.
diff --git a/pkg/seahorse/store.go b/pkg/seahorse/store.go
index 3026533b2..c84aaaf07 100644
--- a/pkg/seahorse/store.go
+++ b/pkg/seahorse/store.go
@@ -728,6 +728,57 @@ func (s *Store) DeleteMessagesAfterID(ctx context.Context, convID int64, afterID
return tx.Commit()
}
+// ClearConversation removes all data for a conversation from all tables.
+// Deletes context_items, summary_messages, summary_parents (via subquery), summaries,
+// message_parts, and messages. FTS entries are handled automatically by triggers.
+// Uses a transaction for atomicity.
+func (s *Store) ClearConversation(ctx context.Context, convID int64) error {
+ tx, err := s.db.BeginTx(ctx, nil)
+ if err != nil {
+ return err
+ }
+ defer tx.Rollback()
+
+ // Delete in child→parent order. FTS tables (messages_fts, summaries_fts) are
+ // kept in sync by DELETE triggers, so we just delete from the parent tables.
+
+ if _, err := tx.ExecContext(ctx,
+ "DELETE FROM context_items WHERE conversation_id = ?", convID); err != nil {
+ return fmt.Errorf("context_items: %w", err)
+ }
+ if _, err := tx.ExecContext(ctx,
+ `DELETE FROM summary_messages WHERE summary_id IN (
+ SELECT summary_id FROM summaries WHERE conversation_id = ?
+ )`, convID); err != nil {
+ return fmt.Errorf("summary_messages: %w", err)
+ }
+ // Note: summary_parents has no convID column; delete via subquery on summaries
+ if _, err := tx.ExecContext(ctx,
+ `DELETE FROM summary_parents WHERE summary_id IN (
+ SELECT summary_id FROM summaries WHERE conversation_id = ?
+ ) OR parent_summary_id IN (
+ SELECT summary_id FROM summaries WHERE conversation_id = ?
+ )`, convID, convID); err != nil {
+ return fmt.Errorf("summary_parents: %w", err)
+ }
+ if _, err := tx.ExecContext(ctx,
+ "DELETE FROM summaries WHERE conversation_id = ?", convID); err != nil {
+ return fmt.Errorf("summaries: %w", err)
+ }
+ if _, err := tx.ExecContext(ctx,
+ `DELETE FROM message_parts WHERE message_id IN (
+ SELECT message_id FROM messages WHERE conversation_id = ?
+ )`, convID); err != nil {
+ return fmt.Errorf("message_parts: %w", err)
+ }
+ if _, err := tx.ExecContext(ctx,
+ "DELETE FROM messages WHERE conversation_id = ?", convID); err != nil {
+ return fmt.Errorf("messages: %w", err)
+ }
+
+ return tx.Commit()
+}
+
// AppendContextMessage appends a single message to context_items at next ordinal.
func (s *Store) AppendContextMessage(ctx context.Context, convID int64, messageID int64) error {
return s.appendContextItems(ctx, convID, []ContextItem{
diff --git a/pkg/seahorse/store_test.go b/pkg/seahorse/store_test.go
index fd55379c6..89635cc9a 100644
--- a/pkg/seahorse/store_test.go
+++ b/pkg/seahorse/store_test.go
@@ -79,7 +79,95 @@ func TestStoreGetConversationBySessionKey(t *testing.T) {
}
}
-// --- Message Operations ---
+// --- Conversation Clear ---
+
+func TestStoreClearConversation(t *testing.T) {
+ s := openTestStore(t)
+ ctx := context.Background()
+
+ conv, err := s.GetOrCreateConversation(ctx, "agent:clear-test")
+ if err != nil {
+ t.Fatalf("create conversation: %v", err)
+ }
+
+ // Add messages
+ msg1, err := s.AddMessage(ctx, conv.ConversationID, "user", "hello", 5)
+ if err != nil {
+ t.Fatalf("add message 1: %v", err)
+ }
+ msg2, err := s.AddMessage(ctx, conv.ConversationID, "assistant", "hi", 5)
+ if err != nil {
+ t.Fatalf("add message 2: %v", err)
+ }
+
+ // Add a summary
+ _, err = s.CreateSummary(ctx, CreateSummaryInput{
+ ConversationID: conv.ConversationID,
+ Content: "test summary",
+ TokenCount: 10,
+ Kind: SummaryKindLeaf,
+ })
+ if err != nil {
+ t.Fatalf("create summary: %v", err)
+ }
+
+ // Verify data exists
+ msgs, err := s.GetMessages(ctx, conv.ConversationID, 0, 0)
+ if err != nil {
+ t.Fatalf("get messages before clear: %v", err)
+ }
+ if len(msgs) != 2 {
+ t.Fatalf("expected 2 messages before clear, got %d", len(msgs))
+ }
+
+ sums, err := s.GetSummariesByConversation(ctx, conv.ConversationID)
+ if err != nil {
+ t.Fatalf("get summaries before clear: %v", err)
+ }
+ if len(sums) != 1 {
+ t.Fatalf("expected 1 summary before clear, got %d", len(sums))
+ }
+
+ // Clear
+ if err = s.ClearConversation(ctx, conv.ConversationID); err != nil {
+ t.Fatalf("clear conversation: %v", err)
+ }
+
+ // Verify all data is gone
+ msgs, err = s.GetMessages(ctx, conv.ConversationID, 0, 0)
+ if err != nil {
+ t.Fatalf("get messages after clear: %v", err)
+ }
+ if len(msgs) != 0 {
+ t.Fatalf("expected 0 messages after clear, got %d", len(msgs))
+ }
+
+ sums, err = s.GetSummariesByConversation(ctx, conv.ConversationID)
+ if err != nil {
+ t.Fatalf("get summaries after clear: %v", err)
+ }
+ if len(sums) != 0 {
+ t.Fatalf("expected 0 summaries after clear, got %d", len(sums))
+ }
+
+ items, err := s.GetContextItems(ctx, conv.ConversationID)
+ if err != nil {
+ t.Fatalf("get context items after clear: %v", err)
+ }
+ if len(items) != 0 {
+ t.Fatalf("expected 0 context items after clear, got %d", len(items))
+ }
+
+ var count int
+ if err := s.db.QueryRowContext(ctx,
+ "SELECT COUNT(*) FROM message_parts WHERE message_id = ? OR message_id = ?",
+ msg1.ID, msg2.ID).Scan(&count); err != nil {
+ t.Fatalf("count message parts: %v", err)
+ }
+ if count != 0 {
+ t.Fatalf("expected 0 message parts after clear, got %d", count)
+ }
+}
func TestStoreAddAndGetMessages(t *testing.T) {
s := openTestStore(t)
From ea2107e8a939a07621a8866f0757e504d081cec0 Mon Sep 17 00:00:00 2001
From: wenjie
Date: Mon, 13 Apr 2026 11:23:55 +0800
Subject: [PATCH 2/6] build(release): split core builds from release-only
artifacts
- add a dedicated build-release-artifacts target for Android bundle packaging
- switch CI and release workflows to Corepack-managed pnpm with cache support
- pin the frontend pnpm version and make dependency installs deterministic
- inject version metadata into launcher binaries in GoReleaser
- update build documentation to reflect the new workflow
---
.github/workflows/build.yml | 10 ++++++++++
.github/workflows/create_dmg.yml | 24 +++++++++++++++---------
.github/workflows/nightly.yml | 12 +++++++++---
.github/workflows/release.yml | 8 +++++---
.goreleaser.yaml | 16 +++++++++++-----
Makefile | 20 ++++++++++++++------
README.fr.md | 18 ++++++++++++++++--
README.id.md | 17 ++++++++++++++++-
README.it.md | 17 ++++++++++++++++-
README.ja.md | 17 ++++++++++++++++-
README.ko.md | 17 ++++++++++++++++-
README.md | 25 +++++++++++++++++++++----
README.my.md | 17 ++++++++++++++++-
README.pt-br.md | 17 ++++++++++++++++-
README.vi.md | 21 ++++++++++++++++++---
README.zh.md | 18 ++++++++++++++++--
web/Makefile | 12 ++++++++----
web/frontend/package.json | 1 +
18 files changed, 240 insertions(+), 47 deletions(-)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 9b89b69ae..a7c066677 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -16,5 +16,15 @@ jobs:
with:
go-version-file: go.mod
+ - name: Setup Node.js
+ uses: actions/setup-node@v6
+ with:
+ node-version: 22
+ cache: pnpm
+ cache-dependency-path: web/frontend/pnpm-lock.yaml
+
+ - name: Setup pnpm
+ run: corepack enable && corepack install
+
- name: Build
run: make build-all
diff --git a/.github/workflows/create_dmg.yml b/.github/workflows/create_dmg.yml
index e03357566..a2221bb70 100644
--- a/.github/workflows/create_dmg.yml
+++ b/.github/workflows/create_dmg.yml
@@ -17,29 +17,35 @@ jobs:
with:
ref: main
- # 1. 安装指定版本的 Go (可选,但推荐)
+ # 1. Install Go from go.mod
- name: Setup Go
uses: actions/setup-go@v6
with:
go-version-file: go.mod
- # 2. 安装 pnpm
- - name: Install pnpm
- run: brew install pnpm
+ - name: Setup Node.js
+ uses: actions/setup-node@v6
+ with:
+ node-version: 22
+ cache: pnpm
+ cache-dependency-path: web/frontend/pnpm-lock.yaml
- # 3. 运行你的 Makefile 编译二进制文件
+ - name: Setup pnpm
+ run: corepack enable && corepack install
+
+ # 3. Build the application bundle
- name: Build with Make
run: make build ARCH=${{ matrix.arch }} && make build-macos-app ARCH=${{ matrix.arch }}
- # 4. 签名
+ # 4. Apply ad-hoc signing
- name: Ad-hoc Sign
run: codesign --force --deep --sign - "build/PicoClaw Launcher.app"
- # 5. 安装打包工具
+ # 5. Install the DMG packaging tool
- name: Install create-dmg
run: brew install create-dmg
- # 6. 执行打包命令
+ # 6. Create the DMG
- name: Create DMG
run: |
mkdir -p dist
@@ -54,7 +60,7 @@ jobs:
"dist/picoclaw-${{ matrix.arch }}.dmg" \
"build/PicoClaw Launcher.app"
- # 7. 上传文件到 GitHub Artifacts (供你下载)
+ # 7. Upload the DMG as a GitHub artifact
- name: Upload DMG
uses: actions/upload-artifact@v7
with:
diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml
index a5002fec5..7e8c7111c 100644
--- a/.github/workflows/nightly.yml
+++ b/.github/workflows/nightly.yml
@@ -51,9 +51,11 @@ jobs:
uses: actions/setup-node@v6
with:
node-version: 22
+ cache: pnpm
+ cache-dependency-path: web/frontend/pnpm-lock.yaml
- name: Setup pnpm
- run: corepack enable && corepack prepare pnpm@latest --activate
+ run: corepack enable && corepack install
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
@@ -97,6 +99,11 @@ jobs:
MACOS_NOTARY_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }}
MACOS_NOTARY_KEY: ${{ secrets.MACOS_NOTARY_KEY }}
+ - name: Build release-only artifacts
+ run: |
+ sudo apt-get install -y zip
+ make build-release-artifacts
+
- name: Update nightly release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -123,7 +130,7 @@ jobs:
# Collect release artifacts from goreleaser dist/
ASSETS=()
- for f in dist/*.tar.gz dist/*.zip dist/*.deb dist/*.rpm dist/checksums.txt; do
+ for f in dist/*.tar.gz dist/*.zip dist/*.deb dist/*.rpm dist/checksums.txt build/picoclaw-android-universal.zip; do
[ -f "$f" ] && ASSETS+=("$f")
done
@@ -135,4 +142,3 @@ jobs:
--prerelease \
--latest=false \
"${ASSETS[@]}"
-
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index aab9cf874..8d7bc02ad 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -69,9 +69,11 @@ jobs:
uses: actions/setup-node@v6
with:
node-version: 22
+ cache: pnpm
+ cache-dependency-path: web/frontend/pnpm-lock.yaml
- name: Setup pnpm
- run: corepack enable && corepack prepare pnpm@latest --activate
+ run: corepack enable && corepack install
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
@@ -110,13 +112,13 @@ jobs:
MACOS_NOTARY_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }}
MACOS_NOTARY_KEY: ${{ secrets.MACOS_NOTARY_KEY }}
- - name: Build and upload Android arm64
+ - name: Build and upload release-only artifacts
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
sudo apt-get install -y zip
- make build-android-bundle
+ make build-release-artifacts
gh release upload "${{ inputs.tag }}" \
build/picoclaw-android-universal.zip \
--clobber
diff --git a/.goreleaser.yaml b/.goreleaser.yaml
index 9c26de34f..b20856110 100644
--- a/.goreleaser.yaml
+++ b/.goreleaser.yaml
@@ -9,11 +9,9 @@ git:
before:
hooks:
- - go mod tidy
- go generate ./...
- - sh -c 'cd web/frontend && pnpm install && pnpm build:backend'
- - go install github.com/tc-hib/go-winres@latest
- - go-winres make --in web/backend/winres/winres.json --out web/backend/rsrc --product-version={{ .Version }} --file-version={{ .Version }}
+ - sh -c 'cd web/frontend && CI=true pnpm install --frozen-lockfile && pnpm build:backend'
+ - sh -c 'GOBIN="$(go env GOPATH)/bin"; mkdir -p "$GOBIN"; go install github.com/tc-hib/go-winres@v0.3.3 && "$GOBIN/go-winres" make --in web/backend/winres/winres.json --out web/backend/rsrc --product-version={{ .Version }} --file-version={{ .Version }}'
builds:
- id: picoclaw
@@ -27,7 +25,7 @@ builds:
- -X github.com/sipeed/picoclaw/pkg/config.Version={{ .Version }}
- -X github.com/sipeed/picoclaw/pkg/config.GitCommit={{ .ShortCommit }}
- -X github.com/sipeed/picoclaw/pkg/config.BuildTime={{ .Date }}
- - -X github.com/sipeed/picoclaw/pkg/config.GoVersion={{ .Env.GOVERSION }}
+ - -X github.com/sipeed/picoclaw/pkg/config.GoVersion={{ with index .Env "GOVERSION" }}{{ . }}{{ else }}unknown{{ end }}
goos:
- linux
- windows
@@ -67,6 +65,10 @@ builds:
- stdjson
ldflags:
- -s -w
+ - -X github.com/sipeed/picoclaw/pkg/config.Version={{ .Version }}
+ - -X github.com/sipeed/picoclaw/pkg/config.GitCommit={{ .ShortCommit }}
+ - -X github.com/sipeed/picoclaw/pkg/config.BuildTime={{ .Date }}
+ - -X github.com/sipeed/picoclaw/pkg/config.GoVersion={{ with index .Env "GOVERSION" }}{{ . }}{{ else }}unknown{{ end }}
goos:
- linux
- windows
@@ -106,6 +108,10 @@ builds:
- stdjson
ldflags:
- -s -w
+ - -X github.com/sipeed/picoclaw/pkg/config.Version={{ .Version }}
+ - -X github.com/sipeed/picoclaw/pkg/config.GitCommit={{ .ShortCommit }}
+ - -X github.com/sipeed/picoclaw/pkg/config.BuildTime={{ .Date }}
+ - -X github.com/sipeed/picoclaw/pkg/config.GoVersion={{ with index .Env "GOVERSION" }}{{ . }}{{ else }}unknown{{ end }}
goos:
- linux
- windows
diff --git a/Makefile b/Makefile
index beddd1138..717273efa 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-.PHONY: all build install uninstall clean help test
+.PHONY: all build install uninstall clean help test build-core-all build-release-artifacts
# Build variables
BINARY_NAME=picoclaw
@@ -217,7 +217,9 @@ build-launcher-android-arm64:
@echo "Building picoclaw-launcher for android/arm64..."
@mkdir -p $(BUILD_DIR)
@$(MAKE) -C web build-android-arm64 \
- OUTPUT="$(CURDIR)/$(BUILD_DIR)/picoclaw-launcher-android-arm64"
+ OUTPUT_ANDROID_ARM64="$(CURDIR)/$(BUILD_DIR)/picoclaw-launcher-android-arm64" \
+ GO='$(GO)' \
+ LDFLAGS='$(LDFLAGS)'
@echo "Build complete: $(BUILD_DIR)/picoclaw-launcher-android-arm64"
## build-android-bundle: Build core and launcher for all Android architectures and package as universal zip
@@ -240,8 +242,8 @@ build-android-bundle: generate
build-pi-zero: build-linux-arm build-linux-arm64
@echo "Pi Zero 2 W builds: $(BUILD_DIR)/$(BINARY_NAME)-linux-arm (32-bit), $(BUILD_DIR)/$(BINARY_NAME)-linux-arm64 (64-bit)"
-## build-all: Build picoclaw for all platforms
-build-all: generate
+## build-core-all: Build the picoclaw core binary for all Makefile-managed platforms
+build-core-all: generate
@echo "Building for multiple platforms..."
@mkdir -p $(BUILD_DIR)
GOOS=linux GOARCH=amd64 $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(BINARY_NAME)-linux-amd64 ./$(CMD_DIR)
@@ -257,8 +259,14 @@ build-all: generate
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)
- @$(MAKE) build-android-bundle
- @echo "All builds complete"
+ @echo "Core builds complete"
+
+## build-all: Build the picoclaw core binary for all Makefile-managed platforms
+build-all: build-core-all
+
+## build-release-artifacts: Build release-only artifacts that sit outside GoReleaser
+build-release-artifacts: build-android-bundle
+ @echo "Release artifact builds complete"
## install: Install picoclaw to system and copy builtin skills
install: build
diff --git a/README.fr.md b/README.fr.md
index 3b2552f6d..ecafefdc7 100644
--- a/README.fr.md
+++ b/README.fr.md
@@ -167,21 +167,32 @@ Vous pouvez aussi télécharger le binaire pour votre plateforme depuis la page
### Compiler depuis les sources (pour le développement)
+Prérequis :
+
+- Go 1.25+
+- Node.js 22+ avec Corepack activé pour les builds Web UI / launcher
+
```bash
git clone https://github.com/sipeed/picoclaw.git
cd picoclaw
make deps
+# Installer le gestionnaire de paquets frontend déclaré par le dépôt
+(cd web/frontend && corepack install)
+
# Compiler le binaire principal
make build
# Compiler le Web UI Launcher (requis pour le mode WebUI)
make build-launcher
-# Compiler pour plusieurs plateformes
+# Compiler les binaires core pour toutes les plateformes gérées par le Makefile
make build-all
+# Compiler les artefacts de release empaquetés séparément des sorties principales de GoReleaser
+make build-release-artifacts
+
# Compiler pour Raspberry Pi Zero 2 W (32 bits : make build-linux-arm ; 64 bits : make build-linux-arm64)
make build-pi-zero
@@ -189,6 +200,10 @@ make build-pi-zero
make install
```
+`make build-all` compile les binaires core de `picoclaw` pour toutes les plateformes gérées par le Makefile.
+
+`make build-release-artifacts` compile les artefacts de release empaquetés séparément des sorties principales de GoReleaser.
+
**Raspberry Pi Zero 2 W :** Utilisez le binaire correspondant à votre OS : Raspberry Pi OS 32 bits -> `make build-linux-arm` ; 64 bits -> `make build-linux-arm64`. Ou exécutez `make build-pi-zero` pour compiler les deux.
## 🚀 Guide de démarrage rapide
@@ -621,4 +636,3 @@ WeChat :
-
diff --git a/README.id.md b/README.id.md
index 5aa7b58f5..f57d2f0bc 100644
--- a/README.id.md
+++ b/README.id.md
@@ -164,21 +164,32 @@ Atau, unduh binary untuk platform Anda dari halaman [GitHub Releases](https://gi
### Build dari source (untuk pengembangan)
+Prasyarat:
+
+- Go 1.25+
+- Node.js 22+ dengan Corepack aktif untuk build Web UI / launcher
+
```bash
git clone https://github.com/sipeed/picoclaw.git
cd picoclaw
make deps
+# Instal package manager frontend yang dideklarasikan repo
+(cd web/frontend && corepack install)
+
# Build binary inti
make build
# Build Web UI Launcher (diperlukan untuk mode WebUI)
make build-launcher
-# Build untuk berbagai platform
+# Build binary inti untuk semua platform yang dikelola Makefile
make build-all
+# Build artefak rilis yang dikemas terpisah dari output utama GoReleaser
+make build-release-artifacts
+
# Build untuk Raspberry Pi Zero 2 W (32-bit: make build-linux-arm; 64-bit: make build-linux-arm64)
make build-pi-zero
@@ -186,6 +197,10 @@ make build-pi-zero
make install
```
+`make build-all` membangun binary inti `picoclaw` untuk semua platform yang dikelola Makefile.
+
+`make build-release-artifacts` membangun artefak rilis yang dikemas terpisah dari output utama GoReleaser.
+
**Raspberry Pi Zero 2 W:** Gunakan binary yang sesuai dengan OS Anda: Raspberry Pi OS 32-bit -> `make build-linux-arm`; 64-bit -> `make build-linux-arm64`. Atau jalankan `make build-pi-zero` untuk build keduanya.
## 🚀 Panduan Memulai Cepat
diff --git a/README.it.md b/README.it.md
index 57dd014b3..4c18f6f5b 100644
--- a/README.it.md
+++ b/README.it.md
@@ -164,21 +164,32 @@ In alternativa, scarica il binario per la tua piattaforma dalla pagina delle [Gi
### Compila dai sorgenti (per lo sviluppo)
+Prerequisiti:
+
+- Go 1.25+
+- Node.js 22+ con Corepack abilitato per le build Web UI / launcher
+
```bash
git clone https://github.com/sipeed/picoclaw.git
cd picoclaw
make deps
+# Installa il package manager frontend dichiarato dal repository
+(cd web/frontend && corepack install)
+
# Compila il binario core
make build
# Compila il Web UI Launcher (necessario per la modalità WebUI)
make build-launcher
-# Compila per più piattaforme
+# Compila i binari core per tutte le piattaforme gestite dal Makefile
make build-all
+# Compila gli artefatti di release impacchettati separatamente dagli output principali di GoReleaser
+make build-release-artifacts
+
# Compila per Raspberry Pi Zero 2 W (32-bit: make build-linux-arm; 64-bit: make build-linux-arm64)
make build-pi-zero
@@ -186,6 +197,10 @@ make build-pi-zero
make install
```
+`make build-all` compila i binari core di `picoclaw` per tutte le piattaforme gestite dal Makefile.
+
+`make build-release-artifacts` compila gli artefatti di release impacchettati separatamente dagli output principali di GoReleaser.
+
**Raspberry Pi Zero 2 W:** Usa il binario che corrisponde al tuo OS: Raspberry Pi OS 32-bit -> `make build-linux-arm`; 64-bit -> `make build-linux-arm64`. Oppure esegui `make build-pi-zero` per compilare entrambi.
## 🚀 Guida Rapida
diff --git a/README.ja.md b/README.ja.md
index 64bff9ee9..0ad159a53 100644
--- a/README.ja.md
+++ b/README.ja.md
@@ -164,21 +164,32 @@ PicoClaw はほぼすべての Linux デバイスにデプロイできます!
### ソースからビルド(開発用)
+前提条件:
+
+- Go 1.25+
+- Web UI / launcher のビルドには Corepack を有効にした Node.js 22+
+
```bash
git clone https://github.com/sipeed/picoclaw.git
cd picoclaw
make deps
+# リポジトリで宣言されたフロントエンド用パッケージマネージャーをインストール
+(cd web/frontend && corepack install)
+
# コアバイナリをビルド
make build
# Web UI Launcher をビルド(WebUI モードに必要)
make build-launcher
-# 複数プラットフォーム向けビルド
+# Makefile が管理するすべてのプラットフォーム向けにコアバイナリをビルド
make build-all
+# メインの GoReleaser 出力とは別にパッケージ化されるリリース専用成果物をビルド
+make build-release-artifacts
+
# Raspberry Pi Zero 2 W 向けビルド(32-bit: make build-linux-arm; 64-bit: make build-linux-arm64)
make build-pi-zero
@@ -186,6 +197,10 @@ make build-pi-zero
make install
```
+`make build-all` は、Makefile が管理するすべてのプラットフォーム向けにコアの `picoclaw` バイナリをビルドします。
+
+`make build-release-artifacts` は、メインの GoReleaser 出力とは別にパッケージ化されるリリース専用成果物をビルドします。
+
**Raspberry Pi Zero 2 W:** OS に合ったバイナリを使用してください:32-bit Raspberry Pi OS → `make build-linux-arm`、64-bit → `make build-linux-arm64`。または `make build-pi-zero` で両方をビルド。
## 🚀 クイックスタートガイド
diff --git a/README.ko.md b/README.ko.md
index 341c09812..5f99dd32e 100644
--- a/README.ko.md
+++ b/README.ko.md
@@ -164,21 +164,32 @@ PicoClaw는 사실상 거의 모든 Linux 장치에 배포할 수 있습니다!
### 소스에서 빌드(개발용)
+필수 사항:
+
+- Go 1.25+
+- Web UI / launcher 빌드를 위한 Corepack 활성화된 Node.js 22+
+
```bash
git clone https://github.com/sipeed/picoclaw.git
cd picoclaw
make deps
+# 저장소에 선언된 프런트엔드 패키지 매니저 설치
+(cd web/frontend && corepack install)
+
# 코어 바이너리 빌드
make build
# WebUI 런처 빌드 (WebUI 모드에 필요)
make build-launcher
-# 여러 플랫폼용 빌드
+# Makefile이 관리하는 모든 플랫폼용 코어 바이너리 빌드
make build-all
+# 메인 GoReleaser 출력과 별도로 패키징되는 릴리스 전용 산출물 빌드
+make build-release-artifacts
+
# Raspberry Pi Zero 2 W용 빌드 (32비트: make build-linux-arm, 64비트: make build-linux-arm64)
make build-pi-zero
@@ -186,6 +197,10 @@ make build-pi-zero
make install
```
+`make build-all`은 Makefile이 관리하는 모든 플랫폼용 핵심 `picoclaw` 바이너리를 빌드합니다.
+
+`make build-release-artifacts`는 메인 GoReleaser 출력과 별도로 패키징되는 릴리스 전용 산출물을 빌드합니다.
+
**Raspberry Pi Zero 2 W:** OS에 맞는 바이너리를 사용하세요. 32비트 Raspberry Pi OS는 `make build-linux-arm`, 64비트는 `make build-linux-arm64`입니다. 또는 `make build-pi-zero`로 둘 다 빌드할 수 있습니다.
## 🚀 빠른 시작 가이드
diff --git a/README.md b/README.md
index eb0d389d2..fd082f6bf 100644
--- a/README.md
+++ b/README.md
@@ -164,28 +164,45 @@ Alternatively, download the binary for your platform from the [GitHub Releases](
### Build from source (for development)
+Prerequisites:
+
+- Go 1.25+
+- Node.js 22+ with Corepack enabled for Web UI / launcher builds
+
```bash
git clone https://github.com/sipeed/picoclaw.git
cd picoclaw
make deps
-# Build core binary
+# Install frontend package manager declared by the repo
+(cd web/frontend && corepack install)
+
+# Build the core binary for the current platform
make build
-# Build Web UI Launcher (required for WebUI mode)
+# Build the Web UI Launcher (required for WebUI mode)
make build-launcher
-# Build for multiple platforms
+# Build core binaries for all Makefile-managed platforms
make build-all
-# Build for Raspberry Pi Zero 2 W (32-bit: make build-linux-arm; 64-bit: make build-linux-arm64)
+# Build release-only artifacts packaged separately from the main GoReleaser outputs
+make build-release-artifacts
+
+# Build for Raspberry Pi Zero 2 W
+# 32-bit: make build-linux-arm
+# 64-bit: make build-linux-arm64
make build-pi-zero
# Build and install
make install
```
+`make build-all` builds the core `picoclaw` binaries for all Makefile-managed platforms.
+
+`make build-release-artifacts` builds release-only artifacts that are packaged separately from the main GoReleaser outputs.
+
**Raspberry Pi Zero 2 W:** Use the binary that matches your OS: 32-bit Raspberry Pi OS -> `make build-linux-arm`; 64-bit -> `make build-linux-arm64`. Or run `make build-pi-zero` to build both.
## 🚀 Quick Start Guide
diff --git a/README.my.md b/README.my.md
index f8e602f83..a5719c696 100644
--- a/README.my.md
+++ b/README.my.md
@@ -165,20 +165,31 @@ Muat turun binari untuk platform anda dari halaman [GitHub Releases](https://git
### Bina dari sumber (untuk pembangunan)
+Prasyarat:
+
+- Go 1.25+
+- Node.js 22+ dengan Corepack diaktifkan untuk binaan Web UI / launcher
+
```bash
git clone https://github.com/sipeed/picoclaw.git
cd picoclaw
make deps
+# Pasang pengurus pakej frontend yang diisytiharkan oleh repositori
+(cd web/frontend && corepack install)
+
# Bina binari teras
make build
# Bina Pelancar Web UI (diperlukan untuk mod WebUI)
make build-launcher
-# Bina untuk pelbagai platform
+# Bina binari teras untuk semua platform yang diuruskan oleh Makefile
make build-all
+# Bina artifak keluaran yang dibungkus berasingan daripada output utama GoReleaser
+make build-release-artifacts
+
# Bina untuk Raspberry Pi Zero 2 W (32-bit: make build-linux-arm; 64-bit: make build-linux-arm64)
make build-pi-zero
@@ -186,6 +197,10 @@ make build-pi-zero
make install
```
+`make build-all` membina binari teras `picoclaw` untuk semua platform yang diuruskan oleh Makefile.
+
+`make build-release-artifacts` membina artifak keluaran yang dibungkus berasingan daripada output utama GoReleaser.
+
**Raspberry Pi Zero 2 W:** Gunakan binari yang sepadan dengan OS anda: Raspberry Pi OS 32-bit -> `make build-linux-arm`; 64-bit -> `make build-linux-arm64`. Atau jalankan `make build-pi-zero` untuk membina kedua-duanya.
## 🚀 Panduan Permulaan Pantas
diff --git a/README.pt-br.md b/README.pt-br.md
index 65d23d1d1..d9b64c959 100644
--- a/README.pt-br.md
+++ b/README.pt-br.md
@@ -164,21 +164,32 @@ Alternativamente, baixe o binário para sua plataforma na página de [GitHub Rel
### Compilar a partir do código-fonte (para desenvolvimento)
+Pré-requisitos:
+
+- Go 1.25+
+- Node.js 22+ com Corepack habilitado para builds do Web UI / launcher
+
```bash
git clone https://github.com/sipeed/picoclaw.git
cd picoclaw
make deps
+# Instalar o gerenciador de pacotes de frontend declarado pelo repositório
+(cd web/frontend && corepack install)
+
# Compilar o binário principal
make build
# Compilar o Web UI Launcher (necessário para o modo WebUI)
make build-launcher
-# Compilar para múltiplas plataformas
+# Compilar os binários core para todas as plataformas gerenciadas pelo Makefile
make build-all
+# Compilar os artefatos de release empacotados separadamente das saídas principais do GoReleaser
+make build-release-artifacts
+
# Compilar para Raspberry Pi Zero 2 W (32-bit: make build-linux-arm; 64-bit: make build-linux-arm64)
make build-pi-zero
@@ -186,6 +197,10 @@ make build-pi-zero
make install
```
+`make build-all` compila os binários core do `picoclaw` para todas as plataformas gerenciadas pelo Makefile.
+
+`make build-release-artifacts` compila os artefatos de release empacotados separadamente das saídas principais do GoReleaser.
+
**Raspberry Pi Zero 2 W:** Use o binário que corresponde ao seu SO: Raspberry Pi OS 32-bit -> `make build-linux-arm`; 64-bit -> `make build-linux-arm64`. Ou execute `make build-pi-zero` para compilar ambos.
## 🚀 Guia de Início Rápido
diff --git a/README.vi.md b/README.vi.md
index 1d70d0615..3475830fb 100644
--- a/README.vi.md
+++ b/README.vi.md
@@ -164,21 +164,32 @@ Ngoài ra, tải binary cho nền tảng của bạn từ trang [GitHub Releases
### Xây dựng từ mã nguồn (để phát triển)
+Yêu cầu:
+
+- Go 1.25+
+- Node.js 22+ với Corepack được bật cho các bản build Web UI / launcher
+
```bash
git clone https://github.com/sipeed/picoclaw.git
cd picoclaw
make deps
-# Build core binary
+# Cài đặt trình quản lý gói frontend được khai báo bởi repo
+(cd web/frontend && corepack install)
+
+# Build binary lõi
make build
-# Build Web UI Launcher (required for WebUI mode)
+# Build Web UI Launcher (cần cho chế độ WebUI)
make build-launcher
-# Build for multiple platforms
+# Build các binary lõi cho mọi nền tảng do Makefile quản lý
make build-all
+# Build các release artifact được đóng gói tách biệt với các đầu ra chính của GoReleaser
+make build-release-artifacts
+
# Build for Raspberry Pi Zero 2 W (32-bit: make build-linux-arm; 64-bit: make build-linux-arm64)
make build-pi-zero
@@ -186,6 +197,10 @@ make build-pi-zero
make install
```
+`make build-all` build các binary lõi `picoclaw` cho mọi nền tảng do Makefile quản lý.
+
+`make build-release-artifacts` build các release artifact được đóng gói tách biệt với các đầu ra chính của GoReleaser.
+
**Raspberry Pi Zero 2 W:** Sử dụng binary phù hợp với hệ điều hành của bạn: Raspberry Pi OS 32-bit -> `make build-linux-arm`; 64-bit -> `make build-linux-arm64`. Hoặc chạy `make build-pi-zero` để xây dựng cả hai.
## 🚀 Hướng dẫn Khởi động Nhanh
diff --git a/README.zh.md b/README.zh.md
index e61ff7e28..ddb3bb230 100644
--- a/README.zh.md
+++ b/README.zh.md
@@ -164,21 +164,32 @@ PicoClaw 几乎可以部署在任何 Linux 设备上!
### 从源码构建(开发用)
+前置要求:
+
+- Go 1.25+
+- Node.js 22+,并启用 Corepack(用于 Web UI / launcher 构建)
+
```bash
git clone https://github.com/sipeed/picoclaw.git
cd picoclaw
make deps
+# 安装仓库声明的前端包管理器
+(cd web/frontend && corepack install)
+
# 构建核心二进制文件
make build
# 构建 Web UI Launcher(WebUI 模式必需)
make build-launcher
-# 为多平台构建
+# 为 Makefile 管理的所有平台构建核心二进制文件
make build-all
+# 构建独立于主 GoReleaser 输出之外的发布附加产物
+make build-release-artifacts
+
# 为 Raspberry Pi Zero 2 W 构建(32位: make build-linux-arm; 64位: make build-linux-arm64)
make build-pi-zero
@@ -186,6 +197,10 @@ make build-pi-zero
make install
```
+`make build-all` 会为所有由 Makefile 管理的平台构建核心 `picoclaw` 二进制文件。
+
+`make build-release-artifacts` 会构建独立于主 GoReleaser 输出之外打包的发布附加产物。
+
**Raspberry Pi Zero 2 W:** 请使用与系统匹配的二进制文件:32 位 Raspberry Pi OS → `make build-linux-arm`;64 位 → `make build-linux-arm64`。或运行 `make build-pi-zero` 同时构建两者。
## 🚀 快速开始
@@ -619,4 +634,3 @@ WeChat:
-
diff --git a/web/Makefile b/web/Makefile
index cf5ea774a..4dca810e7 100644
--- a/web/Makefile
+++ b/web/Makefile
@@ -12,6 +12,7 @@ BUILD_DIR=build
OUTPUT?=$(BUILD_DIR)/picoclaw-launcher
OUTPUT_ANDROID_ARM64?=$(BUILD_DIR)/picoclaw-launcher-android-arm64
FRONTEND_DIR=frontend
+FRONTEND_INSTALL_STAMP=$(FRONTEND_DIR)/node_modules/.picoclaw-install-stamp
BACKEND_DIR=backend
BACKEND_DIST=$(BACKEND_DIR)/dist
PICOCLAW_BINARY_NAME=picoclaw
@@ -105,11 +106,14 @@ build-android-bundle: build-frontend
@echo "All Android launcher builds complete"
build-frontend:
- @if [ ! -d $(FRONTEND_DIR)/node_modules ] || \
- [ $(FRONTEND_DIR)/package.json -nt $(FRONTEND_DIR)/node_modules ] || \
- [ $(FRONTEND_DIR)/pnpm-lock.yaml -nt $(FRONTEND_DIR)/node_modules ]; then \
+ @expected_stamp="$$(cat $(FRONTEND_DIR)/package.json $(FRONTEND_DIR)/pnpm-lock.yaml | cksum | awk '{print $$1 ":" $$2}')"; \
+ if [ ! -d $(FRONTEND_DIR)/node_modules ] || \
+ [ ! -x $(FRONTEND_DIR)/node_modules/.bin/tsc ] || \
+ [ ! -f $(FRONTEND_INSTALL_STAMP) ] || \
+ [ "$$(cat $(FRONTEND_INSTALL_STAMP) 2>/dev/null)" != "$$expected_stamp" ]; then \
echo "Installing frontend dependencies..."; \
- cd $(FRONTEND_DIR) && pnpm install --frozen-lockfile; \
+ (cd $(FRONTEND_DIR) && CI=true pnpm install --frozen-lockfile) && \
+ printf '%s\n' "$$expected_stamp" > $(FRONTEND_INSTALL_STAMP); \
fi
@echo "Building frontend..."
@cd $(FRONTEND_DIR) && pnpm build:backend
diff --git a/web/frontend/package.json b/web/frontend/package.json
index 51e6f1dd9..40d5cf3d8 100644
--- a/web/frontend/package.json
+++ b/web/frontend/package.json
@@ -3,6 +3,7 @@
"private": true,
"version": "0.0.0",
"type": "module",
+ "packageManager": "pnpm@10.33.0",
"engines": {
"node": "^20.19.0 || ^22.13.0 || >=24"
},
From b8819bdbffcd59835544db1682e5b90e7c478533 Mon Sep 17 00:00:00 2001
From: Liu Yuan
Date: Mon, 13 Apr 2026 11:29:02 +0800
Subject: [PATCH 3/6] fix(seahorse): drop/recreate FTS5 triggers so existing
DBs get corrected bodies
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
`CREATE TRIGGER IF NOT EXISTS` does not replace an existing trigger body.
On databases created with the old (buggy) DELETE-FROM-FTS syntax, the
bad trigger body persisted after code updates. Now we explicitly DROP
each trigger before CREATE, so any existing DB gets the corrected body
on next startup — no manual DB deletion required.
---
pkg/seahorse/schema.go | 21 +++++++++++++++------
1 file changed, 15 insertions(+), 6 deletions(-)
diff --git a/pkg/seahorse/schema.go b/pkg/seahorse/schema.go
index bf32d548b..aa829358b 100644
--- a/pkg/seahorse/schema.go
+++ b/pkg/seahorse/schema.go
@@ -118,26 +118,35 @@ func runSchema(db *sql.DB) error {
`CREATE INDEX IF NOT EXISTS idx_summary_messages_message ON summary_messages(message_id)`,
`CREATE INDEX IF NOT EXISTS idx_context_items_conv ON context_items(conversation_id, ordinal)`,
+ // Drop old triggers before creating new ones so existing DBs get updated bodies.
+ // (CREATE TRIGGER IF NOT EXISTS does NOT replace an existing trigger body.)
+ `DROP TRIGGER IF EXISTS summaries_ai`,
+ `DROP TRIGGER IF EXISTS summaries_ad`,
+ `DROP TRIGGER IF EXISTS summaries_au`,
+ `DROP TRIGGER IF EXISTS messages_ai`,
+ `DROP TRIGGER IF EXISTS messages_ad`,
+ `DROP TRIGGER IF EXISTS messages_au`,
+
// FTS5 triggers to keep summaries_fts in sync with summaries table
- `CREATE TRIGGER IF NOT EXISTS summaries_ai AFTER INSERT ON summaries BEGIN
+ `CREATE TRIGGER summaries_ai AFTER INSERT ON summaries BEGIN
INSERT INTO summaries_fts (summary_id, content) VALUES (new.summary_id, new.content);
END`,
- `CREATE TRIGGER IF NOT EXISTS summaries_ad AFTER DELETE ON summaries BEGIN
+ `CREATE TRIGGER summaries_ad AFTER DELETE ON summaries BEGIN
DELETE FROM summaries_fts WHERE summary_id = old.summary_id;
END`,
- `CREATE TRIGGER IF NOT EXISTS summaries_au AFTER UPDATE ON summaries BEGIN
+ `CREATE TRIGGER summaries_au AFTER UPDATE ON summaries BEGIN
DELETE FROM summaries_fts WHERE summary_id = old.summary_id;
INSERT INTO summaries_fts (summary_id, content) VALUES (new.summary_id, new.content);
END`,
// FTS5 triggers to keep messages_fts in sync with messages table
- `CREATE TRIGGER IF NOT EXISTS messages_ai AFTER INSERT ON messages BEGIN
+ `CREATE TRIGGER messages_ai AFTER INSERT ON messages BEGIN
INSERT INTO messages_fts (message_id, content) VALUES (new.message_id, new.content);
END`,
- `CREATE TRIGGER IF NOT EXISTS messages_ad AFTER DELETE ON messages BEGIN
+ `CREATE TRIGGER messages_ad AFTER DELETE ON messages BEGIN
DELETE FROM messages_fts WHERE message_id = old.message_id;
END`,
- `CREATE TRIGGER IF NOT EXISTS messages_au AFTER UPDATE ON messages BEGIN
+ `CREATE TRIGGER messages_au AFTER UPDATE ON messages BEGIN
DELETE FROM messages_fts WHERE message_id = old.message_id;
INSERT INTO messages_fts (message_id, content) VALUES (new.message_id, new.content);
END`,
From 4532627f715310a96fb894b8dccde62a0d35c1de Mon Sep 17 00:00:00 2001
From: Liu Yuan
Date: Mon, 13 Apr 2026 11:37:50 +0800
Subject: [PATCH 4/6] test(seahorse): add TestTriggerMigration for old-DB
trigger upgrade path
Verifies that databases created with the old buggy FTS5 DELETE trigger
body are correctly migrated by runSchema: the old trigger causes DELETE
to fail, and after re-running runSchema (which drops and recreates the
triggers with the corrected body) DELETE works normally.
---
pkg/seahorse/schema_test.go | 78 +++++++++++++++++++++++++++++++++++++
1 file changed, 78 insertions(+)
diff --git a/pkg/seahorse/schema_test.go b/pkg/seahorse/schema_test.go
index e11e6e96e..f3d6a3650 100644
--- a/pkg/seahorse/schema_test.go
+++ b/pkg/seahorse/schema_test.go
@@ -194,6 +194,84 @@ func TestMigrationSummaryParentsPK(t *testing.T) {
}
}
+func TestTriggerMigration(t *testing.T) {
+ db := openTestDB(t)
+
+ // Run schema once to create tables and (correct) triggers
+ if err := runSchema(db); err != nil {
+ t.Fatalf("runSchema: %v", err)
+ }
+
+ // Drop correct triggers and recreate them with the old buggy body.
+ // The old trigger used INSERT INTO fts VALUES('delete', ...) which is wrong
+ // for non-external-content FTS5 tables.
+ oldSummariesDelete := `CREATE TRIGGER summaries_ad AFTER DELETE ON summaries BEGIN
+ INSERT INTO summaries_fts (summaries_fts, summary_id, content) VALUES('delete', old.summary_id, old.content);
+ END`
+ oldMessagesDelete := `CREATE TRIGGER messages_ad AFTER DELETE ON messages BEGIN
+ INSERT INTO messages_fts (messages_fts, message_id, content) VALUES('delete', old.message_id, old.content);
+ END`
+
+ for _, sql := range []string{
+ `DROP TRIGGER IF EXISTS summaries_ad`,
+ `DROP TRIGGER IF EXISTS messages_ad`,
+ oldSummariesDelete,
+ oldMessagesDelete,
+ } {
+ if _, err := db.Exec(sql); err != nil {
+ t.Fatalf("setup old trigger: %v", err)
+ }
+ }
+
+ // Insert a conversation and summary so we have something to delete
+ _, err := db.Exec(`INSERT INTO conversations (session_key) VALUES ('old-db-test')`)
+ if err != nil {
+ t.Fatalf("insert conversation: %v", err)
+ }
+ _, err = db.Exec(`INSERT INTO summaries (summary_id, conversation_id, kind, depth, content, token_count)
+ VALUES ('old-sum', 1, 'leaf', 0, 'old content', 5)`)
+ if err != nil {
+ t.Fatalf("insert summary: %v", err)
+ }
+
+ // The old trigger body is wrong for normal FTS5 — DELETE should fail.
+ _, err = db.Exec(`DELETE FROM summaries WHERE summary_id = 'old-sum'`)
+ if err == nil {
+ t.Error("expected error from old buggy trigger, but DELETE succeeded")
+ } else {
+ t.Logf("old trigger correctly causes error: %v", err)
+ }
+
+ // Now runSchema again — this drops and recreates the triggers with correct bodies.
+ err = runSchema(db)
+ if err != nil {
+ t.Fatalf("runSchema migration: %v", err)
+ }
+
+ // Insert again so we have data to delete
+ _, err = db.Exec(`INSERT INTO summaries (summary_id, conversation_id, kind, depth, content, token_count)
+ VALUES ('migrated-sum', 1, 'leaf', 0, 'new content', 5)`)
+ if err != nil {
+ t.Fatalf("insert after migration: %v", err)
+ }
+
+ // DELETE should now work with the corrected trigger body.
+ _, err = db.Exec(`DELETE FROM summaries WHERE summary_id = 'migrated-sum'`)
+ if err != nil {
+ t.Fatalf("DELETE after migration failed (trigger not corrected): %v", err)
+ }
+
+ // Verify the summary is gone
+ var count int
+ err = db.QueryRow(`SELECT count(*) FROM summaries WHERE summary_id = 'migrated-sum'`).Scan(&count)
+ if err != nil {
+ t.Fatalf("query after delete: %v", err)
+ }
+ if count != 0 {
+ t.Errorf("summary should be gone after DELETE, got count=%d", count)
+ }
+}
+
func TestFTS5SQLConstants(t *testing.T) {
db := openTestDB(t)
From d73a0e89b4780ca0cc7816e069e61beffd7f12aa Mon Sep 17 00:00:00 2001
From: wenjie
Date: Mon, 13 Apr 2026 11:52:35 +0800
Subject: [PATCH 5/6] build(release): move Android bundle publishing into
GoReleaser
- build the Android universal bundle from GoReleaser hooks
- attach the bundle as a release asset
- remove the separate post-release upload step
- simplify Make targets around cross-platform builds
---
.github/workflows/build.yml | 2 +-
.github/workflows/nightly.yml | 9 ++++-----
.github/workflows/release.yml | 15 ++++-----------
.goreleaser.yaml | 3 +++
Makefile | 13 +++----------
README.fr.md | 8 --------
README.id.md | 7 -------
README.it.md | 7 -------
README.ja.md | 7 -------
README.ko.md | 7 -------
README.md | 13 +++----------
README.my.md | 7 -------
README.pt-br.md | 7 -------
README.vi.md | 7 -------
README.zh.md | 8 --------
15 files changed, 18 insertions(+), 102 deletions(-)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index a7c066677..f21e3ef5f 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -26,5 +26,5 @@ jobs:
- name: Setup pnpm
run: corepack enable && corepack install
- - name: Build
+ - name: Build core binaries
run: make build-all
diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml
index 7e8c7111c..f713c4db2 100644
--- a/.github/workflows/nightly.yml
+++ b/.github/workflows/nightly.yml
@@ -77,6 +77,9 @@ jobs:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
+ - name: Install zip
+ run: sudo apt-get install -y zip
+
- name: Create local tag for GoReleaser
run: git tag "${{ steps.version.outputs.version }}"
@@ -92,6 +95,7 @@ jobs:
DOCKERHUB_IMAGE_NAME: ${{ vars.DOCKERHUB_REPOSITORY }}
GOVERSION: ${{ steps.setup-go.outputs.go-version }}
GORELEASER_CURRENT_TAG: ${{ steps.version.outputs.version }}
+ INCLUDE_ANDROID_BUNDLE: "true"
NIGHTLY_BUILD: "true"
MACOS_SIGN_P12: ${{ secrets.MACOS_SIGN_P12 }}
MACOS_SIGN_PASSWORD: ${{ secrets.MACOS_SIGN_PASSWORD }}
@@ -99,11 +103,6 @@ jobs:
MACOS_NOTARY_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }}
MACOS_NOTARY_KEY: ${{ secrets.MACOS_NOTARY_KEY }}
- - name: Build release-only artifacts
- run: |
- sudo apt-get install -y zip
- make build-release-artifacts
-
- name: Update nightly release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 8d7bc02ad..41218032c 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -95,6 +95,9 @@ jobs:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
+ - name: Install zip
+ run: sudo apt-get install -y zip
+
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v7
with:
@@ -106,23 +109,13 @@ jobs:
GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }}
DOCKERHUB_IMAGE_NAME: ${{ vars.DOCKERHUB_REPOSITORY }}
GOVERSION: ${{ steps.setup-go.outputs.go-version }}
+ INCLUDE_ANDROID_BUNDLE: "true"
MACOS_SIGN_P12: ${{ secrets.MACOS_SIGN_P12 }}
MACOS_SIGN_PASSWORD: ${{ secrets.MACOS_SIGN_PASSWORD }}
MACOS_NOTARY_ISSUER_ID: ${{ secrets.MACOS_NOTARY_ISSUER_ID }}
MACOS_NOTARY_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }}
MACOS_NOTARY_KEY: ${{ secrets.MACOS_NOTARY_KEY }}
- - name: Build and upload release-only artifacts
- shell: bash
- env:
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: |
- sudo apt-get install -y zip
- make build-release-artifacts
- gh release upload "${{ inputs.tag }}" \
- build/picoclaw-android-universal.zip \
- --clobber
-
- name: Apply release flags
shell: bash
env:
diff --git a/.goreleaser.yaml b/.goreleaser.yaml
index b20856110..d8c51b069 100644
--- a/.goreleaser.yaml
+++ b/.goreleaser.yaml
@@ -12,6 +12,7 @@ before:
- go generate ./...
- sh -c 'cd web/frontend && CI=true pnpm install --frozen-lockfile && pnpm build:backend'
- sh -c 'GOBIN="$(go env GOPATH)/bin"; mkdir -p "$GOBIN"; go install github.com/tc-hib/go-winres@v0.3.3 && "$GOBIN/go-winres" make --in web/backend/winres/winres.json --out web/backend/rsrc --product-version={{ .Version }} --file-version={{ .Version }}'
+ - sh -c 'if [ "${INCLUDE_ANDROID_BUNDLE:-}" = "true" ]; then make build-android-bundle; fi'
builds:
- id: picoclaw
@@ -251,6 +252,8 @@ changelog:
release:
disable: '{{ isEnvSet "NIGHTLY_BUILD" }}'
+ extra_files:
+ - glob: ./build/picoclaw-android-universal.zip
footer: >-
---
diff --git a/Makefile b/Makefile
index 717273efa..afaa7c29a 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-.PHONY: all build install uninstall clean help test build-core-all build-release-artifacts
+.PHONY: all build install uninstall clean help test build-all
# Build variables
BINARY_NAME=picoclaw
@@ -242,8 +242,8 @@ build-android-bundle: generate
build-pi-zero: build-linux-arm build-linux-arm64
@echo "Pi Zero 2 W builds: $(BUILD_DIR)/$(BINARY_NAME)-linux-arm (32-bit), $(BUILD_DIR)/$(BINARY_NAME)-linux-arm64 (64-bit)"
-## build-core-all: Build the picoclaw core binary for all Makefile-managed platforms
-build-core-all: generate
+## build-all: Build the picoclaw core binary for all Makefile-managed platforms
+build-all: generate
@echo "Building for multiple platforms..."
@mkdir -p $(BUILD_DIR)
GOOS=linux GOARCH=amd64 $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(BINARY_NAME)-linux-amd64 ./$(CMD_DIR)
@@ -261,13 +261,6 @@ build-core-all: generate
GOOS=netbsd GOARCH=arm64 $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/$(BINARY_NAME)-netbsd-arm64 ./$(CMD_DIR)
@echo "Core builds complete"
-## build-all: Build the picoclaw core binary for all Makefile-managed platforms
-build-all: build-core-all
-
-## build-release-artifacts: Build release-only artifacts that sit outside GoReleaser
-build-release-artifacts: build-android-bundle
- @echo "Release artifact builds complete"
-
## install: Install picoclaw to system and copy builtin skills
install: build
@echo "Installing $(BINARY_NAME)..."
diff --git a/README.fr.md b/README.fr.md
index ecafefdc7..570365d00 100644
--- a/README.fr.md
+++ b/README.fr.md
@@ -190,9 +190,6 @@ make build-launcher
# Compiler les binaires core pour toutes les plateformes gérées par le Makefile
make build-all
-# Compiler les artefacts de release empaquetés séparément des sorties principales de GoReleaser
-make build-release-artifacts
-
# Compiler pour Raspberry Pi Zero 2 W (32 bits : make build-linux-arm ; 64 bits : make build-linux-arm64)
make build-pi-zero
@@ -200,10 +197,6 @@ make build-pi-zero
make install
```
-`make build-all` compile les binaires core de `picoclaw` pour toutes les plateformes gérées par le Makefile.
-
-`make build-release-artifacts` compile les artefacts de release empaquetés séparément des sorties principales de GoReleaser.
-
**Raspberry Pi Zero 2 W :** Utilisez le binaire correspondant à votre OS : Raspberry Pi OS 32 bits -> `make build-linux-arm` ; 64 bits -> `make build-linux-arm64`. Ou exécutez `make build-pi-zero` pour compiler les deux.
## 🚀 Guide de démarrage rapide
@@ -635,4 +628,3 @@ Discord :
WeChat :
-
diff --git a/README.id.md b/README.id.md
index f57d2f0bc..f4257f338 100644
--- a/README.id.md
+++ b/README.id.md
@@ -187,9 +187,6 @@ make build-launcher
# Build binary inti untuk semua platform yang dikelola Makefile
make build-all
-# Build artefak rilis yang dikemas terpisah dari output utama GoReleaser
-make build-release-artifacts
-
# Build untuk Raspberry Pi Zero 2 W (32-bit: make build-linux-arm; 64-bit: make build-linux-arm64)
make build-pi-zero
@@ -197,10 +194,6 @@ make build-pi-zero
make install
```
-`make build-all` membangun binary inti `picoclaw` untuk semua platform yang dikelola Makefile.
-
-`make build-release-artifacts` membangun artefak rilis yang dikemas terpisah dari output utama GoReleaser.
-
**Raspberry Pi Zero 2 W:** Gunakan binary yang sesuai dengan OS Anda: Raspberry Pi OS 32-bit -> `make build-linux-arm`; 64-bit -> `make build-linux-arm64`. Atau jalankan `make build-pi-zero` untuk build keduanya.
## 🚀 Panduan Memulai Cepat
diff --git a/README.it.md b/README.it.md
index 4c18f6f5b..b559cda2e 100644
--- a/README.it.md
+++ b/README.it.md
@@ -187,9 +187,6 @@ make build-launcher
# Compila i binari core per tutte le piattaforme gestite dal Makefile
make build-all
-# Compila gli artefatti di release impacchettati separatamente dagli output principali di GoReleaser
-make build-release-artifacts
-
# Compila per Raspberry Pi Zero 2 W (32-bit: make build-linux-arm; 64-bit: make build-linux-arm64)
make build-pi-zero
@@ -197,10 +194,6 @@ make build-pi-zero
make install
```
-`make build-all` compila i binari core di `picoclaw` per tutte le piattaforme gestite dal Makefile.
-
-`make build-release-artifacts` compila gli artefatti di release impacchettati separatamente dagli output principali di GoReleaser.
-
**Raspberry Pi Zero 2 W:** Usa il binario che corrisponde al tuo OS: Raspberry Pi OS 32-bit -> `make build-linux-arm`; 64-bit -> `make build-linux-arm64`. Oppure esegui `make build-pi-zero` per compilare entrambi.
## 🚀 Guida Rapida
diff --git a/README.ja.md b/README.ja.md
index 0ad159a53..0e6483be6 100644
--- a/README.ja.md
+++ b/README.ja.md
@@ -187,9 +187,6 @@ make build-launcher
# Makefile が管理するすべてのプラットフォーム向けにコアバイナリをビルド
make build-all
-# メインの GoReleaser 出力とは別にパッケージ化されるリリース専用成果物をビルド
-make build-release-artifacts
-
# Raspberry Pi Zero 2 W 向けビルド(32-bit: make build-linux-arm; 64-bit: make build-linux-arm64)
make build-pi-zero
@@ -197,10 +194,6 @@ make build-pi-zero
make install
```
-`make build-all` は、Makefile が管理するすべてのプラットフォーム向けにコアの `picoclaw` バイナリをビルドします。
-
-`make build-release-artifacts` は、メインの GoReleaser 出力とは別にパッケージ化されるリリース専用成果物をビルドします。
-
**Raspberry Pi Zero 2 W:** OS に合ったバイナリを使用してください:32-bit Raspberry Pi OS → `make build-linux-arm`、64-bit → `make build-linux-arm64`。または `make build-pi-zero` で両方をビルド。
## 🚀 クイックスタートガイド
diff --git a/README.ko.md b/README.ko.md
index 5f99dd32e..e520ffd29 100644
--- a/README.ko.md
+++ b/README.ko.md
@@ -187,9 +187,6 @@ make build-launcher
# Makefile이 관리하는 모든 플랫폼용 코어 바이너리 빌드
make build-all
-# 메인 GoReleaser 출력과 별도로 패키징되는 릴리스 전용 산출물 빌드
-make build-release-artifacts
-
# Raspberry Pi Zero 2 W용 빌드 (32비트: make build-linux-arm, 64비트: make build-linux-arm64)
make build-pi-zero
@@ -197,10 +194,6 @@ make build-pi-zero
make install
```
-`make build-all`은 Makefile이 관리하는 모든 플랫폼용 핵심 `picoclaw` 바이너리를 빌드합니다.
-
-`make build-release-artifacts`는 메인 GoReleaser 출력과 별도로 패키징되는 릴리스 전용 산출물을 빌드합니다.
-
**Raspberry Pi Zero 2 W:** OS에 맞는 바이너리를 사용하세요. 32비트 Raspberry Pi OS는 `make build-linux-arm`, 64비트는 `make build-linux-arm64`입니다. 또는 `make build-pi-zero`로 둘 다 빌드할 수 있습니다.
## 🚀 빠른 시작 가이드
diff --git a/README.md b/README.md
index fd082f6bf..bbe48061a 100644
--- a/README.md
+++ b/README.md
@@ -187,9 +187,6 @@ make build-launcher
# Build core binaries for all Makefile-managed platforms
make build-all
-# Build release-only artifacts packaged separately from the main GoReleaser outputs
-make build-release-artifacts
-
# Build for Raspberry Pi Zero 2 W
# 32-bit: make build-linux-arm
# 64-bit: make build-linux-arm64
@@ -199,10 +196,6 @@ make build-pi-zero
make install
```
-`make build-all` builds the core `picoclaw` binaries for all Makefile-managed platforms.
-
-`make build-release-artifacts` builds release-only artifacts that are packaged separately from the main GoReleaser outputs.
-
**Raspberry Pi Zero 2 W:** Use the binary that matches your OS: 32-bit Raspberry Pi OS -> `make build-linux-arm`; 64-bit -> `make build-linux-arm64`. Or run `make build-pi-zero` to build both.
## 🚀 Quick Start Guide
@@ -232,7 +225,7 @@ picoclaw-launcher
-**Getting started:**
+**Getting started:**
Open the WebUI, then: **1)** Configure a Provider (add your LLM API key) -> **2)** Configure a Channel (e.g., Telegram) -> **3)** Start the Gateway -> **4)** Chat!
@@ -310,7 +303,7 @@ picoclaw-launcher-tui
-**Getting started:**
+**Getting started:**
Use the TUI menus to: **1)** Configure a Provider -> **2)** Configure a Channel -> **3)** Start the Gateway -> **4)** Chat!
@@ -385,7 +378,7 @@ This creates `~/.picoclaw/config.json` and the workspace directory.
```
> See `config/config.example.json` in the repo for a complete configuration template with all available options.
->
+>
> Please note: config.example.json format is version 0, with sensitive codes in it, and will be auto migrated to version 1+, then, the config.json will only store insensitive data, the sensitive codes will be stored in .security.yml, if you need manually modify the codes, please see `docs/security_configuration.md` for more details.
diff --git a/README.my.md b/README.my.md
index a5719c696..255773263 100644
--- a/README.my.md
+++ b/README.my.md
@@ -187,9 +187,6 @@ make build-launcher
# Bina binari teras untuk semua platform yang diuruskan oleh Makefile
make build-all
-# Bina artifak keluaran yang dibungkus berasingan daripada output utama GoReleaser
-make build-release-artifacts
-
# Bina untuk Raspberry Pi Zero 2 W (32-bit: make build-linux-arm; 64-bit: make build-linux-arm64)
make build-pi-zero
@@ -197,10 +194,6 @@ make build-pi-zero
make install
```
-`make build-all` membina binari teras `picoclaw` untuk semua platform yang diuruskan oleh Makefile.
-
-`make build-release-artifacts` membina artifak keluaran yang dibungkus berasingan daripada output utama GoReleaser.
-
**Raspberry Pi Zero 2 W:** Gunakan binari yang sepadan dengan OS anda: Raspberry Pi OS 32-bit -> `make build-linux-arm`; 64-bit -> `make build-linux-arm64`. Atau jalankan `make build-pi-zero` untuk membina kedua-duanya.
## 🚀 Panduan Permulaan Pantas
diff --git a/README.pt-br.md b/README.pt-br.md
index d9b64c959..36d65d8c4 100644
--- a/README.pt-br.md
+++ b/README.pt-br.md
@@ -187,9 +187,6 @@ make build-launcher
# Compilar os binários core para todas as plataformas gerenciadas pelo Makefile
make build-all
-# Compilar os artefatos de release empacotados separadamente das saídas principais do GoReleaser
-make build-release-artifacts
-
# Compilar para Raspberry Pi Zero 2 W (32-bit: make build-linux-arm; 64-bit: make build-linux-arm64)
make build-pi-zero
@@ -197,10 +194,6 @@ make build-pi-zero
make install
```
-`make build-all` compila os binários core do `picoclaw` para todas as plataformas gerenciadas pelo Makefile.
-
-`make build-release-artifacts` compila os artefatos de release empacotados separadamente das saídas principais do GoReleaser.
-
**Raspberry Pi Zero 2 W:** Use o binário que corresponde ao seu SO: Raspberry Pi OS 32-bit -> `make build-linux-arm`; 64-bit -> `make build-linux-arm64`. Ou execute `make build-pi-zero` para compilar ambos.
## 🚀 Guia de Início Rápido
diff --git a/README.vi.md b/README.vi.md
index 3475830fb..67845d073 100644
--- a/README.vi.md
+++ b/README.vi.md
@@ -187,9 +187,6 @@ make build-launcher
# Build các binary lõi cho mọi nền tảng do Makefile quản lý
make build-all
-# Build các release artifact được đóng gói tách biệt với các đầu ra chính của GoReleaser
-make build-release-artifacts
-
# Build for Raspberry Pi Zero 2 W (32-bit: make build-linux-arm; 64-bit: make build-linux-arm64)
make build-pi-zero
@@ -197,10 +194,6 @@ make build-pi-zero
make install
```
-`make build-all` build các binary lõi `picoclaw` cho mọi nền tảng do Makefile quản lý.
-
-`make build-release-artifacts` build các release artifact được đóng gói tách biệt với các đầu ra chính của GoReleaser.
-
**Raspberry Pi Zero 2 W:** Sử dụng binary phù hợp với hệ điều hành của bạn: Raspberry Pi OS 32-bit -> `make build-linux-arm`; 64-bit -> `make build-linux-arm64`. Hoặc chạy `make build-pi-zero` để xây dựng cả hai.
## 🚀 Hướng dẫn Khởi động Nhanh
diff --git a/README.zh.md b/README.zh.md
index ddb3bb230..329fedb86 100644
--- a/README.zh.md
+++ b/README.zh.md
@@ -187,9 +187,6 @@ make build-launcher
# 为 Makefile 管理的所有平台构建核心二进制文件
make build-all
-# 构建独立于主 GoReleaser 输出之外的发布附加产物
-make build-release-artifacts
-
# 为 Raspberry Pi Zero 2 W 构建(32位: make build-linux-arm; 64位: make build-linux-arm64)
make build-pi-zero
@@ -197,10 +194,6 @@ make build-pi-zero
make install
```
-`make build-all` 会为所有由 Makefile 管理的平台构建核心 `picoclaw` 二进制文件。
-
-`make build-release-artifacts` 会构建独立于主 GoReleaser 输出之外打包的发布附加产物。
-
**Raspberry Pi Zero 2 W:** 请使用与系统匹配的二进制文件:32 位 Raspberry Pi OS → `make build-linux-arm`;64 位 → `make build-linux-arm64`。或运行 `make build-pi-zero` 同时构建两者。
## 🚀 快速开始
@@ -633,4 +626,3 @@ WeChat:
-
From 6a870cb2601828c95bec790a752947119708028b Mon Sep 17 00:00:00 2001
From: wenjie
Date: Mon, 13 Apr 2026 11:56:43 +0800
Subject: [PATCH 6/6] ci(build): remove unused Node.js and pnpm setup from core
build workflow
---
.github/workflows/build.yml | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index f21e3ef5f..def19c3e5 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -16,15 +16,5 @@ jobs:
with:
go-version-file: go.mod
- - name: Setup Node.js
- uses: actions/setup-node@v6
- with:
- node-version: 22
- cache: pnpm
- cache-dependency-path: web/frontend/pnpm-lock.yaml
-
- - name: Setup pnpm
- run: corepack enable && corepack install
-
- name: Build core binaries
run: make build-all