linco-connect 1.0.3 → 1.0.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "linco-connect",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "自研 IM 桥接多 Agent 服务",
5
5
  "main": "server.js",
6
6
  "bin": {
package/public/index.html CHANGED
@@ -931,12 +931,21 @@
931
931
  }
932
932
 
933
933
  function addPermissionConfirm(data) {
934
+ const requestId = data.requestId || '';
935
+ const selector = requestId ? `.permission-confirm[data-request-id="${cssEscape(requestId)}"]` : '';
936
+ const existing = selector ? messagesEl.querySelector(selector) : null;
937
+ if (existing) {
938
+ scrollToBottom();
939
+ return;
940
+ }
941
+
934
942
  const container = document.createElement('div');
935
943
  container.className = 'danger-confirm permission-confirm';
944
+ container.dataset.requestId = requestId;
936
945
 
937
946
  const title = document.createElement('div');
938
947
  title.className = 'danger-text';
939
- title.textContent = `Claude 请求使用工具:${data.toolName || 'tool'}`;
948
+ title.textContent = `${agentLabel(currentAgentType)} 请求使用工具:${data.toolName || 'tool'}`;
940
949
  container.appendChild(title);
941
950
 
942
951
  if (data.input) {
@@ -319,12 +319,27 @@ function handleServerRequest(message, session) {
319
319
 
320
320
  // File change approval — auto-approve but notify user
321
321
  if (method === 'item/fileChange/requestApproval') {
322
+ const toolId = String(message.id);
323
+ const input = summarizeCodexParams(params);
322
324
  session._log?.info('codex auto-approving file change');
325
+ if (ws) {
326
+ send(ws, 'tool_call', {
327
+ id: toolId,
328
+ name: 'fileChange',
329
+ input,
330
+ });
331
+ }
323
332
  sendJsonRpc(session.codexAppServer, {
324
333
  jsonrpc: '2.0',
325
334
  id: message.id,
326
335
  result: { decision: 'accept' },
327
336
  });
337
+ if (ws) {
338
+ send(ws, 'tool_result', {
339
+ id: toolId,
340
+ output: 'approved',
341
+ });
342
+ }
328
343
  return;
329
344
  }
330
345
 
@@ -333,8 +348,11 @@ function handleServerRequest(message, session) {
333
348
  const cmd = params.command || params.tool || '';
334
349
  session._log?.info('codex command execution approval requested', { method, command: cmd });
335
350
 
351
+ if (session.pendingPermission?.requestId === String(message.id)) return;
352
+
336
353
  session.pendingPermission = {
337
354
  provider: 'codex',
355
+ requestId: String(message.id),
338
356
  toolName: 'exec',
339
357
  input: cmd,
340
358
  _codexMethod: method,
@@ -342,11 +360,6 @@ function handleServerRequest(message, session) {
342
360
  };
343
361
 
344
362
  if (ws) {
345
- send(ws, 'tool_call', {
346
- id: String(message.id),
347
- name: 'exec',
348
- input: cmd,
349
- });
350
363
  send(ws, 'permission_request', {
351
364
  requestId: String(message.id),
352
365
  toolName: 'exec',
@@ -369,12 +382,27 @@ function handleServerRequest(message, session) {
369
382
 
370
383
  // Apply patch approval — auto-approve
371
384
  if (method === 'applyPatchApproval') {
385
+ const toolId = String(message.id);
386
+ const input = summarizeCodexParams(params);
372
387
  session._log?.info('codex auto-approving patch');
388
+ if (ws) {
389
+ send(ws, 'tool_call', {
390
+ id: toolId,
391
+ name: 'applyPatch',
392
+ input,
393
+ });
394
+ }
373
395
  sendJsonRpc(session.codexAppServer, {
374
396
  jsonrpc: '2.0',
375
397
  id: message.id,
376
398
  result: { decision: 'approved' },
377
399
  });
400
+ if (ws) {
401
+ send(ws, 'tool_result', {
402
+ id: toolId,
403
+ output: 'approved',
404
+ });
405
+ }
378
406
  return;
379
407
  }
380
408
 
@@ -477,6 +505,25 @@ function handleAppServerMessage(message, session) {
477
505
  }
478
506
 
479
507
  if (method === 'item/completed') {
508
+ const itemType = params.item?.type || '';
509
+ session._log?.info('codex item completed', { itemType, item: summarizeCodexItemForLog(params.item) });
510
+ if (itemType === 'toolCall' || itemType === 'commandExecution' || itemType === 'webSearch') {
511
+ const itemId = params.item?.id || params.itemId || '';
512
+ if (itemType === 'webSearch' && params.item?.query) {
513
+ send(ws, 'tool_call', {
514
+ id: itemId,
515
+ name: 'webSearch',
516
+ input: params.item.query,
517
+ });
518
+ }
519
+ const output = params.item?.output || params.item?.result || params.item?.results || params.output || params.result || '';
520
+ send(ws, 'tool_result', {
521
+ id: itemId,
522
+ output: typeof output === 'string' ? output : JSON.stringify(output).slice(0, 1000),
523
+ });
524
+ return;
525
+ }
526
+
480
527
  // final content fallback if no deltas were emitted
481
528
  const text = extractFinalText(params);
482
529
  if (text && !session.sawPartialAssistantText) {
@@ -549,10 +596,16 @@ function handleAppServerMessage(message, session) {
549
596
 
550
597
  if (method === 'item/started') {
551
598
  const itemType = params.item?.type || '';
552
- session._log?.info('codex item started', { itemType });
553
- if (itemType === 'toolCall' || itemType === 'commandExecution') {
554
- const toolName = params.item?.name || params.item?.tool || params.item?.command || '';
555
- const toolInput = params.item?.input || params.item?.arguments || {};
599
+ session._log?.info('codex item started', { itemType, item: summarizeCodexItemForLog(params.item) });
600
+ if (itemType === 'toolCall' || itemType === 'commandExecution' || itemType === 'webSearch') {
601
+ const isCommand = itemType === 'commandExecution';
602
+ const isWebSearch = itemType === 'webSearch';
603
+ const toolName = isCommand ? 'exec' : isWebSearch ? 'webSearch' : (params.item?.name || params.item?.tool || '');
604
+ const toolInput = isCommand
605
+ ? (params.item?.command || '')
606
+ : isWebSearch
607
+ ? (params.item?.query || params.item?.input || params.item?.arguments || {})
608
+ : (params.item?.input || params.item?.arguments || {});
556
609
  const itemId = params.item?.id || params.itemId || '';
557
610
  if (toolName) {
558
611
  send(ws, 'tool_call', {
@@ -595,6 +648,30 @@ function extractFinalText(params) {
595
648
  return '';
596
649
  }
597
650
 
651
+ function summarizeCodexItemForLog(item) {
652
+ if (!item || typeof item !== 'object') return {};
653
+ const summary = {};
654
+ for (const key of Object.keys(item)) {
655
+ const value = item[key];
656
+ if (typeof value === 'string') {
657
+ summary[key] = value.slice(0, 200);
658
+ } else if (Array.isArray(value)) {
659
+ summary[key] = `[array:${value.length}]`;
660
+ } else if (value && typeof value === 'object') {
661
+ summary[key] = `[object:${Object.keys(value).slice(0, 10).join(',')}]`;
662
+ } else {
663
+ summary[key] = value;
664
+ }
665
+ }
666
+ return summary;
667
+ }
668
+
669
+ function summarizeCodexParams(params) {
670
+ if (!params || typeof params !== 'object') return '';
671
+ const input = params.path || params.file || params.filePath || params.command || params.patch || params.diff || params.input || params;
672
+ return typeof input === 'string' ? input.slice(0, 1000) : JSON.stringify(input).slice(0, 1000);
673
+ }
674
+
598
675
  function buildCodexInput(input, workspace) {
599
676
  if (Array.isArray(input)) {
600
677
  const result = [];
@@ -36,7 +36,7 @@ function createLincoAdapter(rawWs, session, config) {
36
36
  }
37
37
  const payload = mapLocalEventToLinco(event, session, config, linco);
38
38
  if (!payload || closed.current) return;
39
- const wrapped = wrapLincoEnvelope(payload, config);
39
+ const wrapped = wrapLincoEnvelope(payload, config, session);
40
40
  if (Array.isArray(wrapped)) {
41
41
  for (const item of wrapped) rawWs.send(JSON.stringify(item));
42
42
  return;
@@ -55,11 +55,11 @@ function createLincoAdapter(rawWs, session, config) {
55
55
  };
56
56
  }
57
57
 
58
- function wrapLincoEnvelope(payload, config) {
58
+ function wrapLincoEnvelope(payload, config, session) {
59
59
  const meta = lincoMetaDefaults(config, {});
60
60
  return pruneUndefined({
61
61
  ...payload,
62
- from: payload.from || (config.agents ? Object.keys(config.agents)[0] : 'claude'),
62
+ from: payload.from || session?.agentType || (config.agents ? Object.keys(config.agents)[0] : 'claude'),
63
63
  to: payload.to || 'robot',
64
64
  source: payload.source || 'ws',
65
65
  ts: payload.ts || Date.now(),