ec-web 0.0.11 → 0.0.14
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/dist/process-utils.js +20 -6
- package/dist/sources/msg.js +26 -11
- package/dist/sources/session-codex.js +37 -4
- package/dist/static/app.js +98 -9
- package/dist/static/index.html +1 -1
- package/dist/static/style.css +1 -1
- package/package.json +1 -1
package/dist/process-utils.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 });
|
package/dist/sources/msg.js
CHANGED
|
@@ -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
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
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.
|
|
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,
|
|
@@ -430,16 +430,49 @@ function toolOutputText(output) {
|
|
|
430
430
|
return String(output);
|
|
431
431
|
}
|
|
432
432
|
}
|
|
433
|
-
function
|
|
433
|
+
function firstString(...values) {
|
|
434
|
+
return values.find((value) => typeof value === 'string' && value.trim().length > 0)?.trim();
|
|
435
|
+
}
|
|
436
|
+
function approvalAuditFromPayload(payload) {
|
|
437
|
+
const candidates = [
|
|
438
|
+
payload.approval,
|
|
439
|
+
payload.approvalAudit,
|
|
440
|
+
payload.approval_audit,
|
|
441
|
+
payload.metadata,
|
|
442
|
+
payload.meta,
|
|
443
|
+
payload,
|
|
444
|
+
].filter((value) => !!value && typeof value === 'object' && !Array.isArray(value));
|
|
445
|
+
const value = (key) => candidates.map(candidate => candidate[key]).find(candidate => candidate !== undefined);
|
|
446
|
+
const requestId = firstString(value('requestId'), value('request_id'), value('approvalRequestId'), value('approval_request_id'));
|
|
447
|
+
const method = firstString(value('method'), value('approvalMethod'), value('approval_method'));
|
|
448
|
+
const decision = firstString(value('decision'), value('approvalDecision'), value('approval_decision'));
|
|
449
|
+
const decisionSource = firstString(value('decisionSource'), value('decision_source'), value('approver'), value('approverType'));
|
|
450
|
+
const policyCode = firstString(value('policyCode'), value('policy_code'));
|
|
451
|
+
return {
|
|
452
|
+
available: !!(requestId || method || decision || decisionSource || policyCode),
|
|
453
|
+
...(requestId ? { requestId } : {}),
|
|
454
|
+
...(method ? { method } : {}),
|
|
455
|
+
...(decision ? { decision } : {}),
|
|
456
|
+
...(decisionSource ? { decisionSource } : {}),
|
|
457
|
+
...(policyCode ? { policyCode } : {}),
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
function classifyCodexToolRejection(text, payload) {
|
|
434
461
|
const normalized = text.replace(/\\(["'])/g, '$1');
|
|
435
462
|
if (!/Rejected\(\s*["']rejected by user["']\s*\)/i.test(normalized))
|
|
436
463
|
return undefined;
|
|
437
|
-
const
|
|
464
|
+
const audit = approvalAuditFromPayload(payload);
|
|
465
|
+
const source = audit.policyCode || audit.decisionSource?.toLowerCase().includes('policy')
|
|
466
|
+
? 'evolcore-policy'
|
|
467
|
+
: 'codex-approval';
|
|
438
468
|
return {
|
|
439
469
|
kind: 'approval_rejected',
|
|
440
|
-
source
|
|
470
|
+
source,
|
|
441
471
|
reason: 'rejected_by_user',
|
|
442
472
|
executed: false,
|
|
473
|
+
evidence: audit.available ? 'structured_metadata' : 'backend_text',
|
|
474
|
+
backendReason: 'Rejected("rejected by user")',
|
|
475
|
+
audit,
|
|
443
476
|
};
|
|
444
477
|
}
|
|
445
478
|
export function parseCodexToolEvent(event) {
|
|
@@ -470,7 +503,7 @@ export function parseCodexToolEvent(event) {
|
|
|
470
503
|
}
|
|
471
504
|
if (payload.type === 'function_call_output' || payload.type === 'custom_tool_call_output') {
|
|
472
505
|
const text = toolOutputText(payload.output);
|
|
473
|
-
const rejection = classifyCodexToolRejection(text);
|
|
506
|
+
const rejection = classifyCodexToolRejection(text, payload);
|
|
474
507
|
return {
|
|
475
508
|
kind: 'result',
|
|
476
509
|
callId,
|
package/dist/static/app.js
CHANGED
|
@@ -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': '权限',
|
|
@@ -346,7 +346,13 @@ const translations = {
|
|
|
346
346
|
'sessions.block.rejection.source.policy': 'EvolCore 策略自动拦截',
|
|
347
347
|
'sessions.block.rejection.source.approval': '审批通道拒绝',
|
|
348
348
|
'sessions.block.rejection.notExecuted': '命令未执行',
|
|
349
|
-
'sessions.block.rejection.
|
|
349
|
+
'sessions.block.rejection.evidence.backend': '仅有底层文本证据,未提供审批审计',
|
|
350
|
+
'sessions.block.rejection.evidence.structured': '已提供结构化审批审计',
|
|
351
|
+
'sessions.block.rejection.audit.requestId': 'request_id',
|
|
352
|
+
'sessions.block.rejection.audit.method': 'method',
|
|
353
|
+
'sessions.block.rejection.audit.decision': 'decision',
|
|
354
|
+
'sessions.block.rejection.audit.source': 'decision_source',
|
|
355
|
+
'sessions.block.rejection.audit.policy': 'policy_code',
|
|
350
356
|
'sessions.content.expand': '展开内容',
|
|
351
357
|
'sessions.content.collapse': '收起内容',
|
|
352
358
|
'sessions.contextTitle': '最后一轮喂给模型的完整上下文大小',
|
|
@@ -633,6 +639,7 @@ const translations = {
|
|
|
633
639
|
'triggers.error.promptRequired': 'Prompt 不能为空',
|
|
634
640
|
'triggers.error.channelRequired': '目标渠道不能为空',
|
|
635
641
|
'triggers.error.channelIdRequired': '渠道 ID 不能为空',
|
|
642
|
+
'triggers.error.chatTypeRequired': 'AUN 目标必须选择私聊或群聊',
|
|
636
643
|
'triggers.error.scriptPathRequired': '脚本路径不能为空',
|
|
637
644
|
'triggers.error.scriptRuntimeRequired': '脚本运行时不能为空',
|
|
638
645
|
'triggers.error.threadRequired': '指定话题会话时必须填写话题会话 ID',
|
|
@@ -681,6 +688,9 @@ const translations = {
|
|
|
681
688
|
'triggers.delivery.off': '禁用',
|
|
682
689
|
'triggers.field.targetChannel': '渠道实例',
|
|
683
690
|
'triggers.field.channelId': '渠道 ID',
|
|
691
|
+
'triggers.field.chatType': '会话类型',
|
|
692
|
+
'triggers.chatType.private': '私聊',
|
|
693
|
+
'triggers.chatType.group': '群聊',
|
|
684
694
|
'triggers.field.sessionStrategy': '会话选择',
|
|
685
695
|
'triggers.field.threadId': '话题会话 ID',
|
|
686
696
|
'triggers.field.maxRuns': '最大执行次数',
|
|
@@ -1171,7 +1181,7 @@ const translations = {
|
|
|
1171
1181
|
'messages.msgType.command': 'Command',
|
|
1172
1182
|
'messages.groupCount': '{count} groups',
|
|
1173
1183
|
'messages.privateCount': '{count} private',
|
|
1174
|
-
'messages.session.field.sessionId': 'Session ID',
|
|
1184
|
+
'messages.session.field.sessionId': 'EvolCore Session ID',
|
|
1175
1185
|
'messages.session.field.baseagent': 'Baseagent',
|
|
1176
1186
|
'messages.session.field.chatMode': 'Mode',
|
|
1177
1187
|
'messages.session.field.permissionMode': 'Perm',
|
|
@@ -1239,7 +1249,13 @@ const translations = {
|
|
|
1239
1249
|
'sessions.block.rejection.source.policy': 'EvolCore policy auto-blocked',
|
|
1240
1250
|
'sessions.block.rejection.source.approval': 'Approval channel rejected',
|
|
1241
1251
|
'sessions.block.rejection.notExecuted': 'Command was not executed',
|
|
1242
|
-
'sessions.block.rejection.
|
|
1252
|
+
'sessions.block.rejection.evidence.backend': 'Backend text only; approval audit unavailable',
|
|
1253
|
+
'sessions.block.rejection.evidence.structured': 'Structured approval audit available',
|
|
1254
|
+
'sessions.block.rejection.audit.requestId': 'request_id',
|
|
1255
|
+
'sessions.block.rejection.audit.method': 'method',
|
|
1256
|
+
'sessions.block.rejection.audit.decision': 'decision',
|
|
1257
|
+
'sessions.block.rejection.audit.source': 'decision_source',
|
|
1258
|
+
'sessions.block.rejection.audit.policy': 'policy_code',
|
|
1243
1259
|
'sessions.content.expand': 'Expand content',
|
|
1244
1260
|
'sessions.content.collapse': 'Collapse content',
|
|
1245
1261
|
'sessions.contextTitle': 'Full context size sent to the model in the last turn',
|
|
@@ -1526,6 +1542,7 @@ const translations = {
|
|
|
1526
1542
|
'triggers.error.promptRequired': 'Prompt is required',
|
|
1527
1543
|
'triggers.error.channelRequired': 'Target channel is required',
|
|
1528
1544
|
'triggers.error.channelIdRequired': 'Channel ID is required',
|
|
1545
|
+
'triggers.error.chatTypeRequired': 'AUN targets require Private or Group chat type',
|
|
1529
1546
|
'triggers.error.scriptPathRequired': 'Script path is required',
|
|
1530
1547
|
'triggers.error.scriptRuntimeRequired': 'Script runtime is required',
|
|
1531
1548
|
'triggers.error.threadRequired': 'Topic session ID is required',
|
|
@@ -1574,6 +1591,9 @@ const translations = {
|
|
|
1574
1591
|
'triggers.delivery.off': 'Disabled',
|
|
1575
1592
|
'triggers.field.targetChannel': 'Channel instance',
|
|
1576
1593
|
'triggers.field.channelId': 'Channel ID',
|
|
1594
|
+
'triggers.field.chatType': 'Chat Type',
|
|
1595
|
+
'triggers.chatType.private': 'Private',
|
|
1596
|
+
'triggers.chatType.group': 'Group',
|
|
1577
1597
|
'triggers.field.sessionStrategy': 'Session Selection',
|
|
1578
1598
|
'triggers.field.threadId': 'Topic Session ID',
|
|
1579
1599
|
'triggers.field.maxRuns': 'Max Runs',
|
|
@@ -2290,6 +2310,41 @@ function renderLogFields(fields) {
|
|
|
2290
2310
|
).join('')}</span>`;
|
|
2291
2311
|
}
|
|
2292
2312
|
|
|
2313
|
+
function logEntryKey(line) {
|
|
2314
|
+
const text = `${line.file || ''}|${line.timestamp || ''}|${line.raw || ''}`;
|
|
2315
|
+
let hash = 2166136261;
|
|
2316
|
+
for (let index = 0; index < text.length; index++) {
|
|
2317
|
+
hash = Math.imul(hash ^ text.charCodeAt(index), 16777619);
|
|
2318
|
+
}
|
|
2319
|
+
return `${(hash >>> 0).toString(36)}-${text.length.toString(36)}`;
|
|
2320
|
+
}
|
|
2321
|
+
|
|
2322
|
+
function captureLogScrollAnchor(stream) {
|
|
2323
|
+
if (logSel.follow || !stream) return null;
|
|
2324
|
+
const scrollTop = stream.scrollTop;
|
|
2325
|
+
const streamTop = stream.getBoundingClientRect().top;
|
|
2326
|
+
const entry = [...stream.querySelectorAll('.log-entry')]
|
|
2327
|
+
.find(item => item.getBoundingClientRect().bottom > streamTop);
|
|
2328
|
+
return {
|
|
2329
|
+
key: entry?.dataset.logKey || null,
|
|
2330
|
+
offset: entry ? entry.getBoundingClientRect().top - streamTop : 0,
|
|
2331
|
+
scrollTop,
|
|
2332
|
+
};
|
|
2333
|
+
}
|
|
2334
|
+
|
|
2335
|
+
function restoreLogScrollAnchor(stream, anchor) {
|
|
2336
|
+
if (!stream || !anchor || logSel.follow) return;
|
|
2337
|
+
const entry = anchor.key
|
|
2338
|
+
? [...stream.querySelectorAll('.log-entry')].find(item => item.dataset.logKey === anchor.key)
|
|
2339
|
+
: null;
|
|
2340
|
+
if (!entry) {
|
|
2341
|
+
stream.scrollTop = anchor.scrollTop;
|
|
2342
|
+
return;
|
|
2343
|
+
}
|
|
2344
|
+
const currentOffset = entry.getBoundingClientRect().top - stream.getBoundingClientRect().top;
|
|
2345
|
+
stream.scrollTop += currentOffset - anchor.offset;
|
|
2346
|
+
}
|
|
2347
|
+
|
|
2293
2348
|
function bindLogControls() {
|
|
2294
2349
|
const source = $('#log-source');
|
|
2295
2350
|
const level = $('#log-level');
|
|
@@ -2341,6 +2396,7 @@ function renderLogs(data) {
|
|
|
2341
2396
|
const filterResult = $('#log-filter-result');
|
|
2342
2397
|
const stream = $('#log-stream');
|
|
2343
2398
|
if (!source || !stream) return;
|
|
2399
|
+
const scrollAnchor = captureLogScrollAnchor(stream);
|
|
2344
2400
|
bindLogControls();
|
|
2345
2401
|
level.value = logSel.level;
|
|
2346
2402
|
search.value = logSel.search;
|
|
@@ -2423,7 +2479,7 @@ function renderLogs(data) {
|
|
|
2423
2479
|
const event = line.event ? `<span class="log-event">${esc(line.event)}</span>` : '';
|
|
2424
2480
|
const actor = line.actor ? `<span class="log-actor" title="${esc(line.actor)}">${esc(shortAid(line.actor))}</span>` : '';
|
|
2425
2481
|
const message = line.message || (!line.fields?.length ? line.raw : '');
|
|
2426
|
-
return `<div class="log-entry log-entry-${lineLevel}">` +
|
|
2482
|
+
return `<div class="log-entry log-entry-${lineLevel}" data-log-key="${esc(logEntryKey(line))}">` +
|
|
2427
2483
|
'<div class="log-line">' +
|
|
2428
2484
|
`<time class="log-time" title="${esc(line.timestamp || '')}">${esc(formatLogTime(line.timestamp))}</time>` +
|
|
2429
2485
|
`<span class="log-level log-level-${lineLevel}">[${esc(levelLabel)}]</span>` +
|
|
@@ -2433,6 +2489,7 @@ function renderLogs(data) {
|
|
|
2433
2489
|
'</div>';
|
|
2434
2490
|
}).join('');
|
|
2435
2491
|
if (logSel.follow) stream.scrollTop = stream.scrollHeight;
|
|
2492
|
+
else restoreLogScrollAnchor(stream, scrollAnchor);
|
|
2436
2493
|
}
|
|
2437
2494
|
|
|
2438
2495
|
// ── 工具 ──
|
|
@@ -3244,7 +3301,7 @@ function renderMsg(data) {
|
|
|
3244
3301
|
for (const m of messages) {
|
|
3245
3302
|
const cls = m.dir === 'in' ? 'in' : 'out';
|
|
3246
3303
|
const arrow = m.dir === 'in' ? '↓' : '↑';
|
|
3247
|
-
const from = shortId(m.from), to = shortId(m.to);
|
|
3304
|
+
const from = shortId(m.displayFrom || m.from), to = shortId(m.displayTo || m.to);
|
|
3248
3305
|
const tags = [];
|
|
3249
3306
|
if (m.channelType) tags.push(m.channelType);
|
|
3250
3307
|
if (m.chatType === 'group') tags.push(t('messages.tag.group'));
|
|
@@ -3698,12 +3755,30 @@ function renderBlocks(blocks, options = {}) {
|
|
|
3698
3755
|
? `<button class="ctrl-btn result-load-full" type="button" data-result-key="${esc(b.resultKey)}">${t('sessions.loadFullResult') || '加载完整结果'}</button>`
|
|
3699
3756
|
: '';
|
|
3700
3757
|
const rejectionMeta = rejection
|
|
3701
|
-
?
|
|
3758
|
+
? (() => {
|
|
3759
|
+
const audit = rejection.audit && typeof rejection.audit === 'object' ? rejection.audit : {};
|
|
3760
|
+
const auditFields = [
|
|
3761
|
+
['requestId', 'requestId'],
|
|
3762
|
+
['method', 'method'],
|
|
3763
|
+
['decision', 'decision'],
|
|
3764
|
+
['decisionSource', 'source'],
|
|
3765
|
+
['policyCode', 'policy'],
|
|
3766
|
+
].filter(([key]) => typeof audit[key] === 'string' && audit[key]);
|
|
3767
|
+
const auditText = auditFields
|
|
3768
|
+
.map(([key, labelKey]) => `<span class="result-rejection-audit"><code>${t(`sessions.block.rejection.audit.${labelKey}`)}</code>=${esc(audit[key])}</span>`)
|
|
3769
|
+
.join('');
|
|
3770
|
+
const evidenceKey = rejection.evidence === 'structured_metadata' ? 'structured' : 'backend';
|
|
3771
|
+
const backendReason = typeof rejection.backendReason === 'string' && rejection.backendReason
|
|
3772
|
+
? `<span class="result-rejection-reason">${esc(rejection.backendReason)}</span>`
|
|
3773
|
+
: '';
|
|
3774
|
+
return '<div class="result-rejection-meta">' +
|
|
3702
3775
|
`<span class="result-rejection-badge">⚠ ${t('sessions.block.rejection.title')}</span>` +
|
|
3703
3776
|
`<span>${rejection.source === 'evolcore-policy' ? t('sessions.block.rejection.source.policy') : t('sessions.block.rejection.source.approval')}</span>` +
|
|
3704
3777
|
`<span>${t('sessions.block.rejection.notExecuted')}</span>` +
|
|
3705
|
-
`<span
|
|
3706
|
-
|
|
3778
|
+
`<span>${t(`sessions.block.rejection.evidence.${evidenceKey}`)}</span>` +
|
|
3779
|
+
backendReason + auditText +
|
|
3780
|
+
'</div>';
|
|
3781
|
+
})()
|
|
3707
3782
|
: '';
|
|
3708
3783
|
const resultLabel = rejection
|
|
3709
3784
|
? t('sessions.block.rejection.title')
|
|
@@ -5383,6 +5458,10 @@ const TRIGGER_TARGET_SESSIONS = [
|
|
|
5383
5458
|
['main', () => t('triggers.session.main')],
|
|
5384
5459
|
['thread', () => t('triggers.session.thread')],
|
|
5385
5460
|
];
|
|
5461
|
+
const TRIGGER_TARGET_CHAT_TYPES = [
|
|
5462
|
+
['private', () => t('triggers.chatType.private')],
|
|
5463
|
+
['group', () => t('triggers.chatType.group')],
|
|
5464
|
+
];
|
|
5386
5465
|
const TRIGGER_CONCURRENCY_OPTIONS = [
|
|
5387
5466
|
['forbid', () => t('triggers.concurrency.forbid')],
|
|
5388
5467
|
['replace', () => t('triggers.concurrency.replace')],
|
|
@@ -5895,6 +5974,7 @@ function triggerPrimaryTarget(definition) {
|
|
|
5895
5974
|
channelId: definition.origin.channelId || definition.origin.peerId || '',
|
|
5896
5975
|
session: definition.origin.session || 'main',
|
|
5897
5976
|
threadId: definition.origin.threadId || '',
|
|
5977
|
+
chatType: definition.origin.delivery?.chatType || '',
|
|
5898
5978
|
};
|
|
5899
5979
|
}
|
|
5900
5980
|
return null;
|
|
@@ -5971,6 +6051,7 @@ function triggerOriginalEditState(t) {
|
|
|
5971
6051
|
templateFailure: String(feedback.onFailure?.template ?? ''),
|
|
5972
6052
|
targetChannel: String(target.channelKey ?? t?.targetChannel ?? ''),
|
|
5973
6053
|
targetChannelId: String(target.channelId ?? t?.targetChannelId ?? ''),
|
|
6054
|
+
targetChatType: String(target.chatType ?? ''),
|
|
5974
6055
|
targetSessionStrategy: triggerUiSessionStrategy(target.session ?? t?.targetSessionStrategy),
|
|
5975
6056
|
targetThreadId: String(target.threadId ?? t?.targetThreadId ?? ''),
|
|
5976
6057
|
maxRuns: limits.maxRuns == null ? '' : String(limits.maxRuns),
|
|
@@ -6860,6 +6941,7 @@ function readTriggerEditValues(root) {
|
|
|
6860
6941
|
templateFailure: root.querySelector('#trig-edit-template-failure')?.value || '',
|
|
6861
6942
|
targetChannel: (root.querySelector('#trig-edit-channel')?.value || '').trim(),
|
|
6862
6943
|
targetChannelId: (root.querySelector('#trig-edit-channel-id')?.value || '').trim(),
|
|
6944
|
+
targetChatType: root.querySelector('#trig-edit-chat-type')?.value || '',
|
|
6863
6945
|
targetSessionStrategy: root.querySelector('#trig-edit-session-strategy')?.value || 'main',
|
|
6864
6946
|
targetThreadId: (root.querySelector('#trig-edit-thread')?.value || '').trim(),
|
|
6865
6947
|
maxRuns: (root.querySelector('#trig-edit-max-runs')?.value || '').trim(),
|
|
@@ -6929,6 +7011,7 @@ function triggerEditScheduleChanged(original, values) {
|
|
|
6929
7011
|
function triggerEditTargetChanged(original, values) {
|
|
6930
7012
|
return values.targetChannel !== original.targetChannel
|
|
6931
7013
|
|| values.targetChannelId !== original.targetChannelId
|
|
7014
|
+
|| values.targetChatType !== original.targetChatType
|
|
6932
7015
|
|| values.targetSessionStrategy !== original.targetSessionStrategy
|
|
6933
7016
|
|| values.targetThreadId !== original.targetThreadId;
|
|
6934
7017
|
}
|
|
@@ -6995,6 +7078,8 @@ function triggerDefinitionFromEdit(original, values, eventFilter, feedbackStrate
|
|
|
6995
7078
|
const target = triggerEditableObject(feedback.target);
|
|
6996
7079
|
target.channelKey = values.targetChannel;
|
|
6997
7080
|
target.channelId = values.targetChannelId;
|
|
7081
|
+
if (values.targetChatType) target.chatType = values.targetChatType;
|
|
7082
|
+
else delete target.chatType;
|
|
6998
7083
|
target.session = values.targetSessionStrategy;
|
|
6999
7084
|
if (values.targetSessionStrategy === 'thread') target.threadId = values.targetThreadId;
|
|
7000
7085
|
else delete target.threadId;
|
|
@@ -7068,6 +7153,9 @@ function collectTriggerEditPatch(ctx) {
|
|
|
7068
7153
|
if (feedbackStrategy === 'target') {
|
|
7069
7154
|
if (!values.targetChannel) return { error: t('triggers.error.channelRequired') };
|
|
7070
7155
|
if (!values.targetChannelId) return { error: t('triggers.error.channelIdRequired') };
|
|
7156
|
+
if ((values.targetChannel === 'aun' || values.targetChannel.startsWith('aun#')) && !values.targetChatType) {
|
|
7157
|
+
return { error: t('triggers.error.chatTypeRequired') };
|
|
7158
|
+
}
|
|
7071
7159
|
if (values.targetSessionStrategy === 'thread' && !values.targetThreadId) return { error: t('triggers.error.threadRequired') };
|
|
7072
7160
|
}
|
|
7073
7161
|
if (values.maxRuns) {
|
|
@@ -7213,6 +7301,7 @@ function openTriggerEditDrawer(id, agent) {
|
|
|
7213
7301
|
`<div id="trig-edit-target-fields" class="ag-edit-grid trig-edit-grid">` +
|
|
7214
7302
|
`<label class="ag-edit-field"><span>${t('triggers.field.targetChannel')}</span><select id="trig-edit-channel">${channelOptions}</select></label>` +
|
|
7215
7303
|
`<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>` +
|
|
7304
|
+
`<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
7305
|
`<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
7306
|
`<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
7307
|
`</div>` +
|
package/dist/static/index.html
CHANGED
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
|
|
49
49
|
</nav>
|
|
50
50
|
<span style="flex:1"></span>
|
|
51
|
-
2026-08-
|
|
51
|
+
2026-08-25 01:10
|
|
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/dist/static/style.css
CHANGED
|
@@ -199,7 +199,7 @@ body {
|
|
|
199
199
|
.log-live i { width: 7px; height: 7px; border-radius: 50%; background: var(--green); box-shadow: 0 0 0 3px color-mix(in srgb, var(--green) 15%, transparent); }
|
|
200
200
|
.log-meta { display: flex; justify-content: space-between; gap: 12px; padding: 7px 16px; color: var(--dim); font-size: 11px; border-top: 1px solid var(--border); background: var(--bg2); flex-shrink: 0; font-variant-numeric: tabular-nums; }
|
|
201
201
|
.log-meta-status { display: inline-flex; align-items: center; gap: 16px; margin-left: auto; }
|
|
202
|
-
.log-stream { flex: 1; min-height: 0; overflow: auto; padding: 6px 0 16px; background: var(--bg); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 11px; line-height: 1.5; }
|
|
202
|
+
.log-stream { flex: 1; min-height: 0; overflow: auto; overflow-anchor: none; padding: 6px 0 16px; background: var(--bg); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 11px; line-height: 1.5; }
|
|
203
203
|
.log-entry { border-bottom: 1px solid color-mix(in srgb, var(--border) 55%, transparent); }
|
|
204
204
|
.log-line { display: grid; grid-template-columns: 112px 56px 150px minmax(320px, 1fr); gap: 10px; padding: 4px 16px; align-items: start; }
|
|
205
205
|
.log-line:hover { background: var(--bg2); }
|