返回 DeepSeek-Reasonix
main.go
根目录 / desktop / main.go
1 // Command reasonix-desktop is the Reasonix desktop service: the Go-side
2 // control.Controller and platform integrations, driven by the Electron shell
3 // over the desktop host protocol (--host-rpc on stdin/stdout). A plain launch
4 // bootstraps the Electron shell installed beside this binary (app/) and exits;
5 // the shell then restarts this binary as its --host-rpc service. It lives in a
6 // nested module (reasonix/desktop) so the desktop build never touches the
7 // CLI's CGO_ENABLED=0 single-static-binary guarantee, while still importing
8 // the same internal/* kernel.
9 package main
10
11 import (
12 "fmt"
13 "os"
14 "strings"
15
16 "reasonix/internal/skill/skillwatch"
17 "reasonix/internal/winaclresidue"
18
19 // Blank imports wire compile-time built-ins into their registries, exactly as
20 // cmd/reasonix does — boot.Build resolves providers/tools from these registries.
21 _ "reasonix/internal/provider/anthropic"
22 _ "reasonix/internal/provider/openai"
23 _ "reasonix/internal/provider/responses"
24 _ "reasonix/internal/tool/builtin"
25 )
26
27 // version is injected at build time via `-ldflags "-X main.version=..."`,
28 // mirroring cmd/reasonix/main.go. The auto-updater reads it (App.Version) to compare
29 // against the published manifest; an un-injected dev build stays "dev" and never
30 // prompts to update.
31 var version = "dev"
32
33 // channel records the build's release line, injected via
34 // `-X main.channel=preview`. Default "stable" tracks the public release;
35 // "preview" tracks the opt-in test line. Legacy "canary" builds are treated as
36 // preview for compatibility.
37 var channel = "stable"
38
39 // macSelfUpdate is injected as "true" only for Developer ID signed + notarized
40 // macOS release builds. Local/ad-hoc macOS builds keep the manual download path.
41 var macSelfUpdate = "false"
42
43 func macSelfUpdateAllowed() bool {
44 switch strings.ToLower(strings.TrimSpace(macSelfUpdate)) {
45 case "1", "true", "yes", "on":
46 return true
47 default:
48 return false
49 }
50 }
51
52 func main() {
53 // Contract generation is a build-time operation. Dispatch it before crash
54 // capture so packaging cannot create files in the operator's Reasonix home.
55 if dir, ok := emitContractDir(os.Args[1:]); ok {
56 os.Exit(runEmitContract(dir))
57 }
58 // The shell asks for this before Chromium starts a child; it touches no
59 // Reasonix state, so it runs ahead of crash capture and every other mode.
60 if app, ok := stripPackageGrantsRequest(os.Args[1:]); ok {
61 os.Exit(stripPackageGrants(os.Stdout, os.Stderr, app))
62 }
63 // Internal watcher-helper entry: the host-shared skill watch service
64 // re-enters this executable so Windows directory watching never runs
65 // in-process. Dispatch before any application initialization.
66 if skillwatch.MaybeRunHelper() {
67 return
68 }
69 // Older Windows builds could leave sandbox ACL residue behind after a
70 // crash; sweep it in the background so startup never waits on icacls.
71 go winaclresidue.SweepStaleMarkers()
72 // The detached macOS self-update child must run before any shell starts.
73 if handled, exitCode := maybeRunMacUpdateHandoff(os.Args[1:]); handled {
74 os.Exit(exitCode)
75 }
76 capturePreviousFatalCrash()
77 installFatalCrashOutput()
78 exitIfHostLaunchMode(os.Args[1:])
79 if maybeRelaunchIfSuperseded() {
80 return
81 }
82 exitIfShellBootstrapped(os.Args[1:])
83
84 fmt.Fprintln(os.Stderr, "reasonix-desktop: no Electron desktop shell (app/) is installed beside this binary; reinstall Reasonix or run the packaged desktop app")
85 os.Exit(1)
86 }
87
87 lines GO