ec-web 0.0.20 → 0.0.22
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/ipc-client.js +7 -1
- package/dist/paths.js +18 -1
- package/dist/server.js +159 -28
- package/dist/sources/aid.js +69 -49
- package/dist/sources/baseagent-detector.js +60 -6
- package/dist/sources/basic-settings.js +818 -0
- package/dist/sources/gateway.js +5 -4
- package/dist/sources/monitor.js +22 -5
- package/dist/sources/msg.js +4 -96
- package/dist/sources/relation-roles.js +216 -207
- package/dist/sources/role-definitions.js +162 -331
- package/dist/sources/session-codex.js +207 -84
- package/dist/sources/system.js +10 -9
- package/dist/sources/triggers.js +82 -13
- package/dist/sources/types.js +20 -1
- package/dist/static/app.js +175 -15
- package/dist/static/basic-settings.js +1576 -0
- package/dist/static/index.html +43 -1
- package/dist/static/style.css +586 -2
- package/ecweb-wrapper.cjs +5 -1
- package/package.json +1 -1
package/dist/static/app.js
CHANGED
|
@@ -92,6 +92,28 @@ const translations = {
|
|
|
92
92
|
'common.online': '在线',
|
|
93
93
|
'common.offline': '离线',
|
|
94
94
|
'common.ago': '前',
|
|
95
|
+
'basicSettings.open': '基础设置',
|
|
96
|
+
'basicSettings.openTitle': '打开基础设置',
|
|
97
|
+
'basicSettings.title': '基础设置',
|
|
98
|
+
'basicSettings.subtitle': '按用途组织参数。保存前会校验并保留未编辑字段。',
|
|
99
|
+
'basicSettings.reload': '重新读取',
|
|
100
|
+
'basicSettings.tabs.models': '模型与推理',
|
|
101
|
+
'basicSettings.tabs.modelsHint': '基座、模型与连接',
|
|
102
|
+
'basicSettings.tabs.response': '响应与会话',
|
|
103
|
+
'basicSettings.tabs.responseHint': '响应方式与续接',
|
|
104
|
+
'basicSettings.tabs.projects': '项目与服务',
|
|
105
|
+
'basicSettings.tabs.projectsHint': '路径与本机服务',
|
|
106
|
+
'basicSettings.tabs.identity': '身份与安全',
|
|
107
|
+
'basicSettings.tabs.identityHint': 'AID 与访问保护',
|
|
108
|
+
'basicSettings.tabs.runtime': '运行与诊断',
|
|
109
|
+
'basicSettings.tabs.runtimeHint': '日志与稳定性',
|
|
110
|
+
'basicSettings.noChanges': '没有需要保存的改动',
|
|
111
|
+
'basicSettings.viewJson': '查看 JSON',
|
|
112
|
+
'basicSettings.save': '保存设置',
|
|
113
|
+
'basicSettings.jsonTitle': '查看 JSON',
|
|
114
|
+
'basicSettings.jsonSubtitle': '只读预览,敏感值已脱敏。',
|
|
115
|
+
'basicSettings.daemonFile': 'daemon.json',
|
|
116
|
+
'basicSettings.defaultsFile': 'agents/defaults.json',
|
|
95
117
|
'theme.light': '浅色模式',
|
|
96
118
|
'theme.dark': '深色模式',
|
|
97
119
|
'theme.system': '跟随系统',
|
|
@@ -587,6 +609,8 @@ const translations = {
|
|
|
587
609
|
'triggers.history.field.payload': '事件数据',
|
|
588
610
|
'triggers.history.field.sessionId': '会话 ID',
|
|
589
611
|
'triggers.history.field.messageId': '消息 ID',
|
|
612
|
+
'triggers.history.field.operationId': '操作 ID',
|
|
613
|
+
'triggers.history.field.outboxId': 'Outbox ID',
|
|
590
614
|
'triggers.history.field.handoffId': 'Handoff ID',
|
|
591
615
|
'triggers.history.field.attempt': '尝试次数',
|
|
592
616
|
'triggers.history.field.triggerId': 'Trigger ID',
|
|
@@ -609,8 +633,9 @@ const translations = {
|
|
|
609
633
|
'triggers.history.outcome.error': '错误',
|
|
610
634
|
'triggers.history.outcome.interrupted': '已中断',
|
|
611
635
|
'triggers.history.outcome.timeout': '超时',
|
|
636
|
+
'triggers.history.outcome.queued': '已入队',
|
|
612
637
|
'triggers.history.effect.message.send': '发送消息',
|
|
613
|
-
'triggers.history.effect.handoff.enqueue': '
|
|
638
|
+
'triggers.history.effect.handoff.enqueue': 'Handoff 投递',
|
|
614
639
|
'triggers.history.effect.message.inbound': '注入目标会话',
|
|
615
640
|
'triggers.history.effect.agent.conversation': 'Agent 对话',
|
|
616
641
|
'triggers.runStatus.completed': '成功',
|
|
@@ -998,6 +1023,28 @@ const translations = {
|
|
|
998
1023
|
'common.online': 'Online',
|
|
999
1024
|
'common.offline': 'Offline',
|
|
1000
1025
|
'common.ago': 'ago',
|
|
1026
|
+
'basicSettings.open': 'Settings',
|
|
1027
|
+
'basicSettings.openTitle': 'Open basic settings',
|
|
1028
|
+
'basicSettings.title': 'Basic Settings',
|
|
1029
|
+
'basicSettings.subtitle': 'Settings organized by purpose. Saving validates changes and preserves untouched fields.',
|
|
1030
|
+
'basicSettings.reload': 'Reload',
|
|
1031
|
+
'basicSettings.tabs.models': 'Models & Reasoning',
|
|
1032
|
+
'basicSettings.tabs.modelsHint': 'Base Agents, models, connections',
|
|
1033
|
+
'basicSettings.tabs.response': 'Responses & Sessions',
|
|
1034
|
+
'basicSettings.tabs.responseHint': 'Delivery and renewal',
|
|
1035
|
+
'basicSettings.tabs.projects': 'Projects & Services',
|
|
1036
|
+
'basicSettings.tabs.projectsHint': 'Paths and local services',
|
|
1037
|
+
'basicSettings.tabs.identity': 'Identity & Security',
|
|
1038
|
+
'basicSettings.tabs.identityHint': 'AID and access protection',
|
|
1039
|
+
'basicSettings.tabs.runtime': 'Runtime & Diagnostics',
|
|
1040
|
+
'basicSettings.tabs.runtimeHint': 'Logs and stability',
|
|
1041
|
+
'basicSettings.noChanges': 'No unsaved changes',
|
|
1042
|
+
'basicSettings.viewJson': 'View JSON',
|
|
1043
|
+
'basicSettings.save': 'Save Settings',
|
|
1044
|
+
'basicSettings.jsonTitle': 'View JSON',
|
|
1045
|
+
'basicSettings.jsonSubtitle': 'Read-only preview with sensitive values redacted.',
|
|
1046
|
+
'basicSettings.daemonFile': 'daemon.json',
|
|
1047
|
+
'basicSettings.defaultsFile': 'agents/defaults.json',
|
|
1001
1048
|
'theme.light': 'Light',
|
|
1002
1049
|
'theme.dark': 'Dark',
|
|
1003
1050
|
'theme.system': 'System',
|
|
@@ -1493,6 +1540,8 @@ const translations = {
|
|
|
1493
1540
|
'triggers.history.field.payload': 'Event Data',
|
|
1494
1541
|
'triggers.history.field.sessionId': 'Session ID',
|
|
1495
1542
|
'triggers.history.field.messageId': 'Message ID',
|
|
1543
|
+
'triggers.history.field.operationId': 'Operation ID',
|
|
1544
|
+
'triggers.history.field.outboxId': 'Outbox ID',
|
|
1496
1545
|
'triggers.history.field.handoffId': 'Handoff ID',
|
|
1497
1546
|
'triggers.history.field.attempt': 'Attempts',
|
|
1498
1547
|
'triggers.history.field.triggerId': 'Trigger ID',
|
|
@@ -1515,8 +1564,9 @@ const translations = {
|
|
|
1515
1564
|
'triggers.history.outcome.error': 'Error',
|
|
1516
1565
|
'triggers.history.outcome.interrupted': 'Interrupted',
|
|
1517
1566
|
'triggers.history.outcome.timeout': 'Timeout',
|
|
1567
|
+
'triggers.history.outcome.queued': 'Queued',
|
|
1518
1568
|
'triggers.history.effect.message.send': 'Send Message',
|
|
1519
|
-
'triggers.history.effect.handoff.enqueue': '
|
|
1569
|
+
'triggers.history.effect.handoff.enqueue': 'Deliver Handoff',
|
|
1520
1570
|
'triggers.history.effect.message.inbound': 'Inject Target Session',
|
|
1521
1571
|
'triggers.history.effect.agent.conversation': 'Agent Conversation',
|
|
1522
1572
|
'triggers.runStatus.completed': 'Completed',
|
|
@@ -1857,6 +1907,7 @@ function updateI18n() {
|
|
|
1857
1907
|
// 更新 html lang 属性
|
|
1858
1908
|
document.documentElement.lang = currentLang;
|
|
1859
1909
|
updateThemeButton();
|
|
1910
|
+
window.refreshBasicSettingsI18n?.();
|
|
1860
1911
|
}
|
|
1861
1912
|
|
|
1862
1913
|
function toggleLang() {
|
|
@@ -1873,7 +1924,16 @@ function toggleLang() {
|
|
|
1873
1924
|
// 本地直连时页面在 "/",经 AUN Service Proxy 时页面在 "/ecweb/"。
|
|
1874
1925
|
// 取当前页面所在目录(含尾斜杠)作为所有 API/WS 的前缀,使绝对路径在两种
|
|
1875
1926
|
// 部署下都正确(proxy-server 用首段路径选服务,前缀不能丢)。
|
|
1876
|
-
const BASE =
|
|
1927
|
+
const BASE = (() => {
|
|
1928
|
+
const baseElement = document.querySelector('base[href]');
|
|
1929
|
+
if (baseElement) {
|
|
1930
|
+
try {
|
|
1931
|
+
const basePath = new URL(baseElement.href, location.href).pathname;
|
|
1932
|
+
return basePath.endsWith('/') ? basePath : `${basePath}/`;
|
|
1933
|
+
} catch {}
|
|
1934
|
+
}
|
|
1935
|
+
return location.pathname.replace(/[^/]*$/, '');
|
|
1936
|
+
})();
|
|
1877
1937
|
const apiUrl = (p) => BASE + p.replace(/^\/+/, '');
|
|
1878
1938
|
const authApiUrl = (p) => {
|
|
1879
1939
|
const token = localStorage.getItem(TOKEN_KEY);
|
|
@@ -2196,6 +2256,12 @@ function subscribeRoleManagementSubview() {
|
|
|
2196
2256
|
function setRoleManagementSubview(subview, options = {}) {
|
|
2197
2257
|
roleManagementSubview = subview === 'assignments' ? 'assignments' : 'definitions';
|
|
2198
2258
|
localStorage.setItem(ROLE_SUBVIEW_KEY, roleManagementSubview);
|
|
2259
|
+
const newRoleButton = $('#btn-new-role');
|
|
2260
|
+
if (newRoleButton) {
|
|
2261
|
+
const visible = roleManagementSubview === 'definitions';
|
|
2262
|
+
newRoleButton.hidden = !visible;
|
|
2263
|
+
newRoleButton.setAttribute('aria-hidden', String(!visible));
|
|
2264
|
+
}
|
|
2199
2265
|
document.querySelectorAll('[data-role-subview]').forEach(tab => {
|
|
2200
2266
|
const active = tab.dataset.roleSubview === roleManagementSubview;
|
|
2201
2267
|
tab.classList.toggle('active', active);
|
|
@@ -3755,7 +3821,7 @@ function renderBlocks(blocks, options = {}) {
|
|
|
3755
3821
|
: '';
|
|
3756
3822
|
out += `<details class="blk blk-tool" open><summary class="tool-head">${icon} <span class="tool-name">${esc(tool)}</span></summary>${toolParams}</details>`;
|
|
3757
3823
|
} else if (b.kind === 'tool_result') {
|
|
3758
|
-
const rejection = b.rejection
|
|
3824
|
+
const rejection = b.rejection && (b.rejection.kind === 'approval_rejected' || b.rejection.kind === 'policy_blocked') ? b.rejection : undefined;
|
|
3759
3825
|
const cls = b.isError ? `blk-result err${rejection ? ' rejection' : ''}` : 'blk-result';
|
|
3760
3826
|
const loadFull = b.truncated && b.resultKey
|
|
3761
3827
|
? `<button class="ctrl-btn result-load-full" type="button" data-result-key="${esc(b.resultKey)}">${t('sessions.loadFullResult') || '加载完整结果'}</button>`
|
|
@@ -3779,7 +3845,7 @@ function renderBlocks(blocks, options = {}) {
|
|
|
3779
3845
|
: '';
|
|
3780
3846
|
return '<div class="result-rejection-meta">' +
|
|
3781
3847
|
`<span class="result-rejection-badge">⚠ ${t('sessions.block.rejection.title')}</span>` +
|
|
3782
|
-
`<span>${rejection.source === 'evolcore-policy' ? t('sessions.block.rejection.source.policy') : t('sessions.block.rejection.source.approval')}</span>` +
|
|
3848
|
+
`<span>${rejection.kind === 'policy_blocked' || rejection.source === 'evolcore-policy' ? t('sessions.block.rejection.source.policy') : t('sessions.block.rejection.source.approval')}</span>` +
|
|
3783
3849
|
`<span>${t('sessions.block.rejection.notExecuted')}</span>` +
|
|
3784
3850
|
`<span>${t(`sessions.block.rejection.evidence.${evidenceKey}`)}</span>` +
|
|
3785
3851
|
backendReason + auditText +
|
|
@@ -5460,6 +5526,13 @@ const TRIGGER_EXECUTION_TYPES = [
|
|
|
5460
5526
|
];
|
|
5461
5527
|
const TRIGGER_EFFORTS = ['low', 'medium', 'high', 'xhigh', 'max'];
|
|
5462
5528
|
const TRIGGER_PERMISSION_MODES = ['readonly', 'auto', 'request', 'bypass'];
|
|
5529
|
+
function triggerPermissionModes(currentMode = '') {
|
|
5530
|
+
const modes = [...TRIGGER_PERMISSION_MODES];
|
|
5531
|
+
if ((state.triggers?.fullaccessEnabled === true
|
|
5532
|
+
&& state.triggers?.canApprovePersistentFullAccess === true)
|
|
5533
|
+
|| currentMode === 'fullaccess') modes.push('fullaccess');
|
|
5534
|
+
return modes;
|
|
5535
|
+
}
|
|
5463
5536
|
const TRIGGER_TARGET_SESSIONS = [
|
|
5464
5537
|
['main', () => t('triggers.session.main')],
|
|
5465
5538
|
['thread', () => t('triggers.session.thread')],
|
|
@@ -5581,8 +5654,9 @@ async function withTriggerOp(id, agent, label, fn) {
|
|
|
5581
5654
|
finally { setTriggerOp(id, agent, null); }
|
|
5582
5655
|
}
|
|
5583
5656
|
|
|
5584
|
-
function triggerOptionHtml(items, current, emptyLabel) {
|
|
5657
|
+
function triggerOptionHtml(items, current, emptyLabel, disabledValues = null) {
|
|
5585
5658
|
const selected = String(current || '');
|
|
5659
|
+
const disabled = disabledValues instanceof Set ? disabledValues : new Set(disabledValues || []);
|
|
5586
5660
|
let html = emptyLabel == null ? '' : `<option value=""${selected ? '' : ' selected'}>${esc(emptyLabel)}</option>`;
|
|
5587
5661
|
let seen = new Set();
|
|
5588
5662
|
for (const item of items) {
|
|
@@ -5591,10 +5665,10 @@ function triggerOptionHtml(items, current, emptyLabel) {
|
|
|
5591
5665
|
const label = typeof rawLabel === 'function' ? rawLabel() : String(rawLabel);
|
|
5592
5666
|
if (seen.has(value)) continue;
|
|
5593
5667
|
seen.add(value);
|
|
5594
|
-
html += `<option value="${esc(value)}"${value === selected ? ' selected' : ''}>${esc(label)}</option>`;
|
|
5668
|
+
html += `<option value="${esc(value)}"${value === selected ? ' selected' : ''}${disabled.has(value) ? ' disabled' : ''}>${esc(label)}</option>`;
|
|
5595
5669
|
}
|
|
5596
5670
|
if (selected && !seen.has(selected)) {
|
|
5597
|
-
html += `<option value="${esc(selected)}" selected>${esc(selected)} (${t('common.currentSuffix')})</option>`;
|
|
5671
|
+
html += `<option value="${esc(selected)}" selected${disabled.has(selected) ? ' disabled' : ''}>${esc(selected)} (${t('common.currentSuffix')})</option>`;
|
|
5598
5672
|
}
|
|
5599
5673
|
return html;
|
|
5600
5674
|
}
|
|
@@ -6216,7 +6290,9 @@ function triggerHistoryFieldLabel(path, context = '') {
|
|
|
6216
6290
|
channelType: t('triggers.th.channelType'),
|
|
6217
6291
|
channelId: t('triggers.field.channelId'),
|
|
6218
6292
|
sessionId: t('triggers.history.field.sessionId'),
|
|
6293
|
+
operationId: t('triggers.history.field.operationId'),
|
|
6219
6294
|
messageId: t('triggers.history.field.messageId'),
|
|
6295
|
+
outboxId: t('triggers.history.field.outboxId'),
|
|
6220
6296
|
handoffId: t('triggers.history.field.handoffId'),
|
|
6221
6297
|
attempt: t('triggers.history.field.attempt'),
|
|
6222
6298
|
startedAt: t('triggers.history.startedAt'),
|
|
@@ -6254,6 +6330,7 @@ function triggerHistoryFieldValue(path, value, context = '') {
|
|
|
6254
6330
|
}
|
|
6255
6331
|
if (context === 'effects' && path === 'status') {
|
|
6256
6332
|
if (value === 'success') return t('triggers.history.outcome.success');
|
|
6333
|
+
if (value === 'queued') return t('triggers.history.outcome.queued');
|
|
6257
6334
|
if (value === 'failed') return t('triggers.runStatus.failed');
|
|
6258
6335
|
if (value === 'skipped') return t('triggers.runStatus.skipped');
|
|
6259
6336
|
}
|
|
@@ -6368,7 +6445,7 @@ function triggerHistoryEffectsBlock(effects) {
|
|
|
6368
6445
|
'channelId',
|
|
6369
6446
|
...(Number(effect?.attempt) === 1 ? ['attempt'] : []),
|
|
6370
6447
|
],
|
|
6371
|
-
keyOrder: ['type', 'status', 'handoffId', 'sessionId'],
|
|
6448
|
+
keyOrder: ['type', 'status', 'messageId', 'outboxId', 'handoffId', 'sessionId', 'operationId'],
|
|
6372
6449
|
}) +
|
|
6373
6450
|
`</div>`,
|
|
6374
6451
|
).join('')}</div>`;
|
|
@@ -7280,7 +7357,7 @@ function openTriggerEditDrawer(id, agent) {
|
|
|
7280
7357
|
`<label class="ag-edit-field"><span>${t('triggers.field.executionType')}</span><select id="trig-edit-type">${triggerOptionHtml(TRIGGER_EXECUTION_TYPES, original.executionType, null)}</select></label>` +
|
|
7281
7358
|
`<label class="ag-edit-field trig-agent-field"><span>${t('triggers.field.model')}</span><select id="trig-edit-model">${agentSelectOptions([], original.model, t('common.inherited'))}</select></label>` +
|
|
7282
7359
|
`<label class="ag-edit-field trig-agent-field"><span>${t('triggers.field.effort')}</span><select id="trig-edit-effort">${agentSelectOptions([], original.effort, t('common.inherited'))}</select></label>` +
|
|
7283
|
-
`<label class="ag-edit-field trig-agent-field"><span>${t('triggers.field.permission')}</span><select id="trig-edit-permission">${triggerOptionHtml(
|
|
7360
|
+
`<label class="ag-edit-field trig-agent-field"><span>${t('triggers.field.permission')}</span><select id="trig-edit-permission">${triggerOptionHtml(triggerPermissionModes(original.permissionMode), original.permissionMode, t('common.inherited'), state.triggers?.canApprovePersistentFullAccess === true ? [] : ['fullaccess'])}</select></label>` +
|
|
7284
7361
|
`<label class="ag-edit-field trig-script-field"><span>${t('triggers.field.scriptRuntime')}</span><select id="trig-edit-script-runtime">${triggerOptionHtml(['node', 'python', 'bash'], original.scriptRuntime, null)}</select></label>` +
|
|
7285
7362
|
`<label class="ag-edit-field trig-script-field trig-script-path-field"><span>${t('triggers.field.scriptPath')}</span><input id="trig-edit-script-path" type="text" autocomplete="off" spellcheck="false" value="${esc(original.scriptPath)}" placeholder="${t('triggers.placeholder.scriptPath')}"></label>` +
|
|
7286
7363
|
`</div>` +
|
|
@@ -9021,11 +9098,39 @@ function monDualLine(elId, varKey, times, isDark, title, series, fmtY, yRange) {
|
|
|
9021
9098
|
}
|
|
9022
9099
|
|
|
9023
9100
|
function renderRoles(data) {
|
|
9024
|
-
if (!data) return;
|
|
9025
|
-
|
|
9026
9101
|
const agentSelect = $('#roles-agent-select');
|
|
9102
|
+
const tbody = document.querySelector('#relations-table tbody');
|
|
9103
|
+
if (!data) {
|
|
9104
|
+
if (tbody) {
|
|
9105
|
+
tbody.innerHTML = '';
|
|
9106
|
+
const row = tbody.insertRow();
|
|
9107
|
+
const cell = row.insertCell();
|
|
9108
|
+
cell.colSpan = 7;
|
|
9109
|
+
cell.textContent = t('common.loading');
|
|
9110
|
+
cell.style.textAlign = 'center';
|
|
9111
|
+
cell.style.color = 'var(--dim)';
|
|
9112
|
+
cell.style.padding = '40px';
|
|
9113
|
+
}
|
|
9114
|
+
return;
|
|
9115
|
+
}
|
|
9027
9116
|
if (!agentSelect) return;
|
|
9028
9117
|
|
|
9118
|
+
if (data.error) {
|
|
9119
|
+
agentSelect.innerHTML = `<option value="">${esc(t('roles.selectAgentPlaceholder'))}</option>`;
|
|
9120
|
+
rolesCurrentAgent = null;
|
|
9121
|
+
if (tbody) {
|
|
9122
|
+
tbody.innerHTML = '';
|
|
9123
|
+
const row = tbody.insertRow();
|
|
9124
|
+
const cell = row.insertCell();
|
|
9125
|
+
cell.colSpan = 7;
|
|
9126
|
+
cell.textContent = `${t('common.error')}: ${String(data.error)}`;
|
|
9127
|
+
cell.style.textAlign = 'center';
|
|
9128
|
+
cell.style.color = 'var(--red)';
|
|
9129
|
+
cell.style.padding = '40px';
|
|
9130
|
+
}
|
|
9131
|
+
return;
|
|
9132
|
+
}
|
|
9133
|
+
|
|
9029
9134
|
agentSelect.innerHTML = '';
|
|
9030
9135
|
const placeholderOption = document.createElement('option');
|
|
9031
9136
|
placeholderOption.value = '';
|
|
@@ -9063,6 +9168,7 @@ function roleSourceLabel(source) {
|
|
|
9063
9168
|
const labels = {
|
|
9064
9169
|
'relation-assigned': 'Explicit',
|
|
9065
9170
|
'group-member': 'Member override',
|
|
9171
|
+
'relation-actor': 'Private role',
|
|
9066
9172
|
'private-inherited': 'Private role',
|
|
9067
9173
|
'group-default': 'Group role',
|
|
9068
9174
|
default: 'Default',
|
|
@@ -9080,6 +9186,34 @@ function peerTypeText(peerType) {
|
|
|
9080
9186
|
return '-';
|
|
9081
9187
|
}
|
|
9082
9188
|
|
|
9189
|
+
function roleVerificationStatus(item) {
|
|
9190
|
+
const status = String(item?.verifyStatus || 'unknown').toLowerCase();
|
|
9191
|
+
if (status === 'agentmd' || status === 'verified') return 'verified';
|
|
9192
|
+
if (status === 'agentmd-unverified' || status === 'unverified') return 'agentmd-unverified';
|
|
9193
|
+
if (status === 'invalid') return 'invalid';
|
|
9194
|
+
return 'unknown';
|
|
9195
|
+
}
|
|
9196
|
+
|
|
9197
|
+
function roleVerificationMatches(item, filter) {
|
|
9198
|
+
if (!filter) return true;
|
|
9199
|
+
const status = roleVerificationStatus(item);
|
|
9200
|
+
return filter === 'verified' ? status === 'verified' : status === filter;
|
|
9201
|
+
}
|
|
9202
|
+
|
|
9203
|
+
function roleVerificationBadge(item) {
|
|
9204
|
+
const status = roleVerificationStatus(item);
|
|
9205
|
+
if (status === 'invalid') {
|
|
9206
|
+
return ` <span class="verify-badge verify-invalid" title="${esc(t('roles.verify.invalid'))}">⚠️ ${esc(t('roles.verify.invalidShort'))}</span>`;
|
|
9207
|
+
}
|
|
9208
|
+
if (status === 'agentmd-unverified') {
|
|
9209
|
+
return ` <span class="verify-badge verify-unverified" title="${esc(t('roles.verify.unverified'))}">⚠️</span>`;
|
|
9210
|
+
}
|
|
9211
|
+
if (status === 'unknown') {
|
|
9212
|
+
return ` <span class="verify-badge verify-unknown" title="${esc(t('roles.verify.unknown'))}">❓</span>`;
|
|
9213
|
+
}
|
|
9214
|
+
return '';
|
|
9215
|
+
}
|
|
9216
|
+
|
|
9083
9217
|
function roleClass(role) {
|
|
9084
9218
|
return String(role || 'none').replace(/[^a-z0-9_-]/gi, '-');
|
|
9085
9219
|
}
|
|
@@ -9092,7 +9226,9 @@ function assignedRoleFor(scope, item) {
|
|
|
9092
9226
|
if (!item) return '';
|
|
9093
9227
|
if (scope === 'private') return item.source === 'relation-assigned' ? (item.assignment?.role || item.role || '') : '';
|
|
9094
9228
|
if (scope === 'group') return item.source === 'relation-assigned' ? (item.assignment?.role || item.role || '') : '';
|
|
9095
|
-
return item.source === 'group-member'
|
|
9229
|
+
return item.source === 'group-member' || item.source === 'relation-actor'
|
|
9230
|
+
? (item.assignment?.role || item.role || '')
|
|
9231
|
+
: '';
|
|
9096
9232
|
}
|
|
9097
9233
|
|
|
9098
9234
|
function assignableRolesForAgent(agentAid) {
|
|
@@ -9114,6 +9250,16 @@ function renderRelationsTable(data, filterAid = null) {
|
|
|
9114
9250
|
if (!tbody) return;
|
|
9115
9251
|
|
|
9116
9252
|
tbody.innerHTML = '';
|
|
9253
|
+
if (data?.error) {
|
|
9254
|
+
const row = tbody.insertRow();
|
|
9255
|
+
const cell = row.insertCell();
|
|
9256
|
+
cell.colSpan = 7;
|
|
9257
|
+
cell.textContent = `${t('common.error')}: ${String(data.error)}`;
|
|
9258
|
+
cell.style.textAlign = 'center';
|
|
9259
|
+
cell.style.color = 'var(--red)';
|
|
9260
|
+
cell.style.padding = '40px';
|
|
9261
|
+
return;
|
|
9262
|
+
}
|
|
9117
9263
|
let conversations = data.conversations || [];
|
|
9118
9264
|
|
|
9119
9265
|
if (filterAid) {
|
|
@@ -9141,6 +9287,16 @@ function renderRelationsTable(data, filterAid = null) {
|
|
|
9141
9287
|
conversations = conversations.filter(conv => conv.chatType === rolesChatTypeFilter);
|
|
9142
9288
|
}
|
|
9143
9289
|
|
|
9290
|
+
if (rolesVerifyFilter) {
|
|
9291
|
+
conversations = conversations
|
|
9292
|
+
.map(conv => conv.chatType === 'group'
|
|
9293
|
+
? { ...conv, members: (conv.members || []).filter(member => roleVerificationMatches(member, rolesVerifyFilter)) }
|
|
9294
|
+
: conv)
|
|
9295
|
+
.filter(conv => conv.chatType === 'group'
|
|
9296
|
+
? (conv.members || []).length > 0
|
|
9297
|
+
: roleVerificationMatches(conv, rolesVerifyFilter));
|
|
9298
|
+
}
|
|
9299
|
+
|
|
9144
9300
|
conversations.sort((a, b) => {
|
|
9145
9301
|
const lastDiff = (b.lastAt || 0) - (a.lastAt || 0);
|
|
9146
9302
|
if (lastDiff !== 0) return lastDiff;
|
|
@@ -9170,10 +9326,12 @@ function renderPrivateConversationRow(tbody, conv) {
|
|
|
9170
9326
|
const peerId = conv.peerId || conv.peerAid || conv.peerKey || conv.conversationId;
|
|
9171
9327
|
const name = conv.peerName || conv.name || shortAid(peerId);
|
|
9172
9328
|
const assignedRole = assignedRoleFor('private', conv);
|
|
9329
|
+
const verifyBadge = roleVerificationBadge(conv);
|
|
9330
|
+
const verifyClass = roleVerificationStatus(conv) === 'verified' ? '' : ` peer-${roleVerificationStatus(conv) === 'unknown' ? 'unknown' : 'unverified'}`;
|
|
9173
9331
|
const row = tbody.insertRow();
|
|
9174
9332
|
row.innerHTML = `
|
|
9175
9333
|
<td><span class="chat-tag chat-tag-private">${esc(t('roles.chatType.private') || 'Private')}</span></td>
|
|
9176
|
-
<td><strong>${esc(name)}</strong
|
|
9334
|
+
<td class="${verifyClass.trim()}"><strong>${esc(name)}</strong>${verifyBadge}</td>
|
|
9177
9335
|
<td><code>${esc(peerId)}</code></td>
|
|
9178
9336
|
<td>${esc(peerTypeText(conv.peerType))}</td>
|
|
9179
9337
|
<td><span class="role-badge role-${esc(roleClass(conv.role))}">${esc(displayRole(conv.role))}</span></td>
|
|
@@ -9238,11 +9396,13 @@ function renderGroupMemberRow(tbody, conv, member) {
|
|
|
9238
9396
|
const peerId = member.peerId || member.peerAid || member.peerKey;
|
|
9239
9397
|
const name = member.peerName || shortAid(peerId);
|
|
9240
9398
|
const assignedRole = assignedRoleFor('group-member', member);
|
|
9399
|
+
const verifyBadge = roleVerificationBadge(member);
|
|
9400
|
+
const verifyClass = roleVerificationStatus(member) === 'verified' ? '' : ` peer-${roleVerificationStatus(member) === 'unknown' ? 'unknown' : 'unverified'}`;
|
|
9241
9401
|
const row = tbody.insertRow();
|
|
9242
9402
|
row.className = 'group-member-row';
|
|
9243
9403
|
row.innerHTML = `
|
|
9244
9404
|
<td></td>
|
|
9245
|
-
<td><span class="group-member-indent">${esc(name)}</span
|
|
9405
|
+
<td class="${verifyClass.trim()}"><span class="group-member-indent">${esc(name)}</span>${verifyBadge}</td>
|
|
9246
9406
|
<td><code>${esc(peerId)}</code></td>
|
|
9247
9407
|
<td>${esc(peerTypeText(member.peerType))}</td>
|
|
9248
9408
|
<td><span class="role-badge role-${esc(roleClass(member.role))}">${esc(displayRole(member.role))}</span></td>
|