@@ -18,19 +18,82 @@ const BACKEND_HEALTH_URL = `http://${BACKEND_HOST}:${BACKEND_PORT}/api/health`;
1818
1919let backendProc = null ;
2020let backendStdioStream = null ;
21+ let resolvedDataDir = null ;
2122
2223function nowIso ( ) {
2324 return new Date ( ) . toISOString ( ) ;
2425}
2526
27+ function resolveDataDir ( ) {
28+ if ( resolvedDataDir ) return resolvedDataDir ;
29+
30+ const fromEnv = String ( process . env . WECHAT_TOOL_DATA_DIR || "" ) . trim ( ) ;
31+ const fallback = ( ( ) => {
32+ try {
33+ return app . getPath ( "userData" ) ;
34+ } catch {
35+ return null ;
36+ }
37+ } ) ( ) ;
38+
39+ const chosen = fromEnv || fallback ;
40+ if ( ! chosen ) return null ;
41+
42+ try {
43+ fs . mkdirSync ( chosen , { recursive : true } ) ;
44+ } catch { }
45+
46+ resolvedDataDir = chosen ;
47+ process . env . WECHAT_TOOL_DATA_DIR = chosen ;
48+ return chosen ;
49+ }
50+
2651function getUserDataDir ( ) {
52+ // Backwards-compat: we historically used Electron's userData directory for runtime storage.
53+ // Keep this name but resolve to the effective data dir (can be overridden via env).
54+ return resolveDataDir ( ) ;
55+ }
56+
57+ function getExeDir ( ) {
2758 try {
28- return app . getPath ( "userData" ) ;
59+ return path . dirname ( process . execPath ) ;
2960 } catch {
3061 return null ;
3162 }
3263}
3364
65+ function ensureOutputLink ( ) {
66+ // Users often expect an `output/` folder near the installed exe. We keep the real data
67+ // in the per-user data dir, and (when possible) create a Windows junction next to the exe.
68+ if ( ! app . isPackaged ) return ;
69+
70+ const exeDir = getExeDir ( ) ;
71+ const dataDir = resolveDataDir ( ) ;
72+ if ( ! exeDir || ! dataDir ) return ;
73+
74+ const target = path . join ( dataDir , "output" ) ;
75+ const linkPath = path . join ( exeDir , "output" ) ;
76+
77+ // If the target doesn't exist yet, create it so the link points somewhere real.
78+ try {
79+ fs . mkdirSync ( target , { recursive : true } ) ;
80+ } catch { }
81+
82+ // If something already exists at linkPath, do not overwrite it.
83+ try {
84+ if ( fs . existsSync ( linkPath ) ) return ;
85+ } catch {
86+ return ;
87+ }
88+
89+ try {
90+ fs . symlinkSync ( target , linkPath , "junction" ) ;
91+ logMain ( `[main] created output link: ${ linkPath } -> ${ target } ` ) ;
92+ } catch ( err ) {
93+ logMain ( `[main] failed to create output link: ${ err ?. message || err } ` ) ;
94+ }
95+ }
96+
3497function getMainLogPath ( ) {
3598 const dir = getUserDataDir ( ) ;
3699 if ( ! dir ) return null ;
@@ -327,6 +390,11 @@ async function main() {
327390 registerWindowIpc ( ) ;
328391 registerDebugShortcuts ( ) ;
329392
393+ // Resolve/create the data dir early so we can log reliably and (optionally) place a link
394+ // next to the installed exe for easier access.
395+ resolveDataDir ( ) ;
396+ ensureOutputLink ( ) ;
397+
330398 logMain ( `[main] app.isPackaged=${ app . isPackaged } argv=${ JSON . stringify ( process . argv ) } ` ) ;
331399
332400 startBackend ( ) ;
0 commit comments