chaimi-bookkeeping-mcp 3.1.13 → 3.1.15
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/bin/cli.js +4 -1
- package/package.json +1 -1
- package/server.js +53 -45
package/bin/cli.js
CHANGED
|
@@ -25,7 +25,10 @@ const DEFAULT_CHAIMI_CONFIG = {
|
|
|
25
25
|
MCP_OAUTH_URL: 'https://cloud1-2gfe5jhjef06b85d-1412172089.ap-shanghai.app.tcloudbase.com/mcpOAuth',
|
|
26
26
|
MCP_HUB_URL: 'https://cloud1-2gfe5jhjef06b85d-1412172089.ap-shanghai.app.tcloudbase.com/mcpHub-mcp',
|
|
27
27
|
MCP_PROMPT_URL: 'https://cloud1-2gfe5jhjef06b85d-1412172089.ap-shanghai.app.tcloudbase.com/mcpPrompt'
|
|
28
|
-
}
|
|
28
|
+
},
|
|
29
|
+
// 首次授权时需要常驻运行,等待用户授权(3分钟轮询)
|
|
30
|
+
// 授权成功后进程自动退出,下次调用时 mcporter 会重新启动
|
|
31
|
+
lifecycle: 'keep-alive'
|
|
29
32
|
};
|
|
30
33
|
|
|
31
34
|
// 支持的 Agent 列表
|
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -241,7 +241,7 @@ let lastRefreshTime = 0;
|
|
|
241
241
|
async function getToken() {
|
|
242
242
|
// 检查是否已授权
|
|
243
243
|
if (!authState.isAuthorized) {
|
|
244
|
-
//
|
|
244
|
+
// 先检查是否有保存的授权状态(从文件加载)
|
|
245
245
|
const savedAuthState = await oauthManager.loadAuthState();
|
|
246
246
|
if (savedAuthState && savedAuthState.deviceCode) {
|
|
247
247
|
// 有保存的授权状态,尝试直接获取token(用户可能已授权)
|
|
@@ -252,38 +252,28 @@ async function getToken() {
|
|
|
252
252
|
cachedToken = token.accessToken;
|
|
253
253
|
tokenExpireTime = token.expiresAt;
|
|
254
254
|
authState.isAuthorized = true;
|
|
255
|
-
|
|
255
|
+
await oauthManager.tokenStorage.save(token);
|
|
256
256
|
await oauthManager.clearAuthState();
|
|
257
257
|
console.error('✅ 授权成功!可以继续使用记账功能');
|
|
258
258
|
return cachedToken;
|
|
259
259
|
}
|
|
260
|
+
// 用户还未授权,返回同一个验证码
|
|
261
|
+
authState.deviceCode = savedAuthState.deviceCode;
|
|
262
|
+
authState.userCode = savedAuthState.userCode;
|
|
263
|
+
throw new Error(`NEED_AUTH:${savedAuthState.userCode}`);
|
|
260
264
|
} catch (err) {
|
|
261
|
-
|
|
265
|
+
if (err.message.startsWith('NEED_AUTH:')) {
|
|
266
|
+
throw err;
|
|
267
|
+
}
|
|
268
|
+
// 其他错误,继续获取新的验证码
|
|
262
269
|
console.error('⚠️ 检查授权状态失败:', err.message);
|
|
263
270
|
}
|
|
264
271
|
}
|
|
265
272
|
|
|
266
|
-
//
|
|
267
|
-
|
|
268
|
-
await startBackgroundAuth();
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// 等待一段时间,让后台轮询有机会完成授权
|
|
272
|
-
// 最多等待10秒,每500ms检查一次
|
|
273
|
-
let waitAttempts = 0;
|
|
274
|
-
const maxWaitAttempts = 20; // 10秒
|
|
273
|
+
// 没有保存的授权状态,启动新的授权流程
|
|
274
|
+
await startAuthFlow();
|
|
275
275
|
|
|
276
|
-
|
|
277
|
-
await delay(500);
|
|
278
|
-
waitAttempts++;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// 再次检查是否已授权
|
|
282
|
-
if (authState.isAuthorized) {
|
|
283
|
-
return cachedToken;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// 仍未授权,返回验证码给Agent
|
|
276
|
+
// 返回验证码给Agent
|
|
287
277
|
throw new Error(`NEED_AUTH:${authState.userCode || '等待生成验证码'}`);
|
|
288
278
|
}
|
|
289
279
|
|
|
@@ -805,22 +795,29 @@ async function checkAuthInBackground() {
|
|
|
805
795
|
}
|
|
806
796
|
}
|
|
807
797
|
|
|
808
|
-
//
|
|
809
|
-
async function
|
|
810
|
-
if (authState.isWaiting) {
|
|
811
|
-
return; // 已经在等待授权
|
|
812
|
-
}
|
|
813
|
-
|
|
798
|
+
// 启动授权流程(获取验证码,启动后台轮询)
|
|
799
|
+
async function startAuthFlow() {
|
|
814
800
|
try {
|
|
815
|
-
|
|
816
|
-
|
|
801
|
+
// 先检查是否有保存的授权状态
|
|
802
|
+
const savedAuthState = await oauthManager.loadAuthState();
|
|
803
|
+
if (savedAuthState && savedAuthState.userCode) {
|
|
804
|
+
// 有保存的验证码,直接使用
|
|
805
|
+
authState.deviceCode = savedAuthState.deviceCode;
|
|
806
|
+
authState.userCode = savedAuthState.userCode;
|
|
807
|
+
authState.isWaiting = true;
|
|
808
|
+
console.error(`🔑 使用已保存的验证码:${savedAuthState.userCode}`);
|
|
809
|
+
// 启动后台轮询
|
|
810
|
+
pollForAuthInBackground(savedAuthState.deviceCode, 5000);
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
817
813
|
|
|
818
|
-
//
|
|
814
|
+
// 获取新的设备码
|
|
819
815
|
const deviceCodeRes = await oauthManager.requestDeviceCode(false);
|
|
820
816
|
authState.deviceCode = deviceCodeRes.deviceCode;
|
|
821
817
|
authState.userCode = deviceCodeRes.userCode;
|
|
818
|
+
authState.isWaiting = true;
|
|
822
819
|
|
|
823
|
-
//
|
|
820
|
+
// 保存授权状态(30分钟有效)
|
|
824
821
|
await oauthManager.saveAuthState({
|
|
825
822
|
deviceCode: deviceCodeRes.deviceCode,
|
|
826
823
|
userCode: deviceCodeRes.userCode,
|
|
@@ -828,10 +825,10 @@ async function startBackgroundAuth() {
|
|
|
828
825
|
});
|
|
829
826
|
|
|
830
827
|
console.error(`🔑 验证码:${deviceCodeRes.userCode}`);
|
|
831
|
-
console.error('⏳
|
|
832
|
-
|
|
833
|
-
//
|
|
834
|
-
pollForAuthInBackground(deviceCodeRes.deviceCode,
|
|
828
|
+
console.error('⏳ 请在小程序中完成授权,然后再次调用');
|
|
829
|
+
|
|
830
|
+
// 启动后台轮询(3分钟)
|
|
831
|
+
pollForAuthInBackground(deviceCodeRes.deviceCode, 5000);
|
|
835
832
|
|
|
836
833
|
} catch (err) {
|
|
837
834
|
authState.error = err.message;
|
|
@@ -840,42 +837,53 @@ async function startBackgroundAuth() {
|
|
|
840
837
|
}
|
|
841
838
|
}
|
|
842
839
|
|
|
843
|
-
//
|
|
840
|
+
// 后台轮询授权状态(3分钟)
|
|
844
841
|
async function pollForAuthInBackground(deviceCode, interval) {
|
|
845
|
-
const maxAttempts =
|
|
842
|
+
const maxAttempts = 36; // 3分钟(36次 × 5秒)
|
|
846
843
|
let attempts = 0;
|
|
847
844
|
|
|
845
|
+
console.error('⏳ 等待用户授权中...(3分钟内有效)');
|
|
846
|
+
|
|
848
847
|
while (attempts < maxAttempts && authState.isWaiting) {
|
|
849
848
|
attempts++;
|
|
850
849
|
await delay(interval);
|
|
851
850
|
|
|
852
851
|
try {
|
|
852
|
+
// 调用云函数检查授权状态
|
|
853
853
|
const token = await oauthManager.pollForTokenOnce(deviceCode);
|
|
854
|
+
|
|
854
855
|
if (token) {
|
|
855
856
|
// 授权成功
|
|
856
857
|
cachedToken = token.accessToken;
|
|
857
858
|
tokenExpireTime = token.expiresAt;
|
|
858
859
|
authState.isAuthorized = true;
|
|
859
860
|
authState.isWaiting = false;
|
|
860
|
-
|
|
861
|
+
|
|
862
|
+
// 保存token到文件
|
|
863
|
+
await oauthManager.tokenStorage.save(token);
|
|
864
|
+
// 清除授权状态
|
|
861
865
|
await oauthManager.clearAuthState();
|
|
862
|
-
|
|
863
|
-
|
|
866
|
+
|
|
867
|
+
console.error('✅ 授权成功!下次调用将快速启动');
|
|
868
|
+
|
|
869
|
+
// 主动退出进程,让 mcporter 下次重新启动
|
|
870
|
+
process.exit(0);
|
|
864
871
|
}
|
|
865
872
|
} catch (err) {
|
|
866
873
|
if (err.message.includes('expired') || err.message.includes('invalid')) {
|
|
867
874
|
authState.error = err.message;
|
|
868
875
|
authState.isWaiting = false;
|
|
869
876
|
console.error('❌ 授权失败:', err.message);
|
|
870
|
-
|
|
877
|
+
process.exit(1);
|
|
871
878
|
}
|
|
872
879
|
// 继续轮询
|
|
873
880
|
}
|
|
874
881
|
}
|
|
875
882
|
|
|
876
|
-
//
|
|
883
|
+
// 3分钟超时
|
|
877
884
|
authState.isWaiting = false;
|
|
878
|
-
console.error('
|
|
885
|
+
console.error('⏰ 授权超时,请再次调用获取新验证码');
|
|
886
|
+
process.exit(0);
|
|
879
887
|
}
|
|
880
888
|
|
|
881
889
|
// 延迟函数
|