Resolved conflicts:
- pkg/heartbeat/service.go: merged both 'started' field and 'onHeartbeatWithTools'
- pkg/tools/edit.go: use validatePath() with ToolResult return
- pkg/tools/filesystem.go: fixed return values to use ToolResult
- cmd/picoclaw/main.go: kept active setupCronTool, fixed toolsPkg import
- pkg/tools/cron.go: fixed Execute return value handling
Fixed tests for new function signatures (NewEditFileTool, NewAppendFileTool, NewExecTool)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Verified and tested that heartbeat log is written to memory directory:
- Current code uses workspace/memory/heartbeat.log (correct)
- Added TestLogPath test verifying log is in memory directory
- All acceptance criteria met
Note: US-020 was already implemented (log path was already memory/heartbeat.log).
This commit adds the missing test to verify the requirement.
Acceptance criteria met:
- Log path is workspace/memory/heartbeat.log (not workspace/heartbeat.log)
- Directory auto-created if missing (os.MkdirAll)
- Log format unchanged (timestamped messages)
- Typecheck passes (go build ./... succeeds)
- go test ./pkg/heartbeat -run TestLogPath passes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add local ToolResult struct definition to avoid circular dependencies
- Define HeartbeatHandler function type for tool-supporting callbacks
- Add SetOnHeartbeatWithTools method to configure new handler
- Add ExecuteHeartbeatWithTools public method
- Add internal executeHeartbeatWithTools implementation
- Update checkHeartbeat to prefer new tool-supporting handler
- Detect and handle async tasks (log and return immediately)
- Handle error results with proper logging
- Add comprehensive tests for async, error, sync, and nil result cases
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
HeartbeatService.Start() always returned early because running()
checked stopChan closure state, which is "open" (= true) for a
newly created service. This caused Start() to interpret a fresh
service as "already running" and skip launching the goroutine.
Introduce a `started` bool field to separate "has been started"
from "has not been stopped", fixing both the start failure and
a potential double-close panic on Stop().