engine7 7.1.42 → 7.1.44
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/cli.mjs +299 -164
- package/dist/engine-startup.mjs +38 -2
- package/dist/main.mjs +38 -2
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -14,6 +14,156 @@ var __export = (target, all) => {
|
|
|
14
14
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
+
// src/feishu-quick-register.ts
|
|
18
|
+
var feishu_quick_register_exports = {};
|
|
19
|
+
__export(feishu_quick_register_exports, {
|
|
20
|
+
registerFeishuApp: () => registerFeishuApp
|
|
21
|
+
});
|
|
22
|
+
async function postRegistration(domain, body) {
|
|
23
|
+
const url = `${ACCOUNTS_URL[domain]}${REGISTRATION_PATH}`;
|
|
24
|
+
const res = await fetch(url, {
|
|
25
|
+
method: "POST",
|
|
26
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
27
|
+
body: new URLSearchParams(body).toString(),
|
|
28
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
29
|
+
});
|
|
30
|
+
if (!res.ok) {
|
|
31
|
+
throw new Error(`\u98DE\u4E66\u6CE8\u518C\u63A5\u53E3\u8FD4\u56DE ${res.status}: ${await res.text()}`);
|
|
32
|
+
}
|
|
33
|
+
return res.json();
|
|
34
|
+
}
|
|
35
|
+
async function initRegistration(domain) {
|
|
36
|
+
const res = await postRegistration(domain, { action: "init" });
|
|
37
|
+
if (!res.supported_auth_methods?.includes("client_secret")) {
|
|
38
|
+
throw new Error("\u5F53\u524D\u98DE\u4E66\u73AF\u5883\u4E0D\u652F\u6301 client_secret \u8BA4\u8BC1\uFF0C\u65E0\u6CD5\u81EA\u52A8\u6CE8\u518C");
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async function beginRegistration(domain) {
|
|
42
|
+
const res = await postRegistration(domain, {
|
|
43
|
+
action: "begin",
|
|
44
|
+
archetype: "PersonalAgent",
|
|
45
|
+
auth_method: "client_secret",
|
|
46
|
+
request_user_info: "open_id"
|
|
47
|
+
});
|
|
48
|
+
if (!res.device_code || !res.verification_uri_complete) {
|
|
49
|
+
throw new Error(`\u98DE\u4E66\u6CE8\u518C\u5931\u8D25: \u672A\u8FD4\u56DE device_code
|
|
50
|
+
${JSON.stringify(res)}`);
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
deviceCode: res.device_code,
|
|
54
|
+
qrUrl: res.verification_uri_complete,
|
|
55
|
+
userCode: res.user_code,
|
|
56
|
+
interval: res.interval ?? DEFAULT_POLL_INTERVAL,
|
|
57
|
+
expireIn: res.expire_in ?? 300
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
async function pollRegistration(domain, deviceCode, interval, deadline, onLog, signal) {
|
|
61
|
+
let currentInterval = interval;
|
|
62
|
+
let currentDomain = domain;
|
|
63
|
+
while (Date.now() < deadline) {
|
|
64
|
+
if (signal?.aborted) return null;
|
|
65
|
+
let res;
|
|
66
|
+
try {
|
|
67
|
+
res = await postRegistration(currentDomain, {
|
|
68
|
+
action: "poll",
|
|
69
|
+
device_code: deviceCode
|
|
70
|
+
});
|
|
71
|
+
} catch {
|
|
72
|
+
await sleep(currentInterval * 1e3);
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (res.user_info?.tenant_brand === "lark" && currentDomain === "feishu") {
|
|
76
|
+
currentDomain = "lark";
|
|
77
|
+
onLog?.("\u68C0\u6D4B\u5230 Lark \u8D26\u53F7\uFF0C\u5207\u6362\u57DF\u540D...");
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (res.client_id && res.client_secret) {
|
|
81
|
+
return {
|
|
82
|
+
appId: res.client_id,
|
|
83
|
+
appSecret: res.client_secret,
|
|
84
|
+
openId: res.user_info?.open_id,
|
|
85
|
+
domain: currentDomain
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
if (res.error) {
|
|
89
|
+
if (res.error === "authorization_pending") {
|
|
90
|
+
} else if (res.error === "slow_down") {
|
|
91
|
+
currentInterval += 5;
|
|
92
|
+
} else if (res.error === "access_denied") {
|
|
93
|
+
throw new Error("\u7528\u6237\u62D2\u7EDD\u4E86\u6388\u6743");
|
|
94
|
+
} else if (res.error === "expired_token") {
|
|
95
|
+
throw new Error("\u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F");
|
|
96
|
+
} else {
|
|
97
|
+
throw new Error(`\u98DE\u4E66\u6CE8\u518C\u9519\u8BEF: ${res.error} \u2014 ${res.error_description ?? ""}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
await sleep(currentInterval * 1e3);
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
async function registerFeishuApp(options = {}) {
|
|
105
|
+
const domain = options.domain ?? "feishu";
|
|
106
|
+
const timeoutSec = options.timeoutSec ?? 300;
|
|
107
|
+
const log = options.onLog ?? (() => {
|
|
108
|
+
});
|
|
109
|
+
log("\u68C0\u67E5\u98DE\u4E66\u73AF\u5883...");
|
|
110
|
+
await initRegistration(domain);
|
|
111
|
+
log("\u751F\u6210\u4E8C\u7EF4\u7801...");
|
|
112
|
+
const { deviceCode, qrUrl, interval, expireIn } = await beginRegistration(domain);
|
|
113
|
+
options.onQrCode?.(qrUrl);
|
|
114
|
+
log(`\u8BF7\u7528\u98DE\u4E66 App \u626B\u63CF\u4E8C\u7EF4\u7801\uFF08${expireIn}\u79D2\u540E\u8FC7\u671F\uFF09...`);
|
|
115
|
+
const deadline = Date.now() + Math.min(expireIn, timeoutSec) * 1e3;
|
|
116
|
+
const result = await pollRegistration(domain, deviceCode, interval, deadline, log, options.signal);
|
|
117
|
+
if (result) {
|
|
118
|
+
log(`\u2705 \u6CE8\u518C\u6210\u529F\uFF01App ID: ${result.appId}`);
|
|
119
|
+
} else {
|
|
120
|
+
log("\u23F0 \u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F");
|
|
121
|
+
}
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
function sleep(ms) {
|
|
125
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
126
|
+
}
|
|
127
|
+
var ACCOUNTS_URL, REGISTRATION_PATH, REQUEST_TIMEOUT_MS, DEFAULT_POLL_INTERVAL;
|
|
128
|
+
var init_feishu_quick_register = __esm({
|
|
129
|
+
"src/feishu-quick-register.ts"() {
|
|
130
|
+
"use strict";
|
|
131
|
+
ACCOUNTS_URL = {
|
|
132
|
+
feishu: "https://accounts.feishu.cn",
|
|
133
|
+
lark: "https://accounts.larksuite.com"
|
|
134
|
+
};
|
|
135
|
+
REGISTRATION_PATH = "/oauth/v1/app/registration";
|
|
136
|
+
REQUEST_TIMEOUT_MS = 1e4;
|
|
137
|
+
DEFAULT_POLL_INTERVAL = 5;
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// src/qr-render.ts
|
|
142
|
+
var qr_render_exports = {};
|
|
143
|
+
__export(qr_render_exports, {
|
|
144
|
+
renderQrTerminal: () => renderQrTerminal
|
|
145
|
+
});
|
|
146
|
+
import { createRequire } from "node:module";
|
|
147
|
+
async function renderQrTerminal(url, options) {
|
|
148
|
+
return new Promise((resolve2, reject) => {
|
|
149
|
+
try {
|
|
150
|
+
const qt = require2("qrcode-terminal");
|
|
151
|
+
qt.generate(url, { small: options?.small ?? true }, (output) => {
|
|
152
|
+
resolve2(output);
|
|
153
|
+
});
|
|
154
|
+
} catch (err) {
|
|
155
|
+
reject(err);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
var require2;
|
|
160
|
+
var init_qr_render = __esm({
|
|
161
|
+
"src/qr-render.ts"() {
|
|
162
|
+
"use strict";
|
|
163
|
+
require2 = createRequire(import.meta.url);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
17
167
|
// src/channels/wechat.ts
|
|
18
168
|
var wechat_exports = {};
|
|
19
169
|
__export(wechat_exports, {
|
|
@@ -301,20 +451,35 @@ async function wechatQrLogin(options) {
|
|
|
301
451
|
console.error("[wechat] QR response missing qrcode field");
|
|
302
452
|
return null;
|
|
303
453
|
}
|
|
454
|
+
let pollQrValue = qrcodeValue;
|
|
304
455
|
const qrScanData = qrcodeUrl || qrcodeValue;
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
456
|
+
try {
|
|
457
|
+
const { renderQrTerminal: renderQrTerminal2 } = await Promise.resolve().then(() => (init_qr_render(), qr_render_exports));
|
|
458
|
+
const qrBlock = await renderQrTerminal2(qrScanData);
|
|
459
|
+
console.log("\n========== \u5FAE\u4FE1\u626B\u7801\u767B\u5F55 ==========");
|
|
460
|
+
if (qrcodeUrl) {
|
|
461
|
+
console.log(`\u626B\u7801\u94FE\u63A5: ${qrcodeUrl}`);
|
|
462
|
+
}
|
|
463
|
+
if (qrBlock) {
|
|
464
|
+
console.log("\u8BF7\u7528\u5FAE\u4FE1\u626B\u63CF\u4EE5\u4E0B\u4E8C\u7EF4\u7801:");
|
|
465
|
+
console.log(qrBlock);
|
|
466
|
+
} else {
|
|
467
|
+
console.log("\u4E8C\u7EF4\u7801\u6E32\u67D3\u5931\u8D25\uFF0C\u8BF7\u7528\u5FAE\u4FE1\u300C\u626B\u4E00\u626B\u300D\u6253\u5F00\u4E0A\u9762\u7684\u94FE\u63A5:");
|
|
468
|
+
}
|
|
469
|
+
console.log("===================================\n");
|
|
470
|
+
} catch {
|
|
471
|
+
console.log("\n========== \u5FAE\u4FE1\u626B\u7801\u767B\u5F55 ==========");
|
|
472
|
+
if (qrcodeUrl) console.log(`\u626B\u7801\u94FE\u63A5: ${qrcodeUrl}`);
|
|
473
|
+
console.log("\u8BF7\u7528\u5FAE\u4FE1\u626B\u63CF\u4E8C\u7EF4\u7801\uFF08\u6216\u6253\u5F00\u4E0A\u9762\u7684\u94FE\u63A5\uFF09:");
|
|
474
|
+
console.log("===================================\n");
|
|
308
475
|
}
|
|
309
|
-
console.log("\u8BF7\u7528\u5FAE\u4FE1\u626B\u63CF\u4E8C\u7EF4\u7801\uFF08\u6216\u6253\u5F00\u4E0A\u9762\u7684\u94FE\u63A5\uFF09:");
|
|
310
|
-
console.log("===================================\n");
|
|
311
476
|
const deadline = Date.now() + timeoutSeconds * 1e3;
|
|
312
477
|
let currentBaseUrl = ILINK_BASE_URL;
|
|
313
478
|
let refreshCount = 0;
|
|
314
479
|
while (Date.now() < deadline) {
|
|
315
480
|
let statusResp;
|
|
316
481
|
try {
|
|
317
|
-
statusResp = await apiGet(currentBaseUrl, `${EP_GET_QR_STATUS}?qrcode=${
|
|
482
|
+
statusResp = await apiGet(currentBaseUrl, `${EP_GET_QR_STATUS}?qrcode=${pollQrValue}`, "", QR_TIMEOUT_MS);
|
|
318
483
|
} catch {
|
|
319
484
|
await sleep2(1e3);
|
|
320
485
|
continue;
|
|
@@ -339,7 +504,17 @@ async function wechatQrLogin(options) {
|
|
|
339
504
|
qrResp = await apiGet(ILINK_BASE_URL, `${EP_GET_BOT_QR}?bot_type=${botType}`, "", QR_TIMEOUT_MS);
|
|
340
505
|
const newQrValue = String(qrResp?.qrcode || "");
|
|
341
506
|
const newQrUrl = String(qrResp?.qrcode_img_content || "");
|
|
342
|
-
if (
|
|
507
|
+
if (!newQrValue) throw new Error("refresh response missing qrcode");
|
|
508
|
+
pollQrValue = newQrValue;
|
|
509
|
+
console.log("\u65B0\u626B\u7801\u94FE\u63A5:" + (newQrUrl ? ` ${newQrUrl}` : " (\u89C1\u4E0A\u65B9\u4E8C\u7EF4\u7801\u5DF2\u5931\u6548\uFF0C\u8BF7\u91CD\u626B)"));
|
|
510
|
+
if (newQrUrl) {
|
|
511
|
+
try {
|
|
512
|
+
const { renderQrTerminal: renderQrTerminal2 } = await Promise.resolve().then(() => (init_qr_render(), qr_render_exports));
|
|
513
|
+
const qrBlock = await renderQrTerminal2(newQrUrl);
|
|
514
|
+
if (qrBlock) console.log(qrBlock);
|
|
515
|
+
} catch {
|
|
516
|
+
}
|
|
517
|
+
}
|
|
343
518
|
} catch (err) {
|
|
344
519
|
console.error(`[wechat] QR refresh failed: ${err.message}`);
|
|
345
520
|
return null;
|
|
@@ -360,15 +535,6 @@ async function wechatQrLogin(options) {
|
|
|
360
535
|
\u2705 \u5FAE\u4FE1\u767B\u5F55\u6210\u529F!`);
|
|
361
536
|
console.log(` accountId: ${accountId}`);
|
|
362
537
|
console.log(` \u51ED\u8BC1\u5DF2\u4FDD\u5B58: ${credFile}`);
|
|
363
|
-
console.log(`
|
|
364
|
-
\u8BF7\u5C06\u4EE5\u4E0B\u914D\u7F6E\u6DFB\u52A0\u5230 xiaoke.json:`);
|
|
365
|
-
console.log(JSON.stringify({
|
|
366
|
-
wechat: {
|
|
367
|
-
token,
|
|
368
|
-
accountId,
|
|
369
|
-
baseUrl: baseUrl !== ILINK_BASE_URL ? baseUrl : void 0
|
|
370
|
-
}
|
|
371
|
-
}, null, 2));
|
|
372
538
|
return { accountId, token, baseUrl, userId };
|
|
373
539
|
}
|
|
374
540
|
await sleep2(1e3);
|
|
@@ -1569,145 +1735,13 @@ var init_cli_travel = __esm({
|
|
|
1569
1735
|
});
|
|
1570
1736
|
|
|
1571
1737
|
// src/cli-init.ts
|
|
1738
|
+
init_feishu_quick_register();
|
|
1739
|
+
init_wechat();
|
|
1740
|
+
init_qr_render();
|
|
1572
1741
|
import * as path3 from "node:path";
|
|
1573
1742
|
import * as fs3 from "node:fs";
|
|
1574
1743
|
import * as readline from "node:readline";
|
|
1575
1744
|
import { fileURLToPath } from "node:url";
|
|
1576
|
-
|
|
1577
|
-
// src/feishu-quick-register.ts
|
|
1578
|
-
var ACCOUNTS_URL = {
|
|
1579
|
-
feishu: "https://accounts.feishu.cn",
|
|
1580
|
-
lark: "https://accounts.larksuite.com"
|
|
1581
|
-
};
|
|
1582
|
-
var REGISTRATION_PATH = "/oauth/v1/app/registration";
|
|
1583
|
-
var REQUEST_TIMEOUT_MS = 1e4;
|
|
1584
|
-
var DEFAULT_POLL_INTERVAL = 5;
|
|
1585
|
-
async function postRegistration(domain, body) {
|
|
1586
|
-
const url = `${ACCOUNTS_URL[domain]}${REGISTRATION_PATH}`;
|
|
1587
|
-
const res = await fetch(url, {
|
|
1588
|
-
method: "POST",
|
|
1589
|
-
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
1590
|
-
body: new URLSearchParams(body).toString(),
|
|
1591
|
-
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
1592
|
-
});
|
|
1593
|
-
if (!res.ok) {
|
|
1594
|
-
throw new Error(`\u98DE\u4E66\u6CE8\u518C\u63A5\u53E3\u8FD4\u56DE ${res.status}: ${await res.text()}`);
|
|
1595
|
-
}
|
|
1596
|
-
return res.json();
|
|
1597
|
-
}
|
|
1598
|
-
async function initRegistration(domain) {
|
|
1599
|
-
const res = await postRegistration(domain, { action: "init" });
|
|
1600
|
-
if (!res.supported_auth_methods?.includes("client_secret")) {
|
|
1601
|
-
throw new Error("\u5F53\u524D\u98DE\u4E66\u73AF\u5883\u4E0D\u652F\u6301 client_secret \u8BA4\u8BC1\uFF0C\u65E0\u6CD5\u81EA\u52A8\u6CE8\u518C");
|
|
1602
|
-
}
|
|
1603
|
-
}
|
|
1604
|
-
async function beginRegistration(domain) {
|
|
1605
|
-
const res = await postRegistration(domain, {
|
|
1606
|
-
action: "begin",
|
|
1607
|
-
archetype: "PersonalAgent",
|
|
1608
|
-
auth_method: "client_secret",
|
|
1609
|
-
request_user_info: "open_id"
|
|
1610
|
-
});
|
|
1611
|
-
if (!res.device_code || !res.verification_uri_complete) {
|
|
1612
|
-
throw new Error(`\u98DE\u4E66\u6CE8\u518C\u5931\u8D25: \u672A\u8FD4\u56DE device_code
|
|
1613
|
-
${JSON.stringify(res)}`);
|
|
1614
|
-
}
|
|
1615
|
-
return {
|
|
1616
|
-
deviceCode: res.device_code,
|
|
1617
|
-
qrUrl: res.verification_uri_complete,
|
|
1618
|
-
userCode: res.user_code,
|
|
1619
|
-
interval: res.interval ?? DEFAULT_POLL_INTERVAL,
|
|
1620
|
-
expireIn: res.expire_in ?? 300
|
|
1621
|
-
};
|
|
1622
|
-
}
|
|
1623
|
-
async function pollRegistration(domain, deviceCode, interval, deadline, onLog, signal) {
|
|
1624
|
-
let currentInterval = interval;
|
|
1625
|
-
let currentDomain = domain;
|
|
1626
|
-
while (Date.now() < deadline) {
|
|
1627
|
-
if (signal?.aborted) return null;
|
|
1628
|
-
let res;
|
|
1629
|
-
try {
|
|
1630
|
-
res = await postRegistration(currentDomain, {
|
|
1631
|
-
action: "poll",
|
|
1632
|
-
device_code: deviceCode
|
|
1633
|
-
});
|
|
1634
|
-
} catch {
|
|
1635
|
-
await sleep(currentInterval * 1e3);
|
|
1636
|
-
continue;
|
|
1637
|
-
}
|
|
1638
|
-
if (res.user_info?.tenant_brand === "lark" && currentDomain === "feishu") {
|
|
1639
|
-
currentDomain = "lark";
|
|
1640
|
-
onLog?.("\u68C0\u6D4B\u5230 Lark \u8D26\u53F7\uFF0C\u5207\u6362\u57DF\u540D...");
|
|
1641
|
-
continue;
|
|
1642
|
-
}
|
|
1643
|
-
if (res.client_id && res.client_secret) {
|
|
1644
|
-
return {
|
|
1645
|
-
appId: res.client_id,
|
|
1646
|
-
appSecret: res.client_secret,
|
|
1647
|
-
openId: res.user_info?.open_id,
|
|
1648
|
-
domain: currentDomain
|
|
1649
|
-
};
|
|
1650
|
-
}
|
|
1651
|
-
if (res.error) {
|
|
1652
|
-
if (res.error === "authorization_pending") {
|
|
1653
|
-
} else if (res.error === "slow_down") {
|
|
1654
|
-
currentInterval += 5;
|
|
1655
|
-
} else if (res.error === "access_denied") {
|
|
1656
|
-
throw new Error("\u7528\u6237\u62D2\u7EDD\u4E86\u6388\u6743");
|
|
1657
|
-
} else if (res.error === "expired_token") {
|
|
1658
|
-
throw new Error("\u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F");
|
|
1659
|
-
} else {
|
|
1660
|
-
throw new Error(`\u98DE\u4E66\u6CE8\u518C\u9519\u8BEF: ${res.error} \u2014 ${res.error_description ?? ""}`);
|
|
1661
|
-
}
|
|
1662
|
-
}
|
|
1663
|
-
await sleep(currentInterval * 1e3);
|
|
1664
|
-
}
|
|
1665
|
-
return null;
|
|
1666
|
-
}
|
|
1667
|
-
async function registerFeishuApp(options = {}) {
|
|
1668
|
-
const domain = options.domain ?? "feishu";
|
|
1669
|
-
const timeoutSec = options.timeoutSec ?? 300;
|
|
1670
|
-
const log = options.onLog ?? (() => {
|
|
1671
|
-
});
|
|
1672
|
-
log("\u68C0\u67E5\u98DE\u4E66\u73AF\u5883...");
|
|
1673
|
-
await initRegistration(domain);
|
|
1674
|
-
log("\u751F\u6210\u4E8C\u7EF4\u7801...");
|
|
1675
|
-
const { deviceCode, qrUrl, interval, expireIn } = await beginRegistration(domain);
|
|
1676
|
-
options.onQrCode?.(qrUrl);
|
|
1677
|
-
log(`\u8BF7\u7528\u98DE\u4E66 App \u626B\u63CF\u4E8C\u7EF4\u7801\uFF08${expireIn}\u79D2\u540E\u8FC7\u671F\uFF09...`);
|
|
1678
|
-
const deadline = Date.now() + Math.min(expireIn, timeoutSec) * 1e3;
|
|
1679
|
-
const result = await pollRegistration(domain, deviceCode, interval, deadline, log, options.signal);
|
|
1680
|
-
if (result) {
|
|
1681
|
-
log(`\u2705 \u6CE8\u518C\u6210\u529F\uFF01App ID: ${result.appId}`);
|
|
1682
|
-
} else {
|
|
1683
|
-
log("\u23F0 \u4E8C\u7EF4\u7801\u5DF2\u8FC7\u671F");
|
|
1684
|
-
}
|
|
1685
|
-
return result;
|
|
1686
|
-
}
|
|
1687
|
-
function sleep(ms) {
|
|
1688
|
-
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
1689
|
-
}
|
|
1690
|
-
|
|
1691
|
-
// src/cli-init.ts
|
|
1692
|
-
init_wechat();
|
|
1693
|
-
|
|
1694
|
-
// src/qr-render.ts
|
|
1695
|
-
import { createRequire } from "node:module";
|
|
1696
|
-
var require2 = createRequire(import.meta.url);
|
|
1697
|
-
async function renderQrTerminal(url, options) {
|
|
1698
|
-
return new Promise((resolve2, reject) => {
|
|
1699
|
-
try {
|
|
1700
|
-
const qt = require2("qrcode-terminal");
|
|
1701
|
-
qt.generate(url, { small: options?.small ?? true }, (output) => {
|
|
1702
|
-
resolve2(output);
|
|
1703
|
-
});
|
|
1704
|
-
} catch (err) {
|
|
1705
|
-
reject(err);
|
|
1706
|
-
}
|
|
1707
|
-
});
|
|
1708
|
-
}
|
|
1709
|
-
|
|
1710
|
-
// src/cli-init.ts
|
|
1711
1745
|
var __filename = fileURLToPath(import.meta.url);
|
|
1712
1746
|
var __dirname = path3.dirname(__filename);
|
|
1713
1747
|
var SCHEMA_VERSION = 1;
|
|
@@ -1746,7 +1780,7 @@ Engine 7 \u2014 Self-hosted AI agent engine
|
|
|
1746
1780
|
|
|
1747
1781
|
\u7528\u6CD5:
|
|
1748
1782
|
engine7 init --state-dir <path> [\u9009\u9879] \u521D\u59CB\u5316 agent \u5DE5\u4F5C\u76EE\u5F55
|
|
1749
|
-
engine7
|
|
1783
|
+
engine7 reconfig <\u76EE\u6807> [\u9009\u9879] \u91CD\u65B0\u914D\u7F6E\u5DF2\u88C5\u7684 agent\uFF08wechat/feishu/discord/llm/channels\uFF09
|
|
1750
1784
|
engine7 start [--config <path>] \u542F\u52A8 Engine
|
|
1751
1785
|
engine7 restart [--config <path>] \u91CD\u542F Engine\uFF08\u6740\u65E7\u8FDB\u7A0B+\u542F\u52A8\uFF09
|
|
1752
1786
|
engine7 service install|uninstall|status \u5F00\u673A\u81EA\u542F\u52A8\u7BA1\u7406
|
|
@@ -1842,7 +1876,7 @@ async function interactiveConfig(rl, defaults) {
|
|
|
1842
1876
|
v.primaryProvider = providerMap[chosenProvider] || "dashscope";
|
|
1843
1877
|
v.zhipuPlan = "";
|
|
1844
1878
|
if (v.primaryProvider === "zhipu") {
|
|
1845
|
-
const planOptions = ["coding-plan (GLM Coding \u8BA2\u9605)", "
|
|
1879
|
+
const planOptions = ["coding-plan (GLM Coding \u8BA2\u9605\uFF0C\u5305\u6708)", "api-pay (API \u6309\u91CF\u4ED8\u8D39)"];
|
|
1846
1880
|
const chosenPlan = await askChoice(rl, "\u667A\u8C31\u8BA2\u9605\u7C7B\u578B:", planOptions, 0);
|
|
1847
1881
|
v.zhipuPlan = chosenPlan.startsWith("coding") ? "coding" : "token";
|
|
1848
1882
|
}
|
|
@@ -1856,7 +1890,7 @@ async function interactiveConfig(rl, defaults) {
|
|
|
1856
1890
|
const modelMap = {
|
|
1857
1891
|
dashscope: ["dashscope/qwen3.7-max", "dashscope/qwen3.7-plus"],
|
|
1858
1892
|
minimax: ["minimax/MiniMax-M3", "minimax/MiniMax-M2.7"],
|
|
1859
|
-
zhipu: ["zhipu/glm-5.
|
|
1893
|
+
zhipu: ["zhipu/glm-5.3", "zhipu/glm-5v-turbo"],
|
|
1860
1894
|
deepseek: ["deepseek/deepseek-v4-pro", "deepseek/deepseek-v4-flash"]
|
|
1861
1895
|
};
|
|
1862
1896
|
const models = modelMap[v.primaryProvider] || ["dashscope/qwen3.7-max"];
|
|
@@ -1866,7 +1900,7 @@ async function interactiveConfig(rl, defaults) {
|
|
|
1866
1900
|
"dashscope/qwen3.7-plus": true,
|
|
1867
1901
|
"minimax/MiniMax-M3": true,
|
|
1868
1902
|
"zhipu/glm-5v-turbo": true,
|
|
1869
|
-
"zhipu/glm-5.
|
|
1903
|
+
"zhipu/glm-5.3": false,
|
|
1870
1904
|
"deepseek/deepseek-v4-pro": false,
|
|
1871
1905
|
"deepseek/deepseek-v4-flash": false
|
|
1872
1906
|
};
|
|
@@ -2089,8 +2123,8 @@ function generateConfig(v) {
|
|
|
2089
2123
|
baseUrl: "https://open.bigmodel.cn/api/coding/paas/v4",
|
|
2090
2124
|
api: "openai-completions",
|
|
2091
2125
|
models: [
|
|
2092
|
-
{ id: "glm-5.
|
|
2093
|
-
{ id: "glm-5v-turbo", name: "GLM-5V-Turbo", reasoning: true, input: ["text", "image"], contextWindow: 2e5, maxTokens: 128e3 }
|
|
2126
|
+
{ id: "glm-5.3", name: "GLM-5.3 (\u6700\u65B0\u4E3B\u529B)", reasoning: true, input: ["text"], contextWindow: 204800, maxTokens: 131072 },
|
|
2127
|
+
{ id: "glm-5v-turbo", name: "GLM-5V-Turbo (\u89C6\u89C9)", reasoning: true, input: ["text", "image"], contextWindow: 2e5, maxTokens: 128e3 }
|
|
2094
2128
|
]
|
|
2095
2129
|
},
|
|
2096
2130
|
deepseek: {
|
|
@@ -2110,7 +2144,8 @@ function generateConfig(v) {
|
|
|
2110
2144
|
}
|
|
2111
2145
|
config.models.providers[v.primaryProvider] = {
|
|
2112
2146
|
...def,
|
|
2113
|
-
apiKey: v.primaryApiKey
|
|
2147
|
+
apiKey: v.primaryApiKey.trim(),
|
|
2148
|
+
...def.baseUrl ? { baseUrl: def.baseUrl.trim() } : {}
|
|
2114
2149
|
};
|
|
2115
2150
|
}
|
|
2116
2151
|
return config;
|
|
@@ -2272,15 +2307,115 @@ async function main() {
|
|
|
2272
2307
|
printHelp();
|
|
2273
2308
|
process.exit(0);
|
|
2274
2309
|
}
|
|
2275
|
-
if (subcommand === "addchannel") {
|
|
2276
|
-
const
|
|
2310
|
+
if (subcommand === "reconfig" || subcommand === "addchannel") {
|
|
2311
|
+
const isLegacyAddchannel = subcommand === "addchannel";
|
|
2312
|
+
let target = args[1] || "";
|
|
2313
|
+
if (isLegacyAddchannel) target = target || "wechat";
|
|
2314
|
+
const channel = target;
|
|
2277
2315
|
let stateDir = "";
|
|
2278
2316
|
let configName = "";
|
|
2279
2317
|
for (let i = 1; i < args.length; i++) {
|
|
2280
|
-
if (args[i] === "--state-dir" && args[i + 1]) stateDir = args[++i];
|
|
2281
|
-
else if (args[i] === "--config" && args[i + 1]) configName = args[++i];
|
|
2318
|
+
if (args[i] === "--state-dir" && args[i + 1]) stateDir = args[++i].trim();
|
|
2319
|
+
else if (args[i] === "--config" && args[i + 1]) configName = args[++i].trim();
|
|
2282
2320
|
}
|
|
2283
2321
|
if (!stateDir) stateDir = path3.resolve(process.cwd());
|
|
2322
|
+
if (!target && !isLegacyAddchannel) {
|
|
2323
|
+
console.log("\u{1F527} engine7 reconfig \u2014 \u91CD\u65B0\u914D\u7F6E\u5DF2\u88C5\u7684 agent");
|
|
2324
|
+
console.log(" \u7528\u6CD5: engine7 reconfig <\u76EE\u6807>");
|
|
2325
|
+
console.log("");
|
|
2326
|
+
console.log(" \u901A\u9053\u7C7B:");
|
|
2327
|
+
console.log(" wechat \u5FAE\u4FE1\u626B\u7801\u63A5\u5165\uFF08iLink\uFF0C1v1 \u79C1\u804A\uFF09");
|
|
2328
|
+
console.log(" feishu \u98DE\u4E66\u626B\u7801\u63A5\u5165\uFF08OAuth\uFF0C30\u79D2\uFF09");
|
|
2329
|
+
console.log(" discord Discord bot \u914D\u7F6E");
|
|
2330
|
+
console.log(" \u6A21\u578B\u7C7B:");
|
|
2331
|
+
console.log(" llm \u66F4\u6362 LLM provider / API key / \u7AEF\u70B9");
|
|
2332
|
+
console.log(" \u5176\u4ED6:");
|
|
2333
|
+
console.log(" channels \u67E5\u770B\u5F53\u524D\u901A\u9053\u72B6\u6001");
|
|
2334
|
+
console.log("");
|
|
2335
|
+
console.log(" \u9009\u9879: --state-dir <path> --config <file>");
|
|
2336
|
+
process.exit(0);
|
|
2337
|
+
}
|
|
2338
|
+
if (channel === "channels") {
|
|
2339
|
+
const configsDir = path3.join(stateDir, "configs");
|
|
2340
|
+
if (fs3.existsSync(configsDir)) {
|
|
2341
|
+
const files = fs3.readdirSync(configsDir).filter((f) => f.endsWith(".json"));
|
|
2342
|
+
for (const f of files) {
|
|
2343
|
+
try {
|
|
2344
|
+
const j = JSON.parse(fs3.readFileSync(path3.join(configsDir, f), "utf8"));
|
|
2345
|
+
if (!j.channels) continue;
|
|
2346
|
+
console.log(`
|
|
2347
|
+
\u{1F4C4} ${f}:`);
|
|
2348
|
+
for (const [name, conf] of Object.entries(j.channels)) {
|
|
2349
|
+
const c = conf;
|
|
2350
|
+
console.log(` ${c.enabled ? "\u2705" : "\u26D4"} ${name}${c.appId ? " (" + c.appId + ")" : ""}${c.accountId ? " (" + c.accountId + ")" : ""}`);
|
|
2351
|
+
}
|
|
2352
|
+
} catch {
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
} else {
|
|
2356
|
+
console.log(`\u26A0\uFE0F \u672A\u627E\u5230 configs \u76EE\u5F55: ${configsDir}`);
|
|
2357
|
+
}
|
|
2358
|
+
process.exit(0);
|
|
2359
|
+
}
|
|
2360
|
+
if (channel === "llm") {
|
|
2361
|
+
console.log("\u{1F527} LLM \u91CD\u914D\uFF08\u5F00\u53D1\u4E2D\uFF0Cv7.2 \u8BA1\u5212\uFF09");
|
|
2362
|
+
console.log(" \u76EE\u524D\u8BF7\u624B\u52A8\u6539 config \u7684 models.providers \u6BB5");
|
|
2363
|
+
process.exit(0);
|
|
2364
|
+
}
|
|
2365
|
+
if (channel === "discord") {
|
|
2366
|
+
console.log("\u{1F527} Discord \u91CD\u914D\uFF08\u5F00\u53D1\u4E2D\uFF09");
|
|
2367
|
+
console.log(" \u76EE\u524D\u8BF7\u624B\u52A8\u6539 config \u7684 channels.discord \u6BB5\uFF08token/userId\uFF09");
|
|
2368
|
+
process.exit(0);
|
|
2369
|
+
}
|
|
2370
|
+
if (channel === "feishu") {
|
|
2371
|
+
console.log("\u{1F527} \u98DE\u4E66\u626B\u7801\u63A5\u5165...");
|
|
2372
|
+
const { registerFeishuApp: registerFeishuApp2 } = await Promise.resolve().then(() => (init_feishu_quick_register(), feishu_quick_register_exports));
|
|
2373
|
+
const { renderQrTerminal: renderQrTerminal2 } = await Promise.resolve().then(() => (init_qr_render(), qr_render_exports));
|
|
2374
|
+
const result = await registerFeishuApp2({
|
|
2375
|
+
onLog: (msg) => console.log(` ${msg}`),
|
|
2376
|
+
onQrCode: async (url) => {
|
|
2377
|
+
try {
|
|
2378
|
+
console.log(await renderQrTerminal2(url, { small: true }));
|
|
2379
|
+
} catch {
|
|
2380
|
+
console.log(`
|
|
2381
|
+
\u6D4F\u89C8\u5668\u6253\u5F00\u626B\u7801: ${url}
|
|
2382
|
+
`);
|
|
2383
|
+
}
|
|
2384
|
+
}
|
|
2385
|
+
});
|
|
2386
|
+
if (!result) {
|
|
2387
|
+
console.error("\u274C \u626B\u7801\u8D85\u65F6\u6216\u5931\u8D25");
|
|
2388
|
+
process.exit(1);
|
|
2389
|
+
}
|
|
2390
|
+
const configsDir2 = path3.join(stateDir, "configs");
|
|
2391
|
+
let configFile2 = configName ? path3.join(configsDir2, configName) : "";
|
|
2392
|
+
if (!configFile2 || !fs3.existsSync(configFile2)) {
|
|
2393
|
+
if (fs3.existsSync(configsDir2)) {
|
|
2394
|
+
for (const f of fs3.readdirSync(configsDir2).filter((f2) => f2.endsWith(".json"))) {
|
|
2395
|
+
const full = path3.join(configsDir2, f);
|
|
2396
|
+
try {
|
|
2397
|
+
if (JSON.parse(fs3.readFileSync(full, "utf8")).channels) {
|
|
2398
|
+
configFile2 = full;
|
|
2399
|
+
break;
|
|
2400
|
+
}
|
|
2401
|
+
} catch {
|
|
2402
|
+
}
|
|
2403
|
+
}
|
|
2404
|
+
}
|
|
2405
|
+
}
|
|
2406
|
+
if (configFile2 && fs3.existsSync(configFile2)) {
|
|
2407
|
+
const j = JSON.parse(fs3.readFileSync(configFile2, "utf8"));
|
|
2408
|
+
j.channels = j.channels || {};
|
|
2409
|
+
j.channels.feishu = { enabled: true, appId: result.appId, appSecret: result.appSecret, connectionMode: "websocket", dmPolicy: "pairing", groupPolicy: "open" };
|
|
2410
|
+
fs3.writeFileSync(configFile2, JSON.stringify(j, null, 2), "utf8");
|
|
2411
|
+
console.log("\u2705 \u98DE\u4E66\u901A\u9053\u5DF2\u5199\u5165: " + configFile2);
|
|
2412
|
+
console.log("\u91CD\u542F\u751F\u6548: engine7 restart");
|
|
2413
|
+
} else {
|
|
2414
|
+
console.log("\u26A0\uFE0F \u6CA1\u627E\u5230 config\uFF0C\u624B\u52A8\u52A0\uFF1A");
|
|
2415
|
+
console.log(JSON.stringify({ feishu: { enabled: true, appId: result.appId, appSecret: result.appSecret, connectionMode: "websocket", dmPolicy: "pairing", groupPolicy: "open" } }, null, 2));
|
|
2416
|
+
}
|
|
2417
|
+
process.exit(0);
|
|
2418
|
+
}
|
|
2284
2419
|
if (channel === "wechat") {
|
|
2285
2420
|
console.log("\u{1F4F1} \u5FAE\u4FE1\u626B\u7801\u63A5\u5165\uFF08iLink \u4E2A\u4EBA\u5FAE\u4FE1\uFF0C1v1 \u79C1\u804A\uFF09");
|
|
2286
2421
|
console.log(" \u63D0\u793A\uFF1A\u4E00\u4E2A\u5FAE\u4FE1\u53F7\u53EA\u80FD\u7ED1\u4E00\u4E2A bot\uFF1Bbot \u4E0D\u8FDB\u7FA4\uFF08\u817E\u8BAF\u9650\u5236\uFF09\n");
|
|
@@ -2330,8 +2465,8 @@ async function main() {
|
|
|
2330
2465
|
console.log("\n\u91CD\u542F engine \u751F\u6548: engine7 restart");
|
|
2331
2466
|
process.exit(0);
|
|
2332
2467
|
}
|
|
2333
|
-
console.error(`\u672A\u77E5\
|
|
2334
|
-
console.error("\u7528\u6CD5: engine7
|
|
2468
|
+
console.error(`\u672A\u77E5\u76EE\u6807: ${channel || "(\u7A7A)"}\u3002\u652F\u6301: wechat / feishu / discord / llm / channels`);
|
|
2469
|
+
console.error("\u7528\u6CD5: engine7 reconfig <\u76EE\u6807> [--state-dir <path>] [--config <file>]");
|
|
2335
2470
|
process.exit(1);
|
|
2336
2471
|
}
|
|
2337
2472
|
if (subcommand === "export") {
|
package/dist/engine-startup.mjs
CHANGED
|
@@ -2226,9 +2226,19 @@ var init_compact2 = __esm({
|
|
|
2226
2226
|
// src/config/live.ts
|
|
2227
2227
|
var live_exports = {};
|
|
2228
2228
|
__export(live_exports, {
|
|
2229
|
-
|
|
2229
|
+
consumeSelfWrite: () => consumeSelfWrite,
|
|
2230
|
+
liveConfig: () => liveConfig,
|
|
2231
|
+
markSelfWrite: () => markSelfWrite
|
|
2230
2232
|
});
|
|
2231
|
-
|
|
2233
|
+
function markSelfWrite() {
|
|
2234
|
+
selfWrite.pending = true;
|
|
2235
|
+
}
|
|
2236
|
+
function consumeSelfWrite() {
|
|
2237
|
+
const was = selfWrite.pending;
|
|
2238
|
+
selfWrite.pending = false;
|
|
2239
|
+
return was;
|
|
2240
|
+
}
|
|
2241
|
+
var LiveConfigClass, liveConfig, selfWrite;
|
|
2232
2242
|
var init_live = __esm({
|
|
2233
2243
|
"src/config/live.ts"() {
|
|
2234
2244
|
"use strict";
|
|
@@ -2289,6 +2299,7 @@ var init_live = __esm({
|
|
|
2289
2299
|
o[keys[keys.length - 1]] = val;
|
|
2290
2300
|
fs48.writeFileSync(cfgPath, JSON.stringify(raw, null, 2) + "\n", "utf-8");
|
|
2291
2301
|
console.log(`[liveConfig] persisted ${dotPath} = ${JSON.stringify(val)} to ${cfgPath}`);
|
|
2302
|
+
markSelfWrite();
|
|
2292
2303
|
} catch (e) {
|
|
2293
2304
|
console.warn(`[liveConfig] persist failed (${dotPath}): ${e.message}`);
|
|
2294
2305
|
}
|
|
@@ -2299,6 +2310,7 @@ var init_live = __esm({
|
|
|
2299
2310
|
}
|
|
2300
2311
|
};
|
|
2301
2312
|
liveConfig = new LiveConfigClass();
|
|
2313
|
+
selfWrite = { pending: false };
|
|
2302
2314
|
}
|
|
2303
2315
|
});
|
|
2304
2316
|
|
|
@@ -31890,6 +31902,7 @@ function createMemorySideProvider(sideConfig, mainProvider, providers) {
|
|
|
31890
31902
|
console.log(`[memory] Side provider: ${sideConfig.provider}/${sideConfig.model} (thinking=${sideConfig.thinking || "default"})`);
|
|
31891
31903
|
return { provider: sideProvider, model: sideConfig.model, disableThinking };
|
|
31892
31904
|
}
|
|
31905
|
+
var lastLoadedConfigRaw = null;
|
|
31893
31906
|
async function doReloadConfig(config, deps, provider) {
|
|
31894
31907
|
try {
|
|
31895
31908
|
const savedConfigPath = config._configFilePath;
|
|
@@ -31904,7 +31917,17 @@ async function doReloadConfig(config, deps, provider) {
|
|
|
31904
31917
|
reloadConfigPath = altPath;
|
|
31905
31918
|
}
|
|
31906
31919
|
}
|
|
31920
|
+
let configRaw = "";
|
|
31921
|
+
try {
|
|
31922
|
+
configRaw = fs47.readFileSync(reloadConfigPath, "utf-8");
|
|
31923
|
+
} catch {
|
|
31924
|
+
}
|
|
31925
|
+
if (lastLoadedConfigRaw !== null && configRaw.trim() === lastLoadedConfigRaw) {
|
|
31926
|
+
console.log(`[reload] config content unchanged, skipping reload`);
|
|
31927
|
+
return { ok: true, changes: ["unchanged (skipped)"] };
|
|
31928
|
+
}
|
|
31907
31929
|
const newConfig = loadConfig(reloadConfigPath);
|
|
31930
|
+
lastLoadedConfigRaw = configRaw.trim();
|
|
31908
31931
|
const changes = [];
|
|
31909
31932
|
const oldProviderKey = JSON.stringify({
|
|
31910
31933
|
providers: config.providers,
|
|
@@ -32055,9 +32078,22 @@ function startConfigWatcher(config, deps, provider) {
|
|
|
32055
32078
|
return null;
|
|
32056
32079
|
}
|
|
32057
32080
|
let debounceTimer = null;
|
|
32081
|
+
try {
|
|
32082
|
+
lastLoadedConfigRaw = fs47.readFileSync(configPath, "utf-8").trim();
|
|
32083
|
+
} catch {
|
|
32084
|
+
}
|
|
32058
32085
|
const watcher = fs47.watch(configPath, { persistent: true }, (eventType) => {
|
|
32059
32086
|
if (debounceTimer) clearTimeout(debounceTimer);
|
|
32060
32087
|
debounceTimer = setTimeout(async () => {
|
|
32088
|
+
if (consumeSelfWrite()) {
|
|
32089
|
+
console.log(`[config-watch] self-write (liveConfig.set, memory already synced), skipping reload`);
|
|
32090
|
+
try {
|
|
32091
|
+
fs47.appendFileSync(path49.join(config.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] SELF-WRITE SKIP (liveConfig.set, memory synced)
|
|
32092
|
+
`);
|
|
32093
|
+
} catch {
|
|
32094
|
+
}
|
|
32095
|
+
return;
|
|
32096
|
+
}
|
|
32061
32097
|
console.log(`[config-watch] file changed (${eventType}), reloading...`);
|
|
32062
32098
|
try {
|
|
32063
32099
|
fs47.appendFileSync(path49.join(config.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] CHANGE eventType=${eventType}, calling doReloadConfig
|
package/dist/main.mjs
CHANGED
|
@@ -34,9 +34,19 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
34
34
|
// src/config/live.ts
|
|
35
35
|
var live_exports = {};
|
|
36
36
|
__export(live_exports, {
|
|
37
|
-
|
|
37
|
+
consumeSelfWrite: () => consumeSelfWrite,
|
|
38
|
+
liveConfig: () => liveConfig,
|
|
39
|
+
markSelfWrite: () => markSelfWrite
|
|
38
40
|
});
|
|
39
|
-
|
|
41
|
+
function markSelfWrite() {
|
|
42
|
+
selfWrite.pending = true;
|
|
43
|
+
}
|
|
44
|
+
function consumeSelfWrite() {
|
|
45
|
+
const was = selfWrite.pending;
|
|
46
|
+
selfWrite.pending = false;
|
|
47
|
+
return was;
|
|
48
|
+
}
|
|
49
|
+
var LiveConfigClass, liveConfig, selfWrite;
|
|
40
50
|
var init_live = __esm({
|
|
41
51
|
"src/config/live.ts"() {
|
|
42
52
|
"use strict";
|
|
@@ -97,6 +107,7 @@ var init_live = __esm({
|
|
|
97
107
|
o[keys[keys.length - 1]] = val;
|
|
98
108
|
fs48.writeFileSync(cfgPath, JSON.stringify(raw, null, 2) + "\n", "utf-8");
|
|
99
109
|
console.log(`[liveConfig] persisted ${dotPath} = ${JSON.stringify(val)} to ${cfgPath}`);
|
|
110
|
+
markSelfWrite();
|
|
100
111
|
} catch (e) {
|
|
101
112
|
console.warn(`[liveConfig] persist failed (${dotPath}): ${e.message}`);
|
|
102
113
|
}
|
|
@@ -107,6 +118,7 @@ var init_live = __esm({
|
|
|
107
118
|
}
|
|
108
119
|
};
|
|
109
120
|
liveConfig = new LiveConfigClass();
|
|
121
|
+
selfWrite = { pending: false };
|
|
110
122
|
}
|
|
111
123
|
});
|
|
112
124
|
|
|
@@ -31974,6 +31986,7 @@ function createMemorySideProvider(sideConfig, mainProvider, providers) {
|
|
|
31974
31986
|
console.log(`[memory] Side provider: ${sideConfig.provider}/${sideConfig.model} (thinking=${sideConfig.thinking || "default"})`);
|
|
31975
31987
|
return { provider: sideProvider, model: sideConfig.model, disableThinking };
|
|
31976
31988
|
}
|
|
31989
|
+
var lastLoadedConfigRaw = null;
|
|
31977
31990
|
async function doReloadConfig(config2, deps, provider) {
|
|
31978
31991
|
try {
|
|
31979
31992
|
const savedConfigPath = config2._configFilePath;
|
|
@@ -31988,7 +32001,17 @@ async function doReloadConfig(config2, deps, provider) {
|
|
|
31988
32001
|
reloadConfigPath = altPath;
|
|
31989
32002
|
}
|
|
31990
32003
|
}
|
|
32004
|
+
let configRaw = "";
|
|
32005
|
+
try {
|
|
32006
|
+
configRaw = fs47.readFileSync(reloadConfigPath, "utf-8");
|
|
32007
|
+
} catch {
|
|
32008
|
+
}
|
|
32009
|
+
if (lastLoadedConfigRaw !== null && configRaw.trim() === lastLoadedConfigRaw) {
|
|
32010
|
+
console.log(`[reload] config content unchanged, skipping reload`);
|
|
32011
|
+
return { ok: true, changes: ["unchanged (skipped)"] };
|
|
32012
|
+
}
|
|
31991
32013
|
const newConfig = loadConfig(reloadConfigPath);
|
|
32014
|
+
lastLoadedConfigRaw = configRaw.trim();
|
|
31992
32015
|
const changes = [];
|
|
31993
32016
|
const oldProviderKey = JSON.stringify({
|
|
31994
32017
|
providers: config2.providers,
|
|
@@ -32139,9 +32162,22 @@ function startConfigWatcher(config2, deps, provider) {
|
|
|
32139
32162
|
return null;
|
|
32140
32163
|
}
|
|
32141
32164
|
let debounceTimer = null;
|
|
32165
|
+
try {
|
|
32166
|
+
lastLoadedConfigRaw = fs47.readFileSync(configPath2, "utf-8").trim();
|
|
32167
|
+
} catch {
|
|
32168
|
+
}
|
|
32142
32169
|
const watcher = fs47.watch(configPath2, { persistent: true }, (eventType) => {
|
|
32143
32170
|
if (debounceTimer) clearTimeout(debounceTimer);
|
|
32144
32171
|
debounceTimer = setTimeout(async () => {
|
|
32172
|
+
if (consumeSelfWrite()) {
|
|
32173
|
+
console.log(`[config-watch] self-write (liveConfig.set, memory already synced), skipping reload`);
|
|
32174
|
+
try {
|
|
32175
|
+
fs47.appendFileSync(path49.join(config2.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] SELF-WRITE SKIP (liveConfig.set, memory synced)
|
|
32176
|
+
`);
|
|
32177
|
+
} catch {
|
|
32178
|
+
}
|
|
32179
|
+
return;
|
|
32180
|
+
}
|
|
32145
32181
|
console.log(`[config-watch] file changed (${eventType}), reloading...`);
|
|
32146
32182
|
try {
|
|
32147
32183
|
fs47.appendFileSync(path49.join(config2.stateDir, "logs", "engine-config-watch.log"), `[${(/* @__PURE__ */ new Date()).toISOString()}] CHANGE eventType=${eventType}, calling doReloadConfig
|