@winmatrix/daemon 0.2.0
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/README.md +59 -0
- package/bin/winmatrix-daemon.js +6 -0
- package/dist/core/AgentProcessManager.d.ts +99 -0
- package/dist/core/AgentProcessManager.d.ts.map +1 -0
- package/dist/core/AgentProcessManager.js +292 -0
- package/dist/core/AgentProcessManager.js.map +1 -0
- package/dist/core/ConfigLoader.d.ts +92 -0
- package/dist/core/ConfigLoader.d.ts.map +1 -0
- package/dist/core/ConfigLoader.js +240 -0
- package/dist/core/ConfigLoader.js.map +1 -0
- package/dist/core/DaemonFileLogger.d.ts +34 -0
- package/dist/core/DaemonFileLogger.d.ts.map +1 -0
- package/dist/core/DaemonFileLogger.js +157 -0
- package/dist/core/DaemonFileLogger.js.map +1 -0
- package/dist/core/DaemonLifecycle.d.ts +22 -0
- package/dist/core/DaemonLifecycle.d.ts.map +1 -0
- package/dist/core/DaemonLifecycle.js +155 -0
- package/dist/core/DaemonLifecycle.js.map +1 -0
- package/dist/core/DiagnosticsServer.d.ts +28 -0
- package/dist/core/DiagnosticsServer.d.ts.map +1 -0
- package/dist/core/DiagnosticsServer.js +155 -0
- package/dist/core/DiagnosticsServer.js.map +1 -0
- package/dist/core/InstallationId.d.ts +14 -0
- package/dist/core/InstallationId.d.ts.map +1 -0
- package/dist/core/InstallationId.js +50 -0
- package/dist/core/InstallationId.js.map +1 -0
- package/dist/core/RuntimeAvailabilityReporter.d.ts +27 -0
- package/dist/core/RuntimeAvailabilityReporter.d.ts.map +1 -0
- package/dist/core/RuntimeAvailabilityReporter.js +79 -0
- package/dist/core/RuntimeAvailabilityReporter.js.map +1 -0
- package/dist/core/WorkspaceScanner.d.ts +45 -0
- package/dist/core/WorkspaceScanner.d.ts.map +1 -0
- package/dist/core/WorkspaceScanner.js +166 -0
- package/dist/core/WorkspaceScanner.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +238 -0
- package/dist/index.js.map +1 -0
- package/dist/wrapper/AgentWrapper.d.ts +23 -0
- package/dist/wrapper/AgentWrapper.d.ts.map +1 -0
- package/dist/wrapper/AgentWrapper.js +873 -0
- package/dist/wrapper/AgentWrapper.js.map +1 -0
- package/dist/wrapper/ClaudeStreamParser.d.ts +63 -0
- package/dist/wrapper/ClaudeStreamParser.d.ts.map +1 -0
- package/dist/wrapper/ClaudeStreamParser.js +104 -0
- package/dist/wrapper/ClaudeStreamParser.js.map +1 -0
- package/dist/wrapper/supportedAgentTypes.d.ts +7 -0
- package/dist/wrapper/supportedAgentTypes.d.ts.map +1 -0
- package/dist/wrapper/supportedAgentTypes.js +6 -0
- package/dist/wrapper/supportedAgentTypes.js.map +1 -0
- package/package.json +39 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WinMatrix Daemon - Config Loader
|
|
3
|
+
*
|
|
4
|
+
* Loads configuration from ~/.winmatrix/daemon.json, CLI arguments, and environment variables.
|
|
5
|
+
* Optional field `computerToken` in daemon.json holds the Computer token (wmc_...) for restart
|
|
6
|
+
* without re-exporting WINMATRIX_TOKEN. Use `--persist-token` once to write CLI/env token to disk.
|
|
7
|
+
*/
|
|
8
|
+
import { readFileSync, existsSync, writeFileSync, mkdirSync, chmodSync } from 'node:fs';
|
|
9
|
+
import { homedir } from 'node:os';
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
/* ── Constants ── */
|
|
12
|
+
const DAEMON_HOME_DIR = '.winmatrix';
|
|
13
|
+
const DAEMON_CONFIG_FILE = 'daemon.json';
|
|
14
|
+
/** 默认 WinMatrix 外部 Agent WebSocket 地址(与文档一致) */
|
|
15
|
+
export const DEFAULT_DAEMON_SERVER_URL = 'ws://localhost:8400/api/v1/external-agents/connect';
|
|
16
|
+
const EXTERNAL_AGENT_WS_PATH = '/api/v1/external-agents/connect';
|
|
17
|
+
/**
|
|
18
|
+
* 规范化 Daemon WebSocket 地址:
|
|
19
|
+
* - 纠正常见笔误 `ws://http://host` → `ws://host`
|
|
20
|
+
* - 将 `http(s)://` API 基址转为 `ws(s)://` 并补全路径(若未包含 connect 路径)
|
|
21
|
+
* - `ws(s)://host:port` 无路径时补全默认 connect 路径
|
|
22
|
+
*/
|
|
23
|
+
export function normalizeDaemonServerUrl(input) {
|
|
24
|
+
let s = input.trim();
|
|
25
|
+
if (!s)
|
|
26
|
+
return DEFAULT_DAEMON_SERVER_URL;
|
|
27
|
+
s = s.replace(/^ws:\/\/http:\/\//i, 'ws://').replace(/^wss:\/\/https:\/\//i, 'wss://');
|
|
28
|
+
s = s.replace(/^wss:\/\/http:\/\//i, 'wss://');
|
|
29
|
+
if (/^https:\/\//i.test(s)) {
|
|
30
|
+
const base = s.replace(/^https/i, 'wss').replace(/\/$/, '');
|
|
31
|
+
return base.includes(EXTERNAL_AGENT_WS_PATH)
|
|
32
|
+
? base
|
|
33
|
+
: `${base}${EXTERNAL_AGENT_WS_PATH}`;
|
|
34
|
+
}
|
|
35
|
+
if (/^http:\/\//i.test(s)) {
|
|
36
|
+
const base = s.replace(/^http/i, 'ws').replace(/\/$/, '');
|
|
37
|
+
return base.includes(EXTERNAL_AGENT_WS_PATH)
|
|
38
|
+
? base
|
|
39
|
+
: `${base}${EXTERNAL_AGENT_WS_PATH}`;
|
|
40
|
+
}
|
|
41
|
+
if (/^wss:\/\//i.test(s) && !s.includes(EXTERNAL_AGENT_WS_PATH)) {
|
|
42
|
+
return `${s.replace(/\/$/, '')}${EXTERNAL_AGENT_WS_PATH}`;
|
|
43
|
+
}
|
|
44
|
+
if (/^ws:\/\//i.test(s) && !s.includes(EXTERNAL_AGENT_WS_PATH)) {
|
|
45
|
+
return `${s.replace(/\/$/, '')}${EXTERNAL_AGENT_WS_PATH}`;
|
|
46
|
+
}
|
|
47
|
+
return s;
|
|
48
|
+
}
|
|
49
|
+
/* ── Helpers ── */
|
|
50
|
+
function getDaemonHomePath() {
|
|
51
|
+
return path.join(homedir(), DAEMON_HOME_DIR);
|
|
52
|
+
}
|
|
53
|
+
function getDaemonConfigPath() {
|
|
54
|
+
return path.join(getDaemonHomePath(), DAEMON_CONFIG_FILE);
|
|
55
|
+
}
|
|
56
|
+
/** 供 setup / 运维脚本使用 */
|
|
57
|
+
export function getDaemonConfigFilePath() {
|
|
58
|
+
return getDaemonConfigPath();
|
|
59
|
+
}
|
|
60
|
+
/** 控制台用短路径标签(POSIX 语义:~/...),与配置文件实际读取路径一致。 */
|
|
61
|
+
export function getDaemonConfigPathLabel() {
|
|
62
|
+
const h = `${homedir()}${path.sep}`;
|
|
63
|
+
const cfg = getDaemonConfigPath();
|
|
64
|
+
return cfg.startsWith(h) ? `~/${path.relative(homedir(), cfg)}`.replace(/\\/g, '/') : cfg;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 判断是否已在 daemon.json 持久化 Computer token(不涉及进程环境)。
|
|
68
|
+
*/
|
|
69
|
+
export function describeDaemonCredentialFile() {
|
|
70
|
+
const pathLabel = getDaemonConfigPathLabel();
|
|
71
|
+
const fileExists = existsSync(getDaemonConfigPath());
|
|
72
|
+
const hasStoredComputerToken = tokenFromDaemonJsonFields(loadDaemonJson()).length > 0;
|
|
73
|
+
return { pathLabel, fileExists, hasStoredComputerToken };
|
|
74
|
+
}
|
|
75
|
+
/** 从 JSON 段落读取 token(computerToken 优先,其次别名 token) */
|
|
76
|
+
export function tokenFromDaemonJsonFields(file) {
|
|
77
|
+
const raw = file.computerToken ?? file.token;
|
|
78
|
+
return typeof raw === 'string' ? raw.trim() : '';
|
|
79
|
+
}
|
|
80
|
+
export function loadDaemonJson() {
|
|
81
|
+
const configPath = getDaemonConfigPath();
|
|
82
|
+
if (!existsSync(configPath)) {
|
|
83
|
+
return {};
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
const raw = readFileSync(configPath, 'utf-8');
|
|
87
|
+
const parsed = JSON.parse(raw);
|
|
88
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
89
|
+
return {};
|
|
90
|
+
}
|
|
91
|
+
return parsed;
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return {};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function readDaemonJsonObject() {
|
|
98
|
+
const configPath = getDaemonConfigPath();
|
|
99
|
+
if (!existsSync(configPath)) {
|
|
100
|
+
return {};
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
const raw = readFileSync(configPath, 'utf-8');
|
|
104
|
+
const parsed = JSON.parse(raw);
|
|
105
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
106
|
+
return {};
|
|
107
|
+
}
|
|
108
|
+
return { ...parsed };
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return {};
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/** 将遗留 JSON 字段 `token` 合并入 `computerToken` 并从对象中删掉 `token` */
|
|
115
|
+
function migrateLegacyTokenKey(obj) {
|
|
116
|
+
const legacy = typeof obj.token === 'string' ? obj.token.trim() : '';
|
|
117
|
+
const cur = typeof obj.computerToken === 'string' ? obj.computerToken.trim() : '';
|
|
118
|
+
delete obj.token;
|
|
119
|
+
if (!cur && legacy)
|
|
120
|
+
obj.computerToken = legacy;
|
|
121
|
+
}
|
|
122
|
+
export function parseCliArgs(argv) {
|
|
123
|
+
const result = {};
|
|
124
|
+
for (let i = 0; i < argv.length; i++) {
|
|
125
|
+
if (argv[i] === '--server' && i + 1 < argv.length) {
|
|
126
|
+
result.server = argv[++i];
|
|
127
|
+
}
|
|
128
|
+
else if (argv[i] === '--token' && i + 1 < argv.length) {
|
|
129
|
+
result.token = argv[++i];
|
|
130
|
+
result.tokenSource = 'token';
|
|
131
|
+
}
|
|
132
|
+
else if (argv[i].startsWith('--server=')) {
|
|
133
|
+
result.server = argv[i].slice('--server='.length);
|
|
134
|
+
}
|
|
135
|
+
else if (argv[i].startsWith('--token=')) {
|
|
136
|
+
result.token = argv[i].slice('--token='.length);
|
|
137
|
+
result.tokenSource = 'token';
|
|
138
|
+
}
|
|
139
|
+
else if (argv[i] === '--persist-token') {
|
|
140
|
+
result.persistCredentials = true;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
/* ── Public API ── */
|
|
146
|
+
/**
|
|
147
|
+
* Resolve config + optional persistence flag for daemon startup.
|
|
148
|
+
*
|
|
149
|
+
* Token priority:
|
|
150
|
+
* 1. CLI (--token)
|
|
151
|
+
* 2. Environment (WINMATRIX_TOKEN)
|
|
152
|
+
* 3. Config file (~/.winmatrix/daemon.json `computerToken`, or legacy `token`)
|
|
153
|
+
*
|
|
154
|
+
* Server URL priority:
|
|
155
|
+
* 1. CLI (--server)
|
|
156
|
+
* 2. daemon.json serverUrl
|
|
157
|
+
* 3. Default localhost WebSocket URL
|
|
158
|
+
*/
|
|
159
|
+
export function loadDaemonStartupOptions(argv) {
|
|
160
|
+
const fileConfig = loadDaemonJson();
|
|
161
|
+
const argsConfig = parseCliArgs(argv);
|
|
162
|
+
const rawServerUrl = argsConfig.server ?? fileConfig.serverUrl ?? DEFAULT_DAEMON_SERVER_URL;
|
|
163
|
+
const serverUrl = normalizeDaemonServerUrl(rawServerUrl);
|
|
164
|
+
const tokenFromFile = tokenFromDaemonJsonFields(fileConfig);
|
|
165
|
+
const tokenCli = typeof argsConfig.token === 'string' ? argsConfig.token.trim() : '';
|
|
166
|
+
const tokenEnv = (process.env.WINMATRIX_TOKEN ?? '').trim();
|
|
167
|
+
let token = '';
|
|
168
|
+
let tokenSource;
|
|
169
|
+
if (tokenCli.length > 0) {
|
|
170
|
+
token = tokenCli;
|
|
171
|
+
tokenSource = 'token';
|
|
172
|
+
}
|
|
173
|
+
else if (tokenEnv.length > 0) {
|
|
174
|
+
token = tokenEnv;
|
|
175
|
+
tokenSource = 'env';
|
|
176
|
+
}
|
|
177
|
+
else if (tokenFromFile.length > 0) {
|
|
178
|
+
token = tokenFromFile;
|
|
179
|
+
tokenSource = 'file';
|
|
180
|
+
}
|
|
181
|
+
const persistCredentials = argsConfig.persistCredentials === true;
|
|
182
|
+
return {
|
|
183
|
+
config: { serverUrl, token, tokenSource },
|
|
184
|
+
persistCredentials,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
export function loadConfig(argv) {
|
|
188
|
+
return loadDaemonStartupOptions(argv).config;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* 将当前解析得到的 server URL / Computer token 写回磁盘(chmod 0600)。
|
|
192
|
+
* `computerToken` 为空时仅从文件改写 `serverUrl`,不删除已有 `computerToken`。
|
|
193
|
+
*/
|
|
194
|
+
export function mergeDaemonSetupConfigToDisk(opts) {
|
|
195
|
+
const home = getDaemonHomePath();
|
|
196
|
+
if (!existsSync(home)) {
|
|
197
|
+
mkdirSync(home, { recursive: true, mode: 0o700 });
|
|
198
|
+
chmodSync(home, 0o700);
|
|
199
|
+
}
|
|
200
|
+
const obj = readDaemonJsonObject();
|
|
201
|
+
migrateLegacyTokenKey(obj);
|
|
202
|
+
obj.serverUrl = opts.serverUrl;
|
|
203
|
+
const nextTok = opts.computerToken?.trim();
|
|
204
|
+
if (nextTok && nextTok.length > 0) {
|
|
205
|
+
obj.computerToken = nextTok;
|
|
206
|
+
}
|
|
207
|
+
const cfgPath = getDaemonConfigPath();
|
|
208
|
+
const body = `${JSON.stringify(obj, null, 2)}\n`;
|
|
209
|
+
writeFileSync(cfgPath, body, { encoding: 'utf-8', mode: 0o600 });
|
|
210
|
+
chmodSync(cfgPath, 0o600);
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Merge server URL + Computer token into ~/.winmatrix/daemon.json (chmod 0600).
|
|
214
|
+
* Drops legacy JSON key `token` in favor of `computerToken`.
|
|
215
|
+
*/
|
|
216
|
+
export function persistDaemonCredentialsToDisk(config) {
|
|
217
|
+
const home = getDaemonHomePath();
|
|
218
|
+
if (!existsSync(home)) {
|
|
219
|
+
mkdirSync(home, { recursive: true, mode: 0o700 });
|
|
220
|
+
chmodSync(home, 0o700);
|
|
221
|
+
}
|
|
222
|
+
const obj = readDaemonJsonObject();
|
|
223
|
+
migrateLegacyTokenKey(obj);
|
|
224
|
+
obj.serverUrl = config.serverUrl;
|
|
225
|
+
obj.computerToken = config.token;
|
|
226
|
+
const cfgPath = getDaemonConfigPath();
|
|
227
|
+
const body = `${JSON.stringify(obj, null, 2)}\n`;
|
|
228
|
+
writeFileSync(cfgPath, body, { encoding: 'utf-8', mode: 0o600 });
|
|
229
|
+
chmodSync(cfgPath, 0o600);
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Sanitize a config for logging (token replaced with ***).
|
|
233
|
+
*/
|
|
234
|
+
export function sanitizeConfig(config) {
|
|
235
|
+
return {
|
|
236
|
+
serverUrl: config.serverUrl,
|
|
237
|
+
token: config.token.length > 0 ? '***' : '(empty)',
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
//# sourceMappingURL=ConfigLoader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConfigLoader.js","sourceRoot":"","sources":["../../src/core/ConfigLoader.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACxF,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAyB7B,qBAAqB;AAErB,MAAM,eAAe,GAAG,YAAY,CAAC;AACrC,MAAM,kBAAkB,GAAG,aAAa,CAAC;AAEzC,gDAAgD;AAChD,MAAM,CAAC,MAAM,yBAAyB,GAAG,oDAAoD,CAAC;AAE9F,MAAM,sBAAsB,GAAG,iCAAiC,CAAC;AAEjE;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CAAC,KAAa;IACpD,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IACrB,IAAI,CAAC,CAAC;QAAE,OAAO,yBAAyB,CAAC;IAEzC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,sBAAsB,EAAE,QAAQ,CAAC,CAAC;IACvF,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,qBAAqB,EAAE,QAAQ,CAAC,CAAC;IAE/C,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC5D,OAAO,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC;YAC1C,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,GAAG,IAAI,GAAG,sBAAsB,EAAE,CAAC;IACzC,CAAC;IACD,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC1D,OAAO,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC;YAC1C,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,GAAG,IAAI,GAAG,sBAAsB,EAAE,CAAC;IACzC,CAAC;IAED,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,CAAC;QAChE,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,sBAAsB,EAAE,CAAC;IAC5D,CAAC;IACD,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,CAAC;QAC/D,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,sBAAsB,EAAE,CAAC;IAC5D,CAAC;IAED,OAAO,CAAC,CAAC;AACX,CAAC;AAED,mBAAmB;AAEnB,SAAS,iBAAiB;IACxB,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,eAAe,CAAC,CAAC;AAC/C,CAAC;AAED,SAAS,mBAAmB;IAC1B,OAAO,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,kBAAkB,CAAC,CAAC;AAC5D,CAAC;AAED,uBAAuB;AACvB,MAAM,UAAU,uBAAuB;IACrC,OAAO,mBAAmB,EAAE,CAAC;AAC/B,CAAC;AAED,+CAA+C;AAC/C,MAAM,UAAU,wBAAwB;IACtC,MAAM,CAAC,GAAG,GAAG,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACpC,MAAM,GAAG,GAAG,mBAAmB,EAAE,CAAC;IAClC,OAAO,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AAC5F,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,4BAA4B;IAK1C,MAAM,SAAS,GAAG,wBAAwB,EAAE,CAAC;IAC7C,MAAM,UAAU,GAAG,UAAU,CAAC,mBAAmB,EAAE,CAAC,CAAC;IACrD,MAAM,sBAAsB,GAAG,yBAAyB,CAAC,cAAc,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IACtF,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,sBAAsB,EAAE,CAAC;AAC3D,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,yBAAyB,CAAC,IAA6B;IACrE,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,KAAK,CAAC;IAC7C,OAAO,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,MAAM,UAAU,GAAG,mBAAmB,EAAE,CAAC;IACzC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACxC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3E,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,OAAO,MAAiC,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,SAAS,oBAAoB;IAC3B,MAAM,UAAU,GAAG,mBAAmB,EAAE,CAAC;IACzC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACxC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3E,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,OAAO,EAAE,GAAI,MAAkC,EAAE,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,8DAA8D;AAC9D,SAAS,qBAAqB,CAAC,GAA4B;IACzD,MAAM,MAAM,GAAG,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACrE,MAAM,GAAG,GAAG,OAAO,GAAG,CAAC,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAClF,OAAO,GAAG,CAAC,KAAK,CAAC;IACjB,IAAI,CAAC,GAAG,IAAI,MAAM;QAAE,GAAG,CAAC,aAAa,GAAG,MAAM,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAc;IAMzC,MAAM,MAAM,GAKR,EAAE,CAAC;IACP,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,UAAU,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YAClD,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QAC5B,CAAC;aAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YACxD,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YACzB,MAAM,CAAC,WAAW,GAAG,OAAO,CAAC;QAC/B,CAAC;aAAM,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC3C,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QACpD,CAAC;aAAM,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC1C,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;YAChD,MAAM,CAAC,WAAW,GAAG,OAAO,CAAC;QAC/B,CAAC;aAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,iBAAiB,EAAE,CAAC;YACzC,MAAM,CAAC,kBAAkB,GAAG,IAAI,CAAC;QACnC,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,sBAAsB;AAEtB;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,wBAAwB,CAAC,IAAc;IACrD,MAAM,UAAU,GAAG,cAAc,EAAE,CAAC;IACpC,MAAM,UAAU,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAEtC,MAAM,YAAY,GAChB,UAAU,CAAC,MAAM,IAAI,UAAU,CAAC,SAAS,IAAI,yBAAyB,CAAC;IACzE,MAAM,SAAS,GAAG,wBAAwB,CAAC,YAAY,CAAC,CAAC;IAEzD,MAAM,aAAa,GAAG,yBAAyB,CAAC,UAAU,CAAC,CAAC;IAC5D,MAAM,QAAQ,GAAG,OAAO,UAAU,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACrF,MAAM,QAAQ,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAE5D,IAAI,KAAK,GAAG,EAAE,CAAC;IACf,IAAI,WAAwC,CAAC;IAC7C,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,KAAK,GAAG,QAAQ,CAAC;QACjB,WAAW,GAAG,OAAO,CAAC;IACxB,CAAC;SAAM,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,KAAK,GAAG,QAAQ,CAAC;QACjB,WAAW,GAAG,KAAK,CAAC;IACtB,CAAC;SAAM,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpC,KAAK,GAAG,aAAa,CAAC;QACtB,WAAW,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,MAAM,kBAAkB,GAAG,UAAU,CAAC,kBAAkB,KAAK,IAAI,CAAC;IAElE,OAAO;QACL,MAAM,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,WAAW,EAAE;QACzC,kBAAkB;KACnB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAc;IACvC,OAAO,wBAAwB,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AAC/C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,4BAA4B,CAAC,IAG5C;IACC,MAAM,IAAI,GAAG,iBAAiB,EAAE,CAAC;IACjC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,SAAS,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAClD,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACzB,CAAC;IAED,MAAM,GAAG,GAAG,oBAAoB,EAAE,CAAC;IACnC,qBAAqB,CAAC,GAAG,CAAC,CAAC;IAC3B,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;IAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,EAAE,IAAI,EAAE,CAAC;IAC3C,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClC,GAAG,CAAC,aAAa,GAAG,OAAO,CAAC;IAC9B,CAAC;IAED,MAAM,OAAO,GAAG,mBAAmB,EAAE,CAAC;IACtC,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;IACjD,aAAa,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACjE,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;AAC5B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,8BAA8B,CAAC,MAAoB;IACjE,MAAM,IAAI,GAAG,iBAAiB,EAAE,CAAC;IACjC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,SAAS,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAClD,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACzB,CAAC;IAED,MAAM,GAAG,GAAG,oBAAoB,EAAE,CAAC;IACnC,qBAAqB,CAAC,GAAG,CAAC,CAAC;IAC3B,GAAG,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;IACjC,GAAG,CAAC,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC;IAEjC,MAAM,OAAO,GAAG,mBAAmB,EAAE,CAAC;IACtC,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;IACjD,aAAa,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACjE,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;AAC5B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,MAAoB;IACjD,OAAO;QACL,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;KACnD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 将 daemon 运行日志写入 ~/.winmatrix/logs/daemon-YYYY-MM-DD.log,
|
|
3
|
+
* 并清理超过保留期的历史文件(默认 3 天)。
|
|
4
|
+
*/
|
|
5
|
+
/** 内存中保留供 /api/logs 读取的最近行数 */
|
|
6
|
+
export declare const DEFAULT_LOG_RING_MAX = 800;
|
|
7
|
+
export declare function getLogsDirectory(): string;
|
|
8
|
+
/** 日志行首时间戳:本机本地墙钟,非 UTC(避免 …Z) */
|
|
9
|
+
export declare function formatDaemonLocalTimestamp(d?: Date): string;
|
|
10
|
+
/**
|
|
11
|
+
* 删除日志目录下超过 retentionMs 的 daemon-*.log(按文件名日期;无法解析则按 mtime)。
|
|
12
|
+
*/
|
|
13
|
+
export declare function pruneOldDaemonLogs(retentionMs?: number): void;
|
|
14
|
+
export declare class DaemonFileLogger {
|
|
15
|
+
private currentDay;
|
|
16
|
+
private readonly ring;
|
|
17
|
+
private readonly ringMax;
|
|
18
|
+
constructor(ringMax?: number);
|
|
19
|
+
/** 定时清理(例如每 6 小时) */
|
|
20
|
+
startRetentionTimer(intervalMs?: number): ReturnType<typeof setInterval>;
|
|
21
|
+
private rollFileIfNeeded;
|
|
22
|
+
private currentFilePath;
|
|
23
|
+
/**
|
|
24
|
+
* 写入一行带时间戳的文本(无敏感信息过滤;调用方勿记录 token/apiKey 全文)。
|
|
25
|
+
*/
|
|
26
|
+
writeLine(level: string, message: string): void;
|
|
27
|
+
getRecentLines(max: number): string[];
|
|
28
|
+
getLogDirectory(): string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 把 console.log / warn / error 镜像到文件 logger(仍保留原控制台输出)。
|
|
32
|
+
*/
|
|
33
|
+
export declare function mirrorConsoleToFile(logger: DaemonFileLogger): void;
|
|
34
|
+
//# sourceMappingURL=DaemonFileLogger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DaemonFileLogger.d.ts","sourceRoot":"","sources":["../../src/core/DaemonFileLogger.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAuBH,+BAA+B;AAC/B,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAMxC,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AASD,kCAAkC;AAClC,wBAAgB,0BAA0B,CAAC,CAAC,OAAa,GAAG,MAAM,CASjE;AA4BD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,GAAE,MAA6B,GAAG,IAAI,CAiBnF;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgB;IACrC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,OAAO,GAAE,MAA6B;IAOlD,qBAAqB;IACrB,mBAAmB,CAAC,UAAU,GAAE,MAA2B,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC;IAO5F,OAAO,CAAC,gBAAgB;IAOxB,OAAO,CAAC,eAAe;IAKvB;;OAEG;IACH,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAS/C,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE;IAKrC,eAAe,IAAI,MAAM;CAG1B;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAoBlE"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 将 daemon 运行日志写入 ~/.winmatrix/logs/daemon-YYYY-MM-DD.log,
|
|
3
|
+
* 并清理超过保留期的历史文件(默认 3 天)。
|
|
4
|
+
*/
|
|
5
|
+
import { appendFileSync, existsSync, mkdirSync, readdirSync, chmodSync, unlinkSync, statSync, } from 'node:fs';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { homedir } from 'node:os';
|
|
8
|
+
import util from 'node:util';
|
|
9
|
+
const DAEMON_HOME_DIR = '.winmatrix';
|
|
10
|
+
const LOG_SUBDIR = 'logs';
|
|
11
|
+
const LOG_FILE_PREFIX = 'daemon-';
|
|
12
|
+
const LOG_FILE_SUFFIX = '.log';
|
|
13
|
+
/** 默认保留 3 天 */
|
|
14
|
+
const DEFAULT_RETENTION_MS = 3 * 24 * 60 * 60 * 1000;
|
|
15
|
+
/** 内存中保留供 /api/logs 读取的最近行数 */
|
|
16
|
+
export const DEFAULT_LOG_RING_MAX = 800;
|
|
17
|
+
function getDaemonHome() {
|
|
18
|
+
return path.join(homedir(), DAEMON_HOME_DIR);
|
|
19
|
+
}
|
|
20
|
+
export function getLogsDirectory() {
|
|
21
|
+
return path.join(getDaemonHome(), LOG_SUBDIR);
|
|
22
|
+
}
|
|
23
|
+
function localDateStamp(d = new Date()) {
|
|
24
|
+
const y = d.getFullYear();
|
|
25
|
+
const m = String(d.getMonth() + 1).padStart(2, '0');
|
|
26
|
+
const day = String(d.getDate()).padStart(2, '0');
|
|
27
|
+
return `${y}-${m}-${day}`;
|
|
28
|
+
}
|
|
29
|
+
/** 日志行首时间戳:本机本地墙钟,非 UTC(避免 …Z) */
|
|
30
|
+
export function formatDaemonLocalTimestamp(d = new Date()) {
|
|
31
|
+
const y = d.getFullYear();
|
|
32
|
+
const mo = String(d.getMonth() + 1).padStart(2, '0');
|
|
33
|
+
const day = String(d.getDate()).padStart(2, '0');
|
|
34
|
+
const h = String(d.getHours()).padStart(2, '0');
|
|
35
|
+
const min = String(d.getMinutes()).padStart(2, '0');
|
|
36
|
+
const sec = String(d.getSeconds()).padStart(2, '0');
|
|
37
|
+
const ms = String(d.getMilliseconds()).padStart(3, '0');
|
|
38
|
+
return `${y}-${mo}-${day} ${h}:${min}:${sec}.${ms}`;
|
|
39
|
+
}
|
|
40
|
+
function ensureLogsDir() {
|
|
41
|
+
const dir = getLogsDirectory();
|
|
42
|
+
const parent = getDaemonHome();
|
|
43
|
+
if (!existsSync(parent)) {
|
|
44
|
+
mkdirSync(parent, { recursive: true, mode: 0o700 });
|
|
45
|
+
chmodSync(parent, 0o700);
|
|
46
|
+
}
|
|
47
|
+
if (!existsSync(dir)) {
|
|
48
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
49
|
+
chmodSync(dir, 0o700);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const LOG_NAME_RE = /^daemon-(\d{4})-(\d{2})-(\d{2})\.log$/;
|
|
53
|
+
function parseLogDate(name) {
|
|
54
|
+
const m = LOG_NAME_RE.exec(name);
|
|
55
|
+
if (!m)
|
|
56
|
+
return null;
|
|
57
|
+
const y = Number(m[1]);
|
|
58
|
+
const mo = Number(m[2]) - 1;
|
|
59
|
+
const d = Number(m[3]);
|
|
60
|
+
const dt = new Date(y, mo, d);
|
|
61
|
+
if (dt.getFullYear() !== y || dt.getMonth() !== mo || dt.getDate() !== d)
|
|
62
|
+
return null;
|
|
63
|
+
return dt;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* 删除日志目录下超过 retentionMs 的 daemon-*.log(按文件名日期;无法解析则按 mtime)。
|
|
67
|
+
*/
|
|
68
|
+
export function pruneOldDaemonLogs(retentionMs = DEFAULT_RETENTION_MS) {
|
|
69
|
+
const dir = getLogsDirectory();
|
|
70
|
+
if (!existsSync(dir))
|
|
71
|
+
return;
|
|
72
|
+
const cutoff = Date.now() - retentionMs;
|
|
73
|
+
for (const name of readdirSync(dir)) {
|
|
74
|
+
if (!name.startsWith(LOG_FILE_PREFIX) || !name.endsWith(LOG_FILE_SUFFIX))
|
|
75
|
+
continue;
|
|
76
|
+
const full = path.join(dir, name);
|
|
77
|
+
try {
|
|
78
|
+
const fromName = parseLogDate(name);
|
|
79
|
+
const t = fromName ? fromName.getTime() : statSync(full).mtimeMs;
|
|
80
|
+
if (t < cutoff) {
|
|
81
|
+
unlinkSync(full);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
/* ignore per-file errors */
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
export class DaemonFileLogger {
|
|
90
|
+
currentDay;
|
|
91
|
+
ring = [];
|
|
92
|
+
ringMax;
|
|
93
|
+
constructor(ringMax = DEFAULT_LOG_RING_MAX) {
|
|
94
|
+
ensureLogsDir();
|
|
95
|
+
pruneOldDaemonLogs();
|
|
96
|
+
this.currentDay = localDateStamp();
|
|
97
|
+
this.ringMax = ringMax;
|
|
98
|
+
}
|
|
99
|
+
/** 定时清理(例如每 6 小时) */
|
|
100
|
+
startRetentionTimer(intervalMs = 6 * 60 * 60 * 1000) {
|
|
101
|
+
return setInterval(() => {
|
|
102
|
+
pruneOldDaemonLogs();
|
|
103
|
+
this.rollFileIfNeeded();
|
|
104
|
+
}, intervalMs);
|
|
105
|
+
}
|
|
106
|
+
rollFileIfNeeded() {
|
|
107
|
+
const today = localDateStamp();
|
|
108
|
+
if (today !== this.currentDay) {
|
|
109
|
+
this.currentDay = today;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
currentFilePath() {
|
|
113
|
+
this.rollFileIfNeeded();
|
|
114
|
+
return path.join(getLogsDirectory(), `${LOG_FILE_PREFIX}${this.currentDay}${LOG_FILE_SUFFIX}`);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* 写入一行带时间戳的文本(无敏感信息过滤;调用方勿记录 token/apiKey 全文)。
|
|
118
|
+
*/
|
|
119
|
+
writeLine(level, message) {
|
|
120
|
+
const line = `${formatDaemonLocalTimestamp()} [${level}] ${message}\n`;
|
|
121
|
+
appendFileSync(this.currentFilePath(), line, { encoding: 'utf-8' });
|
|
122
|
+
this.ring.push(line.replace(/\n$/, ''));
|
|
123
|
+
if (this.ring.length > this.ringMax) {
|
|
124
|
+
this.ring.splice(0, this.ring.length - this.ringMax);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
getRecentLines(max) {
|
|
128
|
+
if (max <= 0)
|
|
129
|
+
return [];
|
|
130
|
+
return this.ring.slice(-max);
|
|
131
|
+
}
|
|
132
|
+
getLogDirectory() {
|
|
133
|
+
return getLogsDirectory();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* 把 console.log / warn / error 镜像到文件 logger(仍保留原控制台输出)。
|
|
138
|
+
*/
|
|
139
|
+
export function mirrorConsoleToFile(logger) {
|
|
140
|
+
const origLog = console.log.bind(console);
|
|
141
|
+
const origWarn = console.warn.bind(console);
|
|
142
|
+
const origError = console.error.bind(console);
|
|
143
|
+
const fmt = (args) => args.map((a) => (typeof a === 'string' ? a : util.inspect(a, { depth: 6, breakLength: 120 }))).join(' ');
|
|
144
|
+
console.log = (...args) => {
|
|
145
|
+
logger.writeLine('log', fmt(args));
|
|
146
|
+
origLog(...args);
|
|
147
|
+
};
|
|
148
|
+
console.warn = (...args) => {
|
|
149
|
+
logger.writeLine('warn', fmt(args));
|
|
150
|
+
origWarn(...args);
|
|
151
|
+
};
|
|
152
|
+
console.error = (...args) => {
|
|
153
|
+
logger.writeLine('error', fmt(args));
|
|
154
|
+
origError(...args);
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=DaemonFileLogger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DaemonFileLogger.js","sourceRoot":"","sources":["../../src/core/DaemonFileLogger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Daemon 运维:首次目录/init、按 PID 平滑重启。
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* 守护进程主循环开始时写入(供 restart 查找)。
|
|
6
|
+
*/
|
|
7
|
+
export declare function writeDaemonPidFile(): void;
|
|
8
|
+
/**
|
|
9
|
+
* 退出时删除 PID 文件。
|
|
10
|
+
*/
|
|
11
|
+
export declare function clearDaemonPidFile(): void;
|
|
12
|
+
/**
|
|
13
|
+
* 创建 ~/.winmatrix、installation、logs;写入或合并 daemon.json(serverUrl / computerToken)。
|
|
14
|
+
* 可选:`winmatrix-daemon setup [--server <ws-url>] [--token <wmc_...>]`
|
|
15
|
+
*/
|
|
16
|
+
export declare function runSetup(setupArgv: string[]): void;
|
|
17
|
+
/**
|
|
18
|
+
* 向旧进程发 SIGTERM,再后台拉起新进程(参数为 restart 之后的 argv)。
|
|
19
|
+
*/
|
|
20
|
+
export declare function runRestart(forwardArgv: string[]): Promise<void>;
|
|
21
|
+
export declare function printCliHelp(daemonVersion: string): void;
|
|
22
|
+
//# sourceMappingURL=DaemonLifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DaemonLifecycle.d.ts","sourceRoot":"","sources":["../../src/core/DaemonLifecycle.ts"],"names":[],"mappings":"AAAA;;GAEG;AAqCH;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAOzC;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAWzC;AAqBD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,CAsBlD;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAqCrE;AAED,wBAAgB,YAAY,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAyBxD"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Daemon 运维:首次目录/init、按 PID 平滑重启。
|
|
3
|
+
*/
|
|
4
|
+
import { spawn } from 'node:child_process';
|
|
5
|
+
import { existsSync, writeFileSync, readFileSync, unlinkSync, chmodSync, mkdirSync, } from 'node:fs';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { homedir } from 'node:os';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
|
+
import { getOrCreateInstallationId } from './InstallationId.js';
|
|
10
|
+
import { DaemonFileLogger, pruneOldDaemonLogs } from './DaemonFileLogger.js';
|
|
11
|
+
import { DEFAULT_DAEMON_SERVER_URL, getDaemonConfigFilePath, mergeDaemonSetupConfigToDisk, normalizeDaemonServerUrl, parseCliArgs, loadDaemonJson, } from './ConfigLoader.js';
|
|
12
|
+
const DAEMON_HOME = path.join(homedir(), '.winmatrix');
|
|
13
|
+
const PID_FILENAME = 'daemon.pid';
|
|
14
|
+
function getPidFilePath() {
|
|
15
|
+
return path.join(DAEMON_HOME, PID_FILENAME);
|
|
16
|
+
}
|
|
17
|
+
function isProbablyOurDaemonPid(pid) {
|
|
18
|
+
return Number.isInteger(pid) && pid > 0;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 守护进程主循环开始时写入(供 restart 查找)。
|
|
22
|
+
*/
|
|
23
|
+
export function writeDaemonPidFile() {
|
|
24
|
+
if (!existsSync(DAEMON_HOME)) {
|
|
25
|
+
mkdirSync(DAEMON_HOME, { recursive: true, mode: 0o700 });
|
|
26
|
+
chmodSync(DAEMON_HOME, 0o700);
|
|
27
|
+
}
|
|
28
|
+
writeFileSync(getPidFilePath(), String(process.pid), { encoding: 'utf-8', mode: 0o600 });
|
|
29
|
+
chmodSync(getPidFilePath(), 0o600);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 退出时删除 PID 文件。
|
|
33
|
+
*/
|
|
34
|
+
export function clearDaemonPidFile() {
|
|
35
|
+
try {
|
|
36
|
+
if (existsSync(getPidFilePath())) {
|
|
37
|
+
const raw = readFileSync(getPidFilePath(), 'utf-8').trim();
|
|
38
|
+
if (raw === String(process.pid)) {
|
|
39
|
+
unlinkSync(getPidFilePath());
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
/* ignore */
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function readExistingPid() {
|
|
48
|
+
try {
|
|
49
|
+
if (!existsSync(getPidFilePath()))
|
|
50
|
+
return null;
|
|
51
|
+
const n = Number.parseInt(readFileSync(getPidFilePath(), 'utf-8').trim(), 10);
|
|
52
|
+
return isProbablyOurDaemonPid(n) ? n : null;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function sleep(ms) {
|
|
59
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
60
|
+
}
|
|
61
|
+
function resolveEntryScriptPath() {
|
|
62
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
63
|
+
return path.join(here, '..', 'index.js');
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* 创建 ~/.winmatrix、installation、logs;写入或合并 daemon.json(serverUrl / computerToken)。
|
|
67
|
+
* 可选:`winmatrix-daemon setup [--server <ws-url>] [--token <wmc_...>]`
|
|
68
|
+
*/
|
|
69
|
+
export function runSetup(setupArgv) {
|
|
70
|
+
getOrCreateInstallationId();
|
|
71
|
+
new DaemonFileLogger();
|
|
72
|
+
pruneOldDaemonLogs();
|
|
73
|
+
const args = parseCliArgs(setupArgv);
|
|
74
|
+
const file = loadDaemonJson();
|
|
75
|
+
const serverUrl = normalizeDaemonServerUrl(args.server ?? file.serverUrl ?? DEFAULT_DAEMON_SERVER_URL);
|
|
76
|
+
const tokenArg = typeof args.token === 'string' ? args.token.trim() : '';
|
|
77
|
+
mergeDaemonSetupConfigToDisk({ serverUrl, computerToken: tokenArg });
|
|
78
|
+
const cfgPath = getDaemonConfigFilePath();
|
|
79
|
+
console.log(`[daemon] setup: wrote ${cfgPath}`);
|
|
80
|
+
console.log('[daemon] setup: done.');
|
|
81
|
+
if (tokenArg.length === 0) {
|
|
82
|
+
console.log('[daemon] Tip: add Computer token with winmatrix-daemon setup --token wmc_... or edit computerToken in daemon.json');
|
|
83
|
+
}
|
|
84
|
+
console.log('[daemon] Then: winmatrix-daemon or winmatrix-daemon restart');
|
|
85
|
+
console.log('[daemon] Local UI: http://127.0.0.1:18767/ (daemon running)');
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* 向旧进程发 SIGTERM,再后台拉起新进程(参数为 restart 之后的 argv)。
|
|
89
|
+
*/
|
|
90
|
+
export async function runRestart(forwardArgv) {
|
|
91
|
+
const oldPid = readExistingPid();
|
|
92
|
+
if (oldPid !== null) {
|
|
93
|
+
try {
|
|
94
|
+
process.kill(oldPid, 'SIGTERM');
|
|
95
|
+
console.log(`[daemon] restart: sent SIGTERM to pid ${oldPid}`);
|
|
96
|
+
for (let i = 0; i < 50; i++) {
|
|
97
|
+
try {
|
|
98
|
+
process.kill(oldPid, 0);
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
await sleep(100);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
catch (e) {
|
|
107
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
108
|
+
console.log(`[daemon] restart: no process for pid ${oldPid} (${msg}), starting fresh`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
console.log('[daemon] restart: no pid file (daemon was not running or first start)');
|
|
113
|
+
}
|
|
114
|
+
const entry = resolveEntryScriptPath();
|
|
115
|
+
if (!existsSync(entry)) {
|
|
116
|
+
console.error(`[daemon] restart: entry not found: ${entry}`);
|
|
117
|
+
console.error('[daemon] restart: run from built package (npm run build in packages/winmatrix-daemon)');
|
|
118
|
+
process.exitCode = 1;
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const child = spawn(process.execPath, [entry, ...forwardArgv], {
|
|
122
|
+
detached: true,
|
|
123
|
+
stdio: 'inherit',
|
|
124
|
+
env: process.env,
|
|
125
|
+
});
|
|
126
|
+
child.unref();
|
|
127
|
+
console.log(`[daemon] restart: started new daemon (child pid ${child.pid ?? '?'})`);
|
|
128
|
+
}
|
|
129
|
+
export function printCliHelp(daemonVersion) {
|
|
130
|
+
console.log(`WinMatrix Daemon ${daemonVersion}`);
|
|
131
|
+
console.log(`
|
|
132
|
+
Usage:
|
|
133
|
+
winmatrix-daemon [options] Run daemon (foreground)
|
|
134
|
+
winmatrix-daemon setup [options] Create ~/.winmatrix + write/merge daemon.json
|
|
135
|
+
winmatrix-daemon restart [options] SIGTERM old daemon (from pid file), start again with options
|
|
136
|
+
winmatrix-daemon help This help
|
|
137
|
+
|
|
138
|
+
Options (setup / run / restart):
|
|
139
|
+
--server <ws-url> WebSocket URL (default from ~/.winmatrix/daemon.json)
|
|
140
|
+
--token <wmc_...> Computer registration token (overrides env + daemon.json)
|
|
141
|
+
--persist-token After resolving token (CLI or env), save serverUrl + computerToken to daemon.json
|
|
142
|
+
|
|
143
|
+
Environment:
|
|
144
|
+
WINMATRIX_TOKEN Computer token (wmc_...)
|
|
145
|
+
WINMATRIX_DAEMON_DIAG_* Local diagnostics HTTP (see DiagnosticsServer)
|
|
146
|
+
|
|
147
|
+
Config file:
|
|
148
|
+
~/.winmatrix/daemon.json serverUrl, optional computerToken (read on each start; chmod 600)
|
|
149
|
+
|
|
150
|
+
Typical:
|
|
151
|
+
winmatrix-daemon setup --token wmc_... --server ws://host:8400/api/v1/external-agents/connect
|
|
152
|
+
winmatrix-daemon restart
|
|
153
|
+
`);
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=DaemonLifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DaemonLifecycle.js","sourceRoot":"","sources":["../../src/core/DaemonLifecycle.ts"],"names":[],"mappings":"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"}
|