mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-05-07 08:57:12 +00:00
137 lines
4.2 KiB
Go
137 lines
4.2 KiB
Go
package memory
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/unifiedresources"
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/utils"
|
|
)
|
|
|
|
// ChangeTypeLabel returns the canonical human-readable label for a detected
|
|
// memory change type.
|
|
func ChangeTypeLabel(changeType ChangeType) string {
|
|
switch changeType {
|
|
case ChangeCreated:
|
|
return "Created"
|
|
case ChangeDeleted:
|
|
return "Deleted"
|
|
case ChangeConfig:
|
|
return "Config update"
|
|
case ChangeStatus:
|
|
return "Status change"
|
|
case ChangeMigrated:
|
|
return "Migration"
|
|
case ChangeRestarted:
|
|
return "Restart"
|
|
case ChangeBackedUp:
|
|
return "Backup"
|
|
default:
|
|
raw := strings.TrimSpace(strings.ReplaceAll(string(changeType), "_", " "))
|
|
if raw == "" {
|
|
return "Change"
|
|
}
|
|
return strings.ToUpper(raw[:1]) + raw[1:]
|
|
}
|
|
}
|
|
|
|
// FormatRecentChangesContext returns the canonical markdown section for recent
|
|
// memory changes used in AI prompts and summaries.
|
|
func FormatRecentChangesContext(changes []Change, includeResourcePrefix bool, headingLevel string) string {
|
|
if len(changes) == 0 {
|
|
return ""
|
|
}
|
|
|
|
headingLevel = strings.TrimSpace(headingLevel)
|
|
if headingLevel == "" {
|
|
headingLevel = "##"
|
|
}
|
|
|
|
heading := fmt.Sprintf("\n%s Recent Changes", headingLevel)
|
|
if includeResourcePrefix {
|
|
heading = fmt.Sprintf("\n%s Recent Changes Across Infrastructure", headingLevel)
|
|
}
|
|
|
|
lines := []string{heading, "What changed recently:"}
|
|
for _, change := range changes {
|
|
entry := fmt.Sprintf("**%s** %s", ChangeTypeLabel(change.ChangeType), change.Description)
|
|
if includeResourcePrefix {
|
|
scope := strings.TrimSpace(change.ResourceID)
|
|
if scope == "" {
|
|
scope = strings.TrimSpace(change.ResourceName)
|
|
}
|
|
if scope == "" {
|
|
scope = "resource"
|
|
}
|
|
if resourceType := strings.TrimSpace(change.ResourceType); resourceType != "" && !strings.Contains(scope, resourceType) {
|
|
scope = fmt.Sprintf("%s (%s)", scope, resourceType)
|
|
}
|
|
entry = fmt.Sprintf("%s: %s", scope, entry)
|
|
}
|
|
ago := time.Since(change.DetectedAt).Truncate(time.Minute)
|
|
lines = append(lines, fmt.Sprintf("- %s (%s)", entry, utils.FormatDurationAgo(ago)))
|
|
}
|
|
return strings.Join(lines, "\n")
|
|
}
|
|
|
|
// ChangeFromUnifiedResourceChange converts a canonical unified-resource change
|
|
// into the patrol-local memory representation.
|
|
func ChangeFromUnifiedResourceChange(change unifiedresources.ResourceChange) Change {
|
|
detectedAt := change.ObservedAt
|
|
if detectedAt.IsZero() && change.OccurredAt != nil {
|
|
detectedAt = *change.OccurredAt
|
|
}
|
|
if detectedAt.IsZero() {
|
|
detectedAt = time.Now()
|
|
}
|
|
|
|
return Change{
|
|
ID: strings.TrimSpace(change.ID),
|
|
ResourceID: strings.TrimSpace(change.ResourceID),
|
|
ResourceName: strings.TrimSpace(change.ResourceID),
|
|
ChangeType: ChangeType(unifiedresources.ChangeKindLabel(change.Kind)),
|
|
DetectedAt: detectedAt,
|
|
Description: unifiedresources.FormatResourceChangeSummary(change),
|
|
}
|
|
}
|
|
|
|
// ResourceChangeFromMemoryChange converts a patrol-local memory change back
|
|
// into the canonical unified-resource change shape.
|
|
func ResourceChangeFromMemoryChange(change Change) unifiedresources.ResourceChange {
|
|
var related []string
|
|
if resourceName := strings.TrimSpace(change.ResourceName); resourceName != "" {
|
|
related = []string{resourceName}
|
|
}
|
|
|
|
return unifiedresources.ResourceChange{
|
|
ID: strings.TrimSpace(change.ID),
|
|
ObservedAt: change.DetectedAt,
|
|
ResourceID: strings.TrimSpace(change.ResourceID),
|
|
Kind: memoryChangeTypeToUnifiedChangeKind(change.ChangeType),
|
|
SourceType: unifiedresources.SourceHeuristic,
|
|
Confidence: unifiedresources.ConfidenceMedium,
|
|
RelatedResources: related,
|
|
Reason: change.Description,
|
|
Metadata: map[string]any{
|
|
"memoryChangeType": string(change.ChangeType),
|
|
},
|
|
}
|
|
}
|
|
|
|
func memoryChangeTypeToUnifiedChangeKind(changeType ChangeType) unifiedresources.ChangeKind {
|
|
switch changeType {
|
|
case ChangeCreated, ChangeDeleted, ChangeStatus:
|
|
return unifiedresources.ChangeStateTransition
|
|
case ChangeConfig:
|
|
return unifiedresources.ChangeConfigUpdate
|
|
case ChangeMigrated:
|
|
return unifiedresources.ChangeRelationship
|
|
case ChangeRestarted:
|
|
return unifiedresources.ChangeRestart
|
|
case ChangeBackedUp:
|
|
return unifiedresources.ChangeConfigUpdate
|
|
default:
|
|
return unifiedresources.ChangeAnomaly
|
|
}
|
|
}
|