## Rename - Module path: github.com/sipeed/picoclaw -> github.com/sipeed/piconomous - All binary names: picoclaw* -> piconomous* - Config/data paths: ~/.picoclaw -> ~/.piconomous - Env vars: PICOCLAW_* -> PICONOMOUS_* - Directory renames: cmd/picoclaw -> cmd/piconomous, cmd/picoclaw-launcher-tui -> cmd/piconomous-launcher-tui - Asset renames, desktop file, docker services ## Fully Autonomous Mode (new feature) Adds `autonomous` config section with: - `enabled`: activates goal-driven autonomous operation - `interval_minutes`: heartbeat frequency (default 5 min in autonomous mode) - `allow_self_schedule`: agent can create cron jobs for itself without command_confirm - `max_goals`: cap on concurrent active goals (default 20) ### New: Goal Management Tool (pkg/tools/goal.go) - `goal` tool with actions: set/list/complete/update/drop - Goals persist in GOALS.md (human-readable) + goals.json (machine-readable) - Priority levels P1-P5, status lifecycle: active -> completed/dropped ### Enhanced Heartbeat Service - SetAutonomous(bool) activates goal-driven prompt mode - In autonomous mode: reads GOALS.md each cycle, builds a rich prompt that instructs the agent to run the full software dev lifecycle: write code, run tests, fix failures, commit progress, schedule next steps - Creates default GOALS.md template on first run - Autonomous interval overrides heartbeat interval (5 min default vs 30 min) ### Cron Tool - In autonomous mode, agent can self-schedule on internal channels without requiring explicit command_confirm=true (GHSA-pv8c-p6jf-3fpp exception) ### Goal Tool Registration - Registered in AgentLoop.registerSharedTools when autonomous.enabled=true or when tools.goal is explicitly enabled in config https://claude.ai/code/session_0118WWK5KLRM7ZBUoC8EMgKS
57 lines
1.3 KiB
Go
57 lines
1.3 KiB
Go
package cron
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/spf13/cobra"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestNewAddSubcommand(t *testing.T) {
|
|
fn := func() string { return "" }
|
|
cmd := newAddCommand(fn)
|
|
|
|
require.NotNil(t, cmd)
|
|
|
|
assert.Equal(t, "add", cmd.Use)
|
|
assert.Equal(t, "Add a new scheduled job", cmd.Short)
|
|
|
|
assert.True(t, cmd.HasFlags())
|
|
|
|
assert.NotNil(t, cmd.Flags().Lookup("every"))
|
|
assert.NotNil(t, cmd.Flags().Lookup("cron"))
|
|
assert.NotNil(t, cmd.Flags().Lookup("deliver"))
|
|
assert.NotNil(t, cmd.Flags().Lookup("to"))
|
|
assert.NotNil(t, cmd.Flags().Lookup("channel"))
|
|
|
|
nameFlag := cmd.Flags().Lookup("name")
|
|
require.NotNil(t, nameFlag)
|
|
|
|
messageFlag := cmd.Flags().Lookup("message")
|
|
require.NotNil(t, messageFlag)
|
|
|
|
val, found := nameFlag.Annotations[cobra.BashCompOneRequiredFlag]
|
|
require.True(t, found)
|
|
require.NotEmpty(t, val)
|
|
assert.Equal(t, "true", val[0])
|
|
|
|
val, found = messageFlag.Annotations[cobra.BashCompOneRequiredFlag]
|
|
require.True(t, found)
|
|
require.NotEmpty(t, val)
|
|
assert.Equal(t, "true", val[0])
|
|
}
|
|
|
|
func TestNewAddCommandEveryAndCronMutuallyExclusive(t *testing.T) {
|
|
cmd := newAddCommand(func() string { return "testing" })
|
|
|
|
cmd.SetArgs([]string{
|
|
"--name", "job",
|
|
"--message", "hello",
|
|
"--every", "10",
|
|
"--cron", "0 9 * * *",
|
|
})
|
|
|
|
err := cmd.Execute()
|
|
require.Error(t, err)
|
|
}
|