57 lines
1.5 KiB
Go
57 lines
1.5 KiB
Go
|
|
package state
|
||
|
|
|
||
|
|
import (
|
||
|
|
"fmt"
|
||
|
|
"strings"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
// ParseIntentOutput parses `hecate intent` CLI output from local/remote commands.
|
||
|
|
func ParseIntentOutput(raw string) (Intent, error) {
|
||
|
|
for _, line := range strings.Split(raw, "\n") {
|
||
|
|
line = strings.TrimSpace(line)
|
||
|
|
if line == "" {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
idx := strings.Index(line, "intent=")
|
||
|
|
if idx < 0 {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
payload := strings.TrimSpace(line[idx:])
|
||
|
|
fields := strings.Fields(payload)
|
||
|
|
if len(fields) == 0 || !strings.HasPrefix(fields[0], "intent=") {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
stateValue := strings.TrimSpace(strings.TrimPrefix(fields[0], "intent="))
|
||
|
|
if stateValue == "" || stateValue == "none" {
|
||
|
|
return Intent{}, nil
|
||
|
|
}
|
||
|
|
in := Intent{State: stateValue}
|
||
|
|
if strings.Contains(payload, `reason="`) {
|
||
|
|
parts := strings.SplitN(payload, `reason="`, 2)
|
||
|
|
if len(parts) == 2 {
|
||
|
|
if end := strings.Index(parts[1], `"`); end >= 0 {
|
||
|
|
in.Reason = parts[1][:end]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
for _, field := range fields[1:] {
|
||
|
|
if strings.HasPrefix(field, "source=") {
|
||
|
|
in.Source = strings.TrimSpace(strings.TrimPrefix(field, "source="))
|
||
|
|
}
|
||
|
|
if strings.HasPrefix(field, "updated_at=") {
|
||
|
|
ts := strings.TrimSpace(strings.TrimPrefix(field, "updated_at="))
|
||
|
|
if ts != "" {
|
||
|
|
parsed, err := time.Parse(time.RFC3339, ts)
|
||
|
|
if err != nil {
|
||
|
|
return Intent{}, fmt.Errorf("parse updated_at %q: %w", ts, err)
|
||
|
|
}
|
||
|
|
in.UpdatedAt = parsed
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return in, nil
|
||
|
|
}
|
||
|
|
return Intent{}, fmt.Errorf("intent output missing intent= token")
|
||
|
|
}
|