@kafca/agentdock 0.1.22 → 0.1.24
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 +4 -0
- package/dist/renderer/assets/{Badge-B_rgzxYO.js → Badge-CXcUMqb-.js} +1 -1
- package/dist/renderer/assets/{Chat-CYtp6m7T.js → Chat-BRxdPzi-.js} +1 -1
- package/dist/renderer/assets/{ChatMarkdown-DOBMwa9d.js → ChatMarkdown-sWGBIfIb.js} +1 -1
- package/dist/renderer/assets/{Config-DppMSPHF.js → Config-DqxuxIGg.js} +1 -1
- package/dist/renderer/assets/{CronList-BDtB1SuA.js → CronList-OgHxbti5.js} +1 -1
- package/dist/renderer/assets/{Dashboard-iFlRnd7Y.js → Dashboard-DmklXiH1.js} +2 -2
- package/dist/renderer/assets/{EmptyState-bKDt_T88.js → EmptyState-BvDmi8dq.js} +1 -1
- package/dist/renderer/assets/{KnowledgeDetail-CKPhKPIg.js → KnowledgeDetail-Bj59Hdpo.js} +2 -2
- package/dist/renderer/assets/{KnowledgeHome-CFeJre6i.js → KnowledgeHome-CigQ-nSo.js} +3 -3
- package/dist/renderer/assets/{Logs-CyxSVOFK.js → Logs-Bfc7gBpY.js} +1 -1
- package/dist/renderer/assets/{Modal-CxPnk1Ey.js → Modal-CfmiFknz.js} +1 -1
- package/dist/renderer/assets/{Page-kU9vubzj.js → Page-BxtLEw_b.js} +1 -1
- package/dist/renderer/assets/{ProjectDetail-D9FY9NWZ.js → ProjectDetail-CcUphxGm.js} +1 -1
- package/dist/renderer/assets/{ProjectList-DIwr2TXg.js → ProjectList-CVkvDIfy.js} +1 -1
- package/dist/renderer/assets/{Select-BaWoz5Dn.js → Select-DgQMZ0MD.js} +1 -1
- package/dist/renderer/assets/{SessionChat-Cm9CW8Zx.js → SessionChat-CRmGKfBx.js} +1 -1
- package/dist/renderer/assets/{SessionList-UPnWlXXO.js → SessionList-D0E8XbYw.js} +1 -1
- package/dist/renderer/assets/ThreadChat-DUgqZSBB.js +23 -0
- package/dist/renderer/assets/Workspace-Q4g4rlRT.js +14 -0
- package/dist/renderer/assets/{arrow-left-BmZAVGV7.js → arrow-left-BySN_zhF.js} +1 -1
- package/dist/renderer/assets/{book-open-DZ3GXFgI.js → book-open-BGlrnrTc.js} +1 -1
- package/dist/renderer/assets/{check-CeVSvDCv.js → check-BiJogEa5.js} +1 -1
- package/dist/renderer/assets/{chevron-down-yryuMoQ-.js → chevron-down-D2fHRJv6.js} +1 -1
- package/dist/renderer/assets/{circle-eASsFISH.js → circle-CIcjixmI.js} +1 -1
- package/dist/renderer/assets/desktop-DAXY9Bxv.js +4 -0
- package/dist/renderer/assets/desktop-DyA_NYew.js +1 -0
- package/dist/renderer/assets/{funnel-pwAe2Ixp.js → funnel-BUzwb-id.js} +1 -1
- package/dist/renderer/assets/{heart-B2Sp-bCm.js → heart-DZEQ1z_V.js} +1 -1
- package/dist/renderer/assets/{index-BC3MWbS1.js → index-CB_KyLOr.js} +39 -39
- package/dist/renderer/assets/{index-Cse2Br64.js → index-DgsIo4vJ.js} +3 -3
- package/dist/renderer/assets/{pencil-BfEunUF3.js → pencil-DGL4agcl.js} +1 -1
- package/dist/renderer/assets/{play-Dcs9Lj_Z.js → play-DzasCLM4.js} +1 -1
- package/dist/renderer/assets/{plug-B_YschQe.js → plug-dubNMe_m.js} +1 -1
- package/dist/renderer/assets/{plus-Pqo-cXHQ.js → plus-DN4kML4k.js} +1 -1
- package/dist/renderer/assets/projects-migPtfRe.js +1 -0
- package/dist/renderer/assets/{save-BKM5yi1A.js → save-CNIc9tjl.js} +1 -1
- package/dist/renderer/assets/{search-BU42h10M.js → search-C0EGbF3I.js} +1 -1
- package/dist/renderer/assets/{server-DA5t3Rtr.js → server-BMxQ4zmc.js} +1 -1
- package/dist/renderer/assets/{session-utils-Cr9VhNSq.js → session-utils-Bf5O-iMi.js} +1 -1
- package/dist/renderer/assets/{sessions-bvV8ZMfX.js → sessions-BMSs6rEI.js} +1 -1
- package/dist/renderer/assets/{shield-check-BeOJKur_.js → shield-check-i3Tf1TUz.js} +1 -1
- package/dist/renderer/assets/{trash-2-CQ7HKO3q.js → trash-2-SKrcp18f.js} +1 -1
- package/dist/renderer/assets/{user-CtFjY9SV.js → user-cNUZddjZ.js} +1 -1
- package/dist/renderer/assets/{wifi-off-Ci5m0ysf.js → wifi-off-Dyb84ANR.js} +1 -1
- package/dist/renderer/index.html +1 -1
- package/dist-electron/electron/channel-content.test.js +29 -0
- package/dist-electron/electron/lac-cli.test.js +49 -4
- package/dist-electron/electron/local-core-acp-content.test.js +39 -0
- package/dist-electron/electron/local-core-contracts.test.js +67 -0
- package/dist-electron/electron/local-core-refactor.test.js +628 -0
- package/dist-electron/electron/plugin-kernel.test.js +74 -14
- package/dist-electron/electron/workspace-task-store.test.js +124 -0
- package/dist-electron/packages/contracts/src/local-core.js +110 -0
- package/dist-electron/packages/core-sdk/src/index.js +40 -20
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-content.js +25 -4
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-response-processor.js +3 -2
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-store.js +44 -28
- package/dist-electron/services/local-ai-core/src/acp/local-core-acp-turn-coordinator.js +5 -1
- package/dist-electron/services/local-ai-core/src/acp/workspace-acp-permissions.js +15 -6
- package/dist-electron/services/local-ai-core/src/channel/lark/cards.js +210 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/config.js +54 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/local-core-lark-gateway.js +280 -496
- package/dist-electron/services/local-ai-core/src/channel/lark/registration.js +50 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/runtime-state.js +191 -0
- package/dist-electron/services/local-ai-core/src/channel/lark/types.js +2 -0
- package/dist-electron/services/local-ai-core/src/channel/shared/content.js +23 -0
- package/dist-electron/services/local-ai-core/src/channel/shared/plugin.js +31 -0
- package/dist-electron/services/local-ai-core/src/channel/weixin/config.js +125 -0
- package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +164 -352
- package/dist-electron/services/local-ai-core/src/channel/weixin/transport.js +169 -0
- package/dist-electron/services/local-ai-core/src/channel/weixin/types.js +2 -0
- package/dist-electron/services/local-ai-core/src/cli/lac.js +19 -16
- package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +5 -0
- package/dist-electron/services/local-ai-core/src/plugins/builtin/channel-lark-plugin.js +18 -39
- package/dist-electron/services/local-ai-core/src/plugins/builtin/channel-weixin-plugin.js +18 -39
- package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +55 -44
- package/dist-electron/services/local-ai-core/src/runtime/server.js +10 -8
- package/dist-electron/services/local-ai-core/src/scheduler/job-id.js +15 -0
- package/dist-electron/services/local-ai-core/src/scheduler/scheduler-service.js +30 -5
- package/dist-electron/shared/desktop.js +37 -5
- package/dist-electron/src/pages/Threads/thread-chat-model.js +57 -0
- package/dist-electron/src/pages/Threads/thread-chat-permission.test.js +70 -0
- package/package.json +1 -1
- package/dist/renderer/assets/ThreadChat-YvVsACW3.js +0 -23
- package/dist/renderer/assets/Workspace-ST7V8u6T.js +0 -14
- package/dist/renderer/assets/desktop-Che1cbpE.js +0 -4
- package/dist/renderer/assets/desktop-DkrP_s-b.js +0 -1
- package/dist/renderer/assets/projects-BCj0k_Gy.js +0 -1
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LARK_APP_REGISTRATION_SETUP_PATH = exports.DEFAULT_LARK_QR_EXPIRES_IN = void 0;
|
|
4
|
+
exports.getLarkAccountsBase = getLarkAccountsBase;
|
|
5
|
+
exports.getLarkOpenBase = getLarkOpenBase;
|
|
6
|
+
exports.requestAppRegistration = requestAppRegistration;
|
|
7
|
+
exports.pollAppRegistration = pollAppRegistration;
|
|
8
|
+
exports.DEFAULT_LARK_QR_EXPIRES_IN = 180;
|
|
9
|
+
exports.LARK_APP_REGISTRATION_SETUP_PATH = '/page/openclaw';
|
|
10
|
+
const LARK_APP_REGISTRATION_PATH = '/oauth/v1/app/registration';
|
|
11
|
+
function getLarkAccountsBase(binding) {
|
|
12
|
+
return binding.brand === 'lark' ? 'https://accounts.larksuite.com' : 'https://accounts.feishu.cn';
|
|
13
|
+
}
|
|
14
|
+
function getLarkOpenBase(binding) {
|
|
15
|
+
return binding.brand === 'lark' ? 'https://open.larksuite.com' : 'https://open.feishu.cn';
|
|
16
|
+
}
|
|
17
|
+
async function requestAppRegistration(binding) {
|
|
18
|
+
return callAppRegistration(binding, {
|
|
19
|
+
action: 'begin',
|
|
20
|
+
archetype: 'PersonalAgent',
|
|
21
|
+
auth_method: 'client_secret',
|
|
22
|
+
request_user_info: 'open_id tenant_brand',
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
async function pollAppRegistration(binding, deviceCode) {
|
|
26
|
+
return callAppRegistration(binding, {
|
|
27
|
+
action: 'poll',
|
|
28
|
+
device_code: deviceCode,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
async function callAppRegistration(binding, formValues) {
|
|
32
|
+
const form = new URLSearchParams();
|
|
33
|
+
for (const [key, value] of Object.entries(formValues)) {
|
|
34
|
+
form.set(key, value);
|
|
35
|
+
}
|
|
36
|
+
const response = await fetch(`${getLarkAccountsBase(binding)}${LARK_APP_REGISTRATION_PATH}`, {
|
|
37
|
+
method: 'POST',
|
|
38
|
+
headers: {
|
|
39
|
+
Accept: 'application/json',
|
|
40
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
41
|
+
},
|
|
42
|
+
body: form.toString(),
|
|
43
|
+
});
|
|
44
|
+
const text = await response.text();
|
|
45
|
+
const parsed = text ? JSON.parse(text) : {};
|
|
46
|
+
if (!response.ok) {
|
|
47
|
+
throw new Error(`Lark app registration failed (${response.status}): ${String(parsed.error_description || parsed.error || text || response.statusText)}`);
|
|
48
|
+
}
|
|
49
|
+
return parsed;
|
|
50
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createLarkTurnState = createLarkTurnState;
|
|
4
|
+
exports.foldToolResultForLark = foldToolResultForLark;
|
|
5
|
+
exports.consumeLarkBridgeEvent = consumeLarkBridgeEvent;
|
|
6
|
+
exports.renderLarkBridgeEventMessage = renderLarkBridgeEventMessage;
|
|
7
|
+
exports.getLarkRenderedMessageId = getLarkRenderedMessageId;
|
|
8
|
+
exports.setLarkRenderedMessageId = setLarkRenderedMessageId;
|
|
9
|
+
function createLarkTurnState(sessionKey, sourceMessageId) {
|
|
10
|
+
const turn = {
|
|
11
|
+
sessionKey,
|
|
12
|
+
sourceMessageId,
|
|
13
|
+
awaitingPermission: false,
|
|
14
|
+
processing: false,
|
|
15
|
+
previewText: '',
|
|
16
|
+
finalText: '',
|
|
17
|
+
progressMessageIds: {},
|
|
18
|
+
thinkingSteps: [],
|
|
19
|
+
toolCalls: [],
|
|
20
|
+
statusLines: [],
|
|
21
|
+
buttonRows: [],
|
|
22
|
+
lastPatchedAt: 0,
|
|
23
|
+
lastPatchedAtByMessageId: {},
|
|
24
|
+
};
|
|
25
|
+
return turn;
|
|
26
|
+
}
|
|
27
|
+
function foldToolResultForLark(content) {
|
|
28
|
+
const normalized = String(content || '').trim();
|
|
29
|
+
if (!normalized.startsWith('🔧 '))
|
|
30
|
+
return normalized;
|
|
31
|
+
const parts = normalized.split(' - ');
|
|
32
|
+
if (parts.length <= 2)
|
|
33
|
+
return normalized;
|
|
34
|
+
return parts.slice(0, 2).join(' - ');
|
|
35
|
+
}
|
|
36
|
+
function consumeLarkBridgeEvent(turn, event, options) {
|
|
37
|
+
const content = foldToolResultForLark(String(event.content || '').trim());
|
|
38
|
+
if (event.type === 'typing_start') {
|
|
39
|
+
turn.messageId = undefined;
|
|
40
|
+
turn.finalMessageId = undefined;
|
|
41
|
+
turn.replyMessageId = undefined;
|
|
42
|
+
turn.progressMessageIds = {};
|
|
43
|
+
turn.processing = true;
|
|
44
|
+
turn.permissionMessageId = undefined;
|
|
45
|
+
turn.previewText = '';
|
|
46
|
+
turn.finalText = '';
|
|
47
|
+
turn.thinkingSteps = [];
|
|
48
|
+
turn.toolCalls = [];
|
|
49
|
+
turn.buttonRows = [];
|
|
50
|
+
turn.statusLines = [];
|
|
51
|
+
turn.lastPatchedAtByMessageId = {};
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (event.type === 'typing_stop') {
|
|
55
|
+
turn.processing = false;
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (event.type === 'preview_start' || event.type === 'update_message') {
|
|
59
|
+
turn.previewText = content;
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (event.type === 'status') {
|
|
63
|
+
if (content) {
|
|
64
|
+
pushUniqueLarkTurnLine(turn.statusLines, content);
|
|
65
|
+
}
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (event.type === 'buttons') {
|
|
69
|
+
turn.awaitingPermission = true;
|
|
70
|
+
turn.buttonRows = [];
|
|
71
|
+
if (options.mirrorPermissionStateInMainCard && content) {
|
|
72
|
+
pushUniqueLarkTurnLine(turn.statusLines, `等待确认: ${content}`);
|
|
73
|
+
}
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (!content) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (content.startsWith('💭 ')) {
|
|
80
|
+
pushUniqueLarkTurnLine(turn.thinkingSteps, content.slice(3).trim());
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (content.startsWith('🔧 ')) {
|
|
84
|
+
pushUniqueLarkTurnLine(turn.toolCalls, content.slice(3).trim());
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (content.startsWith('⏳ ') || content.startsWith('📤 ')) {
|
|
88
|
+
pushUniqueLarkTurnLine(turn.statusLines, content.slice(3).trim());
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
turn.finalText = content;
|
|
92
|
+
turn.previewText = content;
|
|
93
|
+
}
|
|
94
|
+
function renderLarkBridgeEventMessage(turn, event) {
|
|
95
|
+
const content = foldToolResultForLark(String(event.content || '').trim());
|
|
96
|
+
if (event.type === 'preview_start' || event.type === 'update_message') {
|
|
97
|
+
if (content.startsWith('💭 ')) {
|
|
98
|
+
return renderProgressMessage(event.previewHandle || 'thinking-preview', content);
|
|
99
|
+
}
|
|
100
|
+
if (content.startsWith('🔧 ')) {
|
|
101
|
+
return renderProgressMessage(progressKey('tool', event), content);
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
key: 'final',
|
|
105
|
+
text: content,
|
|
106
|
+
buttonRows: turn.buttonRows,
|
|
107
|
+
isFinal: true,
|
|
108
|
+
finalSource: 'stream',
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
if (event.type === 'status') {
|
|
112
|
+
return renderProgressMessage(progressKey('status', event), content.startsWith('⏳ ') ? content : `⏳ ${content}`);
|
|
113
|
+
}
|
|
114
|
+
if (event.type === 'reply') {
|
|
115
|
+
if (content.startsWith('💭 ')) {
|
|
116
|
+
return renderProgressMessage(progressKey('thinking', event), content);
|
|
117
|
+
}
|
|
118
|
+
if (content.startsWith('🔧 ')) {
|
|
119
|
+
return renderProgressMessage(progressKey('tool', event), content);
|
|
120
|
+
}
|
|
121
|
+
if (content.startsWith('⏳ ') || content.startsWith('📤 ')) {
|
|
122
|
+
return renderProgressMessage(progressKey('status', event), content);
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
key: 'final',
|
|
126
|
+
text: content,
|
|
127
|
+
buttonRows: turn.buttonRows,
|
|
128
|
+
isFinal: true,
|
|
129
|
+
finalSource: 'reply',
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
if (event.type === 'typing_start' || event.type === 'typing_stop') {
|
|
133
|
+
return { key: 'noop', text: '', buttonRows: [], isFinal: false };
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
key: 'noop',
|
|
137
|
+
text: '',
|
|
138
|
+
buttonRows: [],
|
|
139
|
+
isFinal: false,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function getLarkRenderedMessageId(turn, rendered) {
|
|
143
|
+
if (rendered.isFinal) {
|
|
144
|
+
if (rendered.finalSource === 'reply') {
|
|
145
|
+
return turn.replyMessageId;
|
|
146
|
+
}
|
|
147
|
+
return turn.finalMessageId || turn.messageId;
|
|
148
|
+
}
|
|
149
|
+
return turn.progressMessageIds[rendered.key];
|
|
150
|
+
}
|
|
151
|
+
function setLarkRenderedMessageId(turn, rendered, messageId) {
|
|
152
|
+
if (rendered.isFinal) {
|
|
153
|
+
if (rendered.finalSource === 'reply') {
|
|
154
|
+
turn.replyMessageId = messageId;
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
turn.finalMessageId = messageId;
|
|
158
|
+
turn.messageId = messageId;
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
turn.progressMessageIds[rendered.key] = messageId;
|
|
162
|
+
}
|
|
163
|
+
function renderProgressMessage(key, text) {
|
|
164
|
+
return {
|
|
165
|
+
key,
|
|
166
|
+
text,
|
|
167
|
+
buttonRows: [],
|
|
168
|
+
isFinal: false,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
function progressKey(prefix, event) {
|
|
172
|
+
const stableId = String(event.messageId || event.previewHandle || '').trim();
|
|
173
|
+
if (stableId) {
|
|
174
|
+
return `${prefix}:${stableId}`;
|
|
175
|
+
}
|
|
176
|
+
const content = String(event.content || '').trim().replace(/\s+/g, ' ');
|
|
177
|
+
return `${prefix}:${content.slice(0, 120)}`;
|
|
178
|
+
}
|
|
179
|
+
function pushUniqueLarkTurnLine(target, value) {
|
|
180
|
+
const normalized = value.trim();
|
|
181
|
+
if (!normalized) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (target[target.length - 1] === normalized) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
target.push(normalized);
|
|
188
|
+
if (target.length > 6) {
|
|
189
|
+
target.splice(0, target.length - 6);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createWrappedChannelContentParts = createWrappedChannelContentParts;
|
|
4
|
+
exports.createChannelThreadMessageInput = createChannelThreadMessageInput;
|
|
5
|
+
function createWrappedChannelContentParts(wrappedText, parts) {
|
|
6
|
+
const nonTextParts = Array.isArray(parts)
|
|
7
|
+
? parts.filter((part) => part.type !== 'text')
|
|
8
|
+
: [];
|
|
9
|
+
return [
|
|
10
|
+
{ type: 'text', text: wrappedText },
|
|
11
|
+
...nonTextParts,
|
|
12
|
+
];
|
|
13
|
+
}
|
|
14
|
+
function createChannelThreadMessageInput(wrappedText, parts) {
|
|
15
|
+
const hasNonTextPart = Array.isArray(parts) && parts.some((part) => part.type !== 'text');
|
|
16
|
+
if (!hasNonTextPart) {
|
|
17
|
+
return wrappedText;
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
displayText: wrappedText,
|
|
21
|
+
contentParts: createWrappedChannelContentParts(wrappedText, parts),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createBuiltinChannelPlugin = createBuiltinChannelPlugin;
|
|
4
|
+
function createBuiltinChannelPlugin(options) {
|
|
5
|
+
let runtime = null;
|
|
6
|
+
let unsubscribeBridgeEvents = null;
|
|
7
|
+
return {
|
|
8
|
+
manifest: options.manifest,
|
|
9
|
+
capabilities: {
|
|
10
|
+
channels: options.channels,
|
|
11
|
+
},
|
|
12
|
+
createRuntime(ctx) {
|
|
13
|
+
if (!runtime) {
|
|
14
|
+
const channel = options.createChannel(ctx);
|
|
15
|
+
runtime = { channel };
|
|
16
|
+
unsubscribeBridgeEvents = ctx.bus.on('platform.bridge.updated', (event) => {
|
|
17
|
+
void channel.onBridgeEvent?.(event);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
return runtime;
|
|
21
|
+
},
|
|
22
|
+
async start() {
|
|
23
|
+
await runtime?.channel.refreshBindings?.();
|
|
24
|
+
},
|
|
25
|
+
async stop() {
|
|
26
|
+
unsubscribeBridgeEvents?.();
|
|
27
|
+
unsubscribeBridgeEvents = null;
|
|
28
|
+
runtime?.channel.close?.();
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.LONG_POLL_TIMEOUT_MS = exports.DEFAULT_CDN_BASE_URL = exports.DEFAULT_BASE_URL = void 0;
|
|
7
|
+
exports.normalizeChannelInstanceId = normalizeChannelInstanceId;
|
|
8
|
+
exports.channelPlatformKey = channelPlatformKey;
|
|
9
|
+
exports.runtimeKey = runtimeKey;
|
|
10
|
+
exports.getDefaultWeixinStateDir = getDefaultWeixinStateDir;
|
|
11
|
+
exports.safeFilePart = safeFilePart;
|
|
12
|
+
exports.getWeixinBufPath = getWeixinBufPath;
|
|
13
|
+
exports.getWeixinCredentialsPath = getWeixinCredentialsPath;
|
|
14
|
+
exports.loadWeixinCredentials = loadWeixinCredentials;
|
|
15
|
+
exports.saveWeixinCredentials = saveWeixinCredentials;
|
|
16
|
+
exports.loadWeixinBuf = loadWeixinBuf;
|
|
17
|
+
exports.saveWeixinBuf = saveWeixinBuf;
|
|
18
|
+
exports.collectWeixinWorkspaceBindings = collectWeixinWorkspaceBindings;
|
|
19
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
20
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
21
|
+
const desktop_js_1 = require("../../../../../shared/desktop.js");
|
|
22
|
+
exports.DEFAULT_BASE_URL = 'https://ilinkai.weixin.qq.com';
|
|
23
|
+
exports.DEFAULT_CDN_BASE_URL = 'https://novac2c.cdn.weixin.qq.com/c2c';
|
|
24
|
+
exports.LONG_POLL_TIMEOUT_MS = 35_000;
|
|
25
|
+
function normalizeChannelInstanceId(value, fallback) {
|
|
26
|
+
const raw = String(value || '').trim();
|
|
27
|
+
const normalized = raw.replace(/[^a-zA-Z0-9._-]/g, '-').replace(/-+/g, '-').slice(0, 80);
|
|
28
|
+
return normalized || fallback;
|
|
29
|
+
}
|
|
30
|
+
function channelPlatformKey(platform, instanceId) {
|
|
31
|
+
return instanceId === 'default' ? platform : `${platform}:${instanceId}`;
|
|
32
|
+
}
|
|
33
|
+
function runtimeKey(workspaceId, instanceId) {
|
|
34
|
+
return `${workspaceId}::${instanceId}`;
|
|
35
|
+
}
|
|
36
|
+
function getDefaultWeixinStateDir() {
|
|
37
|
+
return node_path_1.default.join(process.cwd(), 'weixin-monitor');
|
|
38
|
+
}
|
|
39
|
+
function safeFilePart(value) {
|
|
40
|
+
return String(value || 'default').replace(/[^a-zA-Z0-9._-]/g, '_').slice(0, 80) || 'default';
|
|
41
|
+
}
|
|
42
|
+
function getWeixinBufPath(binding) {
|
|
43
|
+
return node_path_1.default.join(binding.stateDir, `${binding.accountId}.buf`);
|
|
44
|
+
}
|
|
45
|
+
function getWeixinCredentialsPath(workspaceId, stateDir, instanceId = 'default') {
|
|
46
|
+
const suffix = instanceId === 'default' ? '' : `.${safeFilePart(instanceId)}`;
|
|
47
|
+
return node_path_1.default.join(stateDir, `${safeFilePart(workspaceId)}${suffix}.credentials.json`);
|
|
48
|
+
}
|
|
49
|
+
function loadWeixinCredentials(workspaceId, stateDir, instanceId = 'default') {
|
|
50
|
+
try {
|
|
51
|
+
const raw = node_fs_1.default.readFileSync(getWeixinCredentialsPath(workspaceId, stateDir, instanceId), 'utf-8');
|
|
52
|
+
const parsed = JSON.parse(raw);
|
|
53
|
+
const token = String(parsed.token || '').trim();
|
|
54
|
+
if (!token)
|
|
55
|
+
return null;
|
|
56
|
+
return {
|
|
57
|
+
token,
|
|
58
|
+
baseUrl: parsed.baseUrl ? String(parsed.baseUrl) : undefined,
|
|
59
|
+
botId: parsed.botId ? String(parsed.botId) : undefined,
|
|
60
|
+
userId: parsed.userId ? String(parsed.userId) : undefined,
|
|
61
|
+
savedAt: parsed.savedAt ? String(parsed.savedAt) : new Date().toISOString(),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function saveWeixinCredentials(binding, credentials) {
|
|
69
|
+
node_fs_1.default.mkdirSync(binding.stateDir, { recursive: true });
|
|
70
|
+
node_fs_1.default.writeFileSync(getWeixinCredentialsPath(binding.workspaceId, binding.stateDir, binding.instanceId), JSON.stringify(credentials, null, 2), 'utf-8');
|
|
71
|
+
}
|
|
72
|
+
function loadWeixinBuf(binding) {
|
|
73
|
+
try {
|
|
74
|
+
return node_fs_1.default.readFileSync(getWeixinBufPath(binding), 'utf-8');
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return '';
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function saveWeixinBuf(binding, buf) {
|
|
81
|
+
const dir = binding.stateDir;
|
|
82
|
+
node_fs_1.default.mkdirSync(dir, { recursive: true });
|
|
83
|
+
node_fs_1.default.writeFileSync(getWeixinBufPath(binding), buf, 'utf-8');
|
|
84
|
+
}
|
|
85
|
+
function collectWeixinWorkspaceBindings(config) {
|
|
86
|
+
const projects = Array.isArray(config?.projects) ? config.projects : [];
|
|
87
|
+
return projects.flatMap((project) => {
|
|
88
|
+
const platforms = Array.isArray(project.platforms) ? project.platforms : [];
|
|
89
|
+
return platforms
|
|
90
|
+
.map((platform) => ({
|
|
91
|
+
platformType: (0, desktop_js_1.normalizeDesktopPlatformType)(platform?.type),
|
|
92
|
+
options: platform?.options && typeof platform.options === 'object'
|
|
93
|
+
? platform.options
|
|
94
|
+
: {},
|
|
95
|
+
}))
|
|
96
|
+
.filter((p) => p.platformType === 'weixin')
|
|
97
|
+
.map((p, index) => {
|
|
98
|
+
const instanceId = normalizeChannelInstanceId(p.options.instance_id || p.options.id, index === 0 ? 'default' : `weixin-${index + 1}`);
|
|
99
|
+
const stateDir = String(p.options.state_dir || getDefaultWeixinStateDir()).trim();
|
|
100
|
+
const credentials = loadWeixinCredentials(project.name, stateDir, instanceId);
|
|
101
|
+
const configuredToken = String(p.options.token || '').trim();
|
|
102
|
+
const configuredBaseUrl = String(p.options.base_url || '').trim();
|
|
103
|
+
const accountId = String(p.options.account_id || credentials?.botId || 'qr-login').trim();
|
|
104
|
+
return {
|
|
105
|
+
workspaceId: project.name,
|
|
106
|
+
instanceId,
|
|
107
|
+
displayName: String(p.options.name || p.options.display_name || `WeChat ${index + 1}`).trim(),
|
|
108
|
+
platformKey: channelPlatformKey('weixin', instanceId),
|
|
109
|
+
token: configuredToken || credentials?.token || '',
|
|
110
|
+
accountId,
|
|
111
|
+
baseUrl: configuredBaseUrl || credentials?.baseUrl || exports.DEFAULT_BASE_URL,
|
|
112
|
+
cdnBaseUrl: String(p.options.cdn_base_url || exports.DEFAULT_CDN_BASE_URL).trim(),
|
|
113
|
+
allowFrom: String(p.options.allow_from || '*').trim(),
|
|
114
|
+
routeTag: String(p.options.route_tag || '').trim(),
|
|
115
|
+
longPollTimeoutMs: Number(p.options.long_poll_timeout_ms || exports.LONG_POLL_TIMEOUT_MS) || exports.LONG_POLL_TIMEOUT_MS,
|
|
116
|
+
stateDir,
|
|
117
|
+
proxy: String(p.options.proxy || '').trim(),
|
|
118
|
+
proxyUsername: String(p.options.proxy_username || '').trim(),
|
|
119
|
+
proxyPassword: String(p.options.proxy_password || '').trim(),
|
|
120
|
+
enabled: true,
|
|
121
|
+
project,
|
|
122
|
+
};
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
}
|