mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-21 09:28:14 +00:00
- Six-phase plan complete: webui/cli/healthcheck/pluginmgr/clawhubadapter now interact with the kernel exclusively via internal/sdk interfaces; all Configure() calls and package-level global injection removed - buildSDK in internal/plugin/registry.go is the single assembly point - Add internal/sdk/events.go exporting event types/constants - Fix ProviderManager cooldown sharing: LuaAdaptedProvider.Name() now returns the source name instead of lua_<adapter>, so multiple sources sharing an adapter (single script load via shared VM AdapterCache) no longer share failure-cooldown state - Verified: build/vet/tests green, deployed to homeagent.service with full plugin capability testing via local OpenAI-compatible mock
123 lines
2.7 KiB
Go
123 lines
2.7 KiB
Go
package tracker
|
||
|
||
import (
|
||
"crypto/sha256"
|
||
"encoding/hex"
|
||
"fmt"
|
||
"os"
|
||
"path/filepath"
|
||
"time"
|
||
|
||
sdk "gitcode.com/JianFeeeee/HomeAgent/internal/sdk"
|
||
)
|
||
|
||
// DTO 已迁入内置 SDK,此处保留别名以兼容现有调用方。
|
||
type ChangeType = sdk.ChangeType
|
||
|
||
const (
|
||
ChangeFileCreated = sdk.ChangeFileCreated
|
||
ChangeFileModified = sdk.ChangeFileModified
|
||
ChangeFileDeleted = sdk.ChangeFileDeleted
|
||
)
|
||
|
||
type FileChange = sdk.FileChange
|
||
type ChangeSet = sdk.ChangeSet
|
||
|
||
func NewChangeSet(action string) *ChangeSet {
|
||
return &ChangeSet{
|
||
ID: fmt.Sprintf("cs_%d", time.Now().UnixNano()),
|
||
Action: action,
|
||
Timestamp: time.Now(),
|
||
}
|
||
}
|
||
|
||
func fileHash(path string) (string, int64, error) {
|
||
data, err := os.ReadFile(path)
|
||
if err != nil {
|
||
return "", 0, err
|
||
}
|
||
h := sha256.Sum256(data)
|
||
return hex.EncodeToString(h[:]), int64(len(data)), nil
|
||
}
|
||
|
||
func fileInfo(path string) (size int64, modTime time.Time, err error) {
|
||
info, err := os.Stat(path)
|
||
if err != nil {
|
||
return 0, time.Time{}, err
|
||
}
|
||
return info.Size(), info.ModTime(), nil
|
||
}
|
||
|
||
type FSState struct {
|
||
Files map[string]FileChange `json:"files"`
|
||
Root string `json:"root"`
|
||
}
|
||
|
||
func captureFSState(root string) (*FSState, error) {
|
||
state := &FSState{
|
||
Files: make(map[string]FileChange),
|
||
Root: root,
|
||
}
|
||
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
|
||
if err != nil || info.IsDir() {
|
||
return err
|
||
}
|
||
rel, _ := filepath.Rel(root, path)
|
||
hash, size, err := fileHash(path)
|
||
if err != nil {
|
||
return nil
|
||
}
|
||
state.Files[rel] = FileChange{
|
||
Path: rel,
|
||
HashAfter: hash,
|
||
SizeAfter: size,
|
||
}
|
||
return nil
|
||
})
|
||
return state, err
|
||
}
|
||
|
||
func diffStates(before, after *FSState) []FileChange {
|
||
var changes []FileChange
|
||
if before == nil || after == nil {
|
||
return changes
|
||
}
|
||
seen := make(map[string]bool)
|
||
|
||
for path, afterFile := range after.Files {
|
||
seen[path] = true
|
||
if beforeFile, ok := before.Files[path]; ok {
|
||
if beforeFile.HashAfter != afterFile.HashAfter {
|
||
changes = append(changes, FileChange{
|
||
Path: path,
|
||
Type: ChangeFileModified,
|
||
HashBefore: beforeFile.HashAfter,
|
||
HashAfter: afterFile.HashAfter,
|
||
SizeBefore: beforeFile.SizeAfter,
|
||
SizeAfter: afterFile.SizeAfter,
|
||
})
|
||
}
|
||
} else {
|
||
changes = append(changes, FileChange{
|
||
Path: path,
|
||
Type: ChangeFileCreated,
|
||
HashAfter: afterFile.HashAfter,
|
||
SizeAfter: afterFile.SizeAfter,
|
||
})
|
||
}
|
||
}
|
||
|
||
for path := range before.Files {
|
||
if !seen[path] {
|
||
changes = append(changes, FileChange{
|
||
Path: path,
|
||
Type: ChangeFileDeleted,
|
||
HashBefore: before.Files[path].HashAfter,
|
||
SizeBefore: before.Files[path].SizeAfter,
|
||
})
|
||
}
|
||
}
|
||
|
||
return changes
|
||
}
|