ec-web 0.0.11 → 0.0.12

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.
@@ -66,16 +66,30 @@ function getStartTimeLinux(pid) {
66
66
  const starttimeJiffies = parseInt(tail.split(' ')[19], 10);
67
67
  if (isNaN(starttimeJiffies))
68
68
  return null;
69
- let uptimeSec;
69
+ // Use the kernel boot timestamp, the same source as EvolCore's process
70
+ // introspection. Deriving boot time as `Date.now() - /proc/uptime` can
71
+ // drift when the host clock is stepped while ECWeb is starting, producing
72
+ // instance records tens of seconds away from the real PID start time.
73
+ let bootSec = null;
70
74
  try {
71
- uptimeSec = parseFloat(fs.readFileSync('/proc/uptime', 'utf-8').split(' ')[0]);
75
+ const statContent = fs.readFileSync('/proc/stat', 'utf-8');
76
+ const match = statContent.match(/^btime\s+(\d+)$/m);
77
+ if (match)
78
+ bootSec = parseInt(match[1], 10);
72
79
  }
73
- catch {
74
- return null;
80
+ catch { }
81
+ if (!bootSec || !Number.isFinite(bootSec)) {
82
+ let uptimeSec;
83
+ try {
84
+ uptimeSec = parseFloat(fs.readFileSync('/proc/uptime', 'utf-8').split(' ')[0]);
85
+ }
86
+ catch {
87
+ return null;
88
+ }
89
+ bootSec = (Date.now() - uptimeSec * 1000) / 1000;
75
90
  }
76
91
  const clkTck = 100; // 几乎所有 Linux 为 100
77
- const bootMs = Date.now() - uptimeSec * 1000;
78
- return Math.round(bootMs + (starttimeJiffies / clkTck) * 1000);
92
+ return Math.round((bootSec + (starttimeJiffies / clkTck)) * 1000);
79
93
  }
80
94
  function getStartTimeMacOS(pid) {
81
95
  const r = spawnSync('ps', ['-o', 'lstart=', '-p', String(pid)], { encoding: 'utf-8', timeout: 3000 });
@@ -804,20 +804,35 @@ function selectedChats(chats, scope) {
804
804
  return [];
805
805
  return chats.filter(chat => scopeId(chat) === scope);
806
806
  }
807
+ export function messageDisplayRoute(message) {
808
+ if (message.chatType !== 'group') {
809
+ return { displayFrom: message.from, displayTo: message.to };
810
+ }
811
+ return {
812
+ displayFrom: message.dir === 'out' ? (message.selfAID || message.from) : message.from,
813
+ displayTo: message.groupName || message.groupId || message.to,
814
+ };
815
+ }
807
816
  function messagesFor(chats, peer, before, limit) {
808
817
  const selected = peer
809
818
  ? chats.filter(chat => chatKey(chat) === peer)
810
819
  : chats;
811
- const messages = selected.flatMap(chat => chat.messages.map(msg => ({
812
- ...msg,
813
- channel: chat.channel,
814
- channelType: chat.channelType,
815
- selfAID: chat.selfAID,
816
- peerName: chat.peerName,
817
- groupName: chat.groupName,
818
- partition: chat.partition,
819
- threadName: chat.threadName,
820
- })));
820
+ const messages = selected.flatMap(chat => chat.messages.map(msg => {
821
+ const message = {
822
+ ...msg,
823
+ channelType: chat.channelType,
824
+ selfAID: chat.selfAID,
825
+ peerName: chat.peerName,
826
+ groupName: chat.groupName,
827
+ };
828
+ return {
829
+ ...message,
830
+ channel: chat.channel,
831
+ partition: chat.partition,
832
+ threadName: chat.threadName,
833
+ ...messageDisplayRoute(message),
834
+ };
835
+ }));
821
836
  messages.sort((a, b) => (a.ts || 0) - (b.ts || 0));
822
837
  const end = before == null ? messages.length : Math.min(Math.max(before, 0), messages.length);
823
838
  const start = Math.max(0, end - limit);
@@ -892,7 +907,7 @@ async function buildSessionContext(chat) {
892
907
  }
893
908
  catch { }
894
909
  return {
895
- sessionId: active.agentSessionId || active.id || null,
910
+ sessionId: active.id || null,
896
911
  evolcoreSessionId: active.id || null,
897
912
  name: active.name || null,
898
913
  baseagent: active.baseagent || active.agentType || null,
@@ -278,7 +278,7 @@ const translations = {
278
278
  'messages.msgType.command': '命令',
279
279
  'messages.groupCount': '群 {count}',
280
280
  'messages.privateCount': '单 {count}',
281
- 'messages.session.field.sessionId': '会话 ID',
281
+ 'messages.session.field.sessionId': 'EvolCore 会话 ID',
282
282
  'messages.session.field.baseagent': 'Baseagent',
283
283
  'messages.session.field.chatMode': '模式',
284
284
  'messages.session.field.permissionMode': '权限',
@@ -633,6 +633,7 @@ const translations = {
633
633
  'triggers.error.promptRequired': 'Prompt 不能为空',
634
634
  'triggers.error.channelRequired': '目标渠道不能为空',
635
635
  'triggers.error.channelIdRequired': '渠道 ID 不能为空',
636
+ 'triggers.error.chatTypeRequired': 'AUN 目标必须选择私聊或群聊',
636
637
  'triggers.error.scriptPathRequired': '脚本路径不能为空',
637
638
  'triggers.error.scriptRuntimeRequired': '脚本运行时不能为空',
638
639
  'triggers.error.threadRequired': '指定话题会话时必须填写话题会话 ID',
@@ -681,6 +682,9 @@ const translations = {
681
682
  'triggers.delivery.off': '禁用',
682
683
  'triggers.field.targetChannel': '渠道实例',
683
684
  'triggers.field.channelId': '渠道 ID',
685
+ 'triggers.field.chatType': '会话类型',
686
+ 'triggers.chatType.private': '私聊',
687
+ 'triggers.chatType.group': '群聊',
684
688
  'triggers.field.sessionStrategy': '会话选择',
685
689
  'triggers.field.threadId': '话题会话 ID',
686
690
  'triggers.field.maxRuns': '最大执行次数',
@@ -1171,7 +1175,7 @@ const translations = {
1171
1175
  'messages.msgType.command': 'Command',
1172
1176
  'messages.groupCount': '{count} groups',
1173
1177
  'messages.privateCount': '{count} private',
1174
- 'messages.session.field.sessionId': 'Session ID',
1178
+ 'messages.session.field.sessionId': 'EvolCore Session ID',
1175
1179
  'messages.session.field.baseagent': 'Baseagent',
1176
1180
  'messages.session.field.chatMode': 'Mode',
1177
1181
  'messages.session.field.permissionMode': 'Perm',
@@ -1526,6 +1530,7 @@ const translations = {
1526
1530
  'triggers.error.promptRequired': 'Prompt is required',
1527
1531
  'triggers.error.channelRequired': 'Target channel is required',
1528
1532
  'triggers.error.channelIdRequired': 'Channel ID is required',
1533
+ 'triggers.error.chatTypeRequired': 'AUN targets require Private or Group chat type',
1529
1534
  'triggers.error.scriptPathRequired': 'Script path is required',
1530
1535
  'triggers.error.scriptRuntimeRequired': 'Script runtime is required',
1531
1536
  'triggers.error.threadRequired': 'Topic session ID is required',
@@ -1574,6 +1579,9 @@ const translations = {
1574
1579
  'triggers.delivery.off': 'Disabled',
1575
1580
  'triggers.field.targetChannel': 'Channel instance',
1576
1581
  'triggers.field.channelId': 'Channel ID',
1582
+ 'triggers.field.chatType': 'Chat Type',
1583
+ 'triggers.chatType.private': 'Private',
1584
+ 'triggers.chatType.group': 'Group',
1577
1585
  'triggers.field.sessionStrategy': 'Session Selection',
1578
1586
  'triggers.field.threadId': 'Topic Session ID',
1579
1587
  'triggers.field.maxRuns': 'Max Runs',
@@ -3244,7 +3252,7 @@ function renderMsg(data) {
3244
3252
  for (const m of messages) {
3245
3253
  const cls = m.dir === 'in' ? 'in' : 'out';
3246
3254
  const arrow = m.dir === 'in' ? '↓' : '↑';
3247
- const from = shortId(m.from), to = shortId(m.to);
3255
+ const from = shortId(m.displayFrom || m.from), to = shortId(m.displayTo || m.to);
3248
3256
  const tags = [];
3249
3257
  if (m.channelType) tags.push(m.channelType);
3250
3258
  if (m.chatType === 'group') tags.push(t('messages.tag.group'));
@@ -5383,6 +5391,10 @@ const TRIGGER_TARGET_SESSIONS = [
5383
5391
  ['main', () => t('triggers.session.main')],
5384
5392
  ['thread', () => t('triggers.session.thread')],
5385
5393
  ];
5394
+ const TRIGGER_TARGET_CHAT_TYPES = [
5395
+ ['private', () => t('triggers.chatType.private')],
5396
+ ['group', () => t('triggers.chatType.group')],
5397
+ ];
5386
5398
  const TRIGGER_CONCURRENCY_OPTIONS = [
5387
5399
  ['forbid', () => t('triggers.concurrency.forbid')],
5388
5400
  ['replace', () => t('triggers.concurrency.replace')],
@@ -5895,6 +5907,7 @@ function triggerPrimaryTarget(definition) {
5895
5907
  channelId: definition.origin.channelId || definition.origin.peerId || '',
5896
5908
  session: definition.origin.session || 'main',
5897
5909
  threadId: definition.origin.threadId || '',
5910
+ chatType: definition.origin.delivery?.chatType || '',
5898
5911
  };
5899
5912
  }
5900
5913
  return null;
@@ -5971,6 +5984,7 @@ function triggerOriginalEditState(t) {
5971
5984
  templateFailure: String(feedback.onFailure?.template ?? ''),
5972
5985
  targetChannel: String(target.channelKey ?? t?.targetChannel ?? ''),
5973
5986
  targetChannelId: String(target.channelId ?? t?.targetChannelId ?? ''),
5987
+ targetChatType: String(target.chatType ?? ''),
5974
5988
  targetSessionStrategy: triggerUiSessionStrategy(target.session ?? t?.targetSessionStrategy),
5975
5989
  targetThreadId: String(target.threadId ?? t?.targetThreadId ?? ''),
5976
5990
  maxRuns: limits.maxRuns == null ? '' : String(limits.maxRuns),
@@ -6860,6 +6874,7 @@ function readTriggerEditValues(root) {
6860
6874
  templateFailure: root.querySelector('#trig-edit-template-failure')?.value || '',
6861
6875
  targetChannel: (root.querySelector('#trig-edit-channel')?.value || '').trim(),
6862
6876
  targetChannelId: (root.querySelector('#trig-edit-channel-id')?.value || '').trim(),
6877
+ targetChatType: root.querySelector('#trig-edit-chat-type')?.value || '',
6863
6878
  targetSessionStrategy: root.querySelector('#trig-edit-session-strategy')?.value || 'main',
6864
6879
  targetThreadId: (root.querySelector('#trig-edit-thread')?.value || '').trim(),
6865
6880
  maxRuns: (root.querySelector('#trig-edit-max-runs')?.value || '').trim(),
@@ -6929,6 +6944,7 @@ function triggerEditScheduleChanged(original, values) {
6929
6944
  function triggerEditTargetChanged(original, values) {
6930
6945
  return values.targetChannel !== original.targetChannel
6931
6946
  || values.targetChannelId !== original.targetChannelId
6947
+ || values.targetChatType !== original.targetChatType
6932
6948
  || values.targetSessionStrategy !== original.targetSessionStrategy
6933
6949
  || values.targetThreadId !== original.targetThreadId;
6934
6950
  }
@@ -6995,6 +7011,8 @@ function triggerDefinitionFromEdit(original, values, eventFilter, feedbackStrate
6995
7011
  const target = triggerEditableObject(feedback.target);
6996
7012
  target.channelKey = values.targetChannel;
6997
7013
  target.channelId = values.targetChannelId;
7014
+ if (values.targetChatType) target.chatType = values.targetChatType;
7015
+ else delete target.chatType;
6998
7016
  target.session = values.targetSessionStrategy;
6999
7017
  if (values.targetSessionStrategy === 'thread') target.threadId = values.targetThreadId;
7000
7018
  else delete target.threadId;
@@ -7068,6 +7086,9 @@ function collectTriggerEditPatch(ctx) {
7068
7086
  if (feedbackStrategy === 'target') {
7069
7087
  if (!values.targetChannel) return { error: t('triggers.error.channelRequired') };
7070
7088
  if (!values.targetChannelId) return { error: t('triggers.error.channelIdRequired') };
7089
+ if ((values.targetChannel === 'aun' || values.targetChannel.startsWith('aun#')) && !values.targetChatType) {
7090
+ return { error: t('triggers.error.chatTypeRequired') };
7091
+ }
7071
7092
  if (values.targetSessionStrategy === 'thread' && !values.targetThreadId) return { error: t('triggers.error.threadRequired') };
7072
7093
  }
7073
7094
  if (values.maxRuns) {
@@ -7213,6 +7234,7 @@ function openTriggerEditDrawer(id, agent) {
7213
7234
  `<div id="trig-edit-target-fields" class="ag-edit-grid trig-edit-grid">` +
7214
7235
  `<label class="ag-edit-field"><span>${t('triggers.field.targetChannel')}</span><select id="trig-edit-channel">${channelOptions}</select></label>` +
7215
7236
  `<label class="ag-edit-field"><span>${t('triggers.field.channelId')}</span><input id="trig-edit-channel-id" type="text" autocomplete="off" spellcheck="false" value="${esc(original.targetChannelId)}"></label>` +
7237
+ `<label class="ag-edit-field"><span>${t('triggers.field.chatType')}</span><select id="trig-edit-chat-type">${triggerOptionHtml(TRIGGER_TARGET_CHAT_TYPES, original.targetChatType, t('common.none'))}</select></label>` +
7216
7238
  `<label class="ag-edit-field"><span>${t('triggers.field.sessionStrategy')}</span><select id="trig-edit-session-strategy">${triggerOptionHtml(TRIGGER_TARGET_SESSIONS, original.targetSessionStrategy, null)}</select></label>` +
7217
7239
  `<label id="trig-edit-thread-field" class="ag-edit-field ag-edit-field-wide"><span>${t('triggers.field.threadId')}</span><input id="trig-edit-thread" type="text" autocomplete="off" spellcheck="false" value="${esc(original.targetThreadId)}"></label>` +
7218
7240
  `</div>` +
@@ -48,7 +48,7 @@
48
48
 
49
49
  </nav>
50
50
  <span style="flex:1"></span>
51
- 2026-08-19 05:07
51
+ 2026-08-21 14:14
52
52
  <span id="conn-status" class="conn-status" data-i18n="status.connecting">连接中…</span>
53
53
  <button id="lang-btn" class="theme-btn" data-i18n-title="language.buttonTitle" title="切换语言">🌐</button>
54
54
  <button id="theme-btn" class="theme-btn" data-i18n-title="theme.buttonTitle" title="主题">🌗</button>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ec-web",
3
- "version": "0.0.11",
3
+ "version": "0.0.12",
4
4
  "description": "Web console and monitoring dashboard for EvolCore",
5
5
  "type": "module",
6
6
  "bin": {