linco-connect 1.0.9 → 1.1.1
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/linco-connect.js +23 -4
- package/package.json +1 -1
- package/public/index.html +3 -2
- package/src/agentRunner.js +2 -0
- package/src/agents/codex.js +5 -1
- package/src/agents/hermes.js +4 -1
- package/src/agents/openclaw.js +612 -0
- package/src/attachmentHandler.js +34 -5
- package/src/claudeRunner.js +2 -1
- package/src/config.js +20 -4
- package/src/httpStatic.js +2 -2
- package/src/imConnector.js +78 -3
- package/src/lincoProtocol.js +35 -1
- package/src/openclawGateway.js +442 -0
- package/src/protocol.js +18 -0
- package/src/slashCommands.js +4 -0
- package/src/wsServer.js +5 -1
package/bin/linco-connect.js
CHANGED
|
@@ -16,6 +16,10 @@ const {
|
|
|
16
16
|
} = require('../src/config');
|
|
17
17
|
const { ensureLocalToken, localUrlWithToken } = require('../src/localAuth');
|
|
18
18
|
const { checkGatewayHealth, resolveHermesGatewayOptions } = require('../src/hermesGateway');
|
|
19
|
+
const {
|
|
20
|
+
checkGatewayHealth: checkOpenClawGatewayHealth,
|
|
21
|
+
resolveOpenClawGatewayOptions,
|
|
22
|
+
} = require('../src/openclawGateway');
|
|
19
23
|
const pkg = require('../package.json');
|
|
20
24
|
|
|
21
25
|
const rootDir = path.resolve(__dirname, '..');
|
|
@@ -147,6 +151,8 @@ function mergeInitConfig(current, values) {
|
|
|
147
151
|
appSecret: values.appSecret,
|
|
148
152
|
enabled: true,
|
|
149
153
|
};
|
|
154
|
+
if (values.agentType === 'openclaw') accountEntry.openclawAgentId = 'main';
|
|
155
|
+
const agentType = values.agentType || 'claude';
|
|
150
156
|
|
|
151
157
|
return {
|
|
152
158
|
...current,
|
|
@@ -157,13 +163,13 @@ function mergeInitConfig(current, values) {
|
|
|
157
163
|
...(current.channels?.linco || {}),
|
|
158
164
|
agents: {
|
|
159
165
|
...(current.channels?.linco?.agents || {}),
|
|
160
|
-
[
|
|
161
|
-
...(current.channels?.linco?.agents?.[
|
|
166
|
+
[agentType]: {
|
|
167
|
+
...(current.channels?.linco?.agents?.[agentType] || {}),
|
|
162
168
|
defaultAccount: values.account,
|
|
163
169
|
accounts: {
|
|
164
|
-
...(current.channels?.linco?.agents?.[
|
|
170
|
+
...(current.channels?.linco?.agents?.[agentType]?.accounts || {}),
|
|
165
171
|
[values.account]: {
|
|
166
|
-
...(current.channels?.linco?.agents?.[
|
|
172
|
+
...(current.channels?.linco?.agents?.[agentType]?.accounts?.[values.account] || {}),
|
|
167
173
|
...accountEntry,
|
|
168
174
|
},
|
|
169
175
|
},
|
|
@@ -425,6 +431,19 @@ async function doctorCommand() {
|
|
|
425
431
|
} else {
|
|
426
432
|
checks.push([`${agentType} Gateway`, false, `未运行,且 autoStartGateway=false ${options.gatewayUrl}`]);
|
|
427
433
|
}
|
|
434
|
+
} else if (agentType === 'openclaw') {
|
|
435
|
+
const options = resolveOpenClawGatewayOptions(agent);
|
|
436
|
+
const health = await checkOpenClawGatewayHealth(options.gatewayUrl, agent, { timeoutMs: 3000 });
|
|
437
|
+
if (health.ok) {
|
|
438
|
+
checks.push([`${agentType} Gateway`, true, options.gatewayUrl]);
|
|
439
|
+
} else if (agent.autoStartGateway !== false) {
|
|
440
|
+
const hasCli = !agent.enabled || (path.isAbsolute(options.openclawBin) ? fs.existsSync(options.openclawBin) : commandExists(options.openclawBin));
|
|
441
|
+
checks.push([`${agentType} Gateway`, true, `not running; OpenClaw messages will auto-start ${options.gatewayUrl}`]);
|
|
442
|
+
checks.push([`${agentType} CLI`, hasCli, options.openclawBin]);
|
|
443
|
+
} else {
|
|
444
|
+
checks.push([`${agentType} Gateway`, false, `not running and autoStartGateway=false ${options.gatewayUrl}`]);
|
|
445
|
+
}
|
|
446
|
+
checks.push([`${agentType} Agent ID`, true, agent.openclawAgentId || 'main']);
|
|
428
447
|
} else {
|
|
429
448
|
checks.push([`${agentType} CLI`, !agent.enabled || (path.isAbsolute(agent.bin) ? fs.existsSync(agent.bin) : commandExists(agent.bin)), agent.bin]);
|
|
430
449
|
}
|
package/package.json
CHANGED
package/public/index.html
CHANGED
|
@@ -577,6 +577,7 @@
|
|
|
577
577
|
<option value="claude">Claude Code</option>
|
|
578
578
|
<option value="codex">Codex</option>
|
|
579
579
|
<option value="hermes">Hermes</option>
|
|
580
|
+
<option value="openclaw">OpenClaw</option>
|
|
580
581
|
</select>
|
|
581
582
|
</div>
|
|
582
583
|
<div id="messages"></div>
|
|
@@ -1180,11 +1181,11 @@
|
|
|
1180
1181
|
|
|
1181
1182
|
function normalizeAgentType(value) {
|
|
1182
1183
|
const type = String(value || 'claude').trim().toLowerCase();
|
|
1183
|
-
return ['claude', 'codex', 'hermes'].includes(type) ? type : 'claude';
|
|
1184
|
+
return ['claude', 'codex', 'hermes', 'openclaw'].includes(type) ? type : 'claude';
|
|
1184
1185
|
}
|
|
1185
1186
|
|
|
1186
1187
|
function agentLabel(type) {
|
|
1187
|
-
return type === 'codex' ? 'Codex' : type === 'hermes' ? 'Hermes' : 'Claude Code';
|
|
1188
|
+
return type === 'codex' ? 'Codex' : type === 'hermes' ? 'Hermes' : type === 'openclaw' ? 'OpenClaw' : 'Claude Code';
|
|
1188
1189
|
}
|
|
1189
1190
|
|
|
1190
1191
|
function setAgentSelection(agentType, options = {}) {
|
package/src/agentRunner.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
const claude = require('./agents/claude');
|
|
2
2
|
const codex = require('./agents/codex');
|
|
3
3
|
const hermes = require('./agents/hermes');
|
|
4
|
+
const openclaw = require('./agents/openclaw');
|
|
4
5
|
|
|
5
6
|
const providers = {
|
|
6
7
|
claude,
|
|
7
8
|
codex,
|
|
8
9
|
hermes,
|
|
10
|
+
openclaw,
|
|
9
11
|
};
|
|
10
12
|
|
|
11
13
|
function providerFor(session) {
|
package/src/agents/codex.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const { spawn } = require('child_process');
|
|
2
2
|
const { isDangerousCommand } = require('../danger');
|
|
3
|
-
const { send, sendError, sendSystem } = require('../protocol');
|
|
3
|
+
const { send, sendError, sendSystem, sendTurnEnd } = require('../protocol');
|
|
4
4
|
const { persistAgentSessionId, stopAgentProcess: stopSessionProcess, updateAgentSessionHistory } = require('../session');
|
|
5
5
|
const { getOutboxDir } = require('../outgoingAttachmentHandler');
|
|
6
6
|
const { createTextStreamBuffer, appendTextStream, flushTextStream, resetTextStream } = require('../streamBuffer');
|
|
@@ -603,6 +603,7 @@ function handleAppServerMessage(message, session) {
|
|
|
603
603
|
} else {
|
|
604
604
|
sendSystem(ws, 'Codex 本次执行没有输出。');
|
|
605
605
|
}
|
|
606
|
+
sendTurnEnd(ws, session, 'timeout');
|
|
606
607
|
const cfg = session._lastConfig;
|
|
607
608
|
if (cfg) drainQueue(ws, session, cfg);
|
|
608
609
|
}
|
|
@@ -622,6 +623,7 @@ function handleAppServerMessage(message, session) {
|
|
|
622
623
|
} else {
|
|
623
624
|
sendSystem(ws, 'Codex 本次执行没有输出。');
|
|
624
625
|
}
|
|
626
|
+
sendTurnEnd(ws, session);
|
|
625
627
|
const cfg = session._lastConfig;
|
|
626
628
|
if (cfg) {
|
|
627
629
|
drainQueue(ws, session, cfg);
|
|
@@ -631,6 +633,7 @@ function handleAppServerMessage(message, session) {
|
|
|
631
633
|
|
|
632
634
|
if (method === 'error' || method.includes('error')) {
|
|
633
635
|
sendError(ws, params.message || JSON.stringify(params));
|
|
636
|
+
sendTurnEnd(ws, session, 'error', { error: params.message || JSON.stringify(params) });
|
|
634
637
|
clearTurnState(session);
|
|
635
638
|
return;
|
|
636
639
|
}
|
|
@@ -861,6 +864,7 @@ function runExecTurn(input, ws, session, config) {
|
|
|
861
864
|
if (code === 0) {
|
|
862
865
|
updateCodexSessionStats(session);
|
|
863
866
|
}
|
|
867
|
+
sendTurnEnd(ws, session, code === 0 ? 'completed' : 'error', code === 0 ? {} : { error: stderr.trim() || `Codex 退出,状态码: ${code}` });
|
|
864
868
|
drainQueue(ws, session, config);
|
|
865
869
|
});
|
|
866
870
|
|
package/src/agents/hermes.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const { isDangerousCommand } = require('../danger');
|
|
2
|
-
const { send, sendError, sendSystem } = require('../protocol');
|
|
2
|
+
const { send, sendError, sendSystem, sendTurnEnd } = require('../protocol');
|
|
3
3
|
const { persistAgentSessionId, stopAgentProcess: stopSessionProcess, updateAgentSessionHistory, createAgentSessionEntry, saveSessionMetadata } = require('../session');
|
|
4
4
|
const { getOutboxDir } = require('../outgoingAttachmentHandler');
|
|
5
5
|
const { createTextStreamBuffer, appendTextStream, flushTextStream, resetTextStream } = require('../streamBuffer');
|
|
@@ -177,10 +177,12 @@ function handleHermesEvent(event, ws, session, config) {
|
|
|
177
177
|
return;
|
|
178
178
|
case 'run.failed':
|
|
179
179
|
sendError(ws, event.error || 'Hermes run 执行失败');
|
|
180
|
+
sendTurnEnd(ws, session, 'error', { error: event.error || 'Hermes run 执行失败' });
|
|
180
181
|
finishTurn(ws, session, config);
|
|
181
182
|
return;
|
|
182
183
|
case 'run.cancelled':
|
|
183
184
|
sendSystem(ws, 'Hermes run 已停止。');
|
|
185
|
+
sendTurnEnd(ws, session, 'cancelled');
|
|
184
186
|
finishTurn(ws, session, config);
|
|
185
187
|
return;
|
|
186
188
|
default:
|
|
@@ -240,6 +242,7 @@ function completeRun(event, ws, session, config) {
|
|
|
240
242
|
sendSystem(ws, 'Hermes 本次执行没有输出。');
|
|
241
243
|
}
|
|
242
244
|
updateHermesSessionStats(session, event.usage);
|
|
245
|
+
sendTurnEnd(ws, session);
|
|
243
246
|
finishTurn(ws, session, config);
|
|
244
247
|
}
|
|
245
248
|
|