@markus-global/cli 0.7.3-rc.0 → 0.7.3-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/markus.mjs +35 -146
- package/dist/tray.d.ts +1 -3
- package/dist/tray.d.ts.map +1 -1
- package/dist/tray.js +166 -144
- package/dist/tray.js.map +1 -1
- package/dist/tray.mjs +155 -120
- package/dist/web-ui/assets/{browser-hW8kkJnA.js → browser-CIXBeJ4H.js} +1 -1
- package/dist/web-ui/assets/{index-BgSvPmbf.js → index-BUO-8jKv.js} +2 -2
- package/dist/web-ui/index.html +1 -1
- package/package.json +1 -1
package/dist/tray.js
CHANGED
|
@@ -1,42 +1,70 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Cross-platform system tray controller for Markus.
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* Launched by the desktop shortcut / .app instead of `markus start` directly.
|
|
3
|
+
* Launches the server on start, provides "Open Console" and "Quit" controls.
|
|
6
4
|
*/
|
|
7
5
|
import { spawn, exec, execSync } from 'node:child_process';
|
|
8
|
-
import { readFileSync, existsSync, mkdirSync } from 'node:fs';
|
|
6
|
+
import { readFileSync, existsSync, mkdirSync, appendFileSync, openSync } from 'node:fs';
|
|
9
7
|
import { get as httpGet } from 'node:http';
|
|
10
8
|
import { createConnection } from 'node:net';
|
|
11
|
-
import { resolve, dirname } from 'node:path';
|
|
9
|
+
import { resolve, dirname, join } from 'node:path';
|
|
12
10
|
import { fileURLToPath } from 'node:url';
|
|
13
11
|
import { platform, homedir } from 'node:os';
|
|
14
12
|
import SysTrayModule from 'systray2';
|
|
15
|
-
// systray2 is CJS; default export is the class
|
|
16
13
|
const SysTray = SysTrayModule.default || SysTrayModule;
|
|
17
14
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
18
15
|
const WEB_UI_PORT = 8056;
|
|
19
16
|
const WEB_UI_URL = `http://localhost:${WEB_UI_PORT}`;
|
|
20
|
-
// Resolve paths relative to the binary distribution layout:
|
|
21
|
-
// bin/tray.mjs (this file)
|
|
22
|
-
// bin/node (bundled node)
|
|
23
|
-
// bin/markus.mjs
|
|
24
17
|
const BIN_DIR = __dirname;
|
|
25
18
|
const APP_DIR = resolve(BIN_DIR, '..');
|
|
26
|
-
const NODE_BIN = resolve(BIN_DIR, platform() === 'win32' ? 'node.exe' : 'node');
|
|
27
|
-
const MARKUS_MJS = resolve(BIN_DIR, 'markus.mjs');
|
|
28
19
|
const LOG_DIR = resolve(homedir(), '.markus', 'logs');
|
|
20
|
+
const LOG_FILE = join(LOG_DIR, 'tray-stderr.log');
|
|
21
|
+
const STRINGS = {
|
|
22
|
+
en: {
|
|
23
|
+
openUI: 'Open Console',
|
|
24
|
+
quit: 'Quit Markus',
|
|
25
|
+
tooltip: 'Markus',
|
|
26
|
+
portConflictTitle: 'Markus',
|
|
27
|
+
portConflictMsg: (port, occupant) => `Port ${port} is already in use by "${occupant}".\\nMarkus cannot start.\\n\\nFree the port or change it in ~/.markus/markus.json`,
|
|
28
|
+
},
|
|
29
|
+
zh: {
|
|
30
|
+
openUI: '打开控制台',
|
|
31
|
+
quit: '退出 Markus',
|
|
32
|
+
tooltip: 'Markus',
|
|
33
|
+
portConflictTitle: 'Markus',
|
|
34
|
+
portConflictMsg: (port, occupant) => `端口 ${port} 已被 "${occupant}" 占用。\\nMarkus 无法启动。\\n\\n请释放端口或在 ~/.markus/markus.json 中修改端口`,
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
function detectLocale() {
|
|
38
|
+
const lang = (process.env['LANG'] ?? process.env['LC_ALL'] ?? process.env['LANGUAGE'] ?? '').toLowerCase();
|
|
39
|
+
if (lang.startsWith('zh'))
|
|
40
|
+
return 'zh';
|
|
41
|
+
if (platform() === 'darwin') {
|
|
42
|
+
try {
|
|
43
|
+
const appleLang = execSync('defaults read -g AppleLanguages 2>/dev/null', { encoding: 'utf-8' });
|
|
44
|
+
if (/zh/.test(appleLang))
|
|
45
|
+
return 'zh';
|
|
46
|
+
}
|
|
47
|
+
catch { /* ignore */ }
|
|
48
|
+
}
|
|
49
|
+
return 'en';
|
|
50
|
+
}
|
|
51
|
+
const t = STRINGS[detectLocale()];
|
|
52
|
+
// ── Logging ───────────────────────────────────────────────────────────────────
|
|
53
|
+
function trayLog(msg) {
|
|
54
|
+
const ts = new Date().toISOString();
|
|
55
|
+
const line = `${ts} ${msg}\n`;
|
|
56
|
+
try {
|
|
57
|
+
mkdirSync(LOG_DIR, { recursive: true });
|
|
58
|
+
appendFileSync(LOG_FILE, line);
|
|
59
|
+
}
|
|
60
|
+
catch { /* ignore */ }
|
|
61
|
+
}
|
|
62
|
+
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
29
63
|
function loadIconBase64() {
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
resolve(APP_DIR, 'markus.ico'),
|
|
33
|
-
];
|
|
34
|
-
for (const p of candidates) {
|
|
35
|
-
if (existsSync(p)) {
|
|
64
|
+
for (const p of [resolve(APP_DIR, 'logo.png'), resolve(APP_DIR, 'markus.ico')]) {
|
|
65
|
+
if (existsSync(p))
|
|
36
66
|
return readFileSync(p).toString('base64');
|
|
37
|
-
}
|
|
38
67
|
}
|
|
39
|
-
// Fallback: empty icon (systray2 will show a default)
|
|
40
68
|
return '';
|
|
41
69
|
}
|
|
42
70
|
function openBrowser(url) {
|
|
@@ -46,23 +74,18 @@ function openBrowser(url) {
|
|
|
46
74
|
: `xdg-open "${url}"`;
|
|
47
75
|
exec(cmd, () => { });
|
|
48
76
|
}
|
|
49
|
-
// ── Server process management ────────────────────────────────────────────────
|
|
50
|
-
let serverProcess = null;
|
|
51
|
-
let serverRunning = false;
|
|
52
77
|
function isPortListening(port) {
|
|
53
|
-
return new Promise((
|
|
54
|
-
const socket = createConnection({ port, host: '127.0.0.1' }, () => {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
resolve(false);
|
|
65
|
-
});
|
|
78
|
+
return new Promise((res) => {
|
|
79
|
+
const socket = createConnection({ port, host: '127.0.0.1' }, () => { socket.destroy(); res(true); });
|
|
80
|
+
socket.on('error', () => { socket.destroy(); res(false); });
|
|
81
|
+
socket.setTimeout(2000, () => { socket.destroy(); res(false); });
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
function checkHealthOnce(url) {
|
|
85
|
+
return new Promise((res) => {
|
|
86
|
+
const req = httpGet(url, (r) => { r.resume(); res(r.statusCode !== undefined && r.statusCode >= 200 && r.statusCode < 400); });
|
|
87
|
+
req.on('error', () => res(false));
|
|
88
|
+
req.setTimeout(2000, () => { req.destroy(); res(false); });
|
|
66
89
|
});
|
|
67
90
|
}
|
|
68
91
|
function waitForHealth(url, intervalMs = 500, maxMs = 30000) {
|
|
@@ -73,164 +96,163 @@ function waitForHealth(url, intervalMs = 500, maxMs = 30000) {
|
|
|
73
96
|
res.resume();
|
|
74
97
|
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 400) {
|
|
75
98
|
ok(true);
|
|
99
|
+
return;
|
|
76
100
|
}
|
|
77
|
-
else if (Date.now() >= deadline) {
|
|
78
|
-
ok(false);
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
setTimeout(check, intervalMs);
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
req.on('error', () => {
|
|
85
101
|
if (Date.now() >= deadline) {
|
|
86
102
|
ok(false);
|
|
103
|
+
return;
|
|
87
104
|
}
|
|
88
|
-
|
|
89
|
-
setTimeout(check, intervalMs);
|
|
90
|
-
}
|
|
105
|
+
setTimeout(check, intervalMs);
|
|
91
106
|
});
|
|
92
|
-
req.
|
|
107
|
+
req.on('error', () => { if (Date.now() >= deadline)
|
|
108
|
+
ok(false);
|
|
109
|
+
else
|
|
110
|
+
setTimeout(check, intervalMs); });
|
|
111
|
+
req.setTimeout(2000, () => req.destroy());
|
|
93
112
|
};
|
|
94
113
|
check();
|
|
95
114
|
});
|
|
96
115
|
}
|
|
97
|
-
function
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
116
|
+
function resolveMarkusCommand() {
|
|
117
|
+
const symlink = '/usr/local/bin/markus';
|
|
118
|
+
if (existsSync(symlink))
|
|
119
|
+
return { cmd: symlink, args: ['start'] };
|
|
120
|
+
const wrapper = resolve(APP_DIR, 'markus');
|
|
121
|
+
if (existsSync(wrapper))
|
|
122
|
+
return { cmd: wrapper, args: ['start'] };
|
|
123
|
+
const nodeBin = resolve(BIN_DIR, platform() === 'win32' ? 'node.exe' : 'node');
|
|
124
|
+
const markusMjs = resolve(BIN_DIR, 'markus.mjs');
|
|
125
|
+
return { cmd: nodeBin, args: [markusMjs, 'start'] };
|
|
106
126
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
try {
|
|
111
|
-
occupant = execSync(`lsof -i :${port} -sTCP:LISTEN -t 2>/dev/null | head -1 | xargs ps -p -o comm= 2>/dev/null`, { encoding: 'utf-8' }).trim() || 'unknown';
|
|
112
|
-
}
|
|
113
|
-
catch { /* ignore */ }
|
|
114
|
-
exec(`osascript -e 'display dialog "Port ${port} is already in use by \\"${occupant}\\".\nMarkus cannot start.\n\nFree the port or change it in ~/.markus/markus.json" with title "Markus" buttons {"OK"} default button "OK" with icon stop'`, () => { });
|
|
115
|
-
}
|
|
116
|
-
else {
|
|
117
|
-
console.error(`Port ${port} is already in use by another process. Markus cannot start.`);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
async function startServer() {
|
|
121
|
-
if (serverRunning)
|
|
122
|
-
return;
|
|
127
|
+
// ── Server process management ────────────────────────────────────────────────
|
|
128
|
+
let serverProcess = null;
|
|
129
|
+
async function ensureServerRunning() {
|
|
123
130
|
if (await isPortListening(WEB_UI_PORT)) {
|
|
124
|
-
// Port is occupied — verify it's actually Markus via health endpoint
|
|
125
131
|
const isMarkus = await checkHealthOnce(`${WEB_UI_URL}/api/health`);
|
|
126
132
|
if (isMarkus) {
|
|
127
|
-
|
|
128
|
-
updateTrayMenu();
|
|
133
|
+
trayLog(`Server already running on port ${WEB_UI_PORT}`);
|
|
129
134
|
openBrowser(WEB_UI_URL);
|
|
130
135
|
return;
|
|
131
136
|
}
|
|
132
137
|
// Port occupied by a non-Markus process
|
|
133
|
-
|
|
138
|
+
let occupant = 'unknown';
|
|
139
|
+
try {
|
|
140
|
+
occupant = execSync(`lsof -i :${WEB_UI_PORT} -sTCP:LISTEN -t 2>/dev/null | head -1 | xargs ps -p -o comm= 2>/dev/null`, { encoding: 'utf-8' }).trim() || 'unknown';
|
|
141
|
+
}
|
|
142
|
+
catch { /* ignore */ }
|
|
143
|
+
trayLog(`Port ${WEB_UI_PORT} occupied by "${occupant}"`);
|
|
144
|
+
if (platform() === 'darwin') {
|
|
145
|
+
exec(`osascript -e 'display dialog "${t.portConflictMsg(WEB_UI_PORT, occupant)}" with title "${t.portConflictTitle}" buttons {"OK"} default button "OK" with icon stop'`, () => { });
|
|
146
|
+
}
|
|
134
147
|
return;
|
|
135
148
|
}
|
|
149
|
+
// Start the server
|
|
136
150
|
mkdirSync(LOG_DIR, { recursive: true });
|
|
137
|
-
|
|
138
|
-
|
|
151
|
+
const { cmd, args } = resolveMarkusCommand();
|
|
152
|
+
trayLog(`Starting server: ${cmd} ${args.join(' ')}`);
|
|
153
|
+
const outFd = openSync(join(LOG_DIR, 'stdout.log'), 'a');
|
|
154
|
+
const errFd = openSync(join(LOG_DIR, 'stderr.log'), 'a');
|
|
155
|
+
serverProcess = spawn(cmd, args, {
|
|
156
|
+
stdio: ['ignore', outFd, errFd],
|
|
139
157
|
detached: false,
|
|
140
158
|
env: { ...process.env, NO_BROWSER: '1' },
|
|
141
159
|
});
|
|
142
|
-
serverRunning = true;
|
|
143
|
-
updateTrayMenu();
|
|
144
160
|
serverProcess.on('exit', (code) => {
|
|
145
|
-
|
|
161
|
+
if (code && code !== 0)
|
|
162
|
+
trayLog(`Server exited with code ${code}`);
|
|
146
163
|
serverProcess = null;
|
|
147
|
-
updateTrayMenu();
|
|
148
|
-
if (code && code !== 0) {
|
|
149
|
-
console.error(`Markus server exited with code ${code}`);
|
|
150
|
-
}
|
|
151
164
|
});
|
|
152
165
|
serverProcess.on('error', (err) => {
|
|
153
|
-
|
|
166
|
+
trayLog(`Failed to spawn server: ${err.message}`);
|
|
154
167
|
serverProcess = null;
|
|
155
|
-
updateTrayMenu();
|
|
156
|
-
console.error('Failed to start Markus server:', err.message);
|
|
157
|
-
});
|
|
158
|
-
waitForHealth(`${WEB_UI_URL}/api/health`).then((ok) => {
|
|
159
|
-
if (ok && serverRunning)
|
|
160
|
-
openBrowser(WEB_UI_URL);
|
|
161
168
|
});
|
|
169
|
+
const healthy = await waitForHealth(`${WEB_UI_URL}/api/health`);
|
|
170
|
+
if (healthy) {
|
|
171
|
+
trayLog('Server healthy — opening browser');
|
|
172
|
+
openBrowser(WEB_UI_URL);
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
trayLog('Server did not become healthy within 30s');
|
|
176
|
+
}
|
|
162
177
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
178
|
+
/** Stop all Markus server processes and prevent LaunchAgent from restarting. */
|
|
179
|
+
function killServer() {
|
|
180
|
+
trayLog('Stopping server...');
|
|
181
|
+
// Unload LaunchAgent first so launchd won't auto-restart the process
|
|
182
|
+
if (platform() === 'darwin') {
|
|
183
|
+
try {
|
|
184
|
+
const uid = execSync('id -u', { encoding: 'utf-8' }).trim();
|
|
185
|
+
execSync(`launchctl bootout gui/${uid}/global.markus 2>/dev/null`, { encoding: 'utf-8' });
|
|
186
|
+
trayLog('LaunchAgent unloaded');
|
|
187
|
+
}
|
|
188
|
+
catch { /* not loaded or already unloaded */ }
|
|
189
|
+
}
|
|
190
|
+
// Kill the child process we spawned (if any)
|
|
191
|
+
if (serverProcess) {
|
|
192
|
+
serverProcess.kill('SIGTERM');
|
|
193
|
+
serverProcess = null;
|
|
194
|
+
}
|
|
195
|
+
// Also find and kill any Markus process on the port (may have been started
|
|
196
|
+
// externally, by LaunchAgent, or a previous tray session)
|
|
197
|
+
const killByPort = (signal) => {
|
|
198
|
+
try {
|
|
199
|
+
const pids = execSync(`lsof -i :${WEB_UI_PORT} -sTCP:LISTEN -t 2>/dev/null`, { encoding: 'utf-8' }).trim();
|
|
200
|
+
if (!pids)
|
|
201
|
+
return;
|
|
202
|
+
for (const pid of pids.split('\n')) {
|
|
203
|
+
const p = pid.trim();
|
|
204
|
+
if (p && p !== String(process.pid)) {
|
|
205
|
+
trayLog(`Sending ${signal} to server process ${p}`);
|
|
206
|
+
process.kill(Number(p), signal);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
171
209
|
}
|
|
172
|
-
|
|
173
|
-
|
|
210
|
+
catch { /* no process on port */ }
|
|
211
|
+
};
|
|
212
|
+
killByPort('SIGTERM');
|
|
213
|
+
// Force kill after 3 seconds if still alive
|
|
214
|
+
setTimeout(() => killByPort('SIGKILL'), 3000);
|
|
174
215
|
}
|
|
175
216
|
// ── Tray setup ───────────────────────────────────────────────────────────────
|
|
176
|
-
const SEPARATOR = { title: '<SEPARATOR>', tooltip: '', enabled: true };
|
|
177
|
-
const ITEM_OPEN_UI = { title: 'Open Web UI', tooltip: 'Open Markus in browser', enabled: true };
|
|
178
|
-
const ITEM_START = { title: 'Start Server', tooltip: 'Start Markus server', enabled: true };
|
|
179
|
-
const ITEM_STOP = { title: 'Stop Server', tooltip: 'Stop Markus server', enabled: false };
|
|
180
|
-
const ITEM_QUIT = { title: 'Quit Markus', tooltip: 'Stop server and quit', enabled: true };
|
|
181
217
|
let tray = null;
|
|
182
|
-
function buildMenu() {
|
|
183
|
-
return {
|
|
184
|
-
icon: loadIconBase64(),
|
|
185
|
-
title: '',
|
|
186
|
-
tooltip: serverRunning ? 'Markus (running)' : 'Markus (stopped)',
|
|
187
|
-
items: [
|
|
188
|
-
{ ...ITEM_OPEN_UI, enabled: serverRunning },
|
|
189
|
-
SEPARATOR,
|
|
190
|
-
{ ...ITEM_START, enabled: !serverRunning },
|
|
191
|
-
{ ...ITEM_STOP, enabled: serverRunning },
|
|
192
|
-
SEPARATOR,
|
|
193
|
-
ITEM_QUIT,
|
|
194
|
-
],
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
function updateTrayMenu() {
|
|
198
|
-
if (!tray)
|
|
199
|
-
return;
|
|
200
|
-
tray.sendAction({ type: 'update-menu', menu: buildMenu() });
|
|
201
|
-
}
|
|
202
218
|
async function main() {
|
|
203
|
-
|
|
219
|
+
trayLog(`Tray starting (locale=${detectLocale()}, pid=${process.pid})`);
|
|
220
|
+
tray = new SysTray({
|
|
221
|
+
menu: {
|
|
222
|
+
icon: loadIconBase64(),
|
|
223
|
+
title: '',
|
|
224
|
+
tooltip: t.tooltip,
|
|
225
|
+
items: [
|
|
226
|
+
{ title: t.openUI, tooltip: t.openUI, enabled: true },
|
|
227
|
+
{ title: '<SEPARATOR>', tooltip: '', enabled: true },
|
|
228
|
+
{ title: t.quit, tooltip: t.quit, enabled: true },
|
|
229
|
+
],
|
|
230
|
+
},
|
|
231
|
+
copyDir: false,
|
|
232
|
+
});
|
|
204
233
|
await tray.ready();
|
|
205
234
|
tray.onClick(async (action) => {
|
|
206
235
|
const title = action.item.title;
|
|
207
|
-
if (title ===
|
|
236
|
+
if (title === t.openUI) {
|
|
208
237
|
openBrowser(WEB_UI_URL);
|
|
209
238
|
}
|
|
210
|
-
else if (title ===
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
else if (title === ITEM_STOP.title) {
|
|
214
|
-
stopServer();
|
|
215
|
-
}
|
|
216
|
-
else if (title === ITEM_QUIT.title) {
|
|
217
|
-
stopServer();
|
|
218
|
-
// Wait briefly for server to stop, then exit
|
|
239
|
+
else if (title === t.quit) {
|
|
240
|
+
trayLog('Quit requested');
|
|
241
|
+
killServer();
|
|
219
242
|
setTimeout(async () => {
|
|
220
243
|
if (tray)
|
|
221
244
|
await tray.kill(false);
|
|
222
245
|
process.exit(0);
|
|
223
|
-
},
|
|
246
|
+
}, 4000);
|
|
224
247
|
}
|
|
225
248
|
});
|
|
226
249
|
tray.onError((err) => {
|
|
227
|
-
|
|
250
|
+
trayLog(`Tray error: ${err.message}`);
|
|
228
251
|
});
|
|
229
|
-
|
|
230
|
-
await startServer();
|
|
252
|
+
await ensureServerRunning();
|
|
231
253
|
}
|
|
232
254
|
main().catch((err) => {
|
|
233
|
-
|
|
255
|
+
trayLog(`Tray failed to start: ${err}`);
|
|
234
256
|
process.exit(1);
|
|
235
257
|
});
|
|
236
258
|
//# sourceMappingURL=tray.js.map
|
package/dist/tray.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tray.js","sourceRoot":"","sources":["../src/tray.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"tray.js","sourceRoot":"","sources":["../src/tray.ts"],"names":[],"mappings":"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"}
|