agent/pkg/agentic/commands_platform.go
Virgil 4e82ec8da6 feat(agentic): add auth IP restrictions
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-02 08:18:43 +00:00

639 lines
28 KiB
Go

// SPDX-License-Identifier: EUPL-1.2
package agentic
import (
core "dappco.re/go/core"
)
func (s *PrepSubsystem) registerPlatformCommands() {
c := s.Core()
c.Command("sync/push", core.Command{Description: "Push completed dispatch state to the platform API", Action: s.cmdSyncPush})
c.Command("agentic:sync/push", core.Command{Description: "Push completed dispatch state to the platform API", Action: s.cmdSyncPush})
c.Command("sync/pull", core.Command{Description: "Pull shared fleet context from the platform API", Action: s.cmdSyncPull})
c.Command("agentic:sync/pull", core.Command{Description: "Pull shared fleet context from the platform API", Action: s.cmdSyncPull})
c.Command("sync/status", core.Command{Description: "Show platform sync status for the current or named agent", Action: s.cmdSyncStatus})
c.Command("agentic:sync/status", core.Command{Description: "Show platform sync status for the current or named agent", Action: s.cmdSyncStatus})
c.Command("auth/provision", core.Command{Description: "Provision a platform API key for an authenticated agent user", Action: s.cmdAuthProvision})
c.Command("agentic:auth/provision", core.Command{Description: "Provision a platform API key for an authenticated agent user", Action: s.cmdAuthProvision})
c.Command("auth/revoke", core.Command{Description: "Revoke a platform API key", Action: s.cmdAuthRevoke})
c.Command("agentic:auth/revoke", core.Command{Description: "Revoke a platform API key", Action: s.cmdAuthRevoke})
c.Command("message/send", core.Command{Description: "Send a direct message to another agent", Action: s.cmdMessageSend})
c.Command("messages/send", core.Command{Description: "Send a direct message to another agent", Action: s.cmdMessageSend})
c.Command("agentic:message/send", core.Command{Description: "Send a direct message to another agent", Action: s.cmdMessageSend})
c.Command("agentic:messages/send", core.Command{Description: "Send a direct message to another agent", Action: s.cmdMessageSend})
c.Command("message/inbox", core.Command{Description: "List direct messages for an agent", Action: s.cmdMessageInbox})
c.Command("messages/inbox", core.Command{Description: "List direct messages for an agent", Action: s.cmdMessageInbox})
c.Command("agentic:message/inbox", core.Command{Description: "List direct messages for an agent", Action: s.cmdMessageInbox})
c.Command("agentic:messages/inbox", core.Command{Description: "List direct messages for an agent", Action: s.cmdMessageInbox})
c.Command("message/conversation", core.Command{Description: "List a direct conversation between two agents", Action: s.cmdMessageConversation})
c.Command("messages/conversation", core.Command{Description: "List a direct conversation between two agents", Action: s.cmdMessageConversation})
c.Command("agentic:message/conversation", core.Command{Description: "List a direct conversation between two agents", Action: s.cmdMessageConversation})
c.Command("agentic:messages/conversation", core.Command{Description: "List a direct conversation between two agents", Action: s.cmdMessageConversation})
c.Command("fleet/register", core.Command{Description: "Register a fleet node with the platform API", Action: s.cmdFleetRegister})
c.Command("agentic:fleet/register", core.Command{Description: "Register a fleet node with the platform API", Action: s.cmdFleetRegister})
c.Command("fleet/heartbeat", core.Command{Description: "Send a heartbeat for a registered fleet node", Action: s.cmdFleetHeartbeat})
c.Command("agentic:fleet/heartbeat", core.Command{Description: "Send a heartbeat for a registered fleet node", Action: s.cmdFleetHeartbeat})
c.Command("fleet/deregister", core.Command{Description: "Deregister a fleet node from the platform API", Action: s.cmdFleetDeregister})
c.Command("agentic:fleet/deregister", core.Command{Description: "Deregister a fleet node from the platform API", Action: s.cmdFleetDeregister})
c.Command("fleet/nodes", core.Command{Description: "List registered fleet nodes", Action: s.cmdFleetNodes})
c.Command("agentic:fleet/nodes", core.Command{Description: "List registered fleet nodes", Action: s.cmdFleetNodes})
c.Command("fleet/task/assign", core.Command{Description: "Assign a task to a fleet node", Action: s.cmdFleetTaskAssign})
c.Command("agentic:fleet/task/assign", core.Command{Description: "Assign a task to a fleet node", Action: s.cmdFleetTaskAssign})
c.Command("fleet/task/complete", core.Command{Description: "Complete a fleet task and report findings", Action: s.cmdFleetTaskComplete})
c.Command("agentic:fleet/task/complete", core.Command{Description: "Complete a fleet task and report findings", Action: s.cmdFleetTaskComplete})
c.Command("fleet/task/next", core.Command{Description: "Ask the platform for the next fleet task", Action: s.cmdFleetTaskNext})
c.Command("agentic:fleet/task/next", core.Command{Description: "Ask the platform for the next fleet task", Action: s.cmdFleetTaskNext})
c.Command("fleet/stats", core.Command{Description: "Show fleet activity statistics", Action: s.cmdFleetStats})
c.Command("agentic:fleet/stats", core.Command{Description: "Show fleet activity statistics", Action: s.cmdFleetStats})
c.Command("fleet/events", core.Command{Description: "Read the next fleet event from the platform SSE stream, falling back to polling when needed", Action: s.cmdFleetEvents})
c.Command("agentic:fleet/events", core.Command{Description: "Read the next fleet event from the platform SSE stream, falling back to polling when needed", Action: s.cmdFleetEvents})
c.Command("credits/award", core.Command{Description: "Award credits to a fleet node", Action: s.cmdCreditsAward})
c.Command("agentic:credits/award", core.Command{Description: "Award credits to a fleet node", Action: s.cmdCreditsAward})
c.Command("credits/balance", core.Command{Description: "Show credit balance for a fleet node", Action: s.cmdCreditsBalance})
c.Command("agentic:credits/balance", core.Command{Description: "Show credit balance for a fleet node", Action: s.cmdCreditsBalance})
c.Command("credits/history", core.Command{Description: "Show credit history for a fleet node", Action: s.cmdCreditsHistory})
c.Command("agentic:credits/history", core.Command{Description: "Show credit history for a fleet node", Action: s.cmdCreditsHistory})
c.Command("subscription/detect", core.Command{Description: "Detect available provider capabilities", Action: s.cmdSubscriptionDetect})
c.Command("agentic:subscription/detect", core.Command{Description: "Detect available provider capabilities", Action: s.cmdSubscriptionDetect})
c.Command("subscription/budget", core.Command{Description: "Show compute budget for a fleet node", Action: s.cmdSubscriptionBudget})
c.Command("agentic:subscription/budget", core.Command{Description: "Show compute budget for a fleet node", Action: s.cmdSubscriptionBudget})
c.Command("subscription/budget/update", core.Command{Description: "Update compute budget for a fleet node", Action: s.cmdSubscriptionUpdateBudget})
c.Command("subscription/update-budget", core.Command{Description: "Update compute budget for a fleet node", Action: s.cmdSubscriptionUpdateBudget})
c.Command("agentic:subscription/budget/update", core.Command{Description: "Update compute budget for a fleet node", Action: s.cmdSubscriptionUpdateBudget})
c.Command("agentic:subscription/update-budget", core.Command{Description: "Update compute budget for a fleet node", Action: s.cmdSubscriptionUpdateBudget})
}
func (s *PrepSubsystem) cmdAuthProvision(options core.Options) core.Result {
if optionStringValue(options, "oauth_user_id", "oauth-user-id", "user_id", "user-id", "_arg") == "" {
core.Print(nil, "usage: core-agent auth provision <oauth-user-id> [--name=codex] [--permissions=plans:read,plans:write] [--ip-restrictions=10.0.0.0/8,192.168.0.0/16] [--rate-limit=60] [--expires-at=2026-04-01T00:00:00Z]")
return core.Result{Value: core.E("agentic.cmdAuthProvision", "oauth_user_id is required", nil), OK: false}
}
result := s.handleAuthProvision(s.commandContext(), options)
if !result.OK {
err := commandResultError("agentic.cmdAuthProvision", result)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
output, ok := result.Value.(AuthProvisionOutput)
if !ok {
err := core.E("agentic.cmdAuthProvision", "invalid auth provision output", nil)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
core.Print(nil, "key id: %d", output.Key.ID)
core.Print(nil, "name: %s", output.Key.Name)
core.Print(nil, "prefix: %s", output.Key.Prefix)
if output.Key.Key != "" {
core.Print(nil, "key: %s", output.Key.Key)
}
if len(output.Key.Permissions) > 0 {
core.Print(nil, "permissions: %s", core.Join(",", output.Key.Permissions...))
}
if len(output.Key.IPRestrictions) > 0 {
core.Print(nil, "ip restrictions: %s", core.Join(",", output.Key.IPRestrictions...))
}
if output.Key.ExpiresAt != "" {
core.Print(nil, "expires: %s", output.Key.ExpiresAt)
}
return core.Result{OK: true}
}
func (s *PrepSubsystem) cmdAuthRevoke(options core.Options) core.Result {
if optionStringValue(options, "key_id", "key-id", "_arg") == "" {
core.Print(nil, "usage: core-agent auth revoke <key-id>")
return core.Result{Value: core.E("agentic.cmdAuthRevoke", "key_id is required", nil), OK: false}
}
result := s.handleAuthRevoke(s.commandContext(), options)
if !result.OK {
err := commandResultError("agentic.cmdAuthRevoke", result)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
output, ok := result.Value.(AuthRevokeOutput)
if !ok {
err := core.E("agentic.cmdAuthRevoke", "invalid auth revoke output", nil)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
core.Print(nil, "revoked: %s", output.KeyID)
return core.Result{OK: true}
}
func (s *PrepSubsystem) cmdSyncPush(options core.Options) core.Result {
result := s.handleSyncPush(s.commandContext(), options)
if !result.OK {
err := commandResultError("agentic.cmdSyncPush", result)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
output, ok := result.Value.(SyncPushOutput)
if !ok {
err := core.E("agentic.cmdSyncPush", "invalid sync push output", nil)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
core.Print(nil, "synced: %d", output.Count)
return core.Result{OK: true}
}
func (s *PrepSubsystem) cmdSyncPull(options core.Options) core.Result {
result := s.handleSyncPull(s.commandContext(), options)
if !result.OK {
err := commandResultError("agentic.cmdSyncPull", result)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
output, ok := result.Value.(SyncPullOutput)
if !ok {
err := core.E("agentic.cmdSyncPull", "invalid sync pull output", nil)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
core.Print(nil, "context items: %d", output.Count)
return core.Result{OK: true}
}
func (s *PrepSubsystem) cmdSyncStatus(options core.Options) core.Result {
result := s.handleSyncStatus(s.commandContext(), options)
if !result.OK {
err := commandResultError("agentic.cmdSyncStatus", result)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
output, ok := result.Value.(SyncStatusOutput)
if !ok {
err := core.E("agentic.cmdSyncStatus", "invalid sync status output", nil)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
core.Print(nil, "agent: %s", output.AgentID)
core.Print(nil, "status: %s", output.Status)
core.Print(nil, "queued: %d", output.Queued)
core.Print(nil, "context items: %d", output.ContextCount)
if output.LastPushAt != "" {
core.Print(nil, "last push: %s", output.LastPushAt)
}
if output.LastPullAt != "" {
core.Print(nil, "last pull: %s", output.LastPullAt)
}
if output.RemoteError != "" {
core.Print(nil, "remote error: %s", output.RemoteError)
}
return core.Result{OK: true}
}
func (s *PrepSubsystem) cmdFleetRegister(options core.Options) core.Result {
if optionStringValue(options, "agent_id", "agent-id", "_arg") == "" {
core.Print(nil, "usage: core-agent fleet register <agent-id> --platform=linux [--models=codex,gpt-5.4] [--capabilities=go,review]")
return core.Result{Value: core.E("agentic.cmdFleetRegister", "agent_id is required", nil), OK: false}
}
result := s.handleFleetRegister(s.commandContext(), normalisePlatformCommandOptions(options))
if !result.OK {
err := commandResultError("agentic.cmdFleetRegister", result)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
node, ok := result.Value.(FleetNode)
if !ok {
err := core.E("agentic.cmdFleetRegister", "invalid fleet register output", nil)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
core.Print(nil, "registered: %s", node.AgentID)
core.Print(nil, "status: %s", node.Status)
core.Print(nil, "platform: %s", node.Platform)
return core.Result{OK: true}
}
func (s *PrepSubsystem) cmdFleetHeartbeat(options core.Options) core.Result {
if optionStringValue(options, "agent_id", "agent-id", "_arg") == "" || optionStringValue(options, "status") == "" {
core.Print(nil, "usage: core-agent fleet heartbeat <agent-id> --status=online [--compute-budget='{\"max_daily_hours\":2}']")
return core.Result{Value: core.E("agentic.cmdFleetHeartbeat", "agent_id and status are required", nil), OK: false}
}
result := s.handleFleetHeartbeat(s.commandContext(), normalisePlatformCommandOptions(options))
if !result.OK {
err := commandResultError("agentic.cmdFleetHeartbeat", result)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
node, ok := result.Value.(FleetNode)
if !ok {
err := core.E("agentic.cmdFleetHeartbeat", "invalid fleet heartbeat output", nil)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
core.Print(nil, "heartbeat: %s", node.AgentID)
core.Print(nil, "status: %s", node.Status)
return core.Result{OK: true}
}
func (s *PrepSubsystem) cmdFleetDeregister(options core.Options) core.Result {
if optionStringValue(options, "agent_id", "agent-id", "_arg") == "" {
core.Print(nil, "usage: core-agent fleet deregister <agent-id>")
return core.Result{Value: core.E("agentic.cmdFleetDeregister", "agent_id is required", nil), OK: false}
}
result := s.handleFleetDeregister(s.commandContext(), normalisePlatformCommandOptions(options))
if !result.OK {
err := commandResultError("agentic.cmdFleetDeregister", result)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
data, ok := result.Value.(map[string]any)
if !ok {
err := core.E("agentic.cmdFleetDeregister", "invalid fleet deregister output", nil)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
core.Print(nil, "deregistered: %s", stringValue(data["agent_id"]))
return core.Result{OK: true}
}
func (s *PrepSubsystem) cmdFleetNodes(options core.Options) core.Result {
result := s.handleFleetNodes(s.commandContext(), options)
if !result.OK {
err := commandResultError("agentic.cmdFleetNodes", result)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
output, ok := result.Value.(FleetNodesOutput)
if !ok {
err := core.E("agentic.cmdFleetNodes", "invalid fleet nodes output", nil)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
if len(output.Nodes) == 0 {
core.Print(nil, "no fleet nodes")
return core.Result{OK: true}
}
for _, node := range output.Nodes {
core.Print(nil, " %-10s %-8s %-10s %s", node.Status, node.Platform, node.AgentID, core.Join(",", node.Models...))
}
core.Print(nil, "")
core.Print(nil, "total: %d", output.Total)
return core.Result{OK: true}
}
func (s *PrepSubsystem) cmdFleetTaskAssign(options core.Options) core.Result {
agentID := optionStringValue(options, "agent_id", "agent-id", "_arg")
if agentID == "" || optionStringValue(options, "repo") == "" || optionStringValue(options, "task") == "" {
core.Print(nil, "usage: core-agent fleet task assign <agent-id> --repo=core/go-io --task=\"...\" [--branch=dev] [--template=coding] [--agent-model=codex:gpt-5.4]")
return core.Result{Value: core.E("agentic.cmdFleetTaskAssign", "agent_id, repo, and task are required", nil), OK: false}
}
result := s.handleFleetAssignTask(s.commandContext(), normalisePlatformCommandOptions(options))
if !result.OK {
err := commandResultError("agentic.cmdFleetTaskAssign", result)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
task, ok := result.Value.(FleetTask)
if !ok {
err := core.E("agentic.cmdFleetTaskAssign", "invalid fleet task output", nil)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
printFleetTask(task)
return core.Result{OK: true}
}
func (s *PrepSubsystem) cmdFleetTaskComplete(options core.Options) core.Result {
agentID := optionStringValue(options, "agent_id", "agent-id", "_arg")
taskID := optionIntValue(options, "task_id", "task-id")
if agentID == "" || taskID == 0 {
core.Print(nil, "usage: core-agent fleet task complete <agent-id> --task-id=N [--result='{\"status\":\"completed\"}'] [--findings='[{\"file\":\"x.go\"}]']")
return core.Result{Value: core.E("agentic.cmdFleetTaskComplete", "agent_id and task_id are required", nil), OK: false}
}
result := s.handleFleetCompleteTask(s.commandContext(), normalisePlatformCommandOptions(options))
if !result.OK {
err := commandResultError("agentic.cmdFleetTaskComplete", result)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
task, ok := result.Value.(FleetTask)
if !ok {
err := core.E("agentic.cmdFleetTaskComplete", "invalid fleet task output", nil)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
printFleetTask(task)
return core.Result{OK: true}
}
func (s *PrepSubsystem) cmdFleetTaskNext(options core.Options) core.Result {
if optionStringValue(options, "agent_id", "agent-id", "_arg") == "" {
core.Print(nil, "usage: core-agent fleet task next <agent-id> [--capabilities=go,review]")
return core.Result{Value: core.E("agentic.cmdFleetTaskNext", "agent_id is required", nil), OK: false}
}
result := s.handleFleetNextTask(s.commandContext(), normalisePlatformCommandOptions(options))
if !result.OK {
err := commandResultError("agentic.cmdFleetTaskNext", result)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
task, ok := result.Value.(*FleetTask)
if !ok {
err := core.E("agentic.cmdFleetTaskNext", "invalid fleet next-task output", nil)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
if task == nil {
core.Print(nil, "no task available")
return core.Result{OK: true}
}
printFleetTask(*task)
return core.Result{OK: true}
}
func (s *PrepSubsystem) cmdFleetStats(options core.Options) core.Result {
result := s.handleFleetStats(s.commandContext(), options)
if !result.OK {
err := commandResultError("agentic.cmdFleetStats", result)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
stats, ok := result.Value.(FleetStats)
if !ok {
err := core.E("agentic.cmdFleetStats", "invalid fleet stats output", nil)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
core.Print(nil, "nodes online: %d", stats.NodesOnline)
core.Print(nil, "tasks today: %d", stats.TasksToday)
core.Print(nil, "tasks week: %d", stats.TasksWeek)
core.Print(nil, "repos touched: %d", stats.ReposTouched)
core.Print(nil, "findings total: %d", stats.FindingsTotal)
core.Print(nil, "compute hours: %d", stats.ComputeHours)
return core.Result{OK: true}
}
func (s *PrepSubsystem) cmdFleetEvents(options core.Options) core.Result {
result := s.handleFleetEvents(s.commandContext(), normalisePlatformCommandOptions(options))
if !result.OK {
err := commandResultError("agentic.cmdFleetEvents", result)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
output, ok := result.Value.(FleetEventOutput)
if !ok {
err := core.E("agentic.cmdFleetEvents", "invalid fleet event output", nil)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
core.Print(nil, "event: %s", output.Event.Event)
if output.Event.Type != "" && output.Event.Type != output.Event.Event {
core.Print(nil, "type: %s", output.Event.Type)
}
if output.Event.AgentID != "" {
core.Print(nil, "agent: %s", output.Event.AgentID)
}
if output.Event.Repo != "" {
core.Print(nil, "repo: %s", output.Event.Repo)
}
if output.Event.Branch != "" {
core.Print(nil, "branch: %s", output.Event.Branch)
}
if output.Event.TaskID > 0 {
core.Print(nil, "task id: %d", output.Event.TaskID)
}
if output.Event.Status != "" {
core.Print(nil, "status: %s", output.Event.Status)
}
if len(output.Event.Payload) > 0 {
core.Print(nil, "payload: %s", core.JSONMarshalString(output.Event.Payload))
}
return core.Result{OK: true}
}
func (s *PrepSubsystem) cmdCreditsAward(options core.Options) core.Result {
agentID := optionStringValue(options, "agent_id", "agent-id", "_arg")
taskType := optionStringValue(options, "task_type", "task-type")
amount := optionIntValue(options, "amount")
if agentID == "" || taskType == "" || amount == 0 {
core.Print(nil, "usage: core-agent credits award <agent-id> --task-type=fleet-task --amount=2 [--description=\"...\"]")
return core.Result{Value: core.E("agentic.cmdCreditsAward", "agent_id, task_type, and amount are required", nil), OK: false}
}
result := s.handleCreditsAward(s.commandContext(), normalisePlatformCommandOptions(options))
if !result.OK {
err := commandResultError("agentic.cmdCreditsAward", result)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
entry, ok := result.Value.(CreditEntry)
if !ok {
err := core.E("agentic.cmdCreditsAward", "invalid credit award output", nil)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
core.Print(nil, "entry: %d", entry.ID)
core.Print(nil, "task type: %s", entry.TaskType)
core.Print(nil, "amount: %d", entry.Amount)
core.Print(nil, "balance after: %d", entry.BalanceAfter)
return core.Result{OK: true}
}
func (s *PrepSubsystem) cmdCreditsBalance(options core.Options) core.Result {
if optionStringValue(options, "agent_id", "agent-id", "_arg") == "" {
core.Print(nil, "usage: core-agent credits balance <agent-id>")
return core.Result{Value: core.E("agentic.cmdCreditsBalance", "agent_id is required", nil), OK: false}
}
result := s.handleCreditsBalance(s.commandContext(), normalisePlatformCommandOptions(options))
if !result.OK {
err := commandResultError("agentic.cmdCreditsBalance", result)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
balance, ok := result.Value.(CreditBalance)
if !ok {
err := core.E("agentic.cmdCreditsBalance", "invalid credit balance output", nil)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
core.Print(nil, "agent: %s", balance.AgentID)
core.Print(nil, "balance: %d", balance.Balance)
core.Print(nil, "entries: %d", balance.Entries)
return core.Result{OK: true}
}
func (s *PrepSubsystem) cmdCreditsHistory(options core.Options) core.Result {
if optionStringValue(options, "agent_id", "agent-id", "_arg") == "" {
core.Print(nil, "usage: core-agent credits history <agent-id> [--limit=50]")
return core.Result{Value: core.E("agentic.cmdCreditsHistory", "agent_id is required", nil), OK: false}
}
result := s.handleCreditsHistory(s.commandContext(), normalisePlatformCommandOptions(options))
if !result.OK {
err := commandResultError("agentic.cmdCreditsHistory", result)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
output, ok := result.Value.(CreditsHistoryOutput)
if !ok {
err := core.E("agentic.cmdCreditsHistory", "invalid credit history output", nil)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
if len(output.Entries) == 0 {
core.Print(nil, "no credit entries")
return core.Result{OK: true}
}
for _, entry := range output.Entries {
core.Print(nil, " #%-4d %-12s %+d balance=%d", entry.ID, entry.TaskType, entry.Amount, entry.BalanceAfter)
}
core.Print(nil, "")
core.Print(nil, "total: %d", output.Total)
return core.Result{OK: true}
}
func (s *PrepSubsystem) cmdSubscriptionDetect(options core.Options) core.Result {
result := s.handleSubscriptionDetect(s.commandContext(), options)
if !result.OK {
err := commandResultError("agentic.cmdSubscriptionDetect", result)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
capabilities, ok := result.Value.(SubscriptionCapabilities)
if !ok {
err := core.E("agentic.cmdSubscriptionDetect", "invalid capability output", nil)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
core.Print(nil, "available: %s", core.Join(",", capabilities.Available...))
return core.Result{OK: true}
}
func (s *PrepSubsystem) cmdSubscriptionBudget(options core.Options) core.Result {
if optionStringValue(options, "agent_id", "agent-id", "_arg") == "" {
core.Print(nil, "usage: core-agent subscription budget <agent-id>")
return core.Result{Value: core.E("agentic.cmdSubscriptionBudget", "agent_id is required", nil), OK: false}
}
result := s.handleSubscriptionBudget(s.commandContext(), normalisePlatformCommandOptions(options))
if !result.OK {
err := commandResultError("agentic.cmdSubscriptionBudget", result)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
budget, ok := result.Value.(map[string]any)
if !ok {
err := core.E("agentic.cmdSubscriptionBudget", "invalid budget output", nil)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
core.Print(nil, "%s", core.JSONMarshalString(budget))
return core.Result{OK: true}
}
func (s *PrepSubsystem) cmdSubscriptionUpdateBudget(options core.Options) core.Result {
if optionStringValue(options, "agent_id", "agent-id", "_arg") == "" || len(optionAnyMapValue(options, "limits")) == 0 {
core.Print(nil, "usage: core-agent subscription budget update <agent-id> --limits='{\"max_daily_hours\":2}'")
return core.Result{Value: core.E("agentic.cmdSubscriptionUpdateBudget", "agent_id and limits are required", nil), OK: false}
}
result := s.handleSubscriptionBudgetUpdate(s.commandContext(), normalisePlatformCommandOptions(options))
if !result.OK {
err := commandResultError("agentic.cmdSubscriptionUpdateBudget", result)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
budget, ok := result.Value.(map[string]any)
if !ok {
err := core.E("agentic.cmdSubscriptionUpdateBudget", "invalid updated budget output", nil)
core.Print(nil, "error: %v", err)
return core.Result{Value: err, OK: false}
}
core.Print(nil, "%s", core.JSONMarshalString(budget))
return core.Result{OK: true}
}
func normalisePlatformCommandOptions(options core.Options) core.Options {
normalised := core.NewOptions(options.Items()...)
if normalised.String("agent_id") == "" {
if agentID := optionStringValue(options, "_arg", "agent-id"); agentID != "" {
normalised.Set("agent_id", agentID)
}
}
return normalised
}
func commandResultError(action string, result core.Result) error {
if err, ok := result.Value.(error); ok && err != nil {
return err
}
message := stringValue(result.Value)
if message != "" {
return core.E(action, message, nil)
}
return core.E(action, "command failed", nil)
}
func printFleetTask(task FleetTask) {
core.Print(nil, "task: %d", task.ID)
core.Print(nil, "repo: %s", task.Repo)
core.Print(nil, "status: %s", task.Status)
if task.Branch != "" {
core.Print(nil, "branch: %s", task.Branch)
}
if task.AgentModel != "" {
core.Print(nil, "agent model: %s", task.AgentModel)
}
core.Print(nil, "summary: %s", task.Task)
}