ci: add release-bundle workflow for per-platform zip packages

- workflow_dispatch with tag, prerelease, draft inputs
- Cross-compile picoclaw for 8 platforms
- Build launcher on native runners via go tool wails
- Launcher failure is non-blocking (continue-on-error)
- Taskfile: task all, task build-launcher
- Updated README with install instructions
This commit is contained in:
mingzhi1 2026-03-03 12:50:59 +08:00
parent 946af6b53d
commit 78fdf70a7d
4 changed files with 708 additions and 0 deletions

407
.github/workflows/release-bundle.yml vendored Normal file
View file

@ -0,0 +1,407 @@
name: Release Bundle
on:
workflow_dispatch:
inputs:
tag:
description: "Release tag (e.g. v0.2.0)"
required: true
type: string
prerelease:
description: "Mark as pre-release"
required: false
type: boolean
default: false
draft:
description: "Create as draft"
required: false
type: boolean
default: true
jobs:
# ──────────────────────────────────────────────────────────────────────────
# 1. Create Git tag
# ──────────────────────────────────────────────────────────────────────────
create-tag:
name: Create Git Tag
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Create and push tag
env:
RELEASE_TAG: ${{ inputs.tag }}
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag -a "$RELEASE_TAG" -m "Release $RELEASE_TAG"
git push origin "$RELEASE_TAG"
# ──────────────────────────────────────────────────────────────────────────
# 2. Build picoclaw (CGO_ENABLED=0, pure Go, cross-compile on ubuntu)
# ──────────────────────────────────────────────────────────────────────────
build-picoclaw:
name: Build picoclaw (${{ matrix.goos }}/${{ matrix.goarch }})
needs: create-tag
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
matrix:
include:
- goos: linux
goarch: amd64
suffix: ""
- goos: linux
goarch: arm64
suffix: ""
- goos: linux
goarch: arm
goarm: "7"
suffix: ""
- goos: linux
goarch: riscv64
suffix: ""
- goos: linux
goarch: loong64
suffix: ""
- goos: windows
goarch: amd64
suffix: ".exe"
- goos: darwin
goarch: amd64
suffix: ""
- goos: darwin
goarch: arm64
suffix: ""
steps:
- name: Checkout tag
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ inputs.tag }}
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Generate embedded assets
run: go generate ./...
- name: Build picoclaw
env:
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
GOARM: ${{ matrix.goarm }}
CGO_ENABLED: "0"
VERSION: ${{ inputs.tag }}
run: |
mkdir -p dist
OUTPUT="dist/picoclaw${{ matrix.suffix }}"
go build \
-tags stdjson \
-ldflags "-s -w \
-X github.com/sipeed/picoclaw/cmd/picoclaw/internal.version=${VERSION} \
-X github.com/sipeed/picoclaw/cmd/picoclaw/internal.gitCommit=$(git rev-parse --short HEAD) \
-X github.com/sipeed/picoclaw/cmd/picoclaw/internal.buildTime=$(date -u +%FT%TZ)" \
-o "${OUTPUT}" \
./cmd/picoclaw
- name: Upload picoclaw artifact
uses: actions/upload-artifact@v4
with:
name: picoclaw-${{ matrix.goos }}-${{ matrix.goarch }}${{ matrix.goarm && format('-armv{0}', matrix.goarm) || '' }}
path: dist/picoclaw${{ matrix.suffix }}
retention-days: 1
# ──────────────────────────────────────────────────────────────────────────
# 3a. Build Launcher — Windows (Wails requires WebView2)
# Note: continue-on-error=true so packaging still runs if wails build fails
# ──────────────────────────────────────────────────────────────────────────
build-launcher-windows:
name: Build launcher (windows/amd64)
needs: create-tag
runs-on: windows-latest
continue-on-error: true
permissions:
contents: read
steps:
- name: Checkout tag
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ inputs.tag }}
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Build launcher
working-directory: cmd/picoclaw-launcher
run: |
go tool wails build -tags stdjson -ldflags "-s -w" -o picoclaw-launcher.exe
- name: Upload launcher artifact
uses: actions/upload-artifact@v4
with:
name: launcher-windows-amd64
path: cmd/picoclaw-launcher/build/bin/picoclaw-launcher.exe
retention-days: 1
# ──────────────────────────────────────────────────────────────────────────
# 3b. Build Launcher — Linux/amd64 (Wails requires GTK/WebKit)
# ──────────────────────────────────────────────────────────────────────────
build-launcher-linux:
name: Build launcher (linux/amd64)
needs: create-tag
runs-on: ubuntu-latest
continue-on-error: true
permissions:
contents: read
steps:
- name: Checkout tag
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ inputs.tag }}
- name: Install WebKit/GTK dependencies
run: |
sudo apt-get update -qq
sudo apt-get install -y --no-install-recommends \
libgtk-3-dev \
libwebkit2gtk-4.0-dev \
pkg-config \
build-essential
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Build launcher
working-directory: cmd/picoclaw-launcher
run: |
go tool wails build -tags stdjson -ldflags "-s -w" -o picoclaw-launcher
- name: Upload launcher artifact
uses: actions/upload-artifact@v4
with:
name: launcher-linux-amd64
path: cmd/picoclaw-launcher/build/bin/picoclaw-launcher
retention-days: 1
# ──────────────────────────────────────────────────────────────────────────
# 3c. Build Launcher — macOS (universal binary: amd64 + arm64)
# ──────────────────────────────────────────────────────────────────────────
build-launcher-macos:
name: Build launcher (darwin/universal)
needs: create-tag
runs-on: macos-latest
continue-on-error: true
permissions:
contents: read
steps:
- name: Checkout tag
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ inputs.tag }}
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Build launcher (universal)
working-directory: cmd/picoclaw-launcher
run: |
go tool wails build -tags stdjson -ldflags "-s -w" -platform darwin/universal -o picoclaw-launcher
- name: Upload launcher artifact
uses: actions/upload-artifact@v4
with:
name: launcher-darwin-universal
path: cmd/picoclaw-launcher/build/bin/picoclaw-launcher
retention-days: 1
# ──────────────────────────────────────────────────────────────────────────
# 4. Package: assemble zip bundles per platform and create GitHub Release
# Runs even if launcher builds fail (if: ${{ !cancelled() }})
# Launcher is included only if its artifact was successfully uploaded
# ──────────────────────────────────────────────────────────────────────────
package-and-release:
name: Package & Create Release
needs:
- build-picoclaw
- build-launcher-windows
- build-launcher-linux
- build-launcher-macos
# Run even if launcher jobs fail; only skip if workflow is cancelled
if: ${{ !cancelled() && needs.build-picoclaw.result == 'success' }}
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout tag
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ inputs.tag }}
# ── Download picoclaw artifacts (always present) ──
- name: Download picoclaw artifacts
uses: actions/download-artifact@v4
with:
pattern: picoclaw-*
path: artifacts
merge-multiple: false
# ── Download launcher artifacts (may be missing if build failed) ──
- name: Download launcher-windows artifact
uses: actions/download-artifact@v4
if: ${{ needs.build-launcher-windows.result == 'success' }}
with:
name: launcher-windows-amd64
path: artifacts/launcher-windows-amd64
continue-on-error: true
- name: Download launcher-linux artifact
uses: actions/download-artifact@v4
if: ${{ needs.build-launcher-linux.result == 'success' }}
with:
name: launcher-linux-amd64
path: artifacts/launcher-linux-amd64
continue-on-error: true
- name: Download launcher-macos artifact
uses: actions/download-artifact@v4
if: ${{ needs.build-launcher-macos.result == 'success' }}
with:
name: launcher-darwin-universal
path: artifacts/launcher-darwin-universal
continue-on-error: true
- name: List downloaded artifacts
run: find artifacts -type f | sort
# ── Assemble zip bundles ──
- name: Assemble zip bundles
env:
TAG: ${{ inputs.tag }}
run: |
set -euo pipefail
mkdir -p release staging
# ── helper: bundle picoclaw + optional launcher into a zip ──
make_zip() {
local NAME="$1" # bundle name, e.g. picoclaw_v0.1.0_windows_amd64
local PICOCLAW="$2" # source path of picoclaw binary
local LAUNCHER="${3:-}" # source path of launcher binary (empty = omit)
local EXT="${4:-}" # ".exe" or ""
local DIR="staging/${NAME}"
mkdir -p "${DIR}"
chmod +x "${PICOCLAW}" 2>/dev/null || true
cp "${PICOCLAW}" "${DIR}/picoclaw${EXT}"
if [ -n "${LAUNCHER}" ] && [ -f "${LAUNCHER}" ]; then
chmod +x "${LAUNCHER}" 2>/dev/null || true
cp "${LAUNCHER}" "${DIR}/picoclaw-launcher${EXT}"
echo "PicoClaw Bundle (picoclaw + picoclaw-launcher)" > "${DIR}/README.txt"
else
echo "PicoClaw CLI only (picoclaw-launcher not available for this platform)" > "${DIR}/README.txt"
fi
(cd staging && zip -r "../release/${NAME}.zip" "${NAME}/")
echo " created: release/${NAME}.zip"
}
WINLAUNCHER=""
LINLAUNCHER=""
MACLAUNCHER=""
[ -f "artifacts/launcher-windows-amd64/picoclaw-launcher.exe" ] \
&& WINLAUNCHER="artifacts/launcher-windows-amd64/picoclaw-launcher.exe"
[ -f "artifacts/launcher-linux-amd64/picoclaw-launcher" ] \
&& LINLAUNCHER="artifacts/launcher-linux-amd64/picoclaw-launcher"
[ -f "artifacts/launcher-darwin-universal/picoclaw-launcher" ] \
&& MACLAUNCHER="artifacts/launcher-darwin-universal/picoclaw-launcher"
# Windows amd64
make_zip \
"picoclaw_${TAG}_windows_amd64" \
"artifacts/picoclaw-windows-amd64/picoclaw.exe" \
"${WINLAUNCHER}" \
".exe"
# Linux amd64
make_zip \
"picoclaw_${TAG}_linux_amd64" \
"artifacts/picoclaw-linux-amd64/picoclaw" \
"${LINLAUNCHER}" \
""
# macOS amd64 (with universal launcher if available)
make_zip \
"picoclaw_${TAG}_darwin_amd64" \
"artifacts/picoclaw-darwin-amd64/picoclaw" \
"${MACLAUNCHER}" \
""
# macOS arm64 (with universal launcher if available)
make_zip \
"picoclaw_${TAG}_darwin_arm64" \
"artifacts/picoclaw-darwin-arm64/picoclaw" \
"${MACLAUNCHER}" \
""
# Linux arm64 (picoclaw only)
make_zip \
"picoclaw_${TAG}_linux_arm64" \
"artifacts/picoclaw-linux-arm64/picoclaw" \
"" ""
# Linux armv7 (picoclaw only)
make_zip \
"picoclaw_${TAG}_linux_armv7" \
"artifacts/picoclaw-linux-arm-armv7/picoclaw" \
"" ""
# Linux riscv64 (picoclaw only)
make_zip \
"picoclaw_${TAG}_linux_riscv64" \
"artifacts/picoclaw-linux-riscv64/picoclaw" \
"" ""
# Linux loong64 (picoclaw only)
make_zip \
"picoclaw_${TAG}_linux_loong64" \
"artifacts/picoclaw-linux-loong64/picoclaw" \
"" ""
echo ""
echo "=== Final release assets ==="
ls -lh release/
# ── Create GitHub Release ──
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ inputs.tag }}
name: "PicoClaw ${{ inputs.tag }}"
draft: ${{ inputs.draft }}
prerelease: ${{ inputs.prerelease }}
generate_release_notes: true
files: release/*.zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View file

@ -82,6 +82,87 @@
<img src="assets/compare.jpg" alt="PicoClaw" width="512">
## 🧠 Our Thinking
PicoClaw isn't just small — it **thinks differently**. While most AI agent frameworks treat the LLM as a black box that swallows everything (all tools, all history, all context), PicoClaw introduces a structured **Runtime Loop** that makes every token count.
### Three-Phase Runtime Loop
Every user interaction flows through three distinct phases:
```
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Phase 1 │ → │ Phase 2 │ → │ Phase 3 │
│ Analyse │ │ ExecuteLLM │ │ Reflect │
│ (Orchestrate) │ (Execute) │ │ (Learn) │
└──────────────┘ └──────────────┘ └──────────────┘
```
- **Phase 1 — Analyse**: A lightweight LLM call (can use a cheaper/faster model) that understands intent, assigns semantic tags, and prepares the optimal context. No tools, no history bloat — just pure comprehension.
- **Phase 2 — ExecuteLLM**: The main LLM iterates with only the tools and context that Phase 1 deemed relevant. Fewer tools = less confusion = better decisions.
- **Phase 3 — Reflect**: Synchronous scoring + context update (< 2ms) before the user sees the reply, followed by async persistence. The agent learns from every interaction without adding latency.
### Turn Scoring & Instant Memory
Every Turn gets a **score** based on tool activity, intent weight, content density, and explicit user markers. This score drives a novel context selection algorithm:
```
Instant Memory = { high-score Turns } // always kept, unconditionally
{ tag-matched Turns, score > 0 } // relevant old Turns "resurrected"
{ recent M Turns } // continuity baseline
→ sorted by time, truncated to capacity
```
**No Turn is ever deleted.** Low-score Turns are simply excluded from context — but when a future Phase 1 produces matching tags, they can be recalled. It's like human memory: you don't forget things, you just can't always access them until something triggers the recall.
### Tag-Gated Tool Loading
Instead of feeding 20+ tool definitions to the LLM every request (wasting ~3,000 tokens per iteration), PicoClaw categorizes tools:
| Layer | Tools | Loading |
|-------|-------|---------|
| **always-on** | `read_file`, `write_file`, `shell`, etc. | Always present |
| **tag-gated** | MCP servers, Skills, `web_search`, `cron` | Only when Phase 1 tags match |
As MCP servers and Skills grow, the savings compound exponentially — and the LLM makes better decisions with a focused toolset.
### KV Cache-Friendly Message Ordering
We obsess over **prefix stability** to maximize KV cache hits across providers (Gemini implicit cache, Anthropic `cache_control`, OpenAI prompt caching):
```
[system_prompt] ← always cached ✅
[long_term_memory by tags] ← stable when same tags ✅
[high-score Turns, ASC by ID] ← fixed positions, append-only ✅
[tag-matched Turns] ← may vary
[recent Turns] ← rolling window
[current user message] ← always new
```
High-score Turns are **pinned** right after long-term memory in ascending order. New Turns only append — they never shift existing content. This maximizes the cache-hit prefix length, and the cost difference is dramatic at scale.
### Three-Layer Memory Hierarchy
| Layer | Lifecycle | Source | Consumer |
|-------|-----------|--------|----------|
| **Instant Memory** | Assembled per-Turn | Turn Store (score + tag filter) | Phase 2 (ExecuteLLM) |
| **Active Context** | Rolling update per `channel:chatID` | Phase 3 sync update | Phase 1 (Analyse) |
| **Long-Term Memory** | Persistent | MemoryDigest batch worker | Phase 1 (via tag retrieval) |
Each layer serves a different phase. No overlap, no waste. Active Context (current files, recent errors) helps Phase 1 understand terse messages like "fix it". Instant Memory gives Phase 2 the right historical context. Long-term memory accumulates wisdom across sessions.
### Why This Matters
Traditional agent loops dump everything into one LLM call and hope for the best. PicoClaw's approach means:
- 📉 **~60% fewer wasted tokens** from irrelevant tools and stale context
- 🎯 **Higher decision quality** — focused toolsets reduce LLM confusion
- ⚡ **Sub-2ms overhead** for scoring and context updates (zero perceived latency)
- 🧲 **Associative recall** — old conversations resurface when relevant, like human memory
- 💰 **Multi-model cost optimization** — use cheap models for analysis, strong models for execution
> *"The best token is the one you never send."*
## 🦾 Demonstration
### 🛠️ Standard Assistant Workflows

View file

@ -80,6 +80,87 @@
<img src="assets/compare.jpg" alt="PicoClaw" width="512">
## 🧠 我们的思考
PicoClaw 不只是小——它的**思维方式**和其他 AI Agent 框架根本不同。大多数框架把 LLM 当黑箱把所有工具、所有历史、所有上下文一股脑塞进去。PicoClaw 引入了结构化的 **Runtime Loop**,让每一个 token 都物尽其用。
### 三阶段 Runtime Loop
每次用户交互都经过三个清晰的阶段:
```
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Phase 1 │ → │ Phase 2 │ → │ Phase 3 │
│ 分析 Analyse│ │ 执行 ExecuteLLM│ │ 反思 Reflect │
│ (编排器) │ │ (执行器) │ │ (学习器) │
└──────────────┘ └──────────────┘ └──────────────┘
```
- **Phase 1 — 分析**:轻量 LLM 调用(可用便宜/快速模型),理解用户意图、分配语义标签、准备最优上下文。无工具、无历史膨胀——纯粹的理解力。
- **Phase 2 — 执行**:主 LLM 只携带 Phase 1 认为相关的工具和上下文进行迭代。工具越少 = 干扰越少 = 决策越好。
- **Phase 3 — 反思**:同步打分 + 上下文更新(< 2ms在用户看到回复之前完成然后异步持久化Agent 从每次交互中学习且不增加延迟
### Turn 打分 & 瞬时记忆
每个 Turn 都会根据工具活动、意图权重、内容密度和用户显式标记获得一个**分数**。这个分数驱动一个新颖的上下文选择算法:
```
瞬时记忆 = { 高分 Turn } // 无条件保留
{ tag 匹配的 Turn, score > 0 } // 旧 Turn 被"唤醒"
{ 最近 M 个 Turn } // 连贯性保底
→ 按时间排序,截断到容量上限
```
**Turn 永不删除。** 低分 Turn 只是被排除在上下文之外——但当未来 Phase 1 产生匹配的 tags 时,它们可以被重新召回。就像人类记忆:你不会忘记东西,只是在某个触发点之前无法访问它们。
### Tag 驱动的工具加载
传统框架每次请求都把 20+ 个工具定义喂给 LLM每次迭代浪费 ~3,000 tokens。PicoClaw 把工具分为两层:
| 层级 | 工具 | 加载方式 |
|------|------|---------|
| **always-on** | `read_file``write_file``shell` 等 | 始终加载 |
| **tag-gated** | MCP servers、Skills、`web_search``cron` | 仅当 Phase 1 的 tags 匹配时加载 |
随着 MCP Servers 和 Skills 的增多,节省量呈指数级增长——而且 LLM 在精简的工具集下做出更好的决策。
### KV Cache 友好的消息排列
我们执着于**前缀稳定性**,以最大化跨 Provider 的 KV Cache 命中率Gemini 隐式缓存、Anthropic `cache_control`、OpenAI prompt caching
```
[system_prompt] ← 始终缓存 ✅
[long_term_memory by tags] ← 相同 tags 时稳定 ✅
[高分 Turn, 按 ID 升序] ← 位置固定,只增不移 ✅
[tag 匹配的 Turn] ← 可能变化
[最近的 Turn] ← 滚动窗口
[当前用户消息] ← 总是新内容
```
高分 Turn 被**固定**在长期记忆之后,按升序排列。新 Turn 只追加到末尾,不改变已有内容的位置。这最大化了缓存命中的前缀长度,在规模化场景下成本差异显著。
### 三层记忆体系
| 层次 | 生命周期 | 数据来源 | 消费者 |
|------|---------|---------|--------|
| **瞬时记忆** | 每轮动态组装 | Turn 库score + tag 筛选)| Phase 2ExecuteLLM|
| **活跃上下文** | 跨 Turn 滚动更新per `channel:chatID` | Phase 3 同步维护 | Phase 1Analyse|
| **长期记忆** | 持久化 | MemoryDigest 定时批量提炼 | Phase 1通过 tag 检索)|
每层服务不同的阶段。没有重叠,没有浪费。活跃上下文(当前文件、近期错误)帮助 Phase 1 理解简短消息如"修一下"。瞬时记忆为 Phase 2 提供正确的历史上下文。长期记忆跨会话积累智慧。
### 为什么这很重要
传统的 Agent 循环把所有东西塞进一个 LLM 调用然后听天由命。PicoClaw 的方式意味着:
- 📉 **减少 ~60% 的浪费 token** — 排除无关工具和陈旧上下文
- 🎯 **更高的决策质量** — 精简工具集减少 LLM 的"选择困难症"
- ⚡ **< 2ms 的额外开销** 打分和上下文更新零感知延迟
- 🧲 **联想式召回** — 旧对话在相关时自动浮现,就像人类记忆
- 💰 **多模型成本优化** — 分析用便宜模型,执行用强模型
> *"最好的 token 是你永远不需要发送的那个。"*
## 🦾 演示
### 🛠️ 标准助手工作流

139
Taskfile.yml Normal file
View file

@ -0,0 +1,139 @@
version: '3'
vars:
BINARY_NAME: picoclaw
CMD_DIR: cmd/picoclaw
BUILD_DIR: build
LAUNCHER_DIR: cmd/picoclaw-launcher
LAUNCHER_BUILD_DIR: cmd/picoclaw-launcher/build/bin
INTERNAL: github.com/sipeed/picoclaw/cmd/picoclaw/internal
VERSION:
sh: git describe --tags --always --dirty 2>{{if eq OS "windows"}}nul{{else}}/dev/null{{end}} || echo dev
GIT_COMMIT:
sh: git rev-parse --short=8 HEAD 2>{{if eq OS "windows"}}nul{{else}}/dev/null{{end}} || echo dev
LDFLAGS: -ldflags "-X {{.INTERNAL}}.version={{.VERSION}} -X {{.INTERNAL}}.gitCommit={{.GIT_COMMIT}} -s -w"
tasks:
default:
desc: Build the project
cmds:
- task: build
all:
desc: Build picoclaw + launcher (both binaries)
deps:
- build
- build-launcher
build:
desc: Build picoclaw binary (dev, skip generate)
cmds:
- go build -v {{.LDFLAGS}} -o {{.BUILD_DIR}}/{{.BINARY_NAME}}{{exeExt}} ./{{.CMD_DIR}}
sources:
- "**/*.go"
generates:
- "{{.BUILD_DIR}}/{{.BINARY_NAME}}{{exeExt}}"
build-full:
desc: Build with go generate (release)
cmds:
- task: generate
- task: build
build-launcher:
desc: Build picoclaw-launcher (Wails desktop GUI)
dir: '{{.LAUNCHER_DIR}}'
cmds:
- go tool wails build -tags stdjson -ldflags "-s -w" -o picoclaw-launcher{{exeExt}}
sources:
- "**/*.go"
- frontend/**
generates:
- '../../{{.LAUNCHER_BUILD_DIR}}/picoclaw-launcher{{exeExt}}'
generate:
desc: Run go generate
cmds:
- cmd: powershell -Command "Remove-Item -Recurse -Force '{{.CMD_DIR}}/internal/onboard/workspace' -ErrorAction SilentlyContinue"
platforms: [windows]
- cmd: rm -rf {{.CMD_DIR}}/internal/onboard/workspace
platforms: [linux, darwin]
- go generate ./...
test:
desc: Run all tests
cmds:
- go test -count=1 ./pkg/...
test-v:
desc: Run all tests (verbose)
cmds:
- go test -v -count=1 ./pkg/...
test-agent:
desc: Run agent tests
cmds:
- go test -v -count=1 ./pkg/agent/
test-config:
desc: Run config tests
cmds:
- go test -v -count=1 ./pkg/config/
test-init:
desc: Run init command tests
cmds:
- go test -v -count=1 ./cmd/picoclaw/internal/initcmd/
lint:
desc: Run linters
cmds:
- golangci-lint run
fmt:
desc: Format code
cmds:
- gofmt -w .
vet:
desc: Run go vet
cmds:
- go vet ./...
clean:
desc: Remove build artifacts
cmds:
- cmd: powershell -Command "Remove-Item -Recurse -Force '{{.BUILD_DIR}}' -ErrorAction SilentlyContinue"
platforms: [windows]
- cmd: rm -rf {{.BUILD_DIR}}
platforms: [linux, darwin]
deps:
desc: Download and verify dependencies
cmds:
- go mod download
- go mod verify
tidy:
desc: Tidy dependencies
cmds:
- go mod tidy
check:
desc: Full check (fmt + vet + test)
cmds:
- task: fmt
- task: vet
- task: test
install:
desc: Install picoclaw to system
cmds:
- task: build
- go install ./{{.CMD_DIR}}
run:
desc: Build and run
cmds:
- task: build
- "{{.BUILD_DIR}}/{{.BINARY_NAME}}{{exeExt}} {{.CLI_ARGS}}"