package main import ( "context" "flag" "fmt" "log" "os" "os/signal" "strings" "syscall" ) func main() { base := flag.String("url", envOr("NEURALHUNT_URL", "http://127.0.0.1:8080"), "Neural Hunt server URL") identityPath := flag.String("identity", envOr("NEURALHUNT_IDENTITY", defaultIdentityPath()), "persistent terminal identity file") taskSelector := flag.String("task", "", "initial task: number, ID prefix or display name") maxNodes := flag.Int("max-nodes", 500, "maximum target-field working set") nonInteractive := flag.Bool("non-interactive", false, "run unattended without command prompt") quiet := flag.Bool("quiet", false, "suppress connection/status chatter") beaconPath := flag.String("beacon-path", envOr("NEURALHUNT_BEACON_PATH", "auto"), "Beacon Hunt path: auto, pulse, flux or orbit") importPath := flag.String("import", "", "import browser/terminal identity JSON before login") exportPath := flag.String("export", "", "export current identity in browser-compatible encrypted format and exit") passphrase := flag.String("passphrase", os.Getenv("NEURALHUNT_IDENTITY_PASSPHRASE"), "identity import/export passphrase (prefer environment variable)") flag.Parse() if strings.TrimSpace(*importPath) != "" { id, err := readIdentityImport(*importPath, *passphrase) if err != nil { log.Fatal("identity import: ", err) } if err := saveIdentity(*identityPath, id); err != nil { log.Fatal("save imported identity: ", err) } fmt.Println("Identity importiert nach", *identityPath) } id, key, created, err := loadOrCreateIdentity(*identityPath) if err != nil { log.Fatal(err) } if *exportPath != "" { if err := exportBrowserIdentity(*exportPath, *passphrase, id); err != nil { log.Fatal("identity export: ", err) } fmt.Println("Browser-kompatibler verschlüsselter Export:", *exportPath) return } ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) defer stop() api := newAPI(*base, id, key) if err := api.login(ctx); err != nil { log.Fatal(err) } if err := api.registerHostedWorker(ctx); err != nil { log.Fatal(err) } go api.hostedWorkerLeaseLoop(ctx, stop) if created { fmt.Println("Neue Terminal-Identität erzeugt:", *identityPath) } fmt.Println("NEURAL HUNT SHELL") fmt.Println("Client-ID :", api.clientID()) fmt.Println("Identity-Datei:", *identityPath) fmt.Println("Server :", strings.TrimRight(*base, "/")) fmt.Println("Backup : identity export (verschlüsselt, im Browser importierbar)") fmt.Println("Hinweis : Dieselbe Identity darf nicht gleichzeitig im Browser verbunden sein.") a := newApp(ctx, api, *identityPath, *passphrase, *maxNodes, *quiet, *nonInteractive) a.beaconPathMode = strings.ToLower(strings.TrimSpace(*beaconPath)) initial, err := selectInitialTask(ctx, a, *taskSelector, !*nonInteractive) if err != nil { log.Fatal(err) } if err := a.startTask(ctx, initial); err != nil { log.Fatal(err) } go a.watcher(ctx) if *nonInteractive { <-ctx.Done() a.stopSession() return } if err := a.commandLoop(ctx, os.Stdin); err != nil && ctx.Err() == nil { log.Println(err) } a.stopSession() } func envOr(name, fallback string) string { if v := strings.TrimSpace(os.Getenv(name)); v != "" { return v } return fallback }